@p4code/cli 0.0.35 → 0.0.37
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 +1094 -898
- package/dist/client/assets/{DiffPanel-DZwXXRpa.js → DiffPanel-xkGxJH4k.js} +2 -2
- package/dist/client/assets/{FilePreviewPanel-BHk87SKl.js → FilePreviewPanel-CmJUrNYJ.js} +2 -2
- package/dist/client/assets/{PreviewPanel-Cy7Z3Mfj.js → PreviewPanel-B5dlT-n2.js} +2 -2
- package/dist/client/assets/{fileCommentAnnotations-BBdil_-3.js → fileCommentAnnotations-BKadMjLJ.js} +2 -2
- package/dist/client/assets/{index-CXsSIu-m.js → index-qr_OWE66.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,713 @@ 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.37";
|
|
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
|
+
/**
|
|
920
|
+
* Both commands, because `npm i -g` only replaces the binary on disk. The
|
|
921
|
+
* service is a running process still executing the old code until
|
|
922
|
+
* `service update` restarts it onto the new one.
|
|
923
|
+
*/
|
|
924
|
+
function formatUpdateReminder(input) {
|
|
925
|
+
return [`Update available: ${PACKAGE_NAME}@${input.latestVersion} (running ${input.currentVersion}).`, ` npm i -g ${PACKAGE_NAME}@latest && p4 service update`].join("\n");
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* The reminder line, or null when there is nothing to say. Callers print it;
|
|
929
|
+
* keeping the decision pure makes it testable without a console.
|
|
930
|
+
*/
|
|
931
|
+
const resolveUpdateReminder = Effect.fn("cli.updateCheck.reminder")(function* (input) {
|
|
932
|
+
if (((yield* HostProcessEnvironment)["P4CODE_NO_UPDATE_CHECK"] ?? "") !== "") return null;
|
|
933
|
+
if (input.currentVersion.includes("-")) return null;
|
|
934
|
+
const latestVersion = yield* resolveLatestVersion(input.stateDir);
|
|
935
|
+
if (latestVersion === null) return null;
|
|
936
|
+
if (compareSemverVersions(input.currentVersion, latestVersion) >= 0) return null;
|
|
937
|
+
return formatUpdateReminder({
|
|
938
|
+
currentVersion: input.currentVersion,
|
|
939
|
+
latestVersion
|
|
940
|
+
});
|
|
941
|
+
});
|
|
236
942
|
//#endregion
|
|
237
943
|
//#region ../../packages/contracts/src/baseSchemas.ts
|
|
238
944
|
const TrimmedString = Schema$1.String.pipe(Schema$1.decodeTo(Schema$1.String, SchemaTransformation.transformOrFail({
|
|
@@ -928,7 +1634,7 @@ const ModelSelection = Schema$1.Struct({
|
|
|
928
1634
|
return Effect.succeed(base);
|
|
929
1635
|
}
|
|
930
1636
|
})));
|
|
931
|
-
const RuntimeMode
|
|
1637
|
+
const RuntimeMode = Schema$1.Literals([
|
|
932
1638
|
"approval-required",
|
|
933
1639
|
"auto-accept-edits",
|
|
934
1640
|
"auto",
|
|
@@ -1050,7 +1756,7 @@ const OrchestrationSession = Schema$1.Struct({
|
|
|
1050
1756
|
status: OrchestrationSessionStatus,
|
|
1051
1757
|
providerName: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1052
1758
|
providerInstanceId: Schema$1.optional(ProviderInstanceId),
|
|
1053
|
-
runtimeMode: RuntimeMode
|
|
1759
|
+
runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
|
|
1054
1760
|
activeTurnId: Schema$1.NullOr(TurnId),
|
|
1055
1761
|
lastError: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1056
1762
|
updatedAt: IsoDateTime
|
|
@@ -1111,7 +1817,7 @@ const OrchestrationThread = Schema$1.Struct({
|
|
|
1111
1817
|
projectId: ProjectId,
|
|
1112
1818
|
title: TrimmedNonEmptyString,
|
|
1113
1819
|
modelSelection: ModelSelection,
|
|
1114
|
-
runtimeMode: RuntimeMode
|
|
1820
|
+
runtimeMode: RuntimeMode,
|
|
1115
1821
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1116
1822
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1117
1823
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
@@ -1151,7 +1857,7 @@ const OrchestrationThreadShell = Schema$1.Struct({
|
|
|
1151
1857
|
projectId: ProjectId,
|
|
1152
1858
|
title: TrimmedNonEmptyString,
|
|
1153
1859
|
modelSelection: ModelSelection,
|
|
1154
|
-
runtimeMode: RuntimeMode
|
|
1860
|
+
runtimeMode: RuntimeMode,
|
|
1155
1861
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1156
1862
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1157
1863
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
@@ -1273,7 +1979,7 @@ const ThreadCreateCommand = Schema$1.Struct({
|
|
|
1273
1979
|
projectId: ProjectId,
|
|
1274
1980
|
title: TrimmedNonEmptyString,
|
|
1275
1981
|
modelSelection: ModelSelection,
|
|
1276
|
-
runtimeMode: RuntimeMode
|
|
1982
|
+
runtimeMode: RuntimeMode,
|
|
1277
1983
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1278
1984
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1279
1985
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
@@ -1331,7 +2037,7 @@ const ThreadRuntimeModeSetCommand = Schema$1.Struct({
|
|
|
1331
2037
|
type: Schema$1.Literal("thread.runtime-mode.set"),
|
|
1332
2038
|
commandId: CommandId,
|
|
1333
2039
|
threadId: ThreadId,
|
|
1334
|
-
runtimeMode: RuntimeMode
|
|
2040
|
+
runtimeMode: RuntimeMode,
|
|
1335
2041
|
createdAt: IsoDateTime
|
|
1336
2042
|
});
|
|
1337
2043
|
const ThreadInteractionModeSetCommand = Schema$1.Struct({
|
|
@@ -1345,7 +2051,7 @@ const ThreadTurnStartBootstrapCreateThread = Schema$1.Struct({
|
|
|
1345
2051
|
projectId: ProjectId,
|
|
1346
2052
|
title: TrimmedNonEmptyString,
|
|
1347
2053
|
modelSelection: ModelSelection,
|
|
1348
|
-
runtimeMode: RuntimeMode
|
|
2054
|
+
runtimeMode: RuntimeMode,
|
|
1349
2055
|
interactionMode: ProviderInteractionMode,
|
|
1350
2056
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1351
2057
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
@@ -1374,7 +2080,7 @@ const ThreadTurnStartCommand = Schema$1.Struct({
|
|
|
1374
2080
|
}),
|
|
1375
2081
|
modelSelection: Schema$1.optional(ModelSelection),
|
|
1376
2082
|
titleSeed: Schema$1.optional(TrimmedNonEmptyString),
|
|
1377
|
-
runtimeMode: RuntimeMode
|
|
2083
|
+
runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
|
|
1378
2084
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1379
2085
|
bootstrap: Schema$1.optional(ThreadTurnStartBootstrap),
|
|
1380
2086
|
sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
|
|
@@ -1392,7 +2098,7 @@ const ClientThreadTurnStartCommand = Schema$1.Struct({
|
|
|
1392
2098
|
}),
|
|
1393
2099
|
modelSelection: Schema$1.optional(ModelSelection),
|
|
1394
2100
|
titleSeed: Schema$1.optional(TrimmedNonEmptyString),
|
|
1395
|
-
runtimeMode: RuntimeMode
|
|
2101
|
+
runtimeMode: RuntimeMode,
|
|
1396
2102
|
interactionMode: ProviderInteractionMode,
|
|
1397
2103
|
bootstrap: Schema$1.optional(ThreadTurnStartBootstrap),
|
|
1398
2104
|
sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
|
|
@@ -1608,7 +2314,7 @@ const ThreadCreatedPayload$1 = Schema$1.Struct({
|
|
|
1608
2314
|
projectId: ProjectId,
|
|
1609
2315
|
title: TrimmedNonEmptyString,
|
|
1610
2316
|
modelSelection: ModelSelection,
|
|
1611
|
-
runtimeMode: RuntimeMode
|
|
2317
|
+
runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
|
|
1612
2318
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1613
2319
|
branch: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
1614
2320
|
worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
|
|
@@ -1659,7 +2365,7 @@ const ThreadMetaUpdatedPayload$1 = Schema$1.Struct({
|
|
|
1659
2365
|
});
|
|
1660
2366
|
const ThreadRuntimeModeSetPayload$1 = Schema$1.Struct({
|
|
1661
2367
|
threadId: ThreadId,
|
|
1662
|
-
runtimeMode: RuntimeMode
|
|
2368
|
+
runtimeMode: RuntimeMode,
|
|
1663
2369
|
updatedAt: IsoDateTime
|
|
1664
2370
|
});
|
|
1665
2371
|
const ThreadInteractionModeSetPayload$1 = Schema$1.Struct({
|
|
@@ -1683,7 +2389,7 @@ const ThreadTurnStartRequestedPayload = Schema$1.Struct({
|
|
|
1683
2389
|
messageId: MessageId,
|
|
1684
2390
|
modelSelection: Schema$1.optional(ModelSelection),
|
|
1685
2391
|
titleSeed: Schema$1.optional(TrimmedNonEmptyString),
|
|
1686
|
-
runtimeMode: RuntimeMode
|
|
2392
|
+
runtimeMode: RuntimeMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE$2))),
|
|
1687
2393
|
interactionMode: ProviderInteractionMode.pipe(Schema$1.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE))),
|
|
1688
2394
|
sourceProposedPlan: Schema$1.optional(SourceProposedPlanReference),
|
|
1689
2395
|
createdAt: IsoDateTime
|
|
@@ -3801,7 +4507,7 @@ Schema$1.Struct({
|
|
|
3801
4507
|
provider: ProviderDriverKind,
|
|
3802
4508
|
providerInstanceId: Schema$1.optional(ProviderInstanceId),
|
|
3803
4509
|
status: ProviderSessionStatus,
|
|
3804
|
-
runtimeMode: RuntimeMode
|
|
4510
|
+
runtimeMode: RuntimeMode,
|
|
3805
4511
|
cwd: Schema$1.optional(TrimmedNonEmptyString),
|
|
3806
4512
|
model: Schema$1.optional(TrimmedNonEmptyString),
|
|
3807
4513
|
threadId: ThreadId,
|
|
@@ -3820,7 +4526,7 @@ const ProviderSessionStartInput = Schema$1.Struct({
|
|
|
3820
4526
|
resumeCursor: Schema$1.optional(Schema$1.Unknown),
|
|
3821
4527
|
approvalPolicy: Schema$1.optional(ProviderApprovalPolicy),
|
|
3822
4528
|
sandboxMode: Schema$1.optional(ProviderSandboxMode),
|
|
3823
|
-
runtimeMode: RuntimeMode
|
|
4529
|
+
runtimeMode: RuntimeMode
|
|
3824
4530
|
});
|
|
3825
4531
|
const ProviderSendTurnInput = Schema$1.Struct({
|
|
3826
4532
|
threadId: ThreadId,
|
|
@@ -5371,7 +6077,7 @@ const ServerSignalProcessResult = Schema$1.Struct({
|
|
|
5371
6077
|
signaled: Schema$1.Boolean,
|
|
5372
6078
|
message: Schema$1.Option(TrimmedNonEmptyString)
|
|
5373
6079
|
});
|
|
5374
|
-
const ServerConfig
|
|
6080
|
+
const ServerConfig = Schema$1.Struct({
|
|
5375
6081
|
environment: ExecutionEnvironmentDescriptor,
|
|
5376
6082
|
auth: ServerAuthDescriptor,
|
|
5377
6083
|
cwd: TrimmedNonEmptyString,
|
|
@@ -5418,7 +6124,7 @@ const ServerConfigSettingsUpdatedPayload = Schema$1.Struct({ settings: ServerSet
|
|
|
5418
6124
|
const ServerConfigStreamSnapshotEvent = Schema$1.Struct({
|
|
5419
6125
|
version: Schema$1.Literal(1),
|
|
5420
6126
|
type: Schema$1.Literal("snapshot"),
|
|
5421
|
-
config: ServerConfig
|
|
6127
|
+
config: ServerConfig
|
|
5422
6128
|
});
|
|
5423
6129
|
const ServerConfigStreamKeybindingsUpdatedEvent = Schema$1.Struct({
|
|
5424
6130
|
version: Schema$1.Literal(1),
|
|
@@ -6623,7 +7329,7 @@ const WsServerProbeRpc = Rpc.make(WS_METHODS.serverProbe, {
|
|
|
6623
7329
|
});
|
|
6624
7330
|
const WsServerGetConfigRpc = Rpc.make(WS_METHODS.serverGetConfig, {
|
|
6625
7331
|
payload: Schema$1.Struct({}),
|
|
6626
|
-
success: ServerConfig
|
|
7332
|
+
success: ServerConfig,
|
|
6627
7333
|
error: Schema$1.Union([
|
|
6628
7334
|
KeybindingsConfigError,
|
|
6629
7335
|
ServerSettingsError,
|
|
@@ -7006,117 +7712,6 @@ function parseAllowedOAuthScope(input) {
|
|
|
7006
7712
|
return scopes;
|
|
7007
7713
|
}
|
|
7008
7714
|
//#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
7715
|
//#region src/auth/utils.ts
|
|
7121
7716
|
const SESSION_COOKIE_NAME = "p4_session";
|
|
7122
7717
|
/**
|
|
@@ -7220,7 +7815,7 @@ function deriveAuthClientMetadata(input) {
|
|
|
7220
7815
|
//#region src/auth/EnvironmentAuthPolicy.ts
|
|
7221
7816
|
var EnvironmentAuthPolicy = class extends Context.Service()("@p4code/cli/auth/EnvironmentAuthPolicy") {};
|
|
7222
7817
|
const make$65 = Effect.gen(function* () {
|
|
7223
|
-
const config = yield* ServerConfig;
|
|
7818
|
+
const config = yield* ServerConfig$1;
|
|
7224
7819
|
const isRemoteReachable = isRemoteReachableHost(config.host);
|
|
7225
7820
|
const policy = config.mode === "desktop" ? isRemoteReachable ? "remote-reachable" : "desktop-managed-local" : isRemoteReachable ? "remote-reachable" : "loopback-browser";
|
|
7226
7821
|
const descriptor = {
|
|
@@ -7599,7 +8194,7 @@ const PAIRING_TOKEN_LENGTH = 12;
|
|
|
7599
8194
|
const PAIRING_TOKEN_REJECTION_LIMIT = Math.floor(256 / 32) * 32;
|
|
7600
8195
|
const make$63 = Effect.gen(function* () {
|
|
7601
8196
|
const crypto = yield* Crypto.Crypto;
|
|
7602
|
-
const config = yield* ServerConfig;
|
|
8197
|
+
const config = yield* ServerConfig$1;
|
|
7603
8198
|
const pairingLinks = yield* AuthPairingLinkRepository;
|
|
7604
8199
|
const seededGrantsRef = yield* Ref.make(/* @__PURE__ */ new Map());
|
|
7605
8200
|
const changesPubSub = yield* PubSub.unbounded();
|
|
@@ -7866,7 +8461,7 @@ const make$62 = Effect.gen(function* () {
|
|
|
7866
8461
|
const crypto = yield* Crypto.Crypto;
|
|
7867
8462
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
7868
8463
|
const path = yield* Path.Path;
|
|
7869
|
-
const serverConfig = yield* ServerConfig;
|
|
8464
|
+
const serverConfig = yield* ServerConfig$1;
|
|
7870
8465
|
yield* fileSystem.makeDirectory(serverConfig.secretsDir, { recursive: true });
|
|
7871
8466
|
yield* fileSystem.chmod(serverConfig.secretsDir, 448).pipe(Effect.mapError((cause) => new SecretStoreSecureError({
|
|
7872
8467
|
resource: `secrets directory ${serverConfig.secretsDir}`,
|
|
@@ -8410,7 +9005,7 @@ function toAuthClientSession(input) {
|
|
|
8410
9005
|
}
|
|
8411
9006
|
const make$60 = Effect.gen(function* () {
|
|
8412
9007
|
const crypto = yield* Crypto.Crypto;
|
|
8413
|
-
const serverConfig = yield* ServerConfig;
|
|
9008
|
+
const serverConfig = yield* ServerConfig$1;
|
|
8414
9009
|
const secretStore = yield* ServerSecretStore;
|
|
8415
9010
|
const authSessions = yield* AuthSessionRepository;
|
|
8416
9011
|
const signingSecret = yield* secretStore.getOrCreateRandom(SIGNING_SECRET_NAME$1, 32);
|
|
@@ -10271,7 +10866,7 @@ const makeSqlitePersistenceLive = Effect.fn("makeSqlitePersistenceLive")(functio
|
|
|
10271
10866
|
}));
|
|
10272
10867
|
}, Layer.unwrap);
|
|
10273
10868
|
Layer.provideMerge(setup, makeRuntimeSqliteLayer({ filename: ":memory:" }));
|
|
10274
|
-
const layerConfig = Layer.unwrap(Effect.map(Effect.service(ServerConfig), ({ dbPath }) => makeSqlitePersistenceLive(dbPath)));
|
|
10869
|
+
const layerConfig = Layer.unwrap(Effect.map(Effect.service(ServerConfig$1), ({ dbPath }) => makeSqlitePersistenceLive(dbPath)));
|
|
10275
10870
|
const INTERNAL_ADMINISTRATIVE_BOOTSTRAP_SUBJECT = "administrative-bootstrap";
|
|
10276
10871
|
const serverAuthInternalErrorContext = { cause: Schema$1.Defect() };
|
|
10277
10872
|
var ServerAuthBootstrapCredentialValidationError = class extends Schema$1.TaggedErrorClass()("ServerAuthBootstrapCredentialValidationError", { ...serverAuthInternalErrorContext }) {
|
|
@@ -10940,646 +11535,204 @@ function normalizePersistedServerSettingString(value) {
|
|
|
10940
11535
|
const trimmed = value?.trim();
|
|
10941
11536
|
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
10942
11537
|
}
|
|
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;
|
|
11538
|
+
function extractPersistedServerObservabilitySettings(input) {
|
|
11539
|
+
return {
|
|
11540
|
+
otlpTracesUrl: normalizePersistedServerSettingString(input.observability?.otlpTracesUrl),
|
|
11541
|
+
otlpMetricsUrl: normalizePersistedServerSettingString(input.observability?.otlpMetricsUrl)
|
|
11542
|
+
};
|
|
11360
11543
|
}
|
|
11361
|
-
function
|
|
11362
|
-
|
|
11544
|
+
function parsePersistedServerObservabilitySettings(raw) {
|
|
11545
|
+
const decoded = decodeServerSettingsJson(raw);
|
|
11546
|
+
if (Option.isSome(decoded)) return extractPersistedServerObservabilitySettings(decoded.value);
|
|
11547
|
+
return {
|
|
11548
|
+
otlpTracesUrl: void 0,
|
|
11549
|
+
otlpMetricsUrl: void 0
|
|
11550
|
+
};
|
|
11363
11551
|
}
|
|
11364
|
-
function
|
|
11365
|
-
return
|
|
11552
|
+
function shouldReplaceTextGenerationModelSelection(patch) {
|
|
11553
|
+
return Boolean(patch && (patch.instanceId !== void 0 || patch.model !== void 0));
|
|
11366
11554
|
}
|
|
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;
|
|
11555
|
+
function mergeModelSelectionOptionsById(input) {
|
|
11556
|
+
if (input.patch === void 0) return input.current ? [...input.current] : void 0;
|
|
11557
|
+
if (input.patch.length === 0) return;
|
|
11558
|
+
const merged = new Map((input.current ?? []).map((selection) => [selection.id, selection.value]));
|
|
11559
|
+
for (const selection of input.patch) merged.set(selection.id, selection.value);
|
|
11560
|
+
return [...merged.entries()].map(([id, value]) => ({
|
|
11561
|
+
id,
|
|
11562
|
+
value
|
|
11563
|
+
}));
|
|
11383
11564
|
}
|
|
11384
|
-
function
|
|
11385
|
-
|
|
11386
|
-
const
|
|
11387
|
-
const
|
|
11388
|
-
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
const
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
|
|
11565
|
+
function applyServerSettingsPatch(current, patch) {
|
|
11566
|
+
const selectionPatch = patch.textGenerationModelSelection;
|
|
11567
|
+
const { automaticGitFetchInterval, ...patchForMerge } = patch;
|
|
11568
|
+
const nextWithReplacements = {
|
|
11569
|
+
...deepMerge(current, patchForMerge),
|
|
11570
|
+
...patch.providerInstances !== void 0 ? { providerInstances: patch.providerInstances } : {},
|
|
11571
|
+
...patch.sourceControlWriterModelSelection !== void 0 ? { sourceControlWriterModelSelection: patch.sourceControlWriterModelSelection } : {},
|
|
11572
|
+
...automaticGitFetchInterval !== void 0 ? { automaticGitFetchInterval } : {}
|
|
11573
|
+
};
|
|
11574
|
+
if (!selectionPatch) return nextWithReplacements;
|
|
11575
|
+
const instanceId = selectionPatch.instanceId ?? current.textGenerationModelSelection.instanceId;
|
|
11576
|
+
const model = selectionPatch.model ?? current.textGenerationModelSelection.model;
|
|
11577
|
+
const options = shouldReplaceTextGenerationModelSelection(selectionPatch) ? selectionPatch.options : mergeModelSelectionOptionsById({
|
|
11578
|
+
current: current.textGenerationModelSelection.options,
|
|
11579
|
+
patch: selectionPatch.options
|
|
11580
|
+
});
|
|
11581
|
+
return {
|
|
11582
|
+
...nextWithReplacements,
|
|
11583
|
+
textGenerationModelSelection: createModelSelection(instanceId, model, options)
|
|
11584
|
+
};
|
|
11402
11585
|
}
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
return windowsPathExtensions.includes(extension.toUpperCase());
|
|
11586
|
+
//#endregion
|
|
11587
|
+
//#region src/bootstrap.ts
|
|
11588
|
+
var BootstrapFdStatError = class extends Schema$1.TaggedErrorClass()("BootstrapFdStatError", {
|
|
11589
|
+
fd: Schema$1.Number,
|
|
11590
|
+
cause: Schema$1.Defect()
|
|
11591
|
+
}) {
|
|
11592
|
+
get message() {
|
|
11593
|
+
return `Failed to stat bootstrap file descriptor ${this.fd}.`;
|
|
11412
11594
|
}
|
|
11413
|
-
|
|
11414
|
-
|
|
11415
|
-
|
|
11416
|
-
|
|
11417
|
-
|
|
11418
|
-
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
|
|
11422
|
-
|
|
11423
|
-
return yield* new CommandResolutionError({
|
|
11424
|
-
command,
|
|
11425
|
-
reason: "not-found"
|
|
11426
|
-
});
|
|
11595
|
+
};
|
|
11596
|
+
var BootstrapInputStreamOpenError = class extends Schema$1.TaggedErrorClass()("BootstrapInputStreamOpenError", {
|
|
11597
|
+
fd: Schema$1.Number,
|
|
11598
|
+
platform: Schema$1.String,
|
|
11599
|
+
fdPath: Schema$1.optional(Schema$1.String),
|
|
11600
|
+
cause: Schema$1.Defect()
|
|
11601
|
+
}) {
|
|
11602
|
+
get message() {
|
|
11603
|
+
const path = this.fdPath === void 0 ? "" : ` via '${this.fdPath}'`;
|
|
11604
|
+
return `Failed to open bootstrap input stream for file descriptor ${this.fd}${path} on '${this.platform}'.`;
|
|
11427
11605
|
}
|
|
11428
|
-
|
|
11429
|
-
|
|
11430
|
-
|
|
11431
|
-
|
|
11432
|
-
|
|
11433
|
-
|
|
11434
|
-
|
|
11435
|
-
const pathEntry = stripWrappingQuotes(entry.trim());
|
|
11436
|
-
if (pathEntry.length > 0) pathEntries.push(pathEntry);
|
|
11606
|
+
};
|
|
11607
|
+
var BootstrapEnvelopeReadError = class extends Schema$1.TaggedErrorClass()("BootstrapEnvelopeReadError", {
|
|
11608
|
+
fd: Schema$1.Number,
|
|
11609
|
+
cause: Schema$1.Defect()
|
|
11610
|
+
}) {
|
|
11611
|
+
get message() {
|
|
11612
|
+
return `Failed to read bootstrap envelope from file descriptor ${this.fd}.`;
|
|
11437
11613
|
}
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11614
|
+
};
|
|
11615
|
+
var BootstrapEnvelopeDecodeError = class extends Schema$1.TaggedErrorClass()("BootstrapEnvelopeDecodeError", {
|
|
11616
|
+
fd: Schema$1.Number,
|
|
11617
|
+
cause: Schema$1.Defect()
|
|
11618
|
+
}) {
|
|
11619
|
+
get message() {
|
|
11620
|
+
return `Failed to decode bootstrap envelope from file descriptor ${this.fd}.`;
|
|
11441
11621
|
}
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
|
|
11446
|
-
|
|
11447
|
-
|
|
11448
|
-
|
|
11449
|
-
|
|
11450
|
-
|
|
11451
|
-
|
|
11622
|
+
};
|
|
11623
|
+
Schema$1.Union([
|
|
11624
|
+
BootstrapFdStatError,
|
|
11625
|
+
BootstrapInputStreamOpenError,
|
|
11626
|
+
BootstrapEnvelopeReadError,
|
|
11627
|
+
BootstrapEnvelopeDecodeError
|
|
11628
|
+
]);
|
|
11629
|
+
const readBootstrapEnvelope = Effect.fn("readBootstrapEnvelope")(function* (schema, fd, options) {
|
|
11630
|
+
if (!(yield* isFdReady(fd))) return Option.none();
|
|
11631
|
+
const stream = yield* makeBootstrapInputStream(fd);
|
|
11632
|
+
const timeoutMs = options?.timeoutMs ?? 1e3;
|
|
11633
|
+
return yield* Effect.callback((resume) => {
|
|
11634
|
+
const input = NodeReadline.createInterface({
|
|
11635
|
+
input: stream,
|
|
11636
|
+
crlfDelay: Infinity
|
|
11637
|
+
});
|
|
11638
|
+
const cleanup = () => {
|
|
11639
|
+
stream.removeListener("error", handleError);
|
|
11640
|
+
input.removeListener("line", handleLine);
|
|
11641
|
+
input.removeListener("close", handleClose);
|
|
11642
|
+
input.close();
|
|
11643
|
+
stream.destroy();
|
|
11644
|
+
};
|
|
11645
|
+
const handleError = (error) => {
|
|
11646
|
+
if (isUnavailableBootstrapFdError(error)) {
|
|
11647
|
+
resume(Effect.succeedNone);
|
|
11648
|
+
return;
|
|
11649
|
+
}
|
|
11650
|
+
resume(Effect.fail(new BootstrapEnvelopeReadError({
|
|
11651
|
+
fd,
|
|
11652
|
+
cause: error
|
|
11653
|
+
})));
|
|
11654
|
+
};
|
|
11655
|
+
const handleLine = (line) => {
|
|
11656
|
+
const parsed = decodeJsonResult(schema)(line);
|
|
11657
|
+
if (Result.isSuccess(parsed)) resume(Effect.succeedSome(parsed.success));
|
|
11658
|
+
else resume(Effect.fail(new BootstrapEnvelopeDecodeError({
|
|
11659
|
+
fd,
|
|
11660
|
+
cause: parsed.failure
|
|
11661
|
+
})));
|
|
11662
|
+
};
|
|
11663
|
+
const handleClose = () => {
|
|
11664
|
+
resume(Effect.succeedNone);
|
|
11665
|
+
};
|
|
11666
|
+
stream.once("error", handleError);
|
|
11667
|
+
input.once("line", handleLine);
|
|
11668
|
+
input.once("close", handleClose);
|
|
11669
|
+
return Effect.sync(cleanup);
|
|
11670
|
+
}).pipe(Effect.timeoutOption(timeoutMs), Effect.map(Option.flatten));
|
|
11452
11671
|
});
|
|
11453
|
-
const
|
|
11672
|
+
const isUnavailableBootstrapFdError = Predicate.compose(Predicate.hasProperty("code"), (_) => _.code === "EBADF" || _.code === "ENOENT");
|
|
11673
|
+
const isFdReady = (fd) => Effect.try({
|
|
11674
|
+
try: () => NodeFS.fstatSync(fd),
|
|
11675
|
+
catch: (error) => new BootstrapFdStatError({
|
|
11676
|
+
fd,
|
|
11677
|
+
cause: error
|
|
11678
|
+
})
|
|
11679
|
+
}).pipe(Effect.as(true), Effect.catchTags({ BootstrapFdStatError: (error) => isUnavailableBootstrapFdError(error.cause) ? Effect.succeed(false) : Effect.fail(error) }));
|
|
11680
|
+
const makeBootstrapInputStream = (fd) => Effect.gen(function* () {
|
|
11454
11681
|
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
|
-
|
|
11682
|
+
const fdPath = resolveFdPath(fd, platform);
|
|
11683
|
+
return yield* Effect.try({
|
|
11684
|
+
try: () => {
|
|
11685
|
+
if (fdPath === void 0) return makeDirectBootstrapStream(fd);
|
|
11686
|
+
let streamFd;
|
|
11687
|
+
try {
|
|
11688
|
+
streamFd = NodeFS.openSync(fdPath, "r");
|
|
11689
|
+
return NodeFS.createReadStream("", {
|
|
11690
|
+
fd: streamFd,
|
|
11691
|
+
encoding: "utf8",
|
|
11692
|
+
autoClose: true
|
|
11693
|
+
});
|
|
11694
|
+
} catch (error) {
|
|
11695
|
+
if (isBootstrapFdPathDuplicationError(error)) {
|
|
11696
|
+
if (streamFd !== void 0) NodeFS.closeSync(streamFd);
|
|
11697
|
+
return makeDirectBootstrapStream(fd);
|
|
11698
|
+
}
|
|
11699
|
+
throw error;
|
|
11700
|
+
}
|
|
11701
|
+
},
|
|
11702
|
+
catch: (error) => new BootstrapInputStreamOpenError({
|
|
11703
|
+
fd,
|
|
11704
|
+
platform,
|
|
11705
|
+
...fdPath === void 0 ? {} : { fdPath },
|
|
11706
|
+
cause: error
|
|
11707
|
+
})
|
|
11708
|
+
});
|
|
11480
11709
|
});
|
|
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) {
|
|
11710
|
+
const makeDirectBootstrapStream = (fd) => {
|
|
11493
11711
|
try {
|
|
11494
|
-
return
|
|
11712
|
+
return NodeFS.createReadStream("", {
|
|
11713
|
+
fd,
|
|
11714
|
+
encoding: "utf8",
|
|
11715
|
+
autoClose: true
|
|
11716
|
+
});
|
|
11495
11717
|
} 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;
|
|
11718
|
+
const stream = new NodeNet.Socket({
|
|
11719
|
+
fd,
|
|
11720
|
+
readable: true,
|
|
11721
|
+
writable: false
|
|
11722
|
+
});
|
|
11723
|
+
stream.setEncoding("utf8");
|
|
11724
|
+
return stream;
|
|
11543
11725
|
}
|
|
11544
|
-
|
|
11545
|
-
|
|
11546
|
-
|
|
11726
|
+
};
|
|
11727
|
+
const isBootstrapFdPathDuplicationError = Predicate.compose(Predicate.hasProperty("code"), (_) => _.code === "ENXIO" || _.code === "EINVAL" || _.code === "EPERM" || _.code === "EACCES");
|
|
11728
|
+
function resolveFdPath(fd, platform) {
|
|
11729
|
+
if (platform === "linux") return `/proc/self/fd/${fd}`;
|
|
11730
|
+
if (platform === "win32") return;
|
|
11731
|
+
return `/dev/fd/${fd}`;
|
|
11547
11732
|
}
|
|
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
11733
|
//#endregion
|
|
11581
11734
|
//#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);
|
|
11735
|
+
const modeFlag = Flag.choice("mode", RuntimeMode$1.literals).pipe(Flag.withDescription("Runtime mode. `desktop` keeps loopback defaults unless overridden."), Flag.optional);
|
|
11583
11736
|
const portFlag = Flag.integer("port").pipe(Flag.withSchema(PortSchema), Flag.withDescription("Port for the HTTP/WebSocket server."), Flag.optional);
|
|
11584
11737
|
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
11738
|
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 +11755,7 @@ const EnvServerConfig = Config.all({
|
|
|
11602
11755
|
otlpMetricsUrl: Config.string("P4CODE_OTLP_METRICS_URL").pipe(Config.option, Config.map(Option.getOrUndefined)),
|
|
11603
11756
|
otlpExportIntervalMs: Config.int("P4CODE_OTLP_EXPORT_INTERVAL_MS").pipe(Config.withDefault(1e4)),
|
|
11604
11757
|
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)),
|
|
11758
|
+
mode: Config.schema(RuntimeMode$1, "P4CODE_MODE").pipe(Config.option, Config.map(Option.getOrUndefined)),
|
|
11606
11759
|
port: Config.port("P4CODE_PORT").pipe(Config.option, Config.map(Option.getOrUndefined)),
|
|
11607
11760
|
host: Config.string("P4CODE_HOST").pipe(Config.option, Config.map(Option.getOrUndefined)),
|
|
11608
11761
|
p4Home: Config.string("P4CODE_HOME").pipe(Config.option, Config.map(Option.getOrUndefined)),
|
|
@@ -13952,7 +14105,7 @@ const ProjectionThreadSession = Schema$1.Struct({
|
|
|
13952
14105
|
status: OrchestrationSessionStatus,
|
|
13953
14106
|
providerName: Schema$1.NullOr(Schema$1.String),
|
|
13954
14107
|
providerInstanceId: Schema$1.NullOr(ProviderInstanceId),
|
|
13955
|
-
runtimeMode: RuntimeMode
|
|
14108
|
+
runtimeMode: RuntimeMode,
|
|
13956
14109
|
activeTurnId: Schema$1.NullOr(TurnId),
|
|
13957
14110
|
lastError: Schema$1.NullOr(Schema$1.String),
|
|
13958
14111
|
updatedAt: IsoDateTime
|
|
@@ -14047,7 +14200,7 @@ const ProjectionThread = Schema$1.Struct({
|
|
|
14047
14200
|
projectId: ProjectId,
|
|
14048
14201
|
title: Schema$1.String,
|
|
14049
14202
|
modelSelection: ModelSelection,
|
|
14050
|
-
runtimeMode: RuntimeMode
|
|
14203
|
+
runtimeMode: RuntimeMode,
|
|
14051
14204
|
interactionMode: ProviderInteractionMode,
|
|
14052
14205
|
branch: Schema$1.NullOr(Schema$1.String),
|
|
14053
14206
|
worktreePath: Schema$1.NullOr(Schema$1.String),
|
|
@@ -15368,7 +15521,7 @@ function collectThreadAttachmentRelativePaths(threadId, messages) {
|
|
|
15368
15521
|
return relativePaths;
|
|
15369
15522
|
}
|
|
15370
15523
|
const runAttachmentSideEffects = Effect.fn("runAttachmentSideEffects")(function* (sideEffects) {
|
|
15371
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
15524
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
15372
15525
|
const fileSystem = yield* Effect.service(FileSystem.FileSystem);
|
|
15373
15526
|
const path = yield* Effect.service(Path.Path);
|
|
15374
15527
|
const attachmentsRootDir = serverConfig.attachmentsDir;
|
|
@@ -15430,7 +15583,7 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
|
|
|
15430
15583
|
const projectionPendingApprovalRepository = yield* ProjectionPendingApprovalRepository;
|
|
15431
15584
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
15432
15585
|
const path = yield* Path.Path;
|
|
15433
|
-
const serverConfig = yield* ServerConfig;
|
|
15586
|
+
const serverConfig = yield* ServerConfig$1;
|
|
15434
15587
|
const applyProjectsProjection = Effect.fn("applyProjectsProjection")(function* (event, _attachmentSideEffects) {
|
|
15435
15588
|
switch (event.type) {
|
|
15436
15589
|
case "project.created":
|
|
@@ -16120,9 +16273,9 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
|
|
|
16120
16273
|
})));
|
|
16121
16274
|
});
|
|
16122
16275
|
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))));
|
|
16276
|
+
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
16277
|
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)))),
|
|
16278
|
+
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
16279
|
projectEvent
|
|
16127
16280
|
};
|
|
16128
16281
|
});
|
|
@@ -18537,7 +18690,7 @@ function mergeWithDefaultKeybindings(custom) {
|
|
|
18537
18690
|
*/
|
|
18538
18691
|
var Keybindings = class extends Context.Service()("@p4code/cli/keybindings") {};
|
|
18539
18692
|
const make$56 = Effect.gen(function* () {
|
|
18540
|
-
const { keybindingsConfigPath } = yield* ServerConfig;
|
|
18693
|
+
const { keybindingsConfigPath } = yield* ServerConfig$1;
|
|
18541
18694
|
const fs = yield* FileSystem.FileSystem;
|
|
18542
18695
|
const path = yield* Path.Path;
|
|
18543
18696
|
const upsertSemaphore = yield* Semaphore.make(1);
|
|
@@ -19186,7 +19339,7 @@ function stripDefaultServerSettings(current, defaults) {
|
|
|
19186
19339
|
return Object.is(current, defaults) ? void 0 : current;
|
|
19187
19340
|
}
|
|
19188
19341
|
const make$53 = Effect.gen(function* () {
|
|
19189
|
-
const { settingsPath } = yield* ServerConfig;
|
|
19342
|
+
const { settingsPath } = yield* ServerConfig$1;
|
|
19190
19343
|
const fs = yield* FileSystem.FileSystem;
|
|
19191
19344
|
const pathService = yield* Path.Path;
|
|
19192
19345
|
const secretStore = yield* ServerSecretStore;
|
|
@@ -19517,7 +19670,7 @@ const getClaudeUserId = Effect.fn("TelemetryIdentity.getClaudeUserId")(function*
|
|
|
19517
19670
|
});
|
|
19518
19671
|
const upsertAnonymousId = Effect.gen(function* () {
|
|
19519
19672
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
19520
|
-
const { anonymousIdPath } = yield* ServerConfig;
|
|
19673
|
+
const { anonymousIdPath } = yield* ServerConfig$1;
|
|
19521
19674
|
const existing = yield* readIdentityFile(fileSystem, "anonymous", anonymousIdPath);
|
|
19522
19675
|
if (Option.isSome(existing)) return existing.value;
|
|
19523
19676
|
const anonymousId = yield* Crypto.Crypto.pipe(Effect.flatMap((crypto) => crypto.randomUUIDv4), Effect.mapError((cause) => new TelemetryAnonymousIdGenerationError({
|
|
@@ -19586,7 +19739,7 @@ var AnalyticsService = class AnalyticsService extends Context.Service()("@p4code
|
|
|
19586
19739
|
const make$52 = Effect.gen(function* () {
|
|
19587
19740
|
const telemetryConfig = yield* TelemetryEnvConfig;
|
|
19588
19741
|
const httpClient = yield* HttpClient$1.HttpClient;
|
|
19589
|
-
const serverConfig = yield* ServerConfig;
|
|
19742
|
+
const serverConfig = yield* ServerConfig$1;
|
|
19590
19743
|
const identifier = yield* getTelemetryIdentifier;
|
|
19591
19744
|
const bufferRef = yield* Ref.make([]);
|
|
19592
19745
|
const clientType = serverConfig.mode === "desktop" ? "desktop-app" : "cli-web-client";
|
|
@@ -20202,7 +20355,7 @@ const resolveServerSelfUpdateCapability = Effect.fn("cloud.server_self_update.re
|
|
|
20202
20355
|
});
|
|
20203
20356
|
var ServerSelfUpdate = class extends Context.Service()("@p4code/cli/service/selfUpdate/ServerSelfUpdate") {};
|
|
20204
20357
|
const make$50 = Effect.fn("cloud.server_self_update.make")(function* (options) {
|
|
20205
|
-
const serverConfig = yield* ServerConfig;
|
|
20358
|
+
const serverConfig = yield* ServerConfig$1;
|
|
20206
20359
|
const fs = yield* FileSystem.FileSystem;
|
|
20207
20360
|
const path = yield* Path.Path;
|
|
20208
20361
|
const runner = yield* ProcessRunner;
|
|
@@ -20484,7 +20637,7 @@ function platformArch(architecture) {
|
|
|
20484
20637
|
const make$49 = Effect.gen(function* () {
|
|
20485
20638
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
20486
20639
|
const path = yield* Path.Path;
|
|
20487
|
-
const serverConfig = yield* ServerConfig;
|
|
20640
|
+
const serverConfig = yield* ServerConfig$1;
|
|
20488
20641
|
const crypto = yield* Crypto.Crypto;
|
|
20489
20642
|
const hostPlatform = yield* HostProcessPlatform;
|
|
20490
20643
|
const hostArchitecture = yield* HostProcessArchitecture;
|
|
@@ -21473,7 +21626,7 @@ const formatHeadlessServeOutput = (accessInfo) => [
|
|
|
21473
21626
|
""
|
|
21474
21627
|
].join("\n");
|
|
21475
21628
|
const issueHeadlessServeAccessInfo = Effect.fn("issueHeadlessServeAccessInfo")(function* () {
|
|
21476
|
-
const serverConfig = yield* ServerConfig;
|
|
21629
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21477
21630
|
const httpServer = yield* HttpServer.HttpServer;
|
|
21478
21631
|
const serverAuth = yield* EnvironmentAuth;
|
|
21479
21632
|
const connectionString = resolveHeadlessConnectionString(serverConfig.host, resolveListeningPort(httpServer.address, serverConfig.port));
|
|
@@ -21487,7 +21640,7 @@ const issueHeadlessServeAccessInfo = Effect.fn("issueHeadlessServeAccessInfo")(f
|
|
|
21487
21640
|
//#endregion
|
|
21488
21641
|
//#region src/serverRuntimeStartup.ts
|
|
21489
21642
|
var ServerRuntimeStartupError = class extends Schema$1.TaggedErrorClass()("ServerRuntimeStartupError", {
|
|
21490
|
-
mode: RuntimeMode,
|
|
21643
|
+
mode: RuntimeMode$1,
|
|
21491
21644
|
host: Schema$1.NullOr(Schema$1.String),
|
|
21492
21645
|
port: Schema$1.Number,
|
|
21493
21646
|
cause: Schema$1.Defect()
|
|
@@ -21540,7 +21693,7 @@ const getAutoBootstrapDefaultModelSelection = () => ({
|
|
|
21540
21693
|
model: DEFAULT_MODEL
|
|
21541
21694
|
});
|
|
21542
21695
|
const resolveWelcomeBase = Effect.gen(function* () {
|
|
21543
|
-
const serverConfig = yield* ServerConfig;
|
|
21696
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21544
21697
|
const segments = serverConfig.cwd.split(/[/\\]/).filter(Boolean);
|
|
21545
21698
|
const projectName = segments[segments.length - 1] ?? "project";
|
|
21546
21699
|
return {
|
|
@@ -21550,7 +21703,7 @@ const resolveWelcomeBase = Effect.gen(function* () {
|
|
|
21550
21703
|
});
|
|
21551
21704
|
const resolveAutoBootstrapWelcomeTargets = Effect.gen(function* () {
|
|
21552
21705
|
const randomUUID = (yield* Crypto.Crypto).randomUUIDv4;
|
|
21553
|
-
const serverConfig = yield* ServerConfig;
|
|
21706
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21554
21707
|
const projectionReadModelQuery = yield* ProjectionSnapshotQuery;
|
|
21555
21708
|
const orchestrationEngine = yield* OrchestrationEngineService;
|
|
21556
21709
|
const path = yield* Path.Path;
|
|
@@ -21608,7 +21761,7 @@ const resolveAutoBootstrapWelcomeTargets = Effect.gen(function* () {
|
|
|
21608
21761
|
};
|
|
21609
21762
|
});
|
|
21610
21763
|
const resolveStartupBrowserTarget = Effect.gen(function* () {
|
|
21611
|
-
const serverConfig = yield* ServerConfig;
|
|
21764
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21612
21765
|
const serverAuth = yield* EnvironmentAuth;
|
|
21613
21766
|
const localUrl = `http://localhost:${serverConfig.port}`;
|
|
21614
21767
|
const bindUrl = serverConfig.host && !isWildcardHost(serverConfig.host) ? `http://${formatHostForUrl(serverConfig.host)}:${serverConfig.port}` : localUrl;
|
|
@@ -21616,12 +21769,12 @@ const resolveStartupBrowserTarget = Effect.gen(function* () {
|
|
|
21616
21769
|
return yield* Effect.succeed(serverConfig.mode === "desktop" ? baseTarget : void 0).pipe(Effect.flatMap((target) => target ? Effect.succeed(target) : serverAuth.issueStartupPairingUrl(baseTarget)));
|
|
21617
21770
|
});
|
|
21618
21771
|
const maybeOpenBrowser = (target) => Effect.gen(function* () {
|
|
21619
|
-
if ((yield* ServerConfig).noBrowser) return;
|
|
21772
|
+
if ((yield* ServerConfig$1).noBrowser) return;
|
|
21620
21773
|
yield* (yield* ExternalLauncher).launchBrowser(target).pipe(Effect.catch(() => Effect.logInfo("browser auto-open unavailable", { hint: `Open ${target} in your browser.` })));
|
|
21621
21774
|
});
|
|
21622
21775
|
const runStartupPhase = (phase, effect) => effect.pipe(Effect.annotateSpans({ "startup.phase": phase }), Effect.withSpan(`server.startup.${phase}`));
|
|
21623
21776
|
const make$48 = Effect.gen(function* () {
|
|
21624
|
-
const serverConfig = yield* ServerConfig;
|
|
21777
|
+
const serverConfig = yield* ServerConfig$1;
|
|
21625
21778
|
const keybindings = yield* Keybindings;
|
|
21626
21779
|
const orchestrationReactor = yield* OrchestrationReactor;
|
|
21627
21780
|
const providerSessionReaper = yield* ProviderSessionReaper;
|
|
@@ -23057,7 +23210,7 @@ const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (input) {
|
|
|
23057
23210
|
}
|
|
23058
23211
|
case "attachment": {
|
|
23059
23212
|
const attachmentPath = resolveAttachmentPathById({
|
|
23060
|
-
attachmentsDir: (yield* ServerConfig).attachmentsDir,
|
|
23213
|
+
attachmentsDir: (yield* ServerConfig$1).attachmentsDir,
|
|
23061
23214
|
attachmentId: input.resource.attachmentId
|
|
23062
23215
|
});
|
|
23063
23216
|
if (!attachmentPath) return yield* new AssetAttachmentNotFoundError({ resource: input.resource });
|
|
@@ -23122,7 +23275,7 @@ const resolveAsset = Effect.fn("AssetAccess.resolveAsset")(function* (token, rel
|
|
|
23122
23275
|
if (!claims || claims.expiresAt <= (yield* Clock.currentTimeMillis)) return null;
|
|
23123
23276
|
if (claims.kind === "attachment") {
|
|
23124
23277
|
const attachmentPath = resolveAttachmentPathById({
|
|
23125
|
-
attachmentsDir: (yield* ServerConfig).attachmentsDir,
|
|
23278
|
+
attachmentsDir: (yield* ServerConfig$1).attachmentsDir,
|
|
23126
23279
|
attachmentId: claims.attachmentId
|
|
23127
23280
|
});
|
|
23128
23281
|
if (!attachmentPath) return null;
|
|
@@ -23410,7 +23563,7 @@ const compressHttpResponse = Effect.fnUntraced(function* (response, acceptEncodi
|
|
|
23410
23563
|
});
|
|
23411
23564
|
const httpCompressionLayer = HttpRouter.middleware((httpEffect) => Effect.flatMap(Effect.all([httpEffect, HttpServerRequest.HttpServerRequest]), ([response, request]) => compressHttpResponse(response, request.headers["accept-encoding"])), { global: true });
|
|
23412
23565
|
const browserApiCorsLayer = Layer.unwrap(Effect.gen(function* () {
|
|
23413
|
-
const config = yield* ServerConfig;
|
|
23566
|
+
const config = yield* ServerConfig$1;
|
|
23414
23567
|
const devOrigin = config.devUrl?.origin;
|
|
23415
23568
|
return HttpRouter.cors({
|
|
23416
23569
|
...devOrigin ? {
|
|
@@ -23452,7 +23605,7 @@ var DecodeOtlpTraceRecordsError = class extends Data.TaggedError("DecodeOtlpTrac
|
|
|
23452
23605
|
const otlpTracesProxyRouteLayer = HttpRouter.add("POST", OTLP_TRACES_PROXY_PATH, Effect.gen(function* () {
|
|
23453
23606
|
yield* authenticateRawRouteWithScope(AuthOrchestrationOperateScope);
|
|
23454
23607
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
23455
|
-
const otlpTracesUrl = (yield* ServerConfig).otlpTracesUrl;
|
|
23608
|
+
const otlpTracesUrl = (yield* ServerConfig$1).otlpTracesUrl;
|
|
23456
23609
|
const browserTraceCollector = yield* BrowserTraceCollector;
|
|
23457
23610
|
const httpClient = yield* HttpClient.HttpClient;
|
|
23458
23611
|
const bodyJson = cast(yield* request.json);
|
|
@@ -23497,7 +23650,7 @@ const staticAndDevRouteLayer = HttpRouter.add("GET", "*", Effect.gen(function* (
|
|
|
23497
23650
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
23498
23651
|
const url = HttpServerRequest.toURL(request);
|
|
23499
23652
|
if (Option.isNone(url)) return HttpServerResponse.text("Bad Request", { status: 400 });
|
|
23500
|
-
const config = yield* ServerConfig;
|
|
23653
|
+
const config = yield* ServerConfig$1;
|
|
23501
23654
|
if (config.devUrl && isDevProxiedPath(url.value.pathname)) return HttpServerResponse.text("Not Found", { status: 404 });
|
|
23502
23655
|
if (config.devUrl && isLoopbackHostname(url.value.hostname)) return HttpServerResponse.redirect(resolveDevRedirectUrl(config.devUrl, url.value), { status: 302 });
|
|
23503
23656
|
const staticDir = config.staticDir ?? (config.devUrl ? yield* resolveStaticDir() : void 0);
|
|
@@ -24036,7 +24189,7 @@ const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* () {
|
|
|
24036
24189
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
24037
24190
|
const path = yield* Path.Path;
|
|
24038
24191
|
const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
24039
|
-
const { worktreesDir } = yield* ServerConfig;
|
|
24192
|
+
const { worktreesDir } = yield* ServerConfig$1;
|
|
24040
24193
|
const crypto = yield* Crypto.Crypto;
|
|
24041
24194
|
const executeRaw = Effect.fnUntraced(function* (input) {
|
|
24042
24195
|
const commandInput = {
|
|
@@ -26464,7 +26617,7 @@ const normalizeDispatchCommand = (command) => Effect.gen(function* () {
|
|
|
26464
26617
|
const canonicalCommand = canonicalizeClientCommandTimestamps(command, receivedAt);
|
|
26465
26618
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
26466
26619
|
const path = yield* Path.Path;
|
|
26467
|
-
const serverConfig = yield* ServerConfig;
|
|
26620
|
+
const serverConfig = yield* ServerConfig$1;
|
|
26468
26621
|
const workspacePaths = yield* WorkspacePaths;
|
|
26469
26622
|
const normalizeProjectWorkspaceRoot = (workspaceRoot) => workspacePaths.normalizeWorkspaceRoot(workspaceRoot).pipe(Effect.mapError((cause) => new OrchestrationDispatchCommandError({ message: cause.message })));
|
|
26470
26623
|
const normalizeProjectWorkspaceRootForCreate = (workspaceRoot, createIfMissing) => workspacePaths.normalizeWorkspaceRoot(workspaceRoot, { createIfMissing: createIfMissing === true }).pipe(Effect.mapError((cause) => new OrchestrationDispatchCommandError({ message: cause.message })));
|
|
@@ -26612,79 +26765,6 @@ const makeProviderMaintenanceCommandCoordinator = Effect.fn("makeProviderMainten
|
|
|
26612
26765
|
return { withCommandLock };
|
|
26613
26766
|
});
|
|
26614
26767
|
//#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
26768
|
//#region src/provider/providerMaintenance.ts
|
|
26689
26769
|
const LATEST_VERSION_CACHE_TTL_MS = 3600 * 1e3;
|
|
26690
26770
|
const LATEST_VERSION_TIMEOUT_MS = 4e3;
|
|
@@ -28276,7 +28356,7 @@ function normalizedRuntimeEnv(env) {
|
|
|
28276
28356
|
return Object.fromEntries(entries.toSorted(([left], [right]) => left.localeCompare(right)));
|
|
28277
28357
|
}
|
|
28278
28358
|
const make$35 = Effect.fn("TerminalManager.make")(function* () {
|
|
28279
|
-
const { terminalLogsDir } = yield* ServerConfig;
|
|
28359
|
+
const { terminalLogsDir } = yield* ServerConfig$1;
|
|
28280
28360
|
const ptyAdapter = yield* PtyAdapter;
|
|
28281
28361
|
const portDiscovery = yield* PortDiscovery;
|
|
28282
28362
|
return yield* makeWithOptions$1({
|
|
@@ -33227,7 +33307,7 @@ function bindProviderContext(provider, context) {
|
|
|
33227
33307
|
});
|
|
33228
33308
|
}
|
|
33229
33309
|
const makeWithProviders = Effect.fn("makeSourceControlProviderRegistryWithProviders")(function* (registrations) {
|
|
33230
|
-
const config = yield* ServerConfig;
|
|
33310
|
+
const config = yield* ServerConfig$1;
|
|
33231
33311
|
const process = yield* VcsProcess;
|
|
33232
33312
|
const vcsRegistry = yield* VcsDriverRegistry;
|
|
33233
33313
|
const providers = new Map(registrations.map((registration) => [registration.kind, registration.provider]));
|
|
@@ -35038,7 +35118,7 @@ const layer$10 = Layer.effect(VcsProvisioningService, make$15);
|
|
|
35038
35118
|
//#region src/review/ReviewService.ts
|
|
35039
35119
|
var ReviewService = class extends Context.Service()("@p4code/cli/review/ReviewService") {};
|
|
35040
35120
|
const make$14 = Effect.gen(function* () {
|
|
35041
|
-
const config = yield* ServerConfig;
|
|
35121
|
+
const config = yield* ServerConfig$1;
|
|
35042
35122
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
35043
35123
|
const path = yield* Path.Path;
|
|
35044
35124
|
const vcsRegistry = yield* VcsDriverRegistry;
|
|
@@ -35949,7 +36029,7 @@ const VCS_PROBES = [{
|
|
|
35949
36029
|
}];
|
|
35950
36030
|
var SourceControlDiscovery = class extends Context.Service()("@p4code/cli/sourceControl/SourceControlDiscovery") {};
|
|
35951
36031
|
const make$10 = Effect.gen(function* () {
|
|
35952
|
-
const config = yield* ServerConfig;
|
|
36032
|
+
const config = yield* ServerConfig$1;
|
|
35953
36033
|
const process = yield* VcsProcess;
|
|
35954
36034
|
const sourceControlProviders = yield* SourceControlProviderRegistry;
|
|
35955
36035
|
const probe = (input) => {
|
|
@@ -36031,7 +36111,7 @@ function expandHomePath$1(input, path) {
|
|
|
36031
36111
|
return input;
|
|
36032
36112
|
}
|
|
36033
36113
|
const make$9 = Effect.gen(function* () {
|
|
36034
|
-
const config = yield* ServerConfig;
|
|
36114
|
+
const config = yield* ServerConfig$1;
|
|
36035
36115
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
36036
36116
|
const git = yield* GitVcsDriver;
|
|
36037
36117
|
const path = yield* Path.Path;
|
|
@@ -36390,7 +36470,7 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
|
|
|
36390
36470
|
const providerRegistry = yield* ProviderRegistry;
|
|
36391
36471
|
const providerMaintenanceRunner = yield* ProviderMaintenanceRunner;
|
|
36392
36472
|
const serverSelfUpdate = yield* ServerSelfUpdate;
|
|
36393
|
-
const config = yield* ServerConfig;
|
|
36473
|
+
const config = yield* ServerConfig$1;
|
|
36394
36474
|
const lifecycleEvents = yield* ServerLifecycleEvents;
|
|
36395
36475
|
const serverSettings = yield* ServerSettingsService;
|
|
36396
36476
|
const startup = yield* ServerRuntimeStartup;
|
|
@@ -37034,7 +37114,7 @@ const ProviderSessionRuntime = Schema$1.Struct({
|
|
|
37034
37114
|
*/
|
|
37035
37115
|
providerInstanceId: Schema$1.NullOr(ProviderInstanceId),
|
|
37036
37116
|
adapterKey: Schema$1.String,
|
|
37037
|
-
runtimeMode: RuntimeMode
|
|
37117
|
+
runtimeMode: RuntimeMode,
|
|
37038
37118
|
status: ProviderSessionRuntimeStatus,
|
|
37039
37119
|
lastSeenAt: IsoDateTime,
|
|
37040
37120
|
resumeCursor: Schema$1.NullOr(Schema$1.Unknown),
|
|
@@ -37667,7 +37747,7 @@ var ProviderEventLoggers = class extends Context.Service()("@p4code/cli/provider
|
|
|
37667
37747
|
* is `undefined` and writes from that stream become no-ops downstream.
|
|
37668
37748
|
*/
|
|
37669
37749
|
const ProviderEventLoggersLive = Layer.effect(ProviderEventLoggers, Effect.gen(function* () {
|
|
37670
|
-
const { providerEventLogPath } = yield* ServerConfig;
|
|
37750
|
+
const { providerEventLogPath } = yield* ServerConfig$1;
|
|
37671
37751
|
return {
|
|
37672
37752
|
native: yield* makeEventNdjsonLogger(providerEventLogPath, { stream: "native" }),
|
|
37673
37753
|
canonical: yield* makeEventNdjsonLogger(providerEventLogPath, { stream: "canonical" })
|
|
@@ -41136,7 +41216,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
|
|
|
41136
41216
|
const boundInstanceId = options?.instanceId ?? ProviderInstanceId.make("claudeAgent");
|
|
41137
41217
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
41138
41218
|
const path = yield* Path.Path;
|
|
41139
|
-
const serverConfig = yield* ServerConfig;
|
|
41219
|
+
const serverConfig = yield* ServerConfig$1;
|
|
41140
41220
|
const crypto = yield* Crypto.Crypto;
|
|
41141
41221
|
const claudeEnvironment = yield* makeClaudeEnvironment(claudeSettings, options?.environment).pipe(Effect.provideService(Path.Path, path));
|
|
41142
41222
|
const claudeSdkExecutablePath = yield* resolveClaudeSdkExecutablePath(claudeSettings.binaryPath, claudeEnvironment);
|
|
@@ -43019,7 +43099,7 @@ const ClaudeDriver = {
|
|
|
43019
43099
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
43020
43100
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
43021
43101
|
const path = yield* Path.Path;
|
|
43022
|
-
const { cwd } = yield* ServerConfig;
|
|
43102
|
+
const { cwd } = yield* ServerConfig$1;
|
|
43023
43103
|
const httpClient = yield* HttpClient.HttpClient;
|
|
43024
43104
|
const serverSettings = yield* ServerSettingsService;
|
|
43025
43105
|
const eventLoggers = yield* ProviderEventLoggers;
|
|
@@ -43130,7 +43210,7 @@ const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(function* (
|
|
|
43130
43210
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
43131
43211
|
const path = yield* Path.Path;
|
|
43132
43212
|
const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
43133
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
43213
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
43134
43214
|
const resolvedEnvironment = environment ?? process.env;
|
|
43135
43215
|
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
43216
|
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 +63528,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (codexConfig, o
|
|
|
63448
63528
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
63449
63529
|
const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
63450
63530
|
const crypto = yield* Crypto.Crypto;
|
|
63451
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
63531
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
63452
63532
|
const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== void 0 ? yield* makeEventNdjsonLogger(options.nativeEventLogPath, { stream: "native" }) : void 0);
|
|
63453
63533
|
const managedNativeEventLogger = options?.nativeEventLogger === void 0 ? nativeEventLogger : void 0;
|
|
63454
63534
|
const runtimeEventQueue = yield* Queue.unbounded();
|
|
@@ -69941,7 +70021,7 @@ function makeCursorAdapter(cursorSettings, options) {
|
|
|
69941
70021
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
69942
70022
|
const path = yield* Path.Path;
|
|
69943
70023
|
const childProcessSpawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
|
|
69944
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
70024
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
69945
70025
|
const crypto = yield* Crypto.Crypto;
|
|
69946
70026
|
const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== void 0 ? yield* makeEventNdjsonLogger(options.nativeEventLogPath, { stream: "native" }) : void 0);
|
|
69947
70027
|
const managedNativeEventLogger = options?.nativeEventLogger === void 0 ? nativeEventLogger : void 0;
|
|
@@ -71060,7 +71140,7 @@ function makeGrokAdapter(grokSettings, options) {
|
|
|
71060
71140
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
71061
71141
|
const path = yield* Path.Path;
|
|
71062
71142
|
const childProcessSpawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
|
|
71063
|
-
const serverConfig = yield* Effect.service(ServerConfig);
|
|
71143
|
+
const serverConfig = yield* Effect.service(ServerConfig$1);
|
|
71064
71144
|
const crypto = yield* Crypto.Crypto;
|
|
71065
71145
|
const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== void 0 ? yield* makeEventNdjsonLogger(options.nativeEventLogPath, { stream: "native" }) : void 0);
|
|
71066
71146
|
const managedNativeEventLogger = options?.nativeEventLogger === void 0 ? nativeEventLogger : void 0;
|
|
@@ -72234,7 +72314,7 @@ function getOpenCodeTextResponse(parts) {
|
|
|
72234
72314
|
return (parts ?? []).filter(isOpenCodeTextPart).map((part) => part.text).join("").trim();
|
|
72235
72315
|
}
|
|
72236
72316
|
const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration")(function* (openCodeSettings, environment) {
|
|
72237
|
-
const serverConfig = yield* ServerConfig;
|
|
72317
|
+
const serverConfig = yield* ServerConfig$1;
|
|
72238
72318
|
const openCodeRuntime = yield* OpenCodeRuntime;
|
|
72239
72319
|
const resolvedEnvironment = environment ?? process.env;
|
|
72240
72320
|
const idleFiberScope = yield* Effect.acquireRelease(Scope.make(), (scope) => Scope.close(scope, Exit.void));
|
|
@@ -72765,7 +72845,7 @@ const stopOpenCodeContext = Effect.fn("stopOpenCodeContext")(function* (context)
|
|
|
72765
72845
|
function makeOpenCodeAdapter(openCodeSettings, options) {
|
|
72766
72846
|
return Effect.gen(function* () {
|
|
72767
72847
|
const boundInstanceId = options?.instanceId ?? ProviderInstanceId.make("opencode");
|
|
72768
|
-
const serverConfig = yield* ServerConfig;
|
|
72848
|
+
const serverConfig = yield* ServerConfig$1;
|
|
72769
72849
|
const openCodeRuntime = yield* OpenCodeRuntime;
|
|
72770
72850
|
const crypto = yield* Crypto.Crypto;
|
|
72771
72851
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
@@ -73836,7 +73916,7 @@ const BUILT_IN_DRIVERS = [
|
|
|
73836
73916
|
defaultConfig: () => decodeOpenCodeSettings({}),
|
|
73837
73917
|
create: ({ instanceId, displayName, accentColor, environment, enabled, config }) => Effect.gen(function* () {
|
|
73838
73918
|
const openCodeRuntime = yield* OpenCodeRuntime;
|
|
73839
|
-
const serverConfig = yield* ServerConfig;
|
|
73919
|
+
const serverConfig = yield* ServerConfig$1;
|
|
73840
73920
|
const httpClient = yield* HttpClient.HttpClient;
|
|
73841
73921
|
const serverSettings = yield* ServerSettingsService;
|
|
73842
73922
|
const eventLoggers = yield* ProviderEventLoggers;
|
|
@@ -77547,7 +77627,7 @@ const buildSnapshotSource = (instance) => ({
|
|
|
77547
77627
|
});
|
|
77548
77628
|
const ProviderRegistryLive = Layer.effect(ProviderRegistry, Effect.gen(function* () {
|
|
77549
77629
|
const instanceRegistry = yield* ProviderInstanceRegistry;
|
|
77550
|
-
const config = yield* ServerConfig;
|
|
77630
|
+
const config = yield* ServerConfig$1;
|
|
77551
77631
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
77552
77632
|
const path = yield* Path.Path;
|
|
77553
77633
|
const changesPubSub = yield* Effect.acquireRelease(PubSub.unbounded(), PubSub.shutdown);
|
|
@@ -77774,7 +77854,7 @@ const ProviderRegistryLive = Layer.effect(ProviderRegistry, Effect.gen(function*
|
|
|
77774
77854
|
//#endregion
|
|
77775
77855
|
//#region src/serverLogger.ts
|
|
77776
77856
|
const ServerLoggerLive = Effect.gen(function* () {
|
|
77777
|
-
const config = yield* ServerConfig;
|
|
77857
|
+
const config = yield* ServerConfig$1;
|
|
77778
77858
|
const minimumLogLevelLayer = Layer.succeed(References.MinimumLogLevel, config.logLevel);
|
|
77779
77859
|
const loggerLayer = Logger.layer([Logger.consolePretty(), Logger.tracerLogger], { mergeWithExisting: false });
|
|
77780
77860
|
return Layer.mergeAll(loggerLayer, minimumLogLevelLayer);
|
|
@@ -77783,7 +77863,7 @@ const ServerLoggerLive = Effect.gen(function* () {
|
|
|
77783
77863
|
//#region src/observability/Layers/Observability.ts
|
|
77784
77864
|
const otlpSerializationLayer = OtlpSerialization.layerJson;
|
|
77785
77865
|
const ObservabilityLive = Layer.unwrap(Effect.gen(function* () {
|
|
77786
|
-
const config = yield* ServerConfig;
|
|
77866
|
+
const config = yield* ServerConfig$1;
|
|
77787
77867
|
const traceReferencesLayer = Layer.mergeAll(Layer.succeed(Tracer.MinimumTraceLevel, config.traceMinLevel), Layer.succeed(References.TracerTimingEnabled, config.traceTimingEnabled));
|
|
77788
77868
|
const tracerLayer = Layer.unwrap(Effect.gen(function* () {
|
|
77789
77869
|
const sink = yield* makeTraceSink({
|
|
@@ -78057,11 +78137,11 @@ const disableTailscaleServe = (input = {}) => Effect.gen(function* () {
|
|
|
78057
78137
|
//#region src/server.ts
|
|
78058
78138
|
const HTTP_PREEMPTIVE_SHUTDOWN_GRACE_MS = 0;
|
|
78059
78139
|
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-
|
|
78140
|
+
if (typeof Bun !== "undefined") return (yield* Effect.promise(() => import("./BunPtyAdapter-CLDq7yr1.mjs"))).layer;
|
|
78141
|
+
else return (yield* Effect.promise(() => import("./NodePtyAdapter-BQAnH2v0.mjs"))).layer;
|
|
78062
78142
|
}));
|
|
78063
78143
|
const HttpServerLive = Layer.unwrap(Effect.gen(function* () {
|
|
78064
|
-
const config = yield* ServerConfig;
|
|
78144
|
+
const config = yield* ServerConfig$1;
|
|
78065
78145
|
if (typeof Bun !== "undefined") return (yield* Effect.promise(() => import("@effect/platform-bun/BunHttpServer"))).layer({
|
|
78066
78146
|
port: config.port,
|
|
78067
78147
|
hostname: config.host ?? "127.0.0.1",
|
|
@@ -78112,7 +78192,7 @@ const RuntimeDependenciesLive = ReactorLayerLive.pipe(Layer.provideMerge(Checkpo
|
|
|
78112
78192
|
const RuntimeServicesLive = layer$43.pipe(Layer.provideMerge(RuntimeDependenciesLive));
|
|
78113
78193
|
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
78194
|
const makeServerLayer = Layer.unwrap(Effect.gen(function* () {
|
|
78115
|
-
const config = yield* ServerConfig;
|
|
78195
|
+
const config = yield* ServerConfig$1;
|
|
78116
78196
|
yield* fixPath();
|
|
78117
78197
|
const httpListeningLayer = Layer.effectDiscard(Effect.gen(function* () {
|
|
78118
78198
|
yield* HttpServer.HttpServer;
|
|
@@ -78160,7 +78240,7 @@ const runServer = Layer.launch(makeServerLayer);
|
|
|
78160
78240
|
//#region src/cli/server.ts
|
|
78161
78241
|
const runServerCommand = (flags, options) => Effect.gen(function* () {
|
|
78162
78242
|
const config = yield* resolveServerConfig(flags, yield* GlobalFlag.LogLevel, options);
|
|
78163
|
-
return yield* runServer.pipe(Effect.provideService(ServerConfig, config));
|
|
78243
|
+
return yield* runServer.pipe(Effect.provideService(ServerConfig$1, config));
|
|
78164
78244
|
});
|
|
78165
78245
|
const startCommand = Command.make("start", { ...sharedServerCommandFlags }).pipe(Command.withDescription("Run the P4Code server."), Command.withHandler((flags) => runServerCommand(flags)));
|
|
78166
78246
|
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 +78248,104 @@ const serveCommand = Command.make("serve", { ...sharedServerCommandFlags }).pipe
|
|
|
78168
78248
|
forceAutoBootstrapProjectFromCwd: false
|
|
78169
78249
|
})));
|
|
78170
78250
|
//#endregion
|
|
78251
|
+
//#region src/cli/completions.ts
|
|
78252
|
+
/**
|
|
78253
|
+
* Installs the zsh completion script for the `p4` command.
|
|
78254
|
+
*
|
|
78255
|
+
* zsh ships `_perforce` with `#compdef p4 p4d`, so out of the box tabbing
|
|
78256
|
+
* through our subcommands prints "unhandled perforce command: …" from its
|
|
78257
|
+
* fallback message. `compinit` resolves duplicate `#compdef` claims by fpath
|
|
78258
|
+
* order — first match wins — and `_perforce` lives in the *last* fpath entry
|
|
78259
|
+
* (`/usr/share/zsh/<ver>/functions`). Writing our own `_p4` into any earlier
|
|
78260
|
+
* directory therefore replaces it outright, with no shell-config edit.
|
|
78261
|
+
*/
|
|
78262
|
+
const COMPLETION_FILE = "_p4";
|
|
78263
|
+
const GENERATE_TIMEOUT_MS = 1e4;
|
|
78264
|
+
/**
|
|
78265
|
+
* Directories ahead of `/usr/share/zsh/*` in a default fpath, most specific
|
|
78266
|
+
* first. `~/.zfunc` is the fallback and is the only one needing an fpath line.
|
|
78267
|
+
*/
|
|
78268
|
+
function candidateDirectories(input) {
|
|
78269
|
+
return [
|
|
78270
|
+
{
|
|
78271
|
+
dir: input.join(input.homeDir, ".oh-my-zsh", "custom", "completions"),
|
|
78272
|
+
requiresFpathEntry: false
|
|
78273
|
+
},
|
|
78274
|
+
{
|
|
78275
|
+
dir: "/opt/homebrew/share/zsh/site-functions",
|
|
78276
|
+
requiresFpathEntry: false
|
|
78277
|
+
},
|
|
78278
|
+
{
|
|
78279
|
+
dir: "/usr/local/share/zsh/site-functions",
|
|
78280
|
+
requiresFpathEntry: false
|
|
78281
|
+
},
|
|
78282
|
+
{
|
|
78283
|
+
dir: input.join(input.homeDir, ".zfunc"),
|
|
78284
|
+
requiresFpathEntry: true
|
|
78285
|
+
}
|
|
78286
|
+
];
|
|
78287
|
+
}
|
|
78288
|
+
/**
|
|
78289
|
+
* Asks the running CLI for its own completion script rather than rendering one
|
|
78290
|
+
* here, so the output cannot drift from what `--completions` produces.
|
|
78291
|
+
*/
|
|
78292
|
+
const generateZshCompletionScript = Effect.fn("cli.completions.generate")(function* () {
|
|
78293
|
+
const runner = yield* ProcessRunner;
|
|
78294
|
+
const execPath = yield* HostProcessExecutablePath;
|
|
78295
|
+
const entryPath = (yield* HostProcessArguments)[1] ?? "";
|
|
78296
|
+
if (entryPath === "") return null;
|
|
78297
|
+
const result = yield* runner.run({
|
|
78298
|
+
command: execPath,
|
|
78299
|
+
args: [
|
|
78300
|
+
entryPath,
|
|
78301
|
+
"--completions",
|
|
78302
|
+
"zsh"
|
|
78303
|
+
],
|
|
78304
|
+
timeout: GENERATE_TIMEOUT_MS
|
|
78305
|
+
});
|
|
78306
|
+
if (result.code !== 0) return null;
|
|
78307
|
+
const script = result.stdout.trim();
|
|
78308
|
+
return script.length === 0 ? null : `${script}\n`;
|
|
78309
|
+
});
|
|
78310
|
+
/**
|
|
78311
|
+
* Best-effort: returns null when completions are not applicable (Windows, no
|
|
78312
|
+
* writable directory) rather than failing the command that asked for them.
|
|
78313
|
+
* Installing completions is never the reason an install should fail.
|
|
78314
|
+
*/
|
|
78315
|
+
const installZshCompletion = Effect.fn("cli.completions.install")(function* () {
|
|
78316
|
+
if ((yield* HostProcessPlatform) === "win32") return null;
|
|
78317
|
+
const fs = yield* FileSystem.FileSystem;
|
|
78318
|
+
const path = yield* Path.Path;
|
|
78319
|
+
const homeDir = (yield* HostProcessEnvironment).HOME ?? "";
|
|
78320
|
+
if (homeDir === "") return null;
|
|
78321
|
+
const script = yield* generateZshCompletionScript();
|
|
78322
|
+
if (script === null) return null;
|
|
78323
|
+
for (const candidate of candidateDirectories({
|
|
78324
|
+
homeDir,
|
|
78325
|
+
join: path.join
|
|
78326
|
+
})) {
|
|
78327
|
+
if (candidate.requiresFpathEntry) {
|
|
78328
|
+
if (!(yield* fs.makeDirectory(candidate.dir, { recursive: true }).pipe(Effect.as(true), Effect.orElseSucceed(() => false)))) continue;
|
|
78329
|
+
} else if (!(yield* fs.exists(candidate.dir).pipe(Effect.orElseSucceed(() => false)))) continue;
|
|
78330
|
+
const target = path.join(candidate.dir, COMPLETION_FILE);
|
|
78331
|
+
if (!(yield* fs.writeFileString(target, script).pipe(Effect.as(true), Effect.orElseSucceed(() => false)))) continue;
|
|
78332
|
+
return {
|
|
78333
|
+
path: target,
|
|
78334
|
+
requiresFpathEntry: candidate.requiresFpathEntry
|
|
78335
|
+
};
|
|
78336
|
+
}
|
|
78337
|
+
return null;
|
|
78338
|
+
});
|
|
78339
|
+
function formatZshCompletionInstall(install) {
|
|
78340
|
+
const installed = `Installed zsh completions at ${install.path}.`;
|
|
78341
|
+
if (!install.requiresFpathEntry) return `${installed} Open a new shell to use them.`;
|
|
78342
|
+
return [
|
|
78343
|
+
installed,
|
|
78344
|
+
`Add this to ~/.zshrc before compinit runs, then open a new shell:`,
|
|
78345
|
+
` fpath=(${install.path.replace(/\/[^/]+$/u, "")} $fpath)`
|
|
78346
|
+
].join("\n");
|
|
78347
|
+
}
|
|
78348
|
+
//#endregion
|
|
78171
78349
|
//#region src/cli/service.ts
|
|
78172
78350
|
const isBootServiceCommandError = Schema$1.is(BootServiceCommandError);
|
|
78173
78351
|
const bootServiceLayer = (config) => layer$46({
|
|
@@ -78220,7 +78398,7 @@ const runServiceCommand = Effect.fn("cli.service.run")(function* (flags, run) {
|
|
|
78220
78398
|
const config = yield* resolveCliAuthConfig(flags, yield* GlobalFlag.LogLevel);
|
|
78221
78399
|
const baseDirNotice = yield* describeNonDefaultBaseDir(config.baseDir);
|
|
78222
78400
|
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)));
|
|
78401
|
+
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
78402
|
});
|
|
78225
78403
|
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
78404
|
const result = yield* reconcileService();
|
|
@@ -78234,6 +78412,8 @@ const serviceInstallCommand = Command.make("install", projectLocationFlags).pipe
|
|
|
78234
78412
|
cliVersion: version,
|
|
78235
78413
|
platform: yield* HostProcessPlatform
|
|
78236
78414
|
}));
|
|
78415
|
+
const completion = yield* installZshCompletion().pipe(Effect.orElseSucceed(() => null));
|
|
78416
|
+
if (completion !== null) yield* Console.log(formatZshCompletionInstall(completion));
|
|
78237
78417
|
}))));
|
|
78238
78418
|
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
78419
|
const result = yield* reconcileService();
|
|
@@ -78280,7 +78460,23 @@ const serviceCommand = Command.make("service").pipe(Command.withDescription("Man
|
|
|
78280
78460
|
]));
|
|
78281
78461
|
//#endregion
|
|
78282
78462
|
//#region src/bin.ts
|
|
78283
|
-
const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$62);
|
|
78463
|
+
const CliRuntimeLayer = Layer.mergeAll(NodeServices.layer, layer$62, FetchHttpClient.layer);
|
|
78464
|
+
/**
|
|
78465
|
+
* Prints an update reminder before dispatching, at most once a day.
|
|
78466
|
+
*
|
|
78467
|
+
* On stderr so it never contaminates `--json` output or a redirected
|
|
78468
|
+
* `--completions` script, and fully swallowed: an advisory notice must not be
|
|
78469
|
+
* able to fail a command or change its exit code.
|
|
78470
|
+
*/
|
|
78471
|
+
const reportUpdateAvailable = Effect.gen(function* () {
|
|
78472
|
+
const baseDir = yield* resolveBaseDir((yield* HostProcessEnvironment).P4CODE_HOME);
|
|
78473
|
+
const paths = yield* deriveServerPaths(baseDir, void 0);
|
|
78474
|
+
const reminder = yield* resolveUpdateReminder({
|
|
78475
|
+
currentVersion: version,
|
|
78476
|
+
stateDir: paths.stateDir
|
|
78477
|
+
});
|
|
78478
|
+
if (reminder !== null) yield* Console.error(reminder);
|
|
78479
|
+
}).pipe(Effect.ignore);
|
|
78284
78480
|
const makeCli = () => Command.make("p4", { ...sharedServerCommandFlags }).pipe(Command.withDescription("Run the P4Code server."), Command.withHandler((flags) => runServerCommand(flags)), Command.withSubcommands([
|
|
78285
78481
|
startCommand,
|
|
78286
78482
|
serveCommand,
|
|
@@ -78289,7 +78485,7 @@ const makeCli = () => Command.make("p4", { ...sharedServerCommandFlags }).pipe(C
|
|
|
78289
78485
|
serviceCommand
|
|
78290
78486
|
]));
|
|
78291
78487
|
const cli = makeCli();
|
|
78292
|
-
if (import.meta.main) Command.run(cli, { version })
|
|
78488
|
+
if (import.meta.main) reportUpdateAvailable.pipe(Effect.andThen(Command.run(cli, { version })), Effect.scoped, Effect.provide(CliRuntimeLayer), NodeRuntime.runMain);
|
|
78293
78489
|
//#endregion
|
|
78294
78490
|
export { cli, makeCli };
|
|
78295
78491
|
|