@sjawhar/pi-legion-envoy 5.12.0 → 5.13.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 CHANGED
@@ -35188,6 +35188,27 @@ function onEnvoyRoleRegained(listener) {
35188
35188
  legionRoleClaimBridge().regained = listener;
35189
35189
  }
35190
35190
 
35191
+ // src/side-turn.ts
35192
+ function btwPrompt(question) {
35193
+ return [
35194
+ "<btw>",
35195
+ "Ephemeral side question for current interactive session.",
35196
+ "Answer briefly, directly; use conversation context already provided.",
35197
+ "NEVER use tools.",
35198
+ "NEVER ask follow-up questions.",
35199
+ "Question:",
35200
+ question,
35201
+ "</btw>"
35202
+ ].join(`
35203
+ `);
35204
+ }
35205
+ function sideTurn(pi, context) {
35206
+ const runEphemeralTurn = context?.runEphemeralTurn;
35207
+ if (runEphemeralTurn === undefined)
35208
+ return pi.askEphemeral;
35209
+ return ({ prompt, signal }) => runEphemeralTurn({ promptText: btwPrompt(prompt), signal });
35210
+ }
35211
+
35191
35212
  // src/subagent-session.ts
35192
35213
  import fs from "fs";
35193
35214
  import path3 from "path";
@@ -35433,7 +35454,6 @@ function envoyExtension(pi) {
35433
35454
  availabilityWarningSessionIDs.add(sessionID2);
35434
35455
  context.ui.notify(`envoy: Dispatch open-ask check unavailable (${messageFor(error48)}); the stop-time ask reminder is off until it recovers`, "warning");
35435
35456
  };
35436
- const askEphemeral = pi.askEphemeral;
35437
35457
  const overriddenTimeout = Number(process.env.ENVOY_SELF_CHECK_TIMEOUT_MS);
35438
35458
  const selfCheckTimeoutMs = Number.isFinite(overriddenTimeout) && overriddenTimeout > 0 ? overriddenTimeout : ASK_SELF_CHECK_TIMEOUT_MS;
35439
35459
  const selfCheckWarningSessionIDs = new Set;
