@csdwd/ai-teams-agent 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +308 -75
  2. 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 fs5 from "node:fs";
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 path2 from "node:path";
176
+ import path3 from "node:path";
11
177
 
12
178
  // src/setup.ts
13
- import fs from "node:fs";
14
- import path from "node:path";
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 = path.join(os.homedir(), ".ai-teams");
19
- var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
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 = fs.readFileSync(CONFIG_FILE, "utf8");
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
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
30
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
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 || path2.join(DEFAULT_WORKSPACE, ".ai-teams", "agents", EMPLOYEE_ID);
74
- var STATE_FILE = process.env.AGENT_STATE_FILE || path2.join(AGENT_RECORDS_DIR, "session-state.json");
75
- var LEGACY_STATE_FILE = path2.join(process.cwd(), `.agent-state.${EMPLOYEE_ID}.json`);
76
- var DAILY_RECORDS_DIR = path2.join(AGENT_RECORDS_DIR, "daily");
77
- var HOOKS_DIR = path2.join(AGENT_RECORDS_DIR, "hooks");
78
- var CLAUDE_HOOK_SCRIPT = path2.join(HOOKS_DIR, "claude-session-recorder.cjs");
79
- var CLAUDE_HOOK_SETTINGS = path2.join(HOOKS_DIR, "claude-hooks.settings.json");
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 = path2.join(DEFAULT_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 fs2 from "node:fs";
87
- import path3 from "node:path";
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 = fs2.readFileSync(STATE_FILE, "utf8");
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 || !fs2.existsSync(LEGACY_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(fs2.readFileSync(LEGACY_STATE_FILE, "utf8"));
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
- fs2.mkdirSync(path3.dirname(STATE_FILE), { recursive: true });
124
- fs2.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
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 fs3 from "node:fs";
134
- import path4 from "node:path";
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
- fs3.mkdirSync(DAILY_RECORDS_DIR, { recursive: true });
237
- const filePath = path4.join(DAILY_RECORDS_DIR, `${localDateKey()}.md`);
238
- if (!fs3.existsSync(filePath)) {
239
- fs3.writeFileSync(filePath, `# ${EMPLOYEE_NAME} Daily Activity - ${localDateKey()}
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
- fs3.appendFileSync(filePath, markdown);
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
- fs3.mkdirSync(DEFAULT_WORKSPACE, { recursive: true });
443
+ fs4.mkdirSync(DEFAULT_WORKSPACE, { recursive: true });
278
444
  const section = buildWorkspaceClaudeSection();
279
- const current = fs3.existsSync(WORKSPACE_CLAUDE_MD) ? fs3.readFileSync(WORKSPACE_CLAUDE_MD, "utf8") : "";
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
- fs3.writeFileSync(WORKSPACE_CLAUDE_MD, next2.trimEnd() + "\n");
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
- fs3.writeFileSync(WORKSPACE_CLAUDE_MD, next);
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: \`${path4.join(DAILY_RECORDS_DIR, "YYYY-MM-DD.md")}\`.`,
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
- fs3.mkdirSync(HOOKS_DIR, { recursive: true });
341
- fs3.writeFileSync(CLAUDE_HOOK_SCRIPT, CLAUDE_HOOK_SCRIPT_CONTENT);
342
- fs3.chmodSync(CLAUDE_HOOK_SCRIPT, 493);
343
- fs3.writeFileSync(CLAUDE_HOOK_SETTINGS, JSON.stringify(buildClaudeHookSettings(), null, 2));
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 fs4 from "node:fs";
534
+ import { spawn as spawn2 } from "node:child_process";
535
+ import fs5 from "node:fs";
370
536
  import os2 from "node:os";
371
- import path5 from "node:path";
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 = path5.join(os2.homedir(), resolved.slice(1));
545
+ resolved = path6.join(os2.homedir(), resolved.slice(1));
380
546
  }
381
- if (!path5.isAbsolute(resolved)) {
382
- resolved = path5.join(DEFAULT_WORKSPACE, resolved);
547
+ if (!path6.isAbsolute(resolved)) {
548
+ resolved = path6.join(DEFAULT_WORKSPACE, resolved);
383
549
  }
384
- if (!fs4.existsSync(resolved)) {
385
- fs4.mkdirSync(resolved, { recursive: true });
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 = spawn("claude", args, {
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] && fs5.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url);
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("0.2.0");
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
- void (async () => {
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\u542F\u52A8\u914D\u7F6E\u5411\u5BFC...\n");
1094
- await runSetup(null);
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
- function getArgValue(name) {
1097
- const idx = args.indexOf(name);
1098
- if (idx === -1) return void 0;
1099
- return args[idx + 1];
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
- const cliServer = getArgValue("--server");
1102
- const cliToken = getArgValue("--token");
1103
- const cliId = getArgValue("--id");
1104
- const cliName = getArgValue("--name");
1105
- const cliWorkspace = getArgValue("--workspace");
1106
- const cliRunner = getArgValue("--runner");
1107
- if (cliServer) process.env.SERVER_URL = cliServer;
1108
- if (cliToken) process.env.AI_TEAMS_AUTH_TOKEN = cliToken;
1109
- if (cliId) process.env.EMPLOYEE_ID = cliId;
1110
- if (cliName) process.env.EMPLOYEE_NAME = cliName;
1111
- if (cliWorkspace) process.env.DEFAULT_WORKSPACE = cliWorkspace;
1112
- if (cliRunner) process.env.RUNNER_MODE = cliRunner;
1113
- console.log(` \u2713 \u6B63\u5728\u8FDE\u63A5\u670D\u52A1\u5668...`);
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@csdwd/ai-teams-agent",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "AI Teams agent — connects to server via WebSocket, spawns Claude CLI to execute tasks",
5
5
  "type": "module",
6
6
  "bin": {