@adhdev/daemon-core 0.9.82-rc.136 → 0.9.82-rc.137

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.
Files changed (39) hide show
  1. package/dist/cli-adapters/cli-script-runner.d.ts +45 -0
  2. package/dist/cli-adapters/cli-state-engine.d.ts +154 -0
  3. package/dist/cli-adapters/provider-cli-adapter.d.ts +73 -74
  4. package/dist/cli-adapters/provider-cli-shared.d.ts +4 -0
  5. package/dist/config/chat-history.d.ts +1 -0
  6. package/dist/index.d.ts +3 -3
  7. package/dist/index.js +2591 -1966
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +2594 -1974
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/mesh/beads-db.d.ts +54 -0
  12. package/dist/mesh/mesh-active-work.d.ts +7 -1
  13. package/dist/mesh/mesh-events.d.ts +10 -4
  14. package/dist/mesh/mesh-ledger.d.ts +21 -1
  15. package/dist/mesh/mesh-refine-status.d.ts +2 -3
  16. package/dist/mesh/mesh-work-queue.d.ts +17 -0
  17. package/dist/mesh/worktree-bootstrap-config.d.ts +2 -4
  18. package/dist/repo-mesh-types.d.ts +5 -0
  19. package/package.json +1 -1
  20. package/src/cli-adapters/cli-script-runner.ts +145 -0
  21. package/src/cli-adapters/cli-state-engine.ts +957 -0
  22. package/src/cli-adapters/provider-cli-adapter.d.ts +0 -1
  23. package/src/cli-adapters/provider-cli-adapter.ts +365 -1397
  24. package/src/cli-adapters/provider-cli-shared.ts +4 -0
  25. package/src/commands/chat-commands.ts +17 -1
  26. package/src/commands/router.ts +8 -0
  27. package/src/config/chat-history.ts +7 -3
  28. package/src/git/git-worktree.ts +8 -1
  29. package/src/index.ts +3 -2
  30. package/src/mesh/beads-db.ts +305 -2
  31. package/src/mesh/coordinator-prompt.ts +12 -17
  32. package/src/mesh/mesh-active-work.ts +162 -59
  33. package/src/mesh/mesh-events.ts +198 -53
  34. package/src/mesh/mesh-ledger.ts +321 -105
  35. package/src/mesh/mesh-refine-status.ts +2 -3
  36. package/src/mesh/mesh-work-queue.ts +116 -120
  37. package/src/mesh/worktree-bootstrap-config.ts +17 -4
  38. package/src/providers/provider-schema.ts +2 -0
  39. package/src/repo-mesh-types.ts +10 -0
@@ -1,5 +1,5 @@
1
1
  import type { MeshLedgerEntry } from './mesh-ledger.js';
2
- import type { MeshWorkQueueEntry } from './mesh-work-queue.js';
2
+ import type { MeshWorkQueueEntry, DirectDispatchRecord } from './mesh-work-queue.js';
3
3
 
4
4
  export type MeshActiveWorkSource = 'queue' | 'direct';
5
5
  export type MeshActiveWorkStatus = 'pending' | 'assigned' | 'generating' | 'idle' | 'failed' | 'awaiting_approval';
@@ -69,6 +69,12 @@ export interface BuildMeshActiveWorkOptions {
69
69
  meshId: string;
70
70
  queue?: MeshWorkQueueEntry[];
71
71
  ledgerEntries?: MeshLedgerEntry[];
72
+ /**
73
+ * Active direct dispatches from BeadsDB. When provided, these are used instead of
74
+ * scanning ledger entries for direct dispatches — eliminates the O(n_ledger) scan.
75
+ * Falls back to ledger scanning when not provided.
76
+ */
77
+ directDispatches?: DirectDispatchRecord[];
72
78
  nodes?: any[];
73
79
  now?: number;
74
80
  /** Include terminal direct rows (idle/failed) for handoff/recent-work surfaces. Defaults false. */
@@ -218,66 +224,163 @@ export function buildMeshActiveWork(opts: BuildMeshActiveWorkOptions): { activeW
218
224
  });
219
225
  }
220
226
 
