pi-radar 0.2.0 → 0.4.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.
Files changed (42) hide show
  1. package/README.md +10 -4
  2. package/dist/extension/baseline.js +333 -394
  3. package/dist/extension/radar-client.js +126 -11
  4. package/dist/extension/radar-communication.js +39 -0
  5. package/dist/extension/radar-execution.js +169 -382
  6. package/dist/extension/radar-launch.js +18 -13
  7. package/dist/extension/radar-publication.js +161 -298
  8. package/dist/extension/radar-runtime.js +1 -1
  9. package/dist/index.js +356 -407
  10. package/extension/baseline.ts +2 -0
  11. package/extension/generated-contracts.ts +1310 -10
  12. package/extension/radar-client.ts +191 -23
  13. package/extension/radar-communication.ts +66 -0
  14. package/extension/radar-execution.ts +11 -58
  15. package/extension/radar-launch.ts +29 -22
  16. package/extension/radar-publication.ts +211 -410
  17. package/extension/radar-runtime.ts +4 -1
  18. package/index.ts +1 -0
  19. package/package.json +9 -5
  20. package/schema/public/v1/handoff-inbox.deserialize.schema.json +18 -0
  21. package/schema/public/v1/handoff-inbox.serialize.schema.json +18 -0
  22. package/schema/public/v1/handoff-publish-params.deserialize.schema.json +33 -0
  23. package/schema/public/v1/handoff-publish-params.serialize.schema.json +33 -0
  24. package/schema/public/v1/handoff-receipt.deserialize.schema.json +66 -0
  25. package/schema/public/v1/handoff-receipt.serialize.schema.json +66 -0
  26. package/schema/public/v1/handoff.deserialize.schema.json +84 -0
  27. package/schema/public/v1/handoff.serialize.schema.json +84 -0
  28. package/schema/public/v1/observation-get-params.deserialize.schema.json +46 -0
  29. package/schema/public/v1/observation-get-params.serialize.schema.json +52 -0
  30. package/schema/public/v1/observation-get-response.deserialize.schema.json +2731 -0
  31. package/schema/public/v1/observation-get-response.serialize.schema.json +2862 -0
  32. package/schema/public/v1/observation-snapshot.deserialize.schema.json +2616 -0
  33. package/schema/public/v1/observation-snapshot.serialize.schema.json +2741 -0
  34. package/schema/public/v1/presence-answer.deserialize.schema.json +40 -0
  35. package/schema/public/v1/presence-answer.serialize.schema.json +40 -0
  36. package/schema/public/v1/presence-release.deserialize.schema.json +51 -0
  37. package/schema/public/v1/presence-release.serialize.schema.json +52 -0
  38. package/schema/public/v1/presence-report.deserialize.schema.json +149 -0
  39. package/schema/public/v1/presence-report.serialize.schema.json +157 -0
  40. package/extension/radar-session-marker.ts +0 -146
  41. package/schema/public/v1/launch-identity-marker.deserialize.schema.json +0 -32
  42. package/schema/public/v1/launch-identity-marker.serialize.schema.json +0 -32
