@spec-wave/cli 0.23.0 → 0.25.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.
Files changed (37) hide show
  1. package/README.md +109 -5
  2. package/bin/spec-wave.mjs +35 -2
  3. package/package.json +1 -1
  4. package/src/agent/anthropic-agent.mjs +40 -19
  5. package/src/agent/index.mjs +104 -38
  6. package/src/api/github-rest.mjs +63 -1
  7. package/src/commands/decompose.mjs +3 -10
  8. package/src/commands/doctor.mjs +70 -12
  9. package/src/commands/generate-bug.mjs +8 -14
  10. package/src/commands/generate-plan.mjs +2 -1
  11. package/src/commands/generate-spec.mjs +2 -1
  12. package/src/commands/init.mjs +5 -0
  13. package/src/commands/mode.mjs +169 -0
  14. package/src/commands/run.mjs +396 -0
  15. package/src/commands/validate.mjs +22 -6
  16. package/src/config.mjs +40 -6
  17. package/src/lib/claude.mjs +13 -3
  18. package/src/lib/config-file.mjs +62 -0
  19. package/src/lib/doc-paths.mjs +51 -0
  20. package/src/lib/execution-mode.mjs +110 -0
  21. package/src/lib/next-step.mjs +356 -0
  22. package/src/lib/pr-step.mjs +102 -0
  23. package/src/lib/repo-links.mjs +84 -0
  24. package/src/plugin/.claude-plugin/plugin.json +1 -1
  25. package/src/plugin/skills/doctor/SKILL.md +2 -1
  26. package/src/plugin/skills/run/SKILL.md +76 -0
  27. package/src/plugin/skills/setup/SKILL.md +1 -1
  28. package/src/plugin/skills/spec/SKILL.md +1 -1
  29. package/src/templates/skill/SKILL.md +25 -2
  30. package/src/templates/workflows/code-review.yml +5 -1
  31. package/src/templates/workflows/critique.yml +5 -0
  32. package/src/templates/workflows/decompose.yml +5 -0
  33. package/src/templates/workflows/generate-bug.yml +5 -0
  34. package/src/templates/workflows/generate-plan.yml +5 -0
  35. package/src/templates/workflows/generate-spec.yml +5 -0
  36. package/src/templates/workflows/qa.yml +6 -1
  37. package/src/templates/workflows/validate.yml +4 -0
