@adhdev/daemon-standalone 0.9.76-rc.17 → 0.9.76-rc.19

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/daemon-standalone",
3
- "version": "0.9.76-rc.17",
3
+ "version": "0.9.76-rc.19",
4
4
  "description": "ADHDev standalone daemon — embedded HTTP/WS server for local dashboard",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -30935,6 +30935,34 @@ function normalizeReadChatCommandStatus(status, activeModal) {
30935
30935
  return raw;
30936
30936
  }
30937
30937
  }
30938
+ function isGeneratingLikeStatus(status) {
30939
+ return status === "generating" || status === "streaming" || status === "long_generating" || status === "starting";
30940
+ }
30941
+ function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
30942
+ if (!isGeneratingLikeStatus(parsedStatus)) return false;
30943
+ if (hasNonEmptyModalButtons(activeModal)) return false;
30944
+ const adapterRawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
30945
+ if (adapterRawStatus !== "idle") return false;
30946
+ if (typeof adapter.isProcessing === "function" && adapter.isProcessing()) return false;
30947
+ return true;
30948
+ }
30949
+ function normalizeCliReadChatStatus(parsedStatus, activeModal, adapter, adapterStatus) {
30950
+ if (shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus)) return "idle";
30951
+ return typeof parsedStatus === "string" && parsedStatus.trim() ? parsedStatus : "idle";
30952
+ }
30953
+ function finalizeStreamingMessagesWhenIdle(messages, status) {
30954
+ if (status !== "idle") return messages;
30955
+ return messages.map((message) => {
30956
+ const meta3 = message.meta && typeof message.meta === "object" ? message.meta : void 0;
30957
+ const hasStreamingMeta = meta3?.streaming === true;
30958
+ if (message.bubbleState !== "streaming" && !hasStreamingMeta) return message;
30959
+ return {
30960
+ ...message,
30961
+ ...message.bubbleState === "streaming" ? { bubbleState: "final" } : {},
30962
+ ...hasStreamingMeta ? { meta: { ...meta3, streaming: false } } : {}
30963
+ };
30964
+ });
30965
+ }
30938
30966
  function buildReadChatCommandResult(payload, args) {
30939
30967
  let validatedPayload;
30940
30968
  const debugReadChat = payload?.debugReadChat && typeof payload.debugReadChat === "object" ? payload.debugReadChat : void 0;
@@ -31366,9 +31394,10 @@ async function handleReadChat(h, args) {
31366
31394
  const transcriptAuthority = parsedRecord.transcriptAuthority === "provider" || parsedRecord.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
31367
31395
  const coverage = parsedRecord.coverage === "full" || parsedRecord.coverage === "tail" || parsedRecord.coverage === "current-turn" ? parsedRecord.coverage : void 0;
31368
31396
  const activeModal = parsedRecord.activeModal ?? parsedRecord.modal ?? null;
31369
- const returnedStatus = parsedRecord.status || "idle";
31397
+ const returnedStatus = normalizeCliReadChatStatus(parsedRecord.status, activeModal, adapter, adapterStatus);
31370
31398
  const runtimeMessageMerger = getTargetInstance(h, args);
31371
- const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedRecord.messages) : parsedRecord.messages;
31399
+ const parsedMessages = finalizeStreamingMessagesWhenIdle(parsedRecord.messages, returnedStatus);
31400
+ const returnedMessages = runtimeMessageMerger?.category === "cli" && runtimeMessageMerger.type === adapter.cliType && typeof runtimeMessageMerger.mergeRuntimeChatMessages === "function" ? runtimeMessageMerger.mergeRuntimeChatMessages(parsedMessages) : parsedMessages;
31372
31401
  LOG.debug("Command", `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord.status || "")} parsedMsgCount=${parsedRecord.messages.length} returnedMsgCount=${returnedMessages.length}`);
31373
31402
  return buildReadChatCommandResult({
31374
31403
  messages: returnedMessages,
@@ -56293,27 +56322,49 @@ ${lines.join("\n\n")}`;
56293
56322
  }
56294
56323
 
56295
56324
  // src/tools/mesh-tools.ts
56325
+ async function refreshMeshFromDaemon(ctx) {
56326
+ if (!(ctx.transport instanceof IpcTransport)) return;
56327
+ try {
56328
+ const result = await ctx.transport.command("get_mesh", { meshId: ctx.mesh.id });
56329
+ if (!result?.success || !Array.isArray(result.mesh?.nodes)) return;
56330
+ const refreshedNodes = result.mesh.nodes.filter((n) => n?.id).map((n) => n);
56331
+ if (!refreshedNodes.length) return;
56332
+ ctx.mesh.nodes.splice(0, ctx.mesh.nodes.length, ...refreshedNodes);
56333
+ ctx.mesh.updatedAt = result.mesh.updatedAt ?? ctx.mesh.updatedAt;
56334
+ } catch {
56335
+ }
56336
+ }
56296
56337
  async function findNodeWithRefresh(ctx, nodeId) {
56297
56338
  const hit = ctx.mesh.nodes.find((n) => n.id === nodeId);
56298
56339
  if (hit) return hit;
56299
- if (ctx.transport instanceof IpcTransport) {
56300
- try {
56301
- const result = await ctx.transport.command("get_mesh", { meshId: ctx.mesh.id });
56302
- if (result?.success && Array.isArray(result.mesh?.nodes)) {
56303
- for (const n of result.mesh.nodes) {
56304
- if (n?.id && !ctx.mesh.nodes.find((existing) => existing.id === n.id)) {
56305
- ctx.mesh.nodes.push(n);
56306
- }
56307
- }
56308
- ctx.mesh.updatedAt = result.mesh.updatedAt ?? ctx.mesh.updatedAt;
56309
- }
56310
- } catch {
56311
- }
56312
- }
56340
+ await refreshMeshFromDaemon(ctx);
56313
56341
  const refreshed = ctx.mesh.nodes.find((n) => n.id === nodeId);
56314
56342
  if (!refreshed) throw new Error(`Node '${nodeId}' is not a member of mesh '${ctx.mesh.name}'`);
56315
56343
  return refreshed;
56316
56344
  }
56345
+ function unwrapCommandPayload(value) {
56346
+ return value?.result?.result ?? value?.result ?? value;
56347
+ }
56348
+ function extractGitStatus(value) {
56349
+ const payload = unwrapCommandPayload(value);
56350
+ return payload?.status ?? value?.status ?? payload;
56351
+ }
56352
+ function extractGitDiff(value) {
56353
+ const payload = unwrapCommandPayload(value);
56354
+ return payload?.diffSummary ?? payload?.diff ?? value?.diffSummary ?? value?.diff ?? payload;
56355
+ }
56356
+ function countUncommittedChanges(status) {
56357
+ if (typeof status?.uncommittedChanges === "number") return status.uncommittedChanges;
56358
+ const keys = ["staged", "modified", "untracked", "deleted", "renamed"];
56359
+ const counted = keys.reduce((sum, key) => sum + (Number.isFinite(Number(status?.[key])) ? Number(status[key]) : 0), 0);
56360
+ const conflicts = Array.isArray(status?.conflictFiles) ? status.conflictFiles.length : status?.hasConflicts ? 1 : 0;
56361
+ return counted + conflicts;
56362
+ }
56363
+ function isGitStatusDirty(status) {
56364
+ if (typeof status?.isDirty === "boolean") return status.isDirty;
56365
+ if (typeof status?.dirty === "boolean") return status.dirty;
56366
+ return countUncommittedChanges(status) > 0;
56367
+ }
56317
56368
  async function commandForNode(ctx, node, command, args = {}) {
56318
56369
  if (ctx.transport instanceof IpcTransport && node.daemonId) {
56319
56370
  return ctx.transport.meshCommand(node.daemonId, command, args);
@@ -56450,6 +56501,7 @@ var ALL_MESH_TOOLS = [
56450
56501
  MESH_REMOVE_NODE_TOOL
56451
56502
  ];
56452
56503
  async function meshStatus(ctx) {
56504
+ await refreshMeshFromDaemon(ctx);
56453
56505
  const { mesh, transport } = ctx;
56454
56506
  const results = [];
56455
56507
  for (const node of mesh.nodes) {
@@ -56460,18 +56512,22 @@ async function meshStatus(ctx) {
56460
56512
  try {
56461
56513
  if (!isLocalTransport(transport) && node.daemonId) {
56462
56514
  const result = await transport.gitStatus(node.daemonId, node.workspace, false);
56463
- const status = result?.status ?? result;
56464
- entry.health = status?.isGitRepo ? status?.isDirty ? "dirty" : "online" : "degraded";
56515
+ const status = extractGitStatus(result);
56516
+ const uncommittedChanges = countUncommittedChanges(status);
56517
+ const dirty = isGitStatusDirty(status);
56518
+ entry.health = status?.isGitRepo ? dirty ? "dirty" : "online" : "degraded";
56465
56519
  entry.branch = status?.branch;
56466
- entry.isDirty = status?.isDirty;
56467
- entry.uncommittedChanges = status?.uncommittedChanges ?? 0;
56520
+ entry.isDirty = dirty;
56521
+ entry.uncommittedChanges = uncommittedChanges;
56468
56522
  } else if (isLocalTransport(transport)) {
56469
56523
  const statusResult = await commandForNode(ctx, node, "git_status", { workspace: node.workspace });
56470
- const status = statusResult?.status ?? statusResult;
56471
- entry.health = status?.isGitRepo ? status?.isDirty ? "dirty" : "online" : "degraded";
56524
+ const status = extractGitStatus(statusResult);
56525
+ const uncommittedChanges = countUncommittedChanges(status);
56526
+ const dirty = isGitStatusDirty(status);
56527
+ entry.health = status?.isGitRepo ? dirty ? "dirty" : "online" : "degraded";
56472
56528
  entry.branch = status?.branch;
56473
- entry.isDirty = status?.isDirty;
56474
- entry.uncommittedChanges = status?.uncommittedChanges ?? 0;
56529
+ entry.isDirty = dirty;
56530
+ entry.uncommittedChanges = uncommittedChanges;
56475
56531
  } else {
56476
56532
  entry.health = "unknown";
56477
56533
  entry.note = "No daemonId available for cloud status probe";
@@ -56492,6 +56548,7 @@ async function meshStatus(ctx) {
56492
56548
  }, null, 2);
56493
56549
  }
56494
56550
  async function meshListNodes(ctx) {
56551
+ await refreshMeshFromDaemon(ctx);
56495
56552
  const { mesh } = ctx;
56496
56553
  return JSON.stringify({
56497
56554
  meshId: mesh.id,
@@ -56558,8 +56615,8 @@ async function meshGitStatus(ctx, args) {
56558
56615
  return JSON.stringify({
56559
56616
  nodeId: args.node_id,
56560
56617
  workspace: node.workspace,
56561
- status: result?.status ?? result,
56562
- diff: result?.diff ?? null
56618
+ status: extractGitStatus(result),
56619
+ diff: extractGitDiff(result)
56563
56620
  }, null, 2);
56564
56621
  } else if (isLocalTransport(ctx.transport)) {
56565
56622
  const statusResult = await commandForNode(ctx, node, "git_status", {
@@ -56571,8 +56628,8 @@ async function meshGitStatus(ctx, args) {
56571
56628
  return JSON.stringify({
56572
56629
  nodeId: args.node_id,
56573
56630
  workspace: node.workspace,
56574
- status: statusResult?.status ?? statusResult,
56575
- diff: diffResult?.diffSummary ?? diffResult
56631
+ status: extractGitStatus(statusResult),
56632
+ diff: extractGitDiff(diffResult)
56576
56633
  }, null, 2);
56577
56634
  } else {
56578
56635
  return JSON.stringify({ error: "No daemonId available for cloud git_status probe" });