feihong-code 0.2.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 (154) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  2. package/.github/ISSUE_TEMPLATE/config.yml +14 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +28 -0
  4. package/.github/PULL_REQUEST_TEMPLATE.md +46 -0
  5. package/.github/SECURITY.md +67 -0
  6. package/.github/workflows/ci.yml +140 -0
  7. package/AGENT-GUIDE.md +237 -0
  8. package/CHANGELOG.md +73 -0
  9. package/CODE_OF_CONDUCT.md +56 -0
  10. package/CONTRIBUTING.md +68 -0
  11. package/LICENSE +22 -0
  12. package/README.md +500 -0
  13. package/dist/agent/code-review.js +115 -0
  14. package/dist/agent/code-review.js.map +1 -0
  15. package/dist/agent/code-writer.js +227 -0
  16. package/dist/agent/code-writer.js.map +1 -0
  17. package/dist/agent/context-compactor.js +108 -0
  18. package/dist/agent/context-compactor.js.map +1 -0
  19. package/dist/agent/experience.js +190 -0
  20. package/dist/agent/experience.js.map +1 -0
  21. package/dist/agent/orchestrator.js +212 -0
  22. package/dist/agent/orchestrator.js.map +1 -0
  23. package/dist/agent/parallel-orchestrator.js +94 -0
  24. package/dist/agent/parallel-orchestrator.js.map +1 -0
  25. package/dist/agent/planner.js +53 -0
  26. package/dist/agent/planner.js.map +1 -0
  27. package/dist/agent/prompts.js +26 -0
  28. package/dist/agent/prompts.js.map +1 -0
  29. package/dist/agent/quality-gate.js +143 -0
  30. package/dist/agent/quality-gate.js.map +1 -0
  31. package/dist/agent/repo-reader.js +384 -0
  32. package/dist/agent/repo-reader.js.map +1 -0
  33. package/dist/agent/repo-underwriter.js +132 -0
  34. package/dist/agent/repo-underwriter.js.map +1 -0
  35. package/dist/agent/self-heal.js +134 -0
  36. package/dist/agent/self-heal.js.map +1 -0
  37. package/dist/agent/self-improver.js +148 -0
  38. package/dist/agent/self-improver.js.map +1 -0
  39. package/dist/agent/subagent.js +75 -0
  40. package/dist/agent/subagent.js.map +1 -0
  41. package/dist/agent/swe-agent.js +162 -0
  42. package/dist/agent/swe-agent.js.map +1 -0
  43. package/dist/agent/swe-planner.js +155 -0
  44. package/dist/agent/swe-planner.js.map +1 -0
  45. package/dist/agent/swe-verifier.js +113 -0
  46. package/dist/agent/swe-verifier.js.map +1 -0
  47. package/dist/cli/commands.js +167 -0
  48. package/dist/cli/commands.js.map +1 -0
  49. package/dist/cli/index.js +179 -0
  50. package/dist/cli/index.js.map +1 -0
  51. package/dist/cli/repl.js +67 -0
  52. package/dist/cli/repl.js.map +1 -0
  53. package/dist/cli/run.js +762 -0
  54. package/dist/cli/run.js.map +1 -0
  55. package/dist/cli/version.js +14 -0
  56. package/dist/cli/version.js.map +1 -0
  57. package/dist/enterprise/audit.js +294 -0
  58. package/dist/enterprise/audit.js.map +1 -0
  59. package/dist/enterprise/guard.js +58 -0
  60. package/dist/enterprise/guard.js.map +1 -0
  61. package/dist/enterprise/index.js +99 -0
  62. package/dist/enterprise/index.js.map +1 -0
  63. package/dist/enterprise/policy.js +242 -0
  64. package/dist/enterprise/policy.js.map +1 -0
  65. package/dist/enterprise/quota.js +58 -0
  66. package/dist/enterprise/quota.js.map +1 -0
  67. package/dist/enterprise/tenant.js +143 -0
  68. package/dist/enterprise/tenant.js.map +1 -0
  69. package/dist/models/cost.js +13 -0
  70. package/dist/models/cost.js.map +1 -0
  71. package/dist/models/model-router.js +170 -0
  72. package/dist/models/model-router.js.map +1 -0
  73. package/dist/models/model.dto.js +61 -0
  74. package/dist/models/model.dto.js.map +1 -0
  75. package/dist/models/model.interface.js +3 -0
  76. package/dist/models/model.interface.js.map +1 -0
  77. package/dist/models/providers/mock.provider.js +35 -0
  78. package/dist/models/providers/mock.provider.js.map +1 -0
  79. package/dist/models/providers/ollama.provider.js +88 -0
  80. package/dist/models/providers/ollama.provider.js.map +1 -0
  81. package/dist/models/providers/openai-compatible.provider.js +106 -0
  82. package/dist/models/providers/openai-compatible.provider.js.map +1 -0
  83. package/dist/runtime/event-log.js +42 -0
  84. package/dist/runtime/event-log.js.map +1 -0
  85. package/dist/runtime/git.js +106 -0
  86. package/dist/runtime/git.js.map +1 -0
  87. package/dist/runtime/session-persist.js +60 -0
  88. package/dist/runtime/session-persist.js.map +1 -0
  89. package/dist/runtime/session-store.js +34 -0
  90. package/dist/runtime/session-store.js.map +1 -0
  91. package/dist/runtime/worktree.js +117 -0
  92. package/dist/runtime/worktree.js.map +1 -0
  93. package/dist/shared/config.js +184 -0
  94. package/dist/shared/config.js.map +1 -0
  95. package/dist/shared/errors.js +66 -0
  96. package/dist/shared/errors.js.map +1 -0
  97. package/dist/shared/logger.js +51 -0
  98. package/dist/shared/logger.js.map +1 -0
  99. package/dist/shared/types.js +9 -0
  100. package/dist/shared/types.js.map +1 -0
  101. package/dist/skills/goal.js +60 -0
  102. package/dist/skills/goal.js.map +1 -0
  103. package/dist/skills/grill.js +129 -0
  104. package/dist/skills/grill.js.map +1 -0
  105. package/dist/skills/plan.js +40 -0
  106. package/dist/skills/plan.js.map +1 -0
  107. package/dist/tools/analysis/code-analyzer.js +136 -0
  108. package/dist/tools/analysis/code-analyzer.js.map +1 -0
  109. package/dist/tools/file/edit.tool.js +43 -0
  110. package/dist/tools/file/edit.tool.js.map +1 -0
  111. package/dist/tools/file/list.tool.js +36 -0
  112. package/dist/tools/file/list.tool.js.map +1 -0
  113. package/dist/tools/file/read.tool.js +34 -0
  114. package/dist/tools/file/read.tool.js.map +1 -0
  115. package/dist/tools/file/write.tool.js +39 -0
  116. package/dist/tools/file/write.tool.js.map +1 -0
  117. package/dist/tools/generator/code-generator.js +119 -0
  118. package/dist/tools/generator/code-generator.js.map +1 -0
  119. package/dist/tools/generator/test-generator.js +65 -0
  120. package/dist/tools/generator/test-generator.js.map +1 -0
  121. package/dist/tools/index.js +53 -0
  122. package/dist/tools/index.js.map +1 -0
  123. package/dist/tools/safe-path.js +36 -0
  124. package/dist/tools/safe-path.js.map +1 -0
  125. package/dist/tools/search/grep.tool.js +81 -0
  126. package/dist/tools/search/grep.tool.js.map +1 -0
  127. package/dist/tools/shell/exec.js +50 -0
  128. package/dist/tools/shell/exec.js.map +1 -0
  129. package/dist/tools/shell/run-shell.tool.js +49 -0
  130. package/dist/tools/shell/run-shell.tool.js.map +1 -0
  131. package/dist/tools/tool.interface.js +8 -0
  132. package/dist/tools/tool.interface.js.map +1 -0
  133. package/dist/tools/tool.registry.js +75 -0
  134. package/dist/tools/tool.registry.js.map +1 -0
  135. package/dist/tools/verify/build-check.tool.js +37 -0
  136. package/dist/tools/verify/build-check.tool.js.map +1 -0
  137. package/dist/tools/verify/test-run.tool.js +37 -0
  138. package/dist/tools/verify/test-run.tool.js.map +1 -0
  139. package/dist/web/auth.js +25 -0
  140. package/dist/web/auth.js.map +1 -0
  141. package/dist/web/public/index.html +39 -0
  142. package/dist/web/server.js +60 -0
  143. package/dist/web/server.js.map +1 -0
  144. package/docs//344/272/247/345/223/201/345/274/200/345/217/221/346/226/207/346/241/243.md +614 -0
  145. 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 -0
  146. package/docs//344/275/277/347/224/250/350/257/264/346/230/216/344/271/246.md +358 -0
  147. 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 -0
  148. package/docs//346/212/200/346/234/257/350/257/264/346/230/216/344/271/246.md +303 -0
  149. package/docs//346/236/266/346/236/204/344/270/216API.md +238 -0
  150. package/docs//347/224/250/346/210/267/346/211/213/345/206/214.md +196 -0
  151. package/docs//351/203/250/347/275/262/346/214/207/345/215/227.md +165 -0
  152. package/docs//351/205/215/347/275/256/345/217/202/350/200/203.md +127 -0
  153. package/package.json +83 -0
  154. package/tool-schema.json +127 -0
