@scotthamilton77/sidekick 0.1.14 → 0.1.16

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/bin.js CHANGED
@@ -1030,7 +1030,7 @@ var require_events = __commonJS({
1030
1030
  "../types/dist/events.js"(exports2) {
1031
1031
  "use strict";
1032
1032
  Object.defineProperty(exports2, "__esModule", { value: true });
1033
- exports2.UI_EVENT_VISIBILITY = exports2.UI_EVENT_TYPES = exports2.HOOK_NAMES = void 0;
1033
+ exports2.UI_EVENT_VISIBILITY = exports2.DecisionEvents = exports2.UI_EVENT_TYPES = exports2.HOOK_NAMES = void 0;
1034
1034
  exports2.isHookEvent = isHookEvent;
1035
1035
  exports2.isTranscriptEvent = isTranscriptEvent;
1036
1036
  exports2.isSessionStartEvent = isSessionStartEvent;
@@ -1138,9 +1138,30 @@ var require_events = __commonJS({
1138
1138
  // Transcript events
1139
1139
  "transcript:emitted",
1140
1140
  "transcript:pre-compact",
1141
+ // Bulk processing lifecycle events
1142
+ "bulk-processing:start",
1143
+ "bulk-processing:finish",
1141
1144
  // General error
1142
1145
  "error:occurred"
1143
1146
  ];
1147
+ exports2.DecisionEvents = {
1148
+ /** Emitted when a runtime decision is recorded. */
1149
+ decisionRecorded(context, payload) {
1150
+ return {
1151
+ type: "decision:recorded",
1152
+ time: Date.now(),
1153
+ source: "daemon",
1154
+ context: {
1155
+ sessionId: context.sessionId,
1156
+ correlationId: context.correlationId,
1157
+ traceId: context.traceId,
1158
+ hook: context.hook,
1159
+ taskId: context.taskId
1160
+ },
1161
+ payload
1162
+ };
1163
+ }
1164
+ };
1144
1165
  exports2.UI_EVENT_VISIBILITY = {
1145
1166
  // Timeline events (user-visible state changes)
1146
1167
  "reminder:staged": "timeline",
@@ -1176,7 +1197,9 @@ var require_events = __commonJS({
1176
1197
  "session-summary:skipped": "log",
1177
1198
  "resume-message:skipped": "log",
1178
1199
  "transcript:emitted": "log",
1179
- "transcript:pre-compact": "log"
1200
+ "transcript:pre-compact": "log",
1201
+ "bulk-processing:start": "log",
1202
+ "bulk-processing:finish": "log"
1180
1203
  };
1181
1204
  }
1182
1205
  });
@@ -45774,7 +45797,8 @@ var require_structured_logging = __commonJS({
45774
45797
  payload: {
45775
45798
  hook: context.hook,
45776
45799
  cwd: metadata.cwd,
45777
- mode: metadata.mode
45800
+ mode: metadata.mode,
45801
+ input: metadata.input
45778
45802
  }
45779
45803
  };
45780
45804
  },
@@ -45796,7 +45820,8 @@ var require_structured_logging = __commonJS({
45796
45820
  hook: context.hook,
45797
45821
  durationMs: metadata.durationMs,
45798
45822
  reminderReturned: state?.reminderReturned,
45799
- responseType: state?.responseType
45823
+ responseType: state?.responseType,
45824
+ returnValue: state?.returnValue
45800
45825
  }
45801
45826
  };
45802
45827
  },
@@ -46209,6 +46234,48 @@ var require_structured_logging = __commonJS({
46209
46234
  errorStack: state.errorStack
46210
46235
  }
46211
46236
  };
46237
+ },
46238
+ // --- Bulk Processing Lifecycle Events ---
46239
+ /**
46240
+ * Create a BulkProcessingStart event (logged when transcript bulk replay begins).
46241
+ */
46242
+ bulkProcessingStart(context, metadata) {
46243
+ return {
46244
+ type: "bulk-processing:start",
46245
+ time: Date.now(),
46246
+ source: "transcript",
46247
+ context: {
46248
+ sessionId: context.sessionId,
46249
+ correlationId: context.correlationId,
46250
+ traceId: context.traceId,
46251
+ hook: context.hook,
46252
+ taskId: context.taskId
46253
+ },
46254
+ payload: {
46255
+ fileSize: metadata.fileSize
46256
+ }
46257
+ };
46258
+ },
46259
+ /**
46260
+ * Create a BulkProcessingFinish event (logged when transcript bulk replay completes).
46261
+ */
46262
+ bulkProcessingFinish(context, metadata) {
46263
+ return {
46264
+ type: "bulk-processing:finish",
46265
+ time: Date.now(),
46266
+ source: "transcript",
46267
+ context: {
46268
+ sessionId: context.sessionId,
46269
+ correlationId: context.correlationId,
46270
+ traceId: context.traceId,
46271
+ hook: context.hook,
46272
+ taskId: context.taskId
46273
+ },
46274
+ payload: {
46275
+ totalLinesProcessed: metadata.totalLinesProcessed,
46276
+ durationMs: metadata.durationMs
46277
+ }
46278
+ };
46212
46279
  }
46213
46280
  };
