@csdwd/ai-teams-server 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +56 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ import websocket from "@fastify/websocket";
13
13
  import fastifyStatic from "@fastify/static";
14
14
 
15
15
  // ../../packages/shared/dist/index.js
16
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "timeout"]);
16
17
  var ProtocolError = class extends Error {
17
18
  constructor(message) {
18
19
  super(message);
@@ -578,6 +579,16 @@ async function hydrateState(db, state, defaultTimeoutSec, maxLogChunksPerTask) {
578
579
  queue.push(task.id);
579
580
  state.taskQueues.set(task.employeeId, queue);
580
581
  }
582
+ } else if (task.employeeId && !TERMINAL_STATUSES.has(task.status)) {
583
+ task.status = "queued";
584
+ persistTask(db, task);
585
+ if (task.targetMode === "queue") {
586
+ state.sharedTaskQueue.push(task.id);
587
+ } else {
588
+ const queue = state.mainTaskQueues.get(task.employeeId) ?? [];
589
+ queue.push(task.id);
590
+ state.mainTaskQueues.set(task.employeeId, queue);
591
+ }
581
592
  }
582
593
  }
583
594
  const logRows = await db.all(
@@ -1222,7 +1233,6 @@ var scheduleListResponseSchema = {
1222
1233
  // src/dispatch.ts
1223
1234
  import { createHmac, randomUUID } from "node:crypto";
1224
1235
  import WebSocket from "ws";
1225
- var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "timeout"]);
1226
1236
  function nowIso() {
1227
1237
  return (/* @__PURE__ */ new Date()).toISOString();
1228
1238
  }
@@ -1959,11 +1969,52 @@ function createDispatch(ctx) {
1959
1969
  break;
1960
1970
  }
1961
1971
  }
1972
+ function startDisconnectRecovery(employeeId) {
1973
+ const employee = state.employees.get(employeeId);
1974
+ if (!employee) return;
1975
+ const taskIds = [];
1976
+ if (employee.mainTaskId) taskIds.push(employee.mainTaskId);
1977
+ if (employee.queueTaskId) taskIds.push(employee.queueTaskId);
1978
+ if (taskIds.length === 0) return;
1979
+ const timer = setTimeout(() => {
1980
+ state.disconnectTimers.delete(employeeId);
1981
+ if (state.agentSockets.has(employeeId)) return;
1982
+ for (const taskId of taskIds) {
1983
+ const task = state.tasks.get(taskId);
1984
+ if (!task || TERMINAL_STATUSES.has(task.status)) continue;
1985
+ clearTaskTimeout(taskId);
1986
+ task.status = "queued";
1987
+ task.employeeId = null;
1988
+ upsertTask(task);
1989
+ log.info({ taskId, employeeId }, "Task re-queued after disconnect grace period");
1990
+ if (task.targetMode === "queue") {
1991
+ enqueueSharedTask(taskId);
1992
+ } else {
1993
+ const queue = state.mainTaskQueues.get(employeeId) ?? [];
1994
+ if (!queue.includes(taskId)) queue.push(taskId);
1995
+ state.mainTaskQueues.set(employeeId, queue);
1996
+ }
1997
+ }
1998
+ const emp = state.employees.get(employeeId);
1999
+ if (emp) {
2000
+ if (taskIds.includes(emp.mainTaskId ?? "")) setMainTask(employeeId, null, null);
2001
+ if (taskIds.includes(emp.queueTaskId ?? "")) setQueueTask(employeeId, null, null);
2002
+ broadcastToLeaders({ type: "employee.upsert", employee: emp });
2003
+ }
2004
+ for (const taskId of taskIds) {
2005
+ const task = state.tasks.get(taskId);
2006
+ if (task) broadcastToLeaders({ type: "task.upsert", task });
2007
+ }
2008
+ dispatchSharedQueuedTasks();
2009
+ }, ctx.disconnectGraceMs);
2010
+ state.disconnectTimers.set(employeeId, timer);
2011
+ }
1962
2012
  return {
1963
2013
  dispatchLeaderCommand,
1964
2014
  handleAgentMessage,
1965
2015
  handleLeaderMessage,
1966
- cancelTaskById
2016
+ cancelTaskById,
2017
+ startDisconnectRecovery
1967
2018
  };
1968
2019
  }
1969
2020
 
@@ -2157,7 +2208,7 @@ async function createAiTeamsServer(options) {
2157
2208
  disconnectGraceMs,
2158
2209
  encryptor: createEncryptor(process.env.AI_TEAMS_ENCRYPTION_KEY)
2159
2210
  };
2160
- const { dispatchLeaderCommand, handleAgentMessage, handleLeaderMessage, cancelTaskById } = createDispatch(dispatchCtx);
2211
+ const { dispatchLeaderCommand, handleAgentMessage, handleLeaderMessage, cancelTaskById, startDisconnectRecovery } = createDispatch(dispatchCtx);
2161
2212
  const scheduleDispatchFn = (message, webhookUrl, cliConfig, priority, requiredLabels) => {
2162
2213
  return dispatchLeaderCommand(message, webhookUrl, cliConfig, priority, requiredLabels);
2163
2214
  };
@@ -2786,6 +2837,7 @@ async function createAiTeamsServer(options) {
2786
2837
  for (const leaderSocket of state.leaderSockets) {
2787
2838
  sendJson(leaderSocket, { type: "employee.upsert", employee }, dispatchCtx.encryptor);
2788
2839
  }
2840
+ startDisconnectRecovery(employeeId);
2789
2841
  }
2790
2842
  app.log.info({ employeeId }, "Agent disconnected");
2791
2843
  });
@@ -2891,7 +2943,7 @@ if (isCli) {
2891
2943
  getArgValue2 = getArgValue, resolveDataDir2 = resolveDataDir, resolvePidFile2 = resolvePidFile, resolveLogDir2 = resolveLogDir, applyCliArgsToEnv2 = applyCliArgsToEnv;
2892
2944
  const args = process.argv.slice(2);
2893
2945
  if (args.includes("--version") || args.includes("-v")) {
2894
- console.log("0.3.1");
2946
+ console.log("0.3.2");
2895
2947
  process.exit(0);
2896
2948
  }
2897
2949
  if (args.includes("--help") || args.includes("-h")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@csdwd/ai-teams-server",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "AI Teams central server — Fastify HTTP + WebSocket server for task dispatch, employee management, and web UI",
5
5
  "type": "module",
6
6
  "bin": {