adhdev 0.9.82-rc.13 → 0.9.82-rc.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adhdev",
3
- "version": "0.9.82-rc.13",
3
+ "version": "0.9.82-rc.15",
4
4
  "description": "ADHDev — Agent Dashboard Hub for Dev. Remote-control AI coding agents from anywhere.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -47,7 +47,7 @@
47
47
  "node": ">=18"
48
48
  },
49
49
  "dependencies": {
50
- "@adhdev/daemon-core": "0.9.82-rc.13",
50
+ "@adhdev/daemon-core": "0.9.82-rc.15",
51
51
  "@adhdev/ghostty-vt-node": "*",
52
52
  "@modelcontextprotocol/sdk": "^1.0.0",
53
53
  "@xterm/addon-serialize": "^0.14.0",
@@ -143,6 +143,10 @@ function isLocalTransport(transport) {
143
143
  }
144
144
 
145
145
  // src/tools/chat-compact.ts
146
+ function isAssistantLike(message) {
147
+ const role = String(message?.role ?? "").toLowerCase();
148
+ return role === "assistant" || role === "agent";
149
+ }
146
150
  function messageContent(message) {
147
151
  const content = message?.content;
148
152
  if (typeof content === "string") return content;
@@ -161,16 +165,22 @@ function isCoordinatorVisibleMessage(message) {
161
165
  if (meta?.internal === true || meta?.debug === true || meta?.control === true || meta?.userVisible === false || meta?.user_visible === false) return false;
162
166
  return role === "user" || role === "assistant" || role === "agent";
163
167
  }
168
+ function buildCompactMessageTail(visibleMessages, opts) {
169
+ const summary = typeof opts.summary === "string" ? opts.summary.trim() : "";
170
+ const shouldOmitSummaryMessage = !!summary && !!opts.finalAssistant && isAssistantLike(opts.finalAssistant) && messageContent(opts.finalAssistant).trim() === summary;
171
+ const sourceMessages = shouldOmitSummaryMessage ? visibleMessages.filter((message) => message !== opts.finalAssistant) : visibleMessages;
172
+ return sourceMessages.slice(-opts.limit);
173
+ }
164
174
  function compactChatPayload(payload, opts = {}) {
165
175
  const rawMessages = Array.isArray(payload?.messages) ? payload.messages : [];
166
176
  const visible = rawMessages.filter(isCoordinatorVisibleMessage);
167
177
  const limit = Math.max(1, Math.min(opts.limit ?? 10, 10));
168
- const messages = visible.slice(-limit);
169
178
  const finalAssistant = [...visible].reverse().find((message) => {
170
179
  const role = String(message?.role ?? "").toLowerCase();
171
180
  return (role === "assistant" || role === "agent") && messageContent(message).trim();
172
181
  });
173
182
  const summary = typeof payload?.summary === "string" && payload.summary.trim() ? payload.summary.trim() : messageContent(finalAssistant).trim();
183
+ const messages = buildCompactMessageTail(visible, { summary, finalAssistant, limit });
174
184
  return {
175
185
  success: payload?.success !== false,
176
186
  compact: true,
@@ -252,6 +262,16 @@ async function refreshMeshFromDaemon(ctx) {
252
262
  } catch {
253
263
  }
254
264
  }
265
+ async function syncCoordinatorDaemonMeshCache(ctx) {
266
+ if (!(ctx.transport instanceof IpcTransport)) return;
267
+ try {
268
+ await ctx.transport.command("get_mesh", {
269
+ meshId: ctx.mesh.id,
270
+ inlineMesh: ctx.mesh
271
+ });
272
+ } catch {
273
+ }
274
+ }
255
275
  async function findNodeWithRefresh(ctx, nodeId) {
256
276
  const hit = ctx.mesh.nodes.find((n) => n.id === nodeId);
257
277
  if (hit) return hit;
@@ -314,9 +334,26 @@ function buildMissingNodeReadChatRecovery(ctx, args) {
314
334
  readDebugLocator: readString(lastTerminal?.payload?.readDebugLocator) || readString(lastTerminal?.payload?.debugBundlePath)
315
335
  };
316
336
  if (finalSummary) {
337
+ if (args.compact === true) {
338
+ return {
339
+ ...compactChatPayload({
340
+ success: true,
341
+ status: "idle",
342
+ providerSessionId,
343
+ summary: finalSummary,
344
+ messages: [{ role: "assistant", content: finalSummary, isHistorical: true }]
345
+ }, {
346
+ nodeId: args.node_id,
347
+ sessionId: args.session_id,
348
+ limit: args.tail ?? 10
349
+ }),
350
+ recoveredFromLedger: true,
351
+ ledger
352
+ };
353
+ }
317
354
  return {
318
355
  success: true,
319
- compact: args.compact === true,
356
+ compact: false,
320
357
  recoveredFromLedger: true,
321
358
  nodeId: args.node_id,
322
359
  sessionId: args.session_id,
@@ -2251,6 +2288,7 @@ async function meshCloneNode(ctx, args) {
2251
2288
  if (existingIndex >= 0) ctx.mesh.nodes[existingIndex] = clonePayload.node;
2252
2289
  else ctx.mesh.nodes.push(clonePayload.node);
2253
2290
  ctx.mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2291
+ await syncCoordinatorDaemonMeshCache(ctx);
2254
2292
  }
2255
2293
  return JSON.stringify(result, null, 2);
2256
2294
  } else if (!isLocalTransport(ctx.transport) && sourceNode.daemonId) {
@@ -2268,6 +2306,7 @@ async function meshCloneNode(ctx, args) {
2268
2306
  if (existingIndex >= 0) ctx.mesh.nodes[existingIndex] = clonePayload.node;
2269
2307
  else ctx.mesh.nodes.push(clonePayload.node);
2270
2308
  ctx.mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
2309
+ await syncCoordinatorDaemonMeshCache(ctx);
2271
2310
  }
2272
2311
  return JSON.stringify(res, null, 2);
2273
2312
  } catch (e) {
@@ -3004,6 +3043,22 @@ function formatChatResult(result, sessionId, format, limit = 50, compact = false
3004
3043
  }))
3005
3044
  }, null, 2);
3006
3045
  }
3046
+ if ((format === "text" || format === void 0) && compact && compactPayload) {
3047
+ const lines2 = outputMessages.slice(-limit).map((m) => {
3048
+ const role = m.role === "user" ? "User" : m.role === "assistant" ? "Agent" : m.role;
3049
+ const content = messageContent(m);
3050
+ const truncated = content.length > 500 ? `${content.slice(0, 500)}\u2026` : content;
3051
+ return `[${role}] ${truncated}`;
3052
+ });
3053
+ if (compactPayload.summary) {
3054
+ const truncatedSummary = compactPayload.summary.length > 500 ? `${compactPayload.summary.slice(0, 500)}\u2026` : compactPayload.summary;
3055
+ lines2.push(`[Summary] ${truncatedSummary}`);
3056
+ }
3057
+ if (result?.pollingAdvisory) {
3058
+ lines2.push(`Advisory: ${result.pollingAdvisory.message}`);
3059
+ }
3060
+ return lines2.length > 0 ? lines2.join("\n\n") : "No messages in chat.";
3061
+ }
3007
3062
  if (outputMessages.length === 0) {
3008
3063
  return result?.pollingAdvisory ? `No messages in chat.
3009
3064