Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da7d70825e | |||
| 41c2c2b716 | |||
| 5c08bfc8a8 | |||
| 1371584634 | |||
| d902b2d056 |
@@ -45,6 +45,8 @@ re-brand of opencode-devbox's `pi-only` variant.
|
|||||||
|
|
||||||
1. Confirm `pi --version` resolves from npm to the expected version
|
1. Confirm `pi --version` resolves from npm to the expected version
|
||||||
(`curl -sf 'https://registry.npmjs.org/@earendil-works%2Fpi-coding-agent/latest' | jq -r .version`).
|
(`curl -sf 'https://registry.npmjs.org/@earendil-works%2Fpi-coding-agent/latest' | jq -r .version`).
|
||||||
|
Check release notes at https://github.com/earendil-works/pi/releases for
|
||||||
|
the upstream changelog to include in `CHANGELOG.md`.
|
||||||
2. Update `CHANGELOG.md` Unreleased → vX.Y.Z section.
|
2. Update `CHANGELOG.md` Unreleased → vX.Y.Z section.
|
||||||
3. Verify `docker compose up` works locally with the current `latest` image
|
3. Verify `docker compose up` works locally with the current `latest` image
|
||||||
if you're upgrading users from a previous version. Then run the
|
if you're upgrading users from a previous version. Then run the
|
||||||
|
|||||||
+70
-3
@@ -13,14 +13,81 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`).
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## v1.1.4 — 2026-06-17
|
||||||
|
|
||||||
|
Patch release: config and shell-quality fixes on a preserved volume. No pi
|
||||||
|
version bump (still `0.79.6`, latest). The `pi-toolkit` ref is auto-resolved
|
||||||
|
to `main` HEAD at build, so the AGENTS.md change below lands automatically.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Global `AGENTS.md` auto-loads the pi-extensions skill.** `pi-toolkit` now
|
||||||
|
ships `pi-global-AGENTS.md` and symlinks it to `~/.pi/agent/AGENTS.md` (pi's
|
||||||
|
global-instructions file, loaded at every start). It directs the agent to
|
||||||
|
read the `pi-extensions` skill at session start and carries a core
|
||||||
|
fork/recall cheat-sheet, since on-demand skill description-matching was
|
||||||
|
leaving `pi-fork` / `pi-observational-memory` under-utilised. **Heads-up:**
|
||||||
|
on a preserved volume any pre-existing real `~/.pi/agent/AGENTS.md` is backed
|
||||||
|
up to `*.bak.<timestamp>` and replaced by the symlink (same behavior as
|
||||||
|
`keybindings.json`).
|
||||||
|
- **`settings.json` merge-on-recreate.** The bootstrap only ever copied the
|
||||||
|
template when `settings.json` was *absent*, so a file on a preserved volume
|
||||||
|
never picked up config added in a later image (e.g. the
|
||||||
|
`observational-memory` / `pi-fork` blocks, a newly-enabled model). The
|
||||||
|
entrypoint now deep-merges the template into an existing `settings.json` on
|
||||||
|
start with `jq -s '.[0] * .[1]'` (template first, live second): the user's
|
||||||
|
values always win and only *missing* keys are filled in. Arrays are treated
|
||||||
|
as leaves (a model the user removed is not re-added); the file is only
|
||||||
|
rewritten when the merge changes something, the original is backed up first,
|
||||||
|
and invalid JSON on either side is skipped rather than clobbered. Opt out
|
||||||
|
with `PI_SETTINGS_MERGE=0`.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **bash history loss in nested / tmux shells.** The `DEVBOX_HIST_SET` guard
|
||||||
|
that installs the per-prompt `history -a` flush was `export`ed, so it leaked
|
||||||
|
into child processes. Any nested shell — crucially each tmux pane, which
|
||||||
|
inherits the tmux server's env — saw the guard already set and skipped
|
||||||
|
installing `history -a`, persisting history only on a clean exit. Abrupt
|
||||||
|
termination (`docker stop`, `tmux kill-server`, SIGKILL) then silently lost
|
||||||
|
that shell's in-memory history. The guard is now shell-local (no `export`),
|
||||||
|
so every new interactive shell re-installs its own flush. `zoxide` was less
|
||||||
|
affected (its hook is unguarded and writes immediately). History and zoxide
|
||||||
|
storage were never the issue — `~/.cache/bash` (`devbox-shell-history`) and
|
||||||
|
`~/.local/share/zoxide` (`devbox-zoxide`) are persistent named volumes.
|
||||||
|
**Note:** existing shells/panes keep the old behavior until restarted
|
||||||
|
(`tmux kill-server` or open fresh shells).
|
||||||
|
|
||||||
|
### Maintainer
|
||||||
|
|
||||||
|
- `scripts/recreate-sanity-check.sh` gained assertions for the new wiring: the
|
||||||
|
`~/.pi/agent/AGENTS.md` symlink, a nested login shell installing
|
||||||
|
`history -a`, and `settings.json` carrying the `observational-memory` +
|
||||||
|
`pi-fork` blocks after recreate.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## v1.1.3 — 2026-06-16
|
## v1.1.3 — 2026-06-16
|
||||||
|
|
||||||
Patch release: pi `0.79.4` → `0.79.5` (auto-resolved at build).
|
Patch release: pi `0.79.4` → `0.79.5` (auto-resolved at build).
|
||||||
|
|
||||||
### Changed
|
### Bumped: pi 0.79.4 → 0.79.5
|
||||||
|
|
||||||
- **pi bumped to `0.79.5`** (published upstream 2026-06-16). No image-side
|
Notable upstream changes (from [pi releases](https://github.com/earendil-works/pi/releases/tag/v0.79.5)):
|
||||||
changes beyond the pi npm version.
|
|
||||||
|
- **Provider-scoped API key environments** — `auth.json` API key entries can
|
||||||
|
now include `env` overrides for provider-specific Cloudflare, Azure OpenAI,
|
||||||
|
Google Vertex, Amazon Bedrock, cache retention, and proxy settings without
|
||||||
|
changing the project shell.
|
||||||
|
- **Global HTTP proxy setting** — configure `httpProxy` once in global settings
|
||||||
|
to apply `HTTP_PROXY` / `HTTPS_PROXY` to Pi-managed HTTP clients.
|
||||||
|
- **Vercel AI Gateway attribution** — requests now include Pi attribution
|
||||||
|
headers by default.
|
||||||
|
- **Fixes:** inherited OpenAI Responses streaming tolerates null message content
|
||||||
|
before tool calls; DeepSeek V4 thinking no longer sends both `thinking` and
|
||||||
|
`reasoning_effort`; device-code login no longer auto-opens the browser;
|
||||||
|
various Google/Vertex Gemini model metadata corrections; session selector
|
||||||
|
empty-state fix; Cursor Up history navigation fix.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+29
-3
@@ -86,9 +86,35 @@ if command -v pi &>/dev/null; then
|
|||||||
|
|
||||||
# Bootstrap settings.json from template if absent (pi rewrites this
|
# Bootstrap settings.json from template if absent (pi rewrites this
|
||||||
# file at runtime — lastChangelogVersion, etc — so we can't symlink it).
|
# file at runtime — lastChangelogVersion, etc — so we can't symlink it).
|
||||||
if [ ! -f "$HOME/.pi/agent/settings.json" ] && \
|
_pi_settings="$HOME/.pi/agent/settings.json"
|
||||||
[ -f /opt/pi-toolkit/settings.example.json ]; then
|
_pi_template=/opt/pi-toolkit/settings.example.json
|
||||||
cp /opt/pi-toolkit/settings.example.json "$HOME/.pi/agent/settings.json"
|
if [ ! -f "$_pi_settings" ] && [ -f "$_pi_template" ]; then
|
||||||
|
cp "$_pi_template" "$_pi_settings"
|
||||||
|
echo "pi settings.json bootstrapped from template"
|
||||||
|
elif [ -f "$_pi_settings" ] && [ -f "$_pi_template" ] && \
|
||||||
|
[ "${PI_SETTINGS_MERGE:-1}" != "0" ] && command -v jq >/dev/null 2>&1; then
|
||||||
|
# Non-destructive merge: a settings.json on a PRESERVED volume never
|
||||||
|
# otherwise sees new template keys (the bootstrap above only fires when
|
||||||
|
# the file is absent), so config added in an image upgrade — e.g. the
|
||||||
|
# observational-memory / pi-fork blocks or a newly-enabled model — never
|
||||||
|
# reaches existing users. Deep-merge with the template FIRST and the
|
||||||
|
# live file SECOND ('.[0] * .[1]') so the user's values always win and
|
||||||
|
# only keys MISSING from the live file are filled in from the template.
|
||||||
|
# Arrays are treated as leaves (the user's array is kept verbatim, so a
|
||||||
|
# model they deliberately removed is not re-added). Only rewrite when the
|
||||||
|
# merge actually changes something, and back up the original first.
|
||||||
|
# Set PI_SETTINGS_MERGE=0 to disable. Invalid JSON on either side → skip,
|
||||||
|
# never clobber.
|
||||||
|
if _pi_merged=$(jq -s '.[0] * .[1]' "$_pi_template" "$_pi_settings" 2>/dev/null); then
|
||||||
|
if [ -n "$_pi_merged" ] && \
|
||||||
|
! printf '%s' "$_pi_merged" | jq -e --slurpfile cur "$_pi_settings" '. == $cur[0]' >/dev/null 2>&1; then
|
||||||
|
cp "$_pi_settings" "${_pi_settings}.bak.$(date +%Y%m%d-%H%M%S)"
|
||||||
|
printf '%s\n' "$_pi_merged" > "$_pi_settings"
|
||||||
|
echo "pi settings.json: merged new template keys from settings.example.json (backup saved)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARN: pi settings.json merge skipped (jq could not parse template or live file; left untouched)"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# pi↔mempalace MCP bridge — single extension symlink.
|
# pi↔mempalace MCP bridge — single extension symlink.
|
||||||
|
|||||||
@@ -89,9 +89,16 @@ fi
|
|||||||
# we append with a newline separator to avoid the ';;' parse error
|
# we append with a newline separator to avoid the ';;' parse error
|
||||||
# described at the top of this file. Guarded so repeated sourcing
|
# described at the top of this file. Guarded so repeated sourcing
|
||||||
# (e.g. `exec bash`) doesn't stack duplicates.
|
# (e.g. `exec bash`) doesn't stack duplicates.
|
||||||
|
#
|
||||||
|
# The guard MUST stay shell-local (NOT exported): if it leaks into child
|
||||||
|
# processes, every nested shell -- crucially each tmux pane, which inherits
|
||||||
|
# the tmux server's env -- skips installing `history -a` and only persists
|
||||||
|
# history on a clean exit. Abrupt termination (docker stop, tmux kill-server,
|
||||||
|
# SIGKILL) then loses that shell's in-memory history. Keeping it unexported
|
||||||
|
# means each new interactive shell re-installs its own per-prompt flush.
|
||||||
if [ -z "${DEVBOX_HIST_SET:-}" ]; then
|
if [ -z "${DEVBOX_HIST_SET:-}" ]; then
|
||||||
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a"
|
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a"
|
||||||
export DEVBOX_HIST_SET=1
|
DEVBOX_HIST_SET=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Prompt: show [opencode-devbox] tag so it's obvious you're in the container
|
# ── Prompt: show [opencode-devbox] tag so it's obvious you're in the container
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
# version is supplied — see the version note below)
|
# version is supplied — see the version note below)
|
||||||
# - Persisted named volumes survived (~/.pi config, shell history, zoxide,
|
# - Persisted named volumes survived (~/.pi config, shell history, zoxide,
|
||||||
# nvim data, uv cache, ssh-local)
|
# nvim data, uv cache, ssh-local)
|
||||||
# - pi runtime wiring is intact: keybindings symlink, ≥4 extensions, the
|
# - pi runtime wiring is intact: keybindings symlink, AGENTS.md symlink,
|
||||||
# mempalace.ts bridge, settings.json, and the pi-fork /
|
# ≥4 extensions, the mempalace.ts bridge, settings.json, and the pi-fork /
|
||||||
# pi-observational-memory / (studio variant) pi-studio package registrations
|
# pi-observational-memory / (studio variant) pi-studio package registrations
|
||||||
# - Shell defaults re-seeded from /etc/skel-devbox
|
# - Shell defaults re-seeded from /etc/skel-devbox
|
||||||
# - /tmp/sshcm exists with mode 700 (ssh ControlMaster dir)
|
# - /tmp/sshcm exists with mode 700 (ssh ControlMaster dir)
|
||||||
@@ -157,6 +157,14 @@ else
|
|||||||
fail "~/.pi/agent/keybindings.json missing or not a symlink"
|
fail "~/.pi/agent/keybindings.json missing or not a symlink"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# global AGENTS.md symlink (pi-toolkit) — global instructions loaded by pi at
|
||||||
|
# every start (directs the agent to read the pi-extensions skill at session start)
|
||||||
|
if [ -L "$HOME/.pi/agent/AGENTS.md" ]; then
|
||||||
|
pass "~/.pi/agent/AGENTS.md symlink (pi-toolkit)"
|
||||||
|
else
|
||||||
|
fail "~/.pi/agent/AGENTS.md missing or not a symlink"
|
||||||
|
fi
|
||||||
|
|
||||||
# extensions deployed (pi-extensions) — expect ≥4 *.ts
|
# extensions deployed (pi-extensions) — expect ≥4 *.ts
|
||||||
EXT_COUNT=$(ls -1 "$HOME"/.pi/agent/extensions/*.ts 2>/dev/null | wc -l | tr -d ' ')
|
EXT_COUNT=$(ls -1 "$HOME"/.pi/agent/extensions/*.ts 2>/dev/null | wc -l | tr -d ' ')
|
||||||
if [ "$EXT_COUNT" -ge 4 ]; then
|
if [ "$EXT_COUNT" -ge 4 ]; then
|
||||||
@@ -179,6 +187,18 @@ else
|
|||||||
fail "~/.pi/agent/settings.json missing"
|
fail "~/.pi/agent/settings.json missing"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# settings.json merge: the entrypoint deep-merges new template keys into a
|
||||||
|
# preserved settings.json on every start, so config added in an image upgrade
|
||||||
|
# (e.g. the observational-memory / pi-fork blocks) reaches existing volumes.
|
||||||
|
# Assert those blocks are present and that the file is still valid JSON.
|
||||||
|
if command -v jq >/dev/null 2>&1 && [ -f "$HOME/.pi/agent/settings.json" ]; then
|
||||||
|
if jq -e 'has("observational-memory") and has("pi-fork")' "$HOME/.pi/agent/settings.json" >/dev/null 2>&1; then
|
||||||
|
pass "settings.json has observational-memory + pi-fork blocks (template merge)"
|
||||||
|
else
|
||||||
|
fail "settings.json missing observational-memory and/or pi-fork blocks (template merge did not land)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# pi package registrations (pi install <local-path> → recorded in settings.json)
|
# pi package registrations (pi install <local-path> → recorded in settings.json)
|
||||||
if [ -f "$HOME/.pi/agent/settings.json" ]; then
|
if [ -f "$HOME/.pi/agent/settings.json" ]; then
|
||||||
for pkg in pi-fork pi-observational-memory; do
|
for pkg in pi-fork pi-observational-memory; do
|
||||||
@@ -214,6 +234,16 @@ else
|
|||||||
fail "~/.bash_aliases missing"
|
fail "~/.bash_aliases missing"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# History flush must survive shell nesting. The DEVBOX_HIST_SET guard must NOT
|
||||||
|
# be exported: if it leaks into child processes, nested shells (esp. tmux
|
||||||
|
# panes) skip installing `history -a` and lose in-memory history on abrupt
|
||||||
|
# termination. Assert a child login shell still wires up the per-prompt flush.
|
||||||
|
if bash -lic 'bash -lic "case \"\$PROMPT_COMMAND\" in *\"history -a\"*) exit 0;; *) exit 1;; esac"' </dev/null >/dev/null 2>&1; then
|
||||||
|
pass "nested shell installs 'history -a' (DEVBOX_HIST_SET not exported)"
|
||||||
|
else
|
||||||
|
fail "nested shell missing 'history -a' — DEVBOX_HIST_SET leaking to children?"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -f "$HOME/.inputrc" ]; then
|
if [ -f "$HOME/.inputrc" ]; then
|
||||||
pass "~/.inputrc exists"
|
pass "~/.inputrc exists"
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user