veryfront 0.1.157 → 0.1.159
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/esm/cli/mcp/remote-file-tools.d.ts.map +1 -1
- package/esm/cli/mcp/remote-file-tools.js +16 -9
- package/esm/deno.js +1 -1
- package/esm/src/agent/human-input.d.ts +298 -0
- package/esm/src/agent/human-input.d.ts.map +1 -0
- package/esm/src/agent/human-input.js +112 -0
- package/esm/src/agent/index.d.ts +1 -0
- package/esm/src/agent/index.d.ts.map +1 -1
- package/esm/src/agent/index.js +1 -0
- package/esm/src/mcp/server.d.ts +2 -1
- package/esm/src/mcp/server.d.ts.map +1 -1
- package/esm/src/mcp/server.js +12 -5
- package/esm/src/routing/api/module-loader/loader.d.ts +7 -0
- package/esm/src/routing/api/module-loader/loader.d.ts.map +1 -1
- package/esm/src/routing/api/module-loader/loader.js +104 -94
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
- package/src/cli/mcp/remote-file-tools.ts +24 -13
- package/src/deno.js +1 -1
- package/src/src/agent/human-input.ts +152 -0
- package/src/src/agent/index.ts +18 -0
- package/src/src/mcp/server.ts +14 -5
- package/src/src/routing/api/module-loader/loader.ts +127 -100
- package/src/src/utils/version-constant.ts +1 -1
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { APIRoute, LoadModuleOptions } from "./types.js";
|
|
2
|
+
import type { FileSystem } from "../../../platform/compat/fs.js";
|
|
2
3
|
export declare function toCjsDestructureBindings(bindings: string): string;
|
|
3
4
|
export declare function loadHandlerModule(options: LoadModuleOptions): Promise<APIRoute | null>;
|
|
5
|
+
export declare function getNodeExternalPackagesToResolve(userDeps: Map<string, string>): string[];
|
|
6
|
+
export declare function resolveNodePackageToFileUrl(projectDir: string, packageName: string, fs: FileSystem, pathToFileURL: typeof import("node:url").pathToFileURL): Promise<string | null>;
|
|
7
|
+
export declare function loadVeryfrontExportsMap(projectDir: string, fs: FileSystem): Promise<Record<string, {
|
|
8
|
+
import?: string;
|
|
9
|
+
}>>;
|
|
10
|
+
export declare function rewriteNodeExternalImports(code: string, projectDir: string, fs: FileSystem, userDeps: Map<string, string>): Promise<string>;
|
|
4
11
|
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/routing/api/module-loader/loader.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../../src/src/routing/api/module-loader/loader.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAI9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AA4KjE,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAejE;AAgBD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAyBtF;AAuaD,wBAAgB,gCAAgC,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CAUxF;AAED,wBAAsB,2BAA2B,CAC/C,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,cAAc,UAAU,EAAE,aAAa,GACrD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBxB;AAED,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,GACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAW9C;AAED,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,EACd,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,OAAO,CAAC,MAAM,CAAC,CA6EjB"}
|
|
@@ -512,105 +512,115 @@ async function loadModuleFromCode(code, projectDir, fs, userDeps = new Map()) {
|
|
|
512
512
|
await fs.remove(tempDir, { recursive: true });
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
|
-
|
|
515
|
+
export function getNodeExternalPackagesToResolve(userDeps) {
|
|
516
|
+
const externalPackagesToResolve = ["zod"];
|
|
517
|
+
for (const name of userDeps.keys()) {
|
|
518
|
+
if (!externalPackagesToResolve.includes(name)) {
|
|
519
|
+
externalPackagesToResolve.push(name);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return externalPackagesToResolve;
|
|
523
|
+
}
|
|
524
|
+
export async function resolveNodePackageToFileUrl(projectDir, packageName, fs, pathToFileURL) {
|
|
525
|
+
const packagePath = pathHelper.join(projectDir, "node_modules", packageName);
|
|
526
|
+
const packageJsonPath = pathHelper.join(packagePath, "package.json");
|
|
527
|
+
try {
|
|
528
|
+
const pkgJson = JSON.parse(await fs.readTextFile(packageJsonPath));
|
|
529
|
+
let entryPoint;
|
|
530
|
+
if (pkgJson.exports) {
|
|
531
|
+
entryPoint = resolveExportEntry(pkgJson.exports["."]);
|
|
532
|
+
}
|
|
533
|
+
entryPoint ||= pkgJson.module || pkgJson.main || "index.js";
|
|
534
|
+
if (!entryPoint)
|
|
535
|
+
return null;
|
|
536
|
+
return pathToFileURL(pathHelper.join(packagePath, entryPoint)).href;
|
|
537
|
+
}
|
|
538
|
+
catch (_) {
|
|
539
|
+
/* expected: package.json may not exist or be invalid */
|
|
540
|
+
return null;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
export async function loadVeryfrontExportsMap(projectDir, fs) {
|
|
544
|
+
const vfPackagePath = pathHelper.join(projectDir, "node_modules", "veryfront");
|
|
545
|
+
const vfPackageJsonPath = pathHelper.join(vfPackagePath, "package.json");
|
|
546
|
+
try {
|
|
547
|
+
const pkgJson = JSON.parse(await fs.readTextFile(vfPackageJsonPath));
|
|
548
|
+
return pkgJson.exports || {};
|
|
549
|
+
}
|
|
550
|
+
catch (_error) {
|
|
551
|
+
logger.debug("Could not read veryfront package.json");
|
|
552
|
+
return {};
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
export async function rewriteNodeExternalImports(code, projectDir, fs, userDeps) {
|
|
556
|
+
const { pathToFileURL } = await import("node:url");
|
|
516
557
|
let transformed = code;
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
/* expected: package.json may not exist or be invalid */
|
|
537
|
-
return null;
|
|
538
|
-
}
|
|
539
|
-
};
|
|
540
|
-
const externalPackagesToResolve = ["zod"];
|
|
541
|
-
for (const name of userDeps.keys()) {
|
|
542
|
-
if (!externalPackagesToResolve.includes(name)) {
|
|
543
|
-
externalPackagesToResolve.push(name);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
for (const pkg of externalPackagesToResolve) {
|
|
547
|
-
const escapedPkg = pkg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
548
|
-
// Match both exact imports (from "pkg") and subpath imports (from "pkg/sub")
|
|
549
|
-
const staticImportRegex = new RegExp(`from\\s*["']${escapedPkg}(/[^"']*)?["']`, "g");
|
|
550
|
-
const dynamicImportRegex = new RegExp(`import\\s*\\(\\s*["']${escapedPkg}(/[^"']*)?["']\\s*\\)`, "g");
|
|
551
|
-
const needsStatic = staticImportRegex.test(transformed);
|
|
552
|
-
staticImportRegex.lastIndex = 0;
|
|
553
|
-
const needsDynamic = dynamicImportRegex.test(transformed);
|
|
554
|
-
dynamicImportRegex.lastIndex = 0;
|
|
555
|
-
if (!needsStatic && !needsDynamic)
|
|
556
|
-
continue;
|
|
557
|
-
const packageDir = pathToFileURL(pathHelper.join(projectDir, "node_modules", pkg)).href;
|
|
558
|
-
const resolvedUrl = await resolvePackageToFileUrl(pkg);
|
|
559
|
-
if (needsStatic) {
|
|
560
|
-
transformed = transformed.replace(staticImportRegex, (_, subpath) => {
|
|
561
|
-
if (subpath) {
|
|
562
|
-
const subUrl = `${packageDir}${subpath}`;
|
|
563
|
-
logger.debug(`Resolved ${pkg}${subpath} -> ${subUrl}`);
|
|
564
|
-
return `from "${subUrl}"`;
|
|
565
|
-
}
|
|
566
|
-
if (!resolvedUrl)
|
|
567
|
-
return `from "${pkg}"`;
|
|
568
|
-
logger.debug(`Resolved ${pkg} -> ${resolvedUrl}`);
|
|
569
|
-
return `from "${resolvedUrl}"`;
|
|
570
|
-
});
|
|
571
|
-
}
|
|
572
|
-
if (needsDynamic) {
|
|
573
|
-
transformed = transformed.replace(dynamicImportRegex, (_, subpath) => {
|
|
574
|
-
if (subpath) {
|
|
575
|
-
const subUrl = `${packageDir}${subpath}`;
|
|
576
|
-
return `import("${subUrl}")`;
|
|
577
|
-
}
|
|
578
|
-
if (!resolvedUrl)
|
|
579
|
-
return `import("${pkg}")`;
|
|
580
|
-
return `import("${resolvedUrl}")`;
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
const vfPackagePath = pathHelper.join(projectDir, "node_modules", "veryfront");
|
|
585
|
-
const vfPackageJsonPath = pathHelper.join(vfPackagePath, "package.json");
|
|
586
|
-
let exportsMap = {};
|
|
587
|
-
try {
|
|
588
|
-
const pkgJson = JSON.parse(await fs.readTextFile(vfPackageJsonPath));
|
|
589
|
-
exportsMap = pkgJson.exports || {};
|
|
590
|
-
}
|
|
591
|
-
catch (_error) {
|
|
592
|
-
logger.debug(`Could not read veryfront package.json: `);
|
|
593
|
-
}
|
|
594
|
-
transformed = transformed.replace(/from\s+["'](veryfront\/[^"']+)["']/g, (match, fullSpecifier) => {
|
|
595
|
-
const subpath = "./" + fullSpecifier.replace("veryfront/", "");
|
|
596
|
-
const exportEntry = exportsMap[subpath];
|
|
597
|
-
if (!exportEntry?.import) {
|
|
598
|
-
logger.warn(`No export found for ${subpath}`);
|
|
599
|
-
return match;
|
|
558
|
+
logger.debug(`Rewriting external imports for Node.js, projectDir: ${projectDir}`);
|
|
559
|
+
for (const pkg of getNodeExternalPackagesToResolve(userDeps)) {
|
|
560
|
+
const escapedPkg = pkg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
561
|
+
const staticImportRegex = new RegExp(`from\\s*["']${escapedPkg}(/[^"']*)?["']`, "g");
|
|
562
|
+
const dynamicImportRegex = new RegExp(`import\\s*\\(\\s*["']${escapedPkg}(/[^"']*)?["']\\s*\\)`, "g");
|
|
563
|
+
const needsStatic = staticImportRegex.test(transformed);
|
|
564
|
+
staticImportRegex.lastIndex = 0;
|
|
565
|
+
const needsDynamic = dynamicImportRegex.test(transformed);
|
|
566
|
+
dynamicImportRegex.lastIndex = 0;
|
|
567
|
+
if (!needsStatic && !needsDynamic)
|
|
568
|
+
continue;
|
|
569
|
+
const packageDir = pathToFileURL(pathHelper.join(projectDir, "node_modules", pkg)).href;
|
|
570
|
+
const resolvedUrl = await resolveNodePackageToFileUrl(projectDir, pkg, fs, pathToFileURL);
|
|
571
|
+
if (needsStatic) {
|
|
572
|
+
transformed = transformed.replace(staticImportRegex, (_, subpath) => {
|
|
573
|
+
if (subpath) {
|
|
574
|
+
const subUrl = `${packageDir}${subpath}`;
|
|
575
|
+
logger.debug(`Resolved ${pkg}${subpath} -> ${subUrl}`);
|
|
576
|
+
return `from "${subUrl}"`;
|
|
600
577
|
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
578
|
+
if (!resolvedUrl)
|
|
579
|
+
return `from "${pkg}"`;
|
|
580
|
+
logger.debug(`Resolved ${pkg} -> ${resolvedUrl}`);
|
|
581
|
+
return `from "${resolvedUrl}"`;
|
|
604
582
|
});
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
583
|
+
}
|
|
584
|
+
if (needsDynamic) {
|
|
585
|
+
transformed = transformed.replace(dynamicImportRegex, (_, subpath) => {
|
|
586
|
+
if (subpath) {
|
|
587
|
+
return `import("${packageDir}${subpath}")`;
|
|
588
|
+
}
|
|
589
|
+
if (!resolvedUrl)
|
|
590
|
+
return `import("${pkg}")`;
|
|
591
|
+
return `import("${resolvedUrl}")`;
|
|
612
592
|
});
|
|
613
593
|
}
|
|
594
|
+
}
|
|
595
|
+
const vfPackagePath = pathHelper.join(projectDir, "node_modules", "veryfront");
|
|
596
|
+
const exportsMap = await loadVeryfrontExportsMap(projectDir, fs);
|
|
597
|
+
transformed = transformed.replace(/from\s+["'](veryfront\/[^"']+)["']/g, (match, fullSpecifier) => {
|
|
598
|
+
const subpath = "./" + fullSpecifier.replace("veryfront/", "");
|
|
599
|
+
const exportEntry = exportsMap[subpath];
|
|
600
|
+
if (!exportEntry?.import) {
|
|
601
|
+
logger.warn(`No export found for ${subpath}`);
|
|
602
|
+
return match;
|
|
603
|
+
}
|
|
604
|
+
const resolvedPath = pathHelper.join(vfPackagePath, exportEntry.import);
|
|
605
|
+
logger.debug(`Resolved ${fullSpecifier} -> ${resolvedPath}`);
|
|
606
|
+
return `from "${pathToFileURL(resolvedPath).href}"`;
|
|
607
|
+
});
|
|
608
|
+
transformed = transformed.replace(/from\s+["']veryfront["']/g, () => {
|
|
609
|
+
const exportEntry = exportsMap["."];
|
|
610
|
+
if (!exportEntry?.import)
|
|
611
|
+
return 'from "veryfront"';
|
|
612
|
+
const resolvedPath = pathHelper.join(vfPackagePath, exportEntry.import);
|
|
613
|
+
logger.debug(`Resolved veryfront -> ${resolvedPath}`);
|
|
614
|
+
return `from "${pathToFileURL(resolvedPath).href}"`;
|
|
615
|
+
});
|
|
616
|
+
return transformed;
|
|
617
|
+
}
|
|
618
|
+
async function rewriteExternalImports(code, projectDir, fs, userDeps = new Map()) {
|
|
619
|
+
let transformed = code;
|
|
620
|
+
if (isNode) {
|
|
621
|
+
try {
|
|
622
|
+
transformed = await rewriteNodeExternalImports(transformed, projectDir, fs, userDeps);
|
|
623
|
+
}
|
|
614
624
|
catch (e) {
|
|
615
625
|
logger.warn(`Failed to import node:module: ${e}`);
|
|
616
626
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.1.
|
|
1
|
+
export declare const VERSION = "0.1.159";
|
|
2
2
|
//# sourceMappingURL=version-constant.d.ts.map
|
package/package.json
CHANGED
|
@@ -87,6 +87,15 @@ function getBranchParam(branch?: string): string {
|
|
|
87
87
|
return branch ? `?branch_id=${branch}` : "";
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
function buildProjectApiPath(project: string, resource: string, branch?: string): string {
|
|
91
|
+
const normalizedResource = resource.startsWith("/") ? resource.slice(1) : resource;
|
|
92
|
+
return `/${project}${getBranchPath(branch)}/${normalizedResource}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function buildProjectFilePath(project: string, filePath: string, branch?: string): string {
|
|
96
|
+
return buildProjectApiPath(project, `files/${encodeFilePath(filePath)}`, branch);
|
|
97
|
+
}
|
|
98
|
+
|
|
90
99
|
interface RemoteFile {
|
|
91
100
|
id?: string;
|
|
92
101
|
path: string;
|
|
@@ -214,9 +223,9 @@ export const vfRemoteListFiles: MCPTool<RemoteListFilesInput, RemoteListFilesOut
|
|
|
214
223
|
params.set("limit", String(input.limit));
|
|
215
224
|
params.set("fields", "(path,type,size)");
|
|
216
225
|
|
|
217
|
-
const apiPath =
|
|
218
|
-
|
|
219
|
-
}
|
|
226
|
+
const apiPath = `${
|
|
227
|
+
buildProjectApiPath(input.project, "files", input.branch)
|
|
228
|
+
}?${params.toString()}`;
|
|
220
229
|
const result = await apiRequest<FileListResponse>("GET", apiPath);
|
|
221
230
|
if (!result.ok) return { success: false, error: result.error };
|
|
222
231
|
|
|
@@ -260,9 +269,7 @@ export const vfRemoteGetFile: MCPTool<RemoteGetFileInput, RemoteGetFileOutput> =
|
|
|
260
269
|
withSpan(
|
|
261
270
|
"cli.mcp.tool.vf_remote_get_file",
|
|
262
271
|
async () => {
|
|
263
|
-
const apiPath =
|
|
264
|
-
encodeFilePath(input.path)
|
|
265
|
-
}`;
|
|
272
|
+
const apiPath = buildProjectFilePath(input.project, input.path, input.branch);
|
|
266
273
|
const result = await apiRequest<RemoteFile>("GET", apiPath);
|
|
267
274
|
if (!result.ok) return { success: false, error: result.error };
|
|
268
275
|
|
|
@@ -314,7 +321,7 @@ export const vfRemoteUpdateFile: MCPTool<RemoteUpdateFileInput, RemoteUpdateFile
|
|
|
314
321
|
withSpan(
|
|
315
322
|
"cli.mcp.tool.vf_remote_update_file",
|
|
316
323
|
async () => {
|
|
317
|
-
const apiPath =
|
|
324
|
+
const apiPath = `${buildProjectFilePath(input.project, input.path)}${
|
|
318
325
|
getBranchParam(input.branch)
|
|
319
326
|
}`;
|
|
320
327
|
const result = await apiRequest<{ id: string; path: string }>("PUT", apiPath, {
|
|
@@ -362,7 +369,7 @@ export const vfRemoteDeleteFile: MCPTool<RemoteDeleteFileInput, RemoteDeleteFile
|
|
|
362
369
|
description: "Delete a file from a remote Veryfront project.",
|
|
363
370
|
inputSchema: remoteDeleteFileInput,
|
|
364
371
|
execute: async (input) => {
|
|
365
|
-
const apiPath =
|
|
372
|
+
const apiPath = `${buildProjectFilePath(input.project, input.path)}${
|
|
366
373
|
getBranchParam(input.branch)
|
|
367
374
|
}`;
|
|
368
375
|
const result = await apiRequest<void>("DELETE", apiPath);
|
|
@@ -405,7 +412,7 @@ export const vfRemoteSearchFiles: MCPTool<RemoteSearchFilesInput, RemoteSearchFi
|
|
|
405
412
|
withSpan(
|
|
406
413
|
"cli.mcp.tool.vf_remote_search_files",
|
|
407
414
|
async () => {
|
|
408
|
-
const apiPath =
|
|
415
|
+
const apiPath = buildProjectApiPath(input.project, "files/search", input.branch);
|
|
409
416
|
const result = await apiRequest<SearchResponse>("POST", apiPath, {
|
|
410
417
|
body: {
|
|
411
418
|
query: input.query,
|
|
@@ -455,7 +462,11 @@ export const vfRemoteMoveFile: MCPTool<RemoteMoveFileInput, RemoteMoveFileOutput
|
|
|
455
462
|
description: "Move or rename a file in a remote Veryfront project.",
|
|
456
463
|
inputSchema: remoteMoveFileInput,
|
|
457
464
|
execute: async (input) => {
|
|
458
|
-
const apiPath =
|
|
465
|
+
const apiPath = `${buildProjectApiPath(input.project, "files/move")}${
|
|
466
|
+
getBranchParam(
|
|
467
|
+
input.branch,
|
|
468
|
+
)
|
|
469
|
+
}`;
|
|
459
470
|
const result = await apiRequest<{ source_path: string; destination_path: string }>(
|
|
460
471
|
"POST",
|
|
461
472
|
apiPath,
|
|
@@ -732,7 +743,7 @@ export const vfRemoteCloneProject: MCPTool<RemoteCloneProjectInput, RemoteCloneP
|
|
|
732
743
|
|
|
733
744
|
const listResult = await apiRequest<FileListResponse>(
|
|
734
745
|
"GET",
|
|
735
|
-
|
|
746
|
+
`${buildProjectApiPath(input.source_project, "files")}?${params.toString()}`,
|
|
736
747
|
);
|
|
737
748
|
|
|
738
749
|
if (!listResult.ok) {
|
|
@@ -750,7 +761,7 @@ export const vfRemoteCloneProject: MCPTool<RemoteCloneProjectInput, RemoteCloneP
|
|
|
750
761
|
for (const file of sourceFiles) {
|
|
751
762
|
const getResult = await apiRequest<RemoteFile>(
|
|
752
763
|
"GET",
|
|
753
|
-
|
|
764
|
+
buildProjectFilePath(input.source_project, file.path),
|
|
754
765
|
);
|
|
755
766
|
|
|
756
767
|
if (!getResult.ok || !getResult.data) {
|
|
@@ -760,7 +771,7 @@ export const vfRemoteCloneProject: MCPTool<RemoteCloneProjectInput, RemoteCloneP
|
|
|
760
771
|
|
|
761
772
|
const createFileResult = await apiRequest<{ id: string; path: string }>(
|
|
762
773
|
"PUT",
|
|
763
|
-
|
|
774
|
+
buildProjectFilePath(createResult.slug, file.path),
|
|
764
775
|
{ body: { content: getResult.data.content } },
|
|
765
776
|
);
|
|
766
777
|
|
package/src/deno.js
CHANGED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AgUiRuntimeRunIdSchema } from "./runtime-ag-ui-contract.js";
|
|
3
|
+
import { RunResumeSessionManager } from "./runtime/index.js";
|
|
4
|
+
|
|
5
|
+
const TOOL_CALL_ID_SCHEMA = z.string().min(1).max(128);
|
|
6
|
+
|
|
7
|
+
export const HumanInputOptionSchema = z.object({
|
|
8
|
+
value: z.string(),
|
|
9
|
+
label: z.string(),
|
|
10
|
+
description: z.string().optional(),
|
|
11
|
+
recommended: z.boolean().optional(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const BaseHumanInputFieldSchema = z.object({
|
|
15
|
+
name: z.string().min(1).max(128),
|
|
16
|
+
label: z.string().min(1).max(256),
|
|
17
|
+
description: z.string().max(1024).optional(),
|
|
18
|
+
required: z.boolean().optional().default(false),
|
|
19
|
+
secret: z.boolean().optional().default(false),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const HumanInputFieldSchema = z.discriminatedUnion("type", [
|
|
23
|
+
BaseHumanInputFieldSchema.extend({
|
|
24
|
+
type: z.enum(["text", "email", "url", "password", "number"]),
|
|
25
|
+
placeholder: z.string().max(512).optional(),
|
|
26
|
+
defaultValue: z.string().optional(),
|
|
27
|
+
pattern: z.string().max(512).optional(),
|
|
28
|
+
minLength: z.number().int().nonnegative().optional(),
|
|
29
|
+
maxLength: z.number().int().positive().optional(),
|
|
30
|
+
min: z.number().optional(),
|
|
31
|
+
max: z.number().optional(),
|
|
32
|
+
}),
|
|
33
|
+
BaseHumanInputFieldSchema.extend({
|
|
34
|
+
type: z.literal("textarea"),
|
|
35
|
+
placeholder: z.string().max(512).optional(),
|
|
36
|
+
defaultValue: z.string().optional(),
|
|
37
|
+
minLength: z.number().int().nonnegative().optional(),
|
|
38
|
+
maxLength: z.number().int().positive().optional(),
|
|
39
|
+
rows: z.number().int().positive().optional().default(3),
|
|
40
|
+
}),
|
|
41
|
+
BaseHumanInputFieldSchema.extend({
|
|
42
|
+
type: z.literal("select"),
|
|
43
|
+
options: z.array(HumanInputOptionSchema).min(1),
|
|
44
|
+
defaultValue: z.string().optional(),
|
|
45
|
+
placeholder: z.string().max(512).optional(),
|
|
46
|
+
}),
|
|
47
|
+
BaseHumanInputFieldSchema.extend({
|
|
48
|
+
type: z.literal("checkbox"),
|
|
49
|
+
defaultValue: z.boolean().optional().default(false),
|
|
50
|
+
}),
|
|
51
|
+
BaseHumanInputFieldSchema.extend({
|
|
52
|
+
type: z.literal("radio"),
|
|
53
|
+
options: z.array(HumanInputOptionSchema).min(1),
|
|
54
|
+
defaultValue: z.string().optional(),
|
|
55
|
+
}),
|
|
56
|
+
BaseHumanInputFieldSchema.extend({
|
|
57
|
+
type: z.literal("confirm"),
|
|
58
|
+
confirmLabel: z.string().max(64).optional().default("Yes"),
|
|
59
|
+
denyLabel: z.string().max(64).optional().default("No"),
|
|
60
|
+
}),
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
export const HumanInputRequestSchema = z.object({
|
|
64
|
+
title: z.string().min(1).max(256),
|
|
65
|
+
description: z.string().max(2048).optional(),
|
|
66
|
+
fields: z.array(HumanInputFieldSchema).min(1),
|
|
67
|
+
submitLabel: z.string().max(64).optional().default("Submit"),
|
|
68
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
export const HumanInputResponseValuesSchema = z.record(
|
|
72
|
+
z.string(),
|
|
73
|
+
z.union([z.string(), z.boolean(), z.number(), z.null()]),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
export const HumanInputResultSchema = z.discriminatedUnion("submitted", [
|
|
77
|
+
z.object({
|
|
78
|
+
submitted: z.literal(true),
|
|
79
|
+
values: HumanInputResponseValuesSchema,
|
|
80
|
+
}),
|
|
81
|
+
z.object({
|
|
82
|
+
submitted: z.literal(false),
|
|
83
|
+
values: HumanInputResponseValuesSchema.default({}),
|
|
84
|
+
}),
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
export const HumanInputPendingRequestSchema = z.object({
|
|
88
|
+
runId: AgUiRuntimeRunIdSchema,
|
|
89
|
+
toolCallId: TOOL_CALL_ID_SCHEMA,
|
|
90
|
+
request: HumanInputRequestSchema,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
export type HumanInputOption = z.infer<typeof HumanInputOptionSchema>;
|
|
94
|
+
export type HumanInputField = z.infer<typeof HumanInputFieldSchema>;
|
|
95
|
+
export type HumanInputFieldInput = z.input<typeof HumanInputFieldSchema>;
|
|
96
|
+
export type HumanInputRequest = z.infer<typeof HumanInputRequestSchema>;
|
|
97
|
+
export type HumanInputRequestInput = z.input<typeof HumanInputRequestSchema>;
|
|
98
|
+
export type HumanInputResult = z.infer<typeof HumanInputResultSchema>;
|
|
99
|
+
export type HumanInputPendingRequest = z.infer<typeof HumanInputPendingRequestSchema>;
|
|
100
|
+
|
|
101
|
+
type HumanInputResumeValue = {
|
|
102
|
+
result: unknown;
|
|
103
|
+
isError: boolean;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export interface WaitForHumanInputOptions {
|
|
107
|
+
sessionManager: RunResumeSessionManager<HumanInputResumeValue>;
|
|
108
|
+
runId: string;
|
|
109
|
+
toolCallId: string;
|
|
110
|
+
request: HumanInputRequestInput;
|
|
111
|
+
onRequest?: ((request: HumanInputPendingRequest) => void | Promise<void>) | undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export class HumanInputResumeError extends Error {
|
|
115
|
+
constructor(readonly detail: unknown) {
|
|
116
|
+
super(
|
|
117
|
+
typeof detail === "string" ? detail : "Human input resume failed",
|
|
118
|
+
);
|
|
119
|
+
this.name = "HumanInputResumeError";
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export class InvalidHumanInputResultError extends Error {
|
|
124
|
+
constructor(readonly detail: z.ZodIssue[]) {
|
|
125
|
+
super("Invalid human input resume payload");
|
|
126
|
+
this.name = "InvalidHumanInputResultError";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export async function waitForHumanInput(
|
|
131
|
+
options: WaitForHumanInputOptions,
|
|
132
|
+
): Promise<HumanInputResult> {
|
|
133
|
+
const pendingRequest = HumanInputPendingRequestSchema.parse({
|
|
134
|
+
runId: options.runId,
|
|
135
|
+
toolCallId: options.toolCallId,
|
|
136
|
+
request: options.request,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await options.onRequest?.(pendingRequest);
|
|
140
|
+
|
|
141
|
+
const resumed = await options.sessionManager.waitForSignal(options.runId, options.toolCallId);
|
|
142
|
+
if (resumed.isError) {
|
|
143
|
+
throw new HumanInputResumeError(resumed.result);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const parsed = HumanInputResultSchema.safeParse(resumed.result);
|
|
147
|
+
if (!parsed.success) {
|
|
148
|
+
throw new InvalidHumanInputResultError(parsed.error.issues);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return parsed.data;
|
|
152
|
+
}
|
package/src/src/agent/index.ts
CHANGED
|
@@ -162,6 +162,24 @@ export {
|
|
|
162
162
|
AgUiRequestSchema,
|
|
163
163
|
createAgUiHandler,
|
|
164
164
|
} from "./ag-ui-handler.js";
|
|
165
|
+
export {
|
|
166
|
+
type HumanInputField,
|
|
167
|
+
type HumanInputFieldInput,
|
|
168
|
+
HumanInputFieldSchema,
|
|
169
|
+
type HumanInputOption,
|
|
170
|
+
HumanInputOptionSchema,
|
|
171
|
+
type HumanInputPendingRequest,
|
|
172
|
+
HumanInputPendingRequestSchema,
|
|
173
|
+
type HumanInputRequest,
|
|
174
|
+
type HumanInputRequestInput,
|
|
175
|
+
HumanInputRequestSchema,
|
|
176
|
+
type HumanInputResult,
|
|
177
|
+
HumanInputResultSchema,
|
|
178
|
+
HumanInputResumeError,
|
|
179
|
+
InvalidHumanInputResultError,
|
|
180
|
+
waitForHumanInput,
|
|
181
|
+
type WaitForHumanInputOptions,
|
|
182
|
+
} from "./human-input.js";
|
|
165
183
|
export {
|
|
166
184
|
type ChatHandlerBeforeStream,
|
|
167
185
|
type ChatHandlerBeforeStreamContext,
|
package/src/src/mcp/server.ts
CHANGED
|
@@ -128,9 +128,8 @@ export class MCPServer {
|
|
|
128
128
|
private sessionManager = new SessionManager();
|
|
129
129
|
private taskStore = new TaskStore();
|
|
130
130
|
private pendingTasks = new Map<string, Promise<void>>();
|
|
131
|
-
// TODO(#842): capabilities should be stored per-session (keyed by MCP-Session-Id)
|
|
132
|
-
// so concurrent clients don't overwrite each other's capability flags.
|
|
133
131
|
private clientCapabilities: Record<string, unknown> = {};
|
|
132
|
+
private sessionCapabilities = new Map<string, Record<string, unknown>>();
|
|
134
133
|
|
|
135
134
|
/** Callback for server-initiated notifications. Set by transport layer. */
|
|
136
135
|
onNotification?: (notification: { jsonrpc: "2.0"; method: string; params?: unknown }) => void;
|
|
@@ -167,8 +166,11 @@ export class MCPServer {
|
|
|
167
166
|
this.integrationsLoaded = false;
|
|
168
167
|
}
|
|
169
168
|
|
|
170
|
-
clientSupportsElicitation(mode: "form" | "url"): boolean {
|
|
171
|
-
const
|
|
169
|
+
clientSupportsElicitation(mode: "form" | "url", sessionId?: string): boolean {
|
|
170
|
+
const capabilities = sessionId
|
|
171
|
+
? this.sessionCapabilities.get(sessionId) ?? {}
|
|
172
|
+
: this.clientCapabilities;
|
|
173
|
+
const raw = capabilities.elicitation;
|
|
172
174
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return false;
|
|
173
175
|
const elicitation = raw as Record<string, unknown>;
|
|
174
176
|
// Per MCP spec: empty elicitation object implies basic form support (backwards compat)
|
|
@@ -650,7 +652,10 @@ export class MCPServer {
|
|
|
650
652
|
// DELETE = terminate session
|
|
651
653
|
if (request.method === "DELETE") {
|
|
652
654
|
const sessionId = request.headers.get("MCP-Session-Id");
|
|
653
|
-
if (sessionId)
|
|
655
|
+
if (sessionId) {
|
|
656
|
+
this.sessionManager.terminate(sessionId);
|
|
657
|
+
this.sessionCapabilities.delete(sessionId);
|
|
658
|
+
}
|
|
654
659
|
return new dntShim.Response(null, { status: 200, headers: this.getCORSHeaders(requestOrigin) });
|
|
655
660
|
}
|
|
656
661
|
|
|
@@ -692,7 +697,11 @@ export class MCPServer {
|
|
|
692
697
|
if (rpcRequest.method === "initialize") {
|
|
693
698
|
const context = this.extractRequestContext(request);
|
|
694
699
|
const rpcResponse = await this.handleRequest(rpcRequest, context);
|
|
700
|
+
const clientCaps =
|
|
701
|
+
toParamsRecord(rpcRequest.params).capabilities as Record<string, unknown> ??
|
|
702
|
+
{};
|
|
695
703
|
const sessionId = this.sessionManager.create();
|
|
704
|
+
this.sessionCapabilities.set(sessionId, clientCaps);
|
|
696
705
|
responseHeaders["MCP-Session-Id"] = sessionId;
|
|
697
706
|
return createJSONResponse(rpcResponse, { headers: responseHeaders });
|
|
698
707
|
}
|