@adhdev/daemon-core 0.9.82-rc.57 → 0.9.82-rc.58

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.
@@ -101,6 +101,7 @@ export declare class CliProviderInstance implements ProviderInstance {
101
101
  private completedDebouncePending;
102
102
  private enforceFreshSessionLaunchIfNeeded;
103
103
  private completionHasFinalAssistantMessage;
104
+ private buildCompletedFinalizationDiagnostic;
104
105
  private hasAdapterPendingResponse;
105
106
  private shouldSuppressStaleParsedBusyStatus;
106
107
  private getCompletedFinalizationBlockReason;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.57",
3
+ "version": "0.9.82-rc.58",
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",
@@ -36,7 +36,9 @@ export function resolveCliSpawnPlan(options: {
36
36
  : spawnConfig.command;
37
37
  const binaryPath = findBinary(configuredCommand);
38
38
  const isWin = os.platform() === 'win32';
39
- const allArgs = [...spawnConfig.args, ...extraArgs];
39
+ const allArgs = [...spawnConfig.args, ...extraArgs].map((arg) =>
40
+ typeof arg === 'string' ? arg.replace(/\{\{workingDir\}\}/g, workingDir) : arg,
41
+ );
40
42
 
41
43
  let shellCmd: string;
42
44
  let shellArgs: string[];
@@ -135,10 +135,21 @@ function isMeshCoordinatorEvent(eventName: unknown): eventName is string {
135
135
  }
136
136
 
137
137
  function formatCompletionMetadata(event: Record<string, unknown>): string {
138
+ const completionDiagnostic = event.completionDiagnostic && typeof event.completionDiagnostic === 'object'
139
+ ? event.completionDiagnostic as Record<string, unknown>
140
+ : null;
141
+ const diagnosticReason = completionDiagnostic
142
+ ? readNonEmptyString(completionDiagnostic.blockReason) || 'present'
143
+ : '';
144
+ const finalAssistantPresent = typeof completionDiagnostic?.finalAssistantPresent === 'boolean'
145
+ ? String(completionDiagnostic.finalAssistantPresent)
146
+ : '';
138
147
  const parts = [
139
148
  readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : '',
140
149
  readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : '',
141
150
  readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : '',
151
+ diagnosticReason ? `completion_diagnostic=${diagnosticReason}` : '',
152
+ finalAssistantPresent ? `final_assistant=${finalAssistantPresent}` : '',
142
153
  ].filter(Boolean);
143
154
  return parts.length > 0 ? ` (${parts.join('; ')})` : '';
144
155
  }
@@ -836,6 +847,9 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
836
847
  taskId: completedTaskForLedger?.id || undefined,
837
848
  providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
838
849
  finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
850
+ completionDiagnostic: args.metadataEvent.completionDiagnostic && typeof args.metadataEvent.completionDiagnostic === 'object'
851
+ ? args.metadataEvent.completionDiagnostic
852
+ : undefined,
839
853
  evidence: completionEvidence,
840
854
  },
841
855
  });
@@ -743,6 +743,55 @@ export class CliProviderInstance implements ProviderInstance {
743
743
  return role === 'assistant' && !!content;
744
744
  }
745
745
 
746
+ private buildCompletedFinalizationDiagnostic(args: {
747
+ blockReason: string;
748
+ latestStatus?: any;
749
+ latestVisibleStatus: string;
750
+ waitedMs: number;
751
+ pending: CompletedDebouncePending;
752
+ emittedAfterFinalizationTimeout: boolean;
753
+ }): Record<string, unknown> {
754
+ let parsed: any = null;
755
+ let parseError: string | undefined;
756
+ try {
757
+ parsed = this.adapter.getScriptParsedStatus();
758
+ } catch (error: any) {
759
+ parseError = error?.message || String(error);
760
+ }
761
+
762
+ const visibleMessages = (Array.isArray(parsed?.messages) ? parsed.messages : [])
763
+ .filter((message: any) => isUserFacingChatMessage(message as ChatMessage));
764
+ const lastVisible = visibleMessages[visibleMessages.length - 1] as ChatMessage | undefined;
765
+ const lastVisibleRole = typeof lastVisible?.role === 'string' ? lastVisible.role.trim().toLowerCase() : null;
766
+ const lastVisibleKind = typeof (lastVisible as any)?.kind === 'string' ? (lastVisible as any).kind : null;
767
+ const lastVisibleContentLength = lastVisible ? flattenContent(lastVisible.content).trim().length : 0;
768
+
769
+ return {
770
+ providerType: this.type,
771
+ sessionId: this.instanceId,
772
+ providerSessionId: this.providerSessionId || null,
773
+ workspace: this.workingDir,
774
+ blockReason: args.blockReason,
775
+ emittedAfterFinalizationTimeout: args.emittedAfterFinalizationTimeout,
776
+ waitedMs: args.waitedMs,
777
+ maxWaitMs: COMPLETED_FINALIZATION_MAX_WAIT_MS,
778
+ adapterStatus: typeof args.latestStatus?.status === 'string' ? args.latestStatus.status : null,
779
+ latestVisibleStatus: args.latestVisibleStatus,
780
+ parsedStatus: typeof parsed?.status === 'string' ? parsed.status : (parseError ? 'parse_error' : 'unknown'),
781
+ parseError: parseError || undefined,
782
+ finalAssistantPresent: this.completionHasFinalAssistantMessage(parsed?.messages),
783
+ visibleMessageCount: visibleMessages.length,
784
+ lastVisibleRole,
785
+ lastVisibleKind,
786
+ lastVisibleContentLength,
787
+ pendingStartedAt: this.generatingStartedAt || null,
788
+ pendingFirstObservedAt: args.pending.firstObservedAt,
789
+ pendingTimestamp: args.pending.timestamp,
790
+ pendingDurationSec: args.pending.duration,
791
+ previousBlockReason: args.pending.loggedBlockReason || null,
792
+ };
793
+ }
794
+
746
795
  private hasAdapterPendingResponse(): boolean {
747
796
  const adapterAny = this.adapter as any;
748
797
  if (adapterAny?.isWaitingForResponse === true) return true;
@@ -828,7 +877,23 @@ export class CliProviderInstance implements ProviderInstance {
828
877
  this.scheduleCompletedDebounceFlush(COMPLETED_FINALIZATION_RETRY_MS);
829
878
  return;
830
879
  }
831
- LOG.warn('CLI', `[${this.type}] suppressed completed event after ${waitedMs}ms without finalized assistant turn (${blockReason})`);
880
+ const completionDiagnostic = this.buildCompletedFinalizationDiagnostic({
881
+ blockReason,
882
+ latestStatus,
883
+ latestVisibleStatus,
884
+ waitedMs,
885
+ pending,
886
+ emittedAfterFinalizationTimeout: true,
887
+ });
888
+ LOG.warn('CLI', `[${this.type}] emitting completed event after ${waitedMs}ms without finalized assistant turn (${blockReason})`);
889
+ this.pushEvent({
890
+ event: 'agent:generating_completed',
891
+ chatTitle: pending.chatTitle,
892
+ duration: pending.duration,
893
+ timestamp: pending.timestamp,
894
+ finalSummary: extractFinalSummaryFromMessages(this.adapter?.getScriptParsedStatus()?.messages),
895
+ completionDiagnostic,
896
+ });
832
897
  this.completedDebouncePending = null;
833
898
  this.completedDebounceTimer = null;
834
899
  this.generatingStartedAt = 0;