@detergent-software/conductor 3.4.0 → 3.5.0-dev.10

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 (54) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/README.md +16 -8
  3. package/build/brief.js +9 -2
  4. package/build/brief.js.map +1 -1
  5. package/build/broker.js +9 -3
  6. package/build/broker.js.map +1 -1
  7. package/build/cli.js +5 -0
  8. package/build/cli.js.map +1 -1
  9. package/build/config.js +12 -0
  10. package/build/config.js.map +1 -1
  11. package/build/credentials.js +4 -0
  12. package/build/credentials.js.map +1 -1
  13. package/build/daemon.js +6 -1
  14. package/build/daemon.js.map +1 -1
  15. package/build/help.js +22 -2
  16. package/build/help.js.map +1 -1
  17. package/build/host/browser.js +163 -0
  18. package/build/host/browser.js.map +1 -0
  19. package/build/host/worktree-processes.js +389 -0
  20. package/build/host/worktree-processes.js.map +1 -0
  21. package/build/inbox.js +35 -4
  22. package/build/inbox.js.map +1 -1
  23. package/build/manager.js +181 -27
  24. package/build/manager.js.map +1 -1
  25. package/build/mcp-approval.js +94 -0
  26. package/build/mcp-approval.js.map +1 -0
  27. package/build/notes.js +22 -5
  28. package/build/notes.js.map +1 -1
  29. package/build/project-check.js +38 -3
  30. package/build/project-check.js.map +1 -1
  31. package/build/scheduler.js +25 -6
  32. package/build/scheduler.js.map +1 -1
  33. package/build/spend.js +36 -14
  34. package/build/spend.js.map +1 -1
  35. package/build/watchers/boards.js +3 -2
  36. package/build/watchers/boards.js.map +1 -1
  37. package/build/watchers/index.js +10 -2
  38. package/build/watchers/index.js.map +1 -1
  39. package/build/watchers/issues.js +5 -2
  40. package/build/watchers/issues.js.map +1 -1
  41. package/build/watchers/linear-queue.js +11 -4
  42. package/build/watchers/linear-queue.js.map +1 -1
  43. package/build/watchers/linear.js +55 -17
  44. package/build/watchers/linear.js.map +1 -1
  45. package/build/watchers/source.js +27 -3
  46. package/build/watchers/source.js.map +1 -1
  47. package/build/worktrees.js +30 -20
  48. package/build/worktrees.js.map +1 -1
  49. package/package.json +3 -3
  50. package/plugin/hooks/model.ts +30 -3
  51. package/plugin/hooks/register.tsx +98 -13
  52. package/plugin/skills/conductor-console/SKILL.md +1 -1
  53. package/plugin/skills/work-item/SKILL.md +4 -3
  54. package/protocol/PROTOCOL.md +1 -1
