@sjawhar/opencode-legion-envoy 1.46.1 → 1.48.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/src/server.js +48 -14
- package/package.json +1 -1
- package/skills/dispatch/SKILL.md +7 -3
package/dist/src/server.js
CHANGED
|
@@ -13552,6 +13552,13 @@ function date4(params) {
|
|
|
13552
13552
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
13553
13553
|
config(en_default());
|
|
13554
13554
|
// ../contracts/src/dispatch-api.ts
|
|
13555
|
+
function serviceSubjectLabel(subject) {
|
|
13556
|
+
const parts = subject.split(":");
|
|
13557
|
+
if (parts.length === 4 && parts[0] === "system" && parts[1] === "serviceaccount" && parts[2] !== "" && parts[3] !== "") {
|
|
13558
|
+
return `${parts[2]}/${parts[3]}`;
|
|
13559
|
+
}
|
|
13560
|
+
return subject;
|
|
13561
|
+
}
|
|
13555
13562
|
var ASK_TURNS = ["human", "agent"];
|
|
13556
13563
|
var DELIVERY_CAPABILITIES = ["aside", "btw", "steer"];
|
|
13557
13564
|
var DispatchEventSchema = object({
|
|
@@ -15046,6 +15053,9 @@ class DispatchClient {
|
|
|
15046
15053
|
async syncArchitectureSource(project) {
|
|
15047
15054
|
return this.#json("POST", ["api", "v1", "projects", project, "architecture-source", "sync"]);
|
|
15048
15055
|
}
|
|
15056
|
+
async getArchitectureSource(project) {
|
|
15057
|
+
return this.#json("GET", ["api", "v1", "projects", project, "architecture-source"]);
|
|
15058
|
+
}
|
|
15049
15059
|
async resolveAsk(id, input) {
|
|
15050
15060
|
return this.#json("POST", ["api", "v1", "asks", id, "resolve"], input);
|
|
15051
15061
|
}
|
|
@@ -15564,6 +15574,20 @@ function componentsChange(input, after) {
|
|
|
15564
15574
|
return "components -> inherit";
|
|
15565
15575
|
}
|
|
15566
15576
|
}
|
|
15577
|
+
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.';
|
|
15578
|
+
async function architectureGuidance(client, project, components) {
|
|
15579
|
+
if (components.mode === "none" || components.ids.length > 0)
|
|
15580
|
+
return;
|
|
15581
|
+
try {
|
|
15582
|
+
await client.getArchitectureSource(project);
|
|
15583
|
+
return `Project ${project} has an architecture model, but this issue is not linked to any of its current components. ${architectureComponentsAction}`;
|
|
15584
|
+
} catch (error) {
|
|
15585
|
+
if (error instanceof DispatchServiceError && error.status === 404 && error.code === "SOURCE_NOT_FOUND") {
|
|
15586
|
+
return;
|
|
15587
|
+
}
|
|
15588
|
+
return `Could not check whether project ${project} has an architecture model: ${messageFor(error)}. ${architectureComponentsAction}`;
|
|
15589
|
+
}
|
|
15590
|
+
}
|
|
15567
15591
|
function isDuplicateCandidate(value) {
|
|
15568
15592
|
if (typeof value !== "object" || value === null)
|
|
15569
15593
|
return false;
|
|
@@ -16145,9 +16169,16 @@ function eventHead(event) {
|
|
|
16145
16169
|
return;
|
|
16146
16170
|
}
|
|
16147
16171
|
}
|
|
16172
|
+
function actorText(actor) {
|
|
16173
|
+
const service = actor.kind === "session" ? actor.service : undefined;
|
|
16174
|
+
if (service === undefined) {
|
|
16175
|
+
return `${actor.kind} ${actor.id}`;
|
|
16176
|
+
}
|
|
16177
|
+
return `${actor.kind} ${actor.id} (as ${serviceSubjectLabel(service)})`;
|
|
16178
|
+
}
|
|
16148
16179
|
function eventLine(event) {
|
|
16149
16180
|
const head = eventHead(event);
|
|
16150
|
-
return `- #${event.seq} ${event.type} \xB7 ${event.actor
|
|
16181
|
+
return `- #${event.seq} ${event.type} \xB7 ${actorText(event.actor)} \xB7 ${event.created_at}${head === undefined || head === "" ? "" : ` \xB7 ${head}`}`;
|
|
16151
16182
|
}
|
|
16152
16183
|
function childrenSummary(issue) {
|
|
16153
16184
|
return [
|
|
@@ -16160,7 +16191,7 @@ function childrenSummary(issue) {
|
|
|
16160
16191
|
function askSummary({ ask, replies }, graph) {
|
|
16161
16192
|
const answer = ask.answer;
|
|
16162
16193
|
const chain = replies.flatMap((reply) => [
|
|
16163
|
-
`${reply.id} \xB7 ${reply.author
|
|
16194
|
+
`${reply.id} \xB7 ${actorText(reply.author)}`,
|
|
16164
16195
|
`Body: ${reply.body}`
|
|
16165
16196
|
]);
|
|
16166
16197
|
return [
|
|
@@ -16227,12 +16258,12 @@ function formatOpenAsksSummary(response, baseUrl) {
|
|
|
16227
16258
|
}
|
|
16228
16259
|
function commentSummary({ comment, replies }, graph) {
|
|
16229
16260
|
const root = [
|
|
16230
|
-
`${comment.id} \xB7 ${comment.author
|
|
16261
|
+
`${comment.id} \xB7 ${actorText(comment.author)}`,
|
|
16231
16262
|
...comment.anchor?.quote === undefined ? [] : [`> ${comment.anchor.quote}`],
|
|
16232
16263
|
`Body: ${comment.body}`
|
|
16233
16264
|
];
|
|
16234
16265
|
const chain = replies.flatMap((reply) => [
|
|
16235
|
-
`${reply.id} \xB7 ${reply.author
|
|
16266
|
+
`${reply.id} \xB7 ${actorText(reply.author)}`,
|
|
16236
16267
|
...reply.anchor?.quote === undefined ? [] : [`> ${reply.anchor.quote}`],
|
|
16237
16268
|
`Body: ${reply.body}`
|
|
16238
16269
|
]);
|
|
@@ -16246,12 +16277,9 @@ function commentSummary({ comment, replies }, graph) {
|
|
|
16246
16277
|
`);
|
|
16247
16278
|
}
|
|
16248
16279
|
function messageSummary({ message, replies }, graph) {
|
|
16249
|
-
const root = [
|
|
16250
|
-
`${message.id} \xB7 ${message.author.kind} ${message.author.id}`,
|
|
16251
|
-
`Body: ${message.body}`
|
|
16252
|
-
];
|
|
16280
|
+
const root = [`${message.id} \xB7 ${actorText(message.author)}`, `Body: ${message.body}`];
|
|
16253
16281
|
const chain = replies.flatMap((reply) => [
|
|
16254
|
-
`${reply.id} \xB7 ${reply.author
|
|
16282
|
+
`${reply.id} \xB7 ${actorText(reply.author)}`,
|
|
16255
16283
|
`Body: ${reply.body}`
|
|
16256
16284
|
]);
|
|
16257
16285
|
return [
|
|
@@ -16333,9 +16361,11 @@ async function executeDispatchTool(input) {
|
|
|
16333
16361
|
const client = dispatchClient();
|
|
16334
16362
|
const identity = await client.whoami();
|
|
16335
16363
|
const owner = identity.kind === "agent" ? identity.owner : identity.login.toLowerCase();
|
|
16364
|
+
const service = identity.kind === "agent" ? identity.service ?? null : null;
|
|
16365
|
+
const unowned = "no owner, so issues you create without an assignee are unassigned (or inherit their parent's).";
|
|
16336
16366
|
return {
|
|
16337
|
-
text: owner
|
|
16338
|
-
details: { session: sessionId, owner }
|
|
16367
|
+
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}`,
|
|
16368
|
+
details: { session: sessionId, owner, service }
|
|
16339
16369
|
};
|
|
16340
16370
|
}
|
|
16341
16371
|
const args = parsed.success ? parsed.data : ownerArguments.args;
|
|
@@ -16381,9 +16411,13 @@ async function executeDispatchTool(input) {
|
|
|
16381
16411
|
...Array.isArray(labels) ? { labels } : {},
|
|
16382
16412
|
actor
|
|
16383
16413
|
});
|
|
16384
|
-
const
|
|
16385
|
-
|
|
16386
|
-
|
|
16414
|
+
const componentGuidance = await architectureGuidance(client, created.project, created.components);
|
|
16415
|
+
const adviceLines = [
|
|
16416
|
+
...renderAdvice(input.tool, created.key, created.advice, {
|
|
16417
|
+
isPrimarySpec: spec !== undefined
|
|
16418
|
+
}),
|
|
16419
|
+
...componentGuidance === undefined ? [] : [componentGuidance]
|
|
16420
|
+
];
|
|
16387
16421
|
return {
|
|
16388
16422
|
text: [
|
|
16389
16423
|
`Created ${created.key}: ${created.title} ${notSubscribed(issueTopic(created.key))}`,
|
package/package.json
CHANGED
package/skills/dispatch/SKILL.md
CHANGED
|
@@ -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
|