@spec-wave/cli 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spec-wave/cli",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Setup spec-driven GitHub workflow with Projects v2, labels, issue templates, and AI-powered Actions",
5
5
  "type": "module",
6
6
  "bin": {
@@ -69,13 +69,17 @@ async function setCodeReview(token, project, etapaField, statusField, nodeId) {
69
69
 
70
70
  export async function codeReview({ prNumber }) {
71
71
  const token = await resolveToken();
72
- const [owner, repo] = (process.env.GITHUB_REPOSITORY || '').split('/');
72
+ const [envOwner, envRepo] = (process.env.GITHUB_REPOSITORY || '').split('/');
73
+ const cfgPath = path.join(process.cwd(), CONFIG_FILE);
74
+ let cfg = {};
75
+ try { if (existsSync(cfgPath)) cfg = JSON.parse(readFileSync(cfgPath, 'utf-8')); } catch {}
76
+ const owner = envOwner || cfg.owner;
77
+ const repo = envRepo || cfg.repo;
73
78
 
74
79
  if (!owner || !repo) {
75
80
  throw new Error(
76
- 'GITHUB_REPOSITORY env var não definida.\n' +
77
- 'Este comando roda no GitHub Actions. Para testar localmente:\n' +
78
- ` GITHUB_REPOSITORY=owner/repo spec-wave code-review --pr-number ${prNumber}`
81
+ 'Não foi possível determinar owner/repo.\n' +
82
+ 'Defina GITHUB_REPOSITORY=owner/repo ou rode dentro de um repositório com .spec-wave.json.'
79
83
  );
80
84
  }
81
85
 
@@ -8,7 +8,7 @@ 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 { upsertFile } from '../api/github-rest.mjs';
11
+ import { upsertFile, getFileContent } from '../api/github-rest.mjs';
12
12
  import { CONFIG_FILE, AI_PROVIDERS, getProvider, DEFAULT_PROVIDER } from '../config.mjs';
13
13
 
14
14
  const __dir = path.dirname(fileURLToPath(import.meta.url));
@@ -90,6 +90,22 @@ export async function init(options) {
90
90
  let projectUrl, projectId, projectNumber, projectFields;
91
91
  if (options.skipProject) {
92
92
  p.log.info('Pulando criação do GitHub Project (--skip-project).');
93
+ // Preserva o bloco project do .spec-wave.json existente (se houver).
94
+ try {
95
+ const raw = await getFileContent(token, owner, repo, CONFIG_FILE);
96
+ if (raw) {
97
+ const existing = JSON.parse(raw);
98
+ if (existing.project) {
99
+ projectUrl = existing.project.url ?? undefined;
100
+ projectId = existing.project.id ?? undefined;
101
+ projectNumber = existing.project.number ?? undefined;
102
+ projectFields = existing.project.fields ?? undefined;
103
+ p.log.info('Dados do Project preservados do config existente.');
104
+ }
105
+ }
106
+ } catch {
107
+ // Sem config existente — mantém undefined (será gravado como null).
108
+ }
93
109
  } else {
94
110
  const projectSpinner = p.spinner();
95
111
  projectSpinner.start('Criando GitHub Project...');
@@ -64,13 +64,17 @@ async function setQA(token, project, etapaField, statusField, nodeId) {
64
64
 
65
65
  export async function qa({ prNumber }) {
66
66
  const token = await resolveToken();
67
- const [owner, repo] = (process.env.GITHUB_REPOSITORY || '').split('/');
67
+ const [envOwner, envRepo] = (process.env.GITHUB_REPOSITORY || '').split('/');
68
+ const cfgPath = path.join(process.cwd(), CONFIG_FILE);
69
+ let cfg = {};
70
+ try { if (existsSync(cfgPath)) cfg = JSON.parse(readFileSync(cfgPath, 'utf-8')); } catch {}
71
+ const owner = envOwner || cfg.owner;
72
+ const repo = envRepo || cfg.repo;
68
73
 
69
74
  if (!owner || !repo) {
70
75
  throw new Error(
71
- 'GITHUB_REPOSITORY env var não definida.\n' +
72
- 'Este comando roda no GitHub Actions. Para testar localmente:\n' +
73
- ` GITHUB_REPOSITORY=owner/repo spec-wave qa --pr-number ${prNumber}`
76
+ 'Não foi possível determinar owner/repo.\n' +
77
+ 'Defina GITHUB_REPOSITORY=owner/repo ou rode dentro de um repositório com .spec-wave.json.'
74
78
  );
75
79
  }
76
80
 
@@ -52,13 +52,17 @@ async function moveToDone(token, issue) {
52
52
 
53
53
  export async function validate({ issueNumber }) {
54
54
  const token = await resolveToken();
55
- const [owner, repo] = (process.env.GITHUB_REPOSITORY || '').split('/');
55
+ const [envOwner, envRepo] = (process.env.GITHUB_REPOSITORY || '').split('/');
56
+ const configPath = path.join(process.cwd(), CONFIG_FILE);
57
+ let cfg = {};
58
+ try { if (existsSync(configPath)) cfg = JSON.parse(readFileSync(configPath, 'utf-8')); } catch {}
59
+ const owner = envOwner || cfg.owner;
60
+ const repo = envRepo || cfg.repo;
56
61
 
57
62
  if (!owner || !repo) {
58
63
  throw new Error(
59
- 'GITHUB_REPOSITORY env var não definida.\n' +
60
- 'Este comando roda no GitHub Actions. Para testar localmente:\n' +
61
- ' GITHUB_REPOSITORY=owner/repo spec-wave validate --issue-number 1'
64
+ 'Não foi possível determinar owner/repo.\n' +
65
+ 'Defina GITHUB_REPOSITORY=owner/repo ou rode o comando dentro de um repositório com .spec-wave.json.'
62
66
  );
63
67
  }
64
68
 
@@ -110,7 +114,9 @@ export async function validate({ issueNumber }) {
110
114
  process.exit(1);
111
115
  }
112
116
 
113
- // Validação passou: move a issue para "🎉 Done" no board (best-effort).
117
+ // Validação passou: adiciona label plan-approved e move board para Done.
118
+ await addLabel(token, owner, repo, parseInt(issueNumber, 10), 'spec-wave:plan-approved');
119
+
114
120
  let doneOk = false;
115
121
  try {
116
122
  await moveToDone(token, issue);
package/src/config.mjs CHANGED
@@ -129,10 +129,11 @@ export const PRIORITY_LABELS = [
129
129
  ];
130
130
 
131
131
  export const TRIGGER_LABELS = [
132
- { name: 'spec-wave:spec', color: 'BFD4F2', description: 'Gerar spec.md via GitHub Action' },
133
- { name: 'spec-wave:plan', color: 'BFD4F2', description: 'Gerar plan.md via GitHub Action' },
134
- { name: 'spec-wave:ready', color: '0E8A16', description: 'Validar spec+plan e mover para Ready' },
135
- { name: 'spec-wave:decompose', color: 'BFD4F2', description: 'Decompor em Stories e Tasks' },
132
+ { name: 'spec-wave:spec', color: 'BFD4F2', description: 'Gerar spec.md via GitHub Action' },
133
+ { name: 'spec-wave:plan', color: 'BFD4F2', description: 'Gerar plan.md via GitHub Action' },
134
+ { name: 'spec-wave:ready', color: '0E8A16', description: 'Validar spec+plan e mover para Ready' },
135
+ { name: 'spec-wave:plan-approved', color: '0E8A16', description: 'Spec+plan validados com sucesso' },
136
+ { name: 'spec-wave:decompose', color: 'BFD4F2', description: 'Decompor em Stories e Tasks' },
136
137
  ];
137
138
 
138
139
  export const ALL_LABELS = [...TYPE_LABELS, ...PRIORITY_LABELS, ...TRIGGER_LABELS];