@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.
Files changed (37) hide show
  1. package/dist/autostart.d.ts +28 -1
  2. package/dist/autostart.js +206 -22
  3. package/dist/autostart.js.map +1 -1
  4. package/dist/autostart.test.js +262 -6
  5. package/dist/autostart.test.js.map +1 -1
  6. package/dist/commands/start.d.ts +19 -1
  7. package/dist/commands/start.js +16 -12
  8. package/dist/commands/start.js.map +1 -1
  9. package/dist/commands/start.test.d.ts +1 -0
  10. package/dist/commands/start.test.js +43 -0
  11. package/dist/commands/start.test.js.map +1 -0
  12. package/dist/commands/status.d.ts +13 -1
  13. package/dist/commands/status.js +15 -8
  14. package/dist/commands/status.js.map +1 -1
  15. package/dist/commands/status.test.d.ts +1 -0
  16. package/dist/commands/status.test.js +64 -0
  17. package/dist/commands/status.test.js.map +1 -0
  18. package/dist/daemon-control.d.ts +2 -1
  19. package/dist/daemon-control.js +33 -5
  20. package/dist/daemon-control.js.map +1 -1
  21. package/dist/daemon-control.test.js +88 -0
  22. package/dist/daemon-control.test.js.map +1 -1
  23. package/dist/utils/convention-evaluator.d.ts +7 -0
  24. package/dist/utils/convention-evaluator.js +6 -3
  25. package/dist/utils/convention-evaluator.js.map +1 -1
  26. package/dist/utils/convention-evaluator.test.js +13 -0
  27. package/dist/utils/convention-evaluator.test.js.map +1 -1
  28. package/dist/windows-launcher.d.ts +27 -0
  29. package/dist/windows-launcher.js +114 -0
  30. package/dist/windows-launcher.js.map +1 -0
  31. package/dist/windows-launcher.test.d.ts +1 -0
  32. package/dist/windows-launcher.test.js +150 -0
  33. package/dist/windows-launcher.test.js.map +1 -0
  34. package/native/bin/win32-x64/agentrunner-launcher.exe +0 -0
  35. package/native/bin/win32-x64/manifest.json +8 -0
  36. package/package.json +6 -2
  37. 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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"}
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "version": "0.0.108",
4
+ "platform": "win32",
5
+ "arch": "x64",
6
+ "fileName": "agentrunner-launcher.exe",
7
+ "sha256": "2ef268526b0a99a9006280b3893400af124074779d28760d8d91a3f003cea5e2"
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentteams/runner",
3
- "version": "0.0.106",
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
- "prepublishOnly": "npm run build"
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 scheduled task gets a new runner PID without opening a console window.
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.