openmatrix 0.1.17 → 0.1.19

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.
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const analyzeCommand: Command;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.analyzeCommand = void 0;
4
+ // src/cli/commands/analyze.ts
5
+ const commander_1 = require("commander");
6
+ const smart_question_analyzer_js_1 = require("../../orchestrator/smart-question-analyzer.js");
7
+ exports.analyzeCommand = new commander_1.Command('analyze')
8
+ .description('智能分析任务,推断配置,返回需要确认的问题列表')
9
+ .argument('[task]', '任务描述')
10
+ .option('--json', '输出 JSON 格式')
11
+ .action(async (task, options) => {
12
+ const analyzer = new smart_question_analyzer_js_1.SmartQuestionAnalyzer(process.cwd());
13
+ if (!task) {
14
+ if (options.json) {
15
+ console.log(JSON.stringify({
16
+ status: 'error',
17
+ message: '请提供任务描述'
18
+ }));
19
+ }
20
+ else {
21
+ console.log('❌ 请提供任务描述');
22
+ console.log(' 用法: openmatrix analyze "实现用户登录功能"');
23
+ }
24
+ return;
25
+ }
26
+ try {
27
+ const result = await analyzer.analyze(task);
28
+ if (options.json) {
29
+ // 输出 JSON 格式 (供 Skill 解析)
30
+ const output = result;
31
+ console.log(JSON.stringify(output, null, 2));
32
+ }
33
+ else {
34
+ // 输出人类可读格式
35
+ console.log('\n' + analyzer.generateSummary(result));
36
+ }
37
+ }
38
+ catch (error) {
39
+ if (options.json) {
40
+ console.log(JSON.stringify({
41
+ status: 'error',
42
+ message: error instanceof Error ? error.message : '分析失败'
43
+ }));
44
+ }
45
+ else {
46
+ console.log('❌ 分析失败:', error instanceof Error ? error.message : '未知错误');
47
+ }
48
+ }
49
+ });
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const checkGitignoreCommand: Command;
@@ -0,0 +1,361 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.checkGitignoreCommand = void 0;
40
+ // src/cli/commands/check-gitignore.ts
41
+ const commander_1 = require("commander");
42
+ const fs = __importStar(require("fs/promises"));
43
+ const path = __importStar(require("path"));
44
+ const chalk_1 = __importDefault(require("chalk"));
45
+ /**
46
+ * 项目类型对应的 gitignore 条目
47
+ */
48
+ const GITIGNORE_TEMPLATES = {
49
+ nodejs: [
50
+ 'node_modules/',
51
+ 'dist/',
52
+ 'build/',
53
+ '.npm/',
54
+ '*.log',
55
+ 'npm-debug.log*',
56
+ 'yarn-debug.log*',
57
+ 'yarn-error.log*'
58
+ ],
59
+ typescript: [
60
+ '*.tsbuildinfo',
61
+ '.tsbuildinfo'
62
+ ],
63
+ python: [
64
+ '__pycache__/',
65
+ '*.py[cod]',
66
+ '*$py.class',
67
+ '.venv/',
68
+ 'venv/',
69
+ 'ENV/',
70
+ '.pytest_cache/',
71
+ '.mypy_cache/',
72
+ '*.egg-info/',
73
+ 'dist/',
74
+ 'build/'
75
+ ],
76
+ java: [
77
+ 'target/',
78
+ '.gradle/',
79
+ 'build/',
80
+ '*.class',
81
+ '*.jar',
82
+ '*.war'
83
+ ],
84
+ go: [
85
+ 'vendor/',
86
+ 'bin/',
87
+ '*.exe',
88
+ '*.exe~',
89
+ '*.dll',
90
+ '*.so',
91
+ '*.dylib'
92
+ ],
93
+ rust: [
94
+ 'target/',
95
+ 'Cargo.lock'
96
+ ],
97
+ dotnet: [
98
+ 'bin/',
99
+ 'obj/',
100
+ '*.nupkg',
101
+ '*.snupkg'
102
+ ],
103
+ php: [
104
+ 'vendor/',
105
+ 'composer.lock'
106
+ ],
107
+ dart: [
108
+ '.dart_tool/',
109
+ '.packages',
110
+ 'build/',
111
+ '.pub/',
112
+ 'pubspec.lock'
113
+ ],
114
+ common: [
115
+ '.env',
116
+ '.env.local',
117
+ '.env.*.local',
118
+ '.DS_Store',
119
+ 'Thumbs.db',
120
+ '*.swp',
121
+ '*.swo',
122
+ '*~',
123
+ '.idea/',
124
+ '.vscode/',
125
+ '*.iml'
126
+ ]
127
+ };
128
+ /**
129
+ * 根据项目类型检测需要的 gitignore 条目
130
+ */
131
+ async function detectProjectType(projectRoot) {
132
+ const types = [];
133
+ // 检查 package.json
134
+ try {
135
+ const packageJsonPath = path.join(projectRoot, 'package.json');
136
+ const content = await fs.readFile(packageJsonPath, 'utf-8');
137
+ const pkg = JSON.parse(content);
138
+ types.push('nodejs');
139
+ // 检查 TypeScript
140
+ if (pkg.devDependencies?.typescript || pkg.dependencies?.typescript) {
141
+ types.push('typescript');
142
+ }
143
+ }
144
+ catch {
145
+ // 不是 Node.js 项目
146
+ }
147
+ // 检查 Python
148
+ try {
149
+ await fs.access(path.join(projectRoot, 'pyproject.toml'));
150
+ types.push('python');
151
+ }
152
+ catch { }
153
+ try {
154
+ await fs.access(path.join(projectRoot, 'requirements.txt'));
155
+ if (!types.includes('python'))
156
+ types.push('python');
157
+ }
158
+ catch { }
159
+ // 检查 Java
160
+ try {
161
+ await fs.access(path.join(projectRoot, 'pom.xml'));
162
+ types.push('java');
163
+ }
164
+ catch { }
165
+ try {
166
+ await fs.access(path.join(projectRoot, 'build.gradle'));
167
+ if (!types.includes('java'))
168
+ types.push('java');
169
+ }
170
+ catch { }
171
+ // 检查 Go
172
+ try {
173
+ await fs.access(path.join(projectRoot, 'go.mod'));
174
+ types.push('go');
175
+ }
176
+ catch { }
177
+ // 检查 Rust
178
+ try {
179
+ await fs.access(path.join(projectRoot, 'Cargo.toml'));
180
+ types.push('rust');
181
+ }
182
+ catch { }
183
+ // 检查 .NET
184
+ try {
185
+ const files = await fs.readdir(projectRoot);
186
+ if (files.some(f => f.endsWith('.sln') || f.endsWith('.csproj'))) {
187
+ types.push('dotnet');
188
+ }
189
+ }
190
+ catch { }
191
+ // 检查 PHP
192
+ try {
193
+ await fs.access(path.join(projectRoot, 'composer.json'));
194
+ types.push('php');
195
+ }
196
+ catch { }
197
+ // 检查 Dart
198
+ try {
199
+ await fs.access(path.join(projectRoot, 'pubspec.yaml'));
200
+ types.push('dart');
201
+ }
202
+ catch { }
203
+ // 始终添加通用条目
204
+ types.push('common');
205
+ return types;
206
+ }
207
+ /**
208
+ * 获取所有需要的 gitignore 条目
209
+ */
210
+ function getRequiredEntries(projectTypes) {
211
+ const entries = new Set();
212
+ for (const type of projectTypes) {
213
+ const template = GITIGNORE_TEMPLATES[type];
214
+ if (template) {
215
+ for (const entry of template) {
216
+ entries.add(entry);
217
+ }
218
+ }
219
+ }
220
+ return entries;
221
+ }
222
+ /**
223
+ * 解析现有 gitignore 内容
224
+ */
225
+ function parseGitignore(content) {
226
+ const entries = new Set();
227
+ const lines = content.split('\n');
228
+ for (const line of lines) {
229
+ const trimmed = line.trim();
230
+ // 跳过注释和空行
231
+ if (trimmed && !trimmed.startsWith('#')) {
232
+ entries.add(trimmed);
233
+ }
234
+ }
235
+ return entries;
236
+ }
237
+ exports.checkGitignoreCommand = new commander_1.Command('check-gitignore')
238
+ .description('检查并自动补充 .gitignore 文件')
239
+ .option('--json', '输出 JSON 格式')
240
+ .option('--dry-run', '仅显示会添加的内容,不实际修改')
241
+ .action(async (options) => {
242
+ const projectRoot = process.cwd();
243
+ const gitignorePath = path.join(projectRoot, '.gitignore');
244
+ try {
245
+ // 检测项目类型
246
+ const projectTypes = await detectProjectType(projectRoot);
247
+ const requiredEntries = getRequiredEntries(projectTypes);
248
+ // 读取现有 gitignore
249
+ let existingEntries = new Set();
250
+ let exists = false;
251
+ try {
252
+ const content = await fs.readFile(gitignorePath, 'utf-8');
253
+ existingEntries = parseGitignore(content);
254
+ exists = true;
255
+ }
256
+ catch {
257
+ // 文件不存在
258
+ }
259
+ // 计算缺失的条目
260
+ const missingEntries = [];
261
+ for (const entry of requiredEntries) {
262
+ if (!existingEntries.has(entry)) {
263
+ missingEntries.push(entry);
264
+ }
265
+ }
266
+ // JSON 输出
267
+ if (options.json) {
268
+ console.log(JSON.stringify({
269
+ exists,
270
+ projectTypes,
271
+ missingEntries,
272
+ totalRequired: requiredEntries.size,
273
+ totalExisting: existingEntries.size
274
+ }, null, 2));
275
+ return;
276
+ }
277
+ // 没有缺失条目
278
+ if (missingEntries.length === 0) {
279
+ console.log(chalk_1.default.green('✅ .gitignore 已完善,无需修改\n'));
280
+ return;
281
+ }
282
+ // Dry run 模式
283
+ if (options.dryRun) {
284
+ console.log(chalk_1.default.cyan('🔍 检测到以下缺失条目:\n'));
285
+ for (const entry of missingEntries) {
286
+ console.log(chalk_1.default.gray(` + ${entry}`));
287
+ }
288
+ return;
289
+ }
290
+ // 自动补充
291
+ const newContent = generateGitignoreContent(missingEntries);
292
+ if (exists) {
293
+ // 追加到现有文件
294
+ await fs.appendFile(gitignorePath, `\n${newContent}`);
295
+ console.log(chalk_1.default.green(`✅ 已向 .gitignore 添加 ${missingEntries.length} 个条目:\n`));
296
+ }
297
+ else {
298
+ // 创建新文件
299
+ await fs.writeFile(gitignorePath, newContent);
300
+ console.log(chalk_1.default.green(`✅ 已创建 .gitignore,包含 ${missingEntries.length} 个条目:\n`));
301
+ }
302
+ for (const entry of missingEntries) {
303
+ console.log(chalk_1.default.gray(` + ${entry}`));
304
+ }
305
+ console.log();
306
+ }
307
+ catch (error) {
308
+ if (options.json) {
309
+ console.log(JSON.stringify({ error: String(error) }));
310
+ }
311
+ else {
312
+ console.error(chalk_1.default.red('❌ 检查失败:'), error);
313
+ }
314
+ process.exit(1);
315
+ }
316
+ });
317
+ /**
318
+ * 生成 gitignore 内容
319
+ */
320
+ function generateGitignoreContent(entries) {
321
+ const timestamp = new Date().toISOString().split('T')[0];
322
+ // 按类型分组
323
+ const groups = {
324
+ 'Dependencies': [],
325
+ 'Build': [],
326
+ 'Environment': [],
327
+ 'IDE': [],
328
+ 'OS': [],
329
+ 'Other': []
330
+ };
331
+ for (const entry of entries) {
332
+ if (entry.includes('node_modules') || entry.includes('vendor') || entry.includes('.venv')) {
333
+ groups['Dependencies'].push(entry);
334
+ }
335
+ else if (entry.includes('dist') || entry.includes('build') || entry.includes('target')) {
336
+ groups['Build'].push(entry);
337
+ }
338
+ else if (entry.includes('.env')) {
339
+ groups['Environment'].push(entry);
340
+ }
341
+ else if (entry.includes('.idea') || entry.includes('.vscode') || entry.includes('.iml')) {
342
+ groups['IDE'].push(entry);
343
+ }
344
+ else if (entry.includes('.DS_Store') || entry.includes('Thumbs.db')) {
345
+ groups['OS'].push(entry);
346
+ }
347
+ else {
348
+ groups['Other'].push(entry);
349
+ }
350
+ }
351
+ let content = `\n# Auto-generated by OpenMatrix (${timestamp})\n`;
352
+ for (const [group, items] of Object.entries(groups)) {
353
+ if (items.length > 0) {
354
+ content += `\n# ${group}\n`;
355
+ for (const item of items) {
356
+ content += `${item}\n`;
357
+ }
358
+ }
359
+ }
360
+ return content;
361
+ }
@@ -50,7 +50,7 @@ exports.checkCommand = new commander_1.Command('check')
50
50
  .option('--categories <items>', '指定检测类别 (逗号分隔)', 'bug,quality,capability,ux,style,security,common')
