@sjawhar/opencode-legion-envoy 3.19.5 → 3.19.7

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.
@@ -13807,6 +13807,9 @@ function claimHolds(claim, titles) {
13807
13807
  return titles.has(claim.actor.id) ? "holds" : "lapsed";
13808
13808
  }
13809
13809
  // ../contracts/src/dispatch-href.ts
13810
+ function hasControlCharacter(value) {
13811
+ return /\p{Cc}/u.test(value);
13812
+ }
13810
13813
  function itemFromSearch(search) {
13811
13814
  const params = new URLSearchParams(search);
13812
13815
  const ask = params.get("ask");
@@ -13827,6 +13830,9 @@ function itemFromSearch(search) {
13827
13830
  } catch {
13828
13831
  return null;
13829
13832
  }
13833
+ if (hasControlCharacter(id)) {
13834
+ return null;
13835
+ }
13830
13836
  return ask === null ? { id, kind: "comment" } : { id, kind: "ask" };
13831
13837
  }
13832
13838
  // ../contracts/src/dispatch-snippet.ts
@@ -16782,17 +16788,19 @@ async function refuseRemovingOpenDecisionBlocks(client, tool, resolved, ops) {
16782
16788
  ].join(`
16783
16789
  `));
16784
16790
  }
16785
- function refusalWithCode(error48, suffix = "") {
16791
+ function refusalWithCode(error48, ...clauses) {
16792
+ const suffix = clauses.filter((clause) => clause !== "").join("; ");
16793
+ const joined = suffix === "" ? "" : `; ${suffix}`;
16786
16794
  if (error48 instanceof DispatchGatewayError) {
16787
16795
  let told = error48.message;
16788
- if (suffix !== "") {
16789
- told = error48.mayHaveReachedDispatch ? `${error48.answer}${suffix}` : `${error48.answer}, so ${error48.advice}${suffix}`;
16796
+ if (joined !== "") {
16797
+ told = error48.mayHaveReachedDispatch ? `${error48.answer}${joined}` : `${error48.answer}, so ${error48.advice}${joined}`;
16790
16798
  }
16791
16799
  return new DispatchGatewayError(error48.status, error48.answer, error48.advice, `${error48.code}: ${told}`);
16792
16800
  }
16793
16801
  if (!(error48 instanceof DispatchServiceError))
16794
16802
  return error48;
16795
- return new DispatchServiceError(error48.code, error48.status, `${error48.code}: ${error48.message}${suffix}`, error48.candidates, error48.current, error48.mismatches);
16803
+ return new DispatchServiceError(error48.code, error48.status, `${error48.code}: ${error48.message}${joined}`, error48.candidates, error48.current, error48.mismatches);
16796
16804
  }
16797
16805
  function dispatchAnswered(error48, status) {
16798
16806
  return error48 instanceof DispatchServiceError && error48.fromDispatch && error48.status === status;
@@ -16978,7 +16986,7 @@ async function executeDispatchTool(input) {
16978
16986
  } catch (error48) {
16979
16987
  const told = writeMayHaveLanded(error48) ? "the reason may or may not have been posted, and the close was not sent: read the issue's messages before retrying, since retrying this call posts its reason again" : "the reason was not posted, so the close was not sent";
16980
16988
  if (error48 instanceof DispatchServiceError)
16981
- throw refusalWithCode(error48, `; ${told}`);
16989
+ throw refusalWithCode(error48, told);
16982
16990
  throw withAccount(error48, told);
16983
16991
  }
16984
16992
  }
@@ -16998,14 +17006,14 @@ async function executeDispatchTool(input) {
16998
17006
  actor
16999
17007
  });
17000
17008
  } catch (error48) {
17001
- const taken = dispatchAnswered(error48, 500) && newLinks.length > 0 ? `; one of ${newLinks.join(", ")} may already be linked from another issue (a URL links exactly one issue)` : "";
17009
+ const taken = dispatchAnswered(error48, 500) && newLinks.length > 0 ? `one of ${newLinks.join(", ")} may already be linked from another issue (a URL links exactly one issue)` : "";
17002
17010
  if (closingNote === undefined)
17003
17011
  throw refusalWithCode(error48, taken);
17004
17012
  const posted = `the reason already landed as message ${closingNote.id} (${closingNote.ref})`;
17005
17013
  const fix = error48 instanceof DispatchGatewayError && error48.transient ? "" : "fix what refused the close, then ";
17006
17014
  const landed = writeMayHaveLanded(error48) ? `${posted}, and the close may or may not have taken effect. Read the issue's status before retrying: done means it closed; otherwise retry with a reason that points at message ${closingNote.id}, since retrying this call posts its reason again` : `${posted} but the issue did not close. Retrying this call posts its reason again, so ${fix}retry with a reason that points at message ${closingNote.id}`;
17007
17015
  if (error48 instanceof DispatchServiceError)
17008
- throw refusalWithCode(error48, `${taken}; ${landed}`);
17016
+ throw refusalWithCode(error48, taken, landed);
17009
17017
  throw withAccount(error48, landed);
17010
17018
  }
