codetac 0.1.0 → 0.1.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codetac",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "codeTAC — perceber o que o código da sua app Node faz, ação a ação: do clique no browser às funções do servidor, base de dados e serviços externos.",
5
5
  "keywords": [
6
6
  "debug",
package/readme.md CHANGED
@@ -4,7 +4,13 @@
4
4
 
5
5
  *See what your app's code does, one click at a time: a local tool for Node.js apps, including those generated by AI tools (Lovable, Bolt, v0, Cursor, Replit, Claude Code…). Explanations are in Portuguese by default (`CODETAC_LANG=en` for English).*
6
6
 
7
- Clica num botão da sua app e o codeTAC mostra um **dossiê** dessa ação:
7
+ ![Dossier de um clique no botão «Sign in»: as funções do servidor que correram, com o ficheiro e a linha, e as leituras da base de dados](https://raw.githubusercontent.com/deltaxmodules/codetacvibe/main/.github/imagens/dossier.png)
8
+
9
+ ## Para quê
10
+
11
+ A sua app foi feita por uma IA, ou por outra pessoa, e não sabe ao certo o que acontece quando carrega em «Guardar»? Que funções correm, que tabela é alterada, se sai um email, se o pagamento está em modo de teste ou de produção?
12
+
13
+ Carregue num botão da sua app e o codeTAC mostra um **dossier** dessa ação:
8
14
  - **no browser:** o que foi clicado, o componente e onde está no código;
9
15
  - **no servidor:** as funções do seu projeto que correram, pela ordem, com o ficheiro e a linha;
10
16
  - **as fronteiras:** base de dados, serviços externos, email, pagamentos, ficheiros, IA;
@@ -12,8 +18,45 @@ Clica num botão da sua app e o codeTAC mostra um **dossiê** dessa ação:
12
18
  - **os efeitos permanentes:** linhas gravadas, emails enviados, cookies…;
13
19
  - uma frase simples em cada passo a dizer para que serve.
14
20
 
21
+ Em qualquer passo, pode abrir o código dessa função e fazer uma pergunta sobre ele.
22
+
15
23
  Tudo corre no seu computador. O código da app não é alterado.
16
24
 
25
+ ## Para que apps serve
26
+
27
+ **Apps web em Node.js (JavaScript ou TypeScript), a correr no seu computador.** Incluindo as feitas com Lovable, Bolt, v0, Cursor, Replit ou Claude Code.
28
+
29
+ **Ensaiado com:**
30
+ - Next.js (incluindo a versão 16);
31
+ - Vite + React;
32
+ - Express;
33
+ - TanStack Start;
34
+ - projetos com frontend e backend separados, e monorepos (npm, pnpm, yarn).
35
+
36
+ Outras apps Node devem funcionar (Nuxt, SvelteKit, Astro, Remix, NestJS, Fastify…), mas ainda não foram ensaiadas. Se algo falhar, veja a [secção 6](#6-quando-algo-não-funciona).
37
+
38
+ **Mostra à parte quando a app usa:**
39
+
40
+ | | |
41
+ | --- | --- |
42
+ | Base de dados | Postgres (`pg`), MySQL (`mysql2`), SQLite (`better-sqlite3`, `node:sqlite`), Supabase (com a tabela e a operação) |
43
+ | IA | OpenAI, Anthropic, Google, Mistral, Groq, OpenRouter, DeepSeek, Cohere, Together, modelos locais |
44
+ | Email e mensagens | nodemailer, Resend, SendGrid, Postmark, Mailgun, Brevo, Twilio |
45
+ | Pagamentos | Stripe, com a indicação de modo de teste ou de produção |
46
+ | Autenticação | NextAuth, Supabase Auth, Clerk |
47
+ | Ficheiros | disco do computador, S3, Supabase Storage |
48
+ | Outros | qualquer pedido do servidor a um serviço externo, cookies |
49
+
50
+ Os serviços chamados diretamente do browser (por exemplo o Supabase, em muitas apps do Lovable e do Bolt) aparecem como pedidos do browser, sem o passo a passo do servidor.
51
+
52
+ **Ainda não serve para:**
53
+ - apps em Python, PHP, Go ou Ruby (FastAPI, Flask, Django, Laravel…);
54
+ - sites só com HTML e JavaScript, sem um servidor Node;
55
+ - partes que correm em Bun, Deno, Cloudflare Workers ou no middleware do Next.js;
56
+ - apps em produção ou que só existem na nuvem.
57
+
58
+ Precisa do Node.js 24 ou mais recente. Ensaiado em macOS; o Windows ainda não foi ensaiado.
59
+
17
60
  ---
18
61
 
19
62
  ## 1. Antes de começar
@@ -42,7 +85,7 @@ Confirme com `codetac --version`, que mostra o número da versão.
42
85
 
43
86
  Se aparecer um erro de permissões (`EACCES`), use `npx codetac` em vez de `codetac` nos passos abaixo. Funciona sem instalar.
44
87
 
45
- ## 3. O primeiro dossiê
88
+ ## 3. O primeiro dossier
46
89
 
47
90
  1. No Terminal, vá para a pasta do projeto: escreva `cd ` (com um espaço), arraste a pasta do projeto para a janela do Terminal e carregue em Enter.
48
91
  2. Escreva:
@@ -57,13 +100,13 @@ Se aparecer um erro de permissões (`EACCES`), use `npx codetac` em vez de `code
57
100
  4. Quando aparecer **«✓ App pronta em http://localhost:…»**, o browser abre com a sua app.
58
101
  5. **Use a app:** clique num botão, numa ligação, envie um formulário.
59
102
  - No canto inferior direito da página aparece uma pequena barra com «Gravada: …».
60
- - No Terminal aparece «✓ Primeiro dossiê …» com um link.
61
- 6. Carregue na barra, ou abra o link, para ver o dossiê.
103
+ - No Terminal aparece «✓ Primeiro dossier …» com um link.
104
+ 6. Carregue na barra, ou abra o link, para ver o dossier.
62
105
  7. Para terminar, volte ao Terminal e carregue em **Ctrl+C**.
63
106
 
64
- Numa app que já conhece, o primeiro dossiê chega normalmente em menos de um minuto.
107
+ Numa app que já conhece, o primeiro dossier chega normalmente em menos de um minuto.
65
108
 
66
- ## 4. Ler o dossiê
109
+ ## 4. Ler o dossier
67
110
 
68
111
  - **A frase do topo** resume a ação, por exemplo: «Clique em botão «Add» → POST /api/items (estado 201) → altera o ecrã».
69
112
  - **browser → servidor:** cada pedido que a ação fez ao servidor. Por baixo estão as funções do seu projeto que correram.
@@ -108,7 +151,7 @@ Cada linha começa por **✓** (funciona), **!** (atenção) ou **✗** (problem
108
151
  | «Não encontrei um package.json…» | Está na pasta errada. Vá para a pasta que tem o ficheiro `package.json`, ou indique o arranque: `codetac -- node server.js` |
109
152
  | «A porta 3000 já está ocupada por outro programa…» | Feche o outro programa, por exemplo outra app aberta noutra janela do Terminal. Numa app com uma só parte, o codeTAC muda de porta sozinho |
110
153
  | «A app falhou também em modo mínimo» | O problema é da própria app. Muitas vezes faltam as chaves no ficheiro `.env` (Supabase, Firebase…). Veja o `.env.example` ou as instruções do projeto |
111
- | «A página inicial respondeu com erro 500» | A app arrancou, mas falha. O dossiê desse carregamento mostra onde |
154
+ | «A página inicial respondeu com erro 500» | A app arrancou, mas falha. O dossier desse carregamento mostra onde |
112
155
  | A barra não aparece na página | Recarregue a página. Veja se o endereço é o que o codeTAC indicou |
113
156
 
114
157
  **Comunicar um problema:**
@@ -149,11 +192,10 @@ Guarda o diagnóstico num ficheiro, sem código nem dados da app. Envie-o com um
149
192
 
150
193
  ## 9. Limites
151
194
 
152
- - Só apps **Node.js** (JavaScript e TypeScript) a correr **no seu computador**, em desenvolvimento.
153
- - Não serve para apps em produção nem só na nuvem.
154
- - Partes da app que não correm no Node não são observadas por dentro: Bun, Deno, Cloudflare Workers, o middleware do Next.js. O comando avisa quando as reconhece.
195
+ - Os tipos de app que servem e os que não servem estão em [Para que apps serve](#para-que-apps-serve).
196
+ - É para usar em desenvolvimento, no seu computador. Não serve para apps em produção.
197
+ - As partes que não correm no Node não são observadas por dentro. O comando avisa quando as reconhece.
155
198
  - No browser, mostra-se o elemento, o componente e o caminho até cada pedido, mas não cada função.
156
- - Windows: ainda não ensaiado.
157
199
 
158
200
  ## Licença
159
201
 
package/src/ai.mjs CHANGED
@@ -295,7 +295,7 @@ export async function answerQuestion({ config, dossier, stepId, question, readCo
295
295
  let step = null;
296
296
  let parent = null;
297
297
  walk(dossier.digest.nodes, (node, holder) => { if (node.id === stepId) { step = node; parent = holder; } });
298
- if (!step) return { available: true, known: false, text: 'Este passo não foi encontrado no dossiê.' };
298
+ if (!step) return { available: true, known: false, text: 'Este passo não foi encontrado no dossier.' };
299
299
  const target = step.type === 'function' ? step : parent?.type === 'function' ? parent : null;
300
300
  const code = target ? readCode(dossier.request.run, target.file, target.line, target.endLine) : null;
301
301
  const facts = target ? subtree(target) : { boundaries: [step], functions: [] };
@@ -521,7 +521,7 @@
521
521
  '.top{display:flex;gap:6px;align-items:center;padding:6px 8px;background:#18181b;color:#f4f4f5}.top b{margin-right:auto}' +
522
522
  '.top button,.top a{all:unset;cursor:pointer;padding:2px 8px;border-radius:5px;color:#e4e4e7}.top button:hover,.top a:hover{background:#3f3f46}' +
523
523
  'iframe{border:0;flex:1;width:100%}.msg{padding:16px;color:#27272a}</style>' +
524
- '<button class="pill" part="pill" title="CodeTAC: carregue para ver o dossiê da última ação"><span class="dot"></span><span class="label">CodeTAC</span></button>';
524
+ '<button class="pill" part="pill" title="CodeTAC: carregue para ver o dossier da última ação"><span class="dot"></span><span class="label">CodeTAC</span></button>';
525
525
  shadow.querySelector('.pill').addEventListener('click', () => toggleSheet());
526
526
  document.documentElement.appendChild(host);
527
527
  updateBar(false);
@@ -562,7 +562,7 @@
562
562
  }
563
563
  shown.innerHTML = '<div class="top"><b></b><button data-go="-1" title="Ação anterior">◀</button><button data-go="1" title="Ação seguinte">▶</button>' +
564
564
  '<a target="_blank" rel="noopener" title="Abrir no painel">painel ↗</a><button data-close title="Fechar">✕</button></div>' +
565
- '<iframe title="Dossiê da ação"></iframe>';
565
+ '<iframe title="Dossier da ação"></iframe>';
566
566
  shown.querySelector('b').textContent = (index + 1) + '/' + recorded.length + ' · ' + item.label;
567
567
  shown.querySelector('a').href = panel + '/?action=' + encodeURIComponent(item.id);
568
568
  shown.querySelector('iframe').src = url;
package/src/cli.mjs CHANGED
@@ -491,13 +491,13 @@ async function main() {
491
491
  const appUrl = found.url ?? `http://localhost:${found.port}/`;
492
492
  say('');
493
493
  say(`✓ App pronta em ${appUrl} (${seconds()})${minimal ? ' · modo mínimo' : ''}`);
494
- if (found.status >= 500) say(`! A página inicial respondeu com erro ${found.status}. Veja as mensagens da app acima (faltam variáveis de ambiente?). O dossiê desse pedido mostra onde falhou.`);
494
+ if (found.status >= 500) say(`! A página inicial respondeu com erro ${found.status}. Veja as mensagens da app acima (faltam variáveis de ambiente?). O dossier desse pedido mostra onde falhou.`);
495
495
  if (found.page) {
496
496
  say(' Abra-a no browser e use-a: a barra do CodeTAC aparece no canto inferior direito.');
497
- say(' Cada ação (clique, formulário…) fica com um dossiê; a barra abre-o.');
497
+ say(' Cada ação (clique, formulário…) fica com um dossier; a barra abre-o.');
498
498
  if (!options.noOpen && interactive) openBrowser(appUrl);
499
499
  } else {
500
- say(' Esta app responde sem páginas HTML (uma API). Faça pedidos como de costume; cada pedido fica com um dossiê no painel.');
500
+ say(' Esta app responde sem páginas HTML (uma API). Faça pedidos como de costume; cada pedido fica com um dossier no painel.');
501
501
  }
502
502
  say(` Painel: ${panelUrl} · Terminar: Ctrl+C`);
503
503
  say('');
@@ -511,23 +511,23 @@ async function main() {
511
511
  if (seenActions.has(id)) continue;
512
512
  seenActions.add(id);
513
513
  const link = `${panelUrl}/?action=${encodeURIComponent(id)}`;
514
- if (!firstShown) { firstShown = true; say(`✓ Primeiro dossiê (${seconds()} desde o comando): ${link}`); }
514
+ if (!firstShown) { firstShown = true; say(`✓ Primeiro dossier (${seconds()} desde o comando): ${link}`); }
515
515
  else say(`• Ação gravada: ${link}`);
516
516
  }
517
517
  // A page that loads but where nothing is clicked yet (or that fails to
518
518
  // render): the dossier of its own load.
519
519
  if (!firstShown && summary.firstPage && Date.now() - summary.firstPage.seenAt > 8000) {
520
520
  firstShown = true;
521
- say(`✓ Primeiro dossiê (${seconds()} desde o comando), o do carregamento da página: ${panelUrl}/?request=${encodeURIComponent(summary.firstPage.requestId)}`);
522
- say(' Cada clique na app terá o seu próprio dossiê.');
521
+ say(`✓ Primeiro dossier (${seconds()} desde o comando), o do carregamento da página: ${panelUrl}/?request=${encodeURIComponent(summary.firstPage.requestId)}`);
522
+ say(' Cada clique na app terá o seu próprio dossier.');
523
523
  }
524
524
  if (!firstShown && summary.firstRequest && !found.page) {
525
525
  firstShown = true;
526
- say(`✓ Primeiro dossiê (${seconds()} desde o comando): ${panelUrl}/?request=${encodeURIComponent(summary.firstRequest.requestId)}`);
526
+ say(`✓ Primeiro dossier (${seconds()} desde o comando): ${panelUrl}/?request=${encodeURIComponent(summary.firstRequest.requestId)}`);
527
527
  }
528
528
  if (!silentWarned && !minimal && summary.requests >= 3 && !summary.withFunctions.size && summary.functions === 0) {
529
529
  silentWarned = true;
530
- say('! Já chegaram pedidos, mas nenhuma função do projeto foi observada. Os dossiês mostram pedidos e fronteiras.');
530
+ say('! Já chegaram pedidos, mas nenhuma função do projeto foi observada. Os dossiers mostram pedidos e fronteiras.');
531
531
  say(' «codetac diagnostico» explica porquê.');
532
532
  }
533
533
  // A part that fails later with a taken port: its requests could reach the
package/src/diagnose.mjs CHANGED
@@ -94,7 +94,7 @@ export async function diagnose(root, { panelPort = 4000, out = text => process.s
94
94
  if (!minimal) {
95
95
  if (summary.files) ok(`Ficheiros do projeto preparados: ${summary.files} (${summary.functions} funções).`);
96
96
  else if (summary.requests) bad('Nenhum ficheiro do projeto passou pelo CodeTAC.',
97
- 'O servidor pode estar a correr código já empacotado sem source map, ou fora da pasta do projeto. Os dossiês mostram só pedidos e fronteiras.');
97
+ 'O servidor pode estar a correr código já empacotado sem source map, ou fora da pasta do projeto. Os dossiers mostram só pedidos e fronteiras.');
98
98
  const failed = summary.failed.length;
99
99
  if (failed) {
100
100
  note(`${failed} ficheiro(s) correm sem ser seguidos (não foi possível prepará-los):`);
package/src/digest.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // Vista agrupada do dossiê (Fase 3): árvore de passos com o ruído agrupado,
1
+ // Vista agrupada do dossier (Fase 3): árvore de passos com o ruído agrupado,
2
2
  // uma frase de finalidade por função e por fronteira, e o resumo dos efeitos
3
3
  // permanentes. Tudo deriva dos factos gravados; nada é removido, só agrupado
4
4
  // (cada grupo guarda os passos originais para a expansão).
package/src/panel.mjs CHANGED
@@ -202,7 +202,7 @@ const page = `<!doctype html>
202
202
  <head>
203
203
  <meta charset="utf-8">
204
204
  <meta name="viewport" content="width=device-width, initial-scale=1">
205
- <title>CodeTAC — dossiês</title>
205
+ <title>CodeTAC — dossiers</title>
206
206
  <style>
207
207
  :root { --bg:#f7f7f5; --panel:#fff; --text:#1d1d1b; --muted:#6b6b66; --line:#e4e3de; --accent:#2f5bd3;
208
208
  --db:#0f7b5f; --http:#6a4bc4; --ia:#b4531f; --mail:#1f73b4; --pay:#9b2c86; --file:#7a6a12; --auth:#3d6b2f; --error:#c0392b; --code:#f1f0ec;