@raidiant/notifai 10.1.7 → 11.0.2

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.
Files changed (154) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +23 -13
  3. package/dist/claude-wake.d.ts +1 -2
  4. package/dist/claude-wake.js +15 -61
  5. package/dist/claude-wake.js.map +1 -1
  6. package/dist/cli-bin.js +3 -14
  7. package/dist/cli-bin.js.map +1 -1
  8. package/dist/cli-contract.d.ts +12 -0
  9. package/dist/cli-contract.js +19 -0
  10. package/dist/cli-contract.js.map +1 -0
  11. package/dist/cli-release.d.ts +0 -1
  12. package/dist/cli-release.js +5 -21
  13. package/dist/cli-release.js.map +1 -1
  14. package/dist/client.d.ts +2 -2
  15. package/dist/codex-wake.d.ts +1 -1
  16. package/dist/codex-wake.js +8 -36
  17. package/dist/codex-wake.js.map +1 -1
  18. package/dist/command-session.js +2 -1
  19. package/dist/command-session.js.map +1 -1
  20. package/dist/commands-acknowledge.d.ts +13 -0
  21. package/dist/commands-acknowledge.js +67 -0
  22. package/dist/commands-acknowledge.js.map +1 -0
  23. package/dist/commands-ask.d.ts +63 -0
  24. package/dist/commands-ask.js +407 -0
  25. package/dist/commands-ask.js.map +1 -0
  26. package/dist/commands-close.d.ts +6 -0
  27. package/dist/commands-close.js +197 -0
  28. package/dist/commands-close.js.map +1 -0
  29. package/dist/commands-config.js +2 -2
  30. package/dist/commands-config.js.map +1 -1
  31. package/dist/commands-core.js +2 -2
  32. package/dist/commands-core.js.map +1 -1
  33. package/dist/commands-doctor.js +61 -120
  34. package/dist/commands-doctor.js.map +1 -1
  35. package/dist/commands-harness-context.d.ts +0 -1
  36. package/dist/commands-harness-context.js +2 -4
  37. package/dist/commands-harness-context.js.map +1 -1
  38. package/dist/commands-hook-diagnostics.d.ts +27 -0
  39. package/dist/commands-hook-diagnostics.js +97 -0
  40. package/dist/commands-hook-diagnostics.js.map +1 -0
  41. package/dist/commands-hook-install.d.ts +26 -0
  42. package/dist/commands-hook-install.js +551 -0
  43. package/dist/commands-hook-install.js.map +1 -0
  44. package/dist/commands-hook-run.d.ts +29 -0
  45. package/dist/commands-hook-run.js +517 -0
  46. package/dist/commands-hook-run.js.map +1 -0
  47. package/dist/commands-init.d.ts +2 -7
  48. package/dist/commands-init.js +59 -92
  49. package/dist/commands-init.js.map +1 -1
  50. package/dist/commands-send.js +35 -3
  51. package/dist/commands-send.js.map +1 -1
  52. package/dist/commands-skill.js +5 -5
  53. package/dist/commands-skill.js.map +1 -1
  54. package/dist/commands-update.js +17 -31
  55. package/dist/commands-update.js.map +1 -1
  56. package/dist/commands.d.ts +11 -6
  57. package/dist/commands.js +9 -4
  58. package/dist/commands.js.map +1 -1
  59. package/dist/config.d.ts +14 -4
  60. package/dist/config.js +35 -9
  61. package/dist/config.js.map +1 -1
  62. package/dist/file-lock.d.ts +3 -0
  63. package/dist/file-lock.js +33 -17
  64. package/dist/file-lock.js.map +1 -1
  65. package/dist/guidance-content.js +30 -15
  66. package/dist/guidance-content.js.map +1 -1
  67. package/dist/hook-acknowledgements.d.ts +42 -0
  68. package/dist/hook-acknowledgements.js +316 -0
  69. package/dist/hook-acknowledgements.js.map +1 -0
  70. package/dist/hook-events.d.ts +6 -0
  71. package/dist/hook-events.js +22 -0
  72. package/dist/hook-events.js.map +1 -0
  73. package/dist/hook-gates.d.ts +7 -0
  74. package/dist/hook-gates.js +21 -0
  75. package/dist/hook-gates.js.map +1 -0
  76. package/dist/hook-lifecycle.d.ts +93 -0
  77. package/dist/{hooks.js → hook-lifecycle.js} +61 -1359
  78. package/dist/hook-lifecycle.js.map +1 -0
  79. package/dist/hook-project-sessions.d.ts +28 -0
  80. package/dist/hook-project-sessions.js +141 -0
  81. package/dist/hook-project-sessions.js.map +1 -0
  82. package/dist/hook-question-lock.d.ts +7 -0
  83. package/dist/hook-question-lock.js +173 -0
  84. package/dist/hook-question-lock.js.map +1 -0
  85. package/dist/hook-question-retirement.d.ts +57 -0
  86. package/dist/hook-question-retirement.js +261 -0
  87. package/dist/hook-question-retirement.js.map +1 -0
  88. package/dist/hook-question-state.d.ts +45 -0
  89. package/dist/hook-question-state.js +196 -0
  90. package/dist/hook-question-state.js.map +1 -0
  91. package/dist/hook-session-state.d.ts +31 -0
  92. package/dist/hook-session-state.js +249 -0
  93. package/dist/hook-session-state.js.map +1 -0
  94. package/dist/{hooks.d.ts → hook-types.d.ts} +17 -236
  95. package/dist/hook-types.js +4 -0
  96. package/dist/hook-types.js.map +1 -0
  97. package/dist/install-hooks.d.ts +75 -60
  98. package/dist/install-hooks.js +299 -209
  99. package/dist/install-hooks.js.map +1 -1
  100. package/dist/interactive.d.ts +3 -16
  101. package/dist/interactive.js +19 -95
  102. package/dist/interactive.js.map +1 -1
  103. package/dist/local-path.d.ts +7 -0
  104. package/dist/local-path.js +27 -0
  105. package/dist/local-path.js.map +1 -0
  106. package/dist/node-floor.js +3 -10
  107. package/dist/node-floor.js.map +1 -1
  108. package/dist/npm-invocation.d.ts +34 -0
  109. package/dist/npm-invocation.js +53 -0
  110. package/dist/npm-invocation.js.map +1 -0
  111. package/dist/openclaw-plugin.d.ts +12 -3
  112. package/dist/openclaw-plugin.js +42 -16
  113. package/dist/openclaw-plugin.js.map +1 -1
  114. package/dist/opencode-plugin.d.ts +2 -2
  115. package/dist/opencode-plugin.js +4 -6
  116. package/dist/opencode-plugin.js.map +1 -1
  117. package/dist/program.js +11 -13
  118. package/dist/program.js.map +1 -1
  119. package/dist/project-enablement.d.ts +6 -0
  120. package/dist/project-enablement.js +11 -27
  121. package/dist/project-enablement.js.map +1 -1
  122. package/dist/question-settlement-process.d.ts +1 -1
  123. package/dist/readiness.d.ts +0 -2
  124. package/dist/readiness.js +0 -4
  125. package/dist/readiness.js.map +1 -1
  126. package/dist/send.d.ts +8 -4
  127. package/dist/send.js +145 -26
  128. package/dist/send.js.map +1 -1
  129. package/dist/session-activation.d.ts +3 -1
  130. package/dist/session-activation.js +16 -0
  131. package/dist/session-activation.js.map +1 -1
  132. package/dist/skill-source/manifest.json +4 -4
  133. package/dist/skill-source/notifai/SKILL.md +60 -60
  134. package/dist/skill-source/notifai/references/harness-setup.md +42 -16
  135. package/dist/ui/config-view.d.ts +0 -2
  136. package/dist/ui/config-view.js +1 -5
  137. package/dist/ui/config-view.js.map +1 -1
  138. package/dist/ui/theme.d.ts +0 -3
  139. package/dist/ui/theme.js +0 -1
  140. package/dist/ui/theme.js.map +1 -1
  141. package/dist/version.d.ts +22 -0
  142. package/dist/version.js +51 -0
  143. package/dist/version.js.map +1 -0
  144. package/dist/wake-support.d.ts +8 -0
  145. package/dist/wake-support.js +38 -0
  146. package/dist/wake-support.js.map +1 -0
  147. package/package.json +2 -2
  148. package/dist/cli-update-contract.d.ts +0 -7
  149. package/dist/cli-update-contract.js +0 -10
  150. package/dist/cli-update-contract.js.map +0 -1
  151. package/dist/commands-hooks.d.ts +0 -160
  152. package/dist/commands-hooks.js +0 -1800
  153. package/dist/commands-hooks.js.map +0 -1
  154. package/dist/hooks.js.map +0 -1
