@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.
- package/README.md +127 -77
- package/bin/hermit.mjs +151 -62
- package/dist-renderer/assets/{ProjectEditorOverlay-CZ1LI0pd.js → ProjectEditorOverlay-BBwYdXPv.js} +1 -1
- package/dist-renderer/assets/{TeamGraphOverlay-DvyxOPvU.js → TeamGraphOverlay-DVq8rt6_.js} +1 -1
- package/dist-renderer/assets/{_basePickBy-D8IKEBh4.js → _basePickBy-ZbF0pKvS.js} +1 -1
- package/dist-renderer/assets/{_baseUniq-BDBpSAHY.js → _baseUniq-BBLBOeXc.js} +1 -1
- package/dist-renderer/assets/{arc-CZagJLek.js → arc-wGaEgkCf.js} +1 -1
- package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-Cq083Uu6.js → architectureDiagram-VXUJARFQ-BpMkdC35.js} +1 -1
- package/dist-renderer/assets/{blockDiagram-VD42YOAC-CIEANvSv.js → blockDiagram-VD42YOAC-C8Z1xhG4.js} +1 -1
- package/dist-renderer/assets/{c4Diagram-YG6GDRKO-Ca4h_BlA.js → c4Diagram-YG6GDRKO-CJmlw9LA.js} +1 -1
- package/dist-renderer/assets/channel-DJUrwVrK.js +1 -0
- package/dist-renderer/assets/{chunk-4BX2VUAB-DW9HjNgA.js → chunk-4BX2VUAB-CHPHiRPP.js} +1 -1
- package/dist-renderer/assets/{chunk-55IACEB6-BddOEwBk.js → chunk-55IACEB6-DyVohOQb.js} +1 -1
- package/dist-renderer/assets/{chunk-B4BG7PRW-Cmu8IjLN.js → chunk-B4BG7PRW-p5bffh_R.js} +1 -1
- package/dist-renderer/assets/{chunk-DI55MBZ5-BU7nEH8e.js → chunk-DI55MBZ5-BnfGPSUu.js} +1 -1
- package/dist-renderer/assets/{chunk-FMBD7UC4-BZNeq0CB.js → chunk-FMBD7UC4-B6SCKseX.js} +1 -1
- package/dist-renderer/assets/{chunk-QN33PNHL-DMb3gYzN.js → chunk-QN33PNHL-L12RvLBR.js} +1 -1
- package/dist-renderer/assets/{chunk-QZHKN3VN-8wSSvqz0.js → chunk-QZHKN3VN-DeH1Kxge.js} +1 -1
- package/dist-renderer/assets/{chunk-TZMSLE5B-B4OLgw45.js → chunk-TZMSLE5B-BWnjzSlI.js} +1 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-blc3DrH7.js +1 -0
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-blc3DrH7.js +1 -0
- package/dist-renderer/assets/clone-BftjWakJ.js +1 -0
- package/dist-renderer/assets/{cose-bilkent-S5V4N54A-CS9moNeT.js → cose-bilkent-S5V4N54A-BtzoT5fu.js} +1 -1
- package/dist-renderer/assets/{dagre-6UL2VRFP-3pzdMwjZ.js → dagre-6UL2VRFP-CBBvuoUD.js} +1 -1
- package/dist-renderer/assets/{diagram-PSM6KHXK-CGTnMY5C.js → diagram-PSM6KHXK-Be9BAKws.js} +1 -1
- package/dist-renderer/assets/{diagram-QEK2KX5R-Cyzp8dOw.js → diagram-QEK2KX5R-BDS4PI_i.js} +1 -1
- package/dist-renderer/assets/{diagram-S2PKOQOG-D_5SvdXI.js → diagram-S2PKOQOG-2Rameaq7.js} +1 -1
- package/dist-renderer/assets/{erDiagram-Q2GNP2WA-bWPYfs9c.js → erDiagram-Q2GNP2WA-CSIzCEZD.js} +1 -1
- package/dist-renderer/assets/{flowDiagram-NV44I4VS-C5z47CKB.js → flowDiagram-NV44I4VS-ForEIVM5.js} +1 -1
- package/dist-renderer/assets/{ganttDiagram-JELNMOA3-eye9Cv6S.js → ganttDiagram-JELNMOA3-BJrli_xr.js} +1 -1
- package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-DekQZoF8.js → gitGraphDiagram-V2S2FVAM-C_4GuLno.js} +1 -1
- package/dist-renderer/assets/{graph-kNnl-9Fl.js → graph-B1EAT_gw.js} +1 -1
- package/dist-renderer/assets/index-CWpFqEvz.css +1 -0
- package/dist-renderer/assets/{index-hGBnMHVl.js → index-DOA_jbYb.js} +1 -1
- package/dist-renderer/assets/{index-ATiHUmmE.js → index-DR602dwJ.js} +1 -1
- package/dist-renderer/assets/{index-CrOkTuIK.js → index-DYdseEwc.js} +532 -532
- package/dist-renderer/assets/{index-CnxDIJh8.js → index-Dwr5wu5x.js} +1 -1
- package/dist-renderer/assets/{index-CI2l57ID.js → index-eKRmS5kI.js} +1 -1
- package/dist-renderer/assets/{index-DB0k9yRL.js → index-k4tnOFC5.js} +1 -1
- package/dist-renderer/assets/{infoDiagram-HS3SLOUP-D3ilrGOS.js → infoDiagram-HS3SLOUP-DjI0uaMz.js} +1 -1
- package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-BOCG2Rrk.js → journeyDiagram-XKPGCS4Q-jQ6Thae-.js} +1 -1
- package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-hZ03nCkx.js → kanban-definition-3W4ZIXB7-CKw6InbL.js} +1 -1
- package/dist-renderer/assets/{layout-D5Mqy2My.js → layout-Dad20y3V.js} +1 -1
- package/dist-renderer/assets/{linear-Clp9OpXU.js → linear-vMgo_2Cv.js} +1 -1
- package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-D-w-qhNz.js → mindmap-definition-VGOIOE7T-DYp6YoHL.js} +1 -1
- package/dist-renderer/assets/{pieDiagram-ADFJNKIX-D9K0-ecY.js → pieDiagram-ADFJNKIX-BytBecG9.js} +1 -1
- package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-B2f19Ki3.js → quadrantDiagram-AYHSOK5B-RUaspLsc.js} +1 -1
- package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-VezNpCaU.js → requirementDiagram-UZGBJVZJ-rR2B1Use.js} +1 -1
- package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-BpHjEoR9.js → sankeyDiagram-TZEHDZUN-BJi5qYhq.js} +1 -1
- package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-Tdb7IZ4t.js → sequenceDiagram-WL72ISMW-BM-wggUb.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-BNA5Q-zz.js → stateDiagram-FKZM4ZOC-BqmcVjnj.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-v2-4FDKWEC3-w_4GEN2a.js → stateDiagram-v2-4FDKWEC3-By3JDVbB.js} +1 -1
- package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BghtWMWY.js → timeline-definition-IT6M3QCI-szH0GUyk.js} +1 -1
- package/dist-renderer/assets/{treemap-GDKQZRPO-BVquWjHf.js → treemap-GDKQZRPO-BCMlh-Ex.js} +1 -1
- package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-BSV5wEDU.js → xychartDiagram-PRI3JC2R-dwDpvw0w.js} +1 -1
- package/dist-renderer/index.html +2 -2
- package/package.json +2 -2
- package/src/main/server.ts +52 -12
- package/src/renderer/api/httpClient.ts +1 -1
- package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +2 -0
- package/src/renderer/components/settings/sections/AdvancedSection.tsx +2 -0
- package/src/renderer/components/settings/sections/CliStatusSection.tsx +2 -0
- package/src/renderer/components/settings/sections/HarnessSection.tsx +11 -0
- package/src/renderer/components/settings/sections/PlatformsSection.tsx +10 -2
- package/src/renderer/components/team/TeamDetailView.tsx +53 -42
- package/src/renderer/components/team/TeamListView.tsx +54 -31
- package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +123 -0
- package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +98 -2
- package/src/renderer/utils/openHermitEvents.ts +9 -0
- package/src/shared/types/team.ts +5 -0
- package/dist-renderer/assets/channel-CqQK8EX1.js +0 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-9A3Cg8IA.js +0 -1
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-9A3Cg8IA.js +0 -1
- package/dist-renderer/assets/clone-Bnr-WjeU.js +0 -1
- 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="
|
|
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
|
|
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
|
-
|
|
22
|
+
---
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
让大模型扮演“资深前端”或“产品经理”,本质上是在模仿人类的**职责驱动**(因岗设人)。这注定会走向死锁——因为人类有精力上限和认知边界,才需要划分部门和扯皮;而 AI 没有。
|
|
24
|
+
## 为什么需要 openHermit?
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
目前的 AI Agent 赛道充满了一个巨大误区:**大家都在试图用人类的"HR 组织架构"来管理 AI。**
|
|
27
|
+
让大模型扮演"资深前端"或"产品经理",本质上是在模仿人类的**职责驱动**(因岗设人)。这注定会走向死锁——因为人类有精力上限和认知边界,才需要划分部门和扯皮;而 AI 没有。
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
**OPC(One Person Company)** 不再是一个浪漫的口号,而是最具杠杆率的商业形态。
|
|
28
|
-
你不需要招聘、不需要对齐价值观、不需要处理情绪内耗。你是唯一的决策者,AI 是绝对服从的执行网格。openHermit 为你提供 **TPC(Team · Process · Channel)** 协作结构,将产品、开发、测试、运营转化为可并发现程。你的每一次业务跑通,都是在积累固化的“数字资产”,而不是随员工离职而流失的经验。
|
|
29
|
+
**openHermit 的核心哲学:用管理机器的方式管理 Agent,而不是用管理人的方式。**
|
|
29
30
|
|
|
30
|
-
|
|
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
|
-
##
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
##
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
|
57
|
-
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
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
|
-
###
|
|
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
|
-
|
|
99
|
-
openhermit --daemon
|
|
100
|
-
openhermit status
|
|
101
|
-
openhermit stop
|
|
102
|
-
openhermit --port 8080
|
|
103
|
-
openhermit --version
|
|
104
|
-
openhermit update
|
|
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
|
-
浏览器打开
|
|
119
|
-
|
|
120
|
-
开发模式默认连接本机运行时服务;生产 CLI 会优先使用 openHermit 管理的本地配置。
|
|
114
|
+
浏览器打开 [http://localhost:5174](http://localhost:5174),开发模式默认连接本机运行时。
|
|
121
115
|
|
|
122
116
|
### 创建第一个 AI 团队
|
|
123
117
|
|
|
124
|
-
1.
|
|
125
|
-
2.
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
|
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
|
|
368
|
-
return
|
|
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
|
|
419
|
-
const
|
|
420
|
-
if (!
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
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
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
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
|
-
|
|
491
|
-
|
|
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
|
-
|
|
496
|
-
|
|
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
|
-
|
|
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,
|
package/dist-renderer/assets/{ProjectEditorOverlay-CZ1LI0pd.js → ProjectEditorOverlay-BBwYdXPv.js}
RENAMED
|
@@ -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-
|
|
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-
|
|
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-
|
|
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};
|