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.js CHANGED
@@ -753,6 +753,27 @@ var DEFAULT_PROVIDER_MODELS = {
753
753
  "ollama": "nomic-embed-text"
754
754
  };
755
755
 
756
+ // src/config/env-substitution.ts
757
+ var ENV_REFERENCE_PATTERN = /^\{env:([A-Z_][A-Z0-9_]*)\}$/;
758
+ var ENV_REFERENCE_LIKE_PATTERN = /\{env:[^}]+\}/;
759
+ function substituteEnvString(value, keyPath) {
760
+ const match = value.match(ENV_REFERENCE_PATTERN);
761
+ if (!match) {
762
+ if (ENV_REFERENCE_LIKE_PATTERN.test(value)) {
763
+ throw new Error(
764
+ `Invalid environment variable reference at '${keyPath}'. Expected the entire string to match '{env:VAR_NAME}' with VAR_NAME matching [A-Z_][A-Z0-9_]*.`
765
+ );
766
+ }
767
+ return value;
768
+ }
769
+ const variableName = match[1];
770
+ const envValue = process.env[variableName];
771
+ if (envValue === void 0) {
772
+ throw new Error(`Missing environment variable '${variableName}' referenced by config at '${keyPath}'.`);
773
+ }
774
+ return envValue;
775
+ }
776
+
756
777
  // src/config/schema.ts
