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/cli.js CHANGED
@@ -754,6 +754,27 @@ var DEFAULT_PROVIDER_MODELS = {
754
754
  "ollama": "nomic-embed-text"
755
755
  };
756
756
 
757
+ // src/config/env-substitution.ts
758
+ var ENV_REFERENCE_PATTERN = /^\{env:([A-Z_][A-Z0-9_]*)\}$/;
759
+ var ENV_REFERENCE_LIKE_PATTERN = /\{env:[^}]+\}/;
760
+ function substituteEnvString(value, keyPath) {
761
+ const match = value.match(ENV_REFERENCE_PATTERN);
762
+ if (!match) {
763
+ if (ENV_REFERENCE_LIKE_PATTERN.test(value)) {
764
+ throw new Error(
765
+ `Invalid environment variable reference at '${keyPath}'. Expected the entire string to match '{env:VAR_NAME}' with VAR_NAME matching [A-Z_][A-Z0-9_]*.`
766
+ );
767
+ }
768
+ return value;
769
+ }
770
+ const variableName = match[1];
771
+ const envValue = process.env[variableName];
772
+ if (envValue === void 0) {
773
+ throw new Error(`Missing environment variable '${variableName}' referenced by config at '${keyPath}'.`);
774
+ }
775
+ return envValue;
776
+ }
777
+
757
778
  // src/config/schema.ts
