openmatrix 0.1.61 → 0.1.63

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.
@@ -10,6 +10,7 @@ exports.approveCommand = new commander_1.Command('approve')
10
10
  .argument('[approvalId]', '审批ID')
11
11
  .option('-d, --decision <decision>', '决策 (approve/modify/reject)')
12
12
  .option('-c, --comment <comment>', '备注说明')
13
+ .option('--json', '输出 JSON 格式 (供 Skill 解析)')
13
14
  .action(async (approvalId, options) => {
14
15
  const basePath = process.cwd();
15
16
  const omPath = `${basePath}/.openmatrix`;
@@ -20,23 +21,33 @@ exports.approveCommand = new commander_1.Command('approve')
20
21
  if (!approvalId) {
21
22
  const pendingApprovals = await approvalManager.getPendingApprovals();
22
23
  if (pendingApprovals.length === 0) {
23
- console.log('✅ 没有待处理的审批');
24
+ if (options.json) {
25
+ console.log(JSON.stringify({ status: 'empty', pending: [] }));
26
+ }
27
+ else {
28
+ console.log('✅ 没有待处理的审批');
29
+ }
24
30
  return;
25
31
  }
26
- console.log('📋 待处理审批:\n');
27
- pendingApprovals.forEach((approval, i) => {
28
- const typeEmoji = {
29
- plan: '📋',
30
- merge: '🔀',
31
- deploy: '🚀',
32
- meeting: '🔴',
33
- custom: '📝'
34
- };
35
- const emoji = typeEmoji[approval.type] || '📝';
36
- console.log(` [${i + 1}] ${emoji} ${approval.id}: ${approval.title}`);
37
- console.log(` 类型: ${approval.type} | 任务: ${approval.taskId}`);
38
- });
39
- console.log('\n💡 使用 openmatrix approve <ID> 处理审批');
32
+ if (options.json) {
33
+ console.log(JSON.stringify({ status: 'pending', pending: pendingApprovals }));
34
+ }
35
+ else {
36
+ console.log('📋 待处理审批:\n');
37
+ pendingApprovals.forEach((approval, i) => {
38
+ const typeEmoji = {
39
+ plan: '📋',
40
+ merge: '🔀',
41
+ deploy: '🚀',
42
+ meeting: '🔴',
43
+ custom: '📝'
44
+ };
45
+ const emoji = typeEmoji[approval.type] || '📝';
46
+ console.log(` [${i + 1}] ${emoji} ${approval.id}: ${approval.title}`);
47
+ console.log(` 类型: ${approval.type} | 任务: ${approval.taskId}`);
48
+ });
49
+ console.log('\n💡 使用 openmatrix approve <ID> 处理审批');
50
+ }
40
51
  return;
41
52
  }
42
53
  // 获取审批
@@ -38,6 +38,10 @@ exports.brainstormCommand = void 0;
38
38
  const commander_1 = require("commander");
39
39
  const state_manager_js_1 = require("../../storage/state-manager.js");
40
40
  const gitignore_js_1 = require("../../utils/gitignore.js");
41
+ const smart_question_analyzer_js_1 = require("../../orchestrator/smart-question-analyzer.js");
42
+ const interactive_question_generator_js_1 = require("../../orchestrator/interactive-question-generator.js");
43
+ const task_parser_js_1 = require("../../orchestrator/task-parser.js");
44
+ const answer_mapper_js_1 = require("../../orchestrator/answer-mapper.js");
41
45
  const fs = __importStar(require("fs/promises"));
42
46
  const path = __importStar(require("path"));
43
47
  exports.brainstormCommand = new commander_1.Command('brainstorm')
@@ -175,8 +179,8 @@ exports.brainstormCommand = new commander_1.Command('brainstorm')
175
179
  break;
176
180
  }
177
181
  }
178
- // 生成头脑风暴问题
179
- const questions = generateBrainstormQuestions(taskContent, taskTitle);
182
+ // 生成头脑风暴问题 — 使用智能管道
183
+ const questions = await generateSmartQuestions(taskContent, basePath);
180
184
  // 检测是否涉及垂直领域
181
185
  const domainDetection = detectVerticalDomain(taskContent);
182
186
  // 创建会话
@@ -411,3 +415,166 @@ function generateBrainstormQuestions(taskContent, taskTitle) {
411
415
  }
412
416
  return questions;
413
417
  }
