pi-radar 0.3.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 (36) hide show
  1. package/README.md +4 -2
  2. package/dist/extension/baseline.js +227 -402
  3. package/dist/extension/radar-client.js +53 -13
  4. package/dist/extension/radar-communication.js +5 -5
  5. package/dist/extension/radar-execution.js +168 -383
  6. package/dist/extension/radar-launch.js +13 -13
  7. package/dist/extension/radar-publication.js +160 -299
  8. package/dist/index.js +239 -414
  9. package/extension/generated-contracts.ts +1249 -13
  10. package/extension/radar-client.ts +92 -29
  11. package/extension/radar-communication.ts +5 -5
  12. package/extension/radar-execution.ts +11 -58
  13. package/extension/radar-launch.ts +21 -21
  14. package/extension/radar-publication.ts +209 -412
  15. package/package.json +3 -4
  16. package/schema/public/v1/handoff-publish-params.deserialize.schema.json +2 -2
  17. package/schema/public/v1/handoff-publish-params.serialize.schema.json +2 -2
  18. package/schema/public/v1/handoff-receipt.deserialize.schema.json +4 -4
  19. package/schema/public/v1/handoff-receipt.serialize.schema.json +4 -4
  20. package/schema/public/v1/handoff.deserialize.schema.json +4 -4
  21. package/schema/public/v1/handoff.serialize.schema.json +4 -4
  22. package/schema/public/v1/observation-get-params.deserialize.schema.json +46 -0
  23. package/schema/public/v1/observation-get-params.serialize.schema.json +52 -0
  24. package/schema/public/v1/observation-get-response.deserialize.schema.json +2731 -0
  25. package/schema/public/v1/observation-get-response.serialize.schema.json +2862 -0
  26. package/schema/public/v1/observation-snapshot.deserialize.schema.json +2616 -0
  27. package/schema/public/v1/observation-snapshot.serialize.schema.json +2741 -0
  28. package/schema/public/v1/presence-answer.deserialize.schema.json +40 -0
  29. package/schema/public/v1/presence-answer.serialize.schema.json +40 -0
  30. package/schema/public/v1/presence-release.deserialize.schema.json +51 -0
  31. package/schema/public/v1/presence-release.serialize.schema.json +52 -0
  32. package/schema/public/v1/presence-report.deserialize.schema.json +149 -0
  33. package/schema/public/v1/presence-report.serialize.schema.json +157 -0
  34. package/extension/radar-session-marker.ts +0 -146
  35. package/schema/public/v1/launch-identity-marker.deserialize.schema.json +0 -32
  36. package/schema/public/v1/launch-identity-marker.serialize.schema.json +0 -32
@@ -1,5 +1,100 @@
1
1
  // Generated from the checked-in Rust-derived JSON Schemas. Do not edit.
2
2
 
3
+ export interface PresenceReportDeserialize {
4
+ claim_id: string;
5
+ incarnation: string;
6
+ label?: string | null;
7
+ location?: PresenceReportRegistryLocation | null;
8
+ owner?: string | null;
9
+ process: PresenceReportProcessIdentity;
10
+ registration_id?: string | null;
11
+ run?: string | null;
12
+ session_id: string;
13
+ source: string;
14
+ spawn_token?: string | null;
15
+ subject_id?: string | null;
16
+ }
17
+ /**
18
+ * Where an agent's incarnation lives on one backend, in that backend's own
19
+ * coordinates.
20
+ *
21
+ * The backend name is free-form so a source Radar does not ship yet is
22
+ * preserved rather than rejected; the rest are the coordinates as reported, and
23
+ * each is optional because a backend need not name every level.
24
+ */
25
+ export interface PresenceReportRegistryLocation {
26
+ backend: string;
27
+ instance?: string | null;
28
+ pane?: string | null;
29
+ tab?: string | null;
30
+ workspace?: string | null;
31
+ }
32
+ /**
33
+ * Which process incarnation a sample belongs to.
34
+ *
35
+ * The kernel reuses process ids, so a pid does not name a process: one
36
+ * incarnation is the boot it started in, its pid, and when it started. Those
37
+ * are what make two readings comparable — counters may only be subtracted
38
+ * from an earlier reading of the same identity, and a difference taken across
39
+ * two of them measures neither process.
40
+ */
41
+ export interface PresenceReportProcessIdentity {
42
+ /**
43
+ * The boot this process started in, as the kernel reports it.
44
+ */
45
+ boot_id: string;
46
+ /**
47
+ * The process id, unique within one boot and one incarnation of it.
48
+ */
49
+ pid: number;
50
+ /**
51
+ * Start time since boot, in clock ticks (`starttime` in
52
+ * `/proc/<pid>/stat`): the kernel's stamp for this incarnation.
53
+ */
54
+ start_ticks: number;
55
+ [k: string]: unknown;
56
+ }
57
+ export type PresenceAnswerStanding = "pending" | "granted" | "duplicate" | "released";
58
+
59
+ /**
60
+ * The small public receipt; session/location context stays inside Radar.
61
+ */
62
+ export interface PresenceAnswerSerialize {
63
+ claim_id: string;
64
+ registration_id: string;
65
+ standing: PresenceAnswerStanding;
66
+ subject_id?: string | null;
67
+ }
68
+ export interface PresenceReleaseDeserialize {
69
+ claim_id: string;
70
+ process: PresenceReleaseProcessIdentity;
71
+ registration_id: string;
72
+ }
73
+ /**
74
+ * Which process incarnation a sample belongs to.
75
+ *
76
+ * The kernel reuses process ids, so a pid does not name a process: one
77
+ * incarnation is the boot it started in, its pid, and when it started. Those
78
+ * are what make two readings comparable — counters may only be subtracted
79
+ * from an earlier reading of the same identity, and a difference taken across
80
+ * two of them measures neither process.
81
+ */
82
+ export interface PresenceReleaseProcessIdentity {
83
+ /**
84
+ * The boot this process started in, as the kernel reports it.
85
+ */
86
+ boot_id: string;
87
+ /**
88
+ * The process id, unique within one boot and one incarnation of it.
89
+ */
90
+ pid: number;
91
+ /**
92
+ * Start time since boot, in clock ticks (`starttime` in
93
+ * `/proc/<pid>/stat`): the kernel's stamp for this incarnation.
94
+ */
95
+ start_ticks: number;
96
+ [k: string]: unknown;
97
+ }
3
98
  /**
4
99
  * `daemon.ping` result. Contract names remain strings so older clients can
5
100
  * preserve and ignore names introduced by newer daemon builds.
@@ -27,7 +122,7 @@ export interface HandoffPublishParamsDeserialize {
27
122
  content: string;
28
123
  correlation_id?: string | null;
29
124
  recipient_subject_id: string;
30
- sender_agent_id: string;
125
+ sender_registration_id: string;
31
126
  summary: string;
32
127
  }
33
128
  /**
@@ -56,9 +151,9 @@ export interface HandoffSerialize {
56
151
  * generation identify the exact execution that took the action.
57
152
  */
