@pathbit/agentdevkit 0.0.0-stage → 0.0.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/.pbai4devs/COMPATIBILIDADE.md +109 -0
- package/.pbai4devs/INSTRUCTIONS.md +87 -0
- package/.pbai4devs/README.md +50 -0
- package/.pbai4devs/agents/README.md +18 -0
- package/.pbai4devs/agents/revisor/AGENT.md +16 -0
- package/.pbai4devs/agents/revisor/antigravity.yaml +8 -0
- package/.pbai4devs/agents/revisor/claude.yaml +5 -0
- package/.pbai4devs/agents/revisor/cursor.yaml +5 -0
- package/.pbai4devs/agents/revisor/gemini.yaml +6 -0
- package/.pbai4devs/agents/revisor/github.yaml +5 -0
- package/.pbai4devs/agents/revisor/kimi-code.yaml +5 -0
- package/.pbai4devs/agents/revisor/mimocode.yaml +10 -0
- package/.pbai4devs/agents/revisor/opencode.yaml +7 -0
- package/.pbai4devs/agents/revisor/zcode.yaml +5 -0
- package/.pbai4devs/commands/README.md +30 -0
- package/.pbai4devs/commands/atualizar-ferramentas/COMMAND.md +17 -0
- package/.pbai4devs/commands/diagnosticar/COMMAND.md +18 -0
- package/.pbai4devs/commands/instalar-ferramentas/COMMAND.md +21 -0
- package/.pbai4devs/commands/preparar-dev/COMMAND.md +14 -0
- package/.pbai4devs/commands/proximos-passos/COMMAND.md +9 -0
- package/.pbai4devs/commands/revisar-entrega/COMMAND.md +29 -0
- package/.pbai4devs/commands/sincronizar/COMMAND.md +20 -0
- package/.pbai4devs/commands/status-roadmap/COMMAND.md +12 -0
- package/.pbai4devs/commands/testar-navegador/COMMAND.md +16 -0
- package/.pbai4devs/commands/verificar-agentes/COMMAND.md +19 -0
- package/.pbai4devs/estado/README.md +12 -0
- package/.pbai4devs/external-skills/CATALOG.json +121 -0
- package/.pbai4devs/external-skills/README.md +48 -0
- package/.pbai4devs/rules/README.md +18 -0
- package/.pbai4devs/rules/ambiente-local/RULE.md +33 -0
- package/.pbai4devs/rules/ambiente-local/cursor.yaml +4 -0
- package/.pbai4devs/rules/documentacao/RULE.md +11 -0
- package/.pbai4devs/rules/documentacao/cursor.yaml +4 -0
- package/.pbai4devs/rules/estrutura/RULE.md +33 -0
- package/.pbai4devs/rules/estrutura/cursor.yaml +4 -0
- package/.pbai4devs/rules/git/RULE.md +18 -0
- package/.pbai4devs/rules/git/cursor.yaml +4 -0
- package/.pbai4devs/rules/proximos-passos/RULE.md +14 -0
- package/.pbai4devs/rules/qualidade/RULE.md +32 -0
- package/.pbai4devs/rules/qualidade/cursor.yaml +4 -0
- package/.pbai4devs/scripts/README.md +69 -0
- package/.pbai4devs/scripts/diagnosticar-ambiente/SCRIPT.mjs +41 -0
- package/.pbai4devs/scripts/diagnosticar-ambiente/tests/TEST.mjs +30 -0
- package/.pbai4devs/scripts/executar-script/README.md +28 -0
- package/.pbai4devs/scripts/executar-script/SCRIPT.mjs +78 -0
- package/.pbai4devs/scripts/executar-script/tests/TEST.mjs +122 -0
- package/.pbai4devs/scripts/gerenciar-skills-externas/README.md +31 -0
- package/.pbai4devs/scripts/gerenciar-skills-externas/SCRIPT.mjs +182 -0
- package/.pbai4devs/scripts/gerenciar-skills-externas/tests/TEST.mjs +134 -0
- package/.pbai4devs/scripts/inspecionar-projeto/SCRIPT.mjs +190 -0
- package/.pbai4devs/scripts/inspecionar-projeto/tests/TEST.mjs +161 -0
- package/.pbai4devs/scripts/lib/README.md +9 -0
- package/.pbai4devs/scripts/lib/adapters.mjs +135 -0
- package/.pbai4devs/scripts/lib/catalog.mjs +170 -0
- package/.pbai4devs/scripts/lib/gitignore.mjs +348 -0
- package/.pbai4devs/scripts/lib/npm.mjs +17 -0
- package/.pbai4devs/scripts/lib/resource-path.mjs +20 -0
- package/.pbai4devs/scripts/lib/runtime.mjs +28 -0
- package/.pbai4devs/scripts/lib/script-config.mjs +8 -0
- package/.pbai4devs/scripts/preparar-ferramentas/BOOTSTRAP.md +34 -0
- package/.pbai4devs/scripts/preparar-ferramentas/BOOTSTRAP.mjs +189 -0
- package/.pbai4devs/scripts/preparar-ferramentas/README.md +71 -0
- package/.pbai4devs/scripts/preparar-ferramentas/SCRIPT.mjs +455 -0
- package/.pbai4devs/scripts/preparar-ferramentas/tests/FIXTURE.html +20 -0
- package/.pbai4devs/scripts/preparar-ferramentas/tests/SMOKE_BROWSER.mjs +55 -0
- package/.pbai4devs/scripts/preparar-ferramentas/tests/SMOKE_DESKTOP.mjs +61 -0
- package/.pbai4devs/scripts/preparar-ferramentas/tests/SMOKE_VERCEL.mjs +192 -0
- package/.pbai4devs/scripts/preparar-ferramentas/tests/TEST.mjs +552 -0
- package/.pbai4devs/scripts/preparar-ferramentas/tests/bootstrap.test.mjs +94 -0
- package/.pbai4devs/scripts/preparar-ferramentas/tests/fixtures-vercel/just-bash/input.txt +2 -0
- package/.pbai4devs/scripts/preparar-ferramentas/tests/fixtures-vercel/just-bash-overlay/input.txt +1 -0
- package/.pbai4devs/scripts/preparar-ferramentas/tests/fixtures-vercel/skills/agentdevkit-smoke/SKILL.md +8 -0
- package/.pbai4devs/scripts/preparar-ferramentas/tests/fixtures-vercel/webreel/index.html +6 -0
- package/.pbai4devs/scripts/preparar-ferramentas/tests/fixtures-vercel/webreel/webreel.config.json +10 -0
- package/.pbai4devs/scripts/revisar-entrega/README.md +36 -0
- package/.pbai4devs/scripts/revisar-entrega/SCRIPT.mjs +249 -0
- package/.pbai4devs/scripts/revisar-entrega/tests/TEST.mjs +249 -0
- package/.pbai4devs/scripts/sincronizar-agentes/README.md +41 -0
- package/.pbai4devs/scripts/sincronizar-agentes/SCRIPT.mjs +473 -0
- package/.pbai4devs/scripts/sincronizar-agentes/tests/LOCAL_IGNORE.mjs +290 -0
- package/.pbai4devs/scripts/sincronizar-agentes/tests/TEST.mjs +869 -0
- package/.pbai4devs/scripts/testar-infraestrutura/SCRIPT.mjs +39 -0
- package/.pbai4devs/scripts/testar-infraestrutura/tests/TEST.mjs +29 -0
- package/.pbai4devs/scripts/testar-maturidade/README.md +54 -0
- package/.pbai4devs/scripts/testar-maturidade/SCRIPT.mjs +477 -0
- package/.pbai4devs/scripts/testar-maturidade/assets/calculator.mjs +1 -0
- package/.pbai4devs/scripts/testar-maturidade/assets/calculator.test.mjs.template +8 -0
- package/.pbai4devs/scripts/testar-maturidade/assets/http-api.test.mjs.template +28 -0
- package/.pbai4devs/scripts/testar-maturidade/assets/server.mjs +34 -0
- package/.pbai4devs/scripts/testar-maturidade/tests/TEST.mjs +305 -0
- package/.pbai4devs/scripts/testar-navegador/REFERENCE.md +49 -0
- package/.pbai4devs/scripts/testar-navegador/SCRIPT.conf +1 -0
- package/.pbai4devs/scripts/testar-navegador/SCRIPT.js +64 -0
- package/.pbai4devs/scripts/testar-navegador/tests/FAIL.js +8 -0
- package/.pbai4devs/scripts/testar-navegador/tests/SUCCESS.js +13 -0
- package/.pbai4devs/scripts/verificar-recursos/README.md +25 -0
- package/.pbai4devs/scripts/verificar-recursos/SCRIPT.mjs +209 -0
- package/.pbai4devs/scripts/verificar-recursos/tests/TEST.mjs +310 -0
- package/.pbai4devs/scripts/verificar-recursos/tests/ambiente-local.mjs +80 -0
- package/.pbai4devs/skills/README.md +24 -0
- package/.pbai4devs/skills/git/git-branch/SKILL.md +11 -0
- package/.pbai4devs/skills/git/git-commit/SKILL.md +16 -0
- package/.pbai4devs/skills/git/git-diff/SKILL.md +9 -0
- package/.pbai4devs/skills/git/git-fetch/SKILL.md +10 -0
- package/.pbai4devs/skills/git/git-log/SKILL.md +9 -0
- package/.pbai4devs/skills/git/git-merge/SKILL.md +13 -0
- package/.pbai4devs/skills/git/git-pull/SKILL.md +12 -0
- package/.pbai4devs/skills/git/git-push/SKILL.md +12 -0
- package/.pbai4devs/skills/git/git-status/SKILL.md +9 -0
- package/.pbai4devs/skills/git/git-worktree/SKILL.md +10 -0
- package/.pbai4devs/skills/produto/criar-design-doc/SKILL.md +37 -0
- package/.pbai4devs/skills/produto/criar-prd/SKILL.md +35 -0
- package/.pbai4devs/skills/produto/criar-ux-ui/SKILL.md +34 -0
- package/.pbai4devs/skills/projeto/atualizar-documentacao/SKILL.md +26 -0
- package/.pbai4devs/skills/projeto/configurar-projeto/SKILL.md +62 -0
- package/.pbai4devs/skills/projeto/criar-agente/SKILL.md +20 -0
- package/.pbai4devs/skills/projeto/criar-comando/SKILL.md +25 -0
- package/.pbai4devs/skills/projeto/criar-recurso/SKILL.md +41 -0
- package/.pbai4devs/skills/projeto/criar-regra/SKILL.md +19 -0
- package/.pbai4devs/skills/projeto/criar-skill/SKILL.md +22 -0
- package/.pbai4devs/skills/projeto/executar-script/SKILL.md +29 -0
- package/.pbai4devs/skills/projeto/preparar-dev/SKILL.md +45 -0
- package/.pbai4devs/skills/projeto/preparar-ferramentas/SKILL.md +56 -0
- package/.pbai4devs/skills/projeto/proximos-passos/SKILL.md +23 -0
- package/.pbai4devs/skills/projeto/sincronizar-agentes/SKILL.md +42 -0
- package/.pbai4devs/skills/projeto/usar-skills-externas/SKILL.md +28 -0
- package/.pbai4devs/skills/projeto/verificar-trabalho/SKILL.md +45 -0
- package/.pbai4devs/skills/specs/criar-spec/SKILL.md +33 -0
- package/.pbai4devs/skills/specs/gerenciar-roadmap/SKILL.md +26 -0
- package/.pbai4devs/skills/specs/implementar-spec/SKILL.md +48 -0
- package/.pbai4devs/templates/README.md +65 -0
- package/.pbai4devs/templates/adr/TEMPLATE.md +21 -0
- package/.pbai4devs/templates/ambiente-local/Makefile.template +48 -0
- package/.pbai4devs/templates/ambiente-local/TEMPLATE.md +48 -0
- package/.pbai4devs/templates/ambiente-local/compose.local.yml.template +16 -0
- package/.pbai4devs/templates/ambiente-local/dockerignore.template +28 -0
- package/.pbai4devs/templates/changelog/TEMPLATE.md +17 -0
- package/.pbai4devs/templates/claude/TEMPLATE.md +8 -0
- package/.pbai4devs/templates/clients/ADAPTERS.json +306 -0
- package/.pbai4devs/templates/clients/TEMPLATE.md +12 -0
- package/.pbai4devs/templates/comando/TEMPLATE.md +15 -0
- package/.pbai4devs/templates/configuracao/TEMPLATE.md +46 -0
- package/.pbai4devs/templates/configuracao-raiz/TEMPLATE.md +22 -0
- package/.pbai4devs/templates/configuracao-raiz/editorconfig.template +21 -0
- package/.pbai4devs/templates/configuracao-raiz/env.example.template +3 -0
- package/.pbai4devs/templates/configuracao-raiz/gitattributes.template +6 -0
- package/.pbai4devs/templates/contribuicao/TEMPLATE.md +23 -0
- package/.pbai4devs/templates/design/TEMPLATE.md +30 -0
- package/.pbai4devs/templates/entrypoints/AGENTS.md +19 -0
- package/.pbai4devs/templates/entrypoints/CLAUDE.md +7 -0
- package/.pbai4devs/templates/entrypoints/GEMINI.md +7 -0
- package/.pbai4devs/templates/entrypoints/TEMPLATE.md +12 -0
- package/.pbai4devs/templates/gitignore/TEMPLATE.md +42 -0
- package/.pbai4devs/templates/gitignore/agents.ignore +45 -0
- package/.pbai4devs/templates/gitignore/clients.json +20 -0
- package/.pbai4devs/templates/gitignore/local.ignore +10 -0
- package/.pbai4devs/templates/gitignore/shared.ignore +60 -0
- package/.pbai4devs/templates/instrucoes-agentes/TEMPLATE.md +25 -0
- package/.pbai4devs/templates/plano-implementacao/TEMPLATE.md +27 -0
- package/.pbai4devs/templates/prd/TEMPLATE.md +30 -0
- package/.pbai4devs/templates/readme-pasta/TEMPLATE.md +16 -0
- package/.pbai4devs/templates/readme-projeto/TEMPLATE.md +34 -0
- package/.pbai4devs/templates/release/TEMPLATE.md +23 -0
- package/.pbai4devs/templates/revisao-entrega/TEMPLATE.md +41 -0
- package/.pbai4devs/templates/roadmap/TEMPLATE.md +18 -0
- package/.pbai4devs/templates/seguranca/TEMPLATE.md +22 -0
- package/.pbai4devs/templates/spec/TEMPLATE.md +61 -0
- package/.pbai4devs/templates/tasks/TEMPLATE.md +20 -0
- package/.pbai4devs/templates/ux-ui/TEMPLATE.md +26 -0
- package/.pbai4devs/tools/README.md +87 -0
- package/.pbai4devs/tools/agent-browser/README.md +26 -0
- package/.pbai4devs/tools/agent-browser/SCRIPT.mjs +5 -0
- package/.pbai4devs/tools/agent-browser/TOOL.json +33 -0
- package/.pbai4devs/tools/agent-desktop/README.md +26 -0
- package/.pbai4devs/tools/agent-desktop/SCRIPT.mjs +5 -0
- package/.pbai4devs/tools/agent-desktop/TOOL.json +30 -0
- package/.pbai4devs/tools/just-bash/README.md +23 -0
- package/.pbai4devs/tools/just-bash/SCRIPT.mjs +5 -0
- package/.pbai4devs/tools/just-bash/TOOL.json +27 -0
- package/.pbai4devs/tools/markdownlint-cli2/README.md +18 -0
- package/.pbai4devs/tools/markdownlint-cli2/SCRIPT.mjs +5 -0
- package/.pbai4devs/tools/markdownlint-cli2/TOOL.json +28 -0
- package/.pbai4devs/tools/opensrc/README.md +25 -0
- package/.pbai4devs/tools/opensrc/SCRIPT.mjs +5 -0
- package/.pbai4devs/tools/opensrc/TOOL.json +29 -0
- package/.pbai4devs/tools/portless/README.md +21 -0
- package/.pbai4devs/tools/portless/SCRIPT.mjs +5 -0
- package/.pbai4devs/tools/portless/TOOL.json +30 -0
- package/.pbai4devs/tools/skills/README.md +24 -0
- package/.pbai4devs/tools/skills/SCRIPT.mjs +5 -0
- package/.pbai4devs/tools/skills/TOOL.json +33 -0
- package/.pbai4devs/tools/webreel/README.md +23 -0
- package/.pbai4devs/tools/webreel/SCRIPT.mjs +5 -0
- package/.pbai4devs/tools/webreel/TOOL.json +25 -0
- package/CHANGELOG.md +58 -0
- package/CONTRIBUTING.md +73 -0
- package/LICENSE +21 -0
- package/README.en.md +78 -0
- package/README.es.md +80 -0
- package/README.md +88 -2
- package/bin/README.md +8 -0
- package/bin/agentdevkit.mjs +35 -0
- package/docs/README.md +81 -0
- package/docs/guides/README.md +14 -0
- package/docs/guides/cli.md +81 -0
- package/docs/guides/installation.md +78 -0
- package/docs/guides/resources.md +121 -0
- package/docs/guides/tools-and-testing.md +85 -0
- package/docs/guides/troubleshooting.md +151 -0
- package/docs/guides/workflow.md +130 -0
- package/docs/maintainers/README.md +12 -0
- package/docs/maintainers/community.md +49 -0
- package/docs/maintainers/development.md +54 -0
- package/docs/maintainers/maintenance.md +104 -0
- package/docs/maintainers/packages.md +76 -0
- package/docs/product/README.md +12 -0
- package/docs/product/design.md +94 -0
- package/docs/product/prd.md +64 -0
- package/docs/product/roadmap.md +36 -0
- package/docs/product/ux-ui.md +42 -0
- package/docs/specs/README.md +20 -0
- package/docs/specs/github-packages/SPEC.md +45 -0
- package/docs/specs/v0.0.1/README.md +10 -0
- package/docs/specs/v0.0.1/SPEC.md +57 -0
- package/docs/specs/v0.0.2/README.md +10 -0
- package/docs/specs/v0.0.2/SPEC.md +67 -0
- package/docs/specs/v0.0.3/README.md +10 -0
- package/docs/specs/v0.0.3/SPEC.md +64 -0
- package/docs/specs/v0.0.4/README.md +10 -0
- package/docs/specs/v0.0.4/SPEC.md +53 -0
- package/docs/specs/v0.0.5/README.md +9 -0
- package/docs/specs/v0.0.5/SPEC.md +42 -0
- package/package.json +52 -4
- package/src/README.md +16 -0
- package/src/adapters/index.mjs +1 -0
- package/src/cli.mjs +162 -0
- package/src/config.mjs +14 -0
- package/src/i18n.mjs +42 -0
- package/src/install.mjs +367 -0
- package/src/next.mjs +79 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
import { projectRoot } from '../../lib/runtime.mjs';
|
|
9
|
+
import { planLocalIgnore, applyLocalIgnore, checkLocalIgnore, planUntrack, applyUntrack, restoreUntrack, assertLocalIgnoreUnchanged } from '../../lib/gitignore.mjs';
|
|
10
|
+
|
|
11
|
+
function fixture(t, canonical = true) {
|
|
12
|
+
const created = mkdtempSync(join(tmpdir(), 'agentdevkit-ignore-'));
|
|
13
|
+
const root = canonical ? realpathSync.native(created) : created;
|
|
14
|
+
t.after(() => rmSync(root, { recursive: true, force: true }));
|
|
15
|
+
put(root, '.pbai4devs/templates/gitignore/local.ignore', readFileSync(join(projectRoot, '.pbai4devs/templates/gitignore/local.ignore')));
|
|
16
|
+
return root;
|
|
17
|
+
}
|
|
18
|
+
function put(root, path, content) { mkdirSync(dirname(join(root, path)), { recursive: true }); writeFileSync(join(root, path), content); }
|
|
19
|
+
function git(root, args, input) {
|
|
20
|
+
const result = spawnSync('git', ['-C', root, ...args], { encoding: 'utf8', input });
|
|
21
|
+
assert.ifError(result.error); assert.equal(result.status, 0, result.stderr); return result.stdout;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
test('fallback protege outputs antes de git init e migra para exclude preservando regras', t => {
|
|
25
|
+
const root = fixture(t), outputs = ['.github/skills/generated/SKILL.md', '.vscode/.gitignore', 'AGENTS.md'];
|
|
26
|
+
put(root, '.gitignore', '# Regras humanas\n*.own-cache\n');
|
|
27
|
+
const plan = planLocalIgnore(root, { outputs });
|
|
28
|
+
assert.equal(plan.status, 'fallback'); assert.equal(checkLocalIgnore(plan).ok, false);
|
|
29
|
+
applyLocalIgnore(plan);
|
|
30
|
+
assert.equal(checkLocalIgnore(planLocalIgnore(root, { outputs })).ok, true);
|
|
31
|
+
assert.match(readFileSync(join(root, '.gitignore'), 'utf8'), /^# Regras humanas\n\*\.own-cache\n/);
|
|
32
|
+
git(root, ['init', '-q']);
|
|
33
|
+
put(root, '.git/info/exclude', '# Exclusoes humanas\n*.local-backup\n');
|
|
34
|
+
applyLocalIgnore(planLocalIgnore(root, { outputs }));
|
|
35
|
+
assert.doesNotMatch(readFileSync(join(root, '.gitignore'), 'utf8'), /AGENTDEVKIT LOCAL/);
|
|
36
|
+
assert.match(readFileSync(join(root, '.git/info/exclude'), 'utf8'), /^# Exclusoes humanas/);
|
|
37
|
+
assert.equal(checkLocalIgnore(planLocalIgnore(root, { outputs })).ok, true);
|
|
38
|
+
for (const path of outputs) put(root, path, 'gerado\n');
|
|
39
|
+
for (const path of ['.github/workflows/ci.yml', '.github/ISSUE_TEMPLATE/bug.yml', '.vscode/settings.json', '.github/skills/human/SKILL.md']) put(root, path, 'humano\n');
|
|
40
|
+
git(root, ['add', '--all']);
|
|
41
|
+
const tracked = git(root, ['ls-files', '-z']).split('\0').filter(Boolean);
|
|
42
|
+
for (const path of outputs) assert.equal(tracked.includes(path), false, path);
|
|
43
|
+
for (const path of ['.github/workflows/ci.yml', '.github/ISSUE_TEMPLATE/bug.yml', '.vscode/settings.json', '.github/skills/human/SKILL.md']) assert.ok(tracked.includes(path), path);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('prefixos e projetos distintos preservam blocos locais independentes', t => {
|
|
47
|
+
const root = fixture(t); git(root, ['init', '-q']);
|
|
48
|
+
const template = readFileSync(join(root, '.pbai4devs/templates/gitignore/local.ignore'));
|
|
49
|
+
for (const name of ['first space', 'second']) {
|
|
50
|
+
const child = join(root, name); put(child, '.pbai4devs/templates/gitignore/local.ignore', template);
|
|
51
|
+
applyLocalIgnore(planLocalIgnore(child, { outputs: ['.github/prompts/a[1].md'] }));
|
|
52
|
+
assert.equal(checkLocalIgnore(planLocalIgnore(child, { outputs: ['.github/prompts/a[1].md'] })).ok, true);
|
|
53
|
+
}
|
|
54
|
+
const content = readFileSync(join(root, '.git/info/exclude'), 'utf8');
|
|
55
|
+
assert.equal((content.match(/# BEGIN AGENTDEVKIT LOCAL/g) || []).length, 2);
|
|
56
|
+
assert.match(content, /first\\ space/); assert.match(content, /second/);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('check identifica negação humana e outputs rastreados sem alterar o índice', t => {
|
|
60
|
+
const root = fixture(t), outputs = ['generated.md']; git(root, ['init', '-q']);
|
|
61
|
+
put(root, 'generated.md', 'gerado'); git(root, ['add', 'generated.md']);
|
|
62
|
+
applyLocalIgnore(planLocalIgnore(root, { outputs }));
|
|
63
|
+
put(root, '.gitignore', '!/generated.md\n');
|
|
64
|
+
const result = checkLocalIgnore(planLocalIgnore(root, { outputs }));
|
|
65
|
+
assert.equal(result.ok, false); assert.deepEqual(result.missing, outputs); assert.deepEqual(result.trackedOutputs, outputs);
|
|
66
|
+
assert.equal(git(root, ['ls-files', 'generated.md']).trim(), 'generated.md');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('planejamento é somente leitura e aplicação detecta mudança concorrente', t => {
|
|
70
|
+
const root = fixture(t); put(root, '.gitignore', 'antes\r\n');
|
|
71
|
+
const plan = planLocalIgnore(root, { outputs: ['generated.md'] });
|
|
72
|
+
assert.equal(readFileSync(join(root, '.gitignore'), 'utf8'), 'antes\r\n');
|
|
73
|
+
put(root, '.gitignore', 'depois\r\n');
|
|
74
|
+
assert.throws(() => applyLocalIgnore(plan), /alterada apos planejar/);
|
|
75
|
+
assert.equal(readFileSync(join(root, '.gitignore'), 'utf8'), 'depois\r\n');
|
|
76
|
+
for (const path of ['../outside', '/absolute', 'line\nname', 'a\\b']) assert.throws(() => planLocalIgnore(root, { outputs: [path] }), /invalida/);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('desindexação preserva bytes e outros arquivos staged e recusa hash alterado', t => {
|
|
80
|
+
const root = fixture(t); git(root, ['init', '-q']);
|
|
81
|
+
put(root, 'generated [1].md', 'gerado\n'); put(root, 'human.md', 'humano\n');
|
|
82
|
+
git(root, ['add', '--all']);
|
|
83
|
+
const hash = createHash('sha256').update('gerado\n').digest('hex');
|
|
84
|
+
const plan = planUntrack(root, { 'generated [1].md': hash });
|
|
85
|
+
assert.deepEqual(plan.paths, ['generated [1].md']);
|
|
86
|
+
assert.deepEqual(applyUntrack(plan).removed, plan.paths);
|
|
87
|
+
assert.equal(readFileSync(join(root, 'generated [1].md'), 'utf8'), 'gerado\n');
|
|
88
|
+
assert.equal(git(root, ['ls-files', 'human.md']).trim(), 'human.md');
|
|
89
|
+
git(root, ['add', 'generated [1].md']);
|
|
90
|
+
const pending = planUntrack(root, { 'generated [1].md': hash });
|
|
91
|
+
put(root, 'generated [1].md', 'editado\n');
|
|
92
|
+
assert.throws(() => applyUntrack(pending), /mudou/);
|
|
93
|
+
assert.equal(git(root, ['ls-files', 'generated [1].md']).trim(), 'generated [1].md');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('plano de instalação em alvo inexistente não cria arquivos', t => {
|
|
97
|
+
const root = fixture(t);
|
|
98
|
+
const target = join(root, 'new project', 'nested');
|
|
99
|
+
const fallback = planLocalIgnore(target, { outputs: ['AGENTS.md'] });
|
|
100
|
+
assert.equal(fallback.status, 'fallback'); assert.equal(existsSync(target), false);
|
|
101
|
+
git(root, ['init', '-q']);
|
|
102
|
+
const plan = planLocalIgnore(target, { outputs: ['AGENTS.md'] });
|
|
103
|
+
assert.equal(plan.status, 'git'); assert.equal(existsSync(target), false);
|
|
104
|
+
assert.equal(plan.location.prefix, 'new project/nested');
|
|
105
|
+
assert.match(plan.edits[0].after, /new\\ project\/nested\/AGENTS.md/);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('desindexação não descarta edição humana staged com workingtree restaurado', t => {
|
|
109
|
+
const root = fixture(t); git(root, ['init', '-q']);
|
|
110
|
+
put(root, 'generated.md', 'edição humana\n'); git(root, ['add', 'generated.md']);
|
|
111
|
+
put(root, 'generated.md', 'gerado\n');
|
|
112
|
+
const hash = createHash('sha256').update('gerado\n').digest('hex');
|
|
113
|
+
const plan = planUntrack(root, { 'generated.md': hash });
|
|
114
|
+
assert.deepEqual(plan.paths, []); assert.deepEqual(plan.conflicts, ['generated.md']);
|
|
115
|
+
assert.throws(() => applyUntrack(plan), /alteracoes/);
|
|
116
|
+
assert.equal(git(root, ['show', ':generated.md']), 'edição humana\n');
|
|
117
|
+
assert.equal(readFileSync(join(root, 'generated.md'), 'utf8'), 'gerado\n');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('raízes dedicadas são locais, enquanto configurações de GitHub e VS Code são fontes', t => {
|
|
121
|
+
const root = fixture(t); git(root, ['init', '-q']);
|
|
122
|
+
applyLocalIgnore(planLocalIgnore(root));
|
|
123
|
+
put(root, '.codex/config.toml', 'local'); put(root, '.claude/settings.json', 'local');
|
|
124
|
+
put(root, '.github/settings.json', 'fonte'); put(root, '.vscode/settings.json', 'fonte');
|
|
125
|
+
git(root, ['add', '--all']);
|
|
126
|
+
const tracked = git(root, ['ls-files', '-z']).split('\0');
|
|
127
|
+
assert.equal(tracked.includes('.codex/config.toml'), false);
|
|
128
|
+
assert.equal(tracked.includes('.claude/settings.json'), false);
|
|
129
|
+
assert.ok(tracked.includes('.github/settings.json')); assert.ok(tracked.includes('.vscode/settings.json'));
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('milhares de caminhos usam stdin e não ampliam metadata de área já ignorada', t => {
|
|
133
|
+
const root = fixture(t); git(root, ['init', '-q']); put(root, '.gitignore', '/ignored/\n');
|
|
134
|
+
const before = readFileSync(join(root, '.git/info/exclude'), 'utf8');
|
|
135
|
+
const target = join(root, 'ignored'); mkdirSync(target);
|
|
136
|
+
const outputs = Array.from({ length: 1500 }, (_, index) => `.github/skills/generated-${index}-${'x'.repeat(45)}/SKILL.md`);
|
|
137
|
+
const plan = planLocalIgnore(target, { outputs });
|
|
138
|
+
assert.deepEqual(plan.edits, []); assert.equal(checkLocalIgnore(plan).ok, true);
|
|
139
|
+
applyLocalIgnore(plan); assert.equal(readFileSync(join(root, '.git/info/exclude'), 'utf8'), before);
|
|
140
|
+
assert.deepEqual(planUntrack(target, Object.fromEntries(outputs.map(path => [path, 'a'.repeat(64)]))).paths, []);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test('rollback restaura somente entradas removidas e preserva estágio posterior', t => {
|
|
144
|
+
const root = fixture(t); git(root, ['init', '-q']);
|
|
145
|
+
put(root, 'generated.md', 'gerado\n'); put(root, 'second.md', 'original\n'); put(root, 'human.md', 'humano\n');
|
|
146
|
+
git(root, ['add', '--all']);
|
|
147
|
+
const digest = value => createHash('sha256').update(value).digest('hex');
|
|
148
|
+
const plan = planUntrack(root, { 'generated.md': digest('gerado\n'), 'second.md': digest('original\n') });
|
|
149
|
+
applyUntrack(plan);
|
|
150
|
+
put(root, 'second.md', 'staged depois\n'); git(root, ['add', 'second.md']);
|
|
151
|
+
put(root, 'human.md', 'humano depois\n'); git(root, ['add', 'human.md']);
|
|
152
|
+
const result = restoreUntrack(plan);
|
|
153
|
+
assert.deepEqual(result.restored, ['generated.md']); assert.deepEqual(result.preserved, ['second.md']);
|
|
154
|
+
assert.equal(git(root, ['show', ':generated.md']), 'gerado\n');
|
|
155
|
+
assert.equal(git(root, ['show', ':second.md']), 'staged depois\n');
|
|
156
|
+
assert.equal(git(root, ['show', ':human.md']), 'humano depois\n');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('rollback respeita lock alheio e preflight detecta metadata alterada', t => {
|
|
160
|
+
const root = fixture(t); git(root, ['init', '-q']); put(root, 'generated.md', 'gerado\n'); git(root, ['add', 'generated.md']);
|
|
161
|
+
const plan = planUntrack(root, { 'generated.md': createHash('sha256').update('gerado\n').digest('hex') });
|
|
162
|
+
applyUntrack(plan); put(root, '.git/index.lock', 'lock alheio');
|
|
163
|
+
assert.throws(() => restoreUntrack(plan), /EEXIST/);
|
|
164
|
+
assert.equal(readFileSync(join(root, '.git/index.lock'), 'utf8'), 'lock alheio');
|
|
165
|
+
const metadata = planLocalIgnore(root, { outputs: ['generated.md'] });
|
|
166
|
+
put(root, '.git/info/exclude', 'mudou\n');
|
|
167
|
+
assert.throws(() => assertLocalIgnoreUnchanged(metadata), /alterada apos planejar/);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test('rollback em projeto aninhado restaura o caminho relativo à raiz Git', t => {
|
|
171
|
+
const root = fixture(t); git(root, ['init', '-q']);
|
|
172
|
+
put(root, 'nested/generated.md', 'gerado\n'); put(root, 'human.md', 'humano\n'); git(root, ['add', '--all']);
|
|
173
|
+
const child = join(root, 'nested');
|
|
174
|
+
const plan = planUntrack(child, { 'generated.md': createHash('sha256').update('gerado\n').digest('hex') });
|
|
175
|
+
applyUntrack(plan); restoreUntrack(plan);
|
|
176
|
+
assert.equal(git(root, ['show', ':nested/generated.md']), 'gerado\n');
|
|
177
|
+
assert.equal(git(root, ['show', ':human.md']), 'humano\n');
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('negação humana é detectada antes de aplicar novas exclusões e permanece intacta', t => {
|
|
181
|
+
const root = fixture(t); git(root, ['init', '-q']);
|
|
182
|
+
put(root, '.gitignore', '!/AGENTS.md\n');
|
|
183
|
+
const before = readFileSync(join(root, '.git/info/exclude'), 'utf8');
|
|
184
|
+
const plan = planLocalIgnore(root, { outputs: ['AGENTS.md'] });
|
|
185
|
+
assert.equal(plan.edits.length, 1);
|
|
186
|
+
assert.deepEqual(checkLocalIgnore(plan).missing, ['AGENTS.md']);
|
|
187
|
+
assert.throws(() => applyLocalIgnore(plan), /Regras humanas/);
|
|
188
|
+
assert.equal(readFileSync(join(root, '.git/info/exclude'), 'utf8'), before);
|
|
189
|
+
assert.equal(readFileSync(join(root, '.gitignore'), 'utf8'), '!/AGENTS.md\n');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('cliente não selecionado com symlink próprio não é atravessado pelo probe', t => {
|
|
193
|
+
const root = fixture(t), outside = fixture(t); git(root, ['init', '-q']);
|
|
194
|
+
try { symlinkSync(outside, join(root, '.opencode'), process.platform === 'win32' ? 'junction' : 'dir'); }
|
|
195
|
+
catch (error) { if (['EPERM', 'EACCES'].includes(error.code)) { t.skip('Sem permissão para criar symlink.'); return; } throw error; }
|
|
196
|
+
const before = readdirSync(outside);
|
|
197
|
+
applyLocalIgnore(planLocalIgnore(root, { outputs: ['AGENTS.md'] }));
|
|
198
|
+
assert.equal(checkLocalIgnore(planLocalIgnore(root, { outputs: ['AGENTS.md'] })).ok, true);
|
|
199
|
+
assert.deepEqual(readdirSync(outside), before);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('preflight dispensa somente regras de bloco substituído com hash válido', t => {
|
|
203
|
+
const root = fixture(t); git(root, ['init', '-q']);
|
|
204
|
+
const block = '# BEGIN AGENT IGNORE\r\n!/generated.md\r\n# END AGENT IGNORE';
|
|
205
|
+
put(root, '.github/.gitignore', `# Humano\r\n${block}\r\n!/human.md\r\n`);
|
|
206
|
+
const plan = planLocalIgnore(root, { outputs: ['.github/generated.md', '.github/human.md'] });
|
|
207
|
+
const replacement = { path: join(root, '.github/.gitignore'), firstLine: 2, lastLine: 4, sha256: createHash('sha256').update(block).digest('hex') };
|
|
208
|
+
assert.deepEqual(checkLocalIgnore(plan).missing, ['.github/generated.md', '.github/human.md']);
|
|
209
|
+
assert.deepEqual(checkLocalIgnore(plan, { replacedBlocks: [replacement] }).missing, ['.github/human.md']);
|
|
210
|
+
assert.throws(() => checkLocalIgnore(plan, { replacedBlocks: [{ ...replacement, sha256: '0'.repeat(64) }] }), /Bloco de ignore mudou/);
|
|
211
|
+
assert.throws(() => applyLocalIgnore(plan), /Regras humanas/);
|
|
212
|
+
assert.equal(readFileSync(join(root, '.github/.gitignore'), 'utf8'), `# Humano\r\n${block}\r\n!/human.md\r\n`);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test('aliases ancestrais usam caminhos nativos em exclusão, desindexação e rollback', t => {
|
|
216
|
+
const base = fixture(t), project = join(base, 'project'), alias = join(base, 'alias');
|
|
217
|
+
mkdirSync(project);
|
|
218
|
+
try { symlinkSync(base, alias, process.platform === 'win32' ? 'junction' : 'dir'); }
|
|
219
|
+
catch (error) { if (['EPERM', 'EACCES'].includes(error.code)) { t.skip('Sem permissão para criar alias.'); return; } throw error; }
|
|
220
|
+
git(project, ['init', '-q']);
|
|
221
|
+
const native = realpathSync.native;
|
|
222
|
+
const canonical = native(project), viaAlias = join(alias, 'project');
|
|
223
|
+
let nativeCalls = 0;
|
|
224
|
+
t.mock.method(realpathSync, 'native', (...args) => { nativeCalls++; return native(...args); });
|
|
225
|
+
const plan = planLocalIgnore(viaAlias, { outputs: ['generated.md'] });
|
|
226
|
+
assert.equal(plan.root, canonical); assert.equal(plan.location.top, canonical); assert.equal(plan.location.prefix, '');
|
|
227
|
+
applyLocalIgnore(plan);
|
|
228
|
+
assert.equal(planLocalIgnore(project, { outputs: ['generated.md'] }).edits.length, 0);
|
|
229
|
+
const future = planLocalIgnore(join(viaAlias, 'future', 'nested'), { outputs: ['generated.md'] });
|
|
230
|
+
assert.equal(future.root, join(canonical, 'future', 'nested'));
|
|
231
|
+
assert.equal(future.location.prefix, 'future/nested'); assert.equal(existsSync(future.root), false);
|
|
232
|
+
put(project, 'generated.md', 'gerado\n'); git(project, ['add', '-f', 'generated.md']);
|
|
233
|
+
const untrack = planUntrack(viaAlias, { 'generated.md': createHash('sha256').update('gerado\n').digest('hex') });
|
|
234
|
+
assert.equal(untrack.root, canonical); applyUntrack(untrack); restoreUntrack(untrack);
|
|
235
|
+
assert.equal(git(project, ['show', ':generated.md']), 'gerado\n');
|
|
236
|
+
assert.ok(nativeCalls > 3, 'As comparações devem usar realpathSync.native.');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test('canonicalização recorre a realpath quando operação nativa não é suportada', t => {
|
|
240
|
+
const root = fixture(t), expected = realpathSync(root);
|
|
241
|
+
t.mock.method(realpathSync, 'native', () => { throw Object.assign(new Error('Sem suporte'), { code: 'ENOSYS' }); });
|
|
242
|
+
const plan = planLocalIgnore(join(root, 'future'), { outputs: ['generated.md'] });
|
|
243
|
+
assert.equal(plan.root, join(expected, 'future')); assert.equal(existsSync(plan.root), false);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test('Windows normaliza o alias temporário 8.3 antes de comparar a raiz Git', { skip: process.platform !== 'win32' }, t => {
|
|
247
|
+
const root = fixture(t, false), canonical = realpathSync.native(root);
|
|
248
|
+
git(root, ['init', '-q']);
|
|
249
|
+
const plan = planLocalIgnore(root, { outputs: ['generated.md'] });
|
|
250
|
+
assert.equal(plan.root, canonical); assert.equal(plan.location.top, canonical); assert.equal(plan.location.prefix, '');
|
|
251
|
+
const future = planLocalIgnore(join(root, 'future'), { outputs: ['generated.md'] });
|
|
252
|
+
assert.equal(future.root, join(canonical, 'future')); assert.equal(future.location.prefix, 'future');
|
|
253
|
+
put(root, 'generated.md', 'gerado\n'); git(root, ['add', 'generated.md']);
|
|
254
|
+
const untrack = planUntrack(root, { 'generated.md': createHash('sha256').update('gerado\n').digest('hex') });
|
|
255
|
+
applyUntrack(untrack); restoreUntrack(untrack);
|
|
256
|
+
assert.equal(git(root, ['show', ':generated.md']), 'gerado\n');
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test('canonicalização do índice mantém rejeição de symlink antes de resolver o destino', t => {
|
|
260
|
+
const root = fixture(t); git(root, ['init', '-q']); put(root, 'generated.md', 'gerado\n'); git(root, ['add', 'generated.md']);
|
|
261
|
+
const plan = planUntrack(root, { 'generated.md': createHash('sha256').update('gerado\n').digest('hex') });
|
|
262
|
+
applyUntrack(plan);
|
|
263
|
+
const index = join(root, '.git/index'), saved = join(root, '.git/saved-index');
|
|
264
|
+
renameSync(index, saved);
|
|
265
|
+
try { symlinkSync(saved, index); }
|
|
266
|
+
catch (error) { renameSync(saved, index); if (['EPERM', 'EACCES'].includes(error.code)) { t.skip('Sem permissão para criar symlink.'); return; } throw error; }
|
|
267
|
+
const before = readFileSync(saved);
|
|
268
|
+
assert.throws(() => restoreUntrack(plan), /Link simbolico/);
|
|
269
|
+
assert.throws(() => checkLocalIgnore({ root, location: null, paths: [], edits: [], trackedOutputs: [] }, {
|
|
270
|
+
replacedBlocks: [{ path: index, firstLine: 1, lastLine: 1, sha256: '0'.repeat(64) }],
|
|
271
|
+
}), /Link simbolico/);
|
|
272
|
+
assert.deepEqual(readFileSync(saved), before);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test('worktree usa a raiz nativa, exclude comum e seu próprio índice', t => {
|
|
276
|
+
const root = fixture(t); git(root, ['init', '-q']); put(root, 'seed.txt', 'base\n'); git(root, ['add', 'seed.txt']);
|
|
277
|
+
git(root, ['-c', 'user.name=Test User', '-c', 'user.email=test@example.invalid', '-c', 'commit.gpgsign=false', '-c', 'core.hooksPath=disabled-hooks', 'commit', '-q', '-m', 'test: worktree fixture']);
|
|
278
|
+
const linked = join(root, 'linked-worktree');
|
|
279
|
+
git(root, ['worktree', 'add', '-q', '-b', 'fixture-linked', linked]);
|
|
280
|
+
const plan = planLocalIgnore(linked, { outputs: ['generated.md'] });
|
|
281
|
+
assert.equal(plan.root, realpathSync.native(linked));
|
|
282
|
+
assert.equal(plan.location.top, realpathSync.native(linked));
|
|
283
|
+
assert.equal(plan.location.exclude, realpathSync.native(join(root, '.git/info/exclude')));
|
|
284
|
+
applyLocalIgnore(plan); assert.equal(checkLocalIgnore(planLocalIgnore(linked, { outputs: ['generated.md'] })).ok, true);
|
|
285
|
+
put(linked, 'generated.md', 'gerado\n'); git(linked, ['add', '-f', 'generated.md']);
|
|
286
|
+
const untrack = planUntrack(linked, { 'generated.md': createHash('sha256').update('gerado\n').digest('hex') });
|
|
287
|
+
applyUntrack(untrack); restoreUntrack(untrack);
|
|
288
|
+
assert.equal(git(linked, ['show', ':generated.md']), 'gerado\n');
|
|
289
|
+
assert.equal(git(root, ['ls-files', 'generated.md']), '');
|
|
290
|
+
});
|