c64bridge 1.0.6 → 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.
Files changed (136) hide show
  1. package/.github/skills/assembly-program/SKILL.md +37 -0
  2. package/.github/skills/basic-program/SKILL.md +40 -0
  3. package/.github/skills/cross-platform-demo/SKILL.md +32 -0
  4. package/.github/skills/drive-manager/SKILL.md +33 -0
  5. package/.github/skills/graphics-demo/SKILL.md +30 -0
  6. package/.github/skills/hello-world/SKILL.md +36 -0
  7. package/.github/skills/memory-debug/SKILL.md +32 -0
  8. package/.github/skills/pr-converge/SKILL.md +33 -0
  9. package/.github/skills/printer-job/SKILL.md +30 -0
  10. package/.github/skills/sid-music/SKILL.md +35 -0
  11. package/.github/skills/software-launch/SKILL.md +31 -0
  12. package/.github/skills/stream-control/SKILL.md +29 -0
  13. package/.github/skills/system-control/SKILL.md +32 -0
  14. package/AGENTS.md +28 -7
  15. package/README.md +70 -15
  16. package/data/assembly/assembly-spec.md +2 -0
  17. package/dist/c64Client.js +238 -60
  18. package/dist/chargen.js +0 -4
  19. package/dist/config.js +53 -28
  20. package/dist/device.js +92 -37
  21. package/dist/diagnostics.js +66 -5
  22. package/dist/hostPaths.js +128 -0
  23. package/dist/logger.js +3 -2
  24. package/dist/loggingHttpClient.js +71 -2
  25. package/dist/mcp-server.js +416 -291
  26. package/dist/numericArg.js +55 -0
  27. package/dist/petscii.js +13 -6
  28. package/dist/platform.js +12 -3
  29. package/dist/prompts/registry.js +6 -1
  30. package/dist/redact.js +166 -0
  31. package/dist/tools/access.js +66 -0
  32. package/dist/tools/debug.js +6 -0
  33. package/dist/tools/developer.js +77 -36
  34. package/dist/tools/errors.js +54 -3
  35. package/dist/tools/input.js +25 -8
  36. package/dist/tools/machineControl.js +113 -21
  37. package/dist/tools/memory.js +135 -30
  38. package/dist/tools/meta/artifacts.js +5 -5
  39. package/dist/tools/meta/background.js +216 -54
  40. package/dist/tools/meta/compilation.js +6 -5
  41. package/dist/tools/meta/config.js +20 -10
  42. package/dist/tools/meta/configInventory.js +25 -2
  43. package/dist/tools/meta/diagnostics.js +2 -1
  44. package/dist/tools/meta/filesystem.js +16 -14
  45. package/dist/tools/meta/graphics.js +48 -20
  46. package/dist/tools/meta/memory.js +45 -19
  47. package/dist/tools/meta/program.js +10 -7
  48. package/dist/tools/meta/screen.js +116 -25
  49. package/dist/tools/pauseGuard.js +23 -0
  50. package/dist/tools/pollValidator.js +53 -8
  51. package/dist/tools/programRunners.js +62 -18
  52. package/dist/tools/registry/batch.js +17 -11
  53. package/dist/tools/registry/config.js +9 -2
  54. package/dist/tools/registry/disk.js +12 -2
  55. package/dist/tools/registry/drive.js +3 -0
  56. package/dist/tools/registry/extract.js +3 -0
  57. package/dist/tools/registry/graphics.js +59 -6
  58. package/dist/tools/registry/index.js +17 -1
  59. package/dist/tools/registry/memory.js +11 -1
  60. package/dist/tools/registry/platform.js +4 -1
  61. package/dist/tools/registry/printer.js +2 -1
  62. package/dist/tools/registry/program.js +5 -1
  63. package/dist/tools/registry/rag.js +1 -0
  64. package/dist/tools/registry/sound.js +12 -1
  65. package/dist/tools/registry/stream.js +2 -1
  66. package/dist/tools/registry/system.js +8 -1
  67. package/dist/tools/schema.js +7 -7
  68. package/dist/tools/streaming.js +34 -4
  69. package/dist/tools/translation/assembler.js +247 -24
  70. package/dist/tools/translation/basicDetokenizer.js +80 -0
  71. package/dist/tools/translation/basicTokenizer.js +8 -3
  72. package/dist/tools/translation/disassembler.js +14 -0
  73. package/dist/tools/types.js +258 -7
  74. package/dist/tools/vice.js +5 -16
  75. package/dist/vicBitmap.js +1 -1
  76. package/dist/vice/mockServer.js +3 -0
  77. package/dist/vice/process.js +19 -0
  78. package/dist/vice/resourcePolicy.js +36 -0
  79. package/dist/vice/viceClient.js +22 -5
  80. package/doc/vice/support-matrix.md +17 -11
  81. package/mcp/schemas/c64_batch.schema.json +2 -1
  82. package/mcp/schemas/c64_config.schema.json +33 -466
  83. package/mcp/schemas/c64_debug.schema.json +3 -602
  84. package/mcp/schemas/c64_disk.schema.json +17 -344
  85. package/mcp/schemas/c64_drive.schema.json +2 -157
  86. package/mcp/schemas/c64_extract.schema.json +10 -364
  87. package/mcp/schemas/c64_graphics.schema.json +19 -426
  88. package/mcp/schemas/c64_input.schema.json +5 -318
  89. package/mcp/schemas/c64_memory.schema.json +23 -491
  90. package/mcp/schemas/c64_printer.schema.json +3 -258
  91. package/mcp/schemas/c64_program.schema.json +16 -491
  92. package/mcp/schemas/c64_rag.schema.json +1 -81
  93. package/mcp/schemas/c64_select_backend.schema.json +2 -36
  94. package/mcp/schemas/c64_sound.schema.json +20 -822
  95. package/mcp/schemas/c64_stream.schema.json +4 -75
  96. package/mcp/schemas/c64_system.schema.json +28 -348
  97. package/mcp/schemas/c64_vice.schema.json +2 -71
  98. package/mcp/server.json +1 -1
  99. package/mcp/tools.json +1990 -6900
  100. package/mcp.json +21 -1
  101. package/package.json +19 -8
  102. package/scripts/mockC64Server.mjs +44 -0
  103. package/scripts/run-coverage.mjs +27 -1
  104. package/scripts/smoke-run.sh +3 -2
  105. package/scripts/start.mjs +23 -1
  106. package/server.json +53 -3
  107. package/dist/.tsbuildinfo +0 -1
  108. package/doc/agent-state-spec.md +0 -243
  109. package/doc/plans/bun/baseline-metrics.md +0 -16
  110. package/doc/plans/bun/migration-checklist.md +0 -55
  111. package/doc/plans/bun/migration.md +0 -83
  112. package/doc/plans/improve-knowledge/notes.md +0 -43
  113. package/doc/plans/improve-knowledge/plan.md +0 -121
  114. package/doc/plans/improve-knowledge/rollout.md +0 -110
  115. package/doc/plans/meta-tools/README.md +0 -110
  116. package/doc/plans/meta-tools/analysis.md +0 -272
  117. package/doc/plans/meta-tools/catalog.md +0 -435
  118. package/doc/plans/meta-tools/notes.md +0 -192
  119. package/doc/plans/meta-tools/rollout.md +0 -368
  120. package/doc/plans/prompts/README.md +0 -96
  121. package/doc/plans/prompts/user-prompt-ideas.md +0 -147
  122. package/doc/plans/tool-consolidation/notes.md +0 -28
  123. package/doc/plans/tool-consolidation/plan.md +0 -169
  124. package/doc/plans/tool-consolidation/rollout.md +0 -104
  125. package/doc/plans/vice-backend-switch/plan.md +0 -486
  126. package/doc/plans/vice-backend-switch-2/plan.md +0 -48
  127. package/doc/plans/vice-support/notes.md +0 -63
  128. package/doc/plans/vice-support/plan.md +0 -88
  129. package/doc/plans/vice-support/rollout.md +0 -99
  130. package/doc/reviews/audit.md +0 -143
  131. package/doc/reviews/hardening/01-fable/prompt-handover.md +0 -125
  132. package/doc/reviews/hardening/01-fable/prompt.md +0 -98
  133. package/doc/reviews/hardening/01-fable/review-prompt.md +0 -468
  134. package/doc/reviews/hardening/01-fable/review.md +0 -1234
  135. package/doc/reviews/vice-support-review.md +0 -185
  136. package/scripts/compare-rest/rest-compare-2025-11-01T00-25-21-830Z.json +0 -2513
