@adhdev/daemon-core 0.9.44 → 0.9.45

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.
@@ -0,0 +1,2 @@
1
+ export declare function isMacAppProcessArgs(args: string, appPath: string): boolean;
2
+ export declare function findMacAppProcessPids(psOutput: string, appPaths: readonly string[]): number[];
@@ -55,6 +55,8 @@ export declare class CliProviderInstance implements ProviderInstance {
55
55
  private lastCanonicalHermesWatchPath;
56
56
  private lastCanonicalClaudeRebuildMtimeMs;
57
57
  private lastCanonicalClaudeCheckAt;
58
+ private lastCanonicalCodexRebuildMtimeMs;
59
+ private lastCanonicalCodexCheckAt;
58
60
  private cachedSqliteDb;
59
61
  private cachedSqliteDbPath;
60
62
  private cachedSqliteDbMissingUntil;
@@ -31,6 +31,9 @@ export interface ReadChatResult {
31
31
  controlValues?: Record<string, string | number | boolean>;
32
32
  /** Flexible always-visible metadata for compact/live surfaces. */
33
33
  summaryMetadata?: ProviderSummaryMetadata;
34
+ /** Provider-owned transcript authority/coverage hints for daemon/dashboard sync. */
35
+ transcriptAuthority?: 'provider' | 'daemon';
36
+ coverage?: 'full' | 'tail' | 'current-turn';
34
37
  /** Provider-driven UI effects derived from chat state */
35
38
  effects?: ProviderEffect[];
36
39
  }
@@ -506,13 +509,23 @@ export interface ProviderCanonicalHistoryConfig {
506
509
  * Native history format.
507
510
  * - 'hermes-json': single JSON file per session (~/.hermes/sessions/session_{{sessionId}}.json)
508
511
  * - 'claude-jsonl': JSONL transcript under ~/.claude/projects/
512
+ * - 'codex-jsonl': rollout JSONL transcript under ~/.codex/sessions/YYYY/MM/DD/
509
513
  */
510
- format: 'hermes-json' | 'claude-jsonl';
514
+ format: 'hermes-json' | 'claude-jsonl' | 'codex-jsonl';
511
515
  /**
512
516
  * Path to the native history file. Supports ~ and {{sessionId}} placeholder.
513
517
  * e.g. "~/.hermes/sessions/session_{{sessionId}}.json"
514
518
  */
515
519
  watchPath: string;
520
+ /**
521
+ * How ADHDev should use native history.
522
+ * - 'native-source': provider-native files are canonical; ADHDev reads them directly and keeps only in-memory/thin projections.
523
+ * - 'materialized-mirror': transitional compatibility mode; native files are rewritten into ~/.adhdev/history before read/list.
524
+ * - 'disabled': ignore native history and use ADHDev mirror only.
525
+ *
526
+ * Omitted mode defaults to 'native-source'.
527
+ */
528
+ mode?: 'native-source' | 'materialized-mirror' | 'disabled';
516
529
  }
517
530
  /**
518
531
  * Auto-implement spawn config — controls how the provider is spawned for autonomous AI-driven
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/session-host-core",
3
- "version": "0.9.44",
3
+ "version": "0.9.45",
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.44",
3
+ "version": "0.9.45",
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",
@@ -239,6 +239,20 @@ function sanitizeCommittedMessageForDisplay<T extends { role?: string; kind?: st
239
239
  return { ...message, content };
240
240
  }
241
241
 
242
+ export function trimLastAssistantEchoForCliMessages(messages: CliChatMessage[], prompt: string | undefined): void {
243
+ if (!prompt) return;
244
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
245
+ const message = messages[index];
246
+ if (!message || message.role !== 'assistant' || typeof message.content !== 'string') continue;
247
+ if ((message.kind || 'standard') !== 'standard') continue;
248
+ message.content = trimPromptEchoPrefix(message.content, prompt);
249
+ if (!message.content.trim()) {
250
+ messages.splice(index, 1);
251
+ }
252
+ return;
253
+ }
254
+ }
255
+
242
256
  // ─── Adapter ────────────────────────────────────────
243
257
 
244
258
  export class ProviderCliAdapter implements CliAdapter {
@@ -428,7 +442,16 @@ export class ProviderCliAdapter implements CliAdapter {
428
442
  return null;
429
443
  }
430
444
 
445
+ private providerOwnsTranscript(): boolean {
446
+ return this.provider.transcriptAuthority === 'provider';
447
+ }
448
+
449
+ private shouldUseFullProviderTranscriptContext(): boolean {
450
+ return this.providerOwnsTranscript() && this.provider.transcriptContext === 'full';
451
+ }
452
+
431
453
  private selectParseBaseMessages(baseMessages: CliChatMessage[]): CliChatMessage[] {
454
+ if (this.shouldUseFullProviderTranscriptContext()) return baseMessages;
432
455
  if (baseMessages.length <= ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
433
456
  return baseMessages.slice(-ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
434
457
  }
@@ -1044,9 +1067,7 @@ export class ProviderCliAdapter implements CliAdapter {
1044
1067
  }
1045
1068
 
1046
1069
  private trimLastAssistantEcho(messages: CliChatMessage[], prompt: string | undefined): void {
1047
- if (!prompt) return;
1048
- const last = [...messages].reverse().find((m) => m.role === 'assistant' && typeof m.content === 'string');
1049
- if (last) last.content = trimPromptEchoPrefix(last.content, prompt);
1070
+ trimLastAssistantEchoForCliMessages(messages, prompt);
1050
1071
  }
1051
1072
 
1052
1073
  private clearAllTimers(): void {
@@ -2033,6 +2054,7 @@ export class ProviderCliAdapter implements CliAdapter {
2033
2054
  messages: hydratedMessages,
2034
2055
  activeModal: parsed.activeModal ?? this.activeModal,
2035
2056
  providerSessionId: typeof parsed.providerSessionId === 'string' ? parsed.providerSessionId : undefined,
2057
+ ...(this.providerOwnsTranscript() ? { transcriptAuthority: 'provider', coverage: this.shouldUseFullProviderTranscriptContext() ? 'full' : 'tail' } : {}),
2036
2058
  };
2037
2059
  } else {
2038
2060
  const messages = [...this.committedMessages];
@@ -31,6 +31,8 @@ export interface ParsedSession {
31
31
  messages: any[];
32
32
  modal: { message: string; buttons: string[] } | null;
33
33
  parsedStatus: string | null;
34
+ transcriptAuthority?: 'provider' | 'daemon';
35
+ coverage?: 'full' | 'tail' | 'current-turn';
34
36
  }
35
37
 
36
38
  export interface CliScripts {
@@ -122,6 +124,10 @@ export interface CliProviderModule {
122
124
  submitStrategy?: 'wait_for_echo' | 'immediate';
123
125
  /** Allow sending another prompt while the CLI is still generating so users can intervene mid-turn. */
124
126
  allowInputDuringGeneration?: boolean;
127
+ /** When provider-owned, daemon treats provider parser output as canonical transcript authority. */
128
+ transcriptAuthority?: 'provider' | 'daemon';
129
+ /** Full context lets provider-owned parsers canonicalize retained history instead of daemon prefix stitching. */
130
+ transcriptContext?: 'full' | 'tail';
125
131
  scripts?: CliScripts;
126
132
  spawn: {
127
133
  command: string;
@@ -9,7 +9,7 @@ import { flattenContent, normalizeInputEnvelope, type InputEnvelope, type Provid
9
9
  import { assertProviderSupportsDeclaredInput, assertTextOnlyInput } from '../providers/provider-input-support.js';
10
10
  import { validateReadChatResultPayload } from '../providers/read-chat-contract.js';
11
11
  import type { ProviderInstance } from '../providers/provider-instance.js';
12
- import { readChatHistory } from '../config/chat-history.js';
12
+ import { readProviderChatHistory } from '../config/chat-history.js';
13
13
  import { LOG } from '../logging/logger.js';
14
14
  import { recordDebugTrace } from '../logging/debug-trace.js';
15
15
  import { buildChatMessageSignature } from '../chat/chat-signatures.js';
@@ -564,7 +564,20 @@ export async function handleChatHistory(h: CommandHelpers, args: any): Promise<C
564
564
  const visibleCount = Array.isArray(status?.messages) ? status.messages.length : 0;
565
565
  if (visibleCount > excludeRecentCount) excludeRecentCount = visibleCount;
566
566
  }
567
- const result = readChatHistory(agentStr, offset || 0, limit || 30, historySessionId, excludeRecentCount);
567
+ const workspace = typeof args?.workspace === 'string'
568
+ ? args.workspace
569
+ : typeof (h.currentSession as any)?.workspace === 'string'
570
+ ? (h.currentSession as any).workspace
571
+ : undefined;
572
+ const result = readProviderChatHistory(agentStr, {
573
+ canonicalHistory: provider?.canonicalHistory,
574
+ historySessionId,
575
+ workspace,
576
+ offset: offset || 0,
577
+ limit: limit || 30,
578
+ excludeRecentCount,
579
+ historyBehavior: provider?.historyBehavior,
580
+ });
568
581
  return { success: true, ...result, agent: agentStr };
569
582
  } catch (e: any) {
570
583
  return { success: false, error: e.message };
@@ -595,8 +608,11 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
595
608
  ? parsedStatus as Record<string, any>
596
609
  : null;
597
610
  const adapterStatus = adapter.getStatus();
611
+ const parsedIsProviderAuthoritative = parsedRecord?.transcriptAuthority === 'provider'
612
+ || parsedRecord?.coverage === 'full';
598
613
  const shouldPreferAdapterMessages =
599
- Array.isArray(adapterStatus.messages)
614
+ !parsedIsProviderAuthoritative
615
+ && Array.isArray(adapterStatus.messages)
600
616
  && adapterStatus.messages.length > 0
601
617
  && Array.isArray(parsedRecord?.messages)
602
618
  && adapterStatus.messages.length > parsedRecord.messages.length;
@@ -619,6 +635,12 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
619
635
  const providerSessionId = typeof parsedRecord?.providerSessionId === 'string'
620
636
  ? parsedRecord.providerSessionId
621
637
  : undefined;
638
+ const transcriptAuthority = parsedRecord?.transcriptAuthority === 'provider' || parsedRecord?.transcriptAuthority === 'daemon'
639
+ ? parsedRecord.transcriptAuthority
640
+ : undefined;
641
+ const coverage = parsedRecord?.coverage === 'full' || parsedRecord?.coverage === 'tail' || parsedRecord?.coverage === 'current-turn'
642
+ ? parsedRecord.coverage
643
+ : undefined;
622
644
  if (status) {
623
645
  LOG.debug('Command', `[read_chat] cli-like resolved provider=${adapter.cliType} target=${String(args?.targetSessionId || '')} adapterStatus=${String(adapterStatus.status || '')} parsedStatus=${String(parsedRecord?.status || '')} shouldPreferAdapterMessages=${String(shouldPreferAdapterMessages)} adapterMsgCount=${Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0} parsedMsgCount=${Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0} returnedMsgCount=${Array.isArray((status as any).messages) ? (status as any).messages.length : 0}`);
624
646
  return buildReadChatCommandResult({
@@ -638,6 +660,8 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
638
660
  },
639
661
  ...(title ? { title } : {}),
640
662
  ...(providerSessionId ? { providerSessionId } : {}),
663
+ ...(transcriptAuthority ? { transcriptAuthority } : {}),
664
+ ...(coverage ? { coverage } : {}),
641
665
  }, args);
642
666
  }
643
667
  }