51
51
  .option('--min-priority <level>', '最小优先级 (critical|high|medium|low)', 'low')
52
52
  .option('--max <number>', '最大建议数量', '50')
53
- .option('--scan <dirs>', '扫描目录 (逗号分隔)', 'src,skills,tests,docs')
53
+ .option('--scan <dirs>', '扫描目录 (逗号分隔)', 'src,skills,docs')
54
54
  .option('--interactive', '交互式选择要执行的改进', false)
55
55
  .action(async (hint, options) => {
56
56
  const projectRoot = process.cwd();
package/dist/cli/index.js CHANGED
@@ -12,6 +12,8 @@ const meeting_js_1 = require("./commands/meeting.js");
12
12
  const auto_js_1 = require("./commands/auto.js");
13
13
  const install_skills_js_1 = require("./commands/install-skills.js");
14
14
  const check_js_1 = require("./commands/check.js");
15
+ const check_gitignore_js_1 = require("./commands/check-gitignore.js");
16
+ const analyze_js_1 = require("./commands/analyze.js");
15
17
  const program = new commander_1.Command();
16
18
  program
17
19
  .name('openmatrix')
@@ -28,5 +30,7 @@ program.addCommand(meeting_js_1.meetingCommand);
28
30
  program.addCommand(auto_js_1.autoCommand);
29
31
  program.addCommand(install_skills_js_1.installSkillsCommand);
30
32
  program.addCommand(check_js_1.checkCommand);
33
+ program.addCommand(check_gitignore_js_1.checkGitignoreCommand);
34
+ program.addCommand(analyze_js_1.analyzeCommand);
31
35
  // 默认帮助
32
36
  program.parse();
@@ -39,6 +39,13 @@ export interface QuestionSession {
39
39
  status: 'pending' | 'in_progress' | 'completed';
40
40
  createdAt: string;
41
41
  completedAt?: string;
42
+ /** 推断值 (由 SmartQuestionAnalyzer 提供) */
43
+ inferences?: Map<string, {
44
+ answer: string | string[];
45
+ reason: string;
46
+ }>;
47
+ /** 已跳过的问题 (使用推断值) */
48
+ skippedQuestionIds?: string[];
42
49
  }
43
50
  /**
44
51
  * InteractiveQuestionGenerator - 交互式问题生成器
@@ -48,9 +55,40 @@ export interface QuestionSession {
48
55
  * 2. 优先级排序 - 按重要性顺序提问
49
56
  * 3. 条件分支 - 不同回答触发不同追问
50
57
  * 4. 交互友好 - 支持单步/批量回答
58
+ * 5. 智能推断 - 支持预设推断值,跳过不必要的问题
51
59
  */
52
60
  export declare class InteractiveQuestionGenerator {
53
61
  private session;
62
+ /** 推断值 */
63
+ private inferences;
64
+ /** 需要跳过的问题 ID */
65
+ private skippedQuestionIds;
66
+ /**
67
+ * 设置推断值 (来自 SmartQuestionAnalyzer)
68
+ */
69
+ setInferences(inferences: Map<string, {
70
+ answer: string | string[];
71
+ reason: string;
72
+ }>): void;
73
+ /**
74
+ * 获取推断值
75
+ */
76
+ getInference(questionId: string): {
77
+ answer: string | string[];
78
+ reason: string;
79
+ } | undefined;
80
+ /**
81
+ * 检查问题是否被跳过 (使用推断值)
82
+ */
83
+ isQuestionSkipped(questionId: string): boolean;
84
+ /**
85
+ * 获取所有跳过的问题及其推断值
86
+ */
87
+ getSkippedQuestions(): Array<{
88
+ questionId: string;
89
+ answer: string | string[];
90
+ reason: string;
91
+ }>;
54
92
  /**
55
93
  * 开始新的问答会话
56
94
  */
@@ -9,22 +9,80 @@ exports.InteractiveQuestionGenerator = void 0;
9
9
  * 2. 优先级排序 - 按重要性顺序提问
10
10
  * 3. 条件分支 - 不同回答触发不同追问
11
11
  * 4. 交互友好 - 支持单步/批量回答
12
+ * 5. 智能推断 - 支持预设推断值,跳过不必要的问题
12
13
  */
13
14
  class InteractiveQuestionGenerator {
14
15
  session = null;
16
+ /** 推断值 */
17
+ inferences = new Map();
18
+ /** 需要跳过的问题 ID */
19
+ skippedQuestionIds = new Set();
20
+ /**
21
+ * 设置推断值 (来自 SmartQuestionAnalyzer)
22
+ */
23
+ setInferences(inferences) {
24
+ this.inferences = inferences;
25
+ // 高置信度的推断值可以跳过问题
26
+ for (const [questionId] of inferences) {
27
+ this.skippedQuestionIds.add(questionId);
28
+ }
29
+ }
30
+ /**
31
+ * 获取推断值
32
+ */
33
+ getInference(questionId) {
34
+ return this.inferences.get(questionId);
35
+ }
36
+ /**
37
+ * 检查问题是否被跳过 (使用推断值)
38
+ */
39
+ isQuestionSkipped(questionId) {
40
+ return this.skippedQuestionIds.has(questionId);
41
+ }
42
+ /**
43
+ * 获取所有跳过的问题及其推断值
44
+ */
45
+ getSkippedQuestions() {
46
+ const result = [];
47
+ for (const questionId of this.skippedQuestionIds) {
48
+ const inference = this.inferences.get(questionId);
49
+ if (inference) {
50
+ result.push({ questionId, ...inference });
51
+ }
52
+ }
53
+ return result;
54
+ }
15
55
  /**
16
56
  * 开始新的问答会话
17
57
  */
18
58
  startSession(parsedTask) {
19
- const baseQuestions = this.generateBaseQuestions(parsedTask);
59
+ const allQuestions = this.generateBaseQuestions(parsedTask);
60
+ // 过滤掉已跳过的问题 (使用推断值)
61
+ const questionsToAsk = allQuestions.filter(q => !this.skippedQuestionIds.has(q.id));
62
+ // 为跳过的问题创建答案
63
+ const skippedAnswers = [];
64
+ for (const question of allQuestions) {
65
+ if (this.skippedQuestionIds.has(question.id)) {
66
+ const inference = this.inferences.get(question.id);
67
+ if (inference) {
68
+ const answer = {
69
+ questionId: question.id,
70
+ selectedKeys: Array.isArray(inference.answer) ? inference.answer : [inference.answer]
71
+ };
72
+ skippedAnswers.push(answer);
73
+ }
74
+ }
75
+ }
20
76
  this.session = {
21
77
  sessionId: `qs-${Date.now().toString(36)}`,
22
78
  taskId: parsedTask.title,
23
- questions: baseQuestions.sort((a, b) => a.priority - b.priority),
24
- answers: [],
79
+ questions: questionsToAsk.sort((a, b) => a.priority - b.priority),
80
+ answers: skippedAnswers, // 预填充跳过问题的答案
25
81
  currentQuestionIndex: 0,
26
82
  status: 'in_progress',
27
- createdAt: new Date().toISOString()
83
+ createdAt: new Date().toISOString(),
84
+ inferences: this.inferences,
85
+ skippedQuestionIds: Array.from(this.skippedQuestionIds)
28
86
  };
29
87
  return this.session;
30
88
  }
@@ -0,0 +1,82 @@
1
+ import type { ParsedTask } from '../types/index.js';
2
+ /**
3
+ * 问题推断结果
4
+ */
5
+ export interface QuestionInference {
6
+ questionId: string;
7
+ inferredAnswer?: string | string[];
8
+ confidence: 'high' | 'medium' | 'low';
9
+ reason: string;
10
+ }
11
+ /**
12
+ * 项目上下文
13
+ */
14
+ export interface ProjectContext {
15
+ projectType: 'typescript' | 'javascript' | 'python' | 'go' | 'rust' | 'java' | 'unknown';
16
+ frameworks: string[];
17
+ hasFrontend: boolean;
18
+ hasBackend: boolean;
19
+ hasTests: boolean;
20
+ packageManager: 'npm' | 'yarn' | 'pnpm' | 'pip' | 'go-mod' | 'cargo' | 'unknown';
21
+ dependencies: Record<string, string>;
22
+ }
23
+ /**
24
+ * 分析结果
25
+ */
26
+ export interface AnalysisResult {
27
+ inferences: QuestionInference[];
28
+ questionsToAsk: string[];
29
+ skippedQuestions: string[];
30
+ projectContext: ProjectContext;
31
+ }
32
+ /**
33
+ * SmartQuestionAnalyzer - 智能问答分析器
34
+ *
35
+ * 根据任务描述和项目上下文智能推断问题答案,减少不必要的问答
36
+ *
37
+ * 使用方式:
38
+ * 1. 分析项目文件获取上下文
39
+ * 2. 根据任务关键词推断答案
40
+ * 3. 返回需要提问的问题列表
41
+ */
42
+ export declare class SmartQuestionAnalyzer {
43
+ private projectRoot;
44
+ private cachedContext;
45
+ constructor(projectRoot?: string);
46
+ /**
47
+ * 分析任务,返回推断结果
48
+ */
49
+ analyze(taskDescription: string, parsedTask?: ParsedTask): Promise<AnalysisResult>;
50
+ /**
51
+ * 获取项目上下文
52
+ */
53
+ getProjectContext(): Promise<ProjectContext>;
54
+ /**
55
+ * 推断问题答案
56
+ */
57
+ private inferAnswers;
58
+ /**
59
+ * 推断质量级别
60
+ */
61
+ private inferQualityLevel;
62
+ /**
63
+ * 推断技术栈
64
+ */
65
+ private inferTechStack;
66
+ /**
67
+ * 推断文档级别
68
+ */
69
+ private inferDocLevel;
70
+ /**
71
+ * 推断 E2E 测试
72
+ */
73
+ private inferE2ETest;
74
+ /**
75
+ * 推断执行模式
76
+ */
77
+ private inferExecutionMode;
78
+ /**
79
+ * 生成推断摘要
80
+ */
81
+ generateSummary(result: AnalysisResult): string;
82
+ }
@@ -0,0 +1,412 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SmartQuestionAnalyzer = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ /**
40
+ * SmartQuestionAnalyzer - 智能问答分析器
41
+ *
42
+ * 根据任务描述和项目上下文智能推断问题答案,减少不必要的问答
43
+ *
44
+ * 使用方式:
45
+ * 1. 分析项目文件获取上下文
46
+ * 2. 根据任务关键词推断答案
47
+ * 3. 返回需要提问的问题列表
48
+ */
49
+ class SmartQuestionAnalyzer {
50
+ projectRoot;
51
+ cachedContext = null;
52
+ constructor(projectRoot = process.cwd()) {
53
+ this.projectRoot = projectRoot;
54
+ }
55
+ /**
56
+ * 分析任务,返回推断结果
57
+ */
58
+ async analyze(taskDescription, parsedTask) {
59
+ // 1. 获取项目上下文
60
+ const projectContext = await this.getProjectContext();
61
+ // 2. 执行推断
62
+ const inferences = this.inferAnswers(taskDescription, projectContext);
63
+ // 3. 筛选需要提问的问题
64
+ const questionsToAsk = inferences
65
+ .filter(i => i.confidence === 'low' || !i.inferredAnswer)
66
+ .map(i => i.questionId);
67
+ const skippedQuestions = inferences
68
+ .filter(i => i.confidence !== 'low' && i.inferredAnswer)
69
+ .map(i => i.questionId);
70
+ return {
71
+ inferences,
72
+ questionsToAsk,
73
+ skippedQuestions,
74
+ projectContext
75
+ };
76
+ }
77
+ /**
78
+ * 获取项目上下文
79
+ */
80
+ async getProjectContext() {
81
+ if (this.cachedContext) {
82
+ return this.cachedContext;
83
+ }
84
+ const context = {
85
+ projectType: 'unknown',
86
+ frameworks: [],
87
+ hasFrontend: false,
88
+ hasBackend: false,
89
+ hasTests: false,
90
+ packageManager: 'unknown',
91
+ dependencies: {}
92
+ };
93
+ // 检测项目类型和依赖
94
+ const packageJsonPath = path.join(this.projectRoot, 'package.json');
95
+ if (fs.existsSync(packageJsonPath)) {
96
+ try {
97
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
98
+ context.packageManager = 'npm';
99
+ context.dependencies = {
100
+ ...packageJson.dependencies,
101
+ ...packageJson.devDependencies
102
+ };
103
+ // 检测 TypeScript
104
+ if (context.dependencies['typescript'] || fs.existsSync(path.join(this.projectRoot, 'tsconfig.json'))) {
105
+ context.projectType = 'typescript';
106
+ }
107
+ else {
108
+ context.projectType = 'javascript';
109
+ }
110
+ // 检测框架
111
+ const frameworkDeps = {
112
+ 'react': 'React',
113
+ 'vue': 'Vue',
114
+ 'svelte': 'Svelte',
115
+ 'angular': 'Angular',
116
+ 'next': 'Next.js',
117
+ 'nuxt': 'Nuxt.js',
118
+ 'express': 'Express',
119
+ 'fastify': 'Fastify',
120
+ 'nestjs': 'NestJS',
121
+ 'koa': 'Koa',
122
+ 'electron': 'Electron'
123
+ };
124
+ for (const [dep, name] of Object.entries(frameworkDeps)) {
125
+ if (context.dependencies[dep]) {
126
+ context.frameworks.push(name);
127
+ }
128
+ }
129
+ // 检测前端/后端
130
+ context.hasFrontend = ['react', 'vue', 'svelte', 'angular', 'next', 'nuxt', 'electron']
131
+ .some(dep => context.dependencies[dep]);
132
+ context.hasBackend = ['express', 'fastify', 'nestjs', 'koa']
133
+ .some(dep => context.dependencies[dep]);
134
+ // 检测测试
135
+ context.hasTests = ['vitest', 'jest', 'mocha', 'pytest', 'testing']
136
+ .some(dep => context.dependencies[dep]) ||
137
+ fs.existsSync(path.join(this.projectRoot, 'tests')) ||
138
+ fs.existsSync(path.join(this.projectRoot, 'test'));
139
+ }
140
+ catch {
141
+ // 忽略解析错误
142
+ }
143
+ }
144
+ // 检测 Python 项目
145
+ if (fs.existsSync(path.join(this.projectRoot, 'requirements.txt')) ||
146
+ fs.existsSync(path.join(this.projectRoot, 'pyproject.toml'))) {
147
+ context.projectType = 'python';
148
+ context.packageManager = 'pip';
149
+ }
150
+ // 检测 Go 项目
151
+ if (fs.existsSync(path.join(this.projectRoot, 'go.mod'))) {
152
+ context.projectType = 'go';
153
+ context.packageManager = 'go-mod';
154
+ }
155
+ // 检测 Rust 项目
156
+ if (fs.existsSync(path.join(this.projectRoot, 'Cargo.toml'))) {
157
+ context.projectType = 'rust';
158
+ context.packageManager = 'cargo';
159
+ }
160
+ this.cachedContext = context;
161
+ return context;
162
+ }
163
+ /**
164
+ * 推断问题答案
165
+ */
166
+ inferAnswers(taskDescription, context) {
167
+ const inferences = [];
168
+ const desc = taskDescription.toLowerCase();
169
+ // 1. 推断质量级别
170
+ inferences.push(this.inferQualityLevel(desc, context));
171
+ // 2. 推断技术栈
172
+ inferences.push(this.inferTechStack(desc, context));
173
+ // 3. 推断文档级别
174
+ inferences.push(this.inferDocLevel(desc, context));
175
+ // 4. 推断 E2E 测试
176
+ inferences.push(this.inferE2ETest(desc, context));
177
+ // 5. 推断执行模式
178
+ inferences.push(this.inferExecutionMode(desc, context));
179
+ return inferences;
180
+ }
181
+ /**
182
+ * 推断质量级别
183
+ */
184
+ inferQualityLevel(desc, context) {
185
+ const inference = {
186
+ questionId: 'quality_level',
187
+ confidence: 'low',
188
+ reason: ''
189
+ };
190
+ // Bug 修复 -> balanced
191
+ if (/(fix|bug|修复|hotfix|patch|问题)/i.test(desc)) {
192
+ inference.inferredAnswer = 'balanced';
193
+ inference.confidence = 'high';
194
+ inference.reason = '任务涉及 Bug 修复';
195
+ return inference;
196
+ }
197
+ // 原型/POC -> fast
198
+ if (/(prototype|poc|demo|快速|原型|示例|sample)/i.test(desc)) {
199
+ inference.inferredAnswer = 'fast';
200
+ inference.confidence = 'high';
201
+ inference.reason = '任务涉及原型或演示';
202
+ return inference;
203
+ }
204
+ // 测试相关 -> strict
205
+ if (/(test|测试|单元|unit|coverage|覆盖率)/i.test(desc)) {
206
+ inference.inferredAnswer = 'strict';
207
+ inference.confidence = 'high';
208
+ inference.reason = '任务涉及测试';
209
+ return inference;
210
+ }
211
+ // 新功能/生产代码 -> strict
212
+ if (/(implement|add|新功能|实现|开发|feature|生产)/i.test(desc)) {
213
+ inference.inferredAnswer = 'strict';
214
+ inference.confidence = 'medium';
215
+ inference.reason = '任务涉及新功能开发';
216
+ return inference;
217
+ }
218
+ // 重构 -> balanced
219
+ if (/(refactor|优化|重构|improve)/i.test(desc)) {
220
+ inference.inferredAnswer = 'balanced';
221
+ inference.confidence = 'medium';
222
+ inference.reason = '任务涉及代码重构';
223
+ return inference;
224
+ }
225
+ inference.reason = '无法确定任务类型';
226
+ return inference;
227
+ }
228
+ /**
229
+ * 推断技术栈
230
+ */
231
+ inferTechStack(desc, context) {
232
+ const inference = {
233
+ questionId: 'tech_stack',
234
+ confidence: 'low',
235
+ reason: ''
236
+ };
237
+ const detected = [];
238
+ // 从项目上下文检测
239
+ if (context.projectType === 'typescript') {
240
+ detected.push('typescript');
241
+ }
242
+ else if (context.projectType === 'python') {
243
+ detected.push('python');
244
+ }
245
+ else if (context.projectType === 'go') {
246
+ detected.push('go');
247
+ }
248
+ else if (context.projectType === 'rust') {
249
+ detected.push('rust');
250
+ }
251
+ // 从任务描述检测
252
+ const techKeywords = {
253
+ 'typescript': ['typescript', 'ts', 'tsx'],
254
+ 'javascript': ['javascript', 'js', 'jsx'],
255
+ 'react': ['react', 'reactjs'],
256
+ 'vue': ['vue', 'vuejs', 'vue3'],
257
+ 'node': ['node', 'nodejs', 'express', 'koa'],
258
+ 'python': ['python', 'py', 'django', 'flask', 'fastapi'],
259
+ 'go': ['golang', 'go'],
260
+ 'rust': ['rust', 'cargo']
261
+ };
262
+ for (const [tech, keywords] of Object.entries(techKeywords)) {
263
+ if (keywords.some(kw => desc.includes(kw))) {
264
+ if (!detected.includes(tech)) {
265
+ detected.push(tech);
266
+ }
267
+ }
268
+ }
269
+ // 从项目框架检测
270
+ for (const framework of context.frameworks) {
271
+ const normalized = framework.toLowerCase();
272
+ if (!detected.includes(normalized)) {
273
+ detected.push(normalized);
274
+ }
275
+ }
276
+ if (detected.length > 0) {
277
+ inference.inferredAnswer = detected;
278
+ inference.confidence = context.projectType !== 'unknown' ? 'high' : 'medium';
279
+ inference.reason = `检测到技术栈: ${detected.join(', ')}`;
280
+ }
281
+ else {
282
+ inference.reason = '无法检测技术栈';
283
+ }
284
+ return inference;
285
+ }
286
+ /**
287
+ * 推断文档级别
288
+ */
289
+ inferDocLevel(desc, context) {
290
+ const inference = {
291
+ questionId: 'doc_level',
292
+ confidence: 'low',
293
+ reason: ''
294
+ };
295
+ // Bug 修复 -> 无需文档
296
+ if (/(fix|bug|修复|hotfix)/i.test(desc)) {
297
+ inference.inferredAnswer = 'none';
298
+ inference.confidence = 'high';
299
+ inference.reason = 'Bug 修复通常不需要文档';
300
+ return inference;
301
+ }
302
+ // 重构 -> 最小文档
303
+ if (/(refactor|优化|重构)/i.test(desc)) {
304
+ inference.inferredAnswer = 'minimal';
305
+ inference.confidence = 'medium';
306
+ inference.reason = '重构任务通常需要最小文档';
307
+ return inference;
308
+ }
309
+ // API/模块/库 -> 完整文档
310
+ if (/(api|module|library|组件|库|sdk)/i.test(desc)) {
311
+ inference.inferredAnswer = 'full';
312
+ inference.confidence = 'medium';
313
+ inference.reason = 'API/模块开发需要完整文档';
314
+ return inference;
315
+ }
316
+ // 新功能 -> 基础文档
317
+ if (/(implement|add|新功能|实现|开发|feature)/i.test(desc)) {
318
+ inference.inferredAnswer = 'basic';
319
+ inference.confidence = 'medium';
320
+ inference.reason = '新功能开发需要基础文档';
321
+ return inference;
322
+ }
323
+ inference.reason = '无法确定文档需求';
324
+ return inference;
325
+ }
326
+ /**
327
+ * 推断 E2E 测试
328
+ */
329
+ inferE2ETest(desc, context) {
330
+ const inference = {
331
+ questionId: 'e2e_test',
332
+ confidence: 'low',
333
+ reason: ''
334
+ };
335
+ // CLI/后端 -> 不需要 E2E
336
+ if (/(cli|api|backend|后端|命令行)/i.test(desc) && !context.hasFrontend) {
337
+ inference.inferredAnswer = 'false';
338
+ inference.confidence = 'high';
339
+ inference.reason = 'CLI/后端任务不需要 E2E 测试';
340
+ return inference;
341
+ }
342
+ // 前端页面 -> 询问
343
+ if (context.hasFrontend || /(page|ui|前端|界面|web)/i.test(desc)) {
344
+ inference.confidence = 'low';
345
+ inference.reason = '前端任务可能需要 E2E 测试,需要用户确认';
346
+ return inference;
347
+ }
348
+ // 默认不需要
349
+ inference.inferredAnswer = 'false';
350
+ inference.confidence = 'medium';
351
+ inference.reason = '默认不需要 E2E 测试';
352
+ return inference;
353
+ }
354
+ /**
355
+ * 推断执行模式
356
+ */
357
+ inferExecutionMode(desc, context) {
358
+ const inference = {
359
+ questionId: 'execution_mode',
360
+ confidence: 'low',
361
+ reason: ''
362
+ };
363
+ // 快速原型 -> 全自动
364
+ if (/(prototype|poc|demo|快速|原型)/i.test(desc)) {
365
+ inference.inferredAnswer = 'auto';
366
+ inference.confidence = 'medium';
367
+ inference.reason = '原型任务适合全自动执行';
368
+ return inference;
369
+ }
370
+ // 简单修复 -> 全自动
371
+ if (/(fix|bug|修复|hotfix)/i.test(desc) && desc.length < 100) {
372
+ inference.inferredAnswer = 'auto';
373
+ inference.confidence = 'medium';
374
+ inference.reason = '简单 Bug 修复适合全自动执行';
375
+ return inference;
376
+ }
377
+ // 新功能 -> 每阶段确认
378
+ if (/(implement|add|新功能|实现|开发)/i.test(desc)) {
379
+ inference.inferredAnswer = 'phase';
380
+ inference.confidence = 'medium';
381
+ inference.reason = '新功能开发适合每阶段确认';
382
+ return inference;
383
+ }
384
+ inference.reason = '无法确定执行模式';
385
+ return inference;
386
+ }
387
+ /**
388
+ * 生成推断摘要
389
+ */
390
+ generateSummary(result) {
391
+ const lines = ['📊 AI 推断结果:\n'];
392
+ for (const inference of result.inferences) {
393
+ const icon = inference.confidence === 'high' ? '✅' :
394
+ inference.confidence === 'medium' ? '🤔' : '❓';
395
+ const answer = Array.isArray(inference.inferredAnswer)
396
+ ? inference.inferredAnswer.join(', ')
397
+ : inference.inferredAnswer || '待确认';
398
+ lines.push(`${icon} ${inference.questionId}: ${answer}`);
399
+ if (inference.reason) {
400
+ lines.push(` └─ ${inference.reason}`);
401
+ }
402
+ }
403
+ if (result.questionsToAsk.length > 0) {
404
+ lines.push(`\n❓ 需要确认的问题: ${result.questionsToAsk.join(', ')}`);
405
+ }
406
+ else {
407
+ lines.push('\n✅ 所有问题已推断,无需额外确认');
408
+ }
409
+ return lines.join('\n');
410
+ }
411
+ }
412
+ exports.SmartQuestionAnalyzer = SmartQuestionAnalyzer;
@@ -41,8 +41,8 @@ const path = __importStar(require("path"));
41
41
  * 默认配置
42
42
  */
43
43
  exports.DEFAULT_DETECTOR_CONFIG = {
44
- scanDirs: ['src', 'skills', 'tests', 'docs', 'prompts', '.claude', '.cursor'],
45
- excludeDirs: ['node_modules', 'dist', '.git', '.openmatrix'],
44
+ scanDirs: ['src', 'skills', 'docs', 'prompts', '.claude', '.cursor'],
45
+ excludeDirs: ['node_modules', 'dist', '.git', '.openmatrix', 'tests'],
46
46
  categories: ['bug', 'quality', 'capability', 'ux', 'style', 'security', 'common', 'prompt', 'skill', 'agent'],
47
47
  minPriority: 'low'
48
48
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmatrix",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "AI Agent task orchestration system with Claude Code Skills integration",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/skills/check.md CHANGED
@@ -106,9 +106,7 @@ description: 自动检测项目可改进点并提供升级建议,用户确认
106
106
 
107
107
  ---
108
108
 
109
- ## ✅ 下一步
110
-
111
- 回复 **"继续"**、**"可以"**、**"执行"** 或 **"好"** 开始自动修复这些问题。
109
+ **是否继续?**
112
110
  ```
113
111
 
114
112
  如果没有发现问题:
@@ -118,19 +116,7 @@ description: 自动检测项目可改进点并提供升级建议,用户确认
118
116
 
119
117
  4. **等待用户确认**
120
118
 
121
- 展示报告后,等待用户回复。检测用户回复中的确认词语:
122
-
123
- **确认词语列表**:
124
- - 继续、可以、执行、好、是、ok、OK、确认、同意
125
- - continue、yes、ok、sure、go、do it
126
- - 中文变体:行、好的、没问题、没问题啊、走起、开始吧
127
-
128
- **取消词语列表** (用户不想执行):
129
- - 不、不要、取消、算了、跳过
130
- - no、skip、cancel
131
-
132
- 如果用户回复包含确认词语,立即执行下一步。
133
- 如果用户回复包含取消词语,结束流程。
119
+ 展示报告后,等待用户回复。用户回复确认词语(如"是"、"继续"、"好"、"可以"等)即执行下一步。
134
120
 
135
121
  5. **调用 /om:start 执行改进**
136
122
 
@@ -165,8 +151,8 @@ $ARGUMENTS
165
151
  </arguments>
166
152
 
167
153
  <examples>
168
- /check # 自动扫描 → 展示报告 → 用户回复"继续" → 自动执行
169
- /check 安全 # 聚焦安全问题 → 展示报告 → 用户回复"可以" → 自动修复
154
+ /check # 自动扫描 → 展示报告 → 用户回复"" → 自动执行
155
+ /check 安全 # 聚焦安全问题 → 展示报告 → 用户回复"继续" → 自动修复
170
156
  </examples>
171
157
 
172
158
  <notes>
@@ -180,7 +166,7 @@ $ARGUMENTS
180
166
  ├── 2. 展示报告 ──→ 输出 Markdown 格式的检测报告
181
167
  │ (不使用交互式对话框,让用户能看到完整文档)
182
168
 
183
- ├── 3. 等待确认 ──→ 用户回复 "继续" 或 "可以"
169
+ ├── 3. 等待确认 ──→ 用户回复 "" 或 "继续"
184
170
 
185
171
  └── 4. 自动执行 ──→ 调用 /om:start
186
172
 
@@ -210,27 +196,5 @@ $ARGUMENTS
210
196
  1. 完整查看所有检测到的问题
211
197
  2. 仔细阅读每个问题的描述和建议
212
198
  3. 自由决定是否执行修复
213
- 4. 简单回复"继续"即可开始执行
214
-
215
- ## 确认词语检测
216
-
217
- 检测用户回复中是否包含以下词语(不区分大小写):
218
-
219
- | 中文确认 | 英文确认 |
220
- |---------|---------|
221
- | 继续 | continue |
222
- | 可以 | yes / ok / sure |
223
- | 执行 | go / do it |
224
- | 好 / 是 | |
225
- | 确认 / 同意 | |
226
- | 行 / 好的 | |
227
- | 没问题 | |
228
- | 走起 / 开始吧 | |
229
-
230
- 用户回复示例:
231
- - "继续" → 执行
232
- - "可以,开始吧" → 执行
233
- - "好" → 执行
234
- - "先不要" → 不执行
235
- - "跳过" → 不执行
199
+ 4. 简单回复确认即可开始执行
236
200
  </notes>
package/skills/start.md CHANGED
@@ -8,7 +8,7 @@ description: 启动新的任务执行周期
8
8
  </NO-OTHER-SKILLS>
9
9
 
10
10
  <objective>
11
- 解析任务文档,通过交互式问答澄清需求(3-7个问题,支持多轮追问),确认后启动执行。
11
+ 解析任务文档,通过智能分析自动推断配置,仅对不确定的问题进行交互式问答,确认后启动执行。
12
12
  </objective>
13
13
 
14
14
  <process>
@@ -34,18 +34,86 @@ description: 启动新的任务执行周期
34
34
  - 检查是否有远程仓库配置:
35
35
  - 如果没有远程仓库,提示用户添加: `git remote add origin <url>`
36
36
 
37
- 4. **解析任务输入**
37
+ 4. **智能检测 .gitignore**
38
+
39
+ 检查 `.gitignore` 文件是否存在并完善:
40
+ ```bash
41
+ openmatrix check-gitignore --json
42
+ ```
43
+
44
+ 返回结果:
45
+ ```json
46
+ {
47
+ "exists": true,
48
+ "missingEntries": ["node_modules", "dist", ".env"],
49
+ "suggestedContent": "# Node.js\nnode_modules/\ndist/\n\n# Environment\n.env\n.env.local"
50
+ }
51
+ ```
52
+
53
+ **如果缺少常见忽略项**:
54
+ - 自动补充缺失的条目到 `.gitignore`
55
+ - 不询问用户,静默完成
56
+
57
+ **常见忽略项清单** (按项目类型):
58
+
59
+ | 类型 | 忽略项 |
60
+ |------|--------|
61
+ | Node.js | `node_modules/`, `dist/`, `build/`, `.npm/`, `*.log` |
62
+ | TypeScript | `*.tsbuildinfo`, `.tsbuildinfo` |
63
+ | Python | `__pycache__/`, `*.pyc`, `.venv/`, `venv/`, `.pytest_cache/` |
64
+ | Java | `target/`, `.gradle/`, `build/`, `*.class` |
65
+ | Go | `vendor/`, `bin/`, `*.exe` |
66
+ | Rust | `target/`, `Cargo.lock` (库项目) |
67
+ | 通用 | `.env`, `.env.local`, `.DS_Store`, `Thumbs.db`, `*.swp` |
68
+ | IDE | `.idea/`, `.vscode/`, `*.iml` |
69
+
70
+ 5. **解析任务输入**
38
71
  - 如果 `$ARGUMENTS` 提供文件路径 → 读取文件内容
39
72
  - 如果 `$ARGUMENTS` 是任务描述 → 直接使用
40
73
  - 如果无参数 → **使用 AskUserQuestion 询问用户要执行的任务**
41
74
 
42
- 5. **⚠️ 交互式问答 (必须执行)**
75
+ 5. **🔍 智能分析 (新流程)**
76
+
77
+ **首先调用 CLI 进行智能分析:**
78
+ ```bash
79
+ openmatrix analyze --json
80
+ ```
81
+
82
+ 这会返回分析结果:
83
+ ```json
84
+ {
85
+ "inferences": [
86
+ { "questionId": "quality_level", "inferredAnswer": "strict", "confidence": "high", "reason": "任务涉及新功能开发" },
87
+ { "questionId": "tech_stack", "inferredAnswer": ["typescript", "react"], "confidence": "high", "reason": "检测到技术栈: TypeScript, React" },
88
+ { "questionId": "doc_level", "inferredAnswer": "basic", "confidence": "medium", "reason": "新功能开发需要基础文档" }
89
+ ],
90
+ "questionsToAsk": ["e2e_test"],
91
+ "skippedQuestions": ["quality_level", "tech_stack", "doc_level"],
92
+ "projectContext": { "projectType": "typescript", "frameworks": ["React"], "hasFrontend": true }
93
+ }
94
+ ```
95
+
96
+ **展示推断摘要:**
97
+ ```
98
+ 🔍 AI 正在分析任务...
99
+
100
+ 📊 推断结果:
101
+ ✅ 质量级别: strict (任务涉及新功能开发)
102
+ ✅ 技术栈: TypeScript, React (检测到技术栈)
103
+ ✅ 文档级别: 基础文档 (新功能开发需要基础文档)
104
+
105
+ ❓ 需要确认的问题: E2E测试
106
+ ```
107
+
108
+ 6. **⚠️ 交互式问答 (仅针对不确定的问题)**
109
+
110
+ **重要改进**: 现在只对 AI 无法推断或置信度低的问题进行问答。
43
111
 
44
- **重要**: 除非用户明确指定 `--skip-questions` 或提供了 `--quality` 等选项,否则必须执行交互式问答。
112
+ **如果 `questionsToAsk` 为空**: 直接使用推断值,跳过问答。
45
113
 
46
- 使用 `AskUserQuestion` 工具,逐个提出以下问题:
114
+ **如果有需要确认的问题**: 使用 `AskUserQuestion` 逐个提问。
47
115
 
48
- **问题 0: 质量级别 (最重要,第一个问)**
116
+ **问题 0: 质量级别** (仅当 questionsToAsk 包含 "quality_level" 时询问)
49
117
  ```typescript
50
118
  AskUserQuestion({
51
119
  questions: [{
@@ -116,7 +184,7 @@ description: 启动新的任务执行周期
116
184
  })
117
185
  ```
118
186
 
119
- **问题 1: 任务目标**
187
+ **问题 1: 任务目标** (仅当 questionsToAsk 包含 "objective" 时询问)
120
188
  ```typescript
121
189
  AskUserQuestion({
122
190
  questions: [{
@@ -133,7 +201,7 @@ description: 启动新的任务执行周期
133
201
  })
134
202
  ```
135
203
 
136
- **问题 2: 技术栈** (根据任务内容动态生成)
204
+ **问题 2: 技术栈** (仅当 questionsToAsk 包含 "tech_stack" 时询问,否则使用项目检测值)
137
205
  ```typescript
138
206
  AskUserQuestion({
139
207
  questions: [{
@@ -150,7 +218,7 @@ description: 启动新的任务执行周期
150
218
  })
151
219
  ```
152
220
 
153
- **问题 3: 文档要求**
221
+ **问题 3: 文档要求** (仅当 questionsToAsk 包含 "doc_level" 时询问)
154
222
  ```typescript
155
223
  AskUserQuestion({
156
224
  questions: [{