@agentteams/runner 0.0.114 → 0.0.115
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 +1 -0
- package/dist/api-client.js +13 -0
- package/dist/api-client.js.map +1 -1
- package/dist/commands/update.js +1 -7
- package/dist/commands/update.js.map +1 -1
- package/dist/poller.d.ts +1 -1
- package/dist/poller.js +5 -1
- package/dist/poller.js.map +1 -1
- package/dist/utils/auto-update.d.ts +17 -2
- package/dist/utils/auto-update.js +165 -52
- package/dist/utils/auto-update.js.map +1 -1
- package/dist/utils/auto-update.test.js +357 -7
- package/dist/utils/auto-update.test.js.map +1 -1
- package/dist/utils/npm-global-permission.d.ts +18 -0
- package/dist/utils/npm-global-permission.js +41 -0
- package/dist/utils/npm-global-permission.js.map +1 -0
- package/dist/utils/npm-global-permission.test.d.ts +1 -0
- package/dist/utils/npm-global-permission.test.js +75 -0
- package/dist/utils/npm-global-permission.test.js.map +1 -0
- package/dist/utils/npm-install-error.d.ts +12 -0
- package/dist/utils/npm-install-error.js +19 -0
- package/dist/utils/npm-install-error.js.map +1 -0
- package/dist/utils/npm-install-error.test.d.ts +1 -0
- package/dist/utils/npm-install-error.test.js +28 -0
- package/dist/utils/npm-install-error.test.js.map +1 -0
- package/native/bin/win32-x64/agentrunner-launcher.exe +0 -0
- package/native/bin/win32-x64/manifest.json +2 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { test } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { maybeAutoUpdate, resetAutoUpdateState } from './auto-update.js';
|
|
4
|
-
test('maybeAutoUpdate calls
|
|
4
|
+
test('maybeAutoUpdate calls onUpdateSucceeded after successful install', async () => {
|
|
5
5
|
resetAutoUpdateState();
|
|
6
6
|
let installCalled = false;
|
|
7
7
|
let notifiedVersion = null;
|
|
@@ -18,8 +18,9 @@ test('maybeAutoUpdate calls onRunnerUpdated after successful install', async ()
|
|
|
18
18
|
error: () => { },
|
|
19
19
|
},
|
|
20
20
|
now: () => Date.now(),
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
canWriteGlobalNpmRoot: () => true,
|
|
22
|
+
onUpdateSucceeded: async (input) => {
|
|
23
|
+
notifiedVersion = input.version;
|
|
23
24
|
},
|
|
24
25
|
};
|
|
25
26
|
const meta = {
|
|
@@ -28,9 +29,9 @@ test('maybeAutoUpdate calls onRunnerUpdated after successful install', async ()
|
|
|
28
29
|
};
|
|
29
30
|
await maybeAutoUpdate(meta, deps);
|
|
30
31
|
assert.ok(installCalled, 'installPackage should be called');
|
|
31
|
-
assert.equal(notifiedVersion, '99.9.9', '
|
|
32
|
+
assert.equal(notifiedVersion, '99.9.9', 'onUpdateSucceeded should be called with new version');
|
|
32
33
|
});
|
|
33
|
-
test('maybeAutoUpdate does not call
|
|
34
|
+
test('maybeAutoUpdate does not call onUpdateSucceeded again if it already succeeded for that version', async () => {
|
|
34
35
|
resetAutoUpdateState();
|
|
35
36
|
let installCount = 0;
|
|
36
37
|
let notifyCount = 0;
|
|
@@ -45,7 +46,8 @@ test('maybeAutoUpdate does not call onRunnerUpdated again if it already succeede
|
|
|
45
46
|
error: () => { },
|
|
46
47
|
},
|
|
47
48
|
now: () => Date.now(),
|
|
48
|
-
|
|
49
|
+
canWriteGlobalNpmRoot: () => true,
|
|
50
|
+
onUpdateSucceeded: async () => {
|
|
49
51
|
notifyCount++;
|
|
50
52
|
},
|
|
51
53
|
};
|
|
@@ -62,6 +64,84 @@ test('maybeAutoUpdate does not call onRunnerUpdated again if it already succeede
|
|
|
62
64
|
assert.equal(installCount, 1, 'should not install again');
|
|
63
65
|
assert.equal(notifyCount, 1, 'should not notify again');
|
|
64
66
|
});
|
|
67
|
+
/**
|
|
68
|
+
* 실측 재현 로그(리눅스 systemd --user, npm prefix -g = /usr/local):
|
|
69
|
+
* `npm install -g` 자식 프로세스가 EACCES(errno -13)로 죽는다.
|
|
70
|
+
*/
|
|
71
|
+
const EACCES_INSTALL_ERROR_MESSAGE = [
|
|
72
|
+
'Command failed: /usr/bin/npm install -g @agentteams/runner@99.9.9',
|
|
73
|
+
'npm ERR! code EACCES',
|
|
74
|
+
'npm ERR! syscall rename',
|
|
75
|
+
'npm ERR! path /usr/local/lib/node_modules/@agentteams/runner',
|
|
76
|
+
'npm ERR! errno -13',
|
|
77
|
+
].join('\n');
|
|
78
|
+
test('maybeAutoUpdate reports EACCES install failure as PERMISSION_DENIED exactly once', async () => {
|
|
79
|
+
resetAutoUpdateState();
|
|
80
|
+
const failures = [];
|
|
81
|
+
const deps = {
|
|
82
|
+
runExecutableSync: (name, args) => {
|
|
83
|
+
if (name === 'npm' && args[0] === 'install') {
|
|
84
|
+
throw new Error(EACCES_INSTALL_ERROR_MESSAGE);
|
|
85
|
+
}
|
|
86
|
+
return '';
|
|
87
|
+
},
|
|
88
|
+
logger: {
|
|
89
|
+
info: () => { },
|
|
90
|
+
warn: () => { },
|
|
91
|
+
error: () => { },
|
|
92
|
+
},
|
|
93
|
+
now: () => 20000000,
|
|
94
|
+
// 프리플라이트는 통과시키고 설치 자체가 EACCES로 죽는 경로를 재현한다.
|
|
95
|
+
canWriteGlobalNpmRoot: () => true,
|
|
96
|
+
onUpdateFailed: async (input) => {
|
|
97
|
+
failures.push(input);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
const meta = {
|
|
101
|
+
cliLatestVersion: null,
|
|
102
|
+
runnerLatestVersion: '99.9.9',
|
|
103
|
+
};
|
|
104
|
+
await maybeAutoUpdate(meta, deps);
|
|
105
|
+
assert.equal(failures.length, 1, 'onUpdateFailed should be called exactly once');
|
|
106
|
+
assert.equal(failures[0]?.package, 'runner');
|
|
107
|
+
assert.equal(failures[0]?.version, '99.9.9');
|
|
108
|
+
assert.equal(failures[0]?.reason, 'PERMISSION_DENIED');
|
|
109
|
+
});
|
|
110
|
+
test('maybeAutoUpdate does not retry a permission-blocked install within 24 hours', async () => {
|
|
111
|
+
resetAutoUpdateState();
|
|
112
|
+
let installCount = 0;
|
|
113
|
+
let failureCount = 0;
|
|
114
|
+
const deps = {
|
|
115
|
+
runExecutableSync: (name, args) => {
|
|
116
|
+
if (name === 'npm' && args[0] === 'install') {
|
|
117
|
+
installCount++;
|
|
118
|
+
throw new Error(EACCES_INSTALL_ERROR_MESSAGE);
|
|
119
|
+
}
|
|
120
|
+
return '';
|
|
121
|
+
},
|
|
122
|
+
logger: {
|
|
123
|
+
info: () => { },
|
|
124
|
+
warn: () => { },
|
|
125
|
+
error: () => { },
|
|
126
|
+
},
|
|
127
|
+
now: () => 20000000,
|
|
128
|
+
canWriteGlobalNpmRoot: () => true,
|
|
129
|
+
onUpdateFailed: async () => {
|
|
130
|
+
failureCount++;
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
const meta = {
|
|
134
|
+
cliLatestVersion: null,
|
|
135
|
+
runnerLatestVersion: '99.9.9',
|
|
136
|
+
};
|
|
137
|
+
await maybeAutoUpdate(meta, deps);
|
|
138
|
+
assert.equal(installCount, 1, 'first poll should attempt the install');
|
|
139
|
+
assert.equal(failureCount, 1, 'first poll should report the failure');
|
|
140
|
+
// 기존 1시간 쿨다운은 지났지만 권한 차단 백오프(24시간) 안이므로 재시도하지 않는다.
|
|
141
|
+
await maybeAutoUpdate(meta, { ...deps, now: () => 20000000 + 2 * 60 * 60 * 1000 });
|
|
142
|
+
assert.equal(installCount, 1, 'should not retry install within the permission-blocked backoff');
|
|
143
|
+
assert.equal(failureCount, 1, 'should not report the same failure again');
|
|
144
|
+
});
|
|
65
145
|
test('maybeAutoUpdate RETRIES notification if it failed before', async () => {
|
|
66
146
|
resetAutoUpdateState();
|
|
67
147
|
let notifyCount = 0;
|
|
@@ -74,7 +154,8 @@ test('maybeAutoUpdate RETRIES notification if it failed before', async () => {
|
|
|
74
154
|
error: () => { },
|
|
75
155
|
},
|
|
76
156
|
now: () => 10000000,
|
|
77
|
-
|
|
157
|
+
canWriteGlobalNpmRoot: () => true,
|
|
158
|
+
onUpdateSucceeded: async () => {
|
|
78
159
|
if (shouldFailNotify) {
|
|
79
160
|
shouldFailNotify = false;
|
|
80
161
|
throw new Error('Network error');
|
|
@@ -97,4 +178,273 @@ test('maybeAutoUpdate RETRIES notification if it failed before', async () => {
|
|
|
97
178
|
console.log('Second call done. notifyCount:', notifyCount);
|
|
98
179
|
assert.equal(notifyCount, 1, 'Should retry notification successfully');
|
|
99
180
|
});
|
|
181
|
+
test('maybeAutoUpdate skips the install entirely when the global npm root is not writable', async () => {
|
|
182
|
+
resetAutoUpdateState();
|
|
183
|
+
const commands = [];
|
|
184
|
+
const failures = [];
|
|
185
|
+
const warnings = [];
|
|
186
|
+
const deps = {
|
|
187
|
+
runExecutableSync: (name, args) => {
|
|
188
|
+
commands.push({ name, args });
|
|
189
|
+
return '';
|
|
190
|
+
},
|
|
191
|
+
logger: {
|
|
192
|
+
info: () => { },
|
|
193
|
+
warn: (message) => {
|
|
194
|
+
warnings.push(message);
|
|
195
|
+
},
|
|
196
|
+
error: () => { },
|
|
197
|
+
},
|
|
198
|
+
now: () => 30000000,
|
|
199
|
+
canWriteGlobalNpmRoot: () => false,
|
|
200
|
+
onUpdateFailed: async (input) => {
|
|
201
|
+
failures.push(input);
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
const meta = {
|
|
205
|
+
cliLatestVersion: null,
|
|
206
|
+
runnerLatestVersion: '99.9.9',
|
|
207
|
+
};
|
|
208
|
+
await maybeAutoUpdate(meta, deps);
|
|
209
|
+
assert.equal(commands.filter((command) => command.name === 'npm' && command.args[0] === 'install').length, 0, 'npm install -g should not run when the preflight says the global npm root is not writable');
|
|
210
|
+
assert.equal(failures.length, 1);
|
|
211
|
+
assert.equal(failures[0]?.reason, 'PERMISSION_DENIED');
|
|
212
|
+
assert.equal(warnings.length, 1, 'the remediation hint should be logged once per target version');
|
|
213
|
+
});
|
|
214
|
+
test('maybeAutoUpdate falls back to attempting the install when the preflight cannot decide', async () => {
|
|
215
|
+
resetAutoUpdateState();
|
|
216
|
+
let installCalled = false;
|
|
217
|
+
const deps = {
|
|
218
|
+
runExecutableSync: (name, args) => {
|
|
219
|
+
if (name === 'npm' && args[0] === 'install') {
|
|
220
|
+
installCalled = true;
|
|
221
|
+
}
|
|
222
|
+
return '';
|
|
223
|
+
},
|
|
224
|
+
logger: {
|
|
225
|
+
info: () => { },
|
|
226
|
+
warn: () => { },
|
|
227
|
+
error: () => { },
|
|
228
|
+
},
|
|
229
|
+
now: () => 40000000,
|
|
230
|
+
canWriteGlobalNpmRoot: () => {
|
|
231
|
+
throw new Error('npm prefix -g failed');
|
|
232
|
+
},
|
|
233
|
+
onUpdateFailed: async () => { },
|
|
234
|
+
};
|
|
235
|
+
const meta = {
|
|
236
|
+
cliLatestVersion: null,
|
|
237
|
+
runnerLatestVersion: '99.9.9',
|
|
238
|
+
};
|
|
239
|
+
await maybeAutoUpdate(meta, deps);
|
|
240
|
+
assert.ok(installCalled, 'fail-open: an undecidable preflight must not block the install');
|
|
241
|
+
});
|
|
242
|
+
test('maybeAutoUpdate retries immediately when the permission-blocked target version changes', async () => {
|
|
243
|
+
resetAutoUpdateState();
|
|
244
|
+
let installCount = 0;
|
|
245
|
+
const failures = [];
|
|
246
|
+
const deps = {
|
|
247
|
+
runExecutableSync: (name, args) => {
|
|
248
|
+
if (name === 'npm' && args[0] === 'install') {
|
|
249
|
+
installCount++;
|
|
250
|
+
throw new Error('npm ERR! code EACCES');
|
|
251
|
+
}
|
|
252
|
+
return '';
|
|
253
|
+
},
|
|
254
|
+
logger: {
|
|
255
|
+
info: () => { },
|
|
256
|
+
warn: () => { },
|
|
257
|
+
error: () => { },
|
|
258
|
+
},
|
|
259
|
+
now: () => 50000000,
|
|
260
|
+
canWriteGlobalNpmRoot: () => true,
|
|
261
|
+
onUpdateFailed: async (input) => {
|
|
262
|
+
failures.push(input);
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
await maybeAutoUpdate({ cliLatestVersion: null, runnerLatestVersion: '99.9.9' }, deps);
|
|
266
|
+
assert.equal(installCount, 1);
|
|
267
|
+
// 대상 버전이 바뀌면 24시간 백오프와 무관하게 다시 시도한다(1시간 쿨다운만 적용).
|
|
268
|
+
await maybeAutoUpdate({ cliLatestVersion: null, runnerLatestVersion: '99.9.10' }, { ...deps, now: () => 50000000 + 60 * 60 * 1000 + 1 });
|
|
269
|
+
assert.equal(installCount, 2, 'a new target version should be attempted again');
|
|
270
|
+
assert.deepEqual(failures.map((failure) => failure.version), ['99.9.9', '99.9.10']);
|
|
271
|
+
});
|
|
272
|
+
test('maybeAutoUpdate retries the failure report when the server call failed', async () => {
|
|
273
|
+
resetAutoUpdateState();
|
|
274
|
+
let reportAttempts = 0;
|
|
275
|
+
let shouldFailReport = true;
|
|
276
|
+
const deps = {
|
|
277
|
+
runExecutableSync: () => '',
|
|
278
|
+
logger: {
|
|
279
|
+
info: () => { },
|
|
280
|
+
warn: () => { },
|
|
281
|
+
error: () => { },
|
|
282
|
+
},
|
|
283
|
+
now: () => 60000000,
|
|
284
|
+
canWriteGlobalNpmRoot: () => false,
|
|
285
|
+
onUpdateFailed: async () => {
|
|
286
|
+
reportAttempts++;
|
|
287
|
+
if (shouldFailReport) {
|
|
288
|
+
shouldFailReport = false;
|
|
289
|
+
throw new Error('Network error');
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
const meta = {
|
|
294
|
+
cliLatestVersion: null,
|
|
295
|
+
runnerLatestVersion: '99.9.9',
|
|
296
|
+
};
|
|
297
|
+
await maybeAutoUpdate(meta, deps);
|
|
298
|
+
assert.equal(reportAttempts, 1);
|
|
299
|
+
// 보고 실패는 수렴 대상이 아니다. 24시간 백오프가 지난 뒤 다시 보고를 시도한다.
|
|
300
|
+
await maybeAutoUpdate(meta, { ...deps, now: () => 60000000 + 24 * 60 * 60 * 1000 + 1 });
|
|
301
|
+
assert.equal(reportAttempts, 2, 'a failed report should be retried');
|
|
302
|
+
// 보고에 성공했으면 같은 대상 버전으로 다시 보내지 않는다.
|
|
303
|
+
await maybeAutoUpdate(meta, { ...deps, now: () => 60000000 + 48 * 60 * 60 * 1000 + 2 });
|
|
304
|
+
assert.equal(reportAttempts, 2, 'a succeeded report should converge to once per target version');
|
|
305
|
+
});
|
|
306
|
+
test('maybeAutoUpdate retries the failure report on the next poll even while the install is permission-blocked', async () => {
|
|
307
|
+
resetAutoUpdateState();
|
|
308
|
+
let installCount = 0;
|
|
309
|
+
let reportAttempts = 0;
|
|
310
|
+
let shouldFailReport = true;
|
|
311
|
+
const deps = {
|
|
312
|
+
runExecutableSync: (name, args) => {
|
|
313
|
+
if (name === 'npm' && args[0] === 'install') {
|
|
314
|
+
installCount++;
|
|
315
|
+
throw new Error(EACCES_INSTALL_ERROR_MESSAGE);
|
|
316
|
+
}
|
|
317
|
+
return '';
|
|
318
|
+
},
|
|
319
|
+
logger: {
|
|
320
|
+
info: () => { },
|
|
321
|
+
warn: () => { },
|
|
322
|
+
error: () => { },
|
|
323
|
+
},
|
|
324
|
+
now: () => 70000000,
|
|
325
|
+
canWriteGlobalNpmRoot: () => true,
|
|
326
|
+
onUpdateFailed: async () => {
|
|
327
|
+
reportAttempts++;
|
|
328
|
+
if (shouldFailReport) {
|
|
329
|
+
shouldFailReport = false;
|
|
330
|
+
throw new Error('Network error');
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
const meta = {
|
|
335
|
+
cliLatestVersion: null,
|
|
336
|
+
runnerLatestVersion: '99.9.9',
|
|
337
|
+
};
|
|
338
|
+
await maybeAutoUpdate(meta, deps);
|
|
339
|
+
assert.equal(installCount, 1);
|
|
340
|
+
assert.equal(reportAttempts, 1, 'the first poll should attempt the report');
|
|
341
|
+
// 설치는 24시간 권한 백오프에 걸려 있어도, 미전송 보고는 바로 다음 폴링에서 재시도된다.
|
|
342
|
+
await maybeAutoUpdate(meta, { ...deps, now: () => 70000000 + 60 * 1000 });
|
|
343
|
+
assert.equal(installCount, 1, 'the install must stay inside the permission-blocked backoff');
|
|
344
|
+
assert.equal(reportAttempts, 2, 'an unsent failure report must be retried on the very next poll');
|
|
345
|
+
// 보고에 성공했으면 같은 (version, reason)으로 다시 보내지 않는다.
|
|
346
|
+
await maybeAutoUpdate(meta, { ...deps, now: () => 70000000 + 2 * 60 * 1000 });
|
|
347
|
+
assert.equal(reportAttempts, 2, 'a succeeded report should converge');
|
|
348
|
+
});
|
|
349
|
+
test('maybeAutoUpdate reports a changed failure reason for the same target version', async () => {
|
|
350
|
+
resetAutoUpdateState();
|
|
351
|
+
const failures = [];
|
|
352
|
+
let installError = new Error('npm ERR! network timeout');
|
|
353
|
+
const deps = {
|
|
354
|
+
runExecutableSync: (name, args) => {
|
|
355
|
+
if (name === 'npm' && args[0] === 'install') {
|
|
356
|
+
throw installError;
|
|
357
|
+
}
|
|
358
|
+
return '';
|
|
359
|
+
},
|
|
360
|
+
logger: {
|
|
361
|
+
info: () => { },
|
|
362
|
+
warn: () => { },
|
|
363
|
+
error: () => { },
|
|
364
|
+
},
|
|
365
|
+
now: () => 80000000,
|
|
366
|
+
canWriteGlobalNpmRoot: () => true,
|
|
367
|
+
onUpdateFailed: async (input) => {
|
|
368
|
+
failures.push(input);
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
const meta = {
|
|
372
|
+
cliLatestVersion: null,
|
|
373
|
+
runnerLatestVersion: '99.9.9',
|
|
374
|
+
};
|
|
375
|
+
await maybeAutoUpdate(meta, deps);
|
|
376
|
+
assert.deepEqual(failures.map((failure) => failure.reason), ['UNKNOWN']);
|
|
377
|
+
// 같은 대상 버전이라도 사유가 바뀌면 서버가 새 상태로 취급하므로 다시 보고해야 한다.
|
|
378
|
+
installError = new Error(EACCES_INSTALL_ERROR_MESSAGE);
|
|
379
|
+
await maybeAutoUpdate(meta, { ...deps, now: () => 80000000 + 60 * 60 * 1000 + 1 });
|
|
380
|
+
assert.deepEqual(failures.map((failure) => failure.reason), ['UNKNOWN', 'PERMISSION_DENIED']);
|
|
381
|
+
// 완전히 동일한 (version, reason)만 억제된다.
|
|
382
|
+
await maybeAutoUpdate(meta, { ...deps, now: () => 80000000 + 25 * 60 * 60 * 1000 });
|
|
383
|
+
assert.equal(failures.length, 2, 'an identical (version, reason) report must be suppressed');
|
|
384
|
+
});
|
|
385
|
+
test('maybeAutoUpdate attempts a new target version immediately after a permission failure', async () => {
|
|
386
|
+
resetAutoUpdateState();
|
|
387
|
+
const attemptedVersions = [];
|
|
388
|
+
const deps = {
|
|
389
|
+
runExecutableSync: (name, args) => {
|
|
390
|
+
if (name === 'npm' && args[0] === 'install') {
|
|
391
|
+
attemptedVersions.push(String(args[2]));
|
|
392
|
+
throw new Error(EACCES_INSTALL_ERROR_MESSAGE);
|
|
393
|
+
}
|
|
394
|
+
return '';
|
|
395
|
+
},
|
|
396
|
+
logger: {
|
|
397
|
+
info: () => { },
|
|
398
|
+
warn: () => { },
|
|
399
|
+
error: () => { },
|
|
400
|
+
},
|
|
401
|
+
now: () => 90000000,
|
|
402
|
+
canWriteGlobalNpmRoot: () => true,
|
|
403
|
+
onUpdateFailed: async () => { },
|
|
404
|
+
};
|
|
405
|
+
await maybeAutoUpdate({ cliLatestVersion: null, runnerLatestVersion: '99.9.9' }, deps);
|
|
406
|
+
assert.deepEqual(attemptedVersions, ['@agentteams/runner@99.9.9']);
|
|
407
|
+
// 실패 직후 1분 만에 새 버전이 배포되면 쿨다운을 기다리지 않고 즉시 시도한다.
|
|
408
|
+
await maybeAutoUpdate({ cliLatestVersion: null, runnerLatestVersion: '99.9.10' }, { ...deps, now: () => 90000000 + 60 * 1000 });
|
|
409
|
+
assert.deepEqual(attemptedVersions, ['@agentteams/runner@99.9.9', '@agentteams/runner@99.9.10']);
|
|
410
|
+
});
|
|
411
|
+
test('maybeAutoUpdate reports a CLI install success so the server can clear the CLI failure', async () => {
|
|
412
|
+
resetAutoUpdateState();
|
|
413
|
+
const successes = [];
|
|
414
|
+
const failures = [];
|
|
415
|
+
let canWrite = false;
|
|
416
|
+
const deps = {
|
|
417
|
+
runExecutableSync: (name, args) => {
|
|
418
|
+
if (name === 'npm' && args[0] === 'list') {
|
|
419
|
+
return JSON.stringify({ dependencies: { '@agentteams/cli': { version: '1.0.0' } } });
|
|
420
|
+
}
|
|
421
|
+
return '';
|
|
422
|
+
},
|
|
423
|
+
logger: {
|
|
424
|
+
info: () => { },
|
|
425
|
+
warn: () => { },
|
|
426
|
+
error: () => { },
|
|
427
|
+
},
|
|
428
|
+
now: () => 100000000,
|
|
429
|
+
canWriteGlobalNpmRoot: () => canWrite,
|
|
430
|
+
onUpdateSucceeded: async (input) => {
|
|
431
|
+
successes.push(input);
|
|
432
|
+
},
|
|
433
|
+
onUpdateFailed: async (input) => {
|
|
434
|
+
failures.push(input);
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
const meta = {
|
|
438
|
+
cliLatestVersion: '1.1.0',
|
|
439
|
+
runnerLatestVersion: null,
|
|
440
|
+
};
|
|
441
|
+
await maybeAutoUpdate(meta, deps);
|
|
442
|
+
assert.equal(failures.length, 1, 'the blocked CLI install should be reported');
|
|
443
|
+
assert.equal(failures[0]?.package, 'cli');
|
|
444
|
+
assert.equal(successes.length, 0);
|
|
445
|
+
// 사용자가 권한을 고친 뒤 새 대상 버전이 나오면 즉시 재시도되고, 성공은 패키지와 함께 보고된다.
|
|
446
|
+
canWrite = true;
|
|
447
|
+
await maybeAutoUpdate({ cliLatestVersion: '1.1.1', runnerLatestVersion: null }, { ...deps, canWriteGlobalNpmRoot: () => canWrite, now: () => 100000000 + 60 * 1000 });
|
|
448
|
+
assert.deepEqual(successes, [{ package: 'cli', version: '1.1.1' }]);
|
|
449
|
+
});
|
|
100
450
|
//# sourceMappingURL=auto-update.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-update.test.js","sourceRoot":"","sources":["../../src/utils/auto-update.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auto-update.test.js","sourceRoot":"","sources":["../../src/utils/auto-update.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { accessSync } from 'node:fs';
|
|
2
|
+
import { platform as getPlatform } from 'node:os';
|
|
3
|
+
/**
|
|
4
|
+
* 전역 npm 모듈 루트에 쓸 수 있는지 미리 판정한다.
|
|
5
|
+
*
|
|
6
|
+
* 리눅스 기본 설치(`npm prefix -g` = `/usr/local`, `/usr/local/lib/node_modules`가 root 소유)에서
|
|
7
|
+
* `--user` systemd 서비스로 도는 러너는 `npm install -g`가 항상 EACCES로 죽는다. 실행해봐야 실패할
|
|
8
|
+
* 설치를 매시간 반복하지 않도록 설치 직전에 이 판정을 먼저 한다.
|
|
9
|
+
*
|
|
10
|
+
* ⚠️ fail-open: prefix를 못 구하거나 판정 중 예외가 나면 `true`를 돌려준다. 정상 환경의 자동
|
|
11
|
+
* 업데이트를 새로 막는 것이 반복 실패보다 나쁘기 때문이다.
|
|
12
|
+
*/
|
|
13
|
+
export type NpmGlobalPermissionDeps = {
|
|
14
|
+
npmGlobalPrefix?: () => string | null;
|
|
15
|
+
accessSync?: typeof accessSync;
|
|
16
|
+
platform?: typeof getPlatform;
|
|
17
|
+
};
|
|
18
|
+
export declare const canWriteGlobalNpmRoot: (deps?: NpmGlobalPermissionDeps) => boolean;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { accessSync, constants } from 'node:fs';
|
|
2
|
+
import { platform as getPlatform } from 'node:os';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { getNpmGlobalBinPath } from '../executable.js';
|
|
5
|
+
/** 전역 모듈 루트 경로. win32는 prefix 바로 아래, POSIX는 `<prefix>/lib/node_modules`. */
|
|
6
|
+
const resolveGlobalModulesRoot = (prefix, os) => os === 'win32' ? join(prefix, 'node_modules') : join(prefix, 'lib', 'node_modules');
|
|
7
|
+
export const canWriteGlobalNpmRoot = (deps = {}) => {
|
|
8
|
+
const resolvePrefix = deps.npmGlobalPrefix ?? (() => getNpmGlobalBinPath());
|
|
9
|
+
const access = deps.accessSync ?? accessSync;
|
|
10
|
+
const os = (deps.platform ?? getPlatform)();
|
|
11
|
+
try {
|
|
12
|
+
const prefix = resolvePrefix();
|
|
13
|
+
if (!prefix) {
|
|
14
|
+
return true; // prefix를 못 구하면 판정 불가 → fail-open
|
|
15
|
+
}
|
|
16
|
+
// 설치 대상 디렉터리가 아직 없을 수 있다(최초 전역 설치). 존재하는 가장 가까운 상위 경로로
|
|
17
|
+
// 올라가 그곳의 쓰기 권한으로 판정한다.
|
|
18
|
+
let candidate = resolveGlobalModulesRoot(prefix, os);
|
|
19
|
+
for (;;) {
|
|
20
|
+
try {
|
|
21
|
+
access(candidate, constants.W_OK);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
const code = error.code;
|
|
26
|
+
if (code !== 'ENOENT') {
|
|
27
|
+
return false; // EACCES/EPERM 등 → 쓰기 불가로 확정
|
|
28
|
+
}
|
|
29
|
+
const parent = dirname(candidate);
|
|
30
|
+
if (parent === candidate) {
|
|
31
|
+
return true; // 루트까지 올라가도 못 찾음 → 판정 불가 → fail-open
|
|
32
|
+
}
|
|
33
|
+
candidate = parent;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return true; // 예상 못 한 예외 → fail-open
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=npm-global-permission.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm-global-permission.js","sourceRoot":"","sources":["../../src/utils/npm-global-permission.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,QAAQ,IAAI,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAkBvD,4EAA4E;AAC5E,MAAM,wBAAwB,GAAG,CAAC,MAAc,EAAE,EAAmB,EAAU,EAAE,CAC/E,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;AAEtF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,OAAgC,EAAE,EAAW,EAAE;IACnF,MAAM,aAAa,GAAG,IAAI,CAAC,eAAe,IAAI,CAAC,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC;IAC7C,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,WAAW,CAAC,EAAE,CAAC;IAE5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC,CAAC,kCAAkC;QACjD,CAAC;QAED,uDAAuD;QACvD,wBAAwB;QACxB,IAAI,SAAS,GAAG,wBAAwB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACrD,SAAS,CAAC;YACR,IAAI,CAAC;gBACH,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;gBAClC,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAC;gBACnD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACtB,OAAO,KAAK,CAAC,CAAC,6BAA6B;gBAC7C,CAAC;gBAED,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;gBAClC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;oBACzB,OAAO,IAAI,CAAC,CAAC,qCAAqC;gBACpD,CAAC;gBACD,SAAS,GAAG,MAAM,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,wBAAwB;IACvC,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
import { canWriteGlobalNpmRoot } from './npm-global-permission.js';
|
|
4
|
+
const enoent = () => {
|
|
5
|
+
const error = new Error('ENOENT');
|
|
6
|
+
error.code = 'ENOENT';
|
|
7
|
+
throw error;
|
|
8
|
+
};
|
|
9
|
+
const eacces = () => {
|
|
10
|
+
const error = new Error('EACCES');
|
|
11
|
+
error.code = 'EACCES';
|
|
12
|
+
throw error;
|
|
13
|
+
};
|
|
14
|
+
test('canWriteGlobalNpmRoot checks <prefix>/lib/node_modules on POSIX', () => {
|
|
15
|
+
const checked = [];
|
|
16
|
+
const result = canWriteGlobalNpmRoot({
|
|
17
|
+
npmGlobalPrefix: () => '/usr/local',
|
|
18
|
+
platform: () => 'linux',
|
|
19
|
+
accessSync: ((path) => {
|
|
20
|
+
checked.push(path);
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
assert.equal(result, true);
|
|
24
|
+
assert.deepEqual(checked, ['/usr/local/lib/node_modules']);
|
|
25
|
+
});
|
|
26
|
+
test('canWriteGlobalNpmRoot checks <prefix>\\node_modules on Windows', () => {
|
|
27
|
+
const checked = [];
|
|
28
|
+
canWriteGlobalNpmRoot({
|
|
29
|
+
npmGlobalPrefix: () => 'C:\\Users\\me\\AppData\\Roaming\\npm',
|
|
30
|
+
platform: () => 'win32',
|
|
31
|
+
accessSync: ((path) => {
|
|
32
|
+
checked.push(path);
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
assert.equal(checked.length, 1);
|
|
36
|
+
assert.match(checked[0] ?? '', /node_modules$/);
|
|
37
|
+
});
|
|
38
|
+
test('canWriteGlobalNpmRoot reports false when the global modules root is not writable', () => {
|
|
39
|
+
const result = canWriteGlobalNpmRoot({
|
|
40
|
+
npmGlobalPrefix: () => '/usr/local',
|
|
41
|
+
platform: () => 'linux',
|
|
42
|
+
accessSync: eacces,
|
|
43
|
+
});
|
|
44
|
+
assert.equal(result, false);
|
|
45
|
+
});
|
|
46
|
+
test('canWriteGlobalNpmRoot walks up to the nearest existing directory', () => {
|
|
47
|
+
const checked = [];
|
|
48
|
+
const result = canWriteGlobalNpmRoot({
|
|
49
|
+
npmGlobalPrefix: () => '/usr/local',
|
|
50
|
+
platform: () => 'linux',
|
|
51
|
+
accessSync: ((path) => {
|
|
52
|
+
checked.push(path);
|
|
53
|
+
if (path !== '/usr') {
|
|
54
|
+
enoent();
|
|
55
|
+
}
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
assert.equal(result, true);
|
|
59
|
+
assert.deepEqual(checked, ['/usr/local/lib/node_modules', '/usr/local/lib', '/usr/local', '/usr']);
|
|
60
|
+
});
|
|
61
|
+
test('canWriteGlobalNpmRoot fails open when the prefix cannot be resolved', () => {
|
|
62
|
+
assert.equal(canWriteGlobalNpmRoot({
|
|
63
|
+
npmGlobalPrefix: () => null,
|
|
64
|
+
platform: () => 'linux',
|
|
65
|
+
accessSync: eacces,
|
|
66
|
+
}), true);
|
|
67
|
+
assert.equal(canWriteGlobalNpmRoot({
|
|
68
|
+
npmGlobalPrefix: () => {
|
|
69
|
+
throw new Error('npm prefix -g failed');
|
|
70
|
+
},
|
|
71
|
+
platform: () => 'linux',
|
|
72
|
+
accessSync: eacces,
|
|
73
|
+
}), true);
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=npm-global-permission.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm-global-permission.test.js","sourceRoot":"","sources":["../../src/utils/npm-global-permission.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `npm install -g` 실패 원인 분류의 단일 출처(SSOT).
|
|
3
|
+
*
|
|
4
|
+
* 수동 업데이트(`agentrunner update`)와 자동 업데이트가 같은 판정을 쓰도록 여기로 추출했다.
|
|
5
|
+
* 자동 업데이트는 이 분류 결과를 서버에도 보고하므로, 문구가 아니라 `reason` 코드가 계약이다.
|
|
6
|
+
*/
|
|
7
|
+
export type InstallFailureReason = 'PERMISSION_DENIED' | 'UNKNOWN';
|
|
8
|
+
export declare const classifyInstallError: (error: unknown) => InstallFailureReason;
|
|
9
|
+
/** 사용자에게 보여줄 설치 실패 메시지. 권한 실패는 조치 방법을 담은 고정 문구를 쓴다. */
|
|
10
|
+
export declare const describeInstallError: (error: unknown) => string;
|
|
11
|
+
/** 설치 실패를 사용자용 문구로 정규화한 Error로 바꾼다. */
|
|
12
|
+
export declare const normalizeInstallError: (error: unknown) => Error;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const PERMISSION_DENIED_MESSAGE = 'Global npm install requires elevated permissions. Configure a user-level npm prefix or rerun the update with appropriate permissions.';
|
|
2
|
+
export const classifyInstallError = (error) => {
|
|
3
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4
|
+
if (message.includes('EACCES') || message.includes('EPERM') || message.toLowerCase().includes('permission denied')) {
|
|
5
|
+
return 'PERMISSION_DENIED';
|
|
6
|
+
}
|
|
7
|
+
return 'UNKNOWN';
|
|
8
|
+
};
|
|
9
|
+
/** 사용자에게 보여줄 설치 실패 메시지. 권한 실패는 조치 방법을 담은 고정 문구를 쓴다. */
|
|
10
|
+
export const describeInstallError = (error) => {
|
|
11
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12
|
+
if (classifyInstallError(error) === 'PERMISSION_DENIED') {
|
|
13
|
+
return PERMISSION_DENIED_MESSAGE;
|
|
14
|
+
}
|
|
15
|
+
return `Failed to install the latest AgentRunner package: ${message}`;
|
|
16
|
+
};
|
|
17
|
+
/** 설치 실패를 사용자용 문구로 정규화한 Error로 바꾼다. */
|
|
18
|
+
export const normalizeInstallError = (error) => new Error(describeInstallError(error));
|
|
19
|
+
//# sourceMappingURL=npm-install-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm-install-error.js","sourceRoot":"","sources":["../../src/utils/npm-install-error.ts"],"names":[],"mappings":"AAQA,MAAM,yBAAyB,GAC7B,uIAAuI,CAAC;AAE1I,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAc,EAAwB,EAAE;IAC3E,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEvE,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACnH,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,uDAAuD;AACvD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAc,EAAU,EAAE;IAC7D,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEvE,IAAI,oBAAoB,CAAC,KAAK,CAAC,KAAK,mBAAmB,EAAE,CAAC;QACxD,OAAO,yBAAyB,CAAC;IACnC,CAAC;IAED,OAAO,qDAAqD,OAAO,EAAE,CAAC;AACxE,CAAC,CAAC;AAEF,uCAAuC;AACvC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAc,EAAS,EAAE,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|