feihong-code 0.2.2 → 0.5.1

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.
Files changed (152) hide show
  1. package/.github/FUNDING.yml +4 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +37 -37
  3. package/.github/ISSUE_TEMPLATE/config.yml +14 -14
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +28 -28
  5. package/.github/PULL_REQUEST_TEMPLATE.md +46 -46
  6. package/.github/SECURITY.md +67 -67
  7. package/.github/dependabot.yml +16 -0
  8. package/.github/workflows/ci.yml +1 -1
  9. package/AGENT-GUIDE.md +382 -237
  10. package/CHANGELOG.md +405 -73
  11. package/CODE_OF_CONDUCT.md +56 -56
  12. package/CONTRIBUTING.md +68 -68
  13. package/LICENSE +22 -22
  14. package/README.md +31 -25
  15. package/README.self-evolve.md +274 -0
  16. package/dist/agent/code-review.js +2 -0
  17. package/dist/agent/code-review.js.map +1 -1
  18. package/dist/agent/code-writer.js +70 -17
  19. package/dist/agent/code-writer.js.map +1 -1
  20. package/dist/agent/context-compactor.js +13 -4
  21. package/dist/agent/context-compactor.js.map +1 -1
  22. package/dist/agent/experience.js +262 -62
  23. package/dist/agent/experience.js.map +1 -1
  24. package/dist/agent/orchestrator.js +148 -68
  25. package/dist/agent/orchestrator.js.map +1 -1
  26. package/dist/agent/quality-gate.js +10 -4
  27. package/dist/agent/quality-gate.js.map +1 -1
  28. package/dist/agent/repo-context.js +181 -0
  29. package/dist/agent/repo-context.js.map +1 -0
  30. package/dist/agent/repo-reader.js +92 -99
  31. package/dist/agent/repo-reader.js.map +1 -1
  32. package/dist/agent/self-heal.js +38 -48
  33. package/dist/agent/self-heal.js.map +1 -1
  34. package/dist/agent/self-improver.js +65 -61
  35. package/dist/agent/self-improver.js.map +1 -1
  36. package/dist/agent/subagent-summary.js +31 -0
  37. package/dist/agent/subagent-summary.js.map +1 -0
  38. package/dist/agent/subagent.js +52 -2
  39. package/dist/agent/subagent.js.map +1 -1
  40. package/dist/agent/symbol-index.js +160 -0
  41. package/dist/agent/symbol-index.js.map +1 -0
  42. package/dist/agent/team.js +193 -0
  43. package/dist/agent/team.js.map +1 -0
  44. package/dist/cli/commands.js +124 -143
  45. package/dist/cli/commands.js.map +1 -1
  46. package/dist/cli/index.js +113 -106
  47. package/dist/cli/index.js.map +1 -1
  48. package/dist/cli/repl.js +82 -7
  49. package/dist/cli/repl.js.map +1 -1
  50. package/dist/cli/run.js +601 -95
  51. package/dist/cli/run.js.map +1 -1
  52. package/dist/cli/tui.js +145 -0
  53. package/dist/cli/tui.js.map +1 -0
  54. package/dist/cli/version.js +1 -1
  55. package/dist/enterprise/audit.js +75 -12
  56. package/dist/enterprise/audit.js.map +1 -1
  57. package/dist/enterprise/index.js +14 -11
  58. package/dist/enterprise/index.js.map +1 -1
  59. package/dist/enterprise/policy.js +22 -10
  60. package/dist/enterprise/policy.js.map +1 -1
  61. package/dist/harness/executor.js +127 -0
  62. package/dist/harness/executor.js.map +1 -0
  63. package/dist/harness/harness.js +87 -0
  64. package/dist/harness/harness.js.map +1 -0
  65. package/dist/harness/index.js +31 -0
  66. package/dist/harness/index.js.map +1 -0
  67. package/dist/harness/loader.js +138 -0
  68. package/dist/harness/loader.js.map +1 -0
  69. package/dist/harness/reporter.js +34 -0
  70. package/dist/harness/reporter.js.map +1 -0
  71. package/dist/harness/types.js +10 -0
  72. package/dist/harness/types.js.map +1 -0
  73. package/dist/harness/verifier.js +48 -0
  74. package/dist/harness/verifier.js.map +1 -0
  75. package/dist/hello.js +14 -0
  76. package/dist/hello.js.map +1 -0
  77. package/dist/memory/auto-summarize.js +208 -0
  78. package/dist/memory/auto-summarize.js.map +1 -0
  79. package/dist/memory/index.js +228 -0
  80. package/dist/memory/index.js.map +1 -0
  81. package/dist/models/model-router.js +23 -10
  82. package/dist/models/model-router.js.map +1 -1
  83. package/dist/plugins/plugin-loader.js +179 -0
  84. package/dist/plugins/plugin-loader.js.map +1 -0
  85. package/dist/runtime/event-log.js.map +1 -1
  86. package/dist/runtime/hooks.js +80 -0
  87. package/dist/runtime/hooks.js.map +1 -0
  88. package/dist/self-evolve/hook.js +60 -0
  89. package/dist/self-evolve/hook.js.map +1 -0
  90. package/dist/shared/config.js +35 -3
  91. package/dist/shared/config.js.map +1 -1
  92. package/dist/shared/i18n.js +535 -0
  93. package/dist/shared/i18n.js.map +1 -0
  94. package/dist/skills/grill.js +2 -1
  95. package/dist/skills/grill.js.map +1 -1
  96. package/dist/skills/self-heal.js +73 -0
  97. package/dist/skills/self-heal.js.map +1 -0
  98. package/dist/skills/skill-loader.js +131 -0
  99. package/dist/skills/skill-loader.js.map +1 -0
  100. package/dist/skills/skill-market.js +195 -0
  101. package/dist/skills/skill-market.js.map +1 -0
  102. package/dist/tools/analysis/code-analyzer.js +45 -18
  103. package/dist/tools/analysis/code-analyzer.js.map +1 -1
  104. package/dist/tools/index.js +5 -0
  105. package/dist/tools/index.js.map +1 -1
  106. package/dist/tools/mcp/index.js +84 -0
  107. package/dist/tools/mcp/index.js.map +1 -0
  108. package/dist/tools/mcp/mcp-client.js +172 -0
  109. package/dist/tools/mcp/mcp-client.js.map +1 -0
  110. package/dist/tools/sandbox.js +126 -0
  111. package/dist/tools/sandbox.js.map +1 -0
  112. package/dist/tools/shell/exec.js +25 -0
  113. package/dist/tools/shell/exec.js.map +1 -1
  114. package/dist/tools/shell/run-shell.tool.js +4 -1
  115. package/dist/tools/shell/run-shell.tool.js.map +1 -1
  116. package/dist/tools/skills/load-skill.tool.js +36 -0
  117. package/dist/tools/skills/load-skill.tool.js.map +1 -0
  118. package/dist/tools/tool.interface.js.map +1 -1
  119. package/dist/tools/tool.registry.js +37 -1
  120. package/dist/tools/tool.registry.js.map +1 -1
  121. package/dist/tools/web/web.tool.js +139 -0
  122. package/dist/tools/web/web.tool.js.map +1 -0
  123. package/dist/web/auth.js +42 -3
  124. package/dist/web/auth.js.map +1 -1
  125. package/dist/web/channels.js +171 -0
  126. package/dist/web/channels.js.map +1 -0
  127. package/dist/web/public/index.html +3253 -39
  128. package/dist/web/public/index.html.tmp +3117 -0
  129. package/dist/web/public/index_new.html +3196 -0
  130. package/dist/web/server.js +790 -11
  131. package/dist/web/server.js.map +1 -1
  132. package/dist/web/task-queue.js +352 -0
  133. package/dist/web/task-queue.js.map +1 -0
  134. package/dist/web/web-config.js +143 -0
  135. package/dist/web/web-config.js.map +1 -0
  136. package/docs/Deployment_Guide_EN.md +288 -0
  137. package/docs/Technical_Manual_EN.md +216 -0
  138. package/docs/User_Manual_EN.md +314 -0
  139. package/docs/self-evolve-implementation.md +165 -0
  140. package/docs/self-evolve.md +166 -0
  141. package/docs//344/272/247/345/223/201/345/274/200/345/217/221/346/226/207/346/241/243.md +614 -614
  142. package/docs//344/274/201/344/270/232/351/203/250/347/275/262/344/270/216/345/220/210/350/247/204.md +267 -267
  143. package/docs//344/275/277/347/224/250/350/257/264/346/230/216/344/271/246.md +318 -358
  144. package/docs//345/270/270/350/247/201/351/227/256/351/242/230/344/270/216/346/225/205/351/232/234/346/216/222/346/237/245.md +130 -130
  145. package/docs//346/212/200/346/234/257/350/257/264/346/230/216/344/271/246.md +216 -303
  146. package/docs//346/236/266/346/236/204/344/270/216API.md +238 -238
  147. package/docs//347/224/250/346/210/267/346/211/213/345/206/214.md +196 -196
  148. package/docs//351/203/250/347/275/262/346/214/207/345/215/227.md +165 -165
  149. package/docs//351/203/250/347/275/262/350/257/264/346/230/216/344/271/246.md +288 -0
  150. package/docs//351/205/215/347/275/256/345/217/202/350/200/203.md +127 -127
  151. package/package.json +114 -109
  152. package/tool-schema.json +127 -127
