cdx-manager 0.25.6 → 0.25.8
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.
- package/README.md +1 -1
- package/VERSION +1 -1
- package/changelogs/CHANGELOGS_0_25_7.md +15 -0
- package/changelogs/CHANGELOGS_0_25_8.md +15 -0
- package/changelogs/CHANGELOGS_UNRELEASED.md +11 -2
- package/checksums/release-archives.json +22 -0
- package/docs/cli.md +13 -6
- package/docs/operations.md +39 -0
- package/docs/sessions-and-notifications.md +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/update_all.py +13 -7
- package/src/workspace_sandbox.py +21 -8
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<br clear="left"/>
|
|
6
6
|
|
|
7
|
-
[](LICENSE) ](LICENSE)  
|
|
8
8
|
|
|
9
9
|
**The right AI coding account, when you need it.** CDX Manager keeps your Codex and Claude accounts in separate profiles, shows which ones have quota, and helps you pick the next usable session from your terminal.
|
|
10
10
|
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.25.
|
|
1
|
+
0.25.8
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# CDX Manager 0.25.7
|
|
2
|
+
|
|
3
|
+
Release date: 2026-11-02
|
|
4
|
+
|
|
5
|
+
This patch release corrects Antigravity CLI update detection and verification.
|
|
6
|
+
|
|
7
|
+
## Fixes
|
|
8
|
+
|
|
9
|
+
- Stop comparing Antigravity CLI (`agy`) versions against the editor release feed. Report the latest CLI version as unknown and let the native `agy update` command check and apply updates after confirmation, including with `--yes`. Inventory collection remains read-only. (#89)
|
|
10
|
+
- Accept a successful updater's explicit `You are already on the latest version.` message on stdout or stderr when the installed version is unchanged. Otherwise require a verified version increase reaching the published version when known, and preserve updater failures. (#89)
|
|
11
|
+
|
|
12
|
+
## Maintenance
|
|
13
|
+
|
|
14
|
+
- Record tray companion checksums for v0.25.6. (`53500823f04edb69be9563d327645148439644a6`)
|
|
15
|
+
- Record release archive checksums for v0.25.6. (`974dfb0cac31963883456bda4beddb19b8940152`)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# CDX Manager 0.25.8
|
|
2
|
+
|
|
3
|
+
Release date: 2026-11-02
|
|
4
|
+
|
|
5
|
+
This patch release restores Git history and RTK access in isolated workspaces.
|
|
6
|
+
|
|
7
|
+
## Fixes
|
|
8
|
+
|
|
9
|
+
- Restore read-only Git history access in isolated local and remote workspaces, including linked worktrees with packed objects and refs. Keep Git metadata read-only and exclude host configuration, hooks, remotes, and credentials. (#91)
|
|
10
|
+
- Expose the installed RTK binary in isolated launches and persist its savings history in a dedicated shared cache, separate from the operator's normal RTK history. (#91)
|
|
11
|
+
|
|
12
|
+
## Maintenance
|
|
13
|
+
|
|
14
|
+
- Record tray companion checksums for v0.25.7. (`31b7ecfb8f8189f29b01aaa88f9acf866acccd19`)
|
|
15
|
+
- Record release archive checksums for v0.25.7. (`03d339b9e93e2d7d917df6e614132390ce4436fe`)
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
# Unreleased
|
|
2
2
|
|
|
3
|
+
## Isolated mission Git and RTK
|
|
4
|
+
|
|
5
|
+
- Give local and remote isolated linked worktrees a read-only Git view with their own HEAD/index and shared objects/refs, without traversing private host parents or exposing repository/global configuration, hooks, SSH keys or Git push credentials. Preserve supervisor-owned commits and pushes.
|
|
6
|
+
- Add the mounted operator `~/.local/bin` to sandbox PATH and persist RTK savings in the execution host's shared cache at `/cache/rtk/history.db`, overriding inaccessible host history paths for isolated launches only.
|
|
7
|
+
- Cover real Git commands against selected metadata, local and shipped worker launch environments, and an opt-in required bubblewrap acceptance check for Git, RTK history writes, review mode and an unreadable synthetic SSH key. Document the namespace requirement and sandbox history location.
|
|
8
|
+
|
|
3
9
|
## Truthful workstation updates
|
|
4
10
|
|
|
5
|
-
-
|
|
11
|
+
- Stop querying the editor release feed for the Antigravity CLI: its versions do not match `agy`. Keep `latest_version: null` and `status: unknown`, while still running the native `agy update` with `--yes` or confirmation. No read-only latest-version check is documented by `agy update --help`.
|
|
12
|
+
- Accept a successful native updater's `You are already on the latest version.` message when the installed version is unchanged, or verify a version increase against the published version when known. Preserve updater failures and unknown inventory status. Cover the real Antigravity output line, version increases, failures, and JSON/text uncertainty.
|
|
13
|
+
|
|
14
|
+
- Detect advertised native updater subcommands in both stdout and stderr; use Antigravity's known `agy update` command directly. Verify the installed CLI version after updating, fail unverified updates unless an unchanged version is explicitly confirmed current by the updater, and expose before/after versions without hiding major upgrades.
|
|
6
15
|
- Fall back from empty or failed Ollama vendor responses (including Linux HTTP 204) to the latest stable `ollama/ollama` GitHub release. Keep Linux updates manual with `update_available`, a null command, and a service-safety reason; never replace a potentially active binary or restart models automatically.
|
|
7
16
|
|
|
8
|
-
- Verify latest versions from npm, RTK GitHub releases, and
|
|
17
|
+
- Verify latest versions from npm, RTK GitHub releases, and Ollama vendor update endpoints with short read-only probes. Report `unknown` on unavailable evidence; reserve `up_to_date` for identical known versions, including Ponytail revisions.
|
|
9
18
|
- Preserve the existing JSON fields and `update_available` status, show uncertainty and manual-update reasons in text, and apply only supported native commands or verified Homebrew package upgrades. Cover matching/outdated versions, source failures, missing tools, and command execution with faked sources.
|
|
10
19
|
|
|
11
20
|
## Dependency security
|
|
@@ -749,6 +749,28 @@
|
|
|
749
749
|
"x86_64-pc-windows-msvc": "85945b30580cb82c64ece94652ae0633a6156dfd85e02108c0d4b7676cab9911",
|
|
750
750
|
"x86_64-unknown-linux-musl": "7c5a23938b84c5952be71b5956ed3167c218d05ce661940b0c86f2dde2d8221f"
|
|
751
751
|
}
|
|
752
|
+
},
|
|
753
|
+
"v0.25.6": {
|
|
754
|
+
"github_tarball_sha256": "27663ea4f9c70aafb1d2180d36563ab10d91b9cb336cb3285ed4fd610e698bed",
|
|
755
|
+
"github_zip_sha256": "ba645956971ddd9446389717ad48a74dfb426ff7290c5ebc100ca9e3c2a91d3f",
|
|
756
|
+
"tray_assets": {
|
|
757
|
+
"aarch64-apple-darwin": "41b8d1a0b098407a49fc66ef2b49fbf8283f46f6393f34fae05d0ee3b84fcd1b",
|
|
758
|
+
"aarch64-unknown-linux-musl": "ba88584f8ba6399572961feb4d7bcc056096d3aa398d863bc0e248e57086434e",
|
|
759
|
+
"x86_64-apple-darwin": "ddd032fe6306585397c4c4a461de28cafea5519eb08502224fb5ad87a249b05a",
|
|
760
|
+
"x86_64-pc-windows-msvc": "5c3c4be1dcf6801ed0ed73bef8840deb379e2724d9728f983498d0fe5a99c542",
|
|
761
|
+
"x86_64-unknown-linux-musl": "ba91c1378b78e529da3af35c7e649ed2063ba27963ef91949f1aabe9e3fe2a0f"
|
|
762
|
+
}
|
|
763
|
+
},
|
|
764
|
+
"v0.25.7": {
|
|
765
|
+
"github_tarball_sha256": "e9a943ca212e0706f5a3ad29d9be99b8bf5293836d4f082dddd797e122475310",
|
|
766
|
+
"github_zip_sha256": "19eb0266ed35aae2386fd9d90079a7be5dbc44a3b44249615c244fc7c4f7d85f",
|
|
767
|
+
"tray_assets": {
|
|
768
|
+
"aarch64-apple-darwin": "9fa198f0133ac40747fb00f4353af174b45b550ebef4662398b84aa9459e2388",
|
|
769
|
+
"aarch64-unknown-linux-musl": "c4ccba259e7f910bd5a2ce8abfa2045ba4ad9b975da7dea2c8dfc0ba1bd5bbfc",
|
|
770
|
+
"x86_64-apple-darwin": "1341e59d8da3489368e22c85c9ea3d974254c810d3b68077b2e1b02d2c9aee5a",
|
|
771
|
+
"x86_64-pc-windows-msvc": "be2e6ff8607351019447c6fbf0622254c2f8d8db81581007af71b74932e37f50",
|
|
772
|
+
"x86_64-unknown-linux-musl": "32de07569929ade136cf75ed8f0716e0f3b96a9c53c6632c628e13782d223518"
|
|
773
|
+
}
|
|
752
774
|
}
|
|
753
775
|
}
|
|
754
776
|
}
|
package/docs/cli.md
CHANGED
|
@@ -560,11 +560,14 @@ Versions and commands are explicitly `null` when unavailable.
|
|
|
560
560
|
- `not_installed`: the executable is absent; no installation is guessed.
|
|
561
561
|
|
|
562
562
|
Checks use the npm registry for Codex and `@anthropic-ai/claude-code`, GitHub's
|
|
563
|
-
`rtk-ai/rtk` latest stable release,
|
|
564
|
-
`/releases` feed for `agy`, and Ollama's own `/api/update` endpoint with the local
|
|
563
|
+
`rtk-ai/rtk` latest stable release, and Ollama's own `/api/update` endpoint with the local
|
|
565
564
|
OS/architecture and baseline version `0.0.0`. Ollama's local `/api/version` reports
|
|
566
565
|
an installed server, not the latest published release, and is not used.
|
|
567
|
-
Antigravity
|
|
566
|
+
Antigravity's editor `/releases` feed does not describe the `agy` CLI and is not
|
|
567
|
+
queried. `agy update --help` documents no read-only version check, so its latest
|
|
568
|
+
CLI version stays unknown (`latest_version: null`, `status: unknown`). CDX still
|
|
569
|
+
includes `agy update`, the CLI's own updater, in the plan. It runs only with
|
|
570
|
+
`--yes` or confirmation. Inventory collection never runs that updater.
|
|
568
571
|
HTTP and read-only CLI probes have a five-second timeout; source failures leave
|
|
569
572
|
`latest_version: null` and `status: unknown`. Ponytail also reports `unknown`
|
|
570
573
|
when its remote revision is unavailable. An empty, failed, or invalid Ollama
|
|
@@ -573,7 +576,7 @@ release for `ollama/ollama`. If that source also fails, status is `unknown`;
|
|
|
573
576
|
a different platform's vendor response is never substituted.
|
|
574
577
|
|
|
575
578
|
For an outdated tool, CDX uses a native update command advertised by its
|
|
576
|
-
`--help` on either stdout or stderr (including Claude
|
|
579
|
+
`--help` on either stdout or stderr (including Claude and RTK
|
|
577
580
|
when available), Codex's updater,
|
|
578
581
|
or Homebrew only when the resolved executable belongs to a Caskroom/Cellar
|
|
579
582
|
package. An outdated tool without such a path retains `update_available`,
|
|
@@ -591,8 +594,12 @@ every installed tool was verified current. With `--yes`, the returned plan is th
|
|
|
591
594
|
pre-update inventory; `results` records attempted actions and their exit codes.
|
|
592
595
|
|
|
593
596
|
After each successful tool update command, CDX probes the CLI version again.
|
|
594
|
-
|
|
595
|
-
|
|
597
|
+
A raised version succeeds when it reaches the published release, if known.
|
|
598
|
+
An unchanged version also succeeds when the updater explicitly reports
|
|
599
|
+
`You are already on the latest version.` on stdout or stderr and exits zero;
|
|
600
|
+
this does not change an `unknown` inventory status to `up_to_date`.
|
|
601
|
+
Otherwise an unchanged, unreadable, downgraded, or still older-than-published
|
|
602
|
+
version makes the action fail, even if the updater exited zero. Successful text output
|
|
596
603
|
shows the before/after versions, including major upgrades. JSON keeps the
|
|
597
604
|
pre-update plan and existing result fields; tool verification adds
|
|
598
605
|
`version_before`, `version_after`, and `latest_version` to successful-command
|
package/docs/operations.md
CHANGED
|
@@ -242,6 +242,45 @@ credential sync.
|
|
|
242
242
|
- **On Windows, `doctor` warns that `script` is missing** — this is expected on many setups. Codex still launches, but transcript capture stays disabled unless you point `CDX_SCRIPT_BIN` to a compatible wrapper.
|
|
243
243
|
|
|
244
244
|
|
|
245
|
+
### Git and RTK in isolated workspaces
|
|
246
|
+
|
|
247
|
+
Local and remote `cdx run --isolate-workspace` use the same sandbox implementation.
|
|
248
|
+
For a linked Git worktree, CDX builds a read-only Git view at `/home/agent/.git`:
|
|
249
|
+
the mission's HEAD and index, plus the common objects, refs, packed refs, shallow
|
|
250
|
+
boundary and split-index files. `GIT_DIR`, `GIT_COMMON_DIR` and `GIT_WORK_TREE`
|
|
251
|
+
select that view without traversing the operator's private home directories.
|
|
252
|
+
`git log`, `show`, `diff`, `status`, `blame`, `branch` and `rev-parse` can read
|
|
253
|
+
the mission history, including packed objects and refs. Review runs also keep
|
|
254
|
+
checkout files read-only. Git metadata stays read-only in writable missions,
|
|
255
|
+
as before: committing and pushing remain the supervising mission flow's job.
|
|
256
|
+
|
|
257
|
+
Host repository configuration, hooks, other worktrees, global Git configuration,
|
|
258
|
+
SSH keys, credential helpers and token environment variables are not added.
|
|
259
|
+
The view has no configured remotes. Existing provider authentication rules are
|
|
260
|
+
unchanged; this does not grant Git push credentials.
|
|
261
|
+
|
|
262
|
+
The sandbox appends the mounted operator `~/.local/bin` to PATH, including for
|
|
263
|
+
noninteractive remote launches whose PATH omits it. An installed `rtk` is thus
|
|
264
|
+
available without installing a second copy. Isolated launches override
|
|
265
|
+
`RTK_DB_PATH` with `/cache/rtk/history.db`, backed by
|
|
266
|
+
`~/.cdx/shared-cache/rtk/history.db` on the execution host. Savings persist
|
|
267
|
+
across isolated attempts; the operator's normal RTK history is not mounted.
|
|
268
|
+
Inspect them with `RTK_DB_PATH="$HOME/.cdx/shared-cache/rtk/history.db" rtk gain`
|
|
269
|
+
on that host. Non-isolated launches keep their normal history selection.
|
|
270
|
+
|
|
271
|
+
Run the real confinement acceptance check on a Linux host with bubblewrap and
|
|
272
|
+
RTK installed (it uses disposable fixtures and synthetic secrets):
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
CDX_REQUIRE_SANDBOX_TESTS=1 python3 -m pytest -q test/test_workspace_sandbox_tools_py.py
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
It exercises the local and shipped worker implementations, writable and review
|
|
279
|
+
checkouts, Git history commands, RTK database writes, and denial of a synthetic
|
|
280
|
+
SSH key outside the checkout. The required mode fails rather than skipping
|
|
281
|
+
when nested namespaces or RTK are unavailable. Default test runs skip only
|
|
282
|
+
those unavailable integration cases; copied-metadata Git checks still run.
|
|
283
|
+
|
|
245
284
|
### Playwright in isolated workspaces
|
|
246
285
|
|
|
247
286
|
Isolated preparation and provider environments force `PLAYWRIGHT_SKIP_BROWSER_GC=1`.
|
|
@@ -154,7 +154,7 @@ cdx power all default
|
|
|
154
154
|
cdx model provider:ollama default
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
-
`--model` maps to Codex `--model`, Claude `--model`, and Ollama `ollama run <model>`. `--power` maps to Codex `model_reasoning_effort` and Claude `--effort`; supported values are `minimal`, `low`, `medium`, `high`, and `xhigh`. `--permission` maps to provider-native permission flags. Codex Fast mode is separate from reasoning effort: `--fast on` opts a Codex session into the Codex Fast service tier, while new sessions, `--fast off`, and default launches force the non-Fast `flex` tier. Use `--power low` when you want low reasoning effort without enabling Codex Fast credits. Existing legacy sessions that stored `fast=on` before this split continue to behave as low effort unless the user explicitly sets `--fast on` again. `--priority` is a 0..100 selector preference used as a tie-breaker after readiness and availability. `--policy use|ask-first|never` (default `use`) says whether cdx may pick an account on your behalf: `cdx next`, `cdx select`, `cdx run --provider` and run failover only ever choose `use` accounts; `ask-first` accounts are offered by `cdx rescue` with a confirmation, `never` accounts are not offered at all. Naming an account explicitly (`cdx <name>`, `cdx run <name>`) is always allowed. `--rtk on` adds standing guidance that encourages assistants to use RTK (`rtk <command>`) for noisy terminal commands when RTK is available, while keeping raw commands for exact output. Logics guidance is auto-enabled when `logics-manager` is available; use `--logics off` to disable that guidance for a session, or `--logics on` to pin it explicitly. This guidance is passed as instructions, never as a first message: Claude receives it through `--append-system-prompt` and Codex through `-c developer_instructions=...`, appended after any `developer_instructions` already set in the profile's `config.toml` (on Python older than 3.11 without `tomli`, a profile that sets its own is left untouched and gets no cdx guidance). Launching or resuming a session therefore never submits a turn on your behalf. Antigravity and Ollama have no instruction channel and receive no guidance. Whatever the `--rtk` setting, every launch, resume and `cdx run` sets `RTK_DB_PATH` to the rtk history of your real home (`~/Library/Application Support/rtk/history.db` on macOS, `~/.local/share/rtk/history.db` on Linux, `%LOCALAPPDATA%\rtk\history.db` on Windows), so `rtk gain` in your own shell counts what every account saved instead of each profile keeping its own; an `RTK_DB_PATH` you set yourself is kept. If you also pass `--append-system-prompt` through `--extra-args`, Claude receives the option twice; prefer putting your own text in the profile's `CLAUDE.md`.
|
|
157
|
+
`--model` maps to Codex `--model`, Claude `--model`, and Ollama `ollama run <model>`. `--power` maps to Codex `model_reasoning_effort` and Claude `--effort`; supported values are `minimal`, `low`, `medium`, `high`, and `xhigh`. `--permission` maps to provider-native permission flags. Codex Fast mode is separate from reasoning effort: `--fast on` opts a Codex session into the Codex Fast service tier, while new sessions, `--fast off`, and default launches force the non-Fast `flex` tier. Use `--power low` when you want low reasoning effort without enabling Codex Fast credits. Existing legacy sessions that stored `fast=on` before this split continue to behave as low effort unless the user explicitly sets `--fast on` again. `--priority` is a 0..100 selector preference used as a tie-breaker after readiness and availability. `--policy use|ask-first|never` (default `use`) says whether cdx may pick an account on your behalf: `cdx next`, `cdx select`, `cdx run --provider` and run failover only ever choose `use` accounts; `ask-first` accounts are offered by `cdx rescue` with a confirmation, `never` accounts are not offered at all. Naming an account explicitly (`cdx <name>`, `cdx run <name>`) is always allowed. `--rtk on` adds standing guidance that encourages assistants to use RTK (`rtk <command>`) for noisy terminal commands when RTK is available, while keeping raw commands for exact output. Logics guidance is auto-enabled when `logics-manager` is available; use `--logics off` to disable that guidance for a session, or `--logics on` to pin it explicitly. This guidance is passed as instructions, never as a first message: Claude receives it through `--append-system-prompt` and Codex through `-c developer_instructions=...`, appended after any `developer_instructions` already set in the profile's `config.toml` (on Python older than 3.11 without `tomli`, a profile that sets its own is left untouched and gets no cdx guidance). Launching or resuming a session therefore never submits a turn on your behalf. Antigravity and Ollama have no instruction channel and receive no guidance. Whatever the `--rtk` setting, every launch, resume and `cdx run` sets `RTK_DB_PATH` to the rtk history of your real home (`~/Library/Application Support/rtk/history.db` on macOS, `~/.local/share/rtk/history.db` on Linux, `%LOCALAPPDATA%\rtk\history.db` on Windows), so `rtk gain` in your own shell counts what every account saved instead of each profile keeping its own; an `RTK_DB_PATH` you set yourself is kept. Isolated workspace runs instead use the execution host's shared-cache RTK database at `/cache/rtk/history.db`; see [Git and RTK in isolated workspaces](operations.md#git-and-rtk-in-isolated-workspaces). If you also pass `--append-system-prompt` through `--extra-args`, Claude receives the option twice; prefer putting your own text in the profile's `CLAUDE.md`.
|
|
158
158
|
|
|
159
159
|
## Terminal Titles
|
|
160
160
|
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
package/src/update_all.py
CHANGED
|
@@ -19,7 +19,6 @@ _TOOLS = (
|
|
|
19
19
|
("rtk", "rtk"),
|
|
20
20
|
)
|
|
21
21
|
_SOURCE_TIMEOUT = 5
|
|
22
|
-
_ANTIGRAVITY_RELEASES = "https://antigravity-auto-updater-974169037036.us-central1.run.app/releases"
|
|
23
22
|
_PONYTAIL_URL = "https://github.com/DietrichGebert/ponytail.git"
|
|
24
23
|
|
|
25
24
|
|
|
@@ -79,9 +78,6 @@ def _latest_version(name):
|
|
|
79
78
|
if release.get("draft") or release.get("prerelease"):
|
|
80
79
|
return None
|
|
81
80
|
return _parse_version(release["tag_name"])
|
|
82
|
-
if name == PROVIDER_ANTIGRAVITY:
|
|
83
|
-
# agy belongs to the original editor, whose feed differs from Hub and IDE 2.
|
|
84
|
-
return _parse_version(_fetch_json(_ANTIGRAVITY_RELEASES)[0]["version"])
|
|
85
81
|
if name == PROVIDER_OLLAMA:
|
|
86
82
|
arch = {"x86_64": "amd64", "aarch64": "arm64"}.get(platform.machine().lower(), platform.machine().lower())
|
|
87
83
|
query = urlencode({"os": platform.system().lower(), "arch": arch, "version": "0.0.0"})
|
|
@@ -111,6 +107,8 @@ def _newer(latest, current):
|
|
|
111
107
|
|
|
112
108
|
|
|
113
109
|
def _native_update_command(name, command, path, env, runner):
|
|
110
|
+
if name == PROVIDER_ANTIGRAVITY:
|
|
111
|
+
return [command, "update"]
|
|
114
112
|
if name == PROVIDER_OLLAMA and platform.system().lower() == "linux":
|
|
115
113
|
return None
|
|
116
114
|
real_path = os.path.realpath(path)
|
|
@@ -171,6 +169,11 @@ def collect_update_all_plan(service, env=None, runner=None):
|
|
|
171
169
|
else:
|
|
172
170
|
item["status"] = "unknown"
|
|
173
171
|
item["reason"] = "Latest version unavailable from the official source." if not latest else "Installed version unavailable or does not match the published release."
|
|
172
|
+
if name == PROVIDER_ANTIGRAVITY:
|
|
173
|
+
# The editor release feed does not describe agy's CLI versions.
|
|
174
|
+
item["reason"] = "Latest CLI version unknown; agy update checks and applies its own updates."
|
|
175
|
+
item["update_command"] = _native_update_command(name, command, path, env, runner)
|
|
176
|
+
steps.append({"name": name, "command": item["update_command"], "env": {}})
|
|
174
177
|
items.append(item)
|
|
175
178
|
|
|
176
179
|
rtk_available = any(item["name"] == "rtk" and item["installed"] for item in items)
|
|
@@ -233,10 +236,13 @@ def apply_update_all_plan(plan, service, env=None, runner=None, progress=None):
|
|
|
233
236
|
if result["returncode"] == 0 and item:
|
|
234
237
|
after = _version(item["command"], env, runner)
|
|
235
238
|
result.update(version_before=item["version"], version_after=after, latest_version=item["latest_version"])
|
|
236
|
-
|
|
237
|
-
|
|
239
|
+
output = "\n".join((result["stdout"], result["stderr"]))
|
|
240
|
+
reports_current = bool(re.search(r"(?im)^\s*You are already on the latest version\.\s*$", output))
|
|
241
|
+
advanced = (_newer(after, item["version"]) and
|
|
242
|
+
(not item["latest_version"] or after == item["latest_version"] or _newer(after, item["latest_version"])))
|
|
243
|
+
if not (advanced or (after and after == item["version"] and reports_current)):
|
|
238
244
|
result["returncode"] = 1
|
|
239
|
-
result["reason"] = "Update verification failed: installed version did not advance to the
|
|
245
|
+
result["reason"] = "Update verification failed: installed version did not advance to the expected release and updater did not confirm it is current."
|
|
240
246
|
result["stderr"] = (result["stderr"] + "\n" + result["reason"]).strip()
|
|
241
247
|
results.append(result)
|
|
242
248
|
if result["returncode"] == 0 and step.get("id"):
|
package/src/workspace_sandbox.py
CHANGED
|
@@ -71,12 +71,14 @@ def private_auth_home(auth):
|
|
|
71
71
|
def clean_env(source: dict) -> dict:
|
|
72
72
|
allowed = ("PATH", "LANG", "LC_ALL", "TERM", "TZ")
|
|
73
73
|
env = {key: source[key] for key in allowed if key in source}
|
|
74
|
+
env["PATH"] = source.get("PATH", os.defpath) + os.pathsep + str(Path.home() / ".local/bin")
|
|
74
75
|
env.update(HOME="/home/agent", XDG_CONFIG_HOME="/home/agent/.config",
|
|
75
76
|
XDG_CACHE_HOME="/cache", GIT_CONFIG_NOSYSTEM="1",
|
|
76
77
|
GIT_CONFIG_GLOBAL="/dev/null", GIT_TERMINAL_PROMPT="0", GIT_OPTIONAL_LOCKS="0",
|
|
77
78
|
GIT_CONFIG_COUNT="1", GIT_CONFIG_KEY_0="credential.helper", GIT_CONFIG_VALUE_0="",
|
|
78
79
|
GH_CONFIG_DIR="/home/agent/.config/gh", NPM_CONFIG_CACHE="/cache/npm",
|
|
79
80
|
PIP_CACHE_DIR="/cache/pip", UV_CACHE_DIR="/cache/uv",
|
|
81
|
+
RTK_DB_PATH="/cache/rtk/history.db",
|
|
80
82
|
# Cache users have different mount paths; their GC cannot identify each other's browsers.
|
|
81
83
|
PLAYWRIGHT_BROWSERS_PATH="/cache/playwright", PLAYWRIGHT_SKIP_BROWSER_GC="1", CI="1")
|
|
82
84
|
return env
|
|
@@ -85,7 +87,8 @@ def clean_env(source: dict) -> dict:
|
|
|
85
87
|
def sandbox_command(command: list[str], tree: Path, *, network: bool, writable: bool = True,
|
|
86
88
|
source: dict | None = None, auth_home: str = "", provider: str = "", observation_home: str = "") -> tuple[list[str], dict]:
|
|
87
89
|
source = os.environ if source is None else source
|
|
88
|
-
|
|
90
|
+
env = clean_env(source)
|
|
91
|
+
binary = shutil.which(command[0], path=env["PATH"])
|
|
89
92
|
bwrap = shutil.which("bwrap", path=source.get("PATH"))
|
|
90
93
|
if not binary or not bwrap:
|
|
91
94
|
raise RuntimeError("Workspace isolation requires bubblewrap and " + command[0])
|
|
@@ -93,6 +96,7 @@ def sandbox_command(command: list[str], tree: Path, *, network: bool, writable:
|
|
|
93
96
|
raise RuntimeError("Workspace must be a directory")
|
|
94
97
|
tree = tree.resolve()
|
|
95
98
|
CACHE.mkdir(parents=True, exist_ok=True)
|
|
99
|
+
(CACHE / "rtk").mkdir(exist_ok=True)
|
|
96
100
|
# Provider transport uses the same restricted egress, even for read-only tools.
|
|
97
101
|
online = bool(network or provider)
|
|
98
102
|
if online:
|
|
@@ -137,15 +141,24 @@ def sandbox_command(command: list[str], tree: Path, *, network: bool, writable:
|
|
|
137
141
|
or common.is_relative_to(tree) or common.is_relative_to(CACHE.resolve())
|
|
138
142
|
or Path((gitdir / "gitdir").read_text().strip()).resolve() != marker):
|
|
139
143
|
raise RuntimeError("Invalid external worktree Git directory")
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
# Use sandbox-owned parents rather than traversing private host homes.
|
|
145
|
+
# Do not expose repository config (remote URLs/helpers/includes), hooks,
|
|
146
|
+
# other worktrees, or the source checkout. Git remains read-only.
|
|
147
|
+
private_git = Path("/home/agent/.git")
|
|
148
|
+
args += ["--ro-bind", str(marker), str(marker), "--dir", str(private_git)]
|
|
149
|
+
# Combine this worktree's HEAD/index with shared history, without any
|
|
150
|
+
# commondir/gitdir pointers back into the host filesystem.
|
|
151
|
+
for origin, names in (
|
|
152
|
+
(gitdir, ["HEAD", "index", *[p.name for p in gitdir.glob("sharedindex.*")]]),
|
|
153
|
+
(common, ["objects", "refs", "packed-refs", "shallow", *[p.name for p in common.glob("sharedindex.*")]]),
|
|
154
|
+
):
|
|
155
|
+
for name in names:
|
|
156
|
+
if (origin / name).exists():
|
|
157
|
+
args += ["--ro-bind", str(origin / name), str(private_git / name)]
|
|
158
|
+
env.update(GIT_DIR=str(private_git), GIT_COMMON_DIR=str(private_git),
|
|
159
|
+
GIT_WORK_TREE=str(tree))
|
|
146
160
|
elif marker.exists():
|
|
147
161
|
raise RuntimeError("Expected an isolated git worktree")
|
|
148
|
-
env = clean_env(source)
|
|
149
162
|
if provider == "codex":
|
|
150
163
|
auth_path = Path(auth_home) / "auth.json"
|
|
151
164
|
if json.loads(auth_path.read_text()).get('tokens', {}).get('refresh_token') != '':
|