opencode-codebase-index 0.6.0 → 0.6.1

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/dist/index.cjs CHANGED
@@ -763,6 +763,27 @@ var DEFAULT_PROVIDER_MODELS = {
763
763
  "ollama": "nomic-embed-text"
764
764
  };
765
765
 
766
+ // src/config/env-substitution.ts
767
+ var ENV_REFERENCE_PATTERN = /^\{env:([A-Z_][A-Z0-9_]*)\}$/;
768
+ var ENV_REFERENCE_LIKE_PATTERN = /\{env:[^}]+\}/;
769
+ function substituteEnvString(value, keyPath) {
770
+ const match = value.match(ENV_REFERENCE_PATTERN);
771
+ if (!match) {
772
+ if (ENV_REFERENCE_LIKE_PATTERN.test(value)) {
773
+ throw new Error(
774
+ `Invalid environment variable reference at '${keyPath}'. Expected the entire string to match '{env:VAR_NAME}' with VAR_NAME matching [A-Z_][A-Z0-9_]*.`
775
+ );
776
+ }
777
+ return value;
778
+ }
779
+ const variableName = match[1];
780
+ const envValue = process.env[variableName];
781
+ if (envValue === void 0) {
782
+ throw new Error(`Missing environment variable '${variableName}' referenced by config at '${keyPath}'.`);
783
+ }
784
+ return envValue;
785
+ }
786
+
766
787
  // src/config/schema.ts