@@ -0,0 +1,517 @@
1
+ /** Fail-open CLI adapter from harness input to hook lifecycle handlers. */
2
+ import { claudeWakeRoute } from './claude-wake.js';
3
+ import { ApiCallError } from './client.js';
4
+ import { codexWakeRoute } from './codex-wake.js';
5
+ import { EXIT, SETUP_COMMAND, diagnoseIgnoredOriginOverride, log, makeClient, rejectedPaths, } from './commands-core.js';
6
+ import { claudeSessionPid } from './commands-harness-context.js';
7
+ import { waitForReply } from './commands-send-support.js';
8
+ import { loadConfig } from './config.js';
9
+ import { questionRoutingCapability } from './harnesses.js';
10
+ import { HOOK_EVENTS } from './hook-events.js';
11
+ import { handleSessionEnd, handleStop, handleUserPromptSubmit, parseHookInput, } from './hook-lifecycle.js';
12
+ import { claimCursorStopActivation, confirmCursorStopActivation, pruneAbandonedSessions, readSessionState, recordSessionStart, resetCursorStopActivation, } from './hook-session-state.js';
13
+ import {} from './hook-types.js';
14
+ import { codexStopDefinitionFingerprint, findInstallations } from './install-hooks.js';
15
+ import { logConfigResolved, logSettingsFrom } from './logging.js';
16
+ import { projectBinding, projectEnabled } from './project-enablement.js';
17
+ import { spawnQuestionSettlement } from './question-settlement-process.js';
18
+ import { QUESTION_WAITER_CEILING_SECONDS } from './question-timing.js';
19
+ import { cursorStopActivationOutput, sessionActivationOutput } from './session-activation.js';
20
+ const INTERNAL_HOOK_EVENTS = ['question-settlement'];
21
+ /** SessionEnd cleanup must precede every diagnostic that can wait on a file lock. */
22
+ export function hookDefersDiagnosticsUntilAfterCleanup(event) {
23
+ return event === 'session-end';
24
+ }
25
+ /**
26
+ * Runs one harness hook. Contract with every harness: hook JSON arrives on
27
+ * stdin, harness output (if any) goes to stdout, diagnostics go to stderr, and
28
+ * exit 0 with no stdout means "no decision or added context — carry on as normal".
29
+ *
30
+ * Every failure path in here must reach that no-decision state. A hook that
31
+ * throws, or that blocks past the harness's timeout, degrades the agent for a
32
+ * feature the user only asked to make it more convenient.
33
+ */
34
+ export async function hookRunCommand(deps, event, readStdin, harness) {
35
+ if (!HOOK_EVENTS.includes(event) &&
36
+ !INTERNAL_HOOK_EVENTS.includes(event)) {
37
+ deps.io.err(`Unknown hook event "${event}". Valid: ${HOOK_EVENTS.join(', ')}`);
38
+ return EXIT.usage;
39
+ }
40
+ // One clock owns the complete Stop invocation, including stdin, config,
41
+ // credentials, and client construction. Starting this inside `handleStop`
42
+ // would grant slow setup a second budget and let the harness kill us before
43
+ // an accepted answer is journaled or written to stdout.
44
+ const now = deps.now ?? Date.now;
45
+ // One owner lifetime covers startup and the longest answer window. Claude
46
+ // runs it detached; Codex holds the turn. The delivery mechanism does not
47
+ // change how long the exact Agent Session remains reachable.
48
+ const processDeadlineAt = now() + QUESTION_WAITER_CEILING_SECONDS * 1000;
49
+ const logger = log(deps);
50
+ logger.bind({ cmd: `hook ${event}` });
51
+ let started = false;
52
+ const start = (data = {}) => {
53
+ if (started)
54
+ return;
55
+ started = true;
56
+ logger.info('hook.start', { hook: event, harness: harness ?? 'unknown', ...data });
57
+ };
58
+ const failureData = (err) => err instanceof ApiCallError
59
+ ? { status: err.status, code: err.code, message: err.message, details: err.details }
60
+ : { message: err instanceof Error ? err.message : String(err) };
61
+ // Cursor may load ~/.claude/settings.json in addition to its own native
62
+ // hooks. Cursor guarantees CURSOR_PROJECT_DIR to hook processes, so a Claude
63
+ // compatibility copy becomes a no-op and the native Cursor definition is
64
+ // the single owner. Real Claude hooks do not receive that hook-only marker.
65
+ if (harness === 'claude-code' && deps.env['CURSOR_PROJECT_DIR']) {
66
+ start({ outcome: 'cursor-compatibility-copy-skipped' });
67
+ logger.info('hook.end', {
68
+ hook: event,
69
+ outcome: 'ignored',
70
+ reason: 'cursor-native-handler-owns-event',
71
+ decided: false,
72
+ });
73
+ return EXIT.ok;
74
+ }
75
+ let raw;
76
+ try {
77
+ raw = await readStdin();
78
+ }
79
+ catch (err) {
80
+ start({ input: 'unavailable' });
81
+ logger.error('hook.end', {
82
+ hook: event,
83
+ outcome: 'ignored',
84
+ reason: 'input-read-failed',
85
+ ...failureData(err),
86
+ });
87
+ return EXIT.ok;
88
+ }
89
+ if (raw.trim() !== '') {
90
+ try {
91
+ const parsed = JSON.parse(raw);
92
+ if (typeof parsed !== 'object' || parsed === null)
93
+ throw new Error('not an object');
94
+ }
95
+ catch {
96
+ start({ input: 'malformed' });
97
+ logger.error('hook.end', { hook: event, outcome: 'ignored', reason: 'malformed-input' });
98
+ deps.io.err('notifai: ignored malformed or truncated hook input; no routing action was taken');
99
+ return EXIT.ok;
100
+ }
101
+ }
102
+ let envelope = parseHookInput(raw);
103
+ if (harness === 'cursor') {
104
+ const sessionId = envelope.session_id ?? envelope.conversation_id;
105
+ const cwd = envelope.cwd ?? envelope.workspace_roots?.[0];
106
+ envelope = {
107
+ ...envelope,
108
+ ...(sessionId === undefined ? {} : { session_id: sessionId }),
109
+ ...(cwd === undefined ? {} : { cwd }),
110
+ stop_hook_active: envelope.stop_hook_active ??
111
+ (typeof envelope.loop_count === 'number' && envelope.loop_count > 0),
112
+ };
113
+ }
114
+ const cwd = envelope.cwd ?? deps.cwd;
115
+ const sessionEnd = hookDefersDiagnosticsUntilAfterCleanup(event);
116
+ logger.bind({ session: envelope.session_id ?? null });
117
+ const lifecycleEnabled = () => {
118
+ try {
119
+ const activationConfig = loadConfig({ cwd, env: deps.env, sessionId: envelope.session_id });
120
+ return projectEnabled(projectBinding(cwd, deps.env, activationConfig.project.value));
121
+ }
122
+ catch (err) {
123
+ logger.error('hook.end', { hook: event, outcome: 'enablement-unavailable', ...failureData(err) });
124
+ return false;
125
+ }
126
+ };
127
+ // Installation only makes lifecycle hooks available. Model-visible
128
+ // activation is a separate User-owned Project decision, checked anew on
129
+ // every run so disabling takes effect without reinstalling anything.
130
+ if (event === 'session-start' || event === 'subagent-start') {
131
+ start({ cwd, source: envelope.source ?? null });
132
+ if (!lifecycleEnabled()) {
133
+ logger.info('hook.end', {
134
+ hook: event,
135
+ outcome: 'ignored',
136
+ reason: 'project-disabled',
137
+ decided: false,
138
+ });
139
+ return EXIT.ok;
140
+ }
141
+ if (event === 'session-start' && harness === 'cursor' && envelope.session_id !== undefined) {
142
+ try {
143
+ resetCursorStopActivation(envelope.session_id, deps.env);
144
+ }
145
+ catch (err) {
146
+ logger.error('hook.end', {
147
+ hook: event,
148
+ outcome: 'reset-failed',
149
+ ...failureData(err),
150
+ });
151
+ }
152
+ }
153
+ const stdout = sessionActivationOutput(harness, event === 'session-start' ? 'SessionStart' : 'SubagentStart', cwd, deps.env);
154
+ if (stdout !== undefined)
155
+ deps.io.out(stdout);
156
+ if (event === 'session-start' && envelope.session_id !== undefined) {
157
+ try {
158
+ const stopFingerprint = harness === 'codex'
159
+ ? codexStopDefinitionFingerprint(findInstallations(deps.env, deps.hookAdapterHome, deps.hookPlatform))
160
+ : undefined;
161
+ recordSessionStart(envelope.session_id, deps.env, harness, cwd, stopFingerprint);
162
+ }
163
+ catch (err) {
164
+ logger.error('hook.end', {
165
+ hook: event,
166
+ outcome: 'record-failed',
167
+ reason: 'session-state-failed',
168
+ ...failureData(err),
169
+ });
170
+ }
171
+ }
172
+ logger.info('hook.end', {
173
+ hook: event,
174
+ outcome: stdout === undefined ? 'unsupported-harness' : 'context-added',
175
+ decided: false,
176
+ });
177
+ return EXIT.ok;
178
+ }
179
+ // Cursor has a confirmed host bug in which sessionStart.additional_context
180
+ // is accepted but never reaches the model. A native Stop follow-up is the
181
+ // host's guaranteed model-visible channel. Claim it once per conversation,
182
+ // before config/auth/network, and leave the ordinary Stop handler separate
183
+ // so question delivery is never displaced by activation.
184
+ if (event === 'activation-stop') {
185
+ start({ cwd, stop_hook_active: envelope.stop_hook_active ?? null });
186
+ if (harness !== 'cursor') {
187
+ logger.info('hook.end', { hook: event, outcome: 'unsupported-harness', decided: false });
188
+ return EXIT.ok;
189
+ }
190
+ if (!lifecycleEnabled()) {
191
+ logger.info('hook.end', {
192
+ hook: event,
193
+ outcome: 'ignored',
194
+ reason: 'project-disabled',
195
+ decided: false,
196
+ });
197
+ return EXIT.ok;
198
+ }
199
+ if (envelope.status === 'aborted') {
200
+ logger.info('hook.end', {
201
+ hook: event,
202
+ outcome: 'ignored',
203
+ reason: `turn-${envelope.status}`,
204
+ decided: false,
205
+ });
206
+ return EXIT.ok;
207
+ }
208
+ if (envelope.session_id === undefined) {
209
+ logger.info('hook.end', {
210
+ hook: event,
211
+ outcome: 'ignored',
212
+ reason: 'missing-conversation-id',
213
+ decided: false,
214
+ });
215
+ return EXIT.ok;
216
+ }
217
+ if (envelope.session_id !== undefined &&
218
+ typeof envelope.loop_count === 'number' &&
219
+ envelope.loop_count > 0) {
220
+ let activationOwned = false;
221
+ try {
222
+ activationOwned = confirmCursorStopActivation(envelope.session_id, deps.env, now());
223
+ }
224
+ catch (err) {
225
+ logger.error('hook.end', {
226
+ hook: event,
227
+ outcome: 'confirm-failed',
228
+ ...failureData(err),
229
+ });
230
+ }
231
+ if (activationOwned) {
232
+ logger.info('hook.end', { hook: event, outcome: 'confirmed', decided: false });
233
+ return EXIT.ok;
234
+ }
235
+ }
236
+ const cursorState = readSessionState(envelope.session_id, deps.env);
237
+ if ((cursorState.pending?.length ?? 0) > 0 ||
238
+ cursorState.accepted !== undefined ||
239
+ (cursorState.acknowledgement_due?.length ?? 0) > 0) {
240
+ logger.info('hook.end', {
241
+ hook: event,
242
+ outcome: 'deferred',
243
+ reason: 'question-continuation-owns-stop',
244
+ decided: false,
245
+ });
246
+ return EXIT.ok;
247
+ }
248
+ let claimed = false;
249
+ try {
250
+ claimed = claimCursorStopActivation(envelope.session_id, deps.env, now());
251
+ }
252
+ catch (err) {
253
+ logger.error('hook.end', {
254
+ hook: event,
255
+ outcome: 'claim-failed',
256
+ ...failureData(err),
257
+ });
258
+ }
259
+ logger.info('hook.end', {
260
+ hook: event,
261
+ outcome: claimed ? 'followup-added' : 'already-activated',
262
+ decided: claimed,
263
+ });
264
+ if (claimed)
265
+ deps.io.out(cursorStopActivationOutput(cwd, deps.env));
266
+ return EXIT.ok;
267
+ }
268
+ let config = null;
269
+ let configFailure;
270
+ try {
271
+ config = loadConfig({ cwd, env: deps.env, sessionId: envelope.session_id });
272
+ // The hook's project is the session's, not this process's, and the log
273
+ // settings that apply are that project's too. Keeping a mutable bootstrap
274
+ // logger lets this more-specific layer turn logging back on.
275
+ logger.adopt(logSettingsFrom(config));
276
+ logger.bind({ project: config.project.value });
277
+ if (!sessionEnd) {
278
+ start({ cwd, stop_hook_active: envelope.stop_hook_active ?? null });
279
+ logConfigResolved(logger, config);
280
+ }
281
+ }
282
+ catch (err) {
283
+ configFailure = err;
284
+ if (!sessionEnd) {
285
+ start({ cwd, stop_hook_active: envelope.stop_hook_active ?? null });
286
+ logger.error('hook.end', {
287
+ hook: event,
288
+ outcome: 'failed',
289
+ reason: 'config-failed',
290
+ ...failureData(err),
291
+ });
292
+ for (const line of describeHookFailure(err))
293
+ deps.io.err(`notifai: ${line}`);
294
+ return EXIT.ok;
295
+ }
296
+ }
297
+ // Everything below is inside one fail-open boundary. Credential loading,
298
+ // client construction and hook handling can all throw, and a hook that exits
299
+ // non-zero makes the harness report a failure — strictly worse than skipping.
300
+ try {
301
+ if (sessionEnd) {
302
+ // Codex gives SessionEnd one second total. Do every durable cleanup write
303
+ // before lifecycle diagnostics: the log lock is deliberately allowed to
304
+ // wait that long, and a busy log must never preserve ended-session state
305
+ // or its inherited configuration. The resolved config above is retained
306
+ // in memory so logging still uses the ending session's settings afterwards.
307
+ const outcome = handleSessionEnd(deps.env, envelope, (deps.now ?? Date.now)());
308
+ start({ cwd, stop_hook_active: envelope.stop_hook_active ?? null });
309
+ if (config !== null)
310
+ logConfigResolved(logger, config);
311
+ const data = { hook: event, decided: false, ...outcome.log };
312
+ if (configFailure === undefined)
313
+ logger.info('hook.end', data);
314
+ else {
315
+ logger.error('hook.end', {
316
+ ...data,
317
+ reason: 'config-failed',
318
+ config_error: failureData(configFailure),
319
+ });
320
+ }
321
+ for (const note of outcome.notes)
322
+ deps.io.err(`notifai: ${note}`);
323
+ return EXIT.ok;
324
+ }
325
+ // Non-SessionEnd hooks cannot reach here without resolved configuration.
326
+ const resolved = config;
327
+ const credential = deps.store.load();
328
+ if (!credential) {
329
+ logger.error('hook.end', { hook: event, outcome: 'not-paired' });
330
+ deps.io.err(`notifai: hook skipped: this machine is not paired; run \`${SETUP_COMMAND}\``);
331
+ return EXIT.ok;
332
+ }
333
+ // Pin authenticated traffic to the origin the credential was issued for. A
334
+ // repository can commit `.notifai/config.toml`, and honouring a base_url
335
+ // from it would hand this machine's bearer token to whatever host it names.
336
+ const baseUrl = credential.baseUrl;
337
+ diagnoseIgnoredOriginOverride(deps.io, resolved, credential);
338
+ // UserPromptSubmit runs in front of the user's own prompt under a 15s
339
+ // harness ceiling and can make two calls, so each gets a small slice of it;
340
+ // Stop is allowed to block and keeps the ordinary budget.
341
+ const client = makeClient(deps, baseUrl, `Bearer nfm_${credential.machineId}.${credential.secret}`, {
342
+ timeoutMs: event === 'user-prompt-submit' ? 4_000 : 20_000,
343
+ ...(event === 'stop' || event === 'question-settlement'
344
+ ? { deadlineAt: processDeadlineAt, now }
345
+ : {}),
346
+ });
347
+ const ctx = {
348
+ client,
349
+ config: resolved,
350
+ env: deps.env,
351
+ now,
352
+ sleep: deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
353
+ waitForFirstReply: async (requestId, timeoutSeconds) => {
354
+ const result = await waitForReply(client, requestId, {
355
+ timeoutSeconds,
356
+ afterSeq: 0,
357
+ now: deps.now,
358
+ sleep: deps.sleep,
359
+ });
360
+ return {
361
+ replies: result.response.replies,
362
+ timedOut: result.timedOut,
363
+ degraded: result.degraded,
364
+ };
365
+ },
366
+ log: logger,
367
+ ...(harness === undefined ? {} : { harness }),
368
+ };
369
+ // Real clock, deliberately, not `deps.now`. This compares against file
370
+ // mtimes, which are wall-clock facts — handing it a virtual or skewed clock
371
+ // would have it delete live session state as "abandoned".
372
+ // Daily state pruning is housekeeping, not part of the Stop delivery
373
+ // contract. Its directory scan has no useful bound, so keep it on the
374
+ // short prompt path and never spend the answer owner's finite budget on it.
375
+ if (event !== 'stop' && event !== 'question-settlement') {
376
+ pruneAbandonedSessions(deps.env);
377
+ }
378
+ let outcome;
379
+ if (event === 'user-prompt-submit') {
380
+ outcome = await handleUserPromptSubmit(ctx, envelope);
381
+ if (outcome.settlementRequired === true &&
382
+ envelope.session_id !== undefined &&
383
+ harness !== undefined &&
384
+ questionRoutingCapability(harness, deps.hookPlatform ?? process.platform)
385
+ .stopContinuation !== 'unsupported') {
386
+ try {
387
+ const launchSettlement = deps.spawnQuestionSettlement ?? spawnQuestionSettlement;
388
+ launchSettlement({
389
+ envelope: { session_id: envelope.session_id, cwd },
390
+ harness,
391
+ });
392
+ outcome.log = { ...outcome.log, settlement: 'launched' };
393
+ }
394
+ catch (err) {
395
+ outcome.log = {
396
+ ...outcome.log,
397
+ settlement: 'launch-failed',
398
+ settlement_error: failureData(err),
399
+ };
400
+ }
401
+ }
402
+ }
403
+ else {
404
+ outcome = await handleStop(ctx, envelope, processDeadlineAt, stopWakeRoute(deps, harness, envelope.session_id, cwd, event === 'stop'), event === 'stop');
405
+ }
406
+ // Answer diagnostics are already persisted once as hook.answer. Keep every
407
+ // other note in the lifecycle record without duplicating the user's text.
408
+ const notes = outcome.notes.filter((note) => !/^(?:late )?answer from /.test(note));
409
+ logger.info('hook.end', {
410
+ hook: event,
411
+ decided: outcome.decided ?? outcome.stdout !== undefined,
412
+ ...(notes.length === 0 ? {} : { notes }),
413
+ ...outcome.log,
414
+ });
415
+ for (const note of outcome.notes)
416
+ deps.io.err(`notifai: ${note}`);
417
+ if (outcome.stdout !== undefined) {
418
+ // No work, await, or diagnostic may sit between this cross-process
419
+ // SessionEnd fence and the irreversible harness stdout write.
420
+ if (outcome.commitStdout === undefined || outcome.commitStdout()) {
421
+ deps.io.out(outcome.stdout);
422
+ }
423
+ else {
424
+ deps.io.err('notifai: the Agent Session ended before answer delivery; no continuation was written');
425
+ }
426
+ }
427
+ return EXIT.ok;
428
+ }
429
+ catch (err) {
430
+ // SessionEnd defers its start record until after cleanup; if cleanup itself
431
+ // fails, begin the after-the-fact lifecycle here before recording why.
432
+ if (sessionEnd)
433
+ start({ cwd, stop_hook_active: envelope.stop_hook_active ?? null });
434
+ // The hook still exits 0 — handing the terminal back is always right. What
435
+ // this adds is that the reason survives, including the server's own words.
436
+ logger.error('hook.end', {
437
+ hook: event,
438
+ outcome: 'failed',
439
+ reason: 'execution-failed',
440
+ ...failureData(err),
441
+ });
442
+ for (const line of describeHookFailure(err))
443
+ deps.io.err(`notifai: ${line}`);
444
+ return EXIT.ok;
445
+ }
446
+ }
447
+ /**
448
+ * The last meter for an answer this Stop hook accepted, chosen by harness.
449
+ *
450
+ * Both wake adapters need the harness process that invoked this hook: Claude's
451
+ * to prove exact own-child session ownership before it posts to the inbox
452
+ * socket, Codex's to know whether its own stdout is still a live continuation
453
+ * channel. Without an exact session id neither can prove anything, so the
454
+ * waiter falls back to the plain blocking Stop continuation.
455
+ */
456
+ function stopWakeRoute(deps, harness, sessionId, cwd, continuationActive = true) {
457
+ if (sessionId === undefined)
458
+ return undefined;
459
+ const declaredSourcePid = declaredHookSourcePid(deps);
460
+ if (harness === 'claude-code') {
461
+ if ((deps.hookPlatform ?? process.platform) === 'win32')
462
+ return undefined;
463
+ return claudeWakeRoute({
464
+ sessionId,
465
+ cwd,
466
+ sourcePid: deps.claudeSourcePid ?? declaredSourcePid ?? claudeSessionPid(deps.env),
467
+ ...(deps.claudeWake === undefined ? {} : { adapters: deps.claudeWake }),
468
+ });
469
+ }
470
+ if (harness === 'codex') {
471
+ return codexWakeRoute({
472
+ threadId: sessionId,
473
+ cwd,
474
+ sourcePid: deps.codexSourcePid ?? declaredSourcePid ?? process.ppid,
475
+ env: deps.env,
476
+ ...(deps.codexWake === undefined ? {} : { adapters: deps.codexWake }),
477
+ continuationActive,
478
+ });
479
+ }
480
+ return undefined;
481
+ }
482
+ /** Stable harness parent propagated by the managed adapter across child tools. */
483
+ function declaredHookSourcePid(deps) {
484
+ const value = Number(deps.env['NOTIFAI_HOOK_SOURCE_PID']);
485
+ return Number.isInteger(value) && value > 0 ? value : undefined;
486
+ }
487
+ /**
488
+ * What went wrong, in terms of what to do about it.
489
+ *
490
+ * On 2026-08-03 a contract change shipped without the server deploy that goes
491
+ * with it. The CLI stamped `lifecycle` on every question draft, the deployed
492
+ * server rejected the unknown field, and escalation stopped working entirely —
493
+ * announced as "hook failed, deferring to the terminal", which reads like a
494
+ * flaky network. The information needed to diagnose it in one second was
495
+ * already in hand: a 422 whose details name the offending path. It was being
496
+ * thrown away by `String(err)`.
497
+ *
498
+ * A hook still exits 0 whatever this says. Handing the terminal back is always
499
+ * right; the only question is whether the user is told anything they can use.
500
+ */
501
+ export function describeHookFailure(err) {
502
+ if (!(err instanceof ApiCallError)) {
503
+ return [`hook failed, deferring to the terminal (${String(err)})`];
504
+ }
505
+ const lines = [`hook failed, deferring to the terminal (${err.code}: ${err.message})`];
506
+ const paths = rejectedPaths(err.details);
507
+ if (paths.length > 0)
508
+ lines.push(`the server rejected: ${paths.join(', ')}`);
509
+ // A 422 on a draft this CLI built is not a user error — this CLI's own
510
+ // contract produced it. Either the server is behind, or the two disagree.
511
+ if (err.status === 422) {
512
+ lines.push('this build sent a field the server did not accept, which usually means the server ' +
513
+ 'is older than this CLI — check with `notifai doctor`');
514
+ }
515
+ return lines;
516
+ }
517
+ //# sourceMappingURL=commands-hook-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-hook-run.js","sourceRoot":"","sources":["../src/commands-hook-run.ts"],"names":[],"mappings":"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"}
@@ -2,8 +2,6 @@ import { type SkillScope } from './native-skills.js';
2
2
  import { type CommandDeps } from './commands-core.js';
3
3
  /** Derive a contract-valid project slug; init alone needs a non-empty fallback. */
4
4
  export declare function projectSlugFrom(name: string): string;
5
- /** Project checkout vs this machine. Drives skill, hooks, and config together. */
6
- export type SetupScope = SkillScope;
7
5
  export interface InitFlags {
8
6
  /** Emit the final shared readiness model and never prompt. */
9
7
  json?: boolean;
@@ -16,12 +14,9 @@ export interface InitFlags {
16
14
  */
17
15
  skills?: boolean;
18
16
  /**
19
- * One setup-scope for skill, hooks, and config. The unattended answer to
20
- * init's single project-vs-machine question. Pairing, devices, and the CLI
21
- * binary are not this flag.
17
+ * Where the agent guidance skill is installed. `npx skills` owns this
18
+ * choice; lifecycle wiring has no scope of its own and never reads it.
22
19
  */
23
- setupScope?: SetupScope;
24
- /** Alias of `--setup-scope` when installing the skill unattended. */
25
20
  skillsScope?: SkillScope;
26
21
  /** Same tri-state, for the harness hooks. */
27
22
  hooks?: boolean;