diff --git a/bin/gs b/bin/gs index d851a78..630f0e1 100755 --- a/bin/gs +++ b/bin/gs @@ -16,7 +16,7 @@ usage() { cat <<'EOF' gs - gentle-shell on main, plus one disposable worktree per PR - gs [pi args...] Open gentle-shell (--link) in the current directory. + gs [pi args...] Open gentle-shell (--isolated) in the current directory. Consumer: always the main build from gs sync. Workshop: inside a gentle-shell clone or worktree, Pi loads that path (gs run); elsewhere the synced clone. @@ -31,7 +31,7 @@ gs - gentle-shell on main, plus one disposable worktree per PR gs new New branch from fresh origin/main gs review Check out someone else's PR to test or review it gs base Clean origin/main worktree, to compare failures - gs run [pi args...] Run gentle-shell --link with this worktree as --package-root + gs run [pi args...] Run gentle-shell --isolated with this worktree as --package-root gs sync Bring gentle-shell, gentle-ai and engram to main, run gentle-ai sync for managed configs, and check compatibility (workshop: local clones; elsewhere: GitHub) @@ -54,7 +54,8 @@ Fastest start: gs done -> inside the worktree, after the merge (claim, comment, label, push and merge stay yours) Each session: one worktree, Pi loads the package from it, /reload picks up edits. - Sessions share ~/.pi/agent (--link) and subagents use the main clone. + Sessions share the isolated home ~/.gentle-shell/agent (--isolated, never + --link) and subagents use the main clone. Workshop sync never runs pi update. gs sync is separate: run it with no other session open. gs and gs sync share one source of truth: workshop launches the clone it syncs; @@ -183,17 +184,18 @@ open_or_finish() { pr_prompt() { # Same cortex-only rule as issue_prompt: the cortex variant is mandatory. - printf 'Review Gentleman-Programming/%s PR #%s using the cortex-maintainer-delivery skill, loading ~/.pi/agent/skills/cortex-maintainer-delivery/SKILL.md first (never the plain maintainer-delivery skill): read the PR, its linked issue, CI status and diff; run its preflight and race check; then report scope, risks, and what to test in Spanish. Do not comment, push, or merge.' "$1" "$2" + printf 'Review Gentleman-Programming/%s PR #%s using the cortex-maintainer-delivery skill, loading it first (never the plain maintainer-delivery skill): read the PR, its linked issue, CI status and diff; run its preflight and race check; then report scope, risks, and what to test in Spanish. Do not comment, push, or merge.' "$1" "$2" } issue_prompt() { # Plan-first: the session presents the kickoff and STOPS. Implementation # starts only after the user explicitly approves the plan (agreed workflow; # the previous "then work test-first" wording made sessions auto-implement). - # The CORTEX variant of the skill is mandatory, referenced by name and path: + # The CORTEX variant of the skill is mandatory, referenced by name (no legacy + # ~/.pi/agent path: sessions run on the isolated home): # there is also a plain maintainer-delivery skill and the session must not # pick that one. - printf 'Take Gentleman-Programming/%s issue #%s using the cortex-maintainer-delivery skill, loading ~/.pi/agent/skills/cortex-maintainer-delivery/SKILL.md first (never the plain maintainer-delivery skill): run its preflight, read the issue and repo conventions, then present a kickoff plan (expected behavior, approach, out of scope, branch %s) in Spanish and STOP. Do not implement, edit files, or commit: implementation starts only after the user explicitly approves the plan. Claiming, commenting, pushing, and opening the PR stay mine.' "$1" "$2" "$3" + printf 'Take Gentleman-Programming/%s issue #%s using the cortex-maintainer-delivery skill, loading it first (never the plain maintainer-delivery skill): run its preflight, read the issue and repo conventions, then present a kickoff plan (expected behavior, approach, out of scope, branch %s) in Spanish and STOP. Do not implement, edit files, or commit: implementation starts only after the user explicitly approves the plan. Claiming, commenting, pushing, and opening the PR stay mine.' "$1" "$2" "$3" } cmd_pr() { @@ -269,7 +271,7 @@ cmd_run() { grep -q '"name": *"gentle-pi"' "$root/package.json" 2>/dev/null || die "$root is not gentle-shell" [ -d "$root/node_modules" ] || die "no node_modules in $root (pnpm install --frozen-lockfile)" printf 'gs: gentle-shell @ %s (%s); subagents use main\n' "$(git -C "$root" rev-parse --short HEAD)" "$root" >&2 - cd "$root" && exec node "$root/bin/gentle-shell.mjs" --link --package-root "$root" "$@" + cd "$root" && exec node "$root/bin/gentle-shell.mjs" --isolated --package-root "$root" "$@" } # Workshop (agent-gentle): clean clones in ~/dev/gentle, Pi loads the gentle-shell clone. @@ -365,16 +367,19 @@ sync_dotfiles() { cmd_sync() { local ai_files="" dot_change="" repo shell bin="$HOME/.local/share/gentle-ai/main" reg="$HOME/.pi/gentle-ai/dev-binary.json" name + # The dev-binary registration is install-level state: the official launcher + # reads it from ~/.pi/gentle-ai even in the isolated home (gentle-shell + # lib/gentle-shell-launcher.ts UNMIGRATED_CONFIG_FILES), so it stays there. # Versions before the sync power the closing message: restart only on change. local shell_before ai_before engram_before shell_before=$(shell_version); ai_before=$(ai_version); engram_before=$(engram_version) # Stale GOROOT/GOBIN from a removed version manager breaks every go build. if [ -n "${GOROOT:-}" ] && [ ! -d "$GOROOT" ]; then unset GOROOT; fi if [ -n "${GOBIN:-}" ] && [ ! -d "$(dirname "$GOBIN")" ]; then unset GOBIN; fi - # pi may live in its managed home instead of PATH (managed install schema). - command -v pi >/dev/null 2>&1 || export PATH="$HOME/.pi/agent/bin:$PATH" mkdir -p "$bin" "$HOME/.local/bin" "$(dirname "$reg")" if is_workshop; then + # Workshop runs the Pi bundled in the clone (node_modules): no legacy + # ~/.pi/agent runtime on PATH and no pi update. printf 'gs sync — %s — workshop (local clones)\n' "$(date '+%Y-%m-%d %H:%M')" for repo in $REPOS; do [ -d "$CLONES/$repo/.git" ] || die "missing clean clone $CLONES/$repo" @@ -394,6 +399,8 @@ cmd_sync() { else printf 'gs sync — %s — consumer (official update channels)\n' "$(date '+%Y-%m-%d %H:%M')" command -v gentle-shell >/dev/null 2>&1 || die "consumer sync needs gentle-shell on PATH; install it first" + # pi may live in its managed home instead of PATH (managed install schema). + command -v pi >/dev/null 2>&1 || export PATH="$HOME/.pi/agent/bin:$PATH" # pi self-update cannot handle every installation schema (e.g. bun-compiled # /opt/pi binaries): a failure there must not abort the sync, the official # main channel below is the actual update path for Shell and AI. @@ -519,9 +526,6 @@ cmd_sync() { else printf 'compat: INCOMPATIBLE (gentle-ai emits %s, gentle-shell reads %s)\n' "$emits" "$reads" fi - if is_workshop && grep -qE 'npm:gentle-(pi|engram)|git:github.com/Gentleman-Programming/gentle-(pi|shell)' "$HOME/.pi/agent/settings.json" 2>/dev/null; then - printf 'WARN: ~/.pi/agent/settings.json lists a published gentle-pi/gentle-engram again; remove it\n' - fi if [ -n "$ai_files" ] && [ "$ai_files" -gt 0 ]; then changed="$changed managed configs ($ai_files files)" fi @@ -581,7 +585,7 @@ cmd_launch() { root=$(shell_root) || die "gentle-shell not on PATH (install it, then run: gs sync)" [ -f "$root/bin/gentle-shell.mjs" ] || die "gentle-shell not found at $root (run: gs sync)" herdr_tab_repo - exec node "$root/bin/gentle-shell.mjs" --link "$@" + exec node "$root/bin/gentle-shell.mjs" --isolated "$@" } case "${1:-}" in diff --git a/docs/gentle-official-migration.md b/docs/gentle-official-migration.md index 1fd28dd..c4dd508 100644 --- a/docs/gentle-official-migration.md +++ b/docs/gentle-official-migration.md @@ -265,6 +265,7 @@ Corrección del usuario, textual: - Shell mantiene su mecanismo oficial `gentle-shell upgrade --channel main`. No asumir que ese comando actualiza el Gentle AI externo que usa Claude Code. - Después de actualizar, comprobar qué binario externo resuelve el PATH y qué versión/commit quedó instalado; evitar actualizar una copia y ejecutar otra. Definir y verificar el mecanismo oficial de sincronización de assets de Claude Code cuando se implemente. - Implementado en [`bin/gs-official`](../bin/gs-official) ([doc](gs-official.md)), desplegado solo en hosts migrados como `~/.local/bin/gs`. El `bin/gs` legacy de Mac y workshop no cambia. El PATH permanente se activa con el fragmento opt-in [`zsh/scripts/official-gentle-path.zsh`](../zsh/scripts/official-gentle-path.zsh), enlazado en `~/.config/cortex-dotfiles/shell/official-gentle-path.zsh`. +- Workshop (agent-gentle): el `bin/gs` de workshop conserva sus accesorios (`gs issue`, `gs pr`, `gs review`, `gs new`, `gs base`, `gs ls`, `gs done`, `gs sync`), pero todo arranque usa el home aislado (`--isolated`, nunca `--link`) y, desde un clon o worktree, `--package-root `. `gs sync` en workshop no agrega `~/.pi/agent/bin` al PATH ni ejecuta `pi update`; registra Gentle AI de main en `~/.pi/gentle-ai/dev-binary.json`: es estado de instalación y el lanzador oficial lo lee ahí también con el home aislado, así que no se mueve ni se retira. Ver [gs-sync.md](gs-sync.md). `gs-official` y Mac/agent-dev no cambian por esto. - El instalador oficial `install.sh --channel beta` falló en esta sesión: `get_main_commit_sha` emite un mensaje informativo en stdout y su captura mezcla ese mensaje con el SHA, causando una URL inválida al buscar `go.mod`. Se comprobó en el script remoto. No parchear el instalador ni desactivar verificaciones como workaround. - También hubo un error de pegado independiente (`\\ |` en una misma línea). Corregir el pegado no arregla el bug del instalador. diff --git a/docs/gs-sync.md b/docs/gs-sync.md index 904eccf..397852b 100644 --- a/docs/gs-sync.md +++ b/docs/gs-sync.md @@ -10,6 +10,31 @@ The launcher loads its extensions and its bundled Pi from its own package root, so the package it starts from decides what you see. +## Isolated home, never `--link` + +Every launch (`gs`, `gs run`, and the Pi session opened by `gs pr` / `gs issue`) +passes `--isolated`, so Shell uses the official isolated home +`~/.gentle-shell/agent`; from a clone or worktree it also passes +`--package-root `. `gs` never passes `--link` and never loads `~/.pi/agent`. + +Workshop `gs sync` also stays off the legacy Pi home: + +- It does not add `~/.pi/agent/bin` to PATH and does not run `pi update` or + `pi update --extensions`; Shell runs the Pi bundled in the clone + (`node_modules/@earendil-works/pi-coding-agent`). +- It registers Gentle AI main in `~/.pi/gentle-ai/dev-binary.json` (file + `0600`, atomic write) with + `{"schema":"gentle-pi.dev-binary/v1","path":"~/.local/share/gentle-ai/main/gentle-ai"}`. + This path is install-level state: the official launcher reads it there even + for the isolated home, so it is not moved to `~/.gentle-shell/gentle-ai`. +- It no longer warns about `gentle-pi`/`gentle-engram` in the isolated home's + `settings.json`: the official Shell declares and requires them there, and the + `--package-root` take-over loads the clone instead of the published gentle-pi. + +The `gs pr` / `gs issue` kickoff prompts name the `cortex-maintainer-delivery` +skill without a home path. Consumer sync keeps its official update steps +(`pi update`, `gentle-shell upgrade --channel main`, `pi update --extensions`). + ## Why this changed Before, consumer `gs` started @@ -51,4 +76,5 @@ Run these on each machine. A machine counts as aligned only after step 3 passes ## Tests `tests/gs_test.sh` runs offline in a throwaway HOME with stub binaries and covers -the launcher (consumer and workshop) and the sync result messages. +the launcher (consumer and workshop, `gs run`, `gs pr`, `gs issue`), the isolated +registration, and the sync result messages. diff --git a/odd/tasks/agent-gentle-official-home.md b/odd/tasks/agent-gentle-official-home.md new file mode 100644 index 0000000..8dc2aac --- /dev/null +++ b/odd/tasks/agent-gentle-official-home.md @@ -0,0 +1,27 @@ +# agent-gentle: workshop gs on the official isolated home + +Migrate the dogfooding host agent-gentle off the legacy Pi home without losing the workshop `bin/gs` accessories. +Shell keeps running from the gentle-shell clone; only the home, Pi runtime and Gentle AI registration move to the official layout. + +## Specs + +- S1. Keep every workshop accessory: "tenemos una serie de accesorios tipo gs issue shell 1234 para revisar un issue o un pr ... revisalo bien antes de arrancar". `gs issue`, `gs pr`, `gs review`, `gs new`, `gs base`, `gs ls`, `gs done` and `gs sync` keep their worktree/git/gh behavior. +- S2. Never `--link`: "Shell y Gentle AI SIEMPRE en main. Nunca release, nunca --link, nunca --include-shared." Every Shell launch in `bin/gs` (`gs`, `gs run`, launches from `gs pr`/`gs issue`) uses the isolated home (`--isolated`) and, from a clone or worktree, keeps `--package-root `. +- S3. No legacy Pi runtime: `bin/gs` does not add `~/.pi/agent/bin` to PATH and does not run `pi update` / `pi update --extensions` in workshop mode. Shell uses the Pi package inside the clone (`node_modules/@earendil-works/pi-coding-agent`). +- S4. Gentle AI from main inside Shell: workshop `gs sync` keeps writing the dev-binary registration `{"schema":"gentle-pi.dev-binary/v1","path":"<~/.local/share/gentle-ai/main/gentle-ai>"}` to `~/.pi/gentle-ai/dev-binary.json` (0600, atomic). It is install-level state the official launcher reads there even for the isolated home (gentle-shell `lib/gentle-shell-launcher.ts:252-254`, `lib/gentle-ai-binary.ts:218` `launcherMarker: false`); it is never moved or retired. +- S5. Prompts for `gs pr` / `gs issue` no longer point at `~/.pi/agent/skills/...`; they name the `cortex-maintainer-delivery` skill without a legacy home path. +- S6. Help text and docs (`docs/gs-sync.md`, `docs/gentle-official-migration.md`) describe the new behavior; `gs-official` and Mac/agent-dev are unaffected. +- S7. Host deploy on agent-gentle: confirm last NAS backup succeeded; then pull dotfiles, run `gs sync`, replace the `~/.local/bin/gentle-shell` wrapper so it no longer sets `GENTLE_SHELL_PI=~/.pi/agent/bin/pi`, and move retired legacy pieces to a `mktemp -d` backup (never delete). Never touch Engram data, credentials, conversations, worktrees with uncommitted changes, or Herdr. + +## Tasks + +- T1 (S2-S6) worker + parent fixes: change `bin/gs` + tests + docs. Done. Commit: e89c3d1 +- T2 (S7) parent: deploy and verify on agent-gentle. Commit: n/a (host) + +## Log + +- L1 User: "bueno ahora tenemos que hacer la que para mi es la mas complicada ... capaz no lo es. Agent-gentle es un entorno tipo dogfooding ... yo siendo vos primero miraría bien quehace. Ahí lo que hacemos es trabajar directo con gentle-shell, gentle-ai y engram. Con eso en mente tenemos una serie de accesorios tipo gs issue shell 1234 para revisar un issue o un pr ... revisalo bien antes de arrancar" +- L2 User approved the approach "mantener el gs de workshop y migrar solo su arranque al home aislado": "si". +- L3 Evidence: official launcher (clone 14f44d11c) accepts `--isolated` with `--package-root` (only `--link`+`--isolated` and `--isolated`+`--home` conflict, `lib/gentle-shell-launcher.ts:169-174`); clone has adjacent Pi 1.4.0; isolated home `~/.gentle-shell/agent` already holds pi-mcp-adapter and brains; Engram already at main tip `7cf4ed29b6f9`. +- L4 Parent review: removed the isolated-settings gentle-pi/gentle-engram warning; on agent-gentle the official Shell declares both there (gentle-engram is its required companion), so it would fire on every sync. Skill cortex-maintainer-delivery exists only in ~/.pi/agent/skills on agent-gentle; T2 must expose it to the isolated home before retiring legacy. +- L5 Verifier FAIL on S4: the launcher reads dev-binary.json from ~/.pi/gentle-ai, not the isolated config home (confirmed on agent-gentle clone 14f44d11c, lib/gentle-ai-binary.ts:218). S4 rewritten: keep writing ~/.pi/gentle-ai/dev-binary.json; T1 reopened and fixed. diff --git a/tests/gs_test.sh b/tests/gs_test.sh index 13adec7..687c1d7 100755 --- a/tests/gs_test.sh +++ b/tests/gs_test.sh @@ -29,7 +29,9 @@ pkg=$(dirname "$(dirname "$1")"); shift if [ "${1:-}" = --version ]; then printf 'gentle-shell %s\npi 1.4.0\n' "$(cat "$pkg/VERSION")"; exit 0; fi echo "launch $pkg $*" >> "$CALLS" EOF - for b in pi go pnpm npm; do printf '#!/bin/sh\nexit 0\n' > "$S/$b"; done + printf '#!/bin/sh\necho "go PATH=$PATH" >> "$CALLS"\n' > "$S/go" + for b in pnpm npm; do printf '#!/bin/sh\nexit 0\n' > "$S/$b"; done + printf '#!/bin/sh\necho "pi $*" >> "$CALLS"\necho "PATH=$PATH" >> "$CALLS"\n' > "$S/pi" # Legacy pi-managed checkout that must never be launched again. make_pkg "$HOME/.pi/agent/git/github.com/Gentleman-Programming/gentle-pi" 4.3.0 # gentle-ai binary registered by the main channel. @@ -74,8 +76,8 @@ sha_of() { git -C "$GS_SHELL_REMOTE" rev-parse HEAD; } setup consumer OUT=$("$GS" --foo 2>&1); L=$(cat "$CALLS" 2>/dev/null) -check "consumer: gs launches the package behind gentle-shell on PATH" \ - '[[ "$L" == "launch $NPM --link --foo" ]]' +check "consumer: gs launches the package behind gentle-shell on PATH, isolated" \ + '[[ "$L" == "launch $NPM --isolated --foo" ]]' check "consumer: gs never launches the legacy pi git checkout" '[[ "$L" != *".pi/agent/git"* ]]' setup consumer; rm "$HOME/.local/bin/gentle-shell" @@ -85,7 +87,7 @@ check "consumer: no gentle-shell on PATH fails instead of opening the legacy cop setup workshop OUT=$("$GS" x 2>&1); L=$(cat "$CALLS" 2>/dev/null) -check "workshop: gs launches the clean clone" '[[ "$L" == "launch $HOME/dev/gentle/gentle-shell --link x" ]]' +check "workshop: gs launches the clean clone, isolated" '[[ "$L" == "launch $HOME/dev/gentle/gentle-shell --isolated x" ]]' # A gentle-shell worktree the operator is working in (dogfooding target). make_worktree() { @@ -97,12 +99,48 @@ make_worktree() { setup workshop; make_worktree OUT=$(cd "$W/bin" && "$GS" y 2>&1); L=$(cat "$CALLS" 2>/dev/null) check "workshop: inside a gentle-shell worktree gs loads that path" \ - '[[ "$L" == "launch $W --link --package-root $W y" ]]' + '[[ "$L" == "launch $W --isolated --package-root $W y" ]]' setup consumer; make_worktree OUT=$(cd "$W" && "$GS" 2>&1); L=$(cat "$CALLS" 2>/dev/null) check "consumer: inside a gentle-shell checkout gs still opens the main build" \ - '[[ "$L" == "launch $NPM --link" ]]' + '[[ "$L" == "launch $NPM --isolated" ]]' + +setup workshop; make_worktree +OUT=$(cd "$W" && "$GS" run --z 2>&1); L=$(cat "$CALLS" 2>/dev/null) +check "workshop: gs run uses the isolated home with this worktree as --package-root" \ + '[[ "$L" == "launch $W --isolated --package-root $W --z" ]]' + +# gs pr / gs issue on an existing shell worktree: Pi opens on it with the kickoff. +gh_stub() { + cat > "$S/gh" <<'EOF' +#!/bin/sh +case "$1 $2" in + "issue view") printf 'OPEN\037\037fix: thing\037type:bug\n' ;; +esac +exit 0 +EOF + chmod +x "$S/gh" +} +setup workshop; gh_stub +W="$HOME/dev/worktrees/gentle-shell-pr-7"; make_pkg "$W" 9.9.9-pr +git init -q "$W"; mkdir -p "$W/node_modules"; printf '{\n "name": "gentle-pi"\n}\n' > "$W/package.json" +git -C "$W" add -A; git -C "$W" -c user.email=t@t -c user.name=t commit -q -m pr +OUT=$("$GS" pr shell 7 2>&1); L=$(cat "$CALLS" 2>/dev/null) +check "workshop: gs pr opens the worktree isolated, never --link" \ + '[[ "$L" == "launch $W --isolated --package-root $W Review Gentleman-Programming/gentle-shell PR #7 "* ]] && [[ "$L" != *--link* ]]' +check "workshop: gs pr kickoff names the cortex skill without a legacy home path" \ + '[[ "$L" == *"cortex-maintainer-delivery skill"* ]] && [[ "$L" != *".pi/agent"* ]]' + +setup workshop; gh_stub +W="$HOME/dev/worktrees/gentle-shell-issue-8"; make_pkg "$W" 9.9.9-is +git init -q "$W"; mkdir -p "$W/node_modules"; printf '{\n "name": "gentle-pi"\n}\n' > "$W/package.json" +git -C "$W" add -A; git -C "$W" -c user.email=t@t -c user.name=t commit -q -m is +OUT=$("$GS" issue shell 8 2>&1); L=$(cat "$CALLS" 2>/dev/null) +check "workshop: gs issue reuses the worktree and opens it isolated, never --link" \ + '[[ "$OUT" == *"reusing $W"* ]] && [[ "$L" == "launch $W --isolated --package-root $W Take Gentleman-Programming/gentle-shell issue #8 "* ]] && [[ "$L" != *--link* ]]' +check "workshop: gs issue kickoff names the cortex skill without a legacy home path" \ + '[[ "$L" == *"cortex-maintainer-delivery skill"* ]] && [[ "$L" != *".pi/agent"* ]]' # --- sync (workshop) ---------------------------------------------------------- @@ -117,11 +155,25 @@ for r in gentle-shell gentle-ai engram; do git -C "$c" fetch -q origin done git -C "$HOME/dev/gentle/gentle-shell" checkout -q --detach +mkdir -p "$HOME/dev/gentle/engram/plugin/pi" +rm "$S/pi" # workshop needs no Pi runtime of its own on PATH mkdir -p "$HOME/dev/gentle/gentle-shell/.engram" "$HOME/dev/gentle/gentle-shell/odd/checks" touch "$HOME/dev/gentle/gentle-shell/.engram/x" "$HOME/dev/gentle/gentle-shell/odd/checks/y" OUT=$("$GS" sync 2>&1); rc=$? check "workshop sync: untracked session files and detached HEAD do not block it" \ '[[ "$OUT" != *"clean clones only"* ]] && [ "$(git -C "$HOME/dev/gentle/gentle-shell" branch --show-current)" = main ] && [ -e "$HOME/dev/gentle/gentle-shell/.engram/x" ]' +REG="$HOME/.pi/gentle-ai/dev-binary.json" +check "workshop sync: registers gentle-ai main where the launcher reads it (~/.pi/gentle-ai, file 0600)" \ + '[ "$(cat "$REG")" = "{\"schema\":\"gentle-pi.dev-binary/v1\",\"path\":\"$HOME/.local/share/gentle-ai/main/gentle-ai\"}" ] && [ "$(stat -c %a "$REG" 2>/dev/null || stat -f %Lp "$REG")" = 600 ]' +check "workshop sync: writes no registration into the isolated config home" \ + '[ ! -e "$HOME/.gentle-shell/gentle-ai/dev-binary.json" ]' +check "workshop sync: never runs pi update nor adds ~/.pi/agent/bin to PATH" \ + '! grep -q "^pi " "$CALLS" 2>/dev/null && grep -q "^go PATH=" "$CALLS" && ! grep -q "PATH=.*\.pi/agent/bin" "$CALLS"' +mkdir -p "$HOME/.gentle-shell/agent"; printf '{"packages":["npm:gentle-pi","npm:gentle-engram"]}\n' > "$HOME/.gentle-shell/agent/settings.json" +OUT=$("$GS" sync 2>&1) +check "workshop sync: isolated home packages the official Shell requires raise no warning" \ + '[[ "$OUT" != *"WARN:"*"settings.json"* ]]' +rm "$HOME/.gentle-shell/agent/settings.json" echo tracked >> "$HOME/dev/gentle/gentle-shell/VERSION"; git -C "$HOME/dev/gentle/gentle-shell" add VERSION OUT=$("$GS" sync 2>&1); rc=$? check "workshop sync: tracked edits in a clone still stop it" '[ $rc -ne 0 ] && [[ "$OUT" == *"clean clones only"* ]]' @@ -133,6 +185,8 @@ OUT=$(UPGRADE_TO="4.5.2-main.${main:0:12}" "$GS" sync 2>&1); rc=$? check "sync: reports the version gs opens, from the same package" \ '[ $rc -eq 0 ] && [[ "$OUT" == *"gs opens: 4.5.2-main.${main:0:12} ($NPM)"* ]]' check "sync: a real update asks for a restart" '[[ "$OUT" == *"shell (4.5.1-main.feee99d88dae -> 4.5.2-main"* ]]' +check "consumer sync: still runs pi update and pi update --extensions" \ + 'grep -qx "pi update" "$CALLS" && grep -qx "pi update --extensions" "$CALLS"' check "sync: warns about the unused legacy checkout without deleting it" \ '[[ "$OUT" == *"stale legacy checkout"* ]] && [ -d "$HOME/.pi/agent/git/github.com/Gentleman-Programming/gentle-pi" ]'