@spec-wave/cli 0.5.8 → 0.5.9
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/package.json +1 -1
- package/src/commands/implement.mjs +56 -29
- package/src/commands/info.mjs +3 -1
- package/src/commands/init.mjs +27 -21
- package/src/commands/install-skill.mjs +33 -16
- package/src/config.mjs +11 -0
- package/src/templates/skill/SKILL.md +41 -38
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
|
4
4
|
import { execSync } from 'node:child_process';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { resolveToken } from '../api/auth.mjs';
|
|
7
|
-
import { CONFIG_FILE } from '../config.mjs';
|
|
7
|
+
import { CONFIG_FILE, STAGE_IN_PROGRESS, STAGE_DONE, STAGE_CODE_REVIEW } from '../config.mjs';
|
|
8
8
|
import { getIssue } from '../api/github-rest.mjs';
|
|
9
9
|
import { listSubIssues, getIssueParent } from '../api/github-graphql.mjs';
|
|
10
10
|
import { detectIssueType } from '../lib/issue-type.mjs';
|
|
@@ -14,14 +14,17 @@ import { slugify } from '../lib/slugify.mjs';
|
|
|
14
14
|
const WORK_DIR = '.spec-wave';
|
|
15
15
|
|
|
16
16
|
// Sobe a cadeia de pais (Task → Story → Feature) até achar uma issue do tipo
|
|
17
|
-
// "Feature" e devolve
|
|
18
|
-
//
|
|
19
|
-
|
|
17
|
+
// "Feature" e devolve { number, title } — usado para resolver docs/features/<slug>
|
|
18
|
+
// e para as instruções de fim de Story (mover a Feature para Code Review). Limita
|
|
19
|
+
// a profundidade para evitar loops em dados inconsistentes.
|
|
20
|
+
async function resolveFeature(token, startNodeId) {
|
|
20
21
|
let current = startNodeId;
|
|
21
22
|
for (let depth = 0; depth < 5 && current; depth++) {
|
|
22
23
|
const parent = await getIssueParent(token, current);
|
|
23
24
|
if (!parent) return null;
|
|
24
|
-
if (detectIssueType({ title: parent.title }) === 'Feature')
|
|
25
|
+
if (detectIssueType({ title: parent.title }) === 'Feature') {
|
|
26
|
+
return { number: parent.number, title: parent.title };
|
|
27
|
+
}
|
|
25
28
|
current = parent.nodeId;
|
|
26
29
|
}
|
|
27
30
|
return null;
|
|
@@ -40,7 +43,7 @@ function readSpecPlan(featureDir) {
|
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
// Monta o markdown de contexto que será entregue ao spec-kit implement.
|
|
43
|
-
function buildContext({ type, issue, tasks, spec, plan, specPath, planPath }) {
|
|
46
|
+
function buildContext({ type, issue, tasks, feature, spec, plan, specPath, planPath }) {
|
|
44
47
|
const lines = [];
|
|
45
48
|
lines.push(`# Contexto de implementação — ${type} #${issue.number}`);
|
|
46
49
|
lines.push('');
|
|
@@ -50,32 +53,55 @@ function buildContext({ type, issue, tasks, spec, plan, specPath, planPath }) {
|
|
|
50
53
|
lines.push(issue.body.trim());
|
|
51
54
|
}
|
|
52
55
|
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
.filter((n, i, arr) => arr.indexOf(n) === i);
|
|
56
|
+
// Fluxo SEQUENCIAL, uma task por vez: cada task só vai para "In Progress"
|
|
57
|
+
// quando seu desenvolvimento começa e vai para "Done" ao concluir — nunca
|
|
58
|
+
// todas as tasks em "In Progress" ao mesmo tempo.
|
|
57
59
|
lines.push('');
|
|
58
|
-
lines.push('## Instruções
|
|
60
|
+
lines.push('## Instruções de execução (uma task por vez, sequencial)');
|
|
61
|
+
lines.push('');
|
|
62
|
+
if (type === 'Story') {
|
|
63
|
+
lines.push(
|
|
64
|
+
`Implemente as ${tasks.length} task(s) desta Story **uma de cada vez, na ordem listada ` +
|
|
65
|
+
'abaixo**. É PROIBIDO mover mais de uma task para "In Progress" ao mesmo tempo: uma task ' +
|
|
66
|
+
'só entra em desenvolvimento depois que a anterior estiver concluída.'
|
|
67
|
+
);
|
|
68
|
+
lines.push('');
|
|
69
|
+
lines.push(`1. Ao **iniciar a primeira** task, mova a Story #${issue.number} para **${STAGE_IN_PROGRESS}**.`);
|
|
70
|
+
lines.push('2. Para **cada task**, na ordem, execute este ciclo completo antes de passar para a próxima:');
|
|
71
|
+
lines.push(` 1. **Ao começar a task:** mova o status (campo "Etapa") *apenas dessa task* para **${STAGE_IN_PROGRESS}** (In Progress). Nenhuma outra task.`);
|
|
72
|
+
lines.push(' 2. **Implemente** essa task por completo.');
|
|
73
|
+
lines.push(` 3. **Ao concluir a task:** mova o status *dessa task* para **${STAGE_DONE}** (Done).`);
|
|
74
|
+
lines.push(' 4. Só então avance para a próxima task e repita o ciclo.');
|
|
75
|
+
lines.push('');
|
|
76
|
+
lines.push(`3. **Ao concluir a implementação de TODA a Story** (todas as tasks em **${STAGE_DONE}**):`);
|
|
77
|
+
lines.push(' 1. Faça o **commit** de todas as mudanças da implementação.');
|
|
78
|
+
lines.push(` 2. Abra o **Pull Request** da Story #${issue.number}.`);
|
|
79
|
+
lines.push(
|
|
80
|
+
` 3. Mova ${feature ? `a Feature #${feature.number}` : 'a Feature (issue pai da Story)'} e a ` +
|
|
81
|
+
`Story #${issue.number} para **${STAGE_CODE_REVIEW}**. ` +
|
|
82
|
+
`As **Tasks permanecem em ${STAGE_DONE}** (não as mova para trás).`
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
lines.push(`Implemente a Task #${issue.number} bracketando o status no GitHub Project:`);
|
|
86
|
+
lines.push('');
|
|
87
|
+
lines.push(`1. **Ao começar:** mova o status (campo "Etapa") da Task #${issue.number} para **${STAGE_IN_PROGRESS}** (In Progress).`);
|
|
88
|
+
lines.push('2. **Implemente** a task por completo.');
|
|
89
|
+
lines.push(`3. **Ao concluir:** mova o status da Task #${issue.number} para **${STAGE_DONE}** (Done).`);
|
|
90
|
+
}
|
|
59
91
|
lines.push('');
|
|
60
92
|
lines.push(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
? `da Story #${issue.number} e de cada Task: ${inProgress.filter(n => n !== issue.number).map(n => `#${n}`).join(', ')}.`
|
|
65
|
-
: `da Task #${issue.number}.`)
|
|
66
|
-
);
|
|
67
|
-
lines.push(
|
|
68
|
-
'(Atualize o campo "Etapa"/Status do item no board; mantenha o status coerente ' +
|
|
69
|
-
'conforme o progresso da implementação.)'
|
|
93
|
+
`> Mantenha o status coerente com o progresso real: nenhuma task pode ficar em "${STAGE_IN_PROGRESS}" ` +
|
|
94
|
+
`antes de você começá-la, nem em "${STAGE_DONE}" antes de concluí-la. Atualize o campo "Etapa"/Status ` +
|
|
95
|
+
'do item no GitHub Project.'
|
|
70
96
|
);
|
|
71
97
|
|
|
72
98
|
lines.push('');
|
|
73
|
-
lines.push(`## Tasks a implementar (${tasks.length})`);
|
|
74
|
-
|
|
99
|
+
lines.push(`## Tasks a implementar — NESTA ORDEM (${tasks.length})`);
|
|
100
|
+
tasks.forEach((t, i) => {
|
|
75
101
|
lines.push('');
|
|
76
|
-
lines.push(`### #${t.number} ${t.title}`);
|
|
102
|
+
lines.push(`### ${i + 1}. #${t.number} ${t.title}`);
|
|
77
103
|
if (t.body && t.body.trim()) lines.push(t.body.trim());
|
|
78
|
-
}
|
|
104
|
+
});
|
|
79
105
|
|
|
80
106
|
if (spec) {
|
|
81
107
|
lines.push('');
|
|
@@ -171,11 +197,12 @@ export async function implement({ issue: issueArg, featureDir: featureDirOpt, dr
|
|
|
171
197
|
return;
|
|
172
198
|
}
|
|
173
199
|
|
|
174
|
-
// 4. Resolve spec.md/plan.md
|
|
200
|
+
// 4. Resolve a Feature (pai na cadeia) — para spec.md/plan.md e para as
|
|
201
|
+
// instruções de fim de Story (mover Feature + Story para Code Review).
|
|
202
|
+
const feature = await resolveFeature(token, issue.node_id);
|
|
175
203
|
let featureDir = featureDirOpt;
|
|
176
|
-
if (!featureDir) {
|
|
177
|
-
|
|
178
|
-
if (featureTitle) featureDir = path.join('docs', 'features', slugify(featureTitle));
|
|
204
|
+
if (!featureDir && feature?.title) {
|
|
205
|
+
featureDir = path.join('docs', 'features', slugify(feature.title));
|
|
179
206
|
}
|
|
180
207
|
let specPlan = { spec: null, plan: null, specPath: null, planPath: null };
|
|
181
208
|
if (featureDir && existsSync(featureDir)) {
|
|
@@ -187,7 +214,7 @@ export async function implement({ issue: issueArg, featureDir: featureDirOpt, dr
|
|
|
187
214
|
}
|
|
188
215
|
|
|
189
216
|
// 5. Monta e grava o arquivo de contexto.
|
|
190
|
-
const context = buildContext({ type, issue, tasks, ...specPlan });
|
|
217
|
+
const context = buildContext({ type, issue, tasks, feature, ...specPlan });
|
|
191
218
|
mkdirSync(WORK_DIR, { recursive: true });
|
|
192
219
|
const tasksFile = path.join(WORK_DIR, `implement-${issueNumber}.md`);
|
|
193
220
|
writeFileSync(tasksFile, context);
|
package/src/commands/info.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import * as p from '@clack/prompts';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { readFileSync, existsSync } from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import { CONFIG_FILE } from '../config.mjs';
|
|
5
|
+
import { CONFIG_FILE, PORTAL_URL } from '../config.mjs';
|
|
6
6
|
|
|
7
7
|
// Lê o marcador .spec-wave.json do repositório atual (cwd) e reporta se o
|
|
8
8
|
// spec-wave já foi inicializado. Usado pela skill para decidir entre mostrar
|
|
@@ -17,6 +17,7 @@ export async function info(options = {}) {
|
|
|
17
17
|
}
|
|
18
18
|
p.intro(chalk.bold('spec-wave info'));
|
|
19
19
|
p.log.warn(`Este repositório ${chalk.bold('não foi inicializado')} (sem ${CONFIG_FILE}).`);
|
|
20
|
+
p.log.info(`🌐 Acesse o Portal Web da ferramenta em ${chalk.cyan(PORTAL_URL)}`);
|
|
20
21
|
p.outro('Execute `npx @spec-wave/cli init` para configurar.');
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
@@ -50,5 +51,6 @@ export async function info(options = {}) {
|
|
|
50
51
|
`${chalk.dim('Criado em:')} ${config.initializedAt ?? '?'}`,
|
|
51
52
|
'Configuração'
|
|
52
53
|
);
|
|
54
|
+
p.log.info(`🌐 Acesse o Portal Web da ferramenta em ${chalk.cyan(PORTAL_URL)}`);
|
|
53
55
|
p.outro('Use `/spec-wave feature <descrição>` para criar uma Feature.');
|
|
54
56
|
}
|
package/src/commands/init.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { resolveToken, verifyTokenScopes } from '../api/auth.mjs';
|
|
@@ -8,8 +8,8 @@ import { runWizard } from '../ui/wizard.mjs';
|
|
|
8
8
|
import { setupProject } from '../setup/project.mjs';
|
|
9
9
|
import { setupLabels } from '../setup/labels.mjs';
|
|
10
10
|
import { setupFiles } from '../setup/files.mjs';
|
|
11
|
-
import {
|
|
12
|
-
import { CONFIG_FILE, AI_PROVIDERS, getProvider, DEFAULT_PROVIDER } from '../config.mjs';
|
|
11
|
+
import { getFileContent } from '../api/github-rest.mjs';
|
|
12
|
+
import { CONFIG_FILE, AI_PROVIDERS, getProvider, DEFAULT_PROVIDER, PORTAL_URL } from '../config.mjs';
|
|
13
13
|
|
|
14
14
|
const __dir = path.dirname(fileURLToPath(import.meta.url));
|
|
15
15
|
const pkg = JSON.parse(readFileSync(path.join(__dir, '..', '..', 'package.json'), 'utf-8'));
|
|
@@ -91,8 +91,13 @@ export async function init(options) {
|
|
|
91
91
|
if (options.skipProject) {
|
|
92
92
|
p.log.info('Pulando criação do GitHub Project (--skip-project).');
|
|
93
93
|
// Preserva o bloco project do .spec-wave.json existente (se houver).
|
|
94
|
+
// Prefere o arquivo local; recorre ao remoto para repos configurados por
|
|
95
|
+
// versões antigas (que commitavam o config direto no repo).
|
|
94
96
|
try {
|
|
95
|
-
const
|
|
97
|
+
const localConfigPath = path.join(process.cwd(), CONFIG_FILE);
|
|
98
|
+
const raw = existsSync(localConfigPath)
|
|
99
|
+
? readFileSync(localConfigPath, 'utf-8')
|
|
100
|
+
: await getFileContent(token, owner, repo, CONFIG_FILE);
|
|
96
101
|
if (raw) {
|
|
97
102
|
const existing = JSON.parse(raw);
|
|
98
103
|
if (existing.project) {
|
|
@@ -165,10 +170,13 @@ export async function init(options) {
|
|
|
165
170
|
}
|
|
166
171
|
|
|
167
172
|
// --- Marcador de configuração (.spec-wave.json) ---
|
|
168
|
-
//
|
|
169
|
-
//
|
|
173
|
+
// Gravado LOCALMENTE no diretório atual (não commitado direto no repo): é a
|
|
174
|
+
// fonte de estado persistente lida por info/refresh/uninstall/skill a partir
|
|
175
|
+
// do cwd. O usuário revisa e commita quando quiser.
|
|
176
|
+
const localConfigPath = path.join(process.cwd(), CONFIG_FILE);
|
|
177
|
+
let configWritten = false;
|
|
170
178
|
const configSpinner = p.spinner();
|
|
171
|
-
configSpinner.start(`Gravando ${CONFIG_FILE}...`);
|
|
179
|
+
configSpinner.start(`Gravando ${CONFIG_FILE} local...`);
|
|
172
180
|
try {
|
|
173
181
|
const config = {
|
|
174
182
|
version: pkg.version,
|
|
@@ -187,15 +195,9 @@ export async function init(options) {
|
|
|
187
195
|
},
|
|
188
196
|
initializedAt: new Date().toISOString(),
|
|
189
197
|
};
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
repo,
|
|
194
|
-
CONFIG_FILE,
|
|
195
|
-
JSON.stringify(config, null, 2) + '\n',
|
|
196
|
-
'chore: record spec-wave config [spec-wave]'
|
|
197
|
-
);
|
|
198
|
-
configSpinner.stop(`${CONFIG_FILE} gravado (spec-wave v${pkg.version})`);
|
|
198
|
+
writeFileSync(localConfigPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
199
|
+
configWritten = true;
|
|
200
|
+
configSpinner.stop(`${CONFIG_FILE} gravado local (spec-wave v${pkg.version})`);
|
|
199
201
|
} catch (err) {
|
|
200
202
|
configSpinner.stop('');
|
|
201
203
|
p.log.warn(`Não foi possível gravar ${CONFIG_FILE}: ${err.message}`);
|
|
@@ -214,10 +216,14 @@ export async function init(options) {
|
|
|
214
216
|
`\n${chalk.green('✓')} spec-wave configurado com sucesso!\n\n` +
|
|
215
217
|
(projectUrl ? ` Projeto: ${chalk.cyan(projectUrl)}\n\n` : '') +
|
|
216
218
|
` Próximos passos:\n` +
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
`
|
|
221
|
-
` ${
|
|
219
|
+
(configWritten
|
|
220
|
+
? ` 1. Commite o ${CONFIG_FILE} quando quiser (git add ${CONFIG_FILE} && git commit)\n`
|
|
221
|
+
: '') +
|
|
222
|
+
` ${configWritten ? '2' : '1'}. Adicione ${providerMeta.secret} como secret no repositório (provider: ${providerMeta.label})\n` +
|
|
223
|
+
` ${configWritten ? '3' : '2'}. Configure o board view para agrupar por "Etapa"\n` +
|
|
224
|
+
` ${configWritten ? '4' : '3'}. Crie uma Feature com o prefixo [FEATURE] no título\n` +
|
|
225
|
+
` ${configWritten ? '5' : '4'}. Use a skill spec-wave para guiar o fluxo\n\n` +
|
|
226
|
+
` ${chalk.dim('Para instalar a skill no seu agente: npx @spec-wave/cli install-skill')}\n\n` +
|
|
227
|
+
` 🌐 Acesse o Portal Web da ferramenta em ${chalk.cyan(PORTAL_URL)}`
|
|
222
228
|
);
|
|
223
229
|
}
|
|
@@ -9,6 +9,9 @@ import path from 'node:path';
|
|
|
9
9
|
const __dir = path.dirname(fileURLToPath(import.meta.url));
|
|
10
10
|
// Fonte única da skill, publicada via "files": ["src"] no package.json.
|
|
11
11
|
const SKILL_SOURCE = path.join(__dir, '..', 'templates', 'skill', 'SKILL.md');
|
|
12
|
+
// Versão da CLI que gerou a skill instalada — carimbada no arquivo para detecção
|
|
13
|
+
// de desatualização (a skill é uma cópia estática; não acompanha o `npx` sozinha).
|
|
14
|
+
const pkg = JSON.parse(readFileSync(path.join(__dir, '..', '..', 'package.json'), 'utf-8'));
|
|
12
15
|
|
|
13
16
|
// Marcadores usados para gravar/atualizar a skill de forma idempotente em
|
|
14
17
|
// arquivos compartilhados (AGENTS.md) — permite reinstalar sem duplicar.
|
|
@@ -83,39 +86,50 @@ const TARGET_BY_KEY = new Map(TARGETS.map((t) => [t.key, t]));
|
|
|
83
86
|
// Separa o frontmatter YAML do corpo do SKILL.md. Retorna { meta, body }.
|
|
84
87
|
function parseSkill(raw) {
|
|
85
88
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
86
|
-
if (!match) return { meta: {}, body: raw.trim() };
|
|
89
|
+
if (!match) return { meta: {}, frontmatter: '', body: raw.trim() };
|
|
87
90
|
let meta = {};
|
|
88
91
|
try {
|
|
89
92
|
meta = yaml.load(match[1]) || {};
|
|
90
93
|
} catch {
|
|
91
94
|
meta = {};
|
|
92
95
|
}
|
|
93
|
-
return { meta, body: match[2].trim() };
|
|
96
|
+
return { meta, frontmatter: match[1], body: match[2].trim() };
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
// Banner de versão inserido no topo do corpo da skill instalada. O agente lê
|
|
100
|
+
// esta linha e, se `npx @spec-wave/cli --version` for maior, orienta reinstalar.
|
|
101
|
+
function versionBanner(version) {
|
|
102
|
+
return (
|
|
103
|
+
`> ⚙️ **spec-wave skill v${version}** — esta skill é uma cópia estática. ` +
|
|
104
|
+
'Se `npx @spec-wave/cli --version` indicar uma versão maior, ela está ' +
|
|
105
|
+
'desatualizada: rode `npx @spec-wave/cli install-skill --force` para atualizá-la.'
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Converte o SKILL.md para o formato exigido por cada agente, carimbando a versão.
|
|
110
|
+
function renderContent(format, parsed, version) {
|
|
111
|
+
const { meta, frontmatter, body } = parsed;
|
|
99
112
|
const description = meta.description ?? 'Skill spec-wave.';
|
|
113
|
+
const banner = versionBanner(version);
|
|
100
114
|
switch (format) {
|
|
101
115
|
case 'skill':
|
|
102
|
-
// Claude Code / opencode consomem o SKILL.md nativo.
|
|
103
|
-
//
|
|
104
|
-
return
|
|
116
|
+
// Claude Code / opencode consomem o SKILL.md nativo. Preserva o frontmatter
|
|
117
|
+
// original (allowed-tools etc.) e insere o banner no topo do corpo.
|
|
118
|
+
return `---\n${frontmatter}\n---\n\n${banner}\n\n${body}\n`;
|
|
105
119
|
case 'mdc':
|
|
106
120
|
return (
|
|
107
121
|
`---\n` +
|
|
108
122
|
`description: ${JSON.stringify(description)}\n` +
|
|
109
123
|
`alwaysApply: false\n` +
|
|
110
124
|
`---\n\n` +
|
|
111
|
-
`${body}\n`
|
|
125
|
+
`${banner}\n\n${body}\n`
|
|
112
126
|
);
|
|
113
127
|
case 'rules':
|
|
114
|
-
return `# spec-wave\n\n${description}\n\n${body}\n`;
|
|
128
|
+
return `# spec-wave\n\n${banner}\n\n${description}\n\n${body}\n`;
|
|
115
129
|
case 'agents':
|
|
116
|
-
return `${BLOCK_START}\n\n# spec-wave\n\n${description}\n\n${body}\n\n${BLOCK_END}\n`;
|
|
130
|
+
return `${BLOCK_START}\n\n# spec-wave\n\n${banner}\n\n${description}\n\n${body}\n\n${BLOCK_END}\n`;
|
|
117
131
|
default:
|
|
118
|
-
return
|
|
132
|
+
return body;
|
|
119
133
|
}
|
|
120
134
|
}
|
|
121
135
|
|
|
@@ -258,8 +272,8 @@ export async function installSkill(options = {}) {
|
|
|
258
272
|
for (const { target, dest } of jobs) {
|
|
259
273
|
const content =
|
|
260
274
|
dest.format === 'agents'
|
|
261
|
-
? mergeAgentsFile(dest.path, renderContent('agents',
|
|
262
|
-
: renderContent(dest.format,
|
|
275
|
+
? mergeAgentsFile(dest.path, renderContent('agents', parsed, pkg.version))
|
|
276
|
+
: renderContent(dest.format, parsed, pkg.version);
|
|
263
277
|
|
|
264
278
|
// Confirmar sobrescrita de arquivos "próprios" (skill/rules/mdc). Para
|
|
265
279
|
// 'agents' o merge por marcadores já é seguro (não apaga conteúdo alheio).
|
|
@@ -286,7 +300,10 @@ export async function installSkill(options = {}) {
|
|
|
286
300
|
|
|
287
301
|
p.note(
|
|
288
302
|
written.map((w) => `${chalk.green('✓')} ${chalk.bold(w.target.name)}\n ${chalk.dim(w.dest.path)}`).join('\n'),
|
|
289
|
-
`Skill instalada (escopo: ${scopeLabel})`,
|
|
303
|
+
`Skill v${pkg.version} instalada (escopo: ${scopeLabel})`,
|
|
304
|
+
);
|
|
305
|
+
p.outro(
|
|
306
|
+
'Reinicie/recarregue o agente para que ele detecte a skill. ' +
|
|
307
|
+
'Ao atualizar a CLI, rode `install-skill --force` para atualizar a skill também.',
|
|
290
308
|
);
|
|
291
|
-
p.outro('Reinicie/recarregue o agente para que ele detecte a skill.');
|
|
292
309
|
}
|
package/src/config.mjs
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
// pelo comando `info` (e pela skill) para detectar se o spec-wave já foi configurado.
|
|
5
5
|
export const CONFIG_FILE = '.spec-wave.json';
|
|
6
6
|
|
|
7
|
+
// Portal Web da ferramenta — exibido ao final do `init` e no `info`.
|
|
8
|
+
export const PORTAL_URL = 'https://spec-wave.astratech.net.br';
|
|
9
|
+
|
|
7
10
|
// Providers de IA suportados pelos workflows (generate-plan/spec/decompose).
|
|
8
11
|
// O provider e o modelo escolhidos no `init` são persistidos em .spec-wave.json
|
|
9
12
|
// (bloco `ai`) e lidos em runtime por src/lib/claude.mjs. Cada provider declara
|
|
@@ -48,6 +51,14 @@ export const STATUS_OPTIONS = [
|
|
|
48
51
|
{ name: '🎉 Done', color: 'GREEN' },
|
|
49
52
|
];
|
|
50
53
|
|
|
54
|
+
// Etapas usadas pelo fluxo de implementação (comando `implement`): cada task vai
|
|
55
|
+
// para "In Progress" ao INICIAR seu desenvolvimento e para "Done" ao concluir;
|
|
56
|
+
// ao final da Story, Feature + Story vão para "Code Review" (após commit + PR).
|
|
57
|
+
// Resolvidas por nome para não quebrar se a ordem/cor das opções mudar.
|
|
58
|
+
export const STAGE_IN_PROGRESS = STATUS_OPTIONS.find(s => s.name.includes('Desenvolvimento')).name;
|
|
59
|
+
export const STAGE_DONE = STATUS_OPTIONS.find(s => s.name.includes('Done')).name;
|
|
60
|
+
export const STAGE_CODE_REVIEW = STATUS_OPTIONS.find(s => s.name.includes('Code Review')).name;
|
|
61
|
+
|
|
51
62
|
export const CUSTOM_FIELDS = [
|
|
52
63
|
{
|
|
53
64
|
name: 'Work Item Type',
|
|
@@ -4,7 +4,7 @@ description: "Use when the user wants to set up a spec-driven GitHub workflow, c
|
|
|
4
4
|
argument-hint: "[info|setup|issue|feature|spec|plan|ready|decompose|implement|uninstall|rfc|fix-pr] [target]"
|
|
5
5
|
user-invocable: true
|
|
6
6
|
allowed-tools:
|
|
7
|
-
- Bash(npx spec-wave *)
|
|
7
|
+
- Bash(npx @spec-wave/cli *)
|
|
8
8
|
- Bash(gh issue *)
|
|
9
9
|
- Bash(gh project *)
|
|
10
10
|
- Bash(gh repo view *)
|
|
@@ -27,16 +27,18 @@ Este skill guia o usuário pelo fluxo spec-driven definido no RFC-001.
|
|
|
27
27
|
|
|
28
28
|
> **Antes de responder a qualquer sub-comando**, leia o arquivo `rfc/rfc-integrate-spec-kit-into-kanban.md` se ele existir no diretório atual, para embasar suas respostas no processo real da equipe.
|
|
29
29
|
|
|
30
|
+
> **Verifique se esta skill está atualizada:** logo no topo deste arquivo há um banner `spec-wave skill vX.Y.Z` (inserido na instalação). Compare com `npx @spec-wave/cli --version`. Se a CLI for **mais recente**, esta skill está desatualizada — avise o usuário e sugira rodar `npx @spec-wave/cli install-skill --force` para atualizá-la (a skill é uma cópia estática e **não** acompanha o `npx` sozinha). Se o banner estiver ausente, a skill foi instalada por uma versão antiga: sugira a mesma atualização.
|
|
31
|
+
|
|
30
32
|
---
|
|
31
33
|
|
|
32
34
|
## Detecção de configuração (faça isto primeiro, sempre)
|
|
33
35
|
|
|
34
|
-
Antes de qualquer sub-comando, leia o arquivo `.spec-wave.json` na raiz do repositório atual (use o tool Read). Esse arquivo é gravado pelo `npx spec-wave init` e é a fonte de estado persistente entre sessões.
|
|
36
|
+
Antes de qualquer sub-comando, leia o arquivo `.spec-wave.json` na raiz do repositório atual (use o tool Read). Esse arquivo é gravado pelo `npx @spec-wave/cli init` e é a fonte de estado persistente entre sessões.
|
|
35
37
|
|
|
36
38
|
- **Se existir**, o spec-wave já foi configurado. Use seus campos para contextualizar as respostas, sem perguntar de novo:
|
|
37
39
|
- `owner`/`repo` → repositório alvo dos comandos `gh`
|
|
38
40
|
- `project.url` / `project.title` → o GitHub Project a referenciar
|
|
39
|
-
- `version` → versão da CLI usada no `init` (compare com `npx spec-wave --version`; se divergir, sugira `npx spec-wave refresh --config` para atualizar o arquivo, ou re-rodar o `init` para atualizar workflows/labels)
|
|
41
|
+
- `version` → versão da CLI usada no `init` (compare com `npx @spec-wave/cli --version`; se divergir, sugira `npx @spec-wave/cli refresh --config` para atualizar o arquivo, ou re-rodar o `init` para atualizar workflows/labels)
|
|
40
42
|
- `initializedAt` → quando foi configurado
|
|
41
43
|
Não rode `/spec-wave setup` de novo a menos que o usuário peça explicitamente.
|
|
42
44
|
- **Se não existir**, o repositório provavelmente ainda não foi configurado. Sugira começar por `/spec-wave setup`.
|
|
@@ -80,15 +82,15 @@ Labels de gatilho:
|
|
|
80
82
|
- `spec-wave:ready` → dispara `validate.yml` → valida ambos os arquivos
|
|
81
83
|
- `spec-wave:decompose` → dispara `decompose.yml` → gera Stories e Tasks
|
|
82
84
|
|
|
83
|
-
A etapa **🚧 Desenvolvimento** é coberta pelo comando **local** `spec-wave implement <número>` (não é uma label/Action): lê uma Story ou Task e aciona o spec-kit para implementar. Veja `/spec-wave implement`.
|
|
85
|
+
A etapa **🚧 Desenvolvimento** é coberta pelo comando **local** `npx @spec-wave/cli implement <número>` (não é uma label/Action): lê uma Story ou Task e aciona o spec-kit para implementar. Veja `/spec-wave implement`.
|
|
84
86
|
|
|
85
87
|
---
|
|
86
88
|
|
|
87
89
|
## Referência da CLI (conheça os parâmetros ANTES de executar)
|
|
88
90
|
|
|
89
|
-
Esta skill é um **wrapper** da CLI `spec-wave
|
|
91
|
+
Esta skill é um **wrapper** da CLI `@spec-wave/cli`, sempre invocada como `npx @spec-wave/cli <comando>`. Regra de ouro: **nunca rode um comando sem os parâmetros que ele aceita** esperando que ele pergunte — colete os valores com o usuário e passe via flags. Em especial, **`init` sem `--repo` abre um wizard interativo (@clack/prompts) que a skill NÃO consegue dirigir** — sempre passe `--repo`.
|
|
90
92
|
|
|
91
|
-
###
|
|
93
|
+
### `@spec-wave/cli init` — configura o repositório
|
|
92
94
|
| Flag | Tipo | Descrição |
|
|
93
95
|
|------|------|-----------|
|
|
94
96
|
| `--repo <owner/repo>` | string | Repositório alvo. **Passe SEMPRE** para evitar o wizard interativo. |
|
|
@@ -98,25 +100,25 @@ Esta skill é um **wrapper** da CLI `spec-wave`. Regra de ouro: **nunca rode um
|
|
|
98
100
|
| `--skip-files` | flag | Pula a criação dos workflows + issue templates. |
|
|
99
101
|
| `--dry-run` | flag | Simula a configuração sem alterar nada. |
|
|
100
102
|
|
|
101
|
-
###
|
|
103
|
+
### `@spec-wave/cli issue` — cria um work item tipado, opcionalmente como sub-issue, e adiciona ao board
|
|
102
104
|
| Flag | Tipo | Descrição |
|
|
103
105
|
|------|------|-----------|
|
|
104
106
|
| `--title <title>` | string (obrigatório) | Título, **sem** o prefixo de tipo (a CLI adiciona, ex.: `[STORY]`). |
|
|
105
107
|
| `--type <type>` | string | `initiative`, `epic`, `feature`, `story`, `task`, `bug`, `spike` ou `rfc`. Default: `feature`. |
|
|
106
108
|
| `--parent <n>` | string | Número da issue pai — cria como **sub-issue** dela (relação nativa do GitHub). |
|
|
107
109
|
| `--body <text>` | string | Descrição. |
|
|
108
|
-
| `--priority <p>` | string | `P0`, `P1`, `P2` ou `P3`. |
|
|
110
|
+
| `--priority <p>` | string | **Opcional.** `P0`, `P1`, `P2` ou `P3`. Omita se o usuário não pediu — a prioridade fica `null` (sem prioridade). Nunca atribua por conta própria. |
|
|
109
111
|
| `--area <area>` | string | `Frontend`, `Backend`, `Mobile`, `Infra`, `DevOps` ou `Data`. |
|
|
110
112
|
|
|
111
|
-
> Faz tudo: cria a issue (label de tipo
|
|
113
|
+
> Faz tudo: cria a issue (label de tipo — e de prioridade **apenas se `--priority` for informado**), vincula ao parent como sub-issue, adiciona ao Project e define os campos **Etapa = 📥 Backlog**, **Work Item Type**, **Area** e, **só se informada, Priority**. Grava `Parent: #N` no corpo. Lê o Project do `.spec-wave.json`. **Não use `gh issue create` direto** — ele não adiciona ao board nem vincula o parent.
|
|
112
114
|
|
|
113
|
-
###
|
|
115
|
+
### `@spec-wave/cli initiative` — atalho de `issue --type initiative`
|
|
114
116
|
Cria o nó raiz da hierarquia (agrupa Epics). Mesmas flags do `issue` exceto `--type` (fixo em `initiative`) e `--parent` (Initiative é raiz, não tem pai).
|
|
115
117
|
|
|
116
|
-
###
|
|
118
|
+
### `@spec-wave/cli feature` — atalho de `issue --type feature`
|
|
117
119
|
Mesmas flags do `issue` (exceto `--type`, fixo em `feature`). Mantido para o fluxo do RFC-001.
|
|
118
120
|
|
|
119
|
-
###
|
|
121
|
+
### `@spec-wave/cli uninstall` — remove a configuração (mantém o Project)
|
|
120
122
|
| Flag | Tipo | Descrição |
|
|
121
123
|
|------|------|-----------|
|
|
122
124
|
| `--repo <owner/repo>` | string | Repositório (default: lê do `.spec-wave.json`). |
|
|
@@ -128,33 +130,33 @@ Mesmas flags do `issue` (exceto `--type`, fixo em `feature`). Mantido para o flu
|
|
|
128
130
|
|
|
129
131
|
> Remove labels + arquivos `.github` + `.spec-wave.json`. **NUNCA apaga o GitHub Project** (preserva o histórico do board) — o usuário deve excluí-lo manualmente se quiser.
|
|
130
132
|
|
|
131
|
-
###
|
|
133
|
+
### `@spec-wave/cli info` — status de configuração do repo atual
|
|
132
134
|
| Flag | Tipo | Descrição |
|
|
133
135
|
|------|------|-----------|
|
|
134
136
|
| `--json` | flag | Saída JSON (`{"initialized":bool, ...}`) para parsing programático. |
|
|
135
137
|
|
|
136
|
-
###
|
|
138
|
+
### `@spec-wave/cli refresh` — atualiza o `.spec-wave.json` local
|
|
137
139
|
| Flag | Tipo | Descrição |
|
|
138
140
|
|------|------|-----------|
|
|
139
141
|
| `--config` | flag | Re-consulta o GitHub Project e reescreve o `.spec-wave.json` (IDs do campo Etapa, opções, number, versão da CLI). |
|
|
140
142
|
|
|
141
143
|
> Use quando o `.spec-wave.json` estiver desatualizado: repos inicializados por uma versão antiga (sem `etapaFieldId`/`stageOptions`), Project renomeado, ou versão da CLI divergente. Escreve no arquivo **local** — faça commit depois.
|
|
142
144
|
|
|
143
|
-
###
|
|
145
|
+
### `@spec-wave/cli generate-plan` · `generate-spec` · `validate` · `decompose`
|
|
144
146
|
| Flag | Tipo | Descrição |
|
|
145
147
|
|------|------|-----------|
|
|
146
148
|
| `--issue-number <n>` | string (obrigatório) | Número da issue no GitHub. |
|
|
147
149
|
|
|
148
150
|
> ⚠️ Esses quatro comandos são executados pelos **GitHub Actions** (disparados por labels), **não** pela skill diretamente. Veja a *Regra fundamental*: para gerar plan/spec/decompor, adicione a **label** correspondente — não rode o comando à mão (a não ser para debug local).
|
|
149
151
|
|
|
150
|
-
###
|
|
152
|
+
### `@spec-wave/cli implement` — aciona o spec-kit para uma Story ou Task (comando LOCAL)
|
|
151
153
|
| Flag/Arg | Tipo | Descrição |
|
|
152
154
|
|----------|------|-----------|
|
|
153
155
|
| `<issue>` | string (obrigatório) | Número da issue (Story ou Task), ex.: `12` ou `#12`. Argumento posicional. |
|
|
154
156
|
| `--feature-dir <path>` | string | Caminho `docs/features/<slug>` para anexar `spec.md`/`plan.md` como contexto (sobrescreve a resolução automática). |
|
|
155
157
|
| `--dry-run` | flag | Monta o contexto e imprime o comando do spec-kit **sem executar**. |
|
|
156
158
|
|
|
157
|
-
> Diferente dos quatro acima, `implement` roda **localmente** (lê `.spec-wave.json`, como `issue`), não por Action. Detecta o tipo da issue: **Story** → coleta todas as Tasks (sub-issues) e aciona o spec-kit uma única vez; **Task** → só aquela task. Monta o contexto em `.spec-wave/implement-<n>.md` e chama o comando configurado em `specKit.command` (no `.spec-wave.json`) ou na env `SPEC_WAVE_IMPLEMENT_CMD`. Placeholders disponíveis no template: `{tasksFile} {specFile} {planFile} {issue} {type} {title}`. Se nada estiver configurado, ele apenas monta o contexto e mostra como configurar (não executa). O contexto
|
|
159
|
+
> Diferente dos quatro acima, `implement` roda **localmente** (lê `.spec-wave.json`, como `issue`), não por Action. Detecta o tipo da issue: **Story** → coleta todas as Tasks (sub-issues) e aciona o spec-kit uma única vez; **Task** → só aquela task. Monta o contexto em `.spec-wave/implement-<n>.md` e chama o comando configurado em `specKit.command` (no `.spec-wave.json`) ou na env `SPEC_WAVE_IMPLEMENT_CMD`. Placeholders disponíveis no template: `{tasksFile} {specFile} {planFile} {issue} {type} {title}`. Se nada estiver configurado, ele apenas monta o contexto e mostra como configurar (não executa). O contexto inclui instruções para o agente implementar as Tasks **sequencialmente, uma por vez**: mover a task para **🚧 Desenvolvimento** só ao iniciá-la e para **🎉 Done** ao concluí-la, antes de passar para a próxima (nunca todas em "in progress" ao mesmo tempo). **Ao concluir toda a Story**: fazer o commit, abrir o PR e mover a **Feature** e a **Story** para **👀 Code Review** (as Tasks permanecem em 🎉 Done).
|
|
158
160
|
|
|
159
161
|
---
|
|
160
162
|
|
|
@@ -165,7 +167,7 @@ Mesmas flags do `issue` (exceto `--type`, fixo em `feature`). Mantido para o flu
|
|
|
165
167
|
Mostra se o repositório atual já foi configurado com o spec-wave.
|
|
166
168
|
|
|
167
169
|
**Passos:**
|
|
168
|
-
1. Execute: `npx spec-wave info`
|
|
170
|
+
1. Execute: `npx @spec-wave/cli info`
|
|
169
171
|
2. **Se o repositório estiver inicializado**, o comando mostra os dados do `.spec-wave.json` (owner/repo, project, versão da CLI, data). Apresente essas informações ao usuário.
|
|
170
172
|
3. **Se NÃO estiver inicializado**, pergunte ao usuário: "Este repositório ainda não foi configurado com o spec-wave. Quer rodar o `init` agora?"
|
|
171
173
|
- Se sim → siga o fluxo de `/spec-wave setup`.
|
|
@@ -175,17 +177,17 @@ Mostra se o repositório atual já foi configurado com o spec-wave.
|
|
|
175
177
|
|
|
176
178
|
### `/spec-wave setup`
|
|
177
179
|
|
|
178
|
-
Configura o spec-wave no repositório. Você dirige o `init` com flags — **nunca rode `npx spec-wave init` sem `--repo`** (abre o wizard interativo que você não controla).
|
|
180
|
+
Configura o spec-wave no repositório. Você dirige o `init` com flags — **nunca rode `npx @spec-wave/cli init` sem `--repo`** (abre o wizard interativo que você não controla).
|
|
179
181
|
|
|
180
182
|
**Passos:**
|
|
181
|
-
1. **Já configurado?** Leia `.spec-wave.json` (ou rode `npx spec-wave info`). Se existir, avise (mostre `project.url` e `version`) e confirme com o usuário antes de reconfigurar.
|
|
183
|
+
1. **Já configurado?** Leia `.spec-wave.json` (ou rode `npx @spec-wave/cli info`). Se existir, avise (mostre `project.url` e `version`) e confirme com o usuário antes de reconfigurar.
|
|
182
184
|
2. **Descubra o repositório alvo** (parâmetro `--repo`): rode `gh repo view --json nameWithOwner -q .nameWithOwner` para obter `owner/repo` do repo atual. Confirme com o usuário; se não houver remote, pergunte o `owner/repo`.
|
|
183
185
|
3. **Pergunte o título do Project** (parâmetro `--project-title`). Ofereça o default `<repo> — Spec Wave` e aceite-o se o usuário não tiver preferência.
|
|
184
186
|
4. **Cheque o auth:** `gh auth status`. Se faltarem os escopos `project,repo,workflow`, oriente o usuário a rodar ele mesmo `gh auth refresh --scopes project,repo,workflow` (comando interativo — o usuário executa, não você).
|
|
185
|
-
5. **(Opcional) Pré-visualize** antes de aplicar: `npx spec-wave init --repo <owner/repo> --dry-run`.
|
|
187
|
+
5. **(Opcional) Pré-visualize** antes de aplicar: `npx @spec-wave/cli init --repo <owner/repo> --dry-run`.
|
|
186
188
|
6. **Execute com os parâmetros coletados:**
|
|
187
189
|
```bash
|
|
188
|
-
npx spec-wave init --repo <owner/repo> --project-title "<título>"
|
|
190
|
+
npx @spec-wave/cli init --repo <owner/repo> --project-title "<título>"
|
|
189
191
|
```
|
|
190
192
|
Use `--skip-project` / `--skip-labels` / `--skip-files` **apenas** para re-rodar uma fase específica que falhou antes.
|
|
191
193
|
7. O `init` cria o Project, as labels, os workflows, um **scaffold de `.github/config/tech_context.yml`** (só se ainda não existir) e grava `.spec-wave.json`. Oriente o usuário a fazer `git pull` para trazer os arquivos ao checkout local.
|
|
@@ -201,19 +203,19 @@ Crie um work item tipado (Initiative/Epic/Feature/Story/Task/...) já adicionado
|
|
|
201
203
|
**Hierarquia típica:** Initiative → Epic → Feature → Story → Task. A **Initiative** é o nó raiz e agrupa Epics. Use `--parent <n>` para criar como sub-issue do nível acima (ex.: um Epic filho de uma Initiative, ou uma Story filha de uma Feature). O GitHub mostra o parent na issue filha e vice-versa; a CLI ainda grava `Parent: #N` no corpo.
|
|
202
204
|
|
|
203
205
|
**Passos:**
|
|
204
|
-
1. Pergunte ao usuário: tipo (initiative/epic/feature/story/task/...), título (sem prefixo), descrição
|
|
205
|
-
2. Execute o comando com os parâmetros coletados:
|
|
206
|
+
1. Pergunte ao usuário: tipo (initiative/epic/feature/story/task/...), título (sem prefixo), descrição e se há uma issue **pai** (número). **Prioridade e área são opcionais**: só as inclua se o usuário pedir explicitamente. **Nunca atribua uma prioridade por conta própria** — se o usuário não informou, **omita `--priority`** e a prioridade fica `null` (sem prioridade) no board.
|
|
207
|
+
2. Execute o comando com os parâmetros coletados (inclua **apenas** as flags que o usuário forneceu):
|
|
206
208
|
```bash
|
|
207
|
-
npx spec-wave issue \
|
|
209
|
+
npx @spec-wave/cli issue \
|
|
208
210
|
--type "<tipo>" \
|
|
209
211
|
--title "<título>" \
|
|
210
212
|
--body "<descrição>" \
|
|
211
|
-
--area "<área>" \
|
|
212
|
-
--priority "<prioridade>" \
|
|
213
|
+
--area "<área>" \ # opcional — omita se o usuário não informou
|
|
214
|
+
--priority "<prioridade>" \ # opcional — só se o usuário pediu; caso contrário OMITA (prioridade fica null)
|
|
213
215
|
--parent "<número-do-pai>" # opcional
|
|
214
216
|
```
|
|
215
|
-
Para Features, pode usar o atalho `npx spec-wave feature --title ...` (equivale a `--type feature`).
|
|
216
|
-
A CLI cria a issue (label de tipo
|
|
217
|
+
Para Features, pode usar o atalho `npx @spec-wave/cli feature --title ...` (equivale a `--type feature`).
|
|
218
|
+
A CLI cria a issue (label de tipo — e de prioridade **apenas se `--priority` for informado**), vincula como sub-issue do parent, adiciona ao Project e define Etapa = 📥 Backlog + Work Item Type + Area (+ Priority só se informada). **Não use `gh issue create`** (não adiciona ao board nem vincula o parent).
|
|
217
219
|
3. Informe o número criado e o vínculo com o pai (se houver).
|
|
218
220
|
4. Para Features: "Quando quiser iniciar, mova para **📋 Spec** e use `/spec-wave spec <número>` para gerar a especificação funcional (o plano técnico vem depois)".
|
|
219
221
|
|
|
@@ -225,8 +227,8 @@ Remove a configuração do spec-wave do repositório (labels, arquivos `.github`
|
|
|
225
227
|
|
|
226
228
|
**Passos:**
|
|
227
229
|
1. Confirme com o usuário que ele quer remover (a ação remove labels e faz commits removendo os workflows).
|
|
228
|
-
2. Mostre antes o que será removido com `npx spec-wave uninstall --dry-run`.
|
|
229
|
-
3. Execute `npx spec-wave uninstall` (a CLI pede confirmação; use `--yes` só se o usuário já confirmou).
|
|
230
|
+
2. Mostre antes o que será removido com `npx @spec-wave/cli uninstall --dry-run`.
|
|
231
|
+
3. Execute `npx @spec-wave/cli uninstall` (a CLI pede confirmação; use `--yes` só se o usuário já confirmou).
|
|
230
232
|
4. Lembre o usuário de excluir o **GitHub Project** manualmente, se desejar — a CLI não o apaga de propósito.
|
|
231
233
|
|
|
232
234
|
---
|
|
@@ -267,7 +269,7 @@ O plano técnico segue o schema do RFC-002 §3.2: **Estratégia Técnica** (com
|
|
|
267
269
|
|
|
268
270
|
### Tech Context (`.github/config/tech_context.yml`)
|
|
269
271
|
|
|
270
|
-
Fonte de verdade estática da stack do sistema (RFC-002 §4). O `generate-plan` lê este arquivo para embasar o plano técnico e usar **APENAS** as tecnologias/serviços nele declarados — sem ele, o plano fica genérico e pode inventar APIs inexistentes. O `npx spec-wave init` gera um **scaffold de exemplo** que **deve ser adaptado** à stack real. Use este fluxo quando o arquivo estiver ausente ou desatualizado.
|
|
272
|
+
Fonte de verdade estática da stack do sistema (RFC-002 §4). O `generate-plan` lê este arquivo para embasar o plano técnico e usar **APENAS** as tecnologias/serviços nele declarados — sem ele, o plano fica genérico e pode inventar APIs inexistentes. O `npx @spec-wave/cli init` gera um **scaffold de exemplo** que **deve ser adaptado** à stack real. Use este fluxo quando o arquivo estiver ausente ou desatualizado.
|
|
271
273
|
|
|
272
274
|
**Como ajudar a criar (quando não existir):**
|
|
273
275
|
|
|
@@ -361,17 +363,18 @@ Aciona o spec-kit para implementar uma **Story** (todas as suas Tasks) ou uma **
|
|
|
361
363
|
1. Confirme que há `.spec-wave.json` no repo (senão, oriente `/spec-wave setup`).
|
|
362
364
|
2. **Sempre comece com `--dry-run`** para inspecionar o que será feito — detecção do tipo, lista de Tasks coletadas (no caso de Story) e o comando do spec-kit que seria executado:
|
|
363
365
|
```bash
|
|
364
|
-
npx spec-wave implement <número> --dry-run
|
|
366
|
+
npx @spec-wave/cli implement <número> --dry-run
|
|
365
367
|
```
|
|
366
|
-
3. Mostre ao usuário o contexto montado em `.spec-wave/implement-<número>.md` e o comando.
|
|
367
|
-
4. Se o
|
|
368
|
+
3. Mostre ao usuário o contexto montado em `.spec-wave/implement-<número>.md` e o comando. Esse arquivo contém as **instruções de execução sequencial**: implemente as Tasks **uma por vez** — mova a task para **🚧 Desenvolvimento** só ao iniciá-la e para **🎉 Done** ao concluí-la, antes de passar para a próxima. **Nunca** coloque várias tasks em "in progress" ao mesmo tempo.
|
|
369
|
+
4. **Se você (agente) for implementar diretamente** (sem `specKit.command`): siga o contexto task por task, na ordem listada, respeitando o ciclo In Progress → implementar → Done de cada task antes da seguinte. Atualize o campo "Etapa" do item no board via `gh`. **Ao concluir toda a Story**: faça o commit, abra o PR e mova a **Feature** e a **Story** para **👀 Code Review** (as Tasks ficam em 🎉 Done).
|
|
370
|
+
5. Se o usuário aprovar e o spec-kit estiver configurado, rode sem `--dry-run`:
|
|
368
371
|
```bash
|
|
369
|
-
npx spec-wave implement <número>
|
|
372
|
+
npx @spec-wave/cli implement <número>
|
|
370
373
|
```
|
|
371
374
|
- Se o spec-kit **não** estiver configurado, o comando só monta o contexto e mostra como configurar (`specKit.command` / `SPEC_WAVE_IMPLEMENT_CMD`). Ajude o usuário a definir o template (placeholders: `{tasksFile} {specFile} {planFile} {issue} {type} {title}`).
|
|
372
375
|
- Use `--feature-dir docs/features/<slug>` se a resolução automática da Feature falhar (a skill avisa com warning) e você quiser anexar `spec.md`/`plan.md` como contexto.
|
|
373
|
-
|
|
374
|
-
|
|
376
|
+
6. Se a issue **não** for Story nem Task (ex.: Feature, Bug), o comando recusa — oriente o usuário: Features se decompõem (`/spec-wave decompose`); implemente as Stories/Tasks resultantes.
|
|
377
|
+
7. Ao final (Story implementada, commit feito, PR aberto e Feature/Story em **👀 Code Review**): confirme o resultado com o usuário e oriente a revisão do PR.
|
|
375
378
|
|
|
376
379
|
---
|
|
377
380
|
|