@sjawhar/pi-legion-envoy 0.26.0 → 0.28.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/README.md CHANGED
@@ -79,8 +79,8 @@ extension files it does not contain.
79
79
 
80
80
  ## Native Dispatch tools
81
81
 
82
- The extension registers `dispatch_issue`, `dispatch_ask`, `dispatch_comment`,
83
- `dispatch_suggest`, `dispatch_message`, `dispatch_doc_edit`,
82
+ The extension registers `dispatch_issue`, `dispatch_ask`, `dispatch_resolve_ask`,
83
+ `dispatch_comment`, `dispatch_suggest`, `dispatch_message`, `dispatch_doc_edit`,
84
84
  `dispatch_doc_read`, `dispatch_artifact`, and `dispatch_read` when Dispatch
85
85
  configuration resolves both a base URL and bearer token.
86
86
 
package/dist/envoy.js CHANGED
@@ -29671,7 +29671,13 @@ var ArtifactVersionEventPayloadSchema = object({
29671
29671
  var AskEventPayloadSchema = object({
29672
29672
  question: string2().optional(),
29673
29673
  options: array(object({ label: string2().optional() })).nullish(),
29674
- answer: object({ selected: array(string2()).nullish(), text: string2().nullish() }).nullish()
29674
+ answer: object({ selected: array(string2()).nullish(), text: string2().nullish() }).nullish(),
29675
+ resolution: object({
29676
+ kind: _enum2(["retracted", "resolved"]).optional(),
29677
+ reason: string2().optional(),
29678
+ actor: object({ kind: string2().optional(), id: string2().optional() }).passthrough().optional(),
29679
+ at: string2().optional()
29680
+ }).nullish()
29675
29681
  });
29676
29682
  var CommentEventPayloadSchema = object({
29677
29683
  artifact_name: string2().optional(),
@@ -29727,6 +29733,15 @@ var dispatchToolSpecs = [
29727
29733
  }).describe("Optional document location for the question.").optional()
29728
29734
  })
29729
29735
  },