package/dist/logger.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Buffer } from "node:buffer";
2
+ import { redactText, redactValue } from "./redact.js";
2
3
  const LEVEL_ORDER = {
3
4
  debug: 0,
4
5
  info: 1,
@@ -24,9 +25,9 @@ function createPrefixedLogger(prefix) {
24
25
  return;
25
26
  }
26
27
  const consoleMethod = selectConsole(level);
27
- const label = `[${prefix}] ${message}`;
28
+ const label = `[${prefix}] ${redactText(message)}`;
28
29
  if (details && Object.keys(details).length > 0) {
29
- consoleMethod(label, details);
30
+ consoleMethod(label, redactValue(details));
30
31
  }
31
32
  else {
32
33
  consoleMethod(label);
@@ -1,4 +1,5 @@
1
1
  import { HttpClient } from "../generated/c64/index.js";
2
+ import { registerSecret, scrubRequestError } from "./redact.js";
2
3
  import { formatErrorMessage, formatPayloadForDebug, loggerFor, payloadByteLength } from "./logger.js";
3
4
  /** Headers are useful in diagnostics, but credentials must never leave the
4
5
  * transport layer. Axios normalises some keys and preserves others, so do a
@@ -12,8 +13,55 @@ function redactHeaders(headers) {
12
13
  sensitive.test(key) ? "***" : value,
13
14
  ]));
14
15
  }
15
- export function createLoggingHttpClient(config, logger = loggerFor("c64u")) {
16
+ /**
17
+ * First-in first-out gate that lets one operation run at a time. The Ultimate
18
+ * firmware serves REST requests on a single thread, so every request to one
19
+ * device goes through one queue. A failed operation releases the gate like a
20
+ * successful one, so the queue cannot deadlock.
21
+ */
22
+ export class RequestQueue {
23
+ constructor() {
24
+ this.tail = Promise.resolve();
25
+ }
26
+ /** The shared queue for one device base URL, so every client of that device (backends, fallback clients) waits in the same line. */
27
+ static forDevice(baseUrl) {
28
+ const key = baseUrl.replace(/\/+$/, "").toLowerCase();
29
+ let queue = RequestQueue.byDevice.get(key);
30
+ if (!queue) {
31
+ queue = new RequestQueue();
32
+ RequestQueue.byDevice.set(key, queue);
33
+ }
34
+ return queue;
35
+ }
36
+ /** Resolves when all earlier holders have released; call the returned function exactly once. */
37
+ async acquire() {
38
+ let release;
39
+ const held = new Promise((resolve) => { release = resolve; });
40
+ const previous = this.tail;
41
+ this.tail = previous.then(() => held);
42
+ await previous;
43
+ let released = false;
44
+ return () => {
45
+ if (!released) {
46
+ released = true;
47
+ release();
48
+ }
49
+ };
50
+ }
51
+ async run(operation) {
52
+ const release = await this.acquire();
53
+ try {
54
+ return await operation();
55
+ }
56
+ finally {
57
+ release();
58
+ }
59
+ }
60
+ }
61
+ RequestQueue.byDevice = new Map();
62
+ export function createLoggingHttpClient(config, logger = loggerFor("c64u"), queue) {
16
63
  const http = new HttpClient(config);
64
+ registerSecret(readPasswordHeader(config?.headers));
17
65
  http.instance.interceptors.request.use((request) => {
18
66
  const method = (request.method ?? "get").toUpperCase();
19
67
  const path = resolvePath(request);
@@ -28,15 +76,36 @@ export function createLoggingHttpClient(config, logger = loggerFor("c64u")) {
28
76
  request.__c64Meta = meta;
29
77
  return request;
30
78
  });
79
+ if (queue) {
80
+ // The generated client sends every request through `instance.request`, so
81
+ // the gate is taken around that call. Interceptors, request transforms and
82
+ // the adapter all run inside it: the start time is recorded after the wait,
83
+ // the request timeout (started by the adapter) does not include the wait,
84
+ // and the gate is released however the request settles, including a
85
+ // failure before the adapter is called (for example a body that cannot be
86
+ // serialised).
87
+ const instance = http.instance;
88
+ const sendRequest = instance.request.bind(instance);
89
+ instance.request = ((requestConfig) => queue.run(() => sendRequest(requestConfig)));
90
+ }
31
91
  http.instance.interceptors.response.use((response) => {
32
92
  handleResponse(response, logger);
33
93
  return response;
34
94
  }, (error) => {
35
95
  handleError(error, logger);
36
- return Promise.reject(error);
96
+ return Promise.reject(scrubRequestError(error));
37
97
  });
38
98
  return http;
39
99
  }
100
+ function readPasswordHeader(headers) {
101
+ if (!headers || typeof headers !== "object")
102
+ return undefined;
103
+ for (const [key, value] of Object.entries(headers)) {
104
+ if (/^x-password$/i.test(key) && typeof value === "string")
105
+ return value;
106
+ }
107
+ return undefined;
108
+ }
40
109
  function handleResponse(response, logger) {
41
110
  const meta = extractMeta(response.config);
42
111
  const latency = meta ? Date.now() - meta.startedAt : 0;