@codyswann/lisa 4.81.3 → 4.81.5

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.
Files changed (198) hide show
  1. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  2. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  3. package/dist/core/upstream-evidence-manifest.js +52 -14
  4. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  5. package/package.json +4 -4
  6. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  7. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  8. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/validate-config.mjs +30 -0
  9. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/SKILL.md +15 -8
  10. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/references/runbook-template.md +4 -3
  11. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-manager.mjs +5 -76
  12. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-queue.mjs +9 -3
  13. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-runtime.mjs +1 -0
  14. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-setup.mjs +165 -0
  15. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-usage.mjs +36 -9
  16. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/clipboard.mjs +119 -0
  17. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/config.mjs +22 -36
  18. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/launch.mjs +1 -0
  19. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/repo-detect.mjs +205 -0
  20. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/session-manager.mjs +16 -13
  21. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/setup-checks.mjs +168 -0
  22. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/token.mjs +98 -28
  23. package/plugins/lisa/.codex-plugin/skills/lisa-setup-session-manager/SKILL.md +57 -22
  24. package/plugins/lisa/rules/reference/config-resolution.md +1 -0
  25. package/plugins/lisa/scripts/ready-queue-order.mjs +34 -14
  26. package/plugins/lisa/skills/lisa-secrets-access/scripts/validate-config.mjs +30 -0
  27. package/plugins/lisa/skills/lisa-session-manager/SKILL.md +15 -8
  28. package/plugins/lisa/skills/lisa-session-manager/references/runbook-template.md +4 -3
  29. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-manager.mjs +5 -76
  30. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-queue.mjs +9 -3
  31. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-runtime.mjs +1 -0
  32. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-setup.mjs +165 -0
  33. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-usage.mjs +36 -9
  34. package/plugins/lisa/skills/lisa-session-manager/scripts/clipboard.mjs +119 -0
  35. package/plugins/lisa/skills/lisa-session-manager/scripts/config.mjs +22 -36
  36. package/plugins/lisa/skills/lisa-session-manager/scripts/launch.mjs +1 -0
  37. package/plugins/lisa/skills/lisa-session-manager/scripts/repo-detect.mjs +205 -0
  38. package/plugins/lisa/skills/lisa-session-manager/scripts/session-manager.mjs +16 -13
  39. package/plugins/lisa/skills/lisa-session-manager/scripts/setup-checks.mjs +168 -0
  40. package/plugins/lisa/skills/lisa-session-manager/scripts/token.mjs +98 -28
  41. package/plugins/lisa/skills/lisa-setup-session-manager/SKILL.md +57 -22
  42. package/plugins/lisa-agy/plugin.json +1 -1
  43. package/plugins/lisa-agy/scripts/ready-queue-order.mjs +34 -14
  44. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/validate-config.mjs +30 -0
  45. package/plugins/lisa-agy/skills/lisa-session-manager/SKILL.md +15 -8
  46. package/plugins/lisa-agy/skills/lisa-session-manager/references/runbook-template.md +4 -3
  47. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-manager.mjs +5 -76
  48. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-queue.mjs +9 -3
  49. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-runtime.mjs +1 -0
  50. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-setup.mjs +165 -0
  51. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-usage.mjs +36 -9
  52. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/clipboard.mjs +119 -0
  53. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/config.mjs +22 -36
  54. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/launch.mjs +1 -0
  55. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/repo-detect.mjs +205 -0
  56. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/session-manager.mjs +16 -13
  57. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/setup-checks.mjs +168 -0
  58. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/token.mjs +98 -28
  59. package/plugins/lisa-agy/skills/lisa-setup-session-manager/SKILL.md +57 -22
  60. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  63. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-cdk-devin/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +1 -1
  67. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-copilot/rules/reference/config-resolution.md +1 -0
  69. package/plugins/lisa-copilot/scripts/ready-queue-order.mjs +34 -14
  70. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/validate-config.mjs +30 -0
  71. package/plugins/lisa-copilot/skills/lisa-session-manager/SKILL.md +15 -8
  72. package/plugins/lisa-copilot/skills/lisa-session-manager/references/runbook-template.md +4 -3
  73. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-manager.mjs +5 -76
  74. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-queue.mjs +9 -3
  75. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-runtime.mjs +1 -0
  76. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-setup.mjs +165 -0
  77. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-usage.mjs +36 -9
  78. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/clipboard.mjs +119 -0
  79. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/config.mjs +22 -36
  80. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/launch.mjs +1 -0
  81. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/repo-detect.mjs +205 -0
  82. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/session-manager.mjs +16 -13
  83. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/setup-checks.mjs +168 -0
  84. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/token.mjs +98 -28
  85. package/plugins/lisa-copilot/skills/lisa-setup-session-manager/SKILL.md +57 -22
  86. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  87. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +1 -0
  88. package/plugins/lisa-cursor/scripts/ready-queue-order.mjs +34 -14
  89. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/validate-config.mjs +30 -0
  90. package/plugins/lisa-cursor/skills/lisa-session-manager/SKILL.md +15 -8
  91. package/plugins/lisa-cursor/skills/lisa-session-manager/references/runbook-template.md +4 -3
  92. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-manager.mjs +5 -76
  93. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-queue.mjs +9 -3
  94. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-runtime.mjs +1 -0
  95. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-setup.mjs +165 -0
  96. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-usage.mjs +36 -9
  97. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/clipboard.mjs +119 -0
  98. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/config.mjs +22 -36
  99. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/launch.mjs +1 -0
  100. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/repo-detect.mjs +205 -0
  101. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/session-manager.mjs +16 -13
  102. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/setup-checks.mjs +168 -0
  103. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/token.mjs +98 -28
  104. package/plugins/lisa-cursor/skills/lisa-setup-session-manager/SKILL.md +57 -22
  105. package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
  106. package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
  107. package/plugins/lisa-devin/rules/reference/config-resolution.md +1 -0
  108. package/plugins/lisa-devin/scripts/ready-queue-order.mjs +34 -14
  109. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/validate-config.mjs +30 -0
  110. package/plugins/lisa-devin/skills/lisa-session-manager/SKILL.md +15 -8
  111. package/plugins/lisa-devin/skills/lisa-session-manager/references/runbook-template.md +4 -3
  112. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-manager.mjs +5 -76
  113. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-queue.mjs +9 -3
  114. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-runtime.mjs +1 -0
  115. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-setup.mjs +165 -0
  116. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-usage.mjs +36 -9
  117. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/clipboard.mjs +119 -0
  118. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/config.mjs +22 -36
  119. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/launch.mjs +1 -0
  120. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/repo-detect.mjs +205 -0
  121. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/session-manager.mjs +16 -13
  122. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/setup-checks.mjs +168 -0
  123. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/token.mjs +98 -28
  124. package/plugins/lisa-devin/skills/lisa-setup-session-manager/SKILL.md +57 -22
  125. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  126. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  127. package/plugins/lisa-expo-agy/plugin.json +1 -1
  128. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  129. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  130. package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +1 -1
  131. package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +1 -1
  132. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  133. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  134. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  135. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  136. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  137. package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
  138. package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +1 -1
  139. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  140. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  141. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  142. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  143. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  144. package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +1 -1
  145. package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +1 -1
  146. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  147. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  148. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  149. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  150. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  151. package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +1 -1
  152. package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +1 -1
  153. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  154. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  155. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  156. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  157. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  158. package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +1 -1
  159. package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +1 -1
  160. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  161. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  162. package/plugins/lisa-rails-agy/plugin.json +1 -1
  163. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  164. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  165. package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +1 -1
  166. package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +1 -1
  167. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  168. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  169. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  170. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  171. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  172. package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +1 -1
  173. package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +1 -1
  174. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  175. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  176. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  177. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  178. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  179. package/plugins/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
  180. package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
  181. package/plugins/src/base/rules/reference/config-resolution.md +1 -0
  182. package/plugins/src/base/scripts/ready-queue-order.mjs +34 -14
  183. package/plugins/src/base/skills/lisa-secrets-access/scripts/validate-config.mjs +30 -0
  184. package/plugins/src/base/skills/lisa-session-manager/SKILL.md +15 -8
  185. package/plugins/src/base/skills/lisa-session-manager/references/runbook-template.md +4 -3
  186. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-manager.mjs +5 -76
  187. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-queue.mjs +9 -3
  188. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-runtime.mjs +1 -0
  189. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-setup.mjs +165 -0
  190. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-usage.mjs +36 -9
  191. package/plugins/src/base/skills/lisa-session-manager/scripts/clipboard.mjs +119 -0
  192. package/plugins/src/base/skills/lisa-session-manager/scripts/config.mjs +22 -36
  193. package/plugins/src/base/skills/lisa-session-manager/scripts/launch.mjs +1 -0
  194. package/plugins/src/base/skills/lisa-session-manager/scripts/repo-detect.mjs +205 -0
  195. package/plugins/src/base/skills/lisa-session-manager/scripts/session-manager.mjs +16 -13
  196. package/plugins/src/base/skills/lisa-session-manager/scripts/setup-checks.mjs +168 -0
  197. package/plugins/src/base/skills/lisa-session-manager/scripts/token.mjs +98 -28
  198. package/plugins/src/base/skills/lisa-setup-session-manager/SKILL.md +57 -22
