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.
Files changed (113) hide show
  1. codex_flow/__init__.py +28 -0
  2. codex_flow/__main__.py +9 -0
  3. codex_flow/cli.py +242 -0
  4. codex_flow/data/LICENSE +21 -0
  5. codex_flow/data/README.en.md +303 -0
  6. codex_flow/data/README.md +305 -0
  7. codex_flow/data/VERSION +1 -0
  8. codex_flow/data/apps/chatgpt-mcp/README.md +86 -0
  9. codex_flow/data/apps/chatgpt-mcp/__init__.py +1 -0
  10. codex_flow/data/apps/chatgpt-mcp/adapter.py +458 -0
  11. codex_flow/data/apps/chatgpt-mcp/server.py +358 -0
  12. codex_flow/data/apps/chatgpt-mcp/widget.html +927 -0
  13. codex_flow/data/apps/macos-overlay/README.en.md +121 -0
  14. codex_flow/data/apps/macos-overlay/README.md +123 -0
  15. codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayRuntimeState.swift +126 -0
  16. codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayScreenGeometry.swift +82 -0
  17. codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayWindowController.swift +1052 -0
  18. codex_flow/data/apps/macos-overlay/Sources/Localization.swift +197 -0
  19. codex_flow/data/apps/macos-overlay/Sources/Models/TelemetryData.swift +1557 -0
  20. codex_flow/data/apps/macos-overlay/Sources/Services/AccountSnapshotService.swift +1101 -0
  21. codex_flow/data/apps/macos-overlay/Sources/Services/FlowPilotInstanceLock.swift +153 -0
  22. codex_flow/data/apps/macos-overlay/Sources/Services/IPCServer.swift +298 -0
  23. codex_flow/data/apps/macos-overlay/Sources/Services/TelemetryQueryEngine.swift +800 -0
  24. codex_flow/data/apps/macos-overlay/Sources/Services/TelemetryWatcher.swift +135 -0
  25. codex_flow/data/apps/macos-overlay/Sources/Services/UpdateService.swift +610 -0
  26. codex_flow/data/apps/macos-overlay/Sources/Views/AccountView.swift +610 -0
  27. codex_flow/data/apps/macos-overlay/Sources/Views/AnalyticsView.swift +566 -0
  28. codex_flow/data/apps/macos-overlay/Sources/Views/AutostartView.swift +293 -0
  29. codex_flow/data/apps/macos-overlay/Sources/Views/BubbleView.swift +317 -0
  30. codex_flow/data/apps/macos-overlay/Sources/Views/HistoryView.swift +1124 -0
  31. codex_flow/data/apps/macos-overlay/Sources/Views/HoverRevealText.swift +165 -0
  32. codex_flow/data/apps/macos-overlay/Sources/Views/InspectorSkillsToolsView.swift +121 -0
  33. codex_flow/data/apps/macos-overlay/Sources/Views/LogoView.swift +182 -0
  34. codex_flow/data/apps/macos-overlay/Sources/Views/SleekSwitch.swift +117 -0
  35. codex_flow/data/apps/macos-overlay/Sources/Views/StrategyModeView.swift +561 -0
  36. codex_flow/data/apps/macos-overlay/Sources/Views/SummaryView.swift +1273 -0
  37. codex_flow/data/apps/macos-overlay/Sources/Views/UpdateView.swift +352 -0
  38. codex_flow/data/apps/macos-overlay/Sources/main.swift +340 -0
  39. codex_flow/data/apps/macos-overlay/Tests/OverlayScreenGeometryTests.swift +163 -0
  40. codex_flow/data/apps/macos-overlay/Tests/TelemetryPhase1ContractTests.swift +357 -0
  41. codex_flow/data/apps/macos-overlay/Tests/TelemetryQueryEngineConcurrencyTests.swift +221 -0
  42. codex_flow/data/apps/macos-overlay/Tests/TelemetryQuotaSelectionTests.swift +158 -0
  43. codex_flow/data/apps/macos-overlay/Tests/TelemetryWorkerTokenTests.swift +122 -0
  44. codex_flow/data/apps/macos-overlay/build.sh +75 -0
  45. codex_flow/data/benchmark/corpus.json +103 -0
  46. codex_flow/data/benchmark/manifest.example.json +41 -0
  47. codex_flow/data/benchmark/manifest.schema.json +137 -0
  48. codex_flow/data/benchmark/prices/gpt-5.6-2026-08-30.json +5 -0
  49. codex_flow/data/benchmark/profiles.json +90 -0
  50. codex_flow/data/benchmark/schema.json +77 -0
  51. codex_flow/data/benchmark/tasks.json +50 -0
  52. codex_flow/data/completions/codex-flow.bash +34 -0
  53. codex_flow/data/completions/codex-flow.zsh +52 -0
  54. codex_flow/data/glama.json +6 -0
  55. codex_flow/data/install-release.ps1 +126 -0
  56. codex_flow/data/install-release.sh +155 -0
  57. codex_flow/data/install.ps1 +349 -0
  58. codex_flow/data/install.sh +362 -0
  59. codex_flow/data/policy/benchmark.toml +49 -0
  60. codex_flow/data/policy/defaults.toml +70 -0
  61. codex_flow/data/scripts/analyze-benchmark.py +510 -0
  62. codex_flow/data/scripts/benchmark-local.py +171 -0
  63. codex_flow/data/scripts/check-recommendation.py +277 -0
  64. codex_flow/data/scripts/doctor.py +449 -0
  65. codex_flow/data/scripts/generate-release-manifest.py +74 -0
  66. codex_flow/data/scripts/localization.py +192 -0
  67. codex_flow/data/scripts/manage-hooks.py +448 -0
  68. codex_flow/data/scripts/manage-instructions.py +389 -0
  69. codex_flow/data/scripts/manage-shell.py +151 -0
  70. codex_flow/data/scripts/materialize-corpus.py +193 -0
  71. codex_flow/data/scripts/menu.py +646 -0
  72. codex_flow/data/scripts/migrations/0001_update_settings.py +80 -0
  73. codex_flow/data/scripts/package-release.py +132 -0
  74. codex_flow/data/scripts/render-benchmark-report.py +292 -0
  75. codex_flow/data/scripts/run-benchmark.py +829 -0
  76. codex_flow/data/scripts/strategies/__init__.py +28 -0
  77. codex_flow/data/scripts/strategies/balanced.py +115 -0
  78. codex_flow/data/scripts/strategies/base.py +363 -0
  79. codex_flow/data/scripts/strategies/efficient.py +158 -0
  80. codex_flow/data/scripts/strategies/lifecycle_runtime.py +590 -0
  81. codex_flow/data/scripts/strategies/quality.py +209 -0
  82. codex_flow/data/scripts/strategies/speed.py +108 -0
  83. codex_flow/data/scripts/strategies/task_budget_runtime.py +644 -0
  84. codex_flow/data/scripts/strategies/task_phase_runtime.py +341 -0
  85. codex_flow/data/scripts/strategies/work_unit_runtime.py +421 -0
  86. codex_flow/data/scripts/strategy_runtime.py +1091 -0
  87. codex_flow/data/scripts/telemetry.py +400 -0
  88. codex_flow/data/scripts/telemetry_core/__init__.py +192 -0
  89. codex_flow/data/scripts/telemetry_core/app_server.py +1192 -0
  90. codex_flow/data/scripts/telemetry_core/collector.py +1247 -0
  91. codex_flow/data/scripts/telemetry_core/common.py +421 -0
  92. codex_flow/data/scripts/telemetry_core/latency.py +593 -0
  93. codex_flow/data/scripts/telemetry_core/query.py +427 -0
  94. codex_flow/data/scripts/telemetry_core/quota_ledger.py +598 -0
  95. codex_flow/data/scripts/telemetry_core/render.py +460 -0
  96. codex_flow/data/scripts/telemetry_core/repair.py +223 -0
  97. codex_flow/data/scripts/ui.py +266 -0
  98. codex_flow/data/scripts/update-homebrew-formula.py +146 -0
  99. codex_flow/data/scripts/update_runtime_config.py +134 -0
  100. codex_flow/data/scripts/updater.py +1718 -0
  101. codex_flow/data/smithery.yaml +18 -0
  102. codex_flow/data/templates/agents/worker-explorer.toml +24 -0
  103. codex_flow/data/templates/agents/worker-implementer.toml +49 -0
  104. codex_flow/data/templates/agents/worker-reviewer.toml +25 -0
  105. codex_flow/data/templates/flow-pilot-instructions.md +35 -0
  106. codex_flow/data/templates/skills/flow-pilot/SKILL.md +577 -0
  107. codex_flow/mcp.py +35 -0
  108. codex_flow-2.1.13.dist-info/METADATA +342 -0
  109. codex_flow-2.1.13.dist-info/RECORD +113 -0
  110. codex_flow-2.1.13.dist-info/WHEEL +5 -0
  111. codex_flow-2.1.13.dist-info/entry_points.txt +3 -0
  112. codex_flow-2.1.13.dist-info/licenses/LICENSE +21 -0
  113. codex_flow-2.1.13.dist-info/top_level.txt +1 -0