46214
46281
  function logEvent(logger, event) {
@@ -46293,7 +46360,7 @@ var require_package3 = __commonJS({
46293
46360
  "eslint-config-prettier": "^9.1.0",
46294
46361
  "eslint-plugin-prettier": "^5.1.3",
46295
46362
  prettier: "^3.2.5",
46296
- typescript: "^5.6.3",
46363
+ typescript: "^5.9.3",
46297
46364
  "typescript-eslint": "^8.56.0",
46298
46365
  vitest: "^4.0.18"
46299
46366
  }
@@ -58257,6 +58324,7 @@ var require_staging_service = __commonJS({
58257
58324
  const hookDir = this.getHookDirPath(sessionId, hookName);
58258
58325
  const reminderPath = this.getReminderFilePath(sessionId, hookName, reminderName);
58259
58326
  await this.ensureDir(hookDir);
58327
+ const isRestage = (0, node_fs_1.existsSync)(reminderPath);
58260
58328
  try {
58261
58329
  await this.options.stateService.write(reminderPath, data, types_1.StagedReminderSchema);
58262
58330
  } catch (err) {
@@ -58272,18 +58340,20 @@ var require_staging_service = __commonJS({
58272
58340
  throw err;
58273
58341
  }
58274
58342
  }
58275
- const event = structured_logging_1.LogEvents.reminderStaged({
58276
- sessionId,
58277
- hook: hookName
58278
- }, {
58279
- reminderName: data.name,
58280
- hookName,
58281
- blocking: data.blocking,
58282
- priority: data.priority,
58283
- persistent: data.persistent,
58284
- ...enrichment
58285
- }, { stagingPath: reminderPath });
58286
- (0, structured_logging_1.logEvent)(this.options.logger.child({ context: { sessionId } }), event);
58343
+ if (!isRestage) {
58344
+ const event = structured_logging_1.LogEvents.reminderStaged({
58345
+ sessionId,
58346
+ hook: hookName
58347
+ }, {
58348
+ reminderName: data.name,
58349
+ hookName,
58350
+ blocking: data.blocking,
58351
+ priority: data.priority,
58352
+ persistent: data.persistent,
58353
+ ...enrichment
58354
+ }, { stagingPath: reminderPath });
58355
+ (0, structured_logging_1.logEvent)(this.options.logger.child({ context: { sessionId } }), event);
58356
+ }
58287
58357
  }
58288
58358
  /**
58289
58359
  * Read a staged reminder.
@@ -58362,13 +58432,14 @@ var require_staging_service = __commonJS({
58362
58432
  * Delete a specific staged reminder.
58363
58433
  * Used after consumption of one-shot reminders.
58364
58434
  *
58435
+ * @returns true if the file was actually deleted, false if it didn't exist
58365
58436
  * @throws Error if hookName or reminderName contain path traversal characters
58366
58437
  */
58367
58438
  async deleteReminder(sessionId, hookName, reminderName) {
58368
58439
  (0, staging_paths_js_1.validatePathSegment)(hookName, "hookName");
58369
58440
  (0, staging_paths_js_1.validatePathSegment)(reminderName, "reminderName");
58370
58441
  const reminderPath = this.getReminderFilePath(sessionId, hookName, reminderName);
58371
- await this.options.stateService.delete(reminderPath);
58442
+ return this.options.stateService.delete(reminderPath);
58372
58443
  }
58373
58444
  /**
58374
58445
  * List consumed reminder files for a specific reminder ID.
@@ -60909,7 +60980,7 @@ var require_state_service = __commonJS({
60909
60980
  }
60910
60981
  /**
60911
60982
  * Delete state file if it exists.
60912
- * No-op if file doesn't exist.
60983
+ * @returns true if the file was actually deleted, false if it didn't exist
60913
60984
  */
60914
60985
  async delete(path) {
60915
60986
  try {
@@ -60918,10 +60989,12 @@ var require_state_service = __commonJS({
60918
60989
  this.cache.delete(path);
60919
60990
  }
60920
60991
  this.logger?.debug("State deleted", { path });
60992
+ return true;
60921
60993
  } catch (err) {
60922
60994
  if (!isEnoent(err)) {
60923
60995
  throw err;
60924
60996
  }
60997
+ return false;
60925
60998
  }
60926
60999
  }
60927
61000
  /**
@@ -61176,7 +61249,7 @@ var require_typed_accessor = __commonJS({
61176
61249
  */
61177
61250
  async delete(sessionId) {
61178
61251
  const path = this.stateService.sessionStatePath(sessionId, this.descriptor.filename);
61179
- return this.stateService.delete(path);
61252
+ await this.stateService.delete(path);
61180
61253
  }
61181
61254
  /**
61182
61255
  * Get the path for a session state file.
@@ -61222,7 +61295,7 @@ var require_typed_accessor = __commonJS({
61222
61295
  */
61223
61296
  async delete() {
61224
61297
  const path = this.stateService.globalStatePath(this.descriptor.filename);
61225
- return this.stateService.delete(path);
61298
+ await this.stateService.delete(path);
61226
61299
  }
61227
61300
  /**
61228
61301
  * Get the path for the global state file.
@@ -61544,6 +61617,10 @@ var require_transcript_service = __commonJS({
61544
61617
  prepared = false;
61545
61618
  /** Track whether we're in bulk processing mode (first-time transcript replay) */
61546
61619
  isBulkProcessing = false;
61620
+ /** One-shot guard — prevents BulkProcessingComplete from firing more than once per instance */
61621
+ hasFiredBulkComplete = false;
61622
+ /** Timestamp when bulk processing started (for duration calculation in finish event) */
61623
+ bulkStartTime = 0;
61547
61624
  /** Map tool_use_id → tool name so ToolResult events can include the tool name */
61548
61625
  toolUseIdToName = /* @__PURE__ */ new Map();
61549
61626
  // Streaming state for incremental file processing
@@ -62283,12 +62360,10 @@ var require_transcript_service = __commonJS({
62283
62360
  }
62284
62361
  const startLine = this.metrics.lastProcessedLine;
62285
62362
  const isBulkStart = startLine === 0 && this.lastProcessedByteOffset === 0;
62286
- if (isBulkStart) {
62363
+ if (isBulkStart && !this.hasFiredBulkComplete) {
62287
62364
  this.isBulkProcessing = true;
62288
- this.options.logger.info("Bulk processing started (streaming)", {
62289
- sessionId: this.sessionId,
62290
- fileSize: currentFileSize
62291
- });
62365
+ this.bulkStartTime = Date.now();
62366
+ (0, structured_logging_js_1.logEvent)(this.options.logger, structured_logging_js_1.LogEvents.bulkProcessingStart({ sessionId: this.sessionId }, { fileSize: currentFileSize }));
62292
62367
  }
62293
62368
  const stream = (0, node_fs_1.createReadStream)(this.transcriptPath, {
62294
62369
  encoding: "utf-8",
@@ -62346,13 +62421,12 @@ var require_transcript_service = __commonJS({
62346
62421
  totalLines: lineNumber,
62347
62422
  newByteOffset: bytesRead
62348
62423
  });
62349
- if (isBulkStart && this.isBulkProcessing) {
62424
+ if (isBulkStart && this.isBulkProcessing && !this.hasFiredBulkComplete) {
62350
62425
  this.isBulkProcessing = false;
62426
+ this.hasFiredBulkComplete = true;
62427
+ const durationMs = Date.now() - this.bulkStartTime;
62428
+ (0, structured_logging_js_1.logEvent)(this.options.logger, structured_logging_js_1.LogEvents.bulkProcessingFinish({ sessionId: this.sessionId }, { totalLinesProcessed: lineNumber, durationMs }));
62351
62429
  await this.emitEvent("BulkProcessingComplete", {}, lineNumber);
62352
- this.options.logger.info("Bulk processing complete", {
62353
- sessionId: this.sessionId,
62354
- totalLinesProcessed: lineNumber
62355
- });
62356
62430
  }
62357
62431
  this.notifyMetricsChange();
62358
62432
  this.schedulePersistence();
@@ -71461,7 +71535,7 @@ var require_types2 = __commonJS({
71461
71535
  "../feature-reminders/dist/types.js"(exports2) {
71462
71536
  "use strict";
71463
71537
  Object.defineProperty(exports2, "__esModule", { value: true });
71464
- exports2.ALL_VC_REMINDER_IDS = exports2.VC_TOOL_REMINDER_IDS = exports2.TOOL_REMINDER_MAP = exports2.ReminderIds = exports2.DEFAULT_REMINDERS_SETTINGS = exports2.DEFAULT_COMPLETION_DETECTION_SETTINGS = exports2.DEFAULT_SOURCE_CODE_PATTERNS = exports2.DEFAULT_VERIFICATION_TOOLS = exports2.VerificationToolsMapSchema = exports2.VerificationToolConfigSchema = exports2.ToolPatternSchema = exports2.ToolPatternScopeSchema = void 0;
71538
+ exports2.ALL_VC_REMINDER_IDS = exports2.VC_TOOL_REMINDER_IDS = exports2.TOOL_REMINDER_MAP = exports2.ReminderIds = exports2.DEFAULT_REMINDERS_SETTINGS = exports2.DEFAULT_COMPLETION_DETECTION_SETTINGS = exports2.DEFAULT_SOURCE_CODE_PATTERNS = exports2.DEFAULT_VERIFICATION_TOOLS = exports2.CommandRunnerSchema = exports2.VerificationToolsMapSchema = exports2.VerificationToolConfigSchema = exports2.ToolPatternSchema = exports2.ToolPatternScopeSchema = void 0;
71465
71539
  var zod_1 = require_zod2();
71466
71540
  exports2.ToolPatternScopeSchema = zod_1.z.enum(["project", "package", "file"]);
71467
71541
  exports2.ToolPatternSchema = zod_1.z.object({
@@ -71476,6 +71550,9 @@ var require_types2 = __commonJS({
71476
71550
  clearing_patterns: zod_1.z.array(zod_1.z.string()).min(1)
71477
71551
  });
71478
71552
  exports2.VerificationToolsMapSchema = zod_1.z.record(zod_1.z.string(), exports2.VerificationToolConfigSchema);
71553
+ exports2.CommandRunnerSchema = zod_1.z.object({
71554
+ prefix: zod_1.z.string().trim().min(1)
71555
+ });
71479
71556
  exports2.DEFAULT_VERIFICATION_TOOLS = {
71480
71557
  build: {
71481
71558
  enabled: true,
@@ -71664,7 +71741,30 @@ var require_types2 = __commonJS({
71664
71741
  reminder_thresholds: {
71665
71742
  "user-prompt-submit": 10,
71666
71743
  "remember-your-persona": 5
71667
- }
71744
+ },
71745
+ command_runners: [
71746
+ // Python
71747
+ { prefix: "uv run" },
71748
+ { prefix: "poetry run" },
71749
+ { prefix: "pipx run" },
71750
+ { prefix: "pdm run" },
71751
+ { prefix: "hatch run" },
71752
+ { prefix: "conda run" },
71753
+ // Node.js
71754
+ { prefix: "npx" },
71755
+ { prefix: "pnpx" },
71756
+ { prefix: "bunx" },
71757
+ { prefix: "pnpm dlx" },
71758
+ { prefix: "pnpm exec" },
71759
+ { prefix: "bun run" },
71760
+ { prefix: "yarn dlx" },
71761
+ { prefix: "yarn exec" },
71762
+ { prefix: "npm exec" },
71763
+ // Ruby
71764
+ { prefix: "bundle exec" },
71765
+ // .NET
71766
+ { prefix: "dotnet tool run" }
71767
+ ]
71668
71768
  };
71669
71769
  exports2.ReminderIds = {
71670
71770
  USER_PROMPT_SUBMIT: "user-prompt-submit",
@@ -71767,6 +71867,7 @@ var require_stage_default_user_prompt = __commonJS({
71767
71867
  "use strict";
71768
71868
  Object.defineProperty(exports2, "__esModule", { value: true });
71769
71869
  exports2.registerStageDefaultUserPrompt = registerStageDefaultUserPrompt;
71870
+ var core_1 = require_dist4();
71770
71871
  var types_1 = require_dist();
71771
71872
  var staging_handler_utils_js_1 = require_staging_handler_utils();
71772
71873
  var types_js_1 = require_types2();
@@ -71895,6 +71996,16 @@ var require_stage_default_user_prompt = __commonJS({
71895
71996
  continue;
71896
71997
  const newCount = typedEntry.messagesSinceLastStaging + 1;
71897
71998
  if (newCount >= threshold) {
71999
+ (0, core_1.logEvent)(handlerCtx.logger, types_1.DecisionEvents.decisionRecorded({ sessionId }, {
72000
+ decision: "staged",
72001
+ reason: [
72002
+ `message count reached threshold (${newCount}/${threshold})`,
72003
+ `target hook: ${typedEntry.targetHook}`,
72004
+ `messages since last staging: ${typedEntry.messagesSinceLastStaging}`
72005
+ ].join("; "),
72006
+ subsystem: "reminder-throttle",
72007
+ title: `Re-stage ${reminderId} reminder`
72008
+ }));
71898
72009
  const metrics = event.metadata.metrics;
71899
72010
  const stagedAt = {
71900
72011
  timestamp: Date.now(),
@@ -71955,6 +72066,9 @@ var require_events2 = __commonJS({
71955
72066
  blocking: state.blocking,
71956
72067
  priority: state.priority,
71957
72068
  persistent: state.persistent,
72069
+ ...state.renderedText !== void 0 && {
72070
+ renderedText: state.renderedText
72071
+ },
71958
72072
  ...state.classificationResult !== void 0 && {
71959
72073
  classificationResult: state.classificationResult
71960
72074
  }
@@ -72103,6 +72217,12 @@ var require_stage_pause_and_reflect = __commonJS({
72103
72217
  }));
72104
72218
  return void 0;
72105
72219
  }
72220
+ (0, core_1.logEvent)(ctx.logger, types_1.DecisionEvents.decisionRecorded({ sessionId }, {
72221
+ decision: "staged",
72222
+ reason: `tools since baseline reached threshold (${toolsSinceBaseline}/${config.pause_and_reflect_threshold})`,
72223
+ subsystem: "pause-reflect",
72224
+ title: "Stage pause-and-reflect reminder"
72225
+ }));
72106
72226
  return {
72107
72227
  reminderId: types_js_1.ReminderIds.PAUSE_AND_REFLECT,
72108
72228
  targetHook: "PreToolUse",
@@ -73640,17 +73760,51 @@ var require_tool_pattern_matcher = __commonJS({
73640
73760
  exports2.matchesToolPattern = matchesToolPattern;
73641
73761
  exports2.findMatchingPattern = findMatchingPattern;
73642
73762
  var SHELL_OPERATOR_RE = /\s*(?:&&|\|\||[;|])\s*/;
73643
- function matchesToolPattern(command, pattern) {
73763
+ function detectRunnerPrefix(segmentTokens, runners) {
73764
+ let longestMatch = 0;
73765
+ for (const runner of runners) {
73766
+ if (typeof runner.prefix !== "string")
73767
+ continue;
73768
+ const prefixTokens = runner.prefix.trim().split(/\s+/);
73769
+ if (prefixTokens.length === 0)
73770
+ continue;
73771
+ if (prefixTokens.length > segmentTokens.length)
73772
+ continue;
73773
+ let matches = true;
73774
+ for (let i = 0; i < prefixTokens.length; i++) {
73775
+ if (segmentTokens[i] !== prefixTokens[i]) {
73776
+ matches = false;
73777
+ break;
73778
+ }
73779
+ }
73780
+ if (matches && prefixTokens.length > longestMatch) {
73781
+ longestMatch = prefixTokens.length;
73782
+ }
73783
+ }
73784
+ return longestMatch;
73785
+ }
73786
+ function matchesToolPattern(command, pattern, runners) {
73644
73787
  if (!command || !pattern)
73645
73788
  return false;
73646
73789
  const segments = command.split(SHELL_OPERATOR_RE);
73647
73790
  const patternTokens = pattern.trim().split(/\s+/).filter(Boolean);
73648
73791
  if (patternTokens.length === 0)
73649
73792
  return false;
73793
+ const activeRunners = runners?.length ? runners : void 0;
73650
73794
  return segments.some((segment) => {
73651
73795
  const cmdTokens = segment.trim().split(/\s+/);
73652
73796
  if (cmdTokens.length === 0 || cmdTokens[0] === "")
73653
73797
  return false;
73798
+ const runnerTokenCount = activeRunners ? detectRunnerPrefix(cmdTokens, activeRunners) : 0;
73799
+ if (runnerTokenCount > 0) {
73800
+ let pi2 = 0;
73801
+ for (let ci = runnerTokenCount; ci < cmdTokens.length && pi2 < patternTokens.length; ci++) {
73802
+ if (patternTokens[pi2] === "*" || patternTokens[pi2] === cmdTokens[ci]) {
73803
+ pi2++;
73804
+ }
73805
+ }
73806
+ return pi2 === patternTokens.length;
73807
+ }
73654
73808
  if (cmdTokens[0] !== patternTokens[0])
73655
73809
  return false;
73656
73810
  let pi = 1;
@@ -73662,11 +73816,11 @@ var require_tool_pattern_matcher = __commonJS({
73662
73816
  return pi === patternTokens.length;
73663
73817
  });
73664
73818
  }
73665
- function findMatchingPattern(command, patterns) {
73819
+ function findMatchingPattern(command, patterns, runners) {
73666
73820
  for (const pattern of patterns) {
73667
73821
  if (pattern.tool === null)
73668
73822
  continue;
73669
- if (matchesToolPattern(command, pattern.tool))
73823
+ if (matchesToolPattern(command, pattern.tool, runners))
73670
73824
  return pattern;
73671
73825
  }
73672
73826
  return null;
@@ -73722,13 +73876,14 @@ var require_track_verification_tools = __commonJS({
73722
73876
  const featureConfig = context.config.getFeature("reminders");
73723
73877
  const config = { ...types_js_1.DEFAULT_REMINDERS_SETTINGS, ...featureConfig.settings };
73724
73878
  const verificationTools = config.verification_tools ?? {};
73879
+ const runners = config.command_runners ?? [];
73725
73880
  const remindersState = (0, state_js_1.createRemindersState)(daemonCtx.stateService);
73726
73881
  const stateResult = await remindersState.verificationTools.read(sessionId);
73727
73882
  const toolsState = { ...stateResult.data };
73728
73883
  if (FILE_EDIT_TOOLS.includes(toolName)) {
73729
73884
  await handleFileEdit(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState);
73730
73885
  } else if (toolName === "Bash") {
73731
- await handleBashCommand(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState);
73886
+ await handleBashCommand(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState, runners);
73732
73887
  }
73733
73888
  }
73734
73889
  });
@@ -73790,12 +73945,21 @@ var require_track_verification_tools = __commonJS({
73790
73945
  } else {
73791
73946
  const newEdits = current.editsSinceVerified + 1;
73792
73947
  if (newEdits >= toolConfig.clearing_threshold) {
73948
+ const wasAlreadyStaged = stagedNames.has(reminderId);
73793
73949
  const staged = await ensureToolReminderStaged(daemonCtx, reminderId, stagedNames, {
73794
73950
  reason: "threshold_reached",
73795
73951
  triggeredBy: "file_edit",
73796
73952
  thresholdState: { current: newEdits, threshold: toolConfig.clearing_threshold }
73797
73953
  });
73798
73954
  if (staged) {
73955
+ if (!wasAlreadyStaged) {
73956
+ (0, core_1.logEvent)(daemonCtx.logger, types_1.DecisionEvents.decisionRecorded({ sessionId }, {
73957
+ decision: "staged",
73958
+ reason: `edits reached clearing threshold (${newEdits}/${toolConfig.clearing_threshold})`,
73959
+ subsystem: "vc-reminders",
73960
+ title: "Re-stage VC reminder (threshold reached)"
73961
+ }));
73962
+ }
73799
73963
  toolsState[toolName] = {
73800
73964
  ...current,
73801
73965
  status: "staged",
@@ -73841,7 +74005,7 @@ var require_track_verification_tools = __commonJS({
73841
74005
  return;
73842
74006
  await stageToolsForFiles([filePath], daemonCtx, sessionId, verificationTools, toolsState, remindersState);
73843
74007
  }
73844
- async function handleBashCommand(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState) {
74008
+ async function handleBashCommand(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState, runners = []) {
73845
74009
  const command = extractToolInput(event)?.command;
73846
74010
  if (!command)
73847
74011
  return;
@@ -73852,7 +74016,7 @@ var require_track_verification_tools = __commonJS({
73852
74016
  const reminderId = types_js_1.TOOL_REMINDER_MAP[toolName];
73853
74017
  if (!reminderId)
73854
74018
  continue;
73855
- const match = (0, tool_pattern_matcher_js_1.findMatchingPattern)(command, toolConfig.patterns);
74019
+ const match = (0, tool_pattern_matcher_js_1.findMatchingPattern)(command, toolConfig.patterns, runners);
73856
74020
  if (!match)
73857
74021
  continue;
73858
74022
  toolsState[toolName] = {
@@ -73863,7 +74027,15 @@ var require_track_verification_tools = __commonJS({
73863
74027
  lastMatchedToolId: match.tool_id,
73864
74028
  lastMatchedScope: match.scope
73865
74029
  };
73866
- await daemonCtx.staging.deleteReminder("Stop", reminderId);
74030
+ const deleted = await daemonCtx.staging.deleteReminder("Stop", reminderId);
74031
+ if (deleted) {
74032
+ (0, core_1.logEvent)(daemonCtx.logger, types_1.DecisionEvents.decisionRecorded({ sessionId }, {
74033
+ decision: "unstaged",
74034
+ reason: `verification passed for ${toolName} (matched ${match.tool_id})`,
74035
+ subsystem: "vc-reminders",
74036
+ title: "Unstage VC reminder (verified)"
74037
+ }));
74038
+ }
73867
74039
  (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
73868
74040
  reminderName: reminderId,
73869
74041
  hookName: "Stop",
@@ -74066,8 +74238,9 @@ var require_unstage_verify_completion = __commonJS({
74066
74238
  Object.defineProperty(exports2, "__esModule", { value: true });
74067
74239
  exports2.registerUnstageVerifyCompletion = registerUnstageVerifyCompletion;
74068
74240
  var core_1 = require_dist4();
74069
- var events_js_1 = require_events2();
74070
74241
  var types_1 = require_dist();
74242
+ var events_js_1 = require_events2();
74243
+ var types_2 = require_dist();
74071
74244
  var types_js_1 = require_types2();
74072
74245
  var reminder_utils_js_1 = require_reminder_utils();
74073
74246
  var state_js_1 = require_state4();
@@ -74084,7 +74257,7 @@ var require_unstage_verify_completion = __commonJS({
74084
74257
  return false;
74085
74258
  }
74086
74259
  function registerUnstageVerifyCompletion(context) {
74087
- if (!(0, types_1.isDaemonContext)(context))
74260
+ if (!(0, types_2.isDaemonContext)(context))
74088
74261
  return;
74089
74262
  context.handlers.register({
74090
74263
  id: "reminders:unstage-verify-completion",
@@ -74092,17 +74265,19 @@ var require_unstage_verify_completion = __commonJS({
74092
74265
  // Before consumption handlers (50)
74093
74266
  filter: { kind: "hook", hooks: ["UserPromptSubmit"] },
74094
74267
  handler: async (event, ctx) => {
74095
- if (!(0, types_1.isHookEvent)(event))
74268
+ if (!(0, types_2.isHookEvent)(event))
74096
74269
  return;
74097
- if (!(0, types_1.isDaemonContext)(ctx))
74270
+ if (!(0, types_2.isDaemonContext)(ctx))
74098
74271
  return;
74099
74272
  const daemonCtx = ctx;
74100
74273
  const sessionId = event.context?.sessionId;
74101
74274
  if (!sessionId) {
74102
74275
  daemonCtx.logger.warn("No sessionId in UserPromptSubmit event");
74103
74276
  for (const vcId of types_js_1.ALL_VC_REMINDER_IDS) {
74104
- await daemonCtx.staging.deleteReminder("Stop", vcId);
74105
- (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId: "" }, { reminderName: vcId, hookName: "Stop", reason: "no_session_id" }));
74277
+ const deleted = await daemonCtx.staging.deleteReminder("Stop", vcId);
74278
+ if (deleted) {
74279
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId: "" }, { reminderName: vcId, hookName: "Stop", reason: "no_session_id" }));
74280
+ }
74106
74281
  }
74107
74282
  return;
74108
74283
  }
@@ -74187,6 +74362,12 @@ var require_unstage_verify_completion = __commonJS({
74187
74362
  maxCycles
74188
74363
  });
74189
74364
  await remindersState.vcUnverified.delete(sessionId);
74365
+ (0, core_1.logEvent)(daemonCtx.logger, types_1.DecisionEvents.decisionRecorded({ sessionId }, {
74366
+ decision: "unstaged-all",
74367
+ reason: `verification cycle limit reached (${unverifiedState.cycleCount}/${maxCycles})`,
74368
+ subsystem: "vc-reminders",
74369
+ title: "Unstage all VC reminders (cycle limit)"
74370
+ }));
74190
74371
  }
74191
74372
  } else {
74192
74373
  (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderNotStaged({ sessionId }, {
@@ -74201,16 +74382,24 @@ var require_unstage_verify_completion = __commonJS({
74201
74382
  }
74202
74383
  const eventContext = { sessionId };
74203
74384
  const reason = unverifiedState?.hasUnverifiedChanges ? "cycle_limit_reached" : "no_unverified_changes";
74385
+ let deletedCount = 0;
74204
74386
  for (const vcId of types_js_1.ALL_VC_REMINDER_IDS) {
74205
- await daemonCtx.staging.deleteReminder("Stop", vcId);
74206
- (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged(eventContext, {
74207
- reminderName: vcId,
74208
- hookName: "Stop",
74209
- reason,
74210
- triggeredBy: unverifiedState?.hasUnverifiedChanges ? "cycle_limit" : "no_unverified_changes"
74211
- }));
74387
+ const deleted = await daemonCtx.staging.deleteReminder("Stop", vcId);
74388
+ if (deleted) {
74389
+ deletedCount++;
74390
+ (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged(eventContext, {
74391
+ reminderName: vcId,
74392
+ hookName: "Stop",
74393
+ reason,
74394
+ triggeredBy: unverifiedState?.hasUnverifiedChanges ? "cycle_limit" : "no_unverified_changes"
74395
+ }));
74396
+ }
74212
74397
  }
74213
- daemonCtx.logger.debug("VC unstage: deleted all VC reminders");
74398
+ daemonCtx.logger.debug("VC unstage: cleanup complete", {
74399
+ reason,
74400
+ deletedCount,
74401
+ totalChecked: types_js_1.ALL_VC_REMINDER_IDS.length
74402
+ });
74214
74403
  }
74215
74404
  });
74216
74405
  }
@@ -74643,6 +74832,12 @@ var require_consumption_handler_factory = __commonJS({
74643
74832
  if (onConsume) {
74644
74833
  await onConsume({ reminder: primary, reader, cliCtx, sessionId });
74645
74834
  }
74835
+ const renderedParts = [];
74836
+ if (response.userMessage)
74837
+ renderedParts.push(response.userMessage);
74838
+ if (response.additionalContext)
74839
+ renderedParts.push(response.additionalContext);
74840
+ const renderedText = renderedParts.length > 0 ? renderedParts.join("\n\n") : void 0;
74646
74841
  (0, core_1.logEvent)(cliCtx.logger, events_js_1.ReminderEvents.reminderConsumed({
74647
74842
  sessionId,
74648
74843
  hook
@@ -74652,6 +74847,7 @@ var require_consumption_handler_factory = __commonJS({
74652
74847
  blocking: response.blocking ?? false,
74653
74848
  priority: primary.priority,
74654
74849
  persistent: primary.persistent,
74850
+ renderedText,
74655
74851
  ...enrichment
74656
74852
  }));
74657
74853
  return { response };
@@ -75172,16 +75368,24 @@ var require_orchestrator = __commonJS({
75172
75368
  const staging = this.deps.getStagingService(sessionId);
75173
75369
  const eventContext = { sessionId };
75174
75370
  const sessionLogger = this.deps.logger.child({ context: { sessionId } });
75371
+ let deletedCount = 0;
75175
75372
  for (const vcId of types_js_1.ALL_VC_REMINDER_IDS) {
75176
- await staging.deleteReminder("Stop", vcId);
75177
- (0, core_1.logEvent)(sessionLogger, events_js_1.ReminderEvents.reminderUnstaged(eventContext, {
75178
- reminderName: vcId,
75179
- hookName: "Stop",
75180
- reason: "pause_and_reflect_cascade",
75181
- triggeredBy: "cascade_from_pause_and_reflect"
75182
- }));
75373
+ const deleted = await staging.deleteReminder("Stop", vcId);
75374
+ if (deleted) {
75375
+ deletedCount++;
75376
+ (0, core_1.logEvent)(sessionLogger, events_js_1.ReminderEvents.reminderUnstaged(eventContext, {
75377
+ reminderName: vcId,
75378
+ hookName: "Stop",
75379
+ reason: "pause_and_reflect_cascade",
75380
+ triggeredBy: "cascade_from_pause_and_reflect"
75381
+ }));
75382
+ }
75183
75383
  }
75184
- this.deps.logger.debug("Unstaged all VC reminders after P&R staged", { sessionId });
75384
+ this.deps.logger.debug("VC unstage: P&R cascade complete", {
75385
+ sessionId,
75386
+ deletedCount,
75387
+ totalChecked: types_js_1.ALL_VC_REMINDER_IDS.length
75388
+ });
75185
75389
  } catch (err) {
75186
75390
  this.deps.logger.warn("Failed to unstage VC reminders after P&R staged", {
75187
75391
  sessionId,
@@ -75214,14 +75418,16 @@ var require_orchestrator = __commonJS({
75214
75418
  }
75215
75419
  try {
75216
75420
  const staging = this.deps.getStagingService(sessionId);
75217
- await staging.deleteReminder("PreToolUse", types_js_1.ReminderIds.PAUSE_AND_REFLECT);
75218
- (0, core_1.logEvent)(this.deps.logger.child({ context: { sessionId } }), events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
75219
- reminderName: types_js_1.ReminderIds.PAUSE_AND_REFLECT,
75220
- hookName: "PreToolUse",
75221
- reason: "vc_consumed_cascade",
75222
- triggeredBy: "cascade_from_verify_completion"
75223
- }));
75224
- this.deps.logger.debug("Unstaged P&R after VC consumed", { sessionId });
75421
+ const deleted = await staging.deleteReminder("PreToolUse", types_js_1.ReminderIds.PAUSE_AND_REFLECT);
75422
+ if (deleted) {
75423
+ (0, core_1.logEvent)(this.deps.logger.child({ context: { sessionId } }), events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
75424
+ reminderName: types_js_1.ReminderIds.PAUSE_AND_REFLECT,
75425
+ hookName: "PreToolUse",
75426
+ reason: "vc_consumed_cascade",
75427
+ triggeredBy: "cascade_from_verify_completion"
75428
+ }));
75429
+ }
75430
+ this.deps.logger.debug("VC unstage: P&R cascade from VC consumed", { sessionId, deleted });
75225
75431
  } catch (err) {
75226
75432
  this.deps.logger.warn("Failed to unstage P&R after VC consumed", {
75227
75433
  sessionId,
@@ -75404,6 +75610,8 @@ var require_hook = __commonJS({
75404
75610
  "../sidekick-cli/dist/commands/hook.js"(exports2) {
75405
75611
  "use strict";
75406
75612
  Object.defineProperty(exports2, "__esModule", { value: true });
75613
+ exports2.truncateForLog = truncateForLog;
75614
+ exports2.buildHookInput = buildHookInput;
75407
75615
  exports2.validateHookName = validateHookName;
75408
75616
  exports2.buildHookEvent = buildHookEvent;
75409
75617
  exports2.mergeHookResponses = mergeHookResponses;
@@ -75412,6 +75620,33 @@ var require_hook = __commonJS({
75412
75620
  exports2.getHookName = getHookName;
75413
75621
  var core_1 = require_dist4();
75414
75622
  var context_js_1 = require_context2();
75623
+ function truncateForLog(raw) {
75624
+ const entries = Object.entries(raw);
75625
+ const needsKeyTruncation = entries.length > 20;
75626
+ const result = {};
75627
+ const toProcess = needsKeyTruncation ? entries.slice(0, 20) : entries;
75628
+ for (const [key, value] of toProcess) {
75629
+ if (typeof value === "string" && value.length > 500) {
75630
+ result[key] = value.slice(0, 500) + "\u2026";
75631
+ } else {
75632
+ result[key] = value;
75633
+ }
75634
+ }
75635
+ if (needsKeyTruncation) {
75636
+ result["_truncated"] = true;
75637
+ }
75638
+ return result;
75639
+ }
75640
+ var STRIP_FIELDS = /* @__PURE__ */ new Set(["session_id", "transcript_path", "hook_event_name"]);
75641
+ function buildHookInput(raw) {
75642
+ const filtered = {};
75643
+ for (const [key, value] of Object.entries(raw)) {
75644
+ if (!STRIP_FIELDS.has(key)) {
75645
+ filtered[key] = value;
75646
+ }
75647
+ }
75648
+ return truncateForLog(filtered);
75649
+ }
75415
75650
  var VALID_HOOK_NAMES = /* @__PURE__ */ new Set([
75416
75651
  "SessionStart",
75417
75652
  "SessionEnd",
@@ -75582,7 +75817,12 @@ ${daemonResponse.additionalContext}` : cliResponse.additionalContext;
75582
75817
  correlationId,
75583
75818
  hook: hookName
75584
75819
  };
75585
- (0, core_1.logEvent)(logger, core_1.LogEvents.hookReceived(logContext, { cwd: hookInput.cwd, mode: "hook" }));
75820
+ const builtInput = buildHookInput(hookInput.raw);
75821
+ (0, core_1.logEvent)(logger, core_1.LogEvents.hookReceived(logContext, {
75822
+ cwd: hookInput.cwd,
75823
+ mode: "hook",
75824
+ ...Object.keys(builtInput).length > 0 ? { input: builtInput } : {}
75825
+ }));
75586
75826
  logger.debug("Hook invocation received", { hook: hookName, sessionId: hookInput.sessionId });
75587
75827
  const event = buildHookEvent(hookName, hookInput, correlationId);
75588
75828
  logger.debug("Dispatching hook event to daemon", {
@@ -75634,7 +75874,8 @@ ${daemonResponse.additionalContext}` : cliResponse.additionalContext;
75634
75874
  const outputStr = JSON.stringify(mergedResponse);
75635
75875
  stdout.write(`${outputStr}
75636
75876
  `);
75637
- (0, core_1.logEvent)(logger, core_1.LogEvents.hookCompleted(logContext, { durationMs: Date.now() - startTime }, { reminderReturned: !!mergedResponse.additionalContext }));
75877
+ const returnValue = Object.keys(mergedResponse).length > 0 ? truncateForLog(mergedResponse) : void 0;
75878
+ (0, core_1.logEvent)(logger, core_1.LogEvents.hookCompleted(logContext, { durationMs: Date.now() - startTime }, { reminderReturned: !!mergedResponse.additionalContext, returnValue }));
75638
75879
  return { exitCode: 0, output: outputStr };
75639
75880
  }
75640
75881
  function isHookCommand(command) {
@@ -76194,7 +76435,7 @@ var require_types3 = __commonJS({
76194
76435
  });
76195
76436
  exports2.DEFAULT_STATUSLINE_CONFIG = {
76196
76437
  enabled: true,
76197
- format: "{personaName,prefix='[',suffix='] | '}{model,prefix='[',suffix='] | '}{contextBar} {tokenPercentageActual} | {logs} | {cwd,maxLength=40,truncateStyle='path'}{branch,prefix=' \u2217 ',maxLength=40}{title,wrapAt=80,prefix=' | ',wrapPrefix='\\n'}\n{summary}",
76438
+ format: "{personaName,prefix='[',suffix='] | '}{model,prefix='[',suffix='] | '}{contextBar} {tokenPercentageActual} | {logs} | {cwd,maxLength=40,truncateStyle='path'}{branchWT,prefix=' | ',maxLength=40}{title,wrapAt=80,prefix=' | ',wrapPrefix='\\n'}\n{summary}",
76198
76439
  thresholds: {
76199
76440
  tokens: { warning: 1e5, critical: 16e4 },
76200
76441
  cost: { warning: 0.5, critical: 1 },
@@ -76706,7 +76947,7 @@ var require_events3 = __commonJS({
76706
76947
  "../feature-session-summary/dist/events.js"(exports2) {
76707
76948
  "use strict";
76708
76949
  Object.defineProperty(exports2, "__esModule", { value: true });
76709
- exports2.DecisionEvents = exports2.SessionSummaryEvents = void 0;
76950
+ exports2.SessionSummaryEvents = void 0;
76710
76951
  exports2.SessionSummaryEvents = {
76711
76952
  /** Emitted when summary generation begins. */
76712
76953
  summaryStart(context, payload) {
@@ -76828,24 +77069,6 @@ var require_events3 = __commonJS({
76828
77069
  };
76829
77070
  }
76830
77071
  };
76831
- exports2.DecisionEvents = {
76832
- /** Emitted when an LLM decision is recorded. */
76833
- decisionRecorded(context, payload) {
76834
- return {
76835
- type: "decision:recorded",
76836
- time: Date.now(),
76837
- source: "daemon",
76838
- context: {
76839
- sessionId: context.sessionId,
76840
- correlationId: context.correlationId,
76841
- traceId: context.traceId,
76842
- hook: context.hook,
76843
- taskId: context.taskId
76844
- },
76845
- payload
76846
- };
76847
- }
76848
- };
76849
77072
  }
76850
77073
  });
76851
77074
 
@@ -77001,15 +77224,20 @@ var require_update_summary = __commonJS({
77001
77224
  "use strict";
77002
77225
  Object.defineProperty(exports2, "__esModule", { value: true });
77003
77226
  exports2.buildPersonaContext = void 0;
77227
+ exports2.resetAnalysisGuard = resetAnalysisGuard;
77004
77228
  exports2.interpolateTemplate = interpolateTemplate;
77005
77229
  exports2.updateSessionSummary = updateSessionSummary;
77006
77230
  var core_1 = require_dist4();
77007
77231
  var events_js_1 = require_events3();
77232
+ var types_1 = require_dist();
77008
77233
  var zod_1 = require_zod();
77009
77234
  var types_js_1 = require_types4();
77010
77235
  var state_js_1 = require_state5();
77011
77236
  var persona_utils_js_1 = require_persona_utils();
77012
77237
  var persona_selection_js_1 = require_persona_selection();
77238
+ var DECISION_TITLE_SKIP = "Skip session analysis";
77239
+ var DECISION_TITLE_RUN = "Run session analysis";
77240
+ var analysisInFlight = /* @__PURE__ */ new Map();
77013
77241
  var PROMPT_FILE = "prompts/session-summary.prompt.txt";
77014
77242
  var SNARKY_PROMPT_FILE = "prompts/snarky-message.prompt.txt";
77015
77243
  var RESUME_PROMPT_FILE = "prompts/resume-message.prompt.txt";
@@ -77027,6 +77255,9 @@ var require_update_summary = __commonJS({
77027
77255
  Object.defineProperty(exports2, "buildPersonaContext", { enumerable: true, get: function() {
77028
77256
  return persona_utils_js_2.buildPersonaContext;
77029
77257
  } });
77258
+ function resetAnalysisGuard() {
77259
+ analysisInFlight.clear();
77260
+ }
77030
77261
  function interpolateTemplate(template, context) {
77031
77262
  let result = template;
77032
77263
  const conditionalRegex = /\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g;
@@ -77060,46 +77291,39 @@ var require_update_summary = __commonJS({
77060
77291
  await (0, persona_selection_js_1.ensurePersonaForSession)(sessionId, ctx);
77061
77292
  const metrics = ctx.transcript.getMetrics();
77062
77293
  if (metrics.turnCount === 0) {
77063
- (0, core_1.logEvent)(ctx.logger, events_js_1.DecisionEvents.decisionRecorded(event.context, {
77294
+ (0, core_1.logEvent)(ctx.logger, types_1.DecisionEvents.decisionRecorded(event.context, {
77064
77295
  decision: "skipped",
77065
77296
  reason: "BulkProcessingComplete with no user turns (turnCount=0)",
77066
- detail: "session-summary analysis"
77297
+ subsystem: "session-summary",
77298
+ title: DECISION_TITLE_SKIP
77067
77299
  }));
77068
77300
  return;
77069
77301
  }
77070
- (0, core_1.logEvent)(ctx.logger, events_js_1.DecisionEvents.decisionRecorded(event.context, {
77302
+ (0, core_1.logEvent)(ctx.logger, types_1.DecisionEvents.decisionRecorded(event.context, {
77071
77303
  decision: "calling",
77072
- reason: "BulkProcessingComplete - analyzing full transcript",
77073
- detail: "session-summary analysis"
77304
+ reason: "Bulk transcript replay complete \u2014 running catch-up analysis",
77305
+ subsystem: "session-summary",
77306
+ title: DECISION_TITLE_RUN
77074
77307
  }));
77075
77308
  const countdown2 = await loadCountdownState(summaryState, sessionId);
77076
- void performAnalysis(event, ctx, summaryState, countdown2, "user_prompt_forced");
77309
+ void performAnalysis(event, ctx, summaryState, countdown2, "bulk_replay_complete");
77077
77310
  return;
77078
77311
  }
77079
77312
  const countdown = await loadCountdownState(summaryState, sessionId);
77080
77313
  if (isUserPrompt) {
77081
- (0, core_1.logEvent)(ctx.logger, events_js_1.DecisionEvents.decisionRecorded(event.context, {
77082
- decision: "calling",
77083
- reason: "UserPrompt event forces immediate analysis",
77084
- detail: "session-summary analysis"
77085
- }));
77086
77314
  void performAnalysis(event, ctx, summaryState, countdown, "user_prompt_forced");
77087
77315
  return;
77088
77316
  }
77089
77317
  if (countdown.countdown > 0) {
77090
- (0, core_1.logEvent)(ctx.logger, events_js_1.DecisionEvents.decisionRecorded(event.context, {
77091
- decision: "skipped",
77092
- reason: `countdown not reached (${countdown.countdown} tool results remaining)`,
77093
- detail: "session-summary analysis"
77094
- }));
77095
77318
  countdown.countdown--;
77096
77319
  await saveCountdownState(summaryState, sessionId, countdown);
77097
77320
  return;
77098
77321
  }
77099
- (0, core_1.logEvent)(ctx.logger, events_js_1.DecisionEvents.decisionRecorded(event.context, {
77322
+ (0, core_1.logEvent)(ctx.logger, types_1.DecisionEvents.decisionRecorded(event.context, {
77100
77323
  decision: "calling",
77101
- reason: "countdown reached zero after ToolResult",
77102
- detail: "session-summary analysis"
77324
+ reason: "Prompt countdown reached zero \u2014 running scheduled analysis",
77325
+ subsystem: "session-summary",
77326
+ title: DECISION_TITLE_RUN
77103
77327
  }));
77104
77328
  void performAnalysis(event, ctx, summaryState, countdown, "countdown_reached");
77105
77329
  }
@@ -77132,6 +77356,17 @@ var require_update_summary = __commonJS({
77132
77356
  }
77133
77357
  async function performAnalysis(event, ctx, summaryState, countdown, reason) {
77134
77358
  const { sessionId } = event.context;
77359
+ if (analysisInFlight.has(sessionId)) {
77360
+ analysisInFlight.set(sessionId, true);
77361
+ (0, core_1.logEvent)(ctx.logger, types_1.DecisionEvents.decisionRecorded(event.context, {
77362
+ decision: "deferred",
77363
+ reason: "Analysis deferred \u2014 will rerun after current analysis completes",
77364
+ subsystem: "session-summary",
77365
+ title: DECISION_TITLE_SKIP
77366
+ }));
77367
+ return;
77368
+ }
77369
+ analysisInFlight.set(sessionId, false);
77135
77370
  try {
77136
77371
  const startTime = Date.now();
77137
77372
  (0, core_1.logEvent)(ctx.logger, events_js_1.SessionSummaryEvents.summaryStart(event.context, {
@@ -77241,14 +77476,6 @@ var require_update_summary = __commonJS({
77241
77476
  if (sideEffects.length > 0) {
77242
77477
  await Promise.all(sideEffects);
77243
77478
  }
77244
- (0, core_1.logEvent)(ctx.logger, events_js_1.SessionSummaryEvents.summaryFinish(event.context, {
77245
- session_title: updatedSummary.session_title,
77246
- session_title_confidence: updatedSummary.session_title_confidence,
77247
- latest_intent: updatedSummary.latest_intent,
77248
- latest_intent_confidence: updatedSummary.latest_intent_confidence,
77249
- processing_time_ms: updatedSummary.stats?.processing_time_ms ?? 0,
77250
- pivot_detected: updatedSummary.pivot_detected ?? false
77251
- }));
77252
77479
  if (currentSummary && updatedSummary.session_title !== currentSummary.session_title) {
77253
77480
  (0, core_1.logEvent)(ctx.logger, events_js_1.SessionSummaryEvents.titleChanged(event.context, {
77254
77481
  previousValue: currentSummary.session_title,
@@ -77263,6 +77490,14 @@ var require_update_summary = __commonJS({
77263
77490
  confidence: updatedSummary.latest_intent_confidence
77264
77491
  }));
77265
77492
  }
77493
+ (0, core_1.logEvent)(ctx.logger, events_js_1.SessionSummaryEvents.summaryFinish(event.context, {
77494
+ session_title: updatedSummary.session_title,
77495
+ session_title_confidence: updatedSummary.session_title_confidence,
77496
+ latest_intent: updatedSummary.latest_intent,
77497
+ latest_intent_confidence: updatedSummary.latest_intent_confidence,
77498
+ processing_time_ms: updatedSummary.stats?.processing_time_ms ?? 0,
77499
+ pivot_detected: updatedSummary.pivot_detected ?? false
77500
+ }));
77266
77501
  ctx.logger.info("Updated session summary", {
77267
77502
  sessionId,
77268
77503
  reason,
@@ -77276,6 +77511,13 @@ var require_update_summary = __commonJS({
77276
77511
  reason,
77277
77512
  error: err instanceof Error ? err.message : String(err)
77278
77513
  });
77514
+ } finally {
77515
+ const rerunPending = analysisInFlight.get(sessionId) ?? false;
77516
+ analysisInFlight.delete(sessionId);
77517
+ if (rerunPending) {
77518
+ const freshCountdown = await loadCountdownState(summaryState, sessionId);
77519
+ void performAnalysis(event, ctx, summaryState, freshCountdown, reason);
77520
+ }
77279
77521
  }
77280
77522
  }
77281
77523
  async function loadCurrentSummary(summaryState, sessionId) {
@@ -77746,7 +77988,7 @@ var require_dist6 = __commonJS({
77746
77988
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
77747
77989
  };
77748
77990
  Object.defineProperty(exports2, "__esModule", { value: true });
77749
- exports2.DecisionEvents = exports2.SessionSummaryEvents = exports2.manifest = void 0;
77991
+ exports2.SessionSummaryEvents = exports2.manifest = void 0;
77750
77992
  exports2.register = register;
77751
77993
  var index_js_1 = require_handlers();
77752
77994
  exports2.manifest = {
@@ -77768,9 +78010,6 @@ var require_dist6 = __commonJS({
77768
78010
  Object.defineProperty(exports2, "SessionSummaryEvents", { enumerable: true, get: function() {
77769
78011
  return events_js_1.SessionSummaryEvents;
77770
78012
  } });
77771
- Object.defineProperty(exports2, "DecisionEvents", { enumerable: true, get: function() {
77772
- return events_js_1.DecisionEvents;
77773
- } });
77774
78013
  }
77775
78014
  });
77776
78015
 
@@ -78284,10 +78523,10 @@ var require_formatter = __commonJS({
78284
78523
  duration: viewModel.duration,
78285
78524
  cwd: viewModel.cwd,
78286
78525
  branch: viewModel.branch,
78526
+ branchWT: viewModel.branchWT,
78287
78527
  projectDirShort: viewModel.projectDirShort,
78288
78528
  projectDirFull: viewModel.projectDirFull,
78289
78529
  worktreeName: viewModel.worktreeName,
78290
- worktreeOrBranch: viewModel.worktreeOrBranch,
78291
78530
  summary: convertedSummary,
78292
78531
  title: convertedTitle,
78293
78532
  logs: logsText,
@@ -78318,9 +78557,15 @@ var require_formatter = __commonJS({
78318
78557
  case "projectDirFull":
78319
78558
  return this.colorize(value, this.theme.colors.cwd);
78320
78559
  case "branch":
78321
- case "worktreeOrBranch":
78322
78560
  case "worktreeName":
78323
78561
  return this.colorize(value, branchColor);
78562
+ case "branchWT": {
78563
+ const coloredBranch = this.colorize(value, branchColor);
78564
+ if (!viewModel.worktreeName)
78565
+ return coloredBranch;
78566
+ const wtColor = this.theme.colors.worktreeIndicator ?? "dim";
78567
+ return `${coloredBranch} ${this.colorize("[wt]", wtColor)}`;
78568
+ }
78324
78569
  case "summary":
78325
78570
  return this.colorize(value, this.theme.colors.summary);
78326
78571
  case "title":
@@ -78732,7 +78977,7 @@ var require_statusline_service = __commonJS({
78732
78977
  projectDirShort: "",
78733
78978
  projectDirFull: "",
78734
78979
  worktreeName: "",
78735
- worktreeOrBranch: "",
78980
+ branchWT: "",
78736
78981
  warningCount: 0,
78737
78982
  errorCount: 0,
78738
78983
  logStatus: "normal",
@@ -79152,7 +79397,7 @@ var require_statusline_service = __commonJS({
79152
79397
  projectDirShort,
79153
79398
  projectDirFull: homeShorten(projectRoot),
79154
79399
  worktreeName: worktree?.name ?? "",
79155
- worktreeOrBranch: worktree?.name ?? branch,
79400
+ branchWT: (0, formatter_js_1.formatBranch)(branch),
79156
79401
  displayMode,
79157
79402
  summary: summaryText,
79158
79403
  title,
@@ -79620,11 +79865,11 @@ var require_ui = __commonJS({
79620
79865
  exports2.handleUiCommand = handleUiCommand;
79621
79866
  var node_child_process_1 = require("node:child_process");
79622
79867
  var node_path_1 = require("node:path");
79623
- function resolveProductionServer() {
79868
+ function resolveUiPackageDir() {
79624
79869
  const cliCommandsDir = __dirname;
79625
79870
  const cliPackageDir = (0, node_path_1.resolve)(cliCommandsDir, "..", "..");
79626
- const workspaceRoot = (0, node_path_1.resolve)(cliPackageDir, "..");
79627
- return (0, node_path_1.join)(workspaceRoot, "sidekick-ui", "server", "production.js");
79871
+ const packagesDir = (0, node_path_1.resolve)(cliPackageDir, "..");
79872
+ return (0, node_path_1.join)(packagesDir, "sidekick-ui");
79628
79873
  }
79629
79874
  function openBrowser(url, logger) {
79630
79875
  const platform = process.platform;
@@ -79653,29 +79898,26 @@ var require_ui = __commonJS({
79653
79898
  });
79654
79899
  }
79655
79900
  }
79656
- async function handleUiCommand(projectDir, logger, stdout, options = {}) {
79901
+ async function handleUiCommand(logger, stdout, options = {}) {
79657
79902
  const port = options.port ?? 3e3;
79658
79903
  const host = options.host ?? "localhost";
79659
79904
  const shouldOpen = options.open !== false;
79660
- const preferProject = options.preferProject !== false;
79661
- const serverScript = resolveProductionServer();
79905
+ const uiPackageDir = resolveUiPackageDir();
79906
+ const viteBin = (0, node_path_1.join)(uiPackageDir, "node_modules", ".bin", "vite");
79662
79907
  const url = `http://${host}:${port}`;
79663
- const args = ["--port", String(port)];
79664
- if (!preferProject) {
79665
- args.push("--prefer-user");
79666
- }
79667
- logger.info("Starting Sidekick UI server", { port, host, serverScript });
79668
- const serverProcess = (0, node_child_process_1.spawn)("node", [serverScript, ...args], {
79908
+ const args = ["--port", String(port), "--host", host];
79909
+ logger.info("Starting Sidekick UI server", { port, host, viteBin });
79910
+ const serverProcess = (0, node_child_process_1.spawn)(viteBin, args, {
79669
79911
  stdio: ["ignore", "pipe", "pipe"],
79670
79912
  // Pipe stdout/stderr so we can capture output
79671
- cwd: projectDir
79913
+ cwd: uiPackageDir
79672
79914
  });
79673
79915
  let serverStarted = false;
79674
79916
  if (serverProcess.stdout) {
79675
79917
  serverProcess.stdout.on("data", (data) => {
79676
79918
  const output = data.toString();
79677
79919
  stdout.write(output);
79678
- if (!serverStarted && output.includes("Server listening")) {
79920
+ if (!serverStarted && output.includes("Local:")) {
79679
79921
  serverStarted = true;
79680
79922
  stdout.write(`
79681
79923
  `);
@@ -83771,7 +84013,7 @@ var require_cli = __commonJS({
83771
84013
  var promises_12 = require("node:fs/promises");
83772
84014
  var node_stream_1 = require("node:stream");
83773
84015
  var yargs_parser_1 = __importDefault2(require_build());
83774
- var VERSION = true ? "0.1.14" : "dev";
84016
+ var VERSION = true ? "0.1.16" : "dev";
83775
84017
  var SANDBOX_ERROR_MESSAGE = `Error: Daemon commands cannot run in sandbox mode.
83776
84018
 
83777
84019
  Claude Code's sandbox blocks Unix socket operations required for daemon IPC.
@@ -83866,7 +84108,6 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
83866
84108
  port: parsed.port,
83867
84109
  host: parsed.host,
83868
84110
  open: parsed.open,
83869
- preferProject: parsed["prefer-project"],
83870
84111
  sessionIdArg: parsed["session-id"],
83871
84112
  messageType: parsed.type,
83872
84113
  help: Boolean(parsed.help),
@@ -84086,11 +84327,10 @@ Run 'sidekick hook --help' for available hooks.
84086
84327
  }
84087
84328
  if (parsed.command === "ui") {
84088
84329
  const { handleUiCommand } = await Promise.resolve().then(() => __importStar(require_ui()));
84089
- const result = await handleUiCommand(runtime.projectRoot || process.cwd(), runtime.logger, stdout, {
84330
+ const result = await handleUiCommand(runtime.logger, stdout, {
84090
84331
  port: parsed.port,
84091
84332
  host: parsed.host,
84092
- open: parsed.open,
84093
- preferProject: parsed.preferProject
84333
+ open: parsed.open
84094
84334
  });
84095
84335
  return { exitCode: result.exitCode, stdout: "", stderr: "" };
84096
84336
  }