221
- const ledgerEntries = (opts.ledgerEntries || []).slice().sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
222
- const terminals = ledgerEntries.filter(entry => TERMINAL_LEDGER_KINDS.has(entry.kind) || entry.kind === 'task_approval_needed');
223
- for (const dispatch of ledgerEntries.filter(isDirectDispatch)) {
224
- const taskId = directDispatchTaskId(dispatch);
225
- const terminal = terminals
226
- .filter(entry => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime())
227
- .find(entry => terminalMatchesDispatch(entry, dispatch, taskId));
228
- const terminalStatus = terminal ? statusFromTerminal(terminal) : undefined;
229
- const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
230
- const status = terminalStatus || live.status || 'assigned';
231
- const terminalRow = Boolean(terminal && terminal.kind !== 'task_approval_needed');
232
- // dispatchedToIdleSession is recorded by mesh_send_task when the target session was idle
233
- // at dispatch time. Combined with status === 'idle', it confirms no runtime transition.
234
- const dispatchedToIdleSession = dispatch.payload?.dispatchedToIdleSession === true;
235
- // Flag stale when no terminal event AND either:
236
- // - session is now idle (dispatch not acknowledged), OR
237
- // - no live status reported (node/session absent from live mesh), OR
238
- // - payload flagged idle-at-dispatch AND session is still not generating (redundant guard for clarity).
239
- const isNoTransition = !terminalStatus && !live.status;
240
- const isIdleUnacknowledged = status === 'idle';
241
- const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || (dispatchedToIdleSession && isIdleUnacknowledged))
242
- ? 'direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition'
243
- : undefined;
244
- const message = readString(dispatch.payload?.message) || readString(dispatch.payload?.summary) || '';
245
- const { title, summary } = summarizeMessage(message);
246
- // A dispatch is a fresh unacknowledged failure when the node and session both still exist
247
- // in the live mesh but the session never transitioned to generating. This is distinct from
248
- // historical/orphaned stale entries where the node or session is gone from the live mesh.
249
- // fresh-unacknowledged: ledgerOnlyStaleReason is set (session didn't ack) AND no live.staleReason (node/session is present)
250
- const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
251
- const record: MeshActiveWorkRecord = {
252
- taskId,
253
- source: 'direct',
254
- status,
255
- nodeId: dispatch.nodeId,
256
- sessionId: dispatch.sessionId,
257
- providerType: dispatch.providerType || readString(dispatch.payload?.providerType),
258
- taskTitle: readString(dispatch.payload?.taskTitle) || title,
259
- taskSummary: readString(dispatch.payload?.taskSummary) || summary,
260
- message,
261
- taskMode: readString(dispatch.payload?.taskMode),
262
- createdAt: dispatch.timestamp,
263
- updatedAt: terminal?.timestamp || dispatch.timestamp,
264
- dispatchedAt: dispatch.timestamp,
265
- elapsedMs: elapsedSince(dispatch.timestamp, now),
266
- terminal: terminalRow,
267
- terminalKind: terminal?.kind,
268
- terminalAt: terminal?.timestamp,
269
- staleReason: live.staleReason || ledgerOnlyStaleReason,
270
- ...(isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}),
271
- };
272
- if (terminalRow) {
273
- terminalDirectWork.push(record);
274
- if (opts.includeTerminalDirect !== true) continue;
227
+ // When BeadsDB direct dispatches are provided, use them for LOCAL dispatches (O(1) indexed).
228
+ // ALSO scan ledger for remote dispatches (P2P) whose taskIds are not in BeadsDB — these
229
+ // are never written to the local BeadsDB since they're dispatched from a remote daemon.
230
+ if (opts.directDispatches !== undefined) {
231
+ const dbTaskIds = new Set(opts.directDispatches.map(d => d.taskId));
232
+ for (const dispatch of opts.directDispatches) {
233
+ const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId ?? undefined, dispatch.sessionId ?? undefined);
234
+ const dbStatus = dispatch.status; // 'dispatched' | 'acked' | 'completed' | 'failed' | 'stale'
235
+ const isTerminal = dbStatus === 'completed' || dbStatus === 'failed' || dbStatus === 'stale';
236
+ const status: MeshActiveWorkStatus = isTerminal
237
+ ? (dbStatus === 'completed' ? 'idle' : 'failed')
238
+ : live.status || (dbStatus === 'acked' ? 'generating' : 'assigned');
239
+ const isNoTransition = !isTerminal && !live.status;
240
+ const isIdleUnacknowledged = status === 'idle' && !isTerminal;
241
+ const ledgerOnlyStaleReason = !isTerminal && (isIdleUnacknowledged || isNoTransition || (dispatch.dispatchedToIdleSession && isIdleUnacknowledged))
242
+ ? 'direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition'
243
+ : undefined;
244
+ const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
245
+ const { title, summary } = summarizeMessage(dispatch.message || '');
246
+ const record: MeshActiveWorkRecord = {
247
+ taskId: dispatch.taskId,
248
+ source: 'direct',
249
+ status,
250
+ nodeId: dispatch.nodeId ?? undefined,
251
+ sessionId: dispatch.sessionId ?? undefined,
252
+ providerType: dispatch.providerType ?? undefined,
253
+ taskTitle: title,
254
+ taskSummary: summary,
255
+ message: dispatch.message,
256
+ taskMode: dispatch.taskMode ?? undefined,
257
+ createdAt: dispatch.dispatchedAt,
258
+ updatedAt: dispatch.updatedAt,
259
+ dispatchedAt: dispatch.dispatchedAt,
260
+ elapsedMs: elapsedSince(dispatch.dispatchedAt, now),
261
+ terminal: isTerminal,
262
+ terminalKind: isTerminal ? (dbStatus === 'completed' ? 'task_completed' : 'task_failed') : undefined,
263
+ terminalAt: isTerminal ? dispatch.updatedAt : undefined,
264
+ staleReason: live.staleReason || ledgerOnlyStaleReason,
265
+ ...(isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}),
266
+ };
267
+ if (isTerminal) {
268
+ terminalDirectWork.push(record);
269
+ if (opts.includeTerminalDirect !== true) continue;
270
+ }
271
+ if ((live.staleReason || ledgerOnlyStaleReason) && !isTerminal) {
272
+ staleDirectWork.push(record);
273
+ continue;
274
+ }
275
+ records.push(record);
276
+ }
277
+ // Also scan ledger for remote dispatches (via p2p_direct) whose taskIds are NOT in BeadsDB.
278
+ // Remote daemons write their own local BeadsDB; this coordinator's BeadsDB only has local dispatches.
279
+ const ledgerEntries = (opts.ledgerEntries || []).slice().sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
280
+ const terminals = ledgerEntries.filter(entry => TERMINAL_LEDGER_KINDS.has(entry.kind) || entry.kind === 'task_approval_needed');
281
+ for (const dispatch of ledgerEntries.filter(isDirectDispatch)) {
282
+ const taskId = directDispatchTaskId(dispatch);
283
+ if (dbTaskIds.has(taskId)) continue; // already covered by BeadsDB path above
284
+ const terminal = terminals
285
+ .filter(entry => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime())
286
+ .find(entry => terminalMatchesDispatch(entry, dispatch, taskId));
287
+ const terminalStatus = terminal ? statusFromTerminal(terminal) : undefined;
288
+ const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
289
+ const status = terminalStatus || live.status || 'assigned';
290
+ const terminalRow = Boolean(terminal && terminal.kind !== 'task_approval_needed');
291
+ const dispatchedToIdleSession = dispatch.payload?.dispatchedToIdleSession === true;
292
+ const isNoTransition = !terminalStatus && !live.status;
293
+ const isIdleUnacknowledged = status === 'idle';
294
+ const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || (dispatchedToIdleSession && isIdleUnacknowledged))
295
+ ? 'direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition'
296
+ : undefined;
297
+ const message = readString(dispatch.payload?.message) || readString(dispatch.payload?.summary) || '';
298
+ const { title, summary } = summarizeMessage(message);
299
+ const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
300
+ const record: MeshActiveWorkRecord = {
301
+ taskId,
302
+ source: 'direct',
303
+ status,
304
+ nodeId: dispatch.nodeId,
305
+ sessionId: dispatch.sessionId,
306
+ providerType: dispatch.providerType || readString(dispatch.payload?.providerType),
307
+ taskTitle: readString(dispatch.payload?.taskTitle) || title,
308
+ taskSummary: readString(dispatch.payload?.taskSummary) || summary,
309
+ message,
310
+ taskMode: readString(dispatch.payload?.taskMode),
311
+ createdAt: dispatch.timestamp,
312
+ updatedAt: terminal?.timestamp || dispatch.timestamp,
313
+ dispatchedAt: dispatch.timestamp,
314
+ elapsedMs: elapsedSince(dispatch.timestamp, now),
315
+ terminal: terminalRow,
316
+ terminalKind: terminal?.kind,
317
+ terminalAt: terminal?.timestamp,
318
+ staleReason: live.staleReason || ledgerOnlyStaleReason,
319
+ ...(isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}),
320
+ };
321
+ if (terminalRow) {
322
+ terminalDirectWork.push(record);
323
+ if (opts.includeTerminalDirect !== true) continue;
324
+ }
325
+ if ((live.staleReason || ledgerOnlyStaleReason) && !terminalRow) {
326
+ staleDirectWork.push(record);
327
+ continue;
328
+ }
329
+ records.push(record);
275
330
  }
