@sjawhar/opencode-legion-envoy 0.23.2 → 0.25.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.
@@ -13594,7 +13594,7 @@ function dispatchToolSchema(spec, z, opts) {
13594
13594
  const shape = spec.arguments(z);
13595
13595
  return spec.validation === undefined ? z.object(shape, opts) : z.refineObject(shape, spec.validation.check, spec.validation.message, opts);
13596
13596
  }
13597
- var ISSUE_REFERENCE = "An issue is a native KEY or external owner/repo#n reference; an external reference creates its native issue on first use in the repository's mapped project (DISPATCH_REPO_PROJECTS) or, failing that, the default project (DISPATCH_DEFAULT_PROJECT).";
13597
+ var ISSUE_REFERENCE = "An issue is a native KEY or external owner/repo#n reference; an external reference creates its native issue in the repository's dashboard-configured project or, failing that, the default project (DISPATCH_DEFAULT_PROJECT).";
13598
13598
  var ASK_URGENCIES = ["low", "med", "high", "blocking"];
13599
13599
  var DOC_EDIT_OPS = ["replace", "delete", "insert"];
13600
13600
  var dispatchToolSpecs = [
@@ -13948,25 +13948,10 @@ var LegionDaemonApi = {
13948
13948
  request: architectCapability.extend({ issue: nonEmptyString, comment: string2().optional() }),
13949
13949
  response: object({})
13950
13950
  },
13951
- SpawnToken: {
13952
- request: architectCapability.extend({ issue: nonEmptyString, role: legionRole }),
13953
- response: object({ spawnToken: nonEmptyString })
13954
- },
13955
13951
  ProvisioningCredential: {
13956
13952
  request: architectCapability.extend({ issue: nonEmptyString }),
13957
13953
  response: object({ token: nonEmptyString })
13958
13954
  },
13959
- RoleBacking: {
13960
- request: strictObject({
13961
- tree: nonEmptyString,
13962
- issue: nonEmptyString,
13963
- role: legionRole,
13964
- sessionId: nonEmptyString,
13965
- agentId: nonEmptyString,
13966
- spawnToken: nonEmptyString
13967
- }),
13968
- response: object({})
13969
- },
13970
13955
  WorkerStarted: {
13971
13956
  request: strictObject({
13972
13957
  tree: nonEmptyString,
@@ -14013,20 +13998,6 @@ var LegionDaemonApi = {
14013
13998
  roleToken: nonEmptyString
14014
13999
  })
14015
14000
  },
14016
- Phase: {
14017
- request: strictObject({
14018
- tree: nonEmptyString,
14019
- issue: nonEmptyString,
14020
- phase: nonEmptyString,
14021
- sessionId: nonEmptyString,
14022
- spawnToken: nonEmptyString
14023
- }),
14024
- response: object({
14025
- secret: nonEmptyString,
14026
- gitName: nonEmptyString,
14027
- gitEmail: nonEmptyString
14028
- })
14029
- },
14030
14001
  WorkerSession: {
14031
14002
  request: strictObject({
14032
14003
  sessionId: nonEmptyString,
@@ -14065,6 +14036,10 @@ var LegionDaemonApi = {
14065
14036
  response: object({ token: nonEmptyString, appLogin: string2().endsWith("[bot]") })
14066
14037
  }
14067
14038
  };
14039
+ // ../contracts/src/repo.ts
14040
+ function canonicalRepo(owner, repo) {
14041
+ return `${owner.trim().toLowerCase()}/${repo.trim().toLowerCase().replace(/\.git$/, "")}`;
14042
+ }
14068
14043
  // ../contracts/src/tool-schema.ts
14069
14044
  function zodSchemaApi(zod) {
14070
14045
  const api = zod;
@@ -14280,7 +14255,7 @@ function parseGitHubRemoteUrl(url) {
14280
14255
  for (const pattern of GITHUB_REMOTE_PATTERNS) {
14281
14256
  const match = trimmed.match(pattern);
14282
14257
  if (match)
14283
- return `${match[1]}/${match[2]}`;
14258
+ return canonicalRepo(match[1] ?? "", match[2] ?? "");
14284
14259
  }
14285
14260
  return null;
14286
14261
  }
@@ -14514,6 +14489,10 @@ class DispatchClient {
14514
14489
  var nativeIssueKeyPattern = /^[A-Z][A-Z0-9]{1,9}-[0-9]+$/;
14515
14490
  var externalIssueRefPattern = /^([^/\s]+)\/([^/\s#]+)#([1-9][0-9]*)$/;
14516
14491
  var bareIssueNumberPattern = /^[1-9][0-9]*$/;
14492
+ function canonicalExternalIssueRef(value) {
14493
+ const match = value.trim().match(externalIssueRefPattern);
14494
+ return match ? `${canonicalRepo(match[1] ?? "", match[2] ?? "")}#${match[3]}` : value;
14495
+ }
14517
14496
  function stringArg(args, name) {
14518
14497
  const value = args[name];
14519
14498
  if (typeof value !== "string")
@@ -14583,7 +14562,7 @@ async function resolveIssueArguments(tool, args, cwd, env, exec) {
14583
14562
  return {
14584
14563
  args: {
14585
14564
  ...args,
14586
- ...issueArgument === undefined && ref?.issue !== undefined ? { issue: ref.issue } : {},
14565
+ ...typeof issueArgument === "string" ? { issue: canonicalExternalIssueRef(issueArgument) } : issueArgument === undefined && ref?.issue !== undefined ? { issue: ref.issue } : {},
14587
14566
  ...artifactArgument === undefined && (ref?.kind === "spec" || ref?.kind === "artifact") ? { artifact: ref.id } : {},
14588
14567
  ...versionArgument === undefined && ref?.version !== undefined ? { version: ref.version } : {}
14589
14568
  },
@@ -14594,7 +14573,7 @@ async function resolveIssueArguments(tool, args, cwd, env, exec) {
14594
14573
  if (!legionIssue)
14595
14574
  throw new Error("issue is required; supply issue or set LEGION_ISSUE");
14596
14575
  if (nativeIssueKeyPattern.test(legionIssue) || externalIssueRefPattern.test(legionIssue)) {
14597
- return { args: { ...args, issue: legionIssue }, ref: null };
14576
+ return { args: { ...args, issue: canonicalExternalIssueRef(legionIssue) }, ref: null };
14598
14577
  }
14599
14578
  if (!bareIssueNumberPattern.test(legionIssue)) {
14600
14579
  throw new Error("LEGION_ISSUE must be a native issue key (e.g. LEGION-3), an external owner/repo#n reference, or a bare positive issue number");
@@ -14927,7 +14906,7 @@ async function ensureIssue(client, issueReference, actor) {
14927
14906
  } catch (error) {
14928
14907
  if (error instanceof DispatchServiceError && error.code === "PROJECT_UNMAPPED") {
14929
14908
  const repository = issueReference.slice(0, issueReference.lastIndexOf("#"));
14930
- throw new Error(`repository ${repository} is not mapped in DISPATCH_REPO_PROJECTS and no DISPATCH_DEFAULT_PROJECT is configured`);
14909
+ throw new Error(`repository ${repository} is not mapped in repository settings and no DISPATCH_DEFAULT_PROJECT is configured`);
14931
14910
  }
14932
14911
  throw error;
14933
14912
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/opencode-legion-envoy",
3
- "version": "0.23.2",
3
+ "version": "0.25.0",
4
4
  "type": "module",
5
5
  "main": "dist/src/server.js",
6
6
  "exports": {
@@ -18,7 +18,7 @@ Every session works on an issue. Legion pre-fills `issue` from `LEGION_ISSUE`: u
18
18
  such as `LEGION-3`, an external `owner/repo#n` reference, or a bare positive number (resolved
19
19
  against the cwd repository). Otherwise pass the issue to every issue-scoped tool as its native key
20
20
  or an external `owner/repo#n` reference. On first use, an external reference creates its native issue in the
21
- project mapped by `DISPATCH_REPO_PROJECTS`.
21
+ project configured for that repository in Dispatch Settings, then falls back to `DISPATCH_DEFAULT_PROJECT`.
22
22
 
23
23
  Architects create newly tracked child work with:
24
24
  ```ts
@@ -213,7 +213,7 @@ corresponding lifecycle procedure.
213
213
  | `pr-closed-unmerged` | Decide from current scope whether to reopen the work, send a fresh implementer, or cancel it with a reason. Delegate the repository action to the responsible phase worker and keep ownership. |
214
214
  | `issue-comment` | Interpret the comment in the issue's design context. Answer it, adjust the plan, or relay it via `envoy_publish` to the responsible worker's role token; scope and product decisions remain with you. |
215
215
  | `catchup-overseer` | Verify its gates, child counts, and PR verdicts against current artifacts, then resume the applicable numbered lifecycle step. It is a current-state snapshot, not a raw-event replay. For each entry in its `phaseCompletions` (`{issue, role, summary, at}`, phases that completed while you were not live), handle it exactly as a `phase-complete` wake. |
216
- | `revive-worker` | The extension has revived the backed worker. Do not create a duplicate; message the restored worker via `envoy_publish` to its role token if action is needed and rely on its committed handoff over recollection. |
216
+ | `worker-died` | Payload `{type:"worker-died", issue, role}`. The daemon probed and retried this role's worker through `MAX_LAUNCH_FAILURES` attempts and could not confirm a boot never a raw-event replay or a silent revive. Reassess the work and `spawn_worker` again for the role (it resumes the same agent via `--resume` if a session file survived) or reassign it if the failure looks environmental, not agent-specific. |
217
217
  | `reopened` | Reopen the root lifecycle: inspect the reason and current artifacts, reassess scope and children, and resume at the first applicable numbered step. |
218
218
 
219
219
  ## Escalation judgment