codex-flow 2.1.13__tar.gz → 2.1.14__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 (126) hide show
  1. {codex_flow-2.1.13/codex_flow.egg-info → codex_flow-2.1.14}/PKG-INFO +3 -3
  2. {codex_flow-2.1.13 → codex_flow-2.1.14}/README.en.md +2 -2
  3. {codex_flow-2.1.13 → codex_flow-2.1.14}/README.md +2 -2
  4. codex_flow-2.1.14/VERSION +1 -0
  5. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/chatgpt-mcp/server.py +1 -1
  6. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Controllers/OverlayWindowController.swift +63 -4
  7. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Services/IPCServer.swift +4 -4
  8. codex_flow-2.1.14/benchmark/prices/gpt-6-astra-2026-09-12.json +22 -0
  9. {codex_flow-2.1.13 → codex_flow-2.1.14}/benchmark/profiles.json +32 -2
  10. {codex_flow-2.1.13 → codex_flow-2.1.14/codex_flow.egg-info}/PKG-INFO +3 -3
  11. {codex_flow-2.1.13 → codex_flow-2.1.14}/codex_flow.egg-info/SOURCES.txt +1 -0
  12. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/analyze-benchmark.py +4 -0
  13. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/benchmark-local.py +3 -3
  14. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/render-benchmark-report.py +18 -0
  15. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/run-benchmark.py +53 -14
  16. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/update-homebrew-formula.py +3 -3
  17. codex_flow-2.1.13/VERSION +0 -1
  18. {codex_flow-2.1.13 → codex_flow-2.1.14}/LICENSE +0 -0
  19. {codex_flow-2.1.13 → codex_flow-2.1.14}/MANIFEST.in +0 -0
  20. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/chatgpt-mcp/README.md +0 -0
  21. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/chatgpt-mcp/__init__.py +0 -0
  22. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/chatgpt-mcp/adapter.py +0 -0
  23. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/chatgpt-mcp/widget.html +0 -0
  24. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/README.en.md +0 -0
  25. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/README.md +0 -0
  26. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Controllers/OverlayRuntimeState.swift +0 -0
  27. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Controllers/OverlayScreenGeometry.swift +0 -0
  28. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Localization.swift +0 -0
  29. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Models/TelemetryData.swift +0 -0
  30. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Services/AccountSnapshotService.swift +0 -0
  31. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Services/FlowPilotInstanceLock.swift +0 -0
  32. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Services/TelemetryQueryEngine.swift +0 -0
  33. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Services/TelemetryWatcher.swift +0 -0
  34. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Services/UpdateService.swift +0 -0
  35. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/AccountView.swift +0 -0
  36. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/AnalyticsView.swift +0 -0
  37. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/AutostartView.swift +0 -0
  38. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/BubbleView.swift +0 -0
  39. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/HistoryView.swift +0 -0
  40. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/HoverRevealText.swift +0 -0
  41. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/InspectorSkillsToolsView.swift +0 -0
  42. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/LogoView.swift +0 -0
  43. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/SleekSwitch.swift +0 -0
  44. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/StrategyModeView.swift +0 -0
  45. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/SummaryView.swift +0 -0
  46. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/Views/UpdateView.swift +0 -0
  47. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Sources/main.swift +0 -0
  48. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Tests/OverlayScreenGeometryTests.swift +0 -0
  49. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Tests/TelemetryPhase1ContractTests.swift +0 -0
  50. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Tests/TelemetryQueryEngineConcurrencyTests.swift +0 -0
  51. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Tests/TelemetryQuotaSelectionTests.swift +0 -0
  52. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/Tests/TelemetryWorkerTokenTests.swift +0 -0
  53. {codex_flow-2.1.13 → codex_flow-2.1.14}/apps/macos-overlay/build.sh +0 -0
  54. {codex_flow-2.1.13 → codex_flow-2.1.14}/benchmark/corpus.json +0 -0
  55. {codex_flow-2.1.13 → codex_flow-2.1.14}/benchmark/manifest.example.json +0 -0
  56. {codex_flow-2.1.13 → codex_flow-2.1.14}/benchmark/manifest.schema.json +0 -0
  57. {codex_flow-2.1.13 → codex_flow-2.1.14}/benchmark/prices/gpt-5.6-2026-08-30.json +0 -0
  58. {codex_flow-2.1.13 → codex_flow-2.1.14}/benchmark/schema.json +0 -0
  59. {codex_flow-2.1.13 → codex_flow-2.1.14}/benchmark/tasks.json +0 -0
  60. {codex_flow-2.1.13 → codex_flow-2.1.14}/codex_flow.egg-info/dependency_links.txt +0 -0
  61. {codex_flow-2.1.13 → codex_flow-2.1.14}/codex_flow.egg-info/entry_points.txt +0 -0
  62. {codex_flow-2.1.13 → codex_flow-2.1.14}/codex_flow.egg-info/top_level.txt +0 -0
  63. {codex_flow-2.1.13 → codex_flow-2.1.14}/completions/codex-flow.bash +0 -0
  64. {codex_flow-2.1.13 → codex_flow-2.1.14}/completions/codex-flow.zsh +0 -0
  65. {codex_flow-2.1.13 → codex_flow-2.1.14}/glama.json +0 -0
  66. {codex_flow-2.1.13 → codex_flow-2.1.14}/install-release.ps1 +0 -0
  67. {codex_flow-2.1.13 → codex_flow-2.1.14}/install-release.sh +0 -0
  68. {codex_flow-2.1.13 → codex_flow-2.1.14}/install.ps1 +0 -0
  69. {codex_flow-2.1.13 → codex_flow-2.1.14}/install.sh +0 -0
  70. {codex_flow-2.1.13 → codex_flow-2.1.14}/packaging/pypi/__init__.py +0 -0
  71. {codex_flow-2.1.13 → codex_flow-2.1.14}/packaging/pypi/__main__.py +0 -0
  72. {codex_flow-2.1.13 → codex_flow-2.1.14}/packaging/pypi/cli.py +0 -0
  73. {codex_flow-2.1.13 → codex_flow-2.1.14}/packaging/pypi/mcp.py +0 -0
  74. {codex_flow-2.1.13 → codex_flow-2.1.14}/policy/benchmark.toml +0 -0
  75. {codex_flow-2.1.13 → codex_flow-2.1.14}/policy/defaults.toml +0 -0
  76. {codex_flow-2.1.13 → codex_flow-2.1.14}/pyproject.toml +0 -0
  77. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/check-recommendation.py +0 -0
  78. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/doctor.py +0 -0
  79. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/generate-release-manifest.py +0 -0
  80. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/localization.py +0 -0
  81. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/manage-hooks.py +0 -0
  82. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/manage-instructions.py +0 -0
  83. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/manage-shell.py +0 -0
  84. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/materialize-corpus.py +0 -0
  85. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/menu.py +0 -0
  86. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/migrations/0001_update_settings.py +0 -0
  87. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/package-release.py +0 -0
  88. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/strategies/__init__.py +0 -0
  89. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/strategies/balanced.py +0 -0
  90. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/strategies/base.py +0 -0
  91. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/strategies/efficient.py +0 -0
  92. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/strategies/lifecycle_runtime.py +0 -0
  93. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/strategies/quality.py +0 -0
  94. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/strategies/speed.py +0 -0
  95. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/strategies/task_budget_runtime.py +0 -0
  96. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/strategies/task_phase_runtime.py +0 -0
  97. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/strategies/work_unit_runtime.py +0 -0
  98. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/strategy_runtime.py +0 -0
  99. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/telemetry.py +0 -0
  100. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/telemetry_core/__init__.py +0 -0
  101. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/telemetry_core/app_server.py +0 -0
  102. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/telemetry_core/collector.py +0 -0
  103. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/telemetry_core/common.py +0 -0
  104. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/telemetry_core/latency.py +0 -0
  105. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/telemetry_core/query.py +0 -0
  106. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/telemetry_core/quota_ledger.py +0 -0
  107. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/telemetry_core/render.py +0 -0
  108. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/telemetry_core/repair.py +0 -0
  109. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/ui.py +0 -0
  110. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/update_runtime_config.py +0 -0
  111. {codex_flow-2.1.13 → codex_flow-2.1.14}/scripts/updater.py +0 -0
  112. {codex_flow-2.1.13 → codex_flow-2.1.14}/setup.cfg +0 -0
  113. {codex_flow-2.1.13 → codex_flow-2.1.14}/setup.py +0 -0
  114. {codex_flow-2.1.13 → codex_flow-2.1.14}/smithery.yaml +0 -0
  115. {codex_flow-2.1.13 → codex_flow-2.1.14}/templates/agents/worker-explorer.toml +0 -0
  116. {codex_flow-2.1.13 → codex_flow-2.1.14}/templates/agents/worker-implementer.toml +0 -0
  117. {codex_flow-2.1.13 → codex_flow-2.1.14}/templates/agents/worker-reviewer.toml +0 -0
  118. {codex_flow-2.1.13 → codex_flow-2.1.14}/templates/flow-pilot-instructions.md +0 -0
  119. {codex_flow-2.1.13 → codex_flow-2.1.14}/templates/skills/flow-pilot/SKILL.md +0 -0
  120. {codex_flow-2.1.13 → codex_flow-2.1.14}/tests/test_hook_trust.py +0 -0
  121. {codex_flow-2.1.13 → codex_flow-2.1.14}/tests/test_instructions.py +0 -0
  122. {codex_flow-2.1.13 → codex_flow-2.1.14}/tests/test_quota_ledger.py +0 -0
  123. {codex_flow-2.1.13 → codex_flow-2.1.14}/tests/test_shared_strategy_lifecycle.py +0 -0
  124. {codex_flow-2.1.13 → codex_flow-2.1.14}/tests/test_task_phase_runtime.py +0 -0
  125. {codex_flow-2.1.13 → codex_flow-2.1.14}/tests/test_telemetry_worker_correlation.py +0 -0
  126. {codex_flow-2.1.13 → codex_flow-2.1.14}/tests/test_updater.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-flow
