diff --git a/Cargo.lock b/Cargo.lock index 2b5acdc7e3..91a2c5de5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14016,7 +14016,7 @@ dependencies = [ [[package]] name = "pgx" -version = "0.1.1" +version = "0.1.2" dependencies = [ "libc", "serde_json", diff --git a/README.md b/README.md index 4fa200de06..8462f8d58e 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ npx pgxdb@latest

- Open source · Free · v0.1.1 · For disposable databases, not production data + Open source · Free · v0.1.2 · For disposable databases, not production data

PGX is a database runtime for short-lived Postgres databases: agent @@ -279,8 +279,8 @@ applies to memory and to storage alike. ## Status -PGX is at **v0.1.1**, an early release with known limitations listed in the -[release notes](https://github.com/pgrundev/pgx/releases/tag/v0.1.1). It +PGX is at **v0.1.2**, an early release with known limitations listed in the +[release notes](https://github.com/pgrundev/pgx/releases/tag/v0.1.2). It already powers PGX branches in PGRun. The current focus is PostgreSQL compatibility, Rails/application compatibility, concurrency semantics, lifecycle correctness, predictable resource containment and real agent workloads. @@ -444,7 +444,7 @@ your permissions allow it. | Cursor | hooks installed; `pgx agent exec --` when `PGX_ISOLATION` is unset | env propagation pending live verification | | Codex | `pgx agent exec -- codex` (Codex hooks cannot set environment) | wrapper verified | -Requires PGX 0.1.1 or newer ([release v0.1.1](https://github.com/pgrundev/pgx/releases/tag/v0.1.1)); the Skill checks the installed version before it does anything. +Requires PGX 0.1.2 or newer ([release v0.1.2](https://github.com/pgrundev/pgx/releases/tag/v0.1.2); 0.1.1 isolates sessions but lets subagents share the parent's branch); the Skill checks the installed version before it does anything. Details, the lifecycle, security rules and the validation notes: [`docs/pgx/local-dev/agents.md`](docs/pgx/local-dev/agents.md). The Skill itself: [`skills/pgx/SKILL.md`](skills/pgx/SKILL.md). diff --git a/crates/bin/pgx/Cargo.toml b/crates/bin/pgx/Cargo.toml index 83edacee41..6b54047a5f 100644 --- a/crates/bin/pgx/Cargo.toml +++ b/crates/bin/pgx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pgx" -version = "0.1.1" +version = "0.1.2" edition.workspace = true publish.workspace = true description = "PGX command-line interface: a local, disposable, PostgreSQL-compatible runtime" diff --git a/dist/npm/package.json b/dist/npm/package.json index fc2305dc4f..8d3591d840 100644 --- a/dist/npm/package.json +++ b/dist/npm/package.json @@ -1,6 +1,6 @@ { "name": "pgxdb", - "version": "0.1.1", + "version": "0.1.2", "description": "PGX: a local, disposable, PostgreSQL-compatible runtime. `npx pgxdb` installs the native binary and starts a database.", "license": "AGPL-3.0", "repository": { diff --git a/dist/release-notes.md b/dist/release-notes.md index 725a32023d..796cbe9ce6 100644 --- a/dist/release-notes.md +++ b/dist/release-notes.md @@ -3,6 +3,87 @@ A self-contained, relocatable, PostgreSQL 18 compatible runtime for local development, CI and disposable databases. No system PostgreSQL required. +## PGX v0.1.2 — Every AI Subagent Gets Its Own Postgres + +0.1.1 gave every Claude Code **session** its own branch. Subagents launched +from that session inherited the session's identity and therefore its +database: three parallel subagents, one database. 0.1.2 gives every Claude +Code **subagent** its own branch, with nothing to configure and nothing for +the model to do: + +- **One branch per subagent.** Identity is `(project, host, session, agent)`; + a subagent's branch is `agent---`, a copy-on-write + clone of the same template. The session's branch keeps its name and records. +- **Hooks.** `pgx agent setup` / `pgx agent install claude` now writes six + Claude Code hooks (an existing four-hook installation is completed in place, + nothing duplicated): `SubagentStart` creates the subagent's branch and tells + the model its name, `PreToolUse` (Bash) runs each subagent command through + `pgx agent exec --agent --cwd -- -c ''` so + it sees that branch's `DATABASE_URL`/`PG*`, and `SubagentStop` retires the + branch after terminating whatever it left connected. If a branch cannot be + ensured the command is refused with the reason; it never runs against the + parent's database. +- **Killed agents cannot commit later.** Every agent branch carries + `client_connection_check_interval` (5 s), `idle_in_transaction_session_timeout` + (15 min) and `statement_timeout` (1 h), set with `ALTER DATABASE … SET` and + adjustable or disableable in `.pgx.toml`; the template is never altered. + `pgx agent down` terminates the branch's backends before retiring or + dropping and reports `backends_terminated` / `backends_remaining`. +- **CLI.** `pgx agent exec`: explicit-id branches are labelled `exec`, `--keep` + leaves the branch active for its idle TTL (the next `exec` with the same + `--id` attaches to it), `--json` adds `agent_id`, `source`, `created`, + `fresh`, `method`, `elapsed_ms`, `status`; `PGSERVICE`/`PGSERVICEFILE` are + cleared in the child and the password only ever travels in the environment. + `pgx agent down --id` finds a branch under any host label, `--branch ` + refuses to act on any other branch, `--agent ` on every lifecycle + command. `pgx agent ls` shows an AGENT column and `deadline_kind`; + `pgx agent doctor` reports subagent branches and the new hook audit log + (`~/.pgx/agent/hooks.log`, ids and outcomes only). +- **Skill.** The PGX Agent Skill (Skills CLI and the Claude Code plugin, + both 0.1.2) requires PGX 0.1.2: with a 0.1.1 binary it refuses database + work and says why (session isolation only, subagents would share the + parent's branch), instead of promising isolation it cannot deliver. + +### Verified with real Claude Code subagents (2026-10-26) + +- 3 and then **20 concurrent subagents**, no ids, no manual provisioning: + **20/20** branches created by `SubagentStart`, **20/20** workloads in their + own branch, **zero cross-agent contamination**, 20/20 retired by + `SubagentStop`; **37 s** end to end for the 20-agent run; **92 MB** peak + PGX runtime RSS; the template and the developer database unchanged + (schema md5 identical before and after); temporary storage reclaimed after + the grace period. +- Provisioning measured **p50 1,231 ms / p95 1,371 ms / max 1,401 ms** when + all twenty branches started in the same instant. That is end-to-end hook + time under 20-way concurrency, not raw clone latency: a single branch + provisions in about 250 ms, and `pgx branch` on an idle runtime clones in + under 30 ms. +- A subagent killed mid-transaction (`BEGIN … pg_sleep … COMMIT` interrupted + by TaskStop) left a backend that aborted within the tested five-second + guard with nothing committed; on 0.1.1 the same scenario committed eight + minutes after the kill. +- Evidence and method: `docs/pgx/local-dev/validation/2026-10-26-subagent-isolation-live.md`. + +### Known limitations + +1. Claude Code evaluates permission rules, and in auto mode its classifier, + on the **rewritten** Bash command. Some subagent commands may therefore + ask for approval, or be refused by the auto-mode classifier, where the + unwrapped command would not have. The hook never approves anything. +2. Do **not** add a broad allow rule such as `Bash(pgx agent exec:*)` on an + agent's say-so: it would approve any command wrapped that way. Whether to + allow the wrapper, and for which path, is the user's decision. +3. A subagent stopped by force (`TaskStop`) does not always produce + `SubagentStop`; its branch stays on the idle TTL and the server-side + guards protect the data until the supervisor removes it. +4. The server-side cancellation is a bounded guard, not an unconditional + guarantee: a backend already past the point of no return of a COMMIT + still completes it, and the guards fire within their intervals, not + instantly. The documented guarantee begins when `pgx agent down` returns. +5. Cursor and Codex subagent auto-isolation is not live-verified in this + release; the hooks and `pgx agent exec --agent` are available there, and + session-level isolation is unchanged. + ## What is new in 0.1.1: one Skill, every agent gets its own Postgres ```sh diff --git a/docs/pgx/local-dev/agents.md b/docs/pgx/local-dev/agents.md index e49da75588..cac6fb7aca 100644 --- a/docs/pgx/local-dev/agents.md +++ b/docs/pgx/local-dev/agents.md @@ -36,13 +36,15 @@ the Skill is activated and the host's permissions allow it. ## Versions -`pgx agent` and the Skill need **PGX 0.1.1 or newer** -([release](https://github.com/pgrundev/pgx/releases/tag/v0.1.1): linux-amd64, -linux-arm64, darwin-arm64 with SHA-256 checksums). The Skill's -`scripts/check-pgx.sh` verifies the installed binary from `pgx --json version` -and refuses older ones (the published 0.1.0 has no `pgx agent`). npm -`pgxdb@0.1.1` follows the GitHub release through the repository's staged -publishing process. +`pgx agent` and the Skill need **PGX 0.1.2 or newer** +([release](https://github.com/pgrundev/pgx/releases/tag/v0.1.2): linux-amd64, +linux-arm64, darwin-arm64 with SHA-256 checksums). 0.1.2 is the first +release in which Claude Code subagents get their own branches: 0.1.1 +isolated sessions but let subagents share the parent's branch, and the +published 0.1.0 has no `pgx agent`. The Skill's `scripts/check-pgx.sh` +verifies the installed binary from `pgx --json version` and refuses older +ones with a hint naming what they lack. npm `pgxdb@0.1.2` follows the GitHub +release through the repository's staged publishing process. ## What you get diff --git a/docs/pgx/local-dev/claude-plugin.md b/docs/pgx/local-dev/claude-plugin.md index d06872611d..ae0110d44e 100644 --- a/docs/pgx/local-dev/claude-plugin.md +++ b/docs/pgx/local-dev/claude-plugin.md @@ -36,14 +36,14 @@ Then, in a project with a database: `pgx:pgx` is the skill's name under the plugin's namespace. You can also just describe database work ("add a column and run the tests"); Claude selects the skill when it is relevant. Both routes run the same Skill: detect the -project, check for PGX 0.1.1 or newer and offer to install it, prepare a +project, check for PGX 0.1.2 or newer and offer to install it, prepare a schema-only template, `pgx agent setup`, then work inside the session's branch. See [agents.md](agents.md) for what that gives you. Check what is installed: ```sh -claude plugin list # pgx@pgrundev Version: 0.1.1 Status: enabled +claude plugin list # pgx@pgrundev Version: 0.1.2 Status: enabled claude plugin details pgx # Component inventory: Skills (1) pgx, Hooks (0), MCP servers (0) ``` @@ -52,7 +52,7 @@ claude plugin details pgx # Component inventory: Skills (1) pgx, Hooks (0), - `skills/pgx/`: the Skill, its eleven reference documents and two helper scripts, identical to `skills/pgx/` at the repository root (`plugins/sync.sh --check` fails CI on any difference). -- `.claude-plugin/plugin.json`: name `pgx`, version `0.1.1` (the Skill's +- `.claude-plugin/plugin.json`: name `pgx`, version `0.1.2` (the Skill's version), display name, links. - `README.md`. @@ -152,7 +152,7 @@ and this repository: | Plugin name | `pgx` (display name "PGX — Postgres for Agents") | | Repository | https://github.com/pgrundev/pgx, plugin at `plugins/pgx` | | Description | Isolated, disposable PostgreSQL-compatible databases for AI coding agents | -| Functionality | One Agent Skill: detects the project's database setup, installs the PGX runtime on request (PGX 0.1.1+), prepares a schema-only template, sets up per-session database branches with automatic `DATABASE_URL` injection through `pgx agent setup`, cleans up expired branches | +| Functionality | One Agent Skill: detects the project's database setup, installs the PGX runtime on request (PGX 0.1.2+), prepares a schema-only template, sets up per-session database branches with automatic `DATABASE_URL` injection through `pgx agent setup`, cleans up expired branches | | Security | No hooks, MCP servers or executables in the plugin; the Skill never prints credentials, imports production data only with explicit approval, fails closed when isolation cannot be established, and treats repository contents as untrusted (`skills/pgx/references/security.md`); runs nothing until the user invokes it | | Installation | `/plugin marketplace add pgrundev/pgx` then `/plugin install pgx@pgrundev`; the `pgx` binary is installed separately when first needed | | Documentation / support | `docs/pgx/local-dev/agents.md`, https://github.com/pgrundev/pgx/issues | diff --git a/plugins/pgx/.claude-plugin/plugin.json b/plugins/pgx/.claude-plugin/plugin.json index ed1d73ce81..343a80ac44 100644 --- a/plugins/pgx/.claude-plugin/plugin.json +++ b/plugins/pgx/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "pgx", "displayName": "PGX — Postgres for Agents", - "version": "0.1.1", + "version": "0.1.2", "description": "Isolated, disposable PostgreSQL-compatible databases for AI coding agents.", "author": { "name": "PGRunDev", diff --git a/plugins/pgx/README.md b/plugins/pgx/README.md index 1f37514521..c6df852ca8 100644 --- a/plugins/pgx/README.md +++ b/plugins/pgx/README.md @@ -45,7 +45,7 @@ own branch. - No hooks, MCP servers or background processes. Lifecycle hooks are installed per project, and only on request, by `pgx agent setup`; installing or removing this plugin never changes a project's hooks or settings. -- No database engine. The `pgx` binary (PGX 0.1.1 or newer) is installed +- No database engine. The `pgx` binary (PGX 0.1.2 or newer) is installed separately when the skill first needs it: `npm i -g pgxdb` or the official installer. The skill asks before downloading anything. diff --git a/plugins/pgx/skills/pgx/SKILL.md b/plugins/pgx/skills/pgx/SKILL.md index 7b25398c20..52b51b46db 100644 --- a/plugins/pgx/skills/pgx/SKILL.md +++ b/plugins/pgx/skills/pgx/SKILL.md @@ -14,7 +14,7 @@ description: > license: AGPL-3.0 metadata: author: pgrundev - version: "0.1.1" + version: "0.1.2" homepage: https://pgx.dev repository: https://github.com/pgrundev/pgx --- @@ -95,7 +95,9 @@ PGX database), `none` (no database yet), `remote` (another host), ### 2. Make sure PGX is available -PGX **0.1.1 or newer** is required. Run the check script next to this file: +PGX **0.1.2 or newer** is required. 0.1.1 isolates sessions but not Claude +Code subagents (they shared the parent's branch); 0.1.0 has no `pgx agent` +at all. Run the check script next to this file: ```sh bash .claude/skills/pgx/scripts/check-pgx.sh # or .agents/skills/pgx/scripts/check-pgx.sh, @@ -103,8 +105,9 @@ bash .claude/skills/pgx/scripts/check-pgx.sh # or .agents/skills/pgx/scripts ``` It prints `{"ok":true,"version":…}` and exits 0 for a compatible binary; -exit 3 means `pgx` is missing, 2 too old (for example the published 0.1.0, -which has no `pgx agent`), 4 an unreadable `pgx --json version`. It reads the +exit 3 means `pgx` is missing, 2 too old (0.1.1: session isolation only, +subagents would share the parent's branch; 0.1.0: no `pgx agent`), 4 an +unreadable `pgx --json version`. It reads the structured version only: `pgx agent --help` prints the global help on every version and proves nothing. If `pgx` is missing or too old, follow [references/installation.md](references/installation.md): prefer an diff --git a/plugins/pgx/skills/pgx/references/installation.md b/plugins/pgx/skills/pgx/references/installation.md index ad05942045..8d83aa67ad 100644 --- a/plugins/pgx/skills/pgx/references/installation.md +++ b/plugins/pgx/skills/pgx/references/installation.md @@ -7,8 +7,11 @@ command -v pgx && pgx --json version # {"pgx_version":"0.1.x", …} pgx --json status # exit 3 when initialised but stopped; hooks start it on demand ``` -The skill needs **PGX 0.1.1 or newer**, the first release with the -`pgx agent` command group (https://github.com/pgrundev/pgx/releases/tag/v0.1.1). +The skill needs **PGX 0.1.2 or newer** +(https://github.com/pgrundev/pgx/releases/tag/v0.1.2): the first release +in which Claude Code subagents get their own branches (0.1.1 isolated +sessions only and let subagents share the parent's branch; 0.1.0 has no +`pgx agent` command group). `scripts/check-pgx.sh` decides: exit 0 compatible, 3 missing, 2 too old, 4 malformed, always with one JSON line. It compares `pgx --json version` → `pgx_version` as semver (`PGX_MIN_VERSION` overrides the floor). Do not use diff --git a/plugins/pgx/skills/pgx/scripts/check-pgx.sh b/plugins/pgx/skills/pgx/scripts/check-pgx.sh index d3c5bcd26d..0e41b316be 100755 --- a/plugins/pgx/skills/pgx/scripts/check-pgx.sh +++ b/plugins/pgx/skills/pgx/scripts/check-pgx.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash # check-pgx.sh: is a compatible PGX on PATH? Prints one JSON object and exits -# 0 compatible (version >= MIN) {"ok":true,"version":"0.1.1","path":"…"} +# 0 compatible (version >= MIN) {"ok":true,"version":"0.1.2","path":"…"} # 3 pgx not found {"ok":false,"reason":"missing",…} -# 2 too old {"ok":false,"reason":"too_old","version":"0.1.0",…} +# 2 too old {"ok":false,"reason":"too_old","version":"0.1.1",…} # 4 unreadable version output {"ok":false,"reason":"malformed",…} # `pgx agent --help` exits 0 on every PGX version (global help), so only the # structured `pgx --json version` output counts. set -u -MIN=${PGX_MIN_VERSION:-0.1.1} +MIN=${PGX_MIN_VERSION:-0.1.2} esc() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'; } path=$(command -v pgx 2>/dev/null || true) if [ -z "$path" ]; then @@ -28,4 +28,12 @@ vcmp() { # returns 0 if $1 >= $2 if vcmp "$ver" "$MIN"; then printf '{"ok":true,"version":"%s","path":"%s","min":"%s"}\n' "$ver" "$(esc "$path")" "$MIN"; exit 0 fi -printf '{"ok":false,"reason":"too_old","version":"%s","path":"%s","min":"%s","hint":"PGX %s has no pgx agent; upgrade with the method it was installed with (npm i -g pgxdb@latest, or the installer again)"}\n' "$ver" "$(esc "$path")" "$MIN" "$ver"; exit 2 +# Too old. Say what the installed version lacks: 0.1.1 isolated sessions but +# let Claude Code subagents share the parent's branch; anything older has no +# `pgx agent` at all. Either way: upgrade, do not run database work. +if vcmp "$ver" "0.1.1"; then + why="PGX $ver isolates sessions only: Claude Code subagents would share the parent's branch" +else + why="PGX $ver has no pgx agent" +fi +printf '{"ok":false,"reason":"too_old","version":"%s","path":"%s","min":"%s","hint":"%s; upgrade to %s or newer with the method it was installed with (npm i -g pgxdb@latest, or the installer again)"}\n' "$ver" "$(esc "$path")" "$MIN" "$why" "$MIN"; exit 2 diff --git a/skills/pgx/SKILL.md b/skills/pgx/SKILL.md index 7b25398c20..52b51b46db 100644 --- a/skills/pgx/SKILL.md +++ b/skills/pgx/SKILL.md @@ -14,7 +14,7 @@ description: > license: AGPL-3.0 metadata: author: pgrundev - version: "0.1.1" + version: "0.1.2" homepage: https://pgx.dev repository: https://github.com/pgrundev/pgx --- @@ -95,7 +95,9 @@ PGX database), `none` (no database yet), `remote` (another host), ### 2. Make sure PGX is available -PGX **0.1.1 or newer** is required. Run the check script next to this file: +PGX **0.1.2 or newer** is required. 0.1.1 isolates sessions but not Claude +Code subagents (they shared the parent's branch); 0.1.0 has no `pgx agent` +at all. Run the check script next to this file: ```sh bash .claude/skills/pgx/scripts/check-pgx.sh # or .agents/skills/pgx/scripts/check-pgx.sh, @@ -103,8 +105,9 @@ bash .claude/skills/pgx/scripts/check-pgx.sh # or .agents/skills/pgx/scripts ``` It prints `{"ok":true,"version":…}` and exits 0 for a compatible binary; -exit 3 means `pgx` is missing, 2 too old (for example the published 0.1.0, -which has no `pgx agent`), 4 an unreadable `pgx --json version`. It reads the +exit 3 means `pgx` is missing, 2 too old (0.1.1: session isolation only, +subagents would share the parent's branch; 0.1.0: no `pgx agent`), 4 an +unreadable `pgx --json version`. It reads the structured version only: `pgx agent --help` prints the global help on every version and proves nothing. If `pgx` is missing or too old, follow [references/installation.md](references/installation.md): prefer an diff --git a/skills/pgx/references/installation.md b/skills/pgx/references/installation.md index ad05942045..8d83aa67ad 100644 --- a/skills/pgx/references/installation.md +++ b/skills/pgx/references/installation.md @@ -7,8 +7,11 @@ command -v pgx && pgx --json version # {"pgx_version":"0.1.x", …} pgx --json status # exit 3 when initialised but stopped; hooks start it on demand ``` -The skill needs **PGX 0.1.1 or newer**, the first release with the -`pgx agent` command group (https://github.com/pgrundev/pgx/releases/tag/v0.1.1). +The skill needs **PGX 0.1.2 or newer** +(https://github.com/pgrundev/pgx/releases/tag/v0.1.2): the first release +in which Claude Code subagents get their own branches (0.1.1 isolated +sessions only and let subagents share the parent's branch; 0.1.0 has no +`pgx agent` command group). `scripts/check-pgx.sh` decides: exit 0 compatible, 3 missing, 2 too old, 4 malformed, always with one JSON line. It compares `pgx --json version` → `pgx_version` as semver (`PGX_MIN_VERSION` overrides the floor). Do not use diff --git a/skills/pgx/scripts/check-pgx.sh b/skills/pgx/scripts/check-pgx.sh index d3c5bcd26d..0e41b316be 100755 --- a/skills/pgx/scripts/check-pgx.sh +++ b/skills/pgx/scripts/check-pgx.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash # check-pgx.sh: is a compatible PGX on PATH? Prints one JSON object and exits -# 0 compatible (version >= MIN) {"ok":true,"version":"0.1.1","path":"…"} +# 0 compatible (version >= MIN) {"ok":true,"version":"0.1.2","path":"…"} # 3 pgx not found {"ok":false,"reason":"missing",…} -# 2 too old {"ok":false,"reason":"too_old","version":"0.1.0",…} +# 2 too old {"ok":false,"reason":"too_old","version":"0.1.1",…} # 4 unreadable version output {"ok":false,"reason":"malformed",…} # `pgx agent --help` exits 0 on every PGX version (global help), so only the # structured `pgx --json version` output counts. set -u -MIN=${PGX_MIN_VERSION:-0.1.1} +MIN=${PGX_MIN_VERSION:-0.1.2} esc() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'; } path=$(command -v pgx 2>/dev/null || true) if [ -z "$path" ]; then @@ -28,4 +28,12 @@ vcmp() { # returns 0 if $1 >= $2 if vcmp "$ver" "$MIN"; then printf '{"ok":true,"version":"%s","path":"%s","min":"%s"}\n' "$ver" "$(esc "$path")" "$MIN"; exit 0 fi -printf '{"ok":false,"reason":"too_old","version":"%s","path":"%s","min":"%s","hint":"PGX %s has no pgx agent; upgrade with the method it was installed with (npm i -g pgxdb@latest, or the installer again)"}\n' "$ver" "$(esc "$path")" "$MIN" "$ver"; exit 2 +# Too old. Say what the installed version lacks: 0.1.1 isolated sessions but +# let Claude Code subagents share the parent's branch; anything older has no +# `pgx agent` at all. Either way: upgrade, do not run database work. +if vcmp "$ver" "0.1.1"; then + why="PGX $ver isolates sessions only: Claude Code subagents would share the parent's branch" +else + why="PGX $ver has no pgx agent" +fi +printf '{"ok":false,"reason":"too_old","version":"%s","path":"%s","min":"%s","hint":"%s; upgrade to %s or newer with the method it was installed with (npm i -g pgxdb@latest, or the installer again)"}\n' "$ver" "$(esc "$path")" "$MIN" "$why" "$MIN"; exit 2 diff --git a/skills/tests/pgx/check-pgx.test.sh b/skills/tests/pgx/check-pgx.test.sh index fde1df1a31..c65bf94232 100755 --- a/skills/tests/pgx/check-pgx.test.sh +++ b/skills/tests/pgx/check-pgx.test.sh @@ -9,8 +9,10 @@ mk() { # name version-json-or-garbage run() { PATH="$1:/usr/bin:/bin" bash "$chk"; } set +e out=$(PATH=/usr/bin:/bin bash "$chk"); rc=$?; [ $rc = 3 ] && [[ $out == *'"reason":"missing"'* ]] && ok "missing → 3" || bad "missing: rc=$rc $out" -d=$(mk old '{"pgx_version":"0.1.0","os":"darwin"}'); out=$(run "$d"); rc=$?; [ $rc = 2 ] && [[ $out == *'"too_old"'* ]] && ok "0.1.0 → 2 (too old) even though agent --help exits 0" || bad "old: rc=$rc $out" -d=$(mk cur '{"pgx_version":"0.1.1","os":"darwin"}'); out=$(run "$d"); rc=$?; [ $rc = 0 ] && [[ $out == *'"ok":true'* ]] && ok "0.1.1 → 0" || bad "current: rc=$rc $out" +d=$(mk old '{"pgx_version":"0.1.0","os":"darwin"}'); out=$(run "$d"); rc=$?; [ $rc = 2 ] && [[ $out == *'"too_old"'* ]] && [[ $out == *"no pgx agent"* ]] && ok "0.1.0 → 2 (too old) even though agent --help exits 0" || bad "old: rc=$rc $out" +d=$(mk sess '{"pgx_version":"0.1.1","os":"darwin"}'); out=$(run "$d"); rc=$?; [ $rc = 2 ] && [[ $out == *'"too_old"'* ]] && [[ $out == *subagents* ]] && ok "0.1.1 → 2 (session isolation only; the hint names subagents)" || bad "0.1.1: rc=$rc $out" +d=$(mk cur '{"pgx_version":"0.1.2","os":"darwin"}'); out=$(run "$d"); rc=$?; [ $rc = 0 ] && [[ $out == *'"ok":true'* ]] && ok "0.1.2 → 0" || bad "current: rc=$rc $out" +d=$(mk env '{"pgx_version":"0.1.1","os":"darwin"}'); out=$(PGX_MIN_VERSION=0.1.1 PATH="$d:/usr/bin:/bin" bash "$chk"); rc=$?; [ $rc = 0 ] && ok "PGX_MIN_VERSION override still works" || bad "override: rc=$rc $out" d=$(mk new '{"pgx_version":"0.2.0","os":"linux"}'); out=$(run "$d"); rc=$?; [ $rc = 0 ] && ok "0.2.0 → 0" || bad "newer: rc=$rc $out" d=$(mk ci '{"pgx_version":"0.0.0-ci.abc","os":"linux"}'); out=$(run "$d"); rc=$?; [ $rc = 2 ] && ok "0.0.0-ci → 2" || bad "ci build: rc=$rc $out" d=$(mk bad 'not json at all'); out=$(run "$d"); rc=$?; [ $rc = 4 ] && [[ $out == *'"malformed"'* ]] && ok "garbage → 4 (malformed)" || bad "malformed: rc=$rc $out" diff --git a/skills/tests/pgx/run.sh b/skills/tests/pgx/run.sh index f91788e84f..f01343b992 100755 --- a/skills/tests/pgx/run.sh +++ b/skills/tests/pgx/run.sh @@ -80,7 +80,7 @@ check empty "d['framework']=='unknown' and d['database_config']['classification' check sensitive "d['database_config']['classification']=='sensitive'" check empty "d['pgx']['installed']==False" check remote-ssl "d['database_config']['classification']=='sensitive'" -grep -q '0.1.1 or newer' "$skill/SKILL.md" && ! grep -qE 'pgx agent --help. must succeed' "$skill/SKILL.md" && ok "SKILL.md gates on PGX 0.1.1, not on --help" || bad "SKILL.md must gate on version 0.1.1 (pgx agent --help exits 0 on old binaries)" +grep -q '0.1.2 or newer' "$skill/SKILL.md" && ! grep -q '0.1.1 or newer' "$skill/SKILL.md" && ! grep -qE 'pgx agent --help. must succeed' "$skill/SKILL.md" && ok "SKILL.md gates on PGX 0.1.2, not on --help" || bad "SKILL.md must gate on version 0.1.2 (0.1.1 shares the parent's branch with subagents; pgx agent --help exits 0 on old binaries)" grep -q 'scripts/detect-project.sh' "$skill/SKILL.md" && grep -qE '\.claude/skills/pgx/scripts/detect-project\.sh|\.agents/skills/pgx/scripts/detect-project\.sh' "$skill/SKILL.md" && ok "SKILL.md names the installed script paths" || bad "SKILL.md must name the installed script paths" # Secrets never leak into the output. for f in django prisma node sensitive remote-ssl; do