Add readScreen summary format and readVicState sprite visibility

- readScreen now supports format: "summary" | "full" option
  - summary: non-empty lines with trimming (agent-friendly)
  - full: all 25 lines (debugging use)
- readVicState now tracks sprite visibility:
  - visibleSprites array with sprite numbers
  - visibleCount for quick checking
  - Updated hint when sprites enabled but not visible

AX feedback from owl review.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Simen Svale 2025-12-30 01:59:13 +01:00
parent 37f53616ff
commit 56ea0984bb

View file

@ -673,10 +673,15 @@ Note: This reads from the current screen RAM location (may not be $0400 if the p
In bitmap modes, the data won't represent text. In bitmap modes, the data won't represent text.
Options: Options:
- format: "full" (default) returns all 25 lines, "summary" returns only non-empty lines
- includeRaw: Also return raw screen codes (default: false) - includeRaw: Also return raw screen codes (default: false)
Related tools: readColorRam, readVicState, readMemory`, Related tools: readColorRam, readVicState, readMemory`,
inputSchema: z.object({ inputSchema: z.object({
format: z
.enum(["full", "summary"])
.optional()
.describe("Output format: 'full' (all 25 lines) or 'summary' (non-empty lines only)"),
includeRaw: z includeRaw: z
.boolean() .boolean()
.optional() .optional()
@ -707,21 +712,36 @@ Related tools: readColorRam, readVicState, readMemory`,
.map((line, idx) => ({ line: idx, content: line })) .map((line, idx) => ({ line: idx, content: line }))
.filter((l) => l.content.trim().length > 0); .filter((l) => l.content.trim().length > 0);
const useSummaryFormat = args.format === "summary";
const response: Record<string, unknown> = { const response: Record<string, unknown> = {
screenAddress: { screenAddress: {
value: videoAddrs.screenAddress, value: videoAddrs.screenAddress,
hex: `$${videoAddrs.screenAddress.toString(16).padStart(4, "0")}`, hex: `$${videoAddrs.screenAddress.toString(16).padStart(4, "0")}`,
}, },
vicBank: bankInfo.bank, vicBank: bankInfo.bank,
lines: textLines, format: useSummaryFormat ? "summary" : "full",
summary: { };
if (useSummaryFormat) {
// Summary format: only non-empty lines with line numbers
response.lines = nonEmptyLines.map((l) => ({
lineNumber: l.line,
content: l.content,
}));
response.totalLines = 25;
response.nonEmptyCount = nonEmptyLines.length;
} else {
// Full format: all 25 lines
response.lines = textLines;
response.summary = {
nonEmptyLines: nonEmptyLines.length, nonEmptyLines: nonEmptyLines.length,
preview: preview:
nonEmptyLines.length > 0 nonEmptyLines.length > 0
? nonEmptyLines.slice(0, 3).map((l) => `Line ${l.line}: "${l.content}"`) ? nonEmptyLines.slice(0, 3).map((l) => `Line ${l.line}: "${l.content}"`)
: ["Screen appears empty"], : ["Screen appears empty"],
},
}; };
}
if (args.includeRaw) { if (args.includeRaw) {
response.raw = Array.from(screenData); response.raw = Array.from(screenData);
@ -863,11 +883,25 @@ Related tools: readScreen, readSprites, readMemory (for $D000-$D02E)`,
// Raster position (9-bit) // Raster position (9-bit)
const rasterLine = vicData[0x12] | ((d011 & 0x80) << 1); const rasterLine = vicData[0x12] | ((d011 & 0x80) << 1);
// Sprite enable // Sprite enable and visibility check
const spriteEnable = vicData[0x15]; const spriteEnable = vicData[0x15];
const enabledSprites = []; const spriteXMsb = vicData[0x10];
const enabledSprites: number[] = [];
const visibleSprites: number[] = [];
for (let i = 0; i < 8; i++) { for (let i = 0; i < 8; i++) {
if (spriteEnable & (1 << i)) enabledSprites.push(i); if (spriteEnable & (1 << i)) {
enabledSprites.push(i);
// Check visibility
const xLow = vicData[i * 2];
const xHigh = (spriteXMsb & (1 << i)) ? 256 : 0;
const x = xLow + xHigh;
const y = vicData[i * 2 + 1];
const visibility = isSpriteVisible(x, y, true);
if (visibility.visible) {
visibleSprites.push(i);
}
}
} }
// Display enable // Display enable
@ -921,7 +955,9 @@ Related tools: readScreen, readSprites, readMemory (for $D000-$D02E)`,
value: spriteEnable, value: spriteEnable,
binary: spriteEnable.toString(2).padStart(8, "0"), binary: spriteEnable.toString(2).padStart(8, "0"),
enabledSprites, enabledSprites,
count: enabledSprites.length, enabledCount: enabledSprites.length,
visibleSprites,
visibleCount: visibleSprites.length,
}, },
// Sprite multicolor registers // Sprite multicolor registers
@ -931,7 +967,9 @@ Related tools: readScreen, readSprites, readMemory (for $D000-$D02E)`,
hint: !displayEnabled hint: !displayEnabled
? "Display is blanked (DEN=0) - screen shows border color only" ? "Display is blanked (DEN=0) - screen shows border color only"
: enabledSprites.length > 0 : enabledSprites.length > 0
? `${graphicsMode.mode} mode, ${enabledSprites.length} sprite(s) enabled. Use readSprites() for sprite details.` ? visibleSprites.length < enabledSprites.length
? `${graphicsMode.mode} mode, ${enabledSprites.length} sprite(s) enabled but only ${visibleSprites.length} visible. Use readSprites() for details.`
: `${graphicsMode.mode} mode, ${enabledSprites.length} sprite(s) enabled and visible.`
: `${graphicsMode.mode} mode, no sprites enabled.`, : `${graphicsMode.mode} mode, no sprites enabled.`,
}; };