@sjawhar/pi-legion-envoy 7.2.1 → 7.3.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
|
@@ -30109,7 +30109,7 @@ var dispatchToolSpecs = [
|
|
|
30109
30109
|
spec: z2.string().describe(`Optional initial primary-document markdown. ${SPEC_WRITING_POINTER}`).optional(),
|
|
30110
30110
|
labels: z2.array(z2.string({ min: 1, max: 40 }), { max: 20 }).describe("Optional initial labels, at most 20 labels of up to 40 characters.").optional(),
|
|
30111
30111
|
priority: z2.number({ int: true, min: 0, max: 3 }).describe("Optional coarse priority: P0 is highest and P3 is lowest.").optional(),
|
|
30112
|
-
assignee: z2.string().describe("
|
|
30112
|
+
assignee: z2.string().describe("Email of the person who answers this issue's asks (someone who has signed in to Dispatch); defaults to your owner when you act for a person, else the parent's assignee, else unassigned.").optional(),
|
|
30113
30113
|
components: componentsArgument(z2).optional()
|
|
30114
30114
|
})
|
|
30115
30115
|
},
|
|
@@ -30349,7 +30349,7 @@ var dispatchToolSpecs = [
|
|
|
30349
30349
|
{
|
|
30350
30350
|
name: "dispatch_doc_read",
|
|
30351
30351
|
example: { issue: "DSP-1" },
|
|
30352
|
-
description: "Read a live document or a named document version. Do not use it for issue status, asks, or events; " + "use dispatch_read instead. Supply ref, issue, or project plus artifact; issue plus an omitted artifact reads the primary document. " + "A live read returns its document token for an optional dispatch_doc_edit precondition; use /blocks for per-block tokens. " + OWNER_REFERENCE,
|
|
30352
|
+
description: "Read a live document or a named document version, or the text of an uploaded file at its latest or named version. " + "Do not use it for issue status, asks, or events; " + "use dispatch_read instead. Supply ref, issue, or project plus artifact; issue plus an omitted artifact reads the primary document. " + "A live read returns its document token for an optional dispatch_doc_edit precondition; use /blocks for per-block tokens. " + "A file that is not UTF-8 text is described, with the route that serves its bytes. " + OWNER_REFERENCE,
|
|
30353
30353
|
arguments: (z2) => ({
|
|
30354
30354
|
issue: z2.string().describe(ISSUE_REFERENCE).optional(),
|
|
30355
30355
|
project: z2.string().describe("Project key owning the document.").optional(),
|
|
@@ -30463,7 +30463,7 @@ var dispatchToolSpecs = [
|
|
|
30463
30463
|
{
|
|
30464
30464
|
name: "dispatch_whoami",
|
|
30465
30465
|
example: {},
|
|
30466
|
-
description: "Who Dispatch takes this session for: {session, owner}. owner is the lowercase
|
|
30466
|
+
description: "Who Dispatch takes this session for: {session, owner}. owner is the lowercase email of the person whose personal token you run under (the default assignee of issues you create), or null under the shared token.",
|
|
30467
30467
|
arguments: () => ({}),
|
|
30468
30468
|
strict: true
|
|
30469
30469
|
}
|
|
@@ -32356,6 +32356,20 @@ class DispatchClient {
|
|
|
32356
32356
|
async docRead(id, version2) {
|
|
32357
32357
|
return version2 === undefined ? this.#json("GET", ["api", "v1", "artifacts", id, "text"]) : this.#json("GET", ["api", "v1", "artifacts", id, "versions", String(version2)]);
|
|
32358
32358
|
}
|
|
32359
|
+
async fileVersion(id, version2) {
|
|
32360
|
+
const url2 = this.#url(["api", "v1", "artifacts", id, "versions", String(version2)]);
|
|
32361
|
+
const response = await this.fetchImpl(url2, {
|
|
32362
|
+
method: "GET",
|
|
32363
|
+
headers: { Accept: "*/*", Authorization: `Bearer ${this.token}` },
|
|
32364
|
+
signal: this.#signal
|
|
32365
|
+
});
|
|
32366
|
+
if (!response.ok)
|
|
32367
|
+
return this.#response("GET", url2, response);
|
|
32368
|
+
return {
|
|
32369
|
+
mime: response.headers.get("Content-Type") ?? "application/octet-stream",
|
|
32370
|
+
bytes: new Uint8Array(await response.arrayBuffer())
|
|
32371
|
+
};
|
|
32372
|
+
}
|
|
32359
32373
|
async artifactBlocks(id) {
|
|
32360
32374
|
return this.#json("GET", ["api", "v1", "artifacts", id, "blocks"]);
|
|
32361
32375
|
}
|
|
@@ -33618,6 +33632,30 @@ async function blockAsks(client, resolved, state) {
|
|
|
33618
33632
|
const asks = await (resolved.issue === undefined ? client.getArtifactAsks(resolved.artifact.id, state) : client.listIssueAsks(resolved.issue.key, state));
|
|
33619
33633
|
return asks.filter((ask) => typeof ask.block_id === "string" && ask.block_artifact?.id === resolved.artifact.id);
|
|
33620
33634
|
}
|
|
33635
|
+
async function readUploadedFile(client, resolved, requested) {
|
|
33636
|
+
const { artifact } = resolved;
|
|
33637
|
+
const latest = Math.max(0, ...artifact.versions.map((version2) => version2.number));
|
|
33638
|
+
const number4 = requested ?? latest;
|
|
33639
|
+
const file2 = await client.fileVersion(artifact.id, number4);
|
|
33640
|
+
const of = number4 === latest ? "" : ` of ${latest}`;
|
|
33641
|
+
const size = `${file2.bytes.length.toLocaleString("en-US")} bytes`;
|
|
33642
|
+
const details = resolved.owner.kind === "project" ? { project: artifact.project, document: documentLabel(artifact.project, artifact.slug) } : { issue: resolved.issue?.key };
|
|
33643
|
+
let text;
|
|
33644
|
+
try {
|
|
33645
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(file2.bytes);
|
|
33646
|
+
} catch {
|
|
33647
|
+
return {
|
|
33648
|
+
text: `${artifact.name} is an uploaded ${file2.mime} file (version ${number4}${of}, ${size}) that is not ` + `UTF-8 text, so dispatch_doc_read cannot show it. GET /api/v1/artifacts/${artifact.id}/versions/${number4} serves its bytes.`,
|
|
33649
|
+
details
|
|
33650
|
+
};
|
|
33651
|
+
}
|
|
33652
|
+
return {
|
|
33653
|
+
text: `File ${artifact.name}: ${file2.mime}, version ${number4}${of}, ${size}.
|
|
33654
|
+
|
|
33655
|
+
${text}`,
|
|
33656
|
+
details
|
|
33657
|
+
};
|
|
33658
|
+
}
|
|
33621
33659
|
async function refuseOpenDecisionBlocks(client, tool, resolved) {
|
|
33622
33660
|
const artifact = resolved.artifact;
|
|
33623
33661
|
const latest = artifact.approval?.latest_version;
|
|
@@ -34315,6 +34353,9 @@ ${followsAsk(askOwner)}`,
|
|
|
34315
34353
|
const artifactReference = optionalString(args, "artifact") ?? (ownerArguments.ref?.kind === "spec" || ownerArguments.ref?.kind === "artifact" ? ownerArguments.ref.id : undefined);
|
|
34316
34354
|
const resolved = await resolveDocument(documentOwner(), artifactReference);
|
|
34317
34355
|
const version2 = optionalNumber(args, "version") ?? ownerArguments.ref?.version;
|
|
34356
|
+
if (resolved.artifact.kind === "file" || resolved.artifact.kind === "image") {
|
|
34357
|
+
return readUploadedFile(client, resolved, version2);
|
|
34358
|
+
}
|
|
34318
34359
|
const documentPromise = client.docRead(resolved.artifact.id, version2);
|
|
34319
34360
|
const marksPromise = openArtifactMarks(client, resolved);
|
|
34320
34361
|
const marksResultPromise = marksPromise.then((value) => ({ status: "fulfilled", value }), (reason) => ({ status: "rejected", reason }));
|
package/dist/legion.js
CHANGED
|
@@ -14196,7 +14196,7 @@ var dispatchToolSpecs = [
|
|
|
14196
14196
|
spec: z2.string().describe(`Optional initial primary-document markdown. ${SPEC_WRITING_POINTER}`).optional(),
|
|
14197
14197
|
labels: z2.array(z2.string({ min: 1, max: 40 }), { max: 20 }).describe("Optional initial labels, at most 20 labels of up to 40 characters.").optional(),
|
|
14198
14198
|
priority: z2.number({ int: true, min: 0, max: 3 }).describe("Optional coarse priority: P0 is highest and P3 is lowest.").optional(),
|
|
14199
|
-
assignee: z2.string().describe("
|
|
14199
|
+
assignee: z2.string().describe("Email of the person who answers this issue's asks (someone who has signed in to Dispatch); defaults to your owner when you act for a person, else the parent's assignee, else unassigned.").optional(),
|
|
14200
14200
|
components: componentsArgument(z2).optional()
|
|
14201
14201
|
})
|
|
14202
14202
|
},
|
|
@@ -14436,7 +14436,7 @@ var dispatchToolSpecs = [
|
|
|
14436
14436
|
{
|
|
14437
14437
|
name: "dispatch_doc_read",
|
|
14438
14438
|
example: { issue: "DSP-1" },
|
|
14439
|
-
description: "Read a live document or a named document version. Do not use it for issue status, asks, or events; " + "use dispatch_read instead. Supply ref, issue, or project plus artifact; issue plus an omitted artifact reads the primary document. " + "A live read returns its document token for an optional dispatch_doc_edit precondition; use /blocks for per-block tokens. " + OWNER_REFERENCE,
|
|
14439
|
+
description: "Read a live document or a named document version, or the text of an uploaded file at its latest or named version. " + "Do not use it for issue status, asks, or events; " + "use dispatch_read instead. Supply ref, issue, or project plus artifact; issue plus an omitted artifact reads the primary document. " + "A live read returns its document token for an optional dispatch_doc_edit precondition; use /blocks for per-block tokens. " + "A file that is not UTF-8 text is described, with the route that serves its bytes. " + OWNER_REFERENCE,
|
|
14440
14440
|
arguments: (z2) => ({
|
|
14441
14441
|
issue: z2.string().describe(ISSUE_REFERENCE).optional(),
|
|
14442
14442
|
project: z2.string().describe("Project key owning the document.").optional(),
|
|
@@ -14550,7 +14550,7 @@ var dispatchToolSpecs = [
|
|
|
14550
14550
|
{
|
|
14551
14551
|
name: "dispatch_whoami",
|
|
14552
14552
|
example: {},
|
|
14553
|
-
description: "Who Dispatch takes this session for: {session, owner}. owner is the lowercase
|
|
14553
|
+
description: "Who Dispatch takes this session for: {session, owner}. owner is the lowercase email of the person whose personal token you run under (the default assignee of issues you create), or null under the shared token.",
|
|
14554
14554
|
arguments: () => ({}),
|
|
14555
14555
|
strict: true
|
|
14556
14556
|
}
|
|
@@ -15118,6 +15118,20 @@ class DispatchClient {
|
|
|
15118
15118
|
async docRead(id, version2) {
|
|
15119
15119
|
return version2 === undefined ? this.#json("GET", ["api", "v1", "artifacts", id, "text"]) : this.#json("GET", ["api", "v1", "artifacts", id, "versions", String(version2)]);
|
|
15120
15120
|
}
|
|
15121
|
+
async fileVersion(id, version2) {
|
|
15122
|
+
const url2 = this.#url(["api", "v1", "artifacts", id, "versions", String(version2)]);
|
|
15123
|
+
const response = await this.fetchImpl(url2, {
|
|
15124
|
+
method: "GET",
|
|
15125
|
+
headers: { Accept: "*/*", Authorization: `Bearer ${this.token}` },
|
|
15126
|
+
signal: this.#signal
|
|
15127
|
+
});
|
|
15128
|
+
if (!response.ok)
|
|
15129
|
+
return this.#response("GET", url2, response);
|
|
15130
|
+
return {
|
|
15131
|
+
mime: response.headers.get("Content-Type") ?? "application/octet-stream",
|
|
15132
|
+
bytes: new Uint8Array(await response.arrayBuffer())
|
|
15133
|
+
};
|
|
15134
|
+
}
|
|
15121
15135
|
async artifactBlocks(id) {
|
|
15122
15136
|
return this.#json("GET", ["api", "v1", "artifacts", id, "blocks"]);
|
|
15123
15137
|
}
|
|
@@ -16403,6 +16417,30 @@ async function blockAsks(client, resolved, state) {
|
|
|
16403
16417
|
const asks = await (resolved.issue === undefined ? client.getArtifactAsks(resolved.artifact.id, state) : client.listIssueAsks(resolved.issue.key, state));
|
|
16404
16418
|
return asks.filter((ask) => typeof ask.block_id === "string" && ask.block_artifact?.id === resolved.artifact.id);
|
|
16405
16419
|
}
|
|
16420
|
+
async function readUploadedFile(client, resolved, requested) {
|
|
16421
|
+
const { artifact } = resolved;
|
|
16422
|
+
const latest = Math.max(0, ...artifact.versions.map((version2) => version2.number));
|
|
16423
|
+
const number4 = requested ?? latest;
|
|
16424
|
+
const file2 = await client.fileVersion(artifact.id, number4);
|
|
16425
|
+
const of = number4 === latest ? "" : ` of ${latest}`;
|
|
16426
|
+
const size = `${file2.bytes.length.toLocaleString("en-US")} bytes`;
|
|
16427
|
+
const details = resolved.owner.kind === "project" ? { project: artifact.project, document: documentLabel(artifact.project, artifact.slug) } : { issue: resolved.issue?.key };
|
|
16428
|
+
let text;
|
|
16429
|
+
try {
|
|
16430
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(file2.bytes);
|
|
16431
|
+
} catch {
|
|
16432
|
+
return {
|
|
16433
|
+
text: `${artifact.name} is an uploaded ${file2.mime} file (version ${number4}${of}, ${size}) that is not ` + `UTF-8 text, so dispatch_doc_read cannot show it. GET /api/v1/artifacts/${artifact.id}/versions/${number4} serves its bytes.`,
|
|
16434
|
+
details
|
|
16435
|
+
};
|
|
16436
|
+
}
|
|
16437
|
+
return {
|
|
16438
|
+
text: `File ${artifact.name}: ${file2.mime}, version ${number4}${of}, ${size}.
|
|
16439
|
+
|
|
16440
|
+
${text}`,
|
|
16441
|
+
details
|
|
16442
|
+
};
|
|
16443
|
+
}
|
|
16406
16444
|
async function refuseOpenDecisionBlocks(client, tool, resolved) {
|
|
16407
16445
|
const artifact = resolved.artifact;
|
|
16408
16446
|
const latest = artifact.approval?.latest_version;
|
|
@@ -17100,6 +17138,9 @@ ${followsAsk(askOwner)}`,
|
|
|
17100
17138
|
const artifactReference = optionalString(args, "artifact") ?? (ownerArguments.ref?.kind === "spec" || ownerArguments.ref?.kind === "artifact" ? ownerArguments.ref.id : undefined);
|
|
17101
17139
|
const resolved = await resolveDocument(documentOwner(), artifactReference);
|
|
17102
17140
|
const version2 = optionalNumber(args, "version") ?? ownerArguments.ref?.version;
|
|
17141
|
+
if (resolved.artifact.kind === "file" || resolved.artifact.kind === "image") {
|
|
17142
|
+
return readUploadedFile(client, resolved, version2);
|
|
17143
|
+
}
|
|
17103
17144
|
const documentPromise = client.docRead(resolved.artifact.id, version2);
|
|
17104
17145
|
const marksPromise = openArtifactMarks(client, resolved);
|
|
17105
17146
|
const marksResultPromise = marksPromise.then((value) => ({ status: "fulfilled", value }), (reason) => ({ status: "rejected", reason }));
|
|
@@ -17418,7 +17459,7 @@ function endInjectedUserTurns(sessionID) {
|
|
|
17418
17459
|
// package.json
|
|
17419
17460
|
var package_default = {
|
|
17420
17461
|
name: "@sjawhar/pi-legion-envoy",
|
|
17421
|
-
version: "7.
|
|
17462
|
+
version: "7.3.0",
|
|
17422
17463
|
license: "Apache-2.0",
|
|
17423
17464
|
type: "module",
|
|
17424
17465
|
omp: {
|
|
@@ -156,7 +156,7 @@ Create an issue for newly tracked work with:
|
|
|
156
156
|
```ts
|
|
157
157
|
dispatch_issue({ project, title, parent?, external?, spec?, force?, labels?: string[], priority?: 0 | 1 | 2 | 3, assignee?: string })
|
|
158
158
|
```
|
|
159
|
-
`labels` are optional initial labels: Dispatch trims them, preserves their case, and removes case-insensitive duplicates. `priority` is yours on creation too — see [Priority is yours to set](skill://dispatch/references/issues.md). Set `assignee` (a
|
|
159
|
+
`labels` are optional initial labels: Dispatch trims them, preserves their case, and removes case-insensitive duplicates. `priority` is yours on creation too — see [Priority is yours to set](skill://dispatch/references/issues.md). Set `assignee` (the email of a person who has signed in to Dispatch) only when the human said who owns the work; otherwise the default above applies, so a child inherits its parent's assignee. It returns
|
|
160
160
|
`details` `{ issue }`; creating an issue does not subscribe you to it (see [Following](#following)). Use `dispatch_issue` only to create an issue; never use it to park a question. When `spec` is supplied,
|
|
161
161
|
follow [Writing a spec](#writing-a-spec).
|
|
162
162
|
|
|
@@ -418,10 +418,10 @@ Read the current document before changing it:
|
|
|
418
418
|
```ts
|
|
419
419
|
dispatch_doc_read({ issue?, project?, artifact?, version?, ref? })
|
|
420
420
|
```
|
|
421
|
-
It returns live or versioned markdown with open marks. A live read ends with a document token; `issue` with an
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
421
|
+
It returns live or versioned markdown with open marks. A live read ends with a document token; `issue` with an omitted
|
|
422
|
+
`artifact` reads the issue specification; a project needs `artifact`; and a `dispatch://PROJECT/artifact/<document-ref>`
|
|
423
|
+
ref supplies both, where `document-ref` is the slug (an id or a filename resolves when no document has that slug). A file
|
|
424
|
+
`dispatch_artifact` uploaded reads its text at the latest or named version, or a description when it is not UTF-8 text.
|
|
425
425
|
|
|
426
426
|
Editing one is [Editing a document](skill://dispatch/references/document-edits.md): the shape of `dispatch_doc_edit`,
|
|
427
427
|
how to quote the text you mean, one `replace` per paragraph, preconditions against a stale edit, and
|
|
@@ -12,9 +12,10 @@ is the shared devbox fallback; do not configure it for an individual agent.
|
|
|
12
12
|
|
|
13
13
|
The deployed Dispatch server's browser origin is configured separately with
|
|
14
14
|
`DISPATCH_SERVER_URL` in the deployment `compose/.env`. Do not change an
|
|
15
|
-
agent's `envoy.json` to set the
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
agent's `envoy.json` to set the sign-in callback origin: the value must be the
|
|
16
|
+
exact URL humans type in their browser, and `<DISPATCH_SERVER_URL>/auth/callback`
|
|
17
|
+
is the callback registered on the sign-in pool's app client
|
|
18
|
+
(`DISPATCH_SIGNIN_CLIENT_ID`).
|
|
18
19
|
|
|
19
20
|
### Finding a route
|
|
20
21
|
|
|
@@ -11,7 +11,7 @@ An ask goes to the issue's assignee: their Inbox opens on **Mine**, which lists
|
|
|
11
11
|
```ts
|
|
12
12
|
dispatch_whoami({})
|
|
13
13
|
```
|
|
14
|
-
It returns `details` `{ session, owner, service }`: `owner` is the lowercase
|
|
14
|
+
It returns `details` `{ session, owner, service }`: `owner` is the lowercase email of the person whose personal token you run under, or `null` under the shared token or a verified service token, in which case `service` is that token's subject (`system:serviceaccount:<namespace>:<name>`, `null` otherwise) and every write you make is rendered `(as <namespace>/<name>)` — the namespace is kept because every namespace has a `default` service account, and a subject that is not a Kubernetes one is shown whole. An issue you create without `assignee` goes to your owner; with no owner it inherits its parent's assignee, or stays unassigned without a parent. If an issue you are asking on is unassigned and the answer matters, assign it to your owner (`PATCH /api/v1/issues/{key}` with `{"assignee": "<email>"}`; any authenticated caller may reassign, and an email nobody has signed in with is refused with `ASSIGNEE_NOT_ALLOWED`) or name in the question who should answer it. Never reassign an issue a human holds to get an answer faster: that is the human's call.
|
|
15
15
|
|
|
16
16
|
## Handing a human a to-do, editing, resolving, and replying
|
|
17
17
|
|
|
@@ -126,7 +126,7 @@ reorder it the way [Issue reads](#board-rank-priority-and-assignee-on-a-read) de
|
|
|
126
126
|
|
|
127
127
|
## Board rank, priority, and assignee on a read
|
|
128
128
|
|
|
129
|
-
Issue reads include `rank`, the server-owned ordering key used by project boards; reorder through `PATCH /api/v1/issues/{key}` with `{"rank": {"before": "<key>", "after": "<key>"}}`, either neighbor optional and both in the issue's project. A bearer caller also names its own session in that body, `"actor": {"kind": "session", "id": "<your session id>"}`, or the server refuses with `ACTOR_KIND`. They also include nullable coarse priority (`P0` highest through `P3` lowest) and `assignee`: the lowercase
|
|
129
|
+
Issue reads include `rank`, the server-owned ordering key used by project boards; reorder through `PATCH /api/v1/issues/{key}` with `{"rank": {"before": "<key>", "after": "<key>"}}`, either neighbor optional and both in the issue's project. A bearer caller also names its own session in that body, `"actor": {"kind": "session", "id": "<your session id>"}`, or the server refuses with `ACTOR_KIND`. They also include nullable coarse priority (`P0` highest through `P3` lowest) and `assignee`: the lowercase email of the person who answers the issue's asks, or `null` when nobody holds it. `dispatch_read` of an issue prints it as `Assignee: <email>` or `Assignee: unassigned`.
|
|
130
130
|
|
|
131
131
|
## Reading a project's backlog
|
|
132
132
|
|