@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.
- package/dist/index.js +77 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +77 -2
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events.d.ts +11 -0
- package/package.json +1 -1
- package/src/mesh/mesh-events.ts +81 -0
|
@@ -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
package/src/mesh/mesh-events.ts
CHANGED
|
@@ -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,
|