c64bridge 1.0.7 → 1.1.0
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/skills/assembly-program/SKILL.md +37 -0
- package/.github/skills/basic-program/SKILL.md +40 -0
- package/.github/skills/cross-platform-demo/SKILL.md +32 -0
- package/.github/skills/drive-manager/SKILL.md +33 -0
- package/.github/skills/graphics-demo/SKILL.md +30 -0
- package/.github/skills/hello-world/SKILL.md +36 -0
- package/.github/skills/memory-debug/SKILL.md +32 -0
- package/.github/skills/pr-converge/SKILL.md +33 -0
- package/.github/skills/printer-job/SKILL.md +30 -0
- package/.github/skills/sid-music/SKILL.md +35 -0
- package/.github/skills/software-launch/SKILL.md +31 -0
- package/.github/skills/stream-control/SKILL.md +29 -0
- package/.github/skills/system-control/SKILL.md +32 -0
- package/AGENTS.md +28 -7
- package/README.md +69 -14
- package/data/assembly/assembly-spec.md +2 -0
- package/dist/c64Client.js +238 -60
- package/dist/config.js +48 -26
- package/dist/device.js +92 -37
- package/dist/diagnostics.js +62 -2
- package/dist/hostPaths.js +128 -0
- package/dist/loggingHttpClient.js +59 -1
- package/dist/mcp-server.js +409 -286
- package/dist/numericArg.js +55 -0
- package/dist/petscii.js +13 -1
- package/dist/platform.js +12 -3
- package/dist/prompts/registry.js +6 -1
- package/dist/tools/access.js +66 -0
- package/dist/tools/debug.js +6 -0
- package/dist/tools/developer.js +67 -34
- package/dist/tools/errors.js +54 -3
- package/dist/tools/input.js +23 -6
- package/dist/tools/machineControl.js +112 -20
- package/dist/tools/memory.js +135 -30
- package/dist/tools/meta/artifacts.js +5 -5
- package/dist/tools/meta/background.js +216 -54
- package/dist/tools/meta/compilation.js +6 -5
- package/dist/tools/meta/config.js +15 -6
- package/dist/tools/meta/filesystem.js +16 -14
- package/dist/tools/meta/graphics.js +48 -20
- package/dist/tools/meta/memory.js +45 -19
- package/dist/tools/meta/program.js +10 -7
- package/dist/tools/meta/screen.js +116 -25
- package/dist/tools/pauseGuard.js +23 -0
- package/dist/tools/pollValidator.js +53 -8
- package/dist/tools/programRunners.js +62 -18
- package/dist/tools/registry/batch.js +16 -4
- package/dist/tools/registry/config.js +9 -2
- package/dist/tools/registry/disk.js +12 -2
- package/dist/tools/registry/drive.js +3 -0
- package/dist/tools/registry/extract.js +3 -0
- package/dist/tools/registry/graphics.js +59 -6
- package/dist/tools/registry/index.js +17 -1
- package/dist/tools/registry/memory.js +11 -1
- package/dist/tools/registry/platform.js +4 -1
- package/dist/tools/registry/printer.js +2 -1
- package/dist/tools/registry/program.js +5 -1
- package/dist/tools/registry/rag.js +1 -0
- package/dist/tools/registry/sound.js +12 -1
- package/dist/tools/registry/stream.js +2 -1
- package/dist/tools/registry/system.js +8 -1
- package/dist/tools/schema.js +7 -7
- package/dist/tools/streaming.js +34 -4
- package/dist/tools/translation/assembler.js +247 -24
- package/dist/tools/translation/basicDetokenizer.js +80 -0
- package/dist/tools/translation/basicTokenizer.js +8 -3
- package/dist/tools/translation/disassembler.js +14 -0
- package/dist/tools/types.js +258 -7
- package/dist/tools/vice.js +5 -16
- package/dist/vicBitmap.js +1 -1
- package/dist/vice/mockServer.js +3 -0
- package/dist/vice/process.js +19 -0
- package/dist/vice/resourcePolicy.js +36 -0
- package/dist/vice/viceClient.js +22 -5
- package/doc/vice/support-matrix.md +17 -11
- package/mcp/schemas/c64_batch.schema.json +2 -1
- package/mcp/schemas/c64_config.schema.json +25 -475
- package/mcp/schemas/c64_debug.schema.json +3 -602
- package/mcp/schemas/c64_disk.schema.json +17 -344
- package/mcp/schemas/c64_drive.schema.json +2 -157
- package/mcp/schemas/c64_extract.schema.json +10 -364
- package/mcp/schemas/c64_graphics.schema.json +19 -426
- package/mcp/schemas/c64_input.schema.json +5 -318
- package/mcp/schemas/c64_memory.schema.json +23 -491
- package/mcp/schemas/c64_printer.schema.json +3 -258
- package/mcp/schemas/c64_program.schema.json +16 -491
- package/mcp/schemas/c64_rag.schema.json +1 -81
- package/mcp/schemas/c64_select_backend.schema.json +2 -36
- package/mcp/schemas/c64_sound.schema.json +20 -822
- package/mcp/schemas/c64_stream.schema.json +4 -75
- package/mcp/schemas/c64_system.schema.json +28 -348
- package/mcp/schemas/c64_vice.schema.json +2 -71
- package/mcp/server.json +1 -1
- package/mcp/tools.json +1983 -6910
- package/mcp.json +21 -1
- package/package.json +16 -8
- package/scripts/mockC64Server.mjs +44 -0
- package/scripts/run-coverage.mjs +27 -1
- package/scripts/smoke-run.sh +3 -2
- package/scripts/start.mjs +23 -1
- package/server.json +35 -2
- package/dist/.tsbuildinfo +0 -1
- package/doc/agent-state-spec.md +0 -243
- package/doc/audit/secret-handling.md +0 -61
- package/doc/plans/bun/baseline-metrics.md +0 -16
- package/doc/plans/bun/migration-checklist.md +0 -55
- package/doc/plans/bun/migration.md +0 -83
- package/doc/plans/improve-knowledge/notes.md +0 -43
- package/doc/plans/improve-knowledge/plan.md +0 -121
- package/doc/plans/improve-knowledge/rollout.md +0 -110
- package/doc/plans/meta-tools/README.md +0 -110
- package/doc/plans/meta-tools/analysis.md +0 -272
- package/doc/plans/meta-tools/catalog.md +0 -435
- package/doc/plans/meta-tools/notes.md +0 -192
- package/doc/plans/meta-tools/rollout.md +0 -368
- package/doc/plans/prompts/README.md +0 -96
- package/doc/plans/prompts/user-prompt-ideas.md +0 -147
- package/doc/plans/tool-consolidation/notes.md +0 -28
- package/doc/plans/tool-consolidation/plan.md +0 -169
- package/doc/plans/tool-consolidation/rollout.md +0 -104
- package/doc/plans/vice-backend-switch/plan.md +0 -486
- package/doc/plans/vice-backend-switch-2/plan.md +0 -48
- package/doc/plans/vice-support/notes.md +0 -63
- package/doc/plans/vice-support/plan.md +0 -88
- package/doc/plans/vice-support/rollout.md +0 -99
- package/doc/reviews/audit.md +0 -143
- package/doc/reviews/hardening/01-fable/prompt-handover.md +0 -125
- package/doc/reviews/hardening/01-fable/prompt.md +0 -98
- package/doc/reviews/hardening/01-fable/review-prompt.md +0 -468
- package/doc/reviews/hardening/01-fable/review.md +0 -1234
- package/doc/reviews/vice-support-review.md +0 -185
- package/scripts/compare-rest/rest-compare-2025-11-01T00-25-21-830Z.json +0 -2513
|
@@ -1,486 +0,0 @@
|
|
|
1
|
-
# C64Bridge: Multi-Backend Runtime Switching — Implementation Brief
|
|
2
|
-
|
|
3
|
-
## Context
|
|
4
|
-
|
|
5
|
-
You are working in the repository at `/home/chris/dev/c64/c64bridge`.
|
|
6
|
-
|
|
7
|
-
This is a TypeScript MCP (Model Context Protocol) server that bridges Commodore 64
|
|
8
|
-
hardware and emulator backends to AI agents. Two backends exist:
|
|
9
|
-
|
|
10
|
-
- **C64U** (`c64u`): REST API to physical C64 Ultimate hardware at `http://c64u`
|
|
11
|
-
- **VICE** (`vice`): Binary monitor protocol to the VICE C64 emulator
|
|
12
|
-
|
|
13
|
-
The server is started via `node scripts/start.mjs` (stdio MCP transport).
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Mandatory Process
|
|
18
|
-
|
|
19
|
-
Before writing any code you **must** create `plans.md` at the repo root with the
|
|
20
|
-
full multi-phase plan described below. Every task in `plans.md` must be a checkbox.
|
|
21
|
-
Tick each checkbox the moment that task is complete — never batch. Alongside
|
|
22
|
-
`plans.md`, maintain `worklog.md` at the repo root. Append a timestamped entry to
|
|
23
|
-
`worklog.md` whenever you start a phase, complete a phase, or make a decision that
|
|
24
|
-
deviates from this brief.
|
|
25
|
-
|
|
26
|
-
Format for `worklog.md` entries:
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
## YYYY-MM-DD HH:MM — <one-line summary>
|
|
30
|
-
|
|
31
|
-
<Free prose: what was done, any surprises, decisions made.>
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
**Do not proceed to the next phase until all checkboxes in the current phase are
|
|
35
|
-
ticked.** If you discover that a later phase must be restructured because of
|
|
36
|
-
something you learned in an earlier phase, update `plans.md` and add a worklog
|
|
37
|
-
entry explaining why.
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## Test Coverage Mandate
|
|
42
|
-
|
|
43
|
-
**Minimum 91% line + branch coverage across all modified and new source files.**
|
|
44
|
-
|
|
45
|
-
- Run the existing test suite with `./build test` (mock backend) after every phase.
|
|
46
|
-
- After the final phase run `./build coverage` and verify the threshold.
|
|
47
|
-
- If coverage drops below 91% on any modified file, write additional tests before
|
|
48
|
-
marking that phase complete.
|
|
49
|
-
- Tests live in `src/**/*.test.ts` (co-located) or `test/**/*.ts` — follow the
|
|
50
|
-
existing pattern for the file you are modifying.
|
|
51
|
-
- Do not delete or weaken existing tests.
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## Bug Report: Why Vice Is Never Selected
|
|
56
|
-
|
|
57
|
-
When the server starts, `mcp-server.ts` calls `config.ts::loadConfig()`, which is a
|
|
58
|
-
**C64U-only** legacy loader. It reads `~/.c64bridge.json` or the project root
|
|
59
|
-
`.c64bridge.json` but only ever extracts `c64u.*` fields; the `vice` section is
|
|
60
|
-
silently ignored.
|
|
61
|
-
|
|
62
|
-
Separately, `device.ts::readConfigFile()` — used by `createFacade()` — scans
|
|
63
|
-
candidate paths in order and **returns on the first match**:
|
|
64
|
-
|
|
65
|
-
1. `C64BRIDGE_CONFIG` env var path
|
|
66
|
-
2. `.c64bridge.json` in the project root
|
|
67
|
-
3. `~/.c64bridge.json` in the home directory
|
|
68
|
-
|
|
69
|
-
The project root `.c64bridge.json` currently contains:
|
|
70
|
-
|
|
71
|
-
```json
|
|
72
|
-
{ "c64u": { "host": "c64u", "port": 80 } }
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Because this file is found first and contains no `vice` section,
|
|
76
|
-
`createFacade()` always selects c64u — the user's `~/.c64bridge.json` vice config
|
|
77
|
-
is never reached.
|
|
78
|
-
|
|
79
|
-
A second issue: after `createFacade()` resolves, `platform.ts::currentPlatform`
|
|
80
|
-
remains `"c64u"` (its hardcoded default) even when vice was selected, because
|
|
81
|
-
`mcp-server.ts` never calls `setPlatform()` with the result of the facade selection.
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## Existing Architecture — Key Files
|
|
86
|
-
|
|
87
|
-
Read every file listed here before writing code.
|
|
88
|
-
|
|
89
|
-
| File | Role |
|
|
90
|
-
|---|---|
|
|
91
|
-
| `src/mcp-server.ts` | MCP entry point. Creates `C64Client`, registers MCP handlers. |
|
|
92
|
-
| `src/config.ts` | Legacy C64U-only config loader used by `mcp-server.ts`. |
|
|
93
|
-
| `src/device.ts` | `C64uBackend`, `ViceBackend`, `C64Facade` interface, `createFacade()`, `readConfigFile()`. |
|
|
94
|
-
| `src/c64Client.ts` | Orchestration wrapper around a single `C64Facade`. All tool methods delegate here. |
|
|
95
|
-
| `src/platform.ts` | Global `currentPlatform` state, `setPlatform()`, tool gating helpers. |
|
|
96
|
-
| `src/tools/types.ts` | `ToolExecutionContext` — passed to every tool invocation. |
|
|
97
|
-
| `src/tools/registry/index.ts` | Registers all tool modules; `toolRegistry.invoke()`. |
|
|
98
|
-
| `src/tools/registry/system.ts` | Example of a multi-operation tool module. |
|
|
99
|
-
| `src/tools/vice.ts` | Vice-specific tool (`supportedPlatforms: ["vice"]`). Study this as a pattern. |
|
|
100
|
-
| `mcp.json` | MCP server descriptor with documented env vars. |
|
|
101
|
-
| `.vscode/mcp.json` | VS Code MCP config — stdio invocation. |
|
|
102
|
-
| `data/context/bootstrap.md` | LLM bootstrap prompt injected before every session. |
|
|
103
|
-
| `AGENTS.md` | LLM-facing setup and usage guide. |
|
|
104
|
-
|
|
105
|
-
Also read:
|
|
106
|
-
|
|
107
|
-
- `src/tools/types.ts` fully (especially `ToolExecutionContext` and `ToolModule`).
|
|
108
|
-
- One complete tool module (e.g. `src/tools/registry/system.ts`) to understand the
|
|
109
|
-
pattern before implementing the new tool.
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
## Phase Breakdown for `plans.md`
|
|
114
|
-
|
|
115
|
-
Use exactly the following phase and task names. Add sub-tasks as needed, but do not
|
|
116
|
-
remove or rename the top-level items.
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
### Phase 0 — Bootstrap
|
|
121
|
-
|
|
122
|
-
- [ ] Read every file listed in the architecture table above.
|
|
123
|
-
- [ ] Read `README.md` sections on configuration and VS Code setup.
|
|
124
|
-
- [ ] Read `AGENTS.md` and `data/context/bootstrap.md`.
|
|
125
|
-
- [ ] Run `./build test` and record baseline pass/fail count in `worklog.md`.
|
|
126
|
-
- [ ] Record current `./build coverage` output in `worklog.md`.
|
|
127
|
-
- [ ] Create `plans.md` with all phases and tasks.
|
|
128
|
-
- [ ] Create `worklog.md` with the Phase 0 start entry.
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
### Phase 1 — Merge Config Across Files
|
|
133
|
-
|
|
134
|
-
**Goal**: `readConfigFile()` in `src/device.ts` collects backend sections from
|
|
135
|
-
*all* candidate config files rather than stopping at the first match.
|
|
136
|
-
|
|
137
|
-
**Specification**:
|
|
138
|
-
|
|
139
|
-
- Iterate all candidate paths in order (env var → project root → home dir).
|
|
140
|
-
- Accumulate: take the `c64u` section from the **first** file that contains one;
|
|
141
|
-
take the `vice` section from the **first** file that contains one.
|
|
142
|
-
- Stop iterating early only when both sections have been found.
|
|
143
|
-
- If no file yields a section, that section remains `undefined`.
|
|
144
|
-
- Return `null` only when no candidate file exists at all.
|
|
145
|
-
- The function signature and return type (`C64BridgeConfigFile | null`) must not
|
|
146
|
-
change.
|
|
147
|
-
- Do not change any other behaviour of `createFacade()`.
|
|
148
|
-
|
|
149
|
-
**Tasks**:
|
|
150
|
-
|
|
151
|
-
- [ ] Implement the merge logic in `readConfigFile()`.
|
|
152
|
-
- [ ] Write/update unit tests: config from project root only, home only, both split
|
|
153
|
-
across files, env-var path overrides, missing files.
|
|
154
|
-
- [ ] Run `./build test` — all tests pass.
|
|
155
|
-
- [ ] Coverage ≥ 91% on `src/device.ts`.
|
|
156
|
-
- [ ] Append Phase 1 completion entry to `worklog.md`.
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
### Phase 2 — Env-Var Overrides for C64U Backend
|
|
161
|
-
|
|
162
|
-
**Goal**: The C64U backend respects env-var overrides analogous to the existing
|
|
163
|
-
`VICE_BINARY`, `VICE_HOST`, `VICE_PORT` vars, so a user can fully configure it
|
|
164
|
-
from `.vscode/mcp.json` without a config file.
|
|
165
|
-
|
|
166
|
-
**New env vars** (read inside `C64uBackend` constructor, same pattern as
|
|
167
|
-
`ViceBackend`):
|
|
168
|
-
|
|
169
|
-
| Env var | Overrides |
|
|
170
|
-
|---|---|
|
|
171
|
-
| `C64U_HOST` | `config.host` / `config.hostname` |
|
|
172
|
-
| `C64U_PORT` | `config.port` |
|
|
173
|
-
| `C64U_PASSWORD` | `config.networkPassword` |
|
|
174
|
-
|
|
175
|
-
**Precedence within `C64uBackend`** (highest → lowest):
|
|
176
|
-
|
|
177
|
-
1. Env var (`C64U_HOST`, etc.)
|
|
178
|
-
2. Constructor `config` argument (from config file)
|
|
179
|
-
3. Built-in defaults (`c64u`, port `80`)
|
|
180
|
-
|
|
181
|
-
**Tasks**:
|
|
182
|
-
|
|
183
|
-
- [ ] Read env vars in `C64uBackend` constructor.
|
|
184
|
-
- [ ] Document the three new vars in `mcp.json` `env` section with `description`
|
|
185
|
-
and `default` fields matching the existing format.
|
|
186
|
-
- [ ] Write unit tests: env var alone, config alone, env var beats config,
|
|
187
|
-
neither present → defaults.
|
|
188
|
-
- [ ] Run `./build test` — all tests pass.
|
|
189
|
-
- [ ] Coverage ≥ 91% on the modified constructor path.
|
|
190
|
-
- [ ] Append Phase 2 completion entry to `worklog.md`.
|
|
191
|
-
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
### Phase 3 — Dual-Facade Support in `C64Client`
|
|
195
|
-
|
|
196
|
-
**Goal**: When both backends are configured, `C64Client` initialises both facades
|
|
197
|
-
at construction time and exposes a `switchBackend()` method for zero-reconnect
|
|
198
|
-
runtime switching.
|
|
199
|
-
|
|
200
|
-
**Specification**:
|
|
201
|
-
|
|
202
|
-
Add a new exported async function to `src/device.ts`:
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
export interface AllFacadesResult {
|
|
206
|
-
primary: FacadeSelection; // the initially selected backend
|
|
207
|
-
secondary: C64Facade | null; // the other backend, if configured
|
|
208
|
-
secondaryType: DeviceType | null;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export async function createAllFacades(
|
|
212
|
-
logger?: { info: (...a: any[]) => void },
|
|
213
|
-
options?: FacadeOptions,
|
|
214
|
-
): Promise<AllFacadesResult>
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
Logic:
|
|
218
|
-
|
|
219
|
-
1. Call the existing `createFacade()` to determine the primary selection.
|
|
220
|
-
2. Read the merged config (via the updated `readConfigFile()`).
|
|
221
|
-
3. If the config contains the OTHER backend (the one not selected as primary),
|
|
222
|
-
construct it immediately (no probing required — just instantiate).
|
|
223
|
-
4. Return both.
|
|
224
|
-
|
|
225
|
-
Modify `C64Client`:
|
|
226
|
-
|
|
227
|
-
- Change constructor so that when `forceC64uFacade` is `false` it calls
|
|
228
|
-
`createAllFacades()` instead of `createFacade()`.
|
|
229
|
-
- Store results in:
|
|
230
|
-
```typescript
|
|
231
|
-
private readonly allFacades: Map<DeviceType, Promise<C64Facade>>;
|
|
232
|
-
private activeType: DeviceType;
|
|
233
|
-
private facadePromise: Promise<C64Facade>; // points to allFacades.get(activeType)
|
|
234
|
-
```
|
|
235
|
-
- Add:
|
|
236
|
-
```typescript
|
|
237
|
-
switchBackend(type: DeviceType): void
|
|
238
|
-
// Throws if the type is not in allFacades.
|
|
239
|
-
// Updates this.facadePromise = this.allFacades.get(type).
|
|
240
|
-
// Updates this.activeType.
|
|
241
|
-
// Does NOT call setPlatform() — that is the caller's responsibility.
|
|
242
|
-
|
|
243
|
-
getActiveBackendType(): Promise<DeviceType>
|
|
244
|
-
// Returns activeType (already resolved, but keep async for consistency).
|
|
245
|
-
|
|
246
|
-
getAvailableBackends(): DeviceType[]
|
|
247
|
-
// Returns Array.from(allFacades.keys()).
|
|
248
|
-
```
|
|
249
|
-
- All existing delegate methods in `C64Client` continue to work unchanged because
|
|
250
|
-
they already use `this.facadePromise`.
|
|
251
|
-
|
|
252
|
-
**Tasks**:
|
|
253
|
-
|
|
254
|
-
- [ ] Add `createAllFacades()` to `src/device.ts`.
|
|
255
|
-
- [ ] Modify `C64Client` constructor and add the three new methods.
|
|
256
|
-
- [ ] Write unit tests for `C64Client`: single c64u, single vice, both configured
|
|
257
|
-
(verify both facades initialised), `switchBackend()` swaps the active facade,
|
|
258
|
-
`switchBackend()` to unconfigured type throws.
|
|
259
|
-
- [ ] Run `./build test` — all tests pass.
|
|
260
|
-
- [ ] Coverage ≥ 91% on modified `c64Client.ts` paths.
|
|
261
|
-
- [ ] Append Phase 3 completion entry to `worklog.md`.
|
|
262
|
-
|
|
263
|
-
---
|
|
264
|
-
|
|
265
|
-
### Phase 4 — Sync Platform State on Init and Switch
|
|
266
|
-
|
|
267
|
-
**Goal**: `platform.ts::currentPlatform` always reflects the actually active
|
|
268
|
-
backend, from server start through any subsequent switches.
|
|
269
|
-
|
|
270
|
-
**In `src/mcp-server.ts`**:
|
|
271
|
-
|
|
272
|
-
After constructing `C64Client` and before registering MCP handlers, add:
|
|
273
|
-
|
|
274
|
-
```typescript
|
|
275
|
-
const initialBackendType = await client.getActiveBackendType();
|
|
276
|
-
setPlatform(initialBackendType);
|
|
277
|
-
writeDiagnosticEvent("platform_initialised", { platform: initialBackendType });
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
**In `C64Client::switchBackend()`** — the platform sync is **not** done here;
|
|
281
|
-
it remains the tool's responsibility (see Phase 5). Document this contract in a
|
|
282
|
-
comment.
|
|
283
|
-
|
|
284
|
-
**Tasks**:
|
|
285
|
-
|
|
286
|
-
- [ ] Add the `setPlatform()` call in `mcp-server.ts` after client construction.
|
|
287
|
-
- [ ] Add the `writeDiagnosticEvent` call.
|
|
288
|
-
- [ ] Write/update integration or unit tests that assert the platform matches the
|
|
289
|
-
backend that was selected from config at startup (both the c64u-only and
|
|
290
|
-
vice-only cases).
|
|
291
|
-
- [ ] Run `./build test` — all tests pass.
|
|
292
|
-
- [ ] Append Phase 4 completion entry to `worklog.md`.
|
|
293
|
-
|
|
294
|
-
---
|
|
295
|
-
|
|
296
|
-
### Phase 5 — `c64_select_backend` Tool
|
|
297
|
-
|
|
298
|
-
**Goal**: A new MCP tool lets the LLM (or user) switch the active backend at
|
|
299
|
-
runtime without restarting the server.
|
|
300
|
-
|
|
301
|
-
**Tool name**: `c64_select_backend`
|
|
302
|
-
|
|
303
|
-
**Module placement**: Add a new file `src/tools/registry/platform.ts` following the
|
|
304
|
-
same `ToolModule` / `defineToolModule` / `operationPlatforms` pattern as
|
|
305
|
-
`src/tools/registry/system.ts`. Register it in `src/tools/registry/index.ts`.
|
|
306
|
-
|
|
307
|
-
**Tool specification**:
|
|
308
|
-
|
|
309
|
-
```
|
|
310
|
-
Input schema
|
|
311
|
-
op: "select" (discriminator, required)
|
|
312
|
-
backend: "c64u" | "vice" (required)
|
|
313
|
-
|
|
314
|
-
Supported platforms: ["c64u", "vice"] — available on both
|
|
315
|
-
|
|
316
|
-
Behaviour
|
|
317
|
-
1. Call ctx.client.getAvailableBackends().
|
|
318
|
-
2. If backend is not in the list, return an error result explaining which
|
|
319
|
-
backends are configured (do not throw).
|
|
320
|
-
3. Call ctx.client.switchBackend(backend).
|
|
321
|
-
4. Call ctx.setPlatform(backend).
|
|
322
|
-
5. Return a success result that includes:
|
|
323
|
-
- The newly active backend name
|
|
324
|
-
- The list of tool names now available on that backend
|
|
325
|
-
- The list of tool names now unavailable
|
|
326
|
-
- A one-line usage hint reminding the user they can switch back
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
**Tasks**:
|
|
330
|
-
|
|
331
|
-
- [ ] Create `src/tools/registry/platform.ts` with the `c64_select_backend` tool.
|
|
332
|
-
- [ ] Register the module in `src/tools/registry/index.ts`.
|
|
333
|
-
- [ ] Write unit tests: select available backend succeeds and updates platform,
|
|
334
|
-
select unavailable backend returns error result (not throw), both backends
|
|
335
|
-
configured round-trip switch.
|
|
336
|
-
- [ ] Run `./build test` — all tests pass.
|
|
337
|
-
- [ ] Coverage ≥ 91% on `src/tools/registry/platform.ts`.
|
|
338
|
-
- [ ] Append Phase 5 completion entry to `worklog.md`.
|
|
339
|
-
|
|
340
|
-
---
|
|
341
|
-
|
|
342
|
-
### Phase 6 — LLM Routing Instructions
|
|
343
|
-
|
|
344
|
-
**Goal**: The LLM automatically calls `c64_select_backend` when the user expresses
|
|
345
|
-
a preference for a specific backend in natural language, without requiring any
|
|
346
|
-
server-side prompt parsing.
|
|
347
|
-
|
|
348
|
-
**Update `data/context/bootstrap.md`**:
|
|
349
|
-
|
|
350
|
-
Add a section (before the existing tool listing, or at the top of the "Platform"
|
|
351
|
-
section if one exists) with these exact routing rules:
|
|
352
|
-
|
|
353
|
-
```markdown
|
|
354
|
-
## Backend Selection
|
|
355
|
-
|
|
356
|
-
Two backends may be available: `c64u` (physical C64 Ultimate hardware) and `vice`
|
|
357
|
-
(VICE emulator). Use `c64_select_backend` to switch.
|
|
358
|
-
|
|
359
|
-
**Routing rules — call `c64_select_backend` first when the user:**
|
|
360
|
-
- Says "use vice", "on vice", "in the emulator", "via vice", or similar
|
|
361
|
-
- Says "use c64u", "on hardware", "on the Ultimate", "on the real machine", or similar
|
|
362
|
-
- Prefixes a request with a backend name, e.g. "vice: run this program"
|
|
363
|
-
|
|
364
|
-
Do not assume the current backend is correct without checking
|
|
365
|
-
`c64://platform/status` if the user has expressed a preference.
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
**Update `AGENTS.md`**:
|
|
369
|
-
|
|
370
|
-
Add a short "Runtime Backend Switching" subsection under the configuration section
|
|
371
|
-
that explains:
|
|
372
|
-
- Both backends can be live simultaneously when configured
|
|
373
|
-
- `c64_select_backend` switches without restarting
|
|
374
|
-
- The platform status resource (`c64://platform/status`) always reflects the
|
|
375
|
-
currently active backend
|
|
376
|
-
|
|
377
|
-
**Tasks**:
|
|
378
|
-
|
|
379
|
-
- [ ] Add backend routing rules to `data/context/bootstrap.md`.
|
|
380
|
-
- [ ] Add "Runtime Backend Switching" subsection to `AGENTS.md`.
|
|
381
|
-
- [ ] Verify that the bootstrap content is included in RAG (check
|
|
382
|
-
`src/rag/init.ts` or equivalent to confirm `bootstrap.md` is indexed).
|
|
383
|
-
- [ ] Append Phase 6 completion entry to `worklog.md`.
|
|
384
|
-
|
|
385
|
-
---
|
|
386
|
-
|
|
387
|
-
### Phase 7 — Update Platform Status Resource
|
|
388
|
-
|
|
389
|
-
**Goal**: The `c64://platform/status` resource rendered in `mcp-server.ts` now
|
|
390
|
-
also reports which backends are available (not just which is active) and removes
|
|
391
|
-
the stale notice about needing a restart to switch.
|
|
392
|
-
|
|
393
|
-
**In `mcp-server.ts::renderPlatformStatusMarkdown()`**:
|
|
394
|
-
|
|
395
|
-
- Add a "## Available Backends" section listing each backend from
|
|
396
|
-
`client.getAvailableBackends()`, marking the active one.
|
|
397
|
-
- Remove or update the trailing line:
|
|
398
|
-
> Switching platforms currently requires restarting the MCP server with an
|
|
399
|
-
> updated configuration.
|
|
400
|
-
|
|
401
|
-
Replace with a line explaining `c64_select_backend`.
|
|
402
|
-
|
|
403
|
-
**Tasks**:
|
|
404
|
-
|
|
405
|
-
- [ ] Update `renderPlatformStatusMarkdown()`.
|
|
406
|
-
- [ ] Pass `client` into the function (or use a closure — follow the existing
|
|
407
|
-
style in `mcp-server.ts`).
|
|
408
|
-
- [ ] Write/update tests for the rendered markdown output.
|
|
409
|
-
- [ ] Run `./build test` — all tests pass.
|
|
410
|
-
- [ ] Append Phase 7 completion entry to `worklog.md`.
|
|
411
|
-
|
|
412
|
-
---
|
|
413
|
-
|
|
414
|
-
### Phase 8 — Final Validation
|
|
415
|
-
|
|
416
|
-
- [ ] Run `./build test` (full mock suite) — zero failures.
|
|
417
|
-
- [ ] Run `./build test:matrix` if available — zero failures.
|
|
418
|
-
- [ ] Run `./build coverage` — overall coverage ≥ 91%.
|
|
419
|
-
- [ ] Manually inspect `plans.md` — every checkbox ticked.
|
|
420
|
-
- [ ] Review `worklog.md` — every phase has a completion entry.
|
|
421
|
-
- [ ] Read `README.md` configuration section and update it to document:
|
|
422
|
-
- The new `C64U_HOST`, `C64U_PORT`, `C64U_PASSWORD` env vars.
|
|
423
|
-
- The config-merging behaviour (both config files are read; first-found per
|
|
424
|
-
section wins).
|
|
425
|
-
- The dual-backend runtime switching capability and `c64_select_backend`.
|
|
426
|
-
- [ ] Append Phase 8 completion entry to `worklog.md`.
|
|
427
|
-
|
|
428
|
-
---
|
|
429
|
-
|
|
430
|
-
## Constraints and Non-Goals
|
|
431
|
-
|
|
432
|
-
- **Do not** delete or rename any existing public API on `C64Client` or
|
|
433
|
-
`C64Facade`.
|
|
434
|
-
- **Do not** remove `config.ts` or change its `loadConfig()` signature — it is
|
|
435
|
-
used by `mcp-server.ts` for diagnostics and may be used by external callers.
|
|
436
|
-
- **Do not** change the `createFacade()` function signature or its behaviour when
|
|
437
|
-
called with `preferredC64uBaseUrl` set (that path is used by tests).
|
|
438
|
-
- **Do not** add `npm` dependencies beyond what is already in `package.json`.
|
|
439
|
-
- **Do not** modify generated files under `generated/`.
|
|
440
|
-
- Keep all new source in TypeScript with strict types — no `any` except where the
|
|
441
|
-
existing code already uses it for generated API types.
|
|
442
|
-
- The `switchBackend()` method on `C64Client` must be synchronous (just a pointer
|
|
443
|
-
swap); do not await or re-connect anything inside it.
|
|
444
|
-
- The `createAllFacades()` secondary facade is constructed eagerly but its
|
|
445
|
-
underlying process (VICE) must **not** be started until the first method call
|
|
446
|
-
on it — this matches the existing lazy-start behaviour in `ViceBackend`.
|
|
447
|
-
|
|
448
|
-
---
|
|
449
|
-
|
|
450
|
-
## Precedence Order (for reference and tests)
|
|
451
|
-
|
|
452
|
-
After all phases are complete, the effective configuration precedence for backend
|
|
453
|
-
selection is, from highest to lowest:
|
|
454
|
-
|
|
455
|
-
1. `C64_MODE` env var (`"c64u"` or `"vice"`) → forces a single backend
|
|
456
|
-
2. `C64U_HOST` / `C64U_PORT` / `C64U_PASSWORD` env vars → override c64u fields
|
|
457
|
-
3. `VICE_BINARY` / `VICE_HOST` / `VICE_PORT` env vars → override vice fields
|
|
458
|
-
4. `C64BRIDGE_CONFIG` env var → explicit config file path (first-found wins per
|
|
459
|
-
backend section across this and subsequent candidates)
|
|
460
|
-
5. `.c64bridge.json` in project root → merged into accumulated config
|
|
461
|
-
6. `~/.c64bridge.json` in home directory → merged into accumulated config
|
|
462
|
-
7. Built-in defaults (`c64u:80`, `127.0.0.1:6502`, `x64sc`)
|
|
463
|
-
|
|
464
|
-
---
|
|
465
|
-
|
|
466
|
-
## Acceptance Criteria
|
|
467
|
-
|
|
468
|
-
The implementation is complete when:
|
|
469
|
-
|
|
470
|
-
1. Starting the server with only `{ "vice": { "exe": "/usr/bin/x64sc" } }` in
|
|
471
|
-
`~/.c64bridge.json` and `{ "c64u": { "host": "c64u" } }` in the project root
|
|
472
|
-
results in **both** backends being available and `vice` being selected if
|
|
473
|
-
`C64_MODE=vice` is set (or c64u if not set).
|
|
474
|
-
2. Starting with only `{ "vice": ... }` in `~/.c64bridge.json` and **no** project
|
|
475
|
-
root config results in the vice backend being selected automatically.
|
|
476
|
-
3. `C64U_HOST=192.168.1.99` in the environment overrides the host from any config
|
|
477
|
-
file.
|
|
478
|
-
4. After the server is running with both backends configured, calling the
|
|
479
|
-
`c64_select_backend` tool with `backend: "vice"` returns a success result and
|
|
480
|
-
subsequent tool calls use the vice facade.
|
|
481
|
-
5. Calling `c64_select_backend` with a backend that is not configured returns an
|
|
482
|
-
error result (not a thrown exception) listing which backends are available.
|
|
483
|
-
6. `c64://platform/status` correctly lists available backends and the active one.
|
|
484
|
-
7. `./build coverage` reports ≥ 91% overall.
|
|
485
|
-
8. `plans.md` has every checkbox ticked and `worklog.md` has a completion entry
|
|
486
|
-
for every phase.
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# VICE Backend Switch 2
|
|
2
|
-
|
|
3
|
-
## Goal
|
|
4
|
-
|
|
5
|
-
Make backend switching feel instantaneous in normal LLM-driven use, keep both backends available in one MCP session, and make visible VICE execution match what the MCP server reads programmatically.
|
|
6
|
-
|
|
7
|
-
## Phase 1: Deterministic VICE Launch
|
|
8
|
-
|
|
9
|
-
- Detect and use a valid VICE resource directory automatically instead of assuming the emulator can locate ROMs by itself.
|
|
10
|
-
- Allow explicit VICE resource-directory overrides for local setups that install binaries and ROM assets in different prefixes.
|
|
11
|
-
- Keep visible desktop launches on the user display by default and avoid silent fallback to hidden sessions unless explicitly requested.
|
|
12
|
-
- Add launcher coverage for resource-directory forwarding and startup argument construction.
|
|
13
|
-
|
|
14
|
-
## Phase 2: Always-Ready Mixed Backend Runtime
|
|
15
|
-
|
|
16
|
-
- Make the MCP runtime provision both backends inside one `C64Client` when the session can reasonably address both.
|
|
17
|
-
- Ensure a VICE-first session can still switch to C64U without restarting the MCP server or editing config files mid-session.
|
|
18
|
-
- Preserve platform gating so tools still report accurate compatibility after a switch.
|
|
19
|
-
- Add tests for backend availability and switch behavior in split-config and VICE-first scenarios.
|
|
20
|
-
|
|
21
|
-
## Phase 3: Instant Switch Path
|
|
22
|
-
|
|
23
|
-
- Warm available backends eagerly after MCP startup so the first post-switch tool call does not pay process-start or probe penalties.
|
|
24
|
-
- Serialize VICE monitor access so concurrent tool calls cannot double-start VICE or race the single-client Binary Monitor transport.
|
|
25
|
-
- Keep `c64_select_backend` as a local state change only: no probing, no process launch, no extra round trips.
|
|
26
|
-
- Add tests for eager warmup behavior and race-free VICE access where feasible.
|
|
27
|
-
|
|
28
|
-
## Phase 4: End-to-End Validation
|
|
29
|
-
|
|
30
|
-
- Validate the MCP flow exactly as an LLM would use it: switch backend, run BASIC, read the screen, switch back, repeat.
|
|
31
|
-
- Measure switch-plus-run behavior and confirm the steady-state switch path stays under two seconds on this machine.
|
|
32
|
-
- Confirm that VICE visibly shows the same BASIC screen state that MCP reports from screen RAM.
|
|
33
|
-
- Update user-facing docs and config metadata for the new VICE launch controls.
|
|
34
|
-
|
|
35
|
-
## Phase 5: Environment Override Consistency
|
|
36
|
-
|
|
37
|
-
- Ensure every documented runtime environment variable in `mcp.json` is actually honored when the server is launched from a user-provided MCP client config such as `.vscode/mcp.json`.
|
|
38
|
-
- Make the override model consistent: environment variable override first, merged JSON config next when applicable, built-in defaults last.
|
|
39
|
-
- Keep a generated README table of all supported runtime environment variables, their defaults, and any JSON config key they override.
|
|
40
|
-
- Add concrete `.vscode/mcp.json` examples so it is obvious which settings are env-only flags and which map to JSON config fields.
|
|
41
|
-
|
|
42
|
-
## Success Criteria
|
|
43
|
-
|
|
44
|
-
- `c64_select_backend` returns immediately for already provisioned backends.
|
|
45
|
-
- A VICE-configured session can switch to C64U and back without restarting the server.
|
|
46
|
-
- VICE starts visibly on the desktop with a usable C64 screen instead of an inert grey window caused by missing resources.
|
|
47
|
-
- `vice: run HELLO WORLD` and `c64u: run HELLO WORLD` both work through the grouped MCP tools.
|
|
48
|
-
- Repeated backend switches in one MCP session remain stable and do not spawn duplicate VICE processes.
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
# Vice Support — Working Notes
|
|
2
|
-
|
|
3
|
-
These notes summarize the current state of VICE support in the MCP server, gaps vs. C64U REST, and design constraints for a robust Binary Monitor (BM) integration.
|
|
4
|
-
|
|
5
|
-
## Current State (as of this branch)
|
|
6
|
-
|
|
7
|
-
- Backend abstraction exists (`src/device.ts`) with a `ViceBackend` facade, but it only supports:
|
|
8
|
-
- `runPrg(prg)` and `runPrgFile(path)` by spawning `x64sc` with `-autostart -warp -silent`.
|
|
9
|
-
- Everything else throws `UNSUPPORTED` (memory, system control, config, drives, etc.).
|
|
10
|
-
- A VICE runner utility exists for SID → WAV capture (`src/viceRunner.ts`) but is unrelated to BM.
|
|
11
|
-
- Tools mark some operations as `supportedPlatforms: ["c64u", "vice"]`, yet under VICE most calls fail because the facade is a stub.
|
|
12
|
-
- `read_screen` relies on `client.readMemoryRaw` (screen RAM at `$0400`), which currently fails on the VICE path because `ViceBackend.readMemory` is unsupported.
|
|
13
|
-
|
|
14
|
-
## Protocol & Feature Parity Summary
|
|
15
|
-
|
|
16
|
-
Reference docs:
|
|
17
|
-
|
|
18
|
-
- VICE Binary Monitor protocol: `doc/vice/vice-binary-monitor-spec.md`
|
|
19
|
-
- Comparison: `doc/vice/vice-bm-vs-c64u-rest.md`
|
|
20
|
-
|
|
21
|
-
Key signals from the comparison:
|
|
22
|
-
|
|
23
|
-
- BM excels at debugger primitives: memory read/write, breakpoints, single-stepping, register IO, display framebuffer, palette, keyboard feed.
|
|
24
|
-
- C64U REST excels at hardware orchestration: DMA-based program runners, drive management, persistent configuration, audio/video/debug streaming.
|
|
25
|
-
- Overlap areas: reset and memory IO are available in both; semantics differ (BM supports memspaces and banks, REST exposes a flattened DMA map).
|
|
26
|
-
|
|
27
|
-
Implications for MCP:
|
|
28
|
-
|
|
29
|
-
- We can deliver strong memory/screen/debug flows via BM under VICE.
|
|
30
|
-
- We cannot reasonably replicate drive management, file image creation, streams, or Ultimate firmware configuration on VICE; these remain unsupported or receive emulator-specific resource controls (VICE "resources").
|
|
31
|
-
- Program execution can be handled in two ways under VICE:
|
|
32
|
-
1) BM RAM injection on a long‑lived process (default): fast, DMA‑like, precise control.
|
|
33
|
-
2) BM `0xDD` Autostart (fallback): file‑based, minimal pointer logic.
|
|
34
|
-
3) Per‑run `x64sc -autostart` spawn (last resort): slowest; avoids long‑lived state.
|
|
35
|
-
- For tests, provide a BM stub controlled via `VICE_TEST_TARGET=mock`; default behavior is to use real VICE when available.
|
|
36
|
-
2) Manage a long‑lived VICE process with BM and implement Autostart (`0xDD`) or direct program injection + `Keyboard Feed` for `RUN` (faster iteration, enables pause/step/breakpoints).
|
|
37
|
-
|
|
38
|
-
## Design Constraints & Decisions
|
|
39
|
-
|
|
40
|
-
- Single monitor client at a time: BM accepts one TCP client; keep a singleton session and serialize requests.
|
|
41
|
-
- Pause/resume semantics: the BM halts CPU while processing; explicitly resume (`0xAA Exit`) between polling reads so emulation continues (used in readiness helpers and smoke test).
|
|
42
|
-
- Request/response framing: implement strict STX, API version (use `0x02`), length, request ID, and per‑command bodies; buffer and parse responses until the expected `(cmdId, reqId)` is observed.
|
|
43
|
-
- Timeouts and error mapping: translate BM error codes (0x80–0x8F) into `ToolExecutionError` details; implement clear timeout and ECONNREFUSED handling.
|
|
44
|
-
- Screen capture: map `read_screen` to deferred memory reads of `$0400..$07E7` and conversion via `screenCodesToAscii`; later, optionally provide framebuffer snapshots via `0x84`.
|
|
45
|
-
- Keyboard automation: use `0x72` for `RUN`/`RETURN` when injecting BASIC; require API header `0x02`.
|
|
46
|
-
- Safety: do not emulate hardware operations that do not exist on VICE (drives, poweroff); leave them unsupported with explicit messages.
|
|
47
|
-
|
|
48
|
-
## Viability Evidence
|
|
49
|
-
|
|
50
|
-
- `test/vice/viceSmokeTest.ts` (TS) demonstrates hard/soft reset, memory write/read, keyboard feed, screen polling with resume hooks, and clean process teardown (visible or headless).
|
|
51
|
-
|
|
52
|
-
## Scope Clarifications
|
|
53
|
-
|
|
54
|
-
- Long‑lived VICE process: the default workflow keeps a supervised emulator running and injects programs into RAM for speed and parity with C64U DMA.
|
|
55
|
-
- Autostart remains an optional fallback (BM `0xDD`) but is not the default. Per‑run spawn is a last resort.
|
|
56
|
-
- `src/viceRunner.ts` is kept for SID→WAV audio export only; general VICE control is implemented behind the facade using `src/vice/viceClient.ts` + `src/vice/readiness.ts` and a supervisor.
|
|
57
|
-
|
|
58
|
-
## Targeted Scope per Phase (high level)
|
|
59
|
-
|
|
60
|
-
1) Core BM client + memory/screen + reset + pause/resume (keep current ephemeral PRG runner).
|
|
61
|
-
2) Long‑lived VICE process mgmt + Autostart (`0xDD`) or injection + keyboard feed; stable program runners; keyboard tool.
|
|
62
|
-
3) Debugger features: breakpoints, stepping, registers; bank/memspace awareness surfaced; optional display get.
|
|
63
|
-
4) Emulator resources & display capture polish; finalize platform descriptors and docs.
|