@neetru/cli 1.0.1 → 2.1.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.
- package/CHANGELOG.md +136 -0
- package/README.md +109 -152
- package/dist/commands/add.d.ts +8 -3
- package/dist/commands/add.js +70 -143
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/agent-release.d.ts +13 -0
- package/dist/commands/agent-release.js +204 -0
- package/dist/commands/agent-release.js.map +1 -0
- package/dist/commands/agent-write.d.ts +12 -0
- package/dist/commands/agent-write.js +94 -0
- package/dist/commands/agent-write.js.map +1 -0
- package/dist/commands/ai.d.ts +4 -0
- package/dist/commands/ai.js +88 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/api-catalog.d.ts +20 -0
- package/dist/commands/api-catalog.js +126 -0
- package/dist/commands/api-catalog.js.map +1 -0
- package/dist/commands/audit.d.ts +8 -0
- package/dist/commands/audit.js +69 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/autocomplete.d.ts +7 -0
- package/dist/commands/autocomplete.js +107 -0
- package/dist/commands/autocomplete.js.map +1 -0
- package/dist/commands/billing.d.ts +6 -0
- package/dist/commands/billing.js +69 -0
- package/dist/commands/billing.js.map +1 -0
- package/dist/commands/build.d.ts +18 -0
- package/dist/commands/build.js +295 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/cloud-run.d.ts +11 -0
- package/dist/commands/cloud-run.js +87 -0
- package/dist/commands/cloud-run.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.js +70 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/db.d.ts +14 -0
- package/dist/commands/db.js +187 -0
- package/dist/commands/db.js.map +1 -0
- package/dist/commands/deploy.d.ts +23 -3
- package/dist/commands/deploy.js +530 -177
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/deployments.d.ts +11 -0
- package/dist/commands/deployments.js +69 -0
- package/dist/commands/deployments.js.map +1 -0
- package/dist/commands/doctor.d.ts +27 -0
- package/dist/commands/doctor.js +211 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/dr.d.ts +11 -0
- package/dist/commands/dr.js +79 -0
- package/dist/commands/dr.js.map +1 -0
- package/dist/commands/env.d.ts +15 -0
- package/dist/commands/env.js +56 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/fn.d.ts +6 -0
- package/dist/commands/fn.js +87 -0
- package/dist/commands/fn.js.map +1 -0
- package/dist/commands/infra-read.d.ts +9 -0
- package/dist/commands/infra-read.js +113 -0
- package/dist/commands/infra-read.js.map +1 -0
- package/dist/commands/init.d.ts +10 -3
- package/dist/commands/init.js +275 -142
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts +6 -3
- package/dist/commands/login.js +222 -92
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts +1 -0
- package/dist/commands/logout.js +28 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/logs.d.ts +14 -3
- package/dist/commands/logs.js +132 -106
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/mocks.d.ts +5 -0
- package/dist/commands/mocks.js +23 -0
- package/dist/commands/mocks.js.map +1 -0
- package/dist/commands/open.d.ts +4 -3
- package/dist/commands/open.js +53 -85
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/products-db.d.ts +37 -0
- package/dist/commands/products-db.js +230 -0
- package/dist/commands/products-db.js.map +1 -0
- package/dist/commands/products.d.ts +12 -0
- package/dist/commands/products.js +97 -0
- package/dist/commands/products.js.map +1 -0
- package/dist/commands/promote.d.ts +9 -0
- package/dist/commands/promote.js +114 -0
- package/dist/commands/promote.js.map +1 -0
- package/dist/commands/publish.d.ts +14 -0
- package/dist/commands/publish.js +180 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/servers.d.ts +23 -0
- package/dist/commands/servers.js +166 -0
- package/dist/commands/servers.js.map +1 -0
- package/dist/commands/status.d.ts +5 -3
- package/dist/commands/status.js +91 -93
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/support.d.ts +25 -0
- package/dist/commands/support.js +184 -0
- package/dist/commands/support.js.map +1 -0
- package/dist/commands/surface-status.d.ts +5 -0
- package/dist/commands/surface-status.js +63 -0
- package/dist/commands/surface-status.js.map +1 -0
- package/dist/commands/tenants.d.ts +34 -0
- package/dist/commands/tenants.js +179 -0
- package/dist/commands/tenants.js.map +1 -0
- package/dist/commands/upgrade.d.ts +12 -0
- package/dist/commands/upgrade.js +77 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/validate.d.ts +1 -3
- package/dist/commands/validate.js +83 -91
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/whoami.d.ts +5 -3
- package/dist/commands/whoami.js +76 -28
- package/dist/commands/whoami.js.map +1 -1
- package/dist/commands/workspaces.d.ts +15 -0
- package/dist/commands/workspaces.js +72 -0
- package/dist/commands/workspaces.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1094 -36
- package/dist/index.js.map +1 -1
- package/dist/lib/ai/context.d.ts +11 -0
- package/dist/lib/ai/context.js +112 -0
- package/dist/lib/ai/context.js.map +1 -0
- package/dist/lib/ai/orchestrator.d.ts +10 -0
- package/dist/lib/ai/orchestrator.js +92 -0
- package/dist/lib/ai/orchestrator.js.map +1 -0
- package/dist/lib/api-client.d.ts +39 -0
- package/dist/lib/api-client.js +185 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/auth.d.ts +15 -0
- package/dist/lib/auth.js +98 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/cli-read.d.ts +13 -0
- package/dist/lib/cli-read.js +103 -0
- package/dist/lib/cli-read.js.map +1 -0
- package/dist/lib/cli-write.d.ts +47 -0
- package/dist/lib/cli-write.js +137 -0
- package/dist/lib/cli-write.js.map +1 -0
- package/dist/lib/config-schema.d.ts +165 -0
- package/dist/lib/config-schema.js +57 -0
- package/dist/lib/config-schema.js.map +1 -0
- package/dist/lib/config.d.ts +15 -0
- package/dist/lib/config.js +33 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/render.d.ts +16 -0
- package/dist/lib/render.js +74 -0
- package/dist/lib/render.js.map +1 -0
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.js +27 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +35 -33
- package/templates/auth/callback.ts +22 -0
- package/templates/auth/sign-in.tsx +41 -0
- package/templates/billing/checkout.ts +22 -0
- package/templates/billing/page.tsx +43 -0
- package/templates/support/ticket-form.tsx +68 -0
- package/templates/usage/track.ts +30 -0
- package/templates/users/profile.tsx +43 -0
- package/LICENSE +0 -21
- package/dist/commands/add.d.ts.map +0 -1
- package/dist/commands/deploy.d.ts.map +0 -1
- package/dist/commands/generate-types.d.ts +0 -3
- package/dist/commands/generate-types.d.ts.map +0 -1
- package/dist/commands/generate-types.js +0 -150
- package/dist/commands/generate-types.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/login.d.ts.map +0 -1
- package/dist/commands/logs.d.ts.map +0 -1
- package/dist/commands/open.d.ts.map +0 -1
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/validate.d.ts.map +0 -1
- package/dist/commands/whoami.d.ts.map +0 -1
- package/dist/config.d.ts +0 -14
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -83
- package/dist/config.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/scaffold/auth.d.ts +0 -3
- package/dist/scaffold/auth.d.ts.map +0 -1
- package/dist/scaffold/auth.js +0 -228
- package/dist/scaffold/auth.js.map +0 -1
- package/dist/scaffold/billing.d.ts +0 -3
- package/dist/scaffold/billing.d.ts.map +0 -1
- package/dist/scaffold/billing.js +0 -184
- package/dist/scaffold/billing.js.map +0 -1
- package/dist/scaffold/usage.d.ts +0 -3
- package/dist/scaffold/usage.d.ts.map +0 -1
- package/dist/scaffold/usage.js +0 -173
- package/dist/scaffold/usage.js.map +0 -1
- package/dist/scaffold/users.d.ts +0 -3
- package/dist/scaffold/users.d.ts.map +0 -1
- package/dist/scaffold/users.js +0 -135
- package/dist/scaffold/users.js.map +0 -1
package/dist/commands/add.js
CHANGED
|
@@ -1,150 +1,77 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const ora_1 = __importDefault(require("ora"));
|
|
43
|
-
const fs = __importStar(require("fs-extra"));
|
|
44
|
-
const path = __importStar(require("path"));
|
|
45
|
-
const config_1 = require("../config");
|
|
46
|
-
const auth_1 = require("../scaffold/auth");
|
|
47
|
-
const billing_1 = require("../scaffold/billing");
|
|
48
|
-
const usage_1 = require("../scaffold/usage");
|
|
49
|
-
const users_1 = require("../scaffold/users");
|
|
50
|
-
const FEATURES = {
|
|
51
|
-
auth: {
|
|
52
|
-
description: 'OAuth 2.0 / OIDC com Neetru Core (login, callback, session)',
|
|
53
|
-
scaffold: auth_1.scaffoldAuth,
|
|
54
|
-
},
|
|
55
|
-
billing: {
|
|
56
|
-
description: 'Client de assinaturas e planos via Neetru API',
|
|
57
|
-
scaffold: billing_1.scaffoldBilling,
|
|
58
|
-
},
|
|
59
|
-
usage: {
|
|
60
|
-
description: 'Metered billing — reporte de eventos de uso',
|
|
61
|
-
scaffold: usage_1.scaffoldUsage,
|
|
62
|
-
},
|
|
63
|
-
users: {
|
|
64
|
-
description: 'API de usuários Neetru (perfil, preferências)',
|
|
65
|
-
scaffold: users_1.scaffoldUsers,
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
function addCommand() {
|
|
69
|
-
const cmd = new commander_1.Command('add');
|
|
70
|
-
cmd
|
|
71
|
-
.description('Adiciona uma integração Neetru ao projeto')
|
|
72
|
-
.argument('<feature>', `Feature a adicionar: ${Object.keys(FEATURES).join(' | ')}`)
|
|
73
|
-
.option('--out-dir <dir>', 'Diretório de saída dos arquivos gerados', 'src/lib/neetru')
|
|
74
|
-
.option('--framework <name>', 'Framework do projeto (nextjs | express | fastify | plain)', 'nextjs')
|
|
75
|
-
.action(async (feature, options) => {
|
|
76
|
-
const featureDef = FEATURES[feature];
|
|
77
|
-
if (!featureDef) {
|
|
78
|
-
console.error(chalk_1.default.red(`Feature desconhecida: ${feature}`));
|
|
79
|
-
console.log(chalk_1.default.dim(`Disponíveis: ${Object.keys(FEATURES).join(', ')}`));
|
|
80
|
-
process.exit(1);
|
|
81
|
-
}
|
|
82
|
-
let config;
|
|
83
|
-
try {
|
|
84
|
-
config = (0, config_1.requireConfig)();
|
|
85
|
-
}
|
|
86
|
-
catch (e) {
|
|
87
|
-
console.error(chalk_1.default.red(e.message));
|
|
88
|
-
process.exit(1);
|
|
89
|
-
}
|
|
90
|
-
// Check if feature already added
|
|
91
|
-
if (config.features.includes(feature)) {
|
|
92
|
-
console.log(chalk_1.default.yellow(`${feature} já está listado em neetru.json`));
|
|
1
|
+
/**
|
|
2
|
+
* `neetru add <feature>` — copia um template em `cli/templates/{feature}/*`
|
|
3
|
+
* para `src/lib/neetru/{feature}/*` no projeto atual.
|
|
4
|
+
*
|
|
5
|
+
* Features suportadas: `auth`, `billing`, `usage`, `users`, `support`.
|
|
6
|
+
*
|
|
7
|
+
* Não sobrescreve arquivos existentes — caller deve remover/editar manualmente
|
|
8
|
+
* antes de rodar add de novo no mesmo feature.
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from 'node:fs/promises';
|
|
11
|
+
import * as fsSync from 'node:fs';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import { log } from '../utils/logger.js';
|
|
15
|
+
const SUPPORTED = ['auth', 'billing', 'usage', 'users', 'support'];
|
|
16
|
+
function isSupported(feature) {
|
|
17
|
+
return SUPPORTED.includes(feature);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolve diretório de templates. Em produção (instalado globalmente) o dir
|
|
21
|
+
* fica em `cli/templates` relativo ao binário. Em dev (workspace local), o
|
|
22
|
+
* mesmo path resolve corretamente.
|
|
23
|
+
*/
|
|
24
|
+
function resolveTemplatesDir() {
|
|
25
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
26
|
+
const __dirname = path.dirname(__filename);
|
|
27
|
+
// dist/commands/add.js → ../../templates (cli/dist/commands → cli/templates)
|
|
28
|
+
return path.resolve(__dirname, '../../templates');
|
|
29
|
+
}
|
|
30
|
+
async function copyDir(srcDir, destDir, force) {
|
|
31
|
+
let copied = 0;
|
|
32
|
+
let skipped = 0;
|
|
33
|
+
const entries = await fs.readdir(srcDir, { withFileTypes: true });
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
36
|
+
const destPath = path.join(destDir, entry.name);
|
|
37
|
+
if (entry.isDirectory()) {
|
|
38
|
+
await fs.mkdir(destPath, { recursive: true });
|
|
39
|
+
const r = await copyDir(srcPath, destPath, force);
|
|
40
|
+
copied += r.copied;
|
|
41
|
+
skipped += r.skipped;
|
|
93
42
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
console.log(chalk_1.default.dim('\nArquivos gerados:'));
|
|
101
|
-
createdFiles.forEach((f) => console.log(chalk_1.default.dim(` ${f}`)));
|
|
102
|
-
// Update neetru.json features list
|
|
103
|
-
if (!config.features.includes(feature)) {
|
|
104
|
-
config.features.push(feature);
|
|
105
|
-
const { writeLocalConfig } = await Promise.resolve().then(() => __importStar(require('../config')));
|
|
106
|
-
writeLocalConfig(config);
|
|
43
|
+
else {
|
|
44
|
+
const exists = fsSync.existsSync(destPath);
|
|
45
|
+
if (exists && !force) {
|
|
46
|
+
log.warn(`Skip (existe): ${path.relative(process.cwd(), destPath)}`);
|
|
47
|
+
skipped++;
|
|
48
|
+
continue;
|
|
107
49
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
console.log('');
|
|
50
|
+
await fs.copyFile(srcPath, destPath);
|
|
51
|
+
log.success(`+ ${path.relative(process.cwd(), destPath)}`);
|
|
52
|
+
copied++;
|
|
112
53
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
process.exit(1);
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
return cmd;
|
|
54
|
+
}
|
|
55
|
+
return { copied, skipped };
|
|
119
56
|
}
|
|
120
|
-
function
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
break;
|
|
134
|
-
case 'billing':
|
|
135
|
-
console.log(chalk_1.default.dim(` 1. Adicione NEETRU_CLIENT_ID às env vars`));
|
|
136
|
-
console.log(chalk_1.default.dim(` 2. Use neetruBilling.getSubscription() para verificar plano ativo`));
|
|
137
|
-
console.log(chalk_1.default.dim(` 3. Use neetruBilling.checkEntitlement() para feature flags`));
|
|
138
|
-
break;
|
|
139
|
-
case 'usage':
|
|
140
|
-
console.log(chalk_1.default.dim(` 1. Inicialize o UsageReporter com seu clientId`));
|
|
141
|
-
console.log(chalk_1.default.dim(` 2. Chame reporter.track(eventType, quantity) nos pontos de uso`));
|
|
142
|
-
console.log(chalk_1.default.dim(` 3. Eventos são enviados em batch a cada 60s automaticamente`));
|
|
143
|
-
break;
|
|
144
|
-
case 'users':
|
|
145
|
-
console.log(chalk_1.default.dim(` 1. Use neetruUsers.getProfile(token) para buscar dados do usuário`));
|
|
146
|
-
console.log(chalk_1.default.dim(` 2. O token vem do fluxo OAuth (neetru add auth)`));
|
|
147
|
-
break;
|
|
57
|
+
export async function runAdd(opts) {
|
|
58
|
+
const { feature, cwd = process.cwd(), force = false } = opts;
|
|
59
|
+
if (!isSupported(feature)) {
|
|
60
|
+
log.error(`Feature "${feature}" não suportada. Disponíveis: ${SUPPORTED.join(', ')}.`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const templatesDir = resolveTemplatesDir();
|
|
65
|
+
const srcDir = path.join(templatesDir, feature);
|
|
66
|
+
if (!fsSync.existsSync(srcDir)) {
|
|
67
|
+
log.error(`Template "${feature}" não encontrado em ${templatesDir}.`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
return;
|
|
148
70
|
}
|
|
71
|
+
const destDir = path.join(cwd, 'src', 'lib', 'neetru', feature);
|
|
72
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
73
|
+
const { copied, skipped } = await copyDir(srcDir, destDir, force);
|
|
74
|
+
log.info(`Concluído: ${copied} criados, ${skipped} pulados.`);
|
|
75
|
+
log.dim(`Próximo passo: configure NEETRU_API_KEY/NEETRU_PRODUCT_ID em .env.local.`);
|
|
149
76
|
}
|
|
150
77
|
//# sourceMappingURL=add.js.map
|
package/dist/commands/add.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface AgentReleaseOptions {
|
|
2
|
+
version: string;
|
|
3
|
+
channel?: string;
|
|
4
|
+
changelog?: string;
|
|
5
|
+
minCore?: string;
|
|
6
|
+
/** lista de "arch=path/to/binary" que será sha256-eado e tamanho-medido localmente */
|
|
7
|
+
binary?: string[];
|
|
8
|
+
/** lista de "arch=URL@sha256@sizeBytes" pra usar valores explícitos sem tocar no FS */
|
|
9
|
+
artifact?: string[];
|
|
10
|
+
/** se setado, só monta o payload e imprime, não chama API */
|
|
11
|
+
dryRun?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function runAgentRelease(opts: AgentReleaseOptions): Promise<void>;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `neetru agent release` — publica nova release do agente Neetru.
|
|
3
|
+
*
|
|
4
|
+
* Fluxo completo (manual hoje, CI futuro):
|
|
5
|
+
* 1. Build local: `cd agent/ && npm run release:linux-x64`
|
|
6
|
+
* 2. Upload manual: `gsutil cp agent/neetru-agent-linux-x64 gs://neetru-agent-releases/releases/{version}/`
|
|
7
|
+
* + `gsutil cp agent/neetru-agent-linux-x64.sha256 gs://...`
|
|
8
|
+
* 3. **Este comando** — registra `agent_releases/{version}` no Firestore via
|
|
9
|
+
* Bearer token + Server Action. Idempotente.
|
|
10
|
+
*
|
|
11
|
+
* Backend: `POST api.neetru.com/cli/v1/agent/release` (Bearer token nrt_*),
|
|
12
|
+
* exige role `admin` em `cli_api_keys/{keyId}`.
|
|
13
|
+
*
|
|
14
|
+
* Roadmap:
|
|
15
|
+
* - Sprint futura: comando `--upload` que faz GCS upload + sha256 + register
|
|
16
|
+
* numa só chamada (precisa de credenciais GCP locais ou signed URL via Core).
|
|
17
|
+
*/
|
|
18
|
+
import * as fs from 'node:fs/promises';
|
|
19
|
+
import * as fsSync from 'node:fs';
|
|
20
|
+
import * as path from 'node:path';
|
|
21
|
+
import { createHash } from 'node:crypto';
|
|
22
|
+
import chalk from 'chalk';
|
|
23
|
+
import { log } from '../utils/logger.js';
|
|
24
|
+
import { apiRequest, CliApiError, CliNetworkError } from '../lib/api-client.js';
|
|
25
|
+
const VALID_CHANNELS = ['stable', 'beta', 'canary'];
|
|
26
|
+
const VALID_ARCHS = ['linux-x64', 'linux-arm64', 'darwin-x64', 'darwin-arm64'];
|
|
27
|
+
const SEMVER_RE = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/;
|
|
28
|
+
const SHA256_RE = /^[a-f0-9]{64}$/;
|
|
29
|
+
const GCS_BASE = 'https://storage.googleapis.com/neetru-agent-releases/releases';
|
|
30
|
+
function isArch(s) {
|
|
31
|
+
return VALID_ARCHS.includes(s);
|
|
32
|
+
}
|
|
33
|
+
function isChannel(s) {
|
|
34
|
+
return VALID_CHANNELS.includes(s);
|
|
35
|
+
}
|
|
36
|
+
async function sha256File(filePath) {
|
|
37
|
+
const buf = await fs.readFile(filePath);
|
|
38
|
+
const sha256 = createHash('sha256').update(buf).digest('hex');
|
|
39
|
+
return { sha256, sizeBytes: buf.length };
|
|
40
|
+
}
|
|
41
|
+
async function loadChangelogFromFile(filePath) {
|
|
42
|
+
const abs = path.resolve(process.cwd(), filePath);
|
|
43
|
+
return fs.readFile(abs, 'utf8');
|
|
44
|
+
}
|
|
45
|
+
function parseBinaryArg(arg) {
|
|
46
|
+
const idx = arg.indexOf('=');
|
|
47
|
+
if (idx < 0)
|
|
48
|
+
throw new Error(`--binary inválido "${arg}". Esperado "arch=path".`);
|
|
49
|
+
const arch = arg.slice(0, idx);
|
|
50
|
+
const filePath = arg.slice(idx + 1);
|
|
51
|
+
if (!isArch(arch)) {
|
|
52
|
+
throw new Error(`--binary com arch inválido "${arch}". Válidos: ${VALID_ARCHS.join(', ')}`);
|
|
53
|
+
}
|
|
54
|
+
if (!filePath || !fsSync.existsSync(filePath)) {
|
|
55
|
+
throw new Error(`--binary path não encontrado: ${filePath}`);
|
|
56
|
+
}
|
|
57
|
+
return { arch, filePath };
|
|
58
|
+
}
|
|
59
|
+
function parseArtifactArg(arg) {
|
|
60
|
+
// Format: arch=URL@sha256@sizeBytes
|
|
61
|
+
const parts = arg.split('=');
|
|
62
|
+
if (parts.length !== 2)
|
|
63
|
+
throw new Error(`--artifact inválido "${arg}". Esperado "arch=URL@sha256@sizeBytes".`);
|
|
64
|
+
const arch = parts[0];
|
|
65
|
+
if (!isArch(arch)) {
|
|
66
|
+
throw new Error(`--artifact com arch inválido "${arch}". Válidos: ${VALID_ARCHS.join(', ')}`);
|
|
67
|
+
}
|
|
68
|
+
const rest = parts[1].split('@');
|
|
69
|
+
if (rest.length !== 3)
|
|
70
|
+
throw new Error(`--artifact inválido "${arg}". Esperado "arch=URL@sha256@sizeBytes".`);
|
|
71
|
+
const [url, sha256, sizeStr] = rest;
|
|
72
|
+
if (!SHA256_RE.test(sha256.toLowerCase())) {
|
|
73
|
+
throw new Error(`--artifact ${arch}: sha256 inválido (esperado hex64).`);
|
|
74
|
+
}
|
|
75
|
+
const sizeBytes = Number(sizeStr);
|
|
76
|
+
if (!Number.isFinite(sizeBytes) || sizeBytes <= 0) {
|
|
77
|
+
throw new Error(`--artifact ${arch}: sizeBytes inválido.`);
|
|
78
|
+
}
|
|
79
|
+
return { arch, payload: { url, sha256: sha256.toLowerCase(), sizeBytes } };
|
|
80
|
+
}
|
|
81
|
+
export async function runAgentRelease(opts) {
|
|
82
|
+
log.banner();
|
|
83
|
+
log.heading('neetru agent release');
|
|
84
|
+
// ── validação básica ───────────────────────────────────────────────
|
|
85
|
+
if (!opts.version) {
|
|
86
|
+
log.error('--version é obrigatório (ex: 1.2.0).');
|
|
87
|
+
process.exit(2);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (!SEMVER_RE.test(opts.version)) {
|
|
91
|
+
log.error(`--version inválido "${opts.version}". Use semver (1.2.3 ou 1.2.3-beta.1).`);
|
|
92
|
+
process.exit(2);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const channel = (opts.channel ?? 'beta').toLowerCase();
|
|
96
|
+
if (!isChannel(channel)) {
|
|
97
|
+
log.error(`--channel inválido "${channel}". Válidos: ${VALID_CHANNELS.join(' | ')}`);
|
|
98
|
+
process.exit(2);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// ── changelog ───────────────────────────────────────────────────────
|
|
102
|
+
let changelog = opts.changelog ?? '';
|
|
103
|
+
if (changelog.startsWith('@')) {
|
|
104
|
+
try {
|
|
105
|
+
changelog = await loadChangelogFromFile(changelog.slice(1));
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
log.error(`Falha ao ler changelog "${changelog}": ${err.message}`);
|
|
109
|
+
process.exit(3);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (!changelog || changelog.trim().length < 10) {
|
|
114
|
+
log.error('--changelog obrigatório (mín 10 chars). Use "@path/to/CHANGELOG.md" pra ler de arquivo.');
|
|
115
|
+
process.exit(2);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// ── monta artifacts ────────────────────────────────────────────────
|
|
119
|
+
const artifacts = {};
|
|
120
|
+
// Via --binary: lê arquivo local, computa sha256 + size, URL canônica GCS
|
|
121
|
+
for (const a of opts.binary ?? []) {
|
|
122
|
+
try {
|
|
123
|
+
const { arch, filePath } = parseBinaryArg(a);
|
|
124
|
+
log.info(`Computando sha256 de ${chalk.dim(filePath)}...`);
|
|
125
|
+
const { sha256, sizeBytes } = await sha256File(filePath);
|
|
126
|
+
const url = `${GCS_BASE}/${encodeURIComponent(opts.version)}/neetru-agent-${arch}`;
|
|
127
|
+
artifacts[arch] = { url, sha256, sizeBytes };
|
|
128
|
+
log.success(` ${arch}: sha256=${sha256.slice(0, 12)}... (${(sizeBytes / 1_000_000).toFixed(1)} MB)`);
|
|
129
|
+
log.dim(` URL: ${url}`);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
log.error(err.message);
|
|
133
|
+
process.exit(2);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Via --artifact: tudo explícito, no FS read
|
|
138
|
+
for (const a of opts.artifact ?? []) {
|
|
139
|
+
try {
|
|
140
|
+
const { arch, payload } = parseArtifactArg(a);
|
|
141
|
+
artifacts[arch] = payload;
|
|
142
|
+
log.success(` ${arch}: sha256=${payload.sha256.slice(0, 12)}... (${(payload.sizeBytes / 1_000_000).toFixed(1)} MB)`);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
log.error(err.message);
|
|
146
|
+
process.exit(2);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (Object.keys(artifacts).length === 0) {
|
|
151
|
+
log.error('Nenhum artifact informado. Use --binary arch=path ou --artifact arch=URL@sha256@sizeBytes.');
|
|
152
|
+
process.exit(2);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
// ── payload ─────────────────────────────────────────────────────────
|
|
156
|
+
const payload = {
|
|
157
|
+
version: opts.version,
|
|
158
|
+
channel,
|
|
159
|
+
changelog,
|
|
160
|
+
artifacts,
|
|
161
|
+
...(opts.minCore ? { minSupportedCoreVersion: opts.minCore } : {}),
|
|
162
|
+
};
|
|
163
|
+
if (opts.dryRun) {
|
|
164
|
+
log.heading('Dry run — payload que seria enviado:');
|
|
165
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
166
|
+
log.warn('Nada foi enviado. Remova --dry-run para publicar.');
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
log.info(`Registrando release ${chalk.bold(opts.version)} (channel=${chalk.bold(channel)}, ${Object.keys(artifacts).length} arch(s))...`);
|
|
170
|
+
try {
|
|
171
|
+
const r = await apiRequest('/cli/v1/agent/release', {
|
|
172
|
+
method: 'POST',
|
|
173
|
+
body: payload,
|
|
174
|
+
});
|
|
175
|
+
if (r.alreadyExists) {
|
|
176
|
+
log.warn(`Release ${chalk.bold(r.version)} já existia. Idempotente — nenhuma mudança.`);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
log.success(`Release ${chalk.bold(r.version)} publicada.`);
|
|
180
|
+
}
|
|
181
|
+
log.dim(` Painel: https://core.neetru.com/agent/releases`);
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
if (err instanceof CliApiError) {
|
|
185
|
+
if (err.status === 401 || err.status === 403) {
|
|
186
|
+
log.error('Não autorizado. CLI precisa estar logado com chave admin.');
|
|
187
|
+
log.dim(' neetru login');
|
|
188
|
+
process.exit(4);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
log.error(`API ${err.status}: ${err.message}`);
|
|
192
|
+
process.exit(5);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (err instanceof CliNetworkError) {
|
|
196
|
+
log.error(`Conexão falhou: ${err.message}`);
|
|
197
|
+
process.exit(6);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
log.error(err instanceof Error ? err.message : String(err));
|
|
201
|
+
process.exit(7);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=agent-release.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-release.js","sourceRoot":"","sources":["../../src/commands/agent-release.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type StepUpOptions } from '../lib/cli-write.js';
|
|
2
|
+
export interface AgentYankOptions extends StepUpOptions {
|
|
3
|
+
reason: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function runAgentYank(version: string, opts: AgentYankOptions): Promise<void>;
|
|
6
|
+
export declare function runAgentCanaryStart(version: string, opts: {
|
|
7
|
+
json?: boolean;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
export interface AgentCanaryRollbackOptions extends StepUpOptions {
|
|
10
|
+
reason: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function runAgentCanaryRollback(version: string, opts: AgentCanaryRollbackOptions): Promise<void>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `neetru agent yank` + `neetru agent canary start|rollback` — write commands
|
|
3
|
+
* sobre releases do agente Neetru.
|
|
4
|
+
*
|
|
5
|
+
* Endpoints:
|
|
6
|
+
* POST /api/cli/v1/agent/yank (yank — destrutivo)
|
|
7
|
+
* POST /api/cli/v1/agent/canary?action=start (start canary)
|
|
8
|
+
* POST /api/cli/v1/agent/canary?action=rollback (rollback — destrutivo)
|
|
9
|
+
*
|
|
10
|
+
* `neetru agent release` (publicar release) já existe em `agent-release.ts`.
|
|
11
|
+
*/
|
|
12
|
+
import ora from 'ora';
|
|
13
|
+
import { apiRequest } from '../lib/api-client.js';
|
|
14
|
+
import { requireToken, handleApiError, confirmDestructive, printWriteResult, resolveStepUp, } from '../lib/cli-write.js';
|
|
15
|
+
import { log } from '../utils/logger.js';
|
|
16
|
+
export async function runAgentYank(version, opts) {
|
|
17
|
+
if (!version) {
|
|
18
|
+
log.error('Uso: neetru agent yank <version> --reason "<motivo ≥5 chars>"');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
const token = await requireToken(opts.json);
|
|
22
|
+
await confirmDestructive(`Yankar a release ${version} do agente? Installers/auto-upgrade vão ignorá-la.`, opts);
|
|
23
|
+
const { headers } = await resolveStepUp(opts);
|
|
24
|
+
const spinner = opts.json
|
|
25
|
+
? null
|
|
26
|
+
: ora({ text: `Yankando release ${version}…`, color: 'blue' }).start();
|
|
27
|
+
let res;
|
|
28
|
+
try {
|
|
29
|
+
res = await apiRequest(`/api/cli/v1/agent/yank${opts.dryRun ? '?dryRun=true' : ''}`, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
token,
|
|
32
|
+
headers,
|
|
33
|
+
body: { version, reason: opts.reason },
|
|
34
|
+
});
|
|
35
|
+
spinner?.stop();
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
spinner?.fail('Falha ao yankar release.');
|
|
39
|
+
handleApiError(error, opts.json);
|
|
40
|
+
}
|
|
41
|
+
printWriteResult(res.dryRun ? res : { version: res.version, yanked: res.yanked }, `Release ${res.version} yankada.`, opts.json);
|
|
42
|
+
}
|
|
43
|
+
export async function runAgentCanaryStart(version, opts) {
|
|
44
|
+
if (!version) {
|
|
45
|
+
log.error('Uso: neetru agent canary start <version>');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
const token = await requireToken(opts.json);
|
|
49
|
+
const spinner = opts.json
|
|
50
|
+
? null
|
|
51
|
+
: ora({ text: `Iniciando canary de ${version}…`, color: 'blue' }).start();
|
|
52
|
+
let res;
|
|
53
|
+
try {
|
|
54
|
+
res = await apiRequest('/api/cli/v1/agent/canary?action=start', {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
token,
|
|
57
|
+
body: { version },
|
|
58
|
+
});
|
|
59
|
+
spinner?.stop();
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
spinner?.fail('Falha ao iniciar canary.');
|
|
63
|
+
handleApiError(error, opts.json);
|
|
64
|
+
}
|
|
65
|
+
printWriteResult({ version: res.version, phase: res.phase }, `Canary de ${res.version} iniciado — phase: ${res.phase}`, opts.json);
|
|
66
|
+
}
|
|
67
|
+
export async function runAgentCanaryRollback(version, opts) {
|
|
68
|
+
if (!version) {
|
|
69
|
+
log.error('Uso: neetru agent canary rollback <version> --reason "<motivo ≥5 chars>"');
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
const token = await requireToken(opts.json);
|
|
73
|
+
await confirmDestructive(`Rollback do canary de ${version}? A release não retorna ao rollout — só com nova versão.`, opts);
|
|
74
|
+
const { headers } = await resolveStepUp(opts);
|
|
75
|
+
const spinner = opts.json
|
|
76
|
+
? null
|
|
77
|
+
: ora({ text: `Rollback do canary de ${version}…`, color: 'blue' }).start();
|
|
78
|
+
let res;
|
|
79
|
+
try {
|
|
80
|
+
res = await apiRequest(`/api/cli/v1/agent/canary?action=rollback${opts.dryRun ? '&dryRun=true' : ''}`, {
|
|
81
|
+
method: 'POST',
|
|
82
|
+
token,
|
|
83
|
+
headers,
|
|
84
|
+
body: { version, reason: opts.reason },
|
|
85
|
+
});
|
|
86
|
+
spinner?.stop();
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
spinner?.fail('Falha ao fazer rollback do canary.');
|
|
90
|
+
handleApiError(error, opts.json);
|
|
91
|
+
}
|
|
92
|
+
printWriteResult(res.dryRun ? res : { version: res.version, phase: res.phase }, `Canary de ${res.version} → ${res.phase}`, opts.json);
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=agent-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-write.js","sourceRoot":"","sources":["../../src/commands/agent-write.ts"],"names":[],"mappings":"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"}
|