757
778
  function getDefaultIndexingConfig() {
758
779
  return {
@@ -810,11 +831,27 @@ function isValidScope(value) {
810
831
  function isStringArray(value) {
811
832
  return Array.isArray(value) && value.every((item) => typeof item === "string");
812
833
  }
834
+ function getResolvedString(value, keyPath) {
835
+ if (typeof value !== "string") {
836
+ return void 0;
837
+ }
838
+ return substituteEnvString(value, keyPath);
839
+ }
840
+ function getResolvedStringArray(value, keyPath) {
841
+ if (!isStringArray(value)) {
842
+ return void 0;
843
+ }
844
+ return value.map((item, index) => substituteEnvString(item, `${keyPath}[${index}]`));
845
+ }
813
846
  function isValidLogLevel(value) {
814
847
  return typeof value === "string" && VALID_LOG_LEVELS.includes(value);
815
848
  }
816
849
  function parseConfig(raw) {
817
850
  const input = raw && typeof raw === "object" ? raw : {};
851
+ const embeddingProviderValue = getResolvedString(input.embeddingProvider, "$root.embeddingProvider");
852
+ const scopeValue = getResolvedString(input.scope, "$root.scope");
853
+ const includeValue = getResolvedStringArray(input.include, "$root.include");
854
+ const excludeValue = getResolvedStringArray(input.exclude, "$root.exclude");
818
855
  const defaultIndexing = getDefaultIndexingConfig();
819
856
  const defaultSearch = getDefaultSearchConfig();
820
857
  const defaultDebug = getDefaultDebugConfig();
@@ -857,19 +894,23 @@ function parseConfig(raw) {
857
894
  let embeddingProvider;
858
895
  let embeddingModel = void 0;
859
896
  let customProvider = void 0;
860
- if (input.embeddingProvider === "custom") {
897
+ if (embeddingProviderValue === "custom") {
861
898
  embeddingProvider = "custom";
862
899
  const rawCustom = input.customProvider && typeof input.customProvider === "object" ? input.customProvider : null;
863
- 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) {
900
+ const baseUrlValue = getResolvedString(rawCustom?.baseUrl, "$root.customProvider.baseUrl");
901
+ const modelValue = getResolvedString(rawCustom?.model, "$root.customProvider.model");
902
+ const apiKeyValue = getResolvedString(rawCustom?.apiKey, "$root.customProvider.apiKey");
903
+ 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) {
864
904
  customProvider = {
865
- baseUrl: rawCustom.baseUrl.trim().replace(/\/+$/, ""),
866
- model: rawCustom.model,
905
+ baseUrl: baseUrlValue.trim().replace(/\/+$/, ""),
906
+ model: modelValue,
867
907
  dimensions: rawCustom.dimensions,
868
- apiKey: typeof rawCustom.apiKey === "string" ? rawCustom.apiKey : void 0,
908
+ apiKey: apiKeyValue,
869
909
  maxTokens: typeof rawCustom.maxTokens === "number" ? rawCustom.maxTokens : void 0,
870
910
  timeoutMs: typeof rawCustom.timeoutMs === "number" ? Math.max(1e3, rawCustom.timeoutMs) : void 0,
871
911
  concurrency: typeof rawCustom.concurrency === "number" ? Math.max(1, Math.floor(rawCustom.concurrency)) : void 0,
872
- requestIntervalMs: typeof rawCustom.requestIntervalMs === "number" ? Math.max(0, Math.floor(rawCustom.requestIntervalMs)) : void 0
912
+ requestIntervalMs: typeof rawCustom.requestIntervalMs === "number" ? Math.max(0, Math.floor(rawCustom.requestIntervalMs)) : void 0,
913
+ 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
873
914
  };
874
915
  if (!/\/v\d+\/?$/.test(customProvider.baseUrl)) {
875
916
  console.warn(
@@ -881,10 +922,16 @@ function parseConfig(raw) {
881
922
  "embeddingProvider is 'custom' but customProvider config is missing or invalid. Required fields: baseUrl (string), model (string), dimensions (positive integer)."
882
923
  );
883
924
  }
884
- } else if (isValidProvider(input.embeddingProvider)) {
885
- embeddingProvider = input.embeddingProvider;
886
- if (input.embeddingModel) {
887
- embeddingModel = isValidModel(input.embeddingModel, embeddingProvider) ? input.embeddingModel : DEFAULT_PROVIDER_MODELS[embeddingProvider];
925
+ } else if (isValidProvider(embeddingProviderValue)) {
926
+ embeddingProvider = embeddingProviderValue;
927
+ const rawEmbeddingModel = input.embeddingModel;
928
+ if (typeof rawEmbeddingModel === "string") {
929
+ const embeddingModelValue = substituteEnvString(rawEmbeddingModel, "$root.embeddingModel");
930
+ if (embeddingModelValue) {
931
+ embeddingModel = isValidModel(embeddingModelValue, embeddingProvider) ? embeddingModelValue : DEFAULT_PROVIDER_MODELS[embeddingProvider];
932
+ }
933
+ } else if (rawEmbeddingModel) {
934
+ embeddingModel = DEFAULT_PROVIDER_MODELS[embeddingProvider];
888
935
  }
889
936
  } else {
890
937
  embeddingProvider = "auto";
@@ -893,9 +940,9 @@ function parseConfig(raw) {
893
940
  embeddingProvider,
894
941
  embeddingModel,
895
942
  customProvider,
896
- scope: isValidScope(input.scope) ? input.scope : "project",
897
- include: isStringArray(input.include) ? input.include : DEFAULT_INCLUDE,
898
- exclude: isStringArray(input.exclude) ? input.exclude : DEFAULT_EXCLUDE,
943
+ scope: isValidScope(scopeValue) ? scopeValue : "project",
944
+ include: includeValue ?? DEFAULT_INCLUDE,
945
+ exclude: excludeValue ?? DEFAULT_EXCLUDE,
899
946
  indexing,
900
947
  search,
901
948
  debug
@@ -2079,7 +2126,8 @@ function createCustomProviderInfo(config) {
2079
2126
  dimensions: config.dimensions,
2080
2127
  maxTokens: config.maxTokens ?? 8192,
2081
2128
  costPer1MTokens: 0,
2082
- timeoutMs: config.timeoutMs ?? 3e4
2129
+ timeoutMs: config.timeoutMs ?? 3e4,
2130
+ maxBatchSize: config.maxBatchSize
2083
2131
  }
2084
2132
  };
2085
2133
  }
@@ -2342,21 +2390,24 @@ var CustomEmbeddingProvider = class {
2342
2390
  this.credentials = credentials;
2343
2391
  this.modelInfo = modelInfo;
2344
2392
  }
2345
- async embedQuery(query) {
2346
- const result = await this.embedBatch([query]);
2347
- return {
2348
- embedding: result.embeddings[0],
2349
- tokensUsed: result.totalTokensUsed
2350
- };
2351
- }
2352
- async embedDocument(document) {
2353
- const result = await this.embedBatch([document]);
2354
- return {
2355
- embedding: result.embeddings[0],
2356
- tokensUsed: result.totalTokensUsed
2357
- };
2393
+ splitIntoRequestBatches(texts) {
2394
+ const maxBatchSize = this.modelInfo.maxBatchSize;
2395
+ if (!maxBatchSize || texts.length <= maxBatchSize) {
2396
+ return [texts];
2397
+ }
2398
+ const batches = [];
2399
+ for (let i = 0; i < texts.length; i += maxBatchSize) {
2400
+ batches.push(texts.slice(i, i + maxBatchSize));
2401
+ }
2402
+ return batches;
2358
2403
  }
2359
- async embedBatch(texts) {
2404
+ async embedRequest(texts) {
2405
+ if (texts.length === 0) {
2406
+ return {
2407
+ embeddings: [],
2408
+ totalTokensUsed: 0
2409
+ };
2410
+ }
2360
2411
  const headers = {
2361
2412
  "Content-Type": "application/json"
2362
2413
  };
@@ -2417,6 +2468,34 @@ var CustomEmbeddingProvider = class {
2417
2468
  }
2418
2469
  throw new Error("Custom embedding API returned unexpected response format. Expected OpenAI-compatible format with data[].embedding.");
2419
2470
  }
2471
+ async embedQuery(query) {
2472
+ const result = await this.embedBatch([query]);
2473
+ return {
2474
+ embedding: result.embeddings[0],
2475
+ tokensUsed: result.totalTokensUsed
2476
+ };
2477
+ }
2478
+ async embedDocument(document) {
2479
+ const result = await this.embedBatch([document]);
2480
+ return {
2481
+ embedding: result.embeddings[0],
2482
+ tokensUsed: result.totalTokensUsed
2483
+ };
2484
+ }
2485
+ async embedBatch(texts) {
2486
+ const requestBatches = this.splitIntoRequestBatches(texts);
2487
+ const embeddings = [];
2488
+ let totalTokensUsed = 0;
2489
+ for (const batch of requestBatches) {
2490
+ const result = await this.embedRequest(batch);
2491
+ embeddings.push(...result.embeddings);
2492
+ totalTokensUsed += result.totalTokensUsed;
2493
+ }
2494
+ return {
2495
+ embeddings,
2496
+ totalTokensUsed
2497
+ };
2498
+ }
2420
2499
  getModelInfo() {
2421
2500
  return this.modelInfo;
2422
2501
  }