@winspan/claude-forge 8.28.2 → 8.30.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 +59 -0
- package/dist/capability/execution-manager.d.ts.map +1 -0
- package/dist/capability/execution-manager.js +168 -0
- package/dist/capability/execution-manager.js.map +1 -0
- package/dist/capability/executor/background-executor.d.ts +57 -0
- package/dist/capability/executor/background-executor.d.ts.map +1 -0
- package/dist/capability/executor/background-executor.js +299 -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 +25 -0
- package/dist/capability/executor/orchestrator.d.ts.map +1 -0
- package/dist/capability/executor/orchestrator.js +79 -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 +99 -0
- package/dist/capability/executor/worker-auth-probe.js.map +1 -0
- package/dist/capability/types.d.ts +10 -1
- package/dist/capability/types.d.ts.map +1 -1
- package/dist/core/storage/sqlite.d.ts +18 -0
- package/dist/core/storage/sqlite.d.ts.map +1 -1
- package/dist/core/storage/sqlite.js +75 -4
- package/dist/core/storage/sqlite.js.map +1 -1
- 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/stop.d.ts +6 -1
- package/dist/daemon/handlers/stop.d.ts.map +1 -1
- package/dist/daemon/handlers/stop.js +45 -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 +34 -1
- package/dist/daemon/handlers/user-prompt.js.map +1 -1
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +20 -1
- 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/web/server.d.ts +6 -0
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +127 -7
- package/dist/web/server.js.map +1 -1
- package/dist/web/static/assets/AIConfig-nZgwaowr.js +2 -0
- package/dist/web/static/assets/AIConfig-nZgwaowr.js.map +1 -0
- package/dist/web/static/assets/Agents-BZGXKWC7.js +2 -0
- package/dist/web/static/assets/Agents-BZGXKWC7.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-CnA3f740.js +2 -0
- package/dist/web/static/assets/Events-CnA3f740.js.map +1 -0
- package/dist/web/static/assets/ExecutionTrace-ClPfFIQa.js +2 -0
- package/dist/web/static/assets/ExecutionTrace-ClPfFIQa.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-CAXUXeox.js +2 -0
- package/dist/web/static/assets/Methodologies-CAXUXeox.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-DwWOKgnl.js +2 -0
- package/dist/web/static/assets/Sessions-DwWOKgnl.js.map +1 -0
- package/dist/web/static/assets/Skills-DhM6ALhr.js +2 -0
- package/dist/web/static/assets/Skills-DhM6ALhr.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-CVWult53.css +1 -0
- package/dist/web/static/assets/index-DUYj2ek1.js +3 -0
- package/dist/web/static/assets/index-DUYj2ek1.js.map +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 +1 -1
- 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
package/README.md
CHANGED
|
@@ -1,258 +1,111 @@
|
|
|
1
|
-
# Claude Forge
|
|
1
|
+
# Claude Forge
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> 为 Claude Code 设计的会话治理引擎 —— 通过 Hook 机制把方法论、路由、治理规则注入到 AI 开发流程中。
|
|
4
4
|
|
|
5
|
-
Claude Forge
|
|
5
|
+
Claude Forge 是一个在本地运行的守护进程,通过 Claude Code 的 Hook API 拦截 `UserPromptSubmit`、`PreToolUse`、`PostToolUse`、`Stop` 等事件,在其中做意图分类、方法论匹配、Agent 路由、规则阻断、治理建议。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**版本**: 8.29.0 · **Node**: >= 18 · **License**: MIT
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
基于 DSL 的规则引擎,实时阻断危险操作:
|
|
11
|
-
- 阻止 `rm -rf /` 等破坏性命令
|
|
12
|
-
- 警告 `git push --force` 等风险操作
|
|
13
|
-
- 支持自定义 YAML 规则
|
|
14
|
-
|
|
15
|
-
### 2. 技能推荐(UserPromptSubmit)
|
|
16
|
-
自动分析用户意图,推荐相关技能:
|
|
17
|
-
- 意图分类:simple / moderate / complex
|
|
18
|
-
- 关键词匹配技能库
|
|
19
|
-
- 注入技能内容到 systemMessage
|
|
9
|
+
---
|
|
20
10
|
|
|
21
|
-
|
|
22
|
-
AI 驱动的代码质量审查:
|
|
23
|
-
- 每 3 次 Write/Edit 触发一次审查
|
|
24
|
-
- 检测安全漏洞、代码质量问题
|
|
25
|
-
- 终端红色警告 + 修复建议注入
|
|
11
|
+
## 核心能力
|
|
26
12
|
|
|
27
|
-
###
|
|
28
|
-
|
|
29
|
-
- `decisions.md` — 决策摘要
|
|
30
|
-
- `timeline.md` — 时间线
|
|
31
|
-
- `.claude-forge/history/YYYY-MM-DD-{session}.md` — 完整历史
|
|
13
|
+
### 1. Hook 驱动的治理
|
|
14
|
+
daemon 以 Unix socket 形式与 Claude Code 的 Hook 脚本通信。每次 `UserPromptSubmit` / `PostToolUse` 等事件,daemon 在 100ms 内决定要不要往上下文注入额外指令或建议。
|
|
32
15
|
|
|
33
|
-
|
|
16
|
+
### 2. 方法论执行引擎
|
|
17
|
+
内置两种方法论(`harness-engineering`、`bmad`),AI Planner 根据任务复杂度自动生成多阶段执行计划。执行分两种模式:
|
|
34
18
|
|
|
35
|
-
|
|
19
|
+
- **前台(foreground)** —— 指令注入到当前 Claude Code 会话,由主对话按 plan 调用 `Task(subagent_type=...)` 完成每个阶段
|
|
20
|
+
- **后台(background)** —— daemon 直接 spawn 独立的 `claude -p` 子进程,与当前会话完全隔离地跑完整条 plan,用户离场也能自动完成
|
|
36
21
|
|
|
37
|
-
|
|
38
|
-
npm install -g @winspan/claude-forge
|
|
39
|
-
```
|
|
22
|
+
两种模式共享 plan / phase 数据模型,可在 Web 后台随时切换。
|
|
40
23
|
|
|
41
|
-
###
|
|
24
|
+
### 3. Agent 路由
|
|
25
|
+
基于 intent 分析(`complexity`、`taskType`)和 YAML 规则,UserPromptSubmit 阶段建议 Claude 用哪个子 agent(`researcher`、`tester`、`coder` 等)。路由决策全程记录到 `routing_events` 表,可用于离线分析和 A/B 实验。
|
|
42
26
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
这会:
|
|
48
|
-
1. 创建 `~/.claude-forge/` 目录
|
|
49
|
-
2. 复制 Hook 脚本到 `~/.claude-forge/hooks/`
|
|
50
|
-
3. 复制规则文件到 `~/.claude/conventions/`
|
|
51
|
-
4. 注入 Hooks 到 Claude Code settings.json
|
|
52
|
-
|
|
53
|
-
### 启动守护进程
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
cf daemon start
|
|
57
|
-
```
|
|
27
|
+
### 4. Web 管理后台
|
|
28
|
+
`claude-forge daemon start` 默认在 `http://127.0.0.1:3721` 开放一个 React 管理后台,覆盖:会话浏览、事件流、执行追踪、方法论执行启动/取消、Agent/Skill 编辑、AI 配置、实时 SSE 日志。
|
|
58
29
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
### 查看状态
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
cf status
|
|
65
|
-
```
|
|
30
|
+
---
|
|
66
31
|
|
|
67
|
-
|
|
32
|
+
## 快速开始
|
|
68
33
|
|
|
69
34
|
```bash
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# 方式 2:配置文件
|
|
74
|
-
cf config edit
|
|
75
|
-
# 添加:
|
|
76
|
-
# distill:
|
|
77
|
-
# api_key: sk-ant-...
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## 架构
|
|
81
|
-
|
|
82
|
-
```
|
|
83
|
-
src/
|
|
84
|
-
├── cli/ 363 行 — 4 个命令(init, daemon, status, config)
|
|
85
|
-
├── core/ 532 行 — 类型、配置、存储、AI、工具
|
|
86
|
-
├── daemon/ 825 行 — 守护进程 + 4 个 handler
|
|
87
|
-
├── engine/ 1743 行 — RuleEngine + DSL
|
|
88
|
-
├── intelligence/ 465 行 — 意图分析、质量门禁、蒸馏
|
|
89
|
-
└── skills/ 118 行 — 技能注册、匹配
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### 4 条数据通路
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
UserPromptSubmit → IntentClassifier → SkillRegistry → 注入技能推荐
|
|
96
|
-
PreToolUse → RuleEngine → block/warn/allow
|
|
97
|
-
PostToolUse → QualityGate → 注入纠偏 + 终端警告
|
|
98
|
-
Stop → Distiller → 导出历史
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## 内置规则库
|
|
102
|
-
|
|
103
|
-
Forge v3 包含 11 个技术栈专项规范(980 行规则):
|
|
104
|
-
|
|
105
|
-
| 规范文件 | 覆盖范围 | 规则数 |
|
|
106
|
-
|---------|---------|--------|
|
|
107
|
-
| `basic-security.yaml` | 通用安全(Git、文件系统、数据库) | 10 |
|
|
108
|
-
| `git-safety.yaml` | Git 操作安全 | 12 |
|
|
109
|
-
| `code-quality.yaml` | 代码质量(调试残留、类型安全) | 8 |
|
|
110
|
-
| `dependency-safety.yaml` | 依赖安全 | 10 |
|
|
111
|
-
| `react-best-practices.yaml` | React/前端开发 | 6 |
|
|
112
|
-
| `python-best-practices.yaml` | Python 开发 | 6 |
|
|
113
|
-
| `go-best-practices.yaml` | Go 开发 | 5 |
|
|
114
|
-
| `database-safety.yaml` | 数据库操作 | 5 |
|
|
115
|
-
| `docker-safety.yaml` | Docker/容器化 | 4 |
|
|
116
|
-
| `ts-quality.yaml` | TypeScript 质量 | 3 |
|
|
117
|
-
| `strict-security.yaml` | 严格安全模式 | 2 |
|
|
118
|
-
|
|
119
|
-
### 规则示例
|
|
120
|
-
|
|
121
|
-
**React XSS 防护**:
|
|
122
|
-
```yaml
|
|
123
|
-
- id: "no-dangerously-set-inner-html"
|
|
124
|
-
when: |
|
|
125
|
-
tool.in(["Write", "Edit"])
|
|
126
|
-
&& file_ext.in([".jsx", ".tsx"])
|
|
127
|
-
&& (args.content ?? args.new_string ?? "").match(/dangerouslySetInnerHTML/).ok()
|
|
128
|
-
level: warn
|
|
129
|
-
message: "检测到 dangerouslySetInnerHTML,存在 XSS 风险"
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
**Python 命令注入防护**:
|
|
133
|
-
```yaml
|
|
134
|
-
- id: "no-shell-injection"
|
|
135
|
-
when: |
|
|
136
|
-
tool.in(["Write", "Edit"])
|
|
137
|
-
&& file_ext == ".py"
|
|
138
|
-
&& (args.content ?? args.new_string ?? "").match(/subprocess\.(call|run|Popen)\([^)]*shell\s*=\s*True/).ok()
|
|
139
|
-
level: warn
|
|
140
|
-
message: "检测到 subprocess 使用 shell=True,存在命令注入风险"
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**数据库误删防护**:
|
|
144
|
-
```yaml
|
|
145
|
-
- id: "warn-delete-without-where"
|
|
146
|
-
when: |
|
|
147
|
-
tool.in(["Write", "Edit", "Bash"])
|
|
148
|
-
&& (args.content ?? args.new_string ?? args.command ?? "").lower().match(/delete\s+from\s+\w+\s*;/).ok()
|
|
149
|
-
level: block
|
|
150
|
-
message: "检测到无 WHERE 条件的 DELETE,会删除全表数据"
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## 自定义规则
|
|
154
|
-
|
|
155
|
-
编辑 `~/.claude/conventions/*.yaml` 添加项目特定规则:
|
|
156
|
-
|
|
157
|
-
```yaml
|
|
158
|
-
id: "my-rules"
|
|
159
|
-
name: "项目自定义规则"
|
|
160
|
-
version: "1.0.0"
|
|
161
|
-
triggers: ["custom", "project"]
|
|
162
|
-
|
|
163
|
-
forbidden:
|
|
164
|
-
- id: no-force-push
|
|
165
|
-
when: tool == 'Bash' && args.command.contains('push --force')
|
|
166
|
-
level: warn
|
|
167
|
-
message: Force push 会覆盖远程历史
|
|
35
|
+
# 1. 安装
|
|
36
|
+
npm install -g @winspan/claude-forge
|
|
168
37
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
- 禁止强制推送
|
|
172
|
-
```
|
|
38
|
+
# 2. 初始化(把 hook 脚本装到 ~/.claude/hooks/)
|
|
39
|
+
cf init
|
|
173
40
|
|
|
174
|
-
|
|
41
|
+
# 3. 配置 AI Provider(可选,但未配置时方法论规划走降级规则)
|
|
42
|
+
cf config
|
|
175
43
|
|
|
176
|
-
|
|
177
|
-
cf daemon stop
|
|
44
|
+
# 4. 启动 daemon
|
|
178
45
|
cf daemon start
|
|
179
|
-
```
|
|
180
46
|
|
|
181
|
-
|
|
47
|
+
# 5. 打开管理后台
|
|
48
|
+
open http://127.0.0.1:3721
|
|
49
|
+
```
|
|
182
50
|
|
|
183
|
-
|
|
51
|
+
之后在任何目录下开 Claude Code 会话,daemon 会自动接管 hook 事件。
|
|
184
52
|
|
|
185
|
-
```markdown
|
|
186
|
-
---
|
|
187
|
-
name: React 组件开发
|
|
188
|
-
keywords: [react, 组件, component]
|
|
189
53
|
---
|
|
190
54
|
|
|
191
|
-
|
|
55
|
+
## 方法论执行模式
|
|
192
56
|
|
|
193
|
-
|
|
194
|
-
2. Props 类型定义用 TypeScript interface
|
|
195
|
-
3. 状态管理优先 useState,复杂场景用 useReducer
|
|
196
|
-
...
|
|
197
|
-
```
|
|
57
|
+
创建执行有两种途径:
|
|
198
58
|
|
|
199
|
-
|
|
59
|
+
- **UserPromptSubmit 自动触发** → 默认走**前台**。用户发出类似"帮我重构 xxx"时,daemon 识别 refactor 类任务自动创建 methodology execution,并把阶段 1 指令注入到当前 Claude Code 会话。
|
|
60
|
+
- **Web 管理后台手动创建** → 默认走**后台**。在 `/methodologies` 页面点"新建执行",选择方法论、session id、mode,daemon 立即 spawn `claude -p` 子进程按 plan 顺序跑完所有阶段。
|
|
200
61
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
```bash
|
|
204
|
-
npm run build
|
|
205
|
-
```
|
|
62
|
+
> **前台模式的边界**:如果 Claude 主会话没有任何新输入,daemon 无法主动推 —— 只有 UserPromptSubmit / Stop hook 被触发时才能搭便车注入指令。Stop hook 会检测"当前阶段未推进"并把指令写入 pending 队列,下一次 UserPrompt 时自动消费。**实际生效需要用户至少输入一次任意内容**。
|
|
206
63
|
|
|
207
|
-
|
|
64
|
+
后台模式不受此影响,但消耗额外 API 预算(每个阶段默认上限 `$2`)。
|
|
208
65
|
|
|
209
|
-
|
|
210
|
-
npm run test
|
|
211
|
-
```
|
|
66
|
+
---
|
|
212
67
|
|
|
213
|
-
|
|
68
|
+
## CLI 命令
|
|
214
69
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
cf
|
|
70
|
+
| 命令 | 说明 |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `cf init` | 初始化 hook 脚本到 `~/.claude/hooks/` |
|
|
73
|
+
| `cf daemon {start,stop,status}` | daemon 生命周期 |
|
|
74
|
+
| `cf config` | AI Provider 配置(API key、base_url、model) |
|
|
75
|
+
| `cf status` | 当前 daemon + Web + 存储概况 |
|
|
76
|
+
| `cf logs [--tail]` | 查看 daemon 日志 |
|
|
77
|
+
| `cf stats` | 近期 intent / 路由 / 方法论统计 |
|
|
78
|
+
| `cf rules` | 查看/编辑治理规则(YAML) |
|
|
79
|
+
| `cf agents` | 列出已注册 agent |
|
|
80
|
+
| `cf skills` | 列出可用 skills |
|
|
81
|
+
| `cf menu` | 交互式菜单(推荐入口) |
|
|
218
82
|
|
|
219
|
-
|
|
220
|
-
./test-e2e.sh
|
|
221
|
-
```
|
|
83
|
+
也可用 `claude-forge` 作为 `cf` 的完整别名。
|
|
222
84
|
|
|
223
|
-
|
|
85
|
+
---
|
|
224
86
|
|
|
225
|
-
|
|
226
|
-
|------|----|----|------|
|
|
227
|
-
| 文件数 | 212 | 37 | -82.5% |
|
|
228
|
-
| 代码行数 | 35,617 | 4,046 | -88.6% |
|
|
229
|
-
| CLI 命令 | 14 | 4 | 精简 |
|
|
230
|
-
| Web UI | 有 | 无 | 第一版移除 |
|
|
231
|
-
| 核心通路 | 4(被淹没) | 4(清晰可见) | ✅ |
|
|
87
|
+
## Web 管理后台
|
|
232
88
|
|
|
233
|
-
|
|
234
|
-
- Web UI(可单独重写)
|
|
235
|
-
- Pipeline 编排系统
|
|
236
|
-
- 知识图谱
|
|
237
|
-
- 技能自进化
|
|
238
|
-
- CLAUDE.md 自动精炼
|
|
239
|
-
- Convention 管理
|
|
89
|
+
主要页面:
|
|
240
90
|
|
|
241
|
-
|
|
242
|
-
-
|
|
243
|
-
-
|
|
244
|
-
-
|
|
245
|
-
-
|
|
91
|
+
- `/dashboard` — 总览
|
|
92
|
+
- `/sessions` — 会话列表 + 详情
|
|
93
|
+
- `/events` — Hook 事件流
|
|
94
|
+
- `/execution-trace` — 路由决策追踪(含 SSE 实时)
|
|
95
|
+
- `/methodologies` — 方法论执行列表(mode 徽章 + 新建入口)
|
|
96
|
+
- `/methodologies/:id` — 执行详情(实时 SSE 事件流 + 每阶段 output/error)
|
|
97
|
+
- `/agents` / `/skills` — 在线编辑 `~/.claude/agents/*.md` 和 `~/.claude/skills/*.md`
|
|
98
|
+
- `/ai-config` — 切换 AI Provider / 测试连接
|
|
99
|
+
- `/routing` — 路由规则查看
|
|
246
100
|
|
|
247
|
-
|
|
101
|
+
所有列表支持搜索 + JSON/CSV 导出。
|
|
248
102
|
|
|
249
|
-
|
|
103
|
+
---
|
|
250
104
|
|
|
251
105
|
## 贡献
|
|
252
106
|
|
|
253
|
-
|
|
107
|
+
开发者文档见 [DEVELOPMENT.md](./DEVELOPMENT.md),包含仓库布局、构建/测试流程、架构说明、如何新增方法论或 Agent。
|
|
254
108
|
|
|
255
|
-
##
|
|
109
|
+
## License
|
|
256
110
|
|
|
257
|
-
|
|
258
|
-
- [Anthropic API](https://docs.anthropic.com/)
|
|
111
|
+
MIT © 2026 winspan
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExecutionManager — daemon 进程内单例,统筹所有 methodology_executions 的后台执行。
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* 1. 提供 `start({session_id, plan, mode})` 入口:为前台/后台两种模式分别使用合适的 executor
|
|
6
|
+
* 2. 跟踪活跃的 orchestrator,让 cancel() 能真正 kill 子进程
|
|
7
|
+
* 3. 在 daemon 启动时扫一遍 listRunningBackgroundExecutions() —— 对应 worker
|
|
8
|
+
* 已不在了(孤儿 execution),标记为 failed("crashed")
|
|
9
|
+
*
|
|
10
|
+
* 不负责:路由决策 / planner / UI。
|
|
11
|
+
*/
|
|
12
|
+
import type { SQLiteStorage } from '../core/storage/sqlite.js';
|
|
13
|
+
import type { MethodologyRegistry } from './methodology-registry.js';
|
|
14
|
+
import type { ExecutionPlan } from './types.js';
|
|
15
|
+
import type { ExecutorEventListener } from './executor/types.js';
|
|
16
|
+
import { type BackgroundExecutorOptions } from './executor/background-executor.js';
|
|
17
|
+
export interface StartExecutionInput {
|
|
18
|
+
session_id: string;
|
|
19
|
+
methodology_id: string;
|
|
20
|
+
plan: ExecutionPlan;
|
|
21
|
+
mode: 'foreground' | 'background';
|
|
22
|
+
}
|
|
23
|
+
export interface ExecutionManagerOptions {
|
|
24
|
+
background?: BackgroundExecutorOptions;
|
|
25
|
+
}
|
|
26
|
+
export declare class ExecutionManager {
|
|
27
|
+
private storage;
|
|
28
|
+
private registry;
|
|
29
|
+
private foregroundExecutor;
|
|
30
|
+
private backgroundExecutor;
|
|
31
|
+
private activeOrchestrators;
|
|
32
|
+
private listeners;
|
|
33
|
+
private reconcileTimer;
|
|
34
|
+
constructor(storage: SQLiteStorage, registry: MethodologyRegistry, options?: ExecutionManagerOptions);
|
|
35
|
+
/**
|
|
36
|
+
* Create the execution row + kick off orchestrator.
|
|
37
|
+
* Returns the newly created execution id.
|
|
38
|
+
*/
|
|
39
|
+
start(input: StartExecutionInput): number;
|
|
40
|
+
cancel(execution_id: number): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Subscribe to all executor events. Returns an unsubscribe function.
|
|
43
|
+
*/
|
|
44
|
+
subscribe(listener: ExecutorEventListener): () => void;
|
|
45
|
+
/**
|
|
46
|
+
* At daemon startup: find background executions whose worker_pid is no longer
|
|
47
|
+
* alive. Mark them failed so the UI shows a definitive state.
|
|
48
|
+
*/
|
|
49
|
+
reconcileOrphansOnStartup(): void;
|
|
50
|
+
private isPidAlive;
|
|
51
|
+
/**
|
|
52
|
+
* Start a periodic reconcile loop — picks up workers killed while daemon
|
|
53
|
+
* was running (e.g. user kill -9'd the pid). Safe to call once at startup.
|
|
54
|
+
* Returns a stop function.
|
|
55
|
+
*/
|
|
56
|
+
startReconcileLoop(intervalMs?: number): () => void;
|
|
57
|
+
stopReconcileLoop(): void;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=execution-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-manager.d.ts","sourceRoot":"","sources":["../../src/capability/execution-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAiB,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEhF,OAAO,EAAsB,KAAK,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAKvG,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,YAAY,GAAG,YAAY,CAAC;CACnC;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,yBAAyB,CAAC;CACxC;AAED,qBAAa,gBAAgB;IAQzB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;IARlB,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,mBAAmB,CAAmC;IAC9D,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,cAAc,CAA+B;gBAG3C,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,mBAAmB,EACrC,OAAO,GAAE,uBAA4B;IAevC;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM;IAkDnC,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjD;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,IAAI;IAKtD;;;OAGG;IACH,yBAAyB,IAAI,IAAI;IAkBjC,OAAO,CAAC,UAAU;IASlB;;;;OAIG;IACH,kBAAkB,CAAC,UAAU,SAAS,GAAG,MAAM,IAAI;IAiBnD,iBAAiB,IAAI,IAAI;CAI1B"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExecutionManager — daemon 进程内单例,统筹所有 methodology_executions 的后台执行。
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* 1. 提供 `start({session_id, plan, mode})` 入口:为前台/后台两种模式分别使用合适的 executor
|
|
6
|
+
* 2. 跟踪活跃的 orchestrator,让 cancel() 能真正 kill 子进程
|
|
7
|
+
* 3. 在 daemon 启动时扫一遍 listRunningBackgroundExecutions() —— 对应 worker
|
|
8
|
+
* 已不在了(孤儿 execution),标记为 failed("crashed")
|
|
9
|
+
*
|
|
10
|
+
* 不负责:路由决策 / planner / UI。
|
|
11
|
+
*/
|
|
12
|
+
import { ForegroundExecutor } from './executor/foreground-executor.js';
|
|
13
|
+
import { BackgroundExecutor } from './executor/background-executor.js';
|
|
14
|
+
import { Orchestrator } from './executor/orchestrator.js';
|
|
15
|
+
import { probeWorkerAuth, WorkerAuthError } from './executor/worker-auth-probe.js';
|
|
16
|
+
import { logger } from '../core/utils/logger.js';
|
|
17
|
+
export class ExecutionManager {
|
|
18
|
+
storage;
|
|
19
|
+
registry;
|
|
20
|
+
foregroundExecutor;
|
|
21
|
+
backgroundExecutor;
|
|
22
|
+
activeOrchestrators = new Map();
|
|
23
|
+
listeners = new Set();
|
|
24
|
+
reconcileTimer = null;
|
|
25
|
+
constructor(storage, registry, options = {}) {
|
|
26
|
+
this.storage = storage;
|
|
27
|
+
this.registry = registry;
|
|
28
|
+
this.foregroundExecutor = new ForegroundExecutor(storage, registry);
|
|
29
|
+
this.backgroundExecutor = new BackgroundExecutor(storage, registry, options.background);
|
|
30
|
+
// Relay executor events to external subscribers (SSE, metrics, ...)
|
|
31
|
+
const relay = (ev) => {
|
|
32
|
+
for (const l of this.listeners) {
|
|
33
|
+
try {
|
|
34
|
+
l(ev);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
logger.debug(`[ExecutionManager] relay failed: ${err}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
this.foregroundExecutor.subscribe(relay);
|
|
42
|
+
this.backgroundExecutor.subscribe(relay);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Create the execution row + kick off orchestrator.
|
|
46
|
+
* Returns the newly created execution id.
|
|
47
|
+
*/
|
|
48
|
+
start(input) {
|
|
49
|
+
// 后台模式:前置认证探测,给调用方明确错误而不是等 worker 起来后才报错
|
|
50
|
+
if (input.mode === 'background') {
|
|
51
|
+
const probe = probeWorkerAuth();
|
|
52
|
+
if (!probe.available) {
|
|
53
|
+
throw new WorkerAuthError(probe);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const executionId = this.storage.createMethodologyExecution({
|
|
57
|
+
session_id: input.session_id,
|
|
58
|
+
methodology_id: input.methodology_id,
|
|
59
|
+
plan_json: JSON.stringify(input.plan),
|
|
60
|
+
mode: input.mode,
|
|
61
|
+
});
|
|
62
|
+
// Seed the first phase_executions row so listings show immediately
|
|
63
|
+
if (input.plan.phases[0]) {
|
|
64
|
+
const p0 = input.plan.phases[0];
|
|
65
|
+
this.storage.createPhaseExecution({
|
|
66
|
+
methodology_execution_id: executionId,
|
|
67
|
+
phase_id: p0.id,
|
|
68
|
+
phase_index: 0,
|
|
69
|
+
agent_name: p0.agent,
|
|
70
|
+
prompt: p0.prompt,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const executor = input.mode === 'background' ? this.backgroundExecutor : this.foregroundExecutor;
|
|
74
|
+
const orch = new Orchestrator(this.storage, executor);
|
|
75
|
+
this.activeOrchestrators.set(executionId, orch);
|
|
76
|
+
// Fire-and-forget; errors are logged but don't crash the daemon.
|
|
77
|
+
orch.run(executionId)
|
|
78
|
+
.catch(err => {
|
|
79
|
+
logger.warn(`[ExecutionManager] orchestrator for ${executionId} threw: ${err}`);
|
|
80
|
+
try {
|
|
81
|
+
this.storage.updateMethodologyExecution(executionId, {
|
|
82
|
+
status: 'failed',
|
|
83
|
+
completed_at: Date.now(),
|
|
84
|
+
worker_pid: null,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
catch { /* swallow */ }
|
|
88
|
+
})
|
|
89
|
+
.finally(() => {
|
|
90
|
+
this.activeOrchestrators.delete(executionId);
|
|
91
|
+
});
|
|
92
|
+
return executionId;
|
|
93
|
+
}
|
|
94
|
+
async cancel(execution_id) {
|
|
95
|
+
const exec = this.storage.getMethodologyExecution(execution_id);
|
|
96
|
+
if (!exec)
|
|
97
|
+
throw new Error(`execution ${execution_id} not found`);
|
|
98
|
+
const executor = exec.mode === 'background'
|
|
99
|
+
? this.backgroundExecutor
|
|
100
|
+
: this.foregroundExecutor;
|
|
101
|
+
await executor.cancel(execution_id);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Subscribe to all executor events. Returns an unsubscribe function.
|
|
105
|
+
*/
|
|
106
|
+
subscribe(listener) {
|
|
107
|
+
this.listeners.add(listener);
|
|
108
|
+
return () => { this.listeners.delete(listener); };
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* At daemon startup: find background executions whose worker_pid is no longer
|
|
112
|
+
* alive. Mark them failed so the UI shows a definitive state.
|
|
113
|
+
*/
|
|
114
|
+
reconcileOrphansOnStartup() {
|
|
115
|
+
const rows = this.storage.listRunningBackgroundExecutions();
|
|
116
|
+
for (const row of rows) {
|
|
117
|
+
const pid = row.worker_pid;
|
|
118
|
+
const alive = pid ? this.isPidAlive(pid) : false;
|
|
119
|
+
if (!alive) {
|
|
120
|
+
logger.warn(`[ExecutionManager] execution=${row.id} has stale worker_pid=${pid}; marking failed`);
|
|
121
|
+
this.storage.updateMethodologyExecution(row.id, {
|
|
122
|
+
status: 'failed',
|
|
123
|
+
completed_at: Date.now(),
|
|
124
|
+
worker_pid: null,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
isPidAlive(pid) {
|
|
130
|
+
try {
|
|
131
|
+
process.kill(pid, 0);
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Start a periodic reconcile loop — picks up workers killed while daemon
|
|
140
|
+
* was running (e.g. user kill -9'd the pid). Safe to call once at startup.
|
|
141
|
+
* Returns a stop function.
|
|
142
|
+
*/
|
|
143
|
+
startReconcileLoop(intervalMs = 60_000) {
|
|
144
|
+
if (this.reconcileTimer)
|
|
145
|
+
clearInterval(this.reconcileTimer);
|
|
146
|
+
this.reconcileTimer = setInterval(() => {
|
|
147
|
+
try {
|
|
148
|
+
this.reconcileOrphansOnStartup();
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
logger.debug(`[ExecutionManager] periodic reconcile failed: ${err}`);
|
|
152
|
+
}
|
|
153
|
+
}, intervalMs);
|
|
154
|
+
// Don't keep the event loop alive just for this.
|
|
155
|
+
this.reconcileTimer.unref?.();
|
|
156
|
+
return () => {
|
|
157
|
+
if (this.reconcileTimer)
|
|
158
|
+
clearInterval(this.reconcileTimer);
|
|
159
|
+
this.reconcileTimer = null;
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
stopReconcileLoop() {
|
|
163
|
+
if (this.reconcileTimer)
|
|
164
|
+
clearInterval(this.reconcileTimer);
|
|
165
|
+
this.reconcileTimer = null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=execution-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-manager.js","sourceRoot":"","sources":["../../src/capability/execution-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BackgroundExecutor —— spawn `claude -p` 子进程独立执行一个 phase。
|
|
3
|
+
*
|
|
4
|
+
* 与 ForegroundExecutor 的差异:
|
|
5
|
+
* - 真正调用 CLI 并等待结束,所以 `executePhase` 返回的是最终 status
|
|
6
|
+
* ('completed' | 'failed'), 不是 'injected'
|
|
7
|
+
* - 不会改 pending queue —— 后台执行路径跟 Claude 主会话完全隔离
|
|
8
|
+
* - 进度通过 subscribe() 的 ExecutorEvent 对外暴露(SSE 可订阅)
|
|
9
|
+
*/
|
|
10
|
+
import type { MethodologyExecution, PlannedPhase } from '../types.js';
|
|
11
|
+
import type { SQLiteStorage } from '../../core/storage/sqlite.js';
|
|
12
|
+
import type { MethodologyRegistry } from '../methodology-registry.js';
|
|
13
|
+
import type { ExecutorEventListener, PhaseExecutionResult, PhaseExecutor } from './types.js';
|
|
14
|
+
export interface BackgroundExecutorOptions {
|
|
15
|
+
/** claude CLI 可执行文件路径(默认走 PATH) */
|
|
16
|
+
claudeBin?: string;
|
|
17
|
+
/** 子进程 cwd;默认为当前项目目录 */
|
|
18
|
+
cwd?: string;
|
|
19
|
+
/** 项目根目录,作为 --add-dir 的参数;默认走 cwd */
|
|
20
|
+
projectRoot?: string;
|
|
21
|
+
/** 每个 phase 的最大预算美元(默认 2) */
|
|
22
|
+
maxBudgetUsdPerPhase?: number;
|
|
23
|
+
/** 权限模式(默认 bypassPermissions) */
|
|
24
|
+
permissionMode?: 'acceptEdits' | 'bypassPermissions' | 'default' | 'dontAsk' | 'plan';
|
|
25
|
+
/** 默认禁用的工具(逗号分隔) */
|
|
26
|
+
disallowedTools?: string;
|
|
27
|
+
/** phase 级 wall-clock 超时(ms),默认 30 分钟 */
|
|
28
|
+
phaseTimeoutMs?: number;
|
|
29
|
+
/** stream-json 日志根目录 */
|
|
30
|
+
logDir?: string;
|
|
31
|
+
/**
|
|
32
|
+
* worker 专用 settings.json 路径。若未提供,会懒生成到
|
|
33
|
+
* `$HOME/.claude-forge/worker-settings.json`,内容为 `{"hooks": {}}`。
|
|
34
|
+
* 目的:让 worker 子进程跳过 daemon hooks,避免递归触发。
|
|
35
|
+
*/
|
|
36
|
+
settingsPath?: string;
|
|
37
|
+
}
|
|
38
|
+
export declare class BackgroundExecutor implements PhaseExecutor {
|
|
39
|
+
private storage;
|
|
40
|
+
private registry;
|
|
41
|
+
readonly mode: "background";
|
|
42
|
+
private listeners;
|
|
43
|
+
private running;
|
|
44
|
+
private readonly opts;
|
|
45
|
+
constructor(storage: SQLiteStorage, registry: MethodologyRegistry, options?: BackgroundExecutorOptions);
|
|
46
|
+
executePhase(execution: MethodologyExecution, phase: PlannedPhase, phaseIndex: number): Promise<PhaseExecutionResult>;
|
|
47
|
+
cancel(execution_id: number): Promise<void>;
|
|
48
|
+
subscribe(listener: ExecutorEventListener): () => void;
|
|
49
|
+
private emit;
|
|
50
|
+
/**
|
|
51
|
+
* @internal test-only: 构建 spawn 参数。生产代码请走 `executePhase`。
|
|
52
|
+
*/
|
|
53
|
+
buildArgs(): string[];
|
|
54
|
+
/** @internal test-only */
|
|
55
|
+
getSettingsPath(): string;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=background-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"background-executor.d.ts","sourceRoot":"","sources":["../../../src/capability/executor/background-executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EAEV,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACd,MAAM,YAAY,CAAC;AAWpB,MAAM,WAAW,yBAAyB;IACxC,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iCAAiC;IACjC,cAAc,CAAC,EAAE,aAAa,GAAG,mBAAmB,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACtF,oBAAoB;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAcD,qBAAa,kBAAmB,YAAW,aAAa;IAOpD,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;IAPlB,QAAQ,CAAC,IAAI,EAAG,YAAY,CAAU;IACtC,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,OAAO,CAAqD;IACpE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsF;gBAGjG,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,mBAAmB,EACrC,OAAO,GAAE,yBAA8B;IAiBnC,YAAY,CAChB,SAAS,EAAE,oBAAoB,EAC/B,KAAK,EAAE,YAAY,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,oBAAoB,CAAC;IA4M1B,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBjD,SAAS,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,IAAI;IAKtD,OAAO,CAAC,IAAI;IAMZ;;OAEG;IACH,SAAS,IAAI,MAAM,EAAE;IAoBrB,0BAA0B;IAC1B,eAAe,IAAI,MAAM;CAG1B"}
|