c64bridge 0.5.1 → 0.6.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.
Files changed (48) hide show
  1. package/README.md +17 -5
  2. package/data/assembly/assembly-spec.md +24 -0
  3. package/data/assembly/examples/video/hello_world.asm +39 -0
  4. package/data/basic/basic-pitfalls.md +236 -0
  5. package/data/basic/basic-spec.md +507 -198
  6. package/data/video/petscii-style-guide.md +105 -0
  7. package/data/video/sprite-charset-best-practices.md +292 -0
  8. package/dist/c64Client.js +1 -0
  9. package/dist/prompts/registry.js +10 -2
  10. package/dist/rag/knowledgeIndex.js +111 -24
  11. package/dist/rag/retriever.js +110 -4
  12. package/dist/tools/audio.js +26 -13
  13. package/dist/tools/developer.js +34 -0
  14. package/dist/tools/graphics.js +6 -5
  15. package/dist/tools/memory.js +1 -1
  16. package/dist/tools/pollValidator.js +256 -0
  17. package/dist/tools/programRunners.js +352 -12
  18. package/dist/tools/rag.js +1 -7
  19. package/doc/MCP_SETUP.md +7 -1
  20. package/doc/bun/baseline-metrics.md +16 -0
  21. package/doc/bun/migration-checklist.md +55 -0
  22. package/doc/bun/migration.md +83 -0
  23. package/doc/developer.md +72 -10
  24. package/doc/improve-knowledge/notes.md +29 -0
  25. package/doc/improve-knowledge/plan.md +28 -3
  26. package/doc/improve-knowledge/rollout.md +39 -5
  27. package/doc/meta-tools/README.md +101 -0
  28. package/doc/meta-tools/analysis.md +255 -0
  29. package/doc/{meta-tools.md → meta-tools/catalog.md} +2 -2
  30. package/doc/meta-tools/notes.md +174 -0
  31. package/doc/meta-tools/rollout.md +343 -0
  32. package/mcp.json +1 -1
  33. package/package.json +17 -10
  34. package/scripts/c64-cli.mjs +42 -7
  35. package/scripts/c64-tool.sh +7 -1
  36. package/scripts/check-node-compat.mjs +107 -0
  37. package/scripts/invoke-bun.mjs +58 -0
  38. package/scripts/rag-rebuild.mjs +11 -13
  39. package/scripts/run-mcp-check.sh +10 -2
  40. package/scripts/run-tests.mjs +3 -3
  41. package/scripts/run-tests.ts +187 -0
  42. package/scripts/start.mjs +3 -26
  43. package/scripts/update-readme.ts +17 -1
  44. package/scripts/verify-package.mjs +0 -1
  45. package/data/assembly/examples/effects/sinewave.asm +0 -5
  46. package/doc/meta-tools-rollout.md +0 -211
  47. package/scripts/register-ts-node.mjs +0 -6
  48. /package/data/assembly/examples/{graphics/sprite/mover.asm → video/sprite_mover.asm} +0 -0
