mspec-cli 4.0.2__tar.gz → 4.0.5__tar.gz
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.
- {mspec_cli-4.0.2/src/mspec_cli.egg-info → mspec_cli-4.0.5}/PKG-INFO +24 -3
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/README.md +23 -2
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/pyproject.toml +1 -1
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/commands/doctor.py +23 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/commands/init.py +59 -18
- mspec_cli-4.0.5/src/mspec/core/openspec_manager.py +232 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5/src/mspec_cli.egg-info}/PKG-INFO +24 -3
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec_cli.egg-info/SOURCES.txt +1 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/LICENSE +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/MANIFEST.in +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/setup.cfg +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/__init__.py +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/__main__.py +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/cli.py +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/commands/__init__.py +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/commands/update.py +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/core/__init__.py +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/core/config.py +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/core/template.py +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/templates/config.yaml +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/templates/design-issue-taxonomy.md +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/templates/design-issues.md +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/templates/requirement-issue-taxonomy.md +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/templates/requirement-issues.md +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/utils/__init__.py +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec/utils/console.py +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec_cli.egg-info/dependency_links.txt +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec_cli.egg-info/entry_points.txt +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec_cli.egg-info/requires.txt +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/src/mspec_cli.egg-info/top_level.txt +0 -0
- {mspec_cli-4.0.2 → mspec_cli-4.0.5}/tests/test_init.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mspec-cli
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.5
|
|
4
4
|
Summary: mspec-cli - 成员规范驱动开发工作流 CLI 工具
|
|
5
5
|
Author-email: shirayner <team@mspec.io>
|
|
6
6
|
License: MIT
|
|
@@ -57,8 +57,29 @@ Dynamic: license-file
|
|
|
57
57
|
|
|
58
58
|
## 文档
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
📚 **[完整文档 →](docs/)**
|
|
61
|
+
|
|
62
|
+
### 新手入门
|
|
63
|
+
- [📖 安装指南](docs/getting-started/installation.md) - 系统要求与安装步骤
|
|
64
|
+
- [⚡ 5分钟快速开始](docs/getting-started/quickstart.md) - 体验完整流程
|
|
65
|
+
- [🎯 第一个完整变更](docs/getting-started/first-change.md) - 从零到交付的详细教程
|
|
66
|
+
|
|
67
|
+
### 完整指南
|
|
68
|
+
- [💡 核心概念](docs/guide/concepts.md) - Change、Capability、问题分类学
|
|
69
|
+
- [🔧 CLI 命令详解](docs/guide/cli-commands.md) - init、update、doctor
|
|
70
|
+
- [📋 工作流详解](docs/guide/) - 探索 → 澄清 → 提案 → 设计 → 实施 → 归档
|
|
71
|
+
|
|
72
|
+
### 实战教程
|
|
73
|
+
- [🛠️ Todo 应用开发](docs/tutorial/todo-app/) - 从零开发完整项目
|
|
74
|
+
|
|
75
|
+
### 参考手册
|
|
76
|
+
- [📖 CLI 命令速查](docs/reference/cli-reference.md)
|
|
77
|
+
- [⚙️ 配置参考](docs/reference/config-reference.md)
|
|
78
|
+
- [🗂️ 问题分类学参考](docs/reference/taxonomy-reference.md)
|
|
79
|
+
|
|
80
|
+
### 其他
|
|
81
|
+
- [❓ 常见问题 (FAQ)](docs/faq.md)
|
|
82
|
+
- [🐛 故障排除](docs/troubleshooting.md)
|
|
62
83
|
|
|
63
84
|
## 快速开始
|
|
64
85
|
|
|
@@ -18,8 +18,29 @@
|
|
|
18
18
|
|
|
19
19
|
## 文档
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
📚 **[完整文档 →](docs/)**
|
|
22
|
+
|
|
23
|
+
### 新手入门
|
|
24
|
+
- [📖 安装指南](docs/getting-started/installation.md) - 系统要求与安装步骤
|
|
25
|
+
- [⚡ 5分钟快速开始](docs/getting-started/quickstart.md) - 体验完整流程
|
|
26
|
+
- [🎯 第一个完整变更](docs/getting-started/first-change.md) - 从零到交付的详细教程
|
|
27
|
+
|
|
28
|
+
### 完整指南
|
|
29
|
+
- [💡 核心概念](docs/guide/concepts.md) - Change、Capability、问题分类学
|
|
30
|
+
- [🔧 CLI 命令详解](docs/guide/cli-commands.md) - init、update、doctor
|
|
31
|
+
- [📋 工作流详解](docs/guide/) - 探索 → 澄清 → 提案 → 设计 → 实施 → 归档
|
|
32
|
+
|
|
33
|
+
### 实战教程
|
|
34
|
+
- [🛠️ Todo 应用开发](docs/tutorial/todo-app/) - 从零开发完整项目
|
|
35
|
+
|
|
36
|
+
### 参考手册
|
|
37
|
+
- [📖 CLI 命令速查](docs/reference/cli-reference.md)
|
|
38
|
+
- [⚙️ 配置参考](docs/reference/config-reference.md)
|
|
39
|
+
- [🗂️ 问题分类学参考](docs/reference/taxonomy-reference.md)
|
|
40
|
+
|
|
41
|
+
### 其他
|
|
42
|
+
- [❓ 常见问题 (FAQ)](docs/faq.md)
|
|
43
|
+
- [🐛 故障排除](docs/troubleshooting.md)
|
|
23
44
|
|
|
24
45
|
## 快速开始
|
|
25
46
|
|
|
@@ -9,6 +9,7 @@ import click
|
|
|
9
9
|
from rich.console import Console
|
|
10
10
|
from rich.table import Table
|
|
11
11
|
|
|
12
|
+
from mspec.core.openspec_manager import OpenspecManager, OpenspecStatus
|
|
12
13
|
from mspec.utils.console import print_error, print_success, print_warning
|
|
13
14
|
|
|
14
15
|
console = Console()
|
|
@@ -27,6 +28,7 @@ def doctor_cmd() -> None:
|
|
|
27
28
|
|
|
28
29
|
checks = [
|
|
29
30
|
("Python 版本", _check_python_version),
|
|
31
|
+
("openspec CLI", _check_openspec_cli),
|
|
30
32
|
("openspec/ 目录", _check_openspec_dir),
|
|
31
33
|
("config.yaml", _check_config_file),
|
|
32
34
|
("模板文件", _check_template_files),
|
|
@@ -83,6 +85,27 @@ def _check_python_version() -> dict:
|
|
|
83
85
|
return {"ok": True, "message": f"{sys.version.split()[0]}"}
|
|
84
86
|
|
|
85
87
|
|
|
88
|
+
def _check_openspec_cli() -> dict:
|
|
89
|
+
"""检查 openspec CLI 是否安装"""
|
|
90
|
+
manager = OpenspecManager()
|
|
91
|
+
status = manager.check()
|
|
92
|
+
|
|
93
|
+
if status == OpenspecStatus.INSTALLED:
|
|
94
|
+
version = manager.get_version()
|
|
95
|
+
version_str = f" ({version})" if version else ""
|
|
96
|
+
return {"ok": True, "message": f"已安装{version_str}"}
|
|
97
|
+
elif status == OpenspecStatus.NPX_AVAILABLE:
|
|
98
|
+
return {
|
|
99
|
+
"ok": True,
|
|
100
|
+
"message": "未全局安装,但可通过 npx 运行",
|
|
101
|
+
}
|
|
102
|
+
else:
|
|
103
|
+
return {
|
|
104
|
+
"ok": False,
|
|
105
|
+
"message": "未安装。运行 `npm install -g @fission-ai/openspec` 安装",
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
86
109
|
def _check_openspec_dir() -> dict:
|
|
87
110
|
"""检查 openspec 目录"""
|
|
88
111
|
if not Path("openspec").exists():
|
|
@@ -12,6 +12,7 @@ from rich.panel import Panel
|
|
|
12
12
|
from rich.table import Table
|
|
13
13
|
|
|
14
14
|
from mspec.core.config import ConfigManager
|
|
15
|
+
from mspec.core.openspec_manager import OpenspecManager, OpenspecStatus
|
|
15
16
|
from mspec.core.template import TemplateManager
|
|
16
17
|
from mspec.utils.console import print_error, print_success
|
|
17
18
|
|
|
@@ -117,27 +118,67 @@ def init_cmd(
|
|
|
117
118
|
console.print(f" [red]• {error}[/red]")
|
|
118
119
|
|
|
119
120
|
|
|
120
|
-
def _run_openspec_init(target_path: Path) ->
|
|
121
|
-
"""调用 openspec init 初始化 OpenSpec 目录结构
|
|
122
|
-
|
|
121
|
+
def _run_openspec_init(target_path: Path) -> bool:
|
|
122
|
+
"""调用 openspec init 初始化 OpenSpec 目录结构
|
|
123
|
+
|
|
124
|
+
支持自动检测 openspec,如未安装则尝试使用 npx 或自动安装
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
target_path: 目标目录路径
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
bool: 是否成功调用 openspec init
|
|
131
|
+
"""
|
|
132
|
+
manager = OpenspecManager()
|
|
133
|
+
|
|
134
|
+
# 1. 检查当前状态
|
|
135
|
+
status = manager.check()
|
|
136
|
+
|
|
137
|
+
if status == OpenspecStatus.INSTALLED:
|
|
138
|
+
console.print("[dim]检测到 openspec 已安装[/dim]")
|
|
139
|
+
elif status == OpenspecStatus.NPX_AVAILABLE:
|
|
140
|
+
console.print("[dim]openspec 未全局安装,将使用 npx 运行[/dim]")
|
|
141
|
+
else:
|
|
142
|
+
# 检查 npm 是否安装
|
|
143
|
+
import shutil
|
|
144
|
+
|
|
145
|
+
if not shutil.which("npm"):
|
|
146
|
+
manager.print_npm_not_found_guide()
|
|
147
|
+
# 询问是否继续(不使用 openspec)
|
|
148
|
+
continue_anyway = questionary.confirm(
|
|
149
|
+
"是否继续初始化(跳过 openspec)?", default=True
|
|
150
|
+
).ask()
|
|
151
|
+
return continue_anyway
|
|
152
|
+
|
|
153
|
+
console.print("[yellow]openspec 未安装,正在尝试自动安装...[/yellow]")
|
|
154
|
+
if manager.install():
|
|
155
|
+
# 重新检测
|
|
156
|
+
status = manager.check()
|
|
157
|
+
else:
|
|
158
|
+
# 安装失败,打印指引
|
|
159
|
+
manager.print_install_guide()
|
|
160
|
+
# 询问是否继续(不使用 openspec)
|
|
161
|
+
continue_anyway = questionary.confirm(
|
|
162
|
+
"是否继续初始化(跳过 openspec)?", default=True
|
|
163
|
+
).ask()
|
|
164
|
+
return continue_anyway
|
|
165
|
+
|
|
166
|
+
# 2. 执行 openspec init
|
|
167
|
+
console.print("[dim]正在调用 openspec init...[/dim]")
|
|
123
168
|
try:
|
|
124
|
-
result =
|
|
125
|
-
["openspec", "init"],
|
|
126
|
-
cwd=str(target_path),
|
|
127
|
-
capture_output=True,
|
|
128
|
-
text=True,
|
|
129
|
-
)
|
|
169
|
+
result = manager.run(["init"], cwd=target_path)
|
|
130
170
|
if result.returncode == 0:
|
|
131
|
-
console.print("[
|
|
171
|
+
console.print("[green]✓ openspec init 完成[/green]")
|
|
172
|
+
return True
|
|
132
173
|
else:
|
|
133
|
-
|
|
134
|
-
f"[yellow]⚠ openspec init
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
174
|
+
if result.stderr:
|
|
175
|
+
console.print(f"[yellow]⚠ openspec init 返回警告: {result.stderr}[/yellow]")
|
|
176
|
+
else:
|
|
177
|
+
console.print("[yellow]⚠ openspec init 返回非零退出码,继续执行...[/yellow]")
|
|
178
|
+
return True # 仍视为成功,继续执行
|
|
179
|
+
except Exception as e:
|
|
180
|
+
console.print(f"[yellow]⚠ openspec init 执行异常: {e}[/yellow]")
|
|
181
|
+
return True # 仍视为成功,继续执行
|
|
141
182
|
|
|
142
183
|
|
|
143
184
|
def _show_dry_run(files: dict, target_path: Path) -> None:
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""openspec 管理模块
|
|
3
|
+
|
|
4
|
+
负责检测、安装和调用 openspec
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import platform
|
|
8
|
+
import shutil
|
|
9
|
+
import subprocess
|
|
10
|
+
from enum import Enum
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import List, Optional
|
|
13
|
+
|
|
14
|
+
from rich.console import Console
|
|
15
|
+
|
|
16
|
+
console = Console()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class OpenspecStatus(Enum):
|
|
20
|
+
"""openspec 状态"""
|
|
21
|
+
|
|
22
|
+
INSTALLED = "installed" # 已全局安装
|
|
23
|
+
NPX_AVAILABLE = "npx" # 可通过 npx 运行
|
|
24
|
+
NOT_FOUND = "not_found" # 未安装且无法自动安装
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class OpenspecManager:
|
|
28
|
+
"""openspec 管理器
|
|
29
|
+
|
|
30
|
+
负责检测、安装和调用 openspec
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
PACKAGE_NAME = "@fission-ai/openspec"
|
|
34
|
+
|
|
35
|
+
def __init__(self):
|
|
36
|
+
self._status: Optional[OpenspecStatus] = None
|
|
37
|
+
|
|
38
|
+
def check(self) -> OpenspecStatus:
|
|
39
|
+
"""检查 openspec 可用状态
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
OpenspecStatus: 当前状态
|
|
43
|
+
"""
|
|
44
|
+
if self._status is not None:
|
|
45
|
+
return self._status
|
|
46
|
+
|
|
47
|
+
# 1. 检查全局安装
|
|
48
|
+
# Windows 上优先检查 openspec.cmd,因为 npm 会安装 openspec.cmd
|
|
49
|
+
if self._is_windows():
|
|
50
|
+
if shutil.which("openspec.cmd") or shutil.which("openspec"):
|
|
51
|
+
self._status = OpenspecStatus.INSTALLED
|
|
52
|
+
return self._status
|
|
53
|
+
else:
|
|
54
|
+
if shutil.which("openspec"):
|
|
55
|
+
self._status = OpenspecStatus.INSTALLED
|
|
56
|
+
return self._status
|
|
57
|
+
|
|
58
|
+
# 2. 检查 npx 是否可用
|
|
59
|
+
if shutil.which("npx"):
|
|
60
|
+
self._status = OpenspecStatus.NPX_AVAILABLE
|
|
61
|
+
return self._status
|
|
62
|
+
|
|
63
|
+
self._status = OpenspecStatus.NOT_FOUND
|
|
64
|
+
return self._status
|
|
65
|
+
|
|
66
|
+
def _is_windows(self) -> bool:
|
|
67
|
+
"""检查是否为 Windows 系统"""
|
|
68
|
+
return platform.system() == "Windows"
|
|
69
|
+
|
|
70
|
+
def is_available(self) -> bool:
|
|
71
|
+
"""检查是否可用(已安装或可通过 npx 运行)"""
|
|
72
|
+
return self.check() != OpenspecStatus.NOT_FOUND
|
|
73
|
+
|
|
74
|
+
def _get_openspec_cmd(self) -> List[str]:
|
|
75
|
+
"""获取正确的 openspec 命令
|
|
76
|
+
|
|
77
|
+
在 Windows 上,npm 会安装三个文件:
|
|
78
|
+
- openspec (无扩展名的 shell script,Unix 兼容)
|
|
79
|
+
- openspec.cmd (Windows batch 文件)
|
|
80
|
+
- openspec.ps1 (PowerShell 脚本)
|
|
81
|
+
|
|
82
|
+
Windows 无法直接执行无扩展名的 shell script,
|
|
83
|
+
所以需要优先使用 .cmd 版本。
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
List[str]: 命令列表,如 ["openspec"] 或 ["openspec.cmd"]
|
|
87
|
+
"""
|
|
88
|
+
# Windows 优先使用 openspec.cmd
|
|
89
|
+
if self._is_windows():
|
|
90
|
+
# 先尝试直接找 openspec.cmd
|
|
91
|
+
cmd_path = shutil.which("openspec.cmd")
|
|
92
|
+
if cmd_path:
|
|
93
|
+
return [cmd_path]
|
|
94
|
+
|
|
95
|
+
# 如果没找到,但找到了 openspec(无扩展名),
|
|
96
|
+
# 尝试在同一目录下找 openspec.cmd
|
|
97
|
+
openspec_path = shutil.which("openspec")
|
|
98
|
+
if openspec_path:
|
|
99
|
+
# 构建 openspec.cmd 的完整路径
|
|
100
|
+
base_path = openspec_path.replace("/openspec", "/openspec.cmd")
|
|
101
|
+
base_path = base_path.replace("\\openspec", "\\openspec.cmd")
|
|
102
|
+
if Path(base_path).exists():
|
|
103
|
+
return [base_path]
|
|
104
|
+
|
|
105
|
+
# 非 Windows 或找不到 .cmd,使用默认命令
|
|
106
|
+
openspec_path = shutil.which("openspec")
|
|
107
|
+
if openspec_path:
|
|
108
|
+
return [openspec_path]
|
|
109
|
+
|
|
110
|
+
return ["openspec"]
|
|
111
|
+
|
|
112
|
+
def run(self, args: list, cwd: Optional[Path] = None) -> subprocess.CompletedProcess:
|
|
113
|
+
"""运行 openspec 命令
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
args: 命令参数
|
|
117
|
+
cwd: 工作目录
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
subprocess.CompletedProcess: 执行结果
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
RuntimeError: 当 openspec 不可用时
|
|
124
|
+
"""
|
|
125
|
+
status = self.check()
|
|
126
|
+
|
|
127
|
+
if status == OpenspecStatus.INSTALLED:
|
|
128
|
+
cmd = self._get_openspec_cmd() + args
|
|
129
|
+
elif status == OpenspecStatus.NPX_AVAILABLE:
|
|
130
|
+
cmd = ["npx", self.PACKAGE_NAME] + args
|
|
131
|
+
else:
|
|
132
|
+
raise RuntimeError("openspec 不可用")
|
|
133
|
+
|
|
134
|
+
return subprocess.run(
|
|
135
|
+
cmd,
|
|
136
|
+
cwd=str(cwd) if cwd else None,
|
|
137
|
+
capture_output=True,
|
|
138
|
+
text=True,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
def install(self, global_install: bool = True) -> bool:
|
|
142
|
+
"""安装 openspec
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
global_install: 是否全局安装
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
bool: 是否安装成功
|
|
149
|
+
"""
|
|
150
|
+
if not shutil.which("npm"):
|
|
151
|
+
console.print("[red]✗ npm 未安装,无法自动安装 openspec[/red]")
|
|
152
|
+
return False
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
cmd = ["npm", "install"]
|
|
156
|
+
if global_install:
|
|
157
|
+
cmd.append("-g")
|
|
158
|
+
cmd.append(self.PACKAGE_NAME)
|
|
159
|
+
|
|
160
|
+
console.print(f"[dim]正在执行: {' '.join(cmd)}[/dim]")
|
|
161
|
+
|
|
162
|
+
result = subprocess.run(
|
|
163
|
+
cmd,
|
|
164
|
+
capture_output=True,
|
|
165
|
+
text=True,
|
|
166
|
+
timeout=180, # 3分钟超时
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
if result.returncode == 0:
|
|
170
|
+
# 清除缓存,重新检测
|
|
171
|
+
self._status = None
|
|
172
|
+
console.print("[green]✓ openspec 安装成功[/green]")
|
|
173
|
+
return True
|
|
174
|
+
else:
|
|
175
|
+
# 检查是否是权限问题
|
|
176
|
+
if "EACCES" in result.stderr or "permission" in result.stderr.lower():
|
|
177
|
+
console.print("[yellow]⚠ 权限不足,无法全局安装[/yellow]")
|
|
178
|
+
else:
|
|
179
|
+
console.print(f"[red]✗ 安装失败: {result.stderr}[/red]")
|
|
180
|
+
return False
|
|
181
|
+
|
|
182
|
+
except subprocess.TimeoutExpired:
|
|
183
|
+
console.print("[red]✗ 安装超时[/red]")
|
|
184
|
+
return False
|
|
185
|
+
except Exception as e:
|
|
186
|
+
console.print(f"[red]✗ 安装出错: {e}[/red]")
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
def print_install_guide(self):
|
|
190
|
+
"""打印安装指引"""
|
|
191
|
+
console.print("\n[bold yellow]⚠ openspec 未安装[/bold yellow]")
|
|
192
|
+
console.print("\n请执行以下命令安装:")
|
|
193
|
+
console.print(f" [cyan]npm install -g {self.PACKAGE_NAME}[/cyan]")
|
|
194
|
+
console.print("\n[dim]如果权限不足,请尝试:[/dim]")
|
|
195
|
+
console.print(f" [cyan]sudo npm install -g {self.PACKAGE_NAME}[/cyan]")
|
|
196
|
+
console.print("\n或使用 npx(无需安装):")
|
|
197
|
+
console.print(f" [cyan]npx {self.PACKAGE_NAME} init[/cyan]")
|
|
198
|
+
|
|
199
|
+
def print_npm_not_found_guide(self):
|
|
200
|
+
"""打印 npm 未安装的指引"""
|
|
201
|
+
console.print("\n[bold red]✗ npm 未安装[/bold red]")
|
|
202
|
+
console.print("\n[yellow]openspec 需要 Node.js 环境,请安装 Node.js:[/yellow]")
|
|
203
|
+
console.print(" https://nodejs.org/")
|
|
204
|
+
console.print("\n[dim]安装后请重新运行 mspec init[/dim]")
|
|
205
|
+
|
|
206
|
+
def print_permission_guide(self):
|
|
207
|
+
"""打印权限问题的解决指引"""
|
|
208
|
+
console.print("\n[yellow]⚠ npm 全局安装权限不足[/yellow]")
|
|
209
|
+
console.print("\n解决方案 1 - 使用 npx(推荐,无需安装):")
|
|
210
|
+
console.print(f" [cyan]npx {self.PACKAGE_NAME} init[/cyan]")
|
|
211
|
+
console.print("\n解决方案 2 - 修改 npm 权限:")
|
|
212
|
+
console.print(" https://docs.npmjs.com/resolving-eacces-permissions-errors")
|
|
213
|
+
console.print("\n解决方案 3 - 使用 sudo:")
|
|
214
|
+
console.print(f" [cyan]sudo npm install -g {self.PACKAGE_NAME}[/cyan]")
|
|
215
|
+
|
|
216
|
+
def get_version(self) -> Optional[str]:
|
|
217
|
+
"""获取 openspec 版本
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
Optional[str]: 版本号,如果未安装则返回 None
|
|
221
|
+
"""
|
|
222
|
+
if not self.is_available():
|
|
223
|
+
return None
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
result = self.run(["--version"])
|
|
227
|
+
if result.returncode == 0:
|
|
228
|
+
return result.stdout.strip()
|
|
229
|
+
except Exception:
|
|
230
|
+
pass
|
|
231
|
+
|
|
232
|
+
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mspec-cli
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.5
|
|
4
4
|
Summary: mspec-cli - 成员规范驱动开发工作流 CLI 工具
|
|
5
5
|
Author-email: shirayner <team@mspec.io>
|
|
6
6
|
License: MIT
|
|
@@ -57,8 +57,29 @@ Dynamic: license-file
|
|
|
57
57
|
|
|
58
58
|
## 文档
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
📚 **[完整文档 →](docs/)**
|
|
61
|
+
|
|
62
|
+
### 新手入门
|
|
63
|
+
- [📖 安装指南](docs/getting-started/installation.md) - 系统要求与安装步骤
|
|
64
|
+
- [⚡ 5分钟快速开始](docs/getting-started/quickstart.md) - 体验完整流程
|
|
65
|
+
- [🎯 第一个完整变更](docs/getting-started/first-change.md) - 从零到交付的详细教程
|
|
66
|
+
|
|
67
|
+
### 完整指南
|
|
68
|
+
- [💡 核心概念](docs/guide/concepts.md) - Change、Capability、问题分类学
|
|
69
|
+
- [🔧 CLI 命令详解](docs/guide/cli-commands.md) - init、update、doctor
|
|
70
|
+
- [📋 工作流详解](docs/guide/) - 探索 → 澄清 → 提案 → 设计 → 实施 → 归档
|
|
71
|
+
|
|
72
|
+
### 实战教程
|
|
73
|
+
- [🛠️ Todo 应用开发](docs/tutorial/todo-app/) - 从零开发完整项目
|
|
74
|
+
|
|
75
|
+
### 参考手册
|
|
76
|
+
- [📖 CLI 命令速查](docs/reference/cli-reference.md)
|
|
77
|
+
- [⚙️ 配置参考](docs/reference/config-reference.md)
|
|
78
|
+
- [🗂️ 问题分类学参考](docs/reference/taxonomy-reference.md)
|
|
79
|
+
|
|
80
|
+
### 其他
|
|
81
|
+
- [❓ 常见问题 (FAQ)](docs/faq.md)
|
|
82
|
+
- [🐛 故障排除](docs/troubleshooting.md)
|
|
62
83
|
|
|
63
84
|
## 快速开始
|
|
64
85
|
|
|
@@ -11,6 +11,7 @@ src/mspec/commands/init.py
|
|
|
11
11
|
src/mspec/commands/update.py
|
|
12
12
|
src/mspec/core/__init__.py
|
|
13
13
|
src/mspec/core/config.py
|
|
14
|
+
src/mspec/core/openspec_manager.py
|
|
14
15
|
src/mspec/core/template.py
|
|
15
16
|
src/mspec/templates/config.yaml
|
|
16
17
|
src/mspec/templates/design-issue-taxonomy.md
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|