kaizenai 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/bin/kaizen +49 -9
- package/dist/client/assets/{index-C4Zm475L.js → index-DYFTsr9U.js} +147 -137
- package/dist/client/assets/index-u00ojO6u.css +32 -0
- package/dist/client/index.html +14 -6
- package/dist/client/manifest-dark.webmanifest +6 -0
- package/dist/client/manifest.webmanifest +6 -0
- package/dist/server/cli-supervisor.js +6 -5
- package/dist/server/cli.js +419 -67
- package/package.json +6 -5
- package/dist/client/assets/index-CxKis6wK.css +0 -32
package/dist/server/cli.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/server/cli.ts
|
|
3
3
|
import { existsSync as existsSync10 } from "fs";
|
|
4
|
-
import
|
|
4
|
+
import process10 from "process";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
5
6
|
// package.json
|
|
6
7
|
var package_default = {
|
|
7
8
|
name: "kaizenai",
|
|
8
9
|
type: "module",
|
|
9
|
-
version: "0.
|
|
10
|
+
version: "0.6.0",
|
|
10
11
|
description: "Local web UI for coding agents",
|
|
11
12
|
keywords: [
|
|
12
13
|
"claude",
|
|
@@ -43,15 +44,15 @@ var package_default = {
|
|
|
43
44
|
bun: ">=1.3.5"
|
|
44
45
|
},
|
|
45
46
|
scripts: {
|
|
46
|
-
build: "vite build && bun
|
|
47
|
+
build: "vite build && bun ./scripts/build-server.ts",
|
|
47
48
|
check: "tsc --noEmit && bun run build",
|
|
48
|
-
dev: "bun
|
|
49
|
+
dev: "bun ./scripts/dev.ts",
|
|
49
50
|
"dev:client": "vite --host 0.0.0.0 --port 5174",
|
|
50
|
-
"dev:server": "bun
|
|
51
|
+
"dev:server": "bun ./scripts/dev-server.ts --no-open --port 5175",
|
|
51
52
|
fmt: "prettier package.json README.md --check",
|
|
52
53
|
"install:dev": "bun install && bun run build && bun install -g .",
|
|
53
54
|
lint: "tsc --noEmit",
|
|
54
|
-
start: "bun
|
|
55
|
+
start: "bun ./dist/server/cli.js",
|
|
55
56
|
test: "bun test",
|
|
56
57
|
typecheck: "tsc --noEmit",
|
|
57
58
|
prepublishOnly: "bun run build"
|
|
@@ -67,6 +68,7 @@ var package_default = {
|
|
|
67
68
|
"@xterm/xterm": "^6.0.0",
|
|
68
69
|
"default-shell": "^2.2.0",
|
|
69
70
|
"puppeteer-core": "^24.40.0",
|
|
71
|
+
qrcode: "^1.5.4",
|
|
70
72
|
"react-resizable-panels": "^4.7.3",
|
|
71
73
|
sonner: "^2.0.7"
|
|
72
74
|
},
|
|
@@ -158,8 +160,8 @@ function getProviderSettingsFilePath(homeDir, env = getRuntimeEnv()) {
|
|
|
158
160
|
}
|
|
159
161
|
|
|
160
162
|
// src/server/cli-runtime.ts
|
|
161
|
-
import
|
|
162
|
-
import { spawnSync as
|
|
163
|
+
import process3 from "process";
|
|
164
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
163
165
|
|
|
164
166
|
// src/server/process-utils.ts
|
|
165
167
|
import { spawn, spawnSync } from "child_process";
|
|
@@ -184,6 +186,277 @@ function canOpenMacApp(appName) {
|
|
|
184
186
|
|
|
185
187
|
// src/shared/ports.ts
|
|
186
188
|
var PROD_SERVER_PORT = 3210;
|
|
189
|
+
var DEV_CLIENT_PORT = 5174;
|
|
190
|
+
|
|
191
|
+
// src/server/remote-access.ts
|
|
192
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
193
|
+
import { isIP } from "net";
|
|
194
|
+
import QRCode from "qrcode";
|
|
195
|
+
var TAILSCALE_COMMAND = "tailscale";
|
|
196
|
+
var HTTPS_PORT = 443;
|
|
197
|
+
var COMMAND_TIMEOUT_MS = 5000;
|
|
198
|
+
function normalizeTailscaleHostname(hostname) {
|
|
199
|
+
if (!hostname)
|
|
200
|
+
return null;
|
|
201
|
+
const normalized = hostname.trim().replace(/\.+$/, "");
|
|
202
|
+
return normalized || null;
|
|
203
|
+
}
|
|
204
|
+
function selectPreferredTailscaleHost(status) {
|
|
205
|
+
const dnsName = normalizeTailscaleHostname(status.Self?.DNSName);
|
|
206
|
+
if (dnsName)
|
|
207
|
+
return dnsName;
|
|
208
|
+
const ip = status.Self?.TailscaleIPs?.find((candidate) => candidate.trim().length > 0)?.trim();
|
|
209
|
+
return ip || null;
|
|
210
|
+
}
|
|
211
|
+
function buildRemoteBaseUrl(host, port, protocol = "http") {
|
|
212
|
+
const url = new URL(`${protocol}://${host}`);
|
|
213
|
+
if (protocol === "https" && port !== HTTPS_PORT || protocol === "http" && port !== 80) {
|
|
214
|
+
url.port = String(port);
|
|
215
|
+
}
|
|
216
|
+
return url.toString().replace(/\/$/, "");
|
|
217
|
+
}
|
|
218
|
+
function buildHandoffUrl(remoteBaseUrl) {
|
|
219
|
+
return new URL("/open", `${remoteBaseUrl}/`).toString();
|
|
220
|
+
}
|
|
221
|
+
function buildRemoteSetupUrl(baseUrl, localPort) {
|
|
222
|
+
return buildRemoteSetupUrlWithOptions(baseUrl, localPort, {});
|
|
223
|
+
}
|
|
224
|
+
function buildRemoteSetupUrlWithOptions(baseUrl, localPort, options) {
|
|
225
|
+
const url = new URL("/remote-setup", `${baseUrl}/`);
|
|
226
|
+
url.searchParams.set("localPort", String(localPort));
|
|
227
|
+
if (options.setupReason) {
|
|
228
|
+
url.searchParams.set("reason", options.setupReason);
|
|
229
|
+
}
|
|
230
|
+
if (options.setupCommand) {
|
|
231
|
+
url.searchParams.set("setupCommand", options.setupCommand);
|
|
232
|
+
}
|
|
233
|
+
return url.toString();
|
|
234
|
+
}
|
|
235
|
+
function createRemoteAccessWarning(reason) {
|
|
236
|
+
if (reason === "missing") {
|
|
237
|
+
return "remote mode is available, but Tailscale is not installed. Install Tailscale to print a stable handoff QR code.";
|
|
238
|
+
}
|
|
239
|
+
if (reason === "disconnected") {
|
|
240
|
+
return "remote mode bound all interfaces, but Tailscale is not connected. Run `tailscale up` to enable QR handoff.";
|
|
241
|
+
}
|
|
242
|
+
if (reason === "https_requires_dns") {
|
|
243
|
+
return "Tailscale HTTPS handoff requires this machine\u2019s MagicDNS name. Falling back to HTTP because only a Tailscale IP was available.";
|
|
244
|
+
}
|
|
245
|
+
if (reason === "serve_unavailable") {
|
|
246
|
+
return "Tailscale HTTPS Serve was unavailable, so Kaizen fell back to an HTTP handoff URL.";
|
|
247
|
+
}
|
|
248
|
+
if (reason === "serve_not_enabled") {
|
|
249
|
+
return "Tailscale HTTPS Serve is not enabled on this tailnet, so Kaizen fell back to an HTTP handoff URL.";
|
|
250
|
+
}
|
|
251
|
+
if (reason === "serve_conflict") {
|
|
252
|
+
return "Tailscale HTTPS Serve is already configured for another local service on this machine, so Kaizen fell back to an HTTP handoff URL.";
|
|
253
|
+
}
|
|
254
|
+
if (reason === "serve_permission_denied") {
|
|
255
|
+
return "Kaizen could not enable Tailscale HTTPS Serve because this user is not allowed to change Tailscale Serve config yet.";
|
|
256
|
+
}
|
|
257
|
+
if (reason === "serve_failed") {
|
|
258
|
+
return "Kaizen could not enable Tailscale HTTPS Serve and fell back to an HTTP handoff URL.";
|
|
259
|
+
}
|
|
260
|
+
return "remote mode bound all interfaces, but Kaizen could not resolve this machine\u2019s Tailscale address.";
|
|
261
|
+
}
|
|
262
|
+
function readTailscaleStatus() {
|
|
263
|
+
const result = spawnSync2(TAILSCALE_COMMAND, ["status", "--json"], {
|
|
264
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
265
|
+
encoding: "utf8",
|
|
266
|
+
timeout: COMMAND_TIMEOUT_MS
|
|
267
|
+
});
|
|
268
|
+
if (result.status !== 0) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
return JSON.parse(result.stdout);
|
|
273
|
+
} catch {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function readTailscaleServeStatus() {
|
|
278
|
+
const result = spawnSync2(TAILSCALE_COMMAND, ["serve", "status", "--json"], {
|
|
279
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
280
|
+
encoding: "utf8",
|
|
281
|
+
timeout: COMMAND_TIMEOUT_MS
|
|
282
|
+
});
|
|
283
|
+
if (result.status !== 0) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
return JSON.parse(result.stdout);
|
|
288
|
+
} catch {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function enableTailscaleServeHttps(targetUrl) {
|
|
293
|
+
const result = spawnSync2(TAILSCALE_COMMAND, ["serve", "--bg", "--yes", "--https", String(HTTPS_PORT), targetUrl], {
|
|
294
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
295
|
+
encoding: "utf8",
|
|
296
|
+
timeout: COMMAND_TIMEOUT_MS
|
|
297
|
+
});
|
|
298
|
+
return {
|
|
299
|
+
ok: result.status === 0,
|
|
300
|
+
output: `${result.stdout ?? ""}
|
|
301
|
+
${result.stderr ?? ""}`.trim()
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function isRecord(value) {
|
|
305
|
+
return typeof value === "object" && value !== null;
|
|
306
|
+
}
|
|
307
|
+
function isEmptyTailscaleServeStatus(status) {
|
|
308
|
+
const topLevelValues = Object.values(status);
|
|
309
|
+
if (topLevelValues.length === 0)
|
|
310
|
+
return true;
|
|
311
|
+
return topLevelValues.every((value) => isRecord(value) && Object.keys(value).length === 0);
|
|
312
|
+
}
|
|
313
|
+
function buildServeTargetCandidates(localUrl, port) {
|
|
314
|
+
return [
|
|
315
|
+
localUrl,
|
|
316
|
+
`http://127.0.0.1:${String(port)}`,
|
|
317
|
+
`http://localhost:${String(port)}`,
|
|
318
|
+
`127.0.0.1:${String(port)}`,
|
|
319
|
+
`localhost:${String(port)}`,
|
|
320
|
+
String(port)
|
|
321
|
+
];
|
|
322
|
+
}
|
|
323
|
+
function isKaizenServeConfig(status, localUrl, port, runtimeProfile) {
|
|
324
|
+
const serialized = JSON.stringify(status);
|
|
325
|
+
const currentTargets = buildServeTargetCandidates(localUrl, port);
|
|
326
|
+
if (currentTargets.some((candidate) => serialized.includes(candidate))) {
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
if (runtimeProfile !== "dev") {
|
|
330
|
+
const defaultDevTargets = [
|
|
331
|
+
`http://127.0.0.1:${String(DEV_CLIENT_PORT)}`,
|
|
332
|
+
`http://localhost:${String(DEV_CLIENT_PORT)}`,
|
|
333
|
+
`127.0.0.1:${String(DEV_CLIENT_PORT)}`,
|
|
334
|
+
`localhost:${String(DEV_CLIENT_PORT)}`
|
|
335
|
+
];
|
|
336
|
+
return defaultDevTargets.some((candidate) => serialized.includes(candidate));
|
|
337
|
+
}
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
function canUseTailscaleHttps(host) {
|
|
341
|
+
return isIP(host) === 0 && host.includes(".");
|
|
342
|
+
}
|
|
343
|
+
function createServeOperatorSetupCommand() {
|
|
344
|
+
return "sudo tailscale set --operator=$USER";
|
|
345
|
+
}
|
|
346
|
+
function createDefaultRemoteAccessDeps() {
|
|
347
|
+
return {
|
|
348
|
+
hasCommand,
|
|
349
|
+
readTailscaleStatus,
|
|
350
|
+
readTailscaleServeStatus,
|
|
351
|
+
enableTailscaleServeHttps
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
async function resolveRemoteAccessInfo(options, deps = createDefaultRemoteAccessDeps()) {
|
|
355
|
+
const fallback = {
|
|
356
|
+
localUrl: options.localUrl,
|
|
357
|
+
remoteBaseUrl: null,
|
|
358
|
+
handoffUrl: null,
|
|
359
|
+
warning: null,
|
|
360
|
+
setupCommand: null,
|
|
361
|
+
setupReason: null
|
|
362
|
+
};
|
|
363
|
+
if (!deps.hasCommand(TAILSCALE_COMMAND)) {
|
|
364
|
+
return {
|
|
365
|
+
...fallback,
|
|
366
|
+
warning: createRemoteAccessWarning("missing")
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
const status = deps.readTailscaleStatus();
|
|
370
|
+
if (!status) {
|
|
371
|
+
return {
|
|
372
|
+
...fallback,
|
|
373
|
+
warning: createRemoteAccessWarning("unavailable")
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
if (status.BackendState && status.BackendState !== "Running") {
|
|
377
|
+
return {
|
|
378
|
+
...fallback,
|
|
379
|
+
warning: createRemoteAccessWarning("disconnected")
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
const host = selectPreferredTailscaleHost(status);
|
|
383
|
+
if (!host) {
|
|
384
|
+
return {
|
|
385
|
+
...fallback,
|
|
386
|
+
warning: createRemoteAccessWarning("unavailable")
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
let warning = null;
|
|
390
|
+
let remoteBaseUrl;
|
|
391
|
+
let setupCommand = null;
|
|
392
|
+
let setupReason = null;
|
|
393
|
+
const runtimeProfile = options.runtimeProfile ?? getRuntimeProfile();
|
|
394
|
+
if (canUseTailscaleHttps(host)) {
|
|
395
|
+
const serveStatus = deps.readTailscaleServeStatus();
|
|
396
|
+
if (!serveStatus) {
|
|
397
|
+
warning = createRemoteAccessWarning("serve_unavailable");
|
|
398
|
+
remoteBaseUrl = buildRemoteBaseUrl(host, options.port);
|
|
399
|
+
} else if (!isEmptyTailscaleServeStatus(serveStatus) && !isKaizenServeConfig(serveStatus, options.localUrl, options.port, runtimeProfile)) {
|
|
400
|
+
warning = createRemoteAccessWarning("serve_conflict");
|
|
401
|
+
remoteBaseUrl = buildRemoteBaseUrl(host, options.port);
|
|
402
|
+
} else {
|
|
403
|
+
const serveResult = deps.enableTailscaleServeHttps(`http://127.0.0.1:${String(options.port)}`);
|
|
404
|
+
if (serveResult.ok) {
|
|
405
|
+
remoteBaseUrl = buildRemoteBaseUrl(host, HTTPS_PORT, "https");
|
|
406
|
+
} else {
|
|
407
|
+
const output = serveResult.output.toLowerCase();
|
|
408
|
+
if (output.includes("serve config denied") || output.includes("to not require root") || output.includes("set --operator")) {
|
|
409
|
+
warning = createRemoteAccessWarning("serve_permission_denied");
|
|
410
|
+
setupCommand = createServeOperatorSetupCommand();
|
|
411
|
+
setupReason = "serve_permission_denied";
|
|
412
|
+
} else {
|
|
413
|
+
warning = createRemoteAccessWarning(output.includes("serve is not enabled on your tailnet") ? "serve_not_enabled" : "serve_failed");
|
|
414
|
+
}
|
|
415
|
+
remoteBaseUrl = buildRemoteBaseUrl(host, options.port);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
} else {
|
|
419
|
+
warning = createRemoteAccessWarning("https_requires_dns");
|
|
420
|
+
remoteBaseUrl = buildRemoteBaseUrl(host, options.port);
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
...fallback,
|
|
424
|
+
remoteBaseUrl,
|
|
425
|
+
handoffUrl: buildHandoffUrl(remoteBaseUrl),
|
|
426
|
+
warning,
|
|
427
|
+
setupCommand,
|
|
428
|
+
setupReason
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
async function renderTerminalQrCode(url) {
|
|
432
|
+
return QRCode.toString(url, {
|
|
433
|
+
type: "terminal",
|
|
434
|
+
small: true,
|
|
435
|
+
margin: 1
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// src/server/terminal-output.ts
|
|
440
|
+
import process2 from "process";
|
|
441
|
+
var ANSI_RESET = "\x1B[0m";
|
|
442
|
+
var ANSI_BOLD = "\x1B[1m";
|
|
443
|
+
var ANSI_CYAN = "\x1B[36m";
|
|
444
|
+
var ANSI_YELLOW = "\x1B[33m";
|
|
445
|
+
function shouldUseAnsiColor() {
|
|
446
|
+
return process2.stdout.isTTY === true || process2.stderr.isTTY === true;
|
|
447
|
+
}
|
|
448
|
+
function formatTerminalHighlight(label, value) {
|
|
449
|
+
if (!shouldUseAnsiColor()) {
|
|
450
|
+
return `${label}${value}`;
|
|
451
|
+
}
|
|
452
|
+
return `${ANSI_BOLD}${ANSI_CYAN}${label}${ANSI_RESET}${value}`;
|
|
453
|
+
}
|
|
454
|
+
function formatTerminalWarning(message) {
|
|
455
|
+
if (!shouldUseAnsiColor()) {
|
|
456
|
+
return message;
|
|
457
|
+
}
|
|
458
|
+
return `${ANSI_BOLD}${ANSI_YELLOW}${message}${ANSI_RESET}`;
|
|
459
|
+
}
|
|
187
460
|
|
|
188
461
|
// src/server/restart.ts
|
|
189
462
|
var CLI_CHILD_MODE_ENV_VAR = "KAIZEN_CLI_MODE";
|
|
@@ -240,6 +513,7 @@ function parseChildArgsEnv(value) {
|
|
|
240
513
|
|
|
241
514
|
// src/server/cli-runtime.ts
|
|
242
515
|
var MINIMUM_BUN_VERSION = "1.3.5";
|
|
516
|
+
var SUPPRESS_REMOTE_STARTUP_OUTPUT_ENV_VAR = "KAIZEN_SUPPRESS_REMOTE_STARTUP_OUTPUT";
|
|
243
517
|
function printHelp() {
|
|
244
518
|
console.log(`${APP_NAME} \u2014 local-only project chat UI
|
|
245
519
|
|
|
@@ -249,7 +523,7 @@ Usage:
|
|
|
249
523
|
Options:
|
|
250
524
|
--port <number> Port to listen on (default: ${PROD_SERVER_PORT})
|
|
251
525
|
--host <host> Bind to a specific host or IP
|
|
252
|
-
--remote
|
|
526
|
+
--remote Share to your Tailscale devices and print a QR handoff
|
|
253
527
|
--strict-port Fail instead of trying another port
|
|
254
528
|
--no-open Don't open browser automatically
|
|
255
529
|
--version Print version and exit
|
|
@@ -260,6 +534,7 @@ function parseArgs(argv) {
|
|
|
260
534
|
let host = "127.0.0.1";
|
|
261
535
|
let openBrowser = true;
|
|
262
536
|
let strictPort = false;
|
|
537
|
+
let remoteMode = false;
|
|
263
538
|
for (let index = 0;index < argv.length; index += 1) {
|
|
264
539
|
const arg = argv[index];
|
|
265
540
|
if (arg === "--version" || arg === "-v") {
|
|
@@ -286,6 +561,7 @@ function parseArgs(argv) {
|
|
|
286
561
|
}
|
|
287
562
|
if (arg === "--remote") {
|
|
288
563
|
host = "0.0.0.0";
|
|
564
|
+
remoteMode = true;
|
|
289
565
|
continue;
|
|
290
566
|
}
|
|
291
567
|
if (arg === "--no-open") {
|
|
@@ -305,7 +581,8 @@ function parseArgs(argv) {
|
|
|
305
581
|
port,
|
|
306
582
|
host,
|
|
307
583
|
openBrowser,
|
|
308
|
-
strictPort
|
|
584
|
+
strictPort,
|
|
585
|
+
remoteMode
|
|
309
586
|
}
|
|
310
587
|
};
|
|
311
588
|
}
|
|
@@ -322,14 +599,25 @@ function compareVersions(currentVersion, latestVersion) {
|
|
|
322
599
|
}
|
|
323
600
|
return 0;
|
|
324
601
|
}
|
|
602
|
+
function isNpxRuntimePath(value) {
|
|
603
|
+
return /(^|[\\/])_npx([\\/]|$)/.test(value);
|
|
604
|
+
}
|
|
605
|
+
function createUnsupportedNpxInstallResult() {
|
|
606
|
+
return {
|
|
607
|
+
ok: false,
|
|
608
|
+
errorCode: "install_failed",
|
|
609
|
+
userTitle: "Update unavailable in npx",
|
|
610
|
+
userMessage: "Kaizen cannot self-update while running from npx. Rerun `npx kaizenai` to get the latest version, or install it globally with `npm install -g kaizenai`."
|
|
611
|
+
};
|
|
612
|
+
}
|
|
325
613
|
function normalizeVersion(version) {
|
|
326
614
|
return version.trim().replace(/^v/i, "").split("-")[0].split(".").map((part) => Number.parseInt(part, 10)).filter((part) => Number.isFinite(part));
|
|
327
615
|
}
|
|
328
616
|
async function maybeSelfUpdate(_argv, deps) {
|
|
329
|
-
if (
|
|
617
|
+
if (process3.env[DISABLE_SELF_UPDATE_ENV_VAR] === "1") {
|
|
330
618
|
return null;
|
|
331
619
|
}
|
|
332
|
-
if (shouldSkipStartupUpdateOnce(
|
|
620
|
+
if (shouldSkipStartupUpdateOnce(process3.env[CLI_SKIP_STARTUP_UPDATE_ONCE_ENV_VAR])) {
|
|
333
621
|
deps.warn(`${LOG_PREFIX} skipping startup update after restart to avoid an update loop`);
|
|
334
622
|
return null;
|
|
335
623
|
}
|
|
@@ -394,8 +682,34 @@ async function runCli(argv, deps) {
|
|
|
394
682
|
const displayHost = bindHost === "127.0.0.1" || bindHost === "0.0.0.0" ? "localhost" : bindHost;
|
|
395
683
|
const launchUrl = `http://${displayHost}:${port}`;
|
|
396
684
|
deps.log(`${LOG_PREFIX} listening on http://${bindHost}:${port}`);
|
|
685
|
+
deps.log(`${LOG_PREFIX} local URL: ${launchUrl}`);
|
|
397
686
|
deps.log(`${LOG_PREFIX} data dir: ${getDataDirDisplay()}`);
|
|
398
|
-
|
|
687
|
+
if (parsedArgs.options.remoteMode && process3.env[SUPPRESS_REMOTE_STARTUP_OUTPUT_ENV_VAR] !== "1") {
|
|
688
|
+
const remoteAccess = await deps.resolveRemoteAccessInfo({
|
|
689
|
+
localUrl: launchUrl,
|
|
690
|
+
port,
|
|
691
|
+
runtimeProfile: getRuntimeProfile()
|
|
692
|
+
});
|
|
693
|
+
deps.log(formatTerminalHighlight(`${LOG_PREFIX} remote setup help: `, buildRemoteSetupUrlWithOptions(launchUrl, port, {
|
|
694
|
+
setupReason: remoteAccess.setupReason,
|
|
695
|
+
setupCommand: remoteAccess.setupCommand
|
|
696
|
+
})));
|
|
697
|
+
if (remoteAccess.warning) {
|
|
698
|
+
deps.warn(formatTerminalWarning(`${LOG_PREFIX} ${remoteAccess.warning}`));
|
|
699
|
+
if (remoteAccess.setupCommand) {
|
|
700
|
+
deps.warn(formatTerminalHighlight(`${LOG_PREFIX} one-time Tailscale fix: `, remoteAccess.setupCommand));
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (remoteAccess.remoteBaseUrl && remoteAccess.handoffUrl) {
|
|
704
|
+
deps.log(`${LOG_PREFIX} Tailscale URL: ${remoteAccess.remoteBaseUrl}`);
|
|
705
|
+
deps.log(`${LOG_PREFIX} handoff URL: ${remoteAccess.handoffUrl}`);
|
|
706
|
+
deps.log(`${LOG_PREFIX} scan to open on another Tailscale device:`);
|
|
707
|
+
deps.log((await deps.renderTerminalQrCode(remoteAccess.handoffUrl)).trimEnd());
|
|
708
|
+
}
|
|
709
|
+
} else {
|
|
710
|
+
deps.log(formatTerminalHighlight(`${LOG_PREFIX} remote setup help: `, buildRemoteSetupUrl(launchUrl, port)));
|
|
711
|
+
}
|
|
712
|
+
const suppressOpenBrowser = process3.env[CLI_SUPPRESS_OPEN_ONCE_ENV_VAR] === "1";
|
|
399
713
|
if (parsedArgs.options.openBrowser && !suppressOpenBrowser) {
|
|
400
714
|
deps.openUrl(launchUrl);
|
|
401
715
|
}
|
|
@@ -405,7 +719,7 @@ async function runCli(argv, deps) {
|
|
|
405
719
|
};
|
|
406
720
|
}
|
|
407
721
|
function openUrl(url) {
|
|
408
|
-
const platform =
|
|
722
|
+
const platform = process3.platform;
|
|
409
723
|
if (platform === "darwin") {
|
|
410
724
|
spawnDetached("open", [url]);
|
|
411
725
|
} else if (platform === "win32") {
|
|
@@ -452,16 +766,16 @@ function installPackageVersion(packageName, version) {
|
|
|
452
766
|
userMessage: "Kaizen could not find Bun to install the update."
|
|
453
767
|
};
|
|
454
768
|
}
|
|
455
|
-
const result =
|
|
769
|
+
const result = spawnSync3("bun", ["install", "-g", `${packageName}@${version}`], {
|
|
456
770
|
stdio: ["ignore", "pipe", "pipe"],
|
|
457
771
|
encoding: "utf8"
|
|
458
772
|
});
|
|
459
773
|
const stdout = result.stdout ?? "";
|
|
460
774
|
const stderr = result.stderr ?? "";
|
|
461
775
|
if (stdout)
|
|
462
|
-
|
|
776
|
+
process3.stdout.write(stdout);
|
|
463
777
|
if (stderr)
|
|
464
|
-
|
|
778
|
+
process3.stderr.write(stderr);
|
|
465
779
|
if (result.status === 0) {
|
|
466
780
|
return {
|
|
467
781
|
ok: true,
|
|
@@ -2437,7 +2751,9 @@ class EventStore {
|
|
|
2437
2751
|
}
|
|
2438
2752
|
|
|
2439
2753
|
// src/server/agent.ts
|
|
2440
|
-
import {
|
|
2754
|
+
import {
|
|
2755
|
+
query as query2
|
|
2756
|
+
} from "@anthropic-ai/claude-agent-sdk";
|
|
2441
2757
|
|
|
2442
2758
|
// src/shared/tools.ts
|
|
2443
2759
|
function normalizeToolCall(args) {
|
|
@@ -5622,7 +5938,7 @@ function codexServiceTierFromModelOptions(modelOptions) {
|
|
|
5622
5938
|
import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
5623
5939
|
import { homedir as homedir4 } from "os";
|
|
5624
5940
|
import path7 from "path";
|
|
5625
|
-
import
|
|
5941
|
+
import process4 from "process";
|
|
5626
5942
|
|
|
5627
5943
|
// src/server/usage/base-provider-usage.ts
|
|
5628
5944
|
import { existsSync as existsSync2, readFileSync, writeFileSync } from "fs";
|
|
@@ -6154,7 +6470,7 @@ function collectClaudeUsageScreen(args) {
|
|
|
6154
6470
|
stderr: "pipe",
|
|
6155
6471
|
cwd: args?.cwd,
|
|
6156
6472
|
env: {
|
|
6157
|
-
...
|
|
6473
|
+
...process4.env,
|
|
6158
6474
|
...args?.cwd ? { CLAUDE_USAGE_CWD: args.cwd } : {},
|
|
6159
6475
|
CLAUDE_USAGE_CONTINUE: args?.continueSession ? "1" : "0"
|
|
6160
6476
|
}
|
|
@@ -6163,7 +6479,7 @@ function collectClaudeUsageScreen(args) {
|
|
|
6163
6479
|
}
|
|
6164
6480
|
function isRunningPid(pid) {
|
|
6165
6481
|
try {
|
|
6166
|
-
|
|
6482
|
+
process4.kill(pid, 0);
|
|
6167
6483
|
return true;
|
|
6168
6484
|
} catch {
|
|
6169
6485
|
return false;
|
|
@@ -6511,7 +6827,7 @@ import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync
|
|
|
6511
6827
|
import { mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "fs";
|
|
6512
6828
|
import { tmpdir as tmpdir3 } from "os";
|
|
6513
6829
|
import path10 from "path";
|
|
6514
|
-
import
|
|
6830
|
+
import process6 from "process";
|
|
6515
6831
|
import puppeteer from "puppeteer-core";
|
|
6516
6832
|
|
|
6517
6833
|
// src/server/usage/cursor-cookies.ts
|
|
@@ -6520,7 +6836,7 @@ import { copyFileSync, existsSync as existsSync5, mkdtempSync, readdirSync as re
|
|
|
6520
6836
|
import { createDecipheriv, pbkdf2Sync } from "crypto";
|
|
6521
6837
|
import { homedir as homedir6, tmpdir as tmpdir2 } from "os";
|
|
6522
6838
|
import path9 from "path";
|
|
6523
|
-
import
|
|
6839
|
+
import process5 from "process";
|
|
6524
6840
|
var CHROME_EPOCH_OFFSET_MS = Date.UTC(1601, 0, 1);
|
|
6525
6841
|
var CURSOR_SESSION_COOKIE_NAME = "WorkosCursorSessionToken";
|
|
6526
6842
|
function normalizeCookieDomain(domain) {
|
|
@@ -6817,7 +7133,7 @@ function decryptChromiumCookieValue(encryptedValue, key, platform) {
|
|
|
6817
7133
|
return null;
|
|
6818
7134
|
}
|
|
6819
7135
|
}
|
|
6820
|
-
function bootstrapCursorSessionFromBrowser(platform =
|
|
7136
|
+
function bootstrapCursorSessionFromBrowser(platform = process5.platform) {
|
|
6821
7137
|
if (platform !== "linux" && platform !== "darwin")
|
|
6822
7138
|
return null;
|
|
6823
7139
|
for (const source of discoverChromiumCookieSources(platform)) {
|
|
@@ -7151,7 +7467,7 @@ class CursorUsage extends BaseProviderUsage {
|
|
|
7151
7467
|
return null;
|
|
7152
7468
|
}
|
|
7153
7469
|
}
|
|
7154
|
-
async refresh(platform =
|
|
7470
|
+
async refresh(platform = process6.platform, force = false) {
|
|
7155
7471
|
const now = Date.now();
|
|
7156
7472
|
const persistedEntry = this.loadPersistedEntry();
|
|
7157
7473
|
const lastRequestedAt = persistedEntry?.lastRequestedAt ?? this.readLastRequestedAt(this.provider);
|
|
@@ -7216,7 +7532,7 @@ class CursorUsage extends BaseProviderUsage {
|
|
|
7216
7532
|
this.persistUsageEntry(entry);
|
|
7217
7533
|
return entry;
|
|
7218
7534
|
}
|
|
7219
|
-
async importFromCurl(curlCommand, platform =
|
|
7535
|
+
async importFromCurl(curlCommand, platform = process6.platform) {
|
|
7220
7536
|
const imported = importCursorSessionFromCurl(curlCommand);
|
|
7221
7537
|
if (!imported) {
|
|
7222
7538
|
return cursorStatusEntry({
|
|
@@ -7234,7 +7550,7 @@ class CursorUsage extends BaseProviderUsage {
|
|
|
7234
7550
|
this.persistSession(session);
|
|
7235
7551
|
return this.refresh(platform);
|
|
7236
7552
|
}
|
|
7237
|
-
async signInWithBrowser(platform =
|
|
7553
|
+
async signInWithBrowser(platform = process6.platform) {
|
|
7238
7554
|
const executablePath = resolveBrowserExecutable(platform);
|
|
7239
7555
|
if (!executablePath) {
|
|
7240
7556
|
return cursorStatusEntry({
|
|
@@ -7307,13 +7623,13 @@ function getCursorUsage(dataDir) {
|
|
|
7307
7623
|
}
|
|
7308
7624
|
return _instances3.get(dataDir);
|
|
7309
7625
|
}
|
|
7310
|
-
async function refreshCursorUsage(dataDir, platform =
|
|
7626
|
+
async function refreshCursorUsage(dataDir, platform = process6.platform, force = false) {
|
|
7311
7627
|
return getCursorUsage(dataDir).refresh(platform, force);
|
|
7312
7628
|
}
|
|
7313
|
-
async function importCursorUsageFromCurl(dataDir, curlCommand, platform =
|
|
7629
|
+
async function importCursorUsageFromCurl(dataDir, curlCommand, platform = process6.platform) {
|
|
7314
7630
|
return getCursorUsage(dataDir).importFromCurl(curlCommand, platform);
|
|
7315
7631
|
}
|
|
7316
|
-
async function signInToCursorWithBrowser(dataDir, platform =
|
|
7632
|
+
async function signInToCursorWithBrowser(dataDir, platform = process6.platform) {
|
|
7317
7633
|
return getCursorUsage(dataDir).signInWithBrowser(platform);
|
|
7318
7634
|
}
|
|
7319
7635
|
|
|
@@ -7461,10 +7777,21 @@ function formatRecoveredAskUserQuestionFollowUp(tool, result) {
|
|
|
7461
7777
|
].join(`
|
|
7462
7778
|
`);
|
|
7463
7779
|
}
|
|
7464
|
-
function planModeFollowUp(result) {
|
|
7780
|
+
function planModeFollowUp(result, plan) {
|
|
7465
7781
|
let text = "";
|
|
7466
7782
|
if (result.confirmed) {
|
|
7467
|
-
|
|
7783
|
+
const trimmedPlan = plan?.trim();
|
|
7784
|
+
const sections = [
|
|
7785
|
+
trimmedPlan ? "Proceed with the approved plan below." : "Proceed with the approved plan."
|
|
7786
|
+
];
|
|
7787
|
+
if (trimmedPlan) {
|
|
7788
|
+
sections.push("", "Approved plan:", trimmedPlan);
|
|
7789
|
+
}
|
|
7790
|
+
if (result.message) {
|
|
7791
|
+
sections.push("", `Additional guidance: ${result.message}`);
|
|
7792
|
+
}
|
|
7793
|
+
text = sections.join(`
|
|
7794
|
+
`);
|
|
7468
7795
|
} else {
|
|
7469
7796
|
text = result.message ? `Revise the plan using this feedback: ${result.message}` : "Revise the plan using this feedback.";
|
|
7470
7797
|
}
|
|
@@ -7560,7 +7887,14 @@ function normalizeClaudeStreamMessage(message) {
|
|
|
7560
7887
|
];
|
|
7561
7888
|
}
|
|
7562
7889
|
if (message.type === "system" && message.subtype === "status" && typeof message.status === "string") {
|
|
7563
|
-
return [
|
|
7890
|
+
return [
|
|
7891
|
+
timestamped3({
|
|
7892
|
+
kind: "status",
|
|
7893
|
+
messageId,
|
|
7894
|
+
status: message.status,
|
|
7895
|
+
debugRaw
|
|
7896
|
+
})
|
|
7897
|
+
];
|
|
7564
7898
|
}
|
|
7565
7899
|
if (message.type === "system" && message.subtype === "compact_boundary") {
|
|
7566
7900
|
return [timestamped3({ kind: "compact_boundary", messageId, debugRaw })];
|
|
@@ -7569,7 +7903,14 @@ function normalizeClaudeStreamMessage(message) {
|
|
|
7569
7903
|
return [timestamped3({ kind: "context_cleared", messageId, debugRaw })];
|
|
7570
7904
|
}
|
|
7571
7905
|
if (message.type === "user" && message.message?.role === "user" && typeof message.message.content === "string" && message.message.content.startsWith("This session is being continued")) {
|
|
7572
|
-
return [
|
|
7906
|
+
return [
|
|
7907
|
+
timestamped3({
|
|
7908
|
+
kind: "compact_summary",
|
|
7909
|
+
messageId,
|
|
7910
|
+
summary: message.message.content,
|
|
7911
|
+
debugRaw
|
|
7912
|
+
})
|
|
7913
|
+
];
|
|
7573
7914
|
}
|
|
7574
7915
|
return [];
|
|
7575
7916
|
}
|
|
@@ -8207,7 +8548,7 @@ class AgentCoordinator {
|
|
|
8207
8548
|
await this.store.setSessionToken(command.chatId, null);
|
|
8208
8549
|
await this.store.appendMessage(command.chatId, timestamped3({ kind: "context_cleared" }));
|
|
8209
8550
|
}
|
|
8210
|
-
const followUp = planModeFollowUp(result);
|
|
8551
|
+
const followUp = planModeFollowUp(result, recoveredPending.input.plan);
|
|
8211
8552
|
const messageEntry = timestamped3({
|
|
8212
8553
|
kind: "user_prompt",
|
|
8213
8554
|
content: followUp.content
|
|
@@ -8255,7 +8596,7 @@ class AgentCoordinator {
|
|
|
8255
8596
|
await this.store.appendMessage(command.chatId, timestamped3({ kind: "context_cleared" }));
|
|
8256
8597
|
}
|
|
8257
8598
|
if (shouldUseSyntheticPlanFollowUp(active.provider, pending.tool)) {
|
|
8258
|
-
active.postToolFollowUp = planModeFollowUp(result);
|
|
8599
|
+
active.postToolFollowUp = planModeFollowUp(result, pending.tool.input.plan);
|
|
8259
8600
|
}
|
|
8260
8601
|
}
|
|
8261
8602
|
pending.resolve(command.result);
|
|
@@ -9941,17 +10282,17 @@ function formatDisplayPath3(filePath) {
|
|
|
9941
10282
|
|
|
9942
10283
|
// src/server/machine-name.ts
|
|
9943
10284
|
import { hostname } from "os";
|
|
9944
|
-
import
|
|
9945
|
-
import { spawnSync as
|
|
10285
|
+
import process7 from "process";
|
|
10286
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
9946
10287
|
function runAndRead(command, args) {
|
|
9947
|
-
const result =
|
|
10288
|
+
const result = spawnSync4(command, args, { encoding: "utf8" });
|
|
9948
10289
|
if (result.status !== 0)
|
|
9949
10290
|
return null;
|
|
9950
10291
|
const value = result.stdout.trim();
|
|
9951
10292
|
return value || null;
|
|
9952
10293
|
}
|
|
9953
10294
|
function getMachineDisplayName() {
|
|
9954
|
-
if (
|
|
10295
|
+
if (process7.platform === "darwin") {
|
|
9955
10296
|
const computerName = runAndRead("scutil", ["--get", "ComputerName"]);
|
|
9956
10297
|
if (computerName) {
|
|
9957
10298
|
return computerName;
|
|
@@ -9963,15 +10304,15 @@ function getMachineDisplayName() {
|
|
|
9963
10304
|
|
|
9964
10305
|
// src/server/terminal-manager.ts
|
|
9965
10306
|
import path16 from "path";
|
|
9966
|
-
import
|
|
10307
|
+
import process8 from "process";
|
|
9967
10308
|
import defaultShell, { detectDefaultShell } from "default-shell";
|
|
9968
10309
|
import { Terminal } from "@xterm/headless";
|
|
9969
10310
|
import { SerializeAddon } from "@xterm/addon-serialize";
|
|
9970
10311
|
var DEFAULT_COLS = 80;
|
|
9971
10312
|
var DEFAULT_ROWS = 24;
|
|
9972
|
-
var DEFAULT_SCROLLBACK =
|
|
10313
|
+
var DEFAULT_SCROLLBACK = 1e4;
|
|
9973
10314
|
var MIN_SCROLLBACK = 500;
|
|
9974
|
-
var MAX_SCROLLBACK =
|
|
10315
|
+
var MAX_SCROLLBACK = 50000;
|
|
9975
10316
|
var FOCUS_IN_SEQUENCE = "\x1B[I";
|
|
9976
10317
|
var FOCUS_OUT_SEQUENCE = "\x1B[O";
|
|
9977
10318
|
var MODE_SEQUENCE_TAIL_LENGTH = 16;
|
|
@@ -9991,14 +10332,14 @@ function resolveShell() {
|
|
|
9991
10332
|
} catch {
|
|
9992
10333
|
if (defaultShell)
|
|
9993
10334
|
return defaultShell;
|
|
9994
|
-
if (
|
|
9995
|
-
return
|
|
10335
|
+
if (process8.platform === "win32") {
|
|
10336
|
+
return process8.env.ComSpec || "cmd.exe";
|
|
9996
10337
|
}
|
|
9997
|
-
return
|
|
10338
|
+
return process8.env.SHELL || "/bin/sh";
|
|
9998
10339
|
}
|
|
9999
10340
|
}
|
|
10000
10341
|
function resolveShellArgs(shellPath) {
|
|
10001
|
-
if (
|
|
10342
|
+
if (process8.platform === "win32") {
|
|
10002
10343
|
return [];
|
|
10003
10344
|
}
|
|
10004
10345
|
const shellName = path16.basename(shellPath);
|
|
@@ -10009,7 +10350,7 @@ function resolveShellArgs(shellPath) {
|
|
|
10009
10350
|
}
|
|
10010
10351
|
function createTerminalEnv() {
|
|
10011
10352
|
return {
|
|
10012
|
-
...
|
|
10353
|
+
...process8.env,
|
|
10013
10354
|
TERM: "xterm-256color",
|
|
10014
10355
|
COLORTERM: "truecolor"
|
|
10015
10356
|
};
|
|
@@ -10034,9 +10375,9 @@ function killTerminalProcessTree(subprocess) {
|
|
|
10034
10375
|
const pid = subprocess.pid;
|
|
10035
10376
|
if (typeof pid !== "number")
|
|
10036
10377
|
return;
|
|
10037
|
-
if (
|
|
10378
|
+
if (process8.platform !== "win32") {
|
|
10038
10379
|
try {
|
|
10039
|
-
|
|
10380
|
+
process8.kill(-pid, "SIGKILL");
|
|
10040
10381
|
return;
|
|
10041
10382
|
} catch {}
|
|
10042
10383
|
}
|
|
@@ -10050,9 +10391,9 @@ function signalTerminalProcessGroup(subprocess, signal) {
|
|
|
10050
10391
|
const pid = subprocess.pid;
|
|
10051
10392
|
if (typeof pid !== "number")
|
|
10052
10393
|
return false;
|
|
10053
|
-
if (
|
|
10394
|
+
if (process8.platform !== "win32") {
|
|
10054
10395
|
try {
|
|
10055
|
-
|
|
10396
|
+
process8.kill(-pid, signal);
|
|
10056
10397
|
return true;
|
|
10057
10398
|
} catch {}
|
|
10058
10399
|
}
|
|
@@ -10074,7 +10415,7 @@ class TerminalManager {
|
|
|
10074
10415
|
};
|
|
10075
10416
|
}
|
|
10076
10417
|
createTerminal(args) {
|
|
10077
|
-
if (
|
|
10418
|
+
if (process8.platform === "win32") {
|
|
10078
10419
|
throw new Error("Embedded terminal is currently supported on macOS/Linux only.");
|
|
10079
10420
|
}
|
|
10080
10421
|
if (typeof Bun.Terminal !== "function") {
|
|
@@ -10096,7 +10437,12 @@ class TerminalManager {
|
|
|
10096
10437
|
const rows = normalizeTerminalDimension(args.rows, DEFAULT_ROWS);
|
|
10097
10438
|
const scrollback = clampScrollback(args.scrollback);
|
|
10098
10439
|
const title = path16.basename(shell) || "shell";
|
|
10099
|
-
const headless = new Terminal({
|
|
10440
|
+
const headless = new Terminal({
|
|
10441
|
+
cols,
|
|
10442
|
+
rows,
|
|
10443
|
+
scrollback,
|
|
10444
|
+
allowProposedApi: true
|
|
10445
|
+
});
|
|
10100
10446
|
const serializeAddon = new SerializeAddon;
|
|
10101
10447
|
headless.loadAddon(serializeAddon);
|
|
10102
10448
|
const session = {
|
|
@@ -10241,7 +10587,9 @@ class TerminalManager {
|
|
|
10241
10587
|
cols: session.cols,
|
|
10242
10588
|
rows: session.rows,
|
|
10243
10589
|
scrollback: session.scrollback,
|
|
10244
|
-
serializedState: session.serializeAddon.serialize({
|
|
10590
|
+
serializedState: session.serializeAddon.serialize({
|
|
10591
|
+
scrollback: session.scrollback
|
|
10592
|
+
}),
|
|
10245
10593
|
status: session.status,
|
|
10246
10594
|
exitCode: session.exitCode
|
|
10247
10595
|
};
|
|
@@ -10844,14 +11192,14 @@ function isClientEnvelope(value) {
|
|
|
10844
11192
|
// src/server/external-open.ts
|
|
10845
11193
|
import { stat as stat2 } from "fs/promises";
|
|
10846
11194
|
import path18 from "path";
|
|
10847
|
-
import
|
|
11195
|
+
import process9 from "process";
|
|
10848
11196
|
var DEFAULT_EDITOR_SETTINGS = {
|
|
10849
11197
|
preset: "cursor",
|
|
10850
11198
|
commandTemplate: "cursor {path}"
|
|
10851
11199
|
};
|
|
10852
11200
|
async function openExternal(command) {
|
|
10853
11201
|
const resolvedPath = resolveLocalPath(command.localPath);
|
|
10854
|
-
const platform =
|
|
11202
|
+
const platform = process9.platform;
|
|
10855
11203
|
const info = command.action === "open_editor" || command.action === "open_finder" ? await stat2(resolvedPath).catch(() => null) : null;
|
|
10856
11204
|
if (command.action === "open_editor") {
|
|
10857
11205
|
if (!info) {
|
|
@@ -10921,7 +11269,7 @@ async function openExternal(command) {
|
|
|
10921
11269
|
}
|
|
10922
11270
|
}
|
|
10923
11271
|
async function openUrl2(command) {
|
|
10924
|
-
const platform =
|
|
11272
|
+
const platform = process9.platform;
|
|
10925
11273
|
if (platform === "darwin") {
|
|
10926
11274
|
spawnDetached("open", [command.url]);
|
|
10927
11275
|
return;
|
|
@@ -12584,12 +12932,14 @@ async function serveStatic(distDir, pathname) {
|
|
|
12584
12932
|
|
|
12585
12933
|
// src/server/cli.ts
|
|
12586
12934
|
var packageRootUrl = new URL("../../", import.meta.url);
|
|
12935
|
+
var packageRootPath = fileURLToPath(packageRootUrl);
|
|
12587
12936
|
var pkg = await Bun.file(new URL("package.json", packageRootUrl)).json();
|
|
12588
12937
|
var VERSION = pkg.version ?? "0.0.0";
|
|
12589
|
-
var
|
|
12590
|
-
var
|
|
12938
|
+
var IS_NPX_RUNTIME = isNpxRuntimePath(packageRootPath);
|
|
12939
|
+
var ALLOW_SELF_UPDATE = !existsSync10(new URL(".git", packageRootUrl)) && !IS_NPX_RUNTIME;
|
|
12940
|
+
var argv = process10.argv.slice(2);
|
|
12591
12941
|
var resolveExitAction = null;
|
|
12592
|
-
var WEB_ONLY_MODE = shouldRunWebOnlyMode(
|
|
12942
|
+
var WEB_ONLY_MODE = shouldRunWebOnlyMode(process10.env[CLI_WEB_ONLY_MODE_ENV_VAR]);
|
|
12593
12943
|
var result = await runCli(argv, {
|
|
12594
12944
|
version: VERSION,
|
|
12595
12945
|
bunVersion: Bun.version,
|
|
@@ -12610,27 +12960,29 @@ var result = await runCli(argv, {
|
|
|
12610
12960
|
return started;
|
|
12611
12961
|
},
|
|
12612
12962
|
fetchLatestVersion: fetchLatestPackageVersion,
|
|
12613
|
-
installVersion: installPackageVersion,
|
|
12963
|
+
installVersion: IS_NPX_RUNTIME ? () => createUnsupportedNpxInstallResult() : installPackageVersion,
|
|
12614
12964
|
openUrl,
|
|
12965
|
+
resolveRemoteAccessInfo,
|
|
12966
|
+
renderTerminalQrCode,
|
|
12615
12967
|
log: console.log,
|
|
12616
12968
|
warn: console.warn
|
|
12617
12969
|
});
|
|
12618
12970
|
if (result.kind === "exited") {
|
|
12619
|
-
|
|
12971
|
+
process10.exit(result.code);
|
|
12620
12972
|
}
|
|
12621
12973
|
if (result.kind === "restarting") {
|
|
12622
|
-
|
|
12974
|
+
process10.exit(result.reason === "startup_update" ? CLI_STARTUP_UPDATE_RESTART_EXIT_CODE : CLI_UI_UPDATE_RESTART_EXIT_CODE);
|
|
12623
12975
|
}
|
|
12624
12976
|
var exitAction = await new Promise((resolve2) => {
|
|
12625
12977
|
resolveExitAction = resolve2;
|
|
12626
12978
|
const shutdown = () => {
|
|
12627
12979
|
resolve2("exit");
|
|
12628
12980
|
};
|
|
12629
|
-
|
|
12630
|
-
|
|
12981
|
+
process10.once("SIGINT", shutdown);
|
|
12982
|
+
process10.once("SIGTERM", shutdown);
|
|
12631
12983
|
});
|
|
12632
12984
|
await result.stop();
|
|
12633
12985
|
if (exitAction === "ui_restart") {
|
|
12634
12986
|
console.log(`${LOG_PREFIX} current process stopped, handing restart back to supervisor`);
|
|
12635
12987
|
}
|
|
12636
|
-
|
|
12988
|
+
process10.exit(exitAction === "ui_restart" ? CLI_UI_UPDATE_RESTART_EXIT_CODE : 0);
|