@@ -0,0 +1,389 @@
1
+ import { readdirSync, readFileSync, readlinkSync } from 'node:fs';
2
+ import { posix, win32 } from 'node:path';
3
+ import { z } from 'zod';
4
+ import { ConductorError } from "../errors.js";
5
+ import { processAlive } from "../lock.js";
6
+ import { realOr } from "../paths.js";
7
+ import { outputOf, run as runCommand } from "../run.js";
8
+ import { hostPlatform } from "./platform.js";
9
+ // The programs that run a script file: the first absolute path among their words that aren't options
10
+ // is the script. Not shells, whose options take folders (`pwsh -WorkingDirectory <dir>`, `bash
11
+ // --rcfile <file>`): a terminal opened in the worktree is the operator's.
12
+ const INTERPRETERS = new Set([
13
+ 'bun',
14
+ 'deno',
15
+ 'node',
16
+ 'nodejs',
17
+ 'perl',
18
+ 'php',
19
+ 'python',
20
+ 'python3',
21
+ 'ruby',
22
+ ]);
23
+ // How long a POSIX process gets after SIGTERM before SIGKILL.
24
+ const TERM_MS = 5000;
25
+ // The processes of the listing that belong to the worktree (worktreeProcesses' find), parents first.
26
+ export function belonging(listing, worktree, ports, self, platform) {
27
+ const byPid = new Map(listing.processes.map((p) => [p.pid, p]));
28
+ // The conductor and every process it descends from (a terminal, a supervisor): never stopped, and
29
+ // never looked through for children.
30
+ const guarded = new Set();
31
+ for (let pid = self; pid !== undefined && !guarded.has(pid);) {
32
+ guarded.add(pid);
33
+ const entry = byPid.get(pid);
34
+ if (entry === undefined || entry.ppid === pid)
35
+ break;
36
+ const parent = byPid.get(entry.ppid);
37
+ // A parent that started after its child is a reused pid's process (Windows), not its parent: the
38
+ // walk stops there, or it would guard a process of the worktree.
39
+ const reused = parent !== undefined && parent.started !== null && entry.started !== null && parent.started > entry.started;
40
+ pid = reused ? undefined : entry.ppid;
41
+ }
42
+ const roots = worktreeRoots(worktree, platform);
43
+ const found = new Map();
44
+ const add = (entry, why) => {
45
+ if (!guarded.has(entry.pid) && !found.has(entry.pid))
46
+ found.set(entry.pid, { command: entry.command, pid: entry.pid, why });
47
+ };
48
+ for (const entry of listing.processes)
49
+ if (programPaths(entry, platform).some((path) => roots.some((root) => isUnder(path, root, platform))))
50
+ add(entry, 'path');
51
+ for (const port of ports)
52
+ for (const pid of listing.listeners.get(port) ?? []) {
53
+ const entry = byPid.get(pid);
54
+ add(entry ?? { command: '', executable: null, pid, ppid: 0, started: null }, 'port');
55
+ }
56
+ // Each one's descendants, as each is stopped with its tree.
57
+ const children = new Map();
58
+ for (const entry of listing.processes) {
59
+ if (entry.ppid === entry.pid)
60
+ continue;
61
+ children.set(entry.ppid, [...(children.get(entry.ppid) ?? []), entry]);
62
+ }
63
+ const queue = [...found.keys()];
64
+ for (let pid = queue.shift(); pid !== undefined; pid = queue.shift()) {
65
+ const parent = byPid.get(pid);
66
+ // A listener the process listing missed (it started between the two): with no start to compare,
67
+ // a child of its pid could be a reused pid's.
68
+ if (!parent)
69
+ continue;
70
+ for (const child of children.get(pid) ?? []) {
71
+ if (guarded.has(child.pid) || found.has(child.pid))
72
+ continue;
73
+ // A pid Windows reused: the "child" started before its parent did.
74
+ if (parent.started !== null && child.started !== null && child.started < parent.started)
75
+ continue;
76
+ add(child, 'child');
77
+ queue.push(child.pid);
78
+ }
79
+ }
80
+ return [...found.values()];
81
+ }
82
+ // The command that ends a process by hand, for an inbox item: one that outlived the conductor's own
83
+ // stop, so forcibly, and that process alone, as the item names each one (taskkill /T would walk
84
+ // parent pids Windows may have reused).
85
+ export function killCommand(pid, platform = hostPlatform()) {
86
+ return platform === 'win32' ? `taskkill /PID ${pid} /F` : `kill -9 ${pid}`;
87
+ }
88
+ // `lsof -F pn` output: a `p<pid>` line, then one `n<name>` line per file (other field lines, such as
89
+ // `f<fd>`, are skipped). Listening sockets are named `*:41000`, `127.0.0.1:41000` or `[::1]:41000`.
90
+ export function parseLsofListeners(stdout, ports) {
91
+ const listeners = new Map();
92
+ let pid = null;
93
+ for (const line of stdout.split(/\r?\n/)) {
94
+ if (line.startsWith('p'))
95
+ pid = Number(line.slice(1)) || null;
96
+ else if (line.startsWith('n') && pid !== null)
97
+ addListener(listeners, ports, portOf(line.slice(1)), pid);
98
+ }
99
+ return listeners;
100
+ }
101
+ // `ps -A -ww -o pid=,ppid=,args=` output.
102
+ export function parsePs(stdout) {
103
+ const entries = [];
104
+ for (const line of stdout.split(/\r?\n/)) {
105
+ const match = /^\s*(\d+)\s+(\d+)\s+(.*)$/.exec(line);
106
+ if (!match)
107
+ continue;
108
+ entries.push({
109
+ command: match[3] ?? '',
110
+ executable: null,
111
+ pid: Number(match[1]),
112
+ ppid: Number(match[2]),
113
+ started: null,
114
+ });
115
+ }
116
+ return entries;
117
+ }
118
+ // `ss -ltnpH` output: `LISTEN 0 511 *:41000 *:* users:(("node",pid=1234,fd=20))`. The local address
119
+ // is the fourth column.
120
+ export function parseSs(stdout, ports) {
121
+ const listeners = new Map();
122
+ for (const line of stdout.split(/\r?\n/)) {
123
+ const local = line.trim().split(/\s+/)[3];
124
+ if (local === undefined)
125
+ continue;
126
+ for (const match of line.matchAll(/pid=(\d+)/g))
127
+ addListener(listeners, ports, portOf(local), Number(match[1]));
128
+ }
129
+ return listeners;
130
+ }
131
+ // The Windows script's JSON (windowsListingScript).
132
+ export function parseWindowsListing(stdout, ports) {
133
+ const parsed = windowsListing.safeParse(parseJson(stdout));
134
+ if (!parsed.success)
135
+ throw new ConductorError("couldn't read the process listing", [stdout.slice(0, 500)]);
136
+ const listeners = new Map();
137
+ for (const l of parsed.data.listeners)
138
+ addListener(listeners, ports, l.port, l.pid);
139
+ return {
140
+ listeners,
141
+ processes: parsed.data.processes.map((p) => ({
142
+ command: p.c ?? '',
143
+ executable: p.e ?? null,
144
+ pid: p.p,
145
+ ppid: p.pp,
146
+ started: p.s ?? null,
147
+ })),
148
+ unseen: parsed.data.gap === null || parsed.data.gap === undefined ? [] : [parsed.data.gap],
149
+ };
150
+ }
151
+ // Processes as a retire step or an inbox item names them: `8640 node …\next dev; 912 …`.
152
+ export function processesText(processes) {
153
+ return processes
154
+ .map(({ command, pid }) => {
155
+ const text = command.replace(/\s+/g, ' ').trim();
156
+ return text === '' ? String(pid) : `${pid} ${text.length > 160 ? `${text.slice(0, 159)}…` : text}`;
157
+ })
158
+ .join('; ');
159
+ }
160
+ // One Windows PowerShell run, encoded so its own command line never holds the worktree's path: every
161
+ // process with its parent, executable, command line and start, and the owners of the given ports
162
+ // listening. Get-NetTCPConnection answers an error for a port nobody listens on, hence
163
+ // SilentlyContinue; a Windows without it says so in `gap`.
164
+ export function windowsListingScript(ports) {
165
+ return [
166
+ '[Console]::OutputEncoding = [Text.Encoding]::UTF8',
167
+ `$ports = @(${ports.map((p) => String(Math.trunc(p))).join(',')})`,
168
+ '$procs = @(Get-CimInstance Win32_Process | ForEach-Object { [pscustomobject]@{ p = [int]$_.ProcessId; pp = [int]$_.ParentProcessId; e = $_.ExecutablePath; c = $_.CommandLine; s = $(if ($_.CreationDate) { ([DateTimeOffset]$_.CreationDate).ToUnixTimeMilliseconds() } else { $null }) } })',
169
+ '$gap = $null',
170
+ '$listen = @()',
171
+ "if ($ports.Count -gt 0) { if (Get-Command Get-NetTCPConnection -ErrorAction SilentlyContinue) { $listen = @(Get-NetTCPConnection -State Listen -LocalPort $ports -ErrorAction SilentlyContinue | ForEach-Object { [pscustomobject]@{ port = [int]$_.LocalPort; pid = [int]$_.OwningProcess } }) } else { $gap = 'listening ports: no Get-NetTCPConnection' } }",
172
+ '[pscustomobject]@{ processes = $procs; listeners = $listen; gap = $gap } | ConvertTo-Json -Compress -Depth 3',
173
+ ].join('\n');
174
+ }
175
+ export function worktreeProcesses(host = {}) {
176
+ const platform = host.platform ?? hostPlatform();
177
+ const run = host.run ?? runCommand;
178
+ const self = host.self ?? process.pid;
179
+ const kill = host.kill ?? ((pid, signal) => process.kill(pid, signal));
180
+ const proc = host.proc ?? realProc;
181
+ // A zombie answers kill(pid, 0) until its parent reaps it, but it has ended: Linux says so in /proc.
182
+ const alive = host.alive ??
183
+ (platform === 'linux'
184
+ ? (pid) => processAlive(pid) && !isZombie(proc.read(posix.join('/proc', String(pid), 'stat')))
185
+ : processAlive);
186
+ const sleep = host.sleep ?? ((ms) => new Promise((done) => setTimeout(done, ms)));
187
+ return {
188
+ find: async (worktree, ports) => {
189
+ const listing = await listProcesses(platform, ports, run, proc);
190
+ return { processes: belonging(listing, worktree, ports, self, platform), unseen: listing.unseen };
191
+ },
192
+ stop: async (pids) => {
193
+ const send = (signal, to) => {
194
+ for (const pid of to) {
195
+ try {
196
+ kill(pid, signal);
197
+ }
198
+ catch {
199
+ // Gone already, or not ours to end: what still runs is reported below.
200
+ }
201
+ }
202
+ };
203
+ // On Windows every signal ends the process at once (TerminateProcess).
204
+ send(platform === 'win32' ? 'SIGKILL' : 'SIGTERM', pids);
205
+ for (let waited = 0; waited < (platform === 'win32' ? 1000 : TERM_MS); waited += 250) {
206
+ if (!pids.some(alive))
207
+ return [];
208
+ await sleep(250);
209
+ }
210
+ if (platform !== 'win32') {
211
+ send('SIGKILL', pids.filter(alive));
212
+ await sleep(250);
213
+ }
214
+ return pids.filter(alive);
215
+ },
216
+ };
217
+ }
218
+ function addListener(listeners, ports, port, pid) {
219
+ if (port === null || !ports.includes(port) || !Number.isInteger(pid) || pid <= 0)
220
+ return;
221
+ const pids = listeners.get(port) ?? [];
222
+ if (!pids.includes(pid))
223
+ listeners.set(port, [...pids, pid]);
224
+ }
225
+ // Whether the path is inside the root: a file in it, never the folder itself, which only an argument
226
+ // names (a terminal's or an editor's). Both are normal().
227
+ function isUnder(path, root, platform) {
228
+ const sep = platform === 'win32' ? '\\' : '/';
229
+ const prefix = root.endsWith(sep) ? root : `${root}${sep}`;
230
+ return path.length > prefix.length && path.startsWith(prefix);
231
+ }
232
+ // Whether a /proc/<pid>/stat says the process is a zombie: its state, after the command's `) `, is Z.
233
+ function isZombie(stat) {
234
+ return stat !== null && stat.charAt(stat.lastIndexOf(')') + 2) === 'Z';
235
+ }
236
+ // Linux: every process's parent and start from /proc/<pid>/stat, its executable and its command line.
237
+ // A process that ends while it is read, or one of another user's whose exe can't be read, keeps what
238
+ // could be read.
239
+ function linuxProcesses(proc) {
240
+ const entries = [];
241
+ for (const name of proc.list()) {
242
+ if (!/^\d+$/.test(name))
243
+ continue;
244
+ const stat = proc.read(posix.join('/proc', name, 'stat'));
245
+ // pid (comm) state ppid … starttime (field 22); comm may hold spaces and parentheses.
246
+ const fields = stat?.slice(stat.lastIndexOf(')') + 2).split(' ');
247
+ if (!fields)
248
+ continue;
249
+ const cmdline = proc.read(posix.join('/proc', name, 'cmdline')) ?? '';
250
+ entries.push({
251
+ // Quoted where a word holds a space, so programPaths reads the words back.
252
+ command: cmdline
253
+ .split('\0')
254
+ .filter(Boolean)
255
+ .map((word) => (/\s/.test(word) ? `"${word}"` : word))
256
+ .join(' '),
257
+ executable: proc.link(posix.join('/proc', name, 'exe')),
258
+ pid: Number(name),
259
+ ppid: Number(fields[1]),
260
+ started: Number(fields[19]) || null,
261
+ });
262
+ }
263
+ return entries;
264
+ }
265
+ async function listProcesses(platform, ports, run, proc) {
266
+ if (platform === 'win32') {
267
+ const result = await run('powershell.exe', [
268
+ '-NoProfile',
269
+ '-NonInteractive',
270
+ '-EncodedCommand',
271
+ Buffer.from(windowsListingScript(ports), 'utf16le').toString('base64'),
272
+ ], { timeoutMs: 30_000 });
273
+ if (result.code !== 0)
274
+ throw new ConductorError("couldn't list the processes", [outputOf(result, 500)]);
275
+ return parseWindowsListing(result.stdout, ports);
276
+ }
277
+ const unseen = [];
278
+ let processes;
279
+ if (platform === 'linux') {
280
+ processes = linuxProcesses(proc);
281
+ }
282
+ else {
283
+ // -ww: BSD ps cuts a line at the terminal's width, or 80 columns with none.
284
+ const ps = await run('ps', ['-A', '-ww', '-o', 'pid=,ppid=,args='], { timeoutMs: 20_000 });
285
+ if (ps.code !== 0)
286
+ throw new ConductorError("couldn't list the processes", [outputOf(ps, 500)]);
287
+ processes = parsePs(ps.stdout);
288
+ }
289
+ let listeners = new Map();
290
+ if (ports.length > 0) {
291
+ const result = platform === 'linux'
292
+ ? await run('ss', ['-ltnpH'], { timeoutMs: 20_000 })
293
+ : await run('lsof', ['-nP', '-iTCP', '-sTCP:LISTEN', '-Fpn'], { timeoutMs: 20_000 });
294
+ // lsof exits 1 when nothing listens.
295
+ if (result.code === 0 || (platform === 'darwin' && result.code === 1 && result.stdout.trim() === ''))
296
+ listeners = platform === 'linux' ? parseSs(result.stdout, ports) : parseLsofListeners(result.stdout, ports);
297
+ else
298
+ unseen.push(`listening ports: ${platform === 'linux' ? 'ss' : 'lsof'} failed: ${outputOf(result, 200)}`);
299
+ }
300
+ return { listeners, processes, unseen };
301
+ }
302
+ // A path as compared: Windows' without case and with backslashes alone, so `C:/wt/X` matches `C:\wt\X`.
303
+ function normal(path, platform) {
304
+ return platform === 'win32' ? path.replace(/\//g, '\\').toLowerCase() : path;
305
+ }
306
+ function parseJson(text) {
307
+ try {
308
+ // A PowerShell can start its UTF-8 output with a byte order mark.
309
+ return JSON.parse(text.charCodeAt(0) === 0xfeff ? text.slice(1) : text);
310
+ }
311
+ catch {
312
+ return null;
313
+ }
314
+ }
315
+ function portOf(address) {
316
+ const port = Number(/:(\d+)$/.exec(address.trim())?.[1]);
317
+ return Number.isInteger(port) && port > 0 ? port : null;
318
+ }
319
+ // A program's file name, lower case and without .exe on Windows.
320
+ function programName(path, platform) {
321
+ const base = platform === 'win32' ? win32.basename(path.replace(/\//g, '\\')) : posix.basename(path);
322
+ return platform === 'win32' ? base.toLowerCase().replace(/\.exe$/, '') : base;
323
+ }
324
+ // The paths a process runs from, normal(): its executable, its program word, and, for an interpreter
325
+ // such as node, the script it runs (the first absolute path among the words after the program that
326
+ // aren't options, past an option's value such as `--import tsx`). Never another argument: a process
327
+ // that only takes the worktree as one, such as a terminal or editor opened there or a shell told to
328
+ // cd there, doesn't run from it, and its tree isn't the worker's.
329
+ function programPaths(entry, platform) {
330
+ const path = platform === 'win32' ? win32 : posix;
331
+ const words = [...entry.command.matchAll(/"([^"]*)"|(\S+)/g)].map((m) => m[1] ?? m[2] ?? '');
332
+ const [program = '', ...rest] = words;
333
+ const paths = [program, ...(entry.executable === null ? [] : [entry.executable])];
334
+ if (INTERPRETERS.has(programName(entry.executable ?? program, platform))) {
335
+ const script = rest.find((word) => !word.startsWith('-') && path.isAbsolute(word));
336
+ if (script !== undefined)
337
+ paths.push(script);
338
+ }
339
+ // Normalized, so `<worktree>\..\elsewhere` isn't taken for a path in the worktree.
340
+ return paths.filter((p) => path.isAbsolute(p)).map((p) => normal(path.normalize(p), platform));
341
+ }
342
+ // The worktree's path as given and as its real (long, linked) form, without a trailing separator.
343
+ function worktreeRoots(worktree, platform) {
344
+ const path = platform === 'win32' ? win32 : posix;
345
+ const trim = (p) => {
346
+ const n = normal(p, platform);
347
+ return n.length > 1 && /[\\/]$/.test(n) && !/^[a-z]:\\$/.test(n) ? n.slice(0, -1) : n;
348
+ };
349
+ return [...new Set([trim(path.resolve(worktree)), trim(realOr(worktree))])];
350
+ }
351
+ const realProc = {
352
+ link: (p) => {
353
+ try {
354
+ return readlinkSync(p);
355
+ }
356
+ catch {
357
+ return null;
358
+ }
359
+ },
360
+ list: () => {
361
+ try {
362
+ return readdirSync('/proc');
363
+ }
364
+ catch {
365
+ return [];
366
+ }
367
+ },
368
+ read: (p) => {
369
+ try {
370
+ return readFileSync(p, 'utf8');
371
+ }
372
+ catch {
373
+ return null;
374
+ }
375
+ },
376
+ };
377
+ const windowsListing = z.object({
378
+ gap: z.string().nullish(),
379
+ // ConvertTo-Json writes a one-element array as the element alone in some PowerShells.
380
+ listeners: z.preprocess((v) => (v === null || v === undefined ? [] : Array.isArray(v) ? v : [v]), z.array(z.object({ pid: z.number(), port: z.number() }))),
381
+ processes: z.preprocess((v) => (v === null || v === undefined ? [] : Array.isArray(v) ? v : [v]), z.array(z.object({
382
+ c: z.string().nullish(),
383
+ e: z.string().nullish(),
384
+ p: z.number(),
385
+ pp: z.number(),
386
+ s: z.number().nullish(),
387
+ }))),
388
+ });
389
+ //# sourceMappingURL=worktree-processes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-processes.js","sourceRoot":"","sources":["../../src/host/worktree-processes.ts"],"names":[],"mappings":"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"}
package/build/inbox.js CHANGED
@@ -10,6 +10,7 @@ import { refusalProblems } from "./rules-service.js";
10
10
  import { formatTokens } from "./spend.js";
11
11
  import {} from "./store.js";
12
12
  import { describePending, pendingCallSchema } from "./transcript.js";
13
+ import { goneMessage } from "./watchers/source.js";
13
14
  // A Handoff kind (protocol.ts) to the item it raises. `conductor` isn't the operator's: the console
14
15
  // answers it.
15
16
  const NOTE_KINDS = {
@@ -97,6 +98,9 @@ const waitData = z.looseObject({
97
98
  // A PR's settled checks, on a checks wait (watchers/index.ts).
98
99
  checks: z.string().optional(),
99
100
  condition: z.string(),
101
+ // The item the wait's tracker no longer has (watchers/index.ts, ATK-870).
102
+ gone: z.string().optional(),
103
+ name: z.string().optional(),
100
104
  resolution: z.string().optional(),
101
105
  worker: z.number(),
102
106
  });
@@ -354,11 +358,30 @@ export function inboxService({ onWaitResolved, store, tracker }) {
354
358
  .at(-1);
355
359
  return newest?.resolvedBy?.startsWith(HELD) ? newest : null;
356
360
  };
361
+ // A wait whose item its tracker no longer has (ATK-870): the worker wakes to it, and the operator
362
+ // hears of it once per worker and item, until the worker's next note on its item or its retire.
363
+ const onGone = (event, gone, resolution, worker, name) => {
364
+ const text = `${goneText(gone)} (${goneMessage(gone, resolution)}), so ${name ?? 'its worker'}'s wait on it ended and it woke`;
365
+ if (openOf(worker, ['failed']).some((i) => i.text.startsWith(goneText(gone))))
366
+ return;
367
+ raise({
368
+ commands: name === undefined ? [] : [`conduct attach ${name}`],
369
+ condition: null,
370
+ item: event.subject,
371
+ kind: 'failed',
372
+ links: [],
373
+ project: event.project,
374
+ text,
375
+ worker,
376
+ });
377
+ };
357
378
  const onResolvedWait = (event) => {
358
379
  const data = waitData.safeParse(event.data);
359
380
  if (!data.success)
360
381
  return;
361
- const { checks, condition: text, resolution = text, worker } = data.data;
382
+ const { checks, condition: text, gone, name, resolution = text, worker } = data.data;
383
+ if (gone !== undefined)
384
+ onGone(event, gone, resolution, worker, name);
362
385
  const condition = conditionOf(text);
363
386
  const release = condition ? releaseGate(condition.kind) : null;
364
387
  if (condition?.kind === 'approval') {
@@ -521,7 +544,7 @@ export function inboxService({ onWaitResolved, store, tracker }) {
521
544
  // Red checks are the PR's, and a failed Handoff the worker's, not the session's: a lost session
522
545
  // still raises its own failure.
523
546
  const own = (kind, text, commands) => {
524
- if (openOf(worker, [kind]).some((i) => !isChecksFailure(i) && !answeredOnItem(i)))
547
+ if (openOf(worker, [kind]).some((i) => !isChecksFailure(i) && !answeredOnItem(i) && !isGoneItem(i)))
525
548
  return;
526
549
  raise({ commands, condition: null, item: event.subject, kind, links: [], project: event.project, text, worker });
527
550
  };
@@ -583,8 +606,8 @@ export function inboxService({ onWaitResolved, store, tracker }) {
583
606
  case 'worker.revived':
584
607
  case 'worker.running-again':
585
608
  // Red checks wake their worker, which doesn't make them green, and a failed Handoff waits on
586
- // its answer or the worker's next note (ATK-718).
587
- resolveAll(openOf(worker, [...SESSION_KINDS, 'failed']).filter((i) => !isChecksFailure(i) && !answeredOnItem(i)), `${name} running again`);
609
+ // its answer or the worker's next note (ATK-718), as does a gone item, which woke it (ATK-870).
610
+ resolveAll(openOf(worker, [...SESSION_KINDS, 'failed']).filter((i) => !isChecksFailure(i) && !answeredOnItem(i) && !isGoneItem(i)), `${name} running again`);
588
611
  return;
589
612
  case 'worker.retired': {
590
613
  resolveAll(store.openInbox().filter((i) => i.worker === worker), `${name} retired`);
@@ -807,6 +830,10 @@ function conditionOf(text) {
807
830
  return null;
808
831
  }
809
832
  }
833
+ // How a gone item's failure starts (onGone raises them), which also marks it as one.
834
+ function goneText(item) {
835
+ return `${item} is gone from its tracker`;
836
+ }
810
837
  // A failure about a PR's red checks (onChecksFailed raises them), the only failure on a checks wait.
811
838
  function isChecksFailure(item) {
812
839
  return item.kind === 'failed' && item.condition !== null && item.condition.endsWith(':checks');
@@ -816,6 +843,10 @@ function isChecksFailure(item) {
816
843
  function isCompactFailure(item) {
817
844
  return item.kind === 'context' && item.commands.some((c) => c.startsWith('conduct retire '));
818
845
  }
846
+ // A failure about an item its tracker no longer has (onGone raises them).
847
+ function isGoneItem(item) {
848
+ return item.kind === 'failed' && /^\S+ is gone from its tracker /.test(item.text);
849
+ }
819
850
  function isParkStall(item) {
820
851
  return item.kind === 'stall' && item.commands.some((c) => c.startsWith('conduct retire '));
821
852
  }