fg-tracker-mcp 0.9.1 → 0.11.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 (49) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +22 -10
  3. package/dist/cli.js +12 -7
  4. package/dist/cli.js.map +1 -1
  5. package/dist/client.d.ts +44 -4
  6. package/dist/client.js +80 -11
  7. package/dist/client.js.map +1 -1
  8. package/dist/database.js +1 -1
  9. package/dist/database.js.map +1 -1
  10. package/dist/diagnostics.d.ts +18 -0
  11. package/dist/diagnostics.js +467 -0
  12. package/dist/diagnostics.js.map +1 -0
  13. package/dist/docs.js +22 -22
  14. package/dist/docs.js.map +1 -1
  15. package/dist/format.d.ts +68 -3
  16. package/dist/format.js +113 -11
  17. package/dist/format.js.map +1 -1
  18. package/dist/guide.d.ts +1 -1
  19. package/dist/guide.js +27 -23
  20. package/dist/guide.js.map +1 -1
  21. package/dist/infra/handover.d.ts +1 -1
  22. package/dist/infra/handover.js +25 -23
  23. package/dist/infra/handover.js.map +1 -1
  24. package/dist/infra/iac.js +2 -2
  25. package/dist/infra/iac.js.map +1 -1
  26. package/dist/infra/instrument.js +5 -5
  27. package/dist/infra/instrument.js.map +1 -1
  28. package/dist/infra/tools.js +45 -32
  29. package/dist/infra/tools.js.map +1 -1
  30. package/dist/inputs.d.ts +40 -0
  31. package/dist/inputs.js +30 -0
  32. package/dist/inputs.js.map +1 -0
  33. package/dist/journeys.d.ts +71 -0
  34. package/dist/journeys.js +130 -0
  35. package/dist/journeys.js.map +1 -0
  36. package/dist/links.d.ts +87 -0
  37. package/dist/links.js +124 -0
  38. package/dist/links.js.map +1 -0
  39. package/dist/loadtest/scenario.js +1 -1
  40. package/dist/loadtest/scenario.js.map +1 -1
  41. package/dist/loadtest/tools.js +20 -11
  42. package/dist/loadtest/tools.js.map +1 -1
  43. package/dist/schemas.d.ts +621 -0
  44. package/dist/schemas.js +277 -0
  45. package/dist/schemas.js.map +1 -0
  46. package/dist/server.d.ts +21 -2
  47. package/dist/server.js +757 -147
  48. package/dist/server.js.map +1 -1
  49. package/package.json +3 -3
package/dist/docs.js CHANGED
@@ -6,13 +6,13 @@ export const QUICKSTART_URI = 'fg-tracker://docs/quickstart';
6
6
  /** @deprecated URI do `stread-track-mcp` ≤ 0.3; ainda registrada como alias, removida na 1.0. */
7
7
  export const LEGACY_QUICKSTART_URI = 'stread-track://docs/quickstart';
