@agentteams/runner 0.0.97 → 0.0.99

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 (71) hide show
  1. package/dist/api-client.d.ts +1 -0
  2. package/dist/api-client.js +20 -1
  3. package/dist/api-client.js.map +1 -1
  4. package/dist/api-client.test.js +48 -1
  5. package/dist/api-client.test.js.map +1 -1
  6. package/dist/autostart.d.ts +37 -8
  7. package/dist/autostart.js +158 -68
  8. package/dist/autostart.js.map +1 -1
  9. package/dist/autostart.test.js +130 -76
  10. package/dist/autostart.test.js.map +1 -1
  11. package/dist/commands/start.js +2 -2
  12. package/dist/commands/stop.d.ts +10 -1
  13. package/dist/commands/stop.js +11 -7
  14. package/dist/commands/stop.js.map +1 -1
  15. package/dist/commands/stop.test.d.ts +1 -0
  16. package/dist/commands/stop.test.js +34 -0
  17. package/dist/commands/stop.test.js.map +1 -0
  18. package/dist/commands/uninstall.d.ts +13 -1
  19. package/dist/commands/uninstall.js +21 -10
  20. package/dist/commands/uninstall.js.map +1 -1
  21. package/dist/commands/uninstall.test.d.ts +1 -0
  22. package/dist/commands/uninstall.test.js +42 -0
  23. package/dist/commands/uninstall.test.js.map +1 -0
  24. package/dist/daemon-control.d.ts +2 -1
  25. package/dist/daemon-control.js +16 -6
  26. package/dist/daemon-control.js.map +1 -1
  27. package/dist/daemon-control.test.js +27 -3
  28. package/dist/daemon-control.test.js.map +1 -1
  29. package/dist/executable.test.js +13 -0
  30. package/dist/executable.test.js.map +1 -1
  31. package/dist/handlers/trigger-handler.d.ts +2 -0
  32. package/dist/handlers/trigger-handler.js +36 -5
  33. package/dist/handlers/trigger-handler.js.map +1 -1
  34. package/dist/handlers/trigger-handler.test.js +298 -0
  35. package/dist/handlers/trigger-handler.test.js.map +1 -1
  36. package/dist/poller.test.js +23 -0
  37. package/dist/poller.test.js.map +1 -1
  38. package/dist/runners/capabilities.js +1 -0
  39. package/dist/runners/capabilities.js.map +1 -1
  40. package/dist/runners/capabilities.test.js +13 -1
  41. package/dist/runners/capabilities.test.js.map +1 -1
  42. package/dist/runners/codex.test.js +1 -1
  43. package/dist/runners/codex.test.js.map +1 -1
  44. package/dist/runners/cursor-cli.d.ts +27 -0
  45. package/dist/runners/cursor-cli.js +276 -0
  46. package/dist/runners/cursor-cli.js.map +1 -0
  47. package/dist/runners/cursor-cli.test.d.ts +1 -0
  48. package/dist/runners/cursor-cli.test.js +189 -0
  49. package/dist/runners/cursor-cli.test.js.map +1 -0
  50. package/dist/runners/index.js +3 -0
  51. package/dist/runners/index.js.map +1 -1
  52. package/dist/runners/index.test.js +2 -0
  53. package/dist/runners/index.test.js.map +1 -1
  54. package/dist/runners/stream-json-parser.d.ts +9 -0
  55. package/dist/runners/stream-json-parser.js +143 -0
  56. package/dist/runners/stream-json-parser.js.map +1 -1
  57. package/dist/runners/stream-json-parser.test.js +117 -1
  58. package/dist/runners/stream-json-parser.test.js.map +1 -1
  59. package/dist/types.d.ts +2 -0
  60. package/dist/utils/git-worktree.js +2 -1
  61. package/dist/utils/git-worktree.js.map +1 -1
  62. package/dist/utils/git-worktree.test.js +2 -2
  63. package/dist/utils/git-worktree.test.js.map +1 -1
  64. package/dist/utils/resolve-member-repo.d.ts +39 -0
  65. package/dist/utils/resolve-member-repo.js +180 -0
  66. package/dist/utils/resolve-member-repo.js.map +1 -0
  67. package/dist/utils/resolve-member-repo.test.d.ts +1 -0
  68. package/dist/utils/resolve-member-repo.test.js +201 -0
  69. package/dist/utils/resolve-member-repo.test.js.map +1 -0
  70. package/package.json +2 -2
  71. package/readme.md +24 -6
