@csdwd/ai-teams-server 0.3.4 → 0.3.6

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 CHANGED
@@ -36,7 +36,9 @@ function parseLeaderToServerMessage(value) {
36
36
  atAgents: agentTargetField(message, "atAgents"),
37
37
  prompt: nonEmptyStringField(message, "prompt"),
38
38
  workspace: optionalStringField(message, "workspace"),
39
- timeoutSec: optionalPositiveNumberField(message, "timeoutSec")
39
+ timeoutSec: optionalPositiveNumberField(message, "timeoutSec"),
40
+ priority: optionalNonNegativeNumberField(message, "priority"),
41
+ requiredLabels: optionalStringArrayField(message, "requiredLabels")
40
42
  };
41
43
  }
42
44
  if (type === "command.send") {
@@ -175,6 +177,15 @@ function stringArrayField(record, key) {
175
177
  }
176
178
  return value;
177
179
  }
180
+ function optionalStringArrayField(record, key) {
181
+ const value = record[key];
182
+ if (value === void 0)
183
+ return void 0;
184
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
185
+ throw new ProtocolError(`${key} must be a string array.`);
186
+ }
187
+ return value;
188
+ }
178
189
  function agentTargetField(record, key) {
179
190
  const value = record[key];
180
191
  if (value === "queue") {
@@ -508,7 +519,8 @@ async function initDb(db) {
508
519
  usage_input_tokens INTEGER,
509
520
  usage_output_tokens INTEGER,
510
521
  usage_cache_read_tokens INTEGER,
511
- usage_cache_creation_tokens INTEGER
522
+ usage_cache_creation_tokens INTEGER,
523
+ retry_count INTEGER NOT NULL DEFAULT 0
512
524
  )
513
525
  `);
514
526
  await db.run(`
@@ -559,6 +571,10 @@ async function initDb(db) {
559
571
  updated_at TEXT NOT NULL
560
572
  )
561
573
  `);
574
+ try {
575
+ await db.run("ALTER TABLE tasks ADD COLUMN retry_count INTEGER NOT NULL DEFAULT 0");
576
+ } catch {
577
+ }
562
578
  }
563
579
  async function hydrateState(db, state, defaultTimeoutSec, maxLogChunksPerTask) {
564
580
  const employeeRows = await db.all("SELECT payload_json FROM employees");
@@ -575,13 +591,13 @@ async function hydrateState(db, state, defaultTimeoutSec, maxLogChunksPerTask) {
575
591
  if (task.targetMode === "queue" || !task.employeeId) {
576
592
  state.sharedTaskQueue.push(task.id);
577
593
  } else {
578
- const queue = state.taskQueues.get(task.employeeId) ?? [];
594
+ const queue = state.mainTaskQueues.get(task.employeeId) ?? [];
579
595
  queue.push(task.id);
580
- state.taskQueues.set(task.employeeId, queue);
596
+ state.mainTaskQueues.set(task.employeeId, queue);
581
597
  }
582
598
  } else if (task.employeeId && !TERMINAL_STATUSES.has(task.status)) {
583
599
  task.status = "queued";
584
- persistTask(db, task);
600
+ await persistTask(db, task);
585
601
  if (task.targetMode === "queue") {
586
602
  state.sharedTaskQueue.push(task.id);
587
603
  } else {
@@ -637,6 +653,7 @@ var TASK_COLUMNS = [
637
653
  "cli_config",
638
654
  "priority",
639
655
  "required_labels",
656
+ "retry_count",
640
657
  "created_at",
641
658
  "started_at",
642
659
  "finished_at",
@@ -731,11 +748,38 @@ async function deleteTask(db, taskId) {
731
748
  await db.run("DELETE FROM tasks WHERE id = $1", [taskId]);
732
749
  return true;
733
750
  }
751
+ var UPDATABLE_TASK_FIELDS = /* @__PURE__ */ new Set([
752
+ "status",
753
+ "timeoutSec",
754
+ "cliConfig",
755
+ "priority",
756
+ "requiredLabels",
757
+ "prompt",
758
+ "workspace",
759
+ "employeeId",
760
+ "sessionId",
761
+ "exitCode",
762
+ "summary",
763
+ "error",
764
+ "durationMs",
765
+ "durationApiMs",
766
+ "numTurns",
767
+ "totalCostUsd",
768
+ "usageInputTokens",
769
+ "usageOutputTokens",
770
+ "usageCacheReadTokens",
771
+ "usageCacheCreationTokens"
772
+ ]);
734
773
  async function updateTaskFields(db, taskId, fields) {
735
- const entries = Object.entries(fields);
774
+ const entries = Object.entries(fields).filter(([key]) => UPDATABLE_TASK_FIELDS.has(key));
736
775
  if (entries.length === 0) return getTaskById(db, taskId);
737
776
  const setClauses = entries.map(([key], i) => `${toSnakeCase(key)} = $${i + 2}`).join(", ");
738
- const values = entries.map(([, val]) => val);
777
+ const values = entries.map(([key, val]) => {
778
+ if ((key === "cliConfig" || key === "requiredLabels") && val != null) {
779
+ return JSON.stringify(val);
780
+ }
781
+ return val;
782
+ });
739
783
  await db.run(
740
784
  `UPDATE tasks SET ${setClauses} WHERE id = $1`,
741
785
  [taskId, ...values]
@@ -756,6 +800,7 @@ function dbRowToTask(row, defaultTimeoutSec) {
756
800
  priority: row.priority ?? 1,
757
801
  requiredLabels: row.required_labels ? JSON.parse(row.required_labels) : null,
758
802
  status: row.status || "queued",
803
+ retryCount: row.retry_count ?? 0,
759
804
  createdAt: row.created_at,
760
805
  startedAt: row.started_at,
761
806
  finishedAt: row.finished_at,
@@ -786,6 +831,7 @@ function taskToDbValues(task) {
786
831
  task.cliConfig ? JSON.stringify(task.cliConfig) : null,
787
832
  task.priority,
788
833
  task.requiredLabels ? JSON.stringify(task.requiredLabels) : null,
834
+ task.retryCount,
789
835
  task.createdAt,
790
836
  task.startedAt,
791
837
  task.finishedAt,
@@ -1212,12 +1258,12 @@ var scheduleResponseSchema = {
1212
1258
  targetMode: { type: "string", enum: ["queue", "direct", "broadcast"] },
1213
1259
  targetAgents: { type: "array", items: { type: "string" } },
1214
1260
  prompt: { type: "string" },
1215
- workspace: { type: "string" },
1216
- timeoutSec: { type: "number" },
1261
+ workspace: nullableString,
1262
+ timeoutSec: nullableNumber,
1217
1263
  priority: { type: "integer" },
1218
- requiredLabels: { type: "array", items: { type: "string" } },
1219
- lastRunAt: { type: "string" },
1220
- nextRunAt: { type: "string" },
1264
+ requiredLabels: { anyOf: [{ type: "array", items: { type: "string" } }, { type: "null" }] },
1265
+ lastRunAt: nullableString,
1266
+ nextRunAt: nullableString,
1221
1267
  createdAt: { type: "string" },
1222
1268
  updatedAt: { type: "string" }
1223
1269
  }
@@ -1248,6 +1294,7 @@ function extractDoneSessionId(content) {
1248
1294
  }
1249
1295
  function createDispatch(ctx) {
1250
1296
  const { state, db, log } = ctx;
1297
+ const retryDelays = /* @__PURE__ */ new Map();
1251
1298
  function broadcastToLeaders(payload) {
1252
1299
  for (const socket of state.leaderSockets) {
1253
1300
  sendJson(socket, payload, ctx.encryptor);
@@ -1515,13 +1562,14 @@ function createDispatch(ctx) {
1515
1562
  if (!employee || employee.queueTaskId || employee.status !== "online") {
1516
1563
  return;
1517
1564
  }
1518
- while (state.sharedTaskQueue.length > 0) {
1519
- const taskId = state.sharedTaskQueue.shift();
1565
+ for (let i = 0; i < state.sharedTaskQueue.length; i++) {
1566
+ const taskId = state.sharedTaskQueue[i];
1520
1567
  const task = state.tasks.get(taskId);
1521
- if (task && task.status === "queued" && task.targetMode === "queue") {
1522
- dispatchTask(task, employeeId);
1523
- return;
1524
- }
1568
+ if (!task || task.status !== "queued" || task.targetMode !== "queue") continue;
1569
+ if (retryDelays.has(taskId)) continue;
1570
+ state.sharedTaskQueue.splice(i, 1);
1571
+ dispatchTask(task, employeeId);
1572
+ return;
1525
1573
  }
1526
1574
  }
1527
1575
  function dispatchSharedQueuedTasks() {
@@ -1639,6 +1687,7 @@ function createDispatch(ctx) {
1639
1687
  priority: priority ?? 1,
1640
1688
  requiredLabels: requiredLabels ?? null,
1641
1689
  status: "queued",
1690
+ retryCount: 0,
1642
1691
  createdAt: nowIso(),
1643
1692
  startedAt: null,
1644
1693
  finishedAt: null,
@@ -1679,11 +1728,13 @@ function createDispatch(ctx) {
1679
1728
  }
1680
1729
  function dispatchLeaderCommand(message, webhookUrl, cliConfig, priority, requiredLabels) {
1681
1730
  const leaderCommandId = randomUUID();
1731
+ const resolvedPriority = message.priority ?? priority;
1732
+ const resolvedRequiredLabels = message.requiredLabels ?? requiredLabels;
1682
1733
  if (message.atAgents === "queue") {
1683
1734
  return {
1684
1735
  ok: true,
1685
1736
  leaderCommandId,
1686
- tasks: [createTask(null, message.prompt, message.workspace, message.timeoutSec, leaderCommandId, "queue", webhookUrl, cliConfig, message.priority, message.requiredLabels)]
1737
+ tasks: [createTask(null, message.prompt, message.workspace, message.timeoutSec, leaderCommandId, "queue", webhookUrl, cliConfig, resolvedPriority, resolvedRequiredLabels)]
1687
1738
  };
1688
1739
  }
1689
1740
  const targetIds = resolveTargetIds(message.atAgents);
@@ -1699,7 +1750,7 @@ function createDispatch(ctx) {
1699
1750
  ok: true,
1700
1751
  leaderCommandId,
1701
1752
  tasks: targetIds.map(
1702
- (employeeId) => createTask(employeeId, message.prompt, message.workspace, message.timeoutSec, leaderCommandId, targetMode, webhookUrl, cliConfig, message.priority, message.requiredLabels)
1753
+ (employeeId) => createTask(employeeId, message.prompt, message.workspace, message.timeoutSec, leaderCommandId, targetMode, webhookUrl, cliConfig, resolvedPriority, resolvedRequiredLabels)
1703
1754
  )
1704
1755
  };
1705
1756
  }
@@ -1714,6 +1765,15 @@ function createDispatch(ctx) {
1714
1765
  clearTimeout(disconnectTimer);
1715
1766
  state.disconnectTimers.delete(message.employeeId);
1716
1767
  }
1768
+ for (const prevTaskId of [previousMainTaskId, previousQueueTaskId]) {
1769
+ if (prevTaskId) {
1770
+ const timer = retryDelays.get(prevTaskId);
1771
+ if (timer) {
1772
+ clearTimeout(timer);
1773
+ retryDelays.delete(prevTaskId);
1774
+ }
1775
+ }
1776
+ }
1717
1777
  state.agentSockets.set(message.employeeId, socket);
1718
1778
  state.socketToEmployeeId.set(socket, message.employeeId);
1719
1779
  let mainTaskId = null;
@@ -1757,6 +1817,7 @@ function createDispatch(ctx) {
1757
1817
  if (!queueTaskId) {
1758
1818
  dispatchNextQueuedTask(message.employeeId);
1759
1819
  }
1820
+ dispatchSharedQueuedTasks();
1760
1821
  resetHeartbeatTimer(message.employeeId);
1761
1822
  }
1762
1823
  function taskBelongsToSocket(taskId, employeeId, socket) {
@@ -1983,10 +2044,19 @@ function createDispatch(ctx) {
1983
2044
  const task = state.tasks.get(taskId);
1984
2045
  if (!task || TERMINAL_STATUSES.has(task.status)) continue;
1985
2046
  clearTaskTimeout(taskId);
1986
- task.status = "queued";
1987
2047
  task.employeeId = null;
2048
+ task.retryCount += 1;
2049
+ if (task.retryCount > 3) {
2050
+ task.status = "failed";
2051
+ task.error = `\u4EFB\u52A1\u91CD\u8BD5\u6B21\u6570\u8D85\u8FC7\u4E0A\u9650\uFF083\u6B21\uFF09\uFF0C\u5DF2\u7EC8\u6B62\u3002`;
2052
+ task.finishedAt = nowIso();
2053
+ upsertTask(task);
2054
+ log.warn({ taskId, employeeId, retryCount: task.retryCount }, "Task exceeded max retry count, marked failed");
2055
+ continue;
2056
+ }
2057
+ task.status = "queued";
1988
2058
  upsertTask(task);
1989
- log.info({ taskId, employeeId }, "Task re-queued after disconnect grace period");
2059
+ log.info({ taskId, employeeId, retryCount: task.retryCount }, "Task re-queued after disconnect grace period");
1990
2060
  if (task.targetMode === "queue") {
1991
2061
  enqueueSharedTask(taskId);
1992
2062
  } else {
@@ -1994,6 +2064,16 @@ function createDispatch(ctx) {
1994
2064
  if (!queue.includes(taskId)) queue.push(taskId);
1995
2065
  state.mainTaskQueues.set(employeeId, queue);
1996
2066
  }
2067
+ if (task.retryCount > 1) {
2068
+ const retryDelay = (task.retryCount - 1) * 5e3;
2069
+ const existingDelay = retryDelays.get(taskId);
2070
+ if (existingDelay) clearTimeout(existingDelay);
2071
+ retryDelays.set(taskId, setTimeout(() => {
2072
+ retryDelays.delete(taskId);
2073
+ dispatchSharedQueuedTasks();
2074
+ dispatchNextMainQueuedTask(employeeId);
2075
+ }, retryDelay));
2076
+ }
1997
2077
  }
1998
2078
  const emp = state.employees.get(employeeId);
1999
2079
  if (emp) {
@@ -2014,7 +2094,13 @@ function createDispatch(ctx) {
2014
2094
  handleAgentMessage,
2015
2095
  handleLeaderMessage,
2016
2096
  cancelTaskById,
2017
- startDisconnectRecovery
2097
+ startDisconnectRecovery,
2098
+ cleanup() {
2099
+ for (const timer of retryDelays.values()) {
2100
+ clearTimeout(timer);
2101
+ }
2102
+ retryDelays.clear();
2103
+ }
2018
2104
  };
2019
2105
  }
2020
2106
 
@@ -2121,6 +2207,25 @@ function stopScheduleJob(jobs, scheduleId) {
2121
2207
  }
2122
2208
 
2123
2209
  // src/index.ts
2210
+ function scheduleToResponse(s) {
2211
+ return {
2212
+ id: s.id,
2213
+ name: s.name,
2214
+ cron: s.cronExpr,
2215
+ enabled: s.enabled,
2216
+ targetMode: s.targetMode,
2217
+ targetAgents: s.targetAgents,
2218
+ prompt: s.prompt,
2219
+ workspace: s.workspace,
2220
+ timeoutSec: s.timeoutSec,
2221
+ priority: s.priority,
2222
+ requiredLabels: s.requiredLabels,
2223
+ lastRunAt: s.lastRunAt,
2224
+ nextRunAt: s.nextRunAt,
2225
+ createdAt: s.createdAt,
2226
+ updatedAt: s.updatedAt
2227
+ };
2228
+ }
2124
2229
  var DEFAULT_PORT = 3789;
2125
2230
  function isAuthorized(authToken, rawUrl, headers) {
2126
2231
  const bearer = typeof headers.authorization === "string" ? headers.authorization : "";
@@ -2208,7 +2313,7 @@ async function createAiTeamsServer(options) {
2208
2313
  disconnectGraceMs,
2209
2314
  encryptor: createEncryptor(process.env.AI_TEAMS_ENCRYPTION_KEY)
2210
2315
  };
2211
- const { dispatchLeaderCommand, handleAgentMessage, handleLeaderMessage, cancelTaskById, startDisconnectRecovery } = createDispatch(dispatchCtx);
2316
+ const { dispatchLeaderCommand, handleAgentMessage, handleLeaderMessage, cancelTaskById, startDisconnectRecovery, cleanup: dispatchCleanup } = createDispatch(dispatchCtx);
2212
2317
  const scheduleDispatchFn = (message, webhookUrl, cliConfig, priority, requiredLabels) => {
2213
2318
  return dispatchLeaderCommand(message, webhookUrl, cliConfig, priority, requiredLabels);
2214
2319
  };
@@ -2653,7 +2758,7 @@ async function createAiTeamsServer(options) {
2653
2758
  },
2654
2759
  async () => {
2655
2760
  const schedules = await getAllSchedules(db);
2656
- return { schedules };
2761
+ return { schedules: schedules.map(scheduleToResponse) };
2657
2762
  }
2658
2763
  );
2659
2764
  app.get(
@@ -2669,7 +2774,7 @@ async function createAiTeamsServer(options) {
2669
2774
  async (request, reply) => {
2670
2775
  const schedule = await getScheduleById(db, request.params.scheduleId);
2671
2776
  if (!schedule) return reply.code(404).send({ error: "Schedule not found." });
2672
- return schedule;
2777
+ return scheduleToResponse(schedule);
2673
2778
  }
2674
2779
  );
2675
2780
  app.post(
@@ -2709,7 +2814,7 @@ async function createAiTeamsServer(options) {
2709
2814
  schedule.nextRunAt = state.scheduleJobs.get(id)?.nextDate()?.toISO() ?? null;
2710
2815
  }
2711
2816
  await upsertSchedule(db, schedule);
2712
- return reply.code(201).send(schedule);
2817
+ return reply.code(201).send(scheduleToResponse(schedule));
2713
2818
  } catch (err) {
2714
2819
  stopScheduleJob(state.scheduleJobs, id);
2715
2820
  return reply.code(400).send({ error: err instanceof Error ? err.message : "Invalid schedule." });
@@ -2724,7 +2829,7 @@ async function createAiTeamsServer(options) {
2724
2829
  summary: "Update a schedule",
2725
2830
  params: { type: "object", required: ["scheduleId"], properties: { scheduleId: { type: "string", minLength: 1 } } },
2726
2831
  body: updateScheduleRequestSchema,
2727
- response: { 200: scheduleResponseSchema, 404: errorResponseSchema, 401: errorResponseSchema }
2832
+ response: { 200: scheduleResponseSchema, 400: errorResponseSchema, 404: errorResponseSchema, 401: errorResponseSchema }
2728
2833
  }
2729
2834
  },
2730
2835
  async (request, reply) => {
@@ -2743,13 +2848,18 @@ async function createAiTeamsServer(options) {
2743
2848
  if (request.body.requiredLabels !== void 0) fields.requiredLabels = request.body.requiredLabels;
2744
2849
  const updated = await updateScheduleFields(db, request.params.scheduleId, fields);
2745
2850
  if (!updated) return reply.code(404).send({ error: "Schedule not found." });
2746
- stopScheduleJob(state.scheduleJobs, request.params.scheduleId);
2747
- if (updated.enabled) {
2748
- startScheduleJob(updated, scheduleDispatchFn, state.scheduleJobs, onScheduleFire);
2749
- updated.nextRunAt = state.scheduleJobs.get(request.params.scheduleId)?.nextDate()?.toISO() ?? null;
2750
- await updateScheduleFields(db, request.params.scheduleId, { nextRunAt: updated.nextRunAt });
2851
+ try {
2852
+ stopScheduleJob(state.scheduleJobs, request.params.scheduleId);
2853
+ if (updated.enabled) {
2854
+ startScheduleJob(updated, scheduleDispatchFn, state.scheduleJobs, onScheduleFire);
2855
+ updated.nextRunAt = state.scheduleJobs.get(request.params.scheduleId)?.nextDate()?.toISO() ?? null;
2856
+ await updateScheduleFields(db, request.params.scheduleId, { nextRunAt: updated.nextRunAt });
2857
+ }
2858
+ return scheduleToResponse(updated);
2859
+ } catch (err) {
2860
+ stopScheduleJob(state.scheduleJobs, request.params.scheduleId);
2861
+ return reply.code(400).send({ error: err instanceof Error ? err.message : "Invalid schedule." });
2751
2862
  }
2752
- return updated;
2753
2863
  }
2754
2864
  );
2755
2865
  app.delete(
@@ -2780,7 +2890,7 @@ async function createAiTeamsServer(options) {
2780
2890
  tags: ["schedules"],
2781
2891
  summary: "Manually trigger a schedule",
2782
2892
  params: { type: "object", required: ["scheduleId"], properties: { scheduleId: { type: "string", minLength: 1 } } },
2783
- response: { 200: scheduleResponseSchema, 404: errorResponseSchema, 401: errorResponseSchema }
2893
+ response: { 200: scheduleResponseSchema, 400: errorResponseSchema, 404: errorResponseSchema, 401: errorResponseSchema }
2784
2894
  }
2785
2895
  },
2786
2896
  async (request, reply) => {
@@ -2796,7 +2906,9 @@ async function createAiTeamsServer(options) {
2796
2906
  );
2797
2907
  if (!result.ok) return reply.code(400).send({ error: result.message });
2798
2908
  await onScheduleFire(request.params.scheduleId);
2799
- return await getScheduleById(db, request.params.scheduleId);
2909
+ const updated = await getScheduleById(db, request.params.scheduleId);
2910
+ if (!updated) return reply.code(404).send({ error: "Schedule not found." });
2911
+ return scheduleToResponse(updated);
2800
2912
  }
2801
2913
  );
2802
2914
  app.get("/ws/agent", { websocket: true }, (socket, request) => {
@@ -2886,8 +2998,9 @@ async function createAiTeamsServer(options) {
2886
2998
  for (const timer of state.heartbeatTimers.values()) {
2887
2999
  clearTimeout(timer);
2888
3000
  }
3001
+ dispatchCleanup();
2889
3002
  await app.close();
2890
- db.close();
3003
+ await db.close();
2891
3004
  }
2892
3005
  };
2893
3006
  }
@@ -2965,7 +3078,7 @@ if (isCli) {
2965
3078
  getArgValue2 = getArgValue, loadServerConfig2 = loadServerConfig, saveServerConfig2 = saveServerConfig, resolveDataDir2 = resolveDataDir, resolvePidFile2 = resolvePidFile, resolveLogDir2 = resolveLogDir, applyCliArgsToEnv2 = applyCliArgsToEnv;
2966
3079
  const args = process.argv.slice(2);
2967
3080
  if (args.includes("--version") || args.includes("-v")) {
2968
- console.log("0.3.4");
3081
+ console.log("0.3.6");
2969
3082
  process.exit(0);
2970
3083
  }
2971
3084
  if (args.includes("--help") || args.includes("-h")) {
@@ -3000,19 +3113,21 @@ if (isCli) {
3000
3113
  const subcommand = args[0];
3001
3114
  if (subcommand === "start" || subcommand === "restart") {
3002
3115
  void (async () => {
3003
- if (subcommand === "restart") {
3004
- const status = getDaemonStatus(resolvePidFile());
3005
- if (status.running) {
3006
- await stopDaemon(resolvePidFile());
3007
- }
3008
- } else if (!process.env.__AI_TEAMS_DAEMON_WATCHDOG && !process.env.__AI_TEAMS_DAEMON_WORKER) {
3009
- const status = getDaemonStatus(resolvePidFile());
3010
- if (status.running) {
3011
- console.log(`Already running (PID ${status.pid}).`);
3012
- process.exit(0);
3116
+ applyCliArgsToEnv();
3117
+ if (!process.env.__AI_TEAMS_DAEMON_WATCHDOG && !process.env.__AI_TEAMS_DAEMON_WORKER) {
3118
+ if (subcommand === "restart") {
3119
+ const status = getDaemonStatus(resolvePidFile());
3120
+ if (status.running) {
3121
+ await stopDaemon(resolvePidFile());
3122
+ }
3123
+ } else {
3124
+ const status = getDaemonStatus(resolvePidFile());
3125
+ if (status.running) {
3126
+ console.log(`Already running (PID ${status.pid}).`);
3127
+ process.exit(0);
3128
+ }
3013
3129
  }
3014
3130
  }
3015
- applyCliArgsToEnv();
3016
3131
  if (!process.env.AI_TEAMS_AUTH_TOKEN) {
3017
3132
  console.error("\u9519\u8BEF: \u9700\u8981\u8BA4\u8BC1 Token\u3002\u4F7F\u7528 --token <token> \u6216\u8BBE\u7F6E AI_TEAMS_AUTH_TOKEN \u73AF\u5883\u53D8\u91CF\u3002");
3018
3133
  process.exit(1);