@codyswann/lisa 2.338.2 → 2.338.4

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.
Files changed (66) hide show
  1. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  2. package/dist/core/upstream-evidence-manifest.js +4 -2
  3. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  4. package/package.json +1 -1
  5. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  6. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  7. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/SKILL.md +22 -5
  8. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +23 -1
  9. package/plugins/lisa/skills/lisa-setup-remote-env/SKILL.md +22 -5
  10. package/plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +23 -1
  11. package/plugins/lisa-agy/plugin.json +1 -1
  12. package/plugins/lisa-agy/skills/lisa-setup-remote-env/SKILL.md +22 -5
  13. package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +23 -1
  14. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  16. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  17. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-copilot/skills/lisa-setup-remote-env/SKILL.md +22 -5
  21. package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +23 -1
  22. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-cursor/skills/lisa-setup-remote-env/SKILL.md +22 -5
  24. package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +23 -1
  25. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  27. package/plugins/lisa-expo-agy/plugin.json +1 -1
  28. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  37. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  38. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  43. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  47. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  48. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-rails-agy/plugin.json +1 -1
  53. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  57. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  58. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  63. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/src/base/skills/lisa-setup-remote-env/SKILL.md +22 -5
  66. package/plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +23 -1
package/package.json CHANGED
@@ -118,7 +118,7 @@
118
118
  }
119
119
  },
120
120
  "name": "@codyswann/lisa",
121
- "version": "2.338.2",
121
+ "version": "2.338.4",
122
122
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
123
123
  "main": "dist/index.js",
124
124
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -12,11 +12,26 @@ Prepare a remote surface so a host project can execute there. Today that means *
12
12
 
13
13
  The remote environment's own configuration fields stay **one line into the repository**. Nothing else is pasted into a vendor UI.
14
14
 
15
- ```text
16
- setup: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] && exit "$rc"; g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; do [ -e "$c" ] && g=1; done; if [ "$g" -eq 1 ]; then echo "lisa-remote-env entrypoint not found, but a checkout is present. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; fi; ten="${LISA_TENANT:-${LISA_SECRETS_NAMESPACE:-}}"; if [ -n "$ten" ]; then echo "No checkout; preparing tools and credentials for $ten."; tw=0; tt=0; ts=0; tp=0; npx -y @codyswann/lisa@2.338.1 workstation --install --agents=none --tools=none --provider="${LISA_PROVIDER:-${LISA_SECRETS_PROVIDER:-bitwarden}}" || tw=$?; export PATH="$HOME/.local/bin:$HOME/.opencode/bin:$HOME/.local/share/sonarqube-cli/bin:$PATH"; npx -y @codyswann/lisa@2.338.1 remote-env --phase=secrets || ts=$?; w=$(npx -y @codyswann/lisa@2.338.1 remote-env --print-tools 2>/dev/null) || tp=$?; w=$(printf "%s\n" "$w" | tail -1); [ "$tp" -eq 0 ] || echo "SETUP INCOMPLETE: could not read the tool list from the vault (exit $tp). Installing the full catalogue." >&2; npx -y @codyswann/lisa@2.338.1 workstation --install --agents=none --tools="$w" --provider="${LISA_PROVIDER:-${LISA_SECRETS_PROVIDER:-bitwarden}}" || tt=$?; [ "$tw" -eq 0 ] && [ "$tt" -eq 0 ] || echo "SETUP INCOMPLETE: tool install failed (exit $tw/$tt). The session will start WITHOUT the pinned tools." >&2; [ "$ts" -eq 0 ] || echo "SETUP INCOMPLETE: secrets did not materialize (exit $ts). The session will start WITHOUT credentials." >&2; else echo "No checkout and no tenant configured; nothing to prepare."; fi; exit 0
17
- maintenance: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
15
+ **Ask for that line; do not copy it from here.**
16
+
17
+ ```bash
18
+ npx -y @codyswann/lisa@latest remote-env --emit=claude-web
18
19
  ```
19
20
 
21
+ The field pins the exact Lisa it runs, and the emitter reads that version from
22
+ the package it is running out of — so the line it prints is always pinned to the
23
+ version that printed it.
24
+
25
+ A copy written into this file cannot have that property. It is a snapshot taken
26
+ when the package was *built*, and the release bumps the version *after* the
27
+ build, so a published tarball's copy names the previous release. That is not a
28
+ cosmetic lag: the pinned version predates whatever this file documents, so a
29
+ pasted copy can call flags that version does not implement. Measured on
30
+ `2.338.1`, whose embedded copy named `2.338.0` — a Lisa with no `--print-tools`,
31
+ no `--tools`, and no `tools-from-notes.mjs`. Unknown flags are ignored rather
32
+ than rejected, so it did not fail; it installed the full catalogue and re-ran the
33
+ whole setup, three times over, inside a five-minute budget.
34
+
20
35
  **That line is identical for every project AND every surface.** Nothing in it names the
21
36
  repository or the package manager, so it can be pasted unchanged anywhere.
22
37
 
@@ -236,8 +251,10 @@ When emitting, produce exactly:
236
251
  ```text
