c64bridge 0.5.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/prompts/README.md +6 -0
- package/.github/prompts/assembly-routine-session.prompt.md +13 -0
- package/.github/prompts/basic-program-session.prompt.md +13 -0
- package/.github/prompts/drive-management-session.prompt.md +13 -0
- package/.github/prompts/petscii-art-session.prompt.md +13 -0
- package/.github/prompts/play-classic-game.prompt.md +13 -0
- package/.github/prompts/sid-music-session.prompt.md +13 -0
- package/AGENTS.md +173 -0
- package/LICENSE +339 -0
- package/README.md +582 -0
- package/data/README.md +16 -0
- package/data/api/basic-api-spec.md +154 -0
- package/data/api/kernal-api-spec.md +68 -0
- package/data/assembly/assembly-spec.md +196 -0
- package/data/assembly/examples/effects/sinewave.asm +5 -0
- package/data/assembly/examples/graphics/sprite/mover.asm +15 -0
- package/data/assembly/examples/sid-file-structure.md +8 -0
- package/data/assembly/examples/sid-overview.md +11 -0
- package/data/audio/examples/Biosphere.sid +0 -0
- package/data/audio/sid-file-structure.md +91 -0
- package/data/audio/sid-programming-best-practices.md +198 -0
- package/data/audio/sid-spec.md +166 -0
- package/data/audio/sidwave.md +131 -0
- package/data/audio/sidwave.schema.json +64 -0
- package/data/basic/basic-spec.md +230 -0
- package/data/basic/examples/audio/alle-meine-entchen-expressive.bas +41 -0
- package/data/basic/examples/audio/c-major-scale-pleasant.bas +29 -0
- package/data/basic/examples/io/joystick.bas +5 -0
- package/data/basic/examples/video/bounce.bas +8 -0
- package/data/basic/examples/video/entchen-petscii.bas +16 -0
- package/data/basic/examples/video/hello-world.bas +4 -0
- package/data/basic/examples/video/wave.bas +7 -0
- package/data/context/bootstrap.md +148 -0
- package/data/context/chat.md +36 -0
- package/data/drive/drive-spec.md +215 -0
- package/data/embeddings_asm.json +1 -0
- package/data/embeddings_basic.json +1 -0
- package/data/embeddings_hardware.json +1 -0
- package/data/embeddings_mixed.json +1 -0
- package/data/embeddings_other.json +1 -0
- package/data/io/cia-spec.md +115 -0
- package/data/io/io-spec.md +124 -0
- package/data/memory/kernal-memory-map.md +227 -0
- package/data/memory/low-memory-map.md +133 -0
- package/data/memory/memory-map.md +186 -0
- package/data/printer/printer-commodore-bitmap.md +31 -0
- package/data/printer/printer-commodore.md +28 -0
- package/data/printer/printer-epson-bitmap.md +29 -0
- package/data/printer/printer-epson.md +30 -0
- package/data/printer/printer-prompts.md +29 -0
- package/data/printer/printer-spec.md +180 -0
- package/data/video/character-set.csv +257 -0
- package/data/video/vic-spec.md +276 -0
- package/dist/assemblyConverter.js +1299 -0
- package/dist/audio/record_and_analyze_audio.js +292 -0
- package/dist/basicConverter.js +193 -0
- package/dist/bootstrap/stdio-logger.js +32 -0
- package/dist/c64Client.js +1052 -0
- package/dist/chargen.js +197 -0
- package/dist/config.js +142 -0
- package/dist/context.js +157 -0
- package/dist/device.js +413 -0
- package/dist/index.js +7 -0
- package/dist/knowledge.js +454 -0
- package/dist/logger.js +182 -0
- package/dist/loggingHttpClient.js +88 -0
- package/dist/mcp-server.js +426 -0
- package/dist/petscii.js +135 -0
- package/dist/petsciiArt.js +356 -0
- package/dist/platform.js +82 -0
- package/dist/prompts/registry.js +560 -0
- package/dist/rag/discover.config.json +41 -0
- package/dist/rag/discover.js +401 -0
- package/dist/rag/embeddings.js +60 -0
- package/dist/rag/externalFetcher.js +934 -0
- package/dist/rag/indexer.js +770 -0
- package/dist/rag/init.js +139 -0
- package/dist/rag/knowledgeIndex.js +361 -0
- package/dist/rag/loggingRetriever.js +46 -0
- package/dist/rag/rateLimiter.js +127 -0
- package/dist/rag/retriever.js +74 -0
- package/dist/rag/sources.csv +31 -0
- package/dist/rag/types.js +5 -0
- package/dist/rag/urlUtils.js +38 -0
- package/dist/sidplayRunner.js +240 -0
- package/dist/sidwave.js +101 -0
- package/dist/sidwaveCompiler.js +329 -0
- package/dist/tools/audio.js +944 -0
- package/dist/tools/developer.js +515 -0
- package/dist/tools/errors.js +59 -0
- package/dist/tools/graphics.js +469 -0
- package/dist/tools/machineControl.js +267 -0
- package/dist/tools/memory.js +224 -0
- package/dist/tools/printer.js +482 -0
- package/dist/tools/programRunners.js +315 -0
- package/dist/tools/rag.js +153 -0
- package/dist/tools/registry.js +58 -0
- package/dist/tools/responses.js +36 -0
- package/dist/tools/schema.js +304 -0
- package/dist/tools/storage.js +740 -0
- package/dist/tools/streaming.js +132 -0
- package/dist/tools/types.js +99 -0
- package/dist/viceRunner.js +239 -0
- package/doc/MCP_SETUP.md +153 -0
- package/doc/README.md +7 -0
- package/doc/developer.md +312 -0
- package/doc/img/logo.png +0 -0
- package/doc/img/prompts/duck_petscii.png +0 -0
- package/doc/img/prompts/duck_song.png +0 -0
- package/doc/img/vscode/vscode-copilot-c64-chat-mode.png +0 -0
- package/doc/img/vscode/vscode-copilot-hello-world.png +0 -0
- package/doc/prompts/README.md +96 -0
- package/doc/prompts/user-prompt-ideas.md +147 -0
- package/doc/rest/c64-openapi.yaml +979 -0
- package/doc/rest/c64-rest-api.md +106 -0
- package/doc/troubleshooting-mcp.md +177 -0
- package/generated/c64/index.js +857 -0
- package/mcp.json +106 -0
- package/package.json +79 -0
- package/scripts/c64-cli.mjs +142 -0
- package/scripts/c64-tool.sh +83 -0
- package/scripts/check-package.mjs +89 -0
- package/scripts/cli.js +61 -0
- package/scripts/fetch-external-sources.mjs +67 -0
- package/scripts/generate-changelog.mjs +131 -0
- package/scripts/postbuild.mjs +101 -0
- package/scripts/prepare-release.mjs +58 -0
- package/scripts/rag-rebuild.mjs +53 -0
- package/scripts/register-ts-node.mjs +6 -0
- package/scripts/run-mcp-check.sh +104 -0
- package/scripts/run-tests.mjs +195 -0
- package/scripts/sid2wav.sh +94 -0
- package/scripts/smoke-run.sh +65 -0
- package/scripts/start-mock-c64.mjs +51 -0
- package/scripts/start-mock.mjs +31 -0
- package/scripts/start.mjs +72 -0
- package/scripts/update-readme.ts +164 -0
- package/scripts/verify-package.mjs +147 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { ToolValidationError } from "./errors.js";
|
|
2
|
+
const hasOwn = Object.prototype.hasOwnProperty;
|
|
3
|
+
function withDefaultPath(path) {
|
|
4
|
+
return path ?? "$";
|
|
5
|
+
}
|
|
6
|
+
function createSchema(jsonSchema, parser) {
|
|
7
|
+
return {
|
|
8
|
+
jsonSchema,
|
|
9
|
+
parse(value, path) {
|
|
10
|
+
return parser(value, withDefaultPath(path));
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function ensureType(condition, message, path, details) {
|
|
15
|
+
if (!condition) {
|
|
16
|
+
throw new ToolValidationError(message, { path, details });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function schemaHasDefault(schema) {
|
|
20
|
+
return hasOwn.call(schema.jsonSchema, "default");
|
|
21
|
+
}
|
|
22
|
+
export function stringSchema(options = {}) {
|
|
23
|
+
const jsonSchema = {
|
|
24
|
+
type: "string",
|
|
25
|
+
...(options.description ? { description: options.description } : {}),
|
|
26
|
+
...(options.minLength !== undefined ? { minLength: options.minLength } : {}),
|
|
27
|
+
...(options.maxLength !== undefined ? { maxLength: options.maxLength } : {}),
|
|
28
|
+
...(options.pattern ? { pattern: options.pattern.source } : {}),
|
|
29
|
+
...(options.enum ? { enum: options.enum } : {}),
|
|
30
|
+
...(options.default !== undefined ? { default: options.default } : {}),
|
|
31
|
+
};
|
|
32
|
+
return createSchema(jsonSchema, (value, path) => {
|
|
33
|
+
if (value === undefined || value === null) {
|
|
34
|
+
if (options.default !== undefined) {
|
|
35
|
+
return options.default;
|
|
36
|
+
}
|
|
37
|
+
throw new ToolValidationError("Value is required", { path });
|
|
38
|
+
}
|
|
39
|
+
ensureType(typeof value === "string", "Expected a string", path, {
|
|
40
|
+
receivedType: typeof value,
|
|
41
|
+
});
|
|
42
|
+
const stringValue = value;
|
|
43
|
+
if (options.minLength !== undefined && stringValue.length < options.minLength) {
|
|
44
|
+
throw new ToolValidationError(`String must have length ≥ ${options.minLength}`, { path, details: { minLength: options.minLength } });
|
|
45
|
+
}
|
|
46
|
+
if (options.maxLength !== undefined && stringValue.length > options.maxLength) {
|
|
47
|
+
throw new ToolValidationError(`String must have length ≤ ${options.maxLength}`, { path, details: { maxLength: options.maxLength } });
|
|
48
|
+
}
|
|
49
|
+
if (options.pattern && !options.pattern.test(stringValue)) {
|
|
50
|
+
throw new ToolValidationError("String does not match required pattern", {
|
|
51
|
+
path,
|
|
52
|
+
details: { pattern: options.pattern.source },
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (options.enum && !options.enum.includes(stringValue)) {
|
|
56
|
+
throw new ToolValidationError("Value must be one of the allowed options", {
|
|
57
|
+
path,
|
|
58
|
+
details: { allowed: options.enum },
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return stringValue;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
export function numberSchema(options = {}) {
|
|
65
|
+
const jsonSchema = {
|
|
66
|
+
type: options.integer ? "integer" : "number",
|
|
67
|
+
...(options.description ? { description: options.description } : {}),
|
|
68
|
+
...(options.minimum !== undefined ? { minimum: options.minimum } : {}),
|
|
69
|
+
...(options.maximum !== undefined ? { maximum: options.maximum } : {}),
|
|
70
|
+
...(options.default !== undefined ? { default: options.default } : {}),
|
|
71
|
+
};
|
|
72
|
+
return createSchema(jsonSchema, (value, path) => {
|
|
73
|
+
if (value === undefined || value === null) {
|
|
74
|
+
if (options.default !== undefined) {
|
|
75
|
+
return options.default;
|
|
76
|
+
}
|
|
77
|
+
throw new ToolValidationError("Value is required", { path });
|
|
78
|
+
}
|
|
79
|
+
ensureType(typeof value === "number" && Number.isFinite(value), "Expected a number", path, {
|
|
80
|
+
receivedType: typeof value,
|
|
81
|
+
});
|
|
82
|
+
const numberValue = value;
|
|
83
|
+
if (options.integer && !Number.isInteger(numberValue)) {
|
|
84
|
+
throw new ToolValidationError("Expected an integer", { path });
|
|
85
|
+
}
|
|
86
|
+
if (options.minimum !== undefined && numberValue < options.minimum) {
|
|
87
|
+
throw new ToolValidationError("Value is below minimum", {
|
|
88
|
+
path,
|
|
89
|
+
details: { minimum: options.minimum },
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (options.maximum !== undefined && numberValue > options.maximum) {
|
|
93
|
+
throw new ToolValidationError("Value is above maximum", {
|
|
94
|
+
path,
|
|
95
|
+
details: { maximum: options.maximum },
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return numberValue;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
export function integerSchema(options = {}) {
|
|
102
|
+
return numberSchema({ ...options, integer: true });
|
|
103
|
+
}
|
|
104
|
+
export function booleanSchema(options = {}) {
|
|
105
|
+
const jsonSchema = {
|
|
106
|
+
type: "boolean",
|
|
107
|
+
...(options.description ? { description: options.description } : {}),
|
|
108
|
+
...(options.default !== undefined ? { default: options.default } : {}),
|
|
109
|
+
};
|
|
110
|
+
return createSchema(jsonSchema, (value, path) => {
|
|
111
|
+
if (value === undefined || value === null) {
|
|
112
|
+
if (options.default !== undefined) {
|
|
113
|
+
return options.default;
|
|
114
|
+
}
|
|
115
|
+
throw new ToolValidationError("Value is required", { path });
|
|
116
|
+
}
|
|
117
|
+
ensureType(typeof value === "boolean", "Expected a boolean", path, {
|
|
118
|
+
receivedType: typeof value,
|
|
119
|
+
});
|
|
120
|
+
return value;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
export function literalSchema(literal, description) {
|
|
124
|
+
const jsonSchema = {
|
|
125
|
+
const: literal,
|
|
126
|
+
description,
|
|
127
|
+
};
|
|
128
|
+
return createSchema(jsonSchema, (value, path) => {
|
|
129
|
+
if (value === literal) {
|
|
130
|
+
return literal;
|
|
131
|
+
}
|
|
132
|
+
throw new ToolValidationError(`Expected literal value ${literal}`, { path });
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
export function arraySchema(itemSchema, options = {}) {
|
|
136
|
+
const jsonSchema = {
|
|
137
|
+
type: "array",
|
|
138
|
+
...(options.description ? { description: options.description } : {}),
|
|
139
|
+
items: itemSchema.jsonSchema,
|
|
140
|
+
...(options.minItems !== undefined ? { minItems: options.minItems } : {}),
|
|
141
|
+
...(options.maxItems !== undefined ? { maxItems: options.maxItems } : {}),
|
|
142
|
+
};
|
|
143
|
+
return createSchema(jsonSchema, (value, path) => {
|
|
144
|
+
ensureType(Array.isArray(value), "Expected an array", path, {
|
|
145
|
+
receivedType: typeof value,
|
|
146
|
+
});
|
|
147
|
+
const arrayValue = value;
|
|
148
|
+
const result = [];
|
|
149
|
+
for (let index = 0; index < arrayValue.length; index += 1) {
|
|
150
|
+
const itemPath = `${path}[${index}]`;
|
|
151
|
+
const parsed = itemSchema.parse(arrayValue[index], itemPath);
|
|
152
|
+
result.push(parsed);
|
|
153
|
+
}
|
|
154
|
+
if (options.minItems !== undefined && result.length < options.minItems) {
|
|
155
|
+
throw new ToolValidationError("Array has too few items", {
|
|
156
|
+
path,
|
|
157
|
+
details: { minItems: options.minItems },
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
if (options.maxItems !== undefined && result.length > options.maxItems) {
|
|
161
|
+
throw new ToolValidationError("Array has too many items", {
|
|
162
|
+
path,
|
|
163
|
+
details: { maxItems: options.maxItems },
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
export function optionalSchema(schema, defaultValue) {
|
|
170
|
+
const baseSchema = schema.jsonSchema;
|
|
171
|
+
const baseType = baseSchema.type;
|
|
172
|
+
const optionalType = Array.isArray(baseType)
|
|
173
|
+
? baseType.includes("null")
|
|
174
|
+
? baseType
|
|
175
|
+
: [...baseType, "null"]
|
|
176
|
+
: baseType
|
|
177
|
+
? [baseType, "null"]
|
|
178
|
+
: undefined;
|
|
179
|
+
const baseDefault = baseSchema.default;
|
|
180
|
+
const resolvedDefault = defaultValue !== undefined ? defaultValue : baseDefault;
|
|
181
|
+
const jsonSchema = {
|
|
182
|
+
...baseSchema,
|
|
183
|
+
...(optionalType ? { type: optionalType } : {}),
|
|
184
|
+
...(resolvedDefault !== undefined ? { default: resolvedDefault } : {}),
|
|
185
|
+
};
|
|
186
|
+
return createSchema(jsonSchema, (value, path) => {
|
|
187
|
+
if (value === undefined || value === null) {
|
|
188
|
+
return resolvedDefault;
|
|
189
|
+
}
|
|
190
|
+
return schema.parse(value, path);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function isPlainObject(value) {
|
|
194
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
195
|
+
}
|
|
196
|
+
export function objectSchema(options) {
|
|
197
|
+
const required = options.required ?? [];
|
|
198
|
+
const propertyEntries = Object.entries(options.properties).map(([key, schema]) => [key, schema.jsonSchema]);
|
|
199
|
+
const jsonSchema = {
|
|
200
|
+
type: "object",
|
|
201
|
+
...(options.description ? { description: options.description } : {}),
|
|
202
|
+
properties: Object.fromEntries(propertyEntries),
|
|
203
|
+
...(required.length > 0 ? { required: required.map((key) => key) } : {}),
|
|
204
|
+
...(options.additionalProperties !== undefined
|
|
205
|
+
? { additionalProperties: options.additionalProperties }
|
|
206
|
+
: { additionalProperties: false }),
|
|
207
|
+
};
|
|
208
|
+
return createSchema(jsonSchema, (value, path) => {
|
|
209
|
+
ensureType(isPlainObject(value), "Expected an object", path, {
|
|
210
|
+
receivedType: typeof value,
|
|
211
|
+
});
|
|
212
|
+
const result = {};
|
|
213
|
+
const input = value;
|
|
214
|
+
for (const key of required) {
|
|
215
|
+
if (!hasOwn.call(input, key)) {
|
|
216
|
+
throw new ToolValidationError("Missing required property", {
|
|
217
|
+
path: `${path}.${String(key)}`,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
for (const [key, schema] of Object.entries(options.properties)) {
|
|
222
|
+
const propertyPath = `${path}.${key}`;
|
|
223
|
+
if (hasOwn.call(input, key)) {
|
|
224
|
+
const parsed = schema.parse(input[key], propertyPath);
|
|
225
|
+
if (parsed !== undefined) {
|
|
226
|
+
result[key] = parsed;
|
|
227
|
+
}
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (schemaHasDefault(schema)) {
|
|
231
|
+
const parsed = schema.parse(undefined, propertyPath);
|
|
232
|
+
if (parsed !== undefined) {
|
|
233
|
+
result[key] = parsed;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (options.additionalProperties === false) {
|
|
238
|
+
for (const key of Object.keys(input)) {
|
|
239
|
+
if (!hasOwn.call(options.properties, key)) {
|
|
240
|
+
throw new ToolValidationError("Unexpected property", {
|
|
241
|
+
path: `${path}.${key}`,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
else if (options.additionalProperties === true) {
|
|
247
|
+
for (const key of Object.keys(input)) {
|
|
248
|
+
if (!hasOwn.call(options.properties, key)) {
|
|
249
|
+
result[key] = input[key];
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return result;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
export function mergeSchemas(a, b) {
|
|
257
|
+
const jsonSchema = {
|
|
258
|
+
allOf: [a.jsonSchema, b.jsonSchema],
|
|
259
|
+
};
|
|
260
|
+
return createSchema(jsonSchema, (value, path) => {
|
|
261
|
+
const first = a.parse(prepareValueForMerge(value, a), path);
|
|
262
|
+
const second = b.parse(prepareValueForMerge(value, b), path);
|
|
263
|
+
if (isPlainObject(value)) {
|
|
264
|
+
const strictA = a.jsonSchema.additionalProperties === false;
|
|
265
|
+
const strictB = b.jsonSchema.additionalProperties === false;
|
|
266
|
+
if (strictA && strictB) {
|
|
267
|
+
const allowedKeys = new Set();
|
|
268
|
+
if (a.jsonSchema.properties) {
|
|
269
|
+
for (const key of Object.keys(a.jsonSchema.properties)) {
|
|
270
|
+
allowedKeys.add(key);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (b.jsonSchema.properties) {
|
|
274
|
+
for (const key of Object.keys(b.jsonSchema.properties)) {
|
|
275
|
+
allowedKeys.add(key);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
for (const key of Object.keys(value)) {
|
|
279
|
+
if (!allowedKeys.has(key)) {
|
|
280
|
+
throw new ToolValidationError("Unexpected property", {
|
|
281
|
+
path: `${path}.${key}`,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return { ...first, ...second };
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
function prepareValueForMerge(value, schema) {
|
|
291
|
+
if (!isPlainObject(value)) {
|
|
292
|
+
return value;
|
|
293
|
+
}
|
|
294
|
+
if (schema.jsonSchema.additionalProperties === false && schema.jsonSchema.properties) {
|
|
295
|
+
const subset = {};
|
|
296
|
+
for (const key of Object.keys(schema.jsonSchema.properties)) {
|
|
297
|
+
if (hasOwn.call(value, key)) {
|
|
298
|
+
subset[key] = value[key];
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return subset;
|
|
302
|
+
}
|
|
303
|
+
return value;
|
|
304
|
+
}
|