@adhdev/daemon-core 0.9.82-rc.9 → 0.9.82-rc.90

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 (67) hide show
  1. package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -0
  2. package/dist/cli-adapters/provider-cli-parse.d.ts +1 -0
  3. package/dist/cli-adapters/provider-cli-shared.d.ts +2 -0
  4. package/dist/commands/router.d.ts +22 -0
  5. package/dist/config/mesh-config.d.ts +66 -1
  6. package/dist/index.d.ts +13 -6
  7. package/dist/index.js +5395 -1197
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +5359 -1183
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/installer.d.ts +1 -4
  12. package/dist/launch.d.ts +1 -1
  13. package/dist/logging/async-batch-writer.d.ts +10 -0
  14. package/dist/mesh/beads-db.d.ts +18 -0
  15. package/dist/mesh/mesh-active-work.d.ts +60 -0
  16. package/dist/mesh/mesh-events.d.ts +29 -5
  17. package/dist/mesh/mesh-fast-forward.d.ts +39 -0
  18. package/dist/mesh/mesh-host-ownership.d.ts +9 -0
  19. package/dist/mesh/mesh-ledger.d.ts +38 -1
  20. package/dist/mesh/mesh-work-queue.d.ts +27 -5
  21. package/dist/mesh/refine-config.d.ts +176 -0
  22. package/dist/providers/chat-message-normalization.d.ts +1 -0
  23. package/dist/providers/cli-provider-instance.d.ts +2 -1
  24. package/dist/repo-mesh-types.d.ts +46 -0
  25. package/dist/status/reporter.d.ts +2 -0
  26. package/package.json +3 -1
  27. package/src/boot/daemon-lifecycle.ts +1 -0
  28. package/src/cli-adapters/provider-cli-adapter.ts +91 -3
  29. package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
  30. package/src/cli-adapters/provider-cli-parse.ts +4 -0
  31. package/src/cli-adapters/provider-cli-runtime.ts +3 -1
  32. package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
  33. package/src/cli-adapters/provider-cli-shared.ts +20 -10
  34. package/src/commands/chat-commands.ts +454 -15
  35. package/src/commands/cli-manager.ts +126 -0
  36. package/src/commands/handler.ts +8 -1
  37. package/src/commands/mesh-coordinator.ts +13 -143
  38. package/src/commands/router.ts +2687 -435
  39. package/src/config/chat-history.ts +9 -7
  40. package/src/config/mesh-config.ts +245 -1
  41. package/src/daemon/dev-cli-debug.ts +10 -1
  42. package/src/detection/ide-detector.ts +26 -16
  43. package/src/index.ts +31 -5
  44. package/src/installer.d.ts +1 -1
  45. package/src/installer.ts +8 -6
  46. package/src/launch.d.ts +1 -1
  47. package/src/launch.ts +37 -28
  48. package/src/logging/async-batch-writer.ts +55 -0
  49. package/src/logging/logger.ts +2 -1
  50. package/src/mesh/beads-db.ts +176 -0
  51. package/src/mesh/coordinator-prompt.ts +30 -7
  52. package/src/mesh/mesh-active-work.ts +243 -0
  53. package/src/mesh/mesh-events.ts +400 -47
  54. package/src/mesh/mesh-fast-forward.ts +430 -0
  55. package/src/mesh/mesh-host-ownership.ts +73 -0
  56. package/src/mesh/mesh-ledger.ts +138 -1
  57. package/src/mesh/mesh-work-queue.ts +199 -137
  58. package/src/mesh/refine-config.ts +356 -0
  59. package/src/providers/chat-message-normalization.ts +3 -1
  60. package/src/providers/cli-provider-instance.ts +91 -13
  61. package/src/providers/ide-provider-instance.ts +17 -3
  62. package/src/providers/provider-loader.ts +10 -4
  63. package/src/providers/read-chat-contract.ts +1 -1
  64. package/src/providers/version-archive.ts +38 -20
  65. package/src/repo-mesh-types.ts +51 -0
  66. package/src/status/reporter.ts +15 -0
  67. package/src/system/host-memory.ts +29 -12
