@scotthamilton77/sidekick 0.1.9 → 0.1.11

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 (3) hide show
  1. package/dist/bin.js +327 -132
  2. package/dist/daemon.js +336 -131
  3. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -1098,6 +1098,7 @@ var require_events = __commonJS({
1098
1098
  "reminder:unstaged",
1099
1099
  "reminder:consumed",
1100
1100
  "reminder:cleared",
1101
+ "reminder:not-staged",
1101
1102
  // Decision events
1102
1103
  "decision:recorded",
1103
1104
  // Session summary events
@@ -1146,6 +1147,7 @@ var require_events = __commonJS({
1146
1147
  "reminder:unstaged": "timeline",
1147
1148
  "reminder:consumed": "timeline",
1148
1149
  "reminder:cleared": "timeline",
1150
+ "reminder:not-staged": "log",
1149
1151
  "decision:recorded": "timeline",
1150
1152
  "session-summary:start": "timeline",
1151
1153
  "session-summary:finish": "timeline",
@@ -45865,7 +45867,10 @@ var require_structured_logging = __commonJS({
45865
45867
  hookName: state.hookName,
45866
45868
  blocking: state.blocking,
45867
45869
  priority: state.priority,
45868
- persistent: state.persistent
45870
+ persistent: state.persistent,
45871
+ ...state.reason !== void 0 && { reason: state.reason },
45872
+ ...state.triggeredBy !== void 0 && { triggeredBy: state.triggeredBy },
45873
+ ...state.thresholdState !== void 0 && { thresholdState: state.thresholdState }
45869
45874
  }
45870
45875
  };
45871
45876
  },
@@ -46162,8 +46167,8 @@ var require_structured_logging = __commonJS({
46162
46167
  },
46163
46168
  // --- Error Events ---
46164
46169
  /**
46165
- * Create an ErrorOccurred event (logged when error/fatal level log is emitted).
46166
- * Emitted automatically by HookableLogger hook no manual call-site changes needed.
46170
+ * Create a daemon ErrorOccurred event.
46171
+ * @see packages/sidekick-daemon/src/daemon.ts HookableLogger error hook calls this factory.
46167
46172
  */
46168
46173
  daemonErrorOccurred(context, state) {
46169
46174
  return {
@@ -46182,6 +46187,28 @@ var require_structured_logging = __commonJS({
46182
46187
  errorStack: state.errorStack
46183
46188
  }
46184
46189
  };
46190
+ },
46191
+ /**
46192
+ * Create a CLI ErrorOccurred event.
46193
+ * Available for CLI error hook implementations.
46194
+ */
46195
+ cliErrorOccurred(context, state) {
46196
+ return {
46197
+ type: "error:occurred",
46198
+ time: Date.now(),
46199
+ source: "cli",
46200
+ context: {
46201
+ sessionId: context.sessionId,
46202
+ correlationId: context.correlationId,
46203
+ traceId: context.traceId,
46204
+ hook: context.hook,
46205
+ taskId: context.taskId
46206
+ },
46207
+ payload: {
46208
+ errorMessage: state.errorMessage,
46209
+ errorStack: state.errorStack
46210
+ }
46211
+ };
46185
46212
  }
46186
46213
  };
46187
46214
  function logEvent(logger, event) {
@@ -58137,24 +58164,20 @@ var require_staging_paths = __commonJS({
58137
58164
  function getReminderPath(stateDir, sessionId, hookName, reminderName) {
58138
58165
  return (0, node_path_1.join)(getHookDir(stateDir, sessionId, hookName), `${reminderName}.json`);
58139
58166
  }
58140
- function isValidPathSegment(segment) {
58141
- if (!segment)
58167
+ function isValidPathSegment(s) {
58168
+ if (s === "")
58142
58169
  return false;
58143
- if (segment.includes("..") || segment.includes("/") || segment.includes("\\"))
58170
+ if (s === "." || s === "..")
58144
58171
  return false;
58145
- if (segment.startsWith("."))
58172
+ if (s.includes("/") || s.includes("\\"))
58146
58173
  return false;
58147
- return true;
58174
+ if ((0, node_path_1.basename)(s) !== s)
58175
+ return false;
58176
+ return /^[a-zA-Z0-9._-]+$/.test(s);
58148
58177
  }
58149
58178
  function validatePathSegment(segment, name) {
58150
- if (!segment) {
58151
- throw new Error(`${name} cannot be empty`);
58152
- }
58153
- if (segment.includes("..") || segment.includes("/") || segment.includes("\\")) {
58154
- throw new Error(`Invalid ${name}: path traversal characters not allowed`);
58155
- }
58156
- if (segment.startsWith(".")) {
58157
- throw new Error(`Invalid ${name}: cannot start with '.'`);
58179
+ if (!isValidPathSegment(segment)) {
58180
+ throw new Error(`Invalid ${name}: must be a non-empty alphanumeric string without path separators`);
58158
58181
  }
58159
58182
  }
58160
58183
  exports2.CONSUMED_FILE_PATTERN = /\.\d+\.json$/;
@@ -58228,7 +58251,7 @@ var require_staging_service = __commonJS({
58228
58251
  *
58229
58252
  * @throws Error if hookName or reminderName contain path traversal characters
58230
58253
  */
58231
- async stageReminder(sessionId, hookName, reminderName, data) {
58254
+ async stageReminder(sessionId, hookName, reminderName, data, enrichment) {
58232
58255
  (0, staging_paths_js_1.validatePathSegment)(hookName, "hookName");
58233
58256
  (0, staging_paths_js_1.validatePathSegment)(reminderName, "reminderName");
58234
58257
  const hookDir = this.getHookDirPath(sessionId, hookName);
@@ -58257,9 +58280,10 @@ var require_staging_service = __commonJS({
58257
58280
  hookName,
58258
58281
  blocking: data.blocking,
58259
58282
  priority: data.priority,
58260
- persistent: data.persistent
58283
+ persistent: data.persistent,
58284
+ ...enrichment
58261
58285
  }, { stagingPath: reminderPath });
58262
- (0, structured_logging_1.logEvent)(this.options.logger, event);
58286
+ (0, structured_logging_1.logEvent)(this.options.logger.child({ context: { sessionId } }), event);
58263
58287
  }
58264
58288
  /**
58265
58289
  * Read a staged reminder.
@@ -58401,8 +58425,8 @@ var require_staging_service = __commonJS({
58401
58425
  // ============================================================================
58402
58426
  // StagingService Interface Implementation (delegates to core)
58403
58427
  // ============================================================================
58404
- async stageReminder(hookName, reminderName, data) {
58405
- return this.core.stageReminder(this.sessionId, hookName, reminderName, data);
58428
+ async stageReminder(hookName, reminderName, data, enrichment) {
58429
+ return this.core.stageReminder(this.sessionId, hookName, reminderName, data, enrichment);
58406
58430
  }
58407
58431
  async readReminder(hookName, reminderName) {
58408
58432
  return this.core.readReminder(this.sessionId, hookName, reminderName);
@@ -71350,8 +71374,8 @@ var require_reminder_utils = __commonJS({
71350
71374
  return null;
71351
71375
  }
71352
71376
  }
71353
- async function stageReminder(ctx, hookName, reminder) {
71354
- await ctx.staging.stageReminder(hookName, reminder.name, reminder);
71377
+ async function stageReminder(ctx, hookName, reminder, enrichment) {
71378
+ await ctx.staging.stageReminder(hookName, reminder.name, reminder, enrichment);
71355
71379
  ctx.logger.debug("Staged reminder", { hookName, reminderName: reminder.name, priority: reminder.priority });
71356
71380
  }
71357
71381
  async function consumeReminder(ctx, hookName) {
@@ -71897,13 +71921,125 @@ var require_stage_default_user_prompt = __commonJS({
71897
71921
  }
71898
71922
  });
71899
71923
 
71924
+ // ../feature-reminders/dist/events.js
71925
+ var require_events2 = __commonJS({
71926
+ "../feature-reminders/dist/events.js"(exports2) {
71927
+ "use strict";
71928
+ Object.defineProperty(exports2, "__esModule", { value: true });
71929
+ exports2.ReminderEvents = void 0;
71930
+ exports2.ReminderEvents = {
71931
+ /**
71932
+ * Create a ReminderConsumed event (logged when CLI returns a staged reminder).
71933
+ */
71934
+ reminderConsumed(context, state, _metadata) {
71935
+ return {
71936
+ type: "reminder:consumed",
71937
+ time: Date.now(),
71938
+ source: "cli",
71939
+ context: {
71940
+ sessionId: context.sessionId,
71941
+ correlationId: context.correlationId,
71942
+ traceId: context.traceId,
71943
+ hook: context.hook,
71944
+ taskId: context.taskId
71945
+ },
71946
+ payload: {
71947
+ reminderName: state.reminderName,
71948
+ reminderReturned: state.reminderReturned,
71949
+ blocking: state.blocking,
71950
+ priority: state.priority,
71951
+ persistent: state.persistent,
71952
+ ...state.classificationResult !== void 0 && {
71953
+ classificationResult: state.classificationResult
71954
+ }
71955
+ }
71956
+ };
71957
+ },
71958
+ // Note: reminderStaged stays in @sidekick/core (used by staging-service.ts, circular dep)
71959
+ /**
71960
+ * Create a ReminderUnstaged event (logged when a reminder is removed from staging).
71961
+ */
71962
+ reminderUnstaged(context, state) {
71963
+ return {
71964
+ type: "reminder:unstaged",
71965
+ time: Date.now(),
71966
+ source: "daemon",
71967
+ context: {
71968
+ sessionId: context.sessionId,
71969
+ correlationId: context.correlationId,
71970
+ traceId: context.traceId,
71971
+ hook: context.hook,
71972
+ taskId: context.taskId
71973
+ },
71974
+ payload: {
71975
+ reminderName: state.reminderName,
71976
+ hookName: state.hookName,
71977
+ reason: state.reason,
71978
+ ...state.triggeredBy !== void 0 && { triggeredBy: state.triggeredBy },
71979
+ ...state.toolState !== void 0 && { toolState: state.toolState }
71980
+ }
71981
+ };
71982
+ },
71983
+ /**
71984
+ * Create a RemindersCleared event (logged when staging directory is cleaned).
71985
+ */
71986
+ remindersCleared(context, state, reason) {
71987
+ return {
71988
+ type: "reminder:cleared",
71989
+ time: Date.now(),
71990
+ source: "daemon",
71991
+ context: {
71992
+ sessionId: context.sessionId,
71993
+ correlationId: context.correlationId,
71994
+ traceId: context.traceId,
71995
+ hook: context.hook,
71996
+ taskId: context.taskId
71997
+ },
71998
+ payload: {
71999
+ clearedCount: state.clearedCount,
72000
+ hookNames: state.hookNames,
72001
+ reason
72002
+ }
72003
+ };
72004
+ },
72005
+ /**
72006
+ * Create a ReminderNotStaged event (logged when daemon evaluates but decides not to stage).
72007
+ */
72008
+ reminderNotStaged(context, state) {
72009
+ return {
72010
+ type: "reminder:not-staged",
72011
+ time: Date.now(),
72012
+ source: "daemon",
72013
+ context: {
72014
+ sessionId: context.sessionId,
72015
+ correlationId: context.correlationId,
72016
+ traceId: context.traceId,
72017
+ hook: context.hook,
72018
+ taskId: context.taskId
72019
+ },
72020
+ payload: {
72021
+ reminderName: state.reminderName,
72022
+ hookName: state.hookName,
72023
+ reason: state.reason,
72024
+ ...state.threshold !== void 0 && { threshold: state.threshold },
72025
+ ...state.currentValue !== void 0 && { currentValue: state.currentValue },
72026
+ ...state.triggeredBy !== void 0 && { triggeredBy: state.triggeredBy }
72027
+ }
72028
+ };
72029
+ }
72030
+ };
72031
+ }
72032
+ });
72033
+
71900
72034
  // ../feature-reminders/dist/handlers/staging/stage-pause-and-reflect.js
71901
72035
  var require_stage_pause_and_reflect = __commonJS({
71902
72036
  "../feature-reminders/dist/handlers/staging/stage-pause-and-reflect.js"(exports2) {
71903
72037
  "use strict";
71904
72038
  Object.defineProperty(exports2, "__esModule", { value: true });
71905
72039
  exports2.registerStagePauseAndReflect = registerStagePauseAndReflect;
72040
+ var core_1 = require_dist4();
71906
72041
  var types_1 = require_dist();
72042
+ var events_js_1 = require_events2();
71907
72043
  var staging_handler_utils_js_1 = require_staging_handler_utils();
71908
72044
  var types_js_1 = require_types2();
71909
72045
  var state_js_1 = require_state4();
@@ -71917,15 +72053,17 @@ var require_stage_pause_and_reflect = __commonJS({
71917
72053
  return void 0;
71918
72054
  const metrics = event.metadata.metrics;
71919
72055
  const sessionId = event.context?.sessionId;
72056
+ if (!sessionId) {
72057
+ ctx.logger.warn("[stage-pause-and-reflect] No sessionId available, skipping");
72058
+ return void 0;
72059
+ }
71920
72060
  const featureConfig = context.config.getFeature("reminders");
71921
72061
  const config = { ...types_js_1.DEFAULT_REMINDERS_SETTINGS, ...featureConfig.settings };
71922
72062
  let prBaseline = null;
71923
- if (sessionId) {
71924
- const remindersState = (0, state_js_1.createRemindersState)(ctx.stateService);
71925
- const result = await remindersState.prBaseline.read(sessionId);
71926
- if (result.source !== "default") {
71927
- prBaseline = result.data;
71928
- }
72063
+ const remindersState = (0, state_js_1.createRemindersState)(ctx.stateService);
72064
+ const result = await remindersState.prBaseline.read(sessionId);
72065
+ if (result.source !== "default") {
72066
+ prBaseline = result.data;
71929
72067
  }
71930
72068
  let effectiveBaseline = 0;
71931
72069
  if (prBaseline && prBaseline.turnCount === metrics.turnCount) {
@@ -71937,12 +72075,28 @@ var require_stage_pause_and_reflect = __commonJS({
71937
72075
  effectiveBaseline = Math.max(effectiveBaseline, lastConsumed.stagedAt.toolsThisTurn);
71938
72076
  }
71939
72077
  const shouldReactivate = metrics.turnCount > lastConsumed.stagedAt.turnCount || metrics.toolsThisTurn >= effectiveBaseline + config.pause_and_reflect_threshold;
71940
- if (!shouldReactivate)
72078
+ if (!shouldReactivate) {
72079
+ (0, core_1.logEvent)(ctx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
72080
+ reminderName: "pause-and-reflect",
72081
+ hookName: "PreToolUse",
72082
+ reason: "same_turn",
72083
+ triggeredBy: "tool_result"
72084
+ }));
71941
72085
  return void 0;
72086
+ }
71942
72087
  }
71943
72088
  const toolsSinceBaseline = metrics.toolsThisTurn - effectiveBaseline;
71944
- if (toolsSinceBaseline < config.pause_and_reflect_threshold)
72089
+ if (toolsSinceBaseline < config.pause_and_reflect_threshold) {
72090
+ (0, core_1.logEvent)(ctx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
72091
+ reminderName: "pause-and-reflect",
72092
+ hookName: "PreToolUse",
72093
+ reason: "below_threshold",
72094
+ threshold: config.pause_and_reflect_threshold,
72095
+ currentValue: toolsSinceBaseline,
72096
+ triggeredBy: "tool_result"
72097
+ }));
71945
72098
  return void 0;
72099
+ }
71946
72100
  return {
71947
72101
  reminderId: types_js_1.ReminderIds.PAUSE_AND_REFLECT,
71948
72102
  targetHook: "PreToolUse",
@@ -73472,86 +73626,6 @@ var require_picomatch2 = __commonJS({
73472
73626
  }
73473
73627
  });
73474
73628
 
73475
- // ../feature-reminders/dist/events.js
73476
- var require_events2 = __commonJS({
73477
- "../feature-reminders/dist/events.js"(exports2) {
73478
- "use strict";
73479
- Object.defineProperty(exports2, "__esModule", { value: true });
73480
- exports2.ReminderEvents = void 0;
73481
- exports2.ReminderEvents = {
73482
- /**
73483
- * Create a ReminderConsumed event (logged when CLI returns a staged reminder).
73484
- */
73485
- reminderConsumed(context, state, _metadata) {
73486
- return {
73487
- type: "reminder:consumed",
73488
- time: Date.now(),
73489
- source: "cli",
73490
- context: {
73491
- sessionId: context.sessionId,
73492
- correlationId: context.correlationId,
73493
- traceId: context.traceId,
73494
- hook: context.hook,
73495
- taskId: context.taskId
73496
- },
73497
- payload: {
73498
- reminderName: state.reminderName,
73499
- reminderReturned: state.reminderReturned,
73500
- blocking: state.blocking,
73501
- priority: state.priority,
73502
- persistent: state.persistent
73503
- }
73504
- };
73505
- },
73506
- // Note: reminderStaged stays in @sidekick/core (used by staging-service.ts, circular dep)
73507
- /**
73508
- * Create a ReminderUnstaged event (logged when a reminder is removed from staging).
73509
- */
73510
- reminderUnstaged(context, state) {
73511
- return {
73512
- type: "reminder:unstaged",
73513
- time: Date.now(),
73514
- source: "daemon",
73515
- context: {
73516
- sessionId: context.sessionId,
73517
- correlationId: context.correlationId,
73518
- traceId: context.traceId,
73519
- hook: context.hook,
73520
- taskId: context.taskId
73521
- },
73522
- payload: {
73523
- reminderName: state.reminderName,
73524
- hookName: state.hookName,
73525
- reason: state.reason
73526
- }
73527
- };
73528
- },
73529
- /**
73530
- * Create a RemindersCleared event (logged when staging directory is cleaned).
73531
- */
73532
- remindersCleared(context, state, reason) {
73533
- return {
73534
- type: "reminder:cleared",
73535
- time: Date.now(),
73536
- source: "daemon",
73537
- context: {
73538
- sessionId: context.sessionId,
73539
- correlationId: context.correlationId,
73540
- traceId: context.traceId,
73541
- hook: context.hook,
73542
- taskId: context.taskId
73543
- },
73544
- payload: {
73545
- clearedCount: state.clearedCount,
73546
- hookNames: state.hookNames,
73547
- reason
73548
- }
73549
- };
73550
- }
73551
- };
73552
- }
73553
- });
73554
-
73555
73629
  // ../feature-reminders/dist/tool-pattern-matcher.js
73556
73630
  var require_tool_pattern_matcher = __commonJS({
73557
73631
  "../feature-reminders/dist/tool-pattern-matcher.js"(exports2) {
@@ -73659,22 +73733,48 @@ var require_track_verification_tools = __commonJS({
73659
73733
  }
73660
73734
  });
73661
73735
  }
73662
- async function stageToolsForFiles(filePaths, daemonCtx, sessionId, verificationTools, toolsState, remindersState) {
73736
+ async function stageToolsForFiles(filePaths, daemonCtx, sessionId, verificationTools, toolsState, remindersState, triggeredBy = "file_edit") {
73663
73737
  const existingReminders = await daemonCtx.staging.listReminders("Stop");
73664
73738
  const stagedNames = new Set(existingReminders.map((r) => r.name));
73665
73739
  let anyStaged = false;
73740
+ const emittedNotStaged = /* @__PURE__ */ new Set();
73666
73741
  for (const filePath of filePaths) {
73667
73742
  for (const [toolName, toolConfig] of Object.entries(verificationTools)) {
73668
- if (!toolConfig.enabled)
73669
- continue;
73670
73743
  const reminderId = TOOL_REMINDER_MAP[toolName];
73671
73744
  if (!reminderId)
73672
73745
  continue;
73673
- if (!picomatch_1.default.isMatch(filePath, toolConfig.clearing_patterns))
73746
+ if (!toolConfig.enabled) {
73747
+ const emitKey = `${reminderId}:feature_disabled`;
73748
+ if (!emittedNotStaged.has(emitKey)) {
73749
+ emittedNotStaged.add(emitKey);
73750
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
73751
+ reminderName: reminderId,
73752
+ hookName: "Stop",
73753
+ reason: "feature_disabled",
73754
+ triggeredBy
73755
+ }));
73756
+ }
73757
+ continue;
73758
+ }
73759
+ if (!picomatch_1.default.isMatch(filePath, toolConfig.clearing_patterns)) {
73760
+ const emitKey = `${reminderId}:pattern_mismatch`;
73761
+ if (!emittedNotStaged.has(emitKey)) {
73762
+ emittedNotStaged.add(emitKey);
73763
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
73764
+ reminderName: reminderId,
73765
+ hookName: "Stop",
73766
+ reason: "pattern_mismatch",
73767
+ triggeredBy
73768
+ }));
73769
+ }
73674
73770
  continue;
73771
+ }
73675
73772
  const current = toolsState[toolName];
73676
73773
  if (!current || current.status === "staged") {
73677
- const staged = await ensureToolReminderStaged(daemonCtx, reminderId, stagedNames);
73774
+ const staged = await ensureToolReminderStaged(daemonCtx, reminderId, stagedNames, {
73775
+ reason: current ? "re-staged" : "initial",
73776
+ triggeredBy: "file_edit"
73777
+ });
73678
73778
  if (staged) {
73679
73779
  if (!current) {
73680
73780
  toolsState[toolName] = {
@@ -73690,7 +73790,11 @@ var require_track_verification_tools = __commonJS({
73690
73790
  } else {
73691
73791
  const newEdits = current.editsSinceVerified + 1;
73692
73792
  if (newEdits >= toolConfig.clearing_threshold) {
73693
- const staged = await ensureToolReminderStaged(daemonCtx, reminderId, stagedNames);
73793
+ const staged = await ensureToolReminderStaged(daemonCtx, reminderId, stagedNames, {
73794
+ reason: "threshold_reached",
73795
+ triggeredBy: "file_edit",
73796
+ thresholdState: { current: newEdits, threshold: toolConfig.clearing_threshold }
73797
+ });
73694
73798
  if (staged) {
73695
73799
  toolsState[toolName] = {
73696
73800
  ...current,
@@ -73707,6 +73811,14 @@ var require_track_verification_tools = __commonJS({
73707
73811
  status: "cooldown",
73708
73812
  editsSinceVerified: newEdits
73709
73813
  };
73814
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
73815
+ reminderName: reminderId,
73816
+ hookName: "Stop",
73817
+ reason: "below_threshold",
73818
+ threshold: toolConfig.clearing_threshold,
73819
+ currentValue: newEdits,
73820
+ triggeredBy
73821
+ }));
73710
73822
  }
73711
73823
  }
73712
73824
  }
@@ -73752,7 +73864,16 @@ var require_track_verification_tools = __commonJS({
73752
73864
  lastMatchedScope: match.scope
73753
73865
  };
73754
73866
  await daemonCtx.staging.deleteReminder("Stop", reminderId);
73755
- (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, { reminderName: reminderId, hookName: "Stop", reason: "tool_verified" }));
73867
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
73868
+ reminderName: reminderId,
73869
+ hookName: "Stop",
73870
+ reason: "tool_verified",
73871
+ triggeredBy: "verification_passed",
73872
+ toolState: {
73873
+ status: toolsState[toolName].status,
73874
+ editsSinceVerified: toolsState[toolName].editsSinceVerified
73875
+ }
73876
+ }));
73756
73877
  anyUnstaged = true;
73757
73878
  daemonCtx.logger.debug("VC tool verified", {
73758
73879
  toolName,
@@ -73767,13 +73888,18 @@ var require_track_verification_tools = __commonJS({
73767
73888
  const hasPerToolReminders = remaining.some((r) => VC_TOOL_NAME_SET.has(r.name));
73768
73889
  if (!hasPerToolReminders) {
73769
73890
  await daemonCtx.staging.deleteReminder("Stop", types_js_1.ReminderIds.VERIFY_COMPLETION);
73770
- (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, { reminderName: types_js_1.ReminderIds.VERIFY_COMPLETION, hookName: "Stop", reason: "all_tools_verified" }));
73891
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
73892
+ reminderName: types_js_1.ReminderIds.VERIFY_COMPLETION,
73893
+ hookName: "Stop",
73894
+ reason: "all_tools_verified",
73895
+ triggeredBy: "verification_passed"
73896
+ }));
73771
73897
  daemonCtx.logger.info("All VC tools verified, unstaged wrapper", { sessionId });
73772
73898
  }
73773
73899
  await remindersState.verificationTools.write(sessionId, toolsState);
73774
73900
  }
73775
73901
  }
73776
- async function ensureToolReminderStaged(daemonCtx, reminderId, stagedNames) {
73902
+ async function ensureToolReminderStaged(daemonCtx, reminderId, stagedNames, enrichment) {
73777
73903
  if (stagedNames.has(reminderId))
73778
73904
  return true;
73779
73905
  const reminder = (0, reminder_utils_js_1.resolveReminder)(reminderId, {
@@ -73787,7 +73913,7 @@ var require_track_verification_tools = __commonJS({
73787
73913
  await (0, reminder_utils_js_1.stageReminder)(daemonCtx, "Stop", {
73788
73914
  ...reminder,
73789
73915
  stagedAt: { timestamp: Date.now(), turnCount: 0, toolsThisTurn: 0, toolCount: 0 }
73790
- });
73916
+ }, enrichment);
73791
73917
  return true;
73792
73918
  }
73793
73919
  }
@@ -73803,6 +73929,7 @@ var require_stage_stop_bash_changes = __commonJS({
73803
73929
  Object.defineProperty(exports2, "__esModule", { value: true });
73804
73930
  exports2.registerStageBashChanges = registerStageBashChanges;
73805
73931
  var core_1 = require_dist4();
73932
+ var events_js_1 = require_events2();
73806
73933
  var types_1 = require_dist();
73807
73934
  var picomatch_1 = __importDefault2(require_picomatch2());
73808
73935
  var track_verification_tools_js_1 = require_track_verification_tools();
@@ -73872,6 +73999,12 @@ var require_stage_stop_bash_changes = __commonJS({
73872
73999
  if (lastConsumed?.stagedAt) {
73873
74000
  const shouldReactivate = metrics.turnCount > lastConsumed.stagedAt.turnCount;
73874
74001
  if (!shouldReactivate) {
74002
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
74003
+ reminderName: "verify-completion",
74004
+ hookName: "Stop",
74005
+ reason: "same_turn",
74006
+ triggeredBy: "bash_command"
74007
+ }));
73875
74008
  daemonCtx.logger.debug("Bash VC: skipped (already consumed this turn)", {
73876
74009
  currentTurn: metrics.turnCount,
73877
74010
  lastConsumedTurn: lastConsumed.stagedAt.turnCount
@@ -73887,12 +74020,25 @@ var require_stage_stop_bash_changes = __commonJS({
73887
74020
  currentCount: current.length,
73888
74021
  newFileCount: newFiles.length
73889
74022
  });
73890
- if (newFiles.length === 0)
74023
+ if (newFiles.length === 0) {
74024
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
74025
+ reminderName: "verify-completion",
74026
+ hookName: "Stop",
74027
+ reason: "no_changes_detected",
74028
+ triggeredBy: "bash_command"
74029
+ }));
73891
74030
  return;
74031
+ }
73892
74032
  const featureConfig = context.config.getFeature("reminders");
73893
74033
  const config = { ...types_js_1.DEFAULT_REMINDERS_SETTINGS, ...featureConfig.settings };
73894
74034
  const sourceMatches = newFiles.filter((f) => picomatch_1.default.isMatch(f, config.source_code_patterns));
73895
74035
  if (sourceMatches.length === 0) {
74036
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
74037
+ reminderName: "verify-completion",
74038
+ hookName: "Stop",
74039
+ reason: "pattern_mismatch",
74040
+ triggeredBy: "bash_command"
74041
+ }));
73896
74042
  daemonCtx.logger.debug("Bash VC: new files found but no source code matches", { newFiles });
73897
74043
  return;
73898
74044
  }
@@ -73906,7 +74052,7 @@ var require_stage_stop_bash_changes = __commonJS({
73906
74052
  const remindersState = (0, state_js_1.createRemindersState)(daemonCtx.stateService);
73907
74053
  const stateResult = await remindersState.verificationTools.read(sessionId);
73908
74054
  const toolsState = { ...stateResult.data };
73909
- await (0, track_verification_tools_js_1.stageToolsForFiles)(sourceMatches, daemonCtx, sessionId, verificationTools, toolsState, remindersState);
74055
+ await (0, track_verification_tools_js_1.stageToolsForFiles)(sourceMatches, daemonCtx, sessionId, verificationTools, toolsState, remindersState, "bash_command");
73910
74056
  }
73911
74057
  });
73912
74058
  }
@@ -74019,6 +74165,11 @@ var require_unstage_verify_completion = __commonJS({
74019
74165
  await remindersState.vcUnverified.delete(sessionId);
74020
74166
  }
74021
74167
  } else {
74168
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
74169
+ reminderName: "verify-completion",
74170
+ hookName: "Stop",
74171
+ reason: "no_unverified_changes"
74172
+ }));
74022
74173
  daemonCtx.logger.info("VC unstage: no unverified changes, clearing reminder", {
74023
74174
  sessionId,
74024
74175
  hadState: unverifiedState !== null
@@ -74028,7 +74179,12 @@ var require_unstage_verify_completion = __commonJS({
74028
74179
  const reason = unverifiedState?.hasUnverifiedChanges ? "cycle_limit_reached" : "no_unverified_changes";
74029
74180
  for (const vcId of types_js_1.ALL_VC_REMINDER_IDS) {
74030
74181
  await daemonCtx.staging.deleteReminder("Stop", vcId);
74031
- (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged(eventContext, { reminderName: vcId, hookName: "Stop", reason }));
74182
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged(eventContext, {
74183
+ reminderName: vcId,
74184
+ hookName: "Stop",
74185
+ reason,
74186
+ triggeredBy: unverifiedState?.hasUnverifiedChanges ? "cycle_limit" : "no_unverified_changes"
74187
+ }));
74032
74188
  }
74033
74189
  daemonCtx.logger.debug("VC unstage: deleted all VC reminders");
74034
74190
  }
@@ -74126,12 +74282,22 @@ var require_stage_persona_reminders = __commonJS({
74126
74282
  }
74127
74283
  async function stagePersonaRemindersForSession(ctx, sessionId, options) {
74128
74284
  if (!isPersonaInjectionEnabled(ctx)) {
74285
+ (0, core_1.logEvent)(ctx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
74286
+ reminderName: "remember-your-persona",
74287
+ hookName: "PreToolUse",
74288
+ reason: "feature_disabled"
74289
+ }));
74129
74290
  await clearPersonaReminders(ctx, sessionId);
74130
74291
  ctx.logger.debug("Persona injection disabled by config, cleaned up reminders", { sessionId });
74131
74292
  return;
74132
74293
  }
74133
74294
  const persona = await loadPersonaForSession(ctx, sessionId);
74134
74295
  if (!persona) {
74296
+ (0, core_1.logEvent)(ctx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
74297
+ reminderName: "remember-your-persona",
74298
+ hookName: "PreToolUse",
74299
+ reason: "no_persona"
74300
+ }));
74135
74301
  await clearPersonaReminders(ctx, sessionId);
74136
74302
  ctx.logger.debug("Persona cleared or disabled, unstaged persona reminders", { sessionId });
74137
74303
  return;
@@ -74431,7 +74597,19 @@ var require_consumption_handler_factory = __commonJS({
74431
74597
  reader.renameReminder(hook, reminder.name);
74432
74598
  }
74433
74599
  }
74434
- let response = buildResponse ? await buildResponse({ reminder: primary, reader, cliCtx, sessionId, event, supportsBlocking }) : buildDefaultResponse(primary, supportsBlocking);
74600
+ let enrichment;
74601
+ let response;
74602
+ if (buildResponse) {
74603
+ const result = await buildResponse({ reminder: primary, reader, cliCtx, sessionId, event, supportsBlocking });
74604
+ if ("response" in result && typeof result.response === "object") {
74605
+ response = result.response;
74606
+ enrichment = result.enrichment;
74607
+ } else {
74608
+ response = result;
74609
+ }
74610
+ } else {
74611
+ response = buildDefaultResponse(primary, supportsBlocking);
74612
+ }
74435
74613
  const secondaryContexts = reminders.slice(1).map((r) => r.additionalContext).filter((ctx2) => !!ctx2);
74436
74614
  if (secondaryContexts.length > 0) {
74437
74615
  const existing = response.additionalContext;
@@ -74449,7 +74627,8 @@ var require_consumption_handler_factory = __commonJS({
74449
74627
  reminderReturned: true,
74450
74628
  blocking: response.blocking ?? false,
74451
74629
  priority: primary.priority,
74452
- persistent: primary.persistent
74630
+ persistent: primary.persistent,
74631
+ ...enrichment
74453
74632
  }));
74454
74633
  return { response };
74455
74634
  }
@@ -74551,6 +74730,13 @@ var require_inject_stop = __commonJS({
74551
74730
  shouldBlock: classification.shouldBlock,
74552
74731
  reasoning: classification.reasoning?.slice(0, 200)
74553
74732
  });
74733
+ const classificationEnrichment = {
74734
+ classificationResult: {
74735
+ category: classification.category,
74736
+ confidence: classification.confidence,
74737
+ shouldBlock: classification.shouldBlock
74738
+ }
74739
+ };
74554
74740
  if (classification.shouldBlock) {
74555
74741
  cliCtx.logger.info("VC inject-stop: BLOCKING (claiming completion)", { sessionId });
74556
74742
  try {
@@ -74560,7 +74746,10 @@ var require_inject_stop = __commonJS({
74560
74746
  error: String(clearErr)
74561
74747
  });
74562
74748
  }
74563
- return (0, consumption_handler_factory_js_1.buildDefaultResponse)(reminder, supportsBlocking);
74749
+ return {
74750
+ response: (0, consumption_handler_factory_js_1.buildDefaultResponse)(reminder, supportsBlocking),
74751
+ enrichment: classificationEnrichment
74752
+ };
74564
74753
  } else {
74565
74754
  cliCtx.logger.info("VC inject-stop: NOT BLOCKING", {
74566
74755
  sessionId,
@@ -74586,13 +74775,13 @@ var require_inject_stop = __commonJS({
74586
74775
  });
74587
74776
  }
74588
74777
  if (classification.category === "ASKING_QUESTION" || classification.category === "ANSWERING_QUESTION") {
74589
- return {};
74778
+ return { response: {}, enrichment: classificationEnrichment };
74590
74779
  } else {
74591
74780
  const response = {};
74592
74781
  if (classification.userMessage) {
74593
74782
  response.userMessage = classification.userMessage;
74594
74783
  }
74595
- return response;
74784
+ return { response, enrichment: classificationEnrichment };
74596
74785
  }
74597
74786
  }
74598
74787
  } catch (err) {
@@ -74963,7 +75152,8 @@ var require_orchestrator = __commonJS({
74963
75152
  (0, core_1.logEvent)(this.deps.logger, events_js_1.ReminderEvents.reminderUnstaged(eventContext, {
74964
75153
  reminderName: vcId,
74965
75154
  hookName: "Stop",
74966
- reason: "pause_and_reflect_cascade"
75155
+ reason: "pause_and_reflect_cascade",
75156
+ triggeredBy: "cascade_from_pause_and_reflect"
74967
75157
  }));
74968
75158
  }
74969
75159
  this.deps.logger.debug("Unstaged all VC reminders after P&R staged", { sessionId });
@@ -75000,7 +75190,12 @@ var require_orchestrator = __commonJS({
75000
75190
  try {
75001
75191
  const staging = this.deps.getStagingService(sessionId);
75002
75192
  await staging.deleteReminder("PreToolUse", types_js_1.ReminderIds.PAUSE_AND_REFLECT);
75003
- (0, core_1.logEvent)(this.deps.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, { reminderName: types_js_1.ReminderIds.PAUSE_AND_REFLECT, hookName: "PreToolUse", reason: "vc_consumed_cascade" }));
75193
+ (0, core_1.logEvent)(this.deps.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
75194
+ reminderName: types_js_1.ReminderIds.PAUSE_AND_REFLECT,
75195
+ hookName: "PreToolUse",
75196
+ reason: "vc_consumed_cascade",
75197
+ triggeredBy: "cascade_from_verify_completion"
75198
+ }));
75004
75199
  this.deps.logger.debug("Unstaged P&R after VC consumed", { sessionId });
75005
75200
  } catch (err) {
75006
75201
  this.deps.logger.warn("Failed to unstage P&R after VC consumed", {
@@ -83540,7 +83735,7 @@ var require_cli = __commonJS({
83540
83735
  var promises_12 = require("node:fs/promises");
83541
83736
  var node_stream_1 = require("node:stream");
83542
83737
  var yargs_parser_1 = __importDefault2(require_build());
83543
- var VERSION = true ? "0.1.9" : "dev";
83738
+ var VERSION = true ? "0.1.11" : "dev";
83544
83739
  var SANDBOX_ERROR_MESSAGE = `Error: Daemon commands cannot run in sandbox mode.
83545
83740
 
83546
83741
  Claude Code's sandbox blocks Unix socket operations required for daemon IPC.