@adhdev/daemon-core 0.9.82-rc.61 → 0.9.82-rc.63

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.
@@ -26,6 +26,15 @@ export declare function handleMeshForwardEvent(components: DaemonComponents, pay
26
26
  forwarded: number;
27
27
  suppressed: boolean;
28
28
  intentionalCleanupStop: boolean;
29
+ duplicateRefineTerminalEvent?: undefined;
30
+ duplicateCompletion?: undefined;
31
+ error?: undefined;
32
+ } | {
33
+ success: boolean;
34
+ forwarded: number;
35
+ suppressed: boolean;
36
+ duplicateRefineTerminalEvent: boolean;
37
+ intentionalCleanupStop?: undefined;
29
38
  duplicateCompletion?: undefined;
30
39
  error?: undefined;
31
40
  } | {
@@ -34,12 +43,14 @@ export declare function handleMeshForwardEvent(components: DaemonComponents, pay
34
43
  suppressed: boolean;
35
44
  duplicateCompletion: boolean;
36
45
  intentionalCleanupStop?: undefined;
46
+ duplicateRefineTerminalEvent?: undefined;
37
47
  error?: undefined;
38
48
  } | {
39
49
  success: boolean;
40
50
  forwarded: number;
41
51
  suppressed?: undefined;
42
52
  intentionalCleanupStop?: undefined;
53
+ duplicateRefineTerminalEvent?: undefined;
43
54
  duplicateCompletion?: undefined;
44
55
  error?: undefined;
45
56
  } | {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.61",
3
+ "version": "0.9.82-rc.63",
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",
@@ -58,6 +58,29 @@ export interface PendingMeshCoordinatorEvent {
58
58
  queuedAt: number;
59
59
  }
60
60
 
61
+ const REFINE_TERMINAL_EVENTS = new Set(['refine:completed', 'refine:failed']);
62
+
63
+ function readRefineJobId(event: { metadataEvent?: Record<string, unknown> } | Record<string, unknown>): string {
64
+ const metadata = readRecord((event as any).metadataEvent) || event as Record<string, unknown>;
65
+ const result = readRecord(metadata.result);
66
+ const refineJob = readRecord(result?.refineJob);
67
+ return readNonEmptyString(metadata.jobId) || readNonEmptyString(refineJob?.jobId);
68
+ }
69
+
70
+ function buildRefineTerminalEventFingerprint(meshId: string, eventName: string, metadataEvent: Record<string, unknown>): string {
71
+ const jobId = readRefineJobId({ metadataEvent });
72
+ return jobId && REFINE_TERMINAL_EVENTS.has(eventName) ? `${meshId}::${eventName}::${jobId}` : '';
73
+ }
74
+
75
+ function hasPendingRefineTerminalEventDuplicate(event: PendingMeshCoordinatorEvent): boolean {
76
+ if (!REFINE_TERMINAL_EVENTS.has(event.event)) return false;
77
+ const jobId = readRefineJobId(event);
78
+ if (!jobId) return false;
79
+ return getPendingMeshCoordinatorEvents(event.meshId).some((pending) =>
80
+ pending.event === event.event && readRefineJobId(pending) === jobId,
81
+ );
82
+ }
83
+
61
84
  function getPendingEventsPath(meshId: string): string {
62
85
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, '_');
63
86
  return join(getLedgerDir(), `${safe}.pending-events.jsonl`);
@@ -65,6 +88,10 @@ function getPendingEventsPath(meshId: string): string {
65
88
 
66
89
  export function queuePendingMeshCoordinatorEvent(event: PendingMeshCoordinatorEvent): boolean {
67
90
  try {
91
+ if (hasPendingRefineTerminalEventDuplicate(event)) {
92
+ LOG.info('MeshEvents', `Suppressed duplicate pending ${event.event} for refine job ${readRefineJobId(event)}`);
93
+ return true;
94
+ }
68
95
  appendFileSync(getPendingEventsPath(event.meshId), JSON.stringify(event) + '\n', 'utf-8');
69
96
  return true;
70
97
  } catch (e: any) {
@@ -131,6 +158,9 @@ const MESH_COORDINATOR_EVENTS = new Set([
131
158
  'agent:stopped',
132
159
  'agent:ready',
133
160
  'monitor:long_generating',
161
+ 'refine:accepted',
162
+ 'refine:completed',
163
+ 'refine:failed',
134
164
  ]);
135
165
 
136
166
  const EVENT_TO_LEDGER_KIND: Record<string, MeshLedgerKind> = {
@@ -266,6 +296,18 @@ function isDuplicateMeshCompletionEvent(args: {
266
296
  return false;
267
297
  }
268
298
 
299
+ function isDuplicateRefineTerminalEvent(meshId: string, eventName: string, metadataEvent: Record<string, unknown>): boolean {
300
+ const fingerprint = buildRefineTerminalEventFingerprint(meshId, eventName, metadataEvent);
301
+ if (!fingerprint) return false;
302
+ const now = Date.now();
303
+ for (const [key, seenAt] of recentCompletionFingerprints.entries()) {
304
+ if (now - seenAt > RECENT_COMPLETION_FINGERPRINT_TTL_MS) recentCompletionFingerprints.delete(key);
305
+ }
306
+ if (recentCompletionFingerprints.has(fingerprint)) return true;
307
+ recentCompletionFingerprints.set(fingerprint, now);
308
+ return false;
309
+ }
310
+
269
311
 
270
312
  export function tryAssignQueueTask(
271
313
  components: DaemonComponents,
@@ -700,6 +742,32 @@ function buildMeshSystemMessage(args: {
700
742
  if (args.event === 'monitor:long_generating') {
701
743
  return `[System] ${args.nodeLabel} has been generating for a long time${metadata}. Use mesh_read_chat once for a status check, but do not poll repeatedly.`;
702
744
  }
745
+ if (args.event === 'refine:accepted') {
746
+ const jobId = readRefineJobId({ metadataEvent: args.metadataEvent });
747
+ return `[System] Refinery accepted async job${jobId ? ` ${jobId}` : ''} for ${args.nodeLabel}. Completion/failure will be delivered as a terminal refine event; do not poll repeatedly.`;
748
+ }
749
+ if (args.event === 'refine:completed') {
750
+ const jobId = readRefineJobId({ metadataEvent: args.metadataEvent });
751
+ const result = readRecord(args.metadataEvent.result);
752
+ const validationSummary = readRecord(result?.validationSummary);
753
+ const validationStatus = readNonEmptyString(validationSummary?.status);
754
+ const into = readNonEmptyString(result?.into);
755
+ const branch = readNonEmptyString(result?.branch);
756
+ const details = [
757
+ jobId ? `job_id=${jobId}` : '',
758
+ branch && into ? `${branch}→${into}` : '',
759
+ validationStatus ? `validation=${validationStatus}` : '',
760
+ ].filter(Boolean).join('; ');
761
+ return `[System] Refinery async job for ${args.nodeLabel} completed successfully${details ? ` (${details})` : ''}. The worktree was merged and cleanup completed; continue from the updated mesh state.`;
762
+ }
763
+ if (args.event === 'refine:failed') {
764
+ const jobId = readRefineJobId({ metadataEvent: args.metadataEvent });
765
+ const result = readRecord(args.metadataEvent.result);
766
+ const code = readNonEmptyString(result?.code);
767
+ const error = readNonEmptyString(result?.error);
768
+ const details = [jobId ? `job_id=${jobId}` : '', code ? `code=${code}` : ''].filter(Boolean).join('; ');
769
+ return `[System] Refinery async job for ${args.nodeLabel} failed${details ? ` (${details})` : ''}${error ? `: ${error}` : '.'} Review the terminal refine event/ledger before retrying.`;
770
+ }
703
771
  return '';
704
772
  }
705
773
 
@@ -728,6 +796,11 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
728
796
  return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
729
797
  }
730
798
 
799
+ if (isDuplicateRefineTerminalEvent(args.meshId, args.event, args.metadataEvent)) {
800
+ LOG.info('MeshEvents', `Suppressed duplicate ${args.event} for refine job ${readRefineJobId({ metadataEvent: args.metadataEvent })}`);
801
+ return { success: true, forwarded: 0, suppressed: true, duplicateRefineTerminalEvent: true };
802
+ }
803
+
731
804
  const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
732
805
  if (args.event === 'agent:generating_completed' && eventSessionId) {
733
806
  const duplicateCompletion = isDuplicateMeshCompletionEvent({
@@ -1005,6 +1078,14 @@ export function handleMeshForwardEvent(components: DaemonComponents, payload: Re
1005
1078
  providerType: readNonEmptyString(payload.providerType),
1006
1079
  providerSessionId: readNonEmptyString(payload.providerSessionId),
1007
1080
  finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary),
1081
+ jobId: readNonEmptyString(payload.jobId),
1082
+ interactionId: readNonEmptyString(payload.interactionId),
1083
+ status: readNonEmptyString(payload.status),
1084
+ targetDaemonId: readNonEmptyString(payload.targetDaemonId),
1085
+ startedAt: readNonEmptyString(payload.startedAt),
1086
+ completedAt: readNonEmptyString(payload.completedAt),
1087
+ retryOfJobId: readNonEmptyString(payload.retryOfJobId),
1088
+ ...(payload.result && typeof payload.result === 'object' && !Array.isArray(payload.result) ? { result: payload.result } : {}),
1008
1089
  ...(payload.timestamp !== undefined ? { timestamp: payload.timestamp } : {}),
1009
1090
  intentional: payload.intentional === true,
1010
1091
  intentionalStop: payload.intentionalStop === true,