@elpapi42/pi-fleet 0.1.0-beta.10 → 0.1.0-beta.14
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/CHANGELOG.md +34 -1
- package/README.md +99 -167
- package/dist/cli-meta.json +313 -315
- package/dist/cli.mjs +2504 -1812
- package/dist/cli.mjs.map +4 -4
- package/dist/client/agent-target.d.ts +33 -0
- package/dist/client/contracts.d.ts +81 -0
- package/dist/client/fleet-client.d.ts +118 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/sdk-connector.d.ts +7 -0
- package/dist/client/sdk-facade.d.ts +84 -0
- package/dist/client/sdk-transport.d.ts +24 -0
- package/dist/client/shared-client.d.ts +18 -0
- package/dist/client/socket-fleet-client.d.ts +21 -0
- package/dist/client-meta.json +5736 -0
- package/dist/client.mjs +4434 -0
- package/dist/client.mjs.map +7 -0
- package/dist/installer-meta.json +7 -7
- package/dist/installer.mjs +47 -13
- package/dist/installer.mjs.map +2 -2
- package/dist/journal-sqlite-worker-meta.json +149 -0
- package/dist/journal-sqlite-worker.mjs +1110 -0
- package/dist/journal-sqlite-worker.mjs.map +7 -0
- package/dist/pi/external-installation.d.ts +23 -0
- package/dist/platform/client/start-runtime.d.ts +25 -0
- package/dist/platform/install/runtime-release.d.ts +8 -0
- package/dist/platform/install/tree-integrity.d.ts +7 -0
- package/dist/platform/shared/paths.d.ts +8 -0
- package/dist/platform/shared/runtime-ownership.d.ts +14 -0
- package/dist/protocol/jsonl.d.ts +3 -0
- package/dist/protocol/pi-identity.d.ts +16 -0
- package/dist/protocol/semantic-segmentation.d.ts +22 -0
- package/dist/protocol/version.d.ts +2 -0
- package/dist/runtime/semantic-events.d.ts +43 -0
- package/dist/runtime-manifest.json +156 -31
- package/dist/runtime-meta.json +378 -53
- package/dist/runtime.mjs +3173 -581
- package/dist/runtime.mjs.map +4 -4
- package/dist/shared/result.d.ts +9 -0
- package/package.json +14 -1
- package/dist/sqlite-worker-meta.json +0 -84
- package/dist/sqlite-worker.mjs +0 -359
- package/dist/sqlite-worker.mjs.map +0 -7
package/dist/cli.mjs
CHANGED
|
@@ -5,7 +5,6 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// src/entry/cli.ts
|
|
8
|
-
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
9
8
|
import { pathToFileURL } from "node:url";
|
|
10
9
|
|
|
11
10
|
// node_modules/commander/lib/error.js
|
|
@@ -3391,7 +3390,7 @@ function splitArgv(argv) {
|
|
|
3391
3390
|
|
|
3392
3391
|
// src/shared/product-identity.ts
|
|
3393
3392
|
var PRODUCT_BINARY = "pifleet";
|
|
3394
|
-
var PRODUCT_VERSION = "0.1.0-beta.
|
|
3393
|
+
var PRODUCT_VERSION = "0.1.0-beta.14";
|
|
3395
3394
|
|
|
3396
3395
|
// src/shared/identifiers.ts
|
|
3397
3396
|
var AGENT_NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
@@ -3399,16 +3398,156 @@ function isAgentName(value) {
|
|
|
3399
3398
|
return AGENT_NAME_PATTERN.test(value);
|
|
3400
3399
|
}
|
|
3401
3400
|
|
|
3401
|
+
// src/client/sdk-facade.ts
|
|
3402
|
+
function createPiFleetClient(transport) {
|
|
3403
|
+
return new PiFleetClientImpl(transport);
|
|
3404
|
+
}
|
|
3405
|
+
var PiFleetClientImpl = class {
|
|
3406
|
+
constructor(transport) {
|
|
3407
|
+
this.transport = transport;
|
|
3408
|
+
}
|
|
3409
|
+
#closed = false;
|
|
3410
|
+
#closedController = new AbortController();
|
|
3411
|
+
async create(input, options = {}) {
|
|
3412
|
+
return this.agent(
|
|
3413
|
+
await this.callAgent(() => this.transport.create(input, this.signal(options.signal)))
|
|
3414
|
+
);
|
|
3415
|
+
}
|
|
3416
|
+
async get(name, options = {}) {
|
|
3417
|
+
const summary = await this.callAgent(
|
|
3418
|
+
() => this.transport.get(name, this.signal(options.signal))
|
|
3419
|
+
);
|
|
3420
|
+
if (summary === null) {
|
|
3421
|
+
throw new PiFleetError("agent_not_found", `Agent ${name} was not found.`);
|
|
3422
|
+
}
|
|
3423
|
+
return this.agent(summary);
|
|
3424
|
+
}
|
|
3425
|
+
async list(options = {}) {
|
|
3426
|
+
return this.callAgent(() => this.transport.list(this.signal(options.signal)));
|
|
3427
|
+
}
|
|
3428
|
+
async close() {
|
|
3429
|
+
if (this.#closed) return;
|
|
3430
|
+
this.#closed = true;
|
|
3431
|
+
this.#closedController.abort();
|
|
3432
|
+
await this.transport.close();
|
|
3433
|
+
}
|
|
3434
|
+
agent(summary) {
|
|
3435
|
+
return new AgentImpl(this, this.transport, summary);
|
|
3436
|
+
}
|
|
3437
|
+
async callAgent(operation) {
|
|
3438
|
+
this.assertOpen();
|
|
3439
|
+
try {
|
|
3440
|
+
return await operation();
|
|
3441
|
+
} catch (error) {
|
|
3442
|
+
throw PiFleetError.from(error);
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
signal(signal) {
|
|
3446
|
+
this.assertOpen();
|
|
3447
|
+
return signal === void 0 ? this.#closedController.signal : AbortSignal.any([signal, this.#closedController.signal]);
|
|
3448
|
+
}
|
|
3449
|
+
assertOpen() {
|
|
3450
|
+
if (this.#closed) throw new PiFleetError("runtime_unavailable", "pi-fleet client is closed");
|
|
3451
|
+
}
|
|
3452
|
+
};
|
|
3453
|
+
var agentInternals = /* @__PURE__ */ new WeakMap();
|
|
3454
|
+
var AgentImpl = class {
|
|
3455
|
+
constructor(client, transport, initialSummary) {
|
|
3456
|
+
this.client = client;
|
|
3457
|
+
this.transport = transport;
|
|
3458
|
+
this.id = initialSummary.id;
|
|
3459
|
+
this.name = initialSummary.name;
|
|
3460
|
+
agentInternals.set(this, { client, transport, initialSummary });
|
|
3461
|
+
}
|
|
3462
|
+
id;
|
|
3463
|
+
name;
|
|
3464
|
+
status(options = {}) {
|
|
3465
|
+
return this.client.callAgent(
|
|
3466
|
+
() => this.transport.status(this.target(), this.client.signal(options.signal))
|
|
3467
|
+
);
|
|
3468
|
+
}
|
|
3469
|
+
send(message, options = {}) {
|
|
3470
|
+
return this.client.callAgent(
|
|
3471
|
+
() => this.transport.send(
|
|
3472
|
+
this.target(),
|
|
3473
|
+
message,
|
|
3474
|
+
options.delivery ?? "steer",
|
|
3475
|
+
this.client.signal(options.signal)
|
|
3476
|
+
)
|
|
3477
|
+
);
|
|
3478
|
+
}
|
|
3479
|
+
receive(options = {}) {
|
|
3480
|
+
return this.receiveInternal(options, false);
|
|
3481
|
+
}
|
|
3482
|
+
receiveInternal(options, untilIdle) {
|
|
3483
|
+
return this.client.callAgent(
|
|
3484
|
+
() => this.transport.receive(
|
|
3485
|
+
this.target(),
|
|
3486
|
+
receiveStart(options),
|
|
3487
|
+
this.client.signal(options.signal),
|
|
3488
|
+
untilIdle
|
|
3489
|
+
)
|
|
3490
|
+
);
|
|
3491
|
+
}
|
|
3492
|
+
compact(options = {}) {
|
|
3493
|
+
return this.client.callAgent(
|
|
3494
|
+
() => this.transport.compact(this.target(), this.client.signal(options.signal))
|
|
3495
|
+
);
|
|
3496
|
+
}
|
|
3497
|
+
destroy(options = {}) {
|
|
3498
|
+
return this.client.callAgent(
|
|
3499
|
+
() => this.transport.destroy(this.target(), this.client.signal(options.signal))
|
|
3500
|
+
);
|
|
3501
|
+
}
|
|
3502
|
+
target() {
|
|
3503
|
+
return { name: this.name, expectedAgentId: this.id };
|
|
3504
|
+
}
|
|
3505
|
+
};
|
|
3506
|
+
function receiveStart(options) {
|
|
3507
|
+
if ("after" in options && options.after !== void 0) {
|
|
3508
|
+
return { kind: "after", cursor: options.after };
|
|
3509
|
+
}
|
|
3510
|
+
if ("fromStart" in options && options.fromStart === true) return { kind: "start" };
|
|
3511
|
+
return { kind: "live" };
|
|
3512
|
+
}
|
|
3513
|
+
function agentInitialStatus(agent) {
|
|
3514
|
+
return requireAgentInternals(agent).initialSummary;
|
|
3515
|
+
}
|
|
3516
|
+
function receiveAgentUntilIdle(agent, options = {}) {
|
|
3517
|
+
const { client, transport } = requireAgentInternals(agent);
|
|
3518
|
+
return client.callAgent(
|
|
3519
|
+
() => transport.receive(
|
|
3520
|
+
{ name: agent.name, expectedAgentId: agent.id },
|
|
3521
|
+
{ kind: "live" },
|
|
3522
|
+
client.signal(options.signal),
|
|
3523
|
+
true
|
|
3524
|
+
)
|
|
3525
|
+
);
|
|
3526
|
+
}
|
|
3527
|
+
function requireAgentInternals(agent) {
|
|
3528
|
+
const internals = agentInternals.get(agent);
|
|
3529
|
+
if (internals === void 0) throw new Error("Unknown pi-fleet Agent handle");
|
|
3530
|
+
return internals;
|
|
3531
|
+
}
|
|
3532
|
+
var PiFleetError = class _PiFleetError extends Error {
|
|
3533
|
+
constructor(code, message, details) {
|
|
3534
|
+
super(message);
|
|
3535
|
+
this.code = code;
|
|
3536
|
+
this.details = details;
|
|
3537
|
+
this.name = "PiFleetError";
|
|
3538
|
+
}
|
|
3539
|
+
static from(error) {
|
|
3540
|
+
if (error instanceof _PiFleetError) return error;
|
|
3541
|
+
return new _PiFleetError("internal_error", "pi-fleet client operation failed");
|
|
3542
|
+
}
|
|
3543
|
+
};
|
|
3544
|
+
|
|
3402
3545
|
// src/cli/output.ts
|
|
3403
3546
|
function writeResult(stream, result, human) {
|
|
3404
3547
|
stream.write(human ? `${renderHuman(result)}
|
|
3405
3548
|
` : `${JSON.stringify(result)}
|
|
3406
3549
|
`);
|
|
3407
3550
|
}
|
|
3408
|
-
function writeWatchReady(stream, name) {
|
|
3409
|
-
stream.write(`${JSON.stringify({ schemaVersion: 1, type: "watch.ready", agent: { name } })}
|
|
3410
|
-
`);
|
|
3411
|
-
}
|
|
3412
3551
|
function writeError(stream, error, human) {
|
|
3413
3552
|
if (human) {
|
|
3414
3553
|
stream.write(`${error.message}
|
|
@@ -3424,8 +3563,6 @@ function renderHuman(result) {
|
|
|
3424
3563
|
return `${result.agent.name}: ${result.agent.state} (${result.agent.process.state})`;
|
|
3425
3564
|
case "message.accepted":
|
|
3426
3565
|
return `${result.agent.name}: message accepted`;
|
|
3427
|
-
case "response":
|
|
3428
|
-
return result.response.text;
|
|
3429
3566
|
case "agent.status":
|
|
3430
3567
|
return `${result.agent.name}: ${result.agent.state} (${result.agent.process.state})`;
|
|
3431
3568
|
case "agent.list":
|
|
@@ -3438,23 +3575,42 @@ function renderHuman(result) {
|
|
|
3438
3575
|
}
|
|
3439
3576
|
|
|
3440
3577
|
// src/cli/commands/common.ts
|
|
3441
|
-
function
|
|
3442
|
-
|
|
3443
|
-
writeResult(context.stdout,
|
|
3578
|
+
async function finishSdkFinite(operation, context, human) {
|
|
3579
|
+
try {
|
|
3580
|
+
writeResult(context.stdout, await operation, human);
|
|
3444
3581
|
return 0;
|
|
3582
|
+
} catch (error) {
|
|
3583
|
+
const publicError2 = PiFleetError.from(error);
|
|
3584
|
+
writeError(
|
|
3585
|
+
context.stderr,
|
|
3586
|
+
{
|
|
3587
|
+
code: publicError2.code,
|
|
3588
|
+
message: publicError2.message,
|
|
3589
|
+
...publicError2.details === void 0 ? {} : { details: publicError2.details }
|
|
3590
|
+
},
|
|
3591
|
+
human
|
|
3592
|
+
);
|
|
3593
|
+
return publicError2.code === "timeout" ? 124 : 1;
|
|
3445
3594
|
}
|
|
3446
|
-
writeError(context.stderr, result.error, human);
|
|
3447
|
-
return result.error.code === "timeout" ? 124 : 1;
|
|
3448
3595
|
}
|
|
3449
3596
|
|
|
3450
3597
|
// src/cli/commands/compact.ts
|
|
3451
3598
|
async function runCompact(input, context) {
|
|
3452
3599
|
if (!isAgentName(input.name)) throw new Error("invalid agent name");
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3600
|
+
return finishSdkFinite(
|
|
3601
|
+
(async () => {
|
|
3602
|
+
const agent = await context.client.get(input.name, { signal: context.signal });
|
|
3603
|
+
const compaction = await agent.compact({ signal: context.signal });
|
|
3604
|
+
return {
|
|
3605
|
+
schemaVersion: 1,
|
|
3606
|
+
type: "agent.compacted",
|
|
3607
|
+
agent: { id: agent.id, name: agent.name },
|
|
3608
|
+
compaction
|
|
3609
|
+
};
|
|
3610
|
+
})(),
|
|
3611
|
+
context,
|
|
3612
|
+
input.human
|
|
3456
3613
|
);
|
|
3457
|
-
return finishFinite(result, context, input.human);
|
|
3458
3614
|
}
|
|
3459
3615
|
|
|
3460
3616
|
// src/cli/commands/create.ts
|
|
@@ -3489,116 +3645,154 @@ function requireContent(value) {
|
|
|
3489
3645
|
async function runCreate(input, context) {
|
|
3490
3646
|
if (!isAgentName(input.name)) throw new Error("invalid agent name");
|
|
3491
3647
|
const instructions = input.instructions === void 0 ? void 0 : await resolveMessageInput(input.instructions, context.stdin);
|
|
3492
|
-
|
|
3493
|
-
{
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3648
|
+
return finishSdkFinite(
|
|
3649
|
+
(async () => {
|
|
3650
|
+
const agent = await context.client.create(
|
|
3651
|
+
{
|
|
3652
|
+
name: input.name,
|
|
3653
|
+
...instructions === void 0 ? {} : { instructions },
|
|
3654
|
+
cwd: resolve(context.cwd, input.cwd ?? "."),
|
|
3655
|
+
piArgs: context.piArgv
|
|
3656
|
+
},
|
|
3657
|
+
{ signal: context.signal }
|
|
3658
|
+
);
|
|
3659
|
+
return {
|
|
3660
|
+
schemaVersion: 1,
|
|
3661
|
+
type: "agent.created",
|
|
3662
|
+
agent: agentInitialStatus(agent)
|
|
3663
|
+
};
|
|
3664
|
+
})(),
|
|
3665
|
+
context,
|
|
3666
|
+
input.human
|
|
3500
3667
|
);
|
|
3501
|
-
return finishFinite(result, context, input.human);
|
|
3502
3668
|
}
|
|
3503
3669
|
|
|
3504
3670
|
// src/cli/commands/destroy.ts
|
|
3505
3671
|
async function runDestroy(input, context) {
|
|
3506
3672
|
if (!isAgentName(input.name)) throw new Error("invalid agent name");
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3673
|
+
return finishSdkFinite(
|
|
3674
|
+
(async () => {
|
|
3675
|
+
const agent = await context.client.get(input.name, { signal: context.signal });
|
|
3676
|
+
await agent.destroy({ signal: context.signal });
|
|
3677
|
+
return {
|
|
3678
|
+
schemaVersion: 1,
|
|
3679
|
+
type: "agent.destroyed",
|
|
3680
|
+
agent: { id: agent.id, name: agent.name }
|
|
3681
|
+
};
|
|
3682
|
+
})(),
|
|
3683
|
+
context,
|
|
3684
|
+
input.human
|
|
3510
3685
|
);
|
|
3511
|
-
return finishFinite(result, context, input.human);
|
|
3512
3686
|
}
|
|
3513
3687
|
|
|
3514
3688
|
// src/cli/commands/list.ts
|
|
3515
3689
|
async function runList(input, context) {
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
return { ok: false, error };
|
|
3526
|
-
}
|
|
3527
|
-
|
|
3528
|
-
// src/shared/duration.ts
|
|
3529
|
-
var UNIT_TO_MILLISECONDS = {
|
|
3530
|
-
ms: 1,
|
|
3531
|
-
s: 1e3,
|
|
3532
|
-
m: 6e4,
|
|
3533
|
-
h: 36e5
|
|
3534
|
-
};
|
|
3535
|
-
function parseDuration(input) {
|
|
3536
|
-
const match = /^(\d+)(ms|s|m|h)?$/.exec(input);
|
|
3537
|
-
if (match === null) {
|
|
3538
|
-
return err("invalid_duration");
|
|
3539
|
-
}
|
|
3540
|
-
const amount = Number(match[1]);
|
|
3541
|
-
const unit = match[2] ?? "ms";
|
|
3542
|
-
return ok(amount * UNIT_TO_MILLISECONDS[unit]);
|
|
3690
|
+
return finishSdkFinite(
|
|
3691
|
+
context.client.list({ signal: context.signal }).then((agents) => ({
|
|
3692
|
+
schemaVersion: 1,
|
|
3693
|
+
type: "agent.list",
|
|
3694
|
+
agents
|
|
3695
|
+
})),
|
|
3696
|
+
context,
|
|
3697
|
+
input.human
|
|
3698
|
+
);
|
|
3543
3699
|
}
|
|
3544
3700
|
|
|
3545
3701
|
// src/cli/commands/receive.ts
|
|
3702
|
+
import { once } from "node:events";
|
|
3546
3703
|
async function runReceive(input, context) {
|
|
3547
3704
|
if (!isAgentName(input.name)) throw new Error("invalid agent name");
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3705
|
+
if (input.after !== void 0 && input.fromStart) {
|
|
3706
|
+
throw new Error("--after and --from-start cannot be combined");
|
|
3707
|
+
}
|
|
3708
|
+
if (input.untilIdle && (input.after !== void 0 || input.fromStart)) {
|
|
3709
|
+
throw new Error("--until-idle uses a live boundary and cannot be combined with history");
|
|
3710
|
+
}
|
|
3711
|
+
try {
|
|
3712
|
+
const agent = await context.client.get(input.name, { signal: context.signal });
|
|
3713
|
+
const stream = input.untilIdle ? await receiveAgentUntilIdle(agent, { signal: context.signal }) : await agent.receive(
|
|
3714
|
+
input.after !== void 0 ? { after: input.after, signal: context.signal } : input.fromStart ? { fromStart: true, signal: context.signal } : { signal: context.signal }
|
|
3715
|
+
);
|
|
3716
|
+
context.stderr.write(
|
|
3717
|
+
input.human ? `receive ready at ${stream.cursor}
|
|
3718
|
+
` : `${JSON.stringify({ schemaVersion: 1, type: "receive.ready", cursor: stream.cursor })}
|
|
3719
|
+
`
|
|
3720
|
+
);
|
|
3721
|
+
for await (const event of stream) {
|
|
3722
|
+
const output = input.human ? `${renderHumanEvent(event)}
|
|
3723
|
+
` : `${JSON.stringify(event)}
|
|
3724
|
+
`;
|
|
3725
|
+
try {
|
|
3726
|
+
if (!context.stdout.write(output)) await once(context.stdout, "drain");
|
|
3727
|
+
} catch (error) {
|
|
3728
|
+
if (error.code === "EPIPE") return 0;
|
|
3729
|
+
throw error;
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
return 0;
|
|
3733
|
+
} catch (error) {
|
|
3734
|
+
const publicError2 = PiFleetError.from(error);
|
|
3735
|
+
writeError(
|
|
3736
|
+
context.stderr,
|
|
3737
|
+
{
|
|
3738
|
+
code: publicError2.code,
|
|
3739
|
+
message: publicError2.message,
|
|
3740
|
+
...publicError2.details === void 0 ? {} : { details: publicError2.details }
|
|
3741
|
+
},
|
|
3742
|
+
input.human
|
|
3743
|
+
);
|
|
3744
|
+
return publicError2.code === "timeout" ? 124 : 1;
|
|
3745
|
+
}
|
|
3746
|
+
}
|
|
3747
|
+
function renderHumanEvent(event) {
|
|
3748
|
+
return JSON.stringify(event);
|
|
3556
3749
|
}
|
|
3557
3750
|
|
|
3558
3751
|
// src/cli/commands/send.ts
|
|
3559
3752
|
async function runSend(input, context) {
|
|
3560
3753
|
if (!isAgentName(input.name)) throw new Error("invalid agent name");
|
|
3561
3754
|
const message = await resolveMessageInput(input.message, context.stdin);
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3755
|
+
return finishSdkFinite(
|
|
3756
|
+
(async () => {
|
|
3757
|
+
const agent = await context.client.get(input.name, { signal: context.signal });
|
|
3758
|
+
const receipt = await agent.send(message, {
|
|
3759
|
+
delivery: input.delivery,
|
|
3760
|
+
signal: context.signal
|
|
3761
|
+
});
|
|
3762
|
+
return {
|
|
3763
|
+
schemaVersion: 1,
|
|
3764
|
+
type: "message.accepted",
|
|
3765
|
+
agent: { id: agent.id, name: agent.name },
|
|
3766
|
+
acceptedAt: receipt.acceptedAt
|
|
3767
|
+
};
|
|
3768
|
+
})(),
|
|
3769
|
+
context,
|
|
3770
|
+
input.human
|
|
3565
3771
|
);
|
|
3566
|
-
return finishFinite(result, context, input.human);
|
|
3567
3772
|
}
|
|
3568
3773
|
|
|
3569
3774
|
// src/cli/commands/status.ts
|
|
3570
3775
|
async function runStatus(input, context) {
|
|
3571
3776
|
if (!isAgentName(input.name)) throw new Error("invalid agent name");
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
}
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
return 1;
|
|
3585
|
-
}
|
|
3586
|
-
if (result.value.type === "ready") {
|
|
3587
|
-
writeWatchReady(context.stderr, name);
|
|
3588
|
-
continue;
|
|
3589
|
-
}
|
|
3590
|
-
if (!context.stdout.write(result.value.bytes)) await once(context.stdout, "drain");
|
|
3591
|
-
}
|
|
3592
|
-
return 0;
|
|
3593
|
-
} catch (error) {
|
|
3594
|
-
if (error.code === "EPIPE") return 0;
|
|
3595
|
-
throw error;
|
|
3596
|
-
}
|
|
3777
|
+
return finishSdkFinite(
|
|
3778
|
+
(async () => {
|
|
3779
|
+
const agent = await context.client.get(input.name, { signal: context.signal });
|
|
3780
|
+
return {
|
|
3781
|
+
schemaVersion: 1,
|
|
3782
|
+
type: "agent.status",
|
|
3783
|
+
agent: agentInitialStatus(agent)
|
|
3784
|
+
};
|
|
3785
|
+
})(),
|
|
3786
|
+
context,
|
|
3787
|
+
input.human
|
|
3788
|
+
);
|
|
3597
3789
|
}
|
|
3598
3790
|
|
|
3599
3791
|
// src/cli/program.ts
|
|
3600
3792
|
function createProgram(context, setExitCode) {
|
|
3601
|
-
const program2 = new Command().name(PRODUCT_BINARY).description(
|
|
3793
|
+
const program2 = new Command().name(PRODUCT_BINARY).description(
|
|
3794
|
+
"Control shared local Pi agents; stream durable semantic activity with user-owned sessions"
|
|
3795
|
+
).version(PRODUCT_VERSION).exitOverride().showHelpAfterError(false).showSuggestionAfterError(false).configureOutput({
|
|
3602
3796
|
writeOut: (text) => context.stdout.write(text),
|
|
3603
3797
|
writeErr: () => void 0
|
|
3604
3798
|
});
|
|
@@ -3615,15 +3809,27 @@ function createProgram(context, setExitCode) {
|
|
|
3615
3809
|
)
|
|
3616
3810
|
);
|
|
3617
3811
|
});
|
|
3618
|
-
program2.command("send").description("Submit or steer Pi input").argument("<name>").argument("<message>").option("--human").action(async (name, message, options) => {
|
|
3619
|
-
setExitCode(
|
|
3812
|
+
program2.command("send").description("Submit or steer Pi input").argument("<name>").argument("<message>").option("--follow-up", "Queue the input until Pi is fully done").option("--human").action(async (name, message, options) => {
|
|
3813
|
+
setExitCode(
|
|
3814
|
+
await runSend(
|
|
3815
|
+
{
|
|
3816
|
+
name,
|
|
3817
|
+
message,
|
|
3818
|
+
delivery: options.followUp === true ? "followUp" : "steer",
|
|
3819
|
+
human: options.human ?? false
|
|
3820
|
+
},
|
|
3821
|
+
context
|
|
3822
|
+
)
|
|
3823
|
+
);
|
|
3620
3824
|
});
|
|
3621
|
-
program2.command("receive").description("
|
|
3825
|
+
program2.command("receive").description("Stream durable high-level Pi activity").argument("<name>").option("--after <cursor>", "Replay strictly after a receive cursor, then follow live").option("--from-start", "Replay retained agent history, then follow live").option("--until-idle", "Attach live and exit after the exact observed idle boundary").option("--human").action(async (name, options) => {
|
|
3622
3826
|
setExitCode(
|
|
3623
3827
|
await runReceive(
|
|
3624
3828
|
{
|
|
3625
3829
|
name,
|
|
3626
|
-
...options.
|
|
3830
|
+
...options.after === void 0 ? {} : { after: options.after },
|
|
3831
|
+
fromStart: options.fromStart ?? false,
|
|
3832
|
+
untilIdle: options.untilIdle ?? false,
|
|
3627
3833
|
human: options.human ?? false
|
|
3628
3834
|
},
|
|
3629
3835
|
context
|
|
@@ -3636,9 +3842,6 @@ function createProgram(context, setExitCode) {
|
|
|
3636
3842
|
program2.command("list").description("List agents without waking Pi").option("--human").action(async (options) => {
|
|
3637
3843
|
setExitCode(await runList({ human: options.human ?? false }, context));
|
|
3638
3844
|
});
|
|
3639
|
-
program2.command("watch").description("Stream live raw Pi RPC JSONL").argument("<name>").action(async (name) => {
|
|
3640
|
-
setExitCode(await runWatch(name, context));
|
|
3641
|
-
});
|
|
3642
3845
|
program2.command("compact").description("Compact an idle Pi agent session").argument("<name>").option("--human").action(async (name, options) => {
|
|
3643
3846
|
setExitCode(await runCompact({ name, human: options.human ?? false }, context));
|
|
3644
3847
|
});
|
|
@@ -3648,704 +3851,1545 @@ function createProgram(context, setExitCode) {
|
|
|
3648
3851
|
return program2;
|
|
3649
3852
|
}
|
|
3650
3853
|
|
|
3651
|
-
// src/client/
|
|
3652
|
-
import { randomUUID } from "node:crypto";
|
|
3653
|
-
import { createConnection } from "node:net";
|
|
3654
|
-
|
|
3655
|
-
// src/protocol/version.ts
|
|
3656
|
-
var PROTOCOL_VERSION = 2;
|
|
3657
|
-
var MAX_PROTOCOL_FRAME_BYTES = 1024 * 1024;
|
|
3854
|
+
// src/client/shared-client.ts
|
|
3855
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
3658
3856
|
|
|
3659
|
-
// src/
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
return;
|
|
3684
|
-
}
|
|
3685
|
-
}
|
|
3857
|
+
// src/pi/external-installation.ts
|
|
3858
|
+
import { spawn } from "node:child_process";
|
|
3859
|
+
import { createHash } from "node:crypto";
|
|
3860
|
+
import { constants } from "node:fs";
|
|
3861
|
+
import { createReadStream } from "node:fs";
|
|
3862
|
+
import { access, realpath, stat } from "node:fs/promises";
|
|
3863
|
+
import { delimiter, dirname, isAbsolute, join } from "node:path";
|
|
3864
|
+
var VERSION_TIMEOUT_MS = 3e3;
|
|
3865
|
+
var MAX_VERSION_OUTPUT_BYTES = 4 * 1024;
|
|
3866
|
+
var ExternalPiResolutionError = class extends Error {
|
|
3867
|
+
constructor(code, message) {
|
|
3868
|
+
super(message);
|
|
3869
|
+
this.code = code;
|
|
3870
|
+
this.name = "ExternalPiResolutionError";
|
|
3871
|
+
}
|
|
3872
|
+
};
|
|
3873
|
+
function installationIdentity(installation) {
|
|
3874
|
+
return {
|
|
3875
|
+
mode: "external",
|
|
3876
|
+
selectedPath: installation.selectedPath,
|
|
3877
|
+
nodePath: installation.nodePath,
|
|
3878
|
+
realPath: installation.realPath,
|
|
3879
|
+
version: installation.version,
|
|
3880
|
+
fingerprint: installation.fingerprint
|
|
3686
3881
|
};
|
|
3687
|
-
socket.on("data", onData);
|
|
3688
|
-
return () => socket.off("data", onData);
|
|
3689
|
-
}
|
|
3690
|
-
function writeJsonLine(socket, value) {
|
|
3691
|
-
return socket.write(`${JSON.stringify(value)}
|
|
3692
|
-
`);
|
|
3693
|
-
}
|
|
3694
|
-
|
|
3695
|
-
// node_modules/@sinclair/typebox/build/esm/type/guard/value.mjs
|
|
3696
|
-
var value_exports = {};
|
|
3697
|
-
__export(value_exports, {
|
|
3698
|
-
HasPropertyKey: () => HasPropertyKey,
|
|
3699
|
-
IsArray: () => IsArray,
|
|
3700
|
-
IsAsyncIterator: () => IsAsyncIterator,
|
|
3701
|
-
IsBigInt: () => IsBigInt,
|
|
3702
|
-
IsBoolean: () => IsBoolean,
|
|
3703
|
-
IsDate: () => IsDate,
|
|
3704
|
-
IsFunction: () => IsFunction,
|
|
3705
|
-
IsIterator: () => IsIterator,
|
|
3706
|
-
IsNull: () => IsNull,
|
|
3707
|
-
IsNumber: () => IsNumber,
|
|
3708
|
-
IsObject: () => IsObject,
|
|
3709
|
-
IsRegExp: () => IsRegExp,
|
|
3710
|
-
IsString: () => IsString,
|
|
3711
|
-
IsSymbol: () => IsSymbol,
|
|
3712
|
-
IsUint8Array: () => IsUint8Array,
|
|
3713
|
-
IsUndefined: () => IsUndefined
|
|
3714
|
-
});
|
|
3715
|
-
function HasPropertyKey(value, key) {
|
|
3716
|
-
return key in value;
|
|
3717
3882
|
}
|
|
3718
|
-
function
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3883
|
+
async function resolveExternalPiInstallation(options = {}) {
|
|
3884
|
+
const env = options.env ?? process.env;
|
|
3885
|
+
const selectedPath = await resolveSelectedPath(env);
|
|
3886
|
+
const nodePath = options.nodePath ?? await resolveNodePath(env);
|
|
3887
|
+
await inspectNode(nodePath);
|
|
3888
|
+
const executionEnv = externalPiExecutionEnvironment(env, selectedPath, nodePath);
|
|
3889
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
3890
|
+
const observation = await observeInstallation(selectedPath, executionEnv, options);
|
|
3891
|
+
if (observation !== null) {
|
|
3892
|
+
return {
|
|
3893
|
+
selectedPath,
|
|
3894
|
+
nodePath,
|
|
3895
|
+
...observation
|
|
3896
|
+
};
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
throw new ExternalPiResolutionError(
|
|
3900
|
+
"pi_installation_changed",
|
|
3901
|
+
"Pi changed while its installation was being observed."
|
|
3902
|
+
);
|
|
3723
3903
|
}
|
|
3724
|
-
function
|
|
3725
|
-
return
|
|
3904
|
+
function externalPiExecutionEnvironment(env, selectedPath, nodePath) {
|
|
3905
|
+
return {
|
|
3906
|
+
...env,
|
|
3907
|
+
PATH: [dirname(nodePath), dirname(selectedPath), env.PATH].filter((value) => value !== void 0 && value.length > 0).join(delimiter)
|
|
3908
|
+
};
|
|
3726
3909
|
}
|
|
3727
|
-
function
|
|
3728
|
-
|
|
3910
|
+
async function observeInstallation(selectedPath, env, options) {
|
|
3911
|
+
const beforeRealPath = await inspectExecutable(selectedPath, "Pi");
|
|
3912
|
+
const beforeHash = await hashFile(beforeRealPath);
|
|
3913
|
+
const versionOutput = await (options.versionCommand ?? ((executable) => readVersion(executable, env, options.versionTimeoutMs, options.maxVersionOutputBytes)))(selectedPath);
|
|
3914
|
+
const version = parseVersion(versionOutput);
|
|
3915
|
+
const afterRealPath = await inspectExecutable(selectedPath, "Pi");
|
|
3916
|
+
const afterHash = await hashFile(afterRealPath);
|
|
3917
|
+
if (beforeRealPath !== afterRealPath || beforeHash !== afterHash) return null;
|
|
3918
|
+
return {
|
|
3919
|
+
realPath: afterRealPath,
|
|
3920
|
+
version,
|
|
3921
|
+
fingerprint: createHash("sha256").update(JSON.stringify([selectedPath, afterRealPath, version, afterHash])).digest("hex")
|
|
3922
|
+
};
|
|
3729
3923
|
}
|
|
3730
|
-
function
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
}
|
|
3739
|
-
|
|
3740
|
-
|
|
3924
|
+
async function resolveSelectedPath(env) {
|
|
3925
|
+
const explicit = env.PIFLEET_PI_EXECUTABLE;
|
|
3926
|
+
if (explicit !== void 0) {
|
|
3927
|
+
if (!isAbsolute(explicit)) {
|
|
3928
|
+
throw new ExternalPiResolutionError(
|
|
3929
|
+
"invalid_arguments",
|
|
3930
|
+
"PIFLEET_PI_EXECUTABLE must be an absolute path."
|
|
3931
|
+
);
|
|
3932
|
+
}
|
|
3933
|
+
return explicit;
|
|
3934
|
+
}
|
|
3935
|
+
return resolvePathExecutable(env, "pi", "Pi", "pi_not_found");
|
|
3741
3936
|
}
|
|
3742
|
-
function
|
|
3743
|
-
return
|
|
3937
|
+
async function resolveNodePath(env) {
|
|
3938
|
+
return resolvePathExecutable(env, "node", "Node", "pi_not_executable");
|
|
3744
3939
|
}
|
|
3745
|
-
function
|
|
3746
|
-
|
|
3940
|
+
async function resolvePathExecutable(env, name, label, missingCode) {
|
|
3941
|
+
const path2 = env.PATH;
|
|
3942
|
+
if (path2 === void 0 || path2.length === 0) {
|
|
3943
|
+
throw new ExternalPiResolutionError(missingCode, `${label} was not found on PATH.`);
|
|
3944
|
+
}
|
|
3945
|
+
for (const directory of path2.split(delimiter)) {
|
|
3946
|
+
if (!isAbsolute(directory)) {
|
|
3947
|
+
throw new ExternalPiResolutionError(
|
|
3948
|
+
"invalid_arguments",
|
|
3949
|
+
`PATH entries used to select ${label} must be absolute paths.`
|
|
3950
|
+
);
|
|
3951
|
+
}
|
|
3952
|
+
const candidate = join(directory, name);
|
|
3953
|
+
try {
|
|
3954
|
+
await inspectExecutable(candidate, label);
|
|
3955
|
+
return candidate;
|
|
3956
|
+
} catch (error) {
|
|
3957
|
+
if (!(error instanceof ExternalPiResolutionError) || error.code !== "pi_not_executable" && error.code !== "pi_not_found") {
|
|
3958
|
+
throw error;
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
throw new ExternalPiResolutionError(missingCode, `${label} was not found on PATH.`);
|
|
3747
3963
|
}
|
|
3748
|
-
function
|
|
3749
|
-
|
|
3964
|
+
async function inspectExecutable(path2, label) {
|
|
3965
|
+
try {
|
|
3966
|
+
const target = await realpath(path2);
|
|
3967
|
+
const metadata = await stat(target);
|
|
3968
|
+
if (!metadata.isFile()) {
|
|
3969
|
+
throw new ExternalPiResolutionError("pi_not_executable", `${label} is not a file: ${path2}`);
|
|
3970
|
+
}
|
|
3971
|
+
await access(path2, constants.X_OK);
|
|
3972
|
+
return target;
|
|
3973
|
+
} catch (error) {
|
|
3974
|
+
if (error instanceof ExternalPiResolutionError) throw error;
|
|
3975
|
+
if (error.code === "ENOENT") {
|
|
3976
|
+
throw new ExternalPiResolutionError("pi_not_found", `${label} was not found: ${path2}`);
|
|
3977
|
+
}
|
|
3978
|
+
throw new ExternalPiResolutionError("pi_not_executable", `${label} is not executable: ${path2}`);
|
|
3979
|
+
}
|
|
3750
3980
|
}
|
|
3751
|
-
function
|
|
3752
|
-
|
|
3981
|
+
async function inspectNode(nodePath) {
|
|
3982
|
+
if (!isAbsolute(nodePath)) {
|
|
3983
|
+
throw new ExternalPiResolutionError("invalid_arguments", "Node must be an absolute path.");
|
|
3984
|
+
}
|
|
3985
|
+
try {
|
|
3986
|
+
await inspectExecutable(nodePath, "Node");
|
|
3987
|
+
} catch {
|
|
3988
|
+
throw new ExternalPiResolutionError("pi_not_executable", `Node is not executable: ${nodePath}`);
|
|
3989
|
+
}
|
|
3753
3990
|
}
|
|
3754
|
-
function
|
|
3755
|
-
|
|
3991
|
+
async function hashFile(path2) {
|
|
3992
|
+
const hash = createHash("sha256");
|
|
3993
|
+
await new Promise((resolveHash, rejectHash) => {
|
|
3994
|
+
const stream = createReadStream(path2);
|
|
3995
|
+
stream.on("data", (chunk) => hash.update(chunk));
|
|
3996
|
+
stream.once("error", rejectHash);
|
|
3997
|
+
stream.once("end", resolveHash);
|
|
3998
|
+
});
|
|
3999
|
+
return hash.digest("hex");
|
|
3756
4000
|
}
|
|
3757
|
-
function
|
|
3758
|
-
|
|
4001
|
+
async function readVersion(executable, env, timeoutMs = VERSION_TIMEOUT_MS, maxOutputBytes = MAX_VERSION_OUTPUT_BYTES) {
|
|
4002
|
+
const child = spawn(executable, ["--version"], {
|
|
4003
|
+
detached: process.platform !== "win32",
|
|
4004
|
+
env,
|
|
4005
|
+
shell: false,
|
|
4006
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
4007
|
+
});
|
|
4008
|
+
const chunks = [];
|
|
4009
|
+
let outputBytes = 0;
|
|
4010
|
+
let terminalError = null;
|
|
4011
|
+
let terminated = false;
|
|
4012
|
+
const terminate = () => {
|
|
4013
|
+
if (terminated) return;
|
|
4014
|
+
terminated = true;
|
|
4015
|
+
if (process.platform !== "win32" && child.pid !== void 0) {
|
|
4016
|
+
try {
|
|
4017
|
+
process.kill(-child.pid, "SIGKILL");
|
|
4018
|
+
return;
|
|
4019
|
+
} catch {
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
child.kill("SIGKILL");
|
|
4023
|
+
};
|
|
4024
|
+
child.stdout.on("data", (chunk) => {
|
|
4025
|
+
if (terminalError !== null) return;
|
|
4026
|
+
outputBytes += chunk.byteLength;
|
|
4027
|
+
if (outputBytes > maxOutputBytes) {
|
|
4028
|
+
terminalError = new ExternalPiResolutionError(
|
|
4029
|
+
"pi_version_unavailable",
|
|
4030
|
+
"Pi version output exceeded its limit."
|
|
4031
|
+
);
|
|
4032
|
+
terminate();
|
|
4033
|
+
return;
|
|
4034
|
+
}
|
|
4035
|
+
chunks.push(chunk);
|
|
4036
|
+
});
|
|
4037
|
+
child.stderr.resume();
|
|
4038
|
+
return new Promise((resolveVersion, rejectVersion) => {
|
|
4039
|
+
const timer = setTimeout(() => {
|
|
4040
|
+
terminalError = new ExternalPiResolutionError(
|
|
4041
|
+
"pi_version_unavailable",
|
|
4042
|
+
"Pi version command timed out."
|
|
4043
|
+
);
|
|
4044
|
+
terminate();
|
|
4045
|
+
}, timeoutMs);
|
|
4046
|
+
child.once("error", () => {
|
|
4047
|
+
terminalError ??= new ExternalPiResolutionError(
|
|
4048
|
+
"pi_version_unavailable",
|
|
4049
|
+
"Pi version command failed."
|
|
4050
|
+
);
|
|
4051
|
+
});
|
|
4052
|
+
child.once("close", (code) => {
|
|
4053
|
+
clearTimeout(timer);
|
|
4054
|
+
if (terminalError !== null) {
|
|
4055
|
+
rejectVersion(terminalError);
|
|
4056
|
+
return;
|
|
4057
|
+
}
|
|
4058
|
+
if (code !== 0) {
|
|
4059
|
+
rejectVersion(
|
|
4060
|
+
new ExternalPiResolutionError("pi_version_unavailable", "Pi version command failed.")
|
|
4061
|
+
);
|
|
4062
|
+
return;
|
|
4063
|
+
}
|
|
4064
|
+
try {
|
|
4065
|
+
resolveVersion(new TextDecoder("utf-8", { fatal: true }).decode(Buffer.concat(chunks)));
|
|
4066
|
+
} catch {
|
|
4067
|
+
rejectVersion(
|
|
4068
|
+
new ExternalPiResolutionError(
|
|
4069
|
+
"pi_version_unavailable",
|
|
4070
|
+
"Pi version command returned invalid UTF-8."
|
|
4071
|
+
)
|
|
4072
|
+
);
|
|
4073
|
+
}
|
|
4074
|
+
});
|
|
4075
|
+
});
|
|
3759
4076
|
}
|
|
3760
|
-
function
|
|
3761
|
-
|
|
4077
|
+
function parseVersion(output) {
|
|
4078
|
+
const match = /^(?:pi\s+)?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\s*$/i.exec(output);
|
|
4079
|
+
if (match?.[1] === void 0) {
|
|
4080
|
+
throw new ExternalPiResolutionError(
|
|
4081
|
+
"pi_version_unavailable",
|
|
4082
|
+
"Pi version command returned an invalid version."
|
|
4083
|
+
);
|
|
4084
|
+
}
|
|
4085
|
+
return match[1];
|
|
3762
4086
|
}
|
|
3763
4087
|
|
|
3764
|
-
//
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
}
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
}
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
}
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
result[key] = Visit(value[key]);
|
|
4088
|
+
// src/platform/client/start-runtime.ts
|
|
4089
|
+
import { execFile, spawn as spawn2 } from "node:child_process";
|
|
4090
|
+
import { access as access2, readFile as readFile3 } from "node:fs/promises";
|
|
4091
|
+
import { homedir as homedir2 } from "node:os";
|
|
4092
|
+
import { dirname as dirname2, join as join5, resolve as resolve5 } from "node:path";
|
|
4093
|
+
import { fileURLToPath } from "node:url";
|
|
4094
|
+
import { promisify } from "node:util";
|
|
4095
|
+
|
|
4096
|
+
// src/platform/shared/runtime-ownership.ts
|
|
4097
|
+
import { lstat } from "node:fs/promises";
|
|
4098
|
+
import { createConnection } from "node:net";
|
|
4099
|
+
var RuntimeOwnershipBlockedError = class extends Error {
|
|
4100
|
+
code = "runtime_upgrade_deferred";
|
|
4101
|
+
constructor(message) {
|
|
4102
|
+
super(message);
|
|
4103
|
+
this.name = "RuntimeOwnershipBlockedError";
|
|
3781
4104
|
}
|
|
3782
|
-
|
|
3783
|
-
|
|
4105
|
+
};
|
|
4106
|
+
async function inspectControlSocketOwnership(socketPath, probe = probeControlSocket) {
|
|
4107
|
+
const stats = await lstat(socketPath).catch((error) => {
|
|
4108
|
+
if (error.code === "ENOENT") return null;
|
|
4109
|
+
throw error;
|
|
4110
|
+
});
|
|
4111
|
+
if (stats === null) return "absent";
|
|
4112
|
+
if (!stats.isSocket()) {
|
|
4113
|
+
throw new RuntimeOwnershipBlockedError(
|
|
4114
|
+
`Refusing to replace non-socket pi-fleet control path ${socketPath}`
|
|
4115
|
+
);
|
|
3784
4116
|
}
|
|
3785
|
-
return
|
|
3786
|
-
}
|
|
3787
|
-
function Visit(value) {
|
|
3788
|
-
return IsArray(value) ? ArrayType(value) : IsDate(value) ? DateType(value) : IsUint8Array(value) ? Uint8ArrayType(value) : IsRegExp(value) ? RegExpType(value) : IsObject(value) ? ObjectType(value) : value;
|
|
3789
|
-
}
|
|
3790
|
-
function Clone(value) {
|
|
3791
|
-
return Visit(value);
|
|
4117
|
+
return probe(socketPath);
|
|
3792
4118
|
}
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
4119
|
+
function probeControlSocket(socketPath) {
|
|
4120
|
+
return new Promise((resolveProbe) => {
|
|
4121
|
+
const socket = createConnection(socketPath);
|
|
4122
|
+
let settled = false;
|
|
4123
|
+
const settle = (result) => {
|
|
4124
|
+
if (settled) return;
|
|
4125
|
+
settled = true;
|
|
4126
|
+
clearTimeout(timer);
|
|
4127
|
+
socket.destroy();
|
|
4128
|
+
resolveProbe(result);
|
|
4129
|
+
};
|
|
4130
|
+
const timer = setTimeout(() => settle("uncertain"), 200);
|
|
4131
|
+
socket.once("connect", () => settle("responsive"));
|
|
4132
|
+
socket.once("error", (error) => {
|
|
4133
|
+
settle(error.code === "ECONNREFUSED" || error.code === "ENOENT" ? "stale" : "uncertain");
|
|
4134
|
+
});
|
|
4135
|
+
});
|
|
3797
4136
|
}
|
|
3798
4137
|
|
|
3799
|
-
//
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
}
|
|
3803
|
-
function IsArray2(value) {
|
|
3804
|
-
return globalThis.Array.isArray(value) && !globalThis.ArrayBuffer.isView(value);
|
|
3805
|
-
}
|
|
3806
|
-
function IsUndefined2(value) {
|
|
3807
|
-
return value === void 0;
|
|
3808
|
-
}
|
|
3809
|
-
function IsNumber2(value) {
|
|
3810
|
-
return typeof value === "number";
|
|
3811
|
-
}
|
|
4138
|
+
// src/platform/install/runtime-release.ts
|
|
4139
|
+
import { createHash as createHash3, randomUUID } from "node:crypto";
|
|
4140
|
+
import { chmod, cp, lstat as lstat3, mkdir, readFile as readFile2, rename, rm, writeFile } from "node:fs/promises";
|
|
4141
|
+
import { join as join3, posix, resolve as resolve3, sep as sep2 } from "node:path";
|
|
3812
4142
|
|
|
3813
|
-
//
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
4143
|
+
// src/platform/install/tree-integrity.ts
|
|
4144
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
4145
|
+
import { lstat as lstat2, readFile, readdir, realpath as realpath2, stat as stat2 } from "node:fs/promises";
|
|
4146
|
+
import { join as join2, relative, resolve as resolve2, sep } from "node:path";
|
|
4147
|
+
async function hashDirectoryTree(root, manifestPath) {
|
|
4148
|
+
const resolvedRoot = resolve2(root);
|
|
4149
|
+
const entries = await collectFiles(resolvedRoot, resolvedRoot);
|
|
4150
|
+
const hash = createHash2("sha256");
|
|
4151
|
+
let bytes = 0;
|
|
4152
|
+
for (const entry of entries) {
|
|
4153
|
+
const contents = await readFile(entry.absolutePath);
|
|
4154
|
+
bytes += contents.length;
|
|
4155
|
+
hash.update(entry.relativePath);
|
|
4156
|
+
hash.update("\0");
|
|
4157
|
+
hash.update(String(contents.length));
|
|
4158
|
+
hash.update("\0");
|
|
4159
|
+
hash.update(contents);
|
|
4160
|
+
hash.update("\0");
|
|
3823
4161
|
}
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
4162
|
+
return {
|
|
4163
|
+
path: manifestPath,
|
|
4164
|
+
files: entries.length,
|
|
4165
|
+
bytes,
|
|
4166
|
+
sha256: hash.digest("hex")
|
|
4167
|
+
};
|
|
4168
|
+
}
|
|
4169
|
+
async function collectFiles(root, directory) {
|
|
4170
|
+
const output = [];
|
|
4171
|
+
for (const name of (await readdir(directory)).sort()) {
|
|
4172
|
+
const absolutePath = join2(directory, name);
|
|
4173
|
+
const linkInfo = await lstat2(absolutePath);
|
|
4174
|
+
const info = linkInfo.isSymbolicLink() ? await stat2(absolutePath) : linkInfo;
|
|
4175
|
+
if (info.isDirectory()) {
|
|
4176
|
+
if (linkInfo.isSymbolicLink()) {
|
|
4177
|
+
throw new Error(`Runtime dependency tree contains a directory symlink: ${absolutePath}`);
|
|
4178
|
+
}
|
|
4179
|
+
output.push(...await collectFiles(root, absolutePath));
|
|
4180
|
+
continue;
|
|
4181
|
+
}
|
|
4182
|
+
if (!info.isFile()) {
|
|
4183
|
+
throw new Error(`Runtime dependency tree contains an unsupported entry: ${absolutePath}`);
|
|
4184
|
+
}
|
|
4185
|
+
if (linkInfo.isSymbolicLink()) {
|
|
4186
|
+
const target = await realpath2(absolutePath);
|
|
4187
|
+
if (target !== root && !target.startsWith(`${root}${sep}`)) {
|
|
4188
|
+
throw new Error(
|
|
4189
|
+
`Runtime dependency tree contains an external file symlink: ${absolutePath}`
|
|
4190
|
+
);
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
const relativePath = relative(root, absolutePath).split(sep).join("/");
|
|
4194
|
+
if (relativePath.length === 0 || relativePath.startsWith("../")) {
|
|
4195
|
+
throw new Error(`Runtime dependency path escapes its root: ${absolutePath}`);
|
|
4196
|
+
}
|
|
4197
|
+
output.push({ absolutePath, relativePath });
|
|
3828
4198
|
}
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
4199
|
+
return output.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
4200
|
+
}
|
|
4201
|
+
|
|
4202
|
+
// src/platform/install/runtime-release.ts
|
|
4203
|
+
var requiredRuntimeArtifacts = /* @__PURE__ */ new Set([
|
|
4204
|
+
"package.json",
|
|
4205
|
+
"bin/pifleet.mjs",
|
|
4206
|
+
"bin/pifleet-runtime.mjs",
|
|
4207
|
+
"dist/cli.mjs",
|
|
4208
|
+
"dist/runtime.mjs",
|
|
4209
|
+
"dist/journal-sqlite-worker.mjs",
|
|
4210
|
+
"dist/client.mjs",
|
|
4211
|
+
"dist/client-meta.json",
|
|
4212
|
+
"dist/client/index.d.ts",
|
|
4213
|
+
"dist/client/sdk-facade.d.ts",
|
|
4214
|
+
"dist/client/contracts.d.ts"
|
|
4215
|
+
]);
|
|
4216
|
+
var dependencyTreePath = "node_modules";
|
|
4217
|
+
async function materializeRuntime(options) {
|
|
4218
|
+
const sourceRoot = resolve3(options.sourceRoot);
|
|
4219
|
+
const manifestBytes = await readFile2(join3(sourceRoot, "dist", "runtime-manifest.json"));
|
|
4220
|
+
const sourceManifest = await parseRuntimeManifest(manifestBytes, sourceRoot);
|
|
4221
|
+
if (sourceManifest.closure !== void 0) {
|
|
4222
|
+
await verifyRuntime(sourceRoot);
|
|
4223
|
+
return sourceRoot;
|
|
3832
4224
|
}
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
4225
|
+
await verifyRuntimeFiles(sourceRoot, sourceManifest);
|
|
4226
|
+
await verifyDependencyIdentities(sourceRoot, sourceManifest.dependencies);
|
|
4227
|
+
const sourceTreeRoot = resolveInside(sourceRoot, dependencyTreePath);
|
|
4228
|
+
const sourceTreeBefore = await hashDirectoryTree(sourceTreeRoot, dependencyTreePath);
|
|
4229
|
+
const sourceManifestSha256 = createHash3("sha256").update(manifestBytes).digest("hex");
|
|
4230
|
+
const materializedManifest = {
|
|
4231
|
+
...sourceManifest,
|
|
4232
|
+
closure: { sourceManifestSha256, tree: sourceTreeBefore }
|
|
4233
|
+
};
|
|
4234
|
+
const materializedManifestBytes = serializeManifest(materializedManifest);
|
|
4235
|
+
const closureHash = createHash3("sha256").update(sourceManifestSha256).update("\0").update(JSON.stringify(sourceTreeBefore)).digest("hex").slice(0, 16);
|
|
4236
|
+
const applicationRoot = resolve3(options.applicationRoot);
|
|
4237
|
+
await ensurePrivateDirectory(applicationRoot);
|
|
4238
|
+
const releasesRoot = join3(applicationRoot, "releases");
|
|
4239
|
+
await ensurePrivateDirectory(releasesRoot);
|
|
4240
|
+
const destination = join3(releasesRoot, `${sourceManifest.package.version}-${closureHash}`);
|
|
4241
|
+
if (await pathExists(destination)) {
|
|
4242
|
+
await verifyExpectedRuntime(destination, materializedManifest, materializedManifestBytes);
|
|
4243
|
+
return destination;
|
|
3836
4244
|
}
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
4245
|
+
const staging = join3(releasesRoot, `.staging-${randomUUID()}`);
|
|
4246
|
+
await mkdir(staging, { mode: 448 });
|
|
4247
|
+
try {
|
|
4248
|
+
await cp(join3(sourceRoot, "dist"), join3(staging, "dist"), {
|
|
4249
|
+
recursive: true,
|
|
4250
|
+
dereference: true
|
|
4251
|
+
});
|
|
4252
|
+
await cp(join3(sourceRoot, "bin"), join3(staging, "bin"), {
|
|
4253
|
+
recursive: true,
|
|
4254
|
+
dereference: true
|
|
4255
|
+
});
|
|
4256
|
+
await cp(join3(sourceRoot, "package.json"), join3(staging, "package.json"));
|
|
4257
|
+
await cp(sourceTreeRoot, join3(staging, dependencyTreePath), {
|
|
4258
|
+
recursive: true,
|
|
4259
|
+
dereference: true
|
|
4260
|
+
});
|
|
4261
|
+
await options.hooks?.afterDependencyCopy?.();
|
|
4262
|
+
const stagedTree = await hashDirectoryTree(
|
|
4263
|
+
join3(staging, dependencyTreePath),
|
|
4264
|
+
dependencyTreePath
|
|
4265
|
+
);
|
|
4266
|
+
assertSameTree(sourceTreeBefore, stagedTree, "copied dependency closure");
|
|
4267
|
+
const sourceTreeAfter = await hashDirectoryTree(sourceTreeRoot, dependencyTreePath);
|
|
4268
|
+
assertSameTree(sourceTreeBefore, sourceTreeAfter, "source dependency closure");
|
|
4269
|
+
await writeFile(join3(staging, "dist", "runtime-manifest.json"), materializedManifestBytes);
|
|
4270
|
+
await verifyExpectedRuntime(staging, materializedManifest, materializedManifestBytes);
|
|
4271
|
+
await chmod(staging, 448);
|
|
4272
|
+
try {
|
|
4273
|
+
await rename(staging, destination);
|
|
4274
|
+
} catch (error) {
|
|
4275
|
+
if (!isDestinationRace(error) || !await pathExists(destination)) throw error;
|
|
4276
|
+
await verifyExpectedRuntime(destination, materializedManifest, materializedManifestBytes);
|
|
4277
|
+
}
|
|
4278
|
+
return destination;
|
|
4279
|
+
} finally {
|
|
4280
|
+
await rm(staging, { recursive: true, force: true });
|
|
3841
4281
|
}
|
|
3842
|
-
TypeSystemPolicy2.IsVoidLike = IsVoidLike;
|
|
3843
|
-
})(TypeSystemPolicy || (TypeSystemPolicy = {}));
|
|
3844
|
-
|
|
3845
|
-
// node_modules/@sinclair/typebox/build/esm/type/create/immutable.mjs
|
|
3846
|
-
function ImmutableArray(value) {
|
|
3847
|
-
return globalThis.Object.freeze(value).map((value2) => Immutable(value2));
|
|
3848
4282
|
}
|
|
3849
|
-
function
|
|
3850
|
-
|
|
4283
|
+
async function verifyRuntime(root) {
|
|
4284
|
+
const resolvedRoot = resolve3(root);
|
|
4285
|
+
const manifestBytes = await readFile2(join3(resolvedRoot, "dist", "runtime-manifest.json"));
|
|
4286
|
+
const manifest = await parseRuntimeManifest(manifestBytes, resolvedRoot);
|
|
4287
|
+
if (manifest.closure === void 0) {
|
|
4288
|
+
throw new Error("Runtime release manifest is missing its materialized closure");
|
|
4289
|
+
}
|
|
4290
|
+
await verifyRuntimeFiles(resolvedRoot, manifest);
|
|
4291
|
+
await verifyDependencyIdentities(resolvedRoot, manifest.dependencies);
|
|
4292
|
+
const actualTree = await hashDirectoryTree(
|
|
4293
|
+
resolveInside(resolvedRoot, dependencyTreePath),
|
|
4294
|
+
dependencyTreePath
|
|
4295
|
+
);
|
|
4296
|
+
assertSameTree(manifest.closure.tree, actualTree, "materialized dependency closure");
|
|
3851
4297
|
}
|
|
3852
|
-
function
|
|
3853
|
-
|
|
4298
|
+
async function verifyExpectedRuntime(root, expected, expectedBytes) {
|
|
4299
|
+
const manifestPath = join3(root, "dist", "runtime-manifest.json");
|
|
4300
|
+
const actualBytes = await readFile2(manifestPath);
|
|
4301
|
+
if (!actualBytes.equals(expectedBytes)) {
|
|
4302
|
+
throw new Error("Materialized runtime manifest does not match the expected closure");
|
|
4303
|
+
}
|
|
4304
|
+
const actual = await parseRuntimeManifest(actualBytes, root);
|
|
4305
|
+
if (actual.closure === void 0 || expected.closure === void 0) {
|
|
4306
|
+
throw new Error("Materialized runtime manifest is missing its closure");
|
|
4307
|
+
}
|
|
4308
|
+
await verifyRuntimeFiles(root, actual);
|
|
4309
|
+
await verifyDependencyIdentities(root, actual.dependencies);
|
|
4310
|
+
const actualTree = await hashDirectoryTree(
|
|
4311
|
+
resolveInside(root, dependencyTreePath),
|
|
4312
|
+
dependencyTreePath
|
|
4313
|
+
);
|
|
4314
|
+
assertSameTree(expected.closure.tree, actualTree, "materialized dependency closure");
|
|
3854
4315
|
}
|
|
3855
|
-
function
|
|
3856
|
-
|
|
4316
|
+
async function verifyRuntimeFiles(root, manifest) {
|
|
4317
|
+
for (const file of manifest.files) {
|
|
4318
|
+
const path2 = resolveInside(root, file.path);
|
|
4319
|
+
const info = await lstat3(path2);
|
|
4320
|
+
if (info.isSymbolicLink()) {
|
|
4321
|
+
throw new Error(`Runtime artifact ${file.path} must not be a symbolic link`);
|
|
4322
|
+
}
|
|
4323
|
+
if (!info.isFile() || info.size !== file.bytes) {
|
|
4324
|
+
throw new Error(`Runtime artifact ${file.path} has changed`);
|
|
4325
|
+
}
|
|
4326
|
+
const hash = createHash3("sha256").update(await readFile2(path2)).digest("hex");
|
|
4327
|
+
if (hash !== file.sha256) {
|
|
4328
|
+
throw new Error(`Runtime artifact ${file.path} failed verification`);
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
3857
4331
|
}
|
|
3858
|
-
function
|
|
3859
|
-
const
|
|
3860
|
-
|
|
3861
|
-
|
|
4332
|
+
async function verifyDependencyIdentities(root, dependencies) {
|
|
4333
|
+
const nodeModules = resolveInside(root, dependencyTreePath);
|
|
4334
|
+
const modulesInfo = await lstat3(nodeModules);
|
|
4335
|
+
if (!modulesInfo.isDirectory() || modulesInfo.isSymbolicLink()) {
|
|
4336
|
+
throw new Error("Runtime dependency closure must be a regular directory");
|
|
3862
4337
|
}
|
|
3863
|
-
for (const
|
|
3864
|
-
|
|
4338
|
+
for (const dependency of dependencies) {
|
|
4339
|
+
const packageRoot = resolveInside(root, dependency.path);
|
|
4340
|
+
const packageInfo = await lstat3(packageRoot);
|
|
4341
|
+
if (!packageInfo.isDirectory() || packageInfo.isSymbolicLink()) {
|
|
4342
|
+
throw new Error(`Runtime dependency ${dependency.name} must be a regular directory`);
|
|
4343
|
+
}
|
|
4344
|
+
const packageJsonPath = join3(packageRoot, "package.json");
|
|
4345
|
+
const packageJsonInfo = await lstat3(packageJsonPath);
|
|
4346
|
+
if (!packageJsonInfo.isFile() || packageJsonInfo.isSymbolicLink()) {
|
|
4347
|
+
throw new Error(`Runtime dependency ${dependency.name} has an unsafe package.json`);
|
|
4348
|
+
}
|
|
4349
|
+
const identity = await readPackageMetadata(packageRoot);
|
|
4350
|
+
if (identity.name !== dependency.name || identity.version !== dependency.version) {
|
|
4351
|
+
throw new Error(`Runtime dependency ${dependency.name} has an unexpected identity`);
|
|
4352
|
+
}
|
|
3865
4353
|
}
|
|
3866
|
-
return globalThis.Object.freeze(result);
|
|
3867
|
-
}
|
|
3868
|
-
function Immutable(value) {
|
|
3869
|
-
return IsArray(value) ? ImmutableArray(value) : IsDate(value) ? ImmutableDate(value) : IsUint8Array(value) ? ImmutableUint8Array(value) : IsRegExp(value) ? ImmutableRegExp(value) : IsObject(value) ? ImmutableObject(value) : value;
|
|
3870
4354
|
}
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
return Immutable(result);
|
|
3878
|
-
case "clone":
|
|
3879
|
-
return Clone(result);
|
|
3880
|
-
default:
|
|
3881
|
-
return result;
|
|
4355
|
+
async function parseRuntimeManifest(bytes, root) {
|
|
4356
|
+
let candidate;
|
|
4357
|
+
try {
|
|
4358
|
+
candidate = JSON.parse(bytes.toString("utf8"));
|
|
4359
|
+
} catch {
|
|
4360
|
+
throw new Error("Runtime manifest is not valid JSON");
|
|
3882
4361
|
}
|
|
4362
|
+
await validateRuntimeManifest(candidate, root);
|
|
4363
|
+
return candidate;
|
|
3883
4364
|
}
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
4365
|
+
async function validateRuntimeManifest(candidate, root) {
|
|
4366
|
+
if (!isRecord(candidate) || candidate.schemaVersion !== 4) {
|
|
4367
|
+
throw new Error("Runtime manifest has an unsupported schema version");
|
|
4368
|
+
}
|
|
4369
|
+
if (!isRecord(candidate.package) || typeof candidate.package.name !== "string" || typeof candidate.package.version !== "string" || !isRecord(candidate.piRuntime) || candidate.piRuntime.mode !== "external" || !isRuntimeContract(candidate.runtime)) {
|
|
4370
|
+
throw new Error("Runtime manifest has an invalid package identity");
|
|
4371
|
+
}
|
|
4372
|
+
const packageMetadata = await readPackageMetadata(root, true);
|
|
4373
|
+
if (candidate.package.name !== packageMetadata.name || candidate.package.version !== packageMetadata.version || packageMetadata.runtime === void 0 || !sameRuntimeContract(candidate.runtime, packageMetadata.runtime) || packageMetadata.clientExport === void 0) {
|
|
4374
|
+
throw new Error("Runtime manifest package identity does not match package.json");
|
|
4375
|
+
}
|
|
4376
|
+
if (!Array.isArray(candidate.files) || !Array.isArray(candidate.dependencies)) {
|
|
4377
|
+
throw new Error("Runtime manifest has invalid artifact lists");
|
|
4378
|
+
}
|
|
4379
|
+
const filePaths = /* @__PURE__ */ new Set();
|
|
4380
|
+
for (const file of candidate.files) {
|
|
4381
|
+
if (!isRecord(file) || !isManifestPath(file.path) || !isValidSize(file.bytes) || !isSha256(file.sha256)) {
|
|
4382
|
+
throw new Error("Runtime manifest contains an invalid artifact");
|
|
4383
|
+
}
|
|
4384
|
+
if (filePaths.has(file.path)) {
|
|
4385
|
+
throw new Error(`Runtime manifest has duplicate path ${file.path}`);
|
|
4386
|
+
}
|
|
4387
|
+
filePaths.add(file.path);
|
|
4388
|
+
}
|
|
4389
|
+
for (const required of requiredRuntimeArtifacts) {
|
|
4390
|
+
if (!filePaths.has(required)) {
|
|
4391
|
+
throw new Error(`Runtime manifest is missing required artifact ${required}`);
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
4394
|
+
const dependencyPaths = /* @__PURE__ */ new Set();
|
|
4395
|
+
const dependencyNames = /* @__PURE__ */ new Set();
|
|
4396
|
+
for (const dependency of candidate.dependencies) {
|
|
4397
|
+
if (!isRecord(dependency) || !isManifestPath(dependency.path) || typeof dependency.name !== "string" || dependency.name.length === 0 || typeof dependency.version !== "string" || dependency.version.length === 0 || dependency.path !== `node_modules/${dependency.name}`) {
|
|
4398
|
+
throw new Error("Runtime manifest contains an invalid dependency declaration");
|
|
4399
|
+
}
|
|
4400
|
+
if (dependencyPaths.has(dependency.path) || dependencyNames.has(dependency.name)) {
|
|
4401
|
+
throw new Error(`Runtime manifest has duplicate dependency ${dependency.name}`);
|
|
4402
|
+
}
|
|
4403
|
+
dependencyPaths.add(dependency.path);
|
|
4404
|
+
dependencyNames.add(dependency.name);
|
|
4405
|
+
}
|
|
4406
|
+
const expectedDependencies = packageMetadata.dependencies;
|
|
4407
|
+
if (dependencyNames.size !== Object.keys(expectedDependencies).length || [...dependencyNames].some(
|
|
4408
|
+
(name) => expectedDependencies[name] !== candidate.dependencies.find(
|
|
4409
|
+
(dependency) => dependency.name === name
|
|
4410
|
+
)?.version
|
|
4411
|
+
)) {
|
|
4412
|
+
throw new Error("Runtime manifest dependencies do not match package.json");
|
|
4413
|
+
}
|
|
4414
|
+
for (const filePath of filePaths) {
|
|
4415
|
+
for (const dependencyPath of dependencyPaths) {
|
|
4416
|
+
if (filePath === dependencyPath || filePath.startsWith(`${dependencyPath}/`) || dependencyPath.startsWith(`${filePath}/`)) {
|
|
4417
|
+
throw new Error(`Runtime manifest has overlapping paths ${filePath} and ${dependencyPath}`);
|
|
4418
|
+
}
|
|
4419
|
+
}
|
|
4420
|
+
}
|
|
4421
|
+
if (candidate.closure !== void 0) {
|
|
4422
|
+
if (!isRecord(candidate.closure) || !isSha256(candidate.closure.sourceManifestSha256) || !isTreeIntegrity(candidate.closure.tree) || candidate.closure.tree.path !== dependencyTreePath) {
|
|
4423
|
+
throw new Error("Runtime manifest contains an invalid materialized closure");
|
|
4424
|
+
}
|
|
3889
4425
|
}
|
|
3890
|
-
};
|
|
3891
|
-
|
|
3892
|
-
// node_modules/@sinclair/typebox/build/esm/type/symbols/symbols.mjs
|
|
3893
|
-
var TransformKind = Symbol.for("TypeBox.Transform");
|
|
3894
|
-
var ReadonlyKind = Symbol.for("TypeBox.Readonly");
|
|
3895
|
-
var OptionalKind = Symbol.for("TypeBox.Optional");
|
|
3896
|
-
var Hint = Symbol.for("TypeBox.Hint");
|
|
3897
|
-
var Kind = Symbol.for("TypeBox.Kind");
|
|
3898
|
-
|
|
3899
|
-
// node_modules/@sinclair/typebox/build/esm/type/guard/kind.mjs
|
|
3900
|
-
function IsReadonly(value) {
|
|
3901
|
-
return IsObject(value) && value[ReadonlyKind] === "Readonly";
|
|
3902
|
-
}
|
|
3903
|
-
function IsOptional(value) {
|
|
3904
|
-
return IsObject(value) && value[OptionalKind] === "Optional";
|
|
3905
|
-
}
|
|
3906
|
-
function IsAny(value) {
|
|
3907
|
-
return IsKindOf(value, "Any");
|
|
3908
|
-
}
|
|
3909
|
-
function IsArgument(value) {
|
|
3910
|
-
return IsKindOf(value, "Argument");
|
|
3911
|
-
}
|
|
3912
|
-
function IsArray3(value) {
|
|
3913
|
-
return IsKindOf(value, "Array");
|
|
3914
|
-
}
|
|
3915
|
-
function IsAsyncIterator2(value) {
|
|
3916
|
-
return IsKindOf(value, "AsyncIterator");
|
|
3917
4426
|
}
|
|
3918
|
-
function
|
|
3919
|
-
|
|
4427
|
+
async function readPackageMetadata(root, requireRuntimeContract = false) {
|
|
4428
|
+
let candidate;
|
|
4429
|
+
try {
|
|
4430
|
+
candidate = JSON.parse(await readFile2(join3(root, "package.json"), "utf8"));
|
|
4431
|
+
} catch {
|
|
4432
|
+
throw new Error("Runtime package.json is not valid JSON");
|
|
4433
|
+
}
|
|
4434
|
+
if (!isRecord(candidate) || typeof candidate.name !== "string" || typeof candidate.version !== "string" || requireRuntimeContract && !isRuntimeContract(candidate.pifleet) || candidate.dependencies !== void 0 && !isRecord(candidate.dependencies) || isRecord(candidate.dependencies) && Object.values(candidate.dependencies).some((version) => typeof version !== "string")) {
|
|
4435
|
+
throw new Error("Runtime package.json has invalid package metadata");
|
|
4436
|
+
}
|
|
4437
|
+
const clientExport = isRecord(candidate.exports) ? candidate.exports["./client"] : void 0;
|
|
4438
|
+
return {
|
|
4439
|
+
name: candidate.name,
|
|
4440
|
+
version: candidate.version,
|
|
4441
|
+
...isRuntimeContract(candidate.pifleet) ? { runtime: candidate.pifleet } : {},
|
|
4442
|
+
...isRecord(clientExport) && clientExport.types === "./dist/client/index.d.ts" && clientExport.import === "./dist/client.mjs" ? {
|
|
4443
|
+
clientExport: {
|
|
4444
|
+
types: "./dist/client/index.d.ts",
|
|
4445
|
+
import: "./dist/client.mjs"
|
|
4446
|
+
}
|
|
4447
|
+
} : {},
|
|
4448
|
+
dependencies: isRecord(candidate.dependencies) ? candidate.dependencies : {}
|
|
4449
|
+
};
|
|
3920
4450
|
}
|
|
3921
|
-
function
|
|
3922
|
-
return
|
|
4451
|
+
function serializeManifest(manifest) {
|
|
4452
|
+
return Buffer.from(`${JSON.stringify(manifest, null, 2)}
|
|
4453
|
+
`);
|
|
3923
4454
|
}
|
|
3924
|
-
function
|
|
3925
|
-
|
|
4455
|
+
function assertSameTree(expected, actual, label) {
|
|
4456
|
+
if (expected.path !== actual.path || expected.files !== actual.files || expected.bytes !== actual.bytes || expected.sha256 !== actual.sha256) {
|
|
4457
|
+
throw new Error(`Runtime ${label} changed during materialization`);
|
|
4458
|
+
}
|
|
3926
4459
|
}
|
|
3927
|
-
function
|
|
3928
|
-
|
|
4460
|
+
function resolveInside(root, path2) {
|
|
4461
|
+
if (!isManifestPath(path2)) throw new Error(`Runtime manifest contains an unsafe path ${path2}`);
|
|
4462
|
+
const resolved = resolve3(root, path2);
|
|
4463
|
+
if (!resolved.startsWith(`${root}${sep2}`)) {
|
|
4464
|
+
throw new Error(`Runtime manifest contains an unsafe path ${path2}`);
|
|
4465
|
+
}
|
|
4466
|
+
return resolved;
|
|
3929
4467
|
}
|
|
3930
|
-
function
|
|
3931
|
-
return
|
|
4468
|
+
function isRecord(value) {
|
|
4469
|
+
return typeof value === "object" && value !== null;
|
|
3932
4470
|
}
|
|
3933
|
-
function
|
|
3934
|
-
return
|
|
4471
|
+
function isRuntimeContract(value) {
|
|
4472
|
+
return isRecord(value) && value.protocolVersion === 3 && value.journalSchemaVersion === 3 && value.clientExport === "./client";
|
|
3935
4473
|
}
|
|
3936
|
-
function
|
|
3937
|
-
return
|
|
4474
|
+
function sameRuntimeContract(left, right) {
|
|
4475
|
+
return left.protocolVersion === right.protocolVersion && left.journalSchemaVersion === right.journalSchemaVersion && left.clientExport === right.clientExport;
|
|
3938
4476
|
}
|
|
3939
|
-
function
|
|
3940
|
-
return
|
|
4477
|
+
function isManifestPath(value) {
|
|
4478
|
+
return typeof value === "string" && value.length > 0 && !value.includes("\\") && !value.startsWith("/") && posix.normalize(value) === value && value.split("/").every((part) => part.length > 0 && part !== "." && part !== "..");
|
|
3941
4479
|
}
|
|
3942
|
-
function
|
|
3943
|
-
return
|
|
4480
|
+
function isValidSize(value) {
|
|
4481
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
3944
4482
|
}
|
|
3945
|
-
function
|
|
3946
|
-
return
|
|
4483
|
+
function isSha256(value) {
|
|
4484
|
+
return typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
|
|
3947
4485
|
}
|
|
3948
|
-
function
|
|
3949
|
-
return
|
|
4486
|
+
function isTreeIntegrity(value) {
|
|
4487
|
+
return isRecord(value) && isManifestPath(value.path) && isValidSize(value.files) && isValidSize(value.bytes) && isSha256(value.sha256);
|
|
3950
4488
|
}
|
|
3951
|
-
function
|
|
3952
|
-
|
|
4489
|
+
function isDestinationRace(error) {
|
|
4490
|
+
const code = error.code;
|
|
4491
|
+
return code === "EEXIST" || code === "ENOTEMPTY";
|
|
3953
4492
|
}
|
|
3954
|
-
function
|
|
3955
|
-
|
|
4493
|
+
async function ensurePrivateDirectory(path2) {
|
|
4494
|
+
await mkdir(path2, { recursive: true, mode: 448 });
|
|
4495
|
+
const info = await lstat3(path2);
|
|
4496
|
+
if (!info.isDirectory() || info.isSymbolicLink()) {
|
|
4497
|
+
throw new Error(`Refusing unsafe runtime release path ${path2}`);
|
|
4498
|
+
}
|
|
4499
|
+
if (typeof process.getuid === "function" && info.uid !== process.getuid()) {
|
|
4500
|
+
throw new Error(`Runtime release path ${path2} is not owned by the current user`);
|
|
4501
|
+
}
|
|
4502
|
+
await chmod(path2, 448);
|
|
3956
4503
|
}
|
|
3957
|
-
function
|
|
3958
|
-
|
|
4504
|
+
async function pathExists(path2) {
|
|
4505
|
+
try {
|
|
4506
|
+
await lstat3(path2);
|
|
4507
|
+
return true;
|
|
4508
|
+
} catch (error) {
|
|
4509
|
+
if (error.code === "ENOENT") return false;
|
|
4510
|
+
throw error;
|
|
4511
|
+
}
|
|
3959
4512
|
}
|
|
3960
|
-
|
|
3961
|
-
|
|
4513
|
+
|
|
4514
|
+
// src/platform/shared/paths.ts
|
|
4515
|
+
import { homedir, tmpdir } from "node:os";
|
|
4516
|
+
import { join as join4, resolve as resolve4 } from "node:path";
|
|
4517
|
+
function resolveApplicationRoot(env = process.env) {
|
|
4518
|
+
return env.PIFLEET_APPLICATION_ROOT ?? (process.platform === "darwin" ? join4(homedir(), "Library", "Application Support", "pi-fleet", "runtime") : join4(env.XDG_DATA_HOME ?? join4(homedir(), ".local", "share"), "pi-fleet"));
|
|
3962
4519
|
}
|
|
3963
|
-
function
|
|
3964
|
-
|
|
4520
|
+
function resolveFleetPaths(env = process.env) {
|
|
4521
|
+
const explicitRoot = env.PIFLEET_STATE_ROOT;
|
|
4522
|
+
if (explicitRoot !== void 0) {
|
|
4523
|
+
const root = resolve4(explicitRoot);
|
|
4524
|
+
return {
|
|
4525
|
+
runtimeRoot: root,
|
|
4526
|
+
stateRoot: root,
|
|
4527
|
+
socketPath: join4(root, "control.sock"),
|
|
4528
|
+
databasePath: join4(root, "fleet.sqlite")
|
|
4529
|
+
};
|
|
4530
|
+
}
|
|
4531
|
+
const runtimeRoot = join4(
|
|
4532
|
+
env.XDG_RUNTIME_DIR ?? tmpdir(),
|
|
4533
|
+
`pifleet-${process.getuid?.() ?? "user"}`
|
|
4534
|
+
);
|
|
4535
|
+
const stateRoot = process.platform === "darwin" ? join4(homedir(), "Library", "Application Support", "pi-fleet") : join4(env.XDG_STATE_HOME ?? join4(homedir(), ".local", "state"), "pi-fleet");
|
|
4536
|
+
return {
|
|
4537
|
+
runtimeRoot,
|
|
4538
|
+
stateRoot,
|
|
4539
|
+
socketPath: join4(runtimeRoot, "control.sock"),
|
|
4540
|
+
databasePath: join4(stateRoot, "fleet.sqlite")
|
|
4541
|
+
};
|
|
3965
4542
|
}
|
|
3966
|
-
|
|
3967
|
-
|
|
4543
|
+
|
|
4544
|
+
// src/platform/client/start-runtime.ts
|
|
4545
|
+
var execFileAsync = promisify(execFile);
|
|
4546
|
+
async function ensureRuntime(options) {
|
|
4547
|
+
const inspectOwnership = options.inspectOwnership ?? inspectControlSocketOwnership;
|
|
4548
|
+
const initialOwnership = await inspectOwnership(options.socketPath);
|
|
4549
|
+
if (initialOwnership === "responsive") return;
|
|
4550
|
+
assertRuntimeStartAllowed(initialOwnership, options.socketPath);
|
|
4551
|
+
let env = { ...process.env, ...options.env };
|
|
4552
|
+
const registered = env.PIFLEET_DISABLE_REGISTERED_SERVICE === "1" ? false : options.registeredRuntimeStarter !== void 0 ? await options.registeredRuntimeStarter(env) : await startRegisteredRuntime({
|
|
4553
|
+
env,
|
|
4554
|
+
...options.home === void 0 ? {} : { home: options.home }
|
|
4555
|
+
});
|
|
4556
|
+
if (!registered) {
|
|
4557
|
+
if (options.piInstallation !== void 0) {
|
|
4558
|
+
const installation = await options.piInstallation();
|
|
4559
|
+
if (installation !== null) {
|
|
4560
|
+
env = {
|
|
4561
|
+
...env,
|
|
4562
|
+
PIFLEET_PI_EXECUTABLE: installation.selectedPath,
|
|
4563
|
+
PIFLEET_PI_NODE: installation.nodePath
|
|
4564
|
+
};
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
const sourceRoot = options.sourceRoot ?? await findPackageRoot(fileURLToPath(import.meta.url));
|
|
4568
|
+
const release = await materializeRuntime({
|
|
4569
|
+
sourceRoot,
|
|
4570
|
+
applicationRoot: options.applicationRoot ?? resolveApplicationRoot(env)
|
|
4571
|
+
});
|
|
4572
|
+
const runtimePath = join5(release, "bin", "pifleet-runtime.mjs");
|
|
4573
|
+
const child = spawn2(process.execPath, [runtimePath], {
|
|
4574
|
+
detached: true,
|
|
4575
|
+
env,
|
|
4576
|
+
stdio: "ignore"
|
|
4577
|
+
});
|
|
4578
|
+
child.unref();
|
|
4579
|
+
}
|
|
4580
|
+
const deadline = Date.now() + (options.timeoutMs ?? 5e3);
|
|
4581
|
+
while (Date.now() < deadline) {
|
|
4582
|
+
const ownership = await inspectOwnership(options.socketPath);
|
|
4583
|
+
if (ownership === "responsive") return;
|
|
4584
|
+
if (ownership === "uncertain") {
|
|
4585
|
+
throw new RuntimeOwnershipBlockedError(
|
|
4586
|
+
`pi-fleet control socket ownership is uncertain for ${options.socketPath}`
|
|
4587
|
+
);
|
|
4588
|
+
}
|
|
4589
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, 25));
|
|
4590
|
+
}
|
|
4591
|
+
throw new Error(`pi-fleet runtime did not become ready at ${options.socketPath}`);
|
|
3968
4592
|
}
|
|
3969
|
-
function
|
|
3970
|
-
|
|
4593
|
+
function assertRuntimeStartAllowed(ownership, socketPath) {
|
|
4594
|
+
if (ownership === "uncertain") {
|
|
4595
|
+
throw new RuntimeOwnershipBlockedError(
|
|
4596
|
+
`pi-fleet control socket ownership is uncertain for ${socketPath}`
|
|
4597
|
+
);
|
|
4598
|
+
}
|
|
3971
4599
|
}
|
|
3972
|
-
function
|
|
3973
|
-
|
|
4600
|
+
async function startRegisteredRuntime(options) {
|
|
4601
|
+
const home = options.home ?? homedir2();
|
|
4602
|
+
if (process.platform === "linux") {
|
|
4603
|
+
const unit = join5(home, ".config", "systemd", "user", "pi-fleet.service");
|
|
4604
|
+
if (!await exists(unit)) return false;
|
|
4605
|
+
await assertRegisteredStateRoot(unit, "linux", options.env);
|
|
4606
|
+
await execFileAsync("systemctl", ["--user", "start", "pi-fleet.service"]);
|
|
4607
|
+
return true;
|
|
4608
|
+
}
|
|
4609
|
+
if (process.platform === "darwin") {
|
|
4610
|
+
const plist = join5(home, "Library", "LaunchAgents", "works.elpapi.pifleet.plist");
|
|
4611
|
+
if (!await exists(plist)) return false;
|
|
4612
|
+
await assertRegisteredStateRoot(plist, "darwin", options.env);
|
|
4613
|
+
const domain = `gui/${process.getuid?.() ?? 0}`;
|
|
4614
|
+
await execFileAsync("launchctl", ["kickstart", `${domain}/works.elpapi.pifleet`]);
|
|
4615
|
+
return true;
|
|
4616
|
+
}
|
|
4617
|
+
return false;
|
|
3974
4618
|
}
|
|
3975
|
-
function
|
|
3976
|
-
|
|
4619
|
+
function installedServiceStateRoot(contents, platform) {
|
|
4620
|
+
const encoded = platform === "linux" ? /^Environment=PIFLEET_STATE_ROOT=(.+)$/m.exec(contents)?.[1] : /<key>PIFLEET_STATE_ROOT<\/key><string>([^<]+)<\/string>/.exec(contents)?.[1];
|
|
4621
|
+
if (encoded === void 0) return void 0;
|
|
4622
|
+
if (platform === "linux") return encoded;
|
|
4623
|
+
return encoded.replaceAll("'", "'").replaceAll(""", '"').replaceAll(">", ">").replaceAll("<", "<").replaceAll("&", "&");
|
|
3977
4624
|
}
|
|
3978
|
-
|
|
3979
|
-
|
|
4625
|
+
var PiServiceMismatchError = class extends Error {
|
|
4626
|
+
code = "pi_service_mismatch";
|
|
4627
|
+
constructor(message) {
|
|
4628
|
+
super(message);
|
|
4629
|
+
this.name = "PiServiceMismatchError";
|
|
4630
|
+
}
|
|
4631
|
+
};
|
|
4632
|
+
async function assertRegisteredPiSelection(options) {
|
|
4633
|
+
const home = options.home ?? homedir2();
|
|
4634
|
+
const platform = process.platform;
|
|
4635
|
+
if (platform !== "linux" && platform !== "darwin") return;
|
|
4636
|
+
const path2 = platform === "linux" ? join5(home, ".config", "systemd", "user", "pi-fleet.service") : join5(home, "Library", "LaunchAgents", "works.elpapi.pifleet.plist");
|
|
4637
|
+
if (!await exists(path2)) return;
|
|
4638
|
+
const contents = await readFile3(path2, "utf8");
|
|
4639
|
+
const installed = installedServicePiExecutable(contents, platform);
|
|
4640
|
+
const installedNode = installedServicePiNode(contents, platform);
|
|
4641
|
+
if (installed === void 0 || installedNode === void 0 || resolve5(installed) !== resolve5(options.selectedPath) || resolve5(installedNode) !== resolve5(options.nodePath)) {
|
|
4642
|
+
throw new PiServiceMismatchError(
|
|
4643
|
+
`The installed pi-fleet service uses a different Pi executable or Node interpreter; repair it from the environment selecting ${options.selectedPath}.`
|
|
4644
|
+
);
|
|
4645
|
+
}
|
|
3980
4646
|
}
|
|
3981
|
-
function
|
|
3982
|
-
return
|
|
4647
|
+
function installedServicePiExecutable(contents, platform) {
|
|
4648
|
+
return installedServiceEnvironmentValue(contents, platform, "PIFLEET_PI_EXECUTABLE");
|
|
3983
4649
|
}
|
|
3984
|
-
function
|
|
3985
|
-
return
|
|
4650
|
+
function installedServicePiNode(contents, platform) {
|
|
4651
|
+
return installedServiceEnvironmentValue(contents, platform, "PIFLEET_PI_NODE");
|
|
3986
4652
|
}
|
|
3987
|
-
function
|
|
3988
|
-
|
|
4653
|
+
function installedServiceEnvironmentValue(contents, platform, key) {
|
|
4654
|
+
const encoded = platform === "linux" ? new RegExp(`Environment=(?:"${key}=([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|${key}=(.+))$`, "m").exec(contents)?.slice(1).find(Boolean) : new RegExp(`<key>${key}<\\/key><string>([^<]+)<\\/string>`).exec(contents)?.[1];
|
|
4655
|
+
if (encoded === void 0) return void 0;
|
|
4656
|
+
if (platform === "darwin") {
|
|
4657
|
+
return encoded.replaceAll("'", "'").replaceAll(""", '"').replaceAll(">", ">").replaceAll("<", "<").replaceAll("&", "&");
|
|
4658
|
+
}
|
|
4659
|
+
return encoded.replaceAll('\\"', '"').replaceAll("\\\\", "\\");
|
|
3989
4660
|
}
|
|
3990
|
-
function
|
|
3991
|
-
|
|
4661
|
+
async function assertRegisteredStateRoot(definitionPath, platform, env) {
|
|
4662
|
+
const installed = installedServiceStateRoot(await readFile3(definitionPath, "utf8"), platform);
|
|
4663
|
+
const requested = resolve5(resolveFleetPaths(env).stateRoot);
|
|
4664
|
+
if (installed === void 0) {
|
|
4665
|
+
if (env.PIFLEET_STATE_ROOT === void 0) return;
|
|
4666
|
+
throw new Error(
|
|
4667
|
+
`Registered pi-fleet service uses the default state root, but this command requested ${requested}. Run the pi-fleet installer with PIFLEET_STATE_ROOT=${requested} to repair the service, or omit the override.`
|
|
4668
|
+
);
|
|
4669
|
+
}
|
|
4670
|
+
if (resolve5(installed) !== requested) {
|
|
4671
|
+
throw new Error(
|
|
4672
|
+
`Registered pi-fleet service uses state root ${installed}, but this command requested ${requested}. Repair the service with the intended PIFLEET_STATE_ROOT before retrying.`
|
|
4673
|
+
);
|
|
4674
|
+
}
|
|
3992
4675
|
}
|
|
3993
|
-
function
|
|
3994
|
-
|
|
4676
|
+
async function findPackageRoot(modulePath) {
|
|
4677
|
+
let candidate = dirname2(modulePath);
|
|
4678
|
+
for (let depth = 0; depth < 6; depth += 1) {
|
|
4679
|
+
if (await exists(join5(candidate, "dist", "runtime-manifest.json"))) return candidate;
|
|
4680
|
+
const parent = dirname2(candidate);
|
|
4681
|
+
if (parent === candidate) break;
|
|
4682
|
+
candidate = parent;
|
|
4683
|
+
}
|
|
4684
|
+
throw new Error("Unable to locate the pi-fleet package runtime manifest.");
|
|
3995
4685
|
}
|
|
3996
|
-
function
|
|
3997
|
-
|
|
4686
|
+
async function exists(path2) {
|
|
4687
|
+
try {
|
|
4688
|
+
await access2(path2);
|
|
4689
|
+
return true;
|
|
4690
|
+
} catch {
|
|
4691
|
+
return false;
|
|
4692
|
+
}
|
|
3998
4693
|
}
|
|
3999
|
-
|
|
4000
|
-
|
|
4694
|
+
|
|
4695
|
+
// src/client/socket-fleet-client.ts
|
|
4696
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
4697
|
+
import { createConnection as createConnection2 } from "node:net";
|
|
4698
|
+
|
|
4699
|
+
// src/protocol/version.ts
|
|
4700
|
+
var PROTOCOL_VERSION = 3;
|
|
4701
|
+
var MAX_PROTOCOL_FRAME_BYTES = 1024 * 1024;
|
|
4702
|
+
|
|
4703
|
+
// src/protocol/jsonl.ts
|
|
4704
|
+
function readJsonLines(socket, onValue, onError, maxFrameBytes = MAX_PROTOCOL_FRAME_BYTES) {
|
|
4705
|
+
let buffer = Buffer.alloc(0);
|
|
4706
|
+
const onData = (chunk) => {
|
|
4707
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
4708
|
+
while (true) {
|
|
4709
|
+
const newline = buffer.indexOf(10);
|
|
4710
|
+
if (newline < 0) {
|
|
4711
|
+
if (buffer.length > maxFrameBytes) {
|
|
4712
|
+
onError(new Error("Protocol frame exceeds maximum size"));
|
|
4713
|
+
}
|
|
4714
|
+
return;
|
|
4715
|
+
}
|
|
4716
|
+
if (newline > maxFrameBytes) {
|
|
4717
|
+
onError(new Error("Protocol frame exceeds maximum size"));
|
|
4718
|
+
return;
|
|
4719
|
+
}
|
|
4720
|
+
const line = buffer.subarray(0, newline).toString("utf8").replace(/\r$/, "");
|
|
4721
|
+
buffer = buffer.subarray(newline + 1);
|
|
4722
|
+
if (line.length === 0) continue;
|
|
4723
|
+
try {
|
|
4724
|
+
onValue(JSON.parse(line));
|
|
4725
|
+
} catch {
|
|
4726
|
+
onError(new Error("Malformed JSON protocol frame"));
|
|
4727
|
+
return;
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
};
|
|
4731
|
+
socket.on("data", onData);
|
|
4732
|
+
return () => socket.off("data", onData);
|
|
4001
4733
|
}
|
|
4002
|
-
function
|
|
4003
|
-
return
|
|
4734
|
+
function writeJsonLine(socket, value) {
|
|
4735
|
+
return socket.write(`${JSON.stringify(value)}
|
|
4736
|
+
`);
|
|
4004
4737
|
}
|
|
4005
|
-
|
|
4006
|
-
|
|
4738
|
+
|
|
4739
|
+
// node_modules/@sinclair/typebox/build/esm/type/guard/value.mjs
|
|
4740
|
+
var value_exports = {};
|
|
4741
|
+
__export(value_exports, {
|
|
4742
|
+
HasPropertyKey: () => HasPropertyKey,
|
|
4743
|
+
IsArray: () => IsArray,
|
|
4744
|
+
IsAsyncIterator: () => IsAsyncIterator,
|
|
4745
|
+
IsBigInt: () => IsBigInt,
|
|
4746
|
+
IsBoolean: () => IsBoolean,
|
|
4747
|
+
IsDate: () => IsDate,
|
|
4748
|
+
IsFunction: () => IsFunction,
|
|
4749
|
+
IsIterator: () => IsIterator,
|
|
4750
|
+
IsNull: () => IsNull,
|
|
4751
|
+
IsNumber: () => IsNumber,
|
|
4752
|
+
IsObject: () => IsObject,
|
|
4753
|
+
IsRegExp: () => IsRegExp,
|
|
4754
|
+
IsString: () => IsString,
|
|
4755
|
+
IsSymbol: () => IsSymbol,
|
|
4756
|
+
IsUint8Array: () => IsUint8Array,
|
|
4757
|
+
IsUndefined: () => IsUndefined
|
|
4758
|
+
});
|
|
4759
|
+
function HasPropertyKey(value, key) {
|
|
4760
|
+
return key in value;
|
|
4007
4761
|
}
|
|
4008
|
-
function
|
|
4009
|
-
return
|
|
4762
|
+
function IsAsyncIterator(value) {
|
|
4763
|
+
return IsObject(value) && !IsArray(value) && !IsUint8Array(value) && Symbol.asyncIterator in value;
|
|
4010
4764
|
}
|
|
4011
|
-
function
|
|
4012
|
-
return
|
|
4765
|
+
function IsArray(value) {
|
|
4766
|
+
return Array.isArray(value);
|
|
4013
4767
|
}
|
|
4014
|
-
function
|
|
4015
|
-
return
|
|
4768
|
+
function IsBigInt(value) {
|
|
4769
|
+
return typeof value === "bigint";
|
|
4016
4770
|
}
|
|
4017
|
-
function
|
|
4018
|
-
return
|
|
4771
|
+
function IsBoolean(value) {
|
|
4772
|
+
return typeof value === "boolean";
|
|
4019
4773
|
}
|
|
4020
|
-
function
|
|
4021
|
-
return
|
|
4774
|
+
function IsDate(value) {
|
|
4775
|
+
return value instanceof globalThis.Date;
|
|
4022
4776
|
}
|
|
4023
|
-
function
|
|
4024
|
-
return
|
|
4777
|
+
function IsFunction(value) {
|
|
4778
|
+
return typeof value === "function";
|
|
4025
4779
|
}
|
|
4026
|
-
function
|
|
4027
|
-
return
|
|
4780
|
+
function IsIterator(value) {
|
|
4781
|
+
return IsObject(value) && !IsArray(value) && !IsUint8Array(value) && Symbol.iterator in value;
|
|
4782
|
+
}
|
|
4783
|
+
function IsNull(value) {
|
|
4784
|
+
return value === null;
|
|
4785
|
+
}
|
|
4786
|
+
function IsNumber(value) {
|
|
4787
|
+
return typeof value === "number";
|
|
4788
|
+
}
|
|
4789
|
+
function IsObject(value) {
|
|
4790
|
+
return typeof value === "object" && value !== null;
|
|
4791
|
+
}
|
|
4792
|
+
function IsRegExp(value) {
|
|
4793
|
+
return value instanceof globalThis.RegExp;
|
|
4794
|
+
}
|
|
4795
|
+
function IsString(value) {
|
|
4796
|
+
return typeof value === "string";
|
|
4797
|
+
}
|
|
4798
|
+
function IsSymbol(value) {
|
|
4799
|
+
return typeof value === "symbol";
|
|
4800
|
+
}
|
|
4801
|
+
function IsUint8Array(value) {
|
|
4802
|
+
return value instanceof globalThis.Uint8Array;
|
|
4803
|
+
}
|
|
4804
|
+
function IsUndefined(value) {
|
|
4805
|
+
return value === void 0;
|
|
4028
4806
|
}
|
|
4029
4807
|
|
|
4030
|
-
// node_modules/@sinclair/typebox/build/esm/type/
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
IsAny: () => IsAny2,
|
|
4034
|
-
IsArgument: () => IsArgument2,
|
|
4035
|
-
IsArray: () => IsArray4,
|
|
4036
|
-
IsAsyncIterator: () => IsAsyncIterator3,
|
|
4037
|
-
IsBigInt: () => IsBigInt3,
|
|
4038
|
-
IsBoolean: () => IsBoolean3,
|
|
4039
|
-
IsComputed: () => IsComputed2,
|
|
4040
|
-
IsConstructor: () => IsConstructor2,
|
|
4041
|
-
IsDate: () => IsDate3,
|
|
4042
|
-
IsFunction: () => IsFunction3,
|
|
4043
|
-
IsImport: () => IsImport,
|
|
4044
|
-
IsInteger: () => IsInteger2,
|
|
4045
|
-
IsIntersect: () => IsIntersect2,
|
|
4046
|
-
IsIterator: () => IsIterator3,
|
|
4047
|
-
IsKind: () => IsKind2,
|
|
4048
|
-
IsKindOf: () => IsKindOf2,
|
|
4049
|
-
IsLiteral: () => IsLiteral2,
|
|
4050
|
-
IsLiteralBoolean: () => IsLiteralBoolean,
|
|
4051
|
-
IsLiteralNumber: () => IsLiteralNumber,
|
|
4052
|
-
IsLiteralString: () => IsLiteralString,
|
|
4053
|
-
IsLiteralValue: () => IsLiteralValue2,
|
|
4054
|
-
IsMappedKey: () => IsMappedKey2,
|
|
4055
|
-
IsMappedResult: () => IsMappedResult2,
|
|
4056
|
-
IsNever: () => IsNever2,
|
|
4057
|
-
IsNot: () => IsNot2,
|
|
4058
|
-
IsNull: () => IsNull3,
|
|
4059
|
-
IsNumber: () => IsNumber4,
|
|
4060
|
-
IsObject: () => IsObject4,
|
|
4061
|
-
IsOptional: () => IsOptional2,
|
|
4062
|
-
IsPromise: () => IsPromise2,
|
|
4063
|
-
IsProperties: () => IsProperties,
|
|
4064
|
-
IsReadonly: () => IsReadonly2,
|
|
4065
|
-
IsRecord: () => IsRecord2,
|
|
4066
|
-
IsRecursive: () => IsRecursive,
|
|
4067
|
-
IsRef: () => IsRef2,
|
|
4068
|
-
IsRegExp: () => IsRegExp3,
|
|
4069
|
-
IsSchema: () => IsSchema2,
|
|
4070
|
-
IsString: () => IsString3,
|
|
4071
|
-
IsSymbol: () => IsSymbol3,
|
|
4072
|
-
IsTemplateLiteral: () => IsTemplateLiteral2,
|
|
4073
|
-
IsThis: () => IsThis2,
|
|
4074
|
-
IsTransform: () => IsTransform2,
|
|
4075
|
-
IsTuple: () => IsTuple2,
|
|
4076
|
-
IsUint8Array: () => IsUint8Array3,
|
|
4077
|
-
IsUndefined: () => IsUndefined4,
|
|
4078
|
-
IsUnion: () => IsUnion2,
|
|
4079
|
-
IsUnionLiteral: () => IsUnionLiteral,
|
|
4080
|
-
IsUnknown: () => IsUnknown2,
|
|
4081
|
-
IsUnsafe: () => IsUnsafe2,
|
|
4082
|
-
IsVoid: () => IsVoid2,
|
|
4083
|
-
TypeGuardUnknownTypeError: () => TypeGuardUnknownTypeError
|
|
4084
|
-
});
|
|
4085
|
-
var TypeGuardUnknownTypeError = class extends TypeBoxError {
|
|
4086
|
-
};
|
|
4087
|
-
var KnownTypes = [
|
|
4088
|
-
"Argument",
|
|
4089
|
-
"Any",
|
|
4090
|
-
"Array",
|
|
4091
|
-
"AsyncIterator",
|
|
4092
|
-
"BigInt",
|
|
4093
|
-
"Boolean",
|
|
4094
|
-
"Computed",
|
|
4095
|
-
"Constructor",
|
|
4096
|
-
"Date",
|
|
4097
|
-
"Enum",
|
|
4098
|
-
"Function",
|
|
4099
|
-
"Integer",
|
|
4100
|
-
"Intersect",
|
|
4101
|
-
"Iterator",
|
|
4102
|
-
"Literal",
|
|
4103
|
-
"MappedKey",
|
|
4104
|
-
"MappedResult",
|
|
4105
|
-
"Not",
|
|
4106
|
-
"Null",
|
|
4107
|
-
"Number",
|
|
4108
|
-
"Object",
|
|
4109
|
-
"Promise",
|
|
4110
|
-
"Record",
|
|
4111
|
-
"Ref",
|
|
4112
|
-
"RegExp",
|
|
4113
|
-
"String",
|
|
4114
|
-
"Symbol",
|
|
4115
|
-
"TemplateLiteral",
|
|
4116
|
-
"This",
|
|
4117
|
-
"Tuple",
|
|
4118
|
-
"Undefined",
|
|
4119
|
-
"Union",
|
|
4120
|
-
"Uint8Array",
|
|
4121
|
-
"Unknown",
|
|
4122
|
-
"Void"
|
|
4123
|
-
];
|
|
4124
|
-
function IsPattern(value) {
|
|
4125
|
-
try {
|
|
4126
|
-
new RegExp(value);
|
|
4127
|
-
return true;
|
|
4128
|
-
} catch {
|
|
4129
|
-
return false;
|
|
4130
|
-
}
|
|
4808
|
+
// node_modules/@sinclair/typebox/build/esm/type/clone/value.mjs
|
|
4809
|
+
function ArrayType(value) {
|
|
4810
|
+
return value.map((value2) => Visit(value2));
|
|
4131
4811
|
}
|
|
4132
|
-
function
|
|
4133
|
-
|
|
4134
|
-
return false;
|
|
4135
|
-
for (let i = 0; i < value.length; i++) {
|
|
4136
|
-
const code = value.charCodeAt(i);
|
|
4137
|
-
if (code >= 7 && code <= 13 || code === 27 || code === 127) {
|
|
4138
|
-
return false;
|
|
4139
|
-
}
|
|
4140
|
-
}
|
|
4141
|
-
return true;
|
|
4812
|
+
function DateType(value) {
|
|
4813
|
+
return new Date(value.getTime());
|
|
4142
4814
|
}
|
|
4143
|
-
function
|
|
4144
|
-
return
|
|
4815
|
+
function Uint8ArrayType(value) {
|
|
4816
|
+
return new Uint8Array(value);
|
|
4145
4817
|
}
|
|
4146
|
-
function
|
|
4147
|
-
return
|
|
4818
|
+
function RegExpType(value) {
|
|
4819
|
+
return new RegExp(value.source, value.flags);
|
|
4148
4820
|
}
|
|
4149
|
-
function
|
|
4150
|
-
|
|
4821
|
+
function ObjectType(value) {
|
|
4822
|
+
const result = {};
|
|
4823
|
+
for (const key of Object.getOwnPropertyNames(value)) {
|
|
4824
|
+
result[key] = Visit(value[key]);
|
|
4825
|
+
}
|
|
4826
|
+
for (const key of Object.getOwnPropertySymbols(value)) {
|
|
4827
|
+
result[key] = Visit(value[key]);
|
|
4828
|
+
}
|
|
4829
|
+
return result;
|
|
4151
4830
|
}
|
|
4152
|
-
function
|
|
4153
|
-
return
|
|
4831
|
+
function Visit(value) {
|
|
4832
|
+
return IsArray(value) ? ArrayType(value) : IsDate(value) ? DateType(value) : IsUint8Array(value) ? Uint8ArrayType(value) : IsRegExp(value) ? RegExpType(value) : IsObject(value) ? ObjectType(value) : value;
|
|
4154
4833
|
}
|
|
4155
|
-
function
|
|
4156
|
-
return
|
|
4834
|
+
function Clone(value) {
|
|
4835
|
+
return Visit(value);
|
|
4157
4836
|
}
|
|
4158
|
-
|
|
4159
|
-
|
|
4837
|
+
|
|
4838
|
+
// node_modules/@sinclair/typebox/build/esm/type/clone/type.mjs
|
|
4839
|
+
function CloneType(schema, options) {
|
|
4840
|
+
return options === void 0 ? Clone(schema) : Clone({ ...options, ...schema });
|
|
4160
4841
|
}
|
|
4161
|
-
|
|
4162
|
-
|
|
4842
|
+
|
|
4843
|
+
// node_modules/@sinclair/typebox/build/esm/value/guard/guard.mjs
|
|
4844
|
+
function IsObject2(value) {
|
|
4845
|
+
return value !== null && typeof value === "object";
|
|
4163
4846
|
}
|
|
4164
|
-
function
|
|
4165
|
-
return
|
|
4847
|
+
function IsArray2(value) {
|
|
4848
|
+
return globalThis.Array.isArray(value) && !globalThis.ArrayBuffer.isView(value);
|
|
4166
4849
|
}
|
|
4167
|
-
function
|
|
4168
|
-
return
|
|
4850
|
+
function IsUndefined2(value) {
|
|
4851
|
+
return value === void 0;
|
|
4169
4852
|
}
|
|
4170
|
-
function
|
|
4171
|
-
return
|
|
4853
|
+
function IsNumber2(value) {
|
|
4854
|
+
return typeof value === "number";
|
|
4172
4855
|
}
|
|
4173
|
-
|
|
4174
|
-
|
|
4856
|
+
|
|
4857
|
+
// node_modules/@sinclair/typebox/build/esm/system/policy.mjs
|
|
4858
|
+
var TypeSystemPolicy;
|
|
4859
|
+
(function(TypeSystemPolicy2) {
|
|
4860
|
+
TypeSystemPolicy2.InstanceMode = "default";
|
|
4861
|
+
TypeSystemPolicy2.ExactOptionalPropertyTypes = false;
|
|
4862
|
+
TypeSystemPolicy2.AllowArrayObject = false;
|
|
4863
|
+
TypeSystemPolicy2.AllowNaN = false;
|
|
4864
|
+
TypeSystemPolicy2.AllowNullVoid = false;
|
|
4865
|
+
function IsExactOptionalProperty(value, key) {
|
|
4866
|
+
return TypeSystemPolicy2.ExactOptionalPropertyTypes ? key in value : value[key] !== void 0;
|
|
4867
|
+
}
|
|
4868
|
+
TypeSystemPolicy2.IsExactOptionalProperty = IsExactOptionalProperty;
|
|
4869
|
+
function IsObjectLike(value) {
|
|
4870
|
+
const isObject = IsObject2(value);
|
|
4871
|
+
return TypeSystemPolicy2.AllowArrayObject ? isObject : isObject && !IsArray2(value);
|
|
4872
|
+
}
|
|
4873
|
+
TypeSystemPolicy2.IsObjectLike = IsObjectLike;
|
|
4874
|
+
function IsRecordLike(value) {
|
|
4875
|
+
return IsObjectLike(value) && !(value instanceof Date) && !(value instanceof Uint8Array);
|
|
4876
|
+
}
|
|
4877
|
+
TypeSystemPolicy2.IsRecordLike = IsRecordLike;
|
|
4878
|
+
function IsNumberLike(value) {
|
|
4879
|
+
return TypeSystemPolicy2.AllowNaN ? IsNumber2(value) : Number.isFinite(value);
|
|
4880
|
+
}
|
|
4881
|
+
TypeSystemPolicy2.IsNumberLike = IsNumberLike;
|
|
4882
|
+
function IsVoidLike(value) {
|
|
4883
|
+
const isUndefined = IsUndefined2(value);
|
|
4884
|
+
return TypeSystemPolicy2.AllowNullVoid ? isUndefined || value === null : isUndefined;
|
|
4885
|
+
}
|
|
4886
|
+
TypeSystemPolicy2.IsVoidLike = IsVoidLike;
|
|
4887
|
+
})(TypeSystemPolicy || (TypeSystemPolicy = {}));
|
|
4888
|
+
|
|
4889
|
+
// node_modules/@sinclair/typebox/build/esm/type/create/immutable.mjs
|
|
4890
|
+
function ImmutableArray(value) {
|
|
4891
|
+
return globalThis.Object.freeze(value).map((value2) => Immutable(value2));
|
|
4175
4892
|
}
|
|
4176
|
-
function
|
|
4177
|
-
return
|
|
4893
|
+
function ImmutableDate(value) {
|
|
4894
|
+
return value;
|
|
4178
4895
|
}
|
|
4179
|
-
function
|
|
4180
|
-
return
|
|
4896
|
+
function ImmutableUint8Array(value) {
|
|
4897
|
+
return value;
|
|
4181
4898
|
}
|
|
4182
|
-
function
|
|
4183
|
-
return
|
|
4899
|
+
function ImmutableRegExp(value) {
|
|
4900
|
+
return value;
|
|
4184
4901
|
}
|
|
4185
|
-
function
|
|
4186
|
-
|
|
4902
|
+
function ImmutableObject(value) {
|
|
4903
|
+
const result = {};
|
|
4904
|
+
for (const key of Object.getOwnPropertyNames(value)) {
|
|
4905
|
+
result[key] = Immutable(value[key]);
|
|
4906
|
+
}
|
|
4907
|
+
for (const key of Object.getOwnPropertySymbols(value)) {
|
|
4908
|
+
result[key] = Immutable(value[key]);
|
|
4909
|
+
}
|
|
4910
|
+
return globalThis.Object.freeze(result);
|
|
4187
4911
|
}
|
|
4188
|
-
function
|
|
4189
|
-
return
|
|
4912
|
+
function Immutable(value) {
|
|
4913
|
+
return IsArray(value) ? ImmutableArray(value) : IsDate(value) ? ImmutableDate(value) : IsUint8Array(value) ? ImmutableUint8Array(value) : IsRegExp(value) ? ImmutableRegExp(value) : IsObject(value) ? ImmutableObject(value) : value;
|
|
4190
4914
|
}
|
|
4191
|
-
|
|
4192
|
-
|
|
4915
|
+
|
|
4916
|
+
// node_modules/@sinclair/typebox/build/esm/type/create/type.mjs
|
|
4917
|
+
function CreateType(schema, options) {
|
|
4918
|
+
const result = options !== void 0 ? { ...options, ...schema } : schema;
|
|
4919
|
+
switch (TypeSystemPolicy.InstanceMode) {
|
|
4920
|
+
case "freeze":
|
|
4921
|
+
return Immutable(result);
|
|
4922
|
+
case "clone":
|
|
4923
|
+
return Clone(result);
|
|
4924
|
+
default:
|
|
4925
|
+
return result;
|
|
4926
|
+
}
|
|
4193
4927
|
}
|
|
4194
|
-
|
|
4195
|
-
|
|
4928
|
+
|
|
4929
|
+
// node_modules/@sinclair/typebox/build/esm/type/error/error.mjs
|
|
4930
|
+
var TypeBoxError = class extends Error {
|
|
4931
|
+
constructor(message) {
|
|
4932
|
+
super(message);
|
|
4933
|
+
}
|
|
4934
|
+
};
|
|
4935
|
+
|
|
4936
|
+
// node_modules/@sinclair/typebox/build/esm/type/symbols/symbols.mjs
|
|
4937
|
+
var TransformKind = Symbol.for("TypeBox.Transform");
|
|
4938
|
+
var ReadonlyKind = Symbol.for("TypeBox.Readonly");
|
|
4939
|
+
var OptionalKind = Symbol.for("TypeBox.Optional");
|
|
4940
|
+
var Hint = Symbol.for("TypeBox.Hint");
|
|
4941
|
+
var Kind = Symbol.for("TypeBox.Kind");
|
|
4942
|
+
|
|
4943
|
+
// node_modules/@sinclair/typebox/build/esm/type/guard/kind.mjs
|
|
4944
|
+
function IsReadonly(value) {
|
|
4945
|
+
return IsObject(value) && value[ReadonlyKind] === "Readonly";
|
|
4196
4946
|
}
|
|
4197
|
-
function
|
|
4198
|
-
return
|
|
4947
|
+
function IsOptional(value) {
|
|
4948
|
+
return IsObject(value) && value[OptionalKind] === "Optional";
|
|
4199
4949
|
}
|
|
4200
|
-
function
|
|
4201
|
-
return
|
|
4950
|
+
function IsAny(value) {
|
|
4951
|
+
return IsKindOf(value, "Any");
|
|
4202
4952
|
}
|
|
4203
|
-
function
|
|
4204
|
-
return
|
|
4953
|
+
function IsArgument(value) {
|
|
4954
|
+
return IsKindOf(value, "Argument");
|
|
4205
4955
|
}
|
|
4206
|
-
function
|
|
4207
|
-
return
|
|
4956
|
+
function IsArray3(value) {
|
|
4957
|
+
return IsKindOf(value, "Array");
|
|
4208
4958
|
}
|
|
4209
|
-
function
|
|
4210
|
-
return
|
|
4959
|
+
function IsAsyncIterator2(value) {
|
|
4960
|
+
return IsKindOf(value, "AsyncIterator");
|
|
4211
4961
|
}
|
|
4212
|
-
function
|
|
4213
|
-
return
|
|
4962
|
+
function IsBigInt2(value) {
|
|
4963
|
+
return IsKindOf(value, "BigInt");
|
|
4214
4964
|
}
|
|
4215
|
-
function
|
|
4216
|
-
return
|
|
4965
|
+
function IsBoolean2(value) {
|
|
4966
|
+
return IsKindOf(value, "Boolean");
|
|
4217
4967
|
}
|
|
4218
|
-
function
|
|
4219
|
-
return
|
|
4968
|
+
function IsComputed(value) {
|
|
4969
|
+
return IsKindOf(value, "Computed");
|
|
4220
4970
|
}
|
|
4221
|
-
function
|
|
4222
|
-
return
|
|
4971
|
+
function IsConstructor(value) {
|
|
4972
|
+
return IsKindOf(value, "Constructor");
|
|
4223
4973
|
}
|
|
4224
|
-
function
|
|
4225
|
-
return
|
|
4974
|
+
function IsDate2(value) {
|
|
4975
|
+
return IsKindOf(value, "Date");
|
|
4226
4976
|
}
|
|
4227
|
-
function
|
|
4228
|
-
return
|
|
4977
|
+
function IsFunction2(value) {
|
|
4978
|
+
return IsKindOf(value, "Function");
|
|
4229
4979
|
}
|
|
4230
|
-
function
|
|
4231
|
-
return
|
|
4980
|
+
function IsInteger(value) {
|
|
4981
|
+
return IsKindOf(value, "Integer");
|
|
4232
4982
|
}
|
|
4233
|
-
function
|
|
4234
|
-
return
|
|
4983
|
+
function IsIntersect(value) {
|
|
4984
|
+
return IsKindOf(value, "Intersect");
|
|
4235
4985
|
}
|
|
4236
|
-
function
|
|
4237
|
-
return
|
|
4986
|
+
function IsIterator2(value) {
|
|
4987
|
+
return IsKindOf(value, "Iterator");
|
|
4238
4988
|
}
|
|
4239
|
-
function
|
|
4240
|
-
return
|
|
4989
|
+
function IsKindOf(value, kind) {
|
|
4990
|
+
return IsObject(value) && Kind in value && value[Kind] === kind;
|
|
4241
4991
|
}
|
|
4242
|
-
function
|
|
4243
|
-
return
|
|
4992
|
+
function IsLiteralValue(value) {
|
|
4993
|
+
return IsBoolean(value) || IsNumber(value) || IsString(value);
|
|
4244
4994
|
}
|
|
4245
|
-
function
|
|
4246
|
-
return
|
|
4995
|
+
function IsLiteral(value) {
|
|
4996
|
+
return IsKindOf(value, "Literal");
|
|
4247
4997
|
}
|
|
4248
|
-
function
|
|
4249
|
-
return
|
|
4998
|
+
function IsMappedKey(value) {
|
|
4999
|
+
return IsKindOf(value, "MappedKey");
|
|
4250
5000
|
}
|
|
4251
|
-
function
|
|
4252
|
-
return
|
|
5001
|
+
function IsMappedResult(value) {
|
|
5002
|
+
return IsKindOf(value, "MappedResult");
|
|
4253
5003
|
}
|
|
4254
|
-
function
|
|
4255
|
-
return
|
|
5004
|
+
function IsNever(value) {
|
|
5005
|
+
return IsKindOf(value, "Never");
|
|
4256
5006
|
}
|
|
4257
|
-
function
|
|
4258
|
-
return
|
|
5007
|
+
function IsNot(value) {
|
|
5008
|
+
return IsKindOf(value, "Not");
|
|
4259
5009
|
}
|
|
4260
|
-
function
|
|
4261
|
-
return
|
|
4262
|
-
const keys = Object.getOwnPropertyNames(schema.patternProperties);
|
|
4263
|
-
return keys.length === 1 && IsPattern(keys[0]) && IsObject(schema.patternProperties) && IsSchema2(schema.patternProperties[keys[0]]);
|
|
4264
|
-
})(value);
|
|
5010
|
+
function IsNull2(value) {
|
|
5011
|
+
return IsKindOf(value, "Null");
|
|
4265
5012
|
}
|
|
4266
|
-
function
|
|
4267
|
-
return
|
|
5013
|
+
function IsNumber3(value) {
|
|
5014
|
+
return IsKindOf(value, "Number");
|
|
4268
5015
|
}
|
|
4269
|
-
function
|
|
4270
|
-
return
|
|
5016
|
+
function IsObject3(value) {
|
|
5017
|
+
return IsKindOf(value, "Object");
|
|
4271
5018
|
}
|
|
4272
|
-
function
|
|
4273
|
-
return
|
|
5019
|
+
function IsPromise(value) {
|
|
5020
|
+
return IsKindOf(value, "Promise");
|
|
4274
5021
|
}
|
|
4275
|
-
function
|
|
4276
|
-
return
|
|
5022
|
+
function IsRecord(value) {
|
|
5023
|
+
return IsKindOf(value, "Record");
|
|
4277
5024
|
}
|
|
4278
|
-
function
|
|
4279
|
-
return
|
|
5025
|
+
function IsRef(value) {
|
|
5026
|
+
return IsKindOf(value, "Ref");
|
|
4280
5027
|
}
|
|
4281
|
-
function
|
|
4282
|
-
return
|
|
5028
|
+
function IsRegExp2(value) {
|
|
5029
|
+
return IsKindOf(value, "RegExp");
|
|
4283
5030
|
}
|
|
4284
|
-
function
|
|
4285
|
-
return
|
|
5031
|
+
function IsString2(value) {
|
|
5032
|
+
return IsKindOf(value, "String");
|
|
4286
5033
|
}
|
|
4287
|
-
function
|
|
4288
|
-
return
|
|
5034
|
+
function IsSymbol2(value) {
|
|
5035
|
+
return IsKindOf(value, "Symbol");
|
|
4289
5036
|
}
|
|
4290
|
-
function
|
|
4291
|
-
return
|
|
4292
|
-
(IsUndefined(value.items) && IsUndefined(value.additionalItems) && value.minItems === 0 || IsArray(value.items) && value.items.every((schema) => IsSchema2(schema)));
|
|
5037
|
+
function IsTemplateLiteral(value) {
|
|
5038
|
+
return IsKindOf(value, "TemplateLiteral");
|
|
4293
5039
|
}
|
|
4294
|
-
function
|
|
4295
|
-
return
|
|
5040
|
+
function IsThis(value) {
|
|
5041
|
+
return IsKindOf(value, "This");
|
|
4296
5042
|
}
|
|
4297
|
-
function
|
|
4298
|
-
return
|
|
5043
|
+
function IsTransform(value) {
|
|
5044
|
+
return IsObject(value) && TransformKind in value;
|
|
4299
5045
|
}
|
|
4300
|
-
function
|
|
4301
|
-
return
|
|
5046
|
+
function IsTuple(value) {
|
|
5047
|
+
return IsKindOf(value, "Tuple");
|
|
4302
5048
|
}
|
|
4303
|
-
function
|
|
4304
|
-
return
|
|
5049
|
+
function IsUndefined3(value) {
|
|
5050
|
+
return IsKindOf(value, "Undefined");
|
|
4305
5051
|
}
|
|
4306
|
-
function
|
|
4307
|
-
return
|
|
5052
|
+
function IsUnion(value) {
|
|
5053
|
+
return IsKindOf(value, "Union");
|
|
4308
5054
|
}
|
|
4309
|
-
function
|
|
4310
|
-
return
|
|
5055
|
+
function IsUint8Array2(value) {
|
|
5056
|
+
return IsKindOf(value, "Uint8Array");
|
|
4311
5057
|
}
|
|
4312
|
-
function
|
|
4313
|
-
return
|
|
5058
|
+
function IsUnknown(value) {
|
|
5059
|
+
return IsKindOf(value, "Unknown");
|
|
4314
5060
|
}
|
|
4315
|
-
function
|
|
4316
|
-
return
|
|
5061
|
+
function IsUnsafe(value) {
|
|
5062
|
+
return IsKindOf(value, "Unsafe");
|
|
4317
5063
|
}
|
|
4318
|
-
function
|
|
4319
|
-
return
|
|
5064
|
+
function IsVoid(value) {
|
|
5065
|
+
return IsKindOf(value, "Void");
|
|
4320
5066
|
}
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
var PatternBoolean = "(true|false)";
|
|
4324
|
-
var PatternNumber = "(0|[1-9][0-9]*)";
|
|
4325
|
-
var PatternString = "(.*)";
|
|
4326
|
-
var PatternNever = "(?!.*)";
|
|
4327
|
-
var PatternBooleanExact = `^${PatternBoolean}$`;
|
|
4328
|
-
var PatternNumberExact = `^${PatternNumber}$`;
|
|
4329
|
-
var PatternStringExact = `^${PatternString}$`;
|
|
4330
|
-
var PatternNeverExact = `^${PatternNever}$`;
|
|
4331
|
-
|
|
4332
|
-
// node_modules/@sinclair/typebox/build/esm/type/sets/set.mjs
|
|
4333
|
-
function SetIncludes(T, S) {
|
|
4334
|
-
return T.includes(S);
|
|
5067
|
+
function IsKind(value) {
|
|
5068
|
+
return IsObject(value) && Kind in value && IsString(value[Kind]);
|
|
4335
5069
|
}
|
|
4336
|
-
function
|
|
4337
|
-
return
|
|
5070
|
+
function IsSchema(value) {
|
|
5071
|
+
return IsAny(value) || IsArgument(value) || IsArray3(value) || IsBoolean2(value) || IsBigInt2(value) || IsAsyncIterator2(value) || IsComputed(value) || IsConstructor(value) || IsDate2(value) || IsFunction2(value) || IsInteger(value) || IsIntersect(value) || IsIterator2(value) || IsLiteral(value) || IsMappedKey(value) || IsMappedResult(value) || IsNever(value) || IsNot(value) || IsNull2(value) || IsNumber3(value) || IsObject3(value) || IsPromise(value) || IsRecord(value) || IsRef(value) || IsRegExp2(value) || IsString2(value) || IsSymbol2(value) || IsTemplateLiteral(value) || IsThis(value) || IsTuple(value) || IsUndefined3(value) || IsUnion(value) || IsUint8Array2(value) || IsUnknown(value) || IsUnsafe(value) || IsVoid(value) || IsKind(value);
|
|
4338
5072
|
}
|
|
4339
|
-
|
|
4340
|
-
|
|
5073
|
+
|
|
5074
|
+
// node_modules/@sinclair/typebox/build/esm/type/guard/type.mjs
|
|
5075
|
+
var type_exports = {};
|
|
5076
|
+
__export(type_exports, {
|
|
5077
|
+
IsAny: () => IsAny2,
|
|
5078
|
+
IsArgument: () => IsArgument2,
|
|
5079
|
+
IsArray: () => IsArray4,
|
|
5080
|
+
IsAsyncIterator: () => IsAsyncIterator3,
|
|
5081
|
+
IsBigInt: () => IsBigInt3,
|
|
5082
|
+
IsBoolean: () => IsBoolean3,
|
|
5083
|
+
IsComputed: () => IsComputed2,
|
|
5084
|
+
IsConstructor: () => IsConstructor2,
|
|
5085
|
+
IsDate: () => IsDate3,
|
|
5086
|
+
IsFunction: () => IsFunction3,
|
|
5087
|
+
IsImport: () => IsImport,
|
|
5088
|
+
IsInteger: () => IsInteger2,
|
|
5089
|
+
IsIntersect: () => IsIntersect2,
|
|
5090
|
+
IsIterator: () => IsIterator3,
|
|
5091
|
+
IsKind: () => IsKind2,
|
|
5092
|
+
IsKindOf: () => IsKindOf2,
|
|
5093
|
+
IsLiteral: () => IsLiteral2,
|
|
5094
|
+
IsLiteralBoolean: () => IsLiteralBoolean,
|
|
5095
|
+
IsLiteralNumber: () => IsLiteralNumber,
|
|
5096
|
+
IsLiteralString: () => IsLiteralString,
|
|
5097
|
+
IsLiteralValue: () => IsLiteralValue2,
|
|
5098
|
+
IsMappedKey: () => IsMappedKey2,
|
|
5099
|
+
IsMappedResult: () => IsMappedResult2,
|
|
5100
|
+
IsNever: () => IsNever2,
|
|
5101
|
+
IsNot: () => IsNot2,
|
|
5102
|
+
IsNull: () => IsNull3,
|
|
5103
|
+
IsNumber: () => IsNumber4,
|
|
5104
|
+
IsObject: () => IsObject4,
|
|
5105
|
+
IsOptional: () => IsOptional2,
|
|
5106
|
+
IsPromise: () => IsPromise2,
|
|
5107
|
+
IsProperties: () => IsProperties,
|
|
5108
|
+
IsReadonly: () => IsReadonly2,
|
|
5109
|
+
IsRecord: () => IsRecord2,
|
|
5110
|
+
IsRecursive: () => IsRecursive,
|
|
5111
|
+
IsRef: () => IsRef2,
|
|
5112
|
+
IsRegExp: () => IsRegExp3,
|
|
5113
|
+
IsSchema: () => IsSchema2,
|
|
5114
|
+
IsString: () => IsString3,
|
|
5115
|
+
IsSymbol: () => IsSymbol3,
|
|
5116
|
+
IsTemplateLiteral: () => IsTemplateLiteral2,
|
|
5117
|
+
IsThis: () => IsThis2,
|
|
5118
|
+
IsTransform: () => IsTransform2,
|
|
5119
|
+
IsTuple: () => IsTuple2,
|
|
5120
|
+
IsUint8Array: () => IsUint8Array3,
|
|
5121
|
+
IsUndefined: () => IsUndefined4,
|
|
5122
|
+
IsUnion: () => IsUnion2,
|
|
5123
|
+
IsUnionLiteral: () => IsUnionLiteral,
|
|
5124
|
+
IsUnknown: () => IsUnknown2,
|
|
5125
|
+
IsUnsafe: () => IsUnsafe2,
|
|
5126
|
+
IsVoid: () => IsVoid2,
|
|
5127
|
+
TypeGuardUnknownTypeError: () => TypeGuardUnknownTypeError
|
|
5128
|
+
});
|
|
5129
|
+
var TypeGuardUnknownTypeError = class extends TypeBoxError {
|
|
5130
|
+
};
|
|
5131
|
+
var KnownTypes = [
|
|
5132
|
+
"Argument",
|
|
5133
|
+
"Any",
|
|
5134
|
+
"Array",
|
|
5135
|
+
"AsyncIterator",
|
|
5136
|
+
"BigInt",
|
|
5137
|
+
"Boolean",
|
|
5138
|
+
"Computed",
|
|
5139
|
+
"Constructor",
|
|
5140
|
+
"Date",
|
|
5141
|
+
"Enum",
|
|
5142
|
+
"Function",
|
|
5143
|
+
"Integer",
|
|
5144
|
+
"Intersect",
|
|
5145
|
+
"Iterator",
|
|
5146
|
+
"Literal",
|
|
5147
|
+
"MappedKey",
|
|
5148
|
+
"MappedResult",
|
|
5149
|
+
"Not",
|
|
5150
|
+
"Null",
|
|
5151
|
+
"Number",
|
|
5152
|
+
"Object",
|
|
5153
|
+
"Promise",
|
|
5154
|
+
"Record",
|
|
5155
|
+
"Ref",
|
|
5156
|
+
"RegExp",
|
|
5157
|
+
"String",
|
|
5158
|
+
"Symbol",
|
|
5159
|
+
"TemplateLiteral",
|
|
5160
|
+
"This",
|
|
5161
|
+
"Tuple",
|
|
5162
|
+
"Undefined",
|
|
5163
|
+
"Union",
|
|
5164
|
+
"Uint8Array",
|
|
5165
|
+
"Unknown",
|
|
5166
|
+
"Void"
|
|
5167
|
+
];
|
|
5168
|
+
function IsPattern(value) {
|
|
5169
|
+
try {
|
|
5170
|
+
new RegExp(value);
|
|
5171
|
+
return true;
|
|
5172
|
+
} catch {
|
|
5173
|
+
return false;
|
|
5174
|
+
}
|
|
4341
5175
|
}
|
|
4342
|
-
function
|
|
4343
|
-
|
|
4344
|
-
return
|
|
4345
|
-
|
|
5176
|
+
function IsControlCharacterFree(value) {
|
|
5177
|
+
if (!IsString(value))
|
|
5178
|
+
return false;
|
|
5179
|
+
for (let i = 0; i < value.length; i++) {
|
|
5180
|
+
const code = value.charCodeAt(i);
|
|
5181
|
+
if (code >= 7 && code <= 13 || code === 27 || code === 127) {
|
|
5182
|
+
return false;
|
|
5183
|
+
}
|
|
5184
|
+
}
|
|
5185
|
+
return true;
|
|
4346
5186
|
}
|
|
4347
|
-
function
|
|
4348
|
-
return
|
|
5187
|
+
function IsAdditionalProperties(value) {
|
|
5188
|
+
return IsOptionalBoolean(value) || IsSchema2(value);
|
|
5189
|
+
}
|
|
5190
|
+
function IsOptionalBigInt(value) {
|
|
5191
|
+
return IsUndefined(value) || IsBigInt(value);
|
|
5192
|
+
}
|
|
5193
|
+
function IsOptionalNumber(value) {
|
|
5194
|
+
return IsUndefined(value) || IsNumber(value);
|
|
5195
|
+
}
|
|
5196
|
+
function IsOptionalBoolean(value) {
|
|
5197
|
+
return IsUndefined(value) || IsBoolean(value);
|
|
5198
|
+
}
|
|
5199
|
+
function IsOptionalString(value) {
|
|
5200
|
+
return IsUndefined(value) || IsString(value);
|
|
5201
|
+
}
|
|
5202
|
+
function IsOptionalPattern(value) {
|
|
5203
|
+
return IsUndefined(value) || IsString(value) && IsControlCharacterFree(value) && IsPattern(value);
|
|
5204
|
+
}
|
|
5205
|
+
function IsOptionalFormat(value) {
|
|
5206
|
+
return IsUndefined(value) || IsString(value) && IsControlCharacterFree(value);
|
|
5207
|
+
}
|
|
5208
|
+
function IsOptionalSchema(value) {
|
|
5209
|
+
return IsUndefined(value) || IsSchema2(value);
|
|
5210
|
+
}
|
|
5211
|
+
function IsReadonly2(value) {
|
|
5212
|
+
return IsObject(value) && value[ReadonlyKind] === "Readonly";
|
|
5213
|
+
}
|
|
5214
|
+
function IsOptional2(value) {
|
|
5215
|
+
return IsObject(value) && value[OptionalKind] === "Optional";
|
|
5216
|
+
}
|
|
5217
|
+
function IsAny2(value) {
|
|
5218
|
+
return IsKindOf2(value, "Any") && IsOptionalString(value.$id);
|
|
5219
|
+
}
|
|
5220
|
+
function IsArgument2(value) {
|
|
5221
|
+
return IsKindOf2(value, "Argument") && IsNumber(value.index);
|
|
5222
|
+
}
|
|
5223
|
+
function IsArray4(value) {
|
|
5224
|
+
return IsKindOf2(value, "Array") && value.type === "array" && IsOptionalString(value.$id) && IsSchema2(value.items) && IsOptionalNumber(value.minItems) && IsOptionalNumber(value.maxItems) && IsOptionalBoolean(value.uniqueItems) && IsOptionalSchema(value.contains) && IsOptionalNumber(value.minContains) && IsOptionalNumber(value.maxContains);
|
|
5225
|
+
}
|
|
5226
|
+
function IsAsyncIterator3(value) {
|
|
5227
|
+
return IsKindOf2(value, "AsyncIterator") && value.type === "AsyncIterator" && IsOptionalString(value.$id) && IsSchema2(value.items);
|
|
5228
|
+
}
|
|
5229
|
+
function IsBigInt3(value) {
|
|
5230
|
+
return IsKindOf2(value, "BigInt") && value.type === "bigint" && IsOptionalString(value.$id) && IsOptionalBigInt(value.exclusiveMaximum) && IsOptionalBigInt(value.exclusiveMinimum) && IsOptionalBigInt(value.maximum) && IsOptionalBigInt(value.minimum) && IsOptionalBigInt(value.multipleOf);
|
|
5231
|
+
}
|
|
5232
|
+
function IsBoolean3(value) {
|
|
5233
|
+
return IsKindOf2(value, "Boolean") && value.type === "boolean" && IsOptionalString(value.$id);
|
|
5234
|
+
}
|
|
5235
|
+
function IsComputed2(value) {
|
|
5236
|
+
return IsKindOf2(value, "Computed") && IsString(value.target) && IsArray(value.parameters) && value.parameters.every((schema) => IsSchema2(schema));
|
|
5237
|
+
}
|
|
5238
|
+
function IsConstructor2(value) {
|
|
5239
|
+
return IsKindOf2(value, "Constructor") && value.type === "Constructor" && IsOptionalString(value.$id) && IsArray(value.parameters) && value.parameters.every((schema) => IsSchema2(schema)) && IsSchema2(value.returns);
|
|
5240
|
+
}
|
|
5241
|
+
function IsDate3(value) {
|
|
5242
|
+
return IsKindOf2(value, "Date") && value.type === "Date" && IsOptionalString(value.$id) && IsOptionalNumber(value.exclusiveMaximumTimestamp) && IsOptionalNumber(value.exclusiveMinimumTimestamp) && IsOptionalNumber(value.maximumTimestamp) && IsOptionalNumber(value.minimumTimestamp) && IsOptionalNumber(value.multipleOfTimestamp);
|
|
5243
|
+
}
|
|
5244
|
+
function IsFunction3(value) {
|
|
5245
|
+
return IsKindOf2(value, "Function") && value.type === "Function" && IsOptionalString(value.$id) && IsArray(value.parameters) && value.parameters.every((schema) => IsSchema2(schema)) && IsSchema2(value.returns);
|
|
5246
|
+
}
|
|
5247
|
+
function IsImport(value) {
|
|
5248
|
+
return IsKindOf2(value, "Import") && HasPropertyKey(value, "$defs") && IsObject(value.$defs) && IsProperties(value.$defs) && HasPropertyKey(value, "$ref") && IsString(value.$ref) && value.$ref in value.$defs;
|
|
5249
|
+
}
|
|
5250
|
+
function IsInteger2(value) {
|
|
5251
|
+
return IsKindOf2(value, "Integer") && value.type === "integer" && IsOptionalString(value.$id) && IsOptionalNumber(value.exclusiveMaximum) && IsOptionalNumber(value.exclusiveMinimum) && IsOptionalNumber(value.maximum) && IsOptionalNumber(value.minimum) && IsOptionalNumber(value.multipleOf);
|
|
5252
|
+
}
|
|
5253
|
+
function IsProperties(value) {
|
|
5254
|
+
return IsObject(value) && Object.entries(value).every(([key, schema]) => IsControlCharacterFree(key) && IsSchema2(schema));
|
|
5255
|
+
}
|
|
5256
|
+
function IsIntersect2(value) {
|
|
5257
|
+
return IsKindOf2(value, "Intersect") && (IsString(value.type) && value.type !== "object" ? false : true) && IsArray(value.allOf) && value.allOf.every((schema) => IsSchema2(schema) && !IsTransform2(schema)) && IsOptionalString(value.type) && (IsOptionalBoolean(value.unevaluatedProperties) || IsOptionalSchema(value.unevaluatedProperties)) && IsOptionalString(value.$id);
|
|
5258
|
+
}
|
|
5259
|
+
function IsIterator3(value) {
|
|
5260
|
+
return IsKindOf2(value, "Iterator") && value.type === "Iterator" && IsOptionalString(value.$id) && IsSchema2(value.items);
|
|
5261
|
+
}
|
|
5262
|
+
function IsKindOf2(value, kind) {
|
|
5263
|
+
return IsObject(value) && Kind in value && value[Kind] === kind;
|
|
5264
|
+
}
|
|
5265
|
+
function IsLiteralString(value) {
|
|
5266
|
+
return IsLiteral2(value) && IsString(value.const);
|
|
5267
|
+
}
|
|
5268
|
+
function IsLiteralNumber(value) {
|
|
5269
|
+
return IsLiteral2(value) && IsNumber(value.const);
|
|
5270
|
+
}
|
|
5271
|
+
function IsLiteralBoolean(value) {
|
|
5272
|
+
return IsLiteral2(value) && IsBoolean(value.const);
|
|
5273
|
+
}
|
|
5274
|
+
function IsLiteral2(value) {
|
|
5275
|
+
return IsKindOf2(value, "Literal") && IsOptionalString(value.$id) && IsLiteralValue2(value.const);
|
|
5276
|
+
}
|
|
5277
|
+
function IsLiteralValue2(value) {
|
|
5278
|
+
return IsBoolean(value) || IsNumber(value) || IsString(value);
|
|
5279
|
+
}
|
|
5280
|
+
function IsMappedKey2(value) {
|
|
5281
|
+
return IsKindOf2(value, "MappedKey") && IsArray(value.keys) && value.keys.every((key) => IsNumber(key) || IsString(key));
|
|
5282
|
+
}
|
|
5283
|
+
function IsMappedResult2(value) {
|
|
5284
|
+
return IsKindOf2(value, "MappedResult") && IsProperties(value.properties);
|
|
5285
|
+
}
|
|
5286
|
+
function IsNever2(value) {
|
|
5287
|
+
return IsKindOf2(value, "Never") && IsObject(value.not) && Object.getOwnPropertyNames(value.not).length === 0;
|
|
5288
|
+
}
|
|
5289
|
+
function IsNot2(value) {
|
|
5290
|
+
return IsKindOf2(value, "Not") && IsSchema2(value.not);
|
|
5291
|
+
}
|
|
5292
|
+
function IsNull3(value) {
|
|
5293
|
+
return IsKindOf2(value, "Null") && value.type === "null" && IsOptionalString(value.$id);
|
|
5294
|
+
}
|
|
5295
|
+
function IsNumber4(value) {
|
|
5296
|
+
return IsKindOf2(value, "Number") && value.type === "number" && IsOptionalString(value.$id) && IsOptionalNumber(value.exclusiveMaximum) && IsOptionalNumber(value.exclusiveMinimum) && IsOptionalNumber(value.maximum) && IsOptionalNumber(value.minimum) && IsOptionalNumber(value.multipleOf);
|
|
5297
|
+
}
|
|
5298
|
+
function IsObject4(value) {
|
|
5299
|
+
return IsKindOf2(value, "Object") && value.type === "object" && IsOptionalString(value.$id) && IsProperties(value.properties) && IsAdditionalProperties(value.additionalProperties) && IsOptionalNumber(value.minProperties) && IsOptionalNumber(value.maxProperties);
|
|
5300
|
+
}
|
|
5301
|
+
function IsPromise2(value) {
|
|
5302
|
+
return IsKindOf2(value, "Promise") && value.type === "Promise" && IsOptionalString(value.$id) && IsSchema2(value.item);
|
|
5303
|
+
}
|
|
5304
|
+
function IsRecord2(value) {
|
|
5305
|
+
return IsKindOf2(value, "Record") && value.type === "object" && IsOptionalString(value.$id) && IsAdditionalProperties(value.additionalProperties) && IsObject(value.patternProperties) && ((schema) => {
|
|
5306
|
+
const keys = Object.getOwnPropertyNames(schema.patternProperties);
|
|
5307
|
+
return keys.length === 1 && IsPattern(keys[0]) && IsObject(schema.patternProperties) && IsSchema2(schema.patternProperties[keys[0]]);
|
|
5308
|
+
})(value);
|
|
5309
|
+
}
|
|
5310
|
+
function IsRecursive(value) {
|
|
5311
|
+
return IsObject(value) && Hint in value && value[Hint] === "Recursive";
|
|
5312
|
+
}
|
|
5313
|
+
function IsRef2(value) {
|
|
5314
|
+
return IsKindOf2(value, "Ref") && IsOptionalString(value.$id) && IsString(value.$ref);
|
|
5315
|
+
}
|
|
5316
|
+
function IsRegExp3(value) {
|
|
5317
|
+
return IsKindOf2(value, "RegExp") && IsOptionalString(value.$id) && IsString(value.source) && IsString(value.flags) && IsOptionalNumber(value.maxLength) && IsOptionalNumber(value.minLength);
|
|
5318
|
+
}
|
|
5319
|
+
function IsString3(value) {
|
|
5320
|
+
return IsKindOf2(value, "String") && value.type === "string" && IsOptionalString(value.$id) && IsOptionalNumber(value.minLength) && IsOptionalNumber(value.maxLength) && IsOptionalPattern(value.pattern) && IsOptionalFormat(value.format);
|
|
5321
|
+
}
|
|
5322
|
+
function IsSymbol3(value) {
|
|
5323
|
+
return IsKindOf2(value, "Symbol") && value.type === "symbol" && IsOptionalString(value.$id);
|
|
5324
|
+
}
|
|
5325
|
+
function IsTemplateLiteral2(value) {
|
|
5326
|
+
return IsKindOf2(value, "TemplateLiteral") && value.type === "string" && IsString(value.pattern) && value.pattern[0] === "^" && value.pattern[value.pattern.length - 1] === "$";
|
|
5327
|
+
}
|
|
5328
|
+
function IsThis2(value) {
|
|
5329
|
+
return IsKindOf2(value, "This") && IsOptionalString(value.$id) && IsString(value.$ref);
|
|
5330
|
+
}
|
|
5331
|
+
function IsTransform2(value) {
|
|
5332
|
+
return IsObject(value) && TransformKind in value;
|
|
5333
|
+
}
|
|
5334
|
+
function IsTuple2(value) {
|
|
5335
|
+
return IsKindOf2(value, "Tuple") && value.type === "array" && IsOptionalString(value.$id) && IsNumber(value.minItems) && IsNumber(value.maxItems) && value.minItems === value.maxItems && // empty
|
|
5336
|
+
(IsUndefined(value.items) && IsUndefined(value.additionalItems) && value.minItems === 0 || IsArray(value.items) && value.items.every((schema) => IsSchema2(schema)));
|
|
5337
|
+
}
|
|
5338
|
+
function IsUndefined4(value) {
|
|
5339
|
+
return IsKindOf2(value, "Undefined") && value.type === "undefined" && IsOptionalString(value.$id);
|
|
5340
|
+
}
|
|
5341
|
+
function IsUnionLiteral(value) {
|
|
5342
|
+
return IsUnion2(value) && value.anyOf.every((schema) => IsLiteralString(schema) || IsLiteralNumber(schema));
|
|
5343
|
+
}
|
|
5344
|
+
function IsUnion2(value) {
|
|
5345
|
+
return IsKindOf2(value, "Union") && IsOptionalString(value.$id) && IsObject(value) && IsArray(value.anyOf) && value.anyOf.every((schema) => IsSchema2(schema));
|
|
5346
|
+
}
|
|
5347
|
+
function IsUint8Array3(value) {
|
|
5348
|
+
return IsKindOf2(value, "Uint8Array") && value.type === "Uint8Array" && IsOptionalString(value.$id) && IsOptionalNumber(value.minByteLength) && IsOptionalNumber(value.maxByteLength);
|
|
5349
|
+
}
|
|
5350
|
+
function IsUnknown2(value) {
|
|
5351
|
+
return IsKindOf2(value, "Unknown") && IsOptionalString(value.$id);
|
|
5352
|
+
}
|
|
5353
|
+
function IsUnsafe2(value) {
|
|
5354
|
+
return IsKindOf2(value, "Unsafe");
|
|
5355
|
+
}
|
|
5356
|
+
function IsVoid2(value) {
|
|
5357
|
+
return IsKindOf2(value, "Void") && value.type === "void" && IsOptionalString(value.$id);
|
|
5358
|
+
}
|
|
5359
|
+
function IsKind2(value) {
|
|
5360
|
+
return IsObject(value) && Kind in value && IsString(value[Kind]) && !KnownTypes.includes(value[Kind]);
|
|
5361
|
+
}
|
|
5362
|
+
function IsSchema2(value) {
|
|
5363
|
+
return IsObject(value) && (IsAny2(value) || IsArgument2(value) || IsArray4(value) || IsBoolean3(value) || IsBigInt3(value) || IsAsyncIterator3(value) || IsComputed2(value) || IsConstructor2(value) || IsDate3(value) || IsFunction3(value) || IsInteger2(value) || IsIntersect2(value) || IsIterator3(value) || IsLiteral2(value) || IsMappedKey2(value) || IsMappedResult2(value) || IsNever2(value) || IsNot2(value) || IsNull3(value) || IsNumber4(value) || IsObject4(value) || IsPromise2(value) || IsRecord2(value) || IsRef2(value) || IsRegExp3(value) || IsString3(value) || IsSymbol3(value) || IsTemplateLiteral2(value) || IsThis2(value) || IsTuple2(value) || IsUndefined4(value) || IsUnion2(value) || IsUint8Array3(value) || IsUnknown2(value) || IsUnsafe2(value) || IsVoid2(value) || IsKind2(value));
|
|
5364
|
+
}
|
|
5365
|
+
|
|
5366
|
+
// node_modules/@sinclair/typebox/build/esm/type/patterns/patterns.mjs
|
|
5367
|
+
var PatternBoolean = "(true|false)";
|
|
5368
|
+
var PatternNumber = "(0|[1-9][0-9]*)";
|
|
5369
|
+
var PatternString = "(.*)";
|
|
5370
|
+
var PatternNever = "(?!.*)";
|
|
5371
|
+
var PatternBooleanExact = `^${PatternBoolean}$`;
|
|
5372
|
+
var PatternNumberExact = `^${PatternNumber}$`;
|
|
5373
|
+
var PatternStringExact = `^${PatternString}$`;
|
|
5374
|
+
var PatternNeverExact = `^${PatternNever}$`;
|
|
5375
|
+
|
|
5376
|
+
// node_modules/@sinclair/typebox/build/esm/type/sets/set.mjs
|
|
5377
|
+
function SetIncludes(T, S) {
|
|
5378
|
+
return T.includes(S);
|
|
5379
|
+
}
|
|
5380
|
+
function SetDistinct(T) {
|
|
5381
|
+
return [...new Set(T)];
|
|
5382
|
+
}
|
|
5383
|
+
function SetIntersect(T, S) {
|
|
5384
|
+
return T.filter((L) => S.includes(L));
|
|
5385
|
+
}
|
|
5386
|
+
function SetIntersectManyResolve(T, Init) {
|
|
5387
|
+
return T.reduce((Acc, L) => {
|
|
5388
|
+
return SetIntersect(Acc, L);
|
|
5389
|
+
}, Init);
|
|
5390
|
+
}
|
|
5391
|
+
function SetIntersectMany(T) {
|
|
5392
|
+
return T.length === 1 ? T[0] : T.length > 1 ? SetIntersectManyResolve(T.slice(1), T[0]) : [];
|
|
4349
5393
|
}
|
|
4350
5394
|
function SetUnionMany(T) {
|
|
4351
5395
|
const Acc = [];
|
|
@@ -6191,1234 +7235,882 @@ var TransformDecodeBuilder = class {
|
|
|
6191
7235
|
constructor(schema) {
|
|
6192
7236
|
this.schema = schema;
|
|
6193
7237
|
}
|
|
6194
|
-
Decode(decode) {
|
|
6195
|
-
return new TransformEncodeBuilder(this.schema, decode);
|
|
6196
|
-
}
|
|
6197
|
-
};
|
|
6198
|
-
var TransformEncodeBuilder = class {
|
|
6199
|
-
constructor(schema, decode) {
|
|
6200
|
-
this.schema = schema;
|
|
6201
|
-
this.decode = decode;
|
|
6202
|
-
}
|
|
6203
|
-
EncodeTransform(encode, schema) {
|
|
6204
|
-
const Encode = (value) => schema[TransformKind].Encode(encode(value));
|
|
6205
|
-
const Decode = (value) => this.decode(schema[TransformKind].Decode(value));
|
|
6206
|
-
const Codec = { Encode, Decode };
|
|
6207
|
-
return { ...schema, [TransformKind]: Codec };
|
|
6208
|
-
}
|
|
6209
|
-
EncodeSchema(encode, schema) {
|
|
6210
|
-
const Codec = { Decode: this.decode, Encode: encode };
|
|
6211
|
-
return { ...schema, [TransformKind]: Codec };
|
|
6212
|
-
}
|
|
6213
|
-
Encode(encode) {
|
|
6214
|
-
return IsTransform(this.schema) ? this.EncodeTransform(encode, this.schema) : this.EncodeSchema(encode, this.schema);
|
|
6215
|
-
}
|
|
6216
|
-
};
|
|
6217
|
-
function Transform(schema) {
|
|
6218
|
-
return new TransformDecodeBuilder(schema);
|
|
6219
|
-
}
|
|
6220
|
-
|
|
6221
|
-
// node_modules/@sinclair/typebox/build/esm/type/unsafe/unsafe.mjs
|
|
6222
|
-
function Unsafe(options = {}) {
|
|
6223
|
-
return CreateType({ [Kind]: options[Kind] ?? "Unsafe" }, options);
|
|
6224
|
-
}
|
|
6225
|
-
|
|
6226
|
-
// node_modules/@sinclair/typebox/build/esm/type/void/void.mjs
|
|
6227
|
-
function Void(options) {
|
|
6228
|
-
return CreateType({ [Kind]: "Void", type: "void" }, options);
|
|
6229
|
-
}
|
|
6230
|
-
|
|
6231
|
-
// node_modules/@sinclair/typebox/build/esm/type/type/type.mjs
|
|
6232
|
-
var type_exports2 = {};
|
|
6233
|
-
__export(type_exports2, {
|
|
6234
|
-
Any: () => Any,
|
|
6235
|
-
Argument: () => Argument2,
|
|
6236
|
-
Array: () => Array2,
|
|
6237
|
-
AsyncIterator: () => AsyncIterator,
|
|
6238
|
-
Awaited: () => Awaited,
|
|
6239
|
-
BigInt: () => BigInt,
|
|
6240
|
-
Boolean: () => Boolean2,
|
|
6241
|
-
Capitalize: () => Capitalize,
|
|
6242
|
-
Composite: () => Composite,
|
|
6243
|
-
Const: () => Const,
|
|
6244
|
-
Constructor: () => Constructor,
|
|
6245
|
-
ConstructorParameters: () => ConstructorParameters,
|
|
6246
|
-
Date: () => Date2,
|
|
6247
|
-
Enum: () => Enum,
|
|
6248
|
-
Exclude: () => Exclude,
|
|
6249
|
-
Extends: () => Extends,
|
|
6250
|
-
Extract: () => Extract,
|
|
6251
|
-
Function: () => Function,
|
|
6252
|
-
Index: () => Index,
|
|
6253
|
-
InstanceType: () => InstanceType,
|
|
6254
|
-
Instantiate: () => Instantiate,
|
|
6255
|
-
Integer: () => Integer,
|
|
6256
|
-
Intersect: () => Intersect,
|
|
6257
|
-
Iterator: () => Iterator,
|
|
6258
|
-
KeyOf: () => KeyOf,
|
|
6259
|
-
Literal: () => Literal,
|
|
6260
|
-
Lowercase: () => Lowercase,
|
|
6261
|
-
Mapped: () => Mapped,
|
|
6262
|
-
Module: () => Module,
|
|
6263
|
-
Never: () => Never,
|
|
6264
|
-
Not: () => Not,
|
|
6265
|
-
Null: () => Null,
|
|
6266
|
-
Number: () => Number2,
|
|
6267
|
-
Object: () => Object2,
|
|
6268
|
-
Omit: () => Omit,
|
|
6269
|
-
Optional: () => Optional,
|
|
6270
|
-
Parameters: () => Parameters,
|
|
6271
|
-
Partial: () => Partial,
|
|
6272
|
-
Pick: () => Pick,
|
|
6273
|
-
Promise: () => Promise2,
|
|
6274
|
-
Readonly: () => Readonly,
|
|
6275
|
-
ReadonlyOptional: () => ReadonlyOptional,
|
|
6276
|
-
Record: () => Record,
|
|
6277
|
-
Recursive: () => Recursive,
|
|
6278
|
-
Ref: () => Ref,
|
|
6279
|
-
RegExp: () => RegExp2,
|
|
6280
|
-
Required: () => Required,
|
|
6281
|
-
Rest: () => Rest,
|
|
6282
|
-
ReturnType: () => ReturnType,
|
|
6283
|
-
String: () => String2,
|
|
6284
|
-
Symbol: () => Symbol2,
|
|
6285
|
-
TemplateLiteral: () => TemplateLiteral,
|
|
6286
|
-
Transform: () => Transform,
|
|
6287
|
-
Tuple: () => Tuple,
|
|
6288
|
-
Uint8Array: () => Uint8Array2,
|
|
6289
|
-
Uncapitalize: () => Uncapitalize,
|
|
6290
|
-
Undefined: () => Undefined,
|
|
6291
|
-
Union: () => Union,
|
|
6292
|
-
Unknown: () => Unknown,
|
|
6293
|
-
Unsafe: () => Unsafe,
|
|
6294
|
-
Uppercase: () => Uppercase,
|
|
6295
|
-
Void: () => Void
|
|
6296
|
-
});
|
|
6297
|
-
|
|
6298
|
-
// node_modules/@sinclair/typebox/build/esm/type/type/index.mjs
|
|
6299
|
-
var Type = type_exports2;
|
|
6300
|
-
|
|
6301
|
-
// src/protocol/pi-identity.ts
|
|
6302
|
-
var MANAGED_PI_ARTIFACT_ID = "@earendil-works/pi-coding-agent@0.80.10";
|
|
6303
|
-
var PiRuntimeIdentitySchema = Type.Union([
|
|
6304
|
-
Type.Object(
|
|
6305
|
-
{
|
|
6306
|
-
mode: Type.Literal("managed"),
|
|
6307
|
-
artifactId: Type.String({ minLength: 1 })
|
|
6308
|
-
},
|
|
6309
|
-
{ additionalProperties: false }
|
|
6310
|
-
),
|
|
6311
|
-
Type.Object(
|
|
6312
|
-
{
|
|
6313
|
-
mode: Type.Literal("external"),
|
|
6314
|
-
selectedPath: Type.String({ minLength: 1 }),
|
|
6315
|
-
nodePath: Type.String({ minLength: 1 }),
|
|
6316
|
-
realPath: Type.String({ minLength: 1 }),
|
|
6317
|
-
version: Type.String({ minLength: 1 }),
|
|
6318
|
-
fingerprint: Type.String({ minLength: 1 })
|
|
6319
|
-
},
|
|
6320
|
-
{ additionalProperties: false }
|
|
6321
|
-
)
|
|
6322
|
-
]);
|
|
6323
|
-
var MANAGED_PI_RUNTIME_IDENTITY = Object.freeze({
|
|
6324
|
-
mode: "managed",
|
|
6325
|
-
artifactId: MANAGED_PI_ARTIFACT_ID
|
|
6326
|
-
});
|
|
6327
|
-
|
|
6328
|
-
// src/client/socket-fleet-client.ts
|
|
6329
|
-
var SocketFleetClient = class {
|
|
6330
|
-
constructor(options) {
|
|
6331
|
-
this.options = options;
|
|
6332
|
-
}
|
|
6333
|
-
create(input, options) {
|
|
6334
|
-
return this.#request("agent.create", input, options);
|
|
6335
|
-
}
|
|
6336
|
-
send(input, options) {
|
|
6337
|
-
return this.#request("agent.send", input, options);
|
|
6338
|
-
}
|
|
6339
|
-
receive(input, options) {
|
|
6340
|
-
return this.#request("agent.receive", { ...input, timeoutMs: options.timeoutMs }, options);
|
|
6341
|
-
}
|
|
6342
|
-
status(input, options) {
|
|
6343
|
-
return this.#request("agent.status", input, options);
|
|
6344
|
-
}
|
|
6345
|
-
list(options) {
|
|
6346
|
-
return this.#request("agent.list", {}, options);
|
|
6347
|
-
}
|
|
6348
|
-
async *watch(input, options) {
|
|
6349
|
-
let socket;
|
|
6350
|
-
try {
|
|
6351
|
-
await this.options.beforeConnect?.();
|
|
6352
|
-
socket = await connect(this.options.socketPath, options.signal);
|
|
6353
|
-
} catch (error) {
|
|
6354
|
-
yield err(connectionError(error));
|
|
6355
|
-
return;
|
|
6356
|
-
}
|
|
6357
|
-
const requestId = randomUUID();
|
|
6358
|
-
const frames = frameIterator(socket, options.signal);
|
|
6359
|
-
writeJsonLine(socket, {
|
|
6360
|
-
v: PROTOCOL_VERSION,
|
|
6361
|
-
requestId,
|
|
6362
|
-
method: "agent.watch",
|
|
6363
|
-
params: input
|
|
6364
|
-
});
|
|
6365
|
-
let endedExplicitly = false;
|
|
6366
|
-
try {
|
|
6367
|
-
for await (const frame of frames) {
|
|
6368
|
-
if (!isRecord(frame) || frame.requestId !== requestId) continue;
|
|
6369
|
-
if (frame.v !== PROTOCOL_VERSION) {
|
|
6370
|
-
yield err({
|
|
6371
|
-
code: "protocol_incompatible",
|
|
6372
|
-
message: "The running pi-fleet runtime is incompatible with this client; repair or restart it."
|
|
6373
|
-
});
|
|
6374
|
-
return;
|
|
6375
|
-
}
|
|
6376
|
-
if (frame.stream === "ready") {
|
|
6377
|
-
yield ok({ type: "ready" });
|
|
6378
|
-
continue;
|
|
6379
|
-
}
|
|
6380
|
-
if (frame.stream === "end") {
|
|
6381
|
-
endedExplicitly = true;
|
|
6382
|
-
return;
|
|
6383
|
-
}
|
|
6384
|
-
if (frame.stream === "chunk" && typeof frame.data === "string") {
|
|
6385
|
-
yield ok({ type: "chunk", bytes: Buffer.from(frame.data, "base64") });
|
|
6386
|
-
continue;
|
|
6387
|
-
}
|
|
6388
|
-
if (frame.stream === "error" && isErrorRecord(frame.error)) {
|
|
6389
|
-
yield err(frame.error);
|
|
6390
|
-
return;
|
|
6391
|
-
}
|
|
6392
|
-
yield err({ code: "protocol_error", message: "Invalid watch stream frame." });
|
|
6393
|
-
return;
|
|
6394
|
-
}
|
|
6395
|
-
if (!endedExplicitly && !options.signal.aborted) {
|
|
6396
|
-
yield err({
|
|
6397
|
-
code: "runtime_unavailable",
|
|
6398
|
-
message: "Runtime connection closed before the watch stream ended."
|
|
6399
|
-
});
|
|
6400
|
-
}
|
|
6401
|
-
} catch (error) {
|
|
6402
|
-
if (!options.signal.aborted) yield err(connectionError(error));
|
|
6403
|
-
} finally {
|
|
6404
|
-
socket.destroy();
|
|
6405
|
-
}
|
|
6406
|
-
}
|
|
6407
|
-
destroy(input, options) {
|
|
6408
|
-
return this.#request("agent.destroy", input, options);
|
|
6409
|
-
}
|
|
6410
|
-
compact(input, options) {
|
|
6411
|
-
return this.#request("agent.compact", input, options);
|
|
6412
|
-
}
|
|
6413
|
-
async #request(method, params, options) {
|
|
6414
|
-
let socket;
|
|
6415
|
-
try {
|
|
6416
|
-
await this.options.beforeConnect?.();
|
|
6417
|
-
socket = await connect(this.options.socketPath, options.signal);
|
|
6418
|
-
} catch (error) {
|
|
6419
|
-
return err(connectionError(error));
|
|
6420
|
-
}
|
|
6421
|
-
const requestId = randomUUID();
|
|
6422
|
-
let piIdentity;
|
|
6423
|
-
try {
|
|
6424
|
-
piIdentity = requiresPiIdentity(method) ? await this.#piIdentity() : void 0;
|
|
6425
|
-
} catch (error) {
|
|
6426
|
-
socket.destroy();
|
|
6427
|
-
return err(piSelectionError(error));
|
|
6428
|
-
}
|
|
6429
|
-
const response = firstMatchingFrame(socket, requestId, options.signal);
|
|
6430
|
-
writeJsonLine(socket, {
|
|
6431
|
-
v: PROTOCOL_VERSION,
|
|
6432
|
-
requestId,
|
|
6433
|
-
method,
|
|
6434
|
-
params,
|
|
6435
|
-
...isMutationOptions(options) ? { operation: options.operation } : {},
|
|
6436
|
-
...piIdentity === void 0 ? {} : { runtime: { pi: piIdentity } }
|
|
6437
|
-
});
|
|
6438
|
-
try {
|
|
6439
|
-
const frame = await response;
|
|
6440
|
-
if (!isRecord(frame) || frame.requestId !== requestId || typeof frame.ok !== "boolean") {
|
|
6441
|
-
return err({ code: "protocol_error", message: "Invalid runtime response." });
|
|
6442
|
-
}
|
|
6443
|
-
if (frame.v !== PROTOCOL_VERSION) {
|
|
6444
|
-
return err({
|
|
6445
|
-
code: "protocol_incompatible",
|
|
6446
|
-
message: "The running pi-fleet runtime is incompatible with this client; repair or restart it."
|
|
6447
|
-
});
|
|
6448
|
-
}
|
|
6449
|
-
if (frame.ok) return ok(frame.result);
|
|
6450
|
-
if (method === "agent.compact" && isErrorRecord(frame.error) && frame.error.code === "invalid_request" && frame.error.message === "Invalid protocol request: /method") {
|
|
6451
|
-
return err({
|
|
6452
|
-
code: "protocol_incompatible",
|
|
6453
|
-
message: "The running pi-fleet runtime does not support compact; upgrade or repair it."
|
|
6454
|
-
});
|
|
6455
|
-
}
|
|
6456
|
-
if (isErrorRecord(frame.error)) return err(frame.error);
|
|
6457
|
-
return err({ code: "protocol_error", message: "Runtime returned an invalid error." });
|
|
6458
|
-
} catch (error) {
|
|
6459
|
-
return err(connectionError(error));
|
|
6460
|
-
} finally {
|
|
6461
|
-
socket.destroy();
|
|
6462
|
-
}
|
|
6463
|
-
}
|
|
6464
|
-
async #piIdentity() {
|
|
6465
|
-
const configured = this.options.piIdentity;
|
|
6466
|
-
if (configured === void 0) return MANAGED_PI_RUNTIME_IDENTITY;
|
|
6467
|
-
return typeof configured === "function" ? configured() : configured;
|
|
6468
|
-
}
|
|
6469
|
-
};
|
|
6470
|
-
function piSelectionError(error) {
|
|
6471
|
-
const code = error.code;
|
|
6472
|
-
if (code === "pi_not_found" || code === "pi_not_executable" || code === "pi_version_unavailable" || code === "pi_version_unsupported" || code === "pi_installation_changed" || code === "pi_service_mismatch") {
|
|
6473
|
-
return { code, message: error instanceof Error ? error.message : "Pi is unavailable." };
|
|
6474
|
-
}
|
|
6475
|
-
return { code: "internal_error", message: "Pi selection failed." };
|
|
6476
|
-
}
|
|
6477
|
-
function isMutationOptions(options) {
|
|
6478
|
-
return "operation" in options;
|
|
6479
|
-
}
|
|
6480
|
-
function requiresPiIdentity(method) {
|
|
6481
|
-
return method === "agent.create" || method === "agent.send" || method === "agent.compact";
|
|
6482
|
-
}
|
|
6483
|
-
function connect(socketPath, signal) {
|
|
6484
|
-
return new Promise((resolveConnect, rejectConnect) => {
|
|
6485
|
-
if (signal.aborted) {
|
|
6486
|
-
rejectConnect(new Error("Request cancelled"));
|
|
6487
|
-
return;
|
|
6488
|
-
}
|
|
6489
|
-
const socket = createConnection(socketPath);
|
|
6490
|
-
const onAbort = () => socket.destroy(new Error("Request cancelled"));
|
|
6491
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
6492
|
-
socket.once("connect", () => {
|
|
6493
|
-
signal.removeEventListener("abort", onAbort);
|
|
6494
|
-
resolveConnect(socket);
|
|
6495
|
-
});
|
|
6496
|
-
socket.once("error", rejectConnect);
|
|
6497
|
-
});
|
|
6498
|
-
}
|
|
6499
|
-
function firstMatchingFrame(socket, requestId, signal) {
|
|
6500
|
-
return new Promise((resolveFrame, rejectFrame) => {
|
|
6501
|
-
let settled = false;
|
|
6502
|
-
const finish = (action) => {
|
|
6503
|
-
if (settled) return;
|
|
6504
|
-
settled = true;
|
|
6505
|
-
stop();
|
|
6506
|
-
signal.removeEventListener("abort", onAbort);
|
|
6507
|
-
action();
|
|
6508
|
-
};
|
|
6509
|
-
const stop = readJsonLines(
|
|
6510
|
-
socket,
|
|
6511
|
-
(frame) => {
|
|
6512
|
-
if (!isRecord(frame) || frame.requestId !== requestId) return;
|
|
6513
|
-
finish(() => resolveFrame(frame));
|
|
6514
|
-
},
|
|
6515
|
-
(error) => finish(() => rejectFrame(error))
|
|
6516
|
-
);
|
|
6517
|
-
const onAbort = () => finish(() => rejectFrame(new Error("Request cancelled")));
|
|
6518
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
6519
|
-
socket.once(
|
|
6520
|
-
"close",
|
|
6521
|
-
() => finish(() => rejectFrame(new Error("Runtime connection closed before responding")))
|
|
6522
|
-
);
|
|
6523
|
-
});
|
|
6524
|
-
}
|
|
6525
|
-
async function* frameIterator(socket, signal, maxQueuedBytes = 1024 * 1024) {
|
|
6526
|
-
const queue = [];
|
|
6527
|
-
let queuedBytes = 0;
|
|
6528
|
-
let paused = false;
|
|
6529
|
-
let ended = false;
|
|
6530
|
-
let failure = null;
|
|
6531
|
-
let wake = null;
|
|
6532
|
-
const notify = () => {
|
|
6533
|
-
wake?.();
|
|
6534
|
-
wake = null;
|
|
6535
|
-
};
|
|
6536
|
-
const stop = readJsonLines(
|
|
6537
|
-
socket,
|
|
6538
|
-
(frame) => {
|
|
6539
|
-
const bytes = Buffer.byteLength(JSON.stringify(frame), "utf8");
|
|
6540
|
-
queue.push({ value: frame, bytes });
|
|
6541
|
-
queuedBytes += bytes;
|
|
6542
|
-
if (queuedBytes >= maxQueuedBytes && !paused) {
|
|
6543
|
-
socket.pause();
|
|
6544
|
-
paused = true;
|
|
6545
|
-
}
|
|
6546
|
-
notify();
|
|
6547
|
-
},
|
|
6548
|
-
(error) => {
|
|
6549
|
-
failure = error;
|
|
6550
|
-
ended = true;
|
|
6551
|
-
notify();
|
|
6552
|
-
}
|
|
6553
|
-
);
|
|
6554
|
-
socket.once("end", () => {
|
|
6555
|
-
failure = new Error("Runtime connection closed before completing the stream");
|
|
6556
|
-
ended = true;
|
|
6557
|
-
notify();
|
|
6558
|
-
});
|
|
6559
|
-
const onAbort = () => {
|
|
6560
|
-
failure = new Error("Request cancelled");
|
|
6561
|
-
ended = true;
|
|
6562
|
-
notify();
|
|
6563
|
-
};
|
|
6564
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
6565
|
-
try {
|
|
6566
|
-
while (!ended || queue.length > 0) {
|
|
6567
|
-
if (queue.length === 0) {
|
|
6568
|
-
await new Promise((resolveWake) => {
|
|
6569
|
-
wake = resolveWake;
|
|
6570
|
-
});
|
|
6571
|
-
continue;
|
|
6572
|
-
}
|
|
6573
|
-
const item = queue.shift();
|
|
6574
|
-
if (item === void 0) continue;
|
|
6575
|
-
queuedBytes -= item.bytes;
|
|
6576
|
-
if (paused && queuedBytes < maxQueuedBytes / 2) {
|
|
6577
|
-
socket.resume();
|
|
6578
|
-
paused = false;
|
|
6579
|
-
}
|
|
6580
|
-
yield item.value;
|
|
6581
|
-
}
|
|
6582
|
-
if (failure !== null) throw failure;
|
|
6583
|
-
} finally {
|
|
6584
|
-
stop();
|
|
6585
|
-
signal.removeEventListener("abort", onAbort);
|
|
6586
|
-
}
|
|
6587
|
-
}
|
|
6588
|
-
function isRecord(value) {
|
|
6589
|
-
return typeof value === "object" && value !== null;
|
|
6590
|
-
}
|
|
6591
|
-
function isErrorRecord(value) {
|
|
6592
|
-
return isRecord(value) && typeof value.code === "string" && typeof value.message === "string";
|
|
6593
|
-
}
|
|
6594
|
-
function connectionError(error) {
|
|
6595
|
-
return {
|
|
6596
|
-
code: "runtime_unavailable",
|
|
6597
|
-
message: error instanceof Error ? error.message : "Unable to connect to pi-fleet runtime."
|
|
6598
|
-
};
|
|
6599
|
-
}
|
|
6600
|
-
|
|
6601
|
-
// src/pi/external-installation.ts
|
|
6602
|
-
import { spawn } from "node:child_process";
|
|
6603
|
-
import { createHash } from "node:crypto";
|
|
6604
|
-
import { constants } from "node:fs";
|
|
6605
|
-
import { createReadStream } from "node:fs";
|
|
6606
|
-
import { access, realpath, stat } from "node:fs/promises";
|
|
6607
|
-
import { delimiter, dirname, isAbsolute, join } from "node:path";
|
|
6608
|
-
var VERSION_TIMEOUT_MS = 3e3;
|
|
6609
|
-
var MAX_VERSION_OUTPUT_BYTES = 4 * 1024;
|
|
6610
|
-
var ExternalPiResolutionError = class extends Error {
|
|
6611
|
-
constructor(code, message) {
|
|
6612
|
-
super(message);
|
|
6613
|
-
this.code = code;
|
|
6614
|
-
this.name = "ExternalPiResolutionError";
|
|
6615
|
-
}
|
|
6616
|
-
};
|
|
6617
|
-
async function resolveExternalPiInstallation(options = {}) {
|
|
6618
|
-
const env = options.env ?? process.env;
|
|
6619
|
-
const selectedPath = await resolveSelectedPath(env);
|
|
6620
|
-
const nodePath = options.nodePath ?? await resolveNodePath(env);
|
|
6621
|
-
await inspectNode(nodePath);
|
|
6622
|
-
const executionEnv = externalPiExecutionEnvironment(env, selectedPath, nodePath);
|
|
6623
|
-
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
6624
|
-
const observation = await observeInstallation(selectedPath, executionEnv, options);
|
|
6625
|
-
if (observation !== null) {
|
|
6626
|
-
return {
|
|
6627
|
-
selectedPath,
|
|
6628
|
-
nodePath,
|
|
6629
|
-
...observation
|
|
6630
|
-
};
|
|
6631
|
-
}
|
|
6632
|
-
}
|
|
6633
|
-
throw new ExternalPiResolutionError(
|
|
6634
|
-
"pi_installation_changed",
|
|
6635
|
-
"Pi changed while its installation was being observed."
|
|
6636
|
-
);
|
|
6637
|
-
}
|
|
6638
|
-
function externalPiExecutionEnvironment(env, selectedPath, nodePath) {
|
|
6639
|
-
return {
|
|
6640
|
-
...env,
|
|
6641
|
-
PATH: [dirname(nodePath), dirname(selectedPath), env.PATH].filter((value) => value !== void 0 && value.length > 0).join(delimiter)
|
|
6642
|
-
};
|
|
6643
|
-
}
|
|
6644
|
-
async function observeInstallation(selectedPath, env, options) {
|
|
6645
|
-
const beforeRealPath = await inspectExecutable(selectedPath, "Pi");
|
|
6646
|
-
const beforeHash = await hashFile(beforeRealPath);
|
|
6647
|
-
const versionOutput = await (options.versionCommand ?? ((executable) => readVersion(executable, env, options.versionTimeoutMs, options.maxVersionOutputBytes)))(selectedPath);
|
|
6648
|
-
const version = parseVersion(versionOutput);
|
|
6649
|
-
const afterRealPath = await inspectExecutable(selectedPath, "Pi");
|
|
6650
|
-
const afterHash = await hashFile(afterRealPath);
|
|
6651
|
-
if (beforeRealPath !== afterRealPath || beforeHash !== afterHash) return null;
|
|
6652
|
-
return {
|
|
6653
|
-
realPath: afterRealPath,
|
|
6654
|
-
version,
|
|
6655
|
-
fingerprint: createHash("sha256").update(JSON.stringify([selectedPath, afterRealPath, version, afterHash])).digest("hex")
|
|
6656
|
-
};
|
|
6657
|
-
}
|
|
6658
|
-
async function resolveSelectedPath(env) {
|
|
6659
|
-
const explicit = env.PIFLEET_PI_EXECUTABLE;
|
|
6660
|
-
if (explicit !== void 0) {
|
|
6661
|
-
if (!isAbsolute(explicit)) {
|
|
6662
|
-
throw new ExternalPiResolutionError(
|
|
6663
|
-
"invalid_arguments",
|
|
6664
|
-
"PIFLEET_PI_EXECUTABLE must be an absolute path."
|
|
6665
|
-
);
|
|
6666
|
-
}
|
|
6667
|
-
return explicit;
|
|
6668
|
-
}
|
|
6669
|
-
return resolvePathExecutable(env, "pi", "Pi", "pi_not_found");
|
|
6670
|
-
}
|
|
6671
|
-
async function resolveNodePath(env) {
|
|
6672
|
-
return resolvePathExecutable(env, "node", "Node", "pi_not_executable");
|
|
6673
|
-
}
|
|
6674
|
-
async function resolvePathExecutable(env, name, label, missingCode) {
|
|
6675
|
-
const path2 = env.PATH;
|
|
6676
|
-
if (path2 === void 0 || path2.length === 0) {
|
|
6677
|
-
throw new ExternalPiResolutionError(missingCode, `${label} was not found on PATH.`);
|
|
6678
|
-
}
|
|
6679
|
-
for (const directory of path2.split(delimiter)) {
|
|
6680
|
-
if (!isAbsolute(directory)) {
|
|
6681
|
-
throw new ExternalPiResolutionError(
|
|
6682
|
-
"invalid_arguments",
|
|
6683
|
-
`PATH entries used to select ${label} must be absolute paths.`
|
|
6684
|
-
);
|
|
6685
|
-
}
|
|
6686
|
-
const candidate = join(directory, name);
|
|
6687
|
-
try {
|
|
6688
|
-
await inspectExecutable(candidate, label);
|
|
6689
|
-
return candidate;
|
|
6690
|
-
} catch (error) {
|
|
6691
|
-
if (!(error instanceof ExternalPiResolutionError) || error.code !== "pi_not_executable" && error.code !== "pi_not_found") {
|
|
6692
|
-
throw error;
|
|
6693
|
-
}
|
|
6694
|
-
}
|
|
6695
|
-
}
|
|
6696
|
-
throw new ExternalPiResolutionError(missingCode, `${label} was not found on PATH.`);
|
|
6697
|
-
}
|
|
6698
|
-
async function inspectExecutable(path2, label) {
|
|
6699
|
-
try {
|
|
6700
|
-
const target = await realpath(path2);
|
|
6701
|
-
const metadata = await stat(target);
|
|
6702
|
-
if (!metadata.isFile()) {
|
|
6703
|
-
throw new ExternalPiResolutionError("pi_not_executable", `${label} is not a file: ${path2}`);
|
|
6704
|
-
}
|
|
6705
|
-
await access(path2, constants.X_OK);
|
|
6706
|
-
return target;
|
|
6707
|
-
} catch (error) {
|
|
6708
|
-
if (error instanceof ExternalPiResolutionError) throw error;
|
|
6709
|
-
if (error.code === "ENOENT") {
|
|
6710
|
-
throw new ExternalPiResolutionError("pi_not_found", `${label} was not found: ${path2}`);
|
|
6711
|
-
}
|
|
6712
|
-
throw new ExternalPiResolutionError("pi_not_executable", `${label} is not executable: ${path2}`);
|
|
6713
|
-
}
|
|
6714
|
-
}
|
|
6715
|
-
async function inspectNode(nodePath) {
|
|
6716
|
-
if (!isAbsolute(nodePath)) {
|
|
6717
|
-
throw new ExternalPiResolutionError("invalid_arguments", "Node must be an absolute path.");
|
|
6718
|
-
}
|
|
6719
|
-
try {
|
|
6720
|
-
await inspectExecutable(nodePath, "Node");
|
|
6721
|
-
} catch {
|
|
6722
|
-
throw new ExternalPiResolutionError("pi_not_executable", `Node is not executable: ${nodePath}`);
|
|
6723
|
-
}
|
|
6724
|
-
}
|
|
6725
|
-
async function hashFile(path2) {
|
|
6726
|
-
const hash = createHash("sha256");
|
|
6727
|
-
await new Promise((resolveHash, rejectHash) => {
|
|
6728
|
-
const stream = createReadStream(path2);
|
|
6729
|
-
stream.on("data", (chunk) => hash.update(chunk));
|
|
6730
|
-
stream.once("error", rejectHash);
|
|
6731
|
-
stream.once("end", resolveHash);
|
|
6732
|
-
});
|
|
6733
|
-
return hash.digest("hex");
|
|
6734
|
-
}
|
|
6735
|
-
async function readVersion(executable, env, timeoutMs = VERSION_TIMEOUT_MS, maxOutputBytes = MAX_VERSION_OUTPUT_BYTES) {
|
|
6736
|
-
const child = spawn(executable, ["--version"], {
|
|
6737
|
-
detached: process.platform !== "win32",
|
|
6738
|
-
env,
|
|
6739
|
-
shell: false,
|
|
6740
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
6741
|
-
});
|
|
6742
|
-
const chunks = [];
|
|
6743
|
-
let outputBytes = 0;
|
|
6744
|
-
let terminalError = null;
|
|
6745
|
-
let terminated = false;
|
|
6746
|
-
const terminate = () => {
|
|
6747
|
-
if (terminated) return;
|
|
6748
|
-
terminated = true;
|
|
6749
|
-
if (process.platform !== "win32" && child.pid !== void 0) {
|
|
6750
|
-
try {
|
|
6751
|
-
process.kill(-child.pid, "SIGKILL");
|
|
6752
|
-
return;
|
|
6753
|
-
} catch {
|
|
6754
|
-
}
|
|
6755
|
-
}
|
|
6756
|
-
child.kill("SIGKILL");
|
|
6757
|
-
};
|
|
6758
|
-
child.stdout.on("data", (chunk) => {
|
|
6759
|
-
if (terminalError !== null) return;
|
|
6760
|
-
outputBytes += chunk.byteLength;
|
|
6761
|
-
if (outputBytes > maxOutputBytes) {
|
|
6762
|
-
terminalError = new ExternalPiResolutionError(
|
|
6763
|
-
"pi_version_unavailable",
|
|
6764
|
-
"Pi version output exceeded its limit."
|
|
6765
|
-
);
|
|
6766
|
-
terminate();
|
|
6767
|
-
return;
|
|
6768
|
-
}
|
|
6769
|
-
chunks.push(chunk);
|
|
6770
|
-
});
|
|
6771
|
-
child.stderr.resume();
|
|
6772
|
-
return new Promise((resolveVersion, rejectVersion) => {
|
|
6773
|
-
const timer = setTimeout(() => {
|
|
6774
|
-
terminalError = new ExternalPiResolutionError(
|
|
6775
|
-
"pi_version_unavailable",
|
|
6776
|
-
"Pi version command timed out."
|
|
6777
|
-
);
|
|
6778
|
-
terminate();
|
|
6779
|
-
}, timeoutMs);
|
|
6780
|
-
child.once("error", () => {
|
|
6781
|
-
terminalError ??= new ExternalPiResolutionError(
|
|
6782
|
-
"pi_version_unavailable",
|
|
6783
|
-
"Pi version command failed."
|
|
6784
|
-
);
|
|
6785
|
-
});
|
|
6786
|
-
child.once("close", (code) => {
|
|
6787
|
-
clearTimeout(timer);
|
|
6788
|
-
if (terminalError !== null) {
|
|
6789
|
-
rejectVersion(terminalError);
|
|
6790
|
-
return;
|
|
6791
|
-
}
|
|
6792
|
-
if (code !== 0) {
|
|
6793
|
-
rejectVersion(
|
|
6794
|
-
new ExternalPiResolutionError("pi_version_unavailable", "Pi version command failed.")
|
|
6795
|
-
);
|
|
6796
|
-
return;
|
|
6797
|
-
}
|
|
6798
|
-
try {
|
|
6799
|
-
resolveVersion(new TextDecoder("utf-8", { fatal: true }).decode(Buffer.concat(chunks)));
|
|
6800
|
-
} catch {
|
|
6801
|
-
rejectVersion(
|
|
6802
|
-
new ExternalPiResolutionError(
|
|
6803
|
-
"pi_version_unavailable",
|
|
6804
|
-
"Pi version command returned invalid UTF-8."
|
|
6805
|
-
)
|
|
6806
|
-
);
|
|
6807
|
-
}
|
|
6808
|
-
});
|
|
6809
|
-
});
|
|
6810
|
-
}
|
|
6811
|
-
function parseVersion(output) {
|
|
6812
|
-
const match = /^(?:pi\s+)?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\s*$/i.exec(output);
|
|
6813
|
-
if (match?.[1] === void 0) {
|
|
6814
|
-
throw new ExternalPiResolutionError(
|
|
6815
|
-
"pi_version_unavailable",
|
|
6816
|
-
"Pi version command returned an invalid version."
|
|
6817
|
-
);
|
|
6818
|
-
}
|
|
6819
|
-
return match[1];
|
|
6820
|
-
}
|
|
6821
|
-
|
|
6822
|
-
// src/pi/process.ts
|
|
6823
|
-
var DEFAULT_MAX_STDOUT_FRAME_BYTES = 8 * 1024 * 1024;
|
|
6824
|
-
|
|
6825
|
-
// src/pi/external-target.ts
|
|
6826
|
-
function installationIdentity(installation) {
|
|
6827
|
-
return {
|
|
6828
|
-
mode: "external",
|
|
6829
|
-
selectedPath: installation.selectedPath,
|
|
6830
|
-
nodePath: installation.nodePath,
|
|
6831
|
-
realPath: installation.realPath,
|
|
6832
|
-
version: installation.version,
|
|
6833
|
-
fingerprint: installation.fingerprint
|
|
6834
|
-
};
|
|
6835
|
-
}
|
|
6836
|
-
|
|
6837
|
-
// src/platform/client/start-runtime.ts
|
|
6838
|
-
import { execFile, spawn as spawn2 } from "node:child_process";
|
|
6839
|
-
import { access as access2, readFile as readFile3 } from "node:fs/promises";
|
|
6840
|
-
import { createConnection as createConnection2 } from "node:net";
|
|
6841
|
-
import { homedir as homedir2 } from "node:os";
|
|
6842
|
-
import { dirname as dirname2, join as join5, resolve as resolve5 } from "node:path";
|
|
6843
|
-
import { fileURLToPath } from "node:url";
|
|
6844
|
-
import { promisify } from "node:util";
|
|
6845
|
-
|
|
6846
|
-
// src/platform/install/runtime-release.ts
|
|
6847
|
-
import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
|
|
6848
|
-
import { chmod, cp, lstat as lstat2, mkdir, readFile as readFile2, rename, rm, writeFile } from "node:fs/promises";
|
|
6849
|
-
import { join as join3, posix, resolve as resolve3, sep as sep2 } from "node:path";
|
|
6850
|
-
|
|
6851
|
-
// src/platform/install/tree-integrity.ts
|
|
6852
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
6853
|
-
import { lstat, readFile, readdir, realpath as realpath2, stat as stat2 } from "node:fs/promises";
|
|
6854
|
-
import { join as join2, relative, resolve as resolve2, sep } from "node:path";
|
|
6855
|
-
async function hashDirectoryTree(root, manifestPath) {
|
|
6856
|
-
const resolvedRoot = resolve2(root);
|
|
6857
|
-
const entries = await collectFiles(resolvedRoot, resolvedRoot);
|
|
6858
|
-
const hash = createHash2("sha256");
|
|
6859
|
-
let bytes = 0;
|
|
6860
|
-
for (const entry of entries) {
|
|
6861
|
-
const contents = await readFile(entry.absolutePath);
|
|
6862
|
-
bytes += contents.length;
|
|
6863
|
-
hash.update(entry.relativePath);
|
|
6864
|
-
hash.update("\0");
|
|
6865
|
-
hash.update(String(contents.length));
|
|
6866
|
-
hash.update("\0");
|
|
6867
|
-
hash.update(contents);
|
|
6868
|
-
hash.update("\0");
|
|
6869
|
-
}
|
|
6870
|
-
return {
|
|
6871
|
-
path: manifestPath,
|
|
6872
|
-
files: entries.length,
|
|
6873
|
-
bytes,
|
|
6874
|
-
sha256: hash.digest("hex")
|
|
6875
|
-
};
|
|
6876
|
-
}
|
|
6877
|
-
async function collectFiles(root, directory) {
|
|
6878
|
-
const output = [];
|
|
6879
|
-
for (const name of (await readdir(directory)).sort()) {
|
|
6880
|
-
const absolutePath = join2(directory, name);
|
|
6881
|
-
const linkInfo = await lstat(absolutePath);
|
|
6882
|
-
const info = linkInfo.isSymbolicLink() ? await stat2(absolutePath) : linkInfo;
|
|
6883
|
-
if (info.isDirectory()) {
|
|
6884
|
-
if (linkInfo.isSymbolicLink()) {
|
|
6885
|
-
throw new Error(`Runtime dependency tree contains a directory symlink: ${absolutePath}`);
|
|
6886
|
-
}
|
|
6887
|
-
output.push(...await collectFiles(root, absolutePath));
|
|
6888
|
-
continue;
|
|
6889
|
-
}
|
|
6890
|
-
if (!info.isFile()) {
|
|
6891
|
-
throw new Error(`Runtime dependency tree contains an unsupported entry: ${absolutePath}`);
|
|
6892
|
-
}
|
|
6893
|
-
if (linkInfo.isSymbolicLink()) {
|
|
6894
|
-
const target = await realpath2(absolutePath);
|
|
6895
|
-
if (target !== root && !target.startsWith(`${root}${sep}`)) {
|
|
6896
|
-
throw new Error(
|
|
6897
|
-
`Runtime dependency tree contains an external file symlink: ${absolutePath}`
|
|
6898
|
-
);
|
|
6899
|
-
}
|
|
6900
|
-
}
|
|
6901
|
-
const relativePath = relative(root, absolutePath).split(sep).join("/");
|
|
6902
|
-
if (relativePath.length === 0 || relativePath.startsWith("../")) {
|
|
6903
|
-
throw new Error(`Runtime dependency path escapes its root: ${absolutePath}`);
|
|
6904
|
-
}
|
|
6905
|
-
output.push({ absolutePath, relativePath });
|
|
6906
|
-
}
|
|
6907
|
-
return output.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
6908
|
-
}
|
|
6909
|
-
|
|
6910
|
-
// src/platform/install/runtime-release.ts
|
|
6911
|
-
var requiredRuntimeArtifacts = /* @__PURE__ */ new Set([
|
|
6912
|
-
"package.json",
|
|
6913
|
-
"bin/pifleet.mjs",
|
|
6914
|
-
"bin/pifleet-runtime.mjs",
|
|
6915
|
-
"dist/cli.mjs",
|
|
6916
|
-
"dist/runtime.mjs",
|
|
6917
|
-
"dist/sqlite-worker.mjs"
|
|
6918
|
-
]);
|
|
6919
|
-
var dependencyTreePath = "node_modules";
|
|
6920
|
-
async function materializeRuntime(options) {
|
|
6921
|
-
const sourceRoot = resolve3(options.sourceRoot);
|
|
6922
|
-
const manifestBytes = await readFile2(join3(sourceRoot, "dist", "runtime-manifest.json"));
|
|
6923
|
-
const sourceManifest = await parseRuntimeManifest(manifestBytes, sourceRoot);
|
|
6924
|
-
if (sourceManifest.closure !== void 0) {
|
|
6925
|
-
await verifyRuntime(sourceRoot);
|
|
6926
|
-
return sourceRoot;
|
|
6927
|
-
}
|
|
6928
|
-
await verifyRuntimeFiles(sourceRoot, sourceManifest);
|
|
6929
|
-
await verifyDependencyIdentities(sourceRoot, sourceManifest.dependencies);
|
|
6930
|
-
const sourceTreeRoot = resolveInside(sourceRoot, dependencyTreePath);
|
|
6931
|
-
const sourceTreeBefore = await hashDirectoryTree(sourceTreeRoot, dependencyTreePath);
|
|
6932
|
-
const sourceManifestSha256 = createHash3("sha256").update(manifestBytes).digest("hex");
|
|
6933
|
-
const materializedManifest = {
|
|
6934
|
-
...sourceManifest,
|
|
6935
|
-
closure: { sourceManifestSha256, tree: sourceTreeBefore }
|
|
6936
|
-
};
|
|
6937
|
-
const materializedManifestBytes = serializeManifest(materializedManifest);
|
|
6938
|
-
const closureHash = createHash3("sha256").update(sourceManifestSha256).update("\0").update(JSON.stringify(sourceTreeBefore)).digest("hex").slice(0, 16);
|
|
6939
|
-
const applicationRoot = resolve3(options.applicationRoot);
|
|
6940
|
-
await ensurePrivateDirectory(applicationRoot);
|
|
6941
|
-
const releasesRoot = join3(applicationRoot, "releases");
|
|
6942
|
-
await ensurePrivateDirectory(releasesRoot);
|
|
6943
|
-
const destination = join3(releasesRoot, `${sourceManifest.package.version}-${closureHash}`);
|
|
6944
|
-
if (await pathExists(destination)) {
|
|
6945
|
-
await verifyExpectedRuntime(destination, materializedManifest, materializedManifestBytes);
|
|
6946
|
-
return destination;
|
|
7238
|
+
Decode(decode) {
|
|
7239
|
+
return new TransformEncodeBuilder(this.schema, decode);
|
|
6947
7240
|
}
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
dereference: true
|
|
6954
|
-
});
|
|
6955
|
-
await cp(join3(sourceRoot, "bin"), join3(staging, "bin"), {
|
|
6956
|
-
recursive: true,
|
|
6957
|
-
dereference: true
|
|
6958
|
-
});
|
|
6959
|
-
await cp(join3(sourceRoot, "package.json"), join3(staging, "package.json"));
|
|
6960
|
-
await cp(sourceTreeRoot, join3(staging, dependencyTreePath), {
|
|
6961
|
-
recursive: true,
|
|
6962
|
-
dereference: true
|
|
6963
|
-
});
|
|
6964
|
-
await options.hooks?.afterDependencyCopy?.();
|
|
6965
|
-
const stagedTree = await hashDirectoryTree(
|
|
6966
|
-
join3(staging, dependencyTreePath),
|
|
6967
|
-
dependencyTreePath
|
|
6968
|
-
);
|
|
6969
|
-
assertSameTree(sourceTreeBefore, stagedTree, "copied dependency closure");
|
|
6970
|
-
const sourceTreeAfter = await hashDirectoryTree(sourceTreeRoot, dependencyTreePath);
|
|
6971
|
-
assertSameTree(sourceTreeBefore, sourceTreeAfter, "source dependency closure");
|
|
6972
|
-
await writeFile(join3(staging, "dist", "runtime-manifest.json"), materializedManifestBytes);
|
|
6973
|
-
await verifyExpectedRuntime(staging, materializedManifest, materializedManifestBytes);
|
|
6974
|
-
await chmod(staging, 448);
|
|
6975
|
-
try {
|
|
6976
|
-
await rename(staging, destination);
|
|
6977
|
-
} catch (error) {
|
|
6978
|
-
if (!isDestinationRace(error) || !await pathExists(destination)) throw error;
|
|
6979
|
-
await verifyExpectedRuntime(destination, materializedManifest, materializedManifestBytes);
|
|
6980
|
-
}
|
|
6981
|
-
return destination;
|
|
6982
|
-
} finally {
|
|
6983
|
-
await rm(staging, { recursive: true, force: true });
|
|
7241
|
+
};
|
|
7242
|
+
var TransformEncodeBuilder = class {
|
|
7243
|
+
constructor(schema, decode) {
|
|
7244
|
+
this.schema = schema;
|
|
7245
|
+
this.decode = decode;
|
|
6984
7246
|
}
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
if (manifest.closure === void 0) {
|
|
6991
|
-
throw new Error("Runtime release manifest is missing its materialized closure");
|
|
7247
|
+
EncodeTransform(encode, schema) {
|
|
7248
|
+
const Encode = (value) => schema[TransformKind].Encode(encode(value));
|
|
7249
|
+
const Decode = (value) => this.decode(schema[TransformKind].Decode(value));
|
|
7250
|
+
const Codec = { Encode, Decode };
|
|
7251
|
+
return { ...schema, [TransformKind]: Codec };
|
|
6992
7252
|
}
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
resolveInside(resolvedRoot, dependencyTreePath),
|
|
6997
|
-
dependencyTreePath
|
|
6998
|
-
);
|
|
6999
|
-
assertSameTree(manifest.closure.tree, actualTree, "materialized dependency closure");
|
|
7000
|
-
}
|
|
7001
|
-
async function verifyExpectedRuntime(root, expected, expectedBytes) {
|
|
7002
|
-
const manifestPath = join3(root, "dist", "runtime-manifest.json");
|
|
7003
|
-
const actualBytes = await readFile2(manifestPath);
|
|
7004
|
-
if (!actualBytes.equals(expectedBytes)) {
|
|
7005
|
-
throw new Error("Materialized runtime manifest does not match the expected closure");
|
|
7253
|
+
EncodeSchema(encode, schema) {
|
|
7254
|
+
const Codec = { Decode: this.decode, Encode: encode };
|
|
7255
|
+
return { ...schema, [TransformKind]: Codec };
|
|
7006
7256
|
}
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
throw new Error("Materialized runtime manifest is missing its closure");
|
|
7257
|
+
Encode(encode) {
|
|
7258
|
+
return IsTransform(this.schema) ? this.EncodeTransform(encode, this.schema) : this.EncodeSchema(encode, this.schema);
|
|
7010
7259
|
}
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
resolveInside(root, dependencyTreePath),
|
|
7015
|
-
dependencyTreePath
|
|
7016
|
-
);
|
|
7017
|
-
assertSameTree(expected.closure.tree, actualTree, "materialized dependency closure");
|
|
7260
|
+
};
|
|
7261
|
+
function Transform(schema) {
|
|
7262
|
+
return new TransformDecodeBuilder(schema);
|
|
7018
7263
|
}
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
if (info.isSymbolicLink()) {
|
|
7024
|
-
throw new Error(`Runtime artifact ${file.path} must not be a symbolic link`);
|
|
7025
|
-
}
|
|
7026
|
-
if (!info.isFile() || info.size !== file.bytes) {
|
|
7027
|
-
throw new Error(`Runtime artifact ${file.path} has changed`);
|
|
7028
|
-
}
|
|
7029
|
-
const hash = createHash3("sha256").update(await readFile2(path2)).digest("hex");
|
|
7030
|
-
if (hash !== file.sha256) {
|
|
7031
|
-
throw new Error(`Runtime artifact ${file.path} failed verification`);
|
|
7032
|
-
}
|
|
7033
|
-
}
|
|
7264
|
+
|
|
7265
|
+
// node_modules/@sinclair/typebox/build/esm/type/unsafe/unsafe.mjs
|
|
7266
|
+
function Unsafe(options = {}) {
|
|
7267
|
+
return CreateType({ [Kind]: options[Kind] ?? "Unsafe" }, options);
|
|
7034
7268
|
}
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7269
|
+
|
|
7270
|
+
// node_modules/@sinclair/typebox/build/esm/type/void/void.mjs
|
|
7271
|
+
function Void(options) {
|
|
7272
|
+
return CreateType({ [Kind]: "Void", type: "void" }, options);
|
|
7273
|
+
}
|
|
7274
|
+
|
|
7275
|
+
// node_modules/@sinclair/typebox/build/esm/type/type/type.mjs
|
|
7276
|
+
var type_exports2 = {};
|
|
7277
|
+
__export(type_exports2, {
|
|
7278
|
+
Any: () => Any,
|
|
7279
|
+
Argument: () => Argument2,
|
|
7280
|
+
Array: () => Array2,
|
|
7281
|
+
AsyncIterator: () => AsyncIterator,
|
|
7282
|
+
Awaited: () => Awaited,
|
|
7283
|
+
BigInt: () => BigInt,
|
|
7284
|
+
Boolean: () => Boolean2,
|
|
7285
|
+
Capitalize: () => Capitalize,
|
|
7286
|
+
Composite: () => Composite,
|
|
7287
|
+
Const: () => Const,
|
|
7288
|
+
Constructor: () => Constructor,
|
|
7289
|
+
ConstructorParameters: () => ConstructorParameters,
|
|
7290
|
+
Date: () => Date2,
|
|
7291
|
+
Enum: () => Enum,
|
|
7292
|
+
Exclude: () => Exclude,
|
|
7293
|
+
Extends: () => Extends,
|
|
7294
|
+
Extract: () => Extract,
|
|
7295
|
+
Function: () => Function,
|
|
7296
|
+
Index: () => Index,
|
|
7297
|
+
InstanceType: () => InstanceType,
|
|
7298
|
+
Instantiate: () => Instantiate,
|
|
7299
|
+
Integer: () => Integer,
|
|
7300
|
+
Intersect: () => Intersect,
|
|
7301
|
+
Iterator: () => Iterator,
|
|
7302
|
+
KeyOf: () => KeyOf,
|
|
7303
|
+
Literal: () => Literal,
|
|
7304
|
+
Lowercase: () => Lowercase,
|
|
7305
|
+
Mapped: () => Mapped,
|
|
7306
|
+
Module: () => Module,
|
|
7307
|
+
Never: () => Never,
|
|
7308
|
+
Not: () => Not,
|
|
7309
|
+
Null: () => Null,
|
|
7310
|
+
Number: () => Number2,
|
|
7311
|
+
Object: () => Object2,
|
|
7312
|
+
Omit: () => Omit,
|
|
7313
|
+
Optional: () => Optional,
|
|
7314
|
+
Parameters: () => Parameters,
|
|
7315
|
+
Partial: () => Partial,
|
|
7316
|
+
Pick: () => Pick,
|
|
7317
|
+
Promise: () => Promise2,
|
|
7318
|
+
Readonly: () => Readonly,
|
|
7319
|
+
ReadonlyOptional: () => ReadonlyOptional,
|
|
7320
|
+
Record: () => Record,
|
|
7321
|
+
Recursive: () => Recursive,
|
|
7322
|
+
Ref: () => Ref,
|
|
7323
|
+
RegExp: () => RegExp2,
|
|
7324
|
+
Required: () => Required,
|
|
7325
|
+
Rest: () => Rest,
|
|
7326
|
+
ReturnType: () => ReturnType,
|
|
7327
|
+
String: () => String2,
|
|
7328
|
+
Symbol: () => Symbol2,
|
|
7329
|
+
TemplateLiteral: () => TemplateLiteral,
|
|
7330
|
+
Transform: () => Transform,
|
|
7331
|
+
Tuple: () => Tuple,
|
|
7332
|
+
Uint8Array: () => Uint8Array2,
|
|
7333
|
+
Uncapitalize: () => Uncapitalize,
|
|
7334
|
+
Undefined: () => Undefined,
|
|
7335
|
+
Union: () => Union,
|
|
7336
|
+
Unknown: () => Unknown,
|
|
7337
|
+
Unsafe: () => Unsafe,
|
|
7338
|
+
Uppercase: () => Uppercase,
|
|
7339
|
+
Void: () => Void
|
|
7340
|
+
});
|
|
7341
|
+
|
|
7342
|
+
// node_modules/@sinclair/typebox/build/esm/type/type/index.mjs
|
|
7343
|
+
var Type = type_exports2;
|
|
7344
|
+
|
|
7345
|
+
// src/protocol/pi-identity.ts
|
|
7346
|
+
var MANAGED_PI_ARTIFACT_ID = "@earendil-works/pi-coding-agent@0.80.10";
|
|
7347
|
+
var PiRuntimeIdentitySchema = Type.Union([
|
|
7348
|
+
Type.Object(
|
|
7349
|
+
{
|
|
7350
|
+
mode: Type.Literal("managed"),
|
|
7351
|
+
artifactId: Type.String({ minLength: 1 })
|
|
7352
|
+
},
|
|
7353
|
+
{ additionalProperties: false }
|
|
7354
|
+
),
|
|
7355
|
+
Type.Object(
|
|
7356
|
+
{
|
|
7357
|
+
mode: Type.Literal("external"),
|
|
7358
|
+
selectedPath: Type.String({ minLength: 1 }),
|
|
7359
|
+
nodePath: Type.String({ minLength: 1 }),
|
|
7360
|
+
realPath: Type.String({ minLength: 1 }),
|
|
7361
|
+
version: Type.String({ minLength: 1 }),
|
|
7362
|
+
fingerprint: Type.String({ minLength: 1 })
|
|
7363
|
+
},
|
|
7364
|
+
{ additionalProperties: false }
|
|
7365
|
+
)
|
|
7366
|
+
]);
|
|
7367
|
+
var MANAGED_PI_RUNTIME_IDENTITY = Object.freeze({
|
|
7368
|
+
mode: "managed",
|
|
7369
|
+
artifactId: MANAGED_PI_ARTIFACT_ID
|
|
7370
|
+
});
|
|
7371
|
+
|
|
7372
|
+
// src/protocol/semantic-segmentation.ts
|
|
7373
|
+
var SemanticEventReassembler = class {
|
|
7374
|
+
#maxEventBytes;
|
|
7375
|
+
#maxSegments;
|
|
7376
|
+
#current;
|
|
7377
|
+
constructor(maxEventBytes, maxSegments = 4096) {
|
|
7378
|
+
assertPositiveInteger(maxEventBytes, "Semantic event reassembly limit");
|
|
7379
|
+
assertPositiveInteger(maxSegments, "Semantic segment limit");
|
|
7380
|
+
this.#maxEventBytes = maxEventBytes;
|
|
7381
|
+
this.#maxSegments = maxSegments;
|
|
7382
|
+
}
|
|
7383
|
+
push(frame) {
|
|
7384
|
+
assertFrame(frame);
|
|
7385
|
+
if (frame.count > this.#maxSegments) {
|
|
7386
|
+
throw new Error("Semantic event segment count exceeds reassembly limit");
|
|
7387
|
+
}
|
|
7388
|
+
if (frame.data.length === 0) throw new Error("Semantic event segment must not be empty");
|
|
7389
|
+
if (frame.index === 0) {
|
|
7390
|
+
if (this.#current !== void 0) throw new Error("Semantic event reassembly was interrupted");
|
|
7391
|
+
this.#current = {
|
|
7392
|
+
eventId: frame.eventId,
|
|
7393
|
+
precedingCursor: frame.precedingCursor,
|
|
7394
|
+
eventCursor: frame.eventCursor,
|
|
7395
|
+
count: frame.count,
|
|
7396
|
+
chunks: [],
|
|
7397
|
+
bytes: 0
|
|
7398
|
+
};
|
|
7046
7399
|
}
|
|
7047
|
-
const
|
|
7048
|
-
|
|
7049
|
-
if (
|
|
7050
|
-
|
|
7400
|
+
const current = this.#current;
|
|
7401
|
+
if (current === void 0) throw new Error("Semantic event segment has no start");
|
|
7402
|
+
if (frame.eventId !== current.eventId || frame.precedingCursor !== current.precedingCursor || frame.eventCursor !== current.eventCursor || frame.count !== current.count || frame.index !== current.chunks.length) {
|
|
7403
|
+
this.reset();
|
|
7404
|
+
throw new Error("Semantic event segment sequence is invalid");
|
|
7405
|
+
}
|
|
7406
|
+
const chunk = decodeBase64(frame.data);
|
|
7407
|
+
if (current.bytes + chunk.length > this.#maxEventBytes) {
|
|
7408
|
+
this.reset();
|
|
7409
|
+
throw new Error("Semantic event exceeds reassembly limit");
|
|
7410
|
+
}
|
|
7411
|
+
current.chunks.push(chunk);
|
|
7412
|
+
current.bytes += chunk.length;
|
|
7413
|
+
if (current.chunks.length < current.count) return null;
|
|
7414
|
+
const precedingCursor = current.precedingCursor;
|
|
7415
|
+
const eventCursor = current.eventCursor;
|
|
7416
|
+
const eventId = current.eventId;
|
|
7417
|
+
const bytes = Buffer.concat(current.chunks, current.bytes);
|
|
7418
|
+
this.reset();
|
|
7419
|
+
let event;
|
|
7420
|
+
try {
|
|
7421
|
+
event = JSON.parse(bytes.toString("utf8"));
|
|
7422
|
+
} catch {
|
|
7423
|
+
throw new Error("Semantic event payload is invalid JSON");
|
|
7051
7424
|
}
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
throw new Error(`Runtime dependency ${dependency.name} has an unexpected identity`);
|
|
7425
|
+
if (event.id !== eventId || event.cursor !== eventCursor) {
|
|
7426
|
+
throw new Error("Semantic event payload identity does not match its segments");
|
|
7055
7427
|
}
|
|
7428
|
+
return { event, precedingCursor };
|
|
7056
7429
|
}
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
let candidate;
|
|
7060
|
-
try {
|
|
7061
|
-
candidate = JSON.parse(bytes.toString("utf8"));
|
|
7062
|
-
} catch {
|
|
7063
|
-
throw new Error("Runtime manifest is not valid JSON");
|
|
7430
|
+
reset() {
|
|
7431
|
+
this.#current = void 0;
|
|
7064
7432
|
}
|
|
7065
|
-
|
|
7066
|
-
|
|
7433
|
+
};
|
|
7434
|
+
function assertFrame(frame) {
|
|
7435
|
+
if (frame.type !== "semantic.segment" || !Number.isSafeInteger(frame.index) || !Number.isSafeInteger(frame.count) || frame.index < 0 || frame.count <= 0 || frame.index >= frame.count) {
|
|
7436
|
+
throw new Error("Semantic event segment metadata is invalid");
|
|
7437
|
+
}
|
|
7438
|
+
}
|
|
7439
|
+
function decodeBase64(value) {
|
|
7440
|
+
const decoded = Buffer.from(value, "base64");
|
|
7441
|
+
if (decoded.toString("base64") !== value)
|
|
7442
|
+
throw new Error("Semantic event segment is invalid base64");
|
|
7443
|
+
return decoded;
|
|
7444
|
+
}
|
|
7445
|
+
function assertPositiveInteger(value, label) {
|
|
7446
|
+
if (!Number.isSafeInteger(value) || value <= 0) throw new Error(`${label} must be positive`);
|
|
7447
|
+
}
|
|
7448
|
+
|
|
7449
|
+
// src/client/contracts.ts
|
|
7450
|
+
var PI_FLEET_ERROR_CODES = [
|
|
7451
|
+
"agent_busy",
|
|
7452
|
+
"agent_destroyed",
|
|
7453
|
+
"agent_destroying",
|
|
7454
|
+
"agent_not_found",
|
|
7455
|
+
"capacity_exceeded",
|
|
7456
|
+
"cancelled",
|
|
7457
|
+
"compaction_failed",
|
|
7458
|
+
"compaction_uncertain",
|
|
7459
|
+
"cursor_expired",
|
|
7460
|
+
"cursor_invalid",
|
|
7461
|
+
"cursor_wrong_agent",
|
|
7462
|
+
"delivery_uncertain",
|
|
7463
|
+
"destroy_incomplete",
|
|
7464
|
+
"incarnation_cleanup_uncertain",
|
|
7465
|
+
"internal_error",
|
|
7466
|
+
"invalid_arguments",
|
|
7467
|
+
"invalid_request",
|
|
7468
|
+
"name_taken",
|
|
7469
|
+
"nothing_to_compact",
|
|
7470
|
+
"observation_uncertain",
|
|
7471
|
+
"operation_conflict",
|
|
7472
|
+
"operation_in_progress",
|
|
7473
|
+
"pi_installation_changed",
|
|
7474
|
+
"pi_not_executable",
|
|
7475
|
+
"pi_not_found",
|
|
7476
|
+
"pi_runtime_mismatch",
|
|
7477
|
+
"pi_service_mismatch",
|
|
7478
|
+
"pi_start_failed",
|
|
7479
|
+
"pi_version_unavailable",
|
|
7480
|
+
"pi_version_unsupported",
|
|
7481
|
+
"protocol_error",
|
|
7482
|
+
"protocol_incompatible",
|
|
7483
|
+
"receive_resource_exhausted",
|
|
7484
|
+
"runtime_interrupted",
|
|
7485
|
+
"runtime_unavailable",
|
|
7486
|
+
"runtime_upgrade_deferred",
|
|
7487
|
+
"semantic_event_too_large",
|
|
7488
|
+
"stale_agent",
|
|
7489
|
+
"state_corrupt",
|
|
7490
|
+
"storage_unavailable",
|
|
7491
|
+
"timeout"
|
|
7492
|
+
];
|
|
7493
|
+
var piFleetErrorCodeSet = new Set(PI_FLEET_ERROR_CODES);
|
|
7494
|
+
function isPiFleetErrorCode(value) {
|
|
7495
|
+
return typeof value === "string" && piFleetErrorCodeSet.has(value);
|
|
7067
7496
|
}
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
}
|
|
7072
|
-
|
|
7073
|
-
|
|
7497
|
+
|
|
7498
|
+
// src/shared/result.ts
|
|
7499
|
+
function ok(value) {
|
|
7500
|
+
return { ok: true, value };
|
|
7501
|
+
}
|
|
7502
|
+
function err(error) {
|
|
7503
|
+
return { ok: false, error };
|
|
7504
|
+
}
|
|
7505
|
+
|
|
7506
|
+
// src/client/socket-fleet-client.ts
|
|
7507
|
+
var SocketFleetClient = class {
|
|
7508
|
+
constructor(options) {
|
|
7509
|
+
this.options = options;
|
|
7074
7510
|
}
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
throw new Error("Runtime manifest package identity does not match package.json");
|
|
7511
|
+
create(input, options) {
|
|
7512
|
+
return this.#request("agent.create", input, options);
|
|
7078
7513
|
}
|
|
7079
|
-
|
|
7080
|
-
|
|
7514
|
+
async send(input, options) {
|
|
7515
|
+
const bound = await this.#bind(input, options);
|
|
7516
|
+
if (!bound.ok) return bound;
|
|
7517
|
+
return this.#request("agent.send", bound.value, options);
|
|
7081
7518
|
}
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
if (!
|
|
7085
|
-
|
|
7519
|
+
async *receive(input, options) {
|
|
7520
|
+
const bound = await this.#bind(input, options);
|
|
7521
|
+
if (!bound.ok) {
|
|
7522
|
+
yield bound;
|
|
7523
|
+
return;
|
|
7086
7524
|
}
|
|
7087
|
-
|
|
7088
|
-
|
|
7525
|
+
let socket;
|
|
7526
|
+
try {
|
|
7527
|
+
await this.options.beforeConnect?.();
|
|
7528
|
+
socket = await connect(this.options.socketPath, options.signal);
|
|
7529
|
+
} catch (error) {
|
|
7530
|
+
yield err(connectionError(error));
|
|
7531
|
+
return;
|
|
7089
7532
|
}
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7533
|
+
const requestId = randomUUID2();
|
|
7534
|
+
const frames = frameIterator(socket, options.signal);
|
|
7535
|
+
let reassembler = null;
|
|
7536
|
+
let expectedCursor = null;
|
|
7537
|
+
writeJsonLine(socket, {
|
|
7538
|
+
v: PROTOCOL_VERSION,
|
|
7539
|
+
requestId,
|
|
7540
|
+
method: "agent.receive",
|
|
7541
|
+
params: receiveParams(bound.value)
|
|
7542
|
+
});
|
|
7543
|
+
let ready = false;
|
|
7544
|
+
let ended = false;
|
|
7545
|
+
try {
|
|
7546
|
+
for await (const frame of frames) {
|
|
7547
|
+
if (!isRecord2(frame) || frame.requestId !== requestId) continue;
|
|
7548
|
+
if (frame.v !== PROTOCOL_VERSION) {
|
|
7549
|
+
yield err(protocolIncompatible());
|
|
7550
|
+
return;
|
|
7551
|
+
}
|
|
7552
|
+
if (frame.stream === "ready" && typeof frame.cursor === "string") {
|
|
7553
|
+
if (ready || !isRecord2(frame.limits) || !isPositiveSafeInteger(frame.limits.maxEventBytes) || !isPositiveSafeInteger(frame.limits.maxSegments)) {
|
|
7554
|
+
yield err({ code: "protocol_error", message: "Invalid receive readiness frame." });
|
|
7555
|
+
return;
|
|
7556
|
+
}
|
|
7557
|
+
ready = true;
|
|
7558
|
+
expectedCursor = frame.cursor;
|
|
7559
|
+
reassembler = new SemanticEventReassembler(
|
|
7560
|
+
frame.limits.maxEventBytes,
|
|
7561
|
+
frame.limits.maxSegments
|
|
7562
|
+
);
|
|
7563
|
+
yield ok({ type: "ready", cursor: expectedCursor });
|
|
7564
|
+
continue;
|
|
7565
|
+
}
|
|
7566
|
+
if (frame.stream === "semantic.segment" && isSemanticSegment(frame.segment)) {
|
|
7567
|
+
if (!ready) {
|
|
7568
|
+
yield err({
|
|
7569
|
+
code: "protocol_error",
|
|
7570
|
+
message: "Receive event arrived before readiness."
|
|
7571
|
+
});
|
|
7572
|
+
return;
|
|
7573
|
+
}
|
|
7574
|
+
try {
|
|
7575
|
+
if (reassembler === null || expectedCursor === null) {
|
|
7576
|
+
throw new Error("Receive stream is not ready");
|
|
7577
|
+
}
|
|
7578
|
+
const complete = reassembler.push(frame.segment);
|
|
7579
|
+
if (complete !== null) {
|
|
7580
|
+
if (complete.precedingCursor !== expectedCursor) {
|
|
7581
|
+
throw new Error("Receive event cursor chain is discontinuous");
|
|
7582
|
+
}
|
|
7583
|
+
expectedCursor = complete.event.cursor;
|
|
7584
|
+
yield ok({ type: "event", cursor: complete.event.cursor, event: complete.event });
|
|
7585
|
+
}
|
|
7586
|
+
} catch {
|
|
7587
|
+
yield err({ code: "protocol_error", message: "Receive stream segmentation failed." });
|
|
7588
|
+
return;
|
|
7589
|
+
}
|
|
7590
|
+
continue;
|
|
7591
|
+
}
|
|
7592
|
+
if (frame.stream === "end") {
|
|
7593
|
+
ended = true;
|
|
7594
|
+
return;
|
|
7595
|
+
}
|
|
7596
|
+
if (frame.stream === "error" && isErrorRecord(frame.error)) {
|
|
7597
|
+
yield err(frame.error);
|
|
7598
|
+
return;
|
|
7599
|
+
}
|
|
7600
|
+
yield err({ code: "protocol_error", message: "Invalid receive stream frame." });
|
|
7601
|
+
return;
|
|
7602
|
+
}
|
|
7603
|
+
if (!ended && !options.signal.aborted) {
|
|
7604
|
+
yield err({
|
|
7605
|
+
code: "runtime_unavailable",
|
|
7606
|
+
message: "Runtime connection closed before the receive stream ended."
|
|
7607
|
+
});
|
|
7608
|
+
}
|
|
7609
|
+
} catch (error) {
|
|
7610
|
+
if (!options.signal.aborted) yield err(connectionError(error));
|
|
7611
|
+
} finally {
|
|
7612
|
+
socket.destroy();
|
|
7095
7613
|
}
|
|
7096
7614
|
}
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
for (const dependency of candidate.dependencies) {
|
|
7100
|
-
if (!isRecord2(dependency) || !isManifestPath(dependency.path) || typeof dependency.name !== "string" || dependency.name.length === 0 || typeof dependency.version !== "string" || dependency.version.length === 0 || dependency.path !== `node_modules/${dependency.name}`) {
|
|
7101
|
-
throw new Error("Runtime manifest contains an invalid dependency declaration");
|
|
7102
|
-
}
|
|
7103
|
-
if (dependencyPaths.has(dependency.path) || dependencyNames.has(dependency.name)) {
|
|
7104
|
-
throw new Error(`Runtime manifest has duplicate dependency ${dependency.name}`);
|
|
7105
|
-
}
|
|
7106
|
-
dependencyPaths.add(dependency.path);
|
|
7107
|
-
dependencyNames.add(dependency.name);
|
|
7615
|
+
status(input, options) {
|
|
7616
|
+
return this.#request("agent.status", input, options);
|
|
7108
7617
|
}
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
(name) => expectedDependencies[name] !== candidate.dependencies.find(
|
|
7112
|
-
(dependency) => dependency.name === name
|
|
7113
|
-
)?.version
|
|
7114
|
-
)) {
|
|
7115
|
-
throw new Error("Runtime manifest dependencies do not match package.json");
|
|
7618
|
+
list(options) {
|
|
7619
|
+
return this.#request("agent.list", {}, options);
|
|
7116
7620
|
}
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7621
|
+
async destroy(input, options) {
|
|
7622
|
+
const bound = await this.#bind(input, options);
|
|
7623
|
+
if (!bound.ok) return bound;
|
|
7624
|
+
return this.#request("agent.destroy", bound.value, options);
|
|
7625
|
+
}
|
|
7626
|
+
async compact(input, options) {
|
|
7627
|
+
const bound = await this.#bind(input, options);
|
|
7628
|
+
if (!bound.ok) return bound;
|
|
7629
|
+
return this.#request("agent.compact", bound.value, options);
|
|
7630
|
+
}
|
|
7631
|
+
async #bind(input, options) {
|
|
7632
|
+
if (input.expectedAgentId !== void 0) {
|
|
7633
|
+
return ok({ ...input, expectedAgentId: input.expectedAgentId });
|
|
7634
|
+
}
|
|
7635
|
+
const status = await this.status(
|
|
7636
|
+
{ name: input.name },
|
|
7637
|
+
{
|
|
7638
|
+
signal: options.signal,
|
|
7639
|
+
...options.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs }
|
|
7121
7640
|
}
|
|
7122
|
-
|
|
7641
|
+
);
|
|
7642
|
+
if (!status.ok) return status;
|
|
7643
|
+
return ok({ ...input, expectedAgentId: status.value.agent.id });
|
|
7123
7644
|
}
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7645
|
+
async #request(method, params, options) {
|
|
7646
|
+
let socket;
|
|
7647
|
+
try {
|
|
7648
|
+
await this.options.beforeConnect?.();
|
|
7649
|
+
socket = await connect(this.options.socketPath, options.signal);
|
|
7650
|
+
} catch (error) {
|
|
7651
|
+
return err(connectionError(error));
|
|
7652
|
+
}
|
|
7653
|
+
const requestId = randomUUID2();
|
|
7654
|
+
let piIdentity;
|
|
7655
|
+
try {
|
|
7656
|
+
piIdentity = requiresPiIdentity(method) ? await this.#piIdentity() : void 0;
|
|
7657
|
+
} catch (error) {
|
|
7658
|
+
socket.destroy();
|
|
7659
|
+
return err(piSelectionError(error));
|
|
7660
|
+
}
|
|
7661
|
+
const response = firstMatchingFrame(socket, requestId, options.signal);
|
|
7662
|
+
writeJsonLine(socket, {
|
|
7663
|
+
v: PROTOCOL_VERSION,
|
|
7664
|
+
requestId,
|
|
7665
|
+
method,
|
|
7666
|
+
params,
|
|
7667
|
+
...isMutationOptions(options) ? { operation: options.operation } : {},
|
|
7668
|
+
...piIdentity === void 0 ? {} : { runtime: { pi: piIdentity } }
|
|
7669
|
+
});
|
|
7670
|
+
try {
|
|
7671
|
+
const frame = await response;
|
|
7672
|
+
if (!isRecord2(frame) || frame.requestId !== requestId || typeof frame.ok !== "boolean") {
|
|
7673
|
+
return err({ code: "protocol_error", message: "Invalid runtime response." });
|
|
7674
|
+
}
|
|
7675
|
+
if (frame.v !== PROTOCOL_VERSION) return err(protocolIncompatible());
|
|
7676
|
+
if (frame.ok) return ok(frame.result);
|
|
7677
|
+
if (isErrorRecord(frame.error)) return err(frame.error);
|
|
7678
|
+
return err({ code: "protocol_error", message: "Runtime returned an invalid error." });
|
|
7679
|
+
} catch (error) {
|
|
7680
|
+
return err(connectionError(error));
|
|
7681
|
+
} finally {
|
|
7682
|
+
socket.destroy();
|
|
7127
7683
|
}
|
|
7128
7684
|
}
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
candidate = JSON.parse(await readFile2(join3(root, "package.json"), "utf8"));
|
|
7134
|
-
} catch {
|
|
7135
|
-
throw new Error("Runtime package.json is not valid JSON");
|
|
7136
|
-
}
|
|
7137
|
-
if (!isRecord2(candidate) || typeof candidate.name !== "string" || typeof candidate.version !== "string" || candidate.dependencies !== void 0 && !isRecord2(candidate.dependencies) || isRecord2(candidate.dependencies) && Object.values(candidate.dependencies).some((version) => typeof version !== "string")) {
|
|
7138
|
-
throw new Error("Runtime package.json has invalid package metadata");
|
|
7685
|
+
async #piIdentity() {
|
|
7686
|
+
const configured = this.options.piIdentity;
|
|
7687
|
+
if (configured === void 0) return MANAGED_PI_RUNTIME_IDENTITY;
|
|
7688
|
+
return typeof configured === "function" ? configured() : configured;
|
|
7139
7689
|
}
|
|
7690
|
+
};
|
|
7691
|
+
function receiveParams(input) {
|
|
7692
|
+
const start = input.start ?? { kind: "live" };
|
|
7140
7693
|
return {
|
|
7141
|
-
name:
|
|
7142
|
-
|
|
7143
|
-
|
|
7694
|
+
name: input.name,
|
|
7695
|
+
...input.expectedAgentId === void 0 ? {} : { expectedAgentId: input.expectedAgentId },
|
|
7696
|
+
...start.kind === "after" ? { after: start.cursor } : {},
|
|
7697
|
+
...start.kind === "start" ? { fromStart: true } : {},
|
|
7698
|
+
...input.untilIdle === true ? { untilIdle: true } : {}
|
|
7144
7699
|
};
|
|
7145
7700
|
}
|
|
7146
|
-
function
|
|
7147
|
-
return
|
|
7148
|
-
|
|
7701
|
+
function protocolIncompatible() {
|
|
7702
|
+
return {
|
|
7703
|
+
code: "protocol_incompatible",
|
|
7704
|
+
message: "The running pi-fleet runtime is incompatible with this client; repair or restart it."
|
|
7705
|
+
};
|
|
7149
7706
|
}
|
|
7150
|
-
function
|
|
7151
|
-
|
|
7152
|
-
|
|
7707
|
+
function piSelectionError(error) {
|
|
7708
|
+
const code = error.code;
|
|
7709
|
+
if (code === "pi_not_found" || code === "pi_not_executable" || code === "pi_version_unavailable" || code === "pi_version_unsupported" || code === "pi_installation_changed" || code === "pi_service_mismatch") {
|
|
7710
|
+
return { code, message: error instanceof Error ? error.message : "Pi is unavailable." };
|
|
7153
7711
|
}
|
|
7712
|
+
return { code: "internal_error", message: "Pi selection failed." };
|
|
7154
7713
|
}
|
|
7155
|
-
function
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7714
|
+
function isMutationOptions(options) {
|
|
7715
|
+
return "operation" in options;
|
|
7716
|
+
}
|
|
7717
|
+
function requiresPiIdentity(method) {
|
|
7718
|
+
return method === "agent.create" || method === "agent.send" || method === "agent.compact";
|
|
7719
|
+
}
|
|
7720
|
+
function connect(socketPath, signal) {
|
|
7721
|
+
return new Promise((resolveConnect, rejectConnect) => {
|
|
7722
|
+
if (signal.aborted) {
|
|
7723
|
+
rejectConnect(new Error("Request cancelled"));
|
|
7724
|
+
return;
|
|
7725
|
+
}
|
|
7726
|
+
const socket = createConnection2(socketPath);
|
|
7727
|
+
const onAbort = () => socket.destroy(new Error("Request cancelled"));
|
|
7728
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
7729
|
+
socket.once("connect", () => {
|
|
7730
|
+
signal.removeEventListener("abort", onAbort);
|
|
7731
|
+
resolveConnect(socket);
|
|
7732
|
+
});
|
|
7733
|
+
socket.once("error", rejectConnect);
|
|
7734
|
+
});
|
|
7735
|
+
}
|
|
7736
|
+
function firstMatchingFrame(socket, requestId, signal) {
|
|
7737
|
+
return new Promise((resolveFrame, rejectFrame) => {
|
|
7738
|
+
let settled = false;
|
|
7739
|
+
const finish = (action) => {
|
|
7740
|
+
if (settled) return;
|
|
7741
|
+
settled = true;
|
|
7742
|
+
stop();
|
|
7743
|
+
signal.removeEventListener("abort", onAbort);
|
|
7744
|
+
action();
|
|
7745
|
+
};
|
|
7746
|
+
const stop = readJsonLines(
|
|
7747
|
+
socket,
|
|
7748
|
+
(frame) => {
|
|
7749
|
+
if (!isRecord2(frame) || frame.requestId !== requestId) return;
|
|
7750
|
+
finish(() => resolveFrame(frame));
|
|
7751
|
+
},
|
|
7752
|
+
(error) => finish(() => rejectFrame(error))
|
|
7753
|
+
);
|
|
7754
|
+
const onAbort = () => finish(() => rejectFrame(new Error("Request cancelled")));
|
|
7755
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
7756
|
+
socket.once(
|
|
7757
|
+
"close",
|
|
7758
|
+
() => finish(() => rejectFrame(new Error("Runtime connection closed before responding")))
|
|
7759
|
+
);
|
|
7760
|
+
});
|
|
7761
|
+
}
|
|
7762
|
+
async function* frameIterator(socket, signal, maxQueuedBytes = 1024 * 1024) {
|
|
7763
|
+
const queue = [];
|
|
7764
|
+
let queuedBytes = 0;
|
|
7765
|
+
let paused = false;
|
|
7766
|
+
let ended = false;
|
|
7767
|
+
let failure = null;
|
|
7768
|
+
let wake = null;
|
|
7769
|
+
const notify = () => {
|
|
7770
|
+
wake?.();
|
|
7771
|
+
wake = null;
|
|
7772
|
+
};
|
|
7773
|
+
const stop = readJsonLines(
|
|
7774
|
+
socket,
|
|
7775
|
+
(frame) => {
|
|
7776
|
+
const bytes = Buffer.byteLength(JSON.stringify(frame));
|
|
7777
|
+
queue.push({ value: frame, bytes });
|
|
7778
|
+
queuedBytes += bytes;
|
|
7779
|
+
if (queuedBytes >= maxQueuedBytes && !paused) {
|
|
7780
|
+
socket.pause();
|
|
7781
|
+
paused = true;
|
|
7782
|
+
}
|
|
7783
|
+
notify();
|
|
7784
|
+
},
|
|
7785
|
+
(error) => {
|
|
7786
|
+
failure = error;
|
|
7787
|
+
ended = true;
|
|
7788
|
+
notify();
|
|
7789
|
+
}
|
|
7790
|
+
);
|
|
7791
|
+
socket.once("end", () => {
|
|
7792
|
+
failure = new Error("Runtime connection closed before completing the stream");
|
|
7793
|
+
ended = true;
|
|
7794
|
+
notify();
|
|
7795
|
+
});
|
|
7796
|
+
const onAbort = () => {
|
|
7797
|
+
failure = new Error("Request cancelled");
|
|
7798
|
+
ended = true;
|
|
7799
|
+
notify();
|
|
7800
|
+
};
|
|
7801
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
7802
|
+
try {
|
|
7803
|
+
while (!ended || queue.length > 0) {
|
|
7804
|
+
if (queue.length === 0) {
|
|
7805
|
+
await new Promise((resolveWake) => {
|
|
7806
|
+
wake = resolveWake;
|
|
7807
|
+
});
|
|
7808
|
+
continue;
|
|
7809
|
+
}
|
|
7810
|
+
const item = queue.shift();
|
|
7811
|
+
if (item === void 0) continue;
|
|
7812
|
+
queuedBytes -= item.bytes;
|
|
7813
|
+
if (paused && queuedBytes < maxQueuedBytes / 2) {
|
|
7814
|
+
socket.resume();
|
|
7815
|
+
paused = false;
|
|
7816
|
+
}
|
|
7817
|
+
yield item.value;
|
|
7818
|
+
}
|
|
7819
|
+
if (failure !== null) throw failure;
|
|
7820
|
+
} finally {
|
|
7821
|
+
stop();
|
|
7822
|
+
signal.removeEventListener("abort", onAbort);
|
|
7160
7823
|
}
|
|
7161
|
-
|
|
7824
|
+
}
|
|
7825
|
+
function isSemanticSegment(value) {
|
|
7826
|
+
return isRecord2(value) && value.type === "semantic.segment";
|
|
7162
7827
|
}
|
|
7163
7828
|
function isRecord2(value) {
|
|
7164
7829
|
return typeof value === "object" && value !== null;
|
|
7165
7830
|
}
|
|
7166
|
-
function
|
|
7167
|
-
return
|
|
7168
|
-
}
|
|
7169
|
-
function isValidSize(value) {
|
|
7170
|
-
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
7171
|
-
}
|
|
7172
|
-
function isSha256(value) {
|
|
7173
|
-
return typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
|
|
7174
|
-
}
|
|
7175
|
-
function isTreeIntegrity(value) {
|
|
7176
|
-
return isRecord2(value) && isManifestPath(value.path) && isValidSize(value.files) && isValidSize(value.bytes) && isSha256(value.sha256);
|
|
7177
|
-
}
|
|
7178
|
-
function isDestinationRace(error) {
|
|
7179
|
-
const code = error.code;
|
|
7180
|
-
return code === "EEXIST" || code === "ENOTEMPTY";
|
|
7181
|
-
}
|
|
7182
|
-
async function ensurePrivateDirectory(path2) {
|
|
7183
|
-
await mkdir(path2, { recursive: true, mode: 448 });
|
|
7184
|
-
const info = await lstat2(path2);
|
|
7185
|
-
if (!info.isDirectory() || info.isSymbolicLink()) {
|
|
7186
|
-
throw new Error(`Refusing unsafe runtime release path ${path2}`);
|
|
7187
|
-
}
|
|
7188
|
-
if (typeof process.getuid === "function" && info.uid !== process.getuid()) {
|
|
7189
|
-
throw new Error(`Runtime release path ${path2} is not owned by the current user`);
|
|
7190
|
-
}
|
|
7191
|
-
await chmod(path2, 448);
|
|
7831
|
+
function isPositiveSafeInteger(value) {
|
|
7832
|
+
return Number.isSafeInteger(value) && typeof value === "number" && value > 0;
|
|
7192
7833
|
}
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7834
|
+
function isErrorRecord(value) {
|
|
7835
|
+
return isRecord2(value) && isPiFleetErrorCode(value.code) && typeof value.message === "string" && isSafeErrorDetails(value.code, value.details);
|
|
7836
|
+
}
|
|
7837
|
+
function isSafeErrorDetails(code, details) {
|
|
7838
|
+
if (details === void 0) return true;
|
|
7839
|
+
if (!isRecord2(details)) return false;
|
|
7840
|
+
const allowed = code === "observation_uncertain" ? ["lastSafeCursor", "continuationCursor"] : ["lastSafeCursor"];
|
|
7841
|
+
if (Object.keys(details).some((key) => !allowed.includes(key))) return false;
|
|
7842
|
+
if (!(typeof details.lastSafeCursor === "string" || details.lastSafeCursor === void 0)) {
|
|
7843
|
+
return false;
|
|
7200
7844
|
}
|
|
7845
|
+
if (code !== "observation_uncertain") return true;
|
|
7846
|
+
return typeof details.continuationCursor === "string" || details.continuationCursor === null;
|
|
7201
7847
|
}
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
import { homedir, tmpdir } from "node:os";
|
|
7205
|
-
import { join as join4, resolve as resolve4 } from "node:path";
|
|
7206
|
-
function resolveApplicationRoot(env = process.env) {
|
|
7207
|
-
return env.PIFLEET_APPLICATION_ROOT ?? (process.platform === "darwin" ? join4(homedir(), "Library", "Application Support", "pi-fleet", "runtime") : join4(env.XDG_DATA_HOME ?? join4(homedir(), ".local", "share"), "pi-fleet"));
|
|
7208
|
-
}
|
|
7209
|
-
function resolveFleetPaths(env = process.env) {
|
|
7210
|
-
const explicitRoot = env.PIFLEET_STATE_ROOT;
|
|
7211
|
-
if (explicitRoot !== void 0) {
|
|
7212
|
-
const root = resolve4(explicitRoot);
|
|
7213
|
-
return {
|
|
7214
|
-
runtimeRoot: root,
|
|
7215
|
-
stateRoot: root,
|
|
7216
|
-
socketPath: join4(root, "control.sock"),
|
|
7217
|
-
databasePath: join4(root, "fleet.sqlite")
|
|
7218
|
-
};
|
|
7219
|
-
}
|
|
7220
|
-
const runtimeRoot = join4(
|
|
7221
|
-
env.XDG_RUNTIME_DIR ?? tmpdir(),
|
|
7222
|
-
`pifleet-${process.getuid?.() ?? "user"}`
|
|
7223
|
-
);
|
|
7224
|
-
const stateRoot = process.platform === "darwin" ? join4(homedir(), "Library", "Application Support", "pi-fleet") : join4(env.XDG_STATE_HOME ?? join4(homedir(), ".local", "state"), "pi-fleet");
|
|
7848
|
+
function connectionError(error) {
|
|
7849
|
+
void error;
|
|
7225
7850
|
return {
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
socketPath: join4(runtimeRoot, "control.sock"),
|
|
7229
|
-
databasePath: join4(stateRoot, "fleet.sqlite")
|
|
7851
|
+
code: "runtime_unavailable",
|
|
7852
|
+
message: "Unable to connect to pi-fleet runtime."
|
|
7230
7853
|
};
|
|
7231
7854
|
}
|
|
7232
7855
|
|
|
7233
|
-
// src/
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
7856
|
+
// src/client/shared-client.ts
|
|
7857
|
+
function createSharedClientConnection(options) {
|
|
7858
|
+
const env = {
|
|
7859
|
+
...process.env,
|
|
7860
|
+
...options.env,
|
|
7861
|
+
...options.stateRoot === void 0 ? {} : { PIFLEET_STATE_ROOT: options.stateRoot }
|
|
7862
|
+
};
|
|
7863
|
+
const paths = resolveFleetPaths(env);
|
|
7864
|
+
let installation;
|
|
7865
|
+
const selectedPi = () => installation ??= resolveExternalPiInstallation({ env });
|
|
7866
|
+
const selectPiForMutation = async () => {
|
|
7867
|
+
const selected = await selectedPi();
|
|
7868
|
+
if (env.PIFLEET_DISABLE_REGISTERED_SERVICE !== "1") {
|
|
7869
|
+
await assertRegisteredPiSelection({
|
|
7870
|
+
selectedPath: selected.selectedPath,
|
|
7871
|
+
nodePath: selected.nodePath
|
|
7872
|
+
});
|
|
7873
|
+
}
|
|
7874
|
+
return selected;
|
|
7875
|
+
};
|
|
7876
|
+
const ensureControlPlane = () => ensureRuntime({
|
|
7877
|
+
socketPath: paths.socketPath,
|
|
7239
7878
|
env,
|
|
7240
|
-
...options.
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
PIFLEET_PI_EXECUTABLE: installation.selectedPath,
|
|
7248
|
-
PIFLEET_PI_NODE: installation.nodePath
|
|
7249
|
-
};
|
|
7879
|
+
...options.applicationRoot === void 0 ? {} : { applicationRoot: options.applicationRoot },
|
|
7880
|
+
piInstallation: async () => {
|
|
7881
|
+
try {
|
|
7882
|
+
return await selectedPi();
|
|
7883
|
+
} catch {
|
|
7884
|
+
return null;
|
|
7885
|
+
}
|
|
7250
7886
|
}
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
if (await canConnect(options.socketPath)) return;
|
|
7267
|
-
await new Promise((resolveDelay) => setTimeout(resolveDelay, 25));
|
|
7268
|
-
}
|
|
7269
|
-
throw new Error(`pi-fleet runtime did not become ready at ${options.socketPath}`);
|
|
7887
|
+
});
|
|
7888
|
+
const client = new SocketFleetClient({
|
|
7889
|
+
socketPath: paths.socketPath,
|
|
7890
|
+
...options.autoStartRuntime ? { beforeConnect: ensureControlPlane } : {},
|
|
7891
|
+
piIdentity: async () => installationIdentity(await selectPiForMutation())
|
|
7892
|
+
});
|
|
7893
|
+
return {
|
|
7894
|
+
client,
|
|
7895
|
+
operationIds: () => ({
|
|
7896
|
+
operationId: randomUUID3(),
|
|
7897
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7898
|
+
}),
|
|
7899
|
+
ensureControlPlane,
|
|
7900
|
+
selectPiForMutation
|
|
7901
|
+
};
|
|
7270
7902
|
}
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7903
|
+
|
|
7904
|
+
// src/client/sdk-transport.ts
|
|
7905
|
+
var FleetClientSdkTransport = class {
|
|
7906
|
+
constructor(client, operationIds, options = {}) {
|
|
7907
|
+
this.client = client;
|
|
7908
|
+
this.operationIds = operationIds;
|
|
7909
|
+
this.#reconnectDelayMs = options.reconnectDelayMs ?? 50;
|
|
7910
|
+
this.#autoReconnect = options.autoReconnect !== false;
|
|
7911
|
+
}
|
|
7912
|
+
#reconnectDelayMs;
|
|
7913
|
+
#autoReconnect;
|
|
7914
|
+
#activeReceiveIterators = /* @__PURE__ */ new Set();
|
|
7915
|
+
#closed = false;
|
|
7916
|
+
async create(input, signal) {
|
|
7917
|
+
const result = await this.client.create(
|
|
7918
|
+
{
|
|
7919
|
+
name: input.name,
|
|
7920
|
+
...input.instructions === void 0 ? {} : { instructions: input.instructions },
|
|
7921
|
+
cwd: input.cwd,
|
|
7922
|
+
piArgv: input.piArgs ?? []
|
|
7923
|
+
},
|
|
7924
|
+
{ signal, operation: this.operationIds() }
|
|
7925
|
+
);
|
|
7926
|
+
return unwrap(result).agent;
|
|
7279
7927
|
}
|
|
7280
|
-
|
|
7281
|
-
const
|
|
7282
|
-
if (!
|
|
7283
|
-
|
|
7284
|
-
const domain = `gui/${process.getuid?.() ?? 0}`;
|
|
7285
|
-
await execFileAsync("launchctl", ["kickstart", `${domain}/works.elpapi.pifleet`]);
|
|
7286
|
-
return true;
|
|
7928
|
+
async get(name, signal) {
|
|
7929
|
+
const result = await this.client.status({ name }, { signal });
|
|
7930
|
+
if (!result.ok && result.error.code === "agent_not_found") return null;
|
|
7931
|
+
return unwrap(result).agent;
|
|
7287
7932
|
}
|
|
7288
|
-
|
|
7289
|
-
}
|
|
7290
|
-
function installedServiceStateRoot(contents, platform) {
|
|
7291
|
-
const encoded = platform === "linux" ? /^Environment=PIFLEET_STATE_ROOT=(.+)$/m.exec(contents)?.[1] : /<key>PIFLEET_STATE_ROOT<\/key><string>([^<]+)<\/string>/.exec(contents)?.[1];
|
|
7292
|
-
if (encoded === void 0) return void 0;
|
|
7293
|
-
if (platform === "linux") return encoded;
|
|
7294
|
-
return encoded.replaceAll("'", "'").replaceAll(""", '"').replaceAll(">", ">").replaceAll("<", "<").replaceAll("&", "&");
|
|
7295
|
-
}
|
|
7296
|
-
var PiServiceMismatchError = class extends Error {
|
|
7297
|
-
code = "pi_service_mismatch";
|
|
7298
|
-
constructor(message) {
|
|
7299
|
-
super(message);
|
|
7300
|
-
this.name = "PiServiceMismatchError";
|
|
7933
|
+
async list(signal) {
|
|
7934
|
+
return unwrap(await this.client.list({ signal })).agents;
|
|
7301
7935
|
}
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
const installedNode = installedServicePiNode(contents, platform);
|
|
7312
|
-
if (installed === void 0 || installedNode === void 0 || resolve5(installed) !== resolve5(options.selectedPath) || resolve5(installedNode) !== resolve5(options.nodePath)) {
|
|
7313
|
-
throw new PiServiceMismatchError(
|
|
7314
|
-
`The installed pi-fleet service uses a different Pi executable or Node interpreter; repair it from the environment selecting ${options.selectedPath}.`
|
|
7936
|
+
async status(target, signal) {
|
|
7937
|
+
return unwrap(await this.client.status(target, { signal })).agent;
|
|
7938
|
+
}
|
|
7939
|
+
async send(target, message, delivery, signal) {
|
|
7940
|
+
const result = unwrap(
|
|
7941
|
+
await this.client.send(
|
|
7942
|
+
{ ...target, message, delivery },
|
|
7943
|
+
{ signal, operation: this.operationIds() }
|
|
7944
|
+
)
|
|
7315
7945
|
);
|
|
7946
|
+
return { acceptedAt: result.acceptedAt };
|
|
7316
7947
|
}
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7328
|
-
|
|
7948
|
+
async receive(target, start, signal, untilIdle = false) {
|
|
7949
|
+
const initial = await this.#attach(target, start, signal, void 0, untilIdle);
|
|
7950
|
+
let iterated = false;
|
|
7951
|
+
return {
|
|
7952
|
+
cursor: initial.cursor,
|
|
7953
|
+
[Symbol.asyncIterator]: () => {
|
|
7954
|
+
if (iterated) {
|
|
7955
|
+
throw new PiFleetError("invalid_request", "A receive stream can be iterated only once.");
|
|
7956
|
+
}
|
|
7957
|
+
iterated = true;
|
|
7958
|
+
return this.#events(target, initial, signal, untilIdle);
|
|
7959
|
+
}
|
|
7960
|
+
};
|
|
7329
7961
|
}
|
|
7330
|
-
|
|
7331
|
-
}
|
|
7332
|
-
async function assertRegisteredStateRoot(definitionPath, platform, env) {
|
|
7333
|
-
const installed = installedServiceStateRoot(await readFile3(definitionPath, "utf8"), platform);
|
|
7334
|
-
const requested = resolve5(resolveFleetPaths(env).stateRoot);
|
|
7335
|
-
if (installed === void 0) {
|
|
7336
|
-
if (env.PIFLEET_STATE_ROOT === void 0) return;
|
|
7337
|
-
throw new Error(
|
|
7338
|
-
`Registered pi-fleet service uses the default state root, but this command requested ${requested}. Run the pi-fleet installer with PIFLEET_STATE_ROOT=${requested} to repair the service, or omit the override.`
|
|
7339
|
-
);
|
|
7962
|
+
async compact(target, signal) {
|
|
7963
|
+
return unwrap(await this.client.compact(target, { signal, operation: this.operationIds() })).compaction;
|
|
7340
7964
|
}
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
`Registered pi-fleet service uses state root ${installed}, but this command requested ${requested}. Repair the service with the intended PIFLEET_STATE_ROOT before retrying.`
|
|
7344
|
-
);
|
|
7965
|
+
async destroy(target, signal) {
|
|
7966
|
+
unwrap(await this.client.destroy(target, { signal, operation: this.operationIds() }));
|
|
7345
7967
|
}
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
if (parent === candidate) break;
|
|
7353
|
-
candidate = parent;
|
|
7968
|
+
async close() {
|
|
7969
|
+
if (this.#closed) return;
|
|
7970
|
+
this.#closed = true;
|
|
7971
|
+
const iterators = [...this.#activeReceiveIterators];
|
|
7972
|
+
this.#activeReceiveIterators.clear();
|
|
7973
|
+
await Promise.allSettled(iterators.map(async (iterator) => iterator.return?.()));
|
|
7354
7974
|
}
|
|
7355
|
-
|
|
7975
|
+
async *#events(target, initial, signal, untilIdle) {
|
|
7976
|
+
let attachment = initial;
|
|
7977
|
+
let cursor = initial.cursor;
|
|
7978
|
+
while (true) {
|
|
7979
|
+
let reconnect = false;
|
|
7980
|
+
try {
|
|
7981
|
+
while (true) {
|
|
7982
|
+
const next = await attachment.iterator.next();
|
|
7983
|
+
if (next.done) {
|
|
7984
|
+
throwIfAborted(signal);
|
|
7985
|
+
return;
|
|
7986
|
+
}
|
|
7987
|
+
const result = next.value;
|
|
7988
|
+
if (!result.ok) {
|
|
7989
|
+
if (result.error.code === "runtime_unavailable" && !untilIdle && this.#autoReconnect) {
|
|
7990
|
+
reconnect = true;
|
|
7991
|
+
break;
|
|
7992
|
+
}
|
|
7993
|
+
throw publicError(result.error);
|
|
7994
|
+
}
|
|
7995
|
+
if (result.value.type === "ready") {
|
|
7996
|
+
throw new PiFleetError("protocol_error", "Receive emitted duplicate readiness.");
|
|
7997
|
+
}
|
|
7998
|
+
cursor = result.value.cursor;
|
|
7999
|
+
yield result.value.event;
|
|
8000
|
+
}
|
|
8001
|
+
} finally {
|
|
8002
|
+
await this.#release(attachment.iterator);
|
|
8003
|
+
}
|
|
8004
|
+
if (!reconnect) return;
|
|
8005
|
+
await abortableDelay(this.#reconnectDelayMs, signal);
|
|
8006
|
+
attachment = await this.#attach(target, { kind: "after", cursor }, signal, cursor, false);
|
|
8007
|
+
}
|
|
8008
|
+
}
|
|
8009
|
+
async #attach(target, start, signal, expectedCursor, untilIdle = false) {
|
|
8010
|
+
while (true) {
|
|
8011
|
+
throwIfAborted(signal);
|
|
8012
|
+
if (this.#closed) {
|
|
8013
|
+
throw new PiFleetError("runtime_unavailable", "pi-fleet client is closed");
|
|
8014
|
+
}
|
|
8015
|
+
const input = {
|
|
8016
|
+
...target,
|
|
8017
|
+
start,
|
|
8018
|
+
...untilIdle ? { untilIdle: true } : {}
|
|
8019
|
+
};
|
|
8020
|
+
const iterator = this.client.receive(input, { signal })[Symbol.asyncIterator]();
|
|
8021
|
+
this.#activeReceiveIterators.add(iterator);
|
|
8022
|
+
let first;
|
|
8023
|
+
try {
|
|
8024
|
+
first = await iterator.next();
|
|
8025
|
+
} catch (error) {
|
|
8026
|
+
await this.#release(iterator);
|
|
8027
|
+
throw error;
|
|
8028
|
+
}
|
|
8029
|
+
if (first.done) {
|
|
8030
|
+
await this.#release(iterator);
|
|
8031
|
+
throwIfAborted(signal);
|
|
8032
|
+
throw new PiFleetError(
|
|
8033
|
+
"runtime_unavailable",
|
|
8034
|
+
"Runtime connection closed before receive readiness."
|
|
8035
|
+
);
|
|
8036
|
+
}
|
|
8037
|
+
if (!first.value.ok) {
|
|
8038
|
+
await this.#release(iterator);
|
|
8039
|
+
if (first.value.error.code === "runtime_unavailable" && this.#autoReconnect) {
|
|
8040
|
+
await abortableDelay(this.#reconnectDelayMs, signal);
|
|
8041
|
+
continue;
|
|
8042
|
+
}
|
|
8043
|
+
throw publicError(first.value.error);
|
|
8044
|
+
}
|
|
8045
|
+
if (first.value.value.type !== "ready") {
|
|
8046
|
+
await this.#release(iterator);
|
|
8047
|
+
throw new PiFleetError("protocol_error", "Receive event arrived before readiness.");
|
|
8048
|
+
}
|
|
8049
|
+
if (expectedCursor !== void 0 && first.value.value.cursor !== expectedCursor) {
|
|
8050
|
+
await this.#release(iterator);
|
|
8051
|
+
throw new PiFleetError(
|
|
8052
|
+
"protocol_error",
|
|
8053
|
+
"Reconnected receive boundary does not match the last emitted cursor."
|
|
8054
|
+
);
|
|
8055
|
+
}
|
|
8056
|
+
return { cursor: first.value.value.cursor, iterator };
|
|
8057
|
+
}
|
|
8058
|
+
}
|
|
8059
|
+
async #release(iterator) {
|
|
8060
|
+
this.#activeReceiveIterators.delete(iterator);
|
|
8061
|
+
await iterator.return?.();
|
|
8062
|
+
}
|
|
8063
|
+
};
|
|
8064
|
+
function unwrap(result) {
|
|
8065
|
+
if (result.ok) return result.value;
|
|
8066
|
+
throw publicError(result.error);
|
|
7356
8067
|
}
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
return true;
|
|
7361
|
-
} catch {
|
|
7362
|
-
return false;
|
|
8068
|
+
function publicError(error) {
|
|
8069
|
+
if (!isPiFleetErrorCode(error.code)) {
|
|
8070
|
+
return new PiFleetError("internal_error", "pi-fleet client operation failed");
|
|
7363
8071
|
}
|
|
8072
|
+
return new PiFleetError(error.code, error.message, error.details);
|
|
7364
8073
|
}
|
|
7365
|
-
function
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
clearTimeout(timer);
|
|
7374
|
-
socket.destroy();
|
|
7375
|
-
resolveConnect(true);
|
|
7376
|
-
});
|
|
7377
|
-
socket.once("error", () => {
|
|
8074
|
+
function throwIfAborted(signal) {
|
|
8075
|
+
if (signal.aborted) throw new PiFleetError("cancelled", "Operation cancelled.");
|
|
8076
|
+
}
|
|
8077
|
+
function abortableDelay(durationMs, signal) {
|
|
8078
|
+
throwIfAborted(signal);
|
|
8079
|
+
if (durationMs === 0) return Promise.resolve();
|
|
8080
|
+
return new Promise((resolveDelay, rejectDelay) => {
|
|
8081
|
+
const onAbort = () => {
|
|
7378
8082
|
clearTimeout(timer);
|
|
7379
|
-
|
|
7380
|
-
}
|
|
8083
|
+
rejectDelay(new PiFleetError("cancelled", "Operation cancelled."));
|
|
8084
|
+
};
|
|
8085
|
+
const timer = setTimeout(() => {
|
|
8086
|
+
signal.removeEventListener("abort", onAbort);
|
|
8087
|
+
resolveDelay();
|
|
8088
|
+
}, durationMs);
|
|
8089
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
7381
8090
|
});
|
|
7382
8091
|
}
|
|
7383
8092
|
|
|
7384
8093
|
// src/entry/cli.ts
|
|
7385
8094
|
function defaultDependencies() {
|
|
7386
8095
|
const abort = new AbortController();
|
|
7387
|
-
const
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
const mutationPi = async () => {
|
|
7391
|
-
const selected = await selectedPi();
|
|
7392
|
-
if (process.env.PIFLEET_DISABLE_REGISTERED_SERVICE !== "1") {
|
|
7393
|
-
await assertRegisteredPiSelection({
|
|
7394
|
-
selectedPath: selected.selectedPath,
|
|
7395
|
-
nodePath: selected.nodePath
|
|
7396
|
-
});
|
|
7397
|
-
}
|
|
7398
|
-
return selected;
|
|
7399
|
-
};
|
|
8096
|
+
const connection = createSharedClientConnection({
|
|
8097
|
+
autoStartRuntime: true
|
|
8098
|
+
});
|
|
7400
8099
|
return {
|
|
7401
|
-
client:
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
socketPath: paths.socketPath,
|
|
7405
|
-
env: process.env,
|
|
7406
|
-
piInstallation: selectedPi
|
|
7407
|
-
}),
|
|
7408
|
-
piIdentity: async () => installationIdentity(await mutationPi())
|
|
7409
|
-
}),
|
|
8100
|
+
client: createPiFleetClient(
|
|
8101
|
+
new FleetClientSdkTransport(connection.client, connection.operationIds)
|
|
8102
|
+
),
|
|
7410
8103
|
cwd: process.cwd(),
|
|
7411
8104
|
stdin: process.stdin,
|
|
7412
8105
|
stdout: process.stdout,
|
|
7413
8106
|
stderr: process.stderr,
|
|
7414
|
-
signal: abort.signal
|
|
7415
|
-
operationIds: () => ({ operationId: randomUUID3(), createdAt: (/* @__PURE__ */ new Date()).toISOString() })
|
|
8107
|
+
signal: abort.signal
|
|
7416
8108
|
};
|
|
7417
8109
|
}
|
|
7418
8110
|
async function runCli(argv, dependencies = defaultDependencies()) {
|
|
7419
8111
|
const split = splitArgv(argv);
|
|
7420
8112
|
const commandName = split.fleetArgv[0];
|
|
7421
|
-
const human =
|
|
8113
|
+
const human = split.fleetArgv.includes("--human");
|
|
7422
8114
|
if (split.piArgv.length > 0 && commandName !== "create") {
|
|
7423
8115
|
writeError(
|
|
7424
8116
|
dependencies.stderr,
|