58
153
  export interface HandoffIdentity {
59
- agent_id: string;
60
154
  execution_generation: number;
61
155
  execution_id: string;
156
+ registration_id: string;
62
157
  session_id: string;
63
158
  subject_id: string;
64
159
  }
@@ -77,9 +172,9 @@ export interface HandoffReceiptSerialize {
77
172
  * generation identify the exact execution that took the action.
78
173
  */
79
174
  export interface HandoffIdentity {
80
- agent_id: string;
81
175
  execution_generation: number;
82
176
  execution_id: string;
177
+ registration_id: string;
83
178
  session_id: string;
84
179
  subject_id: string;
85
180
  }
@@ -94,16 +189,6 @@ export interface ManagedLaunchMetadataDeserialize {
94
189
  role?: string | null;
95
190
  run?: string | null;
96
191
  }
97
- /**
98
- * A non-secret Pi-session breadcrumb issued by Radar. This is correlation
99
- * evidence only and cannot establish lifecycle authority.
100
- */
101
- export interface LaunchIdentityMarkerSerialize {
102
- execution_generation: number;
103
- launch_id: string;
104
- subject_id: string;
105
- version: number;
106
- }
107
192
  /**
108
193
  * The agent's own process facts. Self-authored by any Pi session, with no owner
109
194
  * or assignment, and kept separate from execution and assignment. Every field
@@ -149,3 +234,1154 @@ export type SpawnExitObservationSerialize =
149
234
  signal: number | null;
150
235
  state: "exited";
151
236
  };
237
+ /**
238
+ * Input accepted by `observation.get`.
239
+ */
240
+ export interface ObservationGetParamsDeserialize {
241
+ classes?: string[] | null;
242
+ epoch?: string | null;
243
+ since_revision?: number | null;
244
+ wait_ms?: number | null;
245
+ }
246
+ /**
247
+ * The result forms returned by `observation.get`.
248
+ */
249
+ export type ObservationGetResponseSerialize =
250
+ ObservationSnapshotResult | ObservationNotModifiedResult | ObservationExpiredResult | ObservationTooLargeResult;
251
+ /**
252
+ * Why a retained association is reported as not current.
253
+ */
254
+ export type RetainedBasis = "shell_foreground" | "unverified";
255
+ /**
256
+ * Herdsman's projection of an agent's state, as an owner publishes it.
257
+ *
258
+ * This is a control projection, not a lifecycle: `Working` says a model turn
259
+ * or tool call is in flight, `Blocked` says the assignment waits on its owner,
260
+ * and `Waiting` says the turn has yielded while work it depends on is
261
+ * unresolved. Values are additive, so an unrecognised one is preserved.
262
+ */
263
+ export type SemanticState =
264
+ | ("idle" | "working" | "waiting" | "blocked" | "settling" | "unknown" | "lost")
265
+ | {
266
+ other: string;
267
+ };
268
+ /**
269
+ * A validated canonical UUID (lowercase `8-4-4-4-12` hex).
270
+ *
271
+ * Only explicitly supplied UUID metadata is ever turned into this type —
272
+ * session file paths are never scanned for embedded UUIDs.
273
+ */
274
+ export type SessionUuid = string;
275
+ /**
276
+ * Independent publisher channels.
277
+ */
278
+ export type Channel = "execution" | "assignment" | "facts";
279
+ /**
280
+ * Freshness is independent of process identity or completion.
281
+ */
282
+ export type Freshness = "fresh" | "stale";
283
+ /**
284
+ * One complete accepted snapshot, typed by the channel that carries it. Each
285
+ * variant is strict about its own fields, so a field from another channel is
286
+ * refused rather than silently dropped.
287
+ */
288
+ export type Report = Snapshot | AssignmentSnapshot | FactsSnapshot;
289
+ export type Standing = "pending" | "granted" | "duplicate" | "released";
290
+ /**
291
+ * How a registration relates to the live panes.
292
+ */
293
+ export type Binding =
294
+ | "joined"
295
+ | {
296
+ unjoined: Unjoined;
297
+ };
298
+ /**
299
+ * Why a registration did not join a pane.
300
+ */
301
+ export type Unjoined =
302
+ | "no_location"
303
+ | "no_claim"
304
+ | "pane_absent"
305
+ | "location_mismatch"
306
+ | "foreground_unreadable"
307
+ | "identity_mismatch"
308
+ | "ambiguous";
309
+ export type State = "pending" | "captured" | "bound" | "revoked";
310
+ /**
311
+ * The state of one edge in the recorded topology: the strongest statement a
312
+ * read can make about it, and nothing beyond the records and this read's own
313
+ * evidence.
314
+ */
315
+ export type SpawnState = "unbound" | "bound" | "unresolved";
316
+ /**
317
+ * Reported session identity for an agent observation.
318
+ *
319
+ * Identity is separate from [`Location`]: the same session may move between
320
+ * panes, and a pane may host different sessions over time.
321
+ */
322
+ export type SessionIdentity =
323
+ | {
324
+ kind: "uuid";
325
+ value: SessionUuid;
326
+ }
327
+ | {
328
+ kind: "reported";
329
+ value: {
330
+ source: string | null;
331
+ value: string;
332
+ };
333
+ };
334
+ /**
335
+ * Runtime lifecycle exactly as the source reports it.
336
+ *
337
+ * This is not a semantic control state: `Idle` says nothing about
338
+ * availability for new work, result delivery or safe lifecycle actions.
339
+ * Unrecognized values are preserved verbatim in [`RuntimeStatus::Other`] so a
340
+ * source change never fails an otherwise valid inventory.
341
+ */
342
+ export type RuntimeStatus =
343
+ | ("idle" | "working" | "done" | "unknown")
344
+ | {
345
+ other: string;
346
+ };
347
+ /**
348
+ * Evidence about a pane's foreground, decoded inside the connector.
349
+ *
350
+ * The reconciler treats only [`ForegroundEvidence::NonShell`] as positive
351
+ * supersession evidence; absence or ambiguity retains the last observation.
352
+ */
353
+ export type ForegroundEvidence =
354
+ | {
355
+ kind: "shell";
356
+ }
357
+ | {
358
+ /**
359
+ * The leader's command line as the operating system reports it.
360
+ */
361
+ command: string | null;
362
+ kind: "non_shell";
363
+ local: LocalFacts;
364
+ name: string | null;
365
+ pid: number;
366
+ }
367
+ | {
368
+ kind: "inconclusive";
369
+ };
370
+ /**
371
+ * How a foreground process's running executable compares with the installed
372
+ * program it would run.
373
+ */
374
+ export type BinaryFreshness = "current" | "stale" | "unknown";
375
+ /**
376
+ * Why a running executable could not be compared, when it could not.
377
+ *
378
+ * Each variant is something a reader can act on differently: a program that is
379
+ * not installed, an installed entrypoint whose payload cannot be identified,
380
+ * an executable that cannot be read, or a running file that is not the program
381
+ * in question. The words a row uses are the row's, not this type's.
382
+ */
383
+ export type BinaryUnknown = "no_counterpart" | "unsupported_launcher" | "unreadable" | "not_compared";
384
+ /**
385
+ * Interval CPU use of one process, as a percentage of one CPU.
386
+ *
387
+ * Held in hundredths of a percent, as an integer: the value is a ratio of two
388
+ * kernel counter readings, and an exact integer is what a row can show and a
389
+ * test can assert. `12.5%` of one CPU is `1_250`. It measures the process
390
+ * rather than the machine, so a process that used two CPUs for a whole
391
+ * interval is `20_000`, not `100%`.
392
+ */
393
+ export type CpuPercent = number;
394
+ /**
395
+ * What a container is in the hierarchy.
396
+ */
397
+ export type Kind = "workspace" | "tab" | "pane";
398
+ /**
399
+ * Who made the container.
400
+ */
401
+ export type Provenance = "created" | "observed";
402
+ /**
403
+ * Source freshness included in an observation response.
404
+ */
405
+ export type ObservationFreshness =
406
+ | ("pending" | "current")
407
+ | {
408
+ stale: {
409
+ diagnostic: string;
410
+ };
411
+ }
412
+ | {
413
+ unavailable: {
414
+ diagnostic: string;
415
+ };
416
+ };
417
+
418
+ export interface ObservationSnapshotResult {
419
+ epoch: string;
420
+ revision: number;
421
+ snapshot: ObservationSnapshot;
422
+ }
423
+ /**
424
+ * One immutable observation revision on the public wire.
425
+ */
426
+ export interface ObservationSnapshot {
427
+ collected_at: string | null;
428
+ epoch: string;
429
+ observation: ObservationProjection;
430
+ revision: number;
431
+ sources: ObservationSource[];
432
+ tasks: unknown;
433
+ }
434
+ /**
435
+ * Public observation projection. The sampler's mutable state remains private;
436
+ * this DTO names the fields the daemon publishes without serializing that state
437
+ * type directly.
438
+ */
439
+ export interface ObservationProjection {
440
+ awaiting_evidence: string[];
441
+ containment: {
442
+ [k: string]: RetainedObservation;
443
+ };
444
+ foreground: {
445
+ [k: string]: ForegroundEvidence;
446
+ };
447
+ inventory: FleetObservation | null;
448
+ /**
449
+ * Source freshness included in an observation response.
450
+ */
451
+ registry:
452
+ | ("pending" | "current")
453
+ | {
454
+ stale: {
455
+ diagnostic: string;
456
+ };
457
+ }
458
+ | {
459
+ unavailable: {
460
+ diagnostic: string;
461
+ };
462
+ };
463
+ retained: {
464
+ [k: string]: RetainedObservation;
465
+ };
466
+ source: ObservationFreshness;
467
+ }
468
+ /**
469
+ * Retained agent facts carried across an idle-shell gap.
470
+ */
471
+ export interface RetainedObservation {
472
+ basis: RetainedBasis;
473
+ observation: AgentObservation;
474
+ }
475
+ /**
476
+ * A normalized observation of one agent, keyed in the inventory by its pane.
477
+ */
478
+ export interface AgentObservation {
479
+ facts: HerdsmanFacts;
480
+ /**
481
+ * Reported display label (the stripped terminal title), if any.
482
+ */
483
+ label: string | null;
484
+ /**
485
+ * Explicit ownership lineage; `None` unless valid UUID tokens were supplied.
486
+ */
487
+ lineage: Lineage | null;
488
+ location: Location;
489
+ /**
490
+ * Reported agent name (for example `"pi"`), if any.
491
+ */
492
+ name: string | null;
493
+ /**
494
+ * The daemon's registration for this agent, with how it binds to a pane.
495
+ * `None` for an agent the registry does not know, and for every agent when
496
+ * no registry is read. A registration that names a pane protects that pane
497
+ * even when unjoined.
498
+ */
499
+ registry: RegistryView | null;
500
+ /**
501
+ * Reported session identity; `None` when the source reports none.
502
+ */
503
+ session: SessionIdentity | null;
504
+ /**
505
+ * Runtime lifecycle as reported; never a semantic control state.
506
+ */
507
+ status: RuntimeStatus | null;
508
+ }
509
+ /**
510
+ * What Herdsman publishes about this agent. Empty unless the source
511
+ * published metadata; never inferred from runtime facts.
512
+ */
513
+ export interface HerdsmanFacts {
514
+ /**
515
+ * A lead's pending owner question.
516
+ */
517
+ ask: string | null;
518
+ /**
519
+ * How long the active assignment had been running when it was observed.
520
+ * Measured at observation time from Herdsman's own start, because a
521
+ * presentation that had to interpret a timestamp would need a clock.
522
+ */
523
+ assigned_for: number | null;
524
+ /**
525
+ * The active assignment's start, Unix milliseconds as published.
526
+ */
527
+ assigned_started_unix_ms: number | null;
528
+ /**
529
+ * The active assignment's display text.
530
+ */
531
+ assignment: string | null;
532
+ /**
533
+ * What this pane is waiting on: `agent:<label>` for each outstanding
534
+ * child, and `owner` while its own question to its owner is outstanding.
535
+ * Outstanding work, not state: it is published while working and while
536
+ * stopped, and cleared when the last item resolves.
537
+ */
538
+ awaited: string[];
539
+ /**
540
+ * How many of the pane's background tasks are running, as its own
541
+ * extension counts them. Another publisher owns this key, and the count
542
+ * speaks only for the running ones: it is not the set of unresolved work.
543
+ */
544
+ background_running: number | null;
545
+ /**
546
+ * The oldest outstanding background task's start, ISO 8601 as published.
547
+ */
548
+ background_started: string | null;
549
+ /**
550
+ * The pane's unresolved background tasks as its own extension publishes
551
+ * them, each an `<id>:<phase>` entry. The awaited facts are the union of
552
+ * the owner's awaited items and these ids, because neither publisher can
553
+ * express the whole pane alone.
554
+ */
555
+ background_tasks: string[];
556
+ /**
557
+ * The percentage a Herdr token states, percent sign included. It carries no
558
+ * counts, so it is never presented as a typed window.
559
+ */
560
+ context_usage: string | null;
561
+ /**
562
+ * The context window a registry publisher reports as counts.
563
+ */
564
+ context_window: ContextWindow | null;
565
+ /**
566
+ * The agent definition a pane reports as its display agent.
567
+ */
568
+ definition: string | null;
569
+ /**
570
+ * A managed worker's runtime label: the name its owner and its siblings
571
+ * use for it, and the only faithful source for a worker's name. Herdr's
572
+ * own agent name truncates it and its title welds it to the task.
573
+ */
574
+ label: string | null;
575
+ /**
576
+ * The owner's last outcome for the assignment, as it published it.
577
+ */
578
+ last_outcome: string | null;
579
+ /**
580
+ * Whether this pane's tokens carried any `pi_herdsman_*` key.
581
+ *
582
+ * Presence, not readability: the owner's metadata is what makes a Pi pane
583
+ * managed, so a key whose value this build cannot read still counts. The
584
+ * decoder sets this at the adapter boundary, where the raw token map is,
585
+ * because the named fields below discard keys this version does not know.
586
+ */
587
+ managed_metadata: boolean;
588
+ /**
589
+ * The session's model identity as published, provider prefix included.
590
+ */
591
+ model: string | null;
592
+ /**
593
+ * A lead's published session name.
594
+ */
595
+ name: string | null;
596
+ provider: string | null;
597
+ /**
598
+ * The active assignment's request identity.
599
+ */
600
+ request: string | null;
601
+ /**
602
+ * The role the agent runs as: a lead role, or a worker's agent definition.
603
+ */
604
+ role: string | null;
605
+ /**
606
+ * A managed worker's run identity.
607
+ */
608
+ run: string | null;
609
+ /**
610
+ * The source's human session name.
611
+ */
612
+ session_name: string | null;
613
+ /**
614
+ * The owner's projection of this agent's state, while it is published.
615
+ */
616
+ state: SemanticState | null;
617
+ thinking: string | null;
618
+ /**
619
+ * Why the owner says the assignment is waiting, as it published it.
620
+ */
621
+ waiting_reason: string | null;
622
+ }
623
+ /**
624
+ * How much of a model's context window a session has used, as counts.
625
+ *
626
+ * `window` is positive and `tokens` does not exceed it; the percentage a display
627
+ * shows is derived from these and never published. Wire counts stay exact in JS.
628
+ */
629
+ export interface ContextWindow {
630
+ tokens: number;
631
+ window: number;
632
+ }
633
+ /**
634
+ * Explicit ownership lineage from `pi_herdsman_session` /
635
+ * `pi_herdsman_parent_session` UUID metadata.
636
+ *
637
+ * Used only for ownership joins (worker → owner). Lineage is never used as
638
+ * session identity, and absent or malformed tokens yield no lineage at all.
639
+ */
640
+ export interface Lineage {
641
+ parent: SessionUuid | null;
642
+ session: SessionUuid;
643
+ }
644
+ /**
645
+ * Connector-scoped runtime location: Herdr workspace, tab and pane identifiers.
646
+ *
647
+ * Pane identity is a runtime location detail; it is never an agent identity.
648
+ */
649
+ export interface Location {
650
+ pane_id: string;
651
+ tab_id: string;
652
+ workspace_id: string;
653
+ }
654
+ /**
655
+ * A registered agent with its binding, carried on the agent it projects to.
656
+ */
657
+ export interface RegistryView {
658
+ agent: RegistryAgent;
659
+ binding: Binding;
660
+ managed: ManagedSubject | null;
661
+ spawn: SpawnBinding | null;
662
+ }
663
+ /**
664
+ * One registered agent as the daemon's `agent.list` serves it.
665
+ */
666
+ export interface RegistryAgent {
667
+ assignment: PublicChannelFacts | null;
668
+ /**
669
+ * Durable claim decision, if this registration has claimed a session.
670
+ */
671
+ claim_standing?: Standing | null;
672
+ /**
673
+ * Mutable current-session context, kept separate from registration identity.
674
+ */
675
+ context: PublicContext | null;
676
+ execution: PublicChannelFacts | null;
677
+ facts: PublicChannelFacts | null;
678
+ process: ProcessEvidence;
679
+ registration: PublicRegistration;
680
+ }
681
+ /**
682
+ * A channel read for a reader that is not its writer: the same identity,
683
+ * freshness and report facts as [`PublicChannel`], with the fencing handle
684
+ * dropped because it is a credential rather than a fact.
685
+ */
686
+ export interface PublicChannelFacts {
687
+ channel: Channel;
688
+ registration_id: string;
689
+ snapshot?: PublicSnapshotFacts | null;
690
+ version: number;
691
+ writer: PublicWriterFacts;
692
+ }
693
+ /**
694
+ * The last accepted report as an unrelated reader may see it, leaving out the
695
+ * handle that fences further writes.
696
+ */
697
+ export interface PublicSnapshotFacts {
698
+ expires_at: string;
699
+ freshness: Freshness;
700
+ generation: number;
701
+ incarnation: string;
702
+ lease_ms: number;
703
+ observed_at?: string | null;
704
+ received_at: string;
705
+ reporting_owner?: string | null;
706
+ restored: boolean;
707
+ sequence: number;
708
+ snapshot: Report;
709
+ source: string;
710
+ }
711
+ /**
712
+ * One complete snapshot for one channel. Vocabulary is free-form; shape is
713
+ * strict. Unknown state/reason/action words survive, unknown fields do not.
714
+ */
715
+ export interface Snapshot {
716
+ actions?: string[];
717
+ activity: string;
718
+ last_outcome?: Outcome | null;
719
+ waiting_reason?: string | null;
720
+ }
721
+ /**
722
+ * A turn outcome kept distinct from current activity.
723
+ */
724
+ export interface Outcome {
725
+ detail?: string | null;
726
+ /**
727
+ * Producer vocabulary is deliberately free-form.
728
+ */
729
+ result: string;
730
+ }
731
+ /**
732
+ * The owner's complete assignment snapshot: the shared base plus facts only an
733
+ * owner knows. It is authored by the owner's writer and is never derived from
734
+ * execution activity; the owner's identity is provenance, not authority.
735
+ */
736
+ export interface AssignmentSnapshot {
737
+ actions?: string[];
738
+ activity: string;
739
+ ask?: string | null;
740
+ assigned_started_unix_ms?: number | null;
741
+ assignment?: string | null;
742
+ awaited?: string[];
743
+ definition?: string | null;
744
+ last_outcome?: Outcome | null;
745
+ request?: string | null;
746
+ role?: string | null;
747
+ run?: string | null;
748
+ waiting_reason?: string | null;
749
+ }
750
+ /**
751
+ * The agent's own process facts. Self-authored by any Pi session, with no owner
752
+ * or assignment, and kept separate from execution and assignment. Every field
753
+ * is optional and a published snapshot replaces the whole value, so omission
754
+ * withdraws a fact. `context_window` is counts; a display derives the percentage.
755
+ */
756
+ export interface FactsSnapshot {
757
+ background_started_unix_ms?: number | null;
758
+ background_tasks?: BackgroundTask[];
759
+ context_window?: ContextWindow | null;
760
+ model?: string | null;
761
+ provider?: string | null;
762
+ session_name?: string | null;
763
+ thinking?: string | null;
764
+ }
765
+ /**
766
+ * One background task the agent process reports as unresolved.
767
+ */
768
+ export interface BackgroundTask {
769
+ id: string;
770
+ phase: string;
771
+ }
772
+ /**
773
+ * The current writer as an unrelated reader may see it: provenance and
774
+ * generation, without the opaque handle an update must present.
775
+ */
776
+ export interface PublicWriterFacts {
777
+ generation: number;
778
+ incarnation: string;
779
+ reporting_owner?: string | null;
780
+ retired_at?: string | null;
781
+ sequence: number;
782
+ source: string;
783
+ }
784
+ /**
785
+ * One agent record's context as a client reads it. A `None` read of this whole
786
+ * record means never published; a present record with a null session means no
787
+ * current session.
788
+ */
789
+ export interface PublicContext {
790
+ context: PublicSession;
791
+ registration_id: string;
792
+ version: number;
793
+ writer: PublicWriterFacts;
794
+ }
795
+ /**
796
+ * The last accepted context as a client reads it.
797
+ *
798
+ * There is no handle and no serving epoch here by construction, and no other
799
+ * field a private path or argument could be forgotten into.
800
+ */
801
+ export interface PublicSession {
802
+ expires_at: string;
803
+ freshness: Freshness;
804
+ generation: number;
805
+ incarnation: string;
806
+ lease_ms: number;
807
+ observed_at?: string | null;
808
+ received_at: string;
809
+ reporting_owner?: string | null;
810
+ restored: boolean;
811
+ sequence: number;
812
+ /**
813
+ * The current session, or an explicit null for "no current session".
814
+ *
815
+ * Written even when null: a present record is what distinguishes "no
816
+ * current session" from "never published", which is no context record at
817
+ * all.
818
+ */
819
+ session: string | null;
820
+ source: string;
821
+ }
822
+ /**
823
+ * The process evidence `agent.list` serves beside a registration. Only the
824
+ * claimed birth identity is read here; the registry's own verdict is not used
825
+ * to join, because a join needs the claim to match the live foreground.
826
+ */
827
+ export interface ProcessEvidence {
828
+ claim: ProcessIdentity | null;
829
+ }
830
+ /**
831
+ * Which process incarnation a sample belongs to.
832
+ *
833
+ * The kernel reuses process ids, so a pid does not name a process: one
834
+ * incarnation is the boot it started in, its pid, and when it started. Those
835
+ * are what make two readings comparable — counters may only be subtracted
836
+ * from an earlier reading of the same identity, and a difference taken across
837
+ * two of them measures neither process.
838
+ */
839
+ export interface ProcessIdentity {
840
+ /**
841
+ * The boot this process started in, as the kernel reports it.
842
+ */
843
+ boot_id: string;
844
+ /**
845
+ * The process id, unique within one boot and one incarnation of it.
846
+ */
847
+ pid: number;
848
+ /**
849
+ * Start time since boot, in clock ticks (`starttime` in
850
+ * `/proc/<pid>/stat`): the kernel's stamp for this incarnation.
851
+ */
852
+ start_ticks: number;
853
+ }
854
+ /**
855
+ * A registration as a client reads it. The private launch fields are absent by
856
+ * construction, not by redaction: there is no field here to forget to strip.
857
+ */
858
+ export interface PublicRegistration {
859
+ incarnation: string;
860
+ label?: string | null;
861
+ launch: PublicLaunch;
862
+ location?: RegistryLocation | null;
863
+ owner?: string | null;
864
+ /**
865
+ * Whether a process identity was supplied. Its verification is a separate
866
+ * answer and is never asserted by this record.
867
+ */
868
+ process_claimed: boolean;
869
+ registered_at: string;
870
+ registration_id: string;
871
+ run?: string | null;
872
+ session?: string | null;
873
+ source: string;
874
+ version: number;
875
+ }
876
+ /**
877
+ * What a public read says about private launch information: that something is
878
+ * held, and which revision of it.
879
+ */
880
+ export interface PublicLaunch {
881
+ available: boolean;
882
+ revision?: string | null;
883
+ }
884
+ /**
885
+ * Where an agent's incarnation lives on one backend, in that backend's own
886
+ * coordinates.
887
+ *
888
+ * The backend name is free-form so a source Radar does not ship yet is
889
+ * preserved rather than rejected; the rest are the coordinates as reported, and
890
+ * each is optional because a backend need not name every level.
891
+ */
892
+ export interface RegistryLocation {
893
+ backend: string;
894
+ instance?: string | null;
895
+ pane?: string | null;
896
+ tab?: string | null;
897
+ workspace?: string | null;
898
+ }
899
+ /**
900
+ * A daemon-owned process lifecycle target, joined to one registration by exact
901
+ * agent id and process birth identity.
902
+ */
903
+ export interface ManagedSubject {
904
+ child_close: ChildCloseTarget | null;
905
+ identity_unresolved: boolean;
906
+ metadata: ManagedMetadata;
907
+ process: ProcessIdentity;
908
+ session: string | null;
909
+ state: State;
910
+ subject_id: string;
911
+ successor: string | null;
912
+ }
913
+ /**
914
+ * Exact spawn-edge child identity required by `spawn.close`.
915
+ */
916
+ export interface ChildCloseTarget {
917
+ incarnation: string;
918
+ source: string;
919
+ spawn_request_id: string;
920
+ }
921
+ /**
922
+ * One durable launch subject. The correlation is a private credential and is
923
+ * spent at capture; no public read returns it.
924
+ */
925
+ export interface ManagedMetadata {
926
+ label?: string | null;
927
+ owner?: string | null;
928
+ parent_subject_id?: string | null;
929
+ role?: string | null;
930
+ run?: string | null;
931
+ }
932
+ /**
933
+ * The spawn edge that binds this registration as a child, when one exists.
934
+ *
935
+ * Parentage and the edge's own state come from the topology read. The edge's
936
+ * state is never a process-exit claim: an unresolved child is shown as such.
937
+ */
938
+ export interface SpawnBinding {
939
+ child_incarnation: string | null;
940
+ child_source: string | null;
941
+ parent: string;
942
+ request_id: string;
943
+ state: SpawnState;
944
+ subject_id: string | null;
945
+ }
946
+ /**
947
+ * What this machine knows about that process. Filled by the collector
948
+ * from the operating system, never by the runtime's own report.
949
+ */
950
+ export interface LocalFacts {
951
+ binary: BinaryIdentity;
952
+ /**
953
+ * What the process is using, from the sample taken for it. `None` when no
954
+ * sample was taken: this machine has no reader for that process, the
955
+ * process could not be read, or the platform cannot sample at all. A
956
+ * reading from an earlier refresh is never carried here.
957
+ */
958
+ resources: ProcessResources | null;
959
+ /**
960
+ * How long the process has been alive, measured from its own start time
961
+ * rather than from when Radar first saw it.
962
+ */
963
+ running_for: number | null;
964
+ /**
965
+ * What it has done to the terminal.
966
+ */
967
+ terminal: "full_screen" | "line" | "unknown";
968
+ }
969
+ /**
970
+ * How the foreground program's executable compares with the installed
971
+ * program of its own name or package family.
972
+ */
973
+ export interface BinaryIdentity {
974
+ /**
975
+ * The running executable's own path, when it could be read.
976
+ */
977
+ executable: string | null;
978
+ freshness: BinaryFreshness;
979
+ /**
980
+ * The installation the installed counterpart's payload belongs to. `None`
981
+ * when no counterpart was found or its payload could not be identified.
982
+ */
983
+ installed: string | null;
984
+ /**
985
+ * The installation the running executable belongs to. `None` when its
986
+ * executable could not be read.
987
+ */
988
+ running: string | null;
989
+ /**
990
+ * Why nothing was compared, when nothing was.
991
+ */
992
+ unknown: BinaryUnknown | null;
993
+ }
994
+ /**
995
+ * What one process is using, as the collector sampled it.
996
+ *
997
+ * These are the resources of that process and of nothing larger: a build
998
+ * running beneath a pane is a descendant and is summed separately in
999
+ * [`Self::descendants`], and nothing here says who owns the process, what work
1000
+ * it serves, or whether it is progressing. Every field comes from one read of
1001
+ * the process, so a sample never mixes two incarnations; RSS is that process's
1002
+ * resident set, in which pages shared with another process are counted here as
1003
+ * well.
1004
+ */
1005
+ export interface ProcessResources {
1006
+ /**
1007
+ * Interval CPU since the previous sample of this same identity. `None`
1008
+ * until such a sample exists, and whenever the interval cannot be
1009
+ * measured.
1010
+ */
1011
+ cpu: CpuPercent | null;
1012
+ descendants: DescendantResources;
1013
+ identity: ProcessIdentity3;
1014
+ /**
1015
+ * Resident set size in bytes. `None` when this machine cannot convert the
1016
+ * kernel's page count.
1017
+ */
1018
+ rss_bytes: number | null;
1019
+ /**
1020
+ * The kernel's scheduler state when the sample was taken.
1021
+ */
1022
+ state:
1023
+ | {
1024
+ kind: "running";
1025
+ }
1026
+ | {
1027
+ kind: "sleeping";
1028
+ }
1029
+ | {
1030
+ kind: "disk_sleep";
1031
+ }
1032
+ | {
1033
+ kind: "stopped";
1034
+ }
1035
+ | {
1036
+ kind: "tracing_stop";
1037
+ }
1038
+ | {
1039
+ kind: "zombie";
1040
+ }
1041
+ | {
1042
+ kind: "dead";
1043
+ }
1044
+ | {
1045
+ kind: "idle";
1046
+ }
1047
+ | {
1048
+ kind: "other";
1049
+ value: string;
1050
+ };
1051
+ }
1052
+ /**
1053
+ * What the processes beneath this one are using, as the refresh's scan
1054
+ * observed them. Never merged with the fields above: a build's work is not
1055
+ * its launcher's.
1056
+ */
1057
+ export interface DescendantResources {
1058
+ /**
1059
+ * Their interval CPU. Every one of them needs its own matching pair of
1060
+ * readings, so a descendant seen for the first time contributes nothing
1061
+ * and leaves this partial.
1062
+ */
1063
+ cpu:
1064
+ | {
1065
+ kind: "complete";
1066
+ value: CpuPercent;
1067
+ }
1068
+ | {
1069
+ kind: "partial";
1070
+ /**
1071
+ * @minItems 2
1072
+ * @maxItems 2
1073
+ */
1074
+ value: [unknown, unknown];
1075
+ }
1076
+ | {
1077
+ kind: "unknown";
1078
+ value: string;
1079
+ };
1080
+ /**
1081
+ * Those processes: one sample each, and exactly the ones `observed` counts
1082
+ * and the totals cover. Empty when none could be enumerated, and the
1083
+ * totals below say why.
1084
+ */
1085
+ members: DescendantSample[];
1086
+ /**
1087
+ * How many processes the scan observed beneath the root. `None` when none
1088
+ * could be enumerated at all.
1089
+ */
1090
+ observed: number | null;
1091
+ /**
1092
+ * The resident set of those of them whose size could be read.
1093
+ */
1094
+ rss_bytes:
1095
+ | {
1096
+ kind: "complete";
1097
+ value: number;
1098
+ }
1099
+ | {
1100
+ kind: "partial";
1101
+ /**
1102
+ * @minItems 2
1103
+ * @maxItems 2
1104
+ */
1105
+ value: [unknown, unknown];
1106
+ }
1107
+ | {
1108
+ kind: "unknown";
1109
+ value: string;
1110
+ };
1111
+ }
1112
+ /**
1113
+ * One process beneath a root, as one refresh's scan confirmed it.
1114
+ *
1115
+ * These are the members the totals of [`DescendantResources`] are made of, from
1116
+ * the same snapshot, the same reads and the same confirmation — never a second
1117
+ * walk and never a second reading of `/proc`. The parent is the identity of the
1118
+ * process this one was read beneath: what a table can order and fold by is the
1119
+ * incarnation, since a pid alone names a different process once the kernel
1120
+ * reuses it. The name is the kernel's own short name for the process, which is
1121
+ * neither the arguments it was started with nor a claim about what started it.
1122
+ */
1123
+ export interface DescendantSample {
1124
+ /**
1125
+ * Interval CPU since the previous sample of this same identity. `None` when
1126
+ * no interval can be measured; a measured idle interval is `Some(0)`.
1127
+ */
1128
+ cpu: CpuPercent | null;
1129
+ identity: ProcessIdentity1;
1130
+ /**
1131
+ * The kernel's name for the process (`comm` in `/proc/<pid>/stat`), which
1132
+ * is not argv and says nothing about who started it.
1133
+ */
1134
+ name: string;
1135
+ parent: ProcessIdentity2;
1136
+ /**
1137
+ * Resident set size in bytes. `None` when this machine cannot convert the
1138
+ * kernel's page count.
1139
+ */
1140
+ rss_bytes: number | null;
1141
+ /**
1142
+ * The scheduler state the kernel reported for it.
1143
+ */
1144
+ state:
1145
+ | {
1146
+ kind: "running";
1147
+ }
1148
+ | {
1149
+ kind: "sleeping";
1150
+ }
1151
+ | {
1152
+ kind: "disk_sleep";
1153
+ }
1154
+ | {
1155
+ kind: "stopped";
1156
+ }
1157
+ | {
1158
+ kind: "tracing_stop";
1159
+ }
1160
+ | {
1161
+ kind: "zombie";
1162
+ }
1163
+ | {
1164
+ kind: "dead";
1165
+ }
1166
+ | {
1167
+ kind: "idle";
1168
+ }
1169
+ | {
1170
+ kind: "other";
1171
+ value: string;
1172
+ };
1173
+ }
1174
+ /**
1175
+ * Which process incarnation a sample belongs to.
1176
+ *
1177
+ * The kernel reuses process ids, so a pid does not name a process: one
1178
+ * incarnation is the boot it started in, its pid, and when it started. Those
1179
+ * are what make two readings comparable — counters may only be subtracted
1180
+ * from an earlier reading of the same identity, and a difference taken across
1181
+ * two of them measures neither process.
1182
+ */
1183
+ export interface ProcessIdentity1 {
1184
+ /**
1185
+ * The boot this process started in, as the kernel reports it.
1186
+ */
1187
+ boot_id: string;
1188
+ /**
1189
+ * The process id, unique within one boot and one incarnation of it.
1190
+ */
1191
+ pid: number;
1192
+ /**
1193
+ * Start time since boot, in clock ticks (`starttime` in
1194
+ * `/proc/<pid>/stat`): the kernel's stamp for this incarnation.
1195
+ */
1196
+ start_ticks: number;
1197
+ }
1198
+ /**
1199
+ * Which process incarnation a sample belongs to.
1200
+ *
1201
+ * The kernel reuses process ids, so a pid does not name a process: one
1202
+ * incarnation is the boot it started in, its pid, and when it started. Those
1203
+ * are what make two readings comparable — counters may only be subtracted
1204
+ * from an earlier reading of the same identity, and a difference taken across
1205
+ * two of them measures neither process.
1206
+ */
1207
+ export interface ProcessIdentity2 {
1208
+ /**
1209
+ * The boot this process started in, as the kernel reports it.
1210
+ */
1211
+ boot_id: string;
1212
+ /**
1213
+ * The process id, unique within one boot and one incarnation of it.
1214
+ */
1215
+ pid: number;
1216
+ /**
1217
+ * Start time since boot, in clock ticks (`starttime` in
1218
+ * `/proc/<pid>/stat`): the kernel's stamp for this incarnation.
1219
+ */
1220
+ start_ticks: number;
1221
+ }
1222
+ /**
1223
+ * Which process incarnation a sample belongs to.
1224
+ *
1225
+ * The kernel reuses process ids, so a pid does not name a process: one
1226
+ * incarnation is the boot it started in, its pid, and when it started. Those
1227
+ * are what make two readings comparable — counters may only be subtracted
1228
+ * from an earlier reading of the same identity, and a difference taken across
1229
+ * two of them measures neither process.
1230
+ */
1231
+ export interface ProcessIdentity3 {
1232
+ /**
1233
+ * The boot this process started in, as the kernel reports it.
1234
+ */
1235
+ boot_id: string;
1236
+ /**
1237
+ * The process id, unique within one boot and one incarnation of it.
1238
+ */
1239
+ pid: number;
1240
+ /**
1241
+ * Start time since boot, in clock ticks (`starttime` in
1242
+ * `/proc/<pid>/stat`): the kernel's stamp for this incarnation.
1243
+ */
1244
+ start_ticks: number;
1245
+ }
1246
+ /**
1247
+ * One successful inventory: workspaces, tabs, panes, reported agents and
1248
+ * daemon lifecycle subjects not represented by a joined agent row.
1249
+ */
1250
+ export interface FleetObservation {
1251
+ /**
1252
+ * The agents this observation presents as facts. The collector sets these
1253
+ * from the registry; a backend's own metadata records never land here.
1254
+ */
1255
+ agents: AgentObservation[];
1256
+ /**
1257
+ * The containers this daemon records, read beside the registry facts. A
1258
+ * backend's inventory never carries them, and an empty list means no
1259
+ * container was read — not that none exists.
1260
+ */
1261
+ containers?: PublicContainer[];
1262
+ /**
1263
+ * Public lifecycle records from the same daemon read as agent facts. The
1264
+ * tree suppresses subjects already represented by a joined agent row.
1265
+ */
1266
+ lifecycle_subjects?: LifecycleObservation[];
1267
+ /**
1268
+ * Agent records a backend reads from pane metadata. They are physical
1269
+ * evidence that protects a pane from unmanaged control, and are never
1270
+ * presented as agent facts.
1271
+ */
1272
+ metadata_agents?: AgentObservation[];
1273
+ panes: Pane[];
1274
+ tabs: Tab[];
1275
+ workspaces: Workspace[];
1276
+ }
1277
+ /**
1278
+ * One container as a consumer reads it.
1279
+ */
1280
+ export interface PublicContainer {
1281
+ binding: Binding2 | null;
1282
+ container_id: string;
1283
+ created_at: string;
1284
+ /**
1285
+ * The operation that created it, for a caller reconciling its own requests.
1286
+ */
1287
+ created_by: string | null;
1288
+ kind: Kind;
1289
+ label: string | null;
1290
+ observed_at: string | null;
1291
+ parent: string | null;
1292
+ provenance: Provenance;
1293
+ /**
1294
+ * Whether a recipe is held for this container's pane, so a caller knows the
1295
+ * slot can be reloaded without reading private storage.
1296
+ */
1297
+ recipe: boolean;
1298
+ removed_at: string | null;
1299
+ unresolved: string | null;
1300
+ }
1301
+ /**
1302
+ * Where a container's handle lives, and which incarnation answered for it.
1303
+ */
1304
+ export interface Binding2 {
1305
+ backend: string;
1306
+ handle: string;
1307
+ /**
1308
+ * The verified process incarnation serving the handle, when one was
1309
+ * established. A handle alone cannot be told apart from a later server
1310
+ * reusing it, so a binding that names no incarnation is never verified.
1311
+ */
1312
+ incarnation: ProcessIdentity | null;
1313
+ }
1314
+ /**
1315
+ * Public lifecycle identity carried into the display projection.
1316
+ */
1317
+ export interface LifecycleObservation {
1318
+ bound_registration_id: string | null;
1319
+ process: ProcessIdentity | null;
1320
+ session: string | null;
1321
+ state: State;
1322
+ subject_id: string;
1323
+ successor: string | null;
1324
+ }
1325
+ /**
1326
+ * A runtime pane: location plus optional display text.
1327
+ *
1328
+ * `label` is the pane's declared label, `title` its stripped terminal title;
1329
+ * either may be absent, and [`Pane::display_name`] defines the fallback used
1330
+ * by presentation rows.
1331
+ */
1332
+ export interface Pane {
1333
+ /**
1334
+ * Current tmux pane directory, used as the target for a new launch.
1335
+ */
1336
+ current_path?: string | null;
1337
+ label: string | null;
1338
+ location: Location;
1339
+ title: string | null;
1340
+ }
1341
+ /**
1342
+ * A Herdr tab within a workspace; shown as location detail, not a tree level.
1343
+ */
1344
+ export interface Tab {
1345
+ label: string | null;
1346
+ number: number | null;
1347
+ tab_id: string;
1348
+ workspace_id: string;
1349
+ }
1350
+ /**
1351
+ * A Herdr workspace: the first display grouping for the fleet tree.
1352
+ */
1353
+ export interface Workspace {
1354
+ label: string | null;
1355
+ number: number | null;
1356
+ /**
1357
+ * tmux's workspace directory, used as the default target for a new launch.
1358
+ */
1359
+ session_path?: string | null;
1360
+ workspace_id: string;
1361
+ }
1362
+ /**
1363
+ * One source's freshness in a snapshot revision.
1364
+ */
1365
+ export interface ObservationSource {
1366
+ last_success_at: string | null;
1367
+ name: string;
1368
+ state: ObservationFreshness;
1369
+ }
1370
+ export interface ObservationNotModifiedResult {
1371
+ not_modified: ObservationRevision;
1372
+ }
1373
+ export interface ObservationRevision {
1374
+ epoch: string;
1375
+ revision: number;
1376
+ }
1377
+ export interface ObservationExpiredResult {
1378
+ snapshot_expired: ObservationRevision;
1379
+ }
1380
+ export interface ObservationTooLargeResult {
1381
+ snapshot_too_large: ObservationTooLarge;
1382
+ }
1383
+ export interface ObservationTooLarge {
1384
+ epoch: string;
1385
+ limit_bytes: number;
1386
+ revision: number;
1387
+ }