atlas-workflow 0.8.2
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/LICENSE +21 -0
- package/README.md +235 -0
- package/VERSION +1 -0
- package/build/cli/atlas-init.mjs +590 -0
- package/hosts/opencode/.opencode/agents/atlas-direct-execute.md +31 -0
- package/hosts/opencode/.opencode/agents/atlas-findings-repair.md +35 -0
- package/hosts/opencode/.opencode/agents/atlas-plan-execute.md +33 -0
- package/hosts/opencode/.opencode/agents/atlas-slice-review.md +27 -0
- package/hosts/opencode/.opencode/agents/atlas-task-validator.md +121 -0
- package/hosts/opencode/.opencode/atlas/VERSION +1 -0
- package/hosts/opencode/.opencode/atlas/orchestrator/README.md +261 -0
- package/hosts/opencode/.opencode/atlas/orchestrator/commands/workflow.md +37 -0
- package/hosts/opencode/.opencode/atlas/orchestrator/defaults/paths.md +21 -0
- package/hosts/opencode/.opencode/atlas/orchestrator/references/host-adapters.md +104 -0
- package/hosts/opencode/.opencode/atlas/orchestrator/references/qa_s13_matrix.md +141 -0
- package/hosts/opencode/.opencode/atlas/orchestrator/references/subagent_dispatch.md +42 -0
- package/hosts/opencode/.opencode/atlas/orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +412 -0
- package/hosts/opencode/.opencode/atlas/packages/mcp-server/README.md +28 -0
- package/hosts/opencode/.opencode/atlas/packages/mcp-server/package.json +15 -0
- package/hosts/opencode/.opencode/atlas/packages/mcp-server/server.js +3076 -0
- package/hosts/opencode/.opencode/atlas/packages/templates/BACKLOG_MESTRE_TEMPLATE.md +844 -0
- package/hosts/opencode/.opencode/atlas/packages/templates/BOUNDARY_PRD_PLAN.md +93 -0
- package/hosts/opencode/.opencode/atlas/packages/templates/PERGUNTAS_EM_ABERTO_TEMPLATE.md +139 -0
- package/hosts/opencode/.opencode/atlas/packages/templates/PLAN_TEMPLATE.md +146 -0
- package/hosts/opencode/.opencode/atlas/packages/templates/PRD_TEMPLATE.md +149 -0
- package/hosts/opencode/.opencode/atlas/packages/templates/STATE_FILE_SCHEMA.md +32 -0
- package/hosts/opencode/.opencode/skills/atlas-backlog-generator/SKILL.md +88 -0
- package/hosts/opencode/.opencode/skills/atlas-backlog-generator/agents/openai.yaml +4 -0
- package/hosts/opencode/.opencode/skills/atlas-direct-execute/SKILL.md +186 -0
- package/hosts/opencode/.opencode/skills/atlas-direct-execute/agents/openai.yaml +7 -0
- package/hosts/opencode/.opencode/skills/atlas-findings-repair/SKILL.md +148 -0
- package/hosts/opencode/.opencode/skills/atlas-findings-repair/agents/openai.yaml +7 -0
- package/hosts/opencode/.opencode/skills/atlas-plan-execute/SKILL.md +129 -0
- package/hosts/opencode/.opencode/skills/atlas-plan-execute/agents/openai.yaml +7 -0
- package/hosts/opencode/.opencode/skills/atlas-plan-execute/references/plan-contract.md +88 -0
- package/hosts/opencode/.opencode/skills/atlas-plan-execute/references/quality-gates.md +60 -0
- package/hosts/opencode/.opencode/skills/atlas-plan-execute/scripts/check_budget_state.py +96 -0
- package/hosts/opencode/.opencode/skills/atlas-plan-execute/scripts/extract_plan_contract.py +191 -0
- package/hosts/opencode/.opencode/skills/atlas-plan-execute/scripts/validate_gate_result.py +56 -0
- package/hosts/opencode/.opencode/skills/atlas-plan-handoff/SKILL.md +181 -0
- package/hosts/opencode/.opencode/skills/atlas-plan-handoff/agents/openai.yaml +7 -0
- package/hosts/opencode/.opencode/skills/atlas-prd-interview/SKILL.md +77 -0
- package/hosts/opencode/.opencode/skills/atlas-prd-interview/agents/openai.yaml +7 -0
- package/hosts/opencode/.opencode/skills/atlas-slice-review/SKILL.md +121 -0
- package/hosts/opencode/.opencode/skills/atlas-slice-review/agents/openai.yaml +4 -0
- package/hosts/opencode/.opencode/skills/atlas-slice-review/references/review-contract.md +58 -0
- package/hosts/opencode/.opencode/skills/atlas-slice-review/references/scenario-lenses.md +49 -0
- package/hosts/opencode/.opencode/skills/atlas-slice-review/scripts/classify_findings.py +56 -0
- package/hosts/opencode/.opencode/skills/atlas-slice-review/scripts/extract_review_slice.py +158 -0
- package/hosts/opencode/.opencode/skills/atlas-sprint-prd-generator/SKILL.md +74 -0
- package/hosts/opencode/.opencode/skills/atlas-sprint-prd-generator/agents/openai.yaml +7 -0
- package/hosts/opencode/.opencode/skills/atlas-task-validator/SKILL.md +158 -0
- package/hosts/opencode/.opencode/skills/atlas-task-validator/agents/openai.yaml +7 -0
- package/hosts/opencode/.opencode/skills/atlas-workflow-orchestrator/SKILL.md +412 -0
- package/hosts/opencode/opencode.json +13 -0
- package/hosts/pi/.mcp.json +11 -0
- package/hosts/pi/.pi/agents/atlas-direct-execute.md +218 -0
- package/hosts/pi/.pi/agents/atlas-findings-repair.md +184 -0
- package/hosts/pi/.pi/agents/atlas-plan-execute.md +163 -0
- package/hosts/pi/.pi/agents/atlas-slice-review.md +149 -0
- package/hosts/pi/.pi/agents/atlas-task-validator.md +121 -0
- package/hosts/pi/atlas/VERSION +1 -0
- package/hosts/pi/atlas/orchestrator/README.md +261 -0
- package/hosts/pi/atlas/orchestrator/commands/workflow.md +37 -0
- package/hosts/pi/atlas/orchestrator/defaults/paths.md +21 -0
- package/hosts/pi/atlas/orchestrator/references/host-adapters.md +104 -0
- package/hosts/pi/atlas/orchestrator/references/qa_s13_matrix.md +141 -0
- package/hosts/pi/atlas/orchestrator/references/subagent_dispatch.md +42 -0
- package/hosts/pi/atlas/orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +412 -0
- package/hosts/pi/atlas/packages/mcp-server/README.md +28 -0
- package/hosts/pi/atlas/packages/mcp-server/package.json +15 -0
- package/hosts/pi/atlas/packages/mcp-server/server.js +3076 -0
- package/hosts/pi/atlas/packages/templates/BACKLOG_MESTRE_TEMPLATE.md +844 -0
- package/hosts/pi/atlas/packages/templates/BOUNDARY_PRD_PLAN.md +93 -0
- package/hosts/pi/atlas/packages/templates/PERGUNTAS_EM_ABERTO_TEMPLATE.md +139 -0
- package/hosts/pi/atlas/packages/templates/PLAN_TEMPLATE.md +146 -0
- package/hosts/pi/atlas/packages/templates/PRD_TEMPLATE.md +149 -0
- package/hosts/pi/atlas/packages/templates/STATE_FILE_SCHEMA.md +32 -0
- package/hosts/pi/skills/atlas-backlog-generator/SKILL.md +88 -0
- package/hosts/pi/skills/atlas-backlog-generator/agents/openai.yaml +4 -0
- package/hosts/pi/skills/atlas-direct-execute/SKILL.md +186 -0
- package/hosts/pi/skills/atlas-direct-execute/agents/openai.yaml +7 -0
- package/hosts/pi/skills/atlas-findings-repair/SKILL.md +148 -0
- package/hosts/pi/skills/atlas-findings-repair/agents/openai.yaml +7 -0
- package/hosts/pi/skills/atlas-plan-execute/SKILL.md +129 -0
- package/hosts/pi/skills/atlas-plan-execute/agents/openai.yaml +7 -0
- package/hosts/pi/skills/atlas-plan-execute/references/plan-contract.md +88 -0
- package/hosts/pi/skills/atlas-plan-execute/references/quality-gates.md +60 -0
- package/hosts/pi/skills/atlas-plan-execute/scripts/check_budget_state.py +96 -0
- package/hosts/pi/skills/atlas-plan-execute/scripts/extract_plan_contract.py +191 -0
- package/hosts/pi/skills/atlas-plan-execute/scripts/validate_gate_result.py +56 -0
- package/hosts/pi/skills/atlas-plan-handoff/SKILL.md +181 -0
- package/hosts/pi/skills/atlas-plan-handoff/agents/openai.yaml +7 -0
- package/hosts/pi/skills/atlas-prd-interview/SKILL.md +77 -0
- package/hosts/pi/skills/atlas-prd-interview/agents/openai.yaml +7 -0
- package/hosts/pi/skills/atlas-slice-review/SKILL.md +121 -0
- package/hosts/pi/skills/atlas-slice-review/agents/openai.yaml +4 -0
- package/hosts/pi/skills/atlas-slice-review/references/review-contract.md +58 -0
- package/hosts/pi/skills/atlas-slice-review/references/scenario-lenses.md +49 -0
- package/hosts/pi/skills/atlas-slice-review/scripts/classify_findings.py +56 -0
- package/hosts/pi/skills/atlas-slice-review/scripts/extract_review_slice.py +158 -0
- package/hosts/pi/skills/atlas-sprint-prd-generator/SKILL.md +74 -0
- package/hosts/pi/skills/atlas-sprint-prd-generator/agents/openai.yaml +7 -0
- package/hosts/pi/skills/atlas-task-validator/SKILL.md +158 -0
- package/hosts/pi/skills/atlas-task-validator/agents/openai.yaml +7 -0
- package/hosts/pi/skills/atlas-workflow-orchestrator/SKILL.md +412 -0
- package/package.json +17 -0
- package/plugins/atlas-workflow-orchestrator/.codex/agents/atlas-direct-execute.toml +3 -0
- package/plugins/atlas-workflow-orchestrator/.codex/agents/atlas-findings-repair.toml +3 -0
- package/plugins/atlas-workflow-orchestrator/.codex/agents/atlas-plan-execute.toml +3 -0
- package/plugins/atlas-workflow-orchestrator/.codex/agents/atlas-slice-review.toml +3 -0
- package/plugins/atlas-workflow-orchestrator/.codex/agents/atlas-task-validator.toml +5 -0
- package/plugins/atlas-workflow-orchestrator/.codex-plugin/plugin.json +37 -0
- package/plugins/atlas-workflow-orchestrator/.mcp.json +12 -0
- package/plugins/atlas-workflow-orchestrator/VERSION +1 -0
- package/plugins/atlas-workflow-orchestrator/agents/atlas-direct-execute.md +31 -0
- package/plugins/atlas-workflow-orchestrator/agents/atlas-findings-repair.md +35 -0
- package/plugins/atlas-workflow-orchestrator/agents/atlas-plan-execute.md +33 -0
- package/plugins/atlas-workflow-orchestrator/agents/atlas-slice-review.md +27 -0
- package/plugins/atlas-workflow-orchestrator/agents/atlas-task-validator.md +123 -0
- package/plugins/atlas-workflow-orchestrator/orchestrator/README.md +261 -0
- package/plugins/atlas-workflow-orchestrator/orchestrator/commands/workflow.md +37 -0
- package/plugins/atlas-workflow-orchestrator/orchestrator/defaults/paths.md +21 -0
- package/plugins/atlas-workflow-orchestrator/orchestrator/references/host-adapters.md +104 -0
- package/plugins/atlas-workflow-orchestrator/orchestrator/references/qa_s13_matrix.md +141 -0
- package/plugins/atlas-workflow-orchestrator/orchestrator/references/subagent_dispatch.md +42 -0
- package/plugins/atlas-workflow-orchestrator/orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +412 -0
- package/plugins/atlas-workflow-orchestrator/packages/mcp-server/README.md +28 -0
- package/plugins/atlas-workflow-orchestrator/packages/mcp-server/package.json +15 -0
- package/plugins/atlas-workflow-orchestrator/packages/mcp-server/server.js +3076 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-backlog-generator/SKILL.md +88 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-backlog-generator/agents/openai.yaml +4 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-direct-execute/SKILL.md +186 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-direct-execute/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-findings-repair/SKILL.md +148 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-findings-repair/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-plan-execute/SKILL.md +129 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-plan-execute/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-plan-execute/references/plan-contract.md +88 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-plan-execute/references/quality-gates.md +60 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-plan-execute/scripts/check_budget_state.py +96 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-plan-execute/scripts/extract_plan_contract.py +191 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-plan-execute/scripts/validate_gate_result.py +56 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-plan-handoff/SKILL.md +181 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-plan-handoff/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-prd-interview/SKILL.md +77 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-prd-interview/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-slice-review/SKILL.md +121 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-slice-review/agents/openai.yaml +4 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-slice-review/references/review-contract.md +58 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-slice-review/references/scenario-lenses.md +49 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-slice-review/scripts/classify_findings.py +56 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-slice-review/scripts/extract_review_slice.py +158 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-sprint-prd-generator/SKILL.md +74 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-sprint-prd-generator/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-task-validator/SKILL.md +158 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-task-validator/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/packages/templates/BACKLOG_MESTRE_TEMPLATE.md +844 -0
- package/plugins/atlas-workflow-orchestrator/packages/templates/BOUNDARY_PRD_PLAN.md +93 -0
- package/plugins/atlas-workflow-orchestrator/packages/templates/PERGUNTAS_EM_ABERTO_TEMPLATE.md +139 -0
- package/plugins/atlas-workflow-orchestrator/packages/templates/PLAN_TEMPLATE.md +146 -0
- package/plugins/atlas-workflow-orchestrator/packages/templates/PRD_TEMPLATE.md +149 -0
- package/plugins/atlas-workflow-orchestrator/packages/templates/STATE_FILE_SCHEMA.md +32 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-backlog-generator/SKILL.md +88 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-backlog-generator/agents/openai.yaml +4 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-direct-execute/SKILL.md +186 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-direct-execute/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-findings-repair/SKILL.md +148 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-findings-repair/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-plan-execute/SKILL.md +129 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-plan-execute/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-plan-execute/references/plan-contract.md +88 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-plan-execute/references/quality-gates.md +60 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-plan-execute/scripts/check_budget_state.py +96 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-plan-execute/scripts/extract_plan_contract.py +191 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-plan-execute/scripts/validate_gate_result.py +56 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-plan-handoff/SKILL.md +181 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-plan-handoff/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-prd-interview/SKILL.md +77 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-prd-interview/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-slice-review/SKILL.md +121 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-slice-review/agents/openai.yaml +4 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-slice-review/references/review-contract.md +58 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-slice-review/references/scenario-lenses.md +49 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-slice-review/scripts/classify_findings.py +56 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-slice-review/scripts/extract_review_slice.py +158 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-sprint-prd-generator/SKILL.md +74 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-sprint-prd-generator/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-task-validator/SKILL.md +158 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-task-validator/agents/openai.yaml +7 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +412 -0
- package/plugins/atlas-workflow-orchestrator/templates/BACKLOG_MESTRE_TEMPLATE.md +844 -0
- package/plugins/atlas-workflow-orchestrator/templates/BOUNDARY_PRD_PLAN.md +93 -0
- package/plugins/atlas-workflow-orchestrator/templates/PERGUNTAS_EM_ABERTO_TEMPLATE.md +139 -0
- package/plugins/atlas-workflow-orchestrator/templates/PLAN_TEMPLATE.md +146 -0
- package/plugins/atlas-workflow-orchestrator/templates/PRD_TEMPLATE.md +149 -0
- package/plugins/atlas-workflow-orchestrator/templates/STATE_FILE_SCHEMA.md +32 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Atlas Workflow — instalador unificado por host.
|
|
3
|
+
// npx github:pauloborini/atlas-workflow init <host> [dir] [flags]
|
|
4
|
+
//
|
|
5
|
+
// Hosts: claudecode|cursor (via `claude plugin`), codex (via `codex plugin` +
|
|
6
|
+
// custom agents globais),
|
|
7
|
+
// opencode (config + .opencode/), pi (config + .pi/agents/).
|
|
8
|
+
// Sem dependências externas (Node puro). Roda direto do checkout do repo (npx-from-GitHub).
|
|
9
|
+
//
|
|
10
|
+
// claude: orquestra o instalador NATIVO da CLI (marketplace from-source no GitHub).
|
|
11
|
+
// codex: orquestra o instalador nativo + copia custom agents para CODEX_HOME/agents.
|
|
12
|
+
// opencode/pi: coloca o catálogo from-source committed (hosts/<host>/) no diretório alvo.
|
|
13
|
+
import fs from 'node:fs';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import process from 'node:process';
|
|
16
|
+
import { homedir } from 'node:os';
|
|
17
|
+
import { spawnSync } from 'node:child_process';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
|
|
20
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
|
|
21
|
+
const REPO_SLUG = 'pauloborini/atlas-workflow';
|
|
22
|
+
const PLUGIN_ID = 'atlas-workflow-orchestrator@atlas-workflow';
|
|
23
|
+
|
|
24
|
+
const VERSION = (() => {
|
|
25
|
+
try { return fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf8').trim(); }
|
|
26
|
+
catch { return 'desconhecida'; }
|
|
27
|
+
})();
|
|
28
|
+
|
|
29
|
+
const HOST_ALIASES = {
|
|
30
|
+
claude: 'claude', claudecode: 'claude', 'claude-code': 'claude', cursor: 'claude',
|
|
31
|
+
codex: 'codex',
|
|
32
|
+
opencode: 'opencode',
|
|
33
|
+
pi: 'pi',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function log(msg) { process.stdout.write(`${msg}\n`); }
|
|
37
|
+
function fail(msg, code = 1) { process.stderr.write(`erro: ${msg}\n`); process.exit(code); }
|
|
38
|
+
|
|
39
|
+
// No Windows as CLIs instaladas por npm (claude/codex/pi/opencode) são shims .cmd,
|
|
40
|
+
// que o spawn só resolve com shell:true. POSIX dispensa (evita parsing extra).
|
|
41
|
+
const WIN = process.platform === 'win32';
|
|
42
|
+
|
|
43
|
+
function which(cmd) {
|
|
44
|
+
const r = spawnSync(WIN ? 'where' : 'which', [cmd], { encoding: 'utf8', shell: WIN });
|
|
45
|
+
return r.status === 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function run(cmd, args, { dryRun }) {
|
|
49
|
+
log(` $ ${cmd} ${args.join(' ')}`);
|
|
50
|
+
if (dryRun) return 0;
|
|
51
|
+
const r = spawnSync(cmd, args, { stdio: 'inherit', shell: WIN });
|
|
52
|
+
return r.status ?? 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function rmPath(p, { dryRun }) {
|
|
56
|
+
if (!fs.existsSync(p)) return false;
|
|
57
|
+
log(` rm ${p}`);
|
|
58
|
+
if (!dryRun) fs.rmSync(p, { recursive: true, force: true });
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function rmAtlasSkillsQuiet(skillsDir, opts) {
|
|
63
|
+
if (!fs.existsSync(skillsDir)) return;
|
|
64
|
+
for (const name of fs.readdirSync(skillsDir)) {
|
|
65
|
+
if (name.startsWith('atlas-')) rmPath(path.join(skillsDir, name), opts);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Remove todos os agentes Atlas despachados (validator + executores + review), não só
|
|
70
|
+
// o validator — senão upgrade deixa órfãos e install global só copia o validator.
|
|
71
|
+
function rmAtlasAgentsQuiet(agentsDir, opts, exts = ['.md']) {
|
|
72
|
+
if (!fs.existsSync(agentsDir)) return;
|
|
73
|
+
for (const name of fs.readdirSync(agentsDir)) {
|
|
74
|
+
if (name.startsWith('atlas-') && exts.some((ext) => name.endsWith(ext))) rmPath(path.join(agentsDir, name), opts);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Copia todos os agentes atlas-*.md de srcDir para destDir (install global flatten).
|
|
79
|
+
function copyAtlasAgents(srcDir, destDir, exts = ['.md']) {
|
|
80
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
81
|
+
for (const name of fs.readdirSync(srcDir)) {
|
|
82
|
+
if (name.startsWith('atlas-') && exts.some((ext) => name.endsWith(ext))) {
|
|
83
|
+
fs.copyFileSync(path.join(srcDir, name), path.join(destDir, name));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function cleanOpencodeControlled(targetDir, opts) {
|
|
89
|
+
rmPath(path.join(targetDir, '.opencode/atlas'), opts);
|
|
90
|
+
rmAtlasAgentsQuiet(path.join(targetDir, '.opencode/agents'), opts);
|
|
91
|
+
rmAtlasSkillsQuiet(path.join(targetDir, '.opencode/skills'), opts);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function cleanPiControlled(targetDir, opts) {
|
|
95
|
+
rmPath(path.join(targetDir, 'atlas'), opts);
|
|
96
|
+
rmAtlasAgentsQuiet(path.join(targetDir, '.pi/agents'), opts);
|
|
97
|
+
rmAtlasSkillsQuiet(path.join(targetDir, 'skills'), opts);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Falha-cedo: se o config do usuário existe mas é JSON inválido, aborta ANTES de
|
|
101
|
+
// copiar qualquer arquivo (não deixa instalação parcial nem sobrescreve config).
|
|
102
|
+
function assertConfigParseable(file) {
|
|
103
|
+
if (!fs.existsSync(file)) return;
|
|
104
|
+
try { JSON.parse(fs.readFileSync(file, 'utf8')); }
|
|
105
|
+
catch { fail(`${path.basename(file)} existente é JSON inválido: ${file} (corrija antes de instalar; não sobrescrevo config do usuário)`); }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function parseJsonFile(file) {
|
|
109
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isStrictJson(file) {
|
|
113
|
+
if (!fs.existsSync(file)) return true;
|
|
114
|
+
try { parseJsonFile(file); return true; }
|
|
115
|
+
catch { return false; }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function copyInto(srcRel, destDir) {
|
|
119
|
+
const src = path.join(ROOT, srcRel);
|
|
120
|
+
if (!fs.existsSync(src)) fail(`catálogo ausente no repo: ${srcRel} (rode build/build-plugins.sh e commite)`);
|
|
121
|
+
const base = path.basename(srcRel);
|
|
122
|
+
const dest = path.join(destDir, base);
|
|
123
|
+
fs.cpSync(src, dest, { recursive: true });
|
|
124
|
+
return dest;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function mergeOpencodeJson(targetDir) {
|
|
128
|
+
const srcCfg = JSON.parse(fs.readFileSync(path.join(ROOT, 'hosts/opencode/opencode.json'), 'utf8'));
|
|
129
|
+
const dest = path.join(targetDir, 'opencode.json');
|
|
130
|
+
let cfg = {};
|
|
131
|
+
if (fs.existsSync(dest)) {
|
|
132
|
+
try { cfg = JSON.parse(fs.readFileSync(dest, 'utf8')); }
|
|
133
|
+
catch { fail(`opencode.json existente é JSON inválido: ${dest} (não sobrescrevo config do usuário)`); }
|
|
134
|
+
log(` opencode.json já existe — mesclando a chave mcp.atlas-workflow (config do usuário preservada)`);
|
|
135
|
+
}
|
|
136
|
+
cfg.$schema ??= srcCfg.$schema;
|
|
137
|
+
cfg.mcp = { ...(cfg.mcp ?? {}), ...srcCfg.mcp };
|
|
138
|
+
fs.writeFileSync(dest, JSON.stringify(cfg, null, 2) + '\n');
|
|
139
|
+
return dest;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// pi: mesclar a chave mcpServers.atlas-workflow no .mcp.json existente em vez de
|
|
143
|
+
// sobrescrever o arquivo. Preserva outros servers MCP e demais chaves do usuário.
|
|
144
|
+
function mergePiMcpJson(targetDir) {
|
|
145
|
+
const srcCfg = JSON.parse(fs.readFileSync(path.join(ROOT, 'hosts/pi/.mcp.json'), 'utf8'));
|
|
146
|
+
const dest = path.join(targetDir, '.mcp.json');
|
|
147
|
+
let cfg = {};
|
|
148
|
+
if (fs.existsSync(dest)) {
|
|
149
|
+
try { cfg = JSON.parse(fs.readFileSync(dest, 'utf8')); }
|
|
150
|
+
catch { fail(`.mcp.json existente é JSON inválido: ${dest} (não sobrescrevo config do usuário)`); }
|
|
151
|
+
log(` .mcp.json já existe — mesclando mcpServers.atlas-workflow (config do usuário preservada)`);
|
|
152
|
+
}
|
|
153
|
+
cfg.mcpServers = { ...(cfg.mcpServers ?? {}), ...srcCfg.mcpServers };
|
|
154
|
+
fs.writeFileSync(dest, JSON.stringify(cfg, null, 2) + '\n');
|
|
155
|
+
return dest;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// --- paths globais (verificados no source das deps / empiricamente nas CLIs) -----
|
|
159
|
+
// opencode: config global em $XDG_CONFIG_HOME/opencode (default ~/.config/opencode);
|
|
160
|
+
// agentes em <root>/agents/*.md e skills em <root>/skills/* (confirmado por
|
|
161
|
+
// `opencode agent list` com HOME sandbox).
|
|
162
|
+
function opencodeGlobalRoot() {
|
|
163
|
+
const xdg = process.env.XDG_CONFIG_HOME?.trim();
|
|
164
|
+
if (xdg) return path.join(xdg, 'opencode'); // override determinístico (todo SO)
|
|
165
|
+
if (WIN) {
|
|
166
|
+
// Windows: opencode usa %APPDATA%\opencode (não ~/.config). Fallback p/ ~/.config
|
|
167
|
+
// só se APPDATA ausente. Setar XDG_CONFIG_HOME força o caminho POSIX se preferir.
|
|
168
|
+
const appData = process.env.APPDATA?.trim();
|
|
169
|
+
if (appData) return path.join(appData, 'opencode');
|
|
170
|
+
}
|
|
171
|
+
return path.join(homedir(), '.config', 'opencode');
|
|
172
|
+
}
|
|
173
|
+
// prefere o arquivo existente (.jsonc tem precedência se já existir); senão .json.
|
|
174
|
+
function opencodeConfigFile(root) {
|
|
175
|
+
for (const name of ['opencode.jsonc', 'opencode.json']) {
|
|
176
|
+
const p = path.join(root, name);
|
|
177
|
+
if (fs.existsSync(p)) return p;
|
|
178
|
+
}
|
|
179
|
+
return path.join(root, 'opencode.json');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function opencodeWritableConfigFile(root) {
|
|
183
|
+
const jsonc = path.join(root, 'opencode.jsonc');
|
|
184
|
+
if (fs.existsSync(jsonc) && !isStrictJson(jsonc)) {
|
|
185
|
+
log(` opencode.jsonc contém JSONC/comentários — preservando arquivo e mesclando Atlas em ${path.join(root, 'opencode.json')}`);
|
|
186
|
+
return path.join(root, 'opencode.json');
|
|
187
|
+
}
|
|
188
|
+
return opencodeConfigFile(root);
|
|
189
|
+
}
|
|
190
|
+
// pi: getAgentDir() honra PI_CODING_AGENT_DIR (igual ao pi-mcp-adapter/agent-dir.ts).
|
|
191
|
+
function piAgentDir() {
|
|
192
|
+
const c = process.env.PI_CODING_AGENT_DIR?.trim();
|
|
193
|
+
if (!c) return path.join(homedir(), '.pi', 'agent');
|
|
194
|
+
if (c === '~') return homedir();
|
|
195
|
+
if (c.startsWith('~/')) return path.resolve(homedir(), c.slice(2));
|
|
196
|
+
return path.resolve(c);
|
|
197
|
+
}
|
|
198
|
+
// pi-subagents (agents.ts): com PI_CODING_AGENT_DIR setado usa <agentDir>/agents;
|
|
199
|
+
// senão ~/.agents se existir, senão <agentDir>/agents. Replicamos a mesma escolha
|
|
200
|
+
// para escrever onde o pi REALMENTE lê.
|
|
201
|
+
function piGlobalAgentsDir() {
|
|
202
|
+
const agentDir = piAgentDir();
|
|
203
|
+
if (process.env.PI_CODING_AGENT_DIR?.trim()) return path.join(agentDir, 'agents');
|
|
204
|
+
const dotAgents = path.join(homedir(), '.agents');
|
|
205
|
+
return fs.existsSync(dotAgents) ? dotAgents : path.join(agentDir, 'agents');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Lê a entry de server 'atlas-workflow' do catálogo bundled e reescreve o path do
|
|
209
|
+
// server.js para ABSOLUTO (instalação global não tem cwd de projeto). Mantém shape
|
|
210
|
+
// e env em sincronia com o bundle (mudou lá, muda aqui).
|
|
211
|
+
function absServerEntry(host, atlasRootAbs) {
|
|
212
|
+
const absServer = path.join(atlasRootAbs, 'packages/mcp-server/server.js');
|
|
213
|
+
if (host === 'opencode') {
|
|
214
|
+
const c = JSON.parse(fs.readFileSync(path.join(ROOT, 'hosts/opencode/opencode.json'), 'utf8'));
|
|
215
|
+
return { schema: c.$schema, entry: { ...c.mcp['atlas-workflow'], command: ['node', absServer] } };
|
|
216
|
+
}
|
|
217
|
+
const c = JSON.parse(fs.readFileSync(path.join(ROOT, 'hosts/pi/.mcp.json'), 'utf8'));
|
|
218
|
+
return { entry: { ...c.mcpServers['atlas-workflow'], args: [absServer] } };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Merge genérico de uma entry de server num config JSON. Falha-cedo se o arquivo
|
|
222
|
+
// existente for JSON inválido (não sobrescreve). Preserva outros servers e chaves.
|
|
223
|
+
function mergeServerInto(file, containerKey, serverName, entry, { dryRun, schema } = {}) {
|
|
224
|
+
assertConfigParseable(file);
|
|
225
|
+
let cfg = {};
|
|
226
|
+
if (fs.existsSync(file)) {
|
|
227
|
+
cfg = parseJsonFile(file);
|
|
228
|
+
log(` ${path.basename(file)} já existe — mesclando ${containerKey}.${serverName} (config do usuário preservada)`);
|
|
229
|
+
}
|
|
230
|
+
if (schema) cfg.$schema ??= schema;
|
|
231
|
+
cfg[containerKey] = { ...(cfg[containerKey] ?? {}), [serverName]: entry };
|
|
232
|
+
if (dryRun) return file;
|
|
233
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
234
|
+
fs.writeFileSync(file, JSON.stringify(cfg, null, 2) + '\n');
|
|
235
|
+
return file;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function installClaude(opts) {
|
|
239
|
+
if (!which('claude')) fail('CLI `claude` não encontrada no PATH. Instale o Claude Code primeiro.');
|
|
240
|
+
log(`instalando Atlas (claude/cursor) via marketplace from-source @ ${REPO_SLUG}`);
|
|
241
|
+
if (run('claude', ['plugin', 'marketplace', 'add', REPO_SLUG], opts)) fail('falha no `claude plugin marketplace add`');
|
|
242
|
+
if (run('claude', ['plugin', 'install', PLUGIN_ID], opts)) fail('falha no `claude plugin install`');
|
|
243
|
+
log('ok — Claude Code/Cursor instalados (skills + subagente + MCP + hooks).');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function installCodex(opts) {
|
|
247
|
+
if (!which('codex')) fail('CLI `codex` não encontrada no PATH. Instale o Codex primeiro.');
|
|
248
|
+
log(`instalando Atlas (codex) via marketplace from-source @ ${REPO_SLUG}`);
|
|
249
|
+
if (run('codex', ['plugin', 'marketplace', 'add', REPO_SLUG], opts)) fail('falha no `codex plugin marketplace add`');
|
|
250
|
+
if (run('codex', ['plugin', 'add', PLUGIN_ID], opts)) fail('falha no `codex plugin add`');
|
|
251
|
+
const codexHome = process.env.CODEX_HOME?.trim() || path.join(homedir(), '.codex');
|
|
252
|
+
const agentsDir = path.join(codexHome, 'agents');
|
|
253
|
+
const srcAgents = path.join(ROOT, 'plugins/atlas-workflow-orchestrator/.codex/agents');
|
|
254
|
+
if (!fs.existsSync(srcAgents)) fail('agentes Codex ausentes no catálogo: plugins/atlas-workflow-orchestrator/.codex/agents (rode build/build-plugins.sh)');
|
|
255
|
+
if (opts.dryRun) {
|
|
256
|
+
log(` [dry-run] copiaria custom agents Codex → ${agentsDir}`);
|
|
257
|
+
} else {
|
|
258
|
+
rmAtlasAgentsQuiet(agentsDir, opts, ['.toml']);
|
|
259
|
+
copyAtlasAgents(srcAgents, agentsDir, ['.toml']);
|
|
260
|
+
}
|
|
261
|
+
log(`ok — Codex instalado (skills + MCP + custom agents em ${agentsDir}).`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function installOpencode(targetDir, opts) {
|
|
265
|
+
log(`instalando Atlas (opencode v${VERSION}) em ${targetDir}`);
|
|
266
|
+
assertConfigParseable(path.join(targetDir, 'opencode.json'));
|
|
267
|
+
if (opts.dryRun) { log(' [dry-run] copiaria .opencode/ + mesclaria opencode.json'); return; }
|
|
268
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
269
|
+
cleanOpencodeControlled(targetDir, opts);
|
|
270
|
+
copyInto('hosts/opencode/.opencode', targetDir); // subagente + skills + runtime
|
|
271
|
+
mergeOpencodeJson(targetDir); // MCP local (type:local, ATLAS_HOST=opencode)
|
|
272
|
+
log('ok — opencode instalado (MCP + subagente + skills).');
|
|
273
|
+
log(`próximo: cd ${targetDir} && opencode → confirme com as tools atlas_ping`);
|
|
274
|
+
log(' (deve retornar host=opencode) e atlas_capabilities.');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function piDepsStatus() {
|
|
278
|
+
if (!which('pi')) return { piPresent: false, missing: ['pi-mcp-adapter', 'pi-subagents'] };
|
|
279
|
+
const r = spawnSync('pi', ['list'], { encoding: 'utf8', shell: WIN });
|
|
280
|
+
if (r.status !== 0) return { piPresent: true, missing: ['pi-mcp-adapter', 'pi-subagents'], listFailed: true };
|
|
281
|
+
const out = (r.stdout ?? '') + (r.stderr ?? '');
|
|
282
|
+
const missing = ['pi-mcp-adapter', 'pi-subagents'].filter((d) => !out.includes(d));
|
|
283
|
+
return { piPresent: true, missing };
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function printPiDepsHelp() {
|
|
287
|
+
log('instale com:');
|
|
288
|
+
log(' pi install npm:pi-mcp-adapter');
|
|
289
|
+
log(' pi install npm:pi-subagents');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function ensurePiDeps(opts) {
|
|
293
|
+
let status = piDepsStatus();
|
|
294
|
+
if (!status.piPresent) {
|
|
295
|
+
printPiDepsHelp();
|
|
296
|
+
fail('CLI `pi` não encontrada no PATH. Instale o pi antes de instalar o Atlas para pi.');
|
|
297
|
+
}
|
|
298
|
+
if (status.listFailed) {
|
|
299
|
+
fail('`pi list` falhou; não consigo validar deps obrigatórias do pi.');
|
|
300
|
+
}
|
|
301
|
+
if (!status.missing.length) {
|
|
302
|
+
log('deps obrigatórias presentes: pi-mcp-adapter + pi-subagents ✓');
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
log(`deps obrigatórias ausentes: ${status.missing.join(', ')} (DEC-010)`);
|
|
307
|
+
if (!opts.yes) {
|
|
308
|
+
printPiDepsHelp();
|
|
309
|
+
fail('deps obrigatórias ausentes; re-rode com --yes para instalar automaticamente.');
|
|
310
|
+
}
|
|
311
|
+
if (opts.dryRun) {
|
|
312
|
+
for (const dep of status.missing) log(` [dry-run] pi install npm:${dep}`);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
for (const dep of status.missing) {
|
|
316
|
+
const code = run('pi', ['install', `npm:${dep}`], opts);
|
|
317
|
+
if (code !== 0) fail(`falha ao instalar dep obrigatória do pi: ${dep}`);
|
|
318
|
+
}
|
|
319
|
+
status = piDepsStatus();
|
|
320
|
+
if (status.listFailed) fail('`pi list` falhou após instalar deps obrigatórias.');
|
|
321
|
+
if (status.missing.length) {
|
|
322
|
+
fail(`deps obrigatórias ainda ausentes após instalação: ${status.missing.join(', ')}`);
|
|
323
|
+
}
|
|
324
|
+
log('deps obrigatórias instaladas e revalidadas: pi-mcp-adapter + pi-subagents ✓');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function installPi(targetDir, opts) {
|
|
328
|
+
log(`instalando Atlas (pi v${VERSION}) em ${targetDir}`);
|
|
329
|
+
assertConfigParseable(path.join(targetDir, '.mcp.json'));
|
|
330
|
+
ensurePiDeps(opts);
|
|
331
|
+
if (opts.dryRun) { log(' [dry-run] copiaria atlas/ skills/ .pi/agents/ + .mcp.json'); }
|
|
332
|
+
else {
|
|
333
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
334
|
+
cleanPiControlled(targetDir, opts);
|
|
335
|
+
copyInto('hosts/pi/atlas', targetDir);
|
|
336
|
+
copyInto('hosts/pi/skills', targetDir);
|
|
337
|
+
copyInto('hosts/pi/.pi', targetDir); // .pi/agents/<name>.md (descoberta pi-subagents)
|
|
338
|
+
mergePiMcpJson(targetDir); // mescla mcpServers.atlas-workflow (pi-mcp-adapter)
|
|
339
|
+
log('ok — arquivos do pi instalados (.mcp.json + .pi/agents/ + atlas/ + skills/).');
|
|
340
|
+
}
|
|
341
|
+
log(`próximo: cd ${targetDir} && pi → confirme a instalação com as tools atlas_ping`);
|
|
342
|
+
log(' (deve retornar host=pi) e atlas_capabilities. NÃO dispare o validator à mão:');
|
|
343
|
+
log(' o atlas-task-validator roda automaticamente dentro do workflow, com um state');
|
|
344
|
+
log(' file real (.atlas/state/<run_id>/<slice>.json) — não com placeholder.');
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// --- install global ----------------------------------------------------------
|
|
348
|
+
|
|
349
|
+
function installOpencodeGlobal(opts) {
|
|
350
|
+
const root = opencodeGlobalRoot();
|
|
351
|
+
const atlasRoot = path.join(root, 'atlas');
|
|
352
|
+
const cfgFile = opencodeWritableConfigFile(root);
|
|
353
|
+
log(`instalando Atlas (opencode v${VERSION}) GLOBAL em ${root}`);
|
|
354
|
+
assertConfigParseable(cfgFile);
|
|
355
|
+
const { schema, entry } = absServerEntry('opencode', atlasRoot);
|
|
356
|
+
if (opts.dryRun) {
|
|
357
|
+
log(` [dry-run] copiaria runtime → ${atlasRoot}, agente → ${path.join(root, 'agents')}, skills → ${path.join(root, 'skills')}`);
|
|
358
|
+
log(` [dry-run] mesclaria mcp.atlas-workflow em ${cfgFile} (command absoluto)`);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
fs.mkdirSync(root, { recursive: true });
|
|
362
|
+
rmPath(atlasRoot, opts);
|
|
363
|
+
rmAtlasAgentsQuiet(path.join(root, 'agents'), opts);
|
|
364
|
+
rmAtlasSkillsQuiet(path.join(root, 'skills'), opts);
|
|
365
|
+
fs.cpSync(path.join(ROOT, 'hosts/opencode/.opencode/atlas'), atlasRoot, { recursive: true });
|
|
366
|
+
copyAtlasAgents(path.join(ROOT, 'hosts/opencode/.opencode/agents'), path.join(root, 'agents'));
|
|
367
|
+
const skillsSrc = path.join(ROOT, 'hosts/opencode/.opencode/skills');
|
|
368
|
+
for (const name of fs.readdirSync(skillsSrc)) {
|
|
369
|
+
if (name.startsWith('atlas-')) fs.cpSync(path.join(skillsSrc, name), path.join(root, 'skills', name), { recursive: true });
|
|
370
|
+
}
|
|
371
|
+
mergeServerInto(cfgFile, 'mcp', 'atlas-workflow', entry, { schema });
|
|
372
|
+
log('ok — opencode GLOBAL instalado (vale em todos os projetos).');
|
|
373
|
+
log('próximo: abra `opencode` em qualquer pasta → atlas_ping (host=opencode) + atlas_capabilities.');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function installPiGlobal(opts) {
|
|
377
|
+
const agentDir = piAgentDir();
|
|
378
|
+
const atlasRoot = path.join(agentDir, 'atlas');
|
|
379
|
+
const agentsDir = piGlobalAgentsDir();
|
|
380
|
+
const mcpFile = path.join(agentDir, 'mcp.json');
|
|
381
|
+
log(`instalando Atlas (pi v${VERSION}) GLOBAL em ${agentDir}`);
|
|
382
|
+
assertConfigParseable(mcpFile);
|
|
383
|
+
ensurePiDeps(opts);
|
|
384
|
+
const skillsDir = path.join(agentDir, 'skills'); // irmão de atlas/ — mantém o mesmo
|
|
385
|
+
// offset relativo (../../../skills a partir do server) do install de projeto.
|
|
386
|
+
const { entry } = absServerEntry('pi', atlasRoot);
|
|
387
|
+
if (opts.dryRun) {
|
|
388
|
+
log(` [dry-run] copiaria runtime → ${atlasRoot}, skills → ${skillsDir}, agente → ${path.join(agentsDir, 'atlas-task-validator.md')}`);
|
|
389
|
+
log(` [dry-run] mesclaria mcpServers.atlas-workflow em ${mcpFile} (args absoluto)`);
|
|
390
|
+
} else {
|
|
391
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
392
|
+
rmPath(atlasRoot, opts);
|
|
393
|
+
rmAtlasAgentsQuiet(agentsDir, opts);
|
|
394
|
+
rmAtlasSkillsQuiet(skillsDir, opts);
|
|
395
|
+
fs.cpSync(path.join(ROOT, 'hosts/pi/atlas'), atlasRoot, { recursive: true });
|
|
396
|
+
// skills/ canônicas (paridade com install de projeto e com opencode global): copia
|
|
397
|
+
// só os subdirs atlas-* para não tocar skills do usuário.
|
|
398
|
+
const skillsSrc = path.join(ROOT, 'hosts/pi/skills');
|
|
399
|
+
for (const name of fs.readdirSync(skillsSrc)) {
|
|
400
|
+
if (name.startsWith('atlas-')) fs.cpSync(path.join(skillsSrc, name), path.join(skillsDir, name), { recursive: true });
|
|
401
|
+
}
|
|
402
|
+
copyAtlasAgents(path.join(ROOT, 'hosts/pi/.pi/agents'), agentsDir);
|
|
403
|
+
mergeServerInto(mcpFile, 'mcpServers', 'atlas-workflow', entry);
|
|
404
|
+
log(`ok — pi GLOBAL instalado (runtime + skills + agente em ${agentsDir} + mcp.json).`);
|
|
405
|
+
}
|
|
406
|
+
log('próximo: abra `pi` em qualquer pasta → atlas_ping (host=pi) + atlas_capabilities.');
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// --- uninstall ---------------------------------------------------------------
|
|
410
|
+
|
|
411
|
+
function rmIfExists(p, { dryRun }) {
|
|
412
|
+
if (!fs.existsSync(p)) return false;
|
|
413
|
+
log(` rm ${path.relative(process.cwd(), p) || p}`);
|
|
414
|
+
if (!dryRun) fs.rmSync(p, { recursive: true, force: true });
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Remove apenas subdirs com prefixo atlas- (não toca skills do usuário).
|
|
419
|
+
function rmAtlasSkills(skillsDir, opts) {
|
|
420
|
+
if (!fs.existsSync(skillsDir)) return;
|
|
421
|
+
for (const name of fs.readdirSync(skillsDir)) {
|
|
422
|
+
if (name.startsWith('atlas-')) rmIfExists(path.join(skillsDir, name), opts);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Remove uma chave de server MCP de um config JSON; reescreve. Remove o arquivo só
|
|
427
|
+
// se ficou totalmente vazio (era exclusivo do Atlas). Preserva outros servers.
|
|
428
|
+
function dropMcpKey(file, containerKey, serverName, opts) {
|
|
429
|
+
if (!fs.existsSync(file)) return;
|
|
430
|
+
let cfg;
|
|
431
|
+
try { cfg = JSON.parse(fs.readFileSync(file, 'utf8')); }
|
|
432
|
+
catch { log(` aviso: ${path.basename(file)} é JSON inválido — não mexi`); return; }
|
|
433
|
+
const container = cfg[containerKey];
|
|
434
|
+
if (!container || !(serverName in container)) return;
|
|
435
|
+
log(` ${path.basename(file)}: removendo ${containerKey}.${serverName}`);
|
|
436
|
+
if (opts.dryRun) return;
|
|
437
|
+
delete container[serverName];
|
|
438
|
+
const onlyOurs = Object.keys(container).length === 0
|
|
439
|
+
&& Object.keys(cfg).every((k) => k === containerKey || k === '$schema');
|
|
440
|
+
if (onlyOurs) { fs.rmSync(file, { force: true }); log(` ${path.basename(file)} ficou vazio — removido`); }
|
|
441
|
+
else fs.writeFileSync(file, JSON.stringify(cfg, null, 2) + '\n');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function uninstallClaude(opts) {
|
|
445
|
+
if (!which('claude')) fail('CLI `claude` não encontrada no PATH.');
|
|
446
|
+
log('removendo Atlas (claude/cursor)');
|
|
447
|
+
run('claude', ['plugin', 'uninstall', PLUGIN_ID], opts);
|
|
448
|
+
run('claude', ['plugin', 'marketplace', 'remove', 'atlas-workflow'], opts);
|
|
449
|
+
log('ok — removido do Claude Code/Cursor.');
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function uninstallCodex(opts) {
|
|
453
|
+
if (!which('codex')) fail('CLI `codex` não encontrada no PATH.');
|
|
454
|
+
log('removendo Atlas (codex)');
|
|
455
|
+
run('codex', ['plugin', 'remove', PLUGIN_ID], opts);
|
|
456
|
+
run('codex', ['plugin', 'marketplace', 'remove', 'atlas-workflow'], opts);
|
|
457
|
+
const codexHome = process.env.CODEX_HOME?.trim() || path.join(homedir(), '.codex');
|
|
458
|
+
rmAtlasAgentsQuiet(path.join(codexHome, 'agents'), opts, ['.toml']);
|
|
459
|
+
log('ok — removido do Codex.');
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function uninstallOpencode(targetDir, opts) {
|
|
463
|
+
log(`removendo Atlas (opencode) de ${targetDir}`);
|
|
464
|
+
rmIfExists(path.join(targetDir, '.opencode/atlas'), opts);
|
|
465
|
+
rmAtlasAgentsQuiet(path.join(targetDir, '.opencode/agents'), opts);
|
|
466
|
+
rmAtlasSkills(path.join(targetDir, '.opencode/skills'), opts);
|
|
467
|
+
dropMcpKey(path.join(targetDir, 'opencode.json'), 'mcp', 'atlas-workflow', opts);
|
|
468
|
+
log('ok — artefatos do Atlas removidos (config/skills do usuário preservados).');
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function uninstallPi(targetDir, opts) {
|
|
472
|
+
log(`removendo Atlas (pi) de ${targetDir}`);
|
|
473
|
+
rmIfExists(path.join(targetDir, 'atlas'), opts);
|
|
474
|
+
rmAtlasAgentsQuiet(path.join(targetDir, '.pi/agents'), opts);
|
|
475
|
+
rmAtlasSkills(path.join(targetDir, 'skills'), opts);
|
|
476
|
+
dropMcpKey(path.join(targetDir, '.mcp.json'), 'mcpServers', 'atlas-workflow', opts);
|
|
477
|
+
log('ok — artefatos do Atlas removidos. As deps pi-mcp-adapter/pi-subagents ficam (uso geral);');
|
|
478
|
+
log(' remova manualmente se quiser: pi remove pi-mcp-adapter && pi remove pi-subagents');
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function uninstallOpencodeGlobal(opts) {
|
|
482
|
+
const root = opencodeGlobalRoot();
|
|
483
|
+
log(`removendo Atlas (opencode) GLOBAL de ${root}`);
|
|
484
|
+
rmIfExists(path.join(root, 'atlas'), opts);
|
|
485
|
+
rmAtlasAgentsQuiet(path.join(root, 'agents'), opts);
|
|
486
|
+
rmAtlasSkills(path.join(root, 'skills'), opts);
|
|
487
|
+
dropMcpKey(opencodeWritableConfigFile(root), 'mcp', 'atlas-workflow', opts);
|
|
488
|
+
log('ok — artefatos globais do Atlas removidos (config/skills do usuário preservados).');
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function uninstallPiGlobal(opts) {
|
|
492
|
+
const agentDir = piAgentDir();
|
|
493
|
+
log(`removendo Atlas (pi) GLOBAL de ${agentDir}`);
|
|
494
|
+
rmIfExists(path.join(agentDir, 'atlas'), opts);
|
|
495
|
+
rmAtlasAgentsQuiet(piGlobalAgentsDir(), opts);
|
|
496
|
+
rmAtlasSkills(path.join(agentDir, 'skills'), opts);
|
|
497
|
+
dropMcpKey(path.join(agentDir, 'mcp.json'), 'mcpServers', 'atlas-workflow', opts);
|
|
498
|
+
log('ok — artefatos globais do Atlas removidos. As deps pi-mcp-adapter/pi-subagents ficam (uso geral).');
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function usage() {
|
|
502
|
+
log(`atlas-workflow v${VERSION} — instalador multi-host
|
|
503
|
+
|
|
504
|
+
uso:
|
|
505
|
+
npx github:${REPO_SLUG} init <host> [dir] [flags]
|
|
506
|
+
npx github:${REPO_SLUG} uninstall <host> [dir] [flags]
|
|
507
|
+
|
|
508
|
+
hosts:
|
|
509
|
+
claudecode | cursor via \`claude plugin\` (marketplace from-source; já global)
|
|
510
|
+
codex via \`codex plugin\` + custom agents em CODEX_HOME/agents
|
|
511
|
+
opencode por-projeto: .opencode/ + opencode.json no [dir]
|
|
512
|
+
--global: ~/.config/opencode/ (vale em todos os projetos)
|
|
513
|
+
pi por-projeto: .mcp.json + .pi/agents/ no [dir] + deps
|
|
514
|
+
--global: ~/.pi/agent/ (vale em todos os projetos)
|
|
515
|
+
|
|
516
|
+
flags:
|
|
517
|
+
--dir <d> diretório alvo (opencode/pi por-projeto); default: diretório atual
|
|
518
|
+
--global,-g instalação global (opencode/pi); claude/codex já são globais
|
|
519
|
+
--yes,-y auto-instala deps faltantes (pi, no init)
|
|
520
|
+
--dry-run mostra o que faria, sem alterar nada
|
|
521
|
+
-h,--help esta ajuda
|
|
522
|
+
|
|
523
|
+
exemplos:
|
|
524
|
+
npx github:${REPO_SLUG} init claudecode
|
|
525
|
+
npx github:${REPO_SLUG} init opencode # projeto atual
|
|
526
|
+
npx github:${REPO_SLUG} init opencode --global # todos os projetos
|
|
527
|
+
npx github:${REPO_SLUG} init pi --global --yes
|
|
528
|
+
npx github:${REPO_SLUG} uninstall opencode --global
|
|
529
|
+
npx github:${REPO_SLUG} uninstall pi --global --dry-run`);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function parseArgs(argv) {
|
|
533
|
+
if (argv.length === 0) return { help: true };
|
|
534
|
+
const opts = { dryRun: false, yes: false, global: false };
|
|
535
|
+
const positional = [];
|
|
536
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
537
|
+
const a = argv[i];
|
|
538
|
+
if (a === '-h' || a === '--help') return { help: true };
|
|
539
|
+
if (a === '--dry-run') { opts.dryRun = true; continue; }
|
|
540
|
+
if (a === '--yes' || a === '-y') { opts.yes = true; continue; }
|
|
541
|
+
if (a === '--global' || a === '-g') { opts.global = true; continue; }
|
|
542
|
+
if (a === '--dir') {
|
|
543
|
+
const value = argv[i + 1];
|
|
544
|
+
if (!value || value.startsWith('-')) fail('--dir exige um diretório', 2);
|
|
545
|
+
opts.dir = value;
|
|
546
|
+
i += 1;
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
if (a.startsWith('-')) fail(`flag desconhecida: ${a}`, 2);
|
|
550
|
+
positional.push(a);
|
|
551
|
+
}
|
|
552
|
+
return { positional, opts };
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function main() {
|
|
556
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
557
|
+
if (parsed.help) { usage(); process.exit(0); }
|
|
558
|
+
|
|
559
|
+
const [cmd, rawHost, rawDir, ...extra] = parsed.positional;
|
|
560
|
+
if (cmd !== 'init' && cmd !== 'uninstall') {
|
|
561
|
+
fail(`comando desconhecido: ${cmd} (use \`init <host>\` ou \`uninstall <host>\`)`, 2);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (!rawHost) fail('informe o host: claudecode | cursor | codex | opencode | pi', 2);
|
|
565
|
+
if (extra.length) fail(`argumentos extras não suportados: ${extra.join(' ')}`, 2);
|
|
566
|
+
const host = HOST_ALIASES[rawHost.toLowerCase()];
|
|
567
|
+
if (!host) fail(`host inválido: ${rawHost} (use claudecode|cursor|codex|opencode|pi)`, 2);
|
|
568
|
+
|
|
569
|
+
const opts = parsed.opts;
|
|
570
|
+
const targetDir = path.resolve(opts.dir || rawDir || process.cwd());
|
|
571
|
+
const actions = {
|
|
572
|
+
init: { claude: installClaude, codex: installCodex, opencode: installOpencode, pi: installPi },
|
|
573
|
+
uninstall: { claude: uninstallClaude, codex: uninstallCodex, opencode: uninstallOpencode, pi: uninstallPi },
|
|
574
|
+
};
|
|
575
|
+
const globalActions = {
|
|
576
|
+
init: { opencode: installOpencodeGlobal, pi: installPiGlobal },
|
|
577
|
+
uninstall: { opencode: uninstallOpencodeGlobal, pi: uninstallPiGlobal },
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
if (host === 'claude' || host === 'codex') {
|
|
581
|
+
if (opts.global) log('nota: claude/codex já são globais por natureza (registro da CLI) — --global ignorado.');
|
|
582
|
+
actions[cmd][host](opts);
|
|
583
|
+
} else if (opts.global) {
|
|
584
|
+
globalActions[cmd][host](opts);
|
|
585
|
+
} else {
|
|
586
|
+
actions[cmd][host](targetDir, opts);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
main();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Executor direto da família Atlas (modo direct). Despachado em contexto isolado pelo orquestrador para implementar um PRD/tarefa escopada sem artefato de plano separado — toda mutação de código acontece aqui, nunca no fio do orquestrador (Gate G9). Primeira ação: carregar a skill completa atlas-direct-execute. Antes do relatório final, escreve o state_path e retorna validator_handoff_required; o orquestrador despacha a validação fria sibling (atlas-task-validator, Gate G4).
|
|
3
|
+
mode: subagent
|
|
4
|
+
temperature: 0.1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Atlas Direct Execute (sub-agent)
|
|
8
|
+
|
|
9
|
+
<!-- MANUTENÇÃO (cross-host): SHIM portável — carrega o SKILL.md real de
|
|
10
|
+
atlas-direct-execute como primeira ação (references/subagent_dispatch.md). Contrato em
|
|
11
|
+
packages/skills/atlas-direct-execute/SKILL.md (fonte única). Versões Codex/opencode/pi
|
|
12
|
+
GERADAS por build/gen-host-agent.mjs. Não copiar o corpo da skill para cá. -->
|
|
13
|
+
|
|
14
|
+
Sub-agent de execução direta despachado pelo orquestrador `atlas-workflow-orchestrator`. Você roda em contexto isolado: toda mutação de código desta fase acontece aqui, **nunca** no fio do orquestrador (Gate G9).
|
|
15
|
+
|
|
16
|
+
## Primeira ação obrigatória
|
|
17
|
+
|
|
18
|
+
Carregue a skill completa `atlas-direct-execute` e siga-a integralmente:
|
|
19
|
+
|
|
20
|
+
- **Claude Code:** invoque a tool `Skill` com `atlas-direct-execute`.
|
|
21
|
+
- **Outros hosts:** use o mecanismo nativo de skills do host para carregar `atlas-direct-execute`.
|
|
22
|
+
|
|
23
|
+
Proibido "agir como a skill" a partir deste resumo — o `SKILL.md` é o contrato real (ledger de obrigações do PRD, gates finitos, reparo limitado). Se não conseguir carregar a skill, aborte com erro explícito; não emule inline.
|
|
24
|
+
|
|
25
|
+
## Input
|
|
26
|
+
|
|
27
|
+
O orquestrador passa o PRD/spec/path escopado e as flags da fase. Use `atlas_run_state` como fonte primária do estado da run.
|
|
28
|
+
|
|
29
|
+
## Validação fria (Gate G4)
|
|
30
|
+
|
|
31
|
+
Antes do relatório final, a validação fria é sempre **sibling**, em todos os hosts: escreva o `state_path`, pare mutações e retorne `validator_handoff_required` para o orquestrador despachar o validador irmão. Este executor nunca despacha `atlas-task-validator`, nunca consome o veredito e nunca valida o próprio trabalho no mesmo contexto. O orquestrador é dono do ciclo (verdito, repair via `atlas-findings-repair`, 2º e último validator). Só `fail` reabre o loop.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Reparador enxuto da família Atlas. Despachado pelo orquestrador apenas após `atlas-task-validator` retornar `fail` em topologia sibling. Corrige findings P0/P1/P2 dentro do boundary da slice sem carregar `atlas-plan-execute`/`atlas-direct-execute` e sem despachar novo validator.
|
|
3
|
+
mode: subagent
|
|
4
|
+
temperature: 0.1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Atlas Findings Repair (sub-agent)
|
|
8
|
+
|
|
9
|
+
<!-- MANUTENÇÃO (cross-host): shim portável. O contrato real vive em
|
|
10
|
+
packages/skills/atlas-findings-repair/SKILL.md. Codex/opencode/pi geram
|
|
11
|
+
registros nativos a partir deste arquivo por build/gen-host-agent.mjs. -->
|
|
12
|
+
|
|
13
|
+
Sub-agent de reparo bounded despachado pelo orquestrador `atlas-workflow-orchestrator`.
|
|
14
|
+
|
|
15
|
+
## Primeira ação obrigatória
|
|
16
|
+
|
|
17
|
+
Carregue a skill completa `atlas-findings-repair` e siga-a integralmente:
|
|
18
|
+
|
|
19
|
+
- **Claude Code:** invoque a tool `Skill` com `atlas-findings-repair`.
|
|
20
|
+
- **Outros hosts:** use o mecanismo nativo de skills do host para carregar `atlas-findings-repair`.
|
|
21
|
+
|
|
22
|
+
Proibido “agir como executor” a partir deste resumo. Se não conseguir carregar a skill, aborte com erro explícito; não substitua por `atlas-plan-execute` nem `atlas-direct-execute`.
|
|
23
|
+
|
|
24
|
+
## Input
|
|
25
|
+
|
|
26
|
+
O orquestrador passa obrigatoriamente `state_path`, findings estruturados, `validator_attempt`, `repair_run_id` e `repair_budget: 1`. Use `atlas_run_state` como fonte primária do estado da run.
|
|
27
|
+
|
|
28
|
+
## Limites
|
|
29
|
+
|
|
30
|
+
- Corrigir apenas findings P0/P1/P2 da slice atual
|
|
31
|
+
- Não despachar validator nem outro subagente
|
|
32
|
+
- Não replanejar
|
|
33
|
+
- Não ampliar escopo
|
|
34
|
+
- Atualizar o `state_path` original em lugar; não trocar o boundary para outro arquivo
|
|
35
|
+
- Ao terminar, devolver `repair_complete` ou `blocked`
|