litmus-cli 1.4.93 → 1.4.94
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 +48 -0
- package/dist/commands/connect.d.ts +6 -2
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +222 -35
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/forward.d.ts +7 -1
- package/dist/commands/forward.d.ts.map +1 -1
- package/dist/commands/forward.js +8 -7
- package/dist/commands/forward.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +12 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/lib/ai-tracking.d.ts +8 -0
- package/dist/lib/ai-tracking.d.ts.map +1 -1
- package/dist/lib/ai-tracking.js +79 -3
- package/dist/lib/ai-tracking.js.map +1 -1
- package/dist/lib/connect-skills.d.ts +1 -0
- package/dist/lib/connect-skills.d.ts.map +1 -1
- package/dist/lib/connect-skills.js +1 -1
- package/dist/lib/connect-skills.js.map +1 -1
- package/dist/lib/desktop-readiness.d.ts +9 -0
- package/dist/lib/desktop-readiness.d.ts.map +1 -0
- package/dist/lib/desktop-readiness.js +131 -0
- package/dist/lib/desktop-readiness.js.map +1 -0
- package/dist/lib/editor-foreground.d.ts +6 -0
- package/dist/lib/editor-foreground.d.ts.map +1 -0
- package/dist/lib/editor-foreground.js +38 -0
- package/dist/lib/editor-foreground.js.map +1 -0
- package/dist/lib/environment-checks.d.ts +2 -0
- package/dist/lib/environment-checks.d.ts.map +1 -1
- package/dist/lib/environment-checks.js +4 -2
- package/dist/lib/environment-checks.js.map +1 -1
- package/dist/lib/file-monitor.d.ts +18 -0
- package/dist/lib/file-monitor.d.ts.map +1 -0
- package/dist/lib/file-monitor.js +87 -0
- package/dist/lib/file-monitor.js.map +1 -0
- package/dist/lib/hosted-capture.d.ts +1 -1
- package/dist/lib/hosted-capture.d.ts.map +1 -1
- package/dist/lib/hosted-capture.js +22 -12
- package/dist/lib/hosted-capture.js.map +1 -1
- package/dist/lib/init-location.d.ts +4 -0
- package/dist/lib/init-location.d.ts.map +1 -0
- package/dist/lib/init-location.js +36 -0
- package/dist/lib/init-location.js.map +1 -0
- package/dist/lib/installed-tools.d.ts +29 -0
- package/dist/lib/installed-tools.d.ts.map +1 -0
- package/dist/lib/installed-tools.js +159 -0
- package/dist/lib/installed-tools.js.map +1 -0
- package/dist/lib/portal-launcher-background.d.ts +13 -0
- package/dist/lib/portal-launcher-background.d.ts.map +1 -0
- package/dist/lib/portal-launcher-background.js +51 -0
- package/dist/lib/portal-launcher-background.js.map +1 -0
- package/dist/lib/portal-launcher-worker.d.ts +2 -0
- package/dist/lib/portal-launcher-worker.d.ts.map +1 -0
- package/dist/lib/portal-launcher-worker.js +43 -0
- package/dist/lib/portal-launcher-worker.js.map +1 -0
- package/dist/lib/portal-launcher.d.ts +43 -0
- package/dist/lib/portal-launcher.d.ts.map +1 -0
- package/dist/lib/portal-launcher.js +408 -0
- package/dist/lib/portal-launcher.js.map +1 -0
- package/dist/lib/prepared-desktop.d.ts +7 -0
- package/dist/lib/prepared-desktop.d.ts.map +1 -0
- package/dist/lib/prepared-desktop.js +35 -0
- package/dist/lib/prepared-desktop.js.map +1 -0
- package/dist/lib/prepared-editor.d.ts +26 -0
- package/dist/lib/prepared-editor.d.ts.map +1 -0
- package/dist/lib/prepared-editor.js +150 -0
- package/dist/lib/prepared-editor.js.map +1 -0
- package/dist/lib/schemas.d.ts +1 -0
- package/dist/lib/schemas.d.ts.map +1 -1
- package/dist/lib/schemas.js +2 -0
- package/dist/lib/schemas.js.map +1 -1
- package/dist/lib/ssh-client.d.ts +12 -0
- 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/dist/lib/ssh-config-file.d.ts +3 -0
- package/dist/lib/ssh-config-file.d.ts.map +1 -1
- package/dist/lib/ssh-config-file.js +42 -0
- package/dist/lib/ssh-config-file.js.map +1 -1
- package/dist/lib/tracker.d.ts +1 -0
- package/dist/lib/tracker.d.ts.map +1 -1
- package/dist/lib/tracker.js +4 -2
- package/dist/lib/tracker.js.map +1 -1
- package/dist/lib/vscode-server-preparation.d.ts +7 -0
- package/dist/lib/vscode-server-preparation.d.ts.map +1 -0
- package/dist/lib/vscode-server-preparation.js +78 -0
- package/dist/lib/vscode-server-preparation.js.map +1 -0
- package/dist/lib/watcher.js +98 -77
- package/dist/lib/watcher.js.map +1 -1
- package/dist/lib/workspace-start-wait.d.ts +23 -0
- package/dist/lib/workspace-start-wait.d.ts.map +1 -0
- package/dist/lib/workspace-start-wait.js +50 -0
- package/dist/lib/workspace-start-wait.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/** Candidate-scoped, outbound-only launcher. No localhost listener or arbitrary commands. */
|
|
2
|
+
import { fetchSubmissionSaved } from "./api.js";
|
|
3
|
+
import { spawn, fork } from "child_process";
|
|
4
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { discoverInstalledTools } from "./installed-tools.js";
|
|
8
|
+
import { configSetsRemoteCommand } from "./ssh-client.js";
|
|
9
|
+
import { parsePreparedEditor, parseWorkspaceGeneration } from "./prepared-editor.js";
|
|
10
|
+
class LauncherRefusal extends Error {
|
|
11
|
+
constructor(status, readinessPending = false, code) {
|
|
12
|
+
super(`Launcher request refused (${status}). Re-run litmus connect to reconnect.`);
|
|
13
|
+
this.status = status;
|
|
14
|
+
this.readinessPending = readinessPending;
|
|
15
|
+
this.code = code;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function permanentLauncherFailure(error) {
|
|
19
|
+
return error instanceof LauncherRefusal && !error.readinessPending && error.status >= 400 && error.status < 500 && ![408, 429].includes(error.status);
|
|
20
|
+
}
|
|
21
|
+
export function desktopUrl(tool, alias) {
|
|
22
|
+
if (!/^litmus-[a-zA-Z0-9-]+$/.test(alias))
|
|
23
|
+
throw new Error("Invalid assessment SSH alias");
|
|
24
|
+
// `name` is the documented SSH-config alias parameter. Recent ChatGPT apps
|
|
25
|
+
// also accept projectPath/enabled; older ones may stop at SSH settings.
|
|
26
|
+
// Dispatch never proves that sign-in or remote project selection completed.
|
|
27
|
+
return tool === "codex"
|
|
28
|
+
? `codex://settings/connections/ssh/add?name=${encodeURIComponent(alias)}&projectPath=${encodeURIComponent("/home/candidate/workspace")}&enabled=true`
|
|
29
|
+
: `claude://code/new?ssh_host=${encodeURIComponent(alias)}&ssh_folder=${encodeURIComponent("/home/candidate/workspace")}`;
|
|
30
|
+
}
|
|
31
|
+
export function spawnDetached(command, args) {
|
|
32
|
+
return new Promise(resolve => {
|
|
33
|
+
const child = spawn(command, args, { detached: true, stdio: "ignore" });
|
|
34
|
+
child.once("error", () => resolve(false));
|
|
35
|
+
child.once("spawn", () => { child.unref(); resolve(true); });
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export function terminalRemoteCommand(requestId) {
|
|
39
|
+
if (requestId && !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(requestId))
|
|
40
|
+
throw new Error("Invalid launch request");
|
|
41
|
+
const wrapper = "/opt/litmus/bin/litmus-launcher-shell";
|
|
42
|
+
// Fixed remote adapter; old images keep their ordinary interactive shell.
|
|
43
|
+
return `if test -x ${wrapper}; then exec ${wrapper}${requestId ? ` ${requestId}` : ""}; else cd /home/candidate/workspace && exec bash -l; fi`;
|
|
44
|
+
}
|
|
45
|
+
export async function openTerminal(alias, terminal, requestId) {
|
|
46
|
+
if (!/^litmus-[a-zA-Z0-9-]+$/.test(alias))
|
|
47
|
+
return false;
|
|
48
|
+
const remote = terminalRemoteCommand(requestId);
|
|
49
|
+
const options = ["-t", "-o", "PermitLocalCommand=no"];
|
|
50
|
+
if (configSetsRemoteCommand(alias))
|
|
51
|
+
options.push("-o", "RemoteCommand=none");
|
|
52
|
+
if (process.platform === "darwin") {
|
|
53
|
+
const dir = path.join(os.homedir(), ".litmus", "launchers");
|
|
54
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
55
|
+
const file = path.join(dir, `${alias}.command`);
|
|
56
|
+
writeFileSync(file, `#!/bin/sh\nexec ssh ${options.join(" ")} ${alias} '${remote}'\n`, { mode: 0o700 });
|
|
57
|
+
return spawnDetached("/usr/bin/open", ["-a", terminal, file]);
|
|
58
|
+
}
|
|
59
|
+
if (process.platform === "win32")
|
|
60
|
+
return spawnDetached(terminal, ["new-tab", "ssh", ...options, alias, remote]);
|
|
61
|
+
const flag = terminal.endsWith("gnome-terminal") ? "--" : "-e";
|
|
62
|
+
return spawnDetached(terminal, [flag, "ssh", ...options, alias, remote]);
|
|
63
|
+
}
|
|
64
|
+
/** Isolate existing fatal/exit paths and synchronous probes from the heartbeat process. */
|
|
65
|
+
export function openNativeEditor(tool, token, signal, forkFn = fork, onPrepared, generation) {
|
|
66
|
+
return new Promise(resolve => {
|
|
67
|
+
let result = "action_required";
|
|
68
|
+
let prepared = null;
|
|
69
|
+
let announced = false;
|
|
70
|
+
const env = { ...process.env, LITMUS_ASSESSMENT_TOKEN: token, LITMUS_PORTAL_LAUNCHER_CHILD: "1" };
|
|
71
|
+
delete env.LITMUS_LAUNCH_GENERATION;
|
|
72
|
+
const currentGeneration = parseWorkspaceGeneration(generation);
|
|
73
|
+
if (currentGeneration)
|
|
74
|
+
env.LITMUS_LAUNCH_GENERATION = JSON.stringify(currentGeneration);
|
|
75
|
+
const child = forkFn(new URL("../index.js", import.meta.url), ["connect", "--ide", tool, "--no-skills"], {
|
|
76
|
+
execArgv: [], env,
|
|
77
|
+
stdio: ["ignore", "inherit", "inherit", "ipc"],
|
|
78
|
+
});
|
|
79
|
+
child.on("message", message => {
|
|
80
|
+
if (!message || typeof message !== "object")
|
|
81
|
+
return;
|
|
82
|
+
const value = message;
|
|
83
|
+
if (value.type === "litmus-connect-result" && value.result === "server_detected") {
|
|
84
|
+
result = "dispatched";
|
|
85
|
+
prepared = parsePreparedEditor(value.preparedEditor);
|
|
86
|
+
// The child has verified attachment. Reporting/cleanup can finish after
|
|
87
|
+
// the UI stops saying Launching; neither is part of opening the editor.
|
|
88
|
+
if (!announced) {
|
|
89
|
+
announced = true;
|
|
90
|
+
if (prepared?.tool === tool)
|
|
91
|
+
onPrepared?.(prepared);
|
|
92
|
+
resolve("dispatched");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
const stop = () => child.kill();
|
|
97
|
+
signal?.addEventListener("abort", stop, { once: true });
|
|
98
|
+
if (signal?.aborted)
|
|
99
|
+
stop();
|
|
100
|
+
const cleanup = () => { clearTimeout(timer); signal?.removeEventListener("abort", stop); };
|
|
101
|
+
const timer = setTimeout(() => { child.kill(); resolve("action_required"); }, 240000);
|
|
102
|
+
child.once("error", () => { cleanup(); resolve("action_required"); });
|
|
103
|
+
child.once("exit", code => {
|
|
104
|
+
cleanup();
|
|
105
|
+
if (!announced && code === 0 && result === "dispatched" && prepared?.tool === tool)
|
|
106
|
+
onPrepared?.(prepared);
|
|
107
|
+
resolve(code === 0 ? result : "action_required");
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
export async function startPortalPreparation(backendUrl, token) {
|
|
112
|
+
const noop = () => Object.assign(async () => { }, { update: (_stage) => { }, fail: (_reason) => { } });
|
|
113
|
+
const report = { tools: [], phase: "connecting" };
|
|
114
|
+
const request = async (route, key, method = "POST") => {
|
|
115
|
+
const response = await fetch(`${backendUrl}/workspace/launcher${route}`, {
|
|
116
|
+
method, redirect: "error", signal: AbortSignal.timeout(10000),
|
|
117
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json",
|
|
118
|
+
...(key ? { "X-Litmus-Launcher-Key": key } : {}) },
|
|
119
|
+
...(method === "DELETE" ? {} : { body: JSON.stringify(report) }),
|
|
120
|
+
});
|
|
121
|
+
if (!response.ok)
|
|
122
|
+
throw new LauncherRefusal(response.status);
|
|
123
|
+
return response;
|
|
124
|
+
};
|
|
125
|
+
let session;
|
|
126
|
+
try {
|
|
127
|
+
const value = await (await request("/sessions")).json();
|
|
128
|
+
if (!value || typeof value.session_id !== "string" || typeof value.key !== "string")
|
|
129
|
+
return noop();
|
|
130
|
+
session = { session_id: value.session_id, key: value.key, progress_updates: value.progress_updates === true };
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return noop();
|
|
134
|
+
}
|
|
135
|
+
let stopped = false;
|
|
136
|
+
let pending = Promise.resolve();
|
|
137
|
+
const beat = () => {
|
|
138
|
+
pending = request(`/sessions/${session.session_id}/poll`, session.key)
|
|
139
|
+
.then(() => { }, () => { })
|
|
140
|
+
.finally(() => { if (!stopped)
|
|
141
|
+
timer = setTimeout(beat, 5000); });
|
|
142
|
+
};
|
|
143
|
+
let timer = setTimeout(beat, 5000);
|
|
144
|
+
return Object.assign(async () => {
|
|
145
|
+
stopped = true;
|
|
146
|
+
clearTimeout(timer);
|
|
147
|
+
await pending;
|
|
148
|
+
if (report.stage === "failed") {
|
|
149
|
+
// Leave the fixed failure visible for the remaining short session lease.
|
|
150
|
+
await request(`/sessions/${session.session_id}/poll`, session.key).catch(() => { });
|
|
151
|
+
}
|
|
152
|
+
else
|
|
153
|
+
await request(`/sessions/${session.session_id}`, session.key, "DELETE").catch(() => { });
|
|
154
|
+
}, {
|
|
155
|
+
update: (stage) => { if (session.progress_updates && report.stage !== "failed")
|
|
156
|
+
report.stage = stage; },
|
|
157
|
+
fail: (reason) => {
|
|
158
|
+
if (session.progress_updates && report.stage !== "failed") {
|
|
159
|
+
report.stage = "failed";
|
|
160
|
+
report.failure = reason;
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
export async function runPortalLauncher(options) {
|
|
166
|
+
const abort = new AbortController();
|
|
167
|
+
const stop = () => abort.abort();
|
|
168
|
+
options.signal?.addEventListener("abort", stop, { once: true });
|
|
169
|
+
if (options.signal?.aborted)
|
|
170
|
+
stop();
|
|
171
|
+
process.once("SIGINT", stop);
|
|
172
|
+
process.once("SIGTERM", stop);
|
|
173
|
+
let session = null;
|
|
174
|
+
let installed = discoverInstalledTools();
|
|
175
|
+
let lastDiscovery = Date.now();
|
|
176
|
+
let inventory = JSON.stringify(installed);
|
|
177
|
+
let changedInventory;
|
|
178
|
+
let inventoryPoll;
|
|
179
|
+
// Local discovery stays independent of the idle server long poll.
|
|
180
|
+
const discoveryTimer = setInterval(() => {
|
|
181
|
+
const next = discoverInstalledTools();
|
|
182
|
+
const signature = JSON.stringify(next);
|
|
183
|
+
if (signature !== inventory) {
|
|
184
|
+
inventory = signature;
|
|
185
|
+
changedInventory = next;
|
|
186
|
+
inventoryPoll?.abort();
|
|
187
|
+
}
|
|
188
|
+
}, 5000);
|
|
189
|
+
let seenCommandId = null;
|
|
190
|
+
let longPoll = false;
|
|
191
|
+
let readinessSupported = false;
|
|
192
|
+
let desktopConnectionSetupSupported = false;
|
|
193
|
+
const toolIds = () => [...installed.filter(i => !i.unavailable).map(i => i.tool), ...(options.browserAvailable ? ["browser"] : [])];
|
|
194
|
+
const unavailableTools = () => Object.fromEntries(installed.filter(i => i.unavailable).map(i => [i.tool, i.unavailable === "desktop_setup_failed" && !desktopConnectionSetupSupported ? "workspace_not_ready" : i.unavailable]));
|
|
195
|
+
async function call(route, body, method = "POST", polling = false) {
|
|
196
|
+
const response = await fetch(`${options.backendUrl}/workspace/launcher${route}`, {
|
|
197
|
+
method, headers: { Authorization: `Bearer ${options.token}`, "Content-Type": "application/json",
|
|
198
|
+
...(session ? { "X-Litmus-Launcher-Key": session.key } : {}) },
|
|
199
|
+
...(body === undefined ? {} : { body: JSON.stringify(body) }), signal: polling ? AbortSignal.any([abort.signal, inventoryPoll.signal, AbortSignal.timeout(35000)]) : AbortSignal.timeout(10000),
|
|
200
|
+
redirect: "error",
|
|
201
|
+
});
|
|
202
|
+
if (!response.ok) {
|
|
203
|
+
// Only the server's fixed health-pending refusal is recoverable. A
|
|
204
|
+
// replaced/revoked session can also be 409 and must still stop here.
|
|
205
|
+
const detail = [403, 409].includes(response.status) ? await response.json().catch(() => null) : null;
|
|
206
|
+
throw new LauncherRefusal(response.status, detail?.detail?.code === "workspace_not_ready", detail?.detail?.code);
|
|
207
|
+
}
|
|
208
|
+
return await response.json();
|
|
209
|
+
}
|
|
210
|
+
const wait = options.wait ?? ((ms, signal) => new Promise(resolve => {
|
|
211
|
+
const done = () => { clearTimeout(timer); signal.removeEventListener("abort", done); resolve(); };
|
|
212
|
+
const timer = setTimeout(done, ms);
|
|
213
|
+
signal.addEventListener("abort", done, { once: true });
|
|
214
|
+
if (signal.aborted)
|
|
215
|
+
done();
|
|
216
|
+
}));
|
|
217
|
+
try {
|
|
218
|
+
let registered;
|
|
219
|
+
try {
|
|
220
|
+
registered = await call("/sessions", { tools: [], phase: "connecting" });
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
if (!(error instanceof LauncherRefusal) || !([404, 405].includes(error.status) || (error.status === 403 && error.code === "launcher_beta_unavailable")))
|
|
224
|
+
throw error;
|
|
225
|
+
// CLI and backend releases are independent. The prepared SSH alias is
|
|
226
|
+
// usable even when the backend predates the portal launcher.
|
|
227
|
+
console.log("Tool launching is unavailable on this deployment. Open your assessment page or connect directly:");
|
|
228
|
+
console.log(` ${options.pageUrl}\n ssh ${options.alias}`);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
session = registered;
|
|
232
|
+
readinessSupported = registered.tool_readiness === true;
|
|
233
|
+
desktopConnectionSetupSupported = registered.desktop_connection_setup === true;
|
|
234
|
+
if (options.prepareTools && registered.progress_updates) {
|
|
235
|
+
await call(`/sessions/${session.session_id}/poll`, { tools: [], phase: "connecting", stage: "checking_tools" }).catch(() => { });
|
|
236
|
+
}
|
|
237
|
+
if (options.prepareTools) {
|
|
238
|
+
// Preparing a matching editor server may outlast the initial mailbox
|
|
239
|
+
// lease. Renew as connecting, without claiming readiness or starting time.
|
|
240
|
+
// Drain any in-flight renewal before the first ready poll, so a delayed
|
|
241
|
+
// response cannot put a connected laptop back into preparation.
|
|
242
|
+
let preparationEnded = false;
|
|
243
|
+
let pendingRenewal;
|
|
244
|
+
let renewalTimer;
|
|
245
|
+
const renewPreparation = () => {
|
|
246
|
+
if (preparationEnded || abort.signal.aborted)
|
|
247
|
+
return;
|
|
248
|
+
pendingRenewal = call(`/sessions/${session.session_id}/poll`, {
|
|
249
|
+
tools: [], phase: "connecting", ...(registered.progress_updates ? { stage: "checking_tools" } : {}),
|
|
250
|
+
}).then(() => { }, () => { }).finally(() => {
|
|
251
|
+
if (!preparationEnded && !abort.signal.aborted)
|
|
252
|
+
renewalTimer = setTimeout(renewPreparation, 15000);
|
|
253
|
+
});
|
|
254
|
+
};
|
|
255
|
+
renewalTimer = setTimeout(renewPreparation, 15000);
|
|
256
|
+
try {
|
|
257
|
+
installed = await options.prepareTools(installed, abort.signal);
|
|
258
|
+
}
|
|
259
|
+
finally {
|
|
260
|
+
preparationEnded = true;
|
|
261
|
+
clearTimeout(renewalTimer);
|
|
262
|
+
await pendingRenewal;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
lastDiscovery = Date.now();
|
|
266
|
+
if (abort.signal.aborted)
|
|
267
|
+
return;
|
|
268
|
+
let readyAcknowledged = false;
|
|
269
|
+
// The healthy host report can trail a working SSH connection by 60s.
|
|
270
|
+
let readinessDeadline = Date.now() + 120000;
|
|
271
|
+
let readinessFailures = 0;
|
|
272
|
+
let failures = 0;
|
|
273
|
+
const seenCommands = new Set();
|
|
274
|
+
while (!abort.signal.aborted) {
|
|
275
|
+
if (changedInventory || Date.now() - lastDiscovery >= 30000) {
|
|
276
|
+
installed = changedInventory ?? discoverInstalledTools();
|
|
277
|
+
changedInventory = undefined;
|
|
278
|
+
if (options.prepareTools)
|
|
279
|
+
installed = await options.prepareTools(installed, abort.signal);
|
|
280
|
+
lastDiscovery = Date.now();
|
|
281
|
+
}
|
|
282
|
+
let command;
|
|
283
|
+
try {
|
|
284
|
+
// End the wait in time for the next installation inventory refresh.
|
|
285
|
+
const waitSeconds = Math.min(25, Math.max(1, Math.ceil((30000 - (Date.now() - lastDiscovery)) / 1000)));
|
|
286
|
+
const query = new URLSearchParams({ wait_seconds: String(readyAcknowledged ? waitSeconds : 0) });
|
|
287
|
+
if (seenCommandId)
|
|
288
|
+
query.set("seen_command_id", seenCommandId);
|
|
289
|
+
inventoryPoll = new AbortController();
|
|
290
|
+
const reply = await call(`/sessions/${registered.session_id}/poll?${query}`, { tools: toolIds(), phase: "ready", ...(readinessSupported ? { unavailable: unavailableTools() } : {}) }, "POST", true);
|
|
291
|
+
longPoll = reply.long_poll === true;
|
|
292
|
+
command = reply.command;
|
|
293
|
+
failures = 0;
|
|
294
|
+
readinessFailures = 0;
|
|
295
|
+
readinessDeadline = 0;
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
if (abort.signal.aborted)
|
|
299
|
+
break;
|
|
300
|
+
if (inventoryPoll?.signal.aborted && changedInventory)
|
|
301
|
+
continue;
|
|
302
|
+
if (error instanceof LauncherRefusal && error.readinessPending) {
|
|
303
|
+
// A later host-report gap gets its own bounded recovery window;
|
|
304
|
+
// it must not disconnect an already acknowledged laptop after five polls.
|
|
305
|
+
if (!readinessDeadline)
|
|
306
|
+
readinessDeadline = Date.now() + 120000;
|
|
307
|
+
const remaining = readinessDeadline - Date.now();
|
|
308
|
+
if (remaining <= 0)
|
|
309
|
+
throw error;
|
|
310
|
+
// Health-pending responses renew the authenticated session lease;
|
|
311
|
+
// they do not spend the separate transport failure allowance.
|
|
312
|
+
await wait(Math.min(++readinessFailures * 2000, 10000, remaining), abort.signal);
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
// Do not re-register: replacing a session could replay an uncertain launch.
|
|
316
|
+
if (permanentLauncherFailure(error) || ++failures > 5)
|
|
317
|
+
throw error;
|
|
318
|
+
await wait(Math.min(failures * 2000, 10000), abort.signal);
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if (abort.signal.aborted)
|
|
322
|
+
break;
|
|
323
|
+
if (!readyAcknowledged) {
|
|
324
|
+
// Registration/preparation is not readiness. Publish success (including
|
|
325
|
+
// daemon handoff) only after the authenticated ready poll is accepted.
|
|
326
|
+
readyAcknowledged = true;
|
|
327
|
+
console.log("\nYour tool launcher is ready. Open tools from your assessment page.");
|
|
328
|
+
console.log(` ${options.pageUrl}`);
|
|
329
|
+
options.onReady?.();
|
|
330
|
+
await options.openUrl(options.pageUrl);
|
|
331
|
+
}
|
|
332
|
+
if (command && !seenCommands.has(command.id)) {
|
|
333
|
+
// A poll can redeliver an opening command after its response was lost.
|
|
334
|
+
// Record before launching, including while result delivery retries.
|
|
335
|
+
seenCommands.add(command.id);
|
|
336
|
+
seenCommandId = command.id;
|
|
337
|
+
void (async () => {
|
|
338
|
+
let status = "failed";
|
|
339
|
+
if (toolIds().includes(command.tool)) {
|
|
340
|
+
try {
|
|
341
|
+
status = await options.launch(command.tool, installed, abort.signal, { requestId: command.id, ...(command.generation ? { generation: command.generation } : {}) });
|
|
342
|
+
}
|
|
343
|
+
catch { /* fixed failure */ }
|
|
344
|
+
}
|
|
345
|
+
if (abort.signal.aborted)
|
|
346
|
+
return;
|
|
347
|
+
// Deliver the same result again after transport errors; never execute
|
|
348
|
+
// the tool again merely because its acknowledgement was lost.
|
|
349
|
+
// Polling owns the session's lifetime. Cap the delay, not attempts:
|
|
350
|
+
// retain the result until acknowledged, permanently refused or stopped.
|
|
351
|
+
for (let attempt = 0; !abort.signal.aborted; attempt++) {
|
|
352
|
+
try {
|
|
353
|
+
await call(`/sessions/${registered.session_id}/results/${command.id}`, { status });
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
if (permanentLauncherFailure(error)) {
|
|
358
|
+
console.error("Launch result could not be delivered. Check the tool before opening it again.");
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
await wait(Math.min((attempt + 1) * 2000, 10000), abort.signal);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
})();
|
|
365
|
+
}
|
|
366
|
+
// Old backends ignore the query parameters. Preserve their polling rate.
|
|
367
|
+
if (!longPoll)
|
|
368
|
+
await wait(5000, abort.signal);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
finally {
|
|
372
|
+
clearInterval(discoveryTimer);
|
|
373
|
+
abort.abort();
|
|
374
|
+
if (session)
|
|
375
|
+
await call(`/sessions/${session.session_id}`, undefined, "DELETE").catch(() => { });
|
|
376
|
+
options.signal?.removeEventListener("abort", stop);
|
|
377
|
+
process.off("SIGINT", stop);
|
|
378
|
+
process.off("SIGTERM", stop);
|
|
379
|
+
// Session replacement, auth failures and offline time are not submission.
|
|
380
|
+
// Only a positive server acknowledgement permits local connection cleanup.
|
|
381
|
+
if (session && options.onSubmitted) {
|
|
382
|
+
try {
|
|
383
|
+
if (await fetchSubmissionSaved(options.backendUrl, options.token, 5000))
|
|
384
|
+
await options.onSubmitted();
|
|
385
|
+
}
|
|
386
|
+
catch { /* Leave settings intact when submission cannot be verified. */ }
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
/** Observe the OS opener's exit status; spawning it alone does not prove dispatch. */
|
|
391
|
+
export function openDesktop(app, alias, signal, platform = process.platform, spawnFn = spawn) {
|
|
392
|
+
if (app.tool !== "codex" && app.tool !== "claude")
|
|
393
|
+
return Promise.resolve(false);
|
|
394
|
+
const url = desktopUrl(app.tool, alias);
|
|
395
|
+
const command = platform === "darwin" ? "/usr/bin/open" : platform === "win32" ? "rundll32.exe" : "xdg-open";
|
|
396
|
+
const args = platform === "darwin" ? ["-a", app.command, url] : platform === "win32" ? ["url.dll,FileProtocolHandler", url] : [url];
|
|
397
|
+
return new Promise(resolve => {
|
|
398
|
+
try {
|
|
399
|
+
const child = spawnFn(command, args, { stdio: "ignore", windowsHide: true, signal, timeout: 10000 });
|
|
400
|
+
child.once("error", () => resolve(false));
|
|
401
|
+
child.once("exit", code => resolve(code === 0));
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
resolve(false);
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
//# sourceMappingURL=portal-launcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal-launcher.js","sourceRoot":"","sources":["../../src/lib/portal-launcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { desktopRuntimeReady, type DesktopApp } from "./desktop-readiness.js";
|
|
2
|
+
/** A short-lived capability result, never a replacement for mailbox authorization. */
|
|
3
|
+
export declare function createPreparedDesktopReadiness(alias: string, probe?: typeof desktopRuntimeReady, now?: () => number, maxAgeMs?: number): {
|
|
4
|
+
invalidate(): void;
|
|
5
|
+
check(app: DesktopApp, command: string, generationValue: unknown, signal: AbortSignal): Promise<boolean>;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=prepared-desktop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepared-desktop.d.ts","sourceRoot":"","sources":["../../src/lib/prepared-desktop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAG7E,sFAAsF;AACtF,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,EACb,KAAK,6BAAsB,EAC3B,GAAG,eAAW,EACd,QAAQ,SAAS;IAMf,UAAU;IACJ,KAAK,MAAM,UAAU,WAAW,MAAM,mBAAmB,OAAO,UAAU,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;EAgBjH"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { desktopRuntimeReady } from "./desktop-readiness.js";
|
|
2
|
+
import { parseWorkspaceGeneration } from "./prepared-editor.js";
|
|
3
|
+
/** A short-lived capability result, never a replacement for mailbox authorization. */
|
|
4
|
+
export function createPreparedDesktopReadiness(alias, probe = desktopRuntimeReady, now = Date.now, maxAgeMs = 30000) {
|
|
5
|
+
let scope = null;
|
|
6
|
+
let revision = 0;
|
|
7
|
+
const ready = new Map();
|
|
8
|
+
return {
|
|
9
|
+
invalidate() { revision++; scope = null; ready.clear(); },
|
|
10
|
+
async check(app, command, generationValue, signal) {
|
|
11
|
+
const generation = parseWorkspaceGeneration(generationValue);
|
|
12
|
+
const nextScope = generation ? JSON.stringify(generation) : null;
|
|
13
|
+
if (!nextScope || scope !== nextScope) {
|
|
14
|
+
revision++;
|
|
15
|
+
ready.clear();
|
|
16
|
+
scope = nextScope;
|
|
17
|
+
}
|
|
18
|
+
if (signal.aborted)
|
|
19
|
+
return false;
|
|
20
|
+
const key = JSON.stringify([app, command]);
|
|
21
|
+
const checkedAt = ready.get(key);
|
|
22
|
+
if (nextScope && checkedAt !== undefined && now() - checkedAt >= 0 && now() - checkedAt < maxAgeMs)
|
|
23
|
+
return true;
|
|
24
|
+
ready.delete(key);
|
|
25
|
+
const startedRevision = revision;
|
|
26
|
+
const ok = await probe(alias, app, signal);
|
|
27
|
+
if (signal.aborted || scope !== nextScope || startedRevision !== revision)
|
|
28
|
+
return false;
|
|
29
|
+
if (ok && nextScope)
|
|
30
|
+
ready.set(key, now());
|
|
31
|
+
return ok;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=prepared-desktop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepared-desktop.js","sourceRoot":"","sources":["../../src/lib/prepared-desktop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAmB,MAAM,wBAAwB,CAAA;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAE/D,sFAAsF;AACtF,MAAM,UAAU,8BAA8B,CAC5C,KAAa,EACb,KAAK,GAAG,mBAAmB,EAC3B,GAAG,GAAG,IAAI,CAAC,GAAG,EACd,QAAQ,GAAG,KAAM;IAEjB,IAAI,KAAK,GAAkB,IAAI,CAAA;IAC/B,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAA;IACvC,OAAO;QACL,UAAU,KAAK,QAAQ,EAAE,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA,CAAC,CAAC;QACxD,KAAK,CAAC,KAAK,CAAC,GAAe,EAAE,OAAe,EAAE,eAAwB,EAAE,MAAmB;YACzF,MAAM,UAAU,GAAG,wBAAwB,CAAC,eAAe,CAAC,CAAA;YAC5D,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;YAChE,IAAI,CAAC,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBAAC,QAAQ,EAAE,CAAC;gBAAC,KAAK,CAAC,KAAK,EAAE,CAAC;gBAAC,KAAK,GAAG,SAAS,CAAA;YAAC,CAAC;YACvF,IAAI,MAAM,CAAC,OAAO;gBAAE,OAAO,KAAK,CAAA;YAChC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAA;YAC1C,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAChC,IAAI,SAAS,IAAI,SAAS,KAAK,SAAS,IAAI,GAAG,EAAE,GAAG,SAAS,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,SAAS,GAAG,QAAQ;gBAAE,OAAO,IAAI,CAAA;YAC/G,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACjB,MAAM,eAAe,GAAG,QAAQ,CAAA;YAChC,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;YAC1C,IAAI,MAAM,CAAC,OAAO,IAAI,KAAK,KAAK,SAAS,IAAI,eAAe,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAA;YACvF,IAAI,EAAE,IAAI,SAAS;gBAAE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;YAC1C,OAAO,EAAE,CAAA;QACX,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { LaunchResult } from "./portal-launcher.js";
|
|
2
|
+
export interface WorkspaceGeneration {
|
|
3
|
+
epoch: number;
|
|
4
|
+
container_id: string;
|
|
5
|
+
}
|
|
6
|
+
export interface PreparedEditor {
|
|
7
|
+
tool: "vscode" | "cursor";
|
|
8
|
+
command: string;
|
|
9
|
+
commit: string;
|
|
10
|
+
alias: string;
|
|
11
|
+
generation: WorkspaceGeneration;
|
|
12
|
+
}
|
|
13
|
+
export declare function parseWorkspaceGeneration(value: unknown): WorkspaceGeneration | null;
|
|
14
|
+
export declare function parsePreparedEditor(value: unknown): PreparedEditor | null;
|
|
15
|
+
export declare function preparedEditorArgs(editor: PreparedEditor, platform?: NodeJS.Platform): string[];
|
|
16
|
+
export interface PreparedEditorIo {
|
|
17
|
+
canReuse?(editor: PreparedEditor, signal?: AbortSignal): Promise<boolean>;
|
|
18
|
+
currentCommit(editor: PreparedEditor, signal?: AbortSignal): Promise<string | null>;
|
|
19
|
+
dispatch(editor: PreparedEditor, signal?: AbortSignal): Promise<boolean>;
|
|
20
|
+
}
|
|
21
|
+
/** Only call from an authenticated mailbox command, never from a browser URL. */
|
|
22
|
+
export declare function createPreparedEditorLauncher(alias: string, io?: PreparedEditorIo): {
|
|
23
|
+
invalidate: () => void;
|
|
24
|
+
launch(tool: PreparedEditor["tool"], generationValue: unknown, fullLaunch: (remember: (value: unknown) => void) => Promise<LaunchResult>, signal?: AbortSignal): Promise<LaunchResult>;
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=prepared-editor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepared-editor.d.ts","sourceRoot":"","sources":["../../src/lib/prepared-editor.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAExD,MAAM,WAAW,mBAAmB;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE;AAC5E,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,mBAAmB,CAAA;CAChC;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAKnF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CASzE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,kBAAmB,GAAG,MAAM,EAAE,CAIhG;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACzE,aAAa,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IACnF,QAAQ,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACzE;AAsDD,iFAAiF;AACjF,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAE,gBAA4B;;iBAMrE,cAAc,CAAC,MAAM,CAAC,mBAAmB,OAAO,cACrD,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,KAAK,OAAO,CAAC,YAAY,CAAC,WAAW,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;EA8B5H"}
|