@pathbit/agentdevkit 0.0.26 → 0.0.28
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/.pbai4devs/rules/git/RULE.md +5 -2
- package/.pbai4devs/scripts/README.md +3 -2
- package/.pbai4devs/scripts/executar-script/README.md +23 -0
- package/.pbai4devs/scripts/preparar-ferramentas/BOOTSTRAP.md +4 -1
- package/.pbai4devs/scripts/preparar-ferramentas/BOOTSTRAP.mjs +45 -4
- package/.pbai4devs/scripts/preparar-ferramentas/tests/bootstrap.test.mjs +158 -4
- package/.pbai4devs/skills/git/git-diff/SKILL.md +4 -3
- package/.pbai4devs/skills/git/git-status/SKILL.md +4 -2
- package/.pbai4devs/skills/projeto/executar-script/SKILL.md +23 -13
- package/CHANGELOG.md +13 -0
- package/package.json +1 -1
|
@@ -6,8 +6,11 @@ description: Aplique ao consultar, preparar, integrar ou publicar alterações G
|
|
|
6
6
|
# Regras Git
|
|
7
7
|
|
|
8
8
|
Em consultas sem alterações, defina `GIT_OPTIONAL_LOCKS=0` no ambiente do
|
|
9
|
-
subprocesso para
|
|
10
|
-
|
|
9
|
+
subprocesso para reduzir atualizações opcionais. Isso não garante a preservação
|
|
10
|
+
exata do índice: até `git diff` pode atualizá-lo. Quando essa preservação for
|
|
11
|
+
exigida, use apenas métodos comprovadamente seguros para o repositório ou
|
|
12
|
+
informe a limitação. A variável não substitui as travas necessárias para
|
|
13
|
+
operações que alteram o Git.
|
|
11
14
|
|
|
12
15
|
Use Conventional Commits (`tipo(escopo): descrição`, escopo opcional), inclusive
|
|
13
16
|
em checkpoints e merges; destaque mudanças incompatíveis com `!` ou
|
|
@@ -10,8 +10,9 @@ comando em macOS, Linux e Windows. Bun não faz parte do contrato validado.
|
|
|
10
10
|
Versione scripts e testes; salve somente resultados em `.agent-tests/`.
|
|
11
11
|
Prepare ferramentas locais com `preparar-ferramentas`, sem instalações globais.
|
|
12
12
|
O runtime da aplicação será decidido no design doc; este requisito é dos agentes.
|
|
13
|
-
Com Node 18+,
|
|
14
|
-
com `--runtime-only`
|
|
13
|
+
Com Node 18+, o [bootstrap JavaScript](preparar-ferramentas/BOOTSTRAP.md)
|
|
14
|
+
prepara Node 24+ com `--runtime-only` ou encadeia preparo, diagnóstico e seleção
|
|
15
|
+
com [`--executar`](executar-script/README.md).
|
|
15
16
|
Sem Node/npm, o agente instala primeiro pelo mecanismo do sistema operacional.
|
|
16
17
|
Não há inicializadores `.sh` ou `.ps1` no kit.
|
|
17
18
|
|
|
@@ -7,6 +7,29 @@ description: Executor comum dos scripts Node do projeto.
|
|
|
7
7
|
Use Node 24+ com o nome de uma pasta em `.pbai4devs/scripts/`, uma pasta do
|
|
8
8
|
repositório ou o caminho de um arquivo `.mjs`. O comando funciona nos três SOs:
|
|
9
9
|
|
|
10
|
+
```console
|
|
11
|
+
cd .pbai4devs/scripts/preparar-ferramentas
|
|
12
|
+
node BOOTSTRAP.mjs --executar --plan preparar-ferramentas
|
|
13
|
+
node BOOTSTRAP.mjs --executar preparar-ferramentas list
|
|
14
|
+
cd ../../..
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`--executar` prepara Node/npm, diagnostica e só então chama o seletor. Falha
|
|
18
|
+
no diagnóstico interrompe a operação, inclusive se houver configuração de
|
|
19
|
+
ferramenta inválida sem relação com o alvo; inspecione a falha. Diagnóstico com
|
|
20
|
+
sucesso indica inventário concluído, não que todas as dependências do alvo estão
|
|
21
|
+
prontas. Com `--no-install`, o bootstrap usa o runtime atual, o primeiro Node
|
|
22
|
+
do PATH ou o cache, desde que compatível, sem baixar ou instalar o runtime.
|
|
23
|
+
Essa opção não restringe rede nem
|
|
24
|
+
instalações pelo diagnóstico ou script filho. O plano também não baixa, instala
|
|
25
|
+
nem diagnostica, e usa as mesmas opções de runtime.
|
|
26
|
+
O alvo, seus argumentos e o código de saída são preservados.
|
|
27
|
+
Na saída padrão, `--executar` reúne o caminho do runtime, o diagnóstico, o
|
|
28
|
+
cabeçalho do seletor e a saída do alvo; ela não é um JSON único nem uma saída
|
|
29
|
+
bruta do alvo. O seletor direto também inclui seu próprio cabeçalho.
|
|
30
|
+
|
|
31
|
+
Com Node 24+ já disponível, o seletor pode ser chamado diretamente:
|
|
32
|
+
|
|
10
33
|
```console
|
|
11
34
|
node .pbai4devs/scripts/executar-script/SCRIPT.mjs --plan preparar-ferramentas
|
|
12
35
|
node .pbai4devs/scripts/executar-script/SCRIPT.mjs preparar-ferramentas list
|
|
@@ -15,7 +15,10 @@ node .pbai4devs/scripts/preparar-ferramentas/BOOTSTRAP.mjs --runtime-only
|
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
O modo `--runtime-only` imprime `node=<caminho absoluto>` sem instalar
|
|
18
|
-
ferramentas. Sem
|
|
18
|
+
ferramentas. Sem opções, continua com `setup`; aceita grupo ou nome.
|
|
19
|
+
Para preparar o runtime, diagnosticar e executar um script em sequência, veja
|
|
20
|
+
[`--executar`](../executar-script/README.md). O plano e `--no-install` não
|
|
21
|
+
baixam o runtime; não restringem efeitos dos processos que forem executados.
|
|
19
22
|
|
|
20
23
|
O fluxo reutiliza um runtime saudável ou o cache local. Se necessário, baixa
|
|
21
24
|
Node 24 de `nodejs.org`, verifica SHA-256 e extrai usando `tar` nativo.
|
|
@@ -109,7 +109,7 @@ export function validateExtracted(root) {
|
|
|
109
109
|
visit(base);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
export async function ensureRuntime({ root = projectRoot, minimum = 24, node = process.execPath, platform = process.platform, arch = process.arch, libc, run = spawnSync, download = downloadOfficial, environment = process.env } = {}) {
|
|
112
|
+
export async function ensureRuntime({ root = projectRoot, minimum = 24, node = process.execPath, platform = process.platform, arch = process.arch, libc, run = spawnSync, download = downloadOfficial, environment = process.env, allowDownload = true, searchPath = false } = {}) {
|
|
113
113
|
if (Number(process.versions.node.split('.')[0]) < 18) failure('O inicializador requer Node.js 18+; instale Node.js 24+ pelo gerenciador do SO.');
|
|
114
114
|
root = realpathSync(root);
|
|
115
115
|
const current = probe(node, minimum, run, environment);
|
|
@@ -117,6 +117,12 @@ export async function ensureRuntime({ root = projectRoot, minimum = 24, node = p
|
|
|
117
117
|
const npm = npmFor(current.node, run, environment, platform);
|
|
118
118
|
if (npm) return { node: current.node, npm, version: current.version, source: 'current' };
|
|
119
119
|
}
|
|
120
|
+
if (searchPath) {
|
|
121
|
+
const executable = findExecutable('node', environment, platform);
|
|
122
|
+
const found = executable && probe(executable, minimum, run, environment);
|
|
123
|
+
const npm = found && npmFor(found.node, run, environment, platform);
|
|
124
|
+
if (found && npm) return { node: found.node, npm, version: found.version, source: 'path' };
|
|
125
|
+
}
|
|
120
126
|
const targetPlatform = platformName(platform, arch, run, environment, libc);
|
|
121
127
|
const cache = safePath(root, ['.pbai4devs', 'tools', '.cache', 'runtime', 'node', targetPlatform]);
|
|
122
128
|
if (stat(cache) && !stat(cache).isDirectory()) failure('Cache de runtime nao e diretorio.');
|
|
@@ -126,6 +132,7 @@ export async function ensureRuntime({ root = projectRoot, minimum = 24, node = p
|
|
|
126
132
|
const found = probe(executable, minimum, run, environment);
|
|
127
133
|
if (found) { const npm = npmFor(executable, run, environment, platform, true); if (npm) return { node: executable, npm, version: found.version, source: 'cache' }; }
|
|
128
134
|
}
|
|
135
|
+
if (!allowDownload) failure('Node.js 24+ e npm nao encontrados; prepare o runtime antes de continuar.');
|
|
129
136
|
const tar = findExecutable('tar', environment, platform);
|
|
130
137
|
if (!tar) failure('Instale tar pelo gerenciador do SO para extrair o Node local.');
|
|
131
138
|
mkdirSync(cache, { recursive: true });
|
|
@@ -170,11 +177,42 @@ export async function ensureRuntime({ root = projectRoot, minimum = 24, node = p
|
|
|
170
177
|
|
|
171
178
|
export async function main(args = process.argv.slice(2), options = {}) {
|
|
172
179
|
const runtimeOnly = args[0] === '--runtime-only';
|
|
180
|
+
const execute = args[0] === '--executar';
|
|
181
|
+
const selected = execute ? args.slice(1) : [];
|
|
182
|
+
let plan = false, noInstall = false;
|
|
183
|
+
while (execute && ['--plan', '--no-install'].includes(selected[0])) {
|
|
184
|
+
if (selected[0] === '--plan') { if (plan) failure('--plan duplicado.'); plan = true; }
|
|
185
|
+
else { if (noInstall) failure('--no-install duplicado.'); noInstall = true; }
|
|
186
|
+
selected.shift();
|
|
187
|
+
}
|
|
173
188
|
if (runtimeOnly && args.length !== 1) failure('--runtime-only nao aceita selecao ou outros argumentos.');
|
|
174
|
-
if (
|
|
175
|
-
|
|
189
|
+
if (execute && !selected[0]) failure('Use --executar [--no-install] [--plan] <nome-ou-caminho> [argumentos].');
|
|
190
|
+
if (!runtimeOnly && !execute && args.some(arg => arg.startsWith('-'))) failure('Use --runtime-only ou uma selecao de ferramentas.');
|
|
191
|
+
if (execute && ['--help', '-h'].includes(selected[0])) {
|
|
192
|
+
process.stdout.write('Uso: --executar [--no-install] [--plan] <nome-ou-caminho> [argumentos]\n');
|
|
193
|
+
return 0;
|
|
194
|
+
}
|
|
195
|
+
if (execute) {
|
|
196
|
+
const { resolveScript } = await import('../executar-script/SCRIPT.mjs');
|
|
197
|
+
resolveScript(selected[0], { root: options.root || projectRoot });
|
|
198
|
+
}
|
|
199
|
+
const runtime = await ensureRuntime({ ...options, allowDownload: !plan && !noInstall, searchPath: execute });
|
|
176
200
|
process.stdout.write(`node=${runtime.node}\n`);
|
|
177
201
|
if (runtimeOnly) return 0;
|
|
202
|
+
if (execute) {
|
|
203
|
+
const run = options.run || spawnSync;
|
|
204
|
+
const root = options.root || projectRoot;
|
|
205
|
+
const env = environmentWithNode(options.environment || process.env, runtime.node);
|
|
206
|
+
const processOptions = { stdio: 'inherit', env, cwd: root, windowsHide: true };
|
|
207
|
+
if (!plan) {
|
|
208
|
+
const diagnostic = run(runtime.node, [join(root, '.pbai4devs/scripts/diagnosticar-ambiente/SCRIPT.mjs')], processOptions);
|
|
209
|
+
if (diagnostic.error) throw diagnostic.error;
|
|
210
|
+
if (diagnostic.status !== 0) return diagnostic.status ?? 1;
|
|
211
|
+
}
|
|
212
|
+
const result = run(runtime.node, [join(root, '.pbai4devs/scripts/executar-script/SCRIPT.mjs'), ...(plan ? ['--plan'] : []), ...selected], processOptions);
|
|
213
|
+
if (result.error) throw result.error;
|
|
214
|
+
return result.status ?? 1;
|
|
215
|
+
}
|
|
178
216
|
const result = (options.run || spawnSync)(runtime.node, [join(options.root || projectRoot, '.pbai4devs/scripts/preparar-ferramentas/SCRIPT.mjs'), 'setup', ...args], { stdio: 'inherit', env: environmentWithNode(options.environment || process.env, runtime.node) });
|
|
179
217
|
if (result.error) throw result.error;
|
|
180
218
|
return result.status ?? 1;
|
|
@@ -185,5 +223,8 @@ function isEntrypoint() {
|
|
|
185
223
|
catch { return false; }
|
|
186
224
|
}
|
|
187
225
|
if (isEntrypoint()) {
|
|
188
|
-
try { process.exitCode = await main(); } catch (error) {
|
|
226
|
+
try { process.exitCode = await main(); } catch (error) {
|
|
227
|
+
console.error(`bootstrap: ${error.message}`);
|
|
228
|
+
process.exitCode = Number.isInteger(error.exitCode) && error.exitCode >= 1 && error.exitCode <= 255 ? error.exitCode : 1;
|
|
229
|
+
}
|
|
189
230
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import test from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
|
-
import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
5
|
-
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { dirname, join, resolve, sep } from 'node:path';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
6
7
|
import { fileURLToPath } from 'node:url';
|
|
7
8
|
import { spawnSync } from 'node:child_process';
|
|
8
9
|
import { ensureRuntime, main, validateArchive, validateExtracted } from '../BOOTSTRAP.mjs';
|
|
@@ -29,7 +30,7 @@ function fixture(t) {
|
|
|
29
30
|
let manifest = `${checksum} ${top}.${extension}\n`, calls = 0;
|
|
30
31
|
const run = (file, args, options) => {
|
|
31
32
|
if (args[0] === '-p') {
|
|
32
|
-
if (!existsSync(file) || readFileSync(file, 'utf8') !== 'fixture-node') return { status: 1, stdout: '' };
|
|
33
|
+
if (!file.startsWith(root + sep) || !existsSync(file) || readFileSync(file, 'utf8') !== 'fixture-node') return { status: 1, stdout: '' };
|
|
33
34
|
return { status: 0, stdout: JSON.stringify({ version: '24.1.2', node: file, bun: false }) };
|
|
34
35
|
}
|
|
35
36
|
if (args[1] === '--version') return { status: existsSync(args[0]) && readFileSync(args[0], 'utf8') === 'fixture-npm' ? 0 : 1, stdout: '11.0.0\n' };
|
|
@@ -37,7 +38,7 @@ function fixture(t) {
|
|
|
37
38
|
};
|
|
38
39
|
const options = { root, node: join(root, 'missing-node'), platform, arch, libc: 'glibc', run,
|
|
39
40
|
download: async (url, destination) => { calls++; if (url.endsWith('SHASUMS256.txt')) writeFileSync(destination, manifest); else copyFileSync(archive, destination); } };
|
|
40
|
-
return { root, options, archive, key, cache: join(root, '.pbai4devs/tools/.cache/runtime/node', key), setManifest: value => { manifest = value; }, calls: () => calls };
|
|
41
|
+
return { root, options, archive, key, cache: join(root, '.pbai4devs/tools/.cache/runtime/node', key), script: name => write(join(root, '.pbai4devs/scripts', name, 'SCRIPT.mjs'), ''), setManifest: value => { manifest = value; }, calls: () => calls };
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
test('bootstrap Node extrai arquivo real, verifica npm e reutiliza cache sem rede', async t => {
|
|
@@ -92,3 +93,156 @@ test('runtime atual saudável não altera PATH nem grava cache', async t => {
|
|
|
92
93
|
const result = await ensureRuntime({ root: f.root, minimum: Number(process.versions.node.split('.')[0]) });
|
|
93
94
|
assert.equal(result.source, 'current'); assert.equal(process.env.PATH, original); assert.equal(existsSync(f.cache), false);
|
|
94
95
|
});
|
|
96
|
+
|
|
97
|
+
test('entrada única prepara runtime, diagnostica e encaminha argumentos e status sem shell', async t => {
|
|
98
|
+
const f = fixture(t), calls = [];
|
|
99
|
+
f.script('script com espaços');
|
|
100
|
+
const args = ['script com espaços', '--flag', 'valor com espaços', '$(não executar)', '', '--', 'final'];
|
|
101
|
+
const options = { ...f.options, run: (file, argv, settings) => {
|
|
102
|
+
if (argv[0] === '-p' || argv[1] === '--version' || file === tar) return f.options.run(file, argv, settings);
|
|
103
|
+
calls.push({ file, argv, settings });
|
|
104
|
+
return { status: calls.length === 1 ? 0 : 69 };
|
|
105
|
+
} };
|
|
106
|
+
assert.equal(await main(['--executar', ...args], options), 69);
|
|
107
|
+
assert.equal(f.calls(), 2);
|
|
108
|
+
assert.equal(calls.length, 2);
|
|
109
|
+
assert.equal(calls[0].file, calls[1].file);
|
|
110
|
+
assert.deepEqual(calls[0].argv, [join(f.root, '.pbai4devs/scripts/diagnosticar-ambiente/SCRIPT.mjs')]);
|
|
111
|
+
assert.deepEqual(calls[1].argv, [join(f.root, '.pbai4devs/scripts/executar-script/SCRIPT.mjs'), ...args]);
|
|
112
|
+
assert.equal(calls[0].settings.cwd, f.root);
|
|
113
|
+
assert.equal(calls[1].settings.cwd, f.root);
|
|
114
|
+
assert.equal(calls[1].settings.shell, undefined);
|
|
115
|
+
assert.equal(calls[1].settings.stdio, 'inherit');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('falha de diagnóstico impede execução e propaga status', async t => {
|
|
119
|
+
const f = fixture(t), calls = [];
|
|
120
|
+
f.script('qualquer');
|
|
121
|
+
const options = { ...f.options, run: (file, argv, settings) => {
|
|
122
|
+
if (argv[0] === '-p' || argv[1] === '--version' || file === tar) return f.options.run(file, argv, settings);
|
|
123
|
+
calls.push(argv); return { status: 23 };
|
|
124
|
+
} };
|
|
125
|
+
assert.equal(await main(['--executar', 'qualquer'], options), 23);
|
|
126
|
+
assert.equal(calls.length, 1);
|
|
127
|
+
assert.equal(calls[0][0], join(f.root, '.pbai4devs/scripts/diagnosticar-ambiente/SCRIPT.mjs'));
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('plano não instala nem diagnostica; usa apenas runtime disponível', async t => {
|
|
131
|
+
const f = fixture(t), calls = [];
|
|
132
|
+
f.script('qualquer');
|
|
133
|
+
await assert.rejects(main(['--executar', '--plan', 'qualquer'], f.options), /prepare o runtime/);
|
|
134
|
+
assert.equal(f.calls(), 0);
|
|
135
|
+
assert.equal(existsSync(f.cache), false);
|
|
136
|
+
await ensureRuntime(f.options);
|
|
137
|
+
const callsBefore = f.calls();
|
|
138
|
+
const options = { ...f.options, download: async () => { throw new Error('rede indevida'); }, run: (file, argv, settings) => {
|
|
139
|
+
if (argv[0] === '-p' || argv[1] === '--version' || file === tar) return f.options.run(file, argv, settings);
|
|
140
|
+
calls.push(argv); return { status: 0 };
|
|
141
|
+
} };
|
|
142
|
+
assert.equal(await main(['--executar', '--plan', 'qualquer', 'argumento'], options), 0);
|
|
143
|
+
assert.equal(f.calls(), callsBefore);
|
|
144
|
+
assert.deepEqual(calls, [[join(f.root, '.pbai4devs/scripts/executar-script/SCRIPT.mjs'), '--plan', 'qualquer', 'argumento']]);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('--no-install falha sem runtime e usa cache sem rede; preserva flag do alvo', async t => {
|
|
148
|
+
const f = fixture(t), calls = [];
|
|
149
|
+
f.script('alvo');
|
|
150
|
+
await assert.rejects(main(['--executar', '--no-install', 'alvo'], f.options), /prepare o runtime/);
|
|
151
|
+
assert.equal(f.calls(), 0);
|
|
152
|
+
assert.equal(existsSync(f.cache), false);
|
|
153
|
+
await ensureRuntime(f.options);
|
|
154
|
+
const options = { ...f.options, download: async () => { throw new Error('rede indevida'); }, run: (file, argv, settings) => {
|
|
155
|
+
if (argv[0] === '-p' || argv[1] === '--version' || file === tar) return f.options.run(file, argv, settings);
|
|
156
|
+
calls.push(argv); return { status: 0 };
|
|
157
|
+
} };
|
|
158
|
+
assert.equal(await main(['--executar', '--no-install', 'alvo', '--no-install'], options), 0);
|
|
159
|
+
assert.equal(calls.length, 2);
|
|
160
|
+
assert.deepEqual(calls[1], [join(f.root, '.pbai4devs/scripts/executar-script/SCRIPT.mjs'), 'alvo', '--no-install']);
|
|
161
|
+
calls.length = 0;
|
|
162
|
+
assert.equal(await main(['--executar', '--plan', '--no-install', 'alvo'], options), 0);
|
|
163
|
+
assert.deepEqual(calls, [[join(f.root, '.pbai4devs/scripts/executar-script/SCRIPT.mjs'), '--plan', 'alvo']]);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('modo novo encontra Node 24 no PATH com espaços sem baixar runtime', async t => {
|
|
167
|
+
const f = fixture(t), calls = [], bin = join(f.root, 'bin com espaços');
|
|
168
|
+
f.script('alvo');
|
|
169
|
+
mkdirSync(join(bin, 'node_modules/npm/bin'), { recursive: true });
|
|
170
|
+
const executable = join(bin, process.platform === 'win32' ? 'node.exe' : 'node');
|
|
171
|
+
writeFileSync(executable, 'fixture-node');
|
|
172
|
+
if (process.platform !== 'win32') chmodSync(executable, 0o755);
|
|
173
|
+
writeFileSync(join(bin, 'node_modules/npm/bin/npm-cli.js'), 'fixture-npm');
|
|
174
|
+
const options = { ...f.options, environment: { PATH: bin }, download: async () => { throw new Error('rede indevida'); }, run: (file, argv, settings) => {
|
|
175
|
+
if (argv[0] === '-p' || argv[1] === '--version') return f.options.run(file, argv, settings);
|
|
176
|
+
calls.push({ file, argv }); return { status: 0 };
|
|
177
|
+
} };
|
|
178
|
+
const runtime = await ensureRuntime({ ...options, searchPath: true, allowDownload: false });
|
|
179
|
+
assert.equal(runtime.source, 'path');
|
|
180
|
+
assert.equal(runtime.node, executable);
|
|
181
|
+
assert.equal(await main(['--executar', '--no-install', 'alvo', 'argumento com espaços'], options), 0);
|
|
182
|
+
assert.equal(calls.length, 2);
|
|
183
|
+
assert.equal(calls[1].file, executable);
|
|
184
|
+
assert.deepEqual(calls[1].argv.slice(-2), ['alvo', 'argumento com espaços']);
|
|
185
|
+
assert.equal(existsSync(f.cache), false);
|
|
186
|
+
assert.equal(f.calls(), 0);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('entrada única sem alvo falha antes de preparar runtime', async t => {
|
|
190
|
+
const f = fixture(t);
|
|
191
|
+
for (const args of [['--executar'], ['--executar', '--plan'], ['--executar', '--no-install'], ['--executar', '--plan', '--no-install']]) await assert.rejects(main(args, f.options), /nome-ou-caminho/);
|
|
192
|
+
assert.equal(f.calls(), 0);
|
|
193
|
+
assert.equal(existsSync(f.cache), false);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test('ajuda não procura runtime, acessa rede ou inicia diagnóstico', async t => {
|
|
197
|
+
const f = fixture(t), unexpected = [];
|
|
198
|
+
const options = { ...f.options, run: (...args) => { unexpected.push(args); return f.options.run(...args); } };
|
|
199
|
+
for (const args of [['--executar', '--help'], ['--executar', '-h'], ['--executar', '--no-install', '--plan', '--help']]) assert.equal(await main(args, options), 0);
|
|
200
|
+
assert.equal(unexpected.length, 0);
|
|
201
|
+
assert.equal(f.calls(), 0);
|
|
202
|
+
assert.equal(existsSync(f.cache), false);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test('alvo ou configuração inválida falha antes de runtime, rede e diagnóstico', async t => {
|
|
206
|
+
const f = fixture(t), scripts = join(f.root, '.pbai4devs/scripts');
|
|
207
|
+
const invalid = join(scripts, 'invalido'); mkdirSync(invalid, { recursive: true });
|
|
208
|
+
writeFileSync(join(invalid, 'SCRIPT.mjs'), '');
|
|
209
|
+
writeFileSync(join(invalid, 'SCRIPT.conf'), 'executor=desconhecido\n');
|
|
210
|
+
writeFileSync(join(f.root, 'shell.sh'), '');
|
|
211
|
+
const unexpected = [];
|
|
212
|
+
const options = { ...f.options, run: (...args) => { unexpected.push(args); return f.options.run(...args); } };
|
|
213
|
+
for (const target of ['ausente', 'invalido', 'shell.sh', '../fora.mjs']) {
|
|
214
|
+
await assert.rejects(main(['--executar', target], options), /ausente|SCRIPT.conf|JavaScript|fora/);
|
|
215
|
+
}
|
|
216
|
+
assert.equal(unexpected.length, 0);
|
|
217
|
+
assert.equal(f.calls(), 0);
|
|
218
|
+
assert.equal(existsSync(f.cache), false);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test('CLI preserva código do seletor quando alvo não existe', t => {
|
|
222
|
+
const f = fixture(t), target = join(f.root, 'ausente.mjs');
|
|
223
|
+
const selector = join(project, '.pbai4devs/scripts/executar-script/SCRIPT.mjs');
|
|
224
|
+
const bootstrap = join(project, '.pbai4devs/scripts/preparar-ferramentas/BOOTSTRAP.mjs');
|
|
225
|
+
const direct = spawnSync(process.execPath, [selector, target], { encoding: 'utf8', timeout: 30000 });
|
|
226
|
+
const viaBootstrap = spawnSync(process.execPath, [bootstrap, '--executar', target], { encoding: 'utf8', timeout: 30000 });
|
|
227
|
+
assert.equal(direct.status, 2, direct.stderr);
|
|
228
|
+
assert.equal(viaBootstrap.status, direct.status, viaBootstrap.stderr);
|
|
229
|
+
assert.match(viaBootstrap.stderr, /ausente/);
|
|
230
|
+
assert.doesNotMatch(viaBootstrap.stdout, /node=/);
|
|
231
|
+
assert.equal(existsSync(f.cache), false);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('diagnóstico real bem-sucedido não garante dependências do alvo', { timeout: 180000 }, t => {
|
|
235
|
+
const root = mkdtempSync(join(tmpdir(), 'adk-bootstrap-integration-'));
|
|
236
|
+
t.after(() => rmSync(root, { recursive: true, force: true }));
|
|
237
|
+
const cli = spawnSync(process.execPath, [join(project, 'bin/agentdevkit.mjs'), 'init', '--agents', 'codex', '--target', root, '--json'], { encoding: 'utf8', timeout: 120000 });
|
|
238
|
+
assert.equal(cli.status, 0, `${cli.error?.message || ''}\n${cli.stderr}\n${cli.stdout}`);
|
|
239
|
+
const target = join(root, 'probe.cjs');
|
|
240
|
+
writeFileSync(target, `const {spawnSync}=require('node:child_process'); const p=spawnSync('adk-tool-nao-existe-197834',[]); console.log('DEPENDENCIA_AUSENTE='+(p.error?.code==='ENOENT')); process.exit(29);\n`);
|
|
241
|
+
const environment = { ...process.env, PATH: dirname(process.execPath), Path: dirname(process.execPath) };
|
|
242
|
+
const bootstrap = join(root, '.pbai4devs/scripts/preparar-ferramentas/BOOTSTRAP.mjs');
|
|
243
|
+
const result = spawnSync(process.execPath, [bootstrap, '--executar', '--no-install', 'probe.cjs'], { cwd: root, env: environment, encoding: 'utf8', timeout: 30000, maxBuffer: 4 * 1024 * 1024 });
|
|
244
|
+
assert.equal(result.status, 29, `${result.error?.message || ''}\n${result.stderr}\n${result.stdout}`);
|
|
245
|
+
assert.match(result.stdout, /"tools"\s*:/);
|
|
246
|
+
assert.match(result.stdout, /runtime=node/);
|
|
247
|
+
assert.match(result.stdout, /DEPENDENCIA_AUSENTE=true/);
|
|
248
|
+
});
|
|
@@ -6,6 +6,7 @@ description: Examina e resume alterações Git.
|
|
|
6
6
|
# git-diff
|
|
7
7
|
|
|
8
8
|
Examine os diffs preparados e não preparados conforme o pedido, incluindo
|
|
9
|
-
arquivos não rastreados quando relevantes.
|
|
10
|
-
|
|
11
|
-
não
|
|
9
|
+
arquivos não rastreados quando relevantes. Use `GIT_OPTIONAL_LOCKS=0` nas
|
|
10
|
+
consultas, mas não presuma que preserve os bytes do índice: `git diff` ainda
|
|
11
|
+
pode atualizá-lo. Se a preservação exata for exigida, não execute uma consulta
|
|
12
|
+
sem método comprovadamente seguro para o repositório; informe a limitação.
|
|
@@ -6,5 +6,7 @@ description: Inspeciona o estado do repositório e das branches locais e remotas
|
|
|
6
6
|
# git-status
|
|
7
7
|
|
|
8
8
|
Mostre branch, alterações preparadas e não preparadas, arquivos não rastreados e
|
|
9
|
-
divergência do upstream.
|
|
10
|
-
|
|
9
|
+
divergência do upstream. Use `GIT_OPTIONAL_LOCKS=0` nas consultas, sem presumir
|
|
10
|
+
que isso garanta a preservação exata dos bytes do índice. Se ela for exigida,
|
|
11
|
+
use apenas um método comprovadamente seguro para o repositório ou informe a
|
|
12
|
+
limitação.
|
|
@@ -5,20 +5,30 @@ description: Identifica ferramentas instaladas e executa scripts pelo interpreta
|
|
|
5
5
|
|
|
6
6
|
# Executar script
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
com `--runtime-only` para preparar o núcleo. Sem Node, instale-o primeiro
|
|
11
|
-
pelo mecanismo nativo do SO. Preserve a operação originalmente solicitada.
|
|
12
|
-
Faça o preparo pelo usuário e reutilize o caminho absoluto informado, sem
|
|
13
|
-
depender de PATH global. Execute
|
|
14
|
-
`diagnosticar-ambiente` pelo seletor de [scripts](../../../scripts/README.md).
|
|
15
|
-
Reutilize a verificação enquanto o ambiente não mudar.
|
|
8
|
+
Com Node 18+ e npm, use o bootstrap para preparar Node 24+, diagnosticar e
|
|
9
|
+
executar o script solicitado, nessa ordem:
|
|
16
10
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
o
|
|
11
|
+
```sh
|
|
12
|
+
node .pbai4devs/scripts/preparar-ferramentas/BOOTSTRAP.mjs --executar <script> [argumentos...]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Se o diagnóstico falhar, inspecione a causa; o script não é executado. Seu
|
|
16
|
+
sucesso indica inventário concluído, não dependências necessariamente prontas.
|
|
17
|
+
`--executar --no-install`
|
|
18
|
+
evita apenas o download e instalação do runtime; usa o atual, o primeiro Node
|
|
19
|
+
do PATH ou o cache, se compatível. Não restringe o diagnóstico ou script filho.
|
|
20
|
+
Quando rede ou
|
|
21
|
+
instalações forem proibidas, só execute etapas comprovadamente compatíveis com
|
|
22
|
+
essas restrições ou use isolamento adequado. Sem Node/npm, instale-os pelo
|
|
23
|
+
mecanismo do SO quando autorizado. Preserve a operação e os argumentos pedidos.
|
|
24
|
+
|
|
25
|
+
Prefira scripts existentes. Use `--executar --plan <script>` para consultar a
|
|
26
|
+
execução sem instalar nem diagnosticar; o plano usa as mesmas opções de runtime.
|
|
27
|
+
Confira pré-requisitos, efeitos e autorização, e execute sem `--plan`.
|
|
28
|
+
O seletor direto continua disponível e não faz preparo nem diagnóstico.
|
|
29
|
+
O bootstrap reúne na saída informações do runtime, diagnóstico e execução;
|
|
30
|
+
identifique cada trecho antes de relatar o resultado do script.
|
|
31
|
+
Consulte a [referência](../../../scripts/executar-script/README.md).
|
|
22
32
|
|
|
23
33
|
Se indicar `playwright-mcp`, use o conector conforme a
|
|
24
34
|
[referência](../../../scripts/testar-navegador/REFERENCE.md). Não execute esse
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ description: Alterações verificáveis por versão do AgentDevKit.
|
|
|
4
4
|
|
|
5
5
|
# Changelog
|
|
6
6
|
|
|
7
|
+
## 0.0.28 — 2026-11-14
|
|
8
|
+
|
|
9
|
+
- Encadeia preparo do runtime, diagnóstico e execução por `--executar`, com
|
|
10
|
+
plano somente de leitura e opção de não instalar o runtime.
|
|
11
|
+
- Rejeita alvos inválidos antes de preparar o ambiente e reconhece o primeiro
|
|
12
|
+
Node compatível no PATH; documenta os limites de saída e isolamento.
|
|
13
|
+
|
|
14
|
+
## 0.0.27 — 2026-11-14
|
|
15
|
+
|
|
16
|
+
- Esclarece que desativar locks opcionais não garante a preservação dos bytes
|
|
17
|
+
do índice Git e orienta a interromper consultas sem método seguro comprovado.
|
|
18
|
+
- Delimita a garantia do teste de consultas à fixture realmente exercitada.
|
|
19
|
+
|
|
7
20
|
## 0.0.26 — 2026-11-14
|
|
8
21
|
|
|
9
22
|
- Preserva os bytes do índice nas consultas do gate para os casos suportados e
|