@p4code/cli 0.0.34 → 0.0.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BunPtyAdapter-DogtLQSx.mjs → BunPtyAdapter-CLDq7yr1.mjs} +2 -2
- package/dist/{NodePtyAdapter-CS1weRcq.mjs → NodePtyAdapter-BQAnH2v0.mjs} +3 -3
- package/dist/{PtyAdapter-DO4FyE0R.mjs → PtyAdapter-DLKyoorI.mjs} +2 -2
- package/dist/bin.mjs +1114 -905
- package/dist/client/assets/{DiffPanel-DOklgmIE.js → DiffPanel-DKJ8ECjA.js} +2 -2
- package/dist/client/assets/{FilePreviewPanel-CeHOdzAP.js → FilePreviewPanel-DrEwfDlH.js} +2 -2
- package/dist/client/assets/{PreviewPanel-BAIix88r.js → PreviewPanel-DWT1ePi1.js} +2 -2
- package/dist/client/assets/{fileCommentAnnotations-BB-roSM5.js → fileCommentAnnotations-QSDzusB8.js} +2 -2
- package/dist/client/assets/{index-CiPrtrTQ.js → index-BSt_6F_c.js} +4 -4
- package/dist/client/index.html +1 -1
- package/package.json +1 -1
package/dist/bin.mjs
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { a as HostProcessEnvironment, c as HostProcessPlatform, i as HostProcessArguments, l as HostProcessUserId, n as PtySpawnError, o as HostProcessExecutablePath, r as HostProcessArchitecture, s as HostProcessHostname, t as PtyAdapter } from "./PtyAdapter-
|
|
3
|
+
import { a as HostProcessEnvironment, c as HostProcessPlatform, i as HostProcessArguments, l as HostProcessUserId, n as PtySpawnError, o as HostProcessExecutablePath, r as HostProcessArchitecture, s as HostProcessHostname, t as PtyAdapter } from "./PtyAdapter-DLKyoorI.mjs";
|
|
4
4
|
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
|
|
5
5
|
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
6
|
+
import * as Console from "effect/Console";
|
|
6
7
|
import * as Effect from "effect/Effect";
|
|
7
8
|
import * as Layer from "effect/Layer";
|
|
8
9
|
import { Argument, Command, Flag, GlobalFlag, Prompt } from "effect/unstable/cli";
|
|
10
|
+
import { FetchHttpClient, Headers, HttpBody, HttpClient, HttpClientError, HttpClientRequest, HttpClientResponse, HttpRouter, HttpServer, HttpServerRequest, HttpServerRespondable, HttpServerResponse } from "effect/unstable/http";
|
|
11
|
+
import * as Context from "effect/Context";
|
|
12
|
+
import * as NodeOS from "node:os";
|
|
9
13
|
import * as NodeNet from "node:net";
|
|
10
14
|
import * as Data from "effect/Data";
|
|
11
|
-
import * as Context from "effect/Context";
|
|
12
15
|
import * as Predicate from "effect/Predicate";
|
|
16
|
+
import * as FileSystem from "effect/FileSystem";
|
|
17
|
+
import "effect/LogLevel";
|
|
18
|
+
import * as Path from "effect/Path";
|
|
13
19
|
import * as Schema$1 from "effect/Schema";
|
|
20
|
+
import * as NodePath from "node:path";
|
|
21
|
+
import * as NodeChildProcess from "node:child_process";
|
|
22
|
+
import * as NodeFS from "node:fs";
|
|
23
|
+
import * as DateTime from "effect/DateTime";
|
|
24
|
+
import * as Duration from "effect/Duration";
|
|
25
|
+
import * as Option from "effect/Option";
|
|
14
26
|
import * as SchemaTransformation from "effect/SchemaTransformation";
|
|
15
27
|
import * as HttpApiSchema from "effect/unstable/httpapi/HttpApiSchema";
|
|
16
28
|
import * as HttpApi from "effect/unstable/httpapi/HttpApi";
|
|
@@ -19,20 +31,13 @@ import * as HttpApiGroup from "effect/unstable/httpapi/HttpApiGroup";
|
|
|
19
31
|
import * as HttpApiMiddleware from "effect/unstable/httpapi/HttpApiMiddleware";
|
|
20
32
|
import * as HttpServerRespondable$1 from "effect/unstable/http/HttpServerRespondable";
|
|
21
33
|
import * as HttpServerResponse$1 from "effect/unstable/http/HttpServerResponse";
|
|
22
|
-
import * as Option from "effect/Option";
|
|
23
34
|
import * as SchemaIssue from "effect/SchemaIssue";
|
|
24
35
|
import * as Struct from "effect/Struct";
|
|
25
36
|
import { Schema } from "effect";
|
|
26
|
-
import * as Duration from "effect/Duration";
|
|
27
37
|
import * as Rpc from "effect/unstable/rpc/Rpc";
|
|
28
38
|
import * as RpcGroup from "effect/unstable/rpc/RpcGroup";
|
|
29
|
-
import * as Console from "effect/Console";
|
|
30
39
|
import * as References from "effect/References";
|
|
31
|
-
import * as DateTime from "effect/DateTime";
|
|
32
40
|
import * as HttpServerRequest$1 from "effect/unstable/http/HttpServerRequest";
|
|
33
|
-
import * as FileSystem from "effect/FileSystem";
|
|
34
|
-
import "effect/LogLevel";
|
|
35
|
-
import * as Path from "effect/Path";
|
|
36
41
|
import * as NodeCrypto from "node:crypto";
|
|
37
42
|
import * as Encoding from "effect/Encoding";
|
|
38
43
|
import * as Result from "effect/Result";
|
|
@@ -48,12 +53,7 @@ import * as Cause from "effect/Cause";
|
|
|
48
53
|
import * as Exit from "effect/Exit";
|
|
49
54
|
import * as SchemaGetter from "effect/SchemaGetter";
|
|
50
55
|
import * as Config from "effect/Config";
|
|
51
|
-
import * as NodeFS from "node:fs";
|
|
52
56
|
import * as NodeReadline from "node:readline";
|
|
53
|
-
import * as NodeOS from "node:os";
|
|
54
|
-
import * as NodePath from "node:path";
|
|
55
|
-
import * as NodeChildProcess from "node:child_process";
|
|
56
|
-
import { FetchHttpClient, Headers, HttpBody, HttpClient, HttpClientError, HttpClientRequest, HttpClientResponse, HttpRouter, HttpServer, HttpServerRequest, HttpServerRespondable, HttpServerResponse } from "effect/unstable/http";
|
|
57
57
|
import * as HttpApiClient from "effect/unstable/httpapi/HttpApiClient";
|
|
58
58
|
import * as Clock from "effect/Clock";
|
|
59
59
|
import * as Deferred from "effect/Deferred";
|
|
@@ -232,7 +232,708 @@ const make$67 = () => {
|
|
|
232
232
|
const layer$62 = Layer.sync(NetService, make$67);
|
|
233
233
|
//#endregion
|
|
234
234
|
//#region package.json
|
|
235
|
-
var version = "0.0.
|
|
235
|
+
var version = "0.0.36";
|
|
236
|
+
//#endregion
|
|
237
|
+
//#region src/config.ts
|
|
238
|
+
/**
|
|
239
|
+
* ServerConfig - Runtime configuration services.
|
|
240
|
+
*
|
|
241
|
+
* Defines process-level server configuration and networking helpers used by
|
|
242
|
+
* startup and runtime layers.
|
|
243
|
+
*
|
|
244
|
+
* @module ServerConfig
|
|
245
|
+
*/
|
|
246
|
+
const DEFAULT_PORT = 3773;
|
|
247
|
+
const RuntimeMode$1 = Schema$1.Literals(["web", "desktop"]);
|
|
248
|
+
Schema$1.Literals(["browser", "headless"]);
|
|
249
|
+
/**
|
|
250
|
+
* ServerConfig - Service tag for server runtime configuration.
|
|
251
|
+
*/
|
|
252
|
+
var ServerConfig$1 = class extends Context.Service()("@p4code/cli/config/ServerConfig") {
|
|
253
|
+
/** @deprecated Import and use `layerTest` from this module. */
|
|
254
|
+
static layerTest = (cwd, baseDirOrPrefix) => layerTest$2(cwd, baseDirOrPrefix);
|
|
255
|
+
};
|
|
256
|
+
const make$66 = (config) => ServerConfig$1.of(config);
|
|
257
|
+
const layer$61 = (config) => Layer.succeed(ServerConfig$1, make$66(config));
|
|
258
|
+
const deriveServerPaths = Effect.fn(function* (baseDir, devUrl, options = {}) {
|
|
259
|
+
const { join } = yield* Path.Path;
|
|
260
|
+
const stateDir = join(baseDir, devUrl !== void 0 && !options.baseDirIsExplicit ? "dev" : "userdata");
|
|
261
|
+
const dbPath = join(stateDir, "state.sqlite");
|
|
262
|
+
const attachmentsDir = join(stateDir, "attachments");
|
|
263
|
+
const logsDir = join(stateDir, "logs");
|
|
264
|
+
const providerLogsDir = join(logsDir, "provider");
|
|
265
|
+
const providerStatusCacheDir = join(baseDir, "caches");
|
|
266
|
+
return {
|
|
267
|
+
stateDir,
|
|
268
|
+
dbPath,
|
|
269
|
+
keybindingsConfigPath: join(stateDir, "keybindings.json"),
|
|
270
|
+
settingsPath: join(stateDir, "settings.json"),
|
|
271
|
+
providerStatusCacheDir,
|
|
272
|
+
worktreesDir: join(baseDir, "worktrees"),
|
|
273
|
+
attachmentsDir,
|
|
274
|
+
logsDir,
|
|
275
|
+
serverLogPath: join(logsDir, "server.log"),
|
|
276
|
+
serverTracePath: join(logsDir, "server.trace.ndjson"),
|
|
277
|
+
providerLogsDir,
|
|
278
|
+
providerEventLogPath: join(providerLogsDir, "events.log"),
|
|
279
|
+
terminalLogsDir: join(logsDir, "terminals"),
|
|
280
|
+
anonymousIdPath: join(stateDir, "anonymous-id"),
|
|
281
|
+
environmentIdPath: join(stateDir, "environment-id"),
|
|
282
|
+
serverRuntimeStatePath: join(stateDir, "server-runtime.json"),
|
|
283
|
+
secretsDir: join(stateDir, "secrets")
|
|
284
|
+
};
|
|
285
|
+
});
|
|
286
|
+
const ensureServerDirectories = Effect.fn(function* (derivedPaths) {
|
|
287
|
+
const fs = yield* FileSystem.FileSystem;
|
|
288
|
+
const path = yield* Path.Path;
|
|
289
|
+
yield* Effect.all([
|
|
290
|
+
fs.makeDirectory(derivedPaths.stateDir, { recursive: true }),
|
|
291
|
+
fs.makeDirectory(derivedPaths.logsDir, { recursive: true }),
|
|
292
|
+
fs.makeDirectory(derivedPaths.providerLogsDir, { recursive: true }),
|
|
293
|
+
fs.makeDirectory(derivedPaths.terminalLogsDir, { recursive: true }),
|
|
294
|
+
fs.makeDirectory(derivedPaths.attachmentsDir, { recursive: true }),
|
|
295
|
+
fs.makeDirectory(derivedPaths.worktreesDir, { recursive: true }),
|
|
296
|
+
fs.makeDirectory(path.dirname(derivedPaths.keybindingsConfigPath), { recursive: true }),
|
|
297
|
+
fs.makeDirectory(path.dirname(derivedPaths.settingsPath), { recursive: true }),
|
|
298
|
+
fs.makeDirectory(derivedPaths.providerStatusCacheDir, { recursive: true }),
|
|
299
|
+
fs.makeDirectory(path.dirname(derivedPaths.anonymousIdPath), { recursive: true }),
|
|
300
|
+
fs.makeDirectory(path.dirname(derivedPaths.serverRuntimeStatePath), { recursive: true })
|
|
301
|
+
], { concurrency: "unbounded" });
|
|
302
|
+
});
|
|
303
|
+
const makeTest$1 = Effect.fn("ServerConfig.makeTest")(function* (cwd, baseDirOrPrefix) {
|
|
304
|
+
const devUrl = void 0;
|
|
305
|
+
const fs = yield* FileSystem.FileSystem;
|
|
306
|
+
const baseDir = typeof baseDirOrPrefix === "string" ? baseDirOrPrefix : yield* fs.makeTempDirectoryScoped({ prefix: baseDirOrPrefix.prefix });
|
|
307
|
+
const derivedPaths = yield* deriveServerPaths(baseDir, devUrl);
|
|
308
|
+
yield* ensureServerDirectories(derivedPaths);
|
|
309
|
+
return ServerConfig$1.of({
|
|
310
|
+
logLevel: "Error",
|
|
311
|
+
traceMinLevel: "Info",
|
|
312
|
+
traceTimingEnabled: true,
|
|
313
|
+
traceBatchWindowMs: 200,
|
|
314
|
+
traceMaxBytes: 10 * 1024 * 1024,
|
|
315
|
+
traceMaxFiles: 10,
|
|
316
|
+
otlpTracesUrl: void 0,
|
|
317
|
+
otlpMetricsUrl: void 0,
|
|
318
|
+
otlpExportIntervalMs: 1e4,
|
|
319
|
+
otlpServiceName: "p4-server",
|
|
320
|
+
cwd,
|
|
321
|
+
baseDir,
|
|
322
|
+
...derivedPaths,
|
|
323
|
+
mode: "web",
|
|
324
|
+
autoBootstrapProjectFromCwd: false,
|
|
325
|
+
logWebSocketEvents: false,
|
|
326
|
+
tailscaleServeEnabled: false,
|
|
327
|
+
tailscaleServePort: 443,
|
|
328
|
+
port: 0,
|
|
329
|
+
host: void 0,
|
|
330
|
+
desktopBootstrapToken: void 0,
|
|
331
|
+
staticDir: void 0,
|
|
332
|
+
devUrl,
|
|
333
|
+
devAllowedOrigins: [],
|
|
334
|
+
noBrowser: false,
|
|
335
|
+
startupPresentation: "browser"
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
const layerTest$2 = (cwd, baseDirOrPrefix) => Layer.effect(ServerConfig$1, makeTest$1(cwd, baseDirOrPrefix));
|
|
339
|
+
const resolveStaticDir = Effect.fn(function* () {
|
|
340
|
+
const { join, resolve } = yield* Path.Path;
|
|
341
|
+
const { exists } = yield* FileSystem.FileSystem;
|
|
342
|
+
const bundledClient = resolve(join(import.meta.dirname, "client"));
|
|
343
|
+
if (yield* exists(join(bundledClient, "index.html")).pipe(Effect.orElseSucceed(() => false))) return bundledClient;
|
|
344
|
+
const monorepoClient = resolve(join(import.meta.dirname, "../../web/dist"));
|
|
345
|
+
if (yield* exists(join(monorepoClient, "index.html")).pipe(Effect.orElseSucceed(() => false))) return monorepoClient;
|
|
346
|
+
});
|
|
347
|
+
//#endregion
|
|
348
|
+
//#region ../../packages/shared/src/shell.ts
|
|
349
|
+
const SHELL_ENV_NAME_PATTERN = /^[A-Z0-9_]+$/;
|
|
350
|
+
const WINDOWS_PATH_DELIMITER = ";";
|
|
351
|
+
const POSIX_PATH_DELIMITER = ":";
|
|
352
|
+
const WINDOWS_SHELL_CANDIDATES = ["pwsh.exe", "powershell.exe"];
|
|
353
|
+
function canExecuteFile(filePath) {
|
|
354
|
+
try {
|
|
355
|
+
NodeFS.accessSync(filePath, NodeFS.constants.X_OK);
|
|
356
|
+
return true;
|
|
357
|
+
} catch {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
var CommandResolutionError = class extends Data.TaggedError("CommandResolutionError") {};
|
|
362
|
+
const WINDOWS_SHELL_META_CHARS = /([()\][%!^"`<>&|;, *?])/g;
|
|
363
|
+
/**
|
|
364
|
+
* Escapes a single argument for `cmd.exe` shell mode (`spawn(..., { shell: true })`
|
|
365
|
+
* on Windows). Node joins the command and arguments with spaces and hands the
|
|
366
|
+
* resulting string to `cmd.exe` without any quoting, so every dynamic argument
|
|
367
|
+
* must be escaped to survive both cmd.exe parsing and the target program's
|
|
368
|
+
* `CommandLineToArgvW` parsing. Mirrors cross-spawn's argument escaping.
|
|
369
|
+
*/
|
|
370
|
+
function escapeWindowsShellArg(arg) {
|
|
371
|
+
let escaped = arg.replace(/(\\*)"/g, "$1$1\\\"");
|
|
372
|
+
escaped = escaped.replace(/(\\*)$/, "$1$1");
|
|
373
|
+
escaped = `"${escaped}"`;
|
|
374
|
+
return escaped.replace(WINDOWS_SHELL_META_CHARS, "^$1");
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Escapes arguments for shell-mode spawns: applies {@link escapeWindowsShellArg}
|
|
378
|
+
* when the platform is `win32` (where `shell: true` routes through `cmd.exe`)
|
|
379
|
+
* and returns the arguments untouched everywhere else.
|
|
380
|
+
*/
|
|
381
|
+
function sanitizeShellModeArgsForPlatform(args, platform) {
|
|
382
|
+
return platform === "win32" ? args.map(escapeWindowsShellArg) : [...args];
|
|
383
|
+
}
|
|
384
|
+
function resolveSpawnExecutableWithNode(command, platform, env) {
|
|
385
|
+
const path = platform === "win32" ? NodePath.win32 : NodePath.posix;
|
|
386
|
+
const windowsPathExtensions = platform === "win32" ? resolveWindowsPathExtensions(env) : [];
|
|
387
|
+
const candidates = resolveCommandCandidates(command, platform, windowsPathExtensions, path.extname);
|
|
388
|
+
const isExecutable = (candidate) => {
|
|
389
|
+
try {
|
|
390
|
+
if (!NodeFS.statSync(candidate).isFile()) return false;
|
|
391
|
+
if (platform === "win32") return windowsPathExtensions.includes(path.extname(candidate).toUpperCase());
|
|
392
|
+
return canExecuteFile(candidate);
|
|
393
|
+
} catch {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
if (command.includes("/") || command.includes("\\")) return candidates.find(isExecutable);
|
|
398
|
+
for (const pathEntry of (readEnvPath(env) ?? "").split(pathDelimiterForPlatform(platform))) {
|
|
399
|
+
const normalizedPathEntry = stripWrappingQuotes(pathEntry.trim());
|
|
400
|
+
if (normalizedPathEntry.length === 0) continue;
|
|
401
|
+
for (const candidate of candidates) {
|
|
402
|
+
const candidatePath = path.join(normalizedPathEntry, candidate);
|
|
403
|
+
if (isExecutable(candidatePath)) return candidatePath;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
const SpawnExecutableResolution = Context.Reference("@p4code/shared/shell/SpawnExecutableResolution", { defaultValue: () => resolveSpawnExecutableWithNode });
|
|
408
|
+
function trimNonEmpty(value) {
|
|
409
|
+
const trimmed = value?.trim();
|
|
410
|
+
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
411
|
+
}
|
|
412
|
+
function readUserLoginShell() {
|
|
413
|
+
try {
|
|
414
|
+
return trimNonEmpty(NodeOS.userInfo().shell);
|
|
415
|
+
} catch {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
function listLoginShellCandidates(platform, shell, userShell = readUserLoginShell()) {
|
|
420
|
+
const fallbackShell = platform === "darwin" ? "/bin/zsh" : platform === "linux" ? "/bin/bash" : void 0;
|
|
421
|
+
const seen = /* @__PURE__ */ new Set();
|
|
422
|
+
const candidates = [];
|
|
423
|
+
for (const candidate of [
|
|
424
|
+
trimNonEmpty(shell),
|
|
425
|
+
trimNonEmpty(userShell),
|
|
426
|
+
fallbackShell
|
|
427
|
+
]) {
|
|
428
|
+
if (!candidate || seen.has(candidate)) continue;
|
|
429
|
+
seen.add(candidate);
|
|
430
|
+
candidates.push(candidate);
|
|
431
|
+
}
|
|
432
|
+
return candidates;
|
|
433
|
+
}
|
|
434
|
+
function readPathFromLoginShell(shell, execFile = NodeChildProcess.execFileSync) {
|
|
435
|
+
return readEnvironmentFromLoginShell(shell, ["PATH"], execFile).PATH;
|
|
436
|
+
}
|
|
437
|
+
function readPathFromLaunchctl(execFile = NodeChildProcess.execFileSync) {
|
|
438
|
+
try {
|
|
439
|
+
return trimNonEmpty(execFile("/bin/launchctl", ["getenv", "PATH"], {
|
|
440
|
+
encoding: "utf8",
|
|
441
|
+
timeout: 2e3
|
|
442
|
+
}));
|
|
443
|
+
} catch {
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function mergePathEntries(preferredPath, inheritedPath, platform) {
|
|
448
|
+
const delimiter = platform === "win32" ? ";" : ":";
|
|
449
|
+
const merged = [];
|
|
450
|
+
const seen = /* @__PURE__ */ new Set();
|
|
451
|
+
for (const pathValue of [preferredPath, inheritedPath]) {
|
|
452
|
+
if (!pathValue) continue;
|
|
453
|
+
for (const entry of pathValue.split(delimiter)) {
|
|
454
|
+
const trimmedEntry = entry.trim();
|
|
455
|
+
if (!trimmedEntry || seen.has(trimmedEntry)) continue;
|
|
456
|
+
seen.add(trimmedEntry);
|
|
457
|
+
merged.push(trimmedEntry);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return merged.length > 0 ? merged.join(delimiter) : void 0;
|
|
461
|
+
}
|
|
462
|
+
function envCaptureStart(name) {
|
|
463
|
+
return `__P4CODE_ENV_${name}_START__`;
|
|
464
|
+
}
|
|
465
|
+
function envCaptureEnd(name) {
|
|
466
|
+
return `__P4CODE_ENV_${name}_END__`;
|
|
467
|
+
}
|
|
468
|
+
function buildEnvironmentCaptureCommand(names) {
|
|
469
|
+
return names.map((name) => {
|
|
470
|
+
if (!SHELL_ENV_NAME_PATTERN.test(name)) throw new Error(`Unsupported environment variable name: ${name}`);
|
|
471
|
+
return [
|
|
472
|
+
`printf '%s\\n' '${envCaptureStart(name)}'`,
|
|
473
|
+
`printenv ${name} || true`,
|
|
474
|
+
`printf '%s\\n' '${envCaptureEnd(name)}'`
|
|
475
|
+
].join("; ");
|
|
476
|
+
}).join("; ");
|
|
477
|
+
}
|
|
478
|
+
function buildWindowsEnvironmentCaptureCommand(names) {
|
|
479
|
+
return ["$ErrorActionPreference = 'Stop'", ...names.flatMap((name) => {
|
|
480
|
+
if (!SHELL_ENV_NAME_PATTERN.test(name)) throw new Error(`Unsupported environment variable name: ${name}`);
|
|
481
|
+
return [
|
|
482
|
+
`Write-Output '${envCaptureStart(name)}'`,
|
|
483
|
+
`$value = [Environment]::GetEnvironmentVariable('${name}')`,
|
|
484
|
+
"if ($null -ne $value -and $value.Length -gt 0) { Write-Output $value }",
|
|
485
|
+
`Write-Output '${envCaptureEnd(name)}'`
|
|
486
|
+
];
|
|
487
|
+
})].join("; ");
|
|
488
|
+
}
|
|
489
|
+
function extractEnvironmentValue(output, name) {
|
|
490
|
+
const startMarker = envCaptureStart(name);
|
|
491
|
+
const endMarker = envCaptureEnd(name);
|
|
492
|
+
const startIndex = output.indexOf(startMarker);
|
|
493
|
+
if (startIndex === -1) return void 0;
|
|
494
|
+
const valueStartIndex = startIndex + startMarker.length;
|
|
495
|
+
const endIndex = output.indexOf(endMarker, valueStartIndex);
|
|
496
|
+
if (endIndex === -1) return void 0;
|
|
497
|
+
const value = output.slice(valueStartIndex, endIndex).replace(/^\r?\n/, "").replace(/\r?\n$/, "");
|
|
498
|
+
return value.length > 0 ? value : void 0;
|
|
499
|
+
}
|
|
500
|
+
const readEnvironmentFromLoginShell = (shell, names, execFile = NodeChildProcess.execFileSync) => {
|
|
501
|
+
if (names.length === 0) return {};
|
|
502
|
+
const output = execFile(shell, ["-ilc", buildEnvironmentCaptureCommand(names)], {
|
|
503
|
+
encoding: "utf8",
|
|
504
|
+
timeout: 5e3
|
|
505
|
+
});
|
|
506
|
+
const environment = {};
|
|
507
|
+
for (const name of names) {
|
|
508
|
+
const value = extractEnvironmentValue(output, name);
|
|
509
|
+
if (value !== void 0) environment[name] = value;
|
|
510
|
+
}
|
|
511
|
+
return environment;
|
|
512
|
+
};
|
|
513
|
+
const WindowsShellEnvironment = Context.Reference("@p4code/shared/shell/WindowsShellEnvironment", { defaultValue: () => readEnvironmentFromWindowsShell });
|
|
514
|
+
const CommandAvailability = Context.Reference("@p4code/shared/shell/CommandAvailability", { defaultValue: () => isCommandAvailable });
|
|
515
|
+
function readEnvironmentFromWindowsShell(names, optionsOrExecFile, maybeExecFile) {
|
|
516
|
+
if (names.length === 0) return {};
|
|
517
|
+
const options = typeof optionsOrExecFile === "function" ? {} : optionsOrExecFile ?? {};
|
|
518
|
+
const execFile = typeof optionsOrExecFile === "function" ? optionsOrExecFile : maybeExecFile ?? NodeChildProcess.execFileSync;
|
|
519
|
+
const command = buildWindowsEnvironmentCaptureCommand(names);
|
|
520
|
+
const args = [
|
|
521
|
+
"-NoLogo",
|
|
522
|
+
...options.loadProfile ? [] : ["-NoProfile"],
|
|
523
|
+
"-NonInteractive",
|
|
524
|
+
"-Command",
|
|
525
|
+
command
|
|
526
|
+
];
|
|
527
|
+
for (const shell of WINDOWS_SHELL_CANDIDATES) try {
|
|
528
|
+
const output = execFile(shell, args, {
|
|
529
|
+
encoding: "utf8",
|
|
530
|
+
timeout: 5e3
|
|
531
|
+
});
|
|
532
|
+
const environment = {};
|
|
533
|
+
for (const name of names) {
|
|
534
|
+
const value = extractEnvironmentValue(output, name);
|
|
535
|
+
if (value !== void 0) environment[name] = value;
|
|
536
|
+
}
|
|
537
|
+
return environment;
|
|
538
|
+
} catch {
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
return {};
|
|
542
|
+
}
|
|
543
|
+
function stripWrappingQuotes(value) {
|
|
544
|
+
return value.replace(/^"+|"+$/g, "");
|
|
545
|
+
}
|
|
546
|
+
function pathDelimiterForPlatform(platform) {
|
|
547
|
+
return platform === "win32" ? WINDOWS_PATH_DELIMITER : POSIX_PATH_DELIMITER;
|
|
548
|
+
}
|
|
549
|
+
function normalizePathEntryForComparison(entry, platform) {
|
|
550
|
+
const normalized = stripWrappingQuotes(entry.trim());
|
|
551
|
+
return platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
552
|
+
}
|
|
553
|
+
function mergePathValues(preferredPath, inheritedPath, platform) {
|
|
554
|
+
const delimiter = pathDelimiterForPlatform(platform);
|
|
555
|
+
const merged = [];
|
|
556
|
+
const seen = /* @__PURE__ */ new Set();
|
|
557
|
+
for (const rawValue of [preferredPath, inheritedPath]) {
|
|
558
|
+
if (!rawValue) continue;
|
|
559
|
+
for (const entry of rawValue.split(delimiter)) {
|
|
560
|
+
const trimmed = entry.trim();
|
|
561
|
+
if (trimmed.length === 0) continue;
|
|
562
|
+
const normalized = normalizePathEntryForComparison(trimmed, platform);
|
|
563
|
+
if (normalized.length === 0 || seen.has(normalized)) continue;
|
|
564
|
+
seen.add(normalized);
|
|
565
|
+
merged.push(trimmed);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return merged.length > 0 ? merged.join(delimiter) : void 0;
|
|
569
|
+
}
|
|
570
|
+
function readEnvPath(env) {
|
|
571
|
+
return env.PATH ?? env.Path ?? env.path;
|
|
572
|
+
}
|
|
573
|
+
function resolvePathEnvironmentVariable(env) {
|
|
574
|
+
return readEnvPath(env) ?? "";
|
|
575
|
+
}
|
|
576
|
+
function resolveWindowsPathExtensions(env) {
|
|
577
|
+
const rawValue = env.PATHEXT;
|
|
578
|
+
const fallback = [
|
|
579
|
+
".COM",
|
|
580
|
+
".EXE",
|
|
581
|
+
".BAT",
|
|
582
|
+
".CMD"
|
|
583
|
+
];
|
|
584
|
+
if (!rawValue) return fallback;
|
|
585
|
+
const parsed = [];
|
|
586
|
+
for (const entry of rawValue.split(";")) {
|
|
587
|
+
const trimmed = entry.trim();
|
|
588
|
+
if (trimmed.length === 0) continue;
|
|
589
|
+
parsed.push(trimmed.startsWith(".") ? trimmed.toUpperCase() : `.${trimmed.toUpperCase()}`);
|
|
590
|
+
}
|
|
591
|
+
return parsed.length > 0 ? Array.from(new Set(parsed)) : fallback;
|
|
592
|
+
}
|
|
593
|
+
function resolveCommandCandidates(command, platform, windowsPathExtensions, extname) {
|
|
594
|
+
if (platform !== "win32") return [command];
|
|
595
|
+
const extension = extname(command);
|
|
596
|
+
const normalizedExtension = extension.toUpperCase();
|
|
597
|
+
if (extension.length > 0 && windowsPathExtensions.includes(normalizedExtension)) {
|
|
598
|
+
const commandWithoutExtension = command.slice(0, -extension.length);
|
|
599
|
+
return Array.from(/* @__PURE__ */ new Set([
|
|
600
|
+
command,
|
|
601
|
+
`${commandWithoutExtension}${normalizedExtension}`,
|
|
602
|
+
`${commandWithoutExtension}${normalizedExtension.toLowerCase()}`
|
|
603
|
+
]));
|
|
604
|
+
}
|
|
605
|
+
const candidates = [];
|
|
606
|
+
for (const candidateExtension of windowsPathExtensions) {
|
|
607
|
+
candidates.push(`${command}${candidateExtension}`);
|
|
608
|
+
candidates.push(`${command}${candidateExtension.toLowerCase()}`);
|
|
609
|
+
}
|
|
610
|
+
return Array.from(new Set(candidates));
|
|
611
|
+
}
|
|
612
|
+
const isExecutableFile = Effect.fn("shell.isExecutableFile")(function* (filePath, platform, windowsPathExtensions) {
|
|
613
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
614
|
+
const path = yield* Path.Path;
|
|
615
|
+
const stat = yield* fileSystem.stat(filePath).pipe(Effect.orElseSucceed(() => null));
|
|
616
|
+
if (stat === null || stat.type !== "File") return false;
|
|
617
|
+
if (platform === "win32") {
|
|
618
|
+
const extension = path.extname(filePath);
|
|
619
|
+
if (extension.length === 0) return false;
|
|
620
|
+
return windowsPathExtensions.includes(extension.toUpperCase());
|
|
621
|
+
}
|
|
622
|
+
return canExecuteFile(filePath);
|
|
623
|
+
});
|
|
624
|
+
const resolveCommandPathForPlatform = Effect.fn("shell.resolveCommandPathForPlatform")(function* (command, options) {
|
|
625
|
+
const path = yield* Path.Path;
|
|
626
|
+
const platform = options.platform;
|
|
627
|
+
const env = options.env ?? process.env;
|
|
628
|
+
const windowsPathExtensions = platform === "win32" ? resolveWindowsPathExtensions(env) : [];
|
|
629
|
+
const commandCandidates = resolveCommandCandidates(command, platform, windowsPathExtensions, path.extname);
|
|
630
|
+
if (command.includes("/") || command.includes("\\")) {
|
|
631
|
+
for (const candidate of commandCandidates) if (yield* isExecutableFile(candidate, platform, windowsPathExtensions)) return candidate;
|
|
632
|
+
return yield* new CommandResolutionError({
|
|
633
|
+
command,
|
|
634
|
+
reason: "not-found"
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
const pathValue = resolvePathEnvironmentVariable(env);
|
|
638
|
+
if (pathValue.length === 0) return yield* new CommandResolutionError({
|
|
639
|
+
command,
|
|
640
|
+
reason: "not-found"
|
|
641
|
+
});
|
|
642
|
+
const pathEntries = [];
|
|
643
|
+
for (const entry of pathValue.split(pathDelimiterForPlatform(platform))) {
|
|
644
|
+
const pathEntry = stripWrappingQuotes(entry.trim());
|
|
645
|
+
if (pathEntry.length > 0) pathEntries.push(pathEntry);
|
|
646
|
+
}
|
|
647
|
+
for (const pathEntry of pathEntries) for (const candidate of commandCandidates) {
|
|
648
|
+
const candidatePath = path.join(pathEntry, candidate);
|
|
649
|
+
if (yield* isExecutableFile(candidatePath, platform, windowsPathExtensions)) return candidatePath;
|
|
650
|
+
}
|
|
651
|
+
return yield* new CommandResolutionError({
|
|
652
|
+
command,
|
|
653
|
+
reason: "not-found"
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
const resolveCommandPath = Effect.fn("shell.resolveCommandPath")(function* (command, options = {}) {
|
|
657
|
+
return yield* resolveCommandPathForPlatform(command, {
|
|
658
|
+
env: options.env ?? (yield* HostProcessEnvironment),
|
|
659
|
+
platform: yield* HostProcessPlatform
|
|
660
|
+
});
|
|
661
|
+
});
|
|
662
|
+
const resolveSpawnCommand = Effect.fn("shell.resolveSpawnCommand")(function* (command, args, options = {}) {
|
|
663
|
+
const platform = yield* HostProcessPlatform;
|
|
664
|
+
if (platform !== "win32") return {
|
|
665
|
+
command,
|
|
666
|
+
args: [...args],
|
|
667
|
+
shell: false
|
|
668
|
+
};
|
|
669
|
+
const hostEnvironment = yield* HostProcessEnvironment;
|
|
670
|
+
const env = options.env === void 0 ? hostEnvironment : options.extendEnv ? {
|
|
671
|
+
...hostEnvironment,
|
|
672
|
+
...options.env
|
|
673
|
+
} : options.env;
|
|
674
|
+
const resolvedCommand = (yield* SpawnExecutableResolution)(command, platform, env) ?? command;
|
|
675
|
+
const extension = NodePath.win32.extname(resolvedCommand).toLowerCase();
|
|
676
|
+
if (extension !== ".cmd" && extension !== ".bat") return {
|
|
677
|
+
command: resolvedCommand,
|
|
678
|
+
args: [...args],
|
|
679
|
+
shell: false
|
|
680
|
+
};
|
|
681
|
+
return {
|
|
682
|
+
command: escapeWindowsShellArg(resolvedCommand),
|
|
683
|
+
args: sanitizeShellModeArgsForPlatform(args, platform),
|
|
684
|
+
shell: true
|
|
685
|
+
};
|
|
686
|
+
});
|
|
687
|
+
const isCommandAvailable = Effect.fn("shell.isCommandAvailable")(function* (command, options = {}) {
|
|
688
|
+
return yield* resolveCommandPath(command, options).pipe(Effect.as(true), Effect.catchTag("CommandResolutionError", () => Effect.succeed(false)));
|
|
689
|
+
});
|
|
690
|
+
function resolveKnownWindowsCliDirs(env) {
|
|
691
|
+
const appData = env.APPDATA?.trim();
|
|
692
|
+
const localAppData = env.LOCALAPPDATA?.trim();
|
|
693
|
+
const userProfile = env.USERPROFILE?.trim();
|
|
694
|
+
return [
|
|
695
|
+
...appData ? [`${appData}\\npm`] : [],
|
|
696
|
+
...localAppData ? [`${localAppData}\\Programs\\nodejs`, `${localAppData}\\Volta\\bin`] : [],
|
|
697
|
+
...localAppData ? [`${localAppData}\\pnpm`] : [],
|
|
698
|
+
...userProfile ? [`${userProfile}\\.bun\\bin`, `${userProfile}\\scoop\\shims`] : []
|
|
699
|
+
];
|
|
700
|
+
}
|
|
701
|
+
function readWindowsEnvironmentSafely(readEnvironment, names, options) {
|
|
702
|
+
try {
|
|
703
|
+
return readEnvironment(names, options);
|
|
704
|
+
} catch {
|
|
705
|
+
return {};
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
function mergeWindowsEnv(currentEnv, patch) {
|
|
709
|
+
const nextEnv = { ...currentEnv };
|
|
710
|
+
for (const [key, value] of Object.entries(patch)) if (value !== void 0) nextEnv[key] = value;
|
|
711
|
+
return nextEnv;
|
|
712
|
+
}
|
|
713
|
+
const resolveWindowsEnvironment = Effect.fn("shell.resolveWindowsEnvironment")(function* (env) {
|
|
714
|
+
const readEnvironment = yield* WindowsShellEnvironment;
|
|
715
|
+
const commandAvailable = yield* CommandAvailability;
|
|
716
|
+
const inheritedPath = readEnvPath(env);
|
|
717
|
+
const shellPath = readWindowsEnvironmentSafely(readEnvironment, ["PATH"], { loadProfile: false }).PATH;
|
|
718
|
+
const mergedPath = mergePathValues(shellPath, inheritedPath, "win32");
|
|
719
|
+
const baselinePath = mergePathValues(resolveKnownWindowsCliDirs(env).join(WINDOWS_PATH_DELIMITER), mergedPath, "win32");
|
|
720
|
+
const baselinePatch = baselinePath ? { PATH: baselinePath } : {};
|
|
721
|
+
if (yield* commandAvailable("node", { env: mergeWindowsEnv(env, baselinePatch) })) return baselinePatch;
|
|
722
|
+
const profiledEnvironment = readWindowsEnvironmentSafely(readEnvironment, [
|
|
723
|
+
"PATH",
|
|
724
|
+
"FNM_DIR",
|
|
725
|
+
"FNM_MULTISHELL_PATH"
|
|
726
|
+
], { loadProfile: true });
|
|
727
|
+
const profiledPath = mergePathValues(profiledEnvironment.PATH, baselinePath, "win32");
|
|
728
|
+
const profiledPatch = {
|
|
729
|
+
...profiledPath ? { PATH: profiledPath } : {},
|
|
730
|
+
...profiledEnvironment.FNM_DIR ? { FNM_DIR: profiledEnvironment.FNM_DIR } : {},
|
|
731
|
+
...profiledEnvironment.FNM_MULTISHELL_PATH ? { FNM_MULTISHELL_PATH: profiledEnvironment.FNM_MULTISHELL_PATH } : {}
|
|
732
|
+
};
|
|
733
|
+
return Object.keys(profiledPatch).length > 0 ? {
|
|
734
|
+
...baselinePatch,
|
|
735
|
+
...profiledPatch
|
|
736
|
+
} : baselinePatch;
|
|
737
|
+
});
|
|
738
|
+
//#endregion
|
|
739
|
+
//#region src/os-jank.ts
|
|
740
|
+
function logPathHydrationWarning(message, error) {
|
|
741
|
+
process.stderr.write(`[server] ${message} ${error instanceof Error ? error.message : error ?? ""}\n`);
|
|
742
|
+
}
|
|
743
|
+
function hydratePosixPath(env, platform) {
|
|
744
|
+
let shellPath;
|
|
745
|
+
for (const shell of listLoginShellCandidates(platform, env.SHELL)) {
|
|
746
|
+
try {
|
|
747
|
+
shellPath = readPathFromLoginShell(shell);
|
|
748
|
+
} catch (error) {
|
|
749
|
+
logPathHydrationWarning(`Failed to read PATH from login shell ${shell}.`, error);
|
|
750
|
+
}
|
|
751
|
+
if (shellPath) break;
|
|
752
|
+
}
|
|
753
|
+
const launchctlPath = platform === "darwin" && !shellPath ? readPathFromLaunchctl() : void 0;
|
|
754
|
+
const mergedPath = mergePathEntries(shellPath ?? launchctlPath, env.PATH, platform);
|
|
755
|
+
if (mergedPath) env.PATH = mergedPath;
|
|
756
|
+
}
|
|
757
|
+
const fixPath = Effect.fn("fixPath")(function* () {
|
|
758
|
+
const platform = yield* HostProcessPlatform;
|
|
759
|
+
const env = yield* HostProcessEnvironment;
|
|
760
|
+
if (platform === "win32") {
|
|
761
|
+
const repairedEnvironment = yield* resolveWindowsEnvironment(env).pipe(Effect.catchDefect((defect) => Effect.sync(() => {
|
|
762
|
+
logPathHydrationWarning("Failed to hydrate PATH from the user environment.", defect);
|
|
763
|
+
return {};
|
|
764
|
+
})));
|
|
765
|
+
for (const [key, value] of Object.entries(repairedEnvironment)) if (value !== void 0) env[key] = value;
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
if (platform !== "darwin" && platform !== "linux") return;
|
|
769
|
+
yield* Effect.sync(() => hydratePosixPath(env, platform)).pipe(Effect.catchDefect((defect) => Effect.sync(() => {
|
|
770
|
+
logPathHydrationWarning("Failed to hydrate PATH from the user environment.", defect);
|
|
771
|
+
})));
|
|
772
|
+
});
|
|
773
|
+
const expandHomePath$4 = Effect.fn(function* (input) {
|
|
774
|
+
const { join } = yield* Path.Path;
|
|
775
|
+
if (input === "~") return NodeOS.homedir();
|
|
776
|
+
if (input.startsWith("~/") || input.startsWith("~\\")) return join(NodeOS.homedir(), input.slice(2));
|
|
777
|
+
return input;
|
|
778
|
+
});
|
|
779
|
+
/** The data directory used when neither `--base-dir` nor `P4CODE_HOME` is set. */
|
|
780
|
+
const defaultBaseDir = Effect.fn(function* () {
|
|
781
|
+
const { join } = yield* Path.Path;
|
|
782
|
+
return join(NodeOS.homedir(), ".p4");
|
|
783
|
+
});
|
|
784
|
+
const resolveBaseDir = Effect.fn(function* (raw) {
|
|
785
|
+
const { resolve } = yield* Path.Path;
|
|
786
|
+
if (!raw || raw.trim().length === 0) return yield* defaultBaseDir();
|
|
787
|
+
return resolve(yield* expandHomePath$4(raw.trim()));
|
|
788
|
+
});
|
|
789
|
+
//#endregion
|
|
790
|
+
//#region ../../packages/shared/src/semver.ts
|
|
791
|
+
const SEMVER_NUMBER_SEGMENT = /^\d+$/;
|
|
792
|
+
function normalizeSemverVersion(version) {
|
|
793
|
+
const [main, prerelease] = version.trim().split("-", 2);
|
|
794
|
+
const segments = [];
|
|
795
|
+
for (const segment of (main ?? "").split(".")) {
|
|
796
|
+
const trimmed = segment.trim();
|
|
797
|
+
if (trimmed.length > 0) segments.push(trimmed);
|
|
798
|
+
}
|
|
799
|
+
if (segments.length === 2) segments.push("0");
|
|
800
|
+
return prerelease ? `${segments.join(".")}-${prerelease}` : segments.join(".");
|
|
801
|
+
}
|
|
802
|
+
function parseSemver(value) {
|
|
803
|
+
const [main = "", prerelease] = normalizeSemverVersion(value).replace(/^v/, "").split("-", 2);
|
|
804
|
+
const segments = main.split(".");
|
|
805
|
+
if (segments.length !== 3) return null;
|
|
806
|
+
const [majorSegment, minorSegment, patchSegment] = segments;
|
|
807
|
+
if (majorSegment === void 0 || minorSegment === void 0 || patchSegment === void 0) return null;
|
|
808
|
+
if (!SEMVER_NUMBER_SEGMENT.test(majorSegment) || !SEMVER_NUMBER_SEGMENT.test(minorSegment) || !SEMVER_NUMBER_SEGMENT.test(patchSegment)) return null;
|
|
809
|
+
const major = Number.parseInt(majorSegment, 10);
|
|
810
|
+
const minor = Number.parseInt(minorSegment, 10);
|
|
811
|
+
const patch = Number.parseInt(patchSegment, 10);
|
|
812
|
+
if (![
|
|
813
|
+
major,
|
|
814
|
+
minor,
|
|
815
|
+
patch
|
|
816
|
+
].every(Number.isInteger)) return null;
|
|
817
|
+
return {
|
|
818
|
+
major,
|
|
819
|
+
minor,
|
|
820
|
+
patch,
|
|
821
|
+
prerelease: parsePrereleaseSegments(prerelease)
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
function parsePrereleaseSegments(prerelease) {
|
|
825
|
+
if (prerelease === void 0) return [];
|
|
826
|
+
const segments = [];
|
|
827
|
+
for (const segment of prerelease.split(".")) {
|
|
828
|
+
const trimmed = segment.trim();
|
|
829
|
+
if (trimmed.length > 0) segments.push(trimmed);
|
|
830
|
+
}
|
|
831
|
+
return segments;
|
|
832
|
+
}
|
|
833
|
+
function comparePrereleaseIdentifier(left, right) {
|
|
834
|
+
const leftNumeric = SEMVER_NUMBER_SEGMENT.test(left);
|
|
835
|
+
const rightNumeric = SEMVER_NUMBER_SEGMENT.test(right);
|
|
836
|
+
if (leftNumeric && rightNumeric) return Number.parseInt(left, 10) - Number.parseInt(right, 10);
|
|
837
|
+
if (leftNumeric) return -1;
|
|
838
|
+
if (rightNumeric) return 1;
|
|
839
|
+
return left.localeCompare(right);
|
|
840
|
+
}
|
|
841
|
+
function compareSemverVersions(left, right) {
|
|
842
|
+
const parsedLeft = parseSemver(left);
|
|
843
|
+
const parsedRight = parseSemver(right);
|
|
844
|
+
if (!parsedLeft || !parsedRight) return left.localeCompare(right);
|
|
845
|
+
if (parsedLeft.major !== parsedRight.major) return parsedLeft.major - parsedRight.major;
|
|
846
|
+
if (parsedLeft.minor !== parsedRight.minor) return parsedLeft.minor - parsedRight.minor;
|
|
847
|
+
if (parsedLeft.patch !== parsedRight.patch) return parsedLeft.patch - parsedRight.patch;
|
|
848
|
+
if (parsedLeft.prerelease.length === 0 && parsedRight.prerelease.length === 0) return 0;
|
|
849
|
+
if (parsedLeft.prerelease.length === 0) return 1;
|
|
850
|
+
if (parsedRight.prerelease.length === 0) return -1;
|
|
851
|
+
const length = Math.max(parsedLeft.prerelease.length, parsedRight.prerelease.length);
|
|
852
|
+
for (let index = 0; index < length; index += 1) {
|
|
853
|
+
const leftIdentifier = parsedLeft.prerelease[index];
|
|
854
|
+
const rightIdentifier = parsedRight.prerelease[index];
|
|
855
|
+
if (leftIdentifier === void 0) return -1;
|
|
856
|
+
if (rightIdentifier === void 0) return 1;
|
|
857
|
+
const comparison = comparePrereleaseIdentifier(leftIdentifier, rightIdentifier);
|
|
858
|
+
if (comparison !== 0) return comparison;
|
|
859
|
+
}
|
|
860
|
+
return 0;
|
|
861
|
+
}
|
|
862
|
+
//#endregion
|
|
863
|
+
//#region src/cli/updateCheck.ts
|
|
864
|
+
/**
|
|
865
|
+
* Tells the user when a newer `@p4code/cli` has been published.
|
|
866
|
+
*
|
|
867
|
+
* Deliberately advisory and cheap: at most one registry request a day, a short
|
|
868
|
+
* timeout, every failure swallowed, and never anything that changes an exit
|
|
869
|
+
* code. A version check that can break a command is worse than no check.
|
|
870
|
+
*/
|
|
871
|
+
const PACKAGE_NAME = "@p4code/cli";
|
|
872
|
+
const CHECK_INTERVAL = Duration.hours(24);
|
|
873
|
+
const REQUEST_TIMEOUT = Duration.seconds(3);
|
|
874
|
+
/**
|
|
875
|
+
* A failed lookup is retried far sooner than a successful one. Caching "no
|
|
876
|
+
* answer" for a full day would let one cold-start timeout hide a real update
|
|
877
|
+
* until tomorrow, which is the opposite of the point.
|
|
878
|
+
*/
|
|
879
|
+
const FAILURE_RETRY_INTERVAL = Duration.hours(1);
|
|
880
|
+
const CACHE_FILE = "cli-update-check.json";
|
|
881
|
+
const CacheEntry = Schema$1.Struct({
|
|
882
|
+
checkedAtMs: Schema$1.Number,
|
|
883
|
+
latestVersion: Schema$1.NullOr(Schema$1.String)
|
|
884
|
+
});
|
|
885
|
+
const CacheEntryJson = Schema$1.fromJsonString(CacheEntry);
|
|
886
|
+
const decodeCacheEntry = Schema$1.decodeUnknownEffect(CacheEntryJson);
|
|
887
|
+
const encodeCacheEntry = Schema$1.encodeEffect(CacheEntryJson);
|
|
888
|
+
const NpmLatest = Schema$1.Struct({ version: Schema$1.optional(Schema$1.String) });
|
|
889
|
+
const fetchLatestVersion = Effect.fn("cli.updateCheck.fetch")(function* () {
|
|
890
|
+
const client = yield* HttpClient.HttpClient;
|
|
891
|
+
const request = HttpClientRequest.get(`https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME)}/latest`).pipe(HttpClientRequest.setHeader("accept", "application/json"));
|
|
892
|
+
const response = yield* client.execute(request).pipe(Effect.timeout(REQUEST_TIMEOUT));
|
|
893
|
+
if (response.status < 200 || response.status >= 300) return null;
|
|
894
|
+
const version = (yield* response.json.pipe(Effect.flatMap(Schema$1.decodeUnknownEffect(NpmLatest)))).version?.trim();
|
|
895
|
+
return version === void 0 || version.length === 0 ? null : version;
|
|
896
|
+
});
|
|
897
|
+
/**
|
|
898
|
+
* Reads the cached answer, refreshing it at most once per CHECK_INTERVAL.
|
|
899
|
+
* Returns the newest published version, or null when it is unknown.
|
|
900
|
+
*/
|
|
901
|
+
const resolveLatestVersion = Effect.fn("cli.updateCheck.resolve")(function* (stateDir) {
|
|
902
|
+
const fs = yield* FileSystem.FileSystem;
|
|
903
|
+
const cachePath = (yield* Path.Path).join(stateDir, CACHE_FILE);
|
|
904
|
+
const nowMs = DateTime.toEpochMillis(yield* DateTime.now);
|
|
905
|
+
const cached = yield* fs.readFileString(cachePath).pipe(Effect.flatMap(decodeCacheEntry), Effect.asSome, Effect.orElseSucceed(() => Option.none()));
|
|
906
|
+
if (Option.isSome(cached)) {
|
|
907
|
+
const age = nowMs - cached.value.checkedAtMs;
|
|
908
|
+
const interval = cached.value.latestVersion === null ? FAILURE_RETRY_INTERVAL : CHECK_INTERVAL;
|
|
909
|
+
if (age >= 0 && age < Duration.toMillis(interval)) return cached.value.latestVersion;
|
|
910
|
+
}
|
|
911
|
+
const latestVersion = yield* fetchLatestVersion().pipe(Effect.orElseSucceed(() => null));
|
|
912
|
+
yield* fs.makeDirectory(stateDir, { recursive: true }).pipe(Effect.ignore);
|
|
913
|
+
yield* encodeCacheEntry({
|
|
914
|
+
checkedAtMs: nowMs,
|
|
915
|
+
latestVersion
|
|
916
|
+
}).pipe(Effect.flatMap((encoded) => fs.writeFileString(cachePath, encoded)), Effect.ignore);
|
|
917
|
+
return latestVersion;
|
|
918
|
+
});
|
|
919
|
+
function formatUpdateReminder(input) {
|
|
920
|
+
return [`Update available: ${PACKAGE_NAME}@${input.latestVersion} (running ${input.currentVersion}).`, ` npm i -g ${PACKAGE_NAME}@latest && p4 service update`].join("\n");
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* The reminder line, or null when there is nothing to say. Callers print it;
|
|
924
|
+
* keeping the decision pure makes it testable without a console.
|
|
925
|
+
*/
|
|
926
|
+
const resolveUpdateReminder = Effect.fn("cli.updateCheck.reminder")(function* (input) {
|
|
927
|
+
if (((yield* HostProcessEnvironment)["P4CODE_NO_UPDATE_CHECK"] ?? "") !== "") return null;
|
|
928
|
+
if (input.currentVersion.includes("-")) return null;
|
|
929
|
+
const latestVersion = yield* resolveLatestVersion(input.stateDir);
|
|
930
|
+
if (latestVersion === null) return null;
|
|
931
|
+
if (compareSemverVersions(input.currentVersion, latestVersion) >= 0) return null;
|
|
932
|
+
return formatUpdateReminder({
|
|
933
|
+
currentVersion: input.currentVersion,
|
|
934
|
+
latestVersion
|
|
935
|
+
});
|
|
936
|
+
});
|
|
236
937
|
//#endregion
|
|
237
938
|
//#region ../../packages/contracts/src/baseSchemas.ts
|
|
238
939
|
const TrimmedString = Schema$1.String.pipe(Schema$1.decodeTo(Schema$1.String, SchemaTransformation.transformOrFail({
|
|
@@ -928,7 +1629,7 @@ const ModelSelection = Schema$1.Struct({
|
|
|
928
1629
|
return Effect.succeed(base);
|
|
929
1630
|
}
|
|
930
1631
|
})));
|
|
931
|
-
const RuntimeMode
|
|
1632
|
+
const RuntimeMode = Schema$1.Literals([
|
|
932
1633
|
"approval-required",
|
|
933
1634
|
"auto-accept-edits",
|
|
934
1635
|
"auto",
|
|
@@ -1050,7 +1751,7 @@ const OrchestrationSession = Schema$1.Struct({
|
|
|
1050
1751
|
status: OrchestrationSessionStatus,
|
|
1051
1752
|
providerName: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1052
1753
|
providerInstanceId: Schema$1.optional(ProviderInstanceId),
|
|
1053
|
-
runtimeMode: RuntimeMode
|
|
1754
|
+
runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
|
|
1054
1755
|
activeTurnId: Schema$1.NullOr(TurnId),
|
|
1055
1756
|
lastError: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1056
1757
|
updatedAt: IsoDateTime
|
|
@@ -1111,7 +1812,7 @@ const OrchestrationThread = Schema$1.Struct({
|
|
|
1111
1812
|
projectId: ProjectId,
|
|
1112
1813
|
title: TrimmedNonEmptyString,
|
|
1113
1814
|
modelSelection: ModelSelection,
|
|
1114
|
-
runtimeMode: RuntimeMode
|
|
1815
|
+
runtimeMode: RuntimeMode,
|
|
1115
1816
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1116
1817
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1117
1818
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
@@ -1151,7 +1852,7 @@ const OrchestrationThreadShell = Schema$1.Struct({
|
|
|
1151
1852
|
projectId: ProjectId,
|
|
1152
1853
|
title: TrimmedNonEmptyString,
|
|
1153
1854
|
modelSelection: ModelSelection,
|
|
1154
|
-
runtimeMode: RuntimeMode
|
|
1855
|
+
runtimeMode: RuntimeMode,
|
|
1155
1856
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1156
1857
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1157
1858
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
@@ -1273,7 +1974,7 @@ const ThreadCreateCommand = Schema$1.Struct({
|
|
|
1273
1974
|
projectId: ProjectId,
|
|
1274
1975
|
title: TrimmedNonEmptyString,
|
|
1275
1976
|
modelSelection: ModelSelection,
|
|
1276
|
-
runtimeMode: RuntimeMode
|
|
1977
|
+
runtimeMode: RuntimeMode,
|
|
1277
1978
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1278
1979
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1279
1980
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
@@ -1331,7 +2032,7 @@ const ThreadRuntimeModeSetCommand = Schema$1.Struct({
|
|
|
1331
2032
|
type: Schema$1.Literal("thread.runtime-mode.set"),
|
|
1332
2033
|
commandId: CommandId,
|
|
1333
2034
|
threadId: ThreadId,
|
|
1334
|
-
runtimeMode: RuntimeMode
|
|
2035
|
+
runtimeMode: RuntimeMode,
|
|
1335
2036
|
createdAt: IsoDateTime
|
|
1336
2037
|
});
|
|
1337
2038
|
const ThreadInteractionModeSetCommand = Schema$1.Struct({
|
|
@@ -1345,7 +2046,7 @@ const ThreadTurnStartBootstrapCreateThread = Schema$1.Struct({
|
|
|
1345
2046
|
projectId: ProjectId,
|
|
1346
2047
|
title: TrimmedNonEmptyString,
|
|
1347
2048
|
modelSelection: ModelSelection,
|
|
1348
|
-
runtimeMode: RuntimeMode
|
|
2049
|
+
runtimeMode: RuntimeMode,
|
|
1349
2050
|
interactionMode: ProviderInteractionMode,
|
|
1350
2051
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1351
2052
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
@@ -1374,7 +2075,7 @@ const ThreadTurnStartCommand = Schema$1.Struct({
|
|
|
1374
2075
|
}),
|
|
1375
2076
|
modelSelection: Schema$1.optional(ModelSelection),
|
|
1376
2077
|
titleSeed: Schema$1.optional(TrimmedNonEmptyString),
|
|
1377
|
-
runtimeMode: RuntimeMode
|
|
2078
|
+
runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
|
|
1378
2079
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1379
2080
|
bootstrap: Schema$1.optional(ThreadTurnStartBootstrap),
|
|
1380
2081
|
sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
|
|
@@ -1392,7 +2093,7 @@ const ClientThreadTurnStartCommand = Schema$1.Struct({
|
|
|
1392
2093
|
}),
|
|
1393
2094
|
modelSelection: Schema$1.optional(ModelSelection),
|
|
1394
2095
|
titleSeed: Schema$1.optional(TrimmedNonEmptyString),
|
|
1395
|
-
runtimeMode: RuntimeMode
|
|
2096
|
+
runtimeMode: RuntimeMode,
|
|
1396
2097
|
interactionMode: ProviderInteractionMode,
|
|
1397
2098
|
bootstrap: Schema$1.optional(ThreadTurnStartBootstrap),
|
|
1398
2099
|
sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
|
|
@@ -1608,7 +2309,7 @@ const ThreadCreatedPayload$1 = Schema$1.Struct({
|
|
|
1608
2309
|
projectId: ProjectId,
|
|
1609
2310
|
title: TrimmedNonEmptyString,
|
|
1610
2311
|
modelSelection: ModelSelection,
|
|
1611
|
-
runtimeMode: RuntimeMode
|
|
2312
|
+
runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
|
|
1612
2313
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1613
2314
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1614
2315
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
@@ -1659,7 +2360,7 @@ const ThreadMetaUpdatedPayload$1 = Schema$1.Struct({
|
|
|
1659
2360
|
});
|
|
1660
2361
|
const ThreadRuntimeModeSetPayload$1 = Schema$1.Struct({
|
|
1661
2362
|
threadId: ThreadId,
|
|
1662
|
-
runtimeMode: RuntimeMode
|
|
2363
|
+
runtimeMode: RuntimeMode,
|
|
1663
2364
|
updatedAt: IsoDateTime
|
|
1664
2365
|
});
|
|
1665
2366
|
const ThreadInteractionModeSetPayload$1 = Schema$1.Struct({
|
|
@@ -1683,7 +2384,7 @@ const ThreadTurnStartRequestedPayload = Schema$1.Struct({
|
|
|
1683
2384
|
messageId: MessageId,
|
|
1684
2385
|
modelSelection: Schema$1.optional(ModelSelection),
|
|
1685
2386
|
titleSeed: Schema$1.optional(TrimmedNonEmptyString),
|
|
1686
|
-
runtimeMode: RuntimeMode
|
|
2387
|
+
runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
|
|
1687
2388
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1688
2389
|
sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
|
|
1689
2390
|
createdAt: IsoDateTime
|
|
@@ -3801,7 +4502,7 @@ Schema$1.Struct({
|
|
|
3801
4502
|
provider: ProviderDriverKind,
|
|
3802
4503
|
providerInstanceId: Schema$1.optional(ProviderInstanceId),
|
|
3803
4504
|
status: ProviderSessionStatus,
|
|
3804
|
-
runtimeMode: RuntimeMode
|
|
4505
|
+
runtimeMode: RuntimeMode,
|
|
3805
4506
|
cwd: Schema$1.optional(TrimmedNonEmptyString),
|
|
3806
4507
|
model: Schema$1.optional(TrimmedNonEmptyString),
|
|
3807
4508
|
threadId: ThreadId,
|
|
@@ -3820,7 +4521,7 @@ const ProviderSessionStartInput = Schema$1.Struct({
|
|
|
3820
4521
|
resumeCursor: Schema$1.optional(Schema$1.Unknown),
|
|
3821
4522
|
approvalPolicy: Schema$1.optional(ProviderApprovalPolicy),
|
|
3822
4523
|
sandboxMode: Schema$1.optional(ProviderSandboxMode),
|
|
3823
|
-
runtimeMode: RuntimeMode
|
|
4524
|
+
runtimeMode: RuntimeMode
|
|
3824
4525
|
});
|
|
3825
4526
|
const ProviderSendTurnInput = Schema$1.Struct({
|
|
3826
4527
|
threadId: ThreadId,
|
|
@@ -5371,7 +6072,7 @@ const ServerSignalProcessResult = Schema$1.Struct({
|
|
|
5371
6072
|
signaled: Schema$1.Boolean,
|
|
5372
6073
|
message: Schema$1.Option(TrimmedNonEmptyString)
|
|
5373
6074
|
});
|
|
5374
|
-
const ServerConfig
|
|
6075
|
+
const ServerConfig = Schema$1.Struct({
|
|
5375
6076
|
environment: ExecutionEnvironmentDescriptor,
|
|
5376
6077
|
auth: ServerAuthDescriptor,
|
|
5377
6078
|
cwd: TrimmedNonEmptyString,
|
|
@@ -5418,7 +6119,7 @@ const ServerConfigSettingsUpdatedPayload = Schema$1.Struct({ settings: ServerSet
|
|
|
5418
6119
|
const ServerConfigStreamSnapshotEvent = Schema$1.Struct({
|
|
5419
6120
|
version: Schema$1.Literal(1),
|
|
5420
6121
|
type: Schema$1.Literal("snapshot"),
|
|
5421
|
-
config: ServerConfig
|
|
6122
|
+
config: ServerConfig
|
|
5422
6123
|
});
|
|
5423
6124
|
const ServerConfigStreamKeybindingsUpdatedEvent = Schema$1.Struct({
|
|
5424
6125
|
version: Schema$1.Literal(1),
|
|
@@ -6623,7 +7324,7 @@ const WsServerProbeRpc = Rpc.make(WS_METHODS.serverProbe, {
|
|
|
6623
7324
|
});
|
|
6624
7325
|
const WsServerGetConfigRpc = Rpc.make(WS_METHODS.serverGetConfig, {
|
|
6625
7326
|
payload: Schema$1.Struct({}),
|
|
6626
|
-
success: ServerConfig
|
|
7327
|
+
success: ServerConfig,
|
|
6627
7328
|
error: Schema$1.Union([
|
|
6628
7329
|
KeybindingsConfigError,
|
|
6629
7330
|
ServerSettingsError,
|
|
@@ -7006,117 +7707,6 @@ function parseAllowedOAuthScope(input) {
|
|
|
7006
7707
|
return scopes;
|
|
7007
7708
|
}
|
|
7008
7709
|
//#endregion
|
|
7009
|
-
//#region src/config.ts
|
|
7010
|
-
/**
|
|
7011
|
-
* ServerConfig - Runtime configuration services.
|
|
7012
|
-
*
|
|
7013
|
-
* Defines process-level server configuration and networking helpers used by
|
|
7014
|
-
* startup and runtime layers.
|
|
7015
|
-
*
|
|
7016
|
-
* @module ServerConfig
|
|
7017
|
-
*/
|
|
7018
|
-
const DEFAULT_PORT = 3773;
|
|
7019
|
-
const RuntimeMode = Schema$1.Literals(["web", "desktop"]);
|
|
7020
|
-
Schema$1.Literals(["browser", "headless"]);
|
|
7021
|
-
/**
|
|
7022
|
-
* ServerConfig - Service tag for server runtime configuration.
|
|
7023
|
-
*/
|
|
7024
|
-
var ServerConfig = class extends Context.Service()("@p4code/cli/config/ServerConfig") {
|
|
7025
|
-
/** @deprecated Import and use `layerTest` from this module. */
|
|
7026
|
-
static layerTest = (cwd, baseDirOrPrefix) => layerTest$2(cwd, baseDirOrPrefix);
|
|
7027
|
-
};
|
|
7028
|
-
const make$66 = (config) => ServerConfig.of(config);
|
|
7029
|
-
const layer$61 = (config) => Layer.succeed(ServerConfig, make$66(config));
|
|
7030
|
-
const deriveServerPaths = Effect.fn(function* (baseDir, devUrl, options = {}) {
|
|
7031
|
-
const { join } = yield* Path.Path;
|
|
7032
|
-
const stateDir = join(baseDir, devUrl !== void 0 && !options.baseDirIsExplicit ? "dev" : "userdata");
|
|
7033
|
-
const dbPath = join(stateDir, "state.sqlite");
|
|
7034
|
-
const attachmentsDir = join(stateDir, "attachments");
|
|
7035
|
-
const logsDir = join(stateDir, "logs");
|
|
7036
|
-
const providerLogsDir = join(logsDir, "provider");
|
|
7037
|
-
const providerStatusCacheDir = join(baseDir, "caches");
|
|
7038
|
-
return {
|
|
7039
|
-
stateDir,
|
|
7040
|
-
dbPath,
|
|
7041
|
-
keybindingsConfigPath: join(stateDir, "keybindings.json"),
|
|
7042
|
-
settingsPath: join(stateDir, "settings.json"),
|
|
7043
|
-
providerStatusCacheDir,
|
|
7044
|
-
worktreesDir: join(baseDir, "worktrees"),
|
|
7045
|
-
attachmentsDir,
|
|
7046
|
-
logsDir,
|
|
7047
|
-
serverLogPath: join(logsDir, "server.log"),
|
|
7048
|
-
serverTracePath: join(logsDir, "server.trace.ndjson"),
|
|
7049
|
-
providerLogsDir,
|
|
7050
|
-
providerEventLogPath: join(providerLogsDir, "events.log"),
|
|
7051
|
-
terminalLogsDir: join(logsDir, "terminals"),
|
|
7052
|
-
anonymousIdPath: join(stateDir, "anonymous-id"),
|
|
7053
|
-
environmentIdPath: join(stateDir, "environment-id"),
|
|
7054
|
-
serverRuntimeStatePath: join(stateDir, "server-runtime.json"),
|
|
7055
|
-
secretsDir: join(stateDir, "secrets")
|
|
7056
|
-
};
|
|
7057
|
-
});
|
|
7058
|
-
const ensureServerDirectories = Effect.fn(function* (derivedPaths) {
|
|
7059
|
-
const fs = yield* FileSystem.FileSystem;
|
|
7060
|
-
const path = yield* Path.Path;
|
|
7061
|
-
yield* Effect.all([
|
|
7062
|
-
fs.makeDirectory(derivedPaths.stateDir, { recursive: true }),
|
|
7063
|
-
fs.makeDirectory(derivedPaths.logsDir, { recursive: true }),
|
|
7064
|
-
fs.makeDirectory(derivedPaths.providerLogsDir, { recursive: true }),
|
|
7065
|
-
fs.makeDirectory(derivedPaths.terminalLogsDir, { recursive: true }),
|
|
7066
|
-
fs.makeDirectory(derivedPaths.attachmentsDir, { recursive: true }),
|
|
7067
|
-
fs.makeDirectory(derivedPaths.worktreesDir, { recursive: true }),
|
|
7068
|
-
fs.makeDirectory(path.dirname(derivedPaths.keybindingsConfigPath), { recursive: true }),
|
|
7069
|
-
fs.makeDirectory(path.dirname(derivedPaths.settingsPath), { recursive: true }),
|
|
7070
|
-
fs.makeDirectory(derivedPaths.providerStatusCacheDir, { recursive: true }),
|
|
7071
|
-
fs.makeDirectory(path.dirname(derivedPaths.anonymousIdPath), { recursive: true }),
|
|
7072
|
-
fs.makeDirectory(path.dirname(derivedPaths.serverRuntimeStatePath), { recursive: true })
|
|
7073
|
-
], { concurrency: "unbounded" });
|
|
7074
|
-
});
|
|
7075
|
-
const makeTest$1 = Effect.fn("ServerConfig.makeTest")(function* (cwd, baseDirOrPrefix) {
|
|
7076
|
-
const devUrl = void 0;
|
|
7077
|
-
const fs = yield* FileSystem.FileSystem;
|
|
7078
|
-
const baseDir = typeof baseDirOrPrefix === "string" ? baseDirOrPrefix : yield* fs.makeTempDirectoryScoped({ prefix: baseDirOrPrefix.prefix });
|
|
7079
|
-
const derivedPaths = yield* deriveServerPaths(baseDir, devUrl);
|
|
7080
|
-
yield* ensureServerDirectories(derivedPaths);
|
|
7081
|
-
return ServerConfig.of({
|
|
7082
|
-
logLevel: "Error",
|
|
7083
|
-
traceMinLevel: "Info",
|
|
7084
|
-
traceTimingEnabled: true,
|
|
7085
|
-
traceBatchWindowMs: 200,
|
|
7086
|
-
traceMaxBytes: 10 * 1024 * 1024,
|
|
7087
|
-
traceMaxFiles: 10,
|
|
7088
|
-
otlpTracesUrl: void 0,
|
|
7089
|
-
otlpMetricsUrl: void 0,
|
|
7090
|
-
otlpExportIntervalMs: 1e4,
|
|
7091
|
-
otlpServiceName: "p4-server",
|
|
7092
|
-
cwd,
|
|
7093
|
-
baseDir,
|
|
7094
|
-
...derivedPaths,
|
|
7095
|
-
mode: "web",
|
|
7096
|
-
autoBootstrapProjectFromCwd: false,
|
|
7097
|
-
logWebSocketEvents: false,
|
|
7098
|
-
tailscaleServeEnabled: false,
|
|
7099
|
-
tailscaleServePort: 443,
|
|
7100
|
-
port: 0,
|
|
7101
|
-
host: void 0,
|
|
7102
|
-
desktopBootstrapToken: void 0,
|
|
7103
|
-
staticDir: void 0,
|
|
7104
|
-
devUrl,
|
|
7105
|
-
devAllowedOrigins: [],
|
|
7106
|
-
noBrowser: false,
|
|
7107
|
-
startupPresentation: "browser"
|
|
7108
|
-
});
|
|
7109
|
-
});
|
|
7110
|
-
const layerTest$2 = (cwd, baseDirOrPrefix) => Layer.effect(ServerConfig, makeTest$1(cwd, baseDirOrPrefix));
|
|
7111
|
-
const resolveStaticDir = Effect.fn(function* () {
|
|
7112
|
-
const { join, resolve } = yield* Path.Path;
|
|
7113
|
-
const { exists } = yield* FileSystem.FileSystem;
|
|
7114
|
-
const bundledClient = resolve(join(import.meta.dirname, "client"));
|
|
7115
|
-
if (yield* exists(join(bundledClient, "index.html")).pipe(Effect.orElseSucceed(() => false))) return bundledClient;
|
|
7116
|
-
const monorepoClient = resolve(join(import.meta.dirname, "../../web/dist"));
|
|
7117
|
-
if (yield* exists(join(monorepoClient, "index.html")).pipe(Effect.orElseSucceed(() => false))) return monorepoClient;
|
|
7118
|
-
});
|
|
7119
|
-
//#endregion
|
|
7120
7710
|
//#region src/auth/utils.ts
|
|
7121
7711
|
const SESSION_COOKIE_NAME = "p4_session";
|
|
7122
7712
|
/**
|
|
@@ -7220,7 +7810,7 @@ function deriveAuthClientMetadata(input) {
|
|
|
7220
7810
|
//#region src/auth/EnvironmentAuthPolicy.ts
|
|
7221
7811
|
var EnvironmentAuthPolicy = class extends Context.Service()("@p4code/cli/auth/EnvironmentAuthPolicy") {};
|
|
7222
7812
|
const make$65 = Effect.gen(function* () {
|
|
7223
|
-
const config = yield* ServerConfig;
|
|
7813
|
+
const config = yield* ServerConfig$1;
|
|
7224
7814
|
const isRemoteReachable = isRemoteReachableHost(config.host);
|
|
7225
7815
|
const policy = config.mode === "desktop" ? isRemoteReachable ? "remote-reachable" : "desktop-managed-local" : isRemoteReachable ? "remote-reachable" : "loopback-browser";
|
|
7226
7816
|
const descriptor = {
|
|
@@ -7599,7 +8189,7 @@ const PAIRING_TOKEN_LENGTH = 12;
|
|
|
7599
8189
|
const PAIRING_TOKEN_REJECTION_LIMIT = Math.floor(256 / 32) * 32;
|
|
7600
8190
|
const make$63 = Effect.gen(function* () {
|
|
7601
8191
|
const crypto = yield* Crypto.Crypto;
|
|
7602
|
-
const config = yield* ServerConfig;
|
|
8192
|
+
const config = yield* ServerConfig$1;
|
|
7603
8193
|
const pairingLinks = yield* AuthPairingLinkRepository;
|
|
7604
8194
|
const seededGrantsRef = yield* Ref.make(/* @__PURE__ */ new Map());
|
|
7605
8195
|
const changesPubSub = yield* PubSub.unbounded();
|
|
@@ -7866,7 +8456,7 @@ const make$62 = Effect.gen(function* () {
|
|
|
7866
8456
|
const crypto = yield* Crypto.Crypto;
|
|
7867
8457
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
7868
8458
|
const path = yield* Path.Path;
|
|
7869
|
-
const serverConfig = yield* ServerConfig;
|
|
8459
|
+
const serverConfig = yield* ServerConfig$1;
|
|
7870
8460
|
yield* fileSystem.makeDirectory(serverConfig.secretsDir, { recursive: true });
|
|
7871
8461
|
yield* fileSystem.chmod(serverConfig.secretsDir, 448).pipe(Effect.mapError((cause) => new SecretStoreSecureError({
|
|
7872
8462
|
resource: `secrets directory ${serverConfig.secretsDir}`,
|
|
@@ -8410,7 +9000,7 @@ function toAuthClientSession(input) {
|
|
|
8410
9000
|
}
|
|
8411
9001
|
const make$60 = Effect.gen(function* () {
|
|
8412
9002
|
const crypto = yield* Crypto.Crypto;
|
|
8413
|
-
const serverConfig = yield* ServerConfig;
|
|
9003
|
+
const serverConfig = yield* ServerConfig$1;
|
|
8414
9004
|
const secretStore = yield* ServerSecretStore;
|
|
8415
9005
|
const authSessions = yield* AuthSessionRepository;
|
|
8416
9006
|
const signingSecret = yield* secretStore.getOrCreateRandom(SIGNING_SECRET_NAME$1, 32);
|
|
@@ -10271,7 +10861,7 @@ const makeSqlitePersistenceLive = Effect.fn("makeSqlitePersistenceLive")(functio
|
|
|
10271
10861
|
}));
|
|
10272
10862
|
}, Layer.unwrap);
|
|
10273
10863
|
Layer.provideMerge(setup, makeRuntimeSqliteLayer({ filename: ":memory:" }));
|
|
10274
|
-
const layerConfig = Layer.unwrap(Effect.map(Effect.service(ServerConfig), ({ dbPath }) => makeSqlitePersistenceLive(dbPath)));
|
|
10864
|
+
const layerConfig = Layer.unwrap(Effect.map(Effect.service(ServerConfig$1), ({ dbPath }) => makeSqlitePersistenceLive(dbPath)));
|
|
10275
10865
|
const INTERNAL_ADMINISTRATIVE_BOOTSTRAP_SUBJECT = "administrative-bootstrap";
|
|
10276
10866
|
const serverAuthInternalErrorContext = { cause: Schema$1.Defect() };
|
|
10277
10867
|
var ServerAuthBootstrapCredentialValidationError = class extends Schema$1.TaggedErrorClass()("ServerAuthBootstrapCredentialValidationError", { ...serverAuthInternalErrorContext }) {
|
|
@@ -10934,652 +11524,210 @@ function resolveSourceControlWriterModelSelection(settings, providers) {
|
|
|
10934
11524
|
if (!selection || !isModelSelectionProviderEnabled(settings, selection)) return settings.textGenerationModelSelection;
|
|
10935
11525
|
if (providers === void 0) return selection;
|
|
10936
11526
|
const provider = providers.find((candidate) => candidate.instanceId === selection.instanceId);
|
|
10937
|
-
return provider?.enabled === true && isProviderAvailable(provider) ? selection : settings.textGenerationModelSelection;
|
|
10938
|
-
}
|
|
10939
|
-
function normalizePersistedServerSettingString(value) {
|
|
10940
|
-
const trimmed = value?.trim();
|
|
10941
|
-
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
10942
|
-
}
|
|
10943
|
-
function extractPersistedServerObservabilitySettings(input) {
|
|
10944
|
-
return {
|
|
10945
|
-
otlpTracesUrl: normalizePersistedServerSettingString(input.observability?.otlpTracesUrl),
|
|
10946
|
-
otlpMetricsUrl: normalizePersistedServerSettingString(input.observability?.otlpMetricsUrl)
|
|
10947
|
-
};
|
|
10948
|
-
}
|
|
10949
|
-
function parsePersistedServerObservabilitySettings(raw) {
|
|
10950
|
-
const decoded = decodeServerSettingsJson(raw);
|
|
10951
|
-
if (Option.isSome(decoded)) return extractPersistedServerObservabilitySettings(decoded.value);
|
|
10952
|
-
return {
|
|
10953
|
-
otlpTracesUrl: void 0,
|
|
10954
|
-
otlpMetricsUrl: void 0
|
|
10955
|
-
};
|
|
10956
|
-
}
|
|
10957
|
-
function shouldReplaceTextGenerationModelSelection(patch) {
|
|
10958
|
-
return Boolean(patch && (patch.instanceId !== void 0 || patch.model !== void 0));
|
|
10959
|
-
}
|
|
10960
|
-
function mergeModelSelectionOptionsById(input) {
|
|
10961
|
-
if (input.patch === void 0) return input.current ? [...input.current] : void 0;
|
|
10962
|
-
if (input.patch.length === 0) return;
|
|
10963
|
-
const merged = new Map((input.current ?? []).map((selection) => [selection.id, selection.value]));
|
|
10964
|
-
for (const selection of input.patch) merged.set(selection.id, selection.value);
|
|
10965
|
-
return [...merged.entries()].map(([id, value]) => ({
|
|
10966
|
-
id,
|
|
10967
|
-
value
|
|
10968
|
-
}));
|
|
10969
|
-
}
|
|
10970
|
-
function applyServerSettingsPatch(current, patch) {
|
|
10971
|
-
const selectionPatch = patch.textGenerationModelSelection;
|
|
10972
|
-
const { automaticGitFetchInterval, ...patchForMerge } = patch;
|
|
10973
|
-
const nextWithReplacements = {
|
|
10974
|
-
...deepMerge(current, patchForMerge),
|
|
10975
|
-
...patch.providerInstances !== void 0 ? { providerInstances: patch.providerInstances } : {},
|
|
10976
|
-
...patch.sourceControlWriterModelSelection !== void 0 ? { sourceControlWriterModelSelection: patch.sourceControlWriterModelSelection } : {},
|
|
10977
|
-
...automaticGitFetchInterval !== void 0 ? { automaticGitFetchInterval } : {}
|
|
10978
|
-
};
|
|
10979
|
-
if (!selectionPatch) return nextWithReplacements;
|
|
10980
|
-
const instanceId = selectionPatch.instanceId ?? current.textGenerationModelSelection.instanceId;
|
|
10981
|
-
const model = selectionPatch.model ?? current.textGenerationModelSelection.model;
|
|
10982
|
-
const options = shouldReplaceTextGenerationModelSelection(selectionPatch) ? selectionPatch.options : mergeModelSelectionOptionsById({
|
|
10983
|
-
current: current.textGenerationModelSelection.options,
|
|
10984
|
-
patch: selectionPatch.options
|
|
10985
|
-
});
|
|
10986
|
-
return {
|
|
10987
|
-
...nextWithReplacements,
|
|
10988
|
-
textGenerationModelSelection: createModelSelection(instanceId, model, options)
|
|
10989
|
-
};
|
|
10990
|
-
}
|
|
10991
|
-
//#endregion
|
|
10992
|
-
//#region src/bootstrap.ts
|
|
10993
|
-
var BootstrapFdStatError = class extends Schema$1.TaggedErrorClass()("BootstrapFdStatError", {
|
|
10994
|
-
fd: Schema$1.Number,
|
|
10995
|
-
cause: Schema$1.Defect()
|
|
10996
|
-
}) {
|
|
10997
|
-
get message() {
|
|
10998
|
-
return `Failed to stat bootstrap file descriptor ${this.fd}.`;
|
|
10999
|
-
}
|
|
11000
|
-
};
|
|
11001
|
-
var BootstrapInputStreamOpenError = class extends Schema$1.TaggedErrorClass()("BootstrapInputStreamOpenError", {
|
|
11002
|
-
fd: Schema$1.Number,
|
|
11003
|
-
platform: Schema$1.String,
|
|
11004
|
-
fdPath: Schema$1.optional(Schema$1.String),
|
|
11005
|
-
cause: Schema$1.Defect()
|
|
11006
|
-
}) {
|
|
11007
|
-
get message() {
|
|
11008
|
-
const path = this.fdPath === void 0 ? "" : ` via '${this.fdPath}'`;
|
|
11009
|
-
return `Failed to open bootstrap input stream for file descriptor ${this.fd}${path} on '${this.platform}'.`;
|
|
11010
|
-
}
|
|
11011
|
-
};
|
|
11012
|
-
var BootstrapEnvelopeReadError = class extends Schema$1.TaggedErrorClass()("BootstrapEnvelopeReadError", {
|
|
11013
|
-
fd: Schema$1.Number,
|
|
11014
|
-
cause: Schema$1.Defect()
|
|
11015
|
-
}) {
|
|
11016
|
-
get message() {
|
|
11017
|
-
return `Failed to read bootstrap envelope from file descriptor ${this.fd}.`;
|
|
11018
|
-
}
|
|
11019
|
-
};
|
|
11020
|
-
var BootstrapEnvelopeDecodeError = class extends Schema$1.TaggedErrorClass()("BootstrapEnvelopeDecodeError", {
|
|
11021
|
-
fd: Schema$1.Number,
|
|
11022
|
-
cause: Schema$1.Defect()
|
|
11023
|
-
}) {
|
|
11024
|
-
get message() {
|
|
11025
|
-
return `Failed to decode bootstrap envelope from file descriptor ${this.fd}.`;
|
|
11026
|
-
}
|
|
11027
|
-
};
|
|
11028
|
-
Schema$1.Union([
|
|
11029
|
-
BootstrapFdStatError,
|
|
11030
|
-
BootstrapInputStreamOpenError,
|
|
11031
|
-
BootstrapEnvelopeReadError,
|
|
11032
|
-
BootstrapEnvelopeDecodeError
|
|
11033
|
-
]);
|
|
11034
|
-
const readBootstrapEnvelope = Effect.fn("readBootstrapEnvelope")(function* (schema, fd, options) {
|
|
11035
|
-
if (!(yield* isFdReady(fd))) return Option.none();
|
|
11036
|
-
const stream = yield* makeBootstrapInputStream(fd);
|
|
11037
|
-
const timeoutMs = options?.timeoutMs ?? 1e3;
|
|
11038
|
-
return yield* Effect.callback((resume) => {
|
|
11039
|
-
const input = NodeReadline.createInterface({
|
|
11040
|
-
input: stream,
|
|
11041
|
-
crlfDelay: Infinity
|
|
11042
|
-
});
|
|
11043
|
-
const cleanup = () => {
|
|
11044
|
-
stream.removeListener("error", handleError);
|
|
11045
|
-
input.removeListener("line", handleLine);
|
|
11046
|
-
input.removeListener("close", handleClose);
|
|
11047
|
-
input.close();
|
|
11048
|
-
stream.destroy();
|
|
11049
|
-
};
|
|
11050
|
-
const handleError = (error) => {
|
|
11051
|
-
if (isUnavailableBootstrapFdError(error)) {
|
|
11052
|
-
resume(Effect.succeedNone);
|
|
11053
|
-
return;
|
|
11054
|
-
}
|
|
11055
|
-
resume(Effect.fail(new BootstrapEnvelopeReadError({
|
|
11056
|
-
fd,
|
|
11057
|
-
cause: error
|
|
11058
|
-
})));
|
|
11059
|
-
};
|
|
11060
|
-
const handleLine = (line) => {
|
|
11061
|
-
const parsed = decodeJsonResult(schema)(line);
|
|
11062
|
-
if (Result.isSuccess(parsed)) resume(Effect.succeedSome(parsed.success));
|
|
11063
|
-
else resume(Effect.fail(new BootstrapEnvelopeDecodeError({
|
|
11064
|
-
fd,
|
|
11065
|
-
cause: parsed.failure
|
|
11066
|
-
})));
|
|
11067
|
-
};
|
|
11068
|
-
const handleClose = () => {
|
|
11069
|
-
resume(Effect.succeedNone);
|
|
11070
|
-
};
|
|
11071
|
-
stream.once("error", handleError);
|
|
11072
|
-
input.once("line", handleLine);
|
|
11073
|
-
input.once("close", handleClose);
|
|
11074
|
-
return Effect.sync(cleanup);
|
|
11075
|
-
}).pipe(Effect.timeoutOption(timeoutMs), Effect.map(Option.flatten));
|
|
11076
|
-
});
|
|
11077
|
-
const isUnavailableBootstrapFdError = Predicate.compose(Predicate.hasProperty("code"), (_) => _.code === "EBADF" || _.code === "ENOENT");
|
|
11078
|
-
const isFdReady = (fd) => Effect.try({
|
|
11079
|
-
try: () => NodeFS.fstatSync(fd),
|
|
11080
|
-
catch: (error) => new BootstrapFdStatError({
|
|
11081
|
-
fd,
|
|
11082
|
-
cause: error
|
|
11083
|
-
})
|
|
11084
|
-
}).pipe(Effect.as(true), Effect.catchTags({ BootstrapFdStatError: (error) => isUnavailableBootstrapFdError(error.cause) ? Effect.succeed(false) : Effect.fail(error) }));
|
|
11085
|
-
const makeBootstrapInputStream = (fd) => Effect.gen(function* () {
|
|
11086
|
-
const platform = yield* HostProcessPlatform;
|
|
11087
|
-
const fdPath = resolveFdPath(fd, platform);
|
|
11088
|
-
return yield* Effect.try({
|
|
11089
|
-
try: () => {
|
|
11090
|
-
if (fdPath === void 0) return makeDirectBootstrapStream(fd);
|
|
11091
|
-
let streamFd;
|
|
11092
|
-
try {
|
|
11093
|
-
streamFd = NodeFS.openSync(fdPath, "r");
|
|
11094
|
-
return NodeFS.createReadStream("", {
|
|
11095
|
-
fd: streamFd,
|
|
11096
|
-
encoding: "utf8",
|
|
11097
|
-
autoClose: true
|
|
11098
|
-
});
|
|
11099
|
-
} catch (error) {
|
|
11100
|
-
if (isBootstrapFdPathDuplicationError(error)) {
|
|
11101
|
-
if (streamFd !== void 0) NodeFS.closeSync(streamFd);
|
|
11102
|
-
return makeDirectBootstrapStream(fd);
|
|
11103
|
-
}
|
|
11104
|
-
throw error;
|
|
11105
|
-
}
|
|
11106
|
-
},
|
|
11107
|
-
catch: (error) => new BootstrapInputStreamOpenError({
|
|
11108
|
-
fd,
|
|
11109
|
-
platform,
|
|
11110
|
-
...fdPath === void 0 ? {} : { fdPath },
|
|
11111
|
-
cause: error
|
|
11112
|
-
})
|
|
11113
|
-
});
|
|
11114
|
-
});
|
|
11115
|
-
const makeDirectBootstrapStream = (fd) => {
|
|
11116
|
-
try {
|
|
11117
|
-
return NodeFS.createReadStream("", {
|
|
11118
|
-
fd,
|
|
11119
|
-
encoding: "utf8",
|
|
11120
|
-
autoClose: true
|
|
11121
|
-
});
|
|
11122
|
-
} catch {
|
|
11123
|
-
const stream = new NodeNet.Socket({
|
|
11124
|
-
fd,
|
|
11125
|
-
readable: true,
|
|
11126
|
-
writable: false
|
|
11127
|
-
});
|
|
11128
|
-
stream.setEncoding("utf8");
|
|
11129
|
-
return stream;
|
|
11130
|
-
}
|
|
11131
|
-
};
|
|
11132
|
-
const isBootstrapFdPathDuplicationError = Predicate.compose(Predicate.hasProperty("code"), (_) => _.code === "ENXIO" || _.code === "EINVAL" || _.code === "EPERM" || _.code === "EACCES");
|
|
11133
|
-
function resolveFdPath(fd, platform) {
|
|
11134
|
-
if (platform === "linux") return `/proc/self/fd/${fd}`;
|
|
11135
|
-
if (platform === "win32") return;
|
|
11136
|
-
return `/dev/fd/${fd}`;
|
|
11137
|
-
}
|
|
11138
|
-
//#endregion
|
|
11139
|
-
//#region ../../packages/shared/src/shell.ts
|
|
11140
|
-
const SHELL_ENV_NAME_PATTERN = /^[A-Z0-9_]+$/;
|
|
11141
|
-
const WINDOWS_PATH_DELIMITER = ";";
|
|
11142
|
-
const POSIX_PATH_DELIMITER = ":";
|
|
11143
|
-
const WINDOWS_SHELL_CANDIDATES = ["pwsh.exe", "powershell.exe"];
|
|
11144
|
-
function canExecuteFile(filePath) {
|
|
11145
|
-
try {
|
|
11146
|
-
NodeFS.accessSync(filePath, NodeFS.constants.X_OK);
|
|
11147
|
-
return true;
|
|
11148
|
-
} catch {
|
|
11149
|
-
return false;
|
|
11150
|
-
}
|
|
11151
|
-
}
|
|
11152
|
-
var CommandResolutionError = class extends Data.TaggedError("CommandResolutionError") {};
|
|
11153
|
-
const WINDOWS_SHELL_META_CHARS = /([()\][%!^"`<>&|;, *?])/g;
|
|
11154
|
-
/**
|
|
11155
|
-
* Escapes a single argument for `cmd.exe` shell mode (`spawn(..., { shell: true })`
|
|
11156
|
-
* on Windows). Node joins the command and arguments with spaces and hands the
|
|
11157
|
-
* resulting string to `cmd.exe` without any quoting, so every dynamic argument
|
|
11158
|
-
* must be escaped to survive both cmd.exe parsing and the target program's
|
|
11159
|
-
* `CommandLineToArgvW` parsing. Mirrors cross-spawn's argument escaping.
|
|
11160
|
-
*/
|
|
11161
|
-
function escapeWindowsShellArg(arg) {
|
|
11162
|
-
let escaped = arg.replace(/(\\*)"/g, "$1$1\\\"");
|
|
11163
|
-
escaped = escaped.replace(/(\\*)$/, "$1$1");
|
|
11164
|
-
escaped = `"${escaped}"`;
|
|
11165
|
-
return escaped.replace(WINDOWS_SHELL_META_CHARS, "^$1");
|
|
11166
|
-
}
|
|
11167
|
-
/**
|
|
11168
|
-
* Escapes arguments for shell-mode spawns: applies {@link escapeWindowsShellArg}
|
|
11169
|
-
* when the platform is `win32` (where `shell: true` routes through `cmd.exe`)
|
|
11170
|
-
* and returns the arguments untouched everywhere else.
|
|
11171
|
-
*/
|
|
11172
|
-
function sanitizeShellModeArgsForPlatform(args, platform) {
|
|
11173
|
-
return platform === "win32" ? args.map(escapeWindowsShellArg) : [...args];
|
|
11174
|
-
}
|
|
11175
|
-
function resolveSpawnExecutableWithNode(command, platform, env) {
|
|
11176
|
-
const path = platform === "win32" ? NodePath.win32 : NodePath.posix;
|
|
11177
|
-
const windowsPathExtensions = platform === "win32" ? resolveWindowsPathExtensions(env) : [];
|
|
11178
|
-
const candidates = resolveCommandCandidates(command, platform, windowsPathExtensions, path.extname);
|
|
11179
|
-
const isExecutable = (candidate) => {
|
|
11180
|
-
try {
|
|
11181
|
-
if (!NodeFS.statSync(candidate).isFile()) return false;
|
|
11182
|
-
if (platform === "win32") return windowsPathExtensions.includes(path.extname(candidate).toUpperCase());
|
|
11183
|
-
return canExecuteFile(candidate);
|
|
11184
|
-
} catch {
|
|
11185
|
-
return false;
|
|
11186
|
-
}
|
|
11187
|
-
};
|
|
11188
|
-
if (command.includes("/") || command.includes("\\")) return candidates.find(isExecutable);
|
|
11189
|
-
for (const pathEntry of (readEnvPath(env) ?? "").split(pathDelimiterForPlatform(platform))) {
|
|
11190
|
-
const normalizedPathEntry = stripWrappingQuotes(pathEntry.trim());
|
|
11191
|
-
if (normalizedPathEntry.length === 0) continue;
|
|
11192
|
-
for (const candidate of candidates) {
|
|
11193
|
-
const candidatePath = path.join(normalizedPathEntry, candidate);
|
|
11194
|
-
if (isExecutable(candidatePath)) return candidatePath;
|
|
11195
|
-
}
|
|
11196
|
-
}
|
|
11197
|
-
}
|
|
11198
|
-
const SpawnExecutableResolution = Context.Reference("@p4code/shared/shell/SpawnExecutableResolution", { defaultValue: () => resolveSpawnExecutableWithNode });
|
|
11199
|
-
function trimNonEmpty(value) {
|
|
11200
|
-
const trimmed = value?.trim();
|
|
11201
|
-
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
11202
|
-
}
|
|
11203
|
-
function readUserLoginShell() {
|
|
11204
|
-
try {
|
|
11205
|
-
return trimNonEmpty(NodeOS.userInfo().shell);
|
|
11206
|
-
} catch {
|
|
11207
|
-
return;
|
|
11208
|
-
}
|
|
11209
|
-
}
|
|
11210
|
-
function listLoginShellCandidates(platform, shell, userShell = readUserLoginShell()) {
|
|
11211
|
-
const fallbackShell = platform === "darwin" ? "/bin/zsh" : platform === "linux" ? "/bin/bash" : void 0;
|
|
11212
|
-
const seen = /* @__PURE__ */ new Set();
|
|
11213
|
-
const candidates = [];
|
|
11214
|
-
for (const candidate of [
|
|
11215
|
-
trimNonEmpty(shell),
|
|
11216
|
-
trimNonEmpty(userShell),
|
|
11217
|
-
fallbackShell
|
|
11218
|
-
]) {
|
|
11219
|
-
if (!candidate || seen.has(candidate)) continue;
|
|
11220
|
-
seen.add(candidate);
|
|
11221
|
-
candidates.push(candidate);
|
|
11222
|
-
}
|
|
11223
|
-
return candidates;
|
|
11224
|
-
}
|
|
11225
|
-
function readPathFromLoginShell(shell, execFile = NodeChildProcess.execFileSync) {
|
|
11226
|
-
return readEnvironmentFromLoginShell(shell, ["PATH"], execFile).PATH;
|
|
11227
|
-
}
|
|
11228
|
-
function readPathFromLaunchctl(execFile = NodeChildProcess.execFileSync) {
|
|
11229
|
-
try {
|
|
11230
|
-
return trimNonEmpty(execFile("/bin/launchctl", ["getenv", "PATH"], {
|
|
11231
|
-
encoding: "utf8",
|
|
11232
|
-
timeout: 2e3
|
|
11233
|
-
}));
|
|
11234
|
-
} catch {
|
|
11235
|
-
return;
|
|
11236
|
-
}
|
|
11237
|
-
}
|
|
11238
|
-
function mergePathEntries(preferredPath, inheritedPath, platform) {
|
|
11239
|
-
const delimiter = platform === "win32" ? ";" : ":";
|
|
11240
|
-
const merged = [];
|
|
11241
|
-
const seen = /* @__PURE__ */ new Set();
|
|
11242
|
-
for (const pathValue of [preferredPath, inheritedPath]) {
|
|
11243
|
-
if (!pathValue) continue;
|
|
11244
|
-
for (const entry of pathValue.split(delimiter)) {
|
|
11245
|
-
const trimmedEntry = entry.trim();
|
|
11246
|
-
if (!trimmedEntry || seen.has(trimmedEntry)) continue;
|
|
11247
|
-
seen.add(trimmedEntry);
|
|
11248
|
-
merged.push(trimmedEntry);
|
|
11249
|
-
}
|
|
11250
|
-
}
|
|
11251
|
-
return merged.length > 0 ? merged.join(delimiter) : void 0;
|
|
11252
|
-
}
|
|
11253
|
-
function envCaptureStart(name) {
|
|
11254
|
-
return `__P4CODE_ENV_${name}_START__`;
|
|
11255
|
-
}
|
|
11256
|
-
function envCaptureEnd(name) {
|
|
11257
|
-
return `__P4CODE_ENV_${name}_END__`;
|
|
11258
|
-
}
|
|
11259
|
-
function buildEnvironmentCaptureCommand(names) {
|
|
11260
|
-
return names.map((name) => {
|
|
11261
|
-
if (!SHELL_ENV_NAME_PATTERN.test(name)) throw new Error(`Unsupported environment variable name: ${name}`);
|
|
11262
|
-
return [
|
|
11263
|
-
`printf '%s\\n' '${envCaptureStart(name)}'`,
|
|
11264
|
-
`printenv ${name} || true`,
|
|
11265
|
-
`printf '%s\\n' '${envCaptureEnd(name)}'`
|
|
11266
|
-
].join("; ");
|
|
11267
|
-
}).join("; ");
|
|
11268
|
-
}
|
|
11269
|
-
function buildWindowsEnvironmentCaptureCommand(names) {
|
|
11270
|
-
return ["$ErrorActionPreference = 'Stop'", ...names.flatMap((name) => {
|
|
11271
|
-
if (!SHELL_ENV_NAME_PATTERN.test(name)) throw new Error(`Unsupported environment variable name: ${name}`);
|
|
11272
|
-
return [
|
|
11273
|
-
`Write-Output '${envCaptureStart(name)}'`,
|
|
11274
|
-
`$value = [Environment]::GetEnvironmentVariable('${name}')`,
|
|
11275
|
-
"if ($null -ne $value -and $value.Length -gt 0) { Write-Output $value }",
|
|
11276
|
-
`Write-Output '${envCaptureEnd(name)}'`
|
|
11277
|
-
];
|
|
11278
|
-
})].join("; ");
|
|
11279
|
-
}
|
|
11280
|
-
function extractEnvironmentValue(output, name) {
|
|
11281
|
-
const startMarker = envCaptureStart(name);
|
|
11282
|
-
const endMarker = envCaptureEnd(name);
|
|
11283
|
-
const startIndex = output.indexOf(startMarker);
|
|
11284
|
-
if (startIndex === -1) return void 0;
|
|
11285
|
-
const valueStartIndex = startIndex + startMarker.length;
|
|
11286
|
-
const endIndex = output.indexOf(endMarker, valueStartIndex);
|
|
11287
|
-
if (endIndex === -1) return void 0;
|
|
11288
|
-
const value = output.slice(valueStartIndex, endIndex).replace(/^\r?\n/, "").replace(/\r?\n$/, "");
|
|
11289
|
-
return value.length > 0 ? value : void 0;
|
|
11290
|
-
}
|
|
11291
|
-
const readEnvironmentFromLoginShell = (shell, names, execFile = NodeChildProcess.execFileSync) => {
|
|
11292
|
-
if (names.length === 0) return {};
|
|
11293
|
-
const output = execFile(shell, ["-ilc", buildEnvironmentCaptureCommand(names)], {
|
|
11294
|
-
encoding: "utf8",
|
|
11295
|
-
timeout: 5e3
|
|
11296
|
-
});
|
|
11297
|
-
const environment = {};
|
|
11298
|
-
for (const name of names) {
|
|
11299
|
-
const value = extractEnvironmentValue(output, name);
|
|
11300
|
-
if (value !== void 0) environment[name] = value;
|
|
11301
|
-
}
|
|
11302
|
-
return environment;
|
|
11303
|
-
};
|
|
11304
|
-
const WindowsShellEnvironment = Context.Reference("@p4code/shared/shell/WindowsShellEnvironment", { defaultValue: () => readEnvironmentFromWindowsShell });
|
|
11305
|
-
const CommandAvailability = Context.Reference("@p4code/shared/shell/CommandAvailability", { defaultValue: () => isCommandAvailable });
|
|
11306
|
-
function readEnvironmentFromWindowsShell(names, optionsOrExecFile, maybeExecFile) {
|
|
11307
|
-
if (names.length === 0) return {};
|
|
11308
|
-
const options = typeof optionsOrExecFile === "function" ? {} : optionsOrExecFile ?? {};
|
|
11309
|
-
const execFile = typeof optionsOrExecFile === "function" ? optionsOrExecFile : maybeExecFile ?? NodeChildProcess.execFileSync;
|
|
11310
|
-
const command = buildWindowsEnvironmentCaptureCommand(names);
|
|
11311
|
-
const args = [
|
|
11312
|
-
"-NoLogo",
|
|
11313
|
-
...options.loadProfile ? [] : ["-NoProfile"],
|
|
11314
|
-
"-NonInteractive",
|
|
11315
|
-
"-Command",
|
|
11316
|
-
command
|
|
11317
|
-
];
|
|
11318
|
-
for (const shell of WINDOWS_SHELL_CANDIDATES) try {
|
|
11319
|
-
const output = execFile(shell, args, {
|
|
11320
|
-
encoding: "utf8",
|
|
11321
|
-
timeout: 5e3
|
|
11322
|
-
});
|
|
11323
|
-
const environment = {};
|
|
11324
|
-
for (const name of names) {
|
|
11325
|
-
const value = extractEnvironmentValue(output, name);
|
|
11326
|
-
if (value !== void 0) environment[name] = value;
|
|
11327
|
-
}
|
|
11328
|
-
return environment;
|
|
11329
|
-
} catch {
|
|
11330
|
-
continue;
|
|
11331
|
-
}
|
|
11332
|
-
return {};
|
|
11333
|
-
}
|
|
11334
|
-
function stripWrappingQuotes(value) {
|
|
11335
|
-
return value.replace(/^"+|"+$/g, "");
|
|
11336
|
-
}
|
|
11337
|
-
function pathDelimiterForPlatform(platform) {
|
|
11338
|
-
return platform === "win32" ? WINDOWS_PATH_DELIMITER : POSIX_PATH_DELIMITER;
|
|
11339
|
-
}
|
|
11340
|
-
function normalizePathEntryForComparison(entry, platform) {
|
|
11341
|
-
const normalized = stripWrappingQuotes(entry.trim());
|
|
11342
|
-
return platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
11343
|
-
}
|
|
11344
|
-
function mergePathValues(preferredPath, inheritedPath, platform) {
|
|
11345
|
-
const delimiter = pathDelimiterForPlatform(platform);
|
|
11346
|
-
const merged = [];
|
|
11347
|
-
const seen = /* @__PURE__ */ new Set();
|
|
11348
|
-
for (const rawValue of [preferredPath, inheritedPath]) {
|
|
11349
|
-
if (!rawValue) continue;
|
|
11350
|
-
for (const entry of rawValue.split(delimiter)) {
|
|
11351
|
-
const trimmed = entry.trim();
|
|
11352
|
-
if (trimmed.length === 0) continue;
|
|
11353
|
-
const normalized = normalizePathEntryForComparison(trimmed, platform);
|
|
11354
|
-
if (normalized.length === 0 || seen.has(normalized)) continue;
|
|
11355
|
-
seen.add(normalized);
|
|
11356
|
-
merged.push(trimmed);
|
|
11357
|
-
}
|
|
11358
|
-
}
|
|
11359
|
-
return merged.length > 0 ? merged.join(delimiter) : void 0;
|
|
11527
|
+
return provider?.enabled === true && isProviderAvailable(provider) ? selection : settings.textGenerationModelSelection;
|
|
11360
11528
|
}
|
|
11361
|
-
function
|
|
11362
|
-
|
|
11529
|
+
function normalizePersistedServerSettingString(value) {
|
|
11530
|
+
const trimmed = value?.trim();
|
|
11531
|
+
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
11363
11532
|
}
|
|
11364
|
-
function
|
|
11365
|
-
return
|
|
11533
|
+
function extractPersistedServerObservabilitySettings(input) {
|
|
11534
|
+
return {
|
|
11535
|
+
otlpTracesUrl: normalizePersistedServerSettingString(input.observability?.otlpTracesUrl),
|
|
11536
|
+
otlpMetricsUrl: normalizePersistedServerSettingString(input.observability?.otlpMetricsUrl)
|
|
11537
|
+
};
|
|
11366
11538
|
}
|
|
11367
|
-
function
|
|
11368
|
-
const
|
|
11369
|
-
|
|
11370
|
-
|
|
11371
|
-
|
|
11372
|
-
|
|
11373
|
-
|
|
11374
|
-
];
|
|
11375
|
-
if (!rawValue) return fallback;
|
|
11376
|
-
const parsed = [];
|
|
11377
|
-
for (const entry of rawValue.split(";")) {
|
|
11378
|
-
const trimmed = entry.trim();
|
|
11379
|
-
if (trimmed.length === 0) continue;
|
|
11380
|
-
parsed.push(trimmed.startsWith(".") ? trimmed.toUpperCase() : `.${trimmed.toUpperCase()}`);
|
|
11381
|
-
}
|
|
11382
|
-
return parsed.length > 0 ? Array.from(new Set(parsed)) : fallback;
|
|
11539
|
+
function parsePersistedServerObservabilitySettings(raw) {
|
|
11540
|
+
const decoded = decodeServerSettingsJson(raw);
|
|
11541
|
+
if (Option.isSome(decoded)) return extractPersistedServerObservabilitySettings(decoded.value);
|
|
11542
|
+
return {
|
|
11543
|
+
otlpTracesUrl: void 0,
|
|
11544
|
+
otlpMetricsUrl: void 0
|
|
11545
|
+
};
|
|
11383
11546
|
}
|
|
11384
|
-
function
|
|
11385
|
-
|
|
11386
|
-
const extension = extname(command);
|
|
11387
|
-
const normalizedExtension = extension.toUpperCase();
|
|
11388
|
-
if (extension.length > 0 && windowsPathExtensions.includes(normalizedExtension)) {
|
|
11389
|
-
const commandWithoutExtension = command.slice(0, -extension.length);
|
|
11390
|
-
return Array.from(/* @__PURE__ */ new Set([
|
|
11391
|
-
command,
|
|
11392
|
-
`${commandWithoutExtension}${normalizedExtension}`,
|
|
11393
|
-
`${commandWithoutExtension}${normalizedExtension.toLowerCase()}`
|
|
11394
|
-
]));
|
|
11395
|
-
}
|
|
11396
|
-
const candidates = [];
|
|
11397
|
-
for (const candidateExtension of windowsPathExtensions) {
|
|
11398
|
-
candidates.push(`${command}${candidateExtension}`);
|
|
11399
|
-
candidates.push(`${command}${candidateExtension.toLowerCase()}`);
|
|
11400
|
-
}
|
|
11401
|
-
return Array.from(new Set(candidates));
|
|
11547
|
+
function shouldReplaceTextGenerationModelSelection(patch) {
|
|
11548
|
+
return Boolean(patch && (patch.instanceId !== void 0 || patch.model !== void 0));
|
|
11402
11549
|
}
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
const
|
|
11407
|
-
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
|
|
11550
|
+
function mergeModelSelectionOptionsById(input) {
|
|
11551
|
+
if (input.patch === void 0) return input.current ? [...input.current] : void 0;
|
|
11552
|
+
if (input.patch.length === 0) return;
|
|
11553
|
+
const merged = new Map((input.current ?? []).map((selection) => [selection.id, selection.value]));
|
|
11554
|
+
for (const selection of input.patch) merged.set(selection.id, selection.value);
|
|
11555
|
+
return [...merged.entries()].map(([id, value]) => ({
|
|
11556
|
+
id,
|
|
11557
|
+
value
|
|
11558
|
+
}));
|
|
11559
|
+
}
|
|
11560
|
+
function applyServerSettingsPatch(current, patch) {
|
|
11561
|
+
const selectionPatch = patch.textGenerationModelSelection;
|
|
11562
|
+
const { automaticGitFetchInterval, ...patchForMerge } = patch;
|
|
11563
|
+
const nextWithReplacements = {
|
|
11564
|
+
...deepMerge(current, patchForMerge),
|
|
11565
|
+
...patch.providerInstances !== void 0 ? { providerInstances: patch.providerInstances } : {},
|
|
11566
|
+
...patch.sourceControlWriterModelSelection !== void 0 ? { sourceControlWriterModelSelection: patch.sourceControlWriterModelSelection } : {},
|
|
11567
|
+
...automaticGitFetchInterval !== void 0 ? { automaticGitFetchInterval } : {}
|
|
11568
|
+
};
|
|
11569
|
+
if (!selectionPatch) return nextWithReplacements;
|
|
11570
|
+
const instanceId = selectionPatch.instanceId ?? current.textGenerationModelSelection.instanceId;
|
|
11571
|
+
const model = selectionPatch.model ?? current.textGenerationModelSelection.model;
|
|
11572
|
+
const options = shouldReplaceTextGenerationModelSelection(selectionPatch) ? selectionPatch.options : mergeModelSelectionOptionsById({
|
|
11573
|
+
current: current.textGenerationModelSelection.options,
|
|
11574
|
+
patch: selectionPatch.options
|
|
11575
|
+
});
|
|
11576
|
+
return {
|
|
11577
|
+
...nextWithReplacements,
|
|
11578
|
+
textGenerationModelSelection: createModelSelection(instanceId, model, options)
|
|
11579
|
+
};
|
|
11580
|
+
}
|
|
11581
|
+
//#endregion
|
|
11582
|
+
//#region src/bootstrap.ts
|
|
11583
|
+
var BootstrapFdStatError = class extends Schema$1.TaggedErrorClass()("BootstrapFdStatError", {
|
|
11584
|
+
fd: Schema$1.Number,
|
|
11585
|
+
cause: Schema$1.Defect()
|
|
11586
|
+
}) {
|
|
11587
|
+
get message() {
|
|
11588
|
+
return `Failed to stat bootstrap file descriptor ${this.fd}.`;
|
|
11412
11589
|
}
|
|
11413
|
-
|
|
11414
|
-
|
|
11415
|
-
|
|
11416
|
-
|
|
11417
|
-
|
|
11418
|
-
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
|
|
11422
|
-
|
|
11423
|
-
return yield* new CommandResolutionError({
|
|
11424
|
-
command,
|
|
11425
|
-
reason: "not-found"
|
|
11426
|
-
});
|
|
11590
|
+
};
|
|
11591
|
+
var BootstrapInputStreamOpenError = class extends Schema$1.TaggedErrorClass()("BootstrapInputStreamOpenError", {
|
|
11592
|
+
fd: Schema$1.Number,
|
|
11593
|
+
platform: Schema$1.String,
|
|
11594
|
+
fdPath: Schema$1.optional(Schema$1.String),
|
|
11595
|
+
cause: Schema$1.Defect()
|
|
11596
|
+
}) {
|
|
11597
|
+
get message() {
|
|
11598
|
+
const path = this.fdPath === void 0 ? "" : ` via '${this.fdPath}'`;
|
|
11599
|
+
return `Failed to open bootstrap input stream for file descriptor ${this.fd}${path} on '${this.platform}'.`;
|
|
11427
11600
|
}
|
|
11428
|
-
|
|
11429
|
-
|
|
11430
|
-
|
|
11431
|
-
|
|
11432
|
-
|
|
11433
|
-
|
|
11434
|
-
|
|
11435
|
-
const pathEntry = stripWrappingQuotes(entry.trim());
|
|
11436
|
-
if (pathEntry.length > 0) pathEntries.push(pathEntry);
|
|
11601
|
+
};
|
|
11602
|
+
var BootstrapEnvelopeReadError = class extends Schema$1.TaggedErrorClass()("BootstrapEnvelopeReadError", {
|
|
11603
|
+
fd: Schema$1.Number,
|
|
11604
|
+
cause: Schema$1.Defect()
|
|
11605
|
+
}) {
|
|
11606
|
+
get message() {
|
|
11607
|
+
return `Failed to read bootstrap envelope from file descriptor ${this.fd}.`;
|
|
11437
11608
|
}
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11609
|
+
};
|
|
11610
|
+
var BootstrapEnvelopeDecodeError = class extends Schema$1.TaggedErrorClass()("BootstrapEnvelopeDecodeError", {
|
|
11611
|
+
fd: Schema$1.Number,
|
|
11612
|
+
cause: Schema$1.Defect()
|
|
11613
|
+
}) {
|
|
11614
|
+
get message() {
|
|
11615
|
+
return `Failed to decode bootstrap envelope from file descriptor ${this.fd}.`;
|
|
11441
11616
|
}
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
|
|
11446
|
-
|
|
11447
|
-
|
|
11448
|
-
|
|
11449
|
-
|
|
11450
|
-
|
|
11451
|
-
|
|
11617
|
+
};
|
|
11618
|
+
Schema$1.Union([
|
|
11619
|
+
BootstrapFdStatError,
|
|
11620
|
+
BootstrapInputStreamOpenError,
|
|
11621
|
+
BootstrapEnvelopeReadError,
|
|
11622
|
+
BootstrapEnvelopeDecodeError
|
|
11623
|
+
]);
|
|
11624
|
+
const readBootstrapEnvelope = Effect.fn("readBootstrapEnvelope")(function* (schema, fd, options) {
|
|
11625
|
+
if (!(yield* isFdReady(fd))) return Option.none();
|
|
11626
|
+
const stream = yield* makeBootstrapInputStream(fd);
|
|
11627
|
+
const timeoutMs = options?.timeoutMs ?? 1e3;
|
|
11628
|
+
return yield* Effect.callback((resume) => {
|
|
11629
|
+
const input = NodeReadline.createInterface({
|
|
11630
|
+
input: stream,
|
|
11631
|
+
crlfDelay: Infinity
|
|
11632
|
+
});
|
|
11633
|
+
const cleanup = () => {
|
|
11634
|
+
stream.removeListener("error", handleError);
|
|
11635
|
+
input.removeListener("line", handleLine);
|
|
11636
|
+
input.removeListener("close", handleClose);
|
|
11637
|
+
input.close();
|
|
11638
|
+
stream.destroy();
|
|
11639
|
+
};
|
|
11640
|
+
const handleError = (error) => {
|
|
11641
|
+
if (isUnavailableBootstrapFdError(error)) {
|
|
11642
|
+
resume(Effect.succeedNone);
|
|
11643
|
+
return;
|
|
11644
|
+
}
|
|
11645
|
+
resume(Effect.fail(new BootstrapEnvelopeReadError({
|
|
11646
|
+
fd,
|
|
11647
|
+
cause: error
|
|
11648
|
+
})));
|
|
11649
|
+
};
|
|
11650
|
+
const handleLine = (line) => {
|
|
11651
|
+
const parsed = decodeJsonResult(schema)(line);
|
|
11652
|
+
if (Result.isSuccess(parsed)) resume(Effect.succeedSome(parsed.success));
|
|
11653
|
+
else resume(Effect.fail(new BootstrapEnvelopeDecodeError({
|
|
11654
|
+
fd,
|
|
11655
|
+
cause: parsed.failure
|
|
11656
|
+
})));
|
|
11657
|
+
};
|
|
11658
|
+
const handleClose = () => {
|
|
11659
|
+
resume(Effect.succeedNone);
|
|
11660
|
+
};
|
|
11661
|
+
stream.once("error", handleError);
|
|
11662
|
+
input.once("line", handleLine);
|
|
11663
|
+
input.once("close", handleClose);
|
|
11664
|
+
return Effect.sync(cleanup);
|
|
11665
|
+
}).pipe(Effect.timeoutOption(timeoutMs), Effect.map(Option.flatten));
|
|
11452
11666
|
});
|
|
11453
|
-
const
|
|
11667
|
+
const isUnavailableBootstrapFdError = Predicate.compose(Predicate.hasProperty("code"), (_) => _.code === "EBADF" || _.code === "ENOENT");
|
|
11668
|
+
const isFdReady = (fd) => Effect.try({
|
|
11669
|
+
try: () => NodeFS.fstatSync(fd),
|
|
11670
|
+
catch: (error) => new BootstrapFdStatError({
|
|
11671
|
+
fd,
|
|
11672
|
+
cause: error
|
|
11673
|
+
})
|
|
11674
|
+
}).pipe(Effect.as(true), Effect.catchTags({ BootstrapFdStatError: (error) => isUnavailableBootstrapFdError(error.cause) ? Effect.succeed(false) : Effect.fail(error) }));
|
|
11675
|
+
const makeBootstrapInputStream = (fd) => Effect.gen(function* () {
|
|
11454
11676
|
const platform = yield* HostProcessPlatform;
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
|
|
11458
|
-
|
|
11459
|
-
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
|
|
11463
|
-
|
|
11464
|
-
|
|
11465
|
-
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11677
|
+
const fdPath = resolveFdPath(fd, platform);
|
|
11678
|
+
return yield* Effect.try({
|
|
11679
|
+
try: () => {
|
|
11680
|
+
if (fdPath === void 0) return makeDirectBootstrapStream(fd);
|
|
11681
|
+
let streamFd;
|
|
11682
|
+
try {
|
|
11683
|
+
streamFd = NodeFS.openSync(fdPath, "r");
|
|
11684
|
+
return NodeFS.createReadStream("", {
|
|
11685
|
+
fd: streamFd,
|
|
11686
|
+
encoding: "utf8",
|
|
11687
|
+
autoClose: true
|
|
11688
|
+
});
|
|
11689
|
+
} catch (error) {
|
|
11690
|
+
if (isBootstrapFdPathDuplicationError(error)) {
|
|
11691
|
+
if (streamFd !== void 0) NodeFS.closeSync(streamFd);
|
|
11692
|
+
return makeDirectBootstrapStream(fd);
|
|
11693
|
+
}
|
|
11694
|
+
throw error;
|
|
11695
|
+
}
|
|
11696
|
+
},
|
|
11697
|
+
catch: (error) => new BootstrapInputStreamOpenError({
|
|
11698
|
+
fd,
|
|
11699
|
+
platform,
|
|
11700
|
+
...fdPath === void 0 ? {} : { fdPath },
|
|
11701
|
+
cause: error
|
|
11702
|
+
})
|
|
11703
|
+
});
|
|
11480
11704
|
});
|
|
11481
|
-
|
|
11482
|
-
const appData = env.APPDATA?.trim();
|
|
11483
|
-
const localAppData = env.LOCALAPPDATA?.trim();
|
|
11484
|
-
const userProfile = env.USERPROFILE?.trim();
|
|
11485
|
-
return [
|
|
11486
|
-
...appData ? [`${appData}\\npm`] : [],
|
|
11487
|
-
...localAppData ? [`${localAppData}\\Programs\\nodejs`, `${localAppData}\\Volta\\bin`] : [],
|
|
11488
|
-
...localAppData ? [`${localAppData}\\pnpm`] : [],
|
|
11489
|
-
...userProfile ? [`${userProfile}\\.bun\\bin`, `${userProfile}\\scoop\\shims`] : []
|
|
11490
|
-
];
|
|
11491
|
-
}
|
|
11492
|
-
function readWindowsEnvironmentSafely(readEnvironment, names, options) {
|
|
11705
|
+
const makeDirectBootstrapStream = (fd) => {
|
|
11493
11706
|
try {
|
|
11494
|
-
return
|
|
11707
|
+
return NodeFS.createReadStream("", {
|
|
11708
|
+
fd,
|
|
11709
|
+
encoding: "utf8",
|
|
11710
|
+
autoClose: true
|
|
11711
|
+
});
|
|
11495
11712
|
} catch {
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
}
|
|
11504
|
-
const resolveWindowsEnvironment = Effect.fn("shell.resolveWindowsEnvironment")(function* (env) {
|
|
11505
|
-
const readEnvironment = yield* WindowsShellEnvironment;
|
|
11506
|
-
const commandAvailable = yield* CommandAvailability;
|
|
11507
|
-
const inheritedPath = readEnvPath(env);
|
|
11508
|
-
const shellPath = readWindowsEnvironmentSafely(readEnvironment, ["PATH"], { loadProfile: false }).PATH;
|
|
11509
|
-
const mergedPath = mergePathValues(shellPath, inheritedPath, "win32");
|
|
11510
|
-
const baselinePath = mergePathValues(resolveKnownWindowsCliDirs(env).join(WINDOWS_PATH_DELIMITER), mergedPath, "win32");
|
|
11511
|
-
const baselinePatch = baselinePath ? { PATH: baselinePath } : {};
|
|
11512
|
-
if (yield* commandAvailable("node", { env: mergeWindowsEnv(env, baselinePatch) })) return baselinePatch;
|
|
11513
|
-
const profiledEnvironment = readWindowsEnvironmentSafely(readEnvironment, [
|
|
11514
|
-
"PATH",
|
|
11515
|
-
"FNM_DIR",
|
|
11516
|
-
"FNM_MULTISHELL_PATH"
|
|
11517
|
-
], { loadProfile: true });
|
|
11518
|
-
const profiledPath = mergePathValues(profiledEnvironment.PATH, baselinePath, "win32");
|
|
11519
|
-
const profiledPatch = {
|
|
11520
|
-
...profiledPath ? { PATH: profiledPath } : {},
|
|
11521
|
-
...profiledEnvironment.FNM_DIR ? { FNM_DIR: profiledEnvironment.FNM_DIR } : {},
|
|
11522
|
-
...profiledEnvironment.FNM_MULTISHELL_PATH ? { FNM_MULTISHELL_PATH: profiledEnvironment.FNM_MULTISHELL_PATH } : {}
|
|
11523
|
-
};
|
|
11524
|
-
return Object.keys(profiledPatch).length > 0 ? {
|
|
11525
|
-
...baselinePatch,
|
|
11526
|
-
...profiledPatch
|
|
11527
|
-
} : baselinePatch;
|
|
11528
|
-
});
|
|
11529
|
-
//#endregion
|
|
11530
|
-
//#region src/os-jank.ts
|
|
11531
|
-
function logPathHydrationWarning(message, error) {
|
|
11532
|
-
process.stderr.write(`[server] ${message} ${error instanceof Error ? error.message : error ?? ""}\n`);
|
|
11533
|
-
}
|
|
11534
|
-
function hydratePosixPath(env, platform) {
|
|
11535
|
-
let shellPath;
|
|
11536
|
-
for (const shell of listLoginShellCandidates(platform, env.SHELL)) {
|
|
11537
|
-
try {
|
|
11538
|
-
shellPath = readPathFromLoginShell(shell);
|
|
11539
|
-
} catch (error) {
|
|
11540
|
-
logPathHydrationWarning(`Failed to read PATH from login shell ${shell}.`, error);
|
|
11541
|
-
}
|
|
11542
|
-
if (shellPath) break;
|
|
11713
|
+
const stream = new NodeNet.Socket({
|
|
11714
|
+
fd,
|
|
11715
|
+
readable: true,
|
|
11716
|
+
writable: false
|
|
11717
|
+
});
|
|
11718
|
+
stream.setEncoding("utf8");
|
|
11719
|
+
return stream;
|
|
11543
11720
|
}
|
|
11544
|
-
|
|
11545
|
-
|
|
11546
|
-
|
|
11721
|
+
};
|
|
11722
|
+
const isBootstrapFdPathDuplicationError = Predicate.compose(Predicate.hasProperty("code"), (_) => _.code === "ENXIO" || _.code === "EINVAL" || _.code === "EPERM" || _.code === "EACCES");
|
|
11723
|
+
function resolveFdPath(fd, platform) {
|
|
11724
|
+
if (platform === "linux") return `/proc/self/fd/${fd}`;
|
|
11725
|
+
if (platform === "win32") return;
|
|
11726
|
+
return `/dev/fd/${fd}`;
|
|
11547
11727
|
}
|
|
11548
|
-
const fixPath = Effect.fn("fixPath")(function* () {
|
|
11549
|
-
const platform = yield* HostProcessPlatform;
|
|
11550
|
-
const env = yield* HostProcessEnvironment;
|
|
11551
|
-
if (platform === "win32") {
|
|
11552
|
-
const repairedEnvironment = yield* resolveWindowsEnvironment(env).pipe(Effect.catchDefect((defect) => Effect.sync(() => {
|
|
11553
|
-
logPathHydrationWarning("Failed to hydrate PATH from the user environment.", defect);
|
|
11554
|
-
return {};
|
|
11555
|
-
})));
|
|
11556
|
-
for (const [key, value] of Object.entries(repairedEnvironment)) if (value !== void 0) env[key] = value;
|
|
11557
|
-
return;
|
|
11558
|
-
}
|
|
11559
|
-
if (platform !== "darwin" && platform !== "linux") return;
|
|
11560
|
-
yield* Effect.sync(() => hydratePosixPath(env, platform)).pipe(Effect.catchDefect((defect) => Effect.sync(() => {
|
|
11561
|
-
logPathHydrationWarning("Failed to hydrate PATH from the user environment.", defect);
|
|
11562
|
-
})));
|
|
11563
|
-
});
|
|
11564
|
-
const expandHomePath$4 = Effect.fn(function* (input) {
|
|
11565
|
-
const { join } = yield* Path.Path;
|
|
11566
|
-
if (input === "~") return NodeOS.homedir();
|
|
11567
|
-
if (input.startsWith("~/") || input.startsWith("~\\")) return join(NodeOS.homedir(), input.slice(2));
|
|
11568
|
-
return input;
|
|
11569
|
-
});
|
|
11570
|
-
/** The data directory used when neither `--base-dir` nor `P4CODE_HOME` is set. */
|
|
11571
|
-
const defaultBaseDir = Effect.fn(function* () {
|
|
11572
|
-
const { join } = yield* Path.Path;
|
|
11573
|
-
return join(NodeOS.homedir(), ".p4");
|
|
11574
|
-
});
|
|
11575
|
-
const resolveBaseDir = Effect.fn(function* (raw) {
|
|
11576
|
-
const { resolve } = yield* Path.Path;
|
|
11577
|
-
if (!raw || raw.trim().length === 0) return yield* defaultBaseDir();
|
|
11578
|
-
return resolve(yield* expandHomePath$4(raw.trim()));
|
|
11579
|
-
});
|
|
11580
11728
|
//#endregion
|
|
11581
11729
|
//#region src/cli/config.ts
|
|
11582
|
-
const modeFlag = Flag.choice("mode", RuntimeMode.literals).pipe(Flag.withDescription("Runtime mode. `desktop` keeps loopback defaults unless overridden."), Flag.optional);
|
|
11730
|
+
const modeFlag = Flag.choice("mode", RuntimeMode$1.literals).pipe(Flag.withDescription("Runtime mode. `desktop` keeps loopback defaults unless overridden."), Flag.optional);
|
|
11583
11731
|
const portFlag = Flag.integer("port").pipe(Flag.withSchema(PortSchema), Flag.withDescription("Port for the HTTP/WebSocket server."), Flag.optional);
|
|
11584
11732
|
const hostFlag = Flag.string("host").pipe(Flag.withDescription("Host/interface to bind (for example 127.0.0.1, 0.0.0.0, or a Tailnet IP)."), Flag.optional);
|
|
11585
11733
|
const baseDirFlag = Flag.string("base-dir").pipe(Flag.withDescription("Explicit P4Code data directory; runtime state is stored under userdata (equivalent to P4CODE_HOME)."), Flag.optional);
|
|
@@ -11602,7 +11750,7 @@ const EnvServerConfig = Config.all({
|
|
|
11602
11750
|
otlpMetricsUrl: Config.string("P4CODE_OTLP_METRICS_URL").pipe(Config.option, Config.map(Option.getOrUndefined)),
|
|
11603
11751
|
otlpExportIntervalMs: Config.int("P4CODE_OTLP_EXPORT_INTERVAL_MS").pipe(Config.withDefault(1e4)),
|
|
11604
11752
|
otlpServiceName: Config.string("P4CODE_OTLP_SERVICE_NAME").pipe(Config.withDefault("p4-server")),
|
|
11605
|
-
mode: Config.schema(RuntimeMode, "P4CODE_MODE").pipe(Config.option, Config.map(Option.getOrUndefined)),
|
|
11753
|
+
mode: Config.schema(RuntimeMode$1, "P4CODE_MODE").pipe(Config.option, Config.map(Option.getOrUndefined)),
|
|
11606
11754
|
port: Config.port("P4CODE_PORT").pipe(Config.option, Config.map(Option.getOrUndefined)),
|
|
11607
11755
|
host: Config.string("P4CODE_HOST").pipe(Config.option, Config.map(Option.getOrUndefined)),
|
|
11608
11756
|
p4Home: Config.string("P4CODE_HOME").pipe(Config.option, Config.map(Option.getOrUndefined)),
|
|
@@ -13952,7 +14100,7 @@ const ProjectionThreadSession = Schema$1.Struct({
|
|
|
13952
14100
|
status: OrchestrationSessionStatus,
|
|
13953
14101
|
providerName: Schema$1.NullOr(Schema$1.String),
|
|
13954
14102
|
providerInstanceId: Schema$1.NullOr(ProviderInstanceId),
|
|
13955
|
-
runtimeMode: RuntimeMode
|
|
14103
|
+
runtimeMode: RuntimeMode,
|
|
13956
14104
|
activeTurnId: Schema$1.NullOr(TurnId),
|
|
13957
14105
|
lastError: Schema$1.NullOr(Schema$1.String),
|
|
13958
14106
|
updatedAt: IsoDateTime
|
|
@@ -14047,7 +14195,7 @@ const ProjectionThread = Schema$1.Struct({
|
|
|
14047
14195
|
projectId: ProjectId,
|
|
14048
14196
|
title: Schema$1.String,
|
|
14049
14197
|
modelSelection: ModelSelection,
|
|
14050
|
-
runtimeMode: RuntimeMode
|
|
14198
|
+
runtimeMode: RuntimeMode,
|
|
14051
14199
|
interactionMode: ProviderInteractionMode,
|
|
14052
14200
|
branch: Schema$1.NullOr(Schema$1.String),
|
|
14053
14201
|
worktreePath: Schema$1.NullOr(Schema$1.String),
|
|
@@ -15368,7 +15516,7 @@ function collectThreadAttachmentRelativePaths(threadId, messages) {
|
|
|
15368
15516
|
return relativePaths;
|
|
15369
15517
|
}
|
|
15370
15518
|
const runAttachmentSideEffects = Effect.fn("runAttachmentSideEffects")(function* (sideEffects) {
|
|
15371
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
15519
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
15372
15520
|
const fileSystem = yield* Effect.service(FileSystem.FileSystem);
|
|
15373
15521
|
const path = yield* Effect.service(Path.Path);
|
|
15374
15522
|
const attachmentsRootDir = serverConfig.attachmentsDir;
|
|
@@ -15430,7 +15578,7 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
|
|
|
15430
15578
|
const projectionPendingApprovalRepository = yield* ProjectionPendingApprovalRepository;
|
|
15431
15579
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
15432
15580
|
const path = yield* Path.Path;
|
|
15433
|
-
const serverConfig = yield* ServerConfig;
|
|
15581
|
+
const serverConfig = yield* ServerConfig$1;
|
|
15434
15582
|
const applyProjectsProjection = Effect.fn("applyProjectsProjection")(function* (event, _attachmentSideEffects) {
|
|
15435
15583
|
switch (event.type) {
|
|
15436
15584
|
case "project.created":
|
|
@@ -16120,9 +16268,9 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
|
|
|
16120
16268
|
})));
|
|
16121
16269
|
});
|
|
16122
16270
|
const bootstrapProjector = (projector) => projectionStateRepository.getByProjector({ projector: projector.name }).pipe(Effect.flatMap((stateRow) => Stream.runForEach(eventStore.readFromSequence(Option.isSome(stateRow) ? stateRow.value.lastAppliedSequence : 0), (event) => runProjectorForEvent(projector, event))));
|
|
16123
|
-
const projectEvent = (event) => Effect.forEach(projectors, (projector) => runProjectorForEvent(projector, event), { concurrency: 1 }).pipe(Effect.provideService(FileSystem.FileSystem, fileSystem), Effect.provideService(Path.Path, path), Effect.provideService(ServerConfig, serverConfig), Effect.asVoid, Effect.catchTag("SqlError", (sqlError) => Effect.fail(toPersistenceSqlError("ProjectionPipeline.projectEvent:query")(sqlError))));
|
|
16271
|
+
const projectEvent = (event) => Effect.forEach(projectors, (projector) => runProjectorForEvent(projector, event), { concurrency: 1 }).pipe(Effect.provideService(FileSystem.FileSystem, fileSystem), Effect.provideService(Path.Path, path), Effect.provideService(ServerConfig$1, serverConfig), Effect.asVoid, Effect.catchTag("SqlError", (sqlError) => Effect.fail(toPersistenceSqlError("ProjectionPipeline.projectEvent:query")(sqlError))));
|
|
16124
16272
|
return {
|
|
16125
|
-
bootstrap: Effect.forEach(projectors, bootstrapProjector, { concurrency: 1 }).pipe(Effect.provideService(FileSystem.FileSystem, fileSystem), Effect.provideService(Path.Path, path), Effect.provideService(ServerConfig, serverConfig), Effect.asVoid, Effect.tap(() => Effect.logDebug("orchestration projection pipeline bootstrapped").pipe(Effect.annotateLogs({ projectors: projectors.length }))), Effect.catchTag("SqlError", (sqlError) => Effect.fail(toPersistenceSqlError("ProjectionPipeline.bootstrap:query")(sqlError)))),
|
|
16273
|
+
bootstrap: Effect.forEach(projectors, bootstrapProjector, { concurrency: 1 }).pipe(Effect.provideService(FileSystem.FileSystem, fileSystem), Effect.provideService(Path.Path, path), Effect.provideService(ServerConfig$1, serverConfig), Effect.asVoid, Effect.tap(() => Effect.logDebug("orchestration projection pipeline bootstrapped").pipe(Effect.annotateLogs({ projectors: projectors.length }))), Effect.catchTag("SqlError", (sqlError) => Effect.fail(toPersistenceSqlError("ProjectionPipeline.bootstrap:query")(sqlError)))),
|
|
16126
16274
|
projectEvent
|
|
16127
16275
|
};
|
|
16128
16276
|
});
|
|
@@ -18537,7 +18685,7 @@ function mergeWithDefaultKeybindings(custom) {
|
|
|
18537
18685
|
*/
|
|
18538
18686
|
var Keybindings = class extends Context.Service()("@p4code/cli/keybindings") {};
|
|
18539
18687
|
const make$56 = Effect.gen(function* () {
|
|
18540
|
-
const { keybindingsConfigPath } = yield* ServerConfig;
|
|
18688
|
+
const { keybindingsConfigPath } = yield* ServerConfig$1;
|
|
18541
18689
|
const fs = yield* FileSystem.FileSystem;
|
|
18542
18690
|
const path = yield* Path.Path;
|
|
18543
18691
|
const upsertSemaphore = yield* Semaphore.make(1);
|
|
@@ -19186,7 +19334,7 @@ function stripDefaultServerSettings(current, defaults) {
|
|
|
19186
19334
|
return Object.is(current, defaults) ? void 0 : current;
|
|
19187
19335
|
}
|
|
19188
19336
|
const make$53 = Effect.gen(function* () {
|
|
19189
|
-
const { settingsPath } = yield* ServerConfig;
|
|
19337
|
+
const { settingsPath } = yield* ServerConfig$1;
|
|
19190
19338
|
const fs = yield* FileSystem.FileSystem;
|
|
19191
19339
|
const pathService = yield* Path.Path;
|
|
19192
19340
|
const secretStore = yield* ServerSecretStore;
|
|
@@ -19517,7 +19665,7 @@ const getClaudeUserId = Effect.fn("TelemetryIdentity.getClaudeUserId")(function*
|
|
|
19517
19665
|
});
|
|
19518
19666
|
const upsertAnonymousId = Effect.gen(function* () {
|
|
19519
19667
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
19520
|
-
const { anonymousIdPath } = yield* ServerConfig;
|
|
19668
|
+
const { anonymousIdPath } = yield* ServerConfig$1;
|
|
19521
19669
|
const existing = yield* readIdentityFile(fileSystem, "anonymous", anonymousIdPath);
|
|
19522
19670
|
if (Option.isSome(existing)) return existing.value;
|
|
19523
19671
|
const anonymousId = yield* Crypto.Crypto.pipe(Effect.flatMap((crypto) => crypto.randomUUIDv4), Effect.mapError((cause) => new TelemetryAnonymousIdGenerationError({
|
|
@@ -19586,7 +19734,7 @@ var AnalyticsService = class AnalyticsService extends Context.Service()("@p4code
|
|
|
19586
19734
|
const make$52 = Effect.gen(function* () {
|
|
19587
19735
|
const telemetryConfig = yield* TelemetryEnvConfig;
|
|
19588
19736
|
const httpClient = yield* HttpClient$1.HttpClient;
|
|
19589
|
-
const serverConfig = yield* ServerConfig;
|
|
19737
|
+
const serverConfig = yield* ServerConfig$1;
|
|
19590
19738
|
const identifier = yield* getTelemetryIdentifier;
|
|
19591
19739
|
const bufferRef = yield* Ref.make([]);
|
|
19592
19740
|
const clientType = serverConfig.mode === "desktop" ? "desktop-app" : "cli-web-client";
|
|
@@ -20028,6 +20176,22 @@ const make$51 = Effect.fn("cloud.boot_service.make")(function* (input) {
|
|
|
20028
20176
|
serviceTarget
|
|
20029
20177
|
]);
|
|
20030
20178
|
});
|
|
20179
|
+
const restart = Effect.gen(function* () {
|
|
20180
|
+
yield* requireSupportedPlatform;
|
|
20181
|
+
if (isLaunchd) {
|
|
20182
|
+
yield* runStep("restarting the service", "launchctl", [
|
|
20183
|
+
"kickstart",
|
|
20184
|
+
"-k",
|
|
20185
|
+
serviceTarget
|
|
20186
|
+
]);
|
|
20187
|
+
return;
|
|
20188
|
+
}
|
|
20189
|
+
yield* runStep("restarting the service", "systemctl", [
|
|
20190
|
+
"--user",
|
|
20191
|
+
"restart",
|
|
20192
|
+
BOOT_SERVICE_UNIT_FILE
|
|
20193
|
+
]);
|
|
20194
|
+
}).pipe(Effect.withSpan("cloud.boot_service.restart"));
|
|
20031
20195
|
const rollbackFailedInstall = Effect.fn("cloud.boot_service.rollback_failed_install")(function* (previousUnit) {
|
|
20032
20196
|
if (Option.isSome(previousUnit)) yield* fs.writeFileString(unitPath, previousUnit.value).pipe(Effect.ignore);
|
|
20033
20197
|
else if (isLaunchd) {
|
|
@@ -20105,6 +20269,7 @@ const make$51 = Effect.fn("cloud.boot_service.make")(function* (input) {
|
|
|
20105
20269
|
return BootService.of({
|
|
20106
20270
|
install,
|
|
20107
20271
|
uninstall,
|
|
20272
|
+
restart,
|
|
20108
20273
|
status,
|
|
20109
20274
|
logPath
|
|
20110
20275
|
});
|
|
@@ -20185,7 +20350,7 @@ const resolveServerSelfUpdateCapability = Effect.fn("cloud.server_self_update.re
|
|
|
20185
20350
|
});
|
|
20186
20351
|
var ServerSelfUpdate = class extends Context.Service()("@p4code/cli/service/selfUpdate/ServerSelfUpdate") {};
|
|
20187
20352
|
const make$50 = Effect.fn("cloud.server_self_update.make")(function* (options) {
|
|
20188
|
-
const serverConfig = yield* ServerConfig;
|
|
20353
|
+
const serverConfig = yield* ServerConfig$1;
|
|
20189
20354
|
const fs = yield* FileSystem.FileSystem;
|
|
20190
20355
|
const path = yield* Path.Path;
|
|
20191
20356
|
const runner = yield* ProcessRunner;
|
|
@@ -20467,7 +20632,7 @@ function platformArch(architecture) {
|
|
|
20467
20632
|
const make$49 = Effect.gen(function* () {
|
|
20468
20633
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
20469
20634
|
const path = yield* Path.Path;
|
|
20470
|
-
const serverConfig = yield* ServerConfig;
|
|
20635
|
+
const serverConfig = yield* ServerConfig$1;
|
|
20471
20636
|
const crypto = yield* Crypto.Crypto;
|
|
20472
20637
|
const hostPlatform = yield* HostProcessPlatform;
|
|
20473
20638
|
const hostArchitecture = yield* HostProcessArchitecture;
|
|
@@ -21456,7 +21621,7 @@ const formatHeadlessServeOutput = (accessInfo) => [
|
|
|
21456
21621
|
""
|
|
21457
21622
|
].join("\n");
|
|
21458
21623
|
const issueHeadlessServeAccessInfo = Effect.fn("issueHeadlessServeAccessInfo")(function* () {
|
|
21459
|
-
const serverConfig = yield* ServerConfig;
|
|
21624
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21460
21625
|
const httpServer = yield* HttpServer.HttpServer;
|
|
21461
21626
|
const serverAuth = yield* EnvironmentAuth;
|
|
21462
21627
|
const connectionString = resolveHeadlessConnectionString(serverConfig.host, resolveListeningPort(httpServer.address, serverConfig.port));
|
|
@@ -21470,7 +21635,7 @@ const issueHeadlessServeAccessInfo = Effect.fn("issueHeadlessServeAccessInfo")(f
|
|
|
21470
21635
|
//#endregion
|
|
21471
21636
|
//#region src/serverRuntimeStartup.ts
|
|
21472
21637
|
var ServerRuntimeStartupError = class extends Schema$1.TaggedErrorClass()("ServerRuntimeStartupError", {
|
|
21473
|
-
mode: RuntimeMode,
|
|
21638
|
+
mode: RuntimeMode$1,
|
|
21474
21639
|
host: Schema$1.NullOr(Schema$1.String),
|
|
21475
21640
|
port: Schema$1.Number,
|
|
21476
21641
|
cause: Schema$1.Defect()
|
|
@@ -21523,7 +21688,7 @@ const getAutoBootstrapDefaultModelSelection = () => ({
|
|
|
21523
21688
|
model: DEFAULT_MODEL
|
|
21524
21689
|
});
|
|
21525
21690
|
const resolveWelcomeBase = Effect.gen(function* () {
|
|
21526
|
-
const serverConfig = yield* ServerConfig;
|
|
21691
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21527
21692
|
const segments = serverConfig.cwd.split(/[/\\]/).filter(Boolean);
|
|
21528
21693
|
const projectName = segments[segments.length - 1] ?? "project";
|
|
21529
21694
|
return {
|
|
@@ -21533,7 +21698,7 @@ const resolveWelcomeBase = Effect.gen(function* () {
|
|
|
21533
21698
|
});
|
|
21534
21699
|
const resolveAutoBootstrapWelcomeTargets = Effect.gen(function* () {
|
|
21535
21700
|
const randomUUID = (yield* Crypto.Crypto).randomUUIDv4;
|
|
21536
|
-
const serverConfig = yield* ServerConfig;
|
|
21701
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21537
21702
|
const projectionReadModelQuery = yield* ProjectionSnapshotQuery;
|
|
21538
21703
|
const orchestrationEngine = yield* OrchestrationEngineService;
|
|
21539
21704
|
const path = yield* Path.Path;
|
|
@@ -21591,7 +21756,7 @@ const resolveAutoBootstrapWelcomeTargets = Effect.gen(function* () {
|
|
|
21591
21756
|
};
|
|
21592
21757
|
});
|
|
21593
21758
|
const resolveStartupBrowserTarget = Effect.gen(function* () {
|
|
21594
|
-
const serverConfig = yield* ServerConfig;
|
|
21759
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21595
21760
|
const serverAuth = yield* EnvironmentAuth;
|
|
21596
21761
|
const localUrl = `http://localhost:${serverConfig.port}`;
|
|
21597
21762
|
const bindUrl = serverConfig.host && !isWildcardHost(serverConfig.host) ? `http://${formatHostForUrl(serverConfig.host)}:${serverConfig.port}` : localUrl;
|
|
@@ -21599,12 +21764,12 @@ const resolveStartupBrowserTarget = Effect.gen(function* () {
|
|
|
21599
21764
|
return yield* Effect.succeed(serverConfig.mode === "desktop" ? baseTarget : void 0).pipe(Effect.flatMap((target) => target ? Effect.succeed(target) : serverAuth.issueStartupPairingUrl(baseTarget)));
|
|
21600
21765
|
});
|
|
21601
21766
|
const maybeOpenBrowser = (target) => Effect.gen(function* () {
|
|
21602
|
-
if ((yield* ServerConfig).noBrowser) return;
|
|
21767
|
+
if ((yield* ServerConfig$1).noBrowser) return;
|
|
21603
21768
|
yield* (yield* ExternalLauncher).launchBrowser(target).pipe(Effect.catch(() => Effect.logInfo("browser auto-open unavailable", { hint: `Open ${target} in your browser.` })));
|
|
21604
21769
|
});
|
|
21605
21770
|
const runStartupPhase = (phase, effect) => effect.pipe(Effect.annotateSpans({ "startup.phase": phase }), Effect.withSpan(`server.startup.${phase}`));
|
|
21606
21771
|
const make$48 = Effect.gen(function* () {
|
|
21607
|
-
const serverConfig = yield* ServerConfig;
|
|
21772
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21608
21773
|
const keybindings = yield* Keybindings;
|
|
21609
21774
|
const orchestrationReactor = yield* OrchestrationReactor;
|
|
21610
21775
|
const providerSessionReaper = yield* ProviderSessionReaper;
|
|
@@ -23040,7 +23205,7 @@ const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (input) {
|
|
|
23040
23205
|
}
|
|
23041
23206
|
case "attachment": {
|
|
23042
23207
|
const attachmentPath = resolveAttachmentPathById({
|
|
23043
|
-
attachmentsDir: (yield* ServerConfig).attachmentsDir,
|
|
23208
|
+
attachmentsDir: (yield* ServerConfig$1).attachmentsDir,
|
|
23044
23209
|
attachmentId: input.resource.attachmentId
|
|
23045
23210
|
});
|
|
23046
23211
|
if (!attachmentPath) return yield* new AssetAttachmentNotFoundError({ resource: input.resource });
|
|
@@ -23105,7 +23270,7 @@ const resolveAsset = Effect.fn("AssetAccess.resolveAsset")(function* (token, rel
|
|
|
23105
23270
|
if (!claims || claims.expiresAt <= (yield* Clock.currentTimeMillis)) return null;
|
|
23106
23271
|
if (claims.kind === "attachment") {
|
|
23107
23272
|
const attachmentPath = resolveAttachmentPathById({
|
|
23108
|
-
attachmentsDir: (yield* ServerConfig).attachmentsDir,
|
|
23273
|
+
attachmentsDir: (yield* ServerConfig$1).attachmentsDir,
|
|
23109
23274
|
attachmentId: claims.attachmentId
|
|
23110
23275
|
});
|
|
23111
23276
|
if (!attachmentPath) return null;
|
|
@@ -23393,7 +23558,7 @@ const compressHttpResponse = Effect.fnUntraced(function* (response, acceptEncodi
|
|
|
23393
23558
|
});
|
|
23394
23559
|
const httpCompressionLayer = HttpRouter.middleware((httpEffect) => Effect.flatMap(Effect.all([httpEffect, HttpServerRequest.HttpServerRequest]), ([response, request]) => compressHttpResponse(response, request.headers["accept-encoding"])), { global: true });
|
|
23395
23560
|
const browserApiCorsLayer = Layer.unwrap(Effect.gen(function* () {
|
|
23396
|
-
const config = yield* ServerConfig;
|
|
23561
|
+
const config = yield* ServerConfig$1;
|
|
23397
23562
|
const devOrigin = config.devUrl?.origin;
|
|
23398
23563
|
return HttpRouter.cors({
|
|
23399
23564
|
...devOrigin ? {
|
|
@@ -23435,7 +23600,7 @@ var DecodeOtlpTraceRecordsError = class extends Data.TaggedError("DecodeOtlpTrac
|
|
|
23435
23600
|
const otlpTracesProxyRouteLayer = HttpRouter.add("POST", OTLP_TRACES_PROXY_PATH, Effect.gen(function* () {
|
|
23436
23601
|
yield* authenticateRawRouteWithScope(AuthOrchestrationOperateScope);
|
|
23437
23602
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
23438
|
-
const otlpTracesUrl = (yield* ServerConfig).otlpTracesUrl;
|
|
23603
|
+
const otlpTracesUrl = (yield* ServerConfig$1).otlpTracesUrl;
|
|
23439
23604
|
const browserTraceCollector = yield* BrowserTraceCollector;
|
|
23440
23605
|
const httpClient = yield* HttpClient.HttpClient;
|
|
23441
23606
|
const bodyJson = cast(yield* request.json);
|
|
@@ -23480,7 +23645,7 @@ const staticAndDevRouteLayer = HttpRouter.add("GET", "*", Effect.gen(function* (
|
|
|
23480
23645
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
23481
23646
|
const url = HttpServerRequest.toURL(request);
|
|
23482
23647
|
if (Option.isNone(url)) return HttpServerResponse.text("Bad Request", { status: 400 });
|
|
23483
|
-
const config = yield* ServerConfig;
|
|
23648
|
+
const config = yield* ServerConfig$1;
|
|
23484
23649
|
if (config.devUrl && isDevProxiedPath(url.value.pathname)) return HttpServerResponse.text("Not Found", { status: 404 });
|
|
23485
23650
|
if (config.devUrl && isLoopbackHostname(url.value.hostname)) return HttpServerResponse.redirect(resolveDevRedirectUrl(config.devUrl, url.value), { status: 302 });
|
|
23486
23651
|
const staticDir = config.staticDir ?? (config.devUrl ? yield* resolveStaticDir() : void 0);
|
|
@@ -24019,7 +24184,7 @@ const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* () {
|
|
|
24019
24184
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
24020
24185
|
const path = yield* Path.Path;
|
|
24021
24186
|
const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
24022
|
-
const { worktreesDir } = yield* ServerConfig;
|
|
24187
|
+
const { worktreesDir } = yield* ServerConfig$1;
|
|
24023
24188
|
const crypto = yield* Crypto.Crypto;
|
|
24024
24189
|
const executeRaw = Effect.fnUntraced(function* (input) {
|
|
24025
24190
|
const commandInput = {
|
|
@@ -26447,7 +26612,7 @@ const normalizeDispatchCommand = (command) => Effect.gen(function* () {
|
|
|
26447
26612
|
const canonicalCommand = canonicalizeClientCommandTimestamps(command, receivedAt);
|
|
26448
26613
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
26449
26614
|
const path = yield* Path.Path;
|
|
26450
|
-
const serverConfig = yield* ServerConfig;
|
|
26615
|
+
const serverConfig = yield* ServerConfig$1;
|
|
26451
26616
|
const workspacePaths = yield* WorkspacePaths;
|
|
26452
26617
|
const normalizeProjectWorkspaceRoot = (workspaceRoot) => workspacePaths.normalizeWorkspaceRoot(workspaceRoot).pipe(Effect.mapError((cause) => new OrchestrationDispatchCommandError({ message: cause.message })));
|
|
26453
26618
|
const normalizeProjectWorkspaceRootForCreate = (workspaceRoot, createIfMissing) => workspacePaths.normalizeWorkspaceRoot(workspaceRoot, { createIfMissing: createIfMissing === true }).pipe(Effect.mapError((cause) => new OrchestrationDispatchCommandError({ message: cause.message })));
|
|
@@ -26595,79 +26760,6 @@ const makeProviderMaintenanceCommandCoordinator = Effect.fn("makeProviderMainten
|
|
|
26595
26760
|
return { withCommandLock };
|
|
26596
26761
|
});
|
|
26597
26762
|
//#endregion
|
|
26598
|
-
//#region ../../packages/shared/src/semver.ts
|
|
26599
|
-
const SEMVER_NUMBER_SEGMENT = /^\d+$/;
|
|
26600
|
-
function normalizeSemverVersion(version) {
|
|
26601
|
-
const [main, prerelease] = version.trim().split("-", 2);
|
|
26602
|
-
const segments = [];
|
|
26603
|
-
for (const segment of (main ?? "").split(".")) {
|
|
26604
|
-
const trimmed = segment.trim();
|
|
26605
|
-
if (trimmed.length > 0) segments.push(trimmed);
|
|
26606
|
-
}
|
|
26607
|
-
if (segments.length === 2) segments.push("0");
|
|
26608
|
-
return prerelease ? `${segments.join(".")}-${prerelease}` : segments.join(".");
|
|
26609
|
-
}
|
|
26610
|
-
function parseSemver(value) {
|
|
26611
|
-
const [main = "", prerelease] = normalizeSemverVersion(value).replace(/^v/, "").split("-", 2);
|
|
26612
|
-
const segments = main.split(".");
|
|
26613
|
-
if (segments.length !== 3) return null;
|
|
26614
|
-
const [majorSegment, minorSegment, patchSegment] = segments;
|
|
26615
|
-
if (majorSegment === void 0 || minorSegment === void 0 || patchSegment === void 0) return null;
|
|
26616
|
-
if (!SEMVER_NUMBER_SEGMENT.test(majorSegment) || !SEMVER_NUMBER_SEGMENT.test(minorSegment) || !SEMVER_NUMBER_SEGMENT.test(patchSegment)) return null;
|
|
26617
|
-
const major = Number.parseInt(majorSegment, 10);
|
|
26618
|
-
const minor = Number.parseInt(minorSegment, 10);
|
|
26619
|
-
const patch = Number.parseInt(patchSegment, 10);
|
|
26620
|
-
if (![
|
|
26621
|
-
major,
|
|
26622
|
-
minor,
|
|
26623
|
-
patch
|
|
26624
|
-
].every(Number.isInteger)) return null;
|
|
26625
|
-
return {
|
|
26626
|
-
major,
|
|
26627
|
-
minor,
|
|
26628
|
-
patch,
|
|
26629
|
-
prerelease: parsePrereleaseSegments(prerelease)
|
|
26630
|
-
};
|
|
26631
|
-
}
|
|
26632
|
-
function parsePrereleaseSegments(prerelease) {
|
|
26633
|
-
if (prerelease === void 0) return [];
|
|
26634
|
-
const segments = [];
|
|
26635
|
-
for (const segment of prerelease.split(".")) {
|
|
26636
|
-
const trimmed = segment.trim();
|
|
26637
|
-
if (trimmed.length > 0) segments.push(trimmed);
|
|
26638
|
-
}
|
|
26639
|
-
return segments;
|
|
26640
|
-
}
|
|
26641
|
-
function comparePrereleaseIdentifier(left, right) {
|
|
26642
|
-
const leftNumeric = SEMVER_NUMBER_SEGMENT.test(left);
|
|
26643
|
-
const rightNumeric = SEMVER_NUMBER_SEGMENT.test(right);
|
|
26644
|
-
if (leftNumeric && rightNumeric) return Number.parseInt(left, 10) - Number.parseInt(right, 10);
|
|
26645
|
-
if (leftNumeric) return -1;
|
|
26646
|
-
if (rightNumeric) return 1;
|
|
26647
|
-
return left.localeCompare(right);
|
|
26648
|
-
}
|
|
26649
|
-
function compareSemverVersions(left, right) {
|
|
26650
|
-
const parsedLeft = parseSemver(left);
|
|
26651
|
-
const parsedRight = parseSemver(right);
|
|
26652
|
-
if (!parsedLeft || !parsedRight) return left.localeCompare(right);
|
|
26653
|
-
if (parsedLeft.major !== parsedRight.major) return parsedLeft.major - parsedRight.major;
|
|
26654
|
-
if (parsedLeft.minor !== parsedRight.minor) return parsedLeft.minor - parsedRight.minor;
|
|
26655
|
-
if (parsedLeft.patch !== parsedRight.patch) return parsedLeft.patch - parsedRight.patch;
|
|
26656
|
-
if (parsedLeft.prerelease.length === 0 && parsedRight.prerelease.length === 0) return 0;
|
|
26657
|
-
if (parsedLeft.prerelease.length === 0) return 1;
|
|
26658
|
-
if (parsedRight.prerelease.length === 0) return -1;
|
|
26659
|
-
const length = Math.max(parsedLeft.prerelease.length, parsedRight.prerelease.length);
|
|
26660
|
-
for (let index = 0; index < length; index += 1) {
|
|
26661
|
-
const leftIdentifier = parsedLeft.prerelease[index];
|
|
26662
|
-
const rightIdentifier = parsedRight.prerelease[index];
|
|
26663
|
-
if (leftIdentifier === void 0) return -1;
|
|
26664
|
-
if (rightIdentifier === void 0) return 1;
|
|
26665
|
-
const comparison = comparePrereleaseIdentifier(leftIdentifier, rightIdentifier);
|
|
26666
|
-
if (comparison !== 0) return comparison;
|
|
26667
|
-
}
|
|
26668
|
-
return 0;
|
|
26669
|
-
}
|
|
26670
|
-
//#endregion
|
|
26671
26763
|
//#region src/provider/providerMaintenance.ts
|
|
26672
26764
|
const LATEST_VERSION_CACHE_TTL_MS = 3600 * 1e3;
|
|
26673
26765
|
const LATEST_VERSION_TIMEOUT_MS = 4e3;
|
|
@@ -28259,7 +28351,7 @@ function normalizedRuntimeEnv(env) {
|
|
|
28259
28351
|
return Object.fromEntries(entries.toSorted(([left], [right]) => left.localeCompare(right)));
|
|
28260
28352
|
}
|
|
28261
28353
|
const make$35 = Effect.fn("TerminalManager.make")(function* () {
|
|
28262
|
-
const { terminalLogsDir } = yield* ServerConfig;
|
|
28354
|
+
const { terminalLogsDir } = yield* ServerConfig$1;
|
|
28263
28355
|
const ptyAdapter = yield* PtyAdapter;
|
|
28264
28356
|
const portDiscovery = yield* PortDiscovery;
|
|
28265
28357
|
return yield* makeWithOptions$1({
|
|
@@ -33210,7 +33302,7 @@ function bindProviderContext(provider, context) {
|
|
|
33210
33302
|
});
|
|
33211
33303
|
}
|
|
33212
33304
|
const makeWithProviders = Effect.fn("makeSourceControlProviderRegistryWithProviders")(function* (registrations) {
|
|
33213
|
-
const config = yield* ServerConfig;
|
|
33305
|
+
const config = yield* ServerConfig$1;
|
|
33214
33306
|
const process = yield* VcsProcess;
|
|
33215
33307
|
const vcsRegistry = yield* VcsDriverRegistry;
|
|
33216
33308
|
const providers = new Map(registrations.map((registration) => [registration.kind, registration.provider]));
|
|
@@ -35021,7 +35113,7 @@ const layer$10 = Layer.effect(VcsProvisioningService, make$15);
|
|
|
35021
35113
|
//#region src/review/ReviewService.ts
|
|
35022
35114
|
var ReviewService = class extends Context.Service()("@p4code/cli/review/ReviewService") {};
|
|
35023
35115
|
const make$14 = Effect.gen(function* () {
|
|
35024
|
-
const config = yield* ServerConfig;
|
|
35116
|
+
const config = yield* ServerConfig$1;
|
|
35025
35117
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
35026
35118
|
const path = yield* Path.Path;
|
|
35027
35119
|
const vcsRegistry = yield* VcsDriverRegistry;
|
|
@@ -35932,7 +36024,7 @@ const VCS_PROBES = [{
|
|
|
35932
36024
|
}];
|
|
35933
36025
|
var SourceControlDiscovery = class extends Context.Service()("@p4code/cli/sourceControl/SourceControlDiscovery") {};
|
|
35934
36026
|
const make$10 = Effect.gen(function* () {
|
|
35935
|
-
const config = yield* ServerConfig;
|
|
36027
|
+
const config = yield* ServerConfig$1;
|
|
35936
36028
|
const process = yield* VcsProcess;
|
|
35937
36029
|
const sourceControlProviders = yield* SourceControlProviderRegistry;
|
|
35938
36030
|
const probe = (input) => {
|
|
@@ -36014,7 +36106,7 @@ function expandHomePath$1(input, path) {
|
|
|
36014
36106
|
return input;
|
|
36015
36107
|
}
|
|
36016
36108
|
const make$9 = Effect.gen(function* () {
|
|
36017
|
-
const config = yield* ServerConfig;
|
|
36109
|
+
const config = yield* ServerConfig$1;
|
|
36018
36110
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
36019
36111
|
const git = yield* GitVcsDriver;
|
|
36020
36112
|
const path = yield* Path.Path;
|
|
@@ -36373,7 +36465,7 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
|
|
|
36373
36465
|
const providerRegistry = yield* ProviderRegistry;
|
|
36374
36466
|
const providerMaintenanceRunner = yield* ProviderMaintenanceRunner;
|
|
36375
36467
|
const serverSelfUpdate = yield* ServerSelfUpdate;
|
|
36376
|
-
const config = yield* ServerConfig;
|
|
36468
|
+
const config = yield* ServerConfig$1;
|
|
36377
36469
|
const lifecycleEvents = yield* ServerLifecycleEvents;
|
|
36378
36470
|
const serverSettings = yield* ServerSettingsService;
|
|
36379
36471
|
const startup = yield* ServerRuntimeStartup;
|
|
@@ -37017,7 +37109,7 @@ const ProviderSessionRuntime = Schema$1.Struct({
|
|
|
37017
37109
|
*/
|
|
37018
37110
|
providerInstanceId: Schema$1.NullOr(ProviderInstanceId),
|
|
37019
37111
|
adapterKey: Schema$1.String,
|
|
37020
|
-
runtimeMode: RuntimeMode
|
|
37112
|
+
runtimeMode: RuntimeMode,
|
|
37021
37113
|
status: ProviderSessionRuntimeStatus,
|
|
37022
37114
|
lastSeenAt: IsoDateTime,
|
|
37023
37115
|
resumeCursor: Schema$1.NullOr(Schema$1.Unknown),
|
|
@@ -37650,7 +37742,7 @@ var ProviderEventLoggers = class extends Context.Service()("@p4code/cli/provider
|
|
|
37650
37742
|
* is `undefined` and writes from that stream become no-ops downstream.
|
|
37651
37743
|
*/
|
|
37652
37744
|
const ProviderEventLoggersLive = Layer.effect(ProviderEventLoggers, Effect.gen(function* () {
|
|
37653
|
-
const { providerEventLogPath } = yield* ServerConfig;
|
|
37745
|
+
const { providerEventLogPath } = yield* ServerConfig$1;
|
|
37654
37746
|
return {
|
|
37655
37747
|
native: yield* makeEventNdjsonLogger(providerEventLogPath, { stream: "native" }),
|
|
37656
37748
|
canonical: yield* makeEventNdjsonLogger(providerEventLogPath, { stream: "canonical" })
|
|
@@ -41119,7 +41211,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
|
|
|
41119
41211
|
const boundInstanceId = options?.instanceId ?? ProviderInstanceId.make("claudeAgent");
|
|
41120
41212
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
41121
41213
|
const path = yield* Path.Path;
|
|
41122
|
-
const serverConfig = yield* ServerConfig;
|
|
41214
|
+
const serverConfig = yield* ServerConfig$1;
|
|
41123
41215
|
const crypto = yield* Crypto.Crypto;
|
|
41124
41216
|
const claudeEnvironment = yield* makeClaudeEnvironment(claudeSettings, options?.environment).pipe(Effect.provideService(Path.Path, path));
|
|
41125
41217
|
const claudeSdkExecutablePath = yield* resolveClaudeSdkExecutablePath(claudeSettings.binaryPath, claudeEnvironment);
|
|
@@ -43002,7 +43094,7 @@ const ClaudeDriver = {
|
|
|
43002
43094
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
43003
43095
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
43004
43096
|
const path = yield* Path.Path;
|
|
43005
|
-
const { cwd } = yield* ServerConfig;
|
|
43097
|
+
const { cwd } = yield* ServerConfig$1;
|
|
43006
43098
|
const httpClient = yield* HttpClient.HttpClient;
|
|
43007
43099
|
const serverSettings = yield* ServerSettingsService;
|
|
43008
43100
|
const eventLoggers = yield* ProviderEventLoggers;
|
|
@@ -43113,7 +43205,7 @@ const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(function* (
|
|
|
43113
43205
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
43114
43206
|
const path = yield* Path.Path;
|
|
43115
43207
|
const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
43116
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
43208
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
43117
43209
|
const resolvedEnvironment = environment ?? process.env;
|
|
43118
43210
|
const readStreamAsString = (operation, stream) => stream.pipe(Stream.decodeText(), Stream.runFold(() => "", (acc, chunk) => acc + chunk), Effect.mapError((cause) => normalizeCliError("codex", operation, cause, "Failed to collect process output")));
|
|
43119
43211
|
const writeTempFile = (operation, prefix, content) => fileSystem.makeTempFileScoped({ prefix: `p4code-${prefix}-${process.pid}-` }).pipe(Effect.tap((filePath) => fileSystem.writeFileString(filePath, content)), Effect.mapError((cause) => new TextGenerationError({
|
|
@@ -63431,7 +63523,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
|
|
|
63431
63523
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
63432
63524
|
const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
63433
63525
|
const crypto = yield* Crypto.Crypto;
|
|
63434
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
63526
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
63435
63527
|
const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== void 0 ? yield* makeEventNdjsonLogger(options.nativeEventLogPath, { stream: "native" }) : void 0);
|
|
63436
63528
|
const managedNativeEventLogger = options?.nativeEventLogger === void 0 ? nativeEventLogger : void 0;
|
|
63437
63529
|
const runtimeEventQueue = yield* Queue.unbounded();
|
|
@@ -69924,7 +70016,7 @@ function makeCursorAdapter(cursorSettings, options) {
|
|
|
69924
70016
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
69925
70017
|
const path = yield* Path.Path;
|
|
69926
70018
|
const childProcessSpawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
|
|
69927
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
70019
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
69928
70020
|
const crypto = yield* Crypto.Crypto;
|
|
69929
70021
|
const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== void 0 ? yield* makeEventNdjsonLogger(options.nativeEventLogPath, { stream: "native" }) : void 0);
|
|
69930
70022
|
const managedNativeEventLogger = options?.nativeEventLogger === void 0 ? nativeEventLogger : void 0;
|
|
@@ -71043,7 +71135,7 @@ function makeGrokAdapter(grokSettings, options) {
|
|
|
71043
71135
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
71044
71136
|
const path = yield* Path.Path;
|
|
71045
71137
|
const childProcessSpawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
|
|
71046
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
71138
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
71047
71139
|
const crypto = yield* Crypto.Crypto;
|
|
71048
71140
|
const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== void 0 ? yield* makeEventNdjsonLogger(options.nativeEventLogPath, { stream: "native" }) : void 0);
|
|
71049
71141
|
const managedNativeEventLogger = options?.nativeEventLogger === void 0 ? nativeEventLogger : void 0;
|
|
@@ -72217,7 +72309,7 @@ function getOpenCodeTextResponse(parts) {
|
|
|
72217
72309
|
return (parts ?? []).filter(isOpenCodeTextPart).map((part) => part.text).join("").trim();
|
|
72218
72310
|
}
|
|
72219
72311
|
const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration")(function* (openCodeSettings, environment) {
|
|
72220
|
-
const serverConfig = yield* ServerConfig;
|
|
72312
|
+
const serverConfig = yield* ServerConfig$1;
|
|
72221
72313
|
const openCodeRuntime = yield* OpenCodeRuntime;
|
|
72222
72314
|
const resolvedEnvironment = environment ?? process.env;
|
|
72223
72315
|
const idleFiberScope = yield* Effect.acquireRelease(Scope.make(), (scope) => Scope.close(scope, Exit.void));
|
|
@@ -72748,7 +72840,7 @@ const stopOpenCodeContext = Effect.fn("stopOpenCodeContext")(function* (context)
|
|
|
72748
72840
|
function makeOpenCodeAdapter(openCodeSettings, options) {
|
|
72749
72841
|
return Effect.gen(function* () {
|
|
72750
72842
|
const boundInstanceId = options?.instanceId ?? ProviderInstanceId.make("opencode");
|
|
72751
|
-
const serverConfig = yield* ServerConfig;
|
|
72843
|
+
const serverConfig = yield* ServerConfig$1;
|
|
72752
72844
|
const openCodeRuntime = yield* OpenCodeRuntime;
|
|
72753
72845
|
const crypto = yield* Crypto.Crypto;
|
|
72754
72846
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
@@ -73819,7 +73911,7 @@ const BUILT_IN_DRIVERS = [
|
|
|
73819
73911
|
defaultConfig: () => decodeOpenCodeSettings({}),
|
|
73820
73912
|
create: ({ instanceId, displayName, accentColor, environment, enabled, config }) => Effect.gen(function* () {
|
|
73821
73913
|
const openCodeRuntime = yield* OpenCodeRuntime;
|
|
73822
|
-
const serverConfig = yield* ServerConfig;
|
|
73914
|
+
const serverConfig = yield* ServerConfig$1;
|
|
73823
73915
|
const httpClient = yield* HttpClient.HttpClient;
|
|
73824
73916
|
const serverSettings = yield* ServerSettingsService;
|
|
73825
73917
|
const eventLoggers = yield* ProviderEventLoggers;
|
|
@@ -77530,7 +77622,7 @@ const buildSnapshotSource = (instance) => ({
|
|
|
77530
77622
|
});
|
|
77531
77623
|
const ProviderRegistryLive = Layer.effect(ProviderRegistry, Effect.gen(function* () {
|
|
77532
77624
|
const instanceRegistry = yield* ProviderInstanceRegistry;
|
|
77533
|
-
const config = yield* ServerConfig;
|
|
77625
|
+
const config = yield* ServerConfig$1;
|
|
77534
77626
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
77535
77627
|
const path = yield* Path.Path;
|
|
77536
77628
|
const changesPubSub = yield* Effect.acquireRelease(PubSub.unbounded(), PubSub.shutdown);
|
|
@@ -77757,7 +77849,7 @@ const ProviderRegistryLive = Layer.effect(ProviderRegistry, Effect.gen(function*
|
|
|
77757
77849
|
//#endregion
|
|
77758
77850
|
//#region src/serverLogger.ts
|
|
77759
77851
|
const ServerLoggerLive = Effect.gen(function* () {
|
|
77760
|
-
const config = yield* ServerConfig;
|
|
77852
|
+
const config = yield* ServerConfig$1;
|
|
77761
77853
|
const minimumLogLevelLayer = Layer.succeed(References.MinimumLogLevel, config.logLevel);
|
|
77762
77854
|
const loggerLayer = Logger.layer([Logger.consolePretty(), Logger.tracerLogger], { mergeWithExisting: false });
|
|
77763
77855
|
return Layer.mergeAll(loggerLayer, minimumLogLevelLayer);
|
|
@@ -77766,7 +77858,7 @@ const ServerLoggerLive = Effect.gen(function* () {
|
|
|
77766
77858
|
//#region src/observability/Layers/Observability.ts
|
|
77767
77859
|
const otlpSerializationLayer = OtlpSerialization.layerJson;
|
|
77768
77860
|
const ObservabilityLive = Layer.unwrap(Effect.gen(function* () {
|
|
77769
|
-
const config = yield* ServerConfig;
|
|
77861
|
+
const config = yield* ServerConfig$1;
|
|
77770
77862
|
const traceReferencesLayer = Layer.mergeAll(Layer.succeed(Tracer.MinimumTraceLevel, config.traceMinLevel), Layer.succeed(References.TracerTimingEnabled, config.traceTimingEnabled));
|
|
77771
77863
|
const tracerLayer = Layer.unwrap(Effect.gen(function* () {
|
|
77772
77864
|
const sink = yield* makeTraceSink({
|
|
@@ -78040,11 +78132,11 @@ const disableTailscaleServe = (input = {}) => Effect.gen(function* () {
|
|
|
78040
78132
|
//#region src/server.ts
|
|
78041
78133
|
const HTTP_PREEMPTIVE_SHUTDOWN_GRACE_MS = 0;
|
|
78042
78134
|
const PtyAdapterLive = Layer.unwrap(Effect.gen(function* () {
|
|
78043
|
-
if (typeof Bun !== "undefined") return (yield* Effect.promise(() => import("./BunPtyAdapter-
|
|
78044
|
-
else return (yield* Effect.promise(() => import("./NodePtyAdapter-
|
|
78135
|
+
if (typeof Bun !== "undefined") return (yield* Effect.promise(() => import("./BunPtyAdapter-CLDq7yr1.mjs"))).layer;
|
|
78136
|
+
else return (yield* Effect.promise(() => import("./NodePtyAdapter-BQAnH2v0.mjs"))).layer;
|
|
78045
78137
|
}));
|
|
78046
78138
|
const HttpServerLive = Layer.unwrap(Effect.gen(function* () {
|
|
78047
|
-
const config = yield* ServerConfig;
|
|
78139
|
+
const config = yield* ServerConfig$1;
|
|
78048
78140
|
if (typeof Bun !== "undefined") return (yield* Effect.promise(() => import("@effect/platform-bun/BunHttpServer"))).layer({
|
|
78049
78141
|
port: config.port,
|
|
78050
78142
|
hostname: config.host ?? "127.0.0.1",
|
|
@@ -78095,7 +78187,7 @@ const RuntimeDependenciesLive = ReactorLayerLive.pipe(Layer.provideMerge(Checkpo
|
|
|
78095
78187
|
const RuntimeServicesLive = layer$43.pipe(Layer.provideMerge(RuntimeDependenciesLive));
|
|
78096
78188
|
const makeRoutesLayer = Layer.mergeAll(Layer.mergeAll(HttpApiBuilder.layer(EnvironmentHttpApi).pipe(Layer.provide(authHttpApiLayer), Layer.provide(orchestrationHttpApiLayer), Layer.provide(serverEnvironmentHttpApiLayer), Layer.provide(environmentAuthenticatedAuthLayer)), otlpTracesProxyRouteLayer, assetRouteLayer, staticAndDevRouteLayer, websocketRpcRouteLayer), layer.pipe(Layer.provide(layer$2))).pipe(Layer.provide(layer$29), Layer.provide(layer$45), Layer.provide(browserApiCorsLayer), Layer.provide(httpCompressionLayer));
|
|
78097
78189
|
const makeServerLayer = Layer.unwrap(Effect.gen(function* () {
|
|
78098
|
-
const config = yield* ServerConfig;
|
|
78190
|
+
const config = yield* ServerConfig$1;
|
|
78099
78191
|
yield* fixPath();
|
|
78100
78192
|
const httpListeningLayer = Layer.effectDiscard(Effect.gen(function* () {
|
|
78101
78193
|
yield* HttpServer.HttpServer;
|
|
@@ -78143,7 +78235,7 @@ const runServer = Layer.launch(makeServerLayer);
|
|
|
78143
78235
|
//#region src/cli/server.ts
|
|
78144
78236
|
const runServerCommand = (flags, options) => Effect.gen(function* () {
|
|
78145
78237
|
const config = yield* resolveServerConfig(flags, yield* GlobalFlag.LogLevel, options);
|
|
78146
|
-
return yield* runServer.pipe(Effect.provideService(ServerConfig, config));
|
|
78238
|
+
return yield* runServer.pipe(Effect.provideService(ServerConfig$1, config));
|
|
78147
78239
|
});
|
|
78148
78240
|
const startCommand = Command.make("start", { ...sharedServerCommandFlags }).pipe(Command.withDescription("Run the P4Code server."), Command.withHandler((flags) => runServerCommand(flags)));
|
|
78149
78241
|
const serveCommand = Command.make("serve", { ...sharedServerCommandFlags }).pipe(Command.withDescription("Run the P4Code server without opening a browser and print headless pairing details."), Command.withHandler((flags) => runServerCommand(flags, {
|
|
@@ -78151,6 +78243,104 @@ const serveCommand = Command.make("serve", { ...sharedServerCommandFlags }).pipe
|
|
|
78151
78243
|
forceAutoBootstrapProjectFromCwd: false
|
|
78152
78244
|
})));
|
|
78153
78245
|
//#endregion
|
|
78246
|
+
//#region src/cli/completions.ts
|
|
78247
|
+
/**
|
|
78248
|
+
* Installs the zsh completion script for the `p4` command.
|
|
78249
|
+
*
|
|
78250
|
+
* zsh ships `_perforce` with `#compdef p4 p4d`, so out of the box tabbing
|
|
78251
|
+
* through our subcommands prints "unhandled perforce command: …" from its
|
|
78252
|
+
* fallback message. `compinit` resolves duplicate `#compdef` claims by fpath
|
|
78253
|
+
* order — first match wins — and `_perforce` lives in the *last* fpath entry
|
|
78254
|
+
* (`/usr/share/zsh/<ver>/functions`). Writing our own `_p4` into any earlier
|
|
78255
|
+
* directory therefore replaces it outright, with no shell-config edit.
|
|
78256
|
+
*/
|
|
78257
|
+
const COMPLETION_FILE = "_p4";
|
|
78258
|
+
const GENERATE_TIMEOUT_MS = 1e4;
|
|
78259
|
+
/**
|
|
78260
|
+
* Directories ahead of `/usr/share/zsh/*` in a default fpath, most specific
|
|
78261
|
+
* first. `~/.zfunc` is the fallback and is the only one needing an fpath line.
|
|
78262
|
+
*/
|
|
78263
|
+
function candidateDirectories(input) {
|
|
78264
|
+
return [
|
|
78265
|
+
{
|
|
78266
|
+
dir: input.join(input.homeDir, ".oh-my-zsh", "custom", "completions"),
|
|
78267
|
+
requiresFpathEntry: false
|
|
78268
|
+
},
|
|
78269
|
+
{
|
|
78270
|
+
dir: "/opt/homebrew/share/zsh/site-functions",
|
|
78271
|
+
requiresFpathEntry: false
|
|
78272
|
+
},
|
|
78273
|
+
{
|
|
78274
|
+
dir: "/usr/local/share/zsh/site-functions",
|
|
78275
|
+
requiresFpathEntry: false
|
|
78276
|
+
},
|
|
78277
|
+
{
|
|
78278
|
+
dir: input.join(input.homeDir, ".zfunc"),
|
|
78279
|
+
requiresFpathEntry: true
|
|
78280
|
+
}
|
|
78281
|
+
];
|
|
78282
|
+
}
|
|
78283
|
+
/**
|
|
78284
|
+
* Asks the running CLI for its own completion script rather than rendering one
|
|
78285
|
+
* here, so the output cannot drift from what `--completions` produces.
|
|
78286
|
+
*/
|
|
78287
|
+
const generateZshCompletionScript = Effect.fn("cli.completions.generate")(function* () {
|
|
78288
|
+
const runner = yield* ProcessRunner;
|
|
78289
|
+
const execPath = yield* HostProcessExecutablePath;
|
|
78290
|
+
const entryPath = (yield* HostProcessArguments)[1] ?? "";
|
|
78291
|
+
if (entryPath === "") return null;
|
|
78292
|
+
const result = yield* runner.run({
|
|
78293
|
+
command: execPath,
|
|
78294
|
+
args: [
|
|
78295
|
+
entryPath,
|
|
78296
|
+
"--completions",
|
|
78297
|
+
"zsh"
|
|
78298
|
+
],
|
|
78299
|
+
timeout: GENERATE_TIMEOUT_MS
|
|
78300
|
+
});
|
|
78301
|
+
if (result.code !== 0) return null;
|
|
78302
|
+
const script = result.stdout.trim();
|
|
78303
|
+
return script.length === 0 ? null : `${script}\n`;
|
|
78304
|
+
});
|
|
78305
|
+
/**
|
|
78306
|
+
* Best-effort: returns null when completions are not applicable (Windows, no
|
|
78307
|
+
* writable directory) rather than failing the command that asked for them.
|
|
78308
|
+
* Installing completions is never the reason an install should fail.
|
|
78309
|
+
*/
|
|
78310
|
+
const installZshCompletion = Effect.fn("cli.completions.install")(function* () {
|
|
78311
|
+
if ((yield* HostProcessPlatform) === "win32") return null;
|
|
78312
|
+
const fs = yield* FileSystem.FileSystem;
|
|
78313
|
+
const path = yield* Path.Path;
|
|
78314
|
+
const homeDir = (yield* HostProcessEnvironment).HOME ?? "";
|
|
78315
|
+
if (homeDir === "") return null;
|
|
78316
|
+
const script = yield* generateZshCompletionScript();
|
|
78317
|
+
if (script === null) return null;
|
|
78318
|
+
for (const candidate of candidateDirectories({
|
|
78319
|
+
homeDir,
|
|
78320
|
+
join: path.join
|
|
78321
|
+
})) {
|
|
78322
|
+
if (candidate.requiresFpathEntry) {
|
|
78323
|
+
if (!(yield* fs.makeDirectory(candidate.dir, { recursive: true }).pipe(Effect.as(true), Effect.orElseSucceed(() => false)))) continue;
|
|
78324
|
+
} else if (!(yield* fs.exists(candidate.dir).pipe(Effect.orElseSucceed(() => false)))) continue;
|
|
78325
|
+
const target = path.join(candidate.dir, COMPLETION_FILE);
|
|
78326
|
+
if (!(yield* fs.writeFileString(target, script).pipe(Effect.as(true), Effect.orElseSucceed(() => false)))) continue;
|
|
78327
|
+
return {
|
|
78328
|
+
path: target,
|
|
78329
|
+
requiresFpathEntry: candidate.requiresFpathEntry
|
|
78330
|
+
};
|
|
78331
|
+
}
|
|
78332
|
+
return null;
|
|
78333
|
+
});
|
|
78334
|
+
function formatZshCompletionInstall(install) {
|
|
78335
|
+
const installed = `Installed zsh completions at ${install.path}.`;
|
|
78336
|
+
if (!install.requiresFpathEntry) return `${installed} Open a new shell to use them.`;
|
|
78337
|
+
return [
|
|
78338
|
+
installed,
|
|
78339
|
+
`Add this to ~/.zshrc before compinit runs, then open a new shell:`,
|
|
78340
|
+
` fpath=(${install.path.replace(/\/[^/]+$/u, "")} $fpath)`
|
|
78341
|
+
].join("\n");
|
|
78342
|
+
}
|
|
78343
|
+
//#endregion
|
|
78154
78344
|
//#region src/cli/service.ts
|
|
78155
78345
|
const isBootServiceCommandError = Schema$1.is(BootServiceCommandError);
|
|
78156
78346
|
const bootServiceLayer = (config) => layer$46({
|
|
@@ -78203,7 +78393,7 @@ const runServiceCommand = Effect.fn("cli.service.run")(function* (flags, run) {
|
|
|
78203
78393
|
const config = yield* resolveCliAuthConfig(flags, yield* GlobalFlag.LogLevel);
|
|
78204
78394
|
const baseDirNotice = yield* describeNonDefaultBaseDir(config.baseDir);
|
|
78205
78395
|
if (baseDirNotice !== null) yield* Console.error(baseDirNotice);
|
|
78206
|
-
return yield* run.pipe(Effect.tapError((error) => isBootServiceCommandError(error) ? BootService.pipe(Effect.flatMap((service) => Console.error(`Details: ${service.logPath}`))) : Effect.void), Effect.provide(bootServiceLayer(config)));
|
|
78396
|
+
return yield* run.pipe(Effect.tapError((error) => isBootServiceCommandError(error) ? BootService.pipe(Effect.flatMap((service) => Console.error(`Details: ${service.logPath}`))) : Effect.void), Effect.provide(bootServiceLayer(config)), Effect.provide(layer$53));
|
|
78207
78397
|
});
|
|
78208
78398
|
const serviceInstallCommand = Command.make("install", projectLocationFlags).pipe(Command.withDescription("Install P4Code as a background service for this user."), Command.withHandler((flags) => runServiceCommand(flags, Effect.gen(function* () {
|
|
78209
78399
|
const result = yield* reconcileService();
|
|
@@ -78217,11 +78407,14 @@ const serviceInstallCommand = Command.make("install", projectLocationFlags).pipe
|
|
|
78217
78407
|
cliVersion: version,
|
|
78218
78408
|
platform: yield* HostProcessPlatform
|
|
78219
78409
|
}));
|
|
78410
|
+
const completion = yield* installZshCompletion().pipe(Effect.orElseSucceed(() => null));
|
|
78411
|
+
if (completion !== null) yield* Console.log(formatZshCompletionInstall(completion));
|
|
78220
78412
|
}))));
|
|
78221
78413
|
const serviceUpdateCommand = Command.make("update", projectLocationFlags).pipe(Command.withDescription("Update or repair the background service so it runs this CLI build, then restart it."), Command.withHandler((flags) => runServiceCommand(flags, Effect.gen(function* () {
|
|
78222
78414
|
const result = yield* reconcileService();
|
|
78223
78415
|
if (!result.changed) {
|
|
78224
|
-
yield*
|
|
78416
|
+
yield* (yield* BootService).restart;
|
|
78417
|
+
yield* Console.log(`Restarted the P4Code service on @p4code/cli@${version}.`);
|
|
78225
78418
|
return;
|
|
78226
78419
|
}
|
|
78227
78420
|
yield* Console.log(formatReconcileSuccess({
|
|
@@ -78262,7 +78455,23 @@ const serviceCommand = Command.make("service").pipe(Command.withDescription("Man
|
|
|
78262
78455
|
]));
|
|
78263
78456
|
//#endregion
|
|
78264
78457
|
//#region src/bin.ts
|
|
78265
|
-
const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$62);
|
|
78458
|
+
const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$62, FetchHttpClient.layer);
|
|
78459
|
+
/**
|
|
78460
|
+
* Prints an update reminder before dispatching, at most once a day.
|
|
78461
|
+
*
|
|
78462
|
+
* On stderr so it never contaminates `--json` output or a redirected
|
|
78463
|
+
* `--completions` script, and fully swallowed: an advisory notice must not be
|
|
78464
|
+
* able to fail a command or change its exit code.
|
|
78465
|
+
*/
|
|
78466
|
+
const reportUpdateAvailable = Effect.gen(function* () {
|
|
78467
|
+
const baseDir = yield* resolveBaseDir((yield* HostProcessEnvironment).P4CODE_HOME);
|
|
78468
|
+
const paths = yield* deriveServerPaths(baseDir, void 0);
|
|
78469
|
+
const reminder = yield* resolveUpdateReminder({
|
|
78470
|
+
currentVersion: version,
|
|
78471
|
+
stateDir: paths.stateDir
|
|
78472
|
+
});
|
|
78473
|
+
if (reminder !== null) yield* Console.error(reminder);
|
|
78474
|
+
}).pipe(Effect.ignore);
|
|
78266
78475
|
const makeCli = () => Command.make("p4", { ...sharedServerCommandFlags }).pipe(Command.withDescription("Run the P4Code server."), Command.withHandler((flags) => runServerCommand(flags)), Command.withSubcommands([
|
|
78267
78476
|
startCommand,
|
|
78268
78477
|
serveCommand,
|
|
@@ -78271,7 +78480,7 @@ const makeCli = () => Command.make("p4", { ...sharedServerCommandFlags }).pipe(C
|
|
|
78271
78480
|
serviceCommand
|
|
78272
78481
|
]));
|
|
78273
78482
|
const cli = makeCli();
|
|
78274
|
-
if (import.meta.main) Command.run(cli, { version })
|
|
78483
|
+
if (import.meta.main) reportUpdateAvailable.pipe(Effect.andThen(Command.run(cli, { version })), Effect.scoped, Effect.provide(CliRuntimeLayer), NodeRuntime.runMain);
|
|
78275
78484
|
//#endregion
|
|
78276
78485
|
export { cli, makeCli };
|
|
78277
78486
|
|