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.
- package/README.md +10 -4
- package/dist/extension/baseline.js +333 -394
- package/dist/extension/radar-client.js +126 -11
- package/dist/extension/radar-communication.js +39 -0
- package/dist/extension/radar-execution.js +169 -382
- package/dist/extension/radar-launch.js +18 -13
- package/dist/extension/radar-publication.js +161 -298
- package/dist/extension/radar-runtime.js +1 -1
- package/dist/index.js +356 -407
- package/extension/baseline.ts +2 -0
- package/extension/generated-contracts.ts +1310 -10
- package/extension/radar-client.ts +191 -23
- package/extension/radar-communication.ts +66 -0
- package/extension/radar-execution.ts +11 -58
- package/extension/radar-launch.ts +29 -22
- package/extension/radar-publication.ts +211 -410
- package/extension/radar-runtime.ts +4 -1
- package/index.ts +1 -0
- package/package.json +9 -5
- 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/schema/public/v1/observation-get-params.deserialize.schema.json +46 -0
- package/schema/public/v1/observation-get-params.serialize.schema.json +52 -0
- package/schema/public/v1/observation-get-response.deserialize.schema.json +2731 -0
- package/schema/public/v1/observation-get-response.serialize.schema.json +2862 -0
- package/schema/public/v1/observation-snapshot.deserialize.schema.json +2616 -0
- package/schema/public/v1/observation-snapshot.serialize.schema.json +2741 -0
- package/schema/public/v1/presence-answer.deserialize.schema.json +40 -0
- package/schema/public/v1/presence-answer.serialize.schema.json +40 -0
- package/schema/public/v1/presence-release.deserialize.schema.json +51 -0
- package/schema/public/v1/presence-release.serialize.schema.json +52 -0
- package/schema/public/v1/presence-report.deserialize.schema.json +149 -0
- package/schema/public/v1/presence-report.serialize.schema.json +157 -0
- package/extension/radar-session-marker.ts +0 -146
- package/schema/public/v1/launch-identity-marker.deserialize.schema.json +0 -32
- package/schema/public/v1/launch-identity-marker.serialize.schema.json +0 -32
|
@@ -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;
|
|
@@ -108,6 +109,25 @@ function recordAt(value, field) {
|
|
|
108
109
|
function isUuid(value) {
|
|
109
110
|
return typeof value === "string" && UUID.test(value);
|
|
110
111
|
}
|
|
112
|
+
function decodePresenceAnswer(value) {
|
|
113
|
+
const registrationId = recordAt(value, "registration_id");
|
|
114
|
+
const claimId = recordAt(value, "claim_id");
|
|
115
|
+
const standing = recordAt(value, "standing");
|
|
116
|
+
const subjectId = recordAt(value, "subject_id");
|
|
117
|
+
if (!isUuid(registrationId) || !isUuid(claimId) || !["pending", "granted", "duplicate", "released"].includes(String(standing)) || subjectId !== void 0 && !isUuid(subjectId) || standing === "granted" && !isUuid(subjectId))
|
|
118
|
+
return protocol("presence reply carries no valid claim standing");
|
|
119
|
+
return { ok: true, value };
|
|
120
|
+
}
|
|
121
|
+
function managementAt(value) {
|
|
122
|
+
const field = recordAt(value, "management");
|
|
123
|
+
const state = stringAt(field, "state");
|
|
124
|
+
if (state === "managed") {
|
|
125
|
+
const subjectId = stringAt(field, "subject_id");
|
|
126
|
+
return subjectId === void 0 ? void 0 : { state, subject_id: subjectId };
|
|
127
|
+
}
|
|
128
|
+
if (state === "duplicate" || state === "pending" || state === "unmanaged") return { state };
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
111
131
|
function stringAt(value, field) {
|
|
112
132
|
if (typeof value !== "object" || value === null) return void 0;
|
|
113
133
|
const found = value[field];
|
|
@@ -118,6 +138,28 @@ function numberAt(value, field) {
|
|
|
118
138
|
const found = value[field];
|
|
119
139
|
return typeof found === "number" && Number.isFinite(found) ? found : void 0;
|
|
120
140
|
}
|
|
141
|
+
function handoffAt(value) {
|
|
142
|
+
const version = numberAt(value, "version");
|
|
143
|
+
const id = stringAt(value, "id");
|
|
144
|
+
const sender = recordAt(value, "sender");
|
|
145
|
+
const senderGeneration = numberAt(sender, "execution_generation");
|
|
146
|
+
const target = stringAt(value, "recipient_subject_id");
|
|
147
|
+
const summary = stringAt(value, "summary");
|
|
148
|
+
const content = stringAt(value, "content");
|
|
149
|
+
const published = numberAt(value, "published_at_unix_ms");
|
|
150
|
+
const correlation = typeof value === "object" && value !== null ? value.correlation_id : void 0;
|
|
151
|
+
if (version !== 1 || !isUuid(id) || !isUuid(stringAt(sender, "registration_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;
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
function handoffReceiptAt(value) {
|
|
155
|
+
const version = numberAt(value, "version");
|
|
156
|
+
const handoffId = stringAt(value, "handoff_id");
|
|
157
|
+
const recipient = recordAt(value, "recipient");
|
|
158
|
+
const generation = numberAt(recipient, "execution_generation");
|
|
159
|
+
const received = numberAt(value, "received_at_unix_ms");
|
|
160
|
+
if (version !== 1 || !isUuid(handoffId) || !isUuid(stringAt(recipient, "registration_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;
|
|
161
|
+
return value;
|
|
162
|
+
}
|
|
121
163
|
function writerBinding(value) {
|
|
122
164
|
const handle = stringAt(value, "handle");
|
|
123
165
|
const source = stringAt(value, "source");
|
|
@@ -227,7 +269,8 @@ var RADAR_SPAWN_TOKEN_ENV = "PI_RADAR_SPAWN_TOKEN";
|
|
|
227
269
|
var RADAR_MANAGED_IDENTITY_ENV = /* @__PURE__ */ new Set([
|
|
228
270
|
"PI_RADAR_MANAGED_SUBJECT_ID",
|
|
229
271
|
"PI_RADAR_MANAGED_LAUNCH_ID",
|
|
230
|
-
"PI_RADAR_MANAGED_EXECUTION_GENERATION"
|
|
272
|
+
"PI_RADAR_MANAGED_EXECUTION_GENERATION",
|
|
273
|
+
"PI_RADAR_MANAGED_PARENT_SUBJECT_ID"
|
|
231
274
|
]);
|
|
232
275
|
function unresolvedSpawn(requestId, detail) {
|
|
233
276
|
return {
|
|
@@ -272,7 +315,7 @@ function spawnEdge(value) {
|
|
|
272
315
|
const bound = recordAt(value, "bound");
|
|
273
316
|
const source = stringAt(bound, "source");
|
|
274
317
|
const incarnation = stringAt(bound, "incarnation");
|
|
275
|
-
const agentId = stringAt(bound, "
|
|
318
|
+
const agentId = stringAt(bound, "registration_id");
|
|
276
319
|
const exit = exitAt(recordAt(value, "exit_observation"));
|
|
277
320
|
return {
|
|
278
321
|
ok: true,
|
|
@@ -286,7 +329,7 @@ function spawnEdge(value) {
|
|
|
286
329
|
bound: {
|
|
287
330
|
source,
|
|
288
331
|
incarnation,
|
|
289
|
-
...isUuid(agentId) ? {
|
|
332
|
+
...isUuid(agentId) ? { registration_id: agentId } : {}
|
|
290
333
|
}
|
|
291
334
|
} : {},
|
|
292
335
|
...exit !== void 0 ? { exit_observation: exit } : {}
|
|
@@ -684,6 +727,22 @@ function createRadarClient(options = {}) {
|
|
|
684
727
|
return {
|
|
685
728
|
socketPath,
|
|
686
729
|
ping,
|
|
730
|
+
async presence(request) {
|
|
731
|
+
return withRegistry(async () => {
|
|
732
|
+
const answer = await call("agent.presence", { ...request });
|
|
733
|
+
if (!answer.ok) return answer;
|
|
734
|
+
return decodePresenceAnswer(answer.value);
|
|
735
|
+
});
|
|
736
|
+
},
|
|
737
|
+
async releasePresence(request) {
|
|
738
|
+
return withRegistry(async () => {
|
|
739
|
+
const answer = await call("agent.release", { ...request });
|
|
740
|
+
if (!answer.ok) return answer;
|
|
741
|
+
const decoded = decodePresenceAnswer(answer.value);
|
|
742
|
+
if (!decoded.ok) return decoded;
|
|
743
|
+
return decoded.value.standing === "released" ? decoded : protocol("release reply did not confirm the claim release");
|
|
744
|
+
});
|
|
745
|
+
},
|
|
687
746
|
async register(registration) {
|
|
688
747
|
return withRegistry(async () => {
|
|
689
748
|
const answer = await call("agent.register", {
|
|
@@ -699,15 +758,15 @@ function createRadarClient(options = {}) {
|
|
|
699
758
|
});
|
|
700
759
|
if (answer.ok === false) return answer;
|
|
701
760
|
const record = answer.value.registration;
|
|
702
|
-
const agentId = stringAt(record, "
|
|
703
|
-
if (!isUuid(agentId)) return protocol("registration reply carries no
|
|
704
|
-
return { ok: true, value: {
|
|
761
|
+
const agentId = stringAt(record, "registration_id");
|
|
762
|
+
if (!isUuid(agentId)) return protocol("registration reply carries no registration_id");
|
|
763
|
+
return { ok: true, value: { registration_id: agentId } };
|
|
705
764
|
});
|
|
706
765
|
},
|
|
707
766
|
async acquire(request) {
|
|
708
767
|
return withRegistryChannel(request.channel, async () => {
|
|
709
768
|
const answer = await call("agent.acquire", {
|
|
710
|
-
|
|
769
|
+
registration_id: request.registration_id,
|
|
711
770
|
channel: request.channel,
|
|
712
771
|
publisher: request.publisher,
|
|
713
772
|
...request.replace !== void 0 ? { replace: request.replace } : {}
|
|
@@ -736,7 +795,7 @@ function createRadarClient(options = {}) {
|
|
|
736
795
|
}
|
|
737
796
|
return withRegistryChannel(request.channel, async () => {
|
|
738
797
|
const answer = await call("agent.publish", {
|
|
739
|
-
|
|
798
|
+
registration_id: request.registration_id,
|
|
740
799
|
channel: request.channel,
|
|
741
800
|
writer_handle: request.writer_handle,
|
|
742
801
|
sequence: request.sequence,
|
|
@@ -755,7 +814,7 @@ function createRadarClient(options = {}) {
|
|
|
755
814
|
async context(request) {
|
|
756
815
|
return withRegistry(async () => {
|
|
757
816
|
const answer = await call("agent.context", {
|
|
758
|
-
|
|
817
|
+
registration_id: request.registration_id,
|
|
759
818
|
publisher: request.publisher,
|
|
760
819
|
...request.writer_handle !== void 0 ? { writer_handle: request.writer_handle } : {},
|
|
761
820
|
...request.replace !== void 0 ? { replace: request.replace } : {},
|
|
@@ -771,9 +830,14 @@ function createRadarClient(options = {}) {
|
|
|
771
830
|
if (writer === void 0)
|
|
772
831
|
return protocol("context reply carries no writer binding");
|
|
773
832
|
const warning = stringAt(answer.value, "warning");
|
|
833
|
+
const management = managementAt(answer.value);
|
|
774
834
|
return {
|
|
775
835
|
ok: true,
|
|
776
|
-
value: {
|
|
836
|
+
value: {
|
|
837
|
+
writer,
|
|
838
|
+
...warning !== void 0 ? { warning } : {},
|
|
839
|
+
...management !== void 0 ? { management } : {}
|
|
840
|
+
}
|
|
777
841
|
};
|
|
778
842
|
});
|
|
779
843
|
},
|
|
@@ -850,7 +914,7 @@ function createRadarClient(options = {}) {
|
|
|
850
914
|
message: "agent.get requires a canonical agent UUID"
|
|
851
915
|
};
|
|
852
916
|
return withRegistry(async () => {
|
|
853
|
-
const answer = await call("agent.get", {
|
|
917
|
+
const answer = await call("agent.get", { registration_id: agentId });
|
|
854
918
|
if (answer.ok === false) return answer;
|
|
855
919
|
return agentProcessAt(recordAt(answer.value, "agent"));
|
|
856
920
|
});
|
|
@@ -901,6 +965,56 @@ function createRadarClient(options = {}) {
|
|
|
901
965
|
return protocol("spawn.close reply carries no close outcome");
|
|
902
966
|
});
|
|
903
967
|
},
|
|
968
|
+
async communicationPublish(request) {
|
|
969
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
970
|
+
const answer = await call("communication.publish", {
|
|
971
|
+
sender_registration_id: request.sender_registration_id,
|
|
972
|
+
recipient_subject_id: request.recipient_subject_id,
|
|
973
|
+
...request.correlation_id !== void 0 ? { correlation_id: request.correlation_id } : {},
|
|
974
|
+
summary: request.summary,
|
|
975
|
+
content: request.content
|
|
976
|
+
}, request.request_id);
|
|
977
|
+
if (answer.ok === false) return answer;
|
|
978
|
+
const handoff = handoffAt(recordAt(answer.value, "handoff"));
|
|
979
|
+
const created = recordAt(answer.value, "created");
|
|
980
|
+
if (handoff === void 0 || typeof created !== "boolean")
|
|
981
|
+
return protocol("communication.publish reply carries no handoff");
|
|
982
|
+
return { ok: true, value: { handoff, created } };
|
|
983
|
+
});
|
|
984
|
+
},
|
|
985
|
+
async communicationInbox(request) {
|
|
986
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
987
|
+
const answer = await call("communication.inbox", request);
|
|
988
|
+
if (answer.ok === false) return answer;
|
|
989
|
+
const handoffIds = recordAt(answer.value, "handoff_ids");
|
|
990
|
+
if (!Array.isArray(handoffIds) || handoffIds.some((id) => !isUuid(id)))
|
|
991
|
+
return protocol("communication.inbox reply carries malformed handoff IDs");
|
|
992
|
+
return { ok: true, value: answer.value };
|
|
993
|
+
});
|
|
994
|
+
},
|
|
995
|
+
async communicationGet(request) {
|
|
996
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
997
|
+
const answer = await call("communication.get", request);
|
|
998
|
+
if (answer.ok === false) return answer;
|
|
999
|
+
const handoff = handoffAt(recordAt(answer.value, "handoff"));
|
|
1000
|
+
const receiptValue = recordAt(answer.value, "receipt");
|
|
1001
|
+
const receipt = receiptValue === null ? null : handoffReceiptAt(receiptValue);
|
|
1002
|
+
if (handoff === void 0 || receiptValue !== null && receipt === void 0)
|
|
1003
|
+
return protocol("communication.get reply carries malformed content or receipt");
|
|
1004
|
+
return { ok: true, value: { handoff, receipt: receipt ?? null } };
|
|
1005
|
+
});
|
|
1006
|
+
},
|
|
1007
|
+
async communicationAck(request) {
|
|
1008
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
1009
|
+
const answer = await call("communication.ack", request);
|
|
1010
|
+
if (answer.ok === false) return answer;
|
|
1011
|
+
const receipt = handoffReceiptAt(recordAt(answer.value, "receipt"));
|
|
1012
|
+
const created = recordAt(answer.value, "created");
|
|
1013
|
+
if (receipt === void 0 || typeof created !== "boolean")
|
|
1014
|
+
return protocol("communication.ack reply carries no receipt");
|
|
1015
|
+
return { ok: true, value: { receipt, created } };
|
|
1016
|
+
});
|
|
1017
|
+
},
|
|
904
1018
|
async events(request) {
|
|
905
1019
|
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
1020
|
return {
|
|
@@ -1122,6 +1236,7 @@ function boundedRadarSnapshot(snapshot) {
|
|
|
1122
1236
|
}
|
|
1123
1237
|
export {
|
|
1124
1238
|
RADAR_CALL_TIMEOUT_MS,
|
|
1239
|
+
RADAR_COMMUNICATION_CONTRACT,
|
|
1125
1240
|
RADAR_EVENTS_CONTRACT,
|
|
1126
1241
|
RADAR_EVENT_RETRY_MS,
|
|
1127
1242
|
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.registration_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_registration_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({ registration_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({ registration_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({ registration_id: identity.value, handoff_id });
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
createRadarHandoffPort
|
|
39
|
+
};
|