@sjawhar/opencode-legion-envoy 1.40.0 → 1.40.2
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 +118 -12
- package/package.json +1 -1
package/dist/src/server.js
CHANGED
|
@@ -13599,6 +13599,12 @@ var askEventPayloadFields = {
|
|
|
13599
13599
|
mark_id: string2().optional(),
|
|
13600
13600
|
block_id: string2().nullable().optional()
|
|
13601
13601
|
}).passthrough().nullish(),
|
|
13602
|
+
anchor_artifact: object({
|
|
13603
|
+
project: string2().optional(),
|
|
13604
|
+
slug: string2().optional(),
|
|
13605
|
+
name: string2().optional(),
|
|
13606
|
+
primary: boolean2().optional()
|
|
13607
|
+
}).optional(),
|
|
13602
13608
|
resolution: object({
|
|
13603
13609
|
kind: _enum2(["retracted", "resolved"]).optional(),
|
|
13604
13610
|
reason: string2().optional(),
|
|
@@ -13802,6 +13808,7 @@ var DOC_EDIT_OPS = ["replace", "delete", "insert", "retype", "move"];
|
|
|
13802
13808
|
var dispatchToolSpecs = [
|
|
13803
13809
|
{
|
|
13804
13810
|
name: "dispatch_issue",
|
|
13811
|
+
example: { project: "DSP", title: "Native workspace" },
|
|
13805
13812
|
description: "Create a native Dispatch issue for newly tracked work. Search first with dispatch_search; if potentially duplicate issues exist, this returns 409 POSSIBLE_DUPLICATE unless force is true after reading them. " + `Do not use it when an existing issue already covers the work; read or update that issue instead. ${ISSUE_REFERENCE}`,
|
|
13806
13813
|
arguments: (z) => ({
|
|
13807
13814
|
project: z.string().describe("Project key for the new issue."),
|
|
@@ -13818,6 +13825,7 @@ var dispatchToolSpecs = [
|
|
|
13818
13825
|
},
|
|
13819
13826
|
{
|
|
13820
13827
|
name: "dispatch_issue_update",
|
|
13828
|
+
example: { issue: "DSP-1", status: "in_progress" },
|
|
13821
13829
|
description: "Update an existing issue: move its lifecycle status, retitle it, replace its labels, link a URL " + "(the pull request that delivers it, a run, a document), set its route, set or clear its parent, " + "or attach it to architecture components. Status is one of " + `${ISSUE_STATUSES.join(", ")}; outside Legion, move it yourself as the work advances; inside ` + "Legion the daemon moves it. external_links are " + "merged into the issue's existing links by URL, so linking the pull request you just opened " + "keeps every earlier link. components replaces the issue's own attachment and is allowed on a " + "closed issue. Priority is the human's and is not settable here. At least one " + `field besides issue is required. ${ISSUE_REFERENCE}`,
|
|
13822
13830
|
arguments: (z) => ({
|
|
13823
13831
|
issue: z.string().describe(ISSUE_REFERENCE),
|
|
@@ -13840,6 +13848,7 @@ var dispatchToolSpecs = [
|
|
|
13840
13848
|
},
|
|
13841
13849
|
{
|
|
13842
13850
|
name: "dispatch_ask",
|
|
13851
|
+
example: { issue: "DSP-1", question: "Ship this?" },
|
|
13843
13852
|
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
13853
|
arguments: (z) => ({
|
|
13845
13854
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -13863,6 +13872,10 @@ var dispatchToolSpecs = [
|
|
|
13863
13872
|
},
|
|
13864
13873
|
{
|
|
13865
13874
|
name: "dispatch_edit_ask",
|
|
13875
|
+
example: {
|
|
13876
|
+
ask: "01234567-0000-4000-8000-000000000001",
|
|
13877
|
+
question: "Ship the revised plan?"
|
|
13878
|
+
},
|
|
13866
13879
|
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
13880
|
arguments: (z) => ({
|
|
13868
13881
|
ask: z.string().describe("Ask id to edit."),
|
|
@@ -13884,6 +13897,11 @@ var dispatchToolSpecs = [
|
|
|
13884
13897
|
},
|
|
13885
13898
|
{
|
|
13886
13899
|
name: "dispatch_resolve_ask",
|
|
13900
|
+
example: {
|
|
13901
|
+
ask: "01234567-0000-4000-8000-000000000001",
|
|
13902
|
+
kind: "retracted",
|
|
13903
|
+
reason: "A newer question supersedes this one."
|
|
13904
|
+
},
|
|
13887
13905
|
description: "Retract an open question that is moot or resolve one after finding the answer. This closes the question without answering it.",
|
|
13888
13906
|
arguments: (z) => ({
|
|
13889
13907
|
ask: z.string().describe("Ask id to close."),
|
|
@@ -13893,6 +13911,7 @@ var dispatchToolSpecs = [
|
|
|
13893
13911
|
},
|
|
13894
13912
|
{
|
|
13895
13913
|
name: "dispatch_resolve_comment",
|
|
13914
|
+
example: { comment: "01234567-0000-4000-8000-000000000001" },
|
|
13896
13915
|
description: "Resolve a review comment thread once it has been addressed - typically your own comment " + "after the document was fixed. Any session or human may resolve any open comment on an " + "open issue or project document; reopening a resolved comment is human-only (the dashboard). " + "Not for asks: use dispatch_resolve_ask.",
|
|
13897
13916
|
arguments: (z) => ({
|
|
13898
13917
|
comment: z.string().describe("Comment id (uuid), or a dispatch://KEY/comment/<id> or " + "dispatch://PROJECT/artifact/<slug>/comment/<id> reference; a reference accepts an " + "8+ character id prefix that is unique on its owner.")
|
|
@@ -13901,6 +13920,7 @@ var dispatchToolSpecs = [
|
|
|
13901
13920
|
},
|
|
13902
13921
|
{
|
|
13903
13922
|
name: "dispatch_follow",
|
|
13923
|
+
example: { ask: "01234567-0000-4000-8000-000000000001", action: "follow" },
|
|
13904
13924
|
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>.>",
|
|
13905
13925
|
arguments: (z) => ({
|
|
13906
13926
|
ask: z.string().describe("Full ask id (uuid)."),
|
|
@@ -13910,6 +13930,7 @@ var dispatchToolSpecs = [
|
|
|
13910
13930
|
},
|
|
13911
13931
|
{
|
|
13912
13932
|
name: "dispatch_comment",
|
|
13933
|
+
example: { issue: "DSP-1", body: "Looks good." },
|
|
13913
13934
|
description: "Add review feedback to an issue or project document quote, or reply to a question asked with dispatch_ask. " + "Do not use it for an exact replacement; use " + `dispatch_suggest instead. A quote anchor is pinned to its block. Body is at most 2,000 characters. ${OWNER_REFERENCE}`,
|
|
13914
13935
|
arguments: (z) => ({
|
|
13915
13936
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -13927,6 +13948,12 @@ var dispatchToolSpecs = [
|
|
|
13927
13948
|
},
|
|
13928
13949
|
{
|
|
13929
13950
|
name: "dispatch_suggest",
|
|
13951
|
+
example: {
|
|
13952
|
+
issue: "DSP-1",
|
|
13953
|
+
artifact: "spec",
|
|
13954
|
+
quote: "old wording",
|
|
13955
|
+
replace_with: "new wording"
|
|
13956
|
+
},
|
|
13930
13957
|
description: "Propose an exact replacement for quoted document text. Do not use it for general feedback; use " + `dispatch_comment instead. Optional explanation is at most 2,000 characters. ${OWNER_REFERENCE}`,
|
|
13931
13958
|
arguments: (z) => ({
|
|
13932
13959
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -13942,6 +13969,7 @@ var dispatchToolSpecs = [
|
|
|
13942
13969
|
},
|
|
13943
13970
|
{
|
|
13944
13971
|
name: "dispatch_message",
|
|
13972
|
+
example: { issue: "DSP-1", body: "Implementation started." },
|
|
13945
13973
|
description: "Post a note humans must read now: a reply to a human's message, a deliverable that landed, or a blocker only " + "they can clear. Never progress or status updates - Dispatch is a high-signal record, not a log. Not a decision " + `(dispatch_ask) or document feedback (dispatch_comment). Body is at most 2,000 characters. ${ISSUE_REFERENCE}`,
|
|
13946
13974
|
arguments: (z) => ({
|
|
13947
13975
|
issue: z.string().describe(ISSUE_REFERENCE),
|
|
@@ -13951,6 +13979,11 @@ var dispatchToolSpecs = [
|
|
|
13951
13979
|
},
|
|
13952
13980
|
{
|
|
13953
13981
|
name: "dispatch_doc_edit",
|
|
13982
|
+
example: {
|
|
13983
|
+
issue: "DSP-1",
|
|
13984
|
+
artifact: "spec",
|
|
13985
|
+
ops: [{ op: "replace", find: "old", with: "new" }]
|
|
13986
|
+
},
|
|
13954
13987
|
description: "Apply deterministic document edits: replace or delete quoted text, insert markdown at an anchor, retype an identified paragraph or typed block into a schema-declared typed block, and delete or move a whole block by its id. " + "Do not use it for review feedback or for reading; use dispatch_comment, dispatch_suggest, or dispatch_doc_read instead. " + "For replace, delete, and quote anchors, find text as rendered: inline Markdown (**bold**, `code`) is tolerated; a leading '# ' matches a heading. replace is inline: with is the new text of the matched span, so a leading list or heading marker stays literal text. " + "A delete whose find is a block's entire text removes the block (a list emptied of its items goes too); delete with block removes any block by id, and move with block relocates one. " + 'Insert and move anchors also accept "start", "end", "heading:<exact heading text>", and "block:<id>"; block ids are the #id of a typed block or a row of GET /api/v1/artifacts/{id}/blocks. ' + `The spec (or any document) holds requirements, design, and decisions - never progress, status, or timestamps. ${OWNER_REFERENCE} ${SPEC_WRITING_GUIDANCE}`,
|
|
13955
13988
|
arguments: (z) => ({
|
|
13956
13989
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -13975,6 +14008,7 @@ var dispatchToolSpecs = [
|
|
|
13975
14008
|
},
|
|
13976
14009
|
{
|
|
13977
14010
|
name: "dispatch_doc_read",
|
|
14011
|
+
example: { issue: "DSP-1" },
|
|
13978
14012
|
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. " + OWNER_REFERENCE,
|
|
13979
14013
|
arguments: (z) => ({
|
|
13980
14014
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -13987,6 +14021,7 @@ var dispatchToolSpecs = [
|
|
|
13987
14021
|
},
|
|
13988
14022
|
{
|
|
13989
14023
|
name: "dispatch_request_approval",
|
|
14024
|
+
example: { issue: "DSP-1" },
|
|
13990
14025
|
description: "Ask a human to approve a document at its current version - the exception path for a spec " + "that departs from what was settled or proposes children, not a step for every issue. Opens an " + "approval ask (Approve / Request changes) in the human's Inbox; the answer pins a review to the " + "document version and arrives as artifact.approved or artifact.changes_requested. A later edit " + "makes an approval stale; request again for the new version. Idempotent while a request is open. " + OWNER_REFERENCE,
|
|
13991
14026
|
arguments: (z) => ({
|
|
13992
14027
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -13997,6 +14032,8 @@ var dispatchToolSpecs = [
|
|
|
13997
14032
|
},
|
|
13998
14033
|
{
|
|
13999
14034
|
name: "dispatch_artifact",
|
|
14035
|
+
example: { issue: "DSP-1", name: "design.md", content: `# Design
|
|
14036
|
+
` },
|
|
14000
14037
|
description: "Attach a local file or inline text as an issue artifact or project document. Do not use it to edit a live document; use " + `dispatch_doc_edit instead. Exactly one of path or content is required; artifacts are limited to 25 MiB. ${OWNER_REFERENCE}`,
|
|
14001
14038
|
arguments: (z) => ({
|
|
14002
14039
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -14016,6 +14053,7 @@ var dispatchToolSpecs = [
|
|
|
14016
14053
|
},
|
|
14017
14054
|
{
|
|
14018
14055
|
name: "dispatch_read",
|
|
14056
|
+
example: { issue: "DSP-1" },
|
|
14019
14057
|
description: "Read an issue or project-document summary, targeted ask, or targeted comment reply chain. Do not use it for document " + "contents; use dispatch_doc_read instead. Supply ref, issue, or project plus artifact. " + "Every read ends with `Referenced by:` (what cites or hangs off this node, each with its dispatch:// address, " + "an excerpt, and when) and `Links:` (what it cites), so tracing provenance is one call. " + OWNER_REFERENCE,
|
|
14020
14058
|
arguments: (z) => ({
|
|
14021
14059
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -14027,6 +14065,7 @@ var dispatchToolSpecs = [
|
|
|
14027
14065
|
},
|
|
14028
14066
|
{
|
|
14029
14067
|
name: "dispatch_search",
|
|
14068
|
+
example: { query: "astrolabe" },
|
|
14030
14069
|
description: "Search every issue, document, comment, ask, and message for a keyword or phrase and get deep links. " + "Use it before creating an issue or a design document, and to find where a word was written. " + 'Websearch syntax: "quoted phrase", -excluded, OR.',
|
|
14031
14070
|
arguments: (z) => ({
|
|
14032
14071
|
query: z.string({ min: 2 }).describe("Keyword, phrase, or websearch expression; at least 2 characters."),
|
|
@@ -14036,6 +14075,7 @@ var dispatchToolSpecs = [
|
|
|
14036
14075
|
},
|
|
14037
14076
|
{
|
|
14038
14077
|
name: "dispatch_issues",
|
|
14078
|
+
example: { project: "AGENTC" },
|
|
14039
14079
|
description: "List a project's issues for a roadmap or backlog pass: every issue in one project, each carrying " + "its status, priority, parent, labels, and open-ask count, so you can see backlog shape without " + "opening every issue. Optionally filter by status, parent, label, or how recently it changed. Do " + "not use it to search by keyword or phrase; dispatch_search remains the keyword surface. Rows are " + "capped at limit (default 50, max 250), applied to the response here, not by the server.",
|
|
14040
14080
|
arguments: (z) => ({
|
|
14041
14081
|
project: z.string().describe("Project key to list issues from."),
|
|
@@ -14048,6 +14088,7 @@ var dispatchToolSpecs = [
|
|
|
14048
14088
|
},
|
|
14049
14089
|
{
|
|
14050
14090
|
name: "dispatch_architecture_sync",
|
|
14091
|
+
example: { project: "CORE" },
|
|
14051
14092
|
description: "Import a project's architecture model from its configured source repository now, instead of " + "waiting for the server's five-minute schedule. Returns the imported commit and component " + "count, or the recorded error when the model was rejected (the previous model stays up). " + "The source itself is configured by a human in Settings; 404 SOURCE_NOT_FOUND without one.",
|
|
14052
14093
|
arguments: (z) => ({
|
|
14053
14094
|
project: z.string().describe("Project key whose architecture source to sync, such as CORE.")
|
|
@@ -14056,6 +14097,7 @@ var dispatchToolSpecs = [
|
|
|
14056
14097
|
},
|
|
14057
14098
|
{
|
|
14058
14099
|
name: "dispatch_open_asks",
|
|
14100
|
+
example: {},
|
|
14059
14101
|
description: "List active unanswered asks, oldest first, with age and whose reply is needed. Omit project to " + "see only this session's own authored asks (call before saying you are waiting for human input); " + "supply project to see every open ask across that project's issues and documents, whoever authored " + "them.",
|
|
14060
14102
|
arguments: (z) => ({
|
|
14061
14103
|
project: z.string().describe("Project key; when supplied, lists every open ask in the project instead of only this session's own.").optional()
|
|
@@ -14064,6 +14106,7 @@ var dispatchToolSpecs = [
|
|
|
14064
14106
|
},
|
|
14065
14107
|
{
|
|
14066
14108
|
name: "dispatch_whoami",
|
|
14109
|
+
example: {},
|
|
14067
14110
|
description: "Who Dispatch takes this session for: {session, owner}. owner is the lowercase GitHub login of the human whose personal token you run under (the default assignee of issues you create), or null under the shared token.",
|
|
14068
14111
|
arguments: () => ({}),
|
|
14069
14112
|
strict: true
|
|
@@ -15166,9 +15209,11 @@ class ToolInputError extends Error {
|
|
|
15166
15209
|
problems;
|
|
15167
15210
|
constructor(tool, problems) {
|
|
15168
15211
|
const count = problems.length;
|
|
15212
|
+
const help = dispatchInputHelp(tool);
|
|
15169
15213
|
super([
|
|
15170
15214
|
`${tool} was not called: ${count} problem${count === 1 ? "" : "s"}`,
|
|
15171
|
-
...problems.map((problem) => `- ${problem}`)
|
|
15215
|
+
...problems.map((problem) => `- ${problem}`),
|
|
15216
|
+
...help === undefined ? [] : help.map((line) => `- ${line}`)
|
|
15172
15217
|
].join(`
|
|
15173
15218
|
`));
|
|
15174
15219
|
this.name = "ToolInputError";
|
|
@@ -15176,6 +15221,14 @@ class ToolInputError extends Error {
|
|
|
15176
15221
|
this.problems = problems;
|
|
15177
15222
|
}
|
|
15178
15223
|
}
|
|
15224
|
+
function dispatchInputHelp(tool) {
|
|
15225
|
+
const spec = dispatchToolSpecs.find((candidate) => candidate.name === tool);
|
|
15226
|
+
if (spec === undefined)
|
|
15227
|
+
return;
|
|
15228
|
+
const schema = dispatchToolSchema(spec, zodSchemaApi(exports_external), { strict: true });
|
|
15229
|
+
const allowed = Object.keys(shapeOf(schema) ?? {}).join(", ") || "none";
|
|
15230
|
+
return [`Allowed keys: ${allowed}`, `Example: ${tool}(${JSON.stringify(spec.example)})`];
|
|
15231
|
+
}
|
|
15179
15232
|
function unwrap(schema) {
|
|
15180
15233
|
let current = schema;
|
|
15181
15234
|
while (current !== undefined) {
|
|
@@ -15480,7 +15533,21 @@ function refTarget(ref, kind, id) {
|
|
|
15480
15533
|
const ownerRef = ref.owner.kind === "issue" ? dispatchIssueRef(ref.owner.issue) : dispatchDocumentRef(ref.owner.project, `${ref.artifact}`);
|
|
15481
15534
|
return dispatchChildRef(ownerRef, kind, id);
|
|
15482
15535
|
}
|
|
15483
|
-
var
|
|
15536
|
+
var canonicalUUIDPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
15537
|
+
var compactUUIDPattern = /^[0-9a-f]{32}$/i;
|
|
15538
|
+
function normalizeUUID(value) {
|
|
15539
|
+
let compact = value;
|
|
15540
|
+
if (value.slice(0, 9).toLowerCase() === "urn:uuid:") {
|
|
15541
|
+
compact = value.slice(9);
|
|
15542
|
+
} else if (value.length === 38 && value.startsWith("{") && value.endsWith("}")) {
|
|
15543
|
+
compact = value.slice(1, -1);
|
|
15544
|
+
}
|
|
15545
|
+
if (canonicalUUIDPattern.test(compact))
|
|
15546
|
+
compact = compact.replaceAll("-", "");
|
|
15547
|
+
if (!compactUUIDPattern.test(compact))
|
|
15548
|
+
return;
|
|
15549
|
+
return `${compact.slice(0, 8)}-${compact.slice(8, 12)}-${compact.slice(12, 16)}-${compact.slice(16, 20)}-${compact.slice(20)}`.toLowerCase();
|
|
15550
|
+
}
|
|
15484
15551
|
var askIdProblem = "ask must be a bare ask id or a dispatch://.../ask/<id> reference";
|
|
15485
15552
|
var commentIdProblem = "comment must be a bare comment id or a dispatch://.../comment/<id> reference";
|
|
15486
15553
|
var messageIdProblem = "in_reply_to must be a full message id (uuid) or a dispatch://KEY/message/<id> reference";
|
|
@@ -15493,12 +15560,13 @@ function messageIdOf(value) {
|
|
|
15493
15560
|
const reference = parseDispatchRef(value);
|
|
15494
15561
|
return reference?.kind === "message" ? reference.id : undefined;
|
|
15495
15562
|
})() : value;
|
|
15496
|
-
return id
|
|
15563
|
+
return id === undefined ? undefined : normalizeUUID(id);
|
|
15497
15564
|
}
|
|
15498
15565
|
var idPrefixPattern = /^[0-9a-f][0-9a-f-]{7,}$/i;
|
|
15499
15566
|
async function resolveIdPrefix(tool, kind, ref, list) {
|
|
15500
|
-
|
|
15501
|
-
|
|
15567
|
+
const fullID = normalizeUUID(ref.id);
|
|
15568
|
+
if (fullID !== undefined)
|
|
15569
|
+
return fullID;
|
|
15502
15570
|
const ownerName = ref.owner.kind === "issue" ? ref.owner.issue : `${ref.owner.project}/${ref.artifact}`;
|
|
15503
15571
|
if (!idPrefixPattern.test(ref.id)) {
|
|
15504
15572
|
throw new ToolInputError(tool, [
|
|
@@ -15730,21 +15798,53 @@ async function resolveArtifact(client, owner, artifactReference) {
|
|
|
15730
15798
|
return { owner, artifact };
|
|
15731
15799
|
const names = artifacts.filter((candidate) => candidate.name === artifactReference);
|
|
15732
15800
|
if (names.length > 1) {
|
|
15733
|
-
throw new Error(
|
|
15801
|
+
throw new Error(documentReferenceProblem(artifactReference, names, "project", true));
|
|
15802
|
+
}
|
|
15803
|
+
if (names[0] === undefined) {
|
|
15804
|
+
throw new Error(documentReferenceProblem(artifactReference, artifacts, "project"));
|
|
15734
15805
|
}
|
|
15735
|
-
if (names[0] === undefined)
|
|
15736
|
-
throw error;
|
|
15737
15806
|
return { owner, artifact: names[0] };
|
|
15738
15807
|
}
|
|
15739
15808
|
}
|
|
15740
15809
|
const issue = await client.getIssue(owner.issue);
|
|
15741
|
-
|
|
15810
|
+
let artifact;
|
|
15811
|
+
if (artifactReference === undefined || artifactReference === "spec") {
|
|
15812
|
+
artifact = issue.artifacts.find((candidate) => candidate.primary || candidate.id === issue.primary_artifact_id);
|
|
15813
|
+
} else {
|
|
15814
|
+
artifact = issue.artifacts.find((candidate) => candidate.id === artifactReference || candidate.slug === artifactReference);
|
|
15815
|
+
if (artifact === undefined) {
|
|
15816
|
+
const names = issue.artifacts.filter((candidate) => candidate.name === artifactReference);
|
|
15817
|
+
if (names.length > 1) {
|
|
15818
|
+
throw new Error(documentReferenceProblem(artifactReference, names, "issue", true));
|
|
15819
|
+
}
|
|
15820
|
+
artifact = names[0];
|
|
15821
|
+
}
|
|
15822
|
+
}
|
|
15742
15823
|
if (!artifact) {
|
|
15743
|
-
|
|
15744
|
-
throw new Error(`artifact "${artifactReference ?? "spec"}" was not found on issue ${issue.key}; artifacts: ${slugs.length === 0 ? "none" : slugs.join(", ")}`);
|
|
15824
|
+
throw new Error(documentReferenceProblem(artifactReference ?? "spec", issue.artifacts, "issue"));
|
|
15745
15825
|
}
|
|
15746
15826
|
return { owner, issue, artifact };
|
|
15747
15827
|
}
|
|
15828
|
+
var documentHintLimit = 8;
|
|
15829
|
+
function documentReferenceProblem(reference, documents, owner, ambiguous = false) {
|
|
15830
|
+
const hints = documents.slice(0, documentHintLimit).map((document) => `${document.slug} (${document.name})`);
|
|
15831
|
+
const list = hints.length === 0 ? "none" : hints.join(", ");
|
|
15832
|
+
return ambiguous ? `"${reference}" names ${documents.length} documents on this ${owner}; use a slug: ${list}` : `document "${reference}" not found by slug; this ${owner}'s documents: ${list}`;
|
|
15833
|
+
}
|
|
15834
|
+
var askHintLimit = 8;
|
|
15835
|
+
function askIDInputProblem(asks, scope) {
|
|
15836
|
+
const hints = asks.slice(0, askHintLimit).map((ask) => `${ask.id.slice(0, 8)}\u2026 ${textHead(ask.question)}`);
|
|
15837
|
+
return `ask IDs are UUIDs; use the full ask ID; ${scope} open asks: ${hints.length === 0 ? "none" : hints.join(", ")}`;
|
|
15838
|
+
}
|
|
15839
|
+
async function invalidReplyToAskProblem(client, owner, resolved) {
|
|
15840
|
+
if (owner.kind === "issue") {
|
|
15841
|
+
const issue = resolved?.issue ?? await client.getIssue(owner.issue);
|
|
15842
|
+
return askIDInputProblem(issue.open_asks, "this issue's");
|
|
15843
|
+
}
|
|
15844
|
+
if (resolved === undefined)
|
|
15845
|
+
throw new Error("project document is missing its resolved artifact");
|
|
15846
|
+
return askIDInputProblem(await client.getArtifactAsks(resolved.artifact.id, "open"), "this document's");
|
|
15847
|
+
}
|
|
15748
15848
|
function anchor(artifact, args) {
|
|
15749
15849
|
const quote = optionalString(args, "quote");
|
|
15750
15850
|
if (quote === undefined)
|
|
@@ -16348,7 +16448,13 @@ ${followsAsk(askOwner)}`,
|
|
|
16348
16448
|
const resolved = owner.kind === "project" || artifactReference === undefined ? owner.kind === "project" ? await resolveArtifact(client, owner, artifactReference) : undefined : await resolveArtifact(client, owner, artifactReference);
|
|
16349
16449
|
const anchored = resolved ? anchor(resolved.artifact, args) : undefined;
|
|
16350
16450
|
const replyTo = optionalString(args, "reply_to");
|
|
16351
|
-
const
|
|
16451
|
+
const replyToAskReference = optionalString(args, "reply_to_ask");
|
|
16452
|
+
const replyToAsk = replyToAskReference === undefined ? undefined : normalizeUUID(replyToAskReference);
|
|
16453
|
+
if (replyToAskReference !== undefined && replyToAsk === undefined) {
|
|
16454
|
+
throw new ToolInputError(input.tool, [
|
|
16455
|
+
await invalidReplyToAskProblem(client, owner, resolved)
|
|
16456
|
+
]);
|
|
16457
|
+
}
|
|
16352
16458
|
const requestedTurn = optionalString(args, "turn");
|
|
16353
16459
|
const commentInput = {
|
|
16354
16460
|
body: stringArg(args, "body"),
|