@gavin-hjw/sddflow 0.3.2 → 0.3.3
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/README.md +154 -105
- package/README.zh-CN.md +154 -104
- package/bin/sddflow.js +1 -1
- package/dist/cli/init.js +78 -47
- package/dist/cli/status.js +22 -24
- package/dist/cli/update.js +3 -3
- package/dist/core/change-status.d.ts +9 -0
- package/dist/core/change-status.js +66 -0
- package/dist/core/constants.d.ts +14 -2
- package/dist/core/constants.js +60 -2
- package/dist/core/dependency-check.d.ts +29 -3
- package/dist/core/dependency-check.js +167 -17
- package/dist/core/skill-generator.js +15 -115
- package/dist/utils/shell.d.ts +5 -0
- package/dist/utils/shell.js +14 -5
- package/package.json +1 -1
- package/templates/SKILL.md +23 -19
- package/templates/amend.md +18 -14
- package/templates/brainstorming.md +136 -33
- package/templates/build.md +229 -81
- package/templates/close.md +204 -43
- package/templates/spec.md +192 -36
- package/templates/proposal.md +0 -62
package/dist/cli/init.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
|
-
import { checkDependencies, tryAutoInstall,
|
|
3
|
+
import { checkDependencies, tryAutoInstall, writeState, validateComponentInstallation, validateSuperpowersSkills, printInitPrerequisiteFailures, verifyOpenSpecInitIntegrity, runOpenSpecInit, printIntegrityFailures, } from '../core/dependency-check.js';
|
|
4
4
|
import { generateSkills } from '../core/skill-generator.js';
|
|
5
|
-
import {
|
|
5
|
+
import { DEPS, SUPERPOWERS_REQUIRED_SKILLS, OPENSPEC_INIT_MARKERS } from '../core/constants.js';
|
|
6
|
+
import path from 'path';
|
|
6
7
|
import { logger } from '../utils/logger.js';
|
|
7
|
-
import { exec } from '../utils/shell.js';
|
|
8
|
-
const SUPPORTED_TOOLS = Object.keys(TOOL_PATHS);
|
|
9
8
|
export const initCommand = new Command('init')
|
|
10
9
|
.description('Initialize sddflow skills in the current project')
|
|
11
10
|
.option('-t, --tools <tools>', 'Target tools, comma-separated', 'claude')
|
|
@@ -17,8 +16,8 @@ export const initCommand = new Command('init')
|
|
|
17
16
|
logger.blank();
|
|
18
17
|
logger.info(`sddflow init — ${installGlobally ? 'global skill setup' : 'workflow orchestrator setup'}`);
|
|
19
18
|
logger.blank();
|
|
20
|
-
//
|
|
21
|
-
logger.step('Checking OpenSpec ...');
|
|
19
|
+
// ── 阶段 1:检测 OpenSpec CLI + Superpowers 插件 ──
|
|
20
|
+
logger.step('[1/4] Checking OpenSpec CLI ...');
|
|
22
21
|
let depStatus = checkDependencies({ cwd, tools });
|
|
23
22
|
if (!depStatus.openspec.installed) {
|
|
24
23
|
logger.warn('OpenSpec CLI not installed');
|
|
@@ -26,72 +25,105 @@ export const initCommand = new Command('init')
|
|
|
26
25
|
{
|
|
27
26
|
type: 'confirm',
|
|
28
27
|
name: 'installOpenSpec',
|
|
29
|
-
message: `Auto-install? (
|
|
28
|
+
message: `Auto-install? (${DEPS.openspec.installHint})`,
|
|
30
29
|
default: true,
|
|
31
30
|
},
|
|
32
31
|
]);
|
|
33
32
|
if (installOpenSpec) {
|
|
34
33
|
const ok = tryAutoInstall(DEPS.openspec.npmPkg);
|
|
35
|
-
depStatus = checkDependencies({ cwd, tools });
|
|
34
|
+
depStatus = checkDependencies({ cwd, tools });
|
|
36
35
|
if (ok)
|
|
37
36
|
depStatus.openspec.autoInstalled = true;
|
|
38
37
|
}
|
|
39
|
-
else {
|
|
40
|
-
logger.warn('Skipped OpenSpec install — spec phase will use manual fallback');
|
|
41
|
-
}
|
|
42
38
|
}
|
|
43
39
|
else {
|
|
44
40
|
logger.success(`OpenSpec CLI installed${depStatus.openspec.version ? ` (v${depStatus.openspec.version})` : ''}`);
|
|
45
41
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
logger.warn('Superpowers not installed');
|
|
50
|
-
logger.info(DEPS.superpowers.installHint);
|
|
51
|
-
logger.info('Re-run sddflow init after installing, or build phase will use manual fallback');
|
|
42
|
+
logger.step('[1/4] Checking Superpowers plugin ...');
|
|
43
|
+
if (depStatus.superpowers.pluginInstalled) {
|
|
44
|
+
logger.success('Superpowers plugin installed');
|
|
52
45
|
}
|
|
53
46
|
else {
|
|
54
|
-
logger.
|
|
47
|
+
logger.warn('Superpowers plugin not found');
|
|
48
|
+
}
|
|
49
|
+
const componentFailures = validateComponentInstallation(depStatus, tools);
|
|
50
|
+
if (componentFailures.length > 0) {
|
|
51
|
+
printInitPrerequisiteFailures(componentFailures);
|
|
52
|
+
process.exit(1);
|
|
55
53
|
}
|
|
54
|
+
// ── 阶段 2:检测 Superpowers 必需 skills ──
|
|
55
|
+
logger.step('[2/4] Checking Superpowers required skills ...');
|
|
56
|
+
for (const skill of depStatus.superpowers.skills) {
|
|
57
|
+
if (skill.installed) {
|
|
58
|
+
logger.success(` /${skill.name}${skill.path ? ` (${skill.path})` : ''}`);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
logger.warn(` /${skill.name} — missing`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const skillFailures = validateSuperpowersSkills(depStatus, tools);
|
|
65
|
+
if (skillFailures.length > 0) {
|
|
66
|
+
printInitPrerequisiteFailures(skillFailures);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
// ── 阶段 3:自动执行 openspec init ──
|
|
56
70
|
if (installGlobally) {
|
|
57
|
-
logger.step('Skipping project OpenSpec
|
|
71
|
+
logger.step('[3/4] Skipping project OpenSpec init for global install');
|
|
58
72
|
}
|
|
59
73
|
else {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
logger.step('[3/4] Running openspec init ...');
|
|
75
|
+
let integrity = verifyOpenSpecInitIntegrity(cwd, tools);
|
|
76
|
+
if (integrity.ok) {
|
|
77
|
+
logger.success('OpenSpec already initialized in this project');
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
logger.info(`Running: openspec init --tools ${tools.join(',')}`);
|
|
81
|
+
const ok = runOpenSpecInit(cwd, tools);
|
|
82
|
+
if (!ok) {
|
|
83
|
+
printInitPrerequisiteFailures([
|
|
65
84
|
{
|
|
66
|
-
|
|
67
|
-
name: '
|
|
68
|
-
|
|
69
|
-
|
|
85
|
+
id: 'openspec-init',
|
|
86
|
+
name: 'OpenSpec Init',
|
|
87
|
+
reason: 'openspec init 执行失败',
|
|
88
|
+
installSteps: [
|
|
89
|
+
`请手动执行: openspec init --tools ${tools.join(',')}`,
|
|
90
|
+
`完成后重新运行: sddflow init --tools ${tools.join(',')}`,
|
|
91
|
+
],
|
|
70
92
|
},
|
|
71
93
|
]);
|
|
72
|
-
|
|
73
|
-
const toolsFlag = tools.map((t) => t).join(',');
|
|
74
|
-
exec(`openspec init --tools ${toolsFlag}`, { stdio: 'inherit' });
|
|
75
|
-
logger.success('OpenSpec project initialized');
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
logger.info('OpenSpec not initialized — directories will be auto-created on first /sddflow proposal');
|
|
94
|
+
process.exit(1);
|
|
80
95
|
}
|
|
96
|
+
logger.success('openspec init completed');
|
|
81
97
|
}
|
|
82
|
-
|
|
83
|
-
|
|
98
|
+
// ── 阶段 4:校验 OpenSpec 初始化完整性 ──
|
|
99
|
+
logger.step('[4/4] Verifying OpenSpec init integrity ...');
|
|
100
|
+
integrity = verifyOpenSpecInitIntegrity(cwd, tools);
|
|
101
|
+
if (!integrity.ok) {
|
|
102
|
+
printIntegrityFailures(integrity, tools);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
logger.success('OpenSpec init integrity check passed');
|
|
106
|
+
for (const tool of tools) {
|
|
107
|
+
const markers = OPENSPEC_INIT_MARKERS[tool] ?? [];
|
|
108
|
+
for (const marker of markers) {
|
|
109
|
+
const { fileExists: fe } = await import('../utils/shell.js');
|
|
110
|
+
const fp = path.join(cwd, marker);
|
|
111
|
+
if (fe(fp)) {
|
|
112
|
+
logger.info(` ✓ ${marker}`);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
84
116
|
}
|
|
85
117
|
}
|
|
86
|
-
//
|
|
118
|
+
// ── 生成 sddflow skills ──
|
|
87
119
|
logger.step('Generating sddflow skills ...');
|
|
120
|
+
depStatus = checkDependencies({ cwd, tools });
|
|
88
121
|
generateSkills({ cwd, tools, depStatus, global: installGlobally });
|
|
89
122
|
if (!installGlobally) {
|
|
90
|
-
// Step 5: Write state
|
|
91
123
|
writeState(cwd, {
|
|
92
124
|
openspec: depStatus.openspec.installed,
|
|
93
|
-
superpowers: depStatus.superpowers.
|
|
94
|
-
openspecProjectInitialized:
|
|
125
|
+
superpowers: depStatus.superpowers.allSkillsInstalled,
|
|
126
|
+
openspecProjectInitialized: verifyOpenSpecInitIntegrity(cwd, tools).ok,
|
|
95
127
|
createdAt: new Date().toISOString(),
|
|
96
128
|
tools,
|
|
97
129
|
});
|
|
@@ -99,13 +131,12 @@ export const initCommand = new Command('init')
|
|
|
99
131
|
logger.blank();
|
|
100
132
|
logger.success('sddflow initialized!');
|
|
101
133
|
logger.blank();
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
logger.info(`
|
|
105
|
-
logger.blank();
|
|
134
|
+
logger.info(`Verified Superpowers skills (${SUPERPOWERS_REQUIRED_SKILLS.length}):`);
|
|
135
|
+
for (const skill of SUPERPOWERS_REQUIRED_SKILLS) {
|
|
136
|
+
logger.info(` /${skill}`);
|
|
106
137
|
}
|
|
138
|
+
logger.blank();
|
|
107
139
|
logger.info('Available commands:');
|
|
108
|
-
logger.info(' /sddflow proposal Quick requirement capture');
|
|
109
140
|
logger.info(' /sddflow brainstorming Deep design exploration');
|
|
110
141
|
logger.info(' /sddflow spec Generate specs + translate');
|
|
111
142
|
logger.info(' /sddflow amend Revise requirements before close');
|
package/dist/cli/status.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import fs from 'fs';
|
|
4
|
-
import { checkDependencies, readState,
|
|
4
|
+
import { checkDependencies, readState, verifyOpenSpecInitIntegrity, } from '../core/dependency-check.js';
|
|
5
|
+
import { formatChangeWorkflowStatus, getChangeWorkflowStatus } from '../core/change-status.js';
|
|
5
6
|
import { logger } from '../utils/logger.js';
|
|
6
7
|
import { dirExists } from '../utils/shell.js';
|
|
7
8
|
export const statusCommand = new Command('status')
|
|
@@ -12,7 +13,6 @@ export const statusCommand = new Command('status')
|
|
|
12
13
|
logger.info('sddflow status');
|
|
13
14
|
logger.blank();
|
|
14
15
|
const state = readState(cwd);
|
|
15
|
-
// Dependencies
|
|
16
16
|
logger.step('Dependencies:');
|
|
17
17
|
const depStatus = checkDependencies({ cwd, tools: state?.tools });
|
|
18
18
|
if (depStatus.openspec.installed) {
|
|
@@ -21,14 +21,21 @@ export const statusCommand = new Command('status')
|
|
|
21
21
|
else {
|
|
22
22
|
logger.warn('OpenSpec CLI — not installed');
|
|
23
23
|
}
|
|
24
|
-
if (depStatus.superpowers.
|
|
25
|
-
logger.success(
|
|
24
|
+
if (depStatus.superpowers.pluginInstalled) {
|
|
25
|
+
logger.success('Superpowers plugin');
|
|
26
26
|
}
|
|
27
27
|
else {
|
|
28
|
-
logger.warn('Superpowers — not installed
|
|
28
|
+
logger.warn('Superpowers plugin — not installed');
|
|
29
|
+
}
|
|
30
|
+
for (const skill of depStatus.superpowers.skills) {
|
|
31
|
+
if (skill.installed) {
|
|
32
|
+
logger.success(` /${skill.name}${skill.path ? ` (${skill.path})` : ''}`);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
logger.warn(` /${skill.name} — missing`);
|
|
36
|
+
}
|
|
29
37
|
}
|
|
30
38
|
logger.blank();
|
|
31
|
-
// Project state
|
|
32
39
|
logger.step('Project:');
|
|
33
40
|
if (state) {
|
|
34
41
|
logger.success(`Initialized (${state.tools.join(', ')})`);
|
|
@@ -38,14 +45,17 @@ export const statusCommand = new Command('status')
|
|
|
38
45
|
logger.warn('Not initialized — run sddflow init');
|
|
39
46
|
return;
|
|
40
47
|
}
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
const integrity = verifyOpenSpecInitIntegrity(cwd, state.tools);
|
|
49
|
+
if (integrity.ok) {
|
|
50
|
+
logger.success('OpenSpec project initialized (integrity OK)');
|
|
43
51
|
}
|
|
44
52
|
else {
|
|
45
|
-
logger.warn(
|
|
53
|
+
logger.warn(`OpenSpec init incomplete — missing ${integrity.missing.length} file(s)`);
|
|
54
|
+
for (const file of integrity.missing) {
|
|
55
|
+
logger.info(` - ${file}`);
|
|
56
|
+
}
|
|
46
57
|
}
|
|
47
58
|
logger.blank();
|
|
48
|
-
// Active changes
|
|
49
59
|
logger.step('Active changes:');
|
|
50
60
|
const changesDir = path.join(cwd, 'openspec', 'changes');
|
|
51
61
|
if (!dirExists(changesDir)) {
|
|
@@ -59,20 +69,8 @@ export const statusCommand = new Command('status')
|
|
|
59
69
|
return;
|
|
60
70
|
}
|
|
61
71
|
for (const entry of entries) {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
const hasProposal = fs.existsSync(path.join(changeDir, 'proposal.md'));
|
|
65
|
-
let status = '';
|
|
66
|
-
if (hasPlanReady) {
|
|
67
|
-
status = '→ ready for /sddflow build or /sddflow amend';
|
|
68
|
-
}
|
|
69
|
-
else if (hasProposal) {
|
|
70
|
-
status = '→ needs /sddflow spec';
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
status = '→ needs /sddflow proposal';
|
|
74
|
-
}
|
|
75
|
-
logger.info(` ${entry.name} ${status}`);
|
|
72
|
+
const workflowStatus = getChangeWorkflowStatus(cwd, entry.name);
|
|
73
|
+
logger.info(` ${entry.name} ${formatChangeWorkflowStatus(workflowStatus)}`);
|
|
76
74
|
}
|
|
77
75
|
logger.blank();
|
|
78
76
|
});
|
package/dist/cli/update.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { checkDependencies, readState, writeState,
|
|
2
|
+
import { checkDependencies, readState, writeState, verifyOpenSpecInitIntegrity } from '../core/dependency-check.js';
|
|
3
3
|
import { generateSkills } from '../core/skill-generator.js';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
export const updateCommand = new Command('update')
|
|
@@ -23,8 +23,8 @@ export const updateCommand = new Command('update')
|
|
|
23
23
|
writeState(cwd, {
|
|
24
24
|
...state,
|
|
25
25
|
openspec: depStatus.openspec.installed,
|
|
26
|
-
superpowers: depStatus.superpowers.
|
|
27
|
-
openspecProjectInitialized:
|
|
26
|
+
superpowers: depStatus.superpowers.allSkillsInstalled,
|
|
27
|
+
openspecProjectInitialized: verifyOpenSpecInitIntegrity(cwd, state.tools).ok,
|
|
28
28
|
});
|
|
29
29
|
logger.blank();
|
|
30
30
|
logger.success('Skills updated');
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ChangeWorkflowStatus = 'needs_brainstorming' | 'needs_spec' | 'needs_spec_plan' | 'ready_for_build' | 'build_in_progress' | 'ready_for_close';
|
|
2
|
+
export declare function findPlanFileForChange(cwd: string, changeName: string): string | null;
|
|
3
|
+
export declare function getPlanCheckboxStats(content: string): {
|
|
4
|
+
total: number;
|
|
5
|
+
done: number;
|
|
6
|
+
complete: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function getChangeWorkflowStatus(cwd: string, changeName: string): ChangeWorkflowStatus;
|
|
9
|
+
export declare function formatChangeWorkflowStatus(status: ChangeWorkflowStatus): string;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { dirExists } from '../utils/shell.js';
|
|
4
|
+
const PLANS_DIR = 'docs/superpowers/plans';
|
|
5
|
+
export function findPlanFileForChange(cwd, changeName) {
|
|
6
|
+
const plansDir = path.join(cwd, PLANS_DIR);
|
|
7
|
+
if (!dirExists(plansDir))
|
|
8
|
+
return null;
|
|
9
|
+
const suffix = `-${changeName}.md`;
|
|
10
|
+
const entries = fs.readdirSync(plansDir, { withFileTypes: true }).filter((e) => e.isFile());
|
|
11
|
+
const match = entries.find((e) => e.name.endsWith(suffix) || e.name.includes(changeName));
|
|
12
|
+
return match ? path.join(plansDir, match.name) : null;
|
|
13
|
+
}
|
|
14
|
+
export function getPlanCheckboxStats(content) {
|
|
15
|
+
const checkboxRe = /^-\s+\[([ xX])\]/gm;
|
|
16
|
+
let total = 0;
|
|
17
|
+
let done = 0;
|
|
18
|
+
let m;
|
|
19
|
+
while ((m = checkboxRe.exec(content)) !== null) {
|
|
20
|
+
total += 1;
|
|
21
|
+
if (m[1].toLowerCase() === 'x')
|
|
22
|
+
done += 1;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
total,
|
|
26
|
+
done,
|
|
27
|
+
complete: total > 0 && done === total,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function getChangeWorkflowStatus(cwd, changeName) {
|
|
31
|
+
const changeDir = path.join(cwd, 'openspec', 'changes', changeName);
|
|
32
|
+
const hasProposal = fs.existsSync(path.join(changeDir, 'proposal.md'));
|
|
33
|
+
const hasPlanReady = fs.existsSync(path.join(changeDir, 'plan-ready.md'));
|
|
34
|
+
const planPath = findPlanFileForChange(cwd, changeName);
|
|
35
|
+
if (!hasProposal)
|
|
36
|
+
return 'needs_brainstorming';
|
|
37
|
+
if (!hasPlanReady)
|
|
38
|
+
return 'needs_spec';
|
|
39
|
+
if (!planPath)
|
|
40
|
+
return 'needs_spec_plan';
|
|
41
|
+
const planContent = fs.readFileSync(planPath, 'utf-8');
|
|
42
|
+
const { total, done, complete } = getPlanCheckboxStats(planContent);
|
|
43
|
+
if (total === 0)
|
|
44
|
+
return 'needs_spec_plan';
|
|
45
|
+
if (complete)
|
|
46
|
+
return 'ready_for_close';
|
|
47
|
+
if (done > 0)
|
|
48
|
+
return 'build_in_progress';
|
|
49
|
+
return 'ready_for_build';
|
|
50
|
+
}
|
|
51
|
+
export function formatChangeWorkflowStatus(status) {
|
|
52
|
+
switch (status) {
|
|
53
|
+
case 'needs_brainstorming':
|
|
54
|
+
return '→ needs /sddflow brainstorming';
|
|
55
|
+
case 'needs_spec':
|
|
56
|
+
return '→ needs /sddflow spec';
|
|
57
|
+
case 'needs_spec_plan':
|
|
58
|
+
return '→ needs /sddflow spec (missing plan-ready or docs/superpowers/plans)';
|
|
59
|
+
case 'ready_for_build':
|
|
60
|
+
return '→ ready for /sddflow build';
|
|
61
|
+
case 'build_in_progress':
|
|
62
|
+
return '→ build in progress (/sddflow build to resume)';
|
|
63
|
+
case 'ready_for_close':
|
|
64
|
+
return '→ ready for /sddflow close';
|
|
65
|
+
}
|
|
66
|
+
}
|
package/dist/core/constants.d.ts
CHANGED
|
@@ -12,11 +12,23 @@ export declare const DEPS: {
|
|
|
12
12
|
};
|
|
13
13
|
readonly superpowers: {
|
|
14
14
|
readonly name: "Superpowers";
|
|
15
|
-
readonly
|
|
16
|
-
readonly installHint: "请在当前工具中安装 Superpowers writing-plans skill(Claude Code: /plugin install superpowers@claude-plugins-official)";
|
|
15
|
+
readonly installHint: "请在当前工具中安装 Superpowers 插件";
|
|
17
16
|
readonly autoInstallable: false;
|
|
18
17
|
};
|
|
19
18
|
};
|
|
19
|
+
/** sddflow 工作流依赖的 Superpowers skills */
|
|
20
|
+
export declare const SUPERPOWERS_REQUIRED_SKILLS: readonly ["brainstorming", "writing-plans", "subagent-driven-development", "test-driven-development", "verification-before-completion", "finishing-a-development-branch"];
|
|
21
|
+
export type SuperpowersRequiredSkill = (typeof SUPERPOWERS_REQUIRED_SKILLS)[number];
|
|
22
|
+
/**
|
|
23
|
+
* openspec init 为各工具生成的 skill/command 标记文件。
|
|
24
|
+
* 只要其中任意一个存在,就视为 openspec init 已成功执行过。
|
|
25
|
+
* key = tool name,value = 相对项目根的路径列表(任意一个存在即可)
|
|
26
|
+
*/
|
|
27
|
+
export declare const OPENSPEC_INIT_MARKERS: Record<string, string[]>;
|
|
28
|
+
/** 各工具安装 Superpowers 的具体指引 */
|
|
29
|
+
export declare const SUPERPOWERS_INSTALL_HINTS: Record<string, string[]>;
|
|
30
|
+
/** 各工具 Superpowers 插件缓存目录 */
|
|
31
|
+
export declare const SUPERPOWERS_PLUGIN_CACHE_DIRS: Record<string, string>;
|
|
20
32
|
export declare const TOOL_PATHS: Record<string, {
|
|
21
33
|
skillsDir: string;
|
|
22
34
|
commandsDir?: string;
|
package/dist/core/constants.js
CHANGED
|
@@ -12,11 +12,69 @@ export const DEPS = {
|
|
|
12
12
|
},
|
|
13
13
|
superpowers: {
|
|
14
14
|
name: 'Superpowers',
|
|
15
|
-
|
|
16
|
-
installHint: '请在当前工具中安装 Superpowers writing-plans skill(Claude Code: /plugin install superpowers@claude-plugins-official)',
|
|
15
|
+
installHint: '请在当前工具中安装 Superpowers 插件',
|
|
17
16
|
autoInstallable: false,
|
|
18
17
|
},
|
|
19
18
|
};
|
|
19
|
+
/** sddflow 工作流依赖的 Superpowers skills */
|
|
20
|
+
export const SUPERPOWERS_REQUIRED_SKILLS = [
|
|
21
|
+
'brainstorming',
|
|
22
|
+
'writing-plans',
|
|
23
|
+
'subagent-driven-development',
|
|
24
|
+
'test-driven-development',
|
|
25
|
+
'verification-before-completion',
|
|
26
|
+
'finishing-a-development-branch',
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* openspec init 为各工具生成的 skill/command 标记文件。
|
|
30
|
+
* 只要其中任意一个存在,就视为 openspec init 已成功执行过。
|
|
31
|
+
* key = tool name,value = 相对项目根的路径列表(任意一个存在即可)
|
|
32
|
+
*/
|
|
33
|
+
export const OPENSPEC_INIT_MARKERS = {
|
|
34
|
+
claude: [
|
|
35
|
+
'.claude/skills/openspec-propose/SKILL.md',
|
|
36
|
+
'.claude/commands/opsx/propose.md',
|
|
37
|
+
'.claude/commands/openspec/proposal.md',
|
|
38
|
+
'.claude/commands/openspec/archive.md',
|
|
39
|
+
],
|
|
40
|
+
cursor: [
|
|
41
|
+
'.cursor/skills/openspec-propose/SKILL.md',
|
|
42
|
+
'.cursor/commands/opsx/propose.md',
|
|
43
|
+
'.cursor/commands/openspec/proposal.md',
|
|
44
|
+
'.cursor/commands/openspec/archive.md',
|
|
45
|
+
],
|
|
46
|
+
codex: [
|
|
47
|
+
'.codex/skills/openspec-propose/SKILL.md',
|
|
48
|
+
'.codex/commands/opsx/propose.md',
|
|
49
|
+
'.codex/commands/openspec/proposal.md',
|
|
50
|
+
'.codex/commands/openspec/archive.md',
|
|
51
|
+
],
|
|
52
|
+
opencode: [
|
|
53
|
+
'.opencode/commands/opsx/propose.md',
|
|
54
|
+
'.opencode/commands/openspec/proposal.md',
|
|
55
|
+
'.opencode/commands/openspec/archive.md',
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
/** 各工具安装 Superpowers 的具体指引 */
|
|
59
|
+
export const SUPERPOWERS_INSTALL_HINTS = {
|
|
60
|
+
claude: [
|
|
61
|
+
'在 Claude Code 中执行: /plugin install superpowers@claude-plugins-official',
|
|
62
|
+
],
|
|
63
|
+
cursor: [
|
|
64
|
+
'在 Cursor 中安装 Superpowers 插件(Settings → Plugins → superpowers)',
|
|
65
|
+
],
|
|
66
|
+
codex: [
|
|
67
|
+
'在 Codex 中安装 Superpowers 插件',
|
|
68
|
+
],
|
|
69
|
+
opencode: [
|
|
70
|
+
'在 OpenCode 中安装 Superpowers 插件',
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
/** 各工具 Superpowers 插件缓存目录 */
|
|
74
|
+
export const SUPERPOWERS_PLUGIN_CACHE_DIRS = {
|
|
75
|
+
claude: '.claude/plugins/cache/claude-plugins-official/superpowers',
|
|
76
|
+
cursor: '.cursor/plugins/cache/cursor-public/superpowers',
|
|
77
|
+
};
|
|
20
78
|
export const TOOL_PATHS = {
|
|
21
79
|
claude: {
|
|
22
80
|
skillsDir: '.claude/skills',
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { type SuperpowersRequiredSkill } from './constants.js';
|
|
2
|
+
export interface SuperpowersSkillStatus {
|
|
3
|
+
name: SuperpowersRequiredSkill;
|
|
4
|
+
installed: boolean;
|
|
5
|
+
path?: string;
|
|
6
|
+
}
|
|
1
7
|
export interface DepStatus {
|
|
2
8
|
openspec: {
|
|
3
9
|
installed: boolean;
|
|
@@ -5,17 +11,37 @@ export interface DepStatus {
|
|
|
5
11
|
autoInstalled?: boolean;
|
|
6
12
|
};
|
|
7
13
|
superpowers: {
|
|
14
|
+
pluginInstalled: boolean;
|
|
15
|
+
skills: SuperpowersSkillStatus[];
|
|
16
|
+
allSkillsInstalled: boolean;
|
|
17
|
+
/** 兼容旧字段:等同 allSkillsInstalled */
|
|
8
18
|
installed: boolean;
|
|
9
|
-
hint?: string;
|
|
10
|
-
path?: string;
|
|
11
|
-
checkedPaths: string[];
|
|
12
19
|
};
|
|
13
20
|
}
|
|
21
|
+
export interface InitPrerequisiteFailure {
|
|
22
|
+
id: 'openspec-cli' | 'superpowers-plugin' | 'superpowers-skills' | 'openspec-init';
|
|
23
|
+
name: string;
|
|
24
|
+
reason: string;
|
|
25
|
+
installSteps: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface IntegrityCheckResult {
|
|
28
|
+
ok: boolean;
|
|
29
|
+
missing: string[];
|
|
30
|
+
}
|
|
14
31
|
export interface CheckDependencyOptions {
|
|
15
32
|
cwd?: string;
|
|
16
33
|
tools?: string[];
|
|
17
34
|
}
|
|
18
35
|
export declare function checkDependencies(options?: CheckDependencyOptions): DepStatus;
|
|
36
|
+
export declare function checkSuperpowersSkills(cwd: string, home: string, tools: string[]): SuperpowersSkillStatus[];
|
|
37
|
+
/** 阶段 1:检测 OpenSpec CLI + Superpowers 插件是否已安装 */
|
|
38
|
+
export declare function validateComponentInstallation(depStatus: DepStatus, tools: string[]): InitPrerequisiteFailure[];
|
|
39
|
+
/** 阶段 2:检测 Superpowers 必需 skills 是否齐全 */
|
|
40
|
+
export declare function validateSuperpowersSkills(depStatus: DepStatus, tools: string[]): InitPrerequisiteFailure[];
|
|
41
|
+
export declare function verifyOpenSpecInitIntegrity(cwd: string, tools: string[]): IntegrityCheckResult;
|
|
42
|
+
export declare function runOpenSpecInit(cwd: string, tools: string[]): boolean;
|
|
43
|
+
export declare function printInitPrerequisiteFailures(failures: InitPrerequisiteFailure[], title?: string): void;
|
|
44
|
+
export declare function printIntegrityFailures(result: IntegrityCheckResult, tools: string[]): void;
|
|
19
45
|
export declare function tryAutoInstall(pkg: string): boolean;
|
|
20
46
|
export declare function checkOpenSpecInitialized(cwd: string): boolean;
|
|
21
47
|
export interface InitState {
|