@neetru/cli 2.14.0 → 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.
@@ -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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"}
@@ -1,10 +1,17 @@
1
1
  export interface CodeToolRequest {
2
2
  tool: string;
3
3
  path?: unknown;
4
+ paths?: unknown;
4
5
  pattern?: unknown;
6
+ flags?: unknown;
5
7
  query?: unknown;
6
8
  error?: string;
7
9
  }
10
+ export interface PatchFileSummary {
11
+ file: string;
12
+ added: number;
13
+ removed: number;
14
+ }
8
15
  export declare function parseToolRequest(text: string): CodeToolRequest | null;
9
16
  /**
10
17
  * So aceita o bloco explicito `NEETRU_PATCH ... NEETRU_END` do protocolo —
@@ -14,3 +21,4 @@ export declare function parseToolRequest(text: string): CodeToolRequest | null;
14
21
  * review 2026-07-09).
15
22
  */
16
23
  export declare function extractPatch(text: string): string | null;
24
+ export declare function summarizePatch(patch: string): PatchFileSummary[];
@@ -31,4 +31,26 @@ export function extractPatch(text) {
31
31
  const marker = source.match(/NEETRU_PATCH\s*([\s\S]*?)\s*NEETRU_END/);
32
32
  return marker?.[1] ? `${marker[1].trim()}\n` : null;
33
33
  }
34
+ export function summarizePatch(patch) {
35
+ const summaries = new Map();
36
+ let current = null;
37
+ for (const line of patch.split(/\r?\n/)) {
38
+ const match = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
39
+ if (match) {
40
+ const file = match[2] || match[1];
41
+ current = summaries.get(file) ?? { file, added: 0, removed: 0 };
42
+ summaries.set(file, current);
43
+ continue;
44
+ }
45
+ if (!current)
46
+ continue;
47
+ if (line.startsWith('+++') || line.startsWith('---'))
48
+ continue;
49
+ if (line.startsWith('+'))
50
+ current.added += 1;
51
+ if (line.startsWith('-'))
52
+ current.removed += 1;
53
+ }
54
+ return Array.from(summaries.values());
55
+ }
34
56
  //# sourceMappingURL=code-agent-protocol.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"code-agent-protocol.js","sourceRoot":"","sources":["../../src/lib/code-agent-protocol.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACrD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACxC,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,SAAS;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1D,IAAI,CAAC,GAAG;YAAE,SAAS;QAEnB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;YAC1C,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAQ,MAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACpG,OAAO,MAAyB,CAAC;YACnC,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,2CAA2C,EAAE,CAAC;QACjF,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,iCAAiC,GAAG,EAAE,EAAE,CAAC;QAC5E,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACtE,OAAO,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD,CAAC"}
