@raidiant/notifai 1.0.1 → 2.0.0

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 (63) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +17 -7
  3. package/dist/client.d.ts +5 -1
  4. package/dist/client.js +2 -0
  5. package/dist/client.js.map +1 -1
  6. package/dist/commands.d.ts +10 -1
  7. package/dist/commands.js +151 -54
  8. package/dist/commands.js.map +1 -1
  9. package/dist/config.d.ts +2 -2
  10. package/dist/config.js +5 -9
  11. package/dist/config.js.map +1 -1
  12. package/dist/credentials.d.ts +54 -3
  13. package/dist/credentials.js +237 -18
  14. package/dist/credentials.js.map +1 -1
  15. package/dist/file-lock.js +15 -6
  16. package/dist/file-lock.js.map +1 -1
  17. package/dist/hook-adapter.d.ts +6 -2
  18. package/dist/hook-adapter.js +110 -29
  19. package/dist/hook-adapter.js.map +1 -1
  20. package/dist/hooks.d.ts +15 -1
  21. package/dist/hooks.js +183 -12
  22. package/dist/hooks.js.map +1 -1
  23. package/dist/install-hooks.d.ts +50 -21
  24. package/dist/install-hooks.js +141 -57
  25. package/dist/install-hooks.js.map +1 -1
  26. package/dist/logging.d.ts +1 -1
  27. package/dist/logging.js +4 -0
  28. package/dist/logging.js.map +1 -1
  29. package/dist/main.js +14 -3
  30. package/dist/main.js.map +1 -1
  31. package/dist/native-skills.js +5 -10
  32. package/dist/native-skills.js.map +1 -1
  33. package/dist/opencode-plugin.d.ts +7 -2
  34. package/dist/opencode-plugin.js +142 -4
  35. package/dist/opencode-plugin.js.map +1 -1
  36. package/dist/platform.d.ts +73 -0
  37. package/dist/platform.js +143 -0
  38. package/dist/platform.js.map +1 -0
  39. package/dist/ui/config-view.js +5 -1
  40. package/dist/ui/config-view.js.map +1 -1
  41. package/package.json +11 -10
  42. package/src/client.test.ts +53 -0
  43. package/src/client.ts +24 -0
  44. package/src/commands.test.ts +351 -30
  45. package/src/commands.ts +207 -49
  46. package/src/config.ts +11 -9
  47. package/src/credentials.test.ts +291 -0
  48. package/src/credentials.ts +274 -17
  49. package/src/file-lock.ts +34 -9
  50. package/src/hook-adapter.test.ts +136 -0
  51. package/src/hook-adapter.ts +120 -28
  52. package/src/hooks.test.ts +175 -1
  53. package/src/hooks.ts +241 -12
  54. package/src/install-hooks.test.ts +174 -33
  55. package/src/install-hooks.ts +186 -54
  56. package/src/logging.ts +4 -0
  57. package/src/main.ts +17 -2
  58. package/src/native-skills.ts +5 -10
  59. package/src/opencode-plugin.ts +148 -3
  60. package/src/platform.test.ts +152 -0
  61. package/src/platform.ts +173 -0
  62. package/src/skill.test.ts +32 -1
  63. package/src/ui/config-view.ts +5 -5
@@ -4,10 +4,14 @@ import path from 'node:path';
4
4
  import { atomicWriteFileSync } from './atomic-file.js';
5
5
  import { withTargetFileLock } from './file-lock.js';
6
6
  const ADAPTER_MARKER = '# notifai managed hook adapter';
7
+ const WIN32_ADAPTER_MARKER = '// notifai managed hook adapter';
7
8
  const ADAPTER_VERSION = 1;
8
9
  export function isNpxAdapterTarget(target) {
9
10
  return target.kind === 'npx';
10
11
  }
12
+ export function hookHostPlatform(platform = process.platform) {
13
+ return platform === 'win32' ? 'win32' : 'posix';
14
+ }
11
15
  /**
12
16
  * One user-level identity for every harness and every project/global install.
13
17
  *
@@ -22,17 +26,19 @@ export function hookAdapterPath(homeDir = os.userInfo().homedir) {
22
26
  return path.join(homeDir, '.notifai', 'bin', 'hook-adapter');
23
27
  }
24
28
  /** Install or repair the stable adapter and atomically retarget its implementation. */
