@scotthamilton77/sidekick 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/bin.js +59 -39
  2. package/dist/daemon.js +58 -38
  3. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -58164,24 +58164,20 @@ var require_staging_paths = __commonJS({
58164
58164
  function getReminderPath(stateDir, sessionId, hookName, reminderName) {
58165
58165
  return (0, node_path_1.join)(getHookDir(stateDir, sessionId, hookName), `${reminderName}.json`);
58166
58166
  }
58167
- function isValidPathSegment(segment) {
58168
- if (!segment)
58167
+ function isValidPathSegment(s) {
58168
+ if (s === "")
58169
58169
  return false;
58170
- if (segment.includes("..") || segment.includes("/") || segment.includes("\\"))
58170
+ if (s === "." || s === "..")
58171
58171
  return false;
58172
- if (segment.startsWith("."))
58172
+ if (s.includes("/") || s.includes("\\"))
58173
58173
  return false;
58174
- return true;
58174
+ if ((0, node_path_1.basename)(s) !== s)
58175
+ return false;
58176
+ return /^[a-zA-Z0-9._-]+$/.test(s);
58175
58177
  }
58176
58178
  function validatePathSegment(segment, name) {
58177
- if (!segment) {
58178
- throw new Error(`${name} cannot be empty`);
58179
- }
58180
- if (segment.includes("..") || segment.includes("/") || segment.includes("\\")) {
58181
- throw new Error(`Invalid ${name}: path traversal characters not allowed`);
58182
- }
58183
- if (segment.startsWith(".")) {
58184
- throw new Error(`Invalid ${name}: cannot start with '.'`);
58179
+ if (!isValidPathSegment(segment)) {
58180
+ throw new Error(`Invalid ${name}: must be a non-empty alphanumeric string without path separators`);
58185
58181
  }
58186
58182
  }
58187
58183
  exports2.CONSUMED_FILE_PATTERN = /\.\d+\.json$/;
@@ -58287,7 +58283,7 @@ var require_staging_service = __commonJS({
58287
58283
  persistent: data.persistent,
58288
58284
  ...enrichment
58289
58285
  }, { stagingPath: reminderPath });
58290
- (0, structured_logging_1.logEvent)(this.options.logger, event);
58286
+ (0, structured_logging_1.logEvent)(this.options.logger.child({ context: { sessionId } }), event);
58291
58287
  }
58292
58288
  /**
58293
58289
  * Read a staged reminder.
@@ -71465,7 +71461,7 @@ var require_types2 = __commonJS({
71465
71461
  "../feature-reminders/dist/types.js"(exports2) {
71466
71462
  "use strict";
71467
71463
  Object.defineProperty(exports2, "__esModule", { value: true });
71468
- exports2.ALL_VC_REMINDER_IDS = exports2.VC_TOOL_REMINDER_IDS = 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;
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;
71469
71465
  var zod_1 = require_zod2();
71470
71466
  exports2.ToolPatternScopeSchema = zod_1.z.enum(["project", "package", "file"]);
71471
71467
  exports2.ToolPatternSchema = zod_1.z.object({
@@ -71682,6 +71678,12 @@ var require_types2 = __commonJS({
71682
71678
  PERSONA_CHANGED: "persona-changed",
71683
71679
  USER_PROFILE: "user-profile"
71684
71680
  };
71681
+ exports2.TOOL_REMINDER_MAP = {
71682
+ build: exports2.ReminderIds.VC_BUILD,
71683
+ typecheck: exports2.ReminderIds.VC_TYPECHECK,
71684
+ test: exports2.ReminderIds.VC_TEST,
71685
+ lint: exports2.ReminderIds.VC_LINT
71686
+ };
71685
71687
  exports2.VC_TOOL_REMINDER_IDS = [
71686
71688
  exports2.ReminderIds.VC_BUILD,
71687
71689
  exports2.ReminderIds.VC_TYPECHECK,
@@ -73691,12 +73693,6 @@ var require_track_verification_tools = __commonJS({
73691
73693
  var types_js_1 = require_types2();
73692
73694
  var state_js_1 = require_state4();
73693
73695
  var FILE_EDIT_TOOLS = ["Write", "Edit", "MultiEdit"];
73694
- var TOOL_REMINDER_MAP = {
73695
- build: types_js_1.ReminderIds.VC_BUILD,
73696
- typecheck: types_js_1.ReminderIds.VC_TYPECHECK,
73697
- test: types_js_1.ReminderIds.VC_TEST,
73698
- lint: types_js_1.ReminderIds.VC_LINT
73699
- };
73700
73696
  var VC_TOOL_NAME_SET = new Set(types_js_1.VC_TOOL_REMINDER_IDS);
73701
73697
  function extractToolInput(event) {
73702
73698
  const entry = event.payload.entry;
@@ -73744,7 +73740,7 @@ var require_track_verification_tools = __commonJS({
73744
73740
  const emittedNotStaged = /* @__PURE__ */ new Set();
73745
73741
  for (const filePath of filePaths) {
73746
73742
  for (const [toolName, toolConfig] of Object.entries(verificationTools)) {
73747
- const reminderId = TOOL_REMINDER_MAP[toolName];
73743
+ const reminderId = types_js_1.TOOL_REMINDER_MAP[toolName];
73748
73744
  if (!reminderId)
73749
73745
  continue;
73750
73746
  if (!toolConfig.enabled) {
@@ -73853,7 +73849,7 @@ var require_track_verification_tools = __commonJS({
73853
73849
  for (const [toolName, toolConfig] of Object.entries(verificationTools)) {
73854
73850
  if (!toolConfig.enabled)
73855
73851
  continue;
73856
- const reminderId = TOOL_REMINDER_MAP[toolName];
73852
+ const reminderId = types_js_1.TOOL_REMINDER_MAP[toolName];
73857
73853
  if (!reminderId)
73858
73854
  continue;
73859
73855
  const match = (0, tool_pattern_matcher_js_1.findMatchingPattern)(command, toolConfig.patterns);
@@ -74075,6 +74071,18 @@ var require_unstage_verify_completion = __commonJS({
74075
74071
  var types_js_1 = require_types2();
74076
74072
  var reminder_utils_js_1 = require_reminder_utils();
74077
74073
  var state_js_1 = require_state4();
74074
+ function toolNeedsVerification(toolConfig, state) {
74075
+ if (!toolConfig.enabled)
74076
+ return false;
74077
+ if (!state)
74078
+ return true;
74079
+ if (state.status === "staged")
74080
+ return true;
74081
+ if (state.status === "verified" || state.status === "cooldown") {
74082
+ return state.editsSinceVerified >= toolConfig.clearing_threshold;
74083
+ }
74084
+ return false;
74085
+ }
74078
74086
  function registerUnstageVerifyCompletion(context) {
74079
74087
  if (!(0, types_1.isDaemonContext)(context))
74080
74088
  return;
@@ -74092,8 +74100,10 @@ var require_unstage_verify_completion = __commonJS({
74092
74100
  const sessionId = event.context?.sessionId;
74093
74101
  if (!sessionId) {
74094
74102
  daemonCtx.logger.warn("No sessionId in UserPromptSubmit event");
74095
- await daemonCtx.staging.deleteReminder("Stop", types_js_1.ReminderIds.VERIFY_COMPLETION);
74096
- (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId: "" }, { reminderName: types_js_1.ReminderIds.VERIFY_COMPLETION, hookName: "Stop", reason: "no_session_id" }));
74103
+ 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" }));
74106
+ }
74097
74107
  return;
74098
74108
  }
74099
74109
  const remindersState = (0, state_js_1.createRemindersState)(daemonCtx.stateService);
@@ -74116,19 +74126,7 @@ var require_unstage_verify_completion = __commonJS({
74116
74126
  const verificationToolsResult = await remindersState.verificationTools.read(sessionId);
74117
74127
  const toolsState = verificationToolsResult.data;
74118
74128
  const verificationTools = config.verification_tools ?? {};
74119
- const hasToolsNeedingVerification = Object.entries(verificationTools).some(([toolName, toolConfig]) => {
74120
- if (!toolConfig.enabled)
74121
- return false;
74122
- const state = toolsState[toolName];
74123
- if (!state)
74124
- return true;
74125
- if (state.status === "staged")
74126
- return true;
74127
- if (state.status === "verified" || state.status === "cooldown") {
74128
- return state.editsSinceVerified >= toolConfig.clearing_threshold;
74129
- }
74130
- return false;
74131
- });
74129
+ const hasToolsNeedingVerification = Object.entries(verificationTools).some(([toolName, toolConfig]) => toolNeedsVerification(toolConfig, toolsState[toolName]));
74132
74130
  if (!hasToolsNeedingVerification) {
74133
74131
  daemonCtx.logger.info("VC unstage: all tools verified, skipping wrapper re-stage", {
74134
74132
  sessionId,
@@ -74136,6 +74134,28 @@ var require_unstage_verify_completion = __commonJS({
74136
74134
  });
74137
74135
  await remindersState.vcUnverified.delete(sessionId);
74138
74136
  } else {
74137
+ for (const [toolName, toolConfig] of Object.entries(verificationTools)) {
74138
+ if (!toolNeedsVerification(toolConfig, toolsState[toolName]))
74139
+ continue;
74140
+ const reminderId = types_js_1.TOOL_REMINDER_MAP[toolName];
74141
+ if (!reminderId)
74142
+ continue;
74143
+ const toolReminder = (0, reminder_utils_js_1.resolveReminder)(reminderId, {
74144
+ context: {},
74145
+ assets: daemonCtx.assets
74146
+ });
74147
+ if (toolReminder) {
74148
+ await (0, reminder_utils_js_1.stageReminder)(daemonCtx, "Stop", {
74149
+ ...toolReminder,
74150
+ stagedAt: {
74151
+ timestamp: Date.now(),
74152
+ turnCount: unverifiedState.setAt.turnCount,
74153
+ toolsThisTurn: unverifiedState.setAt.toolsThisTurn,
74154
+ toolCount: unverifiedState.setAt.toolCount
74155
+ }
74156
+ });
74157
+ }
74158
+ }
74139
74159
  const reminder = (0, reminder_utils_js_1.resolveReminder)(types_js_1.ReminderIds.VERIFY_COMPLETION, {
74140
74160
  context: {},
74141
74161
  assets: daemonCtx.assets
@@ -83739,7 +83759,7 @@ var require_cli = __commonJS({
83739
83759
  var promises_12 = require("node:fs/promises");
83740
83760
  var node_stream_1 = require("node:stream");
83741
83761
  var yargs_parser_1 = __importDefault2(require_build());
83742
- var VERSION = true ? "0.1.10" : "dev";
83762
+ var VERSION = true ? "0.1.12" : "dev";
83743
83763
  var SANDBOX_ERROR_MESSAGE = `Error: Daemon commands cannot run in sandbox mode.
83744
83764
 
83745
83765
  Claude Code's sandbox blocks Unix socket operations required for daemon IPC.
package/dist/daemon.js CHANGED
@@ -57188,24 +57188,20 @@ var require_staging_paths = __commonJS({
57188
57188
  function getReminderPath(stateDir, sessionId, hookName, reminderName) {
57189
57189
  return (0, node_path_1.join)(getHookDir(stateDir, sessionId, hookName), `${reminderName}.json`);
57190
57190
  }
57191
- function isValidPathSegment(segment) {
57192
- if (!segment)
57191
+ function isValidPathSegment(s) {
57192
+ if (s === "")
57193
57193
  return false;
57194
- if (segment.includes("..") || segment.includes("/") || segment.includes("\\"))
57194
+ if (s === "." || s === "..")
57195
57195
  return false;
57196
- if (segment.startsWith("."))
57196
+ if (s.includes("/") || s.includes("\\"))
57197
57197
  return false;
57198
- return true;
57198
+ if ((0, node_path_1.basename)(s) !== s)
57199
+ return false;
57200
+ return /^[a-zA-Z0-9._-]+$/.test(s);
57199
57201
  }
57200
57202
  function validatePathSegment(segment, name) {
57201
- if (!segment) {
57202
- throw new Error(`${name} cannot be empty`);
57203
- }
57204
- if (segment.includes("..") || segment.includes("/") || segment.includes("\\")) {
57205
- throw new Error(`Invalid ${name}: path traversal characters not allowed`);
57206
- }
57207
- if (segment.startsWith(".")) {
57208
- throw new Error(`Invalid ${name}: cannot start with '.'`);
57203
+ if (!isValidPathSegment(segment)) {
57204
+ throw new Error(`Invalid ${name}: must be a non-empty alphanumeric string without path separators`);
57209
57205
  }
57210
57206
  }
57211
57207
  exports2.CONSUMED_FILE_PATTERN = /\.\d+\.json$/;
@@ -57311,7 +57307,7 @@ var require_staging_service = __commonJS({
57311
57307
  persistent: data.persistent,
57312
57308
  ...enrichment
57313
57309
  }, { stagingPath: reminderPath });
57314
- (0, structured_logging_1.logEvent)(this.options.logger, event);
57310
+ (0, structured_logging_1.logEvent)(this.options.logger.child({ context: { sessionId } }), event);
57315
57311
  }
57316
57312
  /**
57317
57313
  * Read a staged reminder.
@@ -70312,7 +70308,7 @@ var require_types2 = __commonJS({
70312
70308
  "../feature-reminders/dist/types.js"(exports2) {
70313
70309
  "use strict";
70314
70310
  Object.defineProperty(exports2, "__esModule", { value: true });
70315
- exports2.ALL_VC_REMINDER_IDS = exports2.VC_TOOL_REMINDER_IDS = 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;
70311
+ 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;
70316
70312
  var zod_1 = require_zod2();
70317
70313
  exports2.ToolPatternScopeSchema = zod_1.z.enum(["project", "package", "file"]);
70318
70314
  exports2.ToolPatternSchema = zod_1.z.object({
@@ -70529,6 +70525,12 @@ var require_types2 = __commonJS({
70529
70525
  PERSONA_CHANGED: "persona-changed",
70530
70526
  USER_PROFILE: "user-profile"
70531
70527
  };
70528
+ exports2.TOOL_REMINDER_MAP = {
70529
+ build: exports2.ReminderIds.VC_BUILD,
70530
+ typecheck: exports2.ReminderIds.VC_TYPECHECK,
70531
+ test: exports2.ReminderIds.VC_TEST,
70532
+ lint: exports2.ReminderIds.VC_LINT
70533
+ };
70532
70534
  exports2.VC_TOOL_REMINDER_IDS = [
70533
70535
  exports2.ReminderIds.VC_BUILD,
70534
70536
  exports2.ReminderIds.VC_TYPECHECK,
@@ -72538,12 +72540,6 @@ var require_track_verification_tools = __commonJS({
72538
72540
  var types_js_1 = require_types2();
72539
72541
  var state_js_1 = require_state4();
72540
72542
  var FILE_EDIT_TOOLS = ["Write", "Edit", "MultiEdit"];
72541
- var TOOL_REMINDER_MAP = {
72542
- build: types_js_1.ReminderIds.VC_BUILD,
72543
- typecheck: types_js_1.ReminderIds.VC_TYPECHECK,
72544
- test: types_js_1.ReminderIds.VC_TEST,
72545
- lint: types_js_1.ReminderIds.VC_LINT
72546
- };
72547
72543
  var VC_TOOL_NAME_SET = new Set(types_js_1.VC_TOOL_REMINDER_IDS);
72548
72544
  function extractToolInput(event) {
72549
72545
  const entry = event.payload.entry;
@@ -72591,7 +72587,7 @@ var require_track_verification_tools = __commonJS({
72591
72587
  const emittedNotStaged = /* @__PURE__ */ new Set();
72592
72588
  for (const filePath of filePaths) {
72593
72589
  for (const [toolName, toolConfig] of Object.entries(verificationTools)) {
72594
- const reminderId = TOOL_REMINDER_MAP[toolName];
72590
+ const reminderId = types_js_1.TOOL_REMINDER_MAP[toolName];
72595
72591
  if (!reminderId)
72596
72592
  continue;
72597
72593
  if (!toolConfig.enabled) {
@@ -72700,7 +72696,7 @@ var require_track_verification_tools = __commonJS({
72700
72696
  for (const [toolName, toolConfig] of Object.entries(verificationTools)) {
72701
72697
  if (!toolConfig.enabled)
72702
72698
  continue;
72703
- const reminderId = TOOL_REMINDER_MAP[toolName];
72699
+ const reminderId = types_js_1.TOOL_REMINDER_MAP[toolName];
72704
72700
  if (!reminderId)
72705
72701
  continue;
72706
72702
  const match = (0, tool_pattern_matcher_js_1.findMatchingPattern)(command, toolConfig.patterns);
@@ -72922,6 +72918,18 @@ var require_unstage_verify_completion = __commonJS({
72922
72918
  var types_js_1 = require_types2();
72923
72919
  var reminder_utils_js_1 = require_reminder_utils();
72924
72920
  var state_js_1 = require_state4();
72921
+ function toolNeedsVerification(toolConfig, state) {
72922
+ if (!toolConfig.enabled)
72923
+ return false;
72924
+ if (!state)
72925
+ return true;
72926
+ if (state.status === "staged")
72927
+ return true;
72928
+ if (state.status === "verified" || state.status === "cooldown") {
72929
+ return state.editsSinceVerified >= toolConfig.clearing_threshold;
72930
+ }
72931
+ return false;
72932
+ }
72925
72933
  function registerUnstageVerifyCompletion(context) {
72926
72934
  if (!(0, types_1.isDaemonContext)(context))
72927
72935
  return;
@@ -72939,8 +72947,10 @@ var require_unstage_verify_completion = __commonJS({
72939
72947
  const sessionId = event.context?.sessionId;
72940
72948
  if (!sessionId) {
72941
72949
  daemonCtx.logger.warn("No sessionId in UserPromptSubmit event");
72942
- await daemonCtx.staging.deleteReminder("Stop", types_js_1.ReminderIds.VERIFY_COMPLETION);
72943
- (0, core_1.logEvent)(daemonCtx.logger, events_js_1.ReminderEvents.reminderUnstaged({ sessionId: "" }, { reminderName: types_js_1.ReminderIds.VERIFY_COMPLETION, hookName: "Stop", reason: "no_session_id" }));
72950
+ 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" }));
72953
+ }
72944
72954
  return;
72945
72955
  }
72946
72956
  const remindersState = (0, state_js_1.createRemindersState)(daemonCtx.stateService);
@@ -72963,19 +72973,7 @@ var require_unstage_verify_completion = __commonJS({
72963
72973
  const verificationToolsResult = await remindersState.verificationTools.read(sessionId);
72964
72974
  const toolsState = verificationToolsResult.data;
72965
72975
  const verificationTools = config.verification_tools ?? {};
72966
- const hasToolsNeedingVerification = Object.entries(verificationTools).some(([toolName, toolConfig]) => {
72967
- if (!toolConfig.enabled)
72968
- return false;
72969
- const state = toolsState[toolName];
72970
- if (!state)
72971
- return true;
72972
- if (state.status === "staged")
72973
- return true;
72974
- if (state.status === "verified" || state.status === "cooldown") {
72975
- return state.editsSinceVerified >= toolConfig.clearing_threshold;
72976
- }
72977
- return false;
72978
- });
72976
+ const hasToolsNeedingVerification = Object.entries(verificationTools).some(([toolName, toolConfig]) => toolNeedsVerification(toolConfig, toolsState[toolName]));
72979
72977
  if (!hasToolsNeedingVerification) {
72980
72978
  daemonCtx.logger.info("VC unstage: all tools verified, skipping wrapper re-stage", {
72981
72979
  sessionId,
@@ -72983,6 +72981,28 @@ var require_unstage_verify_completion = __commonJS({
72983
72981
  });
72984
72982
  await remindersState.vcUnverified.delete(sessionId);
72985
72983
  } else {
72984
+ for (const [toolName, toolConfig] of Object.entries(verificationTools)) {
72985
+ if (!toolNeedsVerification(toolConfig, toolsState[toolName]))
72986
+ continue;
72987
+ const reminderId = types_js_1.TOOL_REMINDER_MAP[toolName];
72988
+ if (!reminderId)
72989
+ continue;
72990
+ const toolReminder = (0, reminder_utils_js_1.resolveReminder)(reminderId, {
72991
+ context: {},
72992
+ assets: daemonCtx.assets
72993
+ });
72994
+ if (toolReminder) {
72995
+ await (0, reminder_utils_js_1.stageReminder)(daemonCtx, "Stop", {
72996
+ ...toolReminder,
72997
+ stagedAt: {
72998
+ timestamp: Date.now(),
72999
+ turnCount: unverifiedState.setAt.turnCount,
73000
+ toolsThisTurn: unverifiedState.setAt.toolsThisTurn,
73001
+ toolCount: unverifiedState.setAt.toolCount
73002
+ }
73003
+ });
73004
+ }
73005
+ }
72986
73006
  const reminder = (0, reminder_utils_js_1.resolveReminder)(types_js_1.ReminderIds.VERIFY_COMPLETION, {
72987
73007
  context: {},
72988
73008
  assets: daemonCtx.assets
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scotthamilton77/sidekick",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "AI pair programming assistant with personas, session tracking, and contextual nudges",
5
5
  "bin": {
6
6
  "sidekick": "dist/bin.js"