@@ -0,0 +1,243 @@
1
+ import type { MeshLedgerEntry } from './mesh-ledger.js';
2
+ import type { MeshWorkQueueEntry } from './mesh-work-queue.js';
3
+
4
+ export type MeshActiveWorkSource = 'queue' | 'direct';
5
+ export type MeshActiveWorkStatus = 'pending' | 'assigned' | 'generating' | 'idle' | 'failed' | 'awaiting_approval';
6
+
7
+ export interface MeshActiveWorkRecord {
8
+ taskId: string;
9
+ source: MeshActiveWorkSource;
10
+ status: MeshActiveWorkStatus;
11
+ nodeId?: string;
12
+ sessionId?: string;
13
+ providerType?: string;
14
+ taskTitle: string;
15
+ taskSummary: string;
16
+ message?: string;
17
+ taskMode?: string;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ dispatchedAt?: string;
21
+ elapsedMs: number;
22
+ terminal?: boolean;
23
+ terminalKind?: string;
24
+ terminalAt?: string;
25
+ staleReason?: string;
26
+ }
27
+
28
+ export interface MeshActiveWorkSummary {
29
+ totalActiveCount: number;
30
+ queueActiveCount: number;
31
+ directActiveCount: number;
32
+ awaitingApprovalCount: number;
33
+ generatingCount: number;
34
+ failedCount: number;
35
+ idleCount: number;
36
+ sourceCounts: Record<MeshActiveWorkSource, number>;
37
+ statusCounts: Record<MeshActiveWorkStatus, number>;
38
+ staleDirectCount: number;
39
+ /**
40
+ * When staleDirectCount > 0, this note clarifies that stale direct records are
41
+ * historical/recovery evidence — orphaned ledger entries whose original node or session
42
+ * is no longer present in the live mesh. They are NOT active or unresolved work items.
43
+ * The active queue (queue source) is the authoritative source for pending/assigned work.
44
+ */
45
+ staleDirectNote?: string;
46
+ }
47
+
48
+ export interface BuildMeshActiveWorkOptions {
49
+ meshId: string;
50
+ queue?: MeshWorkQueueEntry[];
51
+ ledgerEntries?: MeshLedgerEntry[];
52
+ nodes?: any[];
53
+ now?: number;
54
+ /** Include terminal direct rows (idle/failed) for handoff/recent-work surfaces. Defaults false. */
55
+ includeTerminalDirect?: boolean;
56
+ }
57
+
58
+ const DIRECT_DISPATCH_VIA = new Set(['p2p_direct', 'local_direct', 'mesh_send_task']);
59
+ const TERMINAL_LEDGER_KINDS = new Set(['task_completed', 'task_failed', 'task_stalled']);
60
+
61
+ function readString(value: unknown): string | undefined {
62
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
63
+ }
64
+
65
+ function summarizeMessage(message: string): { title: string; summary: string } {
66
+ const oneLine = message.replace(/\s+/g, ' ').trim();
67
+ const title = oneLine.length > 96 ? `${oneLine.slice(0, 93)}...` : oneLine;
68
+ return { title: title || '(untitled task)', summary: oneLine };
69
+ }
70
+
71
+ function elapsedSince(value: string | undefined, now: number): number {
72
+ const started = value ? new Date(value).getTime() : Number.NaN;
73
+ return Number.isFinite(started) ? Math.max(0, now - started) : 0;
74
+ }
75
+
76
+ function sessionStatusFromNodes(nodes: any[] | undefined, nodeId?: string, sessionId?: string): { status?: MeshActiveWorkStatus; staleReason?: string } {
77
+ if (!Array.isArray(nodes)) return {};
78
+ if (!nodeId) return { staleReason: 'direct task has no node id' };
79
+ const node = nodes.find(item => readString(item?.id) === nodeId || readString(item?.nodeId) === nodeId || readString(item?.node_id) === nodeId);
80
+ if (!node) return { staleReason: 'direct task node is no longer in the live mesh' };
81
+ if (!sessionId) return {};
82
+ const candidates: any[] = [];
83
+ for (const value of [node.sessions, node.activeSessions, node.active_sessions, node.lastProbe?.sessions, node.last_probe?.sessions, node.lastProbe?.status?.sessions, node.last_probe?.status?.sessions]) {
84
+ if (Array.isArray(value)) candidates.push(...value);
85
+ }
86
+ for (const value of [node.activeSession, node.active_session, node.currentSession, node.current_session, node.runtimeSession, node.runtime_session, node.session]) {
87
+ if (value && typeof value === 'object') candidates.push(value);
88
+ }
89
+ const session = candidates.find(item => {
90
+ if (typeof item === 'string') return item === sessionId;
91
+ const id = readString(item?.id) || readString(item?.sessionId) || readString(item?.session_id) || readString(item?.runtimeSessionId) || readString(item?.instanceId);
92
+ return id === sessionId;
93
+ });
94
+ if (!session) return { staleReason: 'direct task session is not present in live session records' };
95
+ if (typeof session === 'string') return {};
96
+ const raw = `${readString(session.status) || ''} ${readString(session.lifecycle) || ''} ${readString(session.state) || ''} ${readString(session.activeChat?.status) || ''}`.toLowerCase();
97
+ if (raw.includes('approval')) return { status: 'awaiting_approval' };
98
+ if (raw.includes('generating') || raw.includes('running') || raw.includes('busy')) return { status: 'generating' };
99
+ if (raw.includes('failed') || raw.includes('stopped') || raw.includes('terminated') || raw.includes('exited')) return { status: 'failed' };
100
+ if (raw.includes('idle') || raw.includes('waiting_input') || raw.includes('ready')) return { status: 'idle' };
101
+ return {};
102
+ }
103
+
104
+ function isDirectDispatch(entry: MeshLedgerEntry): boolean {
105
+ if (entry.kind !== 'task_dispatched') return false;
106
+ const payload = entry.payload || {};
107
+ if (payload.source === 'direct') return true;
108
+ const via = readString(payload.via);
109
+ return Boolean(via && DIRECT_DISPATCH_VIA.has(via) && payload.source !== 'queue');
110
+ }
111
+
112
+ function directDispatchTaskId(entry: MeshLedgerEntry): string {
113
+ return readString(entry.payload?.taskId) || entry.id;
114
+ }
115
+
116
+ function terminalMatchesDispatch(terminal: MeshLedgerEntry, dispatch: MeshLedgerEntry, taskId: string): boolean {
117
+ const terminalTaskId = readString(terminal.payload?.taskId);
118
+ if (terminalTaskId && terminalTaskId === taskId) return true;
119
+ if (terminalTaskId && terminalTaskId !== taskId) return false;
120
+ if (dispatch.sessionId && terminal.sessionId === dispatch.sessionId) return true;
121
+ return Boolean(dispatch.nodeId && terminal.nodeId === dispatch.nodeId && !dispatch.sessionId);
122
+ }
123
+
124
+ function statusFromTerminal(entry: MeshLedgerEntry): MeshActiveWorkStatus {
125
+ if (entry.kind === 'task_approval_needed') return 'awaiting_approval';
126
+ if (entry.kind === 'task_completed') return 'idle';
127
+ return 'failed';
128
+ }
129
+
130
+ export function buildMeshActiveWorkSummary(activeWork: MeshActiveWorkRecord[]): MeshActiveWorkSummary {
131
+ const statusCounts: Record<MeshActiveWorkStatus, number> = {
132
+ pending: 0,
133
+ assigned: 0,
134
+ generating: 0,
135
+ idle: 0,
136
+ failed: 0,
137
+ awaiting_approval: 0,
138
+ };
139
+ const sourceCounts: Record<MeshActiveWorkSource, number> = { queue: 0, direct: 0 };
140
+ for (const item of activeWork) {
141
+ sourceCounts[item.source] += 1;
142
+ statusCounts[item.status] += 1;
143
+ }
144
+ const staleDirectCount = activeWork.filter(item => item.source === 'direct' && item.staleReason).length;
145
+ return {
146
+ totalActiveCount: activeWork.length,
147
+ queueActiveCount: sourceCounts.queue,
148
+ directActiveCount: sourceCounts.direct,
149
+ awaitingApprovalCount: statusCounts.awaiting_approval,
150
+ generatingCount: statusCounts.generating,
151
+ failedCount: statusCounts.failed,
152
+ idleCount: statusCounts.idle,
153
+ sourceCounts,
154
+ statusCounts,
155
+ staleDirectCount,
156
+ ...(staleDirectCount > 0 ? { staleDirectNote: 'Stale direct records are orphaned ledger entries whose node/session no longer exists. They are historical recovery evidence only — not active or unresolved work. The queue (source: queue) is authoritative for pending/assigned tasks.' } : {}),
157
+ };
158
+ }
159
+
160
+
161
+ export function buildMeshActiveWork(opts: BuildMeshActiveWorkOptions): { activeWork: MeshActiveWorkRecord[]; staleDirectWork: MeshActiveWorkRecord[]; staleDirectWorkNote?: string; terminalDirectWork: MeshActiveWorkRecord[]; summary: MeshActiveWorkSummary } {
162
+ const now = opts.now ?? Date.now();
163
+ const records: MeshActiveWorkRecord[] = [];
164
+ const staleDirectWork: MeshActiveWorkRecord[] = [];
165
+ const terminalDirectWork: MeshActiveWorkRecord[] = [];
166
+
167
+ for (const task of opts.queue || []) {
168
+ if (task.status !== 'pending' && task.status !== 'assigned') continue;
169
+ const { title, summary } = summarizeMessage(task.message || '');
170
+ records.push({
171
+ taskId: task.id,
172
+ source: 'queue',
173
+ status: task.status,
174
+ nodeId: task.assignedNodeId || task.targetNodeId,
175
+ sessionId: task.assignedSessionId || task.targetSessionId,
176
+ taskTitle: title,
177
+ taskSummary: summary,
178
+ message: task.message,
179
+ taskMode: task.taskMode,
180
+ createdAt: task.createdAt,
181
+ updatedAt: task.updatedAt,
182
+ dispatchedAt: task.dispatchTimestamp,
183
+ elapsedMs: elapsedSince(task.dispatchTimestamp || task.createdAt, now),
184
+ });
185
+ }
186
+
187
+ const ledgerEntries = (opts.ledgerEntries || []).slice().sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
188
+ const terminals = ledgerEntries.filter(entry => TERMINAL_LEDGER_KINDS.has(entry.kind) || entry.kind === 'task_approval_needed');
189
+ for (const dispatch of ledgerEntries.filter(isDirectDispatch)) {
190
+ const taskId = directDispatchTaskId(dispatch);
191
+ const terminal = terminals
192
+ .filter(entry => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime())
193
+ .find(entry => terminalMatchesDispatch(entry, dispatch, taskId));
194
+ const terminalStatus = terminal ? statusFromTerminal(terminal) : undefined;
195
+ const live = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
196
+ const status = terminalStatus || live.status || 'assigned';
197
+ const terminalRow = Boolean(terminal && terminal.kind !== 'task_approval_needed');
198
+ const message = readString(dispatch.payload?.message) || readString(dispatch.payload?.summary) || '';
199
+ const { title, summary } = summarizeMessage(message);
200
+ const record: MeshActiveWorkRecord = {
201
+ taskId,
202
+ source: 'direct',
203
+ status,
204
+ nodeId: dispatch.nodeId,
205
+ sessionId: dispatch.sessionId,
206
+ providerType: dispatch.providerType || readString(dispatch.payload?.providerType),
207
+ taskTitle: readString(dispatch.payload?.taskTitle) || title,
208
+ taskSummary: readString(dispatch.payload?.taskSummary) || summary,
209
+ message,
210
+ taskMode: readString(dispatch.payload?.taskMode),
211
+ createdAt: dispatch.timestamp,
212
+ updatedAt: terminal?.timestamp || dispatch.timestamp,
213
+ dispatchedAt: dispatch.timestamp,
214
+ elapsedMs: elapsedSince(dispatch.timestamp, now),
215
+ terminal: terminalRow,
216
+ terminalKind: terminal?.kind,
217
+ terminalAt: terminal?.timestamp,
218
+ staleReason: live.staleReason,
219
+ };
220
+ if (terminalRow) {
221
+ terminalDirectWork.push(record);
222
+ if (opts.includeTerminalDirect !== true) continue;
223
+ }
224
+ if (live.staleReason && !terminalRow) {
225
+ staleDirectWork.push(record);
226
+ continue;
227
+ }
228
+ records.push(record);
229
+ }
230
+
231
+ records.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
232
+ staleDirectWork.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
233
+ terminalDirectWork.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
234
+ const summary = buildMeshActiveWorkSummary(records);
235
+ summary.staleDirectCount = staleDirectWork.length;
236
+ const staleDirectWorkNote = staleDirectWork.length > 0
237
+ ? 'These are orphaned ledger entries whose original node or session no longer exists in the live mesh. They are historical/recovery evidence only — not active or unresolved work. Do not treat staleDirectCount as a status mismatch; use the queue (source: queue) as authoritative for pending/assigned tasks.'
238
+ : undefined;
239
+ if (staleDirectWorkNote) {
240
+ summary.staleDirectNote = staleDirectWorkNote;
241
+ }
242
+ return { activeWork: records, staleDirectWork, staleDirectWorkNote, terminalDirectWork, summary };
243
+ }