@agentteams/runner 0.0.106 → 0.0.108
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/autostart.d.ts +28 -1
- package/dist/autostart.js +206 -22
- package/dist/autostart.js.map +1 -1
- package/dist/autostart.test.js +262 -6
- package/dist/autostart.test.js.map +1 -1
- package/dist/commands/start.d.ts +19 -1
- package/dist/commands/start.js +16 -12
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/start.test.d.ts +1 -0
- package/dist/commands/start.test.js +43 -0
- package/dist/commands/start.test.js.map +1 -0
- package/dist/commands/status.d.ts +13 -1
- package/dist/commands/status.js +15 -8
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/status.test.d.ts +1 -0
- package/dist/commands/status.test.js +64 -0
- package/dist/commands/status.test.js.map +1 -0
- package/dist/daemon-control.d.ts +2 -1
- package/dist/daemon-control.js +33 -5
- package/dist/daemon-control.js.map +1 -1
- package/dist/daemon-control.test.js +88 -0
- package/dist/daemon-control.test.js.map +1 -1
- package/dist/utils/convention-evaluator.d.ts +7 -0
- package/dist/utils/convention-evaluator.js +6 -3
- package/dist/utils/convention-evaluator.js.map +1 -1
- package/dist/utils/convention-evaluator.test.js +13 -0
- package/dist/utils/convention-evaluator.test.js.map +1 -1
- package/dist/windows-launcher.d.ts +27 -0
- package/dist/windows-launcher.js +114 -0
- package/dist/windows-launcher.js.map +1 -0
- package/dist/windows-launcher.test.d.ts +1 -0
- package/dist/windows-launcher.test.js +150 -0
- package/dist/windows-launcher.test.js.map +1 -0
- package/native/bin/win32-x64/agentrunner-launcher.exe +0 -0
- package/native/bin/win32-x64/manifest.json +8 -0
- package/package.json +6 -2
- package/readme.md +21 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import { homedir, platform, arch, release } from 'node:os';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
// Matches both installed launchers and the `<target>.<pid>.tmp` staging files an
|
|
7
|
+
// interrupted install can leave behind.
|
|
8
|
+
const INSTALLED_LAUNCHER_PATTERN = /^agentrunner-launcher-.+\.exe(\.\d+\.tmp)?$/u;
|
|
9
|
+
// `keepFileName` is the launcher the caller just verified; every other copy is a
|
|
10
|
+
// superseded version. Uninstall passes nothing so the directory is emptied.
|
|
11
|
+
export const cleanupInstalledWindowsLaunchers = async (deps = {}) => {
|
|
12
|
+
const installDir = join(deps.homeDir ?? homedir(), '.agentteams', 'bin');
|
|
13
|
+
let entries;
|
|
14
|
+
try {
|
|
15
|
+
entries = await (deps.readdir ?? fs.readdir)(installDir);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
await Promise.all(entries
|
|
21
|
+
.filter((entry) => INSTALLED_LAUNCHER_PATTERN.test(entry) && entry !== deps.keepFileName)
|
|
22
|
+
.map(async (entry) => {
|
|
23
|
+
try {
|
|
24
|
+
await (deps.unlink ?? fs.unlink)(join(installDir, entry));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// A launcher still referenced by a live process remains for the next cleanup.
|
|
28
|
+
}
|
|
29
|
+
}));
|
|
30
|
+
};
|
|
31
|
+
const sha256 = (value) => createHash('sha256').update(value).digest('hex');
|
|
32
|
+
const assertSupportedWindows = (os, cpu, osRelease) => {
|
|
33
|
+
if (os !== 'win32') {
|
|
34
|
+
throw new Error('The native AgentRunner launcher can only be installed on Windows.');
|
|
35
|
+
}
|
|
36
|
+
if (cpu === 'x64') {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const windowsBuild = Number.parseInt(osRelease.split('.')[2] ?? '0', 10);
|
|
40
|
+
if (cpu === 'arm64' && windowsBuild >= 22_000) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
throw new Error(`Unsupported Windows architecture '${cpu}' (${osRelease}). ` +
|
|
44
|
+
'Use Windows x64 or Windows 11 ARM64 with x64 emulation.');
|
|
45
|
+
};
|
|
46
|
+
const parseManifest = (raw, packageVersion) => {
|
|
47
|
+
const value = JSON.parse(raw);
|
|
48
|
+
if (value.schemaVersion !== 1 ||
|
|
49
|
+
value.platform !== 'win32' ||
|
|
50
|
+
value.arch !== 'x64' ||
|
|
51
|
+
value.fileName !== 'agentrunner-launcher.exe' ||
|
|
52
|
+
value.version !== packageVersion ||
|
|
53
|
+
!/^[a-f0-9]{64}$/u.test(value.sha256 ?? '')) {
|
|
54
|
+
throw new Error('The packaged Windows launcher manifest is invalid or does not match the Runner version.');
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
};
|
|
58
|
+
export const installWindowsLauncher = async (deps = {}) => {
|
|
59
|
+
assertSupportedWindows(deps.platform ?? platform(), deps.arch ?? arch(), deps.release ?? release());
|
|
60
|
+
const readFile = deps.readFile ?? fs.readFile;
|
|
61
|
+
const packageRoot = deps.packageRoot ?? dirname(dirname(fileURLToPath(import.meta.url)));
|
|
62
|
+
const nativeDir = join(packageRoot, 'native', 'bin', 'win32-x64');
|
|
63
|
+
const packageJson = JSON.parse(await readFile(join(packageRoot, 'package.json'), 'utf8'));
|
|
64
|
+
if (!packageJson.version) {
|
|
65
|
+
throw new Error('Cannot determine the installed AgentRunner package version.');
|
|
66
|
+
}
|
|
67
|
+
const manifest = parseManifest(await readFile(join(nativeDir, 'manifest.json'), 'utf8'), packageJson.version);
|
|
68
|
+
const sourcePath = join(nativeDir, manifest.fileName);
|
|
69
|
+
const sourceBytes = await readFile(sourcePath);
|
|
70
|
+
if (sha256(sourceBytes) !== manifest.sha256) {
|
|
71
|
+
throw new Error('The packaged Windows launcher failed SHA-256 verification. Reinstall @agentteams/runner.');
|
|
72
|
+
}
|
|
73
|
+
const installDir = join(deps.homeDir ?? homedir(), '.agentteams', 'bin');
|
|
74
|
+
const targetFileName = `agentrunner-launcher-${manifest.version}-${manifest.sha256.slice(0, 12)}.exe`;
|
|
75
|
+
const targetPath = join(installDir, targetFileName);
|
|
76
|
+
// Every upgrade installs under a new content-addressed name, so prune the
|
|
77
|
+
// superseded copies here — uninstall is far too late to be the only sweep.
|
|
78
|
+
const pruneSupersededLaunchers = async () => {
|
|
79
|
+
await cleanupInstalledWindowsLaunchers({ ...deps, keepFileName: targetFileName });
|
|
80
|
+
};
|
|
81
|
+
await (deps.mkdir ?? fs.mkdir)(installDir, { recursive: true });
|
|
82
|
+
try {
|
|
83
|
+
const existingBytes = await readFile(targetPath);
|
|
84
|
+
if (sha256(existingBytes) === manifest.sha256) {
|
|
85
|
+
await pruneSupersededLaunchers();
|
|
86
|
+
return targetPath;
|
|
87
|
+
}
|
|
88
|
+
throw new Error(`Existing immutable launcher has unexpected contents: ${targetPath}`);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
if (error.code !== 'ENOENT') {
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const temporaryPath = `${targetPath}.${process.pid}.tmp`;
|
|
96
|
+
await (deps.copyFile ?? fs.copyFile)(sourcePath, temporaryPath);
|
|
97
|
+
const copiedBytes = await readFile(temporaryPath);
|
|
98
|
+
if (sha256(copiedBytes) !== manifest.sha256) {
|
|
99
|
+
await (deps.unlink ?? fs.unlink)(temporaryPath).catch(() => undefined);
|
|
100
|
+
throw new Error('The installed Windows launcher failed SHA-256 verification.');
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
await (deps.rename ?? fs.rename)(temporaryPath, targetPath);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
await (deps.unlink ?? fs.unlink)(temporaryPath).catch(() => undefined);
|
|
107
|
+
if (error.code !== 'EEXIST') {
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
await pruneSupersededLaunchers();
|
|
112
|
+
return targetPath;
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=windows-launcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows-launcher.js","sourceRoot":"","sources":["../src/windows-launcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import test from 'node:test';
|
|
5
|
+
import { cleanupInstalledWindowsLaunchers, installWindowsLauncher } from './windows-launcher.js';
|
|
6
|
+
const hash = (value) => createHash('sha256').update(value).digest('hex');
|
|
7
|
+
test('installWindowsLauncher validates and installs a content-addressed immutable launcher', async () => {
|
|
8
|
+
const binary = Buffer.from('native launcher');
|
|
9
|
+
const packageRoot = join('test-root', 'pkg');
|
|
10
|
+
const files = new Map();
|
|
11
|
+
files.set(join(packageRoot, 'package.json'), Buffer.from(JSON.stringify({ version: '1.2.3' })));
|
|
12
|
+
files.set(join(packageRoot, 'native', 'bin', 'win32-x64', 'manifest.json'), Buffer.from(JSON.stringify({
|
|
13
|
+
schemaVersion: 1,
|
|
14
|
+
version: '1.2.3',
|
|
15
|
+
platform: 'win32',
|
|
16
|
+
arch: 'x64',
|
|
17
|
+
fileName: 'agentrunner-launcher.exe',
|
|
18
|
+
sha256: hash(binary),
|
|
19
|
+
})));
|
|
20
|
+
files.set(join(packageRoot, 'native', 'bin', 'win32-x64', 'agentrunner-launcher.exe'), binary);
|
|
21
|
+
const copied = [];
|
|
22
|
+
const result = await installWindowsLauncher({
|
|
23
|
+
packageRoot,
|
|
24
|
+
homeDir: join('test-root', 'home'),
|
|
25
|
+
platform: 'win32',
|
|
26
|
+
arch: 'x64',
|
|
27
|
+
release: '10.0.26100',
|
|
28
|
+
readFile: (async (path) => {
|
|
29
|
+
const value = files.get(path);
|
|
30
|
+
if (!value) {
|
|
31
|
+
const error = new Error('missing');
|
|
32
|
+
error.code = 'ENOENT';
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}),
|
|
37
|
+
mkdir: async () => undefined,
|
|
38
|
+
copyFile: async (source, destination) => {
|
|
39
|
+
copied.push(String(destination));
|
|
40
|
+
files.set(String(destination), files.get(String(source)));
|
|
41
|
+
},
|
|
42
|
+
rename: async (source, destination) => {
|
|
43
|
+
files.set(String(destination), files.get(String(source)));
|
|
44
|
+
files.delete(String(source));
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
assert.match(result, /agentrunner-launcher-1\.2\.3-[a-f0-9]{12}\.exe$/u);
|
|
48
|
+
assert.equal(copied.length, 1);
|
|
49
|
+
});
|
|
50
|
+
test('installWindowsLauncher prunes superseded launchers and interrupted temp files', async () => {
|
|
51
|
+
const binary = Buffer.from('native launcher');
|
|
52
|
+
const packageRoot = join('test-root', 'pkg');
|
|
53
|
+
const homeDir = join('test-root', 'home');
|
|
54
|
+
const installDir = join(homeDir, '.agentteams', 'bin');
|
|
55
|
+
const digest = hash(binary);
|
|
56
|
+
const targetFileName = `agentrunner-launcher-1.2.3-${digest.slice(0, 12)}.exe`;
|
|
57
|
+
const files = new Map();
|
|
58
|
+
files.set(join(packageRoot, 'package.json'), Buffer.from(JSON.stringify({ version: '1.2.3' })));
|
|
59
|
+
files.set(join(packageRoot, 'native', 'bin', 'win32-x64', 'manifest.json'), Buffer.from(JSON.stringify({
|
|
60
|
+
schemaVersion: 1,
|
|
61
|
+
version: '1.2.3',
|
|
62
|
+
platform: 'win32',
|
|
63
|
+
arch: 'x64',
|
|
64
|
+
fileName: 'agentrunner-launcher.exe',
|
|
65
|
+
sha256: digest,
|
|
66
|
+
})));
|
|
67
|
+
files.set(join(packageRoot, 'native', 'bin', 'win32-x64', 'agentrunner-launcher.exe'), binary);
|
|
68
|
+
// The target already exists and verifies, so this exercises the early return —
|
|
69
|
+
// the path an unchanged runner takes on every single restart.
|
|
70
|
+
files.set(join(installDir, targetFileName), binary);
|
|
71
|
+
const unlinked = [];
|
|
72
|
+
const result = await installWindowsLauncher({
|
|
73
|
+
packageRoot,
|
|
74
|
+
homeDir,
|
|
75
|
+
platform: 'win32',
|
|
76
|
+
arch: 'x64',
|
|
77
|
+
release: '10.0.26100',
|
|
78
|
+
readFile: (async (path) => {
|
|
79
|
+
const value = files.get(path);
|
|
80
|
+
if (!value) {
|
|
81
|
+
const error = new Error('missing');
|
|
82
|
+
error.code = 'ENOENT';
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
return value;
|
|
86
|
+
}),
|
|
87
|
+
mkdir: async () => undefined,
|
|
88
|
+
readdir: (async () => [
|
|
89
|
+
targetFileName,
|
|
90
|
+
'agentrunner-launcher-1.2.2-0123456789ab.exe',
|
|
91
|
+
`${targetFileName}.4242.tmp`,
|
|
92
|
+
'daemon.json',
|
|
93
|
+
]),
|
|
94
|
+
unlink: (async (path) => {
|
|
95
|
+
unlinked.push(String(path));
|
|
96
|
+
}),
|
|
97
|
+
});
|
|
98
|
+
assert.equal(result, join(installDir, targetFileName));
|
|
99
|
+
assert.deepEqual(unlinked.sort(), [
|
|
100
|
+
join(installDir, `${targetFileName}.4242.tmp`),
|
|
101
|
+
join(installDir, 'agentrunner-launcher-1.2.2-0123456789ab.exe'),
|
|
102
|
+
].sort());
|
|
103
|
+
});
|
|
104
|
+
test('cleanupInstalledWindowsLaunchers removes every launcher and temp file but leaves unrelated files', async () => {
|
|
105
|
+
const homeDir = join('test-root', 'home');
|
|
106
|
+
const installDir = join(homeDir, '.agentteams', 'bin');
|
|
107
|
+
const unlinked = [];
|
|
108
|
+
await cleanupInstalledWindowsLaunchers({
|
|
109
|
+
homeDir,
|
|
110
|
+
readdir: (async () => [
|
|
111
|
+
'agentrunner-launcher-1.2.3-0123456789ab.exe',
|
|
112
|
+
'agentrunner-launcher-1.2.3-0123456789ab.exe.777.tmp',
|
|
113
|
+
'daemon.json',
|
|
114
|
+
'agentrunner.log',
|
|
115
|
+
]),
|
|
116
|
+
unlink: (async (path) => {
|
|
117
|
+
unlinked.push(String(path));
|
|
118
|
+
}),
|
|
119
|
+
});
|
|
120
|
+
assert.deepEqual(unlinked.sort(), [
|
|
121
|
+
join(installDir, 'agentrunner-launcher-1.2.3-0123456789ab.exe'),
|
|
122
|
+
join(installDir, 'agentrunner-launcher-1.2.3-0123456789ab.exe.777.tmp'),
|
|
123
|
+
]);
|
|
124
|
+
});
|
|
125
|
+
test('installWindowsLauncher fails closed on hash mismatch and unsupported architecture', async () => {
|
|
126
|
+
const readFile = (async (path) => {
|
|
127
|
+
if (path.endsWith('package.json'))
|
|
128
|
+
return Buffer.from(JSON.stringify({ version: '1.2.3' }));
|
|
129
|
+
if (path.endsWith('manifest.json')) {
|
|
130
|
+
return Buffer.from(JSON.stringify({
|
|
131
|
+
schemaVersion: 1,
|
|
132
|
+
version: '1.2.3',
|
|
133
|
+
platform: 'win32',
|
|
134
|
+
arch: 'x64',
|
|
135
|
+
fileName: 'agentrunner-launcher.exe',
|
|
136
|
+
sha256: '0'.repeat(64),
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
return Buffer.from('tampered');
|
|
140
|
+
});
|
|
141
|
+
await assert.rejects(installWindowsLauncher({ packageRoot: 'C:\\pkg', platform: 'win32', arch: 'x64', readFile }), /SHA-256/u);
|
|
142
|
+
await assert.rejects(installWindowsLauncher({
|
|
143
|
+
packageRoot: 'C:\\pkg',
|
|
144
|
+
platform: 'win32',
|
|
145
|
+
arch: 'arm64',
|
|
146
|
+
release: '10.0.19045',
|
|
147
|
+
readFile,
|
|
148
|
+
}), /Unsupported Windows architecture/u);
|
|
149
|
+
});
|
|
150
|
+
//# sourceMappingURL=windows-launcher.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows-launcher.test.js","sourceRoot":"","sources":["../src/windows-launcher.test.ts"],"names":[],"mappings":"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"}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentteams/runner",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.108",
|
|
4
4
|
"description": "AgentRunner - Background runner that polls and executes AI agent tasks",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,10 +9,13 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist/**/*",
|
|
12
|
+
"native/bin/**/*",
|
|
12
13
|
"readme.md"
|
|
13
14
|
],
|
|
14
15
|
"scripts": {
|
|
15
16
|
"build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc",
|
|
17
|
+
"build:native:win": "powershell -NoProfile -ExecutionPolicy Bypass -File native/win/build.ps1",
|
|
18
|
+
"test:native:win": "powershell -NoProfile -ExecutionPolicy Bypass -File native/win/smoke.ps1",
|
|
16
19
|
"typecheck": "tsc --noEmit",
|
|
17
20
|
"dev": "tsx watch src/index.ts",
|
|
18
21
|
"test": "tsx --test \"src/**/*.test.ts\"",
|
|
@@ -22,7 +25,8 @@
|
|
|
22
25
|
"format:check": "prettier --check .",
|
|
23
26
|
"start": "node dist/index.js",
|
|
24
27
|
"init": "node dist/index.js init",
|
|
25
|
-
"
|
|
28
|
+
"verify:native:win": "node native/win/verify-package.mjs .",
|
|
29
|
+
"prepublishOnly": "pnpm run build && pnpm run verify:native:win"
|
|
26
30
|
},
|
|
27
31
|
"publishConfig": {
|
|
28
32
|
"access": "public"
|
package/readme.md
CHANGED
|
@@ -176,6 +176,26 @@ If a process is already running for the same `agentConfigId`, new triggers are `
|
|
|
176
176
|
|
|
177
177
|
### Windows recovery checks
|
|
178
178
|
|
|
179
|
+
Windows Task Scheduler uses a signed or explicitly unsigned native GUI launcher
|
|
180
|
+
instead of starting `powershell.exe` directly. The launcher is integrity-checked
|
|
181
|
+
and installed under
|
|
182
|
+
`%USERPROFILE%\.agentteams\bin\agentrunner-launcher-<version>-<sha12>.exe`.
|
|
183
|
+
Legacy tasks migrate during restart — both `agentrunner restart` and a restart
|
|
184
|
+
requested from the web UI (the path `agentrunner update` takes) re-register the
|
|
185
|
+
task whenever the live definition still points at a console-bound action. The
|
|
186
|
+
runner also checks the definition during startup and repairs it without
|
|
187
|
+
restarting the current process. That startup repair takes effect the next time
|
|
188
|
+
the runner starts. Use `agentrunner status` to see whether a legacy action is
|
|
189
|
+
still pending, or run `agentrunner restart` to migrate and apply the native
|
|
190
|
+
launcher immediately. The migration never deletes the previous registration
|
|
191
|
+
first; a failed migration restores the prior task XML from an exported backup.
|
|
192
|
+
|
|
193
|
+
Windows x64 and Windows 11 ARM64 (through x64 emulation) are supported. Windows
|
|
194
|
+
10 ARM64 is not supported and fails closed instead of falling back to a visible
|
|
195
|
+
PowerShell process. Because the scheduled task points at the content-addressed
|
|
196
|
+
user copy, a running Runner does not lock the executable inside the npm package
|
|
197
|
+
during a global update.
|
|
198
|
+
|
|
179
199
|
The `AgentRunner` scheduled task ignores duplicate starts and retries failed exits up to three times at one-minute intervals. Inspect it and follow the append-only daemon log with:
|
|
180
200
|
|
|
181
201
|
```powershell
|
|
@@ -185,7 +205,7 @@ Get-Content "$env:USERPROFILE\.agentteams\agentrunner.log" -Wait
|
|
|
185
205
|
|
|
186
206
|
For a release smoke test on a disposable Windows test machine:
|
|
187
207
|
|
|
188
|
-
1. Run `agentrunner restart` and verify the
|
|
208
|
+
1. Run `agentrunner restart`, query `schtasks /Query /TN "AgentRunner" /XML`, and verify the action points at `agentrunner-launcher-*.exe`, the task gets one new runner PID, and no console window appears.
|
|
189
209
|
2. End the runner process unexpectedly and verify Task Scheduler starts it again after the configured delay.
|
|
190
210
|
3. Disconnect and reconnect the network, or suspend and resume Windows. API requests that remain stalled are aborted after 30 seconds and retried; verify a later poll attempt or successful poll appears in the log.
|
|
191
211
|
4. Run `agentrunner status`, then `agentrunner stop`. Verify the current task instance stops and does not immediately respawn.
|