758
779
  function getDefaultIndexingConfig() {
759
780
  return {
@@ -811,11 +832,27 @@ function isValidScope(value) {
811
832
  function isStringArray(value) {
812
833
  return Array.isArray(value) && value.every((item) => typeof item === "string");
813
834
  }
835
+ function getResolvedString(value, keyPath) {
836
+ if (typeof value !== "string") {
837
+ return void 0;
838
+ }
839
+ return substituteEnvString(value, keyPath);
840
+ }
841
+ function getResolvedStringArray(value, keyPath) {
842
+ if (!isStringArray(value)) {
843
+ return void 0;
844
+ }
845
+ return value.map((item, index) => substituteEnvString(item, `${keyPath}[${index}]`));
846
+ }
814
847
  function isValidLogLevel(value) {
815
848
  return typeof value === "string" && VALID_LOG_LEVELS.includes(value);
816
849
  }
817
850
  function parseConfig(raw) {
818
851
  const input = raw && typeof raw === "object" ? raw : {};
852
+ const embeddingProviderValue = getResolvedString(input.embeddingProvider, "$root.embeddingProvider");
853
+ const scopeValue = getResolvedString(input.scope, "$root.scope");
854
+ const includeValue = getResolvedStringArray(input.include, "$root.include");
855
+ const excludeValue = getResolvedStringArray(input.exclude, "$root.exclude");
819
856
  const defaultIndexing = getDefaultIndexingConfig();
820
857
  const defaultSearch = getDefaultSearchConfig();
821
858
  const defaultDebug = getDefaultDebugConfig();
@@ -858,19 +895,23 @@ function parseConfig(raw) {
858
895
  let embeddingProvider;
859
896
  let embeddingModel = void 0;
860
897
  let customProvider = void 0;
861
- if (input.embeddingProvider === "custom") {
898
+ if (embeddingProviderValue === "custom") {
862
899
  embeddingProvider = "custom";
863
900
  const rawCustom = input.customProvider && typeof input.customProvider === "object" ? input.customProvider : null;
864
- 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) {
901
+ const baseUrlValue = getResolvedString(rawCustom?.baseUrl, "$root.customProvider.baseUrl");
902
+ const modelValue = getResolvedString(rawCustom?.model, "$root.customProvider.model");
903
+ const apiKeyValue = getResolvedString(rawCustom?.apiKey, "$root.customProvider.apiKey");
904
+ 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) {
865
905
  customProvider = {
866
- baseUrl: rawCustom.baseUrl.trim().replace(/\/+$/, ""),
867
- model: rawCustom.model,
906
+ baseUrl: baseUrlValue.trim().replace(/\/+$/, ""),
907
+ model: modelValue,
868
908
  dimensions: rawCustom.dimensions,
869
- apiKey: typeof rawCustom.apiKey === "string" ? rawCustom.apiKey : void 0,
909
+ apiKey: apiKeyValue,
870
910
  maxTokens: typeof rawCustom.maxTokens === "number" ? rawCustom.maxTokens : void 0,
871
911
  timeoutMs: typeof rawCustom.timeoutMs === "number" ? Math.max(1e3, rawCustom.timeoutMs) : void 0,
872
912
  concurrency: typeof rawCustom.concurrency === "number" ? Math.max(1, Math.floor(rawCustom.concurrency)) : void 0,
873
- requestIntervalMs: typeof rawCustom.requestIntervalMs === "number" ? Math.max(0, Math.floor(rawCustom.requestIntervalMs)) : void 0
913
+ requestIntervalMs: typeof rawCustom.requestIntervalMs === "number" ? Math.max(0, Math.floor(rawCustom.requestIntervalMs)) : void 0,
914
+ 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
874
915
  };
875
916
  if (!/\/v\d+\/?$/.test(customProvider.baseUrl)) {
876
917
  console.warn(
@@ -882,10 +923,16 @@ function parseConfig(raw) {
882
923
  "embeddingProvider is 'custom' but customProvider config is missing or invalid. Required fields: baseUrl (string), model (string), dimensions (positive integer)."
883
924
  );
884
925
  }
885
- } else if (isValidProvider(input.embeddingProvider)) {
886
- embeddingProvider = input.embeddingProvider;
887
- if (input.embeddingModel) {
888
- embeddingModel = isValidModel(input.embeddingModel, embeddingProvider) ? input.embeddingModel : DEFAULT_PROVIDER_MODELS[embeddingProvider];
926
+ } else if (isValidProvider(embeddingProviderValue)) {
927
+ embeddingProvider = embeddingProviderValue;
928
+ const rawEmbeddingModel = input.embeddingModel;
929
+ if (typeof rawEmbeddingModel === "string") {
930
+ const embeddingModelValue = substituteEnvString(rawEmbeddingModel, "$root.embeddingModel");
931
+ if (embeddingModelValue) {
932
+ embeddingModel = isValidModel(embeddingModelValue, embeddingProvider) ? embeddingModelValue : DEFAULT_PROVIDER_MODELS[embeddingProvider];
933
+ }
934
+ } else if (rawEmbeddingModel) {
935
+ embeddingModel = DEFAULT_PROVIDER_MODELS[embeddingProvider];
889
936
  }
890
937
  } else {
891
938
  embeddingProvider = "auto";
@@ -894,9 +941,9 @@ function parseConfig(raw) {
894
941
  embeddingProvider,
895
942
  embeddingModel,
896
943
  customProvider,
897
- scope: isValidScope(input.scope) ? input.scope : "project",
898
- include: isStringArray(input.include) ? input.include : DEFAULT_INCLUDE,
899
- exclude: isStringArray(input.exclude) ? input.exclude : DEFAULT_EXCLUDE,
944
+ scope: isValidScope(scopeValue) ? scopeValue : "project",
945
+ include: includeValue ?? DEFAULT_INCLUDE,
946
+ exclude: excludeValue ?? DEFAULT_EXCLUDE,
900
947
  indexing,
901
948
  search,
902
949
  debug
@@ -2268,7 +2315,8 @@ function createCustomProviderInfo(config) {
2268
2315
  dimensions: config.dimensions,
2269
2316
  maxTokens: config.maxTokens ?? 8192,
2270
2317
  costPer1MTokens: 0,
2271
- timeoutMs: config.timeoutMs ?? 3e4
2318
+ timeoutMs: config.timeoutMs ?? 3e4,
2319
+ maxBatchSize: config.maxBatchSize
2272
2320
  }
2273
2321
  };
2274
2322
  }
@@ -2531,21 +2579,24 @@ var CustomEmbeddingProvider = class {
2531
2579
  this.credentials = credentials;
2532
2580
  this.modelInfo = modelInfo;
2533
2581
  }
2534
- async embedQuery(query) {
2535
- const result = await this.embedBatch([query]);
2536
- return {
2537
- embedding: result.embeddings[0],
2538
- tokensUsed: result.totalTokensUsed
2539
- };
2540
- }
2541
- async embedDocument(document) {
2542
- const result = await this.embedBatch([document]);
2543
- return {
2544
- embedding: result.embeddings[0],
2545
- tokensUsed: result.totalTokensUsed
2546
- };
2582
+ splitIntoRequestBatches(texts) {
2583
+ const maxBatchSize = this.modelInfo.maxBatchSize;
2584
+ if (!maxBatchSize || texts.length <= maxBatchSize) {
2585
+ return [texts];
2586
+ }
2587
+ const batches = [];
2588
+ for (let i = 0; i < texts.length; i += maxBatchSize) {
2589
+ batches.push(texts.slice(i, i + maxBatchSize));
2590
+ }
2591
+ return batches;
2547
2592
  }
2548
- async embedBatch(texts) {
2593
+ async embedRequest(texts) {
2594
+ if (texts.length === 0) {
2595
+ return {
2596
+ embeddings: [],
2597
+ totalTokensUsed: 0
2598
+ };
2599
+ }
2549
2600
  const headers = {
2550
2601
  "Content-Type": "application/json"
2551
2602
  };
@@ -2606,6 +2657,34 @@ var CustomEmbeddingProvider = class {
2606
2657
  }
2607
2658
  throw new Error("Custom embedding API returned unexpected response format. Expected OpenAI-compatible format with data[].embedding.");
2608
2659
  }
2660
+ async embedQuery(query) {
2661
+ const result = await this.embedBatch([query]);
2662
+ return {
2663
+ embedding: result.embeddings[0],
2664
+ tokensUsed: result.totalTokensUsed
2665
+ };
2666
+ }
2667
+ async embedDocument(document) {
2668
+ const result = await this.embedBatch([document]);
2669
+ return {
2670
+ embedding: result.embeddings[0],
2671
+ tokensUsed: result.totalTokensUsed
2672
+ };
2673
+ }
2674
+ async embedBatch(texts) {
2675
+ const requestBatches = this.splitIntoRequestBatches(texts);
2676
+ const embeddings = [];
2677
+ let totalTokensUsed = 0;
2678
+ for (const batch of requestBatches) {
2679
+ const result = await this.embedRequest(batch);
2680
+ embeddings.push(...result.embeddings);
2681
+ totalTokensUsed += result.totalTokensUsed;
2682
+ }
2683
+ return {
2684
+ embeddings,
2685
+ totalTokensUsed
2686
+ };
2687
+ }
2609
2688
  getModelInfo() {
2610
2689
  return this.modelInfo;
2611
2690
  }