@adhdev/daemon-core 0.9.76-rc.50 → 0.9.76-rc.52
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/index.js +54 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +54 -15
- package/dist/index.mjs.map +1 -1
- package/dist/session-host/runtime-support.d.ts +2 -1
- package/package.json +1 -1
- package/src/commands/chat-commands.ts +15 -0
- package/src/providers/cli-provider-instance.ts +5 -2
- package/src/session-host/runtime-support.ts +55 -7
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { type SessionHostEndpoint } from '@adhdev/session-host-core';
|
|
1
|
+
import { type SessionHostEndpoint, type SessionHostRequestType } from '@adhdev/session-host-core';
|
|
2
2
|
import type { HostedCliRuntimeDescriptor } from '../commands/cli-manager.js';
|
|
3
3
|
export declare function ensureSessionHostReady(options: {
|
|
4
4
|
appName?: string;
|
|
5
5
|
spawnHost: () => void;
|
|
6
6
|
timeoutMs?: number;
|
|
7
|
+
requiredRequestTypes?: readonly SessionHostRequestType[];
|
|
7
8
|
}): Promise<SessionHostEndpoint>;
|
|
8
9
|
export declare function listHostedCliRuntimes(endpoint: SessionHostEndpoint): Promise<HostedCliRuntimeDescriptor[]>;
|
package/package.json
CHANGED
|
@@ -22,6 +22,7 @@ import type { SessionTransport } from '../shared-types.js';
|
|
|
22
22
|
|
|
23
23
|
const RECENT_SEND_WINDOW_MS = 1200;
|
|
24
24
|
export const READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25_000;
|
|
25
|
+
const HERMES_CLI_STARTING_SEND_SETTLE_MS = 2_000;
|
|
25
26
|
const recentSendByTarget = new Map<string, number>();
|
|
26
27
|
|
|
27
28
|
interface ApprovalSelectableInstance extends ProviderInstance {
|
|
@@ -101,6 +102,19 @@ function getSendChatInputEnvelope(args: any): InputEnvelope {
|
|
|
101
102
|
return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
function sleep(ms: number): Promise<void> {
|
|
106
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function waitOnceForFreshHermesCliStart(adapter: CliAdapter, log: (msg: string) => void): Promise<void> {
|
|
110
|
+
if (adapter.cliType !== 'hermes-cli') return;
|
|
111
|
+
const status = typeof adapter.getStatus === 'function' ? adapter.getStatus()?.status : undefined;
|
|
112
|
+
if (status !== 'starting') return;
|
|
113
|
+
|
|
114
|
+
log(`Hermes CLI is still starting; waiting ${HERMES_CLI_STARTING_SEND_SETTLE_MS}ms before first send`);
|
|
115
|
+
await sleep(HERMES_CLI_STARTING_SEND_SETTLE_MS);
|
|
116
|
+
}
|
|
117
|
+
|
|
104
118
|
function getHistorySessionId(h: CommandHelpers, args: any): string | undefined {
|
|
105
119
|
const explicit = typeof args?.historySessionId === 'string' ? args.historySessionId.trim() : '';
|
|
106
120
|
if (explicit) return explicit;
|
|
@@ -1120,6 +1134,7 @@ export async function handleSendChat(h: CommandHelpers, args: any): Promise<Comm
|
|
|
1120
1134
|
try {
|
|
1121
1135
|
assertTextOnlyInput(provider, input);
|
|
1122
1136
|
if (!text) return { success: false, error: 'text required for PTY send' };
|
|
1137
|
+
await waitOnceForFreshHermesCliStart(adapter, _log);
|
|
1123
1138
|
await adapter.sendMessage(text);
|
|
1124
1139
|
return _logSendSuccess(`${transport}-adapter`, adapter.cliType);
|
|
1125
1140
|
} catch (e: any) {
|
|
@@ -1032,8 +1032,11 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
1032
1032
|
const aTime = getTime(a.message);
|
|
1033
1033
|
const bTime = getTime(b.message);
|
|
1034
1034
|
if (aTime && bTime && aTime !== bTime) return aTime - bTime;
|
|
1035
|
-
|
|
1036
|
-
|
|
1035
|
+
// Many provider-owned CLI transcripts (including Hermes CLI in debug bundles)
|
|
1036
|
+
// do not carry timestamps on parsed messages. In that case there is no safe
|
|
1037
|
+
// clock basis for interleaving timestamped runtime/system messages into the
|
|
1038
|
+
// provider transcript, so preserve parsed order and append runtime entries by
|
|
1039
|
+
// their insertion index instead of moving them ahead of the whole transcript.
|
|
1037
1040
|
return a.index - b.index;
|
|
1038
1041
|
})
|
|
1039
1042
|
.map((entry) => entry.message));
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SessionHostClient,
|
|
3
3
|
getDefaultSessionHostEndpoint,
|
|
4
|
+
type SessionHostDiagnostics,
|
|
4
5
|
type SessionHostEndpoint,
|
|
5
6
|
type SessionHostRecord,
|
|
7
|
+
type SessionHostRequestType,
|
|
6
8
|
} from '@adhdev/session-host-core';
|
|
7
9
|
import type { HostedCliRuntimeDescriptor } from '../commands/cli-manager.js';
|
|
8
10
|
import { DEFAULT_SESSION_HOST_READY_TIMEOUT_MS } from '../runtime-defaults.js';
|
|
@@ -10,21 +12,65 @@ import { DEFAULT_SESSION_HOST_READY_TIMEOUT_MS } from '../runtime-defaults.js';
|
|
|
10
12
|
const STARTUP_TIMEOUT_MS = DEFAULT_SESSION_HOST_READY_TIMEOUT_MS;
|
|
11
13
|
const STARTUP_POLL_MS = 200;
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
class SessionHostCompatibilityError extends Error {
|
|
16
|
+
constructor(message: string) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'SessionHostCompatibilityError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getMissingRequestTypes(
|
|
23
|
+
diagnostics: SessionHostDiagnostics | undefined,
|
|
24
|
+
requiredRequestTypes: readonly SessionHostRequestType[],
|
|
25
|
+
): SessionHostRequestType[] {
|
|
26
|
+
const supported = new Set(diagnostics?.supportedRequestTypes || []);
|
|
27
|
+
return requiredRequestTypes.filter((requestType) => !supported.has(requestType));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function assertRequiredRequestTypes(
|
|
31
|
+
client: SessionHostClient,
|
|
32
|
+
requiredRequestTypes: readonly SessionHostRequestType[],
|
|
33
|
+
): Promise<void> {
|
|
34
|
+
if (requiredRequestTypes.length === 0) return;
|
|
35
|
+
|
|
36
|
+
const response = await client.request<SessionHostDiagnostics>({
|
|
37
|
+
type: 'get_host_diagnostics',
|
|
38
|
+
payload: { includeSessions: false },
|
|
39
|
+
});
|
|
40
|
+
const missing = getMissingRequestTypes(response.success ? response.result : undefined, requiredRequestTypes);
|
|
41
|
+
if (missing.length > 0) {
|
|
42
|
+
const detail = response.success ? '' : ` (${response.error || 'capability probe failed'})`;
|
|
43
|
+
throw new SessionHostCompatibilityError(
|
|
44
|
+
`Session host does not support required request types: ${missing.join(', ')}${detail}`,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function canConnect(
|
|
50
|
+
endpoint: SessionHostEndpoint,
|
|
51
|
+
requiredRequestTypes: readonly SessionHostRequestType[] = [],
|
|
52
|
+
): Promise<boolean> {
|
|
14
53
|
const client = new SessionHostClient({ endpoint });
|
|
15
54
|
try {
|
|
16
55
|
await client.connect();
|
|
17
|
-
await client
|
|
56
|
+
await assertRequiredRequestTypes(client, requiredRequestTypes);
|
|
18
57
|
return true;
|
|
19
|
-
} catch {
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (error instanceof SessionHostCompatibilityError) throw error;
|
|
20
60
|
return false;
|
|
61
|
+
} finally {
|
|
62
|
+
await client.close().catch(() => {});
|
|
21
63
|
}
|
|
22
64
|
}
|
|
23
65
|
|
|
24
|
-
async function waitForReady(
|
|
66
|
+
async function waitForReady(
|
|
67
|
+
endpoint: SessionHostEndpoint,
|
|
68
|
+
timeoutMs = STARTUP_TIMEOUT_MS,
|
|
69
|
+
requiredRequestTypes: readonly SessionHostRequestType[] = [],
|
|
70
|
+
): Promise<void> {
|
|
25
71
|
const deadline = Date.now() + timeoutMs;
|
|
26
72
|
while (Date.now() < deadline) {
|
|
27
|
-
if (await canConnect(endpoint)) return;
|
|
73
|
+
if (await canConnect(endpoint, requiredRequestTypes)) return;
|
|
28
74
|
await new Promise((resolve) => setTimeout(resolve, STARTUP_POLL_MS));
|
|
29
75
|
}
|
|
30
76
|
throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
|
|
@@ -34,11 +80,13 @@ export async function ensureSessionHostReady(options: {
|
|
|
34
80
|
appName?: string;
|
|
35
81
|
spawnHost: () => void;
|
|
36
82
|
timeoutMs?: number;
|
|
83
|
+
requiredRequestTypes?: readonly SessionHostRequestType[];
|
|
37
84
|
}): Promise<SessionHostEndpoint> {
|
|
38
85
|
const endpoint = getDefaultSessionHostEndpoint(options.appName || 'adhdev');
|
|
39
|
-
|
|
86
|
+
const requiredRequestTypes = options.requiredRequestTypes || [];
|
|
87
|
+
if (await canConnect(endpoint, requiredRequestTypes)) return endpoint;
|
|
40
88
|
options.spawnHost();
|
|
41
|
-
await waitForReady(endpoint, options.timeoutMs);
|
|
89
|
+
await waitForReady(endpoint, options.timeoutMs, requiredRequestTypes);
|
|
42
90
|
return endpoint;
|
|
43
91
|
}
|
|
44
92
|
|