@adhdev/daemon-core 0.9.49 → 0.9.51

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/session-host-core",
3
- "version": "0.9.49",
3
+ "version": "0.9.51",
4
4
  "description": "ADHDev local session host core \u2014 session registry, protocol, buffers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.49",
3
+ "version": "0.9.51",
4
4
  "description": "ADHDev daemon core \u2014 CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -3,6 +3,10 @@
3
3
  * setMode, changeModel, setThoughtLevel, resolveAction, chatHistory
4
4
  */
5
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';
6
10
  import type { CommandResult, CommandHelpers } from './handler.js';
7
11
  import type { CliAdapter } from '../cli-adapter-types.js';
8
12
  import { flattenContent, normalizeInputEnvelope, type InputEnvelope, type ProviderModule, type ProviderScripts } from '../providers/contracts.js';
@@ -652,10 +656,69 @@ function buildDebugBundleText(bundle: Record<string, unknown>): string {
652
656
  ].join('\n');
653
657
  }
654
658
 
659
+ function getChatDebugBundleDir(): string {
660
+ const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === 'string'
661
+ ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim()
662
+ : '';
663
+ return override || path.join(os.homedir(), '.adhdev', 'debug-bundles', 'chat');
664
+ }
665
+
666
+ function safeBundleIdSegment(value: unknown, fallback: string): string {
667
+ const normalized = String(value || fallback)
668
+ .trim()
669
+ .replace(/[^A-Za-z0-9_.-]+/g, '-')
670
+ .replace(/^-+|-+$/g, '')
671
+ .slice(0, 80);
672
+ return normalized || fallback;
673
+ }
674
+
675
+ function createChatDebugBundleId(targetSessionId: string): string {
676
+ const timestamp = new Date().toISOString().replace(/[-:.]/g, '').replace('T', 'T').replace('Z', 'Z');
677
+ const sessionSegment = safeBundleIdSegment(targetSessionId, 'unknown-session');
678
+ return `chat-debug-${timestamp}-${sessionSegment}-${randomUUID().slice(0, 8)}`;
679
+ }
680
+
681
+ function buildChatDebugBundleSummary(bundle: Record<string, unknown>): Record<string, unknown> {
682
+ const target = bundle.target && typeof bundle.target === 'object' ? bundle.target as Record<string, unknown> : {};
683
+ const readChat = bundle.readChat && typeof bundle.readChat === 'object' ? bundle.readChat as Record<string, unknown> : {};
684
+ const cli = bundle.cli && typeof bundle.cli === 'object' ? bundle.cli as Record<string, unknown> : null;
685
+ const frontend = bundle.frontend && typeof bundle.frontend === 'object' ? bundle.frontend as Record<string, unknown> : null;
686
+ return {
687
+ createdAt: bundle.createdAt,
688
+ targetSessionId: target.targetSessionId,
689
+ providerType: target.providerType,
690
+ transport: target.transport,
691
+ readChatSuccess: readChat.success,
692
+ readChatStatus: readChat.status,
693
+ readChatTotalMessages: readChat.totalMessages,
694
+ cliStatus: cli?.status,
695
+ cliMessageCount: cli?.messageCount,
696
+ hasFrontendSnapshot: !!frontend,
697
+ };
698
+ }
699
+
700
+ function storeChatDebugBundleOnDaemon(bundle: Record<string, unknown>, targetSessionId: string): { bundleId: string; savedPath: string; sizeBytes: number } {
701
+ const bundleId = createChatDebugBundleId(targetSessionId);
702
+ const dir = getChatDebugBundleDir();
703
+ fs.mkdirSync(dir, { recursive: true });
704
+ const savedPath = path.join(dir, `${bundleId}.json`);
705
+ const json = `${JSON.stringify(bundle, null, 2)}\n`;
706
+ fs.writeFileSync(savedPath, json, { encoding: 'utf8', mode: 0o600 });
707
+ return { bundleId, savedPath, sizeBytes: Buffer.byteLength(json, 'utf8') };
708
+ }
709
+
710
+ function isDaemonFileDebugDelivery(args: any): boolean {
711
+ return args?.delivery === 'daemon_file' || args?.delivery === 'file';
712
+ }
713
+
655
714
  export async function handleGetChatDebugBundle(h: CommandHelpers, args: any): Promise<CommandResult> {
715
+ const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId.trim() : '';
716
+ if (!targetSessionId && !h.currentSession) {
717
+ return { success: false, error: 'No targetSessionId specified — cannot route command' };
718
+ }
719
+
656
720
  const provider = h.getProvider(args?.agentType);
657
721
  const transport = getTargetTransport(h, provider);
658
- const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId.trim() : '';
659
722
  const providerType = provider?.type || getCurrentProviderType(h, args?.agentType || '');
660
723
  const adapter = isCliLikeTransport(transport) ? getTargetedCliAdapter(h, args, provider?.type) : null;
661
724
  const targetInstance = getTargetInstance(h, args);
@@ -747,6 +810,20 @@ export async function handleGetChatDebugBundle(h: CommandHelpers, args: any): Pr
747
810
  };