237
252
  Environment name: <project> remote executor
238
253
  Repository: <org>/<repo> (must be the default checkout)
239
- Setup script: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
240
- Maintenance: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
254
+ Setup script: <printed by `remote-env --emit`; never copied
255
+ from prose, so its pin is always the version
256
+ that printed it>
257
+ Maintenance: <same line, printed by the same command>
241
258
  (identical for every project — the script finds the
242
259
  checkout and installs from the committed lockfile)
243
260
  Environment vars: LISA_SECRETS_SURFACE=codex-cloud
@@ -662,7 +662,14 @@ export const SETUP_FIELD =
662
662
  "/workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; " +
663
663
  'do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); ' +
664
664
  'case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; ' +
665
- 'n=$((n+1)); bash "$f" || rc=$?; done; ' +
665
+ // `rc` keeps the FIRST failure, which is what the contract below promises.
666
+ //
667
+ // A bare `rc=$?` keeps the last one, so with two broken checkouts the
668
+ // operator is shown the second and the first is lost — the precise hiding the
669
+ // documented behaviour exists to prevent. A success never overwrites, because
670
+ // `||` only fires on failure, so the bug was confined to the multiple-failure
671
+ // case that the rule was written for.
672
+ 'n=$((n+1)); bash "$f" || { s=$?; [ "$rc" -ne 0 ] || rc=$s; }; done; ' +
666
673
  '[ "$n" -gt 0 ] && exit "$rc"; ' +
667
674
  'g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; ' +
668
675
  'do [ -e "$c" ] && g=1; done; ' +