17011
17019
  const linkCount = `(${after.external_links.length} ${after.external_links.length === 1 ? "link" : "links"})`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/opencode-legion-envoy",
3
- "version": "3.19.5",
3
+ "version": "3.19.7",
4
4
  "type": "module",
5
5
  "main": "dist/src/server.js",
6
6
  "exports": {
@@ -84,7 +84,7 @@ a new version that keeps the human's own text, never a second "spec" artifact be
84
84
  versions keep the history.
85
85
  - **No placeholders.** No TBD, TODO, or hedging ("might", "could consider"): an open item is a
86
86
  decision block, a technical decision your lane makes and records in the text, or, for a
87
- contract between two lanes or a halt condition, a question for the platform PO (see
87
+ contract between two lanes, a question for the platform PO (see
88
88
  [Before you ask](#before-you-ask) under Asking).
89
89
  - **No progress.** The spec records the design and its decisions, never status, timestamps, an
90
90
  "Update HH:MMZ" section, a pull-request list, or handoff notes. Progress is not a Dispatch
@@ -208,10 +208,11 @@ Every `dispatch_ask` passes four gates first:
208
208
  1. **Does it need his authority, taste, or risk appetite?** This is the bar for a decision
209
209
  written as an `:::ask` block in context ([Decision blocks](#decision-blocks)). Technical
210
210
  decisions inside your outcome do not: schema shapes, table layouts, field names, and migration
211
- internals are your lane's to decide and record in the spec. Two things still go to the
212
- platform PO over Envoy: a contract between two lanes, and a halt condition (a change to IAM,
213
- deletion or exposure of production data, anything that reaches a customer). The PO takes those
214
- to Sami as a Dispatch ask; you do not open one yourself, even as a permission ask under gate 2.
211
+ internals are your lane's to decide and record in the spec. A contract between two lanes still
212
+ goes to the platform PO over Envoy, and you open no ask for it. A halt condition (a change to
213
+ IAM, deletion or exposure of production data, anything that reaches a customer) passes this
214
+ gate: it is your own `dispatch_ask` to Sami on your own issue, never routed through the
215
+ platform PO.
215
216
  2. **Is there genuine uncertainty, and have you measured what you can?** If there is none, it is
216
217
  a plan you execute. The one legitimate ask without uncertainty is permission for an action
217
218
  only a human can authorise — a production write, an external send, a console action — and then
@@ -242,9 +243,9 @@ Every `dispatch_ask` passes four gates first:
242
243
  is not what this forbids; changing something else is. An ask that turns his complaint about
243
244
  one control into a choice about another does not address what he asked, and changing that
244
245
  other control is a change he never asked for. What is still an ask the moment you know it,
245
- even before delivery, is anything "Anything that needs the human is an ask" (further down)
246
- lists that the delivery waits on — including a conflict between what he asked for and another
247
- of his rules, which this gate would otherwise bury as settled.
246
+ even before delivery, is anything "Anything you are blocked on a human for is an open ask"
247
+ (further down) lists that the delivery waits on — including a conflict between what he asked
248
+ for and another of his rules, which this gate would otherwise bury as settled.
248
249
 
249
250
  The platform PO audits open asks. One that fails a gate — or that points at another message in
250
251
  prose instead of carrying its content (below) — is retracted, with the PO's answer as the record.
@@ -314,8 +315,7 @@ Before saying you are waiting for human input, call `dispatch_open_asks`. With n
314
315
  **Anything you are blocked on a human for is an open ask.** An agent waits on a human only through
315
316
  an open ask. An approval, a credential or grant to renew, a setting only they can change, a review
316
317
  click, a decision, or a conflict between two of their own rules: open a `dispatch_ask` the moment
317
- you know, the action as the question. The exception is a halt condition from [Before you
318
- ask](#before-you-ask) gate 1, which goes to the platform PO over Envoy instead. Never write it
318
+ you know, the action as the question. Never write it
319
319
  into a spec, a comment reply, a message, or a pull-request body: nothing in those paths reaches
320
320
  the human's Inbox, and a human who is not reading your document does not know they are the
321
321
  blocker. Before asking, try to remove the step: a value already on the machine, a permission you