767
788
  function getDefaultIndexingConfig() {
768
789
  return {
@@ -820,11 +841,27 @@ function isValidScope(value) {
820
841
  function isStringArray(value) {
821
842
  return Array.isArray(value) && value.every((item) => typeof item === "string");
822
843
  }
844
+ function getResolvedString(value, keyPath) {
845
+ if (typeof value !== "string") {
846
+ return void 0;
847
+ }
848
+ return substituteEnvString(value, keyPath);
849
+ }
850
+ function getResolvedStringArray(value, keyPath) {
851
+ if (!isStringArray(value)) {
852
+ return void 0;
853
+ }
854
+ return value.map((item, index) => substituteEnvString(item, `${keyPath}[${index}]`));
855
+ }
823
856
  function isValidLogLevel(value) {
824
857
  return typeof value === "string" && VALID_LOG_LEVELS.includes(value);
825
858
  }
826
859
  function parseConfig(raw) {
827
860
  const input = raw && typeof raw === "object" ? raw : {};
861
+ const embeddingProviderValue = getResolvedString(input.embeddingProvider, "$root.embeddingProvider");
862
+ const scopeValue = getResolvedString(input.scope, "$root.scope");
863
+ const includeValue = getResolvedStringArray(input.include, "$root.include");
864
+ const excludeValue = getResolvedStringArray(input.exclude, "$root.exclude");
828
865
  const defaultIndexing = getDefaultIndexingConfig();
829
866
  const defaultSearch = getDefaultSearchConfig();
830
867
  const defaultDebug = getDefaultDebugConfig();
@@ -867,19 +904,23 @@ function parseConfig(raw) {
867
904
  let embeddingProvider;
868
905
  let embeddingModel = void 0;
869
906
  let customProvider = void 0;
870
- if (input.embeddingProvider === "custom") {
907
+ if (embeddingProviderValue === "custom") {
871
908
  embeddingProvider = "custom";
872
909
  const rawCustom = input.customProvider && typeof input.customProvider === "object" ? input.customProvider : null;
873
- if (rawCustom && typeof rawCustom.baseUrl === "string" && rawCustom.baseUrl.trim().length > 0 && typeof rawCustom.model === "string" && rawCustom.model.trim().length > 0 && typeof rawCustom.dimensions === "number" && Number.isInteger(rawCustom.dimensions) && rawCustom.dimensions > 0) {
910
+ const baseUrlValue = getResolvedString(rawCustom?.baseUrl, "$root.customProvider.baseUrl");
911
+ const modelValue = getResolvedString(rawCustom?.model, "$root.customProvider.model");
912
+ const apiKeyValue = getResolvedString(rawCustom?.apiKey, "$root.customProvider.apiKey");
913
+ if (rawCustom && typeof baseUrlValue === "string" && baseUrlValue.trim().length > 0 && typeof modelValue === "string" && modelValue.trim().length > 0 && typeof rawCustom.dimensions === "number" && Number.isInteger(rawCustom.dimensions) && rawCustom.dimensions > 0) {
874
914
  customProvider = {
875
- baseUrl: rawCustom.baseUrl.trim().replace(/\/+$/, ""),
876
- model: rawCustom.model,
915
+ baseUrl: baseUrlValue.trim().replace(/\/+$/, ""),
916
+ model: modelValue,
877
917
  dimensions: rawCustom.dimensions,
878
- apiKey: typeof rawCustom.apiKey === "string" ? rawCustom.apiKey : void 0,
918
+ apiKey: apiKeyValue,
879
919
  maxTokens: typeof rawCustom.maxTokens === "number" ? rawCustom.maxTokens : void 0,
880
920
  timeoutMs: typeof rawCustom.timeoutMs === "number" ? Math.max(1e3, rawCustom.timeoutMs) : void 0,
881
921
  concurrency: typeof rawCustom.concurrency === "number" ? Math.max(1, Math.floor(rawCustom.concurrency)) : void 0,
882
- requestIntervalMs: typeof rawCustom.requestIntervalMs === "number" ? Math.max(0, Math.floor(rawCustom.requestIntervalMs)) : void 0
922
+ requestIntervalMs: typeof rawCustom.requestIntervalMs === "number" ? Math.max(0, Math.floor(rawCustom.requestIntervalMs)) : void 0,
923
+ maxBatchSize: typeof rawCustom.maxBatchSize === "number" ? Math.max(1, Math.floor(rawCustom.maxBatchSize)) : typeof rawCustom.max_batch_size === "number" ? Math.max(1, Math.floor(rawCustom.max_batch_size)) : void 0
883
924
  };
884
925
  if (!/\/v\d+\/?$/.test(customProvider.baseUrl)) {
885
926
  console.warn(
@@ -891,10 +932,16 @@ function parseConfig(raw) {
891
932
  "embeddingProvider is 'custom' but customProvider config is missing or invalid. Required fields: baseUrl (string), model (string), dimensions (positive integer)."
892
933
  );
893
934
  }
894
- } else if (isValidProvider(input.embeddingProvider)) {
895
- embeddingProvider = input.embeddingProvider;
896
- if (input.embeddingModel) {
897
- embeddingModel = isValidModel(input.embeddingModel, embeddingProvider) ? input.embeddingModel : DEFAULT_PROVIDER_MODELS[embeddingProvider];
935
+ } else if (isValidProvider(embeddingProviderValue)) {
936
+ embeddingProvider = embeddingProviderValue;
937
+ const rawEmbeddingModel = input.embeddingModel;
938
+ if (typeof rawEmbeddingModel === "string") {
939
+ const embeddingModelValue = substituteEnvString(rawEmbeddingModel, "$root.embeddingModel");
940
+ if (embeddingModelValue) {
941
+ embeddingModel = isValidModel(embeddingModelValue, embeddingProvider) ? embeddingModelValue : DEFAULT_PROVIDER_MODELS[embeddingProvider];
942
+ }
943
+ } else if (rawEmbeddingModel) {
944
+ embeddingModel = DEFAULT_PROVIDER_MODELS[embeddingProvider];
898
945
  }
899
946
  } else {
900
947
  embeddingProvider = "auto";
@@ -903,9 +950,9 @@ function parseConfig(raw) {
903
950
  embeddingProvider,
904
951
  embeddingModel,
905
952
  customProvider,
906
- scope: isValidScope(input.scope) ? input.scope : "project",
907
- include: isStringArray(input.include) ? input.include : DEFAULT_INCLUDE,
908
- exclude: isStringArray(input.exclude) ? input.exclude : DEFAULT_EXCLUDE,
953
+ scope: isValidScope(scopeValue) ? scopeValue : "project",
954
+ include: includeValue ?? DEFAULT_INCLUDE,
955
+ exclude: excludeValue ?? DEFAULT_EXCLUDE,
909
956
  indexing,
910
957
  search,
911
958
  debug
@@ -2089,7 +2136,8 @@ function createCustomProviderInfo(config) {
2089
2136
  dimensions: config.dimensions,
2090
2137
  maxTokens: config.maxTokens ?? 8192,
2091
2138
  costPer1MTokens: 0,
2092
- timeoutMs: config.timeoutMs ?? 3e4
2139
+ timeoutMs: config.timeoutMs ?? 3e4,
2140
+ maxBatchSize: config.maxBatchSize
2093
2141
  }
2094
2142
  };
2095
2143
  }
@@ -2352,21 +2400,24 @@ var CustomEmbeddingProvider = class {
2352
2400
  this.credentials = credentials;
2353
2401
  this.modelInfo = modelInfo;
2354
2402
  }
2355
- async embedQuery(query) {
2356
- const result = await this.embedBatch([query]);
2357
- return {
2358
- embedding: result.embeddings[0],
2359
- tokensUsed: result.totalTokensUsed
2360
- };
2361
- }
2362
- async embedDocument(document) {
2363
- const result = await this.embedBatch([document]);
2364
- return {
2365
- embedding: result.embeddings[0],
2366
- tokensUsed: result.totalTokensUsed
2367
- };
2403
+ splitIntoRequestBatches(texts) {
2404
+ const maxBatchSize = this.modelInfo.maxBatchSize;
2405
+ if (!maxBatchSize || texts.length <= maxBatchSize) {
2406
+ return [texts];
2407
+ }
2408
+ const batches = [];
2409
+ for (let i = 0; i < texts.length; i += maxBatchSize) {
2410
+ batches.push(texts.slice(i, i + maxBatchSize));
2411
+ }
2412
+ return batches;
2368
2413
  }
2369
- async embedBatch(texts) {
2414
+ async embedRequest(texts) {
2415
+ if (texts.length === 0) {
2416
+ return {
2417
+ embeddings: [],
2418
+ totalTokensUsed: 0
2419
+ };
2420
+ }
2370
2421
  const headers = {
2371
2422
  "Content-Type": "application/json"
2372
2423
  };
@@ -2427,6 +2478,34 @@ var CustomEmbeddingProvider = class {
2427
2478
  }
2428
2479
  throw new Error("Custom embedding API returned unexpected response format. Expected OpenAI-compatible format with data[].embedding.");
2429
2480
  }
2481
+ async embedQuery(query) {
2482
+ const result = await this.embedBatch([query]);
2483
+ return {
2484
+ embedding: result.embeddings[0],
2485
+ tokensUsed: result.totalTokensUsed
2486
+ };
2487
+ }
2488
+ async embedDocument(document) {
2489
+ const result = await this.embedBatch([document]);
2490
+ return {
2491
+ embedding: result.embeddings[0],
2492
+ tokensUsed: result.totalTokensUsed
2493
+ };
2494
+ }
2495
+ async embedBatch(texts) {
2496
+ const requestBatches = this.splitIntoRequestBatches(texts);
2497
+ const embeddings = [];
2498
+ let totalTokensUsed = 0;
2499
+ for (const batch of requestBatches) {
2500
+ const result = await this.embedRequest(batch);
2501
+ embeddings.push(...result.embeddings);
2502
+ totalTokensUsed += result.totalTokensUsed;
2503
+ }
2504
+ return {
2505
+ embeddings,
2506
+ totalTokensUsed
2507
+ };
2508
+ }
2430
2509
  getModelInfo() {
2431
2510
  return this.modelInfo;
2432
2511
  }