@raidiant/notifai 0.5.0 → 0.5.1

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,101 @@
1
+ import type { EscalationDeliveryRoute } from './hooks.js';
2
+ /** Claude Code's currently observed inbox protocol. Unknown versions fail closed. */
3
+ export declare const CLAUDE_PEER_PROTOCOL = 1;
4
+ /** The first Claude Code release that publishes a session inbox socket. */
5
+ export declare const CLAUDE_MIN_INBOX_VERSION = "2.1.224";
6
+ /** macOS verifies own-child ancestry only while the posting process is alive. */
7
+ export declare const CLAUDE_POST_SEND_LIVENESS_MS = 8000;
8
+ export type ClaudeLiveStatus = 'idle' | 'busy';
9
+ export interface ClaudeSessionDescriptor {
10
+ pid: number;
11
+ sessionId: string;
12
+ cwd: string;
13
+ startedAt: number;
14
+ procStart: string;
15
+ version: string;
16
+ peerProtocol: number;
17
+ messagingSocketPath: string;
18
+ status: string;
19
+ }
20
+ export interface ClaudeAgentObservation {
21
+ pid: number;
22
+ sessionId: string;
23
+ startedAt: number;
24
+ status: string;
25
+ }
26
+ export interface ClaudeWakeAdapters {
27
+ listAgents(): Promise<unknown>;
28
+ readDescriptor(pid: number): unknown;
29
+ sendSocket(socketPath: string, line: string): Promise<void>;
30
+ resume(sessionId: string, cwd: string, context: string): Promise<void>;
31
+ sleep(milliseconds: number): Promise<void>;
32
+ }
33
+ export type ClaudeWakeObservation = {
34
+ state: 'live-idle' | 'live-busy';
35
+ descriptor: ClaudeSessionDescriptor;
36
+ } | {
37
+ state: 'stopped';
38
+ } | {
39
+ state: 'unknown';
40
+ reason: string;
41
+ };
42
+ /**
43
+ * Observe one exact Claude Code session without guessing.
44
+ *
45
+ * `claude agents --json` is the liveness oracle: Claude Code itself validates
46
+ * each registry row against both PID and process start time before returning it.
47
+ * The descriptor supplies the socket and peer protocol, but is never trusted as
48
+ * proof that a process still owns the session.
49
+ */
50
+ export declare function observeClaudeSession(sessionId: string, adapters: Pick<ClaudeWakeAdapters, 'listAgents' | 'readDescriptor'>): Promise<ClaudeWakeObservation>;
51
+ export type ClaudeInboxReadiness = {
52
+ state: 'ready';
53
+ socketPath: string;
54
+ version: string;
55
+ } | {
56
+ state: 'unavailable';
57
+ reason: string;
58
+ };
59
+ /**
60
+ * Whether an answer could reach this exact Claude session over its inbox
61
+ * socket, decided from evidence already on disk.
62
+ *
63
+ * Read-only by construction: it reads the session descriptor and asks whether
64
+ * the socket file exists, and never connects to it. A diagnostic that delivers
65
+ * a message is not a diagnostic.
66
+ *
67
+ * Every negative answer here is a degradation, not a failure — the accepted
68
+ * journal still replays the answer at the session's next turn. What it buys is
69
+ * that the reason is nameable in advance instead of being discovered as
70
+ * silence. The common one is `--bare`, which binds no socket at all (and runs
71
+ * no hooks either, so nothing would have registered a question in the first
72
+ * place).
73
+ */
74
+ export declare function inspectClaudeInbox(options: {
75
+ pid: number;
76
+ platform: NodeJS.Platform;
77
+ readDescriptor: (pid: number) => unknown;
78
+ socketExists: (socketPath: string) => boolean;
79
+ }): ClaudeInboxReadiness;
80
+ /**
81
+ * Claude's own-child delivery route.
82
+ *
83
+ * A successful socket write proves delivery to Claude Code, not model
84
+ * consumption — and this route reports exactly that, no more. It reports
85
+ * `delivered` all the same, because the write is the strongest acknowledgement
86
+ * this route can ever obtain: the message it posts starts a brand-new turn
87
+ * rather than continuing this one, so no later hook will confirm anything about
88
+ * it. An answer delivered once and settled is strictly better than an answer
89
+ * redelivered on every turn-end for ever.
90
+ *
91
+ * Every path that hands nothing over reports `held`, so the accepted journal
92
+ * replays it. Unknown state deliberately returns without throwing, so the
93
+ * journal becomes `hold-for-next-turn` instead of failing the hook.
94
+ */
95
+ export declare function claudeWakeRoute(options: {
96
+ sessionId: string;
97
+ cwd: string;
98
+ sourcePid: number;
99
+ adapters?: ClaudeWakeAdapters;
100
+ }): EscalationDeliveryRoute;
101
+ export declare function systemClaudeWakeAdapters(env?: NodeJS.ProcessEnv): ClaudeWakeAdapters;
@@ -0,0 +1,397 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { createConnection } from 'node:net';
6
+ /** Claude Code's currently observed inbox protocol. Unknown versions fail closed. */
7
+ export const CLAUDE_PEER_PROTOCOL = 1;
8
+ /** The first Claude Code release that publishes a session inbox socket. */
9
+ export const CLAUDE_MIN_INBOX_VERSION = '2.1.224';
10
+ /** The inbox socket is a Unix domain socket; no Windows implementation exists. */
11
+ const INBOX_PLATFORMS = new Set(['darwin', 'linux']);
12
+ /** macOS verifies own-child ancestry only while the posting process is alive. */
13
+ export const CLAUDE_POST_SEND_LIVENESS_MS = 8_000;
14
+ const LIVE_STATUSES = new Set(['idle', 'busy']);
15
+ function isRecord(value) {
16
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
17
+ }
18
+ function parseAgent(value) {
19
+ if (!isRecord(value))
20
+ return null;
21
+ if (typeof value['pid'] !== 'number' ||
22
+ !Number.isInteger(value['pid']) ||
23
+ value['pid'] <= 0 ||
24
+ typeof value['sessionId'] !== 'string' ||
25
+ value['sessionId'] === '' ||
26
+ typeof value['startedAt'] !== 'number' ||
27
+ !Number.isFinite(value['startedAt']) ||
28
+ typeof value['status'] !== 'string') {
29
+ return null;
30
+ }
31
+ return {
32
+ pid: value['pid'],
33
+ sessionId: value['sessionId'],
34
+ startedAt: value['startedAt'],
35
+ status: value['status'],
36
+ };
37
+ }
38
+ function parseDescriptor(value) {
39
+ if (!isRecord(value))
40
+ return null;
41
+ if (typeof value['pid'] !== 'number' ||
42
+ !Number.isInteger(value['pid']) ||
43
+ value['pid'] <= 0 ||
44
+ typeof value['sessionId'] !== 'string' ||
45
+ value['sessionId'] === '' ||
46
+ typeof value['cwd'] !== 'string' ||
47
+ value['cwd'] === '' ||
48
+ typeof value['startedAt'] !== 'number' ||
49
+ !Number.isFinite(value['startedAt']) ||
50
+ typeof value['procStart'] !== 'string' ||
51
+ value['procStart'] === '' ||
52
+ typeof value['version'] !== 'string' ||
53
+ value['version'] === '' ||
54
+ typeof value['peerProtocol'] !== 'number' ||
55
+ !Number.isInteger(value['peerProtocol']) ||
56
+ typeof value['messagingSocketPath'] !== 'string' ||
57
+ value['messagingSocketPath'] === '' ||
58
+ typeof value['status'] !== 'string') {
59
+ return null;
60
+ }
61
+ return {
62
+ pid: value['pid'],
63
+ sessionId: value['sessionId'],
64
+ cwd: value['cwd'],
65
+ startedAt: value['startedAt'],
66
+ procStart: value['procStart'],
67
+ version: value['version'],
68
+ peerProtocol: value['peerProtocol'],
69
+ messagingSocketPath: value['messagingSocketPath'],
70
+ status: value['status'],
71
+ };
72
+ }
73
+ /**
74
+ * Observe one exact Claude Code session without guessing.
75
+ *
76
+ * `claude agents --json` is the liveness oracle: Claude Code itself validates
77
+ * each registry row against both PID and process start time before returning it.
78
+ * The descriptor supplies the socket and peer protocol, but is never trusted as
79
+ * proof that a process still owns the session.
80
+ */
81
+ export async function observeClaudeSession(sessionId, adapters) {
82
+ let listed;
83
+ try {
84
+ listed = await adapters.listAgents();
85
+ }
86
+ catch (err) {
87
+ return {
88
+ state: 'unknown',
89
+ reason: `claude agents probe failed: ${err instanceof Error ? err.message : String(err)}`,
90
+ };
91
+ }
92
+ if (!Array.isArray(listed)) {
93
+ return { state: 'unknown', reason: 'claude agents returned an invalid document' };
94
+ }
95
+ const matchingRaw = listed.filter((value) => isRecord(value) && value['sessionId'] === sessionId);
96
+ if (matchingRaw.length === 0)
97
+ return { state: 'stopped' };
98
+ if (matchingRaw.length !== 1) {
99
+ return { state: 'unknown', reason: 'claude agents returned duplicate session owners' };
100
+ }
101
+ const agent = parseAgent(matchingRaw[0]);
102
+ if (agent === null) {
103
+ return { state: 'unknown', reason: 'claude agents returned an invalid matching row' };
104
+ }
105
+ let descriptorRaw;
106
+ try {
107
+ descriptorRaw = adapters.readDescriptor(agent.pid);
108
+ }
109
+ catch (err) {
110
+ return {
111
+ state: 'unknown',
112
+ reason: `Claude session descriptor could not be read: ${err instanceof Error ? err.message : String(err)}`,
113
+ };
114
+ }
115
+ const descriptor = parseDescriptor(descriptorRaw);
116
+ if (descriptor === null) {
117
+ return { state: 'unknown', reason: 'Claude session descriptor has an unknown shape' };
118
+ }
119
+ if (descriptor.pid !== agent.pid ||
120
+ descriptor.sessionId !== agent.sessionId ||
121
+ descriptor.startedAt !== agent.startedAt) {
122
+ return { state: 'unknown', reason: 'Claude liveness probe and descriptor disagree' };
123
+ }
124
+ if (descriptor.peerProtocol !== CLAUDE_PEER_PROTOCOL) {
125
+ return {
126
+ state: 'unknown',
127
+ reason: `unsupported Claude peer protocol ${descriptor.peerProtocol}`,
128
+ };
129
+ }
130
+ if (!LIVE_STATUSES.has(agent.status)) {
131
+ return { state: 'unknown', reason: `Claude session status ${agent.status} is not wakeable` };
132
+ }
133
+ return {
134
+ state: agent.status === 'idle' ? 'live-idle' : 'live-busy',
135
+ descriptor,
136
+ };
137
+ }
138
+ /** Ordered comparison of dotted release numbers, ignoring any suffix. */
139
+ function versionAtLeast(version, minimum) {
140
+ const parse = (value) => value.split('.').map((part) => Number.parseInt(part, 10) || 0);
141
+ const left = parse(version);
142
+ const right = parse(minimum);
143
+ for (let index = 0; index < Math.max(left.length, right.length); index += 1) {
144
+ const a = left[index] ?? 0;
145
+ const b = right[index] ?? 0;
146
+ if (a !== b)
147
+ return a > b;
148
+ }
149
+ return true;
150
+ }
151
+ /**
152
+ * Whether an answer could reach this exact Claude session over its inbox
153
+ * socket, decided from evidence already on disk.
154
+ *
155
+ * Read-only by construction: it reads the session descriptor and asks whether
156
+ * the socket file exists, and never connects to it. A diagnostic that delivers
157
+ * a message is not a diagnostic.
158
+ *
159
+ * Every negative answer here is a degradation, not a failure — the accepted
160
+ * journal still replays the answer at the session's next turn. What it buys is
161
+ * that the reason is nameable in advance instead of being discovered as
162
+ * silence. The common one is `--bare`, which binds no socket at all (and runs
163
+ * no hooks either, so nothing would have registered a question in the first
164
+ * place).
165
+ */
166
+ export function inspectClaudeInbox(options) {
167
+ if (!INBOX_PLATFORMS.has(options.platform)) {
168
+ return {
169
+ state: 'unavailable',
170
+ reason: `Claude Code publishes no inbox socket on ${options.platform}; it exists on macOS and Linux only`,
171
+ };
172
+ }
173
+ let raw;
174
+ try {
175
+ raw = options.readDescriptor(options.pid);
176
+ }
177
+ catch (err) {
178
+ return {
179
+ state: 'unavailable',
180
+ reason: `no session descriptor for pid ${options.pid} (${err instanceof Error ? err.message : String(err)}); a session started with \`--bare\` binds no inbox socket`,
181
+ };
182
+ }
183
+ const descriptor = parseDescriptor(raw);
184
+ if (descriptor === null) {
185
+ return {
186
+ state: 'unavailable',
187
+ reason: `the session descriptor for pid ${options.pid} has an unknown shape`,
188
+ };
189
+ }
190
+ if (descriptor.peerProtocol !== CLAUDE_PEER_PROTOCOL) {
191
+ return {
192
+ state: 'unavailable',
193
+ reason: `this session speaks inbox protocol ${descriptor.peerProtocol}, and only ${CLAUDE_PEER_PROTOCOL} is known; refusing to guess at an undocumented wire format`,
194
+ };
195
+ }
196
+ if (!versionAtLeast(descriptor.version, CLAUDE_MIN_INBOX_VERSION)) {
197
+ return {
198
+ state: 'unavailable',
199
+ reason: `Claude Code ${descriptor.version} is older than ${CLAUDE_MIN_INBOX_VERSION}, which is where the inbox socket starts`,
200
+ };
201
+ }
202
+ if (!options.socketExists(descriptor.messagingSocketPath)) {
203
+ return {
204
+ state: 'unavailable',
205
+ reason: `the descriptor names ${descriptor.messagingSocketPath}, but no socket exists there`,
206
+ };
207
+ }
208
+ return {
209
+ state: 'ready',
210
+ socketPath: descriptor.messagingSocketPath,
211
+ version: descriptor.version,
212
+ };
213
+ }
214
+ function socketLine(context) {
215
+ return `${JSON.stringify({
216
+ type: 'user',
217
+ message: { role: 'user', content: context },
218
+ })}\n`;
219
+ }
220
+ /**
221
+ * Claude's own-child delivery route.
222
+ *
223
+ * A successful socket write proves delivery to Claude Code, not model
224
+ * consumption — and this route reports exactly that, no more. It reports
225
+ * `delivered` all the same, because the write is the strongest acknowledgement
226
+ * this route can ever obtain: the message it posts starts a brand-new turn
227
+ * rather than continuing this one, so no later hook will confirm anything about
228
+ * it. An answer delivered once and settled is strictly better than an answer
229
+ * redelivered on every turn-end for ever.
230
+ *
231
+ * Every path that hands nothing over reports `held`, so the accepted journal
232
+ * replays it. Unknown state deliberately returns without throwing, so the
233
+ * journal becomes `hold-for-next-turn` instead of failing the hook.
234
+ */
235
+ export function claudeWakeRoute(options) {
236
+ const adapters = options.adapters ?? systemClaudeWakeAdapters();
237
+ let sourceDescriptor = null;
238
+ try {
239
+ const parsed = parseDescriptor(adapters.readDescriptor(options.sourcePid));
240
+ if (parsed !== null &&
241
+ parsed.sessionId === options.sessionId &&
242
+ parsed.pid === options.sourcePid) {
243
+ sourceDescriptor = parsed;
244
+ }
245
+ }
246
+ catch {
247
+ // Delivery fails closed below; route construction must never break the hook.
248
+ }
249
+ return {
250
+ kind: 'inbox-socket',
251
+ async deliver(event) {
252
+ const observation = await observeClaudeSession(options.sessionId, adapters);
253
+ if (observation.state === 'unknown') {
254
+ return {
255
+ notes: [`holding the accepted answer for the next turn: ${observation.reason}`],
256
+ log: { route: 'hold-for-next-turn', stage: 'queued', reason: observation.reason },
257
+ acknowledgement: 'held',
258
+ };
259
+ }
260
+ if (sourceDescriptor === null) {
261
+ const reason = 'the Stop-hook process cannot prove exact Claude session ownership';
262
+ return {
263
+ notes: [`holding the accepted answer for the next turn: ${reason}`],
264
+ log: { route: 'hold-for-next-turn', stage: 'queued', reason },
265
+ acknowledgement: 'held',
266
+ };
267
+ }
268
+ if (observation.state === 'stopped') {
269
+ // Probe immediately before spawn. A prior descriptor or dead socket is
270
+ // never sufficient: resuming a live session creates a divergent ghost.
271
+ const confirmed = await observeClaudeSession(options.sessionId, adapters);
272
+ if (confirmed.state !== 'stopped') {
273
+ const reason = confirmed.state === 'unknown'
274
+ ? confirmed.reason
275
+ : 'the Claude session became live before cold resume';
276
+ return {
277
+ notes: [`holding the accepted answer for the next turn: ${reason}`],
278
+ log: { route: 'hold-for-next-turn', stage: 'queued', reason },
279
+ acknowledgement: 'held',
280
+ };
281
+ }
282
+ await adapters.resume(options.sessionId, sourceDescriptor.cwd, event.context);
283
+ return {
284
+ notes: ['cold-resumed the stopped Claude session with its accepted answer'],
285
+ log: { route: 'cold-resume', stage: 'delivered' },
286
+ acknowledgement: 'delivered',
287
+ };
288
+ }
289
+ if (observation.descriptor.pid !== options.sourcePid ||
290
+ sourceDescriptor.startedAt !== observation.descriptor.startedAt) {
291
+ const reason = 'the Stop-hook process is not the observed exact Claude session child';
292
+ return {
293
+ notes: [`holding the accepted answer for the next turn: ${reason}`],
294
+ log: { route: 'hold-for-next-turn', stage: 'queued', reason },
295
+ acknowledgement: 'held',
296
+ };
297
+ }
298
+ await adapters.sendSocket(observation.descriptor.messagingSocketPath, socketLine(event.context));
299
+ await adapters.sleep(CLAUDE_POST_SEND_LIVENESS_MS);
300
+ return {
301
+ notes: [
302
+ observation.state === 'live-idle'
303
+ ? 'posted the accepted answer to the live Claude session'
304
+ : 'queued the accepted answer for the busy Claude session',
305
+ ],
306
+ log: {
307
+ route: 'inbox-socket',
308
+ stage: 'delivered',
309
+ session_state: observation.state,
310
+ },
311
+ // The write completed: Claude Code holds the message. Nothing later
312
+ // reports on it, so this is where the journal settles.
313
+ acknowledgement: 'delivered',
314
+ };
315
+ },
316
+ };
317
+ }
318
+ function runClaude(args, options = {}) {
319
+ return new Promise((resolve, reject) => {
320
+ const child = spawn('claude', args, {
321
+ ...(options.cwd === undefined ? {} : { cwd: options.cwd }),
322
+ ...(options.env === undefined ? {} : { env: options.env }),
323
+ stdio: ['ignore', 'pipe', 'pipe'],
324
+ });
325
+ const stdout = [];
326
+ const stderr = [];
327
+ child.stdout?.on('data', (chunk) => stdout.push(Buffer.from(chunk)));
328
+ child.stderr?.on('data', (chunk) => stderr.push(Buffer.from(chunk)));
329
+ child.once('error', reject);
330
+ child.once('exit', (code, signal) => {
331
+ if (code === 0) {
332
+ resolve(Buffer.concat(stdout).toString());
333
+ return;
334
+ }
335
+ reject(new Error(`claude ${args[0] ?? ''} exited ${code === null ? `on ${String(signal)}` : String(code)}: ${Buffer.concat(stderr).toString().trim()}`));
336
+ });
337
+ });
338
+ }
339
+ function coldResumeEnvironment(env) {
340
+ const next = { ...env };
341
+ for (const key of Object.keys(next)) {
342
+ if (key === 'CLAUDECODE' || key === 'CLAUDE_PID' || key.startsWith('CLAUDE_CODE_')) {
343
+ delete next[key];
344
+ }
345
+ }
346
+ return next;
347
+ }
348
+ export function systemClaudeWakeAdapters(env = process.env) {
349
+ return {
350
+ async listAgents() {
351
+ const output = await runClaude(['agents', '--json'], { env });
352
+ return JSON.parse(output);
353
+ },
354
+ readDescriptor(pid) {
355
+ const file = path.join(os.homedir(), '.claude', 'sessions', `${pid}.json`);
356
+ return JSON.parse(readFileSync(file, 'utf8'));
357
+ },
358
+ sendSocket(socketPath, line) {
359
+ return new Promise((resolve, reject) => {
360
+ const socket = createConnection(socketPath);
361
+ let settled = false;
362
+ const fail = (err) => {
363
+ if (settled)
364
+ return;
365
+ settled = true;
366
+ socket.destroy();
367
+ reject(err);
368
+ };
369
+ socket.once('error', fail);
370
+ socket.once('connect', () => {
371
+ socket.end(line, () => {
372
+ if (settled)
373
+ return;
374
+ settled = true;
375
+ resolve();
376
+ });
377
+ });
378
+ });
379
+ },
380
+ async resume(sessionId, cwd, context) {
381
+ if (!existsSync(cwd))
382
+ throw new Error(`Claude session cwd no longer exists: ${cwd}`);
383
+ await runClaude([
384
+ '-p',
385
+ '--resume',
386
+ sessionId,
387
+ '--output-format',
388
+ 'json',
389
+ context,
390
+ ], { cwd, env: coldResumeEnvironment(env) });
391
+ },
392
+ sleep(milliseconds) {
393
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
394
+ },
395
+ };
396
+ }
397
+ //# sourceMappingURL=claude-wake.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-wake.js","sourceRoot":"","sources":["../src/claude-wake.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ import { type EscalationDeliveryRoute } from './hooks.js';
2
+ /** Codex's per-thread writer lock directory, relative to `$CODEX_HOME`. */
3
+ export declare const CODEX_THREAD_LOCK_DIR = "thread-writer-locks";
4
+ export type CodexWakeObservation =
5
+ /** A live writer owns this thread. Resuming it would create a divergent ghost. */
6
+ {
7
+ state: 'live';
8
+ }
9
+ /** No process holds the thread's writer lock; a cold resume can own it. */
10
+ | {
11
+ state: 'stopped';
12
+ } | {
13
+ state: 'unknown';
14
+ reason: string;
15
+ };
16
+ export interface CodexWakeAdapters {
17
+ /** Non-blocking writer-lock probe. Never holds the lock beyond the probe. */
18
+ probeThreadWriter(lockPath: string): CodexWakeObservation;
19
+ /** Is the harness process that will read this hook's stdout still running? */
20
+ sourceAlive(pid: number): boolean;
21
+ resume(threadId: string, cwd: string, context: string): Promise<void>;
22
+ }
23
+ /**
24
+ * The one cross-process oracle for "who owns this Codex thread".
25
+ *
26
+ * Codex's thread store takes a non-blocking `flock(LOCK_EX)` on a zero-byte
27
+ * file per thread and holds it for as long as that process owns the thread —
28
+ * verified against both a hosted app-server thread sitting idle and an
29
+ * in-process `codex exec` run (2026-08-12). Because the kernel holds it, a
30
+ * crash, SIGKILL, or reboot releases it instantly, and the leftover file proves
31
+ * nothing: only the lock does. Codex fails closed itself with `-32600` when a
32
+ * second writer contends, but that is the backstop; this is the gate.
33
+ */
34
+ export declare function observeCodexThread(threadId: string, env: NodeJS.ProcessEnv, adapters: Pick<CodexWakeAdapters, 'probeThreadWriter'>): CodexWakeObservation;
35
+ export declare function codexThreadLockPath(threadId: string, env: NodeJS.ProcessEnv): string;
36
+ export declare function codexThreadLockDirectory(env: NodeJS.ProcessEnv): string;
37
+ export type CodexResumeReadiness = {
38
+ state: 'ready';
39
+ lockDirectory: string;
40
+ } | {
41
+ state: 'unavailable';
42
+ reason: string;
43
+ };
44
+ /**
45
+ * Whether a Codex thread whose Stop hook has already returned could still be
46
+ * cold-resumed, decided without taking any lock or spawning anything.
47
+ *
48
+ * Two things have to hold: this platform must implement the non-blocking
49
+ * `flock` the probe is built on, and `$CODEX_HOME` must actually have a
50
+ * thread-writer-lock directory — its absence is not evidence that a thread is
51
+ * unowned, so the gate fails closed and the answer waits for the next turn.
52
+ * Neither affects the ordinary path, where the hook's own stdout continues the
53
+ * held turn.
54
+ */
55
+ export declare function inspectCodexResume(env: NodeJS.ProcessEnv, options: {
56
+ platform: NodeJS.Platform;
57
+ directoryExists: (directory: string) => boolean;
58
+ }): CodexResumeReadiness;
59
+ /**
60
+ * Codex's answer-delivery route: the blocking Stop hook, then nothing else.
61
+ *
62
+ * The default is the hook continuation itself. While the Codex process that
63
+ * invoked this hook is alive it is reading this process's stdout, and
64
+ * `{"decision":"block"}` there creates a real new user turn — no launch
65
+ * ownership, no control plane, no probe required. That path must never depend
66
+ * on the lock probe: printing to a dead pipe cannot ghost-write anything, so
67
+ * an unreadable `$CODEX_HOME` is not a reason to withhold a continuation.
68
+ *
69
+ * Only when that process is gone does the answer need another last meter, and
70
+ * then exactly one is safe: a cold `codex exec resume` of a thread no live
71
+ * writer owns. Anything else — a live writer, an unprobeable platform, a thread
72
+ * id we cannot name — is journaled and replayed at the session's next Stop.
73
+ * That accepted gap is the honest floor of the Codex adapter: a session that
74
+ * went idle after its Stop returned, which Notifai did not launch, cannot be
75
+ * woken in place.
76
+ */
77
+ export declare function codexWakeRoute(options: {
78
+ threadId: string;
79
+ cwd: string;
80
+ sourcePid: number;
81
+ env?: NodeJS.ProcessEnv;
82
+ adapters?: CodexWakeAdapters;
83
+ }): EscalationDeliveryRoute;
84
+ export declare function systemCodexWakeAdapters(env?: NodeJS.ProcessEnv): CodexWakeAdapters;