@sjawhar/opencode-legion-envoy 3.19.4 → 3.19.6
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/src/server.js
CHANGED
|
@@ -14252,7 +14252,7 @@ var dispatchToolSpecs = [
|
|
|
14252
14252
|
{
|
|
14253
14253
|
name: "dispatch_read",
|
|
14254
14254
|
example: { issue: "DSP-1" },
|
|
14255
|
-
description: "Read an issue or project-document summary, targeted ask, or targeted comment reply chain, or the conversation " + "a message belongs to. Do not use it for document contents; use dispatch_doc_read instead. Supply ref, issue, " + "or project plus artifact; or message alone, which reads a human's direct message to this session and every " + "reply to it (they belong to no issue). " + "Every read ends with `Referenced by:` (what cites or hangs off this node, each with its dispatch:// address, " + "an excerpt, and when) and `Links:` (what it cites), so tracing provenance is one call. " + OWNER_REFERENCE,
|
|
14255
|
+
description: "Read an issue or project-document summary, targeted ask, or targeted comment reply chain, or the conversation " + "a message belongs to. Do not use it for document contents; use dispatch_doc_read instead. Supply ref, issue, " + "or project plus artifact; or message alone, which reads a human's direct message to this session and every " + "reply to it (they belong to no issue). " + "An anchored comment or ask also says where its quote sits, as `Position:`: the block's path from the top, " + "and in a table the row (0 is the header), the cells before the anchored one, and the column's header; " + "`Position: unavailable (<code>)` when Dispatch could not read the document: `DOC_SERVICE_UNAVAILABLE` " + "(try again shortly), `DOC_SCHEMA` (the document needs repair) or `INTERNAL`. " + "Every read ends with `Referenced by:` (what cites or hangs off this node, each with its dispatch:// address, " + "an excerpt, and when) and `Links:` (what it cites), so tracing provenance is one call. " + OWNER_REFERENCE,
|
|
14256
14256
|
arguments: (z2) => ({
|
|
14257
14257
|
issue: z2.string().describe(ISSUE_REFERENCE).optional(),
|
|
14258
14258
|
project: z2.string().describe("Project key owning the document.").optional(),
|
|
@@ -16569,6 +16569,7 @@ function askSummary({ ask, replies }, graph) {
|
|
|
16569
16569
|
]);
|
|
16570
16570
|
return [
|
|
16571
16571
|
`Question: ${ask.question}`,
|
|
16572
|
+
...anchorLines(ask),
|
|
16572
16573
|
"Options:",
|
|
16573
16574
|
...ask.options.length === 0 ? ["- none"] : ask.options.map((option) => `- ${option.label}${option.description ? ` \u2014 ${option.description}` : ""}`),
|
|
16574
16575
|
`State: ${ask.state}`,
|
|
@@ -16632,12 +16633,12 @@ function formatOpenAsksSummary(response, baseUrl) {
|
|
|
16632
16633
|
function commentSummary({ comment, replies }, graph) {
|
|
16633
16634
|
const root = [
|
|
16634
16635
|
`${comment.id} \xB7 ${actorText(comment.author)}`,
|
|
16635
|
-
...comment
|
|
16636
|
+
...anchorLines(comment),
|
|
16636
16637
|
`Body: ${comment.body}`
|
|
16637
16638
|
];
|
|
16638
16639
|
const chain = replies.flatMap((reply) => [
|
|
16639
16640
|
`${reply.id} \xB7 ${actorText(reply.author)}`,
|
|
16640
|
-
...reply
|
|
16641
|
+
...anchorLines(reply),
|
|
16641
16642
|
`Body: ${reply.body}`
|
|
16642
16643
|
]);
|
|
16643
16644
|
return [
|
|
@@ -16649,6 +16650,28 @@ function commentSummary({ comment, replies }, graph) {
|
|
|
16649
16650
|
].join(`
|
|
16650
16651
|
`);
|
|
16651
16652
|
}
|
|
16653
|
+
function anchorLines(record2) {
|
|
16654
|
+
return [
|
|
16655
|
+
...record2.anchor?.quote === undefined ? [] : [`> ${record2.anchor.quote}`],
|
|
16656
|
+
...record2.anchor_block === undefined ? [] : [`Position: ${positionText(record2.anchor_block)}`],
|
|
16657
|
+
...record2.anchor_block_error === undefined ? [] : [`Position: unavailable (${record2.anchor_block_error})`]
|
|
16658
|
+
];
|
|
16659
|
+
}
|
|
16660
|
+
function positionText(block) {
|
|
16661
|
+
const { table, path: path2 } = block;
|
|
16662
|
+
const segments = path2.map((entry) => `${entry.type}[${entry.index}]`);
|
|
16663
|
+
if (table === undefined || table.row === null)
|
|
16664
|
+
return segments.join(" \u203A ");
|
|
16665
|
+
const tableAt = path2.findIndex((entry) => entry.type === "table");
|
|
16666
|
+
const cells = table.cells ?? [];
|
|
16667
|
+
const label = (table.column === null ? cells : cells.slice(0, table.column)).map((cell) => cell.trim()).filter((cell) => cell !== "" && !/^\d+$/.test(cell)).join(" \xB7 ");
|
|
16668
|
+
const row = label === "" ? `row ${table.row}` : `row ${table.row} (${label})`;
|
|
16669
|
+
const header = table.header === null || table.header === "" ? String(table.column) : table.header;
|
|
16670
|
+
return [
|
|
16671
|
+
...segments.slice(0, tableAt + 1),
|
|
16672
|
+
table.column === null ? row : `${row}, column ${header}`
|
|
16673
|
+
].join(" \u203A ");
|
|
16674
|
+
}
|
|
16652
16675
|
function messageSummary({ message, replies }, graph) {
|
|
16653
16676
|
const root = [`${message.id} \xB7 ${actorText(message.author)}`, `Body: ${message.body}`];
|
|
16654
16677
|
const chain = replies.flatMap((reply) => [
|
|
@@ -16759,17 +16782,19 @@ async function refuseRemovingOpenDecisionBlocks(client, tool, resolved, ops) {
|
|
|
16759
16782
|
].join(`
|
|
16760
16783
|
`));
|
|
16761
16784
|
}
|
|
16762
|
-
function refusalWithCode(error48,
|
|
16785
|
+
function refusalWithCode(error48, ...clauses) {
|
|
16786
|
+
const suffix = clauses.filter((clause) => clause !== "").join("; ");
|
|
16787
|
+
const joined = suffix === "" ? "" : `; ${suffix}`;
|
|
16763
16788
|
if (error48 instanceof DispatchGatewayError) {
|
|
16764
16789
|
let told = error48.message;
|
|
16765
|
-
if (
|
|
16766
|
-
told = error48.mayHaveReachedDispatch ? `${error48.answer}${
|
|
16790
|
+
if (joined !== "") {
|
|
16791
|
+
told = error48.mayHaveReachedDispatch ? `${error48.answer}${joined}` : `${error48.answer}, so ${error48.advice}${joined}`;
|
|
16767
16792
|
}
|
|
16768
16793
|
return new DispatchGatewayError(error48.status, error48.answer, error48.advice, `${error48.code}: ${told}`);
|
|
16769
16794
|
}
|
|
16770
16795
|
if (!(error48 instanceof DispatchServiceError))
|
|
16771
16796
|
return error48;
|
|
16772
|
-
return new DispatchServiceError(error48.code, error48.status, `${error48.code}: ${error48.message}${
|
|
16797
|
+
return new DispatchServiceError(error48.code, error48.status, `${error48.code}: ${error48.message}${joined}`, error48.candidates, error48.current, error48.mismatches);
|
|
16773
16798
|
}
|
|
16774
16799
|
function dispatchAnswered(error48, status) {
|
|
16775
16800
|
return error48 instanceof DispatchServiceError && error48.fromDispatch && error48.status === status;
|
|
@@ -16955,7 +16980,7 @@ async function executeDispatchTool(input) {
|
|
|
16955
16980
|
} catch (error48) {
|
|
16956
16981
|
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";
|
|
16957
16982
|
if (error48 instanceof DispatchServiceError)
|
|
16958
|
-
throw refusalWithCode(error48,
|
|
16983
|
+
throw refusalWithCode(error48, told);
|
|
16959
16984
|
throw withAccount(error48, told);
|
|
16960
16985
|
}
|
|
16961
16986
|
}
|
|
@@ -16975,14 +17000,14 @@ async function executeDispatchTool(input) {
|
|
|
16975
17000
|
actor
|
|
16976
17001
|
});
|
|
16977
17002
|
} catch (error48) {
|
|
16978
|
-
const taken = dispatchAnswered(error48, 500) && newLinks.length > 0 ?
|
|
17003
|
+
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)` : "";
|
|
16979
17004
|
if (closingNote === undefined)
|
|
16980
17005
|
throw refusalWithCode(error48, taken);
|
|
16981
17006
|
const posted = `the reason already landed as message ${closingNote.id} (${closingNote.ref})`;
|
|
16982
17007
|
const fix = error48 instanceof DispatchGatewayError && error48.transient ? "" : "fix what refused the close, then ";
|
|
16983
17008
|
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}`;
|
|
16984
17009
|
if (error48 instanceof DispatchServiceError)
|
|
16985
|
-
throw refusalWithCode(error48,
|
|
17010
|
+
throw refusalWithCode(error48, taken, landed);
|
|
16986
17011
|
throw withAccount(error48, landed);
|
|
16987
17012
|
}
|
|
16988
17013
|
const linkCount = `(${after.external_links.length} ${after.external_links.length === 1 ? "link" : "links"})`;
|
package/package.json
CHANGED
package/skills/dispatch/SKILL.md
CHANGED
|
@@ -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
|
|
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.
|
|
212
|
-
platform PO over Envoy
|
|
213
|
-
deletion or exposure of production data, anything that reaches a customer)
|
|
214
|
-
|
|
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
|
|
246
|
-
lists that the delivery waits on — including a conflict between what he asked
|
|
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.
|
|
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
|
|
@@ -57,7 +57,10 @@ table's block id. A row index includes the header: row `0` is the header and its
|
|
|
57
57
|
row and any row's last column cannot be deleted. An index is required. A missing, non-integer, negative, or out-of-range index is
|
|
58
58
|
`INVALID_OP` on `index`, naming the supplied value and the table's actual dimensions before making any change. Markdown parsing
|
|
59
59
|
canonicalizes short ragged rows by padding missing cells, so column deletion preserves every non-selected cell in the canonical table.
|
|
60
|
-
`GET /api/v1/artifacts/<artifact UUID>/blocks` reports a table's own references plus its descendant cell anchors.
|
|
60
|
+
`GET /api/v1/artifacts/<artifact UUID>/blocks` reports a table's own references plus its descendant cell anchors.
|
|
61
|
+
`GET /api/v1/artifacts/<artifact UUID>/blocks/<block id>` places one block: its path from the top-level block down, and for a cell
|
|
62
|
+
the row index (0 is the header, what `delete_row` takes), the column index (what `delete_column` takes), the text of the header cell
|
|
63
|
+
drawn above it (with colspans or rowspans, the column the cell is drawn in) and the row's cells. A row or column
|
|
61
64
|
deletion that would remove an open ask or unresolved comment anchor is `INVALID_OP` on `index`, naming the axis and anchor ids;
|
|
62
65
|
answered asks and resolved comments are history and do not block it. A `find` or quote anchor tolerates inline Markdown
|
|
63
66
|
(`**bold**`, `` `code` ``) and a leading `# ` selects a heading by its text; a miss names the quote and the three nearest blocks so
|
|
@@ -16,6 +16,15 @@ document owner or ref, it returns a document summary with `details` `{ project,
|
|
|
16
16
|
question, options, state, answer, and its reply thread. With a comment ref, it returns that comment and its quoted reply chain. With a
|
|
17
17
|
message ref, it returns that message and its reply chain. Reads do not subscribe; use `dispatch_doc_read` for document contents.
|
|
18
18
|
|
|
19
|
+
An anchored comment or ask also prints `Position:`, where its quote's block stands — `table[3] › row 5 (Red-teamer loop), column Due`
|
|
20
|
+
is the fourth top-level block, a table, its row 5 (row 0 is the header; the index `delete_row` takes), labelled by the row's cells
|
|
21
|
+
before the anchored one, in the column headed Due; outside a table it is the path of types and child indexes down to the block. The
|
|
22
|
+
same facts are `anchor_block` on `GET /api/v1/comments/{id}` and `GET /api/v1/asks/{id}`, and
|
|
23
|
+
`GET /api/v1/artifacts/{id}/blocks/{block_id}` answers them for any block id a document holds. When Dispatch could not read the
|
|
24
|
+
document, the read still answers and prints `Position: unavailable (DOC_SERVICE_UNAVAILABLE)` (try again shortly),
|
|
25
|
+
`Position: unavailable (DOC_SCHEMA)` (the document needs repair) or `Position: unavailable (INTERNAL)`; the API carries that
|
|
26
|
+
code as `anchor_block_error`.
|
|
27
|
+
|
|
19
28
|
Every read ends with two sections from the reference graph. `Referenced by:` lists what points at the node — every document, ask,
|
|
20
29
|
comment, or message that cites it, plus its structure: child issues, attached documents, anchored and owned asks and comments, replies,
|
|
21
30
|
followers — and `Links:` lists what it cites. Each row is `- <edge kind> <node kind> dispatch://… (<excerpt> · <when>)`; for a
|