clay-server 4.1.0-beta.8 → 4.1.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 (119) hide show
  1. package/lib/context-usage.js +47 -0
  2. package/lib/issues-mcp-server.js +1 -1
  3. package/lib/issues-service.js +3 -1
  4. package/lib/loop-registry-occurrence.js +1 -0
  5. package/lib/notes.js +20 -3
  6. package/lib/os-users.js +6 -0
  7. package/lib/project-connection.js +14 -3
  8. package/lib/project-file-path.js +13 -0
  9. package/lib/project-file-watch.js +19 -8
  10. package/lib/project-filesystem.js +10 -16
  11. package/lib/project-http.js +53 -48
  12. package/lib/project-logs-mcp-server.js +8 -8
  13. package/lib/project-logs-schema.js +1 -1
  14. package/lib/project-logs-service.js +46 -13
  15. package/lib/project-logs-store.js +17 -15
  16. package/lib/project-logs.js +70 -0
  17. package/lib/project-loop.js +1 -0
  18. package/lib/project-notifications.js +1 -1
  19. package/lib/project-pending-message-queue.js +71 -7
  20. package/lib/project-scheduled-messages.js +235 -52
  21. package/lib/project-scheduled-result-store.js +131 -0
  22. package/lib/project-scheduled-task-execution.js +35 -2
  23. package/lib/project-session-notes.js +11 -4
  24. package/lib/project-sessions.js +7 -0
  25. package/lib/project-user-message.js +72 -5
  26. package/lib/project.js +60 -5
  27. package/lib/public/app.js +27 -12
  28. package/lib/public/css/avatar-imprints.css +1 -1
  29. package/lib/public/css/command-palette.css +20 -0
  30. package/lib/public/css/git-panel.css +13 -12
  31. package/lib/public/css/git-placard.css +4 -4
  32. package/lib/public/css/input.css +0 -109
  33. package/lib/public/css/issues.css +78 -31
  34. package/lib/public/css/mobile-nav.css +7 -0
  35. package/lib/public/css/notifications-center.css +3 -3
  36. package/lib/public/css/pending-message-queue.css +3 -0
  37. package/lib/public/css/project-logs.css +15 -0
  38. package/lib/public/css/sidebar.css +7 -0
  39. package/lib/public/css/sticky-notes.css +29 -0
  40. package/lib/public/modules/app-connection.js +9 -1
  41. package/lib/public/modules/app-favicon.js +10 -0
  42. package/lib/public/modules/app-messages.js +49 -37
  43. package/lib/public/modules/app-notifications.js +2 -0
  44. package/lib/public/modules/app-panels.js +77 -23
  45. package/lib/public/modules/app-projects.js +3 -0
  46. package/lib/public/modules/app-rate-limit.js +148 -243
  47. package/lib/public/modules/avatar-imprint.js +25 -70
  48. package/lib/public/modules/avatar.js +12 -4
  49. package/lib/public/modules/chat-render-runtime.js +20 -2
  50. package/lib/public/modules/clay-issue-links.js +23 -2
  51. package/lib/public/modules/clay-log-links.js +11 -1
  52. package/lib/public/modules/context-view-preference.js +143 -0
  53. package/lib/public/modules/default-vendor.js +116 -0
  54. package/lib/public/modules/filebrowser-tabs.js +1 -0
  55. package/lib/public/modules/filebrowser.js +45 -18
  56. package/lib/public/modules/input.js +81 -20
  57. package/lib/public/modules/issues-render.js +36 -10
  58. package/lib/public/modules/issues.js +95 -13
  59. package/lib/public/modules/markdown.js +3 -1
  60. package/lib/public/modules/pane-bridge.js +14 -8
  61. package/lib/public/modules/pane-issue-bridge.js +27 -0
  62. package/lib/public/modules/pending-message-queue.js +43 -1
  63. package/lib/public/modules/permission-hints.js +13 -0
  64. package/lib/public/modules/profile.js +9 -9
  65. package/lib/public/modules/project-activation.js +49 -0
  66. package/lib/public/modules/project-logs-render.js +13 -3
  67. package/lib/public/modules/project-logs.js +45 -15
  68. package/lib/public/modules/right-workbench.js +44 -0
  69. package/lib/public/modules/scheduled-message-state.js +12 -36
  70. package/lib/public/modules/scheduled-result-client.js +33 -0
  71. package/lib/public/modules/scheduled-result-display.js +50 -0
  72. package/lib/public/modules/scheduled-result-notification.js +31 -0
  73. package/lib/public/modules/scheduled-task-presentation.js +15 -0
  74. package/lib/public/modules/scheduled-tasks.js +9 -21
  75. package/lib/public/modules/sidebar-mobile.js +51 -3
  76. package/lib/public/modules/sidebar-sessions.js +65 -5
  77. package/lib/public/modules/split-session-boundary.js +28 -0
  78. package/lib/public/modules/split-view.js +42 -7
  79. package/lib/public/modules/sticky-notes-browser.js +130 -18
  80. package/lib/public/modules/sticky-notes.js +2 -3
  81. package/lib/public/modules/terminal.js +4 -4
  82. package/lib/public/modules/thinking-lifecycle.js +4 -1
  83. package/lib/public/modules/tools.js +5 -1
  84. package/lib/scheduled-run-state.js +10 -2
  85. package/lib/scheduler.js +1 -0
  86. package/lib/sdk-bridge.js +97 -61
  87. package/lib/sdk-message-processor.js +44 -13
  88. package/lib/sdk-skill-discovery.js +6 -28
  89. package/lib/sdk-turn-queue.js +14 -0
  90. package/lib/server-context-view.js +53 -0
  91. package/lib/server-default-vendor.js +60 -0
  92. package/lib/server.js +23 -6
  93. package/lib/session-notes-mcp-server.js +3 -5
  94. package/lib/session-pair-factory.js +2 -2
  95. package/lib/session-pair-mcp-server.js +5 -4
  96. package/lib/session-title-generator.js +89 -0
  97. package/lib/session-title-policy.js +8 -2
  98. package/lib/sessions.js +26 -1
  99. package/lib/user-presence.js +6 -0
  100. package/lib/users-context-view-preferences.js +65 -0
  101. package/lib/users-default-vendor-preferences.js +80 -0
  102. package/lib/users.js +12 -0
  103. package/lib/ws-schema.js +11 -0
  104. package/lib/yoke/acp-agent-profiles.js +15 -2
  105. package/lib/yoke/adapters/acp.js +3 -2
  106. package/lib/yoke/adapters/antigravity.js +2 -2
  107. package/lib/yoke/adapters/claude-worker.js +11 -12
  108. package/lib/yoke/adapters/claude.js +75 -22
  109. package/lib/yoke/adapters/codex.js +216 -29
  110. package/lib/yoke/adapters/kiro.js +6 -5
  111. package/lib/yoke/claude-context-usage.js +57 -0
  112. package/lib/yoke/claude-message-correlation.js +31 -0
  113. package/lib/yoke/claude-model-switch.js +15 -0
  114. package/lib/yoke/index.js +5 -1
  115. package/lib/yoke/mcp-bridge-server.js +18 -5
  116. package/lib/yoke/session-skill-catalog.js +45 -0
  117. package/lib/yoke/skill-discovery.js +60 -20
  118. package/lib/yoke/vendor-registry.js +1 -1
  119. package/package.json +5 -7