@@ -0,0 +1,201 @@
1
+ import assert from 'node:assert/strict';
2
+ import { execFileSync } from 'node:child_process';
3
+ import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
4
+ import { basename, join } from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ import test from 'node:test';
7
+ import { findMemberRepoCandidates, normalizeRemoteUrl, resolveWorktreeAuthPath } from './resolve-member-repo.js';
8
+ const makeTempDir = (prefix) => mkdtempSync(join(tmpdir(), prefix));
9
+ const initGitRepo = (dir, originUrl) => {
10
+ execFileSync('git', ['init', dir], { stdio: 'pipe' });
11
+ execFileSync('git', ['-C', dir, 'config', 'user.email', 'test@test.com'], { stdio: 'pipe' });
12
+ execFileSync('git', ['-C', dir, 'config', 'user.name', 'Test'], { stdio: 'pipe' });
13
+ execFileSync('git', ['-C', dir, 'commit', '--allow-empty', '-m', 'initial'], { stdio: 'pipe' });
14
+ if (originUrl) {
15
+ execFileSync('git', ['-C', dir, 'remote', 'add', 'origin', originUrl], { stdio: 'pipe' });
16
+ }
17
+ };
18
+ const cleanupDir = (dir) => {
19
+ rmSync(dir, { recursive: true, force: true });
20
+ };
21
+ test('normalizeRemoteUrl unifies https, scp-ssh, and ssh scheme forms', () => {
22
+ const expected = 'github.com/rlarua/kma-ui';
23
+ assert.equal(normalizeRemoteUrl('https://github.com/rlarua/kma-ui.git'), expected);
24
+ assert.equal(normalizeRemoteUrl('https://github.com/rlarua/kma-ui'), expected);
25
+ assert.equal(normalizeRemoteUrl('https://github.com/rlarua/kma-ui/'), expected);
26
+ assert.equal(normalizeRemoteUrl('git@github.com:rlarua/kma-ui.git'), expected);
27
+ assert.equal(normalizeRemoteUrl('ssh://git@github.com/rlarua/kma-ui.git'), expected);
28
+ assert.equal(normalizeRemoteUrl('ssh://git@github.com:22/rlarua/kma-ui.git'), expected);
29
+ assert.equal(normalizeRemoteUrl('HTTPS://GitHub.com/RLarua/KMA-UI.git'), expected);
30
+ });
31
+ // custom port는 서버 신원의 일부다: 같은 호스트의 다른 포트는 다른 Git 서버이므로
32
+ // 불일치해야 하고, 프로토콜 기본 포트만 무포트 URL과 일치한다.
33
+ test('normalizeRemoteUrl keeps non-default ports and strips protocol-default ports', () => {
34
+ assert.equal(normalizeRemoteUrl('https://git.example.com:8443/team/repo.git'), 'git.example.com:8443/team/repo');
35
+ assert.notEqual(normalizeRemoteUrl('https://git.example.com:8443/team/repo.git'), normalizeRemoteUrl('https://git.example.com:9443/team/repo.git'));
36
+ assert.notEqual(normalizeRemoteUrl('https://git.example.com:8443/team/repo.git'), normalizeRemoteUrl('https://git.example.com/team/repo.git'));
37
+ // Explicit default ports match the port-less form.
38
+ assert.equal(normalizeRemoteUrl('https://git.example.com:443/team/repo.git'), 'git.example.com/team/repo');
39
+ assert.equal(normalizeRemoteUrl('http://git.example.com:80/team/repo.git'), 'git.example.com/team/repo');
40
+ assert.equal(normalizeRemoteUrl('ssh://git@git.example.com:22/team/repo.git'), 'git.example.com/team/repo');
41
+ assert.equal(normalizeRemoteUrl('git://git.example.com:9418/team/repo.git'), 'git.example.com/team/repo');
42
+ // Non-default ssh port stays part of the identity.
43
+ assert.equal(normalizeRemoteUrl('ssh://git@git.example.com:2222/team/repo.git'), 'git.example.com:2222/team/repo');
44
+ });
45
+ test('normalizeRemoteUrl rejects empty or unrecognizable values', () => {
46
+ assert.equal(normalizeRemoteUrl(''), null);
47
+ assert.equal(normalizeRemoteUrl(' '), null);
48
+ assert.equal(normalizeRemoteUrl('not a url'), null);
49
+ assert.equal(normalizeRemoteUrl('git@github.com:'), null);
50
+ });
51
+ // 판정 기준 계약 테스트: CLI findMemberRepos(cli/src/utils/projectLayout.ts)와 동일하게
52
+ // 1뎁스 물리 디렉터리만 후보로 삼고 숨김/node_modules/심링크/비-git/중첩 작업트리를 제외한다.
53
+ test('findMemberRepoCandidates matches the CLI findMemberRepos judgement contract', () => {
54
+ const root = makeTempDir('resolve-member-contract-');
55
+ try {
56
+ // Included: plain member git repos at depth 1
57
+ initGitRepo(join(root, 'repo-a'));
58
+ initGitRepo(join(root, 'repo-b'));
59
+ // Excluded: hidden directory, even if it is a git repo
60
+ initGitRepo(join(root, '.hidden-repo'));
61
+ // Excluded: node_modules, even if it is a git repo
62
+ initGitRepo(join(root, 'node_modules'));
63
+ // Excluded: non-git plain directory
64
+ mkdirSync(join(root, 'plain-dir'));
65
+ // Excluded: plain file
66
+ writeFileSync(join(root, 'README.md'), '# root');
67
+ // Excluded: symlinked directory pointing at a real git repo
68
+ symlinkSync(join(root, 'repo-a'), join(root, 'linked-repo'), 'dir');
69
+ // Excluded: directory that is merely inside another repository's work tree
70
+ mkdirSync(join(root, 'repo-a', 'nested'));
71
+ const candidates = findMemberRepoCandidates(root);
72
+ assert.deepEqual(candidates.map((candidate) => basename(candidate)), ['repo-a', 'repo-b']);
73
+ }
74
+ finally {
75
+ cleanupDir(root);
76
+ }
77
+ });
78
+ test('findMemberRepoCandidates returns empty list for unreadable root', () => {
79
+ assert.deepEqual(findMemberRepoCandidates(join(tmpdir(), `nonexistent-${Date.now()}`)), []);
80
+ });
81
+ test('resolveWorktreeAuthPath returns authPath as-is when it is a git repository', () => {
82
+ const repo = makeTempDir('resolve-member-git-');
83
+ try {
84
+ initGitRepo(repo);
85
+ assert.deepEqual(resolveWorktreeAuthPath(repo, null), { path: repo });
86
+ }
87
+ finally {
88
+ cleanupDir(repo);
89
+ }
90
+ });
91
+ test('resolveWorktreeAuthPath resolves the single member repo matching remoteUrl', () => {
92
+ const root = makeTempDir('resolve-member-match-');
93
+ try {
94
+ initGitRepo(join(root, 'kma-ui'), 'git@github.com:rlarua/kma-ui.git');
95
+ initGitRepo(join(root, 'kma-api'), 'git@github.com:rlarua/kma-api.git');
96
+ const resolution = resolveWorktreeAuthPath(root, 'https://github.com/rlarua/kma-ui.git');
97
+ assert.deepEqual(resolution, { path: join(root, 'kma-ui') });
98
+ }
99
+ finally {
100
+ cleanupDir(root);
101
+ }
102
+ });
103
+ test('resolveWorktreeAuthPath fails with guidance when remoteUrl is null', () => {
104
+ const root = makeTempDir('resolve-member-null-');
105
+ try {
106
+ initGitRepo(join(root, 'kma-ui'), 'git@github.com:rlarua/kma-ui.git');
107
+ const resolution = resolveWorktreeAuthPath(root, null);
108
+ assert.ok('error' in resolution);
109
+ assert.match(resolution.error, /has no remote URL/);
110
+ assert.match(resolution.error, /Turn off the runner box/);
111
+ assert.doesNotMatch(resolution.error, /git init/);
112
+ }
113
+ finally {
114
+ cleanupDir(root);
115
+ }
116
+ });
117
+ test('resolveWorktreeAuthPath fails with guidance when no member repo matches', () => {
118
+ const root = makeTempDir('resolve-member-none-');
119
+ try {
120
+ initGitRepo(join(root, 'kma-ui'), 'git@github.com:rlarua/kma-ui.git');
121
+ const resolution = resolveWorktreeAuthPath(root, 'https://github.com/rlarua/other-repo.git');
122
+ assert.ok('error' in resolution);
123
+ assert.match(resolution.error, /no member repository/);
124
+ assert.match(resolution.error, /Turn off the runner box/);
125
+ assert.doesNotMatch(resolution.error, /git init/);
126
+ }
127
+ finally {
128
+ cleanupDir(root);
129
+ }
130
+ });
131
+ test('resolveWorktreeAuthPath fails with guidance when multiple member repos match', () => {
132
+ const root = makeTempDir('resolve-member-dup-');
133
+ try {
134
+ initGitRepo(join(root, 'kma-ui'), 'git@github.com:rlarua/kma-ui.git');
135
+ initGitRepo(join(root, 'kma-ui-copy'), 'https://github.com/rlarua/kma-ui.git');
136
+ const resolution = resolveWorktreeAuthPath(root, 'https://github.com/rlarua/kma-ui.git');
137
+ assert.ok('error' in resolution);
138
+ assert.match(resolution.error, /multiple member repositories/);
139
+ assert.match(resolution.error, /kma-ui/);
140
+ assert.match(resolution.error, /kma-ui-copy/);
141
+ assert.match(resolution.error, /Turn off the runner box/);
142
+ }
143
+ finally {
144
+ cleanupDir(root);
145
+ }
146
+ });
147
+ test('resolveWorktreeAuthPath fails when the remote URL is unrecognizable', () => {
148
+ const root = makeTempDir('resolve-member-badurl-');
149
+ try {
150
+ initGitRepo(join(root, 'kma-ui'), 'git@github.com:rlarua/kma-ui.git');
151
+ const resolution = resolveWorktreeAuthPath(root, 'not a url');
152
+ assert.ok('error' in resolution);
153
+ assert.match(resolution.error, /not recognized/);
154
+ assert.match(resolution.error, /Turn off the runner box/);
155
+ }
156
+ finally {
157
+ cleanupDir(root);
158
+ }
159
+ });
160
+ // 오류 메시지는 TriggerLogReporter/worktreeError로 서버에 영구 전송되므로
161
+ // credential 포함 remote URL의 비밀값이 어떤 실패 경로에서도 노출되면 안 된다.
162
+ test('resolveWorktreeAuthPath never leaks credentials from the remote URL into errors', () => {
163
+ const root = makeTempDir('resolve-member-cred-');
164
+ try {
165
+ initGitRepo(join(root, 'kma-ui'), 'git@github.com:rlarua/kma-ui.git');
166
+ initGitRepo(join(root, 'other-a'), 'https://github.com/rlarua/other.git');
167
+ initGitRepo(join(root, 'other-b'), 'git@github.com:rlarua/other.git');
168
+ const secret = 'user:s3cret-token';
169
+ // Zero matches
170
+ const none = resolveWorktreeAuthPath(root, `https://${secret}@example.com/team/none.git`);
171
+ assert.ok('error' in none);
172
+ assert.doesNotMatch(none.error, /s3cret-token/);
173
+ assert.match(none.error, /example\.com\/team\/none/);
174
+ // Multiple matches
175
+ const dup = resolveWorktreeAuthPath(root, `https://${secret}@github.com/rlarua/other.git`);
176
+ assert.ok('error' in dup);
177
+ assert.doesNotMatch(dup.error, /s3cret-token/);
178
+ assert.match(dup.error, /github\.com\/rlarua\/other/);
179
+ // Unrecognizable URL: raw value must not be echoed at all
180
+ const bad = resolveWorktreeAuthPath(root, `://${secret}@:not-a-url`);
181
+ assert.ok('error' in bad);
182
+ assert.doesNotMatch(bad.error, /s3cret-token/);
183
+ assert.match(bad.error, /not recognized/);
184
+ }
185
+ finally {
186
+ cleanupDir(root);
187
+ }
188
+ });
189
+ test('resolveWorktreeAuthPath ignores member repos without an origin remote', () => {
190
+ const root = makeTempDir('resolve-member-no-origin-');
191
+ try {
192
+ initGitRepo(join(root, 'no-origin'));
193
+ initGitRepo(join(root, 'kma-ui'), 'git@github.com:rlarua/kma-ui.git');
194
+ const resolution = resolveWorktreeAuthPath(root, 'https://github.com/rlarua/kma-ui.git');
195
+ assert.deepEqual(resolution, { path: join(root, 'kma-ui') });
196
+ }
197
+ finally {
198
+ cleanupDir(root);
199
+ }
200
+ });
201
+ //# sourceMappingURL=resolve-member-repo.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-member-repo.test.js","sourceRoot":"","sources":["../../src/utils/resolve-member-repo.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentteams/runner",
3
- "version": "0.0.97",
3
+ "version": "0.0.99",
4
4
  "description": "AgentRunner - Background runner that polls and executes AI agent tasks",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -16,7 +16,7 @@