@@ -0,0 +1,52 @@
1
+ #compdef codex-flow
2
+
3
+ _codex_flow() {
4
+ local -a commands
5
+ commands=(
6
+ 'status:Show installed version and effective FlowPilot strategy'
7
+ 'strategy:Inspect or configure the multi-strategy runtime'
8
+ 'language:Show or set UI language (auto/zh/en)'
9
+ 'update:Pull the checkout and refresh recommendations'
10
+ 'doctor:Verify installation, strategy runtime, and telemetry'
11
+ 'overlay:Manage the native macOS floating widget'
12
+ 'usage:Show deterministic FlowPilot usage summaries and history'
13
+ 'telemetry:Telemetry collection, inspection, and historical repair'
14
+ 'benchmark-local:Run the built-in benchmark through the local Codex login'
15
+ 'benchmark-corpus:Materialize the built-in corpus'
16
+ 'benchmark:Run a reproducible benchmark manifest'
17
+ 'benchmark-analyze:Analyze benchmark JSONL results'
18
+ 'uninstall:Remove codex-flow-managed files'
19
+ 'help:Show command help'
20
+ )
21
+ if (( CURRENT == 2 )); then
22
+ _describe 'command' commands
23
+ elif (( CURRENT == 3 )) && [[ "${words[2]}" == strategy ]]; then
24
+ _describe 'strategy command' '(show profiles enabled enable disable set routing plan)'
25
+ elif (( CURRENT == 4 )) && [[ "${words[2]}" == strategy && "${words[3]}" == set ]]; then
26
+ _describe 'strategy profile' '(efficient balanced quality speed)'
27
+ elif (( CURRENT == 4 )) && [[ "${words[2]}" == strategy && "${words[3]}" == routing ]]; then
28
+ _describe 'routing mode' '(adaptive direct delegate)'
29
+ elif (( CURRENT >= 4 )) && [[ "${words[2]}" == strategy && "${words[3]}" == plan ]]; then
30
+ _describe 'plan option' '(--profile --routing --review --fanout --complexity --uncertainty --risk --scope --parallelism --write-conflict --exploration-need --verification-cost --iteration-intensity --writable-workstreams --quality-intent --quota-pressure --max-threads --max-repairs)'
31
+ elif (( CURRENT == 3 )) && [[ "${words[2]}" == language ]]; then
32
+ _describe 'language' '(auto zh en)'
33
+ elif (( CURRENT == 3 )) && [[ "${words[2]}" == benchmark-local || "${words[2]}" == benchmark-corpus ]]; then
34
+ _describe 'profile' '(quick full)'
35
+ elif (( CURRENT == 3 )) && [[ "${words[2]}" == usage || "${words[2]}" == telemetry ]]; then
36
+ _describe 'usage command' '(last list show stats summary repair)'
37
+ elif (( CURRENT >= 4 )) && [[ "${words[2]}" == usage || "${words[2]}" == telemetry ]]; then
38
+ case "${words[3]}" in
39
+ last|show) _describe 'usage option' '(--json)' ;;
40
+ list) _describe 'list option' '(--json --today -n --limit -p --project)' ;;
41
+ stats|summary) _describe 'stats option' '(--json -d --days -p --project)' ;;
42
+ repair) _describe 'repair option' '(--dry-run --json)' ;;
43
+ esac
44
+ fi
45
+ }
46
+ if (( $+functions[compdef] )); then
47
+ compdef _codex_flow codex-flow
48
+ else
49
+ autoload -Uz compinit
50
+ compinit -i >/dev/null 2>&1 || true
51
+ (( $+functions[compdef] )) && compdef _codex_flow codex-flow
52
+ fi
@@ -0,0 +1,6 @@
1
+ {
2
+ "$schema": "https://glama.ai/mcp/schemas/server.json",
3
+ "maintainers": [
4
+ "Parsifal"
5
+ ]
6
+ }
@@ -0,0 +1,126 @@
1
+ $ErrorActionPreference = 'Stop'
2
+ Set-StrictMode -Version 2.0
3
+
4
+ $Repo = if ($env:CODEX_FLOW_REPO) { $env:CODEX_FLOW_REPO } else { 'ParsifalC/codex-flow' }
5
+ $Channel = if ($env:CODEX_FLOW_UPDATE_CHANNEL) { $env:CODEX_FLOW_UPDATE_CHANNEL } else { 'stable' }
6
+ $CodexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $HOME '.codex' }
7
+ $StateDir = Join-Path $CodexHome 'codex-flow'
8
+ $VersionsDir = Join-Path $StateDir 'versions'
9
+ $TempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ('codex-flow-install-' + [Guid]::NewGuid().ToString('N'))
10
+
11
+ function Fail([string]$Message) { throw "codex-flow installer: $Message" }
12
+ function Say([string]$Message) { Write-Host $Message }
13
+
14
+ if ($Channel -ne 'stable') {
15
+ Fail "first-install bootstrap currently supports the stable channel only; install stable first, then switch update.channel to $Channel"
16
+ }
17
+
18
+ # Windows PowerShell 5 can otherwise negotiate an obsolete TLS version on older systems.
19
+ try {
20
+ [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
21
+ } catch {}
22
+
23
+ $archName = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE }
24
+ switch -Regex ($archName) {
25
+ '^(ARM64|arm64)$' { $Arch = 'arm64'; break }
26
+ '^(AMD64|x86_64|amd64)$' { $Arch = 'x86_64'; break }
27
+ default { Fail "unsupported CPU architecture: $archName" }
28
+ }
29
+ $Platform = "windows-$Arch"
30
+
31
+ New-Item -ItemType Directory -Force -Path $TempRoot,$VersionsDir | Out-Null
32
+ try {
33
+ $ManifestPath = Join-Path $TempRoot 'codex-flow-update.json'
34
+ $ManifestUrl = "https://github.com/$Repo/releases/latest/download/codex-flow-update.json"
35
+ Say "-> Resolving latest codex-flow release for $Platform"
36
+ try {
37
+ Invoke-WebRequest -UseBasicParsing -Uri $ManifestUrl -OutFile $ManifestPath
38
+ } catch {
39
+ Fail 'no OTA-enabled stable release is available yet; publish a stable release containing codex-flow-update.json before using the release bootstrap'
40
+ }
41
+
42
+ $Manifest = Get-Content -Raw -Encoding UTF8 $ManifestPath | ConvertFrom-Json
43
+ if ($Manifest.channel -ne 'stable') { Fail 'latest release manifest is not stable' }
44
+ $Artifacts = $Manifest.artifacts
45
+ if (-not $Artifacts) { Fail 'release manifest does not contain artifacts' }
46
+ $ArtifactProperty = $Artifacts.PSObject.Properties[$Platform]
47
+ $Artifact = if ($ArtifactProperty) { $ArtifactProperty.Value } else { $null }
48
+ if (-not $Artifact) { Fail "release does not contain artifact for $Platform" }
49
+ if (-not $Artifact.url -or -not $Artifact.sha256 -or -not $Artifact.format) { Fail 'release manifest contains an incomplete artifact entry' }
50
+ if ($Artifact.format -ne 'zip') { Fail "unsupported Windows release archive format: $($Artifact.format)" }
51
+
52
+ $Version = [string]$Manifest.version
53
+ if (-not $Version) { Fail 'release manifest does not contain a version' }
54
+ $Archive = Join-Path $TempRoot 'codex-flow.zip'
55
+ Say "-> Downloading codex-flow v$Version"
56
+ Invoke-WebRequest -UseBasicParsing -Uri ([string]$Artifact.url) -OutFile $Archive
57
+
58
+ $ActualSha = (Get-FileHash -Algorithm SHA256 -Path $Archive).Hash.ToLowerInvariant()
59
+ $ExpectedSha = ([string]$Artifact.sha256).Trim().ToLowerInvariant()
60
+ if ($ActualSha -ne $ExpectedSha) { Fail 'SHA-256 mismatch for downloaded release' }
61
+ Say 'OK SHA-256 verified'
62
+
63
+ Add-Type -AssemblyName System.IO.Compression.FileSystem
64
+ $ExtractDir = Join-Path $TempRoot 'package'
65
+ New-Item -ItemType Directory -Force -Path $ExtractDir | Out-Null
66
+ $ExtractRoot = [System.IO.Path]::GetFullPath($ExtractDir + [System.IO.Path]::DirectorySeparatorChar)
67
+ $Zip = [System.IO.Compression.ZipFile]::OpenRead($Archive)
68
+ try {
69
+ foreach ($Entry in $Zip.Entries) {
70
+ $Target = [System.IO.Path]::GetFullPath((Join-Path $ExtractDir $Entry.FullName))
71
+ if (-not $Target.StartsWith($ExtractRoot, [System.StringComparison]::OrdinalIgnoreCase)) {
72
+ Fail "unsafe archive member: $($Entry.FullName)"
73
+ }
74
+ }
75
+ } finally {
76
+ $Zip.Dispose()
77
+ }
78
+ [System.IO.Compression.ZipFile]::ExtractToDirectory($Archive, $ExtractDir)
79
+
80
+ $PackageRoot = Join-Path $ExtractDir "codex-flow-$Version"
81
+ $Installer = Join-Path $PackageRoot 'install.ps1'
82
+ if (-not (Test-Path -LiteralPath $Installer -PathType Leaf)) { Fail 'release package does not contain install.ps1 at the expected root' }
83
+
84
+ $VersionDir = Join-Path $VersionsDir $Version
85
+ $StageDir = Join-Path $VersionsDir ('.install-' + $Version + '-' + [Guid]::NewGuid().ToString('N'))
86
+ Move-Item -LiteralPath $PackageRoot -Destination $StageDir
87
+
88
+ if (Test-Path -LiteralPath $VersionDir) {
89
+ $ExistingSource = Join-Path $StateDir 'source'
90
+ $CurrentSource = if (Test-Path $ExistingSource) { (Get-Content -Raw -Encoding UTF8 $ExistingSource).Trim() } else { '' }
91
+ if ($CurrentSource -and ([System.IO.Path]::GetFullPath($CurrentSource) -eq [System.IO.Path]::GetFullPath($VersionDir))) {
92
+ $BackupDir = Join-Path $VersionsDir ('.previous-install-' + $Version + '-' + [Guid]::NewGuid().ToString('N'))
93
+ Move-Item -LiteralPath $VersionDir -Destination $BackupDir
94
+ try {
95
+ Move-Item -LiteralPath $StageDir -Destination $VersionDir
96
+ Remove-Item -LiteralPath $BackupDir -Recurse -Force -ErrorAction SilentlyContinue
97
+ } catch {
98
+ if (-not (Test-Path $VersionDir) -and (Test-Path $BackupDir)) { Move-Item -LiteralPath $BackupDir -Destination $VersionDir }
99
+ throw
100
+ }
101
+ } else {
102
+ Remove-Item -LiteralPath $VersionDir -Recurse -Force
103
+ Move-Item -LiteralPath $StageDir -Destination $VersionDir
104
+ }
105
+ } else {
106
+ Move-Item -LiteralPath $StageDir -Destination $VersionDir
107
+ }
108
+
109
+ $PersistentInstaller = Join-Path $VersionDir 'install.ps1'
110
+ Say "-> Installing codex-flow v$Version"
111
+ & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $PersistentInstaller
112
+ if ($LASTEXITCODE -ne 0) { Fail "install.ps1 exited with code $LASTEXITCODE" }
113
+
114
+ $Doctor = Join-Path $StateDir 'doctor.py'
115
+ if (Test-Path $Doctor) {
116
+ Say '-> Running doctor'
117
+ & python3 $Doctor
118
+ if ($LASTEXITCODE -ne 0) { Fail "doctor exited with code $LASTEXITCODE" }
119
+ }
120
+
121
+ Say ''
122
+ Say "OK codex-flow v$Version installation complete"
123
+ Say ' Fully restart Codex to activate the new Agent / Skill / Hook / policy snapshot.'
124
+ } finally {
125
+ Remove-Item -LiteralPath $TempRoot -Recurse -Force -ErrorAction SilentlyContinue
126
+ }
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ REPO="${CODEX_FLOW_REPO:-ParsifalC/codex-flow}"
5
+ CHANNEL="${CODEX_FLOW_UPDATE_CHANNEL:-stable}"
6
+ CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
7
+ STATE_DIR="$CODEX_HOME/codex-flow"
8
+ TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/codex-flow-install.XXXXXX")"
9
+ trap 'rm -rf "$TMP_DIR"' EXIT
10
+
11
+ say() { printf '%s\n' "$*"; }
12
+ fail() { printf 'codex-flow installer: %s\n' "$*" >&2; exit 1; }
13
+
14
+ command -v curl >/dev/null 2>&1 || fail "curl is required"
15
+ command -v python3 >/dev/null 2>&1 || fail "python3 is required"
16
+
17
+ case "$(uname -s)" in
18
+ Darwin) os="darwin" ;;
19
+ Linux) os="linux" ;;
20
+ *) fail "unsupported operating system: $(uname -s)" ;;
21
+ esac
22
+
23
+ case "$(uname -m)" in
24
+ arm64|aarch64) arch="arm64" ;;
25
+ x86_64|amd64) arch="x86_64" ;;
26
+ *) fail "unsupported CPU architecture: $(uname -m)" ;;
27
+ esac
28
+
29
+ platform="$os-$arch"
30
+
31
+ if [[ "$CHANNEL" != "stable" ]]; then
32
+ fail "first-install bootstrap currently supports the stable channel only; install stable first, then switch update.channel to $CHANNEL"
33
+ fi
34
+
35
+ manifest_url="https://github.com/$REPO/releases/latest/download/codex-flow-update.json"
36
+ manifest="$TMP_DIR/codex-flow-update.json"
37
+ say "→ Resolving latest codex-flow release for $platform"
38
+ if ! curl -fL --retry 3 --connect-timeout 15 "$manifest_url" -o "$manifest"; then
39
+ fail "no OTA-enabled stable release is available yet; publish a stable release containing codex-flow-update.json before using the release bootstrap"
40
+ fi
41
+
42
+ IFS=$'\t' read -r version artifact_url expected_sha archive_format < <(python3 - "$manifest" "$platform" <<'PY'
43
+ import json, sys
44
+ from pathlib import Path
45
+ manifest_path, platform = Path(sys.argv[1]), sys.argv[2]
46
+ data = json.loads(manifest_path.read_text(encoding="utf-8"))
47
+ if data.get("channel") != "stable":
48
+ raise SystemExit("latest release manifest is not stable")
49
+ artifact = (data.get("artifacts") or {}).get(platform)
50
+ if not artifact:
51
+ raise SystemExit(f"release does not contain artifact for {platform}")
52
+ for key in ("url", "sha256", "format"):
53
+ if not artifact.get(key):
54
+ raise SystemExit(f"artifact is missing {key}")
55
+ print("\t".join((
56
+ data.get("version") or "unknown",
57
+ artifact["url"],
58
+ artifact["sha256"].lower(),
59
+ artifact["format"],
60
+ )))
61
+ PY
62
+ )
63
+
64
+ [[ -n "${version:-}" && -n "${artifact_url:-}" && -n "${expected_sha:-}" && -n "${archive_format:-}" ]] || fail "invalid release manifest"
65
+
66
+ case "$archive_format" in
67
+ tar.gz) archive="$TMP_DIR/codex-flow.tar.gz" ;;
68
+ zip) archive="$TMP_DIR/codex-flow.zip" ;;
69
+ *) fail "unsupported release archive format: $archive_format" ;;
70
+ esac
71
+
72
+ say "→ Downloading codex-flow v$version"
73
+ curl -fL --retry 3 --connect-timeout 15 "$artifact_url" -o "$archive"
74
+
75
+ actual_sha="$(python3 - "$archive" <<'PY'
76
+ import hashlib, sys
77
+ h = hashlib.sha256()
78
+ with open(sys.argv[1], "rb") as f:
79
+ for chunk in iter(lambda: f.read(1024 * 1024), b""):
80
+ h.update(chunk)
81
+ print(h.hexdigest())
82
+ PY
83
+ )"
84
+ [[ "$actual_sha" == "$expected_sha" ]] || fail "SHA-256 mismatch for downloaded release"
85
+ say "✓ SHA-256 verified"
86
+
87
+ package_dir="$TMP_DIR/package"
88
+ mkdir -p "$package_dir"
89
+ case "$archive_format" in
90
+ tar.gz)
91
+ command -v tar >/dev/null 2>&1 || fail "tar is required"
92
+ tar -xzf "$archive" -C "$package_dir"
93
+ ;;
94
+ zip)
95
+ command -v unzip >/dev/null 2>&1 || fail "unzip is required"
96
+ unzip -q "$archive" -d "$package_dir"
97
+ ;;
98
+ esac
99
+
100
+ install_script="$(find "$package_dir" -type f -name install.sh -print | head -n 1)"
101
+ [[ -n "$install_script" ]] || fail "release package does not contain install.sh"
102
+ extracted_root="$(cd "$(dirname "$install_script")" && pwd)"
103
+
104
+ versions_dir="$STATE_DIR/versions"
105
+ version_dir="$versions_dir/$version"
106
+ staged_version_dir="$versions_dir/.${version}.installing.$$"
107
+ mkdir -p "$versions_dir"
108
+ rm -rf "$staged_version_dir"
109
+ mkdir -p "$staged_version_dir"
110
+ cp -R "$extracted_root"/. "$staged_version_dir"/
111
+ [[ -f "$staged_version_dir/install.sh" ]] || fail "staged release package is incomplete"
112
+ rm -rf "$version_dir"
113
+ mv "$staged_version_dir" "$version_dir"
114
+
115
+ say "→ Installing codex-flow v$version"
116
+ (
117
+ cd "$version_dir"
118
+ bash ./install.sh
119
+ )
120
+
121
+ if [[ "$os" == "darwin" ]]; then
122
+ flowpilot="$STATE_DIR/bin/FlowPilot"
123
+ legacy_overlay="$STATE_DIR/bin/codex-flow-overlay"
124
+ if [[ -s "$flowpilot" && -x "$flowpilot" ]]; then
125
+ overlay_bin="$flowpilot"
126
+ elif [[ -s "$legacy_overlay" && -x "$legacy_overlay" ]]; then
127
+ overlay_bin="$legacy_overlay"
128
+ else
129
+ fail "macOS release installed successfully, but no prebuilt FlowPilot binary was found"
130
+ fi
131
+
132
+ say "→ Starting FlowPilot"
133
+ "$overlay_bin" stop >/dev/null 2>&1 || true
134
+ pkill -f "FlowPilot.*start|codex-flow-overlay.*start|bin/FlowPilot" 2>/dev/null || true
135
+ sleep 0.2
136
+ nohup "$overlay_bin" start >/dev/null 2>&1 &
137
+ disown $! 2>/dev/null || true
138
+ sleep 0.4
139
+
140
+ if pgrep -f "FlowPilot.*start|codex-flow-overlay.*start|bin/FlowPilot" >/dev/null 2>&1; then
141
+ say "✓ FlowPilot is running in the background"
142
+ else
143
+ say "! codex-flow installed, but FlowPilot did not stay running. Retry with: codex-flow overlay start" >&2
144
+ fi
145
+ fi
146
+
147
+ doctor="$STATE_DIR/doctor.py"
148
+ if [[ -f "$doctor" ]]; then
149
+ say "→ Running doctor"
150
+ python3 "$doctor"
151
+ fi
152
+
153
+ say ""
154
+ say "✓ codex-flow v$version installation complete"
155
+ say " Fully restart Codex to activate the new Agent / Skill / Hook / policy snapshot."