@sjawhar/opencode-legion-envoy 1.40.1 → 1.41.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 +160 -14
- package/package.json +1 -1
package/dist/src/server.js
CHANGED
|
@@ -13629,6 +13629,24 @@ var AskEditedEventPayloadSchema = object({
|
|
|
13629
13629
|
}),
|
|
13630
13630
|
edited_by: object({ kind: string2(), id: string2() }).passthrough()
|
|
13631
13631
|
});
|
|
13632
|
+
var CommentMentionSchema = object({
|
|
13633
|
+
target: string2(),
|
|
13634
|
+
delivery: _enum2(DELIVERY_CAPABILITIES),
|
|
13635
|
+
session_id: string2().nullable()
|
|
13636
|
+
});
|
|
13637
|
+
var CommentDeliverySchema = object({
|
|
13638
|
+
comment_id: string2(),
|
|
13639
|
+
target: string2(),
|
|
13640
|
+
attempt: number2().int().positive(),
|
|
13641
|
+
delivery: _enum2(DELIVERY_CAPABILITIES),
|
|
13642
|
+
session_id: string2().nullable(),
|
|
13643
|
+
envelope_id: string2().nullable(),
|
|
13644
|
+
state: _enum2(["pending", "sent", "failed"]),
|
|
13645
|
+
error: string2().nullable(),
|
|
13646
|
+
resolve_error: string2().nullable(),
|
|
13647
|
+
reply_id: string2().nullable(),
|
|
13648
|
+
created_at: string2()
|
|
13649
|
+
});
|
|
13632
13650
|
var CommentEventPayloadSchema = object({
|
|
13633
13651
|
id: string2().optional(),
|
|
13634
13652
|
artifact_name: string2().optional(),
|
|
@@ -13644,7 +13662,9 @@ var CommentEventPayloadSchema = object({
|
|
|
13644
13662
|
anchor: object({ block_id: string2().nullable().optional(), quote: string2().optional() }).nullish(),
|
|
13645
13663
|
suggestion: object({ replace_with: string2().optional() }).nullish(),
|
|
13646
13664
|
author: object({ kind: string2(), id: string2() }).optional(),
|
|
13647
|
-
created_at: string2().optional()
|
|
13665
|
+
created_at: string2().optional(),
|
|
13666
|
+
mentions: array(CommentMentionSchema).optional(),
|
|
13667
|
+
deliveries: array(CommentDeliverySchema).optional()
|
|
13648
13668
|
});
|
|
13649
13669
|
var MessageEventPayloadSchema = object({
|
|
13650
13670
|
id: string2().optional(),
|
|
@@ -13654,8 +13674,9 @@ var MessageEventPayloadSchema = object({
|
|
|
13654
13674
|
reply_body: string2().optional(),
|
|
13655
13675
|
author: object({ kind: string2(), id: string2() }).optional()
|
|
13656
13676
|
});
|
|
13677
|
+
var DispatchTargetedResourceIDSchema = uuid2();
|
|
13657
13678
|
var DispatchTargetedMessagePayloadSchema = MessageEventPayloadSchema.extend({
|
|
13658
|
-
id:
|
|
13679
|
+
id: DispatchTargetedResourceIDSchema,
|
|
13659
13680
|
issue_key: string2().nullable(),
|
|
13660
13681
|
author: object({ kind: string2(), id: string2() }),
|
|
13661
13682
|
body: string2(),
|
|
@@ -13664,6 +13685,31 @@ var DispatchTargetedMessagePayloadSchema = MessageEventPayloadSchema.extend({
|
|
|
13664
13685
|
deliveries: array(unknown()),
|
|
13665
13686
|
created_at: string2()
|
|
13666
13687
|
});
|
|
13688
|
+
var DispatchTargetedCommentPayloadSchema = CommentEventPayloadSchema.extend({
|
|
13689
|
+
id: DispatchTargetedResourceIDSchema,
|
|
13690
|
+
issue_key: string2().nullable(),
|
|
13691
|
+
artifact_id: string2().nullable(),
|
|
13692
|
+
author: object({ kind: string2(), id: string2() }),
|
|
13693
|
+
body: string2(),
|
|
13694
|
+
reply_to: string2().nullable(),
|
|
13695
|
+
ask_id: string2().nullable(),
|
|
13696
|
+
mentions: array(CommentMentionSchema),
|
|
13697
|
+
deliveries: array(CommentDeliverySchema),
|
|
13698
|
+
created_at: string2(),
|
|
13699
|
+
artifact_name: string2()
|
|
13700
|
+
});
|
|
13701
|
+
var DispatchTargetedMessageDeliverySchema = object({
|
|
13702
|
+
attempt: number2().int().positive(),
|
|
13703
|
+
mode: _enum2(DELIVERY_CAPABILITIES)
|
|
13704
|
+
});
|
|
13705
|
+
var DispatchTargetedCommentDeliverySchema = DispatchTargetedMessageDeliverySchema.extend({
|
|
13706
|
+
comment_id: DispatchTargetedResourceIDSchema,
|
|
13707
|
+
target: string2()
|
|
13708
|
+
});
|
|
13709
|
+
var DispatchTargetedDeliverySchema = union([
|
|
13710
|
+
DispatchTargetedCommentDeliverySchema,
|
|
13711
|
+
DispatchTargetedMessageDeliverySchema
|
|
13712
|
+
]);
|
|
13667
13713
|
var MessageDeliveryEventPayloadSchema = object({
|
|
13668
13714
|
message_id: string2().optional(),
|
|
13669
13715
|
attempt: number2().int().positive().optional(),
|
|
@@ -13808,6 +13854,7 @@ var DOC_EDIT_OPS = ["replace", "delete", "insert", "retype", "move"];
|
|
|
13808
13854
|
var dispatchToolSpecs = [
|
|
13809
13855
|
{
|
|
13810
13856
|
name: "dispatch_issue",
|
|
13857
|
+
example: { project: "DSP", title: "Native workspace" },
|
|
13811
13858
|
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}`,
|
|
13812
13859
|
arguments: (z) => ({
|
|
13813
13860
|
project: z.string().describe("Project key for the new issue."),
|
|
@@ -13824,6 +13871,7 @@ var dispatchToolSpecs = [
|
|
|
13824
13871
|
},
|
|
13825
13872
|
{
|
|
13826
13873
|
name: "dispatch_issue_update",
|
|
13874
|
+
example: { issue: "DSP-1", status: "in_progress" },
|
|
13827
13875
|
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}`,
|
|
13828
13876
|
arguments: (z) => ({
|
|
13829
13877
|
issue: z.string().describe(ISSUE_REFERENCE),
|
|
@@ -13846,6 +13894,7 @@ var dispatchToolSpecs = [
|
|
|
13846
13894
|
},
|
|
13847
13895
|
{
|
|
13848
13896
|
name: "dispatch_ask",
|
|
13897
|
+
example: { issue: "DSP-1", question: "Ship this?" },
|
|
13849
13898
|
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}`,
|
|
13850
13899
|
arguments: (z) => ({
|
|
13851
13900
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -13869,6 +13918,10 @@ var dispatchToolSpecs = [
|
|
|
13869
13918
|
},
|
|
13870
13919
|
{
|
|
13871
13920
|
name: "dispatch_edit_ask",
|
|
13921
|
+
example: {
|
|
13922
|
+
ask: "01234567-0000-4000-8000-000000000001",
|
|
13923
|
+
question: "Ship the revised plan?"
|
|
13924
|
+
},
|
|
13872
13925
|
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.",
|
|
13873
13926
|
arguments: (z) => ({
|
|
13874
13927
|
ask: z.string().describe("Ask id to edit."),
|
|
@@ -13890,6 +13943,11 @@ var dispatchToolSpecs = [
|
|
|
13890
13943
|
},
|
|
13891
13944
|
{
|
|
13892
13945
|
name: "dispatch_resolve_ask",
|
|
13946
|
+
example: {
|
|
13947
|
+
ask: "01234567-0000-4000-8000-000000000001",
|
|
13948
|
+
kind: "retracted",
|
|
13949
|
+
reason: "A newer question supersedes this one."
|
|
13950
|
+
},
|
|
13893
13951
|
description: "Retract an open question that is moot or resolve one after finding the answer. This closes the question without answering it.",
|
|
13894
13952
|
arguments: (z) => ({
|
|
13895
13953
|
ask: z.string().describe("Ask id to close."),
|
|
@@ -13899,6 +13957,7 @@ var dispatchToolSpecs = [
|
|
|
13899
13957
|
},
|
|
13900
13958
|
{
|
|
13901
13959
|
name: "dispatch_resolve_comment",
|
|
13960
|
+
example: { comment: "01234567-0000-4000-8000-000000000001" },
|
|
13902
13961
|
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.",
|
|
13903
13962
|
arguments: (z) => ({
|
|
13904
13963
|
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.")
|
|
@@ -13907,6 +13966,7 @@ var dispatchToolSpecs = [
|
|
|
13907
13966
|
},
|
|
13908
13967
|
{
|
|
13909
13968
|
name: "dispatch_follow",
|
|
13969
|
+
example: { ask: "01234567-0000-4000-8000-000000000001", action: "follow" },
|
|
13910
13970
|
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>.>",
|
|
13911
13971
|
arguments: (z) => ({
|
|
13912
13972
|
ask: z.string().describe("Full ask id (uuid)."),
|
|
@@ -13916,6 +13976,7 @@ var dispatchToolSpecs = [
|
|
|
13916
13976
|
},
|
|
13917
13977
|
{
|
|
13918
13978
|
name: "dispatch_comment",
|
|
13979
|
+
example: { issue: "DSP-1", body: "Looks good." },
|
|
13919
13980
|
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}`,
|
|
13920
13981
|
arguments: (z) => ({
|
|
13921
13982
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -13933,6 +13994,12 @@ var dispatchToolSpecs = [
|
|
|
13933
13994
|
},
|
|
13934
13995
|
{
|
|
13935
13996
|
name: "dispatch_suggest",
|
|
13997
|
+
example: {
|
|
13998
|
+
issue: "DSP-1",
|
|
13999
|
+
artifact: "spec",
|
|
14000
|
+
quote: "old wording",
|
|
14001
|
+
replace_with: "new wording"
|
|
14002
|
+
},
|
|
13936
14003
|
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}`,
|
|
13937
14004
|
arguments: (z) => ({
|
|
13938
14005
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -13948,6 +14015,7 @@ var dispatchToolSpecs = [
|
|
|
13948
14015
|
},
|
|
13949
14016
|
{
|
|
13950
14017
|
name: "dispatch_message",
|
|
14018
|
+
example: { issue: "DSP-1", body: "Implementation started." },
|
|
13951
14019
|
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}`,
|
|
13952
14020
|
arguments: (z) => ({
|
|
13953
14021
|
issue: z.string().describe(ISSUE_REFERENCE),
|
|
@@ -13957,6 +14025,11 @@ var dispatchToolSpecs = [
|
|
|
13957
14025
|
},
|
|
13958
14026
|
{
|
|
13959
14027
|
name: "dispatch_doc_edit",
|
|
14028
|
+
example: {
|
|
14029
|
+
issue: "DSP-1",
|
|
14030
|
+
artifact: "spec",
|
|
14031
|
+
ops: [{ op: "replace", find: "old", with: "new" }]
|
|
14032
|
+
},
|
|
13960
14033
|
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}`,
|
|
13961
14034
|
arguments: (z) => ({
|
|
13962
14035
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -13981,6 +14054,7 @@ var dispatchToolSpecs = [
|
|
|
13981
14054
|
},
|
|
13982
14055
|
{
|
|
13983
14056
|
name: "dispatch_doc_read",
|
|
14057
|
+
example: { issue: "DSP-1" },
|
|
13984
14058
|
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,
|
|
13985
14059
|
arguments: (z) => ({
|
|
13986
14060
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -13993,6 +14067,7 @@ var dispatchToolSpecs = [
|
|
|
13993
14067
|
},
|
|
13994
14068
|
{
|
|
13995
14069
|
name: "dispatch_request_approval",
|
|
14070
|
+
example: { issue: "DSP-1" },
|
|
13996
14071
|
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,
|
|
13997
14072
|
arguments: (z) => ({
|
|
13998
14073
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -14003,6 +14078,8 @@ var dispatchToolSpecs = [
|
|
|
14003
14078
|
},
|
|
14004
14079
|
{
|
|
14005
14080
|
name: "dispatch_artifact",
|
|
14081
|
+
example: { issue: "DSP-1", name: "design.md", content: `# Design
|
|
14082
|
+
` },
|
|
14006
14083
|
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}`,
|
|
14007
14084
|
arguments: (z) => ({
|
|
14008
14085
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -14022,6 +14099,7 @@ var dispatchToolSpecs = [
|
|
|
14022
14099
|
},
|
|
14023
14100
|
{
|
|
14024
14101
|
name: "dispatch_read",
|
|
14102
|
+
example: { issue: "DSP-1" },
|
|
14025
14103
|
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,
|
|
14026
14104
|
arguments: (z) => ({
|
|
14027
14105
|
issue: z.string().describe(ISSUE_REFERENCE).optional(),
|
|
@@ -14033,6 +14111,7 @@ var dispatchToolSpecs = [
|
|
|
14033
14111
|
},
|
|
14034
14112
|
{
|
|
14035
14113
|
name: "dispatch_search",
|
|
14114
|
+
example: { query: "astrolabe" },
|
|
14036
14115
|
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.',
|
|
14037
14116
|
arguments: (z) => ({
|
|
14038
14117
|
query: z.string({ min: 2 }).describe("Keyword, phrase, or websearch expression; at least 2 characters."),
|
|
@@ -14042,6 +14121,7 @@ var dispatchToolSpecs = [
|
|
|
14042
14121
|
},
|
|
14043
14122
|
{
|
|
14044
14123
|
name: "dispatch_issues",
|
|
14124
|
+
example: { project: "AGENTC" },
|
|
14045
14125
|
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.",
|
|
14046
14126
|
arguments: (z) => ({
|
|
14047
14127
|
project: z.string().describe("Project key to list issues from."),
|
|
@@ -14054,6 +14134,7 @@ var dispatchToolSpecs = [
|
|
|
14054
14134
|
},
|
|
14055
14135
|
{
|
|
14056
14136
|
name: "dispatch_architecture_sync",
|
|
14137
|
+
example: { project: "CORE" },
|
|
14057
14138
|
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.",
|
|
14058
14139
|
arguments: (z) => ({
|
|
14059
14140
|
project: z.string().describe("Project key whose architecture source to sync, such as CORE.")
|
|
@@ -14062,6 +14143,7 @@ var dispatchToolSpecs = [
|
|
|
14062
14143
|
},
|
|
14063
14144
|
{
|
|
14064
14145
|
name: "dispatch_open_asks",
|
|
14146
|
+
example: {},
|
|
14065
14147
|
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.",
|
|
14066
14148
|
arguments: (z) => ({
|
|
14067
14149
|
project: z.string().describe("Project key; when supplied, lists every open ask in the project instead of only this session's own.").optional()
|
|
@@ -14070,6 +14152,7 @@ var dispatchToolSpecs = [
|
|
|
14070
14152
|
},
|
|
14071
14153
|
{
|
|
14072
14154
|
name: "dispatch_whoami",
|
|
14155
|
+
example: {},
|
|
14073
14156
|
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.",
|
|
14074
14157
|
arguments: () => ({}),
|
|
14075
14158
|
strict: true
|
|
@@ -15172,9 +15255,11 @@ class ToolInputError extends Error {
|
|
|
15172
15255
|
problems;
|
|
15173
15256
|
constructor(tool, problems) {
|
|
15174
15257
|
const count = problems.length;
|
|
15258
|
+
const help = dispatchInputHelp(tool);
|
|
15175
15259
|
super([
|
|
15176
15260
|
`${tool} was not called: ${count} problem${count === 1 ? "" : "s"}`,
|
|
15177
|
-
...problems.map((problem) => `- ${problem}`)
|
|
15261
|
+
...problems.map((problem) => `- ${problem}`),
|
|
15262
|
+
...help === undefined ? [] : help.map((line) => `- ${line}`)
|
|
15178
15263
|
].join(`
|
|
15179
15264
|
`));
|
|
15180
15265
|
this.name = "ToolInputError";
|
|
@@ -15182,6 +15267,14 @@ class ToolInputError extends Error {
|
|
|
15182
15267
|
this.problems = problems;
|
|
15183
15268
|
}
|
|
15184
15269
|
}
|
|
15270
|
+
function dispatchInputHelp(tool) {
|
|
15271
|
+
const spec = dispatchToolSpecs.find((candidate) => candidate.name === tool);
|
|
15272
|
+
if (spec === undefined)
|
|
15273
|
+
return;
|
|
15274
|
+
const schema = dispatchToolSchema(spec, zodSchemaApi(exports_external), { strict: true });
|
|
15275
|
+
const allowed = Object.keys(shapeOf(schema) ?? {}).join(", ") || "none";
|
|
15276
|
+
return [`Allowed keys: ${allowed}`, `Example: ${tool}(${JSON.stringify(spec.example)})`];
|
|
15277
|
+
}
|
|
15185
15278
|
function unwrap(schema) {
|
|
15186
15279
|
let current = schema;
|
|
15187
15280
|
while (current !== undefined) {
|
|
@@ -15486,7 +15579,21 @@ function refTarget(ref, kind, id) {
|
|
|
15486
15579
|
const ownerRef = ref.owner.kind === "issue" ? dispatchIssueRef(ref.owner.issue) : dispatchDocumentRef(ref.owner.project, `${ref.artifact}`);
|
|
15487
15580
|
return dispatchChildRef(ownerRef, kind, id);
|
|
15488
15581
|
}
|
|
15489
|
-
var
|
|
15582
|
+
var canonicalUUIDPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
15583
|
+
var compactUUIDPattern = /^[0-9a-f]{32}$/i;
|
|
15584
|
+
function normalizeUUID(value) {
|
|
15585
|
+
let compact = value;
|
|
15586
|
+
if (value.slice(0, 9).toLowerCase() === "urn:uuid:") {
|
|
15587
|
+
compact = value.slice(9);
|
|
15588
|
+
} else if (value.length === 38 && value.startsWith("{") && value.endsWith("}")) {
|
|
15589
|
+
compact = value.slice(1, -1);
|
|
15590
|
+
}
|
|
15591
|
+
if (canonicalUUIDPattern.test(compact))
|
|
15592
|
+
compact = compact.replaceAll("-", "");
|
|
15593
|
+
if (!compactUUIDPattern.test(compact))
|
|
15594
|
+
return;
|
|
15595
|
+
return `${compact.slice(0, 8)}-${compact.slice(8, 12)}-${compact.slice(12, 16)}-${compact.slice(16, 20)}-${compact.slice(20)}`.toLowerCase();
|
|
15596
|
+
}
|
|
15490
15597
|
var askIdProblem = "ask must be a bare ask id or a dispatch://.../ask/<id> reference";
|
|
15491
15598
|
var commentIdProblem = "comment must be a bare comment id or a dispatch://.../comment/<id> reference";
|
|
15492
15599
|
var messageIdProblem = "in_reply_to must be a full message id (uuid) or a dispatch://KEY/message/<id> reference";
|
|
@@ -15499,12 +15606,13 @@ function messageIdOf(value) {
|
|
|
15499
15606
|
const reference = parseDispatchRef(value);
|
|
15500
15607
|
return reference?.kind === "message" ? reference.id : undefined;
|
|
15501
15608
|
})() : value;
|
|
15502
|
-
return id
|
|
15609
|
+
return id === undefined ? undefined : normalizeUUID(id);
|
|
15503
15610
|
}
|
|
15504
15611
|
var idPrefixPattern = /^[0-9a-f][0-9a-f-]{7,}$/i;
|
|
15505
15612
|
async function resolveIdPrefix(tool, kind, ref, list) {
|
|
15506
|
-
|
|
15507
|
-
|
|
15613
|
+
const fullID = normalizeUUID(ref.id);
|
|
15614
|
+
if (fullID !== undefined)
|
|
15615
|
+
return fullID;
|
|
15508
15616
|
const ownerName = ref.owner.kind === "issue" ? ref.owner.issue : `${ref.owner.project}/${ref.artifact}`;
|
|
15509
15617
|
if (!idPrefixPattern.test(ref.id)) {
|
|
15510
15618
|
throw new ToolInputError(tool, [
|
|
@@ -15736,21 +15844,53 @@ async function resolveArtifact(client, owner, artifactReference) {
|
|
|
15736
15844
|
return { owner, artifact };
|
|
15737
15845
|
const names = artifacts.filter((candidate) => candidate.name === artifactReference);
|
|
15738
15846
|
if (names.length > 1) {
|
|
15739
|
-
throw new Error(
|
|
15847
|
+
throw new Error(documentReferenceProblem(artifactReference, names, "project", true));
|
|
15848
|
+
}
|
|
15849
|
+
if (names[0] === undefined) {
|
|
15850
|
+
throw new Error(documentReferenceProblem(artifactReference, artifacts, "project"));
|
|
15740
15851
|
}
|
|
15741
|
-
if (names[0] === undefined)
|
|
15742
|
-
throw error;
|
|
15743
15852
|
return { owner, artifact: names[0] };
|
|
15744
15853
|
}
|
|
15745
15854
|
}
|
|
15746
15855
|
const issue = await client.getIssue(owner.issue);
|
|
15747
|
-
|
|
15856
|
+
let artifact;
|
|
15857
|
+
if (artifactReference === undefined || artifactReference === "spec") {
|
|
15858
|
+
artifact = issue.artifacts.find((candidate) => candidate.primary || candidate.id === issue.primary_artifact_id);
|
|
15859
|
+
} else {
|
|
15860
|
+
artifact = issue.artifacts.find((candidate) => candidate.id === artifactReference || candidate.slug === artifactReference);
|
|
15861
|
+
if (artifact === undefined) {
|
|
15862
|
+
const names = issue.artifacts.filter((candidate) => candidate.name === artifactReference);
|
|
15863
|
+
if (names.length > 1) {
|
|
15864
|
+
throw new Error(documentReferenceProblem(artifactReference, names, "issue", true));
|
|
15865
|
+
}
|
|
15866
|
+
artifact = names[0];
|
|
15867
|
+
}
|
|
15868
|
+
}
|
|
15748
15869
|
if (!artifact) {
|
|
15749
|
-
|
|
15750
|
-
throw new Error(`artifact "${artifactReference ?? "spec"}" was not found on issue ${issue.key}; artifacts: ${slugs.length === 0 ? "none" : slugs.join(", ")}`);
|
|
15870
|
+
throw new Error(documentReferenceProblem(artifactReference ?? "spec", issue.artifacts, "issue"));
|
|
15751
15871
|
}
|
|
15752
15872
|
return { owner, issue, artifact };
|
|
15753
15873
|
}
|
|
15874
|
+
var documentHintLimit = 8;
|
|
15875
|
+
function documentReferenceProblem(reference, documents, owner, ambiguous = false) {
|
|
15876
|
+
const hints = documents.slice(0, documentHintLimit).map((document) => `${document.slug} (${document.name})`);
|
|
15877
|
+
const list = hints.length === 0 ? "none" : hints.join(", ");
|
|
15878
|
+
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}`;
|
|
15879
|
+
}
|
|
15880
|
+
var askHintLimit = 8;
|
|
15881
|
+
function askIDInputProblem(asks, scope) {
|
|
15882
|
+
const hints = asks.slice(0, askHintLimit).map((ask) => `${ask.id.slice(0, 8)}\u2026 ${textHead(ask.question)}`);
|
|
15883
|
+
return `ask IDs are UUIDs; use the full ask ID; ${scope} open asks: ${hints.length === 0 ? "none" : hints.join(", ")}`;
|
|
15884
|
+
}
|
|
15885
|
+
async function invalidReplyToAskProblem(client, owner, resolved) {
|
|
15886
|
+
if (owner.kind === "issue") {
|
|
15887
|
+
const issue = resolved?.issue ?? await client.getIssue(owner.issue);
|
|
15888
|
+
return askIDInputProblem(issue.open_asks, "this issue's");
|
|
15889
|
+
}
|
|
15890
|
+
if (resolved === undefined)
|
|
15891
|
+
throw new Error("project document is missing its resolved artifact");
|
|
15892
|
+
return askIDInputProblem(await client.getArtifactAsks(resolved.artifact.id, "open"), "this document's");
|
|
15893
|
+
}
|
|
15754
15894
|
function anchor(artifact, args) {
|
|
15755
15895
|
const quote = optionalString(args, "quote");
|
|
15756
15896
|
if (quote === undefined)
|
|
@@ -16354,7 +16494,13 @@ ${followsAsk(askOwner)}`,
|
|
|
16354
16494
|
const resolved = owner.kind === "project" || artifactReference === undefined ? owner.kind === "project" ? await resolveArtifact(client, owner, artifactReference) : undefined : await resolveArtifact(client, owner, artifactReference);
|
|
16355
16495
|
const anchored = resolved ? anchor(resolved.artifact, args) : undefined;
|
|
16356
16496
|
const replyTo = optionalString(args, "reply_to");
|
|
16357
|
-
const
|
|
16497
|
+
const replyToAskReference = optionalString(args, "reply_to_ask");
|
|
16498
|
+
const replyToAsk = replyToAskReference === undefined ? undefined : normalizeUUID(replyToAskReference);
|
|
16499
|
+
if (replyToAskReference !== undefined && replyToAsk === undefined) {
|
|
16500
|
+
throw new ToolInputError(input.tool, [
|
|
16501
|
+
await invalidReplyToAskProblem(client, owner, resolved)
|
|
16502
|
+
]);
|
|
16503
|
+
}
|
|
16358
16504
|
const requestedTurn = optionalString(args, "turn");
|
|
16359
16505
|
const commentInput = {
|
|
16360
16506
|
body: stringArg(args, "body"),
|