pi-radar 0.7.0 → 0.9.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 +10 -0
- package/dist/extension/baseline.js +380 -111
- package/dist/extension/radar-children.js +240 -0
- package/dist/extension/radar-client.js +37 -3
- package/dist/extension/radar-launch.js +23 -24
- package/dist/extension/radar-runtime.js +1 -1
- package/dist/index.js +1779 -1623
- package/extension/baseline.ts +2 -0
- package/extension/generated-contracts.ts +5 -0
- package/extension/radar-children.ts +176 -0
- package/extension/radar-client.ts +56 -2
- package/extension/radar-launch.ts +42 -63
- 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 -1
- package/schema/public/v1/observation-get-response.serialize.schema.json +1 -1
- package/schema/public/v1/observation-snapshot.deserialize.schema.json +1 -1
- package/schema/public/v1/observation-snapshot.serialize.schema.json +1 -1
- package/schema/public/v1/spawn-list-page.deserialize.schema.json +7 -0
- package/schema/public/v1/spawn-list-page.serialize.schema.json +7 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// extension/radar-inspection.ts
|
|
2
|
+
var INSPECTION_LINES = 80;
|
|
3
|
+
var INSPECTION_OUTPUT_BYTES = 16 * 1024;
|
|
4
|
+
async function provedRead(client, target) {
|
|
5
|
+
const read = await client.agentGet(target.agentId);
|
|
6
|
+
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;
|
|
7
|
+
}
|
|
8
|
+
async function inspectRadarChild(client, target) {
|
|
9
|
+
const before = await provedRead(client, target);
|
|
10
|
+
if (before === void 0)
|
|
11
|
+
throw new Error("Inspection target identity did not match");
|
|
12
|
+
const output = await client.output({
|
|
13
|
+
pane_id: target.paneId,
|
|
14
|
+
source: "recent_unwrapped",
|
|
15
|
+
lines: INSPECTION_LINES
|
|
16
|
+
});
|
|
17
|
+
if (output.ok === false)
|
|
18
|
+
throw new Error(
|
|
19
|
+
`Inspection output unavailable (${output.code}: ${output.message})`
|
|
20
|
+
);
|
|
21
|
+
const foreground = await client.processInfo({ pane_id: target.paneId });
|
|
22
|
+
const after = await provedRead(client, target);
|
|
23
|
+
if (after === void 0)
|
|
24
|
+
throw new Error("Inspection target changed during capture");
|
|
25
|
+
const lines = output.value.text.trim().split(/\r?\n/).slice(-INSPECTION_LINES);
|
|
26
|
+
const bounded = utf8Tail(lines.join("\n"), INSPECTION_OUTPUT_BYTES);
|
|
27
|
+
return Object.freeze({
|
|
28
|
+
capturedAt: Date.now(),
|
|
29
|
+
recentOutputTruncated: output.value.truncated || bounded.truncated,
|
|
30
|
+
...bounded.text ? { recentOutput: bounded.text } : {},
|
|
31
|
+
...foreground.ok === true ? { foreground: foreground.value } : {},
|
|
32
|
+
...after.activity !== void 0 ? { activity: after.activity } : {}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function utf8Tail(value, maxBytes) {
|
|
36
|
+
const bytes = Buffer.from(value);
|
|
37
|
+
if (bytes.length <= maxBytes) return { text: value, truncated: false };
|
|
38
|
+
let start = bytes.length - maxBytes;
|
|
39
|
+
while (start < bytes.length && (bytes[start] & 192) === 128) start++;
|
|
40
|
+
return { text: bytes.subarray(start).toString(), truncated: true };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// extension/radar-client.ts
|
|
44
|
+
var RADAR_MAX_LINE_BYTES = 1024 * 1024;
|
|
45
|
+
|
|
46
|
+
// extension/radar-launch.ts
|
|
47
|
+
function unknownChild(reason) {
|
|
48
|
+
return { kind: "unknown", diagnostic: trajectory(reason) };
|
|
49
|
+
}
|
|
50
|
+
function trajectory(reason) {
|
|
51
|
+
return `the daemon's current record of this launch's child is ${reason}`;
|
|
52
|
+
}
|
|
53
|
+
async function observeRadarChild(client, provenance) {
|
|
54
|
+
if (provenance.registration_id === void 0)
|
|
55
|
+
return unknownChild("not bound to a child by this launch");
|
|
56
|
+
if (provenance.pane_id === void 0)
|
|
57
|
+
return unknownChild("without a pane this launch recorded for it");
|
|
58
|
+
const read = await client.spawnGet(provenance.request_id);
|
|
59
|
+
if (read.ok === false)
|
|
60
|
+
return unknownChild(
|
|
61
|
+
`not readable (${read.code}: ${read.message})`
|
|
62
|
+
);
|
|
63
|
+
const topology = read.value;
|
|
64
|
+
const edge = topology.edge;
|
|
65
|
+
if (edge.bound === void 0 || edge.bound.registration_id === void 0)
|
|
66
|
+
return unknownChild("not bound to a child by the daemon");
|
|
67
|
+
if (edge.bound.registration_id !== provenance.registration_id)
|
|
68
|
+
return unknownChild(
|
|
69
|
+
`bound to another subject (${edge.bound.registration_id}), not to ${provenance.registration_id}`
|
|
70
|
+
);
|
|
71
|
+
if (edge.location?.pane === void 0)
|
|
72
|
+
return unknownChild("recorded without a pane");
|
|
73
|
+
if (edge.location.pane !== provenance.pane_id)
|
|
74
|
+
return unknownChild(
|
|
75
|
+
`recorded on pane ${edge.location.pane}, not on ${provenance.pane_id}`
|
|
76
|
+
);
|
|
77
|
+
if (edge.exit_observation?.state !== "unknown")
|
|
78
|
+
return unknownChild("recorded with an observed process exit");
|
|
79
|
+
if (topology.freshness !== "fresh")
|
|
80
|
+
return unknownChild(
|
|
81
|
+
"on a pane the daemon's own inventory does not currently report"
|
|
82
|
+
);
|
|
83
|
+
if (topology.state !== "bound")
|
|
84
|
+
return unknownChild(
|
|
85
|
+
`not currently placed (state ${topology.state ?? "unreported"})`
|
|
86
|
+
);
|
|
87
|
+
const reply = await client.agentGet(edge.bound.registration_id);
|
|
88
|
+
if (reply.ok === false)
|
|
89
|
+
return unknownChild(
|
|
90
|
+
`process verdict not readable (${reply.code}: ${reply.message})`
|
|
91
|
+
);
|
|
92
|
+
const { verification, location, contextSession } = reply.value;
|
|
93
|
+
if (verification === "absent" || verification === "mismatched")
|
|
94
|
+
return {
|
|
95
|
+
kind: "gone",
|
|
96
|
+
verification,
|
|
97
|
+
diagnostic: trajectory(`the registered process is ${verification}`)
|
|
98
|
+
};
|
|
99
|
+
if (verification !== "verified")
|
|
100
|
+
return unknownChild(`process verdict is ${verification}`);
|
|
101
|
+
if (location?.pane !== provenance.pane_id)
|
|
102
|
+
return unknownChild(
|
|
103
|
+
`registered on ${location?.pane ?? "no pane"}, not on ${provenance.pane_id}`
|
|
104
|
+
);
|
|
105
|
+
if (provenance.session_id === void 0)
|
|
106
|
+
return unknownChild("without a session this launch recorded for it");
|
|
107
|
+
if (contextSession !== provenance.session_id)
|
|
108
|
+
return unknownChild(
|
|
109
|
+
`publishing session ${contextSession ?? "none"}, not ${provenance.session_id}`
|
|
110
|
+
);
|
|
111
|
+
return {
|
|
112
|
+
kind: "live",
|
|
113
|
+
evidence: {
|
|
114
|
+
request_id: provenance.request_id,
|
|
115
|
+
registration_id: edge.bound.registration_id,
|
|
116
|
+
source: edge.bound.source,
|
|
117
|
+
incarnation: edge.bound.incarnation,
|
|
118
|
+
pane_id: edge.location.pane
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// extension/radar-children.ts
|
|
124
|
+
var PAGE = 100;
|
|
125
|
+
var MAX_PAGES = 20;
|
|
126
|
+
function createRadarChildren(client, publication) {
|
|
127
|
+
const held = /* @__PURE__ */ new Map();
|
|
128
|
+
async function resolveAll() {
|
|
129
|
+
const newest = /* @__PURE__ */ new Map();
|
|
130
|
+
let after;
|
|
131
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
132
|
+
const read = await client.spawnList({ ...after !== void 0 ? { after } : {}, limit: PAGE });
|
|
133
|
+
if (read.ok === false) return read;
|
|
134
|
+
for (const edge of read.value.spawns) {
|
|
135
|
+
const bound = edge.bound;
|
|
136
|
+
if (!bound?.subject_id || !bound.registration_id || edge.launched !== "completed") continue;
|
|
137
|
+
const at = Date.parse(bound.bound_at);
|
|
138
|
+
if (Number.isNaN(at)) continue;
|
|
139
|
+
const current = newest.get(bound.subject_id);
|
|
140
|
+
if (current !== void 0 && current.at >= at) continue;
|
|
141
|
+
newest.set(bound.subject_id, {
|
|
142
|
+
at,
|
|
143
|
+
registration_id: bound.registration_id,
|
|
144
|
+
child: {
|
|
145
|
+
subject_id: bound.subject_id,
|
|
146
|
+
request_id: edge.request_id,
|
|
147
|
+
...edge.location?.pane ? { pane_id: edge.location.pane } : {},
|
|
148
|
+
state: edge.state,
|
|
149
|
+
exited: edge.exit_observation != null && edge.exit_observation.state !== "unknown"
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (!read.value.next) return { ok: true, value: newest };
|
|
154
|
+
after = read.value.next;
|
|
155
|
+
}
|
|
156
|
+
return { ok: false, code: "protocol", message: "the caller's launches exceed the readable pages" };
|
|
157
|
+
}
|
|
158
|
+
async function resolve(subject) {
|
|
159
|
+
const all = await resolveAll();
|
|
160
|
+
return all.ok ? all.value.get(subject) : void 0;
|
|
161
|
+
}
|
|
162
|
+
async function resolveAndFollow(subject) {
|
|
163
|
+
const all = await resolveAll();
|
|
164
|
+
if (!all.ok) return void 0;
|
|
165
|
+
follow(all.value);
|
|
166
|
+
return all.value.get(subject);
|
|
167
|
+
}
|
|
168
|
+
function follow(all) {
|
|
169
|
+
for (const [subject, entry] of held) {
|
|
170
|
+
const target = all.get(subject);
|
|
171
|
+
if (target !== void 0 && entry.published !== target.registration_id)
|
|
172
|
+
entry.publish?.(target);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
async list() {
|
|
177
|
+
const all = await resolveAll();
|
|
178
|
+
if (!all.ok) return all;
|
|
179
|
+
follow(all.value);
|
|
180
|
+
return { ok: true, value: [...all.value.values()].map((entry) => entry.child) };
|
|
181
|
+
},
|
|
182
|
+
assignment(subject, owner) {
|
|
183
|
+
const existing = held.get(subject);
|
|
184
|
+
if (existing !== void 0) return existing.writer;
|
|
185
|
+
let latest;
|
|
186
|
+
const entry = { writer: void 0 };
|
|
187
|
+
const send = (target) => {
|
|
188
|
+
if (latest === void 0) return;
|
|
189
|
+
if (entry.published !== void 0 && entry.published !== target.registration_id)
|
|
190
|
+
publication.retireAssignment(entry.published);
|
|
191
|
+
entry.published = target.registration_id;
|
|
192
|
+
publication.assignment(target.registration_id, owner).update(latest);
|
|
193
|
+
};
|
|
194
|
+
entry.publish = send;
|
|
195
|
+
entry.writer = {
|
|
196
|
+
update(snapshot) {
|
|
197
|
+
latest = snapshot;
|
|
198
|
+
void resolve(subject).then((target) => {
|
|
199
|
+
if (target !== void 0) send(target);
|
|
200
|
+
});
|
|
201
|
+
},
|
|
202
|
+
retire() {
|
|
203
|
+
latest = void 0;
|
|
204
|
+
if (entry.published !== void 0) publication.retireAssignment(entry.published);
|
|
205
|
+
entry.published = void 0;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
held.set(subject, entry);
|
|
209
|
+
return entry.writer;
|
|
210
|
+
},
|
|
211
|
+
retire(subject) {
|
|
212
|
+
held.get(subject)?.writer.retire();
|
|
213
|
+
held.delete(subject);
|
|
214
|
+
},
|
|
215
|
+
async observe(subject, session_id) {
|
|
216
|
+
const target = await resolveAndFollow(subject);
|
|
217
|
+
if (target === void 0)
|
|
218
|
+
return { kind: "unknown", diagnostic: "the daemon records no bound launch for this child" };
|
|
219
|
+
return observeRadarChild(client, {
|
|
220
|
+
request_id: target.child.request_id,
|
|
221
|
+
pane_id: target.child.pane_id,
|
|
222
|
+
registration_id: target.registration_id,
|
|
223
|
+
session_id
|
|
224
|
+
});
|
|
225
|
+
},
|
|
226
|
+
async inspect(subject, session_id) {
|
|
227
|
+
const target = await resolveAndFollow(subject);
|
|
228
|
+
if (target?.child.pane_id === void 0)
|
|
229
|
+
throw new Error("Inspection target is not a bound child with a pane");
|
|
230
|
+
return inspectRadarChild(client, {
|
|
231
|
+
agentId: target.registration_id,
|
|
232
|
+
paneId: target.child.pane_id,
|
|
233
|
+
...session_id !== void 0 ? { session: session_id } : {}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
export {
|
|
239
|
+
createRadarChildren
|
|
240
|
+
};
|
|
@@ -4,12 +4,13 @@ import { lstatSync } from "node:fs";
|
|
|
4
4
|
import { createConnection } from "node:net";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
var RADAR_PROTOCOL_VERSION = 2;
|
|
7
|
-
var RADAR_MINIMUM_REVISION =
|
|
7
|
+
var RADAR_MINIMUM_REVISION = 7;
|
|
8
8
|
var RADAR_REGISTRY_CONTRACT = "registry.v1";
|
|
9
9
|
var RADAR_REGISTRY_FACTS_CONTRACT = "registry.facts.v1";
|
|
10
10
|
var RADAR_SPAWN_CONTRACT = "spawn.v1";
|
|
11
11
|
var RADAR_SPAWN_LIST_CONTRACT = "spawn.list.v1";
|
|
12
12
|
var RADAR_SPAWN_CLOSE_CONTRACT = "spawn.close.v1";
|
|
13
|
+
var RADAR_LIFECYCLE_RESTART_CONTRACT = "lifecycle.restart.v1";
|
|
13
14
|
var RADAR_SPAWN_LAUNCH_CONTEXT_CONTRACT = "spawn.launch_context.v1";
|
|
14
15
|
var RADAR_EVENTS_CONTRACT = "events.v1";
|
|
15
16
|
var RADAR_COMMUNICATION_CONTRACT = "communication.handoff.v1";
|
|
@@ -315,6 +316,7 @@ function spawnEdge(value) {
|
|
|
315
316
|
const source = stringAt(bound, "source");
|
|
316
317
|
const incarnation = stringAt(bound, "incarnation");
|
|
317
318
|
const agentId = stringAt(bound, "registration_id");
|
|
319
|
+
const subjectId = stringAt(bound, "subject_id");
|
|
318
320
|
const exit = exitAt(recordAt(value, "exit_observation"));
|
|
319
321
|
return {
|
|
320
322
|
ok: true,
|
|
@@ -328,7 +330,8 @@ function spawnEdge(value) {
|
|
|
328
330
|
bound: {
|
|
329
331
|
source,
|
|
330
332
|
incarnation,
|
|
331
|
-
...isUuid(agentId) ? { registration_id: agentId } : {}
|
|
333
|
+
...isUuid(agentId) ? { registration_id: agentId } : {},
|
|
334
|
+
...isUuid(subjectId) ? { subject_id: subjectId } : {}
|
|
332
335
|
}
|
|
333
336
|
} : {},
|
|
334
337
|
...exit !== void 0 ? { exit_observation: exit } : {}
|
|
@@ -400,6 +403,8 @@ function spawnTopology(value) {
|
|
|
400
403
|
function spawnRequestShape(request) {
|
|
401
404
|
if (!isUuid(request.request_id))
|
|
402
405
|
return "spawn requires a canonical request UUID";
|
|
406
|
+
if (request.continue_subject_id !== void 0 && !isUuid(request.continue_subject_id))
|
|
407
|
+
return "continue_subject_id must be a canonical UUID";
|
|
403
408
|
if (!isUuid(request.parent))
|
|
404
409
|
return "spawn requires the parent's canonical agent UUID";
|
|
405
410
|
if (!isUuid(request.parent_session_id))
|
|
@@ -866,7 +871,8 @@ function createRadarClient(options = {}) {
|
|
|
866
871
|
argv: request.argv,
|
|
867
872
|
...request.cwd !== void 0 ? { cwd: request.cwd } : {},
|
|
868
873
|
...carriesContext && request.env !== void 0 ? { env: request.env } : {},
|
|
869
|
-
...request.managed !== void 0 ? { managed: request.managed } : {}
|
|
874
|
+
...request.managed !== void 0 ? { managed: request.managed } : {},
|
|
875
|
+
...request.continue_subject_id !== void 0 ? { continue_subject_id: request.continue_subject_id } : {}
|
|
870
876
|
},
|
|
871
877
|
requester
|
|
872
878
|
},
|
|
@@ -894,6 +900,33 @@ function createRadarClient(options = {}) {
|
|
|
894
900
|
}
|
|
895
901
|
);
|
|
896
902
|
},
|
|
903
|
+
async restart(request) {
|
|
904
|
+
if (!isUuid(request.request_id) || !isUuid(request.parent) || !isUuid(request.subject_id))
|
|
905
|
+
return {
|
|
906
|
+
ok: false,
|
|
907
|
+
code: "bad_params",
|
|
908
|
+
message: "restart requires canonical request, parent and subject UUIDs"
|
|
909
|
+
};
|
|
910
|
+
return withContract(RADAR_LIFECYCLE_RESTART_CONTRACT, async () => {
|
|
911
|
+
const answer = await call(
|
|
912
|
+
"lifecycle.restart",
|
|
913
|
+
{
|
|
914
|
+
request: {
|
|
915
|
+
subject_id: request.subject_id,
|
|
916
|
+
parent: request.parent,
|
|
917
|
+
executable: request.executable,
|
|
918
|
+
argv: request.argv,
|
|
919
|
+
...request.cwd !== void 0 ? { cwd: request.cwd } : {},
|
|
920
|
+
...request.env !== void 0 ? { env: request.env } : {}
|
|
921
|
+
},
|
|
922
|
+
requester
|
|
923
|
+
},
|
|
924
|
+
request.request_id
|
|
925
|
+
);
|
|
926
|
+
if (answer.ok === false) return answer;
|
|
927
|
+
return focusOutcome(recordAt(answer.value, "request"), request.request_id);
|
|
928
|
+
});
|
|
929
|
+
},
|
|
897
930
|
async spawnList(request) {
|
|
898
931
|
const registrationId = processRegistrationId;
|
|
899
932
|
if (registrationId === void 0)
|
|
@@ -1265,6 +1298,7 @@ export {
|
|
|
1265
1298
|
RADAR_COMMUNICATION_CONTRACT,
|
|
1266
1299
|
RADAR_EVENTS_CONTRACT,
|
|
1267
1300
|
RADAR_EVENT_RETRY_MS,
|
|
1301
|
+
RADAR_LIFECYCLE_RESTART_CONTRACT,
|
|
1268
1302
|
RADAR_MAX_AWAITED,
|
|
1269
1303
|
RADAR_MAX_BACKGROUND_TASKS,
|
|
1270
1304
|
RADAR_MAX_LINE_BYTES,
|
|
@@ -141,25 +141,31 @@ async function launchRadarWorker(options) {
|
|
|
141
141
|
const pollMs = options.pollMs ?? 250;
|
|
142
142
|
const deadline = Date.now() + options.timeoutMs;
|
|
143
143
|
const remaining = () => Math.max(0, deadline - Date.now());
|
|
144
|
-
const
|
|
145
|
-
if (!isUuid(
|
|
144
|
+
const parent = await options.publication.subject();
|
|
145
|
+
if (parent === void 0 || !isUuid(parent.registration_id))
|
|
146
146
|
return refusedLaunch(
|
|
147
|
-
"
|
|
147
|
+
"this process has no Radar registration, so a worker cannot be spawned under it"
|
|
148
148
|
);
|
|
149
|
-
if (!isUuid(
|
|
149
|
+
if (parent.subject_id === void 0 || !isUuid(parent.subject_id))
|
|
150
150
|
return refusedLaunch(
|
|
151
|
-
"
|
|
151
|
+
"this process has no managed Radar subject, so a worker cannot be spawned under it"
|
|
152
152
|
);
|
|
153
|
+
const pane = parent.location?.pane;
|
|
153
154
|
if (pane === void 0 || pane === "")
|
|
154
155
|
return refusedLaunch(
|
|
155
|
-
"this process's Radar registration names no pane, so
|
|
156
|
+
"this process's Radar registration names no pane, so a worker cannot be placed beside it"
|
|
157
|
+
);
|
|
158
|
+
if (pane !== launch.pane_id)
|
|
159
|
+
return refusedLaunch(
|
|
160
|
+
`this process's Radar registration places it in pane ${pane}, not in the pane this launch would split`
|
|
156
161
|
);
|
|
157
162
|
const spawned = await client.spawn({
|
|
158
163
|
request_id: launch.request_id,
|
|
159
|
-
parent:
|
|
164
|
+
parent: parent.registration_id,
|
|
160
165
|
parent_session_id: launch.parent_session_id,
|
|
161
166
|
executable: launch.executable,
|
|
162
|
-
managed: { parent_subject_id:
|
|
167
|
+
managed: { parent_subject_id: parent.subject_id },
|
|
168
|
+
...launch.continues !== void 0 ? { continue_subject_id: launch.continues } : {},
|
|
163
169
|
argv: launch.argv,
|
|
164
170
|
...launch.cwd !== "" ? { cwd: launch.cwd } : {},
|
|
165
171
|
...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
|
|
@@ -182,16 +188,6 @@ async function launchRadarWorker(options) {
|
|
|
182
188
|
});
|
|
183
189
|
if (bound.kind !== "bound") return bound;
|
|
184
190
|
const agentId = bound.registration_id;
|
|
185
|
-
if (launch.onBound !== void 0) {
|
|
186
|
-
try {
|
|
187
|
-
launch.onBound({ registration_id: agentId, pane_id: bound.pane_id });
|
|
188
|
-
} catch (error) {
|
|
189
|
-
return unresolvedLaunch(
|
|
190
|
-
launch.request_id,
|
|
191
|
-
`the daemon's binding of the child ${agentId} could not be recorded (${String(error)})`
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
191
|
try {
|
|
196
192
|
const state = await options.readers.waitForState(
|
|
197
193
|
launch.mailbox,
|
|
@@ -205,19 +201,15 @@ async function launchRadarWorker(options) {
|
|
|
205
201
|
// the pane the daemon created is what refuses a child that inherited
|
|
206
202
|
// another process's coordinates.
|
|
207
203
|
paneId: radarPaneHandle(bound.pane_id)
|
|
208
|
-
})
|
|
204
|
+
}),
|
|
209
205
|
{ timeoutMs: remaining(), ...signal !== void 0 ? { signal } : {} }
|
|
210
206
|
);
|
|
211
207
|
return {
|
|
212
208
|
kind: "ready",
|
|
213
209
|
value: {
|
|
214
210
|
request_id: launch.request_id,
|
|
215
|
-
|
|
211
|
+
subject_id: bound.subject_id,
|
|
216
212
|
pane_id: bound.pane_id,
|
|
217
|
-
bound_process: {
|
|
218
|
-
source: bound.source,
|
|
219
|
-
incarnation: bound.incarnation
|
|
220
|
-
},
|
|
221
213
|
state
|
|
222
214
|
}
|
|
223
215
|
};
|
|
@@ -267,8 +259,15 @@ async function waitForChild(client, requestId, options) {
|
|
|
267
259
|
requestId,
|
|
268
260
|
`the daemon bound the child ${agentId} without recording the process it registered as`
|
|
269
261
|
);
|
|
262
|
+
const subjectId = edge.bound?.subject_id;
|
|
263
|
+
if (subjectId === void 0 || !isUuid(subjectId))
|
|
264
|
+
return unresolvedLaunch(
|
|
265
|
+
requestId,
|
|
266
|
+
`the daemon bound the child ${agentId} without recording its subject`
|
|
267
|
+
);
|
|
270
268
|
return {
|
|
271
269
|
kind: "bound",
|
|
270
|
+
subject_id: subjectId,
|
|
272
271
|
registration_id: agentId,
|
|
273
272
|
pane_id: pane,
|
|
274
273
|
source,
|