opencode-codebase-index 0.17.0 → 0.18.0

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.cjs CHANGED
@@ -656,467 +656,6 @@ var require_ignore = __commonJS({
656
656
  }
657
657
  });
658
658
 
659
- // node_modules/tiktoken/tiktoken_bg.cjs
660
- var require_tiktoken_bg = __commonJS({
661
- "node_modules/tiktoken/tiktoken_bg.cjs"(exports2, module3) {
662
- "use strict";
663
- var wasm;
664
- module3.exports.__wbg_set_wasm = function(val) {
665
- wasm = val;
666
- };
667
- var lTextDecoder = typeof TextDecoder === "undefined" ? (0, module3.require)("util").TextDecoder : TextDecoder;
668
- var cachedTextDecoder = new lTextDecoder("utf-8", { ignoreBOM: true, fatal: true });
669
- cachedTextDecoder.decode();
670
- var cachedUint8ArrayMemory0 = null;
671
- function getUint8ArrayMemory0() {
672
- if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
673
- cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
674
- }
675
- return cachedUint8ArrayMemory0;
676
- }
677
- function getStringFromWasm0(ptr, len) {
678
- ptr = ptr >>> 0;
679
- return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
680
- }
681
- var heap = new Array(128).fill(void 0);
682
- heap.push(void 0, null, true, false);
683
- var heap_next = heap.length;
684
- function addHeapObject(obj) {
685
- if (heap_next === heap.length) heap.push(heap.length + 1);
686
- const idx = heap_next;
687
- heap_next = heap[idx];
688
- heap[idx] = obj;
689
- return idx;
690
- }
691
- function handleError(f, args) {
692
- try {
693
- return f.apply(this, args);
694
- } catch (e) {
695
- wasm.__wbindgen_export_0(addHeapObject(e));
696
- }
697
- }
698
- function getObject(idx) {
699
- return heap[idx];
700
- }
701
- function dropObject(idx) {
702
- if (idx < 132) return;
703
- heap[idx] = heap_next;
704
- heap_next = idx;
705
- }
706
- function takeObject(idx) {
707
- const ret = getObject(idx);
708
- dropObject(idx);
709
- return ret;
710
- }
711
- var WASM_VECTOR_LEN = 0;
712
- var lTextEncoder = typeof TextEncoder === "undefined" ? (0, module3.require)("util").TextEncoder : TextEncoder;
713
- var cachedTextEncoder = new lTextEncoder("utf-8");
714
- var encodeString = typeof cachedTextEncoder.encodeInto === "function" ? function(arg, view) {
715
- return cachedTextEncoder.encodeInto(arg, view);
716
- } : function(arg, view) {
717
- const buf = cachedTextEncoder.encode(arg);
718
- view.set(buf);
719
- return {
720
- read: arg.length,
721
- written: buf.length
722
- };
723
- };
724
- function passStringToWasm0(arg, malloc, realloc) {
725
- if (realloc === void 0) {
726
- const buf = cachedTextEncoder.encode(arg);
727
- const ptr2 = malloc(buf.length, 1) >>> 0;
728
- getUint8ArrayMemory0().subarray(ptr2, ptr2 + buf.length).set(buf);
729
- WASM_VECTOR_LEN = buf.length;
730
- return ptr2;
731
- }
732
- let len = arg.length;
733
- let ptr = malloc(len, 1) >>> 0;
734
- const mem = getUint8ArrayMemory0();
735
- let offset = 0;
736
- for (; offset < len; offset++) {
737
- const code = arg.charCodeAt(offset);
738
- if (code > 127) break;
739
- mem[ptr + offset] = code;
740
- }
741
- if (offset !== len) {
742
- if (offset !== 0) {
743
- arg = arg.slice(offset);
744
- }
745
- ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
746
- const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
747
- const ret = encodeString(arg, view);
748
- offset += ret.written;
749
- ptr = realloc(ptr, len, offset, 1) >>> 0;
750
- }
751
- WASM_VECTOR_LEN = offset;
752
- return ptr;
753
- }
754
- function isLikeNone(x) {
755
- return x === void 0 || x === null;
756
- }
757
- var cachedDataViewMemory0 = null;
758
- function getDataViewMemory0() {
759
- if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || cachedDataViewMemory0.buffer.detached === void 0 && cachedDataViewMemory0.buffer !== wasm.memory.buffer) {
760
- cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
761
- }
762
- return cachedDataViewMemory0;
763
- }
764
- var cachedUint32ArrayMemory0 = null;
765
- function getUint32ArrayMemory0() {
766
- if (cachedUint32ArrayMemory0 === null || cachedUint32ArrayMemory0.byteLength === 0) {
767
- cachedUint32ArrayMemory0 = new Uint32Array(wasm.memory.buffer);
768
- }
769
- return cachedUint32ArrayMemory0;
770
- }
771
- function getArrayU32FromWasm0(ptr, len) {
772
- ptr = ptr >>> 0;
773
- return getUint32ArrayMemory0().subarray(ptr / 4, ptr / 4 + len);
774
- }
775
- function passArray8ToWasm0(arg, malloc) {
776
- const ptr = malloc(arg.length * 1, 1) >>> 0;
777
- getUint8ArrayMemory0().set(arg, ptr / 1);
778
- WASM_VECTOR_LEN = arg.length;
779
- return ptr;
780
- }
781
- function passArray32ToWasm0(arg, malloc) {
782
- const ptr = malloc(arg.length * 4, 4) >>> 0;
783
- getUint32ArrayMemory0().set(arg, ptr / 4);
784
- WASM_VECTOR_LEN = arg.length;
785
- return ptr;
786
- }
787
- function getArrayU8FromWasm0(ptr, len) {
788
- ptr = ptr >>> 0;
789
- return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
790
- }
791
- module3.exports.get_encoding = function(encoding, extend_special_tokens) {
792
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
793
- try {
794
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
795
- const ptr0 = passStringToWasm0(encoding, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
796
- const len0 = WASM_VECTOR_LEN;
797
- wasm.get_encoding(retptr, ptr0, len0, addHeapObject(extend_special_tokens));
798
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
799
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
800
- var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
801
- if (r2) {
802
- throw takeObject(r1);
803
- }
804
- return Tiktoken.__wrap(r0);
805
- } finally {
806
- wasm.__wbindgen_add_to_stack_pointer(16);
807
- }
808
- };
809
- module3.exports.encoding_for_model = function(model, extend_special_tokens) {
810
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
811
- try {
812
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
813
- const ptr0 = passStringToWasm0(model, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
814
- const len0 = WASM_VECTOR_LEN;
815
- wasm.encoding_for_model(retptr, ptr0, len0, addHeapObject(extend_special_tokens));
816
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
817
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
818
- var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
819
- if (r2) {
820
- throw takeObject(r1);
821
- }
822
- return Tiktoken.__wrap(r0);
823
- } finally {
824
- wasm.__wbindgen_add_to_stack_pointer(16);
825
- }
826
- };
827
- module3.exports.get_encoding_name_for_model = function(model) {
828
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
829
- let deferred3_0;
830
- let deferred3_1;
831
- try {
832
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
833
- const ptr0 = passStringToWasm0(model, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
834
- const len0 = WASM_VECTOR_LEN;
835
- wasm.get_encoding_name_for_model(retptr, ptr0, len0);
836
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
837
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
838
- var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
839
- var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
840
- var ptr2 = r0;
841
- var len2 = r1;
842
- if (r3) {
843
- ptr2 = 0;
844
- len2 = 0;
845
- throw takeObject(r2);
846
- }
847
- deferred3_0 = ptr2;
848
- deferred3_1 = len2;
849
- return getStringFromWasm0(ptr2, len2);
850
- } finally {
851
- wasm.__wbindgen_add_to_stack_pointer(16);
852
- wasm.__wbindgen_export_3(deferred3_0, deferred3_1, 1);
853
- }
854
- };
855
- var TiktokenFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
856
- }, unregister: () => {
857
- } } : new FinalizationRegistry((ptr) => wasm.__wbg_tiktoken_free(ptr >>> 0, 1));
858
- var Tiktoken = class _Tiktoken {
859
- /**
860
- * @param {string} tiktoken_bfe
861
- * @param {any} special_tokens
862
- * @param {string} pat_str
863
- */
864
- constructor(tiktoken_bfe, special_tokens, pat_str) {
865
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
866
- const ptr0 = passStringToWasm0(tiktoken_bfe, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
867
- const len0 = WASM_VECTOR_LEN;
868
- const ptr1 = passStringToWasm0(pat_str, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
869
- const len1 = WASM_VECTOR_LEN;
870
- const ret = wasm.tiktoken_new(ptr0, len0, addHeapObject(special_tokens), ptr1, len1);
871
- this.__wbg_ptr = ret >>> 0;
872
- TiktokenFinalization.register(this, this.__wbg_ptr, this);
873
- return this;
874
- }
875
- /** @returns {string | undefined} */
876
- get name() {
877
- try {
878
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
879
- wasm.tiktoken_name(retptr, this.__wbg_ptr);
880
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
881
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
882
- let v1;
883
- if (r0 !== 0) {
884
- v1 = getStringFromWasm0(r0, r1).slice();
885
- wasm.__wbindgen_export_3(r0, r1 * 1, 1);
886
- }
887
- return v1;
888
- } finally {
889
- wasm.__wbindgen_add_to_stack_pointer(16);
890
- }
891
- }
892
- static __wrap(ptr) {
893
- ptr = ptr >>> 0;
894
- const obj = Object.create(_Tiktoken.prototype);
895
- obj.__wbg_ptr = ptr;
896
- TiktokenFinalization.register(obj, obj.__wbg_ptr, obj);
897
- return obj;
898
- }
899
- __destroy_into_raw() {
900
- const ptr = this.__wbg_ptr;
901
- this.__wbg_ptr = 0;
902
- TiktokenFinalization.unregister(this);
903
- return ptr;
904
- }
905
- free() {
906
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
907
- const ptr = this.__destroy_into_raw();
908
- wasm.__wbg_tiktoken_free(ptr, 0);
909
- }
910
- /**
911
- * @param {string} text
912
- * @param {any} allowed_special
913
- * @param {any} disallowed_special
914
- * @returns {Uint32Array}
915
- */
916
- encode(text, allowed_special, disallowed_special) {
917
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
918
- try {
919
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
920
- const ptr0 = passStringToWasm0(text, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
921
- const len0 = WASM_VECTOR_LEN;
922
- wasm.tiktoken_encode(retptr, this.__wbg_ptr, ptr0, len0, addHeapObject(allowed_special), addHeapObject(disallowed_special));
923
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
924
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
925
- var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
926
- var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
927
- if (r3) {
928
- throw takeObject(r2);
929
- }
930
- var v2 = getArrayU32FromWasm0(r0, r1).slice();
931
- wasm.__wbindgen_export_3(r0, r1 * 4, 4);
932
- return v2;
933
- } finally {
934
- wasm.__wbindgen_add_to_stack_pointer(16);
935
- }
936
- }
937
- /**
938
- * @param {string} text
939
- * @returns {Uint32Array}
940
- */
941
- encode_ordinary(text) {
942
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
943
- try {
944
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
945
- const ptr0 = passStringToWasm0(text, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
946
- const len0 = WASM_VECTOR_LEN;
947
- wasm.tiktoken_encode_ordinary(retptr, this.__wbg_ptr, ptr0, len0);
948
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
949
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
950
- var v2 = getArrayU32FromWasm0(r0, r1).slice();
951
- wasm.__wbindgen_export_3(r0, r1 * 4, 4);
952
- return v2;
953
- } finally {
954
- wasm.__wbindgen_add_to_stack_pointer(16);
955
- }
956
- }
957
- /**
958
- * @param {string} text
959
- * @param {any} allowed_special
960
- * @param {any} disallowed_special
961
- * @returns {any}
962
- */
963
- encode_with_unstable(text, allowed_special, disallowed_special) {
964
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
965
- try {
966
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
967
- const ptr0 = passStringToWasm0(text, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
968
- const len0 = WASM_VECTOR_LEN;
969
- wasm.tiktoken_encode_with_unstable(retptr, this.__wbg_ptr, ptr0, len0, addHeapObject(allowed_special), addHeapObject(disallowed_special));
970
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
971
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
972
- var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
973
- if (r2) {
974
- throw takeObject(r1);
975
- }
976
- return takeObject(r0);
977
- } finally {
978
- wasm.__wbindgen_add_to_stack_pointer(16);
979
- }
980
- }
981
- /**
982
- * @param {Uint8Array} bytes
983
- * @returns {number}
984
- */
985
- encode_single_token(bytes) {
986
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
987
- const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_export_1);
988
- const len0 = WASM_VECTOR_LEN;
989
- const ret = wasm.tiktoken_encode_single_token(this.__wbg_ptr, ptr0, len0);
990
- return ret >>> 0;
991
- }
992
- /**
993
- * @param {Uint32Array} tokens
994
- * @returns {Uint8Array}
995
- */
996
- decode(tokens) {
997
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
998
- try {
999
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1000
- const ptr0 = passArray32ToWasm0(tokens, wasm.__wbindgen_export_1);
1001
- const len0 = WASM_VECTOR_LEN;
1002
- wasm.tiktoken_decode(retptr, this.__wbg_ptr, ptr0, len0);
1003
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1004
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1005
- var v2 = getArrayU8FromWasm0(r0, r1).slice();
1006
- wasm.__wbindgen_export_3(r0, r1 * 1, 1);
1007
- return v2;
1008
- } finally {
1009
- wasm.__wbindgen_add_to_stack_pointer(16);
1010
- }
1011
- }
1012
- /**
1013
- * @param {number} token
1014
- * @returns {Uint8Array}
1015
- */
1016
- decode_single_token_bytes(token) {
1017
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
1018
- try {
1019
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1020
- wasm.tiktoken_decode_single_token_bytes(retptr, this.__wbg_ptr, token);
1021
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1022
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1023
- var v1 = getArrayU8FromWasm0(r0, r1).slice();
1024
- wasm.__wbindgen_export_3(r0, r1 * 1, 1);
1025
- return v1;
1026
- } finally {
1027
- wasm.__wbindgen_add_to_stack_pointer(16);
1028
- }
1029
- }
1030
- /** @returns {any} */
1031
- token_byte_values() {
1032
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
1033
- const ret = wasm.tiktoken_token_byte_values(this.__wbg_ptr);
1034
- return takeObject(ret);
1035
- }
1036
- };
1037
- module3.exports.Tiktoken = Tiktoken;
1038
- module3.exports.__wbg_parse_def2e24ef1252aff = function() {
1039
- return handleError(function(arg0, arg1) {
1040
- const ret = JSON.parse(getStringFromWasm0(arg0, arg1));
1041
- return addHeapObject(ret);
1042
- }, arguments);
1043
- };
1044
- module3.exports.__wbg_stringify_f7ed6987935b4a24 = function() {
1045
- return handleError(function(arg0) {
1046
- const ret = JSON.stringify(getObject(arg0));
1047
- return addHeapObject(ret);
1048
- }, arguments);
1049
- };
1050
- module3.exports.__wbindgen_error_new = function(arg0, arg1) {
1051
- const ret = new Error(getStringFromWasm0(arg0, arg1));
1052
- return addHeapObject(ret);
1053
- };
1054
- module3.exports.__wbindgen_is_undefined = function(arg0) {
1055
- const ret = getObject(arg0) === void 0;
1056
- return ret;
1057
- };
1058
- module3.exports.__wbindgen_object_drop_ref = function(arg0) {
1059
- takeObject(arg0);
1060
- };
1061
- module3.exports.__wbindgen_string_get = function(arg0, arg1) {
1062
- if (wasm == null) throw new Error("tiktoken: WASM binary has not been propery initialized.");
1063
- const obj = getObject(arg1);
1064
- const ret = typeof obj === "string" ? obj : void 0;
1065
- var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_export_1, wasm.__wbindgen_export_2);
1066
- var len1 = WASM_VECTOR_LEN;
1067
- getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
1068
- getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
1069
- };
1070
- module3.exports.__wbindgen_throw = function(arg0, arg1) {
1071
- throw new Error(getStringFromWasm0(arg0, arg1));
1072
- };
1073
- }
1074
- });
1075
-
1076
- // node_modules/tiktoken/tiktoken.cjs
1077
- var require_tiktoken = __commonJS({
1078
- "node_modules/tiktoken/tiktoken.cjs"(exports2) {
1079
- "use strict";
1080
- var wasm = require_tiktoken_bg();
1081
- var imports = {};
1082
- imports["./tiktoken_bg.js"] = wasm;
1083
- var path27 = require("path");
1084
- var fs = require("fs");
1085
- var candidates = __dirname.split(path27.sep).reduce((memo, _, index, array) => {
1086
- const prefix = array.slice(0, index + 1).join(path27.sep) + path27.sep;
1087
- if (!prefix.includes("node_modules" + path27.sep)) {
1088
- memo.unshift(
1089
- path27.join(
1090
- prefix,
1091
- "node_modules",
1092
- "tiktoken",
1093
- "",
1094
- "./tiktoken_bg.wasm"
1095
- )
1096
- );
1097
- }
1098
- return memo;
1099
- }, []);
1100
- candidates.unshift(path27.join(__dirname, "./tiktoken_bg.wasm"));
1101
- var bytes = null;
1102
- for (const candidate of candidates) {
1103
- try {
1104
- bytes = fs.readFileSync(candidate);
1105
- break;
1106
- } catch {
1107
- }
1108
- }
1109
- if (bytes == null) throw new Error("Missing tiktoken_bg.wasm");
1110
- var wasmModule = new WebAssembly.Module(bytes);
1111
- var wasmInstance = new WebAssembly.Instance(wasmModule, imports);
1112
- wasm.__wbg_set_wasm(wasmInstance.exports);
1113
- exports2["get_encoding"] = wasm["get_encoding"];
1114
- exports2["encoding_for_model"] = wasm["encoding_for_model"];
1115
- exports2["get_encoding_name_for_model"] = wasm["get_encoding_name_for_model"];
1116
- exports2["Tiktoken"] = wasm["Tiktoken"];
1117
- }
1118
- });
1119
-
1120
659
  // src/cli.ts
1121
660
  var cli_exports = {};
1122
661
  __export(cli_exports, {
@@ -1146,7 +685,8 @@ var DEFAULT_INCLUDE = [
1146
685
  "**/*.{sh,bash,zsh}",
1147
686
  "**/*.{txt,html,htm}",
1148
687
  "**/*.zig",
1149
- "**/*.gd"
688
+ "**/*.gd",
689
+ "**/*.metal"
1150
690
  ];
1151
691
  var DEFAULT_EXCLUDE = [
1152
692
  "**/node_modules/**",
@@ -1337,6 +877,9 @@ function isValidProvider(value) {
1337
877
  return typeof value === "string" && Object.keys(EMBEDDING_MODELS).includes(value);
1338
878
  }
1339
879
  function isValidModel(value, provider) {
880
+ if (typeof value === "string" && provider === "ollama" && value.trim().length > 0) {
881
+ return true;
882
+ }
1340
883
  return typeof value === "string" && Object.keys(EMBEDDING_MODELS[provider]).includes(value);
1341
884
  }
1342
885
  function isValidScope(value) {
@@ -2919,6 +2462,9 @@ function loadOpenCodeAuth() {
2919
2462
  return {};
2920
2463
  }
2921
2464
  async function detectEmbeddingProvider(preferredProvider, model) {
2465
+ if (preferredProvider === "ollama") {
2466
+ return detectOllamaProvider(model);
2467
+ }
2922
2468
  const credentials = await getProviderCredentials(preferredProvider);
2923
2469
  if (credentials) {
2924
2470
  if (!model) {
@@ -2934,10 +2480,16 @@ async function detectEmbeddingProvider(preferredProvider, model) {
2934
2480
  );
2935
2481
  }
2936
2482
  const providerModels = EMBEDDING_MODELS[preferredProvider];
2483
+ const modelInfo = Object.values(providerModels).find((candidate) => candidate.model === model);
2484
+ if (!modelInfo) {
2485
+ throw new Error(
2486
+ `Model '${model}' is not supported by provider '${preferredProvider}'`
2487
+ );
2488
+ }
2937
2489
  return {
2938
2490
  provider: preferredProvider,
2939
2491
  credentials,
2940
- modelInfo: providerModels[model]
2492
+ modelInfo
2941
2493
  };
2942
2494
  }
2943
2495
  throw new Error(
@@ -2946,6 +2498,13 @@ async function detectEmbeddingProvider(preferredProvider, model) {
2946
2498
  }
2947
2499
  async function tryDetectProvider() {
2948
2500
  for (const provider of autoDetectProviders) {
2501
+ if (provider === "ollama") {
2502
+ const ollamaProvider = await tryDetectOllamaProvider();
2503
+ if (ollamaProvider) {
2504
+ return ollamaProvider;
2505
+ }
2506
+ continue;
2507
+ }
2949
2508
  const credentials = await getProviderCredentials(provider);
2950
2509
  if (credentials) {
2951
2510
  return {
@@ -3013,32 +2572,105 @@ function getGoogleCredentials() {
3013
2572
  }
3014
2573
  return null;
3015
2574
  }
3016
- async function getOllamaCredentials() {
3017
- const baseUrl = process.env.OLLAMA_HOST || "http://localhost:11434";
2575
+ async function fetchOllama(url, init) {
2576
+ const controller = new AbortController();
2577
+ const timeoutId = setTimeout(() => controller.abort(), 2e3);
3018
2578
  try {
3019
- const controller = new AbortController();
3020
- const timeoutId = setTimeout(() => controller.abort(), 2e3);
3021
- const response = await fetch(`${baseUrl}/api/tags`, {
3022
- signal: controller.signal
3023
- });
2579
+ return await fetch(url, { ...init, signal: controller.signal });
2580
+ } finally {
3024
2581
  clearTimeout(timeoutId);
2582
+ }
2583
+ }
2584
+ async function getOllamaCredentials() {
2585
+ const baseUrl = (process.env.OLLAMA_HOST || "http://localhost:11434").replace(/\/+$/, "");
2586
+ try {
2587
+ const response = await fetchOllama(`${baseUrl}/api/tags`);
3025
2588
  if (response.ok) {
3026
- const data = await response.json();
3027
- const hasEmbeddingModel = data.models?.some(
3028
- (m) => m.name.includes("nomic-embed") || m.name.includes("mxbai-embed") || m.name.includes("all-minilm")
3029
- );
3030
- if (hasEmbeddingModel) {
3031
- return {
3032
- provider: "ollama",
3033
- baseUrl
3034
- };
3035
- }
2589
+ return {
2590
+ provider: "ollama",
2591
+ baseUrl
2592
+ };
3036
2593
  }
3037
2594
  } catch {
3038
2595
  return null;
3039
2596
  }
3040
2597
  return null;
3041
2598
  }
2599
+ function findCatalogOllamaModel(model) {
2600
+ const stableName = model.endsWith(":latest") ? model.slice(0, -":latest".length) : model;
2601
+ return Object.values(EMBEDDING_MODELS.ollama).find((candidate) => candidate.model === stableName) ?? null;
2602
+ }
2603
+ function getPositiveIntegerMetadata(modelInfo, suffix) {
2604
+ const values = Object.entries(modelInfo).filter(([key]) => key.endsWith(suffix)).map(([, value]) => value).filter((value) => typeof value === "number" && Number.isInteger(value) && value > 0);
2605
+ return values.length === 1 ? values[0] : null;
2606
+ }
2607
+ async function fetchOllamaModelInfo(credentials, model) {
2608
+ const response = await fetchOllama(`${credentials.baseUrl}/api/show`, {
2609
+ method: "POST",
2610
+ headers: { "Content-Type": "application/json" },
2611
+ body: JSON.stringify({ model })
2612
+ });
2613
+ if (!response.ok) {
2614
+ return null;
2615
+ }
2616
+ const data = await response.json();
2617
+ if (!data.capabilities?.includes("embedding") || !data.model_info) {
2618
+ return null;
2619
+ }
2620
+ const dimensions = getPositiveIntegerMetadata(data.model_info, ".embedding_length");
2621
+ const maxTokens = getPositiveIntegerMetadata(data.model_info, ".context_length");
2622
+ if (!dimensions || !maxTokens) {
2623
+ return null;
2624
+ }
2625
+ return {
2626
+ provider: "ollama",
2627
+ model,
2628
+ dimensions,
2629
+ maxTokens,
2630
+ costPer1MTokens: 0
2631
+ };
2632
+ }
2633
+ async function listOllamaModels(credentials) {
2634
+ const response = await fetchOllama(`${credentials.baseUrl}/api/tags`);
2635
+ if (!response.ok) {
2636
+ return [];
2637
+ }
2638
+ const data = await response.json();
2639
+ return [...new Set((data.models ?? []).map((entry) => entry.name ?? entry.model).filter((name) => typeof name === "string" && name.trim().length > 0))];
2640
+ }
2641
+ async function detectOllamaProvider(model) {
2642
+ const credentials = await getOllamaCredentials();
2643
+ if (!credentials) {
2644
+ throw new Error("Preferred provider 'ollama' is not configured or authenticated");
2645
+ }
2646
+ const requestedModel = model?.trim();
2647
+ if (requestedModel) {
2648
+ const catalogModel = findCatalogOllamaModel(requestedModel);
2649
+ if (catalogModel) {
2650
+ return { provider: "ollama", credentials, modelInfo: catalogModel };
2651
+ }
2652
+ }
2653
+ const candidates = requestedModel ? [requestedModel] : await listOllamaModels(credentials);
2654
+ for (const candidate of candidates) {
2655
+ const modelInfo = await fetchOllamaModelInfo(credentials, candidate);
2656
+ if (modelInfo) {
2657
+ return {
2658
+ provider: "ollama",
2659
+ credentials,
2660
+ modelInfo: findCatalogOllamaModel(candidate) ?? modelInfo
2661
+ };
2662
+ }
2663
+ }
2664
+ const detail = model ? `Model '${model}' is not installed or is not embedding-capable` : "No installed embedding-capable Ollama model was found";
2665
+ throw new Error(detail);
2666
+ }
2667
+ async function tryDetectOllamaProvider() {
2668
+ try {
2669
+ return await detectOllamaProvider();
2670
+ } catch {
2671
+ return null;
2672
+ }
2673
+ }
3042
2674
  function getProviderDisplayName(provider) {
3043
2675
  switch (provider) {
3044
2676
  case "github-copilot":
@@ -3378,6 +3010,7 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddi
3378
3010
  // src/embeddings/providers/ollama.ts
3379
3011
  var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddingProvider {
3380
3012
  static MIN_TRUNCATION_CHARS = 512;
3013
+ static REQUEST_TIMEOUT_MS = 12e4;
3381
3014
  constructor(credentials, modelInfo) {
3382
3015
  super(credentials, modelInfo);
3383
3016
  }
@@ -3452,22 +3085,45 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
3452
3085
  }
3453
3086
  }
3454
3087
  async embedSingle(text) {
3455
- const response = await fetch(`${this.credentials.baseUrl}/api/embeddings`, {
3456
- method: "POST",
3457
- headers: {
3458
- "Content-Type": "application/json"
3459
- },
3460
- body: JSON.stringify({
3461
- model: this.modelInfo.model,
3462
- prompt: text,
3463
- truncate: false
3464
- })
3465
- });
3088
+ const controller = new AbortController();
3089
+ const timeout = setTimeout(
3090
+ () => controller.abort(),
3091
+ _OllamaEmbeddingProvider.REQUEST_TIMEOUT_MS
3092
+ );
3093
+ let response;
3094
+ try {
3095
+ response = await fetch(`${this.credentials.baseUrl}/api/embeddings`, {
3096
+ method: "POST",
3097
+ headers: {
3098
+ "Content-Type": "application/json"
3099
+ },
3100
+ body: JSON.stringify({
3101
+ model: this.modelInfo.model,
3102
+ prompt: text,
3103
+ truncate: false
3104
+ }),
3105
+ signal: controller.signal
3106
+ });
3107
+ } catch (error) {
3108
+ if (error instanceof Error && error.name === "AbortError") {
3109
+ throw new Error(
3110
+ `Ollama embedding request timed out after ${_OllamaEmbeddingProvider.REQUEST_TIMEOUT_MS}ms`
3111
+ );
3112
+ }
3113
+ throw error;
3114
+ } finally {
3115
+ clearTimeout(timeout);
3116
+ }
3466
3117
  if (!response.ok) {
3467
3118
  const error = (await response.text()).slice(0, 500);
3468
3119
  throw new Error(`Ollama embedding API error: ${response.status} - ${error}`);
3469
3120
  }
3470
3121
  const data = await response.json();
3122
+ if (!Array.isArray(data.embedding) || data.embedding.length !== this.modelInfo.dimensions || data.embedding.some((value) => typeof value !== "number" || !Number.isFinite(value))) {
3123
+ throw new Error(
3124
+ `Ollama returned an invalid embedding; expected ${this.modelInfo.dimensions} finite dimensions`
3125
+ );
3126
+ }
3471
3127
  return {
3472
3128
  embedding: data.embedding,
3473
3129
  tokensUsed: this.estimateTokens(text)
@@ -4379,7 +4035,9 @@ function mapChunk(c) {
4379
4035
  return {
4380
4036
  content: c.content,
4381
4037
  startLine: c.startLine ?? c.start_line,
4038
+ startCol: c.startCol ?? c.start_col,
4382
4039
  endLine: c.endLine ?? c.end_line,
4040
+ endCol: c.endCol ?? c.end_col,
4383
4041
  chunkType: c.chunkType ?? c.chunk_type,
4384
4042
  name: c.name ?? void 0,
4385
4043
  language: c.language
@@ -4500,6 +4158,7 @@ function getEmbeddingHeaderParts(chunk, filePath) {
4500
4158
  javascript: "JavaScript",
4501
4159
  python: "Python",
4502
4160
  rust: "Rust",
4161
+ swift: "Swift",
4503
4162
  go: "Go",
4504
4163
  java: "Java"
4505
4164
  };
@@ -4508,7 +4167,16 @@ function getEmbeddingHeaderParts(chunk, filePath) {
4508
4167
  function: "function",
4509
4168
  arrow_function: "arrow function",
4510
4169
  method_definition: "method",
4170
+ method_declaration: "method",
4171
+ protocol_function_declaration: "protocol requirement",
4172
+ init_declaration: "initializer",
4173
+ deinit_declaration: "deinitializer",
4174
+ subscript_declaration: "subscript",
4511
4175
  class_declaration: "class",
4176
+ actor_declaration: "actor",
4177
+ extension_declaration: "extension",
4178
+ protocol_declaration: "protocol",
4179
+ struct_declaration: "struct",
4512
4180
  interface_declaration: "interface",
4513
4181
  type_alias_declaration: "type alias",
4514
4182
  enum_declaration: "enum",
@@ -5202,16 +4870,6 @@ function resolveWorktreeFallbackPath(projectRoot, relativePath) {
5202
4870
  const fallbackPath = path8.join(mainRepoRoot, relativePath);
5203
4871
  return (0, import_fs6.existsSync)(fallbackPath) ? fallbackPath : null;
5204
4872
  }
5205
- function resolveWorktreeFallbackProjectIndexPath(projectRoot, host) {
5206
- const inheritedHostPath = resolveWorktreeFallbackPath(projectRoot, getProjectIndexRelativePath(host));
5207
- if (inheritedHostPath) {
5208
- return inheritedHostPath;
5209
- }
5210
- if (host !== "opencode") {
5211
- return resolveWorktreeFallbackPath(projectRoot, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
5212
- }
5213
- return null;
5214
- }
5215
4873
  function getHostProjectIndexRelativePath(host) {
5216
4874
  return getProjectIndexRelativePath(host);
5217
4875
  }
@@ -5313,6 +4971,9 @@ function resolveProjectIndexPath(projectRoot, scope, host = "opencode") {
5313
4971
  if (hasHostProjectConfig(projectRoot, host)) {
5314
4972
  return localIndexPath;
5315
4973
  }
4974
+ if (resolveWorktreeMainRepoRoot(projectRoot)) {
4975
+ return localIndexPath;
4976
+ }
5316
4977
  const hostFallback = resolveWorktreeFallbackPath(projectRoot, getProjectIndexRelativePath(host));
5317
4978
  if (hostFallback) {
5318
4979
  return hostFallback;
@@ -5837,40 +5498,6 @@ function releaseIndexLock(lease) {
5837
5498
  }
5838
5499
  return true;
5839
5500
  }
5840
- async function withIndexLock(indexPath, operation, callback, options = {}) {
5841
- const lease = acquireIndexLock(indexPath, operation);
5842
- let result;
5843
- let callbackError;
5844
- let callbackFailed = false;
5845
- try {
5846
- result = await callback(lease);
5847
- } catch (error) {
5848
- callbackFailed = true;
5849
- callbackError = error;
5850
- }
5851
- if (!callbackFailed && options.completeRecoveries !== false) {
5852
- try {
5853
- completeLeaseRecovery(lease);
5854
- } catch (error) {
5855
- callbackFailed = true;
5856
- callbackError = error;
5857
- }
5858
- }
5859
- let releaseError;
5860
- try {
5861
- if (!releaseIndexLock(lease)) {
5862
- releaseError = new Error(`Lost ownership of index mutation lease ${lease.owner.token}`);
5863
- }
5864
- } catch (error) {
5865
- releaseError = error;
5866
- }
5867
- if (releaseError !== void 0) {
5868
- if (callbackFailed) throw new AggregateError([callbackError, releaseError], "Index mutation and lease release both failed");
5869
- throw releaseError;
5870
- }
5871
- if (callbackFailed) throw callbackError;
5872
- return result;
5873
- }
5874
5501
  function createLeaseTemporaryPath(targetPath, owner, kind = "tmp") {
5875
5502
  if (kind === "bak") return `${targetPath}.bak.${owner.pid}.${owner.token}`;
5876
5503
  temporaryCounter += 1;
@@ -5905,8 +5532,18 @@ function completeLeaseRecovery(lease) {
5905
5532
  }
5906
5533
 
5907
5534
  // src/indexer/index.ts
5908
- var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab", "bash"]);
5909
- var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex"]);
5535
+ var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "swift", "php", "apex", "zig", "gdscript", "matlab", "bash", "c", "cpp", "metal"]);
5536
+ var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex", "php"]);
5537
+ var CALL_GRAPH_RESOLUTION_VERSION = "4";
5538
+ var PHP_FUNCTION_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
5539
+ "function_declaration",
5540
+ "function",
5541
+ "function_definition"
5542
+ ]);
5543
+ var PHP_CLASS_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
5544
+ "class_declaration",
5545
+ "class_definition"
5546
+ ]);
5910
5547
  var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
5911
5548
  "function_declaration",
5912
5549
  "function",
@@ -5919,6 +5556,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
5919
5556
  "enum_declaration",
5920
5557
  "function_definition",
5921
5558
  "class_definition",
5559
+ "class_specifier",
5560
+ "struct_specifier",
5561
+ "namespace_definition",
5922
5562
  "decorated_definition",
5923
5563
  "method_declaration",
5924
5564
  "type_declaration",
@@ -5934,6 +5574,14 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
5934
5574
  "test_declaration",
5935
5575
  "struct_declaration",
5936
5576
  "union_declaration",
5577
+ // Synthetic Swift declarations or declarations specific to tree-sitter-swift.
5578
+ "actor_declaration",
5579
+ "extension_declaration",
5580
+ "protocol_declaration",
5581
+ "protocol_function_declaration",
5582
+ "init_declaration",
5583
+ "deinit_declaration",
5584
+ "subscript_declaration",
5937
5585
  // GDScript declarations whose names participate in the call graph.
5938
5586
  // `function_definition` and `class_definition` are already in the set
5939
5587
  // above (shared with Python/C/Bash and Python, respectively).
@@ -5943,6 +5591,53 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
5943
5591
  "const_statement",
5944
5592
  "class_name_statement"
5945
5593
  ]);
5594
+ var C_FAMILY_TYPE_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set(["class_specifier", "struct_specifier"]);
5595
+ function isCompatibleCFamilyCallTarget(language, callType, symbolKind) {
5596
+ if (language !== "c" && language !== "cpp") return true;
5597
+ if (symbolKind === "namespace_definition") return callType === "Import";
5598
+ const isTypeSymbol = C_FAMILY_TYPE_SYMBOL_CHUNK_TYPES.has(symbolKind);
5599
+ if (callType === "Constructor" || callType === "Inherits" || callType === "Implements") {
5600
+ return isTypeSymbol;
5601
+ }
5602
+ return !isTypeSymbol;
5603
+ }
5604
+ var EXECUTABLE_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
5605
+ "function_declaration",
5606
+ "function",
5607
+ "arrow_function",
5608
+ "method_definition",
5609
+ "function_definition",
5610
+ "method_declaration",
5611
+ "function_item",
5612
+ "protocol_function_declaration",
5613
+ "init_declaration",
5614
+ "deinit_declaration",
5615
+ "subscript_declaration",
5616
+ "constructor_definition",
5617
+ "trigger_declaration",
5618
+ "test_declaration"
5619
+ ]);
5620
+ function findEnclosingSymbol(symbols, line, column) {
5621
+ let best;
5622
+ for (const symbol of symbols) {
5623
+ if (line < symbol.startLine || line > symbol.endLine) continue;
5624
+ if (column !== void 0 && (line === symbol.startLine && column < symbol.startCol || line === symbol.endLine && column >= symbol.endCol)) {
5625
+ continue;
5626
+ }
5627
+ if (!best) {
5628
+ best = symbol;
5629
+ continue;
5630
+ }
5631
+ const span = symbol.endLine - symbol.startLine;
5632
+ const bestSpan = best.endLine - best.startLine;
5633
+ const isNarrowerPositionRange = column !== void 0 && span === bestSpan && symbol.startLine === best.startLine && symbol.endLine === best.endLine && symbol.startCol >= best.startCol && symbol.endCol <= best.endCol && (symbol.startCol > best.startCol || symbol.endCol < best.endCol);
5634
+ const isMoreSpecificTie = span === bestSpan && symbol.startLine === best.startLine && EXECUTABLE_SYMBOL_CHUNK_TYPES.has(symbol.kind) && !EXECUTABLE_SYMBOL_CHUNK_TYPES.has(best.kind);
5635
+ if (span < bestSpan || span === bestSpan && symbol.startLine > best.startLine || isNarrowerPositionRange || isMoreSpecificTie) {
5636
+ best = symbol;
5637
+ }
5638
+ }
5639
+ return best;
5640
+ }
5946
5641
  function float32ArrayToBuffer(arr) {
5947
5642
  const float32 = new Float32Array(arr);
5948
5643
  return Buffer.from(float32.buffer);
@@ -6027,6 +5722,8 @@ function hasBlameMetadata(metadata) {
6027
5722
  }
6028
5723
  var INDEX_METADATA_VERSION = "1";
6029
5724
  var EMBEDDING_STRATEGY_VERSION = "2";
5725
+ var SWIFT_PARSER_VERSION = "1";
5726
+ var METAL_PARSER_VERSION = "1";
6030
5727
  var RANKING_TOKEN_CACHE_LIMIT = 4096;
6031
5728
  var RANK_HYBRID_CACHE_LIMIT = 256;
6032
5729
  function createPendingChunkStorageText(texts) {
@@ -6349,15 +6046,25 @@ function chunkTypeBoost(chunkType) {
6349
6046
  case "function_declaration":
6350
6047
  case "method":
6351
6048
  case "method_definition":
6049
+ case "method_declaration":
6050
+ case "protocol_function_declaration":
6051
+ case "init_declaration":
6052
+ case "deinit_declaration":
6053
+ case "subscript_declaration":
6352
6054
  case "class":
6353
6055
  case "class_declaration":
6056
+ case "actor_declaration":
6057
+ case "extension_declaration":
6354
6058
  return 0.2;
6355
6059
  case "interface":
6356
6060
  case "type":
6357
6061
  case "enum":
6062
+ case "enum_declaration":
6358
6063
  case "struct":
6064
+ case "struct_declaration":
6359
6065
  case "impl":
6360
6066
  case "trait":
6067
+ case "protocol_declaration":
6361
6068
  case "module":
6362
6069
  return 0.1;
6363
6070
  default:
@@ -6464,11 +6171,21 @@ function isImplementationChunkType(chunkType) {
6464
6171
  "function_declaration",
6465
6172
  "method",
6466
6173
  "method_definition",
6174
+ "method_declaration",
6175
+ "protocol_function_declaration",
6176
+ "init_declaration",
6177
+ "deinit_declaration",
6178
+ "subscript_declaration",
6467
6179
  "class",
6468
6180
  "class_declaration",
6181
+ "actor_declaration",
6182
+ "extension_declaration",
6469
6183
  "interface",
6184
+ "protocol_declaration",
6470
6185
  "type",
6471
6186
  "enum",
6187
+ "enum_declaration",
6188
+ "struct_declaration",
6472
6189
  "module"
6473
6190
  ].includes(chunkType);
6474
6191
  }
@@ -7471,6 +7188,29 @@ var Indexer = class {
7471
7188
  const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
7472
7189
  return `index.forceReembed.${projectHash}`;
7473
7190
  }
7191
+ getCallGraphResolutionMetadataKey() {
7192
+ if (this.config.scope !== "global") {
7193
+ return "index.callGraphResolutionVersion";
7194
+ }
7195
+ const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
7196
+ return `index.callGraphResolutionVersion.${projectHash}`;
7197
+ }
7198
+ getSwiftParserVersionMetadataKey() {
7199
+ const key = "index.parser.swiftVersion";
7200
+ if (this.config.scope !== "global") {
7201
+ return key;
7202
+ }
7203
+ const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
7204
+ return `${key}.${projectHash}`;
7205
+ }
7206
+ getMetalParserVersionMetadataKey() {
7207
+ const key = "index.parser.metalVersion";
7208
+ if (this.config.scope !== "global") {
7209
+ return key;
7210
+ }
7211
+ const projectHash = hashContent(path12.resolve(this.projectRoot)).slice(0, 16);
7212
+ return `${key}.${projectHash}`;
7213
+ }
7474
7214
  hasProjectForceReembedPending() {
7475
7215
  return this.config.scope === "global" && this.database?.getMetadata(this.getProjectForceReembedMetadataKey()) === "true";
7476
7216
  }
@@ -8631,6 +8371,7 @@ var Indexer = class {
8631
8371
  this.database.setMetadata("index.embeddingProvider", provider.provider);
8632
8372
  this.database.setMetadata("index.embeddingModel", provider.modelInfo.model);
8633
8373
  this.database.setMetadata("index.embeddingDimensions", provider.modelInfo.dimensions.toString());
8374
+ this.database.setMetadata(this.getCallGraphResolutionMetadataKey(), CALL_GRAPH_RESOLUTION_VERSION);
8634
8375
  if (this.config.scope === "global") {
8635
8376
  if (completeProjectEmbeddingStrategyReset) {
8636
8377
  this.database.setMetadata(this.getProjectEmbeddingStrategyMetadataKey(), EMBEDDING_STRATEGY_VERSION);
@@ -8818,6 +8559,20 @@ var Indexer = class {
8818
8559
  totalChunks: 0
8819
8560
  });
8820
8561
  this.loadFileHashCache();
8562
+ const swiftParserMetadataKey = this.getSwiftParserVersionMetadataKey();
8563
+ const reparseCachedSwiftFiles = database.getMetadata(swiftParserMetadataKey) !== SWIFT_PARSER_VERSION;
8564
+ const metalParserMetadataKey = this.getMetalParserVersionMetadataKey();
8565
+ const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
8566
+ if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some(
8567
+ (filePath) => path12.extname(filePath).toLowerCase() === ".swift"
8568
+ )) {
8569
+ this.logger.info("Reindexing cached Swift files for parser support");
8570
+ }
8571
+ if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some(
8572
+ (filePath) => path12.extname(filePath).toLowerCase() === ".metal"
8573
+ )) {
8574
+ this.logger.info("Reindexing cached Metal files for parser support");
8575
+ }
8821
8576
  const includePatterns = [...this.config.include, ...this.config.additionalInclude];
8822
8577
  const { files, skipped } = await collectFiles(
8823
8578
  this.projectRoot,
@@ -8837,10 +8592,17 @@ var Indexer = class {
8837
8592
  const changedFiles = [];
8838
8593
  const unchangedFilePaths = /* @__PURE__ */ new Set();
8839
8594
  const currentFileHashes = /* @__PURE__ */ new Map();
8595
+ const needsCallGraphResolutionMigration = database.getMetadata(this.getCallGraphResolutionMetadataKey()) !== CALL_GRAPH_RESOLUTION_VERSION;
8840
8596
  for (const f of files) {
8841
8597
  const currentHash = hashFile(f.path);
8842
8598
  currentFileHashes.set(f.path, currentHash);
8843
- if (this.fileHashCache.get(f.path) === currentHash) {
8599
+ const cachedHashMatches = this.fileHashCache.get(f.path) === currentHash;
8600
+ const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(f.path).some(
8601
+ (chunk) => chunk.language === "php" || chunk.language === "c" || chunk.language === "cpp"
8602
+ );
8603
+ const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path12.extname(f.path).toLowerCase() === ".swift";
8604
+ const requiresMetalParserUpgrade = reparseCachedMetalFiles && path12.extname(f.path).toLowerCase() === ".metal";
8605
+ if (cachedHashMatches && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade) {
8844
8606
  unchangedFilePaths.add(f.path);
8845
8607
  this.logger.recordCacheHit();
8846
8608
  } else {
@@ -9042,16 +8804,28 @@ var Indexer = class {
9042
8804
  const fileSymbols = [];
9043
8805
  for (const chunk of parsed.chunks) {
9044
8806
  if (!chunk.name || !CALL_GRAPH_SYMBOL_CHUNK_TYPES.has(chunk.chunkType)) continue;
9045
- const symbolId = `sym_${hashContent(parsed.path + ":" + chunk.name + ":" + chunk.chunkType + ":" + chunk.startLine).slice(0, 16)}`;
8807
+ const existingMetalSymbol = chunk.language === "metal" ? fileSymbols.find(
8808
+ (symbol2) => symbol2.name === chunk.name && symbol2.kind === chunk.chunkType && symbol2.startLine <= chunk.endLine && chunk.startLine <= symbol2.endLine
8809
+ ) : void 0;
8810
+ if (existingMetalSymbol) {
8811
+ existingMetalSymbol.startLine = Math.min(existingMetalSymbol.startLine, chunk.startLine);
8812
+ existingMetalSymbol.endLine = Math.max(existingMetalSymbol.endLine, chunk.endLine);
8813
+ existingMetalSymbol.startCol = Math.min(existingMetalSymbol.startCol, chunk.startCol ?? 0);
8814
+ existingMetalSymbol.endCol = Math.max(existingMetalSymbol.endCol, chunk.endCol ?? 0);
8815
+ continue;
8816
+ }
8817
+ const symbolId = `sym_${hashContent(
8818
+ parsed.path + ":" + chunk.name + ":" + chunk.chunkType + ":" + chunk.startLine + ":" + (chunk.startCol ?? 0)
8819
+ ).slice(0, 16)}`;
9046
8820
  const symbol = {
9047
8821
  id: symbolId,
9048
8822
  filePath: parsed.path,
9049
8823
  name: chunk.name,
9050
8824
  kind: chunk.chunkType,
9051
8825
  startLine: chunk.startLine,
9052
- startCol: 0,
8826
+ startCol: chunk.startCol ?? 0,
9053
8827
  endLine: chunk.endLine,
9054
- endCol: 0,
8828
+ endCol: chunk.endCol ?? 0,
9055
8829
  language: chunk.language
9056
8830
  };
9057
8831
  fileSymbols.push(symbol);
@@ -9076,8 +8850,10 @@ var Indexer = class {
9076
8850
  if (callSites.length === 0) continue;
9077
8851
  const edges = [];
9078
8852
  for (const site of callSites) {
9079
- const enclosingSymbol = fileSymbols.find(
9080
- (sym) => site.line >= sym.startLine && site.line <= sym.endLine
8853
+ const enclosingSymbol = findEnclosingSymbol(
8854
+ fileSymbols,
8855
+ site.line,
8856
+ site.column
9081
8857
  );
9082
8858
  if (!enclosingSymbol) continue;
9083
8859
  const edgeId = `edge_${hashContent(enclosingSymbol.id + ":" + site.calleeName + ":" + site.line + ":" + site.column).slice(0, 16)}`;
@@ -9096,7 +8872,21 @@ var Indexer = class {
9096
8872
  if (edges.length > 0) {
9097
8873
  database.upsertCallEdgesBatch(edges);
9098
8874
  for (const edge of edges) {
9099
- const candidates = symbolsByName.get(normalizeSymbolKey(edge.targetName));
8875
+ let candidates = symbolsByName.get(normalizeSymbolKey(edge.targetName));
8876
+ if (fileLanguage === "php" && candidates) {
8877
+ if (edge.callType === "Constructor") {
8878
+ candidates = candidates.filter(
8879
+ (candidate) => PHP_CLASS_SYMBOL_CHUNK_TYPES.has(candidate.kind)
8880
+ );
8881
+ } else if (edge.callType === "Call") {
8882
+ candidates = candidates.filter(
8883
+ (candidate) => PHP_FUNCTION_SYMBOL_CHUNK_TYPES.has(candidate.kind)
8884
+ );
8885
+ }
8886
+ }
8887
+ candidates = candidates?.filter(
8888
+ (symbol) => isCompatibleCFamilyCallTarget(fileLanguage, edge.callType, symbol.kind)
8889
+ );
9100
8890
  if (candidates && candidates.length === 1) {
9101
8891
  database.resolveCallEdge(edge.id, candidates[0].id);
9102
8892
  }
@@ -9151,6 +8941,8 @@ var Indexer = class {
9151
8941
  this.saveFileHashCache();
9152
8942
  this.saveFailedBatches([]);
9153
8943
  }
8944
+ database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
8945
+ database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
9154
8946
  this.saveIndexMetadata(configuredProviderInfo);
9155
8947
  this.indexCompatibility = { compatible: true };
9156
8948
  stats.durationMs = Date.now() - startTime;
@@ -9178,6 +8970,8 @@ var Indexer = class {
9178
8970
  this.saveFileHashCache();
9179
8971
  this.saveFailedBatches([]);
9180
8972
  }
8973
+ database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
8974
+ database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
9181
8975
  this.saveIndexMetadata(configuredProviderInfo);
9182
8976
  this.indexCompatibility = { compatible: true };
9183
8977
  stats.durationMs = Date.now() - startTime;
@@ -9448,6 +9242,8 @@ var Indexer = class {
9448
9242
  if (forceScopedReembed && failedForcedChunkIds.size === 0) {
9449
9243
  database.deleteMetadata(this.getProjectForceReembedMetadataKey());
9450
9244
  }
9245
+ database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
9246
+ database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
9451
9247
  this.saveIndexMetadata(configuredProviderInfo);
9452
9248
  this.indexCompatibility = { compatible: true };
9453
9249
  this.logger.recordIndexingEnd();
@@ -10558,232 +10354,26 @@ var Indexer = class {
10558
10354
  var import_fs11 = require("fs");
10559
10355
  var path17 = __toESM(require("path"), 1);
10560
10356
 
10561
- // src/config/merger.ts
10562
- var import_fs9 = require("fs");
10563
- var path14 = __toESM(require("path"), 1);
10564
-
10565
- // src/config/rebase.ts
10357
+ // src/tools/knowledge-base-paths.ts
10566
10358
  var path13 = __toESM(require("path"), 1);
10567
- function isWithinRoot(rootDir, targetPath) {
10568
- const relativePath = path13.relative(rootDir, targetPath);
10569
- return relativePath === "" || !relativePath.startsWith("..") && !path13.isAbsolute(relativePath);
10570
- }
10571
- function rebasePathEntries(values, fromDir, toDir) {
10572
- if (!Array.isArray(values)) {
10573
- return [];
10359
+ function resolveConfigPathValue(value, baseDir) {
10360
+ const trimmed = value.trim();
10361
+ if (!trimmed) {
10362
+ return trimmed;
10574
10363
  }
10575
- return values.filter((value) => typeof value === "string").map((value) => {
10576
- const trimmed = value.trim();
10577
- if (!trimmed || path13.isAbsolute(trimmed)) {
10578
- return trimmed;
10579
- }
10580
- return normalizePathSeparators(path13.normalize(path13.relative(toDir, path13.resolve(fromDir, trimmed))));
10581
- }).filter(Boolean);
10364
+ const absolutePath = path13.isAbsolute(trimmed) ? trimmed : path13.resolve(baseDir, trimmed);
10365
+ return path13.normalize(absolutePath);
10582
10366
  }
10583
- function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
10584
- if (!Array.isArray(values)) {
10585
- return [];
10586
- }
10587
- return values.filter((value) => typeof value === "string").map((value) => {
10588
- const trimmed = value.trim();
10589
- if (!trimmed) {
10590
- return trimmed;
10591
- }
10592
- if (path13.isAbsolute(trimmed)) {
10593
- if (isWithinRoot(sourceRoot, trimmed)) {
10594
- return normalizePathSeparators(path13.normalize(path13.relative(sourceRoot, trimmed) || "."));
10595
- }
10596
- return path13.normalize(trimmed);
10597
- }
10598
- const resolvedFromSource = path13.resolve(sourceRoot, trimmed);
10599
- if (isWithinRoot(sourceRoot, resolvedFromSource)) {
10600
- return normalizePathSeparators(path13.normalize(trimmed));
10601
- }
10602
- return normalizePathSeparators(path13.normalize(path13.relative(targetRoot, resolvedFromSource)));
10603
- }).filter(Boolean);
10604
- }
10605
-
10606
- // src/config/merger.ts
10607
- var PROJECT_OVERRIDE_KEYS = [
10608
- "embeddingProvider",
10609
- "customProvider",
10610
- "embeddingModel",
10611
- "reranker",
10612
- "include",
10613
- "exclude",
10614
- "indexing",
10615
- "search",
10616
- "debug",
10617
- "scope"
10618
- ];
10619
- var MERGE_ARRAY_KEYS = ["knowledgeBases", "additionalInclude"];
10620
- function isRecord(value) {
10621
- return typeof value === "object" && value !== null && !Array.isArray(value);
10622
- }
10623
- function isStringArray2(value) {
10624
- return Array.isArray(value) && value.every((item) => typeof item === "string");
10625
- }
10626
- function applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key) {
10627
- if (key in normalizedProjectConfig) {
10628
- merged[key] = normalizedProjectConfig[key];
10629
- return;
10630
- }
10631
- if (key in globalConfig) {
10632
- merged[key] = globalConfig[key];
10633
- }
10634
- }
10635
- function mergeUniqueStringArray(values) {
10636
- return [...new Set(values.map((value) => String(value).trim()))];
10637
- }
10638
- function normalizeKnowledgeBasePath(value) {
10639
- let normalized = path14.normalize(String(value).trim());
10640
- const root = path14.parse(normalized).root;
10641
- while (normalized.length > root.length && /[\\/]$/.test(normalized)) {
10642
- normalized = normalized.slice(0, -1);
10643
- }
10644
- return normalized;
10645
- }
10646
- function mergeKnowledgeBasePaths(values) {
10647
- return [...new Set(values.map((value) => normalizeKnowledgeBasePath(value)).filter((value) => value.length > 0))];
10648
- }
10649
- function validateConfigLayerShape(rawConfig, filePath) {
10650
- if (!isRecord(rawConfig)) {
10651
- throw new Error(`Config file ${filePath} must contain a JSON object at the root.`);
10652
- }
10653
- if (rawConfig.knowledgeBases !== void 0 && !isStringArray2(rawConfig.knowledgeBases)) {
10654
- throw new Error(`Config file ${filePath} field 'knowledgeBases' must be an array of strings.`);
10655
- }
10656
- if (rawConfig.additionalInclude !== void 0 && !isStringArray2(rawConfig.additionalInclude)) {
10657
- throw new Error(`Config file ${filePath} field 'additionalInclude' must be an array of strings.`);
10658
- }
10659
- if (rawConfig.include !== void 0 && !isStringArray2(rawConfig.include)) {
10660
- throw new Error(`Config file ${filePath} field 'include' must be an array of strings.`);
10661
- }
10662
- if (rawConfig.exclude !== void 0 && !isStringArray2(rawConfig.exclude)) {
10663
- throw new Error(`Config file ${filePath} field 'exclude' must be an array of strings.`);
10664
- }
10665
- for (const section of ["customProvider", "indexing", "search", "debug", "reranker"]) {
10666
- const value = rawConfig[section];
10667
- if (value !== void 0 && !isRecord(value)) {
10668
- throw new Error(`Config file ${filePath} field '${section}' must be an object.`);
10669
- }
10670
- }
10671
- return rawConfig;
10672
- }
10673
- function loadJsonFile(filePath) {
10674
- if (!(0, import_fs9.existsSync)(filePath)) {
10675
- return null;
10676
- }
10677
- try {
10678
- const content = (0, import_fs9.readFileSync)(filePath, "utf-8");
10679
- return validateConfigLayerShape(JSON.parse(content), filePath);
10680
- } catch (error) {
10681
- if (error instanceof Error && error.message.startsWith("Config file ")) {
10682
- throw error;
10683
- }
10684
- const message = error instanceof Error ? error.message : String(error);
10685
- throw new Error(`Failed to load config file ${filePath}: ${message}`);
10686
- }
10687
- }
10688
- function loadConfigFile(filePath) {
10689
- return loadJsonFile(filePath);
10690
- }
10691
- function materializeLocalProjectConfig(projectRoot, config, host = "opencode") {
10692
- const localConfigPath = resolveWritableProjectConfigPath(projectRoot, host);
10693
- (0, import_fs9.mkdirSync)(path14.dirname(localConfigPath), { recursive: true });
10694
- (0, import_fs9.writeFileSync)(localConfigPath, JSON.stringify(config, null, 2), "utf-8");
10695
- return localConfigPath;
10696
- }
10697
- function loadProjectConfigLayer(projectRoot, host = "opencode") {
10698
- const projectConfigPath = resolveProjectConfigPath(projectRoot, host);
10699
- const projectConfig = loadJsonFile(projectConfigPath);
10700
- if (!projectConfig) {
10701
- return {};
10702
- }
10703
- const normalizedConfig = { ...projectConfig };
10704
- const projectConfigBaseDir = path14.dirname(path14.dirname(projectConfigPath));
10705
- if (Array.isArray(normalizedConfig.knowledgeBases)) {
10706
- normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
10707
- normalizedConfig.knowledgeBases,
10708
- projectConfigBaseDir,
10709
- projectRoot
10710
- );
10711
- }
10712
- return normalizedConfig;
10713
- }
10714
- function loadMergedConfig(projectRoot, host = "opencode") {
10715
- const globalConfigPath = resolveGlobalConfigPath(host);
10716
- const projectConfigPath = resolveProjectConfigPath(projectRoot, host);
10717
- let globalConfig = null;
10718
- let globalConfigError = null;
10719
- try {
10720
- globalConfig = loadJsonFile(globalConfigPath);
10721
- } catch (error) {
10722
- globalConfigError = error instanceof Error ? error : new Error(String(error));
10723
- }
10724
- const projectConfig = loadJsonFile(projectConfigPath);
10725
- const normalizedProjectConfig = loadProjectConfigLayer(projectRoot, host);
10726
- if (globalConfigError) {
10727
- if (!projectConfig) {
10728
- throw globalConfigError;
10729
- }
10730
- globalConfig = null;
10731
- }
10732
- if (!globalConfig && !projectConfig) {
10733
- return {};
10734
- }
10735
- if (!projectConfig && globalConfig) {
10736
- return globalConfig;
10737
- }
10738
- if (!globalConfig && projectConfig) {
10739
- return normalizedProjectConfig;
10740
- }
10741
- if (!globalConfig || !projectConfig) {
10742
- return globalConfig ?? normalizedProjectConfig;
10743
- }
10744
- const merged = { ...globalConfig };
10745
- for (const key of PROJECT_OVERRIDE_KEYS) {
10746
- applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key);
10747
- }
10748
- if (projectConfig) {
10749
- for (const key of Object.keys(projectConfig)) {
10750
- if (PROJECT_OVERRIDE_KEYS.includes(key) || MERGE_ARRAY_KEYS.includes(key)) {
10751
- continue;
10752
- }
10753
- merged[key] = normalizedProjectConfig[key];
10754
- }
10755
- }
10756
- const globalKbs = globalConfig && Array.isArray(globalConfig.knowledgeBases) ? globalConfig.knowledgeBases : [];
10757
- const projectKbs = projectConfig ? Array.isArray(normalizedProjectConfig.knowledgeBases) ? normalizedProjectConfig.knowledgeBases : [] : [];
10758
- const allKbs = [...globalKbs, ...projectKbs];
10759
- merged.knowledgeBases = mergeKnowledgeBasePaths(allKbs);
10760
- const globalAdditional = globalConfig && Array.isArray(globalConfig.additionalInclude) ? globalConfig.additionalInclude : [];
10761
- const projectAdditional = projectConfig && Array.isArray(projectConfig.additionalInclude) ? projectConfig.additionalInclude : [];
10762
- const allAdditional = [...globalAdditional, ...projectAdditional];
10763
- merged.additionalInclude = mergeUniqueStringArray(allAdditional);
10764
- return merged;
10765
- }
10766
-
10767
- // src/tools/knowledge-base-paths.ts
10768
- var path15 = __toESM(require("path"), 1);
10769
- function resolveConfigPathValue(value, baseDir) {
10770
- const trimmed = value.trim();
10771
- if (!trimmed) {
10772
- return trimmed;
10773
- }
10774
- const absolutePath = path15.isAbsolute(trimmed) ? trimmed : path15.resolve(baseDir, trimmed);
10775
- return path15.normalize(absolutePath);
10776
- }
10777
-
10778
- // src/tools/utils.ts
10779
- var import_tiktoken = __toESM(require_tiktoken(), 1);
10780
- var MIN_CONTEXT_PACK_TOKEN_BUDGET = 128;
10781
- var MAX_CONTEXT_PACK_TOKEN_BUDGET = 4e3;
10782
- var DEFAULT_CONTEXT_PACK_TOKEN_BUDGET = 1200;
10783
- var CONTEXT_TOKENIZER = (0, import_tiktoken.get_encoding)("cl100k_base");
10784
- function clampContextPackTokenBudget(tokenBudget) {
10785
- if (tokenBudget === void 0 || !Number.isFinite(tokenBudget)) {
10786
- return DEFAULT_CONTEXT_PACK_TOKEN_BUDGET;
10367
+
10368
+ // src/tools/utils.ts
10369
+ var import_tiktoken = require("tiktoken");
10370
+ var MIN_CONTEXT_PACK_TOKEN_BUDGET = 128;
10371
+ var MAX_CONTEXT_PACK_TOKEN_BUDGET = 4e3;
10372
+ var DEFAULT_CONTEXT_PACK_TOKEN_BUDGET = 1200;
10373
+ var CONTEXT_TOKENIZER = (0, import_tiktoken.get_encoding)("cl100k_base");
10374
+ function clampContextPackTokenBudget(tokenBudget) {
10375
+ if (tokenBudget === void 0 || !Number.isFinite(tokenBudget)) {
10376
+ return DEFAULT_CONTEXT_PACK_TOKEN_BUDGET;
10787
10377
  }
10788
10378
  return Math.min(
10789
10379
  MAX_CONTEXT_PACK_TOKEN_BUDGET,
@@ -11184,6 +10774,208 @@ ${truncateContent(r.content)}
11184
10774
  // src/tools/config-state.ts
11185
10775
  var import_fs10 = require("fs");
11186
10776
  var path16 = __toESM(require("path"), 1);
10777
+
10778
+ // src/config/merger.ts
10779
+ var import_fs9 = require("fs");
10780
+ var path15 = __toESM(require("path"), 1);
10781
+
10782
+ // src/config/rebase.ts
10783
+ var path14 = __toESM(require("path"), 1);
10784
+ function isWithinRoot(rootDir, targetPath) {
10785
+ const relativePath = path14.relative(rootDir, targetPath);
10786
+ return relativePath === "" || !relativePath.startsWith("..") && !path14.isAbsolute(relativePath);
10787
+ }
10788
+ function rebasePathEntries(values, fromDir, toDir) {
10789
+ if (!Array.isArray(values)) {
10790
+ return [];
10791
+ }
10792
+ return values.filter((value) => typeof value === "string").map((value) => {
10793
+ const trimmed = value.trim();
10794
+ if (!trimmed || path14.isAbsolute(trimmed)) {
10795
+ return trimmed;
10796
+ }
10797
+ return normalizePathSeparators(path14.normalize(path14.relative(toDir, path14.resolve(fromDir, trimmed))));
10798
+ }).filter(Boolean);
10799
+ }
10800
+ function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
10801
+ if (!Array.isArray(values)) {
10802
+ return [];
10803
+ }
10804
+ return values.filter((value) => typeof value === "string").map((value) => {
10805
+ const trimmed = value.trim();
10806
+ if (!trimmed) {
10807
+ return trimmed;
10808
+ }
10809
+ if (path14.isAbsolute(trimmed)) {
10810
+ if (isWithinRoot(sourceRoot, trimmed)) {
10811
+ return normalizePathSeparators(path14.normalize(path14.relative(sourceRoot, trimmed) || "."));
10812
+ }
10813
+ return path14.normalize(trimmed);
10814
+ }
10815
+ const resolvedFromSource = path14.resolve(sourceRoot, trimmed);
10816
+ if (isWithinRoot(sourceRoot, resolvedFromSource)) {
10817
+ return normalizePathSeparators(path14.normalize(trimmed));
10818
+ }
10819
+ return normalizePathSeparators(path14.normalize(path14.relative(targetRoot, resolvedFromSource)));
10820
+ }).filter(Boolean);
10821
+ }
10822
+
10823
+ // src/config/merger.ts
10824
+ var PROJECT_OVERRIDE_KEYS = [
10825
+ "embeddingProvider",
10826
+ "customProvider",
10827
+ "embeddingModel",
10828
+ "reranker",
10829
+ "include",
10830
+ "exclude",
10831
+ "indexing",
10832
+ "search",
10833
+ "debug",
10834
+ "scope"
10835
+ ];
10836
+ var MERGE_ARRAY_KEYS = ["knowledgeBases", "additionalInclude"];
10837
+ function isRecord(value) {
10838
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10839
+ }
10840
+ function isStringArray2(value) {
10841
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
10842
+ }
10843
+ function applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key) {
10844
+ if (key in normalizedProjectConfig) {
10845
+ merged[key] = normalizedProjectConfig[key];
10846
+ return;
10847
+ }
10848
+ if (key in globalConfig) {
10849
+ merged[key] = globalConfig[key];
10850
+ }
10851
+ }
10852
+ function mergeUniqueStringArray(values) {
10853
+ return [...new Set(values.map((value) => String(value).trim()))];
10854
+ }
10855
+ function normalizeKnowledgeBasePath(value) {
10856
+ let normalized = path15.normalize(String(value).trim());
10857
+ const root = path15.parse(normalized).root;
10858
+ while (normalized.length > root.length && /[\\/]$/.test(normalized)) {
10859
+ normalized = normalized.slice(0, -1);
10860
+ }
10861
+ return normalized;
10862
+ }
10863
+ function mergeKnowledgeBasePaths(values) {
10864
+ return [...new Set(values.map((value) => normalizeKnowledgeBasePath(value)).filter((value) => value.length > 0))];
10865
+ }
10866
+ function validateConfigLayerShape(rawConfig, filePath) {
10867
+ if (!isRecord(rawConfig)) {
10868
+ throw new Error(`Config file ${filePath} must contain a JSON object at the root.`);
10869
+ }
10870
+ if (rawConfig.knowledgeBases !== void 0 && !isStringArray2(rawConfig.knowledgeBases)) {
10871
+ throw new Error(`Config file ${filePath} field 'knowledgeBases' must be an array of strings.`);
10872
+ }
10873
+ if (rawConfig.additionalInclude !== void 0 && !isStringArray2(rawConfig.additionalInclude)) {
10874
+ throw new Error(`Config file ${filePath} field 'additionalInclude' must be an array of strings.`);
10875
+ }
10876
+ if (rawConfig.include !== void 0 && !isStringArray2(rawConfig.include)) {
10877
+ throw new Error(`Config file ${filePath} field 'include' must be an array of strings.`);
10878
+ }
10879
+ if (rawConfig.exclude !== void 0 && !isStringArray2(rawConfig.exclude)) {
10880
+ throw new Error(`Config file ${filePath} field 'exclude' must be an array of strings.`);
10881
+ }
10882
+ for (const section of ["customProvider", "indexing", "search", "debug", "reranker"]) {
10883
+ const value = rawConfig[section];
10884
+ if (value !== void 0 && !isRecord(value)) {
10885
+ throw new Error(`Config file ${filePath} field '${section}' must be an object.`);
10886
+ }
10887
+ }
10888
+ return rawConfig;
10889
+ }
10890
+ function loadJsonFile(filePath) {
10891
+ if (!(0, import_fs9.existsSync)(filePath)) {
10892
+ return null;
10893
+ }
10894
+ try {
10895
+ const content = (0, import_fs9.readFileSync)(filePath, "utf-8");
10896
+ return validateConfigLayerShape(JSON.parse(content), filePath);
10897
+ } catch (error) {
10898
+ if (error instanceof Error && error.message.startsWith("Config file ")) {
10899
+ throw error;
10900
+ }
10901
+ const message = error instanceof Error ? error.message : String(error);
10902
+ throw new Error(`Failed to load config file ${filePath}: ${message}`);
10903
+ }
10904
+ }
10905
+ function loadConfigFile(filePath) {
10906
+ return loadJsonFile(filePath);
10907
+ }
10908
+ function loadProjectConfigLayer(projectRoot, host = "opencode") {
10909
+ const projectConfigPath = resolveProjectConfigPath(projectRoot, host);
10910
+ const projectConfig = loadJsonFile(projectConfigPath);
10911
+ if (!projectConfig) {
10912
+ return {};
10913
+ }
10914
+ const normalizedConfig = { ...projectConfig };
10915
+ const projectConfigBaseDir = path15.dirname(path15.dirname(projectConfigPath));
10916
+ if (Array.isArray(normalizedConfig.knowledgeBases)) {
10917
+ normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
10918
+ normalizedConfig.knowledgeBases,
10919
+ projectConfigBaseDir,
10920
+ projectRoot
10921
+ );
10922
+ }
10923
+ return normalizedConfig;
10924
+ }
10925
+ function loadMergedConfig(projectRoot, host = "opencode") {
10926
+ const globalConfigPath = resolveGlobalConfigPath(host);
10927
+ const projectConfigPath = resolveProjectConfigPath(projectRoot, host);
10928
+ let globalConfig = null;
10929
+ let globalConfigError = null;
10930
+ try {
10931
+ globalConfig = loadJsonFile(globalConfigPath);
10932
+ } catch (error) {
10933
+ globalConfigError = error instanceof Error ? error : new Error(String(error));
10934
+ }
10935
+ const projectConfig = loadJsonFile(projectConfigPath);
10936
+ const normalizedProjectConfig = loadProjectConfigLayer(projectRoot, host);
10937
+ if (globalConfigError) {
10938
+ if (!projectConfig) {
10939
+ throw globalConfigError;
10940
+ }
10941
+ globalConfig = null;
10942
+ }
10943
+ if (!globalConfig && !projectConfig) {
10944
+ return {};
10945
+ }
10946
+ if (!projectConfig && globalConfig) {
10947
+ return globalConfig;
10948
+ }
10949
+ if (!globalConfig && projectConfig) {
10950
+ return normalizedProjectConfig;
10951
+ }
10952
+ if (!globalConfig || !projectConfig) {
10953
+ return globalConfig ?? normalizedProjectConfig;
10954
+ }
10955
+ const merged = { ...globalConfig };
10956
+ for (const key of PROJECT_OVERRIDE_KEYS) {
10957
+ applyProjectOverride(merged, normalizedProjectConfig, globalConfig, key);
10958
+ }
10959
+ if (projectConfig) {
10960
+ for (const key of Object.keys(projectConfig)) {
10961
+ if (PROJECT_OVERRIDE_KEYS.includes(key) || MERGE_ARRAY_KEYS.includes(key)) {
10962
+ continue;
10963
+ }
10964
+ merged[key] = normalizedProjectConfig[key];
10965
+ }
10966
+ }
10967
+ const globalKbs = globalConfig && Array.isArray(globalConfig.knowledgeBases) ? globalConfig.knowledgeBases : [];
10968
+ const projectKbs = projectConfig ? Array.isArray(normalizedProjectConfig.knowledgeBases) ? normalizedProjectConfig.knowledgeBases : [] : [];
10969
+ const allKbs = [...globalKbs, ...projectKbs];
10970
+ merged.knowledgeBases = mergeKnowledgeBasePaths(allKbs);
10971
+ const globalAdditional = globalConfig && Array.isArray(globalConfig.additionalInclude) ? globalConfig.additionalInclude : [];
10972
+ const projectAdditional = projectConfig && Array.isArray(projectConfig.additionalInclude) ? projectConfig.additionalInclude : [];
10973
+ const allAdditional = [...globalAdditional, ...projectAdditional];
10974
+ merged.additionalInclude = mergeUniqueStringArray(allAdditional);
10975
+ return merged;
10976
+ }
10977
+
10978
+ // src/tools/config-state.ts
11187
10979
  function normalizeKnowledgeBasePaths(config, projectRoot) {
11188
10980
  const normalized = { ...config };
11189
10981
  if (Array.isArray(normalized.knowledgeBases)) {
@@ -11267,15 +11059,6 @@ function refreshIndexerForDirectory(projectRoot, host = "opencode", config = par
11267
11059
  indexerCache.set(key, indexer);
11268
11060
  configCache.set(key, config);
11269
11061
  }
11270
- function shouldForceLocalizeProjectIndex(projectRoot, host = "opencode") {
11271
- const root = getProjectRoot(projectRoot, host);
11272
- const localIndexPath = path17.join(root, getHostProjectIndexRelativePath(host));
11273
- if ((0, import_fs11.existsSync)(localIndexPath)) {
11274
- return false;
11275
- }
11276
- const inheritedIndexPath = resolveWorktreeFallbackProjectIndexPath(root, host);
11277
- return inheritedIndexPath !== null;
11278
- }
11279
11062
  async function searchCodebase(projectRoot, host, query, options = {}) {
11280
11063
  const indexer = getIndexerForProject(projectRoot, host);
11281
11064
  return indexer.search(query, options.limit, {
@@ -11325,9 +11108,7 @@ async function getCallGraphPath(projectRoot, host, from, to, maxDepth) {
11325
11108
  }
11326
11109
  async function runIndexCodebase(projectRoot, host, args, onProgress) {
11327
11110
  const root = getProjectRoot(projectRoot, host);
11328
- const key = getIndexerCacheKey(root, host);
11329
- let indexer = getIndexerForProject(root, host);
11330
- const runtimeConfig = configCache.get(key);
11111
+ const indexer = getIndexerForProject(root, host);
11331
11112
  try {
11332
11113
  if (args.estimateOnly) {
11333
11114
  return { kind: "estimate", estimate: await indexer.estimateCost() };
@@ -11348,19 +11129,7 @@ async function runIndexCodebase(projectRoot, host, args, onProgress) {
11348
11129
  return Promise.resolve();
11349
11130
  });
11350
11131
  };
11351
- let stats;
11352
- if (args.force && shouldForceLocalizeProjectIndex(root, host)) {
11353
- const inheritedIndexPath = resolveProjectIndexPath(root, runtimeConfig.scope, host);
11354
- stats = await withIndexLock(inheritedIndexPath, "force-index", async () => {
11355
- materializeLocalProjectConfig(root, loadProjectConfigLayer(root, host), host);
11356
- refreshIndexerForDirectory(root, host, runtimeConfig);
11357
- indexer = getIndexerForProject(root, host);
11358
- return runIndex(indexer);
11359
- }, { completeRecoveries: false });
11360
- } else {
11361
- stats = await runIndex(indexer);
11362
- }
11363
- return { kind: "stats", stats };
11132
+ return { kind: "stats", stats: await runIndex(indexer) };
11364
11133
  } catch (error) {
11365
11134
  const busyResult = getIndexBusyResult(error);
11366
11135
  if (!busyResult) throw error;