@neetru/cli 2.5.0 → 2.6.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,359 @@
1
+ /**
2
+ * `neetru ops` — comandos de operação interna do Neetru Core.
3
+ *
4
+ * Substitui os scripts ad-hoc em scripts/ com interface consistente, autenticação
5
+ * via Bearer token e flags --dry-run onde há mutação.
6
+ *
7
+ * Namespace ops:
8
+ * neetru ops heartbeat — checar heartbeat do agente em um server
9
+ * neetru ops smoke notification — dispara notification de smoke end-to-end
10
+ * neetru ops smoke observability — smoke test do pipeline de observability
11
+ * neetru ops reg-token <serverId> — gerar registration token para um server
12
+ * neetru ops resolve-errors — resolver erros abertos em lote
13
+ * neetru ops openapi-diff — detectar breaking changes na spec OpenAPI
14
+ *
15
+ * TODO (próximo sprint): bootstrap-admin, backfill incidents-source, backfill workspaces,
16
+ * seed api-catalog, rehash-sdk-secrets, migrate cli-keys.
17
+ */
18
+ import chalk from 'chalk';
19
+ import ora from 'ora';
20
+ import { apiRequest } from '../lib/api-client.js';
21
+ import { requireToken, handleApiError } from '../lib/cli-read.js';
22
+ import { log } from '../utils/logger.js';
23
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
24
+ function deprecationBanner(scriptName, command) {
25
+ console.warn(chalk.yellow(`[aviso] scripts/${scriptName} está deprecado. Use: neetru ${command}`));
26
+ }
27
+ export async function runOpsHeartbeat(opts) {
28
+ const token = await requireToken(opts.json);
29
+ const serverId = opts.serverId ?? 'srv-test-01';
30
+ const spinner = opts.json ? null : ora({ text: `Verificando heartbeat de ${serverId}…`, color: 'blue' }).start();
31
+ let res;
32
+ try {
33
+ res = await apiRequest(`/api/cli/v1/ops/heartbeat?serverId=${encodeURIComponent(serverId)}`, { token });
34
+ spinner?.stop();
35
+ }
36
+ catch (error) {
37
+ spinner?.fail('Falha ao verificar heartbeat.');
38
+ handleApiError(error, opts.json);
39
+ }
40
+ if (opts.json) {
41
+ console.log(JSON.stringify(res));
42
+ return;
43
+ }
44
+ const data = res;
45
+ const exists = data.exists;
46
+ if (!exists) {
47
+ console.log(chalk.red(` server/${serverId} NÃO ENCONTRADO`));
48
+ return;
49
+ }
50
+ const fields = data.fields;
51
+ console.log(chalk.bold(`=== servers/${serverId} ===`));
52
+ if (fields) {
53
+ for (const [k, v] of Object.entries(fields).sort()) {
54
+ console.log(` ${chalk.cyan(k)}: ${JSON.stringify(v)}`);
55
+ }
56
+ }
57
+ }
58
+ export async function runOpsSmokeNotification(opts) {
59
+ const token = await requireToken(opts.json);
60
+ const body = {
61
+ recipientRole: opts.recipientRole ?? 'admin',
62
+ recipientUid: opts.recipientUid,
63
+ kind: opts.kind ?? 'smoke_test',
64
+ title: opts.title,
65
+ link: opts.link ?? '/dashboard',
66
+ };
67
+ const spinner = opts.json ? null : ora({ text: 'Disparando smoke notification…', color: 'blue' }).start();
68
+ let res;
69
+ try {
70
+ res = await apiRequest('/api/cli/v1/ops/smoke/notification', {
71
+ method: 'POST',
72
+ body,
73
+ token,
74
+ });
75
+ spinner?.stop();
76
+ }
77
+ catch (error) {
78
+ spinner?.fail('Falha ao disparar smoke notification.');
79
+ handleApiError(error, opts.json);
80
+ }
81
+ if (opts.json) {
82
+ console.log(JSON.stringify(res));
83
+ return;
84
+ }
85
+ const data = res;
86
+ const action = data.action;
87
+ if (action === 'dedup') {
88
+ log.warn(`DEDUP: notification existente ${String(data.docId ?? '')} — occurrences incrementado.`);
89
+ }
90
+ else {
91
+ log.success(`Notification criada: ${String(data.docId ?? '')}`);
92
+ }
93
+ console.log(' Valide em core.neetru.com: sino no header deve mostrar badge unread.');
94
+ }
95
+ export async function runOpsSmokeObservability(opts) {
96
+ const token = await requireToken(opts.json);
97
+ const body = {
98
+ baseUrl: opts.baseUrl ?? 'https://core.neetru.com',
99
+ bearer: opts.bearer,
100
+ waitSec: opts.waitSec ?? 30,
101
+ };
102
+ const spinner = opts.json
103
+ ? null
104
+ : ora({ text: 'Executando smoke observability (aguarda settle)…', color: 'blue' }).start();
105
+ let res;
106
+ try {
107
+ // timeout longo pois o endpoint aguarda settle do Firestore
108
+ res = await apiRequest('/api/cli/v1/ops/smoke/observability', {
109
+ method: 'POST',
110
+ body,
111
+ token,
112
+ });
113
+ spinner?.stop();
114
+ }
115
+ catch (error) {
116
+ spinner?.fail('Falha ao executar smoke observability.');
117
+ handleApiError(error, opts.json);
118
+ }
119
+ if (opts.json) {
120
+ console.log(JSON.stringify(res));
121
+ return;
122
+ }
123
+ const data = res;
124
+ const probes = data.probes;
125
+ console.log(chalk.bold('\nResultado do smoke observability:'));
126
+ if (probes && probes.length > 0) {
127
+ const header = ` ${'FONTE'.padEnd(22)} ${'STATUS HTTP'.padEnd(12)} ${'ÚLTIMA (s)'.padEnd(12)} MATCH`;
128
+ const sep = ` ${'─'.repeat(22)} ${'─'.repeat(12)} ${'─'.repeat(12)} ─────`;
129
+ console.log(chalk.dim(header));
130
+ console.log(chalk.dim(sep));
131
+ for (const p of probes) {
132
+ const matched = p.matched ? chalk.green('SIM') : chalk.red('NÃO');
133
+ console.log(` ${String(p.source ?? '').padEnd(22)} ${String(p.endpointStatus ?? '—').padEnd(12)} ${String(p.lastAgeSec ?? '—').padEnd(12)} ${matched}`);
134
+ }
135
+ }
136
+ const tag = data.runTag;
137
+ if (tag)
138
+ console.log(chalk.dim(`\n run tag: ${tag}`));
139
+ }
140
+ export async function runOpsRegToken(serverId, opts) {
141
+ const token = await requireToken(opts.json);
142
+ const spinner = opts.json ? null : ora({ text: `Gerando registration token para ${serverId}…`, color: 'blue' }).start();
143
+ let res;
144
+ try {
145
+ res = await apiRequest('/api/cli/v1/ops/reg-token', {
146
+ method: 'POST',
147
+ body: { serverId, expiresMin: opts.expiresMin ?? 30 },
148
+ token,
149
+ });
150
+ spinner?.stop();
151
+ }
152
+ catch (error) {
153
+ spinner?.fail('Falha ao gerar registration token.');
154
+ handleApiError(error, opts.json);
155
+ }
156
+ if (opts.json) {
157
+ console.log(JSON.stringify(res));
158
+ return;
159
+ }
160
+ const data = res;
161
+ console.log(chalk.bold('Registration token gerado:'));
162
+ console.log(` ${chalk.green(String(data.token ?? ''))}`);
163
+ console.log(` server: ${String(data.serverId ?? serverId)}`);
164
+ console.log(` expira em: ${String(data.expiresAt ?? '—')}`);
165
+ console.log(chalk.dim(' (use este token no agente durante o registro — uso único)'));
166
+ }
167
+ export async function runOpsResolveErrors(opts) {
168
+ const token = await requireToken(opts.json);
169
+ if (!opts.dryRun && !opts.json) {
170
+ const { default: readline } = await import('node:readline');
171
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
172
+ const answer = await new Promise((resolve) => {
173
+ rl.question(chalk.yellow('Isso irá marcar TODOS os erros abertos como resolvidos. Confirmar? (sim/não): '), (a) => {
174
+ rl.close();
175
+ resolve(a.trim().toLowerCase());
176
+ });
177
+ });
178
+ if (answer !== 'sim' && answer !== 's') {
179
+ log.warn('Operação cancelada.');
180
+ process.exit(0);
181
+ }
182
+ }
183
+ const spinner = opts.json ? null : ora({ text: `Resolvendo erros abertos${opts.dryRun ? ' (dry-run)' : ''}…`, color: 'blue' }).start();
184
+ let res;
185
+ try {
186
+ res = await apiRequest('/api/cli/v1/ops/resolve-errors', {
187
+ method: 'POST',
188
+ body: {
189
+ dryRun: opts.dryRun ?? false,
190
+ resolvedBy: opts.resolvedBy ?? `cli-ops-${new Date().toISOString().slice(0, 10)}`,
191
+ },
192
+ token,
193
+ });
194
+ spinner?.stop();
195
+ }
196
+ catch (error) {
197
+ spinner?.fail('Falha ao resolver erros.');
198
+ handleApiError(error, opts.json);
199
+ }
200
+ if (opts.json) {
201
+ console.log(JSON.stringify(res));
202
+ return;
203
+ }
204
+ const data = res;
205
+ const results = data.results;
206
+ console.log(chalk.bold(`\nResultado (modo: ${opts.dryRun ? 'DRY-RUN' : 'WRITE'}):`));
207
+ if (results) {
208
+ for (const r of results) {
209
+ const skipped = r.skipped ? ` (+${r.skipped} dry-run skipped)` : '';
210
+ console.log(` ${r.collection}: ${chalk.green(String(r.resolved))} resolvidos${skipped}`);
211
+ }
212
+ }
213
+ }
214
+ export async function runOpsOpenapiDiff(opts) {
215
+ const token = await requireToken(opts.json);
216
+ const spinner = opts.json ? null : ora({ text: 'Verificando diff da spec OpenAPI…', color: 'blue' }).start();
217
+ let res;
218
+ try {
219
+ res = await apiRequest('/api/cli/v1/ops/openapi-diff', {
220
+ method: 'POST',
221
+ body: { update: opts.update ?? false },
222
+ token,
223
+ });
224
+ spinner?.stop();
225
+ }
226
+ catch (error) {
227
+ spinner?.fail('Falha ao checar OpenAPI diff.');
228
+ handleApiError(error, opts.json);
229
+ }
230
+ if (opts.json) {
231
+ console.log(JSON.stringify(res));
232
+ return;
233
+ }
234
+ const data = res;
235
+ const breakingChanges = data.breakingChanges;
236
+ const snapshotUpdated = data.snapshotUpdated;
237
+ const status = data.status;
238
+ if (status === 'no_snapshot') {
239
+ log.success('Snapshot inicial criado. Adicione docs/openapi-snapshot.json ao commit.');
240
+ return;
241
+ }
242
+ if (status === 'updated') {
243
+ log.success('Snapshot atualizado com --update.');
244
+ return;
245
+ }
246
+ if (breakingChanges && breakingChanges.length > 0) {
247
+ console.log(chalk.red('\nBREAKING CHANGES DETECTADOS:'));
248
+ for (const b of breakingChanges) {
249
+ console.log(` ${chalk.red('–')} ${b}`);
250
+ }
251
+ console.log(chalk.yellow('\n Recomendação: bump de versão major na spec (info.version).'));
252
+ console.log(chalk.dim(' Para atualizar: neetru ops openapi-diff --update'));
253
+ }
254
+ else if (snapshotUpdated) {
255
+ log.success('Spec mudou sem breaking changes — snapshot atualizado.');
256
+ }
257
+ else {
258
+ log.success('Sem mudanças na spec. Snapshot inalterado.');
259
+ }
260
+ }
261
+ // ─── Registro do comando `ops` em program ─────────────────────────────────────
262
+ export function registerOpsCommand(program) {
263
+ const opsCmd = program
264
+ .command('ops')
265
+ .description('Operações internas do Core (migrado de scripts/)');
266
+ // ── ops heartbeat ──────────────────────────────────────────────────────────
267
+ opsCmd
268
+ .command('heartbeat')
269
+ .description('Verificar heartbeat e estado de um server')
270
+ .option('--server-id <id>', 'ID do server (default: srv-test-01)', 'srv-test-01')
271
+ .option('--json', 'saída em JSON')
272
+ .action(async (cmdOpts) => {
273
+ await runOpsHeartbeat({ serverId: cmdOpts.serverId, json: !!cmdOpts.json });
274
+ });
275
+ // ── ops smoke ──────────────────────────────────────────────────────────────
276
+ const smokeCmd = opsCmd
277
+ .command('smoke')
278
+ .description('Smoke tests end-to-end do Core');
279
+ smokeCmd
280
+ .command('notification')
281
+ .description('Disparar notification de smoke e validar fluxo de alertas')
282
+ .option('--recipient-role <role>', 'role destinatário (admin|operator|billing|viewer)', 'admin')
283
+ .option('--recipient-uid <uid>', 'uid específico (prevalece sobre --recipient-role)')
284
+ .option('--kind <kind>', 'kind da notification (default: smoke_test)', 'smoke_test')
285
+ .option('--title <title>', 'título da notification')
286
+ .option('--link <link>', 'link de destino (default: /dashboard)', '/dashboard')
287
+ .option('--json', 'saída em JSON')
288
+ .action(async (cmdOpts) => {
289
+ await runOpsSmokeNotification({
290
+ recipientRole: cmdOpts.recipientRole,
291
+ recipientUid: cmdOpts.recipientUid,
292
+ kind: cmdOpts.kind,
293
+ title: cmdOpts.title,
294
+ link: cmdOpts.link,
295
+ json: !!cmdOpts.json,
296
+ });
297
+ });
298
+ smokeCmd
299
+ .command('observability')
300
+ .description('Smoke test fim-a-fim do pipeline de observability')
301
+ .option('--base-url <url>', 'base URL do Core', 'https://core.neetru.com')
302
+ .option('--bearer <token>', 'Bearer token da CLI key (opcional — exercita telemetry log)')
303
+ .option('--wait-sec <n>', 'segundos de espera para Firestore propagar (default: 30)', '30')
304
+ .option('--json', 'saída em JSON')
305
+ .action(async (cmdOpts) => {
306
+ await runOpsSmokeObservability({
307
+ baseUrl: cmdOpts.baseUrl,
308
+ bearer: cmdOpts.bearer,
309
+ waitSec: cmdOpts.waitSec ? Number.parseInt(cmdOpts.waitSec, 10) : 30,
310
+ json: !!cmdOpts.json,
311
+ });
312
+ });
313
+ // ── ops reg-token ──────────────────────────────────────────────────────────
314
+ opsCmd
315
+ .command('reg-token <serverId>')
316
+ .description('Gerar registration token para um server (uso único, expira em 30min)')
317
+ .option('--expires-min <n>', 'minutos até expiração (default: 30)', '30')
318
+ .option('--json', 'saída em JSON')
319
+ .action(async (serverId, cmdOpts) => {
320
+ await runOpsRegToken(serverId, {
321
+ expiresMin: cmdOpts.expiresMin ? Number.parseInt(cmdOpts.expiresMin, 10) : 30,
322
+ json: !!cmdOpts.json,
323
+ });
324
+ });
325
+ // ── ops resolve-errors ─────────────────────────────────────────────────────
326
+ opsCmd
327
+ .command('resolve-errors')
328
+ .description('Marcar todos os erros abertos (client_errors + server_errors) como resolvidos')
329
+ .option('--dry-run', 'lista o que seria resolvido sem aplicar')
330
+ .option('--resolved-by <id>', 'identificador do ator (default: cli-ops-<data>')
331
+ .option('--yes', 'pula confirmação interativa')
332
+ .option('--json', 'saída em JSON')
333
+ .action(async (cmdOpts) => {
334
+ await runOpsResolveErrors({
335
+ dryRun: !!cmdOpts.dryRun,
336
+ resolvedBy: cmdOpts.resolvedBy,
337
+ json: !!cmdOpts.json,
338
+ });
339
+ });
340
+ // ── ops openapi-diff ───────────────────────────────────────────────────────
341
+ opsCmd
342
+ .command('openapi-diff')
343
+ .description('Detectar breaking changes na spec OpenAPI comparando com o snapshot')
344
+ .option('--update', 'atualizar o snapshot sem checar breaking changes')
345
+ .option('--json', 'saída em JSON')
346
+ .action(async (cmdOpts) => {
347
+ await runOpsOpenapiDiff({ update: !!cmdOpts.update, json: !!cmdOpts.json });
348
+ });
349
+ // ── TODO (próximo sprint) ──────────────────────────────────────────────────
350
+ // - neetru ops bootstrap-admin (→ scripts/bootstrap-admin.ts)
351
+ // - neetru ops backfill incidents-source (→ scripts/backfill-incidents-source.ts)
352
+ // - neetru ops backfill workspaces (→ scripts/backfill-workspaces.ts)
353
+ // - neetru ops seed api-catalog (→ scripts/seed-api-catalog.mjs)
354
+ // - neetru ops rehash-sdk-secrets (→ scripts/rehash-sdk-client-secrets.mjs)
355
+ // - neetru ops migrate cli-keys (→ scripts/migrate-cli-api-keys.mjs)
356
+ }
357
+ // ─── Re-export deprecation helper para uso em scripts/ ───────────────────────
358
+ export { deprecationBanner };
359
+ //# sourceMappingURL=ops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ops.js","sourceRoot":"","sources":["../../src/commands/ops.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -822,13 +822,14 @@ program
822
822
  .command('logs')
