@sjawhar/pi-legion-envoy 1.5.0 → 1.7.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
@@ -103,14 +103,17 @@ Configure the shared `envoy.json` with:
103
103
  ```
104
104
 
105
105
  The user file is `~/.config/opencode/envoy.json`; a
106
- `<cwd>/.opencode/envoy.json` file shallow-merges over it. `DISPATCH_URL` and
107
- `DISPATCH_TOKEN` override the file values for one process; `DISPATCH_TOKEN_FILE`
108
- (a path whose trimmed contents are the token — how the Legion daemon delivers it
109
- to a pane) wins over both and never falls back when unreadable. Omitting
110
- `dispatch.serverUrl` while `dispatch.enabled` is true targets
106
+ `<cwd>/.opencode/envoy.json` file shallow-merges over it. A repository
107
+ `dispatch.serverUrl` requires `dispatch.token` in that same repository file:
108
+ it never combines with a user-file or process-environment credential. To
109
+ override a repository endpoint for one process, set `DISPATCH_URL` together
110
+ with `DISPATCH_TOKEN` or `DISPATCH_TOKEN_FILE`. `DISPATCH_TOKEN_FILE` (a path
111
+ whose trimmed contents are the token — how the Legion daemon delivers it to a
112
+ pane) wins over every other token source and never falls back when unreadable.
113
+ Omitting `dispatch.serverUrl` while `dispatch.enabled` is true targets
111
114
  `http://localhost:8766`, the Go server's listen address. Invalid configuration,
112
- an invalid URL, or an empty token leaves the twelve tools unavailable and reports
113
- the source of the error.
115
+ an invalid URL, or an empty token leaves the twelve tools unavailable and
116
+ reports the source of the error.
114
117
 
115
118
  Owner-scoped calls use either an issue (a native `KEY` or external `owner/repo#n` reference) or
116
119
  an unlinked project document (`project` plus its `artifact` slug). A Legion session may omit
package/dist/envoy.js CHANGED
@@ -29662,7 +29662,9 @@ var DispatchEventSchema = object({
29662
29662
  });
29663
29663
  var IssueEventPayloadSchema = object({
29664
29664
  title: string2().optional(),
29665
+ labels: array(string2()).optional(),
29665
29666
  status: string2().optional(),
29667
+ rank: string2().optional(),
29666
29668
  route: string2().nullish()
29667
29669
  });
29668
29670
  var ArtifactCreatedEventPayloadSchema = object({
@@ -29836,7 +29838,8 @@ var dispatchToolSpecs = [
29836
29838
  parent: z.string().describe("Optional parent issue.").optional(),
29837
29839
  external: z.string().describe("Optional external issue reference.").optional(),
29838
29840
  force: z.boolean().describe("Create even though POSSIBLE_DUPLICATE listed similar issues; pass it only after reading them.").optional(),
29839
- spec: z.string().describe(`Optional initial primary-document markdown. ${SPEC_WRITING_GUIDANCE}`).optional()
29841
+ spec: z.string().describe(`Optional initial primary-document markdown. ${SPEC_WRITING_GUIDANCE}`).optional(),
29842
+ labels: z.array(z.string({ min: 1, max: 40 }), { max: 20 }).describe("Optional initial labels, at most 20 labels of up to 40 characters.").optional()
29840
29843
  })
29841
29844
  },
