@codyswann/lisa 2.335.0 → 2.336.0

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 (70) hide show
  1. package/dist/core/upstream-evidence-manifest.js +3 -3
  2. package/package.json +1 -1
  3. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  4. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  5. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/surfaces.mjs +42 -2
  6. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/SKILL.md +1 -1
  7. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +33 -6
  8. package/plugins/lisa/skills/lisa-secrets-access/scripts/surfaces.mjs +42 -2
  9. package/plugins/lisa/skills/lisa-setup-remote-env/SKILL.md +1 -1
  10. package/plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +33 -6
  11. package/plugins/lisa-agy/plugin.json +1 -1
  12. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/surfaces.mjs +42 -2
  13. package/plugins/lisa-agy/skills/lisa-setup-remote-env/SKILL.md +1 -1
  14. package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +33 -6
  15. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  16. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  18. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/surfaces.mjs +42 -2
  22. package/plugins/lisa-copilot/skills/lisa-setup-remote-env/SKILL.md +1 -1
  23. package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +33 -6
  24. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/surfaces.mjs +42 -2
  26. package/plugins/lisa-cursor/skills/lisa-setup-remote-env/SKILL.md +1 -1
  27. package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +33 -6
  28. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  30. package/plugins/lisa-expo-agy/plugin.json +1 -1
  31. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  35. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  36. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  40. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  41. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  45. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  46. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  50. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  51. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  55. package/plugins/lisa-rails-agy/plugin.json +1 -1
  56. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  60. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  61. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  65. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  66. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  68. package/plugins/src/base/skills/lisa-secrets-access/scripts/surfaces.mjs +42 -2
  69. package/plugins/src/base/skills/lisa-setup-remote-env/SKILL.md +1 -1
  70. package/plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +33 -6
@@ -560,7 +560,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
560
560
  "plugins/src/base/skills/lisa-secrets-access/scripts/read-secret-note.mjs": "1471d2108058f3059e242f9c71208c99fdbc212bde32de34b798eaa9a27ffbcc",
561
561
  "plugins/src/base/skills/lisa-secrets-access/scripts/resolve-secret.mjs": "04ab89bc1f890526ba3b693cd3b022abc5a24e078b93c08fe7dfd586452b70b1",
562
562
  "plugins/src/base/skills/lisa-secrets-access/scripts/rotate-secret.mjs": "546dc1c2f279cee6db56c0f55c01aabae0c316842f32d3219c5af6d638936a9c",
563
- "plugins/src/base/skills/lisa-secrets-access/scripts/surfaces.mjs": "f8d4404ab105284ee072a26319366a71333c89abb14f9d71aafe461e7ea0686a",
563
+ "plugins/src/base/skills/lisa-secrets-access/scripts/surfaces.mjs": "21d3408de74f2691d61649862b086dfc37a5ce2553bcb17366fcd5d1c50a4ae8",
564
564
  "plugins/src/base/skills/lisa-secrets-access/scripts/validate-config.mjs": "62d1b87d1b852dc00c00ea9d132d9d6953f4ef77beb5fa4b93652c4424f33274",
565
565
  "plugins/src/base/skills/lisa-security-review/SKILL.md": "5a980eaf5efc4fcce66e75521ec5b1eda143a5b0d36e7157234a705dac94e3f5",
566
566
  "plugins/src/base/skills/lisa-security-zap-scan/SKILL.md": "a5189442dbf970cc49fd089ab03c386c8a205b856e09501f6ad1966321e7e4b5",
@@ -578,10 +578,10 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
578
578
  "plugins/src/base/skills/lisa-setup-local-env/scripts/local-env.mjs": "bff68aa66d6d4cd7cb9d0e39be691c6daa232edb097f8a601815432a32cca6a6",
579
579
  "plugins/src/base/skills/lisa-setup-notion/SKILL.md": "f5a1e9290789fd1c33675168d30461fb24a11c98a433ef777c1f536bc2f905ef",
