@sjawhar/pi-legion-envoy 1.57.0 → 1.57.1

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
@@ -30052,7 +30052,7 @@ var dispatchToolSpecs = [
30052
30052
  },
30053
30053
  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.",
30054
30054
  arguments: (z) => ({
30055
- ask: z.string().describe("Ask id to edit."),
30055
+ ask: z.string().describe("Ask id (uuid); an 8+ hex prefix unique among this session's own open asks works too."),
30056
30056
  question: z.string({ max: ASK_QUESTION_MAX }).describe(`Replacement decision question, at most ${ASK_QUESTION_MAX} characters.`).optional(),
30057
30057
  options: z.array(z.object({
30058
30058
  label: z.string().describe("Selectable option label."),
@@ -30078,7 +30078,7 @@ var dispatchToolSpecs = [
30078
30078
  },
30079
30079
  description: "Retract an open question that is moot or resolve one after finding the answer. This closes the question without answering it.",
30080
30080
  arguments: (z) => ({
30081
- ask: z.string().describe("Ask id to close."),
30081
+ ask: z.string().describe("Ask id (uuid) to close; an 8+ hex prefix unique among this session's own open asks " + "works too."),
30082
30082
  kind: z.enum(["retracted", "resolved"]).describe("Whether the ask is retracted or self-resolved."),
30083
30083
  reason: z.string({ min: 1 }).describe("Why the open ask no longer needs a human answer.")
30084
30084
  })
@@ -30097,7 +30097,7 @@ var dispatchToolSpecs = [
30097
30097
  example: { ask: "01234567-0000-4000-8000-000000000001", action: "follow" },
30098
30098
  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>.>",
30099
30099
  arguments: (z) => ({
30100
- ask: z.string().describe("Full ask id (uuid)."),
30100
+ ask: z.string().describe("Ask id (uuid); an 8+ hex prefix unique among this session's own open asks works too."),
30101
30101
  action: z.enum(["follow", "unfollow"]).describe("follow | unfollow")
30102
30102
  }),
30103
30103
  strict: true
@@ -32863,24 +32863,51 @@ function messageIdOf(value) {
32863
32863
  return id === undefined ? undefined : normalizeUUID(id);
32864
32864
  }
32865
32865
  var idPrefixPattern = /^[0-9a-f][0-9a-f-]{7,}$/i;
32866
- async function resolveIdPrefix(tool, kind, ref, list) {
32867
- const fullID = normalizeUUID(ref.id);
32866
+ function refOwnerName(ref) {
32867
+ return ref.owner.kind === "issue" ? ref.owner.issue : `${ref.owner.project}/${ref.artifact}`;
32868
+ }
32869
+ async function resolveIdPrefix(tool, kind, id, ownerName, list) {
32870
+ const fullID = normalizeUUID(id);
32868
32871
  if (fullID !== undefined)
32869
32872
  return fullID;
32870
- const ownerName = ref.owner.kind === "issue" ? ref.owner.issue : `${ref.owner.project}/${ref.artifact}`;
32871
- if (!idPrefixPattern.test(ref.id)) {
32873
+ if (!idPrefixPattern.test(id)) {
32872
32874
  throw new ToolInputError(tool, [
32873
- `${kind} id ${ref.id} must be a full uuid or a prefix of at least 8 hex characters`
32875
+ `${kind} id ${id} must be a full uuid or a prefix of at least 8 hex characters`
32874
32876
  ]);
32875
32877
  }
32876
- const prefix = ref.id.toLowerCase();
32878
+ const prefix = id.toLowerCase();
32877
32879
  const matches = (await list()).filter((item) => item.id.toLowerCase().startsWith(prefix));
32878
32880
  if (matches.length === 1 && matches[0] !== undefined)
32879
32881
  return matches[0].id;
32880
32882
  throw new ToolInputError(tool, [
32881
- matches.length === 0 ? `${kind} id ${ref.id} matches none of the ${kind}s on ${ownerName}; use the full id` : `${kind} id ${ref.id} matches ${matches.length} ${kind}s on ${ownerName}; use the full id`
32883
+ matches.length === 0 ? `${kind} id ${id} matches none of the ${kind}s on ${ownerName}; use the full id` : `${kind} id ${id} matches ${matches.length} ${kind}s on ${ownerName}; use the full id`
32882
32884
  ]);
32883
32885
  }
32886
+ var askIdShapeProblem = "ask ids are uuids (a prefix of at least 8 hex characters works)";
32887
+ async function sessionOpenAsks(client, sessionId) {
32888
+ const session = sessionId?.trim();
32889
+ if (!session)
32890
+ throw new Error("host session id is required to read this session's open asks");
32891
+ return (await client.openAsks(session)).asks;
32892
+ }
32893
+ function openAskHints(asks) {
32894
+ if (asks.length === 0)
32895
+ return "you have no open asks";
32896
+ const hints = asks.slice(0, askHintLimit).map((ask) => `${ask.id.slice(0, 8)} \u2014 ${textHead(ask.question)}`);
32897
+ return `your open asks: ${hints.join("; ")}`;
32898
+ }
32899
+ async function resolveAskArgument(tool, args, client, sessionId) {
32900
+ const id = askId(args);
32901
+ if (normalizeUUID(id) === undefined && !idPrefixPattern.test(id)) {
32902
+ const asks = await sessionOpenAsks(client, sessionId).catch(() => {
32903
+ return;
32904
+ });
32905
+ throw new ToolInputError(tool, [
32906
+ asks === undefined ? askIdShapeProblem : `${askIdShapeProblem}; ${openAskHints(asks)}`
32907
+ ]);
32908
+ }
32909
+ return resolveIdPrefix(tool, "ask", id, "this session", () => sessionOpenAsks(client, sessionId));
32910
+ }
32884
32911
  function messageInReplyTo(args) {
32885
32912
  const inReplyTo = optionalString(args, "in_reply_to");
32886
32913
  return inReplyTo === undefined ? undefined : messageIdOf(inReplyTo);
@@ -32899,7 +32926,8 @@ function argumentProblems(tool, args) {
32899
32926
  break;
32900
32927
  }
32901
32928
  case "dispatch_edit_ask":
32902
- case "dispatch_resolve_ask": {
32929
+ case "dispatch_resolve_ask":
32930
+ case "dispatch_follow": {
32903
32931
  const ask = optionalString(args, "ask");
32904
32932
  if (ask?.startsWith("dispatch://") && parseDispatchRef(ask)?.kind !== "ask") {
32905
32933
  problems.push(askIdProblem);
@@ -33693,7 +33721,8 @@ async function executeDispatchTool(input) {
33693
33721
  }
33694
33722
  case "dispatch_resolve_ask": {
33695
33723
  const kind = stringArg(args, "kind");
33696
- const ask = await client.resolveAsk(stringArg(args, "ask"), {
33724
+ const id = await resolveAskArgument(input.tool, args, client, input.sessionId);
33725
+ const ask = await client.resolveAsk(id, {
33697
33726
  kind,
33698
33727
  reason: stringArg(args, "reason"),
33699
33728
  actor
@@ -33712,11 +33741,11 @@ async function executeDispatchTool(input) {
33712
33741
  let document;
33713
33742
  if (ref?.owner.kind === "issue") {
33714
33743
  const issueKey = ref.owner.issue;
33715
- id = await resolveIdPrefix(input.tool, "comment", ref, () => client.getComments(issueKey));
33744
+ id = await resolveIdPrefix(input.tool, "comment", ref.id, refOwnerName(ref), () => client.getComments(issueKey));
33716
33745
  } else if (ref !== null) {
33717
33746
  const artifact = (await resolveArtifact(client, ref.owner, ref.artifact)).artifact;
33718
33747
  document = artifact;
33719
- id = await resolveIdPrefix(input.tool, "comment", ref, () => client.getArtifactComments(artifact.id));
33748
+ id = await resolveIdPrefix(input.tool, "comment", ref.id, refOwnerName(ref), () => client.getArtifactComments(artifact.id));
33720
33749
  }
33721
33750
  const comment = await client.resolveComment(id, actor);
33722
33751
  const { label, details } = await commentOwnerResult(client, comment, document);
@@ -33760,7 +33789,8 @@ ${followsAsk(askOwner)}`,
33760
33789
  const options = args.options;
33761
33790
  const multiple = optionalBoolean(args, "multiple");
33762
33791
  const urgency = askUrgency(args);
33763
- const ask = await client.editAsk(askId(args), {
33792
+ const id = await resolveAskArgument(input.tool, args, client, input.sessionId);
33793
+ const ask = await client.editAsk(id, {
33764
33794
  ...question === undefined ? {} : { question },
33765
33795
  ...Array.isArray(options) ? { options } : {},
33766
33796
  ...multiple === undefined ? {} : { multiple },
@@ -33987,7 +34017,7 @@ ${trailer.join(`
33987
34017
  const sessionId = input.sessionId?.trim();
33988
34018
  if (!sessionId)
33989
34019
  throw new Error("host session id is required for dispatch_follow");
33990
- const ask = askId(args);
34020
+ const ask = await resolveAskArgument(input.tool, args, client, sessionId);
33991
34021
  const action = stringArg(args, "action");
33992
34022
  if (action === "unfollow") {
33993
34023
  await client.unfollowAsk(ask, sessionId, actor);
@@ -34003,7 +34033,7 @@ ${trailer.join(`
34003
34033
  case "dispatch_read": {
34004
34034
  if (ownerArguments.ref?.kind === "ask") {
34005
34035
  const ref = ownerArguments.ref;
34006
- const id = await resolveIdPrefix(input.tool, "ask", ref, async () => ref.owner.kind === "issue" ? client.listIssueAsks(ref.owner.issue) : client.getArtifactAsks((await resolveArtifact(client, ref.owner, ref.artifact)).artifact.id, "all"));
34036
+ const id = await resolveIdPrefix(input.tool, "ask", ref.id, refOwnerName(ref), async () => ref.owner.kind === "issue" ? client.listIssueAsks(ref.owner.issue) : client.getArtifactAsks((await resolveArtifact(client, ref.owner, ref.artifact)).artifact.id, "all"));
34007
34037
  const askRead = await client.getAsk(id);
34008
34038
  const askRef = refTarget(ref, "ask", id);
34009
34039
  return {
@@ -34013,7 +34043,7 @@ ${trailer.join(`
34013
34043
  }
34014
34044
  if (ownerArguments.ref?.kind === "comment") {
34015
34045
  const ref = ownerArguments.ref;
34016
- const id = await resolveIdPrefix(input.tool, "comment", ref, async () => ref.owner.kind === "issue" ? client.getComments(ref.owner.issue) : client.getArtifactComments((await resolveArtifact(client, ref.owner, ref.artifact)).artifact.id));
34046
+ const id = await resolveIdPrefix(input.tool, "comment", ref.id, refOwnerName(ref), async () => ref.owner.kind === "issue" ? client.getComments(ref.owner.issue) : client.getArtifactComments((await resolveArtifact(client, ref.owner, ref.artifact)).artifact.id));
34017
34047
  const comment = await client.getComment(id);
34018
34048
  const commentRef = refTarget(ref, "comment", id);
34019
34049
  return {
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.57.0",
16148
+ version: "1.57.1",
16149
16149
  type: "module",
16150
16150
  omp: {
16151
16151
  extensions: [
@@ -29371,7 +29371,7 @@ var dispatchToolSpecs = [
29371
29371
  },
29372
29372
  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.",
29373
29373
  arguments: (z) => ({
29374
- ask: z.string().describe("Ask id to edit."),
29374
+ ask: z.string().describe("Ask id (uuid); an 8+ hex prefix unique among this session's own open asks works too."),
29375
29375
  question: z.string({ max: ASK_QUESTION_MAX }).describe(`Replacement decision question, at most ${ASK_QUESTION_MAX} characters.`).optional(),
29376
29376
  options: z.array(z.object({
29377
29377
  label: z.string().describe("Selectable option label."),
@@ -29397,7 +29397,7 @@ var dispatchToolSpecs = [
29397
29397
  },
29398
29398
  description: "Retract an open question that is moot or resolve one after finding the answer. This closes the question without answering it.",
29399
29399
  arguments: (z) => ({
29400
- ask: z.string().describe("Ask id to close."),
29400
+ ask: z.string().describe("Ask id (uuid) to close; an 8+ hex prefix unique among this session's own open asks " + "works too."),
29401
29401
  kind: z.enum(["retracted", "resolved"]).describe("Whether the ask is retracted or self-resolved."),
29402
29402
  reason: z.string({ min: 1 }).describe("Why the open ask no longer needs a human answer.")
29403
29403
  })
@@ -29416,7 +29416,7 @@ var dispatchToolSpecs = [
29416
29416
  example: { ask: "01234567-0000-4000-8000-000000000001", action: "follow" },
29417
29417
  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>.>",
29418
29418
  arguments: (z) => ({
29419
- ask: z.string().describe("Full ask id (uuid)."),
29419
+ ask: z.string().describe("Ask id (uuid); an 8+ hex prefix unique among this session's own open asks works too."),
29420
29420
  action: z.enum(["follow", "unfollow"]).describe("follow | unfollow")
29421
29421
  }),
29422
29422
  strict: true
@@ -708,7 +708,9 @@ the host tells you once per ask. Leave a thread you no longer need, or rejoin on
708
708
  dispatch_follow({ ask, action: "follow" | "unfollow" })
709
709
  ```
710
710
 
711
- `ask` is the full ask id or a `dispatch://KEY/ask/<id>` reference. A human may also remove you from the ask card; either way you are
711
+ `ask` is the full ask id or a `dispatch://KEY/ask/<id>` reference; `dispatch_follow`, `dispatch_edit_ask`, and
712
+ `dispatch_resolve_ask` also take an 8+ hex prefix that is unique among your own open asks, and refuse anything shorter by naming
713
+ those asks. A human may also remove you from the ask card; either way you are
712
714
  told with an `ask.follower_removed` notice, and a human adding you arrives as `ask.follower_added`.
713
715
 
714
716
  No write subscribes you to an issue or document. Following covers your own asks and the threads you joined; everything else on the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/pi-legion-envoy",
3
- "version": "1.57.0",
3
+ "version": "1.57.1",
4
4
  "type": "module",
5
5
  "omp": {
6
6
  "extensions": [