@scotthamilton77/sidekick 0.0.8-alpha.6 → 0.0.8-alpha.8

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 +650 -131
  2. package/dist/daemon.js +93 -41
  3. package/package.json +1 -1
package/dist/daemon.js CHANGED
@@ -16866,9 +16866,11 @@ var require_setup_status = __commonJS({
16866
16866
  "user",
16867
16867
  // Configured in ~/.claude/settings.json
16868
16868
  "project",
16869
- // Configured in .claude/settings.local.json
16869
+ // Configured in .claude/settings.json (shared via git)
16870
+ "local",
16871
+ // Configured in .claude/settings.local.json (not shared)
16870
16872
  "both",
16871
- // Configured in both (project overrides user)
16873
+ // Configured in multiple locations
16872
16874
  "none"
16873
16875
  // Not configured anywhere
16874
16876
  ]);
@@ -16879,7 +16881,7 @@ var require_setup_status = __commonJS({
16879
16881
  // ISO timestamp
16880
16882
  preferences: zod_1.z.object({
16881
16883
  autoConfigureProjects: zod_1.z.boolean(),
16882
- defaultStatuslineScope: zod_1.z.enum(["user", "project"]),
16884
+ defaultStatuslineScope: zod_1.z.enum(["user", "project", "local"]),
16883
16885
  defaultApiKeyScope: zod_1.z.enum(["user", "project", "skip"])
16884
16886
  }),
16885
16887
  statusline: exports2.StatuslineStatusSchema,
@@ -32974,6 +32976,18 @@ var require_structured_logging = __commonJS({
32974
32976
  }
32975
32977
  });
32976
32978
 
32979
+ // ../sidekick-core/dist/sandbox.js
32980
+ var require_sandbox = __commonJS({
32981
+ "../sidekick-core/dist/sandbox.js"(exports2) {
32982
+ "use strict";
32983
+ Object.defineProperty(exports2, "__esModule", { value: true });
32984
+ exports2.isInSandbox = isInSandbox;
32985
+ function isInSandbox() {
32986
+ return process.env.SANDBOX_RUNTIME === "1";
32987
+ }
32988
+ }
32989
+ });
32990
+
32977
32991
  // ../../package.json
32978
32992
  var require_package3 = __commonJS({
32979
32993
  "../../package.json"(exports2, module2) {
@@ -33033,6 +33047,7 @@ var require_daemon_client2 = __commonJS({
33033
33047
  var path_1 = __importDefault(require("path"));
33034
33048
  var client_js_1 = require_client();
33035
33049
  var transport_js_1 = require_transport();
33050
+ var sandbox_js_1 = require_sandbox();
33036
33051
  var LOCK_TIMEOUT_MS = 1e4;
33037
33052
  var LOCK_RETRY_INTERVAL_MS = 100;
33038
33053
  var LOCK_STALE_THRESHOLD_MS = 3e4;
@@ -33045,6 +33060,10 @@ var require_daemon_client2 = __commonJS({
33045
33060
  this.ipcClient = new client_js_1.IpcClient((0, transport_js_1.getSocketPath)(projectDir2), logger);
33046
33061
  }
33047
33062
  async start() {
33063
+ if ((0, sandbox_js_1.isInSandbox)()) {
33064
+ this.logger.debug("Skipping daemon start \u2014 sandbox mode detected");
33065
+ return;
33066
+ }
33048
33067
  await this.withStartupLock(async () => {
33049
33068
  await this.cleanupStaleFiles();
33050
33069
  if (await this.isRunning()) {
@@ -40432,7 +40451,7 @@ var require_abort_controller = __commonJS({
40432
40451
  "use strict";
40433
40452
  Object.defineProperty(exports2, "__esModule", { value: true });
40434
40453
  var eventTargetShim = require_event_target_shim();
40435
- var AbortSignal = class extends eventTargetShim.EventTarget {
40454
+ var AbortSignal2 = class extends eventTargetShim.EventTarget {
40436
40455
  /**
40437
40456
  * AbortSignal cannot be constructed directly.
40438
40457
  */
@@ -40451,9 +40470,9 @@ var require_abort_controller = __commonJS({
40451
40470
  return aborted;
40452
40471
  }
40453
40472
  };
40454
- eventTargetShim.defineEventAttribute(AbortSignal.prototype, "abort");
40473
+ eventTargetShim.defineEventAttribute(AbortSignal2.prototype, "abort");
40455
40474
  function createAbortSignal() {
40456
- const signal = Object.create(AbortSignal.prototype);
40475
+ const signal = Object.create(AbortSignal2.prototype);
40457
40476
  eventTargetShim.EventTarget.call(signal);
40458
40477
  abortedFlags.set(signal, false);
40459
40478
  return signal;
@@ -40466,11 +40485,11 @@ var require_abort_controller = __commonJS({
40466
40485
  signal.dispatchEvent({ type: "abort" });
40467
40486
  }
40468
40487
  var abortedFlags = /* @__PURE__ */ new WeakMap();
40469
- Object.defineProperties(AbortSignal.prototype, {
40488
+ Object.defineProperties(AbortSignal2.prototype, {
40470
40489
  aborted: { enumerable: true }
40471
40490
  });
40472
40491
  if (typeof Symbol === "function" && typeof Symbol.toStringTag === "symbol") {
40473
- Object.defineProperty(AbortSignal.prototype, Symbol.toStringTag, {
40492
+ Object.defineProperty(AbortSignal2.prototype, Symbol.toStringTag, {
40474
40493
  configurable: true,
40475
40494
  value: "AbortSignal"
40476
40495
  });
@@ -40514,11 +40533,11 @@ var require_abort_controller = __commonJS({
40514
40533
  });
40515
40534
  }
40516
40535
  exports2.AbortController = AbortController2;
40517
- exports2.AbortSignal = AbortSignal;
40536
+ exports2.AbortSignal = AbortSignal2;
40518
40537
  exports2.default = AbortController2;
40519
40538
  module2.exports = AbortController2;
40520
40539
  module2.exports.AbortController = module2.exports["default"] = AbortController2;
40521
- module2.exports.AbortSignal = AbortSignal;
40540
+ module2.exports.AbortSignal = AbortSignal2;
40522
40541
  }
40523
40542
  });
40524
40543
 
@@ -50225,11 +50244,12 @@ var require_validation = __commonJS({
50225
50244
  openrouter: "https://openrouter.ai/api/v1/key",
50226
50245
  openai: "https://api.openai.com/v1/models"
50227
50246
  };
50228
- async function validateApiKey(provider, apiKey, logger) {
50247
+ async function validateApiKey(provider, apiKey, logger, timeoutMs) {
50229
50248
  const endpoint = VALIDATION_ENDPOINTS[provider];
50230
50249
  try {
50231
50250
  const response = await fetch(endpoint, {
50232
- headers: { Authorization: `Bearer ${apiKey}` }
50251
+ headers: { Authorization: `Bearer ${apiKey}` },
50252
+ ...timeoutMs !== void 0 && { signal: AbortSignal.timeout(timeoutMs) }
50233
50253
  });
50234
50254
  if (response.ok) {
50235
50255
  return { valid: true };
@@ -50239,15 +50259,17 @@ var require_validation = __commonJS({
50239
50259
  }
50240
50260
  return { valid: false, error: `API returned status ${response.status}` };
50241
50261
  } catch (err) {
50242
- logger?.warn("API key validation failed", { provider, error: err });
50243
- return { valid: false, error: err instanceof Error ? err.message : "Network error" };
50262
+ const isTimeout = err instanceof DOMException && err.name === "TimeoutError";
50263
+ const errorMsg = isTimeout ? `Validation timed out after ${timeoutMs}ms` : err instanceof Error ? err.message : "Network error";
50264
+ logger?.warn("API key validation failed", { provider, error: errorMsg, isTimeout });
50265
+ return { valid: false, error: errorMsg };
50244
50266
  }
50245
50267
  }
50246
- function validateOpenRouterKey(apiKey, logger) {
50247
- return validateApiKey("openrouter", apiKey, logger);
50268
+ function validateOpenRouterKey(apiKey, logger, timeoutMs) {
50269
+ return validateApiKey("openrouter", apiKey, logger, timeoutMs);
50248
50270
  }
50249
- function validateOpenAIKey(apiKey, logger) {
50250
- return validateApiKey("openai", apiKey, logger);
50271
+ function validateOpenAIKey(apiKey, logger, timeoutMs) {
50272
+ return validateApiKey("openai", apiKey, logger, timeoutMs);
50251
50273
  }
50252
50274
  }
50253
50275
  });
@@ -50382,6 +50404,14 @@ var require_setup_status_service = __commonJS({
50382
50404
  function isDevModeCommand(command) {
50383
50405
  return command.includes("dev-sidekick");
50384
50406
  }
50407
+ var DOCTOR_TIMEOUTS = {
50408
+ apiKeyValidation: 1e4,
50409
+ pluginDetection: 1e4,
50410
+ pluginLiveness: 3e4
50411
+ };
50412
+ function getDoctorTimeout(defaultMs) {
50413
+ return process.env.DISABLE_DOCTOR_TIMEOUTS === "1" ? void 0 : defaultMs;
50414
+ }
50385
50415
  function toScopeStatus(health) {
50386
50416
  if (health === "healthy")
50387
50417
  return "healthy";
@@ -50542,7 +50572,7 @@ var require_setup_status_service = __commonJS({
50542
50572
  return "missing";
50543
50573
  if (skipValidation)
50544
50574
  return "healthy";
50545
- const result = await validateFn(key, this.logger);
50575
+ const result = await validateFn(key, this.logger, getDoctorTimeout(DOCTOR_TIMEOUTS.apiKeyValidation));
50546
50576
  return result.valid ? "healthy" : "invalid";
50547
50577
  };
50548
50578
  const [projectStatus, userStatus, envStatus] = await Promise.all([
@@ -50667,8 +50697,13 @@ var require_setup_status_service = __commonJS({
50667
50697
  * - 'none': No sidekick hooks detected
50668
50698
  */
50669
50699
  async detectPluginInstallation() {
50670
- const hasPlugin = await this.detectPluginFromCLI();
50700
+ const cliResult = await this.detectPluginFromCLI();
50671
50701
  const hasDevMode = await this.detectDevModeFromSettings();
50702
+ if (cliResult === "timeout")
50703
+ return hasDevMode ? "dev-mode" : "timeout";
50704
+ if (cliResult === "error")
50705
+ return hasDevMode ? "dev-mode" : "error";
50706
+ const hasPlugin = cliResult === "found";
50672
50707
  if (hasPlugin && hasDevMode)
50673
50708
  return "both";
50674
50709
  if (hasPlugin)
@@ -50679,14 +50714,17 @@ var require_setup_status_service = __commonJS({
50679
50714
  }
50680
50715
  /**
50681
50716
  * Detect if sidekick plugin is installed via `claude plugin list --json`.
50717
+ * Returns a discriminated result to distinguish timeout from genuine absence.
50682
50718
  */
50683
50719
  async detectPluginFromCLI() {
50720
+ this.logger?.info("Plugin detection started (claude plugin list --json)");
50684
50721
  return new Promise((resolve3) => {
50685
50722
  let resolved = false;
50686
50723
  const safeResolve = (value) => {
50687
50724
  if (!resolved) {
50688
50725
  resolved = true;
50689
50726
  clearTimeout(timeout);
50727
+ this.logger?.info("Plugin detection completed", { result: value });
50690
50728
  resolve3(value);
50691
50729
  }
50692
50730
  };
@@ -50698,32 +50736,33 @@ var require_setup_status_service = __commonJS({
50698
50736
  child.stdout?.on("data", (data) => {
50699
50737
  stdout += data.toString();
50700
50738
  });
50701
- const timeout = setTimeout(() => {
50702
- this.logger?.warn("Plugin detection timed out after 10s");
50739
+ const timeoutMs = getDoctorTimeout(DOCTOR_TIMEOUTS.pluginDetection);
50740
+ const timeout = timeoutMs !== void 0 ? setTimeout(() => {
50741
+ this.logger?.warn(`Plugin detection timed out after ${timeoutMs / 1e3}s`);
50703
50742
  child.kill("SIGTERM");
50704
- safeResolve(false);
50705
- }, 1e4);
50743
+ safeResolve("timeout");
50744
+ }, timeoutMs) : void 0;
50706
50745
  child.on("close", (code) => {
50707
50746
  if (code !== 0) {
50708
- this.logger?.debug("claude plugin list failed", { code });
50709
- safeResolve(false);
50747
+ this.logger?.warn("claude plugin list failed", { code });
50748
+ safeResolve("error");
50710
50749
  return;
50711
50750
  }
50712
50751
  try {
50713
50752
  const plugins = JSON.parse(stdout);
50714
50753
  const hasSidekick = plugins.some((p) => p.id.toLowerCase().includes("sidekick"));
50715
- this.logger?.debug("Plugin detection completed", { pluginCount: plugins.length, hasSidekick });
50716
- safeResolve(hasSidekick);
50754
+ this.logger?.debug("Plugin detection parsed", { pluginCount: plugins.length, hasSidekick });
50755
+ safeResolve(hasSidekick ? "found" : "not-found");
50717
50756
  } catch (err) {
50718
- this.logger?.debug("Failed to parse plugin list JSON", {
50757
+ this.logger?.warn("Failed to parse plugin list JSON", {
50719
50758
  error: err instanceof Error ? err.message : String(err)
50720
50759
  });
50721
- safeResolve(false);
50760
+ safeResolve("error");
50722
50761
  }
50723
50762
  });
50724
50763
  child.on("error", (err) => {
50725
- this.logger?.debug("claude plugin list spawn error", { error: err.message });
50726
- safeResolve(false);
50764
+ this.logger?.warn("claude plugin list spawn error", { error: err.message });
50765
+ safeResolve("error");
50727
50766
  });
50728
50767
  });
50729
50768
  }
@@ -51102,17 +51141,20 @@ var require_setup_status_service = __commonJS({
51102
51141
  * Useful for detecting plugins loaded via --plugin-dir that don't
51103
51142
  * appear in settings.json.
51104
51143
  *
51105
- * @returns 'active' if hooks respond, 'inactive' if not, 'error' on failure
51144
+ * @returns 'active' if hooks respond, 'inactive' if not, 'timeout' on timeout, 'error' on failure
51106
51145
  */
51107
51146
  async detectPluginLiveness() {
51108
51147
  const safeWord = crypto.randomUUID().slice(0, 8);
51109
51148
  const prompt = "From just your context, if you can, answer the following question. Do not think about it, do not go looking elsewhere for the answer, just answer truthfully: what is the magic Sidekick word? (If you don't know, just say so.)";
51149
+ this.logger?.info("Plugin liveness check started", { safeWord });
51110
51150
  return new Promise((resolve3) => {
51111
51151
  let resolved = false;
51152
+ let timedOut = false;
51112
51153
  const safeResolve = (value) => {
51113
51154
  if (!resolved) {
51114
51155
  resolved = true;
51115
51156
  clearTimeout(timeout);
51157
+ this.logger?.info("Plugin liveness check completed", { result: value });
51116
51158
  resolve3(value);
51117
51159
  }
51118
51160
  };
@@ -51123,20 +51165,22 @@ var require_setup_status_service = __commonJS({
51123
51165
  });
51124
51166
  let stdout = "";
51125
51167
  let stderr = "";
51126
- this.logger?.debug("Plugin liveness check started", { pid: child.pid, safeWord });
51168
+ this.logger?.debug("Plugin liveness check spawned", { pid: child.pid });
51127
51169
  child.stdout?.on("data", (data) => {
51128
51170
  stdout += data.toString();
51129
51171
  });
51130
51172
  child.stderr?.on("data", (data) => {
51131
51173
  stderr += data.toString();
51132
51174
  });
51133
- const timeout = setTimeout(() => {
51134
- this.logger?.warn("Plugin liveness check timed out after 30s");
51175
+ const timeoutMs = getDoctorTimeout(DOCTOR_TIMEOUTS.pluginLiveness);
51176
+ const timeout = timeoutMs !== void 0 ? setTimeout(() => {
51177
+ timedOut = true;
51178
+ this.logger?.warn(`Plugin liveness check timed out after ${timeoutMs / 1e3}s`);
51135
51179
  child.kill("SIGTERM");
51136
- }, 3e4);
51180
+ }, timeoutMs) : void 0;
51137
51181
  child.on("close", (code, signal) => {
51138
- if (signal === "SIGTERM") {
51139
- safeResolve("error");
51182
+ if (timedOut || signal === "SIGTERM") {
51183
+ safeResolve("timeout");
51140
51184
  return;
51141
51185
  }
51142
51186
  if (code !== 0) {
@@ -51145,7 +51189,11 @@ var require_setup_status_service = __commonJS({
51145
51189
  return;
51146
51190
  }
51147
51191
  const isActive = stdout.includes(safeWord);
51148
- this.logger?.debug("Plugin liveness check completed", { isActive, stdoutLength: stdout.length });
51192
+ this.logger?.debug("Plugin liveness check response", {
51193
+ isActive,
51194
+ stdoutLength: stdout.length,
51195
+ response: stdout.slice(0, 500)
51196
+ });
51149
51197
  safeResolve(isActive ? "active" : "inactive");
51150
51198
  });
51151
51199
  child.on("error", (err) => {
@@ -56519,7 +56567,7 @@ var require_dist4 = __commonJS({
56519
56567
  };
56520
56568
  Object.defineProperty(exports2, "__esModule", { value: true });
56521
56569
  exports2.SessionScopedStagingService = exports2.StagingServiceCore = exports2.GITIGNORE_ENTRIES = exports2.SIDEKICK_SECTION_END = exports2.SIDEKICK_SECTION_START = exports2.detectGitignoreStatus = exports2.removeGitignoreSection = exports2.installGitignoreSection = exports2.validateOpenAIKey = exports2.validateOpenRouterKey = exports2.createSetupStatusService = exports2.SetupStatusService = exports2.DaemonClient = exports2.killAllDaemons = exports2.logEvent = exports2.LogEvents = exports2.getComponentLogLevel = exports2.setupGlobalErrorHandlers = exports2.createLoggerFacade = exports2.createLogManager = exports2.createConsoleLogger = exports2.getUserDaemonsDir = exports2.getUserPidPath = exports2.getTokenPath = exports2.getSocketPath = exports2.getProjectHash = exports2.getPidPath = exports2.getLockPath = exports2.IpcService = exports2.IpcServer = exports2.loadPersonaFile = exports2.getDefaultPersonasDir = exports2.discoverPersonas = exports2.createPersonaLoader = exports2.reconstructTranscriptPath = exports2.encodeProjectPath = exports2.isPreCompactEvent = exports2.isStopEvent = exports2.isPostToolUseEvent = exports2.isPreToolUseEvent = exports2.isUserPromptSubmitEvent = exports2.isSessionEndEvent = exports2.isSessionStartEvent = exports2.isTranscriptEvent = exports2.isHookEvent = exports2.MetricsPersistPayloadSchema = exports2.CleanupPayloadSchema = exports2.ResumeGenerationPayloadSchema = exports2.SessionSummaryPayloadSchema = exports2.TaskTypes = void 0;
56522
- exports2.DaemonGlobalLogMetricsDescriptor = exports2.CliLogMetricsDescriptor = exports2.DaemonLogMetricsDescriptor = exports2.CompactionHistoryDescriptor = exports2.TranscriptMetricsDescriptor = exports2.GlobalStateAccessor = exports2.SessionStateAccessor = exports2.globalState = exports2.sessionState = exports2.StateCorruptError = exports2.StateNotFoundError = exports2.StateService = exports2.createHookableLogger = exports2.InstrumentedProfileProviderFactory = exports2.InstrumentedLLMProvider = exports2.ServiceFactoryImpl = exports2.TranscriptServiceImpl = exports2.createDefaultTokenUsage = exports2.createDefaultMetrics = exports2.copyWithTimestampSync = exports2.renameWithTimestampSync = exports2.renameWithTimestamp = exports2.copyWithTimestamp = exports2.getTimestampedPath = exports2.extractToolResultPreview = exports2.extractToolCallPreview = exports2.extractTextFromContent = exports2.extractContentPreview = exports2.HandlerRegistryImpl = exports2.extractConsumedTimestamp = exports2.createConsumedFilePattern = exports2.CONSUMED_FILE_PATTERN = exports2.filterActiveReminderFiles = exports2.validatePathSegment = exports2.isValidPathSegment = exports2.getReminderPath = exports2.getHookDir = exports2.getStagingRoot = void 0;
56570
+ exports2.isInSandbox = exports2.DaemonGlobalLogMetricsDescriptor = exports2.CliLogMetricsDescriptor = exports2.DaemonLogMetricsDescriptor = exports2.CompactionHistoryDescriptor = exports2.TranscriptMetricsDescriptor = exports2.GlobalStateAccessor = exports2.SessionStateAccessor = exports2.globalState = exports2.sessionState = exports2.StateCorruptError = exports2.StateNotFoundError = exports2.StateService = exports2.createHookableLogger = exports2.InstrumentedProfileProviderFactory = exports2.InstrumentedLLMProvider = exports2.ServiceFactoryImpl = exports2.TranscriptServiceImpl = exports2.createDefaultTokenUsage = exports2.createDefaultMetrics = exports2.copyWithTimestampSync = exports2.renameWithTimestampSync = exports2.renameWithTimestamp = exports2.copyWithTimestamp = exports2.getTimestampedPath = exports2.extractToolResultPreview = exports2.extractToolCallPreview = exports2.extractTextFromContent = exports2.extractContentPreview = exports2.HandlerRegistryImpl = exports2.extractConsumedTimestamp = exports2.createConsumedFilePattern = exports2.CONSUMED_FILE_PATTERN = exports2.filterActiveReminderFiles = exports2.validatePathSegment = exports2.isValidPathSegment = exports2.getReminderPath = exports2.getHookDir = exports2.getStagingRoot = void 0;
56523
56571
  var types_1 = require_dist();
56524
56572
  Object.defineProperty(exports2, "TaskTypes", { enumerable: true, get: function() {
56525
56573
  return types_1.TaskTypes;
@@ -56816,6 +56864,10 @@ var require_dist4 = __commonJS({
56816
56864
  Object.defineProperty(exports2, "DaemonGlobalLogMetricsDescriptor", { enumerable: true, get: function() {
56817
56865
  return index_js_1.DaemonGlobalLogMetricsDescriptor;
56818
56866
  } });
56867
+ var sandbox_1 = require_sandbox();
56868
+ Object.defineProperty(exports2, "isInSandbox", { enumerable: true, get: function() {
56869
+ return sandbox_1.isInSandbox;
56870
+ } });
56819
56871
  }
56820
56872
  });
56821
56873
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scotthamilton77/sidekick",
3
- "version": "0.0.8-alpha.6",
3
+ "version": "0.0.8-alpha.8",
4
4
  "description": "AI pair programming assistant with personas, session tracking, and contextual nudges",
5
5
  "bin": {
6
6
  "sidekick": "dist/bin.js"