@agentteams/runner 0.0.114 → 0.0.116

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 (35) hide show
  1. package/dist/api-client.d.ts +1 -0
  2. package/dist/api-client.js +13 -0
  3. package/dist/api-client.js.map +1 -1
  4. package/dist/commands/update.js +1 -7
  5. package/dist/commands/update.js.map +1 -1
  6. package/dist/poller.d.ts +2 -1
  7. package/dist/poller.js +22 -2
  8. package/dist/poller.js.map +1 -1
  9. package/dist/poller.test.js +70 -1
  10. package/dist/poller.test.js.map +1 -1
  11. package/dist/utils/auto-update.d.ts +17 -2
  12. package/dist/utils/auto-update.js +165 -52
  13. package/dist/utils/auto-update.js.map +1 -1
  14. package/dist/utils/auto-update.test.js +357 -7
  15. package/dist/utils/auto-update.test.js.map +1 -1
  16. package/dist/utils/model-enumerator.d.ts +7 -0
  17. package/dist/utils/model-enumerator.js +72 -12
  18. package/dist/utils/model-enumerator.js.map +1 -1
  19. package/dist/utils/model-enumerator.test.js +72 -1
  20. package/dist/utils/model-enumerator.test.js.map +1 -1
  21. package/dist/utils/npm-global-permission.d.ts +18 -0
  22. package/dist/utils/npm-global-permission.js +41 -0
  23. package/dist/utils/npm-global-permission.js.map +1 -0
  24. package/dist/utils/npm-global-permission.test.d.ts +1 -0
  25. package/dist/utils/npm-global-permission.test.js +75 -0
  26. package/dist/utils/npm-global-permission.test.js.map +1 -0
  27. package/dist/utils/npm-install-error.d.ts +12 -0
  28. package/dist/utils/npm-install-error.js +19 -0
  29. package/dist/utils/npm-install-error.js.map +1 -0
  30. package/dist/utils/npm-install-error.test.d.ts +1 -0
  31. package/dist/utils/npm-install-error.test.js +28 -0
  32. package/dist/utils/npm-install-error.test.js.map +1 -0
  33. package/native/bin/win32-x64/agentrunner-launcher.exe +0 -0
  34. package/native/bin/win32-x64/manifest.json +2 -2
  35. package/package.json +1 -1
@@ -2,7 +2,7 @@ import assert from 'node:assert/strict';
2
2
  import { readFile } from 'node:fs/promises';
3
3
  import { describe, test } from 'node:test';
4
4
  import { fileURLToPath } from 'node:url';
5
- import { enumerateModels, parseCursorModels, parseGrokModels, parseKiroModels, parseLineModels, parseOpenCodeVerboseModels, } from './model-enumerator.js';
5
+ import { enumerateModels, executeModelEnumerationCommand, parseCursorModels, parseGrokModels, parseKiroModels, parseLineModels, parseOpenCodeVerboseModels, sanitizeErrorOutput, } from './model-enumerator.js';
6
6
  const fixture = (name) => readFile(fileURLToPath(new URL(`../runners/fixtures/${name}`, import.meta.url)), 'utf8');