1
+ {"version":3,"file":"code-agent-protocol.js","sourceRoot":"","sources":["../../src/lib/code-agent-protocol.ts"],"names":[],"mappings":"AAgBA,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACrD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACxC,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,SAAS;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1D,IAAI,CAAC,GAAG;YAAE,SAAS;QAEnB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;YAC1C,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAQ,MAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACpG,OAAO,MAAyB,CAAC;YACnC,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,2CAA2C,EAAE,CAAC;QACjF,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,iCAAiC,GAAG,EAAE,EAAE,CAAC;QAC5E,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACtE,OAAO,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,MAAM,SAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;IACtD,IAAI,OAAO,GAA4B,IAAI,CAAC;IAE5C,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC1D,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;YAClC,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YAChE,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC7B,SAAS;QACX,CAAC;QAED,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,SAAS;QAC/D,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;QAC7C,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;IACjD,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Máquina de estados da sessão do `neetru code` (Fase 2,
3
+ * NEETRU_CODE_ARCHITECTURE.md: "Estados da sessão" — "hoje isso esta
4
+ * implicito por prints; o proximo passo e transformar em estrutura
5
+ * testavel"). Pura, sem I/O — commands/code.ts chama `transition()` nos
6
+ * pontos do loop de turno; testes verificam a sequência sem mockar o
7
+ * AI Gateway inteiro.
8
+ */
9
+ export type CodeAgentState = 'idle' | 'thinking' | 'tool_requested' | 'tool_running' | 'patch_ready' | 'awaiting_confirm' | 'applied' | 'failed' | 'aborted';
10
+ export declare class CodeAgentStateMachine {
11
+ private current;
12
+ private readonly log;
13
+ get state(): CodeAgentState;
14
+ /** Histórico de estados desde a criação (ou último `reset`). Só leitura. */
15
+ get history(): readonly CodeAgentState[];
16
+ transition(next: CodeAgentState): void;
17
+ reset(): void;
18
+ }
19
+ export type CodeSessionRole = 'system' | 'user' | 'assistant';
20
+ export interface CodeSessionMessage {
21
+ role: CodeSessionRole;
22
+ content: string;
23
+ }
24
+ export interface CodeSessionSnapshot {
25
+ cwd: string;
26
+ model: string;
27
+ }
28
+ export declare function compactCodeHistory<T extends CodeSessionMessage>(history: T[], keepRecent?: number): number;
29
+ export declare function formatCodeSessionMarkdown(settings: CodeSessionSnapshot, history: CodeSessionMessage[]): string;
30
+ export declare function saveCodeSession(settings: CodeSessionSnapshot, history: CodeSessionMessage[]): string;
31
+ /**
32
+ * Retomar sessao por id (Fase 4, NEETRU_CODE_ARCHITECTURE.md) — mesmo padrao
33
+ * de UX de qualquer REPL com persistencia (lista sessoes salvas, numera,
34
+ * usuario escolhe). Nada disso vem de codigo alheio: e o jeito obvio de
35
+ * resolver "listar + escolher" numa CLI de terminal.
36
+ */
37
+ export interface CodeSessionSummary {
38
+ /** Path relativo ao cwd (ex: `.neetru/code/sessions/2026-07-10T...-abc.md`). */
39
+ file: string;
40
+ timestamp: string;
41
+ messageCount: number;
42
+ /** Primeiras ~80 chars da primeira mensagem de usuario — ajuda a reconhecer a sessao na lista. */
43
+ preview: string;
44
+ }
45
+ /** Lista sessoes salvas, mais recente primeiro (nomes de arquivo ISO ordenam lexicograficamente). */
46
+ export declare function listCodeSessions(cwd: string): CodeSessionSummary[];
47
+ /** Carrega as mensagens de uma sessao salva (`file` relativo ao cwd, vindo de listCodeSessions). */
48
+ export declare function loadCodeSession(cwd: string, file: string): CodeSessionMessage[];
49
+ /**
50
+ * Log local de patch aplicado (Fase 4) — 1 linha por patch, append-only.
51
+ * Nao substitui git log/reflog; e so um resumo rapido "o que o agente mudou
52
+ * e quando", legivel sem abrir o git.
53
+ */
54
+ export declare function logAppliedPatch(cwd: string, summary: string): void;
@@ -0,0 +1,147 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { redactSecrets } from './code-agent-files.js';
4
+ const VALID_TRANSITIONS = {
5
+ idle: ['thinking'],
6
+ // thinking -> idle: turno terminou em texto final (sem tool nem patch).
7
+ thinking: ['tool_requested', 'patch_ready', 'idle', 'failed'],
8
+ tool_requested: ['tool_running'],
9
+ tool_running: ['thinking', 'failed'],
10
+ patch_ready: ['awaiting_confirm', 'applied', 'aborted'],
11
+ awaiting_confirm: ['applied', 'aborted'],
12
+ applied: ['idle'],
13
+ failed: ['idle'],
14
+ aborted: ['idle'],
15
+ };
16
+ export class CodeAgentStateMachine {
17
+ current = 'idle';
18
+ log = ['idle'];
19
+ get state() {
20
+ return this.current;
21
+ }
22
+ /** Histórico de estados desde a criação (ou último `reset`). Só leitura. */
23
+ get history() {
24
+ return this.log;
25
+ }
26
+ transition(next) {
27
+ const allowed = VALID_TRANSITIONS[this.current];
28
+ if (!allowed.includes(next)) {
29
+ throw new Error(`Transicao de estado invalida: ${this.current} -> ${next}`);
30
+ }
31
+ this.current = next;
32
+ this.log.push(next);
33
+ }
34
+ reset() {
35
+ this.current = 'idle';
36
+ this.log.length = 0;
37
+ this.log.push('idle');
38
+ }
39
+ }
40
+ export function compactCodeHistory(history, keepRecent = 8) {
41
+ if (history.length <= keepRecent + 1)
42
+ return 0;
43
+ const system = history.find((message) => message.role === 'system');
44
+ const recent = history.slice(-keepRecent);
45
+ const next = system ? [system, ...recent.filter((message) => message !== system)] : recent;
46
+ const removed = history.length - next.length;
47
+ history.splice(0, history.length, ...next);
48
+ return removed;
49
+ }
50
+ export function formatCodeSessionMarkdown(settings, history) {
51
+ const lines = [
52
+ '# Neetru Code Session',
53
+ '',
54
+ `- date: ${new Date().toISOString()}`,
55
+ `- cwd: ${settings.cwd}`,
56
+ `- model: ${settings.model}`,
57
+ `- messages: ${history.length}`,
58
+ '',
59
+ '## Conversa',
60
+ '',
61
+ ];
62
+ for (const message of history) {
63
+ lines.push(`### ${message.role}`);
64
+ lines.push('');
65
+ lines.push('```text');
66
+ lines.push(redactSecrets(message.content).slice(0, 40_000));
67
+ lines.push('```');
68
+ lines.push('');
69
+ }
70
+ return lines.join('\n');
71
+ }
72
+ export function saveCodeSession(settings, history) {
73
+ const dir = path.join(settings.cwd, '.neetru', 'code', 'sessions');
74
+ fs.mkdirSync(dir, { recursive: true });
75
+ const stamp = new Date().toISOString().replace(/[:.]/g, '-');
76
+ const file = path.join(dir, `${stamp}.md`);
77
+ fs.writeFileSync(file, formatCodeSessionMarkdown(settings, history), 'utf8');
78
+ return path.relative(settings.cwd, file).replace(/\\/g, '/');
79
+ }
80
+ function sessionsDir(cwd) {
81
+ return path.join(cwd, '.neetru', 'code', 'sessions');
82
+ }
83
+ function parseSessionMarkdown(content) {
84
+ const dateMatch = content.match(/^- date: (.+)$/m);
85
+ const countMatch = content.match(/^- messages: (\d+)$/m);
86
+ const messages = [];
87
+ const blockRe = /### (system|user|assistant)\n\n```text\n([\s\S]*?)\n```/g;
88
+ let match;
89
+ while ((match = blockRe.exec(content))) {
90
+ messages.push({ role: match[1], content: match[2] });
91
+ }
92
+ return {
93
+ date: dateMatch?.[1] ?? '',
94
+ messageCount: countMatch ? Number.parseInt(countMatch[1], 10) : messages.length,
95
+ messages,
96
+ };
97
+ }
98
+ /** Lista sessoes salvas, mais recente primeiro (nomes de arquivo ISO ordenam lexicograficamente). */
99
+ export function listCodeSessions(cwd) {
100
+ const dir = sessionsDir(cwd);
101
+ if (!fs.existsSync(dir))
102
+ return [];
103
+ const files = fs.readdirSync(dir).filter((f) => f.endsWith('.md')).sort().reverse();
104
+ return files.map((file) => {
105
+ const full = path.join(dir, file);
106
+ let content = '';
107
+ try {
108
+ content = fs.readFileSync(full, 'utf8');
109
+ }
110
+ catch {
111
+ content = '';
112
+ }
113
+ const parsed = parseSessionMarkdown(content);
114
+ const firstUser = parsed.messages.find((m) => m.role === 'user');
115
+ const preview = (firstUser?.content ?? '').replace(/\s+/g, ' ').trim().slice(0, 80);
116
+ return {
117
+ file: `.neetru/code/sessions/${file}`,
118
+ timestamp: parsed.date || file.replace(/\.md$/, ''),
119
+ messageCount: parsed.messageCount,
120
+ preview,
121
+ };
122
+ });
123
+ }
124
+ /** Carrega as mensagens de uma sessao salva (`file` relativo ao cwd, vindo de listCodeSessions). */
125
+ export function loadCodeSession(cwd, file) {
126
+ const full = path.resolve(cwd, file);
127
+ if (!full.startsWith(path.resolve(sessionsDir(cwd)))) {
128
+ throw new Error(`Sessao fora do diretorio esperado: ${file}`);
129
+ }
130
+ if (!fs.existsSync(full)) {
131
+ throw new Error(`Sessao nao encontrada: ${file}`);
132
+ }
133
+ const content = fs.readFileSync(full, 'utf8');
134
+ return parseSessionMarkdown(content).messages;
135
+ }
136
+ /**
137
+ * Log local de patch aplicado (Fase 4) — 1 linha por patch, append-only.
138
+ * Nao substitui git log/reflog; e so um resumo rapido "o que o agente mudou
139
+ * e quando", legivel sem abrir o git.
140
+ */
141
+ export function logAppliedPatch(cwd, summary) {
142
+ const dir = path.join(cwd, '.neetru', 'code');
143
+ fs.mkdirSync(dir, { recursive: true });
144
+ const file = path.join(dir, 'patches.log');
145
+ fs.appendFileSync(file, `${new Date().toISOString()} ${summary}\n`, 'utf8');
146
+ }
147
+ //# sourceMappingURL=code-agent-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-agent-session.js","sourceRoot":"","sources":["../../src/lib/code-agent-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Registro de ferramentas locais do `neetru code` — extraído de
3
+ * commands/code.ts (Fase 2, NEETRU_CODE_ARCHITECTURE.md: "separar núcleo de
4
+ * interface"). O system prompt é montado a partir do registro: Fase 3
5
+ * (run_tests, read_many_files, search_regex, project_symbols) só precisa
6
+ * adicionar entradas aqui — não editar o prompt à mão em vários lugares.
7
+ *
8
+ * Execução real das ferramentas (I/O de arquivo/git) mora em
9
+ * code-agent-files.ts — este módulo só descreve o protocolo pro modelo.
10
+ */
11
+ export interface CodeToolDescriptor {
12
+ name: string;
13
+ /** Linha de invocação mostrada no system prompt (protocolo NEETRU_TOOL). */
14
+ usage: string;
15
+ }
16
+ export declare const CODE_TOOL_REGISTRY: CodeToolDescriptor[];
17
+ export declare function buildSystemPrompt(): string;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Registro de ferramentas locais do `neetru code` — extraído de
3
+ * commands/code.ts (Fase 2, NEETRU_CODE_ARCHITECTURE.md: "separar núcleo de
4
+ * interface"). O system prompt é montado a partir do registro: Fase 3
5
+ * (run_tests, read_many_files, search_regex, project_symbols) só precisa
6
+ * adicionar entradas aqui — não editar o prompt à mão em vários lugares.
7
+ *
8
+ * Execução real das ferramentas (I/O de arquivo/git) mora em
9
+ * code-agent-files.ts — este módulo só descreve o protocolo pro modelo.
10
+ */
11
+ export const CODE_TOOL_REGISTRY = [
12
+ { name: 'read_file', usage: 'NEETRU_TOOL {"tool":"read_file","path":"caminho/relativo.ext"}' },
13
+ { name: 'list_files', usage: 'NEETRU_TOOL {"tool":"list_files","pattern":"texto opcional"}' },
14
+ { name: 'search', usage: 'NEETRU_TOOL {"tool":"search","query":"texto literal"}' },
15
+ { name: 'git_status', usage: 'NEETRU_TOOL {"tool":"git_status"}' },
16
+ { name: 'git_diff', usage: 'NEETRU_TOOL {"tool":"git_diff"}' },
17
+ { name: 'project_overview', usage: 'NEETRU_TOOL {"tool":"project_overview"}' },
18
+ // Fase 3 (NEETRU_CODE_ARCHITECTURE.md): ferramentas produtivas.
19
+ { name: 'read_many_files', usage: 'NEETRU_TOOL {"tool":"read_many_files","paths":["a.ts","b.ts"]}' },
20
+ { name: 'search_regex', usage: 'NEETRU_TOOL {"tool":"search_regex","pattern":"regex","flags":"i opcional"}' },
21
+ { name: 'run_tests', usage: 'NEETRU_TOOL {"tool":"run_tests"}' },
22
+ { name: 'project_symbols', usage: 'NEETRU_TOOL {"tool":"project_symbols","path":"opcional/um-arquivo.ts"}' },
23
+ ];
24
+ export function buildSystemPrompt() {
25
+ const toolLines = CODE_TOOL_REGISTRY.map((tool) => tool.usage).join('\n');
26
+ return `
27
+ Voce e o Neetru Code, um assistente local de codificacao da Neetru.
28
+ Voce conversa com modelos do AI Gateway do Neetru Core, normalmente Groq/NVIDIA.
29
+ Nao use Anthropic/Claude como caminho assumido.
30
+
31
+ Voce nao tem tool calling nativo. Use exatamente estes protocolos textuais:
32
+
33
+ ${toolLines}
34
+
35
+ Regras:
36
+ - Peca arquivos antes de alterar codigo quando faltar contexto.
37
+ - Use project_overview/git_status quando precisar entender o projeto antes de editar.
38
+ - Use git_diff antes de revisar mudancas ja existentes.
39
+ - Nunca invente conteudo de arquivo.
40
+ - Peca uma tool por resposta, no maximo.
41
+ - Quando estiver pronto para alterar, responda somente com um diff aplicavel por git:
42
+
43
+ NEETRU_PATCH
44
+ diff --git a/path b/path
45
+ ...
46
+ NEETRU_END
47
+
48
+ - Nao coloque explicacao dentro do bloco NEETRU_PATCH.
49
+ - Se a tarefa nao exigir alteracao, responda em texto curto.
50
+ `.trim();
51
+ }
52
+ //# sourceMappingURL=code-agent-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-agent-tools.js","sourceRoot":"","sources":["../../src/lib/code-agent-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,MAAM,CAAC,MAAM,kBAAkB,GAAyB;IACtD,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,gEAAgE,EAAE;IAC9F,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,8DAA8D,EAAE;IAC7F,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,uDAAuD,EAAE;IAClF,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,mCAAmC,EAAE;IAClE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,iCAAiC,EAAE;IAC9D,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,yCAAyC,EAAE;IAC9E,gEAAgE;IAChE,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,gEAAgE,EAAE;IACpG,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,4EAA4E,EAAE;IAC7G,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,kCAAkC,EAAE;IAChE,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,wEAAwE,EAAE;CAC7G,CAAC;AAEF,MAAM,UAAU,iBAAiB;IAC/B,MAAM,SAAS,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE1E,OAAO;;;;;;;EAOP,SAAS;;;;;;;;;;;;;;;;;CAiBV,CAAC,IAAI,EAAE,CAAC;AACT,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Tipos compartilhados entre os módulos do `neetru code`
3
+ * (code.ts, code-agent-ui.ts, code-agent-gateway.ts, code-agent-tools.ts,
4
+ * code-agent-session.ts) — evita import circular de tipo entre eles.
5
+ */
6
+ export type CodeRole = 'system' | 'user' | 'assistant';
7
+ export interface CodeMessage {
8
+ role: CodeRole;
9
+ content: string;
10
+ }
11
+ export interface CodeCommandOptions {
12
+ cwd?: string;
13
+ file?: string[];
14
+ model?: string;
15
+ maxTurns?: string | number;
16
+ maxTokens?: string | number;
17
+ temperature?: string | number;
18
+ plan?: boolean;
19
+ apply?: boolean;
20
+ yes?: boolean;
21
+ }
22
+ export interface CodeSettings {
23
+ cwd: string;
24
+ files: string[];
25
+ model: string;
26
+ modelWarning?: string;
27
+ maxTurns: number;
28
+ maxTokens: number;
29
+ temperature: number;
30
+ apply: boolean;
31
+ yes: boolean;
32
+ timeoutMs: number;
33
+ }
34
+ export type ConfirmFn = (question: string) => Promise<boolean>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tipos compartilhados entre os módulos do `neetru code`
3
+ * (code.ts, code-agent-ui.ts, code-agent-gateway.ts, code-agent-tools.ts,
4
+ * code-agent-session.ts) — evita import circular de tipo entre eles.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=code-agent-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-agent-types.js","sourceRoot":"","sources":["../../src/lib/code-agent-types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,30 @@
1
+ import { type CodeToolRequest } from './code-agent-protocol.js';
2
+ import type { CodeMessage, CodeSettings } from './code-agent-types.js';
3
+ export declare function stripAnsi(text: string): string;
4
+ export declare function visibleLength(text: string): number;
5
+ export declare function padVisible(text: string, width: number): string;
6
+ export declare function terminalWidth(): number;
7
+ export declare function truncateMiddle(text: string, max: number): string;
8
+ export declare function wrapPlain(text: string, width: number): string[];
9
+ export declare function printBox(title: string, rows?: string[]): void;
10
+ export declare function printStatusBar(settings: CodeSettings, mode: 'interactive' | 'oneshot' | 'doctor'): void;
11
+ export declare function printDivider(label?: string): void;
12
+ export declare function printEvent(kind: 'wait' | 'tool' | 'ok' | 'warn' | 'error', title: string, detail?: string): void;
13
+ export declare function summarizeToolResult(result: string): string;
14
+ export declare function printAssistantText(content: string): void;
15
+ export declare function patchSummaryRows(patch: string): string[];
16
+ export declare function printPatchPreview(patch: string): void;
17
+ export declare function renderHeader(settings: CodeSettings, mode?: 'interactive' | 'oneshot' | 'doctor'): void;
18
+ export declare function renderInteractiveHelp(): void;
19
+ export declare function renderSessionStatus(settings: CodeSettings, history?: CodeMessage[]): void;
20
+ export declare function renderPrompt(settings: CodeSettings): string;
21
+ export declare function printFileSample(files: string[], total: number): void;
22
+ /** Picker de arquivos (Fase 5) — lista numerada; `/pick` pede o(s) numero(s) ao usuario. */
23
+ export declare function printFilePicker(files: string[], total: number): void;
24
+ /** Lista sessoes salvas numeradas (Fase 4) — usuario escolhe pelo numero em `/resume`. */
25
+ export declare function printSessionList(sessions: Array<{
26
+ timestamp: string;
27
+ messageCount: number;
28
+ preview: string;
29
+ }>): void;
30
+ export declare function toolDetail(tool: CodeToolRequest | null): string;