@tigorhutasuhut/herdr-claude-retry 0.1.0 → 0.1.2
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/README.md +3 -3
- package/dist/accounts.d.ts +46 -0
- package/dist/accounts.js +173 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.js +137 -0
- package/dist/daemon.d.ts +37 -0
- package/dist/daemon.js +298 -0
- package/dist/format.d.ts +15 -0
- package/dist/format.js +36 -0
- package/dist/herdr.d.ts +162 -0
- package/dist/herdr.js +369 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/log.d.ts +25 -0
- package/dist/log.js +37 -0
- package/dist/monitor.d.ts +33 -0
- package/dist/monitor.js +159 -0
- package/dist/patterns.d.ts +11 -0
- package/dist/patterns.js +103 -0
- package/dist/time-parser.d.ts +14 -0
- package/dist/time-parser.js +138 -0
- package/dist/usage.d.ts +23 -0
- package/dist/usage.js +93 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -82,9 +82,9 @@ npm run verify # typecheck + test + build (publish gate)
|
|
|
82
82
|
npm run e2e # acceptance test — needs live herdr
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
The e2e test (`test/e2e/blocked-pane.e2e.ts`)
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
The e2e test (`test/e2e/blocked-pane.e2e.ts`) verifies live connectivity to the herdr socket:
|
|
86
|
+
connects, lists agents, reads all live panes (the core one-shot protocol fix), and runs a daemon
|
|
87
|
+
reconcile sweep asserting zero paneRead failures. Skips gracefully if no herdr socket is found.
|
|
88
88
|
|
|
89
89
|
## Publishing
|
|
90
90
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account discovery and pane→account resolution.
|
|
3
|
+
*
|
|
4
|
+
* Primary resolution path: UUID→jsonl glob scan across discovered config dirs.
|
|
5
|
+
* Fallback: shell PID → /proc/<pid>/environ → CLAUDE_CONFIG_DIR.
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseConfigDirFromEnviron(buf: string): string | null;
|
|
8
|
+
export interface DiscoverDeps {
|
|
9
|
+
platform?: string;
|
|
10
|
+
readdir: (path: string) => Promise<string[]>;
|
|
11
|
+
readFile: (path: string) => Promise<string>;
|
|
12
|
+
defaultDir: () => string;
|
|
13
|
+
}
|
|
14
|
+
export interface ResolveDeps {
|
|
15
|
+
platform?: string;
|
|
16
|
+
/** List /proc pids */
|
|
17
|
+
listProcPids: () => Promise<string[]>;
|
|
18
|
+
/** Read /proc/<pid>/cmdline */
|
|
19
|
+
readCmdline: (pid: string) => Promise<string>;
|
|
20
|
+
/** Read /proc/<pid>/environ */
|
|
21
|
+
readEnviron: (pid: string) => Promise<string>;
|
|
22
|
+
/** List subdirs of a directory */
|
|
23
|
+
readdir: (path: string) => Promise<string[]>;
|
|
24
|
+
/** Check if a path exists (file or dir) */
|
|
25
|
+
exists: (path: string) => Promise<boolean>;
|
|
26
|
+
defaultDir: () => string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Scan /proc for claude processes and collect their CLAUDE_CONFIG_DIR values.
|
|
30
|
+
* Returns deduplicated list including the default dir.
|
|
31
|
+
*/
|
|
32
|
+
export declare function discoverAccountDirs(deps?: Partial<DiscoverDeps>): Promise<string[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve which config dir owns a pane, given:
|
|
35
|
+
* - sessionUuid: the Claude Code session UUID from agent_session.value
|
|
36
|
+
* - shellPid: the shell PID from pane.process_info (for fallback)
|
|
37
|
+
* - accountDirs: list of discovered config dirs
|
|
38
|
+
*
|
|
39
|
+
* Tier order:
|
|
40
|
+
* 1. Sole account - return it immediately
|
|
41
|
+
* 2. UUID-to-jsonl scan: glob <configDir>/projects/<star>/<uuid>.jsonl
|
|
42
|
+
* 3. PID-to-environ: read /proc/<shellPid>/environ, extract CLAUDE_CONFIG_DIR
|
|
43
|
+
* 4. null
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveAccountDir(sessionUuid: string | null, shellPid: number | null, accountDirs: string[], deps?: Partial<ResolveDeps>): Promise<string | null>;
|
|
46
|
+
//# sourceMappingURL=accounts.d.ts.map
|
package/dist/accounts.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account discovery and pane→account resolution.
|
|
3
|
+
*
|
|
4
|
+
* Primary resolution path: UUID→jsonl glob scan across discovered config dirs.
|
|
5
|
+
* Fallback: shell PID → /proc/<pid>/environ → CLAUDE_CONFIG_DIR.
|
|
6
|
+
*/
|
|
7
|
+
export function parseConfigDirFromEnviron(buf) {
|
|
8
|
+
const entries = buf.split('\0');
|
|
9
|
+
for (const entry of entries) {
|
|
10
|
+
if (entry.startsWith('CLAUDE_CONFIG_DIR=')) {
|
|
11
|
+
const val = entry.slice('CLAUDE_CONFIG_DIR='.length);
|
|
12
|
+
return val.length > 0 ? val : null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
function defaultConfigDir() {
|
|
18
|
+
return process.env['CLAUDE_CONFIG_DIR'] ?? `${process.env['HOME'] ?? '/root'}/.claude`;
|
|
19
|
+
}
|
|
20
|
+
function defaultDiscoverDeps() {
|
|
21
|
+
return {
|
|
22
|
+
platform: process.platform,
|
|
23
|
+
readdir: async (p) => {
|
|
24
|
+
const { readdir } = await import('node:fs/promises');
|
|
25
|
+
return readdir(p);
|
|
26
|
+
},
|
|
27
|
+
readFile: async (p) => {
|
|
28
|
+
const { readFile } = await import('node:fs/promises');
|
|
29
|
+
return readFile(p, 'utf8');
|
|
30
|
+
},
|
|
31
|
+
defaultDir: defaultConfigDir,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function defaultResolveDeps() {
|
|
35
|
+
return {
|
|
36
|
+
platform: process.platform,
|
|
37
|
+
listProcPids: async () => {
|
|
38
|
+
const { readdir } = await import('node:fs/promises');
|
|
39
|
+
const entries = await readdir('/proc');
|
|
40
|
+
return entries.filter(e => /^\d+$/.test(e));
|
|
41
|
+
},
|
|
42
|
+
readCmdline: async (pid) => {
|
|
43
|
+
const { readFile } = await import('node:fs/promises');
|
|
44
|
+
return readFile(`/proc/${pid}/cmdline`, 'utf8');
|
|
45
|
+
},
|
|
46
|
+
readEnviron: async (pid) => {
|
|
47
|
+
const { readFile } = await import('node:fs/promises');
|
|
48
|
+
return readFile(`/proc/${pid}/environ`, 'utf8');
|
|
49
|
+
},
|
|
50
|
+
readdir: async (p) => {
|
|
51
|
+
const { readdir } = await import('node:fs/promises');
|
|
52
|
+
return readdir(p);
|
|
53
|
+
},
|
|
54
|
+
exists: async (p) => {
|
|
55
|
+
const { access } = await import('node:fs/promises');
|
|
56
|
+
try {
|
|
57
|
+
await access(p);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
defaultDir: defaultConfigDir,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Scan /proc for claude processes and collect their CLAUDE_CONFIG_DIR values.
|
|
69
|
+
* Returns deduplicated list including the default dir.
|
|
70
|
+
*/
|
|
71
|
+
export async function discoverAccountDirs(deps) {
|
|
72
|
+
const merged = { ...defaultDiscoverDeps(), ...deps };
|
|
73
|
+
const platform = merged.platform ?? process.platform;
|
|
74
|
+
const base = merged.defaultDir();
|
|
75
|
+
const dirs = new Set([base]);
|
|
76
|
+
if (platform !== 'linux') {
|
|
77
|
+
return [base];
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const entries = await merged.readdir('/proc');
|
|
81
|
+
const pids = entries.filter(e => /^\d+$/.test(e));
|
|
82
|
+
await Promise.all(pids.map(async (pid) => {
|
|
83
|
+
try {
|
|
84
|
+
const cmdline = await merged.readFile(`/proc/${pid}/cmdline`);
|
|
85
|
+
if (!cmdline.includes('claude'))
|
|
86
|
+
return;
|
|
87
|
+
const environ = await merged.readFile(`/proc/${pid}/environ`);
|
|
88
|
+
const dir = parseConfigDirFromEnviron(environ) ?? base;
|
|
89
|
+
dirs.add(dir);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// skip unreadable pids
|
|
93
|
+
}
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return [base];
|
|
98
|
+
}
|
|
99
|
+
return Array.from(dirs);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Resolve which config dir owns a pane, given:
|
|
103
|
+
* - sessionUuid: the Claude Code session UUID from agent_session.value
|
|
104
|
+
* - shellPid: the shell PID from pane.process_info (for fallback)
|
|
105
|
+
* - accountDirs: list of discovered config dirs
|
|
106
|
+
*
|
|
107
|
+
* Tier order:
|
|
108
|
+
* 1. Sole account - return it immediately
|
|
109
|
+
* 2. UUID-to-jsonl scan: glob <configDir>/projects/<star>/<uuid>.jsonl
|
|
110
|
+
* 3. PID-to-environ: read /proc/<shellPid>/environ, extract CLAUDE_CONFIG_DIR
|
|
111
|
+
* 4. null
|
|
112
|
+
*/
|
|
113
|
+
export async function resolveAccountDir(sessionUuid, shellPid, accountDirs, deps) {
|
|
114
|
+
const merged = { ...defaultResolveDeps(), ...deps };
|
|
115
|
+
// Tier 1: sole account
|
|
116
|
+
if (accountDirs.length === 1) {
|
|
117
|
+
return accountDirs[0];
|
|
118
|
+
}
|
|
119
|
+
if (accountDirs.length === 0) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
// Tier 2: UUID→jsonl scan
|
|
123
|
+
if (sessionUuid !== null) {
|
|
124
|
+
for (const configDir of accountDirs) {
|
|
125
|
+
try {
|
|
126
|
+
const projectsDir = `${configDir}/projects`;
|
|
127
|
+
let projects;
|
|
128
|
+
try {
|
|
129
|
+
projects = await merged.readdir(projectsDir);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
let found = false;
|
|
135
|
+
for (const project of projects) {
|
|
136
|
+
const jsonlPath = `${projectsDir}/${project}/${sessionUuid}.jsonl`;
|
|
137
|
+
try {
|
|
138
|
+
const exists = await merged.exists(jsonlPath);
|
|
139
|
+
if (exists) {
|
|
140
|
+
found = true;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// skip
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (found) {
|
|
149
|
+
return configDir;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// skip this dir
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Tier 3: PID→environ fallback
|
|
158
|
+
if (shellPid !== null) {
|
|
159
|
+
try {
|
|
160
|
+
const environ = await merged.readEnviron(String(shellPid));
|
|
161
|
+
const dir = parseConfigDirFromEnviron(environ);
|
|
162
|
+
if (dir !== null && accountDirs.includes(dir)) {
|
|
163
|
+
return dir;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// fallthrough
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Tier 4: unknown
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=accounts.js.map
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cli.ts — CLI entry point for herdr-claude-retry daemon.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* herdr-claude-retry start [options]
|
|
6
|
+
* --socket-path <path> override HERDR_SOCKET_PATH env
|
|
7
|
+
* --margin-seconds <n> default 60
|
|
8
|
+
* --sweep-interval <n> default 300 (seconds)
|
|
9
|
+
* --log-level <level> debug|info|warn|error; default info
|
|
10
|
+
* --help print usage and exit 0
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cli.ts — CLI entry point for herdr-claude-retry daemon.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* herdr-claude-retry start [options]
|
|
6
|
+
* --socket-path <path> override HERDR_SOCKET_PATH env
|
|
7
|
+
* --margin-seconds <n> default 60
|
|
8
|
+
* --sweep-interval <n> default 300 (seconds)
|
|
9
|
+
* --log-level <level> debug|info|warn|error; default info
|
|
10
|
+
* --help print usage and exit 0
|
|
11
|
+
*/
|
|
12
|
+
import { parseArgs } from 'node:util';
|
|
13
|
+
import { HerdrClient } from "./herdr.js";
|
|
14
|
+
import { runDaemon } from "./daemon.js";
|
|
15
|
+
import { makeLogger } from "./log.js";
|
|
16
|
+
import { VERSION } from "./index.js";
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Help text
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
const HELP = `
|
|
21
|
+
herdr-claude-retry v${VERSION}
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
herdr-claude-retry start [options]
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
--socket-path <path> Unix socket path (default: HERDR_SOCKET_PATH env or
|
|
28
|
+
$HOME/.config/herdr/herdr.sock)
|
|
29
|
+
--margin-seconds <n> Extra seconds after rate-limit resets before injecting
|
|
30
|
+
(default: 60)
|
|
31
|
+
--sweep-interval <n> Reconcile sweep interval in seconds (default: 300)
|
|
32
|
+
--log-level <level> Minimum log level: debug|info|warn|error (default: info)
|
|
33
|
+
--help Print this help and exit
|
|
34
|
+
|
|
35
|
+
Environment:
|
|
36
|
+
HERDR_SOCKET_PATH Default socket path if --socket-path not given
|
|
37
|
+
`.trim();
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Main
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
async function main() {
|
|
42
|
+
// Strip argv[0] (node) and argv[1] (script); grab subcommand if present
|
|
43
|
+
const rawArgs = process.argv.slice(2);
|
|
44
|
+
// Handle top-level --help before parseArgs (so it works without a subcommand)
|
|
45
|
+
if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
|
|
46
|
+
process.stdout.write(HELP + '\n');
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
// Require 'start' subcommand
|
|
50
|
+
const [subcommand, ...rest] = rawArgs;
|
|
51
|
+
if (subcommand !== 'start') {
|
|
52
|
+
process.stderr.write(`error: unknown command '${subcommand ?? ''}'. Use 'start'.\n\n${HELP}\n`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
// Parse options
|
|
56
|
+
const { values } = parseArgs({
|
|
57
|
+
args: rest,
|
|
58
|
+
options: {
|
|
59
|
+
'socket-path': { type: 'string' },
|
|
60
|
+
'margin-seconds': { type: 'string' },
|
|
61
|
+
'sweep-interval': { type: 'string' },
|
|
62
|
+
'log-level': { type: 'string' },
|
|
63
|
+
'help': { type: 'boolean' },
|
|
64
|
+
},
|
|
65
|
+
strict: true,
|
|
66
|
+
allowPositionals: false,
|
|
67
|
+
});
|
|
68
|
+
if (values['help']) {
|
|
69
|
+
process.stdout.write(HELP + '\n');
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
// Resolve log level
|
|
73
|
+
const rawLevel = values['log-level'] ?? 'info';
|
|
74
|
+
const validLevels = ['debug', 'info', 'warn', 'error'];
|
|
75
|
+
if (!validLevels.includes(rawLevel)) {
|
|
76
|
+
process.stderr.write(`error: invalid --log-level '${rawLevel}'. Must be one of: ${validLevels.join(', ')}\n`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
const logLevel = rawLevel;
|
|
80
|
+
// Construct logger
|
|
81
|
+
const logFn = makeLogger({ level: logLevel });
|
|
82
|
+
// Resolve socket path
|
|
83
|
+
const socketPath = values['socket-path'] ??
|
|
84
|
+
process.env['HERDR_SOCKET_PATH'] ??
|
|
85
|
+
`${process.env['HOME']}/.config/herdr/herdr.sock`;
|
|
86
|
+
// Parse numeric options
|
|
87
|
+
const marginSeconds = values['margin-seconds'] !== undefined
|
|
88
|
+
? parseInt(values['margin-seconds'], 10)
|
|
89
|
+
: 60;
|
|
90
|
+
const sweepIntervalSeconds = values['sweep-interval'] !== undefined
|
|
91
|
+
? parseInt(values['sweep-interval'], 10)
|
|
92
|
+
: 300;
|
|
93
|
+
if (isNaN(marginSeconds) || marginSeconds < 0) {
|
|
94
|
+
process.stderr.write(`error: invalid --margin-seconds '${values['margin-seconds']}'\n`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
if (isNaN(sweepIntervalSeconds) || sweepIntervalSeconds < 1) {
|
|
98
|
+
process.stderr.write(`error: invalid --sweep-interval '${values['sweep-interval']}'\n`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
// Signal handling
|
|
102
|
+
const ac = new AbortController();
|
|
103
|
+
process.on('SIGINT', () => ac.abort());
|
|
104
|
+
process.on('SIGTERM', () => ac.abort());
|
|
105
|
+
// Construct client
|
|
106
|
+
const client = new HerdrClient({ socketPath });
|
|
107
|
+
// Connect (connectivity check — open+close a socket)
|
|
108
|
+
logFn({ event: 'daemon.start', version: VERSION, socket_path: socketPath });
|
|
109
|
+
try {
|
|
110
|
+
await client.connect();
|
|
111
|
+
logFn({ event: 'socket.connected' });
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
logFn({ level: 'error', event: 'socket.dead' });
|
|
115
|
+
process.stderr.write(`fatal: could not connect to ${socketPath}: ${err}\n`);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
// Run daemon — map daemon's string logger to structured events
|
|
119
|
+
try {
|
|
120
|
+
await runDaemon({
|
|
121
|
+
client,
|
|
122
|
+
marginSeconds,
|
|
123
|
+
sweepIntervalMs: sweepIntervalSeconds * 1000,
|
|
124
|
+
signal: ac.signal,
|
|
125
|
+
log: (msg) => logFn({ event: 'daemon.internal', msg }),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
client.destroy();
|
|
130
|
+
logFn({ event: 'daemon.stop', reason: ac.signal.aborted ? 'signal' : 'exit' });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
main().catch((err) => {
|
|
134
|
+
process.stderr.write(`fatal: ${err}\n`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
});
|
|
137
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/daemon.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* daemon.ts — Event-driven daemon with reconcile sweep.
|
|
3
|
+
*
|
|
4
|
+
* Consumes HerdrClient event subscriptions and a periodic reconcile sweep
|
|
5
|
+
* to detect rate-limited Claude panes and inject 'continue' when limits reset.
|
|
6
|
+
*/
|
|
7
|
+
import type { HerdrClient } from './herdr.ts';
|
|
8
|
+
import { discoverAccountDirs, resolveAccountDir } from './accounts.ts';
|
|
9
|
+
import { readAccessToken, fetchUsage } from './usage.ts';
|
|
10
|
+
import type { Logger } from './monitor.ts';
|
|
11
|
+
export interface DaemonOpts {
|
|
12
|
+
client: HerdrClient;
|
|
13
|
+
/** Override account dir discovery. */
|
|
14
|
+
accountDirs?: string[];
|
|
15
|
+
/** Extra seconds after resetsAt before injecting. Default 60. */
|
|
16
|
+
marginSeconds?: number;
|
|
17
|
+
/** Reconcile sweep interval in ms. Default 5 * 60 * 1000. */
|
|
18
|
+
sweepIntervalMs?: number;
|
|
19
|
+
/** Abort the daemon loop. */
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
/** Injectable logger. Defaults to stderr. */
|
|
22
|
+
log?: Logger;
|
|
23
|
+
/** Injectable clock. Defaults to Date.now. */
|
|
24
|
+
now?: () => number;
|
|
25
|
+
/** Injectable sleep. Defaults to setTimeout promise. */
|
|
26
|
+
sleep?: (ms: number) => Promise<void>;
|
|
27
|
+
/** Injectable fetchUsage for DI in tests. */
|
|
28
|
+
fetchUsageFn?: typeof fetchUsage;
|
|
29
|
+
/** Injectable readAccessToken for DI in tests. */
|
|
30
|
+
readTokenFn?: typeof readAccessToken;
|
|
31
|
+
/** Injectable discoverAccountDirs for DI in tests. */
|
|
32
|
+
discoverDirsFn?: typeof discoverAccountDirs;
|
|
33
|
+
/** Injectable resolveAccountDir for DI in tests. */
|
|
34
|
+
resolveAccountDirFn?: typeof resolveAccountDir;
|
|
35
|
+
}
|
|
36
|
+
export declare function runDaemon(opts: DaemonOpts): Promise<void>;
|
|
37
|
+
//# sourceMappingURL=daemon.d.ts.map
|