openmatrix 0.2.26 → 0.2.28

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.
@@ -206,8 +206,23 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
206
206
  if (jsonStr.startsWith('@')) {
207
207
  const filePath = jsonStr.slice(1);
208
208
  // 如果是相对路径,转换为绝对路径
209
- const resolvedPath = path.isAbsolute(filePath) ? filePath : path.join(basePath, filePath);
210
- jsonStr = await fs.readFile(resolvedPath, 'utf-8');
209
+ let resolvedPath = path.isAbsolute(filePath) ? filePath : path.join(basePath, filePath);
210
+ // 特殊处理:如果文件名是 tasks-input.json 且不带路径,尝试从 runId 目录读取
211
+ if (filePath === 'tasks-input.json' || filePath.endsWith('/tasks-input.json')) {
212
+ // 先尝试从 runId 目录读取
213
+ const state = await stateManager.getState();
214
+ const runIdPath = path.join(omPath, state.runId, 'tasks-input.json');
215
+ try {
216
+ jsonStr = await fs.readFile(runIdPath, 'utf-8');
217
+ }
218
+ catch {
219
+ // 如果 runId 目录不存在,尝试原有路径
220
+ jsonStr = await fs.readFile(resolvedPath, 'utf-8');
221
+ }
222
+ }
223
+ else {
224
+ jsonStr = await fs.readFile(resolvedPath, 'utf-8');
225
+ }
211
226
  }
212
227
  tasksInput = JSON.parse(jsonStr);
213
228
  }
@@ -241,18 +256,14 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
241
256
  console.log(`🔬 已加载研究领域: ${researchContext.domain}`);
242
257
  }
243
258
  }
244
- // 读取独立的技术方案文档(plan.md)
259
+ // 读取独立的技术方案文档(从当前 runId 目录)
245
260
  let planContent;