8
8
  export function quickstartMarkdown(endpoint) {
9
- return `# FG Track — quickstart
9
+ return `# FG Tracker — quickstart
10
10
 
11
11
  APM leve para Node: traces (Express/NestJS/Next.js/Fastify), queries pg, chamadas HTTP de saída, logs e detecção automática de **N+1**, **loops**, **endpoints lentos** e **erros**. API em \`${endpoint}\` (Swagger em \`${endpoint}/docs\`).
12
12
 
13
13
  ## 1. Projeto e chave
14
- - \`track_list_projects\` lista os projetos do usuário do token; \`track_create_project { name }\` cria um e devolve \`apiKey\` (\`stk_...\`).
15
- - \`track_update_allowed_origins { projectId, origins }\` substitui os domínios permitidos (CORS do SDK de navegador); leia a lista atual em \`track_list_projects\` e confirme com o usuário antes.
14
+ - \`tracker_list_projects\` lista os projetos do usuário do token; \`tracker_create_project { name }\` cria um e devolve \`apiKey\` (\`stk_...\`).
15
+ - \`tracker_update_allowed_origins { projectId, origins }\` substitui os domínios permitidos (CORS do SDK de navegador); leia a lista atual em \`tracker_list_projects\` e confirme com o usuário antes.
16
16
  - A chave vai no header \`x-fg-tracker-key\` da ingestão e em \`FG_TRACKER_KEY\` no app instrumentado.
17
17
 
18
18
  ## 2. SDK (\`fg-tracker-sdk\`)
@@ -26,7 +26,7 @@ const tracker = createTracker({
26
26
  });
27
27
  app.use(tracker.express()); // Express / NestJS — PRIMEIRO middleware (continua traceparent, lê req.user.id)
28
28
  app.use(routes); app.use(tracker.expressErrorHandler()); // exceção real no span → issues por causa, não por status
29
- tracker.instrumentPg(pool); // pg only; use track_detect_databases for other drivers // pg.Pool → spans db.query
29
+ tracker.instrumentPg(pool); // pg only; use tracker_detect_databases for other drivers // pg.Pool → spans db.query
30
30
  const fetchTracked = tracker.wrapFetch(); // fetch → spans http.client
31
31
  export const GET = tracker.wrapNextRoute(async (req) => Response.json({ ok: true })); // Next.js
32
32
  await tracker.span('custom', 'send-email', async (span) => { /* ... */ });
@@ -35,7 +35,7 @@ await tracker.checkIn('backup-diario', () => runBackup(), { intervalSeconds: 864
35
35
  await tracker.shutdown(); // no SIGTERM
36
36
  \`\`\`
37
37
  No deploy: \`npx fg-tracker-release --service minha-app --previous-sha $PREV\` registra a release com commits/arquivos (commits suspeitos nas issues, comparação de latência entre versões).
38
- Use \`track_instrumentation_guide { framework, projectId }\` para o passo a passo completo por framework com a chave real.
38
+ Use \`tracker_instrumentation_guide { framework, projectId }\` para o passo a passo completo por framework com a chave real.
39
39
 
40
40
  ## 3. Logs
41
41
  \`\`\`ts
@@ -64,13 +64,13 @@ curl -X POST ${endpoint}/v1/logs -H 'content-type: application/json' -H 'x-fg-tr
64
64
  Kinds de span: \`http.server\` (raiz por request), \`db.query\` (nome = SQL normalizado), \`http.client\`, \`custom\`.
65
65
 
66
66
  ## 5. Verificar e explorar
67
- - \`track_verify_ingest { projectId }\` — confirma spans/logs recentes.
68
- - \`track_get_overview { projectId, range }\` — requests, erro, p50/p95/p99, apdex, top lentos.
69
- - \`track_list_endpoints\`, \`track_list_issues\`, \`track_list_traces\` → \`track_get_trace { traceId }\` (waterfall).
70
- - \`track_search_logs { projectId, q, service, level, range }\` — sintaxe: texto livre, \`"frase"\`, \`key=value\`, \`~substring\`.
71
- - \`track_get_issue { projectId, issueId }\` — ocorrências, usuários afetados, releases, regressões e commits/PRs suspeitos.
72
- - \`track_list_releases { projectId, version? }\`, \`track_register_release\`, \`track_endpoint_history { projectId, name, days }\` — saúde por deploy e latência por rota ao longo do tempo.
73
- - \`track_list_providers { projectId, range }\` (chamadas de saída por host) e \`track_list_monitors { projectId }\` (uptime e jobs).
67
+ - \`tracker_verify_ingest { projectId }\` — confirma spans/logs recentes.
68
+ - \`tracker_get_overview { projectId, range }\` — requests, erro, p50/p95/p99, apdex, top lentos.
69
+ - \`tracker_list_endpoints\`, \`tracker_list_issues\`, \`tracker_list_traces\` → \`tracker_get_trace { traceId }\` (waterfall, 80 spans por página: \`spanOffset\`, filtros \`kind\`/\`service\`/\`name\`).
70
+ - \`tracker_search_logs { projectId, q, service, level, env, requestId, range }\` — sintaxe: texto livre, \`"frase"\`, \`key=value\`, \`~substring\`.
71
+ - \`tracker_get_issue { projectId, issueId }\` — ocorrências, usuários afetados, releases, regressões e commits/PRs suspeitos.
72
+ - \`tracker_list_releases { projectId, version? }\`, \`tracker_register_release\`, \`tracker_endpoint_history { projectId, name, days }\` — saúde por deploy e latência por rota ao longo do tempo.
73
+ - \`tracker_list_providers { projectId, range }\` (chamadas de saída por host) e \`tracker_list_monitors { projectId }\` (uptime e jobs) → \`tracker_get_monitor { projectId, monitorId }\` (histórico de checks com o trace de cada execução).
74
74
 
75
75
  ## 6. Detectores (rodam na ingestão)
76
76
  | tipo | regra |
@@ -82,7 +82,7 @@ Kinds de span: \`http.server\` (raiz por request), \`db.query\` (nome = SQL norm
82
82
  | ERROR | raiz com status ≥ 500 ou \`error != null\` |
83
83
 
84
84
  ## 7. Infraestrutura (AWS)
85
- Prompt \`connect-infrastructure\` guia o fluxo completo: o agente detecta sozinho contas, ambientes e regiões. Nenhuma tool altera recursos na AWS; a única mudança é o stack de conexão, criado com o comando devolvido e só com confirmação do usuário. Mudanças de infra só pelo FG Track, com aprovação humana.
85
+ Prompt \`connect-infrastructure\` guia o fluxo completo: o agente detecta sozinho contas, ambientes e regiões. Nenhuma tool altera recursos na AWS; a única mudança é o stack de conexão, criado com o comando devolvido e só com confirmação do usuário. Mudanças de infra só pelo FG Tracker, com aprovação humana.
86
86
  0. \`infra_detect_environments { profiles?, includeRegions? }\` — perfis do \`~/.aws\` → conta (STS), ambiente sugerido e regiões em uso (local, somente leitura).
87
87
  1. Por ambiente: \`infra_connect_account { projectId, level: 'read'|'operate', environment?, regions?, name?, profile? }\` → template \`./fg-tracker-connection-<ambiente>.json\` + \`aws cloudformation deploy ... --profile --region\` (confirmar com o usuário antes) → \`infra_verify_connection { projectId, connectionId, profile }\`.
88
88
  2. \`infra_discover { projectId, regions?, profile? }\` — inventário com credenciais locais (Resource Explorer/Tagging API + CloudFormation) enviado como snapshot.
@@ -98,9 +98,9 @@ Ranges aceitos: \`15m|1h|6h|24h|7d|30d\`.
98
98
  export function instrumentProjectPrompt(args, endpoint) {
99
99
  const fw = args.framework ? `O usuário indicou o framework **${args.framework}**; confirme lendo o código antes de seguir.` : 'O framework NÃO foi informado: detecte-o.';
100
100
  const proj = args.projectName
101
- ? `Use (ou crie) o projeto chamado **${args.projectName}** no FG Track.`
101
+ ? `Use (ou crie) o projeto chamado **${args.projectName}** no FG Tracker.`
102
102
  : 'Nenhum nome de projeto foi informado: use o nome do pacote (`package.json#name`) ou o nome do diretório.';
103
- return `Você vai conectar o projeto de código atual ao FG Track (APM em ${endpoint}) usando as tools deste servidor MCP. Trabalhe passo a passo, mostre o que fez em cada etapa e só avance quando a anterior estiver ok.
103
+ return `Você vai conectar o projeto de código atual ao FG Tracker (APM em ${endpoint}) usando as tools deste servidor MCP. Trabalhe passo a passo, mostre o que fez em cada etapa e só avance quando a anterior estiver ok.
104
104
 
105
105
  ${fw} ${proj}
106
106
 
@@ -108,20 +108,20 @@ ${fw} ${proj}
108
108
 
109
109
  1. **Detectar framework e logger.** Leia \`package.json\` (dependências: express, @nestjs/core, next, fastify; pino, winston; pg, drizzle-orm, kysely, knex) e o ponto de entrada (\`src/main.ts\`, \`src/index.ts\`, \`app/\`). Anote: framework HTTP, logger, os drivers e os pontos de criação dos clientes, gerenciador de pacotes (lockfile) e como o app é iniciado.
110
110
 
111
- 2. **Detectar bancos.** Chame \`track_detect_databases { projectPath, serviceName }\`. Confirme os imports e pontos de criação retornados; siga o adapter de cada driver ativo. Não suponha pg.Pool para Postgres.js, Prisma ou outro driver.
111
+ 2. **Detectar bancos.** Chame \`tracker_detect_databases { projectPath, serviceName }\`. Confirme os imports e pontos de criação retornados; siga o adapter de cada driver ativo. Não suponha pg.Pool para Postgres.js, Prisma ou outro driver.
112
112
 
113
- 2b. **Checar o FG Track.** Chame \`track_status\`. Se a API estiver fora do ar ou faltar \`FG_TRACKER_TOKEN\`, pare e explique ao usuário o que configurar.
113
+ 2b. **Checar o FG Tracker.** Chame \`tracker_status\`. Se a API estiver fora do ar ou faltar \`FG_TRACKER_TOKEN\`, pare e explique ao usuário o que configurar.
114
114
 
115
- 3. **Escolher ou criar o projeto.** Chame \`track_list_projects\`. Se já existe um projeto com o nome esperado, use-o; senão \`track_create_project { name }\`. Guarde \`projectId\` e \`apiKey\`. Nunca imprima a chave em commits/logs — só em \`.env\` (confira que \`.env\` está no \`.gitignore\`; adicione a variável em \`.env.example\` sem o valor).
115
+ 3. **Escolher ou criar o projeto.** Chame \`tracker_list_projects\`. Se já existe um projeto com o nome esperado, use-o; senão \`tracker_create_project { name }\`. Guarde \`projectId\` e \`apiKey\`. Nunca imprima a chave em commits/logs — só em \`.env\` (confira que \`.env\` está no \`.gitignore\`; adicione a variável em \`.env.example\` sem o valor).
116
116
 
117
- 4. **Obter o guia.** Chame \`track_instrumentation_guide { framework, projectId }\` para o framework detectado. Se o app tem pino ou winston, chame também com \`framework: "pino"\` ou \`"winston"\`.
117
+ 4. **Obter o guia.** Chame \`tracker_instrumentation_guide { framework, projectId }\` para o framework detectado. Se o app tem pino ou winston, chame também com \`framework: "pino"\` ou \`"winston"\`.
118
118
 
119
119
  5. **Instalar o SDK.** \`pnpm add fg-tracker-sdk\` (ou npm/yarn conforme o lockfile). Se o projeto já usa \`stread-track-sdk\`, troque pelo \`fg-tracker-sdk\` (mesma API).
120
120
 
121
121
  6. **Aplicar a instrumentação** seguindo o guia, com edits mínimos e idiomáticos ao projeto:
122
122
  - criar o tracker (um por processo) com \`apiKey\` de \`process.env.FG_TRACKER_KEY\` e \`endpoint\` de \`FG_TRACKER_URL\`;
123
123
  - registrar \`tracker.express()\` como PRIMEIRO middleware (Express/Nest), \`wrapNextRoute\` nos route handlers (Next) ou o hook \`onRequest\` (Fastify);
124
- - aplicar o adapter retornado por \`track_detect_databases\` ao cliente real antes de passá-lo ao ORM; para drivers desconhecidos envolver a conclusão da operação com \`traceDatabase\` ou \`traceDatabaseSync\`;
124
+ - aplicar o adapter retornado por \`tracker_detect_databases\` ao cliente real antes de passá-lo ao ORM; para drivers desconhecidos envolver a conclusão da operação com \`traceDatabase\` ou \`traceDatabaseSync\`;
125
125
  - \`tracker.wrapFetch()\` para chamadas HTTP de saída relevantes;
126
126
  - transport de logs (pino/winston/nest) com \`createLogShipper\`;
127
127
  - \`tracker.shutdown()\` no encerramento (SIGTERM / \`onApplicationShutdown\` / \`onClose\`).
@@ -130,11 +130,11 @@ ${fw} ${proj}
130
130
 
131
131
  8. **Rodar e gerar tráfego.** Inicie o app, faça algumas requisições reais (curl nas rotas principais, inclusive uma que consulte o banco) e aguarde ~3 s.
132
132
 
133
- 9. **Verificar.** Chame \`track_verify_ingest { projectId }\`. Se chegaram spans (e logs, quando configurados), mostre um resumo com \`track_get_overview { projectId, range: "15m" }\` e \`track_list_issues\`.
133
+ 9. **Verificar.** Chame \`tracker_verify_ingest { projectId }\`. Se chegaram spans (e logs, quando configurados), mostre um resumo com \`tracker_get_overview { projectId, range: "15m" }\` e \`tracker_list_issues\`.
134
134
 
135
135
  10. **Corrigir.** Se nada chegou: confira a chave (o SDK loga "4xx" uma vez quando ela é inválida), a ordem do middleware, se o tracker foi criado antes do app subir, se o processo consegue alcançar ${endpoint} (\`curl ${endpoint}/v1/health\`) e se há \`enabled: false\`. Ajuste e repita o passo 8.
136
136
 
137
- Ao final, liste os arquivos alterados, as variáveis adicionadas e o resultado de \`track_verify_ingest\`.`;
137
+ Ao final, liste os arquivos alterados, as variáveis adicionadas e o resultado de \`tracker_verify_ingest\`.`;
138
138
  }