16
16
  "typecheck": "tsc --noEmit",
17
17
  "dev": "tsx watch src/index.ts",
18
18
  "test": "tsx --test \"src/**/*.test.ts\"",
19
- "lint": "eslint 'src/**/*.ts'",
19
+ "lint": "eslint \"src/**/*.ts\" --cache --cache-location .eslintcache --cache-strategy content",
20
20
  "format": "prettier --write .",
21
21
  "format:check": "prettier --check .",
22
22
  "start": "node dist/index.js",
package/readme.md CHANGED
@@ -38,7 +38,7 @@ The `init` command:
38
38
  3. Registers an OS-level autostart service and starts the runner immediately
39
39
  - **macOS**: `~/Library/LaunchAgents/run.agentteams.runner.plist` (launchd)
40
40
  - **Linux**: `~/.config/systemd/user/agentrunner.service` (systemd)
41
- - **Windows**: Startup folder `agentrunner-start.vbs`
41
+ - **Windows**: Task Scheduler task `AgentRunner` (current-user logon trigger)
42
42
 
43
43
  ### Options
44
44
 
@@ -91,9 +91,9 @@ Example output:
91
91
  agentrunner stop
92
92
  ```
93
93
 
94
- Sends SIGTERM to the running process for a graceful shutdown.
94
+ Sends SIGTERM to the running process for a graceful shutdown. On Windows, it ends the current `AgentRunner` scheduled-task instance first so the failure policy does not restart an intentionally stopped runner. The task remains registered and can start again at the next logon.
95
95
 
96
- > If autostart is registered, the OS may restart the runner automatically.
96
+ > On macOS and Linux, the registered OS supervisor may restart the runner automatically.
97
97
  > Use `uninstall` to stop completely.
98
98
 
99
99
  ### 5. Restart (`restart`)
@@ -105,6 +105,7 @@ agentrunner restart
105
105
  Restarts the runner using the current environment:
106
106
 
107
107
  - If autostart is registered, AgentRunner restarts through the registered OS service.
108
+ - On Windows, restart ends the existing `AgentRunner` task instance before running it again.
108
109
  - If autostart is not registered, AgentRunner starts a new detached background process.
109
110
 
110
111
  ### 6. Update (`update`)
@@ -123,8 +124,8 @@ agentrunner uninstall
123
124
 
124
125
  Performs the following:
125
126
 
126
- 1. Stops the running process
127
- 2. Removes the autostart service and deletes the service file
127
+ 1. Removes or disables the autostart supervisor so it cannot respawn the runner
128
+ 2. Stops the running process
128
129
  3. Cleans up the PID file
129
130
 
130
131
  ## Configuration
@@ -170,9 +171,26 @@ If a process is already running for the same `agentConfigId`, new triggers are `
170
171
  - **Runner logs**: console output (forwarded to OS log system when autostarted)
