@adhdev/daemon-core 0.9.82-rc.255 → 0.9.82-rc.257

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-core",
3
- "version": "0.9.82-rc.255",
3
+ "version": "0.9.82-rc.257",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1541,8 +1541,23 @@ export function setupMeshEventForwarding(components: DaemonComponents) {
1541
1541
 
1542
1542
  const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor) || meshIdFromDirectDispatch;
1543
1543
 
1544
- const isMeshDelegate = Boolean(meshIdFromRuntime || settings.launchedByCoordinator);
1545
- if (!isMeshDelegate) return;
1544
+ // A mesh worker must be recognised as a delegate even if its meshNodeFor stamp is
1545
+ // missing. Worker launch envelopes are assembled from several settings, and in
1546
+ // practice a worker can arrive carrying only meshCoordinatorDaemonId (the routing
1547
+ // anchor) without meshNodeFor — e.g. when the node/mesh stamp was dropped on a
1548
+ // direct dispatch or a relaunch. Gating delegate routing solely on meshNodeFor then
1549
+ // silently drops the completion: setupMeshEventForwarding returns here, the
1550
+ // coordinator filter can't resolve args.meshId, and the event only lands in the
1551
+ // pending queue that an idle/generating coordinator never drains. Treat any of the
1552
+ // worker-envelope markers as proof of delegation and recover the mesh id by
1553
+ // workspace when the runtime id is absent.
1554
+ const hasWorkerEnvelope = Boolean(
1555
+ meshIdFromRuntime
1556
+ || settings.launchedByCoordinator
1557
+ || readNonEmptyString(settings.meshCoordinatorDaemonId)
1558
+ || readNonEmptyString(settings.meshCoordinatorNodeId),
1559
+ );
1560
+ if (!hasWorkerEnvelope) return;
1546
1561
 
1547
1562
  const mesh = meshIdFromRuntime ? getMeshWithCache(components, meshIdFromRuntime) : getCachedMeshByWorkspace(workspace);
1548
1563
  const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
@@ -1088,8 +1088,31 @@ export class CliProviderInstance implements ProviderInstance {
1088
1088
  }
1089
1089
 
1090
1090
  private completionFinalSummary(parsedMessages: unknown): string | undefined {
1091
- const evidence = this.completionFinalAssistantEvidence(parsedMessages);
1092
- return extractFinalSummaryFromMessages(evidence.messages as any);
1091
+ // For native-source providers (claude-cli: chatMessagesOwnedExternally), the PTY
1092
+ // screen parse is NOT the source of truth for the final summary — the terminal
1093
+ // wraps/scrolls/clips text, so a screen-parsed assistant message is often a partial
1094
+ // prefix (e.g. 76 chars of a 112-char turn). The append-only native transcript holds
1095
+ // the complete turn. Prefer it whenever it yields a longer/complete summary; fall back
1096
+ // to the parsed screen only when the transcript is unavailable. This is the real cause
1097
+ // of the truncated finalSummary — independent of cloud vs standalone (it surfaces on
1098
+ // any short, fast-completing task where screen parse wins the race).
1099
+ const adapterOwnsMessagesElsewhere = (this.adapter as any)?.chatMessagesOwnedExternally === true;
1100
+ const parsedSummary = extractFinalSummaryFromMessages(
1101
+ (this.completionHasFinalAssistantMessage(parsedMessages)
1102
+ ? (Array.isArray(parsedMessages) ? parsedMessages : [])
1103
+ : []) as any,
1104
+ );
1105
+ if (adapterOwnsMessagesElsewhere) {
1106
+ const externalMessages = this.readExternalCompletionMessages();
1107
+ const externalSummary = externalMessages
1108
+ ? extractFinalSummaryFromMessages(externalMessages as any)
1109
+ : '';
1110
+ // The transcript is authoritative for native-source providers. Use it unless it is
1111
+ // empty (not yet written) — only then fall back to whatever the screen parsed.
1112
+ if (externalSummary) return externalSummary;
1113
+ return parsedSummary || undefined;
1114
+ }
1115
+ return parsedSummary || undefined;
1093
1116
  }
1094
1117
 
1095
1118
  private buildCompletedFinalizationDiagnostic(args: {
@@ -1214,33 +1237,6 @@ export class CliProviderInstance implements ProviderInstance {
1214
1237
  const adapterOwnsMessagesElsewhere = (this.adapter as any)?.chatMessagesOwnedExternally === true;
1215
1238
  const finalAssistantEvidence = this.completionFinalAssistantEvidence(parsed?.messages);
1216
1239
  const allowMissingAssistantTimeout = !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.launchedByCoordinator);
1217
-
1218
- // Transcript settle guard: even when a final assistant message is present, a
1219
- // native-source transcript the CLI is still appending to (the final assistant turn
1220
- // lands in chunks) yields a *partial* finalSummary if read mid-flush — e.g. a 77-char
1221
- // prefix "...base 8e788950, and". Re-read the transcript and compare against the prior
1222
- // probe: if the last assistant message is still growing (msgCount or contentLen
1223
- // increased since the previous probe), it is mid-write — block and retry. Once two
1224
- // consecutive probes agree, the turn is fully flushed and we finalize. This keys on
1225
- // observed growth, not wall-clock age, so an already-settled transcript finalizes with
1226
- // no added latency. Matters most for worktree workers (cwd → a different projects/
1227
- // folder than the primary checkout, where flush timing skews the read).
1228
- if (adapterOwnsMessagesElsewhere && finalAssistantEvidence.source === 'external-native') {
1229
- const prevProbe = (pending.transcriptProbeHistory || [])[ (pending.transcriptProbeHistory?.length ?? 0) - 1 ];
1230
- this.readExternalCompletionMessages();
1231
- const settleProbe = this.lastExternalCompletionProbe;
1232
- if (settleProbe && prevProbe) {
1233
- const stillGrowing = settleProbe.msgCount > prevProbe.msgCount
1234
- || (settleProbe.lastRole === 'assistant' && settleProbe.contentLen > prevProbe.contentLen);
1235
- if (stillGrowing) {
1236
- this.recordPendingTranscriptProbe(pending);
1237
- return { reason: `transcript_settling:${prevProbe.contentLen}->${settleProbe.contentLen}`, terminal: false };
1238
- }
1239
- } else if (settleProbe) {
1240
- // First observation: record a baseline so the next flush attempt can detect growth.
1241
- this.recordPendingTranscriptProbe(pending);
1242
- }
1243
- }
1244
1240
  LOG.debug('CLI', `[${this.type}] finalAssistantEvidence: present=${finalAssistantEvidence.present} source=${finalAssistantEvidence.source} adapterOwnsMessagesElsewhere=${adapterOwnsMessagesElsewhere} parsedStatus=${parsedStatus}`);
1245
1241
  if (!finalAssistantEvidence.present) {
1246
1242
  if (adapterOwnsMessagesElsewhere) {