7
7
  describe('model enumerator parsers', () => {
8
8
  test('parses OpenCode labels and context limits while allowing a missing context', async () => {
@@ -128,5 +128,76 @@ describe('enumerateModels', () => {
128
128
  assert.deepEqual(result, { status: 'UNSUPPORTED' });
129
129
  assert.equal(called, false);
130
130
  });
131
+ test('enumerates ANTIGRAVITY models with tab parser', async () => {
132
+ const calls = [];
133
+ const result = await enumerateModels('ANTIGRAVITY', dependencies(async (_executable, args) => {
134
+ calls.push(args);
135
+ return { stdout: 'gemini-3.7-flash-high\tGemini 3.7 Flash (High)\n' };
136
+ }));
137
+ assert.deepEqual(calls, [['models']]);
138
+ assert.deepEqual(result, {
139
+ status: 'SUCCESS',
140
+ values: [{ value: 'gemini-3.7-flash-high', label: 'Gemini 3.7 Flash (High)' }],
141
+ });
142
+ });
143
+ });
144
+ describe('sanitizeErrorOutput', () => {
145
+ test('redacts sensitive credentials and JWTs from error output', () => {
146
+ const raw = 'Error: Bearer secret-token-123 failed with api_key: key-456 cookie: sess=abc eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMifQ.xyz';
147
+ const sanitized = sanitizeErrorOutput(raw);
148
+ assert.equal(sanitized, 'Error: Bearer [REDACTED] failed with api_key: [REDACTED] cookie: [REDACTED] [REDACTED_JWT]');
149
+ });
150
+ test('truncates error output exceeding max length', () => {
151
+ const longString = 'x'.repeat(600);
152
+ const sanitized = sanitizeErrorOutput(longString);
153
+ assert.equal(sanitized.length, 503);
154
+ assert.ok(sanitized.endsWith('...'));
155
+ });
156
+ test('returns empty string for blank input', () => {
157
+ assert.equal(sanitizeErrorOutput(''), '');
158
+ assert.equal(sanitizeErrorOutput(' \n '), '');
159
+ });
160
+ });
161
+ describe('executeModelEnumerationCommand', () => {
162
+ test('executes command with ignored stdin so process does not hang on stdin', async () => {
163
+ const res = await executeModelEnumerationCommand(process.execPath, [
164
+ '-e',
165
+ 'let receivedData = false; process.stdin.on("data", () => { receivedData = true; }); process.stdin.on("end", () => { console.log(receivedData ? "data" : "no-data-eof"); }); process.stdin.resume();',
166
+ ]);
167
+ assert.equal(res.stdout.trim(), 'no-data-eof');
168
+ });
169
+ test('captures and sanitizes stderr on non-zero exit code', async () => {
170
+ await assert.rejects(async () => {
171
+ await executeModelEnumerationCommand(process.execPath, [
172
+ '-e',
173
+ 'console.error("fatal error: Bearer secret-token-abc"); process.exit(1);',
174
+ ]);
175
+ }, (err) => {
176
+ assert.ok(err.message.includes('Command failed (exit code 1)'));
177
+ assert.ok(err.message.includes('Bearer [REDACTED]'));
178
+ assert.ok(!err.message.includes('secret-token-abc'));
179
+ return true;
180
+ });
181
+ });
182
+ test('enforces timeout and kills hanging processes', async () => {
183
+ await assert.rejects(async () => {
184
+ await executeModelEnumerationCommand(process.execPath, ['-e', 'setInterval(() => {}, 1000);'], {
185
+ timeoutMs: 100,
186
+ });
187
+ }, (err) => {
188
+ assert.ok(err.message.includes('Command timed out after 100ms'));
189
+ return true;
190
+ });
191
+ });
192
+ test('enforces stdout maxBuffer limit', async () => {
193
+ await assert.rejects(async () => {
194
+ await executeModelEnumerationCommand(process.execPath, ['-e', 'console.log("x".repeat(1000));'], {
195
+ maxBufferBytes: 100,
196
+ });
197
+ }, (err) => {
198
+ assert.ok(err.message.includes('stdout maxBuffer exceeded'));
199
+ return true;
200
+ });
201
+ });
131
202
  });
132
203
  //# sourceMappingURL=model-enumerator.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-enumerator.test.js","sourceRoot":"","sources":["../../src/utils/model-enumerator.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"model-enumerator.test.js","sourceRoot":"","sources":["../../src/utils/model-enumerator.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 {};
@@ -0,0 +1,28 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { classifyInstallError, describeInstallError, normalizeInstallError } from './npm-install-error.js';
4
+ test('classifyInstallError detects permission failures from real npm output', () => {
5
+ const eacces = new Error([
6
+ 'Command failed: /usr/bin/npm install -g @agentteams/runner@0.0.114',
7
+ 'npm ERR! code EACCES',
8
+ 'npm ERR! syscall rename',
9
+ 'npm ERR! errno -13',
10
+ ].join('\n'));
11
+ assert.equal(classifyInstallError(eacces), 'PERMISSION_DENIED');
12
+ assert.equal(classifyInstallError(new Error('npm ERR! code EPERM')), 'PERMISSION_DENIED');
13
+ assert.equal(classifyInstallError(new Error('sh: Permission denied')), 'PERMISSION_DENIED');
14
+ });
15
+ test('classifyInstallError falls back to UNKNOWN for other failures', () => {
16
+ assert.equal(classifyInstallError(new Error('network unavailable')), 'UNKNOWN');
17
+ assert.equal(classifyInstallError('ETARGET no matching version'), 'UNKNOWN');
18
+ });
19
+ test('describeInstallError keeps the remediation wording for permission failures', () => {
20
+ assert.match(describeInstallError(new Error('npm ERR! code EACCES')), /elevated permissions/);
21
+ assert.match(describeInstallError(new Error('network unavailable')), /Failed to install the latest AgentRunner/);
22
+ });
23
+ test('normalizeInstallError returns an Error carrying the described message', () => {
24
+ const normalized = normalizeInstallError(new Error('npm ERR! code EACCES'));
25
+ assert.ok(normalized instanceof Error);
26
+ assert.equal(normalized.message, describeInstallError(new Error('npm ERR! code EACCES')));
27
+ });
28
+ //# sourceMappingURL=npm-install-error.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npm-install-error.test.js","sourceRoot":"","sources":["../../src/utils/npm-install-error.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE3G,IAAI,CAAC,uEAAuE,EAAE,GAAG,EAAE;IACjF,MAAM,MAAM,GAAG,IAAI,KAAK,CACtB;QACE,oEAAoE;QACpE,sBAAsB;QACtB,yBAAyB;QACzB,oBAAoB;KACrB,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,MAAM,CAAC,EAAE,mBAAmB,CAAC,CAAC;IAChE,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC;IAC1F,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC;AAC9F,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,+DAA+D,EAAE,GAAG,EAAE;IACzE,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAChF,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,6BAA6B,CAAC,EAAE,SAAS,CAAC,CAAC;AAC/E,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4EAA4E,EAAE,GAAG,EAAE;IACtF,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC;IAC9F,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,EAAE,0CAA0C,CAAC,CAAC;AACnH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,uEAAuE,EAAE,GAAG,EAAE;IACjF,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAC5E,MAAM,CAAC,EAAE,CAAC,UAAU,YAAY,KAAK,CAAC,CAAC;IACvC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,oBAAoB,CAAC,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;AAC5F,CAAC,CAAC,CAAC"}
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.0.114",
3
+ "version": "0.0.116",
4
4
  "platform": "win32",
5
5
  "arch": "x64",
6
6
  "fileName": "agentrunner-launcher.exe",
7
- "sha256": "57d5ee98e3f5a8cda9798b9b03e2fcd2c27cd1b86c6ce1a2226405eb4fe40b96"
7
+ "sha256": "c809675b68b9dc8ff8a871d89f69a1b01a0bee0d4b2f9de2ee5691079dafd6c6"
8
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentteams/runner",
3
- "version": "0.0.114",
3
+ "version": "0.0.116",
4
4
  "description": "AgentRunner - Background runner that polls and executes AI agent tasks",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",