openspec-mcp 0.3.1 → 0.3.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.
Files changed (103) hide show
  1. package/README.md +22 -6
  2. package/README.zh.md +36 -1
  3. package/dist/api/routes/changes.d.ts.map +1 -1
  4. package/dist/api/routes/changes.js +42 -0
  5. package/dist/api/routes/changes.js.map +1 -1
  6. package/dist/api/routes/context.d.ts +8 -0
  7. package/dist/api/routes/context.d.ts.map +1 -0
  8. package/dist/api/routes/context.js +45 -0
  9. package/dist/api/routes/context.js.map +1 -0
  10. package/dist/api/routes/kanban.d.ts +8 -0
  11. package/dist/api/routes/kanban.d.ts.map +1 -0
  12. package/dist/api/routes/kanban.js +181 -0
  13. package/dist/api/routes/kanban.js.map +1 -0
  14. package/dist/api/routes/qa.d.ts +8 -0
  15. package/dist/api/routes/qa.d.ts.map +1 -0
  16. package/dist/api/routes/qa.js +98 -0
  17. package/dist/api/routes/qa.js.map +1 -0
  18. package/dist/api/server.d.ts +1 -0
  19. package/dist/api/server.d.ts.map +1 -1
  20. package/dist/api/server.js +7 -0
  21. package/dist/api/server.js.map +1 -1
  22. package/dist/core/approval-manager.d.ts.map +1 -1
  23. package/dist/core/approval-manager.js +9 -1
  24. package/dist/core/approval-manager.js.map +1 -1
  25. package/dist/core/approval-manager.test.js +14 -0
  26. package/dist/core/approval-manager.test.js.map +1 -1
  27. package/dist/core/context-analyzer.d.ts +116 -0
  28. package/dist/core/context-analyzer.d.ts.map +1 -0
  29. package/dist/core/context-analyzer.js +495 -0
  30. package/dist/core/context-analyzer.js.map +1 -0
  31. package/dist/core/prompt-manager.d.ts +50 -0
  32. package/dist/core/prompt-manager.d.ts.map +1 -0
  33. package/dist/core/prompt-manager.js +186 -0
  34. package/dist/core/prompt-manager.js.map +1 -0
  35. package/dist/core/qa-runner.d.ts +134 -0
  36. package/dist/core/qa-runner.d.ts.map +1 -0
  37. package/dist/core/qa-runner.js +299 -0
  38. package/dist/core/qa-runner.js.map +1 -0
  39. package/dist/core/spec-critic.d.ts +118 -0
  40. package/dist/core/spec-critic.d.ts.map +1 -0
  41. package/dist/core/spec-critic.js +478 -0
  42. package/dist/core/spec-critic.js.map +1 -0
  43. package/dist/core/spec-critic.test.d.ts +5 -0
  44. package/dist/core/spec-critic.test.d.ts.map +1 -0
  45. package/dist/core/spec-critic.test.js +152 -0
  46. package/dist/core/spec-critic.test.js.map +1 -0
  47. package/dist/index.js +33 -0
  48. package/dist/index.js.map +1 -1
  49. package/dist/server/tools/ai-context.d.ts +13 -0
  50. package/dist/server/tools/ai-context.d.ts.map +1 -0
  51. package/dist/server/tools/ai-context.js +212 -0
  52. package/dist/server/tools/ai-context.js.map +1 -0
  53. package/dist/server/tools/approval.d.ts.map +1 -1
  54. package/dist/server/tools/approval.js +33 -18
  55. package/dist/server/tools/approval.js.map +1 -1
  56. package/dist/server/tools/archive.d.ts.map +1 -1
  57. package/dist/server/tools/archive.js +9 -6
  58. package/dist/server/tools/archive.js.map +1 -1
  59. package/dist/server/tools/context.d.ts +12 -0
  60. package/dist/server/tools/context.d.ts.map +1 -0
  61. package/dist/server/tools/context.js +145 -0
  62. package/dist/server/tools/context.js.map +1 -0
  63. package/dist/server/tools/critique.d.ts +12 -0
  64. package/dist/server/tools/critique.d.ts.map +1 -0
  65. package/dist/server/tools/critique.js +194 -0
  66. package/dist/server/tools/critique.js.map +1 -0
  67. package/dist/server/tools/cross-service.d.ts.map +1 -1
  68. package/dist/server/tools/cross-service.js +11 -5
  69. package/dist/server/tools/cross-service.js.map +1 -1
  70. package/dist/server/tools/generator.d.ts.map +1 -1
  71. package/dist/server/tools/generator.js +27 -18
  72. package/dist/server/tools/generator.js.map +1 -1
  73. package/dist/server/tools/guides.d.ts.map +1 -1
  74. package/dist/server/tools/guides.js +8 -2
  75. package/dist/server/tools/guides.js.map +1 -1
  76. package/dist/server/tools/hooks.d.ts.map +1 -1
  77. package/dist/server/tools/hooks.js +7 -4
  78. package/dist/server/tools/hooks.js.map +1 -1
  79. package/dist/server/tools/management.d.ts.map +1 -1
  80. package/dist/server/tools/management.js +26 -14
  81. package/dist/server/tools/management.js.map +1 -1
  82. package/dist/server/tools/qa.d.ts +12 -0
  83. package/dist/server/tools/qa.d.ts.map +1 -0
  84. package/dist/server/tools/qa.js +248 -0
  85. package/dist/server/tools/qa.js.map +1 -0
  86. package/dist/server/tools/reviews.d.ts.map +1 -1
  87. package/dist/server/tools/reviews.js +55 -37
  88. package/dist/server/tools/reviews.js.map +1 -1
  89. package/dist/server/tools/tasks.d.ts.map +1 -1
  90. package/dist/server/tools/tasks.js +29 -17
  91. package/dist/server/tools/tasks.js.map +1 -1
  92. package/dist/server/tools/templates.d.ts.map +1 -1
  93. package/dist/server/tools/templates.js +26 -17
  94. package/dist/server/tools/templates.js.map +1 -1
  95. package/dist/server/tools/validation.d.ts.map +1 -1
  96. package/dist/server/tools/validation.js +31 -22
  97. package/dist/server/tools/validation.js.map +1 -1
  98. package/package.json +1 -1
  99. package/web/dist/assets/index-Bf5mzJti.css +1 -0
  100. package/web/dist/assets/index-W9UMaaAn.js +244 -0
  101. package/web/dist/index.html +2 -2
  102. package/web/dist/assets/index-CCYunmpc.css +0 -1
  103. package/web/dist/assets/index-wgGN6sVJ.js +0 -244
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Prompt Manager
3
+ * 管理和生成 MCP Prompts
4
+ */
5
+ import { ContextAnalyzer } from './context-analyzer.js';
6
+ import { OpenSpecCli } from './openspec-cli.js';
7
+ import { QARunner } from './qa-runner.js';
8
+ import path from 'path';
9
+ import fs from 'fs/promises';
10
+ export class PromptManager {
11
+ analyzer;
12
+ cli;
13
+ qaRunner;
14
+ constructor(options) {
15
+ this.analyzer = new ContextAnalyzer({ cwd: options.cwd });
16
+ this.cli = new OpenSpecCli({ cwd: options.cwd });
17
+ this.qaRunner = new QARunner({ cwd: options.cwd });
18
+ }
19
+ /**
20
+ * 获取所有可用的 Prompts 定义
21
+ */
22
+ getPrompts() {
23
+ return [
24
+ {
25
+ name: 'analyze-project',
26
+ description: '深度分析当前项目架构、技术栈和改进建议',
27
+ arguments: [
28
+ {
29
+ name: 'focus',
30
+ description: '分析重点: overview(默认), architecture, improvements, conventions',
31
+ required: false,
32
+ },
33
+ ],
34
+ },
35
+ {
36
+ name: 'review-change',
37
+ description: '审查指定的变更 (Change),包含 Proposal, Specs 和 Tasks',
38
+ arguments: [
39
+ {
40
+ name: 'changeId',
41
+ description: 'Change ID (例如: feat-login)',
42
+ required: true,
43
+ },
44
+ ],
45
+ },
46
+ ];
47
+ }
48
+ /**
49
+ * 生成 Prompt 内容
50
+ */
51
+ async getPrompt(name, args = {}) {
52
+ switch (name) {
53
+ case 'analyze-project':
54
+ return this.generateAnalyzeProjectPrompt(args.focus || 'overview');
55
+ case 'review-change':
56
+ if (!args.changeId) {
57
+ throw new Error('Missing required argument: changeId');
58
+ }
59
+ return this.generateReviewChangePrompt(args.changeId);
60
+ default:
61
+ throw new Error(`Unknown prompt: ${name}`);
62
+ }
63
+ }
64
+ /**
65
+ * 生成 analyze-project prompt
66
+ */
67
+ async generateAnalyzeProjectPrompt(focus) {
68
+ // 1. 获取静态分析结果
69
+ const context = await this.analyzer.analyze();
70
+ const projectMd = await this.analyzer.getProjectMd();
71
+ const keyFiles = await this.analyzer.getKeyFiles();
72
+ // 2. 构建上下文描述
73
+ let contextDescription = `
74
+ # Project Context
75
+
76
+ ## Tech Stack
77
+ - Languages: ${context.stack.languages.map(l => `${l.name} (${l.percentage}%)`).join(', ')}
78
+ - Frameworks: ${context.stack.frameworks.join(', ')}
79
+ - Package Manager: ${context.stack.packageManager}
80
+ - Build Tools: ${context.stack.buildTools.join(', ')}
81
+
82
+ ## Directory Structure
83
+ ${context.structure.mainDirectories.map(d => `- ${d.name}/: ${d.purpose} (${d.fileCount} files)`).join('\n')}
84
+
85
+ ## Patterns
86
+ - Architecture: ${context.patterns.architecture}
87
+ - Conventions: ${context.patterns.conventions.join(', ')}
88
+ `;
89
+ if (projectMd) {
90
+ contextDescription += `\n## Current project.md\n\n${projectMd}\n`;
91
+ }
92
+ // 3. 构建用户指令
93
+ let instruction = '';
94
+ switch (focus) {
95
+ case 'architecture':
96
+ instruction = '请分析项目的整体架构风格、模块划分和依赖关系。指出潜在的架构风险和改进点。';
97
+ break;
98
+ case 'improvements':
99
+ instruction = '请根据当前的技术栈和代码结构,提出具体的代码质量、性能或可维护性方面的改进建议。';
100
+ break;
101
+ case 'conventions':
102
+ instruction = '请分析项目的目录结构和文件命名,总结当前的开发约定,并建议是否需要制定更严格的规范。';
103
+ break;
104
+ case 'overview':
105
+ default:
106
+ instruction = '请作为一名资深技术专家,对该项目进行全面的技术评审。请总结项目的核心功能、技术亮点,并给出后续开发的建议。如果项目缺少 `project.md`,请帮我生成一个。';
107
+ break;
108
+ }
109
+ // 4. 组装消息
110
+ const messages = [
111
+ {
112
+ role: 'user',
113
+ content: {
114
+ type: 'text',
115
+ text: `${contextDescription}\n\nKey Files Content:\n${Object.entries(keyFiles).map(([path, content]) => `--- ${path} ---\n${content}\n`).join('\n')}\n\nTask: ${instruction}`,
116
+ },
117
+ },
118
+ ];
119
+ return messages;
120
+ }
121
+ /**
122
+ * 生成 review-change prompt
123
+ */
124
+ async generateReviewChangePrompt(changeId) {
125
+ // 1. 获取 Change 详情
126
+ const change = await this.cli.showChange(changeId);
127
+ if (!change) {
128
+ throw new Error(`Change not found: ${changeId}`);
129
+ }
130
+ // 2. 获取 Specs
131
+ const specsDir = path.join(this.cli['getOpenSpecDir'](), 'changes', changeId, 'specs');
132
+ let specsContent = '';
133
+ try {
134
+ const entries = await fs.readdir(specsDir, { withFileTypes: true });
135
+ for (const entry of entries) {
136
+ if (entry.isFile() && entry.name.endsWith('.md')) {
137
+ const content = await fs.readFile(path.join(specsDir, entry.name), 'utf-8');
138
+ specsContent += `\n--- Spec: ${entry.name} ---\n${content}\n`;
139
+ }
140
+ }
141
+ }
142
+ catch {
143
+ specsContent = 'No specs found.';
144
+ }
145
+ // 3. 获取 QA 状态
146
+ const qaResult = await this.qaRunner.getLatestQAResult(changeId);
147
+ const qaSummary = qaResult
148
+ ? `QA Status: ${qaResult.summary.passed} passed, ${qaResult.summary.failed} failed. Last run: ${qaResult.startedAt}`
149
+ : 'QA Status: Never run.';
150
+ // 4. 构建上下文
151
+ const contextDescription = `
152
+ # Change Review: ${changeId}
153
+
154
+ ## Metadata
155
+ - Type: ${change.type || 'unknown'}
156
+ - Status: ${change.status}
157
+ - Created: ${change.createdAt}
158
+
159
+ ## Proposal
160
+ ${change.proposal}
161
+
162
+ ${change.design ? `## Design\n${change.design}` : ''}
163
+
164
+ ## Tasks
165
+ ${change.tasks}
166
+
167
+ ## Specs
168
+ ${specsContent}
169
+
170
+ ## Quality Assurance
171
+ ${qaSummary}
172
+ `;
173
+ // 5. 组装消息
174
+ const messages = [
175
+ {
176
+ role: 'user',
177
+ content: {
178
+ type: 'text',
179
+ text: `${contextDescription}\n\nTask: 请审查这个变更 (Change)。\n1. 检查 Proposal 和 Specs 之间的一致性。\n2. 评估 Design 是否满足需求。\n3.基于 Tasks 列表,评估实施计划的完整性。\n4. 如果有 QA 失败,请给出修复建议。`,
180
+ },
181
+ },
182
+ ];
183
+ return messages;
184
+ }
185
+ }
186
+ //# sourceMappingURL=prompt-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-manager.js","sourceRoot":"","sources":["../../src/core/prompt-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * QA Runner - 质量循环模块
3
+ *
4
+ * 自动运行验证检查,发现问题后可触发修复循环:
5
+ * - 语法检查 (syntax)
6
+ * - 类型检查 (typecheck)
7
+ * - Lint 检查 (lint)
8
+ * - 测试运行 (test)
9
+ * - 构建验证 (build)
10
+ */
11
+ /**
12
+ * QA 检查类型
13
+ */
14
+ export type QACheckType = 'syntax' | 'typecheck' | 'lint' | 'test' | 'build';
15
+ /**
16
+ * QA 配置
17
+ */
18
+ export interface QAConfig {
19
+ maxIterations: number;
20
+ checks: QACheckType[];
21
+ autoFix: boolean;
22
+ timeout: number;
23
+ commands?: Partial<Record<QACheckType, string>>;
24
+ }
25
+ /**
26
+ * 单次检查结果
27
+ */
28
+ export interface QACheckResult {
29
+ type: QACheckType;
30
+ status: 'passed' | 'failed' | 'skipped' | 'timeout';
31
+ output?: string;
32
+ errors?: string[];
33
+ duration: number;
34
+ }
35
+ /**
36
+ * QA 运行状态
37
+ */
38
+ export type QAStatus = 'pending' | 'running' | 'passed' | 'failed' | 'fixing' | 'timeout' | 'stopped';
39
+ /**
40
+ * QA 运行结果
41
+ */
42
+ export interface QAResult {
43
+ id: string;
44
+ changeName: string;
45
+ status: QAStatus;
46
+ iteration: number;
47
+ maxIterations: number;
48
+ checks: QACheckResult[];
49
+ startedAt: string;
50
+ completedAt?: string;
51
+ summary: {
52
+ total: number;
53
+ passed: number;
54
+ failed: number;
55
+ skipped: number;
56
+ };
57
+ }
58
+ /**
59
+ * QARunner 主类
60
+ */
61
+ export declare class QARunner {
62
+ private cwd;
63
+ private config;
64
+ private runningQA;
65
+ constructor(options?: {
66
+ cwd?: string;
67
+ config?: Partial<QAConfig>;
68
+ });
69
+ /**
70
+ * 获取 QA 结果存储目录
71
+ */
72
+ private getQADir;
73
+ /**
74
+ * 获取变更目录
75
+ */
76
+ private getChangeDir;
77
+ /**
78
+ * ID 安全校验
79
+ */
80
+ private ensureSafeId;
81
+ /**
82
+ * 确保目录存在
83
+ */
84
+ private ensureDir;
85
+ /**
86
+ * 运行 QA 检查
87
+ */
88
+ runQA(changeName: string, options?: {
89
+ checks?: QACheckType[];
90
+ }): Promise<QAResult>;
91
+ /**
92
+ * 运行单个检查
93
+ */
94
+ private runCheck;
95
+ /**
96
+ * 获取 QA 状态
97
+ */
98
+ getQAStatus(changeName: string): Promise<QAResult | null>;
99
+ /**
100
+ * 获取 QA 历史
101
+ */
102
+ getQAHistory(changeName: string, limit?: number): Promise<QAResult[]>;
103
+ /**
104
+ * 获取最新 QA 结果
105
+ */
106
+ getLatestQAResult(changeName: string): Promise<QAResult | null>;
107
+ /**
108
+ * 停止正在运行的 QA
109
+ */
110
+ stopQA(changeName: string): Promise<boolean>;
111
+ /**
112
+ * 检查 QA 是否正在运行
113
+ */
114
+ isRunning(changeName: string): boolean;
115
+ /**
116
+ * 保存 QA 结果
117
+ */
118
+ private saveQAResult;
119
+ /**
120
+ * 获取进度汇总(所有变更)
121
+ */
122
+ getQASummary(): Promise<{
123
+ total: number;
124
+ passed: number;
125
+ failed: number;
126
+ running: number;
127
+ changes: Array<{
128
+ name: string;
129
+ status: QAStatus;
130
+ lastRun?: string;
131
+ }>;
132
+ }>;
133
+ }
134
+ //# sourceMappingURL=qa-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-runner.d.ts","sourceRoot":"","sources":["../../src/core/qa-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,299 @@
1
+ /**
2
+ * QA Runner - 质量循环模块
3
+ *
4
+ * 自动运行验证检查,发现问题后可触发修复循环:
5
+ * - 语法检查 (syntax)
6
+ * - 类型检查 (typecheck)
7
+ * - Lint 检查 (lint)
8
+ * - 测试运行 (test)
9
+ * - 构建验证 (build)
10
+ */
11
+ import * as fs from 'fs/promises';
12
+ import * as path from 'path';
13
+ import { exec } from 'child_process';
14
+ import { promisify } from 'util';
15
+ import { randomUUID } from 'crypto';
16
+ const execAsync = promisify(exec);
17
+ /**
18
+ * 默认 QA 配置
19
+ */
20
+ const DEFAULT_CONFIG = {
21
+ maxIterations: 5,
22
+ checks: ['typecheck', 'lint', 'test'],
23
+ autoFix: false,
24
+ timeout: 60000, // 60 seconds
25
+ };
26
+ /**
27
+ * 默认检查命令
28
+ */
29
+ const DEFAULT_COMMANDS = {
30
+ syntax: 'npx tsc --noEmit --skipLibCheck',
31
+ typecheck: 'npx tsc --noEmit',
32
+ lint: 'npm run lint --silent 2>/dev/null || echo "lint script not found"',
33
+ test: 'npm test --silent 2>/dev/null || echo "test script not found"',
34
+ build: 'npm run build --silent',
35
+ };
36
+ /**
37
+ * QARunner 主类
38
+ */
39
+ export class QARunner {
40
+ cwd;
41
+ config;
42
+ runningQA = new Map();
43
+ constructor(options) {
44
+ this.cwd = options?.cwd || process.cwd();
45
+ this.config = { ...DEFAULT_CONFIG, ...options?.config };
46
+ }
47
+ /**
48
+ * 获取 QA 结果存储目录
49
+ */
50
+ getQADir() {
51
+ return path.join(this.cwd, 'openspec', 'qa');
52
+ }
53
+ /**
54
+ * 获取变更目录
55
+ */
56
+ getChangeDir(changeName) {
57
+ const safeId = this.ensureSafeId(changeName);
58
+ return path.join(this.cwd, 'openspec', 'changes', safeId);
59
+ }
60
+ /**
61
+ * ID 安全校验
62
+ */
63
+ ensureSafeId(id) {
64
+ const trimmed = id.trim();
65
+ if (!trimmed || trimmed.includes('..') || trimmed.includes('/') || trimmed.includes('\\')) {
66
+ throw new Error(`Invalid id: ${id}`);
67
+ }
68
+ return trimmed;
69
+ }
70
+ /**
71
+ * 确保目录存在
72
+ */
73
+ async ensureDir(dirPath) {
74
+ await fs.mkdir(dirPath, { recursive: true });
75
+ }
76
+ /**
77
+ * 运行 QA 检查
78
+ */
79
+ async runQA(changeName, options) {
80
+ const safeId = this.ensureSafeId(changeName);
81
+ // 检查变更是否存在
82
+ const changeDir = this.getChangeDir(safeId);
83
+ try {
84
+ await fs.access(changeDir);
85
+ }
86
+ catch {
87
+ throw new Error(`Change not found: ${changeName}`);
88
+ }
89
+ // 初始化结果
90
+ const result = {
91
+ id: randomUUID().substring(0, 8),
92
+ changeName: safeId,
93
+ status: 'running',
94
+ iteration: 1,
95
+ maxIterations: this.config.maxIterations,
96
+ checks: [],
97
+ startedAt: new Date().toISOString(),
98
+ summary: { total: 0, passed: 0, failed: 0, skipped: 0 },
99
+ };
100
+ // 用于控制终止
101
+ const control = { aborted: false };
102
+ this.runningQA.set(safeId, control);
103
+ try {
104
+ const checksToRun = options?.checks || this.config.checks;
105
+ result.summary.total = checksToRun.length;
106
+ for (const checkType of checksToRun) {
107
+ if (control.aborted) {
108
+ result.status = 'stopped';
109
+ break;
110
+ }
111
+ const checkResult = await this.runCheck(checkType);
112
+ result.checks.push(checkResult);
113
+ // 更新统计
114
+ if (checkResult.status === 'passed') {
115
+ result.summary.passed++;
116
+ }
117
+ else if (checkResult.status === 'failed') {
118
+ result.summary.failed++;
119
+ }
120
+ else if (checkResult.status === 'skipped') {
121
+ result.summary.skipped++;
122
+ }
123
+ }
124
+ // 确定最终状态
125
+ if (result.status !== 'stopped') {
126
+ result.status = result.summary.failed > 0 ? 'failed' : 'passed';
127
+ }
128
+ }
129
+ finally {
130
+ this.runningQA.delete(safeId);
131
+ result.completedAt = new Date().toISOString();
132
+ }
133
+ // 保存结果
134
+ await this.saveQAResult(result);
135
+ return result;
136
+ }
137
+ /**
138
+ * 运行单个检查
139
+ */
140
+ async runCheck(type) {
141
+ const startTime = Date.now();
142
+ const command = this.config.commands?.[type] || DEFAULT_COMMANDS[type];
143
+ try {
144
+ const { stdout, stderr } = await execAsync(command, {
145
+ cwd: this.cwd,
146
+ timeout: this.config.timeout,
147
+ env: { ...process.env, CI: 'true' },
148
+ });
149
+ const duration = Date.now() - startTime;
150
+ const output = stdout + (stderr ? '\n' + stderr : '');
151
+ // 检查输出中是否包含错误标识
152
+ const hasError = /error|failed|failure/i.test(output) && !/0 error/i.test(output);
153
+ return {
154
+ type,
155
+ status: hasError ? 'failed' : 'passed',
156
+ output: output.slice(0, 2000), // 限制输出长度
157
+ duration,
158
+ };
159
+ }
160
+ catch (error) {
161
+ const duration = Date.now() - startTime;
162
+ // 检查是否超时(Node.js exec 超时时设置 killed 或 signal)
163
+ const execError = error;
164
+ if (execError.killed || execError.signal === 'SIGTERM') {
165
+ return {
166
+ type,
167
+ status: 'timeout',
168
+ errors: [`Check timed out after ${this.config.timeout}ms`],
169
+ duration,
170
+ };
171
+ }
172
+ // 命令执行失败
173
+ return {
174
+ type,
175
+ status: 'failed',
176
+ output: execError.stdout?.slice(0, 1000),
177
+ errors: [execError.stderr || execError.message || 'Unknown error'].slice(0, 5),
178
+ duration,
179
+ };
180
+ }
181
+ }
182
+ /**
183
+ * 获取 QA 状态
184
+ */
185
+ async getQAStatus(changeName) {
186
+ const latest = await this.getLatestQAResult(changeName);
187
+ return latest;
188
+ }
189
+ /**
190
+ * 获取 QA 历史
191
+ */
192
+ async getQAHistory(changeName, limit = 10) {
193
+ const qaDir = this.getQADir();
194
+ const safeId = this.ensureSafeId(changeName);
195
+ try {
196
+ const files = await fs.readdir(qaDir);
197
+ const matchingFiles = files
198
+ .filter(f => f.startsWith(safeId + '_') && f.endsWith('.json'))
199
+ .sort()
200
+ .reverse();
201
+ const results = [];
202
+ for (const file of matchingFiles.slice(0, limit)) {
203
+ try {
204
+ const content = await fs.readFile(path.join(qaDir, file), 'utf-8');
205
+ results.push(JSON.parse(content));
206
+ }
207
+ catch {
208
+ // 跳过无效文件
209
+ }
210
+ }
211
+ return results;
212
+ }
213
+ catch {
214
+ return [];
215
+ }
216
+ }
217
+ /**
218
+ * 获取最新 QA 结果
219
+ */
220
+ async getLatestQAResult(changeName) {
221
+ const history = await this.getQAHistory(changeName, 1);
222
+ return history[0] || null;
223
+ }
224
+ /**
225
+ * 停止正在运行的 QA
226
+ */
227
+ async stopQA(changeName) {
228
+ const safeId = this.ensureSafeId(changeName);
229
+ const control = this.runningQA.get(safeId);
230
+ if (control) {
231
+ control.aborted = true;
232
+ return true;
233
+ }
234
+ return false;
235
+ }
236
+ /**
237
+ * 检查 QA 是否正在运行
238
+ */
239
+ isRunning(changeName) {
240
+ const safeId = this.ensureSafeId(changeName);
241
+ return this.runningQA.has(safeId);
242
+ }
243
+ /**
244
+ * 保存 QA 结果
245
+ */
246
+ async saveQAResult(result) {
247
+ const qaDir = this.getQADir();
248
+ await this.ensureDir(qaDir);
249
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
250
+ const filePath = path.join(qaDir, `${result.changeName}_${timestamp}.json`);
251
+ await fs.writeFile(filePath, JSON.stringify(result, null, 2), 'utf-8');
252
+ }
253
+ /**
254
+ * 获取进度汇总(所有变更)
255
+ */
256
+ async getQASummary() {
257
+ const changesDir = path.join(this.cwd, 'openspec', 'changes');
258
+ const summary = {
259
+ total: 0,
260
+ passed: 0,
261
+ failed: 0,
262
+ running: 0,
263
+ changes: [],
264
+ };
265
+ try {
266
+ const changes = await fs.readdir(changesDir);
267
+ for (const change of changes) {
268
+ const stat = await fs.stat(path.join(changesDir, change));
269
+ if (!stat.isDirectory())
270
+ continue;
271
+ summary.total++;
272
+ const latest = await this.getLatestQAResult(change);
273
+ if (this.isRunning(change)) {
274
+ summary.running++;
275
+ summary.changes.push({ name: change, status: 'running' });
276
+ }
277
+ else if (latest) {
278
+ if (latest.status === 'passed')
279
+ summary.passed++;
280
+ else if (latest.status === 'failed')
281
+ summary.failed++;
282
+ summary.changes.push({
283
+ name: change,
284
+ status: latest.status,
285
+ lastRun: latest.completedAt,
286
+ });
287
+ }
288
+ else {
289
+ summary.changes.push({ name: change, status: 'pending' });
290
+ }
291
+ }
292
+ }
293
+ catch {
294
+ // 目录不存在时返回空结果
295
+ }
296
+ return summary;
297
+ }
298
+ }
299
+ //# sourceMappingURL=qa-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-runner.js","sourceRoot":"","sources":["../../src/core/qa-runner.ts"],"names":[],"mappings":"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"}