418
+ /**
419
+ * 智能问题生成 — 使用 SmartQuestionAnalyzer + InteractiveQuestionGenerator
420
+ */
421
+ async function generateSmartQuestions(taskContent, basePath) {
422
+ try {
423
+ // 1. 解析任务为 ParsedTask
424
+ const parser = new task_parser_js_1.TaskParser();
425
+ const parsedTask = parser.parse(taskContent);
426
+ // 2. 分析项目上下文 + 推断答案
427
+ const analyzer = new smart_question_analyzer_js_1.SmartQuestionAnalyzer(basePath);
428
+ const analysisResult = await analyzer.analyze(taskContent, parsedTask);
429
+ // 3. 映射推断结果为规范 brainstorm ID
430
+ const inferenceMap = (0, answer_mapper_js_1.translateAnalyzerInferences)(analysisResult.inferences);
431
+ // 4. 创建问题生成器 + 设置推断
432
+ const questionGen = new interactive_question_generator_js_1.InteractiveQuestionGenerator();
433
+ questionGen.setInferences(inferenceMap);
434
+ // 5. 生成基础问题 + 上下文问题
435
+ const session = questionGen.startSession(parsedTask);
436
+ questionGen.addContextualQuestions(parsedTask, session.questions);
437
+ // 6. 转换为 BrainstormQuestion[] 格式
438
+ const questions = session.questions
439
+ .filter(q => !session.skippedQuestionIds?.includes(q.id)) // 跳过高置信度推断的问题
440
+ .sort((a, b) => (a.priority ?? 5) - (b.priority ?? 5))
441
+ .map(q => ({
442
+ id: q.id,
443
+ question: q.question,
444
+ header: q.category,
445
+ options: (q.options || []).map(o => ({
446
+ label: o.label,
447
+ description: o.description || ''
448
+ })),
449
+ multiSelect: q.type === 'multiple',
450
+ why: ''
451
+ }));
452
+ // 7. 追加领域分析问题(底层逻辑思考)
453
+ const domainQuestions = generateDomainAnalysisQuestions(taskContent);
454
+ questions.push(...domainQuestions);
455
+ return questions;
456
+ }
457
+ catch (error) {
458
+ // Fallback: 如果智能管道出错,使用静态问题
459
+ console.error(`⚠️ 智能问题生成失败,使用静态问题: ${error instanceof Error ? error.message : error}`);
460
+ return generateBrainstormQuestions(taskContent, '');
461
+ }
462
+ }
463
+ /**
464
+ * 领域分析问题 — 底层逻辑思考
465
+ *
466
+ * 从任务描述中提取:
467
+ * 1. 核心领域实体及其关系
468
+ * 2. 数据流转路径
469
+ * 3. 关键不变量/约束
470
+ * 4. 核心用户场景链路
471
+ */
472
+ function generateDomainAnalysisQuestions(taskContent) {
473
+ const questions = [];
474
+ const content = taskContent.toLowerCase();
475
+ // ===== 问题 1: 领域实体建模 =====
476
+ const entityHints = extractEntities(taskContent);
477
+ if (entityHints.length > 0) {
478
+ questions.push({
479
+ id: 'domain_entities',
480
+ question: `从任务描述中识别到以下核心实体,请确认或补充:\n${entityHints.map(e => ` • ${e}`).join('\n')}`,
481
+ header: '领域实体',
482
+ options: [
483
+ { label: '以上实体正确', description: '已覆盖核心领域实体,无需补充' },
484
+ { label: '需要补充实体', description: '还有重要实体未被识别,我会在"其他"中补充' },
485
+ { label: '需要调整实体', description: '部分实体不准确,需要修正' }
486
+ ],
487
+ multiSelect: false,
488
+ why: '明确领域实体是设计数据模型和 API 的基础'
489
+ });
490
+ }
491
+ else {
492
+ questions.push({
493
+ id: 'domain_entities',
494
+ question: '这个系统涉及哪些核心领域实体?它们之间是什么关系?(如 用户-订单-商品)',
495
+ header: '领域实体',
496
+ options: [
497
+ { label: '单一实体', description: '系统围绕一个核心实体(如用户管理)' },
498
+ { label: '2-3 个实体', description: '少量实体间有简单关系(如用户-文章)' },
499
+ { label: '多实体复杂关系', description: '多个实体间有多对多等复杂关系' },
500
+ { label: '我来说明', description: '在"其他"中描述具体实体' }
501
+ ],
502
+ multiSelect: false,
503
+ why: '明确领域实体是设计数据模型和 API 的基础'
504
+ });
505
+ }
506
+ // ===== 问题 2: 数据流分析 =====
507
+ questions.push({
508
+ id: 'data_flow',
509
+ question: '数据在系统中如何流转?(从输入到存储到输出)',
510
+ header: '数据流',
511
+ options: [
512
+ { label: '用户输入 → 处理 → 存储 → 展示', description: '经典 CRUD 流程(如后台管理、博客)' },
513
+ { label: '外部 API → 转换 → 存储 → 查询', description: '数据采集/聚合类系统' },
514
+ { label: '事件触发 → 处理 → 通知/存储', description: '事件驱动型(如消息队列、Webhook)' },
515
+ { label: '实时流处理', description: '数据持续流入,实时处理(如监控、聊天)' },
516
+ { label: '我来说明', description: '在"其他"中描述具体数据流' }
517
+ ],
518
+ multiSelect: false,
519
+ why: '数据流决定架构选型(请求驱动 vs 事件驱动 vs 流处理)'
520
+ });
521
+ // ===== 问题 3: 不变量/约束 =====
522
+ questions.push({
523
+ id: 'invariants',
524
+ question: '系统中存在哪些关键不变量或业务约束?(什么条件必须永远成立)',
525
+ header: '不变量',
526
+ options: [
527
+ { label: '数据一致性', description: '如:余额不能为负、库存不能超卖、状态只能单向流转' },
528
+ { label: '权限控制', description: '如:用户只能操作自己的数据、管理员才能访问后台' },
529
+ { label: '唯一性约束', description: '如:用户名唯一、订单号不重复、同一时间只能有一个活跃会话' },
530
+ { label: '无明显约束', description: '纯展示或简单计算,无严格不变量' }
531
+ ],
532
+ multiSelect: true,
533
+ why: '不变量决定了哪些地方需要加锁、事务、校验和防御性编程'
534
+ });
535
+ // ===== 问题 4: 核心场景链路 =====
536
+ questions.push({
537
+ id: 'core_scenarios',
538
+ question: '从用户视角,核心操作链路是什么?(用户会走过的关键路径)',
539
+ header: '场景链路',
540
+ options: [
541
+ { label: '注册→登录→使用→退出', description: '典型用户系统链路' },
542
+ { label: '浏览→选择→下单→支付→确认', description: '电商/交易类链路' },
543
+ { label: '创建→编辑→预览→发布', description: '内容管理类链路' },
544
+ { label: '输入→处理→查看结果', description: '工具/计算类链路' },
545
+ { label: '我来说明', description: '在"其他"中描述具体场景链路' }
546
+ ],
547
+ multiSelect: true,
548
+ why: '核心场景链路决定了 MVP 的功能范围和优先级排序'
549
+ });
550
+ return questions;
551
+ }
552
+ /**
553
+ * 从任务描述中提取可能的领域实体
554
+ */
555
+ function extractEntities(taskContent) {
556
+ const entities = [];
557
+ // 中文常见领域实体
558
+ const zhPatterns = [
559
+ { pattern: /用户|账号|账户|注册|登录|权限|角色/gi, entity: '用户 (User)' },
560
+ { pattern: /订单|交易|购买|支付|退款|结算/gi, entity: '订单 (Order)' },
561
+ { pattern: /商品|产品|物品|库存|上架|下架/gi, entity: '商品 (Product)' },
562
+ { pattern: /文章|帖子|内容|评论|标签|分类/gi, entity: '内容 (Content)' },
563
+ { pattern: /任务|工单|项目|里程碑|迭代/gi, entity: '任务 (Task)' },
564
+ { pattern: /消息|通知|推送|邮件|短信/gi, entity: '消息 (Message)' },
565
+ { pattern: /文件|附件|图片|视频|媒体|上传/gi, entity: '文件 (File)' },
566
+ { pattern: /配置|设置|参数|选项|规则/gi, entity: '配置 (Config)' },
567
+ { pattern: /日志|记录|审计|追踪|监控/gi, entity: '日志 (Log)' },
568
+ { pattern: /数据|报表|统计|分析|仪表盘|dashboard/gi, entity: '数据 (Data)' },
569
+ { pattern: /API|接口|端点|路由|endpoint/gi, entity: 'API' },
570
+ { pattern: /数据库|存储|缓存|表|collection/gi, entity: '存储 (Storage)' },
571
+ ];
572
+ const seen = new Set();
573
+ for (const { pattern, entity } of zhPatterns) {
574
+ if (pattern.test(taskContent) && !seen.has(entity)) {
575
+ entities.push(entity);
576
+ seen.add(entity);
577
+ }
578
+ }
579
+ return entities;
580
+ }
@@ -0,0 +1,24 @@
1
+ import type { QuestionInference } from './smart-question-analyzer.js';
2
+ /**
3
+ * 将 brainstorm 答案键翻译为 TaskPlanner 期望的键
4
+ *
5
+ * 支持两种输入:
6
+ * 1. 规范 ID (如 objective, quality_level) → 直接映射
7
+ * 2. 旧 brainstorm ID (如 core_objective, quality) → 先转规范 ID 再映射
8
+ */
9
+ export declare function translateBrainstormAnswers(answers: Record<string, string | string[]>): Record<string, string | string[]>;
10
+ /**
11
+ * 将 SmartQuestionAnalyzer 推理结果转换为 brainstorm 规范 ID
12
+ */
13
+ export declare function translateAnalyzerInferences(inferences: QuestionInference[]): Map<string, {
14
+ answer: string | string[];
15
+ reason: string;
16
+ }>;
17
+ /**
18
+ * 从 brainstorm 答案中提取 tasks-input.json 所需的字段
19
+ */
20
+ export declare function extractTasksInputFields(answers: Record<string, string | string[]>): {
21
+ quality?: string;
22
+ mode?: string;
23
+ e2eTests?: boolean;
24
+ };
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.translateBrainstormAnswers = translateBrainstormAnswers;
4
+ exports.translateAnalyzerInferences = translateAnalyzerInferences;
5
+ exports.extractTasksInputFields = extractTasksInputFields;
6
+ /**
7
+ * 答案键映射 — 统一三套 ID 体系
8
+ *
9
+ * Brainstorm 问题 ID → 规范 ID → TaskPlanner 期望的键
10
+ */
11
+ /** Brainstorm 旧 ID → 规范 ID */
12
+ const BRAINSTORM_TO_CANONICAL = {
13
+ core_objective: 'objective',
14
+ user_value: 'user_value',
15
+ complexity: 'complexity',
16
+ tech_constraints: 'tech_stack',
17
+ risks: 'risks',
18
+ acceptance: 'acceptance',
19
+ priority: 'priority',
20
+ quality: 'quality_level',
21
+ execution_mode: 'execution_mode',
22
+ e2e_tests: 'e2e_tests',
23
+ };
24
+ /** 规范 ID → TaskPlanner extractUserContext() 期望的键 */
25
+ const CANONICAL_TO_PLANNER = {
26
+ objective: { '目标': '', objective: '' },
27
+ tech_stack: { '技术栈': '', techStack: '' },
28
+ test_coverage: { '测试': '', testCoverage: '' },
29
+ documentation_level: { '文档': '', documentationLevel: '' },
30
+ e2e_tests: { 'E2E测试': '', e2eTests: '', e2e: '' },
31
+ e2e_type: { 'E2E类型': '', e2eType: '' },
32
+ };
33
+ /** Analyzer 旧 ID → 规范 ID */
34
+ const ANALYZER_TO_CANONICAL = {
35
+ quality_level: 'quality_level',
36
+ tech_stack: 'tech_stack',
37
+ doc_level: 'documentation_level',
38
+ e2e_test: 'e2e_tests',
39
+ execution_mode: 'execution_mode',
40
+ objective: 'objective',
41
+ test_coverage: 'test_coverage',
42
+ };
43
+ /**
44
+ * 将 brainstorm 答案键翻译为 TaskPlanner 期望的键
45
+ *
46
+ * 支持两种输入:
47
+ * 1. 规范 ID (如 objective, quality_level) → 直接映射
48
+ * 2. 旧 brainstorm ID (如 core_objective, quality) → 先转规范 ID 再映射
49
+ */
50
+ function translateBrainstormAnswers(answers) {
51
+ const result = {};
52
+ for (const [key, value] of Object.entries(answers)) {
53
+ // 步骤 1: 旧 brainstorm ID → 规范 ID
54
+ const canonical = BRAINSTORM_TO_CANONICAL[key] || key;
55
+ // 步骤 2: 规范 ID → planner 键
56
+ const plannerKeys = CANONICAL_TO_PLANNER[canonical];
57
+ if (plannerKeys) {
58
+ for (const plannerKey of Object.keys(plannerKeys)) {
59
+ result[plannerKey] = value;
60
+ }
61
+ }
62
+ // 同时保留原始键和规范 ID(向后兼容)
63
+ result[key] = value;
64
+ if (canonical !== key) {
65
+ result[canonical] = value;
66
+ }
67
+ }
68
+ return result;
69
+ }
70
+ /**
71
+ * 将 SmartQuestionAnalyzer 推理结果转换为 brainstorm 规范 ID
72
+ */
73
+ function translateAnalyzerInferences(inferences) {
74
+ const result = new Map();
75
+ for (const inf of inferences) {
76
+ if (inf.inferredAnswer === undefined)
77
+ continue;
78
+ const canonical = ANALYZER_TO_CANONICAL[inf.questionId] || inf.questionId;
79
+ result.set(canonical, {
80
+ answer: inf.inferredAnswer,
81
+ reason: inf.reason
82
+ });
83
+ }
84
+ return result;
85
+ }
86
+ /**
87
+ * 从 brainstorm 答案中提取 tasks-input.json 所需的字段
88
+ */
89
+ function extractTasksInputFields(answers) {
90
+ const result = {};
91
+ // quality_level / quality → quality 字段
92
+ const quality = answers['quality_level'] || answers['quality'];
93
+ if (typeof quality === 'string') {
94
+ result.quality = quality;
95
+ }
96
+ // execution_mode → mode 字段
97
+ const mode = answers['execution_mode'];
98
+ if (typeof mode === 'string') {
99
+ result.mode = mode;
100
+ }
101
+ // e2e_tests → e2eTests 布尔字段
102
+ const e2e = answers['e2e_tests'] || answers['e2eTests'] || answers['E2E测试'];
103
+ if (e2e !== undefined) {
104
+ const e2eStr = Array.isArray(e2e) ? e2e[0] : e2e;
105
+ result.e2eTests = e2eStr === 'true' || e2eStr === '启用 E2E 测试' || e2eStr === '是';
106
+ }
107
+ return result;
108
+ }
@@ -39,7 +39,9 @@ export declare class OrchestratorExecutor {
39
39
  private approvalManager;
40
40
  private stateMachine;
41
41
  private phaseExecutor;
42
+ private retryManager;
42
43
  private config;
44
+ private taskTimers;
43
45
  constructor(stateManager: StateManager, approvalManager: ApprovalManager, config?: Partial<ExecutorConfig>);
44
46
  /**
45
47
  * 获取 PhaseExecutor 实例
@@ -112,4 +114,21 @@ export declare class OrchestratorExecutor {
112
114
  * 获取 Scheduler 实例
113
115
  */
114
116
  getScheduler(): Scheduler;
117
+ /**
118
+ * 设置任务超时计时器
119
+ */
120
+ private setupTaskTimeout;
121
+ /**
122
+ * 清除任务超时计时器
123
+ */
124
+ private clearTaskTimeout;
125
+ /**
126
+ * 处理失败任务的重试
127
+ * @returns 成功加入重试队列的任务数量
128
+ */
129
+ private processRetries;
130
+ /**
131
+ * 销毁执行器,清理所有资源
132
+ */
133
+ destroy(): void;
115
134
  }
