@agents-tower/core 0.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 (178) hide show
  1. package/dist/adapters/claude.d.ts +2 -0
  2. package/dist/adapters/claude.js +43 -0
  3. package/dist/adapters/claude.js.map +1 -0
  4. package/dist/adapters/codex-cloud.d.ts +4 -0
  5. package/dist/adapters/codex-cloud.js +80 -0
  6. package/dist/adapters/codex-cloud.js.map +1 -0
  7. package/dist/adapters/codex-local.d.ts +17 -0
  8. package/dist/adapters/codex-local.js +180 -0
  9. package/dist/adapters/codex-local.js.map +1 -0
  10. package/dist/adapters/cursor-cloud.d.ts +2 -0
  11. package/dist/adapters/cursor-cloud.js +54 -0
  12. package/dist/adapters/cursor-cloud.js.map +1 -0
  13. package/dist/adapters/cursor-local.d.ts +2 -0
  14. package/dist/adapters/cursor-local.js +37 -0
  15. package/dist/adapters/cursor-local.js.map +1 -0
  16. package/dist/adapters/helpers.d.ts +15 -0
  17. package/dist/adapters/helpers.js +33 -0
  18. package/dist/adapters/helpers.js.map +1 -0
  19. package/dist/adapters/hermes.d.ts +2 -0
  20. package/dist/adapters/hermes.js +41 -0
  21. package/dist/adapters/hermes.js.map +1 -0
  22. package/dist/adapters/index.d.ts +2 -0
  23. package/dist/adapters/index.js +37 -0
  24. package/dist/adapters/index.js.map +1 -0
  25. package/dist/adapters/openclaw.d.ts +2 -0
  26. package/dist/adapters/openclaw.js +41 -0
  27. package/dist/adapters/openclaw.js.map +1 -0
  28. package/dist/adapters/presence.d.ts +2 -0
  29. package/dist/adapters/presence.js +36 -0
  30. package/dist/adapters/presence.js.map +1 -0
  31. package/dist/adapters/static-source.d.ts +15 -0
  32. package/dist/adapters/static-source.js +41 -0
  33. package/dist/adapters/static-source.js.map +1 -0
  34. package/dist/adapters/types.d.ts +44 -0
  35. package/dist/adapters/types.js +3 -0
  36. package/dist/adapters/types.js.map +1 -0
  37. package/dist/app-server.d.ts +94 -0
  38. package/dist/app-server.js +382 -0
  39. package/dist/app-server.js.map +1 -0
  40. package/dist/app-settings.d.ts +52 -0
  41. package/dist/app-settings.js +268 -0
  42. package/dist/app-settings.js.map +1 -0
  43. package/dist/appearance.d.ts +6 -0
  44. package/dist/appearance.js +84 -0
  45. package/dist/appearance.js.map +1 -0
  46. package/dist/aseprite.d.ts +4 -0
  47. package/dist/aseprite.js +42 -0
  48. package/dist/aseprite.js.map +1 -0
  49. package/dist/claude-agent-sdk.d.ts +44 -0
  50. package/dist/claude-agent-sdk.js +347 -0
  51. package/dist/claude-agent-sdk.js.map +1 -0
  52. package/dist/claude-home-cache.d.ts +61 -0
  53. package/dist/claude-home-cache.js +438 -0
  54. package/dist/claude-home-cache.js.map +1 -0
  55. package/dist/claude.d.ts +154 -0
  56. package/dist/claude.js +3495 -0
  57. package/dist/claude.js.map +1 -0
  58. package/dist/cloud.d.ts +2 -0
  59. package/dist/cloud.js +25 -0
  60. package/dist/cloud.js.map +1 -0
  61. package/dist/codex-command.d.ts +25 -0
  62. package/dist/codex-command.js +235 -0
  63. package/dist/codex-command.js.map +1 -0
  64. package/dist/codex-session-files.d.ts +8 -0
  65. package/dist/codex-session-files.js +509 -0
  66. package/dist/codex-session-files.js.map +1 -0
  67. package/dist/codex-thread-query.d.ts +14 -0
  68. package/dist/codex-thread-query.js +82 -0
  69. package/dist/codex-thread-query.js.map +1 -0
  70. package/dist/cursor-cloud-data.d.ts +34 -0
  71. package/dist/cursor-cloud-data.js +344 -0
  72. package/dist/cursor-cloud-data.js.map +1 -0
  73. package/dist/cursor-lib/local-discovery.d.ts +17 -0
  74. package/dist/cursor-lib/local-discovery.js +251 -0
  75. package/dist/cursor-lib/local-discovery.js.map +1 -0
  76. package/dist/cursor-lib/shared.d.ts +5 -0
  77. package/dist/cursor-lib/shared.js +88 -0
  78. package/dist/cursor-lib/shared.js.map +1 -0
  79. package/dist/cursor.d.ts +8 -0
  80. package/dist/cursor.js +1584 -0
  81. package/dist/cursor.js.map +1 -0
  82. package/dist/domain/codex-turn-semantics.d.ts +4 -0
  83. package/dist/domain/codex-turn-semantics.js +49 -0
  84. package/dist/domain/codex-turn-semantics.js.map +1 -0
  85. package/dist/domain/workload-policy.d.ts +8 -0
  86. package/dist/domain/workload-policy.js +268 -0
  87. package/dist/domain/workload-policy.js.map +1 -0
  88. package/dist/domain/workspace-activity.d.ts +10 -0
  89. package/dist/domain/workspace-activity.js +372 -0
  90. package/dist/domain/workspace-activity.js.map +1 -0
  91. package/dist/goal.d.ts +11 -0
  92. package/dist/goal.js +76 -0
  93. package/dist/goal.js.map +1 -0
  94. package/dist/hermes-hook-install.d.ts +12 -0
  95. package/dist/hermes-hook-install.js +335 -0
  96. package/dist/hermes-hook-install.js.map +1 -0
  97. package/dist/hermes.d.ts +97 -0
  98. package/dist/hermes.js +2446 -0
  99. package/dist/hermes.js.map +1 -0
  100. package/dist/index.d.ts +28 -0
  101. package/dist/index.js +47 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/live-monitor-lib/events.d.ts +43 -0
  104. package/dist/live-monitor-lib/events.js +1463 -0
  105. package/dist/live-monitor-lib/events.js.map +1 -0
  106. package/dist/live-monitor-lib/rollout-hooks.d.ts +13 -0
  107. package/dist/live-monitor-lib/rollout-hooks.js +253 -0
  108. package/dist/live-monitor-lib/rollout-hooks.js.map +1 -0
  109. package/dist/live-monitor.d.ts +102 -0
  110. package/dist/live-monitor.js +1461 -0
  111. package/dist/live-monitor.js.map +1 -0
  112. package/dist/local-thread-selection.d.ts +2 -0
  113. package/dist/local-thread-selection.js +58 -0
  114. package/dist/local-thread-selection.js.map +1 -0
  115. package/dist/openclaw.d.ts +41 -0
  116. package/dist/openclaw.js +715 -0
  117. package/dist/openclaw.js.map +1 -0
  118. package/dist/presence.d.ts +9 -0
  119. package/dist/presence.js +108 -0
  120. package/dist/presence.js.map +1 -0
  121. package/dist/project-identity.d.ts +7 -0
  122. package/dist/project-identity.js +162 -0
  123. package/dist/project-identity.js.map +1 -0
  124. package/dist/project-paths.d.ts +23 -0
  125. package/dist/project-paths.js +394 -0
  126. package/dist/project-paths.js.map +1 -0
  127. package/dist/project-storage.d.ts +7 -0
  128. package/dist/project-storage.js +79 -0
  129. package/dist/project-storage.js.map +1 -0
  130. package/dist/room-config.d.ts +21 -0
  131. package/dist/room-config.js +230 -0
  132. package/dist/room-config.js.map +1 -0
  133. package/dist/services/project-discovery.d.ts +1 -0
  134. package/dist/services/project-discovery.js +16 -0
  135. package/dist/services/project-discovery.js.map +1 -0
  136. package/dist/services/project-live-monitor.d.ts +1 -0
  137. package/dist/services/project-live-monitor.js +6 -0
  138. package/dist/services/project-live-monitor.js.map +1 -0
  139. package/dist/services/project-snapshot-coordinator.d.ts +49 -0
  140. package/dist/services/project-snapshot-coordinator.js +152 -0
  141. package/dist/services/project-snapshot-coordinator.js.map +1 -0
  142. package/dist/services/refresh-scheduler.d.ts +8 -0
  143. package/dist/services/refresh-scheduler.js +44 -0
  144. package/dist/services/refresh-scheduler.js.map +1 -0
  145. package/dist/services/snapshot-assembler.d.ts +8 -0
  146. package/dist/services/snapshot-assembler.js +167 -0
  147. package/dist/services/snapshot-assembler.js.map +1 -0
  148. package/dist/services/thread-store.d.ts +4 -0
  149. package/dist/services/thread-store.js +8 -0
  150. package/dist/services/thread-store.js.map +1 -0
  151. package/dist/snapshot-lib/activity-summary.d.ts +3 -0
  152. package/dist/snapshot-lib/activity-summary.js +220 -0
  153. package/dist/snapshot-lib/activity-summary.js.map +1 -0
  154. package/dist/snapshot-lib/dashboard-builder.d.ts +21 -0
  155. package/dist/snapshot-lib/dashboard-builder.js +146 -0
  156. package/dist/snapshot-lib/dashboard-builder.js.map +1 -0
  157. package/dist/snapshot-lib/thread-summary.d.ts +27 -0
  158. package/dist/snapshot-lib/thread-summary.js +953 -0
  159. package/dist/snapshot-lib/thread-summary.js.map +1 -0
  160. package/dist/snapshot.d.ts +2 -0
  161. package/dist/snapshot.js +21 -0
  162. package/dist/snapshot.js.map +1 -0
  163. package/dist/types.d.ts +368 -0
  164. package/dist/types.js +3 -0
  165. package/dist/types.js.map +1 -0
  166. package/dist/utils/json.d.ts +4 -0
  167. package/dist/utils/json.js +29 -0
  168. package/dist/utils/json.js.map +1 -0
  169. package/dist/utils/text.d.ts +3 -0
  170. package/dist/utils/text.js +26 -0
  171. package/dist/utils/text.js.map +1 -0
  172. package/dist/web-search.d.ts +1 -0
  173. package/dist/web-search.js +52 -0
  174. package/dist/web-search.js.map +1 -0
  175. package/dist/workload.d.ts +1 -0
  176. package/dist/workload.js +12 -0
  177. package/dist/workload.js.map +1 -0
  178. package/package.json +19 -0
