pi-radar 0.2.0 → 0.3.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 +8 -4
- package/dist/extension/baseline.js +116 -2
- package/dist/extension/radar-client.js +76 -1
- package/dist/extension/radar-communication.js +39 -0
- package/dist/extension/radar-execution.js +2 -0
- package/dist/extension/radar-launch.js +5 -0
- package/dist/extension/radar-publication.js +2 -0
- package/dist/extension/radar-runtime.js +1 -1
- package/dist/index.js +126 -2
- package/extension/baseline.ts +2 -0
- package/extension/generated-contracts.ts +64 -0
- package/extension/radar-client.ts +105 -0
- package/extension/radar-communication.ts +66 -0
- package/extension/radar-launch.ts +8 -1
- package/extension/radar-publication.ts +4 -0
- package/extension/radar-runtime.ts +4 -1
- package/index.ts +1 -0
- package/package.json +9 -4
- package/schema/public/v1/handoff-inbox.deserialize.schema.json +18 -0
- package/schema/public/v1/handoff-inbox.serialize.schema.json +18 -0
- package/schema/public/v1/handoff-publish-params.deserialize.schema.json +33 -0
- package/schema/public/v1/handoff-publish-params.serialize.schema.json +33 -0
- package/schema/public/v1/handoff-receipt.deserialize.schema.json +66 -0
- package/schema/public/v1/handoff-receipt.serialize.schema.json +66 -0
- package/schema/public/v1/handoff.deserialize.schema.json +84 -0
- package/schema/public/v1/handoff.serialize.schema.json +84 -0
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ const radar = client.createRadarClient();
|
|
|
9
9
|
const handshake = await radar.ping();
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
Focused subpaths are also exported: `pi-radar/client`, `pi-radar/execution`, `pi-radar/publication`, `pi-radar/runtime`, `pi-radar/launch`, `pi-radar/location`, and `pi-radar/inspection`. The runtime subpath provides a versioned `pi.events` request/reply handoff so multiple extensions can consume one baseline publication without sharing bundled module singletons. `extension/radar-session-marker.ts` provides the versioned Pi custom-session-entry codec; it is correlation evidence only, not lifecycle authority. Existing extension deep imports under `pi-radar/extension/` remain exported.
|
|
12
|
+
Focused subpaths are also exported: `pi-radar/client`, `pi-radar/communication`, `pi-radar/execution`, `pi-radar/publication`, `pi-radar/runtime`, `pi-radar/launch`, `pi-radar/location`, and `pi-radar/inspection`. The shared `runtime` handle exposes `services.communication`, a handoff port bound to the baseline's existing client, this process's current registration, and the managed parent injected by Radar. Callers do not choose sender or recipient identity; `communication.createRadarHandoffPort` is the underlying SDK factory. The runtime subpath provides a versioned `pi.events` request/reply handoff so multiple extensions can consume one baseline publication without sharing bundled module singletons. `extension/radar-session-marker.ts` provides the versioned Pi custom-session-entry codec; it is correlation evidence only, not lifecycle authority. Existing extension deep imports under `pi-radar/extension/` remain exported.
|
|
13
13
|
|
|
14
14
|
## Pi baseline extension
|
|
15
15
|
|
|
@@ -17,15 +17,19 @@ Installing `pi-radar` directly as a Pi package loads `extension/baseline.ts`, wh
|
|
|
17
17
|
|
|
18
18
|
## Daemon contract
|
|
19
19
|
|
|
20
|
-
The client speaks protocol 2 and requires wire revision 3 or newer. Revision 3
|
|
20
|
+
The client speaks protocol 2 and requires wire revision 3 or newer for its existing lifecycle operations. Revision 3 made lifecycle `subject_id` a stable logical identity and exposed the exact current `execution_id` and `u32` generation separately. Handoff methods additionally require the independently negotiated `communication.handoff.v1` contract introduced at wire revision 4; its timestamps remain exactly representable as JSON numbers. Clients that control managed executions must not target the legacy per-execution ID semantics. It reads `revision` and the public `contracts` list from `daemon.ping`, preserves unfamiliar contract names, and preflights only contracts needed for a multi-step or versioned operation. Backend `mux.*` primitives are private to the daemon; direct mux methods are dispatched and return the daemon's backend refusal when unavailable.
|
|
21
21
|
|
|
22
|
-
The client uses `registry.v1` for registry operations and additionally requires `registry.facts.v1` for the facts channel and assignment extensions. Managed children require `spawn.v1`, child-pane removal requires `spawn.close.v1`,
|
|
22
|
+
The client uses `registry.v1` for registry operations and additionally requires `registry.facts.v1` for the facts channel and assignment extensions. Managed children require `spawn.v1`, child-pane removal requires `spawn.close.v1`, event reads require `events.v1`, and handoff operations require `communication.handoff.v1`. The expected wire examples are maintained in this repository's `docs/control-plane.fixture.jsonl` and `docs/agent-registration.fixture.jsonl` and are exercised by the package tests.
|
|
23
23
|
|
|
24
24
|
`RadarFactsSnapshot` matches the daemon facts channel: optional model/provider/thinking/session name, `context_window: { tokens, window }`, typed `background_tasks: { id, phase }[]`, and `background_started_unix_ms`. Context counts and the timestamp are JSON numbers bounded by JavaScript's safe-integer limit. The old text `context_usage` field is not accepted; Rust retains cross-field validation such as a positive window and tokens not exceeding it.
|
|
25
25
|
|
|
26
|
+
## Durable handoffs
|
|
27
|
+
|
|
28
|
+
The handoff API stores immutable bounded content separately from the recipient receipt. `inbox()` returns pending IDs only; retrieve each payload with `get()` and persist it before `ack()`, so a batch cannot exceed the RPC response bound. A worker's first Herdsman handoff is addressed only to the stable `parent_subject_id` recorded by Radar for its accepted managed launch. The parent gets its stable subject ID from `RadarSubject` and supplies it as `RadarWorkerLaunch.parent.subject_id`; `launchRadarWorker` forwards it as `managed.parent_subject_id`, and Radar injects the accepted value into the worker as `PI_RADAR_MANAGED_PARENT_SUBJECT_ID`. The handoff port reads that process context; callers cannot choose a destination. The daemon checks it against the durable parent record. Do not substitute a registration ID, Pi session, owner-session field, pane, or inferred lineage; unmanaged/session routing is deferred. The owner must durably capture the payload locally before calling `ack`; acknowledgement does not settle Herdsman assignment state or authorize worker closure. Pending inbox scans recover work after daemon restart or missed pointer events, and acknowledged content remains retrievable during the retention window. See `docs/control-plane.md` for wire shapes, bounds and recovery semantics.
|
|
29
|
+
|
|
26
30
|
## Generated protocol contracts
|
|
27
31
|
|
|
28
|
-
The selected Rust wire DTOs are the source for the draft 2020-12 schemas in `schema/public/v1/`, shipped and exported under `pi-radar/schema/`. Serialize and deserialize schemas are separate because Serde defaults, null handling and omission differ by direction. The SDK's ping, managed-launch-metadata input, facts-input and spawn-exit types are generated into `extension/generated-contracts.ts`; do not edit that file by hand.
|
|
32
|
+
The selected Rust wire DTOs are the source for the draft 2020-12 schemas in `schema/public/v1/`, shipped and exported under `pi-radar/schema/`. Serialize and deserialize schemas are separate because Serde defaults, null handling and omission differ by direction. The SDK's ping, handoff inbox, publication-parameter, immutable handoff, receipt, managed-launch-metadata input, facts-input and spawn-exit types are generated into `extension/generated-contracts.ts`; do not edit that file by hand.
|
|
29
33
|
|
|
30
34
|
From the repository checkout, run `npm run generate:contracts` in this directory to regenerate schemas and TypeScript declarations. `npm test` checks the generated artifacts are current, typechecks the public SDK aliases, validates canonical wire fixtures and integer bounds against the schemas, and runs the package tests. Generation uses the locked Schemars crate plus pinned `json-schema-to-typescript` and TypeScript development dependencies; it adds no runtime package dependency.
|
|
31
35
|
|
|
@@ -15,6 +15,7 @@ var RADAR_SPAWN_CONTRACT = "spawn.v1";
|
|
|
15
15
|
var RADAR_SPAWN_CLOSE_CONTRACT = "spawn.close.v1";
|
|
16
16
|
var RADAR_SPAWN_LAUNCH_CONTEXT_CONTRACT = "spawn.launch_context.v1";
|
|
17
17
|
var RADAR_EVENTS_CONTRACT = "events.v1";
|
|
18
|
+
var RADAR_COMMUNICATION_CONTRACT = "communication.handoff.v1";
|
|
18
19
|
var RADAR_REQUESTER = "pi-radar";
|
|
19
20
|
var RADAR_MAX_LINE_BYTES = 1024 * 1024;
|
|
20
21
|
var RADAR_CALL_TIMEOUT_MS = 2e3;
|
|
@@ -122,6 +123,28 @@ function numberAt(value, field) {
|
|
|
122
123
|
const found = value[field];
|
|
123
124
|
return typeof found === "number" && Number.isFinite(found) ? found : void 0;
|
|
124
125
|
}
|
|
126
|
+
function handoffAt(value) {
|
|
127
|
+
const version = numberAt(value, "version");
|
|
128
|
+
const id = stringAt(value, "id");
|
|
129
|
+
const sender = recordAt(value, "sender");
|
|
130
|
+
const senderGeneration = numberAt(sender, "execution_generation");
|
|
131
|
+
const target = stringAt(value, "recipient_subject_id");
|
|
132
|
+
const summary = stringAt(value, "summary");
|
|
133
|
+
const content = stringAt(value, "content");
|
|
134
|
+
const published = numberAt(value, "published_at_unix_ms");
|
|
135
|
+
const correlation = typeof value === "object" && value !== null ? value.correlation_id : void 0;
|
|
136
|
+
if (version !== 1 || !isUuid(id) || !isUuid(stringAt(sender, "agent_id")) || !isUuid(stringAt(sender, "session_id")) || !isUuid(stringAt(sender, "subject_id")) || !isUuid(stringAt(sender, "execution_id")) || !Number.isSafeInteger(senderGeneration) || (senderGeneration ?? 0) < 1 || !isUuid(target) || summary === void 0 || content === void 0 || published === void 0 || !Number.isSafeInteger(published) || published < 0 || correlation !== void 0 && correlation !== null && (typeof correlation !== "string" || correlation.length === 0 || Buffer.byteLength(correlation, "utf8") > 256 || new RegExp("\\p{Cc}", "u").test(correlation))) return void 0;
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
function handoffReceiptAt(value) {
|
|
140
|
+
const version = numberAt(value, "version");
|
|
141
|
+
const handoffId = stringAt(value, "handoff_id");
|
|
142
|
+
const recipient = recordAt(value, "recipient");
|
|
143
|
+
const generation = numberAt(recipient, "execution_generation");
|
|
144
|
+
const received = numberAt(value, "received_at_unix_ms");
|
|
145
|
+
if (version !== 1 || !isUuid(handoffId) || !isUuid(stringAt(recipient, "agent_id")) || !isUuid(stringAt(recipient, "session_id")) || !isUuid(stringAt(recipient, "subject_id")) || !isUuid(stringAt(recipient, "execution_id")) || !Number.isSafeInteger(generation) || (generation ?? 0) < 1 || received === void 0 || !Number.isSafeInteger(received) || received < 0) return void 0;
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
125
148
|
function writerBinding(value) {
|
|
126
149
|
const handle = stringAt(value, "handle");
|
|
127
150
|
const source = stringAt(value, "source");
|
|
@@ -227,7 +250,8 @@ var RADAR_SPAWN_TOKEN_ENV = "PI_RADAR_SPAWN_TOKEN";
|
|
|
227
250
|
var RADAR_MANAGED_IDENTITY_ENV = /* @__PURE__ */ new Set([
|
|
228
251
|
"PI_RADAR_MANAGED_SUBJECT_ID",
|
|
229
252
|
"PI_RADAR_MANAGED_LAUNCH_ID",
|
|
230
|
-
"PI_RADAR_MANAGED_EXECUTION_GENERATION"
|
|
253
|
+
"PI_RADAR_MANAGED_EXECUTION_GENERATION",
|
|
254
|
+
"PI_RADAR_MANAGED_PARENT_SUBJECT_ID"
|
|
231
255
|
]);
|
|
232
256
|
function unresolvedSpawn(requestId, detail) {
|
|
233
257
|
return {
|
|
@@ -843,6 +867,56 @@ function createRadarClient(options = {}) {
|
|
|
843
867
|
return protocol("spawn.close reply carries no close outcome");
|
|
844
868
|
});
|
|
845
869
|
},
|
|
870
|
+
async communicationPublish(request) {
|
|
871
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
872
|
+
const answer = await call("communication.publish", {
|
|
873
|
+
sender_agent_id: request.sender_agent_id,
|
|
874
|
+
recipient_subject_id: request.recipient_subject_id,
|
|
875
|
+
...request.correlation_id !== void 0 ? { correlation_id: request.correlation_id } : {},
|
|
876
|
+
summary: request.summary,
|
|
877
|
+
content: request.content
|
|
878
|
+
}, request.request_id);
|
|
879
|
+
if (answer.ok === false) return answer;
|
|
880
|
+
const handoff = handoffAt(recordAt(answer.value, "handoff"));
|
|
881
|
+
const created = recordAt(answer.value, "created");
|
|
882
|
+
if (handoff === void 0 || typeof created !== "boolean")
|
|
883
|
+
return protocol("communication.publish reply carries no handoff");
|
|
884
|
+
return { ok: true, value: { handoff, created } };
|
|
885
|
+
});
|
|
886
|
+
},
|
|
887
|
+
async communicationInbox(request) {
|
|
888
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
889
|
+
const answer = await call("communication.inbox", request);
|
|
890
|
+
if (answer.ok === false) return answer;
|
|
891
|
+
const handoffIds = recordAt(answer.value, "handoff_ids");
|
|
892
|
+
if (!Array.isArray(handoffIds) || handoffIds.some((id) => !isUuid(id)))
|
|
893
|
+
return protocol("communication.inbox reply carries malformed handoff IDs");
|
|
894
|
+
return { ok: true, value: answer.value };
|
|
895
|
+
});
|
|
896
|
+
},
|
|
897
|
+
async communicationGet(request) {
|
|
898
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
899
|
+
const answer = await call("communication.get", request);
|
|
900
|
+
if (answer.ok === false) return answer;
|
|
901
|
+
const handoff = handoffAt(recordAt(answer.value, "handoff"));
|
|
902
|
+
const receiptValue = recordAt(answer.value, "receipt");
|
|
903
|
+
const receipt = receiptValue === null ? null : handoffReceiptAt(receiptValue);
|
|
904
|
+
if (handoff === void 0 || receiptValue !== null && receipt === void 0)
|
|
905
|
+
return protocol("communication.get reply carries malformed content or receipt");
|
|
906
|
+
return { ok: true, value: { handoff, receipt: receipt ?? null } };
|
|
907
|
+
});
|
|
908
|
+
},
|
|
909
|
+
async communicationAck(request) {
|
|
910
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
911
|
+
const answer = await call("communication.ack", request);
|
|
912
|
+
if (answer.ok === false) return answer;
|
|
913
|
+
const receipt = handoffReceiptAt(recordAt(answer.value, "receipt"));
|
|
914
|
+
const created = recordAt(answer.value, "created");
|
|
915
|
+
if (receipt === void 0 || typeof created !== "boolean")
|
|
916
|
+
return protocol("communication.ack reply carries no receipt");
|
|
917
|
+
return { ok: true, value: { receipt, created } };
|
|
918
|
+
});
|
|
919
|
+
},
|
|
846
920
|
async events(request) {
|
|
847
921
|
if (!Number.isSafeInteger(request.after) || request.after < 0 || !Number.isSafeInteger(request.wait_ms) || request.wait_ms < 0 || request.wait_ms > RADAR_EVENT_WAIT_MS)
|
|
848
922
|
return {
|
|
@@ -1063,6 +1137,43 @@ function boundedRadarSnapshot(snapshot) {
|
|
|
1063
1137
|
};
|
|
1064
1138
|
}
|
|
1065
1139
|
|
|
1140
|
+
// extension/radar-communication.ts
|
|
1141
|
+
function createRadarHandoffPort(client, publication, parentSubjectId = () => process.env.PI_RADAR_MANAGED_PARENT_SUBJECT_ID) {
|
|
1142
|
+
async function agentId() {
|
|
1143
|
+
const subject = await publication.subject();
|
|
1144
|
+
return subject === void 0 ? { ok: false, code: "absent", message: "this process has no current Radar registration" } : { ok: true, value: subject.agent_id };
|
|
1145
|
+
}
|
|
1146
|
+
return {
|
|
1147
|
+
async publish(request) {
|
|
1148
|
+
const identity = await agentId();
|
|
1149
|
+
if (identity.ok === false) return identity;
|
|
1150
|
+
const parent = parentSubjectId();
|
|
1151
|
+
if (parent === void 0)
|
|
1152
|
+
return { ok: false, code: "absent", message: "this managed execution has no Radar parent subject" };
|
|
1153
|
+
return client.communicationPublish({
|
|
1154
|
+
...request,
|
|
1155
|
+
sender_agent_id: identity.value,
|
|
1156
|
+
recipient_subject_id: parent
|
|
1157
|
+
});
|
|
1158
|
+
},
|
|
1159
|
+
async inbox() {
|
|
1160
|
+
const identity = await agentId();
|
|
1161
|
+
if (identity.ok === false) return identity;
|
|
1162
|
+
return client.communicationInbox({ agent_id: identity.value });
|
|
1163
|
+
},
|
|
1164
|
+
async get(handoff_id) {
|
|
1165
|
+
const identity = await agentId();
|
|
1166
|
+
if (identity.ok === false) return identity;
|
|
1167
|
+
return client.communicationGet({ agent_id: identity.value, handoff_id });
|
|
1168
|
+
},
|
|
1169
|
+
async ack(handoff_id) {
|
|
1170
|
+
const identity = await agentId();
|
|
1171
|
+
if (identity.ok === false) return identity;
|
|
1172
|
+
return client.communicationAck({ agent_id: identity.value, handoff_id });
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1066
1177
|
// extension/radar-publication.ts
|
|
1067
1178
|
import { createHash, randomUUID as randomUUID2 } from "node:crypto";
|
|
1068
1179
|
import {
|
|
@@ -2190,8 +2301,10 @@ function createRadarPublicationInner(options) {
|
|
|
2190
2301
|
const record = await ensureRegistration();
|
|
2191
2302
|
if (record === void 0) return void 0;
|
|
2192
2303
|
const location = record.registration.location;
|
|
2304
|
+
const subjectId = process.env.PI_RADAR_MANAGED_SUBJECT_ID;
|
|
2193
2305
|
return {
|
|
2194
2306
|
agent_id: agentId2,
|
|
2307
|
+
...subjectId !== void 0 ? { subject_id: subjectId } : {},
|
|
2195
2308
|
...location !== void 0 ? { location } : {}
|
|
2196
2309
|
};
|
|
2197
2310
|
},
|
|
@@ -2589,7 +2702,7 @@ async function resolveRadarProcessLocation(client, env = process.env) {
|
|
|
2589
2702
|
|
|
2590
2703
|
// extension/radar-runtime.ts
|
|
2591
2704
|
var RADAR_RUNTIME_REQUEST = "pi-radar/runtime-request";
|
|
2592
|
-
var RADAR_RUNTIME_VERSION =
|
|
2705
|
+
var RADAR_RUNTIME_VERSION = 2;
|
|
2593
2706
|
function lazyRadarRuntime(start) {
|
|
2594
2707
|
let pending;
|
|
2595
2708
|
return {
|
|
@@ -2617,6 +2730,7 @@ function registerPiRadar(pi) {
|
|
|
2617
2730
|
});
|
|
2618
2731
|
const runtime = lazyRadarRuntime(async () => ({
|
|
2619
2732
|
publication: execution.publication,
|
|
2733
|
+
communication: createRadarHandoffPort(client, execution.publication),
|
|
2620
2734
|
execution
|
|
2621
2735
|
}));
|
|
2622
2736
|
provideRadarRuntime(pi.events, runtime);
|
|
@@ -11,6 +11,7 @@ var RADAR_SPAWN_CONTRACT = "spawn.v1";
|
|
|
11
11
|
var RADAR_SPAWN_CLOSE_CONTRACT = "spawn.close.v1";
|
|
12
12
|
var RADAR_SPAWN_LAUNCH_CONTEXT_CONTRACT = "spawn.launch_context.v1";
|
|
13
13
|
var RADAR_EVENTS_CONTRACT = "events.v1";
|
|
14
|
+
var RADAR_COMMUNICATION_CONTRACT = "communication.handoff.v1";
|
|
14
15
|
var RADAR_REQUESTER = "pi-radar";
|
|
15
16
|
var RADAR_MAX_LINE_BYTES = 1024 * 1024;
|
|
16
17
|
var RADAR_CALL_TIMEOUT_MS = 2e3;
|
|
@@ -118,6 +119,28 @@ function numberAt(value, field) {
|
|
|
118
119
|
const found = value[field];
|
|
119
120
|
return typeof found === "number" && Number.isFinite(found) ? found : void 0;
|
|
120
121
|
}
|
|
122
|
+
function handoffAt(value) {
|
|
123
|
+
const version = numberAt(value, "version");
|
|
124
|
+
const id = stringAt(value, "id");
|
|
125
|
+
const sender = recordAt(value, "sender");
|
|
126
|
+
const senderGeneration = numberAt(sender, "execution_generation");
|
|
127
|
+
const target = stringAt(value, "recipient_subject_id");
|
|
128
|
+
const summary = stringAt(value, "summary");
|
|
129
|
+
const content = stringAt(value, "content");
|
|
130
|
+
const published = numberAt(value, "published_at_unix_ms");
|
|
131
|
+
const correlation = typeof value === "object" && value !== null ? value.correlation_id : void 0;
|
|
132
|
+
if (version !== 1 || !isUuid(id) || !isUuid(stringAt(sender, "agent_id")) || !isUuid(stringAt(sender, "session_id")) || !isUuid(stringAt(sender, "subject_id")) || !isUuid(stringAt(sender, "execution_id")) || !Number.isSafeInteger(senderGeneration) || (senderGeneration ?? 0) < 1 || !isUuid(target) || summary === void 0 || content === void 0 || published === void 0 || !Number.isSafeInteger(published) || published < 0 || correlation !== void 0 && correlation !== null && (typeof correlation !== "string" || correlation.length === 0 || Buffer.byteLength(correlation, "utf8") > 256 || new RegExp("\\p{Cc}", "u").test(correlation))) return void 0;
|
|
133
|
+
return value;
|
|
134
|
+
}
|
|
135
|
+
function handoffReceiptAt(value) {
|
|
136
|
+
const version = numberAt(value, "version");
|
|
137
|
+
const handoffId = stringAt(value, "handoff_id");
|
|
138
|
+
const recipient = recordAt(value, "recipient");
|
|
139
|
+
const generation = numberAt(recipient, "execution_generation");
|
|
140
|
+
const received = numberAt(value, "received_at_unix_ms");
|
|
141
|
+
if (version !== 1 || !isUuid(handoffId) || !isUuid(stringAt(recipient, "agent_id")) || !isUuid(stringAt(recipient, "session_id")) || !isUuid(stringAt(recipient, "subject_id")) || !isUuid(stringAt(recipient, "execution_id")) || !Number.isSafeInteger(generation) || (generation ?? 0) < 1 || received === void 0 || !Number.isSafeInteger(received) || received < 0) return void 0;
|
|
142
|
+
return value;
|
|
143
|
+
}
|
|
121
144
|
function writerBinding(value) {
|
|
122
145
|
const handle = stringAt(value, "handle");
|
|
123
146
|
const source = stringAt(value, "source");
|
|
@@ -227,7 +250,8 @@ var RADAR_SPAWN_TOKEN_ENV = "PI_RADAR_SPAWN_TOKEN";
|
|
|
227
250
|
var RADAR_MANAGED_IDENTITY_ENV = /* @__PURE__ */ new Set([
|
|
228
251
|
"PI_RADAR_MANAGED_SUBJECT_ID",
|
|
229
252
|
"PI_RADAR_MANAGED_LAUNCH_ID",
|
|
230
|
-
"PI_RADAR_MANAGED_EXECUTION_GENERATION"
|
|
253
|
+
"PI_RADAR_MANAGED_EXECUTION_GENERATION",
|
|
254
|
+
"PI_RADAR_MANAGED_PARENT_SUBJECT_ID"
|
|
231
255
|
]);
|
|
232
256
|
function unresolvedSpawn(requestId, detail) {
|
|
233
257
|
return {
|
|
@@ -901,6 +925,56 @@ function createRadarClient(options = {}) {
|
|
|
901
925
|
return protocol("spawn.close reply carries no close outcome");
|
|
902
926
|
});
|
|
903
927
|
},
|
|
928
|
+
async communicationPublish(request) {
|
|
929
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
930
|
+
const answer = await call("communication.publish", {
|
|
931
|
+
sender_agent_id: request.sender_agent_id,
|
|
932
|
+
recipient_subject_id: request.recipient_subject_id,
|
|
933
|
+
...request.correlation_id !== void 0 ? { correlation_id: request.correlation_id } : {},
|
|
934
|
+
summary: request.summary,
|
|
935
|
+
content: request.content
|
|
936
|
+
}, request.request_id);
|
|
937
|
+
if (answer.ok === false) return answer;
|
|
938
|
+
const handoff = handoffAt(recordAt(answer.value, "handoff"));
|
|
939
|
+
const created = recordAt(answer.value, "created");
|
|
940
|
+
if (handoff === void 0 || typeof created !== "boolean")
|
|
941
|
+
return protocol("communication.publish reply carries no handoff");
|
|
942
|
+
return { ok: true, value: { handoff, created } };
|
|
943
|
+
});
|
|
944
|
+
},
|
|
945
|
+
async communicationInbox(request) {
|
|
946
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
947
|
+
const answer = await call("communication.inbox", request);
|
|
948
|
+
if (answer.ok === false) return answer;
|
|
949
|
+
const handoffIds = recordAt(answer.value, "handoff_ids");
|
|
950
|
+
if (!Array.isArray(handoffIds) || handoffIds.some((id) => !isUuid(id)))
|
|
951
|
+
return protocol("communication.inbox reply carries malformed handoff IDs");
|
|
952
|
+
return { ok: true, value: answer.value };
|
|
953
|
+
});
|
|
954
|
+
},
|
|
955
|
+
async communicationGet(request) {
|
|
956
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
957
|
+
const answer = await call("communication.get", request);
|
|
958
|
+
if (answer.ok === false) return answer;
|
|
959
|
+
const handoff = handoffAt(recordAt(answer.value, "handoff"));
|
|
960
|
+
const receiptValue = recordAt(answer.value, "receipt");
|
|
961
|
+
const receipt = receiptValue === null ? null : handoffReceiptAt(receiptValue);
|
|
962
|
+
if (handoff === void 0 || receiptValue !== null && receipt === void 0)
|
|
963
|
+
return protocol("communication.get reply carries malformed content or receipt");
|
|
964
|
+
return { ok: true, value: { handoff, receipt: receipt ?? null } };
|
|
965
|
+
});
|
|
966
|
+
},
|
|
967
|
+
async communicationAck(request) {
|
|
968
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
969
|
+
const answer = await call("communication.ack", request);
|
|
970
|
+
if (answer.ok === false) return answer;
|
|
971
|
+
const receipt = handoffReceiptAt(recordAt(answer.value, "receipt"));
|
|
972
|
+
const created = recordAt(answer.value, "created");
|
|
973
|
+
if (receipt === void 0 || typeof created !== "boolean")
|
|
974
|
+
return protocol("communication.ack reply carries no receipt");
|
|
975
|
+
return { ok: true, value: { receipt, created } };
|
|
976
|
+
});
|
|
977
|
+
},
|
|
904
978
|
async events(request) {
|
|
905
979
|
if (!Number.isSafeInteger(request.after) || request.after < 0 || !Number.isSafeInteger(request.wait_ms) || request.wait_ms < 0 || request.wait_ms > RADAR_EVENT_WAIT_MS)
|
|
906
980
|
return {
|
|
@@ -1122,6 +1196,7 @@ function boundedRadarSnapshot(snapshot) {
|
|
|
1122
1196
|
}
|
|
1123
1197
|
export {
|
|
1124
1198
|
RADAR_CALL_TIMEOUT_MS,
|
|
1199
|
+
RADAR_COMMUNICATION_CONTRACT,
|
|
1125
1200
|
RADAR_EVENTS_CONTRACT,
|
|
1126
1201
|
RADAR_EVENT_RETRY_MS,
|
|
1127
1202
|
RADAR_MAX_AWAITED,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// extension/radar-communication.ts
|
|
2
|
+
function createRadarHandoffPort(client, publication, parentSubjectId = () => process.env.PI_RADAR_MANAGED_PARENT_SUBJECT_ID) {
|
|
3
|
+
async function agentId() {
|
|
4
|
+
const subject = await publication.subject();
|
|
5
|
+
return subject === void 0 ? { ok: false, code: "absent", message: "this process has no current Radar registration" } : { ok: true, value: subject.agent_id };
|
|
6
|
+
}
|
|
7
|
+
return {
|
|
8
|
+
async publish(request) {
|
|
9
|
+
const identity = await agentId();
|
|
10
|
+
if (identity.ok === false) return identity;
|
|
11
|
+
const parent = parentSubjectId();
|
|
12
|
+
if (parent === void 0)
|
|
13
|
+
return { ok: false, code: "absent", message: "this managed execution has no Radar parent subject" };
|
|
14
|
+
return client.communicationPublish({
|
|
15
|
+
...request,
|
|
16
|
+
sender_agent_id: identity.value,
|
|
17
|
+
recipient_subject_id: parent
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
async inbox() {
|
|
21
|
+
const identity = await agentId();
|
|
22
|
+
if (identity.ok === false) return identity;
|
|
23
|
+
return client.communicationInbox({ agent_id: identity.value });
|
|
24
|
+
},
|
|
25
|
+
async get(handoff_id) {
|
|
26
|
+
const identity = await agentId();
|
|
27
|
+
if (identity.ok === false) return identity;
|
|
28
|
+
return client.communicationGet({ agent_id: identity.value, handoff_id });
|
|
29
|
+
},
|
|
30
|
+
async ack(handoff_id) {
|
|
31
|
+
const identity = await agentId();
|
|
32
|
+
if (identity.ok === false) return identity;
|
|
33
|
+
return client.communicationAck({ agent_id: identity.value, handoff_id });
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
createRadarHandoffPort
|
|
39
|
+
};
|
|
@@ -1221,8 +1221,10 @@ function createRadarPublicationInner(options) {
|
|
|
1221
1221
|
const record = await ensureRegistration();
|
|
1222
1222
|
if (record === void 0) return void 0;
|
|
1223
1223
|
const location = record.registration.location;
|
|
1224
|
+
const subjectId = process.env.PI_RADAR_MANAGED_SUBJECT_ID;
|
|
1224
1225
|
return {
|
|
1225
1226
|
agent_id: agentId2,
|
|
1227
|
+
...subjectId !== void 0 ? { subject_id: subjectId } : {},
|
|
1226
1228
|
...location !== void 0 ? { location } : {}
|
|
1227
1229
|
};
|
|
1228
1230
|
},
|
|
@@ -146,6 +146,10 @@ async function launchRadarWorker(options) {
|
|
|
146
146
|
return refusedLaunch(
|
|
147
147
|
"the launch has no exact parent registration to spawn under"
|
|
148
148
|
);
|
|
149
|
+
if (!isUuid(launch.parent.subject_id))
|
|
150
|
+
return refusedLaunch(
|
|
151
|
+
"the launch has no managed Radar subject for its parent"
|
|
152
|
+
);
|
|
149
153
|
if (pane === void 0 || pane === "")
|
|
150
154
|
return refusedLaunch(
|
|
151
155
|
"this process's Radar registration names no pane, so it cannot be a spawn parent"
|
|
@@ -155,6 +159,7 @@ async function launchRadarWorker(options) {
|
|
|
155
159
|
parent: launch.parent.agent_id,
|
|
156
160
|
parent_session_id: launch.parent_session_id,
|
|
157
161
|
executable: launch.executable,
|
|
162
|
+
managed: { parent_subject_id: launch.parent.subject_id },
|
|
158
163
|
argv: launch.argv,
|
|
159
164
|
...launch.cwd !== "" ? { cwd: launch.cwd } : {},
|
|
160
165
|
...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
|
|
@@ -1176,8 +1176,10 @@ function createRadarPublicationInner(options) {
|
|
|
1176
1176
|
const record = await ensureRegistration();
|
|
1177
1177
|
if (record === void 0) return void 0;
|
|
1178
1178
|
const location = record.registration.location;
|
|
1179
|
+
const subjectId = process.env.PI_RADAR_MANAGED_SUBJECT_ID;
|
|
1179
1180
|
return {
|
|
1180
1181
|
agent_id: agentId2,
|
|
1182
|
+
...subjectId !== void 0 ? { subject_id: subjectId } : {},
|
|
1181
1183
|
...location !== void 0 ? { location } : {}
|
|
1182
1184
|
};
|
|
1183
1185
|
},
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ var __export = (target, all) => {
|
|
|
8
8
|
var radar_client_exports = {};
|
|
9
9
|
__export(radar_client_exports, {
|
|
10
10
|
RADAR_CALL_TIMEOUT_MS: () => RADAR_CALL_TIMEOUT_MS,
|
|
11
|
+
RADAR_COMMUNICATION_CONTRACT: () => RADAR_COMMUNICATION_CONTRACT,
|
|
11
12
|
RADAR_EVENTS_CONTRACT: () => RADAR_EVENTS_CONTRACT,
|
|
12
13
|
RADAR_EVENT_RETRY_MS: () => RADAR_EVENT_RETRY_MS,
|
|
13
14
|
RADAR_MAX_AWAITED: () => RADAR_MAX_AWAITED,
|
|
@@ -45,6 +46,7 @@ var RADAR_SPAWN_CONTRACT = "spawn.v1";
|
|
|
45
46
|
var RADAR_SPAWN_CLOSE_CONTRACT = "spawn.close.v1";
|
|
46
47
|
var RADAR_SPAWN_LAUNCH_CONTEXT_CONTRACT = "spawn.launch_context.v1";
|
|
47
48
|
var RADAR_EVENTS_CONTRACT = "events.v1";
|
|
49
|
+
var RADAR_COMMUNICATION_CONTRACT = "communication.handoff.v1";
|
|
48
50
|
var RADAR_REQUESTER = "pi-radar";
|
|
49
51
|
var RADAR_MAX_LINE_BYTES = 1024 * 1024;
|
|
50
52
|
var RADAR_CALL_TIMEOUT_MS = 2e3;
|
|
@@ -152,6 +154,28 @@ function numberAt(value, field) {
|
|
|
152
154
|
const found = value[field];
|
|
153
155
|
return typeof found === "number" && Number.isFinite(found) ? found : void 0;
|
|
154
156
|
}
|
|
157
|
+
function handoffAt(value) {
|
|
158
|
+
const version = numberAt(value, "version");
|
|
159
|
+
const id = stringAt(value, "id");
|
|
160
|
+
const sender = recordAt(value, "sender");
|
|
161
|
+
const senderGeneration = numberAt(sender, "execution_generation");
|
|
162
|
+
const target = stringAt(value, "recipient_subject_id");
|
|
163
|
+
const summary = stringAt(value, "summary");
|
|
164
|
+
const content = stringAt(value, "content");
|
|
165
|
+
const published = numberAt(value, "published_at_unix_ms");
|
|
166
|
+
const correlation = typeof value === "object" && value !== null ? value.correlation_id : void 0;
|
|
167
|
+
if (version !== 1 || !isUuid(id) || !isUuid(stringAt(sender, "agent_id")) || !isUuid(stringAt(sender, "session_id")) || !isUuid(stringAt(sender, "subject_id")) || !isUuid(stringAt(sender, "execution_id")) || !Number.isSafeInteger(senderGeneration) || (senderGeneration ?? 0) < 1 || !isUuid(target) || summary === void 0 || content === void 0 || published === void 0 || !Number.isSafeInteger(published) || published < 0 || correlation !== void 0 && correlation !== null && (typeof correlation !== "string" || correlation.length === 0 || Buffer.byteLength(correlation, "utf8") > 256 || new RegExp("\\p{Cc}", "u").test(correlation))) return void 0;
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
170
|
+
function handoffReceiptAt(value) {
|
|
171
|
+
const version = numberAt(value, "version");
|
|
172
|
+
const handoffId = stringAt(value, "handoff_id");
|
|
173
|
+
const recipient = recordAt(value, "recipient");
|
|
174
|
+
const generation = numberAt(recipient, "execution_generation");
|
|
175
|
+
const received = numberAt(value, "received_at_unix_ms");
|
|
176
|
+
if (version !== 1 || !isUuid(handoffId) || !isUuid(stringAt(recipient, "agent_id")) || !isUuid(stringAt(recipient, "session_id")) || !isUuid(stringAt(recipient, "subject_id")) || !isUuid(stringAt(recipient, "execution_id")) || !Number.isSafeInteger(generation) || (generation ?? 0) < 1 || received === void 0 || !Number.isSafeInteger(received) || received < 0) return void 0;
|
|
177
|
+
return value;
|
|
178
|
+
}
|
|
155
179
|
function writerBinding(value) {
|
|
156
180
|
const handle = stringAt(value, "handle");
|
|
157
181
|
const source = stringAt(value, "source");
|
|
@@ -261,7 +285,8 @@ var RADAR_SPAWN_TOKEN_ENV = "PI_RADAR_SPAWN_TOKEN";
|
|
|
261
285
|
var RADAR_MANAGED_IDENTITY_ENV = /* @__PURE__ */ new Set([
|
|
262
286
|
"PI_RADAR_MANAGED_SUBJECT_ID",
|
|
263
287
|
"PI_RADAR_MANAGED_LAUNCH_ID",
|
|
264
|
-
"PI_RADAR_MANAGED_EXECUTION_GENERATION"
|
|
288
|
+
"PI_RADAR_MANAGED_EXECUTION_GENERATION",
|
|
289
|
+
"PI_RADAR_MANAGED_PARENT_SUBJECT_ID"
|
|
265
290
|
]);
|
|
266
291
|
function unresolvedSpawn(requestId, detail) {
|
|
267
292
|
return {
|
|
@@ -935,6 +960,56 @@ function createRadarClient(options = {}) {
|
|
|
935
960
|
return protocol("spawn.close reply carries no close outcome");
|
|
936
961
|
});
|
|
937
962
|
},
|
|
963
|
+
async communicationPublish(request) {
|
|
964
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
965
|
+
const answer = await call("communication.publish", {
|
|
966
|
+
sender_agent_id: request.sender_agent_id,
|
|
967
|
+
recipient_subject_id: request.recipient_subject_id,
|
|
968
|
+
...request.correlation_id !== void 0 ? { correlation_id: request.correlation_id } : {},
|
|
969
|
+
summary: request.summary,
|
|
970
|
+
content: request.content
|
|
971
|
+
}, request.request_id);
|
|
972
|
+
if (answer.ok === false) return answer;
|
|
973
|
+
const handoff = handoffAt(recordAt(answer.value, "handoff"));
|
|
974
|
+
const created = recordAt(answer.value, "created");
|
|
975
|
+
if (handoff === void 0 || typeof created !== "boolean")
|
|
976
|
+
return protocol("communication.publish reply carries no handoff");
|
|
977
|
+
return { ok: true, value: { handoff, created } };
|
|
978
|
+
});
|
|
979
|
+
},
|
|
980
|
+
async communicationInbox(request) {
|
|
981
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
982
|
+
const answer = await call("communication.inbox", request);
|
|
983
|
+
if (answer.ok === false) return answer;
|
|
984
|
+
const handoffIds = recordAt(answer.value, "handoff_ids");
|
|
985
|
+
if (!Array.isArray(handoffIds) || handoffIds.some((id) => !isUuid(id)))
|
|
986
|
+
return protocol("communication.inbox reply carries malformed handoff IDs");
|
|
987
|
+
return { ok: true, value: answer.value };
|
|
988
|
+
});
|
|
989
|
+
},
|
|
990
|
+
async communicationGet(request) {
|
|
991
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
992
|
+
const answer = await call("communication.get", request);
|
|
993
|
+
if (answer.ok === false) return answer;
|
|
994
|
+
const handoff = handoffAt(recordAt(answer.value, "handoff"));
|
|
995
|
+
const receiptValue = recordAt(answer.value, "receipt");
|
|
996
|
+
const receipt = receiptValue === null ? null : handoffReceiptAt(receiptValue);
|
|
997
|
+
if (handoff === void 0 || receiptValue !== null && receipt === void 0)
|
|
998
|
+
return protocol("communication.get reply carries malformed content or receipt");
|
|
999
|
+
return { ok: true, value: { handoff, receipt: receipt ?? null } };
|
|
1000
|
+
});
|
|
1001
|
+
},
|
|
1002
|
+
async communicationAck(request) {
|
|
1003
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
1004
|
+
const answer = await call("communication.ack", request);
|
|
1005
|
+
if (answer.ok === false) return answer;
|
|
1006
|
+
const receipt = handoffReceiptAt(recordAt(answer.value, "receipt"));
|
|
1007
|
+
const created = recordAt(answer.value, "created");
|
|
1008
|
+
if (receipt === void 0 || typeof created !== "boolean")
|
|
1009
|
+
return protocol("communication.ack reply carries no receipt");
|
|
1010
|
+
return { ok: true, value: { receipt, created } };
|
|
1011
|
+
});
|
|
1012
|
+
},
|
|
938
1013
|
async events(request) {
|
|
939
1014
|
if (!Number.isSafeInteger(request.after) || request.after < 0 || !Number.isSafeInteger(request.wait_ms) || request.wait_ms < 0 || request.wait_ms > RADAR_EVENT_WAIT_MS)
|
|
940
1015
|
return {
|
|
@@ -1155,6 +1230,47 @@ function boundedRadarSnapshot(snapshot) {
|
|
|
1155
1230
|
};
|
|
1156
1231
|
}
|
|
1157
1232
|
|
|
1233
|
+
// extension/radar-communication.ts
|
|
1234
|
+
var radar_communication_exports = {};
|
|
1235
|
+
__export(radar_communication_exports, {
|
|
1236
|
+
createRadarHandoffPort: () => createRadarHandoffPort
|
|
1237
|
+
});
|
|
1238
|
+
function createRadarHandoffPort(client, publication, parentSubjectId = () => process.env.PI_RADAR_MANAGED_PARENT_SUBJECT_ID) {
|
|
1239
|
+
async function agentId() {
|
|
1240
|
+
const subject = await publication.subject();
|
|
1241
|
+
return subject === void 0 ? { ok: false, code: "absent", message: "this process has no current Radar registration" } : { ok: true, value: subject.agent_id };
|
|
1242
|
+
}
|
|
1243
|
+
return {
|
|
1244
|
+
async publish(request) {
|
|
1245
|
+
const identity = await agentId();
|
|
1246
|
+
if (identity.ok === false) return identity;
|
|
1247
|
+
const parent = parentSubjectId();
|
|
1248
|
+
if (parent === void 0)
|
|
1249
|
+
return { ok: false, code: "absent", message: "this managed execution has no Radar parent subject" };
|
|
1250
|
+
return client.communicationPublish({
|
|
1251
|
+
...request,
|
|
1252
|
+
sender_agent_id: identity.value,
|
|
1253
|
+
recipient_subject_id: parent
|
|
1254
|
+
});
|
|
1255
|
+
},
|
|
1256
|
+
async inbox() {
|
|
1257
|
+
const identity = await agentId();
|
|
1258
|
+
if (identity.ok === false) return identity;
|
|
1259
|
+
return client.communicationInbox({ agent_id: identity.value });
|
|
1260
|
+
},
|
|
1261
|
+
async get(handoff_id) {
|
|
1262
|
+
const identity = await agentId();
|
|
1263
|
+
if (identity.ok === false) return identity;
|
|
1264
|
+
return client.communicationGet({ agent_id: identity.value, handoff_id });
|
|
1265
|
+
},
|
|
1266
|
+
async ack(handoff_id) {
|
|
1267
|
+
const identity = await agentId();
|
|
1268
|
+
if (identity.ok === false) return identity;
|
|
1269
|
+
return client.communicationAck({ agent_id: identity.value, handoff_id });
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1158
1274
|
// extension/radar-execution.ts
|
|
1159
1275
|
var radar_execution_exports = {};
|
|
1160
1276
|
__export(radar_execution_exports, {
|
|
@@ -2307,8 +2423,10 @@ function createRadarPublicationInner(options) {
|
|
|
2307
2423
|
const record = await ensureRegistration();
|
|
2308
2424
|
if (record === void 0) return void 0;
|
|
2309
2425
|
const location = record.registration.location;
|
|
2426
|
+
const subjectId = process.env.PI_RADAR_MANAGED_SUBJECT_ID;
|
|
2310
2427
|
return {
|
|
2311
2428
|
agent_id: agentId2,
|
|
2429
|
+
...subjectId !== void 0 ? { subject_id: subjectId } : {},
|
|
2312
2430
|
...location !== void 0 ? { location } : {}
|
|
2313
2431
|
};
|
|
2314
2432
|
},
|
|
@@ -2910,6 +3028,10 @@ async function launchRadarWorker(options) {
|
|
|
2910
3028
|
return refusedLaunch(
|
|
2911
3029
|
"the launch has no exact parent registration to spawn under"
|
|
2912
3030
|
);
|
|
3031
|
+
if (!isUuid(launch.parent.subject_id))
|
|
3032
|
+
return refusedLaunch(
|
|
3033
|
+
"the launch has no managed Radar subject for its parent"
|
|
3034
|
+
);
|
|
2913
3035
|
if (pane === void 0 || pane === "")
|
|
2914
3036
|
return refusedLaunch(
|
|
2915
3037
|
"this process's Radar registration names no pane, so it cannot be a spawn parent"
|
|
@@ -2919,6 +3041,7 @@ async function launchRadarWorker(options) {
|
|
|
2919
3041
|
parent: launch.parent.agent_id,
|
|
2920
3042
|
parent_session_id: launch.parent_session_id,
|
|
2921
3043
|
executable: launch.executable,
|
|
3044
|
+
managed: { parent_subject_id: launch.parent.subject_id },
|
|
2922
3045
|
argv: launch.argv,
|
|
2923
3046
|
...launch.cwd !== "" ? { cwd: launch.cwd } : {},
|
|
2924
3047
|
...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
|
|
@@ -3056,7 +3179,7 @@ __export(radar_runtime_exports, {
|
|
|
3056
3179
|
requestRadarRuntime: () => requestRadarRuntime
|
|
3057
3180
|
});
|
|
3058
3181
|
var RADAR_RUNTIME_REQUEST = "pi-radar/runtime-request";
|
|
3059
|
-
var RADAR_RUNTIME_VERSION =
|
|
3182
|
+
var RADAR_RUNTIME_VERSION = 2;
|
|
3060
3183
|
function lazyRadarRuntime(start) {
|
|
3061
3184
|
let pending;
|
|
3062
3185
|
return {
|
|
@@ -3091,6 +3214,7 @@ function isRadarRuntimeHandle(value) {
|
|
|
3091
3214
|
}
|
|
3092
3215
|
export {
|
|
3093
3216
|
radar_client_exports as client,
|
|
3217
|
+
radar_communication_exports as communication,
|
|
3094
3218
|
radar_execution_exports as execution,
|
|
3095
3219
|
radar_inspection_exports as inspection,
|
|
3096
3220
|
radar_launch_exports as launch,
|
package/extension/baseline.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { createRadarClient } from "./radar-client.ts";
|
|
4
|
+
import { createRadarHandoffPort } from "./radar-communication.ts";
|
|
4
5
|
import {
|
|
5
6
|
createRadarExecutionAdapter,
|
|
6
7
|
type RadarExecutionEventApi,
|
|
@@ -31,6 +32,7 @@ export default function registerPiRadar(pi: PiRadarHost): void {
|
|
|
31
32
|
});
|
|
32
33
|
const runtime = lazyRadarRuntime(async () => ({
|
|
33
34
|
publication: execution.publication,
|
|
35
|
+
communication: createRadarHandoffPort(client, execution.publication),
|
|
34
36
|
execution,
|
|
35
37
|
}));
|
|
36
38
|
provideRadarRuntime(pi.events, runtime);
|