@scotthamilton77/sidekick 0.1.13 → 0.1.15

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/dist/daemon.js CHANGED
@@ -54,7 +54,7 @@ var require_events = __commonJS({
54
54
  "../types/dist/events.js"(exports2) {
55
55
  "use strict";
56
56
  Object.defineProperty(exports2, "__esModule", { value: true });
57
- exports2.UI_EVENT_VISIBILITY = exports2.UI_EVENT_TYPES = exports2.HOOK_NAMES = void 0;
57
+ exports2.UI_EVENT_VISIBILITY = exports2.DecisionEvents = exports2.UI_EVENT_TYPES = exports2.HOOK_NAMES = void 0;
58
58
  exports2.isHookEvent = isHookEvent;
59
59
  exports2.isTranscriptEvent = isTranscriptEvent;
60
60
  exports2.isSessionStartEvent = isSessionStartEvent;
@@ -162,9 +162,30 @@ var require_events = __commonJS({
162
162
  // Transcript events
163
163
  "transcript:emitted",
164
164
  "transcript:pre-compact",
165
+ // Bulk processing lifecycle events
166
+ "bulk-processing:start",
167
+ "bulk-processing:finish",
165
168
  // General error
166
169
  "error:occurred"
167
170
  ];
171
+ exports2.DecisionEvents = {
172
+ /** Emitted when a runtime decision is recorded. */
173
+ decisionRecorded(context, payload) {
174
+ return {
175
+ type: "decision:recorded",
176
+ time: Date.now(),
177
+ source: "daemon",
178
+ context: {
179
+ sessionId: context.sessionId,
180
+ correlationId: context.correlationId,
181
+ traceId: context.traceId,
182
+ hook: context.hook,
183
+ taskId: context.taskId
184
+ },
185
+ payload
186
+ };
187
+ }
188
+ };
168
189
  exports2.UI_EVENT_VISIBILITY = {
169
190
  // Timeline events (user-visible state changes)
170
191
  "reminder:staged": "timeline",
@@ -200,7 +221,9 @@ var require_events = __commonJS({
200
221
  "session-summary:skipped": "log",
201
222
  "resume-message:skipped": "log",
202
223
  "transcript:emitted": "log",
203
- "transcript:pre-compact": "log"
224
+ "transcript:pre-compact": "log",
225
+ "bulk-processing:start": "log",
226
+ "bulk-processing:finish": "log"
204
227
  };
205
228
  }
206
229
  });
@@ -44798,7 +44821,8 @@ var require_structured_logging = __commonJS({
44798
44821
  payload: {
44799
44822
  hook: context.hook,
44800
44823
  cwd: metadata.cwd,
44801
- mode: metadata.mode
44824
+ mode: metadata.mode,
44825
+ input: metadata.input
44802
44826
  }
44803
44827
  };
44804
44828
  },
@@ -44820,7 +44844,8 @@ var require_structured_logging = __commonJS({
44820
44844
  hook: context.hook,
44821
44845
  durationMs: metadata.durationMs,
44822
44846
  reminderReturned: state?.reminderReturned,
44823
- responseType: state?.responseType
44847
+ responseType: state?.responseType,
44848
+ returnValue: state?.returnValue
44824
44849
  }
44825
44850
  };
44826
44851
  },
@@ -45233,6 +45258,48 @@ var require_structured_logging = __commonJS({
45233
45258
  errorStack: state.errorStack
45234
45259
  }
45235
45260
  };
45261
+ },
45262
+ // --- Bulk Processing Lifecycle Events ---
45263
+ /**
45264
+ * Create a BulkProcessingStart event (logged when transcript bulk replay begins).
45265
+ */
45266
+ bulkProcessingStart(context, metadata) {
45267
+ return {
45268
+ type: "bulk-processing:start",
45269
+ time: Date.now(),
45270
+ source: "transcript",
45271
+ context: {
45272
+ sessionId: context.sessionId,
45273
+ correlationId: context.correlationId,
45274
+ traceId: context.traceId,
45275
+ hook: context.hook,
45276
+ taskId: context.taskId
45277
+ },
45278
+ payload: {
45279
+ fileSize: metadata.fileSize
45280
+ }
45281
+ };
45282
+ },
45283
+ /**
45284
+ * Create a BulkProcessingFinish event (logged when transcript bulk replay completes).
45285
+ */
45286
+ bulkProcessingFinish(context, metadata) {
45287
+ return {
45288
+ type: "bulk-processing:finish",
45289
+ time: Date.now(),
45290
+ source: "transcript",
45291
+ context: {
45292
+ sessionId: context.sessionId,
45293
+ correlationId: context.correlationId,
45294
+ traceId: context.traceId,
45295
+ hook: context.hook,
45296
+ taskId: context.taskId
45297
+ },
45298
+ payload: {
45299
+ totalLinesProcessed: metadata.totalLinesProcessed,
45300
+ durationMs: metadata.durationMs
45301
+ }
45302
+ };
45236
45303
  }
45237
45304
  };