139
139
  // Database driver detection must precede selection of an integration adapter.
140
140
  //# sourceMappingURL=docs.js.map
package/dist/docs.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"docs.js","sourceRoot":"","sources":["../src/docs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,8BAA8B,CAAC;AAC7D,iGAAiG;AACjG,MAAM,CAAC,MAAM,qBAAqB,GAAG,gCAAgC,CAAC;AAEtE,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO;;gMAEuL,QAAQ,oBAAoB,QAAQ;;;;;;;;;;;oDAWhL,QAAQ;;;;;;;;;;;;;;;;;;;;;wDAqBJ,QAAQ;;;;;;;;;eASjD,QAAQ;;;;;;;;eAQR,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCtB,CAAC;AACF,CAAC;AAOD,MAAM,UAAU,uBAAuB,CAAC,IAA0B,EAAE,QAAgB;IAClF,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,mCAAmC,IAAI,CAAC,SAAS,8CAA8C,CAAC,CAAC,CAAC,2CAA2C,CAAC;IAC1K,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW;QAC3B,CAAC,CAAC,qCAAqC,IAAI,CAAC,WAAW,iBAAiB;QACxE,CAAC,CAAC,0GAA0G,CAAC;IAE/G,OAAO,mEAAmE,QAAQ;;EAElF,EAAE,IAAI,IAAI;;;;;;;;;;;;;;;;;;;;;;;;wFAwB4E,QAAQ;;;;;;yMAMyG,QAAQ,YAAY,QAAQ;;0GAE3H,CAAC;AAC3G,CAAC;AAED,8EAA8E"}
1
+ {"version":3,"file":"docs.js","sourceRoot":"","sources":["../src/docs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,8BAA8B,CAAC;AAC7D,iGAAiG;AACjG,MAAM,CAAC,MAAM,qBAAqB,GAAG,gCAAgC,CAAC;AAEtE,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO;;gMAEuL,QAAQ,oBAAoB,QAAQ;;;;;;;;;;;oDAWhL,QAAQ;;;;;;;;;;;;;;;;;;;;;wDAqBJ,QAAQ;;;;;;;;;eASjD,QAAQ;;;;;;;;eAQR,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCtB,CAAC;AACF,CAAC;AAOD,MAAM,UAAU,uBAAuB,CAAC,IAA0B,EAAE,QAAgB;IAClF,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,mCAAmC,IAAI,CAAC,SAAS,8CAA8C,CAAC,CAAC,CAAC,2CAA2C,CAAC;IAC1K,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW;QAC3B,CAAC,CAAC,qCAAqC,IAAI,CAAC,WAAW,mBAAmB;QAC1E,CAAC,CAAC,0GAA0G,CAAC;IAE/G,OAAO,qEAAqE,QAAQ;;EAEpF,EAAE,IAAI,IAAI;;;;;;;;;;;;;;;;;;;;;;;;wFAwB4E,QAAQ;;;;;;yMAMyG,QAAQ,YAAY,QAAQ;;4GAEzH,CAAC;AAC7G,CAAC;AAED,8EAA8E"}
package/dist/format.d.ts CHANGED
@@ -1,27 +1,92 @@
1
+ /** Link para um recurso (MCP `resource_link`): o painel ou um `fg-tracker://…` legível pelo servidor. */
2
+ export interface ResourceLink {
3
+ type: 'resource_link';
4
+ uri: string;
5
+ name: string;
6
+ title?: string;
7
+ description?: string;
8
+ mimeType?: string;
9
+ }
1
10
  export interface ToolText {
2
11
  [x: string]: unknown;
3
12
  content: Array<{
4
13
  type: 'text';
5
14
  text: string;
6
- }>;
15
+ } | ResourceLink>;
16
+ structuredContent?: Record<string, unknown>;
7
17
  isError?: boolean;
8
18
  }