@@ -58,6 +58,7 @@ var CLAY_MCP_PATH = claySlug
58
58
 
59
59
  // --- Auth ---
60
60
  var clayAuthToken = process.env.CLAY_AUTH_TOKEN || "";
61
+ var clayBridgeToken = process.env.CLAY_BRIDGE_TOKEN || "";
61
62
 
62
63
  // --- Tool cache ---
63
64
  var _tools = []; // [{ server, name, description, inputSchema }]
@@ -79,6 +80,7 @@ function postJson(urlPath, body) {
79
80
  if (clayAuthToken) {
80
81
  headers["Cookie"] = "relay_auth=" + clayAuthToken;
81
82
  }
83
+ if (clayBridgeToken) headers["X-Clay-Bridge-Token"] = clayBridgeToken;
82
84
 
83
85
  var reqOpts = {
84
86
  hostname: parsed.hostname,
@@ -95,6 +97,15 @@ function postJson(urlPath, body) {
95
97
  res.on("data", function (chunk) { chunks.push(chunk); });
96
98
  res.on("end", function () {
97
99
  var respBody = Buffer.concat(chunks).toString("utf8");
100
+ if (res.statusCode < 200 || res.statusCode >= 300) {
101
+ var statusError = "Clay MCP bridge HTTP " + res.statusCode;
102
+ try {
103
+ var errorBody = JSON.parse(respBody);
104
+ if (errorBody && errorBody.error) statusError += ": " + errorBody.error;
105
+ } catch (e) {}
106
+ reject(new Error(statusError));
107
+ return;
108
+ }
98
109
  try {
99
110
  resolve(JSON.parse(respBody));
100
111
  } catch (e) {
@@ -122,8 +133,7 @@ function postJson(urlPath, body) {
122
133
  function fetchTools() {
123
134
  return postJson(CLAY_MCP_PATH, { action: "list_tools", sessionId: claySessionId, queryGeneration: clayQueryGeneration, sessionOnly: sessionOnly }).then(function (resp) {
124
135
  if (resp.error) {
125
- log("Failed to fetch tools: " + resp.error);
126
- return [];
136
+ throw new Error(resp.error);
127
137
  }
128
138
  _tools = resp.tools || [];
129
139
  _toolsFetched = true;
@@ -135,7 +145,8 @@ function fetchTools() {
135
145
  return _tools;
136
146
  }).catch(function (err) {
137
147
  log("Error fetching tools: " + err.message);
138
- return [];
148
+ _toolsFetched = false;
149
+ throw err;
139
150
  });
140
151
  }
141
152
 
@@ -194,7 +205,7 @@ function handleInitialize(id, params) {
194
205
  });
195
206
 
196
207
  // Pre-fetch tools after handshake
197
- fetchTools();
208
+ fetchTools().catch(function () {});
198
209
  }
199
210
 
200
211
  function handleToolsList(id, params) {
@@ -210,7 +221,9 @@ function handleToolsList(id, params) {
210
221
  }
211
222
 
212
223
  // Always re-fetch: remote MCP servers may connect after initial fetch
213
- fetchTools().then(respond);
224
+ fetchTools().then(respond).catch(function (err) {
225
+ sendError(id, -32001, "Clay tool discovery failed: " + err.message);
226
+ });
214
227
  }
215
228
 
216
229
  function handleToolsCall(id, params) {
@@ -0,0 +1,45 @@
1
+ // Session-owned shared skill catalog.
2
+ // ----------------------------------
3
+ // Keeps personal skill names out of project-wide session-manager state while
4
+ // retaining vendor commands separately for hydration and session switching.
5
+
6
+ var skillDiscovery = require("./skill-discovery");
7
+
8
+ function createSessionSkillCatalog(opts) {
9
+ opts = opts || {};
10
+ var cwd = opts.cwd;
11
+ var osUsers = !!opts.osUsers;
12
+ var getLinuxUser = opts.getLinuxUser || function () { return null; };
13
+ var resolveUser = opts.resolveUser || require("../os-users").resolveOsUserInfo;
14
+
15
+ function optionsFor(session) {
16
+ if (!osUsers) return opts.homeDir ? { homeDir: opts.homeDir, env: opts.env } : {};
17
+ var linuxUser = getLinuxUser(session);
18
+ if (!linuxUser) return { disable: true };
19
+ try {
20
+ return skillDiscovery.optionsForOsUser(resolveUser(linuxUser));
21
+ } catch (e) {
22
+ return { disable: true };
23
+ }
24
+ }
25
+
26
+ function hydrate(session) {
27
+ if (!session) return [];
28
+ var discovered = skillDiscovery.discoverSkills(cwd, optionsFor(session));
29
+ var names = discovered.map(function (skill) { return skill.name; });
30
+ session.skillNames = names;
31
+ var vendorCommands = Array.isArray(session.vendorSlashCommands) ? session.vendorSlashCommands : [];
32
+ var combined = vendorCommands.slice();
33
+ for (var i = 0; i < names.length; i++) {
34
+ if (combined.indexOf(names[i]) === -1) combined.push(names[i]);
35
+ }
36
+ session.slashCommands = combined;
37
+ session.slashCommandsByVendor = session.slashCommandsByVendor || {};
38
+ session.slashCommandsByVendor[session.vendor || "claude"] = combined;
39
+ return combined;
40
+ }
41
+
42
+ return { hydrate: hydrate, optionsFor: optionsFor };
43
+ }
44
+
45
+ module.exports = { createSessionSkillCatalog: createSessionSkillCatalog };
@@ -11,6 +11,18 @@ function defaultHomeDir() {
11
11
  try { return require("../config").REAL_HOME; } catch (e) { return os.homedir(); }
12
12
  }
13
13
 
14
+ function optionsForOsUser(userInfo, fsAsUser) {
15
+ if (!userInfo || typeof userInfo.home !== "string" || !userInfo.home) return { disable: true };
16
+ fsAsUser = fsAsUser || require("../os-users").fsAsUser;
17
+ return {
18
+ homeDir: userInfo.home,
19
+ scopedHome: true,
20
+ readDir: function (dir) { return fsAsUser("list", { dir: dir }, userInfo).map(function (entry) { return { name: entry.name, isDir: entry.isDir }; }); },
21
+ readFile: function (file) { return fsAsUser("read", { file: file, readContent: true }, userInfo).content; },
22
+ realpath: function (file) { return fsAsUser("realpath", { file: file }, userInfo).path; },
23
+ };
24
+ }
25
+
14
26
  function unquote(value) {
15
27
  var text = String(value || "").trim();
16
28
  if ((text[0] === '"' && text[text.length - 1] === '"') ||
@@ -20,61 +32,83 @@ function unquote(value) {
20
32
  return text;
21
33
  }
22
34
 
23
- function readMetadata(skillPath, fallbackName) {
35
+ function readMetadata(skillPath, fallbackName, opts) {
24
36
  var content;
25
- try { content = fs.readFileSync(skillPath, "utf8"); } catch (e) { return null; }
37
+ try { content = opts && opts.readFile ? opts.readFile(skillPath) : fs.readFileSync(skillPath, "utf8"); } catch (e) { return null; }
26
38
  var name = fallbackName;
27
39
  var description = "";
40
+ var version = "";
28
41
  var frontmatter = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---(?:\s*\r?\n|$)/);
29
42
  if (frontmatter) {
30
43
  var nameMatch = frontmatter[1].match(/^name:\s*(.+)$/m);
31
44
  var descriptionMatch = frontmatter[1].match(/^description:\s*(.+)$/m);
32
45
  if (nameMatch) name = unquote(nameMatch[1]) || fallbackName;
33
46
  if (descriptionMatch) description = unquote(descriptionMatch[1]);
47
+ var versionMatch = frontmatter[1].match(/^version:\s*(.+)$/m);
48
+ if (versionMatch) version = unquote(versionMatch[1]);
34
49
  }
35
50
  if (!description) {
36
51
  var heading = content.match(/^#\s+(.+)$/m);
37
52
  if (heading) description = heading[1].trim();
38
53
  }
39
- return { name: name, description: description };
54
+ return { name: name, description: description, version: version };
40
55
  }
41
56
 
42
- function scanRoot(root, source, merged) {
57
+ function scanRoot(root, source, merged, opts) {
43
58
  var entries;
44
- try { entries = fs.readdirSync(root, { withFileTypes: true }); } catch (e) { return; }
59
+ try { entries = opts && opts.readDir ? opts.readDir(root) : fs.readdirSync(root, { withFileTypes: true }); } catch (e) { return; }
45
60
  entries.sort(function(a, b) { return a.name.localeCompare(b.name); });
46
61
  for (var i = 0; i < entries.length; i++) {
47
62
  var entry = entries[i];
48
- if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
63
+ if ((!opts || !opts.readDir) && (entry.isDir === false || (typeof entry.isDirectory === "function" && !entry.isDirectory() && !entry.isSymbolicLink()))) continue;
49
64
  var skillPath = path.join(root, entry.name, "SKILL.md");
50
- var metadata = readMetadata(skillPath, entry.name);
65
+ var realSkillPath;
66
+ try { realSkillPath = opts && opts.realpath ? opts.realpath(skillPath) : fs.realpathSync(skillPath); } catch (e) { continue; }
67
+ var metadata = readMetadata(realSkillPath, entry.name, opts);
51
68
  if (!metadata) continue;
52
- merged[metadata.name] = {
69
+ var key = opts && opts.includeDuplicates ? source + "\0" + metadata.name : metadata.name;
70
+ merged[key] = {
53
71
  name: metadata.name,
54
- path: skillPath,
72
+ path: realSkillPath,
55
73
  description: metadata.description,
74
+ version: metadata.version,
56
75
  source: source,
57
76
  };
58
77
  }
59
78
  }
60
79
 
61
80
  function getSkillRoots(cwd, opts) {
62
- var homeDir = (opts && opts.homeDir) || defaultHomeDir();
81
+ opts = opts || {};
82
+ var env = opts.env || (opts.homeDir ? {} : process.env);
83
+ if (opts.scopedHome) {
84
+ env = Object.assign({}, env);
85
+ delete env.CODEX_HOME;
86
+ delete env.CLAUDE_CONFIG_DIR;
87
+ }
88
+ var homeDir = opts.homeDir || env.HOME || defaultHomeDir();
89
+ var codexHome = env.CODEX_HOME ? path.resolve(homeDir, env.CODEX_HOME) : path.join(homeDir, ".codex");
90
+ var claudeConfigDir = env.CLAUDE_CONFIG_DIR ? path.resolve(homeDir, env.CLAUDE_CONFIG_DIR) : path.join(homeDir, ".claude");
63
91
  var roots = [
64
- { path: path.join(homeDir, ".codex", "skills"), source: "codex-user" },
65
- { path: path.join(homeDir, ".claude", "skills"), source: "claude-user" },
92
+ { path: path.join(homeDir, ".agents", "skills"), source: "agents-user" },
93
+ { path: path.join(codexHome, "skills"), source: "codex-user" },
94
+ { path: path.join(codexHome, "skills", ".system"), source: "codex-system-user" },
95
+ { path: path.join(claudeConfigDir, "skills"), source: "claude-user" },
66
96
  ];
67
97
  if (cwd) {
68
98
  roots.push({ path: path.join(cwd, "skills"), source: "project" });
99
+ roots.push({ path: path.join(cwd, ".agents", "skills"), source: "agents-project" });
100
+ roots.push({ path: path.join(cwd, ".codex", "skills"), source: "codex-project" });
101
+ roots.push({ path: path.join(cwd, ".codex", "skills", ".system"), source: "codex-system-project" });
69
102
  roots.push({ path: path.join(cwd, ".claude", "skills"), source: "claude-project" });
70
103
  }
71
104
  return roots;
72
105
  }
73
106
 
74
107
  function discoverSkills(cwd, opts) {
108
+ if (opts && opts.disable) return [];
75
109
  var merged = {};
76
110
  var roots = getSkillRoots(cwd, opts);
77
- for (var i = 0; i < roots.length; i++) scanRoot(roots[i].path, roots[i].source, merged);
111
+ for (var i = 0; i < roots.length; i++) scanRoot(roots[i].path, roots[i].source, merged, opts);
78
112
  return Object.keys(merged).sort().map(function(name) { return merged[name]; });
79
113
  }
80
114
 
@@ -112,13 +146,13 @@ function buildSkillIndex(skills) {
112
146
  return lines.join("\n");
113
147
  }
114
148
 
115
- function readReferencedSkills(text, skills, maxChars) {
149
+ function readReferencedSkills(text, skills, maxChars, readOpts) {
116
150
  var references = findSkillReferences(text, skills);
117
151
  var remaining = maxChars || 32768;
118
152
  var blocks = [];
119
153
  for (var i = 0; i < references.length && remaining > 0; i++) {
120
154
  var content;
121
- try { content = fs.readFileSync(references[i].path, "utf8"); } catch (e) { continue; }
155
+ try { content = readOpts && readOpts.readFile ? readOpts.readFile(references[i].path) : fs.readFileSync(references[i].path, "utf8"); } catch (e) { continue; }
122
156
  var header = "<shared-skill name=\"" + references[i].name + "\" source=\"" + references[i].source + "\">\n";
123
157
  var footer = "\n</shared-skill>";
124
158
  var available = Math.max(0, remaining - header.length - footer.length);
@@ -142,18 +176,20 @@ function lstatOrNull(target) {
142
176
  }
143
177
 
144
178
  function ensureClaudeCodexPlugin(opts) {
145
- var homeDir = (opts && opts.homeDir) || defaultHomeDir();
146
- var source = path.join(homeDir, ".codex", "skills");
179
+ opts = opts || {};
180
+ var homeDir = opts.homeDir || defaultHomeDir();
181
+ var source = opts.source || path.join(homeDir, ".codex", "skills");
182
+ var bridgeName = opts.name || "codex";
147
183
  try {
148
184
  if (!fs.statSync(source).isDirectory()) return null;
149
185
  } catch (e) { return null; }
150
186
 
151
- var pluginDir = path.join(homeDir, ".clay", "skill-bridge", "codex");
187
+ var pluginDir = path.join(homeDir, ".clay", "skill-bridge", bridgeName);
152
188
  var bridgeRoot = path.dirname(pluginDir);
153
189
  var manifestDir = path.join(pluginDir, ".claude-plugin");
154
190
  var manifestPath = path.join(manifestDir, "plugin.json");
155
191
  var skillsLink = path.join(pluginDir, "skills");
156
- var manifest = JSON.stringify({ name: "codex", version: "1.0.0", description: "Codex skills shared by Clay" }, null, 2) + "\n";
192
+ var manifest = JSON.stringify({ name: bridgeName, version: "1.0.0", description: "Shared skills provided by Clay" }, null, 2) + "\n";
157
193
 
158
194
  try {
159
195
  fs.mkdirSync(path.join(homeDir, ".clay"), { recursive: true });
@@ -168,7 +204,10 @@ function ensureClaudeCodexPlugin(opts) {
168
204
  if (!manifestDirStat) fs.mkdirSync(manifestDir);
169
205
  var manifestStat = lstatOrNull(manifestPath);
170
206
  if (manifestStat) {
171
- if (!manifestStat.isFile() || fs.readFileSync(manifestPath, "utf8") !== manifest) return null;
207
+ if (!manifestStat.isFile()) return null;
208
+ var existingManifest = fs.readFileSync(manifestPath, "utf8");
209
+ var legacyManifest = JSON.stringify({ name: "codex", version: "1.0.0", description: "Codex skills shared by Clay" }, null, 2) + "\n";
210
+ if (existingManifest !== manifest && existingManifest !== legacyManifest) return null;
172
211
  } else {
173
212
  fs.writeFileSync(manifestPath, manifest, { mode: 0o600, flag: "wx" });
174
213
  }
@@ -192,5 +231,6 @@ module.exports = {
192
231
  findSkillReferences: findSkillReferences,
193
232
  getSkillRoots: getSkillRoots,
194
233
  indexSkills: indexSkills,
234
+ optionsForOsUser: optionsForOsUser,
195
235
  readReferencedSkills: readReferencedSkills,
196
236
  };
@@ -38,7 +38,7 @@ var VENDOR_REGISTRY = {
38
38
  usageDashboard: {
39
39
  icon: "/codex-avatar.png",
40
40
  alt: "Codex",
41
- href: "https://chatgpt.com/admin/usage",
41
+ href: "https://chatgpt.com/codex/settings/usage",
42
42
  title: "Check usage on ChatGPT",
43
43
  },
44
44
  rateLimitTracking: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "4.1.0-beta.8",
3
+ "version": "4.1.0",
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"
@@ -8,8 +8,6 @@
8
8
  "scripts": {
9
9
  "dev": "node bin/cli.js --dev",
10
10
  "test": "node --test --test-force-exit test/*.test.js",
11
- "prepack": "npm pkg delete bin.clay-dev",
12
- "postpack": "npm pkg set bin.clay-dev=./bin/cli.js",
13
11
  "semantic-release": "semantic-release"
14
12
  },
15
13
  "files": [
@@ -49,12 +47,12 @@
49
47
  "homepage": "https://github.com/chadbyte/clay#readme",
50
48
  "author": "Chad",
51
49
  "dependencies": {
52
- "@anthropic-ai/claude-agent-sdk": "^0.3.258",
50
+ "@anthropic-ai/claude-agent-sdk": "^0.3.272",
53
51
  "@lydell/node-pty": "^1.2.0-beta.3",
54
- "@openai/codex": "^0.153.4",
52
+ "@openai/codex": "^0.154.0",
55
53
  "@seald-io/nedb": "^4.1.2",
56
- "imapflow": "^1.3.1",
57
- "nodemailer": "^9.0.5",
54
+ "imapflow": "^1.7.8",
55
+ "nodemailer": "^9.1.1",
58
56
  "qrcode-terminal": "^0.12.0",
59
57
  "web-push": "^3.6.7",
60
58
  "ws": "^8.18.0"