@sjawhar/opencode-legion-envoy 1.38.0 → 1.38.1
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 +92 -56
- package/package.json +1 -1
- package/skills/dispatch/SKILL.md +4 -0
package/dist/src/server.js
CHANGED
|
@@ -13552,6 +13552,7 @@ 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
|
+
var ASK_TURNS = ["human", "agent"];
|
|
13555
13556
|
var DELIVERY_CAPABILITIES = ["aside", "btw", "steer"];
|
|
13556
13557
|
var DispatchEventSchema = object({
|
|
13557
13558
|
issue_key: string2().nullable(),
|
|
@@ -13632,8 +13633,8 @@ var CommentEventPayloadSchema = object({
|
|
|
13632
13633
|
ask_id: string2().nullish(),
|
|
13633
13634
|
ask_question: string2().optional(),
|
|
13634
13635
|
ask_state: _enum2(["open", "answered", "resolved"]).optional(),
|
|
13635
|
-
ask_waiting_on: _enum2(
|
|
13636
|
-
turn: _enum2(
|
|
13636
|
+
ask_waiting_on: _enum2(ASK_TURNS).optional(),
|
|
13637
|
+
turn: _enum2(ASK_TURNS).nullish(),
|
|
13637
13638
|
anchor: object({ block_id: string2().nullable().optional(), quote: string2().optional() }).nullish(),
|
|
13638
13639
|
suggestion: object({ replace_with: string2().optional() }).nullish(),
|
|
13639
13640
|
author: object({ kind: string2(), id: string2() }).optional(),
|
|
@@ -13756,16 +13757,14 @@ function documentOwnerValidation(requireArtifact, alwaysRequireArtifact = false)
|
|
|
13756
13757
|
message: alwaysRequireArtifact ? "Exactly one of issue and project is required; artifact or ref must name the document." : "Exactly one of issue and project is required; with project, artifact names the document."
|
|
13757
13758
|
};
|
|
13758
13759
|
}
|
|
13759
|
-
var
|
|
13760
|
-
|
|
13761
|
-
|
|
13762
|
-
|
|
13763
|
-
|
|
13764
|
-
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
};
|
|
13768
|
-
})();
|
|
13760
|
+
var commentOwner = documentOwnerValidation(true);
|
|
13761
|
+
var commentValidation = {
|
|
13762
|
+
check: (value) => {
|
|
13763
|
+
const input = value;
|
|
13764
|
+
return commentOwner.check(value) && (input.turn === undefined || typeof input.reply_to_ask === "string");
|
|
13765
|
+
},
|
|
13766
|
+
message: `${commentOwner.message} turn requires reply_to_ask.`
|
|
13767
|
+
};
|
|
13769
13768
|
var ISSUE_COMPONENTS_MODES = ["inherit", "explicit", "none"];
|
|
13770
13769
|
function componentsArgument(z) {
|
|
13771
13770
|
return z.object({
|
|
@@ -13787,6 +13786,7 @@ var SPEC_SECTIONS = [
|
|
|
13787
13786
|
];
|
|
13788
13787
|
var SPEC_WRITING_GUIDANCE = `When writing a spec, use these sections in order: ${SPEC_SECTIONS.join(", ")}. ` + "Write for a reader who has not seen the code: plain sentences, every identifier expanded on " + "first use, no coined shorthand; see skills/dispatch Writing for the human and Writing a spec.";
|
|
13789
13788
|
var ASK_URGENCIES = ["low", "med", "high", "blocking"];
|
|
13789
|
+
var ASK_QUESTION_MAX = 800;
|
|
13790
13790
|
var ISSUE_STATUSES = [
|
|
13791
13791
|
"triage",
|
|
13792
13792
|
"icebox",
|
|
@@ -13840,13 +13840,13 @@ var dispatchToolSpecs = [
|
|
|
13840
13840
|
},
|
|
13841
13841
|
{
|
|
13842
13842
|
name: "dispatch_ask",
|
|
13843
|
-
description: "Open a durable, answerable decision on an issue or project document. Do not use it for a status update or discussion; " + "use dispatch_message instead. A to-do a human must complete is a question phrased as that to-do, with the options you want (for example Done / Can't). " + "Anchor a document question, thread reply_to/reply_to_ask, or cite a dispatch:// " +
|
|
13843
|
+
description: "Open a durable, answerable decision on an issue or project document. Do not use it for a status update or discussion; " + "use dispatch_message instead. A to-do a human must complete is a question phrased as that to-do, with the options you want (for example Done / Can't). " + "Anchor a document question, thread reply_to/reply_to_ask, or cite a dispatch:// " + `reference \u2014 it must be answerable from its own text and anchor alone, never "see above". A quote anchor is pinned to its block. Question is at most ${ASK_QUESTION_MAX} ` + `characters and has at most 8 options. ${OWNER_REFERENCE}`,
|
|
13844
13844
|
arguments: (z) => ({
|
|
13845
13845
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
13846
13846
|
project: z.string().describe("Project key owning the document.").optional(),
|
|
13847
13847
|
artifact: z.string().describe("Project document artifact id, slug, or filename.").optional(),
|
|
13848
13848
|
ref: z.string().describe("Optional dispatch:// reference (issue, document, message, or ask); appended to the question and rendered as a link.").optional(),
|
|
13849
|
-
question: z.string({ max:
|
|
13849
|
+
question: z.string({ max: ASK_QUESTION_MAX }).describe(`Decision question, at most ${ASK_QUESTION_MAX} characters.`),
|
|
13850
13850
|
options: z.array(z.object({
|
|
13851
13851
|
label: z.string().describe("Selectable option label."),
|
|
13852
13852
|
description: z.string().describe("Optional option context.").optional()
|
|
@@ -13866,7 +13866,7 @@ var dispatchToolSpecs = [
|
|
|
13866
13866
|
description: "Edit an open question in place. Use it to correct or refine the same decision; retract the " + "old ask and open a new one when the decision itself changes. Previous text remains in the " + "event log. Only the asking session can edit it; answered or resolved asks cannot be edited.",
|
|
13867
13867
|
arguments: (z) => ({
|
|
13868
13868
|
ask: z.string().describe("Ask id to edit."),
|
|
13869
|
-
question: z.string({ max:
|
|
13869
|
+
question: z.string({ max: ASK_QUESTION_MAX }).describe(`Replacement decision question, at most ${ASK_QUESTION_MAX} characters.`).optional(),
|
|
13870
13870
|
options: z.array(z.object({
|
|
13871
13871
|
label: z.string().describe("Selectable option label."),
|
|
13872
13872
|
description: z.string().describe("Optional option context.").optional()
|
|
@@ -14700,9 +14700,9 @@ import { resolve as resolvePath } from "path";
|
|
|
14700
14700
|
|
|
14701
14701
|
// ../envoy-client/src/ask-answer.ts
|
|
14702
14702
|
var HEAD_LENGTH = 120;
|
|
14703
|
-
function textHead(text
|
|
14703
|
+
function textHead(text) {
|
|
14704
14704
|
const flat = text.replace(/\s+/g, " ").trim();
|
|
14705
|
-
return flat.length >
|
|
14705
|
+
return flat.length > HEAD_LENGTH ? `${flat.slice(0, HEAD_LENGTH)}\u2026` : flat;
|
|
14706
14706
|
}
|
|
14707
14707
|
function askAnswerText(answer) {
|
|
14708
14708
|
if (answer === null || answer === undefined)
|
|
@@ -15126,6 +15126,29 @@ class DispatchClient {
|
|
|
15126
15126
|
}
|
|
15127
15127
|
}
|
|
15128
15128
|
|
|
15129
|
+
// ../envoy-client/src/dispatch-owner.ts
|
|
15130
|
+
function documentLabel(project, slug) {
|
|
15131
|
+
return `${project}/${slug}`;
|
|
15132
|
+
}
|
|
15133
|
+
function issueTopic(key) {
|
|
15134
|
+
return { label: key, topic: dispatchIssueSubject(key, ">") };
|
|
15135
|
+
}
|
|
15136
|
+
function documentTopicOf(project, slug) {
|
|
15137
|
+
return {
|
|
15138
|
+
label: documentLabel(project, slug),
|
|
15139
|
+
topic: dispatchDocumentSubject(project, slug, ">")
|
|
15140
|
+
};
|
|
15141
|
+
}
|
|
15142
|
+
function dispatchIssueRef(key) {
|
|
15143
|
+
return `dispatch://${key}`;
|
|
15144
|
+
}
|
|
15145
|
+
function dispatchDocumentRef(owner, slug) {
|
|
15146
|
+
return `dispatch://${owner}/artifact/${slug}`;
|
|
15147
|
+
}
|
|
15148
|
+
function dispatchChildRef(ownerRef, kind, id) {
|
|
15149
|
+
return `${ownerRef}/${kind}/${id}`;
|
|
15150
|
+
}
|
|
15151
|
+
|
|
15129
15152
|
// ../envoy-client/src/tool-input-errors.ts
|
|
15130
15153
|
class ToolInputError extends Error {
|
|
15131
15154
|
tool;
|
|
@@ -15237,14 +15260,8 @@ function formatZodIssues(issues, schema) {
|
|
|
15237
15260
|
}
|
|
15238
15261
|
|
|
15239
15262
|
// ../envoy-client/src/dispatch-execute.ts
|
|
15240
|
-
function issueTopic(key) {
|
|
15241
|
-
return { label: key, topic: dispatchIssueSubject(key, ">") };
|
|
15242
|
-
}
|
|
15243
15263
|
function documentTopic(artifact) {
|
|
15244
|
-
return
|
|
15245
|
-
label: `${artifact.project}/${artifact.slug}`,
|
|
15246
|
-
topic: dispatchDocumentSubject(artifact.project, artifact.slug, ">")
|
|
15247
|
-
};
|
|
15264
|
+
return documentTopicOf(artifact.project, artifact.slug);
|
|
15248
15265
|
}
|
|
15249
15266
|
function resolvedTopic(resolved) {
|
|
15250
15267
|
if (resolved.owner.kind === "project")
|
|
@@ -15263,7 +15280,7 @@ function documentResultDetails(artifact) {
|
|
|
15263
15280
|
return {
|
|
15264
15281
|
project: artifact.project,
|
|
15265
15282
|
artifact: artifact.id,
|
|
15266
|
-
document:
|
|
15283
|
+
document: documentLabel(artifact.project, artifact.slug)
|
|
15267
15284
|
};
|
|
15268
15285
|
}
|
|
15269
15286
|
function writeResultDetails(resolved, fields) {
|
|
@@ -15274,15 +15291,15 @@ function writeResultDetails(resolved, fields) {
|
|
|
15274
15291
|
throw new Error("issue document is missing its issue");
|
|
15275
15292
|
return { issue: resolved.issue.key, ...fields };
|
|
15276
15293
|
}
|
|
15277
|
-
async function askOwnerDetails(client, ask,
|
|
15294
|
+
async function askOwnerDetails(client, ask, artifact) {
|
|
15278
15295
|
if (ask.issue_key !== null) {
|
|
15279
15296
|
return { issue: ask.issue_key, ask: ask.id };
|
|
15280
15297
|
}
|
|
15281
15298
|
if (ask.artifact_id === undefined || ask.artifact_id === null) {
|
|
15282
15299
|
throw new Error("document ask is missing its artifact ID");
|
|
15283
15300
|
}
|
|
15284
|
-
const
|
|
15285
|
-
return { ...documentResultDetails(
|
|
15301
|
+
const owner = artifact ?? await client.getArtifact(ask.artifact_id);
|
|
15302
|
+
return { ...documentResultDetails(owner), ask: ask.id };
|
|
15286
15303
|
}
|
|
15287
15304
|
async function commentOwnerResult(client, comment, artifact) {
|
|
15288
15305
|
if (comment.issue_key !== null) {
|
|
@@ -15293,12 +15310,12 @@ async function commentOwnerResult(client, comment, artifact) {
|
|
|
15293
15310
|
}
|
|
15294
15311
|
const owner = artifact ?? await client.getArtifact(comment.artifact_id);
|
|
15295
15312
|
return {
|
|
15296
|
-
label:
|
|
15313
|
+
label: documentLabel(owner.project, owner.slug),
|
|
15297
15314
|
details: { ...documentResultDetails(owner), comment: comment.id }
|
|
15298
15315
|
};
|
|
15299
15316
|
}
|
|
15300
|
-
async function followedAskDetails(client, ask,
|
|
15301
|
-
return { ...await askOwnerDetails(client, ask,
|
|
15317
|
+
async function followedAskDetails(client, ask, artifact) {
|
|
15318
|
+
return { ...await askOwnerDetails(client, ask, artifact), follows: { ask: ask.id } };
|
|
15302
15319
|
}
|
|
15303
15320
|
var nativeIssueKeyPattern = /^[A-Z][A-Z0-9]{1,9}-[0-9]+$/;
|
|
15304
15321
|
var externalIssueRefPattern = /^([^/\s]+)\/([^/\s#]+)#([1-9][0-9]*)$/;
|
|
@@ -15373,7 +15390,7 @@ function searchResultLine(result, baseUrl) {
|
|
|
15373
15390
|
const href = new URL(result.href, baseUrl).toString();
|
|
15374
15391
|
const { owner } = result;
|
|
15375
15392
|
if (owner.kind === "document") {
|
|
15376
|
-
const reference =
|
|
15393
|
+
const reference = dispatchDocumentRef(owner.project, owner.slug);
|
|
15377
15394
|
return `${reference} [document] ${owner.name} - ${result.kind}: ${snippetText(result.snippet)} -> ${href}`;
|
|
15378
15395
|
}
|
|
15379
15396
|
const artifactName = result.artifact ? ` ${result.artifact.name}` : "";
|
|
@@ -15384,7 +15401,6 @@ function askUrgency(args) {
|
|
|
15384
15401
|
const value = args.urgency;
|
|
15385
15402
|
return ASK_URGENCIES.find((urgency) => urgency === value);
|
|
15386
15403
|
}
|
|
15387
|
-
var maxAskQuestion16 = 800;
|
|
15388
15404
|
function questionWithRef(question, ref) {
|
|
15389
15405
|
return ref === undefined || question.includes(ref) ? question : `${question}
|
|
15390
15406
|
|
|
@@ -15394,7 +15410,7 @@ function askQuestionWithRef(args) {
|
|
|
15394
15410
|
return questionWithRef(stringArg(args, "question"), optionalString(args, "ref"));
|
|
15395
15411
|
}
|
|
15396
15412
|
function askQuestionProblem(withRef) {
|
|
15397
|
-
return withRef.length >
|
|
15413
|
+
return withRef.length > ASK_QUESTION_MAX ? `question plus ref ${overCapMessage(withRef.length, ASK_QUESTION_MAX)}; shorten the question or drop the ref` : undefined;
|
|
15398
15414
|
}
|
|
15399
15415
|
function parseDispatchRef(ref) {
|
|
15400
15416
|
const projectDocument = ref.match(/^dispatch:\/\/([A-Z][A-Z0-9]{1,9})\/artifact\/([^/@]+)(?:@v(\d+))?(?:\/(ask|comment)\/([^/]+))?$/);
|
|
@@ -15449,6 +15465,10 @@ function parseDispatchRef(ref) {
|
|
|
15449
15465
|
return { owner, kind: "message", id: message };
|
|
15450
15466
|
return { owner, kind: "issue", id: issue };
|
|
15451
15467
|
}
|
|
15468
|
+
function refTarget(ref, kind, id) {
|
|
15469
|
+
const ownerRef = ref.owner.kind === "issue" ? dispatchIssueRef(ref.owner.issue) : dispatchDocumentRef(ref.owner.project, `${ref.artifact}`);
|
|
15470
|
+
return dispatchChildRef(ownerRef, kind, id);
|
|
15471
|
+
}
|
|
15452
15472
|
var uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
15453
15473
|
var askIdProblem = "ask must be a bare ask id or a dispatch://.../ask/<id> reference";
|
|
15454
15474
|
var commentIdProblem = "comment must be a bare comment id or a dispatch://.../comment/<id> reference";
|
|
@@ -15492,7 +15512,7 @@ function argumentProblems(tool, args) {
|
|
|
15492
15512
|
case "dispatch_ask": {
|
|
15493
15513
|
const question = optionalString(args, "question");
|
|
15494
15514
|
const ref = optionalString(args, "ref");
|
|
15495
|
-
if (question !== undefined && ref !== undefined && question.length <=
|
|
15515
|
+
if (question !== undefined && ref !== undefined && question.length <= ASK_QUESTION_MAX) {
|
|
15496
15516
|
const problem = askQuestionProblem(questionWithRef(question, ref));
|
|
15497
15517
|
if (problem !== undefined)
|
|
15498
15518
|
problems.push(problem);
|
|
@@ -15582,11 +15602,17 @@ function dispatchRefFromUrl(value, serverUrl) {
|
|
|
15582
15602
|
}
|
|
15583
15603
|
var refGrammarProblem = "ref must be a valid dispatch:// reference such as dispatch://KEY-1, " + "dispatch://KEY-1/ask/<uuid>, dispatch://KEY-1/comment/<uuid>, " + "dispatch://KEY-1/message/<uuid>, dispatch://KEY-1/artifact/<slug>, or " + "dispatch://PROJECT/artifact/<document-ref> (an artifact id, slug, or filename); " + "a dashboard URL on this Dispatch server is accepted too";
|
|
15584
15604
|
var ownerRequiredProblem = "issue is required; supply issue or set LEGION_ISSUE";
|
|
15605
|
+
var toolSchemas = new Map;
|
|
15585
15606
|
function toolSchema(tool) {
|
|
15607
|
+
const cached = toolSchemas.get(tool);
|
|
15608
|
+
if (cached !== undefined)
|
|
15609
|
+
return cached;
|
|
15586
15610
|
const spec = dispatchToolSpecs.find((candidate) => candidate.name === tool);
|
|
15587
15611
|
if (!spec)
|
|
15588
15612
|
throw new Error(`Unknown Dispatch tool: ${tool}`);
|
|
15589
|
-
|
|
15613
|
+
const schema = dispatchToolSchema(spec, zodSchemaApi(exports_external), { strict: true });
|
|
15614
|
+
toolSchemas.set(tool, schema);
|
|
15615
|
+
return schema;
|
|
15590
15616
|
}
|
|
15591
15617
|
async function resolveOwnerArguments(tool, input, cwd, env, exec, serverUrl, problems) {
|
|
15592
15618
|
if (issueFreeTools[tool] === true)
|
|
@@ -15794,11 +15820,21 @@ function referenceLines(edges) {
|
|
|
15794
15820
|
return `- ${edge.kind} ${edge.node.kind} ${edge.node.ref ?? edge.node.id} (${excerpt}${edge.created_at})`;
|
|
15795
15821
|
});
|
|
15796
15822
|
}
|
|
15823
|
+
function unavailableReason(error) {
|
|
15824
|
+
return error instanceof DispatchServiceError && error.status === 404 ? "unavailable" : `unavailable: ${messageFor(error)}`;
|
|
15825
|
+
}
|
|
15797
15826
|
async function graphEdges(client, query) {
|
|
15798
15827
|
try {
|
|
15799
15828
|
return (await client.getReferences(query)).edges;
|
|
15800
15829
|
} catch (error) {
|
|
15801
|
-
return
|
|
15830
|
+
return unavailableReason(error);
|
|
15831
|
+
}
|
|
15832
|
+
}
|
|
15833
|
+
async function issueReferencesOrUnavailable(client, key) {
|
|
15834
|
+
try {
|
|
15835
|
+
return await client.getIssueReferences(key);
|
|
15836
|
+
} catch (error) {
|
|
15837
|
+
return unavailableReason(error);
|
|
15802
15838
|
}
|
|
15803
15839
|
}
|
|
15804
15840
|
async function graphSections(client, ref) {
|
|
@@ -16008,8 +16044,9 @@ async function executeDispatchTool(input) {
|
|
|
16008
16044
|
problems.push(...argumentProblems(input.tool, ownerArguments.args));
|
|
16009
16045
|
if (problems.length > 0)
|
|
16010
16046
|
throw new ToolInputError(input.tool, problems);
|
|
16047
|
+
const dispatchClient = () => new DispatchClient(configUrl, configToken, fetchImpl, input.signal);
|
|
16011
16048
|
if (input.tool === "dispatch_open_asks") {
|
|
16012
|
-
const client =
|
|
16049
|
+
const client = dispatchClient();
|
|
16013
16050
|
const project = optionalString(ownerArguments.args, "project");
|
|
16014
16051
|
if (project !== undefined) {
|
|
16015
16052
|
const response = await client.openAsksForProject(project);
|
|
@@ -16025,7 +16062,7 @@ async function executeDispatchTool(input) {
|
|
|
16025
16062
|
const sessionId = input.sessionId?.trim();
|
|
16026
16063
|
if (!sessionId)
|
|
16027
16064
|
throw new Error("host session id is required for dispatch_whoami");
|
|
16028
|
-
const client =
|
|
16065
|
+
const client = dispatchClient();
|
|
16029
16066
|
const identity = await client.whoami();
|
|
16030
16067
|
const owner = identity.kind === "agent" ? identity.owner : identity.login.toLowerCase();
|
|
16031
16068
|
return {
|
|
@@ -16035,7 +16072,7 @@ async function executeDispatchTool(input) {
|
|
|
16035
16072
|
}
|
|
16036
16073
|
const args = parsed.success ? parsed.data : ownerArguments.args;
|
|
16037
16074
|
const actor = toolActor(await resolveOrigin(env, exec, input.cwd), input);
|
|
16038
|
-
const client =
|
|
16075
|
+
const client = dispatchClient();
|
|
16039
16076
|
const owner = ownerArguments.owner?.kind === "issue" ? {
|
|
16040
16077
|
kind: "issue",
|
|
16041
16078
|
issue: await ensureIssue(client, ownerArguments.owner.issue, actor)
|
|
@@ -16274,7 +16311,7 @@ async function executeDispatchTool(input) {
|
|
|
16274
16311
|
return {
|
|
16275
16312
|
text: `Asked ${ask.id} on ${askOwner.label} (urgency ${ask.urgency}): ${ask.question}
|
|
16276
16313
|
${followsAsk(askOwner)}`,
|
|
16277
|
-
details: await followedAskDetails(client, ask, resolved)
|
|
16314
|
+
details: await followedAskDetails(client, ask, resolved?.artifact)
|
|
16278
16315
|
};
|
|
16279
16316
|
}
|
|
16280
16317
|
case "dispatch_edit_ask": {
|
|
@@ -16356,7 +16393,7 @@ ${followsAsk(askOwner)}`,
|
|
|
16356
16393
|
...inReplyTo === undefined ? {} : { in_reply_to: inReplyTo },
|
|
16357
16394
|
actor
|
|
16358
16395
|
});
|
|
16359
|
-
const messageRef =
|
|
16396
|
+
const messageRef = dispatchChildRef(dispatchIssueRef(issueKey), "message", message.id);
|
|
16360
16397
|
return {
|
|
16361
16398
|
text: `Posted message ${message.id} (${messageRef}) ${notSubscribed(issueTopic(issueKey))}`,
|
|
16362
16399
|
details: { issue: issueKey, message: message.id }
|
|
@@ -16418,7 +16455,7 @@ ${trailer.join(`
|
|
|
16418
16455
|
}
|
|
16419
16456
|
};
|
|
16420
16457
|
}
|
|
16421
|
-
const details = await followedAskDetails(client, result.ask, resolved);
|
|
16458
|
+
const details = await followedAskDetails(client, result.ask, resolved.artifact);
|
|
16422
16459
|
return {
|
|
16423
16460
|
text: `Approval requested for ${resolved.artifact.name} (document id ${resolved.artifact.id}) at version ${result.version} (ask ${result.ask.id}). The answer arrives as artifact.approved or artifact.changes_requested; an edit after approval makes it stale, so request again for the new version.`,
|
|
16424
16461
|
details: { ...details, artifact: resolved.artifact.id, version: result.version }
|
|
@@ -16441,7 +16478,7 @@ ${trailer.join(`
|
|
|
16441
16478
|
};
|
|
16442
16479
|
const artifactOwner = documentOwner();
|
|
16443
16480
|
const result = artifactOwner.kind === "project" ? await client.projectArtifact(artifactOwner.project, artifactInput) : await client.artifact(issue(), artifactInput);
|
|
16444
|
-
const artifactRef = artifactOwner.kind === "project" ?
|
|
16481
|
+
const artifactRef = dispatchDocumentRef(artifactOwner.kind === "project" ? artifactOwner.project : issue(), result.artifact.slug);
|
|
16445
16482
|
const uploadOwner = artifactOwner.kind === "project" ? documentTopic(result.artifact) : issueTopic(issue());
|
|
16446
16483
|
return {
|
|
16447
16484
|
text: `Uploaded ${result.artifact.name} as version ${result.version.number} (artifact slug ${result.artifact.slug}; ${artifactRef}) ${notSubscribed(uploadOwner)}`,
|
|
@@ -16477,7 +16514,7 @@ ${trailer.join(`
|
|
|
16477
16514
|
const ref = ownerArguments.ref;
|
|
16478
16515
|
const id = await resolveIdPrefix(input.tool, "ask", ref, async () => ref.owner.kind === "issue" ? client.listIssueAsks(ref.owner.issue) : client.getArtifactAsks((await resolveArtifact(client, ref.owner, ref.artifact)).artifact.id, "all"));
|
|
16479
16516
|
const askRead = await client.getAsk(id);
|
|
16480
|
-
const askRef = ref
|
|
16517
|
+
const askRef = refTarget(ref, "ask", id);
|
|
16481
16518
|
return {
|
|
16482
16519
|
text: askSummary(askRead, await graphSections(client, askRef)),
|
|
16483
16520
|
details: ref.owner.kind === "project" ? { project: ref.owner.project } : { issue: ref.owner.issue }
|
|
@@ -16487,7 +16524,7 @@ ${trailer.join(`
|
|
|
16487
16524
|
const ref = ownerArguments.ref;
|
|
16488
16525
|
const id = await resolveIdPrefix(input.tool, "comment", ref, async () => ref.owner.kind === "issue" ? client.getComments(ref.owner.issue) : client.getArtifactComments((await resolveArtifact(client, ref.owner, ref.artifact)).artifact.id));
|
|
16489
16526
|
const comment = await client.getComment(id);
|
|
16490
|
-
const commentRef = ref
|
|
16527
|
+
const commentRef = refTarget(ref, "comment", id);
|
|
16491
16528
|
return {
|
|
16492
16529
|
text: commentSummary(comment, await graphSections(client, commentRef)),
|
|
16493
16530
|
details: ref.owner.kind === "project" ? { project: ref.owner.project } : { issue: comment.comment.issue_key }
|
|
@@ -16498,7 +16535,7 @@ ${trailer.join(`
|
|
|
16498
16535
|
throw new Error("message references are issue-scoped");
|
|
16499
16536
|
}
|
|
16500
16537
|
const messageRead = await client.getMessage(ownerArguments.ref.owner.issue, ownerArguments.ref.id);
|
|
16501
|
-
const messageRef =
|
|
16538
|
+
const messageRef = dispatchChildRef(dispatchIssueRef(ownerArguments.ref.owner.issue), "message", ownerArguments.ref.id);
|
|
16502
16539
|
return {
|
|
16503
16540
|
text: messageSummary(messageRead, await graphSections(client, messageRef)),
|
|
16504
16541
|
details: { issue: messageRead.message.issue_key }
|
|
@@ -16506,7 +16543,7 @@ ${trailer.join(`
|
|
|
16506
16543
|
}
|
|
16507
16544
|
if (documentOwner().kind === "project") {
|
|
16508
16545
|
const resolved = await resolveArtifact(client, documentOwner(), stringArg(args, "artifact"));
|
|
16509
|
-
const documentRef =
|
|
16546
|
+
const documentRef = dispatchDocumentRef(resolved.artifact.project, resolved.artifact.slug);
|
|
16510
16547
|
return {
|
|
16511
16548
|
text: [
|
|
16512
16549
|
`Document: ${resolved.artifact.project} / ${resolved.artifact.name}`,
|
|
@@ -16518,7 +16555,7 @@ ${trailer.join(`
|
|
|
16518
16555
|
`),
|
|
16519
16556
|
details: {
|
|
16520
16557
|
project: resolved.artifact.project,
|
|
16521
|
-
document:
|
|
16558
|
+
document: documentLabel(resolved.artifact.project, resolved.artifact.slug)
|
|
16522
16559
|
}
|
|
16523
16560
|
};
|
|
16524
16561
|
}
|
|
@@ -16535,14 +16572,12 @@ ${trailer.join(`
|
|
|
16535
16572
|
details: { issue: read.issue.key }
|
|
16536
16573
|
};
|
|
16537
16574
|
}
|
|
16538
|
-
|
|
16539
|
-
|
|
16540
|
-
|
|
16541
|
-
|
|
16542
|
-
references = error instanceof DispatchServiceError && error.status === 404 ? "unavailable" : `unavailable: ${error instanceof Error ? error.message : String(error)}`;
|
|
16543
|
-
}
|
|
16575
|
+
const [references, graph] = await Promise.all([
|
|
16576
|
+
issueReferencesOrUnavailable(client, read.issue.key),
|
|
16577
|
+
graphSections(client, dispatchIssueRef(read.issue.key))
|
|
16578
|
+
]);
|
|
16544
16579
|
return {
|
|
16545
|
-
text: issueSummary(read.issue, read.events, references,
|
|
16580
|
+
text: issueSummary(read.issue, read.events, references, graph),
|
|
16546
16581
|
details: { issue: read.issue.key }
|
|
16547
16582
|
};
|
|
16548
16583
|
}
|
|
@@ -16685,6 +16720,7 @@ var envoyToolSpecs = [
|
|
|
16685
16720
|
requiresSubscriptionCapability: false
|
|
16686
16721
|
}
|
|
16687
16722
|
];
|
|
16723
|
+
var envoyToolSchemas = new Map;
|
|
16688
16724
|
|
|
16689
16725
|
// ../envoy-client/src/transport.ts
|
|
16690
16726
|
var DEFAULT_TIMEOUT_MS = 5000;
|
package/package.json
CHANGED
package/skills/dispatch/SKILL.md
CHANGED
|
@@ -30,6 +30,8 @@ vocabulary, and is often on a phone. Write for that person.
|
|
|
30
30
|
what each costs, and your recommendation with its reason.
|
|
31
31
|
- Before posting, test it: could Sami, reading only this text on his phone, know what he is being
|
|
32
32
|
told or asked? If not, rewrite it. Length is not the problem; density is.
|
|
33
|
+
- When an ask or message communicates a judgment, lead with that judgment in one sentence and put the mechanism underneath it. Do not make the reader ask a second time whether the result is a win. This shapes communication only when a judgment exists; it does not pre-decide an open question or remove its genuine options. Inferred from the AGENTC-186 12-hour-cap incident (platform PO, 2026-09-17).
|
|
34
|
+
- When a Dispatch message states a root cause, include the reproducing command or test in that same message. Without it, label the diagnosis a hypothesis; a diagnosis still in progress may say so plainly. This boundary applies to causal claims, not to reporting that an investigation has started. Inferred from the astro lane's 2026-09-16 retro (platform PO, 2026-09-17).
|
|
33
35
|
|
|
34
36
|
## Agent authentication
|
|
35
37
|
|
|
@@ -267,6 +269,8 @@ It returns the imported commit, or the recorded error when the model was rejecte
|
|
|
267
269
|
|
|
268
270
|
Before saying you are waiting for human input, call `dispatch_open_asks`. With no arguments it lists this session's active asks across open issues and project documents, including whether the human or agent owes the next reply. With `dispatch_open_asks({ project })` it lists every open ask in that project — on its issues and on its documents, whoever authored them — which is how you audit what a whole project is waiting on rather than just your own asks.
|
|
269
271
|
|
|
272
|
+
**Unsettled product shape needs a decision before implementation.** When a page, navigation entry, table key, customer-scoping rule, or persisted sidecar would set product shape that Sami has not already settled, send a one-line ask before the first implementation commit. A platform-PO schema or contract ruling does not settle product shape. This does not turn a user-specified decision or routine implementation into an approval request; it is inferred from AGENTC-186's 2026-09-16 retro (platform PO, 2026-09-17).
|
|
273
|
+
|
|
270
274
|
**Anything that needs the human is an ask, or it does not exist.** An approval, a credential,
|
|
271
275
|
a setting only they can change, a review click, a conflict between two of their own rules - if
|
|
272
276
|
your work waits on it, open a `dispatch_ask` the moment you know, the action as the question.
|