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

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.254",
3
+ "version": "0.9.82-rc.255",
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",
@@ -4309,6 +4309,27 @@ export class DaemonCommandRouter {
4309
4309
  }
4310
4310
 
4311
4311
  case 'launch_cli': {
4312
+ // Worker launch envelope hardening: a mesh worker session must carry
4313
+ // meshCoordinatorDaemonId so completion events route back to the
4314
+ // coordinator (the cloud relay and the daemon-core forwarder both key on
4315
+ // it). mesh_launch_session resolves coordinatorNode.daemonId || ctx.localDaemonId
4316
+ // upstream, but for a freshly-cloned local worktree both can be empty. When the
4317
+ // launch is a coordinator-driven worker on this machine and the id is missing,
4318
+ // stamp this daemon's own id — worker and coordinator are co-located here.
4319
+ {
4320
+ const launchSettings = (args?.settings && typeof args.settings === 'object')
4321
+ ? args.settings as Record<string, unknown>
4322
+ : undefined;
4323
+ const isMeshWorkerLaunch = !!launchSettings
4324
+ && (readStringValue(launchSettings.meshNodeFor) || launchSettings.launchedByCoordinator === true);
4325
+ const hasCoordinatorDaemonId = !!launchSettings && !!readStringValue(launchSettings.meshCoordinatorDaemonId);
4326
+ if (launchSettings && isMeshWorkerLaunch && !hasCoordinatorDaemonId) {
4327
+ try {
4328
+ const localDaemonId = readStringValue(loadConfig().machineId);
4329
+ if (localDaemonId) launchSettings.meshCoordinatorDaemonId = localDaemonId;
4330
+ } catch { /* best-effort — launch proceeds without the stamp */ }
4331
+ }
4332
+ }
4312
4333
  const launchResult = await this.deps.cliManager.handleCliCommand(cmd, args);
4313
4334
  // Bug C fix (part 1): when launching a mesh node worker session, surface
4314
4335
  // bootstrapPending:true if the node's worktree bootstrap is still running.
@@ -1214,6 +1214,33 @@ export class CliProviderInstance implements ProviderInstance {
1214
1214
  const adapterOwnsMessagesElsewhere = (this.adapter as any)?.chatMessagesOwnedExternally === true;
1215
1215
  const finalAssistantEvidence = this.completionFinalAssistantEvidence(parsed?.messages);
1216
1216
  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
+ }
1217
1244
  LOG.debug('CLI', `[${this.type}] finalAssistantEvidence: present=${finalAssistantEvidence.present} source=${finalAssistantEvidence.source} adapterOwnsMessagesElsewhere=${adapterOwnsMessagesElsewhere} parsedStatus=${parsedStatus}`);
1218
1245
  if (!finalAssistantEvidence.present) {
1219
1246
  if (adapterOwnsMessagesElsewhere) {