@neetru/cli 2.20.3 → 2.22.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/commands/code.js +381 -27
  3. package/dist/commands/code.js.map +1 -1
  4. package/dist/index.js +2 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/code-agent-files.d.ts +14 -4
  7. package/dist/lib/code-agent-files.js +88 -9
  8. package/dist/lib/code-agent-files.js.map +1 -1
  9. package/dist/lib/code-agent-gateway.d.ts +2 -2
  10. package/dist/lib/code-agent-gateway.js +9 -4
  11. package/dist/lib/code-agent-gateway.js.map +1 -1
  12. package/dist/lib/code-agent-git-tools.d.ts +12 -16
  13. package/dist/lib/code-agent-git-tools.js +35 -26
  14. package/dist/lib/code-agent-git-tools.js.map +1 -1
  15. package/dist/lib/code-agent-protocol.d.ts +9 -0
  16. package/dist/lib/code-agent-protocol.js.map +1 -1
  17. package/dist/lib/code-agent-session.js +8 -1
  18. package/dist/lib/code-agent-session.js.map +1 -1
  19. package/dist/lib/code-agent-skills.d.ts +38 -0
  20. package/dist/lib/code-agent-skills.js +347 -0
  21. package/dist/lib/code-agent-skills.js.map +1 -0
  22. package/dist/lib/code-agent-tools.d.ts +7 -1
  23. package/dist/lib/code-agent-tools.js +72 -15
  24. package/dist/lib/code-agent-tools.js.map +1 -1
  25. package/dist/lib/code-agent-tui.d.ts +16 -0
  26. package/dist/lib/code-agent-tui.js +75 -5
  27. package/dist/lib/code-agent-tui.js.map +1 -1
  28. package/dist/lib/code-agent-types.d.ts +5 -0
  29. package/dist/lib/code-agent-ui.d.ts +16 -0
  30. package/dist/lib/code-agent-ui.js +76 -27
  31. package/dist/lib/code-agent-ui.js.map +1 -1
  32. package/dist/lib/code-agent-web-tools.d.ts +4 -0
  33. package/dist/lib/code-agent-web-tools.js +257 -0
  34. package/dist/lib/code-agent-web-tools.js.map +1 -0
  35. package/dist/lib/code-agent-write-tools.d.ts +5 -0
  36. package/dist/lib/code-agent-write-tools.js +141 -0
  37. package/dist/lib/code-agent-write-tools.js.map +1 -0
  38. package/package.json +1 -1