748
811
 
749
812
  const bundle = sanitizeDebugBundleValue(rawBundle) as Record<string, unknown>;
813
+ if (isDaemonFileDebugDelivery(args)) {
814
+ const summary = buildChatDebugBundleSummary(bundle);
815
+ const stored = storeChatDebugBundleOnDaemon(bundle, targetSessionId || String(summary.targetSessionId || 'unknown-session'));
816
+ 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 || ''}`);
817
+ return {
818
+ success: true,
819
+ delivery: 'daemon_file',
820
+ bundleId: stored.bundleId,
821
+ savedPath: stored.savedPath,
822
+ sizeBytes: stored.sizeBytes,
823
+ createdAt: bundle.createdAt,
824
+ summary,
825
+ };
826
+ }
750
827
  return {
751
828
  success: true,
752
829
  bundle,
@@ -380,6 +380,7 @@ export class DaemonCommandHandler implements CommandHelpers {
380
380
 
381
381
  const sessionScopedCommands = new Set([
382
382
  'read_chat',
383
+ 'get_chat_debug_bundle',
383
384
  'send_chat',
384
385
  'list_chats',
385
386
  'new_chat',
@@ -525,6 +525,12 @@ export class DaemonCommandRouter {
525
525
  const wantsAll = args?.all === true;
526
526
  const offset = wantsAll ? 0 : Math.max(0, Number(args?.offset) || 0);
527
527
  const limit = wantsAll ? Number.MAX_SAFE_INTEGER : Math.max(1, Math.min(100, Number(args?.limit) || 30));
528
+ const requestedWorkspace = typeof args?.workspace === 'string' ? args.workspace.trim() : '';
529
+ const requestedProviderSessionId = typeof args?.providerSessionId === 'string'
530
+ ? args.providerSessionId.trim()
531
+ : typeof args?.activeProviderSessionId === 'string'
532
+ ? args.activeProviderSessionId.trim()
533
+ : '';
528
534
  const providerMeta = this.deps.providerLoader.resolve?.(providerType) || this.deps.providerLoader.getMeta(providerType);
529
535
  const { sessions: historySessions, hasMore, source } = listProviderHistorySessions(providerType, {
530
536
  canonicalHistory: providerMeta?.canonicalHistory,
@@ -546,6 +552,10 @@ export class DaemonCommandRouter {
546
552
  sessions: historySessions.map(session => {
547
553
  const saved = savedSessionById.get(session.historySessionId);
548
554
  const recent = recentSessionById.get(session.historySessionId);
555
+ const workspace = saved?.workspace
556
+ || recent?.workspace
557
+ || session.workspace
558
+ || (requestedWorkspace && requestedProviderSessionId === session.historySessionId ? requestedWorkspace : undefined);
549
559
  return {
550
560
  id: session.historySessionId,
551
561
  providerSessionId: session.historySessionId,
@@ -553,13 +563,13 @@ export class DaemonCommandRouter {
553
563
  providerName: saved?.providerName || recent?.providerName || providerType,
554
564
  kind: saved?.kind || recent?.kind || kind,
555
565
  title: saved?.title || recent?.title || session.sessionTitle || session.preview || providerType,
556
- workspace: saved?.workspace || recent?.workspace || session.workspace,
566
+ workspace,
557
567
  summaryMetadata: saved?.summaryMetadata || recent?.summaryMetadata,
558
568
  preview: session.preview,
559
569
  messageCount: session.messageCount,
560
570
  firstMessageAt: session.firstMessageAt,
561
571
  lastMessageAt: session.lastMessageAt,
562
- canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById,
572
+ canResume: !!workspace && canResumeById,
563
573
  historySource: session.source,
564
574
  sourcePath: session.sourcePath,
565
575
  sourceMtimeMs: session.sourceMtimeMs,