@@ -23,7 +23,7 @@ import { loadState, saveState } from '../config/state-store.js';
23
23
  import { resolveIdeLaunchWorkspace } from '../config/workspaces.js';
24
24
  import { appendRecentActivity, getRecentActivity, markSessionSeen, dismissSessionNotification, markSessionNotificationUnread } from '../config/recent-activity.js';
25
25
  import { getSavedProviderSessions } from '../config/saved-sessions.js';
26
- import { listSavedHistorySessions } from '../config/chat-history.js';
26
+ import { listProviderHistorySessions } from '../config/chat-history.js';
27
27
  import { detectIDEs } from '../detection/ide-detector.js';
28
28
  import { detectCLI } from '../detection/cli-detector.js';
29
29
  import { SessionRegistry } from '../sessions/registry.js';
@@ -525,14 +525,19 @@ 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 { sessions: historySessions, hasMore } = listSavedHistorySessions(providerType, { offset, limit });
528
+ const providerMeta = this.deps.providerLoader.getMeta(providerType);
529
+ const { sessions: historySessions, hasMore, source } = listProviderHistorySessions(providerType, {
530
+ canonicalHistory: providerMeta?.canonicalHistory,
531
+ offset,
532
+ limit,
533
+ historyBehavior: providerMeta?.historyBehavior,
534
+ });
529
535
  const state = loadState();
530
536
  const savedSessions = getSavedProviderSessions(state, { providerType, kind });
531
537
  const recentSessions = getRecentActivity(state, 200)
532
538
  .filter(entry => entry.providerType === providerType && entry.kind === kind && entry.providerSessionId);
533
539
  const savedSessionById = new Map(savedSessions.map(entry => [entry.providerSessionId, entry]));
534
540
  const recentSessionById = new Map(recentSessions.map(entry => [entry.providerSessionId!, entry]));
535
- const providerMeta = this.deps.providerLoader.getMeta(providerType);
536
541
  const canResumeById = supportsExplicitSessionResume(providerMeta?.resume);
537
542
 
538
543
  return {
@@ -557,6 +562,7 @@ export class DaemonCommandRouter {
557
562
  };
558
563
  }),
559
564
  hasMore,
565
+ source,
560
566
  };
561
567
  }
562
568