@yancyyu/openhermit 1.6.25 → 1.6.27

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 (75) hide show
  1. package/README.md +127 -77
  2. package/bin/hermit.mjs +151 -62
  3. package/dist-renderer/assets/{ProjectEditorOverlay-CZ1LI0pd.js → ProjectEditorOverlay-BBwYdXPv.js} +1 -1
  4. package/dist-renderer/assets/{TeamGraphOverlay-DvyxOPvU.js → TeamGraphOverlay-DVq8rt6_.js} +1 -1
  5. package/dist-renderer/assets/{_basePickBy-D8IKEBh4.js → _basePickBy-ZbF0pKvS.js} +1 -1
  6. package/dist-renderer/assets/{_baseUniq-BDBpSAHY.js → _baseUniq-BBLBOeXc.js} +1 -1
  7. package/dist-renderer/assets/{arc-CZagJLek.js → arc-wGaEgkCf.js} +1 -1
  8. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-Cq083Uu6.js → architectureDiagram-VXUJARFQ-BpMkdC35.js} +1 -1
  9. package/dist-renderer/assets/{blockDiagram-VD42YOAC-CIEANvSv.js → blockDiagram-VD42YOAC-C8Z1xhG4.js} +1 -1
  10. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-Ca4h_BlA.js → c4Diagram-YG6GDRKO-CJmlw9LA.js} +1 -1
  11. package/dist-renderer/assets/channel-DJUrwVrK.js +1 -0
  12. package/dist-renderer/assets/{chunk-4BX2VUAB-DW9HjNgA.js → chunk-4BX2VUAB-CHPHiRPP.js} +1 -1
  13. package/dist-renderer/assets/{chunk-55IACEB6-BddOEwBk.js → chunk-55IACEB6-DyVohOQb.js} +1 -1
  14. package/dist-renderer/assets/{chunk-B4BG7PRW-Cmu8IjLN.js → chunk-B4BG7PRW-p5bffh_R.js} +1 -1
  15. package/dist-renderer/assets/{chunk-DI55MBZ5-BU7nEH8e.js → chunk-DI55MBZ5-BnfGPSUu.js} +1 -1
  16. package/dist-renderer/assets/{chunk-FMBD7UC4-BZNeq0CB.js → chunk-FMBD7UC4-B6SCKseX.js} +1 -1
  17. package/dist-renderer/assets/{chunk-QN33PNHL-DMb3gYzN.js → chunk-QN33PNHL-L12RvLBR.js} +1 -1
  18. package/dist-renderer/assets/{chunk-QZHKN3VN-8wSSvqz0.js → chunk-QZHKN3VN-DeH1Kxge.js} +1 -1
  19. package/dist-renderer/assets/{chunk-TZMSLE5B-B4OLgw45.js → chunk-TZMSLE5B-BWnjzSlI.js} +1 -1
  20. package/dist-renderer/assets/classDiagram-2ON5EDUG-blc3DrH7.js +1 -0
  21. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-blc3DrH7.js +1 -0
  22. package/dist-renderer/assets/clone-BftjWakJ.js +1 -0
  23. package/dist-renderer/assets/{cose-bilkent-S5V4N54A-CS9moNeT.js → cose-bilkent-S5V4N54A-BtzoT5fu.js} +1 -1
  24. package/dist-renderer/assets/{dagre-6UL2VRFP-3pzdMwjZ.js → dagre-6UL2VRFP-CBBvuoUD.js} +1 -1
  25. package/dist-renderer/assets/{diagram-PSM6KHXK-CGTnMY5C.js → diagram-PSM6KHXK-Be9BAKws.js} +1 -1
  26. package/dist-renderer/assets/{diagram-QEK2KX5R-Cyzp8dOw.js → diagram-QEK2KX5R-BDS4PI_i.js} +1 -1
  27. package/dist-renderer/assets/{diagram-S2PKOQOG-D_5SvdXI.js → diagram-S2PKOQOG-2Rameaq7.js} +1 -1
  28. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-bWPYfs9c.js → erDiagram-Q2GNP2WA-CSIzCEZD.js} +1 -1
  29. package/dist-renderer/assets/{flowDiagram-NV44I4VS-C5z47CKB.js → flowDiagram-NV44I4VS-ForEIVM5.js} +1 -1
  30. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-eye9Cv6S.js → ganttDiagram-JELNMOA3-BJrli_xr.js} +1 -1
  31. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-DekQZoF8.js → gitGraphDiagram-V2S2FVAM-C_4GuLno.js} +1 -1
  32. package/dist-renderer/assets/{graph-kNnl-9Fl.js → graph-B1EAT_gw.js} +1 -1
  33. package/dist-renderer/assets/index-CWpFqEvz.css +1 -0
  34. package/dist-renderer/assets/{index-hGBnMHVl.js → index-DOA_jbYb.js} +1 -1
  35. package/dist-renderer/assets/{index-ATiHUmmE.js → index-DR602dwJ.js} +1 -1
  36. package/dist-renderer/assets/{index-CrOkTuIK.js → index-DYdseEwc.js} +532 -532
  37. package/dist-renderer/assets/{index-CnxDIJh8.js → index-Dwr5wu5x.js} +1 -1
  38. package/dist-renderer/assets/{index-CI2l57ID.js → index-eKRmS5kI.js} +1 -1
  39. package/dist-renderer/assets/{index-DB0k9yRL.js → index-k4tnOFC5.js} +1 -1
  40. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-D3ilrGOS.js → infoDiagram-HS3SLOUP-DjI0uaMz.js} +1 -1
  41. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-BOCG2Rrk.js → journeyDiagram-XKPGCS4Q-jQ6Thae-.js} +1 -1
  42. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-hZ03nCkx.js → kanban-definition-3W4ZIXB7-CKw6InbL.js} +1 -1
  43. package/dist-renderer/assets/{layout-D5Mqy2My.js → layout-Dad20y3V.js} +1 -1
  44. package/dist-renderer/assets/{linear-Clp9OpXU.js → linear-vMgo_2Cv.js} +1 -1
  45. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-D-w-qhNz.js → mindmap-definition-VGOIOE7T-DYp6YoHL.js} +1 -1
  46. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-D9K0-ecY.js → pieDiagram-ADFJNKIX-BytBecG9.js} +1 -1
  47. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-B2f19Ki3.js → quadrantDiagram-AYHSOK5B-RUaspLsc.js} +1 -1
  48. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-VezNpCaU.js → requirementDiagram-UZGBJVZJ-rR2B1Use.js} +1 -1
  49. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-BpHjEoR9.js → sankeyDiagram-TZEHDZUN-BJi5qYhq.js} +1 -1
  50. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-Tdb7IZ4t.js → sequenceDiagram-WL72ISMW-BM-wggUb.js} +1 -1
  51. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-BNA5Q-zz.js → stateDiagram-FKZM4ZOC-BqmcVjnj.js} +1 -1
  52. package/dist-renderer/assets/{stateDiagram-v2-4FDKWEC3-w_4GEN2a.js → stateDiagram-v2-4FDKWEC3-By3JDVbB.js} +1 -1
  53. package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BghtWMWY.js → timeline-definition-IT6M3QCI-szH0GUyk.js} +1 -1
  54. package/dist-renderer/assets/{treemap-GDKQZRPO-BVquWjHf.js → treemap-GDKQZRPO-BCMlh-Ex.js} +1 -1
  55. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-BSV5wEDU.js → xychartDiagram-PRI3JC2R-dwDpvw0w.js} +1 -1
  56. package/dist-renderer/index.html +2 -2
  57. package/package.json +2 -2
  58. package/src/main/server.ts +52 -12
  59. package/src/renderer/api/httpClient.ts +1 -1
  60. package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +2 -0
  61. package/src/renderer/components/settings/sections/AdvancedSection.tsx +2 -0
  62. package/src/renderer/components/settings/sections/CliStatusSection.tsx +2 -0
  63. package/src/renderer/components/settings/sections/HarnessSection.tsx +11 -0
  64. package/src/renderer/components/settings/sections/PlatformsSection.tsx +10 -2
  65. package/src/renderer/components/team/TeamDetailView.tsx +53 -42
  66. package/src/renderer/components/team/TeamListView.tsx +54 -31
  67. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +123 -0
  68. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +98 -2
  69. package/src/renderer/utils/openHermitEvents.ts +9 -0
  70. package/src/shared/types/team.ts +5 -0
  71. package/dist-renderer/assets/channel-CqQK8EX1.js +0 -1
  72. package/dist-renderer/assets/classDiagram-2ON5EDUG-9A3Cg8IA.js +0 -1
  73. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-9A3Cg8IA.js +0 -1
  74. package/dist-renderer/assets/clone-Bnr-WjeU.js +0 -1
  75. package/dist-renderer/assets/index-C4x095x4.css +0 -1