@@ -912,6 +919,21 @@ export function emitClaudeWeb({ bootstrapKey }) {
912
919
  " is why exactly one value needs to live here.",
913
920
  "",
914
921
  " Setup script:",
922
+ "",
923
+ " A setup script sees NONE of the variables configured above — it runs",
924
+ " while the image is being built, before the environment exists. So a",
925
+ " session with no checkout has to be told its tenant inside the script",
926
+ " itself, or the field finds nothing to prepare and exits 0 looking like",
927
+ " success. Put these three lines FIRST, then the line after them:",
928
+ "",
929
+ " export LISA_TENANT=<your namespace>",
930
+ ` export ${key}='<the same value as above>'`,
931
+ " export LISA_SECRETS_SURFACE=claude-web",
932
+ "",
933
+ " LISA_SECRETS_SURFACE is set explicitly rather than left to detection:",
934
+ " detection keys off CLAUDE_CODE_REMOTE, and a surface that does not set",
935
+ " it falls through to `local`, which writes no credentials to disk at all.",
936
+ "",
915
937
  ` ${SETUP_FIELD}`,
916
938
  "",
917
939
  " This line is identical for every project and every surface — nothing",
@@ -12,11 +12,26 @@ Prepare a remote surface so a host project can execute there. Today that means *
12
12
 
13
13
  The remote environment's own configuration fields stay **one line into the repository**. Nothing else is pasted into a vendor UI.
14
14
 
15
- ```text
16
- setup: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] && exit "$rc"; g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; do [ -e "$c" ] && g=1; done; if [ "$g" -eq 1 ]; then echo "lisa-remote-env entrypoint not found, but a checkout is present. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; fi; ten="${LISA_TENANT:-${LISA_SECRETS_NAMESPACE:-}}"; if [ -n "$ten" ]; then echo "No checkout; preparing tools and credentials for $ten."; tw=0; tt=0; ts=0; tp=0; npx -y @codyswann/lisa@2.338.1 workstation --install --agents=none --tools=none --provider="${LISA_PROVIDER:-${LISA_SECRETS_PROVIDER:-bitwarden}}" || tw=$?; export PATH="$HOME/.local/bin:$HOME/.opencode/bin:$HOME/.local/share/sonarqube-cli/bin:$PATH"; npx -y @codyswann/lisa@2.338.1 remote-env --phase=secrets || ts=$?; w=$(npx -y @codyswann/lisa@2.338.1 remote-env --print-tools 2>/dev/null) || tp=$?; w=$(printf "%s\n" "$w" | tail -1); [ "$tp" -eq 0 ] || echo "SETUP INCOMPLETE: could not read the tool list from the vault (exit $tp). Installing the full catalogue." >&2; npx -y @codyswann/lisa@2.338.1 workstation --install --agents=none --tools="$w" --provider="${LISA_PROVIDER:-${LISA_SECRETS_PROVIDER:-bitwarden}}" || tt=$?; [ "$tw" -eq 0 ] && [ "$tt" -eq 0 ] || echo "SETUP INCOMPLETE: tool install failed (exit $tw/$tt). The session will start WITHOUT the pinned tools." >&2; [ "$ts" -eq 0 ] || echo "SETUP INCOMPLETE: secrets did not materialize (exit $ts). The session will start WITHOUT credentials." >&2; else echo "No checkout and no tenant configured; nothing to prepare."; fi; exit 0
17
- maintenance: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
15
+ **Ask for that line; do not copy it from here.**
16
+
17
+ ```bash
18
+ npx -y @codyswann/lisa@latest remote-env --emit=claude-web
18
19
  ```
19
20
 
21
+ The field pins the exact Lisa it runs, and the emitter reads that version from
22
+ the package it is running out of — so the line it prints is always pinned to the
23
+ version that printed it.
24
+
25
+ A copy written into this file cannot have that property. It is a snapshot taken
26
+ when the package was *built*, and the release bumps the version *after* the
27
+ build, so a published tarball's copy names the previous release. That is not a
28
+ cosmetic lag: the pinned version predates whatever this file documents, so a
29
+ pasted copy can call flags that version does not implement. Measured on
30
+ `2.338.1`, whose embedded copy named `2.338.0` — a Lisa with no `--print-tools`,
31
+ no `--tools`, and no `tools-from-notes.mjs`. Unknown flags are ignored rather
32
+ than rejected, so it did not fail; it installed the full catalogue and re-ran the
33
+ whole setup, three times over, inside a five-minute budget.
34
+
20
35
  **That line is identical for every project AND every surface.** Nothing in it names the
21
36
  repository or the package manager, so it can be pasted unchanged anywhere.
22
37
 
@@ -236,8 +251,10 @@ When emitting, produce exactly:
236
251
  ```text
237
252
  Environment name: <project> remote executor
238
253
  Repository: <org>/<repo> (must be the default checkout)
239
- Setup script: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
240
- Maintenance: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
254
+ Setup script: <printed by `remote-env --emit`; never copied
255
+ from prose, so its pin is always the version
256
+ that printed it>
257
+ Maintenance: <same line, printed by the same command>
241
258
  (identical for every project — the script finds the
242
259
  checkout and installs from the committed lockfile)
243
260
  Environment vars: LISA_SECRETS_SURFACE=codex-cloud
@@ -662,7 +662,14 @@ export const SETUP_FIELD =
662
662
  "/workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; " +
663
663
  'do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); ' +
664
664
  'case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; ' +
665
- 'n=$((n+1)); bash "$f" || rc=$?; done; ' +
665
+ // `rc` keeps the FIRST failure, which is what the contract below promises.
666
+ //
667
+ // A bare `rc=$?` keeps the last one, so with two broken checkouts the
668
+ // operator is shown the second and the first is lost — the precise hiding the
669
+ // documented behaviour exists to prevent. A success never overwrites, because
670
+ // `||` only fires on failure, so the bug was confined to the multiple-failure
671
+ // case that the rule was written for.
672
+ 'n=$((n+1)); bash "$f" || { s=$?; [ "$rc" -ne 0 ] || rc=$s; }; done; ' +
666
673
  '[ "$n" -gt 0 ] && exit "$rc"; ' +
667
674
  'g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; ' +
668
675
  'do [ -e "$c" ] && g=1; done; ' +
@@ -912,6 +919,21 @@ export function emitClaudeWeb({ bootstrapKey }) {
912
919
  " is why exactly one value needs to live here.",
913
920
  "",
914
921
  " Setup script:",
922
+ "",
923
+ " A setup script sees NONE of the variables configured above — it runs",
924
+ " while the image is being built, before the environment exists. So a",
925
+ " session with no checkout has to be told its tenant inside the script",
926
+ " itself, or the field finds nothing to prepare and exits 0 looking like",
927
+ " success. Put these three lines FIRST, then the line after them:",
928
+ "",
929
+ " export LISA_TENANT=<your namespace>",
930
+ ` export ${key}='<the same value as above>'`,
931
+ " export LISA_SECRETS_SURFACE=claude-web",
932
+ "",
933
+ " LISA_SECRETS_SURFACE is set explicitly rather than left to detection:",
934
+ " detection keys off CLAUDE_CODE_REMOTE, and a surface that does not set",
935
+ " it falls through to `local`, which writes no credentials to disk at all.",
936
+ "",
915
937
  ` ${SETUP_FIELD}`,
916
938
  "",
917
939
  " This line is identical for every project and every surface — nothing",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -12,11 +12,26 @@ Prepare a remote surface so a host project can execute there. Today that means *
12
12
 
13
13
  The remote environment's own configuration fields stay **one line into the repository**. Nothing else is pasted into a vendor UI.
14
14
 
15
- ```text
16
- setup: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] && exit "$rc"; g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; do [ -e "$c" ] && g=1; done; if [ "$g" -eq 1 ]; then echo "lisa-remote-env entrypoint not found, but a checkout is present. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; fi; ten="${LISA_TENANT:-${LISA_SECRETS_NAMESPACE:-}}"; if [ -n "$ten" ]; then echo "No checkout; preparing tools and credentials for $ten."; tw=0; tt=0; ts=0; tp=0; npx -y @codyswann/lisa@2.338.1 workstation --install --agents=none --tools=none --provider="${LISA_PROVIDER:-${LISA_SECRETS_PROVIDER:-bitwarden}}" || tw=$?; export PATH="$HOME/.local/bin:$HOME/.opencode/bin:$HOME/.local/share/sonarqube-cli/bin:$PATH"; npx -y @codyswann/lisa@2.338.1 remote-env --phase=secrets || ts=$?; w=$(npx -y @codyswann/lisa@2.338.1 remote-env --print-tools 2>/dev/null) || tp=$?; w=$(printf "%s\n" "$w" | tail -1); [ "$tp" -eq 0 ] || echo "SETUP INCOMPLETE: could not read the tool list from the vault (exit $tp). Installing the full catalogue." >&2; npx -y @codyswann/lisa@2.338.1 workstation --install --agents=none --tools="$w" --provider="${LISA_PROVIDER:-${LISA_SECRETS_PROVIDER:-bitwarden}}" || tt=$?; [ "$tw" -eq 0 ] && [ "$tt" -eq 0 ] || echo "SETUP INCOMPLETE: tool install failed (exit $tw/$tt). The session will start WITHOUT the pinned tools." >&2; [ "$ts" -eq 0 ] || echo "SETUP INCOMPLETE: secrets did not materialize (exit $ts). The session will start WITHOUT credentials." >&2; else echo "No checkout and no tenant configured; nothing to prepare."; fi; exit 0
17
- maintenance: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
15
+ **Ask for that line; do not copy it from here.**
16
+
17
+ ```bash
18
+ npx -y @codyswann/lisa@latest remote-env --emit=claude-web
18
19
  ```
19
20
 
21
+ The field pins the exact Lisa it runs, and the emitter reads that version from
22
+ the package it is running out of — so the line it prints is always pinned to the
23
+ version that printed it.
24
+
25
+ A copy written into this file cannot have that property. It is a snapshot taken
26
+ when the package was *built*, and the release bumps the version *after* the
27
+ build, so a published tarball's copy names the previous release. That is not a
28
+ cosmetic lag: the pinned version predates whatever this file documents, so a
29
+ pasted copy can call flags that version does not implement. Measured on
30
+ `2.338.1`, whose embedded copy named `2.338.0` — a Lisa with no `--print-tools`,
31
+ no `--tools`, and no `tools-from-notes.mjs`. Unknown flags are ignored rather
32
+ than rejected, so it did not fail; it installed the full catalogue and re-ran the
33
+ whole setup, three times over, inside a five-minute budget.
34
+
20
35
  **That line is identical for every project AND every surface.** Nothing in it names the
21
36
  repository or the package manager, so it can be pasted unchanged anywhere.
22
37
 
@@ -236,8 +251,10 @@ When emitting, produce exactly:
236
251
  ```text
237
252
  Environment name: <project> remote executor
238
253
  Repository: <org>/<repo> (must be the default checkout)
239
- Setup script: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
240
- Maintenance: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
254
+ Setup script: <printed by `remote-env --emit`; never copied
255
+ from prose, so its pin is always the version
256
+ that printed it>
257
+ Maintenance: <same line, printed by the same command>
241
258
  (identical for every project — the script finds the
242
259
  checkout and installs from the committed lockfile)
243
260
  Environment vars: LISA_SECRETS_SURFACE=codex-cloud
@@ -662,7 +662,14 @@ export const SETUP_FIELD =
662
662
  "/workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; " +
663
663
  'do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); ' +
664
664
  'case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; ' +
665
- 'n=$((n+1)); bash "$f" || rc=$?; done; ' +
665
+ // `rc` keeps the FIRST failure, which is what the contract below promises.
666
+ //
667
+ // A bare `rc=$?` keeps the last one, so with two broken checkouts the
668
+ // operator is shown the second and the first is lost — the precise hiding the
669
+ // documented behaviour exists to prevent. A success never overwrites, because
670
+ // `||` only fires on failure, so the bug was confined to the multiple-failure
671
+ // case that the rule was written for.
672
+ 'n=$((n+1)); bash "$f" || { s=$?; [ "$rc" -ne 0 ] || rc=$s; }; done; ' +
666
673
  '[ "$n" -gt 0 ] && exit "$rc"; ' +
667
674
  'g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; ' +
668
675
  'do [ -e "$c" ] && g=1; done; ' +
@@ -912,6 +919,21 @@ export function emitClaudeWeb({ bootstrapKey }) {
912
919
  " is why exactly one value needs to live here.",
913
920
  "",
914
921
  " Setup script:",
922
+ "",
923
+ " A setup script sees NONE of the variables configured above — it runs",
924
+ " while the image is being built, before the environment exists. So a",
925
+ " session with no checkout has to be told its tenant inside the script",
926
+ " itself, or the field finds nothing to prepare and exits 0 looking like",
927
+ " success. Put these three lines FIRST, then the line after them:",
928
+ "",
929
+ " export LISA_TENANT=<your namespace>",
930
+ ` export ${key}='<the same value as above>'`,
931
+ " export LISA_SECRETS_SURFACE=claude-web",
932
+ "",
933
+ " LISA_SECRETS_SURFACE is set explicitly rather than left to detection:",
934
+ " detection keys off CLAUDE_CODE_REMOTE, and a surface that does not set",
935
+ " it falls through to `local`, which writes no credentials to disk at all.",
936
+ "",
915
937
  ` ${SETUP_FIELD}`,
916
938
  "",
917
939
  " This line is identical for every project and every surface — nothing",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -12,11 +12,26 @@ Prepare a remote surface so a host project can execute there. Today that means *
12
12
 
13
13
  The remote environment's own configuration fields stay **one line into the repository**. Nothing else is pasted into a vendor UI.
14
14
 
15
- ```text
16
- setup: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] && exit "$rc"; g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; do [ -e "$c" ] && g=1; done; if [ "$g" -eq 1 ]; then echo "lisa-remote-env entrypoint not found, but a checkout is present. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; fi; ten="${LISA_TENANT:-${LISA_SECRETS_NAMESPACE:-}}"; if [ -n "$ten" ]; then echo "No checkout; preparing tools and credentials for $ten."; tw=0; tt=0; ts=0; tp=0; npx -y @codyswann/lisa@2.338.1 workstation --install --agents=none --tools=none --provider="${LISA_PROVIDER:-${LISA_SECRETS_PROVIDER:-bitwarden}}" || tw=$?; export PATH="$HOME/.local/bin:$HOME/.opencode/bin:$HOME/.local/share/sonarqube-cli/bin:$PATH"; npx -y @codyswann/lisa@2.338.1 remote-env --phase=secrets || ts=$?; w=$(npx -y @codyswann/lisa@2.338.1 remote-env --print-tools 2>/dev/null) || tp=$?; w=$(printf "%s\n" "$w" | tail -1); [ "$tp" -eq 0 ] || echo "SETUP INCOMPLETE: could not read the tool list from the vault (exit $tp). Installing the full catalogue." >&2; npx -y @codyswann/lisa@2.338.1 workstation --install --agents=none --tools="$w" --provider="${LISA_PROVIDER:-${LISA_SECRETS_PROVIDER:-bitwarden}}" || tt=$?; [ "$tw" -eq 0 ] && [ "$tt" -eq 0 ] || echo "SETUP INCOMPLETE: tool install failed (exit $tw/$tt). The session will start WITHOUT the pinned tools." >&2; [ "$ts" -eq 0 ] || echo "SETUP INCOMPLETE: secrets did not materialize (exit $ts). The session will start WITHOUT credentials." >&2; else echo "No checkout and no tenant configured; nothing to prepare."; fi; exit 0
17
- maintenance: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
15
+ **Ask for that line; do not copy it from here.**
16
+
17
+ ```bash
18
+ npx -y @codyswann/lisa@latest remote-env --emit=claude-web
18
19
  ```
19
20
 
21
+ The field pins the exact Lisa it runs, and the emitter reads that version from
22
+ the package it is running out of — so the line it prints is always pinned to the
23
+ version that printed it.
24
+
25
+ A copy written into this file cannot have that property. It is a snapshot taken
26
+ when the package was *built*, and the release bumps the version *after* the
27
+ build, so a published tarball's copy names the previous release. That is not a
28
+ cosmetic lag: the pinned version predates whatever this file documents, so a
29
+ pasted copy can call flags that version does not implement. Measured on
30
+ `2.338.1`, whose embedded copy named `2.338.0` — a Lisa with no `--print-tools`,
31
+ no `--tools`, and no `tools-from-notes.mjs`. Unknown flags are ignored rather
32
+ than rejected, so it did not fail; it installed the full catalogue and re-ran the
33
+ whole setup, three times over, inside a five-minute budget.
34
+
20
35
  **That line is identical for every project AND every surface.** Nothing in it names the
21
36
  repository or the package manager, so it can be pasted unchanged anywhere.
22
37
 
@@ -236,8 +251,10 @@ When emitting, produce exactly:
236
251
  ```text
237
252
  Environment name: <project> remote executor
238
253
  Repository: <org>/<repo> (must be the default checkout)
239
- Setup script: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
240
- Maintenance: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
254
+ Setup script: <printed by `remote-env --emit`; never copied
255
+ from prose, so its pin is always the version
256
+ that printed it>
257
+ Maintenance: <same line, printed by the same command>
241
258
  (identical for every project — the script finds the
242
259
  checkout and installs from the committed lockfile)
243
260
  Environment vars: LISA_SECRETS_SURFACE=codex-cloud
@@ -662,7 +662,14 @@ export const SETUP_FIELD =
662
662
  "/workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; " +
663
663
  'do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); ' +
664
664
  'case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; ' +
665
- 'n=$((n+1)); bash "$f" || rc=$?; done; ' +
665
+ // `rc` keeps the FIRST failure, which is what the contract below promises.
666
+ //
667
+ // A bare `rc=$?` keeps the last one, so with two broken checkouts the
668
+ // operator is shown the second and the first is lost — the precise hiding the
669
+ // documented behaviour exists to prevent. A success never overwrites, because
670
+ // `||` only fires on failure, so the bug was confined to the multiple-failure
671
+ // case that the rule was written for.
672
+ 'n=$((n+1)); bash "$f" || { s=$?; [ "$rc" -ne 0 ] || rc=$s; }; done; ' +
666
673
  '[ "$n" -gt 0 ] && exit "$rc"; ' +
667
674
  'g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; ' +
668
675
  'do [ -e "$c" ] && g=1; done; ' +
@@ -912,6 +919,21 @@ export function emitClaudeWeb({ bootstrapKey }) {
912
919
  " is why exactly one value needs to live here.",
913
920
  "",
914
921
  " Setup script:",
922
+ "",
923
+ " A setup script sees NONE of the variables configured above — it runs",
924
+ " while the image is being built, before the environment exists. So a",
925
+ " session with no checkout has to be told its tenant inside the script",
926
+ " itself, or the field finds nothing to prepare and exits 0 looking like",
927
+ " success. Put these three lines FIRST, then the line after them:",
928
+ "",
929
+ " export LISA_TENANT=<your namespace>",
930
+ ` export ${key}='<the same value as above>'`,
931
+ " export LISA_SECRETS_SURFACE=claude-web",
932
+ "",
933
+ " LISA_SECRETS_SURFACE is set explicitly rather than left to detection:",
934
+ " detection keys off CLAUDE_CODE_REMOTE, and a surface that does not set",
935
+ " it falls through to `local`, which writes no credentials to disk at all.",
936
+ "",
915
937
  ` ${SETUP_FIELD}`,
916
938
  "",
917
939
  " This line is identical for every project and every surface — nothing",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -12,11 +12,26 @@ Prepare a remote surface so a host project can execute there. Today that means *
12
12
 
13
13
  The remote environment's own configuration fields stay **one line into the repository**. Nothing else is pasted into a vendor UI.
14
14
 
15
- ```text
16
- setup: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] && exit "$rc"; g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; do [ -e "$c" ] && g=1; done; if [ "$g" -eq 1 ]; then echo "lisa-remote-env entrypoint not found, but a checkout is present. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; fi; ten="${LISA_TENANT:-${LISA_SECRETS_NAMESPACE:-}}"; if [ -n "$ten" ]; then echo "No checkout; preparing tools and credentials for $ten."; tw=0; tt=0; ts=0; tp=0; npx -y @codyswann/lisa@2.338.1 workstation --install --agents=none --tools=none --provider="${LISA_PROVIDER:-${LISA_SECRETS_PROVIDER:-bitwarden}}" || tw=$?; export PATH="$HOME/.local/bin:$HOME/.opencode/bin:$HOME/.local/share/sonarqube-cli/bin:$PATH"; npx -y @codyswann/lisa@2.338.1 remote-env --phase=secrets || ts=$?; w=$(npx -y @codyswann/lisa@2.338.1 remote-env --print-tools 2>/dev/null) || tp=$?; w=$(printf "%s\n" "$w" | tail -1); [ "$tp" -eq 0 ] || echo "SETUP INCOMPLETE: could not read the tool list from the vault (exit $tp). Installing the full catalogue." >&2; npx -y @codyswann/lisa@2.338.1 workstation --install --agents=none --tools="$w" --provider="${LISA_PROVIDER:-${LISA_SECRETS_PROVIDER:-bitwarden}}" || tt=$?; [ "$tw" -eq 0 ] && [ "$tt" -eq 0 ] || echo "SETUP INCOMPLETE: tool install failed (exit $tw/$tt). The session will start WITHOUT the pinned tools." >&2; [ "$ts" -eq 0 ] || echo "SETUP INCOMPLETE: secrets did not materialize (exit $ts). The session will start WITHOUT credentials." >&2; else echo "No checkout and no tenant configured; nothing to prepare."; fi; exit 0
17
- maintenance: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
15
+ **Ask for that line; do not copy it from here.**
16
+
17
+ ```bash
18
+ npx -y @codyswann/lisa@latest remote-env --emit=claude-web
18
19
  ```
19
20
 
21
+ The field pins the exact Lisa it runs, and the emitter reads that version from
22
+ the package it is running out of — so the line it prints is always pinned to the
23
+ version that printed it.
24
+
25
+ A copy written into this file cannot have that property. It is a snapshot taken
26
+ when the package was *built*, and the release bumps the version *after* the
27
+ build, so a published tarball's copy names the previous release. That is not a
28
+ cosmetic lag: the pinned version predates whatever this file documents, so a
29
+ pasted copy can call flags that version does not implement. Measured on
30
+ `2.338.1`, whose embedded copy named `2.338.0` — a Lisa with no `--print-tools`,
31
+ no `--tools`, and no `tools-from-notes.mjs`. Unknown flags are ignored rather
32
+ than rejected, so it did not fail; it installed the full catalogue and re-ran the
33
+ whole setup, three times over, inside a five-minute budget.
34
+
20
35
  **That line is identical for every project AND every surface.** Nothing in it names the
21
36
  repository or the package manager, so it can be pasted unchanged anywhere.
22
37
 
@@ -236,8 +251,10 @@ When emitting, produce exactly:
236
251
  ```text
237
252
  Environment name: <project> remote executor
238
253
  Repository: <org>/<repo> (must be the default checkout)
239
- Setup script: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
240
- Maintenance: n=0; rc=0; seen=""; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh "$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh /workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; exit "$rc"
254
+ Setup script: <printed by `remote-env --emit`; never copied
255
+ from prose, so its pin is always the version
256
+ that printed it>
257
+ Maintenance: <same line, printed by the same command>
241
258
  (identical for every project — the script finds the
242
259
  checkout and installs from the committed lockfile)
243
260
  Environment vars: LISA_SECRETS_SURFACE=codex-cloud
@@ -662,7 +662,14 @@ export const SETUP_FIELD =
662
662
  "/workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; " +
663
663
  'do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); ' +
664
664
  'case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; ' +
665
- 'n=$((n+1)); bash "$f" || rc=$?; done; ' +
665
+ // `rc` keeps the FIRST failure, which is what the contract below promises.
666
+ //
667
+ // A bare `rc=$?` keeps the last one, so with two broken checkouts the
668
+ // operator is shown the second and the first is lost — the precise hiding the
669
+ // documented behaviour exists to prevent. A success never overwrites, because
670
+ // `||` only fires on failure, so the bug was confined to the multiple-failure
671
+ // case that the rule was written for.
672
+ 'n=$((n+1)); bash "$f" || { s=$?; [ "$rc" -ne 0 ] || rc=$s; }; done; ' +
666
673
  '[ "$n" -gt 0 ] && exit "$rc"; ' +
667
674
  'g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; ' +
668
675
  'do [ -e "$c" ] && g=1; done; ' +
@@ -912,6 +919,21 @@ export function emitClaudeWeb({ bootstrapKey }) {
912
919
  " is why exactly one value needs to live here.",
913
920
  "",
914
921
  " Setup script:",
922
+ "",
923
+ " A setup script sees NONE of the variables configured above — it runs",
924
+ " while the image is being built, before the environment exists. So a",
925
+ " session with no checkout has to be told its tenant inside the script",
926
+ " itself, or the field finds nothing to prepare and exits 0 looking like",
927
+ " success. Put these three lines FIRST, then the line after them:",
928
+ "",
929
+ " export LISA_TENANT=<your namespace>",
930
+ ` export ${key}='<the same value as above>'`,
931
+ " export LISA_SECRETS_SURFACE=claude-web",
932
+ "",
933
+ " LISA_SECRETS_SURFACE is set explicitly rather than left to detection:",
934
+ " detection keys off CLAUDE_CODE_REMOTE, and a surface that does not set",
935
+ " it falls through to `local`, which writes no credentials to disk at all.",
936
+ "",
915
937
  ` ${SETUP_FIELD}`,
916
938
  "",
917
939
  " This line is identical for every project and every surface — nothing",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.338.2",
3
+ "version": "2.338.4",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"