9
19
  export declare const MAX_SERIES_POINTS = 48;
20
+ /** Arrays internos (amostras, ocorrências, checks dentro de um objeto). */
10
21
  export declare const MAX_LIST_ITEMS = 25;
11
22
  export declare const MAX_TRACE_SPANS = 80;
23
+ /** Default de FG_TRACKER_MAX_ITEMS: teto da lista principal de uma ferramenta. */
24
+ export declare const DEFAULT_MAX_ITEMS = 200;
25
+ /** Maior valor aceito em FG_TRACKER_MAX_ITEMS e nos `limit` sem teto próprio da API. */
26
+ export declare const MAX_ITEMS_CEILING = 1000;
27
+ /** Linhas de prévia no texto de uma lista longa; o JSON que segue traz todos os itens. */
28
+ export declare const PREVIEW_LINES = 25;
12
29
  export declare function text(value: string): ToolText;
13
30
  export declare function json(value: unknown, preface?: string): ToolText;
31
+ /**
32
+ * Resultado com `structuredContent` (o que o `outputSchema` descreve) e o texto de sempre:
33
+ * o resumo e, depois de uma linha em branco, o JSON de `body` (default: o próprio `data`).
34
+ * `body` existe para manter o JSON antigo do texto quando o estruturado mudou de forma
35
+ * (ex.: lista que virou `{ items }`). `body: null` deixa só o resumo.
36
+ */
37
+ export declare function structured(data: Record<string, unknown>, summary: string, options?: {
38
+ body?: unknown;
39
+ links?: ResourceLink[];
40
+ }): ToolText;
14
41
  export declare function errorResult(err: unknown): ToolText;
15
42
  /** Executa `fn` e converte qualquer exceção em resultado `isError`. */
16
43
  export declare function guard(fn: () => Promise<ToolText>): Promise<ToolText>;
17
- /** Reduz uma série mantendo a distribuição (amostragem uniforme). */
44
+ /**
45
+ * Reduz uma série a `max` pontos por amostragem uniforme, sempre com o primeiro e o
46
+ * último: numa série em ordem de tempo, o ponto mais recente nunca fica de fora.
47
+ */
18
48
  export declare function sampleSeries<T>(series: T[], max?: number): T[];
19
49
  export declare function truncateList<T>(list: T[], max?: number): {
20
50
  items: T[];
21
51
  truncated: number;
22
52
  };
23
- /** Compacta recursivamente: `series` viram amostras, arrays longos são cortados. */
53
+ export interface MaxItemsSetting {
54
+ value: number;
55
+ /** Presente quando FG_TRACKER_MAX_ITEMS foi ignorado ou reduzido. */
56
+ warning?: string;
57
+ }
58
+ /** Teto da lista principal: FG_TRACKER_MAX_ITEMS (inteiro de 1 a 1000, default 200). */
59
+ export declare function maxItemsFromEnv(env?: NodeJS.ProcessEnv): MaxItemsSetting;
60
+ /** Limite efetivo da lista principal: o `limit` pedido, até `maxItems`. */
61
+ export declare function clampLimit(requested: number, maxItems: number): {
62
+ limit: number;
63
+ capped: boolean;
64
+ };
65
+ /** Aviso para quando `clampLimit` reduziu o pedido. */
66
+ export declare function cappedNote(requested: number, limit: number): string;
67
+ export interface ListPage {
68
+ total: number;
69
+ returned: number;
70
+ truncated: boolean;
71
+ items: unknown[];
72
+ }
73
+ /** Prévia em texto de uma lista: até PREVIEW_LINES linhas e, se cortou, onde está o resto. */
74
+ export declare function preview(lines: string[]): string;
75
+ /**
76
+ * Lista principal de uma API sem paginação: os primeiros `limit` itens (cada um
77
+ * compactado) e quanto ficou de fora. Não há cursor: para ver o resto, aumente
78
+ * `limit` ou filtre.
79
+ */
80
+ export declare function listPage(list: unknown[], limit: number): ListPage;
81
+ /**
82
+ * Compacta recursivamente: `series` viram amostras e arrays internos de um objeto
83
+ * ficam com até 25 itens (`<campo>Omitted` diz quantos saíram). Um array passado
84
+ * direto também é cortado em 25; a lista principal de uma ferramenta deve ser
85
+ * limitada antes (API ou `listPage`) e compactada item a item.
86
+ */
24
87
  export declare function compact(value: unknown, depth?: number): unknown;
25
88
  export declare function ms(value: number | null | undefined): string;
