@p4code/cli 0.0.35 → 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 +1089 -898
- package/dist/client/assets/{DiffPanel-DZwXXRpa.js → DiffPanel-DKJ8ECjA.js} +2 -2
- package/dist/client/assets/{FilePreviewPanel-BHk87SKl.js → FilePreviewPanel-DrEwfDlH.js} +2 -2
- package/dist/client/assets/{PreviewPanel-Cy7Z3Mfj.js → PreviewPanel-DWT1ePi1.js} +2 -2
- package/dist/client/assets/{fileCommentAnnotations-BBdil_-3.js → fileCommentAnnotations-QSDzusB8.js} +2 -2
- package/dist/client/assets/{index-CXsSIu-m.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 }) {
|
|
@@ -10940,646 +11530,204 @@ function normalizePersistedServerSettingString(value) {
|
|
|
10940
11530
|
const trimmed = value?.trim();
|
|
10941
11531
|
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
10942
11532
|
}
|
|
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;
|
|
11533
|
+
function extractPersistedServerObservabilitySettings(input) {
|
|
11534
|
+
return {
|
|
11535
|
+
otlpTracesUrl: normalizePersistedServerSettingString(input.observability?.otlpTracesUrl),
|
|
11536
|
+
otlpMetricsUrl: normalizePersistedServerSettingString(input.observability?.otlpMetricsUrl)
|
|
11537
|
+
};
|
|
11360
11538
|
}
|
|
11361
|
-
function
|
|
11362
|
-
|
|
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
|
+
};
|
|
11363
11546
|
}
|
|
11364
|
-
function
|
|
11365
|
-
return
|
|
11547
|
+
function shouldReplaceTextGenerationModelSelection(patch) {
|
|
11548
|
+
return Boolean(patch && (patch.instanceId !== void 0 || patch.model !== void 0));
|
|
11366
11549
|
}
|
|
11367
|
-
function
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
|
|
11371
|
-
|
|
11372
|
-
|
|
11373
|
-
|
|
11374
|
-
|
|
11375
|
-
|
|
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;
|
|
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
|
+
}));
|
|
11383
11559
|
}
|
|
11384
|
-
function
|
|
11385
|
-
|
|
11386
|
-
const
|
|
11387
|
-
const
|
|
11388
|
-
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
const
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
|
|
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
|
+
};
|
|
11402
11580
|
}
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
return windowsPathExtensions.includes(extension.toUpperCase());
|
|
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";
|
|
@@ -20202,7 +20350,7 @@ const resolveServerSelfUpdateCapability = Effect.fn("cloud.server_self_update.re
|
|
|
20202
20350
|
});
|
|
20203
20351
|
var ServerSelfUpdate = class extends Context.Service()("@p4code/cli/service/selfUpdate/ServerSelfUpdate") {};
|
|
20204
20352
|
const make$50 = Effect.fn("cloud.server_self_update.make")(function* (options) {
|
|
20205
|
-
const serverConfig = yield* ServerConfig;
|
|
20353
|
+
const serverConfig = yield* ServerConfig$1;
|
|
20206
20354
|
const fs = yield* FileSystem.FileSystem;
|
|
20207
20355
|
const path = yield* Path.Path;
|
|
20208
20356
|
const runner = yield* ProcessRunner;
|
|
@@ -20484,7 +20632,7 @@ function platformArch(architecture) {
|
|
|
20484
20632
|
const make$49 = Effect.gen(function* () {
|
|
20485
20633
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
20486
20634
|
const path = yield* Path.Path;
|
|
20487
|
-
const serverConfig = yield* ServerConfig;
|
|
20635
|
+
const serverConfig = yield* ServerConfig$1;
|
|
20488
20636
|
const crypto = yield* Crypto.Crypto;
|
|
20489
20637
|
const hostPlatform = yield* HostProcessPlatform;
|
|
20490
20638
|
const hostArchitecture = yield* HostProcessArchitecture;
|
|
@@ -21473,7 +21621,7 @@ const formatHeadlessServeOutput = (accessInfo) => [
|
|
|
21473
21621
|
""
|
|
21474
21622
|
].join("\n");
|
|
21475
21623
|
const issueHeadlessServeAccessInfo = Effect.fn("issueHeadlessServeAccessInfo")(function* () {
|
|
21476
|
-
const serverConfig = yield* ServerConfig;
|
|
21624
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21477
21625
|
const httpServer = yield* HttpServer.HttpServer;
|
|
21478
21626
|
const serverAuth = yield* EnvironmentAuth;
|
|
21479
21627
|
const connectionString = resolveHeadlessConnectionString(serverConfig.host, resolveListeningPort(httpServer.address, serverConfig.port));
|
|
@@ -21487,7 +21635,7 @@ const issueHeadlessServeAccessInfo = Effect.fn("issueHeadlessServeAccessInfo")(f
|
|
|
21487
21635
|
//#endregion
|
|
21488
21636
|
//#region src/serverRuntimeStartup.ts
|
|
21489
21637
|
var ServerRuntimeStartupError = class extends Schema$1.TaggedErrorClass()("ServerRuntimeStartupError", {
|
|
21490
|
-
mode: RuntimeMode,
|
|
21638
|
+
mode: RuntimeMode$1,
|
|
21491
21639
|
host: Schema$1.NullOr(Schema$1.String),
|
|
21492
21640
|
port: Schema$1.Number,
|
|
21493
21641
|
cause: Schema$1.Defect()
|
|
@@ -21540,7 +21688,7 @@ const getAutoBootstrapDefaultModelSelection = () => ({
|
|
|
21540
21688
|
model: DEFAULT_MODEL
|
|
21541
21689
|
});
|
|
21542
21690
|
const resolveWelcomeBase = Effect.gen(function* () {
|
|
21543
|
-
const serverConfig = yield* ServerConfig;
|
|
21691
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21544
21692
|
const segments = serverConfig.cwd.split(/[/\\]/).filter(Boolean);
|
|
21545
21693
|
const projectName = segments[segments.length - 1] ?? "project";
|
|
21546
21694
|
return {
|
|
@@ -21550,7 +21698,7 @@ const resolveWelcomeBase = Effect.gen(function* () {
|
|
|
21550
21698
|
});
|
|
21551
21699
|
const resolveAutoBootstrapWelcomeTargets = Effect.gen(function* () {
|
|
21552
21700
|
const randomUUID = (yield* Crypto.Crypto).randomUUIDv4;
|
|
21553
|
-
const serverConfig = yield* ServerConfig;
|
|
21701
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21554
21702
|
const projectionReadModelQuery = yield* ProjectionSnapshotQuery;
|
|
21555
21703
|
const orchestrationEngine = yield* OrchestrationEngineService;
|
|
21556
21704
|
const path = yield* Path.Path;
|
|
@@ -21608,7 +21756,7 @@ const resolveAutoBootstrapWelcomeTargets = Effect.gen(function* () {
|
|
|
21608
21756
|
};
|
|
21609
21757
|
});
|
|
21610
21758
|
const resolveStartupBrowserTarget = Effect.gen(function* () {
|
|
21611
|
-
const serverConfig = yield* ServerConfig;
|
|
21759
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21612
21760
|
const serverAuth = yield* EnvironmentAuth;
|
|
21613
21761
|
const localUrl = `http://localhost:${serverConfig.port}`;
|
|
21614
21762
|
const bindUrl = serverConfig.host && !isWildcardHost(serverConfig.host) ? `http://${formatHostForUrl(serverConfig.host)}:${serverConfig.port}` : localUrl;
|
|
@@ -21616,12 +21764,12 @@ const resolveStartupBrowserTarget = Effect.gen(function* () {
|
|
|
21616
21764
|
return yield* Effect.succeed(serverConfig.mode === "desktop" ? baseTarget : void 0).pipe(Effect.flatMap((target) => target ? Effect.succeed(target) : serverAuth.issueStartupPairingUrl(baseTarget)));
|
|
21617
21765
|
});
|
|
21618
21766
|
const maybeOpenBrowser = (target) => Effect.gen(function* () {
|
|
21619
|
-
if ((yield* ServerConfig).noBrowser) return;
|
|
21767
|
+
if ((yield* ServerConfig$1).noBrowser) return;
|
|
21620
21768
|
yield* (yield* ExternalLauncher).launchBrowser(target).pipe(Effect.catch(() => Effect.logInfo("browser auto-open unavailable", { hint: `Open ${target} in your browser.` })));
|
|
21621
21769
|
});
|
|
21622
21770
|
const runStartupPhase = (phase, effect) => effect.pipe(Effect.annotateSpans({ "startup.phase": phase }), Effect.withSpan(`server.startup.${phase}`));
|
|
21623
21771
|
const make$48 = Effect.gen(function* () {
|
|
21624
|
-
const serverConfig = yield* ServerConfig;
|
|
21772
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21625
21773
|
const keybindings = yield* Keybindings;
|
|
21626
21774
|
const orchestrationReactor = yield* OrchestrationReactor;
|
|
21627
21775
|
const providerSessionReaper = yield* ProviderSessionReaper;
|
|
@@ -23057,7 +23205,7 @@ const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (input) {
|
|
|
23057
23205
|
}
|
|
23058
23206
|
case "attachment": {
|
|
23059
23207
|
const attachmentPath = resolveAttachmentPathById({
|
|
23060
|
-
attachmentsDir: (yield* ServerConfig).attachmentsDir,
|
|
23208
|
+
attachmentsDir: (yield* ServerConfig$1).attachmentsDir,
|
|
23061
23209
|
attachmentId: input.resource.attachmentId
|
|
23062
23210
|
});
|
|
23063
23211
|
if (!attachmentPath) return yield* new AssetAttachmentNotFoundError({ resource: input.resource });
|
|
@@ -23122,7 +23270,7 @@ const resolveAsset = Effect.fn("AssetAccess.resolveAsset")(function* (token, rel
|
|
|
23122
23270
|
if (!claims || claims.expiresAt <= (yield* Clock.currentTimeMillis)) return null;
|
|
23123
23271
|
if (claims.kind === "attachment") {
|
|
23124
23272
|
const attachmentPath = resolveAttachmentPathById({
|
|
23125
|
-
attachmentsDir: (yield* ServerConfig).attachmentsDir,
|
|
23273
|
+
attachmentsDir: (yield* ServerConfig$1).attachmentsDir,
|
|
23126
23274
|
attachmentId: claims.attachmentId
|
|
23127
23275
|
});
|
|
23128
23276
|
if (!attachmentPath) return null;
|
|
@@ -23410,7 +23558,7 @@ const compressHttpResponse = Effect.fnUntraced(function* (response, acceptEncodi
|
|
|
23410
23558
|
});
|
|
23411
23559
|
const httpCompressionLayer = HttpRouter.middleware((httpEffect) => Effect.flatMap(Effect.all([httpEffect, HttpServerRequest.HttpServerRequest]), ([response, request]) => compressHttpResponse(response, request.headers["accept-encoding"])), { global: true });
|
|
23412
23560
|
const browserApiCorsLayer = Layer.unwrap(Effect.gen(function* () {
|
|
23413
|
-
const config = yield* ServerConfig;
|
|
23561
|
+
const config = yield* ServerConfig$1;
|
|
23414
23562
|
const devOrigin = config.devUrl?.origin;
|
|
23415
23563
|
return HttpRouter.cors({
|
|
23416
23564
|
...devOrigin ? {
|
|
@@ -23452,7 +23600,7 @@ var DecodeOtlpTraceRecordsError = class extends Data.TaggedError("DecodeOtlpTrac
|
|
|
23452
23600
|
const otlpTracesProxyRouteLayer = HttpRouter.add("POST", OTLP_TRACES_PROXY_PATH, Effect.gen(function* () {
|
|
23453
23601
|
yield* authenticateRawRouteWithScope(AuthOrchestrationOperateScope);
|
|
23454
23602
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
23455
|
-
const otlpTracesUrl = (yield* ServerConfig).otlpTracesUrl;
|
|
23603
|
+
const otlpTracesUrl = (yield* ServerConfig$1).otlpTracesUrl;
|
|
23456
23604
|
const browserTraceCollector = yield* BrowserTraceCollector;
|
|
23457
23605
|
const httpClient = yield* HttpClient.HttpClient;
|
|
23458
23606
|
const bodyJson = cast(yield* request.json);
|
|
@@ -23497,7 +23645,7 @@ const staticAndDevRouteLayer = HttpRouter.add("GET", "*", Effect.gen(function* (
|
|
|
23497
23645
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
23498
23646
|
const url = HttpServerRequest.toURL(request);
|
|
23499
23647
|
if (Option.isNone(url)) return HttpServerResponse.text("Bad Request", { status: 400 });
|
|
23500
|
-
const config = yield* ServerConfig;
|
|
23648
|
+
const config = yield* ServerConfig$1;
|
|
23501
23649
|
if (config.devUrl && isDevProxiedPath(url.value.pathname)) return HttpServerResponse.text("Not Found", { status: 404 });
|
|
23502
23650
|
if (config.devUrl && isLoopbackHostname(url.value.hostname)) return HttpServerResponse.redirect(resolveDevRedirectUrl(config.devUrl, url.value), { status: 302 });
|
|
23503
23651
|
const staticDir = config.staticDir ?? (config.devUrl ? yield* resolveStaticDir() : void 0);
|
|
@@ -24036,7 +24184,7 @@ const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* () {
|
|
|
24036
24184
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
24037
24185
|
const path = yield* Path.Path;
|
|
24038
24186
|
const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
24039
|
-
const { worktreesDir } = yield* ServerConfig;
|
|
24187
|
+
const { worktreesDir } = yield* ServerConfig$1;
|
|
24040
24188
|
const crypto = yield* Crypto.Crypto;
|
|
24041
24189
|
const executeRaw = Effect.fnUntraced(function* (input) {
|
|
24042
24190
|
const commandInput = {
|
|
@@ -26464,7 +26612,7 @@ const normalizeDispatchCommand = (command) => Effect.gen(function* () {
|
|
|
26464
26612
|
const canonicalCommand = canonicalizeClientCommandTimestamps(command, receivedAt);
|
|
26465
26613
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
26466
26614
|
const path = yield* Path.Path;
|
|
26467
|
-
const serverConfig = yield* ServerConfig;
|
|
26615
|
+
const serverConfig = yield* ServerConfig$1;
|
|
26468
26616
|
const workspacePaths = yield* WorkspacePaths;
|
|
26469
26617
|
const normalizeProjectWorkspaceRoot = (workspaceRoot) => workspacePaths.normalizeWorkspaceRoot(workspaceRoot).pipe(Effect.mapError((cause) => new OrchestrationDispatchCommandError({ message: cause.message })));
|
|
26470
26618
|
const normalizeProjectWorkspaceRootForCreate = (workspaceRoot, createIfMissing) => workspacePaths.normalizeWorkspaceRoot(workspaceRoot, { createIfMissing: createIfMissing === true }).pipe(Effect.mapError((cause) => new OrchestrationDispatchCommandError({ message: cause.message })));
|
|
@@ -26612,79 +26760,6 @@ const makeProviderMaintenanceCommandCoordinator = Effect.fn("makeProviderMainten
|
|
|
26612
26760
|
return { withCommandLock };
|
|
26613
26761
|
});
|
|
26614
26762
|
//#endregion
|
|
26615
|
-
//#region ../../packages/shared/src/semver.ts
|
|
26616
|
-
const SEMVER_NUMBER_SEGMENT = /^\d+$/;
|
|
26617
|
-
function normalizeSemverVersion(version) {
|
|
26618
|
-
const [main, prerelease] = version.trim().split("-", 2);
|
|
26619
|
-
const segments = [];
|
|
26620
|
-
for (const segment of (main ?? "").split(".")) {
|
|
26621
|
-
const trimmed = segment.trim();
|
|
26622
|
-
if (trimmed.length > 0) segments.push(trimmed);
|
|
26623
|
-
}
|
|
26624
|
-
if (segments.length === 2) segments.push("0");
|
|
26625
|
-
return prerelease ? `${segments.join(".")}-${prerelease}` : segments.join(".");
|
|
26626
|
-
}
|
|
26627
|
-
function parseSemver(value) {
|
|
26628
|
-
const [main = "", prerelease] = normalizeSemverVersion(value).replace(/^v/, "").split("-", 2);
|
|
26629
|
-
const segments = main.split(".");
|
|
26630
|
-
if (segments.length !== 3) return null;
|
|
26631
|
-
const [majorSegment, minorSegment, patchSegment] = segments;
|
|
26632
|
-
if (majorSegment === void 0 || minorSegment === void 0 || patchSegment === void 0) return null;
|
|
26633
|
-
if (!SEMVER_NUMBER_SEGMENT.test(majorSegment) || !SEMVER_NUMBER_SEGMENT.test(minorSegment) || !SEMVER_NUMBER_SEGMENT.test(patchSegment)) return null;
|
|
26634
|
-
const major = Number.parseInt(majorSegment, 10);
|
|
26635
|
-
const minor = Number.parseInt(minorSegment, 10);
|
|
26636
|
-
const patch = Number.parseInt(patchSegment, 10);
|
|
26637
|
-
if (![
|
|
26638
|
-
major,
|
|
26639
|
-
minor,
|
|
26640
|
-
patch
|
|
26641
|
-
].every(Number.isInteger)) return null;
|
|
26642
|
-
return {
|
|
26643
|
-
major,
|
|
26644
|
-
minor,
|
|
26645
|
-
patch,
|
|
26646
|
-
prerelease: parsePrereleaseSegments(prerelease)
|
|
26647
|
-
};
|
|
26648
|
-
}
|
|
26649
|
-
function parsePrereleaseSegments(prerelease) {
|
|
26650
|
-
if (prerelease === void 0) return [];
|
|
26651
|
-
const segments = [];
|
|
26652
|
-
for (const segment of prerelease.split(".")) {
|
|
26653
|
-
const trimmed = segment.trim();
|
|
26654
|
-
if (trimmed.length > 0) segments.push(trimmed);
|
|
26655
|
-
}
|
|
26656
|
-
return segments;
|
|
26657
|
-
}
|
|
26658
|
-
function comparePrereleaseIdentifier(left, right) {
|
|
26659
|
-
const leftNumeric = SEMVER_NUMBER_SEGMENT.test(left);
|
|
26660
|
-
const rightNumeric = SEMVER_NUMBER_SEGMENT.test(right);
|
|
26661
|
-
if (leftNumeric && rightNumeric) return Number.parseInt(left, 10) - Number.parseInt(right, 10);
|
|
26662
|
-
if (leftNumeric) return -1;
|
|
26663
|
-
if (rightNumeric) return 1;
|
|
26664
|
-
return left.localeCompare(right);
|
|
26665
|
-
}
|
|
26666
|
-
function compareSemverVersions(left, right) {
|
|
26667
|
-
const parsedLeft = parseSemver(left);
|
|
26668
|
-
const parsedRight = parseSemver(right);
|
|
26669
|
-
if (!parsedLeft || !parsedRight) return left.localeCompare(right);
|
|
26670
|
-
if (parsedLeft.major !== parsedRight.major) return parsedLeft.major - parsedRight.major;
|
|
26671
|
-
if (parsedLeft.minor !== parsedRight.minor) return parsedLeft.minor - parsedRight.minor;
|
|
26672
|
-
if (parsedLeft.patch !== parsedRight.patch) return parsedLeft.patch - parsedRight.patch;
|
|
26673
|
-
if (parsedLeft.prerelease.length === 0 && parsedRight.prerelease.length === 0) return 0;
|
|
26674
|
-
if (parsedLeft.prerelease.length === 0) return 1;
|
|
26675
|
-
if (parsedRight.prerelease.length === 0) return -1;
|
|
26676
|
-
const length = Math.max(parsedLeft.prerelease.length, parsedRight.prerelease.length);
|
|
26677
|
-
for (let index = 0; index < length; index += 1) {
|
|
26678
|
-
const leftIdentifier = parsedLeft.prerelease[index];
|
|
26679
|
-
const rightIdentifier = parsedRight.prerelease[index];
|
|
26680
|
-
if (leftIdentifier === void 0) return -1;
|
|
26681
|
-
if (rightIdentifier === void 0) return 1;
|
|
26682
|
-
const comparison = comparePrereleaseIdentifier(leftIdentifier, rightIdentifier);
|
|
26683
|
-
if (comparison !== 0) return comparison;
|
|
26684
|
-
}
|
|
26685
|
-
return 0;
|
|
26686
|
-
}
|
|
26687
|
-
//#endregion
|
|
26688
26763
|
//#region src/provider/providerMaintenance.ts
|
|
26689
26764
|
const LATEST_VERSION_CACHE_TTL_MS = 3600 * 1e3;
|
|
26690
26765
|
const LATEST_VERSION_TIMEOUT_MS = 4e3;
|
|
@@ -28276,7 +28351,7 @@ function normalizedRuntimeEnv(env) {
|
|
|
28276
28351
|
return Object.fromEntries(entries.toSorted(([left], [right]) => left.localeCompare(right)));
|
|
28277
28352
|
}
|
|
28278
28353
|
const make$35 = Effect.fn("TerminalManager.make")(function* () {
|
|
28279
|
-
const { terminalLogsDir } = yield* ServerConfig;
|
|
28354
|
+
const { terminalLogsDir } = yield* ServerConfig$1;
|
|
28280
28355
|
const ptyAdapter = yield* PtyAdapter;
|
|
28281
28356
|
const portDiscovery = yield* PortDiscovery;
|
|
28282
28357
|
return yield* makeWithOptions$1({
|
|
@@ -33227,7 +33302,7 @@ function bindProviderContext(provider, context) {
|
|
|
33227
33302
|
});
|
|
33228
33303
|
}
|
|
33229
33304
|
const makeWithProviders = Effect.fn("makeSourceControlProviderRegistryWithProviders")(function* (registrations) {
|
|
33230
|
-
const config = yield* ServerConfig;
|
|
33305
|
+
const config = yield* ServerConfig$1;
|
|
33231
33306
|
const process = yield* VcsProcess;
|
|
33232
33307
|
const vcsRegistry = yield* VcsDriverRegistry;
|
|
33233
33308
|
const providers = new Map(registrations.map((registration) => [registration.kind, registration.provider]));
|
|
@@ -35038,7 +35113,7 @@ const layer$10 = Layer.effect(VcsProvisioningService, make$15);
|
|
|
35038
35113
|
//#region src/review/ReviewService.ts
|
|
35039
35114
|
var ReviewService = class extends Context.Service()("@p4code/cli/review/ReviewService") {};
|
|
35040
35115
|
const make$14 = Effect.gen(function* () {
|
|
35041
|
-
const config = yield* ServerConfig;
|
|
35116
|
+
const config = yield* ServerConfig$1;
|
|
35042
35117
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
35043
35118
|
const path = yield* Path.Path;
|
|
35044
35119
|
const vcsRegistry = yield* VcsDriverRegistry;
|
|
@@ -35949,7 +36024,7 @@ const VCS_PROBES = [{
|
|
|
35949
36024
|
}];
|
|
35950
36025
|
var SourceControlDiscovery = class extends Context.Service()("@p4code/cli/sourceControl/SourceControlDiscovery") {};
|
|
35951
36026
|
const make$10 = Effect.gen(function* () {
|
|
35952
|
-
const config = yield* ServerConfig;
|
|
36027
|
+
const config = yield* ServerConfig$1;
|
|
35953
36028
|
const process = yield* VcsProcess;
|
|
35954
36029
|
const sourceControlProviders = yield* SourceControlProviderRegistry;
|
|
35955
36030
|
const probe = (input) => {
|
|
@@ -36031,7 +36106,7 @@ function expandHomePath$1(input, path) {
|
|
|
36031
36106
|
return input;
|
|
36032
36107
|
}
|
|
36033
36108
|
const make$9 = Effect.gen(function* () {
|
|
36034
|
-
const config = yield* ServerConfig;
|
|
36109
|
+
const config = yield* ServerConfig$1;
|
|
36035
36110
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
36036
36111
|
const git = yield* GitVcsDriver;
|
|
36037
36112
|
const path = yield* Path.Path;
|
|
@@ -36390,7 +36465,7 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
|
|
|
36390
36465
|
const providerRegistry = yield* ProviderRegistry;
|
|
36391
36466
|
const providerMaintenanceRunner = yield* ProviderMaintenanceRunner;
|
|
36392
36467
|
const serverSelfUpdate = yield* ServerSelfUpdate;
|
|
36393
|
-
const config = yield* ServerConfig;
|
|
36468
|
+
const config = yield* ServerConfig$1;
|
|
36394
36469
|
const lifecycleEvents = yield* ServerLifecycleEvents;
|
|
36395
36470
|
const serverSettings = yield* ServerSettingsService;
|
|
36396
36471
|
const startup = yield* ServerRuntimeStartup;
|
|
@@ -37034,7 +37109,7 @@ const ProviderSessionRuntime = Schema$1.Struct({
|
|
|
37034
37109
|
*/
|
|
37035
37110
|
providerInstanceId: Schema$1.NullOr(ProviderInstanceId),
|
|
37036
37111
|
adapterKey: Schema$1.String,
|
|
37037
|
-
runtimeMode: RuntimeMode
|
|
37112
|
+
runtimeMode: RuntimeMode,
|
|
37038
37113
|
status: ProviderSessionRuntimeStatus,
|
|
37039
37114
|
lastSeenAt: IsoDateTime,
|
|
37040
37115
|
resumeCursor: Schema$1.NullOr(Schema$1.Unknown),
|
|
@@ -37667,7 +37742,7 @@ var ProviderEventLoggers = class extends Context.Service()("@p4code/cli/provider
|
|
|
37667
37742
|
* is `undefined` and writes from that stream become no-ops downstream.
|
|
37668
37743
|
*/
|
|
37669
37744
|
const ProviderEventLoggersLive = Layer.effect(ProviderEventLoggers, Effect.gen(function* () {
|
|
37670
|
-
const { providerEventLogPath } = yield* ServerConfig;
|
|
37745
|
+
const { providerEventLogPath } = yield* ServerConfig$1;
|
|
37671
37746
|
return {
|
|
37672
37747
|
native: yield* makeEventNdjsonLogger(providerEventLogPath, { stream: "native" }),
|
|
37673
37748
|
canonical: yield* makeEventNdjsonLogger(providerEventLogPath, { stream: "canonical" })
|
|
@@ -41136,7 +41211,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
|
|
|
41136
41211
|
const boundInstanceId = options?.instanceId ?? ProviderInstanceId.make("claudeAgent");
|
|
41137
41212
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
41138
41213
|
const path = yield* Path.Path;
|
|
41139
|
-
const serverConfig = yield* ServerConfig;
|
|
41214
|
+
const serverConfig = yield* ServerConfig$1;
|
|
41140
41215
|
const crypto = yield* Crypto.Crypto;
|
|
41141
41216
|
const claudeEnvironment = yield* makeClaudeEnvironment(claudeSettings, options?.environment).pipe(Effect.provideService(Path.Path, path));
|
|
41142
41217
|
const claudeSdkExecutablePath = yield* resolveClaudeSdkExecutablePath(claudeSettings.binaryPath, claudeEnvironment);
|
|
@@ -43019,7 +43094,7 @@ const ClaudeDriver = {
|
|
|
43019
43094
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
43020
43095
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
43021
43096
|
const path = yield* Path.Path;
|
|
43022
|
-
const { cwd } = yield* ServerConfig;
|
|
43097
|
+
const { cwd } = yield* ServerConfig$1;
|
|
43023
43098
|
const httpClient = yield* HttpClient.HttpClient;
|
|
43024
43099
|
const serverSettings = yield* ServerSettingsService;
|
|
43025
43100
|
const eventLoggers = yield* ProviderEventLoggers;
|
|
@@ -43130,7 +43205,7 @@ const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(function* (
|
|
|
43130
43205
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
43131
43206
|
const path = yield* Path.Path;
|
|
43132
43207
|
const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
43133
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
43208
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
43134
43209
|
const resolvedEnvironment = environment ?? process.env;
|
|
43135
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")));
|
|
43136
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({
|
|
@@ -63448,7 +63523,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
|
|
|
63448
63523
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
63449
63524
|
const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
63450
63525
|
const crypto = yield* Crypto.Crypto;
|
|
63451
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
63526
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
63452
63527
|
const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== void 0 ? yield* makeEventNdjsonLogger(options.nativeEventLogPath, { stream: "native" }) : void 0);
|
|
63453
63528
|
const managedNativeEventLogger = options?.nativeEventLogger === void 0 ? nativeEventLogger : void 0;
|
|
63454
63529
|
const runtimeEventQueue = yield* Queue.unbounded();
|
|
@@ -69941,7 +70016,7 @@ function makeCursorAdapter(cursorSettings, options) {
|
|
|
69941
70016
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
69942
70017
|
const path = yield* Path.Path;
|
|
69943
70018
|
const childProcessSpawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
|
|
69944
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
70019
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
69945
70020
|
const crypto = yield* Crypto.Crypto;
|
|
69946
70021
|
const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== void 0 ? yield* makeEventNdjsonLogger(options.nativeEventLogPath, { stream: "native" }) : void 0);
|
|
69947
70022
|
const managedNativeEventLogger = options?.nativeEventLogger === void 0 ? nativeEventLogger : void 0;
|
|
@@ -71060,7 +71135,7 @@ function makeGrokAdapter(grokSettings, options) {
|
|
|
71060
71135
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
71061
71136
|
const path = yield* Path.Path;
|
|
71062
71137
|
const childProcessSpawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
|
|
71063
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
71138
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
71064
71139
|
const crypto = yield* Crypto.Crypto;
|
|
71065
71140
|
const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== void 0 ? yield* makeEventNdjsonLogger(options.nativeEventLogPath, { stream: "native" }) : void 0);
|
|
71066
71141
|
const managedNativeEventLogger = options?.nativeEventLogger === void 0 ? nativeEventLogger : void 0;
|
|
@@ -72234,7 +72309,7 @@ function getOpenCodeTextResponse(parts) {
|
|
|
72234
72309
|
return (parts ?? []).filter(isOpenCodeTextPart).map((part) => part.text).join("").trim();
|
|
72235
72310
|
}
|
|
72236
72311
|
const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration")(function* (openCodeSettings, environment) {
|
|
72237
|
-
const serverConfig = yield* ServerConfig;
|
|
72312
|
+
const serverConfig = yield* ServerConfig$1;
|
|
72238
72313
|
const openCodeRuntime = yield* OpenCodeRuntime;
|
|
72239
72314
|
const resolvedEnvironment = environment ?? process.env;
|
|
72240
72315
|
const idleFiberScope = yield* Effect.acquireRelease(Scope.make(), (scope) => Scope.close(scope, Exit.void));
|
|
@@ -72765,7 +72840,7 @@ const stopOpenCodeContext = Effect.fn("stopOpenCodeContext")(function* (context)
|
|
|
72765
72840
|
function makeOpenCodeAdapter(openCodeSettings, options) {
|
|
72766
72841
|
return Effect.gen(function* () {
|
|
72767
72842
|
const boundInstanceId = options?.instanceId ?? ProviderInstanceId.make("opencode");
|
|
72768
|
-
const serverConfig = yield* ServerConfig;
|
|
72843
|
+
const serverConfig = yield* ServerConfig$1;
|
|
72769
72844
|
const openCodeRuntime = yield* OpenCodeRuntime;
|
|
72770
72845
|
const crypto = yield* Crypto.Crypto;
|
|
72771
72846
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
@@ -73836,7 +73911,7 @@ const BUILT_IN_DRIVERS = [
|
|
|
73836
73911
|
defaultConfig: () => decodeOpenCodeSettings({}),
|
|
73837
73912
|
create: ({ instanceId, displayName, accentColor, environment, enabled, config }) => Effect.gen(function* () {
|
|
73838
73913
|
const openCodeRuntime = yield* OpenCodeRuntime;
|
|
73839
|
-
const serverConfig = yield* ServerConfig;
|
|
73914
|
+
const serverConfig = yield* ServerConfig$1;
|
|
73840
73915
|
const httpClient = yield* HttpClient.HttpClient;
|
|
73841
73916
|
const serverSettings = yield* ServerSettingsService;
|
|
73842
73917
|
const eventLoggers = yield* ProviderEventLoggers;
|
|
@@ -77547,7 +77622,7 @@ const buildSnapshotSource = (instance) => ({
|
|
|
77547
77622
|
});
|
|
77548
77623
|
const ProviderRegistryLive = Layer.effect(ProviderRegistry, Effect.gen(function* () {
|
|
77549
77624
|
const instanceRegistry = yield* ProviderInstanceRegistry;
|
|
77550
|
-
const config = yield* ServerConfig;
|
|
77625
|
+
const config = yield* ServerConfig$1;
|
|
77551
77626
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
77552
77627
|
const path = yield* Path.Path;
|
|
77553
77628
|
const changesPubSub = yield* Effect.acquireRelease(PubSub.unbounded(), PubSub.shutdown);
|
|
@@ -77774,7 +77849,7 @@ const ProviderRegistryLive = Layer.effect(ProviderRegistry, Effect.gen(function*
|
|
|
77774
77849
|
//#endregion
|
|
77775
77850
|
//#region src/serverLogger.ts
|
|
77776
77851
|
const ServerLoggerLive = Effect.gen(function* () {
|
|
77777
|
-
const config = yield* ServerConfig;
|
|
77852
|
+
const config = yield* ServerConfig$1;
|
|
77778
77853
|
const minimumLogLevelLayer = Layer.succeed(References.MinimumLogLevel, config.logLevel);
|
|
77779
77854
|
const loggerLayer = Logger.layer([Logger.consolePretty(), Logger.tracerLogger], { mergeWithExisting: false });
|
|
77780
77855
|
return Layer.mergeAll(loggerLayer, minimumLogLevelLayer);
|
|
@@ -77783,7 +77858,7 @@ const ServerLoggerLive = Effect.gen(function* () {
|
|
|
77783
77858
|
//#region src/observability/Layers/Observability.ts
|
|
77784
77859
|
const otlpSerializationLayer = OtlpSerialization.layerJson;
|
|
77785
77860
|
const ObservabilityLive = Layer.unwrap(Effect.gen(function* () {
|
|
77786
|
-
const config = yield* ServerConfig;
|
|
77861
|
+
const config = yield* ServerConfig$1;
|
|
77787
77862
|
const traceReferencesLayer = Layer.mergeAll(Layer.succeed(Tracer.MinimumTraceLevel, config.traceMinLevel), Layer.succeed(References.TracerTimingEnabled, config.traceTimingEnabled));
|
|
77788
77863
|
const tracerLayer = Layer.unwrap(Effect.gen(function* () {
|
|
77789
77864
|
const sink = yield* makeTraceSink({
|
|
@@ -78057,11 +78132,11 @@ const disableTailscaleServe = (input = {}) => Effect.gen(function* () {
|
|
|
78057
78132
|
//#region src/server.ts
|
|
78058
78133
|
const HTTP_PREEMPTIVE_SHUTDOWN_GRACE_MS = 0;
|
|
78059
78134
|
const PtyAdapterLive = Layer.unwrap(Effect.gen(function* () {
|
|
78060
|
-
if (typeof Bun !== "undefined") return (yield* Effect.promise(() => import("./BunPtyAdapter-
|
|
78061
|
-
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;
|
|
78062
78137
|
}));
|
|
78063
78138
|
const HttpServerLive = Layer.unwrap(Effect.gen(function* () {
|
|
78064
|
-
const config = yield* ServerConfig;
|
|
78139
|
+
const config = yield* ServerConfig$1;
|
|
78065
78140
|
if (typeof Bun !== "undefined") return (yield* Effect.promise(() => import("@effect/platform-bun/BunHttpServer"))).layer({
|
|
78066
78141
|
port: config.port,
|
|
78067
78142
|
hostname: config.host ?? "127.0.0.1",
|
|
@@ -78112,7 +78187,7 @@ const RuntimeDependenciesLive = ReactorLayerLive.pipe(Layer.provideMerge(Checkpo
|
|
|
78112
78187
|
const RuntimeServicesLive = layer$43.pipe(Layer.provideMerge(RuntimeDependenciesLive));
|
|
78113
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));
|
|
78114
78189
|
const makeServerLayer = Layer.unwrap(Effect.gen(function* () {
|
|
78115
|
-
const config = yield* ServerConfig;
|
|
78190
|
+
const config = yield* ServerConfig$1;
|
|
78116
78191
|
yield* fixPath();
|
|
78117
78192
|
const httpListeningLayer = Layer.effectDiscard(Effect.gen(function* () {
|
|
78118
78193
|
yield* HttpServer.HttpServer;
|
|
@@ -78160,7 +78235,7 @@ const runServer = Layer.launch(makeServerLayer);
|
|
|
78160
78235
|
//#region src/cli/server.ts
|
|
78161
78236
|
const runServerCommand = (flags, options) => Effect.gen(function* () {
|
|
78162
78237
|
const config = yield* resolveServerConfig(flags, yield* GlobalFlag.LogLevel, options);
|
|
78163
|
-
return yield* runServer.pipe(Effect.provideService(ServerConfig, config));
|
|
78238
|
+
return yield* runServer.pipe(Effect.provideService(ServerConfig$1, config));
|
|
78164
78239
|
});
|
|
78165
78240
|
const startCommand = Command.make("start", { ...sharedServerCommandFlags }).pipe(Command.withDescription("Run the P4Code server."), Command.withHandler((flags) => runServerCommand(flags)));
|
|
78166
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, {
|
|
@@ -78168,6 +78243,104 @@ const serveCommand = Command.make("serve", { ...sharedServerCommandFlags }).pipe
|
|
|
78168
78243
|
forceAutoBootstrapProjectFromCwd: false
|
|
78169
78244
|
})));
|
|
78170
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
|
|
78171
78344
|
//#region src/cli/service.ts
|
|
78172
78345
|
const isBootServiceCommandError = Schema$1.is(BootServiceCommandError);
|
|
78173
78346
|
const bootServiceLayer = (config) => layer$46({
|
|
@@ -78220,7 +78393,7 @@ const runServiceCommand = Effect.fn("cli.service.run")(function* (flags, run) {
|
|
|
78220
78393
|
const config = yield* resolveCliAuthConfig(flags, yield* GlobalFlag.LogLevel);
|
|
78221
78394
|
const baseDirNotice = yield* describeNonDefaultBaseDir(config.baseDir);
|
|
78222
78395
|
if (baseDirNotice !== null) yield* Console.error(baseDirNotice);
|
|
78223
|
-
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));
|
|
78224
78397
|
});
|
|
78225
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* () {
|
|
78226
78399
|
const result = yield* reconcileService();
|
|
@@ -78234,6 +78407,8 @@ const serviceInstallCommand = Command.make("install", projectLocationFlags).pipe
|
|
|
78234
78407
|
cliVersion: version,
|
|
78235
78408
|
platform: yield* HostProcessPlatform
|
|
78236
78409
|
}));
|
|
78410
|
+
const completion = yield* installZshCompletion().pipe(Effect.orElseSucceed(() => null));
|
|
78411
|
+
if (completion !== null) yield* Console.log(formatZshCompletionInstall(completion));
|
|
78237
78412
|
}))));
|
|
78238
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* () {
|
|
78239
78414
|
const result = yield* reconcileService();
|
|
@@ -78280,7 +78455,23 @@ const serviceCommand = Command.make("service").pipe(Command.withDescription("Man
|
|
|
78280
78455
|
]));
|
|
78281
78456
|
//#endregion
|
|
78282
78457
|
//#region src/bin.ts
|
|
78283
|
-
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);
|
|
78284
78475
|
const makeCli = () => Command.make("p4", { ...sharedServerCommandFlags }).pipe(Command.withDescription("Run the P4Code server."), Command.withHandler((flags) => runServerCommand(flags)), Command.withSubcommands([
|
|
78285
78476
|
startCommand,
|
|
78286
78477
|
serveCommand,
|
|
@@ -78289,7 +78480,7 @@ const makeCli = () => Command.make("p4", { ...sharedServerCommandFlags }).pipe(C
|
|
|
78289
78480
|
serviceCommand
|
|
78290
78481
|
]));
|
|
78291
78482
|
const cli = makeCli();
|
|
78292
|
-
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);
|
|
78293
78484
|
//#endregion
|
|
78294
78485
|
export { cli, makeCli };
|
|
78295
78486
|
|