25
- export function installHookAdapter(target, homeDir) {
26
- assertUsableTarget(target);
29
+ export function installHookAdapter(target, homeDir, platform = process.platform) {
30
+ const host = hookHostPlatform(platform);
31
+ assertUsableTarget(target, host);
27
32
  const file = hookAdapterPath(homeDir);
28
- ensureManagedDirectories(homeDir ?? os.userInfo().homedir);
29
- const source = hookAdapterSource(target);
33
+ ensureManagedDirectories(homeDir ?? os.userInfo().homedir, host);
34
+ const source = hookAdapterSource(target, host);
30
35
  return withTargetFileLock(file, () => {
31
36
  const existing = existsSync(file) ? readSafeManagedFile(file) : null;
32
- const changed = existing === null || existing.contents !== source || (existing.mode & 0o777) !== 0o700;
37
+ const modeDrift = host === 'posix' && existing !== null && (existing.mode & 0o777) !== 0o700;
38
+ const changed = existing === null || existing.contents !== source || modeDrift;
33
39
  if (changed) {
34
40
  atomicWriteFileSync(file, source, {
35
- mode: 0o700,
41
+ mode: host === 'posix' ? 0o700 : 0o600,
36
42
  preserveMode: false,
37
43
  requireCurrentUserOwner: true,
38
44
  });
@@ -40,7 +46,7 @@ export function installHookAdapter(target, homeDir) {
40
46
  return { path: file, changed };
41
47
  });
42
48
  }
43
- function assertUsableTarget(target) {
49
+ function assertUsableTarget(target, host) {
44
50
  let exec;
45
51
  try {
46
52
  exec = statSync(target.execPath);
@@ -48,7 +54,7 @@ function assertUsableTarget(target) {
48
54
  catch {
49
55
  throw new Error(`Hook adapter runtime ${target.execPath} does not exist.`);
50
56
  }
51
- if (!exec.isFile() || (exec.mode & 0o111) === 0) {
57
+ if (!exec.isFile() || (host === 'posix' && (exec.mode & 0o111) === 0)) {
52
58
  throw new Error(`Hook adapter runtime ${target.execPath} is not executable.`);
53
59
  }
54
60
  if (isNpxAdapterTarget(target)) {
@@ -79,7 +85,8 @@ function assertUsableTarget(target) {
79
85
  }
80
86
  }
81
87
  /** Inspect the shared adapter without executing either it or its registered CLI. */
82
- export function inspectHookAdapter(homeDir) {
88
+ export function inspectHookAdapter(homeDir, platform = process.platform) {
89
+ const host = hookHostPlatform(platform);
83
90
  const file = hookAdapterPath(homeDir);
84
91
  if (!existsSync(file)) {
85
92
  return { path: file, target: null, problems: [`${file} is missing; rerun \`notifai hooks install\``] };
@@ -99,18 +106,24 @@ export function inspectHookAdapter(homeDir) {
99
106
  };
100
107
  }
101
108
  const problems = [];
102
- const uid = typeof process.getuid === 'function' ? process.getuid() : undefined;
103
- if (uid !== undefined && stat.uid !== uid) {
104
- problems.push(`${file} is owned by uid ${stat.uid}, not the current user`);
105
- }
106
- if ((stat.mode & 0o077) !== 0 || (stat.mode & 0o700) !== 0o700) {
107
- problems.push(`${file} permissions are ${(stat.mode & 0o777).toString(8)}, expected 700`);
109
+ if (host === 'posix') {
110
+ const uid = typeof process.getuid === 'function' ? process.getuid() : undefined;
111
+ if (uid !== undefined && stat.uid !== uid) {
112
+ problems.push(`${file} is owned by uid ${stat.uid}, not the current user`);
113
+ }
114
+ if ((stat.mode & 0o077) !== 0 || (stat.mode & 0o700) !== 0o700) {
115
+ problems.push(`${file} permissions are ${(stat.mode & 0o777).toString(8)}, expected 700`);
116
+ }
108
117
  }
109
118
  const contents = readFileSync(file, 'utf8');
110
- if (!contents.startsWith(`#!/bin/sh\n${ADAPTER_MARKER}\n`)) {
119
+ const format = adapterFormat(contents);
120
+ if (format === null) {
111
121
  problems.push(`${file} has no managed adapter marker`);
112
122
  }
113
- const version = Number(/^# adapter-version: (\d+)$/m.exec(contents)?.[1] ?? Number.NaN);
123
+ else if (format !== host) {
124
+ problems.push(`${file} is not a ${host} managed adapter; rerun \`notifai hooks install\``);
125
+ }
126
+ const version = Number(meta(contents, 'adapter-version') ?? Number.NaN);
114
127
  if (version !== ADAPTER_VERSION)
115
128
  problems.push(`${file} uses obsolete adapter version ${version}`);
116
129
  const target = parseTarget(contents);
@@ -120,7 +133,7 @@ export function inspectHookAdapter(homeDir) {
120
133
  else {
121
134
  try {
122
135
  const exec = statSync(target.execPath);
123
- if (!exec.isFile() || (exec.mode & 0o111) === 0) {
136
+ if (!exec.isFile() || (host === 'posix' && (exec.mode & 0o111) === 0)) {
124
137
  problems.push(`registered runtime ${target.execPath} is not executable`);
125
138
  }
126
139
  }
@@ -152,7 +165,13 @@ export function inspectHookAdapter(homeDir) {
152
165
  }
153
166
  return { path: file, target, problems };
154
167
  }
155
- function hookAdapterSource(target) {
168
+ /** Generate the managed adapter source for one host. Exported so tests can pin bytes. */
169
+ export function hookAdapterSource(target, platform = process.platform) {
170
+ return hookHostPlatform(platform) === 'win32'
171
+ ? win32HookAdapterSource(target)
172
+ : posixHookAdapterSource(target);
173
+ }
174
+ function posixHookAdapterSource(target) {
156
175
  if (isNpxAdapterTarget(target)) {
157
176
  return `#!/bin/sh
158
177
  ${ADAPTER_MARKER}
@@ -193,9 +212,69 @@ printf '%s\n' 'Notifai hook adapter target is stale; run notifai hooks install.'
193
212
  exit 127
194
213
  `;
195
214
  }
215
+ function win32HookAdapterSource(target) {
216
+ const header = isNpxAdapterTarget(target)
217
+ ? `${WIN32_ADAPTER_MARKER}
218
+ // adapter-version: ${ADAPTER_VERSION}
219
+ // target-kind: npx
220
+ // target-exec-json: ${JSON.stringify(target.execPath)}
221
+ // target-npm-cli-json: ${JSON.stringify(target.npmCli)}
222
+ // target-spec-json: ${JSON.stringify(target.spec)}
223
+ `
224
+ : `${WIN32_ADAPTER_MARKER}
225
+ // adapter-version: ${ADAPTER_VERSION}
226
+ // target-exec-json: ${JSON.stringify(target.execPath)}
227
+ // target-script-json: ${JSON.stringify(target.scriptPath)}
228
+ `;
229
+ const argv = isNpxAdapterTarget(target)
230
+ ? `[${JSON.stringify(target.npmCli)}, "exec", "--yes", "--package", ${JSON.stringify(target.spec)}, "--", "notifai", ...process.argv.slice(2)]`
231
+ : `[${JSON.stringify(target.scriptPath)}, ...process.argv.slice(2)]`;
232
+ const companion = isNpxAdapterTarget(target)
233
+ ? JSON.stringify(target.npmCli)
234
+ : JSON.stringify(target.scriptPath);
235
+ return `${header}"use strict";
236
+ const { spawnSync } = require("node:child_process");
237
+ const { statSync } = require("node:fs");
238
+ const registeredExec = ${JSON.stringify(target.execPath)};
239
+ const registeredCompanion = ${companion};
240
+
241
+ function isFile(file) {
242
+ try {
243
+ return statSync(file).isFile();
244
+ } catch {
245
+ return false;
246
+ }
247
+ }
248
+
249
+ if (isFile(registeredExec) && isFile(registeredCompanion)) {
250
+ const result = spawnSync(registeredExec, ${argv}, {
251
+ stdio: "inherit",
252
+ windowsHide: true,
253
+ });
254
+ if (result.error) {
255
+ process.stderr.write("Notifai hook adapter target is stale; run notifai hooks install.\\n");
256
+ process.exit(127);
257
+ }
258
+ process.exit(result.status === null ? 1 : result.status);
259
+ }
260
+
261
+ process.stderr.write("Notifai hook adapter target is stale; run notifai hooks install.\\n");
262
+ process.exit(127);
263
+ `;
264
+ }
265
+ function adapterFormat(contents) {
266
+ if (contents.startsWith(`#!/bin/sh\n${ADAPTER_MARKER}\n`))
267
+ return 'posix';
268
+ if (contents.startsWith(`${WIN32_ADAPTER_MARKER}\n`))
269
+ return 'win32';
270
+ return null;
271
+ }
272
+ function meta(contents, key) {
273
+ return new RegExp(`^(?:#|//) ${key}: (.+)$`, 'm').exec(contents)?.[1];
274
+ }
196
275
  function parseTarget(contents) {
197
- const kind = /^# target-kind: (.+)$/m.exec(contents)?.[1];
198
- const exec = /^# target-exec-json: (.+)$/m.exec(contents)?.[1];
276
+ const kind = meta(contents, 'target-kind');
277
+ const exec = meta(contents, 'target-exec-json');
199
278
  if (exec === undefined)
200
279
  return null;
201
280
  try {
@@ -203,8 +282,8 @@ function parseTarget(contents) {
203
282
  if (typeof execPath !== 'string')
204
283
  return null;
205
284
  if (kind === 'npx') {
206
- const npmCliRaw = /^# target-npm-cli-json: (.+)$/m.exec(contents)?.[1];
207
- const specRaw = /^# target-spec-json: (.+)$/m.exec(contents)?.[1];
285
+ const npmCliRaw = meta(contents, 'target-npm-cli-json');
286
+ const specRaw = meta(contents, 'target-spec-json');
208
287
  if (npmCliRaw === undefined || specRaw === undefined)
209
288
  return null;
210
289
  const npmCli = JSON.parse(npmCliRaw);
@@ -213,7 +292,7 @@ function parseTarget(contents) {
213
292
  ? { kind: 'npx', execPath, npmCli, spec }
214
293
  : null;
215
294
  }
216
- const script = /^# target-script-json: (.+)$/m.exec(contents)?.[1];
295
+ const script = meta(contents, 'target-script-json');
217
296
  if (script === undefined)
218
297
  return null;
219
298
  const scriptPath = JSON.parse(script);
@@ -226,7 +305,7 @@ function parseTarget(contents) {
226
305
  function quote(value) {
227
306
  return `'${value.replaceAll("'", `'\\''`)}'`;
228
307
  }
229
- function ensureManagedDirectories(homeDir) {
308
+ function ensureManagedDirectories(homeDir, host) {
230
309
  if (!existsSync(homeDir))
231
310
  mkdirSync(homeDir, { recursive: true, mode: 0o700 });
232
311
  for (const dir of [path.join(homeDir, '.notifai'), path.join(homeDir, '.notifai', 'bin')]) {
@@ -236,11 +315,13 @@ function ensureManagedDirectories(homeDir) {
236
315
  if (stat.isSymbolicLink() || !stat.isDirectory()) {
237
316
  throw new Error(`${dir} is not a regular directory; refusing to install the hook adapter.`);
238
317
  }
239
- const uid = typeof process.getuid === 'function' ? process.getuid() : undefined;
240
- if (uid !== undefined && stat.uid !== uid) {
241
- throw new Error(`${dir} is owned by uid ${stat.uid}, not the current user.`);
318
+ if (host === 'posix') {
319
+ const uid = typeof process.getuid === 'function' ? process.getuid() : undefined;
320
+ if (uid !== undefined && stat.uid !== uid) {
321
+ throw new Error(`${dir} is owned by uid ${stat.uid}, not the current user.`);
322
+ }
323
+ chmodSync(dir, 0o700);
242
324
  }
243
- chmodSync(dir, 0o700);
244
325
  }
245
326
  }
246
327
  function readSafeManagedFile(file) {
@@ -1 +1 @@
1
- {"version":3,"file":"hook-adapter.js","sourceRoot":"","sources":["../src/hook-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hook-adapter.js","sourceRoot":"","sources":["../src/hook-adapter.ts"],"names":[],"mappings":"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"}
package/dist/hooks.d.ts CHANGED
@@ -76,6 +76,17 @@ export interface SessionState {
76
76
  * reaches the harness replays it instead of erasing it.
77
77
  */
78
78
  accepted?: AcceptedAnswerDelivery;
79
+ /**
80
+ * Required Agent Acknowledgements that the resumed agent still owes. This is
81
+ * separate from answer delivery: the answer journal may settle as soon as a
82
+ * harness accepts the continuation, while this obligation must survive until
83
+ * the service confirms the agent-authored follow-up exists.
84
+ */
85
+ acknowledgement_due?: AcknowledgementDue[];
86
+ }
87
+ export interface AcknowledgementDue {
88
+ request_id: string;
89
+ recorded_at: number;
79
90
  }
80
91
  interface AcceptedAnswerDelivery {
81
92
  answers: AnsweredPending[];
@@ -288,7 +299,7 @@ export interface HookContext {
288
299
  * the user sees in the terminal — but it is free to be rewritten, and a log a
289
300
  * filter cannot rely on is a log nobody filters.
290
301
  */
291
- export type GateReason = 'no-session' | 'no-question' | 'answered' | 'already-asked' | 'continuation-repeat' | 'continuation-limit' | 'delivery-limit' | 'notifications-off' | 'claimed-elsewhere' | 'no-devices' | 'proceeding';
302
+ export type GateReason = 'no-session' | 'no-question' | 'answered' | 'already-asked' | 'continuation-repeat' | 'continuation-limit' | 'delivery-limit' | 'acknowledgement-required' | 'notifications-off' | 'claimed-elsewhere' | 'no-devices' | 'proceeding';
292
303
  export type HookHarness = Harness;
293
304
  /**
294
305
  * Everything retirement needs. Narrower than a HookContext on purpose:
@@ -331,7 +342,10 @@ interface AnsweredPending {
331
342
  pending: PendingQuestion;
332
343
  reply: ReplyView;
333
344
  replies: ReplyView[];
345
+ /** Immutable server snapshot for this request, known after a replies/close response. */
346
+ agent_acknowledgement_required?: boolean | undefined;
334
347
  }
348
+ export declare function clearAcknowledgementObligation(sessionId: string, env: NodeJS.ProcessEnv, requestId: string): boolean;
335
349
  /**
336
350
  * Records presence and retires anything still asking on companion devices. This is the
337
351
  * "answered in the terminal" case from the original design: we cannot tell
package/dist/hooks.js CHANGED
@@ -540,7 +540,8 @@ async function answerableDevices(ctx) {
540
540
  const { devices } = await ctx.client.listDevices();
541
541
  return devices
542
542
  .filter((device) => (device.platform === 'ios' || device.platform === 'macos') &&
543
- device.registration_healthy)
543
+ device.registration_healthy &&
544
+ device.reply_protocol_version === 2)
544
545
  .filter((device) => configured === null || configured.includes(device.device_id))
545
546
  .map((device) => device.device_id);
546
547
  }
@@ -813,7 +814,14 @@ async function finalizePendings(ctx, pending) {
813
814
  function finalizedAnswer(finalized) {
814
815
  const replies = finalized.response?.replies ?? [];
815
816
  const reply = replies.at(-1);
816
- return reply === undefined ? null : { pending: finalized.pending, reply, replies };
817
+ return reply === undefined
818
+ ? null
819
+ : {
820
+ pending: finalized.pending,
821
+ reply,
822
+ replies,
823
+ agent_acknowledgement_required: finalized.response?.agent_acknowledgement_required,
824
+ };
817
825
  }
818
826
  /** Persist and surface one answer without letting the two representations drift. */
819
827
  function reportAnswer(ctx, notes, answered, late) {
@@ -901,12 +909,35 @@ function answerContext(answered) {
901
909
  * tied to the question that asked it, with a truthful note about anything
902
910
  * still waiting.
903
911
  */
912
+ function acknowledgementCommand(requestId) {
913
+ return `notifai acknowledge ${requestId} --text <text>`;
914
+ }
915
+ function acknowledgementContext(answered) {
916
+ const due = answered.filter((entry) => entry.agent_acknowledgement_required === true && entry.pending.request_id !== undefined);
917
+ if (due.length === 0) {
918
+ return ' Agent Acknowledgement is not required for the answered request(s).';
919
+ }
920
+ if (due.length === 1) {
921
+ const requestId = due[0].pending.request_id;
922
+ return (` Agent Acknowledgement is required for request ${requestId}. Immediately, before doing the resumed work or ending this turn, run ` +
923
+ `\`${acknowledgementCommand(requestId)}\` with non-empty text saying what concrete work you will do because of the reply; a bare acknowledgement is insufficient.`);
924
+ }
925
+ const commands = due
926
+ .map((entry) => {
927
+ const requestId = entry.pending.request_id;
928
+ return `- ${requestId}: \`${acknowledgementCommand(requestId)}\``;
929
+ })
930
+ .join('\n');
931
+ return (` Agent Acknowledgement is required for ${due.length} requests. Immediately, before doing the resumed work or ending this turn, run every command below with non-empty text saying what concrete work you will do because of that reply; a bare acknowledgement is insufficient:\n` +
932
+ commands);
933
+ }
904
934
  function answersContext(answered, remaining) {
905
935
  const tail = remaining > 0
906
936
  ? ` (${remaining} more registered question${remaining === 1 ? ' is' : 's are'} still waiting for an answer.)`
907
937
  : '';
938
+ const guidance = acknowledgementContext(answered);
908
939
  if (answered.length === 1) {
909
- return answerContext(answered[0]) + tail;
940
+ return answerContext(answered[0]) + tail + guidance;
910
941
  }
911
942
  const lines = answered.map(({ pending, replies }) => {
912
943
  const latest = replies.at(-1);
@@ -917,7 +948,7 @@ function answersContext(answered, remaining) {
917
948
  const identity = ids.length === 0 ? '' : `question_id${ids.length === 1 ? '' : 's'} ${ids.join(', ')}: `;
918
949
  return `- ${identity}${JSON.stringify(pending.question)} → ${answer}`;
919
950
  });
920
- return `Notifai — the user answered ${answered.length} questions:\n${lines.join('\n')}${tail}`;
951
+ return `Notifai — the user answered ${answered.length} questions:\n${lines.join('\n')}${tail}${guidance}`;
921
952
  }
922
953
  function stopAnswerOutput(context) {
923
954
  return JSON.stringify({
@@ -939,6 +970,15 @@ function stageAcceptedAnswers(ctx, sessionId, answered, remaining) {
939
970
  };
940
971
  updateSessionState(sessionId, ctx.env, (current) => {
941
972
  const pendingRemaining = pendingList(current).filter((entry) => !answered.some(({ pending }) => isSamePending(entry, pending)));
973
+ const acknowledgementDue = [...(current.acknowledgement_due ?? [])];
974
+ for (const answer of answered) {
975
+ const requestId = answer.pending.request_id;
976
+ if (answer.agent_acknowledgement_required === true &&
977
+ requestId !== undefined &&
978
+ !acknowledgementDue.some((entry) => entry.request_id === requestId)) {
979
+ acknowledgementDue.push({ request_id: requestId, recorded_at: accepted.recorded_at });
980
+ }
981
+ }
942
982
  const next = {
943
983
  ...current,
944
984
  accepted,
@@ -947,6 +987,10 @@ function stageAcceptedAnswers(ctx, sessionId, answered, remaining) {
947
987
  next.pending = pendingRemaining;
948
988
  else
949
989
  delete next.pending;
990
+ if (acknowledgementDue.length > 0)
991
+ next.acknowledgement_due = acknowledgementDue;
992
+ else
993
+ delete next.acknowledgement_due;
950
994
  return next;
951
995
  });
952
996
  return accepted;
@@ -955,6 +999,58 @@ function stageAcceptedAnswers(ctx, sessionId, answered, remaining) {
955
999
  function amendAcceptedAnswers(ctx, sessionId, amend) {
956
1000
  updateSessionState(sessionId, ctx.env, (current) => current.accepted === undefined ? current : { ...current, accepted: amend(current.accepted) });
957
1001
  }
1002
+ export function clearAcknowledgementObligation(sessionId, env, requestId) {
1003
+ let cleared = false;
1004
+ updateSessionState(sessionId, env, (current) => {
1005
+ const due = current.acknowledgement_due ?? [];
1006
+ const remaining = due.filter((entry) => entry.request_id !== requestId);
1007
+ cleared = remaining.length !== due.length;
1008
+ if (!cleared)
1009
+ return current;
1010
+ const next = { ...current };
1011
+ if (remaining.length > 0)
1012
+ next.acknowledgement_due = remaining;
1013
+ else
1014
+ delete next.acknowledgement_due;
1015
+ return next;
1016
+ });
1017
+ return cleared;
1018
+ }
1019
+ function acknowledgementBlockContext(due) {
1020
+ const commands = due
1021
+ .map((entry) => `- ${entry.request_id}: \`${acknowledgementCommand(entry.request_id)}\``)
1022
+ .join('\n');
1023
+ return (`Notifai — required Agent Acknowledgement${due.length === 1 ? '' : 's'} still missing for request${due.length === 1 ? '' : 's'} ${due.map((entry) => entry.request_id).join(', ')}. ` +
1024
+ `Before doing more resumed work or ending this turn, run ${due.length === 1 ? 'this command' : 'every command'} with non-empty text saying what concrete work you will do because of the reply; a bare acknowledgement is insufficient:\n${commands}`);
1025
+ }
1026
+ async function reconcileAcknowledgementObligations(ctx, sessionId, due) {
1027
+ const unresolved = [];
1028
+ for (const obligation of due) {
1029
+ try {
1030
+ const snapshot = await ctx.client.agentAcknowledgement(obligation.request_id, {
1031
+ waitSeconds: 0,
1032
+ });
1033
+ if (snapshot.agent_acknowledgement_required === false ||
1034
+ snapshot.agent_acknowledgement !== null) {
1035
+ clearAcknowledgementObligation(sessionId, ctx.env, obligation.request_id);
1036
+ }
1037
+ else {
1038
+ unresolved.push(obligation);
1039
+ }
1040
+ }
1041
+ catch (err) {
1042
+ unresolved.push(obligation);
1043
+ ctx.log?.error('hook.gate', {
1044
+ verdict: 'held',
1045
+ reason: 'acknowledgement-required',
1046
+ stage: 'reconcile-failed',
1047
+ request_id: obligation.request_id,
1048
+ message: err instanceof Error ? err.message : String(err),
1049
+ });
1050
+ }
1051
+ }
1052
+ return unresolved;
1053
+ }
958
1054
  /**
959
1055
  * Retire the answered questions and close the journal.
960
1056
  *
@@ -1049,7 +1145,13 @@ export async function handleUserPromptSubmit(ctx, envelope) {
1049
1145
  if (response === null) {
1050
1146
  notes.push(`could not confirm the close fence for ${entry.pending.request_id}; preserving the durable answer already observed`);
1051
1147
  }
1052
- return { ...entry, replies, reply: replies.at(-1) };
1148
+ return {
1149
+ ...entry,
1150
+ replies,
1151
+ reply: replies.at(-1),
1152
+ agent_acknowledgement_required: response?.agent_acknowledgement_required ??
1153
+ entry.agent_acknowledgement_required,
1154
+ };
1053
1155
  });
1054
1156
  if (answered.length > 0) {
1055
1157
  stageAcceptedAnswers(ctx, sessionId, lateAnswers, 0);
@@ -1163,6 +1265,23 @@ export async function runEscalationWaiter(ctx, options) {
1163
1265
  let state = readSessionState(sessionId, ctx.env);
1164
1266
  if (state.accepted !== undefined) {
1165
1267
  const accepted = state.accepted;
1268
+ if (envelope.stop_hook_active === true && pendingList(state).length > 0) {
1269
+ const due = await reconcileAcknowledgementObligations(ctx, sessionId, state.acknowledgement_due ?? []);
1270
+ if (due.length > 0) {
1271
+ gate(ctx, 'held', 'acknowledgement-required', {
1272
+ request_ids: due.map((entry) => entry.request_id),
1273
+ });
1274
+ return {
1275
+ stdout: stopAnswerOutput(acknowledgementBlockContext(due)),
1276
+ notes,
1277
+ log: {
1278
+ stage: 'acknowledgement-required',
1279
+ request_ids: due.map((entry) => entry.request_id),
1280
+ },
1281
+ };
1282
+ }
1283
+ state = readSessionState(sessionId, ctx.env);
1284
+ }
1166
1285
  // Acknowledgement is per route, because routes end in different places.
1167
1286
  //
1168
1287
  // A blocking continuation ends at this process's stdout, which the
@@ -1183,6 +1302,39 @@ export async function runEscalationWaiter(ctx, options) {
1183
1302
  settleAcceptedAnswers(ctx, sessionId, accepted);
1184
1303
  settledAnswerThisPass = true;
1185
1304
  state = readSessionState(sessionId, ctx.env);
1305
+ const currentAcceptedIds = new Set(accepted.answers.flatMap(({ pending }) => pending.request_id === undefined ? [] : [pending.request_id]));
1306
+ const due = await reconcileAcknowledgementObligations(ctx, sessionId, (state.acknowledgement_due ?? []).filter((entry) => currentAcceptedIds.has(entry.request_id)));
1307
+ if (due.length > 0) {
1308
+ gate(ctx, 'held', 'acknowledgement-required', {
1309
+ request_ids: due.map((entry) => entry.request_id),
1310
+ });
1311
+ return {
1312
+ stdout: stopAnswerOutput(acknowledgementBlockContext(due)),
1313
+ notes,
1314
+ log: {
1315
+ stage: 'acknowledgement-required',
1316
+ request_ids: due.map((entry) => entry.request_id),
1317
+ },
1318
+ };
1319
+ }
1320
+ state = readSessionState(sessionId, ctx.env);
1321
+ }
1322
+ if (state.accepted === undefined && (state.acknowledgement_due?.length ?? 0) > 0) {
1323
+ const due = await reconcileAcknowledgementObligations(ctx, sessionId, state.acknowledgement_due);
1324
+ if (due.length > 0) {
1325
+ gate(ctx, 'held', 'acknowledgement-required', {
1326
+ request_ids: due.map((entry) => entry.request_id),
1327
+ });
1328
+ return {
1329
+ stdout: stopAnswerOutput(acknowledgementBlockContext(due)),
1330
+ notes,
1331
+ log: {
1332
+ stage: 'acknowledgement-required',
1333
+ request_ids: due.map((entry) => entry.request_id),
1334
+ },
1335
+ };
1336
+ }
1337
+ state = readSessionState(sessionId, ctx.env);
1186
1338
  }
1187
1339
  const pending = pendingList(state);
1188
1340
  if (pending.length === 0) {
@@ -1331,7 +1483,13 @@ async function handleClaimedStop(ctx, envelope, sessionId, state, pending, notes
1331
1483
  if (response === null) {
1332
1484
  notes.push(`could not confirm the close fence for ${entry.pending.request_id}; delivering the durable answer already observed`);
1333
1485
  }
1334
- return { ...entry, replies, reply: replies.at(-1) };
1486
+ return {
1487
+ ...entry,
1488
+ replies,
1489
+ reply: replies.at(-1),
1490
+ agent_acknowledgement_required: response?.agent_acknowledgement_required ??
1491
+ entry.agent_acknowledgement_required,
1492
+ };
1335
1493
  });
1336
1494
  const accepted = stageAcceptedAnswers(ctx, sessionId, authoritative, pending.length - authoritative.length - permanentlyRejected.length);
1337
1495
  for (const answer of authoritative)
@@ -1665,7 +1823,12 @@ async function escalate(ctx, envelope, sessionId, unasked, alreadyLive, notes, h
1665
1823
  // unreachable, never discard the durable reply already observed.
1666
1824
  const finalReplies = finalized.response?.replies ?? [];
1667
1825
  const authoritative = finalReplies.length > 0 ? finalReplies : replies;
1668
- answered.push({ pending: entry, reply: authoritative.at(-1), replies: authoritative });
1826
+ answered.push({
1827
+ pending: entry,
1828
+ reply: authoritative.at(-1),
1829
+ replies: authoritative,
1830
+ agent_acknowledgement_required: finalized.response?.agent_acknowledgement_required,
1831
+ });
1669
1832
  if (finalized.response === null) {
1670
1833
  notes.push(`could not confirm the close fence for ${entry.request_id}; delivering the durable answer already observed`);
1671
1834
  }
@@ -1716,8 +1879,13 @@ export function handleSessionEnd(env, envelope, now = Date.now()) {
1716
1879
  orphanRetirements(env, orphans, label !== undefined && label !== '' ? label : sessionId, now);
1717
1880
  notes.push(`queued ${orphans.length} question${orphans.length > 1 ? 's' : ''} for retirement on the next hook`);
1718
1881
  }
1719
- if (state.accepted !== undefined) {
1720
- const preserved = { accepted: state.accepted };
1882
+ if (state.accepted !== undefined || (state.acknowledgement_due?.length ?? 0) > 0) {
1883
+ const preserved = {};
1884
+ if (state.accepted !== undefined)
1885
+ preserved.accepted = state.accepted;
1886
+ if (state.acknowledgement_due !== undefined && state.acknowledgement_due.length > 0) {
1887
+ preserved.acknowledgement_due = state.acknowledgement_due;
1888
+ }
1721
1889
  if (state.last_prompt_at !== undefined)
1722
1890
  preserved.last_prompt_at = state.last_prompt_at;
1723
1891
  if (state.last_stop_at !== undefined)
@@ -1725,13 +1893,16 @@ export function handleSessionEnd(env, envelope, now = Date.now()) {
1725
1893
  if (state.continuation !== undefined)
1726
1894
  preserved.continuation = state.continuation;
1727
1895
  writeSessionState(sessionId, env, preserved);
1728
- notes.push('preserved an accepted device answer for this exact session to resume');
1896
+ notes.push(state.accepted !== undefined
1897
+ ? 'preserved an accepted device answer for this exact session to resume'
1898
+ : 'preserved required Agent Acknowledgement obligations for this exact session');
1729
1899
  return {
1730
1900
  notes,
1731
1901
  log: {
1732
- outcome: 'answer-preserved',
1902
+ outcome: state.accepted !== undefined ? 'answer-preserved' : 'acknowledgement-preserved',
1733
1903
  queued_retirements: orphans.length,
1734
- accepted_answers: state.accepted.answers.length,
1904
+ accepted_answers: state.accepted?.answers.length ?? 0,
1905
+ acknowledgement_due: state.acknowledgement_due?.length ?? 0,
1735
1906
  },
1736
1907
  };
1737
1908
  }