@@ -0,0 +1,130 @@
1
+ # 飞虹 Code 常见问题与故障排查(FAQ)
2
+
3
+ > 晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹
4
+
5
+ ---
6
+
7
+ ## Q1. 离线模式和真实模式如何切换?
8
+
9
+ - 未配置 `FH_PROVIDERS`(或设为 `[]`/`FH_OFFLINE=true`)→ **离线**(内置 Mock 闭环,零成本)。
10
+ - 配置非空 `FH_PROVIDERS` → **真实模型**。
11
+ - 临时离线:`FH_OFFLINE=true fhcode "..."`。
12
+
13
+ ---
14
+
15
+ ## Q2. 真实并行(`--parallel`)子任务失败,提示 HTTP 429?
16
+
17
+ **原因**:`--parallel` 会**并发**调用 API。免费套餐(如 Agnes free tier)对并发请求有严格限流,触发 `429 Too Many Requests`。
18
+
19
+ **解决**:
20
+ 1. 升级 API 套餐(Token Plan)提高并发额度;
21
+ 2. 改用单命令模式顺序执行大目标:`fhcode "实现A并且添加B"`(单命令串行,不易触发);
22
+ 3. 用 `FH_OFFLINE=true fhcode --parallel "..."` 验证并行机制(不耗额度)。
23
+
24
+ > 代码路径本身正确:真实 `ModelRouter` 已接入,worktree 创建/清理正常,限流被优雅捕获(不崩溃、清理照常)。
25
+
26
+ ---
27
+
28
+ ## Q3. 没配 `FH_HOME` 会崩溃吗?
29
+
30
+ 不会。自 v0.1.0 起 `FH_HOME` 可缺省,默认 `~/.feihong-code`(Windows 为 `%USERPROFILE%/.feihong-code`)。仅当显式设置错误路径时才可能异常。
31
+
32
+ ---
33
+
34
+ ## Q4. `git worktree` 残留 / 清理失败?
35
+
36
+ 正常结束后 worktree 会被强制清理(含 Windows 上 git 顺序移除缺陷的鲁棒兜底)。
37
+
38
+ 若发现残留:
39
+ ```bash
40
+ git worktree list # 查看
41
+ git worktree prune # 清理元数据
42
+ # 手动删除遗留的临时目录(通常在 %TEMP%/fhcode-wt-*)
43
+ ```
44
+ 子代理产品本就不进入主仓库,残留目录可直接删除。
45
+
46
+ ---
47
+
48
+ ## Q5. shell 命令被拒("已拒绝执行(需审批)")?
49
+
50
+ - `run_shell` 要求命令首词命中 `FH_SHELL_ALLOW` 白名单。
51
+ - 非交互 CLI 下,命中白名单自动通过;未命中则拒绝。
52
+ - 检查 `.env` 的 `FH_SHELL_ALLOW` 是否包含你的命令(如 `git,npm,node,ls,cat`)。
53
+
54
+ ---
55
+
56
+ ## Q6. 密钥会泄露吗?
57
+
58
+ - `.env` 已被 `.gitignore` 排除,且 `package.json` 的 `files` 白名单确保 `npm publish` 不含 `.env`。
59
+ - 日志中 `apikey/secret/token/...` 值一律 `[REDACTED]`。
60
+ - 我(助手)全程不回显完整 API key。
61
+ - 建议 `.env` 权限 `chmod 600 .env`。
62
+
63
+ ---
64
+
65
+ ## Q7. 构建失败(tsc 报错)?
66
+
67
+ ```bash
68
+ rm -rf dist node_modules
69
+ npm install
70
+ npm run typecheck # 先看类型错误
71
+ npm run build
72
+ ```
73
+ 确保 Node >= 18 且 `npm install` 已成功(需要联网拉取 zod/typescript)。
74
+
75
+ ---
76
+
77
+ ## Q8. 模型不调用工具,直接给文字?
78
+
79
+ - 编排器默认带 `['code-gen']` 标签筛选 provider,确认 `FH_PROVIDERS` 中模型 `tags` 含 `code-gen`。
80
+ - 温度固定 `0`,模型仍可能选择不调用工具(取决于模型能力)。
81
+ - 若需强制工具使用,可在需求中明确"请使用 list_dir / read_file 等工具"。
82
+
83
+ ---
84
+
85
+ ## Q9. Node 版本要求?
86
+
87
+ `engines.node >= 18`。低于 18 可能出现语法/API 不兼容(如 `structuredClone`、`fetch` 全局)。
88
+
89
+ ---
90
+
91
+ ## Q10. REPL 无法交互(自动化环境)?
92
+
93
+ REPL 依赖标准输入交互。在 CI / 自动化脚本中请使用**单命令模式**或**离线模式**,而非 REPL。
94
+
95
+ ---
96
+
97
+ ## Q11. 真实模式会改我的文件吗?
98
+
99
+ 会。`cwd = 当前目录`,`write_file`/`edit_file` 会直接修改当前工作区文件(受沙箱限制在 cwd 内)。建议:
100
+ - 从干净目录或专用仓库运行;
101
+ - 大改前先用 `/plan`、`/grill` 只读评估;
102
+ - 多模块任务用 `--parallel`(worktree 隔离,不污染主目录)。
103
+
104
+ ---
105
+
106
+ ## Q12. 成本怎么算?会超额吗?
107
+
108
+ 每次调用按 `costPer1k` × tokens 估算,任务结束打印总成本。超过 `FH_BUDGET_USD` 仅**告警**不阻断。离线模式成本恒为 0。
109
+
110
+ ---
111
+
112
+ ## Q13.(企业)任务启动即报 `QUOTA_EXCEEDED`,怎么回事?
113
+
114
+ 说明**租户当日成本已超预算**。触发链:任务启动前 `assertQuota()` 会按 `FH_TENANT_BUDGET_USD`(缺省取角色上限)统计当日已用成本,超限即 fail-fast 拒绝新任务(HTTP 429 语义)。可用 `fhcode whoami` 查看「已用/预算」,或调高 `FH_TENANT_BUDGET_USD` / 次日再跑。注意这是**硬上限**,不会静默放行。
115
+
116
+ ## Q14.(企业)`audit verify` 报链断裂(brokenAt),是日志被改了吗?
117
+
118
+ 哈希链校验规则:每条记录 `hash = sha256(prevHash | seq | ts | tenant | ... | resource | decision)`,且 `prevHash` 必须衔接上一条、`seq` 连续。若某条被增删改,`audit verify` 会定位首个断点 `brokenAt` 行号。常见原因:手工编辑了 `audit-YYYY-MM.jsonl`、文件被截断、或拷贝时丢了行。建议从该断点之后重建或归档受损月份日志。
119
+
120
+ ## Q15.(企业)多租户之间会串数据吗?
121
+
122
+ 不会。每个租户数据落在独立的物理目录 `<FH_HOME>/tenants/<tenantId>/{sessions,audit,goals}`,且 `FH_TENANT` 值受正则 `^[A-Za-z0-9._-]{1,64}$` 强校验,禁止 `../` 等穿越字符。未设 `FH_TENANT` 时走默认租户(兼容旧 `<FH_HOME>/sessions`)。CI 中 `beta` 租户断言读不到 `acme` 租户会话,即验证此隔离。
123
+
124
+ ## Q16.(企业)如何完全关闭企业能力(退回社区版)?
125
+
126
+ 设 `FH_ENTERPRISE=false`,则 RBAC / 审计 / 多租户隔离全部不注入,运行行为与 M3 社区版完全一致,零额外开销。这是单开关、向后兼容设计。
127
+
128
+ ---
129
+
130
+ © 2026 晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹
@@ -0,0 +1,303 @@
1
+ # 飞虹 Code(fhcode)技术说明书
2
+
3
+ > 本文为飞虹 Code 的**权威技术文档**,覆盖架构、企业级能力技术细节、数据契约、CLI/Web API、部署架构、安全模型与构建验证。
4
+ > 用户侧操作请参见《使用说明书》。
5
+
6
+ **版本**:0.2.0(含 M4 企业能力 + M5 Web 控制台 BETA + M6 自我进化 + M7 编程能力 + M8 自主迭代 + M9 全自动软件工程 Agent)
7
+ **署名**:晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹
8
+
9
+ ---
10
+
11
+ ## 1. 概述与定位
12
+
13
+ 飞虹 Code(命令名 `fhcode`)是终端 AI 编程智能体,以"目标"为入口,自动完成需求解析 → 规划 → 工具调用 → 反思的闭环,并支持多子代理并行、会话恢复审计,以及企业级权限/审计/多租户/成本治理。
14
+
15
+ - **适用场景**:代码生成与修改、批量重构、离线脚本化任务、企业内多团队共享的智能体底座。
16
+ - **能力边界**:不修改薪酬/股权/制度、不承诺效果、不伪造身份;危险操作一律人工审批或拒绝。
17
+ - **两种形态**:
18
+ - **社区版(默认)**:CLI 闭环 + 并行 + 恢复审计。
19
+ - **企业版(注入 guard 或 `FH_ENTERPRISE!=='false'`)**:在 community 之上叠加 RBAC、防篡改审计、多租户隔离、成本治理、Web 控制台。未注入 guard 时行为同社区版(无感降级)。
20
+
21
+ ---
22
+
23
+ ## 2. 系统架构
24
+
25
+ ### 2.1 分层架构
26
+
27
+ ```
28
+ cli 命令解析 / 分发 / 交互入口(含 serve)
29
+ └─ agent 编排层(Orchestrator / 并行 / Planner / SubAgent)
30
+ └─ tools 工具集(file / search / shell / verify)+ 注册表 + 守卫接口
31
+ └─ runtime 会话持久化 / git diff·rollback / 成本计量
32
+ └─ models 模型提供商适配 + 成本估算
33
+ └─ shared 通用工具(日志/脱敏/错误)
34
+ enterprise 企业能力(tenant/policy/audit/quota/guard/index)—— 可选注入
35
+ skills 技能定义(plan/grill/goal 等)
36
+ web Web 控制台(server/auth/public)—— M5 BETA
37
+ ```
38
+
39
+ ### 2.2 执行流(社区版 vs 企业版)
40
+
41
+ - **社区版**:`cli` → `Orchestrator.run(goal)` → 循环「规划→选工具→`tool.registry.execute`→反思」→ 终态答案。
42
+ - **企业版**:在「选工具 → 执行」之间插入**唯一权威闸门 `guard`**:
43
+ 1. `guard.check(tool, args)` 调 `policy.evaluate` 做策略判定;
44
+ 2. 命中审批项且无审批通道 → 拒绝;有通道 → 询问并记录 approved/rejected;
45
+ 3. 审计留痕(allow/deny/approval);审计写入失败 = 拒绝执行;
46
+ 4. 通过后才进入 `tool.registry.execute`,且注入 `security` 置空以避免工具层二次弹审批(去重)。
47
+
48
+ ### 2.3 模块清单
49
+
50
+ | 目录 | 职责 |
51
+ |------|------|
52
+ | `src/cli` | 命令解析(`commands.ts`)、分发(`index.ts`)、业务编排(`run.ts`)、版本与署名(`version.ts`) |
53
+ | `src/agent` | `orchestrator.ts`(主循环+成本熔断)、`parallel-orchestrator.ts`、`planner.ts`、`subagent.ts`、`prompts.ts` |
54
+ | `src/tools` | `tool.interface.ts`(含 `ToolGuard`)、`tool.registry.ts`(guard 接线)、`file/`、`search/`、`shell/`、`verify/` |
55
+ | `src/runtime` | `session-persist.ts`(检查点落盘)、`git.ts`(diff/rollback)、`cost.ts` |
56
+ | `src/models` | `providers/`(模型适配)、`cost.ts` |
57
+ | `src/shared` | 日志、脱敏、通用错误 |
58
+ | `src/skills` | 技能定义 |
59
+ | `src/enterprise` | `tenant.ts` `policy.ts` `audit.ts` `quota.ts` `guard.ts` `index.ts` |
60
+ | `src/web` | `server.ts` `auth.ts` `express.d.ts`(本地类型声明) `public/` |
61
+
62
+ ---
63
+
64
+ ## 3. 企业级能力技术细节(M4)
65
+
66
+ ### 3.1 RBAC 与策略引擎(`policy.ts`)
67
+
68
+ **判定顺序(deny 优先)**:
69
+
70
+ 1. `run_shell` 命中**危险命令黑名单** → `deny`(无论角色)。
71
+ 2. 命中**敏感路径黑名单**或**沙箱越界** → `deny`(admin 也拦)。
72
+ 3. 角色矩阵:`deny` / `approval`(需人工审批)/ `allow`。
73
+ 4. `run_shell` 命中**白名单** → 免审批 `allow`。
74
+
75
+ **角色矩阵(`DEFAULT_POLICY.roles`)**:
76
+
77
+ | 角色 | 允许工具 | 危险命令 | 单任务预算上限 |
78
+ |------|----------|----------|----------------|
79
+ | `viewer` | read / list / grep | — | $0.1 |
80
+ | `developer` | + write / edit / tests / build | 需审批 | $1 |
81
+ | `operator` | 全部 | 需审批 | $5 |
82
+ | `admin` | 全部 | 需审批 | ∞ |
83
+
84
+ **危险命令黑名单(23 条,`denyShell`)**:
85
+ `rm -rf /`、`rm -rf ~`、`rm -rf *`、`mkfs`、`dd if=`、`fork bomb :(){`、`shutdown`、`reboot`、`halt`、`format `、`del /s`、`rd /s`、`chmod 777 /`、`chown -R root`、`curl | sh`、`curl|sh`、`wget | sh`、`wget|sh`、`iptables -F`、`net user`、`reg delete`、`history -c`、`shred `。
86
+
87
+ **敏感路径黑名单(11 类,`denyPaths`)**:
88
+ `.env`、`.git/config`、`.git/hooks`、`.npmrc`、`.ssh`、`id_rsa`、`id_ed25519`、`credentials`、`.aws`、`.kube/config`、`shadow`。
89
+
90
+ **策略覆盖规则(仅加严)**:
91
+ - 加载优先级:`DEFAULT_POLICY` → `<FH_HOME>/policy.json` → `<租户>/policy.json` → 环境变量 `FH_POLICY`(JSON 片段)。
92
+ - 合并(`mergePolicy`):**黑名单取并集**(不能放宽);角色预算只能调低或持平;新增 deny 规则有效,移除 deny 无效。
93
+ - 即:任何层级的覆盖只能让策略更严格,不能削弱内置安全基线。
94
+
95
+ ### 3.2 防篡改审计(`audit.ts`)
96
+
97
+ **哈希链结构**:每条记录 `AuditRecord` 含 `seq`、`ts`、`tenant`、`user`、`role`、`runId`、`action`、`resource`、`decision`、`reason`、`prevHash`、`hash`。
98
+ - `computeHash(r) = sha256([seq, ts, tenant, user, role, runId, action, resource, decision, reason, prevHash].join('|'))`
99
+ - 创世哈希 `GENESIS = '0'.repeat(64)`(首条 `prevHash`)。
100
+ - **按月切分**:`audit-YYYY-MM.jsonl`,每条一行 JSON,同步 `appendFileSync` 追加;写入失败抛错(上层拒绝执行)。
101
+
102
+ **脱敏(`redact`)**:值中出现 `apiKey=`/`secret=`/`token=`/`password=`/`Authorization: Bearer`/`sk-*` 等一律替换为 `***`,写入前即脱敏。
103
+
104
+ **校验(`verifyAudit`)**:
105
+ - 检查 `seq` 连续、`prevHash` 与上一行 `hash` 衔接、`hash` 自洽(重算一致);
106
+ - 任一断点返回 `{ ok:false, brokenAt: <行号> }` 定位篡改位置。
107
+
108
+ ### 3.3 多租户隔离(`tenant.ts`)
109
+
110
+ **物理目录隔离**:`<FH_HOME>/tenants/<tenantId>/{sessions,audit,goals}`。
111
+ - 租户 ID 校验:`ID_RE = /^[A-Za-z0-9._-]{1,64}$/`,防路径穿越。
112
+ - **默认租户兼容**:`FH_TENANT` 缺省且尚未建 `tenants/default` 但存在旧 `<FH_HOME>/sessions` 时,沿用旧目录(平滑升级,不丢历史)。
113
+ - 用量统计(`listTenants`):仅提取 `costUsd`/`updatedAt`,不反序列化整份对话。
114
+
115
+ ### 3.4 成本治理(`quota.ts`)
116
+
117
+ - **单任务熔断**:`Orchestrator` 循环内 `if (maxCost>0 && cost>=maxCost)` 终止并给出终态答案(告警式,不抛错)。
118
+ - **租户日预算 fail-fast**:任务启动前 `assertQuota()` 调 `checkQuota()`;超限抛 `QUOTA_EXCEEDED`(HTTP 429 语义)并审计 `quota:block`。
119
+ - 日预算解析优先级:`FH_TENANT_BUDGET_USD` > 策略 `tenantDailyBudgetUsd`;缺省为 0(不限制)。
120
+ - 当日统计:正则提取 `updatedAt` 前缀匹配当天 UTC。
121
+
122
+ ---
123
+
124
+ ## 4. 数据契约与格式
125
+
126
+ ### 4.1 AuditRecord(审计记录)
127
+
128
+ ```json
129
+ {
130
+ "seq": 1,
131
+ "ts": "2026-08-10T14:30:00.000Z",
132
+ "tenant": "acme",
133
+ "user": "alice",
134
+ "role": "developer",
135
+ "runId": "run_xxx",
136
+ "action": "tool:write_file",
137
+ "resource": "src/app.ts",
138
+ "decision": "allow",
139
+ "reason": "命中角色矩阵 allow",
140
+ "prevHash": "0000...0000",
141
+ "hash": "a1b2...ff"
142
+ }
143
+ ```
144
+
145
+ ### 4.2 Policy(策略片段,可经 FH_POLICY / policy.json 覆盖)
146
+
147
+ ```json
148
+ {
149
+ "roles": { "viewer": { "allow": ["read","list","grep"], "maxCostUsd": 0.1 } },
150
+ "denyShell": ["rm -rf /"],
151
+ "denyPaths": [".env"],
152
+ "tenantDailyBudgetUsd": 0
153
+ }
154
+ ```
155
+
156
+ ### 4.3 TenantContext
157
+
158
+ ```ts
159
+ interface TenantContext {
160
+ tenant: string; // 校验后的租户 ID
161
+ user: string; // FH_USER 或 'default'
162
+ role: Role; // viewer|developer|operator|admin
163
+ home: string; // FH_HOME
164
+ dirs: { sessions: string; audit: string; goals: string };
165
+ }
166
+ ```
167
+
168
+ ### 4.4 配置变量全集
169
+
170
+ | 变量 | 作用 | 默认 |
171
+ |------|------|------|
172
+ | `FH_HOME` | 数据根目录(会话/审计/租户) | 平台默认(如 `~/.fhcode`) |
173
+ | `FH_ENTERPRISE` | 企业模式开关(`false` 关闭) | 开启(注入 guard 时) |
174
+ | `FH_TENANT` / `FH_USER` / `FH_ROLE` | 租户/用户/角色身份 | `default`/`default`/`developer` |
175
+ | `FH_TENANT_BUDGET_USD` | 租户日预算(优先于策略) | 0(不限制) |
176
+ | `FH_POLICY` | 策略 JSON 片段(覆盖) | 空 |
177
+ | `FH_WEB_PORT` / `FH_WEB_TOKEN` | Web 控制台端口/令牌 | `8080` / 空(禁用) |
178
+ | `FH_OFFLINE` | 强制离线(不请求模型) | 未设 |
179
+ | `FH_REQUIRE_APPROVAL` | 危险操作是否需审批 | `true` |
180
+ | `FH_BUDGET_USD` | 单任务成本告警阈值 | 未设 |
181
+
182
+ ---
183
+
184
+ ## 5. CLI 与 Web API 参考
185
+
186
+ ### 5.1 CLI 命令
187
+
188
+ | 命令 | 说明 |
189
+ |------|------|
190
+ | `fhcode "目标"` | 运行单条目标(社区/企业) |
191
+ | `fhcode /plan "需求"` | 生成实现规划 |
192
+ | `fhcode /grill <路径>` | 代码评审(grill) |
193
+ | `fhcode /goal` | 进入目标模式 |
194
+ | `fhcode sessions` | 列出会话检查点 |
195
+ | `fhcode resume <id>` | 断点续跑 |
196
+ | `fhcode diff [id]` | 会话作用域 diff |
197
+ | `fhcode rollback <id> [--yes]` | 回滚被改文件(需确认) |
198
+ | `fhcode whoami` | 显示租户/用户/角色/隔离目录/用量 |
199
+ | `fhcode policy` | 渲染 RBAC 角色矩阵与黑名单 |
200
+ | `fhcode audit [--limit N]` | 查看审计链(脱敏) |
201
+ | `fhcode audit verify` | 校验哈希链完整性 |
202
+ | `fhcode tenants` | 列出全部租户与用量汇总 |
203
+ | `fhcode serve [--port 8080]` | 启动 Web 管理控制台(BETA) |
204
+ | `fhcode swe "<目标>" [--repo PATH] [--plan-only] [--verify-only] [--max-tasks N] [--max-retries N] [--max-iterations N]` | 全自动软件工程 Agent(M9) |
205
+
206
+ 通用标志:`--version`、`--help`、`--parallel`、`--yes`、`--limit N`。
207
+
208
+ ### 5.1.1 真实模型接入(M9.1)
209
+
210
+ `swe` 及常规 `fhcode` 命令在真实模式下通过 `ModelRouter.fromConfig` 加载供应商,供应商配置支持三级解析(详见使用说明书第 10 章):
211
+
212
+ 1. 环境变量 `FH_PROVIDERS`(JSON 数组,可多供应商);
213
+ 2. 配置文件 `fhcode.config.json`(`models.providers`);
214
+ 3. 单环境变量快速接入:`FH_MODEL_NAME` / `FH_MODEL_TYPE` / `FH_MODEL_BASE_URL` / `FH_MODEL_API_KEY` / `FH_MODEL_TAGS`。
215
+
216
+ 供应商类型支持 `ollama`(本地零成本)与 `openai-compatible`(DeepSeek / 通义 / OpenRouter 等)。
217
+ **接入校验脚本** `scripts/verify-m9-real.mjs`:用本地 mock HTTP 服务(兼容 OpenAI / Ollama 协议)驱动 `swe` 走完整的"真实 HTTP provider → 编排器工具循环 → 验证器"链路,无需任何外部模型即可验证接入正确性(11 项断言)。
218
+
219
+ ### 5.2 Web REST API(M5 BETA,仅观测、不执行)
220
+
221
+ 所有端点需 `Authorization: Bearer <FH_WEB_TOKEN>`(未设令牌则全 401,fail-closed)。
222
+
223
+ | 方法 | 路径 | 返回 |
224
+ |------|------|------|
225
+ | GET | `/api/health` | `{ product, version, signature, enterprise, time }` |
226
+ | GET | `/api/tenants` | 全部租户与用量 |
227
+ | GET | `/api/whoami` | 当前租户身份与配额 |
228
+ | GET | `/api/policy` | 角色矩阵 + 黑名单 |
229
+ | GET | `/api/audit?limit=N` | 脱敏审计记录(倒序) |
230
+ | GET | `/api/audit/verify` | `{ ok, brokenAt? }` |
231
+ | GET | `/api/sessions` | 会话检查点列表 |
232
+ | GET | `/api/quota` | 配额状态(已用/上限) |
233
+
234
+ 静态仪表盘由 `dist/web/public/index.html` 提供(同源访问)。
235
+
236
+ ---
237
+
238
+ ## 6. 部署架构
239
+
240
+ ### 6.1 CI 四流水线(`.github/workflows/ci.yml`,零 Secrets 全离线)
241
+
242
+ 1. **build**:Node 18/20/22 矩阵 + 类型检查 + 编译 + 离线端到端闭环 + `/plan` `/grill` 只读技能。
243
+ 2. **enterprise**:`verify-m4.mjs`(41 项全离线断言:RBAC/审计链/多租户/配额)+ CLI 企业命令冒烟 + **租户隔离断言**(beta 不得读到其他租户会话)。
244
+ 3. **security**:`npm pack --dry-run` 白名单校验(禁 `.env`/`src`/`.workbuddy`/`policy.json`/`id_rsa`)+ 仓库明文密钥扫描 + `npm audit`。
245
+ 4. **docker**:构建镜像(不推送)+ 容器内 `whoami` 冒烟 + Web 控制台 `/api/health` 健康检查(HTTP 200)。
246
+
247
+ ### 6.2 Docker 部署(稳定部署推荐)
248
+
249
+ - **镜像**:多阶段 `Dockerfile`,构建阶段编译 `dist`,运行阶段仅 `express`+`zod` 生产依赖。
250
+ - **数据卷**:`FH_HOME=/data/fhcode` 挂载命名卷,持久化会话/审计/租户。
251
+ - **端口**:默认 `8080`(Web 控制台)。
252
+ - **编排**:`docker-compose.yml` 提供一键 `docker compose up -d`,令牌经 `FH_WEB_TOKEN` 环境变量注入。
253
+ - **反向代理建议**:前置 Nginx/Caddy 做 TLS 终止与限流;`FH_WEB_TOKEN` 务必为强随机值,勿用默认值。
254
+
255
+ ### 6.3 安装方式
256
+
257
+ - npm 全局:`npm install -g feihong-code`(bin=`fhcode`)。
258
+ - 源码:`git clone` → `npm install` → `npm run build` → `node dist/cli/index.js`。
259
+ - Docker:`docker build -t feihong-code .` → `docker run -p 8080:8080 feihong-code serve`。
260
+ - 安装脚本:`./install.sh`(封装 npm 全局安装)。
261
+
262
+ ---
263
+
264
+ ## 7. 安全模型
265
+
266
+ - **密钥**:仅存 gitignored `.env`;CLI 不回显完整 key;日志脱敏(`redact`)。
267
+ - **最小权限**:`guard` 为唯一权威闸门,deny 优先;Web 仅观测不执行,保持 guard 权威。
268
+ - **fail-closed**:Web 无令牌/错令牌 → 401;审批通道缺失 → 拒绝;审计写入失败 → 拒绝。
269
+ - **发布包白名单**:`package.json` 的 `files`(仅 `dist`+元数据+`docs`)+ `.npmignore`(排除 `.env`/`src`/`.workbuddy`/脚本/日志)双重保障,`.env` 等绝不随 `npm publish` 泄露。
270
+
271
+ ---
272
+
273
+ ## 8. 构建与验证
274
+
275
+ | 脚本 | 作用 |
276
+ |------|------|
277
+ | `npm run typecheck` | `tsc --noEmit` 类型检查 |
278
+ | `npm run build` | `tsc` 编译 + 拷贝 Web 静态资源到 `dist/web/public` |
279
+ | `npm run verify:m4` | 41 项企业能力离线断言 |
280
+ | `npm run verify` | typecheck + build + verify:m4 串联 |
281
+
282
+ > **本地构建注意**:Windows 本地 `tsc` 编译可能被 Windows Defender 实时扫描短暂锁文件(表现为 emit 退出 1 或后台挂起),属环境限制非代码缺陷;GitHub Actions(windows/ubuntu runner)无此问题。CI 是权威构建来源。
283
+
284
+ **verify-m4 断言覆盖(41/41)**:RBAC 矩阵(5) / deny 优先(4) / 策略覆盖加严(4) / 审计哈希链(7) / 守卫链路(11) / 多租户(7) / 配额(3)。
285
+
286
+ ---
287
+
288
+ ## 9. 里程碑与路线图
289
+
290
+ - **M0+M1**:CLI 骨架 + 单代理闭环 ✅
291
+ - **M2**:多子代理并行编排 ✅
292
+ - **M3**:恢复与审计(sessions/resume/diff/rollback + 交互式审批)✅
293
+ - **M4**:企业级权限/审计/多租户/CI ✅(本稳定版)
294
+ - **M5**:Web 管理控制台 —— S1 服务骨架+`serve` 已完成并验证(BETA);S2 观测 API / S3 前端仪表盘 / S4 安全加固 / S5 文档与 verify-m5 待推进。
295
+ - **M6**:自我进化核心 —— 自愈循环(self-heal)、上下文压缩(context-compactor)、经验学习(experience)、模型性能追踪(model-router stat)✅
296
+ - **M7**:编程能力增强 —— 代码分析器(code-analyzer)、代码生成器(code-generator)、AI 代码审查器(code-review)、仓库理解器(repo-underwriter)、测试生成器(test-generator)✅
297
+ - **M8**:自主编程迭代优化 —— CodeWriter 自主编写器(规划→编写→测试→审查→修复闭环)、QualityGate 质量门禁(安全+质量+测试覆盖)、SelfImprover 自我改进(反思→模式提取→经验融合)、CLI 命令(`code-write`/`quality-gate`/`self-improve`)✅
298
+ - **M9**:全自动软件工程 Agent —— 读取整个(大型)代码仓库(repo-reader,限流+忽略规则)→ 任务拆解规划(swe-planner,有序可验证子任务)→ 逐任务(实现+构建/测试验证+自愈重试,swe-agent 主编排)→ 产出结构化报告;CLI 命令 `fhcode swe "<目标>"`(支持 `--repo`/`--plan-only`/`--verify-only`/`--max-tasks`/`--max-retries`/`--max-iterations`)✅
299
+ - **M9.1 真实模型接入与实测调优** —— `loadConfig` 新增三级供应商解析(FH_PROVIDERS / `fhcode.config.json` / 单环境变量 `FH_MODEL_*`);`swe` 新增 `--max-iterations` 控制每子任务推理轮数;针对真实模型强化执行纪律(强制工具落地、必须真跑验证、禁谎报、只改相关文件)与自愈注入(注入真实命令输出);`scripts/verify-m9-real.mjs` 以 mock HTTP 服务实测"真实 provider 全链路"(11/11 通过)✅
300
+
301
+ ---
302
+
303
+ *晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹*
@@ -0,0 +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 晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