code-coordinator 0.5.46__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.
- code_coordinator-0.5.46.dist-info/METADATA +625 -0
- code_coordinator-0.5.46.dist-info/RECORD +295 -0
- code_coordinator-0.5.46.dist-info/WHEEL +5 -0
- code_coordinator-0.5.46.dist-info/entry_points.txt +2 -0
- code_coordinator-0.5.46.dist-info/licenses/LICENSE +110 -0
- code_coordinator-0.5.46.dist-info/top_level.txt +1 -0
- coord/__init__.py +176 -0
- coord/_board_mapping.py +229 -0
- coord/acceptance.py +468 -0
- coord/acceptance_drivers.py +632 -0
- coord/agent.py +7517 -0
- coord/agent_app.py +1555 -0
- coord/agent_update.py +417 -0
- coord/agents/opencode/.gitignore +13 -0
- coord/agents/opencode/agents/work.md +129 -0
- coord/agents/opencode/routing.jsonc +49 -0
- coord/audit.py +301 -0
- coord/auto_loop.py +1440 -0
- coord/board_bool_guard.py +72 -0
- coord/board_service.py +141 -0
- coord/board_wire.py +309 -0
- coord/brain.py +581 -0
- coord/branch_model.py +214 -0
- coord/cargo_cache.py +258 -0
- coord/ci_github.py +386 -0
- coord/ci_store.py +560 -0
- coord/claim.py +353 -0
- coord/cli.py +454 -0
- coord/client.py +610 -0
- coord/commands/__init__.py +1 -0
- coord/commands/_common.py +329 -0
- coord/commands/acceptance.py +916 -0
- coord/commands/agent_ops.py +1339 -0
- coord/commands/audit.py +131 -0
- coord/commands/chat.py +320 -0
- coord/commands/dispatch.py +1780 -0
- coord/commands/dispatch_workers.py +4894 -0
- coord/commands/drive.py +616 -0
- coord/commands/drive_queue.py +1203 -0
- coord/commands/gate_a.py +217 -0
- coord/commands/gates.py +89 -0
- coord/commands/issues.py +681 -0
- coord/commands/lifecycle.py +513 -0
- coord/commands/merge.py +1900 -0
- coord/commands/milestone.py +2081 -0
- coord/commands/plan_followup.py +1243 -0
- coord/commands/plans.py +156 -0
- coord/commands/release.py +2232 -0
- coord/commands/report.py +341 -0
- coord/commands/review.py +1523 -0
- coord/commands/scorecard.py +252 -0
- coord/commands/sessions.py +1930 -0
- coord/commands/setup.py +576 -0
- coord/commands/status.py +2089 -0
- coord/commands/terminal.py +385 -0
- coord/commands/test_gate.py +775 -0
- coord/commands/tui.py +288 -0
- coord/comments.py +718 -0
- coord/config.py +3032 -0
- coord/conflict_fix.py +633 -0
- coord/dao.py +483 -0
- coord/dashboard/__init__.py +0 -0
- coord/dashboard/fixture.py +376 -0
- coord/dashboard/index.html +658 -0
- coord/dashboard/server.py +1894 -0
- coord/dashboard/terminal.py +382 -0
- coord/dashboard/webapp/.gitignore +9 -0
- coord/dashboard/webapp/components.json +17 -0
- coord/dashboard/webapp/dist/assets/Gallery-da3qNiIw.js +71 -0
- coord/dashboard/webapp/dist/assets/Terminal-9CEnUXvW.css +32 -0
- coord/dashboard/webapp/dist/assets/Terminal-skVFCxPU.js +63 -0
- coord/dashboard/webapp/dist/assets/index-DltfZR5f.js +184 -0
- coord/dashboard/webapp/dist/assets/index-Dq4kwTdw.css +1 -0
- coord/dashboard/webapp/dist/assets/workbox-window.prod.es5-BqEJf4Xk.js +2 -0
- coord/dashboard/webapp/dist/icons/icon-192.png +0 -0
- coord/dashboard/webapp/dist/icons/icon-512.png +0 -0
- coord/dashboard/webapp/dist/icons/icon.svg +5 -0
- coord/dashboard/webapp/dist/index.html +38 -0
- coord/dashboard/webapp/dist/manifest.webmanifest +1 -0
- coord/dashboard/webapp/dist/sw.js +1 -0
- coord/dashboard/webapp/dist/workbox-e4022e15.js +1 -0
- coord/dashboard/webapp/e2e/available-gates-terminal.spec.ts +75 -0
- coord/dashboard/webapp/e2e/deep-link.spec.ts +172 -0
- coord/dashboard/webapp/e2e/fixtureServer.ts +155 -0
- coord/dashboard/webapp/e2e/live-update-fixture.spec.ts +113 -0
- coord/dashboard/webapp/e2e/realtime.spec.ts +238 -0
- coord/dashboard/webapp/e2e/shell.spec.ts +309 -0
- coord/dashboard/webapp/e2e/smoke.spec.ts +191 -0
- coord/dashboard/webapp/e2e/terminal.spec.ts +420 -0
- coord/dashboard/webapp/e2e/theme.spec.ts +138 -0
- coord/dashboard/webapp/eslint.config.js +20 -0
- coord/dashboard/webapp/index.html +37 -0
- coord/dashboard/webapp/node_modules/flatted/python/flatted.py +144 -0
- coord/dashboard/webapp/package-lock.json +10584 -0
- coord/dashboard/webapp/package.json +63 -0
- coord/dashboard/webapp/playwright.acceptance.config.ts +166 -0
- coord/dashboard/webapp/playwright.config.ts +93 -0
- coord/dashboard/webapp/postcss.config.js +6 -0
- coord/dashboard/webapp/public/icons/icon-192.png +0 -0
- coord/dashboard/webapp/public/icons/icon-512.png +0 -0
- coord/dashboard/webapp/public/icons/icon.svg +5 -0
- coord/dashboard/webapp/src/App.tsx +140 -0
- coord/dashboard/webapp/src/api/client.ts +199 -0
- coord/dashboard/webapp/src/api/generated.ts +176 -0
- coord/dashboard/webapp/src/components/ConnectionBadge.tsx +52 -0
- coord/dashboard/webapp/src/components/Detail.tsx +800 -0
- coord/dashboard/webapp/src/components/Gallery.tsx +341 -0
- coord/dashboard/webapp/src/components/Home.tsx +435 -0
- coord/dashboard/webapp/src/components/MobileKeyBar.tsx +280 -0
- coord/dashboard/webapp/src/components/PanelHeader.tsx +59 -0
- coord/dashboard/webapp/src/components/PipelineCard.tsx +168 -0
- coord/dashboard/webapp/src/components/SessionCard.tsx +99 -0
- coord/dashboard/webapp/src/components/SessionDetail.tsx +140 -0
- coord/dashboard/webapp/src/components/SessionsList.tsx +81 -0
- coord/dashboard/webapp/src/components/Terminal.tsx +376 -0
- coord/dashboard/webapp/src/components/__tests__/ConnectionBadge.test.tsx +81 -0
- coord/dashboard/webapp/src/components/__tests__/Detail.test.tsx +680 -0
- coord/dashboard/webapp/src/components/__tests__/Gallery.test.tsx +83 -0
- coord/dashboard/webapp/src/components/__tests__/Home.test.tsx +271 -0
- coord/dashboard/webapp/src/components/__tests__/MobileKeyBar.test.tsx +197 -0
- coord/dashboard/webapp/src/components/__tests__/PipelineCard.test.tsx +143 -0
- coord/dashboard/webapp/src/components/__tests__/SessionCard.test.tsx +106 -0
- coord/dashboard/webapp/src/components/__tests__/Terminal.test.tsx +504 -0
- coord/dashboard/webapp/src/components/ui/badge.tsx +41 -0
- coord/dashboard/webapp/src/components/ui/button.tsx +54 -0
- coord/dashboard/webapp/src/components/ui/card.tsx +55 -0
- coord/dashboard/webapp/src/components/ui/dialog.tsx +99 -0
- coord/dashboard/webapp/src/components/ui/dropdown-menu.tsx +189 -0
- coord/dashboard/webapp/src/components/ui/empty-state.tsx +35 -0
- coord/dashboard/webapp/src/components/ui/sheet.tsx +123 -0
- coord/dashboard/webapp/src/components/ui/skeleton.tsx +9 -0
- coord/dashboard/webapp/src/components/ui/tabs.tsx +55 -0
- coord/dashboard/webapp/src/components/ui/theme-provider.tsx +78 -0
- coord/dashboard/webapp/src/components/ui/theme-toggle.tsx +20 -0
- coord/dashboard/webapp/src/components/ui/toast.tsx +123 -0
- coord/dashboard/webapp/src/components/ui/toaster.tsx +30 -0
- coord/dashboard/webapp/src/components/ui/tooltip.tsx +26 -0
- coord/dashboard/webapp/src/components/ui/use-toast.ts +134 -0
- coord/dashboard/webapp/src/index.css +210 -0
- coord/dashboard/webapp/src/lib/pipeline.ts +29 -0
- coord/dashboard/webapp/src/lib/utils.ts +6 -0
- coord/dashboard/webapp/src/main.tsx +46 -0
- coord/dashboard/webapp/src/realtime/RealtimeProvider.tsx +112 -0
- coord/dashboard/webapp/src/realtime/__tests__/RealtimeProvider.test.tsx +189 -0
- coord/dashboard/webapp/src/realtime/__tests__/connection.test.ts +255 -0
- coord/dashboard/webapp/src/realtime/connection.ts +227 -0
- coord/dashboard/webapp/src/realtime/events.ts +100 -0
- coord/dashboard/webapp/src/routes/__tests__/paths.test.ts +92 -0
- coord/dashboard/webapp/src/routes/paths.ts +92 -0
- coord/dashboard/webapp/src/shell/ActivityRail.tsx +335 -0
- coord/dashboard/webapp/src/shell/AppShell.tsx +276 -0
- coord/dashboard/webapp/src/shell/ComingSoon.tsx +33 -0
- coord/dashboard/webapp/src/shell/EmptyDetail.tsx +26 -0
- coord/dashboard/webapp/src/shell/RouteNotFound.tsx +33 -0
- coord/dashboard/webapp/src/shell/ShellLayout.tsx +147 -0
- coord/dashboard/webapp/src/shell/StatusBar.tsx +46 -0
- coord/dashboard/webapp/src/shell/__tests__/ShellLayout.test.tsx +520 -0
- coord/dashboard/webapp/src/shell/__tests__/shellState.test.ts +95 -0
- coord/dashboard/webapp/src/shell/__tests__/stubViewport.ts +40 -0
- coord/dashboard/webapp/src/shell/breakpoints.ts +87 -0
- coord/dashboard/webapp/src/shell/railItems.ts +105 -0
- coord/dashboard/webapp/src/shell/shellState.ts +174 -0
- coord/dashboard/webapp/src/shell/useRegionFocus.ts +95 -0
- coord/dashboard/webapp/src/test-setup.ts +41 -0
- coord/dashboard/webapp/src/vite-env.d.ts +2 -0
- coord/dashboard/webapp/tailwind.config.js +140 -0
- coord/dashboard/webapp/tsconfig.json +25 -0
- coord/dashboard/webapp/tsconfig.node.json +11 -0
- coord/dashboard/webapp/vite.config.ts +71 -0
- coord/db.py +1076 -0
- coord/dead_end.py +332 -0
- coord/deploy/README.md +33 -0
- coord/deploy/coord-agent.service +89 -0
- coord/deploy/coord-db-backup.service +60 -0
- coord/deploy/coord-db-backup.sh +74 -0
- coord/deploy/coord-db-backup.timer +18 -0
- coord/deploy/coord-drive-queue.service +117 -0
- coord/deploy/coord-drive-queue.timer +39 -0
- coord/deploy/coord-notify.service +48 -0
- coord/deploy/coord-notify.timer +24 -0
- coord/deploy/coord-release-propagate.service +83 -0
- coord/deploy/coord-release-propagate.timer +38 -0
- coord/deploy/coord-release-window.service +119 -0
- coord/deploy/coord-release-window.timer +36 -0
- coord/deploy/coord-serve.service +82 -0
- coord/deploy/coord-web-dist-build.service +43 -0
- coord/deploy/coord-web-dist-build.timer +36 -0
- coord/deploy/coord-web.service +125 -0
- coord/deploy_manifest.py +80 -0
- coord/deploy_units.py +384 -0
- coord/deps.py +115 -0
- coord/diagnose.py +1623 -0
- coord/dispatch.py +1009 -0
- coord/dist_name.py +123 -0
- coord/drive.py +3101 -0
- coord/drive_queue.py +2298 -0
- coord/drive_state.py +870 -0
- coord/events.py +381 -0
- coord/failure_class.py +914 -0
- coord/filelock.py +168 -0
- coord/fleet_config_health.py +300 -0
- coord/freshness.py +206 -0
- coord/gate_a.py +469 -0
- coord/gate_b.py +411 -0
- coord/gate_snapshot.py +385 -0
- coord/gates.py +582 -0
- coord/github_ops.py +1954 -0
- coord/goal.py +125 -0
- coord/graph_health.py +348 -0
- coord/health/__init__.py +69 -0
- coord/health/aggregate.py +129 -0
- coord/health/checks/__init__.py +13 -0
- coord/health/checks/agent_install.py +280 -0
- coord/health/checks/cargo_targets.py +171 -0
- coord/health/checks/claude_binary.py +65 -0
- coord/health/checks/deploy_lane_facts.py +458 -0
- coord/health/checks/disk.py +99 -0
- coord/health/checks/fleet_board.py +89 -0
- coord/health/checks/fleet_deploy_lanes.py +469 -0
- coord/health/checks/fleet_phantom.py +69 -0
- coord/health/checks/fleet_unit_drift.py +151 -0
- coord/health/checks/graph.py +192 -0
- coord/health/checks/plan_usage.py +88 -0
- coord/health/checks/repo_state.py +161 -0
- coord/health/checks/spawned_coord.py +465 -0
- coord/health/checks/timer_active.py +254 -0
- coord/health/checks/toolchain.py +547 -0
- coord/health/checks/unit_drift.py +648 -0
- coord/health/checks/unit_enablement.py +171 -0
- coord/health/checks/worktrees.py +96 -0
- coord/health/cli.py +121 -0
- coord/health/context.py +106 -0
- coord/health/fleet_snapshot.py +477 -0
- coord/health/models.py +250 -0
- coord/health/pypi.py +231 -0
- coord/health/registry.py +240 -0
- coord/health/render.py +82 -0
- coord/health/units.py +60 -0
- coord/hooks.py +106 -0
- coord/housekeeping.py +204 -0
- coord/interactive.py +4286 -0
- coord/issue_store.py +1496 -0
- coord/liveness_auditor.py +293 -0
- coord/machine_pause.py +755 -0
- coord/merge_queue.py +4681 -0
- coord/milestone_chat.py +600 -0
- coord/milestone_dispatch.py +943 -0
- coord/milestone_gate.py +709 -0
- coord/milestone_order.py +840 -0
- coord/mock_author.py +334 -0
- coord/models.py +891 -0
- coord/network.py +269 -0
- coord/new_issue_chat.py +229 -0
- coord/notify.py +3226 -0
- coord/openapi.py +404 -0
- coord/overlap_fence.py +133 -0
- coord/parentage.py +200 -0
- coord/parentage_github.py +58 -0
- coord/pipeline.py +481 -0
- coord/plan_parser.py +266 -0
- coord/plans.py +543 -0
- coord/platform_paths.py +43 -0
- coord/pr_body_lint.py +67 -0
- coord/prereqs.py +533 -0
- coord/progress.py +425 -0
- coord/providers/__init__.py +683 -0
- coord/providers/base.py +218 -0
- coord/providers/claude.py +284 -0
- coord/providers/claude_pty.py +610 -0
- coord/providers/opencode.py +896 -0
- coord/reconcile.py +2233 -0
- coord/refine_chat.py +485 -0
- coord/release_cordon.py +525 -0
- coord/release_propagate.py +1176 -0
- coord/release_verify.py +777 -0
- coord/release_window.py +322 -0
- coord/reports.py +1643 -0
- coord/revalidate.py +1101 -0
- coord/review.py +3317 -0
- coord/scorecard.py +484 -0
- coord/serve_app.py +7192 -0
- coord/skills/update-issue/SKILL.md +93 -0
- coord/smoke.py +1030 -0
- coord/split_work.py +210 -0
- coord/stage_projection.py +650 -0
- coord/state.py +5720 -0
- coord/test_author.py +1064 -0
- coord/test_chat.py +352 -0
- coord/test_orchestrator.py +494 -0
- coord/test_report.py +178 -0
- coord/tui_release.py +271 -0
- coord/usage.py +753 -0
- coord/usage_limits.py +358 -0
- coord/usage_rollup.py +709 -0
- coord/worker_events.py +954 -0
coord/commands/tui.py
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"""`coord tui` — self-update the coord-tui binary from this coordinator's
|
|
2
|
+
own GitHub Release channel (#1240, PKG-4).
|
|
3
|
+
|
|
4
|
+
PKG-3 (#1239) put ``coord-tui-<target>`` binaries on the GitHub Release; the
|
|
5
|
+
gap this closes is that a user still had to find the right asset, download
|
|
6
|
+
it, `chmod +x` it, and place it by hand. `coord tui update` does all of
|
|
7
|
+
that in one command, and `coord tui status` (also what a bare `coord tui`
|
|
8
|
+
runs) is the "lightweight version-skew notice" the issue asks for — a
|
|
9
|
+
local, on-demand check, not something bolted onto `main()`'s callback and
|
|
10
|
+
paid by every `coord` invocation.
|
|
11
|
+
|
|
12
|
+
The actual resolve/download/install mechanics live in
|
|
13
|
+
:mod:`coord.tui_release`, framework-agnostic so they're unit-testable
|
|
14
|
+
without going through Click at all; this module is just the CLI wiring.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import sys
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
import click
|
|
23
|
+
|
|
24
|
+
from coord import __version__
|
|
25
|
+
from coord.tui_release import (
|
|
26
|
+
DEFAULT_API_BASE,
|
|
27
|
+
DEFAULT_INSTALL_PATH,
|
|
28
|
+
DEFAULT_REPO,
|
|
29
|
+
DEV_BUILD_SENTINEL_VERSION,
|
|
30
|
+
ReleaseAssetNotFoundError,
|
|
31
|
+
UnsupportedPlatformError,
|
|
32
|
+
detect_target,
|
|
33
|
+
download_asset,
|
|
34
|
+
fetch_release_assets,
|
|
35
|
+
find_asset,
|
|
36
|
+
find_checksum_asset,
|
|
37
|
+
install_atomically,
|
|
38
|
+
read_installed_version,
|
|
39
|
+
sha256_file,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _dest_path(dest: str | None) -> Path:
|
|
44
|
+
return Path(dest).expanduser() if dest else Path(DEFAULT_INSTALL_PATH).expanduser()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@click.group(
|
|
48
|
+
"tui",
|
|
49
|
+
invoke_without_command=True,
|
|
50
|
+
help=(
|
|
51
|
+
"Manage the coord-tui binary. Without a subcommand, runs `coord tui "
|
|
52
|
+
"status` (installed coord-tui version vs. this coordinator's own "
|
|
53
|
+
f"version, {DEFAULT_INSTALL_PATH} by default)."
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
@click.pass_context
|
|
57
|
+
def tui_group(ctx: click.Context) -> None:
|
|
58
|
+
if ctx.invoked_subcommand is None:
|
|
59
|
+
ctx.invoke(tui_status)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@tui_group.command(
|
|
63
|
+
"status",
|
|
64
|
+
help=(
|
|
65
|
+
"Print the installed coord-tui version next to this coordinator's "
|
|
66
|
+
"own version, and hint at `coord tui update` on skew. Purely local "
|
|
67
|
+
"-- reads `<dest> --version`, no network call -- so it's cheap "
|
|
68
|
+
"enough to run on demand without adding it to every `coord` "
|
|
69
|
+
"invocation's hot path."
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
@click.option(
|
|
73
|
+
"--dest",
|
|
74
|
+
default=None,
|
|
75
|
+
help=f"Path to the coord-tui binary to check. Default: {DEFAULT_INSTALL_PATH}",
|
|
76
|
+
)
|
|
77
|
+
def tui_status(dest: str | None) -> None:
|
|
78
|
+
_print_skew_notice(_dest_path(dest))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _print_skew_notice(binary_path: Path) -> bool:
|
|
82
|
+
"""Print installed-vs-coordinator version lines. Returns True on skew
|
|
83
|
+
(including "not installed at all"), False when they match."""
|
|
84
|
+
if not binary_path.exists():
|
|
85
|
+
click.echo(f"coord-tui: not installed at {binary_path}")
|
|
86
|
+
click.echo(f"coord: {__version__}")
|
|
87
|
+
click.echo("Run `coord tui update` to install it.")
|
|
88
|
+
return True
|
|
89
|
+
|
|
90
|
+
installed = read_installed_version(binary_path)
|
|
91
|
+
if installed is None:
|
|
92
|
+
click.echo(f"coord-tui: {binary_path} did not report a parseable --version")
|
|
93
|
+
click.echo(f"coord: {__version__}")
|
|
94
|
+
click.echo("Run `coord tui update` to reinstall it.")
|
|
95
|
+
return True
|
|
96
|
+
|
|
97
|
+
click.echo(f"coord-tui: {installed} ({binary_path})")
|
|
98
|
+
click.echo(f"coord: {__version__}")
|
|
99
|
+
if installed != __version__:
|
|
100
|
+
click.echo(
|
|
101
|
+
"⚠ version skew — run `coord tui update` to match this "
|
|
102
|
+
"coordinator's version."
|
|
103
|
+
)
|
|
104
|
+
return True
|
|
105
|
+
click.echo("✓ up to date")
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@tui_group.command(
|
|
110
|
+
"update",
|
|
111
|
+
help=(
|
|
112
|
+
"Download the coord-tui binary matching this coordinator's own "
|
|
113
|
+
"version (coord --version) from its GitHub Release, and install "
|
|
114
|
+
"it.\n\n"
|
|
115
|
+
"Platform detection: maps this host's `platform.system()`/"
|
|
116
|
+
"`platform.machine()` to one of release-tui.yml's build-matrix "
|
|
117
|
+
"targets (x86_64-linux, x86_64-macos, aarch64-macos, "
|
|
118
|
+
"x86_64-windows) and downloads the matching `coord-tui-<target>` "
|
|
119
|
+
"asset from the GitHub Release tagged v<version>.\n\n"
|
|
120
|
+
f"Install path: {DEFAULT_INSTALL_PATH} by default, override with "
|
|
121
|
+
"--dest. The download always lands in a temp file next to the "
|
|
122
|
+
"destination first -- chmod +x'd and checksum-verified (when the "
|
|
123
|
+
"release publishes one) before an atomic rename into place -- so a "
|
|
124
|
+
"running coord-tui, or an interrupted download, never observes a "
|
|
125
|
+
"partial binary.\n\n"
|
|
126
|
+
"Dev-checkout guard: tui/Cargo.toml's committed [package] version "
|
|
127
|
+
f"is the {DEV_BUILD_SENTINEL_VERSION!r} placeholder that only "
|
|
128
|
+
"release-tui.yml's CI build stamps a real version over (never "
|
|
129
|
+
"committed back) -- so a plain local `cargo build` always reports "
|
|
130
|
+
f"exactly {DEV_BUILD_SENTINEL_VERSION!r}. If the binary already at "
|
|
131
|
+
"--dest reports that sentinel, this refuses to overwrite it "
|
|
132
|
+
"(assuming a developer is iterating on a local build) unless "
|
|
133
|
+
"--force is given."
|
|
134
|
+
),
|
|
135
|
+
)
|
|
136
|
+
@click.option(
|
|
137
|
+
"--version",
|
|
138
|
+
"version_override",
|
|
139
|
+
default=None,
|
|
140
|
+
help="Install this exact version instead of this coordinator's own version (coord --version).",
|
|
141
|
+
)
|
|
142
|
+
@click.option(
|
|
143
|
+
"--dest",
|
|
144
|
+
default=None,
|
|
145
|
+
help=f"Where to install the binary. Default: {DEFAULT_INSTALL_PATH}",
|
|
146
|
+
)
|
|
147
|
+
@click.option(
|
|
148
|
+
"--repo",
|
|
149
|
+
default=DEFAULT_REPO,
|
|
150
|
+
show_default=True,
|
|
151
|
+
help="GitHub owner/repo the release lives on.",
|
|
152
|
+
)
|
|
153
|
+
@click.option(
|
|
154
|
+
"--api-base",
|
|
155
|
+
default=DEFAULT_API_BASE,
|
|
156
|
+
show_default=True,
|
|
157
|
+
help="GitHub API base URL -- override to point at a stub endpoint (tests only).",
|
|
158
|
+
)
|
|
159
|
+
@click.option(
|
|
160
|
+
"--timeout",
|
|
161
|
+
default=30.0,
|
|
162
|
+
show_default=True,
|
|
163
|
+
type=float,
|
|
164
|
+
help="Per-request network timeout (seconds), for both the release lookup and the download.",
|
|
165
|
+
)
|
|
166
|
+
@click.option(
|
|
167
|
+
"--force",
|
|
168
|
+
is_flag=True,
|
|
169
|
+
help=(
|
|
170
|
+
"Overwrite an installed dev build (see the dev-checkout guard "
|
|
171
|
+
"above), and reinstall even when the destination already reports "
|
|
172
|
+
"the target version."
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
def tui_update(
|
|
176
|
+
version_override: str | None,
|
|
177
|
+
dest: str | None,
|
|
178
|
+
repo: str,
|
|
179
|
+
api_base: str,
|
|
180
|
+
timeout: float,
|
|
181
|
+
force: bool, # noqa: FBT001
|
|
182
|
+
) -> None:
|
|
183
|
+
target_version = version_override or __version__
|
|
184
|
+
dest_path = _dest_path(dest)
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
target = detect_target()
|
|
188
|
+
except UnsupportedPlatformError as exc:
|
|
189
|
+
click.echo(f"error: {exc}", err=True)
|
|
190
|
+
sys.exit(1)
|
|
191
|
+
|
|
192
|
+
if dest_path.exists() and not force:
|
|
193
|
+
installed = read_installed_version(dest_path)
|
|
194
|
+
if installed == DEV_BUILD_SENTINEL_VERSION:
|
|
195
|
+
click.echo(
|
|
196
|
+
f"refusing to overwrite {dest_path}: it reports version "
|
|
197
|
+
f"{DEV_BUILD_SENTINEL_VERSION!r}, the sentinel a locally "
|
|
198
|
+
"`cargo build`'d coord-tui always carries (tui/Cargo.toml's "
|
|
199
|
+
"committed version is only stamped for real in CI release "
|
|
200
|
+
"builds). This looks like a dev build someone is iterating "
|
|
201
|
+
"on -- pass --force to overwrite it anyway, or keep "
|
|
202
|
+
"building it yourself: cd tui && cargo build && cp "
|
|
203
|
+
f"target/debug/coord-tui {dest_path}",
|
|
204
|
+
err=True,
|
|
205
|
+
)
|
|
206
|
+
sys.exit(3)
|
|
207
|
+
if installed == target_version:
|
|
208
|
+
click.echo(
|
|
209
|
+
f"coord-tui is already v{target_version} at {dest_path} -- "
|
|
210
|
+
"nothing to do (--force to reinstall)."
|
|
211
|
+
)
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
click.echo(f"Detected platform target: {target}")
|
|
215
|
+
click.echo(f"Resolving coord-tui v{target_version} from {repo}...")
|
|
216
|
+
try:
|
|
217
|
+
assets = fetch_release_assets(
|
|
218
|
+
target_version, repo=repo, api_base=api_base, timeout=timeout
|
|
219
|
+
)
|
|
220
|
+
asset = find_asset(assets, target)
|
|
221
|
+
except ReleaseAssetNotFoundError as exc:
|
|
222
|
+
click.echo(f"error: {exc}", err=True)
|
|
223
|
+
sys.exit(1)
|
|
224
|
+
except Exception as exc: # noqa: BLE001 -- surface any network/HTTP failure plainly
|
|
225
|
+
click.echo(
|
|
226
|
+
f"error: could not resolve release v{target_version} from {repo}: {exc}",
|
|
227
|
+
err=True,
|
|
228
|
+
)
|
|
229
|
+
sys.exit(1)
|
|
230
|
+
|
|
231
|
+
checksum_asset = find_checksum_asset(assets, asset)
|
|
232
|
+
|
|
233
|
+
click.echo(f"Downloading {asset.name}...")
|
|
234
|
+
try:
|
|
235
|
+
tmp_path = download_asset(asset.download_url, dest_path.parent, timeout=timeout)
|
|
236
|
+
except Exception as exc: # noqa: BLE001
|
|
237
|
+
click.echo(f"error: download failed: {exc}", err=True)
|
|
238
|
+
sys.exit(1)
|
|
239
|
+
|
|
240
|
+
if checksum_asset is not None:
|
|
241
|
+
click.echo(f"Verifying checksum against {checksum_asset.name}...")
|
|
242
|
+
try:
|
|
243
|
+
checksum_tmp = download_asset(
|
|
244
|
+
checksum_asset.download_url, dest_path.parent, timeout=timeout
|
|
245
|
+
)
|
|
246
|
+
except Exception as exc: # noqa: BLE001
|
|
247
|
+
tmp_path.unlink(missing_ok=True)
|
|
248
|
+
click.echo(
|
|
249
|
+
f"error: could not download checksum {checksum_asset.name}: {exc}",
|
|
250
|
+
err=True,
|
|
251
|
+
)
|
|
252
|
+
sys.exit(1)
|
|
253
|
+
try:
|
|
254
|
+
expected = checksum_tmp.read_text().split()[0].strip()
|
|
255
|
+
finally:
|
|
256
|
+
checksum_tmp.unlink(missing_ok=True)
|
|
257
|
+
actual = sha256_file(tmp_path)
|
|
258
|
+
if actual != expected:
|
|
259
|
+
tmp_path.unlink(missing_ok=True)
|
|
260
|
+
click.echo(
|
|
261
|
+
f"error: checksum mismatch for {asset.name}: expected "
|
|
262
|
+
f"{expected}, got {actual}",
|
|
263
|
+
err=True,
|
|
264
|
+
)
|
|
265
|
+
sys.exit(1)
|
|
266
|
+
click.echo(f"Checksum OK ({actual}).")
|
|
267
|
+
else:
|
|
268
|
+
click.echo(
|
|
269
|
+
"(no published checksum asset for this binary -- PKG-3 does "
|
|
270
|
+
"not currently publish one, so skipping verification)"
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
try:
|
|
274
|
+
install_atomically(tmp_path, dest_path)
|
|
275
|
+
except Exception as exc: # noqa: BLE001
|
|
276
|
+
tmp_path.unlink(missing_ok=True)
|
|
277
|
+
click.echo(f"error: install failed: {exc}", err=True)
|
|
278
|
+
sys.exit(1)
|
|
279
|
+
|
|
280
|
+
installed_now = read_installed_version(dest_path)
|
|
281
|
+
click.echo(f"Installed {dest_path} -- coord-tui reports {installed_now or '?'}.")
|
|
282
|
+
if installed_now != target_version:
|
|
283
|
+
click.echo(
|
|
284
|
+
f"⚠ installed binary reports {installed_now!r}, expected "
|
|
285
|
+
f"{target_version!r} -- the release asset may be mislabeled.",
|
|
286
|
+
err=True,
|
|
287
|
+
)
|
|
288
|
+
sys.exit(1)
|