26
89
  export declare function pct(value: number | null | undefined): string;
90
+ /** Tempo até `iso` ("em 3.5 d"); no passado vira `ago`. */
91
+ export declare function until(iso: string, now?: number): string;
27
92
  export declare function ago(iso: string, now?: number): string;
package/dist/format.js CHANGED
@@ -1,19 +1,48 @@
1
1
  /**
2
- * Helpers de saída: compactação de payloads grandes (mesma regra do §7 do
3
- * contrato — séries ≤ 48 pontos, listas ≤ 25 itens, traces ≤ 80 spans) e
4
- * conversão para o formato de resultado do MCP.
2
+ * Helpers de saída: compactação de payloads grandes e conversão para o formato
3
+ * de resultado do MCP. Regras (docs/mcp.md, "Limites de saída"):
4
+ * - lista principal de uma ferramenta: respeita `limit` até FG_TRACKER_MAX_ITEMS
5
+ * (default 200, teto 1000), cortada na API (cursor) ou por `listPage`, sempre
6
+ * com metadados de truncamento;
7
+ * - arrays internos de um objeto: ≤ 25 itens, com `<campo>Omitted`;
8
+ * - séries ≤ 48 pontos, amostradas por igual e sempre com o primeiro e o último
9
+ * (o período recente nunca some); `markers` ficam com os 25 mais recentes;
10
+ * - traces ≤ 80 spans por página (tracker_get_trace pagina).
11
+ *
12
+ * Toda ferramenta de leitura devolve também `structuredContent` (validado contra o
13
+ * `outputSchema` da ferramenta), com o texto de antes mantido para compatibilidade.
5
14
  */
6
- import { TrackApiError } from './client.js';
15
+ import { TrackApiError, readEnv } from './client.js';
7
16
  export const MAX_SERIES_POINTS = 48;
17
+ /** Arrays internos (amostras, ocorrências, checks dentro de um objeto). */
8
18
  export const MAX_LIST_ITEMS = 25;
9
19
  export const MAX_TRACE_SPANS = 80;
20
+ /** Default de FG_TRACKER_MAX_ITEMS: teto da lista principal de uma ferramenta. */
21
+ export const DEFAULT_MAX_ITEMS = 200;
22
+ /** Maior valor aceito em FG_TRACKER_MAX_ITEMS e nos `limit` sem teto próprio da API. */
23
+ export const MAX_ITEMS_CEILING = 1000;
24
+ /** Linhas de prévia no texto de uma lista longa; o JSON que segue traz todos os itens. */
25
+ export const PREVIEW_LINES = 25;
26
+ /** Acima disso o JSON sai sem indentação: a mesma lista ocupa bem menos da saída do cliente MCP. */
27
+ const PRETTY_JSON_MAX_CHARS = 20_000;
10
28
  export function text(value) {
11
29
  return { content: [{ type: 'text', text: value }] };
12
30
  }
13
31
  export function json(value, preface) {
14
- const body = JSON.stringify(value, null, 2);
32
+ const pretty = JSON.stringify(value, null, 2);
33
+ const body = pretty !== undefined && pretty.length > PRETTY_JSON_MAX_CHARS ? JSON.stringify(value) : pretty;
15
34
  return text(preface ? `${preface}\n\n${body}` : body);
16
35
  }
36
+ /**
37
+ * Resultado com `structuredContent` (o que o `outputSchema` descreve) e o texto de sempre:
38
+ * o resumo e, depois de uma linha em branco, o JSON de `body` (default: o próprio `data`).
39
+ * `body` existe para manter o JSON antigo do texto quando o estruturado mudou de forma
40
+ * (ex.: lista que virou `{ items }`). `body: null` deixa só o resumo.
41
+ */
42
+ export function structured(data, summary, options = {}) {
43
+ const base = options.body === null ? text(summary) : json(options.body === undefined ? data : options.body, summary);
44
+ return { ...base, content: [...base.content, ...(options.links ?? [])], structuredContent: data };
45
+ }
17
46
  export function errorResult(err) {
18
47
  const message = err instanceof TrackApiError ? err.describe() : err instanceof Error ? err.message : String(err);
19
48
  return { content: [{ type: 'text', text: message }], isError: true };
@@ -27,14 +56,18 @@ export async function guard(fn) {
27
56
  return errorResult(err);
28
57
  }
29
58
  }
