clay-server 3.4.0-beta.21 → 3.4.0-beta.22

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.
@@ -8,6 +8,7 @@ var fs = require("fs");
8
8
  var { CodexAppServer } = require("../codex-app-server");
9
9
  var skillDiscovery = require("../skill-discovery");
10
10
  var { resolveOsUserInfo } = require("../../os-users");
11
+ var backgroundTasks = require("../codex-background-tasks");
11
12
 
12
13
  // --- Event flattening ---
13
14
  // Converts app-server JSON-RPC notifications into flat objects with a yokeType field.
@@ -672,6 +673,7 @@ function createEventState(model) {
672
673
  toolBlocks: {},
673
674
  commandInputs: {},
674
675
  planTexts: {},
676
+ backgroundTasks: backgroundTasks.createState(),
675
677
  };
676
678
  }
677
679
 
@@ -698,6 +700,7 @@ function createCodexQueryHandle(appServer, queryOpts) {
698
700
  var eventWaiting = null;
699
701
  var iteratorDone = false;
700
702
  var finishedNotified = false;
703
+ var removeBackgroundTaskReset = null;
701
704
 
702
705
  function notifyFinished() {
703
706
  if (finishedNotified) return;
@@ -722,6 +725,12 @@ function createCodexQueryHandle(appServer, queryOpts) {
722
725
  }
723
726
  }
724
727
 
728
+ if (typeof queryOpts.registerBackgroundTaskReset === "function") {
729
+ removeBackgroundTaskReset = queryOpts.registerBackgroundTaskReset(function() {
730
+ backgroundTasks.emitReset(state.backgroundTasks, pushEvent);
731
+ });
732
+ }
733
+
725
734
  function endIterator() {
726
735
  iteratorDone = true;
727
736
  if (eventWaiting) {
@@ -729,6 +738,10 @@ function createCodexQueryHandle(appServer, queryOpts) {
729
738
  eventWaiting = null;
730
739
  resolve({ value: undefined, done: true });
731
740
  }
741
+ if (removeBackgroundTaskReset) {
742
+ removeBackgroundTaskReset();
743
+ removeBackgroundTaskReset = null;
744
+ }
732
745
  notifyFinished();
733
746
  }
734
747
 
@@ -934,6 +947,10 @@ function createCodexQueryHandle(appServer, queryOpts) {
934
947
  pushEvent(yokeEvents[i]);
935
948
  }
936
949
 
950
+ if (method === "turn/completed" || method === "turn/failed") {
951
+ backgroundTasks.poll(appServer, state.threadId, state.backgroundTasks, pushEvent).catch(function() {});
952
+ }
953
+
937
954
  // Resolve turn promise when turn ends
938
955
  if (method === "turn/completed" || method === "turn/failed") {
939
956
  if (turnResolve) {
@@ -1246,6 +1263,20 @@ function createCodexAdapter(opts) {
1246
1263
  ];
1247
1264
  var _cachedModels = CODEX_MODELS.slice();
1248
1265
  var _appServer = null;
1266
+ var _backgroundTaskResetListeners = [];
1267
+
1268
+ function registerBackgroundTaskReset(listener) {
1269
+ _backgroundTaskResetListeners.push(listener);
1270
+ return function() {
1271
+ var index = _backgroundTaskResetListeners.indexOf(listener);
1272
+ if (index !== -1) _backgroundTaskResetListeners.splice(index, 1);
1273
+ };
1274
+ }
1275
+
1276
+ function emitBackgroundTaskReset() {
1277
+ var listeners = _backgroundTaskResetListeners.slice();
1278
+ for (var i = 0; i < listeners.length; i++) listeners[i]();
1279
+ }
1249
1280
  var _initPromise = null;
1250
1281
  var _shutdownPromise = null;
1251
1282
  var _refCount = 0;
@@ -1541,6 +1572,7 @@ function createCodexAdapter(opts) {
1541
1572
  // Spawn and initialize app-server
1542
1573
  _appServer = _createAppServer(serverOpts);
1543
1574
  await _appServer.start();
1575
+ emitBackgroundTaskReset();
1544
1576
 
1545
1577
  await _appServer.send("initialize", {
1546
1578
  clientInfo: { name: "clay", title: "Clay", version: "1.0.0" },
@@ -1676,6 +1708,7 @@ function createCodexAdapter(opts) {
1676
1708
  canUseTool: queryOpts.canUseTool || null,
1677
1709
  onElicitation: queryOpts.onElicitation || null,
1678
1710
  resumeSessionId: queryOpts.resumeSessionId || null,
1711
+ registerBackgroundTaskReset: registerBackgroundTaskReset,
1679
1712
  };
1680
1713
 
1681
1714
  // Reasoning effort
@@ -0,0 +1,84 @@
1
+ function terminalList(result) {
2
+ if (Array.isArray(result)) return result;
3
+ if (!result || typeof result !== "object") return [];
4
+ if (Array.isArray(result.terminals)) return result.terminals;
5
+ if (Array.isArray(result.backgroundTerminals)) return result.backgroundTerminals;
6
+ if (Array.isArray(result.items)) return result.items;
7
+ return [];
8
+ }
9
+
10
+ function isLiveTerminal(terminal) {
11
+ var status = String((terminal && (terminal.status || terminal.state)) || "").toLowerCase();
12
+ return status !== "exited" && status !== "terminated" && status !== "completed" && status !== "failed";
13
+ }
14
+
15
+ function mapTerminals(result) {
16
+ var terminals = terminalList(result);
17
+ var tasks = [];
18
+ for (var i = 0; i < terminals.length; i++) {
19
+ var terminal = terminals[i] || {};
20
+ var taskId = terminal.id || terminal.terminalId || terminal.taskId || "";
21
+ if (!taskId || !isLiveTerminal(terminal)) continue;
22
+ tasks.push({
23
+ task_id: String(taskId),
24
+ task_type: "shell",
25
+ description: terminal.commandLine || terminal.command || terminal.name || "",
26
+ });
27
+ }
28
+ return tasks;
29
+ }
30
+
31
+ function taskIds(tasks) {
32
+ var ids = {};
33
+ for (var i = 0; i < tasks.length; i++) ids[tasks[i].task_id] = true;
34
+ return ids;
35
+ }
36
+
37
+ function sameMembership(first, second) {
38
+ var firstKeys = Object.keys(first || {});
39
+ var secondKeys = Object.keys(second || {});
40
+ if (firstKeys.length !== secondKeys.length) return false;
41
+ for (var i = 0; i < firstKeys.length; i++) {
42
+ if (!second[firstKeys[i]]) return false;
43
+ }
44
+ return true;
45
+ }
46
+
47
+ function createState() {
48
+ return { taskIds: null };
49
+ }
50
+
51
+ function emitIfChanged(state, tasks, pushEvent) {
52
+ var ids = taskIds(tasks);
53
+ if (state.taskIds === null && tasks.length === 0) {
54
+ state.taskIds = ids;
55
+ return false;
56
+ }
57
+ if (state.taskIds && sameMembership(state.taskIds, ids)) return false;
58
+ state.taskIds = ids;
59
+ pushEvent({ yokeType: "background_tasks_changed", tasks: tasks });
60
+ return true;
61
+ }
62
+
63
+ function poll(appServer, threadId, state, pushEvent) {
64
+ if (!appServer || !threadId || appServer._clayBackgroundTasksPollingDisabled) return Promise.resolve(false);
65
+ return appServer.send("thread/backgroundTerminals/list", { threadId: threadId }).then(function(result) {
66
+ return emitIfChanged(state, mapTerminals(result), pushEvent);
67
+ }).catch(function() {
68
+ appServer._clayBackgroundTasksPollingDisabled = true;
69
+ return false;
70
+ });
71
+ }
72
+
73
+ function emitReset(state, pushEvent) {
74
+ state.taskIds = {};
75
+ pushEvent({ yokeType: "background_tasks_changed", tasks: [] });
76
+ }
77
+
78
+ module.exports = {
79
+ createState: createState,
80
+ mapTerminals: mapTerminals,
81
+ emitIfChanged: emitIfChanged,
82
+ poll: poll,
83
+ emitReset: emitReset,
84
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "3.4.0-beta.21",
3
+ "version": "3.4.0-beta.22",
4
4
  "description": "Self-hosted team workspace for Claude Code and Codex. Multi-user, browser-based, with persistent AI mates.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",