openmatrix 0.1.86 → 0.1.88

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.
@@ -161,6 +161,7 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
161
161
  title: tasksInput.title,
162
162
  description: tasksInput.description || '',
163
163
  goals: tasksInput.goals,
164
+ goalTypes: tasksInput.goalTypes,
164
165
  constraints: tasksInput.constraints || [],
165
166
  deliverables: tasksInput.deliverables || [],
166
167
  rawContent: ''
@@ -23,8 +23,13 @@ export interface CommitResult {
23
23
  */
24
24
  export declare class GitCommitManager {
25
25
  private repoPath;
26
+ private gitRoot;
26
27
  private enabled;
27
28
  constructor(repoPath?: string);
29
+ /**
30
+ * 获取 git 仓库根目录(支持 .git 在父级目录的情况)
31
+ */
32
+ private getGitRoot;
28
33
  /**
29
34
  * 设置是否启用自动提交
30
35
  */
@@ -50,10 +50,27 @@ const execAsync = (0, util_1.promisify)(child_process_1.exec);
50
50
  */
51
51
  class GitCommitManager {
52
52
  repoPath;
53
+ gitRoot = null;
53
54
  enabled = true;
54
55
  constructor(repoPath = process.cwd()) {
55
56
  this.repoPath = repoPath;
56
57
  }
58
+ /**
59
+ * 获取 git 仓库根目录(支持 .git 在父级目录的情况)
60
+ */
61
+ async getGitRoot() {
62
+ if (this.gitRoot)
63
+ return this.gitRoot;
64
+ try {
65
+ const { stdout } = await execAsync('git rev-parse --show-toplevel', { cwd: this.repoPath });
66
+ this.gitRoot = stdout.trim();
67
+ }
68
+ catch {
69
+ // 不是 git 仓库,回退到 repoPath
70
+ this.gitRoot = this.repoPath;
71
+ }
72
+ return this.gitRoot;
73
+ }
57
74
  /**
58
75
  * 设置是否启用自动提交
59
76
  */
@@ -222,22 +239,21 @@ class GitCommitManager {
222
239
  // 检查是否在 Git 仓库中,如果不是则自动初始化
223
240
  if (!await this.isGitRepo()) {
224
241
  await execAsync('git init', { cwd: this.repoPath });
225
- // 确保 .gitignore 存在并包含 .openmatrix
226
- const gitignorePath = path.join(this.repoPath, '.gitignore');
227
- let gitignoreContent = '';
228
- try {
229
- gitignoreContent = await fs.readFile(gitignorePath, 'utf-8');
230
- }
231
- catch {
232
- // 文件不存在
233
- }
234
- if (!gitignoreContent.includes('.openmatrix')) {
235
- const addition = (gitignoreContent && !gitignoreContent.endsWith('\n') ? '\n' : '') + '.openmatrix/\n';
236
- await fs.writeFile(gitignorePath, gitignoreContent + addition, 'utf-8');
237
- }
238
- // 初始提交
239
- await execAsync('git add .gitignore', { cwd: this.repoPath });
240
- await execAsync('git commit -m "initial commit" --allow-empty', { cwd: this.repoPath }).catch(() => { });
242
+ this.gitRoot = this.repoPath; // 刚初始化的仓库,根目录就是 repoPath
243
+ }
244
+ // 确保 .gitignore 中包含 .openmatrix(写入到 git 根目录)
245
+ const gitRoot = await this.getGitRoot();
246
+ const gitignorePath = path.join(gitRoot, '.gitignore');
247
+ let gitignoreContent = '';
248
+ try {
249
+ gitignoreContent = await fs.readFile(gitignorePath, 'utf-8');
250
+ }
251
+ catch {
252
+ // 文件不存在
253
+ }
254
+ if (!gitignoreContent.includes('.openmatrix')) {
255
+ const addition = (gitignoreContent && !gitignoreContent.endsWith('\n') ? '\n' : '') + '.openmatrix/\n';
256
+ await fs.writeFile(gitignorePath, gitignoreContent + addition, 'utf-8');
241
257
  }
242
258
  // 获取未提交的文件
243
259
  const files = await this.getUncommittedFiles();
@@ -267,7 +283,7 @@ class GitCommitManager {
267
283
  };
268
284
  }
269
285
  // 使用临时文件传递 commit message(避免 Windows 下多行消息转义问题)
270
- const tmpFile = path.join(this.repoPath, '.git', 'COMMIT_MSG_TMP');
286
+ const tmpFile = path.join(gitRoot, '.git', 'COMMIT_MSG_TMP');
271
287
  await fs.writeFile(tmpFile, commitMessage, 'utf-8');
272
288
  try {
273
289
  const { stdout } = await execAsync(`git commit -F "${tmpFile}"`, { cwd: this.repoPath });
@@ -82,7 +82,8 @@ ${globalContext}
82
82
  continue;
83
83
  }
84
84
  seenTitles.add(goal);
85
- const goalType = this.classifyGoal(goal);
85
+ // 优先使用 AI 标注的类型,fallback 到关键词检测
86
+ const goalType = parsedTask.goalTypes?.[i] ?? this.classifyGoal(goal);
86
87
  const deps = designTaskId ? [designTaskId] : [];
87
88
  if (goalType === 'development') {
88
89
  // 开发类目标: 拆分为实现 + 测试 对
@@ -204,10 +204,14 @@ export interface ParsedTask {
204
204
  title: string;
205
205
  description: string;
206
206
  goals: string[];
207
+ /** 每个 goal 的类型标注 (由 AI 在提取时标注),与 goals 数组一一对应 */
208
+ goalTypes?: GoalType[];
207
209
  constraints: string[];
208
210
  deliverables: string[];
209
211
  rawContent: string;
210
212
  }
213
+ /** 目标类型 */
214
+ export type GoalType = 'development' | 'testing' | 'documentation' | 'other';
211
215
  export interface ResearchAgentConfig {
212
216
  role: string;
213
217
  focus: string;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * 确保指定目录被 git 忽略
3
- * @param basePath 项目根目录
3
+ * @param basePath 项目目录(可以是 git 仓库的子目录)
4
4
  * @param ignorePattern 要忽略的模式 (默认 .openmatrix/)
5
5
  */
6
6
  export declare function ensureGitignore(basePath: string, ignorePattern?: string): Promise<void>;
@@ -38,13 +38,30 @@ exports.ensureOpenmatrixGitignore = ensureOpenmatrixGitignore;
38
38
  // src/utils/gitignore.ts
39
39
  const fs = __importStar(require("fs/promises"));
40
40
  const path = __importStar(require("path"));
41
+ const child_process_1 = require("child_process");
42
+ const util_1 = require("util");
43
+ const execAsync = (0, util_1.promisify)(child_process_1.exec);
44
+ /**
45
+ * 获取 git 仓库根目录(支持 .git 在父级目录的情况)
46
+ */
47
+ async function getGitRoot(basePath) {
48
+ try {
49
+ const { stdout } = await execAsync('git rev-parse --show-toplevel', { cwd: basePath });
50
+ return stdout.trim();
51
+ }
52
+ catch {
53
+ return basePath;
54
+ }
55
+ }
41
56
  /**
42
57
  * 确保指定目录被 git 忽略
43
- * @param basePath 项目根目录
58
+ * @param basePath 项目目录(可以是 git 仓库的子目录)
44
59
  * @param ignorePattern 要忽略的模式 (默认 .openmatrix/)
45
60
  */
46
61
  async function ensureGitignore(basePath, ignorePattern = '.openmatrix/') {
47
- const gitignorePath = path.join(basePath, '.gitignore');
62
+ // 写入到 git 根目录的 .gitignore
63
+ const gitRoot = await getGitRoot(basePath);
64
+ const gitignorePath = path.join(gitRoot, '.gitignore');
48
65
  try {
49
66
  const content = await fs.readFile(gitignorePath, 'utf-8');
50
67
  // 检查是否已经包含该模式
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmatrix",
3
- "version": "0.1.86",
3
+ "version": "0.1.88",
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/start.md CHANGED
@@ -230,10 +230,25 @@ AskUserQuestion({
230
230
 
231
231
  从任务描述中提取:
232
232
  - **goals**: 至少 3-8 个明确功能目标,每个是独立可交付模块
233
+ - **goalTypes**: 为每个 goal 标注类型,影响任务拆分策略:
234
+ - `development` — 需要编写代码的功能/模块实现 → 拆分为"实现+测试"任务对
235
+ - `testing` — 明确的测试任务(如"编写 E2E 测试"、"所有模块的单元测试")→ 单个测试任务
236
+ - `documentation` — 文档编写(如"编写 API 文档"、"更新 README")→ 单个文档任务
237
+ - `other` — 配置、部署、优化等非编码任务 → 单个任务
233
238
  - **constraints**: 技术栈、兼容性等约束
234
239
  - **deliverables**: 交付物列表
235
240
  - **plan**: 技术方案、模块划分、接口设计、关键决策
236
241
 
242
+ **goalTypes 标注示例:**
243
+
244
+ | Goal | Type | 理由 |
245
+ |------|------|------|
246
+ | "项目脚手架: Vite+TS 配置" | development | 需要写代码搭建 |
247
+ | "GameLoop 60fps 游戏循环" | development | 功能实现 |
248
+ | "所有核心模块的单元测试" | testing | 已是测试任务 |
249
+ | "API 文档编写" | documentation | 文档类 |
250
+ | "CI/CD 流水线配置" | other | 配置类 |
251
+
237
252
  ### Step 7: 写入 tasks-input.json
238
253
 
239
254
  用 Write 工具写入 `.openmatrix/tasks-input.json`:
@@ -243,6 +258,7 @@ AskUserQuestion({
243
258
  "title": "任务标题",
244
259
  "description": "整体描述",
245
260
  "goals": ["目标1", "目标2", "目标3"],
261
+ "goalTypes": ["development", "testing", "documentation"],
246
262
  "constraints": ["约束1"],
247
263
  "deliverables": ["src/xxx.ts"],
248
264
  "plan": "## 技术方案\n1. ...\n2. ..."
@@ -250,6 +266,7 @@ AskUserQuestion({
250
266
  ```
251
267
 
252
268
  > **注意**: `quality`、`mode`、`e2eTests` 不写入文件,由 Step 8 的 CLI 参数传递。
269
+ > **goalTypes** 必须与 goals 数组长度一致,一一对应。
253
270
 
254
271
  ### Step 8: 调用 CLI 创建任务 ⚠️ 不可跳过
255
272