246
- const planPath = path.join(omPath, 'plan.md');
247
- try {
248
- planContent = await fs.readFile(planPath, 'utf-8');
249
- if (!options.json) {
250
- console.log(`📄 已加载技术方案: plan.md`);
251
- }
252
- }
253
- catch {
254
- // plan.md 不存在时继续(可能由 AI 后续生成或无 plan)
261
+ planContent = await stateManager.getPlan();
262
+ if (planContent && !options.json) {
263
+ console.log(`📄 已加载技术方案: plan.md`);
255
264
  }
265
+ // 转换为 string | undefined(供 TaskPlanner 使用)
266
+ const planContentForPlanner = planContent || undefined;
256
267
  // 构建 ParsedTask
257
268
  const parsedTask = {
258
269
  title: resolvedInput.title || tasksInput.title,
@@ -285,7 +296,7 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
285
296
  }
286
297
  // 使用 TaskPlanner 拆分(保持原有拆分逻辑)
287
298
  const planner = new task_planner_js_1.TaskPlanner();
288
- const subTasks = planner.breakdown(parsedTask, extraAnswers, qualityConfig, planContent);
299
+ const subTasks = planner.breakdown(parsedTask, extraAnswers, qualityConfig, planContentForPlanner);
289
300
  // 创建任务到状态管理器,并建立 ID 映射
290
301
  // TaskPlanner 生成的 taskId 和 StateManager 创建的 id 不同,
291
302
  // 需要映射后才能正确设置 dependencies
@@ -70,7 +70,19 @@ async function showStatus(manager, reporter, options) {
70
70
  const state = await manager.getState();
71
71
  const tasks = await manager.listTasks();
72
72
  if (options.json) {
73
- console.log(JSON.stringify({ state, tasks }, null, 2));
73
+ // 添加文件状态字段
74
+ const hasPlan = await manager.hasPlan();
75
+ const hasTasksInput = await manager.hasTasksInput();
76
+ const hasResearchContext = await manager.hasResearchContext();
77
+ console.log(JSON.stringify({
78
+ state,
79
+ tasks,
80
+ files: {
81
+ hasPlan,
82
+ hasTasksInput,
83
+ hasResearchContext
84
+ }
85
+ }, null, 2));
74
86
  return;
75
87
  }
76
88
  // Header
@@ -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;
@@ -62,6 +62,114 @@ export declare class StateManager {
62
62
  updateApproval(approval: Approval): Promise<void>;
63
63
  getApprovalsByStatus(status: ApprovalStatus): Promise<Approval[]>;
64
64
  getAllApprovals(): Promise<Approval[]>;
65
+ /**
66
+ * 保存技术方案文档 (plan.md)
67
+ * 路径: .openmatrix/{runId}/plan.md
68
+ */
69
+ savePlan(content: string): Promise<void>;
70
+ /**
71
+ * 读取技术方案文档
72
+ * @returns plan.md 内容,不存在返回 null
73
+ */
74
+ getPlan(): Promise<string | null>;
75
+ /**
76
+ * 检查 plan.md 是否存在
77
+ */
78
+ hasPlan(): Promise<boolean>;
79
+ /**
80
+ * 保存任务输入元数据
81
+ * 路径: .openmatrix/{runId}/tasks-input.json
82
+ */
83
+ saveTasksInput(data: {
84
+ title: string;
85
+ description?: string;
86
+ goals: string[];
87
+ goalTypes?: string[];
88
+ goalComplexity?: ('low' | 'medium' | 'high')[];
89
+ constraints?: string[];
90
+ deliverables?: string[];
91
+ answers?: Record<string, string>;
92
+ }): Promise<void>;
93
+ /**
94
+ * 读取任务输入元数据
95
+ * @returns tasks-input.json 数据,不存在返回 null
96
+ */
97
+ getTasksInput(): Promise<{
98
+ title: string;
99
+ description?: string;
100
+ goals: string[];
101
+ goalTypes?: string[];
102
+ goalComplexity?: ('low' | 'medium' | 'high')[];
103
+ constraints?: string[];
104
+ deliverables?: string[];
105
+ answers?: Record<string, string>;
106
+ } | null>;
107
+ /**
108
+ * 检查 tasks-input.json 是否存在
109
+ */
110
+ hasTasksInput(): Promise<boolean>;
111
+ /**
112
+ * 保存研究会话
113
+ * 路径: .openmatrix/{runId}/research/session.json
114
+ */
115
+ saveResearchSession(session: Record<string, unknown>): Promise<void>;
116
+ /**
117
+ * 读取研究会话
118
+ */
119
+ getResearchSession(): Promise<Record<string, unknown> | null>;
120
+ /**
121
+ * 保存研究报告
122
+ */
123
+ saveResearchReport(content: string): Promise<void>;
124
+ /**
125
+ * 读取研究报告
126
+ */
127
+ getResearchReport(): Promise<string | null>;
128
+ /**
129
+ * 保存研究上下文 (供 start 使用)
130
+ */
131
+ saveResearchContext(context: {
132
+ topic: string;
133
+ domain: string;
134
+ goals?: string[];
135
+ constraints?: string[];
136
+ deliverables?: string[];
137
+ reportPath?: string;
138
+ knowledgePath?: string;
139
+ }): Promise<void>;
140
+ /**
141
+ * 读取研究上下文
142
+ */
143
+ getResearchContext(): Promise<{
144
+ topic: string;
145
+ domain: string;
146
+ goals?: string[];
147
+ constraints?: string[];
148
+ deliverables?: string[];
149
+ reportPath?: string;
150
+ knowledgePath?: string;
151
+ } | null>;
152
+ /**
153
+ * 检查研究上下文是否存在
154
+ */
155
+ hasResearchContext(): Promise<boolean>;
156
+ /**
157
+ * 保存知识条目
158
+ */
159
+ saveKnowledgeFinding(index: number, content: string): Promise<void>;
160
+ /**
161
+ * 保存头脑风暴会话
162
+ */
163
+ saveBrainstormSession(session: Record<string, unknown>): Promise<void>;
164
+ /**
165
+ * 读取头脑风暴会话
166
+ */
167
+ getBrainstormSession(): Promise<Record<string, unknown> | null>;
168
+ /**
169
+ * 迁移旧版本文件到 runId 目录
170
+ * 只在首次检测到旧文件时执行
171
+ */
172
+ migrateFromLegacy(): Promise<void>;
65
173
  saveMeeting(meeting: Meeting): Promise<void>;
66
174
  getMeeting(meetingId: string): Promise<Meeting | null>;
67
175
  getMeetingsByStatus(status: MeetingStatus): Promise<Meeting[]>;
@@ -110,6 +110,8 @@ class StateManager {
110
110
  retry_queue: existing.statistics?.retry_queue ?? 0
111
111
  };
112
112
  this.stateCache = existing;
113
+ // 迁移旧版本文件到 runId 目录
114
+ await this.migrateFromLegacy();
113
115
  return;
114
116
  }
115
117
  }
@@ -151,12 +153,17 @@ class StateManager {
151
153
  if (oldRunId) {
152
154
  await this.rootStore.removeDir(oldRunId);
153
155
  }
154
- // 兼容旧版本的目录
156
+ // 兼容旧版本的目录和文件(根目录)
155
157
  await this.rootStore.removeDir('tasks');
156
158
  await this.rootStore.removeDir('approvals');
157
159
  await this.rootStore.removeDir('meetings');
158
160
  await this.rootStore.removeDir('runs');
161
+ await this.rootStore.removeDir('research');
162
+ await this.rootStore.removeDir('brainstorm');
159
163
  await this.rootStore.removeFile('context.md');
164
+ await this.rootStore.removeFile('plan.md');
165
+ await this.rootStore.removeFile('tasks-input.json');
166
+ await this.rootStore.removeFile('state.json');
160
167
  // 创建新运行
161
168
  const runId = this.generateRunId();
162
169
  this.store = new file_store_js_1.FileStore((0, path_1.join)(this.basePath, runId));
@@ -443,6 +450,167 @@ class StateManager {
443
450
  }
444
451
  return approvals.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
445
452
  }
453
+ // ============ Plan Methods ============
454
+ /**
455
+ * 保存技术方案文档 (plan.md)
456
+ * 路径: .openmatrix/{runId}/plan.md
457
+ */
458
+ async savePlan(content) {
459
+ await this.store.writeMarkdown('plan.md', content);
460
+ }
461
+ /**
462
+ * 读取技术方案文档
463
+ * @returns plan.md 内容,不存在返回 null
464
+ */
465
+ async getPlan() {
466
+ return await this.store.readMarkdown('plan.md');
467
+ }
468
+ /**
469
+ * 检查 plan.md 是否存在
470
+ */
471
+ async hasPlan() {
472
+ return await this.store.exists('plan.md');
473
+ }
474
+ // ============ TasksInput Methods ============
475
+ /**
476
+ * 保存任务输入元数据
477
+ * 路径: .openmatrix/{runId}/tasks-input.json
478
+ */
479
+ async saveTasksInput(data) {
480
+ await this.store.writeJson('tasks-input.json', data);
481
+ }
482
+ /**
483
+ * 读取任务输入元数据
484
+ * @returns tasks-input.json 数据,不存在返回 null
485
+ */
486
+ async getTasksInput() {
487
+ return await this.store.readJson('tasks-input.json');
488
+ }
489
+ /**
490
+ * 检查 tasks-input.json 是否存在
491
+ */
492
+ async hasTasksInput() {
493
+ return await this.store.exists('tasks-input.json');
494
+ }
495
+ // ============ Research Methods ============
496
+ /**
497
+ * 保存研究会话
498
+ * 路径: .openmatrix/{runId}/research/session.json
499
+ */
500
+ async saveResearchSession(session) {
501
+ await this.store.ensureDir('research');
502
+ await this.store.writeJson('research/session.json', session);
503
+ }
504
+ /**
505
+ * 读取研究会话
506
+ */
507
+ async getResearchSession() {
508
+ return await this.store.readJson('research/session.json');
509
+ }
510
+ /**
511
+ * 保存研究报告
512
+ */
513
+ async saveResearchReport(content) {
514
+ await this.store.ensureDir('research');
515
+ await this.store.writeMarkdown('research/RESEARCH.md', content);
516
+ }
517
+ /**
518
+ * 读取研究报告
519
+ */
520
+ async getResearchReport() {
521
+ return await this.store.readMarkdown('research/RESEARCH.md');
522
+ }
523
+ /**
524
+ * 保存研究上下文 (供 start 使用)
525
+ */
526
+ async saveResearchContext(context) {
527
+ await this.store.ensureDir('research');
528
+ await this.store.writeJson('research/context.json', context);
529
+ }
530
+ /**
531
+ * 读取研究上下文
532
+ */
533
+ async getResearchContext() {
534
+ return await this.store.readJson('research/context.json');
535
+ }
536
+ /**
537
+ * 检查研究上下文是否存在
538
+ */
539
+ async hasResearchContext() {
540
+ return await this.store.exists('research/context.json');
541
+ }
542
+ /**
543
+ * 保存知识条目
544
+ */
545
+ async saveKnowledgeFinding(index, content) {
546
+ await this.store.ensureDir('research/knowledge');
547
+ await this.store.writeMarkdown(`research/knowledge/finding-${index}.md`, content);
548
+ }
549
+ // ============ Brainstorm Methods ============
550
+ /**
551
+ * 保存头脑风暴会话
552
+ */
553
+ async saveBrainstormSession(session) {
554
+ await this.store.ensureDir('brainstorm');
555
+ await this.store.writeJson('brainstorm/session.json', session);
556
+ }
557
+ /**
558
+ * 读取头脑风暴会话
559
+ */
560
+ async getBrainstormSession() {
561
+ return await this.store.readJson('brainstorm/session.json');
562
+ }
563
+ // ============ Legacy Migration Methods ============
564
+ /**
565
+ * 迁移旧版本文件到 runId 目录
566
+ * 只在首次检测到旧文件时执行
567
+ */
568
+ async migrateFromLegacy() {
569
+ // Check if migration already done
570
+ if (await this.store.exists('plan.md')) {
571
+ return; // Already migrated
572
+ }
573
+ // Move plan.md from root to runId
574
+ const rootPlan = await this.rootStore.readMarkdown('plan.md');
575
+ if (rootPlan) {
576
+ await this.store.writeMarkdown('plan.md', rootPlan);
577
+ await this.rootStore.removeFile('plan.md');
578
+ }
579
+ // Move tasks-input.json from root to runId
580
+ const rootTasksInput = await this.rootStore.readJson('tasks-input.json');
581
+ if (rootTasksInput) {
582
+ await this.store.writeJson('tasks-input.json', rootTasksInput);
583
+ await this.rootStore.removeFile('tasks-input.json');
584
+ }
585
+ // Move research directory from root to runId
586
+ const rootResearchSession = await this.rootStore.readJson('research/session.json');
587
+ if (rootResearchSession) {
588
+ await this.store.ensureDir('research/knowledge');
589
+ // Copy session.json
590
+ if (rootResearchSession) {
591
+ await this.store.writeJson('research/session.json', rootResearchSession);
592
+ }
593
+ // Copy context.json
594
+ const rootContext = await this.rootStore.readJson('research/context.json');
595
+ if (rootContext) {
596
+ await this.store.writeJson('research/context.json', rootContext);
597
+ }
598
+ // Copy RESEARCH.md
599
+ const rootReport = await this.rootStore.readMarkdown('research/RESEARCH.md');
600
+ if (rootReport) {
601
+ await this.store.writeMarkdown('research/RESEARCH.md', rootReport);
602
+ }
603
+ // Remove old directory
604
+ await this.rootStore.removeDir('research');
605
+ }
606
+ // Move brainstorm directory from root to runId
607
+ const rootBrainstormSession = await this.rootStore.readJson('brainstorm/session.json');
608
+ if (rootBrainstormSession) {
609
+ await this.store.ensureDir('brainstorm');
610
+ await this.store.writeJson('brainstorm/session.json', rootBrainstormSession);
611
+ await this.rootStore.removeDir('brainstorm');
612
+ }
613
+ }
446
614
  // ============ Meeting Methods ============
447
615
  async saveMeeting(meeting) {
448
616
  await this.store.writeJson(`meetings/${meeting.id}.json`, meeting);
@@ -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
+ }