@winspan/claude-forge 8.28.2 → 8.33.0
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.
- package/README.md +68 -215
- package/dist/capability/execution-manager.d.ts +96 -0
- package/dist/capability/execution-manager.d.ts.map +1 -0
- package/dist/capability/execution-manager.js +260 -0
- package/dist/capability/execution-manager.js.map +1 -0
- package/dist/capability/executor/background-executor.d.ts +58 -0
- package/dist/capability/executor/background-executor.d.ts.map +1 -0
- package/dist/capability/executor/background-executor.js +322 -0
- package/dist/capability/executor/background-executor.js.map +1 -0
- package/dist/capability/executor/foreground-executor.d.ts +26 -0
- package/dist/capability/executor/foreground-executor.d.ts.map +1 -0
- package/dist/capability/executor/foreground-executor.js +82 -0
- package/dist/capability/executor/foreground-executor.js.map +1 -0
- package/dist/capability/executor/orchestrator.d.ts +38 -0
- package/dist/capability/executor/orchestrator.d.ts.map +1 -0
- package/dist/capability/executor/orchestrator.js +158 -0
- package/dist/capability/executor/orchestrator.js.map +1 -0
- package/dist/capability/executor/stream-parser.d.ts +73 -0
- package/dist/capability/executor/stream-parser.d.ts.map +1 -0
- package/dist/capability/executor/stream-parser.js +56 -0
- package/dist/capability/executor/stream-parser.js.map +1 -0
- package/dist/capability/executor/types.d.ts +44 -0
- package/dist/capability/executor/types.d.ts.map +1 -0
- package/dist/capability/executor/types.js +9 -0
- package/dist/capability/executor/types.js.map +1 -0
- package/dist/capability/executor/worker-auth-probe.d.ts +30 -0
- package/dist/capability/executor/worker-auth-probe.d.ts.map +1 -0
- package/dist/capability/executor/worker-auth-probe.js +108 -0
- package/dist/capability/executor/worker-auth-probe.js.map +1 -0
- package/dist/capability/methodologies/bmad.yaml +17 -5
- package/dist/capability/methodologies/code-quality-audit.yaml +26 -0
- package/dist/capability/methodologies/harness-engineering.yaml +12 -6
- package/dist/capability/methodologies/test-coverage-scan.yaml +26 -0
- package/dist/capability/methodology-planner.d.ts +17 -1
- package/dist/capability/methodology-planner.d.ts.map +1 -1
- package/dist/capability/methodology-planner.js +125 -0
- package/dist/capability/methodology-planner.js.map +1 -1
- package/dist/capability/methodology-registry.d.ts.map +1 -1
- package/dist/capability/methodology-registry.js +21 -5
- package/dist/capability/methodology-registry.js.map +1 -1
- package/dist/capability/types.d.ts +12 -1
- package/dist/capability/types.d.ts.map +1 -1
- package/dist/core/ai/provider.d.ts +17 -9
- package/dist/core/ai/provider.d.ts.map +1 -1
- package/dist/core/ai/provider.js +130 -23
- package/dist/core/ai/provider.js.map +1 -1
- package/dist/core/ai/types.d.ts +26 -5
- package/dist/core/ai/types.d.ts.map +1 -1
- package/dist/core/storage/rows.d.ts +153 -0
- package/dist/core/storage/rows.d.ts.map +1 -0
- package/dist/core/storage/rows.js +14 -0
- package/dist/core/storage/rows.js.map +1 -0
- package/dist/core/storage/schema.sql +26 -2
- package/dist/core/storage/sqlite.d.ts +112 -6
- package/dist/core/storage/sqlite.d.ts.map +1 -1
- package/dist/core/storage/sqlite.js +480 -22
- package/dist/core/storage/sqlite.js.map +1 -1
- package/dist/core/utils/token-tracker.d.ts +40 -0
- package/dist/core/utils/token-tracker.d.ts.map +1 -0
- package/dist/core/utils/token-tracker.js +70 -0
- package/dist/core/utils/token-tracker.js.map +1 -0
- package/dist/daemon/handlers/methodology-formatter.d.ts +7 -0
- package/dist/daemon/handlers/methodology-formatter.d.ts.map +1 -1
- package/dist/daemon/handlers/methodology-formatter.js +46 -0
- package/dist/daemon/handlers/methodology-formatter.js.map +1 -1
- package/dist/daemon/handlers/post-tool-use.d.ts +1 -0
- package/dist/daemon/handlers/post-tool-use.d.ts.map +1 -1
- package/dist/daemon/handlers/post-tool-use.js +7 -0
- package/dist/daemon/handlers/post-tool-use.js.map +1 -1
- package/dist/daemon/handlers/stop.d.ts +17 -1
- package/dist/daemon/handlers/stop.d.ts.map +1 -1
- package/dist/daemon/handlers/stop.js +97 -1
- package/dist/daemon/handlers/stop.js.map +1 -1
- package/dist/daemon/handlers/user-prompt.d.ts.map +1 -1
- package/dist/daemon/handlers/user-prompt.js +97 -5
- package/dist/daemon/handlers/user-prompt.js.map +1 -1
- package/dist/daemon/idle-detector.d.ts +35 -0
- package/dist/daemon/idle-detector.d.ts.map +1 -0
- package/dist/daemon/idle-detector.js +56 -0
- package/dist/daemon/idle-detector.js.map +1 -0
- package/dist/daemon/idle-trigger.d.ts +53 -0
- package/dist/daemon/idle-trigger.d.ts.map +1 -0
- package/dist/daemon/idle-trigger.js +153 -0
- package/dist/daemon/idle-trigger.js.map +1 -0
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +49 -2
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/methodology-pending-queue.d.ts +33 -0
- package/dist/daemon/methodology-pending-queue.d.ts.map +1 -0
- package/dist/daemon/methodology-pending-queue.js +120 -0
- package/dist/daemon/methodology-pending-queue.js.map +1 -0
- package/dist/daemon/routing-observer.d.ts +2 -1
- package/dist/daemon/routing-observer.d.ts.map +1 -1
- package/dist/daemon/routing-observer.js +117 -39
- package/dist/daemon/routing-observer.js.map +1 -1
- package/dist/engine/agent-router.d.ts +6 -0
- package/dist/engine/agent-router.d.ts.map +1 -1
- package/dist/engine/agent-router.js +13 -1
- package/dist/engine/agent-router.js.map +1 -1
- package/dist/engine/conventions/routing.yaml +15 -0
- package/dist/engine/dsl/compiler.d.ts.map +1 -1
- package/dist/engine/dsl/compiler.js +85 -3
- package/dist/engine/dsl/compiler.js.map +1 -1
- package/dist/engine/recommender.d.ts.map +1 -1
- package/dist/engine/recommender.js +10 -1
- package/dist/engine/recommender.js.map +1 -1
- package/dist/intelligence/classifier.d.ts +6 -0
- package/dist/intelligence/classifier.d.ts.map +1 -1
- package/dist/intelligence/classifier.js +57 -0
- package/dist/intelligence/classifier.js.map +1 -1
- package/dist/skills/registry.d.ts +6 -0
- package/dist/skills/registry.d.ts.map +1 -1
- package/dist/skills/registry.js +49 -14
- package/dist/skills/registry.js.map +1 -1
- package/dist/skills/semantic-matcher.d.ts +1 -0
- package/dist/skills/semantic-matcher.d.ts.map +1 -1
- package/dist/skills/semantic-matcher.js +6 -1
- package/dist/skills/semantic-matcher.js.map +1 -1
- package/dist/web/auth-middleware.d.ts +22 -0
- package/dist/web/auth-middleware.d.ts.map +1 -0
- package/dist/web/auth-middleware.js +51 -0
- package/dist/web/auth-middleware.js.map +1 -0
- package/dist/web/routes/agents.d.ts +7 -0
- package/dist/web/routes/agents.d.ts.map +1 -0
- package/dist/web/routes/agents.js +192 -0
- package/dist/web/routes/agents.js.map +1 -0
- package/dist/web/routes/ai.d.ts +10 -0
- package/dist/web/routes/ai.d.ts.map +1 -0
- package/dist/web/routes/ai.js +197 -0
- package/dist/web/routes/ai.js.map +1 -0
- package/dist/web/routes/auth.d.ts +12 -0
- package/dist/web/routes/auth.d.ts.map +1 -0
- package/dist/web/routes/auth.js +20 -0
- package/dist/web/routes/auth.js.map +1 -0
- package/dist/web/routes/events.d.ts +11 -0
- package/dist/web/routes/events.d.ts.map +1 -0
- package/dist/web/routes/events.js +43 -0
- package/dist/web/routes/events.js.map +1 -0
- package/dist/web/routes/execution-trace.d.ts +13 -0
- package/dist/web/routes/execution-trace.d.ts.map +1 -0
- package/dist/web/routes/execution-trace.js +308 -0
- package/dist/web/routes/execution-trace.js.map +1 -0
- package/dist/web/routes/experiments.d.ts +15 -0
- package/dist/web/routes/experiments.d.ts.map +1 -0
- package/dist/web/routes/experiments.js +187 -0
- package/dist/web/routes/experiments.js.map +1 -0
- package/dist/web/routes/methodology.d.ts +12 -0
- package/dist/web/routes/methodology.d.ts.map +1 -0
- package/dist/web/routes/methodology.js +228 -0
- package/dist/web/routes/methodology.js.map +1 -0
- package/dist/web/routes/patch.d.ts +7 -0
- package/dist/web/routes/patch.d.ts.map +1 -0
- package/dist/web/routes/patch.js +106 -0
- package/dist/web/routes/patch.js.map +1 -0
- package/dist/web/routes/routing.d.ts +17 -0
- package/dist/web/routes/routing.d.ts.map +1 -0
- package/dist/web/routes/routing.js +582 -0
- package/dist/web/routes/routing.js.map +1 -0
- package/dist/web/routes/rules.d.ts +7 -0
- package/dist/web/routes/rules.d.ts.map +1 -0
- package/dist/web/routes/rules.js +105 -0
- package/dist/web/routes/rules.js.map +1 -0
- package/dist/web/routes/sessions.d.ts +10 -0
- package/dist/web/routes/sessions.d.ts.map +1 -0
- package/dist/web/routes/sessions.js +234 -0
- package/dist/web/routes/sessions.js.map +1 -0
- package/dist/web/routes/skills.d.ts +10 -0
- package/dist/web/routes/skills.d.ts.map +1 -0
- package/dist/web/routes/skills.js +272 -0
- package/dist/web/routes/skills.js.map +1 -0
- package/dist/web/routes/static.d.ts +19 -0
- package/dist/web/routes/static.d.ts.map +1 -0
- package/dist/web/routes/static.js +61 -0
- package/dist/web/routes/static.js.map +1 -0
- package/dist/web/routes/status.d.ts +7 -0
- package/dist/web/routes/status.d.ts.map +1 -0
- package/dist/web/routes/status.js +28 -0
- package/dist/web/routes/status.js.map +1 -0
- package/dist/web/routes/token-usage.d.ts +7 -0
- package/dist/web/routes/token-usage.d.ts.map +1 -0
- package/dist/web/routes/token-usage.js +33 -0
- package/dist/web/routes/token-usage.js.map +1 -0
- package/dist/web/routes/types.d.ts +40 -0
- package/dist/web/routes/types.d.ts.map +1 -0
- package/dist/web/routes/types.js +52 -0
- package/dist/web/routes/types.js.map +1 -0
- package/dist/web/server.d.ts +13 -4
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +60 -2210
- package/dist/web/server.js.map +1 -1
- package/dist/web/ssrf-guard.d.ts +35 -0
- package/dist/web/ssrf-guard.d.ts.map +1 -0
- package/dist/web/ssrf-guard.js +93 -0
- package/dist/web/ssrf-guard.js.map +1 -0
- package/dist/web/static/assets/AIConfig-D-vrYoJ3.js +2 -0
- package/dist/web/static/assets/AIConfig-D-vrYoJ3.js.map +1 -0
- package/dist/web/static/assets/Agents-DAGWYsJj.js +2 -0
- package/dist/web/static/assets/Agents-DAGWYsJj.js.map +1 -0
- package/dist/web/static/assets/CodeBlock--H53gk46.js +2 -0
- package/dist/web/static/assets/CodeBlock--H53gk46.js.map +1 -0
- package/dist/web/static/assets/Dashboard-qUCxXFSI.js +2 -0
- package/dist/web/static/assets/Dashboard-qUCxXFSI.js.map +1 -0
- package/dist/web/static/assets/Drawer-DeKukfwJ.js +2 -0
- package/dist/web/static/assets/Drawer-DeKukfwJ.js.map +1 -0
- package/dist/web/static/assets/Events-BoQ8Fo5k.js +2 -0
- package/dist/web/static/assets/Events-BoQ8Fo5k.js.map +1 -0
- package/dist/web/static/assets/ExecutionTrace-sFZ_vHNf.js +2 -0
- package/dist/web/static/assets/ExecutionTrace-sFZ_vHNf.js.map +1 -0
- package/dist/web/static/assets/MarkdownRenderer-CCIz1MOz.js +2 -0
- package/dist/web/static/assets/MarkdownRenderer-CCIz1MOz.js.map +1 -0
- package/dist/web/static/assets/Methodologies-C0-Keokj.js +5 -0
- package/dist/web/static/assets/Methodologies-C0-Keokj.js.map +1 -0
- package/dist/web/static/assets/MethodologyDetail-Do1taSKM.js +2 -0
- package/dist/web/static/assets/MethodologyDetail-Do1taSKM.js.map +1 -0
- package/dist/web/static/assets/Routing-CFmM7JuB.js +2 -0
- package/dist/web/static/assets/Routing-CFmM7JuB.js.map +1 -0
- package/dist/web/static/assets/SessionDetail-DzTue2xK.js +2 -0
- package/dist/web/static/assets/SessionDetail-DzTue2xK.js.map +1 -0
- package/dist/web/static/assets/Sessions-Bjf-Mvwb.js +2 -0
- package/dist/web/static/assets/Sessions-Bjf-Mvwb.js.map +1 -0
- package/dist/web/static/assets/Skills-CrLshkrJ.js +2 -0
- package/dist/web/static/assets/Skills-CrLshkrJ.js.map +1 -0
- package/dist/web/static/assets/charts-CLrM0_uM.js +37 -0
- package/dist/web/static/assets/charts-CLrM0_uM.js.map +1 -0
- package/dist/web/static/assets/date-fns-CZ_bHujz.js +2 -0
- package/dist/web/static/assets/date-fns-CZ_bHujz.js.map +1 -0
- package/dist/web/static/assets/export-CEzDNM66.js +4 -0
- package/dist/web/static/assets/export-CEzDNM66.js.map +1 -0
- package/dist/web/static/assets/index-D23sAOAt.js +3 -0
- package/dist/web/static/assets/index-D23sAOAt.js.map +1 -0
- package/dist/web/static/assets/index-Drpf7sLl.css +1 -0
- package/dist/web/static/assets/lucide-DjB4fWNj.js +227 -0
- package/dist/web/static/assets/lucide-DjB4fWNj.js.map +1 -0
- package/dist/web/static/assets/query-C99w429o.js +2 -0
- package/dist/web/static/assets/query-C99w429o.js.map +1 -0
- package/dist/web/static/assets/react-router-I-HqunH7.js +20 -0
- package/dist/web/static/assets/react-router-I-HqunH7.js.map +1 -0
- package/dist/web/static/assets/react-vendor-CSp-GLFF.js +49 -0
- package/dist/web/static/assets/react-vendor-CSp-GLFF.js.map +1 -0
- package/dist/web/static/assets/syntax-highlighter-44FakypI.js +9 -0
- package/dist/web/static/assets/syntax-highlighter-44FakypI.js.map +1 -0
- package/dist/web/static/assets/vendor-CMMjVdZs.js +64 -0
- package/dist/web/static/assets/vendor-CMMjVdZs.js.map +1 -0
- package/dist/web/static/index.html +8 -2
- package/package.json +3 -2
- package/dist/web/static/assets/index-CtylfoaN.css +0 -1
- package/dist/web/static/assets/index-DnaQt27h.js +0 -388
- package/dist/web/static/assets/index-DnaQt27h.js.map +0 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator — 驱动一个 execution 的所有 phase 串行执行。
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* 1. 从 storage 读取 execution 和 plan
|
|
6
|
+
* 2. 对每个 phase 调用 executor.executePhase()
|
|
7
|
+
* 3. 根据结果更新 methodology_executions 状态
|
|
8
|
+
* 4. 其中任一 phase 失败 → 尝试 replan(如果启用)
|
|
9
|
+
* 5. 如果 replan 失败或取消 → 整个 execution 标 failed/cancelled 并停止
|
|
10
|
+
*
|
|
11
|
+
* 前台模式下,executePhase 只是入队 directive(返回 'injected')。此时
|
|
12
|
+
* orchestrator 不推进下一 phase —— 推进由 PostToolUse handler 基于实际
|
|
13
|
+
* 执行结果来做(已有机制)。所以前台模式下 orchestrator 只驱动 phase 0,
|
|
14
|
+
* 其余阶段由 daemon 既有路径推进。
|
|
15
|
+
*
|
|
16
|
+
* 后台模式下,executePhase 阻塞直到 phase 真正完成,orchestrator 再推进。
|
|
17
|
+
*/
|
|
18
|
+
import { logger } from '../../core/utils/logger.js';
|
|
19
|
+
export class Orchestrator {
|
|
20
|
+
storage;
|
|
21
|
+
executor;
|
|
22
|
+
planner;
|
|
23
|
+
enableReplan;
|
|
24
|
+
maxRetry;
|
|
25
|
+
constructor(storage, executor, planner, options) {
|
|
26
|
+
this.storage = storage;
|
|
27
|
+
this.executor = executor;
|
|
28
|
+
this.planner = planner;
|
|
29
|
+
this.enableReplan = options?.enableReplan ?? (process.env.ENABLE_METHODOLOGY_REPLAN !== 'false');
|
|
30
|
+
this.maxRetry = options?.maxRetry ?? parseInt(process.env.MAX_METHODOLOGY_RETRY || '2', 10);
|
|
31
|
+
}
|
|
32
|
+
async run(execution_id) {
|
|
33
|
+
const execution = this.storage.getMethodologyExecution(execution_id);
|
|
34
|
+
if (!execution)
|
|
35
|
+
throw new Error(`execution ${execution_id} not found`);
|
|
36
|
+
if (execution.status !== 'running') {
|
|
37
|
+
logger.info(`[Orchestrator] execution ${execution_id} status=${execution.status}, nothing to do`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const plan = JSON.parse(execution.plan_json);
|
|
41
|
+
const startFrom = execution.current_phase_index ?? 0;
|
|
42
|
+
for (let i = startFrom; i < plan.phases.length; i++) {
|
|
43
|
+
const phase = plan.phases[i];
|
|
44
|
+
logger.info(`[Orchestrator] execution=${execution_id} phase=${i + 1}/${plan.phases.length} (${phase.id} → ${phase.agent})`);
|
|
45
|
+
const fresh = this.storage.getMethodologyExecution(execution_id);
|
|
46
|
+
if (fresh.status !== 'running') {
|
|
47
|
+
logger.info(`[Orchestrator] execution=${execution_id} status changed to ${fresh.status}, stopping`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
this.storage.updateMethodologyExecution(execution_id, {
|
|
51
|
+
current_phase_index: i,
|
|
52
|
+
last_progress_at: Date.now(),
|
|
53
|
+
});
|
|
54
|
+
const result = await this.executor.executePhase(fresh, phase, i);
|
|
55
|
+
if (this.executor.mode === 'foreground') {
|
|
56
|
+
// Foreground 模式:只入队第一阶段,后续由 PostToolUse 推进。
|
|
57
|
+
logger.info(`[Orchestrator] foreground injected phase ${i}, handing off to hook pipeline`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Background 模式:result 指示 phase 的真实状态
|
|
61
|
+
if (result.status === 'failed') {
|
|
62
|
+
// 尝试失败反馈环
|
|
63
|
+
const replanSucceeded = await this.attemptReplan(execution_id, i, result.error || 'unknown error', plan);
|
|
64
|
+
if (replanSucceeded) {
|
|
65
|
+
// Replan 成功,继续执行(从下一个 phase 开始,因为 plan 已更新)
|
|
66
|
+
logger.info(`[Orchestrator] replan succeeded, continuing execution from phase ${i + 1}`);
|
|
67
|
+
// 重新加载更新后的 plan
|
|
68
|
+
const updatedExecution = this.storage.getMethodologyExecution(execution_id);
|
|
69
|
+
const updatedPlan = JSON.parse(updatedExecution.plan_json);
|
|
70
|
+
// 递归调用 run 以继续执行更新后的计划
|
|
71
|
+
return this.run(execution_id);
|
|
72
|
+
}
|
|
73
|
+
// Replan 失败或未启用,标记 execution 为 failed
|
|
74
|
+
this.storage.updateMethodologyExecution(execution_id, {
|
|
75
|
+
status: 'failed',
|
|
76
|
+
completed_at: Date.now(),
|
|
77
|
+
worker_pid: null,
|
|
78
|
+
});
|
|
79
|
+
logger.warn(`[Orchestrator] execution=${execution_id} failed at phase ${i}: ${result.error}`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (result.status === 'cancelled') {
|
|
83
|
+
this.storage.updateMethodologyExecution(execution_id, {
|
|
84
|
+
status: 'cancelled',
|
|
85
|
+
completed_at: Date.now(),
|
|
86
|
+
worker_pid: null,
|
|
87
|
+
});
|
|
88
|
+
logger.info(`[Orchestrator] execution=${execution_id} cancelled at phase ${i}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// 所有 phase 完成
|
|
93
|
+
this.storage.updateMethodologyExecution(execution_id, {
|
|
94
|
+
status: 'completed',
|
|
95
|
+
completed_at: Date.now(),
|
|
96
|
+
worker_pid: null,
|
|
97
|
+
});
|
|
98
|
+
logger.info(`[Orchestrator] execution=${execution_id} completed all ${plan.phases.length} phases`);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 尝试重新规划(失败反馈环)
|
|
102
|
+
* @returns true 如果 replan 成功并更新了 plan,false 否则
|
|
103
|
+
*/
|
|
104
|
+
async attemptReplan(execution_id, failedPhaseIndex, failureReason, currentPlan) {
|
|
105
|
+
// 检查是否启用 replan
|
|
106
|
+
if (!this.enableReplan) {
|
|
107
|
+
logger.info('[Orchestrator] replan disabled by configuration');
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
// 检查是否有 planner
|
|
111
|
+
if (!this.planner) {
|
|
112
|
+
logger.info('[Orchestrator] no planner available for replan');
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
// 检查 retry_count 是否达到上限
|
|
116
|
+
const execution = this.storage.getMethodologyExecution(execution_id);
|
|
117
|
+
const retryCount = execution.retry_count ?? 0;
|
|
118
|
+
if (retryCount >= this.maxRetry) {
|
|
119
|
+
logger.info(`[Orchestrator] retry_count=${retryCount} reached max=${this.maxRetry}, not replanning`);
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
logger.info(`[Orchestrator] attempting replan for execution=${execution_id}, phase=${failedPhaseIndex}, retry=${retryCount + 1}/${this.maxRetry}`);
|
|
123
|
+
// 获取原始计划
|
|
124
|
+
const originalPlan = execution.original_plan_json
|
|
125
|
+
? JSON.parse(execution.original_plan_json)
|
|
126
|
+
: currentPlan;
|
|
127
|
+
// 获取已完成的 phases
|
|
128
|
+
const completedPhases = currentPlan.phases.slice(0, failedPhaseIndex);
|
|
129
|
+
try {
|
|
130
|
+
// 调用 planner.replan()
|
|
131
|
+
const newPlan = await this.planner.replan({
|
|
132
|
+
executionId: execution_id,
|
|
133
|
+
failedPhaseIndex,
|
|
134
|
+
failureReason,
|
|
135
|
+
originalPlan,
|
|
136
|
+
completedPhases,
|
|
137
|
+
});
|
|
138
|
+
if (!newPlan) {
|
|
139
|
+
logger.info('[Orchestrator] planner determined recovery not possible');
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
// 更新 execution 的 plan 和 retry_count
|
|
143
|
+
this.storage.updateMethodologyExecution(execution_id, {
|
|
144
|
+
plan_json: JSON.stringify(newPlan),
|
|
145
|
+
retry_count: retryCount + 1,
|
|
146
|
+
current_phase_index: failedPhaseIndex, // 从失败的 phase 重新开始
|
|
147
|
+
last_progress_at: Date.now(),
|
|
148
|
+
});
|
|
149
|
+
logger.info(`[Orchestrator] replan successful, updated plan with ${newPlan.phases.length} phases`);
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
logger.warn(`[Orchestrator] replan failed with error: ${err}`);
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../../src/capability/executor/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse Claude CLI --output-format stream-json lines.
|
|
3
|
+
*
|
|
4
|
+
* 实际观测到的事件形状(claude 2.1.119):
|
|
5
|
+
* - {"type":"system","subtype":"init", session_id, tools, model, ...}
|
|
6
|
+
* - {"type":"assistant","message":{"content":[{"type":"text","text":"..."} | {"type":"tool_use", name, input, id}]}, session_id, uuid}
|
|
7
|
+
* - {"type":"user","message":{"content":[{"type":"tool_result", tool_use_id, content}]}, session_id}
|
|
8
|
+
* - {"type":"result","subtype":"success"|"error", is_error, result, total_cost_usd, duration_ms, session_id, ...}
|
|
9
|
+
*
|
|
10
|
+
* 本模块只做轻量抽取,不把所有字段建模 —— 用 as StreamEvent 读取关心的几个。
|
|
11
|
+
*/
|
|
12
|
+
export type StreamEvent = {
|
|
13
|
+
type: 'system';
|
|
14
|
+
subtype?: string;
|
|
15
|
+
session_id?: string;
|
|
16
|
+
[k: string]: unknown;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'assistant';
|
|
19
|
+
message: {
|
|
20
|
+
content: Array<ContentBlock>;
|
|
21
|
+
};
|
|
22
|
+
session_id?: string;
|
|
23
|
+
} | {
|
|
24
|
+
type: 'user';
|
|
25
|
+
message: {
|
|
26
|
+
content: Array<ContentBlock>;
|
|
27
|
+
};
|
|
28
|
+
session_id?: string;
|
|
29
|
+
} | {
|
|
30
|
+
type: 'result';
|
|
31
|
+
subtype?: 'success' | 'error';
|
|
32
|
+
is_error?: boolean;
|
|
33
|
+
result?: string;
|
|
34
|
+
total_cost_usd?: number;
|
|
35
|
+
duration_ms?: number;
|
|
36
|
+
session_id?: string;
|
|
37
|
+
stop_reason?: string;
|
|
38
|
+
};
|
|
39
|
+
export type ContentBlock = {
|
|
40
|
+
type: 'text';
|
|
41
|
+
text: string;
|
|
42
|
+
} | {
|
|
43
|
+
type: 'tool_use';
|
|
44
|
+
id: string;
|
|
45
|
+
name: string;
|
|
46
|
+
input: unknown;
|
|
47
|
+
} | {
|
|
48
|
+
type: 'tool_result';
|
|
49
|
+
tool_use_id: string;
|
|
50
|
+
content: unknown;
|
|
51
|
+
};
|
|
52
|
+
export interface ParseResult {
|
|
53
|
+
event: StreamEvent | null;
|
|
54
|
+
error?: string;
|
|
55
|
+
}
|
|
56
|
+
export declare function parseStreamLine(line: string): ParseResult;
|
|
57
|
+
/**
|
|
58
|
+
* Extract final assistant text from a result event (success subtype has `result` field).
|
|
59
|
+
*/
|
|
60
|
+
export declare function extractResultText(event: StreamEvent): string | null;
|
|
61
|
+
/**
|
|
62
|
+
* Extract tool_use blocks from an assistant message event (for observability / agent detection).
|
|
63
|
+
*/
|
|
64
|
+
export declare function extractToolUses(event: StreamEvent): Array<{
|
|
65
|
+
id: string;
|
|
66
|
+
name: string;
|
|
67
|
+
input: unknown;
|
|
68
|
+
}>;
|
|
69
|
+
/**
|
|
70
|
+
* Does this event signal the end of the turn? Result events mark completion.
|
|
71
|
+
*/
|
|
72
|
+
export declare function isTerminal(event: StreamEvent): boolean;
|
|
73
|
+
//# sourceMappingURL=stream-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-parser.d.ts","sourceRoot":"","sources":["../../../src/capability/executor/stream-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GAC/E;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE;QAAE,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,CAAA;KAAE,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACrF;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE;QAAE,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,CAAA;KAAE,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAChF;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAEnE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAYzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAKnE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAQvG;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAEtD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse Claude CLI --output-format stream-json lines.
|
|
3
|
+
*
|
|
4
|
+
* 实际观测到的事件形状(claude 2.1.119):
|
|
5
|
+
* - {"type":"system","subtype":"init", session_id, tools, model, ...}
|
|
6
|
+
* - {"type":"assistant","message":{"content":[{"type":"text","text":"..."} | {"type":"tool_use", name, input, id}]}, session_id, uuid}
|
|
7
|
+
* - {"type":"user","message":{"content":[{"type":"tool_result", tool_use_id, content}]}, session_id}
|
|
8
|
+
* - {"type":"result","subtype":"success"|"error", is_error, result, total_cost_usd, duration_ms, session_id, ...}
|
|
9
|
+
*
|
|
10
|
+
* 本模块只做轻量抽取,不把所有字段建模 —— 用 as StreamEvent 读取关心的几个。
|
|
11
|
+
*/
|
|
12
|
+
export function parseStreamLine(line) {
|
|
13
|
+
const trimmed = line.trim();
|
|
14
|
+
if (!trimmed)
|
|
15
|
+
return { event: null };
|
|
16
|
+
try {
|
|
17
|
+
const obj = JSON.parse(trimmed);
|
|
18
|
+
if (obj && typeof obj === 'object' && 'type' in obj) {
|
|
19
|
+
return { event: obj };
|
|
20
|
+
}
|
|
21
|
+
return { event: null, error: 'not a stream-json event (missing type)' };
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
return { event: null, error: `JSON parse failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Extract final assistant text from a result event (success subtype has `result` field).
|
|
29
|
+
*/
|
|
30
|
+
export function extractResultText(event) {
|
|
31
|
+
if (event.type === 'result' && 'result' in event && typeof event.result === 'string') {
|
|
32
|
+
return event.result;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Extract tool_use blocks from an assistant message event (for observability / agent detection).
|
|
38
|
+
*/
|
|
39
|
+
export function extractToolUses(event) {
|
|
40
|
+
if (event.type !== 'assistant')
|
|
41
|
+
return [];
|
|
42
|
+
const blocks = event.message?.content ?? [];
|
|
43
|
+
const out = [];
|
|
44
|
+
for (const b of blocks) {
|
|
45
|
+
if (b.type === 'tool_use')
|
|
46
|
+
out.push({ id: b.id, name: b.name, input: b.input });
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Does this event signal the end of the turn? Result events mark completion.
|
|
52
|
+
*/
|
|
53
|
+
export function isTerminal(event) {
|
|
54
|
+
return event.type === 'result';
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=stream-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-parser.js","sourceRoot":"","sources":["../../../src/capability/executor/stream-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA2BH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAC;QAC/C,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;YACpD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;QACxB,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAC;IAC1E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,sBAAsB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;IAC1G,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAkB;IAClD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACrF,OAAO,KAAK,CAAC,MAAM,CAAC;IACtB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAkB;IAChD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;IAC5C,MAAM,GAAG,GAAwD,EAAE,CAAC;IACpE,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,KAAkB;IAC3C,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Methodology Phase Executor — 接口 & 公共类型
|
|
3
|
+
*
|
|
4
|
+
* 两种执行模式复用同一份 plan 数据:
|
|
5
|
+
* - foreground:走 hook 注入,Claude 主会话执行(现有机制 + Phase A 兜底)
|
|
6
|
+
* - background:spawn `claude -p` 子进程独立驱动(Phase C)
|
|
7
|
+
*/
|
|
8
|
+
import type { MethodologyExecution, PlannedPhase } from '../types.js';
|
|
9
|
+
export type ExecutorMode = 'foreground' | 'background';
|
|
10
|
+
export interface PhaseExecutionResult {
|
|
11
|
+
/** 'injected' — foreground 已把指令注入;实际执行由 hook 链路完成 */
|
|
12
|
+
/** 'completed' — background 子进程跑完并标记 phase 完成 */
|
|
13
|
+
/** 'failed' — 执行失败(error 字段说明原因) */
|
|
14
|
+
/** 'cancelled' — 被手动取消 */
|
|
15
|
+
status: 'injected' | 'completed' | 'failed' | 'cancelled';
|
|
16
|
+
phase_index: number;
|
|
17
|
+
phase_id: string;
|
|
18
|
+
output_text?: string;
|
|
19
|
+
error?: string;
|
|
20
|
+
duration_ms?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface ExecutorEvent {
|
|
23
|
+
type: 'phase-start' | 'phase-log' | 'phase-finish' | 'done' | 'error';
|
|
24
|
+
execution_id: number;
|
|
25
|
+
phase_index?: number;
|
|
26
|
+
phase_id?: string;
|
|
27
|
+
payload?: unknown;
|
|
28
|
+
timestamp: number;
|
|
29
|
+
}
|
|
30
|
+
export type ExecutorEventListener = (event: ExecutorEvent) => void;
|
|
31
|
+
export interface PhaseExecutor {
|
|
32
|
+
readonly mode: ExecutorMode;
|
|
33
|
+
/**
|
|
34
|
+
* 执行一个 phase。各模式的语义:
|
|
35
|
+
* - foreground:把 directive 放入 pending queue,立即返回 status='injected'
|
|
36
|
+
* - background:spawn claude -p 并等待返回,更新 phase_executions 表
|
|
37
|
+
*/
|
|
38
|
+
executePhase(execution: MethodologyExecution, phase: PlannedPhase, phaseIndex: number): Promise<PhaseExecutionResult>;
|
|
39
|
+
/** 取消正在运行的 execution(background 会 kill 子进程;foreground 清队列) */
|
|
40
|
+
cancel(execution_id: number): Promise<void>;
|
|
41
|
+
/** 监听执行过程事件(用于 SSE / UI 实时展示) */
|
|
42
|
+
subscribe(listener: ExecutorEventListener): () => void;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/capability/executor/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEtE,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,YAAY,CAAC;AAEvD,MAAM,WAAW,oBAAoB;IACnC,qDAAqD;IACrD,iDAAiD;IACjD,oCAAoC;IACpC,0BAA0B;IAC1B,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EACA,aAAa,GACb,WAAW,GACX,cAAc,GACd,MAAM,GACN,OAAO,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAE5B;;;;OAIG;IACH,YAAY,CACV,SAAS,EAAE,oBAAoB,EAC/B,KAAK,EAAE,YAAY,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEjC,8DAA8D;IAC9D,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5C,iCAAiC;IACjC,SAAS,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,IAAI,CAAC;CACxD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/capability/executor/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* worker-auth-probe —— 轻量探测 claude CLI 是否拥有可用认证。
|
|
3
|
+
*
|
|
4
|
+
* 设计原则:
|
|
5
|
+
* - 不启动子进程、不做网络调用,只看 env / 磁盘文件
|
|
6
|
+
* - 宁可 false-negative(判 available=true 实际失败后由 worker 报错),
|
|
7
|
+
* 也不 false-positive 阻断能跑的场景
|
|
8
|
+
* - 只检查 env `ANTHROPIC_API_KEY` 和 `~/.claude/.credentials.json`,
|
|
9
|
+
* 不探测 macOS keychain(平台相关,成本高于收益)
|
|
10
|
+
*/
|
|
11
|
+
export type WorkerAuthMethod = 'api-key-env' | 'oauth-token' | 'keychain' | 'unknown' | 'none';
|
|
12
|
+
export interface WorkerAuthProbe {
|
|
13
|
+
available: boolean;
|
|
14
|
+
method: WorkerAuthMethod;
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 后台 worker 认证缺失错误,带 `code` 便于上层(Web API)分流返回 503。
|
|
19
|
+
*/
|
|
20
|
+
export declare class WorkerAuthError extends Error {
|
|
21
|
+
readonly code: "AUTH_REQUIRED";
|
|
22
|
+
readonly probe: WorkerAuthProbe;
|
|
23
|
+
constructor(probe: WorkerAuthProbe);
|
|
24
|
+
}
|
|
25
|
+
export interface ProbeOptions {
|
|
26
|
+
/** 覆盖凭据文件路径,便于测试 */
|
|
27
|
+
credentialsPath?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function probeWorkerAuth(options?: ProbeOptions): WorkerAuthProbe;
|
|
30
|
+
//# sourceMappingURL=worker-auth-probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-auth-probe.d.ts","sourceRoot":"","sources":["../../../src/capability/executor/worker-auth-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,MAAM,MAAM,gBAAgB,GACxB,aAAa,GACb,aAAa,GACb,UAAU,GACV,SAAS,GACT,MAAM,CAAC;AAEX,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,gBAAgB,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAG,eAAe,CAAU;IACzC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;gBAEpB,KAAK,EAAE,eAAe;CAQnC;AAoCD,MAAM,WAAW,YAAY;IAC3B,oBAAoB;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,OAAO,GAAE,YAAiB,GAAG,eAAe,CA8C3E"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* worker-auth-probe —— 轻量探测 claude CLI 是否拥有可用认证。
|
|
3
|
+
*
|
|
4
|
+
* 设计原则:
|
|
5
|
+
* - 不启动子进程、不做网络调用,只看 env / 磁盘文件
|
|
6
|
+
* - 宁可 false-negative(判 available=true 实际失败后由 worker 报错),
|
|
7
|
+
* 也不 false-positive 阻断能跑的场景
|
|
8
|
+
* - 只检查 env `ANTHROPIC_API_KEY` 和 `~/.claude/.credentials.json`,
|
|
9
|
+
* 不探测 macOS keychain(平台相关,成本高于收益)
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
/**
|
|
15
|
+
* 后台 worker 认证缺失错误,带 `code` 便于上层(Web API)分流返回 503。
|
|
16
|
+
*/
|
|
17
|
+
export class WorkerAuthError extends Error {
|
|
18
|
+
code = 'AUTH_REQUIRED';
|
|
19
|
+
probe;
|
|
20
|
+
constructor(probe) {
|
|
21
|
+
super(`Background mode requires Claude authentication: ${probe.message}. ` +
|
|
22
|
+
'Set ANTHROPIC_API_KEY (or ANTHROPIC_AUTH_TOKEN for third-party proxies), or run `claude login` first.');
|
|
23
|
+
this.name = 'WorkerAuthError';
|
|
24
|
+
this.probe = probe;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 默认 OAuth 凭据文件路径:`~/.claude/.credentials.json`
|
|
29
|
+
* 官方 claude-code 在首次登录后写到这里。
|
|
30
|
+
*/
|
|
31
|
+
function defaultCredentialsPath() {
|
|
32
|
+
return path.join(homedir(), '.claude', '.credentials.json');
|
|
33
|
+
}
|
|
34
|
+
function isNonEmptyString(v) {
|
|
35
|
+
return typeof v === 'string' && v.trim().length > 0;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 粗判 credentials.json 是否"像"一份合法的 OAuth 凭据。
|
|
39
|
+
* 只要能 parse 出对象且含任何 token 形字段就算通过——实际有效性交给 worker 验证。
|
|
40
|
+
*/
|
|
41
|
+
function looksLikeOAuthCredentials(raw) {
|
|
42
|
+
try {
|
|
43
|
+
const parsed = JSON.parse(raw);
|
|
44
|
+
if (!parsed || typeof parsed !== 'object')
|
|
45
|
+
return false;
|
|
46
|
+
const obj = parsed;
|
|
47
|
+
// 常见字段:claudeAiOauth.accessToken / accessToken / oauth / tokens 等
|
|
48
|
+
// 宽松识别即可:有对象内容就认为配过
|
|
49
|
+
if (isNonEmptyString(obj.accessToken))
|
|
50
|
+
return true;
|
|
51
|
+
if (obj.claudeAiOauth && typeof obj.claudeAiOauth === 'object')
|
|
52
|
+
return true;
|
|
53
|
+
if (obj.oauth && typeof obj.oauth === 'object')
|
|
54
|
+
return true;
|
|
55
|
+
if (obj.tokens && typeof obj.tokens === 'object')
|
|
56
|
+
return true;
|
|
57
|
+
// 兜底:只要 JSON 不是空对象就当有配置
|
|
58
|
+
return Object.keys(obj).length > 0;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function probeWorkerAuth(options = {}) {
|
|
65
|
+
// 1) env 优先
|
|
66
|
+
const envKey = process.env.ANTHROPIC_API_KEY;
|
|
67
|
+
if (isNonEmptyString(envKey)) {
|
|
68
|
+
return {
|
|
69
|
+
available: true,
|
|
70
|
+
method: 'api-key-env',
|
|
71
|
+
message: 'ANTHROPIC_API_KEY env is set',
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// 1b) 第三方代理(如 iFlytek / OneHub)使用 ANTHROPIC_AUTH_TOKEN
|
|
75
|
+
const envToken = process.env.ANTHROPIC_AUTH_TOKEN;
|
|
76
|
+
if (isNonEmptyString(envToken)) {
|
|
77
|
+
return {
|
|
78
|
+
available: true,
|
|
79
|
+
method: 'api-key-env',
|
|
80
|
+
message: 'ANTHROPIC_AUTH_TOKEN env is set',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// 2) OAuth credentials 文件
|
|
84
|
+
const credPath = options.credentialsPath ?? defaultCredentialsPath();
|
|
85
|
+
if (existsSync(credPath)) {
|
|
86
|
+
try {
|
|
87
|
+
const raw = readFileSync(credPath, 'utf-8');
|
|
88
|
+
if (looksLikeOAuthCredentials(raw)) {
|
|
89
|
+
return {
|
|
90
|
+
available: true,
|
|
91
|
+
method: 'oauth-token',
|
|
92
|
+
message: `OAuth credentials found at ${credPath}`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// ignore — 读失败当作不可用
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// 3) 都没有
|
|
101
|
+
return {
|
|
102
|
+
available: false,
|
|
103
|
+
method: 'none',
|
|
104
|
+
message: 'no ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN env and no OAuth credentials on disk ' +
|
|
105
|
+
`(expected ${credPath})`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=worker-auth-probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-auth-probe.js","sourceRoot":"","sources":["../../../src/capability/executor/worker-auth-probe.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,11 +10,23 @@ trigger:
|
|
|
10
10
|
complexity:
|
|
11
11
|
- moderate
|
|
12
12
|
- complex
|
|
13
|
+
# keywords 命中才触发,避免 taskType + complexity 导致的误触发
|
|
14
|
+
# BMad 是四角色敏捷方法论,面向 story/sprint 级别的完整功能开发
|
|
13
15
|
keywords:
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
16
|
+
- 敏捷
|
|
17
|
+
- agile
|
|
18
|
+
- story
|
|
19
|
+
- 用户故事
|
|
20
|
+
- user story
|
|
21
|
+
- sprint
|
|
22
|
+
- 迭代
|
|
23
|
+
- 需求分析
|
|
24
|
+
- 产品需求
|
|
25
|
+
- 完整功能
|
|
26
|
+
- 端到端
|
|
27
|
+
- end-to-end
|
|
28
|
+
- 四角色
|
|
29
|
+
- bmad
|
|
18
30
|
|
|
19
31
|
# 阶段模板库
|
|
20
32
|
phase_templates:
|
|
@@ -28,7 +40,7 @@ phase_templates:
|
|
|
28
40
|
required: true
|
|
29
41
|
|
|
30
42
|
design:
|
|
31
|
-
agent:
|
|
43
|
+
agent: planner
|
|
32
44
|
prompt_template: "As Architect: Design technical solution for {target}. Based on requirements document. Output: architecture design, module structure, interfaces, data flow. Document to docs/{target}-design.md"
|
|
33
45
|
description: "Architect designs technical solution"
|
|
34
46
|
artifacts:
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
id: code-quality-audit
|
|
2
|
+
name: "代码质量审计"
|
|
3
|
+
description: "Automated code quality audit during idle time"
|
|
4
|
+
|
|
5
|
+
# Idle 触发配置
|
|
6
|
+
idle_trigger:
|
|
7
|
+
enabled: true
|
|
8
|
+
interval: 7200000 # 2 小时(毫秒)
|
|
9
|
+
priority: low
|
|
10
|
+
|
|
11
|
+
# 不设置 trigger,因为这是 idle 专用方法论
|
|
12
|
+
trigger:
|
|
13
|
+
taskType: []
|
|
14
|
+
complexity: []
|
|
15
|
+
keywords: []
|
|
16
|
+
|
|
17
|
+
# 单阶段审计任务
|
|
18
|
+
phase_templates:
|
|
19
|
+
audit:
|
|
20
|
+
agent: reviewer
|
|
21
|
+
prompt_template: "Audit code quality: check for code smells, security issues, performance bottlenecks. Output report to docs/code-quality-audit.md"
|
|
22
|
+
description: "Audit code quality"
|
|
23
|
+
artifacts:
|
|
24
|
+
- type: file
|
|
25
|
+
pattern: "docs/**/*audit*.md"
|
|
26
|
+
required: false
|
|
@@ -10,12 +10,18 @@ trigger:
|
|
|
10
10
|
complexity:
|
|
11
11
|
- moderate
|
|
12
12
|
- complex
|
|
13
|
-
# keywords
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
# keywords 命中才触发,避免 taskType + complexity 导致的误触发
|
|
14
|
+
keywords:
|
|
15
|
+
- 重构
|
|
16
|
+
- refactor
|
|
17
|
+
- 迁移
|
|
18
|
+
- migrate
|
|
19
|
+
- 遗留代码
|
|
20
|
+
- legacy
|
|
21
|
+
- 技术债
|
|
22
|
+
- technical debt
|
|
23
|
+
- 改写
|
|
24
|
+
- rewrite
|
|
19
25
|
|
|
20
26
|
# 阶段模板库(供 AI Planner 选择)
|
|
21
27
|
phase_templates:
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
id: test-coverage-scan
|
|
2
|
+
name: "测试覆盖率扫描"
|
|
3
|
+
description: "Automated test coverage analysis during idle time"
|
|
4
|
+
|
|
5
|
+
# Idle 触发配置
|
|
6
|
+
idle_trigger:
|
|
7
|
+
enabled: true
|
|
8
|
+
interval: 3600000 # 1 小时(毫秒)
|
|
9
|
+
priority: low
|
|
10
|
+
|
|
11
|
+
# 不设置 trigger,因为这是 idle 专用方法论
|
|
12
|
+
trigger:
|
|
13
|
+
taskType: []
|
|
14
|
+
complexity: []
|
|
15
|
+
keywords: []
|
|
16
|
+
|
|
17
|
+
# 单阶段扫描任务
|
|
18
|
+
phase_templates:
|
|
19
|
+
scan:
|
|
20
|
+
agent: researcher
|
|
21
|
+
prompt_template: "Analyze test coverage for the project. Identify untested modules and critical paths. Output report to docs/test-coverage-report.md"
|
|
22
|
+
description: "Scan test coverage"
|
|
23
|
+
artifacts:
|
|
24
|
+
- type: test_coverage
|
|
25
|
+
min: 0
|
|
26
|
+
required: false
|