bridgeflow 0.1.0__tar.gz

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 (30) hide show
  1. bridgeflow-0.1.0/PKG-INFO +174 -0
  2. bridgeflow-0.1.0/README.md +164 -0
  3. bridgeflow-0.1.0/pyproject.toml +26 -0
  4. bridgeflow-0.1.0/setup.cfg +4 -0
  5. bridgeflow-0.1.0/src/bridgeflow/__init__.py +3 -0
  6. bridgeflow-0.1.0/src/bridgeflow/binding.py +125 -0
  7. bridgeflow-0.1.0/src/bridgeflow/cli.py +304 -0
  8. bridgeflow-0.1.0/src/bridgeflow/config.py +262 -0
  9. bridgeflow-0.1.0/src/bridgeflow/desktop/__init__.py +1 -0
  10. bridgeflow-0.1.0/src/bridgeflow/desktop/cursor_probe.py +145 -0
  11. bridgeflow-0.1.0/src/bridgeflow/desktop/executor.py +155 -0
  12. bridgeflow-0.1.0/src/bridgeflow/desktop/patrol.py +82 -0
  13. bridgeflow-0.1.0/src/bridgeflow/desktop/runner.py +413 -0
  14. bridgeflow-0.1.0/src/bridgeflow/desktop/status_store.py +177 -0
  15. bridgeflow-0.1.0/src/bridgeflow/desktop/window_control.py +78 -0
  16. bridgeflow-0.1.0/src/bridgeflow/file_protocol.py +167 -0
  17. bridgeflow-0.1.0/src/bridgeflow/file_watcher.py +47 -0
  18. bridgeflow-0.1.0/src/bridgeflow/human_admin/__init__.py +1 -0
  19. bridgeflow-0.1.0/src/bridgeflow/human_admin/bridge.py +8 -0
  20. bridgeflow-0.1.0/src/bridgeflow/models/__init__.py +1 -0
  21. bridgeflow-0.1.0/src/bridgeflow/models/events.py +19 -0
  22. bridgeflow-0.1.0/src/bridgeflow/relay_client/__init__.py +1 -0
  23. bridgeflow-0.1.0/src/bridgeflow/relay_client/ws_client.py +30 -0
  24. bridgeflow-0.1.0/src/bridgeflow/task_writer.py +108 -0
  25. bridgeflow-0.1.0/src/bridgeflow.egg-info/PKG-INFO +174 -0
  26. bridgeflow-0.1.0/src/bridgeflow.egg-info/SOURCES.txt +28 -0
  27. bridgeflow-0.1.0/src/bridgeflow.egg-info/dependency_links.txt +1 -0
  28. bridgeflow-0.1.0/src/bridgeflow.egg-info/entry_points.txt +2 -0
  29. bridgeflow-0.1.0/src/bridgeflow.egg-info/requires.txt +1 -0
  30. bridgeflow-0.1.0/src/bridgeflow.egg-info/top_level.txt +1 -0