@@ -21,24 +21,22 @@ async function main() {
21
21
  let LocalMiniHashEmbedding;
22
22
  let buildAllIndexes;
23
23
 
24
- if (await fileExists(distEmbeddings) && await fileExists(distIndexer)) {
24
+ const isBun = typeof globalThis.Bun !== 'undefined';
25
+
26
+ if (!isBun && await fileExists(distEmbeddings) && await fileExists(distIndexer)) {
25
27
  const em = await import(pathToFileURL(distEmbeddings).href);
26
28
  const ix = await import(pathToFileURL(distIndexer).href);
27
29
  LocalMiniHashEmbedding = em.LocalMiniHashEmbedding;
28
30
  buildAllIndexes = ix.buildAllIndexes;
31
+ } else if (isBun) {
32
+ const em = await import(pathToFileURL(path.join(projectRoot, 'src', 'rag', 'embeddings.ts')).href);
33
+ const ix = await import(pathToFileURL(path.join(projectRoot, 'src', 'rag', 'indexer.ts')).href);
34
+ LocalMiniHashEmbedding = em.LocalMiniHashEmbedding;
35
+ buildAllIndexes = ix.buildAllIndexes;
29
36
  } else {
30
- // Fall back to TypeScript sources via ts-node when available
31
- try {
32
- await import('./register-ts-node.mjs');
33
- const em = await import(pathToFileURL(path.join(projectRoot, 'src', 'rag', 'embeddings.ts')).href);
34
- const ix = await import(pathToFileURL(path.join(projectRoot, 'src', 'rag', 'indexer.ts')).href);
35
- LocalMiniHashEmbedding = em.LocalMiniHashEmbedding;
36
- buildAllIndexes = ix.buildAllIndexes;
37
- } catch (err) {
38
- console.error('[rag-rebuild] Unable to load RAG modules from dist or src:', err);
39
- process.exit(1);
40
- return;
41
- }
37
+ console.error('[rag-rebuild] Unable to locate compiled artifacts. Run `bun run build` (or `npm run build`) before invoking this script under Node.');
38
+ process.exit(1);
39
+ return;
42
40
  }
43
41
 
44
42
  const dim = Number(process.env.RAG_EMBED_DIM ?? 384);
@@ -15,6 +15,14 @@ TMPDIR=$(mktemp -d)
15
15
  MOCK_INFO="$TMPDIR/mock-info.json"
16
16
  CFG_FILE="$TMPDIR/.c64bridge.json"
17
17
 
18
+ if command -v bun >/dev/null 2>&1; then
19
+ BUILD_CMD=(bun run build)
20
+ elif [[ -x "${HOME}/.bun/bin/bun" ]]; then
21
+ BUILD_CMD=("${HOME}/.bun/bin/bun" run build)
22
+ else
23
+ BUILD_CMD=(npm run build)
24
+ fi
25
+
18
26
  cleanup() {
19
27
  set +e
20
28
  [[ -n "${MCP_PID:-}" ]] && kill -TERM "$MCP_PID" 2>/dev/null || true
@@ -68,7 +76,7 @@ echo "==> Starting MCP server in '$MODE' mode for $DURATION seconds..."
68
76
  echo "==> Logs will be written to: $(realpath "$LOGFILE")"
69
77
 
70
78
  if [[ "$MODE" == "local" ]]; then
71
- (cd "$ROOT_DIR" && npm run build)
79
+ (cd "$ROOT_DIR" && "${BUILD_CMD[@]}")
72
80
  VERSION=$(node -p "require('$ROOT_DIR/package.json').version")
73
81
  echo "==> Running local build version $VERSION"
74
82
  (cd "$ROOT_DIR" && node dist/index.js) 2>&1 | tee "$LOGFILE" &
@@ -101,4 +109,4 @@ else
101
109
  exit 1
102
110
  fi
103
111
 
104
- echo "==> Run complete. Logs saved to: $(realpath "$LOGFILE")"
112
+ echo "==> Run complete. Logs saved to: $(realpath "$LOGFILE")"
@@ -3,15 +3,15 @@ import { spawn } from "node:child_process";
3
3
  import fs from "node:fs";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
6
- import { fileURLToPath, pathToFileURL } from "node:url";
6
+ import { fileURLToPath } from "node:url";
7
7
 
8
8
  const DEFAULT_TARGET = "mock";
9
9
 
10
10
  let target = DEFAULT_TARGET;
11
11
  let explicitBaseUrl = null;
12
12
  const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
13
- const registerSpec = pathToFileURL(path.join(repoRoot, "scripts", "register-ts-node.mjs")).href;
14
- const nodeArgs = ["--import", registerSpec, "--test"];
13
+ const registerDataUri = "data:text/javascript,import { register } from \"node:module\"; import { pathToFileURL } from \"node:url\"; register(\"ts-node/esm\", pathToFileURL(\"./\"));";
14
+ const nodeArgs = ["--import", registerDataUri, "--test"];
15
15
 
16
16
  for (const arg of process.argv.slice(2)) {
17
17
  if (arg === "--mock") {
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env bun
2
+ import path from "node:path";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import process from "node:process";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const DEFAULT_TARGET = "mock";
9
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
10
+ const defaultEmbeddingsDir = path.join(repoRoot, "artifacts", "test-embeddings");
11
+
12
+ let target = DEFAULT_TARGET;
13
+ let explicitBaseUrl: string | null = null;
14
+ let runCoverage = false;
15
+ const passthrough: string[] = [];
16
+
17
+ for (const arg of process.argv.slice(2)) {
18
+ if (arg === "--mock") {
19
+ target = "mock";
20
+ continue;
21
+ }
22
+ if (arg === "--real") {
23
+ target = "real";
24
+ continue;
25
+ }
26
+ if (arg.startsWith("--target=")) {
27
+ target = arg.split("=", 2)[1] ?? DEFAULT_TARGET;
28
+ continue;
29
+ }
30
+ if (arg.startsWith("--base-url=")) {
31
+ explicitBaseUrl = arg.split("=", 2)[1] ?? null;
32
+ continue;
33
+ }
34
+ if (arg === "--coverage") {
35
+ runCoverage = true;
36
+ continue;
37
+ }
38
+ passthrough.push(arg);
39
+ }
40
+
41
+ if (!fs.existsSync(defaultEmbeddingsDir)) {
42
+ fs.mkdirSync(defaultEmbeddingsDir, { recursive: true });
43
+ }
44
+
45
+ const env: Record<string, string> = { ...process.env } as Record<string, string>;
46
+ env.C64_TEST_TARGET = target;
47
+ if (!env.RAG_EMBEDDINGS_DIR) {
48
+ env.RAG_EMBEDDINGS_DIR = defaultEmbeddingsDir;
49
+ }
50
+ if (explicitBaseUrl) {
51
+ env.C64_TEST_BASE_URL = explicitBaseUrl;
52
+ }
53
+ if (target === "real" && !env.C64_TEST_BASE_URL) {
54
+ env.C64_TEST_BASE_URL = resolveBaseUrlFromConfig() ?? "http://c64u";
55
+ }
56
+
57
+ const bunExecutable = process.execPath;
58
+ const cmd = [
59
+ bunExecutable,
60
+ "test",
61
+ ...(runCoverage
62
+ ? [
63
+ "--coverage",
64
+ // Ensure LCOV is emitted for Codecov
65
+ "--coverage-reporter=lcov",
66
+ // Use supported console reporter in Bun
67
+ "--coverage-reporter=text",
68
+ ]
69
+ : []),
70
+ ...passthrough,
71
+ ];
72
+ const child = Bun.spawn({
73
+ cmd,
74
+ cwd: repoRoot,
75
+ env,
76
+ stdout: "inherit",
77
+ stderr: "inherit",
78
+ });
79
+
80
+ const exitCode = await child.exited;
81
+ process.exit(typeof exitCode === "number" ? exitCode : 1);
82
+
83
+ function resolveBaseUrlFromConfig(): string | null {
84
+ const configPathEnv = env.C64BRIDGE_CONFIG;
85
+ const homeConfig = os.homedir() ? path.join(os.homedir(), ".c64bridge.json") : null;
86
+ const repoConfig = path.join(repoRoot, ".c64bridge.json");
87
+ for (const candidate of [configPathEnv, homeConfig, repoConfig]) {
88
+ if (!candidate) continue;
89
+ try {
90
+ const raw = JSON.parse(fs.readFileSync(candidate, "utf8"));
91
+ const base = resolveBaseUrlFromJson(raw);
92
+ if (base) return base;
93
+ } catch (error) {
94
+ if (isSystemError(error) && error.code === "ENOENT") {
95
+ continue;
96
+ }
97
+ console.warn(`[run-tests] Failed to read config at ${candidate}:`, error);
98
+ }
99
+ }
100
+ return null;
101
+ }
102
+
103
+ function resolveBaseUrlFromJson(raw: unknown): string | null {
104
+ if (!raw || typeof raw !== "object") return null;
105
+ const root = raw as Record<string, unknown>;
106
+ const c64u = root.c64u;
107
+ if (c64u && typeof c64u === "object") {
108
+ const base = stringIfSet((c64u as Record<string, unknown>).baseUrl);
109
+ if (base) return normalizeBase(base);
110
+ const hostEntry = firstDefined(
111
+ stringIfSet((c64u as Record<string, unknown>).host),
112
+ stringIfSet((c64u as Record<string, unknown>).hostname),
113
+ );
114
+ const parsed = parseEndpoint(hostEntry);
115
+ const port = firstDefined(numberIfPort((c64u as Record<string, unknown>).port), parsed.port, DEFAULT_PORT);
116
+ if (parsed.hostname) {
117
+ return buildBaseUrl(parsed.hostname, port);
118
+ }
119
+ }
120
+ const legacyBase = stringIfSet(root.baseUrl);
121
+ if (legacyBase) return normalizeBase(legacyBase);
122
+ const legacyHost = firstDefined(stringIfSet(root.c64_host), stringIfSet(root.c64_ip));
123
+ if (legacyHost) {
124
+ const parsed = parseEndpoint(legacyHost);
125
+ const port = firstDefined(parsed.port, DEFAULT_PORT);
126
+ const hostname = parsed.hostname ?? legacyHost;
127
+ return buildBaseUrl(hostname, port);
128
+ }
129
+ return null;
130
+ }
131
+
132
+ function stringIfSet(value: unknown): string | null {
133
+ return typeof value === "string" && value.trim() ? value.trim() : null;
134
+ }
135
+
136
+ function numberIfPort(value: unknown): number | null {
137
+ if (typeof value === "number" && Number.isInteger(value) && value > 0 && value <= 65535) {
138
+ return value;
139
+ }
140
+ if (typeof value === "string" && value.trim()) {
141
+ const parsed = Number(value.trim());
142
+ if (Number.isInteger(parsed) && parsed > 0 && parsed <= 65535) {
143
+ return parsed;
144
+ }
145
+ }
146
+ return null;
147
+ }
148
+
149
+ function normalizeBase(input: string): string {
150
+ return /^[a-z][a-z0-9+.-]*:\/\//i.test(input) ? input.replace(/\/+$/, "") : `http://${input}`;
151
+ }
152
+
153
+ function parseEndpoint(value: string | null): { hostname?: string; port?: number } {
154
+ const input = value && value.trim() ? value.trim() : null;
155
+ if (!input) return {};
156
+ try {
157
+ const hasScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(input);
158
+ const url = new URL(hasScheme ? input : `http://${input}`);
159
+ const hostname = url.hostname || undefined;
160
+ const port = url.port ? numberIfPort(url.port) ?? undefined : undefined;
161
+ return { hostname, port };
162
+ } catch {
163
+ return {};
164
+ }
165
+ }
166
+
167
+ const DEFAULT_PORT = 80;
168
+
169
+ function buildBaseUrl(host: string, port: number | undefined): string {
170
+ const normalizedPort = Number.isInteger(port) && (port as number) > 0 ? (port as number) : DEFAULT_PORT;
171
+ const hostPart = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
172
+ const suffix = normalizedPort === DEFAULT_PORT ? "" : `:${normalizedPort}`;
173
+ return `http://${hostPart}${suffix}`;
174
+ }
175
+
176
+ function firstDefined<T>(...values: Array<T | undefined | null>): T | undefined {
177
+ for (const value of values) {
178
+ if (value !== undefined && value !== null) {
179
+ return value;
180
+ }
181
+ }
182
+ return undefined;
183
+ }
184
+
185
+ function isSystemError(error: unknown): error is NodeJS.ErrnoException {
186
+ return Boolean(error && typeof error === "object" && "code" in error);
187
+ }
package/scripts/start.mjs CHANGED
@@ -27,36 +27,13 @@ async function fileExists(filePath) {
27
27
  }
28
28
  }
29
29
 
30
- function isModuleNotFound(error) {
31
- if (!error || typeof error !== 'object') {
32
- return false;
33
- }
34
- const err = error;
35
- if (err.code === 'ERR_MODULE_NOT_FOUND') {
36
- return true;
37
- }
38
- const message = typeof err.message === 'string' ? err.message : '';
39
- return message.includes('Cannot find module');
40
- }
41
-
42
30
  async function launch() {
43
31
  const srcEntry = path.resolve(projectRoot, 'src/index.ts');
44
32
  const distEntry = path.resolve(projectRoot, 'dist/index.js');
45
33
 
46
- if (await fileExists(srcEntry)) {
47
- try {
48
- await import('./register-ts-node.mjs');
49
- await import(pathToFileURL(srcEntry).href);
50
- return;
51
- } catch (error) {
52
- if (isModuleNotFound(error)) {
53
- console.warn('[start] ts-node not available; falling back to compiled output.');
54
- } else {
55
- console.error('[start] Failed to launch TypeScript sources:', error);
56
- process.exitCode = 1;
57
- return;
58
- }
59
- }
34
+ if (typeof globalThis.Bun !== 'undefined' && await fileExists(srcEntry)) {
35
+ await import(pathToFileURL(srcEntry).href);
36
+ return;
60
37
  }
61
38
 
62
39
  if (await fileExists(distEntry)) {
@@ -126,8 +126,24 @@ function renderPromptsSection(): string[] {
126
126
  ];
127
127
  }
128
128
 
129
+ function renderSummarySection(): string[] {
130
+ const modules = describeToolModules();
131
+ const resources = listKnowledgeResources();
132
+ const promptRegistry = createPromptRegistry();
133
+ const prompts = promptRegistry.list();
134
+
135
+ const toolCount = modules.reduce((sum, module) => sum + module.tools.length, 0);
136
+ const resourceCount = resources.length;
137
+ const promptCount = prompts.length;
138
+
139
+ return [
140
+ `This MCP server exposes **${toolCount} tools**, **${resourceCount} resources**, and **${promptCount} prompts** for controlling your Commodore 64.`,
141
+ "",
142
+ ];
143
+ }
144
+
129
145
  function buildDocumentation(): string {
130
- const sections = [renderToolsSection(), renderResourcesSection(), renderPromptsSection()];
146
+ const sections = [renderSummarySection(), renderToolsSection(), renderResourcesSection(), renderPromptsSection()];
131
147
  return sections.flat().join("\n").trim();
132
148
  }
133
149
 
@@ -46,7 +46,6 @@ function assertSpotChecks() {
46
46
  'generated/c64/index.js',
47
47
  'scripts/cli.js',
48
48
  'scripts/start.mjs',
49
- 'scripts/register-ts-node.mjs',
50
49
  ];
51
50
  const dirs = [
52
51
  'doc',
@@ -1,5 +0,0 @@
1
- *= $0801
2
- LDA #$00
3
- LOOP STA $D020
4
- ADC #$01
5
- JMP LOOP
@@ -1,211 +0,0 @@
1
- ## Meta Tools Rollout Plan for c64bridge
2
-
3
- Purpose: Provide a concrete, dependency-aware rollout approach for the meta tools defined in `doc/meta-tools.md`. This plan gives ordered, checkable task lists and high-level implementation notes. It is written so another LLM can execute the rollout autonomously.
4
-
5
- ### Required reading
6
-
7
- The following documents need to be read and understood before starting the rollout:
8
-
9
- - `doc/meta-tools.md` — Meta tools definitions, effort/benefit/dependencies matrix
10
- - `doc/agent-state-spec.md` — Background task registry and persistence model
11
- - `doc/developer.md` — Architecture overview and contribution guidelines
12
-
13
- ### Operator rules for the LLM performing the rollout
14
-
15
- - Always work tasks strictly in order as listed. Do not skip ahead unless a task is cancelled.
16
- - After each checklist item, run the full build and test suite and proceed only if it passes:
17
- - Preferred: `npm run check` (build + tests) or `npm test` if already built.
18
- - If tests fail:
19
- - Fix the cause if obvious and retry once.
20
- - If still failing, revert the last change and leave a short note in the status log, then stop.
21
- - Keep edits minimal and focused. Prefer small, incremental changes.
22
- - Update documentation in the same change when tool behavior or surface changes.
23
- - For any new code, add/extend tests that cover basic happy path and one failure path.
24
- - Respect device-affecting safeguards already in the codebase (pause/resume, stream mutual exclusion, time limits).
25
-
26
- ### Global implementation template (apply per meta tool)
27
-
28
- - [ ] Read the tool’s entry in `doc/meta-tools.md` and its Effort/Benefit/Dependencies.
29
- - [ ] Verify prerequisites (dependencies implemented). If missing, pause and complete dependencies first.
30
- - [ ] Implement the meta tool wrapper in the MCP server (compose existing low-level tools; avoid firmware-only assumptions).
31
- - [ ] Add or extend unit/integration tests for the meta tool’s happy path and a basic failure case.
32
- - [ ] Update docs: ensure the tool’s documentation is aligned; add usage hints if applicable.
33
- - [ ] Run full build + tests: `npm run check` must pass.
34
-
35
- Notes:
36
-
37
- - Do not expand the REST surface; meta tools must compose existing MCP tools.
38
- - Ensure mutual exclusion where streams and debug capture conflict.
39
- - Enforce timeouts and guardrails for background/scheduled operations.
40
-
41
- ---
42
-
43
- ### Phase 0 — Foundations (low-effort, high-benefit, unlocks others)
44
-
45
- - [x] `firmware_info_and_healthcheck` — Implementation notes:
46
- - Compose version, info, and a tiny `readmem` probe. Return structured readiness.
47
- - Use short, bounded timeouts; capture latency metrics.
48
- - [x] `wait_for_screen_text` — Implementation notes:
49
- - Poll screen RAM via existing helper; support regex and plain text. Provide timeout and interval.
50
- - Return match bounds and elapsed time.
51
- - [x] `verify_and_write_memory` — Implementation notes:
52
- - Pause → read → verify → write → read-back → resume. Abort on mismatch.
53
- - Parameterize verification masks and expected buffer; return a diff when failing.
54
- - [x] `start_background_task` / `stop_background_task` / `list_background_tasks` / `stop_all_background_tasks` — Implementation notes:
55
- - Implement a persistent registry (in-memory with serialized state to disk if available).
56
- - Support fixed-interval scheduling and a maximum iterations cap.
57
- - [x] `find_paths_by_name` — Implementation notes:
58
- - Container-aware discovery using wildcard info endpoints; return host and logical paths.
59
- - Cache recent results with a short TTL to avoid repeated scans.
60
- - [x] `memory_dump_to_file` — Implementation notes:
61
- - Chunked reads with retries; optional pause/resume. Support hex and binary formats.
62
- - Emit a checksum and write a manifest alongside the dump.
63
- - [x] `config_snapshot_and_restore` — Implementation notes:
64
- - Read all categories, persist versioned JSON; support batch restore and diff preview.
65
-
66
- Requirement: After each checkbox completion, run `npm run check` and proceed only on success.
67
-
68
- ---
69
-
70
- ### Phase 1 — Orchestration and assertions
71
-
72
- - [x] `program_shuffle` — Implementation notes:
73
- - Discover PRG/CRT under root; run each for a duration; capture screen; soft reset.
74
- - Persist a light run log per program.
75
- - [x] `batch_run_with_assertions` — Implementation notes:
76
- - Accept assertions: screen contains text, memory equals byte, SID silent.
77
- - Produce junit-like results; stop on failure or continue-on-error per flag.
78
- - [x] `bundle_run_artifacts` — Implementation notes:
79
- - Gather screen, memory snapshot, debugreg; structure outputs per run id.
80
- - [x] `compile_run_verify_cycle` — Implementation notes:
81
- - Support BASIC/ASM/SID build routes; then run and verify via screen/audio.
82
- - Archive artifacts in a run folder.
83
-
84
- ---
85
-
86
- ### Phase 2 — Filesystem and drives
87
-
88
- - [ ] `drive_mount_and_verify` — Implementation notes:
89
- - Power on if needed; mount; reset; verify via drives list. Retry with backoff.
90
- - [ ] `create_and_mount_blank_d64` — Implementation notes:
91
- - Create blank D64; mount; optional BASIC header writer.
92
- - [ ] `container_aware_walk_and_classify` — Implementation notes:
93
- - Recurse host and container entries; classify BASIC vs PRG-MC via load + read.
94
- - [ ] `classify_prg_basic_or_mc` — Implementation notes:
95
- - For a single PRG; detect BASIC tokenization from header bytes.
96
- - [ ] `filesystem_stats_by_extension` — Implementation notes:
97
- - Compute counts and sizes; rollups per extension and per-folder/container.
98
- - [ ] `dedup_scan` — Implementation notes:
99
- - Group by size and extension; optional normalized names; optional hash when available.
100
- - [ ] `dedup_plan_and_apply` — Implementation notes:
101
- - Produce reversible quarantine plan; default dry-run; require explicit confirm to apply.
102
-
103
- Optional in this phase:
104
-
105
- - [ ] `drive_mode_profile_switch`
106
- - [ ] `eject_and_poweroff_drive`
107
-
108
- ---
109
-
110
- ### Phase 3 — Graphics and screen pipelines
111
-
112
- - [ ] `extract_sprites_from_ram` — Implementation notes:
113
- - Search with stride for 63-byte sprite patterns; export `.spr`/hex/base64.
114
- - [ ] `rip_charset_from_ram` — Implementation notes:
115
- - Locate 2KB charsets by structure; export binary and a PNG preview.
116
- - [ ] `screen_capture_timeline` — Implementation notes:
117
- - Timed captures; export timestamped log and optional GIF.
118
- - [ ] `sprite_preview_prg_batch` — Implementation notes:
119
- - Generate+run preview PRGs for many sprite blobs; capture screens.
120
-
121
- ---
122
-
123
- ### Phase 4 — SID and audio
124
-
125
- - [ ] `silence_and_verify` — Implementation notes:
126
- - Write SID reset/silence; record short audio; verify threshold.
127
- - [ ] `music_compile_play_analyze` — Implementation notes:
128
- - Compile SIDWAVE→PRG or SID; play; record; analyze; save JSON.
129
- - [ ] `sid_param_sweep` — Implementation notes:
130
- - Sweep ADSR/waveform/pulse width; schedule notes; analyze; score.
131
-
132
- ---
133
-
134
- ### Phase 5 — Debug stream workflows (post‑GA)
135
-
136
- - Prerequisites (must be satisfied before starting this phase):
137
- - UDP ingest pipeline with backpressure and packet‑loss handling.
138
- - Sampling/windowing design for high‑rate streams and summary accuracy.
139
- - Performance targets validated via load and soak tests.
140
- - Observability and failure‑mode coverage (metrics, logs, alerts, drop counters).
141
- - [ ] `debug_stream_watch` — Implementation notes:
142
- - Start/stop; summarize rates; enforce mutual exclusion with video stream.
143
- - [ ] `debug_loop_run_and_capture` — Implementation notes:
144
- - Pause → start debug → resume → action → pause → stop → summarize packets.
145
- - Support modes: 6510, VIC, 1541; choose minimal scope by default.
146
- - [ ] `verify_raster_irq_line` — Implementation notes:
147
- - Correlate writes to $D012/$D011 and IRQ ack; configurable tolerance.
148
- - [ ] `debug_trace_until_cpu_write` — Implementation notes:
149
- - Watch address set; freeze a pre/post window when first write observed.
150
- - [ ] `action_latency_measure` — Implementation notes:
151
- - Timestamp action issue and first matching event; compute cycles/µs.
152
-
153
- Optional follow-ons in this phase (implement after above pass):
154
-
155
- - [ ] `verify_irq_jitter`
156
- - [ ] `sid_register_write_profile`
157
- - [ ] `iec_bus_handshake_probe`
158
- - [ ] `time_bounded_trace_around_event`
159
-
160
- ---
161
-
162
- ### Phase 6 — Developer and recovery loops
163
-
164
- - [ ] `red_green_refactor_loop` — Implementation notes:
165
- - Iterate: run → capture screen → write_memory fixes → rerun until pass.
166
- - [ ] `multi_range_guardrails` — Implementation notes:
167
- - Continuously verify invariants; auto-restore from snapshot on violations.
168
- - [ ] `safe_reset_sequence` — Implementation notes:
169
- - Snapshot select ranges; reset; compare persistence; resume.
170
- - [ ] `drive_recovery_sequence` — Implementation notes:
171
- - Detect error; reset; power cycle; remount last image; verify.
172
-
173
- ---
174
-
175
- ### RAG-coupled meta tools
176
-
177
- - [ ] `ask_and_apply_memory_fix` — Implementation notes:
178
- - Retrieve assembly guidance (RAG), compute targeted writes, then `verify_and_write_memory`.
179
- - [ ] `sprite_program_from_prompt` — Implementation notes:
180
- - Generate PETSCII/sprite asset from text; preview PRG; capture screen.
181
-
182
- ---
183
-
184
- ### Optional follow-ups and experiments
185
-
186
- - [ ] `memory_heatmap_over_time`
187
- - [ ] `irq_latency_probe`
188
- - [ ] `sid_voice_stuck_guard`
189
- - [ ] `auto_benchmark_suite`
190
- - [ ] `firmware_compat_matrix`
191
- - [ ] `ultimate_config_migrate`
192
-
193
- ---
194
-
195
- ### Per-task Done Definition (LLM must verify before ticking)
196
-
197
- - Implementation compiles with no TypeScript errors (where applicable).
198
- - New/updated tests exist and are passing locally.
199
- - `npm run check` passes end-to-end.
200
- - Documentation updated if tool behavior changed.
201
-
202
- ### How to tick off checkboxes (LLM instructions)
203
-
204
- - After completing a checklist item and confirming the Done Definition, update the corresponding `- [ ]` line to `- [x]` in `doc/meta-tools-rollout.md`.
205
- - Only tick one line at a time, from top to bottom, respecting phases and dependencies.
206
- - After ticking, immediately run `npm run check` again to ensure that the documentation update did not break formatting-sensitive scripts.
207
-
208
- ### Notes on sequencing
209
-
210
- - Respect the dependency graph from `doc/meta-tools.md` (Effort/Benefit/Dependencies Matrix).
211
- - Within a phase, process items in order. If an item depends on another not yet done, jump to the dependency’s phase, complete it, then resume.
@@ -1,6 +0,0 @@
1
- import { register } from "node:module";
2
-
3
- // Register ts-node ESM loader using the recommended `register` API to avoid
4
- // the experimental loader warning shown during CI runs.
5
- const projectRootUrl = new URL("../", import.meta.url);
6
- register("ts-node/esm", projectRootUrl);