@sjawhar/pi-legion-envoy 1.57.1 → 1.59.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 +48 -14
- package/dist/legion.js +8 -1
- package/dist/skills/dispatch/SKILL.md +7 -3
- package/package.json +1 -1
package/dist/envoy.js
CHANGED
|
@@ -29649,6 +29649,13 @@ function date4(params) {
|
|
|
29649
29649
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
29650
29650
|
config(en_default());
|
|
29651
29651
|
// ../contracts/src/dispatch-api.ts
|
|
29652
|
+
function serviceSubjectLabel(subject) {
|
|
29653
|
+
const parts = subject.split(":");
|
|
29654
|
+
if (parts.length === 4 && parts[0] === "system" && parts[1] === "serviceaccount" && parts[2] !== "" && parts[3] !== "") {
|
|
29655
|
+
return `${parts[2]}/${parts[3]}`;
|
|
29656
|
+
}
|
|
29657
|
+
return subject;
|
|
29658
|
+
}
|
|
29652
29659
|
var ASK_TURNS = ["human", "agent"];
|
|
29653
29660
|
var DELIVERY_CAPABILITIES = ["aside", "btw", "steer"];
|
|
29654
29661
|
var DispatchEventSchema = object({
|
|
@@ -32244,6 +32251,9 @@ class DispatchClient {
|
|
|
32244
32251
|
async syncArchitectureSource(project) {
|
|
32245
32252
|
return this.#json("POST", ["api", "v1", "projects", project, "architecture-source", "sync"]);
|
|
32246
32253
|
}
|
|
32254
|
+
async getArchitectureSource(project) {
|
|
32255
|
+
return this.#json("GET", ["api", "v1", "projects", project, "architecture-source"]);
|
|
32256
|
+
}
|
|
32247
32257
|
async resolveAsk(id, input) {
|
|
32248
32258
|
return this.#json("POST", ["api", "v1", "asks", id, "resolve"], input);
|
|
32249
32259
|
}
|
|
@@ -32739,6 +32749,20 @@ function componentsChange(input, after) {
|
|
|
32739
32749
|
return "components -> inherit";
|
|
32740
32750
|
}
|
|
32741
32751
|
}
|
|
32752
|
+
var architectureComponentsAction = 'Review the `dispatch` skill, "Architecture components", to attach it to the parts it changes or mark it as non-architectural with a reason.';
|
|
32753
|
+
async function architectureGuidance(client, project, components) {
|
|
32754
|
+
if (components.mode === "none" || components.ids.length > 0)
|
|
32755
|
+
return;
|
|
32756
|
+
try {
|
|
32757
|
+
await client.getArchitectureSource(project);
|
|
32758
|
+
return `Project ${project} has an architecture model, but this issue is not linked to any of its current components. ${architectureComponentsAction}`;
|
|
32759
|
+
} catch (error) {
|
|
32760
|
+
if (error instanceof DispatchServiceError && error.status === 404 && error.code === "SOURCE_NOT_FOUND") {
|
|
32761
|
+
return;
|
|
32762
|
+
}
|
|
32763
|
+
return `Could not check whether project ${project} has an architecture model: ${messageFor(error)}. ${architectureComponentsAction}`;
|
|
32764
|
+
}
|
|
32765
|
+
}
|
|
32742
32766
|
function isDuplicateCandidate(value) {
|
|
32743
32767
|
if (typeof value !== "object" || value === null)
|
|
32744
32768
|
return false;
|
|
@@ -33320,9 +33344,16 @@ function eventHead(event) {
|
|
|
33320
33344
|
return;
|
|
33321
33345
|
}
|
|
33322
33346
|
}
|
|
33347
|
+
function actorText(actor) {
|
|
33348
|
+
const service = actor.kind === "session" ? actor.service : undefined;
|
|
33349
|
+
if (service === undefined) {
|
|
33350
|
+
return `${actor.kind} ${actor.id}`;
|
|
33351
|
+
}
|
|
33352
|
+
return `${actor.kind} ${actor.id} (as ${serviceSubjectLabel(service)})`;
|
|
33353
|
+
}
|
|
33323
33354
|
function eventLine(event) {
|
|
33324
33355
|
const head = eventHead(event);
|
|
33325
|
-
return `- #${event.seq} ${event.type} \xB7 ${event.actor
|
|
33356
|
+
return `- #${event.seq} ${event.type} \xB7 ${actorText(event.actor)} \xB7 ${event.created_at}${head === undefined || head === "" ? "" : ` \xB7 ${head}`}`;
|
|
33326
33357
|
}
|
|
33327
33358
|
function childrenSummary(issue) {
|
|
33328
33359
|
return [
|
|
@@ -33335,7 +33366,7 @@ function childrenSummary(issue) {
|
|
|
33335
33366
|
function askSummary({ ask, replies }, graph) {
|
|
33336
33367
|
const answer = ask.answer;
|
|
33337
33368
|
const chain = replies.flatMap((reply) => [
|
|
33338
|
-
`${reply.id} \xB7 ${reply.author
|
|
33369
|
+
`${reply.id} \xB7 ${actorText(reply.author)}`,
|
|
33339
33370
|
`Body: ${reply.body}`
|
|
33340
33371
|
]);
|
|
33341
33372
|
return [
|
|
@@ -33402,12 +33433,12 @@ function formatOpenAsksSummary(response, baseUrl) {
|
|
|
33402
33433
|
}
|
|
33403
33434
|
function commentSummary({ comment, replies }, graph) {
|
|
33404
33435
|
const root = [
|
|
33405
|
-
`${comment.id} \xB7 ${comment.author
|
|
33436
|
+
`${comment.id} \xB7 ${actorText(comment.author)}`,
|
|
33406
33437
|
...comment.anchor?.quote === undefined ? [] : [`> ${comment.anchor.quote}`],
|
|
33407
33438
|
`Body: ${comment.body}`
|
|
33408
33439
|
];
|
|
33409
33440
|
const chain = replies.flatMap((reply) => [
|
|
33410
|
-
`${reply.id} \xB7 ${reply.author
|
|
33441
|
+
`${reply.id} \xB7 ${actorText(reply.author)}`,
|
|
33411
33442
|
...reply.anchor?.quote === undefined ? [] : [`> ${reply.anchor.quote}`],
|
|
33412
33443
|
`Body: ${reply.body}`
|
|
33413
33444
|
]);
|
|
@@ -33421,12 +33452,9 @@ function commentSummary({ comment, replies }, graph) {
|
|
|
33421
33452
|
`);
|
|
33422
33453
|
}
|
|
33423
33454
|
function messageSummary({ message, replies }, graph) {
|
|
33424
|
-
const root = [
|
|
33425
|
-
`${message.id} \xB7 ${message.author.kind} ${message.author.id}`,
|
|
33426
|
-
`Body: ${message.body}`
|
|
33427
|
-
];
|
|
33455
|
+
const root = [`${message.id} \xB7 ${actorText(message.author)}`, `Body: ${message.body}`];
|
|
33428
33456
|
const chain = replies.flatMap((reply) => [
|
|
33429
|
-
`${reply.id} \xB7 ${reply.author
|
|
33457
|
+
`${reply.id} \xB7 ${actorText(reply.author)}`,
|
|
33430
33458
|
`Body: ${reply.body}`
|
|
33431
33459
|
]);
|
|
33432
33460
|
return [
|
|
@@ -33508,9 +33536,11 @@ async function executeDispatchTool(input) {
|
|
|
33508
33536
|
const client = dispatchClient();
|
|
33509
33537
|
const identity = await client.whoami();
|
|
33510
33538
|
const owner = identity.kind === "agent" ? identity.owner : identity.login.toLowerCase();
|
|
33539
|
+
const service = identity.kind === "agent" ? identity.service ?? null : null;
|
|
33540
|
+
const unowned = "no owner, so issues you create without an assignee are unassigned (or inherit their parent's).";
|
|
33511
33541
|
return {
|
|
33512
|
-
text: owner
|
|
33513
|
-
details: { session: sessionId, owner }
|
|
33542
|
+
text: owner !== null ? `Session ${sessionId} acts for ${owner}: issues you create without an assignee are assigned to ${owner}.` : service !== null ? `Session ${sessionId} runs as service ${serviceSubjectLabel(service)}: ${unowned}` : `Session ${sessionId} runs under the shared token: ${unowned}`,
|
|
33543
|
+
details: { session: sessionId, owner, service }
|
|
33514
33544
|
};
|
|
33515
33545
|
}
|
|
33516
33546
|
const args = parsed.success ? parsed.data : ownerArguments.args;
|
|
@@ -33556,9 +33586,13 @@ async function executeDispatchTool(input) {
|
|
|
33556
33586
|
...Array.isArray(labels) ? { labels } : {},
|
|
33557
33587
|
actor
|
|
33558
33588
|
});
|
|
33559
|
-
const
|
|
33560
|
-
|
|
33561
|
-
|
|
33589
|
+
const componentGuidance = await architectureGuidance(client, created.project, created.components);
|
|
33590
|
+
const adviceLines = [
|
|
33591
|
+
...renderAdvice(input.tool, created.key, created.advice, {
|
|
33592
|
+
isPrimarySpec: spec !== undefined
|
|
33593
|
+
}),
|
|
33594
|
+
...componentGuidance === undefined ? [] : [componentGuidance]
|
|
33595
|
+
];
|
|
33562
33596
|
return {
|
|
33563
33597
|
text: [
|
|
33564
33598
|
`Created ${created.key}: ${created.title} ${notSubscribed(issueTopic(created.key))}`,
|
package/dist/legion.js
CHANGED
|
@@ -16145,7 +16145,7 @@ import { logger } from "@oh-my-pi/pi-utils";
|
|
|
16145
16145
|
// package.json
|
|
16146
16146
|
var package_default = {
|
|
16147
16147
|
name: "@sjawhar/pi-legion-envoy",
|
|
16148
|
-
version: "1.
|
|
16148
|
+
version: "1.59.0",
|
|
16149
16149
|
type: "module",
|
|
16150
16150
|
omp: {
|
|
16151
16151
|
extensions: [
|
|
@@ -28968,6 +28968,13 @@ function preprocess(fn, schema) {
|
|
|
28968
28968
|
return pipe(transform(fn), schema);
|
|
28969
28969
|
}
|
|
28970
28970
|
// ../contracts/src/dispatch-api.ts
|
|
28971
|
+
function serviceSubjectLabel(subject) {
|
|
28972
|
+
const parts = subject.split(":");
|
|
28973
|
+
if (parts.length === 4 && parts[0] === "system" && parts[1] === "serviceaccount" && parts[2] !== "" && parts[3] !== "") {
|
|
28974
|
+
return `${parts[2]}/${parts[3]}`;
|
|
28975
|
+
}
|
|
28976
|
+
return subject;
|
|
28977
|
+
}
|
|
28971
28978
|
var ASK_TURNS = ["human", "agent"];
|
|
28972
28979
|
var DELIVERY_CAPABILITIES = ["aside", "btw", "steer"];
|
|
28973
28980
|
var DispatchEventSchema = object({
|
|
@@ -148,7 +148,7 @@ An ask goes to the issue's assignee: their Inbox opens on **Mine**, which lists
|
|
|
148
148
|
```ts
|
|
149
149
|
dispatch_whoami({})
|
|
150
150
|
```
|
|
151
|
-
It returns `details` `{ session, owner }`: `owner` is the lowercase login of the human whose personal token you run under, or `null` under the shared token. An issue you create without `assignee` goes to your owner;
|
|
151
|
+
It returns `details` `{ session, owner, service }`: `owner` is the lowercase login of the human 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": "<login>"}`; any authenticated caller may reassign, and an unlisted login 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.
|
|
152
152
|
|
|
153
153
|
Architects create newly tracked child work with:
|
|
154
154
|
```ts
|
|
@@ -302,7 +302,9 @@ that follow from it:
|
|
|
302
302
|
the question carries `dispatch://KEY/artifact/<slug>` (or `ref`), never just its filename. Text
|
|
303
303
|
they must read to decide belongs in the spec in the first place — see [Artifacts](#artifacts).
|
|
304
304
|
|
|
305
|
-
|
|
305
|
+
## Architecture components
|
|
306
|
+
|
|
307
|
+
Attach every architectural issue to the components it changes. Attach the root before decomposing it: children inherit the root's effective attachment unless they deliberately set their own, so one root attachment classifies the whole tree.
|
|
306
308
|
|
|
307
309
|
```
|
|
308
310
|
dispatch_issue({ project: "CORE", title: "...", components: { mode: "explicit", ids: ["dispatch-server", "web"] } })
|
|
@@ -311,7 +313,9 @@ dispatch_issue_update({ issue: "CORE-13", components: { mode: "none", reason: "h
|
|
|
311
313
|
dispatch_issue_update({ issue: "CORE-14", components: { mode: "inherit" } }) // back to the parent chain's attachment
|
|
312
314
|
```
|
|
313
315
|
|
|
314
|
-
|
|
316
|
+
No native Dispatch tool lists component ids. Read the configured model with `GET /api/v1/projects/{key}/architecture` and use each non-external `components[].id`; when its source repository is your checkout, those ids are the file names under `.dispatch/architecture/` (`web.md` → `web`). An id absent from the model, or an `external` component, is refused with `COMPONENTS_INPUT`.
|
|
317
|
+
|
|
318
|
+
Use `mode: "none"` with a concrete reason only when the work is genuinely non-architectural (for example hiring, process, or operations work). A closed issue can be classified without reopening. Change code and its architecture description (`.dispatch/architecture/<id>.md`) in the same review.
|
|
315
319
|
|
|
316
320
|
Import a project's architecture model from its configured source repository now (a human configures the source in Settings):
|
|
317
321
|
```ts
|