@@ -42,16 +42,31 @@ writes `$SM`, and pass `--project-root "$ROOT"` (the absolute project root) on e
42
42
 
43
43
  1. Preview: `node "$SM/session-manager.mjs" init-config --project-root "$ROOT"`. It detects
44
44
  `projects/*/.lisa.config.json` and proposes `name`, `interval`, `repos`, `capacity`, `stall` and a
45
- per-project `notify.stateDir`. Show the block to the operator.
45
+ per-project `notify.stateDir`. Repo detection leaves out linked worktrees and keeps one checkout
46
+ per remote, so ticket worktrees and second clones under `projects/` are not proposed. Show the
47
+ block to the operator and ask whether any repo is missing or should not be routed.
46
48
  2. Write it: the same command with `--write`. It adds only non-secret fields and never overwrites an
47
49
  existing block (`reason: "exists"` means keep it).
48
- 3. Ask the operator to replace each repo's starter `hints` with the technologies and areas that
49
- identify it (e.g. `api`: `["NestJS","migrations"]`, `web`: `["Expo","screens"]`), and whether to
50
+ 3. Each repo's `hints` are a draft: its name plus one per well-known dependency (`NestJS`, `Expo`,
51
+ `AWS CDK`, ...). Ask the operator to correct them and add the areas that identify the repo
52
+ (e.g. `api`: `["NestJS","migrations"]`, `web`: `["Expo","screens"]`), and whether to
50
53
  set `sessionManager.trustedAuthorIds`. Without it, any author's Ready item reaches a