package/README.md CHANGED
@@ -1,111 +1,107 @@
1
1
  <p align="center">
2
- <img src="resources/icons/png/1024x1024.png" alt="openHermit" width="100" />
2
+ <img src="resources/icons/png/1024x1024.png" alt="openHermit" width="96" />
3
3
  </p>
4
4
 
5
5
  <h1 align="center">openHermit</h1>
6
6
 
7
7
  <p align="center">
8
- <strong>超级个体的 AI 基础设施:用代码重构公司形态</strong><br/>
9
- 告别“玩具级”的提示词角色扮演。用状态机接管工作流,让一个人成为一支军队。
8
+ <strong>超级个体的 AI 基础设施 — 一个人,一块看板,一支军队</strong><br/>
9
+ 用代码重构公司形态,让 AI Agent 团队自主协作、自动流转、自动驾驶。
10
10
  </p>
11
11
 
12
12
  <p align="center">
13
13
  <a href="https://github.com/yancyuu/Hermit/releases/latest"><img src="https://img.shields.io/github/v/release/yancyuu/Hermit?style=flat-square&label=version&color=black" alt="最新版本" /></a>
14
14
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-AGPL--3.0-black?style=flat-square" alt="许可证" /></a>
15
+ <img src="https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-black?style=flat-square" alt="平台" />
15
16
  </p>
16
17
 
17
- ---
18
+ <p align="center">
19
+ <img src="docs/screenshots/openhermit/team-detail.png" alt="openHermit 看板总览" width="100%" />
20
+ </p>
18
21
 
19
- ## 💡 设计哲学:为什么我们需要 openHermit?
22
+ ---
20
23
 
21
- 目前的 AI Agent 赛道充满了一个巨大的误区:**大家都在试图用人类的“HR 组织架构”来管理 AI。**
22
- 让大模型扮演“资深前端”或“产品经理”,本质上是在模仿人类的**职责驱动**(因岗设人)。这注定会走向死锁——因为人类有精力上限和认知边界,才需要划分部门和扯皮;而 AI 没有。
24
+ ## 为什么需要 openHermit?
23
25
 
24
- **openHermit 是一场对传统协作模式的降维打击。** 它的核心哲学只有两条:
26
+ 目前的 AI Agent 赛道充满了一个巨大误区:**大家都在试图用人类的"HR 组织架构"来管理 AI。**
27
+ 让大模型扮演"资深前端"或"产品经理",本质上是在模仿人类的**职责驱动**(因岗设人)。这注定会走向死锁——因为人类有精力上限和认知边界,才需要划分部门和扯皮;而 AI 没有。
25
28
 
26
- ### 1. 对创业者:组织形态的“资产化” (OPC 范式)
27
- **OPC(One Person Company)** 不再是一个浪漫的口号,而是最具杠杆率的商业形态。
28
- 你不需要招聘、不需要对齐价值观、不需要处理情绪内耗。你是唯一的决策者,AI 是绝对服从的执行网格。openHermit 为你提供 **TPC(Team · Process · Channel)** 协作结构,将产品、开发、测试、运营转化为可并发现程。你的每一次业务跑通,都是在积累固化的“数字资产”,而不是随员工离职而流失的经验。
29
+ **openHermit 的核心哲学:用管理机器的方式管理 Agent,而不是用管理人的方式。**
29
30
 
30
- ### 2. 对开发者与工程师:去中心化的“状态机”驱动 (State-Driven DAG)
31
- **用管理机器的方式管理 Agent,而不是用管理人的方式。**
32
- Agent 的协作本质不该是“角色扮演”,而是**分布式状态机**。任务流是一张 DAG,每个节点代表一种确定的状态(Pending → Running → Review → Done)。
33
- * **拒绝死锁**:遇到网络波动或反爬环境,状态机自动 `Fail-Over` 切换运行时,流水线永远不会因为“超出角色职责”而卡死。
34
- * **Zero-Trust 与 Local-First**:真正的生产力工具不能是黑盒。openHermit 坚持本地优先的零信任架构。配置、项目代码、长短期记忆同步都在你的本地机器完成,彻底掌控数据主权。
35
- * **即用即走,上下文随状态流转**:Agent 不拥有固定岗位,只有当任务状态流转到 `Ready` 时,控制面才会将当前状态、上下文(Context)和能力(Skills)动态注入给对应的 Agent 运行时。
31
+ 任务流是一张 DAG,每个节点代表一种确定的状态(Pending Running → Review → Done)。遇到网络波动或反爬环境,状态机自动 `Fail-Over`,流水线永远不会因为"超出角色职责"而卡死。
36
32
 
37
33
  ---
38
34
 
39
- ## ⚙️ 核心架构:TPC 引擎
40
-
41
- 想要让 OPC 跑起来,你需要的不是一堆散落的终端窗口,而是 TPC 架构:
42
-
43
- * **[ T ] Team(隔离与并发)**:给不同的工作建立独立团队。前端用 Claude Code 撸代码,后端用 Codex 构架,调研交由 Kimi。每个团队有独立的隔离运行时环境,但在全局协作看板上,任务可以跨团队无缝调度。
44
- * **[ P ] Process(状态流转)**:彻底放弃“岗位 KPI”。一切以任务的原子化状态为核心,MCP Server 动态向 Agent 注入当前所需工具。
45
- * **[ C ] Channel(全渠道触达)**:支持飞书、微信、Telegram、Discord、Slack 等 10+ 渠道接入。消息即指令,外部输入自动路由至对应 Agent 团队,支持独立上下文串或共享群会话,将你的 IM 变成公司级控制台。
35
+ ## 产品截图
36
+
37
+ <table>
38
+ <tr>
39
+ <td align="center"><b>团队列表</b></td>
40
+ <td align="center"><b>团队详情</b></td>
41
+ </tr>
42
+ <tr>
43
+ <td><img src="docs/screenshots/openhermit/team-list.png" alt="团队列表" width="480" /></td>
44
+ <td><img src="docs/screenshots/openhermit/team-detail.png" alt="团队详情" width="480" /></td>
45
+ </tr>
46
+ <tr>
47
+ <td align="center"><b>运行时配置</b></td>
48
+ <td align="center"><b>渠道绑定</b></td>
49
+ </tr>
50
+ <tr>
51
+ <td><img src="docs/screenshots/openhermit/harness-settings.png" alt="运行时配置" width="480" /></td>
52
+ <td><img src="docs/screenshots/openhermit/channel-binding.png" alt="渠道绑定" width="480" /></td>
53
+ </tr>
54
+ </table>
46
55
 
