@aprovan/stitchery 0.1.0-dev.6bd527d → 0.1.0-dev.c33be64
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/.turbo/turbo-build.log +19 -19
- package/dist/cli.cjs +77 -24
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +77 -24
- package/dist/cli.js.map +1 -1
- package/dist/{index-DNQY1UAP.d.cts → index-JTHGJYLz.d.cts} +11 -1
- package/dist/{index-DNQY1UAP.d.ts → index-JTHGJYLz.d.ts} +11 -1
- package/dist/index.cjs +62 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +62 -14
- package/dist/index.js.map +1 -1
- package/dist/server/index.cjs +62 -14
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +62 -14
- package/dist/server/index.js.map +1 -1
- package/package.json +4 -2
- package/src/cli.ts +47 -39
- package/src/prompts.ts +2 -1
- package/src/server/services.ts +99 -35
- package/src/server/vfs-routes.ts +2 -2
package/.turbo/turbo-build.log
CHANGED
|
@@ -10,27 +10,27 @@
|
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
|
-
[32mCJS[39m [1mdist/index.cjs [22m[
|
|
14
|
-
[32mCJS[39m [1mdist/server/index.cjs [22m[
|
|
15
|
-
[32mCJS[39m [1mdist/cli.cjs [22m[
|
|
16
|
-
[32mCJS[39m [1mdist/index.cjs.map [22m[
|
|
17
|
-
[32mCJS[39m [1mdist/server/index.cjs.map [22m[
|
|
18
|
-
[32mCJS[39m [1mdist/cli.cjs.map [22m[
|
|
19
|
-
[32mCJS[39m ⚡️ Build success in
|
|
20
|
-
[32mESM[39m [1mdist/index.js [22m[
|
|
21
|
-
[32mESM[39m [1mdist/cli.js [22m[
|
|
22
|
-
[32mESM[39m [1mdist/server/index.js [22m[
|
|
23
|
-
[32mESM[39m [1mdist/index.js.map [22m[
|
|
24
|
-
[32mESM[39m [1mdist/
|
|
25
|
-
[32mESM[39m [1mdist/
|
|
26
|
-
[32mESM[39m ⚡️ Build success in
|
|
13
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m45.48 KB[39m
|
|
14
|
+
[32mCJS[39m [1mdist/server/index.cjs [22m[32m45.22 KB[39m
|
|
15
|
+
[32mCJS[39m [1mdist/cli.cjs [22m[32m48.14 KB[39m
|
|
16
|
+
[32mCJS[39m [1mdist/index.cjs.map [22m[32m74.97 KB[39m
|
|
17
|
+
[32mCJS[39m [1mdist/server/index.cjs.map [22m[32m74.52 KB[39m
|
|
18
|
+
[32mCJS[39m [1mdist/cli.cjs.map [22m[32m80.58 KB[39m
|
|
19
|
+
[32mCJS[39m ⚡️ Build success in 83ms
|
|
20
|
+
[32mESM[39m [1mdist/index.js [22m[32m43.02 KB[39m
|
|
21
|
+
[32mESM[39m [1mdist/cli.js [22m[32m46.13 KB[39m
|
|
22
|
+
[32mESM[39m [1mdist/server/index.js [22m[32m42.94 KB[39m
|
|
23
|
+
[32mESM[39m [1mdist/index.js.map [22m[32m74.52 KB[39m
|
|
24
|
+
[32mESM[39m [1mdist/server/index.js.map [22m[32m74.54 KB[39m
|
|
25
|
+
[32mESM[39m [1mdist/cli.js.map [22m[32m80.59 KB[39m
|
|
26
|
+
[32mESM[39m ⚡️ Build success in 84ms
|
|
27
27
|
[34mDTS[39m Build start
|
|
28
|
-
[32mDTS[39m ⚡️ Build success in
|
|
28
|
+
[32mDTS[39m ⚡️ Build success in 5545ms
|
|
29
29
|
[32mDTS[39m [1mdist/cli.d.ts [22m[32m20.00 B[39m
|
|
30
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m13.
|
|
30
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m13.76 KB[39m
|
|
31
31
|
[32mDTS[39m [1mdist/server/index.d.ts [22m[32m122.00 B[39m
|
|
32
|
-
[32mDTS[39m [1mdist/index-
|
|
32
|
+
[32mDTS[39m [1mdist/index-JTHGJYLz.d.ts [22m[32m5.99 KB[39m
|
|
33
33
|
[32mDTS[39m [1mdist/cli.d.cts [22m[32m20.00 B[39m
|
|
34
|
-
[32mDTS[39m [1mdist/index.d.cts [22m[32m13.
|
|
34
|
+
[32mDTS[39m [1mdist/index.d.cts [22m[32m13.76 KB[39m
|
|
35
35
|
[32mDTS[39m [1mdist/server/index.d.cts [22m[32m123.00 B[39m
|
|
36
|
-
[32mDTS[39m [1mdist/index-
|
|
36
|
+
[32mDTS[39m [1mdist/index-JTHGJYLz.d.cts [22m[32m5.99 KB[39m
|
package/dist/cli.cjs
CHANGED
|
@@ -27,6 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var import_path2 = __toESM(require("path"), 1);
|
|
28
28
|
var import_fs2 = __toESM(require("fs"), 1);
|
|
29
29
|
var import_commander = require("commander");
|
|
30
|
+
var import_devtools = require("@aprovan/devtools");
|
|
30
31
|
|
|
31
32
|
// src/server/index.ts
|
|
32
33
|
var import_node_http = require("http");
|
|
@@ -111,7 +112,8 @@ export function Card() {
|
|
|
111
112
|
### Requirements
|
|
112
113
|
- DO think heavily about correctness of code and syntax
|
|
113
114
|
- DO keep things simple and self-contained
|
|
114
|
-
- ALWAYS include the \`path\` attribute specifying the file location.
|
|
115
|
+
- ALWAYS include the \`path\` attribute specifying the file location.
|
|
116
|
+
- ALWAYS use generic component/path names that is not dependent on arguments (e.g. 'dinner.tsx' not 'spaghetti.tsx')
|
|
115
117
|
- ALWAYS output the COMPLETE code block with opening \`\`\`tsx and closing \`\`\` markers
|
|
116
118
|
- Use \`note\` attribute to describe what each code block does (optional but encouraged)
|
|
117
119
|
- NEVER truncate or cut off code - finish the entire component before stopping
|
|
@@ -538,7 +540,7 @@ function joinRelPath(base, name) {
|
|
|
538
540
|
}
|
|
539
541
|
async function listAllFiles(rootDir, relPath) {
|
|
540
542
|
const targetPath = resolvePath(rootDir, relPath);
|
|
541
|
-
let entries
|
|
543
|
+
let entries;
|
|
542
544
|
try {
|
|
543
545
|
entries = await (0, import_promises.readdir)(targetPath, { withFileTypes: true });
|
|
544
546
|
} catch {
|
|
@@ -546,7 +548,7 @@ async function listAllFiles(rootDir, relPath) {
|
|
|
546
548
|
}
|
|
547
549
|
const results = [];
|
|
548
550
|
for (const entry of entries) {
|
|
549
|
-
const entryRelPath = joinRelPath(relPath, entry.name);
|
|
551
|
+
const entryRelPath = joinRelPath(relPath, String(entry.name));
|
|
550
552
|
if (entry.isDirectory()) {
|
|
551
553
|
results.push(...await listAllFiles(rootDir, entryRelPath));
|
|
552
554
|
} else {
|
|
@@ -832,7 +834,15 @@ var ServiceRegistry = class {
|
|
|
832
834
|
this.backends.push(backend);
|
|
833
835
|
if (toolInfos) {
|
|
834
836
|
for (const info of toolInfos) {
|
|
835
|
-
|
|
837
|
+
const infoWithInterface = {
|
|
838
|
+
...info,
|
|
839
|
+
typescriptInterface: this.generateTypeScriptInterfaceFromSchema(
|
|
840
|
+
info.name,
|
|
841
|
+
info.parameters,
|
|
842
|
+
info.outputs
|
|
843
|
+
)
|
|
844
|
+
};
|
|
845
|
+
this.toolInfo.set(info.name, infoWithInterface);
|
|
836
846
|
const tool = {
|
|
837
847
|
description: info.description,
|
|
838
848
|
inputSchema: (0, import_ai2.jsonSchema)(
|
|
@@ -851,20 +861,59 @@ var ServiceRegistry = class {
|
|
|
851
861
|
*/
|
|
852
862
|
generateTypeScriptInterface(name, tool) {
|
|
853
863
|
const schema = tool.inputSchema;
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
864
|
+
return this.generateTypeScriptInterfaceFromSchema(name, schema);
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Convert JSON Schema type to TypeScript type
|
|
868
|
+
*/
|
|
869
|
+
schemaTypeToTs(schema) {
|
|
870
|
+
const type = schema.type;
|
|
871
|
+
const items = schema.items;
|
|
872
|
+
const properties = schema.properties;
|
|
873
|
+
const required = schema.required ?? [];
|
|
874
|
+
if (type === "number" || type === "integer") return "number";
|
|
875
|
+
if (type === "boolean") return "boolean";
|
|
876
|
+
if (type === "null") return "null";
|
|
877
|
+
if (type === "array") {
|
|
878
|
+
if (items) {
|
|
879
|
+
return `${this.schemaTypeToTs(items)}[]`;
|
|
880
|
+
}
|
|
881
|
+
return "unknown[]";
|
|
882
|
+
}
|
|
883
|
+
if (type === "object" && properties) {
|
|
884
|
+
const props = Object.entries(properties).map(([key, val]) => {
|
|
885
|
+
const optional = !required.includes(key) ? "?" : "";
|
|
886
|
+
const propType = this.schemaTypeToTs(val);
|
|
887
|
+
return `${key}${optional}: ${propType}`;
|
|
888
|
+
}).join("; ");
|
|
889
|
+
return `{ ${props} }`;
|
|
890
|
+
}
|
|
891
|
+
if (type === "object") return "Record<string, unknown>";
|
|
892
|
+
return "string";
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Generate TypeScript interface from JSON Schema (supports both inputs and outputs)
|
|
896
|
+
*/
|
|
897
|
+
generateTypeScriptInterfaceFromSchema(name, inputSchema, outputSchema) {
|
|
898
|
+
const safeName = name.replace(/[^a-zA-Z0-9]/g, "_");
|
|
899
|
+
const inputProps = inputSchema?.properties ?? {};
|
|
900
|
+
const inputRequired = inputSchema?.required ?? [];
|
|
901
|
+
const inputParams = Object.entries(inputProps).map(([key, val]) => {
|
|
902
|
+
const optional = !inputRequired.includes(key) ? "?" : "";
|
|
858
903
|
const type = val.type === "number" ? "number" : val.type === "boolean" ? "boolean" : val.type === "array" ? "unknown[]" : val.type === "object" ? "Record<string, unknown>" : "string";
|
|
859
904
|
const comment = val.description ? ` // ${val.description}` : "";
|
|
860
905
|
return ` ${key}${optional}: ${type};${comment}`;
|
|
861
906
|
}).join("\n");
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
"_"
|
|
865
|
-
)}Args {
|
|
866
|
-
${params}
|
|
907
|
+
let result = `interface ${safeName}Args {
|
|
908
|
+
${inputParams}
|
|
867
909
|
}`;
|
|
910
|
+
if (outputSchema && Object.keys(outputSchema).length > 0) {
|
|
911
|
+
const responseType = this.schemaTypeToTs(outputSchema);
|
|
912
|
+
result += `
|
|
913
|
+
|
|
914
|
+
type ${safeName}Response = ${responseType};`;
|
|
915
|
+
}
|
|
916
|
+
return result;
|
|
868
917
|
}
|
|
869
918
|
/**
|
|
870
919
|
* Convert internal tool name (namespace.procedure) to LLM-safe name (namespace_procedure)
|
|
@@ -1013,7 +1062,7 @@ function generateServicesPrompt(registry) {
|
|
|
1013
1062
|
existing.push(service);
|
|
1014
1063
|
byNamespace.set(service.namespace, existing);
|
|
1015
1064
|
}
|
|
1016
|
-
let prompt = `##
|
|
1065
|
+
let prompt = `## Services
|
|
1017
1066
|
|
|
1018
1067
|
The following services are available for generated widgets to call:
|
|
1019
1068
|
|
|
@@ -1320,27 +1369,31 @@ async function createStitcheryServer(config = {}) {
|
|
|
1320
1369
|
// src/cli.ts
|
|
1321
1370
|
var program = new import_commander.Command();
|
|
1322
1371
|
program.name("stitchery").description("Backend services for LLM-generated artifacts").version("0.1.0");
|
|
1323
|
-
program.command("serve").description("Start the stitchery server").option(
|
|
1372
|
+
program.command("serve").description("Start the stitchery server").option(
|
|
1373
|
+
"-p, --port <port>",
|
|
1374
|
+
"Port to listen on (auto-finds available if in use)",
|
|
1375
|
+
"6434"
|
|
1376
|
+
).option("-h, --host <host>", "Host to bind to", "127.0.0.1").option(
|
|
1324
1377
|
"--copilot-proxy-url <url>",
|
|
1325
1378
|
"Copilot proxy URL",
|
|
1326
1379
|
"http://127.0.0.1:6433/v1"
|
|
1327
|
-
).option(
|
|
1380
|
+
).option("--strict", "Fail if the specified port is in use", false).option(
|
|
1328
1381
|
"--mcp <servers...>",
|
|
1329
1382
|
"MCP server commands (format: name:command:arg1,arg2)"
|
|
1330
1383
|
).option("--utcp-config <path>", "Load UTCP configuration from JSON file").option(
|
|
1331
1384
|
"--local-package <packages...>",
|
|
1332
1385
|
"Local package overrides (format: name:path)"
|
|
1333
|
-
).option(
|
|
1334
|
-
"--vfs-dir <path>",
|
|
1335
|
-
"Directory for virtual file system storage",
|
|
1336
|
-
".working/widgets"
|
|
1337
|
-
).option(
|
|
1386
|
+
).option("--vfs-dir <path>", "Directory for virtual file system storage", ".").option(
|
|
1338
1387
|
"--vfs-use-paths",
|
|
1339
1388
|
"Use file paths from code blocks instead of UUIDs for VFS storage"
|
|
1340
1389
|
).option("-v, --verbose", "Enable verbose logging").action(async (options) => {
|
|
1341
1390
|
if (options.verbose) {
|
|
1342
1391
|
console.log("[stitchery] CLI options:", JSON.stringify(options, null, 2));
|
|
1343
1392
|
}
|
|
1393
|
+
let port = parseInt(options.port, 10);
|
|
1394
|
+
if (!options.strict) {
|
|
1395
|
+
port = await (0, import_devtools.getAvailablePort)(port);
|
|
1396
|
+
}
|
|
1344
1397
|
const mcpServers = (options.mcp ?? []).map((spec) => {
|
|
1345
1398
|
const [name, command, ...rest] = spec.split(":");
|
|
1346
1399
|
const rawArgs = rest.join(":").split(",").filter(Boolean);
|
|
@@ -1378,7 +1431,7 @@ program.command("serve").description("Start the stitchery server").option("-p, -
|
|
|
1378
1431
|
console.log("[stitchery] VFS directory:", vfsDir);
|
|
1379
1432
|
}
|
|
1380
1433
|
const server = await createStitcheryServer({
|
|
1381
|
-
port
|
|
1434
|
+
port,
|
|
1382
1435
|
host: options.host,
|
|
1383
1436
|
copilotProxyUrl: options.copilotProxyUrl,
|
|
1384
1437
|
mcpServers,
|
|
@@ -1388,8 +1441,8 @@ program.command("serve").description("Start the stitchery server").option("-p, -
|
|
|
1388
1441
|
vfsUsePaths: options.vfsUsePaths ?? false,
|
|
1389
1442
|
verbose: options.verbose
|
|
1390
1443
|
});
|
|
1391
|
-
const
|
|
1392
|
-
console.log(`Stitchery server running at http://${host}:${port}`);
|
|
1444
|
+
const addr = await server.start();
|
|
1445
|
+
console.log(`Stitchery server running at http://${addr.host}:${addr.port}`);
|
|
1393
1446
|
process.on("SIGINT", async () => {
|
|
1394
1447
|
console.log("\nShutting down...");
|
|
1395
1448
|
await server.stop();
|