@raidiant/notifai 11.6.0 → 11.6.1-beta.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/CHANGELOG.md +36 -0
- package/README.md +12 -14
- package/dist/codex-tool-messages.d.ts +1 -12
- package/dist/codex-tool-messages.js +20 -66
- package/dist/codex-tool-messages.js.map +1 -1
- package/dist/codex-wake.d.ts +6 -25
- package/dist/codex-wake.js +6 -25
- package/dist/codex-wake.js.map +1 -1
- package/dist/commands-ask.d.ts +2 -3
- package/dist/commands-ask.js +29 -11
- package/dist/commands-ask.js.map +1 -1
- package/dist/commands-core.d.ts +1 -1
- package/dist/commands-hook-attend.js +39 -53
- package/dist/commands-hook-attend.js.map +1 -1
- package/dist/commands-hook-run.js +50 -12
- package/dist/commands-hook-run.js.map +1 -1
- package/dist/commands-receive.d.ts +3 -0
- package/dist/commands-receive.js +55 -0
- package/dist/commands-receive.js.map +1 -0
- package/dist/commands-send.js +1 -1
- package/dist/commands-send.js.map +1 -1
- package/dist/commands-update-check.js +2 -1
- package/dist/commands-update-check.js.map +1 -1
- package/dist/commands.d.ts +1 -0
- package/dist/commands.js +1 -0
- package/dist/commands.js.map +1 -1
- package/dist/config-schema.js +2 -2
- package/dist/config-schema.js.map +1 -1
- package/dist/hook-acknowledgements.js +7 -1
- package/dist/hook-acknowledgements.js.map +1 -1
- package/dist/hook-gates.d.ts +1 -1
- package/dist/hook-gates.js +0 -1
- package/dist/hook-gates.js.map +1 -1
- package/dist/hook-lifecycle.d.ts +2 -0
- package/dist/hook-lifecycle.js +354 -360
- package/dist/hook-lifecycle.js.map +1 -1
- package/dist/hook-question-lock.js +3 -3
- package/dist/hook-question-lock.js.map +1 -1
- package/dist/hook-types.d.ts +15 -7
- package/dist/logging.js +1 -1
- package/dist/logging.js.map +1 -1
- package/dist/program.d.ts +2 -1
- package/dist/program.js +11 -6
- package/dist/program.js.map +1 -1
- package/dist/question-settlement-process.d.ts +5 -3
- package/dist/question-settlement-process.js +4 -4
- package/dist/question-settlement-process.js.map +1 -1
- package/dist/session-attendant-probe.d.ts +1 -1
- package/dist/session-attendant-probe.js +1 -1
- package/dist/session-attendant-state.d.ts +3 -3
- package/dist/session-attendant-state.js +3 -3
- package/dist/session-attendant.d.ts +2 -0
- package/dist/session-attendant.js +16 -1
- package/dist/session-attendant.js.map +1 -1
- package/dist/session-delivery.d.ts +5 -1
- package/dist/session-delivery.js +10 -0
- package/dist/session-delivery.js.map +1 -1
- package/dist/session-inputs.d.ts +22 -0
- package/dist/session-inputs.js +254 -0
- package/dist/session-inputs.js.map +1 -0
- package/dist/session-message-handoff.js +6 -1
- package/dist/session-message-handoff.js.map +1 -1
- package/dist/skill-source/manifest.json +6 -6
- package/dist/skill-source/notifai/SKILL.md +20 -21
- package/dist/skill-source/notifai/references/diagnostics.md +1 -1
- package/dist/skill-source/notifai/references/harness-setup.md +39 -33
- package/dist/skill-source/notifai/references/notes-and-edits.md +6 -1
- package/package.json +2 -2
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native queues carry a wake, never User words. The foreground consumer reads
|
|
3
|
+
* the current pending inputs and claims one bounded batch immediately before
|
|
4
|
+
* presentation. A late wake therefore cannot resurrect an acknowledged answer.
|
|
5
|
+
*/
|
|
6
|
+
import { randomUUID } from 'node:crypto';
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { atomicWriteFileSync } from './atomic-file.js';
|
|
10
|
+
import { sanitizeSessionId, stateDir } from './config.js';
|
|
11
|
+
import { answersContext, clearAcknowledgementObligation, recordMessageAcknowledgementDue } from './hook-acknowledgements.js';
|
|
12
|
+
import { retiringQuestion } from './hook-question-retirement.js';
|
|
13
|
+
import { readSessionIncarnation, readSessionState, recordSessionNotified, sessionHasEnded, updateSessionState } from './hook-session-state.js';
|
|
14
|
+
import { sessionMessageContext } from './injection-render.js';
|
|
15
|
+
import { currentProcessIdentity, processIdentityLiveness } from './process-identity.js';
|
|
16
|
+
import { answerWriterGone, beginHandOff, readDeliveryJournal } from './session-delivery.js';
|
|
17
|
+
export function sessionInputWake() {
|
|
18
|
+
return `Notifai — user input may be waiting for this session. Run \`notifai receive\` before continuing. If no input remains, continue your work. This wake-up contains no note, answer, or approval.`;
|
|
19
|
+
}
|
|
20
|
+
/** Atomically coalesce native wakes until one actually reaches its consumer. */
|
|
21
|
+
export async function wakeSessionInputs(sessionId, env, send, log) {
|
|
22
|
+
const incarnation = readSessionIncarnation(sessionId, env)?.incarnation ?? `session:${sessionId}`;
|
|
23
|
+
const writer = currentProcessIdentity();
|
|
24
|
+
if (writer === null || sessionHasEnded(sessionId, env))
|
|
25
|
+
return;
|
|
26
|
+
const token = randomUUID();
|
|
27
|
+
let elected = false;
|
|
28
|
+
updateSessionState(sessionId, env, (state) => {
|
|
29
|
+
if (state.input_wake?.incarnation === incarnation &&
|
|
30
|
+
(state.input_wake.queued || processIdentityLiveness(state.input_wake.writer) !== 'gone'))
|
|
31
|
+
return state;
|
|
32
|
+
elected = true;
|
|
33
|
+
return { ...state, input_wake: { incarnation, token, queued: false, writer } };
|
|
34
|
+
});
|
|
35
|
+
if (!elected) {
|
|
36
|
+
log?.debug('delivery.handoff', { route: 'input-wake', stage: 'coalesced', session: sessionId });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
let sent = false;
|
|
40
|
+
try {
|
|
41
|
+
sent = await send(sessionInputWake());
|
|
42
|
+
log?.info('delivery.handoff', { route: 'input-wake', stage: sent ? 'queued' : 'deferred', session: sessionId });
|
|
43
|
+
if (sent)
|
|
44
|
+
updateSessionState(sessionId, env, (state) => state.input_wake?.token === token
|
|
45
|
+
? { ...state, input_wake: { ...state.input_wake, queued: true } } : state);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
if (!sent)
|
|
49
|
+
updateSessionState(sessionId, env, (state) => {
|
|
50
|
+
if (state.input_wake?.token !== token)
|
|
51
|
+
return state;
|
|
52
|
+
const next = { ...state };
|
|
53
|
+
delete next.input_wake;
|
|
54
|
+
return next;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export function observeSessionInputWake(sessionId, env, prompt) {
|
|
59
|
+
if (prompt !== sessionInputWake())
|
|
60
|
+
return;
|
|
61
|
+
updateSessionState(sessionId, env, (state) => {
|
|
62
|
+
const next = { ...state };
|
|
63
|
+
delete next.input_wake;
|
|
64
|
+
return next;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export function stageSessionAnswers(sessionId, env, accepted) {
|
|
68
|
+
updateSessionState(sessionId, env, (state) => {
|
|
69
|
+
if (state.accepted?.recorded_at !== accepted.recorded_at)
|
|
70
|
+
return state;
|
|
71
|
+
const waiting = [...(state.waiting_answers ?? [])];
|
|
72
|
+
for (const answer of accepted.answers) {
|
|
73
|
+
if (!waiting.some((entry) => entry.pending.request_id === answer.pending.request_id))
|
|
74
|
+
waiting.push(answer);
|
|
75
|
+
}
|
|
76
|
+
const next = { ...state, waiting_answers: waiting };
|
|
77
|
+
delete next.accepted;
|
|
78
|
+
return next;
|
|
79
|
+
});
|
|
80
|
+
// A reply proves submission even when its HTTP receipt was lost. Wake a
|
|
81
|
+
// dormant resident writer without depending on that missing receipt.
|
|
82
|
+
recordSessionNotified(sessionId, env, accepted.recorded_at);
|
|
83
|
+
}
|
|
84
|
+
/** The existing route wakes the exact owner, but no longer owns answer text. */
|
|
85
|
+
export function sessionInputRoute(sessionId, env, route, log) {
|
|
86
|
+
return { ...route, defer: async (accepted) => {
|
|
87
|
+
stageSessionAnswers(sessionId, env, accepted);
|
|
88
|
+
await wakeSessionInputs(sessionId, env, async (text) => {
|
|
89
|
+
const result = await route.deliver({
|
|
90
|
+
context: text, answers: 0, remaining: 0, request_ids: [], journal_recorded_at: accepted.recorded_at,
|
|
91
|
+
commitDelivery: () => !sessionHasEnded(sessionId, env),
|
|
92
|
+
});
|
|
93
|
+
return result.acknowledgement === 'delivered';
|
|
94
|
+
}, log);
|
|
95
|
+
} };
|
|
96
|
+
}
|
|
97
|
+
function messagesPath(sessionId, env) {
|
|
98
|
+
return path.join(stateDir(env), 'sessions', `${sanitizeSessionId(sessionId)}.inputs.json`);
|
|
99
|
+
}
|
|
100
|
+
/** Cache only: the service remains authoritative and claims fence stale copies. */
|
|
101
|
+
export function stageSessionMessages(sessionId, env, lease, messages) {
|
|
102
|
+
atomicWriteFileSync(messagesPath(sessionId, env), JSON.stringify({ session_id: sessionId, ...lease, messages }));
|
|
103
|
+
}
|
|
104
|
+
export function readSessionMessages(sessionId, env, lease) {
|
|
105
|
+
try {
|
|
106
|
+
const data = JSON.parse(readFileSync(messagesPath(sessionId, env), 'utf8'));
|
|
107
|
+
if (data.session_id !== sessionId || data.incarnation !== lease.incarnation || data.generation !== lease.generation || !Array.isArray(data.messages))
|
|
108
|
+
return [];
|
|
109
|
+
if (!data.messages.every((m) => typeof m.message_id === 'string' && /^sm_[A-Za-z0-9_-]+$/.test(m.message_id) &&
|
|
110
|
+
typeof m.created_at === 'string' && typeof m.agent_acknowledgement_text_required === 'boolean' &&
|
|
111
|
+
(m.kind === 'note' ? typeof m.body === 'string' : m.kind === 'answer_edit' && typeof m.request_id === 'string' && typeof m.text === 'string' && Array.isArray(m.answers))))
|
|
112
|
+
return [];
|
|
113
|
+
return data.messages;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function pendingSessionInputs(sessionId, env, lease) {
|
|
120
|
+
const state = readSessionState(sessionId, env);
|
|
121
|
+
const written = new Set(readDeliveryJournal(sessionId, env)
|
|
122
|
+
.filter((entry) => ['writing', 'written', 'failed'].includes(entry.stage))
|
|
123
|
+
.map((entry) => entry.subject.type === 'answer' ? entry.subject.request_id : entry.subject.message_id));
|
|
124
|
+
const owed = new Set(state.acknowledgement_due?.map((entry) => entry.request_id));
|
|
125
|
+
const answers = (state.waiting_answers ?? []).filter((answer) => answer.pending.request_id !== undefined && !written.has(answer.pending.request_id) &&
|
|
126
|
+
owed.has(answer.pending.request_id)).slice(0, 20);
|
|
127
|
+
// Answers precede their edits; notes retain the service's immutable order.
|
|
128
|
+
const messages = (lease === null ? [] : readSessionMessages(sessionId, env, lease))
|
|
129
|
+
.filter((message) => !written.has(message.message_id)).slice(0, 20 - answers.length);
|
|
130
|
+
return { answers, messages };
|
|
131
|
+
}
|
|
132
|
+
export function hasSessionInputs(sessionId, env, lease) {
|
|
133
|
+
const { answers, messages } = pendingSessionInputs(sessionId, env, lease);
|
|
134
|
+
return answers.length + messages.length > 0;
|
|
135
|
+
}
|
|
136
|
+
/** One stdout document, at most 20 inputs, with ownership checked at the byte. */
|
|
137
|
+
export async function drainSessionInputs(input) {
|
|
138
|
+
const { sequencer: deps, lease } = input;
|
|
139
|
+
const { answers, messages } = pendingSessionInputs(deps.sessionId, deps.env, lease);
|
|
140
|
+
if (answers.length + messages.length === 0 || !input.mayWrite())
|
|
141
|
+
return false;
|
|
142
|
+
// An unfenced answer has no server claim to reject a stale local copy.
|
|
143
|
+
// Reconcile it before presentation; inability to check must defer it.
|
|
144
|
+
for (const answer of answers.filter((entry) => entry.delivery_claim !== true)) {
|
|
145
|
+
try {
|
|
146
|
+
const result = await deps.client.agentAcknowledgement(answer.pending.request_id, { waitSeconds: 0 });
|
|
147
|
+
if (result.agent_acknowledgement !== null)
|
|
148
|
+
clearAcknowledgementObligation(deps.sessionId, deps.env, answer.pending.request_id);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const claimUntil = deps.monotonic() + 750;
|
|
155
|
+
const handOff = await beginHandOff(deps, {
|
|
156
|
+
lease, lockWaitMs: 0, stopAtRefusal: true, mayWrite: input.mayWrite,
|
|
157
|
+
mayClaim: () => deps.monotonic() < claimUntil,
|
|
158
|
+
subjects: [
|
|
159
|
+
...answers.filter((answer) => answer.delivery_claim === true).map((answer) => ({ type: 'answer', request_id: answer.pending.request_id })),
|
|
160
|
+
...messages.map((message) => ({ type: 'session_message', message_id: message.message_id })),
|
|
161
|
+
],
|
|
162
|
+
earlierAnswerWriterGone: (subject) => {
|
|
163
|
+
const message = subject.type === 'session_message' ? messages.find((entry) => entry.message_id === subject.message_id) : undefined;
|
|
164
|
+
return message?.kind === 'answer_edit' && answerWriterGone(deps.sessionId, deps.env, message.request_id);
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
if (handOff === null)
|
|
168
|
+
return false;
|
|
169
|
+
const terminal = new Set(handOff.refused.filter((entry) => entry.reason === 'not_claimable' || entry.reason === 'not_found')
|
|
170
|
+
.flatMap((entry) => entry.subject.type === 'answer' ? [entry.subject.request_id] : []));
|
|
171
|
+
if (terminal.size > 0)
|
|
172
|
+
updateSessionState(deps.sessionId, deps.env, (latest) => ({
|
|
173
|
+
...latest, waiting_answers: (latest.waiting_answers ?? []).filter((answer) => !terminal.has(answer.pending.request_id)),
|
|
174
|
+
}));
|
|
175
|
+
const ids = new Set(handOff.claimed.map((claim) => claim.subject.type === 'answer' ? claim.subject.request_id : claim.subject.message_id));
|
|
176
|
+
// A concurrent consumer may have drained an unclaimed answer while this
|
|
177
|
+
// reader waited for the delivery lock. Re-read while holding that lock.
|
|
178
|
+
const current = readSessionState(deps.sessionId, deps.env);
|
|
179
|
+
const readyAnswers = answers.filter((answer) => current.waiting_answers?.some((entry) => entry.pending.request_id === answer.pending.request_id) &&
|
|
180
|
+
current.acknowledgement_due?.some((entry) => entry.request_id === answer.pending.request_id) &&
|
|
181
|
+
(answer.delivery_claim !== true || ids.has(answer.pending.request_id)));
|
|
182
|
+
const readyMessages = messages.filter((message) => ids.has(message.message_id));
|
|
183
|
+
if (readyAnswers.length + readyMessages.length === 0 || !input.mayWrite() || !handOff.writable()) {
|
|
184
|
+
await handOff.finish('not-written');
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
const text = [
|
|
188
|
+
...(readyAnswers.length === 0 ? [] : [answersContext(readyAnswers, current.pending?.length ?? 0)]),
|
|
189
|
+
...readyMessages.map(sessionMessageContext),
|
|
190
|
+
].join('\n\n');
|
|
191
|
+
let began = false;
|
|
192
|
+
let outputAttempted = false;
|
|
193
|
+
const restoreUnwritten = () => {
|
|
194
|
+
updateSessionState(deps.sessionId, deps.env, (latest) => ({
|
|
195
|
+
...latest, waiting_answers: [
|
|
196
|
+
...readyAnswers.filter((answer) => latest.acknowledgement_due?.some((owed) => owed.request_id === answer.pending.request_id) &&
|
|
197
|
+
!latest.waiting_answers?.some((entry) => entry.pending.request_id === answer.pending.request_id)),
|
|
198
|
+
...(latest.waiting_answers ?? []),
|
|
199
|
+
],
|
|
200
|
+
}));
|
|
201
|
+
for (const message of readyMessages) {
|
|
202
|
+
if (!current.message_acknowledgement_due?.some((entry) => entry.message_id === message.message_id)) {
|
|
203
|
+
clearAcknowledgementObligation(deps.sessionId, deps.env, message.message_id);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
try {
|
|
208
|
+
if (!handOff.begin(() => !sessionHasEnded(deps.sessionId, deps.env))) {
|
|
209
|
+
await handOff.finish('not-written');
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
began = true;
|
|
213
|
+
// Persist consumption before stdout; an ambiguous output is never replayed.
|
|
214
|
+
const consumed = new Set(readyAnswers.map((answer) => answer.pending.request_id));
|
|
215
|
+
updateSessionState(deps.sessionId, deps.env, (latest) => {
|
|
216
|
+
const retiring = [...(latest.retiring ?? [])];
|
|
217
|
+
for (const answer of readyAnswers) {
|
|
218
|
+
const entry = retiringQuestion(answer.pending, 'answered');
|
|
219
|
+
if (entry !== null && !retiring.some((item) => item.request_id === entry.request_id))
|
|
220
|
+
retiring.push(entry);
|
|
221
|
+
}
|
|
222
|
+
return { ...latest, waiting_answers: (latest.waiting_answers ?? []).filter((answer) => !consumed.has(answer.pending.request_id)), retiring };
|
|
223
|
+
});
|
|
224
|
+
for (const message of readyMessages)
|
|
225
|
+
recordMessageAcknowledgementDue(deps.sessionId, deps.env, {
|
|
226
|
+
message_id: message.message_id, recorded_at: deps.wall(), text_required: message.agent_acknowledgement_text_required,
|
|
227
|
+
});
|
|
228
|
+
if (!input.mayWrite() || !handOff.writable()) {
|
|
229
|
+
restoreUnwritten();
|
|
230
|
+
await handOff.finish('aborted');
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
outputAttempted = true;
|
|
234
|
+
input.write(text);
|
|
235
|
+
if (readyAnswers.length > 0)
|
|
236
|
+
updateSessionState(deps.sessionId, deps.env, (latest) => ({
|
|
237
|
+
...latest, continuation: { answered_at: deps.wall(), count: (latest.continuation?.count ?? 0) + 1 },
|
|
238
|
+
}));
|
|
239
|
+
await handOff.finish('written');
|
|
240
|
+
deps.log?.info('delivery.handoff', {
|
|
241
|
+
route: 'input-drain', stage: 'presented', answers: readyAnswers.length, messages: readyMessages.length,
|
|
242
|
+
request_ids: readyAnswers.map((answer) => answer.pending.request_id), message_ids: readyMessages.map((message) => message.message_id),
|
|
243
|
+
oldest_message_age_ms: Math.max(0, ...readyMessages.map((message) => deps.wall() - Date.parse(message.created_at))),
|
|
244
|
+
});
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
if (began && !outputAttempted)
|
|
249
|
+
restoreUnwritten();
|
|
250
|
+
await handOff.finish(outputAttempted ? 'failed' : began ? 'aborted' : 'not-written');
|
|
251
|
+
throw error;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=session-inputs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-inputs.js","sourceRoot":"","sources":["../src/session-inputs.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { answerWriterGone, beginHandOff } from './session-delivery.js';
|
|
|
4
4
|
export async function handOffSessionMessages(messages, attendant, deps) {
|
|
5
5
|
const { sequencer } = deps;
|
|
6
6
|
const log = sequencer.log;
|
|
7
|
-
// The service lists messages in acceptance
|
|
7
|
+
// The service lists messages in immutable acceptance order, which is the
|
|
8
8
|
// User's order. Timestamps can tie and identifiers are random, so neither
|
|
9
9
|
// may reorder them: a later edit must never land before an earlier one.
|
|
10
10
|
for (const message of messages) {
|
|
@@ -26,6 +26,7 @@ export async function handOffSessionMessages(messages, attendant, deps) {
|
|
|
26
26
|
await handOff.finish('not-written');
|
|
27
27
|
switch (refusal.reason) {
|
|
28
28
|
case 'awaiting_earlier_answer':
|
|
29
|
+
case 'awaiting_earlier_message':
|
|
29
30
|
case 'attempt_pending':
|
|
30
31
|
case 'unavailable':
|
|
31
32
|
// Later messages keep their order behind this one.
|
|
@@ -36,6 +37,10 @@ export async function handOffSessionMessages(messages, attendant, deps) {
|
|
|
36
37
|
case 'not_claimable':
|
|
37
38
|
case 'not_found':
|
|
38
39
|
continue;
|
|
40
|
+
default: {
|
|
41
|
+
const unsupported = refusal.reason;
|
|
42
|
+
throw new Error(`Unsupported claim refusal: ${unsupported}`);
|
|
43
|
+
}
|
|
39
44
|
}
|
|
40
45
|
}
|
|
41
46
|
let owed = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-message-handoff.js","sourceRoot":"","sources":["../src/session-message-handoff.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,8BAA8B,EAAE,+BAA+B,EAAE,MAAM,4BAA4B,CAAA;AAC5G,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAsB,MAAM,uBAAuB,CAAA;AAmC1F,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,QAAsC,EACtC,SAA0B,EAC1B,IAAwB;IAExB,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;IAC1B,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAA;IACzB,
|
|
1
|
+
{"version":3,"file":"session-message-handoff.js","sourceRoot":"","sources":["../src/session-message-handoff.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
|
-
"package_version": "11.6.
|
|
3
|
+
"package_version": "11.6.1-beta.3",
|
|
4
4
|
"skill": "notifai",
|
|
5
|
-
"digest": "sha256:
|
|
5
|
+
"digest": "sha256:906a99db20da2ee59d8f742a939348a8ea1034bc64a9e37099583751a0bc8141",
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"path": "SKILL.md",
|
|
9
|
-
"sha256": "
|
|
9
|
+
"sha256": "2eb952db3a6042050efd46c7b8e5cf92f655aed0ed5e0d8b31840af580839e79"
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"path": "references/diagnostics.md",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "b58e15432b52e68fb9b1325255ca19a77a438dd31f130707366818959f82351c"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"path": "references/harness-setup.md",
|
|
17
|
-
"sha256": "
|
|
17
|
+
"sha256": "ff8a3219e92da67f0985de1ac992c73f18180b6d3694cc2b87e082dba4c5e8f8"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"path": "references/notes-and-edits.md",
|
|
21
|
-
"sha256": "
|
|
21
|
+
"sha256": "54b47b432f86e42ddc0ffee7822ed9f3ecdfc4d97e6318aa36ad90ccf1fd6738"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"path": "references/send-details.md",
|
|
@@ -92,16 +92,13 @@ without an exact Agent Session is a usage error. With an exact identifier:
|
|
|
92
92
|
notifai send --kind done \
|
|
93
93
|
--session-label "Account creation" \
|
|
94
94
|
--title "Users can now create accounts" \
|
|
95
|
-
--summary "Sign-up, verification, and login now work on staging."
|
|
96
|
-
--body "Sign-up, email verification, and login work end to end on staging. Next: password reset, unless you want something else first."
|
|
95
|
+
--summary "Sign-up, verification, and login now work on staging."
|
|
97
96
|
```
|
|
98
97
|
|
|
99
|
-
Without that identifier, omit `--session-label` and carry only Project context.
|
|
100
|
-
|
|
101
98
|
Outside a Project, or on a Projectless request, pass `--projectless`; it stops
|
|
102
99
|
cwd or config from inventing a Project.
|
|
103
100
|
|
|
104
|
-
`--kind` is required
|
|
101
|
+
`--kind` is required and controls insistence:
|
|
105
102
|
|
|
106
103
|
| kind | what it means | how it arrives |
|
|
107
104
|
| --- | --- | --- |
|
|
@@ -111,7 +108,7 @@ cwd or config from inventing a Project.
|
|
|
111
108
|
| `blocked` | no User reply would resume the work | attention tone |
|
|
112
109
|
| `question` | set for you by `--reply` and by `ask` — never pass it | attention tone |
|
|
113
110
|
|
|
114
|
-
**Declare the kind that is true
|
|
111
|
+
**Declare the kind that is true.**
|
|
115
112
|
|
|
116
113
|
Work needs a User response? [Ask an answerable question](#ask-a-question).
|
|
117
114
|
Use one-way blocked only when no User reply would resume the work.
|
|
@@ -132,14 +129,13 @@ Images (`--image`, referenced in Body as `media:1`), grouping, replacement,
|
|
|
132
129
|
and the User-owned `--sound`, `--level`, and `--device`:
|
|
133
130
|
[Sending details](references/send-details.md).
|
|
134
131
|
|
|
132
|
+
Without that identifier, omit `--session-label`.
|
|
135
133
|
Project and Agent Session are inferred; never pass `--session-id`.
|
|
136
134
|
`--session-label` is 2-6 words about the Agent Session, never the Project, branch,
|
|
137
135
|
status, result, identifier, hash, or filesystem path.
|
|
138
136
|
The initial name comes from the environment when available, then your label,
|
|
139
137
|
then a generated fallback. Repeat the same `--session-label` on sends and asks;
|
|
140
|
-
changing that flag does not rename an existing semantic name. A
|
|
141
|
-
name can replace a generated fallback. Companion Apps show the Account's current
|
|
142
|
-
label, including a User rename.
|
|
138
|
+
changing that flag does not rename an existing semantic name. A semantic name can replace a generated fallback; Companion Apps show the current Account label.
|
|
143
139
|
|
|
144
140
|
### Keep the Agent Session name current
|
|
145
141
|
|
|
@@ -147,12 +143,10 @@ At each change of job, check whether the current name still describes the work.
|
|
|
147
143
|
If the job changed completely enough that the old name would mislead the User,
|
|
148
144
|
run `notifai session rename "New job"` when starting the new job, without
|
|
149
145
|
waiting for a notification or User reminder. Keep the name for milestones,
|
|
150
|
-
ordinary progress, and same-job refinements.
|
|
151
|
-
indexing merits a rename; testing account creation does not.
|
|
146
|
+
ordinary progress, and same-job refinements. Rename for a new job, never its testing milestone.
|
|
152
147
|
|
|
153
|
-
The command updates the Account
|
|
154
|
-
|
|
155
|
-
prove the exact current Agent Session. A harness title change alone does not
|
|
148
|
+
The command updates the Account and local name; use it in later sends and asks.
|
|
149
|
+
It takes no Agent Session id: the active harness must prove the exact session. A harness title change alone does not
|
|
156
150
|
rename an existing Notifai semantic label.
|
|
157
151
|
|
|
158
152
|
## Ask a question
|
|
@@ -183,8 +177,8 @@ notifai ask "Which environment should I roll out to?" \
|
|
|
183
177
|
|
|
184
178
|
`--json` returns choice ids and `question_id`.
|
|
185
179
|
|
|
186
|
-
`registered: true`
|
|
187
|
-
|
|
180
|
+
`registered: true` confirms local registration only, not submission or
|
|
181
|
+
Provider Acceptance. Background submission starts immediately. Never call a question sent
|
|
188
182
|
or delivered from registration alone. Settlement adds `request_id`, keeping
|
|
189
183
|
`question_id`. Inspect:
|
|
190
184
|
|
|
@@ -195,9 +189,9 @@ notifai status <question_id> --json
|
|
|
195
189
|
States: `local`, `frozen`, `live`, `answered`, `withdrawn`, `retired`.
|
|
196
190
|
|
|
197
191
|
**Registering is not the end of the turn.** Ask in plain conversational text,
|
|
198
|
-
say what each answer will make you do,
|
|
199
|
-
|
|
200
|
-
neither path retires the other.
|
|
192
|
+
say what each answer will make you do, and continue independent work.
|
|
193
|
+
Submission does not wait for turn end; answer-dependent work waits for the reply.
|
|
194
|
+
A harness form can remain pending after a reply; neither path retires the other.
|
|
201
195
|
|
|
202
196
|
**Never say where the answer must arrive** ("tell me here"). The harness owns routing.
|
|
203
197
|
|
|
@@ -247,6 +241,11 @@ resume later. Never create a duplicate. On exit 0, act on the answer.
|
|
|
247
241
|
|
|
248
242
|
## When the answer arrives
|
|
249
243
|
|
|
244
|
+
When a wake-up names `notifai receive`, run that exact command
|
|
245
|
+
to read pending notes and answers together. An empty result means continue.
|
|
246
|
+
The wake-up contains no answer and needs no acknowledgement; never recover an
|
|
247
|
+
old answer from it. Hooks may have delivered the input already.
|
|
248
|
+
|
|
250
249
|
The latest reply is the user's current word: later choices correct earlier
|
|
251
250
|
ones; typed parts are read together in order. A relayed answer uses the chosen
|
|
252
251
|
label; `notifai replies <request_id> --json` has stable choice ids.
|
|
@@ -270,8 +269,8 @@ notifai acknowledge <request_id> --text "Rolling out to staging now; I'll report
|
|
|
270
269
|
Keep it under 200 characters and name only the concrete work their reply
|
|
271
270
|
causes: it is a receipt, not a report.
|
|
272
271
|
|
|
273
|
-
If
|
|
274
|
-
|
|
272
|
+
If written replies are off, run the printed command without `--text`.
|
|
273
|
+
Acknowledgement is required.
|
|
275
274
|
|
|
276
275
|
Then resume the committed work without asking them to confirm again; it is
|
|
277
276
|
work you are resuming, not approval you received.
|
|
@@ -22,7 +22,7 @@ hook never ran.
|
|
|
22
22
|
`hook.gate` records carry a fixed `reason` — `notifications-off`,
|
|
23
23
|
`claimed-elsewhere`, `no-question`, `no-session`, `answered`,
|
|
24
24
|
`acknowledgement-required`, `acknowledgement-abandoned`, `harness-cannot-continue`,
|
|
25
|
-
`continuation-
|
|
25
|
+
`continuation-limit`, `delivery-limit`, `proceeding` —
|
|
26
26
|
so filter on that, never on the wording of a message. `notifications-off` is
|
|
27
27
|
the one the user deliberately never sees, which is why it is worth ruling out
|
|
28
28
|
before concluding anything is broken.
|
|
@@ -127,12 +127,17 @@ shell. Do not strip markers or borrow another Agent Session's identity to make
|
|
|
127
127
|
skill and guidance as the new Notification Request owner.
|
|
128
128
|
- **Codex:** run `notifai hooks install --harness codex`. If `hooks-trust`
|
|
129
129
|
fails, open `/hooks` in Codex and approve or enable the Notifai handlers.
|
|
130
|
-
The synchronous `PostToolUse` handler delivers Session Notes and Answer Edits
|
|
130
|
+
The synchronous `PostToolUse` handler delivers pending answers, Session Notes and Answer Edits
|
|
131
131
|
after tools during an active turn. Install and approve that handler, then
|
|
132
132
|
start a fresh Agent Session to use the new attendant and hook definitions.
|
|
133
133
|
Busy delivery starts after that exact session first runs the trusted hook;
|
|
134
|
-
until then, and while idle,
|
|
134
|
+
until then, and while idle, the native queue carries a wake-up to read current
|
|
135
|
+
pending input. It never carries note or answer text. A running tool must
|
|
135
136
|
return before its hook runs.
|
|
137
|
+
Automatic goal continuations are observed at their first trusted tool
|
|
138
|
+
callback even when the harness emits no prompt hook. Notes still need an
|
|
139
|
+
available callback; a long tool or uninterrupted reasoning cannot be cut
|
|
140
|
+
short by this route.
|
|
136
141
|
Then start one fresh Agent Session, send one prompt, and run `notifai doctor`. If
|
|
137
142
|
SessionStart is absent, reinstall the current hooks and start a fresh Agent Session;
|
|
138
143
|
UserPromptSubmit does not activate it. Codex SubagentStart uses the same
|
|
@@ -185,7 +190,7 @@ shell. Do not strip markers or borrow another Agent Session's identity to make
|
|
|
185
190
|
On macOS, the loaded Gateway service can route an asynchronous `notifai ask` answer
|
|
186
191
|
into the same Agent Session after the asking turn ends. It queues a pointer
|
|
187
192
|
through OpenClaw's followup route; run `notifai replies <id>` from that
|
|
188
|
-
session to read the answer and `notifai acknowledge <id>`
|
|
193
|
+
session to read the answer and `notifai acknowledge <id>` before acting on it.
|
|
189
194
|
Question Routing requires the current generation marker, an enabled Project,
|
|
190
195
|
and a local Gateway whose CLI version and process identity match the plugin.
|
|
191
196
|
If this Project is disabled, run `notifai project enable` before `notifai ask`.
|
|
@@ -216,7 +221,8 @@ shell. Do not strip markers or borrow another Agent Session's identity to make
|
|
|
216
221
|
a Note may interrupt a working turn. The plugin checks the current session
|
|
217
222
|
before each write, and the agent must acknowledge the message. An attended
|
|
218
223
|
classic CLI session can route an `ask` answer into that same live session;
|
|
219
|
-
|
|
224
|
+
keep Hermes running for the answer window. Submission starts immediately;
|
|
225
|
+
the plugin owns answer delivery. If the
|
|
220
226
|
process exits first, it does not cold-resume and the answer is not delivered.
|
|
221
227
|
TUI, gateway, API, ACP, remote terminal backends, and Windows remain outside
|
|
222
228
|
this proven cell.
|
|
@@ -240,28 +246,30 @@ reports each harness's supported route separately.
|
|
|
240
246
|
The session that registered a question owns the answer's return. The last
|
|
241
247
|
meter differs per harness:
|
|
242
248
|
|
|
243
|
-
- **Claude Code on POSIX:**
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
+
- **Claude Code on POSIX:** a detached observer starts after submission and
|
|
250
|
+
waits out of band for the complete answer window. The resident Session
|
|
251
|
+
Attendant sends wakes with Claude's required child-process ancestry. Stop
|
|
252
|
+
can recover answer ownership without holding the turn. When the
|
|
253
|
+
answer arrives it is stored with the session's pending inputs. Its own inbox
|
|
254
|
+
socket receives a wake-up: an idle Agent Session starts a new turn, and a busy
|
|
255
|
+
one receives it when its current turn ends. The prompt hook or the named
|
|
256
|
+
`notifai receive` command drains the current notes and answers together.
|
|
257
|
+
An Agent Session that is provably gone is cold-resumed with the wake-up
|
|
249
258
|
instead — never one whose liveness probe cannot rule it out.
|
|
250
259
|
- **Claude Code on Windows:** the Stop hook stays held through the complete
|
|
251
260
|
answer window. When the answer arrives it returns `decision: block`, starting
|
|
252
261
|
the successor turn in the same Agent Session without another User prompt.
|
|
253
262
|
Direct inbox wake is unavailable, but it is not needed while this exact Stop
|
|
254
263
|
continuation owns the answer.
|
|
255
|
-
- **Codex:**
|
|
256
|
-
background for the complete answer window. When an answer arrives, Notifai
|
|
264
|
+
- **Codex:** a detached observer starts after submission and waits in the
|
|
265
|
+
background for the complete answer window; Stop provides recovery. When an answer arrives, Notifai
|
|
257
266
|
invokes `codex queue` for the exact Agent Session in the same Codex home.
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
prompt, producing two copies.
|
|
267
|
+
Only a wake-up is queued. Pending notes and answers remain in Notifai until
|
|
268
|
+
a trusted tool hook, prompt hook, or `notifai receive` drains a bounded batch.
|
|
269
|
+
A late wake-up cannot repeat an acknowledged answer: it contains no answer
|
|
270
|
+
text. Queue success proves wake storage, not input presentation. Inputs are
|
|
271
|
+
claimed immediately before presentation; uncertain writes are never replayed.
|
|
272
|
+
Keep the original question and request identities when investigating a delay.
|
|
265
273
|
- **Grok:** the Stop hook stays held through the complete answer window and
|
|
266
274
|
returns the answer as a decision block to the same Agent Session. Its native
|
|
267
275
|
`stopHookActive` flag on the successor Stop confirms consumption. There is no
|
|
@@ -270,25 +278,22 @@ meter differs per harness:
|
|
|
270
278
|
owner process or its route fails. It is not the normal last meter for an
|
|
271
279
|
unexpired question.
|
|
272
280
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
`ask` an immediate-send command or remove the installed Stop requirement.
|
|
281
|
+
`ask` durably registers the question and immediately launches submission. It
|
|
282
|
+
does not wait for Stop or hold the command for the answer window. Stop and
|
|
283
|
+
UserPromptSubmit recover outstanding work; they are not required to begin
|
|
284
|
+
normal submission. Registration is not evidence of Provider Acceptance.
|
|
278
285
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
result. Otherwise settle or explicitly transfer supervision before an `ask`
|
|
284
|
-
handoff. Ending a turn neither completes delegated work nor transfers ownership.
|
|
286
|
+
Continue independent work and supervision while the question is outstanding.
|
|
287
|
+
Only answer-dependent work waits. Delivery into the agent still follows the
|
|
288
|
+
harness boundaries above; immediate submission does not make every harness
|
|
289
|
+
able to inject an answer during a running turn.
|
|
285
290
|
|
|
286
291
|
Keep the original identity when an answer has not arrived. Queue acceptance
|
|
287
292
|
does not prove consumption, and expiry, retirement, or recovery failure can
|
|
288
293
|
prevent resumption. Inspect `status` and `replies` instead of re-asking.
|
|
289
294
|
|
|
290
295
|
At the `ask_grace_seconds` default of `0`, the question reaches devices as soon
|
|
291
|
-
as
|
|
296
|
+
as registration starts background submission. A positive value keeps it in the terminal for that
|
|
292
297
|
long first, so an answer typed there wins without a notification ever leaving.
|
|
293
298
|
`reply_window_seconds` then controls how long the answer is accepted and how
|
|
294
299
|
long Question Routing keeps an exact return path to this Agent Session. The
|
|
@@ -352,8 +357,9 @@ Those are three different controls and only the last one decides whether an
|
|
|
352
357
|
answer is still wanted. Question Routing owns that complete window. Claude Code
|
|
353
358
|
waits out of band and wakes the Agent Session on POSIX; on Windows its Stop
|
|
354
359
|
stays held and returns the answer as the same Agent Session's continuation,
|
|
355
|
-
while Codex queues
|
|
356
|
-
|
|
360
|
+
while Codex queues a wake-up into its Agent Session's durable inbox. Codex and
|
|
361
|
+
POSIX Claude keep pending input locally until a foreground drain; the native
|
|
362
|
+
wake never stores a second copy of the User's answer.
|
|
357
363
|
|
|
358
364
|
`NOTIFAI_NO_INPUT=1` guarantees no command will ever prompt, which is what you
|
|
359
365
|
want in CI or any shell with nobody at it. `NOTIFAI_CREDENTIALS=file` stores the
|