@neetru/cli 2.13.1 → 2.15.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/CHANGELOG.md +27 -0
- package/dist/commands/ai.js +8 -8
- package/dist/commands/autocomplete.d.ts +1 -1
- package/dist/commands/autocomplete.js +1 -0
- package/dist/commands/autocomplete.js.map +1 -1
- package/dist/commands/code.d.ts +27 -0
- package/dist/commands/code.js +469 -0
- package/dist/commands/code.js.map +1 -0
- package/dist/commands/fn.d.ts +6 -0
- package/dist/commands/fn.js +88 -0
- package/dist/commands/fn.js.map +1 -0
- package/dist/commands/init.js +147 -147
- package/dist/commands/marketplace.d.ts +36 -0
- package/dist/commands/marketplace.js +585 -0
- package/dist/commands/marketplace.js.map +1 -0
- package/dist/commands/ui.d.ts +1 -1
- package/dist/commands/ui.js +9 -0
- package/dist/commands/ui.js.map +1 -1
- package/dist/index.js +19 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/ai/context.js +91 -91
- package/dist/lib/ai/orchestrator.js +7 -43
- package/dist/lib/ai/orchestrator.js.map +1 -1
- package/dist/lib/api-client.d.ts +1 -0
- package/dist/lib/api-client.js +4 -3
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/code-agent-files.d.ts +47 -0
- package/dist/lib/code-agent-files.js +468 -0
- package/dist/lib/code-agent-files.js.map +1 -0
- package/dist/lib/code-agent-gateway.d.ts +27 -0
- package/dist/lib/code-agent-gateway.js +115 -0
- package/dist/lib/code-agent-gateway.js.map +1 -0
- package/dist/lib/code-agent-protocol.d.ts +24 -0
- package/dist/lib/code-agent-protocol.js +56 -0
- package/dist/lib/code-agent-protocol.js.map +1 -0
- package/dist/lib/code-agent-session.d.ts +54 -0
- package/dist/lib/code-agent-session.js +147 -0
- package/dist/lib/code-agent-session.js.map +1 -0
- package/dist/lib/code-agent-settings.d.ts +20 -0
- package/dist/lib/code-agent-settings.js +38 -0
- package/dist/lib/code-agent-settings.js.map +1 -0
- package/dist/lib/code-agent-tools.d.ts +17 -0
- package/dist/lib/code-agent-tools.js +52 -0
- package/dist/lib/code-agent-tools.js.map +1 -0
- package/dist/lib/code-agent-types.d.ts +34 -0
- package/dist/lib/code-agent-types.js +7 -0
- package/dist/lib/code-agent-types.js.map +1 -0
- package/dist/lib/code-agent-ui.d.ts +30 -0
- package/dist/lib/code-agent-ui.js +258 -0
- package/dist/lib/code-agent-ui.js.map +1 -0
- package/dist/lib/sse.d.ts +14 -0
- package/dist/lib/sse.js +43 -0
- package/dist/lib/sse.js.map +1 -0
- package/package.json +1 -1
- package/templates/auth/callback.ts +22 -22
- package/templates/auth/sign-in.tsx +41 -41
- package/templates/billing/checkout.ts +22 -22
- package/templates/billing/page.tsx +43 -43
- package/templates/support/ticket-form.tsx +68 -68
- package/templates/usage/track.ts +30 -30
- package/templates/users/profile.tsx +43 -43
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
const DEFAULT_IGNORES = new Set([
|
|
5
|
+
'.git',
|
|
6
|
+
'.hg',
|
|
7
|
+
'.svn',
|
|
8
|
+
'node_modules',
|
|
9
|
+
'.next',
|
|
10
|
+
'dist',
|
|
11
|
+
'build',
|
|
12
|
+
'coverage',
|
|
13
|
+
'.turbo',
|
|
14
|
+
]);
|
|
15
|
+
const MAX_FILE_BYTES = 250_000;
|
|
16
|
+
const MAX_FILE_CHARS = 40_000;
|
|
17
|
+
const MAX_LIST_FILES = 300;
|
|
18
|
+
const MAX_SEARCH_MATCHES = 80;
|
|
19
|
+
const MAX_TOOL_OUTPUT_CHARS = 60_000;
|
|
20
|
+
// Fase 3 (NEETRU_CODE_ARCHITECTURE.md): limites das ferramentas produtivas.
|
|
21
|
+
const MAX_READ_MANY_FILES = 20;
|
|
22
|
+
const MAX_REGEX_PATTERN_CHARS = 200;
|
|
23
|
+
const MAX_REGEX_LINE_CHARS = 2_000; // pula linhas absurdamente longas (ex: minificado) — reduz risco de ReDoS.
|
|
24
|
+
const MAX_SYMBOL_FILES = 200;
|
|
25
|
+
const MAX_SYMBOLS = 300;
|
|
26
|
+
const RUN_TESTS_TIMEOUT_MS = 120_000;
|
|
27
|
+
function normalizeForCompare(value) {
|
|
28
|
+
return process.platform === 'win32' ? value.toLowerCase() : value;
|
|
29
|
+
}
|
|
30
|
+
function isInside(root, target) {
|
|
31
|
+
const rootCmp = normalizeForCompare(root);
|
|
32
|
+
const targetCmp = normalizeForCompare(target);
|
|
33
|
+
return targetCmp === rootCmp || targetCmp.startsWith(`${rootCmp}${path.sep}`);
|
|
34
|
+
}
|
|
35
|
+
export function resolveInside(rootDir, inputPath) {
|
|
36
|
+
const root = path.resolve(rootDir);
|
|
37
|
+
const resolved = path.resolve(root, inputPath);
|
|
38
|
+
if (!isInside(root, resolved)) {
|
|
39
|
+
throw new Error(`Path fora do cwd: ${inputPath}`);
|
|
40
|
+
}
|
|
41
|
+
// Contenção lexical nao basta: um symlink/junction DENTRO do cwd pode
|
|
42
|
+
// apontar pra fora (ex: `leak -> ~/.config/neetru-cli/auth.json`) e vazar
|
|
43
|
+
// pro contexto do gateway. Resolve o path real e reconfirma a contencao —
|
|
44
|
+
// só roda se o arquivo existir (achado do Codex review 2026-07-09).
|
|
45
|
+
if (fs.existsSync(resolved)) {
|
|
46
|
+
const realRoot = fs.realpathSync(root);
|
|
47
|
+
const realResolved = fs.realpathSync(resolved);
|
|
48
|
+
if (!isInside(realRoot, realResolved)) {
|
|
49
|
+
throw new Error(`Path fora do cwd (symlink aponta pra fora): ${inputPath}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return resolved;
|
|
53
|
+
}
|
|
54
|
+
function toRelative(rootDir, fullPath) {
|
|
55
|
+
return path.relative(path.resolve(rootDir), fullPath).replace(/\\/g, '/');
|
|
56
|
+
}
|
|
57
|
+
// Arquivos que tipicamente carregam segredo bruto — bloqueados mesmo dentro
|
|
58
|
+
// do cwd. Path injection pelo modelo (README/issue com NEETRU_TOOL embutido)
|
|
59
|
+
// nao consegue fazer a IA ler .env/chave/credencial e mandar de volta pro
|
|
60
|
+
// gateway (achado do Codex review 2026-07-09).
|
|
61
|
+
const SECRET_PATH_PATTERN = /(^|[\\/])(\.env(\..+)?|[^\\/]+\.(pem|key|pfx|p12)|id_rsa\w*|id_ed25519\w*|credentials\.json|service[-_]?account.*\.json)$/i;
|
|
62
|
+
function isSecretPath(relativePath) {
|
|
63
|
+
return SECRET_PATH_PATTERN.test(relativePath);
|
|
64
|
+
}
|
|
65
|
+
// Redação defense-in-depth: mesmo em arquivos "normais", uma linha com cara
|
|
66
|
+
// de segredo hardcoded nao vai pro contexto do gateway em texto claro.
|
|
67
|
+
const SECRET_LINE_PATTERN = /((?:api[_-]?key|secret|token|password|passwd)\s*[:=]\s*['"]?)([A-Za-z0-9_\-.\/+]{12,})/gi;
|
|
68
|
+
export function redactSecrets(content) {
|
|
69
|
+
return content.replace(SECRET_LINE_PATTERN, '$1[REDACTED]');
|
|
70
|
+
}
|
|
71
|
+
function clipToolOutput(label, content, maxChars = MAX_TOOL_OUTPUT_CHARS) {
|
|
72
|
+
if (content.length <= maxChars)
|
|
73
|
+
return content;
|
|
74
|
+
return `${content.slice(0, maxChars)}\n\n[TRUNCADO: ${label} maior que ${maxChars} chars]`;
|
|
75
|
+
}
|
|
76
|
+
function runGit(rootDir, args) {
|
|
77
|
+
const result = spawnSync('git', args, { cwd: rootDir, encoding: 'utf8' });
|
|
78
|
+
return {
|
|
79
|
+
ok: result.status === 0,
|
|
80
|
+
stdout: result.stdout ?? '',
|
|
81
|
+
stderr: result.stderr ?? '',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function readFileContext(rootDir, inputPath) {
|
|
85
|
+
const fullPath = resolveInside(rootDir, inputPath);
|
|
86
|
+
const relative = toRelative(rootDir, fullPath);
|
|
87
|
+
if (isSecretPath(relative)) {
|
|
88
|
+
throw new Error(`Leitura bloqueada: "${relative}" parece conter segredo (.env/chave/credencial). ` +
|
|
89
|
+
'Cole o trecho necessario manualmente se precisar que a IA veja.');
|
|
90
|
+
}
|
|
91
|
+
const stat = fs.statSync(fullPath);
|
|
92
|
+
if (!stat.isFile())
|
|
93
|
+
throw new Error(`Nao e arquivo: ${inputPath}`);
|
|
94
|
+
if (stat.size > MAX_FILE_BYTES) {
|
|
95
|
+
throw new Error(`Arquivo muito grande para contexto: ${inputPath} (${stat.size} bytes)`);
|
|
96
|
+
}
|
|
97
|
+
const content = redactSecrets(fs.readFileSync(fullPath, 'utf8'));
|
|
98
|
+
const clipped = content.length > MAX_FILE_CHARS
|
|
99
|
+
? `${content.slice(0, MAX_FILE_CHARS)}\n\n[TRUNCADO: arquivo maior que ${MAX_FILE_CHARS} chars]`
|
|
100
|
+
: content;
|
|
101
|
+
return `--- ${relative} ---\n${clipped}`;
|
|
102
|
+
}
|
|
103
|
+
function walkFiles(rootDir) {
|
|
104
|
+
const out = [];
|
|
105
|
+
function walk(dir) {
|
|
106
|
+
if (out.length >= MAX_LIST_FILES)
|
|
107
|
+
return;
|
|
108
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
109
|
+
if (DEFAULT_IGNORES.has(entry.name))
|
|
110
|
+
continue;
|
|
111
|
+
const full = path.join(dir, entry.name);
|
|
112
|
+
if (entry.isDirectory()) {
|
|
113
|
+
walk(full);
|
|
114
|
+
}
|
|
115
|
+
else if (entry.isFile()) {
|
|
116
|
+
out.push(toRelative(rootDir, full));
|
|
117
|
+
}
|
|
118
|
+
if (out.length >= MAX_LIST_FILES)
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
walk(path.resolve(rootDir));
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
export function listFiles(rootDir, pattern = '') {
|
|
126
|
+
const git = spawnSync('git', ['ls-files'], { cwd: rootDir, encoding: 'utf8' });
|
|
127
|
+
let files = git.status === 0
|
|
128
|
+
? git.stdout.split(/\r?\n/).filter(Boolean)
|
|
129
|
+
: walkFiles(rootDir);
|
|
130
|
+
const needle = pattern.trim().toLowerCase();
|
|
131
|
+
if (needle)
|
|
132
|
+
files = files.filter((file) => file.toLowerCase().includes(needle));
|
|
133
|
+
return files.slice(0, MAX_LIST_FILES);
|
|
134
|
+
}
|
|
135
|
+
export function searchFiles(rootDir, query) {
|
|
136
|
+
const needle = query;
|
|
137
|
+
if (!needle)
|
|
138
|
+
return [];
|
|
139
|
+
const matches = [];
|
|
140
|
+
for (const file of listFiles(rootDir)) {
|
|
141
|
+
if (matches.length >= MAX_SEARCH_MATCHES)
|
|
142
|
+
break;
|
|
143
|
+
if (isSecretPath(file))
|
|
144
|
+
continue;
|
|
145
|
+
try {
|
|
146
|
+
const full = resolveInside(rootDir, file);
|
|
147
|
+
const stat = fs.statSync(full);
|
|
148
|
+
if (!stat.isFile() || stat.size > MAX_FILE_BYTES)
|
|
149
|
+
continue;
|
|
150
|
+
const lines = redactSecrets(fs.readFileSync(full, 'utf8')).split(/\r?\n/);
|
|
151
|
+
for (let i = 0; i < lines.length; i++) {
|
|
152
|
+
if (lines[i].includes(needle)) {
|
|
153
|
+
matches.push(`${file}:${i + 1}: ${lines[i].slice(0, 240)}`);
|
|
154
|
+
if (matches.length >= MAX_SEARCH_MATCHES)
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return matches;
|
|
164
|
+
}
|
|
165
|
+
export function getGitStatusSummary(rootDir) {
|
|
166
|
+
const branch = runGit(rootDir, ['branch', '--show-current']);
|
|
167
|
+
const status = runGit(rootDir, ['status', '--short']);
|
|
168
|
+
if (!status.ok) {
|
|
169
|
+
return `ERRO: git status falhou: ${(status.stderr || status.stdout || 'repo sem git?').trim()}`;
|
|
170
|
+
}
|
|
171
|
+
const changed = status.stdout.split(/\r?\n/).filter(Boolean);
|
|
172
|
+
return [
|
|
173
|
+
`branch: ${branch.ok && branch.stdout.trim() ? branch.stdout.trim() : '(sem branch)'}`,
|
|
174
|
+
`arquivos alterados: ${changed.length}`,
|
|
175
|
+
changed.length ? changed.join('\n') : '(worktree limpo)',
|
|
176
|
+
].join('\n');
|
|
177
|
+
}
|
|
178
|
+
export function getGitDiff(rootDir) {
|
|
179
|
+
const diff = runGit(rootDir, ['diff', '--', '.']);
|
|
180
|
+
if (!diff.ok) {
|
|
181
|
+
return `ERRO: git diff falhou: ${(diff.stderr || diff.stdout || 'repo sem git?').trim()}`;
|
|
182
|
+
}
|
|
183
|
+
const redacted = redactSecrets(diff.stdout);
|
|
184
|
+
return clipToolOutput('git diff', redacted || '(sem diff)');
|
|
185
|
+
}
|
|
186
|
+
export function getProjectOverview(rootDir) {
|
|
187
|
+
const files = listFiles(rootDir);
|
|
188
|
+
const rows = [
|
|
189
|
+
`pasta: ${path.resolve(rootDir)}`,
|
|
190
|
+
`arquivos rastreados/listados: ${files.length}`,
|
|
191
|
+
];
|
|
192
|
+
const packageJson = path.join(path.resolve(rootDir), 'package.json');
|
|
193
|
+
if (fs.existsSync(packageJson)) {
|
|
194
|
+
try {
|
|
195
|
+
const pkg = JSON.parse(fs.readFileSync(packageJson, 'utf8'));
|
|
196
|
+
if (typeof pkg.name === 'string')
|
|
197
|
+
rows.push(`package: ${pkg.name}`);
|
|
198
|
+
if (typeof pkg.version === 'string')
|
|
199
|
+
rows.push(`versao: ${pkg.version}`);
|
|
200
|
+
const scripts = pkg.scripts ? Object.keys(pkg.scripts).slice(0, 12) : [];
|
|
201
|
+
if (scripts.length)
|
|
202
|
+
rows.push(`scripts: ${scripts.join(', ')}`);
|
|
203
|
+
rows.push(`deps: ${pkg.dependencies ? Object.keys(pkg.dependencies).length : 0}`);
|
|
204
|
+
rows.push(`devDeps: ${pkg.devDependencies ? Object.keys(pkg.devDependencies).length : 0}`);
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
rows.push(`package.json: erro ao ler (${error instanceof Error ? error.message : String(error)})`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
rows.push('');
|
|
211
|
+
rows.push('arquivos principais:');
|
|
212
|
+
rows.push(...files.slice(0, 80));
|
|
213
|
+
if (files.length > 80)
|
|
214
|
+
rows.push(`... mais ${files.length - 80} arquivo(s)`);
|
|
215
|
+
return rows.join('\n');
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Le varios arquivos numa so chamada (Fase 3) — bounded pra nao estourar o
|
|
219
|
+
* contexto do gateway numa unica tool call. Reusa readFileContext (mesma
|
|
220
|
+
* contencao de path/symlink + bloqueio de segredo + truncamento por arquivo).
|
|
221
|
+
* Um path invalido nao aborta os demais — devolve a mensagem de erro inline
|
|
222
|
+
* no lugar do conteudo, como o resto das tools.
|
|
223
|
+
*/
|
|
224
|
+
export function readManyFiles(rootDir, paths) {
|
|
225
|
+
const bounded = paths.slice(0, MAX_READ_MANY_FILES);
|
|
226
|
+
const blocks = bounded.map((p) => {
|
|
227
|
+
try {
|
|
228
|
+
return readFileContext(rootDir, p);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
return `--- ${p} ---\nERRO: ${error instanceof Error ? error.message : String(error)}`;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
if (paths.length > MAX_READ_MANY_FILES) {
|
|
235
|
+
blocks.push(`[TRUNCADO: pedidos ${paths.length}, lidos ${MAX_READ_MANY_FILES}]`);
|
|
236
|
+
}
|
|
237
|
+
return clipToolOutput('read_many_files', blocks.join('\n\n'));
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Busca por regex (Fase 3) — mesma varredura arquivo-a-arquivo de searchFiles,
|
|
241
|
+
* mas casando `pattern` como expressao regular em vez de substring literal.
|
|
242
|
+
*
|
|
243
|
+
* Mitigacao ReDoS (defense-in-depth, nao prova formal): pattern vem do
|
|
244
|
+
* modelo, entao (1) limita tamanho do pattern, (2) testa linha-a-linha (nao
|
|
245
|
+
* o arquivo inteiro) e pula linhas absurdamente longas, (3) constroi UM
|
|
246
|
+
* RegExp por chamada (nao por linha) mas sempre sem estado global preso
|
|
247
|
+
* entre chamadas (`String.prototype.match`, nao `exec` com `g` reaproveitado).
|
|
248
|
+
*/
|
|
249
|
+
export function searchFilesRegex(rootDir, pattern, flags = '') {
|
|
250
|
+
if (!pattern)
|
|
251
|
+
return [];
|
|
252
|
+
if (pattern.length > MAX_REGEX_PATTERN_CHARS) {
|
|
253
|
+
throw new Error(`Pattern regex maior que ${MAX_REGEX_PATTERN_CHARS} chars.`);
|
|
254
|
+
}
|
|
255
|
+
const safeFlags = Array.from(new Set(flags.split(''))).filter((f) => 'imsu'.includes(f)).join('');
|
|
256
|
+
let regex;
|
|
257
|
+
try {
|
|
258
|
+
regex = new RegExp(pattern, safeFlags);
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
throw new Error(`Regex invalida: ${error instanceof Error ? error.message : String(error)}`);
|
|
262
|
+
}
|
|
263
|
+
const matches = [];
|
|
264
|
+
for (const file of listFiles(rootDir)) {
|
|
265
|
+
if (matches.length >= MAX_SEARCH_MATCHES)
|
|
266
|
+
break;
|
|
267
|
+
if (isSecretPath(file))
|
|
268
|
+
continue;
|
|
269
|
+
try {
|
|
270
|
+
const full = resolveInside(rootDir, file);
|
|
271
|
+
const stat = fs.statSync(full);
|
|
272
|
+
if (!stat.isFile() || stat.size > MAX_FILE_BYTES)
|
|
273
|
+
continue;
|
|
274
|
+
const lines = redactSecrets(fs.readFileSync(full, 'utf8')).split(/\r?\n/);
|
|
275
|
+
for (let i = 0; i < lines.length; i++) {
|
|
276
|
+
if (lines[i].length > MAX_REGEX_LINE_CHARS)
|
|
277
|
+
continue;
|
|
278
|
+
if (regex.test(lines[i])) {
|
|
279
|
+
matches.push(`${file}:${i + 1}: ${lines[i].slice(0, 240)}`);
|
|
280
|
+
if (matches.length >= MAX_SEARCH_MATCHES)
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return matches;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Roda o script `test` do package.json (Fase 3) — SEM aceitar comando livre
|
|
293
|
+
* do modelo. O modelo so pode disparar exatamente o script ja configurado
|
|
294
|
+
* pelo dev no projeto (allowlist = "so o que ja existe em package.json.scripts
|
|
295
|
+
* .test"); isso fecha a porta pra um "run_tests" virar backdoor de execucao
|
|
296
|
+
* arbitraria de comando via prompt injection.
|
|
297
|
+
*/
|
|
298
|
+
export function runProjectTests(rootDir) {
|
|
299
|
+
const pkgPath = path.join(path.resolve(rootDir), 'package.json');
|
|
300
|
+
if (!fs.existsSync(pkgPath)) {
|
|
301
|
+
return 'ERRO: package.json nao encontrado — sem script de teste configurado.';
|
|
302
|
+
}
|
|
303
|
+
let scripts = {};
|
|
304
|
+
try {
|
|
305
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
306
|
+
scripts = pkg.scripts ?? {};
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
return `ERRO: package.json invalido: ${error instanceof Error ? error.message : String(error)}`;
|
|
310
|
+
}
|
|
311
|
+
if (typeof scripts.test !== 'string' || !scripts.test.trim()) {
|
|
312
|
+
return 'ERRO: package.json nao tem script "test" configurado.';
|
|
313
|
+
}
|
|
314
|
+
const result = spawnSync('npm', ['test', '--silent'], {
|
|
315
|
+
cwd: rootDir,
|
|
316
|
+
encoding: 'utf8',
|
|
317
|
+
timeout: RUN_TESTS_TIMEOUT_MS,
|
|
318
|
+
// Windows resolve `npm` como `npm.cmd` — spawnSync sem shell falha (ENOENT
|
|
319
|
+
// silencioso, status null) sem isso. Mesmo padrao de build.ts/bootstrap.ts.
|
|
320
|
+
shell: process.platform === 'win32',
|
|
321
|
+
});
|
|
322
|
+
const output = [result.stdout, result.stderr].filter(Boolean).join('\n');
|
|
323
|
+
const redacted = redactSecrets(output);
|
|
324
|
+
const status = result.status === 0 ? 'PASSOU' : `FALHOU (exit ${result.status ?? 'timeout'})`;
|
|
325
|
+
return clipToolOutput('run_tests', `status: ${status}\n\n${redacted || '(sem saida)'}`);
|
|
326
|
+
}
|
|
327
|
+
const SYMBOL_PATTERN = /^\s*export\s+(?:default\s+)?(?:async\s+)?(function\*?|class|const|let|interface|type|enum)\s+([A-Za-z_$][\w$]*)/;
|
|
328
|
+
/**
|
|
329
|
+
* Outline leve de simbolos exportados (Fase 3) — sem language server: regex
|
|
330
|
+
* sobre `export function/class/const/interface/type/enum` no topo do
|
|
331
|
+
* arquivo. Suficiente pra IA se orientar sem ler o arquivo inteiro; nao
|
|
332
|
+
* substitui `read_file` quando precisar do corpo real.
|
|
333
|
+
*/
|
|
334
|
+
export function projectSymbols(rootDir, targetPath) {
|
|
335
|
+
const files = targetPath ? [targetPath] : listFiles(rootDir).filter((f) => /\.(ts|tsx|js|jsx)$/.test(f));
|
|
336
|
+
const bounded = files.slice(0, MAX_SYMBOL_FILES);
|
|
337
|
+
const rows = [];
|
|
338
|
+
for (const file of bounded) {
|
|
339
|
+
if (rows.length >= MAX_SYMBOLS)
|
|
340
|
+
break;
|
|
341
|
+
if (isSecretPath(file))
|
|
342
|
+
continue;
|
|
343
|
+
try {
|
|
344
|
+
const full = resolveInside(rootDir, file);
|
|
345
|
+
const stat = fs.statSync(full);
|
|
346
|
+
if (!stat.isFile() || stat.size > MAX_FILE_BYTES)
|
|
347
|
+
continue;
|
|
348
|
+
const lines = fs.readFileSync(full, 'utf8').split(/\r?\n/);
|
|
349
|
+
for (let i = 0; i < lines.length; i++) {
|
|
350
|
+
const match = SYMBOL_PATTERN.exec(lines[i]);
|
|
351
|
+
if (match) {
|
|
352
|
+
rows.push(`${file}:${i + 1}: ${match[1]} ${match[2]}`);
|
|
353
|
+
if (rows.length >= MAX_SYMBOLS)
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (rows.length === 0)
|
|
363
|
+
return '(nenhum simbolo exportado encontrado)';
|
|
364
|
+
if (files.length > bounded.length)
|
|
365
|
+
rows.push(`[TRUNCADO: ${files.length} arquivo(s) elegiveis, ${bounded.length} varridos]`);
|
|
366
|
+
return rows.join('\n');
|
|
367
|
+
}
|
|
368
|
+
export function runCodeTool(rootDir, request) {
|
|
369
|
+
try {
|
|
370
|
+
if (request.tool === 'read_file') {
|
|
371
|
+
if (typeof request.path !== 'string' || !request.path.trim()) {
|
|
372
|
+
return 'ERRO: read_file exige path string.';
|
|
373
|
+
}
|
|
374
|
+
return readFileContext(rootDir, request.path);
|
|
375
|
+
}
|
|
376
|
+
if (request.tool === 'list_files') {
|
|
377
|
+
const pattern = typeof request.pattern === 'string' ? request.pattern : '';
|
|
378
|
+
return listFiles(rootDir, pattern).join('\n') || '(nenhum arquivo encontrado)';
|
|
379
|
+
}
|
|
380
|
+
if (request.tool === 'search') {
|
|
381
|
+
if (typeof request.query !== 'string' || !request.query) {
|
|
382
|
+
return 'ERRO: search exige query string.';
|
|
383
|
+
}
|
|
384
|
+
return searchFiles(rootDir, request.query).join('\n') || '(nenhuma ocorrencia encontrada)';
|
|
385
|
+
}
|
|
386
|
+
if (request.tool === 'git_status') {
|
|
387
|
+
return getGitStatusSummary(rootDir);
|
|
388
|
+
}
|
|
389
|
+
if (request.tool === 'git_diff') {
|
|
390
|
+
return getGitDiff(rootDir);
|
|
391
|
+
}
|
|
392
|
+
if (request.tool === 'project_overview') {
|
|
393
|
+
return getProjectOverview(rootDir);
|
|
394
|
+
}
|
|
395
|
+
if (request.tool === 'read_many_files') {
|
|
396
|
+
const paths = Array.isArray(request.paths)
|
|
397
|
+
? request.paths.filter((p) => typeof p === 'string' && !!p.trim())
|
|
398
|
+
: [];
|
|
399
|
+
if (paths.length === 0)
|
|
400
|
+
return 'ERRO: read_many_files exige paths: string[] nao vazio.';
|
|
401
|
+
return readManyFiles(rootDir, paths);
|
|
402
|
+
}
|
|
403
|
+
if (request.tool === 'search_regex') {
|
|
404
|
+
if (typeof request.pattern !== 'string' || !request.pattern) {
|
|
405
|
+
return 'ERRO: search_regex exige pattern string.';
|
|
406
|
+
}
|
|
407
|
+
const flags = typeof request.flags === 'string' ? request.flags : '';
|
|
408
|
+
return searchFilesRegex(rootDir, request.pattern, flags).join('\n') || '(nenhuma ocorrencia encontrada)';
|
|
409
|
+
}
|
|
410
|
+
if (request.tool === 'run_tests') {
|
|
411
|
+
return runProjectTests(rootDir);
|
|
412
|
+
}
|
|
413
|
+
if (request.tool === 'project_symbols') {
|
|
414
|
+
const targetPath = typeof request.path === 'string' && request.path.trim() ? request.path : undefined;
|
|
415
|
+
return projectSymbols(rootDir, targetPath);
|
|
416
|
+
}
|
|
417
|
+
if (request.tool === 'invalid')
|
|
418
|
+
return `ERRO: ${request.error ?? 'tool invalida'}`;
|
|
419
|
+
return `ERRO: tool desconhecida: ${request.tool}`;
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
return `ERRO: ${error instanceof Error ? error.message : String(error)}`;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
const ANSI_GREEN = '\x1B[32m';
|
|
426
|
+
const ANSI_RED = '\x1B[31m';
|
|
427
|
+
const ANSI_CYAN = '\x1B[36m';
|
|
428
|
+
const ANSI_DIM = '\x1B[2m';
|
|
429
|
+
const ANSI_RESET = '\x1B[0m';
|
|
430
|
+
function colorDiffLine(line) {
|
|
431
|
+
if (line.startsWith('+++') || line.startsWith('---'))
|
|
432
|
+
return `${ANSI_DIM}${line}${ANSI_RESET}`;
|
|
433
|
+
if (line.startsWith('+'))
|
|
434
|
+
return `${ANSI_GREEN}${line}${ANSI_RESET}`;
|
|
435
|
+
if (line.startsWith('-'))
|
|
436
|
+
return `${ANSI_RED}${line}${ANSI_RESET}`;
|
|
437
|
+
if (line.startsWith('@@'))
|
|
438
|
+
return `${ANSI_CYAN}${line}${ANSI_RESET}`;
|
|
439
|
+
if (line.startsWith('diff --git') || line.startsWith('index '))
|
|
440
|
+
return `${ANSI_DIM}${line}${ANSI_RESET}`;
|
|
441
|
+
return line;
|
|
442
|
+
}
|
|
443
|
+
/** Colore um unified diff linha a linha: `+` verde, `-` vermelho, `@@`/headers dim/cyan. */
|
|
444
|
+
export function renderColoredDiff(patch) {
|
|
445
|
+
return patch
|
|
446
|
+
.split('\n')
|
|
447
|
+
.map(colorDiffLine)
|
|
448
|
+
.join('\n');
|
|
449
|
+
}
|
|
450
|
+
export function applyUnifiedPatch(rootDir, patch) {
|
|
451
|
+
const check = spawnSync('git', ['apply', '--check', '-'], {
|
|
452
|
+
cwd: rootDir,
|
|
453
|
+
input: patch,
|
|
454
|
+
encoding: 'utf8',
|
|
455
|
+
});
|
|
456
|
+
if (check.status !== 0) {
|
|
457
|
+
throw new Error((check.stderr || check.stdout || 'git apply --check falhou').trim());
|
|
458
|
+
}
|
|
459
|
+
const apply = spawnSync('git', ['apply', '-'], {
|
|
460
|
+
cwd: rootDir,
|
|
461
|
+
input: patch,
|
|
462
|
+
encoding: 'utf8',
|
|
463
|
+
});
|
|
464
|
+
if (apply.status !== 0) {
|
|
465
|
+
throw new Error((apply.stderr || apply.stdout || 'git apply falhou').trim());
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
//# sourceMappingURL=code-agent-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-agent-files.js","sourceRoot":"","sources":["../../src/lib/code-agent-files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CodeMessage, CodeSettings } from './code-agent-types.js';
|
|
2
|
+
export declare const AI_GATEWAY_CHAT_PATH = "/api/cli/v1/ai/chat";
|
|
3
|
+
export interface GatewayChatResponse {
|
|
4
|
+
choices?: Array<{
|
|
5
|
+
message?: {
|
|
6
|
+
role?: CodeMessage['role'];
|
|
7
|
+
content?: string;
|
|
8
|
+
};
|
|
9
|
+
}>;
|
|
10
|
+
model?: string;
|
|
11
|
+
provider?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function callGateway(settings: CodeSettings, messages: CodeMessage[]): Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Chamada com streaming (Fase 5, NEETRU_CODE_ARCHITECTURE.md: "streaming de
|
|
16
|
+
* resposta se o AI Gateway suportar"). Mesmo padrão de `streamGateway` em
|
|
17
|
+
* `src/lib/ai/orchestrator.ts` (fetch direto + `readSseLines` compartilhado) —
|
|
18
|
+
* não passa por `apiRequest`/`apiStream` porque nenhum dos dois fala SSE, e
|
|
19
|
+
* não importa o orchestrator inteiro só por essa função (ele carrega
|
|
20
|
+
* @anthropic-ai/sdk + openai, que `neetru code` não precisa).
|
|
21
|
+
*
|
|
22
|
+
* Acumula os deltas e retorna o texto completo — o protocolo
|
|
23
|
+
* `NEETRU_TOOL`/`NEETRU_PATCH` só pode ser parseado sobre a resposta inteira,
|
|
24
|
+
* então `onDelta` serve só para feedback visual (ex: contador de chars
|
|
25
|
+
* recebidos), não para processar a resposta aos poucos.
|
|
26
|
+
*/
|
|
27
|
+
export declare function streamGatewayChat(settings: CodeSettings, messages: CodeMessage[], onDelta?: (delta: string, totalChars: number) => void): Promise<string>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chamada ao AI Gateway do Core pro `neetru code` — extraído de
|
|
3
|
+
* commands/code.ts (Fase 2, NEETRU_CODE_ARCHITECTURE.md: "separar núcleo de
|
|
4
|
+
* interface"). Sem lógica de UI/REPL — só monta e envia a requisição.
|
|
5
|
+
*/
|
|
6
|
+
import { apiRequest, maybeWarnUntrustedHost } from './api-client.js';
|
|
7
|
+
import { getActiveTokenSync } from './token-resolver.js';
|
|
8
|
+
import { config } from './config.js';
|
|
9
|
+
import { readSseLines } from './sse.js';
|
|
10
|
+
export const AI_GATEWAY_CHAT_PATH = '/api/cli/v1/ai/chat';
|
|
11
|
+
export async function callGateway(settings, messages) {
|
|
12
|
+
const response = await apiRequest(AI_GATEWAY_CHAT_PATH, {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
body: {
|
|
15
|
+
model: settings.model,
|
|
16
|
+
messages,
|
|
17
|
+
stream: false,
|
|
18
|
+
maxTokens: settings.maxTokens,
|
|
19
|
+
temperature: settings.temperature,
|
|
20
|
+
},
|
|
21
|
+
timeoutMs: settings.timeoutMs,
|
|
22
|
+
});
|
|
23
|
+
const content = response.choices?.[0]?.message?.content;
|
|
24
|
+
if (typeof content !== 'string') {
|
|
25
|
+
throw new Error('AI Gateway retornou resposta sem choices[0].message.content.');
|
|
26
|
+
}
|
|
27
|
+
return content;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Chamada com streaming (Fase 5, NEETRU_CODE_ARCHITECTURE.md: "streaming de
|
|
31
|
+
* resposta se o AI Gateway suportar"). Mesmo padrão de `streamGateway` em
|
|
32
|
+
* `src/lib/ai/orchestrator.ts` (fetch direto + `readSseLines` compartilhado) —
|
|
33
|
+
* não passa por `apiRequest`/`apiStream` porque nenhum dos dois fala SSE, e
|
|
34
|
+
* não importa o orchestrator inteiro só por essa função (ele carrega
|
|
35
|
+
* @anthropic-ai/sdk + openai, que `neetru code` não precisa).
|
|
36
|
+
*
|
|
37
|
+
* Acumula os deltas e retorna o texto completo — o protocolo
|
|
38
|
+
* `NEETRU_TOOL`/`NEETRU_PATCH` só pode ser parseado sobre a resposta inteira,
|
|
39
|
+
* então `onDelta` serve só para feedback visual (ex: contador de chars
|
|
40
|
+
* recebidos), não para processar a resposta aos poucos.
|
|
41
|
+
*/
|
|
42
|
+
export async function streamGatewayChat(settings, messages, onDelta) {
|
|
43
|
+
const token = getActiveTokenSync();
|
|
44
|
+
if (!token) {
|
|
45
|
+
throw new Error('Sessao Neetru ausente ou expirada. Rode `neetru login`.');
|
|
46
|
+
}
|
|
47
|
+
const baseUrl = (config.get('neetruApiUrl') ?? 'https://api.neetru.com').replace(/\/+$/, '');
|
|
48
|
+
maybeWarnUntrustedHost(baseUrl);
|
|
49
|
+
const url = `${baseUrl}${AI_GATEWAY_CHAT_PATH}`;
|
|
50
|
+
const ctrl = new AbortController();
|
|
51
|
+
const timer = setTimeout(() => ctrl.abort(new Error(`neetru code stream timeout (${settings.timeoutMs}ms)`)), settings.timeoutMs);
|
|
52
|
+
try {
|
|
53
|
+
let resp;
|
|
54
|
+
try {
|
|
55
|
+
resp = await fetch(url, {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
headers: {
|
|
58
|
+
'content-type': 'application/json',
|
|
59
|
+
accept: 'text/event-stream',
|
|
60
|
+
authorization: `Bearer ${token}`,
|
|
61
|
+
},
|
|
62
|
+
body: JSON.stringify({
|
|
63
|
+
model: settings.model,
|
|
64
|
+
messages,
|
|
65
|
+
stream: true,
|
|
66
|
+
maxTokens: settings.maxTokens,
|
|
67
|
+
temperature: settings.temperature,
|
|
68
|
+
}),
|
|
69
|
+
signal: ctrl.signal,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (ctrl.signal.aborted)
|
|
74
|
+
throw error;
|
|
75
|
+
throw new Error(`Falha ao contactar o AI Gateway (${url}): ${error?.message ?? String(error)}`);
|
|
76
|
+
}
|
|
77
|
+
if (!resp.ok) {
|
|
78
|
+
const bodyText = await resp.text().catch(() => '');
|
|
79
|
+
let detail = bodyText;
|
|
80
|
+
try {
|
|
81
|
+
const parsed = JSON.parse(bodyText);
|
|
82
|
+
if (parsed?.error?.message)
|
|
83
|
+
detail = parsed.error.message;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// corpo nao-JSON — usa o texto cru (truncado abaixo).
|
|
87
|
+
}
|
|
88
|
+
throw new Error(`AI Gateway retornou ${resp.status}: ${detail.slice(0, 300) || 'erro sem detalhe'}`);
|
|
89
|
+
}
|
|
90
|
+
if (!resp.body)
|
|
91
|
+
throw new Error('AI Gateway retornou resposta sem body.');
|
|
92
|
+
let content = '';
|
|
93
|
+
await readSseLines(resp.body, (payload) => {
|
|
94
|
+
if (payload === '[DONE]')
|
|
95
|
+
return;
|
|
96
|
+
let obj;
|
|
97
|
+
try {
|
|
98
|
+
obj = JSON.parse(payload);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return; // linha nao-JSON (keep-alive) — ignora.
|
|
102
|
+
}
|
|
103
|
+
const delta = obj?.choices?.[0]?.delta?.content;
|
|
104
|
+
if (typeof delta === 'string' && delta) {
|
|
105
|
+
content += delta;
|
|
106
|
+
onDelta?.(delta, content.length);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
return content;
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
clearTimeout(timer);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=code-agent-gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-agent-gateway.js","sourceRoot":"","sources":["../../src/lib/code-agent-gateway.ts"],"names":[],"mappings":"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"}
|