@rlarua/agentrunner 0.0.3
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 +18 -0
- package/dist/api-client.js +133 -0
- package/dist/api-client.js.map +1 -0
- package/dist/autostart.d.ts +15 -0
- package/dist/autostart.js +280 -0
- package/dist/autostart.js.map +1 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +56 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/start.d.ts +1 -0
- package/dist/commands/start.js +21 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +20 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +1 -0
- package/dist/commands/stop.js +21 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/uninstall.d.ts +1 -0
- package/dist/commands/uninstall.js +21 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +66 -0
- package/dist/config.js.map +1 -0
- package/dist/handlers/trigger-handler.d.ts +3 -0
- package/dist/handlers/trigger-handler.js +145 -0
- package/dist/handlers/trigger-handler.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +5 -0
- package/dist/logger.js +25 -0
- package/dist/logger.js.map +1 -0
- package/dist/pid.d.ts +8 -0
- package/dist/pid.js +48 -0
- package/dist/pid.js.map +1 -0
- package/dist/poller.d.ts +4 -0
- package/dist/poller.js +62 -0
- package/dist/poller.js.map +1 -0
- package/dist/runners/claude-code.d.ts +4 -0
- package/dist/runners/claude-code.js +166 -0
- package/dist/runners/claude-code.js.map +1 -0
- package/dist/runners/codex.d.ts +4 -0
- package/dist/runners/codex.js +166 -0
- package/dist/runners/codex.js.map +1 -0
- package/dist/runners/gemini.d.ts +4 -0
- package/dist/runners/gemini.js +166 -0
- package/dist/runners/gemini.js.map +1 -0
- package/dist/runners/index.d.ts +2 -0
- package/dist/runners/index.js +25 -0
- package/dist/runners/index.js.map +1 -0
- package/dist/runners/log-reporter.d.ts +17 -0
- package/dist/runners/log-reporter.js +107 -0
- package/dist/runners/log-reporter.js.map +1 -0
- package/dist/runners/opencode.d.ts +6 -0
- package/dist/runners/opencode.js +170 -0
- package/dist/runners/opencode.js.map +1 -0
- package/dist/runners/types.d.ts +19 -0
- package/dist/runners/types.js +2 -0
- package/dist/runners/types.js.map +1 -0
- package/dist/types.d.ts +52 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/runner-history.d.ts +6 -0
- package/dist/utils/runner-history.js +13 -0
- package/dist/utils/runner-history.js.map +1 -0
- package/package.json +38 -0
- package/readme.md +160 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { logger } from "../logger.js";
|
|
2
|
+
const MAX_BATCH_SIZE = 50;
|
|
3
|
+
const MAX_BUFFERED_LOGS = 500;
|
|
4
|
+
const MAX_MESSAGE_LENGTH = 2000;
|
|
5
|
+
const DEFAULT_FLUSH_INTERVAL_MS = 2000;
|
|
6
|
+
const ANSI_ESCAPE_PATTERN = /\u001B\[[0-9;?]*[ -/]*[@-~]/g;
|
|
7
|
+
const CONTROL_CHAR_PATTERN = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g;
|
|
8
|
+
const normalizeMessage = (message) => {
|
|
9
|
+
const withoutAnsi = message.replace(ANSI_ESCAPE_PATTERN, "");
|
|
10
|
+
const normalizedNewline = withoutAnsi.replace(/\r\n?/g, "\n");
|
|
11
|
+
const withoutControlChars = normalizedNewline.replace(CONTROL_CHAR_PATTERN, "");
|
|
12
|
+
const squashed = withoutControlChars.replace(/\n{3,}/g, "\n\n");
|
|
13
|
+
const trimmed = squashed.trim();
|
|
14
|
+
if (trimmed.length <= MAX_MESSAGE_LENGTH) {
|
|
15
|
+
return trimmed;
|
|
16
|
+
}
|
|
17
|
+
return trimmed.slice(0, MAX_MESSAGE_LENGTH);
|
|
18
|
+
};
|
|
19
|
+
export class TriggerLogReporter {
|
|
20
|
+
client;
|
|
21
|
+
triggerId;
|
|
22
|
+
flushIntervalMs;
|
|
23
|
+
queue = [];
|
|
24
|
+
flushTimer = null;
|
|
25
|
+
flushInFlight = false;
|
|
26
|
+
droppedCount = 0;
|
|
27
|
+
constructor(client, triggerId, flushIntervalMs = DEFAULT_FLUSH_INTERVAL_MS) {
|
|
28
|
+
this.client = client;
|
|
29
|
+
this.triggerId = triggerId;
|
|
30
|
+
this.flushIntervalMs = flushIntervalMs;
|
|
31
|
+
}
|
|
32
|
+
start() {
|
|
33
|
+
if (this.flushTimer) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.flushTimer = setInterval(() => {
|
|
37
|
+
void this.flush({ heartbeat: true });
|
|
38
|
+
}, this.flushIntervalMs);
|
|
39
|
+
}
|
|
40
|
+
append(level, message) {
|
|
41
|
+
const normalized = normalizeMessage(message);
|
|
42
|
+
if (normalized.length === 0) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (this.queue.length >= MAX_BUFFERED_LOGS) {
|
|
46
|
+
this.queue.shift();
|
|
47
|
+
this.droppedCount += 1;
|
|
48
|
+
}
|
|
49
|
+
this.queue.push({ level, message: normalized });
|
|
50
|
+
}
|
|
51
|
+
async stop() {
|
|
52
|
+
if (this.flushTimer) {
|
|
53
|
+
clearInterval(this.flushTimer);
|
|
54
|
+
this.flushTimer = null;
|
|
55
|
+
}
|
|
56
|
+
await this.flush({ heartbeat: true, drain: true });
|
|
57
|
+
}
|
|
58
|
+
async flush(opts) {
|
|
59
|
+
if (this.flushInFlight) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.flushInFlight = true;
|
|
63
|
+
try {
|
|
64
|
+
if (this.droppedCount > 0) {
|
|
65
|
+
const droppedMessage = `Dropped ${this.droppedCount} log line(s) due to buffer limit (${MAX_BUFFERED_LOGS}).`;
|
|
66
|
+
this.queue.unshift({ level: "WARN", message: droppedMessage });
|
|
67
|
+
this.droppedCount = 0;
|
|
68
|
+
}
|
|
69
|
+
if (opts.drain) {
|
|
70
|
+
while (this.queue.length > 0) {
|
|
71
|
+
const batch = this.queue.splice(0, MAX_BATCH_SIZE);
|
|
72
|
+
await this.send({ logs: batch, heartbeat: opts.heartbeat });
|
|
73
|
+
opts.heartbeat = false;
|
|
74
|
+
}
|
|
75
|
+
if (opts.heartbeat) {
|
|
76
|
+
await this.send({ heartbeat: true });
|
|
77
|
+
}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const batch = this.queue.splice(0, MAX_BATCH_SIZE);
|
|
81
|
+
if (batch.length === 0 && !opts.heartbeat) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
await this.send({ logs: batch.length > 0 ? batch : undefined, heartbeat: opts.heartbeat });
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
this.flushInFlight = false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async send(payload) {
|
|
91
|
+
if (!payload.logs && !payload.heartbeat) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
await this.client.appendTriggerLogs(this.triggerId, payload);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
logger.warn("Failed to report trigger logs", {
|
|
99
|
+
triggerId: this.triggerId,
|
|
100
|
+
error: error instanceof Error ? error.message : String(error),
|
|
101
|
+
payloadSize: payload.logs?.length ?? 0,
|
|
102
|
+
heartbeat: payload.heartbeat === true
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=log-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-reporter.js","sourceRoot":"","sources":["../../src/runners/log-reporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { createWriteStream } from "node:fs";
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { logger } from "../logger.js";
|
|
6
|
+
const FORCE_KILL_AFTER_MS = 10_000;
|
|
7
|
+
const PROMPT_PREVIEW_MAX = 500;
|
|
8
|
+
const OUTPUT_PREVIEW_MAX = 400;
|
|
9
|
+
const toPromptPreview = (prompt) => {
|
|
10
|
+
if (prompt.length <= PROMPT_PREVIEW_MAX) {
|
|
11
|
+
return prompt;
|
|
12
|
+
}
|
|
13
|
+
return `${prompt.slice(0, PROMPT_PREVIEW_MAX)}...`;
|
|
14
|
+
};
|
|
15
|
+
const toOutputPreview = (chunk) => {
|
|
16
|
+
const text = (typeof chunk === "string" ? chunk : String(chunk)).trim();
|
|
17
|
+
if (text.length <= OUTPUT_PREVIEW_MAX) {
|
|
18
|
+
return text;
|
|
19
|
+
}
|
|
20
|
+
return `${text.slice(0, OUTPUT_PREVIEW_MAX)}...`;
|
|
21
|
+
};
|
|
22
|
+
export class OpenCodeRunner {
|
|
23
|
+
runnerCmd;
|
|
24
|
+
constructor(runnerCmd = "opencode") {
|
|
25
|
+
this.runnerCmd = runnerCmd;
|
|
26
|
+
}
|
|
27
|
+
async run(opts) {
|
|
28
|
+
if (!opts.authPath || opts.authPath.trim().length === 0) {
|
|
29
|
+
logger.error("authPath is missing for trigger");
|
|
30
|
+
return {
|
|
31
|
+
exitCode: 1,
|
|
32
|
+
errorMessage: "authPath is missing for trigger"
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const cwd = opts.authPath;
|
|
36
|
+
const logPath = join(cwd, ".agentteams", "runner-log", `${opts.triggerId}.log`);
|
|
37
|
+
await mkdir(dirname(logPath), { recursive: true });
|
|
38
|
+
logger.info("Runner prompt", {
|
|
39
|
+
triggerId: opts.triggerId,
|
|
40
|
+
promptLength: opts.prompt.length,
|
|
41
|
+
promptPreview: toPromptPreview(opts.prompt)
|
|
42
|
+
});
|
|
43
|
+
const child = spawn(this.runnerCmd, ["run", opts.prompt], {
|
|
44
|
+
cwd,
|
|
45
|
+
detached: true,
|
|
46
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
47
|
+
env: {
|
|
48
|
+
...process.env,
|
|
49
|
+
AGENTTEAMS_API_KEY: opts.apiKey,
|
|
50
|
+
AGENTTEAMS_API_URL: opts.apiUrl,
|
|
51
|
+
AGENTTEAMS_AGENT_NAME: opts.agentConfigId
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
const logStream = createWriteStream(logPath, { flags: "a" });
|
|
55
|
+
child.stdout?.pipe(logStream);
|
|
56
|
+
child.stderr?.pipe(logStream);
|
|
57
|
+
let lastOutput = "";
|
|
58
|
+
let lastErrorOutput = "";
|
|
59
|
+
child.stdout?.on("data", (chunk) => {
|
|
60
|
+
const output = toOutputPreview(Buffer.isBuffer(chunk) ? chunk.toString("utf8") : chunk);
|
|
61
|
+
if (output.length > 0) {
|
|
62
|
+
lastOutput = output;
|
|
63
|
+
opts.onStdoutChunk?.(output);
|
|
64
|
+
logger.info("Runner stdout", {
|
|
65
|
+
triggerId: opts.triggerId,
|
|
66
|
+
pid: child.pid,
|
|
67
|
+
output
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
child.stderr?.on("data", (chunk) => {
|
|
72
|
+
const output = toOutputPreview(Buffer.isBuffer(chunk) ? chunk.toString("utf8") : chunk);
|
|
73
|
+
if (output.length > 0) {
|
|
74
|
+
lastOutput = output;
|
|
75
|
+
lastErrorOutput = output;
|
|
76
|
+
opts.onStderrChunk?.(output);
|
|
77
|
+
logger.warn("Runner stderr", {
|
|
78
|
+
triggerId: opts.triggerId,
|
|
79
|
+
pid: child.pid,
|
|
80
|
+
output
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
logger.info("Runner started", {
|
|
85
|
+
triggerId: opts.triggerId,
|
|
86
|
+
cwd,
|
|
87
|
+
logPath,
|
|
88
|
+
pid: child.pid
|
|
89
|
+
});
|
|
90
|
+
return await new Promise((resolve) => {
|
|
91
|
+
let finished = false;
|
|
92
|
+
let timedOut = false;
|
|
93
|
+
const cleanup = () => {
|
|
94
|
+
if (finished) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
finished = true;
|
|
98
|
+
logStream.end();
|
|
99
|
+
};
|
|
100
|
+
const timeoutId = setTimeout(() => {
|
|
101
|
+
timedOut = true;
|
|
102
|
+
if (!child.pid) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
logger.warn("Runner timeout reached; sending SIGTERM", {
|
|
106
|
+
triggerId: opts.triggerId,
|
|
107
|
+
pid: child.pid,
|
|
108
|
+
timeoutMs: opts.timeoutMs
|
|
109
|
+
});
|
|
110
|
+
try {
|
|
111
|
+
process.kill(-child.pid, "SIGTERM");
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// ignore
|
|
115
|
+
}
|
|
116
|
+
setTimeout(() => {
|
|
117
|
+
if (!finished && child.pid) {
|
|
118
|
+
logger.warn("Runner still alive after SIGTERM; sending SIGKILL", {
|
|
119
|
+
triggerId: opts.triggerId,
|
|
120
|
+
pid: child.pid
|
|
121
|
+
});
|
|
122
|
+
try {
|
|
123
|
+
process.kill(-child.pid, "SIGKILL");
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// ignore
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}, FORCE_KILL_AFTER_MS);
|
|
130
|
+
}, opts.timeoutMs);
|
|
131
|
+
child.on("error", (error) => {
|
|
132
|
+
clearTimeout(timeoutId);
|
|
133
|
+
cleanup();
|
|
134
|
+
logger.error("Runner process launch failed", {
|
|
135
|
+
triggerId: opts.triggerId,
|
|
136
|
+
error: error.message
|
|
137
|
+
});
|
|
138
|
+
resolve({
|
|
139
|
+
exitCode: 1,
|
|
140
|
+
lastOutput,
|
|
141
|
+
errorMessage: error.message
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
child.on("close", (code) => {
|
|
145
|
+
clearTimeout(timeoutId);
|
|
146
|
+
cleanup();
|
|
147
|
+
logger.info("Runner process closed", {
|
|
148
|
+
triggerId: opts.triggerId,
|
|
149
|
+
pid: child.pid,
|
|
150
|
+
exitCode: code,
|
|
151
|
+
timedOut
|
|
152
|
+
});
|
|
153
|
+
if (timedOut) {
|
|
154
|
+
resolve({
|
|
155
|
+
exitCode: 1,
|
|
156
|
+
lastOutput,
|
|
157
|
+
errorMessage: `Runner timed out after ${opts.timeoutMs}ms`
|
|
158
|
+
});
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
resolve({
|
|
162
|
+
exitCode: code ?? 1,
|
|
163
|
+
lastOutput,
|
|
164
|
+
errorMessage: code === 0 ? undefined : (lastErrorOutput || lastOutput || `Runner exited with code ${code ?? 1}`)
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/runners/opencode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface Runner {
|
|
2
|
+
run(opts: RunnerOptions): Promise<RunResult>;
|
|
3
|
+
}
|
|
4
|
+
export interface RunnerOptions {
|
|
5
|
+
triggerId: string;
|
|
6
|
+
prompt: string;
|
|
7
|
+
authPath: string | null;
|
|
8
|
+
apiKey: string;
|
|
9
|
+
apiUrl: string;
|
|
10
|
+
timeoutMs: number;
|
|
11
|
+
agentConfigId: string;
|
|
12
|
+
onStdoutChunk?: (chunk: string) => void;
|
|
13
|
+
onStderrChunk?: (chunk: string) => void;
|
|
14
|
+
}
|
|
15
|
+
export type RunResult = {
|
|
16
|
+
exitCode: number;
|
|
17
|
+
lastOutput?: string;
|
|
18
|
+
errorMessage?: string;
|
|
19
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/runners/types.ts"],"names":[],"mappings":""}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type RuntimeConfig = {
|
|
2
|
+
daemonToken: string;
|
|
3
|
+
apiUrl: string;
|
|
4
|
+
pollingIntervalMs: number;
|
|
5
|
+
timeoutMs: number;
|
|
6
|
+
runnerCmd: string;
|
|
7
|
+
};
|
|
8
|
+
export type DaemonConfigFile = {
|
|
9
|
+
daemonToken: string;
|
|
10
|
+
apiUrl: string;
|
|
11
|
+
};
|
|
12
|
+
export type DaemonInfo = {
|
|
13
|
+
id: string;
|
|
14
|
+
memberId: string;
|
|
15
|
+
label: string | null;
|
|
16
|
+
lastSeenAt: string | null;
|
|
17
|
+
createdAt: string;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
};
|
|
20
|
+
export type DaemonTrigger = {
|
|
21
|
+
id: string;
|
|
22
|
+
prompt: string | Record<string, unknown>;
|
|
23
|
+
runnerType: string;
|
|
24
|
+
status: string;
|
|
25
|
+
agentConfigId: string;
|
|
26
|
+
startedAt: string | null;
|
|
27
|
+
errorMessage: string | null;
|
|
28
|
+
historyMarkdown: string | null;
|
|
29
|
+
lastHeartbeatAt: string | null;
|
|
30
|
+
conversationId: string | null;
|
|
31
|
+
parentTriggerId: string | null;
|
|
32
|
+
createdByMemberId: string;
|
|
33
|
+
claimedByDaemonId: string | null;
|
|
34
|
+
createdAt: string;
|
|
35
|
+
updatedAt: string;
|
|
36
|
+
};
|
|
37
|
+
export type TriggerFinalStatus = "DONE" | "FAILED" | "REJECTED";
|
|
38
|
+
export type ClaimResult = {
|
|
39
|
+
ok: boolean;
|
|
40
|
+
conflict: boolean;
|
|
41
|
+
};
|
|
42
|
+
export type TriggerRuntime = {
|
|
43
|
+
triggerId: string;
|
|
44
|
+
agentConfigId: string;
|
|
45
|
+
authPath: string | null;
|
|
46
|
+
apiKey: string;
|
|
47
|
+
};
|
|
48
|
+
export type TriggerLogLevel = "INFO" | "WARN" | "ERROR";
|
|
49
|
+
export type TriggerLogInput = {
|
|
50
|
+
level: TriggerLogLevel;
|
|
51
|
+
message: string;
|
|
52
|
+
};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
const historyDirectory = (authPath) => join(authPath, ".agentteams", "runner-history");
|
|
3
|
+
const historyFilePath = (authPath, triggerId) => join(historyDirectory(authPath), `${triggerId}.md`);
|
|
4
|
+
export const resolveRunnerHistoryPaths = (authPath, triggerId, parentTriggerId) => {
|
|
5
|
+
if (!authPath) {
|
|
6
|
+
return { currentHistoryPath: null, parentHistoryPath: null };
|
|
7
|
+
}
|
|
8
|
+
return {
|
|
9
|
+
currentHistoryPath: historyFilePath(authPath, triggerId),
|
|
10
|
+
parentHistoryPath: parentTriggerId ? historyFilePath(authPath, parentTriggerId) : null
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=runner-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-history.js","sourceRoot":"","sources":["../../src/utils/runner-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAOjC,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;AAE/F,MAAM,eAAe,GAAG,CAAC,QAAgB,EAAE,SAAiB,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,GAAG,SAAS,KAAK,CAAC,CAAC;AAErH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,QAAuB,EACvB,SAAiB,EACjB,eAA8B,EACV,EAAE;IACtB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;IAC/D,CAAC;IAED,OAAO;QACL,kBAAkB,EAAE,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC;QACxD,iBAAiB,EAAE,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI;KACvF,CAAC;AACJ,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rlarua/agentrunner",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "AgentRunner - Background runner that polls and executes AI agent tasks",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"agentrunner": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist/**/*",
|
|
12
|
+
"readme.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "rm -rf dist && tsc",
|
|
16
|
+
"dev": "tsx watch src/index.ts",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"init": "node dist/index.js init",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://agentteams.run",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"agentteams",
|
|
27
|
+
"runner",
|
|
28
|
+
"ai-agent",
|
|
29
|
+
"automation"
|
|
30
|
+
],
|
|
31
|
+
"license": "Apache-2.0",
|
|
32
|
+
"dependencies": {},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^24.3.0",
|
|
35
|
+
"tsx": "^4.20.5",
|
|
36
|
+
"typescript": "^5.9.2"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# @rlarua/agentrunner
|
|
2
|
+
|
|
3
|
+
A background runner that polls and executes AI agent tasks from the AgentTeams platform.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js `18` or later
|
|
8
|
+
- AgentTeams API server running
|
|
9
|
+
- A daemon token issued from the web UI (`x-daemon-token`)
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @rlarua/agentrunner
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Verify the installation:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
agentrunner --help
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### 1. Initialize
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
agentrunner init --token <DAEMON_TOKEN>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The `init` command:
|
|
32
|
+
|
|
33
|
+
1. Saves the token to `~/.agentteams/daemon.json`
|
|
34
|
+
2. Validates the token against the API server
|
|
35
|
+
3. Registers an OS-level autostart service and starts the runner immediately
|
|
36
|
+
- **macOS**: `~/Library/LaunchAgents/run.agentteams.daemon.plist` (launchd)
|
|
37
|
+
- **Linux**: `~/.config/systemd/user/agentrunner.service` (systemd)
|
|
38
|
+
- **Windows**: `AgentRunner` (Task Scheduler)
|
|
39
|
+
|
|
40
|
+
### Options
|
|
41
|
+
|
|
42
|
+
- `--token <token>` — **Required**. Daemon token issued from the web UI
|
|
43
|
+
- `--no-autostart` — Optional. Skip autostart registration (manual start only)
|
|
44
|
+
|
|
45
|
+
Examples:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Standard setup (with autostart)
|
|
49
|
+
agentrunner init --token daemon_xxxxx
|
|
50
|
+
|
|
51
|
+
# Token-only setup (no autostart)
|
|
52
|
+
agentrunner init --token daemon_xxxxx --no-autostart
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 2. Start (`start`)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
agentrunner start
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Running without a subcommand defaults to `start`:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
agentrunner
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
> If autostart was registered via `init`, you do not need to run `start` manually.
|
|
68
|
+
> The OS will start the runner automatically on login/boot.
|
|
69
|
+
|
|
70
|
+
### 3. Check Status (`status`)
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
agentrunner status
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Shows whether the runner process is active and whether autostart is registered.
|
|
77
|
+
|
|
78
|
+
Example output:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
[...] INFO Daemon is running { pid: 12345 }
|
|
82
|
+
[...] INFO Autostart is enabled { platform: 'launchd' }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 4. Stop (`stop`)
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
agentrunner stop
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Sends SIGTERM to the running process for a graceful shutdown.
|
|
92
|
+
|
|
93
|
+
> If autostart is registered, the OS may restart the runner automatically.
|
|
94
|
+
> Use `uninstall` to stop completely.
|
|
95
|
+
|
|
96
|
+
### 5. Uninstall (`uninstall`)
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
agentrunner uninstall
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Performs the following:
|
|
103
|
+
|
|
104
|
+
1. Stops the running process
|
|
105
|
+
2. Removes the autostart service and deletes the service file
|
|
106
|
+
3. Cleans up the PID file
|
|
107
|
+
|
|
108
|
+
## Configuration
|
|
109
|
+
|
|
110
|
+
Settings are resolved in the following priority order at runtime.
|
|
111
|
+
|
|
112
|
+
### Token
|
|
113
|
+
|
|
114
|
+
1. `AGENTTEAMS_DAEMON_TOKEN` environment variable
|
|
115
|
+
2. `daemonToken` in `~/.agentteams/daemon.json`
|
|
116
|
+
|
|
117
|
+
### Environment Variables
|
|
118
|
+
|
|
119
|
+
| Variable | Default | Description |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `POLLING_INTERVAL_MS` | `30000` (30s) | Polling interval for pending triggers |
|
|
122
|
+
| `TIMEOUT_MS` | `1800000` (30min) | Runner process timeout |
|
|
123
|
+
| `RUNNER_CMD` | `opencode` | Command used to execute agent tasks |
|
|
124
|
+
| `LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |
|
|
125
|
+
| `DAEMON_VERBOSE_RUNNER_LOGS` | `true` | When `false`, reduces runner stdout/stderr to start/stop/error only |
|
|
126
|
+
| `DAEMON_PROMPT_LOG_MODE` | `preview` | Prompt logging: `off`, `length`, `preview`, `full` |
|
|
127
|
+
|
|
128
|
+
## How It Works
|
|
129
|
+
|
|
130
|
+
After `start`, the runner operates in the following loop:
|
|
131
|
+
|
|
132
|
+
1. Polls for pending triggers periodically
|
|
133
|
+
2. Claims a trigger
|
|
134
|
+
3. Fetches runtime info (working directory, API key)
|
|
135
|
+
4. Executes `RUNNER_CMD run "<prompt>"`
|
|
136
|
+
5. Updates trigger status based on exit code or timeout
|
|
137
|
+
|
|
138
|
+
If a process is already running for the same `agentConfigId`, new triggers are `REJECTED`.
|
|
139
|
+
|
|
140
|
+
## Logs
|
|
141
|
+
|
|
142
|
+
- **Runner logs**: console output (forwarded to OS log system when autostarted)
|
|
143
|
+
- **macOS**: `/tmp/agentrunner.log`, `/tmp/agentrunner-error.log`
|
|
144
|
+
- **Linux**: `journalctl --user -u agentrunner -f`
|
|
145
|
+
- **Windows**: Event Viewer → Windows Logs → Application (`AgentRunner`)
|
|
146
|
+
- **Task logs**: `<workdir>/.agentteams/daemonLog/daemon-<triggerId>.log`
|
|
147
|
+
|
|
148
|
+
## Troubleshooting
|
|
149
|
+
|
|
150
|
+
### `Missing token. Usage: agentrunner init --token <token> ...`
|
|
151
|
+
|
|
152
|
+
The `--token` flag was not provided to `init`.
|
|
153
|
+
|
|
154
|
+
### `Daemon token is missing. Run 'agentrunner init --token <token>' first.`
|
|
155
|
+
|
|
156
|
+
No token found at runtime. Run `init` first or set the `AGENTTEAMS_DAEMON_TOKEN` environment variable.
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
Apache-2.0
|