@adhdev/daemon-core 0.9.36 → 0.9.37
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 -1
- package/dist/index.js +73 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +73 -13
- package/dist/index.mjs.map +1 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +4 -3
- package/src/cli-adapters/provider-cli-parse.ts +89 -11
- package/src/providers/cli-provider-instance.ts +1 -1
package/package.json
CHANGED
|
@@ -1675,11 +1675,12 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
1675
1675
|
|
|
1676
1676
|
// ─── Public API (CliAdapter) ───────────────────
|
|
1677
1677
|
|
|
1678
|
-
getStatus(): CliSessionStatus {
|
|
1679
|
-
const
|
|
1678
|
+
getStatus(options: { allowParse?: boolean } = {}): CliSessionStatus {
|
|
1679
|
+
const allowParse = options.allowParse !== false;
|
|
1680
|
+
const startupModal = allowParse && this.startupParseGate ? this.runParseApproval(this.recentOutputBuffer) : null;
|
|
1680
1681
|
let effectiveStatus = this.projectEffectiveStatus(startupModal);
|
|
1681
1682
|
let effectiveModal = startupModal || this.activeModal;
|
|
1682
|
-
if (!startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === 'function') {
|
|
1683
|
+
if (allowParse && !startupModal && !effectiveModal && typeof this.cliScripts?.parseOutput === 'function') {
|
|
1683
1684
|
let parsed = this.getFreshParsedStatusCache();
|
|
1684
1685
|
if (!parsed && effectiveStatus !== 'idle') {
|
|
1685
1686
|
const now = Date.now();
|
|
@@ -31,37 +31,115 @@ export function hydrateCliParsedMessages(
|
|
|
31
31
|
): any[] {
|
|
32
32
|
const { committedMessages, scope, lastOutputAt } = options;
|
|
33
33
|
const referenceMessages = [...committedMessages];
|
|
34
|
-
const referenceComparables
|
|
34
|
+
const referenceComparables: Array<string | undefined> = new Array(referenceMessages.length);
|
|
35
35
|
const usedReferenceIndexes = new Set<number>();
|
|
36
36
|
const now = options.now ?? Date.now();
|
|
37
|
+
let exactReferenceIndexesByKey: Map<string, number[]> | null = null;
|
|
38
|
+
const exactReferenceCursorByKey = new Map<string, number>();
|
|
39
|
+
|
|
40
|
+
const hasFiniteTimestamp = (message: any): message is { timestamp: number } => (
|
|
41
|
+
typeof message?.timestamp === 'number' && Number.isFinite(message.timestamp)
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const getReferenceComparable = (index: number): string => {
|
|
45
|
+
if (typeof referenceComparables[index] === 'string') return referenceComparables[index] || '';
|
|
46
|
+
const comparable = normalizeComparableMessageContent(referenceMessages[index]?.content || '');
|
|
47
|
+
referenceComparables[index] = comparable;
|
|
48
|
+
return comparable;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const messagesShareStableIdentity = (parsed: any, reference: any): boolean => {
|
|
52
|
+
if (!parsed || !reference) return false;
|
|
53
|
+
const parsedId = typeof parsed.id === 'string' ? parsed.id.trim() : '';
|
|
54
|
+
const referenceId = typeof reference.id === 'string' ? reference.id.trim() : '';
|
|
55
|
+
if (parsedId && referenceId && parsedId === referenceId) return true;
|
|
56
|
+
return typeof parsed.index === 'number'
|
|
57
|
+
&& Number.isFinite(parsed.index)
|
|
58
|
+
&& typeof reference.index === 'number'
|
|
59
|
+
&& Number.isFinite(reference.index)
|
|
60
|
+
&& parsed.index === reference.index;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const exactReferenceKey = (role: 'user' | 'assistant', comparable: string): string => `${role}\u0000${comparable}`;
|
|
64
|
+
|
|
65
|
+
const ensureExactReferenceIndex = (): Map<string, number[]> => {
|
|
66
|
+
if (exactReferenceIndexesByKey) return exactReferenceIndexesByKey;
|
|
67
|
+
const byKey = new Map<string, number[]>();
|
|
68
|
+
for (let i = 0; i < referenceMessages.length; i++) {
|
|
69
|
+
const candidate = referenceMessages[i];
|
|
70
|
+
if (!candidate || (candidate.role !== 'user' && candidate.role !== 'assistant') || !hasFiniteTimestamp(candidate)) continue;
|
|
71
|
+
const comparable = getReferenceComparable(i);
|
|
72
|
+
if (!comparable) continue;
|
|
73
|
+
const key = exactReferenceKey(candidate.role, comparable);
|
|
74
|
+
const indexes = byKey.get(key);
|
|
75
|
+
if (indexes) {
|
|
76
|
+
indexes.push(i);
|
|
77
|
+
} else {
|
|
78
|
+
byKey.set(key, [i]);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exactReferenceIndexesByKey = byKey;
|
|
82
|
+
return byKey;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const takeExactReferenceTimestamp = (role: 'user' | 'assistant', normalizedContent: string): number | undefined => {
|
|
86
|
+
const key = exactReferenceKey(role, normalizedContent);
|
|
87
|
+
const indexes = ensureExactReferenceIndex().get(key);
|
|
88
|
+
if (!indexes) return undefined;
|
|
89
|
+
let cursor = exactReferenceCursorByKey.get(key) || 0;
|
|
90
|
+
while (cursor < indexes.length) {
|
|
91
|
+
const candidateIndex = indexes[cursor];
|
|
92
|
+
cursor += 1;
|
|
93
|
+
if (usedReferenceIndexes.has(candidateIndex)) continue;
|
|
94
|
+
const candidate = referenceMessages[candidateIndex];
|
|
95
|
+
if (!candidate || candidate.role !== role || !hasFiniteTimestamp(candidate)) continue;
|
|
96
|
+
usedReferenceIndexes.add(candidateIndex);
|
|
97
|
+
exactReferenceCursorByKey.set(key, cursor);
|
|
98
|
+
return candidate.timestamp;
|
|
99
|
+
}
|
|
100
|
+
exactReferenceCursorByKey.set(key, cursor);
|
|
101
|
+
return undefined;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const findReferenceTimestamp = (message: any, role: 'user' | 'assistant', content: string, parsedIndex: number): number | undefined => {
|
|
105
|
+
const sameIndex = referenceMessages[parsedIndex];
|
|
106
|
+
if (
|
|
107
|
+
sameIndex
|
|
108
|
+
&& !usedReferenceIndexes.has(parsedIndex)
|
|
109
|
+
&& sameIndex.role === role
|
|
110
|
+
&& hasFiniteTimestamp(sameIndex)
|
|
111
|
+
&& messagesShareStableIdentity(message, sameIndex)
|
|
112
|
+
) {
|
|
113
|
+
usedReferenceIndexes.add(parsedIndex);
|
|
114
|
+
return sameIndex.timestamp;
|
|
115
|
+
}
|
|
37
116
|
|
|
38
|
-
const findReferenceTimestamp = (role: 'user' | 'assistant', content: string, parsedIndex: number): number | undefined => {
|
|
39
117
|
const normalizedContent = normalizeComparableMessageContent(content);
|
|
40
118
|
if (!normalizedContent) return undefined;
|
|
41
119
|
|
|
42
|
-
const sameIndex = referenceMessages[parsedIndex];
|
|
43
120
|
if (
|
|
44
121
|
sameIndex
|
|
45
122
|
&& !usedReferenceIndexes.has(parsedIndex)
|
|
46
123
|
&& sameIndex.role === role
|
|
47
|
-
&&
|
|
48
|
-
&&
|
|
49
|
-
&& Number.isFinite(sameIndex.timestamp)
|
|
124
|
+
&& getReferenceComparable(parsedIndex) === normalizedContent
|
|
125
|
+
&& hasFiniteTimestamp(sameIndex)
|
|
50
126
|
) {
|
|
51
127
|
usedReferenceIndexes.add(parsedIndex);
|
|
52
128
|
return sameIndex.timestamp;
|
|
53
129
|
}
|
|
54
130
|
|
|
131
|
+
const exactTimestamp = takeExactReferenceTimestamp(role, normalizedContent);
|
|
132
|
+
if (typeof exactTimestamp === 'number') return exactTimestamp;
|
|
133
|
+
|
|
55
134
|
for (let i = 0; i < referenceMessages.length; i++) {
|
|
56
135
|
if (usedReferenceIndexes.has(i)) continue;
|
|
57
136
|
const candidate = referenceMessages[i];
|
|
58
137
|
if (!candidate || candidate.role !== role) continue;
|
|
59
|
-
const candidateContent =
|
|
138
|
+
const candidateContent = getReferenceComparable(i);
|
|
60
139
|
if (!candidateContent) continue;
|
|
61
|
-
const exactMatch = candidateContent === normalizedContent;
|
|
62
140
|
const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
|
|
63
|
-
if (!
|
|
64
|
-
if (
|
|
141
|
+
if (!fuzzyMatch) continue;
|
|
142
|
+
if (hasFiniteTimestamp(candidate)) {
|
|
65
143
|
usedReferenceIndexes.add(i);
|
|
66
144
|
return candidate.timestamp;
|
|
67
145
|
}
|
|
@@ -78,7 +156,7 @@ export function hydrateCliParsedMessages(
|
|
|
78
156
|
const parsedTimestamp = typeof message.timestamp === 'number' && Number.isFinite(message.timestamp)
|
|
79
157
|
? message.timestamp
|
|
80
158
|
: undefined;
|
|
81
|
-
const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
|
|
159
|
+
const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(message, role, content, index);
|
|
82
160
|
const fallbackTimestamp = role === 'user'
|
|
83
161
|
? (scope?.startedAt || now)
|
|
84
162
|
: (lastOutputAt || scope?.startedAt || now);
|
|
@@ -494,7 +494,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
494
494
|
}
|
|
495
495
|
|
|
496
496
|
getHotChatSessionState(): HotChatSessionState {
|
|
497
|
-
const adapterStatus = this.adapter.getStatus();
|
|
497
|
+
const adapterStatus = this.adapter.getStatus({ allowParse: false });
|
|
498
498
|
const autoApproveActive = adapterStatus.status === 'waiting_approval' && this.shouldAutoApprove();
|
|
499
499
|
const visibleStatus = autoApproveActive ? 'generating' : adapterStatus.status;
|
|
500
500
|
const runtime = this.adapter.getRuntimeMetadata();
|