veryfront 0.1.644 → 0.1.646
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/deno.js +1 -1
- package/esm/src/agent/factory.js +7 -7
- package/esm/src/agent/hosted/chat-preparation.d.ts +4 -1
- package/esm/src/agent/hosted/chat-preparation.d.ts.map +1 -1
- package/esm/src/agent/hosted/chat-preparation.js +8 -0
- package/esm/src/agent/hosted/chat-runtime-tool-assembly.d.ts +1 -0
- package/esm/src/agent/hosted/chat-runtime-tool-assembly.d.ts.map +1 -1
- package/esm/src/agent/hosted/chat-runtime-tool-assembly.js +4 -1
- package/esm/src/agent/hosted/default-chat-runtime.d.ts.map +1 -1
- package/esm/src/agent/hosted/default-chat-runtime.js +5 -3
- package/esm/src/agent/hosted/project-remote-tool-source.d.ts.map +1 -1
- package/esm/src/agent/hosted/project-remote-tool-source.js +25 -1
- package/esm/src/agent/hosted/veryfront-cloud-agent-service.d.ts +5 -4
- package/esm/src/agent/hosted/veryfront-cloud-agent-service.d.ts.map +1 -1
- package/esm/src/agent/hosted/veryfront-cloud-agent-service.js +7 -6
- package/esm/src/agent/index.d.ts +2 -2
- package/esm/src/agent/index.d.ts.map +1 -1
- package/esm/src/agent/index.js +1 -1
- package/esm/src/agent/runtime/index.d.ts +1 -1
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +25 -20
- package/esm/src/agent/runtime/mcp-server-tool-sources.d.ts +9 -0
- package/esm/src/agent/runtime/mcp-server-tool-sources.d.ts.map +1 -0
- package/esm/src/agent/runtime/mcp-server-tool-sources.js +59 -0
- package/esm/src/agent/runtime/message-preparation.d.ts +1 -0
- package/esm/src/agent/runtime/message-preparation.d.ts.map +1 -1
- package/esm/src/agent/runtime/message-preparation.js +3 -1
- package/esm/src/agent/runtime/model-tool-converter.d.ts +1 -1
- package/esm/src/agent/runtime/model-tool-converter.d.ts.map +1 -1
- package/esm/src/agent/runtime/model-tool-converter.js +1 -1
- package/esm/src/agent/service/mcp-server-config.d.ts +4 -0
- package/esm/src/agent/service/mcp-server-config.d.ts.map +1 -1
- package/esm/src/agent/streaming/fork-runtime-stream.js +1 -1
- package/esm/src/agent/types.d.ts +44 -5
- package/esm/src/agent/types.d.ts.map +1 -1
- package/esm/src/chat/message-prep.d.ts +5 -1
- package/esm/src/chat/message-prep.d.ts.map +1 -1
- package/esm/src/chat/message-prep.js +55 -2
- package/esm/src/discovery/transpiler.d.ts.map +1 -1
- package/esm/src/discovery/transpiler.js +3 -1
- package/esm/src/internal-agents/run-stream.d.ts.map +1 -1
- package/esm/src/internal-agents/run-stream.js +2 -2
- package/esm/src/react/components/chat/chat/components/skill-badge.d.ts +1 -1
- package/esm/src/react/components/chat/chat/components/skill-badge.js +3 -3
- package/esm/src/react/components/chat/chat/utils/message-parts.d.ts +1 -1
- package/esm/src/react/components/chat/chat/utils/message-parts.d.ts.map +1 -1
- package/esm/src/react/components/chat/chat/utils/message-parts.js +4 -4
- package/esm/src/rendering/orchestrator/module-loader/index.d.ts +7 -0
- package/esm/src/rendering/orchestrator/module-loader/index.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-loader/index.js +33 -1
- package/esm/src/server/handlers/dev/framework-candidates.generated.js +7 -7
- package/esm/src/server/handlers/request/agent-stream.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/agent-stream.handler.js +35 -10
- package/esm/src/skill/prompt-augmentation.d.ts +1 -1
- package/esm/src/skill/prompt-augmentation.js +5 -5
- package/esm/src/skill/tools.d.ts +6 -6
- package/esm/src/skill/tools.js +13 -13
- package/esm/src/skill/types.d.ts +1 -1
- package/esm/src/skill/types.js +3 -3
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.d.ts +23 -0
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.js +85 -2
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-parts.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/utils/message-parts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,YAAY,EACb,MAAM,qCAAqC,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAEvD,+CAA+C;AAC/C,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAQ3D;AAED,qCAAqC;AACrC,wBAAgB,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,IAAI,YAAY,GAAG,mBAAmB,CAG5F;AAQD,
|
|
1
|
+
{"version":3,"file":"message-parts.d.ts","sourceRoot":"","sources":["../../../../../../../src/src/react/components/chat/chat/utils/message-parts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,YAAY,EACb,MAAM,qCAAqC,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAEvD,+CAA+C;AAC/C,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAQ3D;AAED,qCAAqC;AACrC,wBAAgB,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,IAAI,YAAY,GAAG,mBAAmB,CAG5F;AAQD,oDAAoD;AACpD,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,mBAAmB,GAAG,OAAO,CAEjF;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,CAC7B,IAAI,EAAE,eAAe,GACpB,IAAI,IAAI;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAAA;CAAE,CAE3E;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,YAAY,GAAG,mBAAmB,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,SAAS,EAAE,CAkDvE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,MAAM,EAAE,CAiC1E"}
|
|
@@ -18,11 +18,11 @@ export function isToolPart(part) {
|
|
|
18
18
|
return part.type.startsWith("tool-") && part.type !== "tool-result";
|
|
19
19
|
}
|
|
20
20
|
const SKILL_TOOL_NAMES = new Set([
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
21
|
+
"load_skill",
|
|
22
|
+
"load_skill_reference",
|
|
23
|
+
"execute_skill_script",
|
|
24
24
|
]);
|
|
25
|
-
/** Check if a tool part is a skill-related tool
|
|
25
|
+
/** Check if a tool part is a skill-related tool. */
|
|
26
26
|
export function isSkillToolPart(tool) {
|
|
27
27
|
return SKILL_TOOL_NAMES.has(tool.toolName);
|
|
28
28
|
}
|
|
@@ -21,6 +21,13 @@ export interface ModuleLoaderConfig {
|
|
|
21
21
|
/** React version for transforms (from project config) */
|
|
22
22
|
reactVersion?: string;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Detect a dynamic `import()` failure caused by a module file that is missing on
|
|
26
|
+
* disk (e.g. a stale/evicted cached page module). Matches Node/Deno's
|
|
27
|
+
* `ERR_MODULE_NOT_FOUND` as well as the "Cannot find module" / "Module not found"
|
|
28
|
+
* message variants the runtimes surface for a missing `import()` target.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isMissingModuleError(error: unknown): boolean;
|
|
24
31
|
/**
|
|
25
32
|
* Load a module by path, transforming it and its dependencies.
|
|
26
33
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AA4BzE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAkJpE,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,cAAc,EAC5B,MAAM,EAAE,kBAAkB,EAC1B,eAAe,UAAQ,GACtB,OAAO,CAAC,MAAM,CAAC,CAsSjB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAyBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAI5D;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA6DlC"}
|
|
@@ -18,7 +18,7 @@ import { validateCachedBundlesByManifestOrCode } from "../../../transforms/esm/c
|
|
|
18
18
|
import { getHttpBundleCacheDir, getMdxEsmCacheDir } from "../../../utils/cache-dir.js";
|
|
19
19
|
import { dirname, join, normalize } from "../../../platform/compat/path/index.js";
|
|
20
20
|
import { hashCodeHex } from "../../../utils/hash-utils.js";
|
|
21
|
-
import { getModulePathCache, lookupMdxEsmCache, saveModulePathCache, } from "../../../transforms/mdx/esm-module-loader/cache/index.js";
|
|
21
|
+
import { getModulePathCache, invalidateMdxEsmModule, lookupMdxEsmCache, saveModulePathCache, } from "../../../transforms/mdx/esm-module-loader/cache/index.js";
|
|
22
22
|
import { buildMdxEsmPathCacheKey } from "../../../transforms/mdx/esm-module-loader/cache-format.js";
|
|
23
23
|
const logger = rendererLogger.component("module-loader");
|
|
24
24
|
// Re-export utilities
|
|
@@ -363,6 +363,19 @@ async function getModuleCacheDir(config) {
|
|
|
363
363
|
}
|
|
364
364
|
return getProjectTmpDir(projectId ?? projectDir);
|
|
365
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* Detect a dynamic `import()` failure caused by a module file that is missing on
|
|
368
|
+
* disk (e.g. a stale/evicted cached page module). Matches Node/Deno's
|
|
369
|
+
* `ERR_MODULE_NOT_FOUND` as well as the "Cannot find module" / "Module not found"
|
|
370
|
+
* message variants the runtimes surface for a missing `import()` target.
|
|
371
|
+
*/
|
|
372
|
+
export function isMissingModuleError(error) {
|
|
373
|
+
if (!(error instanceof Error))
|
|
374
|
+
return false;
|
|
375
|
+
if (error.code === "ERR_MODULE_NOT_FOUND")
|
|
376
|
+
return true;
|
|
377
|
+
return /cannot find module|module not found/i.test(error.message);
|
|
378
|
+
}
|
|
366
379
|
/**
|
|
367
380
|
* Load a module by path, transforming it and its dependencies.
|
|
368
381
|
*
|
|
@@ -395,6 +408,25 @@ export async function loadModule(filePath, config) {
|
|
|
395
408
|
return await import(`file://${tempFilePath}?t=${Date.now()}&retry=1`);
|
|
396
409
|
}
|
|
397
410
|
}
|
|
411
|
+
// Self-heal: the cached module artifact resolved to a path that no longer
|
|
412
|
+
// exists on disk (evicted, or rebuilt under a different content hash by a
|
|
413
|
+
// racing write). Rather than hard-failing the whole page render (#2077),
|
|
414
|
+
// treat it as a cache miss: drop the stale cache pointers so we don't get
|
|
415
|
+
// handed the same dead path, rebuild the module from source, and retry the
|
|
416
|
+
// import once. Skip HTTP-bundle misses, which have dedicated recovery above.
|
|
417
|
+
if (!bundleMatch && isMissingModuleError(error)) {
|
|
418
|
+
logger.warn("Cached module missing on disk, rebuilding and retrying import", {
|
|
419
|
+
filePath,
|
|
420
|
+
tempFilePath,
|
|
421
|
+
});
|
|
422
|
+
config.moduleCache.delete(getModuleCacheKey(filePath, config.projectId, config.projectDir, config.contentSourceId));
|
|
423
|
+
// tmpDir is the exact cache dir this module was registered under, so the
|
|
424
|
+
// invalidation stays scoped to this tenant (the path-cache key is not
|
|
425
|
+
// project-scoped — see invalidateMdxEsmModule).
|
|
426
|
+
invalidateMdxEsmModule(tmpDir, filePath, config.projectDir, config.reactVersion);
|
|
427
|
+
const rebuiltPath = await transformModuleWithDeps(filePath, tmpDir, localAdapter, config);
|
|
428
|
+
return await import(`file://${rebuiltPath}?t=${Date.now()}&rebuilt=1`);
|
|
429
|
+
}
|
|
398
430
|
logger.error("Failed to import module:", {
|
|
399
431
|
filePath,
|
|
400
432
|
tempFilePath,
|
|
@@ -2934,9 +2934,8 @@ export const FRAMEWORK_CANDIDATES = [
|
|
|
2934
2934
|
"etc.,",
|
|
2935
2935
|
"event:",
|
|
2936
2936
|
"event?.preventDefault()}",
|
|
2937
|
-
"
|
|
2938
|
-
"
|
|
2939
|
-
"execute-skill-script).",
|
|
2937
|
+
"execute_skill_script",
|
|
2938
|
+
"execute_skill_script).",
|
|
2940
2939
|
"exist",
|
|
2941
2940
|
"expected:",
|
|
2942
2941
|
"export",
|
|
@@ -3607,16 +3606,16 @@ export const FRAMEWORK_CANDIDATES = [
|
|
|
3607
3606
|
"listboxId",
|
|
3608
3607
|
"load():",
|
|
3609
3608
|
"load();",
|
|
3610
|
-
"load-skill",
|
|
3611
|
-
"load-skill,",
|
|
3612
|
-
"load-skill-reference",
|
|
3613
|
-
"load-skill-reference,",
|
|
3614
3609
|
"loadIndex(key:",
|
|
3615
3610
|
"loadIndex(storageKey);",
|
|
3616
3611
|
"loadMermaid():",
|
|
3617
3612
|
"loadMermaid();",
|
|
3618
3613
|
"loadThread(key:",
|
|
3619
3614
|
"loadThread(storageKey,",
|
|
3615
|
+
"load_skill",
|
|
3616
|
+
"load_skill,",
|
|
3617
|
+
"load_skill_reference",
|
|
3618
|
+
"load_skill_reference,",
|
|
3620
3619
|
"loaded.length",
|
|
3621
3620
|
"loaded.push(thread);",
|
|
3622
3621
|
"loaded.sort((a,",
|
|
@@ -5338,6 +5337,7 @@ export const FRAMEWORK_CANDIDATES = [
|
|
|
5338
5337
|
"tool-primitives.tsx",
|
|
5339
5338
|
"tool-result",
|
|
5340
5339
|
"tool-search",
|
|
5340
|
+
"tool.",
|
|
5341
5341
|
"tool.error",
|
|
5342
5342
|
"tool.errorText}",
|
|
5343
5343
|
"tool.error}",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-stream.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-stream.handler.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-stream.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/agent-stream.handler.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EACL,4BAA4B,EAE7B,MAAM,2CAA2C,CAAC;AAwBnD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAUnG,MAAM,WAAW,sBACf,SAAQ,yBAAyB,EAAE,+BAA+B;IAClE,4BAA4B,CAAC,EAAE,OAAO,4BAA4B,CAAC;CACpE;AA2SD,qBAAa,kBAAmB,SAAQ,WAAW;IASrC,OAAO,CAAC,QAAQ,CAAC,IAAI;IARjC,QAAQ,EAAE,eAAe,CAMvB;gBAE2B,IAAI,GAAE,sBAAoC;IAIvE,OAAO,CAAC,sBAAsB;IAwBxB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CAiKxE"}
|
|
@@ -73,6 +73,28 @@ function mergeAllowedRemoteTools(current, requestedToolNames) {
|
|
|
73
73
|
}
|
|
74
74
|
return [...allowed].sort();
|
|
75
75
|
}
|
|
76
|
+
function getVeryfrontApiMcpPolicy(agent) {
|
|
77
|
+
const requestedToolNames = new Set();
|
|
78
|
+
const deniedToolNames = new Set();
|
|
79
|
+
let allowAll = false;
|
|
80
|
+
for (const server of agent.config.mcpServers ?? []) {
|
|
81
|
+
if (!("kind" in server) || server.kind !== "veryfront-api") {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
for (const toolName of server.toolPolicy?.deny ?? []) {
|
|
85
|
+
deniedToolNames.add(toolName);
|
|
86
|
+
}
|
|
87
|
+
if (server.toolPolicy?.allow) {
|
|
88
|
+
for (const toolName of server.toolPolicy.allow) {
|
|
89
|
+
requestedToolNames.add(toolName);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
allowAll = true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return { allowAll, requestedToolNames: [...requestedToolNames], deniedToolNames };
|
|
97
|
+
}
|
|
76
98
|
function hasVeryfrontPlatformRemoteToolSource(remoteTools) {
|
|
77
99
|
return remoteTools?.some((source) => source.id === VERYFRONT_PLATFORM_REMOTE_TOOL_SOURCE_ID) ??
|
|
78
100
|
false;
|
|
@@ -85,11 +107,12 @@ function createStaticRemoteToolSource(source, toolDefinitions) {
|
|
|
85
107
|
};
|
|
86
108
|
}
|
|
87
109
|
async function withVeryfrontPlatformRemoteTools(input) {
|
|
110
|
+
const veryfrontApiMcpPolicy = getVeryfrontApiMcpPolicy(input.agent);
|
|
88
111
|
const requestedToolNames = getRequestedUnresolvedBooleanToolNames({
|
|
89
112
|
agent: input.agent,
|
|
90
113
|
availableToolNames: input.availableToolNames,
|
|
91
|
-
});
|
|
92
|
-
if (requestedToolNames.length === 0 || !input.token) {
|
|
114
|
+
}).concat(veryfrontApiMcpPolicy.requestedToolNames);
|
|
115
|
+
if ((!veryfrontApiMcpPolicy.allowAll && requestedToolNames.length === 0) || !input.token) {
|
|
93
116
|
return input.agent;
|
|
94
117
|
}
|
|
95
118
|
const apiUrl = getHostEnv("VERYFRONT_API_URL") ?? "https://api.veryfront.com";
|
|
@@ -114,24 +137,26 @@ async function withVeryfrontPlatformRemoteTools(input) {
|
|
|
114
137
|
? new Set(platformToolDefinitions.map((tool) => tool.name))
|
|
115
138
|
: null;
|
|
116
139
|
const requestedPlatformToolNames = platformToolNames
|
|
117
|
-
? requestedToolNames.filter((toolName) => platformToolNames.has(toolName))
|
|
118
|
-
: requestedToolNames;
|
|
140
|
+
? (veryfrontApiMcpPolicy.allowAll ? [...platformToolNames] : requestedToolNames).filter((toolName) => platformToolNames.has(toolName) && !veryfrontApiMcpPolicy.deniedToolNames.has(toolName))
|
|
141
|
+
: requestedToolNames.filter((toolName) => !veryfrontApiMcpPolicy.deniedToolNames.has(toolName));
|
|
119
142
|
if (requestedPlatformToolNames.length === 0) {
|
|
120
143
|
return input.agent;
|
|
121
144
|
}
|
|
122
|
-
const
|
|
145
|
+
const runtimeRemoteToolConfig = input.agent.config;
|
|
146
|
+
const remoteTools = runtimeRemoteToolConfig.__vfRemoteToolSources ?? [];
|
|
123
147
|
const platformRemoteToolSources = hasVeryfrontPlatformRemoteToolSource(remoteTools) ? [] : [
|
|
124
148
|
platformToolDefinitions
|
|
125
149
|
? createStaticRemoteToolSource(platformRemoteToolSource, platformToolDefinitions)
|
|
126
150
|
: platformRemoteToolSource,
|
|
127
151
|
];
|
|
152
|
+
const runtimeConfig = {
|
|
153
|
+
...input.agent.config,
|
|
154
|
+
__vfAllowedRemoteTools: mergeAllowedRemoteTools(runtimeRemoteToolConfig.__vfAllowedRemoteTools, requestedPlatformToolNames),
|
|
155
|
+
__vfRemoteToolSources: [...remoteTools, ...platformRemoteToolSources],
|
|
156
|
+
};
|
|
128
157
|
return {
|
|
129
158
|
...input.agent,
|
|
130
|
-
config:
|
|
131
|
-
...input.agent.config,
|
|
132
|
-
allowedRemoteTools: mergeAllowedRemoteTools(input.agent.config.allowedRemoteTools, requestedPlatformToolNames),
|
|
133
|
-
remoteTools: [...remoteTools, ...platformRemoteToolSources],
|
|
134
|
-
},
|
|
159
|
+
config: runtimeConfig,
|
|
135
160
|
};
|
|
136
161
|
}
|
|
137
162
|
function buildAgentStreamEnv(input) {
|
|
@@ -10,7 +10,7 @@ import type { Skill } from "./types.js";
|
|
|
10
10
|
* Build the skill manifest prompt section for an agent's system prompt.
|
|
11
11
|
*
|
|
12
12
|
* Lists all available skills with their descriptions and instructions
|
|
13
|
-
* on how to use the skill tools (
|
|
13
|
+
* on how to use the skill tools (load_skill, load_skill_reference, execute_skill_script).
|
|
14
14
|
*
|
|
15
15
|
* @param skills - Map of resolved skills for the agent
|
|
16
16
|
* @returns Prompt section string, or empty string if no skills
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Build the skill manifest prompt section for an agent's system prompt.
|
|
10
10
|
*
|
|
11
11
|
* Lists all available skills with their descriptions and instructions
|
|
12
|
-
* on how to use the skill tools (
|
|
12
|
+
* on how to use the skill tools (load_skill, load_skill_reference, execute_skill_script).
|
|
13
13
|
*
|
|
14
14
|
* @param skills - Map of resolved skills for the agent
|
|
15
15
|
* @returns Prompt section string, or empty string if no skills
|
|
@@ -20,7 +20,7 @@ export function buildSkillManifestPrompt(skills) {
|
|
|
20
20
|
const lines = [
|
|
21
21
|
"## Available Skills",
|
|
22
22
|
"",
|
|
23
|
-
"You have access to skills via tool calling. IMPORTANT: You MUST call the
|
|
23
|
+
"You have access to skills via tool calling. IMPORTANT: You MUST call the load_skill tool (not write it as text) to activate a skill before performing skill-related tasks.",
|
|
24
24
|
"",
|
|
25
25
|
];
|
|
26
26
|
for (const [id, skill] of skills) {
|
|
@@ -29,8 +29,8 @@ export function buildSkillManifestPrompt(skills) {
|
|
|
29
29
|
lines.push("");
|
|
30
30
|
lines.push("### Skill Tools (call these as tools, never write them as text)");
|
|
31
31
|
lines.push("");
|
|
32
|
-
lines.push("-
|
|
33
|
-
lines.push("-
|
|
34
|
-
lines.push("-
|
|
32
|
+
lines.push("- load_skill: Call with { skillId } to load a skill's full instructions and available references/resources/scripts");
|
|
33
|
+
lines.push("- load_skill_reference: Call with { skillId, reference } to read a file from the skill's references/, resources/, or assets/ directory");
|
|
34
|
+
lines.push("- execute_skill_script: Call with { skillId, script, args?, env?, timeoutMs? } to execute a script");
|
|
35
35
|
return lines.join("\n");
|
|
36
36
|
}
|
package/esm/src/skill/tools.d.ts
CHANGED
|
@@ -2,25 +2,25 @@
|
|
|
2
2
|
* Skill Tools
|
|
3
3
|
*
|
|
4
4
|
* Three tools exposed to agents for interacting with skills:
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
5
|
+
* - load_skill: Load a skill's full instructions
|
|
6
|
+
* - load_skill_reference: Read a reference file from a skill
|
|
7
|
+
* - execute_skill_script: Execute a script from a skill
|
|
8
8
|
*
|
|
9
9
|
* @module
|
|
10
10
|
*/
|
|
11
11
|
import type { Tool } from "../tool/index.js";
|
|
12
12
|
/**
|
|
13
|
-
* Create the
|
|
13
|
+
* Create the load_skill tool.
|
|
14
14
|
* Loads a skill's full instructions, available references, and scripts.
|
|
15
15
|
*/
|
|
16
16
|
export declare function createLoadSkillTool(): Tool;
|
|
17
17
|
/**
|
|
18
|
-
* Create the
|
|
18
|
+
* Create the load_skill_reference tool.
|
|
19
19
|
* Reads a reference file from a skill's references/, resources/, or assets/ directory.
|
|
20
20
|
*/
|
|
21
21
|
export declare function createLoadSkillReferenceTool(): Tool;
|
|
22
22
|
/**
|
|
23
|
-
* Create the
|
|
23
|
+
* Create the execute_skill_script tool.
|
|
24
24
|
* Executes a script from a skill's scripts/ directory.
|
|
25
25
|
*/
|
|
26
26
|
export declare function createExecuteSkillScriptTool(): Tool;
|
package/esm/src/skill/tools.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Skill Tools
|
|
3
3
|
*
|
|
4
4
|
* Three tools exposed to agents for interacting with skills:
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
5
|
+
* - load_skill: Load a skill's full instructions
|
|
6
|
+
* - load_skill_reference: Read a reference file from a skill
|
|
7
|
+
* - execute_skill_script: Execute a script from a skill
|
|
8
8
|
*
|
|
9
9
|
* @module
|
|
10
10
|
*/
|
|
@@ -52,23 +52,23 @@ async function readSkillFile(skill, path) {
|
|
|
52
52
|
}
|
|
53
53
|
function buildSkillAvailabilityNote(references, scripts) {
|
|
54
54
|
if (scripts.length === 0 && references.length === 0) {
|
|
55
|
-
return "This skill has no scripts or reference files. Do NOT call
|
|
55
|
+
return "This skill has no scripts or reference files. Do NOT call execute_skill_script or load_skill_reference.";
|
|
56
56
|
}
|
|
57
57
|
if (scripts.length === 0) {
|
|
58
|
-
return "This skill has no scripts. Do NOT call
|
|
58
|
+
return "This skill has no scripts. Do NOT call execute_skill_script.";
|
|
59
59
|
}
|
|
60
60
|
if (references.length === 0) {
|
|
61
|
-
return "This skill has no reference files. Do NOT call
|
|
61
|
+
return "This skill has no reference files. Do NOT call load_skill_reference.";
|
|
62
62
|
}
|
|
63
63
|
return undefined;
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
|
-
* Create the
|
|
66
|
+
* Create the load_skill tool.
|
|
67
67
|
* Loads a skill's full instructions, available references, and scripts.
|
|
68
68
|
*/
|
|
69
69
|
export function createLoadSkillTool() {
|
|
70
70
|
return tool({
|
|
71
|
-
id: "
|
|
71
|
+
id: "load_skill",
|
|
72
72
|
description: "Load a skill's full instructions. Returns the skill's markdown instructions, " +
|
|
73
73
|
"allowed tools policy, and lists of available reference files and scripts.",
|
|
74
74
|
inputSchema: getLoadSkillInputSchema(),
|
|
@@ -86,7 +86,7 @@ export function createLoadSkillTool() {
|
|
|
86
86
|
const content = await readSkillFile(skill, skillMdPath);
|
|
87
87
|
// Parse frontmatter to get instructions
|
|
88
88
|
const parsed = await parseSkillFrontmatter(content);
|
|
89
|
-
// List available files the agent can load through
|
|
89
|
+
// List available files the agent can load through load_skill_reference.
|
|
90
90
|
const [references, resources, scripts] = await Promise.all([
|
|
91
91
|
listSkillSubdir(skill.rootPath, SKILL_REFERENCES_DIR, skill.fsAdapter),
|
|
92
92
|
listSkillSubdir(skill.rootPath, SKILL_RESOURCES_DIR, skill.fsAdapter),
|
|
@@ -105,12 +105,12 @@ export function createLoadSkillTool() {
|
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
/**
|
|
108
|
-
* Create the
|
|
108
|
+
* Create the load_skill_reference tool.
|
|
109
109
|
* Reads a reference file from a skill's references/, resources/, or assets/ directory.
|
|
110
110
|
*/
|
|
111
111
|
export function createLoadSkillReferenceTool() {
|
|
112
112
|
return tool({
|
|
113
|
-
id: "
|
|
113
|
+
id: "load_skill_reference",
|
|
114
114
|
description: "Read a reference file from a skill. Only files in the skill's " +
|
|
115
115
|
"references/, resources/, and assets/ directories are accessible.",
|
|
116
116
|
inputSchema: getLoadSkillReferenceInputSchema(),
|
|
@@ -130,12 +130,12 @@ export function createLoadSkillReferenceTool() {
|
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
132
|
/**
|
|
133
|
-
* Create the
|
|
133
|
+
* Create the execute_skill_script tool.
|
|
134
134
|
* Executes a script from a skill's scripts/ directory.
|
|
135
135
|
*/
|
|
136
136
|
export function createExecuteSkillScriptTool() {
|
|
137
137
|
return tool({
|
|
138
|
-
id: "
|
|
138
|
+
id: "execute_skill_script",
|
|
139
139
|
description: "Execute a script from a skill's scripts/ directory. Returns stdout, stderr, and exit code.",
|
|
140
140
|
inputSchema: getExecuteSkillScriptInputSchema(),
|
|
141
141
|
execute: async (input) => {
|
package/esm/src/skill/types.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface SkillMetadata {
|
|
|
37
37
|
/** Arbitrary key-value metadata */
|
|
38
38
|
metadata?: Record<string, string>;
|
|
39
39
|
}
|
|
40
|
-
/** Full skill content returned by
|
|
40
|
+
/** Full skill content returned by load_skill tool */
|
|
41
41
|
export interface SkillContent {
|
|
42
42
|
/** Markdown instructions (body after frontmatter) */
|
|
43
43
|
instructions: string;
|
package/esm/src/skill/types.js
CHANGED
|
@@ -17,9 +17,9 @@ export const SKILL_DESCRIPTION_MAX_LENGTH = 1024;
|
|
|
17
17
|
export const SKILL_MD_FILENAME = "SKILL.md";
|
|
18
18
|
/** Tool IDs that belong to the skill system (single source of truth) */
|
|
19
19
|
export const SKILL_TOOL_IDS = new Set([
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
20
|
+
"load_skill",
|
|
21
|
+
"load_skill_reference",
|
|
22
|
+
"execute_skill_script",
|
|
23
23
|
]);
|
|
24
24
|
/** Conventional subdirectory names */
|
|
25
25
|
export const SKILL_SCRIPTS_DIR = "scripts";
|
|
@@ -24,6 +24,29 @@ export declare function clearModulePathCache(): void;
|
|
|
24
24
|
/** Await any in-flight disk cleanup (for testing only). */
|
|
25
25
|
export declare function waitForDiskCleanup(): Promise<void>;
|
|
26
26
|
export declare function invalidateModulePaths(changedPaths: string[]): void;
|
|
27
|
+
/**
|
|
28
|
+
* Invalidate the cached module path for a single source file in a single cache dir.
|
|
29
|
+
*
|
|
30
|
+
* Unlike {@link invalidateModulePaths} (driven by the file watcher on source
|
|
31
|
+
* edits, which also deletes the stale `.mjs` from disk), this is a targeted,
|
|
32
|
+
* synchronous self-heal for the case where a cached module artifact has already
|
|
33
|
+
* gone missing on disk — evicted, or rebuilt under a different content hash by a
|
|
34
|
+
* racing write — while the in-memory path cache and its verified-deps fast-path
|
|
35
|
+
* still point at the stale path. Clearing both forces the next
|
|
36
|
+
* {@link lookupMdxEsmCache} to report a miss so the module is rebuilt instead of
|
|
37
|
+
* handing back a path whose `import()` fails with ERR_MODULE_NOT_FOUND (#2077).
|
|
38
|
+
*
|
|
39
|
+
* `cacheDir` MUST be the dir that produced the missing path. The path-cache key
|
|
40
|
+
* is scoped only by React version + relative module path (not project/source),
|
|
41
|
+
* so two tenants that both have e.g. `app/page.tsx` share the same key in their
|
|
42
|
+
* separate cache dirs — scanning every dir would evict another tenant's valid
|
|
43
|
+
* entry, so the invalidation is confined to the failing dir.
|
|
44
|
+
*
|
|
45
|
+
* The deletion is also persisted to `_index.json` (fire-and-forget, chained onto
|
|
46
|
+
* the shared disk-cleanup queue like {@link invalidateModulePaths}) so the stale
|
|
47
|
+
* pointer does not resurrect from disk on the next process start.
|
|
48
|
+
*/
|
|
49
|
+
export declare function invalidateMdxEsmModule(cacheDir: string, filePath: string, projectDir?: string, reactVersion?: string): void;
|
|
27
50
|
export declare function clearESMDiskCache(): Promise<void>;
|
|
28
51
|
export declare function clearHttpBundleCache(): Promise<void>;
|
|
29
52
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAI5D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAI9D,eAAO,MAAM,kBAAkB,wBAE7B,CAAC;AA2HH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsBvF;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAezE;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAK3C;AAQD,2DAA2D;AAC3D,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAElD;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAI5D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAI9D,eAAO,MAAM,kBAAkB,wBAE7B,CAAC;AA2HH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsBvF;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAezE;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAK3C;AAQD,2DAA2D;AAC3D,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAElD;AAuBD,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CA0ElE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,SAAwB,GACnC,IAAI,CAgBN;AAOD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAevD;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAc1D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAIzD;AAmBD,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,EAAE,oDAAoD;AAC3E,eAAe,CAAC,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,EAChE,YAAY,SAAwB,GACnC,OAAO,CAAC,iBAAiB,CAAC,CAmJ5B"}
|
|
@@ -184,6 +184,27 @@ let _pendingDiskCleanup = Promise.resolve();
|
|
|
184
184
|
export function waitForDiskCleanup() {
|
|
185
185
|
return _pendingDiskCleanup;
|
|
186
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Persist the given cache dirs' `_index.json` fire-and-forget, chained onto the
|
|
189
|
+
* shared disk-cleanup queue so concurrent invalidations don't clobber each
|
|
190
|
+
* other. Used after an in-memory eviction so the stale pointer does not
|
|
191
|
+
* resurrect from disk on the next process start — callers that drop an entry
|
|
192
|
+
* (e.g. an SSR-only path) may never re-register and re-save it themselves.
|
|
193
|
+
*/
|
|
194
|
+
function queueIndexPersist(cacheDirs) {
|
|
195
|
+
if (cacheDirs.length === 0)
|
|
196
|
+
return;
|
|
197
|
+
const cleanup = async () => {
|
|
198
|
+
for (const cacheDir of cacheDirs) {
|
|
199
|
+
await saveModulePathCache(cacheDir);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
_pendingDiskCleanup = _pendingDiskCleanup.then(cleanup, cleanup).catch((error) => {
|
|
203
|
+
logger.warn(`${LOG_PREFIX_MDX_LOADER} Failed to persist _index.json`, {
|
|
204
|
+
error: error instanceof Error ? error.message : String(error),
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
}
|
|
187
208
|
export function invalidateModulePaths(changedPaths) {
|
|
188
209
|
if (modulePathCaches.size === 0)
|
|
189
210
|
return;
|
|
@@ -250,6 +271,44 @@ export function invalidateModulePaths(changedPaths) {
|
|
|
250
271
|
});
|
|
251
272
|
});
|
|
252
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* Invalidate the cached module path for a single source file in a single cache dir.
|
|
276
|
+
*
|
|
277
|
+
* Unlike {@link invalidateModulePaths} (driven by the file watcher on source
|
|
278
|
+
* edits, which also deletes the stale `.mjs` from disk), this is a targeted,
|
|
279
|
+
* synchronous self-heal for the case where a cached module artifact has already
|
|
280
|
+
* gone missing on disk — evicted, or rebuilt under a different content hash by a
|
|
281
|
+
* racing write — while the in-memory path cache and its verified-deps fast-path
|
|
282
|
+
* still point at the stale path. Clearing both forces the next
|
|
283
|
+
* {@link lookupMdxEsmCache} to report a miss so the module is rebuilt instead of
|
|
284
|
+
* handing back a path whose `import()` fails with ERR_MODULE_NOT_FOUND (#2077).
|
|
285
|
+
*
|
|
286
|
+
* `cacheDir` MUST be the dir that produced the missing path. The path-cache key
|
|
287
|
+
* is scoped only by React version + relative module path (not project/source),
|
|
288
|
+
* so two tenants that both have e.g. `app/page.tsx` share the same key in their
|
|
289
|
+
* separate cache dirs — scanning every dir would evict another tenant's valid
|
|
290
|
+
* entry, so the invalidation is confined to the failing dir.
|
|
291
|
+
*
|
|
292
|
+
* The deletion is also persisted to `_index.json` (fire-and-forget, chained onto
|
|
293
|
+
* the shared disk-cleanup queue like {@link invalidateModulePaths}) so the stale
|
|
294
|
+
* pointer does not resurrect from disk on the next process start.
|
|
295
|
+
*/
|
|
296
|
+
export function invalidateMdxEsmModule(cacheDir, filePath, projectDir, reactVersion = REACT_DEFAULT_VERSION) {
|
|
297
|
+
const cache = modulePathCaches.get(cacheDir);
|
|
298
|
+
if (!cache)
|
|
299
|
+
return;
|
|
300
|
+
const cacheKey = toMdxEsmCacheKey(filePath, projectDir, reactVersion);
|
|
301
|
+
const cachedPath = cache.get(cacheKey);
|
|
302
|
+
if (cachedPath === undefined)
|
|
303
|
+
return;
|
|
304
|
+
cache.delete(cacheKey);
|
|
305
|
+
verifiedModuleDeps.delete(`${cachedPath}:${cacheKey}`);
|
|
306
|
+
logger.debug(`${LOG_PREFIX_MDX_LOADER} Self-heal invalidated missing module`, {
|
|
307
|
+
filePath,
|
|
308
|
+
cachedPath,
|
|
309
|
+
});
|
|
310
|
+
queueIndexPersist([cacheDir]);
|
|
311
|
+
}
|
|
253
312
|
function extractNormalizedCachedModulePath(cachedKey) {
|
|
254
313
|
const normalizedPath = cachedKey.match(/(?:^|:)(_vf_modules\/[^:]+)$/)?.[1] ?? cachedKey;
|
|
255
314
|
return normalizedPath.replace(/^_vf_modules\//, "").replace(/\.js$/, "");
|
|
@@ -312,8 +371,32 @@ recoveryOptions, reactVersion = REACT_DEFAULT_VERSION) {
|
|
|
312
371
|
return { status: "miss" };
|
|
313
372
|
const verifyKey = `${cachedPath}:${cacheKey}`;
|
|
314
373
|
if (verifiedModuleDeps.get(verifyKey)) {
|
|
315
|
-
|
|
316
|
-
|
|
374
|
+
// Fast-path: skip the expensive read + content scans for already-verified
|
|
375
|
+
// modules, but still confirm the artifact is present on disk. A cached module
|
|
376
|
+
// can be evicted or rebuilt under a different content hash out from under us
|
|
377
|
+
// (disk-cache eviction, or a racing rebuild) without going through
|
|
378
|
+
// invalidateModulePaths — which is the only thing that clears this marker.
|
|
379
|
+
// Returning the stale path here makes the SSR loader import() a file that no
|
|
380
|
+
// longer exists and hard-fail the whole page render (#2077), so a single stat
|
|
381
|
+
// (far cheaper than the read + regex scans below) guards correctness.
|
|
382
|
+
try {
|
|
383
|
+
const stat = await getLocalFs().stat(cachedPath);
|
|
384
|
+
if (stat?.isFile) {
|
|
385
|
+
logger.debug(`${LOG_PREFIX_MDX_LOADER} SSR reusing MDX-ESM cache (verified): ${filePath} -> ${cachedPath}`);
|
|
386
|
+
return { status: "hit", path: cachedPath };
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
catch (_) {
|
|
390
|
+
/* expected: verified artifact was evicted/rebuilt; fall through to invalidate */
|
|
391
|
+
}
|
|
392
|
+
// Artifact is gone — drop the stale markers so the caller rebuilds it, and
|
|
393
|
+
// persist the deletion so it can't resurrect from _index.json on restart
|
|
394
|
+
// (an SSR-only caller may never re-register and re-save this entry itself).
|
|
395
|
+
logger.debug(`${LOG_PREFIX_MDX_LOADER} Verified MDX-ESM artifact missing on disk, invalidating`, { filePath, cachedPath });
|
|
396
|
+
verifiedModuleDeps.delete(verifyKey);
|
|
397
|
+
cache.delete(cacheKey);
|
|
398
|
+
queueIndexPersist([cacheDir]);
|
|
399
|
+
return { status: "miss" };
|
|
317
400
|
}
|
|
318
401
|
try {
|
|
319
402
|
const stat = await getLocalFs().stat(cachedPath);
|