@empirical-gauzza/cli 1.0.11 → 1.0.12

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.
@@ -217,16 +217,13 @@ function main() {
217
217
  main();
218
218
  `;
219
219
 
220
- // Claude-only variant of the Stop reminder above. Claude Code's Stop hook contract is the one
221
- // platform of the three we've actually confirmed supports safe forced-continuation: exit code 2
222
- // feeds stderr back to Claude as the reason and blocks the stop, and the stop_hook_active field on
223
- // the next invocation's stdin payload tells us a forced-continuation already happened for this
224
- // turn (Claude sets it specifically so a hook can avoid re-blocking and trapping the session in a
225
- // loop). EMPIRICAL_HOOK_STOP_SOURCE above already reads stop_hook_active defensively but never
226
- // blocks, so on Claude the reminder was silently logged and never reached the model - this variant
227
- // is the same script with the loop guard actually load-bearing: block once per turn, never twice.
228
- // Codex/Copilot keep using the silent EMPIRICAL_HOOK_STOP_SOURCE until their own Stop/agentStop
229
- // blocking semantics are confirmed against source the way Claude's was here.
220
+ // Claude-only variant of the Stop reminder above. hookSpecificOutput.additionalContext (stdout,
221
+ // exit 0) is Claude Code's non-blocking Stop-hook feedback channel: the text is fed into context
222
+ // and the conversation continues, same outcome the earlier exit-2 approach achieved, but the
223
+ // transcript UI renders it as a plain system reminder instead of a red "Stop hook error" line.
224
+ // EMPIRICAL_HOOK_STOP_SOURCE above still uses plain console.log + exit 0, which Claude Code treats
225
+ // as non-blocking output that's logged but never reaches the model - that was this hook's original
226
+ // bug (fixed for Claude here, unconfirmed/unfixed for Codex/Copilot's own Stop/agentStop semantics).
230
227
  const CLAUDE_HOOK_STOP_SOURCE = `#!/usr/bin/env node
231
228
  'use strict';
232
229
 
@@ -264,22 +261,25 @@ function main() {
264
261
  var payload = readStdinPayload();
265
262
 
266
263
  // stop_hook_active === true means Claude is re-invoking this hook because a PRIOR Stop hook
267
- // (possibly this same one) already forced a continuation this turn. Blocking again here would
268
- // trap the session in a forced-continuation loop, so this is the one case that must always exit
269
- // 0 with no reminder, unconditionally.
264
+ // (possibly this same one) already surfaced additionalContext and forced a continuation this
265
+ // turn. additionalContext causes the same forced-continuation behavior decision:block does -
266
+ // confirmed empirically: without this guard the hook re-fired every ~2-3s in an infinite loop,
267
+ // since each additionalContext output triggers another Stop event. Must exit 0 with no output
268
+ // here, unconditionally, or the loop continues.
270
269
  if (payload && payload.stop_hook_active === true) {
271
- appendLog('stop_hook_active=true, skipping reminder (already blocked once this turn)');
270
+ appendLog('stop_hook_active=true, skipping reminder (already surfaced once this turn)');
272
271
  process.exit(0);
273
272
  }
274
273
 
275
- appendLog('stop hook fired (pid=' + process.pid + ', platform=' + process.platform + '), blocking once to surface reminder');
274
+ appendLog('stop hook fired (pid=' + process.pid + ', platform=' + process.platform + '), surfacing reminder via additionalContext');
276
275
 
277
- // Exit 2 is Claude Code's documented Stop-hook blocking signal: stderr is fed back to Claude as
278
- // context and the turn is forced to continue instead of ending, which is what actually gets this
279
- // reminder read (a plain stdout console.log + exit 0 is only logged, never seen by the model -
280
- // this was this hook's exact original bug).
281
- process.stderr.write('[Empirical reminder] Before finishing: if this turn included a completed decision, a corrected mistake, or meaningful work worth remembering, record it now via the empirical-memory skill or \`empirical memory record\` - do not wait to be asked.\\n');
282
- process.exit(2);
276
+ process.stdout.write(JSON.stringify({
277
+ hookSpecificOutput: {
278
+ hookEventName: 'Stop',
279
+ additionalContext: '[Empirical] Record memory-worthy work now via empirical-memory skill.'
280
+ }
281
+ }) + '\\n');
282
+ process.exit(0);
283
283
  }
284
284
 
285
285
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empirical-gauzza/cli",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "Empirical CLI installer and local MCP wiring helper",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",