580
580
  "plugins/src/base/skills/lisa-setup-remote-aws/SKILL.md": "80fbf157f9c562c033886c25a99b37356602edd9e61cd2d492f339769ddcf97e",
581
- "plugins/src/base/skills/lisa-setup-remote-env/SKILL.md": "b570ebc3faa5099dc8e43f33f5ba51bdc1e2312b3c49d28d04a3ae67f138041f",
581
+ "plugins/src/base/skills/lisa-setup-remote-env/SKILL.md": "b5993444364b361c7b365092ab424bc1d0eee61705a5a2471e4e1f443e30d78f",
582
582
  "plugins/src/base/skills/lisa-setup-remote-env/assets/session-start.sh": "cb63d08b14ab7aa2d405e6770e0cf7db5d6588ae1dcb924ea6224b026fcff496",
583
583
  "plugins/src/base/skills/lisa-setup-remote-env/assets/setup.sh": "c30d98a5645f033fc1d3a723043691b9ad997ae5666df539ff6aa19c563431b2",
584
- "plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs": "aa703a3fcadd847594c694f458fc41edd39590dfabeddf4fed1546b73099f33f",
584
+ "plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs": "830a2c75fabb0069ebe1bf3f5ec1c1f4dd3437fea6c059b41b8ab4092277025f",
585
585
  "plugins/src/base/skills/lisa-setup-remote-env/scripts/toolchain.mjs": "496de5aed034692fee421dc3a1fbad9f85ed9e1d0c83a1080f781a486d0274e6",
586
586
  "plugins/src/base/skills/lisa-setup-remote-env/scripts/verify-remote-env.mjs": "82bc2a27a0a5afb2ff413a88365c619fd7f0eaada5de3ccabf2000938f0607a4",
587
587
  "plugins/src/base/skills/lisa-setup-sonar/SKILL.md": "b18e07ae942f75aad5730c0535840ef5f7115072f1b6cc62afac83196b28d6a3",
package/package.json CHANGED
@@ -115,7 +115,7 @@
115
115
  "brace-expansion": ">=5.0.9"
116
116
  },
117
117
  "name": "@codyswann/lisa",
118
- "version": "2.335.0",
118
+ "version": "2.336.0",
119
119
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
120
120
  "main": "dist/index.js",
