opencode-codebase-index 0.17.1 → 0.18.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +45 -8
- package/THIRD_PARTY_LICENSES.md +64 -0
- package/dist/cli.cjs +576 -346
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +582 -352
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +427 -198
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +440 -211
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +735 -505
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +697 -467
- package/dist/pi-extension.js.map +1 -1
- package/native/codebase-index-native.darwin-arm64.node +0 -0
- package/native/codebase-index-native.darwin-x64.node +0 -0
- package/native/codebase-index-native.linux-arm64-gnu.node +0 -0
- package/native/codebase-index-native.linux-x64-gnu.node +0 -0
- package/native/codebase-index-native.win32-x64-msvc.node +0 -0
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -680,7 +680,8 @@ var DEFAULT_INCLUDE = [
|
|
|
680
680
|
"**/*.{sh,bash,zsh}",
|
|
681
681
|
"**/*.{txt,html,htm}",
|
|
682
682
|
"**/*.zig",
|
|
683
|
-
"**/*.gd"
|
|
683
|
+
"**/*.gd",
|
|
684
|
+
"**/*.metal"
|
|
684
685
|
];
|
|
685
686
|
var DEFAULT_EXCLUDE = [
|
|
686
687
|
"**/node_modules/**",
|
|
@@ -871,6 +872,9 @@ function isValidProvider(value) {
|
|
|
871
872
|
return typeof value === "string" && Object.keys(EMBEDDING_MODELS).includes(value);
|
|
872
873
|
}
|
|
873
874
|
function isValidModel(value, provider) {
|
|
875
|
+
if (typeof value === "string" && provider === "ollama" && value.trim().length > 0) {
|
|
876
|
+
return true;
|
|
877
|
+
}
|
|
874
878
|
return typeof value === "string" && Object.keys(EMBEDDING_MODELS[provider]).includes(value);
|
|
875
879
|
}
|
|
876
880
|
function isValidScope(value) {
|
|
@@ -1235,16 +1239,6 @@ function resolveWorktreeFallbackPath(projectRoot, relativePath) {
|
|
|
1235
1239
|
const fallbackPath = path3.join(mainRepoRoot, relativePath);
|
|
1236
1240
|
return (0, import_fs3.existsSync)(fallbackPath) ? fallbackPath : null;
|
|
1237
1241
|
}
|
|
1238
|
-
function resolveWorktreeFallbackProjectIndexPath(projectRoot, host) {
|
|
1239
|
-
const inheritedHostPath = resolveWorktreeFallbackPath(projectRoot, getProjectIndexRelativePath(host));
|
|
1240
|
-
if (inheritedHostPath) {
|
|
1241
|
-
return inheritedHostPath;
|
|
1242
|
-
}
|
|
1243
|
-
if (host !== "opencode") {
|
|
1244
|
-
return resolveWorktreeFallbackPath(projectRoot, OPENCODE_PROJECT_INDEX_RELATIVE_PATH);
|
|
1245
|
-
}
|
|
1246
|
-
return null;
|
|
1247
|
-
}
|
|
1248
1242
|
function getHostProjectConfigRelativePath(host) {
|
|
1249
1243
|
return getProjectConfigRelativePath(host);
|
|
1250
1244
|
}
|
|
@@ -1349,6 +1343,9 @@ function resolveProjectIndexPath(projectRoot, scope, host = "opencode") {
|
|
|
1349
1343
|
if (hasHostProjectConfig(projectRoot, host)) {
|
|
1350
1344
|
return localIndexPath;
|
|
1351
1345
|
}
|
|
1346
|
+
if (resolveWorktreeMainRepoRoot(projectRoot)) {
|
|
1347
|
+
return localIndexPath;
|
|
1348
|
+
}
|
|
1352
1349
|
const hostFallback = resolveWorktreeFallbackPath(projectRoot, getProjectIndexRelativePath(host));
|
|
1353
1350
|
if (hostFallback) {
|
|
1354
1351
|
return hostFallback;
|
|
@@ -1521,12 +1518,6 @@ function loadJsonFile(filePath) {
|
|
|
1521
1518
|
function loadConfigFile(filePath) {
|
|
1522
1519
|
return loadJsonFile(filePath);
|
|
1523
1520
|
}
|
|
1524
|
-
function materializeLocalProjectConfig(projectRoot, config, host = "opencode") {
|
|
1525
|
-
const localConfigPath = resolveWritableProjectConfigPath(projectRoot, host);
|
|
1526
|
-
(0, import_fs4.mkdirSync)(path6.dirname(localConfigPath), { recursive: true });
|
|
1527
|
-
(0, import_fs4.writeFileSync)(localConfigPath, JSON.stringify(config, null, 2), "utf-8");
|
|
1528
|
-
return localConfigPath;
|
|
1529
|
-
}
|
|
1530
1521
|
function loadProjectConfigLayer(projectRoot, host = "opencode") {
|
|
1531
1522
|
const projectConfigPath = resolveProjectConfigPath(projectRoot, host);
|
|
1532
1523
|
const projectConfig = loadJsonFile(projectConfigPath);
|
|
@@ -1955,40 +1946,6 @@ function releaseIndexLock(lease) {
|
|
|
1955
1946
|
}
|
|
1956
1947
|
return true;
|
|
1957
1948
|
}
|
|
1958
|
-
async function withIndexLock(indexPath, operation, callback, options = {}) {
|
|
1959
|
-
const lease = acquireIndexLock(indexPath, operation);
|
|
1960
|
-
let result;
|
|
1961
|
-
let callbackError;
|
|
1962
|
-
let callbackFailed = false;
|
|
1963
|
-
try {
|
|
1964
|
-
result = await callback(lease);
|
|
1965
|
-
} catch (error) {
|
|
1966
|
-
callbackFailed = true;
|
|
1967
|
-
callbackError = error;
|
|
1968
|
-
}
|
|
1969
|
-
if (!callbackFailed && options.completeRecoveries !== false) {
|
|
1970
|
-
try {
|
|
1971
|
-
completeLeaseRecovery(lease);
|
|
1972
|
-
} catch (error) {
|
|
1973
|
-
callbackFailed = true;
|
|
1974
|
-
callbackError = error;
|
|
1975
|
-
}
|
|
1976
|
-
}
|
|
1977
|
-
let releaseError;
|
|
1978
|
-
try {
|
|
1979
|
-
if (!releaseIndexLock(lease)) {
|
|
1980
|
-
releaseError = new Error(`Lost ownership of index mutation lease ${lease.owner.token}`);
|
|
1981
|
-
}
|
|
1982
|
-
} catch (error) {
|
|
1983
|
-
releaseError = error;
|
|
1984
|
-
}
|
|
1985
|
-
if (releaseError !== void 0) {
|
|
1986
|
-
if (callbackFailed) throw new AggregateError([callbackError, releaseError], "Index mutation and lease release both failed");
|
|
1987
|
-
throw releaseError;
|
|
1988
|
-
}
|
|
1989
|
-
if (callbackFailed) throw callbackError;
|
|
1990
|
-
return result;
|
|
1991
|
-
}
|
|
1992
1949
|
function createLeaseTemporaryPath(targetPath, owner, kind = "tmp") {
|
|
1993
1950
|
if (kind === "bak") return `${targetPath}.bak.${owner.pid}.${owner.token}`;
|
|
1994
1951
|
temporaryCounter += 1;
|
|
@@ -3095,6 +3052,9 @@ function loadOpenCodeAuth() {
|
|
|
3095
3052
|
return {};
|
|
3096
3053
|
}
|
|
3097
3054
|
async function detectEmbeddingProvider(preferredProvider, model) {
|
|
3055
|
+
if (preferredProvider === "ollama") {
|
|
3056
|
+
return detectOllamaProvider(model);
|
|
3057
|
+
}
|
|
3098
3058
|
const credentials = await getProviderCredentials(preferredProvider);
|
|
3099
3059
|
if (credentials) {
|
|
3100
3060
|
if (!model) {
|
|
@@ -3110,10 +3070,16 @@ async function detectEmbeddingProvider(preferredProvider, model) {
|
|
|
3110
3070
|
);
|
|
3111
3071
|
}
|
|
3112
3072
|
const providerModels = EMBEDDING_MODELS[preferredProvider];
|
|
3073
|
+
const modelInfo = Object.values(providerModels).find((candidate) => candidate.model === model);
|
|
3074
|
+
if (!modelInfo) {
|
|
3075
|
+
throw new Error(
|
|
3076
|
+
`Model '${model}' is not supported by provider '${preferredProvider}'`
|
|
3077
|
+
);
|
|
3078
|
+
}
|
|
3113
3079
|
return {
|
|
3114
3080
|
provider: preferredProvider,
|
|
3115
3081
|
credentials,
|
|
3116
|
-
modelInfo
|
|
3082
|
+
modelInfo
|
|
3117
3083
|
};
|
|
3118
3084
|
}
|
|
3119
3085
|
throw new Error(
|
|
@@ -3122,6 +3088,13 @@ async function detectEmbeddingProvider(preferredProvider, model) {
|
|
|
3122
3088
|
}
|
|
3123
3089
|
async function tryDetectProvider() {
|
|
3124
3090
|
for (const provider of autoDetectProviders) {
|
|
3091
|
+
if (provider === "ollama") {
|
|
3092
|
+
const ollamaProvider = await tryDetectOllamaProvider();
|
|
3093
|
+
if (ollamaProvider) {
|
|
3094
|
+
return ollamaProvider;
|
|
3095
|
+
}
|
|
3096
|
+
continue;
|
|
3097
|
+
}
|
|
3125
3098
|
const credentials = await getProviderCredentials(provider);
|
|
3126
3099
|
if (credentials) {
|
|
3127
3100
|
return {
|
|
@@ -3189,32 +3162,105 @@ function getGoogleCredentials() {
|
|
|
3189
3162
|
}
|
|
3190
3163
|
return null;
|
|
3191
3164
|
}
|
|
3192
|
-
async function
|
|
3193
|
-
const
|
|
3165
|
+
async function fetchOllama(url, init) {
|
|
3166
|
+
const controller = new AbortController();
|
|
3167
|
+
const timeoutId = setTimeout(() => controller.abort(), 2e3);
|
|
3194
3168
|
try {
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
const response = await fetch(`${baseUrl}/api/tags`, {
|
|
3198
|
-
signal: controller.signal
|
|
3199
|
-
});
|
|
3169
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
3170
|
+
} finally {
|
|
3200
3171
|
clearTimeout(timeoutId);
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
async function getOllamaCredentials() {
|
|
3175
|
+
const baseUrl = (process.env.OLLAMA_HOST || "http://localhost:11434").replace(/\/+$/, "");
|
|
3176
|
+
try {
|
|
3177
|
+
const response = await fetchOllama(`${baseUrl}/api/tags`);
|
|
3201
3178
|
if (response.ok) {
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
if (hasEmbeddingModel) {
|
|
3207
|
-
return {
|
|
3208
|
-
provider: "ollama",
|
|
3209
|
-
baseUrl
|
|
3210
|
-
};
|
|
3211
|
-
}
|
|
3179
|
+
return {
|
|
3180
|
+
provider: "ollama",
|
|
3181
|
+
baseUrl
|
|
3182
|
+
};
|
|
3212
3183
|
}
|
|
3213
3184
|
} catch {
|
|
3214
3185
|
return null;
|
|
3215
3186
|
}
|
|
3216
3187
|
return null;
|
|
3217
3188
|
}
|
|
3189
|
+
function findCatalogOllamaModel(model) {
|
|
3190
|
+
const stableName = model.endsWith(":latest") ? model.slice(0, -":latest".length) : model;
|
|
3191
|
+
return Object.values(EMBEDDING_MODELS.ollama).find((candidate) => candidate.model === stableName) ?? null;
|
|
3192
|
+
}
|
|
3193
|
+
function getPositiveIntegerMetadata(modelInfo, suffix) {
|
|
3194
|
+
const values = Object.entries(modelInfo).filter(([key]) => key.endsWith(suffix)).map(([, value]) => value).filter((value) => typeof value === "number" && Number.isInteger(value) && value > 0);
|
|
3195
|
+
return values.length === 1 ? values[0] : null;
|
|
3196
|
+
}
|
|
3197
|
+
async function fetchOllamaModelInfo(credentials, model) {
|
|
3198
|
+
const response = await fetchOllama(`${credentials.baseUrl}/api/show`, {
|
|
3199
|
+
method: "POST",
|
|
3200
|
+
headers: { "Content-Type": "application/json" },
|
|
3201
|
+
body: JSON.stringify({ model })
|
|
3202
|
+
});
|
|
3203
|
+
if (!response.ok) {
|
|
3204
|
+
return null;
|
|
3205
|
+
}
|
|
3206
|
+
const data = await response.json();
|
|
3207
|
+
if (!data.capabilities?.includes("embedding") || !data.model_info) {
|
|
3208
|
+
return null;
|
|
3209
|
+
}
|
|
3210
|
+
const dimensions = getPositiveIntegerMetadata(data.model_info, ".embedding_length");
|
|
3211
|
+
const maxTokens = getPositiveIntegerMetadata(data.model_info, ".context_length");
|
|
3212
|
+
if (!dimensions || !maxTokens) {
|
|
3213
|
+
return null;
|
|
3214
|
+
}
|
|
3215
|
+
return {
|
|
3216
|
+
provider: "ollama",
|
|
3217
|
+
model,
|
|
3218
|
+
dimensions,
|
|
3219
|
+
maxTokens,
|
|
3220
|
+
costPer1MTokens: 0
|
|
3221
|
+
};
|
|
3222
|
+
}
|
|
3223
|
+
async function listOllamaModels(credentials) {
|
|
3224
|
+
const response = await fetchOllama(`${credentials.baseUrl}/api/tags`);
|
|
3225
|
+
if (!response.ok) {
|
|
3226
|
+
return [];
|
|
3227
|
+
}
|
|
3228
|
+
const data = await response.json();
|
|
3229
|
+
return [...new Set((data.models ?? []).map((entry) => entry.name ?? entry.model).filter((name) => typeof name === "string" && name.trim().length > 0))];
|
|
3230
|
+
}
|
|
3231
|
+
async function detectOllamaProvider(model) {
|
|
3232
|
+
const credentials = await getOllamaCredentials();
|
|
3233
|
+
if (!credentials) {
|
|
3234
|
+
throw new Error("Preferred provider 'ollama' is not configured or authenticated");
|
|
3235
|
+
}
|
|
3236
|
+
const requestedModel = model?.trim();
|
|
3237
|
+
if (requestedModel) {
|
|
3238
|
+
const catalogModel = findCatalogOllamaModel(requestedModel);
|
|
3239
|
+
if (catalogModel) {
|
|
3240
|
+
return { provider: "ollama", credentials, modelInfo: catalogModel };
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
const candidates = requestedModel ? [requestedModel] : await listOllamaModels(credentials);
|
|
3244
|
+
for (const candidate of candidates) {
|
|
3245
|
+
const modelInfo = await fetchOllamaModelInfo(credentials, candidate);
|
|
3246
|
+
if (modelInfo) {
|
|
3247
|
+
return {
|
|
3248
|
+
provider: "ollama",
|
|
3249
|
+
credentials,
|
|
3250
|
+
modelInfo: findCatalogOllamaModel(candidate) ?? modelInfo
|
|
3251
|
+
};
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
const detail = model ? `Model '${model}' is not installed or is not embedding-capable` : "No installed embedding-capable Ollama model was found";
|
|
3255
|
+
throw new Error(detail);
|
|
3256
|
+
}
|
|
3257
|
+
async function tryDetectOllamaProvider() {
|
|
3258
|
+
try {
|
|
3259
|
+
return await detectOllamaProvider();
|
|
3260
|
+
} catch {
|
|
3261
|
+
return null;
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3218
3264
|
function getProviderDisplayName(provider) {
|
|
3219
3265
|
switch (provider) {
|
|
3220
3266
|
case "github-copilot":
|
|
@@ -3554,6 +3600,7 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddi
|
|
|
3554
3600
|
// src/embeddings/providers/ollama.ts
|
|
3555
3601
|
var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddingProvider {
|
|
3556
3602
|
static MIN_TRUNCATION_CHARS = 512;
|
|
3603
|
+
static REQUEST_TIMEOUT_MS = 12e4;
|
|
3557
3604
|
constructor(credentials, modelInfo) {
|
|
3558
3605
|
super(credentials, modelInfo);
|
|
3559
3606
|
}
|
|
@@ -3628,22 +3675,45 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
3628
3675
|
}
|
|
3629
3676
|
}
|
|
3630
3677
|
async embedSingle(text) {
|
|
3631
|
-
const
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3678
|
+
const controller = new AbortController();
|
|
3679
|
+
const timeout = setTimeout(
|
|
3680
|
+
() => controller.abort(),
|
|
3681
|
+
_OllamaEmbeddingProvider.REQUEST_TIMEOUT_MS
|
|
3682
|
+
);
|
|
3683
|
+
let response;
|
|
3684
|
+
try {
|
|
3685
|
+
response = await fetch(`${this.credentials.baseUrl}/api/embeddings`, {
|
|
3686
|
+
method: "POST",
|
|
3687
|
+
headers: {
|
|
3688
|
+
"Content-Type": "application/json"
|
|
3689
|
+
},
|
|
3690
|
+
body: JSON.stringify({
|
|
3691
|
+
model: this.modelInfo.model,
|
|
3692
|
+
prompt: text,
|
|
3693
|
+
truncate: false
|
|
3694
|
+
}),
|
|
3695
|
+
signal: controller.signal
|
|
3696
|
+
});
|
|
3697
|
+
} catch (error) {
|
|
3698
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3699
|
+
throw new Error(
|
|
3700
|
+
`Ollama embedding request timed out after ${_OllamaEmbeddingProvider.REQUEST_TIMEOUT_MS}ms`
|
|
3701
|
+
);
|
|
3702
|
+
}
|
|
3703
|
+
throw error;
|
|
3704
|
+
} finally {
|
|
3705
|
+
clearTimeout(timeout);
|
|
3706
|
+
}
|
|
3642
3707
|
if (!response.ok) {
|
|
3643
3708
|
const error = (await response.text()).slice(0, 500);
|
|
3644
3709
|
throw new Error(`Ollama embedding API error: ${response.status} - ${error}`);
|
|
3645
3710
|
}
|
|
3646
3711
|
const data = await response.json();
|
|
3712
|
+
if (!Array.isArray(data.embedding) || data.embedding.length !== this.modelInfo.dimensions || data.embedding.some((value) => typeof value !== "number" || !Number.isFinite(value))) {
|
|
3713
|
+
throw new Error(
|
|
3714
|
+
`Ollama returned an invalid embedding; expected ${this.modelInfo.dimensions} finite dimensions`
|
|
3715
|
+
);
|
|
3716
|
+
}
|
|
3647
3717
|
return {
|
|
3648
3718
|
embedding: data.embedding,
|
|
3649
3719
|
tokensUsed: this.estimateTokens(text)
|
|
@@ -4507,7 +4577,9 @@ function mapChunk(c) {
|
|
|
4507
4577
|
return {
|
|
4508
4578
|
content: c.content,
|
|
4509
4579
|
startLine: c.startLine ?? c.start_line,
|
|
4580
|
+
startCol: c.startCol ?? c.start_col,
|
|
4510
4581
|
endLine: c.endLine ?? c.end_line,
|
|
4582
|
+
endCol: c.endCol ?? c.end_col,
|
|
4511
4583
|
chunkType: c.chunkType ?? c.chunk_type,
|
|
4512
4584
|
name: c.name ?? void 0,
|
|
4513
4585
|
language: c.language
|
|
@@ -4628,6 +4700,7 @@ function getEmbeddingHeaderParts(chunk, filePath) {
|
|
|
4628
4700
|
javascript: "JavaScript",
|
|
4629
4701
|
python: "Python",
|
|
4630
4702
|
rust: "Rust",
|
|
4703
|
+
swift: "Swift",
|
|
4631
4704
|
go: "Go",
|
|
4632
4705
|
java: "Java"
|
|
4633
4706
|
};
|
|
@@ -4636,7 +4709,16 @@ function getEmbeddingHeaderParts(chunk, filePath) {
|
|
|
4636
4709
|
function: "function",
|
|
4637
4710
|
arrow_function: "arrow function",
|
|
4638
4711
|
method_definition: "method",
|
|
4712
|
+
method_declaration: "method",
|
|
4713
|
+
protocol_function_declaration: "protocol requirement",
|
|
4714
|
+
init_declaration: "initializer",
|
|
4715
|
+
deinit_declaration: "deinitializer",
|
|
4716
|
+
subscript_declaration: "subscript",
|
|
4639
4717
|
class_declaration: "class",
|
|
4718
|
+
actor_declaration: "actor",
|
|
4719
|
+
extension_declaration: "extension",
|
|
4720
|
+
protocol_declaration: "protocol",
|
|
4721
|
+
struct_declaration: "struct",
|
|
4640
4722
|
interface_declaration: "interface",
|
|
4641
4723
|
type_alias_declaration: "type alias",
|
|
4642
4724
|
enum_declaration: "enum",
|
|
@@ -5307,8 +5389,18 @@ async function getChunkGitBlame(projectRoot, filePath, startLine, endLine) {
|
|
|
5307
5389
|
}
|
|
5308
5390
|
|
|
5309
5391
|
// src/indexer/index.ts
|
|
5310
|
-
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab", "bash"]);
|
|
5311
|
-
var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex"]);
|
|
5392
|
+
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "swift", "php", "apex", "zig", "gdscript", "matlab", "bash", "c", "cpp", "metal"]);
|
|
5393
|
+
var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex", "php"]);
|
|
5394
|
+
var CALL_GRAPH_RESOLUTION_VERSION = "4";
|
|
5395
|
+
var PHP_FUNCTION_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5396
|
+
"function_declaration",
|
|
5397
|
+
"function",
|
|
5398
|
+
"function_definition"
|
|
5399
|
+
]);
|
|
5400
|
+
var PHP_CLASS_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5401
|
+
"class_declaration",
|
|
5402
|
+
"class_definition"
|
|
5403
|
+
]);
|
|
5312
5404
|
var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5313
5405
|
"function_declaration",
|
|
5314
5406
|
"function",
|
|
@@ -5321,6 +5413,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
5321
5413
|
"enum_declaration",
|
|
5322
5414
|
"function_definition",
|
|
5323
5415
|
"class_definition",
|
|
5416
|
+
"class_specifier",
|
|
5417
|
+
"struct_specifier",
|
|
5418
|
+
"namespace_definition",
|
|
5324
5419
|
"decorated_definition",
|
|
5325
5420
|
"method_declaration",
|
|
5326
5421
|
"type_declaration",
|
|
@@ -5336,6 +5431,14 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
5336
5431
|
"test_declaration",
|
|
5337
5432
|
"struct_declaration",
|
|
5338
5433
|
"union_declaration",
|
|
5434
|
+
// Synthetic Swift declarations or declarations specific to tree-sitter-swift.
|
|
5435
|
+
"actor_declaration",
|
|
5436
|
+
"extension_declaration",
|
|
5437
|
+
"protocol_declaration",
|
|
5438
|
+
"protocol_function_declaration",
|
|
5439
|
+
"init_declaration",
|
|
5440
|
+
"deinit_declaration",
|
|
5441
|
+
"subscript_declaration",
|
|
5339
5442
|
// GDScript declarations whose names participate in the call graph.
|
|
5340
5443
|
// `function_definition` and `class_definition` are already in the set
|
|
5341
5444
|
// above (shared with Python/C/Bash and Python, respectively).
|
|
@@ -5345,6 +5448,53 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
5345
5448
|
"const_statement",
|
|
5346
5449
|
"class_name_statement"
|
|
5347
5450
|
]);
|
|
5451
|
+
var C_FAMILY_TYPE_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set(["class_specifier", "struct_specifier"]);
|
|
5452
|
+
function isCompatibleCFamilyCallTarget(language, callType, symbolKind) {
|
|
5453
|
+
if (language !== "c" && language !== "cpp") return true;
|
|
5454
|
+
if (symbolKind === "namespace_definition") return callType === "Import";
|
|
5455
|
+
const isTypeSymbol = C_FAMILY_TYPE_SYMBOL_CHUNK_TYPES.has(symbolKind);
|
|
5456
|
+
if (callType === "Constructor" || callType === "Inherits" || callType === "Implements") {
|
|
5457
|
+
return isTypeSymbol;
|
|
5458
|
+
}
|
|
5459
|
+
return !isTypeSymbol;
|
|
5460
|
+
}
|
|
5461
|
+
var EXECUTABLE_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
5462
|
+
"function_declaration",
|
|
5463
|
+
"function",
|
|
5464
|
+
"arrow_function",
|
|
5465
|
+
"method_definition",
|
|
5466
|
+
"function_definition",
|
|
5467
|
+
"method_declaration",
|
|
5468
|
+
"function_item",
|
|
5469
|
+
"protocol_function_declaration",
|
|
5470
|
+
"init_declaration",
|
|
5471
|
+
"deinit_declaration",
|
|
5472
|
+
"subscript_declaration",
|
|
5473
|
+
"constructor_definition",
|
|
5474
|
+
"trigger_declaration",
|
|
5475
|
+
"test_declaration"
|
|
5476
|
+
]);
|
|
5477
|
+
function findEnclosingSymbol(symbols, line, column) {
|
|
5478
|
+
let best;
|
|
5479
|
+
for (const symbol of symbols) {
|
|
5480
|
+
if (line < symbol.startLine || line > symbol.endLine) continue;
|
|
5481
|
+
if (column !== void 0 && (line === symbol.startLine && column < symbol.startCol || line === symbol.endLine && column >= symbol.endCol)) {
|
|
5482
|
+
continue;
|
|
5483
|
+
}
|
|
5484
|
+
if (!best) {
|
|
5485
|
+
best = symbol;
|
|
5486
|
+
continue;
|
|
5487
|
+
}
|
|
5488
|
+
const span = symbol.endLine - symbol.startLine;
|
|
5489
|
+
const bestSpan = best.endLine - best.startLine;
|
|
5490
|
+
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);
|
|
5491
|
+
const isMoreSpecificTie = span === bestSpan && symbol.startLine === best.startLine && EXECUTABLE_SYMBOL_CHUNK_TYPES.has(symbol.kind) && !EXECUTABLE_SYMBOL_CHUNK_TYPES.has(best.kind);
|
|
5492
|
+
if (span < bestSpan || span === bestSpan && symbol.startLine > best.startLine || isNarrowerPositionRange || isMoreSpecificTie) {
|
|
5493
|
+
best = symbol;
|
|
5494
|
+
}
|
|
5495
|
+
}
|
|
5496
|
+
return best;
|
|
5497
|
+
}
|
|
5348
5498
|
function float32ArrayToBuffer(arr) {
|
|
5349
5499
|
const float32 = new Float32Array(arr);
|
|
5350
5500
|
return Buffer.from(float32.buffer);
|
|
@@ -5429,6 +5579,8 @@ function hasBlameMetadata(metadata) {
|
|
|
5429
5579
|
}
|
|
5430
5580
|
var INDEX_METADATA_VERSION = "1";
|
|
5431
5581
|
var EMBEDDING_STRATEGY_VERSION = "2";
|
|
5582
|
+
var SWIFT_PARSER_VERSION = "1";
|
|
5583
|
+
var METAL_PARSER_VERSION = "1";
|
|
5432
5584
|
var RANKING_TOKEN_CACHE_LIMIT = 4096;
|
|
5433
5585
|
var RANK_HYBRID_CACHE_LIMIT = 256;
|
|
5434
5586
|
function createPendingChunkStorageText(texts) {
|
|
@@ -5751,15 +5903,25 @@ function chunkTypeBoost(chunkType) {
|
|
|
5751
5903
|
case "function_declaration":
|
|
5752
5904
|
case "method":
|
|
5753
5905
|
case "method_definition":
|
|
5906
|
+
case "method_declaration":
|
|
5907
|
+
case "protocol_function_declaration":
|
|
5908
|
+
case "init_declaration":
|
|
5909
|
+
case "deinit_declaration":
|
|
5910
|
+
case "subscript_declaration":
|
|
5754
5911
|
case "class":
|
|
5755
5912
|
case "class_declaration":
|
|
5913
|
+
case "actor_declaration":
|
|
5914
|
+
case "extension_declaration":
|
|
5756
5915
|
return 0.2;
|
|
5757
5916
|
case "interface":
|
|
5758
5917
|
case "type":
|
|
5759
5918
|
case "enum":
|
|
5919
|
+
case "enum_declaration":
|
|
5760
5920
|
case "struct":
|
|
5921
|
+
case "struct_declaration":
|
|
5761
5922
|
case "impl":
|
|
5762
5923
|
case "trait":
|
|
5924
|
+
case "protocol_declaration":
|
|
5763
5925
|
case "module":
|
|
5764
5926
|
return 0.1;
|
|
5765
5927
|
default:
|
|
@@ -5866,11 +6028,21 @@ function isImplementationChunkType(chunkType) {
|
|
|
5866
6028
|
"function_declaration",
|
|
5867
6029
|
"method",
|
|
5868
6030
|
"method_definition",
|
|
6031
|
+
"method_declaration",
|
|
6032
|
+
"protocol_function_declaration",
|
|
6033
|
+
"init_declaration",
|
|
6034
|
+
"deinit_declaration",
|
|
6035
|
+
"subscript_declaration",
|
|
5869
6036
|
"class",
|
|
5870
6037
|
"class_declaration",
|
|
6038
|
+
"actor_declaration",
|
|
6039
|
+
"extension_declaration",
|
|
5871
6040
|
"interface",
|
|
6041
|
+
"protocol_declaration",
|
|
5872
6042
|
"type",
|
|
5873
6043
|
"enum",
|
|
6044
|
+
"enum_declaration",
|
|
6045
|
+
"struct_declaration",
|
|
5874
6046
|
"module"
|
|
5875
6047
|
].includes(chunkType);
|
|
5876
6048
|
}
|
|
@@ -6873,6 +7045,29 @@ var Indexer = class {
|
|
|
6873
7045
|
const projectHash = hashContent(path13.resolve(this.projectRoot)).slice(0, 16);
|
|
6874
7046
|
return `index.forceReembed.${projectHash}`;
|
|
6875
7047
|
}
|
|
7048
|
+
getCallGraphResolutionMetadataKey() {
|
|
7049
|
+
if (this.config.scope !== "global") {
|
|
7050
|
+
return "index.callGraphResolutionVersion";
|
|
7051
|
+
}
|
|
7052
|
+
const projectHash = hashContent(path13.resolve(this.projectRoot)).slice(0, 16);
|
|
7053
|
+
return `index.callGraphResolutionVersion.${projectHash}`;
|
|
7054
|
+
}
|
|
7055
|
+
getSwiftParserVersionMetadataKey() {
|
|
7056
|
+
const key = "index.parser.swiftVersion";
|
|
7057
|
+
if (this.config.scope !== "global") {
|
|
7058
|
+
return key;
|
|
7059
|
+
}
|
|
7060
|
+
const projectHash = hashContent(path13.resolve(this.projectRoot)).slice(0, 16);
|
|
7061
|
+
return `${key}.${projectHash}`;
|
|
7062
|
+
}
|
|
7063
|
+
getMetalParserVersionMetadataKey() {
|
|
7064
|
+
const key = "index.parser.metalVersion";
|
|
7065
|
+
if (this.config.scope !== "global") {
|
|
7066
|
+
return key;
|
|
7067
|
+
}
|
|
7068
|
+
const projectHash = hashContent(path13.resolve(this.projectRoot)).slice(0, 16);
|
|
7069
|
+
return `${key}.${projectHash}`;
|
|
7070
|
+
}
|
|
6876
7071
|
hasProjectForceReembedPending() {
|
|
6877
7072
|
return this.config.scope === "global" && this.database?.getMetadata(this.getProjectForceReembedMetadataKey()) === "true";
|
|
6878
7073
|
}
|
|
@@ -8033,6 +8228,7 @@ var Indexer = class {
|
|
|
8033
8228
|
this.database.setMetadata("index.embeddingProvider", provider.provider);
|
|
8034
8229
|
this.database.setMetadata("index.embeddingModel", provider.modelInfo.model);
|
|
8035
8230
|
this.database.setMetadata("index.embeddingDimensions", provider.modelInfo.dimensions.toString());
|
|
8231
|
+
this.database.setMetadata(this.getCallGraphResolutionMetadataKey(), CALL_GRAPH_RESOLUTION_VERSION);
|
|
8036
8232
|
if (this.config.scope === "global") {
|
|
8037
8233
|
if (completeProjectEmbeddingStrategyReset) {
|
|
8038
8234
|
this.database.setMetadata(this.getProjectEmbeddingStrategyMetadataKey(), EMBEDDING_STRATEGY_VERSION);
|
|
@@ -8220,6 +8416,20 @@ var Indexer = class {
|
|
|
8220
8416
|
totalChunks: 0
|
|
8221
8417
|
});
|
|
8222
8418
|
this.loadFileHashCache();
|
|
8419
|
+
const swiftParserMetadataKey = this.getSwiftParserVersionMetadataKey();
|
|
8420
|
+
const reparseCachedSwiftFiles = database.getMetadata(swiftParserMetadataKey) !== SWIFT_PARSER_VERSION;
|
|
8421
|
+
const metalParserMetadataKey = this.getMetalParserVersionMetadataKey();
|
|
8422
|
+
const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
|
|
8423
|
+
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some(
|
|
8424
|
+
(filePath) => path13.extname(filePath).toLowerCase() === ".swift"
|
|
8425
|
+
)) {
|
|
8426
|
+
this.logger.info("Reindexing cached Swift files for parser support");
|
|
8427
|
+
}
|
|
8428
|
+
if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some(
|
|
8429
|
+
(filePath) => path13.extname(filePath).toLowerCase() === ".metal"
|
|
8430
|
+
)) {
|
|
8431
|
+
this.logger.info("Reindexing cached Metal files for parser support");
|
|
8432
|
+
}
|
|
8223
8433
|
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
8224
8434
|
const { files, skipped } = await collectFiles(
|
|
8225
8435
|
this.projectRoot,
|
|
@@ -8239,10 +8449,17 @@ var Indexer = class {
|
|
|
8239
8449
|
const changedFiles = [];
|
|
8240
8450
|
const unchangedFilePaths = /* @__PURE__ */ new Set();
|
|
8241
8451
|
const currentFileHashes = /* @__PURE__ */ new Map();
|
|
8452
|
+
const needsCallGraphResolutionMigration = database.getMetadata(this.getCallGraphResolutionMetadataKey()) !== CALL_GRAPH_RESOLUTION_VERSION;
|
|
8242
8453
|
for (const f of files) {
|
|
8243
8454
|
const currentHash = hashFile(f.path);
|
|
8244
8455
|
currentFileHashes.set(f.path, currentHash);
|
|
8245
|
-
|
|
8456
|
+
const cachedHashMatches = this.fileHashCache.get(f.path) === currentHash;
|
|
8457
|
+
const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(f.path).some(
|
|
8458
|
+
(chunk) => chunk.language === "php" || chunk.language === "c" || chunk.language === "cpp"
|
|
8459
|
+
);
|
|
8460
|
+
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path13.extname(f.path).toLowerCase() === ".swift";
|
|
8461
|
+
const requiresMetalParserUpgrade = reparseCachedMetalFiles && path13.extname(f.path).toLowerCase() === ".metal";
|
|
8462
|
+
if (cachedHashMatches && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade) {
|
|
8246
8463
|
unchangedFilePaths.add(f.path);
|
|
8247
8464
|
this.logger.recordCacheHit();
|
|
8248
8465
|
} else {
|
|
@@ -8444,16 +8661,28 @@ var Indexer = class {
|
|
|
8444
8661
|
const fileSymbols = [];
|
|
8445
8662
|
for (const chunk of parsed.chunks) {
|
|
8446
8663
|
if (!chunk.name || !CALL_GRAPH_SYMBOL_CHUNK_TYPES.has(chunk.chunkType)) continue;
|
|
8447
|
-
const
|
|
8664
|
+
const existingMetalSymbol = chunk.language === "metal" ? fileSymbols.find(
|
|
8665
|
+
(symbol2) => symbol2.name === chunk.name && symbol2.kind === chunk.chunkType && symbol2.startLine <= chunk.endLine && chunk.startLine <= symbol2.endLine
|
|
8666
|
+
) : void 0;
|
|
8667
|
+
if (existingMetalSymbol) {
|
|
8668
|
+
existingMetalSymbol.startLine = Math.min(existingMetalSymbol.startLine, chunk.startLine);
|
|
8669
|
+
existingMetalSymbol.endLine = Math.max(existingMetalSymbol.endLine, chunk.endLine);
|
|
8670
|
+
existingMetalSymbol.startCol = Math.min(existingMetalSymbol.startCol, chunk.startCol ?? 0);
|
|
8671
|
+
existingMetalSymbol.endCol = Math.max(existingMetalSymbol.endCol, chunk.endCol ?? 0);
|
|
8672
|
+
continue;
|
|
8673
|
+
}
|
|
8674
|
+
const symbolId = `sym_${hashContent(
|
|
8675
|
+
parsed.path + ":" + chunk.name + ":" + chunk.chunkType + ":" + chunk.startLine + ":" + (chunk.startCol ?? 0)
|
|
8676
|
+
).slice(0, 16)}`;
|
|
8448
8677
|
const symbol = {
|
|
8449
8678
|
id: symbolId,
|
|
8450
8679
|
filePath: parsed.path,
|
|
8451
8680
|
name: chunk.name,
|
|
8452
8681
|
kind: chunk.chunkType,
|
|
8453
8682
|
startLine: chunk.startLine,
|
|
8454
|
-
startCol: 0,
|
|
8683
|
+
startCol: chunk.startCol ?? 0,
|
|
8455
8684
|
endLine: chunk.endLine,
|
|
8456
|
-
endCol: 0,
|
|
8685
|
+
endCol: chunk.endCol ?? 0,
|
|
8457
8686
|
language: chunk.language
|
|
8458
8687
|
};
|
|
8459
8688
|
fileSymbols.push(symbol);
|
|
@@ -8478,8 +8707,10 @@ var Indexer = class {
|
|
|
8478
8707
|
if (callSites.length === 0) continue;
|
|
8479
8708
|
const edges = [];
|
|
8480
8709
|
for (const site of callSites) {
|
|
8481
|
-
const enclosingSymbol =
|
|
8482
|
-
|
|
8710
|
+
const enclosingSymbol = findEnclosingSymbol(
|
|
8711
|
+
fileSymbols,
|
|
8712
|
+
site.line,
|
|
8713
|
+
site.column
|
|
8483
8714
|
);
|
|
8484
8715
|
if (!enclosingSymbol) continue;
|
|
8485
8716
|
const edgeId = `edge_${hashContent(enclosingSymbol.id + ":" + site.calleeName + ":" + site.line + ":" + site.column).slice(0, 16)}`;
|
|
@@ -8498,7 +8729,21 @@ var Indexer = class {
|
|
|
8498
8729
|
if (edges.length > 0) {
|
|
8499
8730
|
database.upsertCallEdgesBatch(edges);
|
|
8500
8731
|
for (const edge of edges) {
|
|
8501
|
-
|
|
8732
|
+
let candidates = symbolsByName.get(normalizeSymbolKey(edge.targetName));
|
|
8733
|
+
if (fileLanguage === "php" && candidates) {
|
|
8734
|
+
if (edge.callType === "Constructor") {
|
|
8735
|
+
candidates = candidates.filter(
|
|
8736
|
+
(candidate) => PHP_CLASS_SYMBOL_CHUNK_TYPES.has(candidate.kind)
|
|
8737
|
+
);
|
|
8738
|
+
} else if (edge.callType === "Call") {
|
|
8739
|
+
candidates = candidates.filter(
|
|
8740
|
+
(candidate) => PHP_FUNCTION_SYMBOL_CHUNK_TYPES.has(candidate.kind)
|
|
8741
|
+
);
|
|
8742
|
+
}
|
|
8743
|
+
}
|
|
8744
|
+
candidates = candidates?.filter(
|
|
8745
|
+
(symbol) => isCompatibleCFamilyCallTarget(fileLanguage, edge.callType, symbol.kind)
|
|
8746
|
+
);
|
|
8502
8747
|
if (candidates && candidates.length === 1) {
|
|
8503
8748
|
database.resolveCallEdge(edge.id, candidates[0].id);
|
|
8504
8749
|
}
|
|
@@ -8553,6 +8798,8 @@ var Indexer = class {
|
|
|
8553
8798
|
this.saveFileHashCache();
|
|
8554
8799
|
this.saveFailedBatches([]);
|
|
8555
8800
|
}
|
|
8801
|
+
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
8802
|
+
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
8556
8803
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
8557
8804
|
this.indexCompatibility = { compatible: true };
|
|
8558
8805
|
stats.durationMs = Date.now() - startTime;
|
|
@@ -8580,6 +8827,8 @@ var Indexer = class {
|
|
|
8580
8827
|
this.saveFileHashCache();
|
|
8581
8828
|
this.saveFailedBatches([]);
|
|
8582
8829
|
}
|
|
8830
|
+
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
8831
|
+
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
8583
8832
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
8584
8833
|
this.indexCompatibility = { compatible: true };
|
|
8585
8834
|
stats.durationMs = Date.now() - startTime;
|
|
@@ -8850,6 +9099,8 @@ var Indexer = class {
|
|
|
8850
9099
|
if (forceScopedReembed && failedForcedChunkIds.size === 0) {
|
|
8851
9100
|
database.deleteMetadata(this.getProjectForceReembedMetadataKey());
|
|
8852
9101
|
}
|
|
9102
|
+
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
9103
|
+
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
8853
9104
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
8854
9105
|
this.indexCompatibility = { compatible: true };
|
|
8855
9106
|
this.logger.recordIndexingEnd();
|
|
@@ -10510,15 +10761,6 @@ function refreshIndexerForDirectory(projectRoot, host = "opencode", config = par
|
|
|
10510
10761
|
indexerCache.set(key, indexer);
|
|
10511
10762
|
configCache.set(key, config);
|
|
10512
10763
|
}
|
|
10513
|
-
function shouldForceLocalizeProjectIndex(projectRoot, host = "opencode") {
|
|
10514
|
-
const root = getProjectRoot(projectRoot, host);
|
|
10515
|
-
const localIndexPath = path16.join(root, getHostProjectIndexRelativePath(host));
|
|
10516
|
-
if ((0, import_fs10.existsSync)(localIndexPath)) {
|
|
10517
|
-
return false;
|
|
10518
|
-
}
|
|
10519
|
-
const inheritedIndexPath = resolveWorktreeFallbackProjectIndexPath(root, host);
|
|
10520
|
-
return inheritedIndexPath !== null;
|
|
10521
|
-
}
|
|
10522
10764
|
async function searchCodebase(projectRoot, host, query, options = {}) {
|
|
10523
10765
|
const indexer = getIndexerForProject(projectRoot, host);
|
|
10524
10766
|
return indexer.search(query, options.limit, {
|
|
@@ -10568,9 +10810,7 @@ async function getCallGraphPath(projectRoot, host, from, to, maxDepth) {
|
|
|
10568
10810
|
}
|
|
10569
10811
|
async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
10570
10812
|
const root = getProjectRoot(projectRoot, host);
|
|
10571
|
-
const
|
|
10572
|
-
let indexer = getIndexerForProject(root, host);
|
|
10573
|
-
const runtimeConfig = configCache.get(key);
|
|
10813
|
+
const indexer = getIndexerForProject(root, host);
|
|
10574
10814
|
try {
|
|
10575
10815
|
if (args.estimateOnly) {
|
|
10576
10816
|
return { kind: "estimate", estimate: await indexer.estimateCost() };
|
|
@@ -10591,19 +10831,7 @@ async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
|
10591
10831
|
return Promise.resolve();
|
|
10592
10832
|
});
|
|
10593
10833
|
};
|
|
10594
|
-
|
|
10595
|
-
if (args.force && shouldForceLocalizeProjectIndex(root, host)) {
|
|
10596
|
-
const inheritedIndexPath = resolveProjectIndexPath(root, runtimeConfig.scope, host);
|
|
10597
|
-
stats = await withIndexLock(inheritedIndexPath, "force-index", async () => {
|
|
10598
|
-
materializeLocalProjectConfig(root, loadProjectConfigLayer(root, host), host);
|
|
10599
|
-
refreshIndexerForDirectory(root, host, runtimeConfig);
|
|
10600
|
-
indexer = getIndexerForProject(root, host);
|
|
10601
|
-
return runIndex(indexer);
|
|
10602
|
-
}, { completeRecoveries: false });
|
|
10603
|
-
} else {
|
|
10604
|
-
stats = await runIndex(indexer);
|
|
10605
|
-
}
|
|
10606
|
-
return { kind: "stats", stats };
|
|
10834
|
+
return { kind: "stats", stats: await runIndex(indexer) };
|
|
10607
10835
|
} catch (error) {
|
|
10608
10836
|
const busyResult = getIndexBusyResult(error);
|
|
10609
10837
|
if (!busyResult) throw error;
|
|
@@ -12892,11 +13120,12 @@ function getConfigPaths(projectRoot, host, options) {
|
|
|
12892
13120
|
].map((configPath) => pathNormalize(configPath));
|
|
12893
13121
|
}
|
|
12894
13122
|
|
|
12895
|
-
//
|
|
12896
|
-
var
|
|
12897
|
-
|
|
12898
|
-
|
|
12899
|
-
|
|
13123
|
+
// node_modules/@opencode-ai/plugin/dist/tool.js
|
|
13124
|
+
var import_zod = require("zod");
|
|
13125
|
+
function tool(input) {
|
|
13126
|
+
return input;
|
|
13127
|
+
}
|
|
13128
|
+
tool.schema = import_zod.z;
|
|
12900
13129
|
|
|
12901
13130
|
// src/tools/format-pr-impact.ts
|
|
12902
13131
|
function formatPrImpact(result) {
|
|
@@ -12950,16 +13179,16 @@ function formatPrImpact(result) {
|
|
|
12950
13179
|
}
|
|
12951
13180
|
|
|
12952
13181
|
// src/tools/pr-impact.ts
|
|
12953
|
-
var
|
|
12954
|
-
var pr_impact =
|
|
13182
|
+
var z2 = tool.schema;
|
|
13183
|
+
var pr_impact = tool({
|
|
12955
13184
|
description: "Analyze the impact of a pull request or branch by examining changed files, affected symbols, transitive callers, communities touched, hub nodes, and risk level. Use to understand blast radius before merging.",
|
|
12956
13185
|
args: {
|
|
12957
|
-
pr:
|
|
12958
|
-
branch:
|
|
12959
|
-
maxDepth:
|
|
12960
|
-
hubThreshold:
|
|
12961
|
-
checkConflicts:
|
|
12962
|
-
direction:
|
|
13186
|
+
pr: z2.number().optional().describe("Pull request number to analyze"),
|
|
13187
|
+
branch: z2.string().optional().describe("Branch name to analyze (defaults to current branch)"),
|
|
13188
|
+
maxDepth: z2.number().optional().default(5).describe("Maximum traversal depth for transitive callers (default: 5)"),
|
|
13189
|
+
hubThreshold: z2.number().optional().default(10).describe("Minimum caller count to flag a symbol as a hub node (default: 10)"),
|
|
13190
|
+
checkConflicts: z2.boolean().optional().default(false).describe("Check for conflicting open PRs touching the same communities (default: false)"),
|
|
13191
|
+
direction: z2.enum(["callers", "callees", "both"]).optional().default("both").describe("Call-graph traversal direction: 'callers' for upstream, 'callees' for downstream, 'both' for union (default: both)")
|
|
12963
13192
|
},
|
|
12964
13193
|
async execute(args, context) {
|
|
12965
13194
|
const indexer = getIndexerForProject2(context?.worktree);
|
|
@@ -13936,7 +14165,7 @@ function transformForVisualization(symbols, edges, options = {}) {
|
|
|
13936
14165
|
}
|
|
13937
14166
|
|
|
13938
14167
|
// src/tools/index.ts
|
|
13939
|
-
var
|
|
14168
|
+
var z3 = tool.schema;
|
|
13940
14169
|
var DEFAULT_HOST = "opencode";
|
|
13941
14170
|
var CHUNK_TYPE_VALUES = [
|
|
13942
14171
|
"function",
|
|
@@ -13958,34 +14187,34 @@ function initializeTools2(projectRoot, config) {
|
|
|
13958
14187
|
function getIndexerForProject2(directory) {
|
|
13959
14188
|
return getIndexerForProject(directory, DEFAULT_HOST);
|
|
13960
14189
|
}
|
|
13961
|
-
var codebase_context =
|
|
14190
|
+
var codebase_context = tool({
|
|
13962
14191
|
description: "PREFERRED FIRST TOOL for repository questions. Returns a deduplicated, file-diverse evidence pack within tokenBudget. Provide from and to for dependency paths, symbol for definitions, or only query for conceptual discovery.",
|
|
13963
14192
|
args: {
|
|
13964
|
-
query:
|
|
13965
|
-
from:
|
|
13966
|
-
to:
|
|
13967
|
-
symbol:
|
|
13968
|
-
limit:
|
|
13969
|
-
maxDepth:
|
|
13970
|
-
fileType:
|
|
13971
|
-
directory:
|
|
13972
|
-
tokenBudget:
|
|
14193
|
+
query: z3.string().describe("The repository question or behavior to locate"),
|
|
14194
|
+
from: z3.string().nullable().optional().describe("Source symbol for a dependency path"),
|
|
14195
|
+
to: z3.string().nullable().optional().describe("Target symbol for a dependency path"),
|
|
14196
|
+
symbol: z3.string().nullable().optional().describe("Exact symbol for authoritative definition lookup"),
|
|
14197
|
+
limit: z3.number().int().min(MIN_CONTEXT_RESULT_LIMIT).max(MAX_CONTEXT_RESULT_LIMIT).nullable().optional().default(10).describe(`Maximum number of results (${MIN_CONTEXT_RESULT_LIMIT}-${MAX_CONTEXT_RESULT_LIMIT})`),
|
|
14198
|
+
maxDepth: z3.number().int().min(MIN_CONTEXT_PATH_DEPTH).max(MAX_CONTEXT_PATH_DEPTH).nullable().optional().default(10).describe(`Maximum call-path traversal depth (${MIN_CONTEXT_PATH_DEPTH}-${MAX_CONTEXT_PATH_DEPTH})`),
|
|
14199
|
+
fileType: z3.string().nullable().optional().describe("Filter by file extension"),
|
|
14200
|
+
directory: z3.string().nullable().optional().describe("Filter by directory path"),
|
|
14201
|
+
tokenBudget: z3.number().int().min(MIN_CONTEXT_PACK_TOKEN_BUDGET).max(MAX_CONTEXT_PACK_TOKEN_BUDGET).nullable().optional().default(DEFAULT_CONTEXT_PACK_TOKEN_BUDGET).describe(`Maximum response tokens (${MIN_CONTEXT_PACK_TOKEN_BUDGET}-${MAX_CONTEXT_PACK_TOKEN_BUDGET})`)
|
|
13973
14202
|
},
|
|
13974
14203
|
async execute(args, context) {
|
|
13975
14204
|
return (await resolveCodebaseContext(context?.worktree, DEFAULT_HOST, args)).text;
|
|
13976
14205
|
}
|
|
13977
14206
|
});
|
|
13978
|
-
var codebase_peek =
|
|
14207
|
+
var codebase_peek = tool({
|
|
13979
14208
|
description: "Quick lookup of code locations by meaning. Returns only metadata (file, line, name, type) WITHOUT code content. Use this first to find WHERE code is, then use Read tool to examine specific files. Saves tokens by not returning full code blocks. Best for: discovery, navigation, finding multiple related locations.",
|
|
13980
14209
|
args: {
|
|
13981
|
-
query:
|
|
13982
|
-
limit:
|
|
13983
|
-
fileType:
|
|
13984
|
-
directory:
|
|
13985
|
-
chunkType:
|
|
13986
|
-
blameAuthor:
|
|
13987
|
-
blameSha:
|
|
13988
|
-
blameSince:
|
|
14210
|
+
query: z3.string().describe("Natural language description of what code you're looking for."),
|
|
14211
|
+
limit: z3.number().optional().default(10).describe("Maximum number of results to return"),
|
|
14212
|
+
fileType: z3.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
14213
|
+
directory: z3.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
14214
|
+
chunkType: z3.enum(CHUNK_TYPE_VALUES).optional().describe("Filter by code chunk type"),
|
|
14215
|
+
blameAuthor: z3.string().optional().describe("Filter by git blame author name or email"),
|
|
14216
|
+
blameSha: z3.string().optional().describe("Filter by git blame commit SHA or prefix"),
|
|
14217
|
+
blameSince: z3.string().optional().describe("Filter to chunks last changed on or after this date (e.g., 2025-01-01)")
|
|
13989
14218
|
},
|
|
13990
14219
|
async execute(args, context) {
|
|
13991
14220
|
const results = await searchCodebase(context?.worktree, DEFAULT_HOST, args.query, {
|
|
@@ -14001,12 +14230,12 @@ var codebase_peek = (0, import_plugin2.tool)({
|
|
|
14001
14230
|
return formatCodebasePeek(results);
|
|
14002
14231
|
}
|
|
14003
14232
|
});
|
|
14004
|
-
var index_codebase =
|
|
14233
|
+
var index_codebase = tool({
|
|
14005
14234
|
description: "Index the codebase for semantic search. Creates vector embeddings of code chunks. Incremental - only re-indexes changed files (~50ms when nothing changed). Run before first codebase_search.",
|
|
14006
14235
|
args: {
|
|
14007
|
-
force:
|
|
14008
|
-
estimateOnly:
|
|
14009
|
-
verbose:
|
|
14236
|
+
force: z3.boolean().optional().default(false).describe("Force reindex even if already indexed"),
|
|
14237
|
+
estimateOnly: z3.boolean().optional().default(false).describe("Only show cost estimate without indexing"),
|
|
14238
|
+
verbose: z3.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
|
|
14010
14239
|
},
|
|
14011
14240
|
async execute(args, context) {
|
|
14012
14241
|
const result = await runIndexCodebase(context?.worktree, DEFAULT_HOST, args, (title, metadata) => {
|
|
@@ -14017,14 +14246,14 @@ var index_codebase = (0, import_plugin2.tool)({
|
|
|
14017
14246
|
return formatIndexStats(result.stats, args.verbose ?? false);
|
|
14018
14247
|
}
|
|
14019
14248
|
});
|
|
14020
|
-
var index_status =
|
|
14249
|
+
var index_status = tool({
|
|
14021
14250
|
description: "Check the status of the codebase index. Shows whether the codebase is indexed, how many chunks are stored, and the embedding provider being used.",
|
|
14022
14251
|
args: {},
|
|
14023
14252
|
async execute(_args, context) {
|
|
14024
14253
|
return formatStatus(await getIndexStatus(context?.worktree, DEFAULT_HOST));
|
|
14025
14254
|
}
|
|
14026
14255
|
});
|
|
14027
|
-
var index_health_check =
|
|
14256
|
+
var index_health_check = tool({
|
|
14028
14257
|
description: "Check index health and remove stale entries from deleted files. Run this to clean up the index after files have been deleted.",
|
|
14029
14258
|
args: {},
|
|
14030
14259
|
async execute(_args, context) {
|
|
@@ -14033,33 +14262,33 @@ var index_health_check = (0, import_plugin2.tool)({
|
|
|
14033
14262
|
return formatHealthCheck(result.health);
|
|
14034
14263
|
}
|
|
14035
14264
|
});
|
|
14036
|
-
var index_metrics =
|
|
14265
|
+
var index_metrics = tool({
|
|
14037
14266
|
description: "Get metrics and performance statistics for the codebase index. Shows indexing stats, search timings, cache hit rates, and API usage. Requires debug.enabled=true and debug.metrics=true in config.",
|
|
14038
14267
|
args: {},
|
|
14039
14268
|
async execute(_args, context) {
|
|
14040
14269
|
return (await getIndexMetrics(context?.worktree, DEFAULT_HOST)).text;
|
|
14041
14270
|
}
|
|
14042
14271
|
});
|
|
14043
|
-
var index_logs =
|
|
14272
|
+
var index_logs = tool({
|
|
14044
14273
|
description: "Get recent debug logs from the codebase indexer. Shows timestamped log entries with level and category. Requires debug.enabled=true in config.",
|
|
14045
14274
|
args: {
|
|
14046
|
-
limit:
|
|
14047
|
-
category:
|
|
14048
|
-
level:
|
|
14275
|
+
limit: z3.number().optional().default(20).describe("Maximum number of log entries to return"),
|
|
14276
|
+
category: z3.enum(["search", "embedding", "cache", "gc", "branch", "general"]).optional().describe("Filter by log category"),
|
|
14277
|
+
level: z3.enum(["error", "warn", "info", "debug"]).optional().describe("Filter by minimum log level")
|
|
14049
14278
|
},
|
|
14050
14279
|
async execute(args, context) {
|
|
14051
14280
|
return (await getIndexLogs(context?.worktree, DEFAULT_HOST, args)).text;
|
|
14052
14281
|
}
|
|
14053
14282
|
});
|
|
14054
|
-
var find_similar =
|
|
14283
|
+
var find_similar = tool({
|
|
14055
14284
|
description: "Find code similar to a given snippet. Use for duplicate detection, pattern discovery, or refactoring prep. Paste code and find semantically similar implementations elsewhere in the codebase.",
|
|
14056
14285
|
args: {
|
|
14057
|
-
code:
|
|
14058
|
-
limit:
|
|
14059
|
-
fileType:
|
|
14060
|
-
directory:
|
|
14061
|
-
chunkType:
|
|
14062
|
-
excludeFile:
|
|
14286
|
+
code: z3.string().describe("The code snippet to find similar code for"),
|
|
14287
|
+
limit: z3.number().optional().default(10).describe("Maximum number of results to return"),
|
|
14288
|
+
fileType: z3.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
14289
|
+
directory: z3.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
14290
|
+
chunkType: z3.enum(CHUNK_TYPE_VALUES).optional().describe("Filter by code chunk type"),
|
|
14291
|
+
excludeFile: z3.string().optional().describe("Exclude results from this file path (useful when searching for duplicates of code from a specific file)")
|
|
14063
14292
|
},
|
|
14064
14293
|
async execute(args, context) {
|
|
14065
14294
|
const results = await findSimilarCode(context?.worktree, DEFAULT_HOST, args.code, {
|
|
@@ -14075,18 +14304,18 @@ var find_similar = (0, import_plugin2.tool)({
|
|
|
14075
14304
|
return formatSearchResults(results);
|
|
14076
14305
|
}
|
|
14077
14306
|
});
|
|
14078
|
-
var codebase_search =
|
|
14307
|
+
var codebase_search = tool({
|
|
14079
14308
|
description: "Search codebase by MEANING, not keywords. Returns full code content. Use when you need to see actual implementation. For just finding WHERE code is (saves ~90% tokens), use codebase_peek instead. For known identifiers like 'validateToken', use grep - it's faster.",
|
|
14080
14309
|
args: {
|
|
14081
|
-
query:
|
|
14082
|
-
limit:
|
|
14083
|
-
fileType:
|
|
14084
|
-
directory:
|
|
14085
|
-
chunkType:
|
|
14086
|
-
contextLines:
|
|
14087
|
-
blameAuthor:
|
|
14088
|
-
blameSha:
|
|
14089
|
-
blameSince:
|
|
14310
|
+
query: z3.string().describe("Natural language description of what code you're looking for. Describe behavior, not syntax."),
|
|
14311
|
+
limit: z3.number().optional().default(5).describe("Maximum number of results to return"),
|
|
14312
|
+
fileType: z3.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
14313
|
+
directory: z3.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
14314
|
+
chunkType: z3.enum(CHUNK_TYPE_VALUES).optional().describe("Filter by code chunk type"),
|
|
14315
|
+
contextLines: z3.number().optional().describe("Number of extra lines to include before/after each match (default: 0)"),
|
|
14316
|
+
blameAuthor: z3.string().optional().describe("Filter by git blame author name or email"),
|
|
14317
|
+
blameSha: z3.string().optional().describe("Filter by git blame commit SHA or prefix"),
|
|
14318
|
+
blameSince: z3.string().optional().describe("Filter to chunks last changed on or after this date (e.g., 2025-01-01)")
|
|
14090
14319
|
},
|
|
14091
14320
|
async execute(args, context) {
|
|
14092
14321
|
const results = await searchCodebase(context?.worktree, DEFAULT_HOST, args.query, {
|
|
@@ -14105,13 +14334,13 @@ var codebase_search = (0, import_plugin2.tool)({
|
|
|
14105
14334
|
return formatSearchResults(results, "score");
|
|
14106
14335
|
}
|
|
14107
14336
|
});
|
|
14108
|
-
var implementation_lookup =
|
|
14337
|
+
var implementation_lookup = tool({
|
|
14109
14338
|
description: "Jump to symbol definition. Find WHERE something is defined. Returns the authoritative source location(s) for a function, class, method, type, or variable. Prefers real implementation files over tests, docs, examples, and fixtures. Use when you need the definition site, not all usages.",
|
|
14110
14339
|
args: {
|
|
14111
|
-
query:
|
|
14112
|
-
limit:
|
|
14113
|
-
fileType:
|
|
14114
|
-
directory:
|
|
14340
|
+
query: z3.string().describe("Symbol name or natural language description (e.g., 'validateToken', 'where is the payment handler defined')"),
|
|
14341
|
+
limit: z3.number().optional().default(5).describe("Maximum number of results"),
|
|
14342
|
+
fileType: z3.string().optional().describe("Filter by file extension (e.g., 'ts', 'py')"),
|
|
14343
|
+
directory: z3.string().optional().describe("Filter by directory path (e.g., 'src/utils')")
|
|
14115
14344
|
},
|
|
14116
14345
|
async execute(args, context) {
|
|
14117
14346
|
const results = await implementationLookup(context?.worktree, DEFAULT_HOST, args.query, {
|
|
@@ -14122,13 +14351,13 @@ var implementation_lookup = (0, import_plugin2.tool)({
|
|
|
14122
14351
|
return formatDefinitionLookup(results, args.query);
|
|
14123
14352
|
}
|
|
14124
14353
|
});
|
|
14125
|
-
var call_graph =
|
|
14354
|
+
var call_graph = tool({
|
|
14126
14355
|
description: "Query the call graph to find callers or callees of a function/method. Use to understand code flow and dependencies between functions. Supports relationship types: Call, MethodCall, Constructor, Import, Inherits, Implements.",
|
|
14127
14356
|
args: {
|
|
14128
|
-
name:
|
|
14129
|
-
direction:
|
|
14130
|
-
symbolId:
|
|
14131
|
-
relationshipType:
|
|
14357
|
+
name: z3.string().describe("Function or method name to query"),
|
|
14358
|
+
direction: z3.enum(["callers", "callees"]).default("callers").describe("Direction: 'callers' finds who calls this function, 'callees' finds what this function calls"),
|
|
14359
|
+
symbolId: z3.string().optional().describe("Symbol ID (required for 'callees' direction, returned by previous call_graph queries)"),
|
|
14360
|
+
relationshipType: z3.enum(RELATIONSHIP_TYPE_VALUES).optional().describe("Filter by relationship type. Omit to show all.")
|
|
14132
14361
|
},
|
|
14133
14362
|
async execute(args, context) {
|
|
14134
14363
|
if (args.direction === "callees") {
|
|
@@ -14142,49 +14371,49 @@ var call_graph = (0, import_plugin2.tool)({
|
|
|
14142
14371
|
return formatCallGraphCallers(args.name, callers, args.relationshipType);
|
|
14143
14372
|
}
|
|
14144
14373
|
});
|
|
14145
|
-
var call_graph_path =
|
|
14374
|
+
var call_graph_path = tool({
|
|
14146
14375
|
description: "Find the shortest connection path between two symbols in the call graph. Given a source and target function/method name, returns the chain of calls connecting them.",
|
|
14147
14376
|
args: {
|
|
14148
|
-
from:
|
|
14149
|
-
to:
|
|
14150
|
-
maxDepth:
|
|
14377
|
+
from: z3.string().describe("Source function/method name (starting point)"),
|
|
14378
|
+
to: z3.string().describe("Target function/method name (destination)"),
|
|
14379
|
+
maxDepth: z3.number().optional().default(10).describe("Maximum traversal depth (default: 10)")
|
|
14151
14380
|
},
|
|
14152
14381
|
async execute(args, context) {
|
|
14153
14382
|
const path24 = await getCallGraphPath(context?.worktree, DEFAULT_HOST, args.from, args.to, args.maxDepth);
|
|
14154
14383
|
return formatCallGraphPath(args.from, args.to, path24);
|
|
14155
14384
|
}
|
|
14156
14385
|
});
|
|
14157
|
-
var add_knowledge_base =
|
|
14386
|
+
var add_knowledge_base = tool({
|
|
14158
14387
|
description: "Add a folder as a knowledge base to the semantic search index. The folder will be indexed alongside the main project code. Supports absolute paths or relative paths (relative to the project root).",
|
|
14159
14388
|
args: {
|
|
14160
|
-
path:
|
|
14389
|
+
path: z3.string().describe("Path to the folder to add as a knowledge base (absolute or relative to the project root)")
|
|
14161
14390
|
},
|
|
14162
14391
|
async execute(args, context) {
|
|
14163
14392
|
return addKnowledgeBase(context?.worktree, DEFAULT_HOST, args.path);
|
|
14164
14393
|
}
|
|
14165
14394
|
});
|
|
14166
|
-
var list_knowledge_bases =
|
|
14395
|
+
var list_knowledge_bases = tool({
|
|
14167
14396
|
description: "List all configured knowledge base folders that are indexed alongside the main project.",
|
|
14168
14397
|
args: {},
|
|
14169
14398
|
async execute(_args, context) {
|
|
14170
14399
|
return listKnowledgeBases(context?.worktree, DEFAULT_HOST);
|
|
14171
14400
|
}
|
|
14172
14401
|
});
|
|
14173
|
-
var remove_knowledge_base =
|
|
14402
|
+
var remove_knowledge_base = tool({
|
|
14174
14403
|
description: "Remove a knowledge base folder from the semantic search index.",
|
|
14175
14404
|
args: {
|
|
14176
|
-
path:
|
|
14405
|
+
path: z3.string().describe("Path of the knowledge base to remove (must match the configured path exactly)")
|
|
14177
14406
|
},
|
|
14178
14407
|
async execute(args, context) {
|
|
14179
14408
|
return removeKnowledgeBase(context?.worktree, DEFAULT_HOST, args.path.trim());
|
|
14180
14409
|
}
|
|
14181
14410
|
});
|
|
14182
|
-
var index_visualize =
|
|
14411
|
+
var index_visualize = tool({
|
|
14183
14412
|
description: "Generate an interactive HTML visualization of recent code movement and the call graph. Starts with temporal onboarding context from Git history, then supports module, symbol, hotspot, and cycle drill-down.",
|
|
14184
14413
|
args: {
|
|
14185
|
-
directory:
|
|
14186
|
-
maxNodes:
|
|
14187
|
-
includeOrphans:
|
|
14414
|
+
directory: z3.string().optional().describe("Filter to symbols in this directory (e.g., 'src/services')"),
|
|
14415
|
+
maxNodes: z3.number().optional().default(5e3).describe("Maximum nodes to include (default 5000)"),
|
|
14416
|
+
includeOrphans: z3.boolean().optional().default(false).describe("Include symbols with no call relationships")
|
|
14188
14417
|
},
|
|
14189
14418
|
async execute(args, context) {
|
|
14190
14419
|
const projectRoot = context?.worktree ?? process.cwd();
|