@agentteams/runner 0.0.85 → 0.0.86
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 +2 -2
- package/dist/api-client.js +66 -66
- package/dist/api-client.js.map +1 -1
- package/dist/api-client.test.js +63 -54
- package/dist/api-client.test.js.map +1 -1
- package/dist/autostart.js +81 -81
- package/dist/autostart.js.map +1 -1
- package/dist/autostart.test.js +35 -35
- package/dist/autostart.test.js.map +1 -1
- package/dist/commands/cleanup.js +4 -4
- package/dist/commands/init.js +14 -14
- package/dist/commands/restart.js +3 -3
- package/dist/commands/start.js +10 -10
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.js +7 -7
- package/dist/commands/stop.js +7 -7
- package/dist/commands/uninstall.js +6 -6
- package/dist/commands/update.d.ts +4 -4
- package/dist/commands/update.js +20 -22
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/update.test.js +38 -42
- package/dist/commands/update.test.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +12 -12
- package/dist/config.test.js +61 -61
- package/dist/config.test.js.map +1 -1
- package/dist/daemon-control.d.ts +5 -5
- package/dist/daemon-control.js +21 -22
- package/dist/daemon-control.js.map +1 -1
- package/dist/daemon-control.test.js +29 -29
- package/dist/executable.d.ts +3 -3
- package/dist/executable.js +46 -49
- package/dist/executable.js.map +1 -1
- package/dist/executable.test.js +62 -62
- package/dist/executable.test.js.map +1 -1
- package/dist/handlers/trigger-handler.d.ts +6 -6
- package/dist/handlers/trigger-handler.js +118 -124
- package/dist/handlers/trigger-handler.js.map +1 -1
- package/dist/handlers/trigger-handler.test.js +373 -365
- package/dist/handlers/trigger-handler.test.js.map +1 -1
- package/dist/index.js +25 -25
- package/dist/logger.js +1 -1
- package/dist/pid.js +6 -6
- package/dist/poller.d.ts +7 -7
- package/dist/poller.js +55 -54
- package/dist/poller.js.map +1 -1
- package/dist/poller.test.js +264 -180
- package/dist/poller.test.js.map +1 -1
- package/dist/runners/amp.d.ts +1 -1
- package/dist/runners/amp.js +74 -81
- package/dist/runners/amp.js.map +1 -1
- package/dist/runners/antigravity.d.ts +3 -3
- package/dist/runners/antigravity.js +116 -127
- package/dist/runners/antigravity.js.map +1 -1
- package/dist/runners/antigravity.replay.test.js +25 -25
- package/dist/runners/antigravity.replay.test.js.map +1 -1
- package/dist/runners/antigravity.test.js +98 -98
- package/dist/runners/antigravity.test.js.map +1 -1
- package/dist/runners/claude-code.d.ts +1 -1
- package/dist/runners/claude-code.js +85 -84
- package/dist/runners/claude-code.js.map +1 -1
- package/dist/runners/claude-code.test.js +37 -40
- package/dist/runners/claude-code.test.js.map +1 -1
- package/dist/runners/codex.d.ts +1 -1
- package/dist/runners/codex.js +87 -96
- package/dist/runners/codex.js.map +1 -1
- package/dist/runners/codex.test.js +68 -68
- package/dist/runners/codex.test.js.map +1 -1
- package/dist/runners/index.d.ts +1 -1
- package/dist/runners/index.js +10 -10
- package/dist/runners/index.test.js +16 -16
- package/dist/runners/log-reporter.d.ts +2 -2
- package/dist/runners/log-reporter.js +10 -10
- package/dist/runners/log-reporter.test.js +70 -70
- package/dist/runners/log-reporter.test.js.map +1 -1
- package/dist/runners/opencode.d.ts +1 -1
- package/dist/runners/opencode.js +68 -75
- package/dist/runners/opencode.js.map +1 -1
- package/dist/runners/process-control.d.ts +1 -1
- package/dist/runners/process-control.js +13 -11
- package/dist/runners/process-control.js.map +1 -1
- package/dist/runners/stream-json-parser.d.ts +1 -1
- package/dist/runners/stream-json-parser.js +70 -67
- package/dist/runners/stream-json-parser.js.map +1 -1
- package/dist/runners/stream-json-parser.replay.test.js +17 -17
- package/dist/runners/stream-json-parser.replay.test.js.map +1 -1
- package/dist/runners/stream-json-parser.test.js +76 -78
- package/dist/runners/stream-json-parser.test.js.map +1 -1
- package/dist/types.d.ts +4 -4
- package/dist/utils/auth-path-store.js +7 -7
- package/dist/utils/auth-path-store.test.js +24 -29
- package/dist/utils/auth-path-store.test.js.map +1 -1
- package/dist/utils/auto-update.d.ts +4 -4
- package/dist/utils/auto-update.js +30 -28
- package/dist/utils/auto-update.js.map +1 -1
- package/dist/utils/auto-update.test.js +30 -30
- package/dist/utils/convention-evaluator.d.ts +1 -1
- package/dist/utils/convention-evaluator.js +22 -21
- package/dist/utils/convention-evaluator.js.map +1 -1
- package/dist/utils/convention-evaluator.test.js +120 -110
- package/dist/utils/convention-evaluator.test.js.map +1 -1
- package/dist/utils/convention-sync.d.ts +3 -3
- package/dist/utils/convention-sync.js +86 -18
- package/dist/utils/convention-sync.js.map +1 -1
- package/dist/utils/convention-sync.test.js +122 -30
- package/dist/utils/convention-sync.test.js.map +1 -1
- package/dist/utils/git-worktree.js +20 -18
- package/dist/utils/git-worktree.js.map +1 -1
- package/dist/utils/git-worktree.test.js +98 -98
- package/dist/utils/git-worktree.test.js.map +1 -1
- package/dist/utils/origin-issue-safeguard.js +35 -30
- package/dist/utils/origin-issue-safeguard.js.map +1 -1
- package/dist/utils/power-save-blocker.d.ts +4 -4
- package/dist/utils/power-save-blocker.js +33 -33
- package/dist/utils/power-save-blocker.test.js +37 -37
- package/dist/utils/power-save-blocker.test.js.map +1 -1
- package/dist/utils/runner-cleanup.d.ts +3 -3
- package/dist/utils/runner-cleanup.js +13 -13
- package/dist/utils/runner-cleanup.test.js +35 -35
- package/dist/utils/runner-history.js +3 -3
- package/dist/utils/runner-history.test.js +17 -17
- package/package.json +4 -1
- package/readme.md +10 -10
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { execFileSync, spawn } from
|
|
2
|
-
import { platform as osPlatform } from
|
|
3
|
-
import { logger } from
|
|
1
|
+
import { execFileSync, spawn } from 'node:child_process';
|
|
2
|
+
import { platform as osPlatform } from 'node:os';
|
|
3
|
+
import { logger } from '../logger.js';
|
|
4
4
|
// launchd 환경에서는 PATH가 비어 있을 수 있으므로 macOS 시스템 바이너리는 절대 경로로 호출한다.
|
|
5
|
-
const CAFFEINATE_PATH =
|
|
6
|
-
const PMSET_PATH =
|
|
5
|
+
const CAFFEINATE_PATH = '/usr/bin/caffeinate';
|
|
6
|
+
const PMSET_PATH = '/usr/bin/pmset';
|
|
7
7
|
// -i: 시스템 idle 절전 방지, -m: 디스크 idle 절전 방지, -s: 시스템 절전 방지(AC 전원에서만 유효)
|
|
8
|
-
const DEFAULT_CAFFEINATE_ARGS = [
|
|
8
|
+
const DEFAULT_CAFFEINATE_ARGS = ['-i', '-m', '-s'];
|
|
9
9
|
// 실행 도중 배터리로 전환되는 경우를 감지하기 위한 전원 상태 재확인 주기
|
|
10
10
|
const DEFAULT_POWER_RECHECK_INTERVAL_MS = 30_000;
|
|
11
11
|
// `pmset -g batt`의 첫 줄은 "Now drawing from 'AC Power'" 또는 "Now drawing from 'Battery Power'" 형태다.
|
|
12
12
|
export const parsePowerSource = (output) => {
|
|
13
13
|
const match = output.match(/Now drawing from '([^']+)'/i);
|
|
14
14
|
if (!match) {
|
|
15
|
-
return
|
|
15
|
+
return 'UNKNOWN';
|
|
16
16
|
}
|
|
17
17
|
const source = match[1].toLowerCase();
|
|
18
|
-
if (source.includes(
|
|
19
|
-
return
|
|
18
|
+
if (source.includes('ac')) {
|
|
19
|
+
return 'AC';
|
|
20
20
|
}
|
|
21
|
-
if (source.includes(
|
|
22
|
-
return
|
|
21
|
+
if (source.includes('battery')) {
|
|
22
|
+
return 'BATTERY';
|
|
23
23
|
}
|
|
24
|
-
return
|
|
24
|
+
return 'UNKNOWN';
|
|
25
25
|
};
|
|
26
26
|
const noopRelease = () => { };
|
|
27
27
|
export const createPowerSaveBlocker = (deps = {}) => {
|
|
@@ -34,20 +34,20 @@ export const createPowerSaveBlocker = (deps = {}) => {
|
|
|
34
34
|
const recheckIntervalMs = deps.recheckIntervalMs ?? DEFAULT_POWER_RECHECK_INTERVAL_MS;
|
|
35
35
|
const caffeinateArgs = deps.caffeinateArgs ?? DEFAULT_CAFFEINATE_ARGS;
|
|
36
36
|
// 기능 토글이 꺼져 있거나 macOS가 아니면 전부 no-op으로 동작한다.
|
|
37
|
-
const supported = (deps.enabled ?? true) && platform() ===
|
|
37
|
+
const supported = (deps.enabled ?? true) && platform() === 'darwin';
|
|
38
38
|
let activeSessions = 0;
|
|
39
39
|
let caffeinate = null;
|
|
40
40
|
let monitorInterval = null;
|
|
41
41
|
const readPowerSource = () => {
|
|
42
42
|
try {
|
|
43
|
-
const output = String(execFileSyncFn(PMSET_PATH, [
|
|
43
|
+
const output = String(execFileSyncFn(PMSET_PATH, ['-g', 'batt'], { encoding: 'utf8' }));
|
|
44
44
|
return parsePowerSource(output);
|
|
45
45
|
}
|
|
46
46
|
catch (error) {
|
|
47
|
-
log.warn(
|
|
48
|
-
error: error instanceof Error ? error.message : String(error)
|
|
47
|
+
log.warn('Failed to read power source via pmset', {
|
|
48
|
+
error: error instanceof Error ? error.message : String(error),
|
|
49
49
|
});
|
|
50
|
-
return
|
|
50
|
+
return 'UNKNOWN';
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
const startCaffeinate = () => {
|
|
@@ -55,26 +55,26 @@ export const createPowerSaveBlocker = (deps = {}) => {
|
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
try {
|
|
58
|
-
const child = spawnFn(CAFFEINATE_PATH, caffeinateArgs, { stdio:
|
|
59
|
-
child.on(
|
|
60
|
-
log.warn(
|
|
61
|
-
error: error instanceof Error ? error.message : String(error)
|
|
58
|
+
const child = spawnFn(CAFFEINATE_PATH, caffeinateArgs, { stdio: 'ignore' });
|
|
59
|
+
child.on('error', (error) => {
|
|
60
|
+
log.warn('caffeinate process failed', {
|
|
61
|
+
error: error instanceof Error ? error.message : String(error),
|
|
62
62
|
});
|
|
63
63
|
if (caffeinate === child) {
|
|
64
64
|
caffeinate = null;
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
|
-
child.on(
|
|
67
|
+
child.on('exit', () => {
|
|
68
68
|
if (caffeinate === child) {
|
|
69
69
|
caffeinate = null;
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
caffeinate = child;
|
|
73
|
-
log.info(
|
|
73
|
+
log.info('Sleep prevention started', { pid: child.pid ?? null, args: caffeinateArgs });
|
|
74
74
|
}
|
|
75
75
|
catch (error) {
|
|
76
|
-
log.warn(
|
|
77
|
-
error: error instanceof Error ? error.message : String(error)
|
|
76
|
+
log.warn('Failed to start caffeinate', {
|
|
77
|
+
error: error instanceof Error ? error.message : String(error),
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
};
|
|
@@ -85,12 +85,12 @@ export const createPowerSaveBlocker = (deps = {}) => {
|
|
|
85
85
|
const child = caffeinate;
|
|
86
86
|
caffeinate = null;
|
|
87
87
|
try {
|
|
88
|
-
child.kill(
|
|
88
|
+
child.kill('SIGTERM');
|
|
89
89
|
}
|
|
90
90
|
catch {
|
|
91
91
|
// 이미 종료되었거나 종료할 수 없는 경우 무시한다.
|
|
92
92
|
}
|
|
93
|
-
log.info(
|
|
93
|
+
log.info('Sleep prevention stopped', { reason });
|
|
94
94
|
};
|
|
95
95
|
// 의도한 상태(세션 존재 && AC 전원)와 실제 caffeinate 실행 여부를 일치시킨다.
|
|
96
96
|
const reconcile = () => {
|
|
@@ -98,15 +98,15 @@ export const createPowerSaveBlocker = (deps = {}) => {
|
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
100
|
if (activeSessions <= 0) {
|
|
101
|
-
stopCaffeinate(
|
|
101
|
+
stopCaffeinate('no-active-sessions');
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
104
|
const source = readPowerSource();
|
|
105
|
-
if (source ===
|
|
105
|
+
if (source === 'AC') {
|
|
106
106
|
startCaffeinate();
|
|
107
107
|
}
|
|
108
108
|
else {
|
|
109
|
-
stopCaffeinate(source ===
|
|
109
|
+
stopCaffeinate(source === 'BATTERY' ? 'on-battery' : 'power-source-unknown');
|
|
110
110
|
}
|
|
111
111
|
};
|
|
112
112
|
const startMonitor = () => {
|
|
@@ -115,7 +115,7 @@ export const createPowerSaveBlocker = (deps = {}) => {
|
|
|
115
115
|
}
|
|
116
116
|
monitorInterval = setIntervalFn(() => reconcile(), recheckIntervalMs);
|
|
117
117
|
// 절전 방지 모니터가 데몬 종료를 막지 않도록 unref 처리한다.
|
|
118
|
-
if (typeof monitorInterval.unref ===
|
|
118
|
+
if (typeof monitorInterval.unref === 'function') {
|
|
119
119
|
monitorInterval.unref();
|
|
120
120
|
}
|
|
121
121
|
};
|
|
@@ -132,8 +132,8 @@ export const createPowerSaveBlocker = (deps = {}) => {
|
|
|
132
132
|
}
|
|
133
133
|
activeSessions += 1;
|
|
134
134
|
const source = readPowerSource();
|
|
135
|
-
if (source !==
|
|
136
|
-
log.info(
|
|
135
|
+
if (source !== 'AC') {
|
|
136
|
+
log.info('Sleep prevention skipped while on battery or unknown power', { source, label: label ?? null });
|
|
137
137
|
}
|
|
138
138
|
reconcile();
|
|
139
139
|
startMonitor();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import assert from
|
|
2
|
-
import { EventEmitter } from
|
|
3
|
-
import test from
|
|
4
|
-
import { createPowerSaveBlocker, parsePowerSource } from
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
import test from 'node:test';
|
|
4
|
+
import { createPowerSaveBlocker, parsePowerSource } from './power-save-blocker.js';
|
|
5
5
|
const AC_OUTPUT = "Now drawing from 'AC Power'\n -InternalBattery-0 (id=123)\t100%; charged; 0:00 remaining present: true";
|
|
6
6
|
const BATTERY_OUTPUT = "Now drawing from 'Battery Power'\n -InternalBattery-0 (id=123)\t80%; discharging; 3:20 remaining present: true";
|
|
7
7
|
const createFakeChild = (pid) => {
|
|
@@ -16,59 +16,59 @@ const createFakeChild = (pid) => {
|
|
|
16
16
|
};
|
|
17
17
|
const silentLogger = {
|
|
18
18
|
info: () => undefined,
|
|
19
|
-
warn: () => undefined
|
|
19
|
+
warn: () => undefined,
|
|
20
20
|
};
|
|
21
21
|
// setInterval/clearInterval를 주입해 모니터 루프가 실제 타이머를 만들지 않게 한다.
|
|
22
22
|
const noopTimers = {
|
|
23
23
|
setInterval: (() => ({ unref: () => undefined })),
|
|
24
|
-
clearInterval: (() => undefined)
|
|
24
|
+
clearInterval: (() => undefined),
|
|
25
25
|
};
|
|
26
|
-
test(
|
|
27
|
-
assert.equal(parsePowerSource(AC_OUTPUT),
|
|
28
|
-
assert.equal(parsePowerSource(BATTERY_OUTPUT),
|
|
29
|
-
assert.equal(parsePowerSource(
|
|
26
|
+
test('parsePowerSource detects AC, battery, and unknown sources', () => {
|
|
27
|
+
assert.equal(parsePowerSource(AC_OUTPUT), 'AC');
|
|
28
|
+
assert.equal(parsePowerSource(BATTERY_OUTPUT), 'BATTERY');
|
|
29
|
+
assert.equal(parsePowerSource('garbage output'), 'UNKNOWN');
|
|
30
30
|
});
|
|
31
|
-
test(
|
|
31
|
+
test('acquire spawns caffeinate on macOS while on AC power', () => {
|
|
32
32
|
const spawned = [];
|
|
33
33
|
const child = createFakeChild(4242);
|
|
34
34
|
const blocker = createPowerSaveBlocker({
|
|
35
|
-
platform: () =>
|
|
35
|
+
platform: () => 'darwin',
|
|
36
36
|
execFileSync: (() => AC_OUTPUT),
|
|
37
37
|
spawn: ((command, args) => {
|
|
38
38
|
spawned.push({ command, args });
|
|
39
39
|
return child;
|
|
40
40
|
}),
|
|
41
41
|
logger: silentLogger,
|
|
42
|
-
...noopTimers
|
|
42
|
+
...noopTimers,
|
|
43
43
|
});
|
|
44
|
-
const release = blocker.acquire(
|
|
44
|
+
const release = blocker.acquire('trigger-1');
|
|
45
45
|
assert.equal(spawned.length, 1);
|
|
46
|
-
assert.equal(spawned[0]?.command,
|
|
47
|
-
assert.deepEqual(spawned[0]?.args, [
|
|
46
|
+
assert.equal(spawned[0]?.command, '/usr/bin/caffeinate');
|
|
47
|
+
assert.deepEqual(spawned[0]?.args, ['-i', '-m', '-s']);
|
|
48
48
|
release();
|
|
49
49
|
assert.equal(child.killed, true);
|
|
50
50
|
});
|
|
51
|
-
test(
|
|
51
|
+
test('acquire is a no-op while on battery power', () => {
|
|
52
52
|
let spawnCalls = 0;
|
|
53
53
|
const blocker = createPowerSaveBlocker({
|
|
54
|
-
platform: () =>
|
|
54
|
+
platform: () => 'darwin',
|
|
55
55
|
execFileSync: (() => BATTERY_OUTPUT),
|
|
56
56
|
spawn: (() => {
|
|
57
57
|
spawnCalls += 1;
|
|
58
58
|
return createFakeChild(1);
|
|
59
59
|
}),
|
|
60
60
|
logger: silentLogger,
|
|
61
|
-
...noopTimers
|
|
61
|
+
...noopTimers,
|
|
62
62
|
});
|
|
63
63
|
const release = blocker.acquire();
|
|
64
64
|
assert.equal(spawnCalls, 0);
|
|
65
65
|
release();
|
|
66
66
|
});
|
|
67
|
-
test(
|
|
67
|
+
test('acquire is a no-op on non-macOS platforms', () => {
|
|
68
68
|
let spawnCalls = 0;
|
|
69
69
|
let pmsetCalls = 0;
|
|
70
70
|
const blocker = createPowerSaveBlocker({
|
|
71
|
-
platform: () =>
|
|
71
|
+
platform: () => 'linux',
|
|
72
72
|
execFileSync: (() => {
|
|
73
73
|
pmsetCalls += 1;
|
|
74
74
|
return AC_OUTPUT;
|
|
@@ -78,17 +78,17 @@ test("acquire is a no-op on non-macOS platforms", () => {
|
|
|
78
78
|
return createFakeChild(1);
|
|
79
79
|
}),
|
|
80
80
|
logger: silentLogger,
|
|
81
|
-
...noopTimers
|
|
81
|
+
...noopTimers,
|
|
82
82
|
});
|
|
83
83
|
const release = blocker.acquire();
|
|
84
84
|
assert.equal(spawnCalls, 0);
|
|
85
85
|
assert.equal(pmsetCalls, 0);
|
|
86
86
|
release();
|
|
87
87
|
});
|
|
88
|
-
test(
|
|
88
|
+
test('acquire is a no-op when the feature is disabled', () => {
|
|
89
89
|
let spawnCalls = 0;
|
|
90
90
|
const blocker = createPowerSaveBlocker({
|
|
91
|
-
platform: () =>
|
|
91
|
+
platform: () => 'darwin',
|
|
92
92
|
enabled: false,
|
|
93
93
|
execFileSync: (() => AC_OUTPUT),
|
|
94
94
|
spawn: (() => {
|
|
@@ -96,12 +96,12 @@ test("acquire is a no-op when the feature is disabled", () => {
|
|
|
96
96
|
return createFakeChild(1);
|
|
97
97
|
}),
|
|
98
98
|
logger: silentLogger,
|
|
99
|
-
...noopTimers
|
|
99
|
+
...noopTimers,
|
|
100
100
|
});
|
|
101
101
|
blocker.acquire()();
|
|
102
102
|
assert.equal(spawnCalls, 0);
|
|
103
103
|
});
|
|
104
|
-
test(
|
|
104
|
+
test('release can be called multiple times without killing twice', () => {
|
|
105
105
|
let killCount = 0;
|
|
106
106
|
const child = createFakeChild(7);
|
|
107
107
|
child.kill = () => {
|
|
@@ -110,11 +110,11 @@ test("release can be called multiple times without killing twice", () => {
|
|
|
110
110
|
return true;
|
|
111
111
|
};
|
|
112
112
|
const blocker = createPowerSaveBlocker({
|
|
113
|
-
platform: () =>
|
|
113
|
+
platform: () => 'darwin',
|
|
114
114
|
execFileSync: (() => AC_OUTPUT),
|
|
115
115
|
spawn: (() => child),
|
|
116
116
|
logger: silentLogger,
|
|
117
|
-
...noopTimers
|
|
117
|
+
...noopTimers,
|
|
118
118
|
});
|
|
119
119
|
const release = blocker.acquire();
|
|
120
120
|
release();
|
|
@@ -122,21 +122,21 @@ test("release can be called multiple times without killing twice", () => {
|
|
|
122
122
|
release();
|
|
123
123
|
assert.equal(killCount, 1);
|
|
124
124
|
});
|
|
125
|
-
test(
|
|
125
|
+
test('concurrent sessions keep caffeinate alive until the last release', () => {
|
|
126
126
|
let spawnCalls = 0;
|
|
127
127
|
const child = createFakeChild(9);
|
|
128
128
|
const blocker = createPowerSaveBlocker({
|
|
129
|
-
platform: () =>
|
|
129
|
+
platform: () => 'darwin',
|
|
130
130
|
execFileSync: (() => AC_OUTPUT),
|
|
131
131
|
spawn: (() => {
|
|
132
132
|
spawnCalls += 1;
|
|
133
133
|
return child;
|
|
134
134
|
}),
|
|
135
135
|
logger: silentLogger,
|
|
136
|
-
...noopTimers
|
|
136
|
+
...noopTimers,
|
|
137
137
|
});
|
|
138
|
-
const releaseA = blocker.acquire(
|
|
139
|
-
const releaseB = blocker.acquire(
|
|
138
|
+
const releaseA = blocker.acquire('a');
|
|
139
|
+
const releaseB = blocker.acquire('b');
|
|
140
140
|
// 두 세션이 동일한 caffeinate 프로세스를 공유한다.
|
|
141
141
|
assert.equal(spawnCalls, 1);
|
|
142
142
|
releaseA();
|
|
@@ -144,12 +144,12 @@ test("concurrent sessions keep caffeinate alive until the last release", () => {
|
|
|
144
144
|
releaseB();
|
|
145
145
|
assert.equal(child.killed, true);
|
|
146
146
|
});
|
|
147
|
-
test(
|
|
147
|
+
test('monitor releases caffeinate when power switches to battery mid-run', () => {
|
|
148
148
|
let powerOutput = AC_OUTPUT;
|
|
149
149
|
const monitorTicks = [];
|
|
150
150
|
const child = createFakeChild(11);
|
|
151
151
|
const blocker = createPowerSaveBlocker({
|
|
152
|
-
platform: () =>
|
|
152
|
+
platform: () => 'darwin',
|
|
153
153
|
execFileSync: (() => powerOutput),
|
|
154
154
|
spawn: (() => child),
|
|
155
155
|
logger: silentLogger,
|
|
@@ -157,13 +157,13 @@ test("monitor releases caffeinate when power switches to battery mid-run", () =>
|
|
|
157
157
|
monitorTicks.push(handler);
|
|
158
158
|
return { unref: () => undefined };
|
|
159
159
|
}),
|
|
160
|
-
clearInterval: (() => undefined)
|
|
160
|
+
clearInterval: (() => undefined),
|
|
161
161
|
});
|
|
162
162
|
blocker.acquire();
|
|
163
163
|
assert.equal(child.killed, false);
|
|
164
164
|
// 배터리로 전환된 뒤 모니터가 동작하면 caffeinate가 종료되어야 한다.
|
|
165
165
|
powerOutput = BATTERY_OUTPUT;
|
|
166
|
-
assert.equal(monitorTicks.length, 1,
|
|
166
|
+
assert.equal(monitorTicks.length, 1, 'monitor interval should be registered');
|
|
167
167
|
monitorTicks[0]?.();
|
|
168
168
|
assert.equal(child.killed, true);
|
|
169
169
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"power-save-blocker.test.js","sourceRoot":"","sources":["../../src/utils/power-save-blocker.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEnF,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"power-save-blocker.test.js","sourceRoot":"","sources":["../../src/utils/power-save-blocker.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { readdir, stat, unlink } from
|
|
2
|
-
import { logger } from
|
|
1
|
+
import { readdir, stat, unlink } from 'node:fs/promises';
|
|
2
|
+
import { logger } from '../logger.js';
|
|
3
3
|
type CleanupDeps = {
|
|
4
4
|
readdir?: typeof readdir;
|
|
5
5
|
stat?: typeof stat;
|
|
6
6
|
unlink?: typeof unlink;
|
|
7
|
-
logger?: Pick<typeof logger,
|
|
7
|
+
logger?: Pick<typeof logger, 'info' | 'warn'>;
|
|
8
8
|
};
|
|
9
9
|
export declare const runCleanup: (authPath: string, deps?: CleanupDeps) => Promise<void>;
|
|
10
10
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readdir, stat, unlink } from
|
|
2
|
-
import { join } from
|
|
3
|
-
import { logger } from
|
|
1
|
+
import { readdir, stat, unlink } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { logger } from '../logger.js';
|
|
4
4
|
const LOG_TTL_MS = 6 * 60 * 60 * 1000;
|
|
5
5
|
const HISTORY_TTL_MS = 3 * 24 * 60 * 60 * 1000;
|
|
6
6
|
const purgeExpiredFiles = async (directory, ttlMs, deps) => {
|
|
@@ -10,7 +10,7 @@ const purgeExpiredFiles = async (directory, ttlMs, deps) => {
|
|
|
10
10
|
entries = await deps.readdir(directory);
|
|
11
11
|
}
|
|
12
12
|
catch (error) {
|
|
13
|
-
if (error.code ===
|
|
13
|
+
if (error.code === 'ENOENT') {
|
|
14
14
|
return 0;
|
|
15
15
|
}
|
|
16
16
|
throw error;
|
|
@@ -26,12 +26,12 @@ const purgeExpiredFiles = async (directory, ttlMs, deps) => {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
catch (error) {
|
|
29
|
-
if (error.code ===
|
|
29
|
+
if (error.code === 'ENOENT') {
|
|
30
30
|
continue;
|
|
31
31
|
}
|
|
32
|
-
deps.logger.warn(
|
|
32
|
+
deps.logger.warn('Failed to delete expired file', {
|
|
33
33
|
filePath,
|
|
34
|
-
error: error instanceof Error ? error.message : String(error)
|
|
34
|
+
error: error instanceof Error ? error.message : String(error),
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -42,18 +42,18 @@ export const runCleanup = async (authPath, deps = {}) => {
|
|
|
42
42
|
readdir: deps.readdir ?? readdir,
|
|
43
43
|
stat: deps.stat ?? stat,
|
|
44
44
|
unlink: deps.unlink ?? unlink,
|
|
45
|
-
logger: deps.logger ?? logger
|
|
45
|
+
logger: deps.logger ?? logger,
|
|
46
46
|
};
|
|
47
|
-
const logDir = join(authPath,
|
|
48
|
-
const historyDir = join(authPath,
|
|
47
|
+
const logDir = join(authPath, '.agentteams', 'runner', 'log');
|
|
48
|
+
const historyDir = join(authPath, '.agentteams', 'runner', 'history');
|
|
49
49
|
const [logDeleted, historyDeleted] = await Promise.all([
|
|
50
50
|
purgeExpiredFiles(logDir, LOG_TTL_MS, resolvedDeps),
|
|
51
|
-
purgeExpiredFiles(historyDir, HISTORY_TTL_MS, resolvedDeps)
|
|
51
|
+
purgeExpiredFiles(historyDir, HISTORY_TTL_MS, resolvedDeps),
|
|
52
52
|
]);
|
|
53
|
-
resolvedDeps.logger.info(
|
|
53
|
+
resolvedDeps.logger.info('Runner cleanup completed', {
|
|
54
54
|
authPath,
|
|
55
55
|
logDeleted,
|
|
56
|
-
historyDeleted
|
|
56
|
+
historyDeleted,
|
|
57
57
|
});
|
|
58
58
|
};
|
|
59
59
|
//# sourceMappingURL=runner-cleanup.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import assert from
|
|
2
|
-
import { mkdir, mkdtemp, rm, utimes, writeFile } from
|
|
3
|
-
import { tmpdir } from
|
|
4
|
-
import { join } from
|
|
5
|
-
import test, { mock } from
|
|
6
|
-
import { logger } from
|
|
7
|
-
import { runCleanup } from
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdir, mkdtemp, rm, utimes, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import test, { mock } from 'node:test';
|
|
6
|
+
import { logger } from '../logger.js';
|
|
7
|
+
import { runCleanup } from './runner-cleanup.js';
|
|
8
8
|
const makeAuthDir = async () => {
|
|
9
|
-
return await mkdtemp(join(tmpdir(),
|
|
9
|
+
return await mkdtemp(join(tmpdir(), 'runner-cleanup-test-'));
|
|
10
10
|
};
|
|
11
11
|
const touchAge = async (filePath, ageMs) => {
|
|
12
12
|
const target = new Date(Date.now() - ageMs);
|
|
@@ -15,7 +15,7 @@ const touchAge = async (filePath, ageMs) => {
|
|
|
15
15
|
test.afterEach(() => {
|
|
16
16
|
mock.restoreAll();
|
|
17
17
|
});
|
|
18
|
-
test(
|
|
18
|
+
test('runCleanup ignores missing log and history directories', async () => {
|
|
19
19
|
const authPath = await makeAuthDir();
|
|
20
20
|
try {
|
|
21
21
|
await runCleanup(authPath);
|
|
@@ -24,29 +24,29 @@ test("runCleanup ignores missing log and history directories", async () => {
|
|
|
24
24
|
await rm(authPath, { recursive: true, force: true });
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
|
-
test(
|
|
27
|
+
test('runCleanup deletes only files older than each directory TTL', async () => {
|
|
28
28
|
const authPath = await makeAuthDir();
|
|
29
|
-
const logDir = join(authPath,
|
|
30
|
-
const historyDir = join(authPath,
|
|
29
|
+
const logDir = join(authPath, '.agentteams', 'runner', 'log');
|
|
30
|
+
const historyDir = join(authPath, '.agentteams', 'runner', 'history');
|
|
31
31
|
try {
|
|
32
32
|
await mkdir(logDir, { recursive: true });
|
|
33
33
|
await mkdir(historyDir, { recursive: true });
|
|
34
|
-
const oldLog = join(logDir,
|
|
35
|
-
const freshLog = join(logDir,
|
|
36
|
-
const oldHistory = join(historyDir,
|
|
37
|
-
const freshHistory = join(historyDir,
|
|
38
|
-
await writeFile(oldLog,
|
|
39
|
-
await writeFile(freshLog,
|
|
40
|
-
await writeFile(oldHistory,
|
|
41
|
-
await writeFile(freshHistory,
|
|
34
|
+
const oldLog = join(logDir, 'old.log');
|
|
35
|
+
const freshLog = join(logDir, 'fresh.log');
|
|
36
|
+
const oldHistory = join(historyDir, 'old.md');
|
|
37
|
+
const freshHistory = join(historyDir, 'fresh.md');
|
|
38
|
+
await writeFile(oldLog, 'old');
|
|
39
|
+
await writeFile(freshLog, 'fresh');
|
|
40
|
+
await writeFile(oldHistory, 'old');
|
|
41
|
+
await writeFile(freshHistory, 'fresh');
|
|
42
42
|
await touchAge(oldLog, 2 * 24 * 60 * 60 * 1000);
|
|
43
43
|
await touchAge(freshLog, 3 * 60 * 60 * 1000);
|
|
44
44
|
await touchAge(oldHistory, 4 * 24 * 60 * 60 * 1000);
|
|
45
45
|
await touchAge(freshHistory, 2 * 24 * 60 * 60 * 1000);
|
|
46
46
|
await runCleanup(authPath);
|
|
47
|
-
await assert.rejects(() => import(
|
|
48
|
-
await assert.rejects(() => import(
|
|
49
|
-
await import(
|
|
47
|
+
await assert.rejects(() => import('node:fs/promises').then(({ stat }) => stat(oldLog)));
|
|
48
|
+
await assert.rejects(() => import('node:fs/promises').then(({ stat }) => stat(oldHistory)));
|
|
49
|
+
await import('node:fs/promises').then(async ({ stat }) => {
|
|
50
50
|
await stat(freshLog);
|
|
51
51
|
await stat(freshHistory);
|
|
52
52
|
});
|
|
@@ -55,33 +55,33 @@ test("runCleanup deletes only files older than each directory TTL", async () =>
|
|
|
55
55
|
await rm(authPath, { recursive: true, force: true });
|
|
56
56
|
}
|
|
57
57
|
});
|
|
58
|
-
test(
|
|
58
|
+
test('runCleanup logs a warning and continues when an expired file cannot be deleted', async () => {
|
|
59
59
|
const authPath = await makeAuthDir();
|
|
60
|
-
const logDir = join(authPath,
|
|
61
|
-
const historyDir = join(authPath,
|
|
60
|
+
const logDir = join(authPath, '.agentteams', 'runner', 'log');
|
|
61
|
+
const historyDir = join(authPath, '.agentteams', 'runner', 'history');
|
|
62
62
|
const warnings = [];
|
|
63
|
-
mock.method(logger,
|
|
63
|
+
mock.method(logger, 'warn', (message, meta) => {
|
|
64
64
|
warnings.push({ message, meta });
|
|
65
65
|
});
|
|
66
66
|
try {
|
|
67
67
|
await mkdir(logDir, { recursive: true });
|
|
68
68
|
await mkdir(historyDir, { recursive: true });
|
|
69
|
-
const lockedFile = join(logDir,
|
|
70
|
-
const historyFile = join(historyDir,
|
|
71
|
-
await writeFile(lockedFile,
|
|
72
|
-
await writeFile(historyFile,
|
|
69
|
+
const lockedFile = join(logDir, 'locked.log');
|
|
70
|
+
const historyFile = join(historyDir, 'history.md');
|
|
71
|
+
await writeFile(lockedFile, 'locked');
|
|
72
|
+
await writeFile(historyFile, 'history');
|
|
73
73
|
await touchAge(lockedFile, 2 * 24 * 60 * 60 * 1000);
|
|
74
74
|
await touchAge(historyFile, 4 * 24 * 60 * 60 * 1000);
|
|
75
75
|
await runCleanup(authPath, {
|
|
76
76
|
unlink: async (filePath) => {
|
|
77
77
|
if (filePath === lockedFile) {
|
|
78
|
-
throw new Error(
|
|
78
|
+
throw new Error('file is locked');
|
|
79
79
|
}
|
|
80
|
-
await import(
|
|
81
|
-
}
|
|
80
|
+
await import('node:fs/promises').then(async ({ unlink }) => unlink(filePath));
|
|
81
|
+
},
|
|
82
82
|
});
|
|
83
83
|
assert.equal(warnings.length >= 1, true);
|
|
84
|
-
await import(
|
|
84
|
+
await import('node:fs/promises').then(async ({ stat }) => {
|
|
85
85
|
await stat(lockedFile);
|
|
86
86
|
await assert.rejects(() => stat(historyFile));
|
|
87
87
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { join } from
|
|
2
|
-
const historyDirectory = (authPath) => join(authPath,
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
const historyDirectory = (authPath) => join(authPath, '.agentteams', 'runner', 'history');
|
|
3
3
|
const historyFilePath = (authPath, triggerId) => join(historyDirectory(authPath), `${triggerId}.md`);
|
|
4
4
|
export const resolveRunnerHistoryPaths = (authPath, triggerId, parentTriggerId) => {
|
|
5
5
|
if (!authPath) {
|
|
@@ -7,7 +7,7 @@ export const resolveRunnerHistoryPaths = (authPath, triggerId, parentTriggerId)
|
|
|
7
7
|
}
|
|
8
8
|
return {
|
|
9
9
|
currentHistoryPath: historyFilePath(authPath, triggerId),
|
|
10
|
-
parentHistoryPath: parentTriggerId ? historyFilePath(authPath, parentTriggerId) : null
|
|
10
|
+
parentHistoryPath: parentTriggerId ? historyFilePath(authPath, parentTriggerId) : null,
|
|
11
11
|
};
|
|
12
12
|
};
|
|
13
13
|
//# sourceMappingURL=runner-history.js.map
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import assert from
|
|
2
|
-
import { join } from
|
|
3
|
-
import test from
|
|
4
|
-
import { resolveRunnerHistoryPaths } from
|
|
5
|
-
test(
|
|
6
|
-
assert.deepEqual(resolveRunnerHistoryPaths(null,
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import test from 'node:test';
|
|
4
|
+
import { resolveRunnerHistoryPaths } from './runner-history.js';
|
|
5
|
+
test('resolveRunnerHistoryPaths returns null paths when authPath is missing', () => {
|
|
6
|
+
assert.deepEqual(resolveRunnerHistoryPaths(null, 'trigger-1', 'parent-1'), {
|
|
7
7
|
currentHistoryPath: null,
|
|
8
|
-
parentHistoryPath: null
|
|
8
|
+
parentHistoryPath: null,
|
|
9
9
|
});
|
|
10
10
|
});
|
|
11
|
-
test(
|
|
12
|
-
const authPath = join(
|
|
13
|
-
assert.deepEqual(resolveRunnerHistoryPaths(authPath,
|
|
14
|
-
currentHistoryPath: join(authPath,
|
|
15
|
-
parentHistoryPath: join(authPath,
|
|
11
|
+
test('resolveRunnerHistoryPaths returns current and parent history paths', () => {
|
|
12
|
+
const authPath = join('workspace', 'auth');
|
|
13
|
+
assert.deepEqual(resolveRunnerHistoryPaths(authPath, 'trigger-1', 'parent-1'), {
|
|
14
|
+
currentHistoryPath: join(authPath, '.agentteams', 'runner', 'history', 'trigger-1.md'),
|
|
15
|
+
parentHistoryPath: join(authPath, '.agentteams', 'runner', 'history', 'parent-1.md'),
|
|
16
16
|
});
|
|
17
17
|
});
|
|
18
|
-
test(
|
|
19
|
-
const authPath = join(
|
|
20
|
-
assert.deepEqual(resolveRunnerHistoryPaths(authPath,
|
|
21
|
-
currentHistoryPath: join(authPath,
|
|
22
|
-
parentHistoryPath: null
|
|
18
|
+
test('resolveRunnerHistoryPaths omits parent path when parent trigger is absent', () => {
|
|
19
|
+
const authPath = join('workspace', 'auth');
|
|
20
|
+
assert.deepEqual(resolveRunnerHistoryPaths(authPath, 'trigger-1', null), {
|
|
21
|
+
currentHistoryPath: join(authPath, '.agentteams', 'runner', 'history', 'trigger-1.md'),
|
|
22
|
+
parentHistoryPath: null,
|
|
23
23
|
});
|
|
24
24
|
});
|
|
25
25
|
//# sourceMappingURL=runner-history.test.js.map
|