@agentteams/runner 0.0.84-dev.206 → 0.0.84-dev.208
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-client.d.ts +2 -2
- package/dist/api-client.js +66 -66
- package/dist/api-client.js.map +1 -1
- package/dist/api-client.test.js +63 -54
- package/dist/api-client.test.js.map +1 -1
- package/dist/autostart.js +81 -81
- package/dist/autostart.js.map +1 -1
- package/dist/autostart.test.js +35 -35
- package/dist/autostart.test.js.map +1 -1
- package/dist/commands/cleanup.js +4 -4
- package/dist/commands/init.js +14 -14
- package/dist/commands/restart.js +3 -3
- package/dist/commands/start.js +10 -10
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.js +7 -7
- package/dist/commands/stop.js +7 -7
- package/dist/commands/uninstall.js +6 -6
- package/dist/commands/update.d.ts +4 -4
- package/dist/commands/update.js +20 -22
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/update.test.js +38 -42
- package/dist/commands/update.test.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +12 -12
- package/dist/config.test.js +61 -61
- package/dist/config.test.js.map +1 -1
- package/dist/daemon-control.d.ts +5 -5
- package/dist/daemon-control.js +21 -22
- package/dist/daemon-control.js.map +1 -1
- package/dist/daemon-control.test.js +29 -29
- package/dist/executable.d.ts +3 -3
- package/dist/executable.js +46 -49
- package/dist/executable.js.map +1 -1
- package/dist/executable.test.js +62 -62
- package/dist/executable.test.js.map +1 -1
- package/dist/handlers/trigger-handler.d.ts +6 -6
- package/dist/handlers/trigger-handler.js +118 -124
- package/dist/handlers/trigger-handler.js.map +1 -1
- package/dist/handlers/trigger-handler.test.js +373 -365
- package/dist/handlers/trigger-handler.test.js.map +1 -1
- package/dist/index.js +25 -25
- package/dist/logger.js +1 -1
- package/dist/pid.js +6 -6
- package/dist/poller.d.ts +7 -7
- package/dist/poller.js +54 -53
- package/dist/poller.js.map +1 -1
- package/dist/poller.test.js +209 -181
- package/dist/poller.test.js.map +1 -1
- package/dist/runners/amp.d.ts +1 -1
- package/dist/runners/amp.js +74 -81
- package/dist/runners/amp.js.map +1 -1
- package/dist/runners/antigravity.d.ts +3 -3
- package/dist/runners/antigravity.js +116 -127
- package/dist/runners/antigravity.js.map +1 -1
- package/dist/runners/antigravity.replay.test.js +25 -25
- package/dist/runners/antigravity.replay.test.js.map +1 -1
- package/dist/runners/antigravity.test.js +98 -98
- package/dist/runners/antigravity.test.js.map +1 -1
- package/dist/runners/claude-code.d.ts +1 -1
- package/dist/runners/claude-code.js +85 -84
- package/dist/runners/claude-code.js.map +1 -1
- package/dist/runners/claude-code.test.js +37 -40
- package/dist/runners/claude-code.test.js.map +1 -1
- package/dist/runners/codex.d.ts +1 -1
- package/dist/runners/codex.js +87 -96
- package/dist/runners/codex.js.map +1 -1
- package/dist/runners/codex.test.js +68 -68
- package/dist/runners/codex.test.js.map +1 -1
- package/dist/runners/index.d.ts +1 -1
- package/dist/runners/index.js +10 -10
- package/dist/runners/index.test.js +16 -16
- package/dist/runners/log-reporter.d.ts +2 -2
- package/dist/runners/log-reporter.js +10 -10
- package/dist/runners/log-reporter.test.js +70 -70
- package/dist/runners/log-reporter.test.js.map +1 -1
- package/dist/runners/opencode.d.ts +1 -1
- package/dist/runners/opencode.js +68 -75
- package/dist/runners/opencode.js.map +1 -1
- package/dist/runners/process-control.d.ts +1 -1
- package/dist/runners/process-control.js +13 -11
- package/dist/runners/process-control.js.map +1 -1
- package/dist/runners/stream-json-parser.d.ts +1 -1
- package/dist/runners/stream-json-parser.js +70 -67
- package/dist/runners/stream-json-parser.js.map +1 -1
- package/dist/runners/stream-json-parser.replay.test.js +17 -17
- package/dist/runners/stream-json-parser.replay.test.js.map +1 -1
- package/dist/runners/stream-json-parser.test.js +76 -78
- package/dist/runners/stream-json-parser.test.js.map +1 -1
- package/dist/types.d.ts +4 -4
- package/dist/utils/auth-path-store.js +7 -7
- package/dist/utils/auth-path-store.test.js +24 -29
- package/dist/utils/auth-path-store.test.js.map +1 -1
- package/dist/utils/auto-update.d.ts +4 -4
- package/dist/utils/auto-update.js +30 -28
- package/dist/utils/auto-update.js.map +1 -1
- package/dist/utils/auto-update.test.js +30 -30
- package/dist/utils/convention-evaluator.d.ts +1 -1
- package/dist/utils/convention-evaluator.js +22 -21
- package/dist/utils/convention-evaluator.js.map +1 -1
- package/dist/utils/convention-evaluator.test.js +120 -110
- package/dist/utils/convention-evaluator.test.js.map +1 -1
- package/dist/utils/convention-sync.d.ts +3 -3
- package/dist/utils/convention-sync.js +10 -10
- package/dist/utils/convention-sync.test.js +39 -25
- package/dist/utils/convention-sync.test.js.map +1 -1
- package/dist/utils/git-worktree.js +20 -18
- package/dist/utils/git-worktree.js.map +1 -1
- package/dist/utils/git-worktree.test.js +98 -98
- package/dist/utils/git-worktree.test.js.map +1 -1
- package/dist/utils/origin-issue-safeguard.js +35 -30
- package/dist/utils/origin-issue-safeguard.js.map +1 -1
- package/dist/utils/power-save-blocker.d.ts +4 -4
- package/dist/utils/power-save-blocker.js +33 -33
- package/dist/utils/power-save-blocker.test.js +37 -37
- package/dist/utils/power-save-blocker.test.js.map +1 -1
- package/dist/utils/runner-cleanup.d.ts +3 -3
- package/dist/utils/runner-cleanup.js +13 -13
- package/dist/utils/runner-cleanup.test.js +35 -35
- package/dist/utils/runner-history.js +3 -3
- package/dist/utils/runner-history.test.js +17 -17
- package/package.json +4 -1
- package/readme.md +10 -10
package/dist/poller.test.js
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import assert from
|
|
2
|
-
import * as fsModule from
|
|
3
|
-
import os from
|
|
4
|
-
import path from
|
|
5
|
-
import test, { mock } from
|
|
6
|
-
import { logger } from
|
|
7
|
-
import { startPolling } from
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import * as fsModule from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import test, { mock } from 'node:test';
|
|
6
|
+
import { logger } from './logger.js';
|
|
7
|
+
import { startPolling } from './poller.js';
|
|
8
8
|
const config = {
|
|
9
|
-
daemonToken:
|
|
10
|
-
apiUrl:
|
|
9
|
+
daemonToken: 'daemon-token',
|
|
10
|
+
apiUrl: 'https://api.example',
|
|
11
11
|
pollingIntervalMs: 5000,
|
|
12
12
|
timeoutMs: 1000,
|
|
13
13
|
idleTimeoutMs: 500,
|
|
14
|
-
runnerCmd:
|
|
15
|
-
preventSleepWhileBusy: false
|
|
14
|
+
runnerCmd: 'opencode',
|
|
15
|
+
preventSleepWhileBusy: false,
|
|
16
16
|
};
|
|
17
17
|
const trigger = {
|
|
18
|
-
id:
|
|
19
|
-
prompt:
|
|
20
|
-
runnerType:
|
|
21
|
-
model:
|
|
18
|
+
id: 'trigger-1',
|
|
19
|
+
prompt: 'hello',
|
|
20
|
+
runnerType: 'CODEX',
|
|
21
|
+
model: 'o4-mini',
|
|
22
22
|
fastMode: false,
|
|
23
|
-
status:
|
|
24
|
-
agentConfigId:
|
|
23
|
+
status: 'PENDING',
|
|
24
|
+
agentConfigId: 'agent-1',
|
|
25
25
|
startedAt: null,
|
|
26
26
|
errorMessage: null,
|
|
27
27
|
worktreeError: null,
|
|
28
28
|
lastHeartbeatAt: null,
|
|
29
29
|
conversationId: null,
|
|
30
30
|
parentTriggerId: null,
|
|
31
|
-
createdByMemberId:
|
|
31
|
+
createdByMemberId: 'member-1',
|
|
32
32
|
planMode: false,
|
|
33
33
|
targetDaemonId: null,
|
|
34
34
|
claimedByDaemonId: null,
|
|
@@ -36,8 +36,8 @@ const trigger = {
|
|
|
36
36
|
baseBranch: null,
|
|
37
37
|
worktreeId: null,
|
|
38
38
|
worktreeStatus: null,
|
|
39
|
-
createdAt:
|
|
40
|
-
updatedAt:
|
|
39
|
+
createdAt: '2026-01-01T00:00:00.000Z',
|
|
40
|
+
updatedAt: '2026-01-01T00:00:00.000Z',
|
|
41
41
|
};
|
|
42
42
|
test.afterEach(() => {
|
|
43
43
|
mock.restoreAll();
|
|
@@ -48,15 +48,15 @@ const createRecordingBlocker = () => {
|
|
|
48
48
|
events,
|
|
49
49
|
blocker: {
|
|
50
50
|
acquire: (label) => {
|
|
51
|
-
events.push(`acquire:${label ??
|
|
52
|
-
return () => events.push(`release:${label ??
|
|
53
|
-
}
|
|
54
|
-
}
|
|
51
|
+
events.push(`acquire:${label ?? ''}`);
|
|
52
|
+
return () => events.push(`release:${label ?? ''}`);
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
55
|
};
|
|
56
56
|
};
|
|
57
|
-
test(
|
|
57
|
+
test('startPolling handles a claimed trigger, registers auth paths, and runs scheduled cleanup', async () => {
|
|
58
58
|
const infos = [];
|
|
59
|
-
mock.method(logger,
|
|
59
|
+
mock.method(logger, 'info', (message, meta) => {
|
|
60
60
|
infos.push({ message, meta });
|
|
61
61
|
});
|
|
62
62
|
const signals = new Map();
|
|
@@ -74,10 +74,10 @@ test("startPolling handles a claimed trigger, registers auth paths, and runs sch
|
|
|
74
74
|
fetchPendingWorktreeRemovals: async () => [],
|
|
75
75
|
reportWorktreeStatus: async () => undefined,
|
|
76
76
|
notifyUpdate: async () => undefined,
|
|
77
|
-
ackRestartRequest: async () => undefined
|
|
77
|
+
ackRestartRequest: async () => undefined,
|
|
78
78
|
};
|
|
79
79
|
const createHandler = (onAuthPathDiscovered) => {
|
|
80
|
-
onAuthPathDiscovered(
|
|
80
|
+
onAuthPathDiscovered('/auth/path');
|
|
81
81
|
return async (value) => {
|
|
82
82
|
handledTriggers.push(value.id);
|
|
83
83
|
};
|
|
@@ -97,39 +97,40 @@ test("startPolling handles a claimed trigger, registers auth paths, and runs sch
|
|
|
97
97
|
signals.set(event, listener);
|
|
98
98
|
}),
|
|
99
99
|
processExit: (() => {
|
|
100
|
-
throw new Error(
|
|
100
|
+
throw new Error('should not exit');
|
|
101
101
|
}),
|
|
102
102
|
now: () => nowValue,
|
|
103
103
|
loadAuthPaths: () => [],
|
|
104
104
|
saveAuthPath: (authPath) => {
|
|
105
105
|
savedAuthPaths.push(authPath);
|
|
106
|
-
return
|
|
106
|
+
return '/tmp/auth-paths.json';
|
|
107
107
|
},
|
|
108
108
|
keepAlive: () => new Promise((resolve) => {
|
|
109
109
|
keepAliveResolve = resolve;
|
|
110
|
-
})
|
|
110
|
+
}),
|
|
111
111
|
});
|
|
112
112
|
await new Promise((resolve) => setImmediate(resolve));
|
|
113
|
-
assert.deepEqual(handledTriggers, [
|
|
113
|
+
assert.deepEqual(handledTriggers, ['trigger-1']);
|
|
114
114
|
assert.deepEqual(cleanupCalls, []);
|
|
115
115
|
assert.equal(intervalCallbacks.length, 1);
|
|
116
116
|
nowValue = 24 * 60 * 60 * 1000 + 1;
|
|
117
117
|
await intervalCallbacks[0]?.();
|
|
118
118
|
await new Promise((resolve) => setImmediate(resolve));
|
|
119
|
-
assert.deepEqual(cleanupCalls, [
|
|
120
|
-
assert.deepEqual(savedAuthPaths, [
|
|
121
|
-
assert.equal(signals.has(
|
|
122
|
-
assert.equal(signals.has(
|
|
123
|
-
assert.equal(infos.some((entry) => entry.message ===
|
|
124
|
-
const resolveKeepAlive = keepAliveResolve ??
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
assert.deepEqual(cleanupCalls, ['/auth/path']);
|
|
120
|
+
assert.deepEqual(savedAuthPaths, ['/auth/path']);
|
|
121
|
+
assert.equal(signals.has('SIGINT'), true);
|
|
122
|
+
assert.equal(signals.has('SIGTERM'), true);
|
|
123
|
+
assert.equal(infos.some((entry) => entry.message === 'Daemon polling started'), true);
|
|
124
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
125
|
+
(() => {
|
|
126
|
+
throw new Error('keepAlive resolver was not registered');
|
|
127
|
+
});
|
|
127
128
|
resolveKeepAlive();
|
|
128
129
|
await pollingPromise;
|
|
129
130
|
});
|
|
130
|
-
test(
|
|
131
|
+
test('startPolling logs conflicts and suppresses overlapping polling cycles', async () => {
|
|
131
132
|
const infos = [];
|
|
132
|
-
mock.method(logger,
|
|
133
|
+
mock.method(logger, 'info', (message, meta) => {
|
|
133
134
|
infos.push({ message, meta });
|
|
134
135
|
});
|
|
135
136
|
let releaseFetch = null;
|
|
@@ -143,12 +144,12 @@ test("startPolling logs conflicts and suppresses overlapping polling cycles", as
|
|
|
143
144
|
fetchPendingWorktreeRemovals: async () => [],
|
|
144
145
|
reportWorktreeStatus: async () => undefined,
|
|
145
146
|
notifyUpdate: async () => undefined,
|
|
146
|
-
ackRestartRequest: async () => undefined
|
|
147
|
+
ackRestartRequest: async () => undefined,
|
|
147
148
|
};
|
|
148
149
|
const intervalCallbacks = [];
|
|
149
150
|
let keepAliveResolve = null;
|
|
150
151
|
const pollingPromise = startPolling(config, () => async () => {
|
|
151
|
-
throw new Error(
|
|
152
|
+
throw new Error('handler should not run');
|
|
152
153
|
}, {
|
|
153
154
|
createClient: () => client,
|
|
154
155
|
runCleanup: async () => undefined,
|
|
@@ -159,30 +160,32 @@ test("startPolling logs conflicts and suppresses overlapping polling cycles", as
|
|
|
159
160
|
clearInterval: (() => undefined),
|
|
160
161
|
processOn: (() => undefined),
|
|
161
162
|
processExit: (() => {
|
|
162
|
-
throw new Error(
|
|
163
|
+
throw new Error('should not exit');
|
|
163
164
|
}),
|
|
164
165
|
now: () => 0,
|
|
165
166
|
loadAuthPaths: () => [],
|
|
166
|
-
saveAuthPath: () =>
|
|
167
|
+
saveAuthPath: () => '/tmp/auth-paths.json',
|
|
167
168
|
keepAlive: () => new Promise((resolve) => {
|
|
168
169
|
keepAliveResolve = resolve;
|
|
169
|
-
})
|
|
170
|
+
}),
|
|
170
171
|
});
|
|
171
172
|
await new Promise((resolve) => setImmediate(resolve));
|
|
172
173
|
await intervalCallbacks[0]?.();
|
|
173
|
-
const releasePendingFetch = releaseFetch ??
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
const releasePendingFetch = releaseFetch ??
|
|
175
|
+
(() => {
|
|
176
|
+
throw new Error('fetch release was not registered');
|
|
177
|
+
});
|
|
176
178
|
releasePendingFetch();
|
|
177
179
|
await new Promise((resolve) => setImmediate(resolve));
|
|
178
|
-
assert.equal(infos.some((entry) => entry.message ===
|
|
179
|
-
const resolveKeepAlive = keepAliveResolve ??
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
assert.equal(infos.some((entry) => entry.message === 'Trigger already claimed by another daemon'), true);
|
|
181
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
182
|
+
(() => {
|
|
183
|
+
throw new Error('keepAlive resolver was not registered');
|
|
184
|
+
});
|
|
182
185
|
resolveKeepAlive();
|
|
183
186
|
await pollingPromise;
|
|
184
187
|
});
|
|
185
|
-
test(
|
|
188
|
+
test('startPolling clears the interval and exits on shutdown signals', async () => {
|
|
186
189
|
const signals = new Map();
|
|
187
190
|
const cleared = [];
|
|
188
191
|
let keepAliveResolve = null;
|
|
@@ -197,7 +200,7 @@ test("startPolling clears the interval and exits on shutdown signals", async ()
|
|
|
197
200
|
fetchPendingWorktreeRemovals: async () => [],
|
|
198
201
|
reportWorktreeStatus: async () => undefined,
|
|
199
202
|
notifyUpdate: async () => undefined,
|
|
200
|
-
ackRestartRequest: async () => undefined
|
|
203
|
+
ackRestartRequest: async () => undefined,
|
|
201
204
|
}),
|
|
202
205
|
runCleanup: async () => undefined,
|
|
203
206
|
setInterval: (() => intervalHandle),
|
|
@@ -213,36 +216,37 @@ test("startPolling clears the interval and exits on shutdown signals", async ()
|
|
|
213
216
|
}),
|
|
214
217
|
now: () => 0,
|
|
215
218
|
loadAuthPaths: () => [],
|
|
216
|
-
saveAuthPath: () =>
|
|
219
|
+
saveAuthPath: () => '/tmp/auth-paths.json',
|
|
217
220
|
keepAlive: () => new Promise((resolve) => {
|
|
218
221
|
keepAliveResolve = resolve;
|
|
219
|
-
})
|
|
222
|
+
}),
|
|
220
223
|
}).catch((error) => {
|
|
221
|
-
if (error.message !==
|
|
224
|
+
if (error.message !== 'exit') {
|
|
222
225
|
throw error;
|
|
223
226
|
}
|
|
224
227
|
});
|
|
225
228
|
await new Promise((resolve) => setImmediate(resolve));
|
|
226
|
-
assert.ok(signals.get(
|
|
227
|
-
const sigterm = signals.get(
|
|
229
|
+
assert.ok(signals.get('SIGTERM'));
|
|
230
|
+
const sigterm = signals.get('SIGTERM');
|
|
228
231
|
assert.ok(sigterm);
|
|
229
232
|
sigterm();
|
|
230
233
|
assert.equal(exitCode, 0);
|
|
231
234
|
assert.deepEqual(cleared, [intervalHandle]);
|
|
232
|
-
const resolveKeepAlive = keepAliveResolve ??
|
|
233
|
-
|
|
234
|
-
|
|
235
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
236
|
+
(() => {
|
|
237
|
+
throw new Error('keepAlive resolver was not registered');
|
|
238
|
+
});
|
|
235
239
|
resolveKeepAlive();
|
|
236
240
|
await pollingPromise;
|
|
237
241
|
});
|
|
238
|
-
test(
|
|
242
|
+
test('startPolling delegates auto-update via injected dependency', async () => {
|
|
239
243
|
let autoUpdateCallCount = 0;
|
|
240
244
|
let keepAliveResolve = null;
|
|
241
245
|
const pollingPromise = startPolling(config, () => async () => undefined, {
|
|
242
246
|
createClient: () => ({
|
|
243
247
|
fetchPendingTrigger: async () => ({
|
|
244
248
|
data: null,
|
|
245
|
-
meta: { cliLatestVersion: null, runnerLatestVersion:
|
|
249
|
+
meta: { cliLatestVersion: null, runnerLatestVersion: '99.0.0' },
|
|
246
250
|
}),
|
|
247
251
|
claimTrigger: async () => ({ ok: true, conflict: false }),
|
|
248
252
|
fetchOrphanedCancelRequested: async () => [],
|
|
@@ -250,7 +254,7 @@ test("startPolling delegates auto-update via injected dependency", async () => {
|
|
|
250
254
|
fetchPendingWorktreeRemovals: async () => [],
|
|
251
255
|
reportWorktreeStatus: async () => undefined,
|
|
252
256
|
notifyUpdate: async () => undefined,
|
|
253
|
-
ackRestartRequest: async () => undefined
|
|
257
|
+
ackRestartRequest: async () => undefined,
|
|
254
258
|
}),
|
|
255
259
|
runCleanup: async () => undefined,
|
|
256
260
|
maybeAutoUpdate: async () => {
|
|
@@ -263,33 +267,34 @@ test("startPolling delegates auto-update via injected dependency", async () => {
|
|
|
263
267
|
processExit: (() => undefined),
|
|
264
268
|
now: () => 0,
|
|
265
269
|
loadAuthPaths: () => [],
|
|
266
|
-
saveAuthPath: () =>
|
|
270
|
+
saveAuthPath: () => '/tmp/auth-paths.json',
|
|
267
271
|
keepAlive: () => new Promise((resolve) => {
|
|
268
272
|
keepAliveResolve = resolve;
|
|
269
|
-
})
|
|
273
|
+
}),
|
|
270
274
|
});
|
|
271
275
|
await new Promise((resolve) => setImmediate(resolve));
|
|
272
|
-
assert.equal(autoUpdateCallCount, 1,
|
|
273
|
-
const resolveKeepAlive = keepAliveResolve ??
|
|
274
|
-
|
|
275
|
-
|
|
276
|
+
assert.equal(autoUpdateCallCount, 1, 'should call injected maybeAutoUpdate on idle poll');
|
|
277
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
278
|
+
(() => {
|
|
279
|
+
throw new Error('keepAlive resolver was not registered');
|
|
280
|
+
});
|
|
276
281
|
resolveKeepAlive();
|
|
277
282
|
await pollingPromise;
|
|
278
283
|
});
|
|
279
|
-
test(
|
|
284
|
+
test('startPolling restores persisted auth paths for worktree removals after restart', async () => {
|
|
280
285
|
const removedWorktrees = [];
|
|
281
286
|
const reportedStatuses = [];
|
|
282
|
-
const tempRoot = fsModule.mkdtempSync(path.join(os.tmpdir(),
|
|
283
|
-
const authPath = path.join(tempRoot,
|
|
284
|
-
const worktreePath = path.join(tempRoot,
|
|
287
|
+
const tempRoot = fsModule.mkdtempSync(path.join(os.tmpdir(), 'agentrunner-poller-'));
|
|
288
|
+
const authPath = path.join(tempRoot, 'path');
|
|
289
|
+
const worktreePath = path.join(tempRoot, '.path-worktrees', 'wt-worktree-1');
|
|
285
290
|
fsModule.mkdirSync(authPath, { recursive: true });
|
|
286
291
|
fsModule.mkdirSync(worktreePath, { recursive: true });
|
|
287
292
|
const worktreeRemovalTrigger = {
|
|
288
293
|
...trigger,
|
|
289
|
-
id:
|
|
294
|
+
id: 'trigger-remove',
|
|
290
295
|
useWorktree: true,
|
|
291
|
-
worktreeId:
|
|
292
|
-
worktreeStatus:
|
|
296
|
+
worktreeId: 'worktree-1',
|
|
297
|
+
worktreeStatus: 'REMOVE_REQUESTED',
|
|
293
298
|
};
|
|
294
299
|
let keepAliveResolve = null;
|
|
295
300
|
const pollingPromise = startPolling(config, () => async () => undefined, {
|
|
@@ -303,7 +308,7 @@ test("startPolling restores persisted auth paths for worktree removals after res
|
|
|
303
308
|
reportedStatuses.push({ triggerId, status, worktreeError });
|
|
304
309
|
},
|
|
305
310
|
notifyUpdate: async () => undefined,
|
|
306
|
-
ackRestartRequest: async () => undefined
|
|
311
|
+
ackRestartRequest: async () => undefined,
|
|
307
312
|
}),
|
|
308
313
|
runCleanup: async () => undefined,
|
|
309
314
|
removeWorktree: (authPath, worktreePath, worktreeId) => {
|
|
@@ -313,37 +318,40 @@ test("startPolling restores persisted auth paths for worktree removals after res
|
|
|
313
318
|
clearInterval: (() => undefined),
|
|
314
319
|
processOn: (() => undefined),
|
|
315
320
|
processExit: (() => {
|
|
316
|
-
throw new Error(
|
|
321
|
+
throw new Error('should not exit');
|
|
317
322
|
}),
|
|
318
323
|
now: () => 0,
|
|
319
324
|
loadAuthPaths: () => [authPath],
|
|
320
|
-
saveAuthPath: () =>
|
|
325
|
+
saveAuthPath: () => '/tmp/auth-paths.json',
|
|
321
326
|
keepAlive: () => new Promise((resolve) => {
|
|
322
327
|
keepAliveResolve = resolve;
|
|
323
|
-
})
|
|
328
|
+
}),
|
|
324
329
|
});
|
|
325
330
|
await new Promise((resolve) => setImmediate(resolve));
|
|
326
|
-
assert.deepEqual(removedWorktrees, [
|
|
331
|
+
assert.deepEqual(removedWorktrees, [
|
|
332
|
+
{
|
|
327
333
|
authPath,
|
|
328
334
|
worktreePath,
|
|
329
|
-
worktreeId:
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
+
worktreeId: 'worktree-1',
|
|
336
|
+
},
|
|
337
|
+
]);
|
|
338
|
+
assert.deepEqual(reportedStatuses, [{ triggerId: 'trigger-remove', status: 'REMOVED', worktreeError: undefined }]);
|
|
339
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
340
|
+
(() => {
|
|
341
|
+
throw new Error('keepAlive resolver was not registered');
|
|
342
|
+
});
|
|
335
343
|
resolveKeepAlive();
|
|
336
344
|
await pollingPromise;
|
|
337
345
|
fsModule.rmSync(tempRoot, { recursive: true, force: true });
|
|
338
346
|
});
|
|
339
|
-
test(
|
|
347
|
+
test('startPolling reports FAILED when no persisted auth path matches the worktree', async () => {
|
|
340
348
|
const reportedStatuses = [];
|
|
341
349
|
const worktreeRemovalTrigger = {
|
|
342
350
|
...trigger,
|
|
343
|
-
id:
|
|
351
|
+
id: 'trigger-remove-missing',
|
|
344
352
|
useWorktree: true,
|
|
345
|
-
worktreeId:
|
|
346
|
-
worktreeStatus:
|
|
353
|
+
worktreeId: 'worktree-missing',
|
|
354
|
+
worktreeStatus: 'REMOVE_REQUESTED',
|
|
347
355
|
};
|
|
348
356
|
let keepAliveResolve = null;
|
|
349
357
|
const pollingPromise = startPolling(config, () => async () => undefined, {
|
|
@@ -357,50 +365,53 @@ test("startPolling reports FAILED when no persisted auth path matches the worktr
|
|
|
357
365
|
reportedStatuses.push({ triggerId, status, worktreeError });
|
|
358
366
|
},
|
|
359
367
|
notifyUpdate: async () => undefined,
|
|
360
|
-
ackRestartRequest: async () => undefined
|
|
368
|
+
ackRestartRequest: async () => undefined,
|
|
361
369
|
}),
|
|
362
370
|
runCleanup: async () => undefined,
|
|
363
371
|
removeWorktree: () => {
|
|
364
|
-
throw new Error(
|
|
372
|
+
throw new Error('removeWorktree should not be called');
|
|
365
373
|
},
|
|
366
374
|
setInterval: (() => ({ ref() { }, unref() { } })),
|
|
367
375
|
clearInterval: (() => undefined),
|
|
368
376
|
processOn: (() => undefined),
|
|
369
377
|
processExit: (() => {
|
|
370
|
-
throw new Error(
|
|
378
|
+
throw new Error('should not exit');
|
|
371
379
|
}),
|
|
372
380
|
now: () => 0,
|
|
373
|
-
loadAuthPaths: () => [
|
|
374
|
-
saveAuthPath: () =>
|
|
381
|
+
loadAuthPaths: () => ['/persisted/auth/path'],
|
|
382
|
+
saveAuthPath: () => '/tmp/auth-paths.json',
|
|
375
383
|
keepAlive: () => new Promise((resolve) => {
|
|
376
384
|
keepAliveResolve = resolve;
|
|
377
|
-
})
|
|
385
|
+
}),
|
|
378
386
|
});
|
|
379
387
|
await new Promise((resolve) => setImmediate(resolve));
|
|
380
|
-
assert.deepEqual(reportedStatuses, [
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
+
assert.deepEqual(reportedStatuses, [
|
|
389
|
+
{
|
|
390
|
+
triggerId: 'trigger-remove-missing',
|
|
391
|
+
status: 'FAILED',
|
|
392
|
+
worktreeError: 'Failed to remove RunnerBox: worktree path was not found for worktree-missing',
|
|
393
|
+
},
|
|
394
|
+
]);
|
|
395
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
396
|
+
(() => {
|
|
397
|
+
throw new Error('keepAlive resolver was not registered');
|
|
398
|
+
});
|
|
388
399
|
resolveKeepAlive();
|
|
389
400
|
await pollingPromise;
|
|
390
401
|
});
|
|
391
|
-
test(
|
|
402
|
+
test('startPolling reports FAILED when worktree removal throws after matching a path', async () => {
|
|
392
403
|
const reportedStatuses = [];
|
|
393
|
-
const tempRoot = fsModule.mkdtempSync(path.join(os.tmpdir(),
|
|
394
|
-
const authPath = path.join(tempRoot,
|
|
395
|
-
const worktreePath = path.join(tempRoot,
|
|
404
|
+
const tempRoot = fsModule.mkdtempSync(path.join(os.tmpdir(), 'agentrunner-poller-'));
|
|
405
|
+
const authPath = path.join(tempRoot, 'path');
|
|
406
|
+
const worktreePath = path.join(tempRoot, '.path-worktrees', 'wt-worktree-failed');
|
|
396
407
|
fsModule.mkdirSync(authPath, { recursive: true });
|
|
397
408
|
fsModule.mkdirSync(worktreePath, { recursive: true });
|
|
398
409
|
const worktreeRemovalTrigger = {
|
|
399
410
|
...trigger,
|
|
400
|
-
id:
|
|
411
|
+
id: 'trigger-remove-failed',
|
|
401
412
|
useWorktree: true,
|
|
402
|
-
worktreeId:
|
|
403
|
-
worktreeStatus:
|
|
413
|
+
worktreeId: 'worktree-failed',
|
|
414
|
+
worktreeStatus: 'REMOVE_REQUESTED',
|
|
404
415
|
};
|
|
405
416
|
let keepAliveResolve = null;
|
|
406
417
|
const pollingPromise = startPolling(config, () => async () => undefined, {
|
|
@@ -414,45 +425,51 @@ test("startPolling reports FAILED when worktree removal throws after matching a
|
|
|
414
425
|
reportedStatuses.push({ triggerId, status, worktreeError });
|
|
415
426
|
},
|
|
416
427
|
notifyUpdate: async () => undefined,
|
|
417
|
-
ackRestartRequest: async () => undefined
|
|
428
|
+
ackRestartRequest: async () => undefined,
|
|
418
429
|
}),
|
|
419
430
|
runCleanup: async () => undefined,
|
|
420
431
|
removeWorktree: () => {
|
|
421
|
-
throw new Error(
|
|
432
|
+
throw new Error('permission denied');
|
|
422
433
|
},
|
|
423
434
|
setInterval: (() => ({ ref() { }, unref() { } })),
|
|
424
435
|
clearInterval: (() => undefined),
|
|
425
436
|
processOn: (() => undefined),
|
|
426
437
|
processExit: (() => {
|
|
427
|
-
throw new Error(
|
|
438
|
+
throw new Error('should not exit');
|
|
428
439
|
}),
|
|
429
440
|
now: () => 0,
|
|
430
441
|
loadAuthPaths: () => [authPath],
|
|
431
|
-
saveAuthPath: () =>
|
|
442
|
+
saveAuthPath: () => '/tmp/auth-paths.json',
|
|
432
443
|
keepAlive: () => new Promise((resolve) => {
|
|
433
444
|
keepAliveResolve = resolve;
|
|
434
|
-
})
|
|
445
|
+
}),
|
|
435
446
|
});
|
|
436
447
|
await new Promise((resolve) => setImmediate(resolve));
|
|
437
|
-
assert.deepEqual(reportedStatuses, [
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
448
|
+
assert.deepEqual(reportedStatuses, [
|
|
449
|
+
{
|
|
450
|
+
triggerId: 'trigger-remove-failed',
|
|
451
|
+
status: 'FAILED',
|
|
452
|
+
worktreeError: 'permission denied',
|
|
453
|
+
},
|
|
454
|
+
]);
|
|
455
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
456
|
+
(() => {
|
|
457
|
+
throw new Error('keepAlive resolver was not registered');
|
|
458
|
+
});
|
|
445
459
|
resolveKeepAlive();
|
|
446
460
|
await pollingPromise;
|
|
447
461
|
fsModule.rmSync(tempRoot, { recursive: true, force: true });
|
|
448
462
|
});
|
|
449
|
-
test(
|
|
463
|
+
test('startPolling acks and runs restart when meta.restartRequested is true with no pending trigger', async () => {
|
|
450
464
|
let ackCalled = 0;
|
|
451
465
|
let restartCalled = 0;
|
|
452
466
|
let keepAliveResolve = null;
|
|
453
467
|
const pollingPromise = startPolling(config, () => async () => undefined, {
|
|
454
468
|
createClient: () => ({
|
|
455
|
-
fetchPendingTrigger: async () => ({
|
|
469
|
+
fetchPendingTrigger: async () => ({
|
|
470
|
+
data: null,
|
|
471
|
+
meta: { cliLatestVersion: null, runnerLatestVersion: null, restartRequested: true },
|
|
472
|
+
}),
|
|
456
473
|
claimTrigger: async () => ({ ok: true, conflict: false }),
|
|
457
474
|
fetchOrphanedCancelRequested: async () => [],
|
|
458
475
|
updateTriggerStatus: async () => undefined,
|
|
@@ -461,11 +478,11 @@ test("startPolling acks and runs restart when meta.restartRequested is true with
|
|
|
461
478
|
notifyUpdate: async () => undefined,
|
|
462
479
|
ackRestartRequest: async () => {
|
|
463
480
|
ackCalled += 1;
|
|
464
|
-
}
|
|
481
|
+
},
|
|
465
482
|
}),
|
|
466
483
|
runCleanup: async () => undefined,
|
|
467
484
|
maybeAutoUpdate: async () => {
|
|
468
|
-
throw new Error(
|
|
485
|
+
throw new Error('auto-update must be skipped while restarting');
|
|
469
486
|
},
|
|
470
487
|
executeRestartRequest: () => {
|
|
471
488
|
restartCalled += 1;
|
|
@@ -476,30 +493,34 @@ test("startPolling acks and runs restart when meta.restartRequested is true with
|
|
|
476
493
|
processExit: (() => undefined),
|
|
477
494
|
now: () => 0,
|
|
478
495
|
loadAuthPaths: () => [],
|
|
479
|
-
saveAuthPath: () =>
|
|
496
|
+
saveAuthPath: () => '/tmp/auth-paths.json',
|
|
480
497
|
keepAlive: () => new Promise((resolve) => {
|
|
481
498
|
keepAliveResolve = resolve;
|
|
482
|
-
})
|
|
499
|
+
}),
|
|
483
500
|
});
|
|
484
501
|
await new Promise((resolve) => setImmediate(resolve));
|
|
485
|
-
assert.equal(ackCalled, 1,
|
|
486
|
-
assert.equal(restartCalled, 1,
|
|
487
|
-
const resolveKeepAlive = keepAliveResolve ??
|
|
488
|
-
|
|
489
|
-
|
|
502
|
+
assert.equal(ackCalled, 1, 'ackRestartRequest should be called exactly once');
|
|
503
|
+
assert.equal(restartCalled, 1, 'executeRestartRequest should be called exactly once');
|
|
504
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
505
|
+
(() => {
|
|
506
|
+
throw new Error('keepAlive resolver was not registered');
|
|
507
|
+
});
|
|
490
508
|
resolveKeepAlive();
|
|
491
509
|
await pollingPromise;
|
|
492
510
|
});
|
|
493
|
-
test(
|
|
511
|
+
test('startPolling restarts even when a pending trigger is present, ignoring the trigger', async () => {
|
|
494
512
|
let ackCalled = 0;
|
|
495
513
|
let restartCalled = 0;
|
|
496
514
|
let claimCalled = 0;
|
|
497
515
|
let keepAliveResolve = null;
|
|
498
516
|
const pollingPromise = startPolling(config, () => async () => {
|
|
499
|
-
throw new Error(
|
|
517
|
+
throw new Error('trigger handler must not run when restart wins');
|
|
500
518
|
}, {
|
|
501
519
|
createClient: () => ({
|
|
502
|
-
fetchPendingTrigger: async () => ({
|
|
520
|
+
fetchPendingTrigger: async () => ({
|
|
521
|
+
data: trigger,
|
|
522
|
+
meta: { cliLatestVersion: null, runnerLatestVersion: null, restartRequested: true },
|
|
523
|
+
}),
|
|
503
524
|
claimTrigger: async () => {
|
|
504
525
|
claimCalled += 1;
|
|
505
526
|
return { ok: true, conflict: false };
|
|
@@ -511,7 +532,7 @@ test("startPolling restarts even when a pending trigger is present, ignoring the
|
|
|
511
532
|
notifyUpdate: async () => undefined,
|
|
512
533
|
ackRestartRequest: async () => {
|
|
513
534
|
ackCalled += 1;
|
|
514
|
-
}
|
|
535
|
+
},
|
|
515
536
|
}),
|
|
516
537
|
runCleanup: async () => undefined,
|
|
517
538
|
executeRestartRequest: () => {
|
|
@@ -523,27 +544,31 @@ test("startPolling restarts even when a pending trigger is present, ignoring the
|
|
|
523
544
|
processExit: (() => undefined),
|
|
524
545
|
now: () => 0,
|
|
525
546
|
loadAuthPaths: () => [],
|
|
526
|
-
saveAuthPath: () =>
|
|
547
|
+
saveAuthPath: () => '/tmp/auth-paths.json',
|
|
527
548
|
keepAlive: () => new Promise((resolve) => {
|
|
528
549
|
keepAliveResolve = resolve;
|
|
529
|
-
})
|
|
550
|
+
}),
|
|
530
551
|
});
|
|
531
552
|
await new Promise((resolve) => setImmediate(resolve));
|
|
532
|
-
assert.equal(ackCalled, 1,
|
|
533
|
-
assert.equal(restartCalled, 1,
|
|
534
|
-
assert.equal(claimCalled, 0,
|
|
535
|
-
const resolveKeepAlive = keepAliveResolve ??
|
|
536
|
-
|
|
537
|
-
|
|
553
|
+
assert.equal(ackCalled, 1, 'ack should run before restart');
|
|
554
|
+
assert.equal(restartCalled, 1, 'restart should run even with a pending trigger');
|
|
555
|
+
assert.equal(claimCalled, 0, 'trigger must not be claimed while restarting');
|
|
556
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
557
|
+
(() => {
|
|
558
|
+
throw new Error('keepAlive resolver was not registered');
|
|
559
|
+
});
|
|
538
560
|
resolveKeepAlive();
|
|
539
561
|
await pollingPromise;
|
|
540
562
|
});
|
|
541
|
-
test(
|
|
563
|
+
test('startPolling skips restart and leaves the flag for retry when ack fails', async () => {
|
|
542
564
|
let restartCalled = 0;
|
|
543
565
|
let keepAliveResolve = null;
|
|
544
566
|
const pollingPromise = startPolling(config, () => async () => undefined, {
|
|
545
567
|
createClient: () => ({
|
|
546
|
-
fetchPendingTrigger: async () => ({
|
|
568
|
+
fetchPendingTrigger: async () => ({
|
|
569
|
+
data: null,
|
|
570
|
+
meta: { cliLatestVersion: null, runnerLatestVersion: null, restartRequested: true },
|
|
571
|
+
}),
|
|
547
572
|
claimTrigger: async () => ({ ok: true, conflict: false }),
|
|
548
573
|
fetchOrphanedCancelRequested: async () => [],
|
|
549
574
|
updateTriggerStatus: async () => undefined,
|
|
@@ -551,8 +576,8 @@ test("startPolling skips restart and leaves the flag for retry when ack fails",
|
|
|
551
576
|
reportWorktreeStatus: async () => undefined,
|
|
552
577
|
notifyUpdate: async () => undefined,
|
|
553
578
|
ackRestartRequest: async () => {
|
|
554
|
-
throw new Error(
|
|
555
|
-
}
|
|
579
|
+
throw new Error('network down');
|
|
580
|
+
},
|
|
556
581
|
}),
|
|
557
582
|
runCleanup: async () => undefined,
|
|
558
583
|
executeRestartRequest: () => {
|
|
@@ -564,20 +589,21 @@ test("startPolling skips restart and leaves the flag for retry when ack fails",
|
|
|
564
589
|
processExit: (() => undefined),
|
|
565
590
|
now: () => 0,
|
|
566
591
|
loadAuthPaths: () => [],
|
|
567
|
-
saveAuthPath: () =>
|
|
592
|
+
saveAuthPath: () => '/tmp/auth-paths.json',
|
|
568
593
|
keepAlive: () => new Promise((resolve) => {
|
|
569
594
|
keepAliveResolve = resolve;
|
|
570
|
-
})
|
|
595
|
+
}),
|
|
571
596
|
});
|
|
572
597
|
await new Promise((resolve) => setImmediate(resolve));
|
|
573
|
-
assert.equal(restartCalled, 0,
|
|
574
|
-
const resolveKeepAlive = keepAliveResolve ??
|
|
575
|
-
|
|
576
|
-
|
|
598
|
+
assert.equal(restartCalled, 0, 'restart must not run when ack fails');
|
|
599
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
600
|
+
(() => {
|
|
601
|
+
throw new Error('keepAlive resolver was not registered');
|
|
602
|
+
});
|
|
577
603
|
resolveKeepAlive();
|
|
578
604
|
await pollingPromise;
|
|
579
605
|
});
|
|
580
|
-
test(
|
|
606
|
+
test('startPolling acquires the power save blocker on start and releases it on shutdown', async () => {
|
|
581
607
|
const { events, blocker } = createRecordingBlocker();
|
|
582
608
|
const signals = new Map();
|
|
583
609
|
let keepAliveResolve = null;
|
|
@@ -590,7 +616,7 @@ test("startPolling acquires the power save blocker on start and releases it on s
|
|
|
590
616
|
fetchPendingWorktreeRemovals: async () => [],
|
|
591
617
|
reportWorktreeStatus: async () => undefined,
|
|
592
618
|
notifyUpdate: async () => undefined,
|
|
593
|
-
ackRestartRequest: async () => undefined
|
|
619
|
+
ackRestartRequest: async () => undefined,
|
|
594
620
|
}),
|
|
595
621
|
runCleanup: async () => undefined,
|
|
596
622
|
setInterval: (() => ({})),
|
|
@@ -601,25 +627,26 @@ test("startPolling acquires the power save blocker on start and releases it on s
|
|
|
601
627
|
processExit: (() => undefined),
|
|
602
628
|
now: () => 0,
|
|
603
629
|
loadAuthPaths: () => [],
|
|
604
|
-
saveAuthPath: () =>
|
|
630
|
+
saveAuthPath: () => '/tmp/auth-paths.json',
|
|
605
631
|
powerSaveBlocker: blocker,
|
|
606
632
|
keepAlive: () => new Promise((resolve) => {
|
|
607
633
|
keepAliveResolve = resolve;
|
|
608
|
-
})
|
|
634
|
+
}),
|
|
609
635
|
});
|
|
610
636
|
await new Promise((resolve) => setImmediate(resolve));
|
|
611
|
-
assert.deepEqual(events, [
|
|
612
|
-
const sigterm = signals.get(
|
|
637
|
+
assert.deepEqual(events, ['acquire:daemon-polling'], 'blocker should be acquired exactly once on start');
|
|
638
|
+
const sigterm = signals.get('SIGTERM');
|
|
613
639
|
assert.ok(sigterm);
|
|
614
640
|
sigterm();
|
|
615
|
-
assert.deepEqual(events, [
|
|
616
|
-
const resolveKeepAlive = keepAliveResolve ??
|
|
617
|
-
|
|
618
|
-
|
|
641
|
+
assert.deepEqual(events, ['acquire:daemon-polling', 'release:daemon-polling'], 'blocker should be released on shutdown');
|
|
642
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
643
|
+
(() => {
|
|
644
|
+
throw new Error('keepAlive resolver was not registered');
|
|
645
|
+
});
|
|
619
646
|
resolveKeepAlive();
|
|
620
647
|
await pollingPromise;
|
|
621
648
|
});
|
|
622
|
-
test(
|
|
649
|
+
test('startPolling releases the power save blocker when keepAlive resolves', async () => {
|
|
623
650
|
const { events, blocker } = createRecordingBlocker();
|
|
624
651
|
let keepAliveResolve = null;
|
|
625
652
|
const pollingPromise = startPolling(config, () => async () => undefined, {
|
|
@@ -631,7 +658,7 @@ test("startPolling releases the power save blocker when keepAlive resolves", asy
|
|
|
631
658
|
fetchPendingWorktreeRemovals: async () => [],
|
|
632
659
|
reportWorktreeStatus: async () => undefined,
|
|
633
660
|
notifyUpdate: async () => undefined,
|
|
634
|
-
ackRestartRequest: async () => undefined
|
|
661
|
+
ackRestartRequest: async () => undefined,
|
|
635
662
|
}),
|
|
636
663
|
runCleanup: async () => undefined,
|
|
637
664
|
setInterval: (() => ({})),
|
|
@@ -640,19 +667,20 @@ test("startPolling releases the power save blocker when keepAlive resolves", asy
|
|
|
640
667
|
processExit: (() => undefined),
|
|
641
668
|
now: () => 0,
|
|
642
669
|
loadAuthPaths: () => [],
|
|
643
|
-
saveAuthPath: () =>
|
|
670
|
+
saveAuthPath: () => '/tmp/auth-paths.json',
|
|
644
671
|
powerSaveBlocker: blocker,
|
|
645
672
|
keepAlive: () => new Promise((resolve) => {
|
|
646
673
|
keepAliveResolve = resolve;
|
|
647
|
-
})
|
|
674
|
+
}),
|
|
648
675
|
});
|
|
649
676
|
await new Promise((resolve) => setImmediate(resolve));
|
|
650
|
-
assert.deepEqual(events, [
|
|
651
|
-
const resolveKeepAlive = keepAliveResolve ??
|
|
652
|
-
|
|
653
|
-
|
|
677
|
+
assert.deepEqual(events, ['acquire:daemon-polling']);
|
|
678
|
+
const resolveKeepAlive = keepAliveResolve ??
|
|
679
|
+
(() => {
|
|
680
|
+
throw new Error('keepAlive resolver was not registered');
|
|
681
|
+
});
|
|
654
682
|
resolveKeepAlive();
|
|
655
683
|
await pollingPromise;
|
|
656
|
-
assert.deepEqual(events, [
|
|
684
|
+
assert.deepEqual(events, ['acquire:daemon-polling', 'release:daemon-polling'], 'blocker should be released after keepAlive resolves');
|
|
657
685
|
});
|
|
658
686
|
//# sourceMappingURL=poller.test.js.map
|