@adhdev/daemon-core 0.9.82-rc.376 → 0.9.82-rc.378

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 (48) hide show
  1. package/dist/commands/chat-commands-debug-bundle.d.ts +14 -0
  2. package/dist/commands/chat-commands-read.d.ts +7 -0
  3. package/dist/commands/chat-commands-scope.d.ts +39 -0
  4. package/dist/commands/chat-commands-shared.d.ts +33 -0
  5. package/dist/commands/chat-commands-write.d.ts +14 -0
  6. package/dist/commands/chat-commands.d.ts +9 -49
  7. package/dist/commands/router.d.ts +3 -470
  8. package/dist/index.js +3166 -3115
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +3561 -3510
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  13. package/dist/mesh/mesh-event-classify.d.ts +5 -0
  14. package/dist/mesh/mesh-event-forwarding.d.ts +18 -0
  15. package/dist/mesh/mesh-events-coordinator.d.ts +4 -92
  16. package/dist/mesh/mesh-events-utils.d.ts +3 -0
  17. package/dist/mesh/mesh-ledger-reconciliation.d.ts +0 -1
  18. package/dist/mesh/mesh-node-identity.d.ts +289 -0
  19. package/dist/mesh/mesh-queue-assignment.d.ts +86 -0
  20. package/dist/mesh/mesh-refine-gates.d.ts +428 -0
  21. package/dist/mesh/mesh-runtime-store.d.ts +0 -3
  22. package/dist/providers/native-history/constants.d.ts +12 -0
  23. package/dist/runtime-defaults.d.ts +2 -0
  24. package/package.json +2 -2
  25. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  26. package/src/commands/chat-commands-read.ts +2327 -0
  27. package/src/commands/chat-commands-scope.ts +54 -0
  28. package/src/commands/chat-commands-shared.ts +114 -0
  29. package/src/commands/chat-commands-write.ts +880 -0
  30. package/src/commands/chat-commands.ts +20 -3697
  31. package/src/commands/router.ts +59 -3631
  32. package/src/mesh/mesh-coordinator-config.ts +97 -0
  33. package/src/mesh/mesh-event-classify.ts +51 -0
  34. package/src/mesh/mesh-event-forwarding.ts +1502 -0
  35. package/src/mesh/mesh-events-coordinator.ts +30 -2993
  36. package/src/mesh/mesh-events-pending.ts +1 -10
  37. package/src/mesh/mesh-events-stale.ts +3 -14
  38. package/src/mesh/mesh-events-utils.ts +52 -14
  39. package/src/mesh/mesh-ledger-reconciliation.ts +0 -2
  40. package/src/mesh/mesh-node-identity.ts +1887 -0
  41. package/src/mesh/mesh-queue-assignment.ts +1457 -0
  42. package/src/mesh/mesh-refine-gates.ts +1652 -0
  43. package/src/mesh/mesh-runtime-store.ts +0 -37
  44. package/src/providers/cli-provider-instance.ts +40 -1
  45. package/src/providers/native-history/constants.ts +19 -0
  46. package/src/providers/native-history/dispatcher.ts +2 -3
  47. package/src/providers/spec/native-history-executor.ts +1 -9
  48. package/src/runtime-defaults.ts +39 -0