276
- if ((live.staleReason || ledgerOnlyStaleReason) && !terminalRow) {
277
- staleDirectWork.push(record);
278
- continue;
331
+ } else {
332
+ // Full ledger scan: no BeadsDB direct dispatches available (standalone mode or empty).
333
+ const ledgerEntries = (opts.ledgerEntries || []).slice().sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
334
+ const terminals = ledgerEntries.filter(entry => TERMINAL_LEDGER_KINDS.has(entry.kind) || entry.kind === 'task_approval_needed');
335
+ for (const dispatch of ledgerEntries.filter(isDirectDispatch)) {
336
+ const taskId = directDispatchTaskId(dispatch);
337
+ const terminal = terminals
338
+ .filter(entry => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime())
339
+ .find(entry => terminalMatchesDispatch(entry, dispatch, taskId));
340
+ const terminalStatus = terminal ? statusFromTerminal(terminal) : undefined;
341
+ const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
342
+ const status = terminalStatus || live.status || 'assigned';
343
+ const terminalRow = Boolean(terminal && terminal.kind !== 'task_approval_needed');
344
+ const dispatchedToIdleSession = dispatch.payload?.dispatchedToIdleSession === true;
345
+ const isNoTransition = !terminalStatus && !live.status;
346
+ const isIdleUnacknowledged = status === 'idle';
347
+ const ledgerOnlyStaleReason = !terminalRow && (isIdleUnacknowledged || isNoTransition || (dispatchedToIdleSession && isIdleUnacknowledged))
348
+ ? 'direct task dispatch has no provider acknowledgement, transcript append, or active runtime transition'
349
+ : undefined;
350
+ const message = readString(dispatch.payload?.message) || readString(dispatch.payload?.summary) || '';
351
+ const { title, summary } = summarizeMessage(message);
352
+ const isFreshUnacknowledged = Boolean(ledgerOnlyStaleReason && !live.staleReason);
353
+ const record: MeshActiveWorkRecord = {
354
+ taskId,
355
+ source: 'direct',
356
+ status,
357
+ nodeId: dispatch.nodeId,
358
+ sessionId: dispatch.sessionId,
359
+ providerType: dispatch.providerType || readString(dispatch.payload?.providerType),
360
+ taskTitle: readString(dispatch.payload?.taskTitle) || title,
361
+ taskSummary: readString(dispatch.payload?.taskSummary) || summary,
362
+ message,
363
+ taskMode: readString(dispatch.payload?.taskMode),
364
+ createdAt: dispatch.timestamp,
365
+ updatedAt: terminal?.timestamp || dispatch.timestamp,
366
+ dispatchedAt: dispatch.timestamp,
367
+ elapsedMs: elapsedSince(dispatch.timestamp, now),
368
+ terminal: terminalRow,
369
+ terminalKind: terminal?.kind,
370
+ terminalAt: terminal?.timestamp,
371
+ staleReason: live.staleReason || ledgerOnlyStaleReason,
372
+ ...(isFreshUnacknowledged ? { staleDispatchUnacknowledged: true } : {}),
373
+ };
374
+ if (terminalRow) {
375
+ terminalDirectWork.push(record);
376
+ if (opts.includeTerminalDirect !== true) continue;
377
+ }
378
+ if ((live.staleReason || ledgerOnlyStaleReason) && !terminalRow) {
379
+ staleDirectWork.push(record);
380
+ continue;
381
+ }
382
+ records.push(record);
279
383
  }
280
- records.push(record);
281
384
  }
282
385
 
283
386
  records.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());