51
54
  bypass-permissions worker; say so plainly. The list holds stable tracker user ids as strings,
52
55
  never logins: the GitHub numeric user id (`gh api users/<login> --jq .id`), the Jira
53
56
  `accountId`, or the Linear user id. A login matches no one and silently excludes every item.
54
- 4. `node "$SM/session-manager.mjs" validate --project-root "$ROOT"` must print `valid: true`.
57
+ 4. Set `sessionManager.operatorIds` to a non-empty **array** holding the operator's own tracker
58
+ user id, e.g. `"operatorIds": ["<operator-id>"]` (a bare string fails `validate`). Look up the
59
+ OPERATOR, not the credential: `gh api user` / `viewer.id` return whoever the tracker credential
60
+ belongs to, which is the agent account in exactly the case this key exists for. The manager dispatches
61
+ the operator's assigned items first, then items assigned to the tracker credential's identity
62
+ ("me"), then unassigned ones, and skips items assigned to anyone else. When the tracker
63
+ credential is not the operator's (an agent or bot account), leaving this unset means the
64
+ operator's own Ready items are never dispatched; say so plainly. Unlike `trustedAuthorIds`, this
65
+ is matched against the assignee, exactly and case-sensitively, so use the same kind of id as
66
+ "me", spelled as the tracker API returns it: the GitHub **login** (`gh api users/<login> --jq
67
+ .login`), the Jira `accountId`, or the Linear user id (the operator's entry in the team's member
68
+ list, or `viewer.id` only when the operator runs the lookup with their own credential).
69
+ 5. `node "$SM/session-manager.mjs" validate --project-root "$ROOT"` must print `valid: true`.
55
70
 
56
71
  ## Step 3: Store the bot token
57
72
 
@@ -61,8 +76,14 @@ The operator creates a bot with @BotFather, one per project. Then run
61
76
  - `stored: true`: done.
62
77
  - Exit 2 because a token already exists: keep it (re-running setup is safe). Only when the operator
63
78
  says the stored token is wrong or belongs to another project, re-run with `store-token --replace`.
