opencode-codebase-index 0.10.0 → 0.12.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 +42 -3
- package/commands/call-graph.md +9 -5
- package/commands/pr-impact.md +23 -0
- package/dist/cli.cjs +635 -178
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +635 -178
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +805 -338
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +805 -338
- 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.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 +4 -3
- package/skill/SKILL.md +6 -3
package/dist/index.js
CHANGED
|
@@ -7,7 +7,11 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
9
|
var __commonJS = (cb, mod) => function __require() {
|
|
10
|
-
|
|
10
|
+
try {
|
|
11
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
throw mod = 0, e;
|
|
14
|
+
}
|
|
11
15
|
};
|
|
12
16
|
var __copyProps = (to, from, except, desc) => {
|
|
13
17
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -324,7 +328,7 @@ var require_ignore = __commonJS({
|
|
|
324
328
|
// path matching.
|
|
325
329
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
326
330
|
// @returns {TestResult} true if a file is ignored
|
|
327
|
-
test(
|
|
331
|
+
test(path19, checkUnignored, mode) {
|
|
328
332
|
let ignored = false;
|
|
329
333
|
let unignored = false;
|
|
330
334
|
let matchedRule;
|
|
@@ -333,7 +337,7 @@ var require_ignore = __commonJS({
|
|
|
333
337
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
334
338
|
return;
|
|
335
339
|
}
|
|
336
|
-
const matched = rule[mode].test(
|
|
340
|
+
const matched = rule[mode].test(path19);
|
|
337
341
|
if (!matched) {
|
|
338
342
|
return;
|
|
339
343
|
}
|
|
@@ -354,17 +358,17 @@ var require_ignore = __commonJS({
|
|
|
354
358
|
var throwError = (message, Ctor) => {
|
|
355
359
|
throw new Ctor(message);
|
|
356
360
|
};
|
|
357
|
-
var checkPath = (
|
|
358
|
-
if (!isString(
|
|
361
|
+
var checkPath = (path19, originalPath, doThrow) => {
|
|
362
|
+
if (!isString(path19)) {
|
|
359
363
|
return doThrow(
|
|
360
364
|
`path must be a string, but got \`${originalPath}\``,
|
|
361
365
|
TypeError
|
|
362
366
|
);
|
|
363
367
|
}
|
|
364
|
-
if (!
|
|
368
|
+
if (!path19) {
|
|
365
369
|
return doThrow(`path must not be empty`, TypeError);
|
|
366
370
|
}
|
|
367
|
-
if (checkPath.isNotRelative(
|
|
371
|
+
if (checkPath.isNotRelative(path19)) {
|
|
368
372
|
const r = "`path.relative()`d";
|
|
369
373
|
return doThrow(
|
|
370
374
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -373,7 +377,7 @@ var require_ignore = __commonJS({
|
|
|
373
377
|
}
|
|
374
378
|
return true;
|
|
375
379
|
};
|
|
376
|
-
var isNotRelative = (
|
|
380
|
+
var isNotRelative = (path19) => REGEX_TEST_INVALID_PATH.test(path19);
|
|
377
381
|
checkPath.isNotRelative = isNotRelative;
|
|
378
382
|
checkPath.convert = (p) => p;
|
|
379
383
|
var Ignore2 = class {
|
|
@@ -403,19 +407,19 @@ var require_ignore = __commonJS({
|
|
|
403
407
|
}
|
|
404
408
|
// @returns {TestResult}
|
|
405
409
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
406
|
-
const
|
|
410
|
+
const path19 = originalPath && checkPath.convert(originalPath);
|
|
407
411
|
checkPath(
|
|
408
|
-
|
|
412
|
+
path19,
|
|
409
413
|
originalPath,
|
|
410
414
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
411
415
|
);
|
|
412
|
-
return this._t(
|
|
416
|
+
return this._t(path19, cache, checkUnignored, slices);
|
|
413
417
|
}
|
|
414
|
-
checkIgnore(
|
|
415
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
416
|
-
return this.test(
|
|
418
|
+
checkIgnore(path19) {
|
|
419
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path19)) {
|
|
420
|
+
return this.test(path19);
|
|
417
421
|
}
|
|
418
|
-
const slices =
|
|
422
|
+
const slices = path19.split(SLASH2).filter(Boolean);
|
|
419
423
|
slices.pop();
|
|
420
424
|
if (slices.length) {
|
|
421
425
|
const parent = this._t(
|
|
@@ -428,18 +432,18 @@ var require_ignore = __commonJS({
|
|
|
428
432
|
return parent;
|
|
429
433
|
}
|
|
430
434
|
}
|
|
431
|
-
return this._rules.test(
|
|
435
|
+
return this._rules.test(path19, false, MODE_CHECK_IGNORE);
|
|
432
436
|
}
|
|
433
|
-
_t(
|
|
434
|
-
if (
|
|
435
|
-
return cache[
|
|
437
|
+
_t(path19, cache, checkUnignored, slices) {
|
|
438
|
+
if (path19 in cache) {
|
|
439
|
+
return cache[path19];
|
|
436
440
|
}
|
|
437
441
|
if (!slices) {
|
|
438
|
-
slices =
|
|
442
|
+
slices = path19.split(SLASH2).filter(Boolean);
|
|
439
443
|
}
|
|
440
444
|
slices.pop();
|
|
441
445
|
if (!slices.length) {
|
|
442
|
-
return cache[
|
|
446
|
+
return cache[path19] = this._rules.test(path19, checkUnignored, MODE_IGNORE);
|
|
443
447
|
}
|
|
444
448
|
const parent = this._t(
|
|
445
449
|
slices.join(SLASH2) + SLASH2,
|
|
@@ -447,29 +451,29 @@ var require_ignore = __commonJS({
|
|
|
447
451
|
checkUnignored,
|
|
448
452
|
slices
|
|
449
453
|
);
|
|
450
|
-
return cache[
|
|
454
|
+
return cache[path19] = parent.ignored ? parent : this._rules.test(path19, checkUnignored, MODE_IGNORE);
|
|
451
455
|
}
|
|
452
|
-
ignores(
|
|
453
|
-
return this._test(
|
|
456
|
+
ignores(path19) {
|
|
457
|
+
return this._test(path19, this._ignoreCache, false).ignored;
|
|
454
458
|
}
|
|
455
459
|
createFilter() {
|
|
456
|
-
return (
|
|
460
|
+
return (path19) => !this.ignores(path19);
|
|
457
461
|
}
|
|
458
462
|
filter(paths) {
|
|
459
463
|
return makeArray(paths).filter(this.createFilter());
|
|
460
464
|
}
|
|
461
465
|
// @returns {TestResult}
|
|
462
|
-
test(
|
|
463
|
-
return this._test(
|
|
466
|
+
test(path19) {
|
|
467
|
+
return this._test(path19, this._testCache, true);
|
|
464
468
|
}
|
|
465
469
|
};
|
|
466
470
|
var factory = (options) => new Ignore2(options);
|
|
467
|
-
var isPathValid = (
|
|
471
|
+
var isPathValid = (path19) => checkPath(path19 && checkPath.convert(path19), path19, RETURN_FALSE);
|
|
468
472
|
var setupWindows = () => {
|
|
469
473
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
470
474
|
checkPath.convert = makePosix;
|
|
471
475
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
472
|
-
checkPath.isNotRelative = (
|
|
476
|
+
checkPath.isNotRelative = (path19) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path19) || isNotRelative(path19);
|
|
473
477
|
};
|
|
474
478
|
if (
|
|
475
479
|
// Detect `process` so that it can run in browsers.
|
|
@@ -648,7 +652,7 @@ var require_eventemitter3 = __commonJS({
|
|
|
648
652
|
|
|
649
653
|
// src/index.ts
|
|
650
654
|
import * as os6 from "os";
|
|
651
|
-
import * as
|
|
655
|
+
import * as path18 from "path";
|
|
652
656
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
653
657
|
|
|
654
658
|
// src/config/constants.ts
|
|
@@ -795,6 +799,7 @@ function getDefaultSearchConfig() {
|
|
|
795
799
|
rerankTopN: 20,
|
|
796
800
|
contextLines: 0,
|
|
797
801
|
routingHints: true,
|
|
802
|
+
routingGraphHandoffHints: false,
|
|
798
803
|
routingHintRole: "system"
|
|
799
804
|
};
|
|
800
805
|
}
|
|
@@ -917,6 +922,7 @@ function parseConfig(raw) {
|
|
|
917
922
|
rerankTopN: typeof rawSearch.rerankTopN === "number" ? Math.min(200, Math.max(0, Math.floor(rawSearch.rerankTopN))) : defaultSearch.rerankTopN,
|
|
918
923
|
contextLines: typeof rawSearch.contextLines === "number" ? Math.min(50, Math.max(0, rawSearch.contextLines)) : defaultSearch.contextLines,
|
|
919
924
|
routingHints: typeof rawSearch.routingHints === "boolean" ? rawSearch.routingHints : defaultSearch.routingHints,
|
|
925
|
+
routingGraphHandoffHints: typeof rawSearch.routingGraphHandoffHints === "boolean" ? rawSearch.routingGraphHandoffHints : defaultSearch.routingGraphHandoffHints,
|
|
920
926
|
routingHintRole: rawSearch.routingHintRole === "developer" || rawSearch.routingHintRole === "system" ? rawSearch.routingHintRole : defaultSearch.routingHintRole
|
|
921
927
|
};
|
|
922
928
|
const rawDebug = input.debug && typeof input.debug === "object" ? input.debug : {};
|
|
@@ -1543,7 +1549,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
1543
1549
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
1544
1550
|
const statMethod = opts.lstat ? lstat : stat;
|
|
1545
1551
|
if (wantBigintFsStats) {
|
|
1546
|
-
this._stat = (
|
|
1552
|
+
this._stat = (path19) => statMethod(path19, { bigint: true });
|
|
1547
1553
|
} else {
|
|
1548
1554
|
this._stat = statMethod;
|
|
1549
1555
|
}
|
|
@@ -1568,8 +1574,8 @@ var ReaddirpStream = class extends Readable {
|
|
|
1568
1574
|
const par = this.parent;
|
|
1569
1575
|
const fil = par && par.files;
|
|
1570
1576
|
if (fil && fil.length > 0) {
|
|
1571
|
-
const { path:
|
|
1572
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
1577
|
+
const { path: path19, depth } = par;
|
|
1578
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path19));
|
|
1573
1579
|
const awaited = await Promise.all(slice);
|
|
1574
1580
|
for (const entry of awaited) {
|
|
1575
1581
|
if (!entry)
|
|
@@ -1609,20 +1615,20 @@ var ReaddirpStream = class extends Readable {
|
|
|
1609
1615
|
this.reading = false;
|
|
1610
1616
|
}
|
|
1611
1617
|
}
|
|
1612
|
-
async _exploreDir(
|
|
1618
|
+
async _exploreDir(path19, depth) {
|
|
1613
1619
|
let files;
|
|
1614
1620
|
try {
|
|
1615
|
-
files = await readdir(
|
|
1621
|
+
files = await readdir(path19, this._rdOptions);
|
|
1616
1622
|
} catch (error) {
|
|
1617
1623
|
this._onError(error);
|
|
1618
1624
|
}
|
|
1619
|
-
return { files, depth, path:
|
|
1625
|
+
return { files, depth, path: path19 };
|
|
1620
1626
|
}
|
|
1621
|
-
async _formatEntry(dirent,
|
|
1627
|
+
async _formatEntry(dirent, path19) {
|
|
1622
1628
|
let entry;
|
|
1623
1629
|
const basename5 = this._isDirent ? dirent.name : dirent;
|
|
1624
1630
|
try {
|
|
1625
|
-
const fullPath = presolve(pjoin(
|
|
1631
|
+
const fullPath = presolve(pjoin(path19, basename5));
|
|
1626
1632
|
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename5 };
|
|
1627
1633
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
1628
1634
|
} catch (err) {
|
|
@@ -2022,16 +2028,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
2022
2028
|
};
|
|
2023
2029
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
2024
2030
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
2025
|
-
function createFsWatchInstance(
|
|
2031
|
+
function createFsWatchInstance(path19, options, listener, errHandler, emitRaw) {
|
|
2026
2032
|
const handleEvent = (rawEvent, evPath) => {
|
|
2027
|
-
listener(
|
|
2028
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
2029
|
-
if (evPath &&
|
|
2030
|
-
fsWatchBroadcast(sp.resolve(
|
|
2033
|
+
listener(path19);
|
|
2034
|
+
emitRaw(rawEvent, evPath, { watchedPath: path19 });
|
|
2035
|
+
if (evPath && path19 !== evPath) {
|
|
2036
|
+
fsWatchBroadcast(sp.resolve(path19, evPath), KEY_LISTENERS, sp.join(path19, evPath));
|
|
2031
2037
|
}
|
|
2032
2038
|
};
|
|
2033
2039
|
try {
|
|
2034
|
-
return fs_watch(
|
|
2040
|
+
return fs_watch(path19, {
|
|
2035
2041
|
persistent: options.persistent
|
|
2036
2042
|
}, handleEvent);
|
|
2037
2043
|
} catch (error) {
|
|
@@ -2047,12 +2053,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
2047
2053
|
listener(val1, val2, val3);
|
|
2048
2054
|
});
|
|
2049
2055
|
};
|
|
2050
|
-
var setFsWatchListener = (
|
|
2056
|
+
var setFsWatchListener = (path19, fullPath, options, handlers) => {
|
|
2051
2057
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
2052
2058
|
let cont = FsWatchInstances.get(fullPath);
|
|
2053
2059
|
let watcher;
|
|
2054
2060
|
if (!options.persistent) {
|
|
2055
|
-
watcher = createFsWatchInstance(
|
|
2061
|
+
watcher = createFsWatchInstance(path19, options, listener, errHandler, rawEmitter);
|
|
2056
2062
|
if (!watcher)
|
|
2057
2063
|
return;
|
|
2058
2064
|
return watcher.close.bind(watcher);
|
|
@@ -2063,7 +2069,7 @@ var setFsWatchListener = (path18, fullPath, options, handlers) => {
|
|
|
2063
2069
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
2064
2070
|
} else {
|
|
2065
2071
|
watcher = createFsWatchInstance(
|
|
2066
|
-
|
|
2072
|
+
path19,
|
|
2067
2073
|
options,
|
|
2068
2074
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
2069
2075
|
errHandler,
|
|
@@ -2078,7 +2084,7 @@ var setFsWatchListener = (path18, fullPath, options, handlers) => {
|
|
|
2078
2084
|
cont.watcherUnusable = true;
|
|
2079
2085
|
if (isWindows && error.code === "EPERM") {
|
|
2080
2086
|
try {
|
|
2081
|
-
const fd = await open(
|
|
2087
|
+
const fd = await open(path19, "r");
|
|
2082
2088
|
await fd.close();
|
|
2083
2089
|
broadcastErr(error);
|
|
2084
2090
|
} catch (err) {
|
|
@@ -2109,7 +2115,7 @@ var setFsWatchListener = (path18, fullPath, options, handlers) => {
|
|
|
2109
2115
|
};
|
|
2110
2116
|
};
|
|
2111
2117
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
2112
|
-
var setFsWatchFileListener = (
|
|
2118
|
+
var setFsWatchFileListener = (path19, fullPath, options, handlers) => {
|
|
2113
2119
|
const { listener, rawEmitter } = handlers;
|
|
2114
2120
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
2115
2121
|
const copts = cont && cont.options;
|
|
@@ -2131,7 +2137,7 @@ var setFsWatchFileListener = (path18, fullPath, options, handlers) => {
|
|
|
2131
2137
|
});
|
|
2132
2138
|
const currmtime = curr.mtimeMs;
|
|
2133
2139
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
2134
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
2140
|
+
foreach(cont.listeners, (listener2) => listener2(path19, curr));
|
|
2135
2141
|
}
|
|
2136
2142
|
})
|
|
2137
2143
|
};
|
|
@@ -2161,13 +2167,13 @@ var NodeFsHandler = class {
|
|
|
2161
2167
|
* @param listener on fs change
|
|
2162
2168
|
* @returns closer for the watcher instance
|
|
2163
2169
|
*/
|
|
2164
|
-
_watchWithNodeFs(
|
|
2170
|
+
_watchWithNodeFs(path19, listener) {
|
|
2165
2171
|
const opts = this.fsw.options;
|
|
2166
|
-
const directory = sp.dirname(
|
|
2167
|
-
const basename5 = sp.basename(
|
|
2172
|
+
const directory = sp.dirname(path19);
|
|
2173
|
+
const basename5 = sp.basename(path19);
|
|
2168
2174
|
const parent = this.fsw._getWatchedDir(directory);
|
|
2169
2175
|
parent.add(basename5);
|
|
2170
|
-
const absolutePath = sp.resolve(
|
|
2176
|
+
const absolutePath = sp.resolve(path19);
|
|
2171
2177
|
const options = {
|
|
2172
2178
|
persistent: opts.persistent
|
|
2173
2179
|
};
|
|
@@ -2177,12 +2183,12 @@ var NodeFsHandler = class {
|
|
|
2177
2183
|
if (opts.usePolling) {
|
|
2178
2184
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
2179
2185
|
options.interval = enableBin && isBinaryPath(basename5) ? opts.binaryInterval : opts.interval;
|
|
2180
|
-
closer = setFsWatchFileListener(
|
|
2186
|
+
closer = setFsWatchFileListener(path19, absolutePath, options, {
|
|
2181
2187
|
listener,
|
|
2182
2188
|
rawEmitter: this.fsw._emitRaw
|
|
2183
2189
|
});
|
|
2184
2190
|
} else {
|
|
2185
|
-
closer = setFsWatchListener(
|
|
2191
|
+
closer = setFsWatchListener(path19, absolutePath, options, {
|
|
2186
2192
|
listener,
|
|
2187
2193
|
errHandler: this._boundHandleError,
|
|
2188
2194
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -2204,7 +2210,7 @@ var NodeFsHandler = class {
|
|
|
2204
2210
|
let prevStats = stats;
|
|
2205
2211
|
if (parent.has(basename5))
|
|
2206
2212
|
return;
|
|
2207
|
-
const listener = async (
|
|
2213
|
+
const listener = async (path19, newStats) => {
|
|
2208
2214
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
2209
2215
|
return;
|
|
2210
2216
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -2218,11 +2224,11 @@ var NodeFsHandler = class {
|
|
|
2218
2224
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
2219
2225
|
}
|
|
2220
2226
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
2221
|
-
this.fsw._closeFile(
|
|
2227
|
+
this.fsw._closeFile(path19);
|
|
2222
2228
|
prevStats = newStats2;
|
|
2223
2229
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
2224
2230
|
if (closer2)
|
|
2225
|
-
this.fsw._addPathCloser(
|
|
2231
|
+
this.fsw._addPathCloser(path19, closer2);
|
|
2226
2232
|
} else {
|
|
2227
2233
|
prevStats = newStats2;
|
|
2228
2234
|
}
|
|
@@ -2254,7 +2260,7 @@ var NodeFsHandler = class {
|
|
|
2254
2260
|
* @param item basename of this item
|
|
2255
2261
|
* @returns true if no more processing is needed for this entry.
|
|
2256
2262
|
*/
|
|
2257
|
-
async _handleSymlink(entry, directory,
|
|
2263
|
+
async _handleSymlink(entry, directory, path19, item) {
|
|
2258
2264
|
if (this.fsw.closed) {
|
|
2259
2265
|
return;
|
|
2260
2266
|
}
|
|
@@ -2264,7 +2270,7 @@ var NodeFsHandler = class {
|
|
|
2264
2270
|
this.fsw._incrReadyCount();
|
|
2265
2271
|
let linkPath;
|
|
2266
2272
|
try {
|
|
2267
|
-
linkPath = await fsrealpath(
|
|
2273
|
+
linkPath = await fsrealpath(path19);
|
|
2268
2274
|
} catch (e) {
|
|
2269
2275
|
this.fsw._emitReady();
|
|
2270
2276
|
return true;
|
|
@@ -2274,12 +2280,12 @@ var NodeFsHandler = class {
|
|
|
2274
2280
|
if (dir.has(item)) {
|
|
2275
2281
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
2276
2282
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
2277
|
-
this.fsw._emit(EV.CHANGE,
|
|
2283
|
+
this.fsw._emit(EV.CHANGE, path19, entry.stats);
|
|
2278
2284
|
}
|
|
2279
2285
|
} else {
|
|
2280
2286
|
dir.add(item);
|
|
2281
2287
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
2282
|
-
this.fsw._emit(EV.ADD,
|
|
2288
|
+
this.fsw._emit(EV.ADD, path19, entry.stats);
|
|
2283
2289
|
}
|
|
2284
2290
|
this.fsw._emitReady();
|
|
2285
2291
|
return true;
|
|
@@ -2309,9 +2315,9 @@ var NodeFsHandler = class {
|
|
|
2309
2315
|
return;
|
|
2310
2316
|
}
|
|
2311
2317
|
const item = entry.path;
|
|
2312
|
-
let
|
|
2318
|
+
let path19 = sp.join(directory, item);
|
|
2313
2319
|
current.add(item);
|
|
2314
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
2320
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path19, item)) {
|
|
2315
2321
|
return;
|
|
2316
2322
|
}
|
|
2317
2323
|
if (this.fsw.closed) {
|
|
@@ -2320,11 +2326,11 @@ var NodeFsHandler = class {
|
|
|
2320
2326
|
}
|
|
2321
2327
|
if (item === target || !target && !previous.has(item)) {
|
|
2322
2328
|
this.fsw._incrReadyCount();
|
|
2323
|
-
|
|
2324
|
-
this._addToNodeFs(
|
|
2329
|
+
path19 = sp.join(dir, sp.relative(dir, path19));
|
|
2330
|
+
this._addToNodeFs(path19, initialAdd, wh, depth + 1);
|
|
2325
2331
|
}
|
|
2326
2332
|
}).on(EV.ERROR, this._boundHandleError);
|
|
2327
|
-
return new Promise((
|
|
2333
|
+
return new Promise((resolve13, reject) => {
|
|
2328
2334
|
if (!stream)
|
|
2329
2335
|
return reject();
|
|
2330
2336
|
stream.once(STR_END, () => {
|
|
@@ -2333,7 +2339,7 @@ var NodeFsHandler = class {
|
|
|
2333
2339
|
return;
|
|
2334
2340
|
}
|
|
2335
2341
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
2336
|
-
|
|
2342
|
+
resolve13(void 0);
|
|
2337
2343
|
previous.getChildren().filter((item) => {
|
|
2338
2344
|
return item !== directory && !current.has(item);
|
|
2339
2345
|
}).forEach((item) => {
|
|
@@ -2390,13 +2396,13 @@ var NodeFsHandler = class {
|
|
|
2390
2396
|
* @param depth Child path actually targeted for watch
|
|
2391
2397
|
* @param target Child path actually targeted for watch
|
|
2392
2398
|
*/
|
|
2393
|
-
async _addToNodeFs(
|
|
2399
|
+
async _addToNodeFs(path19, initialAdd, priorWh, depth, target) {
|
|
2394
2400
|
const ready = this.fsw._emitReady;
|
|
2395
|
-
if (this.fsw._isIgnored(
|
|
2401
|
+
if (this.fsw._isIgnored(path19) || this.fsw.closed) {
|
|
2396
2402
|
ready();
|
|
2397
2403
|
return false;
|
|
2398
2404
|
}
|
|
2399
|
-
const wh = this.fsw._getWatchHelpers(
|
|
2405
|
+
const wh = this.fsw._getWatchHelpers(path19);
|
|
2400
2406
|
if (priorWh) {
|
|
2401
2407
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
2402
2408
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -2412,8 +2418,8 @@ var NodeFsHandler = class {
|
|
|
2412
2418
|
const follow = this.fsw.options.followSymlinks;
|
|
2413
2419
|
let closer;
|
|
2414
2420
|
if (stats.isDirectory()) {
|
|
2415
|
-
const absPath = sp.resolve(
|
|
2416
|
-
const targetPath = follow ? await fsrealpath(
|
|
2421
|
+
const absPath = sp.resolve(path19);
|
|
2422
|
+
const targetPath = follow ? await fsrealpath(path19) : path19;
|
|
2417
2423
|
if (this.fsw.closed)
|
|
2418
2424
|
return;
|
|
2419
2425
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -2423,29 +2429,29 @@ var NodeFsHandler = class {
|
|
|
2423
2429
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
2424
2430
|
}
|
|
2425
2431
|
} else if (stats.isSymbolicLink()) {
|
|
2426
|
-
const targetPath = follow ? await fsrealpath(
|
|
2432
|
+
const targetPath = follow ? await fsrealpath(path19) : path19;
|
|
2427
2433
|
if (this.fsw.closed)
|
|
2428
2434
|
return;
|
|
2429
2435
|
const parent = sp.dirname(wh.watchPath);
|
|
2430
2436
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
2431
2437
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
2432
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
2438
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path19, wh, targetPath);
|
|
2433
2439
|
if (this.fsw.closed)
|
|
2434
2440
|
return;
|
|
2435
2441
|
if (targetPath !== void 0) {
|
|
2436
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
2442
|
+
this.fsw._symlinkPaths.set(sp.resolve(path19), targetPath);
|
|
2437
2443
|
}
|
|
2438
2444
|
} else {
|
|
2439
2445
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
2440
2446
|
}
|
|
2441
2447
|
ready();
|
|
2442
2448
|
if (closer)
|
|
2443
|
-
this.fsw._addPathCloser(
|
|
2449
|
+
this.fsw._addPathCloser(path19, closer);
|
|
2444
2450
|
return false;
|
|
2445
2451
|
} catch (error) {
|
|
2446
2452
|
if (this.fsw._handleError(error)) {
|
|
2447
2453
|
ready();
|
|
2448
|
-
return
|
|
2454
|
+
return path19;
|
|
2449
2455
|
}
|
|
2450
2456
|
}
|
|
2451
2457
|
}
|
|
@@ -2477,35 +2483,35 @@ function createPattern(matcher) {
|
|
|
2477
2483
|
if (matcher.path === string)
|
|
2478
2484
|
return true;
|
|
2479
2485
|
if (matcher.recursive) {
|
|
2480
|
-
const
|
|
2481
|
-
if (!
|
|
2486
|
+
const relative9 = sp2.relative(matcher.path, string);
|
|
2487
|
+
if (!relative9) {
|
|
2482
2488
|
return false;
|
|
2483
2489
|
}
|
|
2484
|
-
return !
|
|
2490
|
+
return !relative9.startsWith("..") && !sp2.isAbsolute(relative9);
|
|
2485
2491
|
}
|
|
2486
2492
|
return false;
|
|
2487
2493
|
};
|
|
2488
2494
|
}
|
|
2489
2495
|
return () => false;
|
|
2490
2496
|
}
|
|
2491
|
-
function normalizePath(
|
|
2492
|
-
if (typeof
|
|
2497
|
+
function normalizePath(path19) {
|
|
2498
|
+
if (typeof path19 !== "string")
|
|
2493
2499
|
throw new Error("string expected");
|
|
2494
|
-
|
|
2495
|
-
|
|
2500
|
+
path19 = sp2.normalize(path19);
|
|
2501
|
+
path19 = path19.replace(/\\/g, "/");
|
|
2496
2502
|
let prepend = false;
|
|
2497
|
-
if (
|
|
2503
|
+
if (path19.startsWith("//"))
|
|
2498
2504
|
prepend = true;
|
|
2499
|
-
|
|
2505
|
+
path19 = path19.replace(DOUBLE_SLASH_RE, "/");
|
|
2500
2506
|
if (prepend)
|
|
2501
|
-
|
|
2502
|
-
return
|
|
2507
|
+
path19 = "/" + path19;
|
|
2508
|
+
return path19;
|
|
2503
2509
|
}
|
|
2504
2510
|
function matchPatterns(patterns, testString, stats) {
|
|
2505
|
-
const
|
|
2511
|
+
const path19 = normalizePath(testString);
|
|
2506
2512
|
for (let index = 0; index < patterns.length; index++) {
|
|
2507
2513
|
const pattern = patterns[index];
|
|
2508
|
-
if (pattern(
|
|
2514
|
+
if (pattern(path19, stats)) {
|
|
2509
2515
|
return true;
|
|
2510
2516
|
}
|
|
2511
2517
|
}
|
|
@@ -2543,19 +2549,19 @@ var toUnix = (string) => {
|
|
|
2543
2549
|
}
|
|
2544
2550
|
return str;
|
|
2545
2551
|
};
|
|
2546
|
-
var normalizePathToUnix = (
|
|
2547
|
-
var normalizeIgnored = (cwd = "") => (
|
|
2548
|
-
if (typeof
|
|
2549
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
2552
|
+
var normalizePathToUnix = (path19) => toUnix(sp2.normalize(toUnix(path19)));
|
|
2553
|
+
var normalizeIgnored = (cwd = "") => (path19) => {
|
|
2554
|
+
if (typeof path19 === "string") {
|
|
2555
|
+
return normalizePathToUnix(sp2.isAbsolute(path19) ? path19 : sp2.join(cwd, path19));
|
|
2550
2556
|
} else {
|
|
2551
|
-
return
|
|
2557
|
+
return path19;
|
|
2552
2558
|
}
|
|
2553
2559
|
};
|
|
2554
|
-
var getAbsolutePath = (
|
|
2555
|
-
if (sp2.isAbsolute(
|
|
2556
|
-
return
|
|
2560
|
+
var getAbsolutePath = (path19, cwd) => {
|
|
2561
|
+
if (sp2.isAbsolute(path19)) {
|
|
2562
|
+
return path19;
|
|
2557
2563
|
}
|
|
2558
|
-
return sp2.join(cwd,
|
|
2564
|
+
return sp2.join(cwd, path19);
|
|
2559
2565
|
};
|
|
2560
2566
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
2561
2567
|
var DirEntry = class {
|
|
@@ -2620,10 +2626,10 @@ var WatchHelper = class {
|
|
|
2620
2626
|
dirParts;
|
|
2621
2627
|
followSymlinks;
|
|
2622
2628
|
statMethod;
|
|
2623
|
-
constructor(
|
|
2629
|
+
constructor(path19, follow, fsw) {
|
|
2624
2630
|
this.fsw = fsw;
|
|
2625
|
-
const watchPath =
|
|
2626
|
-
this.path =
|
|
2631
|
+
const watchPath = path19;
|
|
2632
|
+
this.path = path19 = path19.replace(REPLACER_RE, "");
|
|
2627
2633
|
this.watchPath = watchPath;
|
|
2628
2634
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
2629
2635
|
this.dirParts = [];
|
|
@@ -2763,20 +2769,20 @@ var FSWatcher = class extends EventEmitter {
|
|
|
2763
2769
|
this._closePromise = void 0;
|
|
2764
2770
|
let paths = unifyPaths(paths_);
|
|
2765
2771
|
if (cwd) {
|
|
2766
|
-
paths = paths.map((
|
|
2767
|
-
const absPath = getAbsolutePath(
|
|
2772
|
+
paths = paths.map((path19) => {
|
|
2773
|
+
const absPath = getAbsolutePath(path19, cwd);
|
|
2768
2774
|
return absPath;
|
|
2769
2775
|
});
|
|
2770
2776
|
}
|
|
2771
|
-
paths.forEach((
|
|
2772
|
-
this._removeIgnoredPath(
|
|
2777
|
+
paths.forEach((path19) => {
|
|
2778
|
+
this._removeIgnoredPath(path19);
|
|
2773
2779
|
});
|
|
2774
2780
|
this._userIgnored = void 0;
|
|
2775
2781
|
if (!this._readyCount)
|
|
2776
2782
|
this._readyCount = 0;
|
|
2777
2783
|
this._readyCount += paths.length;
|
|
2778
|
-
Promise.all(paths.map(async (
|
|
2779
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
2784
|
+
Promise.all(paths.map(async (path19) => {
|
|
2785
|
+
const res = await this._nodeFsHandler._addToNodeFs(path19, !_internal, void 0, 0, _origAdd);
|
|
2780
2786
|
if (res)
|
|
2781
2787
|
this._emitReady();
|
|
2782
2788
|
return res;
|
|
@@ -2798,17 +2804,17 @@ var FSWatcher = class extends EventEmitter {
|
|
|
2798
2804
|
return this;
|
|
2799
2805
|
const paths = unifyPaths(paths_);
|
|
2800
2806
|
const { cwd } = this.options;
|
|
2801
|
-
paths.forEach((
|
|
2802
|
-
if (!sp2.isAbsolute(
|
|
2807
|
+
paths.forEach((path19) => {
|
|
2808
|
+
if (!sp2.isAbsolute(path19) && !this._closers.has(path19)) {
|
|
2803
2809
|
if (cwd)
|
|
2804
|
-
|
|
2805
|
-
|
|
2810
|
+
path19 = sp2.join(cwd, path19);
|
|
2811
|
+
path19 = sp2.resolve(path19);
|
|
2806
2812
|
}
|
|
2807
|
-
this._closePath(
|
|
2808
|
-
this._addIgnoredPath(
|
|
2809
|
-
if (this._watched.has(
|
|
2813
|
+
this._closePath(path19);
|
|
2814
|
+
this._addIgnoredPath(path19);
|
|
2815
|
+
if (this._watched.has(path19)) {
|
|
2810
2816
|
this._addIgnoredPath({
|
|
2811
|
-
path:
|
|
2817
|
+
path: path19,
|
|
2812
2818
|
recursive: true
|
|
2813
2819
|
});
|
|
2814
2820
|
}
|
|
@@ -2872,38 +2878,38 @@ var FSWatcher = class extends EventEmitter {
|
|
|
2872
2878
|
* @param stats arguments to be passed with event
|
|
2873
2879
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
2874
2880
|
*/
|
|
2875
|
-
async _emit(event,
|
|
2881
|
+
async _emit(event, path19, stats) {
|
|
2876
2882
|
if (this.closed)
|
|
2877
2883
|
return;
|
|
2878
2884
|
const opts = this.options;
|
|
2879
2885
|
if (isWindows)
|
|
2880
|
-
|
|
2886
|
+
path19 = sp2.normalize(path19);
|
|
2881
2887
|
if (opts.cwd)
|
|
2882
|
-
|
|
2883
|
-
const args = [
|
|
2888
|
+
path19 = sp2.relative(opts.cwd, path19);
|
|
2889
|
+
const args = [path19];
|
|
2884
2890
|
if (stats != null)
|
|
2885
2891
|
args.push(stats);
|
|
2886
2892
|
const awf = opts.awaitWriteFinish;
|
|
2887
2893
|
let pw;
|
|
2888
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
2894
|
+
if (awf && (pw = this._pendingWrites.get(path19))) {
|
|
2889
2895
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
2890
2896
|
return this;
|
|
2891
2897
|
}
|
|
2892
2898
|
if (opts.atomic) {
|
|
2893
2899
|
if (event === EVENTS.UNLINK) {
|
|
2894
|
-
this._pendingUnlinks.set(
|
|
2900
|
+
this._pendingUnlinks.set(path19, [event, ...args]);
|
|
2895
2901
|
setTimeout(() => {
|
|
2896
|
-
this._pendingUnlinks.forEach((entry,
|
|
2902
|
+
this._pendingUnlinks.forEach((entry, path20) => {
|
|
2897
2903
|
this.emit(...entry);
|
|
2898
2904
|
this.emit(EVENTS.ALL, ...entry);
|
|
2899
|
-
this._pendingUnlinks.delete(
|
|
2905
|
+
this._pendingUnlinks.delete(path20);
|
|
2900
2906
|
});
|
|
2901
2907
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
2902
2908
|
return this;
|
|
2903
2909
|
}
|
|
2904
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
2910
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path19)) {
|
|
2905
2911
|
event = EVENTS.CHANGE;
|
|
2906
|
-
this._pendingUnlinks.delete(
|
|
2912
|
+
this._pendingUnlinks.delete(path19);
|
|
2907
2913
|
}
|
|
2908
2914
|
}
|
|
2909
2915
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -2921,16 +2927,16 @@ var FSWatcher = class extends EventEmitter {
|
|
|
2921
2927
|
this.emitWithAll(event, args);
|
|
2922
2928
|
}
|
|
2923
2929
|
};
|
|
2924
|
-
this._awaitWriteFinish(
|
|
2930
|
+
this._awaitWriteFinish(path19, awf.stabilityThreshold, event, awfEmit);
|
|
2925
2931
|
return this;
|
|
2926
2932
|
}
|
|
2927
2933
|
if (event === EVENTS.CHANGE) {
|
|
2928
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
2934
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path19, 50);
|
|
2929
2935
|
if (isThrottled)
|
|
2930
2936
|
return this;
|
|
2931
2937
|
}
|
|
2932
2938
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
2933
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
2939
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path19) : path19;
|
|
2934
2940
|
let stats2;
|
|
2935
2941
|
try {
|
|
2936
2942
|
stats2 = await stat3(fullPath);
|
|
@@ -2961,23 +2967,23 @@ var FSWatcher = class extends EventEmitter {
|
|
|
2961
2967
|
* @param timeout duration of time to suppress duplicate actions
|
|
2962
2968
|
* @returns tracking object or false if action should be suppressed
|
|
2963
2969
|
*/
|
|
2964
|
-
_throttle(actionType,
|
|
2970
|
+
_throttle(actionType, path19, timeout) {
|
|
2965
2971
|
if (!this._throttled.has(actionType)) {
|
|
2966
2972
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
2967
2973
|
}
|
|
2968
2974
|
const action = this._throttled.get(actionType);
|
|
2969
2975
|
if (!action)
|
|
2970
2976
|
throw new Error("invalid throttle");
|
|
2971
|
-
const actionPath = action.get(
|
|
2977
|
+
const actionPath = action.get(path19);
|
|
2972
2978
|
if (actionPath) {
|
|
2973
2979
|
actionPath.count++;
|
|
2974
2980
|
return false;
|
|
2975
2981
|
}
|
|
2976
2982
|
let timeoutObject;
|
|
2977
2983
|
const clear = () => {
|
|
2978
|
-
const item = action.get(
|
|
2984
|
+
const item = action.get(path19);
|
|
2979
2985
|
const count = item ? item.count : 0;
|
|
2980
|
-
action.delete(
|
|
2986
|
+
action.delete(path19);
|
|
2981
2987
|
clearTimeout(timeoutObject);
|
|
2982
2988
|
if (item)
|
|
2983
2989
|
clearTimeout(item.timeoutObject);
|
|
@@ -2985,7 +2991,7 @@ var FSWatcher = class extends EventEmitter {
|
|
|
2985
2991
|
};
|
|
2986
2992
|
timeoutObject = setTimeout(clear, timeout);
|
|
2987
2993
|
const thr = { timeoutObject, clear, count: 0 };
|
|
2988
|
-
action.set(
|
|
2994
|
+
action.set(path19, thr);
|
|
2989
2995
|
return thr;
|
|
2990
2996
|
}
|
|
2991
2997
|
_incrReadyCount() {
|
|
@@ -2999,44 +3005,44 @@ var FSWatcher = class extends EventEmitter {
|
|
|
2999
3005
|
* @param event
|
|
3000
3006
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
3001
3007
|
*/
|
|
3002
|
-
_awaitWriteFinish(
|
|
3008
|
+
_awaitWriteFinish(path19, threshold, event, awfEmit) {
|
|
3003
3009
|
const awf = this.options.awaitWriteFinish;
|
|
3004
3010
|
if (typeof awf !== "object")
|
|
3005
3011
|
return;
|
|
3006
3012
|
const pollInterval = awf.pollInterval;
|
|
3007
3013
|
let timeoutHandler;
|
|
3008
|
-
let fullPath =
|
|
3009
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
3010
|
-
fullPath = sp2.join(this.options.cwd,
|
|
3014
|
+
let fullPath = path19;
|
|
3015
|
+
if (this.options.cwd && !sp2.isAbsolute(path19)) {
|
|
3016
|
+
fullPath = sp2.join(this.options.cwd, path19);
|
|
3011
3017
|
}
|
|
3012
3018
|
const now = /* @__PURE__ */ new Date();
|
|
3013
3019
|
const writes = this._pendingWrites;
|
|
3014
3020
|
function awaitWriteFinishFn(prevStat) {
|
|
3015
3021
|
statcb(fullPath, (err, curStat) => {
|
|
3016
|
-
if (err || !writes.has(
|
|
3022
|
+
if (err || !writes.has(path19)) {
|
|
3017
3023
|
if (err && err.code !== "ENOENT")
|
|
3018
3024
|
awfEmit(err);
|
|
3019
3025
|
return;
|
|
3020
3026
|
}
|
|
3021
3027
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
3022
3028
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
3023
|
-
writes.get(
|
|
3029
|
+
writes.get(path19).lastChange = now2;
|
|
3024
3030
|
}
|
|
3025
|
-
const pw = writes.get(
|
|
3031
|
+
const pw = writes.get(path19);
|
|
3026
3032
|
const df = now2 - pw.lastChange;
|
|
3027
3033
|
if (df >= threshold) {
|
|
3028
|
-
writes.delete(
|
|
3034
|
+
writes.delete(path19);
|
|
3029
3035
|
awfEmit(void 0, curStat);
|
|
3030
3036
|
} else {
|
|
3031
3037
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
3032
3038
|
}
|
|
3033
3039
|
});
|
|
3034
3040
|
}
|
|
3035
|
-
if (!writes.has(
|
|
3036
|
-
writes.set(
|
|
3041
|
+
if (!writes.has(path19)) {
|
|
3042
|
+
writes.set(path19, {
|
|
3037
3043
|
lastChange: now,
|
|
3038
3044
|
cancelWait: () => {
|
|
3039
|
-
writes.delete(
|
|
3045
|
+
writes.delete(path19);
|
|
3040
3046
|
clearTimeout(timeoutHandler);
|
|
3041
3047
|
return event;
|
|
3042
3048
|
}
|
|
@@ -3047,8 +3053,8 @@ var FSWatcher = class extends EventEmitter {
|
|
|
3047
3053
|
/**
|
|
3048
3054
|
* Determines whether user has asked to ignore this path.
|
|
3049
3055
|
*/
|
|
3050
|
-
_isIgnored(
|
|
3051
|
-
if (this.options.atomic && DOT_RE.test(
|
|
3056
|
+
_isIgnored(path19, stats) {
|
|
3057
|
+
if (this.options.atomic && DOT_RE.test(path19))
|
|
3052
3058
|
return true;
|
|
3053
3059
|
if (!this._userIgnored) {
|
|
3054
3060
|
const { cwd } = this.options;
|
|
@@ -3058,17 +3064,17 @@ var FSWatcher = class extends EventEmitter {
|
|
|
3058
3064
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
3059
3065
|
this._userIgnored = anymatch(list, void 0);
|
|
3060
3066
|
}
|
|
3061
|
-
return this._userIgnored(
|
|
3067
|
+
return this._userIgnored(path19, stats);
|
|
3062
3068
|
}
|
|
3063
|
-
_isntIgnored(
|
|
3064
|
-
return !this._isIgnored(
|
|
3069
|
+
_isntIgnored(path19, stat4) {
|
|
3070
|
+
return !this._isIgnored(path19, stat4);
|
|
3065
3071
|
}
|
|
3066
3072
|
/**
|
|
3067
3073
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
3068
3074
|
* @param path file or directory pattern being watched
|
|
3069
3075
|
*/
|
|
3070
|
-
_getWatchHelpers(
|
|
3071
|
-
return new WatchHelper(
|
|
3076
|
+
_getWatchHelpers(path19) {
|
|
3077
|
+
return new WatchHelper(path19, this.options.followSymlinks, this);
|
|
3072
3078
|
}
|
|
3073
3079
|
// Directory helpers
|
|
3074
3080
|
// -----------------
|
|
@@ -3100,63 +3106,63 @@ var FSWatcher = class extends EventEmitter {
|
|
|
3100
3106
|
* @param item base path of item/directory
|
|
3101
3107
|
*/
|
|
3102
3108
|
_remove(directory, item, isDirectory) {
|
|
3103
|
-
const
|
|
3104
|
-
const fullPath = sp2.resolve(
|
|
3105
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
3106
|
-
if (!this._throttle("remove",
|
|
3109
|
+
const path19 = sp2.join(directory, item);
|
|
3110
|
+
const fullPath = sp2.resolve(path19);
|
|
3111
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path19) || this._watched.has(fullPath);
|
|
3112
|
+
if (!this._throttle("remove", path19, 100))
|
|
3107
3113
|
return;
|
|
3108
3114
|
if (!isDirectory && this._watched.size === 1) {
|
|
3109
3115
|
this.add(directory, item, true);
|
|
3110
3116
|
}
|
|
3111
|
-
const wp = this._getWatchedDir(
|
|
3117
|
+
const wp = this._getWatchedDir(path19);
|
|
3112
3118
|
const nestedDirectoryChildren = wp.getChildren();
|
|
3113
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
3119
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path19, nested));
|
|
3114
3120
|
const parent = this._getWatchedDir(directory);
|
|
3115
3121
|
const wasTracked = parent.has(item);
|
|
3116
3122
|
parent.remove(item);
|
|
3117
3123
|
if (this._symlinkPaths.has(fullPath)) {
|
|
3118
3124
|
this._symlinkPaths.delete(fullPath);
|
|
3119
3125
|
}
|
|
3120
|
-
let relPath =
|
|
3126
|
+
let relPath = path19;
|
|
3121
3127
|
if (this.options.cwd)
|
|
3122
|
-
relPath = sp2.relative(this.options.cwd,
|
|
3128
|
+
relPath = sp2.relative(this.options.cwd, path19);
|
|
3123
3129
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
3124
3130
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
3125
3131
|
if (event === EVENTS.ADD)
|
|
3126
3132
|
return;
|
|
3127
3133
|
}
|
|
3128
|
-
this._watched.delete(
|
|
3134
|
+
this._watched.delete(path19);
|
|
3129
3135
|
this._watched.delete(fullPath);
|
|
3130
3136
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
3131
|
-
if (wasTracked && !this._isIgnored(
|
|
3132
|
-
this._emit(eventName,
|
|
3133
|
-
this._closePath(
|
|
3137
|
+
if (wasTracked && !this._isIgnored(path19))
|
|
3138
|
+
this._emit(eventName, path19);
|
|
3139
|
+
this._closePath(path19);
|
|
3134
3140
|
}
|
|
3135
3141
|
/**
|
|
3136
3142
|
* Closes all watchers for a path
|
|
3137
3143
|
*/
|
|
3138
|
-
_closePath(
|
|
3139
|
-
this._closeFile(
|
|
3140
|
-
const dir = sp2.dirname(
|
|
3141
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
3144
|
+
_closePath(path19) {
|
|
3145
|
+
this._closeFile(path19);
|
|
3146
|
+
const dir = sp2.dirname(path19);
|
|
3147
|
+
this._getWatchedDir(dir).remove(sp2.basename(path19));
|
|
3142
3148
|
}
|
|
3143
3149
|
/**
|
|
3144
3150
|
* Closes only file-specific watchers
|
|
3145
3151
|
*/
|
|
3146
|
-
_closeFile(
|
|
3147
|
-
const closers = this._closers.get(
|
|
3152
|
+
_closeFile(path19) {
|
|
3153
|
+
const closers = this._closers.get(path19);
|
|
3148
3154
|
if (!closers)
|
|
3149
3155
|
return;
|
|
3150
3156
|
closers.forEach((closer) => closer());
|
|
3151
|
-
this._closers.delete(
|
|
3157
|
+
this._closers.delete(path19);
|
|
3152
3158
|
}
|
|
3153
|
-
_addPathCloser(
|
|
3159
|
+
_addPathCloser(path19, closer) {
|
|
3154
3160
|
if (!closer)
|
|
3155
3161
|
return;
|
|
3156
|
-
let list = this._closers.get(
|
|
3162
|
+
let list = this._closers.get(path19);
|
|
3157
3163
|
if (!list) {
|
|
3158
3164
|
list = [];
|
|
3159
|
-
this._closers.set(
|
|
3165
|
+
this._closers.set(path19, list);
|
|
3160
3166
|
}
|
|
3161
3167
|
list.push(closer);
|
|
3162
3168
|
}
|
|
@@ -3486,7 +3492,7 @@ var FileWatcher = class {
|
|
|
3486
3492
|
return;
|
|
3487
3493
|
}
|
|
3488
3494
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
3489
|
-
([
|
|
3495
|
+
([path19, type]) => ({ path: path19, type })
|
|
3490
3496
|
);
|
|
3491
3497
|
this.pendingChanges.clear();
|
|
3492
3498
|
try {
|
|
@@ -3619,12 +3625,14 @@ function createWatcherWithIndexer(getIndexer, projectRoot, config) {
|
|
|
3619
3625
|
}
|
|
3620
3626
|
|
|
3621
3627
|
// src/tools/index.ts
|
|
3622
|
-
import { tool } from "@opencode-ai/plugin";
|
|
3628
|
+
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
3623
3629
|
|
|
3624
3630
|
// src/indexer/index.ts
|
|
3625
3631
|
import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync2, renameSync, unlinkSync, mkdirSync as mkdirSync2, promises as fsPromises2 } from "fs";
|
|
3626
|
-
import * as
|
|
3632
|
+
import * as path13 from "path";
|
|
3627
3633
|
import { performance as performance2 } from "perf_hooks";
|
|
3634
|
+
import { execFile as execFile2 } from "child_process";
|
|
3635
|
+
import { promisify as promisify2 } from "util";
|
|
3628
3636
|
|
|
3629
3637
|
// node_modules/eventemitter3/index.mjs
|
|
3630
3638
|
var import_index = __toESM(require_eventemitter3(), 1);
|
|
@@ -3648,7 +3656,7 @@ function pTimeout(promise, options) {
|
|
|
3648
3656
|
} = options;
|
|
3649
3657
|
let timer;
|
|
3650
3658
|
let abortHandler;
|
|
3651
|
-
const wrappedPromise = new Promise((
|
|
3659
|
+
const wrappedPromise = new Promise((resolve13, reject) => {
|
|
3652
3660
|
if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
|
|
3653
3661
|
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
3654
3662
|
}
|
|
@@ -3662,7 +3670,7 @@ function pTimeout(promise, options) {
|
|
|
3662
3670
|
};
|
|
3663
3671
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
3664
3672
|
}
|
|
3665
|
-
promise.then(
|
|
3673
|
+
promise.then(resolve13, reject);
|
|
3666
3674
|
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
3667
3675
|
return;
|
|
3668
3676
|
}
|
|
@@ -3670,7 +3678,7 @@ function pTimeout(promise, options) {
|
|
|
3670
3678
|
timer = customTimers.setTimeout.call(void 0, () => {
|
|
3671
3679
|
if (fallback) {
|
|
3672
3680
|
try {
|
|
3673
|
-
|
|
3681
|
+
resolve13(fallback());
|
|
3674
3682
|
} catch (error) {
|
|
3675
3683
|
reject(error);
|
|
3676
3684
|
}
|
|
@@ -3680,7 +3688,7 @@ function pTimeout(promise, options) {
|
|
|
3680
3688
|
promise.cancel();
|
|
3681
3689
|
}
|
|
3682
3690
|
if (message === false) {
|
|
3683
|
-
|
|
3691
|
+
resolve13();
|
|
3684
3692
|
} else if (message instanceof Error) {
|
|
3685
3693
|
reject(message);
|
|
3686
3694
|
} else {
|
|
@@ -4082,7 +4090,7 @@ var PQueue = class extends import_index.default {
|
|
|
4082
4090
|
// Assign unique ID if not provided
|
|
4083
4091
|
id: options.id ?? (this.#idAssigner++).toString()
|
|
4084
4092
|
};
|
|
4085
|
-
return new Promise((
|
|
4093
|
+
return new Promise((resolve13, reject) => {
|
|
4086
4094
|
const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
|
|
4087
4095
|
let cleanupQueueAbortHandler = () => void 0;
|
|
4088
4096
|
const run = async () => {
|
|
@@ -4122,7 +4130,7 @@ var PQueue = class extends import_index.default {
|
|
|
4122
4130
|
})]);
|
|
4123
4131
|
}
|
|
4124
4132
|
const result = await operation;
|
|
4125
|
-
|
|
4133
|
+
resolve13(result);
|
|
4126
4134
|
this.emit("completed", result);
|
|
4127
4135
|
} catch (error) {
|
|
4128
4136
|
reject(error);
|
|
@@ -4310,13 +4318,13 @@ var PQueue = class extends import_index.default {
|
|
|
4310
4318
|
});
|
|
4311
4319
|
}
|
|
4312
4320
|
async #onEvent(event, filter) {
|
|
4313
|
-
return new Promise((
|
|
4321
|
+
return new Promise((resolve13) => {
|
|
4314
4322
|
const listener = () => {
|
|
4315
4323
|
if (filter && !filter()) {
|
|
4316
4324
|
return;
|
|
4317
4325
|
}
|
|
4318
4326
|
this.off(event, listener);
|
|
4319
|
-
|
|
4327
|
+
resolve13();
|
|
4320
4328
|
};
|
|
4321
4329
|
this.on(event, listener);
|
|
4322
4330
|
});
|
|
@@ -4602,7 +4610,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
4602
4610
|
const finalDelay = Math.min(delayTime, remainingTime);
|
|
4603
4611
|
options.signal?.throwIfAborted();
|
|
4604
4612
|
if (finalDelay > 0) {
|
|
4605
|
-
await new Promise((
|
|
4613
|
+
await new Promise((resolve13, reject) => {
|
|
4606
4614
|
const onAbort = () => {
|
|
4607
4615
|
clearTimeout(timeoutToken);
|
|
4608
4616
|
options.signal?.removeEventListener("abort", onAbort);
|
|
@@ -4610,7 +4618,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
4610
4618
|
};
|
|
4611
4619
|
const timeoutToken = setTimeout(() => {
|
|
4612
4620
|
options.signal?.removeEventListener("abort", onAbort);
|
|
4613
|
-
|
|
4621
|
+
resolve13();
|
|
4614
4622
|
}, finalDelay);
|
|
4615
4623
|
if (options.unref) {
|
|
4616
4624
|
timeoutToken.unref?.();
|
|
@@ -4851,6 +4859,8 @@ var BaseEmbeddingProvider = class {
|
|
|
4851
4859
|
this.credentials = credentials;
|
|
4852
4860
|
this.modelInfo = modelInfo;
|
|
4853
4861
|
}
|
|
4862
|
+
credentials;
|
|
4863
|
+
modelInfo;
|
|
4854
4864
|
async embedQuery(query) {
|
|
4855
4865
|
const result = await this.embedBatch([query]);
|
|
4856
4866
|
return {
|
|
@@ -5835,6 +5845,15 @@ function createMockNativeBinding() {
|
|
|
5835
5845
|
close() {
|
|
5836
5846
|
throw error;
|
|
5837
5847
|
}
|
|
5848
|
+
getTransitiveReachability() {
|
|
5849
|
+
throw error;
|
|
5850
|
+
}
|
|
5851
|
+
detectCommunities() {
|
|
5852
|
+
throw error;
|
|
5853
|
+
}
|
|
5854
|
+
computeCentrality() {
|
|
5855
|
+
throw error;
|
|
5856
|
+
}
|
|
5838
5857
|
}
|
|
5839
5858
|
};
|
|
5840
5859
|
}
|
|
@@ -6385,6 +6404,14 @@ var Database = class {
|
|
|
6385
6404
|
this.throwIfClosed();
|
|
6386
6405
|
return this.inner.getSymbolsByNameCi(name);
|
|
6387
6406
|
}
|
|
6407
|
+
getSymbolsForBranch(branch) {
|
|
6408
|
+
this.throwIfClosed();
|
|
6409
|
+
return this.inner.getSymbolsForBranch(branch);
|
|
6410
|
+
}
|
|
6411
|
+
getSymbolsForFiles(filePaths, branch) {
|
|
6412
|
+
this.throwIfClosed();
|
|
6413
|
+
return this.inner.getSymbolsForFiles(filePaths, branch);
|
|
6414
|
+
}
|
|
6388
6415
|
deleteSymbolsByFile(filePath) {
|
|
6389
6416
|
this.throwIfClosed();
|
|
6390
6417
|
return this.inner.deleteSymbolsByFile(filePath);
|
|
@@ -6398,17 +6425,17 @@ var Database = class {
|
|
|
6398
6425
|
if (edges.length === 0) return;
|
|
6399
6426
|
this.inner.upsertCallEdgesBatch(edges);
|
|
6400
6427
|
}
|
|
6401
|
-
getCallers(targetName, branch) {
|
|
6428
|
+
getCallers(targetName, branch, callTypeFilter) {
|
|
6402
6429
|
this.throwIfClosed();
|
|
6403
|
-
return this.inner.getCallers(targetName, branch);
|
|
6430
|
+
return this.inner.getCallers(targetName, branch, callTypeFilter ?? null);
|
|
6404
6431
|
}
|
|
6405
|
-
getCallersWithContext(targetName, branch) {
|
|
6432
|
+
getCallersWithContext(targetName, branch, callTypeFilter) {
|
|
6406
6433
|
this.throwIfClosed();
|
|
6407
|
-
return this.inner.getCallersWithContext(targetName, branch);
|
|
6434
|
+
return this.inner.getCallersWithContext(targetName, branch, callTypeFilter ?? null);
|
|
6408
6435
|
}
|
|
6409
|
-
getCallees(symbolId, branch) {
|
|
6436
|
+
getCallees(symbolId, branch, callTypeFilter) {
|
|
6410
6437
|
this.throwIfClosed();
|
|
6411
|
-
return this.inner.getCallees(symbolId, branch);
|
|
6438
|
+
return this.inner.getCallees(symbolId, branch, callTypeFilter ?? null);
|
|
6412
6439
|
}
|
|
6413
6440
|
deleteCallEdgesByFile(filePath) {
|
|
6414
6441
|
this.throwIfClosed();
|
|
@@ -6418,6 +6445,10 @@ var Database = class {
|
|
|
6418
6445
|
this.throwIfClosed();
|
|
6419
6446
|
this.inner.resolveCallEdge(edgeId, toSymbolId);
|
|
6420
6447
|
}
|
|
6448
|
+
findShortestPath(fromName, toName, branch, maxDepth) {
|
|
6449
|
+
this.throwIfClosed();
|
|
6450
|
+
return this.inner.findShortestPath(fromName, toName, branch, maxDepth ?? null);
|
|
6451
|
+
}
|
|
6421
6452
|
addSymbolsToBranch(branch, symbolIds) {
|
|
6422
6453
|
this.throwIfClosed();
|
|
6423
6454
|
this.inner.addSymbolsToBranch(branch, symbolIds);
|
|
@@ -6458,8 +6489,125 @@ var Database = class {
|
|
|
6458
6489
|
this.throwIfClosed();
|
|
6459
6490
|
return this.inner.gcOrphanCallEdges();
|
|
6460
6491
|
}
|
|
6492
|
+
getTransitiveReachability(rootSymbolIds, branch, direction, maxDepth) {
|
|
6493
|
+
this.throwIfClosed();
|
|
6494
|
+
return this.inner.getTransitiveReachability(
|
|
6495
|
+
rootSymbolIds,
|
|
6496
|
+
branch,
|
|
6497
|
+
direction,
|
|
6498
|
+
maxDepth ?? null
|
|
6499
|
+
);
|
|
6500
|
+
}
|
|
6501
|
+
detectCommunities(branch, symbolIds) {
|
|
6502
|
+
this.throwIfClosed();
|
|
6503
|
+
return this.inner.detectCommunities(branch, symbolIds ?? null);
|
|
6504
|
+
}
|
|
6505
|
+
computeCentrality(branch) {
|
|
6506
|
+
this.throwIfClosed();
|
|
6507
|
+
return this.inner.computeCentrality(branch);
|
|
6508
|
+
}
|
|
6461
6509
|
};
|
|
6462
6510
|
|
|
6511
|
+
// src/tools/changed-files.ts
|
|
6512
|
+
import * as path12 from "path";
|
|
6513
|
+
import { execFile } from "child_process";
|
|
6514
|
+
import { promisify } from "util";
|
|
6515
|
+
var execFileAsync = promisify(execFile);
|
|
6516
|
+
function getErrorMessage(error) {
|
|
6517
|
+
if (error instanceof Error) return error.message;
|
|
6518
|
+
return String(error);
|
|
6519
|
+
}
|
|
6520
|
+
async function getChangedFiles(opts) {
|
|
6521
|
+
const { pr, branch, projectRoot, baseBranch = "main" } = opts;
|
|
6522
|
+
if (pr !== void 0) {
|
|
6523
|
+
return getChangedFilesForPr(pr, projectRoot, baseBranch);
|
|
6524
|
+
}
|
|
6525
|
+
return getChangedFilesForBranch(branch, projectRoot, baseBranch);
|
|
6526
|
+
}
|
|
6527
|
+
async function getChangedFilesForPr(pr, projectRoot, baseBranch) {
|
|
6528
|
+
let headRefName;
|
|
6529
|
+
let actualBaseBranch = baseBranch;
|
|
6530
|
+
try {
|
|
6531
|
+
const { stdout } = await execFileAsync(
|
|
6532
|
+
"gh",
|
|
6533
|
+
["pr", "view", String(pr), "--json", "headRefName,baseRefName,files"],
|
|
6534
|
+
{ cwd: projectRoot, timeout: 3e4 }
|
|
6535
|
+
);
|
|
6536
|
+
const data = JSON.parse(stdout);
|
|
6537
|
+
headRefName = data.headRefName;
|
|
6538
|
+
actualBaseBranch = data.baseRefName || baseBranch;
|
|
6539
|
+
if (data.files && data.files.length > 0) {
|
|
6540
|
+
return {
|
|
6541
|
+
files: normalizeFiles(
|
|
6542
|
+
data.files.map((f) => f.path),
|
|
6543
|
+
projectRoot
|
|
6544
|
+
),
|
|
6545
|
+
baseBranch: actualBaseBranch,
|
|
6546
|
+
source: "gh",
|
|
6547
|
+
headRefName
|
|
6548
|
+
};
|
|
6549
|
+
}
|
|
6550
|
+
} catch (error) {
|
|
6551
|
+
throw new Error(
|
|
6552
|
+
`Failed to retrieve PR #${pr} via gh CLI: ${getErrorMessage(error)}`
|
|
6553
|
+
);
|
|
6554
|
+
}
|
|
6555
|
+
if (headRefName === void 0) {
|
|
6556
|
+
throw new Error(
|
|
6557
|
+
`PR #${pr} returned no usable branch or file information.`
|
|
6558
|
+
);
|
|
6559
|
+
}
|
|
6560
|
+
const result = await getChangedFilesForBranch(headRefName, projectRoot, actualBaseBranch);
|
|
6561
|
+
return { ...result, headRefName };
|
|
6562
|
+
}
|
|
6563
|
+
async function getChangedFilesForBranch(branch, projectRoot, baseBranch) {
|
|
6564
|
+
const targetBranch = branch || await getCurrentBranch2(projectRoot);
|
|
6565
|
+
const mergeBase = await getMergeBase(projectRoot, baseBranch, targetBranch);
|
|
6566
|
+
const { stdout } = await execFileAsync(
|
|
6567
|
+
"git",
|
|
6568
|
+
["diff", "--name-only", `${mergeBase}...${targetBranch}`],
|
|
6569
|
+
{ cwd: projectRoot, timeout: 3e4 }
|
|
6570
|
+
);
|
|
6571
|
+
return {
|
|
6572
|
+
files: normalizeFiles(stdout.split("\n"), projectRoot),
|
|
6573
|
+
baseBranch,
|
|
6574
|
+
source: "git",
|
|
6575
|
+
headRefName: targetBranch
|
|
6576
|
+
};
|
|
6577
|
+
}
|
|
6578
|
+
async function getCurrentBranch2(projectRoot) {
|
|
6579
|
+
const { stdout } = await execFileAsync(
|
|
6580
|
+
"git",
|
|
6581
|
+
["branch", "--show-current"],
|
|
6582
|
+
{ cwd: projectRoot, timeout: 3e4 }
|
|
6583
|
+
);
|
|
6584
|
+
return stdout.trim() || "HEAD";
|
|
6585
|
+
}
|
|
6586
|
+
async function getMergeBase(projectRoot, baseBranch, branch) {
|
|
6587
|
+
const { stdout } = await execFileAsync(
|
|
6588
|
+
"git",
|
|
6589
|
+
["merge-base", baseBranch, branch],
|
|
6590
|
+
{ cwd: projectRoot, timeout: 3e4 }
|
|
6591
|
+
);
|
|
6592
|
+
return stdout.trim();
|
|
6593
|
+
}
|
|
6594
|
+
function normalizeFiles(rawFiles, projectRoot) {
|
|
6595
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6596
|
+
const result = [];
|
|
6597
|
+
for (const raw of rawFiles) {
|
|
6598
|
+
const trimmed = raw.trim();
|
|
6599
|
+
if (!trimmed) continue;
|
|
6600
|
+
const absolute = path12.resolve(projectRoot, trimmed);
|
|
6601
|
+
const relative9 = path12.relative(projectRoot, absolute);
|
|
6602
|
+
const cleaned = relative9.startsWith("./") ? relative9.slice(2) : relative9;
|
|
6603
|
+
if (!seen.has(cleaned)) {
|
|
6604
|
+
seen.add(cleaned);
|
|
6605
|
+
result.push(cleaned);
|
|
6606
|
+
}
|
|
6607
|
+
}
|
|
6608
|
+
return result;
|
|
6609
|
+
}
|
|
6610
|
+
|
|
6463
6611
|
// src/indexer/index.ts
|
|
6464
6612
|
var CALL_GRAPH_LANGUAGES = /* @__PURE__ */ new Set(["typescript", "tsx", "javascript", "jsx", "python", "go", "rust", "php", "apex", "zig", "gdscript", "matlab"]);
|
|
6465
6613
|
var CASE_INSENSITIVE_LANGUAGES = /* @__PURE__ */ new Set(["apex"]);
|
|
@@ -6467,6 +6615,7 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
6467
6615
|
"function_declaration",
|
|
6468
6616
|
"function",
|
|
6469
6617
|
"arrow_function",
|
|
6618
|
+
"export_statement",
|
|
6470
6619
|
"method_definition",
|
|
6471
6620
|
"class_declaration",
|
|
6472
6621
|
"interface_declaration",
|
|
@@ -6505,7 +6654,7 @@ function float32ArrayToBuffer(arr) {
|
|
|
6505
6654
|
function bufferToFloat32Array(buf) {
|
|
6506
6655
|
return new Float32Array(buf.buffer, buf.byteOffset, buf.byteLength / 4);
|
|
6507
6656
|
}
|
|
6508
|
-
function
|
|
6657
|
+
function getErrorMessage2(error) {
|
|
6509
6658
|
if (error instanceof Error) {
|
|
6510
6659
|
return error.message;
|
|
6511
6660
|
}
|
|
@@ -6518,7 +6667,7 @@ function getErrorMessage(error) {
|
|
|
6518
6667
|
return String(error);
|
|
6519
6668
|
}
|
|
6520
6669
|
function isRateLimitError(error) {
|
|
6521
|
-
const message =
|
|
6670
|
+
const message = getErrorMessage2(error);
|
|
6522
6671
|
return message.includes("429") || message.toLowerCase().includes("rate limit") || message.toLowerCase().includes("too many requests");
|
|
6523
6672
|
}
|
|
6524
6673
|
function getSafeEmbeddingChunkTokenLimit(provider) {
|
|
@@ -6536,7 +6685,7 @@ function getDynamicBatchOptions(provider) {
|
|
|
6536
6685
|
return {};
|
|
6537
6686
|
}
|
|
6538
6687
|
function isSqliteCorruptionError(error) {
|
|
6539
|
-
const message =
|
|
6688
|
+
const message = getErrorMessage2(error).toLowerCase();
|
|
6540
6689
|
return message.includes("database disk image is malformed") || message.includes("file is not a database") || message.includes("database schema is corrupt") || message.includes("sqlite_corrupt");
|
|
6541
6690
|
}
|
|
6542
6691
|
var STARTUP_WARNING_METADATA_KEY = "index.startupWarning";
|
|
@@ -6698,9 +6847,9 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
|
|
|
6698
6847
|
return true;
|
|
6699
6848
|
}
|
|
6700
6849
|
function isPathWithinRoot(filePath, rootPath) {
|
|
6701
|
-
const normalizedFilePath =
|
|
6702
|
-
const normalizedRoot =
|
|
6703
|
-
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${
|
|
6850
|
+
const normalizedFilePath = path13.resolve(filePath);
|
|
6851
|
+
const normalizedRoot = path13.resolve(rootPath);
|
|
6852
|
+
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path13.sep}`);
|
|
6704
6853
|
}
|
|
6705
6854
|
var rankingQueryTokenCache = /* @__PURE__ */ new Map();
|
|
6706
6855
|
var rankingNameTokenCache = /* @__PURE__ */ new Map();
|
|
@@ -7753,9 +7902,9 @@ var Indexer = class {
|
|
|
7753
7902
|
this.projectRoot = projectRoot;
|
|
7754
7903
|
this.config = config;
|
|
7755
7904
|
this.indexPath = this.getIndexPath();
|
|
7756
|
-
this.fileHashCachePath =
|
|
7757
|
-
this.failedBatchesPath =
|
|
7758
|
-
this.indexingLockPath =
|
|
7905
|
+
this.fileHashCachePath = path13.join(this.indexPath, "file-hashes.json");
|
|
7906
|
+
this.failedBatchesPath = path13.join(this.indexPath, "failed-batches.json");
|
|
7907
|
+
this.indexingLockPath = path13.join(this.indexPath, "indexing.lock");
|
|
7759
7908
|
this.logger = initializeLogger(config.debug);
|
|
7760
7909
|
}
|
|
7761
7910
|
getIndexPath() {
|
|
@@ -7787,14 +7936,14 @@ var Indexer = class {
|
|
|
7787
7936
|
}
|
|
7788
7937
|
atomicWriteSync(targetPath, data) {
|
|
7789
7938
|
const tempPath = `${targetPath}.tmp`;
|
|
7790
|
-
mkdirSync2(
|
|
7939
|
+
mkdirSync2(path13.dirname(targetPath), { recursive: true });
|
|
7791
7940
|
writeFileSync2(tempPath, data);
|
|
7792
7941
|
renameSync(tempPath, targetPath);
|
|
7793
7942
|
}
|
|
7794
7943
|
getScopedRoots() {
|
|
7795
|
-
const roots = /* @__PURE__ */ new Set([
|
|
7944
|
+
const roots = /* @__PURE__ */ new Set([path13.resolve(this.projectRoot)]);
|
|
7796
7945
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
7797
|
-
roots.add(
|
|
7946
|
+
roots.add(path13.resolve(this.projectRoot, kbRoot));
|
|
7798
7947
|
}
|
|
7799
7948
|
return Array.from(roots);
|
|
7800
7949
|
}
|
|
@@ -7803,22 +7952,29 @@ var Indexer = class {
|
|
|
7803
7952
|
if (this.config.scope !== "global") {
|
|
7804
7953
|
return branchName;
|
|
7805
7954
|
}
|
|
7806
|
-
const projectHash = hashContent(
|
|
7955
|
+
const projectHash = hashContent(path13.resolve(this.projectRoot)).slice(0, 16);
|
|
7956
|
+
return `${projectHash}:${branchName}`;
|
|
7957
|
+
}
|
|
7958
|
+
getBranchCatalogKeyFor(branchName) {
|
|
7959
|
+
if (this.config.scope !== "global") {
|
|
7960
|
+
return branchName;
|
|
7961
|
+
}
|
|
7962
|
+
const projectHash = hashContent(path13.resolve(this.projectRoot)).slice(0, 16);
|
|
7807
7963
|
return `${projectHash}:${branchName}`;
|
|
7808
7964
|
}
|
|
7809
7965
|
getLegacyBranchCatalogKey() {
|
|
7810
7966
|
return this.currentBranch || "default";
|
|
7811
7967
|
}
|
|
7812
7968
|
getLegacyMigrationMetadataKey() {
|
|
7813
|
-
const projectHash = hashContent(
|
|
7969
|
+
const projectHash = hashContent(path13.resolve(this.projectRoot)).slice(0, 16);
|
|
7814
7970
|
return `index.globalBranchMigration.${projectHash}`;
|
|
7815
7971
|
}
|
|
7816
7972
|
getProjectEmbeddingStrategyMetadataKey() {
|
|
7817
|
-
const projectHash = hashContent(
|
|
7973
|
+
const projectHash = hashContent(path13.resolve(this.projectRoot)).slice(0, 16);
|
|
7818
7974
|
return `index.embeddingStrategyVersion.${projectHash}`;
|
|
7819
7975
|
}
|
|
7820
7976
|
getProjectForceReembedMetadataKey() {
|
|
7821
|
-
const projectHash = hashContent(
|
|
7977
|
+
const projectHash = hashContent(path13.resolve(this.projectRoot)).slice(0, 16);
|
|
7822
7978
|
return `index.forceReembed.${projectHash}`;
|
|
7823
7979
|
}
|
|
7824
7980
|
hasProjectForceReembedPending() {
|
|
@@ -7912,7 +8068,7 @@ var Indexer = class {
|
|
|
7912
8068
|
if (!this.database) {
|
|
7913
8069
|
return { chunkIds, symbolIds };
|
|
7914
8070
|
}
|
|
7915
|
-
const projectRootPath =
|
|
8071
|
+
const projectRootPath = path13.resolve(this.projectRoot);
|
|
7916
8072
|
const projectLocalFilePaths = /* @__PURE__ */ new Set([
|
|
7917
8073
|
...Array.from(this.fileHashCache.keys()).filter(
|
|
7918
8074
|
(filePath) => this.isFileInCurrentScope(filePath, roots) && isPathWithinRoot(filePath, projectRootPath)
|
|
@@ -7935,7 +8091,7 @@ var Indexer = class {
|
|
|
7935
8091
|
if (this.config.scope !== "global") {
|
|
7936
8092
|
return this.getBranchCatalogCleanupKeys();
|
|
7937
8093
|
}
|
|
7938
|
-
const projectHash = hashContent(
|
|
8094
|
+
const projectHash = hashContent(path13.resolve(this.projectRoot)).slice(0, 16);
|
|
7939
8095
|
const keys = /* @__PURE__ */ new Set();
|
|
7940
8096
|
const projectChunkIdSet = new Set(projectChunkIds);
|
|
7941
8097
|
const projectSymbolIdSet = new Set(projectSymbolIds);
|
|
@@ -8019,7 +8175,7 @@ var Indexer = class {
|
|
|
8019
8175
|
if (!this.database || this.config.scope !== "global") {
|
|
8020
8176
|
return false;
|
|
8021
8177
|
}
|
|
8022
|
-
const projectHash = hashContent(
|
|
8178
|
+
const projectHash = hashContent(path13.resolve(this.projectRoot)).slice(0, 16);
|
|
8023
8179
|
const roots = this.getScopedRoots();
|
|
8024
8180
|
const { chunkIds: projectLocalChunkIds, symbolIds: projectLocalSymbolIds } = this.getProjectLocalScopedOwnershipIds(roots);
|
|
8025
8181
|
return this.database.getAllBranches().some(
|
|
@@ -8053,7 +8209,7 @@ var Indexer = class {
|
|
|
8053
8209
|
...Array.from(this.fileHashCache.keys()).filter((filePath) => this.isFileInCurrentScope(filePath, roots)),
|
|
8054
8210
|
...scopedEntries.map(({ metadata }) => metadata.filePath)
|
|
8055
8211
|
]);
|
|
8056
|
-
const projectRootPath =
|
|
8212
|
+
const projectRootPath = path13.resolve(this.projectRoot);
|
|
8057
8213
|
const projectLocalFilePaths = new Set(
|
|
8058
8214
|
Array.from(filePaths).filter((filePath) => isPathWithinRoot(filePath, projectRootPath))
|
|
8059
8215
|
);
|
|
@@ -8306,7 +8462,7 @@ var Indexer = class {
|
|
|
8306
8462
|
this.logger.search("warn", "External reranker failed; using deterministic order", {
|
|
8307
8463
|
provider: reranker.provider,
|
|
8308
8464
|
model: reranker.model,
|
|
8309
|
-
error:
|
|
8465
|
+
error: getErrorMessage2(error)
|
|
8310
8466
|
});
|
|
8311
8467
|
return candidates;
|
|
8312
8468
|
}
|
|
@@ -8413,13 +8569,13 @@ var Indexer = class {
|
|
|
8413
8569
|
}
|
|
8414
8570
|
await fsPromises2.mkdir(this.indexPath, { recursive: true });
|
|
8415
8571
|
const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
|
|
8416
|
-
const storePath =
|
|
8572
|
+
const storePath = path13.join(this.indexPath, "vectors");
|
|
8417
8573
|
this.store = new VectorStore(storePath, dimensions);
|
|
8418
|
-
const indexFilePath =
|
|
8574
|
+
const indexFilePath = path13.join(this.indexPath, "vectors.usearch");
|
|
8419
8575
|
if (existsSync7(indexFilePath)) {
|
|
8420
8576
|
this.store.load();
|
|
8421
8577
|
}
|
|
8422
|
-
const invertedIndexPath =
|
|
8578
|
+
const invertedIndexPath = path13.join(this.indexPath, "inverted-index.json");
|
|
8423
8579
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
8424
8580
|
try {
|
|
8425
8581
|
this.invertedIndex.load();
|
|
@@ -8429,7 +8585,7 @@ var Indexer = class {
|
|
|
8429
8585
|
}
|
|
8430
8586
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
8431
8587
|
}
|
|
8432
|
-
const dbPath =
|
|
8588
|
+
const dbPath = path13.join(this.indexPath, "codebase.db");
|
|
8433
8589
|
let dbIsNew = !existsSync7(dbPath);
|
|
8434
8590
|
try {
|
|
8435
8591
|
this.database = new Database(dbPath);
|
|
@@ -8510,7 +8666,7 @@ var Indexer = class {
|
|
|
8510
8666
|
if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
|
|
8511
8667
|
return {
|
|
8512
8668
|
resetCorruptedIndex: true,
|
|
8513
|
-
warning: this.getCorruptedIndexWarning(
|
|
8669
|
+
warning: this.getCorruptedIndexWarning(path13.join(this.indexPath, "codebase.db"))
|
|
8514
8670
|
};
|
|
8515
8671
|
}
|
|
8516
8672
|
throw error;
|
|
@@ -8525,7 +8681,7 @@ var Indexer = class {
|
|
|
8525
8681
|
return;
|
|
8526
8682
|
}
|
|
8527
8683
|
const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
|
|
8528
|
-
const storeBasePath =
|
|
8684
|
+
const storeBasePath = path13.join(this.indexPath, "vectors");
|
|
8529
8685
|
const storeIndexPath = `${storeBasePath}.usearch`;
|
|
8530
8686
|
const storeMetadataPath = `${storeBasePath}.meta.json`;
|
|
8531
8687
|
const backupIndexPath = `${storeIndexPath}.bak`;
|
|
@@ -8610,9 +8766,9 @@ var Indexer = class {
|
|
|
8610
8766
|
if (!isSqliteCorruptionError(error)) {
|
|
8611
8767
|
return false;
|
|
8612
8768
|
}
|
|
8613
|
-
const dbPath =
|
|
8769
|
+
const dbPath = path13.join(this.indexPath, "codebase.db");
|
|
8614
8770
|
const warning = this.getCorruptedIndexWarning(dbPath);
|
|
8615
|
-
const errorMessage =
|
|
8771
|
+
const errorMessage = getErrorMessage2(error);
|
|
8616
8772
|
if (this.config.scope === "global") {
|
|
8617
8773
|
this.logger.error("Detected corrupted shared global index database", {
|
|
8618
8774
|
stage,
|
|
@@ -8633,15 +8789,15 @@ var Indexer = class {
|
|
|
8633
8789
|
this.indexCompatibility = null;
|
|
8634
8790
|
this.fileHashCache.clear();
|
|
8635
8791
|
const resetPaths = [
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8792
|
+
path13.join(this.indexPath, "codebase.db"),
|
|
8793
|
+
path13.join(this.indexPath, "codebase.db-shm"),
|
|
8794
|
+
path13.join(this.indexPath, "codebase.db-wal"),
|
|
8795
|
+
path13.join(this.indexPath, "vectors.usearch"),
|
|
8796
|
+
path13.join(this.indexPath, "inverted-index.json"),
|
|
8797
|
+
path13.join(this.indexPath, "file-hashes.json"),
|
|
8798
|
+
path13.join(this.indexPath, "failed-batches.json"),
|
|
8799
|
+
path13.join(this.indexPath, "indexing.lock"),
|
|
8800
|
+
path13.join(this.indexPath, "vectors")
|
|
8645
8801
|
];
|
|
8646
8802
|
await Promise.all(resetPaths.map(async (targetPath) => {
|
|
8647
8803
|
try {
|
|
@@ -8906,7 +9062,7 @@ var Indexer = class {
|
|
|
8906
9062
|
for (const parsed of parsedFiles) {
|
|
8907
9063
|
currentFilePaths.add(parsed.path);
|
|
8908
9064
|
if (parsed.chunks.length === 0) {
|
|
8909
|
-
const relativePath =
|
|
9065
|
+
const relativePath = path13.relative(this.projectRoot, parsed.path);
|
|
8910
9066
|
stats.parseFailures.push(relativePath);
|
|
8911
9067
|
}
|
|
8912
9068
|
let fileChunkCount = 0;
|
|
@@ -9045,6 +9201,7 @@ var Indexer = class {
|
|
|
9045
9201
|
targetName: site.calleeName,
|
|
9046
9202
|
toSymbolId: void 0,
|
|
9047
9203
|
callType: site.callType,
|
|
9204
|
+
confidence: site.confidence,
|
|
9048
9205
|
line: site.line,
|
|
9049
9206
|
col: site.column,
|
|
9050
9207
|
isResolved: false
|
|
@@ -9189,7 +9346,7 @@ var Indexer = class {
|
|
|
9189
9346
|
for (const requestBatch of requestBatches) {
|
|
9190
9347
|
queue.add(async () => {
|
|
9191
9348
|
if (rateLimitBackoffMs > 0) {
|
|
9192
|
-
await new Promise((
|
|
9349
|
+
await new Promise((resolve13) => setTimeout(resolve13, rateLimitBackoffMs));
|
|
9193
9350
|
}
|
|
9194
9351
|
try {
|
|
9195
9352
|
const result = await pRetry(
|
|
@@ -9204,7 +9361,7 @@ var Indexer = class {
|
|
|
9204
9361
|
factor: 2,
|
|
9205
9362
|
shouldRetry: (error) => !(error.error instanceof CustomProviderNonRetryableError),
|
|
9206
9363
|
onFailedAttempt: (error) => {
|
|
9207
|
-
const message =
|
|
9364
|
+
const message = getErrorMessage2(error);
|
|
9208
9365
|
if (isRateLimitError(error)) {
|
|
9209
9366
|
rateLimitBackoffMs = Math.min(providerRateLimits.maxRetryMs, (rateLimitBackoffMs || providerRateLimits.minRetryMs) * 2);
|
|
9210
9367
|
this.logger.embedding("warn", `Rate limited, backing off`, {
|
|
@@ -9311,7 +9468,7 @@ var Indexer = class {
|
|
|
9311
9468
|
});
|
|
9312
9469
|
} catch (error) {
|
|
9313
9470
|
const failedChunks = getUniquePendingChunksFromRequests(requestBatch).filter((chunk) => !completedChunkIds.has(chunk.id));
|
|
9314
|
-
const failureMessage =
|
|
9471
|
+
const failureMessage = getErrorMessage2(error);
|
|
9315
9472
|
const failureTimestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
9316
9473
|
for (const chunk of failedChunks) {
|
|
9317
9474
|
if (!failedChunkIds.has(chunk.id)) {
|
|
@@ -9750,8 +9907,8 @@ var Indexer = class {
|
|
|
9750
9907
|
this.indexCompatibility = compatibility;
|
|
9751
9908
|
return;
|
|
9752
9909
|
}
|
|
9753
|
-
const localProjectIndexPath =
|
|
9754
|
-
if (
|
|
9910
|
+
const localProjectIndexPath = path13.join(this.projectRoot, ".opencode", "index");
|
|
9911
|
+
if (path13.resolve(this.indexPath) !== path13.resolve(localProjectIndexPath)) {
|
|
9755
9912
|
throw new Error(
|
|
9756
9913
|
"Project-scoped force rebuild is unsafe while using an inherited worktree index. Create a local project config boundary before clearing the index."
|
|
9757
9914
|
);
|
|
@@ -9839,7 +9996,7 @@ var Indexer = class {
|
|
|
9839
9996
|
gcOrphanSymbols: 0,
|
|
9840
9997
|
gcOrphanCallEdges: 0,
|
|
9841
9998
|
resetCorruptedIndex: true,
|
|
9842
|
-
warning: this.getCorruptedIndexWarning(
|
|
9999
|
+
warning: this.getCorruptedIndexWarning(path13.join(this.indexPath, "codebase.db"))
|
|
9843
10000
|
};
|
|
9844
10001
|
}
|
|
9845
10002
|
this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
|
|
@@ -9990,7 +10147,7 @@ var Indexer = class {
|
|
|
9990
10147
|
succeeded += successfulResults.length;
|
|
9991
10148
|
stillFailing.push(...failedChunksForBatch.values());
|
|
9992
10149
|
} catch (error) {
|
|
9993
|
-
const failureMessage =
|
|
10150
|
+
const failureMessage = getErrorMessage2(error);
|
|
9994
10151
|
const failureTimestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
9995
10152
|
const unaccountedChunks = batch.chunks.filter(
|
|
9996
10153
|
(chunk) => !failedChunksForBatch.has(chunk.id) && !completedChunkIds.has(chunk.id)
|
|
@@ -10164,12 +10321,12 @@ var Indexer = class {
|
|
|
10164
10321
|
})
|
|
10165
10322
|
);
|
|
10166
10323
|
}
|
|
10167
|
-
async getCallers(targetName) {
|
|
10324
|
+
async getCallers(targetName, callTypeFilter) {
|
|
10168
10325
|
const { database } = await this.ensureInitialized();
|
|
10169
10326
|
const seen = /* @__PURE__ */ new Set();
|
|
10170
10327
|
const results = [];
|
|
10171
10328
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
10172
|
-
for (const edge of database.getCallersWithContext(targetName, branchKey)) {
|
|
10329
|
+
for (const edge of database.getCallersWithContext(targetName, branchKey, callTypeFilter)) {
|
|
10173
10330
|
if (!seen.has(edge.id)) {
|
|
10174
10331
|
seen.add(edge.id);
|
|
10175
10332
|
results.push(edge);
|
|
@@ -10178,12 +10335,12 @@ var Indexer = class {
|
|
|
10178
10335
|
}
|
|
10179
10336
|
return results;
|
|
10180
10337
|
}
|
|
10181
|
-
async getCallees(symbolId) {
|
|
10338
|
+
async getCallees(symbolId, callTypeFilter) {
|
|
10182
10339
|
const { database } = await this.ensureInitialized();
|
|
10183
10340
|
const seen = /* @__PURE__ */ new Set();
|
|
10184
10341
|
const results = [];
|
|
10185
10342
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
10186
|
-
for (const edge of database.getCallees(symbolId, branchKey)) {
|
|
10343
|
+
for (const edge of database.getCallees(symbolId, branchKey, callTypeFilter)) {
|
|
10187
10344
|
if (!seen.has(edge.id)) {
|
|
10188
10345
|
seen.add(edge.id);
|
|
10189
10346
|
results.push(edge);
|
|
@@ -10192,6 +10349,198 @@ var Indexer = class {
|
|
|
10192
10349
|
}
|
|
10193
10350
|
return results;
|
|
10194
10351
|
}
|
|
10352
|
+
async findCallPath(fromName, toName, maxDepth) {
|
|
10353
|
+
const { database } = await this.ensureInitialized();
|
|
10354
|
+
let shortest = [];
|
|
10355
|
+
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
10356
|
+
const path19 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
|
|
10357
|
+
if (path19.length > 0 && (shortest.length === 0 || path19.length < shortest.length)) {
|
|
10358
|
+
shortest = path19;
|
|
10359
|
+
}
|
|
10360
|
+
}
|
|
10361
|
+
return shortest;
|
|
10362
|
+
}
|
|
10363
|
+
async getSymbolsForBranch(branch) {
|
|
10364
|
+
const { database } = await this.ensureInitialized();
|
|
10365
|
+
const resolvedBranch = branch ?? this.getBranchCatalogKey();
|
|
10366
|
+
return database.getSymbolsForBranch(resolvedBranch);
|
|
10367
|
+
}
|
|
10368
|
+
async getSymbolsForFiles(filePaths, branch) {
|
|
10369
|
+
const { database } = await this.ensureInitialized();
|
|
10370
|
+
const resolvedBranch = branch ?? this.getBranchCatalogKey();
|
|
10371
|
+
return database.getSymbolsForFiles(filePaths, resolvedBranch);
|
|
10372
|
+
}
|
|
10373
|
+
async getTransitiveReachability(rootSymbolIds, direction, maxDepth) {
|
|
10374
|
+
const { database } = await this.ensureInitialized();
|
|
10375
|
+
const branch = this.getBranchCatalogKey();
|
|
10376
|
+
return database.getTransitiveReachability(rootSymbolIds, branch, direction, maxDepth);
|
|
10377
|
+
}
|
|
10378
|
+
async detectCommunities(branch, symbolIds) {
|
|
10379
|
+
const { database } = await this.ensureInitialized();
|
|
10380
|
+
const resolvedBranch = branch ?? this.getBranchCatalogKey();
|
|
10381
|
+
return database.detectCommunities(resolvedBranch, symbolIds);
|
|
10382
|
+
}
|
|
10383
|
+
async computeCentrality(branch) {
|
|
10384
|
+
const { database } = await this.ensureInitialized();
|
|
10385
|
+
const resolvedBranch = branch ?? this.getBranchCatalogKey();
|
|
10386
|
+
return database.computeCentrality(resolvedBranch);
|
|
10387
|
+
}
|
|
10388
|
+
async getPrImpact(opts) {
|
|
10389
|
+
const { database } = await this.ensureInitialized();
|
|
10390
|
+
const execFileAsync2 = promisify2(execFile2);
|
|
10391
|
+
const changedFilesResult = await getChangedFiles({
|
|
10392
|
+
pr: opts.pr,
|
|
10393
|
+
branch: opts.branch,
|
|
10394
|
+
projectRoot: this.projectRoot,
|
|
10395
|
+
baseBranch: this.baseBranch
|
|
10396
|
+
});
|
|
10397
|
+
const changedFiles = changedFilesResult.files;
|
|
10398
|
+
const headRefName = changedFilesResult.headRefName;
|
|
10399
|
+
if (opts.pr !== void 0 && headRefName === void 0) {
|
|
10400
|
+
throw new Error(
|
|
10401
|
+
`Could not resolve head branch for PR #${opts.pr}. Run index_codebase on the PR branch first.`
|
|
10402
|
+
);
|
|
10403
|
+
}
|
|
10404
|
+
const resolvedBranch = opts.pr !== void 0 ? headRefName : opts.branch || this.currentBranch;
|
|
10405
|
+
const branchKey = this.getBranchCatalogKeyFor(resolvedBranch || "default");
|
|
10406
|
+
const branchSymbols = database.getSymbolsForBranch(branchKey);
|
|
10407
|
+
if (branchSymbols.length === 0) {
|
|
10408
|
+
throw new Error(
|
|
10409
|
+
"Run index_codebase first to build the call graph and symbol index for this branch."
|
|
10410
|
+
);
|
|
10411
|
+
}
|
|
10412
|
+
const absoluteChangedFiles = changedFiles.map((f) => path13.resolve(this.projectRoot, f));
|
|
10413
|
+
const directSymbols = database.getSymbolsForFiles(absoluteChangedFiles, branchKey);
|
|
10414
|
+
const directIds = directSymbols.map((s) => s.id);
|
|
10415
|
+
const direction = opts.direction ?? "both";
|
|
10416
|
+
const maxDepth = opts.maxDepth ?? 5;
|
|
10417
|
+
const transitiveCallers = database.getTransitiveReachability(
|
|
10418
|
+
directIds,
|
|
10419
|
+
branchKey,
|
|
10420
|
+
direction,
|
|
10421
|
+
maxDepth
|
|
10422
|
+
);
|
|
10423
|
+
const affectedIdsSet = new Set(directIds);
|
|
10424
|
+
for (const caller of transitiveCallers) {
|
|
10425
|
+
affectedIdsSet.add(caller.symbolId);
|
|
10426
|
+
}
|
|
10427
|
+
const allAffectedIds = Array.from(affectedIdsSet);
|
|
10428
|
+
const communitiesData = database.detectCommunities(branchKey, allAffectedIds);
|
|
10429
|
+
const communityMap = /* @__PURE__ */ new Map();
|
|
10430
|
+
for (const c of communitiesData) {
|
|
10431
|
+
if (!communityMap.has(c.communityLabel)) {
|
|
10432
|
+
communityMap.set(c.communityLabel, {
|
|
10433
|
+
label: c.communityLabel,
|
|
10434
|
+
symbolCount: 0,
|
|
10435
|
+
directSymbols: /* @__PURE__ */ new Set()
|
|
10436
|
+
});
|
|
10437
|
+
}
|
|
10438
|
+
const entry = communityMap.get(c.communityLabel);
|
|
10439
|
+
entry.symbolCount++;
|
|
10440
|
+
if (directIds.includes(c.symbolId)) {
|
|
10441
|
+
entry.directSymbols.add(c.symbolId);
|
|
10442
|
+
}
|
|
10443
|
+
}
|
|
10444
|
+
const communities = Array.from(communityMap.values()).map((c) => ({
|
|
10445
|
+
label: c.label,
|
|
10446
|
+
symbolCount: c.symbolCount,
|
|
10447
|
+
directSymbols: Array.from(c.directSymbols)
|
|
10448
|
+
}));
|
|
10449
|
+
const centralityData = database.computeCentrality(branchKey);
|
|
10450
|
+
const hubThreshold = opts.hubThreshold ?? 10;
|
|
10451
|
+
const hubNodes = centralityData.filter((c) => directIds.includes(c.symbolId) && c.callerCount >= hubThreshold).map((c) => ({
|
|
10452
|
+
id: c.symbolId,
|
|
10453
|
+
name: c.symbolName,
|
|
10454
|
+
callerCount: c.callerCount,
|
|
10455
|
+
filePath: c.filePath
|
|
10456
|
+
}));
|
|
10457
|
+
const totalAffected = allAffectedIds.length;
|
|
10458
|
+
let riskLevel;
|
|
10459
|
+
let riskReason;
|
|
10460
|
+
if (totalAffected < 5 && hubNodes.length === 0) {
|
|
10461
|
+
riskLevel = "LOW";
|
|
10462
|
+
riskReason = `Small impact: ${totalAffected} affected symbols, no hub nodes touched.`;
|
|
10463
|
+
} else if (totalAffected > 20 || hubNodes.length > 1) {
|
|
10464
|
+
riskLevel = "HIGH";
|
|
10465
|
+
riskReason = `Large impact: ${totalAffected} affected symbols${hubNodes.length > 0 ? `, ${hubNodes.length} hub nodes touched` : ""}.`;
|
|
10466
|
+
} else {
|
|
10467
|
+
riskLevel = "MEDIUM";
|
|
10468
|
+
riskReason = `Moderate impact: ${totalAffected} affected symbols${hubNodes.length === 1 ? ", 1 hub node touched" : ""}.`;
|
|
10469
|
+
}
|
|
10470
|
+
let conflictingPRs;
|
|
10471
|
+
if (opts.checkConflicts) {
|
|
10472
|
+
conflictingPRs = [];
|
|
10473
|
+
try {
|
|
10474
|
+
const { stdout } = await execFileAsync2(
|
|
10475
|
+
"gh",
|
|
10476
|
+
["pr", "list", "--state", "open", "--json", "number,headRefName", "--limit", "10000"],
|
|
10477
|
+
{ cwd: this.projectRoot, timeout: 3e4 }
|
|
10478
|
+
);
|
|
10479
|
+
const openPRs = JSON.parse(stdout);
|
|
10480
|
+
const currentCommunityLabels = new Set(communities.map((c) => c.label));
|
|
10481
|
+
const allCommunitiesData = database.detectCommunities(branchKey);
|
|
10482
|
+
const symbolToCommunity = /* @__PURE__ */ new Map();
|
|
10483
|
+
const structuralKey = (filePath, name) => `${filePath.toLowerCase()}:${name.toLowerCase()}`;
|
|
10484
|
+
for (const c of allCommunitiesData) {
|
|
10485
|
+
symbolToCommunity.set(structuralKey(c.filePath, c.symbolName), c.communityLabel);
|
|
10486
|
+
}
|
|
10487
|
+
for (const openPr of openPRs) {
|
|
10488
|
+
if (openPr.number === opts.pr) continue;
|
|
10489
|
+
try {
|
|
10490
|
+
const otherChanged = await getChangedFiles({
|
|
10491
|
+
pr: openPr.number,
|
|
10492
|
+
projectRoot: this.projectRoot,
|
|
10493
|
+
baseBranch: this.baseBranch
|
|
10494
|
+
});
|
|
10495
|
+
const otherAbsolute = otherChanged.files.map((f) => path13.resolve(this.projectRoot, f));
|
|
10496
|
+
const otherBranchKey = this.getBranchCatalogKeyFor(openPr.headRefName);
|
|
10497
|
+
const otherSymbols = database.getSymbolsForFiles(otherAbsolute, otherBranchKey);
|
|
10498
|
+
const otherLabels = /* @__PURE__ */ new Set();
|
|
10499
|
+
for (const sym of otherSymbols) {
|
|
10500
|
+
const label = symbolToCommunity.get(structuralKey(sym.filePath, sym.name));
|
|
10501
|
+
if (label) {
|
|
10502
|
+
otherLabels.add(label);
|
|
10503
|
+
}
|
|
10504
|
+
}
|
|
10505
|
+
const overlapping = Array.from(otherLabels).filter(
|
|
10506
|
+
(l) => currentCommunityLabels.has(l)
|
|
10507
|
+
);
|
|
10508
|
+
if (overlapping.length > 0) {
|
|
10509
|
+
conflictingPRs.push({
|
|
10510
|
+
pr: openPr.number,
|
|
10511
|
+
branch: openPr.headRefName,
|
|
10512
|
+
overlappingCommunities: overlapping
|
|
10513
|
+
});
|
|
10514
|
+
}
|
|
10515
|
+
} catch {
|
|
10516
|
+
}
|
|
10517
|
+
}
|
|
10518
|
+
} catch {
|
|
10519
|
+
}
|
|
10520
|
+
}
|
|
10521
|
+
return {
|
|
10522
|
+
changedFiles,
|
|
10523
|
+
directSymbols: directSymbols.map((s) => ({
|
|
10524
|
+
id: s.id,
|
|
10525
|
+
name: s.name,
|
|
10526
|
+
kind: s.kind,
|
|
10527
|
+
filePath: s.filePath
|
|
10528
|
+
})),
|
|
10529
|
+
transitiveCallers: transitiveCallers.map((c) => ({
|
|
10530
|
+
id: c.symbolId,
|
|
10531
|
+
name: c.symbolName,
|
|
10532
|
+
filePath: c.filePath,
|
|
10533
|
+
depth: c.depth
|
|
10534
|
+
})),
|
|
10535
|
+
totalAffected,
|
|
10536
|
+
communities,
|
|
10537
|
+
hubNodes,
|
|
10538
|
+
riskLevel,
|
|
10539
|
+
riskReason,
|
|
10540
|
+
direction,
|
|
10541
|
+
conflictingPRs
|
|
10542
|
+
};
|
|
10543
|
+
}
|
|
10195
10544
|
async close() {
|
|
10196
10545
|
await this.database?.close();
|
|
10197
10546
|
this.database = null;
|
|
@@ -10419,54 +10768,139 @@ ${truncateContent(r.content)}
|
|
|
10419
10768
|
return formatted.join("\n\n");
|
|
10420
10769
|
}
|
|
10421
10770
|
|
|
10771
|
+
// src/tools/pr-impact.ts
|
|
10772
|
+
import { tool } from "@opencode-ai/plugin";
|
|
10773
|
+
|
|
10774
|
+
// src/tools/format-pr-impact.ts
|
|
10775
|
+
function formatPrImpact(result) {
|
|
10776
|
+
const lines = [];
|
|
10777
|
+
lines.push(`\u2192 Files changed: ${result.changedFiles.length}`);
|
|
10778
|
+
for (const file of result.changedFiles) {
|
|
10779
|
+
lines.push(` - ${file}`);
|
|
10780
|
+
}
|
|
10781
|
+
const directCount = result.directSymbols.length;
|
|
10782
|
+
const transitiveCount = result.transitiveCallers.length;
|
|
10783
|
+
const directionLabel = result.direction === "callees" ? "callees" : result.direction === "both" ? "reachable (callers + callees)" : "callers";
|
|
10784
|
+
lines.push(
|
|
10785
|
+
`\u2192 Symbols affected: ${result.totalAffected} (${directCount} direct, ${transitiveCount} transitive ${directionLabel})`
|
|
10786
|
+
);
|
|
10787
|
+
if (directCount > 0) {
|
|
10788
|
+
lines.push(
|
|
10789
|
+
` Direct: ${result.directSymbols.map((s) => `${s.name} (${s.kind})`).join(", ")}`
|
|
10790
|
+
);
|
|
10791
|
+
}
|
|
10792
|
+
if (transitiveCount > 0) {
|
|
10793
|
+
lines.push(
|
|
10794
|
+
` Transitive ${directionLabel}: ${result.transitiveCallers.map((s) => s.name).join(", ")}`
|
|
10795
|
+
);
|
|
10796
|
+
}
|
|
10797
|
+
if (result.communities.length > 0) {
|
|
10798
|
+
lines.push(
|
|
10799
|
+
`\u2192 Communities touched: ${result.communities.map((c) => c.label).join(", ")}`
|
|
10800
|
+
);
|
|
10801
|
+
for (const community of result.communities) {
|
|
10802
|
+
lines.push(
|
|
10803
|
+
` - ${community.label}: ${community.symbolCount} symbols`
|
|
10804
|
+
);
|
|
10805
|
+
}
|
|
10806
|
+
} else {
|
|
10807
|
+
lines.push("\u2192 Communities touched: none");
|
|
10808
|
+
}
|
|
10809
|
+
lines.push(`\u2192 Risk: ${result.riskLevel} \u2014 ${result.riskReason}`);
|
|
10810
|
+
if (result.hubNodes.length > 0) {
|
|
10811
|
+
lines.push(" Hub nodes in change scope:");
|
|
10812
|
+
for (const hub of result.hubNodes) {
|
|
10813
|
+
lines.push(` - ${hub.name} (${hub.callerCount} callers) at ${hub.filePath}`);
|
|
10814
|
+
}
|
|
10815
|
+
}
|
|
10816
|
+
if (result.conflictingPRs && result.conflictingPRs.length > 0) {
|
|
10817
|
+
const conflictList = result.conflictingPRs.map(
|
|
10818
|
+
(c) => `PR #${c.pr} (also touches ${c.overlappingCommunities.join(", ")} community)`
|
|
10819
|
+
);
|
|
10820
|
+
lines.push(`\u2192 Potential conflicts with: ${conflictList.join(", ")}`);
|
|
10821
|
+
}
|
|
10822
|
+
return lines.join("\n");
|
|
10823
|
+
}
|
|
10824
|
+
|
|
10825
|
+
// src/tools/pr-impact.ts
|
|
10826
|
+
var z = tool.schema;
|
|
10827
|
+
var pr_impact = tool({
|
|
10828
|
+
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.",
|
|
10829
|
+
args: {
|
|
10830
|
+
pr: z.number().optional().describe("Pull request number to analyze"),
|
|
10831
|
+
branch: z.string().optional().describe("Branch name to analyze (defaults to current branch)"),
|
|
10832
|
+
maxDepth: z.number().optional().default(5).describe("Maximum traversal depth for transitive callers (default: 5)"),
|
|
10833
|
+
hubThreshold: z.number().optional().default(10).describe("Minimum caller count to flag a symbol as a hub node (default: 10)"),
|
|
10834
|
+
checkConflicts: z.boolean().optional().default(false).describe("Check for conflicting open PRs touching the same communities (default: false)"),
|
|
10835
|
+
direction: z.enum(["callers", "callees", "both"]).optional().default("both").describe("Call-graph traversal direction: 'callers' for upstream, 'callees' for downstream, 'both' for union (default: both)")
|
|
10836
|
+
},
|
|
10837
|
+
async execute(args, context) {
|
|
10838
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
10839
|
+
try {
|
|
10840
|
+
const result = await indexer.getPrImpact({
|
|
10841
|
+
pr: args.pr,
|
|
10842
|
+
branch: args.branch,
|
|
10843
|
+
maxDepth: args.maxDepth,
|
|
10844
|
+
hubThreshold: args.hubThreshold,
|
|
10845
|
+
checkConflicts: args.checkConflicts,
|
|
10846
|
+
direction: args.direction
|
|
10847
|
+
});
|
|
10848
|
+
return formatPrImpact(result);
|
|
10849
|
+
} catch (error) {
|
|
10850
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10851
|
+
return `Error analyzing PR impact: ${message}`;
|
|
10852
|
+
}
|
|
10853
|
+
}
|
|
10854
|
+
});
|
|
10855
|
+
|
|
10422
10856
|
// src/tools/knowledge-base-paths.ts
|
|
10423
|
-
import * as
|
|
10857
|
+
import * as path14 from "path";
|
|
10424
10858
|
function resolveConfigPathValue(value, baseDir) {
|
|
10425
10859
|
const trimmed = value.trim();
|
|
10426
10860
|
if (!trimmed) {
|
|
10427
10861
|
return trimmed;
|
|
10428
10862
|
}
|
|
10429
|
-
const absolutePath =
|
|
10430
|
-
return
|
|
10863
|
+
const absolutePath = path14.isAbsolute(trimmed) ? trimmed : path14.resolve(baseDir, trimmed);
|
|
10864
|
+
return path14.normalize(absolutePath);
|
|
10431
10865
|
}
|
|
10432
10866
|
function serializeConfigPathValue(value, baseDir) {
|
|
10433
10867
|
const trimmed = value.trim();
|
|
10434
10868
|
if (!trimmed) {
|
|
10435
10869
|
return trimmed;
|
|
10436
10870
|
}
|
|
10437
|
-
if (!
|
|
10438
|
-
return normalizePathSeparators(
|
|
10871
|
+
if (!path14.isAbsolute(trimmed)) {
|
|
10872
|
+
return normalizePathSeparators(path14.normalize(trimmed));
|
|
10439
10873
|
}
|
|
10440
|
-
const relativePath =
|
|
10441
|
-
if (!relativePath || !relativePath.startsWith("..") && !
|
|
10442
|
-
return normalizePathSeparators(
|
|
10874
|
+
const relativePath = path14.relative(baseDir, trimmed);
|
|
10875
|
+
if (!relativePath || !relativePath.startsWith("..") && !path14.isAbsolute(relativePath)) {
|
|
10876
|
+
return normalizePathSeparators(path14.normalize(relativePath || "."));
|
|
10443
10877
|
}
|
|
10444
|
-
return
|
|
10878
|
+
return path14.normalize(trimmed);
|
|
10445
10879
|
}
|
|
10446
10880
|
function resolveKnowledgeBasePath(value, projectRoot) {
|
|
10447
|
-
return
|
|
10881
|
+
return path14.isAbsolute(value) ? value : path14.resolve(projectRoot, value);
|
|
10448
10882
|
}
|
|
10449
10883
|
function normalizeKnowledgeBasePath2(value, projectRoot) {
|
|
10450
|
-
return
|
|
10884
|
+
return path14.normalize(resolveKnowledgeBasePath(value, projectRoot));
|
|
10451
10885
|
}
|
|
10452
10886
|
function hasMatchingKnowledgeBasePath(knowledgeBases, inputPath, projectRoot) {
|
|
10453
|
-
const normalizedInput =
|
|
10887
|
+
const normalizedInput = path14.normalize(inputPath);
|
|
10454
10888
|
return knowledgeBases.some((kb) => normalizeKnowledgeBasePath2(kb, projectRoot) === normalizedInput);
|
|
10455
10889
|
}
|
|
10456
10890
|
function findKnowledgeBasePathIndex(knowledgeBases, inputPath, projectRoot) {
|
|
10457
|
-
const normalizedInput =
|
|
10891
|
+
const normalizedInput = path14.normalize(inputPath);
|
|
10458
10892
|
return knowledgeBases.findIndex(
|
|
10459
|
-
(kb) =>
|
|
10893
|
+
(kb) => path14.normalize(kb) === normalizedInput || normalizeKnowledgeBasePath2(kb, projectRoot) === normalizedInput
|
|
10460
10894
|
);
|
|
10461
10895
|
}
|
|
10462
10896
|
|
|
10463
10897
|
// src/tools/index.ts
|
|
10464
10898
|
import { existsSync as existsSync9, realpathSync, statSync as statSync3 } from "fs";
|
|
10465
|
-
import * as
|
|
10899
|
+
import * as path16 from "path";
|
|
10466
10900
|
|
|
10467
10901
|
// src/tools/config-state.ts
|
|
10468
10902
|
import { existsSync as existsSync8, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
10469
|
-
import * as
|
|
10903
|
+
import * as path15 from "path";
|
|
10470
10904
|
function normalizeKnowledgeBasePaths(config, projectRoot) {
|
|
10471
10905
|
const normalized = { ...config };
|
|
10472
10906
|
if (Array.isArray(normalized.knowledgeBases)) {
|
|
@@ -10493,8 +10927,8 @@ function loadEditableConfig(projectRoot) {
|
|
|
10493
10927
|
}
|
|
10494
10928
|
function saveConfig(projectRoot, config) {
|
|
10495
10929
|
const configPath = getConfigPath(projectRoot);
|
|
10496
|
-
const configDir =
|
|
10497
|
-
const configBaseDir =
|
|
10930
|
+
const configDir = path15.dirname(configPath);
|
|
10931
|
+
const configBaseDir = path15.dirname(configDir);
|
|
10498
10932
|
if (!existsSync8(configDir)) {
|
|
10499
10933
|
mkdirSync3(configDir, { recursive: true });
|
|
10500
10934
|
}
|
|
@@ -10512,7 +10946,7 @@ import * as os5 from "os";
|
|
|
10512
10946
|
function ensureStringArray(value) {
|
|
10513
10947
|
return Array.isArray(value) ? value : [];
|
|
10514
10948
|
}
|
|
10515
|
-
var
|
|
10949
|
+
var z2 = tool2.schema;
|
|
10516
10950
|
var indexerMap = /* @__PURE__ */ new Map();
|
|
10517
10951
|
var defaultProjectRoot = "";
|
|
10518
10952
|
function initializeTools(projectRoot, config) {
|
|
@@ -10532,12 +10966,12 @@ function shouldForceLocalizeProjectIndex(projectRoot) {
|
|
|
10532
10966
|
if (currentConfig.scope !== "project") {
|
|
10533
10967
|
return false;
|
|
10534
10968
|
}
|
|
10535
|
-
const localIndexPath =
|
|
10969
|
+
const localIndexPath = path16.join(projectRoot, ".opencode", "index");
|
|
10536
10970
|
const mainRepoRoot = resolveWorktreeMainRepoRoot(projectRoot);
|
|
10537
10971
|
if (!mainRepoRoot) {
|
|
10538
10972
|
return false;
|
|
10539
10973
|
}
|
|
10540
|
-
const inheritedIndexPath =
|
|
10974
|
+
const inheritedIndexPath = path16.join(mainRepoRoot, ".opencode", "index");
|
|
10541
10975
|
return !existsSync9(localIndexPath) && existsSync9(inheritedIndexPath);
|
|
10542
10976
|
}
|
|
10543
10977
|
function getIndexerForProject(directory) {
|
|
@@ -10553,14 +10987,14 @@ function getIndexerForProject(directory) {
|
|
|
10553
10987
|
}
|
|
10554
10988
|
return indexer;
|
|
10555
10989
|
}
|
|
10556
|
-
var codebase_peek =
|
|
10990
|
+
var codebase_peek = tool2({
|
|
10557
10991
|
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.",
|
|
10558
10992
|
args: {
|
|
10559
|
-
query:
|
|
10560
|
-
limit:
|
|
10561
|
-
fileType:
|
|
10562
|
-
directory:
|
|
10563
|
-
chunkType:
|
|
10993
|
+
query: z2.string().describe("Natural language description of what code you're looking for."),
|
|
10994
|
+
limit: z2.number().optional().default(10).describe("Maximum number of results to return"),
|
|
10995
|
+
fileType: z2.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
10996
|
+
directory: z2.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
10997
|
+
chunkType: z2.enum(["function", "class", "method", "interface", "type", "enum", "struct", "impl", "trait", "module", "other"]).optional().describe("Filter by code chunk type")
|
|
10564
10998
|
},
|
|
10565
10999
|
async execute(args, context) {
|
|
10566
11000
|
const indexer = getIndexerForProject(context?.worktree);
|
|
@@ -10573,12 +11007,12 @@ var codebase_peek = tool({
|
|
|
10573
11007
|
return formatCodebasePeek(results);
|
|
10574
11008
|
}
|
|
10575
11009
|
});
|
|
10576
|
-
var index_codebase =
|
|
11010
|
+
var index_codebase = tool2({
|
|
10577
11011
|
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.",
|
|
10578
11012
|
args: {
|
|
10579
|
-
force:
|
|
10580
|
-
estimateOnly:
|
|
10581
|
-
verbose:
|
|
11013
|
+
force: z2.boolean().optional().default(false).describe("Force reindex even if already indexed"),
|
|
11014
|
+
estimateOnly: z2.boolean().optional().default(false).describe("Only show cost estimate without indexing"),
|
|
11015
|
+
verbose: z2.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
|
|
10582
11016
|
},
|
|
10583
11017
|
async execute(args, context) {
|
|
10584
11018
|
const projectRoot = context?.worktree || defaultProjectRoot;
|
|
@@ -10611,7 +11045,7 @@ var index_codebase = tool({
|
|
|
10611
11045
|
return formatIndexStats(stats, args.verbose ?? false);
|
|
10612
11046
|
}
|
|
10613
11047
|
});
|
|
10614
|
-
var index_status =
|
|
11048
|
+
var index_status = tool2({
|
|
10615
11049
|
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.",
|
|
10616
11050
|
args: {},
|
|
10617
11051
|
async execute(_args, context) {
|
|
@@ -10620,7 +11054,7 @@ var index_status = tool({
|
|
|
10620
11054
|
return formatStatus(status);
|
|
10621
11055
|
}
|
|
10622
11056
|
});
|
|
10623
|
-
var index_health_check =
|
|
11057
|
+
var index_health_check = tool2({
|
|
10624
11058
|
description: "Check index health and remove stale entries from deleted files. Run this to clean up the index after files have been deleted.",
|
|
10625
11059
|
args: {},
|
|
10626
11060
|
async execute(_args, context) {
|
|
@@ -10629,7 +11063,7 @@ var index_health_check = tool({
|
|
|
10629
11063
|
return formatHealthCheck(result);
|
|
10630
11064
|
}
|
|
10631
11065
|
});
|
|
10632
|
-
var index_metrics =
|
|
11066
|
+
var index_metrics = tool2({
|
|
10633
11067
|
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.",
|
|
10634
11068
|
args: {},
|
|
10635
11069
|
async execute(_args, context) {
|
|
@@ -10644,12 +11078,12 @@ var index_metrics = tool({
|
|
|
10644
11078
|
return logger.formatMetrics();
|
|
10645
11079
|
}
|
|
10646
11080
|
});
|
|
10647
|
-
var index_logs =
|
|
11081
|
+
var index_logs = tool2({
|
|
10648
11082
|
description: "Get recent debug logs from the codebase indexer. Shows timestamped log entries with level and category. Requires debug.enabled=true in config.",
|
|
10649
11083
|
args: {
|
|
10650
|
-
limit:
|
|
10651
|
-
category:
|
|
10652
|
-
level:
|
|
11084
|
+
limit: z2.number().optional().default(20).describe("Maximum number of log entries to return"),
|
|
11085
|
+
category: z2.enum(["search", "embedding", "cache", "gc", "branch", "general"]).optional().describe("Filter by log category"),
|
|
11086
|
+
level: z2.enum(["error", "warn", "info", "debug"]).optional().describe("Filter by minimum log level")
|
|
10653
11087
|
},
|
|
10654
11088
|
async execute(args, context) {
|
|
10655
11089
|
const indexer = getIndexerForProject(context?.worktree);
|
|
@@ -10668,15 +11102,15 @@ var index_logs = tool({
|
|
|
10668
11102
|
return formatLogs(logs);
|
|
10669
11103
|
}
|
|
10670
11104
|
});
|
|
10671
|
-
var find_similar =
|
|
11105
|
+
var find_similar = tool2({
|
|
10672
11106
|
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.",
|
|
10673
11107
|
args: {
|
|
10674
|
-
code:
|
|
10675
|
-
limit:
|
|
10676
|
-
fileType:
|
|
10677
|
-
directory:
|
|
10678
|
-
chunkType:
|
|
10679
|
-
excludeFile:
|
|
11108
|
+
code: z2.string().describe("The code snippet to find similar code for"),
|
|
11109
|
+
limit: z2.number().optional().default(10).describe("Maximum number of results to return"),
|
|
11110
|
+
fileType: z2.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
11111
|
+
directory: z2.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
11112
|
+
chunkType: z2.enum(["function", "class", "method", "interface", "type", "enum", "struct", "impl", "trait", "module", "other"]).optional().describe("Filter by code chunk type"),
|
|
11113
|
+
excludeFile: z2.string().optional().describe("Exclude results from this file path (useful when searching for duplicates of code from a specific file)")
|
|
10680
11114
|
},
|
|
10681
11115
|
async execute(args, context) {
|
|
10682
11116
|
const indexer = getIndexerForProject(context?.worktree);
|
|
@@ -10692,15 +11126,15 @@ var find_similar = tool({
|
|
|
10692
11126
|
return formatSearchResults(results);
|
|
10693
11127
|
}
|
|
10694
11128
|
});
|
|
10695
|
-
var codebase_search =
|
|
11129
|
+
var codebase_search = tool2({
|
|
10696
11130
|
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.",
|
|
10697
11131
|
args: {
|
|
10698
|
-
query:
|
|
10699
|
-
limit:
|
|
10700
|
-
fileType:
|
|
10701
|
-
directory:
|
|
10702
|
-
chunkType:
|
|
10703
|
-
contextLines:
|
|
11132
|
+
query: z2.string().describe("Natural language description of what code you're looking for. Describe behavior, not syntax."),
|
|
11133
|
+
limit: z2.number().optional().default(5).describe("Maximum number of results to return"),
|
|
11134
|
+
fileType: z2.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
11135
|
+
directory: z2.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
11136
|
+
chunkType: z2.enum(["function", "class", "method", "interface", "type", "enum", "struct", "impl", "trait", "module", "other"]).optional().describe("Filter by code chunk type"),
|
|
11137
|
+
contextLines: z2.number().optional().describe("Number of extra lines to include before/after each match (default: 0)")
|
|
10704
11138
|
},
|
|
10705
11139
|
async execute(args, context) {
|
|
10706
11140
|
const indexer = getIndexerForProject(context?.worktree);
|
|
@@ -10716,13 +11150,13 @@ var codebase_search = tool({
|
|
|
10716
11150
|
return formatSearchResults(results, "score");
|
|
10717
11151
|
}
|
|
10718
11152
|
});
|
|
10719
|
-
var implementation_lookup =
|
|
11153
|
+
var implementation_lookup = tool2({
|
|
10720
11154
|
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.",
|
|
10721
11155
|
args: {
|
|
10722
|
-
query:
|
|
10723
|
-
limit:
|
|
10724
|
-
fileType:
|
|
10725
|
-
directory:
|
|
11156
|
+
query: z2.string().describe("Symbol name or natural language description (e.g., 'validateToken', 'where is the payment handler defined')"),
|
|
11157
|
+
limit: z2.number().optional().default(5).describe("Maximum number of results"),
|
|
11158
|
+
fileType: z2.string().optional().describe("Filter by file extension (e.g., 'ts', 'py')"),
|
|
11159
|
+
directory: z2.string().optional().describe("Filter by directory path (e.g., 'src/utils')")
|
|
10726
11160
|
},
|
|
10727
11161
|
async execute(args, context) {
|
|
10728
11162
|
const indexer = getIndexerForProject(context?.worktree);
|
|
@@ -10734,12 +11168,13 @@ var implementation_lookup = tool({
|
|
|
10734
11168
|
return formatDefinitionLookup(results, args.query);
|
|
10735
11169
|
}
|
|
10736
11170
|
});
|
|
10737
|
-
var call_graph =
|
|
10738
|
-
description: "Query the call graph to find callers or callees of a function/method. Use to understand code flow and dependencies between functions.",
|
|
11171
|
+
var call_graph = tool2({
|
|
11172
|
+
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.",
|
|
10739
11173
|
args: {
|
|
10740
|
-
name:
|
|
10741
|
-
direction:
|
|
10742
|
-
symbolId:
|
|
11174
|
+
name: z2.string().describe("Function or method name to query"),
|
|
11175
|
+
direction: z2.enum(["callers", "callees"]).default("callers").describe("Direction: 'callers' finds who calls this function, 'callees' finds what this function calls"),
|
|
11176
|
+
symbolId: z2.string().optional().describe("Symbol ID (required for 'callees' direction, returned by previous call_graph queries)"),
|
|
11177
|
+
relationshipType: z2.enum(["Call", "MethodCall", "Constructor", "Import", "Inherits", "Implements"]).optional().describe("Filter by relationship type. Omit to show all.")
|
|
10743
11178
|
},
|
|
10744
11179
|
async execute(args, context) {
|
|
10745
11180
|
const indexer = getIndexerForProject(context?.worktree);
|
|
@@ -10747,35 +11182,59 @@ var call_graph = tool({
|
|
|
10747
11182
|
if (!args.symbolId) {
|
|
10748
11183
|
return "Error: 'symbolId' is required when direction is 'callees'. First use direction='callers' to find the symbol ID.";
|
|
10749
11184
|
}
|
|
10750
|
-
const callees = await indexer.getCallees(args.symbolId);
|
|
11185
|
+
const callees = await indexer.getCallees(args.symbolId, args.relationshipType);
|
|
10751
11186
|
if (callees.length === 0) {
|
|
10752
|
-
return `No callees found for symbol ${args.symbolId}. The function may not call any other tracked functions.`;
|
|
11187
|
+
return `No callees found for symbol ${args.symbolId}${args.relationshipType ? ` with type ${args.relationshipType}` : ""}. The function may not call any other tracked functions.`;
|
|
10753
11188
|
}
|
|
10754
|
-
const formatted2 = callees.map(
|
|
10755
|
-
|
|
10756
|
-
|
|
11189
|
+
const formatted2 = callees.map((e, i) => {
|
|
11190
|
+
const conf = e.confidence !== "Direct" ? ` [${e.confidence.toLowerCase()}]` : "";
|
|
11191
|
+
return `[${i + 1}] \u2192 ${e.targetName} (${e.callType})${conf} at line ${e.line}${e.isResolved ? ` [resolved: ${e.toSymbolId}]` : " [unresolved]"}`;
|
|
11192
|
+
});
|
|
10757
11193
|
return formatted2.join("\n");
|
|
10758
11194
|
}
|
|
10759
|
-
const callers = await indexer.getCallers(args.name);
|
|
11195
|
+
const callers = await indexer.getCallers(args.name, args.relationshipType);
|
|
10760
11196
|
if (callers.length === 0) {
|
|
10761
|
-
return `No callers found for "${args.name}". It may not be called by any tracked function, or the index needs updating.`;
|
|
11197
|
+
return `No callers found for "${args.name}"${args.relationshipType ? ` with type ${args.relationshipType}` : ""}. It may not be called by any tracked function, or the index needs updating.`;
|
|
10762
11198
|
}
|
|
10763
|
-
const formatted = callers.map(
|
|
10764
|
-
|
|
10765
|
-
|
|
11199
|
+
const formatted = callers.map((e, i) => {
|
|
11200
|
+
const conf = e.confidence !== "Direct" ? ` [${e.confidence.toLowerCase()}]` : "";
|
|
11201
|
+
return `[${i + 1}] \u2190 from ${e.fromSymbolName ?? "<unknown>"} in ${e.fromSymbolFilePath ?? "<unknown file>"} [${e.fromSymbolId}] (${e.callType})${conf} at line ${e.line}${e.isResolved ? " [resolved]" : " [unresolved]"}`;
|
|
11202
|
+
});
|
|
10766
11203
|
return formatted.join("\n");
|
|
10767
11204
|
}
|
|
10768
11205
|
});
|
|
10769
|
-
var
|
|
11206
|
+
var call_graph_path = tool2({
|
|
11207
|
+
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.",
|
|
11208
|
+
args: {
|
|
11209
|
+
from: z2.string().describe("Source function/method name (starting point)"),
|
|
11210
|
+
to: z2.string().describe("Target function/method name (destination)"),
|
|
11211
|
+
maxDepth: z2.number().optional().default(10).describe("Maximum traversal depth (default: 10)")
|
|
11212
|
+
},
|
|
11213
|
+
async execute(args, context) {
|
|
11214
|
+
const indexer = getIndexerForProject(context?.worktree);
|
|
11215
|
+
const path19 = await indexer.findCallPath(args.from, args.to, args.maxDepth);
|
|
11216
|
+
if (path19.length === 0) {
|
|
11217
|
+
return `No path found between "${args.from}" and "${args.to}". They may be in disconnected components, or the call graph index needs updating.`;
|
|
11218
|
+
}
|
|
11219
|
+
const formatted = path19.map((hop, i) => {
|
|
11220
|
+
const prefix = i === 0 ? "[start]" : `--${hop.callType}-->`;
|
|
11221
|
+
const location = hop.filePath ? ` (${hop.filePath}:${hop.line})` : "";
|
|
11222
|
+
return `${prefix} ${hop.symbolName}${location}`;
|
|
11223
|
+
});
|
|
11224
|
+
return `Path (${path19.length} hops):
|
|
11225
|
+
${formatted.join("\n")}`;
|
|
11226
|
+
}
|
|
11227
|
+
});
|
|
11228
|
+
var add_knowledge_base = tool2({
|
|
10770
11229
|
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).",
|
|
10771
11230
|
args: {
|
|
10772
|
-
path:
|
|
11231
|
+
path: z2.string().describe("Path to the folder to add as a knowledge base (absolute or relative to project root)")
|
|
10773
11232
|
},
|
|
10774
11233
|
async execute(args, context) {
|
|
10775
11234
|
const projectRoot = context?.worktree || defaultProjectRoot;
|
|
10776
11235
|
const inputPath = args.path.trim();
|
|
10777
|
-
const normalizedPath =
|
|
10778
|
-
|
|
11236
|
+
const normalizedPath = path16.resolve(
|
|
11237
|
+
path16.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, projectRoot)
|
|
10779
11238
|
);
|
|
10780
11239
|
if (!existsSync9(normalizedPath)) {
|
|
10781
11240
|
return `Error: Directory does not exist: ${normalizedPath}`;
|
|
@@ -10804,7 +11263,7 @@ var add_knowledge_base = tool({
|
|
|
10804
11263
|
}
|
|
10805
11264
|
}
|
|
10806
11265
|
for (const dotDir of sensitiveDotDirs) {
|
|
10807
|
-
const sensitiveDir =
|
|
11266
|
+
const sensitiveDir = path16.join(homeDir, dotDir);
|
|
10808
11267
|
if (realPath === sensitiveDir || realPath.startsWith(sensitiveDir + "/")) {
|
|
10809
11268
|
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath}`;
|
|
10810
11269
|
}
|
|
@@ -10838,7 +11297,7 @@ Run /index to rebuild the index with the new knowledge base.`;
|
|
|
10838
11297
|
return result;
|
|
10839
11298
|
}
|
|
10840
11299
|
});
|
|
10841
|
-
var list_knowledge_bases =
|
|
11300
|
+
var list_knowledge_bases = tool2({
|
|
10842
11301
|
description: "List all configured knowledge base folders that are indexed alongside the main project.",
|
|
10843
11302
|
args: {},
|
|
10844
11303
|
async execute(_args, context) {
|
|
@@ -10875,10 +11334,10 @@ var list_knowledge_bases = tool({
|
|
|
10875
11334
|
return result;
|
|
10876
11335
|
}
|
|
10877
11336
|
});
|
|
10878
|
-
var remove_knowledge_base =
|
|
11337
|
+
var remove_knowledge_base = tool2({
|
|
10879
11338
|
description: "Remove a knowledge base folder from the semantic search index.",
|
|
10880
11339
|
args: {
|
|
10881
|
-
path:
|
|
11340
|
+
path: z2.string().describe("Path of the knowledge base to remove (must match the configured path exactly)")
|
|
10882
11341
|
},
|
|
10883
11342
|
async execute(args, context) {
|
|
10884
11343
|
const projectRoot = context?.worktree || defaultProjectRoot;
|
|
@@ -10920,7 +11379,7 @@ Run /index to rebuild the index without the removed knowledge base.`;
|
|
|
10920
11379
|
|
|
10921
11380
|
// src/commands/loader.ts
|
|
10922
11381
|
import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync7 } from "fs";
|
|
10923
|
-
import * as
|
|
11382
|
+
import * as path17 from "path";
|
|
10924
11383
|
function parseFrontmatter(content) {
|
|
10925
11384
|
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
10926
11385
|
const match = content.match(frontmatterRegex);
|
|
@@ -10946,7 +11405,7 @@ function loadCommandsFromDirectory(commandsDir) {
|
|
|
10946
11405
|
}
|
|
10947
11406
|
const files = readdirSync2(commandsDir).filter((f) => f.endsWith(".md"));
|
|
10948
11407
|
for (const file of files) {
|
|
10949
|
-
const filePath =
|
|
11408
|
+
const filePath = path17.join(commandsDir, file);
|
|
10950
11409
|
let content;
|
|
10951
11410
|
try {
|
|
10952
11411
|
content = readFileSync7(filePath, "utf-8");
|
|
@@ -10955,7 +11414,7 @@ function loadCommandsFromDirectory(commandsDir) {
|
|
|
10955
11414
|
throw new Error(`Failed to load command file ${filePath}: ${message}`);
|
|
10956
11415
|
}
|
|
10957
11416
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
10958
|
-
const name =
|
|
11417
|
+
const name = path17.basename(file, ".md");
|
|
10959
11418
|
const description = frontmatter.description || `Run the ${name} command`;
|
|
10960
11419
|
commands.set(name, {
|
|
10961
11420
|
description,
|
|
@@ -11177,7 +11636,7 @@ function assessRoutingIntent(text) {
|
|
|
11177
11636
|
reason: "no_local_discovery_signal"
|
|
11178
11637
|
};
|
|
11179
11638
|
}
|
|
11180
|
-
function buildRoutingHint(assessment, status) {
|
|
11639
|
+
function buildRoutingHint(assessment, status, includeGraphHandoff = false) {
|
|
11181
11640
|
if (assessment.intent === "definition_lookup") {
|
|
11182
11641
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
11183
11642
|
return "For this turn, if you need a symbol definition, check `index_status` first and run `index_codebase` if the index is missing or incompatible. Then use `implementation_lookup` for the definition site. Use `grep` for exhaustive literal matches.";
|
|
@@ -11188,15 +11647,21 @@ function buildRoutingHint(assessment, status) {
|
|
|
11188
11647
|
return null;
|
|
11189
11648
|
}
|
|
11190
11649
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
11191
|
-
|
|
11650
|
+
const graphHandoff2 = includeGraphHandoff ? " Use graph tools after semantic discovery identifies relevant symbols." : "";
|
|
11651
|
+
return `For this turn, if local code discovery by behavior is needed, check \`index_status\` first and run \`index_codebase\` if the index is missing or incompatible.${graphHandoff2} Use \`grep\` for exact identifiers or exhaustive matches.`;
|
|
11192
11652
|
}
|
|
11193
|
-
|
|
11653
|
+
const graphHandoff = includeGraphHandoff ? " before graph tools such as `call_graph`, `call_graph_path`, `pr_impact`, or OMO CodeGraph" : "";
|
|
11654
|
+
return `For this turn, prefer \`codebase_peek\` for local code discovery by behavior or likely location${graphHandoff}. Then use \`codebase_search\` when you need implementation content. Use \`grep\` for exact identifiers or exhaustive matches.`;
|
|
11194
11655
|
}
|
|
11195
11656
|
var RoutingHintController = class {
|
|
11196
|
-
constructor(getStatus, maxSessions = 200) {
|
|
11657
|
+
constructor(getStatus, maxSessions = 200, includeGraphHandoff = false) {
|
|
11197
11658
|
this.getStatus = getStatus;
|
|
11198
11659
|
this.maxSessions = maxSessions;
|
|
11660
|
+
this.includeGraphHandoff = includeGraphHandoff;
|
|
11199
11661
|
}
|
|
11662
|
+
getStatus;
|
|
11663
|
+
maxSessions;
|
|
11664
|
+
includeGraphHandoff;
|
|
11200
11665
|
sessionState = /* @__PURE__ */ new Map();
|
|
11201
11666
|
observeUserMessage(sessionID, parts) {
|
|
11202
11667
|
const assessment = assessRoutingIntent(extractUserText(parts));
|
|
@@ -11217,7 +11682,7 @@ var RoutingHintController = class {
|
|
|
11217
11682
|
return [];
|
|
11218
11683
|
}
|
|
11219
11684
|
const status = await this.safeGetStatus();
|
|
11220
|
-
const hint = buildRoutingHint(state.assessment, status);
|
|
11685
|
+
const hint = buildRoutingHint(state.assessment, status, this.includeGraphHandoff);
|
|
11221
11686
|
return hint ? [hint] : [];
|
|
11222
11687
|
}
|
|
11223
11688
|
markToolUsed(sessionID, toolName) {
|
|
@@ -11267,9 +11732,9 @@ function replaceActiveWatcher(projectRoot, nextWatcher) {
|
|
|
11267
11732
|
function getCommandsDir() {
|
|
11268
11733
|
let currentDir = process.cwd();
|
|
11269
11734
|
if (typeof import.meta !== "undefined" && import.meta.url) {
|
|
11270
|
-
currentDir =
|
|
11735
|
+
currentDir = path18.dirname(fileURLToPath2(import.meta.url));
|
|
11271
11736
|
}
|
|
11272
|
-
return
|
|
11737
|
+
return path18.join(currentDir, "..", "commands");
|
|
11273
11738
|
}
|
|
11274
11739
|
function appendRoutingHints(output, hints, preferredRole) {
|
|
11275
11740
|
const preferredBucket = preferredRole === "developer" ? output.developer : output.system;
|
|
@@ -11288,8 +11753,8 @@ var plugin = async ({ directory, worktree }) => {
|
|
|
11288
11753
|
const config = parseConfig(rawConfig);
|
|
11289
11754
|
initializeTools(projectRoot, config);
|
|
11290
11755
|
const getProjectIndexer = () => getIndexerForProject(projectRoot);
|
|
11291
|
-
const routingHints = config.search.routingHints ? new RoutingHintController(() => getProjectIndexer().getStatus()) : null;
|
|
11292
|
-
const isHomeDir =
|
|
11756
|
+
const routingHints = config.search.routingHints ? new RoutingHintController(() => getProjectIndexer().getStatus(), 200, config.search.routingGraphHandoffHints) : null;
|
|
11757
|
+
const isHomeDir = path18.resolve(projectRoot) === path18.resolve(os6.homedir());
|
|
11293
11758
|
const isValidProject = !isHomeDir && (!config.indexing.requireProjectMarker || hasProjectMarker(projectRoot));
|
|
11294
11759
|
if (isHomeDir) {
|
|
11295
11760
|
console.warn(
|
|
@@ -11324,10 +11789,12 @@ var plugin = async ({ directory, worktree }) => {
|
|
|
11324
11789
|
index_logs,
|
|
11325
11790
|
find_similar,
|
|
11326
11791
|
call_graph,
|
|
11792
|
+
call_graph_path,
|
|
11327
11793
|
implementation_lookup,
|
|
11328
11794
|
add_knowledge_base,
|
|
11329
11795
|
list_knowledge_bases,
|
|
11330
|
-
remove_knowledge_base
|
|
11796
|
+
remove_knowledge_base,
|
|
11797
|
+
pr_impact
|
|
11331
11798
|
},
|
|
11332
11799
|
async "chat.message"(input, output) {
|
|
11333
11800
|
routingHints?.observeUserMessage(input.sessionID, output.parts);
|