@sjawhar/pi-legion-envoy 5.12.0 → 5.13.1
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 +47 -22
- package/dist/legion.js +1 -1
- package/dist/skills/dispatch/SKILL.md +4 -0
- package/dist/skills/envoy/SKILL.md +1 -1
- package/package.json +1 -1
package/dist/envoy.js
CHANGED
|
@@ -32850,12 +32850,11 @@ async function architectureGuidance(client, project, components) {
|
|
|
32850
32850
|
if (components.mode === "none" || components.ids.length > 0)
|
|
32851
32851
|
return;
|
|
32852
32852
|
try {
|
|
32853
|
-
await client.getArchitectureSource(project)
|
|
32854
|
-
return `Project ${project} has an architecture model, but this issue is not linked to any of its current components. ${architectureComponentsAction}`;
|
|
32855
|
-
} catch (error48) {
|
|
32856
|
-
if (error48 instanceof DispatchServiceError && error48.status === 404 && error48.code === "SOURCE_NOT_FOUND") {
|
|
32853
|
+
if (await client.getArchitectureSource(project) === null) {
|
|
32857
32854
|
return;
|
|
32858
32855
|
}
|
|
32856
|
+
return `Project ${project} has an architecture model, but this issue is not linked to any of its current components. ${architectureComponentsAction}`;
|
|
32857
|
+
} catch (error48) {
|
|
32859
32858
|
return `Could not check whether project ${project} has an architecture model: ${messageFor(error48)}. ${architectureComponentsAction}`;
|
|
32860
32859
|
}
|
|
32861
32860
|
}
|
|
@@ -35188,6 +35187,27 @@ function onEnvoyRoleRegained(listener) {
|
|
|
35188
35187
|
legionRoleClaimBridge().regained = listener;
|
|
35189
35188
|
}
|
|
35190
35189
|
|
|
35190
|
+
// src/side-turn.ts
|
|
35191
|
+
function btwPrompt(question) {
|
|
35192
|
+
return [
|
|
35193
|
+
"<btw>",
|
|
35194
|
+
"Ephemeral side question for current interactive session.",
|
|
35195
|
+
"Answer briefly, directly; use conversation context already provided.",
|
|
35196
|
+
"NEVER use tools.",
|
|
35197
|
+
"NEVER ask follow-up questions.",
|
|
35198
|
+
"Question:",
|
|
35199
|
+
question,
|
|
35200
|
+
"</btw>"
|
|
35201
|
+
].join(`
|
|
35202
|
+
`);
|
|
35203
|
+
}
|
|
35204
|
+
function sideTurn(pi, context) {
|
|
35205
|
+
const runEphemeralTurn = context?.runEphemeralTurn;
|
|
35206
|
+
if (runEphemeralTurn === undefined)
|
|
35207
|
+
return pi.askEphemeral;
|
|
35208
|
+
return ({ prompt, signal }) => runEphemeralTurn({ promptText: btwPrompt(prompt), signal });
|
|
35209
|
+
}
|
|
35210
|
+
|
|
35191
35211
|
// src/subagent-session.ts
|
|
35192
35212
|
import fs from "fs";
|
|
35193
35213
|
import path3 from "path";
|
|
@@ -35433,7 +35453,6 @@ function envoyExtension(pi) {
|
|
|
35433
35453
|
availabilityWarningSessionIDs.add(sessionID2);
|
|
35434
35454
|
context.ui.notify(`envoy: Dispatch open-ask check unavailable (${messageFor(error48)}); the stop-time ask reminder is off until it recovers`, "warning");
|
|
35435
35455
|
};
|
|
35436
|
-
const askEphemeral = pi.askEphemeral;
|
|
35437
35456
|
const overriddenTimeout = Number(process.env.ENVOY_SELF_CHECK_TIMEOUT_MS);
|
|
35438
35457
|
const selfCheckTimeoutMs = Number.isFinite(overriddenTimeout) && overriddenTimeout > 0 ? overriddenTimeout : ASK_SELF_CHECK_TIMEOUT_MS;
|
|
35439
35458
|
const selfCheckWarningSessionIDs = new Set;
|
|
@@ -35542,13 +35561,18 @@ function envoyExtension(pi) {
|
|
|
35542
35561
|
} else if (rendered.malformedDelivery === true) {
|
|
35543
35562
|
console.warn("[envoy] dropping malformed Dispatch targeted delivery without a reply address");
|
|
35544
35563
|
} else if (rendered.delivery?.mode === "btw") {
|
|
35545
|
-
|
|
35564
|
+
const answer = sideTurn(pi, activeSessionContext);
|
|
35565
|
+
if (shuttingDown) {
|
|
35566
|
+
await postDispatchReply(rendered.delivery, {
|
|
35567
|
+
error: "This OMP session is shutting down"
|
|
35568
|
+
});
|
|
35569
|
+
} else if (answer === undefined) {
|
|
35546
35570
|
await postDispatchReply(rendered.delivery, {
|
|
35547
35571
|
error: "This OMP host does not support BTW delivery"
|
|
35548
35572
|
});
|
|
35549
35573
|
} else {
|
|
35550
35574
|
try {
|
|
35551
|
-
const reply2 = await
|
|
35575
|
+
const reply2 = await answer({ prompt: rendered.delivery.body });
|
|
35552
35576
|
await postDispatchReply(rendered.delivery, { body: reply2.replyText });
|
|
35553
35577
|
} catch (error48) {
|
|
35554
35578
|
await postDispatchReply(rendered.delivery, { error: messageFor(error48) });
|
|
@@ -35733,7 +35757,7 @@ function envoyExtension(pi) {
|
|
|
35733
35757
|
],
|
|
35734
35758
|
port: 0,
|
|
35735
35759
|
title: activeSessionContext?.sessionManager.getSessionName?.() ?? "",
|
|
35736
|
-
capabilities:
|
|
35760
|
+
capabilities: sideTurn(pi, activeSessionContext) === undefined ? CAPABILITIES_WITHOUT_BTW : DELIVERY_CAPABILITIES,
|
|
35737
35761
|
driving: false,
|
|
35738
35762
|
selfSubscribed: true
|
|
35739
35763
|
});
|
|
@@ -36127,7 +36151,7 @@ function envoyExtension(pi) {
|
|
|
36127
36151
|
registerEnvoyWhoamiCommand(pi, replyAddress);
|
|
36128
36152
|
pi.on("before_agent_start", async (event, context) => {
|
|
36129
36153
|
const id = context.sessionManager.getSessionId();
|
|
36130
|
-
if (id === "" || event.prompt.trim() === "" || !context.hasUI ||
|
|
36154
|
+
if (id === "" || event.prompt.trim() === "" || !context.hasUI || sideTurn(pi, context) === undefined || legionManaged(id)) {
|
|
36131
36155
|
return;
|
|
36132
36156
|
}
|
|
36133
36157
|
if (await isSubagent(context))
|
|
@@ -36158,39 +36182,40 @@ function envoyExtension(pi) {
|
|
|
36158
36182
|
pi.on("agent_end", async (event, context) => {
|
|
36159
36183
|
const id = context.sessionManager.getSessionId();
|
|
36160
36184
|
const lastReply = event.messages?.findLast((message) => message.role === "assistant");
|
|
36161
|
-
|
|
36185
|
+
const ask = sideTurn(pi, context);
|
|
36186
|
+
if (event.willContinue === true || lastReply?.stopReason !== "stop" || !context.hasUI || id === "" || ask === undefined || !checkOwed(id)) {
|
|
36162
36187
|
return;
|
|
36163
36188
|
}
|
|
36189
|
+
const settle = { context, ask, seenRun: runSeq, generation: awarenessGeneration };
|
|
36164
36190
|
if (askCheckInFlight) {
|
|
36165
|
-
settledDuringCheck =
|
|
36191
|
+
settledDuringCheck = settle;
|
|
36166
36192
|
return;
|
|
36167
36193
|
}
|
|
36168
36194
|
askCheckInFlight = true;
|
|
36195
|
+
context.setTimeout(() => checkFromSettle(id, settle), 0);
|
|
36196
|
+
});
|
|
36197
|
+
async function checkFromSettle(id, first) {
|
|
36169
36198
|
try {
|
|
36170
|
-
let settle =
|
|
36199
|
+
let settle = first;
|
|
36171
36200
|
while (settle !== undefined) {
|
|
36172
36201
|
await checkAtSettle(id, settle);
|
|
36173
36202
|
settle = takeSettledDuringCheck();
|
|
36174
|
-
if (settle?.context.sessionManager.getSessionId() !== id || settle.seenRun !== runSeq || !checkOwed(id)) {
|
|
36175
|
-
settle = undefined;
|
|
36176
|
-
}
|
|
36177
36203
|
}
|
|
36178
36204
|
} finally {
|
|
36179
36205
|
askCheckInFlight = false;
|
|
36180
36206
|
settledDuringCheck = undefined;
|
|
36181
36207
|
}
|
|
36182
|
-
}
|
|
36208
|
+
}
|
|
36183
36209
|
function checkOwed(id) {
|
|
36184
|
-
return !(shuttingDown || legionManaged(id) || askAwareness.session_id !== id || askAwareness.period === 0 || !askAwareness.check_due || askAwareness.checks >= ASK_CHECKS_PER_PERIOD || askAwareness.baseline_as_of === null
|
|
36210
|
+
return !(shuttingDown || legionManaged(id) || askAwareness.session_id !== id || askAwareness.period === 0 || !askAwareness.check_due || askAwareness.checks >= ASK_CHECKS_PER_PERIOD || askAwareness.baseline_as_of === null);
|
|
36185
36211
|
}
|
|
36186
36212
|
async function checkAtSettle(id, settle) {
|
|
36187
|
-
const { context, seenRun } = settle;
|
|
36213
|
+
const { context, ask, seenRun, generation } = settle;
|
|
36188
36214
|
const period = askAwareness.period;
|
|
36189
|
-
const generation = awarenessGeneration;
|
|
36190
36215
|
const baseline = askAwareness.baseline_as_of;
|
|
36191
|
-
if (baseline === null || askEphemeral === undefined)
|
|
36192
|
-
return;
|
|
36193
36216
|
const stale = () => shuttingDown || generation !== awarenessGeneration || context.sessionManager.getSessionId() !== id || legionManaged(id) || askAwareness.session_id !== id || askAwareness.period !== period || !askAwareness.check_due;
|
|
36217
|
+
if (baseline === null || !checkOwed(id) || stale() || runSeq !== seenRun)
|
|
36218
|
+
return;
|
|
36194
36219
|
let open;
|
|
36195
36220
|
try {
|
|
36196
36221
|
open = await queryOpenAsks(id, baseline);
|
|
@@ -36207,7 +36232,7 @@ function envoyExtension(pi) {
|
|
|
36207
36232
|
askCheckAbort = abort;
|
|
36208
36233
|
let answered;
|
|
36209
36234
|
try {
|
|
36210
|
-
answered =
|
|
36235
|
+
answered = ask({
|
|
36211
36236
|
prompt: ASK_SELF_CHECK_PROMPT(open.snapshot.asks),
|
|
36212
36237
|
signal: abort.signal
|
|
36213
36238
|
}).then((reply) => reply.replyText, (error48) => {
|
package/dist/legion.js
CHANGED
|
@@ -16192,7 +16192,7 @@ import { logger } from "@oh-my-pi/pi-utils";
|
|
|
16192
16192
|
// package.json
|
|
16193
16193
|
var package_default = {
|
|
16194
16194
|
name: "@sjawhar/pi-legion-envoy",
|
|
16195
|
-
version: "5.
|
|
16195
|
+
version: "5.13.1",
|
|
16196
16196
|
type: "module",
|
|
16197
16197
|
omp: {
|
|
16198
16198
|
extensions: [
|
|
@@ -277,6 +277,10 @@ start with the issue key; standalone project-document hit lines start with
|
|
|
277
277
|
|
|
278
278
|
`dispatch_issue` refuses a title that near-duplicates an issue in the same project and returns the candidates (`POSSIBLE_DUPLICATE`).
|
|
279
279
|
Read them; reference the existing issue, or repeat the call with `force: true` when it is genuinely new work.
|
|
280
|
+
The check compares title words only (shared stemmed terms), never meaning: "four tests that fail a
|
|
281
|
+
merge" pairs with "four CI gates that cannot fail a merge". So when you force past a candidate, give
|
|
282
|
+
the new issue a title that names what differs where you can, and open its spec's Summary with the
|
|
283
|
+
distinction from the named issue, citing it (`dispatch://KEY`), for whoever reads the next pairing.
|
|
280
284
|
|
|
281
285
|
## Reading a project's backlog
|
|
282
286
|
|
|
@@ -140,7 +140,7 @@ Each session row from `envoy_sessions` carries `capabilities`, the targeted-deli
|
|
|
140
140
|
session's host honours: `aside` (a message queued beside the model's work), `btw` (an ephemeral
|
|
141
141
|
question the host answers without disturbing the current turn), and `steer` (an interjection at
|
|
142
142
|
the next tool boundary). An OMP session advertises `aside`, `btw`, and `steer` (`aside` and
|
|
143
|
-
`steer` on a host
|
|
143
|
+
`steer` on a host that cannot run a side turn); a Claude Code session advertises `aside` only, because
|
|
144
144
|
its channel notifications queue for the next turn. Target a session only with a mode it
|
|
145
145
|
advertises.
|
|
146
146
|
|