@adhdev/daemon-core 1.0.18-rc.2 → 1.0.18-rc.3
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/cli-state-engine.d.ts +77 -0
- package/dist/cli-adapters/pty-transport.d.ts +2 -1
- package/dist/commands/process-lifecycle.d.ts +43 -0
- package/dist/commands/windows-atomic-upgrade.d.ts +12 -1
- package/dist/index.js +470 -147
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +479 -156
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/cli-adapters/cli-state-engine.ts +204 -3
- package/src/cli-adapters/provider-cli-adapter.ts +39 -5
- package/src/cli-adapters/pty-transport.d.ts +2 -1
- package/src/cli-adapters/pty-transport.ts +1 -1
- package/src/cli-adapters/session-host-transport.ts +8 -3
- package/src/commands/process-lifecycle.ts +248 -0
- package/src/commands/upgrade-helper.ts +29 -68
- package/src/commands/windows-atomic-upgrade.ts +96 -4
- package/src/session-host/managed-host.ts +34 -0
|
@@ -59,6 +59,17 @@ export interface CliStateEngineCallbacks {
|
|
|
59
59
|
*/
|
|
60
60
|
isInApprovalResumeGrace?(): boolean;
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Minimal shape computeApprovalContentSignature / isStaleResolvedApproval
|
|
64
|
+
* actually need — deliberately narrower than the full CliBufferSnapshot so
|
|
65
|
+
* callers outside the settled-eval loop (e.g. the adapter's startup-gate
|
|
66
|
+
* modal parse in getStatus/getDebugState) can supply just these two fields
|
|
67
|
+
* without having to fabricate an entire snapshot.
|
|
68
|
+
*/
|
|
69
|
+
interface ApprovalSignatureSnapshot {
|
|
70
|
+
screenText?: string;
|
|
71
|
+
accumulatedBuffer?: string;
|
|
72
|
+
}
|
|
62
73
|
export declare class CliStateEngine {
|
|
63
74
|
private readonly provider;
|
|
64
75
|
private readonly runner;
|
|
@@ -76,6 +87,22 @@ export declare class CliStateEngine {
|
|
|
76
87
|
} | null;
|
|
77
88
|
lastApprovalResolvedAt: number;
|
|
78
89
|
lastResolvedModalMessage: string;
|
|
90
|
+
/**
|
|
91
|
+
* Normalized approval-context signature captured at resolve time (see
|
|
92
|
+
* `computeApprovalContentSignature`) — the screen text with blank-line
|
|
93
|
+
* padding and any manifest-declared chrome (transcriptPty.chromePatterns,
|
|
94
|
+
* spinner.patterns) stripped out. Used by applyWaitingApproval's
|
|
95
|
+
* isStaleResolvedRepaint check to tell "the same already-answered modal,
|
|
96
|
+
* re-parsed from a screen that has not meaningfully changed" apart from
|
|
97
|
+
* "a genuinely new approval" — content-based, not time-based, because
|
|
98
|
+
* ordinary TUI chrome (status bar, context meter, blank-line repaint)
|
|
99
|
+
* keeps producing fresh PTY bytes on an otherwise-unchanged screen and
|
|
100
|
+
* defeats any output-timestamp discriminator within a few hundred ms.
|
|
101
|
+
* Cleared whenever a turn starts or the session tears down (see
|
|
102
|
+
* onTurnStarted / resetActiveTurnState / onPtyExit) so a next-turn
|
|
103
|
+
* approval is never compared against stale prior-turn state.
|
|
104
|
+
*/
|
|
105
|
+
lastApprovalResolvedContentSignature: string;
|
|
79
106
|
/**
|
|
80
107
|
* Monotonic counter bumped every time the FSM *enters* waiting_approval
|
|
81
108
|
* with a freshly captured modal (see `applyWaitingApproval`). It is the
|
|
@@ -243,6 +270,55 @@ export declare class CliStateEngine {
|
|
|
243
270
|
finishResponse(): void;
|
|
244
271
|
private scheduleIdleFinish;
|
|
245
272
|
private cancelPendingIdleFinish;
|
|
273
|
+
/**
|
|
274
|
+
* Derive a stable approval-context signature from the current screen,
|
|
275
|
+
* with blank-line padding and any manifest-declared chrome stripped out.
|
|
276
|
+
*
|
|
277
|
+
* Generic by design — no kimi- or provider-specific hardcoding: it reads
|
|
278
|
+
* whatever `tui.transcriptPty.chromePatterns` and `tui.spinner.patterns`
|
|
279
|
+
* the ACTIVE provider's own manifest already declares (present on any
|
|
280
|
+
* declarative-TUI provider; simply absent/empty for scripted providers,
|
|
281
|
+
* in which case this degrades to blank-line stripping only — never worse
|
|
282
|
+
* than comparing the raw screen). Those pattern lists exist precisely to
|
|
283
|
+
* name "known volatile repaint noise" (status bar, context meter, spinner
|
|
284
|
+
* ticks, banners) — reusing them here means the SAME declared knowledge
|
|
285
|
+
* that governs transcript-chrome stripping also governs staleness
|
|
286
|
+
* detection, instead of re-encoding provider knowledge into daemon-core.
|
|
287
|
+
*
|
|
288
|
+
* Deliberately NOT a hash of the whole screen/buffer: an ordinary TUI
|
|
289
|
+
* repaints its footer/status/context-meter chrome continuously even while
|
|
290
|
+
* genuinely idle, so a raw whole-screen or whole-buffer fingerprint (or a
|
|
291
|
+
* mere "did any bytes arrive" timestamp) changes on every repaint tick
|
|
292
|
+
* regardless of whether anything approval-relevant actually happened.
|
|
293
|
+
* Stripping the declared chrome first yields a signature that only
|
|
294
|
+
* changes when the surrounding conversation/tool-output content itself
|
|
295
|
+
* changes — exactly the discriminator applyWaitingApproval's
|
|
296
|
+
* isStaleResolvedRepaint check needs.
|
|
297
|
+
*/
|
|
298
|
+
private computeApprovalContentSignature;
|
|
299
|
+
/**
|
|
300
|
+
* True when `modal` is a stale re-parse of an already-resolved approval:
|
|
301
|
+
* same message text, and the chrome-stripped approval-context signature
|
|
302
|
+
* of `snap` is unchanged from the signature captured at resolve time.
|
|
303
|
+
*
|
|
304
|
+
* Public and reused verbatim by BOTH the settled-eval capture path
|
|
305
|
+
* (applyWaitingApproval, below) and any OUTSIDE re-parse the adapter
|
|
306
|
+
* performs independently of the settle loop — e.g. provider-cli-adapter's
|
|
307
|
+
* getStatus()/getDebugState() startup-gate modal detection, which reads
|
|
308
|
+
* `recentOutputBuffer` directly while `startupParseGate` is open and can
|
|
309
|
+
* re-surface the same already-resolved modal before the gate closes.
|
|
310
|
+
* Centralizing the discriminator here means there is exactly ONE
|
|
311
|
+
* definition of "stale" for the whole session — no divergent duplicate
|
|
312
|
+
* heuristic re-implemented per call site.
|
|
313
|
+
*/
|
|
314
|
+
isStaleResolvedApproval(modal: {
|
|
315
|
+
message: string;
|
|
316
|
+
buttons: string[];
|
|
317
|
+
} | null, snap: ApprovalSignatureSnapshot): boolean;
|
|
318
|
+
/** Clear all resolve-time approval bookkeeping (message, timestamp, content
|
|
319
|
+
* signature) — called at turn/session boundaries so a next-turn or
|
|
320
|
+
* next-session approval is never compared against stale prior state. */
|
|
321
|
+
private clearApprovalResolutionMemory;
|
|
246
322
|
/**
|
|
247
323
|
* Schedule one more settled evaluation while pinned to `waiting_approval`
|
|
248
324
|
* with no actionable modal. The settled FSM normally only re-runs on new
|
|
@@ -269,3 +345,4 @@ export declare class CliStateEngine {
|
|
|
269
345
|
private parsedStatusHasFinalStandardAssistantMessage;
|
|
270
346
|
private recordTrace;
|
|
271
347
|
}
|
|
348
|
+
export {};
|
|
@@ -39,7 +39,8 @@ export interface PtyRuntimeTransport {
|
|
|
39
39
|
getMetadata?(): PtyRuntimeMetadata | null;
|
|
40
40
|
onData(callback: (data: string) => void): void;
|
|
41
41
|
onExit(callback: (info: {
|
|
42
|
-
exitCode: number;
|
|
42
|
+
exitCode: number | null;
|
|
43
|
+
signal?: number | null;
|
|
43
44
|
}) => void): void;
|
|
44
45
|
}
|
|
45
46
|
export interface PtyTransportFactory {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface ProcessLifecycleOptions {
|
|
2
|
+
platform?: NodeJS.Platform;
|
|
3
|
+
execFileSync?: typeof import('child_process').execFileSync;
|
|
4
|
+
}
|
|
5
|
+
export interface OwnedProcessInfo {
|
|
6
|
+
pid: number;
|
|
7
|
+
commandLine: string | null;
|
|
8
|
+
}
|
|
9
|
+
export declare function getProcessCommandLine(pid: number, options?: ProcessLifecycleOptions): string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Extract the script argument (the token after the node executable) from a
|
|
12
|
+
* command line. Handles both quoted and unquoted executables/scripts.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseNodeScriptPath(commandLine: string | null): string | null;
|
|
15
|
+
export declare function killProcess(pid: number, options?: ProcessLifecycleOptions): boolean;
|
|
16
|
+
export declare function waitForPidExit(pid: number, timeoutMs: number): Promise<boolean>;
|
|
17
|
+
/**
|
|
18
|
+
* List Node processes whose command line places them under any of the supplied
|
|
19
|
+
* prefixes. Windows-only — the versioned-prefix lifecycle this supports does not
|
|
20
|
+
* exist on POSIX, so the helper is a no-op there.
|
|
21
|
+
*/
|
|
22
|
+
export declare function listOwnedNodeProcesses(options: {
|
|
23
|
+
prefixes: readonly string[];
|
|
24
|
+
excludePids?: readonly number[];
|
|
25
|
+
markers?: readonly string[];
|
|
26
|
+
} & ProcessLifecycleOptions): OwnedProcessInfo[];
|
|
27
|
+
export declare function stopOwnedProcesses(options: {
|
|
28
|
+
processes: readonly OwnedProcessInfo[];
|
|
29
|
+
waitMs?: number;
|
|
30
|
+
} & ProcessLifecycleOptions): Promise<{
|
|
31
|
+
stopped: number;
|
|
32
|
+
survivors: OwnedProcessInfo[];
|
|
33
|
+
}>;
|
|
34
|
+
export declare function stopOwnedProcessesForPrefixes(options: {
|
|
35
|
+
prefixes: readonly string[];
|
|
36
|
+
excludePids?: readonly number[];
|
|
37
|
+
markers?: readonly string[];
|
|
38
|
+
waitMs?: number;
|
|
39
|
+
log?: (message: string) => void;
|
|
40
|
+
} & ProcessLifecycleOptions): Promise<{
|
|
41
|
+
stopped: number;
|
|
42
|
+
survivors: OwnedProcessInfo[];
|
|
43
|
+
}>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ChildProcess } from 'child_process';
|
|
2
|
+
export declare const ADHDEV_OWNED_MARKERS: readonly ["session-host-daemon", "node_modules/adhdev", "node_modules/@adhdev/daemon-standalone"];
|
|
2
3
|
export interface WindowsInstallerLayout {
|
|
3
4
|
homeDir: string;
|
|
4
5
|
installRoot: string;
|
|
@@ -13,7 +14,7 @@ export interface WindowsAtomicUpgradeHooks {
|
|
|
13
14
|
restartOld: (portableNode: string) => void;
|
|
14
15
|
waitForHealth: (pid: number, targetVersion: string) => Promise<boolean>;
|
|
15
16
|
stopProcess: (pid: number) => void;
|
|
16
|
-
cleanup: (layout: WindowsInstallerLayout, activePrefix: string) => void
|
|
17
|
+
cleanup: (layout: WindowsInstallerLayout, activePrefix: string) => void | Promise<void>;
|
|
17
18
|
log: (message: string) => void;
|
|
18
19
|
}
|
|
19
20
|
export interface WindowsAtomicUpgradeOptions {
|
|
@@ -22,6 +23,8 @@ export interface WindowsAtomicUpgradeOptions {
|
|
|
22
23
|
targetVersion: string;
|
|
23
24
|
portableNode: string;
|
|
24
25
|
hooks: WindowsAtomicUpgradeHooks;
|
|
26
|
+
/** PIDs that must never be terminated during prefix sweeps (helper + parent daemon). */
|
|
27
|
+
excludePids?: number[];
|
|
25
28
|
}
|
|
26
29
|
export interface WindowsAtomicUpgradeResult {
|
|
27
30
|
stagedPrefix: string;
|
|
@@ -45,3 +48,11 @@ export declare function createDefaultWindowsAtomicHooks(options: {
|
|
|
45
48
|
log: (message: string) => void;
|
|
46
49
|
}): WindowsAtomicUpgradeHooks;
|
|
47
50
|
export declare function boundedCleanupInactivePrefixes(layout: WindowsInstallerLayout, activePrefix: string, log: (message: string) => void): void;
|
|
51
|
+
export declare function cleanupInactivePrefixesWithGuard(options: {
|
|
52
|
+
layout: WindowsInstallerLayout;
|
|
53
|
+
activePrefix: string;
|
|
54
|
+
excludePids?: number[];
|
|
55
|
+
markers?: readonly string[];
|
|
56
|
+
waitMs?: number;
|
|
57
|
+
log?: (message: string) => void;
|
|
58
|
+
}): Promise<void>;
|