@sjawhar/opencode-legion-envoy 3.8.2 → 3.9.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.
@@ -14255,13 +14255,14 @@ var dispatchToolSpecs = [
14255
14255
  },
14256
14256
  {
14257
14257
  name: "dispatch_issues",
14258
- example: { project: "AGENTC" },
14259
- description: "List a project's issues for a roadmap or backlog pass: every issue in one project, each carrying " + "its status, priority, parent, labels, and open-ask count, so you can see backlog shape without " + "opening every issue. Optionally filter by status, parent, label, or how recently it changed. Do " + "not use it to search by keyword or phrase; dispatch_search remains the keyword surface. Rows are " + "capped at limit (default 50, max 250), applied to the response here, not by the server.",
14258
+ example: { project: "AGENTC", priority: [0, 1] },
14259
+ description: "List a project's issues for a roadmap or backlog pass: every issue in one project, each carrying " + "its status, priority, parent, labels, and open-ask count, so you can see backlog shape without " + "opening every issue. Optionally filter by status, parent, label, priority, or how recently it " + "changed; priority takes one or more of 0-3 (P0-P3) and null for an issue with no priority, so " + "an owner's P0/P1 audit is priority [0, 1]. Do not use it to search by keyword or phrase; " + "dispatch_search remains the keyword surface. Rows are capped at limit (default 50, max 250), " + "applied to the response here, not by the server.",
14260
14260
  arguments: (z2) => ({
14261
14261
  project: z2.string().describe("Project key to list issues from."),
14262
14262
  status: z2.enum(ISSUE_STATUSES).describe("Optional lifecycle status filter.").optional(),
14263
14263
  parent: z2.string().describe("Optional parent issue key filter.").optional(),
14264
14264
  label: z2.string().describe("Optional label filter.").optional(),
14265
+ priority: z2.array(z2.number({ int: true, min: 0, max: 3 }).nullable(), { min: 1, max: 5 }).describe("Optional priority filter: one or more of 0 (P0, highest) through 3 (P3, lowest), and null " + "for an issue with no priority; an issue matching any listed value is returned.").optional(),
14265
14266
  updated_since: z2.string().describe("Optional RFC3339 timestamp; only issues updated at or after it.").optional(),
14266
14267
  limit: z2.number({ int: true, min: 1, max: 250 }).describe("Maximum rows, 1-250; default 50.").optional()
14267
14268
  })
@@ -15323,6 +15324,9 @@ class DispatchClient {
15323
15324
  for (const [name, value] of Object.entries(query)) {
15324
15325
  if (typeof value === "string" || typeof value === "number") {
15325
15326
  url2.searchParams.set(name, String(value));
15327
+ } else if (Array.isArray(value)) {
15328
+ for (const item of value)
15329
+ url2.searchParams.append(name, String(item));
15326
15330
  }
15327
15331
  }
15328
15332
  }
@@ -15623,6 +15627,10 @@ function optionalPriority(args, name) {
15623
15627
  return null;
15624
15628
  return typeof value === "number" ? value : undefined;
15625
15629
  }
15630
+ function optionalPriorityFilter(args, name) {
15631
+ const value = args[name];
15632
+ return Array.isArray(value) ? value.map((item) => item ?? "none") : undefined;
15633
+ }
15626
15634
  function optionalComponents(args, name) {
15627
15635
  const value = args[name];
15628
15636
  if (typeof value !== "object" || value === null)
@@ -16688,6 +16696,7 @@ async function executeDispatchTool(input) {
16688
16696
  const status = optionalString(args, "status");
16689
16697
  const parent = optionalString(args, "parent");
16690
16698
  const label = optionalString(args, "label");
16699
+ const priority = optionalPriorityFilter(args, "priority");
16691
16700
  const updatedSince = optionalString(args, "updated_since");
16692
16701
  const limit = Math.min(Math.max(optionalNumber(args, "limit") ?? 50, 1), 250);
16693
16702
  const issues = await client.listIssues({
@@ -16695,6 +16704,7 @@ async function executeDispatchTool(input) {
16695
16704
  ...status === undefined ? {} : { status },
16696
16705
  ...parent === undefined ? {} : { parent },
16697
16706
  ...label === undefined ? {} : { label },
16707
+ ...priority === undefined ? {} : { priority },
16698
16708
  ...updatedSince === undefined ? {} : { updated_since: updatedSince }
16699
16709
  });
16700
16710
  const rows = issues.slice(0, limit).map((row) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/opencode-legion-envoy",
3
- "version": "3.8.2",
3
+ "version": "3.9.0",
4
4
  "type": "module",
5
5
  "main": "dist/src/server.js",
6
6
  "exports": {
@@ -286,16 +286,54 @@ distinction from the named issue, citing it (`dispatch://KEY`), for whoever read
286
286
 
287
287
  To see the shape of a project rather than find a phrase, list its issues:
288
288
  ```ts
289
- dispatch_issues({ project, status?, parent?, label?, updated_since?, limit? })
289
+ dispatch_issues({ project, status?, parent?, label?, priority?, updated_since?, limit? })
290
290
  ```
291
291
  Each row carries the issue key, title, status, priority, parent, labels, its open-ask count, and
292
292
  when it last changed — a roadmap or backlog pass without opening every issue. Filter with `status`
293
- (a lifecycle status), `parent` (one issue's children), `label`, or `updated_since` (an RFC3339
293
+ (a lifecycle status), `parent` (one issue's children), `label`, `priority` (a list of `0`–`3`, with
294
+ `null` for an issue with no priority: `[0, 1]` is every P0 and P1), or `updated_since` (an RFC3339
294
295
  timestamp, for "what moved this week"). `limit` caps the rows at 50 by default and 250 at most.
295
296
 
296
297
  This is not search: it matches no text. Use `dispatch_search` for a keyword or phrase, and
297
298
  `dispatch_issues` when you want every issue in a project and its current state.
298
299
 
300
+ ### The owner audit
301
+
302
+ As the owner of a surface, list your area's P0 and P1 issues and staff or close each one nobody
303
+ has started:
304
+ ```ts
305
+ dispatch_issues({ project, priority: [0, 1], limit: 250 })
306
+ ```
307
+ Every unclaimed row in `triage`, `icebox`, `backlog` or `todo` is a decision: someone takes it and
308
+ builds it, or it closes. A row in `in_progress`, `testing`, `needs_review` or `retro`, or one that
309
+ carries a claim, is work under way ([Issue status is yours to move](#issue-status-is-yours-to-move))
310
+ and is not re-staffed. A todo with a finished spec reads as queued work that nobody is doing
311
+ (LEGION-173 sat in todo for two weeks with a complete spec; AGENTC-1010's v4 plan sat in backlog
312
+ with nobody building it).
313
+
314
+ The audit finds three shapes:
315
+
316
+ - **Unstaffed work.** A plan or measurement exists, and no one is building it.
317
+ - **Unrecorded delivery.** An issue not yet in `testing` or `done`, claimed or not, has a merged PR
318
+ naming it. Check the change live, then move the issue (AGENTC-1033 sat at `triage` after its fix,
319
+ agent-c #20367, merged).
320
+ - **Unrecorded practice.** Someone does the issue's work by hand, more than once, while the issue
321
+ sits in backlog (OPS-132, done by hand on every migration merge). It leaves no plan and no PR to
322
+ find; the tell is your own messages. Doing something by hand more than once means an issue is
323
+ wearing the wrong status.
324
+
325
+ Run the audit as a step of a coordinator's loop, at each checkpoint, not as a habit: these shapes
326
+ are found by running the check, not by noticing them.
327
+
328
+ ### Symptom versus cause
329
+
330
+ When a symptom and its cause sit on different issues, the work accrues to the cause's issue, and
331
+ the symptom's issue carries a pointer to it. Before posting a measurement or finding, search
332
+ Dispatch for the failing identity's or component's name, and post on the issue whose title names
333
+ the fix, not the one naming the symptom. A symptom issue gathering messages with no human response
334
+ is the tell. (The production freeze was iterated on AGENTC-546, the failing gate, while its cause
335
+ and answer sat on AGENTC-1010.)
336
+
299
337
  ## Asking
300
338
 
301
339
  ### Before you ask