@codyswann/lisa 2.322.4 → 2.322.6
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.
- package/dist/core/upstream-evidence-manifest.js +6 -6
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-remote-dispatch/SKILL.md +3 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-remote-dispatch/scripts/dispatch.mjs +27 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/SKILL.md +4 -4
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/assets/setup.sh +22 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +27 -11
- package/plugins/lisa/skills/lisa-remote-dispatch/SKILL.md +4 -1
- package/plugins/lisa/skills/lisa-remote-dispatch/scripts/dispatch.mjs +27 -3
- package/plugins/lisa/skills/lisa-setup-remote-env/SKILL.md +4 -4
- package/plugins/lisa/skills/lisa-setup-remote-env/assets/setup.sh +22 -0
- package/plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +27 -11
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-remote-dispatch/SKILL.md +4 -1
- package/plugins/lisa-agy/skills/lisa-remote-dispatch/scripts/dispatch.mjs +27 -3
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/SKILL.md +4 -4
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/assets/setup.sh +22 -0
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +27 -11
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/skills/lisa-remote-dispatch/SKILL.md +4 -1
- package/plugins/lisa-copilot/skills/lisa-remote-dispatch/scripts/dispatch.mjs +27 -3
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/SKILL.md +4 -4
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/assets/setup.sh +22 -0
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +27 -11
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/skills/lisa-remote-dispatch/SKILL.md +4 -1
- package/plugins/lisa-cursor/skills/lisa-remote-dispatch/scripts/dispatch.mjs +27 -3
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/SKILL.md +4 -4
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/assets/setup.sh +22 -0
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +27 -11
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/skills/lisa-remote-dispatch/SKILL.md +4 -1
- package/plugins/src/base/skills/lisa-remote-dispatch/scripts/dispatch.mjs +27 -3
- package/plugins/src/base/skills/lisa-setup-remote-env/SKILL.md +4 -4
- package/plugins/src/base/skills/lisa-setup-remote-env/assets/setup.sh +22 -0
- package/plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +27 -11
- package/scripts/lisa-remote-env/setup.sh +22 -0
|
@@ -526,8 +526,8 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
|
|
|
526
526
|
"plugins/src/base/skills/lisa-qa-queue/SKILL.md": "1d5f009f60004bf75b5d79bca370096ce40e1d41d585dc8afd4389f21bba84ae",
|
|
527
527
|
"plugins/src/base/skills/lisa-quality-review/SKILL.md": "17ba45f4c4b7877c0b0c9a3c1cc1cb9e18c642ead74ff7263698d8034d3241da",
|
|
528
528
|
"plugins/src/base/skills/lisa-queue-status/SKILL.md": "87c6d34d0511d4afd812d1af3fee80fa3b7aa47db8449760b12f2699fedc1d78",
|
|
529
|
-
"plugins/src/base/skills/lisa-remote-dispatch/SKILL.md": "
|
|
530
|
-
"plugins/src/base/skills/lisa-remote-dispatch/scripts/dispatch.mjs": "
|
|
529
|
+
"plugins/src/base/skills/lisa-remote-dispatch/SKILL.md": "f3c48120a206d01db45f849ca5b61690d572abc16bc36d559a4cacc8f9422c06",
|
|
530
|
+
"plugins/src/base/skills/lisa-remote-dispatch/scripts/dispatch.mjs": "475963ed64d9e72a6cbd6cbb61c8b57a419f2e1805e3ddfa76066047c590deeb",
|
|
531
531
|
"plugins/src/base/skills/lisa-repair-intake/SKILL.md": "4f85ac1381631e9f250d9cf3239baba633ae0df9ba1959f8835ed662592e2d77",
|
|
532
532
|
"plugins/src/base/skills/lisa-reproduce-bug/SKILL.md": "4d460993fac6021219ca23eee29b1b9afa7c37479dddc662b2fcfaca510edd68",
|
|
533
533
|
"plugins/src/base/skills/lisa-research/SKILL.md": "19de7c5910b117c4b3b1bb7ae42cf9c8b6ff2a376b2e21961526bc7ebde18e85",
|
|
@@ -559,10 +559,10 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
|
|
|
559
559
|
"plugins/src/base/skills/lisa-setup-linear/SKILL.md": "ec76f832a6df6f58b163f7f5ba6826ed2fcbddc91e44a8372e874858e4d0c518",
|
|
560
560
|
"plugins/src/base/skills/lisa-setup-notion/SKILL.md": "f5a1e9290789fd1c33675168d30461fb24a11c98a433ef777c1f536bc2f905ef",
|
|
561
561
|
"plugins/src/base/skills/lisa-setup-remote-aws/SKILL.md": "80fbf157f9c562c033886c25a99b37356602edd9e61cd2d492f339769ddcf97e",
|
|
562
|
-
"plugins/src/base/skills/lisa-setup-remote-env/SKILL.md": "
|
|
562
|
+
"plugins/src/base/skills/lisa-setup-remote-env/SKILL.md": "f706b5c94267d128bf41ef1a5fa6b68ea184e22c7929bda126128f08e1728b86",
|
|
563
563
|
"plugins/src/base/skills/lisa-setup-remote-env/assets/session-start.sh": "6e3871ec2f8d56b8ebb85376ebdd3956f3ed8fa4f7b278c2ed90ca9b8845897c",
|
|
564
|
-
"plugins/src/base/skills/lisa-setup-remote-env/assets/setup.sh": "
|
|
565
|
-
"plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs": "
|
|
564
|
+
"plugins/src/base/skills/lisa-setup-remote-env/assets/setup.sh": "c04afb1cf8e14a2713645228e679fa7772559488330a240ec0297cae6afd03e2",
|
|
565
|
+
"plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs": "f468dcf72512ff0b7d0d0ff6a38e81e5b57d83361ffff45c5265147f67ca01df",
|
|
566
566
|
"plugins/src/base/skills/lisa-setup-remote-env/scripts/toolchain.mjs": "ff66d33ba41a068d09be18f81ac68988238c2afa1d4e3733ae906b73eea74324",
|
|
567
567
|
"plugins/src/base/skills/lisa-setup-remote-env/scripts/verify-remote-env.mjs": "82bc2a27a0a5afb2ff413a88365c619fd7f0eaada5de3ccabf2000938f0607a4",
|
|
568
568
|
"plugins/src/base/skills/lisa-setup-sonar/SKILL.md": "53fbd8acce4b5e47e88195a7b90d5be424fa6ef7ad872f52c50467c690664c3b",
|
|
@@ -990,7 +990,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
|
|
|
990
990
|
"scripts/lisa-github-repo-setup.sh": "dc2f1c9d718aa34ba57161120d9319b5f78fe6b0b496d8e3c77226a08795aa36",
|
|
991
991
|
"scripts/lisa-github-rulesets.sh": "920a43ba268421b6fe55096062bd85850468bee9389f6006ad7c671010e7cccb",
|
|
992
992
|
"scripts/lisa-remote-env/session-start.sh": "6e3871ec2f8d56b8ebb85376ebdd3956f3ed8fa4f7b278c2ed90ca9b8845897c",
|
|
993
|
-
"scripts/lisa-remote-env/setup.sh": "
|
|
993
|
+
"scripts/lisa-remote-env/setup.sh": "c04afb1cf8e14a2713645228e679fa7772559488330a240ec0297cae6afd03e2",
|
|
994
994
|
"scripts/lisa-update-local.sh": "c811f9e10dbcb38499a9791c1ae9051460b347051d04a1d2046925bab9a53c96",
|
|
995
995
|
"scripts/lisa-work-item.mjs": "acb359ed7a39150fd5e1e68f4c95144045e75d9d53b735da4a7a9271f063044e",
|
|
996
996
|
"scripts/migrate-deploy-order.sh": "77d909b4cbbfc05169a79168d7868600ea7f56f846feefb7d5121618c54800c3",
|
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.322.
|
|
118
|
+
"version": "2.322.6",
|
|
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": {
|
|
@@ -16,9 +16,12 @@ It changes **where** work happens and nothing about **what** happens. The remote
|
|
|
16
16
|
| --- | --- |
|
|
17
17
|
| omitted / `local` | The calling skill proceeds normally. Nothing is dispatched. |
|
|
18
18
|
| `codex-cloud` | Submit to the project's Codex Cloud environment and return. |
|
|
19
|
+
| `claude-web` | Fire the project's Claude routine, which starts a cloud session, and return. |
|
|
19
20
|
|
|
20
21
|
Any other value is **rejected explicitly**. A silently ignored `executionEnv` would run the work locally while the operator believes it went remote, and nothing downstream would contradict that belief.
|
|
21
22
|
|
|
23
|
+
For the same reason, the parameter is accepted as both `executionEnv=…` and `--executionEnv=…`, and a *dashed* parameter this skill does not recognise is an error rather than payload. The bare form is the documented one, but the dashed form is what anyone who has used a CLI will type, and a misspelling of either is indistinguishable from not asking at all — which is the one failure an operator cannot act on. A bare `key=value` still belongs to the payload, since prose may legitimately contain an equals sign.
|
|
24
|
+
|
|
22
25
|
If a behaviour must differ between local and remote, it belongs in the calling skill as an explicit branch — never here. The moment this file starts encoding domain behaviour, there are two implementations to keep in sync.
|
|
23
26
|
|
|
24
27
|
## The invocation stays thin
|
|
@@ -68,11 +68,25 @@ const LEDGER = join(".lisa", "remote-dispatch.json");
|
|
|
68
68
|
/** This file's directory, for locating the sibling secrets skill. */
|
|
69
69
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
70
70
|
|
|
71
|
+
/** Every parameter this program reads. Anything else is a typo. */
|
|
72
|
+
const KNOWN_PARAMS = new Set(["executionEnv"]);
|
|
73
|
+
|
|
71
74
|
/**
|
|
72
75
|
* Split `key=value` parameters from the rest of an invocation.
|
|
73
76
|
*
|
|
74
77
|
* The remainder is passed through untouched. It is the caller's payload — a
|
|
75
78
|
* ticket key, a description — and this program has no business interpreting it.
|
|
79
|
+
*
|
|
80
|
+
* A leading `--` is accepted and stripped. The bare form is the documented one,
|
|
81
|
+
* but `--executionEnv=claude-web` is what anyone who has used a CLI this decade
|
|
82
|
+
* types, and it previously fell through to the payload and left the surface at
|
|
83
|
+
* its default. That is precisely the outcome this skill says it exists to
|
|
84
|
+
* prevent: work runs locally while the operator believes it went remote, and
|
|
85
|
+
* nothing downstream contradicts them.
|
|
86
|
+
*
|
|
87
|
+
* An unrecognised parameter is rejected for the same reason. A misspelled
|
|
88
|
+
* `executionEnvv=claude-web` is indistinguishable from not asking at all, and
|
|
89
|
+
* silence is the one response that cannot be acted on.
|
|
76
90
|
* @param {string} input Raw argument string.
|
|
77
91
|
* @returns {{params: Record<string, string>, rest: string}} Parsed invocation.
|
|
78
92
|
*/
|
|
@@ -83,9 +97,19 @@ export function parseInvocation(input) {
|
|
|
83
97
|
.trim()
|
|
84
98
|
.split(/\s+/)
|
|
85
99
|
.filter(Boolean)) {
|
|
86
|
-
const match = /^([A-Za-z][A-Za-z0-9_]*)=(.*)$/.exec(token);
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
const match = /^(--)?([A-Za-z][A-Za-z0-9_]*)=(.*)$/.exec(token);
|
|
101
|
+
// Only a dashed token is required to be a known parameter. A bare `x=y` may
|
|
102
|
+
// legitimately be part of a payload — a description, a query — and this
|
|
103
|
+
// program has no business rejecting the caller's prose.
|
|
104
|
+
if (match && (match[1] || KNOWN_PARAMS.has(match[2]))) {
|
|
105
|
+
if (!KNOWN_PARAMS.has(match[2])) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`unknown parameter "${match[2]}".\n` +
|
|
108
|
+
`Supported: ${[...KNOWN_PARAMS].join(", ")}.`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
params[match[2]] = match[3];
|
|
112
|
+
} else rest.push(token);
|
|
89
113
|
}
|
|
90
114
|
return { params, rest: rest.join(" ") };
|
|
91
115
|
}
|
|
@@ -13,8 +13,8 @@ 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; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
17
|
-
maintenance: n=0; rc=0; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
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"
|
|
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
|
|
|
20
20
|
**That line is identical for every project AND every surface.** Nothing in it names the
|
|
@@ -164,8 +164,8 @@ When emitting, produce exactly:
|
|
|
164
164
|
```text
|
|
165
165
|
Environment name: <project> remote executor
|
|
166
166
|
Repository: <org>/<repo> (must be the default checkout)
|
|
167
|
-
Setup script: n=0; rc=0; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
168
|
-
Maintenance: n=0; rc=0; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
167
|
+
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"
|
|
168
|
+
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"
|
|
169
169
|
(identical for every project — the script finds the
|
|
170
170
|
checkout and installs from the committed lockfile)
|
|
171
171
|
Environment vars: LISA_SECRETS_SURFACE=codex-cloud
|
|
@@ -105,11 +105,21 @@ fi
|
|
|
105
105
|
# plugin-delivered harnesses work at all. Lisa is a dependency of every project
|
|
106
106
|
# it is applied to, so `node_modules` carries the same skill at the version that
|
|
107
107
|
# project pins, which is the version its setup should run.
|
|
108
|
+
#
|
|
109
|
+
# `plugins/lisa/skills/` sits between them, and exists for exactly one project:
|
|
110
|
+
# Lisa itself. There the checkout IS Lisa, at HEAD, while `node_modules` holds
|
|
111
|
+
# whatever version its own lockfile pins — which was four months and a hundred
|
|
112
|
+
# skills behind, so this file did not exist there at all and setup aborted
|
|
113
|
+
# claiming the skill could not be found. The one place it was is the only place
|
|
114
|
+
# that was not searched. It is ahead of node_modules because a checkout that
|
|
115
|
+
# builds this skill is newer than any published copy of it, and harmless
|
|
116
|
+
# everywhere else because no other project has that directory.
|
|
108
117
|
runner=""
|
|
109
118
|
for candidate in \
|
|
110
119
|
".claude/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
|
|
111
120
|
".agents/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
|
|
112
121
|
".codex/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
|
|
122
|
+
"plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
|
|
113
123
|
"node_modules/@codyswann/lisa/plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs"; do
|
|
114
124
|
if [ -f "$candidate" ]; then
|
|
115
125
|
runner="$candidate"
|
|
@@ -132,6 +142,18 @@ if [ -z "$runner" ]; then
|
|
|
132
142
|
echo >&2
|
|
133
143
|
echo "If dependencies are installed, run 'lisa apply' so the skills are" >&2
|
|
134
144
|
echo "present, then re-run setup." >&2
|
|
145
|
+
echo >&2
|
|
146
|
+
# The version actually resolved, because "not found" and "found, but too old
|
|
147
|
+
# to contain this skill" read identically above and are fixed differently.
|
|
148
|
+
# The second is what happened on Lisa itself: node_modules held a release
|
|
149
|
+
# from before this skill existed, so every path checked was legitimately
|
|
150
|
+
# absent and the message blamed the install.
|
|
151
|
+
if [ -f node_modules/@codyswann/lisa/package.json ]; then
|
|
152
|
+
echo "For reference, node_modules has @codyswann/lisa version:" >&2
|
|
153
|
+
node -p "require('./node_modules/@codyswann/lisa/package.json').version" >&2 2>/dev/null ||
|
|
154
|
+
echo " (unreadable)" >&2
|
|
155
|
+
echo "If that predates this skill, the pin is the problem, not the install." >&2
|
|
156
|
+
fi
|
|
135
157
|
exit 1
|
|
136
158
|
fi
|
|
137
159
|
|
package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs
CHANGED
|
@@ -308,28 +308,44 @@ export function installAssets(cwd = process.cwd()) {
|
|
|
308
308
|
* at all — so a `$HOME` glob matched nothing there and bash was handed a path
|
|
309
309
|
* still containing a literal asterisk.
|
|
310
310
|
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
311
|
+
* Candidates are therefore tried relative to cwd first, then under `$HOME` and
|
|
312
|
+
* `/workspace` — the container roots the two surfaces actually use — because
|
|
313
|
+
* cwd is not reliably either of them. A Claude environment reported `$HOME` as
|
|
314
|
+
* `/root` with no checkout beneath it, which a cwd-only search cannot reach.
|
|
315
|
+
*
|
|
316
|
+
* EVERY match is prepared rather than the first. A Claude Code web environment
|
|
317
|
+
* can hold more than one checkout, so stopping at the first hit would prepare
|
|
318
|
+
* whichever repository sorts first and silently ignore the rest — arbitrary
|
|
319
|
+
* rather than merely limited. Each script anchors itself on its own repository
|
|
320
|
+
* root and each project materializes under its own `secrets.namespace`, so
|
|
321
|
+
* preparing several is well defined rather than a collision. Matches are
|
|
322
|
+
* deduplicated by resolved directory, since the candidate globs overlap
|
|
323
|
+
* whenever cwd happens to be one of the roots.
|
|
318
324
|
*
|
|
319
325
|
* The status is the first failure and every checkout is still attempted: one
|
|
320
326
|
* broken repository must neither hide the others nor report success. The
|
|
321
327
|
* explicit `exit 1` on no matches matters because a `for` loop over a glob that
|
|
322
328
|
* matches nothing otherwise exits 0 — the quiet success this guards against.
|
|
323
329
|
*
|
|
330
|
+
* Failure prints the layout it found rather than only the path it wanted. This
|
|
331
|
+
* field lives in a vendor settings box with a slow edit-and-retry loop, and a
|
|
332
|
+
* miss that reports nothing costs a whole round trip to learn one fact; the
|
|
333
|
+
* listing means the next message names the layout instead of repeating it.
|
|
334
|
+
*
|
|
324
335
|
* A field that named the repository and package manager was a string a human
|
|
325
336
|
* had to get right, in a settings box with no review, no version history and no
|
|
326
337
|
* test — and the logic it encoded belongs in a file that has all three.
|
|
327
338
|
*/
|
|
328
339
|
export const SETUP_FIELD =
|
|
329
|
-
|
|
330
|
-
"for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh
|
|
331
|
-
'
|
|
332
|
-
|
|
340
|
+
'n=0; rc=0; seen=""; ' +
|
|
341
|
+
"for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh " +
|
|
342
|
+
'"$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh ' +
|
|
343
|
+
"/workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; " +
|
|
344
|
+
'do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); ' +
|
|
345
|
+
'case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; ' +
|
|
346
|
+
'n=$((n+1)); bash "$f" || rc=$?; done; ' +
|
|
347
|
+
'[ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. ' +
|
|
348
|
+
'PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; ' +
|
|
333
349
|
'exit "$rc"';
|
|
334
350
|
|
|
335
351
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lisa-remote-dispatch
|
|
3
|
-
description: "Route one unit of work to a remote execution surface. Reads the executionEnv parameter (local by default, codex-cloud today), verifies the environment is provisioned and bound to this repository, submits a thin skill invocation, records the task identifier to .lisa/remote-dispatch.json, and exits without polling. Routing only — the remote runs the identical skill from the identical repository. Composable and inline: other skills invoke it via the Skill tool rather than users calling it directly."
|
|
3
|
+
description: "Route one unit of work to a remote execution surface. Reads the executionEnv parameter (local by default, codex-cloud or claude-web today), verifies the environment is provisioned and bound to this repository, submits a thin skill invocation, records the task identifier to .lisa/remote-dispatch.json, and exits without polling. Routing only — the remote runs the identical skill from the identical repository. Composable and inline: other skills invoke it via the Skill tool rather than users calling it directly."
|
|
4
4
|
allowed-tools: ["Bash", "Read", "Skill"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -16,9 +16,12 @@ It changes **where** work happens and nothing about **what** happens. The remote
|
|
|
16
16
|
| --- | --- |
|
|
17
17
|
| omitted / `local` | The calling skill proceeds normally. Nothing is dispatched. |
|
|
18
18
|
| `codex-cloud` | Submit to the project's Codex Cloud environment and return. |
|
|
19
|
+
| `claude-web` | Fire the project's Claude routine, which starts a cloud session, and return. |
|
|
19
20
|
|
|
20
21
|
Any other value is **rejected explicitly**. A silently ignored `executionEnv` would run the work locally while the operator believes it went remote, and nothing downstream would contradict that belief.
|
|
21
22
|
|
|
23
|
+
For the same reason, the parameter is accepted as both `executionEnv=…` and `--executionEnv=…`, and a *dashed* parameter this skill does not recognise is an error rather than payload. The bare form is the documented one, but the dashed form is what anyone who has used a CLI will type, and a misspelling of either is indistinguishable from not asking at all — which is the one failure an operator cannot act on. A bare `key=value` still belongs to the payload, since prose may legitimately contain an equals sign.
|
|
24
|
+
|
|
22
25
|
If a behaviour must differ between local and remote, it belongs in the calling skill as an explicit branch — never here. The moment this file starts encoding domain behaviour, there are two implementations to keep in sync.
|
|
23
26
|
|
|
24
27
|
## The invocation stays thin
|
|
@@ -68,11 +68,25 @@ const LEDGER = join(".lisa", "remote-dispatch.json");
|
|
|
68
68
|
/** This file's directory, for locating the sibling secrets skill. */
|
|
69
69
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
70
70
|
|
|
71
|
+
/** Every parameter this program reads. Anything else is a typo. */
|
|
72
|
+
const KNOWN_PARAMS = new Set(["executionEnv"]);
|
|
73
|
+
|
|
71
74
|
/**
|
|
72
75
|
* Split `key=value` parameters from the rest of an invocation.
|
|
73
76
|
*
|
|
74
77
|
* The remainder is passed through untouched. It is the caller's payload — a
|
|
75
78
|
* ticket key, a description — and this program has no business interpreting it.
|
|
79
|
+
*
|
|
80
|
+
* A leading `--` is accepted and stripped. The bare form is the documented one,
|
|
81
|
+
* but `--executionEnv=claude-web` is what anyone who has used a CLI this decade
|
|
82
|
+
* types, and it previously fell through to the payload and left the surface at
|
|
83
|
+
* its default. That is precisely the outcome this skill says it exists to
|
|
84
|
+
* prevent: work runs locally while the operator believes it went remote, and
|
|
85
|
+
* nothing downstream contradicts them.
|
|
86
|
+
*
|
|
87
|
+
* An unrecognised parameter is rejected for the same reason. A misspelled
|
|
88
|
+
* `executionEnvv=claude-web` is indistinguishable from not asking at all, and
|
|
89
|
+
* silence is the one response that cannot be acted on.
|
|
76
90
|
* @param {string} input Raw argument string.
|
|
77
91
|
* @returns {{params: Record<string, string>, rest: string}} Parsed invocation.
|
|
78
92
|
*/
|
|
@@ -83,9 +97,19 @@ export function parseInvocation(input) {
|
|
|
83
97
|
.trim()
|
|
84
98
|
.split(/\s+/)
|
|
85
99
|
.filter(Boolean)) {
|
|
86
|
-
const match = /^([A-Za-z][A-Za-z0-9_]*)=(.*)$/.exec(token);
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
const match = /^(--)?([A-Za-z][A-Za-z0-9_]*)=(.*)$/.exec(token);
|
|
101
|
+
// Only a dashed token is required to be a known parameter. A bare `x=y` may
|
|
102
|
+
// legitimately be part of a payload — a description, a query — and this
|
|
103
|
+
// program has no business rejecting the caller's prose.
|
|
104
|
+
if (match && (match[1] || KNOWN_PARAMS.has(match[2]))) {
|
|
105
|
+
if (!KNOWN_PARAMS.has(match[2])) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`unknown parameter "${match[2]}".\n` +
|
|
108
|
+
`Supported: ${[...KNOWN_PARAMS].join(", ")}.`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
params[match[2]] = match[3];
|
|
112
|
+
} else rest.push(token);
|
|
89
113
|
}
|
|
90
114
|
return { params, rest: rest.join(" ") };
|
|
91
115
|
}
|
|
@@ -13,8 +13,8 @@ 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; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
17
|
-
maintenance: n=0; rc=0; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
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"
|
|
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
|
|
|
20
20
|
**That line is identical for every project AND every surface.** Nothing in it names the
|
|
@@ -164,8 +164,8 @@ When emitting, produce exactly:
|
|
|
164
164
|
```text
|
|
165
165
|
Environment name: <project> remote executor
|
|
166
166
|
Repository: <org>/<repo> (must be the default checkout)
|
|
167
|
-
Setup script: n=0; rc=0; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
168
|
-
Maintenance: n=0; rc=0; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
167
|
+
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"
|
|
168
|
+
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"
|
|
169
169
|
(identical for every project — the script finds the
|
|
170
170
|
checkout and installs from the committed lockfile)
|
|
171
171
|
Environment vars: LISA_SECRETS_SURFACE=codex-cloud
|
|
@@ -105,11 +105,21 @@ fi
|
|
|
105
105
|
# plugin-delivered harnesses work at all. Lisa is a dependency of every project
|
|
106
106
|
# it is applied to, so `node_modules` carries the same skill at the version that
|
|
107
107
|
# project pins, which is the version its setup should run.
|
|
108
|
+
#
|
|
109
|
+
# `plugins/lisa/skills/` sits between them, and exists for exactly one project:
|
|
110
|
+
# Lisa itself. There the checkout IS Lisa, at HEAD, while `node_modules` holds
|
|
111
|
+
# whatever version its own lockfile pins — which was four months and a hundred
|
|
112
|
+
# skills behind, so this file did not exist there at all and setup aborted
|
|
113
|
+
# claiming the skill could not be found. The one place it was is the only place
|
|
114
|
+
# that was not searched. It is ahead of node_modules because a checkout that
|
|
115
|
+
# builds this skill is newer than any published copy of it, and harmless
|
|
116
|
+
# everywhere else because no other project has that directory.
|
|
108
117
|
runner=""
|
|
109
118
|
for candidate in \
|
|
110
119
|
".claude/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
|
|
111
120
|
".agents/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
|
|
112
121
|
".codex/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
|
|
122
|
+
"plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
|
|
113
123
|
"node_modules/@codyswann/lisa/plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs"; do
|
|
114
124
|
if [ -f "$candidate" ]; then
|
|
115
125
|
runner="$candidate"
|
|
@@ -132,6 +142,18 @@ if [ -z "$runner" ]; then
|
|
|
132
142
|
echo >&2
|
|
133
143
|
echo "If dependencies are installed, run 'lisa apply' so the skills are" >&2
|
|
134
144
|
echo "present, then re-run setup." >&2
|
|
145
|
+
echo >&2
|
|
146
|
+
# The version actually resolved, because "not found" and "found, but too old
|
|
147
|
+
# to contain this skill" read identically above and are fixed differently.
|
|
148
|
+
# The second is what happened on Lisa itself: node_modules held a release
|
|
149
|
+
# from before this skill existed, so every path checked was legitimately
|
|
150
|
+
# absent and the message blamed the install.
|
|
151
|
+
if [ -f node_modules/@codyswann/lisa/package.json ]; then
|
|
152
|
+
echo "For reference, node_modules has @codyswann/lisa version:" >&2
|
|
153
|
+
node -p "require('./node_modules/@codyswann/lisa/package.json').version" >&2 2>/dev/null ||
|
|
154
|
+
echo " (unreadable)" >&2
|
|
155
|
+
echo "If that predates this skill, the pin is the problem, not the install." >&2
|
|
156
|
+
fi
|
|
135
157
|
exit 1
|
|
136
158
|
fi
|
|
137
159
|
|
|
@@ -308,28 +308,44 @@ export function installAssets(cwd = process.cwd()) {
|
|
|
308
308
|
* at all — so a `$HOME` glob matched nothing there and bash was handed a path
|
|
309
309
|
* still containing a literal asterisk.
|
|
310
310
|
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
311
|
+
* Candidates are therefore tried relative to cwd first, then under `$HOME` and
|
|
312
|
+
* `/workspace` — the container roots the two surfaces actually use — because
|
|
313
|
+
* cwd is not reliably either of them. A Claude environment reported `$HOME` as
|
|
314
|
+
* `/root` with no checkout beneath it, which a cwd-only search cannot reach.
|
|
315
|
+
*
|
|
316
|
+
* EVERY match is prepared rather than the first. A Claude Code web environment
|
|
317
|
+
* can hold more than one checkout, so stopping at the first hit would prepare
|
|
318
|
+
* whichever repository sorts first and silently ignore the rest — arbitrary
|
|
319
|
+
* rather than merely limited. Each script anchors itself on its own repository
|
|
320
|
+
* root and each project materializes under its own `secrets.namespace`, so
|
|
321
|
+
* preparing several is well defined rather than a collision. Matches are
|
|
322
|
+
* deduplicated by resolved directory, since the candidate globs overlap
|
|
323
|
+
* whenever cwd happens to be one of the roots.
|
|
318
324
|
*
|
|
319
325
|
* The status is the first failure and every checkout is still attempted: one
|
|
320
326
|
* broken repository must neither hide the others nor report success. The
|
|
321
327
|
* explicit `exit 1` on no matches matters because a `for` loop over a glob that
|
|
322
328
|
* matches nothing otherwise exits 0 — the quiet success this guards against.
|
|
323
329
|
*
|
|
330
|
+
* Failure prints the layout it found rather than only the path it wanted. This
|
|
331
|
+
* field lives in a vendor settings box with a slow edit-and-retry loop, and a
|
|
332
|
+
* miss that reports nothing costs a whole round trip to learn one fact; the
|
|
333
|
+
* listing means the next message names the layout instead of repeating it.
|
|
334
|
+
*
|
|
324
335
|
* A field that named the repository and package manager was a string a human
|
|
325
336
|
* had to get right, in a settings box with no review, no version history and no
|
|
326
337
|
* test — and the logic it encoded belongs in a file that has all three.
|
|
327
338
|
*/
|
|
328
339
|
export const SETUP_FIELD =
|
|
329
|
-
|
|
330
|
-
"for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh
|
|
331
|
-
'
|
|
332
|
-
|
|
340
|
+
'n=0; rc=0; seen=""; ' +
|
|
341
|
+
"for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh " +
|
|
342
|
+
'"$HOME"/scripts/lisa-remote-env/setup.sh "$HOME"/*/scripts/lisa-remote-env/setup.sh ' +
|
|
343
|
+
"/workspace/scripts/lisa-remote-env/setup.sh /workspace/*/scripts/lisa-remote-env/setup.sh; " +
|
|
344
|
+
'do [ -f "$f" ] || continue; d=$(cd "$(dirname "$f")" && pwd -P); ' +
|
|
345
|
+
'case " $seen " in *" $d "*) continue;; esac; seen="$seen $d"; ' +
|
|
346
|
+
'n=$((n+1)); bash "$f" || rc=$?; done; ' +
|
|
347
|
+
'[ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found. ' +
|
|
348
|
+
'PWD=$PWD HOME=$HOME" >&2; ls -1 . "$HOME" /workspace 2>&1 | head -40 >&2; exit 1; }; ' +
|
|
333
349
|
'exit "$rc"';
|
|
334
350
|
|
|
335
351
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lisa-remote-dispatch
|
|
3
|
-
description: "Route one unit of work to a remote execution surface. Reads the executionEnv parameter (local by default, codex-cloud today), verifies the environment is provisioned and bound to this repository, submits a thin skill invocation, records the task identifier to .lisa/remote-dispatch.json, and exits without polling. Routing only — the remote runs the identical skill from the identical repository. Composable and inline: other skills invoke it via the Skill tool rather than users calling it directly."
|
|
3
|
+
description: "Route one unit of work to a remote execution surface. Reads the executionEnv parameter (local by default, codex-cloud or claude-web today), verifies the environment is provisioned and bound to this repository, submits a thin skill invocation, records the task identifier to .lisa/remote-dispatch.json, and exits without polling. Routing only — the remote runs the identical skill from the identical repository. Composable and inline: other skills invoke it via the Skill tool rather than users calling it directly."
|
|
4
4
|
allowed-tools: ["Bash", "Read", "Skill"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -16,9 +16,12 @@ It changes **where** work happens and nothing about **what** happens. The remote
|
|
|
16
16
|
| --- | --- |
|
|
17
17
|
| omitted / `local` | The calling skill proceeds normally. Nothing is dispatched. |
|
|
18
18
|
| `codex-cloud` | Submit to the project's Codex Cloud environment and return. |
|
|
19
|
+
| `claude-web` | Fire the project's Claude routine, which starts a cloud session, and return. |
|
|
19
20
|
|
|
20
21
|
Any other value is **rejected explicitly**. A silently ignored `executionEnv` would run the work locally while the operator believes it went remote, and nothing downstream would contradict that belief.
|
|
21
22
|
|
|
23
|
+
For the same reason, the parameter is accepted as both `executionEnv=…` and `--executionEnv=…`, and a *dashed* parameter this skill does not recognise is an error rather than payload. The bare form is the documented one, but the dashed form is what anyone who has used a CLI will type, and a misspelling of either is indistinguishable from not asking at all — which is the one failure an operator cannot act on. A bare `key=value` still belongs to the payload, since prose may legitimately contain an equals sign.
|
|
24
|
+
|
|
22
25
|
If a behaviour must differ between local and remote, it belongs in the calling skill as an explicit branch — never here. The moment this file starts encoding domain behaviour, there are two implementations to keep in sync.
|
|
23
26
|
|
|
24
27
|
## The invocation stays thin
|
|
@@ -68,11 +68,25 @@ const LEDGER = join(".lisa", "remote-dispatch.json");
|
|
|
68
68
|
/** This file's directory, for locating the sibling secrets skill. */
|
|
69
69
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
70
70
|
|
|
71
|
+
/** Every parameter this program reads. Anything else is a typo. */
|
|
72
|
+
const KNOWN_PARAMS = new Set(["executionEnv"]);
|
|
73
|
+
|
|
71
74
|
/**
|
|
72
75
|
* Split `key=value` parameters from the rest of an invocation.
|
|
73
76
|
*
|
|
74
77
|
* The remainder is passed through untouched. It is the caller's payload — a
|
|
75
78
|
* ticket key, a description — and this program has no business interpreting it.
|
|
79
|
+
*
|
|
80
|
+
* A leading `--` is accepted and stripped. The bare form is the documented one,
|
|
81
|
+
* but `--executionEnv=claude-web` is what anyone who has used a CLI this decade
|
|
82
|
+
* types, and it previously fell through to the payload and left the surface at
|
|
83
|
+
* its default. That is precisely the outcome this skill says it exists to
|
|
84
|
+
* prevent: work runs locally while the operator believes it went remote, and
|
|
85
|
+
* nothing downstream contradicts them.
|
|
86
|
+
*
|
|
87
|
+
* An unrecognised parameter is rejected for the same reason. A misspelled
|
|
88
|
+
* `executionEnvv=claude-web` is indistinguishable from not asking at all, and
|
|
89
|
+
* silence is the one response that cannot be acted on.
|
|
76
90
|
* @param {string} input Raw argument string.
|
|
77
91
|
* @returns {{params: Record<string, string>, rest: string}} Parsed invocation.
|
|
78
92
|
*/
|
|
@@ -83,9 +97,19 @@ export function parseInvocation(input) {
|
|
|
83
97
|
.trim()
|
|
84
98
|
.split(/\s+/)
|
|
85
99
|
.filter(Boolean)) {
|
|
86
|
-
const match = /^([A-Za-z][A-Za-z0-9_]*)=(.*)$/.exec(token);
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
const match = /^(--)?([A-Za-z][A-Za-z0-9_]*)=(.*)$/.exec(token);
|
|
101
|
+
// Only a dashed token is required to be a known parameter. A bare `x=y` may
|
|
102
|
+
// legitimately be part of a payload — a description, a query — and this
|
|
103
|
+
// program has no business rejecting the caller's prose.
|
|
104
|
+
if (match && (match[1] || KNOWN_PARAMS.has(match[2]))) {
|
|
105
|
+
if (!KNOWN_PARAMS.has(match[2])) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`unknown parameter "${match[2]}".\n` +
|
|
108
|
+
`Supported: ${[...KNOWN_PARAMS].join(", ")}.`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
params[match[2]] = match[3];
|
|
112
|
+
} else rest.push(token);
|
|
89
113
|
}
|
|
90
114
|
return { params, rest: rest.join(" ") };
|
|
91
115
|
}
|
|
@@ -13,8 +13,8 @@ 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; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
17
|
-
maintenance: n=0; rc=0; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
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"
|
|
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
|
|
|
20
20
|
**That line is identical for every project AND every surface.** Nothing in it names the
|
|
@@ -164,8 +164,8 @@ When emitting, produce exactly:
|
|
|
164
164
|
```text
|
|
165
165
|
Environment name: <project> remote executor
|
|
166
166
|
Repository: <org>/<repo> (must be the default checkout)
|
|
167
|
-
Setup script: n=0; rc=0; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
168
|
-
Maintenance: n=0; rc=0; for f in scripts/lisa-remote-env/setup.sh */scripts/lisa-remote-env/setup.sh; do [ -f "$f" ] || continue; n=$((n+1)); bash "$f" || rc=$?; done; [ "$n" -gt 0 ] || { echo "lisa-remote-env entrypoint not found
|
|
167
|
+
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"
|
|
168
|
+
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"
|
|
169
169
|
(identical for every project — the script finds the
|
|
170
170
|
checkout and installs from the committed lockfile)
|
|
171
171
|
Environment vars: LISA_SECRETS_SURFACE=codex-cloud
|