@spec-wave/cli 0.34.0 → 0.34.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 +1 -1
- package/src/commands/decompose.mjs +2 -1
- package/src/commands/generate-bug.mjs +1 -1
- package/src/commands/generate-plan.mjs +2 -2
- package/src/commands/generate-qa-plan.mjs +2 -1
- package/src/commands/generate-spec.mjs +1 -1
- package/src/lib/flow-run.mjs +27 -1
- package/src/plugin/.claude-plugin/plugin.json +1 -1
- package/src/templates/workflows/code-review.yml +4 -4
- package/src/templates/workflows/critique.yml +2 -2
- package/src/templates/workflows/decompose.yml +2 -2
- package/src/templates/workflows/generate-bug.yml +2 -2
- package/src/templates/workflows/generate-plan.yml +2 -2
- package/src/templates/workflows/generate-qa-plan.yml +2 -2
- package/src/templates/workflows/generate-spec.yml +2 -2
- package/src/templates/workflows/qa.yml +2 -2
- package/src/templates/workflows/validate.yml +2 -2
package/package.json
CHANGED
|
@@ -36,7 +36,7 @@ import { resolveDocDir } from '../lib/doc-paths.mjs';
|
|
|
36
36
|
import { docBlobUrl } from '../lib/repo-links.mjs';
|
|
37
37
|
import { detectIssueType } from '../lib/issue-type.mjs';
|
|
38
38
|
import { loadConfig } from '../lib/project-root.mjs';
|
|
39
|
-
import { resolveFlowContext } from '../lib/flow-run.mjs';
|
|
39
|
+
import { executionMode, missingRootMessage, resolveFlowContext } from '../lib/flow-run.mjs';
|
|
40
40
|
import { publishArtifact } from '../lib/artifact-publish.mjs';
|
|
41
41
|
import { buildDependencyMap, storiesFromAppliedDoc, DEPENDENCY_MAP_FILE } from '../lib/dependency-map.mjs';
|
|
42
42
|
import { invalidateCache } from '../lib/net-cache.mjs';
|
|
@@ -1136,6 +1136,7 @@ export async function decompose({ issueNumber, apply }) {
|
|
|
1136
1136
|
|
|
1137
1137
|
// Config do repo: raiz para os caminhos de documento e escalada da crítica.
|
|
1138
1138
|
const { config, root } = loadConfig();
|
|
1139
|
+
if (!root) throw new Error(missingRootMessage('decompose', executionMode()));
|
|
1139
1140
|
const { rel: docRel } = resolveDocDir(root, issue, type);
|
|
1140
1141
|
|
|
1141
1142
|
// Branch base: é dela que os documentos são lidos quando não estão no clone, e
|
|
@@ -52,7 +52,7 @@ export async function generateBug({ issueNumber }) {
|
|
|
52
52
|
// Mesmo contexto dos outros geradores: GITHUB_REPOSITORY quando existe, o
|
|
53
53
|
// `.spec-wave.json` quando não. Este comando exigia a env crua e morria fora
|
|
54
54
|
// do runner mandando exportá-la — dentro de um repo que já sabe seu owner/repo.
|
|
55
|
-
const { owner, repo, root, config, mode } = resolveFlowContext({ command: 'generate-bug' });
|
|
55
|
+
const { owner, repo, root, config, mode } = resolveFlowContext({ command: 'generate-bug', requireRoot: true });
|
|
56
56
|
const n = parseInt(issueNumber, 10);
|
|
57
57
|
|
|
58
58
|
console.log(`Buscando issue #${n}...`);
|
|
@@ -132,7 +132,7 @@ async function critiquePlan({
|
|
|
132
132
|
export async function generatePlan({ issueNumber }) {
|
|
133
133
|
const token = await resolveToken();
|
|
134
134
|
// Roda nos dois modos: no Action (disparado por label) e na sessão local.
|
|
135
|
-
const { owner, repo, root, config, mode } = resolveFlowContext({ command: 'generate-plan' });
|
|
135
|
+
const { owner, repo, root, config, mode } = resolveFlowContext({ command: 'generate-plan', requireRoot: true });
|
|
136
136
|
console.log(`Modo de execução: ${mode}`);
|
|
137
137
|
|
|
138
138
|
console.log(`Buscando issue #${issueNumber}...`);
|
|
@@ -384,7 +384,7 @@ export async function critique({ issueNumber, file, kind, failOnGrave = false })
|
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
const token = await resolveToken();
|
|
387
|
-
const { owner, repo, root, config, mode } = resolveFlowContext({ command: 'critique' });
|
|
387
|
+
const { owner, repo, root, config, mode } = resolveFlowContext({ command: 'critique', requireRoot: true });
|
|
388
388
|
console.log(`Modo de execução: ${mode}`);
|
|
389
389
|
|
|
390
390
|
const n = parseInt(issueNumber, 10);
|
|
@@ -27,7 +27,7 @@ import { recordUsage } from '../lib/usage-report.mjs';
|
|
|
27
27
|
import { resolveDocDir } from '../lib/doc-paths.mjs';
|
|
28
28
|
import { docBlobUrl } from '../lib/repo-links.mjs';
|
|
29
29
|
import { loadConfig } from '../lib/project-root.mjs';
|
|
30
|
-
import { resolveFlowContext } from '../lib/flow-run.mjs';
|
|
30
|
+
import { executionMode, missingRootMessage, resolveFlowContext } from '../lib/flow-run.mjs';
|
|
31
31
|
import { publishArtifact } from '../lib/artifact-publish.mjs';
|
|
32
32
|
import { loadArtifact, isAwaitingMerge } from '../lib/doc-source.mjs';
|
|
33
33
|
import { awaitingMergeBlock, renderPrLine } from '../lib/artifact-pr.mjs';
|
|
@@ -121,6 +121,7 @@ export async function generateQaPlan({ issueNumber }) {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
const { config, root } = loadConfig();
|
|
124
|
+
if (!root) throw new Error(missingRootMessage('generate-qa-plan', executionMode()));
|
|
124
125
|
const { rel: dirRel } = resolveDocDir(root, issue, type);
|
|
125
126
|
const docRel = `${dirRel}/${QA_PLAN_FILE}`;
|
|
126
127
|
const base = await getRepoDefaultBranch(token, owner, repo).catch(() => null);
|
|
@@ -32,7 +32,7 @@ function formatLintWarning(lintFindings) {
|
|
|
32
32
|
export async function generateSpec({ issueNumber }) {
|
|
33
33
|
const token = await resolveToken();
|
|
34
34
|
// Roda nos dois modos: no Action (disparado por label) e na sessão local.
|
|
35
|
-
const { owner, repo, root, mode } = resolveFlowContext({ command: 'generate-spec' });
|
|
35
|
+
const { owner, repo, root, mode } = resolveFlowContext({ command: 'generate-spec', requireRoot: true });
|
|
36
36
|
console.log(`Modo de execução: ${mode}`);
|
|
37
37
|
|
|
38
38
|
console.log(`Buscando issue #${issueNumber}...`);
|
package/src/lib/flow-run.mjs
CHANGED
|
@@ -43,9 +43,14 @@ export function executionMode(env = process.env) {
|
|
|
43
43
|
* @param {string} [opts.cwd]
|
|
44
44
|
* @param {string} [opts.command] nome do comando, para a mensagem de erro
|
|
45
45
|
* @param {object} [opts.env]
|
|
46
|
+
* @param {boolean} [opts.requireRoot] comandos que ancoram caminhos/prompts na
|
|
47
|
+
* raiz devem exigi-la: sem isto um repo nunca inicializado (checkout
|
|
48
|
+
* dos Actions sem .spec-wave.json) seguia com root=null e morria três
|
|
49
|
+
* chamadas depois com `path.join(null, …)` — "The path argument must
|
|
50
|
+
* be of type string. Received null" (caso real, 2026-09-06).
|
|
46
51
|
* @returns {{owner: string, repo: string, root: string|null, config: object|null, mode: 'actions'|'local'}}
|
|
47
52
|
*/
|
|
48
|
-
export function resolveFlowContext({ cwd = process.cwd(), command = 'este comando', env = process.env } = {}) {
|
|
53
|
+
export function resolveFlowContext({ cwd = process.cwd(), command = 'este comando', env = process.env, requireRoot = false } = {}) {
|
|
49
54
|
// Repassa o `env` recebido: sem isso o modo local fica intestável dentro do
|
|
50
55
|
// GitHub Actions, que define GITHUB_REPOSITORY em toda execução.
|
|
51
56
|
const { owner, repo, root, config } = resolveRepoContext(cwd, env);
|
|
@@ -61,5 +66,26 @@ export function resolveFlowContext({ cwd = process.cwd(), command = 'este comand
|
|
|
61
66
|
` GITHUB_REPOSITORY=owner/repo spec-wave ${command} --issue-number 1`)
|
|
62
67
|
);
|
|
63
68
|
}
|
|
69
|
+
if (requireRoot && !root) {
|
|
70
|
+
throw new Error(missingRootMessage(command, mode));
|
|
71
|
+
}
|
|
64
72
|
return { owner, repo, root, config, mode };
|
|
65
73
|
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Mensagem de "repositório não inicializado" — compartilhada com os comandos
|
|
77
|
+
* que resolvem a raiz via loadConfig() direto (decompose, generate-qa-plan).
|
|
78
|
+
*
|
|
79
|
+
* @param {string} command
|
|
80
|
+
* @param {'actions'|'local'} mode
|
|
81
|
+
* @returns {string}
|
|
82
|
+
*/
|
|
83
|
+
export function missingRootMessage(command, mode) {
|
|
84
|
+
return (
|
|
85
|
+
`${CONFIG_FILE} não encontrado — spec-wave ${command} precisa da raiz do projeto.\n` +
|
|
86
|
+
(mode === 'actions'
|
|
87
|
+
? `Este repositório ainda não foi inicializado para o spec-wave: rode \`spec-wave init\` ` +
|
|
88
|
+
`no repositório e commite o ${CONFIG_FILE}.`
|
|
89
|
+
: `Rode \`spec-wave init\` na raiz do repositório primeiro.`)
|
|
90
|
+
);
|
|
91
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec-wave",
|
|
3
3
|
"displayName": "Spec Wave",
|
|
4
|
-
"version": "0.34.
|
|
4
|
+
"version": "0.34.2",
|
|
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",
|
|
@@ -35,8 +35,8 @@ jobs:
|
|
|
35
35
|
outputs:
|
|
36
36
|
feature: ${{ steps.resolve.outputs.feature }}
|
|
37
37
|
steps:
|
|
38
|
-
- uses: actions/checkout@
|
|
39
|
-
- uses: actions/setup-node@
|
|
38
|
+
- uses: actions/checkout@v5
|
|
39
|
+
- uses: actions/setup-node@v5
|
|
40
40
|
with:
|
|
41
41
|
node-version: '24'
|
|
42
42
|
|
|
@@ -69,9 +69,9 @@ jobs:
|
|
|
69
69
|
contents: read
|
|
70
70
|
|
|
71
71
|
steps:
|
|
72
|
-
- uses: actions/checkout@
|
|
72
|
+
- uses: actions/checkout@v5
|
|
73
73
|
|
|
74
|
-
- uses: actions/setup-node@
|
|
74
|
+
- uses: actions/setup-node@v5
|
|
75
75
|
with:
|
|
76
76
|
node-version: '24'
|
|
77
77
|
|
|
@@ -39,11 +39,11 @@ jobs:
|
|
|
39
39
|
contents: read
|
|
40
40
|
|
|
41
41
|
steps:
|
|
42
|
-
- uses: actions/checkout@
|
|
42
|
+
- uses: actions/checkout@v5
|
|
43
43
|
with:
|
|
44
44
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
45
45
|
|
|
46
|
-
- uses: actions/setup-node@
|
|
46
|
+
- uses: actions/setup-node@v5
|
|
47
47
|
with:
|
|
48
48
|
node-version: '24'
|
|
49
49
|
|
|
@@ -70,11 +70,11 @@ jobs:
|
|
|
70
70
|
pull-requests: write
|
|
71
71
|
|
|
72
72
|
steps:
|
|
73
|
-
- uses: actions/checkout@
|
|
73
|
+
- uses: actions/checkout@v5
|
|
74
74
|
with:
|
|
75
75
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
76
76
|
|
|
77
|
-
- uses: actions/setup-node@
|
|
77
|
+
- uses: actions/setup-node@v5
|
|
78
78
|
with:
|
|
79
79
|
node-version: '24'
|
|
80
80
|
|
|
@@ -54,11 +54,11 @@ jobs:
|
|
|
54
54
|
pull-requests: write
|
|
55
55
|
|
|
56
56
|
steps:
|
|
57
|
-
- uses: actions/checkout@
|
|
57
|
+
- uses: actions/checkout@v5
|
|
58
58
|
with:
|
|
59
59
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
60
60
|
|
|
61
|
-
- uses: actions/setup-node@
|
|
61
|
+
- uses: actions/setup-node@v5
|
|
62
62
|
with:
|
|
63
63
|
node-version: '24'
|
|
64
64
|
|
|
@@ -64,11 +64,11 @@ jobs:
|
|
|
64
64
|
pull-requests: write
|
|
65
65
|
|
|
66
66
|
steps:
|
|
67
|
-
- uses: actions/checkout@
|
|
67
|
+
- uses: actions/checkout@v5
|
|
68
68
|
with:
|
|
69
69
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
70
70
|
|
|
71
|
-
- uses: actions/setup-node@
|
|
71
|
+
- uses: actions/setup-node@v5
|
|
72
72
|
with:
|
|
73
73
|
node-version: '24'
|
|
74
74
|
|
|
@@ -41,11 +41,11 @@ jobs:
|
|
|
41
41
|
pull-requests: write
|
|
42
42
|
|
|
43
43
|
steps:
|
|
44
|
-
- uses: actions/checkout@
|
|
44
|
+
- uses: actions/checkout@v5
|
|
45
45
|
with:
|
|
46
46
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
47
47
|
|
|
48
|
-
- uses: actions/setup-node@
|
|
48
|
+
- uses: actions/setup-node@v5
|
|
49
49
|
with:
|
|
50
50
|
node-version: '24'
|
|
51
51
|
|
|
@@ -64,11 +64,11 @@ jobs:
|
|
|
64
64
|
pull-requests: write
|
|
65
65
|
|
|
66
66
|
steps:
|
|
67
|
-
- uses: actions/checkout@
|
|
67
|
+
- uses: actions/checkout@v5
|
|
68
68
|
with:
|
|
69
69
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
70
70
|
|
|
71
|
-
- uses: actions/setup-node@
|
|
71
|
+
- uses: actions/setup-node@v5
|
|
72
72
|
with:
|
|
73
73
|
node-version: '24'
|
|
74
74
|
|