litmus-cli 1.4.27 → 1.4.29
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 +4 -2
- package/dist/commands/connect.d.ts +349 -7
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +751 -58
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/doctor.d.ts +52 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +76 -7
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +30 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pause.d.ts +13 -8
- package/dist/commands/pause.d.ts.map +1 -1
- package/dist/commands/pause.js +18 -10
- package/dist/commands/pause.js.map +1 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +6 -2
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/submit.js +7 -4
- package/dist/commands/submit.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/ai-tracking.d.ts +19 -0
- package/dist/lib/ai-tracking.d.ts.map +1 -1
- package/dist/lib/ai-tracking.js +282 -1
- package/dist/lib/ai-tracking.js.map +1 -1
- package/dist/lib/api-base.d.ts +80 -0
- package/dist/lib/api-base.d.ts.map +1 -1
- package/dist/lib/api-base.js +83 -0
- package/dist/lib/api-base.js.map +1 -1
- package/dist/lib/editor-binary.d.ts +110 -0
- package/dist/lib/editor-binary.d.ts.map +1 -0
- package/dist/lib/editor-binary.js +72 -0
- package/dist/lib/editor-binary.js.map +1 -0
- package/dist/lib/editor-ide.d.ts +11 -0
- package/dist/lib/editor-ide.d.ts.map +1 -0
- package/dist/lib/editor-ide.js +2 -0
- package/dist/lib/editor-ide.js.map +1 -0
- package/dist/lib/editor-server.d.ts +253 -0
- package/dist/lib/editor-server.d.ts.map +1 -0
- package/dist/lib/editor-server.js +286 -0
- package/dist/lib/editor-server.js.map +1 -0
- package/dist/lib/watcher.js +18 -1
- package/dist/lib/watcher.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -100,8 +100,10 @@ in addition to the submission ZIP you upload at the end:
|
|
|
100
100
|
- Captured AI prompts and responses from Claude Code, Codex CLI, Cursor, the
|
|
101
101
|
Gemini CLI, and Copilot CLI via those tools' hooks. `litmus init` installs
|
|
102
102
|
the hooks and marks them trusted for the assessment folder (Codex's per-hook
|
|
103
|
-
trust, Gemini's and Copilot's folder trust),
|
|
104
|
-
|
|
103
|
+
trust, Gemini's and Copilot's folder trust), and records that one folder as
|
|
104
|
+
trusted in Claude Code (`~/.claude.json`) and Codex (`[projects]` in
|
|
105
|
+
`~/.codex/config.toml`), so no tool asks you to approve the hooks or the
|
|
106
|
+
folder; `litmus submit` removes the hooks and every trust entry again. Copilot
|
|
105
107
|
Chat (VS Code side panel) is not hookable and is not captured.
|
|
106
108
|
- A periodic codebase snapshot (every five minutes) so the optional
|
|
107
109
|
live-interview agent has up-to-date context. Snapshots are capped at 2 MB
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { NativeIde } from "../lib/editor-ide.js";
|
|
2
|
+
import { type EditorVersion, type SeedVerdict, type VerifyVerdict, type WorkspaceProbe } from "../lib/editor-server.js";
|
|
1
3
|
export interface ParsedSsh {
|
|
2
4
|
user: string;
|
|
3
5
|
host: string;
|
|
@@ -125,8 +127,9 @@ export declare function aliasFor(sshHostname: string | null | undefined, token:
|
|
|
125
127
|
*
|
|
126
128
|
* - `--version` CANNOT tell them apart. Both print exactly three lines — version,
|
|
127
129
|
* commit, arch — with no product name anywhere ("3.18.25" from the `code` that was
|
|
128
|
-
* Cursor). So `
|
|
129
|
-
* check, and the version numbers (1.x vs 3.x) are a
|
|
130
|
+
* Cursor). So `probeEditorCli`'s `--version` read is not merely unchecked as an
|
|
131
|
+
* identity, it has nothing to check, and the version numbers (1.x vs 3.x) are a
|
|
132
|
+
* coincidence, not a contract.
|
|
130
133
|
* - `--help` line 1 IS the product name: "Visual Studio Code 1.136.1" against
|
|
131
134
|
* "Cursor 3.18.25", on STDOUT (stderr empty), exit 0, no window, instant. It is
|
|
132
135
|
* `product.json`'s `nameLong`, which is why the patterns below are anchored prefixes
|
|
@@ -139,7 +142,7 @@ export declare function aliasFor(sshHostname: string | null | undefined, token:
|
|
|
139
142
|
* exit 0, mapping the Microsoft id onto its own `anysphere.remote-ssh`. So the dead
|
|
140
143
|
* remote window is version-dependent and the FALSE success line is not.
|
|
141
144
|
*/
|
|
142
|
-
export type NativeIde
|
|
145
|
+
export type { NativeIde } from "../lib/editor-ide.js";
|
|
143
146
|
export interface NativeEditor {
|
|
144
147
|
/** Which choice this record IS, so a record is self-describing once resolved. */
|
|
145
148
|
ide: NativeIde;
|
|
@@ -161,12 +164,64 @@ export interface NativeEditor {
|
|
|
161
164
|
remoteSshExt: string;
|
|
162
165
|
/** The palette command that puts `bin` on PATH, for the no-CLI fallback. */
|
|
163
166
|
shellCommand: string;
|
|
167
|
+
/**
|
|
168
|
+
* ENG-2332. The image's pointer at the server build it baked, and the directory in the
|
|
169
|
+
* candidate home that this editor's server lives in. Together they are what
|
|
170
|
+
* `lib/editor-server.ts` reads over the alias: the first answers "will this client find
|
|
171
|
+
* its own build already here", the second "did a server actually come up".
|
|
172
|
+
*/
|
|
173
|
+
seedCommitPath: string;
|
|
174
|
+
serverHomeDir: string;
|
|
175
|
+
/**
|
|
176
|
+
* ENG-2332 — whether a PROVEN commit mismatch refuses the launch, or only explains a
|
|
177
|
+
* launch that then failed.
|
|
178
|
+
*
|
|
179
|
+
* It is not symmetric, and the asymmetry is evidence rather than taste. A client whose
|
|
180
|
+
* build the image did not bake has exactly one route to its own server: the mirror
|
|
181
|
+
* (`infra/vscode-mirror/`), which the container reaches and the open internet it does
|
|
182
|
+
* not. VS Code's route is the original one and is validated end to end against both
|
|
183
|
+
* live origins; Cursor's has now failed twice in production — ENG-1936, where the one
|
|
184
|
+
* listed path shape had stopped being the one clients request, and ENG-2332, where a
|
|
185
|
+
* 3.19.13 client asked for nothing at all and opened a dead window.
|
|
186
|
+
*
|
|
187
|
+
* So for Cursor a mismatch is a refusal: the measured outcome is a window that looks
|
|
188
|
+
* normal, is served by a LOCAL extension host, and records nothing, which is the worst
|
|
189
|
+
* thing this product can do to a candidate. For VS Code it is a note kept back and used
|
|
190
|
+
* to explain a failed verification, because refusing there would take away a path that
|
|
191
|
+
* works today on the strength of a fault that has never been seen on it.
|
|
192
|
+
*
|
|
193
|
+
* This flips to `false` for Cursor the day the mirror is measured serving a drifted
|
|
194
|
+
* Cursor client — not before, and not on the strength of it looking like it should.
|
|
195
|
+
*/
|
|
196
|
+
requiresSeedMatch: boolean;
|
|
164
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* The two editors, and the one place every measured difference between them lives.
|
|
200
|
+
*
|
|
201
|
+
* EXPORTED so the tests drive the SHIPPED record rather than literals they wrote
|
|
202
|
+
* themselves — an assertion against a fixture declared in the test file is a tautology,
|
|
203
|
+
* and `requiresSeedMatch`, `seedCommitPath` and `serverHomeDir` could all have been
|
|
204
|
+
* changed here with every test staying green.
|
|
205
|
+
*
|
|
206
|
+
* `seedCommitPath` and `serverHomeDir` are CROSS-TIER and their drift is silent: the
|
|
207
|
+
* first is `CACHE_ROOT` in `infra/codespaces-v2-image/scripts/install-{vscode,cursor}-
|
|
208
|
+
* server.sh`, the second the home subdir `litmus-firstboot.sh`'s `prewarm_editor` links
|
|
209
|
+
* into. A probe pointed at a path the image no longer writes reads "no seed" and "no
|
|
210
|
+
* logs" — which this module deliberately treats as missing inputs, so the launch
|
|
211
|
+
* proceeds unrefused and the verification stops being able to see a server. Nothing
|
|
212
|
+
* fails; the guarantee just quietly stops existing. `backend/tests/
|
|
213
|
+
* test_editor_server_paths.py` holds the pair, in pytest rather than vitest because the
|
|
214
|
+
* CLI suite is path-filtered on `cli/**` and an image-only edit is exactly the edit that
|
|
215
|
+
* has to fail.
|
|
216
|
+
*/
|
|
217
|
+
export declare const NATIVE_EDITORS: Record<NativeIde, NativeEditor>;
|
|
165
218
|
/**
|
|
166
219
|
* ENG-2152 — what the editor CLI we are about to drive says it IS.
|
|
167
220
|
*
|
|
168
|
-
* `
|
|
169
|
-
*
|
|
221
|
+
* `resolveEditorCommand` above answers "which command can we run", which is a different
|
|
222
|
+
* and much weaker question — `probeEditorCli` establishes only that something at that
|
|
223
|
+
* name ran and printed a version — and treating either answer as an identity is the whole
|
|
224
|
+
* of this bug: the
|
|
170
225
|
* `code` on a Cursor user's PATH can be Cursor's own CLI, which is literally installed
|
|
171
226
|
* under that name inside `Cursor.app`. The measurement behind `banner` is in the
|
|
172
227
|
* `NATIVE_EDITORS` block comment; the three verdicts are what the caller may conclude.
|
|
@@ -198,7 +253,7 @@ export type EditorIdentity = {
|
|
|
198
253
|
export declare function identifyEditorBanner(helpOutput: string): NativeIde | null;
|
|
199
254
|
/** How the identity probe reaches the binary. Injected so the verdicts are testable. */
|
|
200
255
|
export type EditorHelpRunner = (bin: string) => string | null;
|
|
201
|
-
export declare function identifyEditorCli(ed: NativeEditor, run?: EditorHelpRunner): EditorIdentity;
|
|
256
|
+
export declare function identifyEditorCli(ed: NativeEditor, command: string, run?: EditorHelpRunner): EditorIdentity;
|
|
202
257
|
/**
|
|
203
258
|
* ENG-2152 — the refusal, when the command the candidate's PATH answers with is the
|
|
204
259
|
* other editor.
|
|
@@ -222,6 +277,284 @@ export declare function identifyEditorCli(ed: NativeEditor, run?: EditorHelpRunn
|
|
|
222
277
|
* this path is false.
|
|
223
278
|
*/
|
|
224
279
|
export declare function editorMismatchLines(chosen: NativeEditor, actual: NativeEditor, reentry?: CursorReentry): string[];
|
|
280
|
+
/**
|
|
281
|
+
* ENG-2332 — the refusal when the candidate's editor is a different build from the one
|
|
282
|
+
* this workspace has, and the route to the workspace that still works.
|
|
283
|
+
*
|
|
284
|
+
* It says what was compared and what it means, because "version mismatch" on its own
|
|
285
|
+
* reads as pedantry and a candidate mid-assessment will look for a way round it. What it
|
|
286
|
+
* must never do is offer one: there is no flag, no retry and no "open it anyway" here,
|
|
287
|
+
* since the thing on the other side of that door is a window that looks completely normal
|
|
288
|
+
* and records nothing (`lib/editor-server.ts` carries the measurement).
|
|
289
|
+
*
|
|
290
|
+
* The browser IDE leads, because it is the same container, the same files and the same
|
|
291
|
+
* capture, and it is the one route that cannot have this fault — it is served FROM the
|
|
292
|
+
* workspace rather than fetched INTO it. When the workspace publishes no URL the fallback
|
|
293
|
+
* is the terminal, which is a real way to work and not a consolation.
|
|
294
|
+
*/
|
|
295
|
+
export declare function editorSeedMismatchLines(ed: NativeEditor, verdict: Extract<SeedVerdict, {
|
|
296
|
+
kind: "mismatch";
|
|
297
|
+
}>, browserIdeUrl: string | null, alias: string): string[];
|
|
298
|
+
/**
|
|
299
|
+
* ENG-2332 — what to say when the editor CLI cannot be found anywhere.
|
|
300
|
+
*
|
|
301
|
+
* The line this replaces offered `<bin> --remote ssh-remote+<alias> …` as the
|
|
302
|
+
* remediation for `<bin>` not existing. Everything here is something the candidate can do
|
|
303
|
+
* WITHOUT that command: the editor's own Remote-SSH picker (the alias is already in their
|
|
304
|
+
* `~/.ssh/config`), the palette command that would put the CLI on PATH, and the browser
|
|
305
|
+
* IDE, which needs nothing installed at all.
|
|
306
|
+
*/
|
|
307
|
+
export declare function editorNotFoundLines(ed: NativeEditor, alias: string, browserIdeUrl: string | null): string[];
|
|
308
|
+
/**
|
|
309
|
+
* ENG-2332 — the positive signal, which the CLI had none of.
|
|
310
|
+
*
|
|
311
|
+
* It states exactly what was verified and not one step more. A server running in the
|
|
312
|
+
* workspace means the window is editing the container's files, so the file, terminal and
|
|
313
|
+
* commit lanes are live — that is what "recorded" may claim here.
|
|
314
|
+
*
|
|
315
|
+
* IT MAY NOT CLAIM AI CAPTURE ON CURSOR, and that is not hedging. Cursor reads its hooks
|
|
316
|
+
* configuration once, at application startup (ENG-1728, measured): a candidate who
|
|
317
|
+
* connected from an already-running Cursor has a live, correct, never-loaded hook, and
|
|
318
|
+
* their prompts are not recorded although everything else is. The verification above
|
|
319
|
+
* cannot see that — a server is up either way — so a flat "your work is being recorded"
|
|
320
|
+
* would be the same false reassurance this ticket is about, moved one lane along. The
|
|
321
|
+
* full notice is printed at selection time; this restates only the dependency.
|
|
322
|
+
*/
|
|
323
|
+
export declare function editorConnectedLines(ed: NativeEditor, alias: string): string[];
|
|
324
|
+
/**
|
|
325
|
+
* ENG-2332 — what to say when a window opened and no server came up in the workspace.
|
|
326
|
+
*
|
|
327
|
+
* This is the copy the ticket was opened about. It used to be
|
|
328
|
+
* "If a new window doesn't appear, run litmus connect again" — which is wrong twice: a
|
|
329
|
+
* window DOES appear in this failure, and re-running connect cannot change the state,
|
|
330
|
+
* which is exactly what had the reporter run it four times. So it names what was
|
|
331
|
+
* observed, and every route it offers is one this failure does not block.
|
|
332
|
+
*
|
|
333
|
+
* `seed` rides along because on VS Code a mismatch is not a refusal (see
|
|
334
|
+
* `requiresSeedMatch`) — so when a VS Code launch does fail, the build difference is the
|
|
335
|
+
* first thing worth knowing, and it is already in hand.
|
|
336
|
+
*
|
|
337
|
+
* WHAT IT MAY NOT SAY IS THAT NOTHING WILL CHANGE. That is what it said first, and it is
|
|
338
|
+
* a claim about the future made on a reading that stops at the verification budget. A VS
|
|
339
|
+
* Code client whose build the image did not bake is NOT refused (`requiresSeedMatch`), so
|
|
340
|
+
* its launch legitimately goes on to fetch a server through the mirror — a ~28.6 MB CLI
|
|
341
|
+
* and, on a prewarm miss, the whole bundle — and a slow link can still be fetching when
|
|
342
|
+
* the budget runs out. Telling that candidate their window is dead and pointing them
|
|
343
|
+
* elsewhere is the harm `unverified` exists to avoid, arriving on the branch below it.
|
|
344
|
+
* So it states the bound it actually waited (derived from `VERIFY_SCHEDULE_MS`, never a
|
|
345
|
+
* second hard-coded copy), says the window may yet attach, and offers the other two
|
|
346
|
+
* routes rather than instructing an exit. What it still may not do is tell them to re-run
|
|
347
|
+
* this command, which is the original bug.
|
|
348
|
+
*
|
|
349
|
+
* AND IT MAY NOT HAND THEM A CHECK THAT PASSES ON THE DEAD WINDOW. It pointed at the
|
|
350
|
+
* remote indicator — "the bottom-left corner reads SSH: <alias>" — and this repo has
|
|
351
|
+
* measured that indicator PRESENT in exactly the failure case: `lib/editor-server.ts`'s
|
|
352
|
+
* header records the never-attached window carrying `"remoteAuthority":
|
|
353
|
+
* "ssh-remote+<alias>"` and being indistinguishable from a working one, and
|
|
354
|
+
* `lib/session-end.ts` records (ENG-2154) that a window whose transport is gone still
|
|
355
|
+
* reads `[SSH: <host>]`. A candidate told to look at the corner sees what they were told
|
|
356
|
+
* to look for and goes on working unrecorded, which is this ticket's own bug re-entering
|
|
357
|
+
* through its remediation. The honest sentence is that the two windows look the same —
|
|
358
|
+
* that is WHY the CLI checks — so the copy says so and names no visual test at all.
|
|
359
|
+
*/
|
|
360
|
+
export declare function editorNotConnectedLines(ed: NativeEditor, alias: string, browserIdeUrl: string | null, seed: SeedVerdict, launchLog: string | null): string[];
|
|
361
|
+
/**
|
|
362
|
+
* ENG-2332 — what to say when the editor never started at all.
|
|
363
|
+
*
|
|
364
|
+
* THIS BRANCH EXISTS BECAUSE THE ONE ABOVE MUST NOT BE REACHABLE WITHOUT A WINDOW.
|
|
365
|
+
* `editorNotConnectedLines` opens by stating, as a fact, that a window is on screen and
|
|
366
|
+
* running against the candidate's own machine; when `spawn` itself fails that sentence is
|
|
367
|
+
* false, and the reading the verification produces is identical either way (no server,
|
|
368
|
+
* empty launch log). So the spawn error is recorded (`EditorLaunchHandle`) and routed
|
|
369
|
+
* here instead, where the only claim made is the one we can support.
|
|
370
|
+
*
|
|
371
|
+
* It offers the same two routes and, like every other failure branch, offers rather than
|
|
372
|
+
* instructs: there is no window to close, and re-running this command is the remediation
|
|
373
|
+
* the ticket was opened about. The error text is carried verbatim because it is the whole
|
|
374
|
+
* of what we know — `ENOENT` on a resolved path means the app moved or was removed since
|
|
375
|
+
* the `--version` probe a moment earlier, which is a thing the candidate can act on and
|
|
376
|
+
* we cannot diagnose for them.
|
|
377
|
+
*/
|
|
378
|
+
export declare function editorLaunchFailedLines(ed: NativeEditor, alias: string, browserIdeUrl: string | null, error: string, launchLog: string | null): string[];
|
|
379
|
+
/**
|
|
380
|
+
* ENG-2332 — what to say when we could not reach the workspace to ask at all.
|
|
381
|
+
*
|
|
382
|
+
* Three-valued on purpose: "we could not check" is not "nothing came up", and saying
|
|
383
|
+
* either of the other two here would be a claim we cannot make. It lives beside the other
|
|
384
|
+
* copy rather than inline in `runConnect` so that what it may and may not say is testable
|
|
385
|
+
* — it is bound by the same rule as `editorNotConnectedLines` and broke it the same way.
|
|
386
|
+
*
|
|
387
|
+
* It may NOT tell the candidate to look at the remote indicator. That indicator is
|
|
388
|
+
* rendered from the remote authority, which the never-attached window carries (see
|
|
389
|
+
* `lib/editor-server.ts`'s header, and ENG-2154 in `lib/session-end.ts`), so the check
|
|
390
|
+
* passes in exactly the case it was offered to detect. It states the ambiguity instead
|
|
391
|
+
* and offers the two routes that are not in doubt.
|
|
392
|
+
*/
|
|
393
|
+
export declare function editorUnverifiedLines(ed: NativeEditor, alias: string, browserIdeUrl: string | null): string[];
|
|
394
|
+
/**
|
|
395
|
+
* ENG-2332 — where the editor's own output goes.
|
|
396
|
+
*
|
|
397
|
+
* It used to go to `stdio: "ignore"`, which is the mechanical half of this ticket: a
|
|
398
|
+
* resolver that cannot fetch its server writes its reason here and nowhere else, so
|
|
399
|
+
* discarding it leaves exit code 0, an empty terminal and a dead window as the entire
|
|
400
|
+
* record of the failure.
|
|
401
|
+
*
|
|
402
|
+
* A FILE and not a pipe, and that is not a style choice. The child is `detached` and
|
|
403
|
+
* outlives this process by design; a pipe belongs to the parent, so once `litmus connect`
|
|
404
|
+
* returns the editor would be writing into a closed pipe and could take an EPIPE for it.
|
|
405
|
+
* A file descriptor on a real file has neither problem, survives our exit, and is still
|
|
406
|
+
* here when a candidate is asked for it.
|
|
407
|
+
*
|
|
408
|
+
* THE NAME IS PER RUN, and both reasons are real. `os.tmpdir()` is a shared `/tmp` on a
|
|
409
|
+
* Linux box with no `TMPDIR`, so a fixed name is a name another local user can create
|
|
410
|
+
* first — and `openSync(path, "w")` FOLLOWS a symlink and TRUNCATES, so a link planted
|
|
411
|
+
* there redirects the editor's output into, or empties, a file of theirs. And two
|
|
412
|
+
* `litmus connect` runs on one machine would otherwise share the file, so a candidate
|
|
413
|
+
* being walked through one failure can be shown the other run's output. The pid plus a
|
|
414
|
+
* random suffix answers both; `openEditorLaunchLog` then refuses to follow a link or to
|
|
415
|
+
* reuse an existing name, so an attacker who guesses one gets nothing rather than a
|
|
416
|
+
* write.
|
|
417
|
+
*/
|
|
418
|
+
export declare function editorLaunchLogPath(): string;
|
|
419
|
+
/**
|
|
420
|
+
* Open the launch log for the child, or answer null when we cannot do it safely.
|
|
421
|
+
*
|
|
422
|
+
* `O_EXCL | O_NOFOLLOW` is the whole point: EXCL means an existing name — planted or
|
|
423
|
+
* left over — is refused rather than written into, and NOFOLLOW means a symlink at that
|
|
424
|
+
* name is refused rather than followed to its target. Neither is reachable in the
|
|
425
|
+
* ordinary case, since the name carries a random suffix; they are what makes the
|
|
426
|
+
* ordinary case's safety a property of the open rather than of the name being unguessed.
|
|
427
|
+
* A refusal costs the diagnostics from one launch and never the launch.
|
|
428
|
+
*/
|
|
429
|
+
export declare function openEditorLaunchLog(logPath: string): number | null;
|
|
430
|
+
/**
|
|
431
|
+
* A launch in flight. The one thing it can say is whether the spawn itself failed.
|
|
432
|
+
*
|
|
433
|
+
* THAT IS THE ONLY SIGNAL SEPARATING "A WINDOW OPENED AND DID NOT ATTACH" FROM "NO
|
|
434
|
+
* WINDOW OPENED AT ALL", and it used to be thrown away. `child.on("error", () => {})`
|
|
435
|
+
* carried the comment "reported through the verification below", which was false: the
|
|
436
|
+
* verification reads the WORKSPACE, so all it can ever report is that no server came up
|
|
437
|
+
* — the same reading a spawn that never happened produces, down to the empty launch log.
|
|
438
|
+
* `editorNotConnectedLines` then told the candidate that "a <label> window is on screen
|
|
439
|
+
* and it is NOT attached to your workspace", and built a whole paragraph around a window
|
|
440
|
+
* that had never been created. That is the same class of unverifiable claim this ticket
|
|
441
|
+
* exists to remove, pointed the other way, so the error is recorded and the failure it
|
|
442
|
+
* describes gets its own outcome.
|
|
443
|
+
*
|
|
444
|
+
* It is a READER rather than a value because `spawn` reports this asynchronously: the
|
|
445
|
+
* error arrives on a later tick, so anything reading it must do so after an await. The
|
|
446
|
+
* handler itself still has to exist for the reason it always did — an unhandled `error`
|
|
447
|
+
* event on a ChildProcess is an uncaught exception that would take `connect` down.
|
|
448
|
+
*/
|
|
449
|
+
export interface EditorLaunchHandle {
|
|
450
|
+
launchFailure: () => string | null;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* ENG-2332, Greptile P1 on #2442 — ON WINDOWS THE `error` EVENT IS NOT THE FAILURE.
|
|
454
|
+
*
|
|
455
|
+
* `editorSpawnSpec` gives every Windows launch `shell: true`, so what `spawn` starts is
|
|
456
|
+
* `cmd.exe`, not the editor. `cmd.exe` starts fine essentially always — a missing `.cmd`,
|
|
457
|
+
* a path that stopped resolving, an editor that refuses its own argv are all reported by
|
|
458
|
+
* cmd.exe EXITING non-zero, not by an `error` event. So a handle watching only `error`
|
|
459
|
+
* reports "the window opened" for every one of them, which collapses the whole
|
|
460
|
+
* spawn-failed / opened-but-unattached distinction back into the wrong branch on exactly
|
|
461
|
+
* the platform the resolution work was added for.
|
|
462
|
+
*
|
|
463
|
+
* A NON-ZERO EXIT IS THEREFORE A LAUNCH FAILURE, and a zero exit is not. Both editors'
|
|
464
|
+
* CLIs return immediately after handing the argv to an already-running instance, so an
|
|
465
|
+
* ordinary successful launch exits 0 within moments and the process being gone says
|
|
466
|
+
* nothing. That asymmetry is what makes the exit code readable at all.
|
|
467
|
+
*
|
|
468
|
+
* The listeners outlive `unref()`: it stops the child holding the event loop open, and we
|
|
469
|
+
* are awaiting the verification anyway, so an exit inside the window still reaches us.
|
|
470
|
+
* Whichever signal arrives first wins and neither overwrites the other, because both
|
|
471
|
+
* describe the same thing — no window was created — and the first is the more specific.
|
|
472
|
+
*/
|
|
473
|
+
export declare function launchEditor(ed: NativeEditor, command: string, alias: string, logPath: string): EditorLaunchHandle;
|
|
474
|
+
/**
|
|
475
|
+
* Point at the editor's own output. `namePath` is for the branch where a human is
|
|
476
|
+
* walking a candidate through a failure: there the file is named whether or not
|
|
477
|
+
* `--verbose` was asked for, since `editorLaunchLogPath` gives it a per-run suffix that
|
|
478
|
+
* nobody can guess unaided.
|
|
479
|
+
*
|
|
480
|
+
* A PATH IS NAMED ONLY WHEN THERE IS SOMETHING AT IT, and the reason is that the file
|
|
481
|
+
* routinely does not exist. `launchEditor` falls back to `stdio: "ignore"` whenever
|
|
482
|
+
* `openEditorLaunchLog` refuses — an unwritable tmpdir, or its own `O_EXCL`/`O_NOFOLLOW`
|
|
483
|
+
* refusal — and even on the ordinary path the measured failure is an editor that exits 0
|
|
484
|
+
* and prints nothing, so an empty file is the common case rather than the odd one.
|
|
485
|
+
* Handing a support person a path with nothing behind it reads as the CLI having lost
|
|
486
|
+
* the log, which is a worse answer than saying plainly that the editor wrote nothing.
|
|
487
|
+
*/
|
|
488
|
+
export declare function editorLaunchOutputLines(logPath: string, launchLog: string | null, verbose: boolean, namePath: boolean): string[];
|
|
489
|
+
/**
|
|
490
|
+
* ENG-2332 — one reading of the workspace, over the alias we have just written.
|
|
491
|
+
*
|
|
492
|
+
* `BatchMode=yes` so a key that needs a passphrase, or a host key we somehow did not
|
|
493
|
+
* accept, fails in seconds instead of blocking the CLI on a prompt nobody is watching
|
|
494
|
+
* for. Every failure answers null, which every caller reads as "we could not tell" and
|
|
495
|
+
* never as "there is no server" — see `verifyVerdict`.
|
|
496
|
+
*/
|
|
497
|
+
export type WorkspaceProbeRunner = (remoteCommand: string) => string | null;
|
|
498
|
+
export declare function verifyEditorAttached(ed: NativeEditor, baseline: WorkspaceProbe | null, run: WorkspaceProbeRunner, onWait: (secondsWaited: number) => void, launched: EditorLaunchHandle): Promise<VerifyVerdict>;
|
|
499
|
+
/** Whether the editor's Remote-SSH extension was already there, put there, or could not be. */
|
|
500
|
+
export type RemoteSshExtensionState = "present" | "installed" | "failed";
|
|
501
|
+
/**
|
|
502
|
+
* ENG-2332 — the launch sequence itself, with every side effect injected.
|
|
503
|
+
*
|
|
504
|
+
* It exists as a unit because the ORDER is the guarantee, and order is not something the
|
|
505
|
+
* pieces can hold on their own: `seedVerdict` and `verifyVerdict` are each correct in
|
|
506
|
+
* isolation while a flow that installs an extension before the refusal, or takes its
|
|
507
|
+
* baseline after the spawn, or prints a success between the two, is the bug back. Those
|
|
508
|
+
* were first held by reading `connect.ts` and matching strings in it, which goes green
|
|
509
|
+
* for the wrong reasons — a rename breaks it and a genuinely reordered flow can still
|
|
510
|
+
* satisfy it. Here they are properties of what this function DOES, so the test drives it
|
|
511
|
+
* with recording doubles and reads the calls off them.
|
|
512
|
+
*
|
|
513
|
+
* Four things are therefore structural rather than conventional. A refused mismatch
|
|
514
|
+
* returns before `ensureExtension` or `launch` is reached, so "nothing was opened" is
|
|
515
|
+
* observable. `baseline` is taken from the probe before `launch` is called, so the
|
|
516
|
+
* verification is always comparing against a reading older than the spawn. The only
|
|
517
|
+
* success this can report is the one `verifyAttached` answered with, so there is no seam
|
|
518
|
+
* between the spawn and the verdict for a premature claim to live in — the caller renders
|
|
519
|
+
* `result.verdict` and has nothing else to render. And a spawn that FAILED returns its
|
|
520
|
+
* own `launch-failed` kind, which carries no `verdict` at all: the copy describing a
|
|
521
|
+
* window on screen is then unreachable by construction rather than by the caller
|
|
522
|
+
* remembering to check, which is what `EditorLaunchHandle` above exists for.
|
|
523
|
+
*/
|
|
524
|
+
export interface EditorLaunchIo {
|
|
525
|
+
/** One reading of the workspace, for the seed check and as the verification's baseline. */
|
|
526
|
+
probe: (ed: NativeEditor) => WorkspaceProbe | null;
|
|
527
|
+
/** What the client says it is. Already in hand from the resolution — see `resolveEditorCommand`. */
|
|
528
|
+
clientVersion: EditorVersion;
|
|
529
|
+
ensureExtension: () => RemoteSshExtensionState;
|
|
530
|
+
/** A fresh, per-run path for the editor's own output. */
|
|
531
|
+
launchLogPath: () => string;
|
|
532
|
+
launch: (logPath: string) => EditorLaunchHandle;
|
|
533
|
+
readLaunchLog: (logPath: string) => string | null;
|
|
534
|
+
verifyAttached: (baseline: WorkspaceProbe | null, launched: EditorLaunchHandle) => Promise<VerifyVerdict>;
|
|
535
|
+
}
|
|
536
|
+
export type EditorLaunchResult = {
|
|
537
|
+
kind: "refused";
|
|
538
|
+
reason: "seed-mismatch";
|
|
539
|
+
seed: Extract<SeedVerdict, {
|
|
540
|
+
kind: "mismatch";
|
|
541
|
+
}>;
|
|
542
|
+
} | {
|
|
543
|
+
kind: "launch-failed";
|
|
544
|
+
seed: SeedVerdict;
|
|
545
|
+
extension: RemoteSshExtensionState;
|
|
546
|
+
error: string;
|
|
547
|
+
logPath: string;
|
|
548
|
+
launchLog: string | null;
|
|
549
|
+
} | {
|
|
550
|
+
kind: "launched";
|
|
551
|
+
seed: SeedVerdict;
|
|
552
|
+
extension: RemoteSshExtensionState;
|
|
553
|
+
verdict: VerifyVerdict;
|
|
554
|
+
logPath: string;
|
|
555
|
+
launchLog: string | null;
|
|
556
|
+
};
|
|
557
|
+
export declare function attemptEditorLaunch(ed: NativeEditor, io: EditorLaunchIo): Promise<EditorLaunchResult>;
|
|
225
558
|
export type IdeChoice = "vscode" | "cursor" | "browser" | "ssh";
|
|
226
559
|
/**
|
|
227
560
|
* Resolve which editor to open: an explicit --ide flag wins; otherwise prompt.
|
|
@@ -392,5 +725,14 @@ export declare function chatConfigActionForIdentity(ide: IdeChoice, state: "conf
|
|
|
392
725
|
* branch it claims to describe.
|
|
393
726
|
*/
|
|
394
727
|
export declare function browserFallback(hasUrl: boolean, ideWasChosen: boolean): "browser" | "vscode" | "unavailable";
|
|
395
|
-
export
|
|
728
|
+
export interface ConnectOptions {
|
|
729
|
+
/**
|
|
730
|
+
* ENG-2332 item 4 — print what the editor wrote while opening, and where that log is.
|
|
731
|
+
* The output is CAPTURED either way (a failed verification prints its tail whether or
|
|
732
|
+
* not this is set); this is for the case where the candidate is being walked through a
|
|
733
|
+
* problem by a human and everything looks fine from here.
|
|
734
|
+
*/
|
|
735
|
+
verbose?: boolean;
|
|
736
|
+
}
|
|
737
|
+
export declare function runConnect(token: string, ideOpt?: string, opts?: ConnectOptions): Promise<void>;
|
|
396
738
|
//# sourceMappingURL=connect.d.ts.map
|
|
@@ -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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"}
|