@csdwd/ai-teams-agent 0.2.0 → 0.3.1
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/index.js +308 -75
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,32 +2,198 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
5
|
-
import
|
|
5
|
+
import fs6 from "node:fs";
|
|
6
|
+
import path7 from "node:path";
|
|
6
7
|
import { fileURLToPath } from "node:url";
|
|
7
8
|
import WebSocket2 from "ws";
|
|
8
9
|
|
|
10
|
+
// ../../packages/shared/dist/daemon.js
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { spawn } from "node:child_process";
|
|
14
|
+
function readPidFile(pidFile) {
|
|
15
|
+
try {
|
|
16
|
+
const content = fs.readFileSync(pidFile, "utf-8").trim();
|
|
17
|
+
const pid = Number(content);
|
|
18
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function writePidFile(pidFile, pid) {
|
|
24
|
+
fs.mkdirSync(path.dirname(pidFile), { recursive: true });
|
|
25
|
+
fs.writeFileSync(pidFile, String(pid), "utf-8");
|
|
26
|
+
}
|
|
27
|
+
function removePidFile(pidFile) {
|
|
28
|
+
try {
|
|
29
|
+
fs.unlinkSync(pidFile);
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function isProcessRunning(pid) {
|
|
34
|
+
try {
|
|
35
|
+
process.kill(pid, 0);
|
|
36
|
+
return true;
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function spawnWorker(script, args, logDir) {
|
|
42
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
43
|
+
const logFile = path.join(logDir, "worker.log");
|
|
44
|
+
const logStream = fs.openSync(logFile, "a");
|
|
45
|
+
const child = spawn(process.execPath, [script, ...args], {
|
|
46
|
+
stdio: ["ignore", logStream, logStream],
|
|
47
|
+
env: {
|
|
48
|
+
...process.env,
|
|
49
|
+
__AI_TEAMS_DAEMON_WORKER: "1",
|
|
50
|
+
__AI_TEAMS_DAEMON_WATCHDOG: void 0
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
fs.closeSync(logStream);
|
|
54
|
+
return child;
|
|
55
|
+
}
|
|
56
|
+
var MAX_RESTARTS_PER_MINUTE = 10;
|
|
57
|
+
var RESTART_DELAY_MS = 3e3;
|
|
58
|
+
async function runWatchdog(opts) {
|
|
59
|
+
const { name, pidFile, logDir, workerScript, workerArgs } = opts;
|
|
60
|
+
writePidFile(pidFile, process.pid);
|
|
61
|
+
let restartTimestamps = [];
|
|
62
|
+
function cleanupAndExit(code) {
|
|
63
|
+
removePidFile(pidFile);
|
|
64
|
+
process.exit(code);
|
|
65
|
+
}
|
|
66
|
+
let worker = null;
|
|
67
|
+
let shuttingDown2 = false;
|
|
68
|
+
function shutdown() {
|
|
69
|
+
if (shuttingDown2)
|
|
70
|
+
return;
|
|
71
|
+
shuttingDown2 = true;
|
|
72
|
+
if (worker)
|
|
73
|
+
worker.kill("SIGTERM");
|
|
74
|
+
}
|
|
75
|
+
process.on("SIGTERM", shutdown);
|
|
76
|
+
process.on("SIGINT", shutdown);
|
|
77
|
+
while (!shuttingDown2) {
|
|
78
|
+
await new Promise((resolve) => {
|
|
79
|
+
worker = spawnWorker(workerScript, workerArgs, logDir);
|
|
80
|
+
worker.on("exit", (code, signal) => {
|
|
81
|
+
worker = null;
|
|
82
|
+
if (shuttingDown2) {
|
|
83
|
+
cleanupAndExit(0);
|
|
84
|
+
}
|
|
85
|
+
if (code === 0) {
|
|
86
|
+
console.log(`${name}: worker exited cleanly, daemon stopping.`);
|
|
87
|
+
cleanupAndExit(0);
|
|
88
|
+
}
|
|
89
|
+
const now = Date.now();
|
|
90
|
+
restartTimestamps = restartTimestamps.filter((t) => now - t < 6e4);
|
|
91
|
+
restartTimestamps.push(now);
|
|
92
|
+
if (restartTimestamps.length > MAX_RESTARTS_PER_MINUTE) {
|
|
93
|
+
console.error(`${name}: exceeded ${MAX_RESTARTS_PER_MINUTE} restarts/minute, daemon stopping.`);
|
|
94
|
+
cleanupAndExit(1);
|
|
95
|
+
}
|
|
96
|
+
console.log(`${name}: worker crashed (code=${code}, signal=${signal}), restarting in ${RESTART_DELAY_MS}ms...`);
|
|
97
|
+
setTimeout(resolve, RESTART_DELAY_MS);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
cleanupAndExit(0);
|
|
102
|
+
}
|
|
103
|
+
function getDaemonStatus(pidFile) {
|
|
104
|
+
const pid = readPidFile(pidFile);
|
|
105
|
+
if (pid === null) {
|
|
106
|
+
return { running: false, pid: null };
|
|
107
|
+
}
|
|
108
|
+
if (isProcessRunning(pid)) {
|
|
109
|
+
return { running: true, pid };
|
|
110
|
+
}
|
|
111
|
+
removePidFile(pidFile);
|
|
112
|
+
return { running: false, pid: null };
|
|
113
|
+
}
|
|
114
|
+
async function stopDaemon(pidFile) {
|
|
115
|
+
const pid = readPidFile(pidFile);
|
|
116
|
+
if (pid === null) {
|
|
117
|
+
console.log("Not running (no PID file found).");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (!isProcessRunning(pid)) {
|
|
121
|
+
removePidFile(pidFile);
|
|
122
|
+
console.log("Not running (stale PID file cleaned).");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
process.kill(pid, "SIGTERM");
|
|
126
|
+
for (let i = 0; i < 20; i++) {
|
|
127
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
128
|
+
if (!isProcessRunning(pid)) {
|
|
129
|
+
removePidFile(pidFile);
|
|
130
|
+
console.log(`Stopped (PID ${pid}).`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
process.kill(pid, "SIGKILL");
|
|
135
|
+
removePidFile(pidFile);
|
|
136
|
+
console.log(`Force killed (PID ${pid}).`);
|
|
137
|
+
}
|
|
138
|
+
function daemonize(opts) {
|
|
139
|
+
if (process.env.__AI_TEAMS_DAEMON_WORKER === "1") {
|
|
140
|
+
return opts.run();
|
|
141
|
+
}
|
|
142
|
+
if (process.env.__AI_TEAMS_DAEMON_WATCHDOG === "1") {
|
|
143
|
+
return runWatchdog({
|
|
144
|
+
name: opts.name,
|
|
145
|
+
pidFile: opts.pidFile,
|
|
146
|
+
logDir: path.dirname(opts.logFile),
|
|
147
|
+
workerScript: process.argv[1],
|
|
148
|
+
workerArgs: process.argv.slice(2)
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
fs.mkdirSync(path.dirname(opts.logFile), { recursive: true });
|
|
152
|
+
const child = spawn(process.execPath, [process.argv[1], ...process.argv.slice(2)], {
|
|
153
|
+
detached: true,
|
|
154
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
155
|
+
env: {
|
|
156
|
+
...process.env,
|
|
157
|
+
__AI_TEAMS_DAEMON_WATCHDOG: "1"
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
child.unref();
|
|
161
|
+
return new Promise((resolve) => {
|
|
162
|
+
setTimeout(() => {
|
|
163
|
+
const pid = readPidFile(opts.pidFile);
|
|
164
|
+
if (pid) {
|
|
165
|
+
console.log(`${opts.name} started (PID ${pid})`);
|
|
166
|
+
} else {
|
|
167
|
+
console.error(`${opts.name}: failed to start \u2014 PID file not found.`);
|
|
168
|
+
}
|
|
169
|
+
resolve();
|
|
170
|
+
process.exit(pid ? 0 : 1);
|
|
171
|
+
}, 500);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
9
175
|
// src/config.ts
|
|
10
|
-
import
|
|
176
|
+
import path3 from "node:path";
|
|
11
177
|
|
|
12
178
|
// src/setup.ts
|
|
13
|
-
import
|
|
14
|
-
import
|
|
179
|
+
import fs2 from "node:fs";
|
|
180
|
+
import path2 from "node:path";
|
|
15
181
|
import os from "node:os";
|
|
16
182
|
import { createInterface } from "node:readline/promises";
|
|
17
183
|
import { stdin as input, stdout as output } from "node:process";
|
|
18
|
-
var CONFIG_DIR =
|
|
19
|
-
var CONFIG_FILE =
|
|
184
|
+
var CONFIG_DIR = path2.join(os.homedir(), ".ai-teams");
|
|
185
|
+
var CONFIG_FILE = path2.join(CONFIG_DIR, "config.json");
|
|
20
186
|
function loadConfigFile() {
|
|
21
187
|
try {
|
|
22
|
-
const raw =
|
|
188
|
+
const raw = fs2.readFileSync(CONFIG_FILE, "utf8");
|
|
23
189
|
return JSON.parse(raw);
|
|
24
190
|
} catch {
|
|
25
191
|
return null;
|
|
26
192
|
}
|
|
27
193
|
}
|
|
28
194
|
function saveConfigFile(config) {
|
|
29
|
-
|
|
30
|
-
|
|
195
|
+
fs2.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
196
|
+
fs2.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
|
|
31
197
|
}
|
|
32
198
|
async function runSetup(existing) {
|
|
33
199
|
const rl = createInterface({ input, output });
|
|
@@ -69,26 +235,26 @@ var RUNNER_MODE = process.env.RUNNER_MODE || fileConfig?.runnerMode || "claude";
|
|
|
69
235
|
var DEFAULT_WORKSPACE = process.env.DEFAULT_WORKSPACE || fileConfig?.workspace || process.cwd();
|
|
70
236
|
var MAX_BUFFERED_MESSAGES = Number(process.env.AGENT_BUFFER_LIMIT) || 400;
|
|
71
237
|
var MAX_ERROR_TAIL = 16e3;
|
|
72
|
-
var CLAUDE_MISSING_CONVERSATION_PATTERN = /No conversation found with session ID/i;
|
|
73
|
-
var AGENT_RECORDS_DIR = process.env.AGENT_RECORDS_DIR ||
|
|
74
|
-
var STATE_FILE = process.env.AGENT_STATE_FILE ||
|
|
75
|
-
var LEGACY_STATE_FILE =
|
|
76
|
-
var DAILY_RECORDS_DIR =
|
|
77
|
-
var HOOKS_DIR =
|
|
78
|
-
var CLAUDE_HOOK_SCRIPT =
|
|
79
|
-
var CLAUDE_HOOK_SETTINGS =
|
|
238
|
+
var CLAUDE_MISSING_CONVERSATION_PATTERN = /No conversation found with session ID|Session ID .+ is already in use/i;
|
|
239
|
+
var AGENT_RECORDS_DIR = process.env.AGENT_RECORDS_DIR || path3.join(DEFAULT_WORKSPACE, ".ai-teams", "agents", EMPLOYEE_ID);
|
|
240
|
+
var STATE_FILE = process.env.AGENT_STATE_FILE || path3.join(AGENT_RECORDS_DIR, "session-state.json");
|
|
241
|
+
var LEGACY_STATE_FILE = path3.join(process.cwd(), `.agent-state.${EMPLOYEE_ID}.json`);
|
|
242
|
+
var DAILY_RECORDS_DIR = path3.join(AGENT_RECORDS_DIR, "daily");
|
|
243
|
+
var HOOKS_DIR = path3.join(AGENT_RECORDS_DIR, "hooks");
|
|
244
|
+
var CLAUDE_HOOK_SCRIPT = path3.join(HOOKS_DIR, "claude-session-recorder.cjs");
|
|
245
|
+
var CLAUDE_HOOK_SETTINGS = path3.join(HOOKS_DIR, "claude-hooks.settings.json");
|
|
80
246
|
var CLAUDE_HOOKS_ENABLED = process.env.CLAUDE_HOOKS_ENABLED !== "false";
|
|
81
|
-
var WORKSPACE_CLAUDE_MD =
|
|
247
|
+
var WORKSPACE_CLAUDE_MD = path3.join(DEFAULT_WORKSPACE, "CLAUDE.md");
|
|
82
248
|
var CLAUDE_MD_SECTION_START = "<!-- AI_TEAMS_AGENT_RULES_START -->";
|
|
83
249
|
var CLAUDE_MD_SECTION_END = "<!-- AI_TEAMS_AGENT_RULES_END -->";
|
|
84
250
|
|
|
85
251
|
// src/state.ts
|
|
86
|
-
import
|
|
87
|
-
import
|
|
252
|
+
import fs3 from "node:fs";
|
|
253
|
+
import path4 from "node:path";
|
|
88
254
|
import { randomUUID } from "node:crypto";
|
|
89
255
|
function loadState() {
|
|
90
256
|
try {
|
|
91
|
-
const content =
|
|
257
|
+
const content = fs3.readFileSync(STATE_FILE, "utf8");
|
|
92
258
|
const parsed = JSON.parse(content);
|
|
93
259
|
return {
|
|
94
260
|
claudeSessionId: parsed.claudeSessionId || randomUUID(),
|
|
@@ -106,11 +272,11 @@ function loadState() {
|
|
|
106
272
|
}
|
|
107
273
|
}
|
|
108
274
|
function loadLegacyState() {
|
|
109
|
-
if (process.env.AGENT_STATE_FILE || LEGACY_STATE_FILE === STATE_FILE || !
|
|
275
|
+
if (process.env.AGENT_STATE_FILE || LEGACY_STATE_FILE === STATE_FILE || !fs3.existsSync(LEGACY_STATE_FILE)) {
|
|
110
276
|
return null;
|
|
111
277
|
}
|
|
112
278
|
try {
|
|
113
|
-
const parsed = JSON.parse(
|
|
279
|
+
const parsed = JSON.parse(fs3.readFileSync(LEGACY_STATE_FILE, "utf8"));
|
|
114
280
|
return {
|
|
115
281
|
claudeSessionId: parsed.claudeSessionId || randomUUID(),
|
|
116
282
|
sessionReady: parsed.sessionReady ?? false
|
|
@@ -120,8 +286,8 @@ function loadLegacyState() {
|
|
|
120
286
|
}
|
|
121
287
|
}
|
|
122
288
|
function persistState(state) {
|
|
123
|
-
|
|
124
|
-
|
|
289
|
+
fs3.mkdirSync(path4.dirname(STATE_FILE), { recursive: true });
|
|
290
|
+
fs3.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
125
291
|
}
|
|
126
292
|
function resetClaudeSession() {
|
|
127
293
|
const state = { claudeSessionId: randomUUID(), sessionReady: false };
|
|
@@ -130,8 +296,8 @@ function resetClaudeSession() {
|
|
|
130
296
|
}
|
|
131
297
|
|
|
132
298
|
// src/records.ts
|
|
133
|
-
import
|
|
134
|
-
import
|
|
299
|
+
import fs4 from "node:fs";
|
|
300
|
+
import path5 from "node:path";
|
|
135
301
|
|
|
136
302
|
// src/claude-hook-script.ts
|
|
137
303
|
var CLAUDE_HOOK_SCRIPT_CONTENT = `#!/usr/bin/env node
|
|
@@ -233,14 +399,14 @@ function localDateKey() {
|
|
|
233
399
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
234
400
|
}
|
|
235
401
|
function appendDailyRecord(markdown) {
|
|
236
|
-
|
|
237
|
-
const filePath =
|
|
238
|
-
if (!
|
|
239
|
-
|
|
402
|
+
fs4.mkdirSync(DAILY_RECORDS_DIR, { recursive: true });
|
|
403
|
+
const filePath = path5.join(DAILY_RECORDS_DIR, `${localDateKey()}.md`);
|
|
404
|
+
if (!fs4.existsSync(filePath)) {
|
|
405
|
+
fs4.writeFileSync(filePath, `# ${EMPLOYEE_NAME} Daily Activity - ${localDateKey()}
|
|
240
406
|
|
|
241
407
|
`);
|
|
242
408
|
}
|
|
243
|
-
|
|
409
|
+
fs4.appendFileSync(filePath, markdown);
|
|
244
410
|
}
|
|
245
411
|
function formatPromptForRecord(prompt) {
|
|
246
412
|
return prompt.trim().replace(/\n/g, "\n ");
|
|
@@ -274,9 +440,9 @@ function recordTaskFinish(task, status, detail) {
|
|
|
274
440
|
);
|
|
275
441
|
}
|
|
276
442
|
function ensureWorkspaceClaudeMd() {
|
|
277
|
-
|
|
443
|
+
fs4.mkdirSync(DEFAULT_WORKSPACE, { recursive: true });
|
|
278
444
|
const section = buildWorkspaceClaudeSection();
|
|
279
|
-
const current =
|
|
445
|
+
const current = fs4.existsSync(WORKSPACE_CLAUDE_MD) ? fs4.readFileSync(WORKSPACE_CLAUDE_MD, "utf8") : "";
|
|
280
446
|
const startIndex = current.indexOf(CLAUDE_MD_SECTION_START);
|
|
281
447
|
const endIndex = current.indexOf(CLAUDE_MD_SECTION_END);
|
|
282
448
|
if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
|
|
@@ -285,7 +451,7 @@ function ensureWorkspaceClaudeMd() {
|
|
|
285
451
|
${section}
|
|
286
452
|
|
|
287
453
|
${current.slice(endIndex + CLAUDE_MD_SECTION_END.length).trimStart()}`;
|
|
288
|
-
|
|
454
|
+
fs4.writeFileSync(WORKSPACE_CLAUDE_MD, next2.trimEnd() + "\n");
|
|
289
455
|
return;
|
|
290
456
|
}
|
|
291
457
|
const next = current.trim() ? `${current.trimEnd()}
|
|
@@ -293,7 +459,7 @@ ${current.slice(endIndex + CLAUDE_MD_SECTION_END.length).trimStart()}`;
|
|
|
293
459
|
${section}
|
|
294
460
|
` : `${section}
|
|
295
461
|
`;
|
|
296
|
-
|
|
462
|
+
fs4.writeFileSync(WORKSPACE_CLAUDE_MD, next);
|
|
297
463
|
}
|
|
298
464
|
function buildWorkspaceClaudeSection() {
|
|
299
465
|
return [
|
|
@@ -303,7 +469,7 @@ function buildWorkspaceClaudeSection() {
|
|
|
303
469
|
`- Agent identity: ${EMPLOYEE_NAME} (${EMPLOYEE_ID}).`,
|
|
304
470
|
`- Default workspace: \`${DEFAULT_WORKSPACE}\`.`,
|
|
305
471
|
`- Default managed session state: \`${STATE_FILE}\`.`,
|
|
306
|
-
`- Daily memory files: \`${
|
|
472
|
+
`- Daily memory files: \`${path5.join(DAILY_RECORDS_DIR, "YYYY-MM-DD.md")}\`.`,
|
|
307
473
|
`- Claude hook settings: \`${CLAUDE_HOOK_SETTINGS}\`.`,
|
|
308
474
|
"",
|
|
309
475
|
"### Conversation Responsibility",
|
|
@@ -337,10 +503,10 @@ function ensureClaudeHookFiles() {
|
|
|
337
503
|
if (!CLAUDE_HOOKS_ENABLED) {
|
|
338
504
|
return;
|
|
339
505
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
506
|
+
fs4.mkdirSync(HOOKS_DIR, { recursive: true });
|
|
507
|
+
fs4.writeFileSync(CLAUDE_HOOK_SCRIPT, CLAUDE_HOOK_SCRIPT_CONTENT);
|
|
508
|
+
fs4.chmodSync(CLAUDE_HOOK_SCRIPT, 493);
|
|
509
|
+
fs4.writeFileSync(CLAUDE_HOOK_SETTINGS, JSON.stringify(buildClaudeHookSettings(), null, 2));
|
|
344
510
|
}
|
|
345
511
|
function buildHookCommand() {
|
|
346
512
|
return `${shellQuote(process.execPath)} ${shellQuote(CLAUDE_HOOK_SCRIPT)}`;
|
|
@@ -365,10 +531,10 @@ function buildClaudeHookSettings() {
|
|
|
365
531
|
}
|
|
366
532
|
|
|
367
533
|
// src/runner.ts
|
|
368
|
-
import { spawn } from "node:child_process";
|
|
369
|
-
import
|
|
534
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
535
|
+
import fs5 from "node:fs";
|
|
370
536
|
import os2 from "node:os";
|
|
371
|
-
import
|
|
537
|
+
import path6 from "node:path";
|
|
372
538
|
import readline from "node:readline";
|
|
373
539
|
function resolveWorkspace(raw) {
|
|
374
540
|
if (!raw || !raw.trim()) {
|
|
@@ -376,13 +542,13 @@ function resolveWorkspace(raw) {
|
|
|
376
542
|
}
|
|
377
543
|
let resolved = raw.trim();
|
|
378
544
|
if (resolved.startsWith("~")) {
|
|
379
|
-
resolved =
|
|
545
|
+
resolved = path6.join(os2.homedir(), resolved.slice(1));
|
|
380
546
|
}
|
|
381
|
-
if (!
|
|
382
|
-
resolved =
|
|
547
|
+
if (!path6.isAbsolute(resolved)) {
|
|
548
|
+
resolved = path6.join(DEFAULT_WORKSPACE, resolved);
|
|
383
549
|
}
|
|
384
|
-
if (!
|
|
385
|
-
|
|
550
|
+
if (!fs5.existsSync(resolved)) {
|
|
551
|
+
fs5.mkdirSync(resolved, { recursive: true });
|
|
386
552
|
}
|
|
387
553
|
return resolved;
|
|
388
554
|
}
|
|
@@ -575,7 +741,7 @@ function runClaudeTask(taskId, prompt, workspace, deps) {
|
|
|
575
741
|
const agentState2 = getAgentState();
|
|
576
742
|
const args = buildClaudeArgs(prompt, currentTask, agentState2);
|
|
577
743
|
const resolvedWorkspace = resolveWorkspace(workspace);
|
|
578
|
-
const child =
|
|
744
|
+
const child = spawn2("claude", args, {
|
|
579
745
|
cwd: resolvedWorkspace,
|
|
580
746
|
env: {
|
|
581
747
|
...process.env,
|
|
@@ -879,6 +1045,7 @@ function connect(state, getMainTask, getQueueTask, onMessage) {
|
|
|
879
1045
|
}
|
|
880
1046
|
|
|
881
1047
|
// src/index.ts
|
|
1048
|
+
var PKG_VERSION = "0.2.0";
|
|
882
1049
|
var mainTask = null;
|
|
883
1050
|
var queueTask = null;
|
|
884
1051
|
var agentState = loadState();
|
|
@@ -1055,17 +1222,52 @@ function gracefulShutdown(signal) {
|
|
|
1055
1222
|
}
|
|
1056
1223
|
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
|
|
1057
1224
|
process.on("SIGINT", () => gracefulShutdown("SIGINT"));
|
|
1058
|
-
var isCli = process.argv[1] &&
|
|
1225
|
+
var isCli = process.argv[1] && fs6.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
1059
1226
|
if (isCli) {
|
|
1227
|
+
let getArgValue = function(name) {
|
|
1228
|
+
const idx = args.indexOf(name);
|
|
1229
|
+
if (idx === -1) return void 0;
|
|
1230
|
+
return args[idx + 1];
|
|
1231
|
+
}, resolveWorkspace2 = function() {
|
|
1232
|
+
return getArgValue("--workspace") || process.env.DEFAULT_WORKSPACE || process.cwd();
|
|
1233
|
+
}, resolveAgentDir = function() {
|
|
1234
|
+
const ws = resolveWorkspace2();
|
|
1235
|
+
const id = getArgValue("--id") || process.env.EMPLOYEE_ID || "emp_local";
|
|
1236
|
+
return path7.join(ws, ".ai-teams", "agents", id);
|
|
1237
|
+
}, resolvePidFile = function() {
|
|
1238
|
+
return path7.join(resolveAgentDir(), "agent.pid");
|
|
1239
|
+
}, resolveLogDir = function() {
|
|
1240
|
+
return path7.join(resolveAgentDir(), "logs");
|
|
1241
|
+
}, applyCliArgsToEnv = function() {
|
|
1242
|
+
const cliServer = getArgValue("--server");
|
|
1243
|
+
const cliToken = getArgValue("--token");
|
|
1244
|
+
const cliId = getArgValue("--id");
|
|
1245
|
+
const cliName = getArgValue("--name");
|
|
1246
|
+
const cliWorkspace = getArgValue("--workspace");
|
|
1247
|
+
const cliRunner = getArgValue("--runner");
|
|
1248
|
+
if (cliServer) process.env.SERVER_URL = cliServer;
|
|
1249
|
+
if (cliToken) process.env.AI_TEAMS_AUTH_TOKEN = cliToken;
|
|
1250
|
+
if (cliId) process.env.EMPLOYEE_ID = cliId;
|
|
1251
|
+
if (cliName) process.env.EMPLOYEE_NAME = cliName;
|
|
1252
|
+
if (cliWorkspace) process.env.DEFAULT_WORKSPACE = cliWorkspace;
|
|
1253
|
+
if (cliRunner) process.env.RUNNER_MODE = cliRunner;
|
|
1254
|
+
};
|
|
1255
|
+
getArgValue2 = getArgValue, resolveWorkspace3 = resolveWorkspace2, resolveAgentDir2 = resolveAgentDir, resolvePidFile2 = resolvePidFile, resolveLogDir2 = resolveLogDir, applyCliArgsToEnv2 = applyCliArgsToEnv;
|
|
1060
1256
|
const args = process.argv.slice(2);
|
|
1061
1257
|
if (args.includes("--version") || args.includes("-v")) {
|
|
1062
|
-
console.log(
|
|
1258
|
+
console.log(PKG_VERSION);
|
|
1063
1259
|
process.exit(0);
|
|
1064
1260
|
}
|
|
1065
1261
|
if (args.includes("--help") || args.includes("-h")) {
|
|
1066
1262
|
console.log(`ai-teams-agent \u2014 AI Teams \u5458\u5DE5\u4EE3\u7406
|
|
1067
1263
|
|
|
1068
|
-
\u7528\u6CD5: ai-teams-agent [\u9009\u9879]
|
|
1264
|
+
\u7528\u6CD5: ai-teams-agent <command> [\u9009\u9879]
|
|
1265
|
+
|
|
1266
|
+
\u547D\u4EE4:
|
|
1267
|
+
start [\u9009\u9879] \u540E\u53F0\u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B
|
|
1268
|
+
stop \u505C\u6B62\u5B88\u62A4\u8FDB\u7A0B
|
|
1269
|
+
restart [\u9009\u9879] \u91CD\u542F\u5B88\u62A4\u8FDB\u7A0B
|
|
1270
|
+
status \u67E5\u770B\u8FD0\u884C\u72B6\u6001
|
|
1069
1271
|
|
|
1070
1272
|
\u9009\u9879:
|
|
1071
1273
|
--server <url> \u670D\u52A1\u5668\u5730\u5740
|
|
@@ -1077,6 +1279,8 @@ if (isCli) {
|
|
|
1077
1279
|
--config \u91CD\u65B0\u8FD0\u884C\u914D\u7F6E\u5411\u5BFC
|
|
1078
1280
|
-v, --version \u663E\u793A\u7248\u672C\u53F7
|
|
1079
1281
|
-h, --help \u663E\u793A\u5E2E\u52A9
|
|
1282
|
+
|
|
1283
|
+
\u4E0D\u5E26\u547D\u4EE4\u76F4\u63A5\u8FD0\u884C\u65F6\u4E3A\u524D\u53F0\u6A21\u5F0F\u3002
|
|
1080
1284
|
`);
|
|
1081
1285
|
process.exit(0);
|
|
1082
1286
|
}
|
|
@@ -1086,35 +1290,64 @@ if (isCli) {
|
|
|
1086
1290
|
process.exit(0);
|
|
1087
1291
|
});
|
|
1088
1292
|
} else {
|
|
1089
|
-
|
|
1293
|
+
const subcommand = args[0];
|
|
1294
|
+
if (subcommand === "start" || subcommand === "restart") {
|
|
1295
|
+
if (subcommand === "restart") {
|
|
1296
|
+
const pidFile = resolvePidFile();
|
|
1297
|
+
const status = getDaemonStatus(pidFile);
|
|
1298
|
+
if (status.running) {
|
|
1299
|
+
void stopDaemon(pidFile);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
applyCliArgsToEnv();
|
|
1090
1303
|
const fileConfig2 = loadConfigFile();
|
|
1091
1304
|
const hasEnvConfig = process.env.AI_TEAMS_AUTH_TOKEN || process.env.SERVER_URL;
|
|
1092
1305
|
if (!fileConfig2 && !hasEnvConfig) {
|
|
1093
|
-
console.log("\n \u26A0 \u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\u4E14\u672A\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF\uFF0C\
|
|
1094
|
-
|
|
1306
|
+
console.log("\n \u26A0 \u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\u4E14\u672A\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF\uFF0C\u8BF7\u5148\u8FD0\u884C --config \u914D\u7F6E\u3002\n");
|
|
1307
|
+
process.exit(1);
|
|
1095
1308
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1309
|
+
void (async () => {
|
|
1310
|
+
await daemonize({
|
|
1311
|
+
name: "ai-teams-agent",
|
|
1312
|
+
pidFile: resolvePidFile(),
|
|
1313
|
+
logFile: path7.join(resolveLogDir(), "agent.log"),
|
|
1314
|
+
run: async () => {
|
|
1315
|
+
console.log(" \u2713 \u6B63\u5728\u8FDE\u63A5\u670D\u52A1\u5668...");
|
|
1316
|
+
connect2();
|
|
1317
|
+
}
|
|
1318
|
+
});
|
|
1319
|
+
})();
|
|
1320
|
+
} else if (subcommand === "stop") {
|
|
1321
|
+
void stopDaemon(resolvePidFile());
|
|
1322
|
+
} else if (subcommand === "status") {
|
|
1323
|
+
const status = getDaemonStatus(resolvePidFile());
|
|
1324
|
+
if (status.running) {
|
|
1325
|
+
console.log(`ai-teams-agent is running (PID ${status.pid})`);
|
|
1326
|
+
console.log(`Log: ${path7.join(resolveLogDir(), "agent.log")}`);
|
|
1327
|
+
} else {
|
|
1328
|
+
console.log("ai-teams-agent is not running.");
|
|
1100
1329
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
connect2();
|
|
1115
|
-
})();
|
|
1330
|
+
} else {
|
|
1331
|
+
void (async () => {
|
|
1332
|
+
const fileConfig2 = loadConfigFile();
|
|
1333
|
+
const hasEnvConfig = process.env.AI_TEAMS_AUTH_TOKEN || process.env.SERVER_URL;
|
|
1334
|
+
if (!fileConfig2 && !hasEnvConfig) {
|
|
1335
|
+
console.log("\n \u26A0 \u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\u4E14\u672A\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF\uFF0C\u542F\u52A8\u914D\u7F6E\u5411\u5BFC...\n");
|
|
1336
|
+
await runSetup(null);
|
|
1337
|
+
}
|
|
1338
|
+
applyCliArgsToEnv();
|
|
1339
|
+
console.log(" \u2713 \u6B63\u5728\u8FDE\u63A5\u670D\u52A1\u5668...");
|
|
1340
|
+
connect2();
|
|
1341
|
+
})();
|
|
1342
|
+
}
|
|
1116
1343
|
}
|
|
1117
1344
|
}
|
|
1345
|
+
var getArgValue2;
|
|
1346
|
+
var resolveWorkspace3;
|
|
1347
|
+
var resolveAgentDir2;
|
|
1348
|
+
var resolvePidFile2;
|
|
1349
|
+
var resolveLogDir2;
|
|
1350
|
+
var applyCliArgsToEnv2;
|
|
1118
1351
|
export {
|
|
1119
1352
|
connect2 as connect
|
|
1120
1353
|
};
|