@neetru/cli 2.12.2 → 2.12.5
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/dist/commands/auth.d.ts +18 -0
- package/dist/commands/auth.js +84 -0
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/build.d.ts +16 -1
- package/dist/commands/build.js +95 -11
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/db.d.ts +12 -1
- package/dist/commands/db.js +21 -8
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.js +90 -9
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/logout.js +7 -0
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/ui.js +12 -5
- package/dist/commands/ui.js.map +1 -1
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/cli-write.d.ts +31 -6
- package/dist/lib/cli-write.js +98 -8
- package/dist/lib/cli-write.js.map +1 -1
- package/dist/lib/db-pipeline/build-deps.d.ts +2 -1
- package/dist/lib/db-pipeline/build-deps.js +29 -19
- package/dist/lib/db-pipeline/build-deps.js.map +1 -1
- package/dist/lib/db-pipeline/rehearse.d.ts +11 -1
- package/dist/lib/db-pipeline/rehearse.js +73 -32
- package/dist/lib/db-pipeline/rehearse.js.map +1 -1
- package/dist/utils/safe-exit.js +20 -4
- package/dist/utils/safe-exit.js.map +1 -1
- package/package.json +2 -2
|
@@ -49,21 +49,24 @@ function readSchemaFile(path) {
|
|
|
49
49
|
return fs.readFileSync(path, 'utf8');
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
|
-
*
|
|
52
|
+
* Obtém o DDL SQL do schema via `drizzle-kit export`.
|
|
53
53
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
54
|
+
* BUG FIX (bug_c7842bbe): antes rodávamos `drizzle-kit generate` e retornávamos
|
|
55
|
+
* o STDOUT — mas `generate` NÃO emite SQL no stdout: escreve o `.sql` no
|
|
56
|
+
* diretório `out` e imprime apenas BANNER/STATUS ("Reading config file ...",
|
|
57
|
+
* "N tables", ...). Esse banner virava o "SQL candidato" e quebrava o rehearse
|
|
58
|
+
* (o psql interpretava "No config path ..." como statement → syntax error) e,
|
|
59
|
+
* com `--skip-rehearse`, mandaria o banner como corpo da migração pro Core.
|
|
59
60
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
61
|
+
* `drizzle-kit export` emite o DDL PURO e AUTO-CONTIDO no STDOUT (sem banner,
|
|
62
|
+
* sem conexão ao banco — só lê o schema), que é exatamente o que o rehearse
|
|
63
|
+
* (Postgres fresco/efêmero) e o classify esperam. Verificado contra
|
|
64
|
+
* drizzle-kit 0.31.x. `export` lê a `drizzle.config.ts` do produto (schema +
|
|
65
|
+
* dialect); não precisa de `dbCredentials`.
|
|
63
66
|
*/
|
|
64
67
|
function generateSql(schemaPath) {
|
|
65
68
|
return new Promise((resolve, reject) => {
|
|
66
|
-
const child = spawn('npx', ['drizzle-kit', '
|
|
69
|
+
const child = spawn('npx', ['drizzle-kit', 'export'], {
|
|
67
70
|
cwd: process.cwd(),
|
|
68
71
|
env: { ...process.env, NEETRU_DB_SCHEMA: schemaPath },
|
|
69
72
|
shell: process.platform === 'win32',
|
|
@@ -77,16 +80,15 @@ function generateSql(schemaPath) {
|
|
|
77
80
|
stderr += String(chunk);
|
|
78
81
|
});
|
|
79
82
|
child.on('error', (err) => {
|
|
80
|
-
reject(new Error(`não foi possível executar drizzle-kit
|
|
83
|
+
reject(new Error(`não foi possível executar drizzle-kit export: ${err.message}`));
|
|
81
84
|
});
|
|
82
85
|
child.on('exit', (code) => {
|
|
83
|
-
if (code
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
reject(new Error(`drizzle-kit generate falhou (exit ${code ?? '?'})` +
|
|
86
|
+
if (code !== 0) {
|
|
87
|
+
reject(new Error(`drizzle-kit export falhou (exit ${code ?? '?'})` +
|
|
88
88
|
`${stderr.trim() ? `: ${stderr.trim()}` : '.'}`));
|
|
89
|
+
return;
|
|
89
90
|
}
|
|
91
|
+
resolve(stdout);
|
|
90
92
|
});
|
|
91
93
|
});
|
|
92
94
|
}
|
|
@@ -102,7 +104,15 @@ function generateSql(schemaPath) {
|
|
|
102
104
|
* Lança `RehearseDockerUnavailableError` quando Docker indisponível — nunca
|
|
103
105
|
* retorna `{ ok: true }` sem fazer o trabalho.
|
|
104
106
|
*/
|
|
105
|
-
|
|
107
|
+
/**
|
|
108
|
+
* C5 (auditoria 2026-06-10): o rehearse é construído por-MOTOR. Postgres sobe
|
|
109
|
+
* `postgres:16-alpine` + psql; MySQL sobe `mysql:8` + cliente mysql. Antes era
|
|
110
|
+
* sempre Postgres, então a DDL MySQL (drizzle dialect mysql) quebrava no parser
|
|
111
|
+
* do Postgres e bloqueava o `neetru db apply` de engines MySQL.
|
|
112
|
+
*/
|
|
113
|
+
function makeRehearse(engine) {
|
|
114
|
+
return buildRehearseInContainer(buildDockerExecFn(), { engine });
|
|
115
|
+
}
|
|
106
116
|
/**
|
|
107
117
|
* Classifica o `.sql` em aditiva/destrutiva via `@neetru/db-classifier`.
|
|
108
118
|
* Função pura — sem I/O. O shape do `ClassificationReport` do classifier é
|
|
@@ -145,11 +155,11 @@ async function pushToCore(artifact) {
|
|
|
145
155
|
* `overrides` permite sobrescrever deps individuais (ex.: `pushToCore` em
|
|
146
156
|
* `--dry-run`, ou `onPhase` para ligar num spinner do `ora`).
|
|
147
157
|
*/
|
|
148
|
-
export function buildPipelineDeps(overrides = {}) {
|
|
158
|
+
export function buildPipelineDeps(overrides = {}, engine = 'postgres') {
|
|
149
159
|
return {
|
|
150
160
|
readSchemaFile,
|
|
151
161
|
generateSql,
|
|
152
|
-
rehearseInContainer,
|
|
162
|
+
rehearseInContainer: makeRehearse(engine),
|
|
153
163
|
classify,
|
|
154
164
|
pushToCore,
|
|
155
165
|
...overrides,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-deps.js","sourceRoot":"","sources":["../../../src/lib/db-pipeline/build-deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,wBAAwB,EACxB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"build-deps.js","sourceRoot":"","sources":["../../../src/lib/db-pipeline/build-deps.ts"],"names":[],"mappings":"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"}
|
|
@@ -44,7 +44,7 @@ export interface DockerExecResult {
|
|
|
44
44
|
* código de saída. Só lança em falha estrutural (ex.: `spawn` não encontrou o
|
|
45
45
|
* executável).
|
|
46
46
|
*/
|
|
47
|
-
export type DockerExecFn = (args: string[]) => Promise<DockerExecResult>;
|
|
47
|
+
export type DockerExecFn = (args: string[], input?: string) => Promise<DockerExecResult>;
|
|
48
48
|
/** Opções para `buildRehearseInContainer`. */
|
|
49
49
|
export interface RehearseOptions {
|
|
50
50
|
/**
|
|
@@ -64,6 +64,14 @@ export interface RehearseOptions {
|
|
|
64
64
|
* flag `--skip-rehearse` na CLI. Não é silencioso por contrato.
|
|
65
65
|
*/
|
|
66
66
|
skipRehearse?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Motor do banco a ensaiar (C5 — auditoria 2026-06-10). Default `postgres`.
|
|
69
|
+
* Engines MySQL (`vm-mysql-single`, `cloud-sql-mysql`) precisam ensaiar a DDL
|
|
70
|
+
* num MySQL real — antes o rehearse SEMPRE subia Postgres + psql, então a DDL
|
|
71
|
+
* MySQL (drizzle-kit dialect mysql) quebrava no parser do Postgres e bloqueava
|
|
72
|
+
* o apply. `mysql` sobe `mysql:8` + aplica via cliente `mysql`.
|
|
73
|
+
*/
|
|
74
|
+
engine?: RehearseEngine;
|
|
67
75
|
}
|
|
68
76
|
/**
|
|
69
77
|
* Lançado quando o Docker CLI não está disponível no PATH ou o daemon não
|
|
@@ -77,6 +85,8 @@ export declare class RehearseDockerUnavailableError extends Error {
|
|
|
77
85
|
}
|
|
78
86
|
/** Type guard — `true` sse `value` é um `RehearseDockerUnavailableError`. */
|
|
79
87
|
export declare function isRehearseDockerUnavailableError(value: unknown): value is RehearseDockerUnavailableError;
|
|
88
|
+
/** Motor suportado pelo ensaio. */
|
|
89
|
+
export type RehearseEngine = 'postgres' | 'mysql';
|
|
80
90
|
/**
|
|
81
91
|
* Constrói a função `rehearseInContainer` com a camada Docker injetada.
|
|
82
92
|
*
|
|
@@ -68,6 +68,51 @@ const PG_ENV = {
|
|
|
68
68
|
password: 'neetru_rehearse_dev',
|
|
69
69
|
db: 'neetru_rehearse',
|
|
70
70
|
};
|
|
71
|
+
/** Credenciais do container MySQL efêmero (root, descartado em <60s). */
|
|
72
|
+
const MYSQL_ENV = {
|
|
73
|
+
password: 'neetru_rehearse_dev',
|
|
74
|
+
db: 'neetru_rehearse',
|
|
75
|
+
};
|
|
76
|
+
const ENGINE_SPECS = {
|
|
77
|
+
postgres: {
|
|
78
|
+
defaultImage: DEFAULT_IMAGE,
|
|
79
|
+
readyTimeoutMs: DEFAULT_READY_TIMEOUT_MS,
|
|
80
|
+
runEnvArgs: [
|
|
81
|
+
'-e', `POSTGRES_USER=${PG_ENV.user}`,
|
|
82
|
+
'-e', `POSTGRES_PASSWORD=${PG_ENV.password}`,
|
|
83
|
+
'-e', `POSTGRES_DB=${PG_ENV.db}`,
|
|
84
|
+
],
|
|
85
|
+
readyCmd: (c) => [
|
|
86
|
+
'exec', c, 'pg_isready', '--username', PG_ENV.user, '--dbname', PG_ENV.db, '--quiet',
|
|
87
|
+
],
|
|
88
|
+
// psql --single-transaction: rollback total em erro parcial (container limpo).
|
|
89
|
+
applyCmd: (c) => [
|
|
90
|
+
'exec', '--interactive', c, 'psql',
|
|
91
|
+
'--username', PG_ENV.user, '--dbname', PG_ENV.db,
|
|
92
|
+
'--no-psqlrc', '--single-transaction', '--file', '-',
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
mysql: {
|
|
96
|
+
defaultImage: 'mysql:8',
|
|
97
|
+
// mysql:8 tem cold-start mais lento (entrypoint sobe servidor temporário de
|
|
98
|
+
// init e reinicia) — 60s cobre a janela real.
|
|
99
|
+
readyTimeoutMs: 60_000,
|
|
100
|
+
runEnvArgs: [
|
|
101
|
+
'-e', `MYSQL_ROOT_PASSWORD=${MYSQL_ENV.password}`,
|
|
102
|
+
'-e', `MYSQL_DATABASE=${MYSQL_ENV.db}`,
|
|
103
|
+
],
|
|
104
|
+
// SELECT 1 autenticado só passa quando o servidor REAL (não o temporário de
|
|
105
|
+
// init) está no ar e o root é utilizável — mais robusto que `mysqladmin ping`.
|
|
106
|
+
readyCmd: (c) => [
|
|
107
|
+
'exec', c, 'mysql', '-uroot', `-p${MYSQL_ENV.password}`, '-e', 'SELECT 1',
|
|
108
|
+
],
|
|
109
|
+
// mysql client lê DDL do STDIN. DDL no MySQL auto-commita (não-transacional);
|
|
110
|
+
// o container efêmero é descartado, então não há resíduo a limpar.
|
|
111
|
+
applyCmd: (c) => [
|
|
112
|
+
'exec', '--interactive', c, 'mysql', '-uroot', `-p${MYSQL_ENV.password}`, MYSQL_ENV.db,
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
};
|
|
71
116
|
// ---------------------------------------------------------------------------
|
|
72
117
|
// Helpers internos
|
|
73
118
|
// ---------------------------------------------------------------------------
|
|
@@ -76,19 +121,13 @@ function ephemeralContainerName() {
|
|
|
76
121
|
return `neetru-rehearse-${randomBytes(6).toString('hex')}`;
|
|
77
122
|
}
|
|
78
123
|
/**
|
|
79
|
-
* Aguarda o
|
|
80
|
-
* Retorna `true` se ficou pronto
|
|
124
|
+
* Aguarda o banco aceitar conexões, sondando `readyCmd` (pg_isready / SELECT 1)
|
|
125
|
+
* até exit 0. Retorna `true` se ficou pronto no timeout, `false` caso contrário.
|
|
81
126
|
*/
|
|
82
|
-
async function
|
|
127
|
+
async function waitForReady(execDocker, containerName, readyCmd, timeoutMs) {
|
|
83
128
|
const deadline = Date.now() + timeoutMs;
|
|
84
129
|
while (Date.now() < deadline) {
|
|
85
|
-
const result = await execDocker(
|
|
86
|
-
'exec', containerName,
|
|
87
|
-
'pg_isready',
|
|
88
|
-
'--username', PG_ENV.user,
|
|
89
|
-
'--dbname', PG_ENV.db,
|
|
90
|
-
'--quiet',
|
|
91
|
-
]);
|
|
130
|
+
const result = await execDocker(readyCmd(containerName));
|
|
92
131
|
if (result.exit === 0)
|
|
93
132
|
return true;
|
|
94
133
|
// Aguarda antes do próximo poll.
|
|
@@ -111,8 +150,10 @@ async function waitForPostgresReady(execDocker, containerName, timeoutMs) {
|
|
|
111
150
|
* Testes: injeta um mock de `execDocker` que controla cada resposta.
|
|
112
151
|
*/
|
|
113
152
|
export function buildRehearseInContainer(execDocker, opts = {}) {
|
|
114
|
-
const
|
|
115
|
-
const
|
|
153
|
+
const engine = opts.engine ?? 'postgres';
|
|
154
|
+
const spec = ENGINE_SPECS[engine];
|
|
155
|
+
const image = opts.image ?? spec.defaultImage;
|
|
156
|
+
const readyTimeoutMs = opts.readyTimeoutMs ?? spec.readyTimeoutMs;
|
|
116
157
|
const skipRehearse = opts.skipRehearse ?? false;
|
|
117
158
|
return async function rehearseInContainer(sql) {
|
|
118
159
|
// ── Override explícito (--skip-rehearse) ─────────────────────────────
|
|
@@ -133,9 +174,7 @@ export function buildRehearseInContainer(execDocker, opts = {}) {
|
|
|
133
174
|
const runResult = await execDocker([
|
|
134
175
|
'run', '--detach', '--rm',
|
|
135
176
|
'--name', containerName,
|
|
136
|
-
|
|
137
|
-
'-e', `POSTGRES_PASSWORD=${PG_ENV.password}`,
|
|
138
|
-
'-e', `POSTGRES_DB=${PG_ENV.db}`,
|
|
177
|
+
...spec.runEnvArgs,
|
|
139
178
|
image,
|
|
140
179
|
]);
|
|
141
180
|
if (runResult.exit !== 0) {
|
|
@@ -144,26 +183,20 @@ export function buildRehearseInContainer(execDocker, opts = {}) {
|
|
|
144
183
|
}
|
|
145
184
|
// ── 3. Aguardar pronto + aplicar SQL + derrubar ───────────────────────
|
|
146
185
|
try {
|
|
147
|
-
const ready = await
|
|
186
|
+
const ready = await waitForReady(execDocker, containerName, spec.readyCmd, readyTimeoutMs);
|
|
148
187
|
if (!ready) {
|
|
149
188
|
return {
|
|
150
189
|
ok: false,
|
|
151
|
-
error: `Timeout (${readyTimeoutMs}ms) aguardando o
|
|
190
|
+
error: `Timeout (${readyTimeoutMs}ms) aguardando o ${engine} ficar pronto ` +
|
|
152
191
|
`no container "${containerName}". ` +
|
|
153
192
|
`Verifique se a imagem "${image}" está disponível localmente.`,
|
|
154
193
|
};
|
|
155
194
|
}
|
|
156
|
-
// Aplica o SQL candidato
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
'--username', PG_ENV.user,
|
|
162
|
-
'--dbname', PG_ENV.db,
|
|
163
|
-
'--no-psqlrc',
|
|
164
|
-
'--single-transaction',
|
|
165
|
-
'--command', sql,
|
|
166
|
-
]);
|
|
195
|
+
// Aplica o SQL candidato via STDIN (psql `--file -` / mysql lê stdin), NÃO
|
|
196
|
+
// via argumento. BUG FIX (bug_c7842bbe): SQL multi-linha como `--command`
|
|
197
|
+
// sofria word-split do shell no Windows → "syntax error". Pelo STDIN a SQL
|
|
198
|
+
// chega intacta. Comando exato por motor em ENGINE_SPECS.applyCmd.
|
|
199
|
+
const applyResult = await execDocker(spec.applyCmd(containerName), sql);
|
|
167
200
|
if (applyResult.exit !== 0) {
|
|
168
201
|
// SQL inválido — retorna o erro (não lança). O pipeline trata como
|
|
169
202
|
// `PipelineError('rehearse')`.
|
|
@@ -196,11 +229,13 @@ export function buildRehearseInContainer(execDocker, opts = {}) {
|
|
|
196
229
|
* (b) o `spawn` seja injetável em camada superior quando necessário.
|
|
197
230
|
*/
|
|
198
231
|
export function buildDockerExecFn() {
|
|
199
|
-
return function execDocker(args) {
|
|
232
|
+
return function execDocker(args, input) {
|
|
200
233
|
return new Promise((resolve) => {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
234
|
+
// SEM `shell` — `docker` é um executável (docker.exe no Windows). Evitar o
|
|
235
|
+
// shell (a) impede word-split de argumentos (a SQL/banner vinham quebrados
|
|
236
|
+
// no Windows com shell:true) e (b) elimina o aviso DEP0190 (args + shell).
|
|
237
|
+
// Se o docker não resolver, o handler 'error' resolve exit=1 (fail-closed).
|
|
238
|
+
const child = spawn('docker', args);
|
|
204
239
|
let stdout = '';
|
|
205
240
|
let stderr = '';
|
|
206
241
|
child.stdout?.on('data', (chunk) => { stdout += String(chunk); });
|
|
@@ -213,6 +248,12 @@ export function buildDockerExecFn() {
|
|
|
213
248
|
// Combina stdout + stderr: psql escreve erros em stderr.
|
|
214
249
|
resolve({ stdout: stdout + stderr, exit: code ?? 1 });
|
|
215
250
|
});
|
|
251
|
+
// Passa a SQL via STDIN quando fornecida (psql --file -). Sempre fecha o
|
|
252
|
+
// stdin pra processos que não leem (version/run/stop) não travarem.
|
|
253
|
+
if (input !== undefined) {
|
|
254
|
+
child.stdin?.write(input);
|
|
255
|
+
}
|
|
256
|
+
child.stdin?.end();
|
|
216
257
|
});
|
|
217
258
|
};
|
|
218
259
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rehearse.js","sourceRoot":"","sources":["../../../src/lib/db-pipeline/rehearse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"rehearse.js","sourceRoot":"","sources":["../../../src/lib/db-pipeline/rehearse.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/safe-exit.js
CHANGED
|
@@ -32,11 +32,27 @@ function cleanupHandles() {
|
|
|
32
32
|
stopAllSpinners();
|
|
33
33
|
}
|
|
34
34
|
catch { /* best-effort */ }
|
|
35
|
-
// 2. Destroy stdin (handle libuv ReadStream)
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
// 2. Destroy stdin (handle libuv ReadStream) — MAS só quando NÃO estamos
|
|
36
|
+
// dentro de um menu interativo.
|
|
37
|
+
//
|
|
38
|
+
// Por quê o guard de isRaw?
|
|
39
|
+
// Quando `runTerminalUi` está ativo, ele faz `stdin.setRawMode(true)`.
|
|
40
|
+
// Se destruirmos stdin aqui (via safeExit chamado por um sub-comando),
|
|
41
|
+
// o `readMenuKey()` fica pendurado para sempre porque seu listener
|
|
42
|
+
// `process.stdin.once('data', ...)` nunca dispara em stdin destruído.
|
|
43
|
+
// Resultado: o top-level `await runTerminalUi()` nunca resolve e o
|
|
44
|
+
// Node emite "Detected unsettled top-level await".
|
|
45
|
+
//
|
|
46
|
+
// Quando stdin.isRaw === true sabemos que estamos dentro do loop do
|
|
47
|
+
// menu; o menu restaura stdin no próprio finally — não precisamos
|
|
48
|
+
// destruir aqui. Fora do menu (CLI normal), isRaw é false/undefined e
|
|
49
|
+
// o destroy garante que handles libuv fechem antes do process.exit().
|
|
50
|
+
if (!process.stdin.isRaw) {
|
|
51
|
+
try {
|
|
52
|
+
process.stdin.destroy();
|
|
53
|
+
}
|
|
54
|
+
catch { /* já fechado */ }
|
|
38
55
|
}
|
|
39
|
-
catch { /* já fechado */ }
|
|
40
56
|
// 3. M-05 fix (Opus review 2026-05-27): NÃO destruir globalAgent.
|
|
41
57
|
// Antes destruíamos http.globalAgent.destroy() + https.globalAgent.destroy()
|
|
42
58
|
// pra fechar keep-alive sockets — mas isso quebrava telemetria flush
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safe-exit.js","sourceRoot":"","sources":["../../src/utils/safe-exit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,SAAS,cAAc;IACrB,gEAAgE;IAChE,IAAI,CAAC;QAAC,eAAe,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAEtD,
|
|
1
|
+
{"version":3,"file":"safe-exit.js","sourceRoot":"","sources":["../../src/utils/safe-exit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,SAAS,cAAc;IACrB,gEAAgE;IAChE,IAAI,CAAC;QAAC,eAAe,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAEtD,yEAAyE;IACzE,mCAAmC;IACnC,EAAE;IACF,+BAA+B;IAC/B,0EAA0E;IAC1E,0EAA0E;IAC1E,sEAAsE;IACtE,yEAAyE;IACzE,sEAAsE;IACtE,sDAAsD;IACtD,EAAE;IACF,uEAAuE;IACvE,qEAAqE;IACrE,yEAAyE;IACzE,yEAAyE;IACzE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAC7D,CAAC;IAED,kEAAkE;IAClE,gFAAgF;IAChF,wEAAwE;IACxE,0EAA0E;IAC1E,mEAAmE;IACnE,uEAAuE;IACvE,wEAAwE;IACxE,0EAA0E;AAC5E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,cAAc,EAAE,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,cAAc,EAAE,CAAC;IACjB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC1B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neetru/cli",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Neetru Developer Kit — scaffold, AI assistant, publish, build e deploy de produtos SaaS Neetru via Core (VM-based agents)",
|
|
6
6
|
"keywords": [
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@anthropic-ai/sdk": "^0.96.0",
|
|
44
|
-
"@neetru/db-classifier": "^0.1.
|
|
44
|
+
"@neetru/db-classifier": "^0.1.2",
|
|
45
45
|
"chalk": "^5.4.1",
|
|
46
46
|
"commander": "^12.1.0",
|
|
47
47
|
"conf": "^13.0.1",
|