veryfront 0.1.1042 → 0.1.1043
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/shared/config.d.ts +2 -0
- package/esm/cli/shared/config.d.ts.map +1 -1
- package/esm/cli/shared/config.js +40 -2
- package/esm/deno.js +1 -1
- package/esm/src/platform/adapters/fs/veryfront/stat-operations.d.ts +1 -0
- package/esm/src/platform/adapters/fs/veryfront/stat-operations.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/veryfront/stat-operations.js +111 -99
- package/esm/src/skill/path-safety.d.ts.map +1 -1
- package/esm/src/skill/path-safety.js +19 -2
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +4 -4
|
@@ -18,11 +18,13 @@ export type VeryfrontConfig = InferSchema<ReturnType<typeof getVeryfrontConfigSc
|
|
|
18
18
|
export declare const getResolvedConfigSchema: () => import("../../src/internal-agents/schema.js").Schema<import("../../src/extensions/schema/schema-validator.js").InferShape<{
|
|
19
19
|
apiUrl: import("../../src/internal-agents/schema.js").Schema<string>;
|
|
20
20
|
apiToken: import("../../src/internal-agents/schema.js").Schema<string>;
|
|
21
|
+
apiTokenSource: import("../../src/internal-agents/schema.js").Schema<string | undefined>;
|
|
21
22
|
projectSlug: import("../../src/internal-agents/schema.js").Schema<string>;
|
|
22
23
|
}>>;
|
|
23
24
|
export declare const ResolvedConfigSchema: import("../../src/internal-agents/schema.js").Schema<import("../../src/extensions/schema/schema-validator.js").InferShape<{
|
|
24
25
|
apiUrl: import("../../src/internal-agents/schema.js").Schema<string>;
|
|
25
26
|
apiToken: import("../../src/internal-agents/schema.js").Schema<string>;
|
|
27
|
+
apiTokenSource: import("../../src/internal-agents/schema.js").Schema<string | undefined>;
|
|
26
28
|
projectSlug: import("../../src/internal-agents/schema.js").Schema<string>;
|
|
27
29
|
}>>;
|
|
28
30
|
export type ResolvedConfig = InferSchema<ReturnType<typeof getResolvedConfigSchema>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/cli/shared/config.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAGxE,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/cli/shared/config.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAGxE,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,2BAA2B,CAAC;AA8BzF,eAAO,MAAM,wBAAwB;;IAGjC,mDAAmD;;;;GAKtD,CAAC;AACF,eAAO,MAAM,qBAAqB;;IAN9B,mDAAmD;;;;GAMkB,CAAC;AAC1E,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC,CAAC;AAEvF,eAAO,MAAM,uBAAuB;;;;;GAOnC,CAAC;AACF,eAAO,MAAM,oBAAoB;;;;;GAAsC,CAAC;AACxE,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC,CAAC;AAGrF,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA2CxF;AAED,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAatF;AAmHD,eAAO,MAAM,aAAa,gBAJH,MAAM,QAAQ,iBAAiB,KAAG,OAAO,CAAC,cAAc,CAIvB,CAAC;AAEzD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,gBAZX,MAAM,QAAQ,iBAAiB,KAAG,OAAO,CAAC,cAAc,CAYhB,CAAC;AAUhE,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAClE,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAClD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACjD,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACrC;AAED,eAAO,MAAM,iBAAiB;;;;GAM7B,CAAC;AACF,eAAO,MAAM,cAAc;;;;GAAgC,CAAC;AAC5D,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC;AAEzE,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CAuHjE"}
|
package/esm/cli/shared/config.js
CHANGED
|
@@ -9,6 +9,7 @@ import { defineSchema, lazySchema } from "../../src/schemas/index.js";
|
|
|
9
9
|
import { join } from "../../src/platform/compat/path/index.js";
|
|
10
10
|
import { createFileSystem, cwd, getEnv } from "../../src/platform/index.js";
|
|
11
11
|
import { getEnvironmentConfig } from "../../src/config/index.js";
|
|
12
|
+
import { getEnvSource } from "../../src/utils/env-loader.js";
|
|
12
13
|
import { cliLogger, VERSION } from "../utils/index.js";
|
|
13
14
|
import { readToken } from "../auth/token-store.js";
|
|
14
15
|
import { ensureAuthenticated } from "../auth/login.js";
|
|
@@ -44,6 +45,7 @@ export const VeryfrontConfigSchema = lazySchema(getVeryfrontConfigSchema);
|
|
|
44
45
|
export const getResolvedConfigSchema = defineSchema((v) => v.object({
|
|
45
46
|
apiUrl: v.string(),
|
|
46
47
|
apiToken: v.string(),
|
|
48
|
+
apiTokenSource: v.enum(["env", "env-file", "config-file", "token-store"]).optional(),
|
|
47
49
|
projectSlug: v.string(),
|
|
48
50
|
}));
|
|
49
51
|
export const ResolvedConfigSchema = lazySchema(getResolvedConfigSchema);
|
|
@@ -130,16 +132,44 @@ function resolveTenantProjectReference() {
|
|
|
130
132
|
getEnv("TENANT_PROJECT_ID") ||
|
|
131
133
|
undefined;
|
|
132
134
|
}
|
|
135
|
+
async function resolveApiTokenForMode(env, configFile, interactive) {
|
|
136
|
+
const envToken = env.apiToken;
|
|
137
|
+
const envSource = envToken ? getEnvSource("VERYFRONT_API_TOKEN") : { source: "unset" };
|
|
138
|
+
const storedToken = await readToken(env);
|
|
139
|
+
if (envToken && envSource.source !== "env-file") {
|
|
140
|
+
return {
|
|
141
|
+
apiToken: envToken,
|
|
142
|
+
apiTokenSource: "env",
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (configFile?.apiToken) {
|
|
146
|
+
return { apiToken: configFile.apiToken, apiTokenSource: "config-file" };
|
|
147
|
+
}
|
|
148
|
+
if (interactive && envToken && envSource.source === "env-file" && storedToken) {
|
|
149
|
+
return { apiToken: storedToken, apiTokenSource: "token-store" };
|
|
150
|
+
}
|
|
151
|
+
if (envToken) {
|
|
152
|
+
return {
|
|
153
|
+
apiToken: envToken,
|
|
154
|
+
apiTokenSource: envSource.source === "env-file" ? "env-file" : "env",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (storedToken) {
|
|
158
|
+
return { apiToken: storedToken, apiTokenSource: "token-store" };
|
|
159
|
+
}
|
|
160
|
+
return { apiToken: null };
|
|
161
|
+
}
|
|
133
162
|
async function resolveConfigBase(projectDir, env, interactive) {
|
|
134
163
|
const dir = projectDir ?? cwd();
|
|
135
164
|
const configFile = await readConfigFile(dir);
|
|
136
165
|
const apiUrl = resolveCliApiUrl(env, configFile?.apiUrl);
|
|
137
|
-
let
|
|
166
|
+
let { apiToken, apiTokenSource } = await resolveApiTokenForMode(env, configFile, interactive);
|
|
138
167
|
if (!apiToken && interactive) {
|
|
139
168
|
const userInfo = await ensureAuthenticated(env);
|
|
140
169
|
if (!userInfo)
|
|
141
170
|
throw new Error("Authentication required for this operation.");
|
|
142
171
|
apiToken = (await readToken(env)) ?? null;
|
|
172
|
+
apiTokenSource = apiToken ? "token-store" : undefined;
|
|
143
173
|
if (!apiToken)
|
|
144
174
|
throw new Error("Authentication failed. Please try again.");
|
|
145
175
|
}
|
|
@@ -153,7 +183,7 @@ async function resolveConfigBase(projectDir, env, interactive) {
|
|
|
153
183
|
if (!projectSlug) {
|
|
154
184
|
throw new Error("Could not determine project reference. Set VERYFRONT_PROJECT_SLUG, TENANT_PROJECT_SLUG, VERYFRONT_PROJECT_ID, or add projectSlug to veryfront.config.ts");
|
|
155
185
|
}
|
|
156
|
-
return { apiUrl, apiToken, projectSlug };
|
|
186
|
+
return { apiUrl, apiToken, ...(apiTokenSource ? { apiTokenSource } : {}), projectSlug };
|
|
157
187
|
}
|
|
158
188
|
function createConfigResolver(interactive) {
|
|
159
189
|
return (projectDir, env) => resolveConfigByMode(projectDir, env, interactive);
|
|
@@ -177,6 +207,13 @@ export const getApiErrorSchema = defineSchema((v) => v.object({
|
|
|
177
207
|
export const ApiErrorSchema = lazySchema(getApiErrorSchema);
|
|
178
208
|
export function createApiClient(config) {
|
|
179
209
|
const { apiUrl, apiToken } = config;
|
|
210
|
+
function addTokenSourceHint(message, status) {
|
|
211
|
+
if (config.apiTokenSource !== "env-file")
|
|
212
|
+
return message;
|
|
213
|
+
if (status !== 401 && status !== 403 && status !== 404)
|
|
214
|
+
return message;
|
|
215
|
+
return `${message}. VERYFRONT_API_TOKEN was loaded from a project .env file. For management commands, run 'veryfront login' and remove or rename the project runtime token, or pass a management token explicitly in the shell.`;
|
|
216
|
+
}
|
|
180
217
|
async function requestOnce(method, url, body) {
|
|
181
218
|
const response = await fetch(url, {
|
|
182
219
|
method,
|
|
@@ -199,6 +236,7 @@ export function createApiClient(config) {
|
|
|
199
236
|
catch {
|
|
200
237
|
// Keep default error message if JSON parsing fails
|
|
201
238
|
}
|
|
239
|
+
errorMessage = addTokenSourceHint(errorMessage, response.status);
|
|
202
240
|
const err = new Error(errorMessage);
|
|
203
241
|
err.status = response.status;
|
|
204
242
|
throw err;
|
package/esm/deno.js
CHANGED
|
@@ -9,6 +9,7 @@ export declare class StatOperations extends VeryfrontOperationsBase {
|
|
|
9
9
|
private pathMapping;
|
|
10
10
|
private readonly apiSearchCircuitBreaker;
|
|
11
11
|
stat(path: string): Promise<FileInfo>;
|
|
12
|
+
private statWithoutSpan;
|
|
12
13
|
private ensureIndexBuilt;
|
|
13
14
|
private buildIndex;
|
|
14
15
|
clearIndex(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stat-operations.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/stat-operations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAElE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"stat-operations.d.ts","sourceRoot":"","sources":["../../../../../../src/src/platform/adapters/fs/veryfront/stat-operations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAElE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAiC/D,qBAAa,cAAe,SAAQ,uBAAuB;IACzD,OAAO,CAAC,SAAS,CAAyC;IAC1D,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,aAAa,CAA8B;IAEnD,OAAO,CAAC,sBAAsB,CAA6B;IAC3D,OAAO,CAAC,qBAAqB,CAA8B;IAE3D,OAAO,CAAC,WAAW,CAAkC;IAErD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAGrC;IAEH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;YAIvB,eAAe;YA4Gf,gBAAgB;YAwChB,UAAU;IAkDxB,UAAU,IAAI,IAAI;IAMlB,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM;YAIpC,cAAc;IAU5B,OAAO,CAAC,0BAA0B;IAgClC,OAAO,CAAC,qBAAqB;YAQf,sBAAsB;YA8EtB,iBAAiB;IAS/B,OAAO,CAAC,gBAAgB;IA6DlB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkBtC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CA0F1F"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { logger as baseLogger } from "../../../../utils/index.js";
|
|
2
2
|
import { isFrameworkSourcePath } from "../../../../utils/path-utils.js";
|
|
3
3
|
import { VeryfrontOperationsBase } from "./base-operations.js";
|
|
4
|
-
import { createError, toError } from "../../../../errors/index.js";
|
|
4
|
+
import { createError, toError, VeryfrontError } from "../../../../errors/index.js";
|
|
5
|
+
import { fromError } from "../../../../errors/veryfront-error.js";
|
|
5
6
|
import { buildStatCacheKeyPrefix } from "./cache-keys.js";
|
|
6
7
|
import { STAT_OPERATION_EXTENSION_PRIORITY as EXTENSION_PRIORITY } from "./extension-priority.js";
|
|
7
8
|
import { collectParentDirectories, normalizeIndexedFilePath, resolveByExtensionPriority, resolveIndexByExtensionPriority, sortPathsByExtensionPriority, stripKnownExtension, } from "./stat-operations-helpers.js";
|
|
@@ -12,6 +13,13 @@ const logger = baseLogger.component("stat-operations");
|
|
|
12
13
|
const NOT_FOUND_SENTINEL = "__NOT_FOUND__";
|
|
13
14
|
const API_SEARCH_CIRCUIT_BREAKER_THRESHOLD = 5;
|
|
14
15
|
const API_SEARCH_CIRCUIT_BREAKER_COOLDOWN_MS = 30_000;
|
|
16
|
+
function isFileNotFoundError(error) {
|
|
17
|
+
if (error instanceof VeryfrontError && error.slug === "file-not-found") {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
const veryfrontError = fromError(error);
|
|
21
|
+
return veryfrontError?.type === "file" && veryfrontError.message.startsWith("File not found:");
|
|
22
|
+
}
|
|
15
23
|
export class StatOperations extends VeryfrontOperationsBase {
|
|
16
24
|
fileIndex = null;
|
|
17
25
|
directoryIndex = null;
|
|
@@ -24,100 +32,101 @@ export class StatOperations extends VeryfrontOperationsBase {
|
|
|
24
32
|
cooldownMs: API_SEARCH_CIRCUIT_BREAKER_COOLDOWN_MS,
|
|
25
33
|
});
|
|
26
34
|
stat(path) {
|
|
27
|
-
return withSpan("fs.veryfront.stat",
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
35
|
+
return withSpan("fs.veryfront.stat", () => this.statWithoutSpan(path), { "fs.path": path });
|
|
36
|
+
}
|
|
37
|
+
async statWithoutSpan(path) {
|
|
38
|
+
const normalizedPath = this.normalizer.normalize(path);
|
|
39
|
+
const ctx = this.contextProvider?.getContentContext();
|
|
40
|
+
const cacheKey = `${buildStatCacheKeyPrefix(ctx)}:${normalizedPath}`;
|
|
41
|
+
logger.debug("stat called", { path, normalizedPath, cacheKey });
|
|
42
|
+
await this.ensureIndexBuilt();
|
|
43
|
+
const fileIdx = this.fileIndex;
|
|
44
|
+
const dirIdx = this.directoryIndex;
|
|
45
|
+
if (!fileIdx || !dirIdx) {
|
|
46
|
+
logger.debug("stat - no index available", { normalizedPath });
|
|
47
|
+
throw toError(createError({
|
|
48
|
+
type: "file",
|
|
49
|
+
message: `Index not available for: ${normalizedPath}`,
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
const file = fileIdx.get(normalizedPath);
|
|
53
|
+
if (file) {
|
|
54
|
+
logger.debug("stat found file", { normalizedPath });
|
|
55
|
+
return {
|
|
56
|
+
size: file.size,
|
|
57
|
+
mtime: new Date(file.updated_at),
|
|
58
|
+
isDirectory: false,
|
|
59
|
+
isFile: true,
|
|
60
|
+
isSymlink: false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (dirIdx.has(normalizedPath)) {
|
|
64
|
+
logger.debug("stat found directory", { normalizedPath });
|
|
65
|
+
return {
|
|
66
|
+
size: 0,
|
|
67
|
+
mtime: new Date(),
|
|
68
|
+
isDirectory: true,
|
|
69
|
+
isFile: false,
|
|
70
|
+
isSymlink: false,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// File not in index - try API pattern search as fallback for project files
|
|
74
|
+
// Skip for framework paths (node_modules, _veryfront, etc.)
|
|
75
|
+
if (!isFrameworkSourcePath(normalizedPath) && this.apiSearchCircuitBreaker.canSearch()) {
|
|
76
|
+
const hasKnownExt = EXTENSION_PRIORITY.some((ext) => normalizedPath.endsWith(ext));
|
|
77
|
+
if (hasKnownExt) {
|
|
78
|
+
logger.debug("stat file not in index, trying API search", {
|
|
79
|
+
normalizedPath,
|
|
80
|
+
indexSize: fileIdx.size,
|
|
81
|
+
});
|
|
82
|
+
try {
|
|
83
|
+
// Search for the exact file path
|
|
84
|
+
const matches = await this.client.searchFiles(normalizedPath);
|
|
85
|
+
this.apiSearchCircuitBreaker.recordSuccess();
|
|
86
|
+
const exactMatch = matches.find((m) => m.path === normalizedPath);
|
|
87
|
+
if (exactMatch) {
|
|
88
|
+
logger.debug("stat found via API search", { normalizedPath });
|
|
89
|
+
// Add to index for future lookups
|
|
90
|
+
fileIdx.set(normalizedPath, {
|
|
91
|
+
id: exactMatch.id,
|
|
92
|
+
version_id: undefined,
|
|
93
|
+
path: normalizedPath,
|
|
94
|
+
content: undefined,
|
|
95
|
+
type: "file",
|
|
96
|
+
size: 0,
|
|
97
|
+
updated_at: new Date().toISOString(),
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
size: 0,
|
|
101
|
+
mtime: new Date(),
|
|
102
|
+
isDirectory: false,
|
|
103
|
+
isFile: true,
|
|
104
|
+
isSymlink: false,
|
|
105
|
+
};
|
|
97
106
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
logger.debug("stat API search failed", {
|
|
106
|
-
normalizedPath,
|
|
107
|
-
error: error instanceof Error ? error.message : String(error),
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
const result = this.apiSearchCircuitBreaker.recordFailure();
|
|
110
|
+
if (result.tripped) {
|
|
111
|
+
logger.warn("stat API search circuit breaker tripped", {
|
|
112
|
+
failures: result.failures,
|
|
108
113
|
});
|
|
109
114
|
}
|
|
115
|
+
logger.debug("stat API search failed", {
|
|
116
|
+
normalizedPath,
|
|
117
|
+
error: error instanceof Error ? error.message : String(error),
|
|
118
|
+
});
|
|
110
119
|
}
|
|
111
120
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
+
}
|
|
122
|
+
logger.debug("stat file not found (not in index)", {
|
|
123
|
+
normalizedPath,
|
|
124
|
+
indexSize: fileIdx.size,
|
|
125
|
+
});
|
|
126
|
+
throw toError(createError({
|
|
127
|
+
type: "file",
|
|
128
|
+
message: `File not found: ${normalizedPath}`,
|
|
129
|
+
}));
|
|
121
130
|
}
|
|
122
131
|
async ensureIndexBuilt() {
|
|
123
132
|
if (this.fileIndex && this.directoryIndex) {
|
|
@@ -357,15 +366,18 @@ export class StatOperations extends VeryfrontOperationsBase {
|
|
|
357
366
|
return null;
|
|
358
367
|
}
|
|
359
368
|
async exists(path) {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
+
return withSpan("fs.veryfront.exists", async () => {
|
|
370
|
+
try {
|
|
371
|
+
await this.statWithoutSpan(path);
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
if (isFileNotFoundError(error)) {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
throw error;
|
|
379
|
+
}
|
|
380
|
+
}, { "fs.path": path });
|
|
369
381
|
}
|
|
370
382
|
async resolveFile(basePath, options) {
|
|
371
383
|
const resolveStart = performance.now();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-safety.d.ts","sourceRoot":"","sources":["../../../src/src/skill/path-safety.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"path-safety.d.ts","sourceRoot":"","sources":["../../../src/src/skill/path-safety.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AA2FtE;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EAAE,EACxB,SAAS,CAAC,EAAE,iBAAiB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAmEjB;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,iBAAiB,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CA2BnB"}
|
|
@@ -10,11 +10,19 @@ import * as dntShim from "../../_dnt.shims.js";
|
|
|
10
10
|
import { validatePath } from "../security/index.js";
|
|
11
11
|
import { isAbsolute, join, relative, resolve } from "../platform/compat/path/index.js";
|
|
12
12
|
import { exists, readDir, stat } from "../platform/compat/fs.js";
|
|
13
|
-
import {
|
|
13
|
+
import { VeryfrontError } from "../errors/index.js";
|
|
14
|
+
import { createError, fromError, toError } from "../errors/veryfront-error.js";
|
|
14
15
|
function isInsideDir(baseDir, targetPath) {
|
|
15
16
|
const rel = relative(baseDir, targetPath);
|
|
16
17
|
return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
17
18
|
}
|
|
19
|
+
function isFileNotFoundError(error) {
|
|
20
|
+
if (error instanceof VeryfrontError && error.slug === "file-not-found") {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
const veryfrontError = fromError(error);
|
|
24
|
+
return veryfrontError?.type === "file" && veryfrontError.message.startsWith("File not found:");
|
|
25
|
+
}
|
|
18
26
|
async function pathExists(path, fsAdapter) {
|
|
19
27
|
return fsAdapter ? await fsAdapter.exists(path) : await exists(path);
|
|
20
28
|
}
|
|
@@ -148,7 +156,16 @@ export async function validateSkillPath(skillRoot, requestedPath, allowedSubdirs
|
|
|
148
156
|
*/
|
|
149
157
|
export async function listSkillSubdir(skillRoot, subdir, fsAdapter) {
|
|
150
158
|
const dirPath = join(skillRoot, subdir);
|
|
151
|
-
|
|
159
|
+
let dirExists;
|
|
160
|
+
try {
|
|
161
|
+
dirExists = fsAdapter ? await fsAdapter.exists(dirPath) : await exists(dirPath);
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
if (isFileNotFoundError(error)) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
152
169
|
if (!dirExists) {
|
|
153
170
|
return [];
|
|
154
171
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "veryfront",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1043",
|
|
4
4
|
"description": "The simplest way to build AI-powered apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -330,9 +330,9 @@
|
|
|
330
330
|
"@types/react": "19.2.14",
|
|
331
331
|
"@types/react-dom": "19.2.3",
|
|
332
332
|
"ws": "8.21.0",
|
|
333
|
-
"@veryfront/ext-bundler-esbuild": "0.1.
|
|
334
|
-
"@veryfront/ext-content-mdx": "0.1.
|
|
335
|
-
"@veryfront/ext-css-tailwind": "0.1.
|
|
333
|
+
"@veryfront/ext-bundler-esbuild": "0.1.1043",
|
|
334
|
+
"@veryfront/ext-content-mdx": "0.1.1043",
|
|
335
|
+
"@veryfront/ext-css-tailwind": "0.1.1043"
|
|
336
336
|
},
|
|
337
337
|
"devDependencies": {
|
|
338
338
|
"@types/node": "20.9.0"
|