nuxs-capsule 0.1.18 → 0.1.23

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,4 @@
1
+ #!/usr/bin/env node
2
+ // Entry do Hook PostToolUse Task/WebFetch — Lugar 2 (agent compressor).
3
+ // Comprime outputs de agents/web >10k bytes em TL;DR + bullets + refs.
4
+ await import('../dist/agent-compress.js');
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ // Entry do Hook PostToolUse Read — Lugar 1 (read compressor).
3
+ // Comprime Read >5k tokens em índice estrutural; original em ~/.nuxs/archive.
4
+ await import('../dist/read-compress.js');
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ // Entry do Hook SessionEnd — Lugar 8 (session summary popup).
3
+ // Mostra resumo de cápsulas + tokens economizados no fim de cada sessão.
4
+ await import('../dist/session-end.js');
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ // Entry do Hook UserPromptSubmit — Lugar 4 (avisos sticky).
3
+ // Anexa regras duráveis do projeto antes de cada msg do user virar input LLM.
4
+ await import('../dist/sticky-inject.js');
@@ -1,9 +1,25 @@
1
1
  #!/usr/bin/env node
2
- // Entry CLI multi-comando: nuxs-capsule [install|setup|wrap|flush|serve]
2
+ // Entry CLI multi-comando: nuxs-capsule [install|setup|wrap|flush|scan|version|serve]
3
+
4
+ import { readFileSync } from 'node:fs';
5
+
6
+ // Carrega versão SEMPRE — printa na primeira linha de qualquer comando.
7
+ const pkgPath = new URL('../package.json', import.meta.url);
8
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
9
+ const VERSION = pkg.version;
3
10
 
4
11
  const cmd = process.argv[2];
5
12
 