121
121
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.335.0",
3
+ "version": "2.336.0",
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.335.0",
3
+ "version": "2.336.0",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -165,9 +165,19 @@ export function materializedPaths(namespace, env = process.env) {
165
165
  * @param {string} [cwd] Directory to look in.
166
166
  * @returns {object} Resolved configuration with defaults applied.
167
167
  */
168
- export function readConfig(cwd = process.cwd()) {
168
+ export function readConfig(cwd = process.cwd(), env = process.env) {
169
169
  const path = join(cwd, ".lisa.config.json");
170
- if (!existsSync(path)) return withSurface(DEFAULTS);
170
+ // No repository is a real, supported state — not just a missing file.
171
+ //
172
+ // A Claude Tag channel session runs as the organization with no user account,
173
+ // and a repository "doesn't enter a session until a request names it". So a
174
+ // session can legitimately have no checkout and therefore no config, while
175
+ // still needing the credentials and profiles every other surface gets.
176
+ //
177
+ // The only values a config would supply here are the namespace and provider,
178
+ // so they can come from the environment instead. Everything else keeps its
179
+ // default, and an environment that sets neither still gets the old behaviour.
180
+ if (!existsSync(path)) return withSurface(fromEnvironment(env));
171
181
  let cfg;
172
182
  try {
173
183
  cfg = JSON.parse(readFileSync(path, "utf8")).secrets;
@@ -186,6 +196,36 @@ export function readConfig(cwd = process.cwd()) {
186
196
  });
187
197
  }
188
198
 
199
+ /**
200
+ * Build a configuration from the environment, for sessions with no checkout.
201
+ *
202
+ * `LISA_SECRETS_NAMESPACE` is the one value with no safe default: it names the
203
+ * directory secrets are written to and the tenant they belong to, so guessing
204
+ * it would write one tenant's credentials under another's name. Absent, this
205
+ * returns the ordinary defaults and the caller behaves exactly as before.
206
+ *
207
+ * The bootstrap key follows the namespace by convention
208
+ * (`BWS_ACCESS_TOKEN_<namespace>`) so a channel environment needs one variable
209
+ * set, not two.
210
+ * @param {object} env The environment to read.
211
+ * @returns {object} A configuration, defaulted where the environment is silent.
212
+ */
213
+ function fromEnvironment(env) {
214
+ const namespace = (env.LISA_SECRETS_NAMESPACE ?? "").trim();
215
+ if (!namespace) return DEFAULTS;
216
+
217
+ const provider = (env.LISA_SECRETS_PROVIDER ?? "").trim() || "bitwarden";
218
+ return {
219
+ ...DEFAULTS,
220
+ provider,
221
+ namespace: assertNamespace(namespace),
222
+ bootstrap: {
223
+ ...DEFAULTS.bootstrap,
224
+ key: env.LISA_SECRETS_BOOTSTRAP_KEY ?? `BWS_ACCESS_TOKEN_${namespace}`,
225
+ },
226
+ };
227
+ }
228
+
189
229
  /**
190
230
  * Attach the resolved surface and its capabilities to a configuration.
191
231
  * @param {object} cfg Configuration without surface resolution.
@@ -13,7 +13,7 @@ Prepare a remote surface so a host project can execute there. Today that means *
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
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 ] || { 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"
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; if [ -n "${LISA_SECRETS_NAMESPACE:-}" ]; then echo "No checkout; preparing tools and credentials for $LISA_SECRETS_NAMESPACE."; npx -y @codyswann/lisa@latest workstation --provider "${LISA_SECRETS_PROVIDER:-bitwarden}" --yes || true; npx -y @codyswann/lisa@latest remote-env --phase=secrets || true; else echo "No checkout and no LISA_SECRETS_NAMESPACE; nothing to prepare."; fi; exit 0
17
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"
18
18
  ```
19
19
 
@@ -559,9 +559,26 @@ export function installAssets(cwd = process.cwd()) {
559
559
  * whenever cwd happens to be one of the roots.
560
560
  *
561
561
  * The status is the first failure and every checkout is still attempted: one
562
- * broken repository must neither hide the others nor report success. The
563
- * explicit `exit 1` on no matches matters because a `for` loop over a glob that
564
- * matches nothing otherwise exits 0 the quiet success this guards against.
562
+ * broken repository must neither hide the others nor report success.
563
+ *
564
+ * Preparing nothing has two causes, and they are not the same failure:
565
+ *
566
+ * - A checkout is present but carries no entrypoint. That is a
567
+ * misconfiguration, and a `for` loop over a glob that matches nothing exits
568
+ * 0 on its own — the quiet success this has always guarded against. It
569
+ * still fails loudly, printing the layout it found rather than only the
570
+ * path it wanted.
571
+ * - There is NO checkout. A Claude Tag channel session runs as the
572
+ * organization with no user account, and a repository does not enter the
573
+ * session until a request names one, so this is an ordinary state rather
574
+ * than an error. Failing here would be severe: a setup script that exits
575
+ * non-zero stops the session from starting at all, so the old blanket
576
+ * `exit 1` would have killed every repo-less channel session.
577
+ *
578
+ * With no checkout, `LISA_SECRETS_NAMESPACE` decides whether there is anything
579
+ * to do: it names the tenant, which is the one value no default can supply.
580
+ * Given it, the machine itself is prepared — tools and credentials, no repo
581
+ * required. Without it there is nothing to prepare and nothing to fail about.
565
582
  *
566
583
  * Failure prints the layout it found rather than only the path it wanted. This
567
584
  * field lives in a vendor settings box with a slow edit-and-retry loop, and a
@@ -580,9 +597,19 @@ export const SETUP_FIELD =
580
597
  'do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); ' +
581
598
  'case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; ' +
582
599
  'n=$((n+1)); bash "$f" || rc=$?; done; ' +
583
- '[ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. ' +
584
- 'PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; ' +
585
- 'exit "$rc"';
600
+ '[ "$n" -gt 0 ] && exit "$rc"; ' +
601
+ 'g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; ' +
602
+ 'do [ -e "$c" ] && g=1; done; ' +
603
+ 'if [ "$g" -eq 1 ]; then ' +
604
+ 'echo "lisa-remote-env entrypoint not found, but a checkout is present. ' +
605
+ 'PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; fi; ' +
606
+ 'if [ -n "${LISA_SECRETS_NAMESPACE:-}" ]; then ' +
607
+ 'echo "No checkout; preparing tools and credentials for $LISA_SECRETS_NAMESPACE."; ' +
608
+ "npx -y @codyswann/lisa@latest workstation " +
609
+ '--provider "${LISA_SECRETS_PROVIDER:-bitwarden}" --yes || true; ' +
610
+ "npx -y @codyswann/lisa@latest remote-env --phase=secrets || true; " +
611
+ 'else echo "No checkout and no LISA_SECRETS_NAMESPACE; nothing to prepare."; fi; ' +
612
+ "exit 0";
586
613
 
587
614
  /**
588
615
  * Register the session-start hook at USER scope, so it fires wherever the
@@ -165,9 +165,19 @@ export function materializedPaths(namespace, env = process.env) {
165
165
  * @param {string} [cwd] Directory to look in.
166
166
  * @returns {object} Resolved configuration with defaults applied.
167
167
  */
168
- export function readConfig(cwd = process.cwd()) {
168
+ export function readConfig(cwd = process.cwd(), env = process.env) {
169
169
  const path = join(cwd, ".lisa.config.json");
170
- if (!existsSync(path)) return withSurface(DEFAULTS);
170
+ // No repository is a real, supported state — not just a missing file.
171
+ //
172
+ // A Claude Tag channel session runs as the organization with no user account,
173
+ // and a repository "doesn't enter a session until a request names it". So a
174
+ // session can legitimately have no checkout and therefore no config, while
175
+ // still needing the credentials and profiles every other surface gets.
176
+ //
177
+ // The only values a config would supply here are the namespace and provider,
178
+ // so they can come from the environment instead. Everything else keeps its
179
+ // default, and an environment that sets neither still gets the old behaviour.
180
+ if (!existsSync(path)) return withSurface(fromEnvironment(env));
171
181
  let cfg;
172
182
  try {
173
183
  cfg = JSON.parse(readFileSync(path, "utf8")).secrets;
@@ -186,6 +196,36 @@ export function readConfig(cwd = process.cwd()) {
186
196
  });
187
197
  }
188
198
 
199
+ /**
200
+ * Build a configuration from the environment, for sessions with no checkout.
201
+ *
202
+ * `LISA_SECRETS_NAMESPACE` is the one value with no safe default: it names the
203
+ * directory secrets are written to and the tenant they belong to, so guessing
204
+ * it would write one tenant's credentials under another's name. Absent, this
205
+ * returns the ordinary defaults and the caller behaves exactly as before.
206
+ *
207
+ * The bootstrap key follows the namespace by convention
208
+ * (`BWS_ACCESS_TOKEN_<namespace>`) so a channel environment needs one variable
209
+ * set, not two.
210
+ * @param {object} env The environment to read.
211
+ * @returns {object} A configuration, defaulted where the environment is silent.
212
+ */
213
+ function fromEnvironment(env) {
214
+ const namespace = (env.LISA_SECRETS_NAMESPACE ?? "").trim();
215
+ if (!namespace) return DEFAULTS;
216
+
217
+ const provider = (env.LISA_SECRETS_PROVIDER ?? "").trim() || "bitwarden";
218
+ return {
219
+ ...DEFAULTS,
220
+ provider,
221
+ namespace: assertNamespace(namespace),
222
+ bootstrap: {
223
+ ...DEFAULTS.bootstrap,
224
+ key: env.LISA_SECRETS_BOOTSTRAP_KEY ?? `BWS_ACCESS_TOKEN_${namespace}`,
225
+ },
226
+ };
227
+ }
228
+
189
229
  /**
190
230
  * Attach the resolved surface and its capabilities to a configuration.
191
231
  * @param {object} cfg Configuration without surface resolution.
@@ -13,7 +13,7 @@ Prepare a remote surface so a host project can execute there. Today that means *
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
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 ] || { 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"
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; if [ -n "${LISA_SECRETS_NAMESPACE:-}" ]; then echo "No checkout; preparing tools and credentials for $LISA_SECRETS_NAMESPACE."; npx -y @codyswann/lisa@latest workstation --provider "${LISA_SECRETS_PROVIDER:-bitwarden}" --yes || true; npx -y @codyswann/lisa@latest remote-env --phase=secrets || true; else echo "No checkout and no LISA_SECRETS_NAMESPACE; nothing to prepare."; fi; exit 0
17
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"
18
18
  ```
19
19
 
@@ -559,9 +559,26 @@ export function installAssets(cwd = process.cwd()) {
559
559
  * whenever cwd happens to be one of the roots.
560
560
  *
561
561
  * The status is the first failure and every checkout is still attempted: one
562
- * broken repository must neither hide the others nor report success. The
563
- * explicit `exit 1` on no matches matters because a `for` loop over a glob that
564
- * matches nothing otherwise exits 0 the quiet success this guards against.
562
+ * broken repository must neither hide the others nor report success.
563
+ *
564
+ * Preparing nothing has two causes, and they are not the same failure:
565
+ *
566
+ * - A checkout is present but carries no entrypoint. That is a
567
+ * misconfiguration, and a `for` loop over a glob that matches nothing exits
568
+ * 0 on its own — the quiet success this has always guarded against. It
569
+ * still fails loudly, printing the layout it found rather than only the
570
+ * path it wanted.
571
+ * - There is NO checkout. A Claude Tag channel session runs as the
572
+ * organization with no user account, and a repository does not enter the
573
+ * session until a request names one, so this is an ordinary state rather
574
+ * than an error. Failing here would be severe: a setup script that exits
575
+ * non-zero stops the session from starting at all, so the old blanket
576
+ * `exit 1` would have killed every repo-less channel session.
577
+ *
578
+ * With no checkout, `LISA_SECRETS_NAMESPACE` decides whether there is anything
579
+ * to do: it names the tenant, which is the one value no default can supply.
580
+ * Given it, the machine itself is prepared — tools and credentials, no repo
581
+ * required. Without it there is nothing to prepare and nothing to fail about.
565
582
  *
566
583
  * Failure prints the layout it found rather than only the path it wanted. This
567
584
  * field lives in a vendor settings box with a slow edit-and-retry loop, and a
@@ -580,9 +597,19 @@ export const SETUP_FIELD =
580
597
  'do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); ' +
581
598
  'case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; ' +
582
599
  'n=$((n+1)); bash "$f" || rc=$?; done; ' +
583
- '[ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. ' +
584
- 'PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; ' +
585
- 'exit "$rc"';
600
+ '[ "$n" -gt 0 ] && exit "$rc"; ' +
601
+ 'g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; ' +
602
+ 'do [ -e "$c" ] && g=1; done; ' +
603
+ 'if [ "$g" -eq 1 ]; then ' +
604
+ 'echo "lisa-remote-env entrypoint not found, but a checkout is present. ' +
605
+ 'PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; fi; ' +
606
+ 'if [ -n "${LISA_SECRETS_NAMESPACE:-}" ]; then ' +
607
+ 'echo "No checkout; preparing tools and credentials for $LISA_SECRETS_NAMESPACE."; ' +
608
+ "npx -y @codyswann/lisa@latest workstation " +
609
+ '--provider "${LISA_SECRETS_PROVIDER:-bitwarden}" --yes || true; ' +
610
+ "npx -y @codyswann/lisa@latest remote-env --phase=secrets || true; " +
611
+ 'else echo "No checkout and no LISA_SECRETS_NAMESPACE; nothing to prepare."; fi; ' +
612
+ "exit 0";
586
613
 
587
614
  /**
588
615
  * Register the session-start hook at USER scope, so it fires wherever the
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.335.0",
3
+ "version": "2.336.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -165,9 +165,19 @@ export function materializedPaths(namespace, env = process.env) {
165
165
  * @param {string} [cwd] Directory to look in.
166
166
  * @returns {object} Resolved configuration with defaults applied.
167
167
  */
168
- export function readConfig(cwd = process.cwd()) {
168
+ export function readConfig(cwd = process.cwd(), env = process.env) {
169
169
  const path = join(cwd, ".lisa.config.json");
170
- if (!existsSync(path)) return withSurface(DEFAULTS);
170
+ // No repository is a real, supported state — not just a missing file.
171
+ //
172
+ // A Claude Tag channel session runs as the organization with no user account,
173
+ // and a repository "doesn't enter a session until a request names it". So a
174
+ // session can legitimately have no checkout and therefore no config, while
175
+ // still needing the credentials and profiles every other surface gets.
176
+ //
177
+ // The only values a config would supply here are the namespace and provider,
178
+ // so they can come from the environment instead. Everything else keeps its
179
+ // default, and an environment that sets neither still gets the old behaviour.
180
+ if (!existsSync(path)) return withSurface(fromEnvironment(env));
171
181
  let cfg;
172
182
  try {
173
183
  cfg = JSON.parse(readFileSync(path, "utf8")).secrets;
@@ -186,6 +196,36 @@ export function readConfig(cwd = process.cwd()) {
186
196
  });
187
197
  }
188
198
 
199
+ /**
200
+ * Build a configuration from the environment, for sessions with no checkout.
201
+ *
202
+ * `LISA_SECRETS_NAMESPACE` is the one value with no safe default: it names the
203
+ * directory secrets are written to and the tenant they belong to, so guessing
204
+ * it would write one tenant's credentials under another's name. Absent, this
205
+ * returns the ordinary defaults and the caller behaves exactly as before.
206
+ *
207
+ * The bootstrap key follows the namespace by convention
208
+ * (`BWS_ACCESS_TOKEN_<namespace>`) so a channel environment needs one variable
209
+ * set, not two.
210
+ * @param {object} env The environment to read.
211
+ * @returns {object} A configuration, defaulted where the environment is silent.
212
+ */
213
+ function fromEnvironment(env) {
214
+ const namespace = (env.LISA_SECRETS_NAMESPACE ?? "").trim();
215
+ if (!namespace) return DEFAULTS;
216
+
217
+ const provider = (env.LISA_SECRETS_PROVIDER ?? "").trim() || "bitwarden";
218
+ return {
219
+ ...DEFAULTS,
220
+ provider,
221
+ namespace: assertNamespace(namespace),
222
+ bootstrap: {
223
+ ...DEFAULTS.bootstrap,
224
+ key: env.LISA_SECRETS_BOOTSTRAP_KEY ?? `BWS_ACCESS_TOKEN_${namespace}`,
225
+ },
226
+ };
227
+ }
228
+
189
229
  /**
190
230
  * Attach the resolved surface and its capabilities to a configuration.
191
231
  * @param {object} cfg Configuration without surface resolution.
@@ -13,7 +13,7 @@ Prepare a remote surface so a host project can execute there. Today that means *
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
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 ] || { 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"
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; if [ -n "${LISA_SECRETS_NAMESPACE:-}" ]; then echo "No checkout; preparing tools and credentials for $LISA_SECRETS_NAMESPACE."; npx -y @codyswann/lisa@latest workstation --provider "${LISA_SECRETS_PROVIDER:-bitwarden}" --yes || true; npx -y @codyswann/lisa@latest remote-env --phase=secrets || true; else echo "No checkout and no LISA_SECRETS_NAMESPACE; nothing to prepare."; fi; exit 0
17
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"
18
18
  ```
19
19
 
@@ -559,9 +559,26 @@ export function installAssets(cwd = process.cwd()) {
559
559
  * whenever cwd happens to be one of the roots.
560
560
  *
561
561
  * The status is the first failure and every checkout is still attempted: one
562
- * broken repository must neither hide the others nor report success. The
563
- * explicit `exit 1` on no matches matters because a `for` loop over a glob that
564
- * matches nothing otherwise exits 0 the quiet success this guards against.
562
+ * broken repository must neither hide the others nor report success.
563
+ *
564
+ * Preparing nothing has two causes, and they are not the same failure:
565
+ *
566
+ * - A checkout is present but carries no entrypoint. That is a
567
+ * misconfiguration, and a `for` loop over a glob that matches nothing exits
568
+ * 0 on its own — the quiet success this has always guarded against. It
569
+ * still fails loudly, printing the layout it found rather than only the
570
+ * path it wanted.
571
+ * - There is NO checkout. A Claude Tag channel session runs as the
572
+ * organization with no user account, and a repository does not enter the
573
+ * session until a request names one, so this is an ordinary state rather
574
+ * than an error. Failing here would be severe: a setup script that exits
575
+ * non-zero stops the session from starting at all, so the old blanket
576
+ * `exit 1` would have killed every repo-less channel session.
577
+ *
578
+ * With no checkout, `LISA_SECRETS_NAMESPACE` decides whether there is anything
579
+ * to do: it names the tenant, which is the one value no default can supply.
580
+ * Given it, the machine itself is prepared — tools and credentials, no repo
581
+ * required. Without it there is nothing to prepare and nothing to fail about.
565
582
  *
566
583
  * Failure prints the layout it found rather than only the path it wanted. This
567
584
  * field lives in a vendor settings box with a slow edit-and-retry loop, and a
@@ -580,9 +597,19 @@ export const SETUP_FIELD =
580
597
  'do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); ' +
581
598
  'case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; ' +
582
599
  'n=$((n+1)); bash "$f" || rc=$?; done; ' +
583
- '[ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. ' +
584
- 'PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; ' +
585
- 'exit "$rc"';
600
+ '[ "$n" -gt 0 ] && exit "$rc"; ' +
601
+ 'g=0; for c in ./.git ./*/.git "$HOME"/*/.git /workspace/*/.git; ' +
602
+ 'do [ -e "$c" ] && g=1; done; ' +
603
+ 'if [ "$g" -eq 1 ]; then ' +
604
+ 'echo "lisa-remote-env entrypoint not found, but a checkout is present. ' +
605
+ 'PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; fi; ' +
606
+ 'if [ -n "${LISA_SECRETS_NAMESPACE:-}" ]; then ' +
607
+ 'echo "No checkout; preparing tools and credentials for $LISA_SECRETS_NAMESPACE."; ' +
608
+ "npx -y @codyswann/lisa@latest workstation " +
609
+ '--provider "${LISA_SECRETS_PROVIDER:-bitwarden}" --yes || true; ' +
610
+ "npx -y @codyswann/lisa@latest remote-env --phase=secrets || true; " +
611
+ 'else echo "No checkout and no LISA_SECRETS_NAMESPACE; nothing to prepare."; fi; ' +
612
+ "exit 0";
586
613
 
587
614
  /**
588
615
  * Register the session-start hook at USER scope, so it fires wherever the
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.335.0",
3
+ "version": "2.336.0",
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.335.0",
3
+ "version": "2.336.0",
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.335.0",
3
+ "version": "2.336.0",
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.335.0",
3
+ "version": "2.336.0",
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.335.0",
3
+ "version": "2.336.0",
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.335.0",
3
+ "version": "2.336.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -165,9 +165,19 @@ export function materializedPaths(namespace, env = process.env) {
165
165
  * @param {string} [cwd] Directory to look in.
166
166
  * @returns {object} Resolved configuration with defaults applied.
167
167
  */
168
- export function readConfig(cwd = process.cwd()) {
168
+ export function readConfig(cwd = process.cwd(), env = process.env) {
169
169
  const path = join(cwd, ".lisa.config.json");
170
- if (!existsSync(path)) return withSurface(DEFAULTS);
170
+ // No repository is a real, supported state — not just a missing file.
171
+ //
172
+ // A Claude Tag channel session runs as the organization with no user account,
173
+ // and a repository "doesn't enter a session until a request names it". So a
174
+ // session can legitimately have no checkout and therefore no config, while
175
+ // still needing the credentials and profiles every other surface gets.
176
+ //
177
+ // The only values a config would supply here are the namespace and provider,
178
+ // so they can come from the environment instead. Everything else keeps its
179
+ // default, and an environment that sets neither still gets the old behaviour.
180
+ if (!existsSync(path)) return withSurface(fromEnvironment(env));
171
181
  let cfg;
172
182
  try {
173
183
  cfg = JSON.parse(readFileSync(path, "utf8")).secrets;
@@ -186,6 +196,36 @@ export function readConfig(cwd = process.cwd()) {
186
196
  });
187
197
  }
188
198
 
199
+ /**
200
+ * Build a configuration from the environment, for sessions with no checkout.
201
+ *
202
+ * `LISA_SECRETS_NAMESPACE` is the one value with no safe default: it names the
203
+ * directory secrets are written to and the tenant they belong to, so guessing
204
+ * it would write one tenant's credentials under another's name. Absent, this
205
+ * returns the ordinary defaults and the caller behaves exactly as before.
206
+ *
207
+ * The bootstrap key follows the namespace by convention
208
+ * (`BWS_ACCESS_TOKEN_<namespace>`) so a channel environment needs one variable
209
+ * set, not two.
210
+ * @param {object} env The environment to read.
211
+ * @returns {object} A configuration, defaulted where the environment is silent.
212
+ */
213
+ function fromEnvironment(env) {
214
+ const namespace = (env.LISA_SECRETS_NAMESPACE ?? "").trim();
215
+ if (!namespace) return DEFAULTS;
216
+
217
+ const provider = (env.LISA_SECRETS_PROVIDER ?? "").trim() || "bitwarden";
218
+ return {
219
+ ...DEFAULTS,
220
+ provider,
221
+ namespace: assertNamespace(namespace),
222
+ bootstrap: {
223
+ ...DEFAULTS.bootstrap,
224
+ key: env.LISA_SECRETS_BOOTSTRAP_KEY ?? `BWS_ACCESS_TOKEN_${namespace}`,
225
+ },
226
+ };
227
+ }
228
+
189
229
  /**
190
230
  * Attach the resolved surface and its capabilities to a configuration.
191
231
  * @param {object} cfg Configuration without surface resolution.
@@ -13,7 +13,7 @@ Prepare a remote surface so a host project can execute there. Today that means *
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
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 ] || { 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"
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; if [ -n "${LISA_SECRETS_NAMESPACE:-}" ]; then echo "No checkout; preparing tools and credentials for $LISA_SECRETS_NAMESPACE."; npx -y @codyswann/lisa@latest workstation --provider "${LISA_SECRETS_PROVIDER:-bitwarden}" --yes || true; npx -y @codyswann/lisa@latest remote-env --phase=secrets || true; else echo "No checkout and no LISA_SECRETS_NAMESPACE; nothing to prepare."; fi; exit 0
17
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"
18
18
  ```
19
19