@adhdev/daemon-core 0.9.44 → 0.9.46
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.
- package/dist/cli-adapters/provider-cli-adapter.d.ts +3 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +6 -0
- package/dist/config/chat-history.d.ts +34 -11
- package/dist/index.js +410 -310
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +410 -310
- package/dist/index.mjs.map +1 -1
- package/dist/launch/macos-app-process.d.ts +2 -0
- package/dist/providers/cli-provider-instance.d.ts +2 -5
- package/dist/providers/contracts.d.ts +33 -11
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +25 -3
- package/src/cli-adapters/provider-cli-shared.ts +6 -0
- package/src/commands/chat-commands.ts +28 -3
- package/src/commands/router.ts +13 -3
- package/src/config/chat-history.ts +282 -284
- package/src/launch/macos-app-process.ts +37 -0
- package/src/launch.ts +43 -5
- package/src/providers/cli-provider-instance.ts +57 -46
- package/src/providers/contracts.ts +35 -12
- package/src/providers/provider-schema.ts +40 -0
- package/src/providers/read-chat-contract.ts +2 -0
|
@@ -50,11 +50,8 @@ export declare class CliProviderInstance implements ProviderInstance {
|
|
|
50
50
|
private historyWriter;
|
|
51
51
|
private runtimeMessages;
|
|
52
52
|
private lastPersistedHistoryMessages;
|
|
53
|
-
private
|
|
54
|
-
private
|
|
55
|
-
private lastCanonicalHermesWatchPath;
|
|
56
|
-
private lastCanonicalClaudeRebuildMtimeMs;
|
|
57
|
-
private lastCanonicalClaudeCheckAt;
|
|
53
|
+
private lastNativeSourceCanonicalCheckAt;
|
|
54
|
+
private lastNativeSourceCanonicalCacheKey;
|
|
58
55
|
private cachedSqliteDb;
|
|
59
56
|
private cachedSqliteDbPath;
|
|
60
57
|
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
|
}
|
|
@@ -496,23 +499,42 @@ export interface ProviderHistoryBehavior {
|
|
|
496
499
|
/** If true, session ID must match sessionIdPattern exactly — reject and return '' if it doesn't match */
|
|
497
500
|
requireStrictSessionIdFormat?: boolean;
|
|
498
501
|
}
|
|
502
|
+
/**
|
|
503
|
+
* Provider-owned native history script names.
|
|
504
|
+
*
|
|
505
|
+
* These functions live in the provider's versioned CLI script bundle, not in
|
|
506
|
+
* daemon-core. They let each provider own native transcript file discovery and
|
|
507
|
+
* parsing while daemon-core only validates/pages the normalized result.
|
|
508
|
+
*/
|
|
509
|
+
export interface ProviderCanonicalHistoryScriptsConfig {
|
|
510
|
+
/** Reads one native session. Default: 'readNativeHistory'. */
|
|
511
|
+
readSession?: string;
|
|
512
|
+
/** Lists native sessions with summary metadata. Default: 'listNativeHistory'. */
|
|
513
|
+
listSessions?: string;
|
|
514
|
+
}
|
|
499
515
|
/**
|
|
500
516
|
* Canonical history sync config — for providers that maintain their own native history files.
|
|
501
|
-
*
|
|
502
|
-
*
|
|
517
|
+
*
|
|
518
|
+
* Preferred mode is provider-owned scripts via `scripts`. `format` is now an
|
|
519
|
+
* opaque provider label retained for diagnostics/backward compatibility; daemon
|
|
520
|
+
* live paths must not branch on provider-specific format values.
|
|
503
521
|
*/
|
|
504
522
|
export interface ProviderCanonicalHistoryConfig {
|
|
523
|
+
/** Opaque provider-owned history format label. */
|
|
524
|
+
format?: string;
|
|
525
|
+
/** Optional native history glob/template for diagnostics only. */
|
|
526
|
+
watchPath?: string;
|
|
527
|
+
/** Provider-owned script entry points for native transcript list/read. */
|
|
528
|
+
scripts?: ProviderCanonicalHistoryScriptsConfig;
|
|
505
529
|
/**
|
|
506
|
-
*
|
|
507
|
-
* - '
|
|
508
|
-
* - '
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
* Path to the native history file. Supports ~ and {{sessionId}} placeholder.
|
|
513
|
-
* e.g. "~/.hermes/sessions/session_{{sessionId}}.json"
|
|
530
|
+
* How ADHDev should use native history.
|
|
531
|
+
* - 'native-source': provider-native files are canonical; ADHDev reads them directly and keeps only in-memory/thin projections.
|
|
532
|
+
* - 'materialized-mirror': transitional compatibility mode; native files are rewritten into ~/.adhdev/history before read/list.
|
|
533
|
+
* - 'disabled': ignore native history and use ADHDev mirror only.
|
|
534
|
+
*
|
|
535
|
+
* Omitted mode defaults to 'native-source'.
|
|
514
536
|
*/
|
|
515
|
-
|
|
537
|
+
mode?: 'native-source' | 'materialized-mirror' | 'disabled';
|
|
516
538
|
}
|
|
517
539
|
/**
|
|
518
540
|
* Auto-implement spawn config — controls how the provider is spawned for autonomous AI-driven
|
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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 {
|
|
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,21 @@ 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
|
|
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
|
+
scripts: provider?.scripts as any,
|
|
581
|
+
});
|
|
568
582
|
return { success: true, ...result, agent: agentStr };
|
|
569
583
|
} catch (e: any) {
|
|
570
584
|
return { success: false, error: e.message };
|
|
@@ -595,8 +609,11 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
595
609
|
? parsedStatus as Record<string, any>
|
|
596
610
|
: null;
|
|
597
611
|
const adapterStatus = adapter.getStatus();
|
|
612
|
+
const parsedIsProviderAuthoritative = parsedRecord?.transcriptAuthority === 'provider'
|
|
613
|
+
|| parsedRecord?.coverage === 'full';
|
|
598
614
|
const shouldPreferAdapterMessages =
|
|
599
|
-
|
|
615
|
+
!parsedIsProviderAuthoritative
|
|
616
|
+
&& Array.isArray(adapterStatus.messages)
|
|
600
617
|
&& adapterStatus.messages.length > 0
|
|
601
618
|
&& Array.isArray(parsedRecord?.messages)
|
|
602
619
|
&& adapterStatus.messages.length > parsedRecord.messages.length;
|
|
@@ -619,6 +636,12 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
619
636
|
const providerSessionId = typeof parsedRecord?.providerSessionId === 'string'
|
|
620
637
|
? parsedRecord.providerSessionId
|
|
621
638
|
: undefined;
|
|
639
|
+
const transcriptAuthority = parsedRecord?.transcriptAuthority === 'provider' || parsedRecord?.transcriptAuthority === 'daemon'
|
|
640
|
+
? parsedRecord.transcriptAuthority
|
|
641
|
+
: undefined;
|
|
642
|
+
const coverage = parsedRecord?.coverage === 'full' || parsedRecord?.coverage === 'tail' || parsedRecord?.coverage === 'current-turn'
|
|
643
|
+
? parsedRecord.coverage
|
|
644
|
+
: undefined;
|
|
622
645
|
if (status) {
|
|
623
646
|
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
647
|
return buildReadChatCommandResult({
|
|
@@ -638,6 +661,8 @@ export async function handleReadChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
638
661
|
},
|
|
639
662
|
...(title ? { title } : {}),
|
|
640
663
|
...(providerSessionId ? { providerSessionId } : {}),
|
|
664
|
+
...(transcriptAuthority ? { transcriptAuthority } : {}),
|
|
665
|
+
...(coverage ? { coverage } : {}),
|
|
641
666
|
}, args);
|
|
642
667
|
}
|
|
643
668
|
}
|
package/src/commands/router.ts
CHANGED
|
@@ -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 {
|
|
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,20 @@ 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
|
|
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
|
+
scripts: providerMeta?.scripts as any,
|
|
535
|
+
});
|
|
529
536
|
const state = loadState();
|
|
530
537
|
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
531
538
|
const recentSessions = getRecentActivity(state, 200)
|
|
532
539
|
.filter(entry => entry.providerType === providerType && entry.kind === kind && entry.providerSessionId);
|
|
533
540
|
const savedSessionById = new Map(savedSessions.map(entry => [entry.providerSessionId, entry]));
|
|
534
541
|
const recentSessionById = new Map(recentSessions.map(entry => [entry.providerSessionId!, entry]));
|
|
535
|
-
const providerMeta = this.deps.providerLoader.getMeta(providerType);
|
|
536
542
|
const canResumeById = supportsExplicitSessionResume(providerMeta?.resume);
|
|
537
543
|
|
|
538
544
|
return {
|
|
@@ -554,9 +560,13 @@ export class DaemonCommandRouter {
|
|
|
554
560
|
firstMessageAt: session.firstMessageAt,
|
|
555
561
|
lastMessageAt: session.lastMessageAt,
|
|
556
562
|
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById,
|
|
563
|
+
historySource: session.source,
|
|
564
|
+
sourcePath: session.sourcePath,
|
|
565
|
+
sourceMtimeMs: session.sourceMtimeMs,
|
|
557
566
|
};
|
|
558
567
|
}),
|
|
559
568
|
hasMore,
|
|
569
|
+
source,
|
|
560
570
|
};
|
|
561
571
|
}
|
|
562
572
|
|