replicas-engine 0.1.434 → 0.1.436
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/README.md +1 -0
- package/dist/src/index.js +94 -32
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,6 +97,7 @@ Engine persistence locations:
|
|
|
97
97
|
- `~/.replicas/startHooks.log`
|
|
98
98
|
- Canvas read locations (for `/canvas` endpoints):
|
|
99
99
|
- `~/.claude/plans` (where Claude Code writes its plans)
|
|
100
|
+
- `~/.local/share/opencode/plans` and each repository's `.opencode/plans`
|
|
100
101
|
- `~/.replicas/canvas`
|
|
101
102
|
- Health endpoint readiness signal file:
|
|
102
103
|
- `/var/log/cloud-init-output.log` (if missing, `/health` reports `initializing`)
|
package/dist/src/index.js
CHANGED
|
@@ -506,7 +506,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
506
506
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
507
507
|
|
|
508
508
|
// ../shared/src/e2b.ts
|
|
509
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-14-
|
|
509
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-14-v7";
|
|
510
510
|
|
|
511
511
|
// ../shared/src/runtime-env.ts
|
|
512
512
|
function shellQuotePosix(value) {
|
|
@@ -2792,6 +2792,9 @@ function paginateChatHistory(full, params) {
|
|
|
2792
2792
|
// ../shared/src/routes/codex.ts
|
|
2793
2793
|
var CODEX_AUTH_ENV_KEYS = [
|
|
2794
2794
|
"OPENAI_API_KEY",
|
|
2795
|
+
"AZURE_OPENAI_API_KEY",
|
|
2796
|
+
"CODEX_FOUNDRY_BASE_URL",
|
|
2797
|
+
"CODEX_FOUNDRY_MODEL",
|
|
2795
2798
|
"REPLICAS_CODEX_AUTH_METHOD"
|
|
2796
2799
|
];
|
|
2797
2800
|
function codexAuthEnvFromResponse(response) {
|
|
@@ -2800,13 +2803,21 @@ function codexAuthEnvFromResponse(response) {
|
|
|
2800
2803
|
return { REPLICAS_CODEX_AUTH_METHOD: "oauth" };
|
|
2801
2804
|
case "api_key":
|
|
2802
2805
|
return { OPENAI_API_KEY: response.apiKey, REPLICAS_CODEX_AUTH_METHOD: "api_key" };
|
|
2806
|
+
case "foundry":
|
|
2807
|
+
return {
|
|
2808
|
+
AZURE_OPENAI_API_KEY: response.apiKey,
|
|
2809
|
+
CODEX_FOUNDRY_BASE_URL: response.baseUrl,
|
|
2810
|
+
CODEX_FOUNDRY_MODEL: response.model,
|
|
2811
|
+
REPLICAS_CODEX_AUTH_METHOD: "foundry"
|
|
2812
|
+
};
|
|
2803
2813
|
}
|
|
2804
2814
|
}
|
|
2805
2815
|
var CODEX_AUTH_ENV_KEYS_BY_METHOD = {
|
|
2806
2816
|
none: [],
|
|
2807
2817
|
oauth: ["REPLICAS_CODEX_AUTH_METHOD"],
|
|
2808
2818
|
api_key: ["OPENAI_API_KEY", "REPLICAS_CODEX_AUTH_METHOD"],
|
|
2809
|
-
bedrock: []
|
|
2819
|
+
bedrock: [],
|
|
2820
|
+
foundry: ["AZURE_OPENAI_API_KEY", "CODEX_FOUNDRY_BASE_URL", "CODEX_FOUNDRY_MODEL", "REPLICAS_CODEX_AUTH_METHOD"]
|
|
2810
2821
|
};
|
|
2811
2822
|
|
|
2812
2823
|
// ../shared/src/routes/claude.ts
|
|
@@ -2817,6 +2828,12 @@ var CLAUDE_AUTH_ENV_KEYS = [
|
|
|
2817
2828
|
"AWS_SECRET_ACCESS_KEY",
|
|
2818
2829
|
"AWS_REGION",
|
|
2819
2830
|
"ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION",
|
|
2831
|
+
"CLAUDE_CODE_USE_FOUNDRY",
|
|
2832
|
+
"ANTHROPIC_FOUNDRY_API_KEY",
|
|
2833
|
+
"ANTHROPIC_FOUNDRY_RESOURCE",
|
|
2834
|
+
"ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
2835
|
+
"ANTHROPIC_DEFAULT_HAIKU_MODEL",
|
|
2836
|
+
"ANTHROPIC_DEFAULT_OPUS_MODEL",
|
|
2820
2837
|
"REPLICAS_CLAUDE_AUTH_METHOD"
|
|
2821
2838
|
];
|
|
2822
2839
|
function claudeAuthEnvFromResponse(response) {
|
|
@@ -2834,6 +2851,16 @@ function claudeAuthEnvFromResponse(response) {
|
|
|
2834
2851
|
...response.smallFastModelRegion ? { ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION: response.smallFastModelRegion } : {},
|
|
2835
2852
|
REPLICAS_CLAUDE_AUTH_METHOD: "bedrock"
|
|
2836
2853
|
};
|
|
2854
|
+
case "foundry":
|
|
2855
|
+
return {
|
|
2856
|
+
CLAUDE_CODE_USE_FOUNDRY: "1",
|
|
2857
|
+
ANTHROPIC_FOUNDRY_API_KEY: response.apiKey,
|
|
2858
|
+
ANTHROPIC_FOUNDRY_RESOURCE: response.resource,
|
|
2859
|
+
...response.sonnetModel ? { ANTHROPIC_DEFAULT_SONNET_MODEL: response.sonnetModel } : {},
|
|
2860
|
+
...response.haikuModel ? { ANTHROPIC_DEFAULT_HAIKU_MODEL: response.haikuModel } : {},
|
|
2861
|
+
...response.opusModel ? { ANTHROPIC_DEFAULT_OPUS_MODEL: response.opusModel } : {},
|
|
2862
|
+
REPLICAS_CLAUDE_AUTH_METHOD: "foundry"
|
|
2863
|
+
};
|
|
2837
2864
|
}
|
|
2838
2865
|
}
|
|
2839
2866
|
var CLAUDE_AUTH_ENV_KEYS_BY_METHOD = {
|
|
@@ -2847,6 +2874,15 @@ var CLAUDE_AUTH_ENV_KEYS_BY_METHOD = {
|
|
|
2847
2874
|
"AWS_REGION",
|
|
2848
2875
|
"ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION",
|
|
2849
2876
|
"REPLICAS_CLAUDE_AUTH_METHOD"
|
|
2877
|
+
],
|
|
2878
|
+
foundry: [
|
|
2879
|
+
"CLAUDE_CODE_USE_FOUNDRY",
|
|
2880
|
+
"ANTHROPIC_FOUNDRY_API_KEY",
|
|
2881
|
+
"ANTHROPIC_FOUNDRY_RESOURCE",
|
|
2882
|
+
"ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
2883
|
+
"ANTHROPIC_DEFAULT_HAIKU_MODEL",
|
|
2884
|
+
"ANTHROPIC_DEFAULT_OPUS_MODEL",
|
|
2885
|
+
"REPLICAS_CLAUDE_AUTH_METHOD"
|
|
2850
2886
|
]
|
|
2851
2887
|
};
|
|
2852
2888
|
|
|
@@ -3301,13 +3337,13 @@ function requireValidURL(value, name) {
|
|
|
3301
3337
|
}
|
|
3302
3338
|
}
|
|
3303
3339
|
function parseClaudeAuthMethod(value) {
|
|
3304
|
-
if (value === "oauth" || value === "api_key" || value === "bedrock") {
|
|
3340
|
+
if (value === "oauth" || value === "api_key" || value === "bedrock" || value === "foundry") {
|
|
3305
3341
|
return value;
|
|
3306
3342
|
}
|
|
3307
3343
|
return void 0;
|
|
3308
3344
|
}
|
|
3309
3345
|
function parseCodexAuthMethod(value) {
|
|
3310
|
-
if (value === "oauth" || value === "api_key") {
|
|
3346
|
+
if (value === "oauth" || value === "api_key" || value === "foundry") {
|
|
3311
3347
|
return value;
|
|
3312
3348
|
}
|
|
3313
3349
|
return void 0;
|
|
@@ -3709,7 +3745,7 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
|
3709
3745
|
}
|
|
3710
3746
|
getSkipReason() {
|
|
3711
3747
|
const method = ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD;
|
|
3712
|
-
if (method === "api_key" || method === "bedrock") {
|
|
3748
|
+
if (method === "api_key" || method === "bedrock" || method === "foundry") {
|
|
3713
3749
|
return `auth method is ${method}`;
|
|
3714
3750
|
}
|
|
3715
3751
|
return null;
|
|
@@ -3813,8 +3849,8 @@ var CodexTokenManager = class extends BaseRefreshManager {
|
|
|
3813
3849
|
super("CodexTokenManager");
|
|
3814
3850
|
}
|
|
3815
3851
|
getSkipReason() {
|
|
3816
|
-
if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "api_key") {
|
|
3817
|
-
return
|
|
3852
|
+
if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "api_key" || ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "foundry") {
|
|
3853
|
+
return `auth method is ${ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD}`;
|
|
3818
3854
|
}
|
|
3819
3855
|
if (!ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD && ENGINE_ENV.OPENAI_API_KEY) {
|
|
3820
3856
|
return "OPENAI_API_KEY is set";
|
|
@@ -3843,7 +3879,7 @@ var CodexTokenManager = class extends BaseRefreshManager {
|
|
|
3843
3879
|
try {
|
|
3844
3880
|
console.log("[CodexTokenManager] Fetching fresh credentials from monolith after auth failure...");
|
|
3845
3881
|
const failedMethod = ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD;
|
|
3846
|
-
await this.refreshWithRequest(failedMethod === "oauth" || failedMethod === "api_key" ? {
|
|
3882
|
+
await this.refreshWithRequest(failedMethod === "oauth" || failedMethod === "api_key" || failedMethod === "foundry" ? {
|
|
3847
3883
|
failedMethod,
|
|
3848
3884
|
failureReason
|
|
3849
3885
|
} : void 0);
|
|
@@ -4900,6 +4936,9 @@ function detectClaudeAuthMethod() {
|
|
|
4900
4936
|
if (existsSync3(CLAUDE_CREDENTIALS_PATH)) {
|
|
4901
4937
|
return "oauth";
|
|
4902
4938
|
}
|
|
4939
|
+
if (ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD === "foundry") {
|
|
4940
|
+
return "foundry";
|
|
4941
|
+
}
|
|
4903
4942
|
if (ENGINE_ENV.CLAUDE_CODE_USE_BEDROCK && ENGINE_ENV.AWS_ACCESS_KEY_ID && ENGINE_ENV.AWS_SECRET_ACCESS_KEY) {
|
|
4904
4943
|
return "bedrock";
|
|
4905
4944
|
}
|
|
@@ -4915,6 +4954,7 @@ function detectCodexAuthMethod() {
|
|
|
4915
4954
|
if (ENGINE_ENV.OPENAI_API_KEY) {
|
|
4916
4955
|
return "api_key";
|
|
4917
4956
|
}
|
|
4957
|
+
if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "foundry") return "foundry";
|
|
4918
4958
|
return "none";
|
|
4919
4959
|
}
|
|
4920
4960
|
function detectCursorAuthMethod() {
|
|
@@ -6689,13 +6729,13 @@ function buildCodexAgentEnv() {
|
|
|
6689
6729
|
}
|
|
6690
6730
|
function shouldStripAnthropicApiKey(isBedrock) {
|
|
6691
6731
|
const method = ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD;
|
|
6692
|
-
return method === "oauth" || method === "bedrock" || isBedrock;
|
|
6732
|
+
return method === "oauth" || method === "bedrock" || method === "foundry" || isBedrock;
|
|
6693
6733
|
}
|
|
6694
6734
|
function isClaudeBedrockEnv(env) {
|
|
6695
6735
|
return ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD === "bedrock" || env.REPLICAS_CLAUDE_AUTH_METHOD === "bedrock" || env.CLAUDE_CODE_USE_BEDROCK === "1";
|
|
6696
6736
|
}
|
|
6697
6737
|
function shouldStripOpenAIApiKey() {
|
|
6698
|
-
return ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "oauth";
|
|
6738
|
+
return ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "oauth" || ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "foundry";
|
|
6699
6739
|
}
|
|
6700
6740
|
|
|
6701
6741
|
// src/utils/agent-additional-directories.ts
|
|
@@ -7673,12 +7713,14 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
7673
7713
|
return "Anthropic API key authentication failed. The key may be invalid, revoked, out of credits, or missing access to the selected Claude model. Update the Anthropic API key in Settings \u2192 Agents and try again.";
|
|
7674
7714
|
case "bedrock":
|
|
7675
7715
|
return "AWS Bedrock authentication failed. Check the Bedrock credentials, region, IAM permissions, and Claude model access in Settings \u2192 Agents, then try again.";
|
|
7716
|
+
case "foundry":
|
|
7717
|
+
return "Microsoft Foundry authentication failed. Check the API key, resource, and Claude deployment names in Settings \u2192 Agents, then try again.";
|
|
7676
7718
|
default:
|
|
7677
7719
|
return "Claude authentication failed after multiple attempts. Check your Claude, Anthropic API key, or Bedrock credentials in Settings \u2192 Agents and try again.";
|
|
7678
7720
|
}
|
|
7679
7721
|
}
|
|
7680
7722
|
resolveClaudeAuthMethodForMessage() {
|
|
7681
|
-
if (ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD === "oauth" || ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD === "api_key" || ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD === "bedrock") {
|
|
7723
|
+
if (ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD === "oauth" || ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD === "api_key" || ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD === "bedrock" || ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD === "foundry") {
|
|
7682
7724
|
return ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD;
|
|
7683
7725
|
}
|
|
7684
7726
|
if (ENGINE_ENV.CLAUDE_CODE_USE_BEDROCK === "1" || ENGINE_ENV.AWS_ACCESS_KEY_ID || ENGINE_ENV.AWS_SECRET_ACCESS_KEY) return "bedrock";
|
|
@@ -8478,7 +8520,7 @@ var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
|
8478
8520
|
var MIN_CODEX_CLI_VERSION = "0.144.0";
|
|
8479
8521
|
var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
|
|
8480
8522
|
var codexCliVersionEnsured = null;
|
|
8481
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
8523
|
+
var ENGINE_PACKAGE_VERSION = "0.1.436";
|
|
8482
8524
|
var INITIALIZE_METHOD = "initialize";
|
|
8483
8525
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
8484
8526
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -8493,7 +8535,21 @@ var AppServerProcess = class {
|
|
|
8493
8535
|
shuttingDown = false;
|
|
8494
8536
|
constructor(options = {}) {
|
|
8495
8537
|
this.binary = options.binary ?? DEFAULT_CODEX_BINARY;
|
|
8496
|
-
this.args = options.args ??
|
|
8538
|
+
this.args = options.args ?? (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "foundry" ? [
|
|
8539
|
+
...DEFAULT_CODEX_ARGS,
|
|
8540
|
+
"-c",
|
|
8541
|
+
`model=${JSON.stringify(process.env.CODEX_FOUNDRY_MODEL)}`,
|
|
8542
|
+
"-c",
|
|
8543
|
+
'model_provider="azure"',
|
|
8544
|
+
"-c",
|
|
8545
|
+
'model_providers.azure.name="Azure OpenAI"',
|
|
8546
|
+
"-c",
|
|
8547
|
+
`model_providers.azure.base_url=${JSON.stringify(process.env.CODEX_FOUNDRY_BASE_URL)}`,
|
|
8548
|
+
"-c",
|
|
8549
|
+
'model_providers.azure.env_key="AZURE_OPENAI_API_KEY"',
|
|
8550
|
+
"-c",
|
|
8551
|
+
'model_providers.azure.wire_api="responses"'
|
|
8552
|
+
] : DEFAULT_CODEX_ARGS);
|
|
8497
8553
|
this.env = options.env ?? buildCodexAgentEnv();
|
|
8498
8554
|
this.cwd = options.cwd ?? ENGINE_ENV.WORKSPACE_ROOT;
|
|
8499
8555
|
}
|
|
@@ -9224,7 +9280,7 @@ async function buildTurnInput(request) {
|
|
|
9224
9280
|
})));
|
|
9225
9281
|
return { input, tempImagePaths };
|
|
9226
9282
|
}
|
|
9227
|
-
async function buildTurnStartParams(threadId, request,
|
|
9283
|
+
async function buildTurnStartParams(threadId, request, serviceTier) {
|
|
9228
9284
|
const effort = toReasoningEffort(request.thinkingLevel);
|
|
9229
9285
|
const model = request.model ?? DEFAULT_MODEL;
|
|
9230
9286
|
const { input, tempImagePaths } = await buildTurnInput(request);
|
|
@@ -9236,16 +9292,14 @@ async function buildTurnStartParams(threadId, request, developerInstructions, se
|
|
|
9236
9292
|
...serviceTier !== void 0 ? { serviceTier } : {},
|
|
9237
9293
|
...codexApprovalPolicyOverrides(),
|
|
9238
9294
|
...effort ? { effort } : {},
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
9245
|
-
developer_instructions: developerInstructions
|
|
9246
|
-
}
|
|
9295
|
+
collaborationMode: {
|
|
9296
|
+
mode: request.planMode ? "plan" : "default",
|
|
9297
|
+
settings: {
|
|
9298
|
+
model,
|
|
9299
|
+
reasoning_effort: effort ?? null,
|
|
9300
|
+
developer_instructions: null
|
|
9247
9301
|
}
|
|
9248
|
-
}
|
|
9302
|
+
}
|
|
9249
9303
|
},
|
|
9250
9304
|
tempImagePaths
|
|
9251
9305
|
};
|
|
@@ -9724,10 +9778,10 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
9724
9778
|
const threadId = await this.ensureThread(host, request, developerInstructions);
|
|
9725
9779
|
const serviceTier = await this.resolveRequestedServiceTier(host, request);
|
|
9726
9780
|
await this.applyThreadServiceTier(host, threadId, serviceTier);
|
|
9727
|
-
const runTurn = options.runTurn ?? ((aspHost, aspThreadId
|
|
9781
|
+
const runTurn = options.runTurn ?? ((aspHost, aspThreadId) => this.runTurn(aspHost, aspThreadId, request, serviceTier));
|
|
9728
9782
|
let completedTurn;
|
|
9729
9783
|
try {
|
|
9730
|
-
completedTurn = await runTurn(host, threadId
|
|
9784
|
+
completedTurn = await runTurn(host, threadId);
|
|
9731
9785
|
} catch (error) {
|
|
9732
9786
|
await this.refreshQuotaSnapshot(host);
|
|
9733
9787
|
if (this.quotaStatus.blocked) {
|
|
@@ -9822,8 +9876,8 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
9822
9876
|
console.warn("[CodexAspManager] Failed to apply skill registries:", error);
|
|
9823
9877
|
}
|
|
9824
9878
|
}
|
|
9825
|
-
async runTurn(host, threadId, request,
|
|
9826
|
-
const { params, tempImagePaths } = await buildTurnStartParams(threadId, request,
|
|
9879
|
+
async runTurn(host, threadId, request, serviceTier) {
|
|
9880
|
+
const { params, tempImagePaths } = await buildTurnStartParams(threadId, request, serviceTier);
|
|
9827
9881
|
return this.observeTurn(host, threadId, request, async () => {
|
|
9828
9882
|
const turnStartResponse = await host.client.request(
|
|
9829
9883
|
TURN_START_METHOD,
|
|
@@ -12290,14 +12344,22 @@ var keepAliveService = new KeepAliveService();
|
|
|
12290
12344
|
import { readdir as readdir6, readFile as readFile12, stat as stat3 } from "fs/promises";
|
|
12291
12345
|
import { homedir as homedir13 } from "os";
|
|
12292
12346
|
import { join as join19 } from "path";
|
|
12293
|
-
var
|
|
12294
|
-
join19(homedir13(), ".
|
|
12295
|
-
join19(homedir13(), ".
|
|
12347
|
+
var GLOBAL_CANVAS_DIRECTORIES = [
|
|
12348
|
+
join19(homedir13(), ".claude", "plans"),
|
|
12349
|
+
join19(process.env.XDG_DATA_HOME ?? join19(homedir13(), ".local", "share"), "opencode", "plans"),
|
|
12350
|
+
join19(homedir13(), ".replicas", "canvas")
|
|
12296
12351
|
];
|
|
12352
|
+
async function canvasDirectories() {
|
|
12353
|
+
const repositories = await gitService.listRepositories().catch(() => []);
|
|
12354
|
+
return [
|
|
12355
|
+
...GLOBAL_CANVAS_DIRECTORIES,
|
|
12356
|
+
...repositories.map((repository) => join19(repository.path, ".opencode", "plans"))
|
|
12357
|
+
];
|
|
12358
|
+
}
|
|
12297
12359
|
var CanvasService = class {
|
|
12298
12360
|
async listItems() {
|
|
12299
12361
|
const items = /* @__PURE__ */ new Map();
|
|
12300
|
-
for (const directory of
|
|
12362
|
+
for (const directory of await canvasDirectories()) {
|
|
12301
12363
|
let entries;
|
|
12302
12364
|
try {
|
|
12303
12365
|
entries = await readdir6(directory, { withFileTypes: true });
|
|
@@ -12325,7 +12387,7 @@ var CanvasService = class {
|
|
|
12325
12387
|
const safe = sanitizeCanvasFilename(filename);
|
|
12326
12388
|
if (!safe) return null;
|
|
12327
12389
|
const { kind, mimeType } = classifyCanvasFilename(safe);
|
|
12328
|
-
for (const directory of
|
|
12390
|
+
for (const directory of await canvasDirectories()) {
|
|
12329
12391
|
const filePath = join19(directory, safe);
|
|
12330
12392
|
let sizeBytes = 0;
|
|
12331
12393
|
let updatedAt = "";
|