@@ -0,0 +1,715 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.openClawSessionToActivityState = openClawSessionToActivityState;
4
+ exports.openClawSessionDetail = openClawSessionDetail;
5
+ exports.openClawWorkspaceMatchesProject = openClawWorkspaceMatchesProject;
6
+ exports.discoverOpenClawProjects = discoverOpenClawProjects;
7
+ exports.loadOpenClawAgents = loadOpenClawAgents;
8
+ exports.loadRoamingOpenClawSnapshotData = loadRoamingOpenClawSnapshotData;
9
+ exports.openClawSessionWorkspaceLabel = openClawSessionWorkspaceLabel;
10
+ const node_crypto_1 = require("node:crypto");
11
+ const node_path_1 = require("node:path");
12
+ const appearance_1 = require("./appearance");
13
+ const project_paths_1 = require("./project-paths");
14
+ const DEFAULT_OPENCLAW_GATEWAY_URL = "ws://127.0.0.1:18789";
15
+ const OPENCLAW_REQUEST_TIMEOUT_MS = 4000;
16
+ const OPENCLAW_CONNECT_TIMEOUT_MS = 2500;
17
+ const OPENCLAW_CACHE_TTL_MS = 5000;
18
+ const OPENCLAW_DISCOVERY_WINDOW_MS = 24 * 60 * 60 * 1000;
19
+ const OPENCLAW_PROTOCOL_VERSION = 1;
20
+ let cachedWorkspaceData = null;
21
+ let cachedWorkspaceDataAt = 0;
22
+ let cachedIdentity = null;
23
+ function openClawEnabled() {
24
+ return [
25
+ process.env.OPENCLAW_GATEWAY_URL,
26
+ process.env.OPENCLAW_GATEWAY_TOKEN,
27
+ process.env.OPENCLAW_GATEWAY_PASSWORD
28
+ ].some((value) => typeof value === "string" && value.trim().length > 0);
29
+ }
30
+ function openClawGatewayUrl() {
31
+ const configured = process.env.OPENCLAW_GATEWAY_URL;
32
+ if (typeof configured !== "string" || configured.trim().length === 0) {
33
+ return DEFAULT_OPENCLAW_GATEWAY_URL;
34
+ }
35
+ return configured.trim();
36
+ }
37
+ function openClawGatewayToken() {
38
+ const configured = process.env.OPENCLAW_GATEWAY_TOKEN;
39
+ if (typeof configured !== "string") {
40
+ return undefined;
41
+ }
42
+ const trimmed = configured.trim();
43
+ return trimmed.length > 0 ? trimmed : undefined;
44
+ }
45
+ function openClawGatewayPassword() {
46
+ const configured = process.env.OPENCLAW_GATEWAY_PASSWORD;
47
+ if (typeof configured !== "string") {
48
+ return undefined;
49
+ }
50
+ const trimmed = configured.trim();
51
+ return trimmed.length > 0 ? trimmed : undefined;
52
+ }
53
+ function openClawTimeoutError(label, timeoutMs) {
54
+ return new Error(`OpenClaw ${label} timed out after ${timeoutMs}ms`);
55
+ }
56
+ function shorten(text, maxLength) {
57
+ const normalized = text.replace(/\s+/g, " ").trim();
58
+ if (normalized.length <= maxLength) {
59
+ return normalized;
60
+ }
61
+ return `${normalized.slice(0, maxLength - 1)}…`;
62
+ }
63
+ function base64UrlEncode(buffer) {
64
+ return buffer.toString("base64").replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/g, "");
65
+ }
66
+ function normalizeAgentIdFromSessionKey(sessionKey) {
67
+ if (typeof sessionKey !== "string") {
68
+ return null;
69
+ }
70
+ const match = sessionKey.trim().match(/^agent:([^:]+):/i);
71
+ return match ? match[1].trim().toLowerCase() : null;
72
+ }
73
+ function cachedOpenClawIdentity() {
74
+ if (cachedIdentity) {
75
+ return cachedIdentity;
76
+ }
77
+ const { publicKey, privateKey } = (0, node_crypto_1.generateKeyPairSync)("ed25519");
78
+ const publicKeyDer = publicKey.export({ type: "spki", format: "der" });
79
+ const publicKeyRaw = publicKeyDer.subarray(publicKeyDer.length - 32);
80
+ cachedIdentity = {
81
+ deviceId: (0, node_crypto_1.createHash)("sha256").update(publicKeyRaw).digest("hex"),
82
+ publicKeyRawBase64Url: base64UrlEncode(publicKeyRaw),
83
+ privateKeyPem: privateKey.export({ type: "pkcs8", format: "pem" }).toString()
84
+ };
85
+ return cachedIdentity;
86
+ }
87
+ function buildDeviceAuthPayload(params) {
88
+ return [
89
+ "v3",
90
+ params.deviceId,
91
+ params.clientId,
92
+ params.clientMode,
93
+ params.role,
94
+ params.scopes.join(","),
95
+ String(params.signedAtMs),
96
+ params.token ?? "",
97
+ params.nonce,
98
+ params.platform ?? "",
99
+ params.deviceFamily ?? ""
100
+ ].join("|");
101
+ }
102
+ function onceSocketEvent(socket, eventType, timeoutMs, predicate) {
103
+ return new Promise((resolve, reject) => {
104
+ const timeout = setTimeout(() => {
105
+ cleanup();
106
+ reject(openClawTimeoutError(eventType, timeoutMs));
107
+ }, timeoutMs);
108
+ const onEvent = (event) => {
109
+ if (predicate && !predicate(event)) {
110
+ return;
111
+ }
112
+ cleanup();
113
+ resolve(event);
114
+ };
115
+ const cleanup = () => {
116
+ clearTimeout(timeout);
117
+ socket.removeEventListener(eventType, onEvent);
118
+ };
119
+ socket.addEventListener(eventType, onEvent);
120
+ });
121
+ }
122
+ function readSocketMessageData(event) {
123
+ const candidate = typeof event === "object" && event && "data" in event
124
+ ? event.data
125
+ : null;
126
+ if (typeof candidate === "string") {
127
+ return candidate;
128
+ }
129
+ if (candidate instanceof ArrayBuffer) {
130
+ return Buffer.from(candidate).toString("utf8");
131
+ }
132
+ if (ArrayBuffer.isView(candidate)) {
133
+ return Buffer.from(candidate.buffer, candidate.byteOffset, candidate.byteLength).toString("utf8");
134
+ }
135
+ return "";
136
+ }
137
+ class OpenClawGatewayClient {
138
+ socket;
139
+ pending = new Map();
140
+ connectNonce = null;
141
+ closed = false;
142
+ constructor(socket) {
143
+ this.socket = socket;
144
+ this.socket.addEventListener("message", (event) => this.onMessage(event));
145
+ this.socket.addEventListener("close", () => this.failAll(new Error("OpenClaw gateway closed")));
146
+ this.socket.addEventListener("error", () => this.failAll(new Error("OpenClaw gateway error")));
147
+ }
148
+ static async connect() {
149
+ const WebSocketCtor = globalThis.WebSocket;
150
+ if (typeof WebSocketCtor !== "function") {
151
+ throw new Error("WebSocket runtime unavailable");
152
+ }
153
+ const socket = new WebSocketCtor(openClawGatewayUrl());
154
+ await onceSocketEvent(socket, "open", OPENCLAW_CONNECT_TIMEOUT_MS);
155
+ const client = new OpenClawGatewayClient(socket);
156
+ await client.handshake();
157
+ return client;
158
+ }
159
+ async close() {
160
+ if (this.closed) {
161
+ return;
162
+ }
163
+ this.closed = true;
164
+ this.failAll(new Error("OpenClaw gateway client closed"));
165
+ this.socket.close(1000, "done");
166
+ }
167
+ async request(method, params) {
168
+ if (this.closed) {
169
+ throw new Error("OpenClaw gateway client already closed");
170
+ }
171
+ const id = (0, node_crypto_1.randomUUID)();
172
+ const frame = JSON.stringify({
173
+ type: "req",
174
+ id,
175
+ method,
176
+ params
177
+ });
178
+ return await new Promise((resolve, reject) => {
179
+ const timeout = setTimeout(() => {
180
+ this.pending.delete(id);
181
+ reject(openClawTimeoutError(method, OPENCLAW_REQUEST_TIMEOUT_MS));
182
+ }, OPENCLAW_REQUEST_TIMEOUT_MS);
183
+ this.pending.set(id, {
184
+ resolve: (value) => resolve(value),
185
+ reject,
186
+ timeout
187
+ });
188
+ this.socket.send(frame);
189
+ });
190
+ }
191
+ async handshake() {
192
+ this.connectNonce = await this.waitForConnectChallenge();
193
+ const identity = cachedOpenClawIdentity();
194
+ const clientId = "codex-agents-office";
195
+ const clientMode = "backend";
196
+ const role = "operator";
197
+ const scopes = ["operator.read"];
198
+ const signedAtMs = Date.now();
199
+ const signaturePayload = buildDeviceAuthPayload({
200
+ deviceId: identity.deviceId,
201
+ clientId,
202
+ clientMode,
203
+ role,
204
+ scopes,
205
+ signedAtMs,
206
+ token: openClawGatewayToken(),
207
+ nonce: this.connectNonce,
208
+ platform: process.platform,
209
+ deviceFamily: "desktop"
210
+ });
211
+ const signature = base64UrlEncode((0, node_crypto_1.sign)(null, Buffer.from(signaturePayload, "utf8"), identity.privateKeyPem));
212
+ await this.request("connect", {
213
+ minProtocol: OPENCLAW_PROTOCOL_VERSION,
214
+ maxProtocol: OPENCLAW_PROTOCOL_VERSION,
215
+ client: {
216
+ id: clientId,
217
+ displayName: "Codex Agents Office",
218
+ version: "0.1.0",
219
+ platform: process.platform,
220
+ mode: clientMode
221
+ },
222
+ caps: [],
223
+ commands: [],
224
+ role,
225
+ scopes,
226
+ auth: openClawGatewayToken() || openClawGatewayPassword()
227
+ ? {
228
+ token: openClawGatewayToken(),
229
+ password: openClawGatewayPassword()
230
+ }
231
+ : undefined,
232
+ device: {
233
+ id: identity.deviceId,
234
+ publicKey: identity.publicKeyRawBase64Url,
235
+ signature,
236
+ signedAt: signedAtMs,
237
+ nonce: this.connectNonce
238
+ }
239
+ });
240
+ }
241
+ async waitForConnectChallenge() {
242
+ return await new Promise((resolve, reject) => {
243
+ const timeout = setTimeout(() => {
244
+ cleanup();
245
+ reject(openClawTimeoutError("connect.challenge", OPENCLAW_CONNECT_TIMEOUT_MS));
246
+ }, OPENCLAW_CONNECT_TIMEOUT_MS);
247
+ const onMessage = (event) => {
248
+ const text = readSocketMessageData(event);
249
+ if (!text) {
250
+ return;
251
+ }
252
+ let parsed;
253
+ try {
254
+ parsed = JSON.parse(text);
255
+ }
256
+ catch {
257
+ return;
258
+ }
259
+ if (parsed.type !== "event" || parsed.event !== "connect.challenge") {
260
+ return;
261
+ }
262
+ const nonce = typeof parsed.payload?.nonce === "string" ? parsed.payload.nonce.trim() : "";
263
+ if (!nonce) {
264
+ return;
265
+ }
266
+ cleanup();
267
+ resolve(nonce);
268
+ };
269
+ const cleanup = () => {
270
+ clearTimeout(timeout);
271
+ this.socket.removeEventListener("message", onMessage);
272
+ };
273
+ this.socket.addEventListener("message", onMessage);
274
+ });
275
+ }
276
+ onMessage(event) {
277
+ const text = readSocketMessageData(event);
278
+ if (!text) {
279
+ return;
280
+ }
281
+ let parsed;
282
+ try {
283
+ parsed = JSON.parse(text);
284
+ }
285
+ catch {
286
+ return;
287
+ }
288
+ if (parsed.type !== "res" || typeof parsed.id !== "string") {
289
+ return;
290
+ }
291
+ const pending = this.pending.get(parsed.id);
292
+ if (!pending) {
293
+ return;
294
+ }
295
+ this.pending.delete(parsed.id);
296
+ clearTimeout(pending.timeout);
297
+ if (parsed.ok) {
298
+ pending.resolve(parsed.payload);
299
+ return;
300
+ }
301
+ pending.reject(new Error(parsed.error?.message ?? parsed.error?.code ?? "OpenClaw gateway request failed"));
302
+ }
303
+ failAll(error) {
304
+ for (const [id, pending] of this.pending.entries()) {
305
+ this.pending.delete(id);
306
+ clearTimeout(pending.timeout);
307
+ pending.reject(error);
308
+ }
309
+ }
310
+ }
311
+ function sessionRowTimestamp(row) {
312
+ if (typeof row.updatedAt === "number" && Number.isFinite(row.updatedAt)) {
313
+ return row.updatedAt;
314
+ }
315
+ if (typeof row.endedAt === "number" && Number.isFinite(row.endedAt)) {
316
+ return row.endedAt;
317
+ }
318
+ if (typeof row.startedAt === "number" && Number.isFinite(row.startedAt)) {
319
+ return row.startedAt;
320
+ }
321
+ return Number.NaN;
322
+ }
323
+ function workspaceAgentsFromGatewayData(input) {
324
+ const workspaceAgents = new Map();
325
+ const configuredAgents = Array.isArray(input.config?.agents?.list) ? input.config.agents.list : [];
326
+ const defaultWorkspace = (0, project_paths_1.canonicalizeProjectPath)(input.config?.agents?.defaults?.workspace ?? null);
327
+ const gatewayAgentNames = new Map();
328
+ for (const agent of input.gatewayAgents) {
329
+ gatewayAgentNames.set(agent.id.trim().toLowerCase(), agent.name?.trim() || agent.identity?.name?.trim() || null);
330
+ }
331
+ for (const configuredAgent of configuredAgents) {
332
+ const agentId = typeof configuredAgent?.id === "string" ? configuredAgent.id.trim().toLowerCase() : "";
333
+ if (!agentId) {
334
+ continue;
335
+ }
336
+ const workspaceRoot = (0, project_paths_1.canonicalizeProjectPath)(configuredAgent.workspace ?? null);
337
+ if (!workspaceRoot) {
338
+ continue;
339
+ }
340
+ workspaceAgents.set(agentId, {
341
+ agentId,
342
+ name: configuredAgent.name?.trim()
343
+ || gatewayAgentNames.get(agentId)
344
+ || null,
345
+ workspaceRoot,
346
+ isDefault: input.defaultAgentId === agentId
347
+ });
348
+ }
349
+ if (input.defaultAgentId && defaultWorkspace && !workspaceAgents.has(input.defaultAgentId)) {
350
+ workspaceAgents.set(input.defaultAgentId, {
351
+ agentId: input.defaultAgentId,
352
+ name: gatewayAgentNames.get(input.defaultAgentId) ?? null,
353
+ workspaceRoot: defaultWorkspace,
354
+ isDefault: true
355
+ });
356
+ }
357
+ return [...workspaceAgents.values()];
358
+ }
359
+ function openClawDisplayLabel(params) {
360
+ return (params.row.label?.trim()
361
+ || params.row.displayName?.trim()
362
+ || params.row.derivedTitle?.trim()
363
+ || params.agent.name?.trim()
364
+ || params.row.key);
365
+ }
366
+ function openClawLatestMessage(row) {
367
+ const preview = row.lastMessagePreview?.trim() ?? "";
368
+ return preview.length > 0 ? preview : null;
369
+ }
370
+ function pathWithinOpenClawProject(projectRoot, candidate) {
371
+ if (!candidate) {
372
+ return false;
373
+ }
374
+ if ((0, project_paths_1.sameProjectPath)(projectRoot, candidate)) {
375
+ return true;
376
+ }
377
+ const rootKey = (0, project_paths_1.projectPathIdentityKey)(projectRoot);
378
+ const candidateKey = (0, project_paths_1.projectPathIdentityKey)(candidate);
379
+ return Boolean(rootKey && candidateKey && candidateKey.startsWith(`${rootKey}/`));
380
+ }
381
+ function openClawWorkspaceInsideAnyProject(workspaceRoot, projectRoots) {
382
+ if (!workspaceRoot) {
383
+ return false;
384
+ }
385
+ return projectRoots.some((projectRoot) => pathWithinOpenClawProject(projectRoot, workspaceRoot));
386
+ }
387
+ function openClawSessionToActivityState(params) {
388
+ if (params.activeChildCount > 0) {
389
+ return "delegating";
390
+ }
391
+ switch (params.row.status) {
392
+ case "running":
393
+ return "thinking";
394
+ case "done":
395
+ return "done";
396
+ case "failed":
397
+ case "killed":
398
+ case "timeout":
399
+ return "blocked";
400
+ default:
401
+ return "idle";
402
+ }
403
+ }
404
+ function openClawSessionDetail(params) {
405
+ if (params.activeChildCount > 0) {
406
+ return `Delegating to ${params.activeChildCount} session${params.activeChildCount === 1 ? "" : "s"}`;
407
+ }
408
+ const preview = openClawLatestMessage(params.row);
409
+ if (preview) {
410
+ return shorten(preview, 88);
411
+ }
412
+ if (params.row.derivedTitle?.trim()) {
413
+ return shorten(params.row.derivedTitle, 88);
414
+ }
415
+ switch (params.row.status) {
416
+ case "running":
417
+ return "Thinking";
418
+ case "done":
419
+ return "Finished recently";
420
+ case "failed":
421
+ return "Session failed";
422
+ case "killed":
423
+ return "Session stopped";
424
+ case "timeout":
425
+ return "Session timed out";
426
+ default:
427
+ return "Idle";
428
+ }
429
+ }
430
+ function sessionDepthForKey(key, parentByKey, seen = new Set()) {
431
+ const parent = parentByKey.get(key) ?? null;
432
+ if (!parent) {
433
+ return 0;
434
+ }
435
+ if (seen.has(key) || seen.has(parent)) {
436
+ return 1;
437
+ }
438
+ seen.add(key);
439
+ return 1 + sessionDepthForKey(parent, parentByKey, seen);
440
+ }
441
+ function activeOpenClawChildCounts(sessions) {
442
+ const activeChildCountByKey = new Map();
443
+ for (const session of sessions) {
444
+ const parentKey = session.parentSessionKey?.trim() || null;
445
+ if (!parentKey) {
446
+ continue;
447
+ }
448
+ const state = openClawSessionToActivityState({ row: session, activeChildCount: 0 });
449
+ if (state === "done" || state === "idle") {
450
+ continue;
451
+ }
452
+ activeChildCountByKey.set(parentKey, (activeChildCountByKey.get(parentKey) ?? 0) + 1);
453
+ }
454
+ return activeChildCountByKey;
455
+ }
456
+ async function openClawDashboardAgentFromSession(input) {
457
+ const updatedAtMs = sessionRowTimestamp(input.session);
458
+ if (!Number.isFinite(updatedAtMs)) {
459
+ return null;
460
+ }
461
+ const agentId = normalizeAgentIdFromSessionKey(input.session.key);
462
+ const labelAgent = input.agent ?? {
463
+ agentId: agentId ?? "openclaw",
464
+ name: null,
465
+ workspaceRoot: input.projectRoot,
466
+ isDefault: false
467
+ };
468
+ const activeChildCount = input.activeChildCount;
469
+ const state = openClawSessionToActivityState({
470
+ row: input.session,
471
+ activeChildCount
472
+ });
473
+ const sourceKind = input.sourceKind
474
+ ?? (input.session.modelProvider && input.session.model
475
+ ? `openclaw:${input.session.modelProvider}/${input.session.model}`
476
+ : input.session.model
477
+ ? `openclaw:${input.session.model}`
478
+ : "openclaw");
479
+ const appearance = await (0, appearance_1.ensureAgentAppearance)(input.projectRoot, `openclaw:${input.session.key}`);
480
+ const cwd = input.agent?.workspaceRoot ?? null;
481
+ return {
482
+ id: `openclaw:${input.session.key}`,
483
+ label: openClawDisplayLabel({ row: input.session, agent: labelAgent }),
484
+ source: "openclaw",
485
+ sourceKind,
486
+ parentThreadId: input.session.parentSessionKey ? `openclaw:${input.session.parentSessionKey}` : null,
487
+ depth: sessionDepthForKey(input.session.key, input.parentByKey),
488
+ isCurrent: false,
489
+ isOngoing: input.session.status === "running",
490
+ statusText: input.statusText ?? input.session.status ?? null,
491
+ role: labelAgent.isDefault ? (labelAgent.name ?? "openclaw") : labelAgent.agentId,
492
+ nickname: labelAgent.name,
493
+ isSubagent: Boolean(input.session.parentSessionKey),
494
+ state,
495
+ detail: openClawSessionDetail({ row: input.session, activeChildCount }),
496
+ cwd,
497
+ roomId: null,
498
+ appearance,
499
+ updatedAt: new Date(updatedAtMs).toISOString(),
500
+ stoppedAt: typeof input.session.endedAt === "number" && Number.isFinite(input.session.endedAt)
501
+ ? new Date(input.session.endedAt).toISOString()
502
+ : null,
503
+ paths: cwd ? [cwd] : [],
504
+ activityEvent: null,
505
+ latestMessage: openClawLatestMessage(input.session),
506
+ threadId: input.session.key,
507
+ taskId: null,
508
+ resumeCommand: null,
509
+ url: null,
510
+ git: null,
511
+ provenance: "openclaw",
512
+ confidence: "typed",
513
+ needsUser: null,
514
+ liveSubscription: "readOnly",
515
+ network: null
516
+ };
517
+ }
518
+ async function loadOpenClawWorkspaceDataUncached() {
519
+ if (!openClawEnabled()) {
520
+ return null;
521
+ }
522
+ const client = await OpenClawGatewayClient.connect();
523
+ try {
524
+ const [configResult, agentsResult, sessionsResult] = await Promise.all([
525
+ client.request("config.get", {}),
526
+ client.request("agents.list", {}),
527
+ client.request("sessions.list", {
528
+ includeGlobal: false,
529
+ includeUnknown: false,
530
+ includeDerivedTitles: true,
531
+ includeLastMessage: true
532
+ })
533
+ ]);
534
+ const defaultAgentId = typeof agentsResult?.defaultId === "string" && agentsResult.defaultId.trim().length > 0
535
+ ? agentsResult.defaultId.trim().toLowerCase()
536
+ : null;
537
+ return {
538
+ fetchedAt: Date.now(),
539
+ agents: workspaceAgentsFromGatewayData({
540
+ config: configResult?.config,
541
+ gatewayAgents: Array.isArray(agentsResult?.agents) ? agentsResult.agents : [],
542
+ defaultAgentId
543
+ }),
544
+ sessions: Array.isArray(sessionsResult?.sessions) ? sessionsResult.sessions : []
545
+ };
546
+ }
547
+ finally {
548
+ await client.close();
549
+ }
550
+ }
551
+ async function loadOpenClawWorkspaceData() {
552
+ const now = Date.now();
553
+ if (cachedWorkspaceData && now - cachedWorkspaceDataAt <= OPENCLAW_CACHE_TTL_MS) {
554
+ return await cachedWorkspaceData;
555
+ }
556
+ cachedWorkspaceDataAt = now;
557
+ cachedWorkspaceData = loadOpenClawWorkspaceDataUncached().catch((error) => {
558
+ cachedWorkspaceData = null;
559
+ cachedWorkspaceDataAt = 0;
560
+ throw error;
561
+ });
562
+ return await cachedWorkspaceData;
563
+ }
564
+ function openClawWorkspaceMatchesProject(workspaceRoot, projectRoot) {
565
+ return pathWithinOpenClawProject(projectRoot, workspaceRoot);
566
+ }
567
+ async function discoverOpenClawProjects(limit = 20) {
568
+ const data = await loadOpenClawWorkspaceData();
569
+ if (!data) {
570
+ return [];
571
+ }
572
+ const recentCutoff = Date.now() - OPENCLAW_DISCOVERY_WINDOW_MS;
573
+ const projects = new Map();
574
+ const workspaceByAgentId = new Map(data.agents.map((agent) => [agent.agentId, agent.workspaceRoot]));
575
+ for (const session of data.sessions) {
576
+ const updatedAt = sessionRowTimestamp(session);
577
+ if (!Number.isFinite(updatedAt) || updatedAt < recentCutoff) {
578
+ continue;
579
+ }
580
+ const agentId = normalizeAgentIdFromSessionKey(session.key);
581
+ const workspaceRoot = agentId ? workspaceByAgentId.get(agentId) ?? null : null;
582
+ if (!workspaceRoot) {
583
+ continue;
584
+ }
585
+ const existing = projects.get(workspaceRoot);
586
+ if (existing) {
587
+ existing.updatedAt = Math.max(existing.updatedAt, updatedAt);
588
+ existing.count += 1;
589
+ continue;
590
+ }
591
+ projects.set(workspaceRoot, {
592
+ root: workspaceRoot,
593
+ label: openClawSessionWorkspaceLabel(workspaceRoot) ?? workspaceRoot,
594
+ updatedAt,
595
+ count: 1
596
+ });
597
+ }
598
+ return [...projects.values()]
599
+ .sort((left, right) => right.updatedAt - left.updatedAt)
600
+ .slice(0, limit);
601
+ }
602
+ async function loadOpenClawAgents(projectRoot) {
603
+ const data = await loadOpenClawWorkspaceData();
604
+ if (!data) {
605
+ return [];
606
+ }
607
+ const matchedAgents = data.agents.filter((agent) => openClawWorkspaceMatchesProject(agent.workspaceRoot, projectRoot));
608
+ if (matchedAgents.length === 0) {
609
+ return [];
610
+ }
611
+ const matchedAgentIds = new Set(matchedAgents.map((agent) => agent.agentId));
612
+ const agentById = new Map(matchedAgents.map((agent) => [agent.agentId, agent]));
613
+ const relevantSessions = data.sessions.filter((session) => {
614
+ const agentId = normalizeAgentIdFromSessionKey(session.key);
615
+ return Boolean(agentId && matchedAgentIds.has(agentId));
616
+ });
617
+ const parentByKey = new Map();
618
+ for (const session of relevantSessions) {
619
+ parentByKey.set(session.key, session.parentSessionKey?.trim() || null);
620
+ }
621
+ const activeChildCountByKey = activeOpenClawChildCounts(relevantSessions);
622
+ const agents = [];
623
+ for (const session of relevantSessions.sort((left, right) => {
624
+ return sessionRowTimestamp(right) - sessionRowTimestamp(left);
625
+ })) {
626
+ const agentId = normalizeAgentIdFromSessionKey(session.key);
627
+ if (!agentId) {
628
+ continue;
629
+ }
630
+ const agent = agentById.get(agentId);
631
+ if (!agent) {
632
+ continue;
633
+ }
634
+ const activeChildCount = activeChildCountByKey.get(session.key) ?? 0;
635
+ const dashboardAgent = await openClawDashboardAgentFromSession({
636
+ projectRoot,
637
+ session,
638
+ agent,
639
+ parentByKey,
640
+ activeChildCount
641
+ });
642
+ if (dashboardAgent) {
643
+ agents.push(dashboardAgent);
644
+ }
645
+ }
646
+ return agents;
647
+ }
648
+ async function loadRoamingOpenClawSnapshotData(input) {
649
+ const anchorRoot = (0, project_paths_1.canonicalizeProjectPath)(input.anchorProjectRoot);
650
+ if (!anchorRoot) {
651
+ return { agents: [], notes: [] };
652
+ }
653
+ const data = await loadOpenClawWorkspaceData();
654
+ if (!data) {
655
+ return { agents: [], notes: [] };
656
+ }
657
+ const knownRoots = input.knownProjectRoots
658
+ .map((root) => (0, project_paths_1.canonicalizeProjectPath)(root))
659
+ .filter((root) => Boolean(root));
660
+ const limit = input.limit ?? 4;
661
+ const recentCutoff = Date.now() - OPENCLAW_DISCOVERY_WINDOW_MS;
662
+ const agentById = new Map(data.agents.map((agent) => [agent.agentId, agent]));
663
+ const candidateSessions = data.sessions.filter((session) => {
664
+ const updatedAt = sessionRowTimestamp(session);
665
+ if (!Number.isFinite(updatedAt) || updatedAt < recentCutoff) {
666
+ return false;
667
+ }
668
+ const agentId = normalizeAgentIdFromSessionKey(session.key);
669
+ const agent = agentId ? agentById.get(agentId) ?? null : null;
670
+ return !openClawWorkspaceInsideAnyProject(agent?.workspaceRoot ?? null, knownRoots);
671
+ });
672
+ const parentByKey = new Map();
673
+ for (const session of candidateSessions) {
674
+ parentByKey.set(session.key, session.parentSessionKey?.trim() || null);
675
+ }
676
+ const activeChildCountByKey = activeOpenClawChildCounts(candidateSessions);
677
+ const agents = [];
678
+ for (const session of candidateSessions.sort((left, right) => {
679
+ return sessionRowTimestamp(right) - sessionRowTimestamp(left);
680
+ })) {
681
+ const agentId = normalizeAgentIdFromSessionKey(session.key);
682
+ const sourceAgent = agentId ? agentById.get(agentId) ?? null : null;
683
+ const activeChildCount = activeChildCountByKey.get(session.key) ?? 0;
684
+ const dashboardAgent = await openClawDashboardAgentFromSession({
685
+ projectRoot: anchorRoot,
686
+ session,
687
+ agent: sourceAgent,
688
+ parentByKey,
689
+ activeChildCount,
690
+ sourceKind: "openclaw:roaming",
691
+ statusText: session.status === "running" ? "roaming" : session.status ?? null
692
+ });
693
+ if (!dashboardAgent) {
694
+ continue;
695
+ }
696
+ if (dashboardAgent.state === "idle" && dashboardAgent.isOngoing !== true) {
697
+ continue;
698
+ }
699
+ agents.push(dashboardAgent);
700
+ }
701
+ return {
702
+ agents: agents
703
+ .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt))
704
+ .slice(0, limit),
705
+ notes: []
706
+ };
707
+ }
708
+ function openClawSessionWorkspaceLabel(workspaceRoot) {
709
+ const canonical = (0, project_paths_1.canonicalizeProjectPath)(workspaceRoot);
710
+ if (!canonical) {
711
+ return null;
712
+ }
713
+ return (0, node_path_1.basename)(canonical) || canonical;
714
+ }
715
+ //# sourceMappingURL=openclaw.js.map