pi-radar 0.7.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/extension/baseline.js +386 -10
- package/dist/extension/radar-children.js +344 -0
- package/dist/extension/radar-client.js +47 -4
- package/dist/extension/radar-launch.js +42 -112
- package/dist/extension/radar-runtime.js +1 -1
- package/dist/index.js +471 -341
- package/extension/baseline.ts +2 -0
- package/extension/generated-contracts.ts +15 -2
- package/extension/radar-children.ts +222 -0
- package/extension/radar-client.ts +70 -2
- package/extension/radar-launch.ts +91 -274
- package/extension/radar-runtime.ts +4 -1
- package/index.ts +1 -0
- package/package.json +8 -3
- package/schema/public/v1/observation-get-response.deserialize.schema.json +1 -13
- package/schema/public/v1/observation-get-response.serialize.schema.json +3 -17
- package/schema/public/v1/observation-snapshot.deserialize.schema.json +1 -13
- package/schema/public/v1/observation-snapshot.serialize.schema.json +3 -17
- package/schema/public/v1/spawn-list-page.deserialize.schema.json +7 -0
- package/schema/public/v1/spawn-list-page.serialize.schema.json +7 -0
package/dist/index.js
CHANGED
|
@@ -4,6 +4,72 @@ var __export = (target, all) => {
|
|
|
4
4
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
+
// extension/radar-children.ts
|
|
8
|
+
var radar_children_exports = {};
|
|
9
|
+
__export(radar_children_exports, {
|
|
10
|
+
createRadarChildren: () => createRadarChildren
|
|
11
|
+
});
|
|
12
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
13
|
+
|
|
14
|
+
// extension/radar-inspection.ts
|
|
15
|
+
var radar_inspection_exports = {};
|
|
16
|
+
__export(radar_inspection_exports, {
|
|
17
|
+
inspectRadarChild: () => inspectRadarChild,
|
|
18
|
+
provedRead: () => provedRead
|
|
19
|
+
});
|
|
20
|
+
var INSPECTION_LINES = 80;
|
|
21
|
+
var INSPECTION_OUTPUT_BYTES = 16 * 1024;
|
|
22
|
+
async function provedRead(client, target) {
|
|
23
|
+
const read = await client.agentGet(target.agentId);
|
|
24
|
+
return read.ok === true && read.value.verification === "verified" && read.value.location?.pane === target.paneId && (target.session === void 0 || read.value.contextSession === target.session) ? read.value : void 0;
|
|
25
|
+
}
|
|
26
|
+
async function inspectRadarChild(client, target) {
|
|
27
|
+
const before = await provedRead(client, target);
|
|
28
|
+
if (before === void 0)
|
|
29
|
+
throw new Error("Inspection target identity did not match");
|
|
30
|
+
const output = await client.output({
|
|
31
|
+
pane_id: target.paneId,
|
|
32
|
+
source: "recent_unwrapped",
|
|
33
|
+
lines: INSPECTION_LINES
|
|
34
|
+
});
|
|
35
|
+
if (output.ok === false)
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Inspection output unavailable (${output.code}: ${output.message})`
|
|
38
|
+
);
|
|
39
|
+
const foreground = await client.processInfo({ pane_id: target.paneId });
|
|
40
|
+
const after = await provedRead(client, target);
|
|
41
|
+
if (after === void 0)
|
|
42
|
+
throw new Error("Inspection target changed during capture");
|
|
43
|
+
const lines = output.value.text.trim().split(/\r?\n/).slice(-INSPECTION_LINES);
|
|
44
|
+
const bounded2 = utf8Tail(lines.join("\n"), INSPECTION_OUTPUT_BYTES);
|
|
45
|
+
return Object.freeze({
|
|
46
|
+
capturedAt: Date.now(),
|
|
47
|
+
recentOutputTruncated: output.value.truncated || bounded2.truncated,
|
|
48
|
+
...bounded2.text ? { recentOutput: bounded2.text } : {},
|
|
49
|
+
...foreground.ok === true ? { foreground: foreground.value } : {},
|
|
50
|
+
...after.activity !== void 0 ? { activity: after.activity } : {}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function utf8Tail(value, maxBytes) {
|
|
54
|
+
const bytes = Buffer.from(value);
|
|
55
|
+
if (bytes.length <= maxBytes) return { text: value, truncated: false };
|
|
56
|
+
let start = bytes.length - maxBytes;
|
|
57
|
+
while (start < bytes.length && (bytes[start] & 192) === 128) start++;
|
|
58
|
+
return { text: bytes.subarray(start).toString(), truncated: true };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// extension/radar-launch.ts
|
|
62
|
+
var radar_launch_exports = {};
|
|
63
|
+
__export(radar_launch_exports, {
|
|
64
|
+
launchFailure: () => launchFailure,
|
|
65
|
+
launchRadarWorker: () => launchRadarWorker,
|
|
66
|
+
observeRadarChild: () => observeRadarChild,
|
|
67
|
+
readProcessGone: () => readProcessGone,
|
|
68
|
+
relaunchRefusalForChild: () => relaunchRefusalForChild,
|
|
69
|
+
waitForChild: () => waitForChild
|
|
70
|
+
});
|
|
71
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
72
|
+
|
|
7
73
|
// extension/radar-client.ts
|
|
8
74
|
var radar_client_exports = {};
|
|
9
75
|
__export(radar_client_exports, {
|
|
@@ -11,6 +77,7 @@ __export(radar_client_exports, {
|
|
|
11
77
|
RADAR_COMMUNICATION_CONTRACT: () => RADAR_COMMUNICATION_CONTRACT,
|
|
12
78
|
RADAR_EVENTS_CONTRACT: () => RADAR_EVENTS_CONTRACT,
|
|
13
79
|
RADAR_EVENT_RETRY_MS: () => RADAR_EVENT_RETRY_MS,
|
|
80
|
+
RADAR_LIFECYCLE_RESTART_CONTRACT: () => RADAR_LIFECYCLE_RESTART_CONTRACT,
|
|
14
81
|
RADAR_MAX_AWAITED: () => RADAR_MAX_AWAITED,
|
|
15
82
|
RADAR_MAX_BACKGROUND_TASKS: () => RADAR_MAX_BACKGROUND_TASKS,
|
|
16
83
|
RADAR_MAX_LINE_BYTES: () => RADAR_MAX_LINE_BYTES,
|
|
@@ -40,12 +107,13 @@ import { lstatSync } from "node:fs";
|
|
|
40
107
|
import { createConnection } from "node:net";
|
|
41
108
|
import { dirname, join } from "node:path";
|
|
42
109
|
var RADAR_PROTOCOL_VERSION = 2;
|
|
43
|
-
var RADAR_MINIMUM_REVISION =
|
|
110
|
+
var RADAR_MINIMUM_REVISION = 8;
|
|
44
111
|
var RADAR_REGISTRY_CONTRACT = "registry.v1";
|
|
45
112
|
var RADAR_REGISTRY_FACTS_CONTRACT = "registry.facts.v1";
|
|
46
113
|
var RADAR_SPAWN_CONTRACT = "spawn.v1";
|
|
47
114
|
var RADAR_SPAWN_LIST_CONTRACT = "spawn.list.v1";
|
|
48
115
|
var RADAR_SPAWN_CLOSE_CONTRACT = "spawn.close.v1";
|
|
116
|
+
var RADAR_LIFECYCLE_RESTART_CONTRACT = "lifecycle.restart.v1";
|
|
49
117
|
var RADAR_SPAWN_LAUNCH_CONTEXT_CONTRACT = "spawn.launch_context.v1";
|
|
50
118
|
var RADAR_EVENTS_CONTRACT = "events.v1";
|
|
51
119
|
var RADAR_COMMUNICATION_CONTRACT = "communication.handoff.v1";
|
|
@@ -351,7 +419,11 @@ function spawnEdge(value) {
|
|
|
351
419
|
const source = stringAt(bound, "source");
|
|
352
420
|
const incarnation = stringAt(bound, "incarnation");
|
|
353
421
|
const agentId = stringAt(bound, "registration_id");
|
|
422
|
+
const subjectId = stringAt(bound, "subject_id");
|
|
354
423
|
const exit = exitAt(recordAt(value, "exit_observation"));
|
|
424
|
+
const withdrawnRecord = recordAt(value, "withdrawn");
|
|
425
|
+
const withdrawnAt = stringAt(withdrawnRecord, "at");
|
|
426
|
+
const withdrawnReason = stringAt(withdrawnRecord, "reason");
|
|
355
427
|
return {
|
|
356
428
|
ok: true,
|
|
357
429
|
value: {
|
|
@@ -364,10 +436,13 @@ function spawnEdge(value) {
|
|
|
364
436
|
bound: {
|
|
365
437
|
source,
|
|
366
438
|
incarnation,
|
|
367
|
-
...isUuid(agentId) ? { registration_id: agentId } : {}
|
|
439
|
+
...isUuid(agentId) ? { registration_id: agentId } : {},
|
|
440
|
+
...isUuid(subjectId) ? { subject_id: subjectId } : {}
|
|
368
441
|
}
|
|
369
442
|
} : {},
|
|
370
|
-
...exit !== void 0 ? { exit_observation: exit } : {}
|
|
443
|
+
...exit !== void 0 ? { exit_observation: exit } : {},
|
|
444
|
+
...stringAt(value, "granted_at") !== void 0 ? { granted_at: stringAt(value, "granted_at") } : {},
|
|
445
|
+
...withdrawnAt !== void 0 && withdrawnReason !== void 0 ? { withdrawn: { at: withdrawnAt, reason: withdrawnReason } } : {}
|
|
371
446
|
}
|
|
372
447
|
};
|
|
373
448
|
}
|
|
@@ -436,6 +511,8 @@ function spawnTopology(value) {
|
|
|
436
511
|
function spawnRequestShape(request) {
|
|
437
512
|
if (!isUuid(request.request_id))
|
|
438
513
|
return "spawn requires a canonical request UUID";
|
|
514
|
+
if (request.continue_subject_id !== void 0 && !isUuid(request.continue_subject_id))
|
|
515
|
+
return "continue_subject_id must be a canonical UUID";
|
|
439
516
|
if (!isUuid(request.parent))
|
|
440
517
|
return "spawn requires the parent's canonical agent UUID";
|
|
441
518
|
if (!isUuid(request.parent_session_id))
|
|
@@ -902,7 +979,8 @@ function createRadarClient(options = {}) {
|
|
|
902
979
|
argv: request.argv,
|
|
903
980
|
...request.cwd !== void 0 ? { cwd: request.cwd } : {},
|
|
904
981
|
...carriesContext && request.env !== void 0 ? { env: request.env } : {},
|
|
905
|
-
...request.managed !== void 0 ? { managed: request.managed } : {}
|
|
982
|
+
...request.managed !== void 0 ? { managed: request.managed } : {},
|
|
983
|
+
...request.continue_subject_id !== void 0 ? { continue_subject_id: request.continue_subject_id } : {}
|
|
906
984
|
},
|
|
907
985
|
requester
|
|
908
986
|
},
|
|
@@ -930,6 +1008,37 @@ function createRadarClient(options = {}) {
|
|
|
930
1008
|
}
|
|
931
1009
|
);
|
|
932
1010
|
},
|
|
1011
|
+
async restart(request) {
|
|
1012
|
+
if (!isUuid(request.request_id) || !isUuid(request.parent) || !isUuid(request.subject_id))
|
|
1013
|
+
return {
|
|
1014
|
+
ok: false,
|
|
1015
|
+
code: "bad_params",
|
|
1016
|
+
message: "restart requires canonical request, parent and subject UUIDs"
|
|
1017
|
+
};
|
|
1018
|
+
return withContract(RADAR_LIFECYCLE_RESTART_CONTRACT, async () => {
|
|
1019
|
+
const answer = await call(
|
|
1020
|
+
"lifecycle.restart",
|
|
1021
|
+
{
|
|
1022
|
+
request: {
|
|
1023
|
+
subject_id: request.subject_id,
|
|
1024
|
+
parent: request.parent,
|
|
1025
|
+
executable: request.executable,
|
|
1026
|
+
argv: request.argv,
|
|
1027
|
+
...request.cwd !== void 0 ? { cwd: request.cwd } : {},
|
|
1028
|
+
...request.env !== void 0 ? { env: request.env } : {}
|
|
1029
|
+
},
|
|
1030
|
+
requester
|
|
1031
|
+
},
|
|
1032
|
+
request.request_id
|
|
1033
|
+
);
|
|
1034
|
+
if (answer.ok === false) return answer;
|
|
1035
|
+
const settled = focusOutcome(recordAt(answer.value, "request"), request.request_id);
|
|
1036
|
+
if (settled.ok === false) return settled;
|
|
1037
|
+
const launch = recordAt(recordAt(answer.value, "request"), "launch_request_id");
|
|
1038
|
+
if (!isUuid(launch)) return protocol("lifecycle.restart reply names no launch");
|
|
1039
|
+
return { ok: true, value: { ...settled.value, launch_request_id: launch } };
|
|
1040
|
+
});
|
|
1041
|
+
},
|
|
933
1042
|
async spawnList(request) {
|
|
934
1043
|
const registrationId = processRegistrationId;
|
|
935
1044
|
if (registrationId === void 0)
|
|
@@ -1297,6 +1406,357 @@ function boundedRadarSnapshot(snapshot) {
|
|
|
1297
1406
|
};
|
|
1298
1407
|
}
|
|
1299
1408
|
|
|
1409
|
+
// extension/radar-launch.ts
|
|
1410
|
+
function unknownChild(reason) {
|
|
1411
|
+
return { kind: "unknown", diagnostic: trajectory(reason) };
|
|
1412
|
+
}
|
|
1413
|
+
function trajectory(reason) {
|
|
1414
|
+
return `the daemon's current record of this launch's child is ${reason}`;
|
|
1415
|
+
}
|
|
1416
|
+
async function observeRadarChild(client, provenance) {
|
|
1417
|
+
if (provenance.registration_id === void 0)
|
|
1418
|
+
return unknownChild("not bound to a child by this launch");
|
|
1419
|
+
if (provenance.pane_id === void 0)
|
|
1420
|
+
return unknownChild("without a pane this launch recorded for it");
|
|
1421
|
+
const read = await client.spawnGet(provenance.request_id);
|
|
1422
|
+
if (read.ok === false)
|
|
1423
|
+
return unknownChild(
|
|
1424
|
+
`not readable (${read.code}: ${read.message})`
|
|
1425
|
+
);
|
|
1426
|
+
const topology = read.value;
|
|
1427
|
+
const edge = topology.edge;
|
|
1428
|
+
if (edge.bound === void 0 || edge.bound.registration_id === void 0)
|
|
1429
|
+
return unknownChild("not bound to a child by the daemon");
|
|
1430
|
+
if (edge.bound.registration_id !== provenance.registration_id)
|
|
1431
|
+
return unknownChild(
|
|
1432
|
+
`bound to another subject (${edge.bound.registration_id}), not to ${provenance.registration_id}`
|
|
1433
|
+
);
|
|
1434
|
+
if (edge.location?.pane === void 0)
|
|
1435
|
+
return unknownChild("recorded without a pane");
|
|
1436
|
+
if (edge.location.pane !== provenance.pane_id)
|
|
1437
|
+
return unknownChild(
|
|
1438
|
+
`recorded on pane ${edge.location.pane}, not on ${provenance.pane_id}`
|
|
1439
|
+
);
|
|
1440
|
+
if (edge.exit_observation?.state !== "unknown")
|
|
1441
|
+
return unknownChild("recorded with an observed process exit");
|
|
1442
|
+
if (topology.freshness !== "fresh")
|
|
1443
|
+
return unknownChild(
|
|
1444
|
+
"on a pane the daemon's own inventory does not currently report"
|
|
1445
|
+
);
|
|
1446
|
+
if (topology.state !== "bound")
|
|
1447
|
+
return unknownChild(
|
|
1448
|
+
`not currently placed (state ${topology.state ?? "unreported"})`
|
|
1449
|
+
);
|
|
1450
|
+
const reply = await client.agentGet(edge.bound.registration_id);
|
|
1451
|
+
if (reply.ok === false)
|
|
1452
|
+
return unknownChild(
|
|
1453
|
+
`process verdict not readable (${reply.code}: ${reply.message})`
|
|
1454
|
+
);
|
|
1455
|
+
const { verification, location, contextSession } = reply.value;
|
|
1456
|
+
if (verification === "absent" || verification === "mismatched")
|
|
1457
|
+
return {
|
|
1458
|
+
kind: "gone",
|
|
1459
|
+
verification,
|
|
1460
|
+
diagnostic: trajectory(`the registered process is ${verification}`)
|
|
1461
|
+
};
|
|
1462
|
+
if (verification !== "verified")
|
|
1463
|
+
return unknownChild(`process verdict is ${verification}`);
|
|
1464
|
+
if (location?.pane !== provenance.pane_id)
|
|
1465
|
+
return unknownChild(
|
|
1466
|
+
`registered on ${location?.pane ?? "no pane"}, not on ${provenance.pane_id}`
|
|
1467
|
+
);
|
|
1468
|
+
if (provenance.session_id === void 0)
|
|
1469
|
+
return unknownChild("without a session this launch recorded for it");
|
|
1470
|
+
if (contextSession !== provenance.session_id)
|
|
1471
|
+
return unknownChild(
|
|
1472
|
+
`publishing session ${contextSession ?? "none"}, not ${provenance.session_id}`
|
|
1473
|
+
);
|
|
1474
|
+
return {
|
|
1475
|
+
kind: "live",
|
|
1476
|
+
evidence: {
|
|
1477
|
+
request_id: provenance.request_id,
|
|
1478
|
+
registration_id: edge.bound.registration_id,
|
|
1479
|
+
source: edge.bound.source,
|
|
1480
|
+
incarnation: edge.bound.incarnation,
|
|
1481
|
+
pane_id: edge.location.pane
|
|
1482
|
+
}
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
async function readProcessGone(client, agentId) {
|
|
1486
|
+
const read = await client.agentGet(agentId);
|
|
1487
|
+
if (read.ok === false) return void 0;
|
|
1488
|
+
const { verification } = read.value;
|
|
1489
|
+
return verification === "absent" || verification === "mismatched" ? verification : void 0;
|
|
1490
|
+
}
|
|
1491
|
+
async function relaunchRefusalForChild(client, agentId) {
|
|
1492
|
+
const read = await client.agentGet(agentId);
|
|
1493
|
+
if (read.ok === false)
|
|
1494
|
+
return `the child's process cannot be read (${read.code}: ${read.message})`;
|
|
1495
|
+
const { verification } = read.value;
|
|
1496
|
+
if (verification === "absent" || verification === "mismatched") return void 0;
|
|
1497
|
+
return `the child's registered process is ${verification === "verified" ? "still running" : "not proved gone"}`;
|
|
1498
|
+
}
|
|
1499
|
+
function refusedLaunch(message) {
|
|
1500
|
+
return { kind: "failed", message };
|
|
1501
|
+
}
|
|
1502
|
+
function unresolvedLaunch(requestId, message) {
|
|
1503
|
+
return {
|
|
1504
|
+
kind: "unresolved",
|
|
1505
|
+
request_id: requestId,
|
|
1506
|
+
message: `spawn ${requestId} is unresolved (${message})`
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
var PRE_EFFECT_CODES = [
|
|
1510
|
+
"absent",
|
|
1511
|
+
"unsupported",
|
|
1512
|
+
"bad_version",
|
|
1513
|
+
"bad_request",
|
|
1514
|
+
"bad_params",
|
|
1515
|
+
"unknown_method",
|
|
1516
|
+
"refused",
|
|
1517
|
+
"not_found",
|
|
1518
|
+
"busy",
|
|
1519
|
+
"backend_unavailable"
|
|
1520
|
+
];
|
|
1521
|
+
function launchFailure(result, requestId) {
|
|
1522
|
+
return PRE_EFFECT_CODES.includes(result.code) ? refusedLaunch(result.message) : unresolvedLaunch(requestId, result.message);
|
|
1523
|
+
}
|
|
1524
|
+
async function launchRadarWorker(options) {
|
|
1525
|
+
const { client, launch, signal } = options;
|
|
1526
|
+
const pollMs = options.pollMs ?? 250;
|
|
1527
|
+
const parent = await options.publication.subject();
|
|
1528
|
+
if (parent === void 0 || !isUuid(parent.registration_id))
|
|
1529
|
+
return refusedLaunch(
|
|
1530
|
+
"this process has no Radar registration, so a worker cannot be spawned under it"
|
|
1531
|
+
);
|
|
1532
|
+
if (parent.subject_id === void 0 || !isUuid(parent.subject_id))
|
|
1533
|
+
return refusedLaunch(
|
|
1534
|
+
"this process has no managed Radar subject, so a worker cannot be spawned under it"
|
|
1535
|
+
);
|
|
1536
|
+
const pane = parent.location?.pane;
|
|
1537
|
+
if (pane === void 0 || pane === "")
|
|
1538
|
+
return refusedLaunch(
|
|
1539
|
+
"this process's Radar registration names no pane, so a worker cannot be placed beside it"
|
|
1540
|
+
);
|
|
1541
|
+
if (pane !== launch.pane_id)
|
|
1542
|
+
return refusedLaunch(
|
|
1543
|
+
`this process's Radar registration places it in pane ${pane}, not in the pane this launch would split`
|
|
1544
|
+
);
|
|
1545
|
+
const spawned = await client.spawn({
|
|
1546
|
+
request_id: launch.request_id,
|
|
1547
|
+
parent: parent.registration_id,
|
|
1548
|
+
parent_session_id: launch.parent_session_id,
|
|
1549
|
+
executable: launch.executable,
|
|
1550
|
+
managed: { parent_subject_id: parent.subject_id },
|
|
1551
|
+
...launch.continues !== void 0 ? { continue_subject_id: launch.continues } : {},
|
|
1552
|
+
argv: launch.argv,
|
|
1553
|
+
...launch.cwd !== "" ? { cwd: launch.cwd } : {},
|
|
1554
|
+
...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
|
|
1555
|
+
});
|
|
1556
|
+
if (spawned.ok === false) {
|
|
1557
|
+
const refusal = launchFailure(spawned, launch.request_id);
|
|
1558
|
+
if (refusal.kind === "failed") return refusal;
|
|
1559
|
+
}
|
|
1560
|
+
const bound = await waitForChild(client, launch.request_id, {
|
|
1561
|
+
pollMs,
|
|
1562
|
+
...signal !== void 0 ? { signal } : {}
|
|
1563
|
+
});
|
|
1564
|
+
if (bound.kind !== "bound") return bound;
|
|
1565
|
+
return {
|
|
1566
|
+
kind: "ready",
|
|
1567
|
+
value: {
|
|
1568
|
+
request_id: launch.request_id,
|
|
1569
|
+
subject_id: bound.subject_id,
|
|
1570
|
+
pane_id: bound.pane_id
|
|
1571
|
+
}
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
async function waitForChild(client, requestId, options) {
|
|
1575
|
+
let last = "the daemon has not answered";
|
|
1576
|
+
for (; ; ) {
|
|
1577
|
+
if (options.signal?.aborted)
|
|
1578
|
+
return unresolvedLaunch(requestId, `the launch was cancelled (${last})`);
|
|
1579
|
+
const answer = await client.spawnGet(requestId);
|
|
1580
|
+
if (answer.ok === true) {
|
|
1581
|
+
const { edge } = answer.value;
|
|
1582
|
+
if (edge.withdrawn !== void 0)
|
|
1583
|
+
return refusedLaunch(`the daemon withdrew this launch: ${edge.withdrawn.reason}`);
|
|
1584
|
+
if (edge.granted_at === void 0) {
|
|
1585
|
+
await delay(options.pollMs);
|
|
1586
|
+
continue;
|
|
1587
|
+
}
|
|
1588
|
+
const pane = edge.location?.pane;
|
|
1589
|
+
if (pane === void 0 || pane === "")
|
|
1590
|
+
return unresolvedLaunch(
|
|
1591
|
+
requestId,
|
|
1592
|
+
"the daemon's launch recorded no pane to verify the child against"
|
|
1593
|
+
);
|
|
1594
|
+
const agentId = edge.bound?.registration_id;
|
|
1595
|
+
if (agentId !== void 0 && isUuid(agentId)) {
|
|
1596
|
+
const subjectId = edge.bound?.subject_id;
|
|
1597
|
+
if (subjectId === void 0 || !isUuid(subjectId))
|
|
1598
|
+
return unresolvedLaunch(
|
|
1599
|
+
requestId,
|
|
1600
|
+
`the daemon bound the child ${agentId} without recording its subject`
|
|
1601
|
+
);
|
|
1602
|
+
return {
|
|
1603
|
+
kind: "bound",
|
|
1604
|
+
subject_id: subjectId,
|
|
1605
|
+
pane_id: pane
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
last = "no child has registered with this launch's token yet";
|
|
1609
|
+
} else {
|
|
1610
|
+
return unresolvedLaunch(requestId, answer.message);
|
|
1611
|
+
}
|
|
1612
|
+
await delay(options.pollMs);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
// extension/radar-children.ts
|
|
1617
|
+
var PAGE = 100;
|
|
1618
|
+
var MAX_PAGES = 20;
|
|
1619
|
+
function createRadarChildren(client, publication) {
|
|
1620
|
+
const held = /* @__PURE__ */ new Map();
|
|
1621
|
+
async function resolveAll() {
|
|
1622
|
+
const newest = /* @__PURE__ */ new Map();
|
|
1623
|
+
let after;
|
|
1624
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
1625
|
+
const read = await client.spawnList({ ...after !== void 0 ? { after } : {}, limit: PAGE });
|
|
1626
|
+
if (read.ok === false) return read;
|
|
1627
|
+
for (const edge of read.value.spawns) {
|
|
1628
|
+
const bound = edge.bound;
|
|
1629
|
+
if (!bound?.subject_id || !bound.registration_id || edge.granted_at == null || edge.withdrawn != null) continue;
|
|
1630
|
+
const at = Date.parse(bound.bound_at);
|
|
1631
|
+
if (Number.isNaN(at)) continue;
|
|
1632
|
+
const current = newest.get(bound.subject_id);
|
|
1633
|
+
if (current !== void 0 && current.at >= at) continue;
|
|
1634
|
+
newest.set(bound.subject_id, {
|
|
1635
|
+
at,
|
|
1636
|
+
registration_id: bound.registration_id,
|
|
1637
|
+
child: {
|
|
1638
|
+
subject_id: bound.subject_id,
|
|
1639
|
+
request_id: edge.request_id,
|
|
1640
|
+
...edge.location?.pane ? { pane_id: edge.location.pane } : {},
|
|
1641
|
+
state: edge.state,
|
|
1642
|
+
exited: edge.exit_observation != null && edge.exit_observation.state !== "unknown"
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
if (!read.value.next) return { ok: true, value: newest };
|
|
1647
|
+
after = read.value.next;
|
|
1648
|
+
}
|
|
1649
|
+
return { ok: false, code: "protocol", message: "the caller's launches exceed the readable pages" };
|
|
1650
|
+
}
|
|
1651
|
+
async function resolve2(subject) {
|
|
1652
|
+
const all = await resolveAll();
|
|
1653
|
+
return all.ok ? all.value.get(subject) : void 0;
|
|
1654
|
+
}
|
|
1655
|
+
async function resolveAndFollow(subject) {
|
|
1656
|
+
const all = await resolveAll();
|
|
1657
|
+
if (!all.ok) return void 0;
|
|
1658
|
+
follow(all.value);
|
|
1659
|
+
return all.value.get(subject);
|
|
1660
|
+
}
|
|
1661
|
+
function follow(all) {
|
|
1662
|
+
for (const [subject, entry] of held) {
|
|
1663
|
+
const target = all.get(subject);
|
|
1664
|
+
if (target !== void 0 && entry.published !== target.registration_id)
|
|
1665
|
+
entry.publish?.(target);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
return {
|
|
1669
|
+
async list() {
|
|
1670
|
+
const all = await resolveAll();
|
|
1671
|
+
if (!all.ok) return all;
|
|
1672
|
+
follow(all.value);
|
|
1673
|
+
return { ok: true, value: [...all.value.values()].map((entry) => entry.child) };
|
|
1674
|
+
},
|
|
1675
|
+
async restart(subject, program, options) {
|
|
1676
|
+
const parent = await publication.subject();
|
|
1677
|
+
if (parent?.subject_id === void 0)
|
|
1678
|
+
return { kind: "failed", message: "this process has no Radar registration to restart a child under" };
|
|
1679
|
+
const request_id = randomUUID2();
|
|
1680
|
+
const requested = await client.restart({
|
|
1681
|
+
request_id,
|
|
1682
|
+
parent: parent.registration_id,
|
|
1683
|
+
subject_id: subject,
|
|
1684
|
+
...program
|
|
1685
|
+
});
|
|
1686
|
+
if (requested.ok === false)
|
|
1687
|
+
return launchFailure(requested, request_id);
|
|
1688
|
+
const bound = await waitForChild(client, requested.value.launch_request_id, {
|
|
1689
|
+
pollMs: options?.pollMs ?? 250,
|
|
1690
|
+
...options?.signal !== void 0 ? { signal: options.signal } : {}
|
|
1691
|
+
});
|
|
1692
|
+
if (bound.kind !== "bound") return bound;
|
|
1693
|
+
await resolveAndFollow(subject);
|
|
1694
|
+
return {
|
|
1695
|
+
kind: "ready",
|
|
1696
|
+
value: {
|
|
1697
|
+
request_id: requested.value.launch_request_id,
|
|
1698
|
+
subject_id: bound.subject_id,
|
|
1699
|
+
pane_id: bound.pane_id
|
|
1700
|
+
}
|
|
1701
|
+
};
|
|
1702
|
+
},
|
|
1703
|
+
assignment(subject, owner) {
|
|
1704
|
+
const existing = held.get(subject);
|
|
1705
|
+
if (existing !== void 0) return existing.writer;
|
|
1706
|
+
let latest;
|
|
1707
|
+
const entry = { writer: void 0 };
|
|
1708
|
+
const send = (target) => {
|
|
1709
|
+
if (latest === void 0) return;
|
|
1710
|
+
if (entry.published !== void 0 && entry.published !== target.registration_id)
|
|
1711
|
+
publication.retireAssignment(entry.published);
|
|
1712
|
+
entry.published = target.registration_id;
|
|
1713
|
+
publication.assignment(target.registration_id, owner).update(latest);
|
|
1714
|
+
};
|
|
1715
|
+
entry.publish = send;
|
|
1716
|
+
entry.writer = {
|
|
1717
|
+
update(snapshot) {
|
|
1718
|
+
latest = snapshot;
|
|
1719
|
+
void resolve2(subject).then((target) => {
|
|
1720
|
+
if (target !== void 0) send(target);
|
|
1721
|
+
});
|
|
1722
|
+
},
|
|
1723
|
+
retire() {
|
|
1724
|
+
latest = void 0;
|
|
1725
|
+
if (entry.published !== void 0) publication.retireAssignment(entry.published);
|
|
1726
|
+
entry.published = void 0;
|
|
1727
|
+
}
|
|
1728
|
+
};
|
|
1729
|
+
held.set(subject, entry);
|
|
1730
|
+
return entry.writer;
|
|
1731
|
+
},
|
|
1732
|
+
retire(subject) {
|
|
1733
|
+
held.get(subject)?.writer.retire();
|
|
1734
|
+
held.delete(subject);
|
|
1735
|
+
},
|
|
1736
|
+
async observe(subject, session_id) {
|
|
1737
|
+
const target = await resolveAndFollow(subject);
|
|
1738
|
+
if (target === void 0)
|
|
1739
|
+
return { kind: "unknown", diagnostic: "the daemon records no bound launch for this child" };
|
|
1740
|
+
return observeRadarChild(client, {
|
|
1741
|
+
request_id: target.child.request_id,
|
|
1742
|
+
pane_id: target.child.pane_id,
|
|
1743
|
+
registration_id: target.registration_id,
|
|
1744
|
+
session_id
|
|
1745
|
+
});
|
|
1746
|
+
},
|
|
1747
|
+
async inspect(subject, session_id) {
|
|
1748
|
+
const target = await resolveAndFollow(subject);
|
|
1749
|
+
if (target?.child.pane_id === void 0)
|
|
1750
|
+
throw new Error("Inspection target is not a bound child with a pane");
|
|
1751
|
+
return inspectRadarChild(client, {
|
|
1752
|
+
agentId: target.registration_id,
|
|
1753
|
+
paneId: target.child.pane_id,
|
|
1754
|
+
...session_id !== void 0 ? { session: session_id } : {}
|
|
1755
|
+
});
|
|
1756
|
+
}
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1300
1760
|
// extension/radar-communication.ts
|
|
1301
1761
|
var radar_communication_exports = {};
|
|
1302
1762
|
__export(radar_communication_exports, {
|
|
@@ -1361,7 +1821,7 @@ __export(radar_publication_exports, {
|
|
|
1361
1821
|
radarProcessSlot: () => radarProcessSlot,
|
|
1362
1822
|
readProcessBirth: () => readProcessBirth
|
|
1363
1823
|
});
|
|
1364
|
-
import { createHash, randomUUID as
|
|
1824
|
+
import { createHash, randomUUID as randomUUID3 } from "node:crypto";
|
|
1365
1825
|
import {
|
|
1366
1826
|
closeSync,
|
|
1367
1827
|
constants,
|
|
@@ -1491,7 +1951,7 @@ function createPublicationStore(root) {
|
|
|
1491
1951
|
ensureDirectory(directory);
|
|
1492
1952
|
const temporary = join2(
|
|
1493
1953
|
directory,
|
|
1494
|
-
`.${name.slice(name.lastIndexOf("/") + 1)}.${
|
|
1954
|
+
`.${name.slice(name.lastIndexOf("/") + 1)}.${randomUUID3()}.tmp`
|
|
1495
1955
|
);
|
|
1496
1956
|
const bytes = Buffer.from(JSON.stringify(value), "utf8");
|
|
1497
1957
|
if (bytes.length > MAX_RECORD_BYTES)
|
|
@@ -1547,7 +2007,7 @@ function radarProcessSlot() {
|
|
|
1547
2007
|
return host[PROCESS_SLOT];
|
|
1548
2008
|
}
|
|
1549
2009
|
function radarProcessIncarnation(slot = radarProcessSlot()) {
|
|
1550
|
-
return slot.incarnation ??=
|
|
2010
|
+
return slot.incarnation ??= randomUUID3();
|
|
1551
2011
|
}
|
|
1552
2012
|
function radarBindingKey(run, owner, label) {
|
|
1553
2013
|
return createHash("sha256").update(`${run}\0${owner}\0${label}`).digest("hex").slice(0, 32);
|
|
@@ -2015,7 +2475,7 @@ function createPresenceReporter(input) {
|
|
|
2015
2475
|
releases.push({ registration_id: state.registration_id, claim_id: state.claim_id });
|
|
2016
2476
|
}
|
|
2017
2477
|
standing = void 0;
|
|
2018
|
-
state = { version: 2, session, claim_id:
|
|
2478
|
+
state = { version: 2, session, claim_id: randomUUID3(), releases };
|
|
2019
2479
|
save();
|
|
2020
2480
|
stopped = false;
|
|
2021
2481
|
void ensure();
|
|
@@ -2052,7 +2512,7 @@ var STORE_IDENTITY = /* @__PURE__ */ new WeakMap();
|
|
|
2052
2512
|
function storeIdentity(store) {
|
|
2053
2513
|
const known = STORE_IDENTITY.get(store);
|
|
2054
2514
|
if (known !== void 0) return known;
|
|
2055
|
-
const created =
|
|
2515
|
+
const created = randomUUID3();
|
|
2056
2516
|
STORE_IDENTITY.set(store, created);
|
|
2057
2517
|
return created;
|
|
2058
2518
|
}
|
|
@@ -2579,63 +3039,6 @@ function createRadarExecutionAdapter(pi, options) {
|
|
|
2579
3039
|
};
|
|
2580
3040
|
}
|
|
2581
3041
|
|
|
2582
|
-
// extension/radar-inspection.ts
|
|
2583
|
-
var radar_inspection_exports = {};
|
|
2584
|
-
__export(radar_inspection_exports, {
|
|
2585
|
-
inspectRadarChild: () => inspectRadarChild,
|
|
2586
|
-
provedRead: () => provedRead
|
|
2587
|
-
});
|
|
2588
|
-
var INSPECTION_LINES = 80;
|
|
2589
|
-
var INSPECTION_OUTPUT_BYTES = 16 * 1024;
|
|
2590
|
-
async function provedRead(client, target) {
|
|
2591
|
-
const read = await client.agentGet(target.agentId);
|
|
2592
|
-
return read.ok === true && read.value.verification === "verified" && read.value.location?.pane === target.paneId && (target.session === void 0 || read.value.contextSession === target.session) ? read.value : void 0;
|
|
2593
|
-
}
|
|
2594
|
-
async function inspectRadarChild(client, target) {
|
|
2595
|
-
const before = await provedRead(client, target);
|
|
2596
|
-
if (before === void 0)
|
|
2597
|
-
throw new Error("Inspection target identity did not match");
|
|
2598
|
-
const output = await client.output({
|
|
2599
|
-
pane_id: target.paneId,
|
|
2600
|
-
source: "recent_unwrapped",
|
|
2601
|
-
lines: INSPECTION_LINES
|
|
2602
|
-
});
|
|
2603
|
-
if (output.ok === false)
|
|
2604
|
-
throw new Error(
|
|
2605
|
-
`Inspection output unavailable (${output.code}: ${output.message})`
|
|
2606
|
-
);
|
|
2607
|
-
const foreground = await client.processInfo({ pane_id: target.paneId });
|
|
2608
|
-
const after = await provedRead(client, target);
|
|
2609
|
-
if (after === void 0)
|
|
2610
|
-
throw new Error("Inspection target changed during capture");
|
|
2611
|
-
const lines = output.value.text.trim().split(/\r?\n/).slice(-INSPECTION_LINES);
|
|
2612
|
-
const bounded2 = utf8Tail(lines.join("\n"), INSPECTION_OUTPUT_BYTES);
|
|
2613
|
-
return Object.freeze({
|
|
2614
|
-
capturedAt: Date.now(),
|
|
2615
|
-
recentOutputTruncated: output.value.truncated || bounded2.truncated,
|
|
2616
|
-
...bounded2.text ? { recentOutput: bounded2.text } : {},
|
|
2617
|
-
...foreground.ok === true ? { foreground: foreground.value } : {},
|
|
2618
|
-
...after.activity !== void 0 ? { activity: after.activity } : {}
|
|
2619
|
-
});
|
|
2620
|
-
}
|
|
2621
|
-
function utf8Tail(value, maxBytes) {
|
|
2622
|
-
const bytes = Buffer.from(value);
|
|
2623
|
-
if (bytes.length <= maxBytes) return { text: value, truncated: false };
|
|
2624
|
-
let start = bytes.length - maxBytes;
|
|
2625
|
-
while (start < bytes.length && (bytes[start] & 192) === 128) start++;
|
|
2626
|
-
return { text: bytes.subarray(start).toString(), truncated: true };
|
|
2627
|
-
}
|
|
2628
|
-
|
|
2629
|
-
// extension/radar-launch.ts
|
|
2630
|
-
var radar_launch_exports = {};
|
|
2631
|
-
__export(radar_launch_exports, {
|
|
2632
|
-
launchRadarWorker: () => launchRadarWorker,
|
|
2633
|
-
observeRadarChild: () => observeRadarChild,
|
|
2634
|
-
readProcessGone: () => readProcessGone,
|
|
2635
|
-
relaunchRefusalForChild: () => relaunchRefusalForChild
|
|
2636
|
-
});
|
|
2637
|
-
import { setTimeout as delay } from "node:timers/promises";
|
|
2638
|
-
|
|
2639
3042
|
// extension/radar-location.ts
|
|
2640
3043
|
var radar_location_exports = {};
|
|
2641
3044
|
__export(radar_location_exports, {
|
|
@@ -2753,280 +3156,6 @@ async function resolveRadarProcessLocation(client, env = process.env) {
|
|
|
2753
3156
|
};
|
|
2754
3157
|
}
|
|
2755
3158
|
|
|
2756
|
-
// extension/radar-launch.ts
|
|
2757
|
-
function unknownChild(reason) {
|
|
2758
|
-
return { kind: "unknown", diagnostic: trajectory(reason) };
|
|
2759
|
-
}
|
|
2760
|
-
function trajectory(reason) {
|
|
2761
|
-
return `the daemon's current record of this launch's child is ${reason}`;
|
|
2762
|
-
}
|
|
2763
|
-
async function observeRadarChild(client, provenance) {
|
|
2764
|
-
if (provenance.registration_id === void 0)
|
|
2765
|
-
return unknownChild("not bound to a child by this launch");
|
|
2766
|
-
if (provenance.pane_id === void 0)
|
|
2767
|
-
return unknownChild("without a pane this launch recorded for it");
|
|
2768
|
-
const read = await client.spawnGet(provenance.request_id);
|
|
2769
|
-
if (read.ok === false)
|
|
2770
|
-
return unknownChild(
|
|
2771
|
-
`not readable (${read.code}: ${read.message})`
|
|
2772
|
-
);
|
|
2773
|
-
const topology = read.value;
|
|
2774
|
-
const edge = topology.edge;
|
|
2775
|
-
if (edge.bound === void 0 || edge.bound.registration_id === void 0)
|
|
2776
|
-
return unknownChild("not bound to a child by the daemon");
|
|
2777
|
-
if (edge.bound.registration_id !== provenance.registration_id)
|
|
2778
|
-
return unknownChild(
|
|
2779
|
-
`bound to another subject (${edge.bound.registration_id}), not to ${provenance.registration_id}`
|
|
2780
|
-
);
|
|
2781
|
-
if (edge.location?.pane === void 0)
|
|
2782
|
-
return unknownChild("recorded without a pane");
|
|
2783
|
-
if (edge.location.pane !== provenance.pane_id)
|
|
2784
|
-
return unknownChild(
|
|
2785
|
-
`recorded on pane ${edge.location.pane}, not on ${provenance.pane_id}`
|
|
2786
|
-
);
|
|
2787
|
-
if (edge.exit_observation?.state !== "unknown")
|
|
2788
|
-
return unknownChild("recorded with an observed process exit");
|
|
2789
|
-
if (topology.freshness !== "fresh")
|
|
2790
|
-
return unknownChild(
|
|
2791
|
-
"on a pane the daemon's own inventory does not currently report"
|
|
2792
|
-
);
|
|
2793
|
-
if (topology.state !== "bound")
|
|
2794
|
-
return unknownChild(
|
|
2795
|
-
`not currently placed (state ${topology.state ?? "unreported"})`
|
|
2796
|
-
);
|
|
2797
|
-
const reply = await client.agentGet(edge.bound.registration_id);
|
|
2798
|
-
if (reply.ok === false)
|
|
2799
|
-
return unknownChild(
|
|
2800
|
-
`process verdict not readable (${reply.code}: ${reply.message})`
|
|
2801
|
-
);
|
|
2802
|
-
const { verification, location, contextSession } = reply.value;
|
|
2803
|
-
if (verification === "absent" || verification === "mismatched")
|
|
2804
|
-
return {
|
|
2805
|
-
kind: "gone",
|
|
2806
|
-
verification,
|
|
2807
|
-
diagnostic: trajectory(`the registered process is ${verification}`)
|
|
2808
|
-
};
|
|
2809
|
-
if (verification !== "verified")
|
|
2810
|
-
return unknownChild(`process verdict is ${verification}`);
|
|
2811
|
-
if (location?.pane !== provenance.pane_id)
|
|
2812
|
-
return unknownChild(
|
|
2813
|
-
`registered on ${location?.pane ?? "no pane"}, not on ${provenance.pane_id}`
|
|
2814
|
-
);
|
|
2815
|
-
if (provenance.session_id === void 0)
|
|
2816
|
-
return unknownChild("without a session this launch recorded for it");
|
|
2817
|
-
if (contextSession !== provenance.session_id)
|
|
2818
|
-
return unknownChild(
|
|
2819
|
-
`publishing session ${contextSession ?? "none"}, not ${provenance.session_id}`
|
|
2820
|
-
);
|
|
2821
|
-
return {
|
|
2822
|
-
kind: "live",
|
|
2823
|
-
evidence: {
|
|
2824
|
-
request_id: provenance.request_id,
|
|
2825
|
-
registration_id: edge.bound.registration_id,
|
|
2826
|
-
source: edge.bound.source,
|
|
2827
|
-
incarnation: edge.bound.incarnation,
|
|
2828
|
-
pane_id: edge.location.pane
|
|
2829
|
-
}
|
|
2830
|
-
};
|
|
2831
|
-
}
|
|
2832
|
-
async function readProcessGone(client, agentId) {
|
|
2833
|
-
const read = await client.agentGet(agentId);
|
|
2834
|
-
if (read.ok === false) return void 0;
|
|
2835
|
-
const { verification } = read.value;
|
|
2836
|
-
return verification === "absent" || verification === "mismatched" ? verification : void 0;
|
|
2837
|
-
}
|
|
2838
|
-
async function relaunchRefusalForChild(client, agentId) {
|
|
2839
|
-
const read = await client.agentGet(agentId);
|
|
2840
|
-
if (read.ok === false)
|
|
2841
|
-
return `the child's process cannot be read (${read.code}: ${read.message})`;
|
|
2842
|
-
const { verification } = read.value;
|
|
2843
|
-
if (verification === "absent" || verification === "mismatched") return void 0;
|
|
2844
|
-
return `the child's registered process is ${verification === "verified" ? "still running" : "not proved gone"}`;
|
|
2845
|
-
}
|
|
2846
|
-
function refusedLaunch(message) {
|
|
2847
|
-
return { kind: "refused", message };
|
|
2848
|
-
}
|
|
2849
|
-
function unresolvedLaunch(requestId, message) {
|
|
2850
|
-
return {
|
|
2851
|
-
kind: "unresolved",
|
|
2852
|
-
request_id: requestId,
|
|
2853
|
-
message: `spawn ${requestId} is unresolved (${message})`
|
|
2854
|
-
};
|
|
2855
|
-
}
|
|
2856
|
-
function edgeStanding(edge) {
|
|
2857
|
-
if (edge.created === "refused" || edge.launched === "refused")
|
|
2858
|
-
return "refused";
|
|
2859
|
-
return edge.created === "completed" && edge.launched === "completed" ? "launched" : "unknown";
|
|
2860
|
-
}
|
|
2861
|
-
function edgeMessage(edge) {
|
|
2862
|
-
return `the daemon's spawn record is created ${edge.created} and launched ${edge.launched}`;
|
|
2863
|
-
}
|
|
2864
|
-
var PRE_EFFECT_CODES = [
|
|
2865
|
-
"absent",
|
|
2866
|
-
"unsupported",
|
|
2867
|
-
"bad_version",
|
|
2868
|
-
"bad_request",
|
|
2869
|
-
"bad_params",
|
|
2870
|
-
"unknown_method",
|
|
2871
|
-
"refused",
|
|
2872
|
-
"not_found",
|
|
2873
|
-
"busy",
|
|
2874
|
-
"backend_unavailable"
|
|
2875
|
-
];
|
|
2876
|
-
function spawnFailure(result, requestId) {
|
|
2877
|
-
return PRE_EFFECT_CODES.includes(result.code) ? refusedLaunch(result.message) : unresolvedLaunch(requestId, result.message);
|
|
2878
|
-
}
|
|
2879
|
-
async function launchRadarWorker(options) {
|
|
2880
|
-
const { client, launch, signal } = options;
|
|
2881
|
-
const pollMs = options.pollMs ?? 250;
|
|
2882
|
-
const deadline = Date.now() + options.timeoutMs;
|
|
2883
|
-
const remaining = () => Math.max(0, deadline - Date.now());
|
|
2884
|
-
const pane = launch.parent.location?.pane;
|
|
2885
|
-
if (!isUuid(launch.parent.registration_id))
|
|
2886
|
-
return refusedLaunch(
|
|
2887
|
-
"the launch has no exact parent registration to spawn under"
|
|
2888
|
-
);
|
|
2889
|
-
if (!isUuid(launch.parent.subject_id))
|
|
2890
|
-
return refusedLaunch(
|
|
2891
|
-
"the launch has no managed Radar subject for its parent"
|
|
2892
|
-
);
|
|
2893
|
-
if (pane === void 0 || pane === "")
|
|
2894
|
-
return refusedLaunch(
|
|
2895
|
-
"this process's Radar registration names no pane, so it cannot be a spawn parent"
|
|
2896
|
-
);
|
|
2897
|
-
const spawned = await client.spawn({
|
|
2898
|
-
request_id: launch.request_id,
|
|
2899
|
-
parent: launch.parent.registration_id,
|
|
2900
|
-
parent_session_id: launch.parent_session_id,
|
|
2901
|
-
executable: launch.executable,
|
|
2902
|
-
managed: { parent_subject_id: launch.parent.subject_id },
|
|
2903
|
-
argv: launch.argv,
|
|
2904
|
-
...launch.cwd !== "" ? { cwd: launch.cwd } : {},
|
|
2905
|
-
...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
|
|
2906
|
-
});
|
|
2907
|
-
if (spawned.ok === false) {
|
|
2908
|
-
const refusal = spawnFailure(spawned, launch.request_id);
|
|
2909
|
-
if (refusal.kind === "refused") return refusal;
|
|
2910
|
-
}
|
|
2911
|
-
if (spawned.ok === true) {
|
|
2912
|
-
const standing = edgeStanding(spawned.value);
|
|
2913
|
-
if (standing === "refused")
|
|
2914
|
-
return refusedLaunch(edgeMessage(spawned.value));
|
|
2915
|
-
if (standing === "unknown")
|
|
2916
|
-
return unresolvedLaunch(launch.request_id, edgeMessage(spawned.value));
|
|
2917
|
-
}
|
|
2918
|
-
const bound = await waitForChild(client, launch.request_id, {
|
|
2919
|
-
remaining,
|
|
2920
|
-
pollMs,
|
|
2921
|
-
...signal !== void 0 ? { signal } : {}
|
|
2922
|
-
});
|
|
2923
|
-
if (bound.kind !== "bound") return bound;
|
|
2924
|
-
const agentId = bound.registration_id;
|
|
2925
|
-
if (launch.onBound !== void 0) {
|
|
2926
|
-
try {
|
|
2927
|
-
launch.onBound({ registration_id: agentId, pane_id: bound.pane_id });
|
|
2928
|
-
} catch (error) {
|
|
2929
|
-
return unresolvedLaunch(
|
|
2930
|
-
launch.request_id,
|
|
2931
|
-
`the daemon's binding of the child ${agentId} could not be recorded (${String(error)})`
|
|
2932
|
-
);
|
|
2933
|
-
}
|
|
2934
|
-
}
|
|
2935
|
-
try {
|
|
2936
|
-
const state = await options.readers.waitForState(
|
|
2937
|
-
launch.mailbox,
|
|
2938
|
-
(candidate) => options.readers.startupAckMatches(candidate, {
|
|
2939
|
-
generation: launch.generation,
|
|
2940
|
-
runId: launch.identity.runId,
|
|
2941
|
-
ownerSessionId: launch.identity.ownerSessionId,
|
|
2942
|
-
workspaceId: launch.identity.workspaceId,
|
|
2943
|
-
agentLabel: launch.identity.agentLabel,
|
|
2944
|
-
// The child writes the raw TMUX_PANE of the pane it runs in. Requiring
|
|
2945
|
-
// the pane the daemon created is what refuses a child that inherited
|
|
2946
|
-
// another process's coordinates.
|
|
2947
|
-
paneId: radarPaneHandle(bound.pane_id)
|
|
2948
|
-
}) && (launch.observedChildAgent === void 0 || launch.observedChildAgent() === agentId),
|
|
2949
|
-
{ timeoutMs: remaining(), ...signal !== void 0 ? { signal } : {} }
|
|
2950
|
-
);
|
|
2951
|
-
return {
|
|
2952
|
-
kind: "ready",
|
|
2953
|
-
value: {
|
|
2954
|
-
request_id: launch.request_id,
|
|
2955
|
-
registration_id: agentId,
|
|
2956
|
-
pane_id: bound.pane_id,
|
|
2957
|
-
bound_process: {
|
|
2958
|
-
source: bound.source,
|
|
2959
|
-
incarnation: bound.incarnation
|
|
2960
|
-
},
|
|
2961
|
-
state
|
|
2962
|
-
}
|
|
2963
|
-
};
|
|
2964
|
-
} catch (error) {
|
|
2965
|
-
const claimed = options.readers.readState(launch.mailbox)?.paneId;
|
|
2966
|
-
return unresolvedLaunch(
|
|
2967
|
-
launch.request_id,
|
|
2968
|
-
claimed !== void 0 && claimed !== radarPaneHandle(bound.pane_id) ? `the bound child ${agentId} claims the pane ${claimed}, not the pane ${bound.pane_id} this launch created for it` : `the bound child ${agentId} has not acknowledged this launch's startup (${String(error)})`
|
|
2969
|
-
);
|
|
2970
|
-
}
|
|
2971
|
-
}
|
|
2972
|
-
async function waitForChild(client, requestId, options) {
|
|
2973
|
-
let last = "the daemon has not answered";
|
|
2974
|
-
for (; ; ) {
|
|
2975
|
-
if (options.signal?.aborted)
|
|
2976
|
-
return unresolvedLaunch(requestId, `the launch was cancelled (${last})`);
|
|
2977
|
-
const answer = await client.spawnGet(requestId);
|
|
2978
|
-
if (answer.ok === true) {
|
|
2979
|
-
const { edge, state, freshness } = answer.value;
|
|
2980
|
-
const standing = edgeStanding(edge);
|
|
2981
|
-
if (standing === "refused")
|
|
2982
|
-
return refusedLaunch(`${edgeMessage(edge)}`);
|
|
2983
|
-
if (standing === "unknown")
|
|
2984
|
-
return unresolvedLaunch(requestId, edgeMessage(edge));
|
|
2985
|
-
const pane = edge.location?.pane;
|
|
2986
|
-
if (pane === void 0 || pane === "")
|
|
2987
|
-
return unresolvedLaunch(
|
|
2988
|
-
requestId,
|
|
2989
|
-
"the daemon's launch recorded no pane to verify the child against"
|
|
2990
|
-
);
|
|
2991
|
-
if (freshness !== "fresh")
|
|
2992
|
-
return unresolvedLaunch(
|
|
2993
|
-
requestId,
|
|
2994
|
-
state === "unresolved" ? `the daemon's inventory does not report the pane ${pane} its own record names for this child` : `the daemon cannot confirm the pane ${pane} it recorded for this child`
|
|
2995
|
-
);
|
|
2996
|
-
if (edge.exit_observation?.state === "exited")
|
|
2997
|
-
return unresolvedLaunch(
|
|
2998
|
-
requestId,
|
|
2999
|
-
"the daemon observed the launched child's process exit"
|
|
3000
|
-
);
|
|
3001
|
-
const agentId = edge.bound?.registration_id;
|
|
3002
|
-
if (agentId !== void 0 && isUuid(agentId)) {
|
|
3003
|
-
const source = edge.bound?.source;
|
|
3004
|
-
const incarnation = edge.bound?.incarnation;
|
|
3005
|
-
if (source === void 0 || source === "" || incarnation === void 0 || incarnation === "")
|
|
3006
|
-
return unresolvedLaunch(
|
|
3007
|
-
requestId,
|
|
3008
|
-
`the daemon bound the child ${agentId} without recording the process it registered as`
|
|
3009
|
-
);
|
|
3010
|
-
return {
|
|
3011
|
-
kind: "bound",
|
|
3012
|
-
registration_id: agentId,
|
|
3013
|
-
pane_id: pane,
|
|
3014
|
-
source,
|
|
3015
|
-
incarnation
|
|
3016
|
-
};
|
|
3017
|
-
}
|
|
3018
|
-
last = "no child has registered with this launch's token yet";
|
|
3019
|
-
} else {
|
|
3020
|
-
last = answer.message;
|
|
3021
|
-
}
|
|
3022
|
-
if (options.remaining() <= 0)
|
|
3023
|
-
return unresolvedLaunch(requestId, last);
|
|
3024
|
-
await delay(options.pollMs, void 0, {
|
|
3025
|
-
...options.signal !== void 0 ? { signal: options.signal } : {}
|
|
3026
|
-
});
|
|
3027
|
-
}
|
|
3028
|
-
}
|
|
3029
|
-
|
|
3030
3159
|
// extension/radar-runtime.ts
|
|
3031
3160
|
var radar_runtime_exports = {};
|
|
3032
3161
|
__export(radar_runtime_exports, {
|
|
@@ -3037,7 +3166,7 @@ __export(radar_runtime_exports, {
|
|
|
3037
3166
|
requestRadarRuntime: () => requestRadarRuntime
|
|
3038
3167
|
});
|
|
3039
3168
|
var RADAR_RUNTIME_REQUEST = "pi-radar/runtime-request";
|
|
3040
|
-
var RADAR_RUNTIME_VERSION =
|
|
3169
|
+
var RADAR_RUNTIME_VERSION = 4;
|
|
3041
3170
|
function lazyRadarRuntime(start) {
|
|
3042
3171
|
let pending;
|
|
3043
3172
|
return {
|
|
@@ -3071,6 +3200,7 @@ function isRadarRuntimeHandle(value) {
|
|
|
3071
3200
|
return handle.version === RADAR_RUNTIME_VERSION && typeof handle.start === "function";
|
|
3072
3201
|
}
|
|
3073
3202
|
export {
|
|
3203
|
+
radar_children_exports as children,
|
|
3074
3204
|
radar_client_exports as client,
|
|
3075
3205
|
radar_communication_exports as communication,
|
|
3076
3206
|
radar_execution_exports as execution,
|