@@ -0,0 +1,84 @@
1
+ // Links para os documentos gerados, apontando para a REF que de fato os recebeu.
2
+ //
3
+ // Os comentários das issues traziam `blob/main/...` fixo. No runner isso é quase
4
+ // sempre verdade (o push vai para a branch default), mas o modo local publica da
5
+ // branch corrente — e aí o link nasce 404 até o merge, ou para sempre. Com o
6
+ // `run` industrializando a execução local, o defeito deixaria de ser eventual.
7
+ //
8
+ // Decisão pura (`blobUrl`, `resolveDocRef`), I/O isolado em `currentGitBranch`.
9
+
10
+ import { execSync } from 'node:child_process';
11
+
12
+ /**
13
+ * URL de um arquivo no GitHub (função PURA).
14
+ *
15
+ * A ref não é escapada: nome de branch com `/` (feat/x) funciona cru na URL do
16
+ * GitHub, e `encodeURIComponent` o quebraria.
17
+ *
18
+ * @param {{owner: string, repo: string, ref: string, pathRel: string}} params
19
+ * @returns {string}
20
+ */
21
+ export function blobUrl({ owner, repo, ref, pathRel }) {
22
+ return `https://github.com/${owner}/${repo}/blob/${ref}/${pathRel}`;
23
+ }
24
+
25
+ /**
26
+ * Qual ref o link deve citar (função PURA).
27
+ *
28
+ * No Actions, `GITHUB_REF_NAME` é a branch do evento. Localmente, a branch
29
+ * corrente é a que `commitGenerated` acabou de publicar. `main` é o último
30
+ * recurso — o mesmo valor que estava hardcoded, então nunca piora.
31
+ *
32
+ * @param {object} params
33
+ * @param {'actions'|'local'} params.mode
34
+ * @param {object} [params.env]
35
+ * @param {string|null} [params.gitBranch] branch corrente (modo local)
36
+ * @param {object|null} [params.config] `.spec-wave.json` (campo `defaultBranch`)
37
+ * @returns {string}
38
+ */
39
+ export function resolveDocRef({ mode, env = {}, gitBranch = null, config = null }) {
40
+ const fallback = config?.defaultBranch || 'main';
41
+ if (mode === 'actions') return env.GITHUB_REF_NAME || fallback;
42
+ return gitBranch || fallback;
43
+ }
44
+
45
+ /**
46
+ * Branch corrente do clone. Best-effort — NUNCA lança.
47
+ *
48
+ * @param {string} [cwd]
49
+ * @returns {string|null} null em detached HEAD ou fora de um repositório git
50
+ */
51
+ export function currentGitBranch(cwd = process.cwd()) {
52
+ try {
53
+ const branch = execSync('git rev-parse --abbrev-ref HEAD', {
54
+ cwd,
55
+ encoding: 'utf-8',
56
+ stdio: ['ignore', 'pipe', 'ignore'],
57
+ }).trim();
58
+ return branch && branch !== 'HEAD' ? branch : null;
59
+ } catch {
60
+ return null;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * URL do documento gerado, resolvendo a ref pelo modo de execução.
66
+ *
67
+ * @param {object} params
68
+ * @param {string} params.owner
69
+ * @param {string} params.repo
70
+ * @param {string} params.pathRel
71
+ * @param {'actions'|'local'} params.mode
72
+ * @param {string|null} [params.root] raiz do repo (para ler a branch corrente)
73
+ * @param {object|null} [params.config]
74
+ * @returns {string}
75
+ */
76
+ export function docBlobUrl({ owner, repo, pathRel, mode, root = null, config = null }) {
77
+ const ref = resolveDocRef({
78
+ mode,
79
+ env: process.env,
80
+ gitBranch: mode === 'actions' ? null : currentGitBranch(root || process.cwd()),
81
+ config,
82
+ });
83
+ return blobUrl({ owner, repo, ref, pathRel });
84
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "spec-wave",
3
3
  "displayName": "Spec Wave",
4
- "version": "0.23.0",
4
+ "version": "0.25.0",
5
5
  "description": "Fluxo spec-driven no GitHub (RFC-001): Projects v2, labels de gatilho, spec/plan gerados por Action, decomposição em duas etapas e implementação orientada a Stories/Tasks.",
6
6
  "author": {
7
7
  "name": "Astratech",
@@ -43,7 +43,8 @@ npx @spec-wave/cli@latest doctor
43
43
  - escopo faltando → o usuário roda `!gh auth refresh --scopes project,repo,workflow` (interativo, ele executa)
44
44
  - `.spec-wave.json` dessincronizado → `npx @spec-wave/cli@latest refresh --config`
45
45
  - workflows/labels divergentes → skill **update**
46
- - secret de IA ausente → Settings → Secrets → Actions (`ANTHROPIC_API_KEY` ou `OPENROUTER_API_KEY`)
46
+ - secret de IA ausente → Settings → Secrets → Actions (`ANTHROPIC_API_KEY`, `CLAUDE_CODE_OAUTH_TOKEN` ou `OPENROUTER_API_KEY`, conforme o provider)
47
+ - modo de execução divergente (config diz `local` e a variável `SPEC_WAVE_EXECUTION` não está setada, ou vice-versa) → `npx @spec-wave/cli@latest mode local|actions` — veja a skill **run**
47
48
  - `specKit.command` ausente → configure antes de usar a skill **implement**
48
49
  3. Trate `!` como "não deu para verificar", não como falha.
49
50
  4. Se tudo passar e o problema original persistir, aí sim investigue a superfície específica (Action, issue, board).
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: spec-wave-run
3
+ description: "Use para conduzir o fluxo do spec-wave LOCALMENTE, sem gastar minutos de GitHub Actions: `spec-wave run <issue>` executa nesta máquina o passo que a label dispararia (spec, plan, crítica, validate, decompose, apply) e `spec-wave mode local|actions` alterna entre os dois mundos. Gatilhos: 'rodar o spec-wave local', 'qual o próximo passo da issue 12', 'sem gastar Actions', 'desligar os workflows', 'trocar para execução local'."
4
+ allowed-tools:
5
+ - Bash(npx @spec-wave/cli@latest *)
6
+ - Bash(gh issue view *)
7
+ - Read
8
+ ---
9
+
10
+ # spec-wave run — o fluxo inteiro na sua máquina
11
+
12
+ Os workflows do spec-wave nunca fizeram o trabalho: eles instalam a CLI e chamam um comando. O `run` é o mesmo comando, disparado **daqui** — e o `mode` desarma os workflows para o gatilho não acontecer duas vezes.
13
+
14
+ ```bash
15
+ npx @spec-wave/cli@latest mode local # desarma os workflows (0 minutos de Actions)
16
+ npx @spec-wave/cli@latest run <issue> # executa o próximo passo pendente
17
+ npx @spec-wave/cli@latest mode actions # volta tudo para o CI
18
+ ```
19
+
20
+ **Contexto:** leia `.spec-wave.json` (Read). Ausente → skill **setup**. O campo `execution.mode` diz em qual mundo o repositório está.
21
+
22
+ ## Como decidir o que fazer
23
+
24
+ 1. **Sempre comece pelo `--dry-run`.** Ele consulta a issue, olha os documentos e explica o passo sem executar nada nem chamar IA:
25
+ ```bash
26
+ npx @spec-wave/cli@latest run <issue> --dry-run
27
+ ```
28
+ 2. Mostre ao usuário o passo, o motivo e o comando que rodaria. **Só então** execute sem a flag.
29
+ 3. `--json` devolve a mesma decisão em JSON, quando você precisar ramificar programaticamente.
30
+
31
+ ## O que o `run` decide sozinho
32
+
33
+ | Estado da issue | Passo |
34
+ |---|---|
35
+ | Feature sem `spec.md` | `generate-spec` |
36
+ | spec pronta, sem `plan.md` | `generate-plan` (a crítica roda embutida) |
37
+ | spec+plan sem `spec-wave:plan-approved` | `validate` |
38
+ | validada, sem `decomposition.md` | `decompose` (rascunho) |
39
+ | `spec-wave:decompose-ready` | `decompose-apply` — **exige `--apply`** |
40
+ | `spec-wave:decomposed` | nada: sugere a skill **implement** |
41
+ | Bug sem `bug.md` → com `bug.md` → validado | `generate-bug` → `validate` → `triage` (humano) |
42
+ | RFC | `decompose` → `decompose-apply` |
43
+
44
+ Para PRs: `run --pr <n>` roda `code-review` e, se houver review aprovada, também `qa` — a mesma coisa que os workflows fariam nos eventos do PR.
45
+
46
+ ## Portões (quando ele se recusa a rodar)
47
+
48
+ O comando **explica e para**, saindo com código 2. Não force sem entender:
49
+
50
+ - **`trigger-pending`** — há label de gatilho na issue: um Action está em voo (ou falhou deixando-a). Rodar por cima duplicaria documento e comentário. `--force` fura, quando você tem certeza.
51
+ - **`needs-human` / `critique-failed`** — portões humanos da crítica. O caminho é corrigir o documento e remover a label; para o `critique-failed` o passo de retomada é **re-criticar**, nunca regerar.
52
+ - **`stale-checkout`** — o documento existe no repositório e não no seu clone. `git pull` e repita; seguir sobrescreveria o que já foi publicado.
53
+ - **`needs-confirmation`** — o passo cria issues (`decompose-apply`) ou gasta IA repetindo a crítica de um rascunho existente. Revise antes e confirme com `--apply` / `--yes`.
54
+ - **`inconsistent-state`** — as labels afirmam um documento que não existe. Quase sempre o título da issue mudou depois de gerar (o slug vira outro diretório).
55
+
56
+ ## Regras que o `run` respeita — e você também
57
+
58
+ - **Nunca aplique label de gatilho no modo local.** Ela dispararia o Action e o passo aconteceria duas vezes. O `run` não aplica nenhuma.
59
+ - **Um passo por invocação.** `--max-steps <n>` encadeia, mas cada passo de IA custa dinheiro — encadeie só quando o usuário pedir.
60
+ - A **Regra fundamental** continua valendo: nunca escreva `spec.md`/`plan.md`/`decomposition.md` à mão. Quem gera é a CLI, aqui como no Action.
61
+
62
+ ## `mode` — o interruptor
63
+
64
+ ```bash
65
+ npx @spec-wave/cli@latest mode # estado atual
66
+ npx @spec-wave/cli@latest mode local # config + variável SPEC_WAVE_EXECUTION
67
+ npx @spec-wave/cli@latest mode actions # remove a variável
68
+ ```
69
+
70
+ Ele escreve os **dois** lados: o `.spec-wave.json` (que a CLI e as skills leem) e a variável de repositório que o `if:` de cada job avalia. Com ela setada, o run do workflow aparece como *skipped* — job que não roda não é faturado.
71
+
72
+ - A variável exige **admin** no repositório. Sem permissão o comando grava o config, avisa e aponta Settings → Secrets and variables → Actions → Variables.
73
+ - **Commite o `.spec-wave.json`**: quem clona o repo (inclusive o dev-agent) lê a versão versionada.
74
+ - Se os workflows instalados forem anteriores à guarda, o comando avisa e o conserto é a skill **update**.
75
+
76
+ O `doctor` tem um check dedicado: config e variável em desacordo é problema, não detalhe — é o usuário achando que desligou o CI e continuando a pagar por ele.
@@ -58,7 +58,7 @@ Você dirige o `init` **com flags**. Nunca rode `npx @spec-wave/cli@latest init`
58
58
 
59
59
  8. **Adapte o `tech_context.yml`** — o scaffold vem com dados de exemplo e a qualidade do `plan.md` depende dele. Ofereça ajustá-lo agora; o passo a passo está na skill **plan** (`reference/tech-context.md`).
60
60
 
61
- 9. **Secret de IA:** instrua a adicionar em Settings → Secrets → Actions a chave do provider escolhido: `ANTHROPIC_API_KEY` (Anthropic) ou `OPENROUTER_API_KEY` (OpenRouter).
61
+ 9. **Secret de IA:** instrua a adicionar em Settings → Secrets → Actions a credencial do provider escolhido: `ANTHROPIC_API_KEY` (Anthropic), `CLAUDE_CODE_OAUTH_TOKEN` (assinatura Claude Pro/Max — gere com `claude setup-token`) ou `OPENROUTER_API_KEY` (OpenRouter).
62
62
 
63
63
  10. **Próximo passo:** criar a primeira Feature — skill **issue**.
64
64
 
@@ -20,7 +20,7 @@ allowed-tools:
20
20
 
21
21
  O modo é detectado pelo ambiente — fora do Actions, a CLI roda em modo local automaticamente. Os dois geram o arquivo, commitam, dão push, comentam na issue e removem a label de gatilho. **Pergunte ao usuário qual ele quer** se não estiver claro; na dúvida numa sessão interativa, prefira o local (o resultado aparece em segundos, em vez de exigir acompanhar o Action).
22
22
 
23
- > Local exige a chave de IA no seu ambiente (`OPENROUTER_API_KEY` ou `ANTHROPIC_API_KEY`) e um `.spec-wave.json` no repositório. O provider `anthropic` **só** funciona local no Action ele precisaria do Claude Code como subprocesso, que o runner não tem.
23
+ > Local exige a credencial de IA no seu ambiente (`OPENROUTER_API_KEY`, `ANTHROPIC_API_KEY` ou o login do Claude Code, se o provider for `claude-oauth`) e um `.spec-wave.json` no repositório. Para conduzir o fluxo inteiro sem gastar minutos de Actions, veja a skill **run**.
24
24
 
25
25
  **Contexto:** leia `.spec-wave.json` (Read). Ausente → skill **setup**.
26
26
 
@@ -61,9 +61,32 @@ Exemplo de `.spec-wave.json`:
61
61
 
62
62
  ---
63
63
 
64
+ ## Modo de execução (Actions × local)
65
+
66
+ Leia `execution.mode` no `.spec-wave.json` **antes** de acionar qualquer passo do fluxo:
67
+
68
+ | `execution.mode` | Como acionar um passo | Custo |
69
+ |---|---|---|
70
+ | `actions` (default) | aplicar a label de gatilho (`spec-wave:spec`, `:plan`, …) | minutos de GitHub Actions |
71
+ | `local` | `npx @spec-wave/cli@latest run <issue>` | nenhum — roda nesta máquina |
72
+
73
+ **No modo `local`, NÃO aplique label de gatilho.** Os workflows estão desarmados por uma variável de repositório, mas a label continua sendo o contrato do outro modo — aplicá-la só polui a issue (e, se alguém religar o CI, dispara tarde).
74
+
75
+ ```bash
76
+ npx @spec-wave/cli@latest mode # estado atual dos dois lados do interruptor
77
+ npx @spec-wave/cli@latest mode local # desarma os workflows
78
+ npx @spec-wave/cli@latest run <issue> --dry-run # explica o próximo passo sem executar
79
+ npx @spec-wave/cli@latest run <issue> # executa
80
+ npx @spec-wave/cli@latest run --pr <n> # code-review (+ qa, se houver aprovação)
81
+ ```
82
+
83
+ O `run` decide o passo pelo estado da issue (documentos existentes + labels), respeita os portões humanos (`needs-human`, `critique-failed`), recusa rodar com uma label de gatilho pendente e **exige `--apply`** para o `decompose-apply`, que cria issues. Sempre mostre o `--dry-run` ao usuário antes de executar.
84
+
85
+ ---
86
+
64
87
  ## Regra fundamental
65
88
 
66
- **Nunca gere `spec.md` ou `plan.md` diretamente.** Sempre acione a label correspondente e deixe o GitHub Action gerar o arquivo. Isso garante que o arquivo seja commitado no repositório e referenciado na issue.
89
+ **Nunca gere `spec.md` ou `plan.md` diretamente.** Acione o passo — a label (modo actions) ou o `run` (modo local) — e deixe o spec-wave gerar o arquivo. Isso garante que o arquivo seja commitado no repositório e referenciado na issue.
67
90
 
68
91
  Exceção: se o usuário pedir explicitamente para revisar ou melhorar um documento já gerado, use o Write tool para editar o arquivo local.
69
92
 
@@ -459,7 +482,7 @@ Configura o spec-wave no repositório. Você dirige o `init` com flags — **nun
459
482
  Use `--skip-project` / `--skip-labels` / `--skip-files` **apenas** para re-rodar uma fase específica que falhou antes.
460
483
  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.
461
484
  8. **Adapte o `tech_context.yml`**: o scaffold vem com dados de exemplo. Ofereça ajustá-lo à stack real do repo seguindo a seção **Tech Context** (perto do comando `/spec-wave plan`) — isso melhora muito a qualidade do `plan.md`.
462
- 9. Instrua o usuário a adicionar a chave de IA como secret no repositório (Settings → Secrets → Actions): `ANTHROPIC_API_KEY` (Anthropic) ou `OPENROUTER_API_KEY` (OpenRouter), conforme o provider escolhido no `init`.
485
+ 9. Instrua o usuário a adicionar a credencial de IA como secret no repositório (Settings → Secrets → Actions): `ANTHROPIC_API_KEY` (Anthropic), `CLAUDE_CODE_OAUTH_TOKEN` (assinatura Claude Pro/Max — gere com `claude setup-token`) ou `OPENROUTER_API_KEY` (OpenRouter), conforme o provider escolhido no `init`.
463
486
 
464
487
  ---
465
488
 
@@ -15,6 +15,10 @@ jobs:
15
15
  # de concurrency ao job seguinte: `concurrency` de workflow é avaliada no
16
16
  # trigger, quando ainda não se sabe qual issue o PR implementa.
17
17
  resolve:
18
+ # Modo de execução: `spec-wave mode local` cria a variável de repositório
19
+ # SPEC_WAVE_EXECUTION=local e este job passa a ser PULADO — run aparece como
20
+ # skipped e job que não roda não é faturado. `mode actions` remove a variável.
21
+ if: vars.SPEC_WAVE_EXECUTION != 'local'
18
22
  runs-on: ubuntu-latest
19
23
  permissions:
20
24
  issues: read
@@ -40,7 +44,7 @@ jobs:
40
44
  move:
41
45
  needs: resolve
42
46
  # PR sem vínculo explícito não resolve Feature nenhuma — e não move nada.
43
- if: needs.resolve.outputs.feature != ''
47
+ if: vars.SPEC_WAVE_EXECUTION != 'local' && needs.resolve.outputs.feature != ''
44
48
  runs-on: ubuntu-latest
45
49
  # MESMO namespace do decompose.yml: um `decompose-apply` em curso na Feature
46
50
  # segura este job na fila em vez de disputar a subárvore com ele. Foi essa
@@ -24,7 +24,11 @@ concurrency:
24
24
 
25
25
  jobs:
26
26
  critique:
27
+ # Modo de execução: `spec-wave mode local` cria a variável de repositório
28
+ # SPEC_WAVE_EXECUTION=local e este job passa a ser PULADO — run aparece como
29
+ # skipped e job que não roda não é faturado. `mode actions` remove a variável.
27
30
  if: >
31
+ vars.SPEC_WAVE_EXECUTION != 'local' &&
28
32
  github.event.label.name == 'spec-wave:critique' &&
29
33
  contains(github.event.issue.title, '[FEATURE]')
30
34
  runs-on: ubuntu-latest
@@ -51,5 +55,6 @@ jobs:
51
55
  env:
52
56
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53
57
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
58
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
54
59
  OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
55
60
  GITHUB_REPOSITORY: ${{ github.repository }}
@@ -44,7 +44,11 @@ jobs:
44
44
  # • spec-wave:decompose-apply → cria as Stories/Tasks a partir do rascunho
45
45
  # O `[RFC]` no título também dispara: o caminho RFC → Tasks existe na CLI
46
46
  # desde sempre, mas era inalcançável porque o filtro exigia `[FEATURE]`.
47
+ # Modo de execução: `spec-wave mode local` cria a variável de repositório
48
+ # SPEC_WAVE_EXECUTION=local e este job passa a ser PULADO — run aparece como
49
+ # skipped e job que não roda não é faturado. `mode actions` remove a variável.
47
50
  if: >
51
+ vars.SPEC_WAVE_EXECUTION != 'local' &&
48
52
  (github.event.label.name == 'spec-wave:decompose' ||
49
53
  github.event.label.name == 'spec-wave:decompose-apply') &&
50
54
  (contains(github.event.issue.title, '[FEATURE]') ||
@@ -76,5 +80,6 @@ jobs:
76
80
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
77
81
  PROJECT_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }}
78
82
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
83
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
79
84
  OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
80
85
  GITHUB_REPOSITORY: ${{ github.repository }}
@@ -31,7 +31,11 @@ concurrency:
31
31
 
32
32
  jobs:
33
33
  generate-bug:
34
+ # Modo de execução: `spec-wave mode local` cria a variável de repositório
35
+ # SPEC_WAVE_EXECUTION=local e este job passa a ser PULADO — run aparece como
36
+ # skipped e job que não roda não é faturado. `mode actions` remove a variável.
34
37
  if: >
38
+ vars.SPEC_WAVE_EXECUTION != 'local' &&
35
39
  github.event.label.name == 'spec-wave:bug' &&
36
40
  contains(github.event.issue.title, '[BUG]')
37
41
  runs-on: ubuntu-latest
@@ -56,5 +60,6 @@ jobs:
56
60
  env:
57
61
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58
62
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
63
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
59
64
  OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
60
65
  GITHUB_REPOSITORY: ${{ github.repository }}
@@ -39,7 +39,11 @@ concurrency:
39
39
 
40
40
  jobs:
41
41
  generate-plan:
42
+ # Modo de execução: `spec-wave mode local` cria a variável de repositório
43
+ # SPEC_WAVE_EXECUTION=local e este job passa a ser PULADO — run aparece como
44
+ # skipped e job que não roda não é faturado. `mode actions` remove a variável.
42
45
  if: >
46
+ vars.SPEC_WAVE_EXECUTION != 'local' &&
43
47
  github.event.label.name == 'spec-wave:plan' &&
44
48
  contains(github.event.issue.title, '[FEATURE]')
45
49
  runs-on: ubuntu-latest
@@ -64,5 +68,6 @@ jobs:
64
68
  env:
65
69
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
66
70
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
71
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
67
72
  OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
68
73
  GITHUB_REPOSITORY: ${{ github.repository }}
@@ -39,7 +39,11 @@ concurrency:
39
39
 
40
40
  jobs:
41
41
  generate-spec:
42
+ # Modo de execução: `spec-wave mode local` cria a variável de repositório
43
+ # SPEC_WAVE_EXECUTION=local e este job passa a ser PULADO — run aparece como
44
+ # skipped e job que não roda não é faturado. `mode actions` remove a variável.
42
45
  if: >
46
+ vars.SPEC_WAVE_EXECUTION != 'local' &&
43
47
  github.event.label.name == 'spec-wave:spec' &&
44
48
  contains(github.event.issue.title, '[FEATURE]')
45
49
  runs-on: ubuntu-latest
@@ -64,5 +68,6 @@ jobs:
64
68
  env:
65
69
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
66
70
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
71
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
67
72
  OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
68
73
  GITHUB_REPOSITORY: ${{ github.repository }}
@@ -10,7 +10,12 @@ concurrency:
10
10
 
11
11
  jobs:
12
12
  qa:
13
- if: github.event.review.state == 'approved'
13
+ # Modo de execução: `spec-wave mode local` cria a variável de repositório
14
+ # SPEC_WAVE_EXECUTION=local e este job passa a ser PULADO — run aparece como
15
+ # skipped e job que não roda não é faturado. `mode actions` remove a variável.
16
+ if: >
17
+ vars.SPEC_WAVE_EXECUTION != 'local' &&
18
+ github.event.review.state == 'approved'
14
19
  runs-on: ubuntu-latest
15
20
  permissions:
16
21
  issues: write
@@ -24,7 +24,11 @@ concurrency:
24
24
 
25
25
  jobs:
26
26
  validate:
27
+ # Modo de execução: `spec-wave mode local` cria a variável de repositório
28
+ # SPEC_WAVE_EXECUTION=local e este job passa a ser PULADO — run aparece como
29
+ # skipped e job que não roda não é faturado. `mode actions` remove a variável.
27
30
  if: >
31
+ vars.SPEC_WAVE_EXECUTION != 'local' &&
28
32
  github.event.label.name == 'spec-wave:ready' &&
29
33
  (contains(github.event.issue.title, '[FEATURE]') ||
30
34
  contains(github.event.issue.title, '[BUG]'))