45238
45305
  function logEvent(logger, event) {
@@ -45317,7 +45384,7 @@ var require_package3 = __commonJS({
45317
45384
  "eslint-config-prettier": "^9.1.0",
45318
45385
  "eslint-plugin-prettier": "^5.1.3",
45319
45386
  prettier: "^3.2.5",
45320
- typescript: "^5.6.3",
45387
+ typescript: "^5.9.3",
45321
45388
  "typescript-eslint": "^8.56.0",
45322
45389
  vitest: "^4.0.18"
45323
45390
  }
@@ -57281,6 +57348,7 @@ var require_staging_service = __commonJS({
57281
57348
  const hookDir = this.getHookDirPath(sessionId, hookName);
57282
57349
  const reminderPath = this.getReminderFilePath(sessionId, hookName, reminderName);
57283
57350
  await this.ensureDir(hookDir);
57351
+ const isRestage = (0, node_fs_1.existsSync)(reminderPath);
57284
57352
  try {
57285
57353
  await this.options.stateService.write(reminderPath, data, types_1.StagedReminderSchema);
57286
57354
  } catch (err) {
@@ -57296,18 +57364,20 @@ var require_staging_service = __commonJS({
57296
57364
  throw err;
57297
57365
  }
57298
57366
  }
57299
- const event = structured_logging_1.LogEvents.reminderStaged({
57300
- sessionId,
57301
- hook: hookName
57302
- }, {
57303
- reminderName: data.name,
57304
- hookName,
57305
- blocking: data.blocking,
57306
- priority: data.priority,
57307
- persistent: data.persistent,
57308
- ...enrichment
57309
- }, { stagingPath: reminderPath });
57310
- (0, structured_logging_1.logEvent)(this.options.logger.child({ context: { sessionId } }), event);
57367
+ if (!isRestage) {
57368
+ const event = structured_logging_1.LogEvents.reminderStaged({
57369
+ sessionId,
57370
+ hook: hookName
57371
+ }, {
57372
+ reminderName: data.name,
57373
+ hookName,
57374
+ blocking: data.blocking,
57375
+ priority: data.priority,
57376
+ persistent: data.persistent,
57377
+ ...enrichment
57378
+ }, { stagingPath: reminderPath });
57379
+ (0, structured_logging_1.logEvent)(this.options.logger.child({ context: { sessionId } }), event);
57380
+ }
57311
57381
  }
57312
57382
  /**
57313
57383
  * Read a staged reminder.
@@ -57386,13 +57456,14 @@ var require_staging_service = __commonJS({
57386
57456
  * Delete a specific staged reminder.
57387
57457
  * Used after consumption of one-shot reminders.
57388
57458
  *
57459
+ * @returns true if the file was actually deleted, false if it didn't exist
57389
57460
  * @throws Error if hookName or reminderName contain path traversal characters
57390
57461
  */
57391
57462
  async deleteReminder(sessionId, hookName, reminderName) {
57392
57463
  (0, staging_paths_js_1.validatePathSegment)(hookName, "hookName");
57393
57464
  (0, staging_paths_js_1.validatePathSegment)(reminderName, "reminderName");
57394
57465
  const reminderPath = this.getReminderFilePath(sessionId, hookName, reminderName);
57395
- await this.options.stateService.delete(reminderPath);
57466
+ return this.options.stateService.delete(reminderPath);
57396
57467
  }
57397
57468
  /**
57398
57469
  * List consumed reminder files for a specific reminder ID.
@@ -59933,7 +60004,7 @@ var require_state_service = __commonJS({
59933
60004
  }
59934
60005
  /**
59935
60006
  * Delete state file if it exists.
59936
- * No-op if file doesn't exist.
60007
+ * @returns true if the file was actually deleted, false if it didn't exist
59937
60008
  */
59938
60009
  async delete(path) {
59939
60010
  try {
@@ -59942,10 +60013,12 @@ var require_state_service = __commonJS({
59942
60013
  this.cache.delete(path);
59943
60014
  }
59944
60015
  this.logger?.debug("State deleted", { path });
60016
+ return true;
59945
60017
  } catch (err) {
59946
60018
  if (!isEnoent(err)) {
59947
60019
  throw err;
59948
60020
  }
60021
+ return false;
59949
60022
  }
59950
60023
  }
59951
60024
  /**
@@ -60200,7 +60273,7 @@ var require_typed_accessor = __commonJS({
60200
60273
  */
60201
60274
  async delete(sessionId) {
60202
60275
  const path = this.stateService.sessionStatePath(sessionId, this.descriptor.filename);
60203
- return this.stateService.delete(path);
60276
+ await this.stateService.delete(path);
60204
60277
  }
60205
60278
  /**
60206
60279
  * Get the path for a session state file.
@@ -60246,7 +60319,7 @@ var require_typed_accessor = __commonJS({
60246
60319
  */
60247
60320
  async delete() {
60248
60321
  const path = this.stateService.globalStatePath(this.descriptor.filename);
60249
- return this.stateService.delete(path);
60322
+ await this.stateService.delete(path);
60250
60323
  }
60251
60324
  /**
60252
60325
  * Get the path for the global state file.
@@ -60568,6 +60641,10 @@ var require_transcript_service = __commonJS({
60568
60641
  prepared = false;
60569
60642
  /** Track whether we're in bulk processing mode (first-time transcript replay) */
60570
60643
  isBulkProcessing = false;
60644
+ /** One-shot guard — prevents BulkProcessingComplete from firing more than once per instance */
60645
+ hasFiredBulkComplete = false;
60646
+ /** Timestamp when bulk processing started (for duration calculation in finish event) */
60647
+ bulkStartTime = 0;
60571
60648
  /** Map tool_use_id → tool name so ToolResult events can include the tool name */
60572
60649
  toolUseIdToName = /* @__PURE__ */ new Map();
60573
60650
  // Streaming state for incremental file processing
@@ -61307,12 +61384,10 @@ var require_transcript_service = __commonJS({
61307
61384
  }
61308
61385
  const startLine = this.metrics.lastProcessedLine;
61309
61386
  const isBulkStart = startLine === 0 && this.lastProcessedByteOffset === 0;
61310
- if (isBulkStart) {
61387
+ if (isBulkStart && !this.hasFiredBulkComplete) {
61311
61388
  this.isBulkProcessing = true;
61312
- this.options.logger.info("Bulk processing started (streaming)", {
61313
- sessionId: this.sessionId,
61314
- fileSize: currentFileSize
61315
- });
61389
+ this.bulkStartTime = Date.now();
61390
+ (0, structured_logging_js_1.logEvent)(this.options.logger, structured_logging_js_1.LogEvents.bulkProcessingStart({ sessionId: this.sessionId }, { fileSize: currentFileSize }));
61316
61391
  }
61317
61392
  const stream = (0, node_fs_1.createReadStream)(this.transcriptPath, {
61318
61393
  encoding: "utf-8",
@@ -61370,13 +61445,12 @@ var require_transcript_service = __commonJS({
61370
61445
  totalLines: lineNumber,
61371
61446
  newByteOffset: bytesRead
61372
61447
  });
61373
- if (isBulkStart && this.isBulkProcessing) {
61448
+ if (isBulkStart && this.isBulkProcessing && !this.hasFiredBulkComplete) {
61374
61449
  this.isBulkProcessing = false;
61450
+ this.hasFiredBulkComplete = true;
61451
+ const durationMs = Date.now() - this.bulkStartTime;
61452
+ (0, structured_logging_js_1.logEvent)(this.options.logger, structured_logging_js_1.LogEvents.bulkProcessingFinish({ sessionId: this.sessionId }, { totalLinesProcessed: lineNumber, durationMs }));
61375
61453
  await this.emitEvent("BulkProcessingComplete", {}, lineNumber);
61376
- this.options.logger.info("Bulk processing complete", {
61377
- sessionId: this.sessionId,
61378
- totalLinesProcessed: lineNumber
61379
- });
61380
61454
  }
61381
61455
  this.notifyMetricsChange();
61382
61456
  this.schedulePersistence();
@@ -70614,6 +70688,7 @@ var require_stage_default_user_prompt = __commonJS({
70614
70688
  "use strict";
70615
70689
  Object.defineProperty(exports2, "__esModule", { value: true });
70616
70690
  exports2.registerStageDefaultUserPrompt = registerStageDefaultUserPrompt;
70691
+ var core_1 = require_dist4();
70617
70692
  var types_1 = require_dist();
70618
70693
  var staging_handler_utils_js_1 = require_staging_handler_utils();
70619
70694
  var types_js_1 = require_types2();
@@ -70753,6 +70828,12 @@ var require_stage_default_user_prompt = __commonJS({
70753
70828
  ...typedEntry.cachedReminder,
70754
70829
  stagedAt
70755
70830
  });
70831
+ (0, core_1.logEvent)(handlerCtx.logger, types_1.DecisionEvents.decisionRecorded({ sessionId }, {
70832
+ decision: "staged",
70833
+ reason: `message count reached threshold (${newCount}/${threshold})`,
70834
+ subsystem: "user-prompt-reminders",
70835
+ title: "Stage user-prompt reminder"
70836
+ }));
70756
70837
  state[reminderId] = { ...typedEntry, messagesSinceLastStaging: 0 };
70757
70838
  handlerCtx.logger.debug("Throttle: re-staged reminder", {
70758
70839
  sessionId,
@@ -70950,6 +71031,12 @@ var require_stage_pause_and_reflect = __commonJS({
70950
71031
  }));
70951
71032
  return void 0;
70952
71033
  }
71034
+ (0, core_1.logEvent)(ctx.logger, types_1.DecisionEvents.decisionRecorded({ sessionId }, {
71035
+ decision: "staged",
71036
+ reason: `tools since baseline reached threshold (${toolsSinceBaseline}/${config.pause_and_reflect_threshold})`,
71037
+ subsystem: "pause-reflect",
71038
+ title: "Stage pause-and-reflect reminder"
71039
+ }));
70953
71040
  return {
70954
71041
  reminderId: types_js_1.ReminderIds.PAUSE_AND_REFLECT,
70955
71042
  targetHook: "PreToolUse",
@@ -72637,12 +72724,21 @@ var require_track_verification_tools = __commonJS({
72637
72724
  } else {
72638
72725
  const newEdits = current.editsSinceVerified + 1;
72639
72726
  if (newEdits >= toolConfig.clearing_threshold) {
72727
+ const wasAlreadyStaged = stagedNames.has(reminderId);
72640
72728
  const staged = await ensureToolReminderStaged(daemonCtx, reminderId, stagedNames, {
72641
72729
  reason: "threshold_reached",
72642
72730
  triggeredBy: "file_edit",
72643
72731
  thresholdState: { current: newEdits, threshold: toolConfig.clearing_threshold }
72644
72732
  });
72645
72733
  if (staged) {
72734
+ if (!wasAlreadyStaged) {
72735
+ (0, core_1.logEvent)(daemonCtx.logger, types_1.DecisionEvents.decisionRecorded({ sessionId }, {
72736
+ decision: "staged",
72737
+ reason: `edits reached clearing threshold (${newEdits}/${toolConfig.clearing_threshold})`,
72738
+ subsystem: "vc-reminders",
72739
+ title: "Re-stage VC reminder (threshold reached)"
72740
+ }));
72741
+ }
72646
72742
  toolsState[toolName] = {
72647
72743
  ...current,
72648
72744
  status: "staged",
@@ -72710,7 +72806,15 @@ var require_track_verification_tools = __commonJS({
72710
72806
  lastMatchedToolId: match.tool_id,
72711
72807
  lastMatchedScope: match.scope
72712
72808
  };
72713
- await daemonCtx.staging.deleteReminder("Stop", reminderId);
72809
+ const deleted = await daemonCtx.staging.deleteReminder("Stop", reminderId);
72810
+ if (deleted) {
72811
+ (0, core_1.logEvent)(daemonCtx.logger, types_1.DecisionEvents.decisionRecorded({ sessionId }, {
72812
+ decision: "unstaged",
72813
+ reason: `verification passed for ${toolName} (matched ${match.tool_id})`,
72814
+ subsystem: "vc-reminders",
72815
+ title: "Unstage VC reminder (verified)"
72816
+ }));
72817
+ }
72714
72818
  (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
72715
72819
  reminderName: reminderId,
72716
72820
  hookName: "Stop",
@@ -72913,8 +73017,9 @@ var require_unstage_verify_completion = __commonJS({
72913
73017
  Object.defineProperty(exports2, "__esModule", { value: true });
72914
73018
  exports2.registerUnstageVerifyCompletion = registerUnstageVerifyCompletion;
72915
73019
  var core_1 = require_dist4();
72916
- var events_js_1 = require_events2();
72917
73020
  var types_1 = require_dist();
73021
+ var events_js_1 = require_events2();
73022
+ var types_2 = require_dist();
72918
73023
  var types_js_1 = require_types2();
72919
73024
  var reminder_utils_js_1 = require_reminder_utils();
72920
73025
  var state_js_1 = require_state4();
@@ -72931,7 +73036,7 @@ var require_unstage_verify_completion = __commonJS({
72931
73036
  return false;
72932
73037
  }
72933
73038
  function registerUnstageVerifyCompletion(context) {
72934
- if (!(0, types_1.isDaemonContext)(context))
73039
+ if (!(0, types_2.isDaemonContext)(context))
72935
73040
  return;
72936
73041
  context.handlers.register({
72937
73042
  id: "reminders:unstage-verify-completion",
@@ -72939,17 +73044,19 @@ var require_unstage_verify_completion = __commonJS({
72939
73044
  // Before consumption handlers (50)
72940
73045
  filter: { kind: "hook", hooks: ["UserPromptSubmit"] },
72941
73046
  handler: async (event, ctx) => {
72942
- if (!(0, types_1.isHookEvent)(event))
73047
+ if (!(0, types_2.isHookEvent)(event))
72943
73048
  return;
72944
- if (!(0, types_1.isDaemonContext)(ctx))
73049
+ if (!(0, types_2.isDaemonContext)(ctx))
72945
73050
  return;
72946
73051
  const daemonCtx = ctx;
72947
73052
  const sessionId = event.context?.sessionId;
72948
73053
  if (!sessionId) {
72949
73054
  daemonCtx.logger.warn("No sessionId in UserPromptSubmit event");
72950
73055
  for (const vcId of types_js_1.ALL_VC_REMINDER_IDS) {
72951
- await daemonCtx.staging.deleteReminder("Stop", vcId);
72952
- (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId: "" }, { reminderName: vcId, hookName: "Stop", reason: "no_session_id" }));
73056
+ const deleted = await daemonCtx.staging.deleteReminder("Stop", vcId);
73057
+ if (deleted) {
73058
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId: "" }, { reminderName: vcId, hookName: "Stop", reason: "no_session_id" }));
73059
+ }
72953
73060
  }
72954
73061
  return;
72955
73062
  }
@@ -73034,6 +73141,12 @@ var require_unstage_verify_completion = __commonJS({
73034
73141
  maxCycles
73035
73142
  });
73036
73143
  await remindersState.vcUnverified.delete(sessionId);
73144
+ (0, core_1.logEvent)(daemonCtx.logger, types_1.DecisionEvents.decisionRecorded({ sessionId }, {
73145
+ decision: "unstaged-all",
73146
+ reason: `verification cycle limit reached (${unverifiedState.cycleCount}/${maxCycles})`,
73147
+ subsystem: "vc-reminders",
73148
+ title: "Unstage all VC reminders (cycle limit)"
73149
+ }));
73037
73150
  }
73038
73151
  } else {
73039
73152
  (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
@@ -73048,16 +73161,24 @@ var require_unstage_verify_completion = __commonJS({
73048
73161
  }
73049
73162
  const eventContext = { sessionId };
73050
73163
  const reason = unverifiedState?.hasUnverifiedChanges ? "cycle_limit_reached" : "no_unverified_changes";
73164
+ let deletedCount = 0;
73051
73165
  for (const vcId of types_js_1.ALL_VC_REMINDER_IDS) {
73052
- await daemonCtx.staging.deleteReminder("Stop", vcId);
73053
- (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged(eventContext, {
73054
- reminderName: vcId,
73055
- hookName: "Stop",
73056
- reason,
73057
- triggeredBy: unverifiedState?.hasUnverifiedChanges ? "cycle_limit" : "no_unverified_changes"
73058
- }));
73166
+ const deleted = await daemonCtx.staging.deleteReminder("Stop", vcId);
73167
+ if (deleted) {
73168
+ deletedCount++;
73169
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged(eventContext, {
73170
+ reminderName: vcId,
73171
+ hookName: "Stop",
73172
+ reason,
73173
+ triggeredBy: unverifiedState?.hasUnverifiedChanges ? "cycle_limit" : "no_unverified_changes"
73174
+ }));
73175
+ }
73059
73176
  }
73060
- daemonCtx.logger.debug("VC unstage: deleted all VC reminders");
73177
+ daemonCtx.logger.debug("VC unstage: cleanup complete", {
73178
+ reason,
73179
+ deletedCount,
73180
+ totalChecked: types_js_1.ALL_VC_REMINDER_IDS.length
73181
+ });
73061
73182
  }
73062
73183
  });
73063
73184
  }
@@ -74019,16 +74140,24 @@ var require_orchestrator = __commonJS({
74019
74140
  const staging = this.deps.getStagingService(sessionId);
74020
74141
  const eventContext = { sessionId };
74021
74142
  const sessionLogger = this.deps.logger.child({ context: { sessionId } });
74143
+ let deletedCount = 0;
74022
74144
  for (const vcId of types_js_1.ALL_VC_REMINDER_IDS) {
74023
- await staging.deleteReminder("Stop", vcId);
74024
- (0, core_1.logEvent)(sessionLogger, events_js_1.ReminderEvents.reminderUnstaged(eventContext, {
74025
- reminderName: vcId,
74026
- hookName: "Stop",
74027
- reason: "pause_and_reflect_cascade",
74028
- triggeredBy: "cascade_from_pause_and_reflect"
74029
- }));
74145
+ const deleted = await staging.deleteReminder("Stop", vcId);
74146
+ if (deleted) {
74147
+ deletedCount++;
74148
+ (0, core_1.logEvent)(sessionLogger, events_js_1.ReminderEvents.reminderUnstaged(eventContext, {
74149
+ reminderName: vcId,
74150
+ hookName: "Stop",
74151
+ reason: "pause_and_reflect_cascade",
74152
+ triggeredBy: "cascade_from_pause_and_reflect"
74153
+ }));
74154
+ }
74030
74155
  }
74031
- this.deps.logger.debug("Unstaged all VC reminders after P&R staged", { sessionId });
74156
+ this.deps.logger.debug("VC unstage: P&R cascade complete", {
74157
+ sessionId,
74158
+ deletedCount,
74159
+ totalChecked: types_js_1.ALL_VC_REMINDER_IDS.length
74160
+ });
74032
74161
  } catch (err) {
74033
74162
  this.deps.logger.warn("Failed to unstage VC reminders after P&R staged", {
74034
74163
  sessionId,
@@ -74061,14 +74190,16 @@ var require_orchestrator = __commonJS({
74061
74190
  }
74062
74191
  try {
74063
74192
  const staging = this.deps.getStagingService(sessionId);
74064
- await staging.deleteReminder("PreToolUse", types_js_1.ReminderIds.PAUSE_AND_REFLECT);
74065
- (0, core_1.logEvent)(this.deps.logger.child({ context: { sessionId } }), events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
74066
- reminderName: types_js_1.ReminderIds.PAUSE_AND_REFLECT,
74067
- hookName: "PreToolUse",
74068
- reason: "vc_consumed_cascade",
74069
- triggeredBy: "cascade_from_verify_completion"
74070
- }));
74071
- this.deps.logger.debug("Unstaged P&R after VC consumed", { sessionId });
74193
+ const deleted = await staging.deleteReminder("PreToolUse", types_js_1.ReminderIds.PAUSE_AND_REFLECT);
74194
+ if (deleted) {
74195
+ (0, core_1.logEvent)(this.deps.logger.child({ context: { sessionId } }), events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
74196
+ reminderName: types_js_1.ReminderIds.PAUSE_AND_REFLECT,
74197
+ hookName: "PreToolUse",
74198
+ reason: "vc_consumed_cascade",
74199
+ triggeredBy: "cascade_from_verify_completion"
74200
+ }));
74201
+ }
74202
+ this.deps.logger.debug("VC unstage: P&R cascade from VC consumed", { sessionId, deleted });
74072
74203
  } catch (err) {
74073
74204
  this.deps.logger.warn("Failed to unstage P&R after VC consumed", {
74074
74205
  sessionId,
@@ -74534,7 +74665,7 @@ var require_events3 = __commonJS({
74534
74665
  "../feature-session-summary/dist/events.js"(exports2) {
74535
74666
  "use strict";
74536
74667
  Object.defineProperty(exports2, "__esModule", { value: true });
74537
- exports2.DecisionEvents = exports2.SessionSummaryEvents = void 0;
74668
+ exports2.SessionSummaryEvents = void 0;
74538
74669
  exports2.SessionSummaryEvents = {
74539
74670
  /** Emitted when summary generation begins. */
74540
74671
  summaryStart(context, payload) {
@@ -74656,24 +74787,6 @@ var require_events3 = __commonJS({
74656
74787
  };
74657
74788
  }
74658
74789
  };
74659
- exports2.DecisionEvents = {
74660
- /** Emitted when an LLM decision is recorded. */
74661
- decisionRecorded(context, payload) {
74662
- return {
74663
- type: "decision:recorded",
74664
- time: Date.now(),
74665
- source: "daemon",
74666
- context: {
74667
- sessionId: context.sessionId,
74668
- correlationId: context.correlationId,
74669
- traceId: context.traceId,
74670
- hook: context.hook,
74671
- taskId: context.taskId
74672
- },
74673
- payload
74674
- };
74675
- }
74676
- };
74677
74790
  }
74678
74791
  });
74679
74792
 
@@ -74833,11 +74946,14 @@ var require_update_summary = __commonJS({
74833
74946
  exports2.updateSessionSummary = updateSessionSummary;
74834
74947
  var core_1 = require_dist4();
74835
74948
  var events_js_1 = require_events3();
74949
+ var types_1 = require_dist();
74836
74950
  var zod_1 = require_zod();
74837
74951
  var types_js_1 = require_types3();
74838
74952
  var state_js_1 = require_state5();
74839
74953
  var persona_utils_js_1 = require_persona_utils();
74840
74954
  var persona_selection_js_1 = require_persona_selection();
74955
+ var DECISION_TITLE_SKIP = "Skip session analysis";
74956
+ var DECISION_TITLE_RUN = "Run session analysis";
74841
74957
  var PROMPT_FILE = "prompts/session-summary.prompt.txt";
74842
74958
  var SNARKY_PROMPT_FILE = "prompts/snarky-message.prompt.txt";
74843
74959
  var RESUME_PROMPT_FILE = "prompts/resume-message.prompt.txt";
@@ -74888,17 +75004,19 @@ var require_update_summary = __commonJS({
74888
75004
  await (0, persona_selection_js_1.ensurePersonaForSession)(sessionId, ctx);
74889
75005
  const metrics = ctx.transcript.getMetrics();
74890
75006
  if (metrics.turnCount === 0) {
74891
- (0, core_1.logEvent)(ctx.logger, events_js_1.DecisionEvents.decisionRecorded(event.context, {
75007
+ (0, core_1.logEvent)(ctx.logger, types_1.DecisionEvents.decisionRecorded(event.context, {
74892
75008
  decision: "skipped",
74893
75009
  reason: "BulkProcessingComplete with no user turns (turnCount=0)",
74894
- detail: "session-summary analysis"
75010
+ subsystem: "session-summary",
75011
+ title: DECISION_TITLE_SKIP
74895
75012
  }));
74896
75013
  return;
74897
75014
  }
74898
- (0, core_1.logEvent)(ctx.logger, events_js_1.DecisionEvents.decisionRecorded(event.context, {
75015
+ (0, core_1.logEvent)(ctx.logger, types_1.DecisionEvents.decisionRecorded(event.context, {
74899
75016
  decision: "calling",
74900
75017
  reason: "BulkProcessingComplete - analyzing full transcript",
74901
- detail: "session-summary analysis"
75018
+ subsystem: "session-summary",
75019
+ title: DECISION_TITLE_RUN
74902
75020
  }));
74903
75021
  const countdown2 = await loadCountdownState(summaryState, sessionId);
74904
75022
  void performAnalysis(event, ctx, summaryState, countdown2, "user_prompt_forced");
@@ -74906,28 +75024,19 @@ var require_update_summary = __commonJS({
74906
75024
  }
74907
75025
  const countdown = await loadCountdownState(summaryState, sessionId);
74908
75026
  if (isUserPrompt) {
74909
- (0, core_1.logEvent)(ctx.logger, events_js_1.DecisionEvents.decisionRecorded(event.context, {
74910
- decision: "calling",
74911
- reason: "UserPrompt event forces immediate analysis",
74912
- detail: "session-summary analysis"
74913
- }));
74914
75027
  void performAnalysis(event, ctx, summaryState, countdown, "user_prompt_forced");
74915
75028
  return;
74916
75029
  }
74917
75030
  if (countdown.countdown > 0) {
74918
- (0, core_1.logEvent)(ctx.logger, events_js_1.DecisionEvents.decisionRecorded(event.context, {
74919
- decision: "skipped",
74920
- reason: `countdown not reached (${countdown.countdown} tool results remaining)`,
74921
- detail: "session-summary analysis"
74922
- }));
74923
75031
  countdown.countdown--;
74924
75032
  await saveCountdownState(summaryState, sessionId, countdown);
74925
75033
  return;
74926
75034
  }
74927
- (0, core_1.logEvent)(ctx.logger, events_js_1.DecisionEvents.decisionRecorded(event.context, {
75035
+ (0, core_1.logEvent)(ctx.logger, types_1.DecisionEvents.decisionRecorded(event.context, {
74928
75036
  decision: "calling",
74929
75037
  reason: "countdown reached zero after ToolResult",
74930
- detail: "session-summary analysis"
75038
+ subsystem: "session-summary",
75039
+ title: DECISION_TITLE_RUN
74931
75040
  }));
74932
75041
  void performAnalysis(event, ctx, summaryState, countdown, "countdown_reached");
74933
75042
  }
@@ -75069,14 +75178,6 @@ var require_update_summary = __commonJS({
75069
75178
  if (sideEffects.length > 0) {
75070
75179
  await Promise.all(sideEffects);
75071
75180
  }
75072
- (0, core_1.logEvent)(ctx.logger, events_js_1.SessionSummaryEvents.summaryFinish(event.context, {
75073
- session_title: updatedSummary.session_title,
75074
- session_title_confidence: updatedSummary.session_title_confidence,
75075
- latest_intent: updatedSummary.latest_intent,
75076
- latest_intent_confidence: updatedSummary.latest_intent_confidence,
75077
- processing_time_ms: updatedSummary.stats?.processing_time_ms ?? 0,
75078
- pivot_detected: updatedSummary.pivot_detected ?? false
75079
- }));
75080
75181
  if (currentSummary && updatedSummary.session_title !== currentSummary.session_title) {
75081
75182
  (0, core_1.logEvent)(ctx.logger, events_js_1.SessionSummaryEvents.titleChanged(event.context, {
75082
75183
  previousValue: currentSummary.session_title,
@@ -75091,6 +75192,14 @@ var require_update_summary = __commonJS({
75091
75192
  confidence: updatedSummary.latest_intent_confidence
75092
75193
  }));
75093
75194
  }
75195
+ (0, core_1.logEvent)(ctx.logger, events_js_1.SessionSummaryEvents.summaryFinish(event.context, {
75196
+ session_title: updatedSummary.session_title,
75197
+ session_title_confidence: updatedSummary.session_title_confidence,
75198
+ latest_intent: updatedSummary.latest_intent,
75199
+ latest_intent_confidence: updatedSummary.latest_intent_confidence,
75200
+ processing_time_ms: updatedSummary.stats?.processing_time_ms ?? 0,
75201
+ pivot_detected: updatedSummary.pivot_detected ?? false
75202
+ }));
75094
75203
  ctx.logger.info("Updated session summary", {
75095
75204
  sessionId,
75096
75205
  reason,
@@ -75574,7 +75683,7 @@ var require_dist6 = __commonJS({
75574
75683
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
75575
75684
  };
75576
75685
  Object.defineProperty(exports2, "__esModule", { value: true });
75577
- exports2.DecisionEvents = exports2.SessionSummaryEvents = exports2.manifest = void 0;
75686
+ exports2.SessionSummaryEvents = exports2.manifest = void 0;
75578
75687
  exports2.register = register;
75579
75688
  var index_js_1 = require_handlers();
75580
75689
  exports2.manifest = {
@@ -75596,9 +75705,6 @@ var require_dist6 = __commonJS({
75596
75705
  Object.defineProperty(exports2, "SessionSummaryEvents", { enumerable: true, get: function() {
75597
75706
  return events_js_1.SessionSummaryEvents;
75598
75707
  } });
75599
- Object.defineProperty(exports2, "DecisionEvents", { enumerable: true, get: function() {
75600
- return events_js_1.DecisionEvents;
75601
- } });
75602
75708
  }
75603
75709
  });
75604
75710
 
@@ -77950,8 +78056,7 @@ var require_daemon = __commonJS({
77950
78056
  clearStaging: async () => {
77951
78057
  },
77952
78058
  listReminders: () => Promise.resolve([]),
77953
- deleteReminder: async () => {
77954
- },
78059
+ deleteReminder: () => Promise.resolve(false),
77955
78060
  listConsumedReminders: () => Promise.resolve([]),
77956
78061
  getLastConsumed: () => Promise.resolve(null)
77957
78062
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scotthamilton77/sidekick",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "AI pair programming assistant with personas, session tracking, and contextual nudges",
5
5
  "bin": {
6
6
  "sidekick": "dist/bin.js"