@@ -35542,13 +35562,18 @@ function envoyExtension(pi) {
35542
35562
  } else if (rendered.malformedDelivery === true) {
35543
35563
  console.warn("[envoy] dropping malformed Dispatch targeted delivery without a reply address");
35544
35564
  } else if (rendered.delivery?.mode === "btw") {
35545
- if (pi.askEphemeral === undefined) {
35565
+ const answer = sideTurn(pi, activeSessionContext);
35566
+ if (shuttingDown) {
35567
+ await postDispatchReply(rendered.delivery, {
35568
+ error: "This OMP session is shutting down"
35569
+ });
35570
+ } else if (answer === undefined) {
35546
35571
  await postDispatchReply(rendered.delivery, {
35547
35572
  error: "This OMP host does not support BTW delivery"
35548
35573
  });
35549
35574
  } else {
35550
35575
  try {
35551
- const reply2 = await pi.askEphemeral({ prompt: rendered.delivery.body });
35576
+ const reply2 = await answer({ prompt: rendered.delivery.body });
35552
35577
  await postDispatchReply(rendered.delivery, { body: reply2.replyText });
35553
35578
  } catch (error48) {
35554
35579
  await postDispatchReply(rendered.delivery, { error: messageFor(error48) });
@@ -35733,7 +35758,7 @@ function envoyExtension(pi) {
35733
35758
  ],
35734
35759
  port: 0,
35735
35760
  title: activeSessionContext?.sessionManager.getSessionName?.() ?? "",
35736
- capabilities: typeof pi.askEphemeral === "function" ? DELIVERY_CAPABILITIES : CAPABILITIES_WITHOUT_BTW,
35761
+ capabilities: sideTurn(pi, activeSessionContext) === undefined ? CAPABILITIES_WITHOUT_BTW : DELIVERY_CAPABILITIES,
35737
35762
  driving: false,
35738
35763
  selfSubscribed: true
35739
35764
  });
@@ -36127,7 +36152,7 @@ function envoyExtension(pi) {
36127
36152
  registerEnvoyWhoamiCommand(pi, replyAddress);
36128
36153
  pi.on("before_agent_start", async (event, context) => {
36129
36154
  const id = context.sessionManager.getSessionId();
36130
- if (id === "" || event.prompt.trim() === "" || !context.hasUI || askEphemeral === undefined || legionManaged(id)) {
36155
+ if (id === "" || event.prompt.trim() === "" || !context.hasUI || sideTurn(pi, context) === undefined || legionManaged(id)) {
36131
36156
  return;
36132
36157
  }
36133
36158
  if (await isSubagent(context))
@@ -36158,39 +36183,40 @@ function envoyExtension(pi) {
36158
36183
  pi.on("agent_end", async (event, context) => {
36159
36184
  const id = context.sessionManager.getSessionId();
36160
36185
  const lastReply = event.messages?.findLast((message) => message.role === "assistant");
36161
- if (event.willContinue === true || lastReply?.stopReason !== "stop" || !context.hasUI || id === "" || !checkOwed(id)) {
36186
+ const ask = sideTurn(pi, context);
36187
+ if (event.willContinue === true || lastReply?.stopReason !== "stop" || !context.hasUI || id === "" || ask === undefined || !checkOwed(id)) {
36162
36188
  return;
36163
36189
  }
36190
+ const settle = { context, ask, seenRun: runSeq, generation: awarenessGeneration };
36164
36191
  if (askCheckInFlight) {
36165
- settledDuringCheck = { context, seenRun: runSeq };
36192
+ settledDuringCheck = settle;
36166
36193
  return;
36167
36194
  }
36168
36195
  askCheckInFlight = true;
36196
+ context.setTimeout(() => checkFromSettle(id, settle), 0);
36197
+ });
36198
+ async function checkFromSettle(id, first) {
36169
36199
  try {
36170
- let settle = { context, seenRun: runSeq };
36200
+ let settle = first;
36171
36201
  while (settle !== undefined) {
36172
36202
  await checkAtSettle(id, settle);
36173
36203
  settle = takeSettledDuringCheck();
36174
- if (settle?.context.sessionManager.getSessionId() !== id || settle.seenRun !== runSeq || !checkOwed(id)) {
36175
- settle = undefined;
36176
- }
36177
36204
  }
36178
36205
  } finally {
36179
36206
  askCheckInFlight = false;
36180
36207
  settledDuringCheck = undefined;
36181
36208
  }
36182
- });
36209
+ }
36183
36210
  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 || askEphemeral === undefined);
36211
+ 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
36212
  }
36186
36213
  async function checkAtSettle(id, settle) {
36187
- const { context, seenRun } = settle;
36214
+ const { context, ask, seenRun, generation } = settle;
36188
36215
  const period = askAwareness.period;
36189
- const generation = awarenessGeneration;
36190
36216
  const baseline = askAwareness.baseline_as_of;
36191
- if (baseline === null || askEphemeral === undefined)
36192
- return;
36193
36217
  const stale = () => shuttingDown || generation !== awarenessGeneration || context.sessionManager.getSessionId() !== id || legionManaged(id) || askAwareness.session_id !== id || askAwareness.period !== period || !askAwareness.check_due;
36218
+ if (baseline === null || !checkOwed(id) || stale() || runSeq !== seenRun)
36219
+ return;
36194
36220
  let open;
36195
36221
  try {
36196
36222
  open = await queryOpenAsks(id, baseline);
@@ -36207,7 +36233,7 @@ function envoyExtension(pi) {
36207
36233
  askCheckAbort = abort;
36208
36234
  let answered;
36209
36235
  try {
36210
- answered = askEphemeral({
36236
+ answered = ask({
36211
36237
  prompt: ASK_SELF_CHECK_PROMPT(open.snapshot.asks),
36212
36238
  signal: abort.signal
36213
36239
  }).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.12.0",
16195
+ version: "5.13.0",
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 without `askEphemeral`); a Claude Code session advertises `aside` only, because
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/pi-legion-envoy",
3
- "version": "5.12.0",
3
+ "version": "5.13.0",
4
4
  "type": "module",
5
5
  "omp": {
6
6
  "extensions": [