@adhdev/daemon-core 0.9.82-rc.401 → 0.9.82-rc.403
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 +232 -183
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +229 -180
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/mesh/mesh-work-queue.ts +23 -0
- package/src/providers/cli-provider-instance.ts +69 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhdev/daemon-core",
|
|
3
|
-
"version": "0.9.82-rc.
|
|
3
|
+
"version": "0.9.82-rc.403",
|
|
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",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"author": "vilmire",
|
|
47
47
|
"license": "AGPL-3.0-or-later",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@adhdev/mesh-shared": "0.9.82-rc.
|
|
49
|
+
"@adhdev/mesh-shared": "0.9.82-rc.403",
|
|
50
50
|
"@adhdev/session-host-core": "*",
|
|
51
51
|
"@agentclientprotocol/sdk": "^0.16.1",
|
|
52
52
|
"ajv": "^8.20.0",
|
|
@@ -7,6 +7,7 @@ import { getMesh } from '../config/mesh-config.js';
|
|
|
7
7
|
import { LOG } from '../logging/logger.js';
|
|
8
8
|
import { appendLedgerEntry } from './mesh-ledger.js';
|
|
9
9
|
import type { MeshLedgerKind } from './mesh-ledger.js';
|
|
10
|
+
import { createSessionDelivery } from './mesh-delivery-policy.js';
|
|
10
11
|
|
|
11
12
|
export type MeshTaskStatus = 'pending' | 'assigned' | 'completed' | 'failed' | 'cancelled';
|
|
12
13
|
export type MeshActiveTaskStatus = Extract<MeshTaskStatus, 'pending' | 'assigned'>;
|
|
@@ -836,6 +837,28 @@ export function recordDirectDispatchTask(
|
|
|
836
837
|
updatedAt: now,
|
|
837
838
|
};
|
|
838
839
|
MeshRuntimeStore.getInstance().insertQueueEntry(entry);
|
|
840
|
+
// R2 / NOTIF-DROP: a mission-attributed DIRECT dispatch (mesh_send_task) has
|
|
841
|
+
// already been handed to the transport by the time we materialise this assigned
|
|
842
|
+
// row — unlike a queue claim, there is no later delivery-confirmation write for
|
|
843
|
+
// it. Without a confirmed delivery record keyed by this taskId, the assigned-
|
|
844
|
+
// stranded watchdog (recoverStrandedAssignedDispatches → taskHasConfirmedDelivery)
|
|
845
|
+
// sees the row as never-confirmed after ASSIGNED_STRANDED_DEADLINE_MS and reclaims
|
|
846
|
+
// a task the worker already COMPLETED, dropping its agent:generating_completed
|
|
847
|
+
// (live PROBE-B repro: "never confirmed delivered → pending"). Record a confirmed
|
|
848
|
+
// delivery here so taskHasConfirmedDelivery() is true and the watchdog leaves the
|
|
849
|
+
// row to PHASE 4 completion reconcile. This point is only reached after the direct
|
|
850
|
+
// dispatch's result.success, so 'delivered' is the accurate state.
|
|
851
|
+
try {
|
|
852
|
+
createSessionDelivery({
|
|
853
|
+
meshId,
|
|
854
|
+
...(opts.assignedNodeId ? { nodeId: opts.assignedNodeId } : {}),
|
|
855
|
+
...(opts.assignedSessionId ? { sessionId: opts.assignedSessionId } : {}),
|
|
856
|
+
taskId,
|
|
857
|
+
kind: 'task',
|
|
858
|
+
message,
|
|
859
|
+
status: 'delivered',
|
|
860
|
+
});
|
|
861
|
+
} catch { /* best-effort — the assigned row is already recorded */ }
|
|
839
862
|
return entry;
|
|
840
863
|
});
|
|
841
864
|
}
|
|
@@ -2276,6 +2276,75 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
2276
2276
|
}
|
|
2277
2277
|
} else if (newStatus === 'idle' && this.lastStatus === 'starting') {
|
|
2278
2278
|
this.emitAgentReadyOnce(chatTitle, now);
|
|
2279
|
+
// GENERATING-BOUNDARY fast-collapse (R4, win32 startup-grace first turn):
|
|
2280
|
+
// a turn dispatched into the startup-grace window can START and FINISH while
|
|
2281
|
+
// the FSM is still in 'starting'. On a daemon whose claude-cli spec has NOT yet
|
|
2282
|
+
// synced the starting→busy edge (the primary cure lives in the spec's
|
|
2283
|
+
// idle→busy.from), the FSM never reaches 'busy'/generating, so
|
|
2284
|
+
// detectStatusTransition observes starting→idle DIRECTLY with no intervening
|
|
2285
|
+
// 'generating' frame. The idle→generating arm — the only path that sets
|
|
2286
|
+
// generatingStartedAt and arms the completion — never fired, so the completing
|
|
2287
|
+
// turn's agent:generating_completed is never emitted and the mesh coordinator
|
|
2288
|
+
// never learns the worker went idle. Synthesize the started+completed pair here.
|
|
2289
|
+
//
|
|
2290
|
+
// Discriminator (false-positive safe — must NOT fire on a benign boot):
|
|
2291
|
+
// adapter.currentTurnTaskId is set ONLY by onTurnStarted (a real turn STARTED
|
|
2292
|
+
// this boot) and persists past completion, so it cleanly separates the three
|
|
2293
|
+
// non-firing cases — a true idle boot (no turn → null), a queued-pending
|
|
2294
|
+
// first turn that only runs AFTER startup-grace drains the composer (onTurnStarted
|
|
2295
|
+
// not yet called → null; it completes normally later via idle→busy→idle), and a
|
|
2296
|
+
// turn STILL running at the 8s mark (hasAdapterPendingResponse() still true →
|
|
2297
|
+
// excluded so we don't fire a premature mid-turn completion; idle→busy self-
|
|
2298
|
+
// corrects once the FSM reaches idle). We fire only when a turn started AND has
|
|
2299
|
+
// already finished: started-this-boot && !still-in-flight.
|
|
2300
|
+
const startedTurnTaskId = typeof (this.adapter as any)?.currentTurnTaskId === 'string'
|
|
2301
|
+
&& (this.adapter as any).currentTurnTaskId.trim()
|
|
2302
|
+
? (this.adapter as any).currentTurnTaskId as string
|
|
2303
|
+
: undefined;
|
|
2304
|
+
const fastCollapsed = !!startedTurnTaskId
|
|
2305
|
+
&& !this.hasAdapterPendingResponse()
|
|
2306
|
+
&& !this.generatingStartedAt
|
|
2307
|
+
&& !this.generatingDebouncePending;
|
|
2308
|
+
if (fastCollapsed) {
|
|
2309
|
+
let fcFinalSummary: string | undefined;
|
|
2310
|
+
let fcEvidenceSource: CompletionFinalAssistantEvidence['source'] = 'unavailable';
|
|
2311
|
+
try {
|
|
2312
|
+
const parsedMessages = this.adapter?.getScriptParsedStatus()?.messages;
|
|
2313
|
+
const evidence = this.completionFinalAssistantEvidence(parsedMessages);
|
|
2314
|
+
fcEvidenceSource = evidence.source;
|
|
2315
|
+
fcFinalSummary = extractFinalSummaryFromMessages(evidence.messages as any);
|
|
2316
|
+
} catch { /* best-effort */ }
|
|
2317
|
+
const missingEvidence = ((this.provider as any).requiresFinalAssistantBeforeIdle === true || fcEvidenceSource === 'external-native') && !fcFinalSummary;
|
|
2318
|
+
// Mirror the short-generating idle path's suppression: a provider that
|
|
2319
|
+
// requires a final assistant (or external-native history) with NO confirmed
|
|
2320
|
+
// summary and NO mesh context emits nothing — the session is idle with no
|
|
2321
|
+
// confirmed turn, matching startup-blip semantics. With mesh context we still
|
|
2322
|
+
// emit so the coordinator can apply its own timeout/retry logic.
|
|
2323
|
+
const hasMeshContext = !!(this.settings.meshNodeFor || this.settings.meshActiveTaskId || this.settings.launchedByCoordinator);
|
|
2324
|
+
if (missingEvidence && !hasMeshContext) {
|
|
2325
|
+
LOG.info('CLI', `[${this.type}] startup-grace fast-collapse suppressed: missing final assistant evidence, no mesh context (source=${fcEvidenceSource})`);
|
|
2326
|
+
} else {
|
|
2327
|
+
LOG.info('CLI', `[${this.type}] startup-grace fast-collapse: synthesizing started+completed (taskId=${startedTurnTaskId} source=${fcEvidenceSource} hadFinalSummary=${!!fcFinalSummary})`);
|
|
2328
|
+
// Retroactive started so the started→completed pair (and the chat bubble)
|
|
2329
|
+
// is well-formed; pushEvent stamps the per-turn taskId for CANON-B ack.
|
|
2330
|
+
this.pushEvent({ event: 'agent:generating_started', chatTitle, timestamp: now });
|
|
2331
|
+
if (this.isMeshWorkerSession()) {
|
|
2332
|
+
traceMeshEventStage('fired', this.meshTraceCtx(), `startup-grace fast-collapse (source=${fcEvidenceSource})`);
|
|
2333
|
+
}
|
|
2334
|
+
this.pushEvent({
|
|
2335
|
+
event: 'agent:generating_completed',
|
|
2336
|
+
chatTitle,
|
|
2337
|
+
duration: 0,
|
|
2338
|
+
timestamp: now,
|
|
2339
|
+
finalSummary: fcFinalSummary,
|
|
2340
|
+
completionDiagnostic: {
|
|
2341
|
+
reason: 'startup_grace_fast_collapse',
|
|
2342
|
+
finalAssistantEvidenceSource: fcEvidenceSource,
|
|
2343
|
+
...(missingEvidence ? { blockReason: 'missing_final_assistant' } : {}),
|
|
2344
|
+
},
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2279
2348
|
} else if (newStatus === 'error') {
|
|
2280
2349
|
if (this.generatingDebounceTimer) { clearTimeout(this.generatingDebounceTimer); this.generatingDebounceTimer = null; }
|
|
2281
2350
|
this.generatingDebouncePending = null;
|