@zvec/zvec-grep 0.1.4 → 0.1.6
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 +86 -162
- package/README_CN.md +80 -162
- package/dist/authorization/index.d.ts +7 -0
- package/dist/authorization/index.js +7 -0
- package/dist/authorization/index.js.map +1 -0
- package/dist/authorization/manager.d.ts +8 -0
- package/dist/authorization/manager.js +19 -0
- package/dist/authorization/manager.js.map +1 -0
- package/dist/authorization/operation.d.ts +7 -0
- package/dist/authorization/operation.js +50 -0
- package/dist/authorization/operation.js.map +1 -0
- package/dist/authorization/planner.d.ts +21 -0
- package/dist/authorization/planner.js +97 -0
- package/dist/authorization/planner.js.map +1 -0
- package/dist/authorization/prompt.d.ts +11 -0
- package/dist/authorization/prompt.js +62 -0
- package/dist/authorization/prompt.js.map +1 -0
- package/dist/authorization/store.d.ts +20 -0
- package/dist/authorization/store.js +251 -0
- package/dist/authorization/store.js.map +1 -0
- package/dist/authorization/target.d.ts +15 -0
- package/dist/authorization/target.js +49 -0
- package/dist/authorization/target.js.map +1 -0
- package/dist/authorization/types.d.ts +61 -0
- package/dist/authorization/types.js +2 -0
- package/dist/authorization/types.js.map +1 -0
- package/dist/cli/args.d.ts +3 -0
- package/dist/cli/args.js +749 -201
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth.d.ts +21 -0
- package/dist/cli/auth.js +212 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/commands.d.ts +3 -1
- package/dist/cli/commands.js +529 -180
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/errors.js +7 -6
- package/dist/cli/errors.js.map +1 -1
- package/dist/cli/format/context.d.ts +1 -0
- package/dist/cli/format/context.js +270 -70
- package/dist/cli/format/context.js.map +1 -1
- package/dist/cli/format/debug.js +14 -16
- package/dist/cli/format/debug.js.map +1 -1
- package/dist/cli/format/highlight.js.map +1 -1
- package/dist/cli/format/progress.d.ts +4 -0
- package/dist/cli/format/progress.js +222 -44
- package/dist/cli/format/progress.js.map +1 -1
- package/dist/cli/format/range.js.map +1 -1
- package/dist/cli/format/status.d.ts +77 -6
- package/dist/cli/format/status.js +343 -114
- package/dist/cli/format/status.js.map +1 -1
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.js +368 -84
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/index.js +4 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/install.d.ts +4 -0
- package/dist/cli/install.js +845 -0
- package/dist/cli/install.js.map +1 -0
- package/dist/cli/managed-rg.d.ts +10 -0
- package/dist/cli/managed-rg.js +329 -0
- package/dist/cli/managed-rg.js.map +1 -0
- package/dist/cli/types.d.ts +40 -13
- package/dist/cli/types.js.map +1 -1
- package/dist/cli/version.js +3 -1
- package/dist/cli/version.js.map +1 -1
- package/dist/client/daemon-client.d.ts +19 -0
- package/dist/client/daemon-client.js +180 -0
- package/dist/client/daemon-client.js.map +1 -0
- package/dist/client/mode-router.d.ts +9 -0
- package/dist/client/mode-router.js +28 -0
- package/dist/client/mode-router.js.map +1 -0
- package/dist/client/search-policy.d.ts +11 -0
- package/dist/client/search-policy.js +15 -0
- package/dist/client/search-policy.js.map +1 -0
- package/dist/daemon/backend.d.ts +76 -0
- package/dist/daemon/backend.js +1049 -0
- package/dist/daemon/backend.js.map +1 -0
- package/dist/daemon/change-set.d.ts +25 -0
- package/dist/daemon/change-set.js +101 -0
- package/dist/daemon/change-set.js.map +1 -0
- package/dist/daemon/config.d.ts +24 -0
- package/dist/daemon/config.js +88 -0
- package/dist/daemon/config.js.map +1 -0
- package/dist/daemon/errors.d.ts +5 -0
- package/dist/daemon/errors.js +11 -0
- package/dist/daemon/errors.js.map +1 -0
- package/dist/daemon/http-server.d.ts +30 -0
- package/dist/daemon/http-server.js +287 -0
- package/dist/daemon/http-server.js.map +1 -0
- package/dist/daemon/index-coordinator.d.ts +23 -0
- package/dist/daemon/index-coordinator.js +68 -0
- package/dist/daemon/index-coordinator.js.map +1 -0
- package/dist/daemon/job-scheduler.d.ts +70 -0
- package/dist/daemon/job-scheduler.js +366 -0
- package/dist/daemon/job-scheduler.js.map +1 -0
- package/dist/daemon/logger.d.ts +9 -0
- package/dist/daemon/logger.js +53 -0
- package/dist/daemon/logger.js.map +1 -0
- package/dist/daemon/model-pool.d.ts +45 -0
- package/dist/daemon/model-pool.js +187 -0
- package/dist/daemon/model-pool.js.map +1 -0
- package/dist/daemon/root-lease.d.ts +14 -0
- package/dist/daemon/root-lease.js +188 -0
- package/dist/daemon/root-lease.js.map +1 -0
- package/dist/daemon/root-runtime.d.ts +78 -0
- package/dist/daemon/root-runtime.js +333 -0
- package/dist/daemon/root-runtime.js.map +1 -0
- package/dist/daemon/runtime-manager.d.ts +45 -0
- package/dist/daemon/runtime-manager.js +243 -0
- package/dist/daemon/runtime-manager.js.map +1 -0
- package/dist/daemon/runtime.d.ts +12 -0
- package/dist/daemon/runtime.js +102 -0
- package/dist/daemon/runtime.js.map +1 -0
- package/dist/daemon/server-controller.d.ts +39 -0
- package/dist/daemon/server-controller.js +203 -0
- package/dist/daemon/server-controller.js.map +1 -0
- package/dist/daemon/watch-manager.d.ts +50 -0
- package/dist/daemon/watch-manager.js +293 -0
- package/dist/daemon/watch-manager.js.map +1 -0
- package/dist/daemon/workspace-read-session-cache.d.ts +31 -0
- package/dist/daemon/workspace-read-session-cache.js +115 -0
- package/dist/daemon/workspace-read-session-cache.js.map +1 -0
- package/dist/engine/config.d.ts +50 -0
- package/dist/engine/config.js +321 -0
- package/dist/engine/config.js.map +1 -0
- package/dist/engine/{errors/index.d.ts → errors.d.ts} +6 -1
- package/dist/engine/{errors/details.js → errors.js} +17 -4
- package/dist/engine/errors.js.map +1 -0
- package/dist/engine/extraction/code/adapter.d.ts +1 -1
- package/dist/engine/extraction/code/adapter.js.map +1 -1
- package/dist/engine/extraction/code/extractor.d.ts +5 -11
- package/dist/engine/extraction/code/extractor.js +184 -109
- package/dist/engine/extraction/code/extractor.js.map +1 -1
- package/dist/engine/extraction/code/families/c-family.js +13 -7
- package/dist/engine/extraction/code/families/c-family.js.map +1 -1
- package/dist/engine/extraction/code/families/js-ts.d.ts +1 -1
- package/dist/engine/extraction/code/families/js-ts.js +24 -18
- package/dist/engine/extraction/code/families/js-ts.js.map +1 -1
- package/dist/engine/extraction/code/families/metadata.d.ts +1 -1
- package/dist/engine/extraction/code/families/metadata.js +11 -8
- package/dist/engine/extraction/code/families/metadata.js.map +1 -1
- package/dist/engine/extraction/code/families/name-field.js +5 -5
- package/dist/engine/extraction/code/families/name-field.js.map +1 -1
- package/dist/engine/extraction/code/languages/c.js +1 -4
- package/dist/engine/extraction/code/languages/c.js.map +1 -1
- package/dist/engine/extraction/code/languages/cpp.js.map +1 -1
- package/dist/engine/extraction/code/languages/go.js +1 -3
- package/dist/engine/extraction/code/languages/go.js.map +1 -1
- package/dist/engine/extraction/code/languages/java.js.map +1 -1
- package/dist/engine/extraction/code/languages/javascript.js +1 -3
- package/dist/engine/extraction/code/languages/javascript.js.map +1 -1
- package/dist/engine/extraction/code/languages/python.js +5 -6
- package/dist/engine/extraction/code/languages/python.js.map +1 -1
- package/dist/engine/extraction/code/languages/rust.js +1 -5
- package/dist/engine/extraction/code/languages/rust.js.map +1 -1
- package/dist/engine/extraction/code/languages/typescript.js.map +1 -1
- package/dist/engine/extraction/code/tree-sitter/grammar.js.map +1 -0
- package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/nodes.js +2 -1
- package/dist/engine/extraction/code/tree-sitter/nodes.js.map +1 -0
- package/dist/engine/extraction/code/tree-sitter/parser.js.map +1 -0
- package/dist/engine/extraction/ids.js.map +1 -1
- package/dist/engine/extraction/image/extractor.d.ts +5 -0
- package/dist/engine/extraction/image/extractor.js +35 -0
- package/dist/engine/extraction/image/extractor.js.map +1 -0
- package/dist/engine/extraction/index.d.ts +3 -44
- package/dist/engine/extraction/index.js +1 -280
- package/dist/engine/extraction/index.js.map +1 -1
- package/dist/engine/extraction/markdown/extractor.d.ts +5 -11
- package/dist/engine/extraction/markdown/extractor.js +37 -16
- package/dist/engine/extraction/markdown/extractor.js.map +1 -1
- package/dist/engine/extraction/runtime.d.ts +4 -0
- package/dist/engine/extraction/runtime.js +26 -0
- package/dist/engine/extraction/runtime.js.map +1 -0
- package/dist/engine/extraction/source.d.ts +18 -0
- package/dist/engine/extraction/source.js +22 -0
- package/dist/engine/extraction/source.js.map +1 -0
- package/dist/engine/extraction/text/extractor.d.ts +7 -0
- package/dist/engine/extraction/text/extractor.js +168 -0
- package/dist/engine/extraction/text/extractor.js.map +1 -0
- package/dist/engine/extraction/types.d.ts +4 -0
- package/dist/engine/{models → extraction}/types.js.map +1 -1
- package/dist/engine/{files/file-type.d.ts → file-type.d.ts} +1 -1
- package/dist/engine/file-type.js.map +1 -0
- package/dist/engine/index-status.d.ts +9 -0
- package/dist/engine/index-status.js +38 -0
- package/dist/engine/index-status.js.map +1 -0
- package/dist/engine/manifest.d.ts +12 -0
- package/dist/engine/manifest.js +120 -0
- package/dist/engine/manifest.js.map +1 -0
- package/dist/engine/models/{providers/llama-cpp/embedding.d.ts → backends/llama-cpp.d.ts} +25 -20
- package/dist/engine/models/{providers/llama-cpp/embedding.js → backends/llama-cpp.js} +165 -113
- package/dist/engine/models/backends/llama-cpp.js.map +1 -0
- package/dist/engine/models/backends/model2vec.d.ts +57 -0
- package/dist/engine/models/backends/model2vec.js +332 -0
- package/dist/engine/models/backends/model2vec.js.map +1 -0
- package/dist/engine/models/backends/qwen.d.ts +44 -0
- package/dist/engine/models/{providers/qwen/embedding.js → backends/qwen.js} +168 -102
- package/dist/engine/models/backends/qwen.js.map +1 -0
- package/dist/engine/models/backends/transformers-js.d.ts +87 -0
- package/dist/engine/models/backends/transformers-js.js +316 -0
- package/dist/engine/models/backends/transformers-js.js.map +1 -0
- package/dist/engine/models/catalog.d.ts +188 -23
- package/dist/engine/models/catalog.js +172 -41
- package/dist/engine/models/catalog.js.map +1 -1
- package/dist/engine/models/download-progress.d.ts +15 -0
- package/dist/engine/models/download-progress.js +48 -0
- package/dist/engine/models/download-progress.js.map +1 -0
- package/dist/engine/models/embeddings.d.ts +58 -18
- package/dist/engine/models/embeddings.js +53 -29
- package/dist/engine/models/embeddings.js.map +1 -1
- package/dist/engine/models/factory.d.ts +2 -5
- package/dist/engine/models/factory.js +41 -56
- package/dist/engine/models/factory.js.map +1 -1
- package/dist/engine/models/index.d.ts +4 -6
- package/dist/engine/models/index.js +4 -4
- package/dist/engine/models/index.js.map +1 -1
- package/dist/engine/models/ranking.d.ts +7 -3
- package/dist/engine/models/resolution.d.ts +8 -0
- package/dist/engine/models/resolution.js +22 -0
- package/dist/engine/models/resolution.js.map +1 -0
- package/dist/engine/pipeline/indexing/index.d.ts +9 -7
- package/dist/engine/pipeline/indexing/index.js +399 -147
- package/dist/engine/pipeline/indexing/index.js.map +1 -1
- package/dist/engine/pipeline/indexing/root-paths.js +16 -19
- package/dist/engine/pipeline/indexing/root-paths.js.map +1 -1
- package/dist/engine/pipeline/indexing/scanner/index.d.ts +6 -1
- package/dist/engine/pipeline/indexing/scanner/index.js +318 -66
- package/dist/engine/pipeline/indexing/scanner/index.js.map +1 -1
- package/dist/engine/pipeline/search/index.d.ts +6 -6
- package/dist/engine/pipeline/search/index.js +76 -34
- package/dist/engine/pipeline/search/index.js.map +1 -1
- package/dist/engine/service/index.d.ts +3 -2
- package/dist/engine/service/index.js +1 -1
- package/dist/engine/service/index.js.map +1 -1
- package/dist/engine/service/lexical.d.ts +14 -15
- package/dist/engine/service/lexical.js +78 -119
- package/dist/engine/service/lexical.js.map +1 -1
- package/dist/engine/service/root.d.ts +13 -12
- package/dist/engine/service/root.js +35 -24
- package/dist/engine/service/root.js.map +1 -1
- package/dist/engine/service/structure-enrichment.js +29 -25
- package/dist/engine/service/structure-enrichment.js.map +1 -1
- package/dist/engine/service/types.d.ts +61 -35
- package/dist/engine/service/workspace-index.d.ts +24 -0
- package/dist/engine/service/workspace-index.js +151 -0
- package/dist/engine/service/workspace-index.js.map +1 -0
- package/dist/engine/service/zvec-grep.d.ts +12 -1
- package/dist/engine/service/zvec-grep.js +878 -544
- package/dist/engine/service/zvec-grep.js.map +1 -1
- package/dist/engine/storage/index.d.ts +8 -4
- package/dist/engine/storage/index.js +1 -1
- package/dist/engine/storage/index.js.map +1 -1
- package/dist/engine/storage/zvec.d.ts +10 -33
- package/dist/engine/storage/zvec.js +110 -49
- package/dist/engine/storage/zvec.js.map +1 -1
- package/dist/engine/types.d.ts +29 -23
- package/dist/engine/types.js +1 -1
- package/dist/engine/types.js.map +1 -1
- package/dist/engine/utils/daemon-lease.d.ts +17 -0
- package/dist/engine/utils/daemon-lease.js +175 -0
- package/dist/engine/utils/daemon-lease.js.map +1 -0
- package/dist/engine/utils/file-selection.d.ts +10 -0
- package/dist/engine/utils/file-selection.js +157 -0
- package/dist/engine/utils/file-selection.js.map +1 -0
- package/dist/engine/utils/glob.d.ts +3 -0
- package/dist/engine/utils/glob.js +116 -18
- package/dist/engine/utils/glob.js.map +1 -1
- package/dist/engine/utils/hash.js.map +1 -1
- package/dist/engine/utils/json.d.ts +6 -2
- package/dist/engine/utils/json.js +50 -12
- package/dist/engine/utils/json.js.map +1 -1
- package/dist/engine/utils/lock.js +7 -7
- package/dist/engine/utils/lock.js.map +1 -1
- package/dist/engine/utils/path.js +2 -2
- package/dist/engine/utils/path.js.map +1 -1
- package/dist/engine/utils/timing.js.map +1 -1
- package/dist/index-progress.d.ts +10 -0
- package/dist/index-progress.js +159 -0
- package/dist/index-progress.js.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/http-transport.d.ts +27 -0
- package/dist/mcp/http-transport.js +182 -0
- package/dist/mcp/http-transport.js.map +1 -0
- package/dist/mcp/input-normalization.d.ts +38 -0
- package/dist/mcp/input-normalization.js +95 -0
- package/dist/mcp/input-normalization.js.map +1 -0
- package/dist/mcp/progress-heartbeat.d.ts +17 -0
- package/dist/mcp/progress-heartbeat.js +46 -0
- package/dist/mcp/progress-heartbeat.js.map +1 -0
- package/dist/mcp/request-metadata.d.ts +2 -0
- package/dist/mcp/request-metadata.js +11 -0
- package/dist/mcp/request-metadata.js.map +1 -0
- package/dist/mcp/request-state.d.ts +40 -0
- package/dist/mcp/request-state.js +210 -0
- package/dist/mcp/request-state.js.map +1 -0
- package/dist/mcp/result-format.d.ts +13 -0
- package/dist/mcp/result-format.js +75 -0
- package/dist/mcp/result-format.js.map +1 -0
- package/dist/mcp/schemas.d.ts +430 -0
- package/dist/mcp/schemas.js +447 -0
- package/dist/mcp/schemas.js.map +1 -0
- package/dist/mcp/tools.d.ts +150 -0
- package/dist/mcp/tools.js +448 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/toolset.d.ts +5 -0
- package/dist/mcp/toolset.js +12 -0
- package/dist/mcp/toolset.js.map +1 -0
- package/dist/observability/trace-context.d.ts +11 -0
- package/dist/observability/trace-context.js +138 -0
- package/dist/observability/trace-context.js.map +1 -0
- package/docs/01-agents.md +111 -0
- package/docs/02-cli.md +229 -0
- package/docs/03-mcp.md +167 -0
- package/docs/04-pipeline.md +218 -0
- package/docs/05-architecture.md +86 -0
- package/docs/06-server.md +210 -0
- package/docs/07-embedding.md +179 -0
- package/docs/08-roadmap.md +85 -0
- package/docs/README.md +53 -0
- package/package.json +43 -7
- package/skills/zvec-grep/SKILL.md +43 -123
- package/skills/zvec-grep/agents/openai.yaml +2 -2
- package/skills/zvec-grep/references/cli-fallback.md +85 -0
- package/dist/engine/collection/index.d.ts +0 -55
- package/dist/engine/collection/index.js +0 -710
- package/dist/engine/collection/index.js.map +0 -1
- package/dist/engine/errors/details.d.ts +0 -6
- package/dist/engine/errors/details.js.map +0 -1
- package/dist/engine/errors/index.js +0 -16
- package/dist/engine/errors/index.js.map +0 -1
- package/dist/engine/extraction/tree-sitter/grammar.js.map +0 -1
- package/dist/engine/extraction/tree-sitter/nodes.js.map +0 -1
- package/dist/engine/extraction/tree-sitter/parser.js.map +0 -1
- package/dist/engine/files/file-type.js.map +0 -1
- package/dist/engine/models/providers/index.d.ts +0 -2
- package/dist/engine/models/providers/index.js +0 -3
- package/dist/engine/models/providers/index.js.map +0 -1
- package/dist/engine/models/providers/llama-cpp/embedding.js.map +0 -1
- package/dist/engine/models/providers/llama-cpp/index.d.ts +0 -1
- package/dist/engine/models/providers/llama-cpp/index.js +0 -2
- package/dist/engine/models/providers/llama-cpp/index.js.map +0 -1
- package/dist/engine/models/providers/qwen/embedding.d.ts +0 -42
- package/dist/engine/models/providers/qwen/embedding.js.map +0 -1
- package/dist/engine/models/providers/qwen/index.d.ts +0 -1
- package/dist/engine/models/providers/qwen/index.js +0 -2
- package/dist/engine/models/providers/qwen/index.js.map +0 -1
- package/dist/engine/models/types.d.ts +0 -30
- /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/grammar.d.ts +0 -0
- /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/grammar.js +0 -0
- /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/nodes.d.ts +0 -0
- /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/parser.d.ts +0 -0
- /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/parser.js +0 -0
- /package/dist/engine/{models → extraction}/types.js +0 -0
- /package/dist/engine/{files/file-type.js → file-type.js} +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import {
|
|
1
|
+
import { lstat, readFile } from "node:fs/promises";
|
|
2
|
+
import { workspaceIndexDetail, detail, EngineError, errorDetails, isEngineError, } from "../../errors.js";
|
|
3
3
|
import { sha256Bytes } from "../../utils/hash.js";
|
|
4
|
+
import { normalizePath } from "../../utils/path.js";
|
|
4
5
|
import { ConcurrentTiming, TimingCollector } from "../../utils/timing.js";
|
|
5
|
-
import {
|
|
6
|
-
import { scanRootPaths } from "./scanner/index.js";
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const DEFAULT_EMBEDDING_MAX_CONCURRENCY = 12;
|
|
6
|
+
import { extract, } from "../../extraction/index.js";
|
|
7
|
+
import { scanDirectoryPath, scanFilePath, scanRootPaths, } from "./scanner/index.js";
|
|
8
|
+
const APPROXIMATE_CHARS_PER_TOKEN = 2;
|
|
9
|
+
const CHUNK_OVERLAP_RATIO = 0.15;
|
|
10
10
|
const EMBEDDING_TRANSIENT_MAX_RETRIES = 3;
|
|
11
11
|
const EMBEDDING_RATE_LIMIT_MAX_RETRIES = 6;
|
|
12
12
|
const EMBEDDING_TRANSIENT_RETRY_BASE_DELAY_MS = 500;
|
|
@@ -15,33 +15,44 @@ const EMBEDDING_TRANSIENT_RETRY_MAX_DELAY_MS = 8000;
|
|
|
15
15
|
const EMBEDDING_RATE_LIMIT_RETRY_MAX_DELAY_MS = 30000;
|
|
16
16
|
const EMBEDDING_RETRY_JITTER_MS = 500;
|
|
17
17
|
const EMBEDDING_SUCCESS_STREAK_MIN = 4;
|
|
18
|
-
export async function
|
|
18
|
+
export async function indexWorkspace(ctx) {
|
|
19
19
|
try {
|
|
20
|
-
return await
|
|
20
|
+
return await indexWorkspaceUnchecked(ctx);
|
|
21
21
|
}
|
|
22
22
|
catch (error) {
|
|
23
|
-
throw toEngineError(error, "Indexing
|
|
24
|
-
code: "ZVEC_GREP.ENGINE.INDEXING.
|
|
25
|
-
context:
|
|
23
|
+
throw toEngineError(error, "Indexing workspace failed", {
|
|
24
|
+
code: "ZVEC_GREP.ENGINE.INDEXING.WORKSPACE_FAILED",
|
|
25
|
+
context: workspaceIndexContext(ctx.workspaceIndex),
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
export async function
|
|
29
|
+
export async function indexWorkspacePaths(ctx, changedPaths) {
|
|
30
30
|
try {
|
|
31
|
-
|
|
31
|
+
return await indexWorkspacePathsUnchecked(ctx, changedPaths);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw toEngineError(error, "Indexing changed paths failed", {
|
|
35
|
+
code: "ZVEC_GREP.ENGINE.INDEXING.WORKSPACE_FAILED",
|
|
36
|
+
context: workspaceIndexContext(ctx.workspaceIndex),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export async function getWorkspaceIndexStatus(workspaceIndex, storedFiles) {
|
|
41
|
+
try {
|
|
42
|
+
const scan = await scanRootPaths(workspaceIndex.id, workspaceIndex.rootPaths);
|
|
32
43
|
const diff = await computeDiffFromFiles(scan.files, storedFiles);
|
|
33
44
|
const pendingFiles = storedFiles.filter((file) => file.indexStatus?.indexedTime === null);
|
|
34
45
|
const failedFiles = pendingFiles.filter((file) => file.indexStatus?.error !== undefined);
|
|
35
|
-
const indexedFiles = storedFiles.filter((file) => file.indexStatus?.indexedTime !== undefined
|
|
36
|
-
|
|
46
|
+
const indexedFiles = storedFiles.filter((file) => file.indexStatus?.indexedTime !== undefined &&
|
|
47
|
+
file.indexStatus.indexedTime !== null);
|
|
37
48
|
const entitiesIndexed = indexedFiles.reduce((count, file) => count + (file.indexStatus?.entityCount ?? 0), 0);
|
|
49
|
+
const fragmentsTruncated = indexedFiles.reduce((count, file) => count + (file.indexStatus?.truncatedFragmentCount ?? 0), 0);
|
|
38
50
|
return {
|
|
39
|
-
collectionId: collection.id,
|
|
40
|
-
collectionName: collection.name,
|
|
41
51
|
filesScanned: scan.files.length,
|
|
42
52
|
filesStored: storedFiles.length,
|
|
43
53
|
filesIndexed: indexedFiles.length,
|
|
44
54
|
entitiesIndexed,
|
|
55
|
+
fragmentsTruncated,
|
|
45
56
|
filesPending: pendingFiles.length,
|
|
46
57
|
filesFailed: failedFiles.length,
|
|
47
58
|
filesAdded: diff.added.length,
|
|
@@ -56,36 +67,42 @@ export async function getCollectionIndexStatus(collection, storedFiles) {
|
|
|
56
67
|
};
|
|
57
68
|
}
|
|
58
69
|
catch (error) {
|
|
59
|
-
throw toEngineError(error, "Inspecting
|
|
70
|
+
throw toEngineError(error, "Inspecting workspace index status failed", {
|
|
60
71
|
code: "ZVEC_GREP.ENGINE.INDEXING.STATUS_FAILED",
|
|
61
|
-
context:
|
|
72
|
+
context: workspaceIndexContext(workspaceIndex),
|
|
62
73
|
});
|
|
63
74
|
}
|
|
64
75
|
}
|
|
65
|
-
async function
|
|
76
|
+
async function indexWorkspaceUnchecked(ctx) {
|
|
66
77
|
const start = Date.now();
|
|
67
78
|
const report = ctx.onProgress ?? (() => undefined);
|
|
68
79
|
const timings = new TimingCollector();
|
|
80
|
+
throwIfIndexCancelled(ctx);
|
|
69
81
|
const firstPass = await runIndexPass(ctx, report, "Scanning files...", timings);
|
|
70
82
|
const passes = [firstPass];
|
|
83
|
+
let progressBase;
|
|
71
84
|
if (firstPass.stats.filesFailed > 0) {
|
|
72
85
|
const failed = firstPass.stats.filesFailed;
|
|
86
|
+
progressBase = retryProgressBase(firstPass);
|
|
73
87
|
report({
|
|
74
88
|
phase: "scanning",
|
|
89
|
+
filesTotal: progressBase.filesTotal,
|
|
90
|
+
filesIndexed: progressBase.filesSucceeded,
|
|
75
91
|
detail: `Retrying ${failed} failed ${failed === 1 ? "file" : "files"}...`,
|
|
76
92
|
});
|
|
77
|
-
passes.push(await runIndexPass(ctx, report, "Scanning retry candidates...", timings));
|
|
93
|
+
passes.push(await runIndexPass(ctx, report, "Scanning retry candidates...", timings, progressBase));
|
|
78
94
|
}
|
|
79
95
|
const finalPass = passes[passes.length - 1];
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
throwIfIndexCancelled(ctx);
|
|
97
|
+
reportIndexFinalizing(ctx, report, finalPass, progressBase);
|
|
98
|
+
await timings.time("index_optimize", () => optimizeStorage(ctx));
|
|
82
99
|
const result = buildIndexResult(ctx, passes, Date.now() - start, timings);
|
|
83
100
|
if (result.filesFailed > 0) {
|
|
84
101
|
report({ phase: "done", detail: "Indexing completed with failed files" });
|
|
85
102
|
throw new EngineError(`Indexing completed with ${result.filesFailed} failed ${result.filesFailed === 1 ? "file" : "files"}`, {
|
|
86
103
|
code: "ZVEC_GREP.ENGINE.INDEXING.FILES_FAILED",
|
|
87
104
|
context: errorDetails([
|
|
88
|
-
|
|
105
|
+
workspaceIndexDetail(ctx.workspaceIndex.name),
|
|
89
106
|
detail("filesFailed", result.filesFailed),
|
|
90
107
|
detail("filesScanned", result.filesScanned),
|
|
91
108
|
detail("failedFiles", summarizeFailedFiles(finalPass.stats.failedFiles)),
|
|
@@ -99,18 +116,78 @@ async function indexCollectionUnchecked(ctx) {
|
|
|
99
116
|
report({ phase: "done", detail: "Indexing complete" });
|
|
100
117
|
return result;
|
|
101
118
|
}
|
|
102
|
-
async function
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
const
|
|
119
|
+
async function indexWorkspacePathsUnchecked(ctx, changedPaths) {
|
|
120
|
+
const start = Date.now();
|
|
121
|
+
const report = ctx.onProgress ?? (() => undefined);
|
|
122
|
+
const timings = new TimingCollector();
|
|
123
|
+
const normalizedPaths = [...new Set(changedPaths.map(normalizePath))];
|
|
124
|
+
throwIfIndexCancelled(ctx);
|
|
125
|
+
const firstPass = await runPathIndexPass(ctx, report, normalizedPaths, timings);
|
|
126
|
+
const passes = [firstPass];
|
|
127
|
+
let progressBase;
|
|
128
|
+
if (firstPass.stats.filesFailed > 0) {
|
|
129
|
+
progressBase = retryProgressBase(firstPass);
|
|
130
|
+
passes.push(await runPathIndexPass(ctx, report, normalizedPaths, timings, progressBase));
|
|
131
|
+
}
|
|
132
|
+
const finalPass = passes[passes.length - 1];
|
|
133
|
+
throwIfIndexCancelled(ctx);
|
|
134
|
+
reportIndexFinalizing(ctx, report, finalPass, progressBase);
|
|
135
|
+
await timings.time("index_optimize", () => optimizeStorage(ctx));
|
|
136
|
+
const result = buildIndexResult(ctx, passes, Date.now() - start, timings);
|
|
137
|
+
if (result.filesFailed > 0) {
|
|
138
|
+
throw new EngineError(`Indexing completed with ${result.filesFailed} failed files`, {
|
|
139
|
+
code: "ZVEC_GREP.ENGINE.INDEXING.FILES_FAILED",
|
|
140
|
+
context: workspaceIndexContext(ctx.workspaceIndex),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
report({ phase: "done", detail: "Indexing complete" });
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
async function runPathIndexPass(ctx, report, changedPaths, timings, progressBase) {
|
|
147
|
+
reportScanning(report, "Scanning changed paths...", progressBase);
|
|
148
|
+
const scanned = await timings.time("index_scan_paths", async () => {
|
|
149
|
+
const files = [];
|
|
150
|
+
for (const path of changedPaths) {
|
|
151
|
+
throwIfIndexCancelled(ctx);
|
|
152
|
+
const info = await lstat(path).catch(() => null);
|
|
153
|
+
const scan = info?.isDirectory()
|
|
154
|
+
? await scanDirectoryPath(ctx.workspaceIndex.id, ctx.workspaceIndex.rootPaths, path, { signal: ctx.signal })
|
|
155
|
+
: await scanFilePath(ctx.workspaceIndex.id, ctx.workspaceIndex.rootPaths, path, {
|
|
156
|
+
signal: ctx.signal,
|
|
157
|
+
});
|
|
158
|
+
files.push(...scan.files);
|
|
159
|
+
}
|
|
160
|
+
return [...new Map(files.map((file) => [file.id, file])).values()];
|
|
161
|
+
});
|
|
162
|
+
throwIfIndexCancelled(ctx);
|
|
163
|
+
const existing = [
|
|
164
|
+
...new Map(changedPaths
|
|
165
|
+
.flatMap((path) => ctx.storage.listFilesByPathPrefix(path))
|
|
166
|
+
.map((file) => [file.id, file])).values(),
|
|
167
|
+
];
|
|
168
|
+
return runDiffPass(ctx, report, scanned, existing, timings, progressBase);
|
|
169
|
+
}
|
|
170
|
+
async function runIndexPass(ctx, report, scanningDetail, timings, progressBase) {
|
|
171
|
+
reportScanning(report, scanningDetail, progressBase);
|
|
172
|
+
const scan = await timings.time("index_scan", () => scanRootPaths(ctx.workspaceIndex.id, ctx.workspaceIndex.rootPaths, {
|
|
173
|
+
signal: ctx.signal,
|
|
174
|
+
}));
|
|
175
|
+
throwIfIndexCancelled(ctx);
|
|
176
|
+
return runDiffPass(ctx, report, scan.files, ctx.storage.listFiles(), timings, progressBase);
|
|
177
|
+
}
|
|
178
|
+
async function runDiffPass(ctx, report, scannedFiles, existingFiles, timings, progressBase) {
|
|
179
|
+
const diff = await timings.time("index_diff", () => computeDiffFromFiles(scannedFiles, existingFiles));
|
|
180
|
+
throwIfIndexCancelled(ctx);
|
|
106
181
|
const pending = [...diff.added, ...diff.modified, ...diff.pending];
|
|
107
182
|
report({
|
|
108
183
|
phase: "scanning",
|
|
109
|
-
filesTotal:
|
|
184
|
+
filesTotal: progressBase?.filesTotal ?? scannedFiles.length,
|
|
185
|
+
filesIndexed: progressBase?.filesSucceeded ?? 0,
|
|
110
186
|
detail: `${diff.added.length} added, ${diff.modified.length} modified, ${diff.pending.length} pending, ${diff.deleted.length} deleted, ${diff.unchanged.length} unchanged`,
|
|
111
187
|
});
|
|
112
188
|
timings.timeSync("index_delete_stale", () => {
|
|
113
189
|
for (const file of diff.deleted) {
|
|
190
|
+
throwIfIndexCancelled(ctx);
|
|
114
191
|
try {
|
|
115
192
|
ctx.storage.deleteFile(file.id);
|
|
116
193
|
}
|
|
@@ -125,46 +202,78 @@ async function runIndexPass(ctx, report, scanningDetail, timings) {
|
|
|
125
202
|
const reportIndexing = (currentStats, detail, embedding) => {
|
|
126
203
|
report({
|
|
127
204
|
phase: "indexing",
|
|
128
|
-
filesTotal: pending.length,
|
|
129
|
-
filesIndexed:
|
|
205
|
+
filesTotal: progressBase?.filesTotal ?? pending.length,
|
|
206
|
+
filesIndexed: (progressBase?.filesSucceeded ?? 0) +
|
|
207
|
+
currentStats.filesIndexed +
|
|
208
|
+
currentStats.filesFailed,
|
|
130
209
|
filesFailed: currentStats.filesFailed,
|
|
131
210
|
detail,
|
|
132
211
|
embedding,
|
|
133
212
|
});
|
|
134
213
|
};
|
|
135
|
-
reportIndexing({
|
|
214
|
+
reportIndexing({
|
|
215
|
+
filesIndexed: 0,
|
|
216
|
+
filesFailed: 0,
|
|
217
|
+
failedFiles: [],
|
|
218
|
+
failedFileReasons: [],
|
|
219
|
+
entitiesCreated: 0,
|
|
220
|
+
});
|
|
136
221
|
const stats = await indexFiles(pending, ctx, reportIndexing, timings);
|
|
222
|
+
throwIfIndexCancelled(ctx);
|
|
137
223
|
return {
|
|
138
|
-
filesScanned:
|
|
224
|
+
filesScanned: scannedFiles.length,
|
|
139
225
|
diff,
|
|
140
226
|
stats,
|
|
141
227
|
};
|
|
142
228
|
}
|
|
143
|
-
function reportIndexFinalizing(ctx, report, pass) {
|
|
229
|
+
function reportIndexFinalizing(ctx, report, pass, progressBase) {
|
|
144
230
|
report({
|
|
145
231
|
phase: "indexing",
|
|
146
|
-
filesTotal:
|
|
147
|
-
|
|
232
|
+
filesTotal: progressBase?.filesTotal ??
|
|
233
|
+
pass.diff.added.length +
|
|
234
|
+
pass.diff.modified.length +
|
|
235
|
+
pass.diff.pending.length,
|
|
236
|
+
filesIndexed: (progressBase?.filesSucceeded ?? 0) +
|
|
237
|
+
pass.stats.filesIndexed +
|
|
238
|
+
pass.stats.filesFailed,
|
|
148
239
|
filesFailed: pass.stats.filesFailed,
|
|
149
240
|
detail: "finalizing index",
|
|
150
241
|
});
|
|
151
242
|
}
|
|
243
|
+
function retryProgressBase(pass) {
|
|
244
|
+
return {
|
|
245
|
+
filesSucceeded: pass.stats.filesIndexed,
|
|
246
|
+
filesTotal: pass.diff.added.length +
|
|
247
|
+
pass.diff.modified.length +
|
|
248
|
+
pass.diff.pending.length,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function reportScanning(report, detail, progressBase) {
|
|
252
|
+
report({
|
|
253
|
+
phase: "scanning",
|
|
254
|
+
...(progressBase
|
|
255
|
+
? {
|
|
256
|
+
filesTotal: progressBase.filesTotal,
|
|
257
|
+
filesIndexed: progressBase.filesSucceeded,
|
|
258
|
+
}
|
|
259
|
+
: {}),
|
|
260
|
+
detail,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
152
263
|
function buildIndexResult(ctx, passes, durationMs, timings) {
|
|
153
264
|
const firstPass = passes[0];
|
|
154
265
|
const retryPasses = passes.slice(1);
|
|
155
266
|
const finalPass = passes[passes.length - 1];
|
|
156
267
|
return {
|
|
157
|
-
collectionId: ctx.collection.id,
|
|
158
|
-
collectionName: ctx.collection.name,
|
|
159
268
|
filesScanned: finalPass.filesScanned,
|
|
160
|
-
filesAdded: firstPass.diff.added.length
|
|
161
|
-
|
|
162
|
-
filesModified: firstPass.diff.modified.length
|
|
163
|
-
|
|
164
|
-
filesPending: firstPass.diff.pending.length
|
|
165
|
-
|
|
166
|
-
filesDeleted: firstPass.diff.deleted.length
|
|
167
|
-
|
|
269
|
+
filesAdded: firstPass.diff.added.length +
|
|
270
|
+
retryPasses.reduce((count, pass) => count + pass.diff.added.length, 0),
|
|
271
|
+
filesModified: firstPass.diff.modified.length +
|
|
272
|
+
retryPasses.reduce((count, pass) => count + pass.diff.modified.length, 0),
|
|
273
|
+
filesPending: firstPass.diff.pending.length +
|
|
274
|
+
retryPasses.reduce((count, pass) => count + pass.diff.pending.length, 0),
|
|
275
|
+
filesDeleted: firstPass.diff.deleted.length +
|
|
276
|
+
retryPasses.reduce((count, pass) => count + pass.diff.deleted.length, 0),
|
|
168
277
|
filesUnchanged: firstPass.diff.unchanged.length,
|
|
169
278
|
filesFailed: finalPass.stats.filesFailed,
|
|
170
279
|
entitiesCreated: passes.reduce((count, pass) => count + pass.stats.entitiesCreated, 0),
|
|
@@ -172,20 +281,17 @@ function buildIndexResult(ctx, passes, durationMs, timings) {
|
|
|
172
281
|
timings: timings.entries(),
|
|
173
282
|
};
|
|
174
283
|
}
|
|
175
|
-
function optimizeStorage(ctx) {
|
|
284
|
+
async function optimizeStorage(ctx) {
|
|
176
285
|
try {
|
|
177
|
-
ctx.storage.optimize();
|
|
286
|
+
await ctx.storage.optimize();
|
|
178
287
|
}
|
|
179
288
|
catch (error) {
|
|
180
289
|
throw toEngineError(error, "Indexing failed to finalize storage", {
|
|
181
290
|
code: "ZVEC_GREP.ENGINE.INDEXING.OPTIMIZE_FAILED",
|
|
182
|
-
context:
|
|
291
|
+
context: workspaceIndexContext(ctx.workspaceIndex),
|
|
183
292
|
});
|
|
184
293
|
}
|
|
185
294
|
}
|
|
186
|
-
async function computeDiff(scannedFiles, storage) {
|
|
187
|
-
return computeDiffFromFiles(scannedFiles, storage.listFiles());
|
|
188
|
-
}
|
|
189
295
|
async function computeDiffFromFiles(scannedFiles, existingFiles) {
|
|
190
296
|
const existingById = new Map(existingFiles.map((file) => [file.id, file]));
|
|
191
297
|
const seen = new Set();
|
|
@@ -204,15 +310,15 @@ async function computeDiffFromFiles(scannedFiles, existingFiles) {
|
|
|
204
310
|
pending.push(await withContentHash(file));
|
|
205
311
|
continue;
|
|
206
312
|
}
|
|
207
|
-
if (existing.sizeBytes === file.sizeBytes
|
|
208
|
-
|
|
209
|
-
|
|
313
|
+
if (existing.sizeBytes === file.sizeBytes &&
|
|
314
|
+
existing.lastModifiedTime === file.lastModifiedTime &&
|
|
315
|
+
existing.contentHash) {
|
|
210
316
|
unchanged.push(existing);
|
|
211
317
|
continue;
|
|
212
318
|
}
|
|
213
319
|
const hashed = await withContentHash(file);
|
|
214
|
-
if (existing.sizeBytes === hashed.sizeBytes
|
|
215
|
-
|
|
320
|
+
if (existing.sizeBytes === hashed.sizeBytes &&
|
|
321
|
+
existing.contentHash === hashed.contentHash) {
|
|
216
322
|
unchanged.push(existing);
|
|
217
323
|
continue;
|
|
218
324
|
}
|
|
@@ -234,10 +340,12 @@ async function indexFiles(files, ctx, onProgress, timings) {
|
|
|
234
340
|
const embeddingScheduler = createEmbeddingScheduler(ctx.embeddingConcurrency, ctx.embeddingModel);
|
|
235
341
|
const embeddingTiming = new ConcurrentTiming(timings, "index_embedding");
|
|
236
342
|
const runningEmbeddings = new Set();
|
|
343
|
+
const chunkOptions = indexChunkOptions(ctx);
|
|
237
344
|
const reportEmbeddingProgress = (currentStats, detail) => {
|
|
238
345
|
onProgress(currentStats, detail, embeddingScheduler.snapshot());
|
|
239
346
|
};
|
|
240
347
|
const flushBatch = async () => {
|
|
348
|
+
throwIfIndexCancelled(ctx);
|
|
241
349
|
if (batchFiles.length === 0) {
|
|
242
350
|
return;
|
|
243
351
|
}
|
|
@@ -246,8 +354,8 @@ async function indexFiles(files, ctx, onProgress, timings) {
|
|
|
246
354
|
await scheduleEmbeddingTask(() => embedAndCommitBatch(filesToEmbed, ctx, stats, onProgress, embeddingScheduler, timings, embeddingTiming));
|
|
247
355
|
};
|
|
248
356
|
const scheduleEmbeddingTask = async (task) => {
|
|
249
|
-
|
|
250
|
-
|
|
357
|
+
throwIfIndexCancelled(ctx);
|
|
358
|
+
const promise = task().finally(() => {
|
|
251
359
|
runningEmbeddings.delete(promise);
|
|
252
360
|
});
|
|
253
361
|
runningEmbeddings.add(promise);
|
|
@@ -255,70 +363,109 @@ async function indexFiles(files, ctx, onProgress, timings) {
|
|
|
255
363
|
await Promise.race(runningEmbeddings);
|
|
256
364
|
}
|
|
257
365
|
};
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
await
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
366
|
+
try {
|
|
367
|
+
for (const file of files) {
|
|
368
|
+
throwIfIndexCancelled(ctx);
|
|
369
|
+
onProgress(stats, `reading ${file.relativePath}`);
|
|
370
|
+
const prepared = await timings.time("index_prepare", () => prepareFile(file, ctx, chunkOptions));
|
|
371
|
+
throwIfIndexCancelled(ctx);
|
|
372
|
+
if ("failedReason" in prepared) {
|
|
373
|
+
recordFileFailed(stats, file, prepared.failedReason);
|
|
374
|
+
onProgress(stats, `failed ${file.relativePath}`);
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
if (prepared.fragments.length === 0) {
|
|
378
|
+
const committed = commitFile(prepared, [], ctx, stats);
|
|
379
|
+
onProgress(stats, finishedFileDetail(committed, file.relativePath));
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
if (prepared.fragments.length > ctx.embeddingModel.info.limits.maxBatchSize) {
|
|
383
|
+
await flushBatch();
|
|
384
|
+
await scheduleEmbeddingTask(async () => {
|
|
385
|
+
throwIfIndexCancelled(ctx);
|
|
386
|
+
reportEmbeddingProgress(stats, `embedding ${file.relativePath}`);
|
|
387
|
+
await embedAndCommitFile(prepared, ctx, stats, onProgress, embeddingScheduler, timings, embeddingTiming);
|
|
388
|
+
});
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
if (batchFragmentCount > 0 &&
|
|
392
|
+
batchFragmentCount + prepared.fragments.length >
|
|
393
|
+
ctx.embeddingModel.info.limits.maxBatchSize) {
|
|
394
|
+
await flushBatch();
|
|
395
|
+
}
|
|
396
|
+
batchFiles.push(prepared);
|
|
397
|
+
batchFragmentCount += prepared.fragments.length;
|
|
398
|
+
if (batchFragmentCount === ctx.embeddingModel.info.limits.maxBatchSize) {
|
|
399
|
+
await flushBatch();
|
|
400
|
+
}
|
|
287
401
|
}
|
|
402
|
+
await flushBatch();
|
|
403
|
+
await Promise.all(runningEmbeddings);
|
|
288
404
|
}
|
|
289
|
-
|
|
290
|
-
|
|
405
|
+
catch (error) {
|
|
406
|
+
await Promise.allSettled(runningEmbeddings);
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
409
|
+
throwIfIndexCancelled(ctx);
|
|
291
410
|
return stats;
|
|
292
411
|
}
|
|
293
|
-
async function prepareFile(file, ctx) {
|
|
412
|
+
async function prepareFile(file, ctx, chunkOptions) {
|
|
294
413
|
try {
|
|
414
|
+
throwIfIndexCancelled(ctx);
|
|
295
415
|
const source = await readSource(file);
|
|
296
|
-
const extracted = await
|
|
297
|
-
|
|
416
|
+
const extracted = await extract(source, chunkOptions);
|
|
417
|
+
throwIfIndexCancelled(ctx);
|
|
418
|
+
const fragments = extracted.filter((fragment) => ctx.embeddingModel.info.inputKinds.includes(fragment.content.kind));
|
|
298
419
|
return { file, fragments };
|
|
299
420
|
}
|
|
300
421
|
catch (error) {
|
|
422
|
+
if (indexIsCancelled(ctx)) {
|
|
423
|
+
throw indexCancellationError(ctx);
|
|
424
|
+
}
|
|
301
425
|
return {
|
|
302
426
|
file,
|
|
303
427
|
failedReason: markFileFailed(ctx, file, error, "prepare"),
|
|
304
428
|
};
|
|
305
429
|
}
|
|
306
430
|
}
|
|
431
|
+
function indexChunkOptions(ctx) {
|
|
432
|
+
const maxInputTokens = ctx.embeddingModel.info.limits.maxInputTokens;
|
|
433
|
+
if (maxInputTokens === undefined) {
|
|
434
|
+
return {};
|
|
435
|
+
}
|
|
436
|
+
const maxChunkChars = Math.floor(maxInputTokens * APPROXIMATE_CHARS_PER_TOKEN);
|
|
437
|
+
const chunkOverlapChars = Math.floor(maxChunkChars * CHUNK_OVERLAP_RATIO);
|
|
438
|
+
return { maxChunkChars, chunkOverlapChars };
|
|
439
|
+
}
|
|
307
440
|
async function embedAndCommitBatch(files, ctx, stats, onProgress, embeddingScheduler, timings, embeddingTiming) {
|
|
308
441
|
const fragments = files.flatMap((file) => file.fragments);
|
|
309
442
|
try {
|
|
443
|
+
throwIfIndexCancelled(ctx);
|
|
310
444
|
const contents = fragments.map(vectorContentForFragment);
|
|
311
445
|
onProgress(stats, `embedding ${describePreparedFiles(files)}`, embeddingScheduler.snapshot());
|
|
312
|
-
const
|
|
446
|
+
const embedding = await embeddingTiming.time(() => embedContentsWithRetry(contents, ctx.embeddingModel, embeddingScheduler, ctx.signal, (progress) => reportModelDownloadProgress(stats, progress, onProgress, embeddingScheduler)));
|
|
447
|
+
const truncatedInputIndexes = new Set(embedding.truncated);
|
|
448
|
+
throwIfIndexCancelled(ctx);
|
|
313
449
|
let offset = 0;
|
|
314
450
|
for (const file of files) {
|
|
315
|
-
|
|
451
|
+
throwIfIndexCancelled(ctx);
|
|
452
|
+
const end = offset + file.fragments.length;
|
|
453
|
+
const fileVectors = embedding.vectors.slice(offset, end);
|
|
454
|
+
let truncatedFragmentCount = 0;
|
|
455
|
+
for (let index = offset; index < end; index++) {
|
|
456
|
+
if (truncatedInputIndexes.has(index)) {
|
|
457
|
+
truncatedFragmentCount++;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
316
460
|
offset += file.fragments.length;
|
|
317
|
-
const committed = timings.timeSync("index_commit", () => commitFile(file, fileVectors, ctx, stats));
|
|
461
|
+
const committed = timings.timeSync("index_commit", () => commitFile(file, fileVectors, ctx, stats, truncatedFragmentCount));
|
|
318
462
|
onProgress(stats, finishedFileDetail(committed, file.file.relativePath));
|
|
319
463
|
}
|
|
320
464
|
}
|
|
321
465
|
catch (error) {
|
|
466
|
+
if (indexIsCancelled(ctx)) {
|
|
467
|
+
throw indexCancellationError(ctx);
|
|
468
|
+
}
|
|
322
469
|
if (isRetryableEmbeddingError(error)) {
|
|
323
470
|
for (const file of files) {
|
|
324
471
|
const reason = markFileFailed(ctx, file.file, error, "embed");
|
|
@@ -335,29 +482,57 @@ async function embedAndCommitBatch(files, ctx, stats, onProgress, embeddingSched
|
|
|
335
482
|
}
|
|
336
483
|
async function embedAndCommitFile(file, ctx, stats, onProgress, embeddingScheduler, timings, embeddingTiming) {
|
|
337
484
|
try {
|
|
338
|
-
|
|
339
|
-
const
|
|
485
|
+
throwIfIndexCancelled(ctx);
|
|
486
|
+
const embedding = await embeddingTiming.time(() => embedFragments(file.fragments, ctx.embeddingModel, embeddingScheduler, ctx.signal, (progress) => reportModelDownloadProgress(stats, progress, onProgress, embeddingScheduler)));
|
|
487
|
+
throwIfIndexCancelled(ctx);
|
|
488
|
+
const committed = timings.timeSync("index_commit", () => commitFile(file, embedding.vectors, ctx, stats, embedding.truncated.length));
|
|
340
489
|
onProgress(stats, finishedFileDetail(committed, file.file.relativePath));
|
|
341
490
|
}
|
|
342
491
|
catch (error) {
|
|
492
|
+
if (indexIsCancelled(ctx)) {
|
|
493
|
+
throw indexCancellationError(ctx);
|
|
494
|
+
}
|
|
343
495
|
const reason = markFileFailed(ctx, file.file, error, "embed");
|
|
344
496
|
recordFileFailed(stats, file.file, reason);
|
|
345
497
|
onProgress(stats, finishedFileDetail(false, file.file.relativePath));
|
|
346
498
|
}
|
|
347
499
|
}
|
|
348
|
-
function commitFile(file, vectors, ctx, stats) {
|
|
500
|
+
function commitFile(file, vectors, ctx, stats, truncatedFragmentCount = 0) {
|
|
349
501
|
try {
|
|
350
|
-
ctx
|
|
502
|
+
throwIfIndexCancelled(ctx);
|
|
503
|
+
ctx.storage.upsertFile(file.file, file.fragments, vectors, {
|
|
504
|
+
truncatedFragmentCount,
|
|
505
|
+
});
|
|
351
506
|
stats.filesIndexed++;
|
|
352
507
|
stats.entitiesCreated += countPublicEntities(file.fragments);
|
|
353
508
|
return true;
|
|
354
509
|
}
|
|
355
510
|
catch (error) {
|
|
511
|
+
if (indexIsCancelled(ctx)) {
|
|
512
|
+
throw indexCancellationError(ctx);
|
|
513
|
+
}
|
|
356
514
|
const reason = markFileFailed(ctx, file.file, error, "commit");
|
|
357
515
|
recordFileFailed(stats, file.file, reason);
|
|
358
516
|
return false;
|
|
359
517
|
}
|
|
360
518
|
}
|
|
519
|
+
function throwIfIndexCancelled(ctx) {
|
|
520
|
+
if (!indexIsCancelled(ctx)) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
throw indexCancellationError(ctx);
|
|
524
|
+
}
|
|
525
|
+
function indexIsCancelled(ctx) {
|
|
526
|
+
return ctx.signal?.aborted === true;
|
|
527
|
+
}
|
|
528
|
+
function indexCancellationError(ctx) {
|
|
529
|
+
return ctx.signal?.reason instanceof Error
|
|
530
|
+
? ctx.signal.reason
|
|
531
|
+
: new EngineError("Indexing was cancelled.", {
|
|
532
|
+
code: "ZVEC_GREP.ENGINE.INDEXING.CANCELLED",
|
|
533
|
+
context: workspaceIndexContext(ctx.workspaceIndex),
|
|
534
|
+
});
|
|
535
|
+
}
|
|
361
536
|
function recordFileFailed(stats, file, reason) {
|
|
362
537
|
stats.filesFailed++;
|
|
363
538
|
stats.failedFiles.push(file.relativePath);
|
|
@@ -409,14 +584,15 @@ async function readSource(file) {
|
|
|
409
584
|
text: bytes.toString("utf8"),
|
|
410
585
|
};
|
|
411
586
|
}
|
|
412
|
-
async function embedFragments(fragments, model, embeddingScheduler) {
|
|
587
|
+
async function embedFragments(fragments, model, embeddingScheduler, signal, onModelProgress) {
|
|
413
588
|
const batches = [];
|
|
414
|
-
for (let start = 0; start < fragments.length; start += model.limits.maxBatchSize) {
|
|
415
|
-
const batch = fragments.slice(start, start + model.limits.maxBatchSize);
|
|
589
|
+
for (let start = 0; start < fragments.length; start += model.info.limits.maxBatchSize) {
|
|
590
|
+
const batch = fragments.slice(start, start + model.info.limits.maxBatchSize);
|
|
416
591
|
batches.push({ start, fragments: batch });
|
|
417
592
|
}
|
|
418
593
|
const vectors = new Array(fragments.length);
|
|
419
|
-
const
|
|
594
|
+
const truncatedInputIndexes = [];
|
|
595
|
+
const results = await Promise.allSettled(batches.map((batch) => embedFragmentBatch(batch.fragments, model, batch.start, embeddingScheduler, signal, onModelProgress)));
|
|
420
596
|
let firstError;
|
|
421
597
|
for (const [index, result] of results.entries()) {
|
|
422
598
|
if (result.status === "rejected") {
|
|
@@ -424,43 +600,54 @@ async function embedFragments(fragments, model, embeddingScheduler) {
|
|
|
424
600
|
continue;
|
|
425
601
|
}
|
|
426
602
|
const start = batches[index].start;
|
|
427
|
-
for (const [offset, vector] of result.value.entries()) {
|
|
603
|
+
for (const [offset, vector] of result.value.vectors.entries()) {
|
|
428
604
|
vectors[start + offset] = vector;
|
|
429
605
|
}
|
|
606
|
+
truncatedInputIndexes.push(...result.value.truncated.map((inputIndex) => start + inputIndex));
|
|
430
607
|
}
|
|
431
608
|
if (firstError) {
|
|
432
609
|
throw firstError;
|
|
433
610
|
}
|
|
434
|
-
return
|
|
611
|
+
return {
|
|
612
|
+
vectors,
|
|
613
|
+
truncated: truncatedInputIndexes,
|
|
614
|
+
};
|
|
435
615
|
}
|
|
436
|
-
async function embedFragmentBatch(fragments, model, startIndex, embeddingScheduler) {
|
|
616
|
+
async function embedFragmentBatch(fragments, model, startIndex, embeddingScheduler, signal, onModelProgress) {
|
|
437
617
|
const contents = fragments.map(vectorContentForFragment);
|
|
438
618
|
try {
|
|
439
|
-
return await embedContentsWithRetry(contents, model, embeddingScheduler);
|
|
619
|
+
return await embedContentsWithRetry(contents, model, embeddingScheduler, signal, onModelProgress);
|
|
440
620
|
}
|
|
441
621
|
catch (error) {
|
|
442
622
|
if (fragments.length === 1 || isRetryableEmbeddingError(error)) {
|
|
443
623
|
throw error;
|
|
444
624
|
}
|
|
445
|
-
return await embedFragmentBatchOneByOne(fragments, model, startIndex, embeddingScheduler);
|
|
625
|
+
return await embedFragmentBatchOneByOne(fragments, model, startIndex, embeddingScheduler, signal, onModelProgress);
|
|
446
626
|
}
|
|
447
627
|
}
|
|
448
|
-
async function embedFragmentBatchOneByOne(fragments, model, startIndex, embeddingScheduler) {
|
|
628
|
+
async function embedFragmentBatchOneByOne(fragments, model, startIndex, embeddingScheduler, signal, onModelProgress) {
|
|
449
629
|
const vectors = [];
|
|
630
|
+
const truncatedInputIndexes = [];
|
|
450
631
|
for (const [index, fragment] of fragments.entries()) {
|
|
451
632
|
try {
|
|
452
|
-
const
|
|
453
|
-
vectors.push(
|
|
633
|
+
const result = await embedContentsWithRetry([vectorContentForFragment(fragment)], model, embeddingScheduler, signal, onModelProgress);
|
|
634
|
+
vectors.push(result.vectors[0]);
|
|
635
|
+
if (result.truncated.length > 0) {
|
|
636
|
+
truncatedInputIndexes.push(index);
|
|
637
|
+
}
|
|
454
638
|
}
|
|
455
639
|
catch (error) {
|
|
456
640
|
throw new EngineError("Embedding entity fragment failed after one-by-one fallback", {
|
|
457
641
|
code: "ZVEC_GREP.ENGINE.INDEXING.EMBEDDING_FRAGMENT_FAILED",
|
|
458
|
-
context: `model=${model.
|
|
642
|
+
context: `model=${model.info.reference} fragmentId=${fragment.id} fragmentIndex=${startIndex + index}`,
|
|
459
643
|
cause: error,
|
|
460
644
|
});
|
|
461
645
|
}
|
|
462
646
|
}
|
|
463
|
-
return
|
|
647
|
+
return {
|
|
648
|
+
vectors,
|
|
649
|
+
truncated: truncatedInputIndexes,
|
|
650
|
+
};
|
|
464
651
|
}
|
|
465
652
|
function vectorContentForFragment(fragment) {
|
|
466
653
|
if (fragment.content.kind !== "text") {
|
|
@@ -486,13 +673,17 @@ function vectorMetadataText(metadata) {
|
|
|
486
673
|
: `symbol: ${metadata.symbolType}`,
|
|
487
674
|
metadata.scope ? `scope: ${metadata.scope}` : null,
|
|
488
675
|
metadata.signature ? `signature: ${oneLine(metadata.signature)}` : null,
|
|
489
|
-
metadata.modifiers.length > 0
|
|
676
|
+
metadata.modifiers.length > 0
|
|
677
|
+
? `modifiers: ${metadata.modifiers.join(" ")}`
|
|
678
|
+
: null,
|
|
490
679
|
metadata.doc ? `doc: ${oneLine(metadata.doc)}` : null,
|
|
491
680
|
]);
|
|
492
681
|
}
|
|
493
682
|
return compactMetadataLines([
|
|
494
683
|
metadata.heading ? `heading: ${metadata.heading}` : null,
|
|
495
|
-
typeof metadata.level === "number"
|
|
684
|
+
typeof metadata.level === "number"
|
|
685
|
+
? `heading_level: ${metadata.level}`
|
|
686
|
+
: null,
|
|
496
687
|
metadata.scope ? `scope: ${metadata.scope}` : null,
|
|
497
688
|
]);
|
|
498
689
|
}
|
|
@@ -501,13 +692,18 @@ function compactMetadataLines(lines) {
|
|
|
501
692
|
.filter((line) => line !== null && line.trim().length > 0)
|
|
502
693
|
.join("\n");
|
|
503
694
|
}
|
|
504
|
-
async function embedContentsWithRetry(contents, model, embeddingScheduler) {
|
|
695
|
+
async function embedContentsWithRetry(contents, model, embeddingScheduler, signal, onModelProgress) {
|
|
505
696
|
let attempt = 0;
|
|
506
697
|
while (true) {
|
|
507
698
|
let retry = nonRetryableEmbeddingError();
|
|
508
699
|
let delayMs = 0;
|
|
509
700
|
try {
|
|
510
|
-
|
|
701
|
+
throwIfAborted(signal);
|
|
702
|
+
const result = await embeddingScheduler.run(() => model.embed(contents, {
|
|
703
|
+
purpose: "document",
|
|
704
|
+
signal,
|
|
705
|
+
onProgress: onModelProgress,
|
|
706
|
+
}), signal, (error) => {
|
|
511
707
|
retry = classifyEmbeddingRetry(error);
|
|
512
708
|
delayMs = retryDelayMs(attempt, retry);
|
|
513
709
|
if (retry.retryable) {
|
|
@@ -518,9 +714,14 @@ async function embedContentsWithRetry(contents, model, embeddingScheduler) {
|
|
|
518
714
|
}
|
|
519
715
|
});
|
|
520
716
|
embeddingScheduler.recordSuccess();
|
|
521
|
-
return
|
|
717
|
+
return result;
|
|
522
718
|
}
|
|
523
719
|
catch (error) {
|
|
720
|
+
if (signal?.aborted) {
|
|
721
|
+
throw signal.reason instanceof Error
|
|
722
|
+
? signal.reason
|
|
723
|
+
: new Error("Embedding was cancelled.");
|
|
724
|
+
}
|
|
524
725
|
if (!retry.retryable) {
|
|
525
726
|
retry = classifyEmbeddingRetry(error);
|
|
526
727
|
delayMs = retryDelayMs(attempt, retry);
|
|
@@ -528,18 +729,24 @@ async function embedContentsWithRetry(contents, model, embeddingScheduler) {
|
|
|
528
729
|
if (attempt >= maxRetryAttempts(retry) || !retry.retryable) {
|
|
529
730
|
throw error;
|
|
530
731
|
}
|
|
531
|
-
await
|
|
732
|
+
await abortableDelay(delayMs, signal);
|
|
532
733
|
attempt++;
|
|
533
734
|
}
|
|
534
735
|
}
|
|
535
736
|
}
|
|
737
|
+
function reportModelDownloadProgress(stats, progress, onProgress, embeddingScheduler) {
|
|
738
|
+
onProgress(stats, `downloading ${progress.model}`, {
|
|
739
|
+
...embeddingScheduler.snapshot(),
|
|
740
|
+
...progress,
|
|
741
|
+
});
|
|
742
|
+
}
|
|
536
743
|
function createEmbeddingScheduler(requestedConcurrency, model) {
|
|
537
744
|
return new AdaptiveEmbeddingScheduler(resolveEmbeddingConcurrencyPolicy(requestedConcurrency, model));
|
|
538
745
|
}
|
|
539
746
|
function resolveEmbeddingConcurrencyPolicy(requestedConcurrency, model) {
|
|
540
|
-
if (requestedConcurrency !== undefined
|
|
541
|
-
|
|
542
|
-
|
|
747
|
+
if (requestedConcurrency !== undefined &&
|
|
748
|
+
Number.isInteger(requestedConcurrency) &&
|
|
749
|
+
requestedConcurrency > 0) {
|
|
543
750
|
return {
|
|
544
751
|
initial: requestedConcurrency,
|
|
545
752
|
min: 1,
|
|
@@ -547,10 +754,11 @@ function resolveEmbeddingConcurrencyPolicy(requestedConcurrency, model) {
|
|
|
547
754
|
adaptive: requestedConcurrency > 1,
|
|
548
755
|
};
|
|
549
756
|
}
|
|
550
|
-
const
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
const
|
|
757
|
+
const remote = model.info.provider === "qwen";
|
|
758
|
+
const multimodal = model.info.inputKinds.includes("image");
|
|
759
|
+
const initial = remote ? (multimodal ? 4 : 8) : 1;
|
|
760
|
+
const max = remote ? (multimodal ? 8 : 12) : 1;
|
|
761
|
+
const min = Math.min(initial, 4);
|
|
554
762
|
return {
|
|
555
763
|
initial,
|
|
556
764
|
min,
|
|
@@ -573,11 +781,13 @@ class AdaptiveEmbeddingScheduler {
|
|
|
573
781
|
get taskConcurrency() {
|
|
574
782
|
return this.policy.max;
|
|
575
783
|
}
|
|
576
|
-
async run(task, onError) {
|
|
577
|
-
|
|
578
|
-
await this.
|
|
784
|
+
async run(task, signal, onError) {
|
|
785
|
+
throwIfAborted(signal);
|
|
786
|
+
await this.waitForCooldown(signal);
|
|
787
|
+
await this.acquire(signal);
|
|
579
788
|
try {
|
|
580
|
-
await this.waitForCooldown();
|
|
789
|
+
await this.waitForCooldown(signal);
|
|
790
|
+
throwIfAborted(signal);
|
|
581
791
|
return await task();
|
|
582
792
|
}
|
|
583
793
|
catch (error) {
|
|
@@ -593,7 +803,8 @@ class AdaptiveEmbeddingScheduler {
|
|
|
593
803
|
return;
|
|
594
804
|
}
|
|
595
805
|
this.successStreak++;
|
|
596
|
-
if (this.successStreak <
|
|
806
|
+
if (this.successStreak <
|
|
807
|
+
Math.max(EMBEDDING_SUCCESS_STREAK_MIN, this.currentConcurrency * 2)) {
|
|
597
808
|
return;
|
|
598
809
|
}
|
|
599
810
|
this.currentConcurrency++;
|
|
@@ -618,19 +829,36 @@ class AdaptiveEmbeddingScheduler {
|
|
|
618
829
|
retryableFailures: this.retryableFailures,
|
|
619
830
|
};
|
|
620
831
|
}
|
|
621
|
-
async waitForCooldown() {
|
|
832
|
+
async waitForCooldown(signal) {
|
|
622
833
|
const remaining = this.cooldownUntil - Date.now();
|
|
623
834
|
if (remaining > 0) {
|
|
624
|
-
await
|
|
835
|
+
await abortableDelay(remaining, signal);
|
|
625
836
|
}
|
|
626
837
|
}
|
|
627
|
-
async acquire() {
|
|
838
|
+
async acquire(signal) {
|
|
839
|
+
throwIfAborted(signal);
|
|
628
840
|
if (this.active < this.currentConcurrency) {
|
|
629
841
|
this.active++;
|
|
630
842
|
return;
|
|
631
843
|
}
|
|
632
|
-
await new Promise((resolve) => {
|
|
633
|
-
|
|
844
|
+
await new Promise((resolve, reject) => {
|
|
845
|
+
const queued = () => {
|
|
846
|
+
signal?.removeEventListener("abort", abort);
|
|
847
|
+
resolve();
|
|
848
|
+
};
|
|
849
|
+
const abort = () => {
|
|
850
|
+
const index = this.queue.indexOf(queued);
|
|
851
|
+
if (index >= 0) {
|
|
852
|
+
this.queue.splice(index, 1);
|
|
853
|
+
}
|
|
854
|
+
reject(abortError(signal));
|
|
855
|
+
};
|
|
856
|
+
if (signal?.aborted) {
|
|
857
|
+
reject(abortError(signal));
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
861
|
+
this.queue.push(queued);
|
|
634
862
|
});
|
|
635
863
|
}
|
|
636
864
|
release() {
|
|
@@ -659,8 +887,8 @@ function classifyEmbeddingRetry(error) {
|
|
|
659
887
|
const context = isEngineError(error) && error.context ? ` ${error.context}` : "";
|
|
660
888
|
const text = `${message}${context}`;
|
|
661
889
|
const status = httpStatusFromText(text);
|
|
662
|
-
const rateLimited = status === 429
|
|
663
|
-
|
|
890
|
+
const rateLimited = status === 429 ||
|
|
891
|
+
/rate limit|quota exceeded|too many requests|request rate increased too quickly/i.test(text);
|
|
664
892
|
const serverError = typeof status === "number" && status >= 500 && status <= 599;
|
|
665
893
|
return {
|
|
666
894
|
retryable: rateLimited || serverError,
|
|
@@ -711,8 +939,32 @@ function retryAfterMsFromText(text) {
|
|
|
711
939
|
}
|
|
712
940
|
return undefined;
|
|
713
941
|
}
|
|
714
|
-
function
|
|
715
|
-
|
|
942
|
+
function abortableDelay(ms, signal) {
|
|
943
|
+
if (ms <= 0) {
|
|
944
|
+
return Promise.resolve();
|
|
945
|
+
}
|
|
946
|
+
throwIfAborted(signal);
|
|
947
|
+
return new Promise((resolve, reject) => {
|
|
948
|
+
const timer = setTimeout(() => {
|
|
949
|
+
signal?.removeEventListener("abort", abort);
|
|
950
|
+
resolve();
|
|
951
|
+
}, ms);
|
|
952
|
+
const abort = () => {
|
|
953
|
+
clearTimeout(timer);
|
|
954
|
+
reject(abortError(signal));
|
|
955
|
+
};
|
|
956
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
function throwIfAborted(signal) {
|
|
960
|
+
if (signal?.aborted) {
|
|
961
|
+
throw abortError(signal);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
function abortError(signal) {
|
|
965
|
+
return signal?.reason instanceof Error
|
|
966
|
+
? signal.reason
|
|
967
|
+
: new Error("Embedding was cancelled.");
|
|
716
968
|
}
|
|
717
969
|
function countPublicEntities(fragments) {
|
|
718
970
|
let count = 0;
|
|
@@ -764,11 +1016,11 @@ function toEngineError(error, message, options) {
|
|
|
764
1016
|
cause: error,
|
|
765
1017
|
});
|
|
766
1018
|
}
|
|
767
|
-
function
|
|
768
|
-
return errorDetails([
|
|
769
|
-
detail("
|
|
770
|
-
|
|
771
|
-
]) ?? "";
|
|
1019
|
+
function workspaceIndexContext(workspaceIndex) {
|
|
1020
|
+
return (errorDetails([
|
|
1021
|
+
detail("workspace_index_id", workspaceIndex.id),
|
|
1022
|
+
workspaceIndexDetail(workspaceIndex.name),
|
|
1023
|
+
]) ?? "");
|
|
772
1024
|
}
|
|
773
1025
|
function fileContext(file) {
|
|
774
1026
|
return `fileId=${file.id} path=${file.relativePath}`;
|