litmus-cli 1.4.85-desktop.1 → 1.4.85
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/README.md +103 -122
- package/dist/commands/connect.d.ts +1 -2
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +10 -60
- package/dist/commands/connect.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/ai-tracking.js +1 -1
- package/dist/lib/ai-tracking.js.map +1 -1
- package/dist/lib/connection-attempt.js +1 -1
- package/dist/lib/connection-attempt.js.map +1 -1
- package/dist/lib/hook-logger.cjs +145 -3
- package/dist/lib/ssh-client.d.ts +0 -12
- package/dist/lib/ssh-client.d.ts.map +1 -1
- package/dist/lib/ssh-client.js +1 -1
- package/dist/lib/ssh-client.js.map +1 -1
- package/package.json +1 -1
- package/dist/lib/desktop-app.d.ts +0 -17
- package/dist/lib/desktop-app.d.ts.map +0 -1
- package/dist/lib/desktop-app.js +0 -115
- package/dist/lib/desktop-app.js.map +0 -1
package/README.md
CHANGED
|
@@ -10,72 +10,46 @@ npm install -g litmus-cli
|
|
|
10
10
|
|
|
11
11
|
Requires Node.js 20.19+.
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Current candidate flow: hosted workspace
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Start from your Litmus assessment page, accept its disclosure, and follow its
|
|
16
|
+
connection instructions. The hosted workflow uses `litmus connect`, not
|
|
17
|
+
`litmus init`: your project and development tools run in the remote workspace.
|
|
18
|
+
The commands on your assessment page are authoritative for your assigned flow.
|
|
16
19
|
|
|
17
20
|
```bash
|
|
18
|
-
litmus
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
- Downloads the assessment package
|
|
22
|
-
- Installs dependencies automatically
|
|
23
|
-
- Initializes a git repo with an initial commit
|
|
24
|
-
- Starts background file tracking
|
|
25
|
-
- Checks that AI capture works: a test prompt is sent through each installed
|
|
26
|
-
hook and confirmed to have reached Litmus. The result is the last thing
|
|
27
|
-
printed. If it fails for a tool you use, follow the steps it prints before
|
|
28
|
-
you start (`litmus doctor` repairs the hook files and re-runs the check).
|
|
29
|
-
Cursor, Codex and the other CLIs read their hook config once, at launch, so
|
|
30
|
-
a tool that was already open needs to be quit and reopened.
|
|
31
|
-
- **Your timer begins when you run this command**
|
|
32
|
-
- Your work is automatically submitted when the time limit is reached — if auto-submit fails, run `litmus submit` manually within 5 minutes of the deadline
|
|
33
|
-
|
|
34
|
-
Your token is provided on the Litmus candidate portal when you open your assessment.
|
|
35
|
-
|
|
36
|
-
### Check your machine before you start
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
litmus setup-check
|
|
21
|
+
litmus connect <token>
|
|
40
22
|
```
|
|
41
23
|
|
|
42
|
-
|
|
43
|
-
folder. It needs no token and touches nothing outside a temporary directory.
|
|
44
|
-
It confirms Node.js is new enough, the CLI is the current version, git is
|
|
45
|
-
installed, Litmus is reachable from your network, and the activity tracker
|
|
46
|
-
can start on this machine (antivirus software occasionally blocks it). It
|
|
47
|
-
ends with either `Ready` or one line saying what to fix.
|
|
48
|
-
|
|
49
|
-
### Check your status
|
|
24
|
+
Choose VS Code, Cursor, the browser editor, or SSH. To open a terminal directly:
|
|
50
25
|
|
|
51
26
|
```bash
|
|
52
|
-
litmus
|
|
27
|
+
litmus connect <token> --ide ssh
|
|
53
28
|
```
|
|
54
29
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
- Git commit stats
|
|
60
|
-
- Estimated submission size
|
|
61
|
-
- Tracker status
|
|
62
|
-
|
|
63
|
-
### Submit your work
|
|
30
|
+
This configures the SSH key and workspace alias and opens a shell in
|
|
31
|
+
`/home/candidate/workspace`. Work on the remote files, run your tests there, and
|
|
32
|
+
submit from the assessment page or with `litmus push`. Follow the page's timing
|
|
33
|
+
and any post-submission questions or walkthrough instructions.
|
|
64
34
|
|
|
65
|
-
|
|
66
|
-
litmus submit
|
|
67
|
-
```
|
|
35
|
+
### Codex desktop app and SSH
|
|
68
36
|
|
|
69
|
-
|
|
37
|
+
There is no `--ide codex` destination or automatic Codex desktop handoff in
|
|
38
|
+
this CLI. After `litmus connect <token> --ide ssh` has configured the connection,
|
|
39
|
+
use the app's native SSH connection settings to select the generated
|
|
40
|
+
`litmus-<workspace-id>` host from `~/.ssh/config`, then open the remote project at
|
|
41
|
+
`/home/candidate/workspace`. The app runs its remote agent through SSH; opening
|
|
42
|
+
a local folder alone does not attach it to the hosted filesystem. See the
|
|
43
|
+
[official remote connection instructions](https://learn.chatgpt.com/docs/remote-connections#connect-to-an-ssh-host).
|
|
70
44
|
|
|
71
|
-
|
|
45
|
+
Litmus compatibility with that native desktop connection and desktop
|
|
46
|
+
prompt/response capture still need an end-to-end check for the installed app
|
|
47
|
+
version. Configuring SSH or installing Codex hooks alone does not verify either.
|
|
48
|
+
Running `codex` in the workspace's SSH shell instead uses the remote Codex CLI.
|
|
72
49
|
|
|
73
|
-
###
|
|
50
|
+
### Submit a hosted workspace
|
|
74
51
|
|
|
75
|
-
|
|
76
|
-
it in the browser or connect to it with `litmus connect`. There is nothing local
|
|
77
|
-
to package there, so `litmus submit` does not apply and will tell you so. Submit
|
|
78
|
-
with:
|
|
52
|
+
Use the Submit button on your assessment page, or run:
|
|
79
53
|
|
|
80
54
|
```bash
|
|
81
55
|
litmus push
|
|
@@ -86,37 +60,6 @@ as `litmus push <token>` with the token from your assessment page. Either way it
|
|
|
86
60
|
captures the workspace exactly as it stands, so there is nothing to commit or push
|
|
87
61
|
first. The Submit button on your assessment page does the same thing.
|
|
88
62
|
|
|
89
|
-
### Codex App and Claude Desktop
|
|
90
|
-
|
|
91
|
-
For a hosted workspace, select the app on the assessment page, then use its setup command:
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
litmus connect <token> --ide codex
|
|
95
|
-
litmus connect <token> --ide claude
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
Both configure the same dedicated Litmus SSH key and host alias and verify SSH plus
|
|
99
|
-
remote runtime/capture configuration before handing off. Codex App uses Settings →
|
|
100
|
-
Connections → SSH: enable the printed host and choose `/home/candidate/workspace`.
|
|
101
|
-
If the workspace uses your own AI account, first run
|
|
102
|
-
`ssh -t <litmus-host-alias> codex login --device-auth`, open the printed browser
|
|
103
|
-
link, and enter the one-time code. Enable device code login in ChatGPT security
|
|
104
|
-
settings if prompted. Litmus pre-authenticated workspaces do not need this step.
|
|
105
|
-
Claude Desktop opens its Code tab with that host and folder prefilled (v2.110.0 or
|
|
106
|
-
later); confirm the connection. Neither requires downloading the assessment locally.
|
|
107
|
-
Keep edits in the workspace folder, without a separate worktree, and submit through
|
|
108
|
-
the assessment page. A successful handoff verifies setup, not that an app has attached
|
|
109
|
-
or a prompt has been captured.
|
|
110
|
-
|
|
111
|
-
For maintainers, merging this support does not activate the new app choices:
|
|
112
|
-
`NEXT_PUBLIC_LITMUS_DESKTOP_CLI_VERSION` stays unset until rollout, hiding both.
|
|
113
|
-
Use a verified published prerelease only on its Preview branch. After merge,
|
|
114
|
-
land a new stable package/lockfile version bump (for example `1.4.85`) through a reviewed PR,
|
|
115
|
-
then tag that merged `main` commit with the matching version (for example `cli/v1.4.85`) to publish it. Obtain
|
|
116
|
-
production approval before setting the production gate to that version and
|
|
117
|
-
redeploying. Leave npm `latest` unchanged during preview testing. See the
|
|
118
|
-
[desktop app rollout runbook](https://github.com/litmus-team/litmus/blob/main/docs/runbooks/desktop-app-workspaces.md).
|
|
119
|
-
|
|
120
63
|
`litmus connect` also asks permission to record supported local AI-agent prompts
|
|
121
64
|
and responses across folders during the assessment, alongside hosted capture.
|
|
122
65
|
A background capture watcher stays on your computer after connect returns. It
|
|
@@ -168,17 +111,71 @@ If a connection drops it reconnects on its own. Once your assessment is submitte
|
|
|
168
111
|
over, or locked, forwarding stops and explains why.
|
|
169
112
|
|
|
170
113
|
|
|
171
|
-
##
|
|
114
|
+
## Legacy local-package flow — only when your assessment page directs it
|
|
115
|
+
|
|
116
|
+
`litmus init` remains for local-package assessments and explicit fallback to
|
|
117
|
+
local work. These instructions do not describe hosted workspaces. Do not run
|
|
118
|
+
`init` or submit a local archive for a hosted assessment.
|
|
119
|
+
|
|
120
|
+
### Initialize a legacy local-package assessment
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
litmus init <token>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- Downloads the assessment package
|
|
127
|
+
- Installs dependencies automatically
|
|
128
|
+
- Initializes a git repo with an initial commit
|
|
129
|
+
- Starts background file tracking
|
|
130
|
+
- Checks that AI capture works: a test prompt is sent through each installed
|
|
131
|
+
hook and confirmed to have reached Litmus. The result is the last thing
|
|
132
|
+
printed. If it fails for a tool you use, follow the steps it prints before
|
|
133
|
+
you start (`litmus doctor` repairs the hook files and re-runs the check).
|
|
134
|
+
Cursor, Codex and the other CLIs read their hook config once, at launch, so
|
|
135
|
+
a tool that was already open needs to be quit and reopened.
|
|
136
|
+
- **Your timer begins when you run this command**
|
|
137
|
+
- Your work is automatically submitted when the time limit is reached — if auto-submit fails, run `litmus submit` manually within 5 minutes of the deadline
|
|
138
|
+
|
|
139
|
+
Your token is provided on the Litmus candidate portal when you open your assessment.
|
|
140
|
+
|
|
141
|
+
### Check your machine before you start
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
litmus setup-check
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Run this before a live interview or before opening a take-home, from any
|
|
148
|
+
folder. It needs no token and touches nothing outside a temporary directory.
|
|
149
|
+
It confirms Node.js is new enough, the CLI is the current version, git is
|
|
150
|
+
installed, Litmus is reachable from your network, and the activity tracker
|
|
151
|
+
can start on this machine (antivirus software occasionally blocks it). It
|
|
152
|
+
ends with either `Ready` or one line saying what to fix.
|
|
153
|
+
|
|
154
|
+
### Check your status
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
litmus status
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Run this from inside your assessment folder to see:
|
|
161
|
+
|
|
162
|
+
- Time elapsed and remaining
|
|
163
|
+
- Deadline info
|
|
164
|
+
- Git commit stats
|
|
165
|
+
- Estimated submission size
|
|
166
|
+
- Tracker status
|
|
167
|
+
|
|
168
|
+
### Submit your work
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
litmus submit
|
|
172
|
+
```
|
|
172
173
|
|
|
173
|
-
|
|
174
|
-
1. `litmus init <token>` — sets up your workspace and starts the clock
|
|
175
|
-
2. Work in your preferred editor, committing frequently
|
|
176
|
-
3. `litmus status` — check your progress and time remaining
|
|
177
|
-
4. `litmus submit` — packages and uploads everything in one step
|
|
174
|
+
Run this from inside your assessment folder when you're done. It packages your work (source code + git history + activity log) and uploads it automatically. The assessment folder is deleted after a successful submission.
|
|
178
175
|
|
|
179
|
-
|
|
176
|
+
Use `litmus submit --yes` to skip the confirmation prompt.
|
|
180
177
|
|
|
181
|
-
|
|
178
|
+
### Legacy local-package activity and capture
|
|
182
179
|
|
|
183
180
|
While you're working, the background tracker sends activity data to Litmus
|
|
184
181
|
in addition to the submission ZIP you upload at the end:
|
|
@@ -214,7 +211,7 @@ in addition to the submission ZIP you upload at the end:
|
|
|
214
211
|
You can confirm what's installed and what's being captured at any point with
|
|
215
212
|
`litmus status`.
|
|
216
213
|
|
|
217
|
-
|
|
214
|
+
### Legacy local-package hook installation
|
|
218
215
|
|
|
219
216
|
`litmus init` installs the hooks for Claude Code, Codex, Cursor and the Gemini
|
|
220
217
|
CLI in your user-level config for each tool: `~/.claude/settings.json`,
|
|
@@ -247,45 +244,29 @@ GitHub Actions workflow. **Do not run `npm publish` by hand** — the workflow
|
|
|
247
244
|
publishes via npm OIDC trusted publishing (no npm login or token needed), and a
|
|
248
245
|
manual publish skips the build/test gate and the GitHub release.
|
|
249
246
|
|
|
250
|
-
###
|
|
251
|
-
|
|
252
|
-
The dist-tag is derived from the **version string**, not from a flag: a
|
|
253
|
-
prerelease like `1.4.0-dogfood.3` publishes under `dogfood`, a stable `1.3.13`
|
|
254
|
-
publishes to `latest`. So the version number *is* the decision about who gets it.
|
|
255
|
-
|
|
256
|
-
- **`latest` (1.3.x) — what candidates install.** `main` is **not** on this line;
|
|
257
|
-
`main` carries the `1.4.0-dogfood` track with unreleased Codespaces v2
|
|
258
|
-
(`litmus connect`, `litmus push`). Cutting a stable release from `main` would
|
|
259
|
-
put v2's surface in front of every candidate. A candidate-facing fix therefore
|
|
260
|
-
ships as a **backport**: branch off the newest `cli/v1.3.*` tag, `git
|
|
261
|
-
cherry-pick -x` the merged commits, bump, tag. Release branches are never
|
|
262
|
-
merged back to `main`.
|
|
263
|
-
- **`dogfood` (1.4.0-dogfood.N)** — cut from `main` for internal testing.
|
|
247
|
+
### Stable and prerelease publishing
|
|
264
248
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
cli
|
|
270
|
-
```
|
|
249
|
+
The dist-tag comes from the version string: stable versions publish to `latest`;
|
|
250
|
+
a prerelease such as `1.4.0-dogfood.3` publishes to `dogfood`. The current stable
|
|
251
|
+
CLI includes `connect` and `push`; they are not an unreleased dogfood-only flow.
|
|
252
|
+
The publish workflow requires a stable release commit to be on `main` or a
|
|
253
|
+
`release/cli-*` branch. A prerelease may come from another branch.
|
|
271
254
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
`cli/scripts/no-backport.txt` with a reason so the list stays actionable.
|
|
255
|
+
Merging to `main` does not publish the CLI. Bump through a PR, merge, then tag the
|
|
256
|
+
reviewed commit. If deliberately backporting to a separate release branch, use
|
|
257
|
+
`git cherry-pick -x` to retain provenance; do not assume all fixes need a 1.3.x
|
|
258
|
+
backport. `cli/scripts/pending-backports.sh` is the historical backport report.
|
|
277
259
|
|
|
278
260
|
To cut a release:
|
|
279
261
|
|
|
280
|
-
1. Set the version in `cli/package.json` on the branch you are tagging — the
|
|
281
|
-
|
|
282
|
-
protected) for a dogfood cut.
|
|
262
|
+
1. Set the version in `cli/package.json` on the branch you are tagging — `main` (through a PR), or the
|
|
263
|
+
intended `release/cli-*` branch for an explicit backport.
|
|
283
264
|
2. Push a tag matching `cli/vX.Y.Z`, where `X.Y.Z` **exactly equals** the version
|
|
284
265
|
at the tagged commit:
|
|
285
266
|
|
|
286
267
|
```bash
|
|
287
|
-
git tag cli/
|
|
288
|
-
git push origin cli/
|
|
268
|
+
git tag cli/vX.Y.Z
|
|
269
|
+
git push origin cli/vX.Y.Z
|
|
289
270
|
```
|
|
290
271
|
|
|
291
272
|
The tag push triggers the workflow, which builds and tests the CLI on Linux +
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type DesktopApp } from "../lib/desktop-app.js";
|
|
2
1
|
import { ConnectionAttempt } from "../lib/connection-attempt.js";
|
|
3
2
|
import { type ResolvedEditorCommand } from "../lib/editor-binary.js";
|
|
4
3
|
import type { NativeIde } from "../lib/editor-ide.js";
|
|
@@ -620,7 +619,7 @@ export type EditorLaunchResult = {
|
|
|
620
619
|
launchLog: string | null;
|
|
621
620
|
};
|
|
622
621
|
export declare function attemptEditorLaunch(ed: NativeEditor, io: EditorLaunchIo): Promise<EditorLaunchResult>;
|
|
623
|
-
export type IdeChoice = "vscode" | "cursor" | "browser" | "ssh"
|
|
622
|
+
export type IdeChoice = "vscode" | "cursor" | "browser" | "ssh";
|
|
624
623
|
/**
|
|
625
624
|
* Resolve which editor to open: an explicit --ide flag wins; otherwise prompt.
|
|
626
625
|
* Falls back to native VS Code when the flag is unknown or stdin isn't a TTY
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/commands/connect.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/commands/connect.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/connect.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { claudeDesktopUrl, desktopAppInstructions, desktopAppProbeCommand } from "../lib/desktop-app.js";
|
|
2
1
|
import { startHostedCapture } from "../lib/hosted-capture.js";
|
|
3
2
|
import { installSshForwardHook } from "../lib/install-ssh-forward-hook.js";
|
|
4
3
|
import { runSsh } from "./ssh.js";
|
|
@@ -23,7 +22,7 @@ import { editorInstallCandidates, editorSpawnSpec } from "../lib/editor-binary.j
|
|
|
23
22
|
import { isWsl, whichOnPath, windowsSideEditor, wslEditorHint } from "../lib/wsl.js";
|
|
24
23
|
import { parseEditorVersion, parseWorkspaceProbe, remoteProbeCommand, seedVerdict, verifyVerdict, VERIFY_SCHEDULE_MS, } from "../lib/editor-server.js";
|
|
25
24
|
import { fatal, holdExitFor, success, info, warn, setErrorContext, reportEvent } from "../lib/errors.js";
|
|
26
|
-
import {
|
|
25
|
+
import { oldWindowsSshHint, parseOpenSshVersion, proxyJumpBroken, readEditorSettings, readSshVersionBanner, sshExecutableFor, sshPreflight, sshPreflightHint, } from "../lib/ssh-client.js";
|
|
27
26
|
import { editorEndingForewarning } from "../lib/session-end.js";
|
|
28
27
|
import { attemptRelaunch, platformSupportsGracefulCursorRestart, realCursorProcessIo, } from "../lib/cursor-restart.js";
|
|
29
28
|
/**
|
|
@@ -907,14 +906,9 @@ function readEditorLaunchLog(logPath) {
|
|
|
907
906
|
}
|
|
908
907
|
}
|
|
909
908
|
export function sshProbeRunner(alias, executable = "ssh") {
|
|
910
|
-
const options = ["-o", "BatchMode=yes", "-o", "ConnectTimeout=10", "-o", "LogLevel=ERROR"];
|
|
911
|
-
// Match preflight: inherited tmux commands must not replace our remote probe.
|
|
912
|
-
// Only clients that configure RemoteCommand understand this option (OpenSSH 7.6+).
|
|
913
|
-
if (configSetsRemoteCommand(alias, executable, spawnSync))
|
|
914
|
-
options.push("-o", "RemoteCommand=none");
|
|
915
909
|
return (remoteCommand) => {
|
|
916
910
|
try {
|
|
917
|
-
const probed = spawnSync(executable, [
|
|
911
|
+
const probed = spawnSync(executable, ["-o", "BatchMode=yes", "-o", "ConnectTimeout=10", "-o", "LogLevel=ERROR", alias, remoteCommand], { encoding: "utf8", timeout: 20000 });
|
|
918
912
|
if (probed.error || probed.status !== 0)
|
|
919
913
|
return null;
|
|
920
914
|
return probed.stdout ?? null;
|
|
@@ -1018,7 +1012,7 @@ export async function attemptEditorLaunch(ed, io) {
|
|
|
1018
1012
|
*/
|
|
1019
1013
|
export async function resolveIde(flag, log = console.log, platform = process.platform) {
|
|
1020
1014
|
const norm = (flag ?? "").trim().toLowerCase();
|
|
1021
|
-
if (norm === "vscode" || norm === "cursor" || norm === "browser" || norm === "ssh"
|
|
1015
|
+
if (norm === "vscode" || norm === "cursor" || norm === "browser" || norm === "ssh") {
|
|
1022
1016
|
if (norm === "cursor")
|
|
1023
1017
|
for (const line of cursorSelectionNoticeLines(platform))
|
|
1024
1018
|
log(line);
|
|
@@ -1027,7 +1021,7 @@ export async function resolveIde(flag, log = console.log, platform = process.pla
|
|
|
1027
1021
|
// ENG-2895: no "asking instead". Without a terminal this falls through to VS Code below,
|
|
1028
1022
|
// so that would be false there.
|
|
1029
1023
|
if (norm)
|
|
1030
|
-
warn(`Unknown --ide "${flag}". Use vscode, cursor,
|
|
1024
|
+
warn(`Unknown --ide "${flag}". Use vscode, cursor, browser or ssh.`);
|
|
1031
1025
|
if (!process.stdin.isTTY)
|
|
1032
1026
|
return { ide: "vscode", chosen: false };
|
|
1033
1027
|
const answered = await promptIdeAnswer();
|
|
@@ -1175,10 +1169,6 @@ export function ideForChoice(answer) {
|
|
|
1175
1169
|
return "cursor";
|
|
1176
1170
|
if (a === "4")
|
|
1177
1171
|
return "ssh";
|
|
1178
|
-
if (a === "5")
|
|
1179
|
-
return "codex";
|
|
1180
|
-
if (a === "6")
|
|
1181
|
-
return "claude";
|
|
1182
1172
|
return "browser";
|
|
1183
1173
|
}
|
|
1184
1174
|
/**
|
|
@@ -1191,11 +1181,9 @@ export function ideMenuLines() {
|
|
|
1191
1181
|
` ${chalk.bold("1")}) Browser IDE — nothing to install locally ${chalk.dim("[default]")}`,
|
|
1192
1182
|
` ${chalk.bold("2")}) VS Code — native, via Remote-SSH`,
|
|
1193
1183
|
// ENG-2389. Cursor sits beside VS Code, where it belongs by kinship, and plain SSH is
|
|
1194
|
-
//
|
|
1184
|
+
// last — see `ideForChoice` for what that renumbering costs and why it is bounded.
|
|
1195
1185
|
` ${chalk.bold("3")}) Cursor — native, via Remote-SSH`,
|
|
1196
1186
|
` ${chalk.bold("4")}) SSH — open the workspace in this terminal`,
|
|
1197
|
-
` ${chalk.bold("5")}) Codex App — connect over SSH`,
|
|
1198
|
-
` ${chalk.bold("6")}) Claude Desktop — connect over SSH`,
|
|
1199
1187
|
];
|
|
1200
1188
|
}
|
|
1201
1189
|
/**
|
|
@@ -1289,7 +1277,7 @@ function promptIdeAnswer() {
|
|
|
1289
1277
|
*/
|
|
1290
1278
|
function openBrowser(url) {
|
|
1291
1279
|
const spec = process.platform === "darwin" ? ["open", [url]]
|
|
1292
|
-
: process.platform === "win32" ? ["
|
|
1280
|
+
: process.platform === "win32" ? ["cmd", ["/c", "start", "", url]]
|
|
1293
1281
|
: ["xdg-open", [url]];
|
|
1294
1282
|
return new Promise((resolve) => {
|
|
1295
1283
|
try {
|
|
@@ -1454,10 +1442,6 @@ async function connectFlow(token, ideOpt, opts, skillImport, attempt) {
|
|
|
1454
1442
|
const { ide: chosenIde, chosen: ideWasChosen } = await resolveIde(ideOpt, console.log);
|
|
1455
1443
|
let ide = chosenIde;
|
|
1456
1444
|
attempt.editor(ide);
|
|
1457
|
-
if ((ide === "codex" || ide === "claude") && isWsl()) {
|
|
1458
|
-
fatal("Run desktop app setup from your computer's native terminal.", "Use PowerShell or Windows Terminal outside WSL so the app and Litmus share the same SSH configuration.", { severity: "warning" });
|
|
1459
|
-
return;
|
|
1460
|
-
}
|
|
1461
1445
|
// ENG-2814: asked here, next to the editor choice, and uploaded once the workspace is
|
|
1462
1446
|
// ready. Never fails the connect. See `lib/connect-skills.ts`.
|
|
1463
1447
|
attempt.stage("skills");
|
|
@@ -1584,7 +1568,7 @@ async function connectFlow(token, ideOpt, opts, skillImport, attempt) {
|
|
|
1584
1568
|
if (conn.ssh_command) {
|
|
1585
1569
|
try {
|
|
1586
1570
|
const parsed = parseSshCommand(conn.ssh_command);
|
|
1587
|
-
const alias = aliasFor(conn.ssh_hostname
|
|
1571
|
+
const alias = aliasFor(conn.ssh_hostname, token);
|
|
1588
1572
|
pruneStaleHostKeys(parsed);
|
|
1589
1573
|
const cfgPath = await writeSshConfig(alias, buildSshConfigBlock(alias, KEY_PATH, parsed), buildControlPathBlock(alias, parsed));
|
|
1590
1574
|
if (verbose)
|
|
@@ -1625,16 +1609,13 @@ async function connectFlow(token, ideOpt, opts, skillImport, attempt) {
|
|
|
1625
1609
|
sshBanners.set(executable, readSshVersionBanner(executable));
|
|
1626
1610
|
return sshBanners.get(executable) ?? null;
|
|
1627
1611
|
};
|
|
1628
|
-
const desktopApp = ide === "codex" || ide === "claude";
|
|
1629
|
-
const sshRoute = desktopApp ? "ssh" : ide;
|
|
1630
|
-
const sshSettings = sshRoute === "ssh" || ide === "browser" ? null : readEditorSettings(sshRoute);
|
|
1631
1612
|
// ENG-2682 — Windows' own OpenSSH below 8.1 cannot run the ProxyJump every bastion
|
|
1632
1613
|
// route depends on (see `lib/ssh-client.ts`). Refuse before writing anything, with the
|
|
1633
1614
|
// version named and a way out, rather than hand an editor a connection it will lose
|
|
1634
1615
|
// before it reaches us. The client judged is the one this route will run: the editor's
|
|
1635
1616
|
// `remote.SSH.path` when it names one, PATH's ssh otherwise.
|
|
1636
1617
|
if (process.platform === "win32" && parsed.jumpHost && ide !== "browser") {
|
|
1637
|
-
const executable = sshExecutableFor(
|
|
1618
|
+
const executable = sshExecutableFor(ide, ide === "ssh" ? null : readEditorSettings(ide));
|
|
1638
1619
|
const client = parseOpenSshVersion(sshBanner(executable) ?? "");
|
|
1639
1620
|
if (client && proxyJumpBroken(client)) {
|
|
1640
1621
|
const where = executable === "ssh" ? "" : ` at ${executable}, set in remote.SSH.path`;
|
|
@@ -1642,17 +1623,8 @@ async function connectFlow(token, ideOpt, opts, skillImport, attempt) {
|
|
|
1642
1623
|
return;
|
|
1643
1624
|
}
|
|
1644
1625
|
}
|
|
1645
|
-
// Claude uses its built-in SSH client on Windows before OpenSSH 9.4; that client
|
|
1646
|
-
// cannot follow our generated ProxyCommand bastion route.
|
|
1647
|
-
if (ide === "claude" && process.platform === "win32") {
|
|
1648
|
-
const client = parseOpenSshVersion(sshBanner("ssh") ?? "");
|
|
1649
|
-
if (!client || client.major < 9 || (client.major === 9 && client.minor < 4)) {
|
|
1650
|
-
fatal("Claude Desktop needs Windows OpenSSH 9.4 or later for this workspace.", "Update Windows OpenSSH and Claude Desktop, then run this command again. You can also select Browser on the assessment page.", { severity: "warning" });
|
|
1651
|
-
return;
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
1626
|
attempt.stage("ssh_config");
|
|
1655
|
-
const alias = aliasFor(conn.ssh_hostname
|
|
1627
|
+
const alias = aliasFor(conn.ssh_hostname, token);
|
|
1656
1628
|
pruneStaleHostKeys(parsed);
|
|
1657
1629
|
const block = buildSshConfigBlock(alias, KEY_PATH, parsed);
|
|
1658
1630
|
const cfgPath = await writeSshConfig(alias, block, buildControlPathBlock(alias, parsed));
|
|
@@ -1668,7 +1640,7 @@ async function connectFlow(token, ideOpt, opts, skillImport, attempt) {
|
|
|
1668
1640
|
// Called per route, not here once: the native route runs it only AFTER the WSL check
|
|
1669
1641
|
// (Greptile on #2844), so a candidate whose Windows editor cannot see WSL's config is
|
|
1670
1642
|
// told that, rather than a generic ssh failure from the wrong side of the pairing.
|
|
1671
|
-
const sshExecutable = sshExecutableFor(
|
|
1643
|
+
const sshExecutable = sshExecutableFor(ide, ide === "ssh" ? null : readEditorSettings(ide));
|
|
1672
1644
|
const preflightStops = async (route) => {
|
|
1673
1645
|
// ENG-2895: up to two 45s attempts, so it gets a spinner; it says nothing when it works.
|
|
1674
1646
|
const checking = ora("Checking the connection to your workspace...").start();
|
|
@@ -1690,28 +1662,6 @@ async function connectFlow(token, ideOpt, opts, skillImport, attempt) {
|
|
|
1690
1662
|
});
|
|
1691
1663
|
return true;
|
|
1692
1664
|
};
|
|
1693
|
-
if (ide === "codex" || ide === "claude") {
|
|
1694
|
-
// Desktop apps use OpenSSH directly, not VS Code's remote.SSH.path setting.
|
|
1695
|
-
if (await preflightStops("ssh"))
|
|
1696
|
-
return;
|
|
1697
|
-
attempt.stage("ssh_preflight");
|
|
1698
|
-
const probe = sshProbeRunner(alias, sshExecutable)(desktopAppProbeCommand(ide));
|
|
1699
|
-
if (probe?.trim() !== "ready") {
|
|
1700
|
-
fatal(`The workspace is not ready for ${ide === "codex" ? "Codex App" : "Claude Desktop"}.`, "Return to the assessment page and reconnect. If this continues, contact Litmus support.", { severity: "error", internalDetail: `desktop_app=${ide} readiness=${probe === null ? "unreachable" : "missing-runtime-or-capture"}` });
|
|
1701
|
-
return;
|
|
1702
|
-
}
|
|
1703
|
-
attempt.stage("ssh_handoff");
|
|
1704
|
-
for (const line of desktopAppInstructions(ide, alias))
|
|
1705
|
-
console.log(line);
|
|
1706
|
-
if (ide === "claude") {
|
|
1707
|
-
const opened = await openBrowser(claudeDesktopUrl(alias));
|
|
1708
|
-
if (!opened)
|
|
1709
|
-
warn("Claude Desktop could not be opened. Copy the link above into your browser, or add the SSH host in the Code tab.");
|
|
1710
|
-
}
|
|
1711
|
-
// Readiness proves SSH/runtime/config, not an attached app or a captured turn.
|
|
1712
|
-
attempt.finish("ssh_ready");
|
|
1713
|
-
return;
|
|
1714
|
-
}
|
|
1715
1665
|
// SSH option: open the shell here (no editor launch). Without a terminal on both ends
|
|
1716
1666
|
// there is no one to hand a shell to, so a piped or scripted run gets the command.
|
|
1717
1667
|
if (ide === "ssh") {
|