47
56
  ---
48
57
 
49
- ## 🛠️ 支持的 Agent 运行时与渠道
50
-
51
- openHermit 不提供闭源模型,也不劫持你的代码。它是一个高度可扩展的本地环境壳层。
52
-
53
- ### 极客级的多端运行时支持
54
- 创建团队时,底层 MCP Server 会自动完成零配置注入。能否启动,取决于你的算力边界。
55
-
56
- | 标识 | 运行时说明 | 标识 | 运行时说明 |
57
- |:---|:---|:---|:---|
58
- | `claudecode` | Anthropic 官方 CLI | `devin` | Cognition Devin |
59
- | `codex` | OpenAI Codex CLI | `opencode` | OpenCode CLI |
60
- | `cursor` | Cursor IDE Agent | `qoder` | Qoder CLI |
61
- | `gemini` | Google Gemini CLI | `pi` | Inflection Pi |
62
- | `iflow` | iFlow CLI | `acp` | Agent Communication Protocol |
63
- | `kimi` | Moonshot Kimi | `tmux` | 经典 Tmux Session 桥接 |
64
-
65
- ### 模块化的信使网络 (Channels)
66
- 让外部世界无缝接入你的自动化流水线:
67
- * **研发协同**:飞书(支持高级消息卡片)、钉钉、企业微信、Slack
68
- * **极客与海外**:Telegram、Discord、LINE
69
- * **私域与社群**:微信、QQ
70
- * **自定义集成**:原生支持 openHermit 内部 Bridge 协议
58
+ ## 核心能力
59
+
60
+ | 能力 | 说明 |
61
+ |:---|:---|
62
+ | **Agent 团队** | 创建多角色团队,Agent 自主并行工作 |
63
+ | **看板管理** | 任务状态实时流转 — 待办、执行中、审查、完成 |
64
+ | **代码审查** | 每个任务独立的 Diff 视图,支持接受/拒绝/评论 |
65
+ | **跨团队通信** | Agent 之间跨团队结构化消息传递 |
66
+ | **直接消息** | 向任意 Agent 发消息、评论任务、快捷操作 |
67
+ | **会话分析** | 深度拆解:Bash 命令、推理链、子进程 |
68
+ | **上下文监控** | 按类别追踪 Token 消耗,掌控上下文窗口 |
69
+ | **MCP 集成** | 内置 MCP Server,支持外部工具和 Agent 插件 |
70
+ | **权限控制** | 精细化允许/拒绝工具执行和 Agent 操作 |
71
+ | **渠道绑定** | 接入飞书、Slack、Telegram、Discord、微信等 10+ 渠道 |
72
+ | **零配置上手** | 内置 Claude Code CLI 安装和认证 |
71
73
 
72
74
  ---
73
75
 
74
- ## 🚀 极速部署
76
+ ## 极速部署
75
77
 
76
- ### 1. 安装启动
78
+ ### 方式一:npx(免安装直接运行)
77
79
 
78
- 方式一:npx(免安装直接运行)
79
80
  ```bash
80
81
  npx @yancyyu/openhermit@latest
81
82
  ```
82
83
 