@@ -0,0 +1,174 @@
1
+ Metadata-Version: 2.4
2
+ Name: bridgeflow
3
+ Version: 0.1.0
4
+ Summary: BridgeFlow 人机协作桥接与团队巡检工具
5
+ Author: joinwell52-AI
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: websockets<16,>=12
10
+
11
+ # BridgeFlow
12
+
13
+ `BridgeFlow` 是一个面向多 Agent 团队协作场景的人机桥接与轻量巡检工具。
14
+
15
+ 第一阶段目标不是“远程操控电脑”,而是把真人成员 `ADMIN01` 正式纳入团队协议:
16
+
17
+ - 手机端通过 PWA 发送文本
18
+ - 桌面端收到文本后落成标准任务文件
19
+ - `PM01` 按既有 `TASK-*.md` 协议接单
20
+ - `PM01` 或团队给 `ADMIN01` 的回复,也通过标准文本文件回流
21
+
22
+ 这样,手机端看到的不是一套独立聊天记录,而是按时间展开的一条条项目文本文件。
23
+
24
+ ## 第一阶段能力
25
+
26
+ - Python 包与 CLI 入口
27
+ - `ADMIN01 -> PM01` 任务文件生成
28
+ - `PM01/DEV01/OPS01/QA01 -> ADMIN01` 回复文件识别与摘要推送
29
+ - WebSocket 轻量中继
30
+ - GitHub Pages 可托管的手机 PWA 静态页
31
+ - `bridgeflow_config.json` 配置化
32
+
33
+ ## 架构
34
+
35
+ ```mermaid
36
+ flowchart LR
37
+ adminPwa[AdminPWA]
38
+ relayServer[RelayServer]
39
+ desktopBridge[DesktopBridge]
40
+ taskFiles[TaskFiles]
41
+ replyFiles[ReplyFiles]
42
+ pmAgent[PMAgent]
43
+
44
+ adminPwa -->|"文本消息"| relayServer
45
+ relayServer -->|"JSON事件"| desktopBridge
46
+ desktopBridge -->|"写 TASK-*-ADMIN01-to-PM01.md"| taskFiles
47
+ pmAgent -->|"处理任务"| taskFiles
48
+ pmAgent -->|"写 TASK-*-PM01-to-ADMIN01.md"| replyFiles
49
+ desktopBridge -->|"扫描回复并推送摘要"| relayServer
50
+ relayServer -->|"状态/回执/链接"| adminPwa
51
+ ```
52
+
53
+ ## 目录结构
54
+
55
+ ```text
56
+ BridgeFlow/
57
+ ├── .cursor/
58
+ │ └── rules/
59
+ │ └── admin-human-bridge.mdc
60
+ ├── pyproject.toml
61
+ ├── README.md
62
+ ├── docs/
63
+ │ ├── 产品设计说明.md
64
+ │ └── agents/
65
+ │ ├── README.md
66
+ │ └── ADMIN-01.md
67
+ ├── examples/
68
+ │ └── bridgeflow_config.json
69
+ ├── server/
70
+ │ └── relay/
71
+ │ └── server.py
72
+ ├── src/
73
+ │ └── bridgeflow/
74
+ │ ├── cli.py
75
+ │ ├── config.py
76
+ │ ├── file_protocol.py
77
+ │ ├── task_writer.py
78
+ │ ├── relay_client/
79
+ │ │ └── ws_client.py
80
+ │ ├── desktop/
81
+ │ │ └── runner.py
82
+ │ └── models/
83
+ │ └── events.py
84
+ └── web/
85
+ └── pwa/
86
+ └── index.html
87
+ ```
88
+
89
+ ## Agent 文件结构
90
+
91
+ `BridgeFlow` 第一阶段已经内置一套最小 `agent_bridge` 协议骨架:
92
+
93
+ - [docs/agents/README.md](docs/agents/README.md)
94
+ - [docs/agents/ADMIN-01.md](docs/agents/ADMIN-01.md)
95
+ - [docs/联调启动说明.md](docs/联调启动说明.md)
96
+ - [.cursor/rules/admin-human-bridge.mdc](.cursor/rules/admin-human-bridge.mdc)
97
+
98
+ 作用分别是:
99
+
100
+ - `README.md`:说明 `docs/agents/` 的目录结构和文件协议
101
+ - `ADMIN-01.md`:定义真人角色 `ADMIN01` 的职责和边界
102
+ - `admin-human-bridge.mdc`:给桥接逻辑或后续会话一个明确规则,要求“每条手机文本都必须落成任务文件”
103
+
104
+ ## 核心原则
105
+
106
+ - 手机端只处理文本文件,不碰 Cursor 窗口
107
+ - PC 端负责团队内部巡检与文件桥接
108
+ - 中继只传文本与链接,不传大文件
109
+ - 发送与回复都必须文件化,避免形成第二套协议
110
+ - 角色与显示名分离,后续支持 `PM/CTO` 等别名
111
+
112
+ ## 中继边界
113
+
114
+ - 默认接口端口:`5252`
115
+ - 仅转发文本 JSON 事件
116
+ - 不落盘、不执行、不上传文件
117
+ - 单条消息限制 `8KB`
118
+ - 默认频率限制:`10 秒内最多 20 条`
119
+ - 公网入口示例:`wss://relay.example.com/bridgeflow/ws/`
120
+
121
+ 公开发布建议:
122
+
123
+ - 不要把真实生产 `wss` 地址写死到默认配置
124
+ - `room_key` 建议改成随机值,不要继续使用演示房间
125
+ - 生产环境建议通过配置文件或环境变量覆盖示例值
126
+
127
+ ## 本地开发
128
+
129
+ ```powershell
130
+ cd BridgeFlow
131
+ py -3.10 -m venv .venv
132
+ .\.venv\Scripts\Activate.ps1
133
+ python -m pip install -U pip
134
+ python -m pip install -e .
135
+ ```
136
+
137
+ ## 主要命令
138
+
139
+ ```powershell
140
+ bridgeflow init
141
+ bridgeflow write-admin-task --text "请 PM 帮我安排下一步任务"
142
+ bridgeflow write-reply --sender PM01 --text "已接单,开始拆解任务" --thread-key "demo-thread-001"
143
+ bridgeflow relay-connect
144
+ bridgeflow run
145
+ ```
146
+
147
+ 示例配置建议:
148
+
149
+ - 本地联调可使用 `ws://127.0.0.1:5252`
150
+ - 公开示例中的 `room_key` 请替换成你自己的随机房间名
151
+ - PWA 默认配置建议使用示例中继地址,发布时再按部署环境覆盖
152
+
153
+ ## 第一阶段联调顺序
154
+
155
+ 1. 启动 `server/relay/server.py`
156
+ 2. 运行 `bridgeflow init`
157
+ 3. 运行 `bridgeflow run`
158
+ 4. 打开 `web/pwa/index.html` 本地预览或发布到 GitHub Pages
159
+ 5. 在手机端输入文本,验证桌面端是否生成 `TASK-*-ADMIN01-to-PM01.md`
160
+ 6. 运行 `bridgeflow write-reply --sender PM01 --text "已接单"`,验证手机端是否收到回复摘要
161
+
162
+ ## 后续扩展
163
+
164
+ - 对接现有 `ops/auto_patrol.py` 的窗口巡检逻辑
165
+ - 把当前基础 `thread_key` 能力升级成完整会话线程 UI
166
+ - 增加 OSS 链接分享与图片附件
167
+ - 加入 `room_key` 和更严格的中继鉴权
168
+
169
+ ## 命名约定
170
+
171
+ - 应用名:`BridgeFlow`
172
+ - 文件协作协议:`agent_bridge`
173
+ - Python 包名:`bridgeflow`
174
+ - CLI 命令:`bridgeflow`
@@ -0,0 +1,164 @@
1
+ # BridgeFlow
2
+
3
+ `BridgeFlow` 是一个面向多 Agent 团队协作场景的人机桥接与轻量巡检工具。
4
+
5
+ 第一阶段目标不是“远程操控电脑”,而是把真人成员 `ADMIN01` 正式纳入团队协议:
6
+
7
+ - 手机端通过 PWA 发送文本
8
+ - 桌面端收到文本后落成标准任务文件
9
+ - `PM01` 按既有 `TASK-*.md` 协议接单
10
+ - `PM01` 或团队给 `ADMIN01` 的回复,也通过标准文本文件回流
11
+
12
+ 这样,手机端看到的不是一套独立聊天记录,而是按时间展开的一条条项目文本文件。
13
+
14
+ ## 第一阶段能力
15
+
16
+ - Python 包与 CLI 入口
17
+ - `ADMIN01 -> PM01` 任务文件生成
18
+ - `PM01/DEV01/OPS01/QA01 -> ADMIN01` 回复文件识别与摘要推送
19
+ - WebSocket 轻量中继
20
+ - GitHub Pages 可托管的手机 PWA 静态页
21
+ - `bridgeflow_config.json` 配置化
22
+
23
+ ## 架构
24
+
25
+ ```mermaid
26
+ flowchart LR
27
+ adminPwa[AdminPWA]
28
+ relayServer[RelayServer]
29
+ desktopBridge[DesktopBridge]
30
+ taskFiles[TaskFiles]
31
+ replyFiles[ReplyFiles]
32
+ pmAgent[PMAgent]
33
+
34
+ adminPwa -->|"文本消息"| relayServer
35
+ relayServer -->|"JSON事件"| desktopBridge
36
+ desktopBridge -->|"写 TASK-*-ADMIN01-to-PM01.md"| taskFiles
37
+ pmAgent -->|"处理任务"| taskFiles
38
+ pmAgent -->|"写 TASK-*-PM01-to-ADMIN01.md"| replyFiles
39
+ desktopBridge -->|"扫描回复并推送摘要"| relayServer
40
+ relayServer -->|"状态/回执/链接"| adminPwa
41
+ ```
42
+
43
+ ## 目录结构
44
+
45
+ ```text
46
+ BridgeFlow/
47
+ ├── .cursor/
48
+ │ └── rules/
49
+ │ └── admin-human-bridge.mdc
50
+ ├── pyproject.toml
51
+ ├── README.md
52
+ ├── docs/
53
+ │ ├── 产品设计说明.md
54
+ │ └── agents/
55
+ │ ├── README.md
56
+ │ └── ADMIN-01.md
57
+ ├── examples/
58
+ │ └── bridgeflow_config.json
59
+ ├── server/
60
+ │ └── relay/
61
+ │ └── server.py
62
+ ├── src/
63
+ │ └── bridgeflow/
64
+ │ ├── cli.py
65
+ │ ├── config.py
66
+ │ ├── file_protocol.py
67
+ │ ├── task_writer.py
68
+ │ ├── relay_client/
69
+ │ │ └── ws_client.py
70
+ │ ├── desktop/
71
+ │ │ └── runner.py
72
+ │ └── models/
73
+ │ └── events.py
74
+ └── web/
75
+ └── pwa/
76
+ └── index.html
77
+ ```
78
+
79
+ ## Agent 文件结构
80
+
81
+ `BridgeFlow` 第一阶段已经内置一套最小 `agent_bridge` 协议骨架:
82
+
83
+ - [docs/agents/README.md](docs/agents/README.md)
84
+ - [docs/agents/ADMIN-01.md](docs/agents/ADMIN-01.md)
85
+ - [docs/联调启动说明.md](docs/联调启动说明.md)
86
+ - [.cursor/rules/admin-human-bridge.mdc](.cursor/rules/admin-human-bridge.mdc)
87
+
88
+ 作用分别是:
89
+
90
+ - `README.md`:说明 `docs/agents/` 的目录结构和文件协议
91
+ - `ADMIN-01.md`:定义真人角色 `ADMIN01` 的职责和边界
92
+ - `admin-human-bridge.mdc`:给桥接逻辑或后续会话一个明确规则,要求“每条手机文本都必须落成任务文件”
93
+
94
+ ## 核心原则
95
+
96
+ - 手机端只处理文本文件,不碰 Cursor 窗口
97
+ - PC 端负责团队内部巡检与文件桥接
98
+ - 中继只传文本与链接,不传大文件
99
+ - 发送与回复都必须文件化,避免形成第二套协议
100
+ - 角色与显示名分离,后续支持 `PM/CTO` 等别名
101
+
102
+ ## 中继边界
103
+
104
+ - 默认接口端口:`5252`
105
+ - 仅转发文本 JSON 事件
106
+ - 不落盘、不执行、不上传文件
107
+ - 单条消息限制 `8KB`
108
+ - 默认频率限制:`10 秒内最多 20 条`
109
+ - 公网入口示例:`wss://relay.example.com/bridgeflow/ws/`
110
+
111
+ 公开发布建议:
112
+
113
+ - 不要把真实生产 `wss` 地址写死到默认配置
114
+ - `room_key` 建议改成随机值,不要继续使用演示房间
115
+ - 生产环境建议通过配置文件或环境变量覆盖示例值
116
+
117
+ ## 本地开发
118
+
119
+ ```powershell
120
+ cd BridgeFlow
121
+ py -3.10 -m venv .venv
122
+ .\.venv\Scripts\Activate.ps1
123
+ python -m pip install -U pip
124
+ python -m pip install -e .
125
+ ```
126
+
127
+ ## 主要命令
128
+
129
+ ```powershell
130
+ bridgeflow init
131
+ bridgeflow write-admin-task --text "请 PM 帮我安排下一步任务"
132
+ bridgeflow write-reply --sender PM01 --text "已接单,开始拆解任务" --thread-key "demo-thread-001"
133
+ bridgeflow relay-connect
134
+ bridgeflow run
135
+ ```
136
+
137
+ 示例配置建议:
138
+
139
+ - 本地联调可使用 `ws://127.0.0.1:5252`
140
+ - 公开示例中的 `room_key` 请替换成你自己的随机房间名
141
+ - PWA 默认配置建议使用示例中继地址,发布时再按部署环境覆盖
142
+
143
+ ## 第一阶段联调顺序
144
+
145
+ 1. 启动 `server/relay/server.py`
146
+ 2. 运行 `bridgeflow init`
147
+ 3. 运行 `bridgeflow run`
148
+ 4. 打开 `web/pwa/index.html` 本地预览或发布到 GitHub Pages
149
+ 5. 在手机端输入文本,验证桌面端是否生成 `TASK-*-ADMIN01-to-PM01.md`
150
+ 6. 运行 `bridgeflow write-reply --sender PM01 --text "已接单"`,验证手机端是否收到回复摘要
151
+
152
+ ## 后续扩展
153
+
154
+ - 对接现有 `ops/auto_patrol.py` 的窗口巡检逻辑
155
+ - 把当前基础 `thread_key` 能力升级成完整会话线程 UI
156
+ - 增加 OSS 链接分享与图片附件
157
+ - 加入 `room_key` 和更严格的中继鉴权
158
+
159
+ ## 命名约定
160
+
161
+ - 应用名:`BridgeFlow`
162
+ - 文件协作协议:`agent_bridge`
163
+ - Python 包名:`bridgeflow`
164
+ - CLI 命令:`bridgeflow`
@@ -0,0 +1,26 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "bridgeflow"
7
+ version = "0.1.0"
8
+ description = "BridgeFlow 人机协作桥接与团队巡检工具"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "joinwell52-AI" }
14
+ ]
15
+ dependencies = [
16
+ "websockets>=12,<16"
17
+ ]
18
+
19
+ [project.scripts]
20
+ bridgeflow = "bridgeflow.cli:main"
21
+
22
+ [tool.setuptools]
23
+ package-dir = { "" = "src" }
24
+
25
+ [tool.setuptools.packages.find]
26
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ __all__ = ["__version__"]
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,125 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime, timedelta
4
+ import secrets
5
+ import string
6
+
7
+ from bridgeflow.config import PatrolConfig
8
+
9
+
10
+ BIND_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
11
+
12
+
13
+ def _now() -> datetime:
14
+ return datetime.now()
15
+
16
+
17
+ def _fmt(dt: datetime) -> str:
18
+ return dt.strftime("%Y-%m-%d %H:%M:%S")
19
+
20
+
21
+ def _parse(value: str) -> datetime | None:
22
+ if not value:
23
+ return None
24
+ try:
25
+ return datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
26
+ except ValueError:
27
+ return None
28
+
29
+
30
+ def _new_code(length: int = 6) -> str:
31
+ return "".join(secrets.choice(BIND_ALPHABET) for _ in range(length))
32
+
33
+
34
+ def has_active_bind_code(config: PatrolConfig) -> bool:
35
+ if not config.pending_bind_code or not config.pending_bind_expires_at:
36
+ return False
37
+ expires_at = _parse(config.pending_bind_expires_at)
38
+ return expires_at is not None and expires_at >= _now()
39
+
40
+
41
+ def public_bind_state(config: PatrolConfig) -> dict:
42
+ return {
43
+ "status": config.bind_status,
44
+ "machine_code": config.machine_code,
45
+ "bound_mobile_device_id": config.bound_mobile_device_id,
46
+ "bound_mobile_device_name": config.bound_mobile_device_name,
47
+ "bound_at": config.bound_at,
48
+ "has_pending_code": has_active_bind_code(config),
49
+ "pending_bind_expires_at": config.pending_bind_expires_at if has_active_bind_code(config) else "",
50
+ "pending_mobile_device_id": config.pending_mobile_device_id,
51
+ "pending_mobile_device_name": config.pending_mobile_device_name,
52
+ "bind_code_ttl_seconds": config.bind_code_ttl_seconds,
53
+ }
54
+
55
+
56
+ def private_bind_state(config: PatrolConfig) -> dict:
57
+ data = public_bind_state(config)
58
+ data["pending_bind_code"] = config.pending_bind_code if has_active_bind_code(config) else ""
59
+ data["last_bind_code_issued_at"] = config.last_bind_code_issued_at
60
+ return data
61
+
62
+
63
+ def issue_bind_code(
64
+ config: PatrolConfig,
65
+ *,
66
+ mobile_device_id: str = "",
67
+ mobile_device_name: str = "",
68
+ ) -> dict:
69
+ now = _now()
70
+ code = _new_code()
71
+ expires_at = now + timedelta(seconds=config.bind_code_ttl_seconds)
72
+ config.update_bind(
73
+ status="pending",
74
+ pending_bind_code=code,
75
+ pending_bind_expires_at=_fmt(expires_at),
76
+ pending_mobile_device_id=mobile_device_id.strip(),
77
+ pending_mobile_device_name=mobile_device_name.strip(),
78
+ last_bind_code_issued_at=_fmt(now),
79
+ )
80
+ return private_bind_state(config)
81
+
82
+
83
+ def approve_bind(
84
+ config: PatrolConfig,
85
+ *,
86
+ bind_code: str,
87
+ mobile_device_id: str,
88
+ mobile_device_name: str,
89
+ ) -> dict:
90
+ bind_code = bind_code.strip().upper()
91
+ if not bind_code:
92
+ raise ValueError("绑定码不能为空")
93
+ if not mobile_device_id.strip():
94
+ raise ValueError("mobile_device_id 不能为空")
95
+ if not has_active_bind_code(config):
96
+ raise ValueError("当前没有可用的绑定码")
97
+ if bind_code != config.pending_bind_code.strip().upper():
98
+ raise ValueError("绑定码不正确")
99
+
100
+ now = _now()
101
+ config.update_bind(
102
+ status="bound",
103
+ bound_mobile_device_id=mobile_device_id.strip(),
104
+ bound_mobile_device_name=mobile_device_name.strip(),
105
+ bound_at=_fmt(now),
106
+ pending_bind_code="",
107
+ pending_bind_expires_at="",
108
+ pending_mobile_device_id="",
109
+ pending_mobile_device_name="",
110
+ )
111
+ return public_bind_state(config)
112
+
113
+
114
+ def clear_binding(config: PatrolConfig) -> dict:
115
+ config.update_bind(
116
+ status="unbound",
117
+ bound_mobile_device_id="",
118
+ bound_mobile_device_name="",
119
+ bound_at="",
120
+ pending_bind_code="",
121
+ pending_bind_expires_at="",
122
+ pending_mobile_device_id="",
123
+ pending_mobile_device_name="",
124
+ )
125
+ return public_bind_state(config)