30
- /** Reduz uma série mantendo a distribuição (amostragem uniforme). */
59
+ /**
60
+ * Reduz uma série a `max` pontos por amostragem uniforme, sempre com o primeiro e o
61
+ * último: numa série em ordem de tempo, o ponto mais recente nunca fica de fora.
62
+ */
31
63
  export function sampleSeries(series, max = MAX_SERIES_POINTS) {
32
64
  if (series.length <= max)
33
65
  return series;
34
- const step = series.length / max;
66
+ if (max <= 1)
67
+ return series.slice(-1);
35
68
  const out = [];
36
69
  for (let i = 0; i < max; i++) {
37
- const item = series[Math.floor(i * step)];
70
+ const item = series[Math.round((i * (series.length - 1)) / (max - 1))];
38
71
  if (item !== undefined)
39
72
  out.push(item);
40
73
  }
@@ -45,7 +78,50 @@ export function truncateList(list, max = MAX_LIST_ITEMS) {
45
78
  return { items: list, truncated: 0 };
46
79
  return { items: list.slice(0, max), truncated: list.length - max };
47
80
  }
48
- /** Compacta recursivamente: `series` viram amostras, arrays longos são cortados. */
81
+ /** Teto da lista principal: FG_TRACKER_MAX_ITEMS (inteiro de 1 a 1000, default 200). */
82
+ export function maxItemsFromEnv(env = process.env) {
83
+ const raw = readEnv('MAX_ITEMS', env);
84
+ if (raw === undefined)
85
+ return { value: DEFAULT_MAX_ITEMS };
86
+ const parsed = Number(raw);
87
+ if (!/^\d+$/.test(raw) || !Number.isSafeInteger(parsed) || parsed < 1) {
88
+ return { value: DEFAULT_MAX_ITEMS, warning: `FG_TRACKER_MAX_ITEMS="${raw.slice(0, 20)}" é inválido (use um inteiro de 1 a ${MAX_ITEMS_CEILING}); usando ${DEFAULT_MAX_ITEMS}.` };
89
+ }
90
+ if (parsed > MAX_ITEMS_CEILING)
91
+ return { value: MAX_ITEMS_CEILING, warning: `FG_TRACKER_MAX_ITEMS=${parsed} passa do teto; usando ${MAX_ITEMS_CEILING}.` };
92
+ return { value: parsed };
93
+ }
94
+ /** Limite efetivo da lista principal: o `limit` pedido, até `maxItems`. */
95
+ export function clampLimit(requested, maxItems) {
96
+ return requested > maxItems ? { limit: maxItems, capped: true } : { limit: requested, capped: false };
97
+ }
98
+ /** Aviso para quando `clampLimit` reduziu o pedido. */
99
+ export function cappedNote(requested, limit) {
100
+ return requested > limit ? ` limit ${requested} reduzido para ${limit} por FG_TRACKER_MAX_ITEMS.` : '';
101
+ }
102
+ /** Prévia em texto de uma lista: até PREVIEW_LINES linhas e, se cortou, onde está o resto. */
103
+ export function preview(lines) {
104
+ if (lines.length <= PREVIEW_LINES)
105
+ return lines.join('\n');
106
+ return [...lines.slice(0, PREVIEW_LINES), `… prévia de ${PREVIEW_LINES} de ${lines.length}; todos os ${lines.length} estão no JSON abaixo.`].join('\n');
107
+ }
108
+ /**
109
+ * Lista principal de uma API sem paginação: os primeiros `limit` itens (cada um
110
+ * compactado) e quanto ficou de fora. Não há cursor: para ver o resto, aumente
111
+ * `limit` ou filtre.
112
+ */
113
+ export function listPage(list, limit) {
114
+ const items = list.slice(0, limit).map((item) => compact(item));
115
+ return { total: list.length, returned: items.length, truncated: items.length < list.length, items };
116
+ }
117
+ /** Campos que são séries temporais em ordem crescente (`points` = histórico de uma rota). */
118
+ const SERIES_KEYS = new Set(['series', 'seriesQueriesPerMin', 'histogram', 'points']);
119
+ /**
120
+ * Compacta recursivamente: `series` viram amostras e arrays internos de um objeto
121
+ * ficam com até 25 itens (`<campo>Omitted` diz quantos saíram). Um array passado
122
+ * direto também é cortado em 25; a lista principal de uma ferramenta deve ser
123
+ * limitada antes (API ou `listPage`) e compactada item a item.
124
+ */
49
125
  export function compact(value, depth = 0) {
50
126
  if (Array.isArray(value)) {
51
127
  const { items, truncated } = truncateList(value);
@@ -55,10 +131,16 @@ export function compact(value, depth = 0) {
55
131
  if (value && typeof value === 'object') {
56
132
  const out = {};
57
133
  for (const [k, v] of Object.entries(value)) {
58
- if ((k === 'series' || k === 'seriesQueriesPerMin' || k === 'histogram') && Array.isArray(v)) {
134
+ if (SERIES_KEYS.has(k) && Array.isArray(v)) {
59
135
  out[k] = sampleSeries(v);
60
136
  if (v.length > MAX_SERIES_POINTS)
61
- out[`${k}Points`] = `${v.length} pontos, amostrados para ${MAX_SERIES_POINTS}`;
137
+ out[`${k}Points`] = `${v.length} pontos, amostrados para ${MAX_SERIES_POINTS} (inclui o primeiro e o último)`;
138
+ }
139
+ else if (k === 'markers' && Array.isArray(v)) {
140
+ // Marcadores de deploy em ordem de tempo: os mais recentes são os que importam.
141
+ out[k] = v.slice(-MAX_LIST_ITEMS).map((item) => compact(item, depth + 1));
142
+ if (v.length > MAX_LIST_ITEMS)
143
+ out.markersOmitted = v.length - MAX_LIST_ITEMS;
62
144
  }
63
145
  else if (k === 'spans' && Array.isArray(v)) {
64
146
  const { items, truncated } = truncateList(v, MAX_TRACE_SPANS);
@@ -69,6 +151,12 @@ export function compact(value, depth = 0) {
69
151
  else if (k === 'sparkline' && Array.isArray(v)) {
70
152
  out[k] = v; // 24 pontos, já pequeno
71
153
  }
154
+ else if (Array.isArray(v)) {
155
+ const { items, truncated } = truncateList(v);
156
+ out[k] = items.map((item) => compact(item, depth + 1));
157
+ if (truncated > 0)
158
+ out[`${k}Omitted`] = truncated;
159
+ }
72
160
  else {
73
161
  out[k] = compact(v, depth + 1);
74
162
  }
@@ -87,6 +175,20 @@ export function pct(value) {
87
175
  return '—';
88
176
  return `${(value * 100).toFixed(2)}%`;
89
177
  }
178
+ /** Tempo até `iso` ("em 3.5 d"); no passado vira `ago`. */
179
+ export function until(iso, now = Date.now()) {
180
+ const t = Date.parse(iso);
181
+ if (Number.isNaN(t))
182
+ return iso;
183
+ if (t <= now)
184
+ return ago(iso, now);
185
+ const s = Math.round((t - now) / 1000);
186
+ if (s < 3600)
187
+ return `em ${Math.max(1, Math.round(s / 60))} min`;
188
+ if (s < 86400)
189
+ return `em ${(s / 3600).toFixed(1)} h`;
190
+ return `em ${(s / 86400).toFixed(1)} d`;
191
+ }
90
192
  export function ago(iso, now = Date.now()) {
91
193
  const t = Date.parse(iso);
92
194
  if (Number.isNaN(t))
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
package/dist/guide.d.ts CHANGED
@@ -8,7 +8,7 @@ export type Framework = (typeof FRAMEWORKS)[number];
8
8
  export interface GuideInput {
9
9
  framework: Framework;
10
10
  databaseDriver?: string;
11
- /** URL base da API do FG Track (endpoint do SDK). */
11
+ /** URL base da API do FG Tracker (endpoint do SDK). */
12
12
  endpoint: string;
13
13
  /** Chave do projeto; sem ela usa placeholder. */
14
14
  apiKey?: string;
package/dist/guide.js CHANGED
@@ -6,7 +6,7 @@
6
6
  export const FRAMEWORKS = ['express', 'nestjs', 'nextjs', 'fastify', 'pino', 'winston'];
7
7
  const PLACEHOLDER_KEY = 'stk_SUA_CHAVE_AQUI';
8
8
  function envBlock(input) {
9
- const key = input.apiKey ?? PLACEHOLDER_KEY;
9
+ const key = input.apiKey || PLACEHOLDER_KEY;
10
10
  return [
11
11
  '```bash',
12
12
  '# .env (não commitar a chave)',
@@ -23,18 +23,22 @@ function install(extra = []) {
23
23
  `# npm install ${pkgs} | yarn add ${pkgs}`,
24
24
  '```',
25
25
  '',
26
- '> Dentro do monorepo do FG Track use `"fg-tracker-sdk": "workspace:*"`. Projetos que já usam `stread-track-sdk` só trocam o nome do pacote nos imports (mesma API; as variáveis `STREAD_TRACK_*` continuam lidas como fallback).',
26
+ '> Dentro do monorepo do FG Tracker use `"fg-tracker-sdk": "workspace:*"`. Projetos que já usam `stread-track-sdk` só trocam o nome do pacote nos imports (mesma API; as variáveis `STREAD_TRACK_*` continuam lidas como fallback).',
27
27
  ].join('\n');
28
28
  }
29
29
  function header(input, title) {
30
30
  const lines = [`# ${title}`, ''];
31
- if (input.projectName && input.projectId) {
31
+ if (input.projectName && input.projectId && !input.apiKey) {
32
+ // Token de leitura (fgt_…) ou papel viewer: a API devolve apiKey ''.
33
+ lines.push(`Projeto: **${input.projectName}** (\`${input.projectId}\`). A API não devolveu a chave de ingestão (token de leitura \`fgt_…\` ou papel viewer): o código usa o placeholder \`${PLACEHOLDER_KEY}\`. Peça ao usuário para copiar \`FG_TRACKER_KEY\` no painel, em Conectar.`);
34
+ }
35
+ else if (input.projectName && input.projectId) {
32
36
  lines.push(`Projeto: **${input.projectName}** (\`${input.projectId}\`). A chave abaixo é a chave real deste projeto — trate como segredo.`);
33
37
  }
34
38
  else {
35
- lines.push(`Nenhum projeto informado: o código usa o placeholder \`${PLACEHOLDER_KEY}\`. Crie um projeto com \`track_create_project { name }\` (ou use \`track_list_projects\`) e chame este guia de novo com \`projectId\` para receber a chave real.`);
39
+ lines.push(`Nenhum projeto informado: o código usa o placeholder \`${PLACEHOLDER_KEY}\`. Crie um projeto com \`tracker_create_project { name }\` (ou use \`tracker_list_projects\`) e chame este guia de novo com \`projectId\` para receber a chave real.`);
36
40
  }
37
- lines.push('', `API do FG Track: \`${input.endpoint}\`.`, '');
41
+ lines.push('', `API do FG Tracker: \`${input.endpoint}\`.`, '');
38
42
  return lines.join('\n');
39
43
  }
40
44
  function trackerFile(input, path, service) {
@@ -44,7 +48,7 @@ function trackerFile(input, path, service) {
44
48
  `import { createTracker } from 'fg-tracker-sdk';`,
45
49
  ``,
46
50
  `export const tracker = createTracker({`,
47
- ` apiKey: process.env.FG_TRACKER_KEY!, // ${input.apiKey ?? PLACEHOLDER_KEY}`,
51
+ ` apiKey: process.env.FG_TRACKER_KEY!, // ${input.apiKey || PLACEHOLDER_KEY}`,
48
52
  ` endpoint: process.env.FG_TRACKER_URL ?? '${input.endpoint}',`,
49
53
  ` serviceName: '${service}',`,
50
54
  ` flushIntervalMs: 2000,`,
@@ -76,7 +80,7 @@ const FETCH_BLOCK = [
76
80
  '```',
77
81
  ].join('\n');
78
82
  function logsSection(input, service, logger) {
79
- const key = input.apiKey ?? PLACEHOLDER_KEY;
83
+ const key = input.apiKey || PLACEHOLDER_KEY;
80
84
  const shipper = [
81
85
  '```ts',
82
86
  '// src/logs.ts — um shipper por processo; correlaciona traceId/spanId automaticamente',
@@ -127,7 +131,7 @@ function logsSection(input, service, logger) {
127
131
  ' format: winston.format.json(),',
128
132
  ' transports: [',
129
133
  ' new winston.transports.Console(),',
130
- ' winstonTransport(logShipper), // envia cada log ao FG Track',
134
+ ' winstonTransport(logShipper), // envia cada log ao FG Tracker',
131
135
  ' ],',
132
136
  '});',
133
137
  '```',
@@ -153,9 +157,9 @@ function logsSection(input, service, logger) {
153
157
  else if (logger === 'winston')
154
158
  parts.push(winston);
155
159
  else if (logger === 'nest')
156
- parts.push(nest, '', 'Se o app usa pino ou winston, chame `track_instrumentation_guide { framework: "pino" | "winston" }` para o transport correspondente.');
160
+ parts.push(nest, '', 'Se o app usa pino ou winston, chame `tracker_instrumentation_guide { framework: "pino" | "winston" }` para o transport correspondente.');
157
161
  else
158
- parts.push(raw, '', 'Com pino ou winston, chame `track_instrumentation_guide { framework: "pino" | "winston" }` para o transport pronto.');
162
+ parts.push(raw, '', 'Com pino ou winston, chame `tracker_instrumentation_guide { framework: "pino" | "winston" }` para o transport pronto.');
159
163
  parts.push('', 'Contrato (§11): o shipper envia lotes para `POST /v1/logs` com o header `x-fg-tracker-key`; níveis `trace|debug|info|warn|error|fatal`; `traceId`/`spanId` são preenchidos automaticamente quando o log acontece dentro de um request instrumentado pelo tracker. Se os exports `fg-tracker-sdk/pino` e `fg-tracker-sdk/winston` ainda não existirem na versão instalada do SDK, envie os logs direto para `POST /v1/logs` (veja o resource `fg-tracker://docs/quickstart`).');
160
164
  return parts.join('\n');
161
165
  }
@@ -167,14 +171,14 @@ function verifySection(input) {
167
171
  '2. Aguarde ~3 s (flush a cada 2 s).',
168
172
  ];
169
173
  if (input.projectId) {
170
- lines.push(`3. Chame \`track_verify_ingest { projectId: "${input.projectId}" }\` — deve reportar spans (e logs) recentes.`);
174
+ lines.push(`3. Chame \`tracker_verify_ingest { projectId: "${input.projectId}" }\` — deve reportar spans (e logs) recentes.`);
171
175
  }
172
176
  else {
173
- lines.push('3. Chame `track_verify_ingest { projectId }` — deve reportar spans (e logs) recentes.');
177
+ lines.push('3. Chame `tracker_verify_ingest { projectId }` — deve reportar spans (e logs) recentes.');
174
178
  }
175
179
  lines.push('4. Se nada chegou: confira `FG_TRACKER_KEY` (4xx no envio = chave inválida, o SDK loga uma vez), se a API responde em `' +
176
180
  input.endpoint +
177
- '/v1/health`, e se `app.use(tracker.express())` é o PRIMEIRO middleware.', '', 'Depois, `track_get_overview`, `track_list_endpoints` e `track_list_issues` mostram o que foi coletado.');
181
+ '/v1/health`, e se `app.use(tracker.express())` é o PRIMEIRO middleware.', '', 'Depois, `tracker_get_overview`, `tracker_list_endpoints` e `tracker_list_issues` mostram o que foi coletado.');
178
182
  return lines.join('\n');
179
183
  }
180
184
  export function buildGuide(input) {
@@ -182,7 +186,7 @@ export function buildGuide(input) {
182
186
  switch (input.framework) {
183
187
  case 'express':
184
188
  return [
185
- header(input, 'Instrumentar Express com FG Track'),
189
+ header(input, 'Instrumentar Express com FG Tracker'),
186
190
  '## 1. Instalar',
187
191
  install(),
188
192
  '',
@@ -226,7 +230,7 @@ export function buildGuide(input) {
226
230
  ].join('\n');
227
231
  case 'nestjs':
228
232
  return [
229
- header(input, 'Instrumentar NestJS (platform-express) com FG Track'),
233
+ header(input, 'Instrumentar NestJS (platform-express) com FG Tracker'),
230
234
  '## 1. Instalar',
231
235
  install(),
232
236
  '',
@@ -243,7 +247,7 @@ export function buildGuide(input) {
243
247
  "import { AppModule } from './app.module';",
244
248
  '',
245
249
  'export const tracker = createTracker({',
246
- ` apiKey: process.env.FG_TRACKER_KEY!, // ${input.apiKey ?? PLACEHOLDER_KEY}`,
250
+ ` apiKey: process.env.FG_TRACKER_KEY!, // ${input.apiKey || PLACEHOLDER_KEY}`,
247
251
  ` endpoint: process.env.FG_TRACKER_URL ?? '${input.endpoint}',`,
248
252
  ` serviceName: '${service}',`,
249
253
  '});',
@@ -297,7 +301,7 @@ export function buildGuide(input) {
297
301
  ].join('\n');
298
302
  case 'nextjs':
299
303
  return [
300
- header(input, 'Instrumentar Next.js (App Router, runtime Node) com FG Track'),
304
+ header(input, 'Instrumentar Next.js (App Router, runtime Node) com FG Tracker'),
301
305
  '## 1. Instalar',
302
306
  install(),
303
307
  '',
@@ -315,7 +319,7 @@ export function buildGuide(input) {
315
319
  'export const tracker: Tracker =',
316
320
  ' g.__fgTracker ??',
317
321
  ' (g.__fgTracker = createTracker({',
318
- ` apiKey: process.env.FG_TRACKER_KEY!, // ${input.apiKey ?? PLACEHOLDER_KEY}`,
322
+ ` apiKey: process.env.FG_TRACKER_KEY!, // ${input.apiKey || PLACEHOLDER_KEY}`,
319
323
  ` endpoint: process.env.FG_TRACKER_URL ?? '${input.endpoint}',`,
320
324
  ` serviceName: '${service}',`,
321
325
  ' }));',
@@ -374,7 +378,7 @@ export function buildGuide(input) {
374
378
  ].join('\n');
375
379
  case 'fastify':
376
380
  return [
377
- header(input, 'Instrumentar Fastify com FG Track'),
381
+ header(input, 'Instrumentar Fastify com FG Tracker'),
378
382
  'O SDK não tem plugin Fastify dedicado; o middleware Express funciona num hook `onRequest` sobre `request.raw`/`reply.raw` (o hook chama `done` dentro do contexto assíncrono do span, então `instrumentPg`, `wrapFetch` e `tracker.span` enxergam o request).',
379
383
  '',
380
384
  '## 1. Instalar',
@@ -447,7 +451,7 @@ export function buildGuide(input) {
447
451
  ].join('\n');
448
452
  case 'pino':
449
453
  return [
450
- header(input, 'Enviar logs do pino para o FG Track'),
454
+ header(input, 'Enviar logs do pino para o FG Tracker'),
451
455
  '## 1. Instalar',
452
456
  install(),
453
457
  '',
@@ -459,7 +463,7 @@ export function buildGuide(input) {
459
463
  '## 4. Correlação com traces',
460
464
  'Se o processo também usa o tracker (`createTracker` + `tracker.express()`), cada log emitido durante um request ganha `traceId`/`spanId` e aparece com link para o trace no console. Sem tracker, os logs chegam normalmente, só sem correlação.',
461
465
  '',
462
- '## 5. Sintaxe de busca (`track_search_logs` e página /logs)',
466
+ '## 5. Sintaxe de busca (`tracker_search_logs` e página /logs)',
463
467
  '- texto livre → busca full-text (`websearch_to_tsquery`); `"frase exata"` entre aspas;',
464
468
  '- `key=value` → filtra `context->>key`;',
465
469
  '- `~trecho` → ILIKE (substring, via trigram).',
@@ -468,7 +472,7 @@ export function buildGuide(input) {
468
472
  ].join('\n');
469
473
  case 'winston':
470
474
  return [
471
- header(input, 'Enviar logs do winston para o FG Track'),
475
+ header(input, 'Enviar logs do winston para o FG Tracker'),
472
476
  '## 1. Instalar',
473
477
  install(),
474
478
  '',
@@ -480,7 +484,7 @@ export function buildGuide(input) {
480
484
  '## 4. Correlação com traces',
481
485
  'Se o processo também usa o tracker (`createTracker` + `tracker.express()`), cada log emitido durante um request ganha `traceId`/`spanId`. Chame `logShipper.flush()` (ou `tracker.shutdown()` + `logShipper.shutdown()`) no encerramento para não perder o último lote.',
482
486
  '',
483
- '## 5. Sintaxe de busca (`track_search_logs` e página /logs)',
487
+ '## 5. Sintaxe de busca (`tracker_search_logs` e página /logs)',
484
488
  '- texto livre → full-text; `"frase exata"` entre aspas; `key=value` → `context->>key`; `~trecho` → substring.',
485
489
  '',
486
490
  verifySection(input),