opencode-codebase-index 0.9.0 → 0.10.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/README.md +4 -2
- package/dist/cli.cjs +6 -5
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +6 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +171 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +171 -90
- package/dist/index.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.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -647,6 +647,7 @@ var require_eventemitter3 = __commonJS({
|
|
|
647
647
|
});
|
|
648
648
|
|
|
649
649
|
// src/index.ts
|
|
650
|
+
import * as os6 from "os";
|
|
650
651
|
import * as path17 from "path";
|
|
651
652
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
652
653
|
|
|
@@ -793,7 +794,8 @@ function getDefaultSearchConfig() {
|
|
|
793
794
|
rrfK: 60,
|
|
794
795
|
rerankTopN: 20,
|
|
795
796
|
contextLines: 0,
|
|
796
|
-
routingHints: true
|
|
797
|
+
routingHints: true,
|
|
798
|
+
routingHintRole: "system"
|
|
797
799
|
};
|
|
798
800
|
}
|
|
799
801
|
function getDefaultRerankerBaseUrl(provider) {
|
|
@@ -914,7 +916,8 @@ function parseConfig(raw) {
|
|
|
914
916
|
rrfK: typeof rawSearch.rrfK === "number" ? Math.max(1, Math.floor(rawSearch.rrfK)) : defaultSearch.rrfK,
|
|
915
917
|
rerankTopN: typeof rawSearch.rerankTopN === "number" ? Math.min(200, Math.max(0, Math.floor(rawSearch.rerankTopN))) : defaultSearch.rerankTopN,
|
|
916
918
|
contextLines: typeof rawSearch.contextLines === "number" ? Math.min(50, Math.max(0, rawSearch.contextLines)) : defaultSearch.contextLines,
|
|
917
|
-
routingHints: typeof rawSearch.routingHints === "boolean" ? rawSearch.routingHints : defaultSearch.routingHints
|
|
919
|
+
routingHints: typeof rawSearch.routingHints === "boolean" ? rawSearch.routingHints : defaultSearch.routingHints,
|
|
920
|
+
routingHintRole: rawSearch.routingHintRole === "developer" || rawSearch.routingHintRole === "system" ? rawSearch.routingHintRole : defaultSearch.routingHintRole
|
|
918
921
|
};
|
|
919
922
|
const rawDebug = input.debug && typeof input.debug === "object" ? input.debug : {};
|
|
920
923
|
const debug = {
|
|
@@ -1236,6 +1239,32 @@ function hasFilteredPathSegment(relativePath, separator = path4.sep) {
|
|
|
1236
1239
|
(part) => isHiddenPathSegment(part) || isBuildPathSegment(part)
|
|
1237
1240
|
);
|
|
1238
1241
|
}
|
|
1242
|
+
var RESTRICTED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
1243
|
+
// macOS
|
|
1244
|
+
"library",
|
|
1245
|
+
"applications",
|
|
1246
|
+
"system",
|
|
1247
|
+
"volumes",
|
|
1248
|
+
"private",
|
|
1249
|
+
"cores",
|
|
1250
|
+
// Linux
|
|
1251
|
+
"proc",
|
|
1252
|
+
"sys",
|
|
1253
|
+
"dev",
|
|
1254
|
+
"run",
|
|
1255
|
+
"snap",
|
|
1256
|
+
// Windows
|
|
1257
|
+
"windows",
|
|
1258
|
+
"programdata",
|
|
1259
|
+
"program files",
|
|
1260
|
+
"program files (x86)",
|
|
1261
|
+
"$recycle.bin"
|
|
1262
|
+
]);
|
|
1263
|
+
function isRestrictedDirectory(relativePath, separator = path4.sep) {
|
|
1264
|
+
const firstSegment = relativePath.split(separator)[0];
|
|
1265
|
+
if (!firstSegment) return false;
|
|
1266
|
+
return RESTRICTED_DIRECTORIES.has(firstSegment.toLowerCase());
|
|
1267
|
+
}
|
|
1239
1268
|
|
|
1240
1269
|
// src/config/rebase.ts
|
|
1241
1270
|
function isWithinRoot(rootDir, targetPath) {
|
|
@@ -2295,7 +2324,7 @@ var NodeFsHandler = class {
|
|
|
2295
2324
|
this._addToNodeFs(path18, initialAdd, wh, depth + 1);
|
|
2296
2325
|
}
|
|
2297
2326
|
}).on(EV.ERROR, this._boundHandleError);
|
|
2298
|
-
return new Promise((
|
|
2327
|
+
return new Promise((resolve12, reject) => {
|
|
2299
2328
|
if (!stream)
|
|
2300
2329
|
return reject();
|
|
2301
2330
|
stream.once(STR_END, () => {
|
|
@@ -2304,7 +2333,7 @@ var NodeFsHandler = class {
|
|
|
2304
2333
|
return;
|
|
2305
2334
|
}
|
|
2306
2335
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
2307
|
-
|
|
2336
|
+
resolve12(void 0);
|
|
2308
2337
|
previous.getChildren().filter((item) => {
|
|
2309
2338
|
return item !== directory && !current.has(item);
|
|
2310
2339
|
}).forEach((item) => {
|
|
@@ -3404,6 +3433,9 @@ var FileWatcher = class {
|
|
|
3404
3433
|
if (hasFilteredPathSegment(relativePath, path8.sep)) {
|
|
3405
3434
|
return true;
|
|
3406
3435
|
}
|
|
3436
|
+
if (isRestrictedDirectory(relativePath, path8.sep)) {
|
|
3437
|
+
return true;
|
|
3438
|
+
}
|
|
3407
3439
|
if (ignoreFilter.ignores(relativePath)) {
|
|
3408
3440
|
return true;
|
|
3409
3441
|
}
|
|
@@ -3416,6 +3448,13 @@ var FileWatcher = class {
|
|
|
3416
3448
|
pollInterval: 100
|
|
3417
3449
|
}
|
|
3418
3450
|
});
|
|
3451
|
+
this.watcher.on("error", (error) => {
|
|
3452
|
+
const err = error instanceof Error ? error : null;
|
|
3453
|
+
if (err?.code === "EPERM" || err?.code === "EACCES") {
|
|
3454
|
+
return;
|
|
3455
|
+
}
|
|
3456
|
+
console.error("[codebase-index] Watcher error:", err?.message ?? error);
|
|
3457
|
+
});
|
|
3419
3458
|
this.watcher.on("add", (filePath) => this.handleChange("add", filePath));
|
|
3420
3459
|
this.watcher.on("change", (filePath) => this.handleChange("change", filePath));
|
|
3421
3460
|
this.watcher.on("unlink", (filePath) => this.handleChange("unlink", filePath));
|
|
@@ -3550,7 +3589,7 @@ var GitHeadWatcher = class {
|
|
|
3550
3589
|
};
|
|
3551
3590
|
|
|
3552
3591
|
// src/watcher/index.ts
|
|
3553
|
-
function createWatcherWithIndexer(
|
|
3592
|
+
function createWatcherWithIndexer(getIndexer, projectRoot, config) {
|
|
3554
3593
|
const fileWatcher = new FileWatcher(projectRoot, config);
|
|
3555
3594
|
fileWatcher.start(async (changes) => {
|
|
3556
3595
|
const hasAddOrChange = changes.some(
|
|
@@ -3558,7 +3597,7 @@ function createWatcherWithIndexer(getIndexer2, projectRoot, config) {
|
|
|
3558
3597
|
);
|
|
3559
3598
|
const hasDelete = changes.some((c) => c.type === "unlink");
|
|
3560
3599
|
if (hasAddOrChange || hasDelete) {
|
|
3561
|
-
await
|
|
3600
|
+
await getIndexer().index();
|
|
3562
3601
|
}
|
|
3563
3602
|
});
|
|
3564
3603
|
let gitWatcher = null;
|
|
@@ -3566,7 +3605,7 @@ function createWatcherWithIndexer(getIndexer2, projectRoot, config) {
|
|
|
3566
3605
|
gitWatcher = new GitHeadWatcher(projectRoot);
|
|
3567
3606
|
gitWatcher.start(async (oldBranch, newBranch) => {
|
|
3568
3607
|
console.log(`Branch changed: ${oldBranch ?? "(none)"} -> ${newBranch}`);
|
|
3569
|
-
await
|
|
3608
|
+
await getIndexer().index();
|
|
3570
3609
|
});
|
|
3571
3610
|
}
|
|
3572
3611
|
return {
|
|
@@ -3609,7 +3648,7 @@ function pTimeout(promise, options) {
|
|
|
3609
3648
|
} = options;
|
|
3610
3649
|
let timer;
|
|
3611
3650
|
let abortHandler;
|
|
3612
|
-
const wrappedPromise = new Promise((
|
|
3651
|
+
const wrappedPromise = new Promise((resolve12, reject) => {
|
|
3613
3652
|
if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
|
|
3614
3653
|
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
3615
3654
|
}
|
|
@@ -3623,7 +3662,7 @@ function pTimeout(promise, options) {
|
|
|
3623
3662
|
};
|
|
3624
3663
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
3625
3664
|
}
|
|
3626
|
-
promise.then(
|
|
3665
|
+
promise.then(resolve12, reject);
|
|
3627
3666
|
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
3628
3667
|
return;
|
|
3629
3668
|
}
|
|
@@ -3631,7 +3670,7 @@ function pTimeout(promise, options) {
|
|
|
3631
3670
|
timer = customTimers.setTimeout.call(void 0, () => {
|
|
3632
3671
|
if (fallback) {
|
|
3633
3672
|
try {
|
|
3634
|
-
|
|
3673
|
+
resolve12(fallback());
|
|
3635
3674
|
} catch (error) {
|
|
3636
3675
|
reject(error);
|
|
3637
3676
|
}
|
|
@@ -3641,7 +3680,7 @@ function pTimeout(promise, options) {
|
|
|
3641
3680
|
promise.cancel();
|
|
3642
3681
|
}
|
|
3643
3682
|
if (message === false) {
|
|
3644
|
-
|
|
3683
|
+
resolve12();
|
|
3645
3684
|
} else if (message instanceof Error) {
|
|
3646
3685
|
reject(message);
|
|
3647
3686
|
} else {
|
|
@@ -4043,7 +4082,7 @@ var PQueue = class extends import_index.default {
|
|
|
4043
4082
|
// Assign unique ID if not provided
|
|
4044
4083
|
id: options.id ?? (this.#idAssigner++).toString()
|
|
4045
4084
|
};
|
|
4046
|
-
return new Promise((
|
|
4085
|
+
return new Promise((resolve12, reject) => {
|
|
4047
4086
|
const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
|
|
4048
4087
|
let cleanupQueueAbortHandler = () => void 0;
|
|
4049
4088
|
const run = async () => {
|
|
@@ -4083,7 +4122,7 @@ var PQueue = class extends import_index.default {
|
|
|
4083
4122
|
})]);
|
|
4084
4123
|
}
|
|
4085
4124
|
const result = await operation;
|
|
4086
|
-
|
|
4125
|
+
resolve12(result);
|
|
4087
4126
|
this.emit("completed", result);
|
|
4088
4127
|
} catch (error) {
|
|
4089
4128
|
reject(error);
|
|
@@ -4271,13 +4310,13 @@ var PQueue = class extends import_index.default {
|
|
|
4271
4310
|
});
|
|
4272
4311
|
}
|
|
4273
4312
|
async #onEvent(event, filter) {
|
|
4274
|
-
return new Promise((
|
|
4313
|
+
return new Promise((resolve12) => {
|
|
4275
4314
|
const listener = () => {
|
|
4276
4315
|
if (filter && !filter()) {
|
|
4277
4316
|
return;
|
|
4278
4317
|
}
|
|
4279
4318
|
this.off(event, listener);
|
|
4280
|
-
|
|
4319
|
+
resolve12();
|
|
4281
4320
|
};
|
|
4282
4321
|
this.on(event, listener);
|
|
4283
4322
|
});
|
|
@@ -4563,7 +4602,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
4563
4602
|
const finalDelay = Math.min(delayTime, remainingTime);
|
|
4564
4603
|
options.signal?.throwIfAborted();
|
|
4565
4604
|
if (finalDelay > 0) {
|
|
4566
|
-
await new Promise((
|
|
4605
|
+
await new Promise((resolve12, reject) => {
|
|
4567
4606
|
const onAbort = () => {
|
|
4568
4607
|
clearTimeout(timeoutToken);
|
|
4569
4608
|
options.signal?.removeEventListener("abort", onAbort);
|
|
@@ -4571,7 +4610,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
4571
4610
|
};
|
|
4572
4611
|
const timeoutToken = setTimeout(() => {
|
|
4573
4612
|
options.signal?.removeEventListener("abort", onAbort);
|
|
4574
|
-
|
|
4613
|
+
resolve12();
|
|
4575
4614
|
}, finalDelay);
|
|
4576
4615
|
if (options.unref) {
|
|
4577
4616
|
timeoutToken.unref?.();
|
|
@@ -9150,7 +9189,7 @@ var Indexer = class {
|
|
|
9150
9189
|
for (const requestBatch of requestBatches) {
|
|
9151
9190
|
queue.add(async () => {
|
|
9152
9191
|
if (rateLimitBackoffMs > 0) {
|
|
9153
|
-
await new Promise((
|
|
9192
|
+
await new Promise((resolve12) => setTimeout(resolve12, rateLimitBackoffMs));
|
|
9154
9193
|
}
|
|
9155
9194
|
try {
|
|
9156
9195
|
const result = await pRetry(
|
|
@@ -10474,39 +10513,45 @@ function ensureStringArray(value) {
|
|
|
10474
10513
|
return Array.isArray(value) ? value : [];
|
|
10475
10514
|
}
|
|
10476
10515
|
var z = tool.schema;
|
|
10477
|
-
var
|
|
10478
|
-
var
|
|
10516
|
+
var indexerMap = /* @__PURE__ */ new Map();
|
|
10517
|
+
var defaultProjectRoot = "";
|
|
10479
10518
|
function initializeTools(projectRoot, config) {
|
|
10480
|
-
|
|
10481
|
-
|
|
10519
|
+
defaultProjectRoot = projectRoot;
|
|
10520
|
+
const indexer = new Indexer(projectRoot, config);
|
|
10521
|
+
indexerMap.set(projectRoot, indexer);
|
|
10482
10522
|
}
|
|
10483
|
-
function
|
|
10484
|
-
|
|
10485
|
-
}
|
|
10486
|
-
function refreshIndexerFromConfig() {
|
|
10487
|
-
if (!sharedProjectRoot) {
|
|
10523
|
+
function refreshIndexerForDirectory(projectRoot) {
|
|
10524
|
+
if (!projectRoot) {
|
|
10488
10525
|
throw new Error("Codebase index tools not initialized. Plugin may not be loaded correctly.");
|
|
10489
10526
|
}
|
|
10490
|
-
|
|
10527
|
+
const indexer = new Indexer(projectRoot, parseConfig(loadRuntimeConfig(projectRoot)));
|
|
10528
|
+
indexerMap.set(projectRoot, indexer);
|
|
10491
10529
|
}
|
|
10492
|
-
function shouldForceLocalizeProjectIndex() {
|
|
10493
|
-
const currentConfig = parseConfig(loadRuntimeConfig(
|
|
10530
|
+
function shouldForceLocalizeProjectIndex(projectRoot) {
|
|
10531
|
+
const currentConfig = parseConfig(loadRuntimeConfig(projectRoot));
|
|
10494
10532
|
if (currentConfig.scope !== "project") {
|
|
10495
10533
|
return false;
|
|
10496
10534
|
}
|
|
10497
|
-
const localIndexPath = path15.join(
|
|
10498
|
-
const mainRepoRoot = resolveWorktreeMainRepoRoot(
|
|
10535
|
+
const localIndexPath = path15.join(projectRoot, ".opencode", "index");
|
|
10536
|
+
const mainRepoRoot = resolveWorktreeMainRepoRoot(projectRoot);
|
|
10499
10537
|
if (!mainRepoRoot) {
|
|
10500
10538
|
return false;
|
|
10501
10539
|
}
|
|
10502
10540
|
const inheritedIndexPath = path15.join(mainRepoRoot, ".opencode", "index");
|
|
10503
10541
|
return !existsSync9(localIndexPath) && existsSync9(inheritedIndexPath);
|
|
10504
10542
|
}
|
|
10505
|
-
function
|
|
10506
|
-
|
|
10543
|
+
function getIndexerForProject(directory) {
|
|
10544
|
+
const projectRoot = directory || defaultProjectRoot;
|
|
10545
|
+
if (!projectRoot) {
|
|
10507
10546
|
throw new Error("Codebase index tools not initialized. Plugin may not be loaded correctly.");
|
|
10508
10547
|
}
|
|
10509
|
-
|
|
10548
|
+
let indexer = indexerMap.get(projectRoot);
|
|
10549
|
+
if (!indexer) {
|
|
10550
|
+
const config = parseConfig(loadRuntimeConfig(projectRoot));
|
|
10551
|
+
indexer = new Indexer(projectRoot, config);
|
|
10552
|
+
indexerMap.set(projectRoot, indexer);
|
|
10553
|
+
}
|
|
10554
|
+
return indexer;
|
|
10510
10555
|
}
|
|
10511
10556
|
var codebase_peek = tool({
|
|
10512
10557
|
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.",
|
|
@@ -10517,8 +10562,8 @@ var codebase_peek = tool({
|
|
|
10517
10562
|
directory: z.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
10518
10563
|
chunkType: z.enum(["function", "class", "method", "interface", "type", "enum", "struct", "impl", "trait", "module", "other"]).optional().describe("Filter by code chunk type")
|
|
10519
10564
|
},
|
|
10520
|
-
async execute(args) {
|
|
10521
|
-
const indexer =
|
|
10565
|
+
async execute(args, context) {
|
|
10566
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10522
10567
|
const results = await indexer.search(args.query, args.limit ?? 10, {
|
|
10523
10568
|
fileType: args.fileType,
|
|
10524
10569
|
directory: args.directory,
|
|
@@ -10536,16 +10581,17 @@ var index_codebase = tool({
|
|
|
10536
10581
|
verbose: z.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
|
|
10537
10582
|
},
|
|
10538
10583
|
async execute(args, context) {
|
|
10539
|
-
|
|
10584
|
+
const projectRoot = context?.worktree || defaultProjectRoot;
|
|
10585
|
+
let indexer = getIndexerForProject(projectRoot);
|
|
10540
10586
|
if (args.estimateOnly) {
|
|
10541
10587
|
const estimate = await indexer.estimateCost();
|
|
10542
10588
|
return formatCostEstimate(estimate);
|
|
10543
10589
|
}
|
|
10544
10590
|
if (args.force) {
|
|
10545
|
-
if (shouldForceLocalizeProjectIndex()) {
|
|
10546
|
-
materializeLocalProjectConfig(
|
|
10547
|
-
|
|
10548
|
-
indexer =
|
|
10591
|
+
if (shouldForceLocalizeProjectIndex(projectRoot)) {
|
|
10592
|
+
materializeLocalProjectConfig(projectRoot, loadProjectConfigLayer(projectRoot));
|
|
10593
|
+
refreshIndexerForDirectory(projectRoot);
|
|
10594
|
+
indexer = getIndexerForProject(projectRoot);
|
|
10549
10595
|
}
|
|
10550
10596
|
await indexer.clearIndex();
|
|
10551
10597
|
}
|
|
@@ -10568,8 +10614,8 @@ var index_codebase = tool({
|
|
|
10568
10614
|
var index_status = tool({
|
|
10569
10615
|
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.",
|
|
10570
10616
|
args: {},
|
|
10571
|
-
async execute() {
|
|
10572
|
-
const indexer =
|
|
10617
|
+
async execute(_args, context) {
|
|
10618
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10573
10619
|
const status = await indexer.getStatus();
|
|
10574
10620
|
return formatStatus(status);
|
|
10575
10621
|
}
|
|
@@ -10577,8 +10623,8 @@ var index_status = tool({
|
|
|
10577
10623
|
var index_health_check = tool({
|
|
10578
10624
|
description: "Check index health and remove stale entries from deleted files. Run this to clean up the index after files have been deleted.",
|
|
10579
10625
|
args: {},
|
|
10580
|
-
async execute() {
|
|
10581
|
-
const indexer =
|
|
10626
|
+
async execute(_args, context) {
|
|
10627
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10582
10628
|
const result = await indexer.healthCheck();
|
|
10583
10629
|
return formatHealthCheck(result);
|
|
10584
10630
|
}
|
|
@@ -10586,8 +10632,8 @@ var index_health_check = tool({
|
|
|
10586
10632
|
var index_metrics = tool({
|
|
10587
10633
|
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.",
|
|
10588
10634
|
args: {},
|
|
10589
|
-
async execute() {
|
|
10590
|
-
const indexer =
|
|
10635
|
+
async execute(_args, context) {
|
|
10636
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10591
10637
|
const logger = indexer.getLogger();
|
|
10592
10638
|
if (!logger.isEnabled()) {
|
|
10593
10639
|
return 'Debug mode is disabled. Enable it in your config:\n\n```json\n{\n "debug": {\n "enabled": true,\n "metrics": true\n }\n}\n```';
|
|
@@ -10605,8 +10651,8 @@ var index_logs = tool({
|
|
|
10605
10651
|
category: z.enum(["search", "embedding", "cache", "gc", "branch", "general"]).optional().describe("Filter by log category"),
|
|
10606
10652
|
level: z.enum(["error", "warn", "info", "debug"]).optional().describe("Filter by minimum log level")
|
|
10607
10653
|
},
|
|
10608
|
-
async execute(args) {
|
|
10609
|
-
const indexer =
|
|
10654
|
+
async execute(args, context) {
|
|
10655
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10610
10656
|
const logger = indexer.getLogger();
|
|
10611
10657
|
if (!logger.isEnabled()) {
|
|
10612
10658
|
return 'Debug mode is disabled. Enable it in your config:\n\n```json\n{\n "debug": {\n "enabled": true\n }\n}\n```';
|
|
@@ -10632,8 +10678,8 @@ var find_similar = tool({
|
|
|
10632
10678
|
chunkType: z.enum(["function", "class", "method", "interface", "type", "enum", "struct", "impl", "trait", "module", "other"]).optional().describe("Filter by code chunk type"),
|
|
10633
10679
|
excludeFile: z.string().optional().describe("Exclude results from this file path (useful when searching for duplicates of code from a specific file)")
|
|
10634
10680
|
},
|
|
10635
|
-
async execute(args) {
|
|
10636
|
-
const indexer =
|
|
10681
|
+
async execute(args, context) {
|
|
10682
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10637
10683
|
const results = await indexer.findSimilar(args.code, args.limit, {
|
|
10638
10684
|
fileType: args.fileType,
|
|
10639
10685
|
directory: args.directory,
|
|
@@ -10656,8 +10702,8 @@ var codebase_search = tool({
|
|
|
10656
10702
|
chunkType: z.enum(["function", "class", "method", "interface", "type", "enum", "struct", "impl", "trait", "module", "other"]).optional().describe("Filter by code chunk type"),
|
|
10657
10703
|
contextLines: z.number().optional().describe("Number of extra lines to include before/after each match (default: 0)")
|
|
10658
10704
|
},
|
|
10659
|
-
async execute(args) {
|
|
10660
|
-
const indexer =
|
|
10705
|
+
async execute(args, context) {
|
|
10706
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10661
10707
|
const results = await indexer.search(args.query, args.limit ?? 5, {
|
|
10662
10708
|
fileType: args.fileType,
|
|
10663
10709
|
directory: args.directory,
|
|
@@ -10678,8 +10724,8 @@ var implementation_lookup = tool({
|
|
|
10678
10724
|
fileType: z.string().optional().describe("Filter by file extension (e.g., 'ts', 'py')"),
|
|
10679
10725
|
directory: z.string().optional().describe("Filter by directory path (e.g., 'src/utils')")
|
|
10680
10726
|
},
|
|
10681
|
-
async execute(args) {
|
|
10682
|
-
const indexer =
|
|
10727
|
+
async execute(args, context) {
|
|
10728
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10683
10729
|
const results = await indexer.search(args.query, args.limit ?? 5, {
|
|
10684
10730
|
fileType: args.fileType,
|
|
10685
10731
|
directory: args.directory,
|
|
@@ -10695,8 +10741,8 @@ var call_graph = tool({
|
|
|
10695
10741
|
direction: z.enum(["callers", "callees"]).default("callers").describe("Direction: 'callers' finds who calls this function, 'callees' finds what this function calls"),
|
|
10696
10742
|
symbolId: z.string().optional().describe("Symbol ID (required for 'callees' direction, returned by previous call_graph queries)")
|
|
10697
10743
|
},
|
|
10698
|
-
async execute(args) {
|
|
10699
|
-
const indexer =
|
|
10744
|
+
async execute(args, context) {
|
|
10745
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10700
10746
|
if (args.direction === "callees") {
|
|
10701
10747
|
if (!args.symbolId) {
|
|
10702
10748
|
return "Error: 'symbolId' is required when direction is 'callees'. First use direction='callers' to find the symbol ID.";
|
|
@@ -10725,10 +10771,11 @@ var add_knowledge_base = tool({
|
|
|
10725
10771
|
args: {
|
|
10726
10772
|
path: z.string().describe("Path to the folder to add as a knowledge base (absolute or relative to project root)")
|
|
10727
10773
|
},
|
|
10728
|
-
async execute(args) {
|
|
10774
|
+
async execute(args, context) {
|
|
10775
|
+
const projectRoot = context?.worktree || defaultProjectRoot;
|
|
10729
10776
|
const inputPath = args.path.trim();
|
|
10730
10777
|
const normalizedPath = path15.resolve(
|
|
10731
|
-
path15.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath,
|
|
10778
|
+
path15.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, projectRoot)
|
|
10732
10779
|
);
|
|
10733
10780
|
if (!existsSync9(normalizedPath)) {
|
|
10734
10781
|
return `Error: Directory does not exist: ${normalizedPath}`;
|
|
@@ -10770,21 +10817,21 @@ var add_knowledge_base = tool({
|
|
|
10770
10817
|
} catch (error) {
|
|
10771
10818
|
return `Error: Cannot access directory: ${normalizedPath} - ${error instanceof Error ? error.message : String(error)}`;
|
|
10772
10819
|
}
|
|
10773
|
-
const config = loadEditableConfig(
|
|
10820
|
+
const config = loadEditableConfig(projectRoot);
|
|
10774
10821
|
const knowledgeBases = ensureStringArray(config.knowledgeBases);
|
|
10775
|
-
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases, normalizedPath,
|
|
10822
|
+
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases, normalizedPath, projectRoot);
|
|
10776
10823
|
if (alreadyExists) {
|
|
10777
10824
|
return `Knowledge base already configured: ${normalizedPath}`;
|
|
10778
10825
|
}
|
|
10779
10826
|
knowledgeBases.push(normalizedPath);
|
|
10780
10827
|
config.knowledgeBases = knowledgeBases;
|
|
10781
|
-
saveConfig(
|
|
10782
|
-
|
|
10828
|
+
saveConfig(projectRoot, config);
|
|
10829
|
+
refreshIndexerForDirectory(projectRoot);
|
|
10783
10830
|
let result = `${normalizedPath}
|
|
10784
10831
|
`;
|
|
10785
10832
|
result += `Total knowledge bases: ${knowledgeBases.length}
|
|
10786
10833
|
`;
|
|
10787
|
-
result += `Config saved to: ${getConfigPath(
|
|
10834
|
+
result += `Config saved to: ${getConfigPath(projectRoot)}
|
|
10788
10835
|
`;
|
|
10789
10836
|
result += `
|
|
10790
10837
|
Run /index to rebuild the index with the new knowledge base.`;
|
|
@@ -10794,8 +10841,9 @@ Run /index to rebuild the index with the new knowledge base.`;
|
|
|
10794
10841
|
var list_knowledge_bases = tool({
|
|
10795
10842
|
description: "List all configured knowledge base folders that are indexed alongside the main project.",
|
|
10796
10843
|
args: {},
|
|
10797
|
-
async execute() {
|
|
10798
|
-
const
|
|
10844
|
+
async execute(_args, context) {
|
|
10845
|
+
const projectRoot = context?.worktree || defaultProjectRoot;
|
|
10846
|
+
const config = loadRuntimeConfig(projectRoot);
|
|
10799
10847
|
const knowledgeBases = ensureStringArray(config.knowledgeBases);
|
|
10800
10848
|
if (knowledgeBases.length === 0) {
|
|
10801
10849
|
return "No knowledge bases configured. Use add_knowledge_base to add folders.";
|
|
@@ -10805,7 +10853,7 @@ var list_knowledge_bases = tool({
|
|
|
10805
10853
|
`;
|
|
10806
10854
|
for (let i = 0; i < knowledgeBases.length; i++) {
|
|
10807
10855
|
const kb = knowledgeBases[i];
|
|
10808
|
-
const resolvedPath = resolveKnowledgeBasePath(kb,
|
|
10856
|
+
const resolvedPath = resolveKnowledgeBasePath(kb, projectRoot);
|
|
10809
10857
|
const exists = existsSync9(resolvedPath);
|
|
10810
10858
|
result += `[${i + 1}] ${kb}
|
|
10811
10859
|
`;
|
|
@@ -10823,7 +10871,7 @@ var list_knowledge_bases = tool({
|
|
|
10823
10871
|
}
|
|
10824
10872
|
result += "\n";
|
|
10825
10873
|
}
|
|
10826
|
-
result += `Config file: ${getConfigPath(
|
|
10874
|
+
result += `Config file: ${getConfigPath(projectRoot)}`;
|
|
10827
10875
|
return result;
|
|
10828
10876
|
}
|
|
10829
10877
|
});
|
|
@@ -10832,14 +10880,15 @@ var remove_knowledge_base = tool({
|
|
|
10832
10880
|
args: {
|
|
10833
10881
|
path: z.string().describe("Path of the knowledge base to remove (must match the configured path exactly)")
|
|
10834
10882
|
},
|
|
10835
|
-
async execute(args) {
|
|
10883
|
+
async execute(args, context) {
|
|
10884
|
+
const projectRoot = context?.worktree || defaultProjectRoot;
|
|
10836
10885
|
const inputPath = args.path.trim();
|
|
10837
|
-
const config = loadEditableConfig(
|
|
10886
|
+
const config = loadEditableConfig(projectRoot);
|
|
10838
10887
|
const knowledgeBases = ensureStringArray(config.knowledgeBases);
|
|
10839
10888
|
if (knowledgeBases.length === 0) {
|
|
10840
10889
|
return "No knowledge bases configured.";
|
|
10841
10890
|
}
|
|
10842
|
-
const index = findKnowledgeBasePathIndex(knowledgeBases, inputPath,
|
|
10891
|
+
const index = findKnowledgeBasePathIndex(knowledgeBases, inputPath, projectRoot);
|
|
10843
10892
|
if (index === -1) {
|
|
10844
10893
|
let result2 = `Knowledge base not found: ${inputPath}
|
|
10845
10894
|
|
|
@@ -10854,14 +10903,14 @@ var remove_knowledge_base = tool({
|
|
|
10854
10903
|
}
|
|
10855
10904
|
const removed = knowledgeBases.splice(index, 1)[0];
|
|
10856
10905
|
config.knowledgeBases = knowledgeBases;
|
|
10857
|
-
saveConfig(
|
|
10858
|
-
|
|
10906
|
+
saveConfig(projectRoot, config);
|
|
10907
|
+
refreshIndexerForDirectory(projectRoot);
|
|
10859
10908
|
let result = `Removed: ${removed}
|
|
10860
10909
|
|
|
10861
10910
|
`;
|
|
10862
10911
|
result += `Remaining knowledge bases: ${knowledgeBases.length}
|
|
10863
10912
|
`;
|
|
10864
|
-
result += `Config saved to: ${getConfigPath(
|
|
10913
|
+
result += `Config saved to: ${getConfigPath(projectRoot)}
|
|
10865
10914
|
`;
|
|
10866
10915
|
result += `
|
|
10867
10916
|
Run /index to rebuild the index without the removed knowledge base.`;
|
|
@@ -11204,10 +11253,16 @@ var RoutingHintController = class {
|
|
|
11204
11253
|
};
|
|
11205
11254
|
|
|
11206
11255
|
// src/index.ts
|
|
11207
|
-
var
|
|
11208
|
-
function replaceActiveWatcher(nextWatcher) {
|
|
11209
|
-
|
|
11210
|
-
|
|
11256
|
+
var activeWatchers = /* @__PURE__ */ new Map();
|
|
11257
|
+
function replaceActiveWatcher(projectRoot, nextWatcher) {
|
|
11258
|
+
const existing = activeWatchers.get(projectRoot);
|
|
11259
|
+
if (existing) {
|
|
11260
|
+
existing.stop();
|
|
11261
|
+
activeWatchers.delete(projectRoot);
|
|
11262
|
+
}
|
|
11263
|
+
if (nextWatcher) {
|
|
11264
|
+
activeWatchers.set(projectRoot, nextWatcher);
|
|
11265
|
+
}
|
|
11211
11266
|
}
|
|
11212
11267
|
function getCommandsDir() {
|
|
11213
11268
|
let currentDir = process.cwd();
|
|
@@ -11216,21 +11271,37 @@ function getCommandsDir() {
|
|
|
11216
11271
|
}
|
|
11217
11272
|
return path17.join(currentDir, "..", "commands");
|
|
11218
11273
|
}
|
|
11219
|
-
|
|
11274
|
+
function appendRoutingHints(output, hints, preferredRole) {
|
|
11275
|
+
const preferredBucket = preferredRole === "developer" ? output.developer : output.system;
|
|
11276
|
+
if (Array.isArray(preferredBucket)) {
|
|
11277
|
+
preferredBucket.push(...hints);
|
|
11278
|
+
return;
|
|
11279
|
+
}
|
|
11280
|
+
if (Array.isArray(output.system)) {
|
|
11281
|
+
output.system.push(...hints);
|
|
11282
|
+
}
|
|
11283
|
+
}
|
|
11284
|
+
var plugin = async ({ directory, worktree }) => {
|
|
11220
11285
|
try {
|
|
11221
|
-
const projectRoot = directory;
|
|
11286
|
+
const projectRoot = worktree || directory;
|
|
11222
11287
|
const rawConfig = loadMergedConfig(projectRoot);
|
|
11223
11288
|
const config = parseConfig(rawConfig);
|
|
11224
11289
|
initializeTools(projectRoot, config);
|
|
11225
|
-
const
|
|
11226
|
-
const routingHints = config.search.routingHints ? new RoutingHintController(() =>
|
|
11227
|
-
const
|
|
11228
|
-
|
|
11290
|
+
const getProjectIndexer = () => getIndexerForProject(projectRoot);
|
|
11291
|
+
const routingHints = config.search.routingHints ? new RoutingHintController(() => getProjectIndexer().getStatus()) : null;
|
|
11292
|
+
const isHomeDir = path17.resolve(projectRoot) === path17.resolve(os6.homedir());
|
|
11293
|
+
const isValidProject = !isHomeDir && (!config.indexing.requireProjectMarker || hasProjectMarker(projectRoot));
|
|
11294
|
+
if (isHomeDir) {
|
|
11295
|
+
console.warn(
|
|
11296
|
+
`[codebase-index] Refusing to watch or index home directory "${projectRoot}". Open a specific project directory instead.`
|
|
11297
|
+
);
|
|
11298
|
+
} else if (!isValidProject) {
|
|
11229
11299
|
console.warn(
|
|
11230
11300
|
`[codebase-index] Skipping file watching and auto-indexing: no project marker found in "${projectRoot}". Set "indexing.requireProjectMarker": false in config to override.`
|
|
11231
11301
|
);
|
|
11232
11302
|
}
|
|
11233
11303
|
if (config.indexing.autoIndex && isValidProject) {
|
|
11304
|
+
const indexer = getProjectIndexer();
|
|
11234
11305
|
indexer.initialize().then(() => {
|
|
11235
11306
|
indexer.index().catch(() => {
|
|
11236
11307
|
});
|
|
@@ -11238,9 +11309,9 @@ var plugin = async ({ directory }) => {
|
|
|
11238
11309
|
});
|
|
11239
11310
|
}
|
|
11240
11311
|
if (config.indexing.watchFiles && isValidProject) {
|
|
11241
|
-
replaceActiveWatcher(createWatcherWithIndexer(
|
|
11312
|
+
replaceActiveWatcher(projectRoot, createWatcherWithIndexer(getProjectIndexer, projectRoot, config));
|
|
11242
11313
|
} else {
|
|
11243
|
-
replaceActiveWatcher(null);
|
|
11314
|
+
replaceActiveWatcher(projectRoot, null);
|
|
11244
11315
|
}
|
|
11245
11316
|
return {
|
|
11246
11317
|
tool: {
|
|
@@ -11262,8 +11333,18 @@ var plugin = async ({ directory }) => {
|
|
|
11262
11333
|
routingHints?.observeUserMessage(input.sessionID, output.parts);
|
|
11263
11334
|
},
|
|
11264
11335
|
async "experimental.chat.system.transform"(input, output) {
|
|
11336
|
+
if (config.search.routingHintRole !== "system") {
|
|
11337
|
+
return;
|
|
11338
|
+
}
|
|
11265
11339
|
const hints = await routingHints?.getSystemHints(input.sessionID) ?? [];
|
|
11266
|
-
output
|
|
11340
|
+
appendRoutingHints(output, hints, "system");
|
|
11341
|
+
},
|
|
11342
|
+
async "experimental.chat.developer.transform"(input, output) {
|
|
11343
|
+
if (config.search.routingHintRole !== "developer") {
|
|
11344
|
+
return;
|
|
11345
|
+
}
|
|
11346
|
+
const hints = await routingHints?.getSystemHints(input.sessionID) ?? [];
|
|
11347
|
+
appendRoutingHints(output, hints, "developer");
|
|
11267
11348
|
},
|
|
11268
11349
|
async "tool.execute.after"(input) {
|
|
11269
11350
|
routingHints?.markToolUsed(input.sessionID, input.tool);
|
|
@@ -11277,8 +11358,8 @@ var plugin = async ({ directory }) => {
|
|
|
11277
11358
|
}
|
|
11278
11359
|
}
|
|
11279
11360
|
};
|
|
11280
|
-
} catch
|
|
11281
|
-
console.error("[codebase-index] Failed to initialize plugin
|
|
11361
|
+
} catch {
|
|
11362
|
+
console.error("[codebase-index] Failed to initialize plugin (check config and network)");
|
|
11282
11363
|
return {
|
|
11283
11364
|
tool: void 0,
|
|
11284
11365
|
async config() {
|