823
823
  .description('Visualizar logs do workspace (suporta tail contínuo)')
824
824
  .option('--client-id <id>', 'oauthClientId do workspace')
825
- .option('-f, --follow', 'tail contínuo (poll a cada 5s)')
825
+ .option('-f, --follow', 'tail contínuo (poll a cada 5s, SSE se disponível)')
826
826
  .option('-n, --lines <count>', 'número de linhas a buscar', '50')
827
827
  .option('--since <duration>', 'logs desde N atrás (ex: 30m, 2h, 1d)', '15m')
828
828
  .option('--level <level>', 'filtrar por nível: info | warn | error | debug')
829
829
  .option('--product <product>', 'v1.3 — filtrar por productId')
830
830
  .option('--channel <channel>', 'v1.3 — filtrar por channel (stdout | stderr | app)')
831
831
  .option('--correlation-id <id>', 'v1.3 — filtrar por correlationId (UUID)')
832
+ .option('--json', 'saída em JSON (NDJSON linha a linha, útil para pipes)')
832
833
  .action(async (opts) => {
833
834
  const { runLogs } = await import('./commands/logs.js');
834
835
  await runLogs({
@@ -840,6 +841,7 @@ program
840
841
  product: opts.product,
841
842
  channel: opts.channel,
842
843
  correlationId: opts.correlationId,
844
+ json: !!opts.json,
843
845
  });
844
846
  });