64
- - `reason: "no-tty"` (an agent's Bash has no terminal): print `command` from the output and ask the
65
- operator to run it in their own terminal, where it prompts with echo off. Wait for them to confirm.
79
+ - `reason: "no-tty"` (an agent's Bash has no terminal): offer the operator both routes, and say
80
+ plainly that Claude Code's `!` prefix has no terminal either, so it fails the same way:
81
+ - **Clipboard (simplest):** they copy the token from the BotFather chat and tell you; then run
82
+ `clipboardCommand` from the output (`store-token --from-clipboard`). It validates the token,
83
+ stores it, never prints it, and clears the clipboard. On `stored: false`, say what `message`
84
+ reports and ask them to copy it again.
85
+ - **Separate terminal app:** print `command` and ask them to run it in Terminal, iTerm or similar,
86
+ outside the agent, where it prompts with echo off. Wait for them to confirm.
66
87
  - `empty` / `invalid`: say what was wrong and ask again.
67
88
 
68
89
  Never ask for the token in chat, never echo, log or commit it, and never put it in
@@ -97,14 +118,24 @@ If `.lisa/automations/session-manager.runbook.md` does not exist, copy
97
118
  `$SM/../references/runbook-template.md` there. Never overwrite an existing runbook: it is the
98
119
  project's. It is checked in, like every automation runbook (`automation-runbook-contract`).
99
120
 
100
- ## Step 7: Coexistence warning
101
-
102
- Tell the operator, before starting: if this project also runs the scheduled `intake-repair` loop, it
103
- can re-dispatch an item a local worker is still building (it treats a claimed item with no tracker
104
- activity for `intake.repair.staleAfterHours` as stalled). `intake-tickets` competes for the same
105
- Ready items. Recommend tearing down `intake-tickets` (`/lisa:tear-down-automations intake-tickets`)
106
- and either raising `intake.repair.staleAfterHours` above `stall.noOutputMinutes × stall.maxAttempts`
107
- or tearing down `intake-repair`.
121
+ ## Step 7: Check for competing intake loops
122
+
123
+ The scheduled `intake-repair` loop can re-dispatch an item a local worker is still building (it treats
124
+ a claimed item with no tracker activity for `intake.repair.staleAfterHours` as stalled), and
125
+ `intake-tickets` competes for the same Ready items. Find out whether either is running before you
126
+ start the manager; do not leave the operator to check.
127
+
128
+ 1. Run `node "$SM/session-manager.mjs" coexistence --project-root "$ROOT"`. For each loop it reports
129
+ the last run recorded in this project's run log and whether that is `recent`. `live` lists the
130
+ loops that ran recently.
131
+ 2. A run log is evidence, not proof: also list your runtime's scheduler for those loop names (Claude
132
+ Code: the `/schedule` listing of claude.ai routines; Codex: automations; a `lisa-<loop>.yml`
133
+ workflow with a `schedule:` trigger on GitHub Actions).
134
+ 3. Report what you found, per loop, in one line each. Only for a loop that is live (a recent run, or a
135
+ scheduler entry): recommend tearing down `intake-tickets` (`/lisa:tear-down-automations
136
+ intake-tickets`) and either raising `intake.repair.staleAfterHours` above
137
+ `stall.noOutputMinutes × stall.maxAttempts` or tearing down `intake-repair`. When neither is live,
138
+ say so and move on.
108
139
 
109
140
  ## Step 8: Accept workspace trust in each worker repo
110
141
 
@@ -113,12 +144,15 @@ folder?" prompt: until someone has accepted it in a directory, `claude --bg` ref
113
144
  and `spawn` exits 2 saying so. Do this once per routed repo (or once for the root on a single-repo
114
145
  project), on every machine that runs the manager:
115
146
 
116
- 1. List the directories workers start in. Single-repo: the project root. Multi-repo: for each key in
117
- `sessionManager.repos.entries`,
118
- `node "$SM/session-manager.mjs" repo-dir --repo <key> --raw --project-root "$ROOT"`.
119
- 2. Ask the operator, in their own terminal, to run `claude` once in that directory,
120
- accept the trust prompt, then exit. An agent's Bash cannot answer that prompt, so never try to
121
- accept it for them.
147
+ 1. Run `node "$SM/session-manager.mjs" trust-status --project-root "$ROOT"`. It lists every
148
+ directory workers start in (each routed repo, or the root on a single-repo project) with whether
149
+ Claude Code has already recorded trust for it. `needsTrust` lists the ones that are not
150
+ `trusted: true`. When it is empty, this step is done: say so.
151
+ 2. For each directory in `needsTrust`, ask the operator, in a separate terminal app (not the agent's
152
+ Bash or Claude Code's `!` prefix), to run `claude` once in that directory, accept the trust prompt,
153
+ then exit. An agent's Bash cannot answer that prompt, so never try to accept it for them. Then
154
+ re-run `trust-status` to confirm. (`trusted: "unknown"` means Claude Code's state file could not be
155
+ read; treat it as needing trust.)
122
156
  3. Re-run this step whenever a repo is added to `sessionManager.repos`.
123
157
 
124
158
  ## Step 9: Start and pair
@@ -152,5 +186,6 @@ confirm the "Session manager Telegram isolation?" check is green. Fix every warn
152
186
  `node "$SM/session-manager.mjs" status --project-root "$ROOT"` should show the manager running.
153
187
 
154
188
  Report: the config block written (or kept), where the token lives (the path, never the value), the
155
- plugin scope result, the runbook path, which repo dirs had workspace trust accepted, the manager's
156
- tmux session name, and the doctor result.
189
+ plugin scope result, the runbook path, which repo dirs were already trusted and which the operator
190
+ accepted trust in, what the competing-loop check found, the manager's tmux session name, and the
191
+ doctor result.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.81.3",
3
+ "version": "4.81.5",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.81.3",
3
+ "version": "4.81.5",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -733,6 +733,7 @@ bypassed). `/lisa:setup:session-manager` writes it, detecting a multi-repo layou
733
733
  | `sessionManager.notify.provider` | no | `telegram` | Only `telegram` is implemented. |
734
734
  | `sessionManager.notify.stateDir` | **yes** | — | This project's own Telegram state dir. Never the shared default `~/.claude/channels/telegram`, because one bot per state dir is how projects stay isolated. Setup writes `~/.claude/channels/telegram-<project>`. |
735
735
  | `sessionManager.trustedAuthorIds` | no | — | Optional list of **stable tracker user ids**, as strings: the GitHub numeric user id (`gh api users/<login> --jq .id`), the Jira `accountId`, or the Linear user id. Not logins or display names: matching compares ids, so a login silently matches no one and excludes every item. When set, the manager takes only items authored by these people. |
736
+ | `sessionManager.operatorIds` | no | — | Optional, non-empty list of the people the manager works for, as tracker user ids matched against the **assignee** the same way "me" is: the GitHub **login**, the Jira `accountId`, or the Linear user id, spelled exactly as the tracker API returns it (matching is case-sensitive, so look the OPERATOR up rather than typing from memory: `gh api users/<operator-login> --jq .login` returns the canonical GitHub spelling. Do not use `gh api user`, which returns whoever the credential belongs to — the agent account, when that is the case this key exists for). Dispatch order is assigned to an operator, then to "me" (the tracker credential's identity), then unassigned; items assigned to anyone else are skipped. Set it whenever the tracker credential is not the operator's own (an agent account), or the operator's Ready items are never dispatched. |
736
737
 
737
738
  - **Non-secret only.** The bot token lives in `<stateDir>/.env` (directory 0700, file 0600),
738
739
  written by setup. A credential-named field or a token-shaped value anywhere in this block is a
@@ -1,15 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Vendor-neutral Ready-queue normalization and mine-first dispatch order.
3
+ * Vendor-neutral Ready-queue normalization and operator-first dispatch order.
4
4
  *
5
5
  * ## Why this exists
6
6
  *
7
7
  * Intake has always taken Ready work in whatever order the tracker returned
8
8
  * it, and `intake.assignee` only NARROWS a selection — it never ranks one. A
9
9
  * dispatcher that runs several workers at once needs a stable answer to "what
10
- * next?": the work already assigned to me first (somebody chose me for it),
11
- * then unassigned work, most urgent and oldest first. Work assigned to someone
12
- * else is theirs, so it is excluded, never re-ordered.
10
+ * next?": work assigned to the operator first (the person the dispatcher works
11
+ * for), then work assigned to me (the identity the tracker credential belongs
12
+ * to, often an agent account rather than the operator), then unassigned work,
13
+ * most urgent and oldest first. Work assigned to anyone else is theirs, so it
14
+ * is excluded, never re-ordered. When the credential IS the operator's, the
15
+ * first two groups coincide. With "me" as the only identity, an operator whose
16
+ * credential is an agent account had every one of their own items excluded as
17
+ * someone else's (CodySwannGT/lisa#4467).
13
18
  *
14
19
  * The three trackers disagree on every field this needs — GitHub has priority
15
20
  * LABELS, Linear a native 0..4 number where 0 means "none", Jira a priority
@@ -252,12 +257,18 @@ function shape(input) {
252
257
  * Order matters only for the reason reported: an item can fail several rules,
253
258
  * and "someone else owns it" is the most useful thing to say about it.
254
259
  * @param {Record<string, any>} item
255
- * @param {{ me: string | null, trusted: ReadonlySet<string>, humanNeededLabel: string }} context
260
+ * @param {{ me: string | null, operators: ReadonlySet<string>, trusted: ReadonlySet<string>, humanNeededLabel: string }} context
256
261
  * @returns {string | null}
257
262
  */
258
263
  function exclusionReason(item, context) {
259
264
  const assignee = idOrNull(item.assigneeId);
260
- if (assignee !== null && assignee !== context.me) return "assigned-to-other";
265
+ if (
266
+ assignee !== null &&
267
+ assignee !== context.me &&
268
+ !context.operators.has(assignee)
269
+ ) {
270
+ return "assigned-to-other";
271
+ }
261
272
  if (item.isContainer === true) return "container";
262
273
  if (
263
274
  isHumanGated({
@@ -293,20 +304,25 @@ function compareWithinGroup(left, right) {
293
304
  }
294
305
 
295
306
  /**
296
- * Order normalized Ready items for dispatch, mine first.
307
+ * Order normalized Ready items for dispatch: the operator's, then mine, then
308
+ * unassigned.
297
309
  *
298
- * Group 0 is assigned to `me`, group 1 unassigned; within a group, priority
299
- * rank ascending, then creation time ascending, then ref as a stable
300
- * tiebreak. Excluded items keep their input order. With no `me`, every
301
- * assigned item is someone else's — the safe direction, since claiming
302
- * assigned work steals it.
310
+ * Group 0 is assigned to an operator, group 1 to `me`, group 2 unassigned;
311
+ * within a group, priority rank ascending, then creation time ascending, then
312
+ * ref as a stable tiebreak. Excluded items keep their input order. With no
313
+ * `me` and no operators, every assigned item is someone else's — the safe
314
+ * direction, since claiming assigned work steals it.
315
+ *
316
+ * `operators` match the way `me` does, against the normalized assignee id:
317
+ * GitHub login, Jira accountId, Linear user id.
303
318
  * @param {readonly Record<string, any>[]} items - Normalized items
304
- * @param {{ me?: string | null, trustedAuthorIds?: readonly unknown[], humanNeededLabel?: string }} [options]
319
+ * @param {{ me?: string | null, operators?: readonly unknown[], trustedAuthorIds?: readonly unknown[], humanNeededLabel?: string }} [options]
305
320
  * @returns {{ ordered: Record<string, any>[], excluded: { ref: string, reason: string }[] }}
306
321
  */
307
322
  export function orderReadyQueue(items, options = {}) {
308
323
  const context = {
309
324
  me: idOrNull(options.me),
325
+ operators: new Set((options.operators ?? []).map(idOrNull).filter(Boolean)),
310
326
  trusted: new Set(
311
327
  (options.trustedAuthorIds ?? []).map(idOrNull).filter(Boolean)
312
328
  ),
@@ -319,7 +335,11 @@ export function orderReadyQueue(items, options = {}) {
319
335
  const eligible = judged
320
336
  .filter(one => one.reason === null)
321
337
  .map(one => one.item);
322
- const group = item => (idOrNull(item.assigneeId) === null ? 1 : 0);
338
+ const group = item => {
339
+ const assignee = idOrNull(item.assigneeId);
340
+ if (assignee === null) return 2;
341
+ return context.operators.has(assignee) ? 0 : 1;
342
+ };
323
343
 
324
344
  return {
325
345
  ordered: [...eligible].sort(
@@ -727,6 +727,35 @@ function findCredentials(value, path) {
727
727
  );
728
728
  }
729
729
 
730
+ /**
731
+ * Validate `sessionManager.operatorIds`: the people the manager works for,
732
+ * whose assigned items it dispatches first. Matched against the assignee the
733
+ * way "me" is, so the GitHub entry is a login, not the numeric id
734
+ * `trustedAuthorIds` takes. An empty list reads as configured but names no
735
+ * one, so it is refused like an empty `trustedAuthorIds`.
736
+ * @param {unknown} ids The value, if present.
737
+ * @returns {string[]} Problems found.
738
+ */
739
+ function validateOperatorIds(ids) {
740
+ if (ids === undefined) return [];
741
+ if (
742
+ !Array.isArray(ids) ||
743
+ !ids.every(id => typeof id === "string" && id.trim() !== "")
744
+ ) {
745
+ return [
746
+ `sessionManager.operatorIds must be an array of tracker user ids as ` +
747
+ `strings, matched against the assignee: the GitHub login, the Jira ` +
748
+ `accountId or the Linear user id.`,
749
+ ];
750
+ }
751
+ return ids.length === 0
752
+ ? [
753
+ `sessionManager.operatorIds must name at least one person. Remove ` +
754
+ `the key instead if the manager works only for its own identity.`,
755
+ ]
756
+ : [];
757
+ }
758
+
730
759
  /**
731
760
  * Validate the opt-in `sessionManager` block.
732
761
  *
@@ -786,6 +815,7 @@ export function validateSessionManager(block) {
786
815
  `if every author's item may be dispatched.`,
787
816
  ]
788
817
  : []),
818
+ ...validateOperatorIds(block.operatorIds),
789
819
  ...findCredentials(block, "sessionManager"),
790
820
  ];
791
821
  }
@@ -23,9 +23,9 @@ channels (Telegram) and cross-session messaging (`SendMessage`, `crossSessionInb
23
23
  | Runtime | lisa-setup-session-manager | lisa-session-manager (manager) | `managedBy=` |
24
24
  |---|---|---|---|
25
25
  | Claude Code | supported | supported (reference). Needs `claude` ≥ 2.1.224, `tmux`, `bun` | supported |
26
- | Codex | config, token and runbook are supported. `start` launches a Claude Code manager, so it works when the `claude` CLI is installed | the skill ships, but `cycle` refuses to run here (no `/loop`, channels or `SendMessage`); tell the operator to run `start` | rejected with the gap message |
26
+ | Codex | config, token (prompt or `--from-clipboard`), runbook, `trust-status` and `coexistence` are supported. `trust-status` reads Claude Code's trust record, which is the one that matters (workers are Claude Code); accepting trust needs the `claude` CLI. `coexistence` sees only run logs, so also list Codex automations. `start` launches a Claude Code manager, so it works when the `claude` CLI is installed | the skill ships, but `cycle` refuses to run here (no `/loop`, channels or `SendMessage`); tell the operator to run `start` | rejected with the gap message |
27
27
  | Cursor / Antigravity (agy) / Copilot / Devin | same as Codex | same as Codex | rejected |
28
- | OpenCode | config and token are supported; script resolution relies on the npm rung, so `queue` and `record-cycle` need the npm package | gap | rejected |
28
+ | OpenCode | same setup subcommands as Codex, but script resolution relies on the npm rung: the CLI imports plugin-level scripts the skill-folder copy lacks, so every subcommand needs the npm package | gap | rejected |
29
29
 
30
30
  On any runtime other than Claude Code, `cycle` stops with: "The session manager runs on Claude Code
31
31
  only (background sessions, channels, cross-session messaging). Run `/lisa:session-manager start`
@@ -66,7 +66,12 @@ the manager.
66
66
  claims go through `lisa-tracker-claim`. Never call a vendor API around them.
67
67
  - **"Me".** Resolve once per manager run and store it with `ledger control --me <id>`: GitHub
68
68
  `gh api user --jq .login`; Jira the accountId from the `lisa-atlassian-access` identity probe;
69
- Linear `viewer.id` through `lisa-linear-access`.
69
+ Linear `viewer.id` through `lisa-linear-access`. "Me" is whoever the tracker credential belongs
70
+ to, which is often an agent account.
71
+ - **Operators.** `sessionManager.operatorIds` names the people the manager works for (the same
72
+ kind of id as "me": GitHub login, Jira accountId, Linear user id). Their assigned items come
73
+ first, then items assigned to "me", then unassigned. Items assigned to anyone else are never
74
+ dispatched. Never treat an operator's item as someone else's.
70
75
  - **Workers** start only through `spawn`. The worker prompt is exactly
71
76
  `/lisa:implement <REF> managedBy=<manager-name>`; `lisa-implement` owns what `managedBy=` means.
72
77
  Never start a worker another way, and never reuse a worker for another item or a new attempt.
@@ -207,8 +212,8 @@ Skip while `capacity` reports `paused`. Otherwise:
207
212
  Raw Jira issues carry `key` and `fields` (summary, priority, assignee, created, labels,
208
213
  description, reporter, issuetype, subtasks); raw Linear nodes carry identifier, title, priority,
209
214
  createdAt, assignee, labels, description, creator and children with their state type.
210
- - `ordered` is the dispatch order (mine, then unassigned, then priority, then age). `excluded`
211
- needs no action.
215
+ - `ordered` is the dispatch order: assigned to an operator, then to "me", then unassigned; each
216
+ group by priority, then age. `excluded` needs no action.
212
217
  2. **While `capacity` says `can_spawn`** and items remain, take the next item that has no pending
213
218
  question in the ledger:
214
219
  1. Read it fully (`lisa-tracker-read`): title, description, labels, project, parent, comments.
@@ -223,9 +228,11 @@ Skip while `capacity` reports `paused`. Otherwise:
223
228
  `cd "$(node "$SM/session-manager.mjs" repo-dir --repo <key> --raw --project-root "$ROOT")"`
224
229
  (omit `--repo` on a single-repo project), invoke `lisa-tracker-claim <ref>`, then
225
230
  `cd "$ROOT" && pwd` and confirm the path. Continue only on `claimed` or `reused` with the
226
- assignee equal to "me"; anything else means skip. Then re-read the item with
227
- `lisa-tracker-read`: if the re-read shows a different assignee, or shows the state did not
228
- change to the `claimed` role, skip it (someone else holds it, or the claim did not land).
231
+ assignee equal to "me" or to one of `sessionManager.operatorIds` (the claim assigns only an
232
+ unassigned item, so an operator's item keeps the operator); anything else means skip. Then
233
+ re-read the item with `lisa-tracker-read`: if the re-read shows an assignee that is neither
234
+ "me" nor an operator, or shows the state did not change to the `claimed` role, skip it
235
+ (someone else holds it, or the claim did not land).
229
236
  Never spawn on the claim's word alone.
230
237
  4. **Spawn.** `spawn <ref> [--repo <key>]`.
231
238
  - exit 0: post `[<REF>] started in <repo> (<name>)` to Telegram.
@@ -18,9 +18,10 @@ session list from `claude agents`; and the project's own Telegram chat.
18
18
 
19
19
  ## Candidate selection
20
20
 
21
- Leaf items in the `ready` role, ordered: assigned to the operator, then unassigned, then by priority,
22
- then oldest. Items assigned to someone else, containers, human-held items and (when configured)
23
- items by untrusted authors are skipped. As many as the machine has capacity for.
21
+ Leaf items in the `ready` role, ordered: assigned to an operator (`sessionManager.operatorIds`),
22
+ then to the manager's own tracker identity, then unassigned; within each, by priority, then oldest.
23
+ Items assigned to someone else, containers, human-held items and (when configured) items by
24
+ untrusted authors are skipped. As many as the machine has capacity for.
24
25
 
25
26
  ## Scope/bounds
26
27
 
@@ -1,6 +1,7 @@
1
1
  /**
2
- * Manager and setup subcommands of the session-manager CLI: start, stop,
3
- * status, repo-dir, validate, init-config and store-token.
2
+ * Manager subcommands of the session-manager CLI: start, stop, status,
3
+ * repo-dir and validate. The setup ones (init-config, store-token,
4
+ * trust-status, coexistence) live in cli-setup.mjs.
4
5
  *
5
6
  * `start` hosts the manager in tmux. It refuses (exit 2) unless the bot
6
7
  * token file exists with owner-only permissions in the project's own state
@@ -11,15 +12,11 @@
11
12
  * manager's tmux session: workers hold claimed work and keep running.
12
13
  * @module session-manager/cli-manager
13
14
  */
14
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
15
- import path from "node:path";
16
-
17
15
  import {
18
16
  CliError,
19
17
  EXIT,
20
18
  GLOBAL_CONFIG_FILE,
21
19
  asSetupError,
22
- asSetupErrorAsync,
23
20
  intFlag,
24
21
  listAgents,
25
22
  loadProject,
@@ -28,12 +25,8 @@ import {
28
25
  requireLisaRepo,
29
26
  run,
30
27
  } from "./cli-runtime.mjs";
31
- import { buildDefaultBlock, detectRepos, resolveRepoDir } from "./config.mjs";
32
- import {
33
- defaultProjectSlug,
34
- probeOwnSession,
35
- sessionSurvives,
36
- } from "./isolation.mjs";
28
+ import { resolveRepoDir } from "./config.mjs";
29
+ import { probeOwnSession, sessionSurvives } from "./isolation.mjs";
37
30
  import {
38
31
  assertTokenPresent,
39
32
  buildForegroundCommand,
@@ -41,7 +34,6 @@ import {
41
34
  buildManagerLaunch,
42
35
  buildStopManager,
43
36
  resolveStateDir,
44
- storeToken as storeTokenFile,
45
37
  } from "./launch.mjs";
46
38
  import { readLedger } from "./ledger.mjs";
47
39
  import { parseWorkerName, scrubWorkerEnv } from "./workers.mjs";
@@ -208,69 +200,6 @@ export function validate(ctx) {
208
200
  };
209
201
  }
210
202
 
211
- /**
212
- * `init-config [--slug <slug>] [--write]`: the default block for this
213
- * project, written to `.lisa.config.json` only with `--write` and only when
214
- * no block exists. Non-secret fields only; the token never goes here.
215
- * @param {object} ctx - CLI context
216
- * @returns {{ json: object }} `{written,block,...}`
217
- */
218
- export function initConfig(ctx) {
219
- const { global } = loadProject(ctx.root);
220
- if (global?.sessionManager) {
221
- return {
222
- json: { written: false, reason: "exists", block: global.sessionManager },
223
- };
224
- }
225
- const slug =
226
- ctx.values.slug ?? defaultProjectSlug(ctx.root, global?.github?.repo);
227
- const block = asSetupError(() =>
228
- buildDefaultBlock({
229
- projectSlug: slug,
230
- detectedRepos: detectRepos(ctx.root),
231
- })
232
- );
233
- if (!ctx.values.write) return { json: { written: false, block } };
234
-
235
- const file = path.join(ctx.root, GLOBAL_CONFIG_FILE);
236
- if (!existsSync(file)) {
237
- throw new CliError(
238
- `${file} does not exist; set up Lisa in this project first.`,
239
- EXIT.SETUP
240
- );
241
- }
242
- const current = JSON.parse(readFileSync(file, "utf8"));
243
- writeFileSync(
244
- file,
245
- `${JSON.stringify({ ...current, sessionManager: block }, null, 2)}\n`
246
- );
247
- return { json: { written: true, path: file, block } };
248
- }
249
-
250
- /**
251
- * `store-token [--replace]`: prompt for the bot token on the operator's
252
- * terminal and write `<stateDir>/.env`. An existing token is kept (exit 2)
253
- * unless `--replace` is given. With no TTY it prints the command the operator
254
- * must run themselves and exits 0 with `stored:false`.
255
- * @param {object} ctx - CLI context
256
- * @returns {Promise<{ json: object, exitCode: number }>} Outcome
257
- */
258
- export async function storeToken(ctx) {
259
- const config = requireConfig(ctx);
260
- const result = await asSetupErrorAsync(() =>
261
- storeTokenFile({
262
- stateDir: config.notify?.stateDir,
263
- scriptsDir: ctx.scriptsDir,
264
- projectRoot: ctx.root,
265
- replace: ctx.values.replace === true,
266
- env: ctx.env,
267
- homedir: ctx.homedir,
268
- })
269
- );
270
- const refused = result.stored === false && result.reason !== "no-tty";
271
- return { json: result, exitCode: refused ? EXIT.SETUP : EXIT.OK };
272
- }
273
-
274
203
  /**
275
204
  * `status`: is the manager's tmux session up, and what does the ledger say
276
205
  * about each worker it dispatched.
@@ -123,9 +123,11 @@ function readEnvelopeQueue(ctx, tracker) {
123
123
  }
124
124
 
125
125
  /**
126
- * `queue --tracker <github|jira|linear>`: the Ready queue, mine first.
126
+ * `queue --tracker <github|jira|linear>`: the Ready queue, the operator's
127
+ * items first (`sessionManager.operatorIds`), then mine, then unassigned.
127
128
  * @param {object} ctx - CLI context
128
- * @returns {Promise<{ json: object }>} `{tracker,me,total,pages,ordered,excluded}`
129
+ * @returns {Promise<{ json: object }>}
130
+ * `{tracker,me,operators,total,pages,ordered,excluded}`
129
131
  */
130
132
  export async function queue(ctx) {
131
133
  const tracker = ctx.values.tracker;
@@ -139,10 +141,14 @@ export async function queue(ctx) {
139
141
  ? fetchGithubQueue(ctx, project)
140
142
  : readEnvelopeQueue(ctx, tracker);
141
143
  const me = ctx.values.me ?? (await readLedger(ctx.root)).control.me ?? null;
144
+ const operators = config?.operatorIds ?? [];
142
145
  const order = orderReadyQueue(items, {
143
146
  me,
147
+ operators,
144
148
  trustedAuthorIds: config?.trustedAuthorIds ?? undefined,
145
149
  humanNeededLabel: humanNeededLabel(project, tracker),
146
150
  });
147
- return { json: { tracker, me, total: items.length, pages, ...order } };
151
+ return {
152
+ json: { tracker, me, operators, total: items.length, pages, ...order },
153
+ };
148
154
  }
@@ -126,6 +126,7 @@ function validationView(config) {
126
126
  ...config,
127
127
  repos: config.repos ?? undefined,
128
128
  trustedAuthorIds: config.trustedAuthorIds ?? undefined,
129
+ operatorIds: config.operatorIds,
129
130
  };
130
131
  }
131
132