171
172
  - **macOS**: `/tmp/agentrunner.log`, `/tmp/agentrunner-error.log`
172
173
  - **Linux**: `journalctl --user -u agentrunner -f`
173
- - **Windows**: check the Startup folder script and the spawned background process
174
+ - **Windows**: `%USERPROFILE%\.agentteams\agentrunner.log`
174
175
  - **Task logs**: `<workdir>/.agentteams/daemonLog/daemon-<triggerId>.log`
175
176
 
177
+ ### Windows recovery checks
178
+
179
+ 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
+
181
+ ```powershell
182
+ schtasks /Query /TN "AgentRunner" /V /FO LIST
183
+ Get-Content "$env:USERPROFILE\.agentteams\agentrunner.log" -Wait
184
+ ```
185
+
186
+ For a release smoke test on a disposable Windows test machine:
187
+
188
+ 1. Run `agentrunner restart` and verify the scheduled task gets a new runner PID without opening a console window.
189
+ 2. End the runner process unexpectedly and verify Task Scheduler starts it again after the configured delay.
190
+ 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
+ 4. Run `agentrunner status`, then `agentrunner stop`. Verify the current task instance stops and does not immediately respawn.
192
+ 5. Run `agentrunner uninstall` only when cleanup is intended, and verify `schtasks /Query /TN "AgentRunner"` reports that the task no longer exists.
193
+
176
194
  ## Troubleshooting
177
195
 
178
196
  ### `Missing token. Usage: agentrunner init --token <token> ...`