codex-flow 2.1.13__py3-none-any.whl
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.
- codex_flow/__init__.py +28 -0
- codex_flow/__main__.py +9 -0
- codex_flow/cli.py +242 -0
- codex_flow/data/LICENSE +21 -0
- codex_flow/data/README.en.md +303 -0
- codex_flow/data/README.md +305 -0
- codex_flow/data/VERSION +1 -0
- codex_flow/data/apps/chatgpt-mcp/README.md +86 -0
- codex_flow/data/apps/chatgpt-mcp/__init__.py +1 -0
- codex_flow/data/apps/chatgpt-mcp/adapter.py +458 -0
- codex_flow/data/apps/chatgpt-mcp/server.py +358 -0
- codex_flow/data/apps/chatgpt-mcp/widget.html +927 -0
- codex_flow/data/apps/macos-overlay/README.en.md +121 -0
- codex_flow/data/apps/macos-overlay/README.md +123 -0
- codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayRuntimeState.swift +126 -0
- codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayScreenGeometry.swift +82 -0
- codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayWindowController.swift +1052 -0
- codex_flow/data/apps/macos-overlay/Sources/Localization.swift +197 -0
- codex_flow/data/apps/macos-overlay/Sources/Models/TelemetryData.swift +1557 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/AccountSnapshotService.swift +1101 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/FlowPilotInstanceLock.swift +153 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/IPCServer.swift +298 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/TelemetryQueryEngine.swift +800 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/TelemetryWatcher.swift +135 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/UpdateService.swift +610 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/AccountView.swift +610 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/AnalyticsView.swift +566 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/AutostartView.swift +293 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/BubbleView.swift +317 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/HistoryView.swift +1124 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/HoverRevealText.swift +165 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/InspectorSkillsToolsView.swift +121 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/LogoView.swift +182 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/SleekSwitch.swift +117 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/StrategyModeView.swift +561 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/SummaryView.swift +1273 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/UpdateView.swift +352 -0
- codex_flow/data/apps/macos-overlay/Sources/main.swift +340 -0
- codex_flow/data/apps/macos-overlay/Tests/OverlayScreenGeometryTests.swift +163 -0
- codex_flow/data/apps/macos-overlay/Tests/TelemetryPhase1ContractTests.swift +357 -0
- codex_flow/data/apps/macos-overlay/Tests/TelemetryQueryEngineConcurrencyTests.swift +221 -0
- codex_flow/data/apps/macos-overlay/Tests/TelemetryQuotaSelectionTests.swift +158 -0
- codex_flow/data/apps/macos-overlay/Tests/TelemetryWorkerTokenTests.swift +122 -0
- codex_flow/data/apps/macos-overlay/build.sh +75 -0
- codex_flow/data/benchmark/corpus.json +103 -0
- codex_flow/data/benchmark/manifest.example.json +41 -0
- codex_flow/data/benchmark/manifest.schema.json +137 -0
- codex_flow/data/benchmark/prices/gpt-5.6-2026-08-30.json +5 -0
- codex_flow/data/benchmark/profiles.json +90 -0
- codex_flow/data/benchmark/schema.json +77 -0
- codex_flow/data/benchmark/tasks.json +50 -0
- codex_flow/data/completions/codex-flow.bash +34 -0
- codex_flow/data/completions/codex-flow.zsh +52 -0
- codex_flow/data/glama.json +6 -0
- codex_flow/data/install-release.ps1 +126 -0
- codex_flow/data/install-release.sh +155 -0
- codex_flow/data/install.ps1 +349 -0
- codex_flow/data/install.sh +362 -0
- codex_flow/data/policy/benchmark.toml +49 -0
- codex_flow/data/policy/defaults.toml +70 -0
- codex_flow/data/scripts/analyze-benchmark.py +510 -0
- codex_flow/data/scripts/benchmark-local.py +171 -0
- codex_flow/data/scripts/check-recommendation.py +277 -0
- codex_flow/data/scripts/doctor.py +449 -0
- codex_flow/data/scripts/generate-release-manifest.py +74 -0
- codex_flow/data/scripts/localization.py +192 -0
- codex_flow/data/scripts/manage-hooks.py +448 -0
- codex_flow/data/scripts/manage-instructions.py +389 -0
- codex_flow/data/scripts/manage-shell.py +151 -0
- codex_flow/data/scripts/materialize-corpus.py +193 -0
- codex_flow/data/scripts/menu.py +646 -0
- codex_flow/data/scripts/migrations/0001_update_settings.py +80 -0
- codex_flow/data/scripts/package-release.py +132 -0
- codex_flow/data/scripts/render-benchmark-report.py +292 -0
- codex_flow/data/scripts/run-benchmark.py +829 -0
- codex_flow/data/scripts/strategies/__init__.py +28 -0
- codex_flow/data/scripts/strategies/balanced.py +115 -0
- codex_flow/data/scripts/strategies/base.py +363 -0
- codex_flow/data/scripts/strategies/efficient.py +158 -0
- codex_flow/data/scripts/strategies/lifecycle_runtime.py +590 -0
- codex_flow/data/scripts/strategies/quality.py +209 -0
- codex_flow/data/scripts/strategies/speed.py +108 -0
- codex_flow/data/scripts/strategies/task_budget_runtime.py +644 -0
- codex_flow/data/scripts/strategies/task_phase_runtime.py +341 -0
- codex_flow/data/scripts/strategies/work_unit_runtime.py +421 -0
- codex_flow/data/scripts/strategy_runtime.py +1091 -0
- codex_flow/data/scripts/telemetry.py +400 -0
- codex_flow/data/scripts/telemetry_core/__init__.py +192 -0
- codex_flow/data/scripts/telemetry_core/app_server.py +1192 -0
- codex_flow/data/scripts/telemetry_core/collector.py +1247 -0
- codex_flow/data/scripts/telemetry_core/common.py +421 -0
- codex_flow/data/scripts/telemetry_core/latency.py +593 -0
- codex_flow/data/scripts/telemetry_core/query.py +427 -0
- codex_flow/data/scripts/telemetry_core/quota_ledger.py +598 -0
- codex_flow/data/scripts/telemetry_core/render.py +460 -0
- codex_flow/data/scripts/telemetry_core/repair.py +223 -0
- codex_flow/data/scripts/ui.py +266 -0
- codex_flow/data/scripts/update-homebrew-formula.py +146 -0
- codex_flow/data/scripts/update_runtime_config.py +134 -0
- codex_flow/data/scripts/updater.py +1718 -0
- codex_flow/data/smithery.yaml +18 -0
- codex_flow/data/templates/agents/worker-explorer.toml +24 -0
- codex_flow/data/templates/agents/worker-implementer.toml +49 -0
- codex_flow/data/templates/agents/worker-reviewer.toml +25 -0
- codex_flow/data/templates/flow-pilot-instructions.md +35 -0
- codex_flow/data/templates/skills/flow-pilot/SKILL.md +577 -0
- codex_flow/mcp.py +35 -0
- codex_flow-2.1.13.dist-info/METADATA +342 -0
- codex_flow-2.1.13.dist-info/RECORD +113 -0
- codex_flow-2.1.13.dist-info/WHEEL +5 -0
- codex_flow-2.1.13.dist-info/entry_points.txt +3 -0
- codex_flow-2.1.13.dist-info/licenses/LICENSE +21 -0
- codex_flow-2.1.13.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# macOS Native Floating Widget (FlowPilot Overlay)
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
[ 简体中文 ](README.md) | [ English ](README.en.md)
|
|
6
|
+
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
`codex-flow-overlay` is a 100% native macOS floating widget built with **SwiftUI + AppKit**, deeply integrating the entire suite of `codex-flow usage` capabilities (live inspection, rate-limit quota monitoring, multi-session history, and aggregate efficiency analytics).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<div align="center">
|
|
14
|
+
<img src="../../docs/assets/promo/flowpilot_promo_poster.png" alt="FlowPilot Native Overlay Showcase" width="100%" style="border-radius: 12px; margin: 12px 0;" />
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## ✨ Core Highlights
|
|
20
|
+
|
|
21
|
+
- 🟢 **Micro Capsule (Idle State)**:
|
|
22
|
+
- 68px diameter Frosted Glass bubble (macOS `ultraThinMaterial`);
|
|
23
|
+
- Dynamic rainbow gradient border with real-time breathing status aura;
|
|
24
|
+
- Status indicator (🟢 Idle/Complete · 🔵 Task Running · 🟠 Alert/Error);
|
|
25
|
+
- Live token badge displaying latest turn tokens (e.g. `198.2k`);
|
|
26
|
+
- Automatic half-tuck edge docking and magnetic screen snapping.
|
|
27
|
+
|
|
28
|
+
- ⚡️ **Glass TabBar Control Center (Expanded State)**:
|
|
29
|
+
- **⚡️ Inspector**:
|
|
30
|
+
- **Header**: Project tag, Git branch badge, status pill, Pin lock, and collapse button;
|
|
31
|
+
- **Objective & Outcome**: Auto-extracted task goal and delivery conclusion;
|
|
32
|
+
- **3 KPI Rings**: Real-time circular gauges for Duration, Tokens, and Cost;
|
|
33
|
+
- **Rate Limits & Quota**: 5m / 1h / 1d / 7d quota progression bars and reset countdowns;
|
|
34
|
+
- **Token Distribution Bar**: Stacked breakdown of Prompt, Cached, Output, and Reasoning tokens;
|
|
35
|
+
- **Multi-Agent Topology**: Parent model reasoning effort and Worker subagent concurrency;
|
|
36
|
+
- **Skills & MCP Badges**: Automatic discovery and badge labeling of activated skills and MCP tools;
|
|
37
|
+
- **Historical Drilldown**: Inspect any past task with one-click `[⚡️ Jump to Live]`;
|
|
38
|
+
- **Action Bar**: Copy formatted summary, open Terminal console, Pin lock toggle.
|
|
39
|
+
- **📜 History**:
|
|
40
|
+
- Project filter, `All` / `Today` scope, and instant keyword search;
|
|
41
|
+
- **Chat Accordion**: Aggregates multi-turn runs into chronological chat sessions;
|
|
42
|
+
- **Session Turns**: Turn-level timeline with duration, tokens, worker badges, and quota deltas (`+1%` / `-1%`);
|
|
43
|
+
- Click any turn to inspect full details in the Inspector.
|
|
44
|
+
- **📊 Analytics**:
|
|
45
|
+
- Aggregate efficiency analysis with `7 Days` / `30 Days` toggles;
|
|
46
|
+
- Total tasks (dispatched vs. direct), active hours, and total attributed tokens;
|
|
47
|
+
- **Cache Efficiency**: Hit percentage and cached tokens saved;
|
|
48
|
+
- **Worker Offload**: Percentage of workload delegated to economic models;
|
|
49
|
+
- **Model Breakdown**: Calls, token proportions, and Parent/Worker roles;
|
|
50
|
+
- **Projects Distribution**: Multi-repository activity rankings.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 🔒 Privacy & Demo Mode
|
|
55
|
+
|
|
56
|
+
FlowPilot includes built-in privacy protection (`isPrivacyMode`):
|
|
57
|
+
- All sensitive project names, prompt titles, task goals, and delivery conclusions are automatically frosted with smooth Gaussian blur filters (`blur(radius: 4.5)`).
|
|
58
|
+
- Ideal for public presentations, videos, and documentation screenshots.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 🚀 Quick Start
|
|
63
|
+
|
|
64
|
+
### 1. Build
|
|
65
|
+
```bash
|
|
66
|
+
bash apps/macos-overlay/build.sh
|
|
67
|
+
```
|
|
68
|
+
Binary output: `apps/macos-overlay/bin/FlowPilot`.
|
|
69
|
+
|
|
70
|
+
### 2. Launch Daemon
|
|
71
|
+
```bash
|
|
72
|
+
# Start background overlay widget
|
|
73
|
+
codex-flow overlay start
|
|
74
|
+
|
|
75
|
+
# Or run directly
|
|
76
|
+
./apps/macos-overlay/bin/FlowPilot start &
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3. CLI Commands
|
|
80
|
+
```bash
|
|
81
|
+
# Check status
|
|
82
|
+
codex-flow overlay status
|
|
83
|
+
|
|
84
|
+
# Toggle expand / collapse
|
|
85
|
+
codex-flow overlay toggle
|
|
86
|
+
codex-flow overlay expand
|
|
87
|
+
codex-flow overlay collapse
|
|
88
|
+
|
|
89
|
+
# Switch tabs
|
|
90
|
+
codex-flow overlay tab inspector
|
|
91
|
+
codex-flow overlay tab history
|
|
92
|
+
codex-flow overlay tab analytics
|
|
93
|
+
|
|
94
|
+
# Inspect historical task
|
|
95
|
+
codex-flow overlay show 1
|
|
96
|
+
|
|
97
|
+
# Open analytics or history directly
|
|
98
|
+
codex-flow overlay stats 30
|
|
99
|
+
codex-flow overlay history
|
|
100
|
+
|
|
101
|
+
# Update telemetry data
|
|
102
|
+
codex-flow overlay update
|
|
103
|
+
|
|
104
|
+
# Stop overlay
|
|
105
|
+
codex-flow overlay stop
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 🖱 Mouse & Keyboard Interactions
|
|
111
|
+
|
|
112
|
+
| Action | Result |
|
|
113
|
+
| :--- | :--- |
|
|
114
|
+
| **Hover on Capsule (0.4s)** | Spring animation expands into full Glass Card |
|
|
115
|
+
| **Mouse Leave (0.8s)** | Smoothly collapses back to Capsule (when unpinned) |
|
|
116
|
+
| **Click Capsule / Header** | Toggle expanded/collapsed state immediately |
|
|
117
|
+
| **Click Pin Icon (`📌`)** | Lock widget permanently open on top of all windows |
|
|
118
|
+
| **Drag Anywhere** | Smooth desktop repositioning with screen-edge magnetic snap |
|
|
119
|
+
| **Right-Click Context Menu**| Quick access to View Switcher, Pin, Refresh, Terminal, and Quit |
|
|
120
|
+
| **Click "Copy Summary"** | Copies formatted run card to system clipboard |
|
|
121
|
+
| **Click "Console"** | Opens `codex-flow` interactive management menu in Terminal |
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# macOS 原生悬浮窗 (Native Floating Widget)
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
[ 简体中文 ](README.md) | [ English ](README.en.md)
|
|
6
|
+
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
`codex-flow-overlay` 是专为 macOS 设计的 100% 纯原生(基于 **SwiftUI + AppKit** 构建)桌面悬浮窗组件,深度集成了 `codex-flow usage` 的全部核心能力(实时巡检、配额监控、历史回溯、聚合效能分析)。
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<div align="center">
|
|
14
|
+
<img src="../../docs/assets/promo/flowpilot_promo_poster.png" alt="FlowPilot Native Overlay Showcase" width="100%" style="border-radius: 12px; margin: 12px 0;" />
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## ✨ 核心特性
|
|
20
|
+
|
|
21
|
+
- 🟢 **默认形态(灵动微胶囊 Micro Capsule)**:
|
|
22
|
+
- 直径 68px 的 Frosted Glass 毛玻璃拟物圆环(macOS `ultraThinMaterial`);
|
|
23
|
+
- 外圈动态彩虹渐变边框与实时呼吸灯;
|
|
24
|
+
- 实时状态角标(🟢 空闲/完成 · 🔵 任务运行中 · 🟠 异常/告警);
|
|
25
|
+
- 底部微缩显示最近任务的 Token 消耗徽章(如 `198.2k`);
|
|
26
|
+
- 边缘自动半收起(Half-Tuck)与屏幕防溢出磁吸贴靠。
|
|
27
|
+
|
|
28
|
+
- ⚡️ **展开态(全功能 Glass TabBar 监控台)**:
|
|
29
|
+
- **⚡️ Inspector(任务巡检)**:
|
|
30
|
+
- **Header**:项目名标签、Git 分支胶囊、任务状态徽章、Pin 锁定按钮与折叠按钮;
|
|
31
|
+
- **任务目标与交付结论卡**:智能提炼展示会话目标与交付成果;
|
|
32
|
+
- **KPI Rings**:3 组高精环形仪表盘(Time 耗时、Tokens 消耗、Cost 费用估算);
|
|
33
|
+
- **Rate Limits & Quota**:5m / 1h / 1d / 7d 账户配额消耗百分比进度与重置倒计时;
|
|
34
|
+
- **Token 细分条**:多色堆叠胶囊条,直观呈现 Prompt、Output、Cached 与 Reasoning 思考 Token 分布;
|
|
35
|
+
- **多 Agent 路由拓扑**:展示 Parent Agent(模型与 Reasoning 强度)及各个 Worker Subagents 的独立用量与状态;
|
|
36
|
+
- **技能与 MCP 标签**:自动标注调用的 Skills 与 MCP Server 工具;
|
|
37
|
+
- **历史查看态导航**:支持回溯任意历史任务,提供一键 `[⚡️ 查看最新]` 返回实时任务;
|
|
38
|
+
- **操作底栏**:一键复制 Summary 剪贴板(带 Copied 动画反馈)、唤起终端控制台、Pin 锁定常驻。
|
|
39
|
+
- **📜 History(历史回溯)**:
|
|
40
|
+
- 多维历史会话:支持按工程过滤、`All` / `Today` 切换与实时关键词检索;
|
|
41
|
+
- **会话手风琴 (Chat Accordion)**:按会话聚合多轮任务,展示会话总 Token 与最大并发;
|
|
42
|
+
- **轮次流水线 (Session Turns)**:精确展开每一轮次的时间、耗时、Worker 标签与配额消耗差值(`+1%` / `-1%`);
|
|
43
|
+
- 点击任意历史任务条目即刻在 Inspector 中展开深度详情。
|
|
44
|
+
- **📊 Analytics(效能看板)**:
|
|
45
|
+
- 集成聚合效能分析,支持 `7 Days` / `30 Days` 周期切换;
|
|
46
|
+
- 汇总总任务数(委派 vs 直接)、总活跃时长、总 Token 消耗与费用预估;
|
|
47
|
+
- **Cache Efficiency**:缓存命中率与节省 Token 统计;
|
|
48
|
+
- **Worker Offload**:Worker 算力委派比例仪表;
|
|
49
|
+
- **Model Breakdown**:各模型调用次数、Token 占比与角色标签(Parent/Worker);
|
|
50
|
+
- **Projects Distribution**:多仓库/多项目活跃度排行。
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 🔒 隐私脱敏与演示模式
|
|
55
|
+
|
|
56
|
+
内置 `isPrivacyMode` 隐私保护:
|
|
57
|
+
- 所有敏感项目名、对话指令、任务目标与交付结论均自动采用平滑的高斯模糊滤镜(`blur(radius: 4.5)`)打码;
|
|
58
|
+
- 非常适合录屏演示、公开分享与制作文档插图。
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 🚀 快速使用
|
|
63
|
+
|
|
64
|
+
### 1. 编译构建
|
|
65
|
+
```bash
|
|
66
|
+
bash apps/macos-overlay/build.sh
|
|
67
|
+
```
|
|
68
|
+
编译产物位于 `apps/macos-overlay/bin/FlowPilot`。
|
|
69
|
+
|
|
70
|
+
### 2. 启动悬浮窗守护进程
|
|
71
|
+
```bash
|
|
72
|
+
# 启动后台常驻悬浮窗
|
|
73
|
+
codex-flow overlay start
|
|
74
|
+
# 或直接执行二进制
|
|
75
|
+
./apps/macos-overlay/bin/FlowPilot start &
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 3. CLI 控制指令
|
|
79
|
+
```bash
|
|
80
|
+
# 检查浮窗运行状态
|
|
81
|
+
codex-flow overlay status
|
|
82
|
+
|
|
83
|
+
# 切换展开 / 折叠
|
|
84
|
+
codex-flow overlay toggle
|
|
85
|
+
codex-flow overlay expand
|
|
86
|
+
codex-flow overlay collapse
|
|
87
|
+
|
|
88
|
+
# 切换视图选项卡
|
|
89
|
+
codex-flow overlay tab inspector
|
|
90
|
+
codex-flow overlay tab history
|
|
91
|
+
codex-flow overlay tab analytics
|
|
92
|
+
|
|
93
|
+
# 查看指定历史任务(支持 #1、#2 或 session_id)
|
|
94
|
+
codex-flow overlay show 1
|
|
95
|
+
|
|
96
|
+
# 打开统计看板(可指定天数)
|
|
97
|
+
codex-flow overlay stats 30
|
|
98
|
+
|
|
99
|
+
# 打开任务历史列表
|
|
100
|
+
codex-flow overlay history
|
|
101
|
+
|
|
102
|
+
# 推送并刷新最新 telemetry 运行数据
|
|
103
|
+
codex-flow overlay update
|
|
104
|
+
|
|
105
|
+
# 停止悬浮窗
|
|
106
|
+
codex-flow overlay stop
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 🖱 交互与快捷操作
|
|
112
|
+
|
|
113
|
+
| 动作 | 效果 |
|
|
114
|
+
|---|---|
|
|
115
|
+
| **光标移入气泡停留 0.4 秒** | 触发 Spring 弹性展开为 Telemetry 卡片 |
|
|
116
|
+
| **光标移出卡片区域** | 延迟 0.8 秒自动收起为圆形气泡(未 Pin 时) |
|
|
117
|
+
| **单击气泡 / 顶部折叠按钮** | 立即切换展开 / 收起状态 |
|
|
118
|
+
| **切换 Tab 选项卡** | 平滑切换 Inspector(任务详情)、History(任务列表)、Analytics(效能统计) |
|
|
119
|
+
| **点击 History 任务条目** | 立即在 Inspector 中回溯该任务的完整 Token、费用与配额明细 |
|
|
120
|
+
| **按住气泡拖拽** | 自由拖拽到屏幕任意角落(带边界贴靠保护) |
|
|
121
|
+
| **右键点击** | 弹出上下文菜单(Pin 锁定、折叠/展开、打开控制台、刷新、退出) |
|
|
122
|
+
| **点击「Copy Summary」** | 格式化复制任务摘要至系统剪贴板 |
|
|
123
|
+
| **点击「Console」** | 快速唤起终端打开 `codex-flow` 管理控制台 |
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import Cocoa
|
|
2
|
+
|
|
3
|
+
enum OverlayGeometryActivity: Equatable {
|
|
4
|
+
case presentation
|
|
5
|
+
case snap
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/// Small, deterministic state machine for the overlay's interaction/geometry
|
|
9
|
+
/// lifecycle. It deliberately knows nothing about NSWindow animation APIs.
|
|
10
|
+
///
|
|
11
|
+
/// Invariants:
|
|
12
|
+
/// - only one geometry activity may own the window at a time;
|
|
13
|
+
/// - pointer interaction is independent of animation completion;
|
|
14
|
+
/// - presentation updates requested during drag/animation are coalesced and
|
|
15
|
+
/// replayed once the current owner releases the window.
|
|
16
|
+
struct OverlayRuntimeState {
|
|
17
|
+
private(set) var activeGeometry: OverlayGeometryActivity?
|
|
18
|
+
private(set) var pointerInteractionActive = false
|
|
19
|
+
private(set) var pendingPresentationUpdate = false
|
|
20
|
+
|
|
21
|
+
var isGeometryTransitioning: Bool { activeGeometry != nil }
|
|
22
|
+
|
|
23
|
+
mutating func beginPointerInteraction() -> Bool {
|
|
24
|
+
guard activeGeometry == nil, !pointerInteractionActive else { return false }
|
|
25
|
+
pointerInteractionActive = true
|
|
26
|
+
return true
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
mutating func endPointerInteraction() {
|
|
30
|
+
pointerInteractionActive = false
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// Returns true when the caller owns the geometry immediately and should
|
|
34
|
+
/// start the presentation transition now. Otherwise the request is coalesced.
|
|
35
|
+
mutating func requestPresentationGeometry() -> Bool {
|
|
36
|
+
guard activeGeometry == nil, !pointerInteractionActive else {
|
|
37
|
+
pendingPresentationUpdate = true
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
activeGeometry = .presentation
|
|
41
|
+
return true
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Snap is only valid after the pointer has been released. A snap is never
|
|
45
|
+
/// queued behind another geometry owner because a drag cannot begin while
|
|
46
|
+
/// geometry is transitioning.
|
|
47
|
+
mutating func beginSnapGeometry() -> Bool {
|
|
48
|
+
guard activeGeometry == nil, !pointerInteractionActive else { return false }
|
|
49
|
+
activeGeometry = .snap
|
|
50
|
+
return true
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// Releases the current geometry owner. Returns true when a coalesced
|
|
54
|
+
/// presentation update has now acquired ownership and should be run next.
|
|
55
|
+
mutating func completeGeometry() -> Bool {
|
|
56
|
+
activeGeometry = nil
|
|
57
|
+
return claimPendingPresentationIfIdle()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// Used after a pointer interaction ends without a snap.
|
|
61
|
+
mutating func claimPendingPresentationIfIdle() -> Bool {
|
|
62
|
+
guard pendingPresentationUpdate,
|
|
63
|
+
activeGeometry == nil,
|
|
64
|
+
!pointerInteractionActive else { return false }
|
|
65
|
+
pendingPresentationUpdate = false
|
|
66
|
+
activeGeometry = .presentation
|
|
67
|
+
return true
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// Filters the rectangular 76x76 NSHostingView down to what the user can
|
|
72
|
+
/// actually see. This prevents the transparent host from behaving as a hover
|
|
73
|
+
/// target after the compact view changes shape.
|
|
74
|
+
enum OverlayCompactHitRegion {
|
|
75
|
+
static func contains(
|
|
76
|
+
_ point: NSPoint,
|
|
77
|
+
in hostBounds: NSRect,
|
|
78
|
+
expanded: Bool,
|
|
79
|
+
docked: Bool
|
|
80
|
+
) -> Bool {
|
|
81
|
+
guard hostBounds.contains(point) else { return false }
|
|
82
|
+
if expanded { return true }
|
|
83
|
+
|
|
84
|
+
if docked {
|
|
85
|
+
let pillSize = NSSize(width: 44, height: 56)
|
|
86
|
+
let pillRect = NSRect(
|
|
87
|
+
x: hostBounds.maxX - pillSize.width,
|
|
88
|
+
y: hostBounds.midY - pillSize.height / 2,
|
|
89
|
+
width: pillSize.width,
|
|
90
|
+
height: pillSize.height
|
|
91
|
+
)
|
|
92
|
+
return pillRect.contains(point)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let center = NSPoint(x: hostBounds.midX, y: hostBounds.midY)
|
|
96
|
+
let dx = point.x - center.x
|
|
97
|
+
let dy = point.y - center.y
|
|
98
|
+
let radius: CGFloat = 31 // 58pt circle + a small allowance for its glow.
|
|
99
|
+
return dx * dx + dy * dy <= radius * radius
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/// Synthetic AppKit tracking events may be emitted when a window resizes under
|
|
104
|
+
/// a stationary pointer. Require real pointer travel before hover behavior is
|
|
105
|
+
/// re-armed after a programmatic compacting/snap operation.
|
|
106
|
+
struct OverlayHoverGate {
|
|
107
|
+
private(set) var suppressedAt: NSPoint?
|
|
108
|
+
let rearmDistance: CGFloat
|
|
109
|
+
|
|
110
|
+
init(rearmDistance: CGFloat = 6) {
|
|
111
|
+
self.rearmDistance = rearmDistance
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
mutating func suppress(at point: NSPoint) {
|
|
115
|
+
suppressedAt = point
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
mutating func allowsHover(at point: NSPoint) -> Bool {
|
|
119
|
+
guard let anchor = suppressedAt else { return true }
|
|
120
|
+
let dx = point.x - anchor.x
|
|
121
|
+
let dy = point.y - anchor.y
|
|
122
|
+
guard dx * dx + dy * dy >= rearmDistance * rearmDistance else { return false }
|
|
123
|
+
suppressedAt = nil
|
|
124
|
+
return true
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import Cocoa
|
|
2
|
+
|
|
3
|
+
/// Pure screen-geometry selection used by the overlay window controller.
|
|
4
|
+
///
|
|
5
|
+
/// `NSWindow.screen` can be temporarily nil or point at a different display while
|
|
6
|
+
/// AppKit is animating/resizing a borderless panel. Geometry routing therefore
|
|
7
|
+
/// derives the destination display from global coordinates instead.
|
|
8
|
+
enum OverlayScreenGeometry {
|
|
9
|
+
static func bestVisibleFrame(for windowFrame: NSRect, among visibleFrames: [NSRect]) -> NSRect? {
|
|
10
|
+
guard !visibleFrames.isEmpty else { return nil }
|
|
11
|
+
|
|
12
|
+
let center = NSPoint(x: windowFrame.midX, y: windowFrame.midY)
|
|
13
|
+
if let containingCenter = visibleFrames.first(where: { $0.contains(center) }) {
|
|
14
|
+
return containingCenter
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
var bestIntersectionFrame: NSRect?
|
|
18
|
+
var bestIntersectionArea: CGFloat = 0
|
|
19
|
+
for candidate in visibleFrames {
|
|
20
|
+
let intersection = windowFrame.intersection(candidate)
|
|
21
|
+
guard !intersection.isNull, !intersection.isEmpty else { continue }
|
|
22
|
+
let area = intersection.width * intersection.height
|
|
23
|
+
if area > bestIntersectionArea {
|
|
24
|
+
bestIntersectionArea = area
|
|
25
|
+
bestIntersectionFrame = candidate
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if let bestIntersectionFrame {
|
|
29
|
+
return bestIntersectionFrame
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return visibleFrames.min {
|
|
33
|
+
distanceSquared(from: center, to: $0) < distanceSquared(from: center, to: $1)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// Presentation expand/collapse is anchored at the window's top-trailing
|
|
38
|
+
/// corner. A wide panel may straddle two displays while its top-trailing
|
|
39
|
+
/// anchor still clearly belongs to the display where the compact bubble
|
|
40
|
+
/// lives. Using the panel center here can move the bubble to the neighbor.
|
|
41
|
+
static func presentationVisibleFrame(for windowFrame: NSRect, among visibleFrames: [NSRect]) -> NSRect? {
|
|
42
|
+
guard !visibleFrames.isEmpty else { return nil }
|
|
43
|
+
let anchor = topTrailingAnchor(for: windowFrame)
|
|
44
|
+
return visibleFrame(containing: anchor, among: visibleFrames)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static func topTrailingAnchor(for frame: NSRect, inset: CGFloat = 1) -> NSPoint {
|
|
48
|
+
NSPoint(
|
|
49
|
+
x: max(frame.minX, frame.maxX - inset),
|
|
50
|
+
y: max(frame.minY, frame.maxY - inset)
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static func visibleFrame(containing point: NSPoint, among visibleFrames: [NSRect]) -> NSRect? {
|
|
55
|
+
guard !visibleFrames.isEmpty else { return nil }
|
|
56
|
+
if let containing = visibleFrames.first(where: { $0.contains(point) }) {
|
|
57
|
+
return containing
|
|
58
|
+
}
|
|
59
|
+
return visibleFrames.min {
|
|
60
|
+
distanceSquared(from: point, to: $0) < distanceSquared(from: point, to: $1)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static func clamp(_ origin: NSPoint, windowSize: NSSize, to visibleFrame: NSRect, margin: CGFloat = 0) -> NSPoint {
|
|
65
|
+
let minX = visibleFrame.minX + margin
|
|
66
|
+
let maxX = visibleFrame.maxX - windowSize.width - margin
|
|
67
|
+
let minY = visibleFrame.minY + margin
|
|
68
|
+
let maxY = visibleFrame.maxY - windowSize.height - margin
|
|
69
|
+
return NSPoint(
|
|
70
|
+
x: max(minX, min(origin.x, maxX)),
|
|
71
|
+
y: max(minY, min(origin.y, maxY))
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private static func distanceSquared(from point: NSPoint, to rect: NSRect) -> CGFloat {
|
|
76
|
+
let x = max(rect.minX, min(point.x, rect.maxX))
|
|
77
|
+
let y = max(rect.minY, min(point.y, rect.maxY))
|
|
78
|
+
let dx = point.x - x
|
|
79
|
+
let dy = point.y - y
|
|
80
|
+
return dx * dx + dy * dy
|
|
81
|
+
}
|
|
82
|
+
}
|