agen-vektor 0.3.12 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/agent.js +61 -1
- package/dist/agent/loop.js +5 -0
- package/dist/agent/prompts.js +1 -1
- package/dist/cli/index.js +24 -20
- package/dist/cli/keyboard.js +56 -3
- package/dist/config/free-tier.js +230 -0
- package/dist/providers/openai-compat.js +70 -28
- package/dist/tools/search.js +62 -12
- package/dist/tui/app.js +298 -75
- package/dist/tui/commands.js +1 -0
- package/dist/tui/components.js +143 -68
- package/dist/tui/input.js +24 -0
- package/dist/tui/suggest.js +27 -9
- package/dist/utils/terminal.js +6 -0
- package/package.json +4 -1
package/dist/tools/search.js
CHANGED
|
@@ -36,8 +36,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.createSearchTools = createSearchTools;
|
|
37
37
|
/**
|
|
38
38
|
* Search tools — search files by name or content.
|
|
39
|
-
* Implementation uses ripgrep
|
|
39
|
+
* Implementation uses ripgrep when available, else a pure-Node
|
|
40
40
|
* recursive walk with string matching (slow but dependency-free).
|
|
41
|
+
*
|
|
42
|
+
* Ripgrep resolution order:
|
|
43
|
+
* 1. @vscode/ripgrep bundled binary (optionalDependency — ships the rg
|
|
44
|
+
* binary in the npm tarball via per-platform optionalDependencies, so
|
|
45
|
+
* `npm i -g agen-vektor` auto-installs it with NO install scripts,
|
|
46
|
+
* safe under npm 12's allowScripts=off default; skipped silently on
|
|
47
|
+
* exotic platforms, where the fallback below takes over)
|
|
48
|
+
* 2. `rg` found on PATH
|
|
49
|
+
* 3. pure-Node fallback (always works)
|
|
41
50
|
*/
|
|
42
51
|
const fs = __importStar(require("node:fs"));
|
|
43
52
|
const path = __importStar(require("node:path"));
|
|
@@ -45,17 +54,40 @@ const node_child_process_1 = require("node:child_process");
|
|
|
45
54
|
const node_util_1 = require("node:util");
|
|
46
55
|
const execFileP = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
47
56
|
const IGNORE = new Set(['.git', 'node_modules', 'vendor', 'dist', 'build', '.cache', '.env', '.next', 'target', 'coverage']);
|
|
48
|
-
|
|
57
|
+
/** Bundled ripgrep from @vscode/ripgrep, when the optional dep installed. */
|
|
58
|
+
function bundledRgPath() {
|
|
49
59
|
try {
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
61
|
+
const { rgPath } = require('@vscode/ripgrep');
|
|
62
|
+
if (rgPath && fs.existsSync(rgPath))
|
|
63
|
+
return rgPath;
|
|
52
64
|
}
|
|
53
65
|
catch {
|
|
54
|
-
|
|
66
|
+
/* optional dep not installed (npm 12 script-skip / exotic platform) */
|
|
55
67
|
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
/** Probe a candidate rg binary (bundled path or PATH lookup). */
|
|
71
|
+
function probeRg(cmd) {
|
|
72
|
+
const res = (0, node_child_process_1.spawnSync)(cmd, ['--version'], { stdio: 'ignore' });
|
|
73
|
+
return !res.error;
|
|
74
|
+
}
|
|
75
|
+
function hasRg() {
|
|
76
|
+
// NOTE: spawnSync does NOT throw when the binary is missing — it returns
|
|
77
|
+
// { error: ENOENT }. A try/catch here never fired, so the old check
|
|
78
|
+
// wrongly returned true on machines without ripgrep and every search
|
|
79
|
+
// died with "spawn rg ENOENT" instead of using the pure-Node fallback.
|
|
80
|
+
const bundled = bundledRgPath();
|
|
81
|
+
if (bundled && probeRg(bundled))
|
|
82
|
+
return true;
|
|
83
|
+
return probeRg('rg');
|
|
56
84
|
}
|
|
57
|
-
|
|
58
|
-
|
|
85
|
+
/** Which rg binary to actually spawn (bundled first, then PATH). */
|
|
86
|
+
function rgCommand() {
|
|
87
|
+
const bundled = bundledRgPath();
|
|
88
|
+
if (bundled && probeRg(bundled))
|
|
89
|
+
return bundled;
|
|
90
|
+
return 'rg';
|
|
59
91
|
}
|
|
60
92
|
function walkFiles(dir, out, max) {
|
|
61
93
|
let entries;
|
|
@@ -114,9 +146,16 @@ function createSearchTools() {
|
|
|
114
146
|
}
|
|
115
147
|
async function runRg(base, query, filename, max) {
|
|
116
148
|
try {
|
|
117
|
-
|
|
149
|
+
// NOTE: --max-count must appear exactly once. Passing both "-m 1" and
|
|
150
|
+
// "--max-count 3" makes ripgrep exit with code 2 ("The argument
|
|
151
|
+
// '--max-count' was provided more than once") — a bug that silently
|
|
152
|
+
// broke every search when rg was installed.
|
|
153
|
+
const args = ['--no-ignore', '--line-number', '--max-count', '3'];
|
|
154
|
+
// "**/<dir>/**" so exclusion works even when the search base is an
|
|
155
|
+
// absolute path outside the rg process cwd (plain "!dir/**" only
|
|
156
|
+
// matches relative to cwd — bit us with tmpdir-based tests).
|
|
118
157
|
for (const ig of IGNORE)
|
|
119
|
-
args.push('-g',
|
|
158
|
+
args.push('-g', `!**/${ig}/**`);
|
|
120
159
|
if (filename) {
|
|
121
160
|
args.push('-g', filename.includes('*') ? filename : `*${filename}*`);
|
|
122
161
|
}
|
|
@@ -124,9 +163,12 @@ async function runRg(base, query, filename, max) {
|
|
|
124
163
|
args.push('--', query, base);
|
|
125
164
|
}
|
|
126
165
|
else {
|
|
127
|
-
|
|
166
|
+
// Filename-only search: --files lists matching paths. (The previous
|
|
167
|
+
// empty-pattern hack "rg -l -- '' <dir>" matched nothing, so
|
|
168
|
+
// filename search never returned results.)
|
|
169
|
+
args.push('--files', base);
|
|
128
170
|
}
|
|
129
|
-
const { stdout } = await execFileP(
|
|
171
|
+
const { stdout } = await execFileP(rgCommand(), args, { maxBuffer: 10 * 1024 * 1024 });
|
|
130
172
|
const lines = stdout.split('\n').filter(Boolean).slice(0, max);
|
|
131
173
|
if (lines.length === 0) {
|
|
132
174
|
return { output: 'no matches found', summary: 'search: no matches' };
|
|
@@ -167,7 +209,15 @@ function fallbackSearch(base, query, filename, max, cwd) {
|
|
|
167
209
|
try {
|
|
168
210
|
const content = fs.readFileSync(f, 'utf8');
|
|
169
211
|
if (content.includes(query)) {
|
|
170
|
-
|
|
212
|
+
// Include line numbers like ripgrep does — the tool description
|
|
213
|
+
// promises "line numbers for text search".
|
|
214
|
+
const lines = content.split('\n');
|
|
215
|
+
const hits = [];
|
|
216
|
+
for (let i = 0; i < lines.length && hits.length < 3; i++) {
|
|
217
|
+
if (lines[i].includes(query))
|
|
218
|
+
hits.push(`${rel}:${i + 1}`);
|
|
219
|
+
}
|
|
220
|
+
results.push(hits.length > 0 ? hits.join('\n') : rel);
|
|
171
221
|
}
|
|
172
222
|
}
|
|
173
223
|
catch {
|