openmatrix 0.2.27 → 0.2.29

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.
@@ -40,12 +40,16 @@ const fs = __importStar(require("fs"));
40
40
  const path = __importStar(require("path"));
41
41
  const os = __importStar(require("os"));
42
42
  exports.installSkillsCommand = new commander_1.Command('install-skills')
43
- .description('Install OpenMatrix skills to ~/.claude/commands/om/')
43
+ .description('Install OpenMatrix skills to ~/.claude/commands/om/ and ~/.matrix/skills/om/ (if MatrixCode detected)')
44
44
  .option('-f, --force', 'Force overwrite existing skills', false)
45
45
  .action((options) => {
46
46
  const skillsDir = path.join(__dirname, '..', '..', '..', 'skills');
47
47
  const claudeDir = path.join(os.homedir(), '.claude');
48
- const commandsDir = path.join(claudeDir, 'commands', 'om');
48
+ const claudeCommandsDir = path.join(claudeDir, 'commands', 'om');
49
+ // Check for MatrixCode installation
50
+ const matrixDir = path.join(os.homedir(), '.matrix');
51
+ const matrixSkillsDir = path.join(matrixDir, 'skills', 'om');
52
+ const hasMatrixCode = fs.existsSync(matrixDir);
49
53
  console.log('📦 OpenMatrix Skills Installer\n');
50
54
  // Check if skills directory exists
51
55
  if (!fs.existsSync(skillsDir)) {
@@ -53,106 +57,124 @@ exports.installSkillsCommand = new commander_1.Command('install-skills')
53
57
  console.error(' Make sure openmatrix is installed correctly.');
54
58
  process.exit(1);
55
59
  }
56
- // Create commands directory
57
- try {
58
- if (!fs.existsSync(commandsDir)) {
59
- fs.mkdirSync(commandsDir, { recursive: true });
60
- console.log('📁 Created directory:', commandsDir);
61
- }
62
- }
63
- catch (err) {
64
- console.error('❌ Cannot create directory:', commandsDir);
65
- console.error(' Error:', err instanceof Error ? err.message : String(err));
66
- process.exit(1);
67
- }
68
- // Get skill files (excluding om.md and openmatrix.md which are handled separately)
60
+ // Define target directories
61
+ const targets = [
62
+ { name: 'Claude Code', dir: claudeCommandsDir, enabled: true },
63
+ { name: 'MatrixCode', dir: matrixSkillsDir, enabled: hasMatrixCode },
64
+ ];
65
+ // Get skill files
69
66
  const files = fs.readdirSync(skillsDir).filter(f => f.endsWith('.md') && f !== 'om.md' && f !== 'openmatrix.md');
70
67
  if (files.length === 0) {
71
68
  console.error('❌ No skill files found in:', skillsDir);
72
69
  process.exit(1);
73
70
  }
74
71
  console.log(`📋 Found ${files.length} skill files\n`);
75
- let installed = 0;
76
- let skipped = 0;
77
- let failed = 0;
78
- // Install skill files to ~/.claude/commands/om/
79
- files.forEach(file => {
80
- const src = path.join(skillsDir, file);
81
- const dest = path.join(commandsDir, file);
72
+ let totalInstalled = 0;
73
+ let totalSkipped = 0;
74
+ let totalFailed = 0;
75
+ // Install to each target
76
+ for (const target of targets) {
77
+ if (!target.enabled) {
78
+ console.log(`⏭️ ${target.name}: skipped (not installed)`);
79
+ continue;
80
+ }
81
+ console.log(`\n🔧 Installing to ${target.name}...`);
82
82
  try {
83
- // Check if file exists and not forcing
84
- if (fs.existsSync(dest) && !options.force) {
85
- console.log(` ⏭️ Skipped: ${file} (already exists)`);
86
- skipped++;
87
- return;
83
+ if (!fs.existsSync(target.dir)) {
84
+ fs.mkdirSync(target.dir, { recursive: true });
85
+ console.log(`📁 Created directory: ${target.dir}`);
88
86
  }
89
- fs.copyFileSync(src, dest);
90
- const skillName = path.basename(file, '.md');
91
- console.log(` ✅ Installed: /om:${skillName}`);
92
- installed++;
93
87
  }
94
88
  catch (err) {
95
- console.log(` ❌ Failed: ${file} (${err instanceof Error ? err.message : String(err)})`);
96
- failed++;
89
+ console.error(`❌ Cannot create directory: ${target.dir}`);
90
+ console.error(` Error: ${err instanceof Error ? err.message : String(err)}`);
91
+ continue;
97
92
  }
98
- });
99
- // Install default /om command to ~/.claude/commands/om.md
100
- const omSrc = path.join(skillsDir, 'om.md');
101
- const omDest = path.join(claudeDir, 'commands', 'om.md');
102
- if (fs.existsSync(omSrc)) {
103
- try {
104
- if (fs.existsSync(omDest) && !options.force) {
105
- console.log(` ⏭️ Skipped: om.md (already exists)`);
106
- skipped++;
107
- }
108
- else {
109
- fs.copyFileSync(omSrc, omDest);
110
- console.log(` ✅ Installed: /om (default entry)`);
93
+ let installed = 0;
94
+ let skipped = 0;
95
+ let failed = 0;
96
+ // Install skill files
97
+ files.forEach(file => {
98
+ const src = path.join(skillsDir, file);
99
+ const dest = path.join(target.dir, file);
100
+ try {
101
+ if (fs.existsSync(dest) && !options.force) {
102
+ skipped++;
103
+ return;
104
+ }
105
+ fs.copyFileSync(src, dest);
111
106
  installed++;
112
107
  }
113
- }
114
- catch (err) {
115
- console.log(` ❌ Failed: om.md (${err instanceof Error ? err.message : String(err)})`);
116
- failed++;
117
- }
118
- }
119
- // Install auto-detection instructions
120
- const autoSrc = path.join(skillsDir, 'openmatrix.md');
121
- const autoDest = path.join(claudeDir, 'commands', 'openmatrix.md');
122
- if (fs.existsSync(autoSrc)) {
123
- try {
124
- if (fs.existsSync(autoDest) && !options.force) {
125
- console.log(` ⏭️ Skipped: openmatrix.md (already exists)`);
126
- skipped++;
108
+ catch (err) {
109
+ console.log(` ❌ Failed: ${file} (${err instanceof Error ? err.message : String(err)})`);
110
+ failed++;
127
111
  }
128
- else {
129
- fs.copyFileSync(autoSrc, autoDest);
130
- console.log(` ✅ Installed: /om:openmatrix (auto-detection)`);
131
- installed++;
112
+ });
113
+ // Install om.md to parent directory for Claude Code
114
+ if (target.name === 'Claude Code') {
115
+ const omSrc = path.join(skillsDir, 'om.md');
116
+ const omDest = path.join(claudeDir, 'commands', 'om.md');
117
+ if (fs.existsSync(omSrc)) {
118
+ try {
119
+ if (fs.existsSync(omDest) && !options.force) {
120
+ skipped++;
121
+ }
122
+ else {
123
+ fs.copyFileSync(omSrc, omDest);
124
+ installed++;
125
+ }
126
+ }
127
+ catch (err) {
128
+ failed++;
129
+ }
130
+ }
131
+ // Install openmatrix.md (auto-detection)
132
+ const autoSrc = path.join(skillsDir, 'openmatrix.md');
133
+ const autoDest = path.join(claudeDir, 'commands', 'openmatrix.md');
134
+ if (fs.existsSync(autoSrc)) {
135
+ try {
136
+ if (fs.existsSync(autoDest) && !options.force) {
137
+ skipped++;
138
+ }
139
+ else {
140
+ fs.copyFileSync(autoSrc, autoDest);
141
+ installed++;
142
+ }
143
+ }
144
+ catch (err) {
145
+ failed++;
146
+ }
132
147
  }
133
148
  }
134
- catch (err) {
135
- console.log(` ❌ Failed: openmatrix.md (${err instanceof Error ? err.message : String(err)})`);
136
- failed++;
149
+ console.log(` ✅ Installed: ${installed}`);
150
+ console.log(` ⏭️ Skipped: ${skipped}`);
151
+ if (failed > 0) {
152
+ console.log(` ❌ Failed: ${failed}`);
137
153
  }
154
+ totalInstalled += installed;
155
+ totalSkipped += skipped;
156
+ totalFailed += failed;
138
157
  }
139
158
  console.log('\n' + '─'.repeat(50));
140
- console.log(`📊 Summary:`);
141
- console.log(` ✅ Installed: ${installed}`);
142
- console.log(` ⏭️ Skipped: ${skipped}`);
143
- console.log(` ❌ Failed: ${failed}`);
144
- console.log(`\n📁 Skills: ${commandsDir}`);
145
- console.log(`📁 Default: ${omDest}`);
146
- if (installed > 0) {
159
+ console.log(`📊 Total Summary:`);
160
+ console.log(` ✅ Installed: ${totalInstalled}`);
161
+ console.log(` ⏭️ Skipped: ${totalSkipped}`);
162
+ console.log(` ❌ Failed: ${totalFailed}`);
163
+ console.log('\n📁 Installation locations:');
164
+ for (const target of targets) {
165
+ if (target.enabled) {
166
+ console.log(` ${target.name}: ${target.dir}`);
167
+ }
168
+ }
169
+ if (totalInstalled > 0) {
147
170
  console.log('\n🎉 Skills installed successfully!');
148
171
  console.log(' Try: /om <your task>');
149
172
  console.log(' Or: /om:start <your task>');
150
- console.log('\n💡 Auto-detection enabled!');
151
- console.log(' Type task descriptions directly:');
152
- console.log(' - "实现用户登录功能" → auto invokes /om:start');
153
- console.log(' - "fix the login bug" → auto invokes /om:start');
154
173
  }
155
- if (failed > 0) {
174
+ if (hasMatrixCode) {
175
+ console.log('\n✅ MatrixCode detected! Skills also installed to ~/.matrix/skills/om/');
176
+ }
177
+ if (totalFailed > 0) {
156
178
  process.exit(1);
157
179
  }
158
180
  });
@@ -1,4 +1,5 @@
1
1
  import type { Task } from '../types/index.js';
2
+ import { WorktreeSyncManager } from '../utils/worktree-sync.js';
2
3
  export interface CommitInfo {
3
4
  taskId: string;
4
5
  taskTitle: string;
@@ -25,6 +26,7 @@ export declare class GitCommitManager {
25
26
  private repoPath;
26
27
  private gitRoot;
27
28
  private enabled;
29
+ private worktreeSyncManager;
28
30
  constructor(repoPath?: string);
29
31
  /**
30
32
  * 获取 git 仓库根目录(支持 .git 在父级目录的情况)
@@ -107,4 +109,15 @@ export declare class GitCommitManager {
107
109
  * 提交验收阶段完成
108
110
  */
109
111
  commitAcceptComplete(task: Task, runId: string): Promise<CommitResult>;
112
+ /**
113
+ * 同步 worktree 改动到主工作树
114
+ *
115
+ * 当 Agent 在 worktree 中工作时,改动会提交到 worktree 的分支。
116
+ * 此方法将这些改动同步回主工作树,确保提交可见。
117
+ */
118
+ private syncWorktreeChanges;
119
+ /**
120
+ * 获取 WorktreeSyncManager 实例(供外部调用)
121
+ */
122
+ getWorktreeSyncManager(): WorktreeSyncManager;
110
123
  }
@@ -41,6 +41,7 @@ const path = __importStar(require("path"));
41
41
  const fs = __importStar(require("fs/promises"));
42
42
  const gitignore_js_1 = require("../utils/gitignore.js");
43
43
  const error_handler_js_1 = require("../utils/error-handler.js");
44
+ const worktree_sync_js_1 = require("../utils/worktree-sync.js");
44
45
  const execAsync = (0, util_1.promisify)(child_process_1.exec);
45
46
  /**
46
47
  * GitCommitManager - Git 自动提交管理器
@@ -54,8 +55,10 @@ class GitCommitManager {
54
55
  repoPath;
55
56
  gitRoot = null;
56
57
  enabled = true;
58
+ worktreeSyncManager;
57
59
  constructor(repoPath = process.cwd()) {
58
60
  this.repoPath = repoPath;
61
+ this.worktreeSyncManager = new worktree_sync_js_1.WorktreeSyncManager(repoPath);
59
62
  }
60
63
  /**
61
64
  * 获取 git 仓库根目录(支持 .git 在父级目录的情况)
@@ -329,6 +332,8 @@ class GitCommitManager {
329
332
  }
330
333
  // 确保 .gitignore 中包含 .openmatrix(写入到 git 根目录)
331
334
  await (0, gitignore_js_1.ensureOpenmatrixGitignore)(this.repoPath);
335
+ // 🔄 同步 worktree 改动到主工作树(关键步骤)
336
+ await this.syncWorktreeChanges();
332
337
  // 获取未提交的文件(用于生成 commit message,在 git add 之前获取)
333
338
  const files = await this.getUncommittedFiles();
334
339
  if (files.length === 0) {
@@ -449,5 +454,57 @@ class GitCommitManager {
449
454
  impactScope: []
450
455
  });
451
456
  }
457
+ /**
458
+ * 同步 worktree 改动到主工作树
459
+ *
460
+ * 当 Agent 在 worktree 中工作时,改动会提交到 worktree 的分支。
461
+ * 此方法将这些改动同步回主工作树,确保提交可见。
462
+ */
463
+ async syncWorktreeChanges() {
464
+ try {
465
+ // 检查是否有 Agent worktree
466
+ const hasChanges = await this.worktreeSyncManager.hasUnsyncedChanges();
467
+ if (!hasChanges) {
468
+ console.log('✅ 未检测到 worktree 改动,跳过同步');
469
+ return;
470
+ }
471
+ console.log('🔄 检测到 worktree 改动,开始同步...');
472
+ // 执行完整同步
473
+ const { syncResults, cleanupResults } = await this.worktreeSyncManager.fullSync();
474
+ // 输出同步结果
475
+ for (const result of syncResults) {
476
+ if (result.success && result.syncedFiles.length > 0) {
477
+ console.log(`✅ 同步成功: ${result.syncedFiles.length} 个文件`);
478
+ console.log(` 文件: ${result.syncedFiles.slice(0, 5).join(', ')}${result.syncedFiles.length > 5 ? '...' : ''}`);
479
+ if (result.commitHash) {
480
+ console.log(` 来源提交: ${result.commitHash}`);
481
+ }
482
+ }
483
+ else if (result.error) {
484
+ console.log(`⚠️ 同步跳过: ${result.error}`);
485
+ }
486
+ }
487
+ // 输出清理结果
488
+ for (const cleanup of cleanupResults) {
489
+ if (cleanup.success) {
490
+ console.log(`🧹 清理 worktree: ${cleanup.path}`);
491
+ }
492
+ else {
493
+ console.log(`⚠️ 清理失败: ${cleanup.path}`);
494
+ }
495
+ }
496
+ }
497
+ catch (error) {
498
+ // 同步失败不应该阻止提交,但需要记录警告
499
+ console.warn('⚠️ Worktree 同步失败:', error instanceof Error ? error.message : String(error));
500
+ (0, error_handler_js_1.logError)(error, { operation: 'syncWorktreeChanges', file: this.repoPath });
501
+ }
502
+ }
503
+ /**
504
+ * 获取 WorktreeSyncManager 实例(供外部调用)
505
+ */
506
+ getWorktreeSyncManager() {
507
+ return this.worktreeSyncManager;
508
+ }
452
509
  }
453
510
  exports.GitCommitManager = GitCommitManager;
@@ -124,6 +124,8 @@ const GITIGNORE_TEMPLATES = {
124
124
  ],
125
125
  openmatrix: [
126
126
  '.openmatrix/',
127
+ '.claude/worktrees/',
128
+ '.playwright-mcp/',
127
129
  ],
128
130
  };
129
131
  /**
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Worktree 同步结果
3
+ */
4
+ export interface WorktreeSyncResult {
5
+ success: boolean;
6
+ syncedFiles: string[];
7
+ commitHash?: string;
8
+ branch?: string;
9
+ error?: string;
10
+ }
11
+ /**
12
+ * Worktree 信息
13
+ */
14
+ export interface WorktreeInfo {
15
+ path: string;
16
+ branch: string;
17
+ commit: string;
18
+ isMain: boolean;
19
+ }
20
+ /**
21
+ * WorktreeSyncManager - 管理 Git Worktree 同步
22
+ *
23
+ * 当 Agent 在 worktree 中工作时,改动会提交到 worktree 的分支。
24
+ * 此类负责将这些改动同步回主工作树。
25
+ *
26
+ * 同步策略:
27
+ * 1. 检测 Agent 创建的 worktree
28
+ * 2. 获取 worktree 中的提交和改动文件
29
+ * 3. 将改动文件复制到主工作树(或 cherry-pick 提交)
30
+ * 4. 清理临时 worktree
31
+ */
32
+ export declare class WorktreeSyncManager {
33
+ private repoPath;
34
+ private gitRoot;
35
+ constructor(repoPath?: string);
36
+ /**
37
+ * 获取 git 仓库根目录
38
+ */
39
+ private getGitRoot;
40
+ /**
41
+ * 列出所有 worktree
42
+ */
43
+ listWorktrees(): Promise<WorktreeInfo[]>;
44
+ /**
45
+ * 获取 Agent worktree 目录
46
+ *
47
+ * Claude Code 创建的 worktree 通常在 .claude/worktrees/ 目录下
48
+ */
49
+ getAgentWorktrees(): Promise<WorktreeInfo[]>;
50
+ /**
51
+ * 获取 worktree 相对于主工作树的改动
52
+ */
53
+ getWorktreeChanges(worktreePath: string): Promise<string[]>;
54
+ /**
55
+ * 获取 worktree 中最新提交的改动文件
56
+ */
57
+ getLatestCommitChanges(worktreePath: string): Promise<string[]>;
58
+ /**
59
+ * 同步 worktree 改动到主工作树
60
+ *
61
+ * 策略:
62
+ * 1. 获取 worktree 中已提交但未同步的改动
63
+ * 2. 将改动文件复制到主工作树
64
+ * 3. 在主工作树中暂存这些文件
65
+ *
66
+ * @param worktreePath worktree 路径(可选,不提供则自动检测所有 Agent worktree)
67
+ */
68
+ syncWorktreeToMain(worktreePath?: string): Promise<WorktreeSyncResult[]>;
69
+ /**
70
+ * Cherry-pick worktree 的提交到主工作树
71
+ *
72
+ * 替代方案:直接 cherry-pick worktree 的提交
73
+ * 适用于:改动较大、需要保留完整提交历史的场景
74
+ */
75
+ cherryPickWorktreeCommit(worktreePath: string): Promise<WorktreeSyncResult>;
76
+ /**
77
+ * 清理已同步的 worktree
78
+ */
79
+ cleanupWorktree(worktreePath: string): Promise<boolean>;
80
+ /**
81
+ * 完整的同步流程
82
+ *
83
+ * 1. 检测所有 Agent worktree
84
+ * 2. 同步改动到主工作树
85
+ * 3. 清理 worktree
86
+ *
87
+ * @returns 同步结果
88
+ */
89
+ fullSync(): Promise<{
90
+ syncResults: WorktreeSyncResult[];
91
+ cleanupResults: {
92
+ path: string;
93
+ success: boolean;
94
+ }[];
95
+ }>;
96
+ /**
97
+ * 检查是否有未同步的 worktree 改动
98
+ */
99
+ hasUnsyncedChanges(): Promise<boolean>;
100
+ }