29736
+ {
29737
+ name: "dispatch_resolve_ask",
29738
+ description: "Retract an open question that is moot or resolve one after finding the answer. This closes the question without answering it.",
29739
+ arguments: (z) => ({
29740
+ ask: z.string().describe("Ask id to close."),
29741
+ kind: z.enum(["retracted", "resolved"]).describe("Whether the ask is retracted or self-resolved."),
29742
+ reason: z.string({ min: 1 }).describe("Why the open ask no longer needs a human answer.")
29743
+ })
29744
+ },
29730
29745
  {
29731
29746
  name: "dispatch_comment",
29732
29747
  description: "Add review feedback to an issue or document quote, or reply to a question asked with dispatch_ask. " + "Do not use it for an exact replacement; use " + `dispatch_suggest instead. Body is at most 2,000 characters. ${ISSUE_REFERENCE}`,
@@ -30798,6 +30813,7 @@ var DISPATCH_PAYLOAD_SCHEMAS = {
30798
30813
  "artifact.version": ArtifactVersionEventPayloadSchema,
30799
30814
  "ask.opened": AskEventPayloadSchema,
30800
30815
  "ask.answered": AskEventPayloadSchema,
30816
+ "ask.resolved": AskEventPayloadSchema,
30801
30817
  "comment.created": CommentEventPayloadSchema,
30802
30818
  "comment.resolved": CommentEventPayloadSchema,
30803
30819
  "suggestion.accepted": CommentEventPayloadSchema,
@@ -31180,6 +31196,9 @@ class DispatchClient {
31180
31196
  async ask(issue, input) {
31181
31197
  return this.#json("POST", ["api", "v1", "issues", await this.#resolveIssue(issue), "asks"], input);
31182
31198
  }
31199
+ async resolveAsk(id, input) {
31200
+ return this.#json("POST", ["api", "v1", "asks", id, "resolve"], input);
31201
+ }
31183
31202
  async comment(issue, input) {
31184
31203
  return this.#json("POST", ["api", "v1", "issues", await this.#resolveIssue(issue), "comments"], input);
31185
31204
  }
@@ -31398,7 +31417,7 @@ function toolSchema(tool) {
31398
31417
  return dispatchToolSchema(spec, zodSchemaApi(exports_external), { strict: true });
31399
31418
  }
31400
31419
  async function resolveIssueArguments(tool, args, cwd, env, exec) {
31401
- if (tool === "dispatch_issue")
31420
+ if (tool === "dispatch_issue" || tool === "dispatch_resolve_ask")
31402
31421
  return { args, ref: null };
31403
31422
  const refArgument = args.ref;
31404
31423
  const ref = typeof refArgument === "string" ? parseDispatchRef(refArgument) ?? (() => {
@@ -31505,6 +31524,12 @@ function askSummary({ ask, replies }) {
31505
31524
  `- Selected: ${answer.selected.length === 0 ? "none" : answer.selected.join(", ")}`,
31506
31525
  ...answer.text === null ? [] : [`- Text: ${answer.text}`]
31507
31526
  ],
31527
+ ...ask.resolution === undefined ? [] : [
31528
+ "Resolution:",
31529
+ `- By: ${ask.resolution.actor.id}`,
31530
+ `- Kind: ${ask.resolution.kind}`,
31531
+ `- Reason: ${ask.resolution.reason}`
31532
+ ],
31508
31533
  "Replies:",
31509
31534
  ...chain.length === 0 ? ["- none"] : chain
31510
31535
  ].join(`
@@ -31549,7 +31574,7 @@ async function executeDispatchTool(input) {
31549
31574
  const args = toolSchema(input.tool).parse(issueArguments.args);
31550
31575
  const actor = toolActor(await resolveOrigin(env, exec, input.cwd), input);
31551
31576
  const client = new DispatchClient(input.config.url, input.config.token, input.fetchImpl);
31552
- const issueKey = input.tool === "dispatch_issue" ? null : await ensureIssue(client, stringArg(args, "issue"), actor);
31577
+ const issueKey = input.tool === "dispatch_issue" || input.tool === "dispatch_resolve_ask" ? null : await ensureIssue(client, stringArg(args, "issue"), actor);
31553
31578
  const issue = () => {
31554
31579
  if (issueKey === null)
31555
31580
  throw new Error("issue is required");
@@ -31573,6 +31598,26 @@ async function executeDispatchTool(input) {
31573
31598
  details: { issue: created.key, topic: dispatchIssueSubject(created.key, ">") }
31574
31599
  };
31575
31600
  }
31601
+ case "dispatch_resolve_ask": {
31602
+ const kind = stringArg(args, "kind");
31603
+ if (kind !== "retracted" && kind !== "resolved")
31604
+ throw new Error("kind must be retracted or resolved");
31605
+ const ask = await client.resolveAsk(stringArg(args, "ask"), {
31606
+ kind,
31607
+ reason: stringArg(args, "reason"),
31608
+ actor
31609
+ });
31610
+ if (ask.resolution === undefined)
31611
+ throw new Error("resolved ask is missing its resolution");
31612
+ return {
31613
+ text: `${kind === "retracted" ? "Retracted" : "Resolved"} ask ${ask.id}: ${ask.resolution.reason}`,
31614
+ details: {
31615
+ issue: ask.issue_key,
31616
+ topic: dispatchIssueSubject(ask.issue_key, ">"),
31617
+ ask: ask.id
31618
+ }
31619
+ };
31620
+ }
31576
31621
  case "dispatch_ask": {
31577
31622
  const anchorArgs = asObject(args.anchor);
31578
31623
  const resolved = anchorArgs ? await resolveArtifact(client, issue(), stringArg(anchorArgs, "artifact")) : undefined;
package/dist/legion.js CHANGED
@@ -29669,7 +29669,13 @@ var ArtifactVersionEventPayloadSchema = object({
29669
29669
  var AskEventPayloadSchema = object({
29670
29670
  question: string2().optional(),
29671
29671
  options: array(object({ label: string2().optional() })).nullish(),
29672
- answer: object({ selected: array(string2()).nullish(), text: string2().nullish() }).nullish()
29672
+ answer: object({ selected: array(string2()).nullish(), text: string2().nullish() }).nullish(),
29673
+ resolution: object({
29674
+ kind: _enum2(["retracted", "resolved"]).optional(),
29675
+ reason: string2().optional(),
29676
+ actor: object({ kind: string2().optional(), id: string2().optional() }).passthrough().optional(),
29677
+ at: string2().optional()
29678
+ }).nullish()
29673
29679
  });
29674
29680
  var CommentEventPayloadSchema = object({
29675
29681
  artifact_name: string2().optional(),
@@ -29725,6 +29731,15 @@ var dispatchToolSpecs = [
29725
29731
  }).describe("Optional document location for the question.").optional()
29726
29732
  })
29727
29733
  },
29734
+ {
29735
+ name: "dispatch_resolve_ask",
29736
+ description: "Retract an open question that is moot or resolve one after finding the answer. This closes the question without answering it.",
29737
+ arguments: (z) => ({
29738
+ ask: z.string().describe("Ask id to close."),
29739
+ kind: z.enum(["retracted", "resolved"]).describe("Whether the ask is retracted or self-resolved."),
29740
+ reason: z.string({ min: 1 }).describe("Why the open ask no longer needs a human answer.")
29741
+ })
29742
+ },
29728
29743
  {
29729
29744
  name: "dispatch_comment",
29730
29745
  description: "Add review feedback to an issue or document quote, or reply to a question asked with dispatch_ask. " + "Do not use it for an exact replacement; use " + `dispatch_suggest instead. Body is at most 2,000 characters. ${ISSUE_REFERENCE}`,
@@ -31290,6 +31305,7 @@ var DISPATCH_PAYLOAD_SCHEMAS = {
31290
31305
  "artifact.version": ArtifactVersionEventPayloadSchema,
31291
31306
  "ask.opened": AskEventPayloadSchema,
31292
31307
  "ask.answered": AskEventPayloadSchema,
31308
+ "ask.resolved": AskEventPayloadSchema,
31293
31309
  "comment.created": CommentEventPayloadSchema,
31294
31310
  "comment.resolved": CommentEventPayloadSchema,
31295
31311
  "suggestion.accepted": CommentEventPayloadSchema,
@@ -31665,6 +31681,9 @@ class DispatchClient {
31665
31681
  async ask(issue, input) {
31666
31682
  return this.#json("POST", ["api", "v1", "issues", await this.#resolveIssue(issue), "asks"], input);
31667
31683
  }
31684
+ async resolveAsk(id, input) {
31685
+ return this.#json("POST", ["api", "v1", "asks", id, "resolve"], input);
31686
+ }
31668
31687
  async comment(issue, input) {
31669
31688
  return this.#json("POST", ["api", "v1", "issues", await this.#resolveIssue(issue), "comments"], input);
31670
31689
  }
@@ -31883,7 +31902,7 @@ function toolSchema(tool) {
31883
31902
  return dispatchToolSchema(spec, zodSchemaApi(exports_external), { strict: true });
31884
31903
  }
31885
31904
  async function resolveIssueArguments(tool, args, cwd, env, exec) {
31886
- if (tool === "dispatch_issue")
31905
+ if (tool === "dispatch_issue" || tool === "dispatch_resolve_ask")
31887
31906
  return { args, ref: null };
31888
31907
  const refArgument = args.ref;
31889
31908
  const ref = typeof refArgument === "string" ? parseDispatchRef(refArgument) ?? (() => {
@@ -31990,6 +32009,12 @@ function askSummary({ ask, replies }) {
31990
32009
  `- Selected: ${answer.selected.length === 0 ? "none" : answer.selected.join(", ")}`,
31991
32010
  ...answer.text === null ? [] : [`- Text: ${answer.text}`]
31992
32011
  ],
32012
+ ...ask.resolution === undefined ? [] : [
32013
+ "Resolution:",
32014
+ `- By: ${ask.resolution.actor.id}`,
32015
+ `- Kind: ${ask.resolution.kind}`,
32016
+ `- Reason: ${ask.resolution.reason}`
32017
+ ],
31993
32018
  "Replies:",
31994
32019
  ...chain.length === 0 ? ["- none"] : chain
31995
32020
  ].join(`
@@ -32034,7 +32059,7 @@ async function executeDispatchTool(input) {
32034
32059
  const args = toolSchema(input.tool).parse(issueArguments.args);
32035
32060
  const actor = toolActor(await resolveOrigin(env, exec, input.cwd), input);
32036
32061
  const client = new DispatchClient(input.config.url, input.config.token, input.fetchImpl);
32037
- const issueKey = input.tool === "dispatch_issue" ? null : await ensureIssue(client, stringArg(args, "issue"), actor);
32062
+ const issueKey = input.tool === "dispatch_issue" || input.tool === "dispatch_resolve_ask" ? null : await ensureIssue(client, stringArg(args, "issue"), actor);
32038
32063
  const issue = () => {
32039
32064
  if (issueKey === null)
32040
32065
  throw new Error("issue is required");
@@ -32058,6 +32083,26 @@ async function executeDispatchTool(input) {
32058
32083
  details: { issue: created.key, topic: dispatchIssueSubject(created.key, ">") }
32059
32084
  };
32060
32085
  }
32086
+ case "dispatch_resolve_ask": {
32087
+ const kind = stringArg(args, "kind");
32088
+ if (kind !== "retracted" && kind !== "resolved")
32089
+ throw new Error("kind must be retracted or resolved");
32090
+ const ask = await client.resolveAsk(stringArg(args, "ask"), {
32091
+ kind,
32092
+ reason: stringArg(args, "reason"),
32093
+ actor
32094
+ });
32095
+ if (ask.resolution === undefined)
32096
+ throw new Error("resolved ask is missing its resolution");
32097
+ return {
32098
+ text: `${kind === "retracted" ? "Retracted" : "Resolved"} ask ${ask.id}: ${ask.resolution.reason}`,
32099
+ details: {
32100
+ issue: ask.issue_key,
32101
+ topic: dispatchIssueSubject(ask.issue_key, ">"),
32102
+ ask: ask.id
32103
+ }
32104
+ };
32105
+ }
32061
32106
  case "dispatch_ask": {
32062
32107
  const anchorArgs = asObject(args.anchor);
32063
32108
  const resolved = anchorArgs ? await resolveArtifact(client, issue(), stringArg(anchorArgs, "artifact")) : undefined;
@@ -44,8 +44,20 @@ It returns `details` `{ issue, topic, ask }`. Options are buttons: never enumera
44
44
  prose. Put the recommendation in `question`, and put each selectable choice in `options`.
45
45
  Anchor a document question with `anchor: { artifact, quote, occurrence? }`; `occurrence` is
46
46
  zero-based and selects a repeated quote. An anchor whose quote disappears becomes orphaned but
47
- remains readable against its original document version. An ask stays open until a human answers;
48
- you cannot withdraw it. Ask once and well. The host steers you when a human answers.
47
+ remains readable against its original document version.
48
+
49
+ An ask stays open until a human answers, unless its question no longer needs that answer. Retract a
50
+ moot or superseded question, or self-resolve one after finding the answer:
51
+ ```ts
52
+ dispatch_resolve_ask({
53
+ ask,
54
+ kind: "retracted",
55
+ reason: "A newer ask supersedes this question.",
56
+ })
57
+ ```
58
+ Use `retracted` when the question is obsolete and `resolved` when you found the answer. Include the
59
+ reason because the question remains in its issue log and reply thread. Resolution is not an answer:
60
+ it never records a human decision, and an answered ask cannot be resolved.
49
61
 
50
62
  An ask is a thread, not a dead end: a human can reply to it before or after answering, and you
51
63
  (the asker) can reply too — e.g. acknowledging a clarifying question, or following up after the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/pi-legion-envoy",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "type": "module",
5
5
  "omp": {
6
6
  "extensions": [