6
- if (cmd === 'install') {
13
+ // `wrap` é silencioso (pipe). `serve` é MCP (stdio limpo). `version` printa
14
+ // pelo console.log diretamente. Outros mostram banner em stderr.
15
+ const SILENT_COMMANDS = new Set(['wrap', 'serve', 'version', '--version', '-v', undefined]);
16
+ if (!SILENT_COMMANDS.has(cmd)) {
17
+ process.stderr.write(`nuxs-capsule v${VERSION}\n`);
18
+ }
19
+
20
+ if (cmd === 'version' || cmd === '--version' || cmd === '-v') {
21
+ console.log(`nuxs-capsule v${VERSION}`);
22
+ } else if (cmd === 'install') {
7
23
  await import('../dist/install.js');
8
24
  } else if (cmd === 'setup') {
9
25
  await import('../dist/setup.js');
@@ -26,6 +42,6 @@ if (cmd === 'install') {
26
42
  await import('../dist/server.js');
27
43
  } else {
28
44
  console.error(`nuxs-capsule: comando desconhecido "${cmd}"`);
29
- console.error('Use: install | setup | wrap | flush | scan | serve');
45
+ console.error('Use: install | setup | wrap | flush | scan | version | serve');
30
46
  process.exit(1);
31
47
  }
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Hook PostToolUse — `nuxs-capsule-agent-compress`.
4
+ *
5
+ * Intercepta result do tool Task (Agent) ou WebFetch quando retorna
6
+ * payload grande (>10k bytes). Gera cápsula TL;DR + bullets com refs.
7
+ *
8
+ * Pra agent: já é um sumário gerado por outro Claude — comprimir o
9
+ * sumário em sumário curto é seguro (não perde primários, eles ja
10
+ * são derivados).
11
+ *
12
+ * Pra WebFetch: comprime HTML/MD em snippet limpo.
13
+ *
14
+ * Original arquivado em ~/.nuxs/archive/.
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=agent-compress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-compress.d.ts","sourceRoot":"","sources":["../src/agent-compress.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG"}
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Hook PostToolUse — `nuxs-capsule-agent-compress`.
4
+ *
5
+ * Intercepta result do tool Task (Agent) ou WebFetch quando retorna
6
+ * payload grande (>10k bytes). Gera cápsula TL;DR + bullets com refs.
7
+ *
8
+ * Pra agent: já é um sumário gerado por outro Claude — comprimir o
9
+ * sumário em sumário curto é seguro (não perde primários, eles ja
10
+ * são derivados).
11
+ *
12
+ * Pra WebFetch: comprime HTML/MD em snippet limpo.
13
+ *
14
+ * Original arquivado em ~/.nuxs/archive/.
15
+ */
16
+ import { archiveOriginal } from './lib/archive.js';
17
+ import { trackUsage } from './telemetry/usage.js';
18
+ import { getMachineFingerprint } from './lib/fingerprint.js';
19
+ import { estimateTokensFromBytes, estimateCostUsd } from './lib/tokenCount.js';
20
+ const THRESHOLD_BYTES = 10_000;
21
+ async function readStdin() {
22
+ return new Promise((resolve) => {
23
+ let data = '';
24
+ process.stdin.setEncoding('utf8');
25
+ process.stdin.on('data', (c) => { data += c; });
26
+ process.stdin.on('end', () => resolve(data));
27
+ setTimeout(() => resolve(data), 4000);
28
+ });
29
+ }
30
+ function extractToolText(resp) {
31
+ if (typeof resp === 'string')
32
+ return resp;
33
+ if (!resp)
34
+ return '';
35
+ const c = resp.content;
36
+ if (typeof c === 'string')
37
+ return c;
38
+ if (Array.isArray(c))
39
+ return c.map((x) => (x && typeof x === 'object' && 'text' in x ? x.text : '')).join('\n');
40
+ return '';
41
+ }
42
+ /**
43
+ * Comprime sumário gerado por agent.
44
+ * Estratégia: manter primeiras N linhas (geralmente conclusão),
45
+ * extrair bullets e file:line refs, descartar prosa.
46
+ */
47
+ function compressAgentOutput(text) {
48
+ const lines = text.split('\n');
49
+ const head = lines.slice(0, 10);
50
+ // Coleta bullets (markdown - ou *)
51
+ const bullets = lines.filter((l) => /^\s*[-*•]\s/.test(l)).slice(0, 30);
52
+ // Coleta refs file:line (típico em sumários de Explore)
53
+ const refRegex = /([\w/.-]+\.(ts|tsx|js|jsx|py|md|json|sql|yml|yaml)):(\d+)/g;
54
+ const refs = new Set();
55
+ let m;
56
+ while ((m = refRegex.exec(text)) !== null) {
57
+ refs.add(`${m[1]}:${m[3]}`);
58
+ if (refs.size >= 50)
59
+ break;
60
+ }
61
+ const out = [];
62
+ out.push('[NUXS CAPSULE: agent output comprimido]');
63
+ out.push(`Original: ${lines.length} linhas, ${Buffer.byteLength(text, 'utf8')} bytes.`);
64
+ out.push('');
65
+ out.push('── TL;DR (primeiras 10 linhas) ──');
66
+ out.push(...head);
67
+ if (bullets.length > 0) {
68
+ out.push('');
69
+ out.push('── bullets ──');
70
+ out.push(...bullets);
71
+ }
72
+ if (refs.size > 0) {
73
+ out.push('');
74
+ out.push('── refs encontradas ──');
75
+ out.push(...Array.from(refs));
76
+ }
77
+ return out.join('\n');
78
+ }
79
+ async function main() {
80
+ const stdin = await readStdin();
81
+ if (!stdin) {
82
+ process.exit(0);
83
+ return;
84
+ }
85
+ let input;
86
+ try {
87
+ input = JSON.parse(stdin);
88
+ }
89
+ catch {
90
+ process.exit(0);
91
+ return;
92
+ }
93
+ const toolName = input.tool_name ?? '';
94
+ // Aplica em Task (subagents) e WebFetch
95
+ if (!/^(Task|WebFetch)$/.test(toolName)) {
96
+ process.exit(0);
97
+ return;
98
+ }
99
+ const text = extractToolText(input.tool_response);
100
+ const bytes = Buffer.byteLength(text, 'utf8');
101
+ if (bytes < THRESHOLD_BYTES) {
102
+ process.exit(0);
103
+ return;
104
+ }
105
+ const source = toolName === 'Task'
106
+ ? `agent:${input.tool_input?.subagent_type ?? 'unknown'}:${(input.tool_input?.description ?? '').slice(0, 40)}`
107
+ : `webfetch:${input.tool_input?.url ?? 'unknown'}`;
108
+ const compressed = compressAgentOutput(text);
109
+ const compressedBytes = Buffer.byteLength(compressed, 'utf8');
110
+ const tokensOriginal = estimateTokensFromBytes(bytes);
111
+ const tokensCompressed = estimateTokensFromBytes(compressedBytes);
112
+ const tokensSaved = tokensOriginal - tokensCompressed;
113
+ if (tokensSaved <= 0) {
114
+ process.exit(0);
115
+ return;
116
+ }
117
+ let archivePath;
118
+ try {
119
+ archivePath = archiveOriginal('agent', source, text, {
120
+ tokens_original: tokensOriginal,
121
+ tokens_compressed: tokensCompressed
122
+ });
123
+ }
124
+ catch { /* */ }
125
+ const fingerprint = getMachineFingerprint();
126
+ const record = {
127
+ timestamp: new Date().toISOString(),
128
+ capsule_type: 'api',
129
+ input_size_bytes: bytes,
130
+ output_size_bytes: compressedBytes,
131
+ input_tokens_estimated: tokensOriginal,
132
+ output_tokens_estimated: tokensCompressed,
133
+ tokens_saved: tokensSaved,
134
+ provider_used: 'algorithm',
135
+ cost_saved_usd: estimateCostUsd(tokensSaved, 0, 'sonnet-4-6'),
136
+ agent_detected: 'claude_code',
137
+ latency_ms: 0,
138
+ machine_fingerprint: fingerprint
139
+ };
140
+ try {
141
+ await trackUsage(record);
142
+ }
143
+ catch { /* */ }
144
+ const refLine = archivePath ? `\n📦 Original: ${archivePath}` : '';
145
+ const out = {
146
+ hookSpecificOutput: {
147
+ hookEventName: 'PostToolUse',
148
+ additionalContext: compressed + refLine
149
+ }
150
+ };
151
+ process.stdout.write(JSON.stringify(out));
152
+ process.exit(0);
153
+ }
154
+ main().catch(() => process.exit(0));
155
+ //# sourceMappingURL=agent-compress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-compress.js","sourceRoot":"","sources":["../src/agent-compress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Arquivamento MD — backup do conteúdo original ANTES de comprimir.
3
+ *
4
+ * Toda cápsula nova (Read compressor, Agent compressor, sticky injector,
5
+ * proxy histórico) chama archiveOriginal() antes de gerar a versão
6
+ * comprimida. Resultado: usuário (ou eu) pode SEMPRE recuperar o original
7
+ * lendo o arquivo MD da pasta, evitando "perda de contexto" mesmo quando
8
+ * a cápsula erra resumo.
9
+ *
10
+ * Estrutura:
11
+ * ~/.nuxs/archive/
12
+ * 2026-05-28/
13
+ * sticky-bff3a01-1716902400.md
14
+ * read-page-tsx-1716902404.md
15
+ * agent-explore-1716902412.md
16
+ * _index.jsonl ← uma linha por arquivo, fácil de listar
17
+ *
18
+ * Granularidade: 1 arquivo por evento (não agrupado por sessão). Mantém
19
+ * busca/limpeza simples. Cleanup: archives > 30 dias removidos no flush.
20
+ */
21
+ export interface ArchiveEntry {
22
+ kind: 'sticky' | 'read' | 'agent' | 'history' | 'tool_result';
23
+ source: string;
24
+ timestamp: string;
25
+ tokens_original: number;
26
+ tokens_compressed: number;
27
+ archive_path: string;
28
+ }
29
+ /**
30
+ * Salva conteúdo original num MD. Retorna o path completo.
31
+ *
32
+ * @param kind — tipo da cápsula
33
+ * @param source — identificador legível (ex: "page.tsx", "agent:explore-rotas")
34
+ * @param content — conteúdo cru a preservar
35
+ * @param meta — tokens estimados original e comprimido (pra dashboard)
36
+ */
37
+ export declare function archiveOriginal(kind: ArchiveEntry['kind'], source: string, content: string, meta: {
38
+ tokens_original: number;
39
+ tokens_compressed: number;
40
+ }): string;
41
+ /**
42
+ * Hash curto de conteúdo — útil pra dedup quando o mesmo conteúdo é
43
+ * arquivado várias vezes (mesmo Read no mesmo arquivo).
44
+ */
45
+ export declare function contentHash(content: string): string;
46
+ /**
47
+ * Cleanup automático — chamado pelo flush. Remove archives > N dias.
48
+ * Idempotente, silencioso em erros.
49
+ */
50
+ export declare function cleanOldArchives(retentionDays?: number): {
51
+ removed: number;
52
+ };
53
+ //# sourceMappingURL=archive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../src/lib/archive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAWH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,aAAa,CAAC;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAC1B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAC3D,MAAM,CAyCR;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,SAAiB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CA4BpF"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Arquivamento MD — backup do conteúdo original ANTES de comprimir.
3
+ *
4
+ * Toda cápsula nova (Read compressor, Agent compressor, sticky injector,
5
+ * proxy histórico) chama archiveOriginal() antes de gerar a versão
6
+ * comprimida. Resultado: usuário (ou eu) pode SEMPRE recuperar o original
7
+ * lendo o arquivo MD da pasta, evitando "perda de contexto" mesmo quando
8
+ * a cápsula erra resumo.
9
+ *
10
+ * Estrutura:
11
+ * ~/.nuxs/archive/
12
+ * 2026-05-28/
13
+ * sticky-bff3a01-1716902400.md
14
+ * read-page-tsx-1716902404.md
15
+ * agent-explore-1716902412.md
16
+ * _index.jsonl ← uma linha por arquivo, fácil de listar
17
+ *
18
+ * Granularidade: 1 arquivo por evento (não agrupado por sessão). Mantém
19
+ * busca/limpeza simples. Cleanup: archives > 30 dias removidos no flush.
20
+ */
21
+ import { writeFileSync, existsSync, appendFileSync, readdirSync, statSync, unlinkSync, rmdirSync } from 'node:fs';
22
+ import { homedir } from 'node:os';
23
+ import { join } from 'node:path';
24
+ import { createHash } from 'node:crypto';
25
+ import { ensureDir } from './fileStat.js';
26
+ const ARCHIVE_DIR = join(homedir(), '.nuxs', 'archive');
27
+ const RETENTION_DAYS = 30;
28
+ /**
29
+ * Salva conteúdo original num MD. Retorna o path completo.
30
+ *
31
+ * @param kind — tipo da cápsula
32
+ * @param source — identificador legível (ex: "page.tsx", "agent:explore-rotas")
33
+ * @param content — conteúdo cru a preservar
34
+ * @param meta — tokens estimados original e comprimido (pra dashboard)
35
+ */
36
+ export function archiveOriginal(kind, source, content, meta) {
37
+ const date = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
38
+ const dayDir = join(ARCHIVE_DIR, date);
39
+ ensureDir(dayDir);
40
+ const ts = Date.now();
41
+ const slug = source
42
+ .replace(/[^a-zA-Z0-9._-]+/g, '-')
43
+ .replace(/^-+|-+$/g, '')
44
+ .slice(0, 60) || 'unknown';
45
+ const filename = `${kind}-${slug}-${ts}.md`;
46
+ const archivePath = join(dayDir, filename);
47
+ const header = [
48
+ `<!-- nuxs-capsule archive -->`,
49
+ `# ${kind}: ${source}`,
50
+ ``,
51
+ `- **Timestamp:** ${new Date(ts).toISOString()}`,
52
+ `- **Tokens original:** ${meta.tokens_original}`,
53
+ `- **Tokens comprimido:** ${meta.tokens_compressed}`,
54
+ `- **Redução:** ${meta.tokens_original > 0 ? Math.round((1 - meta.tokens_compressed / meta.tokens_original) * 100) : 0}%`,
55
+ ``,
56
+ `---`,
57
+ ``
58
+ ].join('\n');
59
+ writeFileSync(archivePath, header + content);
60
+ // Append no índice diário (1 linha JSONL por entry)
61
+ const indexPath = join(dayDir, '_index.jsonl');
62
+ const entry = {
63
+ kind,
64
+ source,
65
+ timestamp: new Date(ts).toISOString(),
66
+ tokens_original: meta.tokens_original,
67
+ tokens_compressed: meta.tokens_compressed,
68
+ archive_path: archivePath
69
+ };
70
+ appendFileSync(indexPath, JSON.stringify(entry) + '\n');
71
+ return archivePath;
72
+ }
73
+ /**
74
+ * Hash curto de conteúdo — útil pra dedup quando o mesmo conteúdo é
75
+ * arquivado várias vezes (mesmo Read no mesmo arquivo).
76
+ */
77
+ export function contentHash(content) {
78
+ return createHash('sha256').update(content).digest('hex').slice(0, 12);
79
+ }
80
+ /**
81
+ * Cleanup automático — chamado pelo flush. Remove archives > N dias.
82
+ * Idempotente, silencioso em erros.
83
+ */
84
+ export function cleanOldArchives(retentionDays = RETENTION_DAYS) {
85
+ if (!existsSync(ARCHIVE_DIR))
86
+ return { removed: 0 };
87
+ const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
88
+ let removed = 0;
89
+ try {
90
+ const days = readdirSync(ARCHIVE_DIR);
91
+ for (const day of days) {
92
+ const dayPath = join(ARCHIVE_DIR, day);
93
+ let dayStat;
94
+ try {
95
+ dayStat = statSync(dayPath);
96
+ }
97
+ catch {
98
+ continue;
99
+ }
100
+ if (!dayStat.isDirectory())
101
+ continue;
102
+ if (dayStat.mtimeMs > cutoff)
103
+ continue;
104
+ // Limpa arquivos do dia
105
+ try {
106
+ for (const f of readdirSync(dayPath)) {
107
+ try {
108
+ unlinkSync(join(dayPath, f));
109
+ removed++;
110
+ }
111
+ catch { /* ignore */ }
112
+ }
113
+ rmdirSync(dayPath);
114
+ }
115
+ catch { /* ignore */ }
116
+ }
117
+ }
118
+ catch { /* ignore */ }
119
+ return { removed };
120
+ }
121
+ //# sourceMappingURL=archive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/lib/archive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Stickies — regras críticas do projeto que sempre acompanham o contexto.
3
+ *
4
+ * Carregadas de duas fontes (uniões):
5
+ *
6
+ * 1. `~/.nuxs/stickies.json` — lista explícita criada pelo user/setup.
7
+ * 2. `~/.claude/projects/.../memory/MEMORY.md` — entradas marcadas como
8
+ * sticky via `[STICKY]` no início da linha OU memórias do tipo
9
+ * `feedback` (regras duráveis que o user já reforçou).
10
+ *
11
+ * Uso: hook UserPromptSubmit lê esta lista e injeta como pre-message
12
+ * pra cada turno. Mantém eu (Claude) lembrado de "DeepSeek != Haiku",
13
+ * "ctrl+c+v != recriar", "1 conta por provider", etc.
14
+ *
15
+ * Custo: 100-300 tokens/turno, ganho: zero retrabalho por esquecimento.
16
+ */
17
+ export interface Sticky {
18
+ source: 'manual' | 'memory-feedback' | 'memory-tagged';
19
+ text: string;
20
+ origin?: string;
21
+ }
22
+ /**
23
+ * Lê stickies de ambas fontes, faz dedup, limita tamanho.
24
+ */
25
+ export declare function loadStickies(): Sticky[];
26
+ /**
27
+ * Adiciona uma sticky manual (chamada via CLI `nuxs-capsule sticky add "..."`).
28
+ */
29
+ export declare function addManualSticky(text: string): void;
30
+ /**
31
+ * Formata stickies como bloco pra anexar a um prompt.
32
+ */
33
+ export declare function formatStickiesBlock(stickies: Sticky[]): string;
34
+ //# sourceMappingURL=stickies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stickies.d.ts","sourceRoot":"","sources":["../../src/lib/stickies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAcH,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,QAAQ,GAAG,iBAAiB,GAAG,eAAe,CAAC;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,EAAE,CA6CvC;AA0DD;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CASlD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAS9D"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Stickies — regras críticas do projeto que sempre acompanham o contexto.
3
+ *
4
+ * Carregadas de duas fontes (uniões):
5
+ *
6
+ * 1. `~/.nuxs/stickies.json` — lista explícita criada pelo user/setup.
7
+ * 2. `~/.claude/projects/.../memory/MEMORY.md` — entradas marcadas como
8
+ * sticky via `[STICKY]` no início da linha OU memórias do tipo
9
+ * `feedback` (regras duráveis que o user já reforçou).
10
+ *
11
+ * Uso: hook UserPromptSubmit lê esta lista e injeta como pre-message
12
+ * pra cada turno. Mantém eu (Claude) lembrado de "DeepSeek != Haiku",
13
+ * "ctrl+c+v != recriar", "1 conta por provider", etc.
14
+ *
15
+ * Custo: 100-300 tokens/turno, ganho: zero retrabalho por esquecimento.
16
+ */
17
+ import { readFileSync, existsSync, writeFileSync, readdirSync } from 'node:fs';
18
+ import { homedir } from 'node:os';
19
+ import { join } from 'node:path';
20
+ import { ensureDir } from './fileStat.js';
21
+ const NUXS_DIR = join(homedir(), '.nuxs');
22
+ const STICKIES_FILE = join(NUXS_DIR, 'stickies.json');
23
+ const MEMORY_BASE = join(homedir(), '.claude', 'projects');
24
+ const MAX_STICKIES = 12; // limite duro
25
+ const MAX_TOTAL_TOKENS = 600; // ~ orçamento token por turno
26
+ /**
27
+ * Lê stickies de ambas fontes, faz dedup, limita tamanho.
28
+ */
29
+ export function loadStickies() {
30
+ const stickies = [];
31
+ // 1. ~/.nuxs/stickies.json (lista manual)
32
+ if (existsSync(STICKIES_FILE)) {
33
+ try {
34
+ const raw = JSON.parse(readFileSync(STICKIES_FILE, 'utf8'));
35
+ if (Array.isArray(raw)) {
36
+ for (const entry of raw) {
37
+ if (typeof entry === 'string') {
38
+ stickies.push({ source: 'manual', text: entry });
39
+ }
40
+ else if (entry && typeof entry.text === 'string') {
41
+ stickies.push({ source: 'manual', text: entry.text });
42
+ }
43
+ }
44
+ }
45
+ }
46
+ catch { /* arquivo corrupto, ignora */ }
47
+ }
48
+ // 2. MEMORY.md — extrai linhas de feedback (regras duráveis)
49
+ try {
50
+ stickies.push(...loadFromMemory());
51
+ }
52
+ catch { /* memory dir não existe */ }
53
+ // Dedup por texto
54
+ const seen = new Set();
55
+ const deduped = [];
56
+ for (const s of stickies) {
57
+ const key = s.text.trim().toLowerCase();
58
+ if (seen.has(key))
59
+ continue;
60
+ seen.add(key);
61
+ deduped.push(s);
62
+ }
63
+ // Limite token aproximado (~4 chars/token)
64
+ let totalChars = 0;
65
+ const result = [];
66
+ for (const s of deduped) {
67
+ if (result.length >= MAX_STICKIES)
68
+ break;
69
+ const chars = s.text.length;
70
+ if (totalChars + chars > MAX_TOTAL_TOKENS * 4)
71
+ break;
72
+ totalChars += chars;
73
+ result.push(s);
74
+ }
75
+ return result;
76
+ }
77
+ /**
78
+ * Lê MEMORY.md do projeto atual (cwd) e extrai linhas de feedback.
79
+ * MEMORY.md tem formato `- [Title](file.md) — hook`. Pegamos hook.
80
+ */
81
+ function loadFromMemory() {
82
+ if (!existsSync(MEMORY_BASE))
83
+ return [];
84
+ // Encontra o projeto que tem cwd no path
85
+ const cwd = process.cwd();
86
+ const projects = readdirSync(MEMORY_BASE);
87
+ let memoryDir = null;
88
+ for (const proj of projects) {
89
+ // Nome do projeto na pasta `.claude/projects` é o path escapado
90
+ // ex: "-Users-josuca-Documents-pixeldesk" pra /Users/josuca/Documents/pixeldesk
91
+ const restored = proj.replace(/^-/, '/').replace(/-/g, '/');
92
+ if (cwd.startsWith(restored)) {
93
+ const candidate = join(MEMORY_BASE, proj, 'memory', 'MEMORY.md');
94
+ if (existsSync(candidate)) {
95
+ memoryDir = join(MEMORY_BASE, proj, 'memory');
96
+ break;
97
+ }
98
+ }
99
+ }
100
+ if (!memoryDir)
101
+ return [];
102
+ const memoryFile = join(memoryDir, 'MEMORY.md');
103
+ let content;
104
+ try {
105
+ content = readFileSync(memoryFile, 'utf8');
106
+ }
107
+ catch {
108
+ return [];
109
+ }
110
+ const out = [];
111
+ const lines = content.split('\n');
112
+ for (const line of lines) {
113
+ // formato: - [Title](file.md) — hook texto curto
114
+ const m = line.match(/^-\s+\[([^\]]+)\]\(([^)]+\.md)\)\s+[—\-–]\s+(.+)$/);
115
+ if (!m)
116
+ continue;
117
+ const filename = m[2];
118
+ const hook = m[3].trim();
119
+ // Carrega arquivo pra ver tipo
120
+ const targetFile = join(memoryDir, filename);
121
+ if (!existsSync(targetFile)) {
122
+ // hook do índice já vale como sticky
123
+ out.push({ source: 'memory-tagged', text: hook, origin: filename });
124
+ continue;
125
+ }
126
+ try {
127
+ const raw = readFileSync(targetFile, 'utf8');
128
+ const isFeedback = /type:\s*feedback/.test(raw);
129
+ if (isFeedback) {
130
+ out.push({ source: 'memory-feedback', text: hook, origin: filename });
131
+ }
132
+ }
133
+ catch { /* ignora */ }
134
+ }
135
+ return out;
136
+ }
137
+ /**
138
+ * Adiciona uma sticky manual (chamada via CLI `nuxs-capsule sticky add "..."`).
139
+ */
140
+ export function addManualSticky(text) {
141
+ ensureDir(NUXS_DIR);
142
+ let list = [];
143
+ if (existsSync(STICKIES_FILE)) {
144
+ try {
145
+ list = JSON.parse(readFileSync(STICKIES_FILE, 'utf8'));
146
+ }
147
+ catch { /* */ }
148
+ }
149
+ if (!Array.isArray(list))
150
+ list = [];
151
+ list.push({ text });
152
+ writeFileSync(STICKIES_FILE, JSON.stringify(list, null, 2));
153
+ }
154
+ /**
155
+ * Formata stickies como bloco pra anexar a um prompt.
156
+ */
157
+ export function formatStickiesBlock(stickies) {
158
+ if (stickies.length === 0)
159
+ return '';
160
+ const lines = [
161
+ '⚠️ AVISOS DURÁVEIS DESSE PROJETO (não esquecer):'
162
+ ];
163
+ for (const s of stickies) {
164
+ lines.push(`• ${s.text}`);
165
+ }
166
+ return lines.join('\n');
167
+ }
168
+ //# sourceMappingURL=stickies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stickies.js","sourceRoot":"","sources":["../../src/lib/stickies.ts"],"names":[],"mappings":"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"}