@sjawhar/pi-envoy 10.16.0 → 10.17.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/dispatch.js
CHANGED
|
@@ -14000,7 +14000,7 @@ function imagesArgument(z2, owner, cap) {
|
|
|
14000
14000
|
}
|
|
14001
14001
|
var ASK_URGENCIES = ["low", "med", "high", "blocking"];
|
|
14002
14002
|
var ASK_QUESTION_MAX = 800;
|
|
14003
|
-
var DISPATCH_BODY_MAX =
|
|
14003
|
+
var DISPATCH_BODY_MAX = 32000;
|
|
14004
14004
|
var SEARCH_QUERY_MAX = 1000;
|
|
14005
14005
|
var SEARCH_QUERY_HINT = "search with a short phrase of a few words, not a passage";
|
|
14006
14006
|
var SEARCH_KIND_DEPTH = 100;
|
|
@@ -14058,7 +14058,7 @@ var dispatchToolSpecs = [
|
|
|
14058
14058
|
arguments: (z2) => ({
|
|
14059
14059
|
issue: z2.string().describe(ISSUE_REFERENCE),
|
|
14060
14060
|
status: z2.enum(ISSUE_STATUSES).describe("New lifecycle status.").optional(),
|
|
14061
|
-
reason: z2.string({ max:
|
|
14061
|
+
reason: z2.string({ max: DISPATCH_BODY_MAX }).describe(`Required with status done, and only with it: why the issue is closing, at most ${DISPATCH_BODY_MAX} characters. Posted on the issue as a message before it closes.`).optional(),
|
|
14062
14062
|
title: z2.string({ min: 1, max: ISSUE_TITLE_MAX }).describe("Replacement title, at most 1,000 characters.").optional(),
|
|
14063
14063
|
labels: z2.array(z2.string({ min: 1, max: 40 }), { max: 20 }).describe("Replacement label set, at most 20 labels of up to 40 characters; replaces every existing label.").optional(),
|
|
14064
14064
|
priority: z2.number({ int: true, min: 0, max: 3 }).nullable().optional().describe("Coarse priority: 0 is P0 (highest) through 3 is P3 (lowest); null clears it."),
|
|
@@ -14198,7 +14198,7 @@ var dispatchToolSpecs = [
|
|
|
14198
14198
|
{
|
|
14199
14199
|
name: "dispatch_comment",
|
|
14200
14200
|
example: { issue: "DSP-1", body: "Looks good." },
|
|
14201
|
-
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
|
|
14201
|
+
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 ${DISPATCH_BODY_MAX} characters, the lines images appends included. ${OWNER_REFERENCE}`,
|
|
14202
14202
|
arguments: (z2) => ({
|
|
14203
14203
|
issue: z2.string().describe(ISSUE_REFERENCE).optional(),
|
|
14204
14204
|
project: z2.string().describe("Project key owning the document.").optional(),
|
|
@@ -14206,11 +14206,11 @@ var dispatchToolSpecs = [
|
|
|
14206
14206
|
ref: z2.string().describe("Optional dispatch:// issue or document reference.").optional(),
|
|
14207
14207
|
quote: z2.string().describe("Optional exact quoted document text.").optional(),
|
|
14208
14208
|
occurrence: z2.number({ int: true, min: 0 }).describe("Optional zero-based occurrence of quote.").optional(),
|
|
14209
|
-
body: z2.string({ max: DISPATCH_BODY_MAX }).describe(
|
|
14209
|
+
body: z2.string({ max: DISPATCH_BODY_MAX }).describe(`Review comment, at most ${DISPATCH_BODY_MAX} characters.`),
|
|
14210
14210
|
reply_to: z2.string().describe("A comment id (uuid); replying to any comment in a thread continues that thread (an " + "ask's clarification thread included). To reply to an ask, use reply_to_ask with the " + "ask id instead.").optional(),
|
|
14211
14211
|
reply_to_ask: z2.string().describe("Optional ask id to reply to, threading this comment under that question. Mutually " + "exclusive with reply_to.").optional(),
|
|
14212
14212
|
turn: z2.enum(["agent", "human"]).describe("Only with reply_to_ask: who holds the turn after this reply. agent: a progress note - " + "you keep the turn and the ask stays 'Waiting on agents' for the human; human (default): " + "you need the human to act - the ask returns to 'Waiting on you'.").optional(),
|
|
14213
|
-
images: imagesArgument(z2, "the issue (or the project document's project)",
|
|
14213
|
+
images: imagesArgument(z2, "the issue (or the project document's project)", `the ${DISPATCH_BODY_MAX}-character body limit`)
|
|
14214
14214
|
}),
|
|
14215
14215
|
validation: commentValidation
|
|
14216
14216
|
},
|
|
@@ -14222,7 +14222,7 @@ var dispatchToolSpecs = [
|
|
|
14222
14222
|
quote: "old wording",
|
|
14223
14223
|
replace_with: "new wording"
|
|
14224
14224
|
},
|
|
14225
|
-
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
|
|
14225
|
+
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 ${DISPATCH_BODY_MAX} characters. ${OWNER_REFERENCE}`,
|
|
14226
14226
|
arguments: (z2) => ({
|
|
14227
14227
|
issue: z2.string().describe(ISSUE_REFERENCE).optional(),
|
|
14228
14228
|
project: z2.string().describe("Project key owning the document.").optional(),
|
|
@@ -14230,7 +14230,7 @@ var dispatchToolSpecs = [
|
|
|
14230
14230
|
ref: z2.string().describe("Optional dispatch:// issue or document reference.").optional(),
|
|
14231
14231
|
quote: z2.string().describe("Exact document text to replace."),
|
|
14232
14232
|
replace_with: z2.string().describe("Replacement text; a CR LF or a lone carriage return in it is written as a line feed."),
|
|
14233
|
-
body: z2.string({ max:
|
|
14233
|
+
body: z2.string({ max: DISPATCH_BODY_MAX }).describe(`Optional rationale, at most ${DISPATCH_BODY_MAX} characters.`).optional(),
|
|
14234
14234
|
occurrence: z2.number({ int: true, min: 0 }).describe("Optional zero-based occurrence of quote.").optional()
|
|
14235
14235
|
}),
|
|
14236
14236
|
validation: documentOwnerValidation(true, true)
|
|
@@ -14238,12 +14238,12 @@ var dispatchToolSpecs = [
|
|
|
14238
14238
|
{
|
|
14239
14239
|
name: "dispatch_message",
|
|
14240
14240
|
example: { issue: "DSP-1", body: "Implementation started." },
|
|
14241
|
-
description: "Post a note humans must read now: a reply to a human's message or a deliverable that landed. A to-do only a human can " + "complete is an ask (dispatch ask), so it reaches their inbox. Never progress or status updates - Dispatch is a high-signal " + "record, not a log. Not a design decision (write it as a decision block in the document) or document feedback (dispatch comment). " + "To answer a human's direct message to this session - one sent from the Agents page, which names no issue - pass that message's bare id as " + "in_reply_to and no issue; the reply lands in that conversation. Another call with the same in_reply_to and new text posts a follow-up, " + "threaded under this session's first reply; the same text again posts nothing. dispatch read --message <id> reads " + "that conversation back. Every other message names its issue. " + `Body is at most
|
|
14241
|
+
description: "Post a note humans must read now: a reply to a human's message or a deliverable that landed. A to-do only a human can " + "complete is an ask (dispatch ask), so it reaches their inbox. Never progress or status updates - Dispatch is a high-signal " + "record, not a log. Not a design decision (write it as a decision block in the document) or document feedback (dispatch comment). " + "To answer a human's direct message to this session - one sent from the Agents page, which names no issue - pass that message's bare id as " + "in_reply_to and no issue; the reply lands in that conversation. Another call with the same in_reply_to and new text posts a follow-up, " + "threaded under this session's first reply; the same text again posts nothing. dispatch read --message <id> reads " + "that conversation back. Every other message names its issue. " + `Body is at most ${DISPATCH_BODY_MAX} characters, the lines images appends included. ${ISSUE_REFERENCE}`,
|
|
14242
14242
|
arguments: (z2) => ({
|
|
14243
14243
|
issue: z2.string().describe(`${ISSUE_REFERENCE} Omit it only when in_reply_to answers a human's direct message to this session.`).optional(),
|
|
14244
|
-
body: z2.string({ max: DISPATCH_BODY_MAX }).describe(
|
|
14244
|
+
body: z2.string({ max: DISPATCH_BODY_MAX }).describe(`Update text, at most ${DISPATCH_BODY_MAX} characters.`),
|
|
14245
14245
|
in_reply_to: z2.string().describe("Optional message id or dispatch://KEY/message/<id> reference to reply to, threading " + "this message under it so the reply stays with the original in the Conversation. " + "A bare id with no issue answers a human's direct message to this session; a " + "dispatch://KEY/message/<id> names the issue its message lives on, so that form is a " + "reply on that issue.").optional(),
|
|
14246
|
-
images: imagesArgument(z2, "the issue (a reply to a direct message: your own conversation, dispatch://agent/<your session id>)",
|
|
14246
|
+
images: imagesArgument(z2, "the issue (a reply to a direct message: your own conversation, dispatch://agent/<your session id>)", `the ${DISPATCH_BODY_MAX}-character body limit`)
|
|
14247
14247
|
}),
|
|
14248
14248
|
validation: messageValidation
|
|
14249
14249
|
},
|
|
@@ -14335,11 +14335,11 @@ var dispatchToolSpecs = [
|
|
|
14335
14335
|
{
|
|
14336
14336
|
name: "dispatch_read",
|
|
14337
14337
|
example: { issue: "DSP-1" },
|
|
14338
|
-
description: "Read an issue or
|
|
14338
|
+
description: "Read an issue or document summary, targeted ask, or targeted comment reply chain, or the conversation " + "a message belongs to. Do not use it for document contents; use dispatch doc-read instead. Supply ref, issue, " + "issue plus artifact (one of its documents), or project plus artifact; or message alone, which reads a human's direct message to this session and every " + "reply to it (they belong to no issue). A document summary names its issue, reference, versions and approval. " + "An anchored comment or ask also says where its quote sits, as `Position:`: the block's path from the top, " + "and in a table the row (0 is the header), the cells before the anchored one, and the column's header; " + "`Position: unavailable (<code>)` when Dispatch could not read the document: `DOC_SERVICE_UNAVAILABLE` " + "(try again shortly), `DOC_SCHEMA` (the document needs repair), `DOCUMENT_UNLOADABLE` (the document " + "needs a rebuild) or `INTERNAL`. " + "An issue read carries a `Progress:` line, `tasks 3/7, children 2/5`: its spec's task-list items " + "(`- [ ]` / `- [x]`, nested lists included) and its direct children, each done of total and each only " + "when it has any (`Progress: none` otherwise). " + "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. " + "The pictures the shown messages, asks and comments embed come back as images you see, newest first, at most 8 " + "and 10 MiB of them per read, each a PNG, JPEG, GIF or WebP of at most 3,750,000 bytes (5 MB of base64); a `Pictures:` section names each " + "one shown, in order, and the rest by reference, for dispatch doc-read. A picture this session was already shown is named, not sent again " + "(every request carries the session's history, and the provider refuses one over 32 MB); dispatch doc-read shows it again. " + OWNER_REFERENCE,
|
|
14339
14339
|
arguments: (z2) => ({
|
|
14340
14340
|
issue: z2.string().describe(ISSUE_REFERENCE).optional(),
|
|
14341
14341
|
project: z2.string().describe("Project key owning the document.").optional(),
|
|
14342
|
-
artifact: z2.string().describe("
|
|
14342
|
+
artifact: z2.string().describe("Document artifact id, slug, or filename: one of the issue's, or a project document.").optional(),
|
|
14343
14343
|
ref: z2.string().describe("Optional dispatch:// issue or document reference.").optional(),
|
|
14344
14344
|
message: z2.string().describe("A message id (uuid): reads the conversation it belongs to, the root message and every " + "reply. Name nothing else with it.").optional()
|
|
14345
14345
|
}),
|
|
@@ -15585,6 +15585,8 @@ function parseDispatchRef(ref) {
|
|
|
15585
15585
|
...version3 === undefined ? {} : { version: Number(version3) }
|
|
15586
15586
|
};
|
|
15587
15587
|
}
|
|
15588
|
+
if (version3 !== undefined)
|
|
15589
|
+
return null;
|
|
15588
15590
|
if (targetID === undefined || targetKind !== "ask" && targetKind !== "comment")
|
|
15589
15591
|
return null;
|
|
15590
15592
|
return {
|
|
@@ -16455,7 +16457,27 @@ function messageIdOf(value) {
|
|
|
16455
16457
|
}
|
|
16456
16458
|
var idPrefixPattern = /^[0-9a-f][0-9a-f-]{7,}$/i;
|
|
16457
16459
|
function refOwnerName(ref) {
|
|
16458
|
-
return ref.owner.kind === "issue" ? ref.owner.issue : `${ref.owner.project}/${ref.artifact}`;
|
|
16460
|
+
return ref.owner.kind === "issue" ? ref.owner.issue : `${ref.owner.project}/${ref.artifact ?? ref.id}`;
|
|
16461
|
+
}
|
|
16462
|
+
async function refuseItemOffRef(tool, kind, ref, refText, item, documentId) {
|
|
16463
|
+
if (ref.owner.kind === "issue") {
|
|
16464
|
+
if (item.issue_key === ref.owner.issue)
|
|
16465
|
+
return;
|
|
16466
|
+
} else if (item.issue_key === null) {
|
|
16467
|
+
const id = await documentId();
|
|
16468
|
+
if ([
|
|
16469
|
+
item.artifact_id,
|
|
16470
|
+
item.anchor?.artifact_id,
|
|
16471
|
+
item.block_artifact?.id,
|
|
16472
|
+
item.approval?.artifact_id
|
|
16473
|
+
].includes(id)) {
|
|
16474
|
+
return;
|
|
16475
|
+
}
|
|
16476
|
+
}
|
|
16477
|
+
const where = item.issue_key === null ? "another document" : `${item.issue_key}; name it dispatch://${item.issue_key}/${kind}/${item.id}`;
|
|
16478
|
+
throw new ToolInputError(tool, [
|
|
16479
|
+
`${refText} names ${kind} ${item.id} on ${refOwnerName(ref)}, but it is on ${where}`
|
|
16480
|
+
]);
|
|
16459
16481
|
}
|
|
16460
16482
|
async function resolveIdPrefix(tool, kind, id, ownerName, list) {
|
|
16461
16483
|
const fullID = normalizeUUID(id);
|
|
@@ -16528,7 +16550,17 @@ async function resolveAskArgument(tool, args, client, sessionId) {
|
|
|
16528
16550
|
asks === undefined ? askIdShapeProblem : `${askIdShapeProblem}; ${openAskHints(asks)}`
|
|
16529
16551
|
]);
|
|
16530
16552
|
}
|
|
16531
|
-
|
|
16553
|
+
const resolved = await resolveIdPrefix(tool, "ask", id, "this session", () => sessionOpenAsks(client, sessionId));
|
|
16554
|
+
const reference = stringArg(args, "ask");
|
|
16555
|
+
const ref = reference.startsWith("dispatch://") ? parseDispatchRef(reference) : null;
|
|
16556
|
+
if (ref === null)
|
|
16557
|
+
return { id: resolved };
|
|
16558
|
+
const read = await client.getAsk(resolved);
|
|
16559
|
+
await refuseItemOffRef(tool, "ask", ref, reference, read.ask, async () => {
|
|
16560
|
+
const document = await resolveArtifact(client, ref.owner, ref.artifact, { canonical: true });
|
|
16561
|
+
return document.artifact.id;
|
|
16562
|
+
});
|
|
16563
|
+
return { id: resolved, read };
|
|
16532
16564
|
}
|
|
16533
16565
|
function messageInReplyTo(args) {
|
|
16534
16566
|
const inReplyTo = optionalString(args, "in_reply_to");
|
|
@@ -16552,14 +16584,14 @@ function argumentProblems(tool, args) {
|
|
|
16552
16584
|
case "dispatch_follow": {
|
|
16553
16585
|
const ask = optionalString(args, "ask");
|
|
16554
16586
|
if (ask?.startsWith("dispatch://") && parseDispatchRef(ask)?.kind !== "ask") {
|
|
16555
|
-
problems.push(askIdProblem);
|
|
16587
|
+
problems.push(itemRefProblem(ask) ?? askIdProblem);
|
|
16556
16588
|
}
|
|
16557
16589
|
break;
|
|
16558
16590
|
}
|
|
16559
16591
|
case "dispatch_resolve_comment": {
|
|
16560
16592
|
const comment = optionalString(args, "comment");
|
|
16561
16593
|
if (comment?.startsWith("dispatch://") && parseDispatchRef(comment)?.kind !== "comment") {
|
|
16562
|
-
problems.push(commentIdProblem);
|
|
16594
|
+
problems.push(itemRefProblem(comment) ?? commentIdProblem);
|
|
16563
16595
|
}
|
|
16564
16596
|
break;
|
|
16565
16597
|
}
|
|
@@ -16649,26 +16681,96 @@ function dispatchRefFromUrl(value, serverUrl) {
|
|
|
16649
16681
|
if (!documentPage)
|
|
16650
16682
|
return;
|
|
16651
16683
|
const [, project, slug] = documentPage;
|
|
16652
|
-
const document = `dispatch://${project}/artifact/${decodeURIComponent(slug ?? "")}
|
|
16684
|
+
const document = `dispatch://${project}/artifact/${decodeURIComponent(slug ?? "")}`;
|
|
16653
16685
|
const item = itemFromSearch(url2.search);
|
|
16654
16686
|
if (item === null)
|
|
16655
16687
|
return;
|
|
16656
|
-
return item === undefined ? document : `${document}/${item.kind}/${item.id}`;
|
|
16688
|
+
return item === undefined ? `${document}${versionOf("version")}` : `${document}/${item.kind}/${item.id}`;
|
|
16657
16689
|
}
|
|
16658
16690
|
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>, " + "dispatch://PROJECT/artifact/<document-ref> (an artifact id, slug, or filename), or " + "dispatch://agent/<session id>/artifact/<slug> (a picture in a conversation on the Agents page, " + "for dispatch doc-read); a dashboard URL on this Dispatch server is accepted too";
|
|
16659
16691
|
var ownerRequiredProblem = "issue is required; supply issue or set LEGION_ISSUE";
|
|
16660
16692
|
function innerRefProblem(tool, ref, refText) {
|
|
16661
|
-
if (ref.kind !== "ask" && ref.kind !== "comment" && ref.kind !== "message")
|
|
16693
|
+
if (ref.kind !== "ask" && ref.kind !== "comment" && ref.kind !== "message" && ref.kind !== "log" && ref.kind !== "children") {
|
|
16662
16694
|
return;
|
|
16695
|
+
}
|
|
16663
16696
|
if (tool === "dispatch_read" || tool === "dispatch_ask")
|
|
16664
16697
|
return;
|
|
16665
16698
|
const owner = refOwnerName(ref);
|
|
16666
16699
|
const documentTool = tool === "dispatch_suggest" || tool === "dispatch_doc_edit";
|
|
16667
16700
|
const ownerArguments = ref.owner.kind === "issue" ? `issue ${ref.owner.issue}${documentTool ? " and artifact <the document's slug>" : ""}` : `project ${ref.owner.project} and artifact ${ref.artifact}`;
|
|
16668
16701
|
const fix = tool === "dispatch_comment" && ref.kind === "ask" ? `reply under it with reply_to_ask ${ref.id} and ${ownerArguments}` : tool === "dispatch_comment" && ref.kind === "comment" ? `reply in its thread with reply_to ${ref.id} and ${ownerArguments}` : `read it with dispatch read, or name ${owner} with ${ownerArguments}`;
|
|
16669
|
-
const item = ref.kind === "ask" ? "an ask" : `a ${ref.kind}`;
|
|
16702
|
+
const item = ref.kind === "ask" ? "an ask" : ref.kind === "log" ? "the event log" : ref.kind === "children" ? "the children" : `a ${ref.kind}`;
|
|
16670
16703
|
return `ref ${refText} names ${item} on ${owner}; dispatch ${commandName(tool)} would act on ${owner} and drop the ${ref.kind}: ${fix}`;
|
|
16671
16704
|
}
|
|
16705
|
+
var documentItemPattern = /^dispatch:\/\/([A-Z][A-Z0-9]{1,9}-[1-9][0-9]*)\/artifact\/[^/@]+(?:@v\d+)?\/(ask|comment)\/([^/]+)$/;
|
|
16706
|
+
var versionedProjectItemPattern = /^dispatch:\/\/([A-Z][A-Z0-9]{1,9})\/artifact\/([^/@]+)@v\d+\/(ask|comment)\/([^/]+)$/;
|
|
16707
|
+
function itemRefProblem(value) {
|
|
16708
|
+
const throughDocument = value.match(documentItemPattern);
|
|
16709
|
+
if (throughDocument !== null) {
|
|
16710
|
+
const [, issue2, kind, id] = throughDocument;
|
|
16711
|
+
return `${value} names ${kind === "ask" ? "an ask" : "a comment"} through its document, which Dispatch does not address; name it dispatch://${issue2}/${kind}/${id}`;
|
|
16712
|
+
}
|
|
16713
|
+
const versioned = value.match(versionedProjectItemPattern);
|
|
16714
|
+
if (versioned !== null) {
|
|
16715
|
+
const [, project, slug, kind, id] = versioned;
|
|
16716
|
+
const item = kind === "ask" ? "an ask" : "a comment";
|
|
16717
|
+
return `${value} names ${item} at a document version, which ${item} does not have; name it dispatch://${project}/artifact/${slug}/${kind}/${id}`;
|
|
16718
|
+
}
|
|
16719
|
+
return;
|
|
16720
|
+
}
|
|
16721
|
+
function ownerConflictProblems(tool, args, parsedRef, refText) {
|
|
16722
|
+
const problems = [];
|
|
16723
|
+
const command = `dispatch ${commandName(tool)}`;
|
|
16724
|
+
const issue2 = optionalString(args, "issue");
|
|
16725
|
+
const project = optionalString(args, "project");
|
|
16726
|
+
const artifact = optionalString(args, "artifact");
|
|
16727
|
+
const version2 = optionalNumber(args, "version");
|
|
16728
|
+
const ref = tool === "dispatch_ask" && (issue2 !== undefined || project !== undefined) ? null : parsedRef;
|
|
16729
|
+
const refDocument = ref === null ? undefined : ref.owner.kind === "project" ? ref.artifact ?? ref.id : ref.kind === "spec" || ref.kind === "artifact" ? ref.id : undefined;
|
|
16730
|
+
if (ref !== null && refText !== undefined) {
|
|
16731
|
+
const refOwner = refOwnerName(ref);
|
|
16732
|
+
if (issue2 !== undefined && (ref.owner.kind !== "issue" || nativeIssueKeyPattern.test(issue2) && issue2 !== ref.owner.issue)) {
|
|
16733
|
+
problems.push(`issue ${issue2} and ref ${refText} name two owners; --ref ${refText} alone acts on ${refOwner}, and --issue ${issue2} alone acts on ${issue2}`);
|
|
16734
|
+
}
|
|
16735
|
+
if (project !== undefined && ref.owner.kind === "issue") {
|
|
16736
|
+
problems.push(`project ${project} and ref ${refText} name two owners; --ref ${refText} alone acts on ${refOwner}, and --project ${project}${artifact === undefined ? "" : ` --artifact ${artifact}`} alone acts on that project document`);
|
|
16737
|
+
}
|
|
16738
|
+
if (tool !== "dispatch_ask" && project === undefined && artifact !== undefined && refDocument !== undefined && artifact !== refDocument) {
|
|
16739
|
+
const owner = ref.owner.kind === "issue" ? `--issue ${ref.owner.issue}` : `--project ${ref.owner.project}`;
|
|
16740
|
+
problems.push(`artifact ${artifact} and ref ${refText} name two documents; --ref ${refText} alone names ${refDocument}, and ${owner} --artifact ${artifact} names ${artifact}`);
|
|
16741
|
+
}
|
|
16742
|
+
if (tool === "dispatch_read" && project === undefined && artifact !== undefined && ref.owner.kind === "issue" && ref.kind !== "issue" && refDocument === undefined) {
|
|
16743
|
+
problems.push(`ref ${refText} names no document, so dispatch read would read it and drop artifact ${artifact}: drop --artifact to read the ref, or read the document with --issue ${ref.owner.issue} --artifact ${artifact}`);
|
|
16744
|
+
}
|
|
16745
|
+
if (version2 !== undefined && ref.version !== undefined && version2 !== ref.version) {
|
|
16746
|
+
problems.push(`version ${version2} and ref ${refText} name two versions; name the version once`);
|
|
16747
|
+
}
|
|
16748
|
+
if (ref.version !== undefined && (tool === "dispatch_comment" || tool === "dispatch_suggest" || tool === "dispatch_doc_edit")) {
|
|
16749
|
+
problems.push(`${command} acts on the live document, so the version ref ${refText} names would be dropped: drop its @v${ref.version}`);
|
|
16750
|
+
}
|
|
16751
|
+
if (ref.version !== undefined && tool === "dispatch_read") {
|
|
16752
|
+
problems.push(`dispatch read prints the live document's summary, so the version ref ${refText} names would be dropped: read that version with dispatch doc-read --ref ${refText}`);
|
|
16753
|
+
}
|
|
16754
|
+
}
|
|
16755
|
+
const projectOwned = project !== undefined || ref?.owner.kind === "project";
|
|
16756
|
+
if (tool === "dispatch_comment" && !projectOwned && optionalString(args, "quote") === undefined) {
|
|
16757
|
+
const document = artifact ?? refDocument;
|
|
16758
|
+
if (document !== undefined) {
|
|
16759
|
+
problems.push(`${command} posts on the issue unless quote anchors it in a document, so document ${document} would be dropped: add --quote to comment on a passage of it, or name only the issue`);
|
|
16760
|
+
}
|
|
16761
|
+
}
|
|
16762
|
+
if (tool === "dispatch_ask") {
|
|
16763
|
+
const anchor = asObject(args.anchor);
|
|
16764
|
+
const anchorArtifact = anchor === null ? undefined : optionalString(anchor, "artifact");
|
|
16765
|
+
if (!projectOwned && artifact !== undefined && anchor === null) {
|
|
16766
|
+
problems.push(`${command} opens the ask on the issue unless anchor quotes a document, so artifact ${artifact} would be dropped: add --anchor-json '${JSON.stringify({ artifact, quote: "<exact text>" })}' to ask about a passage of it, or drop --artifact`);
|
|
16767
|
+
}
|
|
16768
|
+
if (artifact !== undefined && anchorArtifact !== undefined && anchorArtifact !== artifact) {
|
|
16769
|
+
problems.push(`artifact ${artifact} and anchor.artifact ${anchorArtifact} name two documents; name the document once`);
|
|
16770
|
+
}
|
|
16771
|
+
}
|
|
16772
|
+
return problems;
|
|
16773
|
+
}
|
|
16672
16774
|
var toolSchemas = new Map;
|
|
16673
16775
|
function toolSchema(tool) {
|
|
16674
16776
|
const cached2 = toolSchemas.get(tool);
|
|
@@ -16703,7 +16805,7 @@ async function resolveOwnerArguments(tool, input, cwd, env, exec, dashboardUrls,
|
|
|
16703
16805
|
}
|
|
16704
16806
|
ref = parseDispatchRef(refText);
|
|
16705
16807
|
if (ref === null) {
|
|
16706
|
-
problems.push(tool === "dispatch_ask" && !refText.startsWith("dispatch://") ? "ref must be a dispatch:// reference" : refGrammarProblem);
|
|
16808
|
+
problems.push(itemRefProblem(refText) ?? (tool === "dispatch_ask" && !refText.startsWith("dispatch://") ? "ref must be a dispatch:// reference" : refGrammarProblem));
|
|
16707
16809
|
} else {
|
|
16708
16810
|
const inner = innerRefProblem(tool, ref, refText);
|
|
16709
16811
|
if (inner !== undefined)
|
|
@@ -16713,7 +16815,9 @@ async function resolveOwnerArguments(tool, input, cwd, env, exec, dashboardUrls,
|
|
|
16713
16815
|
const issueArgument = args.issue;
|
|
16714
16816
|
const projectArgument = args.project;
|
|
16715
16817
|
const artifactArgument = args.artifact;
|
|
16716
|
-
const
|
|
16818
|
+
const versionFromRef = tool === "dispatch_doc_read" && args.version === undefined ? ref?.version : undefined;
|
|
16819
|
+
const refVersion = versionFromRef === undefined ? {} : { version: versionFromRef };
|
|
16820
|
+
const ownerRef = tool === "dispatch_ask" && (issueArgument !== undefined || projectArgument !== undefined) ? null : ref;
|
|
16717
16821
|
if (issueArgument !== undefined && projectArgument !== undefined) {
|
|
16718
16822
|
problems.push("exactly one of issue and project is required");
|
|
16719
16823
|
}
|
|
@@ -16721,45 +16825,47 @@ async function resolveOwnerArguments(tool, input, cwd, env, exec, dashboardUrls,
|
|
|
16721
16825
|
if (!PROJECT_KEY_PATTERN.test(projectArgument)) {
|
|
16722
16826
|
problems.push(`project is not a project key: ${PROJECT_KEY_RULE}`);
|
|
16723
16827
|
}
|
|
16724
|
-
const refDocument =
|
|
16725
|
-
if (
|
|
16828
|
+
const refDocument = ownerRef?.owner.kind === "project" ? ownerRef.artifact ?? ownerRef.id : undefined;
|
|
16829
|
+
if (ownerRef?.owner.kind === "project" && (ownerRef.owner.project !== projectArgument || artifactArgument !== undefined && artifactArgument !== refDocument)) {
|
|
16726
16830
|
problems.push("project and ref must name the same document");
|
|
16727
16831
|
}
|
|
16728
16832
|
return {
|
|
16729
16833
|
args: {
|
|
16730
16834
|
...args,
|
|
16731
16835
|
...artifactArgument === undefined && refDocument !== undefined ? { artifact: refDocument } : {},
|
|
16732
|
-
...
|
|
16836
|
+
...refVersion
|
|
16733
16837
|
},
|
|
16734
16838
|
ref,
|
|
16735
16839
|
owner: { kind: "project", project: projectArgument }
|
|
16736
16840
|
};
|
|
16737
16841
|
}
|
|
16738
|
-
if (
|
|
16842
|
+
if (ownerRef?.owner.kind === "project") {
|
|
16739
16843
|
return {
|
|
16740
16844
|
args: {
|
|
16741
16845
|
...args,
|
|
16742
|
-
project:
|
|
16743
|
-
...artifactArgument === undefined ? { artifact:
|
|
16744
|
-
...
|
|
16846
|
+
project: ownerRef.owner.project,
|
|
16847
|
+
...artifactArgument === undefined ? { artifact: ownerRef.artifact ?? ownerRef.id } : {},
|
|
16848
|
+
...refVersion
|
|
16745
16849
|
},
|
|
16746
16850
|
ref,
|
|
16747
|
-
owner:
|
|
16851
|
+
owner: ownerRef.owner
|
|
16748
16852
|
};
|
|
16749
16853
|
}
|
|
16750
|
-
if (issueArgument !== undefined ||
|
|
16854
|
+
if (issueArgument !== undefined || ownerRef !== null) {
|
|
16751
16855
|
const issue3 = typeof issueArgument === "string" ? canonicalExternalIssueRef(issueArgument) : ref?.owner.kind === "issue" ? ref.owner.issue : undefined;
|
|
16752
16856
|
return {
|
|
16753
16857
|
args: {
|
|
16754
16858
|
...args,
|
|
16755
16859
|
...issue3 === undefined ? {} : { issue: issue3 },
|
|
16756
|
-
...artifactArgument === undefined && (ref?.kind === "spec" || ref?.kind === "artifact") ? { artifact: ref.id } : {},
|
|
16757
|
-
...
|
|
16860
|
+
...artifactArgument === undefined && tool !== "dispatch_ask" && (ref?.kind === "spec" || ref?.kind === "artifact") ? { artifact: ref.id } : {},
|
|
16861
|
+
...refVersion
|
|
16758
16862
|
},
|
|
16759
16863
|
ref,
|
|
16760
16864
|
owner: issue3 === undefined ? null : { kind: "issue", issue: issue3 }
|
|
16761
16865
|
};
|
|
16762
16866
|
}
|
|
16867
|
+
if (typeof args.ref === "string")
|
|
16868
|
+
return { args, ref, owner: null };
|
|
16763
16869
|
const replyTarget = args.in_reply_to;
|
|
16764
16870
|
if (tool === "dispatch_message" && typeof replyTarget === "string" && !replyTarget.startsWith("dispatch://")) {
|
|
16765
16871
|
return { args, ref, owner: null };
|
|
@@ -17480,7 +17586,9 @@ async function executeDispatchTool(input) {
|
|
|
17480
17586
|
const exec = input.exec ?? defaultExec;
|
|
17481
17587
|
const problems = [];
|
|
17482
17588
|
const ownerArguments = await resolveOwnerArguments(input.tool, input.args, input.cwd, env, exec, input.config.publicUrl === undefined ? [configUrl] : [configUrl, input.config.publicUrl], problems);
|
|
17483
|
-
const
|
|
17589
|
+
const conflicts = issueFreeTools[input.tool] === true ? [] : ownerConflictProblems(input.tool, input.args, ownerArguments.ref, optionalString(ownerArguments.args, "ref"));
|
|
17590
|
+
problems.push(...conflicts);
|
|
17591
|
+
const ownerMissing = issueFreeTools[input.tool] !== true && (ownerArguments.owner === null || conflicts.length > 0);
|
|
17484
17592
|
const schema = toolSchema(input.tool);
|
|
17485
17593
|
const parsed = schema.safeParse(ownerArguments.args, { reportInput: true });
|
|
17486
17594
|
if (!parsed.success) {
|
|
@@ -17530,6 +17638,13 @@ async function executeDispatchTool(input) {
|
|
|
17530
17638
|
kind: "issue",
|
|
17531
17639
|
issue: await resolveExistingIssue(client, ownerArguments.owner.issue)
|
|
17532
17640
|
} : ownerArguments.owner;
|
|
17641
|
+
const issueArgument = optionalString(input.args, "issue");
|
|
17642
|
+
const refText = optionalString(ownerArguments.args, "ref");
|
|
17643
|
+
if (input.tool !== "dispatch_ask" && owner?.kind === "issue" && issueArgument !== undefined && refText !== undefined && ownerArguments.ref?.owner.kind === "issue" && owner.issue !== ownerArguments.ref.owner.issue) {
|
|
17644
|
+
throw new ToolInputError(input.tool, [
|
|
17645
|
+
`issue ${issueArgument} and ref ${refText} name two owners; --ref ${refText} alone acts on ${ownerArguments.ref.owner.issue}, and --issue ${issueArgument} alone acts on ${owner.issue}`
|
|
17646
|
+
]);
|
|
17647
|
+
}
|
|
17533
17648
|
const issue2 = () => {
|
|
17534
17649
|
if (owner?.kind !== "issue")
|
|
17535
17650
|
throw new Error("issue is required");
|
|
@@ -17857,7 +17972,7 @@ async function executeDispatchTool(input) {
|
|
|
17857
17972
|
}
|
|
17858
17973
|
case "dispatch_resolve_ask": {
|
|
17859
17974
|
const kind = stringArg(args, "kind");
|
|
17860
|
-
const id = await resolveAskArgument(input.tool, args, client, input.sessionId);
|
|
17975
|
+
const { id } = await resolveAskArgument(input.tool, args, client, input.sessionId);
|
|
17861
17976
|
const ask = await client.resolveAsk(id, {
|
|
17862
17977
|
kind,
|
|
17863
17978
|
reason: stringArg(args, "reason"),
|
|
@@ -17883,6 +17998,10 @@ async function executeDispatchTool(input) {
|
|
|
17883
17998
|
document = artifact;
|
|
17884
17999
|
id = await resolveIdPrefix(input.tool, "comment", ref.id, refOwnerName(ref), () => client.getArtifactComments(artifact.id));
|
|
17885
18000
|
}
|
|
18001
|
+
if (ref !== null) {
|
|
18002
|
+
const read = await client.getComment(id);
|
|
18003
|
+
await refuseItemOffRef(input.tool, "comment", ref, reference, read.comment, async () => document === undefined ? "" : document.id);
|
|
18004
|
+
}
|
|
17886
18005
|
const comment = await client.resolveComment(id, actor);
|
|
17887
18006
|
const { label, details } = await commentOwnerResult(client, comment, document);
|
|
17888
18007
|
return { text: `Resolved comment ${comment.id} on ${label}.`, details };
|
|
@@ -17935,7 +18054,7 @@ ${await followsAsk(askOwner, input.subscriptions)}`,
|
|
|
17935
18054
|
const options = args.options;
|
|
17936
18055
|
const multiple = optionalBoolean(args, "multiple");
|
|
17937
18056
|
const urgency = askUrgency(args);
|
|
17938
|
-
const id = await resolveAskArgument(input.tool, args, client, input.sessionId);
|
|
18057
|
+
const { id } = await resolveAskArgument(input.tool, args, client, input.sessionId);
|
|
17939
18058
|
const ask = await client.editAsk(id, {
|
|
17940
18059
|
...question === undefined ? {} : { question },
|
|
17941
18060
|
...Array.isArray(options) ? { options } : {},
|
|
@@ -18264,13 +18383,13 @@ ${trailer.join(`
|
|
|
18264
18383
|
const sessionId = input.sessionId?.trim();
|
|
18265
18384
|
if (!sessionId)
|
|
18266
18385
|
throw new Error("host session id is required for dispatch follow");
|
|
18267
|
-
const ask = await resolveAskArgument(input.tool, args, client, sessionId);
|
|
18386
|
+
const { id: ask, read: refRead } = await resolveAskArgument(input.tool, args, client, sessionId);
|
|
18268
18387
|
const action = stringArg(args, "action");
|
|
18269
18388
|
if (action === "unfollow") {
|
|
18270
18389
|
await client.unfollowAsk(ask, sessionId, actor);
|
|
18271
18390
|
return { text: `Unfollowed ask ${ask}.`, details: { ask } };
|
|
18272
18391
|
}
|
|
18273
|
-
const read = await client.getAsk(ask);
|
|
18392
|
+
const read = refRead ?? await client.getAsk(ask);
|
|
18274
18393
|
await client.followAsk(ask, sessionId, actor);
|
|
18275
18394
|
return {
|
|
18276
18395
|
text: `Following ask ${ask}: its answer and replies reach this session directly.`,
|
|
@@ -18304,9 +18423,15 @@ ${trailer.join(`
|
|
|
18304
18423
|
...showImages(pictures3)
|
|
18305
18424
|
};
|
|
18306
18425
|
}
|
|
18426
|
+
let refDocumentId;
|
|
18427
|
+
const documentIdOf = (ref) => {
|
|
18428
|
+
refDocumentId ??= resolveDocument(ref.owner, ref.artifact).then((resolved) => resolved.artifact.id);
|
|
18429
|
+
return refDocumentId;
|
|
18430
|
+
};
|
|
18307
18431
|
if (ownerArguments.ref?.kind === "ask") {
|
|
18308
18432
|
const ref = ownerArguments.ref;
|
|
18309
|
-
const askRead = await readAskRef(input.tool, ref.id, refOwnerName(ref), client, async () => ref.owner.kind === "issue" ? client.listIssueAsks(ref.owner.issue) : client.getArtifactAsks(
|
|
18433
|
+
const askRead = await readAskRef(input.tool, ref.id, refOwnerName(ref), client, async () => ref.owner.kind === "issue" ? client.listIssueAsks(ref.owner.issue) : client.getArtifactAsks(await documentIdOf(ref), "all"));
|
|
18434
|
+
await refuseItemOffRef(input.tool, "ask", ref, stringArg(args, "ref"), askRead.ask, () => documentIdOf(ref));
|
|
18310
18435
|
const askRef = refTarget(ref, "ask", askRead.ask.id);
|
|
18311
18436
|
const [pictures3, graph2] = await Promise.all([
|
|
18312
18437
|
picturesOf(askTexts(askRead)),
|
|
@@ -18320,8 +18445,9 @@ ${trailer.join(`
|
|
|
18320
18445
|
}
|
|
18321
18446
|
if (ownerArguments.ref?.kind === "comment") {
|
|
18322
18447
|
const ref = ownerArguments.ref;
|
|
18323
|
-
const id = await resolveIdPrefix(input.tool, "comment", ref.id, refOwnerName(ref), async () => ref.owner.kind === "issue" ? client.getComments(ref.owner.issue) : client.getArtifactComments(
|
|
18448
|
+
const id = await resolveIdPrefix(input.tool, "comment", ref.id, refOwnerName(ref), async () => ref.owner.kind === "issue" ? client.getComments(ref.owner.issue) : client.getArtifactComments(await documentIdOf(ref)));
|
|
18324
18449
|
const comment = await client.getComment(id);
|
|
18450
|
+
await refuseItemOffRef(input.tool, "comment", ref, stringArg(args, "ref"), comment.comment, () => documentIdOf(ref));
|
|
18325
18451
|
const commentRef = refTarget(ref, "comment", id);
|
|
18326
18452
|
const [pictures3, graph2] = await Promise.all([
|
|
18327
18453
|
picturesOf(datedBodies([comment.comment, ...comment.replies])),
|
|
@@ -18349,21 +18475,28 @@ ${trailer.join(`
|
|
|
18349
18475
|
...showImages(pictures3)
|
|
18350
18476
|
};
|
|
18351
18477
|
}
|
|
18352
|
-
|
|
18353
|
-
|
|
18354
|
-
const
|
|
18478
|
+
const documentReference = optionalString(args, "artifact");
|
|
18479
|
+
if (documentOwner().kind === "project" || documentReference !== undefined) {
|
|
18480
|
+
const resolved = await resolveDocument(documentOwner(), documentReference);
|
|
18481
|
+
const { artifact } = resolved;
|
|
18482
|
+
const ownerKey = resolved.issue?.key ?? artifact.project;
|
|
18483
|
+
const documentRef = dispatchDocumentRef(ownerKey, artifact.slug);
|
|
18484
|
+
const approval = approvalLine(artifact);
|
|
18355
18485
|
return {
|
|
18356
18486
|
text: [
|
|
18357
|
-
`Document: ${
|
|
18487
|
+
`Document: ${ownerKey} / ${artifact.name}`,
|
|
18488
|
+
...resolved.issue === undefined ? [] : [
|
|
18489
|
+
`Issue: ${resolved.issue.key} [${resolved.issue.status}] ${resolved.issue.title}`
|
|
18490
|
+
],
|
|
18358
18491
|
`Reference: ${documentRef}`,
|
|
18359
|
-
`Versions: ${
|
|
18360
|
-
...
|
|
18492
|
+
`Versions: ${artifact.versions.length}`,
|
|
18493
|
+
...approval === undefined ? [] : [approval],
|
|
18361
18494
|
...await graphSections(client, documentRef)
|
|
18362
18495
|
].join(`
|
|
18363
18496
|
`),
|
|
18364
18497
|
details: {
|
|
18365
|
-
project: resolved.
|
|
18366
|
-
document: documentLabel(
|
|
18498
|
+
...resolved.issue === undefined ? { project: artifact.project } : { issue: resolved.issue.key },
|
|
18499
|
+
document: documentLabel(ownerKey, artifact.slug)
|
|
18367
18500
|
}
|
|
18368
18501
|
};
|
|
18369
18502
|
}
|
package/dist/envoy.js
CHANGED
|
@@ -29987,7 +29987,7 @@ function imagesArgument(z2, owner, cap) {
|
|
|
29987
29987
|
}
|
|
29988
29988
|
var ASK_URGENCIES = ["low", "med", "high", "blocking"];
|
|
29989
29989
|
var ASK_QUESTION_MAX = 800;
|
|
29990
|
-
var DISPATCH_BODY_MAX =
|
|
29990
|
+
var DISPATCH_BODY_MAX = 32000;
|
|
29991
29991
|
var SEARCH_QUERY_MAX = 1000;
|
|
29992
29992
|
var SEARCH_QUERY_HINT = "search with a short phrase of a few words, not a passage";
|
|
29993
29993
|
var SEARCH_KIND_DEPTH = 100;
|
|
@@ -30045,7 +30045,7 @@ var dispatchToolSpecs = [
|
|
|
30045
30045
|
arguments: (z2) => ({
|
|
30046
30046
|
issue: z2.string().describe(ISSUE_REFERENCE),
|
|
30047
30047
|
status: z2.enum(ISSUE_STATUSES).describe("New lifecycle status.").optional(),
|
|
30048
|
-
reason: z2.string({ max:
|
|
30048
|
+
reason: z2.string({ max: DISPATCH_BODY_MAX }).describe(`Required with status done, and only with it: why the issue is closing, at most ${DISPATCH_BODY_MAX} characters. Posted on the issue as a message before it closes.`).optional(),
|
|
30049
30049
|
title: z2.string({ min: 1, max: ISSUE_TITLE_MAX }).describe("Replacement title, at most 1,000 characters.").optional(),
|
|
30050
30050
|
labels: z2.array(z2.string({ min: 1, max: 40 }), { max: 20 }).describe("Replacement label set, at most 20 labels of up to 40 characters; replaces every existing label.").optional(),
|
|
30051
30051
|
priority: z2.number({ int: true, min: 0, max: 3 }).nullable().optional().describe("Coarse priority: 0 is P0 (highest) through 3 is P3 (lowest); null clears it."),
|
|
@@ -30185,7 +30185,7 @@ var dispatchToolSpecs = [
|
|
|
30185
30185
|
{
|
|
30186
30186
|
name: "dispatch_comment",
|
|
30187
30187
|
example: { issue: "DSP-1", body: "Looks good." },
|
|
30188
|
-
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
|
|
30188
|
+
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 ${DISPATCH_BODY_MAX} characters, the lines images appends included. ${OWNER_REFERENCE}`,
|
|
30189
30189
|
arguments: (z2) => ({
|
|
30190
30190
|
issue: z2.string().describe(ISSUE_REFERENCE).optional(),
|
|
30191
30191
|
project: z2.string().describe("Project key owning the document.").optional(),
|
|
@@ -30193,11 +30193,11 @@ var dispatchToolSpecs = [
|
|
|
30193
30193
|
ref: z2.string().describe("Optional dispatch:// issue or document reference.").optional(),
|
|
30194
30194
|
quote: z2.string().describe("Optional exact quoted document text.").optional(),
|
|
30195
30195
|
occurrence: z2.number({ int: true, min: 0 }).describe("Optional zero-based occurrence of quote.").optional(),
|
|
30196
|
-
body: z2.string({ max: DISPATCH_BODY_MAX }).describe(
|
|
30196
|
+
body: z2.string({ max: DISPATCH_BODY_MAX }).describe(`Review comment, at most ${DISPATCH_BODY_MAX} characters.`),
|
|
30197
30197
|
reply_to: z2.string().describe("A comment id (uuid); replying to any comment in a thread continues that thread (an " + "ask's clarification thread included). To reply to an ask, use reply_to_ask with the " + "ask id instead.").optional(),
|
|
30198
30198
|
reply_to_ask: z2.string().describe("Optional ask id to reply to, threading this comment under that question. Mutually " + "exclusive with reply_to.").optional(),
|
|
30199
30199
|
turn: z2.enum(["agent", "human"]).describe("Only with reply_to_ask: who holds the turn after this reply. agent: a progress note - " + "you keep the turn and the ask stays 'Waiting on agents' for the human; human (default): " + "you need the human to act - the ask returns to 'Waiting on you'.").optional(),
|
|
30200
|
-
images: imagesArgument(z2, "the issue (or the project document's project)",
|
|
30200
|
+
images: imagesArgument(z2, "the issue (or the project document's project)", `the ${DISPATCH_BODY_MAX}-character body limit`)
|
|
30201
30201
|
}),
|
|
30202
30202
|
validation: commentValidation
|
|
30203
30203
|
},
|
|
@@ -30209,7 +30209,7 @@ var dispatchToolSpecs = [
|
|
|
30209
30209
|
quote: "old wording",
|
|
30210
30210
|
replace_with: "new wording"
|
|
30211
30211
|
},
|
|
30212
|
-
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
|
|
30212
|
+
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 ${DISPATCH_BODY_MAX} characters. ${OWNER_REFERENCE}`,
|
|
30213
30213
|
arguments: (z2) => ({
|
|
30214
30214
|
issue: z2.string().describe(ISSUE_REFERENCE).optional(),
|
|
30215
30215
|
project: z2.string().describe("Project key owning the document.").optional(),
|
|
@@ -30217,7 +30217,7 @@ var dispatchToolSpecs = [
|
|
|
30217
30217
|
ref: z2.string().describe("Optional dispatch:// issue or document reference.").optional(),
|
|
30218
30218
|
quote: z2.string().describe("Exact document text to replace."),
|
|
30219
30219
|
replace_with: z2.string().describe("Replacement text; a CR LF or a lone carriage return in it is written as a line feed."),
|
|
30220
|
-
body: z2.string({ max:
|
|
30220
|
+
body: z2.string({ max: DISPATCH_BODY_MAX }).describe(`Optional rationale, at most ${DISPATCH_BODY_MAX} characters.`).optional(),
|
|
30221
30221
|
occurrence: z2.number({ int: true, min: 0 }).describe("Optional zero-based occurrence of quote.").optional()
|
|
30222
30222
|
}),
|
|
30223
30223
|
validation: documentOwnerValidation(true, true)
|
|
@@ -30225,12 +30225,12 @@ var dispatchToolSpecs = [
|
|
|
30225
30225
|
{
|
|
30226
30226
|
name: "dispatch_message",
|
|
30227
30227
|
example: { issue: "DSP-1", body: "Implementation started." },
|
|
30228
|
-
description: "Post a note humans must read now: a reply to a human's message or a deliverable that landed. A to-do only a human can " + "complete is an ask (dispatch ask), so it reaches their inbox. Never progress or status updates - Dispatch is a high-signal " + "record, not a log. Not a design decision (write it as a decision block in the document) or document feedback (dispatch comment). " + "To answer a human's direct message to this session - one sent from the Agents page, which names no issue - pass that message's bare id as " + "in_reply_to and no issue; the reply lands in that conversation. Another call with the same in_reply_to and new text posts a follow-up, " + "threaded under this session's first reply; the same text again posts nothing. dispatch read --message <id> reads " + "that conversation back. Every other message names its issue. " + `Body is at most
|
|
30228
|
+
description: "Post a note humans must read now: a reply to a human's message or a deliverable that landed. A to-do only a human can " + "complete is an ask (dispatch ask), so it reaches their inbox. Never progress or status updates - Dispatch is a high-signal " + "record, not a log. Not a design decision (write it as a decision block in the document) or document feedback (dispatch comment). " + "To answer a human's direct message to this session - one sent from the Agents page, which names no issue - pass that message's bare id as " + "in_reply_to and no issue; the reply lands in that conversation. Another call with the same in_reply_to and new text posts a follow-up, " + "threaded under this session's first reply; the same text again posts nothing. dispatch read --message <id> reads " + "that conversation back. Every other message names its issue. " + `Body is at most ${DISPATCH_BODY_MAX} characters, the lines images appends included. ${ISSUE_REFERENCE}`,
|
|
30229
30229
|
arguments: (z2) => ({
|
|
30230
30230
|
issue: z2.string().describe(`${ISSUE_REFERENCE} Omit it only when in_reply_to answers a human's direct message to this session.`).optional(),
|
|
30231
|
-
body: z2.string({ max: DISPATCH_BODY_MAX }).describe(
|
|
30231
|
+
body: z2.string({ max: DISPATCH_BODY_MAX }).describe(`Update text, at most ${DISPATCH_BODY_MAX} characters.`),
|
|
30232
30232
|
in_reply_to: z2.string().describe("Optional message id or dispatch://KEY/message/<id> reference to reply to, threading " + "this message under it so the reply stays with the original in the Conversation. " + "A bare id with no issue answers a human's direct message to this session; a " + "dispatch://KEY/message/<id> names the issue its message lives on, so that form is a " + "reply on that issue.").optional(),
|
|
30233
|
-
images: imagesArgument(z2, "the issue (a reply to a direct message: your own conversation, dispatch://agent/<your session id>)",
|
|
30233
|
+
images: imagesArgument(z2, "the issue (a reply to a direct message: your own conversation, dispatch://agent/<your session id>)", `the ${DISPATCH_BODY_MAX}-character body limit`)
|
|
30234
30234
|
}),
|
|
30235
30235
|
validation: messageValidation
|
|
30236
30236
|
},
|
|
@@ -30322,11 +30322,11 @@ var dispatchToolSpecs = [
|
|
|
30322
30322
|
{
|
|
30323
30323
|
name: "dispatch_read",
|
|
30324
30324
|
example: { issue: "DSP-1" },
|
|
30325
|
-
description: "Read an issue or
|
|
30325
|
+
description: "Read an issue or document summary, targeted ask, or targeted comment reply chain, or the conversation " + "a message belongs to. Do not use it for document contents; use dispatch doc-read instead. Supply ref, issue, " + "issue plus artifact (one of its documents), or project plus artifact; or message alone, which reads a human's direct message to this session and every " + "reply to it (they belong to no issue). A document summary names its issue, reference, versions and approval. " + "An anchored comment or ask also says where its quote sits, as `Position:`: the block's path from the top, " + "and in a table the row (0 is the header), the cells before the anchored one, and the column's header; " + "`Position: unavailable (<code>)` when Dispatch could not read the document: `DOC_SERVICE_UNAVAILABLE` " + "(try again shortly), `DOC_SCHEMA` (the document needs repair), `DOCUMENT_UNLOADABLE` (the document " + "needs a rebuild) or `INTERNAL`. " + "An issue read carries a `Progress:` line, `tasks 3/7, children 2/5`: its spec's task-list items " + "(`- [ ]` / `- [x]`, nested lists included) and its direct children, each done of total and each only " + "when it has any (`Progress: none` otherwise). " + "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. " + "The pictures the shown messages, asks and comments embed come back as images you see, newest first, at most 8 " + "and 10 MiB of them per read, each a PNG, JPEG, GIF or WebP of at most 3,750,000 bytes (5 MB of base64); a `Pictures:` section names each " + "one shown, in order, and the rest by reference, for dispatch doc-read. A picture this session was already shown is named, not sent again " + "(every request carries the session's history, and the provider refuses one over 32 MB); dispatch doc-read shows it again. " + OWNER_REFERENCE,
|
|
30326
30326
|
arguments: (z2) => ({
|
|
30327
30327
|
issue: z2.string().describe(ISSUE_REFERENCE).optional(),
|
|
30328
30328
|
project: z2.string().describe("Project key owning the document.").optional(),
|
|
30329
|
-
artifact: z2.string().describe("
|
|
30329
|
+
artifact: z2.string().describe("Document artifact id, slug, or filename: one of the issue's, or a project document.").optional(),
|
|
30330
30330
|
ref: z2.string().describe("Optional dispatch:// issue or document reference.").optional(),
|
|
30331
30331
|
message: z2.string().describe("A message id (uuid): reads the conversation it belongs to, the root message and every " + "reply. Name nothing else with it.").optional()
|
|
30332
30332
|
}),
|
|
@@ -31335,6 +31335,8 @@ function parseDispatchRef(ref) {
|
|
|
31335
31335
|
...version3 === undefined ? {} : { version: Number(version3) }
|
|
31336
31336
|
};
|
|
31337
31337
|
}
|
|
31338
|
+
if (version3 !== undefined)
|
|
31339
|
+
return null;
|
|
31338
31340
|
if (targetID === undefined || targetKind !== "ask" && targetKind !== "comment")
|
|
31339
31341
|
return null;
|
|
31340
31342
|
return {
|
|
@@ -4,7 +4,7 @@ Read this to catch up after a restart, read a node, trace what cites it, or writ
|
|
|
4
4
|
|
|
5
5
|
## What comes back
|
|
6
6
|
|
|
7
|
-
- After a restart, catch up with `dispatch read --issue <KEY>` (or `--
|
|
7
|
+
- After a restart, catch up with `dispatch read --issue <KEY>` (or `--artifact` with `--issue` or `--project`, or `--ref`). It prints the issue's summary, open asks, references and recent events, a document's summary (its issue, reference, versions and approval), or an ask's, comment's or message's thread. Reads do not subscribe. Use `dispatch doc-read` for document text.
|
|
8
8
|
- An anchored comment or ask prints `Position:`, where its quote's block stands. `unavailable (DOC_SERVICE_UNAVAILABLE)` means try again shortly. `unavailable (DOC_SCHEMA)` means the document needs repair.
|
|
9
9
|
- The API gives the same facts as `anchor_block` (or `anchor_block_error`) on `GET /api/v1/comments/{id}` and `GET /api/v1/asks/{id}`. `GET /api/v1/artifacts/{id}/blocks/{block_id}` gives them for any block.
|
|
10
10
|
- Each read ends with `Referenced by:` (what cites the node) and `Links:` (what it cites), across projects. "What led to this decision" is one read on the ask.
|
|
@@ -28,3 +28,4 @@ dispatch://PROJECT/artifact/<document-ref>/comment/<id>
|
|
|
28
28
|
- A reference renders as a link titled by its target. A body that is only a reference gets an unfurl card.
|
|
29
29
|
- A bare UUID or `KEY#seq` is not a reference. `dispatch read` also takes a dashboard URL, also on the public dashboard when `DISPATCH_PUBLIC_URL` names one. An issue read prints its `Link:`: hand that to a person.
|
|
30
30
|
- An ask or comment id can be a unique 8+ hex prefix. A message id is always the full UUID.
|
|
31
|
+
- An ask or comment on an issue's document is `dispatch://KEY/ask/<id>` or `dispatch://KEY/comment/<id>`, never written through its document.
|
|
@@ -18,7 +18,7 @@ dispatch search --query 'reviewer threads OR review comments'
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
- No hits: drop a word before you add one. Try two or three wordings (the component's name, the symptom, the fix) before you conclude that nothing exists.
|
|
21
|
-
- Open each hit that could be yours with `dispatch read`, then its parent (the `child_of` row under `Links:`). The parent's children and the `Components:` line show where the rest of the work is.
|
|
21
|
+
- Open each hit that could be yours with `dispatch read`, then its parent (the `child_of` row under `Links:`; a document hit names its issue on `Issue:`). The parent's children and the `Components:` line show where the rest of the work is.
|
|
22
22
|
|
|
23
23
|
## What to do with what you find
|
|
24
24
|
|