@sjawhar/pi-legion-envoy 1.51.0 → 1.51.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/envoy.js CHANGED
@@ -29696,6 +29696,12 @@ var askEventPayloadFields = {
29696
29696
  mark_id: string2().optional(),
29697
29697
  block_id: string2().nullable().optional()
29698
29698
  }).passthrough().nullish(),
29699
+ anchor_artifact: object({
29700
+ project: string2().optional(),
29701
+ slug: string2().optional(),
29702
+ name: string2().optional(),
29703
+ primary: boolean2().optional()
29704
+ }).optional(),
29699
29705
  resolution: object({
29700
29706
  kind: _enum2(["retracted", "resolved"]).optional(),
29701
29707
  reason: string2().optional(),
@@ -29902,6 +29908,7 @@ var DOC_EDIT_OPS = ["replace", "delete", "insert", "retype", "move"];
29902
29908
  var dispatchToolSpecs = [
29903
29909
  {
29904
29910
  name: "dispatch_issue",
29911
+ example: { project: "DSP", title: "Native workspace" },
29905
29912
  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}`,
29906
29913
  arguments: (z) => ({
29907
29914
  project: z.string().describe("Project key for the new issue."),
@@ -29918,6 +29925,7 @@ var dispatchToolSpecs = [
29918
29925
  },
29919
29926
  {
29920
29927
  name: "dispatch_issue_update",
29928
+ example: { issue: "DSP-1", status: "in_progress" },
29921
29929
  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}`,
29922
29930
  arguments: (z) => ({
29923
29931
  issue: z.string().describe(ISSUE_REFERENCE),
@@ -29940,6 +29948,7 @@ var dispatchToolSpecs = [
29940
29948
  },
29941
29949
  {
29942
29950
  name: "dispatch_ask",
29951
+ example: { issue: "DSP-1", question: "Ship this?" },
29943
29952
  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}`,
29944
29953
  arguments: (z) => ({
29945
29954
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -29963,6 +29972,10 @@ var dispatchToolSpecs = [
29963
29972
  },
29964
29973
  {
29965
29974
  name: "dispatch_edit_ask",
29975
+ example: {
29976
+ ask: "01234567-0000-4000-8000-000000000001",
29977
+ question: "Ship the revised plan?"
29978
+ },
29966
29979
  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.",
29967
29980
  arguments: (z) => ({
29968
29981
  ask: z.string().describe("Ask id to edit."),
@@ -29984,6 +29997,11 @@ var dispatchToolSpecs = [
29984
29997
  },
29985
29998
  {
29986
29999
  name: "dispatch_resolve_ask",
30000
+ example: {
30001
+ ask: "01234567-0000-4000-8000-000000000001",
30002
+ kind: "retracted",
30003
+ reason: "A newer question supersedes this one."
30004
+ },
29987
30005
  description: "Retract an open question that is moot or resolve one after finding the answer. This closes the question without answering it.",
29988
30006
  arguments: (z) => ({
29989
30007
  ask: z.string().describe("Ask id to close."),
@@ -29993,6 +30011,7 @@ var dispatchToolSpecs = [
29993
30011
  },
29994
30012
  {
29995
30013
  name: "dispatch_resolve_comment",
30014
+ example: { comment: "01234567-0000-4000-8000-000000000001" },
29996
30015
  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.",
29997
30016
  arguments: (z) => ({
29998
30017
  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.")
@@ -30001,6 +30020,7 @@ var dispatchToolSpecs = [
30001
30020
  },
30002
30021
  {
30003
30022
  name: "dispatch_follow",
30023
+ example: { ask: "01234567-0000-4000-8000-000000000001", action: "follow" },
30004
30024
  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>.>",
30005
30025
  arguments: (z) => ({
30006
30026
  ask: z.string().describe("Full ask id (uuid)."),
@@ -30010,6 +30030,7 @@ var dispatchToolSpecs = [
30010
30030
  },
30011
30031
  {
30012
30032
  name: "dispatch_comment",
30033
+ example: { issue: "DSP-1", body: "Looks good." },
30013
30034
  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}`,
30014
30035
  arguments: (z) => ({
30015
30036
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -30027,6 +30048,12 @@ var dispatchToolSpecs = [
30027
30048
  },
30028
30049
  {
30029
30050
  name: "dispatch_suggest",
30051
+ example: {
30052
+ issue: "DSP-1",
30053
+ artifact: "spec",
30054
+ quote: "old wording",
30055
+ replace_with: "new wording"
30056
+ },
30030
30057
  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}`,
30031
30058
  arguments: (z) => ({
30032
30059
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -30042,6 +30069,7 @@ var dispatchToolSpecs = [
30042
30069
  },
30043
30070
  {
30044
30071
  name: "dispatch_message",
30072
+ example: { issue: "DSP-1", body: "Implementation started." },
30045
30073
  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}`,
30046
30074
  arguments: (z) => ({
30047
30075
  issue: z.string().describe(ISSUE_REFERENCE),
@@ -30051,6 +30079,11 @@ var dispatchToolSpecs = [
30051
30079
  },
30052
30080
  {
30053
30081
  name: "dispatch_doc_edit",
30082
+ example: {
30083
+ issue: "DSP-1",
30084
+ artifact: "spec",
30085
+ ops: [{ op: "replace", find: "old", with: "new" }]
30086
+ },
30054
30087
  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}`,
30055
30088
  arguments: (z) => ({
30056
30089
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -30075,6 +30108,7 @@ var dispatchToolSpecs = [
30075
30108
  },
30076
30109
  {
30077
30110
  name: "dispatch_doc_read",
30111
+ example: { issue: "DSP-1" },
30078
30112
  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,
30079
30113
  arguments: (z) => ({
30080
30114
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -30087,6 +30121,7 @@ var dispatchToolSpecs = [
30087
30121
  },
30088
30122
  {
30089
30123
  name: "dispatch_request_approval",
30124
+ example: { issue: "DSP-1" },
30090
30125
  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,
30091
30126
  arguments: (z) => ({
30092
30127
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -30097,6 +30132,8 @@ var dispatchToolSpecs = [
30097
30132
  },
30098
30133
  {
30099
30134
  name: "dispatch_artifact",
30135
+ example: { issue: "DSP-1", name: "design.md", content: `# Design
30136
+ ` },
30100
30137
  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}`,
30101
30138
  arguments: (z) => ({
30102
30139
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -30116,6 +30153,7 @@ var dispatchToolSpecs = [
30116
30153
  },
30117
30154
  {
30118
30155
  name: "dispatch_read",
30156
+ example: { issue: "DSP-1" },
30119
30157
  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,
30120
30158
  arguments: (z) => ({
30121
30159
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -30127,6 +30165,7 @@ var dispatchToolSpecs = [
30127
30165
  },
30128
30166
  {
30129
30167
  name: "dispatch_search",
30168
+ example: { query: "astrolabe" },
30130
30169
  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.',
30131
30170
  arguments: (z) => ({
30132
30171
  query: z.string({ min: 2 }).describe("Keyword, phrase, or websearch expression; at least 2 characters."),
@@ -30136,6 +30175,7 @@ var dispatchToolSpecs = [
30136
30175
  },
30137
30176
  {
30138
30177
  name: "dispatch_issues",
30178
+ example: { project: "AGENTC" },
30139
30179
  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.",
30140
30180
  arguments: (z) => ({
30141
30181
  project: z.string().describe("Project key to list issues from."),
@@ -30148,6 +30188,7 @@ var dispatchToolSpecs = [
30148
30188
  },
30149
30189
  {
30150
30190
  name: "dispatch_architecture_sync",
30191
+ example: { project: "CORE" },
30151
30192
  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.",
30152
30193
  arguments: (z) => ({
30153
30194
  project: z.string().describe("Project key whose architecture source to sync, such as CORE.")
@@ -30156,6 +30197,7 @@ var dispatchToolSpecs = [
30156
30197
  },
30157
30198
  {
30158
30199
  name: "dispatch_open_asks",
30200
+ example: {},
30159
30201
  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.",
30160
30202
  arguments: (z) => ({
30161
30203
  project: z.string().describe("Project key; when supplied, lists every open ask in the project instead of only this session's own.").optional()
@@ -30164,6 +30206,7 @@ var dispatchToolSpecs = [
30164
30206
  },
30165
30207
  {
30166
30208
  name: "dispatch_whoami",
30209
+ example: {},
30167
30210
  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.",
30168
30211
  arguments: () => ({}),
30169
30212
  strict: true
@@ -32254,9 +32297,11 @@ class ToolInputError extends Error {
32254
32297
  problems;
32255
32298
  constructor(tool, problems) {
32256
32299
  const count = problems.length;
32300
+ const help = dispatchInputHelp(tool);
32257
32301
  super([
32258
32302
  `${tool} was not called: ${count} problem${count === 1 ? "" : "s"}`,
32259
- ...problems.map((problem) => `- ${problem}`)
32303
+ ...problems.map((problem) => `- ${problem}`),
32304
+ ...help === undefined ? [] : help.map((line) => `- ${line}`)
32260
32305
  ].join(`
32261
32306
  `));
32262
32307
  this.name = "ToolInputError";
@@ -32264,6 +32309,14 @@ class ToolInputError extends Error {
32264
32309
  this.problems = problems;
32265
32310
  }
32266
32311
  }
32312
+ function dispatchInputHelp(tool) {
32313
+ const spec = dispatchToolSpecs.find((candidate) => candidate.name === tool);
32314
+ if (spec === undefined)
32315
+ return;
32316
+ const schema = dispatchToolSchema(spec, zodSchemaApi(exports_external), { strict: true });
32317
+ const allowed = Object.keys(shapeOf(schema) ?? {}).join(", ") || "none";
32318
+ return [`Allowed keys: ${allowed}`, `Example: ${tool}(${JSON.stringify(spec.example)})`];
32319
+ }
32267
32320
  function unwrap(schema) {
32268
32321
  let current = schema;
32269
32322
  while (current !== undefined) {
@@ -32568,7 +32621,21 @@ function refTarget(ref, kind, id) {
32568
32621
  const ownerRef = ref.owner.kind === "issue" ? dispatchIssueRef(ref.owner.issue) : dispatchDocumentRef(ref.owner.project, `${ref.artifact}`);
32569
32622
  return dispatchChildRef(ownerRef, kind, id);
32570
32623
  }
32571
- var uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
32624
+ var canonicalUUIDPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
32625
+ var compactUUIDPattern = /^[0-9a-f]{32}$/i;
32626
+ function normalizeUUID(value) {
32627
+ let compact = value;
32628
+ if (value.slice(0, 9).toLowerCase() === "urn:uuid:") {
32629
+ compact = value.slice(9);
32630
+ } else if (value.length === 38 && value.startsWith("{") && value.endsWith("}")) {
32631
+ compact = value.slice(1, -1);
32632
+ }
32633
+ if (canonicalUUIDPattern.test(compact))
32634
+ compact = compact.replaceAll("-", "");
32635
+ if (!compactUUIDPattern.test(compact))
32636
+ return;
32637
+ return `${compact.slice(0, 8)}-${compact.slice(8, 12)}-${compact.slice(12, 16)}-${compact.slice(16, 20)}-${compact.slice(20)}`.toLowerCase();
32638
+ }
32572
32639
  var askIdProblem = "ask must be a bare ask id or a dispatch://.../ask/<id> reference";
32573
32640
  var commentIdProblem = "comment must be a bare comment id or a dispatch://.../comment/<id> reference";
32574
32641
  var messageIdProblem = "in_reply_to must be a full message id (uuid) or a dispatch://KEY/message/<id> reference";
@@ -32581,12 +32648,13 @@ function messageIdOf(value) {
32581
32648
  const reference = parseDispatchRef(value);
32582
32649
  return reference?.kind === "message" ? reference.id : undefined;
32583
32650
  })() : value;
32584
- return id !== undefined && uuidPattern.test(id) ? id : undefined;
32651
+ return id === undefined ? undefined : normalizeUUID(id);
32585
32652
  }
32586
32653
  var idPrefixPattern = /^[0-9a-f][0-9a-f-]{7,}$/i;
32587
32654
  async function resolveIdPrefix(tool, kind, ref, list) {
32588
- if (uuidPattern.test(ref.id))
32589
- return ref.id;
32655
+ const fullID = normalizeUUID(ref.id);
32656
+ if (fullID !== undefined)
32657
+ return fullID;
32590
32658
  const ownerName = ref.owner.kind === "issue" ? ref.owner.issue : `${ref.owner.project}/${ref.artifact}`;
32591
32659
  if (!idPrefixPattern.test(ref.id)) {
32592
32660
  throw new ToolInputError(tool, [
@@ -32818,21 +32886,53 @@ async function resolveArtifact(client, owner, artifactReference) {
32818
32886
  return { owner, artifact };
32819
32887
  const names = artifacts.filter((candidate) => candidate.name === artifactReference);
32820
32888
  if (names.length > 1) {
32821
- throw new Error(`artifact name ${artifactReference} is ambiguous in project ${owner.project}; ` + `${names.length} documents share it \u2014 use its slug instead`);
32889
+ throw new Error(documentReferenceProblem(artifactReference, names, "project", true));
32890
+ }
32891
+ if (names[0] === undefined) {
32892
+ throw new Error(documentReferenceProblem(artifactReference, artifacts, "project"));
32822
32893
  }
32823
- if (names[0] === undefined)
32824
- throw error;
32825
32894
  return { owner, artifact: names[0] };
32826
32895
  }
32827
32896
  }
32828
32897
  const issue = await client.getIssue(owner.issue);
32829
- const artifact = artifactReference === undefined || artifactReference === "spec" ? issue.artifacts.find((candidate) => candidate.primary || candidate.id === issue.primary_artifact_id) : issue.artifacts.find((candidate) => candidate.id === artifactReference || candidate.slug === artifactReference || candidate.name === artifactReference);
32898
+ let artifact;
32899
+ if (artifactReference === undefined || artifactReference === "spec") {
32900
+ artifact = issue.artifacts.find((candidate) => candidate.primary || candidate.id === issue.primary_artifact_id);
32901
+ } else {
32902
+ artifact = issue.artifacts.find((candidate) => candidate.id === artifactReference || candidate.slug === artifactReference);
32903
+ if (artifact === undefined) {
32904
+ const names = issue.artifacts.filter((candidate) => candidate.name === artifactReference);
32905
+ if (names.length > 1) {
32906
+ throw new Error(documentReferenceProblem(artifactReference, names, "issue", true));
32907
+ }
32908
+ artifact = names[0];
32909
+ }
32910
+ }
32830
32911
  if (!artifact) {
32831
- const slugs = issue.artifacts.map((candidate) => `${candidate.slug}${candidate.primary || candidate.id === issue.primary_artifact_id ? " (primary)" : ""}`);
32832
- throw new Error(`artifact "${artifactReference ?? "spec"}" was not found on issue ${issue.key}; artifacts: ${slugs.length === 0 ? "none" : slugs.join(", ")}`);
32912
+ throw new Error(documentReferenceProblem(artifactReference ?? "spec", issue.artifacts, "issue"));
32833
32913
  }
32834
32914
  return { owner, issue, artifact };
32835
32915
  }
32916
+ var documentHintLimit = 8;
32917
+ function documentReferenceProblem(reference, documents, owner, ambiguous = false) {
32918
+ const hints = documents.slice(0, documentHintLimit).map((document) => `${document.slug} (${document.name})`);
32919
+ const list = hints.length === 0 ? "none" : hints.join(", ");
32920
+ 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}`;
32921
+ }
32922
+ var askHintLimit = 8;
32923
+ function askIDInputProblem(asks, scope) {
32924
+ const hints = asks.slice(0, askHintLimit).map((ask) => `${ask.id.slice(0, 8)}\u2026 ${textHead(ask.question)}`);
32925
+ return `ask IDs are UUIDs; use the full ask ID; ${scope} open asks: ${hints.length === 0 ? "none" : hints.join(", ")}`;
32926
+ }
32927
+ async function invalidReplyToAskProblem(client, owner, resolved) {
32928
+ if (owner.kind === "issue") {
32929
+ const issue = resolved?.issue ?? await client.getIssue(owner.issue);
32930
+ return askIDInputProblem(issue.open_asks, "this issue's");
32931
+ }
32932
+ if (resolved === undefined)
32933
+ throw new Error("project document is missing its resolved artifact");
32934
+ return askIDInputProblem(await client.getArtifactAsks(resolved.artifact.id, "open"), "this document's");
32935
+ }
32836
32936
  function anchor(artifact, args) {
32837
32937
  const quote = optionalString(args, "quote");
32838
32938
  if (quote === undefined)
@@ -33436,7 +33536,13 @@ ${followsAsk(askOwner)}`,
33436
33536
  const resolved = owner.kind === "project" || artifactReference === undefined ? owner.kind === "project" ? await resolveArtifact(client, owner, artifactReference) : undefined : await resolveArtifact(client, owner, artifactReference);
33437
33537
  const anchored = resolved ? anchor(resolved.artifact, args) : undefined;
33438
33538
  const replyTo = optionalString(args, "reply_to");
33439
- const replyToAsk = optionalString(args, "reply_to_ask");
33539
+ const replyToAskReference = optionalString(args, "reply_to_ask");
33540
+ const replyToAsk = replyToAskReference === undefined ? undefined : normalizeUUID(replyToAskReference);
33541
+ if (replyToAskReference !== undefined && replyToAsk === undefined) {
33542
+ throw new ToolInputError(input.tool, [
33543
+ await invalidReplyToAskProblem(client, owner, resolved)
33544
+ ]);
33545
+ }
33440
33546
  const requestedTurn = optionalString(args, "turn");
33441
33547
  const commentInput = {
33442
33548
  body: stringArg(args, "body"),
package/dist/legion.js CHANGED
@@ -16145,7 +16145,7 @@ import { logger } from "@oh-my-pi/pi-utils";
16145
16145
  // package.json
16146
16146
  var package_default = {
16147
16147
  name: "@sjawhar/pi-legion-envoy",
16148
- version: "1.51.0",
16148
+ version: "1.51.2",
16149
16149
  type: "module",
16150
16150
  omp: {
16151
16151
  extensions: [
@@ -29015,6 +29015,12 @@ var askEventPayloadFields = {
29015
29015
  mark_id: string2().optional(),
29016
29016
  block_id: string2().nullable().optional()
29017
29017
  }).passthrough().nullish(),
29018
+ anchor_artifact: object({
29019
+ project: string2().optional(),
29020
+ slug: string2().optional(),
29021
+ name: string2().optional(),
29022
+ primary: boolean2().optional()
29023
+ }).optional(),
29018
29024
  resolution: object({
29019
29025
  kind: _enum2(["retracted", "resolved"]).optional(),
29020
29026
  reason: string2().optional(),
@@ -29221,6 +29227,7 @@ var DOC_EDIT_OPS = ["replace", "delete", "insert", "retype", "move"];
29221
29227
  var dispatchToolSpecs = [
29222
29228
  {
29223
29229
  name: "dispatch_issue",
29230
+ example: { project: "DSP", title: "Native workspace" },
29224
29231
  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}`,
29225
29232
  arguments: (z) => ({
29226
29233
  project: z.string().describe("Project key for the new issue."),
@@ -29237,6 +29244,7 @@ var dispatchToolSpecs = [
29237
29244
  },
29238
29245
  {
29239
29246
  name: "dispatch_issue_update",
29247
+ example: { issue: "DSP-1", status: "in_progress" },
29240
29248
  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}`,
29241
29249
  arguments: (z) => ({
29242
29250
  issue: z.string().describe(ISSUE_REFERENCE),
@@ -29259,6 +29267,7 @@ var dispatchToolSpecs = [
29259
29267
  },
29260
29268
  {
29261
29269
  name: "dispatch_ask",
29270
+ example: { issue: "DSP-1", question: "Ship this?" },
29262
29271
  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}`,
29263
29272
  arguments: (z) => ({
29264
29273
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -29282,6 +29291,10 @@ var dispatchToolSpecs = [
29282
29291
  },
29283
29292
  {
29284
29293
  name: "dispatch_edit_ask",
29294
+ example: {
29295
+ ask: "01234567-0000-4000-8000-000000000001",
29296
+ question: "Ship the revised plan?"
29297
+ },
29285
29298
  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.",
29286
29299
  arguments: (z) => ({
29287
29300
  ask: z.string().describe("Ask id to edit."),
@@ -29303,6 +29316,11 @@ var dispatchToolSpecs = [
29303
29316
  },
29304
29317
  {
29305
29318
  name: "dispatch_resolve_ask",
29319
+ example: {
29320
+ ask: "01234567-0000-4000-8000-000000000001",
29321
+ kind: "retracted",
29322
+ reason: "A newer question supersedes this one."
29323
+ },
29306
29324
  description: "Retract an open question that is moot or resolve one after finding the answer. This closes the question without answering it.",
29307
29325
  arguments: (z) => ({
29308
29326
  ask: z.string().describe("Ask id to close."),
@@ -29312,6 +29330,7 @@ var dispatchToolSpecs = [
29312
29330
  },
29313
29331
  {
29314
29332
  name: "dispatch_resolve_comment",
29333
+ example: { comment: "01234567-0000-4000-8000-000000000001" },
29315
29334
  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.",
29316
29335
  arguments: (z) => ({
29317
29336
  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.")
@@ -29320,6 +29339,7 @@ var dispatchToolSpecs = [
29320
29339
  },
29321
29340
  {
29322
29341
  name: "dispatch_follow",
29342
+ example: { ask: "01234567-0000-4000-8000-000000000001", action: "follow" },
29323
29343
  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>.>",
29324
29344
  arguments: (z) => ({
29325
29345
  ask: z.string().describe("Full ask id (uuid)."),
@@ -29329,6 +29349,7 @@ var dispatchToolSpecs = [
29329
29349
  },
29330
29350
  {
29331
29351
  name: "dispatch_comment",
29352
+ example: { issue: "DSP-1", body: "Looks good." },
29332
29353
  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}`,
29333
29354
  arguments: (z) => ({
29334
29355
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -29346,6 +29367,12 @@ var dispatchToolSpecs = [
29346
29367
  },
29347
29368
  {
29348
29369
  name: "dispatch_suggest",
29370
+ example: {
29371
+ issue: "DSP-1",
29372
+ artifact: "spec",
29373
+ quote: "old wording",
29374
+ replace_with: "new wording"
29375
+ },
29349
29376
  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}`,
29350
29377
  arguments: (z) => ({
29351
29378
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -29361,6 +29388,7 @@ var dispatchToolSpecs = [
29361
29388
  },
29362
29389
  {
29363
29390
  name: "dispatch_message",
29391
+ example: { issue: "DSP-1", body: "Implementation started." },
29364
29392
  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}`,
29365
29393
  arguments: (z) => ({
29366
29394
  issue: z.string().describe(ISSUE_REFERENCE),
@@ -29370,6 +29398,11 @@ var dispatchToolSpecs = [
29370
29398
  },
29371
29399
  {
29372
29400
  name: "dispatch_doc_edit",
29401
+ example: {
29402
+ issue: "DSP-1",
29403
+ artifact: "spec",
29404
+ ops: [{ op: "replace", find: "old", with: "new" }]
29405
+ },
29373
29406
  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}`,
29374
29407
  arguments: (z) => ({
29375
29408
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -29394,6 +29427,7 @@ var dispatchToolSpecs = [
29394
29427
  },
29395
29428
  {
29396
29429
  name: "dispatch_doc_read",
29430
+ example: { issue: "DSP-1" },
29397
29431
  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,
29398
29432
  arguments: (z) => ({
29399
29433
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -29406,6 +29440,7 @@ var dispatchToolSpecs = [
29406
29440
  },
29407
29441
  {
29408
29442
  name: "dispatch_request_approval",
29443
+ example: { issue: "DSP-1" },
29409
29444
  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,
29410
29445
  arguments: (z) => ({
29411
29446
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -29416,6 +29451,8 @@ var dispatchToolSpecs = [
29416
29451
  },
29417
29452
  {
29418
29453
  name: "dispatch_artifact",
29454
+ example: { issue: "DSP-1", name: "design.md", content: `# Design
29455
+ ` },
29419
29456
  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}`,
29420
29457
  arguments: (z) => ({
29421
29458
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -29435,6 +29472,7 @@ var dispatchToolSpecs = [
29435
29472
  },
29436
29473
  {
29437
29474
  name: "dispatch_read",
29475
+ example: { issue: "DSP-1" },
29438
29476
  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,
29439
29477
  arguments: (z) => ({
29440
29478
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
@@ -29446,6 +29484,7 @@ var dispatchToolSpecs = [
29446
29484
  },
29447
29485
  {
29448
29486
  name: "dispatch_search",
29487
+ example: { query: "astrolabe" },
29449
29488
  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.',
29450
29489
  arguments: (z) => ({
29451
29490
  query: z.string({ min: 2 }).describe("Keyword, phrase, or websearch expression; at least 2 characters."),
@@ -29455,6 +29494,7 @@ var dispatchToolSpecs = [
29455
29494
  },
29456
29495
  {
29457
29496
  name: "dispatch_issues",
29497
+ example: { project: "AGENTC" },
29458
29498
  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.",
29459
29499
  arguments: (z) => ({
29460
29500
  project: z.string().describe("Project key to list issues from."),
@@ -29467,6 +29507,7 @@ var dispatchToolSpecs = [
29467
29507
  },
29468
29508
  {
29469
29509
  name: "dispatch_architecture_sync",
29510
+ example: { project: "CORE" },
29470
29511
  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.",
29471
29512
  arguments: (z) => ({
29472
29513
  project: z.string().describe("Project key whose architecture source to sync, such as CORE.")
@@ -29475,6 +29516,7 @@ var dispatchToolSpecs = [
29475
29516
  },
29476
29517
  {
29477
29518
  name: "dispatch_open_asks",
29519
+ example: {},
29478
29520
  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.",
29479
29521
  arguments: (z) => ({
29480
29522
  project: z.string().describe("Project key; when supplied, lists every open ask in the project instead of only this session's own.").optional()
@@ -29483,6 +29525,7 @@ var dispatchToolSpecs = [
29483
29525
  },
29484
29526
  {
29485
29527
  name: "dispatch_whoami",
29528
+ example: {},
29486
29529
  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.",
29487
29530
  arguments: () => ({}),
29488
29531
  strict: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/pi-legion-envoy",
3
- "version": "1.51.0",
3
+ "version": "1.51.2",
4
4
  "type": "module",
5
5
  "omp": {
6
6
  "extensions": [