@@ -6,6 +6,7 @@ const scheduler_js_1 = require("./scheduler.js");
6
6
  const agent_runner_js_1 = require("../agents/agent-runner.js");
7
7
  const state_machine_js_1 = require("./state-machine.js");
8
8
  const phase_executor_js_1 = require("./phase-executor.js");
9
+ const retry_manager_js_1 = require("./retry-manager.js");
9
10
  /**
10
11
  * OrchestratorExecutor - 执行循环核心
11
12
  *
@@ -18,7 +19,9 @@ class OrchestratorExecutor {
18
19
  approvalManager;
19
20
  stateMachine;
20
21
  phaseExecutor;
22
+ retryManager;
21
23
  config;
24
+ taskTimers = new Map();
22
25
  constructor(stateManager, approvalManager, config) {
23
26
  this.stateManager = stateManager;
24
27
  this.approvalManager = approvalManager;
@@ -37,6 +40,7 @@ class OrchestratorExecutor {
37
40
  });
38
41
  this.stateMachine = new state_machine_js_1.StateMachine();
39
42
  this.phaseExecutor = new phase_executor_js_1.PhaseExecutor(stateManager, approvalManager);
43
+ this.retryManager = new retry_manager_js_1.RetryManager();
40
44
  }
41
45
  /**
42
46
  * 获取 PhaseExecutor 实例
@@ -64,6 +68,18 @@ class OrchestratorExecutor {
64
68
  // 4. 检查是否有失败任务需要重试
65
69
  const failedTasks = allTasks.filter(t => t.status === 'failed');
66
70
  if (failedTasks.length > 0) {
71
+ // 尝试自动重试
72
+ const retried = await this.processRetries(failedTasks);
73
+ if (retried > 0) {
74
+ // 有任务被重新放入队列,继续执行循环
75
+ return {
76
+ status: 'continue',
77
+ subagentTasks: [],
78
+ message: `${retried} 个失败任务已加入重试队列`,
79
+ statistics: this.getStatistics(state)
80
+ };
81
+ }
82
+ // 所有重试次数已耗尽
67
83
  return this.createRetryNeededResult(failedTasks, state);
68
84
  }
69
85
  // 5. 检查是否有阻塞任务
@@ -85,9 +101,10 @@ class OrchestratorExecutor {
85
101
  }
86
102
  // 10. 准备 Subagent 任务
87
103
  const subagentTasks = await this.agentRunner.prepareSubagentTasks(executableTasks);
88
- // 8. 更新任务状态为 scheduled
104
+ // 8. 更新任务状态为 scheduled 并设置超时
89
105
  for (const task of executableTasks) {
90
106
  await this.scheduler.markTaskStarted(task.id);
107
+ this.setupTaskTimeout(task.id);
91
108
  }
92
109
  return {
93
110
  status: 'continue',
@@ -241,6 +258,8 @@ class OrchestratorExecutor {
241
258
  throw new Error(`Task ${taskId} not found`);
242
259
  }
243
260
  if (result.success) {
261
+ // 清除超时计时器
262
+ this.clearTaskTimeout(taskId);
244
263
  // 更新阶段状态
245
264
  const currentPhase = this.getCurrentPhase(task);
246
265
  const updatedPhases = { ...task.phases };
@@ -281,6 +300,7 @@ class OrchestratorExecutor {
281
300
  }
282
301
  }
283
302
  else {
303
+ this.clearTaskTimeout(taskId);
284
304
  await this.scheduler.markTaskFailed(taskId, result.error || 'Unknown error');
285
305
  }
286
306
  }
@@ -321,5 +341,60 @@ class OrchestratorExecutor {
321
341
  getScheduler() {
322
342
  return this.scheduler;
323
343
  }
344
+ // ============ Timeout Management ============
345
+ /**
346
+ * 设置任务超时计时器
347
+ */
348
+ setupTaskTimeout(taskId) {
349
+ const timer = setTimeout(async () => {
350
+ console.error(`⏰ 任务超时: ${taskId} (${this.config.taskTimeout / 1000}s)`);
351
+ this.taskTimers.delete(taskId);
352
+ await this.scheduler.markTaskFailed(taskId, `Task timed out after ${this.config.taskTimeout / 1000}s`);
353
+ }, this.config.taskTimeout);
354
+ this.taskTimers.set(taskId, timer);
355
+ }
356
+ /**
357
+ * 清除任务超时计时器
358
+ */
359
+ clearTaskTimeout(taskId) {
360
+ const timer = this.taskTimers.get(taskId);
361
+ if (timer) {
362
+ clearTimeout(timer);
363
+ this.taskTimers.delete(taskId);
364
+ }
365
+ }
366
+ // ============ Retry Management ============
367
+ /**
368
+ * 处理失败任务的重试
369
+ * @returns 成功加入重试队列的任务数量
370
+ */
371
+ async processRetries(failedTasks) {
372
+ let retried = 0;
373
+ for (const task of failedTasks) {
374
+ this.retryManager.addToQueue(task.id, task.error || 'Unknown error');
375
+ if (this.retryManager.shouldRetry(task.id)) {
376
+ // 将任务从 failed 转为 retry_queue 再转为 pending
377
+ await this.stateManager.updateTask(task.id, {
378
+ status: 'retry_queue',
379
+ retryCount: (task.retryCount || 0) + 1
380
+ });
381
+ await this.stateManager.updateTask(task.id, {
382
+ status: 'pending'
383
+ });
384
+ this.retryManager.removeFromQueue(task.id);
385
+ retried++;
386
+ }
387
+ }
388
+ return retried;
389
+ }
390
+ /**
391
+ * 销毁执行器,清理所有资源
392
+ */
393
+ destroy() {
394
+ for (const timer of this.taskTimers.values()) {
395
+ clearTimeout(timer);
396
+ }
397
+ this.taskTimers.clear();
398
+ }
324
399
  }
325
400
  exports.OrchestratorExecutor = OrchestratorExecutor;