@@ -0,0 +1,257 @@
1
+ import { URL } from 'node:url';
2
+ const WEB_TIMEOUT_MS = 15_000;
3
+ const MAX_HTTP_BYTES = 900_000;
4
+ const MAX_TOOL_OUTPUT_CHARS = 28_000;
5
+ const DEFAULT_RESULTS = 5;
6
+ const MAX_RESULTS = 10;
7
+ function clipWebOutput(label, content) {
8
+ if (content.length <= MAX_TOOL_OUTPUT_CHARS)
9
+ return content;
10
+ return `${content.slice(0, MAX_TOOL_OUTPUT_CHARS)}\n\n[TRUNCADO: ${label} maior que ${MAX_TOOL_OUTPUT_CHARS} chars]`;
11
+ }
12
+ function parseLimit(value) {
13
+ const raw = typeof value === 'number' ? value : typeof value === 'string' ? Number.parseInt(value, 10) : NaN;
14
+ if (!Number.isFinite(raw))
15
+ return DEFAULT_RESULTS;
16
+ return Math.max(1, Math.min(MAX_RESULTS, Math.trunc(raw)));
17
+ }
18
+ function cleanText(value) {
19
+ return decodeHtml(value)
20
+ .replace(/<script[\s\S]*?<\/script>/gi, ' ')
21
+ .replace(/<style[\s\S]*?<\/style>/gi, ' ')
22
+ .replace(/<noscript[\s\S]*?<\/noscript>/gi, ' ')
23
+ .replace(/<svg[\s\S]*?<\/svg>/gi, ' ')
24
+ .replace(/<[^>]+>/g, ' ')
25
+ .replace(/\s+/g, ' ')
26
+ .trim();
27
+ }
28
+ function decodeHtml(value) {
29
+ return value
30
+ .replace(/&quot;/g, '"')
31
+ .replace(/&#x27;/g, "'")
32
+ .replace(/&#39;/g, "'")
33
+ .replace(/&amp;/g, '&')
34
+ .replace(/&lt;/g, '<')
35
+ .replace(/&gt;/g, '>')
36
+ .replace(/&nbsp;/g, ' ');
37
+ }
38
+ function assertSafePublicUrl(rawUrl) {
39
+ let parsed;
40
+ try {
41
+ parsed = new URL(rawUrl);
42
+ }
43
+ catch {
44
+ throw new Error(`URL invalida: ${rawUrl}`);
45
+ }
46
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
47
+ throw new Error('web_fetch aceita apenas http/https.');
48
+ }
49
+ const host = parsed.hostname.toLowerCase();
50
+ if (host === 'localhost' ||
51
+ host.endsWith('.localhost') ||
52
+ host === 'metadata.google.internal' ||
53
+ host === '0.0.0.0' ||
54
+ host === '::1' ||
55
+ host === '[::1]' ||
56
+ /^127\./.test(host) ||
57
+ /^10\./.test(host) ||
58
+ /^192\.168\./.test(host) ||
59
+ /^169\.254\./.test(host) ||
60
+ /^172\.(1[6-9]|2\d|3[0-1])\./.test(host)) {
61
+ throw new Error(`Host bloqueado para evitar SSRF/local network: ${host}`);
62
+ }
63
+ return parsed;
64
+ }
65
+ async function fetchText(rawUrl, headers = {}) {
66
+ const url = assertSafePublicUrl(rawUrl);
67
+ const controller = new AbortController();
68
+ const timer = setTimeout(() => controller.abort(), WEB_TIMEOUT_MS);
69
+ try {
70
+ const response = await fetch(url, {
71
+ headers: {
72
+ 'accept': 'text/html,application/xhtml+xml,application/json,text/plain;q=0.9,*/*;q=0.3',
73
+ 'user-agent': 'neetru-code/1.0 (+https://core.neetru.com)',
74
+ ...headers,
75
+ },
76
+ redirect: 'follow',
77
+ signal: controller.signal,
78
+ });
79
+ const contentLength = Number.parseInt(response.headers.get('content-length') ?? '', 10);
80
+ if (Number.isFinite(contentLength) && contentLength > MAX_HTTP_BYTES) {
81
+ throw new Error(`Resposta maior que ${MAX_HTTP_BYTES} bytes (${contentLength}).`);
82
+ }
83
+ const text = await response.text();
84
+ if (text.length > MAX_HTTP_BYTES) {
85
+ throw new Error(`Resposta maior que ${MAX_HTTP_BYTES} chars.`);
86
+ }
87
+ return {
88
+ url: response.url || url.toString(),
89
+ status: response.status,
90
+ contentType: response.headers.get('content-type') ?? '',
91
+ text,
92
+ };
93
+ }
94
+ finally {
95
+ clearTimeout(timer);
96
+ }
97
+ }
98
+ function duckDuckGoUrl(rawHref) {
99
+ const href = decodeHtml(rawHref);
100
+ const full = href.startsWith('//') ? `https:${href}` : href;
101
+ try {
102
+ const url = new URL(full, 'https://duckduckgo.com');
103
+ const uddg = url.searchParams.get('uddg');
104
+ return uddg ? decodeURIComponent(uddg) : url.toString();
105
+ }
106
+ catch {
107
+ return href;
108
+ }
109
+ }
110
+ function parseDuckDuckGoHtml(html, limit) {
111
+ const results = [];
112
+ const seen = new Set();
113
+ const anchorRe = /<a[^>]+class=["'][^"']*result__a[^"']*["'][^>]+href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi;
114
+ let match;
115
+ while ((match = anchorRe.exec(html)) && results.length < limit) {
116
+ const url = duckDuckGoUrl(match[1]);
117
+ if (!/^https?:\/\//i.test(url) || seen.has(url))
118
+ continue;
119
+ seen.add(url);
120
+ const title = cleanText(match[2]);
121
+ const after = html.slice(anchorRe.lastIndex, anchorRe.lastIndex + 1800);
122
+ const snippetMatch = after.match(/class=["'][^"']*result__snippet[^"']*["'][^>]*>([\s\S]*?)<\/(?:a|div)>/i);
123
+ const snippet = snippetMatch ? cleanText(snippetMatch[1]) : undefined;
124
+ results.push({ title: title || url, url, snippet });
125
+ }
126
+ return results;
127
+ }
128
+ function formatSearchResults(label, query, results) {
129
+ if (results.length === 0)
130
+ return `${label}: nenhuma ocorrencia encontrada para "${query}".`;
131
+ const rows = [`${label}: "${query}"`, ''];
132
+ for (const [index, result] of results.entries()) {
133
+ rows.push(`${index + 1}. ${result.title}`);
134
+ rows.push(` URL: ${result.url}`);
135
+ if (result.snippet)
136
+ rows.push(` Trecho: ${result.snippet}`);
137
+ }
138
+ return clipWebOutput(label, rows.join('\n'));
139
+ }
140
+ export async function webSearchTool(query, limitValue) {
141
+ const trimmed = query.trim();
142
+ if (!trimmed)
143
+ return 'ERRO: web_search exige query string nao vazia.';
144
+ const limit = parseLimit(limitValue);
145
+ const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(trimmed)}`;
146
+ const response = await fetchText(url);
147
+ if (response.status < 200 || response.status >= 300) {
148
+ return `ERRO: web_search HTTP ${response.status} em DuckDuckGo.`;
149
+ }
150
+ return formatSearchResults('web_search', trimmed, parseDuckDuckGoHtml(response.text, limit));
151
+ }
152
+ function htmlToReadableText(html) {
153
+ const title = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i)?.[1];
154
+ const body = cleanText(html);
155
+ return [title ? `Titulo: ${cleanText(title)}` : '', body].filter(Boolean).join('\n\n');
156
+ }
157
+ export async function webFetchTool(rawUrl) {
158
+ const response = await fetchText(rawUrl);
159
+ if (response.status < 200 || response.status >= 300) {
160
+ return `ERRO: web_fetch HTTP ${response.status} em ${response.url}.`;
161
+ }
162
+ const isHtml = /html/i.test(response.contentType) || /<\/?[a-z][\s\S]*>/i.test(response.text);
163
+ const readable = isHtml ? htmlToReadableText(response.text) : response.text;
164
+ return clipWebOutput('web_fetch', [
165
+ `URL: ${response.url}`,
166
+ `status: ${response.status}`,
167
+ response.contentType ? `content-type: ${response.contentType}` : '',
168
+ '',
169
+ readable.trim() || '(sem corpo legivel)',
170
+ ].filter(Boolean).join('\n'));
171
+ }
172
+ async function fetchGithubJson(url) {
173
+ const response = await fetchText(url, {
174
+ accept: 'application/vnd.github+json',
175
+ 'x-github-api-version': '2022-11-28',
176
+ });
177
+ if (response.status < 200 || response.status >= 300) {
178
+ return {
179
+ error: `GitHub HTTP ${response.status}`,
180
+ body: response.text.slice(0, 500),
181
+ };
182
+ }
183
+ return JSON.parse(response.text);
184
+ }
185
+ function asRecord(value) {
186
+ return value && typeof value === 'object' ? value : {};
187
+ }
188
+ export async function githubSearchTool(query, limitValue) {
189
+ const trimmed = query.trim();
190
+ if (!trimmed)
191
+ return 'ERRO: github_search exige query string nao vazia.';
192
+ const limit = parseLimit(limitValue);
193
+ const url = `https://api.github.com/search/repositories?q=${encodeURIComponent(trimmed)}&sort=stars&order=desc&per_page=${limit}`;
194
+ const payload = asRecord(await fetchGithubJson(url));
195
+ if (payload.error)
196
+ return `ERRO: ${String(payload.error)}\n${String(payload.body ?? '')}`.trim();
197
+ const items = Array.isArray(payload.items) ? payload.items.map(asRecord) : [];
198
+ const rows = [`github_search: "${trimmed}"`, ''];
199
+ for (const [index, item] of items.slice(0, limit).entries()) {
200
+ const fullName = typeof item.full_name === 'string' ? item.full_name : '(repo sem nome)';
201
+ const htmlUrl = typeof item.html_url === 'string' ? item.html_url : '';
202
+ const description = typeof item.description === 'string' && item.description ? item.description : '(sem descricao)';
203
+ const stars = typeof item.stargazers_count === 'number' ? item.stargazers_count : 0;
204
+ const language = typeof item.language === 'string' ? item.language : 'n/a';
205
+ const license = asRecord(item.license).spdx_id;
206
+ const topics = Array.isArray(item.topics) ? item.topics.filter((v) => typeof v === 'string') : [];
207
+ rows.push(`${index + 1}. ${fullName} (${stars} stars, ${language}, licenca ${typeof license === 'string' ? license : 'n/a'})`);
208
+ if (htmlUrl)
209
+ rows.push(` URL: ${htmlUrl}`);
210
+ rows.push(` Descricao: ${description}`);
211
+ if (topics.length)
212
+ rows.push(` Topicos: ${topics.slice(0, 10).join(', ')}`);
213
+ }
214
+ if (items.length === 0)
215
+ rows.push('(nenhum repositorio encontrado)');
216
+ return clipWebOutput('github_search', rows.join('\n'));
217
+ }
218
+ function normalizeRepoName(value) {
219
+ const repo = value.trim().replace(/^https:\/\/github\.com\//i, '').replace(/\/+$/, '');
220
+ if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repo)) {
221
+ throw new Error('github_repo exige repo no formato owner/name.');
222
+ }
223
+ return repo;
224
+ }
225
+ export async function githubRepoTool(rawRepo) {
226
+ const repo = normalizeRepoName(rawRepo);
227
+ const metadata = asRecord(await fetchGithubJson(`https://api.github.com/repos/${repo}`));
228
+ if (metadata.error)
229
+ return `ERRO: ${String(metadata.error)}\n${String(metadata.body ?? '')}`.trim();
230
+ const readmeResponse = await fetchText(`https://api.github.com/repos/${repo}/readme`, {
231
+ accept: 'application/vnd.github.raw',
232
+ 'x-github-api-version': '2022-11-28',
233
+ }).catch((error) => ({
234
+ url: `https://api.github.com/repos/${repo}/readme`,
235
+ status: 0,
236
+ contentType: '',
237
+ text: `README indisponivel: ${error instanceof Error ? error.message : String(error)}`,
238
+ }));
239
+ const license = asRecord(metadata.license).spdx_id;
240
+ const topics = Array.isArray(metadata.topics) ? metadata.topics.filter((v) => typeof v === 'string') : [];
241
+ const rows = [
242
+ `repo: ${typeof metadata.full_name === 'string' ? metadata.full_name : repo}`,
243
+ `URL: ${typeof metadata.html_url === 'string' ? metadata.html_url : `https://github.com/${repo}`}`,
244
+ `descricao: ${typeof metadata.description === 'string' && metadata.description ? metadata.description : '(sem descricao)'}`,
245
+ `stars: ${typeof metadata.stargazers_count === 'number' ? metadata.stargazers_count : 0}`,
246
+ `linguagem: ${typeof metadata.language === 'string' ? metadata.language : 'n/a'}`,
247
+ `licenca: ${typeof license === 'string' ? license : 'n/a'}`,
248
+ topics.length ? `topicos: ${topics.slice(0, 16).join(', ')}` : '',
249
+ '',
250
+ 'README:',
251
+ readmeResponse.status >= 200 && readmeResponse.status < 300
252
+ ? readmeResponse.text.trim()
253
+ : `README indisponivel (HTTP ${readmeResponse.status}).`,
254
+ ].filter(Boolean);
255
+ return clipWebOutput('github_repo', rows.join('\n'));
256
+ }
257
+ //# sourceMappingURL=code-agent-web-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-agent-web-tools.js","sourceRoot":"","sources":["../../src/lib/code-agent-web-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { CodeToolRequest } from './code-agent-protocol.js';
2
+ import type { CodeToolContext } from './code-agent-types.js';
3
+ export declare function writeFileTool(rootDir: string, request: CodeToolRequest, ctx: CodeToolContext): Promise<string>;
4
+ export declare function appendFileTool(rootDir: string, request: CodeToolRequest, ctx: CodeToolContext): Promise<string>;
5
+ export declare function replaceInFileTool(rootDir: string, request: CodeToolRequest, ctx: CodeToolContext): Promise<string>;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Ferramentas deterministicas de escrita do `neetru code` — write_file,
3
+ * append_file, replace_in_file (2026-07-13). Existem pra tirar do
4
+ * NEETRU_PATCH (unified diff cru gerado pelo modelo, so validado por `git
5
+ * apply --check`, sem reparo de hunk/CRLF/newline) o papel de UNICO caminho
6
+ * de escrita — achado em uso real (transcript colado pelo usuario: o modelo
7
+ * ficava preso reescrevendo o mesmo diff quebrado, esgotando o orcamento de
8
+ * turnos inteiro sem nunca conseguir mudar o arquivo) + diagnostico
9
+ * confirmado por revisao de codigo (Codex). NEETRU_PATCH continua existindo
10
+ * pra mudancas que precisam de diff multi-arquivo/multi-hunk num so turno;
11
+ * estas 3 ferramentas viram o caminho PRINCIPAL pra criar/editar UM arquivo.
12
+ *
13
+ * Nivel de cautela: local e reversivel (git mostra a mudanca depois, `git
14
+ * checkout`/`git restore` desfaz) — mesmo tier de git_commit/git_branch:
15
+ * `--yes`/`/yes` dispensa a pergunta, senao confirma mostrando o preview.
16
+ * Path sempre resolvido via `resolveInside` (contencao + symlink real path,
17
+ * mesma guarda de read_file); escrita em arquivo de segredo (.env/chave)
18
+ * bloqueada, espelhando o bloqueio de leitura.
19
+ */
20
+ import fs from 'node:fs';
21
+ import path from 'node:path';
22
+ import { clipToolOutput, isSecretPath, resolveInside } from './code-agent-files.js';
23
+ const MAX_WRITE_CONTENT_CHARS = 200_000;
24
+ const PREVIEW_MAX_LINES = 12;
25
+ const PREVIEW_MAX_CHARS = 600;
26
+ function asString(value) {
27
+ return typeof value === 'string' ? value : undefined;
28
+ }
29
+ function relativeOf(rootDir, fullPath) {
30
+ return path.relative(path.resolve(rootDir), fullPath).replace(/\\/g, '/');
31
+ }
32
+ /** Resolve+valida o path (contencao/symlink/segredo) — lanca em qualquer problema; `runCodeTool` converte pra `ERRO: ...`. */
33
+ function guardPath(rootDir, inputPath) {
34
+ if (typeof inputPath !== 'string' || !inputPath.trim()) {
35
+ throw new Error('exige path string nao vazio.');
36
+ }
37
+ const full = resolveInside(rootDir, inputPath.trim());
38
+ const relative = relativeOf(rootDir, full);
39
+ if (isSecretPath(relative)) {
40
+ throw new Error(`escrita bloqueada: "${relative}" parece arquivo de segredo (.env/chave/credencial).`);
41
+ }
42
+ return { full, relative };
43
+ }
44
+ // Mesma lista de code-agent-git-tools.ts: ESC/CR no conteudo (que pode vir
45
+ // "repetido" de um arquivo lido — prompt injection) nao pode reescrever
46
+ // visualmente o preview de confirmacao.
47
+ function sanitizeForPreview(value) {
48
+ return value.replace(/[\x00-\x08\x0B-\x1F\x7F-\x9F]/g, '');
49
+ }
50
+ function previewSnippet(content) {
51
+ const clipped = content.length > PREVIEW_MAX_CHARS ? `${content.slice(0, PREVIEW_MAX_CHARS)}…` : content;
52
+ const lines = sanitizeForPreview(clipped).split(/\r?\n/);
53
+ const shown = lines.slice(0, PREVIEW_MAX_LINES).map((l) => ` ${l}`);
54
+ if (lines.length > PREVIEW_MAX_LINES)
55
+ shown.push(` ... mais ${lines.length - PREVIEW_MAX_LINES} linha(s)`);
56
+ return shown.join('\n');
57
+ }
58
+ function assertContentSize(tool, content) {
59
+ if (content.length > MAX_WRITE_CONTENT_CHARS) {
60
+ throw new Error(`${tool}: content maior que ${MAX_WRITE_CONTENT_CHARS} chars — quebre em partes menores.`);
61
+ }
62
+ }
63
+ export async function writeFileTool(rootDir, request, ctx) {
64
+ const guard = guardPath(rootDir, request.path);
65
+ const content = asString(request.content);
66
+ if (content === undefined)
67
+ return 'ERRO: write_file exige content string.';
68
+ assertContentSize('write_file', content);
69
+ const exists = fs.existsSync(guard.full);
70
+ const before = exists ? fs.statSync(guard.full).size : null;
71
+ const action = exists
72
+ ? `sobrescrever arquivo existente (${before} -> ${content.length} chars)`
73
+ : 'criar arquivo novo';
74
+ const preview = [
75
+ `write_file ${guard.relative}`,
76
+ ` acao: ${action}`,
77
+ ' conteudo:',
78
+ previewSnippet(content),
79
+ ].join('\n');
80
+ const approved = ctx.settings.yes || (await ctx.confirm(`${preview}\n\nEscrever este arquivo? [y/N] `));
81
+ if (!approved)
82
+ return 'ERRO: escrita cancelada pelo usuario.';
83
+ fs.mkdirSync(path.dirname(guard.full), { recursive: true });
84
+ fs.writeFileSync(guard.full, content, 'utf8');
85
+ return clipToolOutput('write_file', `OK: ${exists ? 'sobrescrito' : 'criado'} ${guard.relative} (${content.length} chars).`);
86
+ }
87
+ export async function appendFileTool(rootDir, request, ctx) {
88
+ const guard = guardPath(rootDir, request.path);
89
+ const content = asString(request.content);
90
+ if (content === undefined)
91
+ return 'ERRO: append_file exige content string.';
92
+ assertContentSize('append_file', content);
93
+ const preview = [
94
+ `append_file ${guard.relative}`,
95
+ ' conteudo a adicionar no final:',
96
+ previewSnippet(content),
97
+ ].join('\n');
98
+ const approved = ctx.settings.yes || (await ctx.confirm(`${preview}\n\nAdicionar ao final do arquivo? [y/N] `));
99
+ if (!approved)
100
+ return 'ERRO: escrita cancelada pelo usuario.';
101
+ fs.mkdirSync(path.dirname(guard.full), { recursive: true });
102
+ fs.appendFileSync(guard.full, content, 'utf8');
103
+ return clipToolOutput('append_file', `OK: adicionado ao final de ${guard.relative} (+${content.length} chars).`);
104
+ }
105
+ export async function replaceInFileTool(rootDir, request, ctx) {
106
+ const guard = guardPath(rootDir, request.path);
107
+ const oldString = asString(request.old_string);
108
+ const newString = asString(request.new_string);
109
+ if (!oldString)
110
+ return 'ERRO: replace_in_file exige old_string string nao vazio.';
111
+ if (newString === undefined)
112
+ return 'ERRO: replace_in_file exige new_string string.';
113
+ if (!fs.existsSync(guard.full))
114
+ return `ERRO: replace_in_file arquivo nao existe: ${guard.relative}`;
115
+ const before = fs.readFileSync(guard.full, 'utf8');
116
+ const occurrences = before.split(oldString).length - 1;
117
+ if (occurrences === 0) {
118
+ return `ERRO: old_string nao encontrado em ${guard.relative}. Releia o arquivo antes de tentar de novo.`;
119
+ }
120
+ const replaceAll = request.replace_all === true;
121
+ if (occurrences > 1 && !replaceAll) {
122
+ return (`ERRO: old_string aparece ${occurrences}x em ${guard.relative} — inclua mais contexto pra ficar unico, ` +
123
+ 'ou use "replace_all":true de proposito.');
124
+ }
125
+ const after = replaceAll ? before.split(oldString).join(newString) : before.replace(oldString, newString);
126
+ assertContentSize('replace_in_file', after);
127
+ const preview = [
128
+ `replace_in_file ${guard.relative}`,
129
+ ` ocorrencias: ${occurrences}${replaceAll ? ' (todas)' : ''}`,
130
+ ' de:',
131
+ previewSnippet(oldString),
132
+ ' para:',
133
+ previewSnippet(newString),
134
+ ].join('\n');
135
+ const approved = ctx.settings.yes || (await ctx.confirm(`${preview}\n\nAplicar esta substituicao? [y/N] `));
136
+ if (!approved)
137
+ return 'ERRO: substituicao cancelada pelo usuario.';
138
+ fs.writeFileSync(guard.full, after, 'utf8');
139
+ return clipToolOutput('replace_in_file', `OK: ${occurrences} ocorrencia(s) substituida(s) em ${guard.relative}.`);
140
+ }
141
+ //# sourceMappingURL=code-agent-write-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-agent-write-tools.js","sourceRoot":"","sources":["../../src/lib/code-agent-write-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpF,MAAM,uBAAuB,GAAG,OAAO,CAAC;AACxC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,SAAS,UAAU,CAAC,OAAe,EAAE,QAAgB;IACnD,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAC5E,CAAC;AAED,8HAA8H;AAC9H,SAAS,SAAS,CAAC,OAAe,EAAE,SAAkB;IACpD,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC3C,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,sDAAsD,CAAC,CAAC;IACzG,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED,2EAA2E;AAC3E,wEAAwE;AACxE,wCAAwC;AACxC,SAAS,kBAAkB,CAAC,KAAa;IACvC,OAAO,KAAK,CAAC,OAAO,CAAC,gCAAgC,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,cAAc,CAAC,OAAe;IACrC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;IACzG,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACzD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACvE,IAAI,KAAK,CAAC,MAAM,GAAG,iBAAiB;QAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,KAAK,CAAC,MAAM,GAAG,iBAAiB,WAAW,CAAC,CAAC;IAC9G,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY,EAAE,OAAe;IACtD,IAAI,OAAO,CAAC,MAAM,GAAG,uBAAuB,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,uBAAuB,uBAAuB,oCAAoC,CAAC,CAAC;IAC7G,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAe,EACf,OAAwB,EACxB,GAAoB;IAEpB,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,wCAAwC,CAAC;IAC3E,iBAAiB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5D,MAAM,MAAM,GAAG,MAAM;QACnB,CAAC,CAAC,mCAAmC,MAAM,OAAO,OAAO,CAAC,MAAM,SAAS;QACzE,CAAC,CAAC,oBAAoB,CAAC;IACzB,MAAM,OAAO,GAAG;QACd,cAAc,KAAK,CAAC,QAAQ,EAAE;QAC9B,WAAW,MAAM,EAAE;QACnB,aAAa;QACb,cAAc,CAAC,OAAO,CAAC;KACxB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,mCAAmC,CAAC,CAAC,CAAC;IACxG,IAAI,CAAC,QAAQ;QAAE,OAAO,uCAAuC,CAAC;IAE9D,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC9C,OAAO,cAAc,CACnB,YAAY,EACZ,OAAO,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC,MAAM,UAAU,CACxF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAe,EACf,OAAwB,EACxB,GAAoB;IAEpB,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,yCAAyC,CAAC;IAC5E,iBAAiB,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAE1C,MAAM,OAAO,GAAG;QACd,eAAe,KAAK,CAAC,QAAQ,EAAE;QAC/B,kCAAkC;QAClC,cAAc,CAAC,OAAO,CAAC;KACxB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,2CAA2C,CAAC,CAAC,CAAC;IAChH,IAAI,CAAC,QAAQ;QAAE,OAAO,uCAAuC,CAAC;IAE9D,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/C,OAAO,cAAc,CAAC,aAAa,EAAE,8BAA8B,KAAK,CAAC,QAAQ,MAAM,OAAO,CAAC,MAAM,UAAU,CAAC,CAAC;AACnH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAe,EACf,OAAwB,EACxB,GAAoB;IAEpB,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,IAAI,CAAC,SAAS;QAAE,OAAO,0DAA0D,CAAC;IAClF,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,gDAAgD,CAAC;IACrF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,6CAA6C,KAAK,CAAC,QAAQ,EAAE,CAAC;IAErG,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACvD,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,sCAAsC,KAAK,CAAC,QAAQ,6CAA6C,CAAC;IAC3G,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,KAAK,IAAI,CAAC;IAChD,IAAI,WAAW,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QACnC,OAAO,CACL,4BAA4B,WAAW,QAAQ,KAAK,CAAC,QAAQ,2CAA2C;YACxG,yCAAyC,CAC1C,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC1G,iBAAiB,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG;QACd,mBAAmB,KAAK,CAAC,QAAQ,EAAE;QACnC,kBAAkB,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9D,OAAO;QACP,cAAc,CAAC,SAAS,CAAC;QACzB,SAAS;QACT,cAAc,CAAC,SAAS,CAAC;KAC1B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,uCAAuC,CAAC,CAAC,CAAC;IAC5G,IAAI,CAAC,QAAQ;QAAE,OAAO,4CAA4C,CAAC;IAEnE,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO,cAAc,CAAC,iBAAiB,EAAE,OAAO,WAAW,oCAAoC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;AACpH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neetru/cli",
3
- "version": "2.20.3",
3
+ "version": "2.22.0",
4
4
  "type": "module",
5
5
  "description": "Neetru Developer Kit — scaffold, AI assistant, publish, build e deploy de produtos SaaS Neetru via Core (VM-based agents)",
6
6
  "keywords": [