@@ -0,0 +1,398 @@
1
+ /**
2
+ * Chat Commands — get_chat_debug_bundle: sanitize, summarize and store a
3
+ * diagnostic snapshot of the current read_chat / provider / session state.
4
+ */
5
+
6
+ import * as fs from 'node:fs';
7
+ import * as os from 'node:os';
8
+ import * as path from 'node:path';
9
+ import { randomUUID } from 'node:crypto';
10
+ import type { CommandResult, CommandHelpers } from './handler.js';
11
+ import type { ProviderModule } from '../providers/contracts.js';
12
+ import { LOG, getRecentLogs } from '../logging/logger.js';
13
+ import { getRecentDebugTrace } from '../logging/debug-trace.js';
14
+ import {
15
+ getCurrentManagerKey,
16
+ getCurrentProviderType,
17
+ getTargetTransport,
18
+ getTargetedCliAdapter,
19
+ getTargetInstance,
20
+ isCliLikeTransport,
21
+ parseMaybeJson,
22
+ } from './chat-commands-shared.js';
23
+ import { handleReadChat } from './chat-commands-read.js';
24
+
25
+ interface DebugSanitizeOptions {
26
+ maxDepth?: number;
27
+ maxArrayLength?: number;
28
+ maxObjectKeys?: number;
29
+ maxStringLength?: number;
30
+ }
31
+
32
+ const DEFAULT_DEBUG_SANITIZE_OPTIONS: Required<DebugSanitizeOptions> = {
33
+ maxDepth: 8,
34
+ maxArrayLength: 80,
35
+ maxObjectKeys: 120,
36
+ maxStringLength: 16_000,
37
+ };
38
+
39
+ const SECRET_KEY_PATTERN = /(?:token|secret|password|passwd|authorization|cookie|api[_-]?key|access[_-]?key|refresh[_-]?token|client[_-]?secret|private[_-]?key)/i;
40
+
41
+ function truncateDebugString(value: string, maxLength: number): string {
42
+ if (value.length <= maxLength) return value;
43
+ return `${value.slice(0, maxLength)}…[truncated ${value.length - maxLength} chars]`;
44
+ }
45
+
46
+ function redactDebugSecrets(value: string): string {
47
+ return value
48
+ .replace(/(Authorization\s*:\s*Bearer\s+)[^\s'"`]+/gi, '$1[REDACTED:bearer]')
49
+ .replace(/(Bearer\s+)[A-Za-z0-9._~+\/-]{16,}=*/gi, '$1[REDACTED:bearer]')
50
+ .replace(/\b(?:gh[pousr]|github_pat)_[A-Za-z0-9_]{20,}\b/g, '[REDACTED:github-token]')
51
+ .replace(/\bsk-[A-Za-z0-9_-]{16,}\b/g, '[REDACTED:api-key]')
52
+ .replace(/\bxox[baprs]-[A-Za-z0-9-]{12,}\b/g, '[REDACTED:slack-token]')
53
+ .replace(/\b(?:adk|adm)_[A-Za-z0-9_-]{16,}\b/g, '[REDACTED:adhdev-token]')
54
+ .replace(/((?:api[_-]?key|token|secret|password|passwd|client[_-]?secret)\s*[:=]\s*)[^\s,'"`}&]+/gi, '$1[REDACTED:secret]')
55
+ .replace(/([?&](?:api[_-]?key|token|secret|password|client_secret)=)[^&#\s]+/gi, '$1[REDACTED:secret]');
56
+ }
57
+
58
+ export function sanitizeDebugBundleValue(
59
+ value: unknown,
60
+ options: DebugSanitizeOptions = {},
61
+ depth = 0,
62
+ keyHint = '',
63
+ ): unknown {
64
+ const normalizedOptions = { ...DEFAULT_DEBUG_SANITIZE_OPTIONS, ...options };
65
+ if (value === null || value === undefined) return value;
66
+ if (typeof value === 'number' || typeof value === 'boolean') return value;
67
+ if (typeof value === 'bigint') return String(value);
68
+ if (typeof value === 'string') {
69
+ if (SECRET_KEY_PATTERN.test(keyHint) && value.trim()) return '[REDACTED:secret-field]';
70
+ return truncateDebugString(redactDebugSecrets(value), normalizedOptions.maxStringLength);
71
+ }
72
+ if (typeof value === 'function') return `[Function ${value.name || 'anonymous'}]`;
73
+ if (typeof value !== 'object') return String(value);
74
+ if (depth >= normalizedOptions.maxDepth) return '[MaxDepth]';
75
+
76
+ if (Array.isArray(value)) {
77
+ const items = value
78
+ .slice(0, normalizedOptions.maxArrayLength)
79
+ .map((item) => sanitizeDebugBundleValue(item, normalizedOptions, depth + 1, keyHint));
80
+ if (value.length > normalizedOptions.maxArrayLength) {
81
+ items.push(`[truncated ${value.length - normalizedOptions.maxArrayLength} items]`);
82
+ }
83
+ return items;
84
+ }
85
+
86
+ const record = value as Record<string, unknown>;
87
+ const result: Record<string, unknown> = {};
88
+ const entries = Object.entries(record).slice(0, normalizedOptions.maxObjectKeys);
89
+ for (const [key, item] of entries) {
90
+ result[key] = sanitizeDebugBundleValue(item, normalizedOptions, depth + 1, key);
91
+ }
92
+ const remaining = Object.keys(record).length - entries.length;
93
+ if (remaining > 0) result.__truncatedKeys = remaining;
94
+ return result;
95
+ }
96
+
97
+ function summarizeProviderForDebug(provider: ProviderModule | undefined): Record<string, unknown> | null {
98
+ if (!provider) return null;
99
+ const scripts = provider.scripts && typeof provider.scripts === 'object'
100
+ ? Object.keys(provider.scripts)
101
+ : [];
102
+ const controls = Array.isArray((provider as any).controls)
103
+ ? (provider as any).controls.map((control: any) => ({
104
+ id: control?.id,
105
+ label: control?.label,
106
+ type: control?.type,
107
+ settingKey: control?.settingKey,
108
+ invokeScript: control?.invokeScript,
109
+ listScript: control?.listScript,
110
+ location: control?.location,
111
+ }))
112
+ : [];
113
+ return {
114
+ type: provider.type,
115
+ name: provider.name,
116
+ category: provider.category,
117
+ version: (provider as any).version,
118
+ canonicalHistory: provider.nativeHistory,
119
+ historyBehavior: provider.historyBehavior,
120
+ webviewMatchText: provider.webviewMatchText,
121
+ scriptNames: scripts,
122
+ controls,
123
+ resume: provider.resume,
124
+ };
125
+ }
126
+
127
+ function summarizeSessionForDebug(session: any): Record<string, unknown> | null {
128
+ if (!session || typeof session !== 'object') return null;
129
+ return {
130
+ sessionId: session.sessionId,
131
+ instanceKey: session.instanceKey,
132
+ adapterKey: session.adapterKey,
133
+ providerType: session.providerType,
134
+ providerName: session.providerName,
135
+ transport: session.transport,
136
+ kind: session.kind,
137
+ cdpManagerKey: session.cdpManagerKey,
138
+ parentSessionId: session.parentSessionId,
139
+ providerSessionId: session.providerSessionId,
140
+ workspace: session.workspace,
141
+ title: session.title,
142
+ status: session.status,
143
+ mode: session.mode,
144
+ capabilities: session.capabilities,
145
+ };
146
+ }
147
+
148
+ function summarizeStateForDebug(state: any): Record<string, unknown> | null {
149
+ if (!state || typeof state !== 'object') return null;
150
+ const activeChat = state.activeChat && typeof state.activeChat === 'object' ? state.activeChat : null;
151
+ return {
152
+ type: state.type,
153
+ name: state.name,
154
+ category: state.category,
155
+ status: state.status,
156
+ instanceId: state.instanceId,
157
+ providerSessionId: state.providerSessionId,
158
+ title: state.title,
159
+ transport: state.transport,
160
+ mode: state.mode,
161
+ workspace: state.workspace,
162
+ runtime: state.runtime,
163
+ errorMessage: state.errorMessage,
164
+ errorReason: state.errorReason,
165
+ activeChat: activeChat ? {
166
+ status: activeChat.status,
167
+ title: activeChat.title,
168
+ messageCount: Array.isArray(activeChat.messages) ? activeChat.messages.length : undefined,
169
+ activeModal: activeChat.activeModal,
170
+ activeInteractivePrompt: activeChat.activeInteractivePrompt ?? null,
171
+ messagesTail: Array.isArray(activeChat.messages) ? activeChat.messages.slice(-10) : undefined,
172
+ } : null,
173
+ activeInteractivePrompt: (state as { activeInteractivePrompt?: unknown }).activeInteractivePrompt ?? null,
174
+ controlValues: state.controlValues,
175
+ summaryMetadata: state.summaryMetadata,
176
+ };
177
+ }
178
+
179
+ function buildDebugBundleText(bundle: Record<string, unknown>): string {
180
+ return [
181
+ '# ADHDev Chat Debug Bundle',
182
+ '',
183
+ '```json',
184
+ JSON.stringify(bundle, null, 2),
185
+ '```',
186
+ ].join('\n');
187
+ }
188
+
189
+ function getChatDebugBundleDir(): string {
190
+ const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === 'string'
191
+ ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim()
192
+ : '';
193
+ return override || path.join(os.homedir(), '.adhdev', 'debug-bundles', 'chat');
194
+ }
195
+
196
+ function safeBundleIdSegment(value: unknown, fallback: string): string {
197
+ const normalized = String(value || fallback)
198
+ .trim()
199
+ .replace(/[^A-Za-z0-9_.-]+/g, '-')
200
+ .replace(/^-+|-+$/g, '')
201
+ .slice(0, 80);
202
+ return normalized || fallback;
203
+ }
204
+
205
+ function createChatDebugBundleId(targetSessionId: string): string {
206
+ const timestamp = new Date().toISOString().replace(/[-:.]/g, '').replace('T', 'T').replace('Z', 'Z');
207
+ const sessionSegment = safeBundleIdSegment(targetSessionId, 'unknown-session');
208
+ return `chat-debug-${timestamp}-${sessionSegment}-${randomUUID().slice(0, 8)}`;
209
+ }
210
+
211
+ function buildChatDebugBundleSummary(bundle: Record<string, unknown>): Record<string, unknown> {
212
+ const target = bundle.target && typeof bundle.target === 'object' ? bundle.target as Record<string, unknown> : {};
213
+ const readChat = bundle.readChat && typeof bundle.readChat === 'object' ? bundle.readChat as Record<string, unknown> : {};
214
+ const cli = bundle.cli && typeof bundle.cli === 'object' ? bundle.cli as Record<string, unknown> : null;
215
+ const frontend = bundle.frontend && typeof bundle.frontend === 'object' ? bundle.frontend as Record<string, unknown> : null;
216
+ const debugReadChat = readChat.debugReadChat && typeof readChat.debugReadChat === 'object'
217
+ ? readChat.debugReadChat as Record<string, unknown>
218
+ : {};
219
+ const parsedStatus = cli?.parsedStatus && typeof cli.parsedStatus === 'object'
220
+ ? cli.parsedStatus as Record<string, unknown>
221
+ : null;
222
+ const cliParsedMessageCount = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages.length : undefined;
223
+ const readChatReturnedMessages = Array.isArray(readChat.messagesTail) ? readChat.messagesTail.length : undefined;
224
+ const cliPartialResponse = typeof cli?.partialResponse === 'string' ? cli.partialResponse : '';
225
+ const readChatStatus = typeof readChat.status === 'string' ? readChat.status : '';
226
+ const cliStatus = typeof cli?.status === 'string' ? cli.status : '';
227
+ const cliParsedStatus = typeof parsedStatus?.status === 'string' ? parsedStatus.status : '';
228
+ return {
229
+ createdAt: bundle.createdAt,
230
+ targetSessionId: target.targetSessionId,
231
+ providerType: target.providerType,
232
+ transport: target.transport,
233
+ readChatSuccess: readChat.success,
234
+ readChatStatus: readChat.status,
235
+ readChatTotalMessages: readChat.totalMessages,
236
+ readChatReturnedMessages,
237
+ cliStatus: cli?.status,
238
+ cliParsedStatus: cliParsedStatus || undefined,
239
+ cliMessageCount: cli?.messageCount,
240
+ cliParsedMessageCount,
241
+ cliPartialResponseChars: cliPartialResponse.length,
242
+ parserAdapterStatusMismatch: Boolean(cliStatus && cliParsedStatus && cliStatus !== cliParsedStatus),
243
+ parserReadChatStatusMismatch: Boolean(readChatStatus && cliParsedStatus && readChatStatus !== cliParsedStatus),
244
+ readChatDebug: Object.keys(debugReadChat).length ? {
245
+ adapterStatus: debugReadChat.adapterStatus,
246
+ parsedStatus: debugReadChat.parsedStatus,
247
+ returnedStatus: debugReadChat.returnedStatus,
248
+ selectedMessageSource: debugReadChat.selectedMessageSource,
249
+ messageSource: debugReadChat.messageSource,
250
+ parsedMsgCount: debugReadChat.parsedMsgCount,
251
+ returnedMsgCount: debugReadChat.returnedMsgCount,
252
+ shouldPreferAdapterMessages: debugReadChat.shouldPreferAdapterMessages,
253
+ } : undefined,
254
+ hasFrontendSnapshot: !!frontend,
255
+ };
256
+ }
257
+
258
+ function storeChatDebugBundleOnDaemon(bundle: Record<string, unknown>, targetSessionId: string): { bundleId: string; savedPath: string; sizeBytes: number } {
259
+ const bundleId = createChatDebugBundleId(targetSessionId);
260
+ const dir = getChatDebugBundleDir();
261
+ fs.mkdirSync(dir, { recursive: true });
262
+ const savedPath = path.join(dir, `${bundleId}.json`);
263
+ const json = `${JSON.stringify(bundle, null, 2)}\n`;
264
+ fs.writeFileSync(savedPath, json, { encoding: 'utf8', mode: 0o600 });
265
+ return { bundleId, savedPath, sizeBytes: Buffer.byteLength(json, 'utf8') };
266
+ }
267
+
268
+ function isDaemonFileDebugDelivery(args: any): boolean {
269
+ return args?.delivery === 'daemon_file' || args?.delivery === 'file';
270
+ }
271
+
272
+ export async function handleGetChatDebugBundle(h: CommandHelpers, args: any): Promise<CommandResult> {
273
+ const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId.trim() : '';
274
+ if (!targetSessionId && !h.currentSession) {
275
+ return { success: false, error: 'No targetSessionId specified — cannot route command' };
276
+ }
277
+
278
+ const provider = h.getProvider(args?.agentType);
279
+ const transport = getTargetTransport(h, provider);
280
+ const providerType = provider?.type || getCurrentProviderType(h, args?.agentType || '');
281
+ const adapter = isCliLikeTransport(transport) ? getTargetedCliAdapter(h, args, provider?.type) : null;
282
+ const targetInstance = getTargetInstance(h, args);
283
+
284
+ let adapterStatus: unknown = null;
285
+ let parsedStatus: unknown = null;
286
+ let adapterDebugSnapshot: unknown = null;
287
+ let partialResponse = '';
288
+ if (adapter) {
289
+ try { adapterStatus = adapter.getStatus?.(); } catch (error: any) { adapterStatus = { error: error?.message || String(error) }; }
290
+ try { parsedStatus = typeof adapter.getScriptParsedStatus === 'function' ? parseMaybeJson(adapter.getScriptParsedStatus()) : null; } catch (error: any) { parsedStatus = { error: error?.message || String(error) }; }
291
+ try { adapterDebugSnapshot = typeof adapter.getDebugSnapshot === 'function' ? adapter.getDebugSnapshot() : null; } catch (error: any) { adapterDebugSnapshot = { error: error?.message || String(error) }; }
292
+ try { partialResponse = adapter.getPartialResponse?.() || ''; } catch { partialResponse = ''; }
293
+ }
294
+
295
+ let instanceState: unknown = null;
296
+ if (targetInstance?.getState) {
297
+ try { instanceState = summarizeStateForDebug(targetInstance.getState()); } catch (error: any) { instanceState = { error: error?.message || String(error) }; }
298
+ }
299
+
300
+ let readChat: unknown = null;
301
+ try {
302
+ const readResult = await handleReadChat(h, { ...args, tailLimit: Math.max(1, Math.min(40, Number(args?.tailLimit || 40))) });
303
+ readChat = readResult.success
304
+ ? {
305
+ success: true,
306
+ status: readResult.status,
307
+ title: readResult.title,
308
+ totalMessages: readResult.totalMessages,
309
+ providerSessionId: readResult.providerSessionId,
310
+ transcriptAuthority: readResult.transcriptAuthority,
311
+ coverage: readResult.coverage,
312
+ messageSource: readResult.messageSource,
313
+ transcriptProvenance: readResult.transcriptProvenance,
314
+ activeModal: readResult.activeModal,
315
+ messagesTail: Array.isArray(readResult.messages) ? readResult.messages.slice(-20) : [],
316
+ debugReadChat: readResult.debugReadChat,
317
+ }
318
+ : {
319
+ success: false,
320
+ error: readResult.error,
321
+ code: readResult.code,
322
+ messageSource: readResult.messageSource,
323
+ transcriptProvenance: readResult.transcriptProvenance,
324
+ debugReadChat: readResult.debugReadChat,
325
+ };
326
+ } catch (error: any) {
327
+ readChat = { success: false, error: error?.message || String(error) };
328
+ }
329
+
330
+ const cdp = h.getCdp();
331
+ const rawBundle: Record<string, unknown> = {
332
+ version: 1,
333
+ createdAt: new Date().toISOString(),
334
+ target: {
335
+ targetSessionId,
336
+ providerType,
337
+ transport,
338
+ routeManagerKey: h.currentManagerKey,
339
+ currentIdeType: h.currentIdeType,
340
+ },
341
+ session: summarizeSessionForDebug(h.currentSession),
342
+ provider: summarizeProviderForDebug(provider),
343
+ daemon: {
344
+ pid: process.pid,
345
+ platform: process.platform,
346
+ nodeVersion: process.version,
347
+ cwd: process.cwd(),
348
+ },
349
+ cdp: {
350
+ requested: !!cdp,
351
+ connected: !!cdp?.isConnected,
352
+ managerKey: getCurrentManagerKey(h),
353
+ },
354
+ instanceState,
355
+ cli: adapter ? {
356
+ cliType: adapter.cliType,
357
+ cliName: adapter.cliName,
358
+ workingDir: adapter.workingDir,
359
+ status: (adapterStatus as any)?.status,
360
+ activeModal: (adapterStatus as any)?.activeModal,
361
+ messageCount: Array.isArray((adapterStatus as any)?.messages) ? (adapterStatus as any).messages.length : undefined,
362
+ messagesTail: Array.isArray((adapterStatus as any)?.messages) ? (adapterStatus as any).messages.slice(-20) : undefined,
363
+ parsedStatus,
364
+ partialResponse,
365
+ ready: typeof adapter.isReady === 'function' ? adapter.isReady() : undefined,
366
+ processing: typeof adapter.isProcessing === 'function' ? adapter.isProcessing() : undefined,
367
+ debugSnapshot: adapterDebugSnapshot,
368
+ scriptInvocationTrace: typeof (adapter as any).getScriptInvocationTrace === 'function'
369
+ ? (adapter as any).getScriptInvocationTrace()
370
+ : undefined,
371
+ } : null,
372
+ readChat,
373
+ frontend: args?.frontendSnapshot && typeof args.frontendSnapshot === 'object' ? args.frontendSnapshot : null,
374
+ recentLogs: getRecentLogs(80, 'debug'),
375
+ recentDebugTrace: getRecentDebugTrace({ limit: 120 }),
376
+ };
377
+
378
+ const bundle = sanitizeDebugBundleValue(rawBundle) as Record<string, unknown>;
379
+ if (isDaemonFileDebugDelivery(args)) {
380
+ const summary = buildChatDebugBundleSummary(bundle);
381
+ const stored = storeChatDebugBundleOnDaemon(bundle, targetSessionId || String(summary.targetSessionId || 'unknown-session'));
382
+ LOG.info('Command', `[get_chat_debug_bundle] saved daemon_file bundle id=${stored.bundleId} path=${stored.savedPath} sizeBytes=${stored.sizeBytes} targetSessionId=${summary.targetSessionId || ''} providerType=${summary.providerType || ''} transport=${summary.transport || ''}`);
383
+ return {
384
+ success: true,
385
+ delivery: 'daemon_file',
386
+ bundleId: stored.bundleId,
387
+ savedPath: stored.savedPath,
388
+ sizeBytes: stored.sizeBytes,
389
+ createdAt: bundle.createdAt,
390
+ summary,
391
+ };
392
+ }
393
+ return {
394
+ success: true,
395
+ bundle,
396
+ text: buildDebugBundleText(bundle),
397
+ };
398
+ }