3
- Version: 2.1.13
3
+ Version: 2.1.14
4
4
  Summary: Intelligent, Efficient, Adaptive Multi-Agent Strategy Orchestration for Codex
5
5
  Home-page: https://github.com/ParsifalC/codex-flow
6
6
  Author: Parsifal
@@ -45,7 +45,7 @@ Dynamic: requires-python
45
45
 
46
46
  **智能、高效、自适应的 Codex 多 Agent 策略编排引擎**
47
47
 
48
- [![Version](https://img.shields.io/badge/version-2.1.13-blue.svg?style=flat-square)](VERSION)
48
+ [![Version](https://img.shields.io/badge/version-2.1.14-blue.svg?style=flat-square)](VERSION)
49
49
  [![Homebrew](https://img.shields.io/badge/Homebrew-ParsifalC%2Ftap-orange.svg?style=flat-square&logo=homebrew)](https://github.com/ParsifalC/homebrew-tap)
50
50
  [![PyPI](https://img.shields.io/pypi/v/codex-flow.svg?style=flat-square&logo=pypi)](https://pypi.org/project/codex-flow/)
51
51
  [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-brightgreen.svg?style=flat-square)](#-快速安装)
@@ -256,7 +256,7 @@ codex-flow
256
256
 
257
257
  ```text
258
258
  ╭────────────────────────────────────────────────────────────────────╮
259
- │ 🚀 codex-flow 控制台 (v2.1.13) │
259
+ │ 🚀 codex-flow 控制台 (v2.1.14) │
260
260
  │ FlowPilot 智能编排 · 确定性任务遥测 · 本地 Benchmark 验证 │
261
261
  ╰────────────────────────────────────────────────────────────────────╯
262
262
  [1] 🪟 macOS 原生悬浮窗 (overlay widget)
@@ -8,7 +8,7 @@
8
8
 
9
9
  **Intelligent, Efficient, Adaptive Multi-Agent Strategy Orchestration for Codex**
10
10
 
11
- [![Version](https://img.shields.io/badge/version-2.1.13-blue.svg?style=flat-square)](VERSION)
11
+ [![Version](https://img.shields.io/badge/version-2.1.14-blue.svg?style=flat-square)](VERSION)
12
12
  [![Homebrew](https://img.shields.io/badge/Homebrew-ParsifalC%2Ftap-orange.svg?style=flat-square&logo=homebrew)](https://github.com/ParsifalC/homebrew-tap)
13
13
  [![PyPI](https://img.shields.io/pypi/v/codex-flow.svg?style=flat-square&logo=pypi)](https://pypi.org/project/codex-flow/)
14
14
  [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-brightgreen.svg?style=flat-square)](#-quick-start)
@@ -217,7 +217,7 @@ The latest console also integrates Overlay build/start management, effective pol
217
217
 
218
218
  ```text
219
219
  ╭────────────────────────────────────────────────────────────────────╮
220
- │ 🚀 codex-flow Console (v2.1.13) │
220
+ │ 🚀 codex-flow Console (v2.1.14) │
221
221
  │ FlowPilot orchestration · deterministic telemetry · validation │
222
222
  ╰────────────────────────────────────────────────────────────────────╯
223
223
  [1] 🪟 macOS native floating widget (overlay widget)
@@ -8,7 +8,7 @@
8
8
 
9
9
  **智能、高效、自适应的 Codex 多 Agent 策略编排引擎**
10
10
 
11
- [![Version](https://img.shields.io/badge/version-2.1.13-blue.svg?style=flat-square)](VERSION)
11
+ [![Version](https://img.shields.io/badge/version-2.1.14-blue.svg?style=flat-square)](VERSION)
12
12
  [![Homebrew](https://img.shields.io/badge/Homebrew-ParsifalC%2Ftap-orange.svg?style=flat-square&logo=homebrew)](https://github.com/ParsifalC/homebrew-tap)
13
13
  [![PyPI](https://img.shields.io/pypi/v/codex-flow.svg?style=flat-square&logo=pypi)](https://pypi.org/project/codex-flow/)
14
14
  [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-brightgreen.svg?style=flat-square)](#-快速安装)
@@ -219,7 +219,7 @@ codex-flow
219
219
 
220
220
  ```text
221
221
  ╭────────────────────────────────────────────────────────────────────╮
222
- │ 🚀 codex-flow 控制台 (v2.1.13) │
222
+ │ 🚀 codex-flow 控制台 (v2.1.14) │
223
223
  │ FlowPilot 智能编排 · 确定性任务遥测 · 本地 Benchmark 验证 │
224
224
  ╰────────────────────────────────────────────────────────────────────╯
225
225
  [1] 🪟 macOS 原生悬浮窗 (overlay widget)
@@ -0,0 +1 @@
1
+ 2.1.14
@@ -25,7 +25,7 @@ else:
25
25
 
26
26
  JSONRPC_VERSION = "2.0"
27
27
  SERVER_NAME = "chatgpt-codex-flow"
28
- SERVER_VERSION = "2.1.13"
28
+ SERVER_VERSION = "2.1.14"
29
29
  MAX_REQUEST_BYTES = 1024 * 1024
30
30
 
31
31
 
@@ -11,7 +11,13 @@ public enum DockEdge: String, Codable {
11
11
  // MARK: - Shared Observable State
12
12
  public class OverlayState: ObservableObject {
13
13
  @Published public var isExpanded: Bool = false
14
- @Published public var isPinned: Bool = false
14
+ @Published public var isPinned: Bool = false {
15
+ didSet {
16
+ if isPinned {
17
+ windowController?.cancelNotificationAutoCollapseTimer()
18
+ }
19
+ }
20
+ }
15
21
  @Published public var isTaskRunning: Bool = false
16
22
  @Published public var isDocked: Bool = false
17
23
  @Published public var dockEdge: DockEdge = .right
@@ -55,14 +61,24 @@ public class OverlayState: ObservableObject {
55
61
  }
56
62
  }
57
63
 
58
- public func expand() {
59
- guard !isExpanded else { return }
64
+ public func expand(notificationTriggered: Bool = false) {
65
+ if isExpanded {
66
+ if notificationTriggered {
67
+ DispatchQueue.main.async {
68
+ self.windowController?.scheduleNotificationAutoCollapse()
69
+ }
70
+ }
71
+ return
72
+ }
60
73
  loadMenuData()
61
74
  DispatchQueue.main.async {
62
75
  self.windowController?.prepareForPresentationChange()
63
76
  self.isDocked = false
64
77
  self.isExpanded = true
65
78
  self.windowController?.updateWindowFrame(animated: true)
79
+ if notificationTriggered {
80
+ self.windowController?.scheduleNotificationAutoCollapse()
81
+ }
66
82
  }
67
83
  }
68
84
 
@@ -354,6 +370,7 @@ class TrackingHostingView<Content: View>: NSHostingView<Content> {
354
370
  isDragging = false
355
371
  windowController.cancelDwellTimer()
356
372
  windowController.cancelTuckTimer()
373
+ windowController.cancelNotificationAutoCollapseTimer()
357
374
  super.mouseDown(with: event)
358
375
  }
359
376
 
@@ -529,6 +546,8 @@ public class OverlayWindowController: NSObject, NSWindowDelegate {
529
546
 
530
547
  private var hoverDwellTimer: Timer?
531
548
  private var collapseTimer: Timer?
549
+ private var notificationCollapseTimer: Timer?
550
+ private let notificationAutoCollapseDuration: TimeInterval = 5.0
532
551
  private var tuckTimer: Timer?
533
552
  private let edgeTuckIdleInterval: TimeInterval = 30.0
534
553
 
@@ -612,6 +631,7 @@ public class OverlayWindowController: NSObject, NSWindowDelegate {
612
631
  public func prepareForPresentationChange() {
613
632
  cancelDwellTimer()
614
633
  cancelTuckTimer()
634
+ cancelNotificationAutoCollapseTimer()
615
635
  collapseTimer?.invalidate()
616
636
  collapseTimer = nil
617
637
  }
@@ -719,6 +739,9 @@ public class OverlayWindowController: NSObject, NSWindowDelegate {
719
739
  return true
720
740
  }
721
741
  reconcilePointerAfterGeometryIfNeeded()
742
+ if state.isExpanded && isPointerInAppWindowOrPopover() {
743
+ cancelNotificationAutoCollapseTimer()
744
+ }
722
745
  return false
723
746
  }
724
747
 
@@ -813,6 +836,7 @@ public class OverlayWindowController: NSObject, NSWindowDelegate {
813
836
  }
814
837
 
815
838
  public func handleMouseEntered(at point: NSPoint) {
839
+ cancelNotificationAutoCollapseTimer()
816
840
  if isGeometryTransitioning {
817
841
  needsPointerReconciliationAfterGeometry = true
818
842
  return
@@ -833,6 +857,7 @@ public class OverlayWindowController: NSObject, NSWindowDelegate {
833
857
  }
834
858
 
835
859
  public func handleMouseMoved(at point: NSPoint) {
860
+ cancelNotificationAutoCollapseTimer()
836
861
  if isGeometryTransitioning {
837
862
  needsPointerReconciliationAfterGeometry = true
838
863
  return
@@ -892,7 +917,41 @@ public class OverlayWindowController: NSObject, NSWindowDelegate {
892
917
  }
893
918
  }
894
919
 
895
- private func isPointerInAppWindowOrPopover() -> Bool {
920
+ public func scheduleNotificationAutoCollapse(duration: TimeInterval? = nil) {
921
+ cancelNotificationAutoCollapseTimer()
922
+ let interval = duration ?? notificationAutoCollapseDuration
923
+ guard state.isExpanded,
924
+ !state.isPinned,
925
+ !isInteractingOrDragging else { return }
926
+
927
+ if isPointerInAppWindowOrPopover() {
928
+ return
929
+ }
930
+
931
+ let timer = Timer(timeInterval: interval, repeats: false) { [weak self] _ in
932
+ guard let self,
933
+ self.state.isExpanded,
934
+ !self.state.isPinned,
935
+ !self.isInteractingOrDragging,
936
+ !self.isGeometryTransitioning else { return }
937
+
938
+ if self.isPointerInAppWindowOrPopover() {
939
+ self.cancelNotificationAutoCollapseTimer()
940
+ return
941
+ }
942
+
943
+ self.state.collapse()
944
+ }
945
+ RunLoop.main.add(timer, forMode: .common)
946
+ notificationCollapseTimer = timer
947
+ }
948
+
949
+ public func cancelNotificationAutoCollapseTimer() {
950
+ notificationCollapseTimer?.invalidate()
951
+ notificationCollapseTimer = nil
952
+ }
953
+
954
+ public func isPointerInAppWindowOrPopover() -> Bool {
896
955
  let mouseLocation = NSEvent.mouseLocation
897
956
  for appWindow in NSApp.windows {
898
957
  guard appWindow.isVisible,
@@ -196,23 +196,23 @@ public class IPCService {
196
196
  var run = try? JSONDecoder().decode(TaskRun.self, from: data) {
197
197
  TelemetryQueryEngine.shared.enrichRunIfNeeded(&run)
198
198
  state.update(run: run)
199
- state.expand()
199
+ state.expand(notificationTriggered: true)
200
200
  return "{\"ok\": true, \"updatedFrom\": \"last.json\"}\n"
201
201
  }
202
- state.expand()
202
+ state.expand(notificationTriggered: true)
203
203
  return "{\"ok\": true, \"action\": \"expanded\"}\n"
204
204
  } else {
205
205
  if let fileData = try? Data(contentsOf: URL(fileURLWithPath: payload)),
206
206
  var run = try? JSONDecoder().decode(TaskRun.self, from: fileData) {
207
207
  TelemetryQueryEngine.shared.enrichRunIfNeeded(&run)
208
208
  state.update(run: run)
209
- state.expand()
209
+ state.expand(notificationTriggered: true)
210
210
  return "{\"ok\": true, \"updatedFrom\": \"file\"}\n"
211
211
  } else if let json = payload.data(using: .utf8),
212
212
  var run = try? JSONDecoder().decode(TaskRun.self, from: json) {
213
213
  TelemetryQueryEngine.shared.enrichRunIfNeeded(&run)
214
214
  state.update(run: run)
215
- state.expand()
215
+ state.expand(notificationTriggered: true)
216
216
  return "{\"ok\": true, \"updatedFrom\": \"json\"}\n"
217
217
  }
218
218
  }
@@ -0,0 +1,22 @@
1
+ {
2
+ "gpt-5.6-luna": {
3
+ "input": 0.2,
4
+ "cached_input": 0.02,
5
+ "output": 1.2
6
+ },
7
+ "gpt-5.6-terra": {
8
+ "input": 2.0,
9
+ "cached_input": 0.2,
10
+ "output": 12.0
11
+ },
12
+ "gpt-5.6-sol": {
13
+ "input": 4.0,
14
+ "cached_input": 0.4,
15
+ "output": 20.0
16
+ },
17
+ "gpt-6-astra": {
18
+ "input": 10.0,
19
+ "cached_input": 1.0,
20
+ "output": 50.0
21
+ }
22
+ }
@@ -31,7 +31,7 @@
31
31
  ]
32
32
  },
33
33
  "full": {
34
- "description": "Three repetitions across three high direct models, fixed-high flow, and adaptive-effort flow.",
34
+ "description": "Three repetitions across three high direct models, fixed-high flow, and adaptive-effort flow. Includes Astra/high parent with the real efficient FlowPilot runtime.",
35
35
  "repetitions": 3,
36
36
  "matrix": [
37
37
  {"id": "luna-direct", "strategy": "direct", "model": "gpt-5.6-luna", "reasoning_effort": "high"},
@@ -56,11 +56,26 @@
56
56
  "model": "gpt-5.6-luna",
57
57
  "reasoning_effort": {"routine": "high", "complex": "xhigh", "critical": "max"}
58
58
  }
59
+ },
60
+ {
61
+ "id": "codex-flow-runtime-astra-high",
62
+ "strategy": "runtime",
63
+ "reasoning_policy": "fixed",
64
+ "profile": "efficient",
65
+ "routing_mode": "delegate",
66
+ "parent": {
67
+ "model": "gpt-6-astra",
68
+ "reasoning_effort": "high"
69
+ },
70
+ "worker": {
71
+ "model": "gpt-5.6-luna",
72
+ "reasoning_effort": "high"
73
+ }
59
74
  }
60
75
  ]
61
76
  },
62
77
  "agentic": {
63
- "description": "One repetition comparing direct baselines with real FlowPilot runtime execution under efficient and balanced profiles.",
78
+ "description": "One repetition comparing direct baselines with real FlowPilot runtime execution under efficient and balanced profiles. Includes Astra/high parent with the real efficient FlowPilot runtime.",
64
79
  "repetitions": 1,
65
80
  "matrix": [
66
81
  {"id": "luna-direct", "strategy": "direct", "model": "gpt-5.6-luna", "reasoning_effort": "high"},
@@ -83,6 +98,21 @@
83
98
  "routing_mode": "delegate",
84
99
  "parent": {"model": "gpt-5.6-sol", "reasoning_effort": "high"},
85
100
  "worker": {"model": "gpt-5.6-luna", "reasoning_effort": "high"}
101
+ },
102
+ {
103
+ "id": "codex-flow-runtime-astra-high",
104
+ "strategy": "runtime",
105
+ "reasoning_policy": "fixed",
106
+ "profile": "efficient",
107
+ "routing_mode": "delegate",
108
+ "parent": {
109
+ "model": "gpt-6-astra",
110
+ "reasoning_effort": "high"
111
+ },
112
+ "worker": {
113
+ "model": "gpt-5.6-luna",
114
+ "reasoning_effort": "high"
115
+ }
86
116
  }
87
117
  ]
88
118
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-flow
3
- Version: 2.1.13
3
+ Version: 2.1.14
4
4
  Summary: Intelligent, Efficient, Adaptive Multi-Agent Strategy Orchestration for Codex
5
5
  Home-page: https://github.com/ParsifalC/codex-flow
6
6
  Author: Parsifal
@@ -45,7 +45,7 @@ Dynamic: requires-python
45
45
 
46
46
  **智能、高效、自适应的 Codex 多 Agent 策略编排引擎**
47
47
 
48
- [![Version](https://img.shields.io/badge/version-2.1.13-blue.svg?style=flat-square)](VERSION)
48
+ [![Version](https://img.shields.io/badge/version-2.1.14-blue.svg?style=flat-square)](VERSION)
49
49
  [![Homebrew](https://img.shields.io/badge/Homebrew-ParsifalC%2Ftap-orange.svg?style=flat-square&logo=homebrew)](https://github.com/ParsifalC/homebrew-tap)
50
50
  [![PyPI](https://img.shields.io/pypi/v/codex-flow.svg?style=flat-square&logo=pypi)](https://pypi.org/project/codex-flow/)
51
51
  [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-brightgreen.svg?style=flat-square)](#-快速安装)
@@ -256,7 +256,7 @@ codex-flow
256
256
 
257
257
  ```text
258
258
  ╭────────────────────────────────────────────────────────────────────╮
259
- │ 🚀 codex-flow 控制台 (v2.1.13) │
259
+ │ 🚀 codex-flow 控制台 (v2.1.14) │
260
260
  │ FlowPilot 智能编排 · 确定性任务遥测 · 本地 Benchmark 验证 │
261
261
  ╰────────────────────────────────────────────────────────────────────╯
262
262
  [1] 🪟 macOS 原生悬浮窗 (overlay widget)
@@ -55,6 +55,7 @@ benchmark/profiles.json
55
55
  benchmark/schema.json
56
56
  benchmark/tasks.json
57
57
  benchmark/prices/gpt-5.6-2026-08-30.json
58
+ benchmark/prices/gpt-6-astra-2026-09-12.json
58
59
  codex_flow.egg-info/PKG-INFO
59
60
  codex_flow.egg-info/SOURCES.txt
60
61
  codex_flow.egg-info/dependency_links.txt
@@ -176,6 +176,10 @@ def load_jsonl(path: Path) -> list[dict[str, Any]]:
176
176
  for usage in row["model_usage"]:
177
177
  if usage["role"] == "direct":
178
178
  raise ValueError(f"{path}:{n}: {row['strategy']} model_usage cannot use direct role")
179
+ # Runtime workers are selected by the planner. The top-level
180
+ # worker fields describe configuration, not observed actors.
181
+ if row["strategy"] == "runtime" and usage["role"] == "worker":
182
+ continue
179
183
  expected_model = row["model"] if usage["role"] == "parent" else row["worker_model"]
180
184
  expected_effort = row["reasoning_effort"] if usage["role"] == "parent" else row["worker_reasoning_effort"]
181
185
  if usage["model"] != expected_model or usage["reasoning_effort"] != expected_effort:
@@ -11,7 +11,7 @@ from datetime import datetime, timezone
11
11
  from pathlib import Path
12
12
 
13
13
  ROOT = Path(__file__).resolve().parents[1]
14
- DEFAULT_PRICE = ROOT / "benchmark/prices/gpt-5.6-2026-08-30.json"
14
+ DEFAULT_PRICE = ROOT / "benchmark/prices/gpt-6-astra-2026-09-12.json"
15
15
 
16
16
 
17
17
  def run(cmd: list[str], *, check: bool = True, capture: bool = False) -> subprocess.CompletedProcess[str]:
@@ -35,7 +35,7 @@ def main() -> int:
35
35
  ap = argparse.ArgumentParser(
36
36
  description="Run the built-in codex-flow benchmark using the local Codex login session."
37
37
  )
38
- ap.add_argument("profile", nargs="?", choices=["quick", "full"], default="quick")
38
+ ap.add_argument("profile", nargs="?", choices=["quick", "full", "agentic"], default="quick")
39
39
  ap.add_argument("--workspace", default=".codex-flow-benchmark")
40
40
  ap.add_argument("--output")
41
41
  ap.add_argument("--prices", default=str(DEFAULT_PRICE))
@@ -79,7 +79,7 @@ def main() -> int:
79
79
  if disp_output.startswith(home_str):
80
80
  disp_output = "~" + disp_output[len(home_str):]
81
81
 
82
- budget = "~15M tokens (planning + repairs may increase)" if args.profile == "quick" else "high (90 runs, substantial Codex quota)"
82
+ budget = "~15M tokens (planning + repairs may increase)" if args.profile == "quick" else f"{planned} runs; usage depends on task execution and repairs"
83
83
 
84
84
  def pad_line(content: str, width: int = 68) -> str:
85
85
  pad = max(0, width - len(content))
@@ -71,6 +71,8 @@ def yes_no(value: bool) -> str:
71
71
  def composition(row: dict[str, Any]) -> str:
72
72
  if row["strategy"] == "direct":
73
73
  return f"{row['model']} / {row['reasoning_effort']}"
74
+ if row["strategy"] == "runtime":
75
+ return f"{row['model']} / {row['reasoning_effort']} parent → runtime-selected workers"
74
76
  policy = row.get("reasoning_policy", "fixed")
75
77
  if policy == "adaptive":
76
78
  return f"{row['model']} parent → {row['worker_model']} worker / adaptive"
@@ -180,6 +182,22 @@ def main() -> int:
180
182
  f"{pct(item_first, len(items))} | {item_repairs} | {item_reviews} | {item_wall:.1f}s | ${item_cost / len(items):.6f} |"
181
183
  )
182
184
 
185
+ runtime_actors: dict[tuple[str, str, str, str], int] = defaultdict(int)
186
+ for row in rows:
187
+ if row["strategy"] == "runtime":
188
+ for usage in row["model_usage"]:
189
+ key = (row["strategy_id"], usage["role"], usage["model"], usage["reasoning_effort"])
190
+ runtime_actors[key] += usage["calls"]
191
+ if runtime_actors:
192
+ lines.extend([
193
+ "", "## Runtime actor usage", "",
194
+ "Runtime worker configuration may differ from planner-selected actors. The following model/effort values come from recorded usage attribution.",
195
+ "", "| Strategy | Role | Model | Effort | Calls |",
196
+ "| --- | --- | --- | --- | ---: |",
197
+ ])
198
+ for (strategy_id, role, model, effort), calls in sorted(runtime_actors.items()):
199
+ lines.append(f"| {strategy_id} | {role} | {model} | {effort} | {calls} |")
200
+
183
201
  lines.extend([
184
202
  "",
185
203
  "## Token efficiency",
@@ -196,6 +196,20 @@ def parse_usage(jsonl: str) -> dict[str, int]:
196
196
  return usage
197
197
 
198
198
 
199
+ def seed_local_login(destination: Path) -> None:
200
+ """Seed a private run home without importing global instructions/config."""
201
+ destination.mkdir(parents=True, exist_ok=True)
202
+ login_home = Path(os.environ.get("CODEX_HOME", str(Path.home() / ".codex")))
203
+ login_file = login_home / "auth.json"
204
+ credential = destination / "auth.json"
205
+ if login_file.is_file() and not credential.exists():
206
+ with open(credential, "x", encoding="utf-8", opener=lambda path, flags: os.open(path, flags, 0o600)) as sink:
207
+ sink.write(login_file.read_text(encoding="utf-8"))
208
+ model_cache = login_home / "models_cache.json"
209
+ if model_cache.is_file() and not (destination / "models_cache.json").exists():
210
+ shutil.copyfile(model_cache, destination / "models_cache.json")
211
+
212
+
199
213
  def run_codex(
200
214
  workdir: Path,
201
215
  model: str,
@@ -208,16 +222,19 @@ def run_codex(
208
222
  output_schema_path: Path | None = None,
209
223
  ignore_user_config: bool = True,
210
224
  env: dict[str, str] | None = None,
225
+ writable_dirs: tuple[Path, ...] = (),
211
226
  ) -> tuple[int, dict[str, int], str, float, str]:
212
227
  cmd = [
213
- "codex", "exec", "--ephemeral", "--json",
228
+ "codex", "exec", "--json",
214
229
  ]
215
230
  if ignore_user_config:
216
- cmd.append("--ignore-user-config")
231
+ cmd.extend(["--ephemeral", "--ignore-user-config"])
217
232
  cmd.extend([
218
233
  "--sandbox", sandbox, "--model", model,
219
234
  "-c", f'model_reasoning_effort="{effort}"',
220
235
  ])
236
+ for directory in writable_dirs:
237
+ cmd.extend(["--add-dir", str(directory)])
221
238
  if output_schema_path is not None:
222
239
  cmd.extend(["--output-schema", str(output_schema_path)])
223
240
  if last_message_path is not None:
@@ -225,20 +242,32 @@ def run_codex(
225
242
  cmd.extend(["--cd", str(workdir), prompt])
226
243
  started = time.monotonic()
227
244
  run_env = os.environ.copy()
245
+ if ignore_user_config:
246
+ baseline_home = workdir.parent / ".codex-baseline"
247
+ seed_local_login(baseline_home)
248
+ run_env["CODEX_HOME"] = str(baseline_home)
228
249
  if env:
229
250
  run_env.update(env)
230
251
  try:
231
- proc = subprocess.run(cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout, env=run_env)
252
+ proc = subprocess.run(cmd, cwd=workdir, text=True, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout, env=run_env)
232
253
  elapsed = time.monotonic() - started
233
254
  last_message = ""
234
255
  if last_message_path is not None and last_message_path.exists():
235
256
  last_message = last_message_path.read_text()[-MAX_CAPTURE:]
236
- return proc.returncode, parse_usage(proc.stdout), (proc.stderr or proc.stdout)[-MAX_CAPTURE:], elapsed, last_message
257
+ diagnostic = (
258
+ proc.stderr[-MAX_CAPTURE // 4:] + "\n" + proc.stdout[-3 * MAX_CAPTURE // 4:]
259
+ if proc.stderr and proc.stdout else (proc.stderr or proc.stdout)[-MAX_CAPTURE:]
260
+ )
261
+ return proc.returncode, parse_usage(proc.stdout), diagnostic, elapsed, last_message
237
262
  except subprocess.TimeoutExpired as exc:
238
263
  elapsed = time.monotonic() - started
239
- stdout = exc.stdout if isinstance(exc.stdout, str) else ""
240
- stderr = exc.stderr if isinstance(exc.stderr, str) else ""
241
- return 124, parse_usage(stdout), (stderr or stdout)[-MAX_CAPTURE:], elapsed, ""
264
+ stdout = exc.stdout.decode("utf-8", errors="replace") if isinstance(exc.stdout, bytes) else (exc.stdout or "")
265
+ stderr = exc.stderr.decode("utf-8", errors="replace") if isinstance(exc.stderr, bytes) else (exc.stderr or "")
266
+ diagnostic = (
267
+ stderr[-MAX_CAPTURE // 4:] + "\n" + stdout[-3 * MAX_CAPTURE // 4:]
268
+ if stderr and stdout else (stderr or stdout)[-MAX_CAPTURE:]
269
+ )
270
+ return 124, parse_usage(stdout), diagnostic, elapsed, ""
242
271
 
243
272
 
244
273
  def run_verify(workdir: Path, argv: list[str], timeout: int) -> tuple[bool, str, float]:
@@ -335,7 +364,7 @@ def build_row(
335
364
  "repetition": repetition,
336
365
  "codex_exit_code": codex_exit,
337
366
  "verification_excerpt": verification[-2000:] if not passed else "",
338
- "diagnostic_excerpt": diagnostic[-2000:] if codex_exit != 0 else "",
367
+ "diagnostic_excerpt": diagnostic[-MAX_CAPTURE:] if not passed or codex_exit != 0 else "",
339
368
  }
340
369
 
341
370
 
@@ -639,6 +668,11 @@ def execute_runtime(
639
668
  # Pre-authorize hooks for headless non-interactive execution
640
669
  authorize_hooks(codex_home)
641
670
 
671
+ # Reuse file-backed local login without importing the user's routing or
672
+ # plugin configuration. Keep the temporary credential private; the run's
673
+ # TemporaryDirectory removes it together with the isolated runtime.
674
+ seed_local_login(codex_home)
675
+
642
676
  runtime_env = {
643
677
  "CODEX_HOME": str(codex_home),
644
678
  "PATH": f"{bin_dir}:{os.environ.get('PATH', '')}",
@@ -653,7 +687,7 @@ def execute_runtime(
653
687
 
654
688
  codex_exit, usage, diagnostic, elapsed, _ = run_codex(
655
689
  workdir, parent_model, parent_effort, runtime_prompt, timeout,
656
- ignore_user_config=False, env=runtime_env,
690
+ ignore_user_config=False, env=runtime_env, writable_dirs=(codex_home,),
657
691
  )
658
692
  total_wall += elapsed
659
693
  cumulative_codex_usage = empty_usage()
@@ -677,7 +711,7 @@ def execute_runtime(
677
711
  )
678
712
  codex_exit, usage, diagnostic, elapsed, _ = run_codex(
679
713
  workdir, parent_model, parent_effort, repair_prompt, timeout,
680
- ignore_user_config=False, env=runtime_env,
714
+ ignore_user_config=False, env=runtime_env, writable_dirs=(codex_home,),
681
715
  )
682
716
  total_wall += elapsed
683
717
  add_usage(cumulative_codex_usage, usage)
@@ -705,15 +739,20 @@ def execute_runtime(
705
739
  workers = run_data.get("workers")
706
740
  if isinstance(workers, dict):
707
741
  for w_name, w in workers.items():
708
- if "review" in w_name.lower():
742
+ if not isinstance(w, dict):
743
+ continue
744
+ if "review" in str(w.get("agent_type", w_name)).lower():
709
745
  review_cycles += 1
710
746
  if isinstance(w, dict) and isinstance(w.get("usage"), dict):
711
747
  w_u = w["usage"]
712
748
  if any(w_u.get(k, 0) > 0 for k in ("input_tokens", "cached_input_tokens", "output_tokens")):
713
- add_model_usage(usage_by_model, "worker", worker_model, worker_effort, w_u)
749
+ add_model_usage(
750
+ usage_by_model, "worker", w.get("model") or worker_model,
751
+ w.get("reasoning_effort") or worker_effort, w_u,
752
+ )
714
753
 
715
754
  # Fallback to top-level codex exec usage attributed to parent if telemetry was not populated
716
- if not usage_by_model:
755
+ if not any(role == "parent" for role, _, _ in usage_by_model):
717
756
  add_model_usage(usage_by_model, "parent", parent_model, parent_effort, cumulative_codex_usage)
718
757
 
719
758
  return build_row(
@@ -799,7 +838,7 @@ def main() -> int:
799
838
  for repetition in range(1, manifest.get("repetitions", 1) + 1):
800
839
  with tempfile.TemporaryDirectory(prefix="codex-flow-bench-") as tmp:
801
840
  row = execute_run(
802
- task, config, Path(tmp), repetition,
841
+ task, config, Path(tmp).resolve(), repetition,
803
842
  manifest.get("timeout_seconds", 1800),
804
843
  task.get("max_repair_cycles", manifest.get("max_repair_cycles", 2)),
805
844
  )
@@ -16,7 +16,6 @@ FORMULA_PATH = ROOT / "packaging" / "homebrew" / "codex-flow.rb"
16
16
  TEMPLATE = """class CodexFlow < Formula
17
17
  desc "Intelligent, Efficient, Adaptive Multi-Agent Strategy Orchestration for Codex"
18
18
  homepage "https://github.com/ParsifalC/codex-flow"
19
- version "{version}"
20
19
 
21
20
  on_macos do
22
21
  if Hardware::CPU.arm?
@@ -42,7 +41,8 @@ TEMPLATE = """class CodexFlow < Formula
42
41
  libexec.install Dir["*"]
43
42
  bin.write_exec_script libexec/"bin/codex-flow"
44
43
  bin.write_exec_script libexec/"bin/codex-flow-mcp"
45
- bash_completion.install libexec/"completions/codex-flow.bash" => "codex-flow" if (libexec/"completions/codex-flow.bash").exist?
44
+ completion = libexec/"completions/codex-flow.bash"
45
+ bash_completion.install completion => "codex-flow" if completion.exist?
46
46
  end
47
47
 
48
48
  def caveats
@@ -56,7 +56,7 @@ TEMPLATE = """class CodexFlow < Formula
56
56
  end
57
57
 
58
58
  test do
59
- assert_match "codex-flow", shell_output("#{{bin}}/codex-flow --help", 0)
59
+ assert_match "codex-flow", shell_output("#{{bin}}/codex-flow --help")
60
60
  end
61
61
  end
62
62
  """
codex_flow-2.1.13/VERSION DELETED
@@ -1 +0,0 @@
1
- 2.1.13
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes