atlas-workflow 0.9.1 → 0.9.3
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/README.md +5 -2
- package/VERSION +1 -1
- package/build/bump-version.mjs +6 -21
- package/build/cli/atlas-init.mjs +92 -5
- package/build/tests/classify-findings.test.mjs +20 -0
- package/build/tests/etapa3.test.mjs +161 -0
- package/build/tests/test_classify_findings.py +79 -0
- package/hosts/opencode/.opencode/agents/atlas-findings-repair.md +4 -0
- package/hosts/opencode/.opencode/agents/atlas-task-validator.md +18 -1
- package/hosts/opencode/.opencode/atlas/VERSION +1 -1
- package/hosts/opencode/.opencode/atlas/orchestrator/README.md +7 -5
- package/hosts/opencode/.opencode/atlas/orchestrator/commands/workflow.md +1 -1
- package/hosts/opencode/.opencode/atlas/orchestrator/references/host-adapters.md +13 -12
- package/hosts/opencode/.opencode/atlas/orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +24 -17
- package/hosts/opencode/.opencode/atlas/packages/mcp-server/README.md +1 -1
- package/hosts/opencode/.opencode/atlas/packages/mcp-server/package.json +1 -1
- package/hosts/opencode/.opencode/atlas/packages/mcp-server/server.js +514 -20
- package/hosts/opencode/.opencode/atlas/packages/templates/BACKLOG_MESTRE_TEMPLATE.md +14 -3
- package/hosts/opencode/.opencode/atlas/packages/templates/PRD_TEMPLATE.md +2 -1
- package/hosts/opencode/.opencode/atlas/packages/templates/STATE_FILE_SCHEMA.md +25 -1
- package/hosts/opencode/.opencode/skills/_shared/references/stack-profiles.md +36 -0
- package/hosts/opencode/.opencode/skills/_shared/scripts/document_quality.mjs +252 -0
- package/hosts/opencode/.opencode/skills/atlas-backlog-generator/SKILL.md +7 -2
- package/hosts/opencode/.opencode/skills/atlas-direct-execute/SKILL.md +6 -2
- package/hosts/opencode/.opencode/skills/atlas-findings-repair/SKILL.md +11 -1
- package/hosts/opencode/.opencode/skills/atlas-plan-execute/SKILL.md +16 -2
- package/hosts/opencode/.opencode/skills/atlas-plan-handoff/SKILL.md +6 -4
- package/hosts/opencode/.opencode/skills/atlas-prd-interview/SKILL.md +7 -2
- package/hosts/opencode/.opencode/skills/atlas-slice-review/SKILL.md +37 -2
- package/hosts/opencode/.opencode/skills/atlas-slice-review/references/scenario-lenses.md +8 -0
- package/hosts/opencode/.opencode/skills/atlas-slice-review/scripts/classify_findings.mjs +60 -0
- package/hosts/opencode/.opencode/skills/atlas-slice-review/scripts/classify_findings.py +9 -41
- package/hosts/opencode/.opencode/skills/atlas-sprint-prd-generator/SKILL.md +7 -4
- package/hosts/opencode/.opencode/skills/atlas-task-validator/SKILL.md +29 -14
- package/hosts/opencode/.opencode/skills/atlas-workflow-orchestrator/SKILL.md +24 -17
- package/hosts/pi/.pi/agents/atlas-direct-execute.md +6 -2
- package/hosts/pi/.pi/agents/atlas-findings-repair.md +15 -1
- package/hosts/pi/.pi/agents/atlas-plan-execute.md +16 -2
- package/hosts/pi/.pi/agents/atlas-slice-review.md +37 -2
- package/hosts/pi/.pi/agents/atlas-task-validator.md +18 -1
- package/hosts/pi/atlas/VERSION +1 -1
- package/hosts/pi/atlas/orchestrator/README.md +7 -5
- package/hosts/pi/atlas/orchestrator/commands/workflow.md +1 -1
- package/hosts/pi/atlas/orchestrator/references/host-adapters.md +13 -12
- package/hosts/pi/atlas/orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +24 -17
- package/hosts/pi/atlas/packages/mcp-server/README.md +1 -1
- package/hosts/pi/atlas/packages/mcp-server/package.json +1 -1
- package/hosts/pi/atlas/packages/mcp-server/server.js +514 -20
- package/hosts/pi/atlas/packages/templates/BACKLOG_MESTRE_TEMPLATE.md +14 -3
- package/hosts/pi/atlas/packages/templates/PRD_TEMPLATE.md +2 -1
- package/hosts/pi/atlas/packages/templates/STATE_FILE_SCHEMA.md +25 -1
- package/hosts/pi/skills/_shared/references/stack-profiles.md +36 -0
- package/hosts/pi/skills/_shared/scripts/document_quality.mjs +252 -0
- package/hosts/pi/skills/atlas-backlog-generator/SKILL.md +7 -2
- package/hosts/pi/skills/atlas-direct-execute/SKILL.md +6 -2
- package/hosts/pi/skills/atlas-findings-repair/SKILL.md +11 -1
- package/hosts/pi/skills/atlas-plan-execute/SKILL.md +16 -2
- package/hosts/pi/skills/atlas-plan-handoff/SKILL.md +6 -4
- package/hosts/pi/skills/atlas-prd-interview/SKILL.md +7 -2
- package/hosts/pi/skills/atlas-slice-review/SKILL.md +37 -2
- package/hosts/pi/skills/atlas-slice-review/references/scenario-lenses.md +8 -0
- package/hosts/pi/skills/atlas-slice-review/scripts/classify_findings.mjs +60 -0
- package/hosts/pi/skills/atlas-slice-review/scripts/classify_findings.py +9 -41
- package/hosts/pi/skills/atlas-sprint-prd-generator/SKILL.md +7 -4
- package/hosts/pi/skills/atlas-task-validator/SKILL.md +29 -14
- package/hosts/pi/skills/atlas-workflow-orchestrator/SKILL.md +24 -17
- package/hosts/zcode/.zcode-plugin/plugin.json +27 -0
- package/hosts/zcode/agents/atlas-direct-execute.md +31 -0
- package/hosts/zcode/agents/atlas-findings-repair.md +39 -0
- package/hosts/zcode/agents/atlas-plan-execute.md +33 -0
- package/hosts/zcode/agents/atlas-slice-review.md +27 -0
- package/hosts/zcode/agents/atlas-task-validator.md +138 -0
- package/hosts/zcode/packages/mcp-server/README.md +29 -0
- package/hosts/zcode/packages/mcp-server/VERSION +1 -0
- package/hosts/zcode/packages/mcp-server/package.json +15 -0
- package/hosts/zcode/packages/mcp-server/server.js +3897 -0
- package/hosts/zcode/packages/orchestrator/README.md +270 -0
- package/hosts/zcode/packages/orchestrator/commands/workflow.md +37 -0
- package/hosts/zcode/packages/orchestrator/defaults/paths.md +21 -0
- package/hosts/zcode/packages/orchestrator/references/host-adapters.md +106 -0
- package/hosts/zcode/packages/orchestrator/references/qa_s13_matrix.md +141 -0
- package/hosts/zcode/packages/orchestrator/references/subagent_dispatch.md +42 -0
- package/hosts/zcode/packages/orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +391 -0
- package/hosts/zcode/packages/templates/BACKLOG_MESTRE_TEMPLATE.md +855 -0
- package/hosts/zcode/packages/templates/BOUNDARY_PRD_PLAN.md +93 -0
- package/hosts/zcode/packages/templates/PERGUNTAS_EM_ABERTO_TEMPLATE.md +139 -0
- package/hosts/zcode/packages/templates/PLAN_TEMPLATE.md +146 -0
- package/hosts/zcode/packages/templates/PRD_TEMPLATE.md +150 -0
- package/hosts/zcode/packages/templates/STATE_FILE_SCHEMA.md +56 -0
- package/hosts/zcode/skills/_shared/references/stack-profiles.md +36 -0
- package/hosts/zcode/skills/_shared/scripts/document_quality.mjs +252 -0
- package/hosts/zcode/skills/atlas-backlog-generator/SKILL.md +93 -0
- package/hosts/zcode/skills/atlas-backlog-generator/agents/openai.yaml +4 -0
- package/hosts/zcode/skills/atlas-direct-execute/SKILL.md +221 -0
- package/hosts/zcode/skills/atlas-direct-execute/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-findings-repair/SKILL.md +158 -0
- package/hosts/zcode/skills/atlas-findings-repair/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-plan-execute/SKILL.md +175 -0
- package/hosts/zcode/skills/atlas-plan-execute/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-plan-execute/references/plan-contract.md +88 -0
- package/hosts/zcode/skills/atlas-plan-execute/references/quality-gates.md +60 -0
- package/hosts/zcode/skills/atlas-plan-execute/scripts/check_budget_state.py +96 -0
- package/hosts/zcode/skills/atlas-plan-execute/scripts/extract_plan_contract.py +191 -0
- package/hosts/zcode/skills/atlas-plan-execute/scripts/validate_gate_result.py +56 -0
- package/hosts/zcode/skills/atlas-plan-handoff/SKILL.md +183 -0
- package/hosts/zcode/skills/atlas-plan-handoff/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-prd-interview/SKILL.md +82 -0
- package/hosts/zcode/skills/atlas-prd-interview/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-slice-review/SKILL.md +156 -0
- package/hosts/zcode/skills/atlas-slice-review/agents/openai.yaml +4 -0
- package/hosts/zcode/skills/atlas-slice-review/references/review-contract.md +58 -0
- package/hosts/zcode/skills/atlas-slice-review/references/scenario-lenses.md +57 -0
- package/hosts/zcode/skills/atlas-slice-review/scripts/classify_findings.mjs +60 -0
- package/hosts/zcode/skills/atlas-slice-review/scripts/classify_findings.py +24 -0
- package/hosts/zcode/skills/atlas-slice-review/scripts/extract_review_slice.py +158 -0
- package/hosts/zcode/skills/atlas-sprint-prd-generator/SKILL.md +77 -0
- package/hosts/zcode/skills/atlas-sprint-prd-generator/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-task-validator/SKILL.md +173 -0
- package/hosts/zcode/skills/atlas-task-validator/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-workflow-orchestrator/SKILL.md +391 -0
- package/package.json +1 -1
- package/plugins/atlas-workflow-orchestrator/.codex/agents/atlas-findings-repair.toml +1 -1
- package/plugins/atlas-workflow-orchestrator/.codex/agents/atlas-task-validator.toml +1 -1
- package/plugins/atlas-workflow-orchestrator/.codex-plugin/plugin.json +1 -1
- package/plugins/atlas-workflow-orchestrator/VERSION +1 -1
- package/plugins/atlas-workflow-orchestrator/agents/atlas-findings-repair.md +4 -0
- package/plugins/atlas-workflow-orchestrator/agents/atlas-task-validator.md +18 -1
- package/plugins/atlas-workflow-orchestrator/orchestrator/README.md +7 -5
- package/plugins/atlas-workflow-orchestrator/orchestrator/commands/workflow.md +1 -1
- package/plugins/atlas-workflow-orchestrator/orchestrator/references/host-adapters.md +13 -12
- package/plugins/atlas-workflow-orchestrator/orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +24 -17
- package/plugins/atlas-workflow-orchestrator/packages/mcp-server/README.md +1 -1
- package/plugins/atlas-workflow-orchestrator/packages/mcp-server/package.json +1 -1
- package/plugins/atlas-workflow-orchestrator/packages/mcp-server/server.js +514 -20
- package/plugins/atlas-workflow-orchestrator/packages/skills/_shared/references/stack-profiles.md +36 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/_shared/scripts/document_quality.mjs +252 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-backlog-generator/SKILL.md +7 -2
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-direct-execute/SKILL.md +6 -2
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-findings-repair/SKILL.md +11 -1
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-plan-execute/SKILL.md +16 -2
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-plan-handoff/SKILL.md +6 -4
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-prd-interview/SKILL.md +7 -2
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-slice-review/SKILL.md +37 -2
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-slice-review/references/scenario-lenses.md +8 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-slice-review/scripts/classify_findings.mjs +60 -0
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-slice-review/scripts/classify_findings.py +9 -41
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-sprint-prd-generator/SKILL.md +7 -4
- package/plugins/atlas-workflow-orchestrator/packages/skills/atlas-task-validator/SKILL.md +29 -14
- package/plugins/atlas-workflow-orchestrator/packages/templates/BACKLOG_MESTRE_TEMPLATE.md +14 -3
- package/plugins/atlas-workflow-orchestrator/packages/templates/PRD_TEMPLATE.md +2 -1
- package/plugins/atlas-workflow-orchestrator/packages/templates/STATE_FILE_SCHEMA.md +25 -1
- package/plugins/atlas-workflow-orchestrator/skills/_shared/references/stack-profiles.md +36 -0
- package/plugins/atlas-workflow-orchestrator/skills/_shared/scripts/document_quality.mjs +252 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-backlog-generator/SKILL.md +7 -2
- package/plugins/atlas-workflow-orchestrator/skills/atlas-direct-execute/SKILL.md +6 -2
- package/plugins/atlas-workflow-orchestrator/skills/atlas-findings-repair/SKILL.md +11 -1
- package/plugins/atlas-workflow-orchestrator/skills/atlas-plan-execute/SKILL.md +16 -2
- package/plugins/atlas-workflow-orchestrator/skills/atlas-plan-handoff/SKILL.md +6 -4
- package/plugins/atlas-workflow-orchestrator/skills/atlas-prd-interview/SKILL.md +7 -2
- package/plugins/atlas-workflow-orchestrator/skills/atlas-slice-review/SKILL.md +37 -2
- package/plugins/atlas-workflow-orchestrator/skills/atlas-slice-review/references/scenario-lenses.md +8 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-slice-review/scripts/classify_findings.mjs +60 -0
- package/plugins/atlas-workflow-orchestrator/skills/atlas-slice-review/scripts/classify_findings.py +9 -41
- package/plugins/atlas-workflow-orchestrator/skills/atlas-sprint-prd-generator/SKILL.md +7 -4
- package/plugins/atlas-workflow-orchestrator/skills/atlas-task-validator/SKILL.md +29 -14
- package/plugins/atlas-workflow-orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +24 -17
- package/plugins/atlas-workflow-orchestrator/templates/BACKLOG_MESTRE_TEMPLATE.md +14 -3
- package/plugins/atlas-workflow-orchestrator/templates/PRD_TEMPLATE.md +2 -1
- package/plugins/atlas-workflow-orchestrator/templates/STATE_FILE_SCHEMA.md +25 -1
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const VALID = Object.freeze({
|
|
6
|
+
moscow: new Set(['Must', 'Should', 'Could', "Won't now"]),
|
|
7
|
+
gain: new Set(['alto', 'médio', 'baixo']),
|
|
8
|
+
effort: new Set(['alto', 'médio', 'baixo']),
|
|
9
|
+
priority: new Set(['P0', 'P1', 'P2', 'P3']),
|
|
10
|
+
state: new Set(['backlog', 'ready', 'doing', 'review', 'done', 'blocked']),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const STACK_MANIFESTS = ['package.json', 'tsconfig.json', 'pubspec.yaml', 'pyproject.toml', 'requirements.txt', 'setup.py'];
|
|
14
|
+
|
|
15
|
+
function boundaryRoot(projectRoot, boundary) {
|
|
16
|
+
const project = path.resolve(projectRoot);
|
|
17
|
+
let current = path.resolve(project, boundary ?? '.');
|
|
18
|
+
const relative = path.relative(project, current);
|
|
19
|
+
if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
20
|
+
throw new Error(`BOUNDARY_OUTSIDE_PROJECT:${boundary}`);
|
|
21
|
+
}
|
|
22
|
+
if (fs.existsSync(current) && fs.statSync(current).isFile()) current = path.dirname(current);
|
|
23
|
+
while (current === project || current.startsWith(`${project}${path.sep}`)) {
|
|
24
|
+
if (STACK_MANIFESTS.some((name) => fs.existsSync(path.join(current, name)))) return current;
|
|
25
|
+
if (current === project) break;
|
|
26
|
+
current = path.dirname(current);
|
|
27
|
+
}
|
|
28
|
+
return path.resolve(project, boundary ?? '.');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function containsGetxImport(root) {
|
|
32
|
+
const queue = ['lib', 'test'].map((name) => path.join(root, name)).filter((dir) => fs.existsSync(dir));
|
|
33
|
+
let inspected = 0;
|
|
34
|
+
while (queue.length > 0 && inspected < 5000) {
|
|
35
|
+
const current = queue.pop();
|
|
36
|
+
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
|
|
37
|
+
const target = path.join(current, entry.name);
|
|
38
|
+
if (entry.isDirectory()) queue.push(target);
|
|
39
|
+
else if (entry.isFile() && entry.name.endsWith('.dart')) {
|
|
40
|
+
inspected += 1;
|
|
41
|
+
if (/package:get\/get(?:_core)?\.dart/.test(fs.readFileSync(target, 'utf8'))) return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function detectBoundaryProfile(root, declaredCommands) {
|
|
49
|
+
const exists = (name) => fs.existsSync(path.join(root, name));
|
|
50
|
+
const commands = declaredCommands.filter((v) => typeof v === 'string');
|
|
51
|
+
let packageJson = null;
|
|
52
|
+
if (exists('package.json')) {
|
|
53
|
+
try { packageJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')); } catch {}
|
|
54
|
+
}
|
|
55
|
+
let pubspec = '';
|
|
56
|
+
if (exists('pubspec.yaml')) {
|
|
57
|
+
try { pubspec = fs.readFileSync(path.join(root, 'pubspec.yaml'), 'utf8'); } catch {}
|
|
58
|
+
}
|
|
59
|
+
const packageCommands = Object.values(packageJson?.scripts ?? {}).filter((v) => typeof v === 'string');
|
|
60
|
+
const allCommands = [...commands, ...packageCommands];
|
|
61
|
+
const hasCommand = (re) => allCommands.some((command) => re.test(command));
|
|
62
|
+
return {
|
|
63
|
+
universal: true,
|
|
64
|
+
flutter_dart: exists('pubspec.yaml') || hasCommand(/\b(flutter|dart)\b/),
|
|
65
|
+
node_typescript: exists('package.json') || exists('tsconfig.json') || hasCommand(/\b(node|npm|pnpm|yarn|bun|tsc)\b/),
|
|
66
|
+
python: exists('pyproject.toml') || exists('requirements.txt') || exists('setup.py') || hasCommand(/\b(python3?|pytest|ruff|mypy)\b/),
|
|
67
|
+
getx: /^\s{0,4}get\s*:/m.test(pubspec) || containsGetxImport(root),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function detectStackProfiles(root, declaredCommands = [], boundaryPaths = ['.']) {
|
|
72
|
+
const project = path.resolve(root);
|
|
73
|
+
const requested = boundaryPaths.length > 0 ? boundaryPaths : ['.'];
|
|
74
|
+
const boundaries = [...new Set(requested.map((boundary) => boundaryRoot(project, boundary)))].map((dir) => ({
|
|
75
|
+
boundary: path.relative(project, dir).replaceAll('\\', '/') || '.',
|
|
76
|
+
...detectBoundaryProfile(dir, declaredCommands),
|
|
77
|
+
}));
|
|
78
|
+
return {
|
|
79
|
+
universal: true,
|
|
80
|
+
flutter_dart: boundaries.some((profile) => profile.flutter_dart),
|
|
81
|
+
node_typescript: boundaries.some((profile) => profile.node_typescript),
|
|
82
|
+
python: boundaries.some((profile) => profile.python),
|
|
83
|
+
getx: boundaries.some((profile) => profile.getx),
|
|
84
|
+
boundaries,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function parseTable(markdown, heading) {
|
|
89
|
+
const start = markdown.indexOf(heading);
|
|
90
|
+
if (start < 0) return [];
|
|
91
|
+
const tail = markdown.slice(start + heading.length);
|
|
92
|
+
const end = tail.search(/\n##?\s/);
|
|
93
|
+
return (end < 0 ? tail : tail.slice(0, end)).split('\n')
|
|
94
|
+
.filter((line) => /^\|.*\|\s*$/.test(line))
|
|
95
|
+
.map((line) => line.split('|').slice(1, -1).map((cell) => cell.trim()))
|
|
96
|
+
.filter((cells) => cells.length && !cells.every((cell) => /^-+$/.test(cell)));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function parseSprintRows(markdown) {
|
|
100
|
+
const rows = parseTable(markdown, '## 7. Registro de sprints');
|
|
101
|
+
const header = rows.findIndex((row) => row[0] === 'ID');
|
|
102
|
+
return rows.slice(header + 1).filter((row) => /^S\d{2}[a-z]?$/.test(row[0])).map((row) => ({
|
|
103
|
+
id: row[0], name: row[1], phase: row[2], objective: row[3], moscow: row[4], gain: row[5].toLowerCase(),
|
|
104
|
+
effort: row[6].toLowerCase(), priority: row[7], prd: row[8], dependencies: row[9], state: row[10], gate: row[11], raw: row,
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function parseDecisionRows(markdown) {
|
|
109
|
+
const rows = parseTable(markdown, '### Decisões bloqueantes');
|
|
110
|
+
const header = rows.findIndex((row) => row[0] === 'ID');
|
|
111
|
+
return rows.slice(header + 1).filter((row) => /^D\d+$/.test(row[0])).map((row) => ({
|
|
112
|
+
id: row[0], decision: row[1], blocks: row[2], owner: row[3], status: row[4], raw: row,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function dependencyIds(value) {
|
|
117
|
+
if (!value || value === '—') return [];
|
|
118
|
+
return [...value.matchAll(/S\d{2}[a-z]?/g)].map((match) => match[0]);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function findCycle(rows) {
|
|
122
|
+
const graph = new Map(rows.map((row) => [row.id, dependencyIds(row.dependencies)]));
|
|
123
|
+
const visiting = new Set(); const visited = new Set();
|
|
124
|
+
const walk = (id, chain = []) => {
|
|
125
|
+
if (visiting.has(id)) return [...chain.slice(chain.indexOf(id)), id];
|
|
126
|
+
if (visited.has(id)) return null;
|
|
127
|
+
visiting.add(id);
|
|
128
|
+
for (const dep of graph.get(id) ?? []) {
|
|
129
|
+
const cycle = walk(dep, [...chain, id]);
|
|
130
|
+
if (cycle) return cycle;
|
|
131
|
+
}
|
|
132
|
+
visiting.delete(id); visited.add(id); return null;
|
|
133
|
+
};
|
|
134
|
+
for (const id of graph.keys()) { const cycle = walk(id); if (cycle) return cycle; }
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function changeLogBody(markdown) {
|
|
139
|
+
const match = /^##\s+(?:Registro de alterações|Histórico de alterações)\s*$/im.exec(markdown);
|
|
140
|
+
if (!match) return null;
|
|
141
|
+
const tail = markdown.slice(match.index + match[0].length);
|
|
142
|
+
const end = tail.search(/\n##\s+/);
|
|
143
|
+
return (end < 0 ? tail : tail.slice(0, end)).trim();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function validateBacklogUpdate(before, after, { authorizedIds = [] } = {}) {
|
|
147
|
+
const errors = [];
|
|
148
|
+
const authorized = new Set(authorizedIds);
|
|
149
|
+
const oldRows = parseSprintRows(before); const newRows = parseSprintRows(after);
|
|
150
|
+
const oldById = new Map(oldRows.map((row) => [row.id, row]));
|
|
151
|
+
const newById = new Map(newRows.map((row) => [row.id, row]));
|
|
152
|
+
if (oldById.size !== oldRows.length) errors.push('DUPLICATE_SPRINT_ID_BEFORE');
|
|
153
|
+
if (newById.size !== newRows.length) errors.push('DUPLICATE_SPRINT_ID_AFTER');
|
|
154
|
+
for (const [id, oldRow] of oldById) {
|
|
155
|
+
const next = newById.get(id);
|
|
156
|
+
if (!next) errors.push(`SPRINT_REMOVED:${id}`);
|
|
157
|
+
else if (JSON.stringify(oldRow.raw) !== JSON.stringify(next.raw) && !authorized.has(id)) {
|
|
158
|
+
errors.push(oldRow.state === 'done' ? `DONE_SPRINT_CHANGED:${id}` : `UNAUTHORIZED_SPRINT_CHANGED:${id}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const oldDecisions = new Map(parseDecisionRows(before).map((row) => [row.id, row]));
|
|
162
|
+
const newDecisions = new Map(parseDecisionRows(after).map((row) => [row.id, row]));
|
|
163
|
+
for (const [id, row] of oldDecisions) {
|
|
164
|
+
const next = newDecisions.get(id);
|
|
165
|
+
if (!next) errors.push(`DECISION_REMOVED:${id}`);
|
|
166
|
+
else if (/^(decidido|fechado|aprovado)$/i.test(row.status)
|
|
167
|
+
&& JSON.stringify(row.raw) !== JSON.stringify(next.raw) && !authorized.has(id)) errors.push(`CLOSED_DECISION_CHANGED:${id}`);
|
|
168
|
+
}
|
|
169
|
+
for (const row of newRows) {
|
|
170
|
+
for (const [field, values] of Object.entries(VALID)) if (!values.has(row[field])) errors.push(`INVALID_ENUM:${row.id}:${field}:${row[field]}`);
|
|
171
|
+
for (const dependency of dependencyIds(row.dependencies)) {
|
|
172
|
+
if (!newById.has(dependency)) errors.push(`DEPENDENCY_NOT_FOUND:${row.id}:${dependency}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const cycle = findCycle(newRows); if (cycle) errors.push(`DEPENDENCY_CYCLE:${cycle.join('>')}`);
|
|
176
|
+
if (/\[(?:NOME_|RESULTADO_|observação|decisão|slug|pendente\])/i.test(after)) errors.push('UNRESOLVED_PLACEHOLDER');
|
|
177
|
+
if (before !== after) {
|
|
178
|
+
const oldLog = changeLogBody(before);
|
|
179
|
+
const newLog = changeLogBody(after);
|
|
180
|
+
if (newLog === null) errors.push('CHANGELOG_REQUIRED');
|
|
181
|
+
else if (oldLog !== null && !newLog.startsWith(oldLog)) errors.push('CHANGELOG_REWRITTEN');
|
|
182
|
+
else if (newLog === oldLog) errors.push('CHANGELOG_ENTRY_REQUIRED');
|
|
183
|
+
}
|
|
184
|
+
return { valid: errors.length === 0, errors };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function resolveSprintAuthority({ sprintId, explicitPath, canonicalPath, candidates }) {
|
|
188
|
+
const normalized = candidates.map((candidate) => ({ ...candidate, path: path.resolve(candidate.path) }));
|
|
189
|
+
const byPath = (target) => normalized.find((candidate) => candidate.path === path.resolve(target));
|
|
190
|
+
if (explicitPath) {
|
|
191
|
+
const match = byPath(explicitPath); if (!match?.sprints.includes(sprintId)) throw new Error(`SPRINT_NOT_FOUND_IN_EXPLICIT_PATH:${sprintId}`); return match;
|
|
192
|
+
}
|
|
193
|
+
if (canonicalPath) {
|
|
194
|
+
const match = byPath(canonicalPath); if (!match?.sprints.includes(sprintId)) throw new Error(`SPRINT_NOT_FOUND_IN_CANONICAL_BACKLOG:${sprintId}`); return match;
|
|
195
|
+
}
|
|
196
|
+
const matches = normalized.filter((candidate) => candidate.sprints.includes(sprintId));
|
|
197
|
+
if (matches.length !== 1) throw new Error(matches.length ? `AMBIGUOUS_BACKLOG_AUTHORITY:${matches.map((m) => m.path).join(',')}` : `SPRINT_NOT_FOUND:${sprintId}`);
|
|
198
|
+
return matches[0];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function closedDecisionIds(prd) {
|
|
202
|
+
return new Set([...prd.matchAll(/^\|\s*(D\d+)\s*\|\s*(?!<|\[)(.+?)\s*\|\s*$/gm)].map((match) => match[1]));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function pendingInterviewQuestions(prd, questions) {
|
|
206
|
+
const closed = closedDecisionIds(prd);
|
|
207
|
+
return questions.filter((question) => !closed.has(question.decision_id));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function applyInterviewRound(prd, answers, date = new Date().toISOString().slice(0, 10)) {
|
|
211
|
+
const ids = new Set();
|
|
212
|
+
for (const answer of answers) {
|
|
213
|
+
if (!answer || typeof answer.decision_id !== 'string' || !/^D\d+$/.test(answer.decision_id)) throw new Error('INVALID_DECISION_ID');
|
|
214
|
+
if (ids.has(answer.decision_id)) throw new Error(`DUPLICATE_DECISION_ID:${answer.decision_id}`);
|
|
215
|
+
if (typeof answer.value !== 'string' || !answer.value.trim()) throw new Error(`EMPTY_DECISION_VALUE:${answer.decision_id}`);
|
|
216
|
+
ids.add(answer.decision_id);
|
|
217
|
+
}
|
|
218
|
+
let updated = prd;
|
|
219
|
+
for (const answer of answers) {
|
|
220
|
+
const row = new RegExp(`^\\|\\s*${answer.decision_id}\\s*\\|.*$`, 'm');
|
|
221
|
+
const replacement = `| ${answer.decision_id} | ${answer.value} |`;
|
|
222
|
+
updated = row.test(updated) ? updated.replace(row, replacement) : updated.replace(/(\| ID \| Decisão \|\n\|[-| ]+\|)/, `$1\n${replacement}`);
|
|
223
|
+
}
|
|
224
|
+
const log = `${date} — entrevista: ${answers.map((answer) => answer.decision_id).join(', ')} persistida(s)`;
|
|
225
|
+
updated = /\*\*Histórico:\*\*/.test(updated)
|
|
226
|
+
? updated.replace(/(\*\*Histórico:\*\*[^\n]*)/, `$1 · ${log}`)
|
|
227
|
+
: `${updated.trimEnd()}\n\n**Histórico:** ${log}\n`;
|
|
228
|
+
return updated;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function persistInterviewRound(prdPath, answers, date = new Date().toISOString().slice(0, 10)) {
|
|
232
|
+
const absolute = path.resolve(prdPath);
|
|
233
|
+
const temporary = path.join(path.dirname(absolute), `.${path.basename(absolute)}.${process.pid}.${Date.now()}.tmp`);
|
|
234
|
+
try {
|
|
235
|
+
const current = fs.readFileSync(absolute, 'utf8');
|
|
236
|
+
const updated = applyInterviewRound(current, answers, date);
|
|
237
|
+
const materialized = closedDecisionIds(updated);
|
|
238
|
+
const missingBeforeWrite = answers.filter((answer) => !materialized.has(answer.decision_id));
|
|
239
|
+
if (missingBeforeWrite.length > 0) {
|
|
240
|
+
throw new Error(`DECISION_NOT_MATERIALIZED:${missingBeforeWrite.map((answer) => answer.decision_id).join(',')}`);
|
|
241
|
+
}
|
|
242
|
+
const mode = fs.statSync(absolute).mode;
|
|
243
|
+
fs.writeFileSync(temporary, updated, { encoding: 'utf8', mode });
|
|
244
|
+
fs.renameSync(temporary, absolute);
|
|
245
|
+
const readback = fs.readFileSync(absolute, 'utf8');
|
|
246
|
+
if (readback !== updated) throw new Error('READBACK_DIVERGENT');
|
|
247
|
+
return readback;
|
|
248
|
+
} catch (error) {
|
|
249
|
+
try { fs.rmSync(temporary, { force: true }); } catch {}
|
|
250
|
+
throw new Error(`INTERVIEW_PERSISTENCE_FAILED:${error.message}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atlas-backlog-generator
|
|
3
|
+
description: Skill `atlas-backlog-generator`. Use somente quando o usuário acionar explicitamente `$atlas-backlog-generator` ou pedir explicitamente para criar, gerar, montar, estruturar ou atualizar um backlog mestre Atlas a partir de uma conversa, prompt, ideia de feature, briefing, PRD macro, lista solta de requisitos, roadmap ou objetivo de produto, usando `BACKLOG_MESTRE_TEMPLATE.md` como template canônico e aplicando fases, sprints, dependências, MoSCoW e esforço x ganho. Não usar por inferência implícita em pedidos genéricos de planejamento, brainstorming, PRD ou implementação.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Atlas Backlog Generator
|
|
7
|
+
|
|
8
|
+
Crie backlogs mestres Atlas em PT-BR, ancorados no template canônico, com decomposição gradual em fases e sprints pequenas, priorização MoSCoW, matriz esforço x ganho, dependências explícitas, gates, riscos e próxima sprint executável.
|
|
9
|
+
|
|
10
|
+
Esta skill é documental: ela cria ou atualiza o `BACKLOG_MESTRE*.md` no projeto consumidor. Ela não implementa código, não gera PRDs de sprint e não substitui `atlas-sprint-prd-generator`.
|
|
11
|
+
|
|
12
|
+
Acione esta skill apenas por pedido explícito. Se o usuário apenas pedir planejamento, brainstorming, PRD ou execução, não usar esta skill automaticamente.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Entradas aceitas
|
|
17
|
+
|
|
18
|
+
- Conversa livre, ideia de feature, prompt exploratório ou briefing incompleto.
|
|
19
|
+
- PRD macro, roadmap, lista de requisitos, issue/backlog item ou texto colado pelo usuário.
|
|
20
|
+
- Opcional: nome do projeto/feature, path de saída, fontes canônicas, restrições técnicas, prioridade de negócio e escopo fora do ciclo.
|
|
21
|
+
|
|
22
|
+
Se faltar informação não bloqueante, gere o backlog com premissas marcadas e registre perguntas/riscos. Pergunte antes de salvar somente quando faltar uma das decisões bloqueantes: resultado final esperado, fronteira de escopo ou plataforma/produto alvo.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Workflow obrigatório
|
|
27
|
+
|
|
28
|
+
1. **Resolver template canônico:** descubra a raiz do plugin/bundle e leia `packages/templates/BACKLOG_MESTRE_TEMPLATE.md`. Se ausente, aborte com: `Template canônico ausente: BACKLOG_MESTRE_TEMPLATE.md`.
|
|
29
|
+
2. **Entender pedido:** extraia objetivo, usuários, resultado final esperado, fora de escopo, restrições, dependências, riscos, stakeholders e sinais de valor.
|
|
30
|
+
3. **Inspecionar contexto real:** quando houver repo/projeto ativo, busque documentos existentes (`BACKLOG_MESTRE*.md`, `PRD*.md`, `ROADMAP*.md`, specs, OpenAPI, docs de arquitetura) e código que influencie dependências. Não invente contrato técnico.
|
|
31
|
+
4. **Fechar ambiguidade crítica:** se uma decisão bloquear a decomposição segura, faça até 3 perguntas objetivas. Se o usuário não responder e houver caminho razoável, registre a premissa como risco/decisão pendente.
|
|
32
|
+
5. **Preencher o template:** mantenha todas as seções do template e substitua placeholders por conteúdo específico. Não apague seções; use `não aplicável` apenas com justificativa curta.
|
|
33
|
+
6. **Decompor em sprints:** transforme o objetivo em fatias verticais pequenas, cada uma com objetivo único, dependências e PRD futuro (`PRD_S<NN>_<slug>.md`).
|
|
34
|
+
7. **Priorizar:** para cada sprint, preencha MoSCoW, ganho, esforço e prioridade usando a regra da seção 8.3 do template.
|
|
35
|
+
8. **Selecionar próxima sprint:** escolha a primeira sprint executável respeitando dependências, DoR, MoSCoW, esforço x ganho e risco. Registre a justificativa na seção 20.
|
|
36
|
+
9. **Atualização não destrutiva:** se o arquivo já existe, compare antes/depois com `validateBacklogUpdate(before, after, { authorizedIds })` de `../_shared/scripts/document_quality.mjs`. `authorizedIds` contém somente IDs cuja mudança foi explicitamente decidida pelo usuário. Preserve demais IDs, linhas `done`, decisões `decidido|fechado|aprovado`, itens/sprints e ordem histórica.
|
|
37
|
+
10. **Registrar alterações:** toda atualização acrescenta `## Registro de alterações` (data, IDs afetados, motivo e fonte). Não reescreva histórico anterior.
|
|
38
|
+
11. **Salvar artefato:** grave o backlog no path pedido ou, se não houver path, crie o diretório `.atlas/backlog/` no projeto consumidor e use `.atlas/backlog/BACKLOG_MESTRE_<slug>.md`.
|
|
39
|
+
12. **Validar antes de finalizar:** bloqueie se `validateBacklogUpdate` apontar sprint/decisão removida, sprint `done` alterada, enum inválido, ciclo de dependência, placeholder acidental ou falta de registro. Confirme também que dependências referenciam IDs existentes.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Regras de decomposição
|
|
44
|
+
|
|
45
|
+
- Gere sprints como unidades de entrega, não períodos de tempo.
|
|
46
|
+
- Mantenha cada sprint com 6 a 8 tasks no máximo quando o PRD futuro for detalhado; se uma sprint tiver mais de um objetivo, quebre em `S<NN>a/b/c`.
|
|
47
|
+
- Comece com descoberta/contrato quando houver ambiguidade ou integração. Não pule para implementação quando o contrato ainda for desconhecido.
|
|
48
|
+
- Preserve a ordem natural: descoberta → especificação/contrato → backend/infra quando necessário → front/app → hardening → QA → rollout.
|
|
49
|
+
- Use dependências para permitir paralelismo seguro; não transforme fase em fila rígida se duas sprints independentes puderem avançar.
|
|
50
|
+
- Inclua estados de erro, loading, empty, permission, observabilidade, QA e rollout onde aplicável. Esses itens não são “extras”; são parte do produto pronto.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Regras de priorização
|
|
55
|
+
|
|
56
|
+
- `Must`: obrigatório para resultado final, segurança, compliance, contrato ou desbloqueio.
|
|
57
|
+
- `Should`: importante para qualidade/adoção, mas contornável por um ciclo.
|
|
58
|
+
- `Could`: refinamento ou melhoria desejável que não bloqueia entrega.
|
|
59
|
+
- `Won't now`: fora do ciclo atual; registre para reduzir reabertura de discussão.
|
|
60
|
+
- `P0`: alto ganho com baixo/médio esforço ou Must desbloqueador.
|
|
61
|
+
- `P1`: alto ganho com alto esforço, ou médio ganho com baixo esforço.
|
|
62
|
+
- `P2`: médio ganho/médio esforço, ou baixo ganho/baixo esforço.
|
|
63
|
+
- `P3`: baixo ganho com médio/alto esforço, candidato a adiar.
|
|
64
|
+
|
|
65
|
+
Se MoSCoW e esforço x ganho conflitarem, MoSCoW vence; uma sprint `Must` de esforço alto deve ser quebrada, não rebaixada silenciosamente.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Qualidade esperada do backlog
|
|
70
|
+
|
|
71
|
+
O backlog final deve:
|
|
72
|
+
|
|
73
|
+
- Declarar precedência documental e fontes canônicas.
|
|
74
|
+
- Explicitar resultado esperado e fora do escopo.
|
|
75
|
+
- Ter dependências internas/externas e decisões bloqueantes com dono/status.
|
|
76
|
+
- Ter registro de sprints com MoSCoW, ganho, esforço, prioridade, PRD futuro, dependências, estado e gate.
|
|
77
|
+
- Ter grafo de dependência coerente com a tabela de sprints.
|
|
78
|
+
- Ter catálogo de fases preservado e adaptado apenas quando necessário.
|
|
79
|
+
- Ter riscos, decisões e próxima sprint executável preenchidos.
|
|
80
|
+
- Ser específico o bastante para gerar PRDs de sprint depois com `atlas-sprint-prd-generator`.
|
|
81
|
+
- Preservar histórico/IDs em update e passar validação de ciclos/enums/placeholders.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Proibições
|
|
86
|
+
|
|
87
|
+
- Não entregar uma lista genérica de tarefas sem usar o template.
|
|
88
|
+
- Não remover gates, DoR/DoD, riscos, decisões ou trilhas transversais.
|
|
89
|
+
- Não inventar endpoints, tabelas, schemas, fornecedores, métricas ou responsabilidades como fatos. Quando forem hipóteses, marcar como premissa.
|
|
90
|
+
- Não transformar o backlog em plano técnico de implementação. Código, classes e comandos entram no plano/PRD quando apropriado, não no backlog mestre.
|
|
91
|
+
- Não deixar `[...]` ou placeholders óbvios no arquivo final, salvo quando o campo estiver deliberadamente pendente e explicado.
|
|
92
|
+
- Não renumerar IDs, reabrir/editar sprint `done`, alterar decisão fechada ou remover item não relacionado por conveniência editorial.
|
|
93
|
+
- Não ser acionada pelo orquestrador: permanece **explicit-only**, fora de qualquer cadeia automática.
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atlas-direct-execute
|
|
3
|
+
description: Execute a scoped PRD, task, or implementation slice directly using a compact execution contract, PRD obligation tracking, finite task gates, bounded repair, and mandatory cold validation via atlas-task-validator. Use when the user provides a PRD/spec/path or a debated task and wants implementation now without first producing a separate planning artifact. Preserve evidence against acceptance criteria, dependencies, fixtures, and invariants.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Atlas Direct Execute
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Execute directly from a PRD/spec/task while preserving execution quality: explicit scope, obligations, invariants, task order, risks, and validation. Do not write a separate planning artifact unless the user asks.
|
|
11
|
+
|
|
12
|
+
This is not planless execution. Replace the visible markdown plan with a compact operational contract held in the current turn and passed to validation.
|
|
13
|
+
|
|
14
|
+
## Executor liveness checkpoints
|
|
15
|
+
|
|
16
|
+
Depois de carregar esta skill e antes de qualquer discovery longo, emita um checkpoint MCP:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
atlas_lock_dispatch({
|
|
20
|
+
"action": "checkpoint",
|
|
21
|
+
"phase": "plan_execute",
|
|
22
|
+
"event": "executor_started"
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Em seguida, emita checkpoints materiais conforme avança:
|
|
27
|
+
|
|
28
|
+
- `skill_loaded` — skill carregada e contrato reconhecido.
|
|
29
|
+
- `plan_loaded` — PRD/spec/task de entrada lido.
|
|
30
|
+
- `handoff_accepted` — boundary, obligations, `state_path` alvo e contrato direto aceitos.
|
|
31
|
+
- `task_started` — primeira task começou.
|
|
32
|
+
- `first_write` — primeira mutação de workspace feita.
|
|
33
|
+
- `state_path_created` — state file escrito antes de devolver `validator_handoff_required`.
|
|
34
|
+
|
|
35
|
+
Se não conseguir emitir checkpoint por MCP, retorne `blocked`: liveness não é comprovável. Sem `state_path_created` com o mesmo `state_path`, `atlas_lock_validator(start)` bloqueia em G12 e o orquestrador não pode despachar o validador frio.
|
|
36
|
+
|
|
37
|
+
## Use Criteria
|
|
38
|
+
|
|
39
|
+
Use when all are true:
|
|
40
|
+
|
|
41
|
+
- User wants implementation, not a planning artifact.
|
|
42
|
+
- Scope is a PRD/spec/path or a debated task with clear boundaries.
|
|
43
|
+
- Work fits one coherent slice or a bounded task sequence.
|
|
44
|
+
- Execution happens in the same chat/context.
|
|
45
|
+
- A compact contract can be materialized into the state file boundary required by `atlas-task-validator`.
|
|
46
|
+
|
|
47
|
+
Do not use when any are true:
|
|
48
|
+
|
|
49
|
+
- User asks only for planning, review, explanation, or handoff artifact.
|
|
50
|
+
- Product rules, permissions, backend contract, migrations, security, or data-loss risk are materially ambiguous.
|
|
51
|
+
- The PRD/spec conflicts with code or adjacent docs in a way that blocks implementation.
|
|
52
|
+
|
|
53
|
+
## Workflow
|
|
54
|
+
|
|
55
|
+
### 0. Triage
|
|
56
|
+
|
|
57
|
+
Before implementation, decide one exact path:
|
|
58
|
+
|
|
59
|
+
- `direct`: proceed with this skill.
|
|
60
|
+
- `blocked`: ask for the missing decision or environment.
|
|
61
|
+
|
|
62
|
+
Ask at most 1-3 blocking questions only when a reasonable assumption could change product behavior, contract, permissions, persistence, or user-visible outcome. Otherwise state assumptions and proceed.
|
|
63
|
+
|
|
64
|
+
### 1. Load inputs
|
|
65
|
+
|
|
66
|
+
First, emit `executor_started`, then `skill_loaded`, before doing any long scan.
|
|
67
|
+
|
|
68
|
+
Read the user-provided PRD/spec/task and any directly referenced files needed to resolve scope. If the input names repo artifacts, verify those artifacts exist before editing.
|
|
69
|
+
|
|
70
|
+
Extract only execution-relevant items:
|
|
71
|
+
|
|
72
|
+
- in scope / out of scope
|
|
73
|
+
- acceptance criteria and required deliverables
|
|
74
|
+
- accepted decisions
|
|
75
|
+
- invariants and "do not change" rules
|
|
76
|
+
- contracts, entities, routes, schemas, wrappers, generated files
|
|
77
|
+
- dependency contracts that must be consumed, bridged, or preserved
|
|
78
|
+
- fixture requirements and scenario language such as "weeks", "profiles", "matrix", "sequence", or "integration"
|
|
79
|
+
- validation requirements
|
|
80
|
+
- regression risks
|
|
81
|
+
- likely files/modules
|
|
82
|
+
|
|
83
|
+
If the PRD references another PRD or code contract as dependency, inspect enough to confirm the dependency shape and required bridge. Do not satisfy a dependency by creating parallel synthetic contracts unless the PRD explicitly allows it.
|
|
84
|
+
|
|
85
|
+
After the input is loaded, emit `plan_loaded`. After validating the execution boundary, obligations, and `state_path` target, emit `handoff_accepted`.
|
|
86
|
+
|
|
87
|
+
### 2. Build Compact Execution Contract
|
|
88
|
+
|
|
89
|
+
Before editing, write a compact contract in the working response or internal task state. Size follows complexity: terse for simple tasks, denser only where needed to preserve scope, invariants, and validator quality.
|
|
90
|
+
|
|
91
|
+
Required shape:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
Direct Execute Contract
|
|
95
|
+
- Goal:
|
|
96
|
+
- Boundary:
|
|
97
|
+
- In scope:
|
|
98
|
+
- Out of scope:
|
|
99
|
+
- Obligations:
|
|
100
|
+
- Invariants:
|
|
101
|
+
- Dependency bridges:
|
|
102
|
+
- Fixtures/scenarios:
|
|
103
|
+
- Scenario probes:
|
|
104
|
+
- Risk probes:
|
|
105
|
+
- Task order:
|
|
106
|
+
- Validation:
|
|
107
|
+
- Stop conditions:
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Do not expand this into a separate planning artifact. The goal is execution guardrails, not transfer documentation. The contract may be terse in the user-visible response, but it must be concrete enough to materialize into `.atlas/state/<run_id>/<slice>.json` and referenced evidence for `atlas-task-validator`.
|
|
111
|
+
|
|
112
|
+
Obligations are mandatory. Convert every PRD acceptance criterion and explicit deliverable into one compact row:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
O1 <requirement> -> evidence: <file/test/check>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
When the PRD asks for fixtures, profiles, weeks, matrices, bridges/adapters, immutability, determinism, or calendar semantics, name those explicitly in `Obligations`. Do not collapse them into generic "tests cover rules".
|
|
119
|
+
|
|
120
|
+
Add a closure analysis packet before implementation starts. Keep it compact, but concrete enough that a cold validator can hunt omissions instead of only confirming obvious files:
|
|
121
|
+
|
|
122
|
+
- `Invariant ledger`: each invariant or "do not change" rule, with expected code evidence.
|
|
123
|
+
- `Scenario probes`: negative, repeated, empty/null, out-of-order, partial failure, stale state, permission, and cleanup scenarios relevant to this slice.
|
|
124
|
+
- `Contract probes`: DTO/entity/schema/route/RPC/generated/localization/import boundaries that could drift.
|
|
125
|
+
- `Risk probes`: each regression risk translated into a specific question the validator must answer from code.
|
|
126
|
+
- `Validation map`: which checks prove which obligations, and which obligations remain only manually evidenced.
|
|
127
|
+
|
|
128
|
+
If a probe is irrelevant, omit it. Do not write generic probes such as "check edge cases"; name the exact state, actor, field, route, or failure mode.
|
|
129
|
+
|
|
130
|
+
### 3. Implement by finite tasks
|
|
131
|
+
|
|
132
|
+
Execute one task at a time. Prefer this order when applicable:
|
|
133
|
+
|
|
134
|
+
1. contracts/types/domain
|
|
135
|
+
2. dependency bridges/adapters from existing models or contracts
|
|
136
|
+
3. datasource/client boundary
|
|
137
|
+
4. repository/use case/state
|
|
138
|
+
5. UI/route wiring
|
|
139
|
+
6. fixtures/tests/generation/docs required for closure
|
|
140
|
+
|
|
141
|
+
For each task, keep a tiny task contract:
|
|
142
|
+
|
|
143
|
+
- objective
|
|
144
|
+
- files likely touched
|
|
145
|
+
- invariants at risk
|
|
146
|
+
- obligations satisfied
|
|
147
|
+
- focused check
|
|
148
|
+
- repair budget
|
|
149
|
+
|
|
150
|
+
Do not widen scope for opportunistic cleanup.
|
|
151
|
+
|
|
152
|
+
**Minimalism rung (per task, before writing):** prefer the minimal viable implementation that satisfies the obligation — reuse existing repo code/symbol before introducing a new abstraction; use a stdlib/native platform feature before a new dependency; avoid indirection, factory, wrapper, extra layer, config option, or extra file not required by an obligation or invariant. This rung constrains only new abstraction/indirection/file/dependency. It never reduces trust-boundary validation, error handling, data-loss handling, invariants, scenario/test coverage, or negative paths. When minimal and safe conflict, choose safe.
|
|
153
|
+
|
|
154
|
+
Before the first concrete task, emit `task_started`. After the first workspace mutation, emit `first_write`.
|
|
155
|
+
|
|
156
|
+
### 4. Gate each task
|
|
157
|
+
|
|
158
|
+
Run focused checks appropriate to the diff:
|
|
159
|
+
|
|
160
|
+
- targeted tests
|
|
161
|
+
- analyzer/typecheck/lint
|
|
162
|
+
- codegen/localization/schema checks when relevant
|
|
163
|
+
- diff scan for scope creep
|
|
164
|
+
- runtime/browser verification when UI changed
|
|
165
|
+
|
|
166
|
+
If a check fails, classify:
|
|
167
|
+
|
|
168
|
+
- `fixable`: caused by current diff and repairable inside budget
|
|
169
|
+
- `blocked`: missing env, upstream failure, ambiguous contract, or required decision
|
|
170
|
+
- `pre-existing`: outside slice; report, do not repair unless blocking closure
|
|
171
|
+
|
|
172
|
+
Repair only current-diff failures. Stop after repeated failure or budget exhaustion.
|
|
173
|
+
|
|
174
|
+
### 5. Mandatory cold validation
|
|
175
|
+
|
|
176
|
+
After tasks and local gates pass, write `.atlas/state/<run_id>/<slice>.json` following `packages/templates/STATE_FILE_SCHEMA.md`.
|
|
177
|
+
|
|
178
|
+
For direct execution, the state file is still the only validator input. Use the user-provided PRD/spec path as `plan_path` when no handoff plan exists, and include direct-contract anchors in `boundary_refs` such as `direct.O1`, `direct.invariant.permissions`, or `direct.risk.partial_failure`.
|
|
179
|
+
|
|
180
|
+
Persist the full direct contract using the additive state extension: `base_sha`, `head_sha`, `contract_kind: direct`, non-empty `obligations`, `invariants`, `scenario_probes`, `risk_probes`, `validation_map`, `task_evidence`, empty `repair_evidence`, `worktree_baseline` and `worktree_final`. Capture baseline before the first mutation and final immediately before handoff; `files_changed`/evidence must equal `base_sha...head_sha` + snapshot delta. Capture base from an explicit task/spec anchor or execution-start `HEAD`; never infer it from branch name. Recompute `head_sha` and `diff_stat` immediately before handoff. A direct state without obligations is invalid and must block.
|
|
181
|
+
|
|
182
|
+
The state file is the only validator input. Validation is always **sibling**, on every host: this executor **never** dispatches `atlas-task-validator` itself and never validates its own work in the same context. After tasks and local gates pass and the state file is written, this executor **stops mutation** and returns `validator_handoff_required` with the `state_path`. The orchestrator then dispatches `atlas-task-validator` as the next isolated sibling phase, locks it via `atlas_lock_validator`, and — if the verdict is `fail` — dispatches `atlas-findings-repair` (not this executor) before the **2nd and last** validator.
|
|
183
|
+
|
|
184
|
+
After writing the state file and before returning, emit `state_path_created` with the same `state_path`.
|
|
185
|
+
|
|
186
|
+
Do not paste the compact contract, diff, obligation ledger, local checks, or closure analysis packet into the state file's handoff. Those belong in the state file and referenced artifacts.
|
|
187
|
+
|
|
188
|
+
**Finish all local work before the handoff — then stop idle.** Finish every local gate (lint, analyze, tests, `git diff --check`, diff-stat) and write the state file **before** returning the handoff. After returning `validator_handoff_required`, do nothing: no diff hygiene checks, no extra reads, no opportunistic edits, no parallel work. The orchestrator now owns the slice; any mutation here would change what the sibling validator reads and breaks determinism (same failure class as the orchestrator's G9).
|
|
189
|
+
|
|
190
|
+
The verdict is consumed by the **orchestrator**, not by this executor:
|
|
191
|
+
|
|
192
|
+
- `pass` / `pass_with_observations`: terminal — the orchestrator closes the slice (observations are reported residuals, never a trigger for another validator dispatch).
|
|
193
|
+
- `fail`: the orchestrator opens `repair_start`, dispatches `atlas-findings-repair`, closes with `repair_run_id`, and runs the **2nd and last** validator. This executor does not re-validate itself and is not reused for the repair retry.
|
|
194
|
+
|
|
195
|
+
This executor only re-engages if the orchestrator explicitly re-dispatches it for a new slice. It must not "fix" observations and reopen a closed slice; real follow-up from an observation goes to the final report or backlog, not into an extra in-slice change.
|
|
196
|
+
|
|
197
|
+
If isolated subagents or MCP are unavailable, return `blocked` with the missing prerequisite and next safe action. Never replace cold validation with a local self-check or report `validator not run` as an accepted pipeline outcome.
|
|
198
|
+
|
|
199
|
+
## Stop Conditions
|
|
200
|
+
|
|
201
|
+
Stop and report instead of improvising when:
|
|
202
|
+
|
|
203
|
+
- code contradicts the PRD in product behavior, permissions, backend contract, or persistence shape
|
|
204
|
+
- required dependency PRD/contract is missing or unstable
|
|
205
|
+
- implementing would violate explicit out-of-scope
|
|
206
|
+
- deterministic checks cannot run and no equivalent evidence exists
|
|
207
|
+
- repair loops repeat the same failure twice
|
|
208
|
+
- validator cannot receive a valid `.atlas/state/<run_id>/<slice>.json` state path
|
|
209
|
+
- any PRD obligation lacks code/test/check evidence after implementation
|
|
210
|
+
|
|
211
|
+
## Final Report
|
|
212
|
+
|
|
213
|
+
Keep final report short:
|
|
214
|
+
|
|
215
|
+
- changed scope
|
|
216
|
+
- files touched
|
|
217
|
+
- validations run
|
|
218
|
+
- `validator_handoff_required` + `state_path`
|
|
219
|
+
- blockers or residual risks
|
|
220
|
+
|
|
221
|
+
Do not include the full internal contract unless the user asks.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "Atlas Direct Execute"
|
|
3
|
+
short_description: "Direct PRD execution with cold validation"
|
|
4
|
+
default_prompt: "Use $atlas-direct-execute to implement this PRD or scoped task directly with a compact obligation ledger, focused gates, and validator closure."
|
|
5
|
+
|
|
6
|
+
policy:
|
|
7
|
+
allow_implicit_invocation: true
|