@@ -46,7 +46,7 @@ export type LaunchMailbox<State extends LaunchState> = {
46
46
  * the child's exact command into it, and still reports that pane in its own
47
47
  * inventory;
48
48
  * 2. a child registered with the launch's private token, so the edge names the
49
- * exact `agent_id` that child obtained — never a label, pane or session;
49
+ * exact `registration_id` that child obtained — never a label, pane or session;
50
50
  * 3. that child wrote a fresh startup acknowledgment for this launch generation
51
51
  * after Herdsman startup finished, naming the pane the daemon created as its
52
52
  * own location.
@@ -64,9 +64,11 @@ export type LaunchMailbox<State extends LaunchState> = {
64
64
  * different leaves the launch unresolved rather than placed.
65
65
  */
66
66
 
67
- /** The exact parent this launch may use, and nothing inferred about it. */
67
+ /** The exact managed parent this launch may use, and nothing inferred about it. */
68
68
  export type RadarLaunchParent = {
69
- agent_id: string;
69
+ registration_id: string;
70
+ /** Stable subject from this process's current Radar registration. */
71
+ subject_id: string;
70
72
  location?: RadarLocation;
71
73
  };
72
74
 
@@ -107,12 +109,12 @@ export type RadarWorkerLaunch = {
107
109
  * because a binding that was not persisted is one no later reader can hold the
108
110
  * child by.
109
111
  */
110
- onBound?: (bound: { agent_id: string; pane_id: string }) => void;
112
+ onBound?: (bound: { registration_id: string; pane_id: string }) => void;
111
113
  };
112
114
 
113
115
  export type RadarWorkerLaunched<State = unknown> = {
114
116
  request_id: string;
115
- agent_id: string;
117
+ registration_id: string;
116
118
  pane_id: string;
117
119
  /**
118
120
  * The process the daemon bound this launch's edge to, taken from that same
@@ -141,7 +143,7 @@ export type RadarLaunchOutcome<State = unknown> =
141
143
  */
142
144
  export type RadarChildEvidence = {
143
145
  request_id: string;
144
- agent_id: string;
146
+ registration_id: string;
145
147
  source: string;
146
148
  incarnation: string;
147
149
  pane_id: string;
@@ -190,12 +192,12 @@ export async function observeRadarChild(
190
192
  provenance: {
191
193
  request_id: string;
192
194
  pane_id: string | undefined;
193
- agent_id: string | undefined;
195
+ registration_id: string | undefined;
194
196
  /** The session this launch's mailbox records for the child. */
195
197
  session_id: string | undefined;
196
198
  },
197
199
  ): Promise<RadarChildObservation> {
198
- if (provenance.agent_id === undefined)
200
+ if (provenance.registration_id === undefined)
199
201
  return unknownChild("not bound to a child by this launch");
200
202
  // A launch that recorded no pane has nothing to compare the daemon's read
201
203
  // against: the child's own claim about where it runs is not where the launch
@@ -209,11 +211,11 @@ export async function observeRadarChild(
209
211
  );
210
212
  const topology = read.value;
211
213
  const edge = topology.edge;
212
- if (edge.bound === undefined || edge.bound.agent_id === undefined)
214
+ if (edge.bound === undefined || edge.bound.registration_id === undefined)
213
215
  return unknownChild("not bound to a child by the daemon");
214
- if (edge.bound.agent_id !== provenance.agent_id)
216
+ if (edge.bound.registration_id !== provenance.registration_id)
215
217
  return unknownChild(
216
- `bound to another subject (${edge.bound.agent_id}), not to ${provenance.agent_id}`,
218
+ `bound to another subject (${edge.bound.registration_id}), not to ${provenance.registration_id}`,
217
219
  );
218
220
  if (edge.location?.pane === undefined)
219
221
  return unknownChild("recorded without a pane");
@@ -239,7 +241,7 @@ export async function observeRadarChild(
239
241
  // The edge says where the child was bound, not that its process still runs.
240
242
  // The registry's verdict on the bound subject, and the location it registered
241
243
  // with, are what prove the child live.
242
- const reply = await client.agentGet(edge.bound.agent_id);
244
+ const reply = await client.agentGet(edge.bound.registration_id);
243
245
  if (reply.ok === false)
244
246
  return unknownChild(
245
247
  `process verdict not readable (${reply.code}: ${reply.message})`,
@@ -269,7 +271,7 @@ export async function observeRadarChild(
269
271
  kind: "live",
270
272
  evidence: {
271
273
  request_id: provenance.request_id,
272
- agent_id: edge.bound.agent_id,
274
+ registration_id: edge.bound.registration_id,
273
275
  source: edge.bound.source,
274
276
  incarnation: edge.bound.incarnation,
275
277
  pane_id: edge.location.pane,
@@ -391,10 +393,14 @@ export async function launchRadarWorker<State extends LaunchState>(
391
393
  const deadline = Date.now() + options.timeoutMs;
392
394
  const remaining = (): number => Math.max(0, deadline - Date.now());
393
395
  const pane = launch.parent.location?.pane;
394
- if (!isUuid(launch.parent.agent_id))
396
+ if (!isUuid(launch.parent.registration_id))
395
397
  return refusedLaunch(
396
398
  "the launch has no exact parent registration to spawn under",
397
399
  );
400
+ if (!isUuid(launch.parent.subject_id))
401
+ return refusedLaunch(
402
+ "the launch has no managed Radar subject for its parent",
403
+ );
398
404
  // A spawn is created under the pane its parent registered, and this port
399
405
  // registers no location it was not given: without one there is nothing to
400
406
  // place the child beside, and a name or session lookup is not a substitute.
@@ -405,9 +411,10 @@ export async function launchRadarWorker<State extends LaunchState>(
405
411
 
406
412
  const spawned = await client.spawn({
407
413
  request_id: launch.request_id,
408
- parent: launch.parent.agent_id,
414
+ parent: launch.parent.registration_id,
409
415
  parent_session_id: launch.parent_session_id,
410
416
  executable: launch.executable,
417
+ managed: { parent_subject_id: launch.parent.subject_id },
411
418
  argv: launch.argv,
412
419
  ...(launch.cwd !== "" ? { cwd: launch.cwd } : {}),
413
420
  ...(Object.keys(launch.env).length > 0 ? { env: launch.env } : {}),
@@ -430,13 +437,13 @@ export async function launchRadarWorker<State extends LaunchState>(
430
437
  ...(signal !== undefined ? { signal } : {}),
431
438
  });
432
439
  if (bound.kind !== "bound") return bound;
433
- const agentId = bound.agent_id;
440
+ const agentId = bound.registration_id;
434
441
  // The binding is recorded before the readiness wait, not after it: the child
435
442
  // may never acknowledge, and the subject and pane the daemon named are still
436
443
  // what a reload has to prove this child by.
437
444
  if (launch.onBound !== undefined) {
438
445
  try {
439
- launch.onBound({ agent_id: agentId, pane_id: bound.pane_id });
446
+ launch.onBound({ registration_id: agentId, pane_id: bound.pane_id });
440
447
  } catch (error) {
441
448
  return unresolvedLaunch(
442
449
  launch.request_id,
@@ -468,7 +475,7 @@ export async function launchRadarWorker<State extends LaunchState>(
468
475
  kind: "ready",
469
476
  value: {
470
477
  request_id: launch.request_id,
471
- agent_id: agentId,
478
+ registration_id: agentId,
472
479
  pane_id: bound.pane_id,
473
480
  bound_process: {
474
481
  source: bound.source,
@@ -491,7 +498,7 @@ export async function launchRadarWorker<State extends LaunchState>(
491
498
  type BoundChild =
492
499
  | {
493
500
  kind: "bound";
494
- agent_id: string;
501
+ registration_id: string;
495
502
  pane_id: string;
496
503
  source: string;
497
504
  incarnation: string;
@@ -502,7 +509,7 @@ type BoundChild =
502
509
  * Poll the edge this request id authored until a child presents its token.
503
510
  *
504
511
  * The daemon binds the edge once, to the exact registration the token produced,
505
- * so `bound.agent_id` is the child identity. A refusal or an unknown launch
512
+ * so `bound.registration_id` is the child identity. A refusal or an unknown launch
506
513
  * effect ends the wait at once: neither becomes a child by waiting longer. An
507
514
  * edge whose recorded pane the daemon no longer reports ends it too: waiting
508
515
  * cannot create the pane a launch claims, and a location read afterwards would
@@ -552,7 +559,7 @@ async function waitForChild(
552
559
  requestId,
553
560
  "the daemon observed the launched child's process exit",
554
561
  );
555
- const agentId = edge.bound?.agent_id;
562
+ const agentId = edge.bound?.registration_id;
556
563
  if (agentId !== undefined && isUuid(agentId)) {
557
564
  // A child the daemon bound without the process it registered as is a
558
565
  // child no assignment can be addressed to, and an unaddressed Radar
@@ -572,7 +579,7 @@ async function waitForChild(
572
579
  );
573
580
  return {
574
581
  kind: "bound",
575
- agent_id: agentId,
582
+ registration_id: agentId,
576
583
  pane_id: pane,
577
584
  source,
578
585
  incarnation,