@spec-wave/cli 0.1.0

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.
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: "Especificação Funcional (spec.md)"
3
+ about: "Especificação funcional de uma Feature. Gerado automaticamente ao mover para a coluna 📋 Spec."
4
+ title: "[FEATURE] "
5
+ labels: "[FEATURE]"
6
+ assignees: ""
7
+ ---
8
+
9
+ # Objetivo
10
+
11
+ <!-- O que esta Feature entrega e qual problema resolve? -->
12
+
13
+ # Regras de Negócio
14
+
15
+ <!-- Liste as regras que governam o comportamento desta Feature -->
16
+
17
+ # Fluxos
18
+
19
+ <!-- Descreva o fluxo principal e os fluxos alternativos -->
20
+
21
+ # Critérios de Aceite
22
+
23
+ - [ ]
24
+ - [ ]
25
+
26
+ # Casos de Erro
27
+
28
+ <!-- O que acontece quando algo dá errado? Como o sistema se comporta? -->
29
+
30
+ # Dependências
31
+
32
+ <!-- Outras Features, integrações, APIs externas ou pré-requisitos -->
@@ -0,0 +1,29 @@
1
+ name: Decompose Feature
2
+
3
+ on:
4
+ issues:
5
+ types: [labeled]
6
+
7
+ jobs:
8
+ decompose:
9
+ if: >
10
+ github.event.label.name == 'spec-wave:decompose' &&
11
+ contains(github.event.issue.title, '[FEATURE]')
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ issues: write
15
+ contents: read
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - uses: actions/setup-node@v4
21
+ with:
22
+ node-version: '20'
23
+
24
+ - name: Decompose into Stories and Tasks
25
+ run: npx @spec-wave/cli decompose --issue-number ${{ github.event.issue.number }}
26
+ env:
27
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
29
+ GITHUB_REPOSITORY: ${{ github.repository }}
@@ -0,0 +1,31 @@
1
+ name: Generate Plan
2
+
3
+ on:
4
+ issues:
5
+ types: [labeled]
6
+
7
+ jobs:
8
+ generate-plan:
9
+ if: >
10
+ github.event.label.name == 'spec-wave:plan' &&
11
+ contains(github.event.issue.title, '[FEATURE]')
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ issues: write
15
+ contents: write
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ with:
20
+ token: ${{ secrets.GITHUB_TOKEN }}
21
+
22
+ - uses: actions/setup-node@v4
23
+ with:
24
+ node-version: '20'
25
+
26
+ - name: Generate plan.md
27
+ run: npx @spec-wave/cli generate-plan --issue-number ${{ github.event.issue.number }}
28
+ env:
29
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
31
+ GITHUB_REPOSITORY: ${{ github.repository }}
@@ -0,0 +1,31 @@
1
+ name: Generate Spec
2
+
3
+ on:
4
+ issues:
5
+ types: [labeled]
6
+
7
+ jobs:
8
+ generate-spec:
9
+ if: >
10
+ github.event.label.name == 'spec-wave:spec' &&
11
+ contains(github.event.issue.title, '[FEATURE]')
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ issues: write
15
+ contents: write
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ with:
20
+ token: ${{ secrets.GITHUB_TOKEN }}
21
+
22
+ - uses: actions/setup-node@v4
23
+ with:
24
+ node-version: '20'
25
+
26
+ - name: Generate spec.md
27
+ run: npx @spec-wave/cli generate-spec --issue-number ${{ github.event.issue.number }}
28
+ env:
29
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
31
+ GITHUB_REPOSITORY: ${{ github.repository }}
@@ -0,0 +1,27 @@
1
+ name: Validate Spec + Plan
2
+
3
+ on:
4
+ issues:
5
+ types: [labeled]
6
+
7
+ jobs:
8
+ validate:
9
+ if: >
10
+ github.event.label.name == 'spec-wave:ready' &&
11
+ contains(github.event.issue.title, '[FEATURE]')
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ issues: write
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: actions/setup-node@v4
20
+ with:
21
+ node-version: '20'
22
+
23
+ - name: Validate spec and plan
24
+ run: npx @spec-wave/cli validate --issue-number ${{ github.event.issue.number }}
25
+ env:
26
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27
+ GITHUB_REPOSITORY: ${{ github.repository }}
@@ -0,0 +1,83 @@
1
+ import * as p from '@clack/prompts';
2
+ import { execSync } from 'node:child_process';
3
+
4
+ export async function runWizard() {
5
+ p.intro('spec-wave — configuração do fluxo spec-driven');
6
+
7
+ const answers = await p.group(
8
+ {
9
+ repo: () =>
10
+ p.text({
11
+ message: 'Repositório GitHub (owner/repo):',
12
+ placeholder: detectRepo(),
13
+ defaultValue: detectRepo(),
14
+ validate: v => {
15
+ if (!v || !v.includes('/')) return 'Formato esperado: owner/repo';
16
+ },
17
+ }),
18
+
19
+ projectTitle: ({ results }) =>
20
+ p.text({
21
+ message: 'Nome do GitHub Project:',
22
+ defaultValue: `${results.repo?.split('/')[1] ?? 'projeto'} — Spec Wave`,
23
+ placeholder: 'Meu Projeto — Spec Wave',
24
+ }),
25
+
26
+ triggerStrategy: () =>
27
+ p.select({
28
+ message: 'Como prefere acionar os workflows automáticos?',
29
+ options: [
30
+ {
31
+ value: 'labels',
32
+ label: 'Labels (recomendado)',
33
+ hint: 'A skill adiciona labels automaticamente ao mover cards',
34
+ },
35
+ {
36
+ value: 'webhook',
37
+ label: 'Webhook (em breve)',
38
+ hint: 'Acionamento automático ao mover card no board — requer endpoint externo',
39
+ },
40
+ ],
41
+ }),
42
+
43
+ confirm: ({ results }) =>
44
+ p.confirm({
45
+ message: `Configurar ${results.repo} com GitHub Project "${results.projectTitle}"?\n - 12 colunas kanban\n - 5 campos customizados\n - 15 labels\n - 4 workflows + 2 issue templates`,
46
+ initialValue: true,
47
+ }),
48
+ },
49
+ {
50
+ onCancel: () => {
51
+ p.cancel('Operação cancelada.');
52
+ process.exit(0);
53
+ },
54
+ }
55
+ );
56
+
57
+ if (!answers.confirm) {
58
+ p.cancel('Operação cancelada.');
59
+ process.exit(0);
60
+ }
61
+
62
+ if (answers.triggerStrategy === 'webhook') {
63
+ p.note(
64
+ 'Webhook support está planejado para uma versão futura.\nUsando labels por enquanto.',
65
+ 'Aviso'
66
+ );
67
+ }
68
+
69
+ const [owner, repo] = answers.repo.split('/');
70
+ return { owner, repo, projectTitle: answers.projectTitle };
71
+ }
72
+
73
+ function detectRepo() {
74
+ try {
75
+ const remote = execSync('git remote get-url origin', { stdio: ['pipe', 'pipe', 'pipe'] })
76
+ .toString()
77
+ .trim();
78
+ const match = remote.match(/github\.com[:/]([^/]+\/[^/.]+)/);
79
+ return match ? match[1] : '';
80
+ } catch {
81
+ return '';
82
+ }
83
+ }