@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/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, checkOpenSpecInitialized, writeState } from '../core/dependency-check.js';
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 { TOOL_PATHS, DEPS } from '../core/constants.js';
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
- // Step 1: Check OpenSpec
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? (npm install -g ${DEPS.openspec.npmPkg}@latest)`,
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 }); // recheck
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
- // Step 2: Check Superpowers
47
- logger.step('Checking Superpowers ...');
48
- if (!depStatus.superpowers.installed) {
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.success(`Superpowers installed${depStatus.superpowers.path ? ` (${depStatus.superpowers.path})` : ''}`);
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 initialization for global install');
71
+ logger.step('[3/4] Skipping project OpenSpec init for global install');
58
72
  }
59
73
  else {
60
- // Step 3: Check if OpenSpec is initialized in project
61
- logger.step('Checking project OpenSpec initialization ...');
62
- if (!checkOpenSpecInitialized(cwd)) {
63
- if (depStatus.openspec.installed) {
64
- const { initOpenSpec } = await inquirer.prompt([
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
- type: 'confirm',
67
- name: 'initOpenSpec',
68
- message: 'OpenSpec not initialized in this project. Run openspec init?',
69
- default: true,
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
- if (initOpenSpec) {
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
- else {
83
- logger.success('OpenSpec project initialized');
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
- // Step 4: Generate skills
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.installed,
94
- openspecProjectInitialized: checkOpenSpecInitialized(cwd),
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
- if (!depStatus.superpowers.installed) {
103
- logger.warn('Note: Superpowers not installed — /sddflow build will use manual execution mode');
104
- logger.info(` Install with: ${DEPS.superpowers.installHint}`);
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');
@@ -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, checkOpenSpecInitialized } from '../core/dependency-check.js';
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.installed) {
25
- logger.success(`Superpowers${depStatus.superpowers.path ? ` (${depStatus.superpowers.path})` : ''}`);
24
+ if (depStatus.superpowers.pluginInstalled) {
25
+ logger.success('Superpowers plugin');
26
26
  }
27
27
  else {
28
- logger.warn('Superpowers — not installed (build phase will use manual mode)');
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
- if (checkOpenSpecInitialized(cwd)) {
42
- logger.success('OpenSpec project initialized');
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('OpenSpec project not initialized');
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 changeDir = path.join(changesDir, entry.name);
63
- const hasPlanReady = fs.existsSync(path.join(changeDir, 'plan-ready.md'));
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
  });
@@ -1,5 +1,5 @@
1
1
  import { Command } from 'commander';
2
- import { checkDependencies, readState, writeState, checkOpenSpecInitialized } from '../core/dependency-check.js';
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.installed,
27
- openspecProjectInitialized: checkOpenSpecInitialized(cwd),
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
+ }
@@ -12,11 +12,23 @@ export declare const DEPS: {
12
12
  };
13
13
  readonly superpowers: {
14
14
  readonly name: "Superpowers";
15
- readonly checkPath: "writing-plans/SKILL.md";
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;
@@ -12,11 +12,69 @@ export const DEPS = {
12
12
  },
13
13
  superpowers: {
14
14
  name: 'Superpowers',
15
- checkPath: 'writing-plans/SKILL.md',
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 {