845
847
  // ── neetru validate ───────────────────────────────────────────────────
@@ -1018,6 +1020,24 @@ program
1018
1020
  const { runDoctor } = await import('./commands/doctor.js');
1019
1021
  await runDoctor({ json: !!opts.json });
1020
1022
  });
1023
+ // ── neetru bootstrap ──────────────────────────────────────────────────
1024
+ // Setup zero-to-working da máquina dev: checa Node/gcloud/Docker/Firebase/git,
1025
+ // roda `npm ci` no cwd se necessário, faz `gcloud auth ADC login`,
1026
+ // e termina rodando `neetru doctor` pra confirmar.
1027
+ program
1028
+ .command('bootstrap')
1029
+ .description('Setup completo da máquina dev (binários + deps NPM + ADC)')
1030
+ .option('-y, --yes', 'aceita todos os auto-installs sem prompt')
1031
+ .option('--check', 'só lista o que falta, sem instalar nada')
1032
+ .option('--json', 'saída em JSON (machine-readable)')
1033
+ .action(async (opts) => {
1034
+ const { runBootstrap } = await import('./commands/bootstrap.js');
1035
+ await runBootstrap({
1036
+ yes: !!opts.yes,
1037
+ check: !!opts.check,
1038
+ json: !!opts.json,
1039
+ });
1040
+ });
1021
1041
  // ── neetru upgrade ────────────────────────────────────────────────────
1022
1042
  program
1023
1043
  .command('upgrade')
@@ -1301,6 +1321,13 @@ drCmd
1301
1321
  const { registerSchemaCommand } = await import('./commands/schema.js');
1302
1322
  registerSchemaCommand(program);
1303
1323
  }
1324
+ // ── neetru ops ────────────────────────────────────────────────────────
1325
+ // Operações internas migradas de scripts/ (heartbeat, smoke, reg-token,
1326
+ // resolve-errors, openapi-diff). Substitui acesso ad-hoc via tsx/node.
1327
+ {
1328
+ const { registerOpsCommand } = await import('./commands/ops.js');
1329
+ registerOpsCommand(program);
1330
+ }
1304
1331
  // ── parse ─────────────────────────────────────────────────────────────
1305
1332
  if (!process.argv.slice(2).length) {
1306
1333
  if (process.stdin.isTTY && process.stdout.isTTY && process.env.CI !== 'true') {