@sjawhar/pi-legion-envoy 0.43.0 → 0.44.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/dist/envoy.js +68 -1
- package/dist/legion.js +68 -1
- package/dist/skills/dispatch/SKILL.md +4 -2
- package/package.json +1 -1
package/dist/envoy.js
CHANGED
|
@@ -29725,6 +29725,11 @@ var ChildStatusEventPayloadSchema = object({
|
|
|
29725
29725
|
from: string2().optional(),
|
|
29726
29726
|
to: string2().optional()
|
|
29727
29727
|
});
|
|
29728
|
+
var SubscriptionRemovedEventPayloadSchema = object({
|
|
29729
|
+
session_id: string2().optional(),
|
|
29730
|
+
by: object({ kind: string2(), id: string2().optional() }).passthrough().optional(),
|
|
29731
|
+
topics: array(string2()).optional()
|
|
29732
|
+
});
|
|
29728
29733
|
// ../contracts/src/dispatch-snippet.ts
|
|
29729
29734
|
var HTML_ENTITIES = [
|
|
29730
29735
|
["<", "<"],
|
|
@@ -31107,6 +31112,18 @@ function renderInbound(raw, sessionID, subject) {
|
|
|
31107
31112
|
if (frame.event.actor.kind === "session" && frame.event.actor.id === sessionID) {
|
|
31108
31113
|
return { skip: true, content: "", envelope };
|
|
31109
31114
|
}
|
|
31115
|
+
if (frame.event.type === "subscription.removed") {
|
|
31116
|
+
const removed = SubscriptionRemovedEventPayloadSchema.safeParse(frame.event.payload);
|
|
31117
|
+
if (!removed.success || removed.data.session_id !== sessionID) {
|
|
31118
|
+
return { skip: true, content: "", envelope };
|
|
31119
|
+
}
|
|
31120
|
+
const who = removed.data.by?.id ?? "someone";
|
|
31121
|
+
return {
|
|
31122
|
+
skip: false,
|
|
31123
|
+
content: `Unsubscribed from ${dispatchOwner(frame.event, subject ?? envelope.topic)} by ${who}`,
|
|
31124
|
+
envelope
|
|
31125
|
+
};
|
|
31126
|
+
}
|
|
31110
31127
|
askQuestion = dispatchAskQuestion(frame.event);
|
|
31111
31128
|
messageReplyPreview = dispatchMessageReplyPreview(frame.event);
|
|
31112
31129
|
dispatchEvent = {
|
|
@@ -32387,6 +32404,46 @@ function dispatchSubscriptionTopic(details) {
|
|
|
32387
32404
|
const { topic } = details;
|
|
32388
32405
|
return typeof topic === "string" && topic.startsWith("notifications.dispatch.") ? topic : null;
|
|
32389
32406
|
}
|
|
32407
|
+
function dispatchTopicLabel(topic) {
|
|
32408
|
+
if (topic.startsWith(DISPATCH_ISSUE_TOPIC_PREFIX)) {
|
|
32409
|
+
const [key] = topic.slice(DISPATCH_ISSUE_TOPIC_PREFIX.length).split(".", 2);
|
|
32410
|
+
if (key !== undefined && key !== "")
|
|
32411
|
+
return key;
|
|
32412
|
+
}
|
|
32413
|
+
if (topic.startsWith(DISPATCH_DOCUMENT_TOPIC_PREFIX)) {
|
|
32414
|
+
const [project, slug] = topic.slice(DISPATCH_DOCUMENT_TOPIC_PREFIX.length).split(".", 3);
|
|
32415
|
+
if (project !== undefined && project !== "" && slug !== undefined && slug !== "") {
|
|
32416
|
+
return `${project}/${slug}`;
|
|
32417
|
+
}
|
|
32418
|
+
}
|
|
32419
|
+
return topic;
|
|
32420
|
+
}
|
|
32421
|
+
function subscriptionRemovedTopics(raw, sessionID) {
|
|
32422
|
+
let envelope;
|
|
32423
|
+
try {
|
|
32424
|
+
envelope = JSON.parse(raw);
|
|
32425
|
+
} catch {
|
|
32426
|
+
return;
|
|
32427
|
+
}
|
|
32428
|
+
if (typeof envelope !== "object" || envelope === null)
|
|
32429
|
+
return;
|
|
32430
|
+
const { source, payload } = envelope;
|
|
32431
|
+
if (source !== "dispatch" || typeof payload !== "string")
|
|
32432
|
+
return;
|
|
32433
|
+
let event;
|
|
32434
|
+
try {
|
|
32435
|
+
event = JSON.parse(payload);
|
|
32436
|
+
} catch {
|
|
32437
|
+
return;
|
|
32438
|
+
}
|
|
32439
|
+
const parsedEvent = DispatchEventSchema.safeParse(event);
|
|
32440
|
+
if (!parsedEvent.success || parsedEvent.data.type !== "subscription.removed")
|
|
32441
|
+
return;
|
|
32442
|
+
const parsedPayload = SubscriptionRemovedEventPayloadSchema.safeParse(parsedEvent.data.payload);
|
|
32443
|
+
if (!parsedPayload.success || parsedPayload.data.session_id !== sessionID)
|
|
32444
|
+
return;
|
|
32445
|
+
return parsedPayload.data.topics ?? [];
|
|
32446
|
+
}
|
|
32390
32447
|
|
|
32391
32448
|
// ../envoy-client/src/tool-contract.ts
|
|
32392
32449
|
var DELIVERY_CONTRACT = "Delivery is at-least-once, possibly out of order across topics; use id for dedupe and at for freshness.";
|
|
@@ -32864,6 +32921,8 @@ function envoyExtension(pi) {
|
|
|
32864
32921
|
};
|
|
32865
32922
|
const deliver = async (subject, raw, reply) => {
|
|
32866
32923
|
const rendered = renderInbound(raw, sessionID, subject);
|
|
32924
|
+
for (const topic of subscriptionRemovedTopics(raw, sessionID) ?? [])
|
|
32925
|
+
closeIntentionally(topic);
|
|
32867
32926
|
const dedupeKey = rendered.envelope?.dedupe_key;
|
|
32868
32927
|
const duplicate = dedupeKey !== undefined && dedupeKeys.has(dedupeKey);
|
|
32869
32928
|
if (!duplicate && !rendered.skip) {
|
|
@@ -33255,8 +33314,16 @@ function envoyExtension(pi) {
|
|
|
33255
33314
|
if (topic === null)
|
|
33256
33315
|
return;
|
|
33257
33316
|
try {
|
|
33258
|
-
|
|
33317
|
+
const isNew = await subscribe(topic);
|
|
33318
|
+
if (isNew)
|
|
33259
33319
|
await registerSession();
|
|
33320
|
+
if (isNew) {
|
|
33321
|
+
pi.sendMessage({
|
|
33322
|
+
customType: "envoy-message",
|
|
33323
|
+
content: `Subscribed to ${dispatchTopicLabel(topic)} (every event on this issue reaches you; envoy_unsubscribe ${topic} to stop).`,
|
|
33324
|
+
display: true
|
|
33325
|
+
}, { deliverAs: "steer", triggerTurn: false });
|
|
33326
|
+
}
|
|
33260
33327
|
} catch (error) {
|
|
33261
33328
|
activeSessionContext?.ui.notify(`envoy: dispatch reply auto-subscribe failed (${messageFor(error)}); run envoy_subscribe ${topic}`, "warning");
|
|
33262
33329
|
}
|
package/dist/legion.js
CHANGED
|
@@ -29724,6 +29724,11 @@ var ChildStatusEventPayloadSchema = object({
|
|
|
29724
29724
|
from: string2().optional(),
|
|
29725
29725
|
to: string2().optional()
|
|
29726
29726
|
});
|
|
29727
|
+
var SubscriptionRemovedEventPayloadSchema = object({
|
|
29728
|
+
session_id: string2().optional(),
|
|
29729
|
+
by: object({ kind: string2(), id: string2().optional() }).passthrough().optional(),
|
|
29730
|
+
topics: array(string2()).optional()
|
|
29731
|
+
});
|
|
29727
29732
|
// ../contracts/src/dispatch-snippet.ts
|
|
29728
29733
|
var HTML_ENTITIES = [
|
|
29729
29734
|
["<", "<"],
|
|
@@ -31554,6 +31559,18 @@ function renderInbound(raw, sessionID, subject) {
|
|
|
31554
31559
|
if (frame.event.actor.kind === "session" && frame.event.actor.id === sessionID) {
|
|
31555
31560
|
return { skip: true, content: "", envelope };
|
|
31556
31561
|
}
|
|
31562
|
+
if (frame.event.type === "subscription.removed") {
|
|
31563
|
+
const removed = SubscriptionRemovedEventPayloadSchema.safeParse(frame.event.payload);
|
|
31564
|
+
if (!removed.success || removed.data.session_id !== sessionID) {
|
|
31565
|
+
return { skip: true, content: "", envelope };
|
|
31566
|
+
}
|
|
31567
|
+
const who = removed.data.by?.id ?? "someone";
|
|
31568
|
+
return {
|
|
31569
|
+
skip: false,
|
|
31570
|
+
content: `Unsubscribed from ${dispatchOwner(frame.event, subject ?? envelope.topic)} by ${who}`,
|
|
31571
|
+
envelope
|
|
31572
|
+
};
|
|
31573
|
+
}
|
|
31557
31574
|
askQuestion = dispatchAskQuestion(frame.event);
|
|
31558
31575
|
messageReplyPreview = dispatchMessageReplyPreview(frame.event);
|
|
31559
31576
|
dispatchEvent = {
|
|
@@ -32827,6 +32844,46 @@ function dispatchSubscriptionTopic(details) {
|
|
|
32827
32844
|
const { topic } = details;
|
|
32828
32845
|
return typeof topic === "string" && topic.startsWith("notifications.dispatch.") ? topic : null;
|
|
32829
32846
|
}
|
|
32847
|
+
function dispatchTopicLabel(topic) {
|
|
32848
|
+
if (topic.startsWith(DISPATCH_ISSUE_TOPIC_PREFIX)) {
|
|
32849
|
+
const [key] = topic.slice(DISPATCH_ISSUE_TOPIC_PREFIX.length).split(".", 2);
|
|
32850
|
+
if (key !== undefined && key !== "")
|
|
32851
|
+
return key;
|
|
32852
|
+
}
|
|
32853
|
+
if (topic.startsWith(DISPATCH_DOCUMENT_TOPIC_PREFIX)) {
|
|
32854
|
+
const [project, slug] = topic.slice(DISPATCH_DOCUMENT_TOPIC_PREFIX.length).split(".", 3);
|
|
32855
|
+
if (project !== undefined && project !== "" && slug !== undefined && slug !== "") {
|
|
32856
|
+
return `${project}/${slug}`;
|
|
32857
|
+
}
|
|
32858
|
+
}
|
|
32859
|
+
return topic;
|
|
32860
|
+
}
|
|
32861
|
+
function subscriptionRemovedTopics(raw, sessionID) {
|
|
32862
|
+
let envelope;
|
|
32863
|
+
try {
|
|
32864
|
+
envelope = JSON.parse(raw);
|
|
32865
|
+
} catch {
|
|
32866
|
+
return;
|
|
32867
|
+
}
|
|
32868
|
+
if (typeof envelope !== "object" || envelope === null)
|
|
32869
|
+
return;
|
|
32870
|
+
const { source, payload } = envelope;
|
|
32871
|
+
if (source !== "dispatch" || typeof payload !== "string")
|
|
32872
|
+
return;
|
|
32873
|
+
let event;
|
|
32874
|
+
try {
|
|
32875
|
+
event = JSON.parse(payload);
|
|
32876
|
+
} catch {
|
|
32877
|
+
return;
|
|
32878
|
+
}
|
|
32879
|
+
const parsedEvent = DispatchEventSchema.safeParse(event);
|
|
32880
|
+
if (!parsedEvent.success || parsedEvent.data.type !== "subscription.removed")
|
|
32881
|
+
return;
|
|
32882
|
+
const parsedPayload = SubscriptionRemovedEventPayloadSchema.safeParse(parsedEvent.data.payload);
|
|
32883
|
+
if (!parsedPayload.success || parsedPayload.data.session_id !== sessionID)
|
|
32884
|
+
return;
|
|
32885
|
+
return parsedPayload.data.topics ?? [];
|
|
32886
|
+
}
|
|
32830
32887
|
|
|
32831
32888
|
// ../envoy-client/src/tool-contract.ts
|
|
32832
32889
|
var DELIVERY_CONTRACT = "Delivery is at-least-once, possibly out of order across topics; use id for dedupe and at for freshness.";
|
|
@@ -33296,6 +33353,8 @@ function envoyExtension(pi) {
|
|
|
33296
33353
|
};
|
|
33297
33354
|
const deliver = async (subject, raw, reply) => {
|
|
33298
33355
|
const rendered = renderInbound(raw, sessionID, subject);
|
|
33356
|
+
for (const topic of subscriptionRemovedTopics(raw, sessionID) ?? [])
|
|
33357
|
+
closeIntentionally(topic);
|
|
33299
33358
|
const dedupeKey = rendered.envelope?.dedupe_key;
|
|
33300
33359
|
const duplicate = dedupeKey !== undefined && dedupeKeys.has(dedupeKey);
|
|
33301
33360
|
if (!duplicate && !rendered.skip) {
|
|
@@ -33687,8 +33746,16 @@ function envoyExtension(pi) {
|
|
|
33687
33746
|
if (topic === null)
|
|
33688
33747
|
return;
|
|
33689
33748
|
try {
|
|
33690
|
-
|
|
33749
|
+
const isNew = await subscribe(topic);
|
|
33750
|
+
if (isNew)
|
|
33691
33751
|
await registerSession();
|
|
33752
|
+
if (isNew) {
|
|
33753
|
+
pi.sendMessage({
|
|
33754
|
+
customType: "envoy-message",
|
|
33755
|
+
content: `Subscribed to ${dispatchTopicLabel(topic)} (every event on this issue reaches you; envoy_unsubscribe ${topic} to stop).`,
|
|
33756
|
+
display: true
|
|
33757
|
+
}, { deliverAs: "steer", triggerTurn: false });
|
|
33758
|
+
}
|
|
33692
33759
|
} catch (error) {
|
|
33693
33760
|
activeSessionContext?.ui.notify(`envoy: dispatch reply auto-subscribe failed (${messageFor(error)}); run envoy_subscribe ${topic}`, "warning");
|
|
33694
33761
|
}
|
|
@@ -226,9 +226,11 @@ It returns `details` `{ issue, topic, message }`. `body` is capped at 2,000 char
|
|
|
226
226
|
|
|
227
227
|
## What comes back
|
|
228
228
|
|
|
229
|
-
A write result's `details.topic` subscribes the host to its owner
|
|
229
|
+
A write result's `details.topic` subscribes the host to its owner, and the first such subscription on an issue or document also tells
|
|
230
|
+
you so (an already-subscribed write stays quiet — no repeat notice). Issue writes use `notifications.dispatch.issue.<KEY>.>`;
|
|
230
231
|
project-document writes use `notifications.dispatch.document.<PROJECT>.<SLUG>.>`. The owner topic carries every Dispatch event; `notify`
|
|
231
|
-
only controls agent wake and routed delivery.
|
|
232
|
+
only controls agent wake and routed delivery. A human may unsubscribe you from the issue or document header; you are told with a
|
|
233
|
+
`subscription.removed` notice when that happens. After a restart, catch up with:
|
|
232
234
|
|
|
233
235
|
```ts
|
|
234
236
|
dispatch_read({ issue?, project?, artifact?, ref? })
|