@scotthamilton77/sidekick 0.1.4 → 0.1.5

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
@@ -17213,7 +17213,7 @@ var require_state = __commonJS({
17213
17213
  "../types/dist/services/state.js"(exports2) {
17214
17214
  "use strict";
17215
17215
  Object.defineProperty(exports2, "__esModule", { value: true });
17216
- exports2.DEFAULT_LATENCY_STATS = exports2.LLMMetricsStateSchema = exports2.LLMSessionTotalsSchema = exports2.LLMProviderMetricsSchema = exports2.LLMModelMetricsSchema = exports2.LLMLatencyStatsSchema = exports2.DEFAULT_PROJECT_METRICS = exports2.DEFAULT_BASE_METRICS = exports2.SessionContextMetricsSchema = exports2.ProjectContextMetricsSchema = exports2.BaseTokenMetricsStateSchema = exports2.VerificationToolsStateSchema = exports2.VerificationToolStatusSchema = exports2.VCUnverifiedStateSchema = exports2.PRBaselineStateSchema = exports2.EMPTY_LOG_METRICS = exports2.LogMetricsStateSchema = exports2.TranscriptMetricsStateSchema = exports2.ResumeMessageStateSchema = exports2.SnarkyMessageStateSchema = exports2.SummaryCountdownStateSchema = exports2.LastStagedPersonaSchema = exports2.SessionPersonaStateSchema = exports2.SESSION_SUMMARY_PLACEHOLDERS = exports2.SessionSummaryStateSchema = void 0;
17216
+ exports2.DEFAULT_LATENCY_STATS = exports2.LLMMetricsStateSchema = exports2.LLMSessionTotalsSchema = exports2.LLMProviderMetricsSchema = exports2.LLMModelMetricsSchema = exports2.LLMLatencyStatsSchema = exports2.DEFAULT_PROJECT_METRICS = exports2.DEFAULT_BASE_METRICS = exports2.SessionContextMetricsSchema = exports2.ProjectContextMetricsSchema = exports2.BaseTokenMetricsStateSchema = exports2.UPSThrottleStateSchema = exports2.VerificationToolsStateSchema = exports2.VerificationToolStatusSchema = exports2.VCUnverifiedStateSchema = exports2.PRBaselineStateSchema = exports2.EMPTY_LOG_METRICS = exports2.LogMetricsStateSchema = exports2.TranscriptMetricsStateSchema = exports2.ResumeMessageStateSchema = exports2.SnarkyMessageStateSchema = exports2.SummaryCountdownStateSchema = exports2.LastStagedPersonaSchema = exports2.SessionPersonaStateSchema = exports2.SESSION_SUMMARY_PLACEHOLDERS = exports2.SessionSummaryStateSchema = void 0;
17217
17217
  exports2.createDefaultLLMMetrics = createDefaultLLMMetrics;
17218
17218
  var zod_1 = require_zod();
17219
17219
  exports2.SessionSummaryStateSchema = zod_1.z.object({
@@ -17377,6 +17377,10 @@ var require_state = __commonJS({
17377
17377
  lastMatchedScope: zod_1.z.enum(["project", "package", "file"]).nullable().optional()
17378
17378
  });
17379
17379
  exports2.VerificationToolsStateSchema = zod_1.z.record(zod_1.z.string(), exports2.VerificationToolStatusSchema);
17380
+ exports2.UPSThrottleStateSchema = zod_1.z.object({
17381
+ /** Number of conversation messages since the reminder was last staged */
17382
+ messagesSinceLastStaging: zod_1.z.number()
17383
+ });
17380
17384
  exports2.BaseTokenMetricsStateSchema = zod_1.z.object({
17381
17385
  /** System prompt tokens (~3.2k) */
17382
17386
  systemPromptTokens: zod_1.z.number(),
@@ -45265,7 +45269,10 @@ var require_structured_logging = __commonJS({
45265
45269
  mkdir: true
45266
45270
  }).then((stream) => {
45267
45271
  this.realStream = stream;
45268
- this.drainPending((chunk, cb) => stream.write(chunk, cb));
45272
+ this.drainPending((chunk, cb) => {
45273
+ stream.write(chunk);
45274
+ cb();
45275
+ });
45269
45276
  }).catch((err) => {
45270
45277
  process.stderr.write(`[sidekick] pino-roll init failed, using appendFileSync fallback: ${err}
45271
45278
  `);
@@ -45274,7 +45281,8 @@ var require_structured_logging = __commonJS({
45274
45281
  }
45275
45282
  _write(chunk, _encoding, callback) {
45276
45283
  if (this.realStream) {
45277
- this.realStream.write(chunk, callback);
45284
+ this.realStream.write(chunk);
45285
+ callback();
45278
45286
  } else if (this.initPending) {
45279
45287
  this.pending.push({ chunk, callback });
45280
45288
  } else {
@@ -71292,7 +71300,8 @@ var require_types2 = __commonJS({
71292
71300
  source_code_patterns: exports2.DEFAULT_SOURCE_CODE_PATTERNS,
71293
71301
  max_verification_cycles: -1,
71294
71302
  // -1 = unlimited, 0 = disabled
71295
- verification_tools: exports2.DEFAULT_VERIFICATION_TOOLS
71303
+ verification_tools: exports2.DEFAULT_VERIFICATION_TOOLS,
71304
+ user_prompt_submit_threshold: 10
71296
71305
  };
71297
71306
  exports2.ReminderIds = {
71298
71307
  USER_PROMPT_SUBMIT: "user-prompt-submit",
@@ -71316,6 +71325,41 @@ var require_types2 = __commonJS({
71316
71325
  }
71317
71326
  });
71318
71327
 
71328
+ // ../feature-reminders/dist/state.js
71329
+ var require_state3 = __commonJS({
71330
+ "../feature-reminders/dist/state.js"(exports2) {
71331
+ "use strict";
71332
+ Object.defineProperty(exports2, "__esModule", { value: true });
71333
+ exports2.createRemindersState = createRemindersState;
71334
+ var core_1 = require_dist4();
71335
+ var types_1 = require_dist();
71336
+ var PRBaselineDescriptor = (0, core_1.sessionState)("pr-baseline.json", types_1.PRBaselineStateSchema, {
71337
+ defaultValue: null,
71338
+ trackHistory: true
71339
+ });
71340
+ var VCUnverifiedDescriptor = (0, core_1.sessionState)("vc-unverified.json", types_1.VCUnverifiedStateSchema, {
71341
+ defaultValue: null,
71342
+ trackHistory: true
71343
+ });
71344
+ var VerificationToolsDescriptor = (0, core_1.sessionState)("verification-tools.json", types_1.VerificationToolsStateSchema, {
71345
+ defaultValue: {},
71346
+ trackHistory: false
71347
+ });
71348
+ var UPSThrottleDescriptor = (0, core_1.sessionState)("ups-throttle.json", types_1.UPSThrottleStateSchema, {
71349
+ defaultValue: { messagesSinceLastStaging: 0 },
71350
+ trackHistory: false
71351
+ });
71352
+ function createRemindersState(stateService) {
71353
+ return {
71354
+ prBaseline: new core_1.SessionStateAccessor(stateService, PRBaselineDescriptor),
71355
+ vcUnverified: new core_1.SessionStateAccessor(stateService, VCUnverifiedDescriptor),
71356
+ verificationTools: new core_1.SessionStateAccessor(stateService, VerificationToolsDescriptor),
71357
+ upsThrottle: new core_1.SessionStateAccessor(stateService, UPSThrottleDescriptor)
71358
+ };
71359
+ }
71360
+ }
71361
+ });
71362
+
71319
71363
  // ../feature-reminders/dist/handlers/staging/stage-default-user-prompt.js
71320
71364
  var require_stage_default_user_prompt = __commonJS({
71321
71365
  "../feature-reminders/dist/handlers/staging/stage-default-user-prompt.js"(exports2) {
@@ -71325,6 +71369,8 @@ var require_stage_default_user_prompt = __commonJS({
71325
71369
  var types_1 = require_dist();
71326
71370
  var staging_handler_utils_js_1 = require_staging_handler_utils();
71327
71371
  var types_js_1 = require_types2();
71372
+ var reminder_utils_js_1 = require_reminder_utils();
71373
+ var state_js_1 = require_state3();
71328
71374
  function registerStageDefaultUserPrompt(context) {
71329
71375
  (0, staging_handler_utils_js_1.createStagingHandler)(context, {
71330
71376
  id: "reminders:stage-default-user-prompt",
@@ -71342,6 +71388,23 @@ var require_stage_default_user_prompt = __commonJS({
71342
71388
  };
71343
71389
  }
71344
71390
  });
71391
+ if ((0, types_1.isDaemonContext)(context)) {
71392
+ const startCtx = context;
71393
+ context.handlers.register({
71394
+ id: "reminders:ups-throttle-reset-session-start",
71395
+ priority: 49,
71396
+ filter: { kind: "hook", hooks: ["SessionStart"] },
71397
+ handler: async (event) => {
71398
+ if (!(0, types_1.isHookEvent)(event) || !(0, types_1.isSessionStartEvent)(event))
71399
+ return;
71400
+ const sessionId = event.context.sessionId;
71401
+ if (!sessionId)
71402
+ return;
71403
+ const remindersState = (0, state_js_1.createRemindersState)(startCtx.stateService);
71404
+ await remindersState.upsThrottle.write(sessionId, { messagesSinceLastStaging: 0 });
71405
+ }
71406
+ });
71407
+ }
71345
71408
  (0, staging_handler_utils_js_1.createStagingHandler)(context, {
71346
71409
  id: "reminders:stage-default-user-prompt-after-bulk",
71347
71410
  priority: 50,
@@ -71358,36 +71421,68 @@ var require_stage_default_user_prompt = __commonJS({
71358
71421
  };
71359
71422
  }
71360
71423
  });
71361
- }
71362
- }
71363
- });
71364
-
71365
- // ../feature-reminders/dist/state.js
71366
- var require_state3 = __commonJS({
71367
- "../feature-reminders/dist/state.js"(exports2) {
71368
- "use strict";
71369
- Object.defineProperty(exports2, "__esModule", { value: true });
71370
- exports2.createRemindersState = createRemindersState;
71371
- var core_1 = require_dist4();
71372
- var types_1 = require_dist();
71373
- var PRBaselineDescriptor = (0, core_1.sessionState)("pr-baseline.json", types_1.PRBaselineStateSchema, {
71374
- defaultValue: null,
71375
- trackHistory: true
71376
- });
71377
- var VCUnverifiedDescriptor = (0, core_1.sessionState)("vc-unverified.json", types_1.VCUnverifiedStateSchema, {
71378
- defaultValue: null,
71379
- trackHistory: true
71380
- });
71381
- var VerificationToolsDescriptor = (0, core_1.sessionState)("verification-tools.json", types_1.VerificationToolsStateSchema, {
71382
- defaultValue: {},
71383
- trackHistory: false
71384
- });
71385
- function createRemindersState(stateService) {
71386
- return {
71387
- prBaseline: new core_1.SessionStateAccessor(stateService, PRBaselineDescriptor),
71388
- vcUnverified: new core_1.SessionStateAccessor(stateService, VCUnverifiedDescriptor),
71389
- verificationTools: new core_1.SessionStateAccessor(stateService, VerificationToolsDescriptor)
71390
- };
71424
+ if ((0, types_1.isDaemonContext)(context)) {
71425
+ const bulkCtx = context;
71426
+ context.handlers.register({
71427
+ id: "reminders:ups-throttle-reset-bulk",
71428
+ priority: 49,
71429
+ filter: { kind: "transcript", eventTypes: ["BulkProcessingComplete"] },
71430
+ handler: async (event) => {
71431
+ if (!(0, types_1.isTranscriptEvent)(event))
71432
+ return;
71433
+ if (event.metadata.isBulkProcessing)
71434
+ return;
71435
+ const sessionId = event.context?.sessionId;
71436
+ if (!sessionId)
71437
+ return;
71438
+ const remindersState = (0, state_js_1.createRemindersState)(bulkCtx.stateService);
71439
+ await remindersState.upsThrottle.write(sessionId, { messagesSinceLastStaging: 0 });
71440
+ }
71441
+ });
71442
+ }
71443
+ if (!(0, types_1.isDaemonContext)(context))
71444
+ return;
71445
+ context.handlers.register({
71446
+ id: "reminders:ups-throttle-restage",
71447
+ priority: 50,
71448
+ filter: { kind: "transcript", eventTypes: ["UserPrompt", "AssistantMessage"] },
71449
+ handler: async (event, ctx) => {
71450
+ if (!(0, types_1.isTranscriptEvent)(event))
71451
+ return;
71452
+ if (!(0, types_1.isDaemonContext)(ctx))
71453
+ return;
71454
+ if (event.metadata.isBulkProcessing)
71455
+ return;
71456
+ const sessionId = event.context?.sessionId;
71457
+ if (!sessionId)
71458
+ return;
71459
+ const handlerCtx = ctx;
71460
+ const remindersState = (0, state_js_1.createRemindersState)(handlerCtx.stateService);
71461
+ const result = await remindersState.upsThrottle.read(sessionId);
71462
+ const current = result.data.messagesSinceLastStaging;
71463
+ const featureConfig = handlerCtx.config.getFeature("reminders");
71464
+ const config = { ...types_js_1.DEFAULT_REMINDERS_SETTINGS, ...featureConfig.settings };
71465
+ const threshold = config.user_prompt_submit_threshold ?? 10;
71466
+ const newCount = current + 1;
71467
+ if (newCount >= threshold) {
71468
+ const reminder = (0, reminder_utils_js_1.resolveReminder)(types_js_1.ReminderIds.USER_PROMPT_SUBMIT, {
71469
+ context: { sessionId },
71470
+ assets: handlerCtx.assets
71471
+ });
71472
+ if (reminder) {
71473
+ await (0, reminder_utils_js_1.stageReminder)(handlerCtx, "UserPromptSubmit", reminder);
71474
+ handlerCtx.logger.debug("UPS throttle: re-staged reminder", {
71475
+ sessionId,
71476
+ messageCount: newCount,
71477
+ threshold
71478
+ });
71479
+ }
71480
+ await remindersState.upsThrottle.write(sessionId, { messagesSinceLastStaging: 0 });
71481
+ } else {
71482
+ await remindersState.upsThrottle.write(sessionId, { messagesSinceLastStaging: newCount });
71483
+ }
71484
+ }
71485
+ });
71391
71486
  }
71392
71487
  }
71393
71488
  });
@@ -72967,121 +73062,6 @@ var require_picomatch2 = __commonJS({
72967
73062
  }
72968
73063
  });
72969
73064
 
72970
- // ../feature-reminders/dist/handlers/staging/stage-stop-bash-changes.js
72971
- var require_stage_stop_bash_changes = __commonJS({
72972
- "../feature-reminders/dist/handlers/staging/stage-stop-bash-changes.js"(exports2) {
72973
- "use strict";
72974
- var __importDefault2 = exports2 && exports2.__importDefault || function(mod) {
72975
- return mod && mod.__esModule ? mod : { "default": mod };
72976
- };
72977
- Object.defineProperty(exports2, "__esModule", { value: true });
72978
- exports2.registerStageBashChanges = registerStageBashChanges;
72979
- var core_1 = require_dist4();
72980
- var types_1 = require_dist();
72981
- var picomatch_1 = __importDefault2(require_picomatch2());
72982
- var staging_handler_utils_js_1 = require_staging_handler_utils();
72983
- var types_js_1 = require_types2();
72984
- var GIT_STATUS_TIMEOUT_MS = 200;
72985
- var MAX_BASELINES = 50;
72986
- function registerStageBashChanges(context) {
72987
- if (!(0, types_1.isDaemonContext)(context))
72988
- return;
72989
- const cwd = context.paths.projectDir;
72990
- if (!cwd)
72991
- return;
72992
- const baselines = /* @__PURE__ */ new Map();
72993
- context.handlers.register({
72994
- id: "reminders:git-baseline-capture",
72995
- priority: 40,
72996
- // Before unstage-verify-completion (45)
72997
- filter: { kind: "hook", hooks: ["UserPromptSubmit"] },
72998
- handler: async (event, ctx) => {
72999
- if (!(0, types_1.isHookEvent)(event))
73000
- return;
73001
- if (!(0, types_1.isDaemonContext)(ctx))
73002
- return;
73003
- const daemonCtx = ctx;
73004
- const sessionId = event.context?.sessionId;
73005
- if (!sessionId)
73006
- return;
73007
- const files = await (0, core_1.getGitFileStatus)(cwd, GIT_STATUS_TIMEOUT_MS);
73008
- if (baselines.size >= MAX_BASELINES) {
73009
- const oldest = baselines.keys().next().value;
73010
- if (oldest)
73011
- baselines.delete(oldest);
73012
- }
73013
- baselines.set(sessionId, files);
73014
- daemonCtx.logger.debug("Git baseline captured", {
73015
- sessionId,
73016
- fileCount: files.length
73017
- });
73018
- }
73019
- });
73020
- (0, staging_handler_utils_js_1.createStagingHandler)(context, {
73021
- id: "reminders:stage-stop-bash-changes",
73022
- priority: 55,
73023
- filter: { kind: "transcript", eventTypes: ["ToolResult"] },
73024
- execute: async (event, ctx) => {
73025
- if (!(0, types_1.isTranscriptEvent)(event))
73026
- return void 0;
73027
- const toolName = event.payload.toolName;
73028
- if (toolName !== "Bash")
73029
- return void 0;
73030
- const sessionId = event.context?.sessionId;
73031
- if (!sessionId)
73032
- return void 0;
73033
- const baseline = baselines.get(sessionId);
73034
- if (!baseline) {
73035
- ctx.logger.debug("Bash VC: no baseline for session, skipping", { sessionId });
73036
- return void 0;
73037
- }
73038
- const metrics = event.metadata.metrics;
73039
- const lastConsumed = await ctx.staging.getLastConsumed("Stop", types_js_1.ReminderIds.VERIFY_COMPLETION);
73040
- if (lastConsumed?.stagedAt) {
73041
- const shouldReactivate = metrics.turnCount > lastConsumed.stagedAt.turnCount;
73042
- if (!shouldReactivate) {
73043
- ctx.logger.debug("Bash VC: skipped (already consumed this turn)", {
73044
- currentTurn: metrics.turnCount,
73045
- lastConsumedTurn: lastConsumed.stagedAt.turnCount
73046
- });
73047
- return void 0;
73048
- }
73049
- }
73050
- const current = await (0, core_1.getGitFileStatus)(cwd, GIT_STATUS_TIMEOUT_MS);
73051
- const baselineSet = new Set(baseline);
73052
- const newFiles = current.filter((f) => !baselineSet.has(f));
73053
- ctx.logger.debug("Bash VC: git status diff", {
73054
- baselineCount: baseline.length,
73055
- currentCount: current.length,
73056
- newFileCount: newFiles.length
73057
- });
73058
- if (newFiles.length === 0)
73059
- return void 0;
73060
- const featureConfig = context.config.getFeature("reminders");
73061
- const config = { ...types_js_1.DEFAULT_REMINDERS_SETTINGS, ...featureConfig.settings };
73062
- const sourceMatches = newFiles.filter((f) => picomatch_1.default.isMatch(f, config.source_code_patterns));
73063
- if (sourceMatches.length === 0) {
73064
- ctx.logger.debug("Bash VC: new files found but no source code matches", {
73065
- newFiles
73066
- });
73067
- return void 0;
73068
- }
73069
- ctx.logger.info("Bash VC: staging verify-completion", {
73070
- sourceMatches,
73071
- turnCount: metrics.turnCount,
73072
- toolCount: metrics.toolCount
73073
- });
73074
- baselines.set(sessionId, current);
73075
- return {
73076
- reminderId: types_js_1.ReminderIds.VERIFY_COMPLETION,
73077
- targetHook: "Stop"
73078
- };
73079
- }
73080
- });
73081
- }
73082
- }
73083
- });
73084
-
73085
73065
  // ../feature-reminders/dist/tool-pattern-matcher.js
73086
73066
  var require_tool_pattern_matcher = __commonJS({
73087
73067
  "../feature-reminders/dist/tool-pattern-matcher.js"(exports2) {
@@ -73133,6 +73113,7 @@ var require_track_verification_tools = __commonJS({
73133
73113
  };
73134
73114
  Object.defineProperty(exports2, "__esModule", { value: true });
73135
73115
  exports2.registerTrackVerificationTools = registerTrackVerificationTools;
73116
+ exports2.stageToolsForFiles = stageToolsForFiles;
73136
73117
  var types_1 = require_dist();
73137
73118
  var picomatch_1 = __importDefault2(require_picomatch2());
73138
73119
  var tool_pattern_matcher_js_1 = require_tool_pattern_matcher();
@@ -73186,53 +73167,49 @@ var require_track_verification_tools = __commonJS({
73186
73167
  }
73187
73168
  });
73188
73169
  }
73189
- async function handleFileEdit(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState) {
73190
- const filePath = extractToolInput(event)?.file_path;
73191
- if (!filePath)
73192
- return;
73193
- const projectDir = daemonCtx.paths?.projectDir;
73194
- if (projectDir && !filePath.startsWith(projectDir))
73195
- return;
73170
+ async function stageToolsForFiles(filePaths, daemonCtx, sessionId, verificationTools, toolsState, remindersState) {
73196
73171
  const existingReminders = await daemonCtx.staging.listReminders("Stop");
73197
73172
  const stagedNames = new Set(existingReminders.map((r) => r.name));
73198
73173
  let anyStaged = false;
73199
- for (const [toolName, toolConfig] of Object.entries(verificationTools)) {
73200
- if (!toolConfig.enabled)
73201
- continue;
73202
- const reminderId = TOOL_REMINDER_MAP[toolName];
73203
- if (!reminderId)
73204
- continue;
73205
- if (!picomatch_1.default.isMatch(filePath, toolConfig.clearing_patterns))
73206
- continue;
73207
- const current = toolsState[toolName];
73208
- if (!current || current.status === "staged") {
73209
- if (!current) {
73210
- toolsState[toolName] = {
73211
- status: "staged",
73212
- editsSinceVerified: 0,
73213
- lastVerifiedAt: null,
73214
- lastStagedAt: Date.now()
73215
- };
73216
- }
73217
- await stageToolReminderIfNeeded(daemonCtx, reminderId, stagedNames);
73218
- anyStaged = true;
73219
- } else {
73220
- const newEdits = current.editsSinceVerified + 1;
73221
- if (newEdits >= toolConfig.clearing_threshold) {
73222
- toolsState[toolName] = {
73223
- ...current,
73224
- status: "staged",
73225
- editsSinceVerified: 0,
73226
- lastStagedAt: Date.now()
73227
- };
73174
+ for (const filePath of filePaths) {
73175
+ for (const [toolName, toolConfig] of Object.entries(verificationTools)) {
73176
+ if (!toolConfig.enabled)
73177
+ continue;
73178
+ const reminderId = TOOL_REMINDER_MAP[toolName];
73179
+ if (!reminderId)
73180
+ continue;
73181
+ if (!picomatch_1.default.isMatch(filePath, toolConfig.clearing_patterns))
73182
+ continue;
73183
+ const current = toolsState[toolName];
73184
+ if (!current || current.status === "staged") {
73185
+ if (!current) {
73186
+ toolsState[toolName] = {
73187
+ status: "staged",
73188
+ editsSinceVerified: 0,
73189
+ lastVerifiedAt: null,
73190
+ lastStagedAt: Date.now()
73191
+ };
73192
+ }
73228
73193
  await stageToolReminderIfNeeded(daemonCtx, reminderId, stagedNames);
73229
73194
  anyStaged = true;
73230
73195
  } else {
73231
- toolsState[toolName] = {
73232
- ...current,
73233
- status: "cooldown",
73234
- editsSinceVerified: newEdits
73235
- };
73196
+ const newEdits = current.editsSinceVerified + 1;
73197
+ if (newEdits >= toolConfig.clearing_threshold) {
73198
+ toolsState[toolName] = {
73199
+ ...current,
73200
+ status: "staged",
73201
+ editsSinceVerified: 0,
73202
+ lastStagedAt: Date.now()
73203
+ };
73204
+ await stageToolReminderIfNeeded(daemonCtx, reminderId, stagedNames);
73205
+ anyStaged = true;
73206
+ } else {
73207
+ toolsState[toolName] = {
73208
+ ...current,
73209
+ status: "cooldown",
73210
+ editsSinceVerified: newEdits
73211
+ };
73212
+ }
73236
73213
  }
73237
73214
  }
73238
73215
  }
@@ -73240,6 +73217,16 @@ var require_track_verification_tools = __commonJS({
73240
73217
  await stageToolReminderIfNeeded(daemonCtx, types_js_1.ReminderIds.VERIFY_COMPLETION, stagedNames);
73241
73218
  }
73242
73219
  await remindersState.verificationTools.write(sessionId, toolsState);
73220
+ return anyStaged;
73221
+ }
73222
+ async function handleFileEdit(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState) {
73223
+ const filePath = extractToolInput(event)?.file_path;
73224
+ if (!filePath)
73225
+ return;
73226
+ const projectDir = daemonCtx.paths?.projectDir;
73227
+ if (projectDir && !filePath.startsWith(projectDir))
73228
+ return;
73229
+ await stageToolsForFiles([filePath], daemonCtx, sessionId, verificationTools, toolsState, remindersState);
73243
73230
  }
73244
73231
  async function handleBashCommand(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState) {
73245
73232
  const command = extractToolInput(event)?.command;
@@ -73302,6 +73289,126 @@ var require_track_verification_tools = __commonJS({
73302
73289
  }
73303
73290
  });
73304
73291
 
73292
+ // ../feature-reminders/dist/handlers/staging/stage-stop-bash-changes.js
73293
+ var require_stage_stop_bash_changes = __commonJS({
73294
+ "../feature-reminders/dist/handlers/staging/stage-stop-bash-changes.js"(exports2) {
73295
+ "use strict";
73296
+ var __importDefault2 = exports2 && exports2.__importDefault || function(mod) {
73297
+ return mod && mod.__esModule ? mod : { "default": mod };
73298
+ };
73299
+ Object.defineProperty(exports2, "__esModule", { value: true });
73300
+ exports2.registerStageBashChanges = registerStageBashChanges;
73301
+ var core_1 = require_dist4();
73302
+ var types_1 = require_dist();
73303
+ var picomatch_1 = __importDefault2(require_picomatch2());
73304
+ var track_verification_tools_js_1 = require_track_verification_tools();
73305
+ var types_js_1 = require_types2();
73306
+ var state_js_1 = require_state3();
73307
+ var GIT_STATUS_TIMEOUT_MS = 200;
73308
+ var MAX_BASELINES = 50;
73309
+ function registerStageBashChanges(context) {
73310
+ if (!(0, types_1.isDaemonContext)(context))
73311
+ return;
73312
+ const cwd = context.paths.projectDir;
73313
+ if (!cwd)
73314
+ return;
73315
+ const baselines = /* @__PURE__ */ new Map();
73316
+ context.handlers.register({
73317
+ id: "reminders:git-baseline-capture",
73318
+ priority: 40,
73319
+ // Before unstage-verify-completion (45)
73320
+ filter: { kind: "hook", hooks: ["UserPromptSubmit"] },
73321
+ handler: async (event, ctx) => {
73322
+ if (!(0, types_1.isHookEvent)(event))
73323
+ return;
73324
+ if (!(0, types_1.isDaemonContext)(ctx))
73325
+ return;
73326
+ const daemonCtx = ctx;
73327
+ const sessionId = event.context?.sessionId;
73328
+ if (!sessionId)
73329
+ return;
73330
+ const files = await (0, core_1.getGitFileStatus)(cwd, GIT_STATUS_TIMEOUT_MS);
73331
+ if (baselines.size >= MAX_BASELINES) {
73332
+ const oldest = baselines.keys().next().value;
73333
+ if (oldest)
73334
+ baselines.delete(oldest);
73335
+ }
73336
+ baselines.set(sessionId, files);
73337
+ daemonCtx.logger.debug("Git baseline captured", {
73338
+ sessionId,
73339
+ fileCount: files.length
73340
+ });
73341
+ }
73342
+ });
73343
+ context.handlers.register({
73344
+ id: "reminders:stage-stop-bash-changes",
73345
+ priority: 55,
73346
+ filter: { kind: "transcript", eventTypes: ["ToolResult"] },
73347
+ handler: async (event, ctx) => {
73348
+ if (!(0, types_1.isTranscriptEvent)(event))
73349
+ return;
73350
+ if (event.metadata.isBulkProcessing)
73351
+ return;
73352
+ if (!(0, types_1.isDaemonContext)(ctx))
73353
+ return;
73354
+ const daemonCtx = ctx;
73355
+ const toolName = event.payload.toolName;
73356
+ if (toolName !== "Bash")
73357
+ return;
73358
+ const sessionId = event.context?.sessionId;
73359
+ if (!sessionId)
73360
+ return;
73361
+ const baseline = baselines.get(sessionId);
73362
+ if (!baseline) {
73363
+ daemonCtx.logger.debug("Bash VC: no baseline for session, skipping", { sessionId });
73364
+ return;
73365
+ }
73366
+ const metrics = event.metadata.metrics;
73367
+ const lastConsumed = await daemonCtx.staging.getLastConsumed("Stop", types_js_1.ReminderIds.VERIFY_COMPLETION);
73368
+ if (lastConsumed?.stagedAt) {
73369
+ const shouldReactivate = metrics.turnCount > lastConsumed.stagedAt.turnCount;
73370
+ if (!shouldReactivate) {
73371
+ daemonCtx.logger.debug("Bash VC: skipped (already consumed this turn)", {
73372
+ currentTurn: metrics.turnCount,
73373
+ lastConsumedTurn: lastConsumed.stagedAt.turnCount
73374
+ });
73375
+ return;
73376
+ }
73377
+ }
73378
+ const current = await (0, core_1.getGitFileStatus)(cwd, GIT_STATUS_TIMEOUT_MS);
73379
+ const baselineSet = new Set(baseline);
73380
+ const newFiles = current.filter((f) => !baselineSet.has(f));
73381
+ daemonCtx.logger.debug("Bash VC: git status diff", {
73382
+ baselineCount: baseline.length,
73383
+ currentCount: current.length,
73384
+ newFileCount: newFiles.length
73385
+ });
73386
+ if (newFiles.length === 0)
73387
+ return;
73388
+ const featureConfig = context.config.getFeature("reminders");
73389
+ const config = { ...types_js_1.DEFAULT_REMINDERS_SETTINGS, ...featureConfig.settings };
73390
+ const sourceMatches = newFiles.filter((f) => picomatch_1.default.isMatch(f, config.source_code_patterns));
73391
+ if (sourceMatches.length === 0) {
73392
+ daemonCtx.logger.debug("Bash VC: new files found but no source code matches", { newFiles });
73393
+ return;
73394
+ }
73395
+ daemonCtx.logger.info("Bash VC: staging per-tool reminders for source changes", {
73396
+ sourceMatches,
73397
+ turnCount: metrics.turnCount,
73398
+ toolCount: metrics.toolCount
73399
+ });
73400
+ baselines.set(sessionId, current);
73401
+ const verificationTools = config.verification_tools ?? {};
73402
+ const remindersState = (0, state_js_1.createRemindersState)(daemonCtx.stateService);
73403
+ const stateResult = await remindersState.verificationTools.read(sessionId);
73404
+ const toolsState = { ...stateResult.data };
73405
+ await (0, track_verification_tools_js_1.stageToolsForFiles)(sourceMatches, daemonCtx, sessionId, verificationTools, toolsState, remindersState);
73406
+ }
73407
+ });
73408
+ }
73409
+ }
73410
+ });
73411
+
73305
73412
  // ../feature-reminders/dist/handlers/staging/unstage-verify-completion.js
73306
73413
  var require_unstage_verify_completion = __commonJS({
73307
73414
  "../feature-reminders/dist/handlers/staging/unstage-verify-completion.js"(exports2) {
@@ -73349,28 +73456,52 @@ var require_unstage_verify_completion = __commonJS({
73349
73456
  setAtToolCount: unverifiedState.setAt.toolCount
73350
73457
  });
73351
73458
  if (maxCycles < 0 || unverifiedState.cycleCount < maxCycles) {
73352
- const reminder = (0, reminder_utils_js_1.resolveReminder)(types_js_1.ReminderIds.VERIFY_COMPLETION, {
73353
- context: {},
73354
- assets: daemonCtx.assets
73459
+ const verificationToolsResult = await remindersState.verificationTools.read(sessionId);
73460
+ const toolsState = verificationToolsResult.data;
73461
+ const verificationTools = config.verification_tools ?? {};
73462
+ const hasToolsNeedingVerification = Object.entries(verificationTools).some(([toolName, toolConfig]) => {
73463
+ if (!toolConfig.enabled)
73464
+ return false;
73465
+ const state = toolsState[toolName];
73466
+ if (!state)
73467
+ return true;
73468
+ if (state.status === "staged")
73469
+ return true;
73470
+ if (state.status === "verified" || state.status === "cooldown") {
73471
+ return state.editsSinceVerified >= toolConfig.clearing_threshold;
73472
+ }
73473
+ return false;
73355
73474
  });
73356
- if (reminder) {
73357
- await (0, reminder_utils_js_1.stageReminder)(daemonCtx, "Stop", {
73358
- ...reminder,
73359
- stagedAt: {
73360
- timestamp: Date.now(),
73361
- turnCount: unverifiedState.setAt.turnCount,
73362
- toolsThisTurn: unverifiedState.setAt.toolsThisTurn,
73363
- toolCount: unverifiedState.setAt.toolCount
73364
- }
73365
- });
73366
- daemonCtx.logger.info("VC unstage: re-staged for next Stop", {
73475
+ if (!hasToolsNeedingVerification) {
73476
+ daemonCtx.logger.info("VC unstage: all tools verified, skipping wrapper re-stage", {
73367
73477
  sessionId,
73368
- cycleCount: unverifiedState.cycleCount,
73369
- lastCategory: unverifiedState.lastClassification.category
73478
+ cycleCount: unverifiedState.cycleCount
73370
73479
  });
73371
- return;
73480
+ await remindersState.vcUnverified.delete(sessionId);
73372
73481
  } else {
73373
- daemonCtx.logger.warn("VC unstage: failed to resolve reminder for re-staging");
73482
+ const reminder = (0, reminder_utils_js_1.resolveReminder)(types_js_1.ReminderIds.VERIFY_COMPLETION, {
73483
+ context: {},
73484
+ assets: daemonCtx.assets
73485
+ });
73486
+ if (reminder) {
73487
+ await (0, reminder_utils_js_1.stageReminder)(daemonCtx, "Stop", {
73488
+ ...reminder,
73489
+ stagedAt: {
73490
+ timestamp: Date.now(),
73491
+ turnCount: unverifiedState.setAt.turnCount,
73492
+ toolsThisTurn: unverifiedState.setAt.toolsThisTurn,
73493
+ toolCount: unverifiedState.setAt.toolCount
73494
+ }
73495
+ });
73496
+ daemonCtx.logger.info("VC unstage: re-staged for next Stop", {
73497
+ sessionId,
73498
+ cycleCount: unverifiedState.cycleCount,
73499
+ lastCategory: unverifiedState.lastClassification.category
73500
+ });
73501
+ return;
73502
+ } else {
73503
+ daemonCtx.logger.warn("VC unstage: failed to resolve reminder for re-staging");
73504
+ }
73374
73505
  }
73375
73506
  } else {
73376
73507
  daemonCtx.logger.info("VC unstage: cycle limit reached, clearing", {
@@ -74739,6 +74870,7 @@ ${daemonResponse.additionalContext}` : cliResponse.additionalContext;
74739
74870
  hook: hookName
74740
74871
  };
74741
74872
  (0, core_1.logEvent)(logger, core_1.LogEvents.hookReceived(logContext, { cwd: hookInput.cwd, mode: "hook" }));
74873
+ logger.debug("Hook invocation received", { hook: hookName, sessionId: hookInput.sessionId });
74742
74874
  const event = buildHookEvent(hookName, hookInput, correlationId);
74743
74875
  logger.debug("Dispatching hook event to daemon", {
74744
74876
  hook: hookName,
@@ -75544,7 +75676,8 @@ var require_types4 = __commonJS({
75544
75676
  injectPersonaIntoClaude: true,
75545
75677
  defaultLlmProfile: "",
75546
75678
  llmProfiles: {},
75547
- weights: {}
75679
+ weights: {},
75680
+ persistThroughClear: true
75548
75681
  }
75549
75682
  };
75550
75683
  exports2.RESUME_MIN_CONFIDENCE = 0.7;
@@ -75619,7 +75752,7 @@ var require_persona_selection = __commonJS({
75619
75752
  }
75620
75753
  return weighted[weighted.length - 1].persona;
75621
75754
  }
75622
- async function selectPersonaForSession(sessionId, config, ctx) {
75755
+ async function selectPersonaForSession(sessionId, config, ctx, options) {
75623
75756
  const personaConfig = {
75624
75757
  ...types_js_1.DEFAULT_SESSION_SUMMARY_CONFIG.personas,
75625
75758
  ...config.personas
@@ -75658,6 +75791,38 @@ var require_persona_selection = __commonJS({
75658
75791
  availablePersonas: Array.from(allPersonas.keys())
75659
75792
  });
75660
75793
  }
75794
+ const persistThroughClear = personaConfig.persistThroughClear ?? true;
75795
+ ctx.logger.debug("Persona clear handoff check", {
75796
+ persistThroughClear,
75797
+ startType: options?.startType,
75798
+ hasClearCache: !!ctx.personaClearCache
75799
+ });
75800
+ if (persistThroughClear && options?.startType === "clear" && ctx.personaClearCache) {
75801
+ const cachedPersonaId = ctx.personaClearCache.consume();
75802
+ if (cachedPersonaId) {
75803
+ const cachedPersona = allPersonas.get(cachedPersonaId);
75804
+ if (cachedPersona) {
75805
+ const personaState2 = {
75806
+ persona_id: cachedPersona.id,
75807
+ selected_from: [cachedPersona.id],
75808
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
75809
+ };
75810
+ const summaryState2 = (0, state_js_1.createSessionSummaryState)(ctx.stateService);
75811
+ await summaryState2.sessionPersona.write(sessionId, personaState2);
75812
+ ctx.logger.info("Preserved persona through clear", {
75813
+ sessionId,
75814
+ personaId: cachedPersona.id,
75815
+ personaName: cachedPersona.display_name
75816
+ });
75817
+ return cachedPersona.id;
75818
+ } else {
75819
+ ctx.logger.warn("Cached persona from clear not found in available personas, falling back to selection", {
75820
+ sessionId,
75821
+ cachedPersonaId
75822
+ });
75823
+ }
75824
+ }
75825
+ }
75661
75826
  const allowList = parsePersonaList(personaConfig.allowList ?? "");
75662
75827
  const blockList = parsePersonaList(personaConfig.blockList ?? "");
75663
75828
  const eligiblePersonas = filterPersonas(allPersonas, allowList, blockList, ctx.logger);
@@ -75744,7 +75909,7 @@ var require_create_first_summary = __commonJS({
75744
75909
  const summaryState = (0, state_js_1.createSessionSummaryState)(ctx.stateService);
75745
75910
  await summaryState.sessionSummary.write(sessionId, placeholder);
75746
75911
  ctx.logger.info("Created placeholder session summary", { sessionId });
75747
- await (0, persona_selection_js_1.selectPersonaForSession)(sessionId, config, ctx);
75912
+ await (0, persona_selection_js_1.selectPersonaForSession)(sessionId, config, ctx, { startType });
75748
75913
  }
75749
75914
  }
75750
75915
  });
@@ -76604,10 +76769,10 @@ var require_handlers = __commonJS({
76604
76769
  id: "session-summary:init",
76605
76770
  priority: 80,
76606
76771
  filter: { kind: "hook", hooks: ["SessionStart"] },
76607
- handler: async (event) => {
76772
+ handler: async (event, context2) => {
76608
76773
  if (!(0, core_1.isHookEvent)(event) || !(0, core_1.isSessionStartEvent)(event))
76609
76774
  return;
76610
- await (0, create_first_summary_js_1.createFirstSessionSummary)(event, ctx);
76775
+ await (0, create_first_summary_js_1.createFirstSessionSummary)(event, context2);
76611
76776
  }
76612
76777
  });
76613
76778
  ctx.handlers.register({
@@ -82516,7 +82681,7 @@ var require_cli = __commonJS({
82516
82681
  var promises_12 = require("node:fs/promises");
82517
82682
  var node_stream_1 = require("node:stream");
82518
82683
  var yargs_parser_1 = __importDefault2(require_build());
82519
- var VERSION = true ? "0.1.4" : "dev";
82684
+ var VERSION = true ? "0.1.5" : "dev";
82520
82685
  var SANDBOX_ERROR_MESSAGE = `Error: Daemon commands cannot run in sandbox mode.
82521
82686
 
82522
82687
  Claude Code's sandbox blocks Unix socket operations required for daemon IPC.