@@ -1,238 +1,238 @@
1
- # 飞虹 Code 架构与 API
2
-
3
- > 晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹
4
-
5
- 本文面向**开发者/集成者**,讲解分层、编排循环、模型路由、工具协议、事件日志与并行架构。
6
-
7
- ---
8
-
9
- ## 1. 分层(feature-first)
10
-
11
- ```
12
- src/
13
- ├── cli/ 入口(commands/run/index/repl/version)
14
- ├── shared/ config / errors / logger / types
15
- ├── agent/ orchestrator / planner / prompts / parallel-orchestrator / subagent
16
- ├── tools/ tool.interface / tool.registry / safe-path + file|shell|search|verify
17
- ├── models/ model-router / model.interface / model.dto / cost + providers
18
- ├── runtime/ event-log / session-store / worktree
19
- └── skills/ plan / grill / goal
20
- ```
21
-
22
- 依赖方向:`cli → agent/tools/models/runtime → shared`,上层可依赖下层,下层不反向依赖。
23
-
24
- ---
25
-
26
- ## 2. 编排循环(ReAct)
27
-
28
- `Orchestrator.run(goal)`:
29
-
30
- ```
31
- 1. planTask(goal) → 系统提示 + 用户目标 → 初始消息
32
- 2. loop (max 12 次):
33
- a. router.chat(messages, ['code-gen']) → ChatResponse
34
- b. 若 message.toolCalls 为空 → 视为完成,break
35
- c. 对每个 toolCall: toolRegistry.execute(...) → 回填 role=tool 消息
36
- 3. 返回 { ok, finalAnswer, iterations, costUsd, logFile }
37
- ```
38
-
39
- - 每次模型调用写入事件日志(`model.response` / `tool.call` / `tool.result`)。
40
- - 温度固定 `0`,`max_tokens=4096`,超时 `180s`(AbortController)。
41
- - `maxIterations` 默认 12,可在构造 `OrchestratorDeps` 时覆盖。
42
-
43
- ---
44
-
45
- ## 3. 模型路由
46
-
47
- `ModelRouter`:
48
-
49
- - `rank(tags?)`:按 tags 过滤(全不命中则退回全量),按 `score()` 排序。
50
- - `score()`:`cost`→`-costPer1k`;`latency`→本地优先;`capability`→reasoning/code-gen 加权。
51
- - `chat(req, tags?)`:依次调用 provider,**任一成功即返回**;全部失败抛最后错误(自动 fallback)。
52
-
53
- ### Provider 接口(ModelProvider)
54
-
55
- ```ts
56
- interface ModelProvider {
57
- readonly id: string;
58
- readonly model: string;
59
- readonly tags: CapabilityTag[];
60
- readonly costPer1k?: number;
61
- chat(req: ChatRequest): Promise<ChatResponse>;
62
- }
63
- ```
64
-
65
- 已实现:`OpenAICompatibleProvider`(DeepSeek/通义/Agnes/任意 OpenAI 协议)、`OllamaProvider`(本地)、`ScriptedMockProvider`(离线)。
66
-
67
- ---
68
-
69
- ## 4. 工具协议
70
-
71
- ### 契约
72
-
73
- ```ts
74
- interface Tool {
75
- name: string;
76
- description: string;
77
- jsonSchema: Record<string, unknown>; // 给模型看的 JSON Schema
78
- schema: z.ZodTypeAny; // 运行时 zod 校验
79
- execute(args, ctx: ToolContext): Promise<ToolResult>;
80
- }
81
-
82
- interface ToolContext {
83
- runId: string;
84
- cwd: string; // 沙箱根
85
- security: { shellAllowlist: string[]; requireApproval: boolean };
86
- approve?: (action: string) => Promise<boolean>;
87
- }
88
-
89
- interface ToolResult { ok: boolean; output: string; error?: string; }
90
- ```
91
-
92
- ### 注册与执行
93
-
94
- `ToolRegistry`:`register` / `get` / `definitions()`(→ 模型可见定义)/ `execute()`(zod 校验 + 错误归一)。
95
-
96
- ### 安全沙箱
97
-
98
- `tools/safe-path.ts` 的 `safeJoin(base, target)`:解析绝对路径并校验未超出 `base`(防 `../` 穿越),越界抛 `SecurityError`。所有文件工具均经此校验。
99
-
100
- ### run_shell 执行
101
-
102
- `tools/shell/exec.ts` 用 `spawn(cmd, { shell: true })`;白名单检查命令首词(`commandHead`),审批由 `ctx.approve` 回调决定(CLI 默认审批器:白名单命中自动通过,否则拒绝)。
103
-
104
- ---
105
-
106
- ## 5. 事件日志(单一可信源)
107
-
108
- `runtime/event-log.ts`:`append-only` JSONL,每条 `{ ts, runId, type, ...payload }`。
109
-
110
- 事件类型:`session.start` / `session.end` / `model.request` / `model.response` / `tool.call` / `tool.result` / `plan` / `error`。
111
-
112
- 路径:`${FH_LOG_DIR}/${runId}.jsonl`(默认 `~/.feihong-code/sessions/`)。写入失败不影响主流程(仅告警)。
113
-
114
- ---
115
-
116
- ## 6. 并行架构(M2)
117
-
118
- `agent/parallel-orchestrator.ts`:
119
-
120
- ```
121
- runParallel(goal):
122
- 1. decomposeGoal(goal) → SubTask[]
123
- 2. 为每个 SubTask: createWorktree(repoRoot, id) → { path, branch }
124
- 3. Promise.allSettled( 每个 SubTask → runSubAgent({ worktree, goal, router, approve }) )
125
- 4. finally: 逐个 removeWorktree(鲁棒清理)
126
- ```
127
-
128
- ### 子代理隔离
129
-
130
- `agent/subagent.ts`:复用 `Orchestrator`,但 `cwd = worktree.path`,故工具沙箱天然将其限制在独立 worktree 内——**物理隔离**。
131
-
132
- ### worktree 清理鲁棒策略
133
-
134
- `runtime/worktree.ts` 的 `removeWorktree` 应对 Windows 上"顺序移除多 worktree 会连带清掉 `.git/worktrees`"的已知缺陷,采用三段式:
135
-
136
- 1. `git worktree remove --force`(best-effort)
137
- 2. `rmSync` 强制删磁盘目录(防孤儿)
138
- 3. `git worktree prune`(清元数据残留)
139
-
140
- 子代理结果在清理前已收集,清理仅针对工作区本身。
141
-
142
- ---
143
-
144
- ## 7. 恢复与审计架构(M3)
145
-
146
- ### 7.1 会话检查点持久化
147
-
148
- `runtime/session-persist.ts`:
149
-
150
- ```
151
- saveCheckpoint(logDir, cp): 写 <runId>.session.json(含 messages / iterations / costUsd / touchedFiles / status)
152
- loadCheckpoint(logDir, id): 精确或前缀匹配读取
153
- listCheckpoints(logDir): 按 updatedAt 倒序列出
154
- updateStatus(logDir, id, s): 标记 running / done / crashed
155
- ```
156
-
157
- `Orchestrator.run(goal, resume?)` 在**每一轮迭代后**通过注入的 `persist` 回调落盘检查点(见 `cli/run.ts` 装配)。`ChatMessage` 完全可 JSON 序列化,因此检查点可直接重建对话。
158
-
159
- ### 7.2 断点续跑(resume)
160
-
161
- ```
162
- resume <id>:
163
- 1. loadCheckpoint → 校验存在且 status != done
164
- 2. SessionStore.restore(cp) 重建会话(保留 runId / 对话历史)
165
- 3. Orchestrator.run(cp.goal, { messages: cp.messages, iterations, costUsd, touchedFiles })
166
- - 跳过 planTask,直接以检查点对话作为起始上下文
167
- - 继续 ReAct 循环,直到产出最终答案
168
- 4. 续跑过程仍写入同一 runId 的事件日志,审计连续
169
- ```
170
-
171
- ### 7.3 diff / rollback(会话作用域)
172
-
173
- `runtime/git.ts` 仅对会话 `touchedFiles` 操作,绝不整仓回滚:
174
-
175
- - `gitDiff(cwd, files?)`:已跟踪文件走 `git diff`;未跟踪文件走 `git diff --no-index /dev/null <file>` 展示新增内容。非 git 仓库安全退出并提示。
176
- - `gitRollback(cwd, files, { yes })`:已跟踪文件 `git checkout --`;未跟踪文件删除。`--yes` 缺失或非 git 仓库时**拒绝执行**,避免误删。
177
-
178
- ### 7.4 交互式审批流
179
-
180
- `cli/run.ts` 的审批解析优先级:
181
-
182
- 1. 显式传入 `opts.approve`(测试/REPL 注入)。
183
- 2. 真实模式 + TTY:交互式审批器 `interactiveApprover()`,逐条 `y/n` 确认高危操作。
184
- 3. 真实模式 + 非 TTY(CI/管道):白名单审批器 `defaultApproverFor()`,命中 `FH_SHELL_ALLOW` 自动通过,其余拒绝留痕。
185
- 4. 离线模式:不注入审批(`requireApproval` 仍为真,但 `run_shell` 缺乏 approve 通道时按安全默认拒绝)。
186
-
187
- `run_shell` 工具在 `tools/shell/run-shell.tool.ts` 中统一通过 `ctx.approve?.(action)` 发起审批,结果决定放行或拒绝。
188
-
189
- ---
190
-
191
- ## 8. 企业级架构(M4)
192
-
193
- `src/enterprise/` 提供企业能力,由 `cli/run.ts` 在装配期惰性注入;**未注入时全链路行为与社区版一致**(向后兼容)。
194
-
195
- ### 8.1 模块划分
196
-
197
- | 模块 | 职责 |
198
- | --- | --- |
199
- | `tenant.ts` | 多租户身份解析与目录隔离(`<FH_HOME>/tenants/<tenantId>/{sessions,audit,goals}`);`ID_RE` 正则防穿越;默认租户兼容旧 `sessions` |
200
- | `policy.ts` | RBAC 策略引擎:`evaluate()` 判定顺序 deny 优先;`loadPolicy()` 合并 `DEFAULT_POLICY → <FH_HOME>/policy.json → <租户>/policy.json → FH_POLICY`,黑名单取并集 |
201
- | `audit.ts` | 防篡改哈希链:`computeHash = sha256([seq,ts,tenant,user,role,runId,action,resource,decision,reason,prevHash])`;按月切分 `audit-YYYY-MM.jsonl`;`verifyAudit()` 定位篡改断点;`redact()` 脱敏 |
202
- | `quota.ts` | 成本治理:`tenantSpendToday()` / `resolveDailyLimit()`(`FH_TENANT_BUDGET_USD` 优先)/ `checkQuota()` |
203
- | `guard.ts` | `createEnterpriseGuard(deps)` 返回 `ToolGuard`,作为**唯一权威闸门**:策略判定→人工审批→审计留痕在工具执行前一次性完成;命中允许时清空 `security` 去重,避免工具层二次弹审批 |
204
- | `index.ts` | 聚合装配:`createEnterpriseRuntime()` / `isEnterpriseEnabled()`(`FH_ENTERPRISE!=='false'`)/ `assertQuota()`(超限抛 `QUOTA_EXCEEDED`)/ `renderWhoami()` |
205
-
206
- ### 8.2 守卫注入点
207
-
208
- `tools/tool.registry.ts` 的 `execute` 在 zod 校验后、执行前插入 guard 检查;`agent/orchestrator.ts` 透传 `guard` 并在循环中插入单任务 `maxCostUsd` 熔断。审计写入失败 = 拒绝执行(fail-closed)。
209
-
210
- ### 8.3 判定顺序(deny 优先)
211
-
212
- 1. `run_shell` 命中危险命令(23 条 `denyShell`)→ deny;
213
- 2. 敏感路径(`denyPaths` 11 类)或沙箱越界 → deny(**admin 也拦**);
214
- 3. 角色矩阵 `deny / approval / allow`;
215
- 4. shell 白名单命中 → 免审批。
216
-
217
- ### 8.4 角色矩阵(内置)
218
-
219
- | 角色 | 允许工具 | 审批要求 | 单任务上限 |
220
- | --- | --- | --- | --- |
221
- | `viewer` | 只读(read/list/grep) | — | $0.1 |
222
- | `developer` | 读写 + 测试/构建 | `run_shell` 需审批 | $1 |
223
- | `operator` | 全部 | `run_shell` 需审批 | $5 |
224
- | `admin` | 全部 | `run_shell` 需审批 | 无限制 |
225
-
226
- ---
227
-
228
- ## 9. 类型速查
229
-
230
- - `ChatMessage`:`{ role, content, toolCalls?, toolCallId? }`
231
- - `ToolCall`:`{ id, name, arguments }`
232
- - `ChatResponse`:`{ message, usage, providerId, model, costUsd }`
233
- - `RunResult`:`{ ok, finalAnswer, iterations, costUsd, logFile }`
234
- - `AppError` 子类:`ConfigError` / `ModelError` / `ToolError` / `ApprovalRequiredError` / `SecurityError`
235
-
236
- ---
237
-
238
- © 2026 晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹
1
+ # 飞虹 Code 架构与 API
2
+
3
+ > 晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹
4
+
5
+ 本文面向**开发者/集成者**,讲解分层、编排循环、模型路由、工具协议、事件日志与并行架构。
6
+
7
+ ---
8
+
9
+ ## 1. 分层(feature-first)
10
+
11
+ ```
12
+ src/
13
+ ├── cli/ 入口(commands/run/index/repl/version)
14
+ ├── shared/ config / errors / logger / types
15
+ ├── agent/ orchestrator / planner / prompts / parallel-orchestrator / subagent
16
+ ├── tools/ tool.interface / tool.registry / safe-path + file|shell|search|verify
17
+ ├── models/ model-router / model.interface / model.dto / cost + providers
18
+ ├── runtime/ event-log / session-store / worktree
19
+ └── skills/ plan / grill / goal
20
+ ```
21
+
22
+ 依赖方向:`cli → agent/tools/models/runtime → shared`,上层可依赖下层,下层不反向依赖。
23
+
24
+ ---
25
+
26
+ ## 2. 编排循环(ReAct)
27
+
28
+ `Orchestrator.run(goal)`:
29
+
30
+ ```
31
+ 1. planTask(goal) → 系统提示 + 用户目标 → 初始消息
32
+ 2. loop (max 12 次):
33
+ a. router.chat(messages, ['code-gen']) → ChatResponse
34
+ b. 若 message.toolCalls 为空 → 视为完成,break
35
+ c. 对每个 toolCall: toolRegistry.execute(...) → 回填 role=tool 消息
36
+ 3. 返回 { ok, finalAnswer, iterations, costUsd, logFile }
37
+ ```
38
+
39
+ - 每次模型调用写入事件日志(`model.response` / `tool.call` / `tool.result`)。
40
+ - 温度固定 `0`,`max_tokens=4096`,超时 `180s`(AbortController)。
41
+ - `maxIterations` 默认 12,可在构造 `OrchestratorDeps` 时覆盖。
42
+
43
+ ---
44
+
45
+ ## 3. 模型路由
46
+
47
+ `ModelRouter`:
48
+
49
+ - `rank(tags?)`:按 tags 过滤(全不命中则退回全量),按 `score()` 排序。
50
+ - `score()`:`cost`→`-costPer1k`;`latency`→本地优先;`capability`→reasoning/code-gen 加权。
51
+ - `chat(req, tags?)`:依次调用 provider,**任一成功即返回**;全部失败抛最后错误(自动 fallback)。
52
+
53
+ ### Provider 接口(ModelProvider)
54
+
55
+ ```ts
56
+ interface ModelProvider {
57
+ readonly id: string;
58
+ readonly model: string;
59
+ readonly tags: CapabilityTag[];
60
+ readonly costPer1k?: number;
61
+ chat(req: ChatRequest): Promise<ChatResponse>;
62
+ }
63
+ ```
64
+
65
+ 已实现:`OpenAICompatibleProvider`(DeepSeek/通义/Agnes/任意 OpenAI 协议)、`OllamaProvider`(本地)、`ScriptedMockProvider`(离线)。
66
+
67
+ ---
68
+
69
+ ## 4. 工具协议
70
+
71
+ ### 契约
72
+
73
+ ```ts
74
+ interface Tool {
75
+ name: string;
76
+ description: string;
77
+ jsonSchema: Record<string, unknown>; // 给模型看的 JSON Schema
78
+ schema: z.ZodTypeAny; // 运行时 zod 校验
79
+ execute(args, ctx: ToolContext): Promise<ToolResult>;
80
+ }
81
+
82
+ interface ToolContext {
83
+ runId: string;
84
+ cwd: string; // 沙箱根
85
+ security: { shellAllowlist: string[]; requireApproval: boolean };
86
+ approve?: (action: string) => Promise<boolean>;
87
+ }
88
+
89
+ interface ToolResult { ok: boolean; output: string; error?: string; }
90
+ ```
91
+
92
+ ### 注册与执行
93
+
94
+ `ToolRegistry`:`register` / `get` / `definitions()`(→ 模型可见定义)/ `execute()`(zod 校验 + 错误归一)。
95
+
96
+ ### 安全沙箱
97
+
98
+ `tools/safe-path.ts` 的 `safeJoin(base, target)`:解析绝对路径并校验未超出 `base`(防 `../` 穿越),越界抛 `SecurityError`。所有文件工具均经此校验。
99
+
100
+ ### run_shell 执行
101
+
102
+ `tools/shell/exec.ts` 用 `spawn(cmd, { shell: true })`;白名单检查命令首词(`commandHead`),审批由 `ctx.approve` 回调决定(CLI 默认审批器:白名单命中自动通过,否则拒绝)。
103
+
104
+ ---
105
+
106
+ ## 5. 事件日志(单一可信源)
107
+
108
+ `runtime/event-log.ts`:`append-only` JSONL,每条 `{ ts, runId, type, ...payload }`。
109
+
110
+ 事件类型:`session.start` / `session.end` / `model.request` / `model.response` / `tool.call` / `tool.result` / `plan` / `error`。
111
+
112
+ 路径:`${FH_LOG_DIR}/${runId}.jsonl`(默认 `~/.feihong-code/sessions/`)。写入失败不影响主流程(仅告警)。
113
+
114
+ ---
115
+
116
+ ## 6. 并行架构(M2)
117
+
118
+ `agent/parallel-orchestrator.ts`:
119
+
120
+ ```
121
+ runParallel(goal):
122
+ 1. decomposeGoal(goal) → SubTask[]
123
+ 2. 为每个 SubTask: createWorktree(repoRoot, id) → { path, branch }
124
+ 3. Promise.allSettled( 每个 SubTask → runSubAgent({ worktree, goal, router, approve }) )
125
+ 4. finally: 逐个 removeWorktree(鲁棒清理)
126
+ ```
127
+
128
+ ### 子代理隔离
129
+
130
+ `agent/subagent.ts`:复用 `Orchestrator`,但 `cwd = worktree.path`,故工具沙箱天然将其限制在独立 worktree 内——**物理隔离**。
131
+
132
+ ### worktree 清理鲁棒策略
133
+
134
+ `runtime/worktree.ts` 的 `removeWorktree` 应对 Windows 上"顺序移除多 worktree 会连带清掉 `.git/worktrees`"的已知缺陷,采用三段式:
135
+
136
+ 1. `git worktree remove --force`(best-effort)
137
+ 2. `rmSync` 强制删磁盘目录(防孤儿)
138
+ 3. `git worktree prune`(清元数据残留)
139
+
140
+ 子代理结果在清理前已收集,清理仅针对工作区本身。
141
+
142
+ ---
143
+
144
+ ## 7. 恢复与审计架构(M3)
145
+
146
+ ### 7.1 会话检查点持久化
147
+
148
+ `runtime/session-persist.ts`:
149
+
150
+ ```
151
+ saveCheckpoint(logDir, cp): 写 <runId>.session.json(含 messages / iterations / costUsd / touchedFiles / status)
152
+ loadCheckpoint(logDir, id): 精确或前缀匹配读取
153
+ listCheckpoints(logDir): 按 updatedAt 倒序列出
154
+ updateStatus(logDir, id, s): 标记 running / done / crashed
155
+ ```
156
+
157
+ `Orchestrator.run(goal, resume?)` 在**每一轮迭代后**通过注入的 `persist` 回调落盘检查点(见 `cli/run.ts` 装配)。`ChatMessage` 完全可 JSON 序列化,因此检查点可直接重建对话。
158
+
159
+ ### 7.2 断点续跑(resume)
160
+
161
+ ```
162
+ resume <id>:
163
+ 1. loadCheckpoint → 校验存在且 status != done
164
+ 2. SessionStore.restore(cp) 重建会话(保留 runId / 对话历史)
165
+ 3. Orchestrator.run(cp.goal, { messages: cp.messages, iterations, costUsd, touchedFiles })
166
+ - 跳过 planTask,直接以检查点对话作为起始上下文
167
+ - 继续 ReAct 循环,直到产出最终答案
168
+ 4. 续跑过程仍写入同一 runId 的事件日志,审计连续
169
+ ```
170
+
171
+ ### 7.3 diff / rollback(会话作用域)
172
+
173
+ `runtime/git.ts` 仅对会话 `touchedFiles` 操作,绝不整仓回滚:
174
+
175
+ - `gitDiff(cwd, files?)`:已跟踪文件走 `git diff`;未跟踪文件走 `git diff --no-index /dev/null <file>` 展示新增内容。非 git 仓库安全退出并提示。
176
+ - `gitRollback(cwd, files, { yes })`:已跟踪文件 `git checkout --`;未跟踪文件删除。`--yes` 缺失或非 git 仓库时**拒绝执行**,避免误删。
177
+
178
+ ### 7.4 交互式审批流
179
+
180
+ `cli/run.ts` 的审批解析优先级:
181
+
182
+ 1. 显式传入 `opts.approve`(测试/REPL 注入)。
183
+ 2. 真实模式 + TTY:交互式审批器 `interactiveApprover()`,逐条 `y/n` 确认高危操作。
184
+ 3. 真实模式 + 非 TTY(CI/管道):白名单审批器 `defaultApproverFor()`,命中 `FH_SHELL_ALLOW` 自动通过,其余拒绝留痕。
185
+ 4. 离线模式:不注入审批(`requireApproval` 仍为真,但 `run_shell` 缺乏 approve 通道时按安全默认拒绝)。
186
+
187
+ `run_shell` 工具在 `tools/shell/run-shell.tool.ts` 中统一通过 `ctx.approve?.(action)` 发起审批,结果决定放行或拒绝。
188
+
189
+ ---
190
+
191
+ ## 8. 企业级架构(M4)
192
+
193
+ `src/enterprise/` 提供企业能力,由 `cli/run.ts` 在装配期惰性注入;**未注入时全链路行为与社区版一致**(向后兼容)。
194
+
195
+ ### 8.1 模块划分
196
+
197
+ | 模块 | 职责 |
198
+ | --- | --- |
199
+ | `tenant.ts` | 多租户身份解析与目录隔离(`<FH_HOME>/tenants/<tenantId>/{sessions,audit,goals}`);`ID_RE` 正则防穿越;默认租户兼容旧 `sessions` |
200
+ | `policy.ts` | RBAC 策略引擎:`evaluate()` 判定顺序 deny 优先;`loadPolicy()` 合并 `DEFAULT_POLICY → <FH_HOME>/policy.json → <租户>/policy.json → FH_POLICY`,黑名单取并集 |
201
+ | `audit.ts` | 防篡改哈希链:`computeHash = sha256([seq,ts,tenant,user,role,runId,action,resource,decision,reason,prevHash])`;按月切分 `audit-YYYY-MM.jsonl`;`verifyAudit()` 定位篡改断点;`redact()` 脱敏 |
202
+ | `quota.ts` | 成本治理:`tenantSpendToday()` / `resolveDailyLimit()`(`FH_TENANT_BUDGET_USD` 优先)/ `checkQuota()` |
203
+ | `guard.ts` | `createEnterpriseGuard(deps)` 返回 `ToolGuard`,作为**唯一权威闸门**:策略判定→人工审批→审计留痕在工具执行前一次性完成;命中允许时清空 `security` 去重,避免工具层二次弹审批 |
204
+ | `index.ts` | 聚合装配:`createEnterpriseRuntime()` / `isEnterpriseEnabled()`(`FH_ENTERPRISE!=='false'`)/ `assertQuota()`(超限抛 `QUOTA_EXCEEDED`)/ `renderWhoami()` |
205
+
206
+ ### 8.2 守卫注入点
207
+
208
+ `tools/tool.registry.ts` 的 `execute` 在 zod 校验后、执行前插入 guard 检查;`agent/orchestrator.ts` 透传 `guard` 并在循环中插入单任务 `maxCostUsd` 熔断。审计写入失败 = 拒绝执行(fail-closed)。
209
+
210
+ ### 8.3 判定顺序(deny 优先)
211
+
212
+ 1. `run_shell` 命中危险命令(23 条 `denyShell`)→ deny;
213
+ 2. 敏感路径(`denyPaths` 11 类)或沙箱越界 → deny(**admin 也拦**);
214
+ 3. 角色矩阵 `deny / approval / allow`;
215
+ 4. shell 白名单命中 → 免审批。
216
+
217
+ ### 8.4 角色矩阵(内置)
218
+
219
+ | 角色 | 允许工具 | 审批要求 | 单任务上限 |
220
+ | --- | --- | --- | --- |
221
+ | `viewer` | 只读(read/list/grep) | — | $0.1 |
222
+ | `developer` | 读写 + 测试/构建 | `run_shell` 需审批 | $1 |
223
+ | `operator` | 全部 | `run_shell` 需审批 | $5 |
224
+ | `admin` | 全部 | `run_shell` 需审批 | 无限制 |
225
+
226
+ ---
227
+
228
+ ## 9. 类型速查
229
+
230
+ - `ChatMessage`:`{ role, content, toolCalls?, toolCallId? }`
231
+ - `ToolCall`:`{ id, name, arguments }`
232
+ - `ChatResponse`:`{ message, usage, providerId, model, costUsd }`
233
+ - `RunResult`:`{ ok, finalAnswer, iterations, costUsd, logFile }`
234
+ - `AppError` 子类:`ConfigError` / `ModelError` / `ToolError` / `ApprovalRequiredError` / `SecurityError`
235
+
236
+ ---
237
+
238
+ © 2026 晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