@sjawhar/opencode-legion-envoy 1.45.5 → 1.46.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 +48 -18
- package/package.json +1 -1
- package/skills/dispatch/SKILL.md +3 -1
package/dist/src/server.js
CHANGED
|
@@ -13952,7 +13952,7 @@ var dispatchToolSpecs = [
|
|
|
13952
13952
|
},
|
|
13953
13953
|
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.",
|
|
13954
13954
|
arguments: (z) => ({
|
|
13955
|
-
ask: z.string().describe("Ask id
|
|
13955
|
+
ask: z.string().describe("Ask id (uuid); an 8+ hex prefix unique among this session's own open asks works too."),
|
|
13956
13956
|
question: z.string({ max: ASK_QUESTION_MAX }).describe(`Replacement decision question, at most ${ASK_QUESTION_MAX} characters.`).optional(),
|
|
13957
13957
|
options: z.array(z.object({
|
|
13958
13958
|
label: z.string().describe("Selectable option label."),
|
|
@@ -13978,7 +13978,7 @@ var dispatchToolSpecs = [
|
|
|
13978
13978
|
},
|
|
13979
13979
|
description: "Retract an open question that is moot or resolve one after finding the answer. This closes the question without answering it.",
|
|
13980
13980
|
arguments: (z) => ({
|
|
13981
|
-
ask: z.string().describe("Ask id to close."),
|
|
13981
|
+
ask: z.string().describe("Ask id (uuid) to close; an 8+ hex prefix unique among this session's own open asks " + "works too."),
|
|
13982
13982
|
kind: z.enum(["retracted", "resolved"]).describe("Whether the ask is retracted or self-resolved."),
|
|
13983
13983
|
reason: z.string({ min: 1 }).describe("Why the open ask no longer needs a human answer.")
|
|
13984
13984
|
})
|
|
@@ -13997,7 +13997,7 @@ var dispatchToolSpecs = [
|
|
|
13997
13997
|
example: { ask: "01234567-0000-4000-8000-000000000001", action: "follow" },
|
|
13998
13998
|
description: "Follow or unfollow an ask. Every session that opens or replies to an ask follows it: its answer, " + "edits, resolution, and replies reach that session directly. Unfollow to stop; follow to rejoin or " + "to hear an ask you never wrote to. Whole-issue subscription is separate: envoy_subscribe " + "notifications.dispatch.issue.<KEY>.>",
|
|
13999
13999
|
arguments: (z) => ({
|
|
14000
|
-
ask: z.string().describe("
|
|
14000
|
+
ask: z.string().describe("Ask id (uuid); an 8+ hex prefix unique among this session's own open asks works too."),
|
|
14001
14001
|
action: z.enum(["follow", "unfollow"]).describe("follow | unfollow")
|
|
14002
14002
|
}),
|
|
14003
14003
|
strict: true
|
|
@@ -15688,24 +15688,51 @@ function messageIdOf(value) {
|
|
|
15688
15688
|
return id === undefined ? undefined : normalizeUUID(id);
|
|
15689
15689
|
}
|
|
15690
15690
|
var idPrefixPattern = /^[0-9a-f][0-9a-f-]{7,}$/i;
|
|
15691
|
-
|
|
15692
|
-
|
|
15691
|
+
function refOwnerName(ref) {
|
|
15692
|
+
return ref.owner.kind === "issue" ? ref.owner.issue : `${ref.owner.project}/${ref.artifact}`;
|
|
15693
|
+
}
|
|
15694
|
+
async function resolveIdPrefix(tool, kind, id, ownerName, list) {
|
|
15695
|
+
const fullID = normalizeUUID(id);
|
|
15693
15696
|
if (fullID !== undefined)
|
|
15694
15697
|
return fullID;
|
|
15695
|
-
|
|
15696
|
-
if (!idPrefixPattern.test(ref.id)) {
|
|
15698
|
+
if (!idPrefixPattern.test(id)) {
|
|
15697
15699
|
throw new ToolInputError(tool, [
|
|
15698
|
-
`${kind} id ${
|
|
15700
|
+
`${kind} id ${id} must be a full uuid or a prefix of at least 8 hex characters`
|
|
15699
15701
|
]);
|
|
15700
15702
|
}
|
|
15701
|
-
const prefix =
|
|
15703
|
+
const prefix = id.toLowerCase();
|
|
15702
15704
|
const matches = (await list()).filter((item) => item.id.toLowerCase().startsWith(prefix));
|
|
15703
15705
|
if (matches.length === 1 && matches[0] !== undefined)
|
|
15704
15706
|
return matches[0].id;
|
|
15705
15707
|
throw new ToolInputError(tool, [
|
|
15706
|
-
matches.length === 0 ? `${kind} id ${
|
|
15708
|
+
matches.length === 0 ? `${kind} id ${id} matches none of the ${kind}s on ${ownerName}; use the full id` : `${kind} id ${id} matches ${matches.length} ${kind}s on ${ownerName}; use the full id`
|
|
15707
15709
|
]);
|
|
15708
15710
|
}
|
|
15711
|
+
var askIdShapeProblem = "ask ids are uuids (a prefix of at least 8 hex characters works)";
|
|
15712
|
+
async function sessionOpenAsks(client, sessionId) {
|
|
15713
|
+
const session = sessionId?.trim();
|
|
15714
|
+
if (!session)
|
|
15715
|
+
throw new Error("host session id is required to read this session's open asks");
|
|
15716
|
+
return (await client.openAsks(session)).asks;
|
|
15717
|
+
}
|
|
15718
|
+
function openAskHints(asks) {
|
|
15719
|
+
if (asks.length === 0)
|
|
15720
|
+
return "you have no open asks";
|
|
15721
|
+
const hints = asks.slice(0, askHintLimit).map((ask) => `${ask.id.slice(0, 8)} \u2014 ${textHead(ask.question)}`);
|
|
15722
|
+
return `your open asks: ${hints.join("; ")}`;
|
|
15723
|
+
}
|
|
15724
|
+
async function resolveAskArgument(tool, args, client, sessionId) {
|
|
15725
|
+
const id = askId(args);
|
|
15726
|
+
if (normalizeUUID(id) === undefined && !idPrefixPattern.test(id)) {
|
|
15727
|
+
const asks = await sessionOpenAsks(client, sessionId).catch(() => {
|
|
15728
|
+
return;
|
|
15729
|
+
});
|
|
15730
|
+
throw new ToolInputError(tool, [
|
|
15731
|
+
asks === undefined ? askIdShapeProblem : `${askIdShapeProblem}; ${openAskHints(asks)}`
|
|
15732
|
+
]);
|
|
15733
|
+
}
|
|
15734
|
+
return resolveIdPrefix(tool, "ask", id, "this session", () => sessionOpenAsks(client, sessionId));
|
|
15735
|
+
}
|
|
15709
15736
|
function messageInReplyTo(args) {
|
|
15710
15737
|
const inReplyTo = optionalString(args, "in_reply_to");
|
|
15711
15738
|
return inReplyTo === undefined ? undefined : messageIdOf(inReplyTo);
|
|
@@ -15724,7 +15751,8 @@ function argumentProblems(tool, args) {
|
|
|
15724
15751
|
break;
|
|
15725
15752
|
}
|
|
15726
15753
|
case "dispatch_edit_ask":
|
|
15727
|
-
case "dispatch_resolve_ask":
|
|
15754
|
+
case "dispatch_resolve_ask":
|
|
15755
|
+
case "dispatch_follow": {
|
|
15728
15756
|
const ask = optionalString(args, "ask");
|
|
15729
15757
|
if (ask?.startsWith("dispatch://") && parseDispatchRef(ask)?.kind !== "ask") {
|
|
15730
15758
|
problems.push(askIdProblem);
|
|
@@ -16518,7 +16546,8 @@ async function executeDispatchTool(input) {
|
|
|
16518
16546
|
}
|
|
16519
16547
|
case "dispatch_resolve_ask": {
|
|
16520
16548
|
const kind = stringArg(args, "kind");
|
|
16521
|
-
const
|
|
16549
|
+
const id = await resolveAskArgument(input.tool, args, client, input.sessionId);
|
|
16550
|
+
const ask = await client.resolveAsk(id, {
|
|
16522
16551
|
kind,
|
|
16523
16552
|
reason: stringArg(args, "reason"),
|
|
16524
16553
|
actor
|
|
@@ -16537,11 +16566,11 @@ async function executeDispatchTool(input) {
|
|
|
16537
16566
|
let document;
|
|
16538
16567
|
if (ref?.owner.kind === "issue") {
|
|
16539
16568
|
const issueKey = ref.owner.issue;
|
|
16540
|
-
id = await resolveIdPrefix(input.tool, "comment", ref, () => client.getComments(issueKey));
|
|
16569
|
+
id = await resolveIdPrefix(input.tool, "comment", ref.id, refOwnerName(ref), () => client.getComments(issueKey));
|
|
16541
16570
|
} else if (ref !== null) {
|
|
16542
16571
|
const artifact = (await resolveArtifact(client, ref.owner, ref.artifact)).artifact;
|
|
16543
16572
|
document = artifact;
|
|
16544
|
-
id = await resolveIdPrefix(input.tool, "comment", ref, () => client.getArtifactComments(artifact.id));
|
|
16573
|
+
id = await resolveIdPrefix(input.tool, "comment", ref.id, refOwnerName(ref), () => client.getArtifactComments(artifact.id));
|
|
16545
16574
|
}
|
|
16546
16575
|
const comment = await client.resolveComment(id, actor);
|
|
16547
16576
|
const { label, details } = await commentOwnerResult(client, comment, document);
|
|
@@ -16585,7 +16614,8 @@ ${followsAsk(askOwner)}`,
|
|
|
16585
16614
|
const options = args.options;
|
|
16586
16615
|
const multiple = optionalBoolean(args, "multiple");
|
|
16587
16616
|
const urgency = askUrgency(args);
|
|
16588
|
-
const
|
|
16617
|
+
const id = await resolveAskArgument(input.tool, args, client, input.sessionId);
|
|
16618
|
+
const ask = await client.editAsk(id, {
|
|
16589
16619
|
...question === undefined ? {} : { question },
|
|
16590
16620
|
...Array.isArray(options) ? { options } : {},
|
|
16591
16621
|
...multiple === undefined ? {} : { multiple },
|
|
@@ -16812,7 +16842,7 @@ ${trailer.join(`
|
|
|
16812
16842
|
const sessionId = input.sessionId?.trim();
|
|
16813
16843
|
if (!sessionId)
|
|
16814
16844
|
throw new Error("host session id is required for dispatch_follow");
|
|
16815
|
-
const ask =
|
|
16845
|
+
const ask = await resolveAskArgument(input.tool, args, client, sessionId);
|
|
16816
16846
|
const action = stringArg(args, "action");
|
|
16817
16847
|
if (action === "unfollow") {
|
|
16818
16848
|
await client.unfollowAsk(ask, sessionId, actor);
|
|
@@ -16828,7 +16858,7 @@ ${trailer.join(`
|
|
|
16828
16858
|
case "dispatch_read": {
|
|
16829
16859
|
if (ownerArguments.ref?.kind === "ask") {
|
|
16830
16860
|
const ref = ownerArguments.ref;
|
|
16831
|
-
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"));
|
|
16861
|
+
const id = await resolveIdPrefix(input.tool, "ask", ref.id, refOwnerName(ref), async () => ref.owner.kind === "issue" ? client.listIssueAsks(ref.owner.issue) : client.getArtifactAsks((await resolveArtifact(client, ref.owner, ref.artifact)).artifact.id, "all"));
|
|
16832
16862
|
const askRead = await client.getAsk(id);
|
|
16833
16863
|
const askRef = refTarget(ref, "ask", id);
|
|
16834
16864
|
return {
|
|
@@ -16838,7 +16868,7 @@ ${trailer.join(`
|
|
|
16838
16868
|
}
|
|
16839
16869
|
if (ownerArguments.ref?.kind === "comment") {
|
|
16840
16870
|
const ref = ownerArguments.ref;
|
|
16841
|
-
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));
|
|
16871
|
+
const id = await resolveIdPrefix(input.tool, "comment", ref.id, refOwnerName(ref), async () => ref.owner.kind === "issue" ? client.getComments(ref.owner.issue) : client.getArtifactComments((await resolveArtifact(client, ref.owner, ref.artifact)).artifact.id));
|
|
16842
16872
|
const comment = await client.getComment(id);
|
|
16843
16873
|
const commentRef = refTarget(ref, "comment", id);
|
|
16844
16874
|
return {
|
package/package.json
CHANGED
package/skills/dispatch/SKILL.md
CHANGED
|
@@ -708,7 +708,9 @@ the host tells you once per ask. Leave a thread you no longer need, or rejoin on
|
|
|
708
708
|
dispatch_follow({ ask, action: "follow" | "unfollow" })
|
|
709
709
|
```
|
|
710
710
|
|
|
711
|
-
`ask` is the full ask id or a `dispatch://KEY/ask/<id>` reference
|
|
711
|
+
`ask` is the full ask id or a `dispatch://KEY/ask/<id>` reference; `dispatch_follow`, `dispatch_edit_ask`, and
|
|
712
|
+
`dispatch_resolve_ask` also take an 8+ hex prefix that is unique among your own open asks, and refuse anything shorter by naming
|
|
713
|
+
those asks. A human may also remove you from the ask card; either way you are
|
|
712
714
|
told with an `ask.follower_removed` notice, and a human adding you arrives as `ask.follower_added`.
|
|
713
715
|
|
|
714
716
|
No write subscribes you to an issue or document. Following covers your own asks and the threads you joined; everything else on the
|