83
- 方式二:全局安装
84
+ 启动后打开 [http://127.0.0.1:5680](http://127.0.0.1:5680)
85
+
86
+ ### 方式二:全局安装
87
+
84
88
  ```bash
85
89
  npm install -g @yancyyu/openhermit@latest --prefer-online
86
90
  openhermit
87
91
  ```
88
92
 
89
- 启动后打开:
90
-
91
- ```text
92
- http://127.0.0.1:5680
93
- ```
94
-
95
- 常用命令:
93
+ ### 常用命令
96
94
 
97
95
  ```bash
98
- open-hermit # 等同于 openhermit
99
- openhermit --daemon # 后台运行
100
- openhermit status # 查看后台运行状态
101
- openhermit stop # 停止后台服务
102
- openhermit --port 8080 # 指定 Web 控制台端口
103
- openhermit --version # 查看版本
104
- openhermit update # 更新 openHermit
96
+ openhermit # 启动工作台
97
+ openhermit --daemon # 后台运行
98
+ openhermit status # 查看后台状态
99
+ openhermit stop # 停止后台服务
100
+ openhermit --port 8080 # 指定端口
101
+ openhermit --version # 查看版本
102
+ openhermit update # 自更新
105
103
  ```
106
104
 
107
- 首次启动会自动创建本地运行时配置,并生成本地 token。通常只需要打开 `http://127.0.0.1:5680` 使用 openHermit。
108
-
109
105
  ### 本地开发
110
106
 
111
107
  ```bash
@@ -115,26 +111,80 @@ pnpm install
115
111
  pnpm dev
116
112
  ```
117
113
 
118
- 浏览器打开 `http://localhost:5174`
119
-
120
- 开发模式默认连接本机运行时服务;生产 CLI 会优先使用 openHermit 管理的本地配置。
114
+ 浏览器打开 [http://localhost:5174](http://localhost:5174),开发模式默认连接本机运行时。
121
115
 
122
116
  ### 创建第一个 AI 团队
123
117
 
124
- 1. 点击「新建团队」
125
- 2. 填写团队名、选 harness(如 `claudecode`)
126
- 3. 选择对应的本地项目和运行时
118
+ 1. 点击 **「新建团队」**
119
+ 2. 填写团队名,选择 harness(如 `claudecode`)
120
+ 3. 选择本地项目目录和运行时
127
121
  4. 保存 → 看板就绪,任务等你分配
128
122
 
129
123
  ---
130
124
 
125
+ ## 支持的 Agent 运行时
126
+
127
+ openHermit 不提供闭源模型,也不劫持你的代码。它是一个高度可扩展的本地壳层。
128
+
129
+ | 标识 | 运行时 | 标识 | 运行时 |
130
+ |:---|:---|:---|:---|
131
+ | `claudecode` | Anthropic Claude Code CLI | `devin` | Cognition Devin |
132
+ | `codex` | OpenAI Codex CLI | `opencode` | OpenCode CLI |
133
+ | `cursor` | Cursor IDE Agent | `qoder` | Qoder CLI |
134
+ | `gemini` | Google Gemini CLI | `pi` | Inflection Pi |
135
+ | `iflow` | iFlow CLI | `acp` | Agent Communication Protocol |
136
+ | `kimi` | Moonshot Kimi | `tmux` | 经典 Tmux Session |
137
+
138
+ ---
139
+
140
+ ## 核心架构:TPC 引擎
141
+
142
+ ```
143
+ ┌─────────────────────────────────────────────┐
144
+ │ openHermit │
145
+ │ │
146
+ │ ┌─────────┐ ┌─────────┐ ┌─────────────┐ │
147
+ │ │ Team A │ │ Team B │ │ Team C │ │
148
+ │ │ (agents) │ │ (agents) │ │ (agents) │ │
149
+ │ └────┬─────┘ └────┬─────┘ └──────┬─────┘ │
150
+ │ │ │ │ │
151
+ │ ─────┴──────────────┴───────────────┴────── │
152
+ │ 看板 · 消息总线 │
153
+ │ ─────────────────────────────────────────── │
154
+ │ MCP Server · Bridge 协议 │
155
+ │ ─────────────────────────────────────────── │
156
+ │ 渠道(飞书 · Slack · Telegram · ...) │
157
+ └─────────────────────────────────────────────┘
158
+ ```
159
+
160
+ - **[T]eam(隔离与并发)** — 不同团队独立运行时,全局看板跨团队调度
161
+ - **[P]rocess(状态流转)** — 任务以原子化状态为核心,MCP 动态注入能力
162
+ - **[C]hannel(全渠道触达)** — 10+ 消息渠道统一控制面,消息即指令
163
+
164
+ ---
165
+
131
166
  ## 技术栈
132
167
 
133
- - **前端**:React + TypeScript + Tailwind CSS + Zustand
134
- - **后端**:Fastify(Node.js)
135
- - **存储**:本地文件(`~/.hermit/`)
136
- - **通信**:本地 Bridge WebSocket + Management HTTP API
137
- - **协议**:MCP over HTTP(SSE + JSON-RPC)
168
+ | 层级 | 技术 |
169
+ |:---|:---|
170
+ | 前端 | React 19 · TypeScript 5 · Tailwind CSS 3 · Zustand 4 |
171
+ | 后端 | Fastify (Node.js) |
172
+ | 桌面 | Electron 40 |
173
+ | 存储 | 本地文件(`~/.hermit/`) |
174
+ | 通信 | WebSocket Bridge + HTTP Management API |
175
+ | 协议 | MCP over HTTP(SSE + JSON-RPC) |
176
+
177
+ ---
178
+
179
+ ## 贡献
180
+
181
+ 欢迎 PR。Fork → Branch → Push → PR,标准流程。
182
+
183
+ ```bash
184
+ pnpm install
185
+ pnpm dev # 启动开发服务
186
+ pnpm check # 完整质量检查(类型 + Lint + 测试 + 构建)
187
+ ```
138
188
 
139
189
  ---
140
190
 
package/bin/hermit.mjs CHANGED
@@ -18,6 +18,7 @@ import { spawn, execSync } from 'node:child_process';
18
18
  import crypto from 'node:crypto';
19
19
  import { appendFileSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
20
20
  import { createRequire } from 'node:module';
21
+ import net from 'node:net';
21
22
  import os from 'node:os';
22
23
  import path from 'node:path';
23
24
  import { fileURLToPath, pathToFileURL } from 'node:url';
@@ -96,8 +97,7 @@ const ccConnectConfigPath =
96
97
  process.env.HERMIT_CC_CONNECT_CONFIG ||
97
98
  process.env.CC_CONNECT_CONFIG ||
98
99
  path.join(hermitHome, 'cc-connect', 'config.toml');
99
- const bootstrapProjectName = 'default';
100
- const legacyBootstrapProjectName = '__openhermit_bootstrap__';
100
+ const starterProjectName = 'my-project';
101
101
 
102
102
  // ---------------------------------------------------------------------------
103
103
  // Update command
@@ -351,10 +351,6 @@ Please install dependencies first:
351
351
  // cc-connect sidecar
352
352
  // ---------------------------------------------------------------------------
353
353
 
354
- function randomToken() {
355
- return crypto.randomBytes(16).toString('hex');
356
- }
357
-
358
354
  function escapeTomlPath(value) {
359
355
  return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
360
356
  }
@@ -364,34 +360,8 @@ function parseTomlToken(raw, section) {
364
360
  return match?.[1] || '';
365
361
  }
366
362
 
367
- function hasProjectEntries(raw) {
368
- return /^\s*\[\[projects\]\]/m.test(raw);
369
- }
370
-
371
- function buildBootstrapProjectToml() {
372
- return `
373
- # Internal bootstrap project used only so cc-connect can start with an otherwise empty config.
374
- # It is safe to keep this project; users can replace or delete it after creating real teams.
375
- [[projects]]
376
- name = "${bootstrapProjectName}"
377
- disabled_commands = ["*"]
378
-
379
- [projects.agent]
380
- type = "claudecode"
381
-
382
- [projects.agent.options]
383
- work_dir = "${escapeTomlPath(hermitHome)}"
384
- mode = "default"
385
-
386
- [[projects.platforms]]
387
- type = "line"
388
-
389
- [projects.platforms.options]
390
- channel_secret = "openhermit-bootstrap"
391
- channel_token = "openhermit-bootstrap"
392
- port = "0"
393
- callback_path = "/openhermit-bootstrap"
394
- `;
363
+ function randomToken() {
364
+ return crypto.randomBytes(16).toString('hex');
395
365
  }
396
366
 
397
367
  function escapeRegExp(value) {
@@ -415,22 +385,28 @@ function isManagedBootstrapBlock(block) {
415
385
  );
416
386
  }
417
387
 
418
- function migrateManagedBootstrapProject(raw) {
419
- const legacyBlock = findProjectBlock(raw, legacyBootstrapProjectName);
420
- if (!legacyBlock || !isManagedBootstrapBlock(legacyBlock.match[0])) return raw;
421
-
422
- const withoutLegacy = raw.replace(legacyBlock.pattern, '').replace(/\n{3,}/g, '\n\n').trimEnd();
423
- if (findProjectBlock(withoutLegacy, bootstrapProjectName)) {
424
- return `${withoutLegacy}\n`;
425
- }
426
-
427
- return `${withoutLegacy}\n${buildBootstrapProjectToml()}`;
388
+ function isStarterProjectConfig(raw) {
389
+ const block = findProjectBlock(raw, starterProjectName);
390
+ if (!block) return false;
391
+ const text = block.match[0];
392
+ return (
393
+ text.includes('name = "my-project"') &&
394
+ text.includes('type = "claudecode"') &&
395
+ text.includes('work_dir = "/path/to/your/project"') &&
396
+ text.includes('app_id = "your-feishu-app-id"') &&
397
+ text.includes('app_secret = "your-feishu-app-secret"')
398
+ );
428
399
  }
429
400
 
430
401
  function configRequiresClaudeCode(raw) {
431
402
  return /type\s*=\s*"claudecode"/.test(raw);
432
403
  }
433
404
 
405
+ function hasProjectEntries(raw) {
406
+ const projectPattern = /\[\[projects\]\]\nname\s*=\s*"([^"]+)"[\s\S]*?(?=\n\[\[projects\]\]|\s*$)/g;
407
+ return [...raw.matchAll(projectPattern)].some((match) => !isManagedBootstrapBlock(match[0]));
408
+ }
409
+
434
410
  function commandExists(command) {
435
411
  try {
436
412
  execSync(`${command} --version`, { stdio: 'ignore', shell: true });
@@ -464,12 +440,15 @@ function ensureClaudeCodeCliIfNeeded(raw) {
464
440
  console.log('[openHermit] Claude Code CLI installed and available in PATH.');
465
441
  }
466
442
 
467
- function ensureCcConnectConfig() {
468
- mkdirSync(path.dirname(ccConnectConfigPath), { recursive: true });
469
- if (!existsSync(ccConnectConfigPath)) {
470
- const managementToken = randomToken();
471
- const bridgeToken = randomToken();
472
- const config = `data_dir = "${escapeTomlPath(path.join(hermitHome, 'cc-connect', 'data'))}"
443
+ function hasTomlSection(raw, section) {
444
+ return new RegExp(`^\\[${section}\\]\\s*$`, 'm').test(raw);
445
+ }
446
+
447
+ function buildOpenHermitStarterConfig(managementToken, bridgeToken) {
448
+ return `# cc-connect configuration
449
+ # Docs: https://github.com/chenhg5/cc-connect
450
+
451
+ data_dir = "${escapeTomlPath(path.join(hermitHome, 'cc-connect', 'data'))}"
473
452
  language = "zh"
474
453
 
475
454
  [management]
@@ -487,23 +466,73 @@ path = "/bridge/ws"
487
466
 
488
467
  [log]
489
468
  level = "info"
490
- ${buildBootstrapProjectToml()}`;
491
- writeFileSync(ccConnectConfigPath, config, 'utf-8');
469
+
470
+ [[projects]]
471
+ name = "my-project"
472
+
473
+ [projects.agent]
474
+ type = "claudecode" # "claudecode", "codex", "cursor", "gemini", "qoder", "opencode", or "iflow"
475
+
476
+ [projects.agent.options]
477
+ work_dir = "/path/to/your/project"
478
+ mode = "default"
479
+ # model = "claude-sonnet-4-20250514"
480
+
481
+ # --- Choose at least one platform below ---
482
+
483
+ [[projects.platforms]]
484
+ type = "feishu"
485
+
486
+ [projects.platforms.options]
487
+ app_id = "your-feishu-app-id"
488
+ app_secret = "your-feishu-app-secret"
489
+ `;
490
+ }
491
+
492
+ function ensureOpenHermitRuntimeConfig() {
493
+ mkdirSync(path.dirname(ccConnectConfigPath), { recursive: true });
494
+ if (!existsSync(ccConnectConfigPath)) {
495
+ writeFileSync(ccConnectConfigPath, buildOpenHermitStarterConfig(randomToken(), randomToken()), 'utf-8');
496
+ return;
492
497
  }
493
498
 
494
499
  let raw = readFileSync(ccConnectConfigPath, 'utf-8');
495
- if (!hasProjectEntries(raw)) {
496
- raw = `${raw.trimEnd()}\n${buildBootstrapProjectToml()}`;
500
+ let changed = false;
501
+ if (!hasTomlSection(raw, 'management')) {
502
+ raw = `${raw.trimEnd()}
503
+
504
+ [management]
505
+ enabled = true
506
+ host = "127.0.0.1"
507
+ port = 9820
508
+ token = "${randomToken()}"
509
+ `;
510
+ changed = true;
511
+ }
512
+ if (!hasTomlSection(raw, 'bridge')) {
513
+ raw = `${raw.trimEnd()}
514
+
515
+ [bridge]
516
+ enabled = true
517
+ host = "127.0.0.1"
518
+ port = 9810
519
+ token = "${randomToken()}"
520
+ path = "/bridge/ws"
521
+ `;
522
+ changed = true;
523
+ }
524
+ if (changed) {
497
525
  writeFileSync(ccConnectConfigPath, raw, 'utf-8');
498
- } else {
499
- const migrated = migrateManagedBootstrapProject(raw);
500
- if (migrated !== raw) {
501
- raw = migrated;
502
- writeFileSync(ccConnectConfigPath, raw, 'utf-8');
503
- }
504
526
  }
527
+ }
528
+
529
+ function readCcConnectConfigState() {
530
+ ensureOpenHermitRuntimeConfig();
531
+
532
+ const raw = readFileSync(ccConnectConfigPath, 'utf-8');
505
533
 
506
534
  return {
535
+ configExists: true,
507
536
  managementToken:
508
537
  process.env.CC_CONNECT_TOKEN ||
509
538
  process.env.CC_CONNECT_MANAGEMENT_TOKEN ||
@@ -512,6 +541,8 @@ ${buildBootstrapProjectToml()}`;
512
541
  process.env.CC_CONNECT_BRIDGE_TOKEN ||
513
542
  process.env.CC_CONNECT_TOKEN ||
514
543
  parseTomlToken(raw, 'bridge'),
544
+ hasProjects: hasProjectEntries(raw),
545
+ isStarterConfig: isStarterProjectConfig(raw),
515
546
  raw,
516
547
  };
517
548
  }
@@ -594,25 +625,82 @@ function resolveAliasLoaderRegister() {
594
625
  return `data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(${JSON.stringify(aliasLoaderUrl)}, pathToFileURL("./"));`;
595
626
  }
596
627
 
628
+ async function checkExistingOpenHermitServer() {
629
+ const url = `http://127.0.0.1:${port}`;
630
+ try {
631
+ const res = await fetch(`${url}/api/version`, { signal: AbortSignal.timeout(1000) });
632
+ if (res.ok) {
633
+ const version = (await res.text()).trim() || 'unknown';
634
+ return { running: true, version, url };
635
+ }
636
+ } catch {
637
+ // Port may be unused or owned by another process.
638
+ }
639
+ return { running: false, version: '', url };
640
+ }
641
+
642
+ async function isTcpPortAvailable(portNumber) {
643
+ return new Promise((resolve) => {
644
+ const server = net.createServer();
645
+ server.once('error', () => resolve(false));
646
+ server.once('listening', () => {
647
+ server.close(() => resolve(true));
648
+ });
649
+ server.listen(portNumber, '127.0.0.1');
650
+ });
651
+ }
652
+
653
+ async function assertWebPortAvailable() {
654
+ const existingServer = await checkExistingOpenHermitServer();
655
+ if (existingServer.running) {
656
+ console.log(`[openHermit] Already running: ${existingServer.url}`);
657
+ console.log(`[openHermit] Version: ${existingServer.version}`);
658
+ console.log('[openHermit] Run `openhermit stop` first, or use `openhermit --port <port>` for another instance.');
659
+ process.exit(0);
660
+ }
661
+
662
+ const available = await isTcpPortAvailable(Number.parseInt(port, 10));
663
+ if (!available) {
664
+ console.error(`[openHermit] Port ${port} is already in use.`);
665
+ console.error('[openHermit] Stop the existing process first, or start with another port:');
666
+ console.error(` openhermit --port ${Number.parseInt(port, 10) + 1}`);
667
+ console.error('[openHermit] macOS/Linux: lsof -nP -iTCP:' + port + ' -sTCP:LISTEN');
668
+ console.error('[openHermit] Windows: netstat -ano | findstr :' + port);
669
+ process.exit(1);
670
+ }
671
+ }
672
+
597
673
  let ccConnectProcess = null;
598
674
  let ccTokens = {
599
675
  managementToken: process.env.CC_CONNECT_TOKEN || process.env.CC_CONNECT_MANAGEMENT_TOKEN || '',
600
676
  bridgeToken: process.env.CC_CONNECT_BRIDGE_TOKEN || process.env.CC_CONNECT_TOKEN || '',
601
677
  };
678
+ let runtimeSetupMode = false;
679
+
680
+ await assertWebPortAvailable();
602
681
 
603
682
  if (!skipCcConnect) {
604
- ccTokens = ensureCcConnectConfig();
683
+ let shouldStartRuntime = false;
684
+ ccTokens = readCcConnectConfigState();
605
685
  const ccBaseUrl = process.env.CC_CONNECT_BASE_URL || 'http://127.0.0.1:9820';
606
686
  const alreadyRunning = await waitForCcConnect(ccBaseUrl, ccTokens.managementToken, 1_000);
607
687
  if (alreadyRunning) {
608
688
  console.log(`[openHermit] Runtime service already running: ${ccBaseUrl}`);
609
- } else {
689
+ } else if (ccTokens.hasProjects) {
610
690
  try {
611
691
  ensureClaudeCodeCliIfNeeded(ccTokens.raw);
612
692
  } catch {
613
693
  printLogTail('Runtime', runtimeLogPath);
614
694
  process.exit(1);
615
695
  }
696
+ shouldStartRuntime = true;
697
+ } else {
698
+ console.error('[openHermit] Runtime config has no projects. Please edit the config and try again.');
699
+ console.error(`[openHermit] Runtime config: ${ccConnectConfigPath}`);
700
+ process.exit(1);
701
+ }
702
+
703
+ if (shouldStartRuntime) {
616
704
  console.log('[openHermit] Starting bundled runtime service...');
617
705
  console.log(`[openHermit] Runtime config: ${ccConnectConfigPath}`);
618
706
  ccConnectProcess = spawn(process.execPath, [resolveCcConnectRunner(), '-config', ccConnectConfigPath], {
@@ -700,6 +788,7 @@ const serverProcess = spawn(process.execPath, ['--import', resolveAliasLoaderReg
700
788
  HOST: process.env.HOST || '127.0.0.1',
701
789
  NODE_ENV: 'production',
702
790
  HERMIT_HOME: hermitHome,
791
+ HERMIT_RUNTIME_SETUP_MODE: runtimeSetupMode ? '1' : '0',
703
792
  CC_CONNECT_TOKEN: ccTokens.managementToken,
704
793
  CC_CONNECT_MANAGEMENT_TOKEN: ccTokens.managementToken,
705
794
  CC_CONNECT_BRIDGE_TOKEN: ccTokens.bridgeToken,
@@ -1,4 +1,4 @@
1
- import{bD as de,bE as w,bF as Re,r as s,bG as Ce,bH as As,bI as Ls,E as pe,bJ as Os,bK as zs,q as e,bL as $s,bM as Ks,bN as Kt,bO as Gt,bP as Gs,bQ as Bs,bR as Us,bS as Vs,bT as H,bU as X,bV as sn,bW as rn,bX as q,bY as mt,bZ as he,b_ as on,b$ as P,c0 as Ws,c1 as tt,c2 as Hs,c3 as Xs,c4 as qs,c5 as Ys,c6 as Qs,c7 as Zs,c8 as Js,c9 as er,ca as tr,cb as nr,cc as sr,cd as rr,ce as or,cf as ar,cg as Bt,ch as ir,ci as an,cj as cn,ck as cr,cl as lr,cm as dr,cn as ur,co as xr,cp as je,cq as nt,cr as fr,cs as Ee,ct as hr,cu as gt,cv as ln,cw as mr,cx as dn,cy as un,cz as bt,cA as pr,cB as gr,cC as br,cD as st,cE as vr,cF as Be,cG as $,cH as Ie,cI as Cr,cJ as jr,cK as yr,cL as Nr,cM as wr,cN as Sr,cO as kr,cP as Mr,cQ as Tr,cR as Er,cS as Rr,cT as Ir,cU as Ze,cV as Dr,cW as Pr,cX as vt,cY as xn,cZ as fn,c_ as hn,c$ as _r,d0 as Fr,d1 as Ar,d2 as mn,d3 as pn,d4 as gn,d5 as Le,d6 as Oe,d7 as ze,d8 as $e,d9 as Ye,da as Qe,db as bn,dc as vn,dd as Lr,de as Ue,df as Or,dg as zr,dh as $r,di as Kr,dj as Gr,dk as Br,dl as Ur,dm as Vr,dn as Wr,dp as Hr,dq as Xr,dr as qr,ds as Yr,dt as Qr,du as Zr,dv as Fe,dw as Jr,dx as Ut,dy as eo,dz as to,dA as Vt,dB as no,dC as so,dD as ro,dE as Wt}from"./index-CrOkTuIK.js";import"./splashScene-C8lWNnm4.js";/**
1
+ import{bD as de,bE as w,bF as Re,r as s,bG as Ce,bH as As,bI as Ls,E as pe,bJ as Os,bK as zs,q as e,bL as $s,bM as Ks,bN as Kt,bO as Gt,bP as Gs,bQ as Bs,bR as Us,bS as Vs,bT as H,bU as X,bV as sn,bW as rn,bX as q,bY as mt,bZ as he,b_ as on,b$ as P,c0 as Ws,c1 as tt,c2 as Hs,c3 as Xs,c4 as qs,c5 as Ys,c6 as Qs,c7 as Zs,c8 as Js,c9 as er,ca as tr,cb as nr,cc as sr,cd as rr,ce as or,cf as ar,cg as Bt,ch as ir,ci as an,cj as cn,ck as cr,cl as lr,cm as dr,cn as ur,co as xr,cp as je,cq as nt,cr as fr,cs as Ee,ct as hr,cu as gt,cv as ln,cw as mr,cx as dn,cy as un,cz as bt,cA as pr,cB as gr,cC as br,cD as st,cE as vr,cF as Be,cG as $,cH as Ie,cI as Cr,cJ as jr,cK as yr,cL as Nr,cM as wr,cN as Sr,cO as kr,cP as Mr,cQ as Tr,cR as Er,cS as Rr,cT as Ir,cU as Ze,cV as Dr,cW as Pr,cX as vt,cY as xn,cZ as fn,c_ as hn,c$ as _r,d0 as Fr,d1 as Ar,d2 as mn,d3 as pn,d4 as gn,d5 as Le,d6 as Oe,d7 as ze,d8 as $e,d9 as Ye,da as Qe,db as bn,dc as vn,dd as Lr,de as Ue,df as Or,dg as zr,dh as $r,di as Kr,dj as Gr,dk as Br,dl as Ur,dm as Vr,dn as Wr,dp as Hr,dq as Xr,dr as qr,ds as Yr,dt as Qr,du as Zr,dv as Fe,dw as Jr,dx as Ut,dy as eo,dz as to,dA as Vt,dB as no,dC as so,dD as ro,dE as Wt}from"./index-DYdseEwc.js";import"./splashScene-C8lWNnm4.js";/**
2
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1 +1 @@
1
- import{u as R,m as V,n as q,o as D,r as n,q as a,T as P,G as W,v as I,w as Z,x as z,y as O,z as B}from"./index-CrOkTuIK.js";import"./splashScene-C8lWNnm4.js";const M=({teamName:s,onClose:c,onPinAsTab:h,sidebarVisible:C,onToggleSidebar:v,onSendMessage:u,onOpenTaskDetail:i,onOpenMemberProfile:d})=>{const T=R(s),{openTeamPage:k,commitOwnerSlotDrop:w,commitOwnerGridOrderDrop:S,setLayoutMode:x}=V(s),{sidebarVisible:m,toggleSidebarVisible:f}=q(),{dialog:G,openCreateTaskDialog:g}=D(s),b=C??m,y=v??f,t=n.useCallback(o=>e=>window.dispatchEvent(new CustomEvent(`graph:${o}`,{detail:{teamName:s,taskId:e}})),[s]),A=n.useMemo(()=>({onStartTask:t("start-task"),onCompleteTask:t("complete-task"),onApproveTask:t("approve-task"),onRequestReview:t("request-review"),onRequestChanges:t("request-changes"),onCancelTask:t("cancel-task"),onMoveBackToDone:t("move-back-to-done"),onDeleteTask:t("delete-task")}),[t]),j=n.useCallback(()=>{k(),c()},[c,k]),H=n.useCallback(()=>{g("")},[g]),E={onNodeDoubleClick:n.useCallback(o=>{o.kind==="task"?i?.(o.taskId):o.kind==="member"&&d?.(o.memberName)},[i,d]),onSendMessage:n.useCallback(o=>u?.(o),[u]),onOpenTaskDetail:n.useCallback(o=>i?.(o),[i]),onOpenMemberProfile:n.useCallback(o=>d?.(o),[d])};return a.jsxs("div",{className:"fixed inset-0 z-50 flex overflow-hidden",style:{background:"#050510"},children:[b?a.jsx(P,{teamName:s,surface:"graph-overlay",isActive:!0,isFocused:!0}):null,a.jsx(W,{data:T,events:E,isSurfaceActive:!0,onRequestClose:c,onRequestPinAsTab:h,onOpenTeamPage:j,onCreateTask:H,onToggleSidebar:y,isSidebarVisible:b,renderTopToolbarContent:()=>a.jsx(B,{teamName:s}),onLayoutModeChange:x,onOwnerSlotDrop:w,onOwnerGridOrderDrop:S,className:"team-graph-view min-w-0 flex-1",renderHud:o=>{const e=o,{getViewportSize:r,focusNodeIds:l,filters:p}=e;return a.jsxs(a.Fragment,{children:[a.jsx(z,{teamName:s,getTransientHandoffSnapshot:e.getTransientHandoffSnapshot,getCameraZoom:e.getCameraZoom,worldToScreen:e.worldToScreen,getNodeWorldPosition:e.getNodeWorldPosition,focusNodeIds:l,focusEdgeIds:e.focusEdgeIds??null}),a.jsx(O,{teamName:s,nodes:T.nodes,getActivityWorldRect:e.getActivityWorldRect,getCameraZoom:e.getCameraZoom,worldToScreen:e.worldToScreen,getNodeWorldPosition:e.getNodeWorldPosition,getViewportSize:r,focusNodeIds:l,enabled:p?.showActivity??!0,onOpenTaskDetail:i,onOpenMemberProfile:d})]})},renderEdgeOverlay:({edge:o,sourceNode:e,targetNode:r,onClose:l,onSelectNode:p})=>a.jsx(Z,{teamName:s,edge:o,sourceNode:e,targetNode:r,onClose:l,onSelectNode:p,onOpenTaskDetail:i}),renderOverlay:({node:o,onClose:e})=>a.jsx(I,{node:o,teamName:s,onClose:e,onSendMessage:r=>{u?.(r),e()},onCreateTask:g,onOpenTaskDetail:r=>{i?.(r),e()},onOpenMemberProfile:r=>{d?.(r),e()},...A})}),G]})};export{M as TeamGraphOverlay};
1
+ import{u as R,m as V,n as q,o as D,r as n,q as a,T as P,G as W,v as I,w as Z,x as z,y as O,z as B}from"./index-DYdseEwc.js";import"./splashScene-C8lWNnm4.js";const M=({teamName:s,onClose:c,onPinAsTab:h,sidebarVisible:C,onToggleSidebar:v,onSendMessage:u,onOpenTaskDetail:i,onOpenMemberProfile:d})=>{const T=R(s),{openTeamPage:k,commitOwnerSlotDrop:w,commitOwnerGridOrderDrop:S,setLayoutMode:x}=V(s),{sidebarVisible:m,toggleSidebarVisible:f}=q(),{dialog:G,openCreateTaskDialog:g}=D(s),b=C??m,y=v??f,t=n.useCallback(o=>e=>window.dispatchEvent(new CustomEvent(`graph:${o}`,{detail:{teamName:s,taskId:e}})),[s]),A=n.useMemo(()=>({onStartTask:t("start-task"),onCompleteTask:t("complete-task"),onApproveTask:t("approve-task"),onRequestReview:t("request-review"),onRequestChanges:t("request-changes"),onCancelTask:t("cancel-task"),onMoveBackToDone:t("move-back-to-done"),onDeleteTask:t("delete-task")}),[t]),j=n.useCallback(()=>{k(),c()},[c,k]),H=n.useCallback(()=>{g("")},[g]),E={onNodeDoubleClick:n.useCallback(o=>{o.kind==="task"?i?.(o.taskId):o.kind==="member"&&d?.(o.memberName)},[i,d]),onSendMessage:n.useCallback(o=>u?.(o),[u]),onOpenTaskDetail:n.useCallback(o=>i?.(o),[i]),onOpenMemberProfile:n.useCallback(o=>d?.(o),[d])};return a.jsxs("div",{className:"fixed inset-0 z-50 flex overflow-hidden",style:{background:"#050510"},children:[b?a.jsx(P,{teamName:s,surface:"graph-overlay",isActive:!0,isFocused:!0}):null,a.jsx(W,{data:T,events:E,isSurfaceActive:!0,onRequestClose:c,onRequestPinAsTab:h,onOpenTeamPage:j,onCreateTask:H,onToggleSidebar:y,isSidebarVisible:b,renderTopToolbarContent:()=>a.jsx(B,{teamName:s}),onLayoutModeChange:x,onOwnerSlotDrop:w,onOwnerGridOrderDrop:S,className:"team-graph-view min-w-0 flex-1",renderHud:o=>{const e=o,{getViewportSize:r,focusNodeIds:l,filters:p}=e;return a.jsxs(a.Fragment,{children:[a.jsx(z,{teamName:s,getTransientHandoffSnapshot:e.getTransientHandoffSnapshot,getCameraZoom:e.getCameraZoom,worldToScreen:e.worldToScreen,getNodeWorldPosition:e.getNodeWorldPosition,focusNodeIds:l,focusEdgeIds:e.focusEdgeIds??null}),a.jsx(O,{teamName:s,nodes:T.nodes,getActivityWorldRect:e.getActivityWorldRect,getCameraZoom:e.getCameraZoom,worldToScreen:e.worldToScreen,getNodeWorldPosition:e.getNodeWorldPosition,getViewportSize:r,focusNodeIds:l,enabled:p?.showActivity??!0,onOpenTaskDetail:i,onOpenMemberProfile:d})]})},renderEdgeOverlay:({edge:o,sourceNode:e,targetNode:r,onClose:l,onSelectNode:p})=>a.jsx(Z,{teamName:s,edge:o,sourceNode:e,targetNode:r,onClose:l,onSelectNode:p,onOpenTaskDetail:i}),renderOverlay:({node:o,onClose:e})=>a.jsx(I,{node:o,teamName:s,onClose:e,onSendMessage:r=>{u?.(r),e()},onCreateTask:g,onOpenTaskDetail:r=>{i?.(r),e()},onOpenMemberProfile:r=>{d?.(r),e()},...A})}),G]})};export{M as TeamGraphOverlay};
@@ -1 +1 @@
1
- import{e as v,c as O,g,k as P,h as p,j as w,l as c,m as A,n as x,t as N,o as E}from"./_baseUniq-BDBpSAHY.js";import{bf as b,aV as F,bg as M,bh as _,bi as $,bj as I,bk as B,bl as T,bm as y,bn as S}from"./index-CrOkTuIK.js";var G=/\s/;function H(n){for(var r=n.length;r--&&G.test(n.charAt(r)););return r}var L=/^\s+/;function R(n){return n&&n.slice(0,H(n)+1).replace(L,"")}var m=NaN,q=/^[-+]0x[0-9a-f]+$/i,z=/^0b[01]+$/i,C=/^0o[0-7]+$/i,K=parseInt;function W(n){if(typeof n=="number")return n;if(v(n))return m;if(b(n)){var r=typeof n.valueOf=="function"?n.valueOf():n;n=b(r)?r+"":r}if(typeof n!="string")return n===0?n:+n;n=R(n);var t=z.test(n);return t||C.test(n)?K(n.slice(2),t?2:8):q.test(n)?m:+n}var o=1/0,X=17976931348623157e292;function Y(n){if(!n)return n===0?n:0;if(n=W(n),n===o||n===-o){var r=n<0?-1:1;return r*X}return n===n?n:0}function D(n){var r=Y(n),t=r%1;return r===r?t?r-t:r:0}function fn(n){var r=n==null?0:n.length;return r?O(n):[]}var l=Object.prototype,J=l.hasOwnProperty,dn=F(function(n,r){n=Object(n);var t=-1,a=r.length,e=a>2?r[2]:void 0;for(e&&M(r[0],r[1],e)&&(a=1);++t<a;)for(var f=r[t],i=_(f),s=-1,d=i.length;++s<d;){var u=i[s],h=n[u];(h===void 0||$(h,l[u])&&!J.call(n,u))&&(n[u]=f[u])}return n});function un(n){var r=n==null?0:n.length;return r?n[r-1]:void 0}function Q(n){return function(r,t,a){var e=Object(r);if(!I(r)){var f=g(t);r=P(r),t=function(s){return f(e[s],s,e)}}var i=n(r,t,a);return i>-1?e[f?r[i]:i]:void 0}}var U=Math.max;function Z(n,r,t){var a=n==null?0:n.length;if(!a)return-1;var e=t==null?0:D(t);return e<0&&(e=U(a+e,0)),p(n,g(r),e)}var hn=Q(Z);function V(n,r){var t=-1,a=I(n)?Array(n.length):[];return w(n,function(e,f,i){a[++t]=r(e,f,i)}),a}function bn(n,r){var t=B(n)?c:V;return t(n,g(r))}var j=Object.prototype,k=j.hasOwnProperty;function nn(n,r){return n!=null&&k.call(n,r)}function gn(n,r){return n!=null&&A(n,r,nn)}function rn(n,r){return n<r}function tn(n,r,t){for(var a=-1,e=n.length;++a<e;){var f=n[a],i=r(f);if(i!=null&&(s===void 0?i===i&&!v(i):t(i,s)))var s=i,d=f}return d}function mn(n){return n&&n.length?tn(n,T,rn):void 0}function en(n,r,t,a){if(!b(n))return n;r=x(r,n);for(var e=-1,f=r.length,i=f-1,s=n;s!=null&&++e<f;){var d=N(r[e]),u=t;if(d==="__proto__"||d==="constructor"||d==="prototype")return n;if(e!=i){var h=s[d];u=void 0,u===void 0&&(u=b(h)?h:y(r[e+1])?[]:{})}S(s,d,u),s=s[d]}return n}function on(n,r,t){for(var a=-1,e=r.length,f={};++a<e;){var i=r[a],s=E(n,i);t(s,i)&&en(f,x(i,n),s)}return f}export{rn as a,tn as b,V as c,on as d,mn as e,fn as f,hn as g,gn as h,dn as i,D as j,un as l,bn as m,Y as t};
1
+ import{e as v,c as O,g,k as P,h as p,j as w,l as c,m as A,n as x,t as N,o as E}from"./_baseUniq-BBLBOeXc.js";import{bf as b,aV as F,bg as M,bh as _,bi as $,bj as I,bk as B,bl as T,bm as y,bn as S}from"./index-DYdseEwc.js";var G=/\s/;function H(n){for(var r=n.length;r--&&G.test(n.charAt(r)););return r}var L=/^\s+/;function R(n){return n&&n.slice(0,H(n)+1).replace(L,"")}var m=NaN,q=/^[-+]0x[0-9a-f]+$/i,z=/^0b[01]+$/i,C=/^0o[0-7]+$/i,K=parseInt;function W(n){if(typeof n=="number")return n;if(v(n))return m;if(b(n)){var r=typeof n.valueOf=="function"?n.valueOf():n;n=b(r)?r+"":r}if(typeof n!="string")return n===0?n:+n;n=R(n);var t=z.test(n);return t||C.test(n)?K(n.slice(2),t?2:8):q.test(n)?m:+n}var o=1/0,X=17976931348623157e292;function Y(n){if(!n)return n===0?n:0;if(n=W(n),n===o||n===-o){var r=n<0?-1:1;return r*X}return n===n?n:0}function D(n){var r=Y(n),t=r%1;return r===r?t?r-t:r:0}function fn(n){var r=n==null?0:n.length;return r?O(n):[]}var l=Object.prototype,J=l.hasOwnProperty,dn=F(function(n,r){n=Object(n);var t=-1,a=r.length,e=a>2?r[2]:void 0;for(e&&M(r[0],r[1],e)&&(a=1);++t<a;)for(var f=r[t],i=_(f),s=-1,d=i.length;++s<d;){var u=i[s],h=n[u];(h===void 0||$(h,l[u])&&!J.call(n,u))&&(n[u]=f[u])}return n});function un(n){var r=n==null?0:n.length;return r?n[r-1]:void 0}function Q(n){return function(r,t,a){var e=Object(r);if(!I(r)){var f=g(t);r=P(r),t=function(s){return f(e[s],s,e)}}var i=n(r,t,a);return i>-1?e[f?r[i]:i]:void 0}}var U=Math.max;function Z(n,r,t){var a=n==null?0:n.length;if(!a)return-1;var e=t==null?0:D(t);return e<0&&(e=U(a+e,0)),p(n,g(r),e)}var hn=Q(Z);function V(n,r){var t=-1,a=I(n)?Array(n.length):[];return w(n,function(e,f,i){a[++t]=r(e,f,i)}),a}function bn(n,r){var t=B(n)?c:V;return t(n,g(r))}var j=Object.prototype,k=j.hasOwnProperty;function nn(n,r){return n!=null&&k.call(n,r)}function gn(n,r){return n!=null&&A(n,r,nn)}function rn(n,r){return n<r}function tn(n,r,t){for(var a=-1,e=n.length;++a<e;){var f=n[a],i=r(f);if(i!=null&&(s===void 0?i===i&&!v(i):t(i,s)))var s=i,d=f}return d}function mn(n){return n&&n.length?tn(n,T,rn):void 0}function en(n,r,t,a){if(!b(n))return n;r=x(r,n);for(var e=-1,f=r.length,i=f-1,s=n;s!=null&&++e<f;){var d=N(r[e]),u=t;if(d==="__proto__"||d==="constructor"||d==="prototype")return n;if(e!=i){var h=s[d];u=void 0,u===void 0&&(u=b(h)?h:y(r[e+1])?[]:{})}S(s,d,u),s=s[d]}return n}function on(n,r,t){for(var a=-1,e=r.length,f={};++a<e;){var i=r[a],s=E(n,i);t(s,i)&&en(f,x(i,n),s)}return f}export{rn as a,tn as b,V as c,on as d,mn as e,fn as f,hn as g,gn as h,dn as i,D as j,un as l,bn as m,Y as t};