29842
29845
  {
@@ -29845,7 +29848,7 @@ var dispatchToolSpecs = [
29845
29848
  arguments: (z) => ({
29846
29849
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29847
29850
  project: z.string().describe("Project key owning the document.").optional(),
29848
- artifact: z.string().describe("Project document slug or id.").optional(),
29851
+ artifact: z.string().describe("Project document artifact id, slug, or filename.").optional(),
29849
29852
  ref: z.string().describe("Optional dispatch:// issue or document reference.").optional(),
29850
29853
  question: z.string({ max: 800 }).describe("Decision question, at most 800 characters."),
29851
29854
  options: z.array(z.object({
@@ -29898,7 +29901,7 @@ var dispatchToolSpecs = [
29898
29901
  arguments: (z) => ({
29899
29902
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29900
29903
  project: z.string().describe("Project key owning the document.").optional(),
29901
- artifact: z.string().describe("Artifact slug or id required when quote is given.").optional(),
29904
+ artifact: z.string().describe("Project document artifact id, slug, or filename required when quote is given.").optional(),
29902
29905
  ref: z.string().describe("Optional dispatch:// issue or document reference.").optional(),
29903
29906
  quote: z.string().describe("Optional exact quoted document text.").optional(),
29904
29907
  occurrence: z.number({ int: true, min: 0 }).describe("Optional zero-based occurrence of quote.").optional(),
@@ -29914,7 +29917,7 @@ var dispatchToolSpecs = [
29914
29917
  arguments: (z) => ({
29915
29918
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29916
29919
  project: z.string().describe("Project key owning the document.").optional(),
29917
- artifact: z.string().describe("Artifact slug or id containing the quoted text; optional when ref names it.").optional(),
29920
+ artifact: z.string().describe("Project document artifact id, slug, or filename containing the quoted text; optional when ref names it.").optional(),
29918
29921
  ref: z.string().describe("Optional dispatch:// issue or document reference.").optional(),
29919
29922
  quote: z.string().describe("Exact document text to replace."),
29920
29923
  replace_with: z.string().describe("Replacement text."),
@@ -29938,7 +29941,7 @@ var dispatchToolSpecs = [
29938
29941
  arguments: (z) => ({
29939
29942
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29940
29943
  project: z.string().describe("Project key owning the document.").optional(),
29941
- artifact: z.string().describe("Artifact slug or id for the document; optional when ref names it.").optional(),
29944
+ artifact: z.string().describe("Project document artifact id, slug, or filename; optional when ref names it.").optional(),
29942
29945
  ref: z.string().describe("Optional dispatch:// issue or document reference.").optional(),
29943
29946
  ops: z.array(z.object({
29944
29947
  op: z.enum(DOC_EDIT_OPS).describe("Edit operation."),
@@ -29959,7 +29962,7 @@ var dispatchToolSpecs = [
29959
29962
  arguments: (z) => ({
29960
29963
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29961
29964
  project: z.string().describe("Project key owning the document.").optional(),
29962
- artifact: z.string().describe("Optional artifact slug or id; primary document by default for an issue.").optional(),
29965
+ artifact: z.string().describe("Optional project document artifact id, slug, or filename; primary document by default for an issue.").optional(),
29963
29966
  version: z.number({ int: true, min: 1 }).describe("Optional version number.").optional(),
29964
29967
  ref: z.string().describe("Optional dispatch:// document reference.").optional()
29965
29968
  }),
@@ -29971,7 +29974,7 @@ var dispatchToolSpecs = [
29971
29974
  arguments: (z) => ({
29972
29975
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29973
29976
  project: z.string().describe("Project key owning the document.").optional(),
29974
- artifact: z.string().describe("Artifact slug or id; primary document by default for an issue.").optional()
29977
+ artifact: z.string().describe("Project document artifact id, slug, or filename; primary document by default for an issue.").optional()
29975
29978
  }),
29976
29979
  validation: documentOwnerValidation(true)
29977
29980
  },
@@ -30000,7 +30003,7 @@ var dispatchToolSpecs = [
30000
30003
  arguments: (z) => ({
30001
30004
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
30002
30005
  project: z.string().describe("Project key owning the document.").optional(),
30003
- artifact: z.string().describe("Project document slug or id.").optional(),
30006
+ artifact: z.string().describe("Project document artifact id, slug, or filename.").optional(),
30004
30007
  ref: z.string().describe("Optional dispatch:// issue or document reference.").optional()
30005
30008
  }),
30006
30009
  validation: documentOwnerValidation(true)
@@ -31300,10 +31303,25 @@ function resolveDispatchConfig(env, options = {}) {
31300
31303
  return { enabled: false, url: null, token: null, error: file.reason };
31301
31304
  }
31302
31305
  }
31303
- const merged = {
31304
- ...userFile.kind === "valid" ? userFile.settings : null,
31305
- ...repoFile.kind === "valid" ? repoFile.settings : null
31306
- };
31306
+ const userSettings = userFile.kind === "valid" ? userFile.settings : null;
31307
+ const repoSettings = repoFile.kind === "valid" ? repoFile.settings : null;
31308
+ const merged = { ...userSettings, ...repoSettings };
31309
+ const repoURL = repoSettings?.serverUrl;
31310
+ if (explicitUrl === undefined && merged.enabled === true && repoURL !== undefined) {
31311
+ const token = repoSettings?.token ?? null;
31312
+ if (!token) {
31313
+ return {
31314
+ enabled: false,
31315
+ url: null,
31316
+ token: null,
31317
+ error: "repository dispatch.serverUrl requires dispatch.token from the same .opencode/envoy.json or DISPATCH_URL with DISPATCH_TOKEN"
31318
+ };
31319
+ }
31320
+ const url2 = parsedDispatchUrl(repoURL, "repository dispatch.serverUrl");
31321
+ if (url2.error !== null)
31322
+ return { enabled: false, url: null, token: null, error: url2.error };
31323
+ return { enabled: true, url: url2.url, token, error: null };
31324
+ }
31307
31325
  const rawUrl = explicitUrl !== undefined ? { value: explicitUrl, source: "DISPATCH_URL" } : merged.enabled === true ? { value: merged.serverUrl ?? DEFAULT_SERVER_URL, source: "dispatch.serverUrl" } : null;
31308
31326
  const url2 = rawUrl ? parsedDispatchUrl(rawUrl.value, rawUrl.source) : { url: null, error: null };
31309
31327
  let token;
@@ -31876,7 +31894,7 @@ async function resolveOwnerArguments(tool, args, cwd, env, exec) {
31876
31894
  return { args, ref: null, owner: null };
31877
31895
  const refArgument = args.ref;
31878
31896
  const ref = typeof refArgument === "string" ? parseDispatchRef(refArgument) ?? (() => {
31879
- throw new Error("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>, or " + "dispatch://PROJECT/artifact/<slug>");
31897
+ throw new Error("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>, or " + "dispatch://PROJECT/artifact/<document-ref> (an artifact id, slug, or filename)");
31880
31898
  })() : null;
31881
31899
  const issueArgument = args.issue;
31882
31900
  const projectArgument = args.project;
@@ -31957,14 +31975,16 @@ async function resolveArtifact(client, owner, artifactReference) {
31957
31975
  if (!(error instanceof DispatchServiceError) || error.status !== 404)
31958
31976
  throw error;
31959
31977
  const artifacts = await client.listProjectArtifacts(owner.project, true);
31960
- const matches = artifacts.filter((candidate) => candidate.name === artifactReference);
31961
- if (matches.length > 1) {
31962
- throw new Error(`artifact name ${artifactReference} is ambiguous in project ${owner.project}; ` + `${matches.length} documents share it \u2014 use its slug instead`);
31963
- }
31964
- const artifact = matches[0];
31965
- if (!artifact)
31978
+ const artifact = artifacts.find((candidate) => candidate.id === artifactReference) ?? artifacts.find((candidate) => candidate.slug === artifactReference);
31979
+ if (artifact)
31980
+ return { owner, artifact };
31981
+ const names = artifacts.filter((candidate) => candidate.name === artifactReference);
31982
+ if (names.length > 1) {
31983
+ throw new Error(`artifact name ${artifactReference} is ambiguous in project ${owner.project}; ` + `${names.length} documents share it \u2014 use its slug instead`);
31984
+ }
31985
+ if (names[0] === undefined)
31966
31986
  throw error;
31967
- return { owner, artifact };
31987
+ return { owner, artifact: names[0] };
31968
31988
  }
31969
31989
  }
31970
31990
  const issue = await client.getIssue(owner.issue);
@@ -32015,6 +32035,7 @@ function issueSummary(issue, events, references) {
32015
32035
  `Title: ${issue.title}`,
32016
32036
  `Key: ${issue.key}`,
32017
32037
  `Status: ${issue.status}`,
32038
+ `Labels: ${issue.labels.length === 0 ? "none" : issue.labels.join(", ")}`,
32018
32039
  `Route: ${issue.route ?? "none"}`,
32019
32040
  ...specApproval === undefined ? [] : [`Spec ${specApproval.replace(/^Approval/, "approval")}`],
32020
32041
  "Open asks:",
@@ -32147,6 +32168,7 @@ async function executeDispatchTool(input) {
32147
32168
  const external = optionalString(args, "external");
32148
32169
  const force = optionalBoolean(args, "force");
32149
32170
  const spec = optionalString(args, "spec");
32171
+ const labels = args.labels;
32150
32172
  try {
32151
32173
  const created = await client.issue({
32152
32174
  project,
@@ -32155,6 +32177,7 @@ async function executeDispatchTool(input) {
32155
32177
  ...external === undefined ? {} : { external },
32156
32178
  ...force === undefined ? {} : { force },
32157
32179
  ...spec === undefined ? {} : { spec },
32180
+ ...Array.isArray(labels) ? { labels } : {},
32158
32181
  actor
32159
32182
  });
32160
32183
  return {
package/dist/legion.js CHANGED
@@ -29661,7 +29661,9 @@ var DispatchEventSchema = object({
29661
29661
  });
29662
29662
  var IssueEventPayloadSchema = object({
29663
29663
  title: string2().optional(),
29664
+ labels: array(string2()).optional(),
29664
29665
  status: string2().optional(),
29666
+ rank: string2().optional(),
29665
29667
  route: string2().nullish()
29666
29668
  });
29667
29669
  var ArtifactCreatedEventPayloadSchema = object({
@@ -29835,7 +29837,8 @@ var dispatchToolSpecs = [
29835
29837
  parent: z.string().describe("Optional parent issue.").optional(),
29836
29838
  external: z.string().describe("Optional external issue reference.").optional(),
29837
29839
  force: z.boolean().describe("Create even though POSSIBLE_DUPLICATE listed similar issues; pass it only after reading them.").optional(),
29838
- spec: z.string().describe(`Optional initial primary-document markdown. ${SPEC_WRITING_GUIDANCE}`).optional()
29840
+ spec: z.string().describe(`Optional initial primary-document markdown. ${SPEC_WRITING_GUIDANCE}`).optional(),
29841
+ labels: z.array(z.string({ min: 1, max: 40 }), { max: 20 }).describe("Optional initial labels, at most 20 labels of up to 40 characters.").optional()
29839
29842
  })
29840
29843
  },
29841
29844
  {
@@ -29844,7 +29847,7 @@ var dispatchToolSpecs = [
29844
29847
  arguments: (z) => ({
29845
29848
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29846
29849
  project: z.string().describe("Project key owning the document.").optional(),
29847
- artifact: z.string().describe("Project document slug or id.").optional(),
29850
+ artifact: z.string().describe("Project document artifact id, slug, or filename.").optional(),
29848
29851
  ref: z.string().describe("Optional dispatch:// issue or document reference.").optional(),
29849
29852
  question: z.string({ max: 800 }).describe("Decision question, at most 800 characters."),
29850
29853
  options: z.array(z.object({
@@ -29897,7 +29900,7 @@ var dispatchToolSpecs = [
29897
29900
  arguments: (z) => ({
29898
29901
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29899
29902
  project: z.string().describe("Project key owning the document.").optional(),
29900
- artifact: z.string().describe("Artifact slug or id required when quote is given.").optional(),
29903
+ artifact: z.string().describe("Project document artifact id, slug, or filename required when quote is given.").optional(),
29901
29904
  ref: z.string().describe("Optional dispatch:// issue or document reference.").optional(),
29902
29905
  quote: z.string().describe("Optional exact quoted document text.").optional(),
29903
29906
  occurrence: z.number({ int: true, min: 0 }).describe("Optional zero-based occurrence of quote.").optional(),
@@ -29913,7 +29916,7 @@ var dispatchToolSpecs = [
29913
29916
  arguments: (z) => ({
29914
29917
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29915
29918
  project: z.string().describe("Project key owning the document.").optional(),
29916
- artifact: z.string().describe("Artifact slug or id containing the quoted text; optional when ref names it.").optional(),
29919
+ artifact: z.string().describe("Project document artifact id, slug, or filename containing the quoted text; optional when ref names it.").optional(),
29917
29920
  ref: z.string().describe("Optional dispatch:// issue or document reference.").optional(),
29918
29921
  quote: z.string().describe("Exact document text to replace."),
29919
29922
  replace_with: z.string().describe("Replacement text."),
@@ -29937,7 +29940,7 @@ var dispatchToolSpecs = [
29937
29940
  arguments: (z) => ({
29938
29941
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29939
29942
  project: z.string().describe("Project key owning the document.").optional(),
29940
- artifact: z.string().describe("Artifact slug or id for the document; optional when ref names it.").optional(),
29943
+ artifact: z.string().describe("Project document artifact id, slug, or filename; optional when ref names it.").optional(),
29941
29944
  ref: z.string().describe("Optional dispatch:// issue or document reference.").optional(),
29942
29945
  ops: z.array(z.object({
29943
29946
  op: z.enum(DOC_EDIT_OPS).describe("Edit operation."),
@@ -29958,7 +29961,7 @@ var dispatchToolSpecs = [
29958
29961
  arguments: (z) => ({
29959
29962
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29960
29963
  project: z.string().describe("Project key owning the document.").optional(),
29961
- artifact: z.string().describe("Optional artifact slug or id; primary document by default for an issue.").optional(),
29964
+ artifact: z.string().describe("Optional project document artifact id, slug, or filename; primary document by default for an issue.").optional(),
29962
29965
  version: z.number({ int: true, min: 1 }).describe("Optional version number.").optional(),
29963
29966
  ref: z.string().describe("Optional dispatch:// document reference.").optional()
29964
29967
  }),
@@ -29970,7 +29973,7 @@ var dispatchToolSpecs = [
29970
29973
  arguments: (z) => ({
29971
29974
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
29972
29975
  project: z.string().describe("Project key owning the document.").optional(),
29973
- artifact: z.string().describe("Artifact slug or id; primary document by default for an issue.").optional()
29976
+ artifact: z.string().describe("Project document artifact id, slug, or filename; primary document by default for an issue.").optional()
29974
29977
  }),
29975
29978
  validation: documentOwnerValidation(true)
29976
29979
  },
@@ -29999,7 +30002,7 @@ var dispatchToolSpecs = [
29999
30002
  arguments: (z) => ({
30000
30003
  issue: z.string().describe(ISSUE_REFERENCE).optional(),
30001
30004
  project: z.string().describe("Project key owning the document.").optional(),
30002
- artifact: z.string().describe("Project document slug or id.").optional(),
30005
+ artifact: z.string().describe("Project document artifact id, slug, or filename.").optional(),
30003
30006
  ref: z.string().describe("Optional dispatch:// issue or document reference.").optional()
30004
30007
  }),
30005
30008
  validation: documentOwnerValidation(true)
@@ -31726,10 +31729,25 @@ function resolveDispatchConfig(env, options = {}) {
31726
31729
  return { enabled: false, url: null, token: null, error: file.reason };
31727
31730
  }
31728
31731
  }
31729
- const merged = {
31730
- ...userFile.kind === "valid" ? userFile.settings : null,
31731
- ...repoFile.kind === "valid" ? repoFile.settings : null
31732
- };
31732
+ const userSettings = userFile.kind === "valid" ? userFile.settings : null;
31733
+ const repoSettings = repoFile.kind === "valid" ? repoFile.settings : null;
31734
+ const merged = { ...userSettings, ...repoSettings };
31735
+ const repoURL = repoSettings?.serverUrl;
31736
+ if (explicitUrl === undefined && merged.enabled === true && repoURL !== undefined) {
31737
+ const token = repoSettings?.token ?? null;
31738
+ if (!token) {
31739
+ return {
31740
+ enabled: false,
31741
+ url: null,
31742
+ token: null,
31743
+ error: "repository dispatch.serverUrl requires dispatch.token from the same .opencode/envoy.json or DISPATCH_URL with DISPATCH_TOKEN"
31744
+ };
31745
+ }
31746
+ const url2 = parsedDispatchUrl(repoURL, "repository dispatch.serverUrl");
31747
+ if (url2.error !== null)
31748
+ return { enabled: false, url: null, token: null, error: url2.error };
31749
+ return { enabled: true, url: url2.url, token, error: null };
31750
+ }
31733
31751
  const rawUrl = explicitUrl !== undefined ? { value: explicitUrl, source: "DISPATCH_URL" } : merged.enabled === true ? { value: merged.serverUrl ?? DEFAULT_SERVER_URL, source: "dispatch.serverUrl" } : null;
31734
31752
  const url2 = rawUrl ? parsedDispatchUrl(rawUrl.value, rawUrl.source) : { url: null, error: null };
31735
31753
  let token;
@@ -32302,7 +32320,7 @@ async function resolveOwnerArguments(tool, args, cwd, env, exec) {
32302
32320
  return { args, ref: null, owner: null };
32303
32321
  const refArgument = args.ref;
32304
32322
  const ref = typeof refArgument === "string" ? parseDispatchRef(refArgument) ?? (() => {
32305
- throw new Error("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>, or " + "dispatch://PROJECT/artifact/<slug>");
32323
+ throw new Error("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>, or " + "dispatch://PROJECT/artifact/<document-ref> (an artifact id, slug, or filename)");
32306
32324
  })() : null;
32307
32325
  const issueArgument = args.issue;
32308
32326
  const projectArgument = args.project;
@@ -32383,14 +32401,16 @@ async function resolveArtifact(client, owner, artifactReference) {
32383
32401
  if (!(error instanceof DispatchServiceError) || error.status !== 404)
32384
32402
  throw error;
32385
32403
  const artifacts = await client.listProjectArtifacts(owner.project, true);
32386
- const matches = artifacts.filter((candidate) => candidate.name === artifactReference);
32387
- if (matches.length > 1) {
32388
- throw new Error(`artifact name ${artifactReference} is ambiguous in project ${owner.project}; ` + `${matches.length} documents share it \u2014 use its slug instead`);
32389
- }
32390
- const artifact = matches[0];
32391
- if (!artifact)
32404
+ const artifact = artifacts.find((candidate) => candidate.id === artifactReference) ?? artifacts.find((candidate) => candidate.slug === artifactReference);
32405
+ if (artifact)
32406
+ return { owner, artifact };
32407
+ const names = artifacts.filter((candidate) => candidate.name === artifactReference);
32408
+ if (names.length > 1) {
32409
+ throw new Error(`artifact name ${artifactReference} is ambiguous in project ${owner.project}; ` + `${names.length} documents share it \u2014 use its slug instead`);
32410
+ }
32411
+ if (names[0] === undefined)
32392
32412
  throw error;
32393
- return { owner, artifact };
32413
+ return { owner, artifact: names[0] };
32394
32414
  }
32395
32415
  }
32396
32416
  const issue = await client.getIssue(owner.issue);
@@ -32441,6 +32461,7 @@ function issueSummary(issue, events, references) {
32441
32461
  `Title: ${issue.title}`,
32442
32462
  `Key: ${issue.key}`,
32443
32463
  `Status: ${issue.status}`,
32464
+ `Labels: ${issue.labels.length === 0 ? "none" : issue.labels.join(", ")}`,
32444
32465
  `Route: ${issue.route ?? "none"}`,
32445
32466
  ...specApproval === undefined ? [] : [`Spec ${specApproval.replace(/^Approval/, "approval")}`],
32446
32467
  "Open asks:",
@@ -32573,6 +32594,7 @@ async function executeDispatchTool(input) {
32573
32594
  const external = optionalString(args, "external");
32574
32595
  const force = optionalBoolean(args, "force");
32575
32596
  const spec = optionalString(args, "spec");
32597
+ const labels = args.labels;
32576
32598
  try {
32577
32599
  const created = await client.issue({
32578
32600
  project,
@@ -32581,6 +32603,7 @@ async function executeDispatchTool(input) {
32581
32603
  ...external === undefined ? {} : { external },
32582
32604
  ...force === undefined ? {} : { force },
32583
32605
  ...spec === undefined ? {} : { spec },
32606
+ ...Array.isArray(labels) ? { labels } : {},
32584
32607
  actor
32585
32608
  });
32586
32609
  return {
@@ -72,12 +72,15 @@ exactly one owner to every owner-scoped tool: `issue` for an issue, or `project`
72
72
  [References](#references) for the resulting ref shape). On first use, an external issue reference creates its native issue in the
73
73
  project configured for that repository in Dispatch Settings, then falls back to `DISPATCH_DEFAULT_PROJECT`.
74
74
 
75
+ Issue reads include `rank`, the server-owned ordering key used by project boards; reorder through `PATCH /api/v1/issues/{key}` with neighboring issue keys rather than writing a priority value.
76
+
75
77
  Architects create newly tracked child work with:
76
78
  ```ts
77
- dispatch_issue({ project, title, parent?, external?, spec?, force? })
79
+ dispatch_issue({ project, title, parent?, external?, spec?, force?, labels?: string[] })
78
80
  ```
79
- It returns `details` `{ issue, topic }`. Use `dispatch_issue` only to create an issue; never use it to park a question. When `spec` is
80
- supplied, follow [Writing a spec](#writing-a-spec).
81
+ `labels` are optional initial labels: Dispatch trims them, preserves their case, and removes case-insensitive duplicates. It returns
82
+ `details` `{ issue, topic }`. Use `dispatch_issue` only to create an issue; never use it to park a question. When `spec` is supplied,
83
+ follow [Writing a spec](#writing-a-spec).
81
84
 
82
85
  ## Search first
83
86
 
@@ -186,7 +189,7 @@ Read the current document before changing it:
186
189
  dispatch_doc_read({ issue?, project?, artifact?, version?, ref? })
187
190
  ```
188
191
  It returns live or versioned markdown with open marks. `issue` with an omitted `artifact` reads the issue specification; a project needs
189
- `artifact`; and a `dispatch://PROJECT/artifact/<slug>` ref supplies both. Then write with:
192
+ `artifact`; and a `dispatch://PROJECT/artifact/<document-ref>` ref supplies both, where `document-ref` is the id, slug, or filename.
190
193
 
191
194
  ```ts
192
195
  dispatch_doc_edit({ issue?, project?, artifact, ops, summary? })
@@ -264,7 +267,8 @@ Exactly one of `issue` and `project` is required. A project upload creates an un
264
267
  Exactly one of `path` and `content` is required. It returns issue or project-document owner details plus `artifact`, `version`, and its
265
268
  write `topic`. Uploading the same `name` creates its next version — so uploading `spec.md` **replaces the issue's own specification**
266
269
  with your text. Never do that: the spec is edited in place with `dispatch_doc_edit` (see [The Spec](#the-spec)). Address an existing
267
- artifact by the slug shown in the upload result or by its filename; the slug also arrives on `artifact.created` events.
270
+ artifact by the slug shown in the upload result or by its filename, and a project document by its artifact id, slug, or filename; the
271
+ slug also arrives on `artifact.created` events.
268
272
 
269
273
  ## Messages
270
274
 
@@ -313,9 +317,9 @@ dispatch://KEY/artifact/<slug>[@vN]
313
317
  dispatch://KEY/ask/<id>
314
318
  dispatch://KEY/comment/<id>
315
319
  dispatch://KEY/message/<id>
316
- dispatch://PROJECT/artifact/<slug>[@vN]
317
- dispatch://PROJECT/artifact/<slug>/ask/<id>
318
- dispatch://PROJECT/artifact/<slug>/comment/<id>
320
+ dispatch://PROJECT/artifact/<document-ref>[@vN]
321
+ dispatch://PROJECT/artifact/<document-ref>/ask/<id>
322
+ dispatch://PROJECT/artifact/<document-ref>/comment/<id>
319
323
  ```
320
324
 
321
325
  A bare UUID or `KEY#seq` is not a reference; the `dispatch://` form is what Dispatch links and records.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/pi-legion-envoy",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "type": "module",
5
5
  "omp": {
6
6
  "extensions": [