@scotthamilton77/sidekick 0.1.19 → 0.1.20

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
@@ -1038,6 +1038,8 @@ var require_hook_events = __commonJS({
1038
1038
  exports2.isPostToolUseEvent = isPostToolUseEvent;
1039
1039
  exports2.isStopEvent = isStopEvent;
1040
1040
  exports2.isPreCompactEvent = isPreCompactEvent;
1041
+ exports2.isSubagentStartEvent = isSubagentStartEvent;
1042
+ exports2.isSubagentStopEvent = isSubagentStopEvent;
1041
1043
  exports2.HOOK_NAMES = [
1042
1044
  "SessionStart",
1043
1045
  "SessionEnd",
@@ -1045,7 +1047,9 @@ var require_hook_events = __commonJS({
1045
1047
  "PreToolUse",
1046
1048
  "PostToolUse",
1047
1049
  "Stop",
1048
- "PreCompact"
1050
+ "PreCompact",
1051
+ "SubagentStart",
1052
+ "SubagentStop"
1049
1053
  ];
1050
1054
  function isSessionStartEvent(event) {
1051
1055
  return event.hook === "SessionStart";
@@ -1068,6 +1072,12 @@ var require_hook_events = __commonJS({
1068
1072
  function isPreCompactEvent(event) {
1069
1073
  return event.hook === "PreCompact";
1070
1074
  }
1075
+ function isSubagentStartEvent(event) {
1076
+ return event.hook === "SubagentStart";
1077
+ }
1078
+ function isSubagentStopEvent(event) {
1079
+ return event.hook === "SubagentStop";
1080
+ }
1071
1081
  }
1072
1082
  });
1073
1083
 
@@ -17942,7 +17952,7 @@ var require_hook_input = __commonJS({
17942
17952
  "../types/dist/hook-input.js"(exports2) {
17943
17953
  "use strict";
17944
17954
  Object.defineProperty(exports2, "__esModule", { value: true });
17945
- exports2.HookInputSchema = exports2.StatuslineInputSchema = exports2.StatuslineWorkspaceSchema = exports2.StatuslineCostSchema = exports2.StatuslineContextWindowSchema = exports2.StatuslineModelSchema = exports2.NotificationInputSchema = exports2.PreCompactInputSchema = exports2.SessionEndInputSchema = exports2.SessionStartInputSchema = exports2.StopInputSchema = exports2.PostToolUseInputSchema = exports2.PreToolUseInputSchema = exports2.UserPromptSubmitInputSchema = exports2.HookInputBaseSchema = void 0;
17955
+ exports2.HookInputSchema = exports2.StatuslineInputSchema = exports2.StatuslineWorkspaceSchema = exports2.StatuslineCostSchema = exports2.StatuslineContextWindowSchema = exports2.StatuslineModelSchema = exports2.SubagentStopInputSchema = exports2.SubagentStartInputSchema = exports2.NotificationInputSchema = exports2.PreCompactInputSchema = exports2.SessionEndInputSchema = exports2.SessionStartInputSchema = exports2.StopInputSchema = exports2.PostToolUseInputSchema = exports2.PreToolUseInputSchema = exports2.UserPromptSubmitInputSchema = exports2.HookInputBaseSchema = void 0;
17946
17956
  var zod_1 = require_zod();
17947
17957
  exports2.HookInputBaseSchema = zod_1.z.object({
17948
17958
  /** Unique identifier for the current Claude session */
@@ -17954,7 +17964,11 @@ var require_hook_input = __commonJS({
17954
17964
  /** Current permission level: "default", "plan", "acceptEdits", or "bypassPermissions" */
17955
17965
  permission_mode: zod_1.z.string().optional(),
17956
17966
  /** Name of the triggered hook (e.g., "UserPromptSubmit", "SessionStart") */
17957
- hook_event_name: zod_1.z.string()
17967
+ hook_event_name: zod_1.z.string(),
17968
+ /** Unique identifier for the subagent (present when hook fires inside a subagent) */
17969
+ agent_id: zod_1.z.string().optional(),
17970
+ /** Agent type/name: "Bash", "Explore", "Plan", or custom (present when inside a subagent) */
17971
+ agent_type: zod_1.z.string().optional()
17958
17972
  });
17959
17973
  exports2.UserPromptSubmitInputSchema = exports2.HookInputBaseSchema.extend({
17960
17974
  /** The user's message text */
@@ -18002,6 +18016,26 @@ var require_hook_input = __commonJS({
18002
18016
  /** Type: "permission_prompt", "idle_prompt", "auth_success", or "elicitation_dialog" */
18003
18017
  notification_type: zod_1.z.string()
18004
18018
  });
18019
+ exports2.SubagentStartInputSchema = exports2.HookInputBaseSchema.extend({
18020
+ /** Unique identifier for the subagent (required per official docs) */
18021
+ agent_id: zod_1.z.string(),
18022
+ /** Agent name: "Bash", "Explore", "Plan", or custom agent name */
18023
+ agent_type: zod_1.z.string()
18024
+ });
18025
+ exports2.SubagentStopInputSchema = exports2.HookInputBaseSchema.extend({
18026
+ /** Unique identifier for the subagent */
18027
+ agent_id: zod_1.z.string(),
18028
+ /** Agent name */
18029
+ agent_type: zod_1.z.string(),
18030
+ /** Path to subagent's own transcript JSONL */
18031
+ agent_transcript_path: zod_1.z.string(),
18032
+ /** Text content of the subagent's final response */
18033
+ last_assistant_message: zod_1.z.string(),
18034
+ /** Permission mode for the subagent session */
18035
+ permission_mode: zod_1.z.string(),
18036
+ /** Optional: whether stop hook is active (probe doc says never populated; official docs show false) */
18037
+ stop_hook_active: zod_1.z.boolean().optional()
18038
+ });
18005
18039
  exports2.StatuslineModelSchema = zod_1.z.object({
18006
18040
  /** Full model identifier (e.g., "claude-opus-4-1") */
18007
18041
  id: zod_1.z.string(),
@@ -18057,13 +18091,15 @@ var require_hook_input = __commonJS({
18057
18091
  output_style: zod_1.z.object({ name: zod_1.z.string() }).optional()
18058
18092
  });
18059
18093
  exports2.HookInputSchema = zod_1.z.union([
18094
+ exports2.SessionStartInputSchema,
18095
+ exports2.SessionEndInputSchema,
18060
18096
  exports2.UserPromptSubmitInputSchema,
18061
18097
  exports2.PreToolUseInputSchema,
18062
18098
  exports2.PostToolUseInputSchema,
18063
18099
  exports2.StopInputSchema,
18064
- exports2.SessionStartInputSchema,
18065
- exports2.SessionEndInputSchema,
18066
18100
  exports2.PreCompactInputSchema,
18101
+ exports2.SubagentStartInputSchema,
18102
+ exports2.SubagentStopInputSchema,
18067
18103
  exports2.NotificationInputSchema,
18068
18104
  exports2.HookInputBaseSchema
18069
18105
  // Fallback for hooks without extra fields
@@ -18160,9 +18196,11 @@ var require_setup_status = __commonJS({
18160
18196
  "missing",
18161
18197
  // User declined or entries not present
18162
18198
  "incomplete",
18163
- // Section exists but missing end marker or required entries
18164
- "installed"
18165
- // Sidekick section present with all required entries
18199
+ // .sidekick/.gitignore exists but missing required entries (legacy: partial root section)
18200
+ "installed",
18201
+ // .sidekick/.gitignore present with all entries (new format)
18202
+ "legacy"
18203
+ // Root .gitignore has old marked section — functional, migrate recommended
18166
18204
  ]);
18167
18205
  exports2.ProjectApiKeyValueSchema = zod_1.z.union([exports2.ProjectApiKeyHealthSchema, exports2.ProjectApiKeyStatusSchema]);
18168
18206
  exports2.ProjectSetupStatusSchema = zod_1.z.object({
@@ -27199,6 +27237,18 @@ var require_dist2 = __commonJS({
27199
27237
  }
27200
27238
  });
27201
27239
 
27240
+ // ../sidekick-core/dist/error-utils.js
27241
+ var require_error_utils = __commonJS({
27242
+ "../sidekick-core/dist/error-utils.js"(exports2) {
27243
+ "use strict";
27244
+ Object.defineProperty(exports2, "__esModule", { value: true });
27245
+ exports2.toErrorMessage = toErrorMessage;
27246
+ function toErrorMessage(error) {
27247
+ return error instanceof Error ? error.message : String(error);
27248
+ }
27249
+ }
27250
+ });
27251
+
27202
27252
  // ../sidekick-core/dist/assets.js
27203
27253
  var require_assets = __commonJS({
27204
27254
  "../sidekick-core/dist/assets.js"(exports2) {
@@ -27212,6 +27262,7 @@ var require_assets = __commonJS({
27212
27262
  var yaml_1 = require_dist2();
27213
27263
  var node_os_1 = require("node:os");
27214
27264
  var node_path_1 = require("node:path");
27265
+ var error_utils_js_1 = require_error_utils();
27215
27266
  function createCascadingResolver(options) {
27216
27267
  const { cascadeLayers } = options;
27217
27268
  const findFile = (relativePath) => {
@@ -27261,7 +27312,7 @@ var require_assets = __commonJS({
27261
27312
  try {
27262
27313
  return (0, yaml_1.parse)(content);
27263
27314
  } catch (error) {
27264
- throw new Error(`Failed to parse YAML file ${relativePath}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
27315
+ throw new Error(`Failed to parse YAML file ${relativePath}: ${(0, error_utils_js_1.toErrorMessage)(error)}`, { cause: error });
27265
27316
  }
27266
27317
  },
27267
27318
  cascadeLayers
@@ -27336,6 +27387,7 @@ var require_persona_loader = __commonJS({
27336
27387
  var node_path_1 = require("node:path");
27337
27388
  var types_1 = require_dist();
27338
27389
  var assets_js_1 = require_assets();
27390
+ var error_utils_js_1 = require_error_utils();
27339
27391
  function buildPersonaCascadeLayers(defaultPersonasDir, homeDir, projectRoot) {
27340
27392
  const layers = [];
27341
27393
  layers.push(defaultPersonasDir);
@@ -27363,7 +27415,7 @@ var require_persona_loader = __commonJS({
27363
27415
  }
27364
27416
  return result.data;
27365
27417
  } catch (error) {
27366
- const message = error instanceof Error ? error.message : String(error);
27418
+ const message = (0, error_utils_js_1.toErrorMessage)(error);
27367
27419
  logger?.warn(`Failed to load persona file ${filename}: ${message}`);
27368
27420
  return null;
27369
27421
  }
@@ -27946,6 +27998,7 @@ var require_config2 = __commonJS({
27946
27998
  var node_path_1 = require("node:path");
27947
27999
  var yaml_1 = require_dist2();
27948
28000
  var v4_1 = require_v4();
28001
+ var error_utils_js_1 = require_error_utils();
27949
28002
  function deepFreeze(obj) {
27950
28003
  if (obj === null || typeof obj !== "object") {
27951
28004
  return obj;
@@ -27972,7 +28025,7 @@ var require_config2 = __commonJS({
27972
28025
  consoleEnabled: v4_1.z.boolean(),
27973
28026
  /** Per-component log level overrides. Keys are component names (e.g., 'reminders', 'statusline'). */
27974
28027
  components: v4_1.z.record(v4_1.z.string(), LogLevelSchema).optional(),
27975
- /** Log rotation settings. Defaults to 10MB/5 files if not specified. */
28028
+ /** Log rotation settings. Defaults come from core.defaults.yaml (2MB/2 files). */
27976
28029
  rotation: v4_1.z.object({
27977
28030
  maxSizeBytes: v4_1.z.number().min(1),
27978
28031
  maxFiles: v4_1.z.number().min(1)
@@ -28022,7 +28075,10 @@ var require_config2 = __commonJS({
28022
28075
  fallbackProfileId: v4_1.z.string().optional(),
28023
28076
  // OpenRouter-specific provider routing (ignored for other providers)
28024
28077
  providerAllowlist: v4_1.z.array(v4_1.z.string()).optional(),
28025
- providerBlocklist: v4_1.z.array(v4_1.z.string()).optional()
28078
+ providerBlocklist: v4_1.z.array(v4_1.z.string()).optional(),
28079
+ // OpenRouter-specific: toggle the model's reasoning mode (maps to reasoning.enabled).
28080
+ // Ignored for non-openrouter providers.
28081
+ reasoning: v4_1.z.boolean().optional()
28026
28082
  });
28027
28083
  exports2.LlmConfigSchema = v4_1.z.object({
28028
28084
  defaultProfile: v4_1.z.string(),
@@ -28138,7 +28194,7 @@ var require_config2 = __commonJS({
28138
28194
  const parsed = (0, yaml_1.parse)(content);
28139
28195
  return parsed ?? {};
28140
28196
  } catch (err) {
28141
- const message = err instanceof Error ? err.message : String(err);
28197
+ const message = (0, error_utils_js_1.toErrorMessage)(err);
28142
28198
  throw new Error(`Failed to parse YAML at ${filePath}: ${message}`, { cause: err });
28143
28199
  }
28144
28200
  }
@@ -28446,6 +28502,7 @@ var require_config_writer = __commonJS({
28446
28502
  var node_os_1 = require("node:os");
28447
28503
  var node_path_1 = require("node:path");
28448
28504
  var yaml_1 = __importDefault2(require_dist2());
28505
+ var error_utils_js_1 = require_error_utils();
28449
28506
  var config_1 = require_config2();
28450
28507
  var VALID_DOMAINS = /* @__PURE__ */ new Set(["core", "llm", "transcript", "features"]);
28451
28508
  var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
@@ -28572,7 +28629,7 @@ var require_config_writer = __commonJS({
28572
28629
  } catch {
28573
28630
  }
28574
28631
  }
28575
- const message = err instanceof Error ? err.message : String(err);
28632
+ const message = (0, error_utils_js_1.toErrorMessage)(err);
28576
28633
  throw new Error(`Configuration validation failed after setting "${dotPath}": ${message}`, { cause: err });
28577
28634
  }
28578
28635
  return {
@@ -34235,6 +34292,8 @@ var require_session_log_writer = __commonJS({
34235
34292
  idleTimeoutMs;
34236
34293
  /** Map key: `${sessionId}/${logFile}` */
34237
34294
  handles = /* @__PURE__ */ new Map();
34295
+ /** Sentinel map to prevent duplicate handle creation on concurrent writes */
34296
+ pendingCreation = /* @__PURE__ */ new Map();
34238
34297
  constructor(options) {
34239
34298
  this.sessionsDir = options.sessionsDir;
34240
34299
  this.maxHandles = options.maxHandles ?? 10;
@@ -34254,30 +34313,26 @@ var require_session_log_writer = __commonJS({
34254
34313
  if (!(0, staging_paths_js_1.isValidPathSegment)(sessionId) || !(0, staging_paths_js_1.isValidPathSegment)(logFile))
34255
34314
  return;
34256
34315
  const key = `${sessionId}/${logFile}`;
34316
+ const pending = this.pendingCreation.get(key);
34317
+ if (pending) {
34318
+ try {
34319
+ await pending;
34320
+ } catch {
34321
+ }
34322
+ }
34257
34323
  let entry = this.handles.get(key);
34258
34324
  if (!entry) {
34259
34325
  if (this.handles.size >= this.maxHandles) {
34260
34326
  this.evictLRU();
34261
34327
  }
34262
- const logDir = (0, node_path_1.join)(this.sessionsDir, sessionId, "logs");
34263
- await (0, promises_12.mkdir)(logDir, { recursive: true });
34264
- const filePath = (0, node_path_1.join)(logDir, logFile);
34265
- const stream = (0, node_fs_1.createWriteStream)(filePath, { flags: "a" });
34266
- const ready = new Promise((resolve3, reject) => {
34267
- stream.once("open", () => resolve3());
34268
- stream.once("error", (err) => {
34269
- this.handles.delete(key);
34270
- stream.destroy();
34271
- reject(err);
34272
- });
34273
- });
34274
- entry = {
34275
- stream,
34276
- lastUsed: Date.now(),
34277
- timer: null,
34278
- ready
34279
- };
34280
- this.handles.set(key, entry);
34328
+ const creationPromise = this.createHandle(sessionId, logFile);
34329
+ this.pendingCreation.set(key, creationPromise);
34330
+ try {
34331
+ entry = await creationPromise;
34332
+ this.handles.set(key, entry);
34333
+ } finally {
34334
+ this.pendingCreation.delete(key);
34335
+ }
34281
34336
  }
34282
34337
  await entry.ready;
34283
34338
  entry.lastUsed = Date.now();
@@ -34293,6 +34348,25 @@ var require_session_log_writer = __commonJS({
34293
34348
  });
34294
34349
  });
34295
34350
  }
34351
+ async createHandle(sessionId, logFile) {
34352
+ const logDir = (0, node_path_1.join)(this.sessionsDir, sessionId, "logs");
34353
+ await (0, promises_12.mkdir)(logDir, { recursive: true });
34354
+ const filePath = (0, node_path_1.join)(logDir, logFile);
34355
+ const stream = (0, node_fs_1.createWriteStream)(filePath, { flags: "a" });
34356
+ const ready = new Promise((resolve3, reject) => {
34357
+ stream.once("open", () => resolve3());
34358
+ stream.once("error", (err) => {
34359
+ stream.destroy();
34360
+ reject(err);
34361
+ });
34362
+ });
34363
+ return {
34364
+ stream,
34365
+ lastUsed: Date.now(),
34366
+ timer: null,
34367
+ ready
34368
+ };
34369
+ }
34296
34370
  /** Close all handles for a specific session. */
34297
34371
  async closeSession(sessionId) {
34298
34372
  const prefix = `${sessionId}/`;
@@ -46093,6 +46167,7 @@ var require_structured_logging = __commonJS({
46093
46167
  var node_fs_1 = require("node:fs");
46094
46168
  var node_path_1 = require("node:path");
46095
46169
  var node_stream_1 = require("node:stream");
46170
+ var error_utils_js_1 = require_error_utils();
46096
46171
  var log_events_1 = require_log_events();
46097
46172
  Object.defineProperty(exports2, "LogEvents", { enumerable: true, get: function() {
46098
46173
  return log_events_1.LogEvents;
@@ -46122,8 +46197,8 @@ var require_structured_logging = __commonJS({
46122
46197
  }
46123
46198
  return defaultLevel;
46124
46199
  }
46125
- exports2.DEFAULT_ROTATE_SIZE_BYTES = 10 * 1024 * 1024;
46126
- exports2.DEFAULT_MAX_FILES = 5;
46200
+ exports2.DEFAULT_ROTATE_SIZE_BYTES = 2 * 1024 * 1024;
46201
+ exports2.DEFAULT_MAX_FILES = 2;
46127
46202
  var DEFAULT_REDACT_KEYS = [
46128
46203
  "apiKey",
46129
46204
  "token",
@@ -46464,7 +46539,7 @@ var require_structured_logging = __commonJS({
46464
46539
  upgradeOptions.onUpgradeError(err);
46465
46540
  }
46466
46541
  activeLogger.error("Failed to upgrade to Pino logger", {
46467
- error: err instanceof Error ? err.message : String(err)
46542
+ error: (0, error_utils_js_1.toErrorMessage)(err)
46468
46543
  });
46469
46544
  }
46470
46545
  },
@@ -46480,7 +46555,7 @@ var require_structured_logging = __commonJS({
46480
46555
  };
46481
46556
  const rejectionHandler = (reason) => {
46482
46557
  logger.fatal("Unhandled promise rejection", {
46483
- reason: reason instanceof Error ? reason.message : String(reason)
46558
+ reason: (0, error_utils_js_1.toErrorMessage)(reason)
46484
46559
  });
46485
46560
  };
46486
46561
  process.on("uncaughtException", uncaughtHandler);
@@ -46573,13 +46648,11 @@ var require_daemon_client2 = __commonJS({
46573
46648
  var client_js_1 = require_client();
46574
46649
  var transport_js_1 = require_transport();
46575
46650
  var sandbox_js_1 = require_sandbox();
46651
+ var error_utils_js_1 = require_error_utils();
46576
46652
  var LOCK_TIMEOUT_MS = 1e4;
46577
46653
  var LOCK_RETRY_INTERVAL_MS = 100;
46578
46654
  var LOCK_STALE_THRESHOLD_MS = 3e4;
46579
46655
  var CLIENT_VERSION = require_package3().version;
46580
- function toErrorMsg(err) {
46581
- return err instanceof Error ? err.message : String(err);
46582
- }
46583
46656
  var DaemonClient = class {
46584
46657
  projectDir;
46585
46658
  logger;
@@ -46945,7 +47018,7 @@ var require_daemon_client2 = __commonJS({
46945
47018
  } catch (err) {
46946
47019
  logger.debug("Graceful stop failed, falling back to SIGKILL", {
46947
47020
  pid: info.pid,
46948
- error: toErrorMsg(err)
47021
+ error: (0, error_utils_js_1.toErrorMessage)(err)
46949
47022
  });
46950
47023
  }
46951
47024
  }
@@ -46954,7 +47027,7 @@ var require_daemon_client2 = __commonJS({
46954
47027
  logger.info("Killed daemon", { pid: info.pid, projectDir: info.projectDir });
46955
47028
  results.push({ projectDir: info.projectDir, pid: info.pid, killed: true });
46956
47029
  } catch (err) {
46957
- const msg = toErrorMsg(err);
47030
+ const msg = (0, error_utils_js_1.toErrorMessage)(err);
46958
47031
  logger.warn("Failed to kill daemon", { pid: info.pid, error: msg });
46959
47032
  results.push({ projectDir: info.projectDir, pid: info.pid, killed: false, error: msg });
46960
47033
  }
@@ -46966,7 +47039,7 @@ var require_daemon_client2 = __commonJS({
46966
47039
  });
46967
47040
  }
46968
47041
  } catch (err) {
46969
- logger.warn("Invalid PID file, removing", { pidFile, error: toErrorMsg(err) });
47042
+ logger.warn("Invalid PID file, removing", { pidFile, error: (0, error_utils_js_1.toErrorMessage)(err) });
46970
47043
  await promises_12.default.unlink(pidPath).catch(() => {
46971
47044
  });
46972
47045
  }
@@ -46987,7 +47060,7 @@ var require_daemon_client2 = __commonJS({
46987
47060
  });
46988
47061
  } catch (err) {
46989
47062
  logger.warn("Failed to run ps \u2014 cannot detect zombie daemons", {
46990
- error: toErrorMsg(err)
47063
+ error: (0, error_utils_js_1.toErrorMessage)(err)
46991
47064
  });
46992
47065
  return [];
46993
47066
  }
@@ -47048,7 +47121,7 @@ var require_daemon_client2 = __commonJS({
47048
47121
  logger.info("Killed zombie daemon", { pid: zombie.pid, command: zombie.command });
47049
47122
  results.push({ projectDir: "unknown", pid: zombie.pid, killed: true });
47050
47123
  } catch (err) {
47051
- const msg = toErrorMsg(err);
47124
+ const msg = (0, error_utils_js_1.toErrorMessage)(err);
47052
47125
  logger.warn("Failed to kill zombie daemon", { pid: zombie.pid, error: msg });
47053
47126
  results.push({ projectDir: "unknown", pid: zombie.pid, killed: false, error: msg });
47054
47127
  }
@@ -47100,60 +47173,94 @@ var require_gitignore = __commonJS({
47100
47173
  };
47101
47174
  })();
47102
47175
  Object.defineProperty(exports2, "__esModule", { value: true });
47103
- exports2.GITIGNORE_ENTRIES = exports2.SIDEKICK_SECTION_END = exports2.SIDEKICK_SECTION_START = void 0;
47176
+ exports2.GITIGNORE_ENTRIES = exports2.SIDEKICK_GITIGNORE_HEADER = exports2.SIDEKICK_SECTION_END = exports2.SIDEKICK_SECTION_START = void 0;
47104
47177
  exports2.installGitignoreSection = installGitignoreSection;
47105
- exports2.removeGitignoreSection = removeGitignoreSection;
47106
47178
  exports2.detectGitignoreStatus = detectGitignoreStatus;
47179
+ exports2.removeGitignoreSection = removeGitignoreSection;
47180
+ exports2.detectLegacyGitignoreSection = detectLegacyGitignoreSection;
47181
+ exports2.removeLegacyGitignoreSection = removeLegacyGitignoreSection;
47107
47182
  var fs = __importStar(require("node:fs/promises"));
47108
47183
  var path = __importStar(require("node:path"));
47109
47184
  exports2.SIDEKICK_SECTION_START = "# >>> sidekick";
47110
47185
  exports2.SIDEKICK_SECTION_END = "# <<< sidekick";
47186
+ exports2.SIDEKICK_GITIGNORE_HEADER = "# Sidekick \u2014 managed file, do not edit manually";
47111
47187
  exports2.GITIGNORE_ENTRIES = [
47112
- ".sidekick/logs/",
47113
- ".sidekick/sessions/",
47114
- ".sidekick/state/",
47115
- ".sidekick/setup-status.json",
47116
- ".sidekick/.env",
47117
- ".sidekick/.env.local",
47118
- ".sidekick/sidekick*.pid",
47119
- ".sidekick/sidekick*.token",
47120
- ".sidekick/*.local.yaml"
47188
+ "logs/",
47189
+ "sessions/",
47190
+ "state/",
47191
+ "setup-status.json",
47192
+ ".env",
47193
+ ".env.local",
47194
+ "sidekick*.pid",
47195
+ "sidekick*.token",
47196
+ "*.local.yaml"
47121
47197
  ];
47122
47198
  async function installGitignoreSection(projectDir) {
47123
- const gitignorePath = path.join(projectDir, ".gitignore");
47124
- let content = "";
47199
+ let status;
47125
47200
  try {
47126
- content = await fs.readFile(gitignorePath, "utf-8");
47201
+ status = await detectGitignoreStatus(projectDir);
47127
47202
  } catch (err) {
47128
- if (err.code !== "ENOENT") {
47129
- return { status: "error", error: `Failed to read .gitignore: ${err.message}` };
47130
- }
47203
+ return { status: "error", error: `Failed to check gitignore status: ${err.message}` };
47131
47204
  }
47132
- const status = await detectGitignoreStatus(projectDir);
47133
47205
  if (status === "installed") {
47134
47206
  return { status: "already-installed" };
47135
47207
  }
47136
- if (status === "incomplete") {
47137
- await removeGitignoreSection(projectDir);
47138
- try {
47139
- content = await fs.readFile(gitignorePath, "utf-8");
47140
- } catch {
47141
- content = "";
47142
- }
47208
+ const sidekickDir = path.join(projectDir, ".sidekick");
47209
+ try {
47210
+ await fs.mkdir(sidekickDir, { recursive: true });
47211
+ } catch (err) {
47212
+ return { status: "error", error: `Failed to create .sidekick directory: ${err.message}` };
47143
47213
  }
47144
- const section = ["", exports2.SIDEKICK_SECTION_START, ...exports2.GITIGNORE_ENTRIES, exports2.SIDEKICK_SECTION_END].join("\n");
47145
- const newContent = content.trimEnd() + section + "\n";
47214
+ const content = [exports2.SIDEKICK_GITIGNORE_HEADER, ...exports2.GITIGNORE_ENTRIES].join("\n") + "\n";
47146
47215
  try {
47147
- await fs.writeFile(gitignorePath, newContent);
47216
+ await fs.writeFile(path.join(sidekickDir, ".gitignore"), content);
47148
47217
  return { status: "installed", entriesAdded: exports2.GITIGNORE_ENTRIES };
47149
47218
  } catch (err) {
47150
- return { status: "error", error: `Failed to write .gitignore: ${err.message}` };
47219
+ return { status: "error", error: `Failed to write .sidekick/.gitignore: ${err.message}` };
47151
47220
  }
47152
47221
  }
47222
+ async function detectGitignoreStatus(projectDir) {
47223
+ const sidekickGitignorePath = path.join(projectDir, ".sidekick", ".gitignore");
47224
+ try {
47225
+ const content = await fs.readFile(sidekickGitignorePath, "utf-8");
47226
+ const missingEntries = exports2.GITIGNORE_ENTRIES.filter((entry) => !content.includes(entry));
47227
+ return missingEntries.length === 0 ? "installed" : "incomplete";
47228
+ } catch (err) {
47229
+ if (err.code !== "ENOENT") {
47230
+ throw err;
47231
+ }
47232
+ }
47233
+ const hasLegacy = await detectLegacyGitignoreSection(projectDir);
47234
+ return hasLegacy ? "legacy" : "missing";
47235
+ }
47153
47236
  async function removeGitignoreSection(projectDir) {
47154
- const gitignorePath = path.join(projectDir, ".gitignore");
47237
+ let removed = false;
47238
+ try {
47239
+ await fs.unlink(path.join(projectDir, ".sidekick", ".gitignore"));
47240
+ removed = true;
47241
+ } catch (err) {
47242
+ if (err.code !== "ENOENT") {
47243
+ throw err;
47244
+ }
47245
+ }
47246
+ const legacyRemoved = await removeLegacyGitignoreSection(projectDir);
47247
+ return removed || legacyRemoved;
47248
+ }
47249
+ async function detectLegacyGitignoreSection(projectDir) {
47155
47250
  try {
47156
- const content = await fs.readFile(gitignorePath, "utf-8");
47251
+ const content = await fs.readFile(path.join(projectDir, ".gitignore"), "utf-8");
47252
+ return content.includes(exports2.SIDEKICK_SECTION_START);
47253
+ } catch (err) {
47254
+ if (err.code === "ENOENT") {
47255
+ return false;
47256
+ }
47257
+ throw err;
47258
+ }
47259
+ }
47260
+ async function removeLegacyGitignoreSection(projectDir) {
47261
+ const rootGitignorePath = path.join(projectDir, ".gitignore");
47262
+ try {
47263
+ const content = await fs.readFile(rootGitignorePath, "utf-8");
47157
47264
  const startIdx = content.indexOf(exports2.SIDEKICK_SECTION_START);
47158
47265
  const endIdx = content.indexOf(exports2.SIDEKICK_SECTION_END);
47159
47266
  if (startIdx === -1 || endIdx === -1 || endIdx < startIdx) {
@@ -47165,37 +47272,13 @@ var require_gitignore = __commonJS({
47165
47272
  const before = content.slice(0, lineStartIdx).trimEnd();
47166
47273
  const after = content.slice(actualEndIdx).trimStart();
47167
47274
  const newContent = before + (after ? "\n" + after : "") + "\n";
47168
- await fs.writeFile(gitignorePath, newContent);
47275
+ await fs.writeFile(rootGitignorePath, newContent);
47169
47276
  return true;
47170
- } catch {
47171
- return false;
47172
- }
47173
- }
47174
- async function detectGitignoreStatus(projectDir) {
47175
- const gitignorePath = path.join(projectDir, ".gitignore");
47176
- try {
47177
- const content = await fs.readFile(gitignorePath, "utf-8");
47178
- const hasStart = content.includes(exports2.SIDEKICK_SECTION_START);
47179
- const hasEnd = content.includes(exports2.SIDEKICK_SECTION_END);
47180
- if (!hasStart && !hasEnd) {
47181
- return "missing";
47182
- }
47183
- if (!hasStart || !hasEnd) {
47184
- return "incomplete";
47185
- }
47186
- const startIdx = content.indexOf(exports2.SIDEKICK_SECTION_START);
47187
- const endIdx = content.indexOf(exports2.SIDEKICK_SECTION_END);
47188
- if (endIdx <= startIdx) {
47189
- return "incomplete";
47190
- }
47191
- const sectionContent = content.slice(startIdx, endIdx + exports2.SIDEKICK_SECTION_END.length);
47192
- const missingEntries = exports2.GITIGNORE_ENTRIES.filter((entry) => !sectionContent.includes(entry));
47193
- if (missingEntries.length > 0) {
47194
- return "incomplete";
47277
+ } catch (err) {
47278
+ if (err.code === "ENOENT") {
47279
+ return false;
47195
47280
  }
47196
- return "installed";
47197
- } catch {
47198
- return "missing";
47281
+ throw err;
47199
47282
  }
47200
47283
  }
47201
47284
  }
@@ -47206,7 +47289,7 @@ var require_errors4 = __commonJS({
47206
47289
  "../shared-providers/dist/errors.js"(exports2) {
47207
47290
  "use strict";
47208
47291
  Object.defineProperty(exports2, "__esModule", { value: true });
47209
- exports2.TimeoutError = exports2.AuthError = exports2.RateLimitError = exports2.ProviderError = void 0;
47292
+ exports2.MalformedResponseError = exports2.TimeoutError = exports2.AuthError = exports2.RateLimitError = exports2.ProviderError = void 0;
47210
47293
  var ProviderError = class _ProviderError extends Error {
47211
47294
  provider;
47212
47295
  retryable;
@@ -47247,6 +47330,18 @@ var require_errors4 = __commonJS({
47247
47330
  }
47248
47331
  };
47249
47332
  exports2.TimeoutError = TimeoutError;
47333
+ var MalformedResponseError = class _MalformedResponseError extends ProviderError {
47334
+ code;
47335
+ providerMessage;
47336
+ constructor(provider, code, providerMessage, cause) {
47337
+ super(`Malformed response from ${provider}: ${code ?? "unknown"} - ${providerMessage ?? "no message"}`, provider, false, cause);
47338
+ this.name = "MalformedResponseError";
47339
+ this.code = code;
47340
+ this.providerMessage = providerMessage;
47341
+ Object.setPrototypeOf(this, _MalformedResponseError.prototype);
47342
+ }
47343
+ };
47344
+ exports2.MalformedResponseError = MalformedResponseError;
47250
47345
  }
47251
47346
  });
47252
47347
 
@@ -56225,6 +56320,7 @@ var require_base = __commonJS({
56225
56320
  model: response.model,
56226
56321
  durationMs,
56227
56322
  usage: response.usage,
56323
+ finishReason: response.finishReason,
56228
56324
  status: response.rawResponse.status,
56229
56325
  contentLength: response.content.length
56230
56326
  });
@@ -56272,6 +56368,7 @@ var require_openai_native = __commonJS({
56272
56368
  maxTokens;
56273
56369
  providerAllowlist;
56274
56370
  providerBlocklist;
56371
+ reasoning;
56275
56372
  constructor(config, logger) {
56276
56373
  super(logger);
56277
56374
  this.id = config.baseURL?.includes("openrouter") ? "openrouter" : "openai";
@@ -56280,6 +56377,7 @@ var require_openai_native = __commonJS({
56280
56377
  this.maxTokens = config.maxTokens;
56281
56378
  this.providerAllowlist = config.providerAllowlist;
56282
56379
  this.providerBlocklist = config.providerBlocklist;
56380
+ this.reasoning = config.reasoning;
56283
56381
  this.client = new openai_1.default({
56284
56382
  apiKey: config.apiKey,
56285
56383
  baseURL: config.baseURL,
@@ -56295,6 +56393,7 @@ var require_openai_native = __commonJS({
56295
56393
  maxTokens: this.maxTokens,
56296
56394
  providerAllowlist: this.providerAllowlist,
56297
56395
  providerBlocklist: this.providerBlocklist,
56396
+ reasoning: this.reasoning,
56298
56397
  apiKey: this.redactApiKey(config.apiKey)
56299
56398
  });
56300
56399
  }
@@ -56312,6 +56411,7 @@ var require_openai_native = __commonJS({
56312
56411
  }
56313
56412
  } : void 0;
56314
56413
  const providerRouting = this.buildProviderRouting();
56414
+ const reasoningParam = this.buildReasoningParam();
56315
56415
  const completion = await this.client.chat.completions.create({
56316
56416
  model: request.model ?? this.defaultModel,
56317
56417
  messages,
@@ -56319,8 +56419,13 @@ var require_openai_native = __commonJS({
56319
56419
  max_tokens: this.maxTokens,
56320
56420
  response_format: responseFormat,
56321
56421
  ...providerRouting,
56422
+ ...reasoningParam,
56322
56423
  ...request.additionalParams
56323
56424
  });
56425
+ if (!completion.choices || completion.choices.length === 0) {
56426
+ const errorPayload = completion.error;
56427
+ throw new errors_1.MalformedResponseError(this.id, errorPayload?.code, errorPayload?.message);
56428
+ }
56324
56429
  const response = {
56325
56430
  content: completion.choices[0]?.message?.content ?? "",
56326
56431
  model: completion.model,
@@ -56328,6 +56433,7 @@ var require_openai_native = __commonJS({
56328
56433
  inputTokens: completion.usage.prompt_tokens,
56329
56434
  outputTokens: completion.usage.completion_tokens
56330
56435
  } : void 0,
56436
+ finishReason: completion.choices[0]?.finish_reason ?? void 0,
56331
56437
  rawResponse: {
56332
56438
  status: 200,
56333
56439
  body: JSON.stringify(completion)
@@ -56363,7 +56469,25 @@ var require_openai_native = __commonJS({
56363
56469
  }
56364
56470
  return { provider: providerObj };
56365
56471
  }
56472
+ /**
56473
+ * Build OpenRouter reasoning param object.
56474
+ * Returns empty object if reasoning is unset or provider is not OpenRouter.
56475
+ * Maps `reasoning?: boolean` to OpenRouter's `reasoning: { enabled: <bool> }`.
56476
+ * @see https://openrouter.ai/docs/use-cases/reasoning-tokens
56477
+ */
56478
+ buildReasoningParam() {
56479
+ if (this.id !== "openrouter") {
56480
+ return {};
56481
+ }
56482
+ if (this.reasoning === void 0) {
56483
+ return {};
56484
+ }
56485
+ return { reasoning: { enabled: this.reasoning } };
56486
+ }
56366
56487
  mapError(error) {
56488
+ if (error instanceof errors_1.ProviderError) {
56489
+ return error;
56490
+ }
56367
56491
  if (error instanceof openai_1.default.APIError) {
56368
56492
  if (error.status === 401 || error.status === 403) {
56369
56493
  return new errors_1.AuthError(this.id, error);
@@ -56457,7 +56581,13 @@ var require_claude_cli_spawn = __commonJS({
56457
56581
  });
56458
56582
  const child = (0, node_child_process_1.spawn)(cliPath, args, {
56459
56583
  cwd,
56460
- stdio: ["pipe", "pipe", "pipe"]
56584
+ stdio: ["pipe", "pipe", "pipe"],
56585
+ // Recursion guard: Sidekick's own Claude Code hooks fire inside any
56586
+ // `claude -p` subprocess we spawn. Without this flag, the subprocess
56587
+ // hook handler would dispatch to the daemon, trigger another LLM call,
56588
+ // spawn another subprocess, and so on. handleHookCommand short-circuits
56589
+ // when SIDEKICK_SUBPROCESS=1 is set. See packages/sidekick-cli/src/commands/hook.ts.
56590
+ env: { ...process.env, SIDEKICK_SUBPROCESS: "1" }
56461
56591
  });
56462
56592
  let stdout = "";
56463
56593
  let stderr = "";
@@ -56519,6 +56649,31 @@ var require_claude_cli_spawn = __commonJS({
56519
56649
  }
56520
56650
  });
56521
56651
 
56652
+ // ../shared-providers/dist/providers/anthropic-stop-reason.js
56653
+ var require_anthropic_stop_reason = __commonJS({
56654
+ "../shared-providers/dist/providers/anthropic-stop-reason.js"(exports2) {
56655
+ "use strict";
56656
+ Object.defineProperty(exports2, "__esModule", { value: true });
56657
+ exports2.mapAnthropicStopReason = mapAnthropicStopReason;
56658
+ function mapAnthropicStopReason(stopReason) {
56659
+ if (!stopReason)
56660
+ return void 0;
56661
+ switch (stopReason) {
56662
+ case "end_turn":
56663
+ return "stop";
56664
+ case "max_tokens":
56665
+ return "length";
56666
+ case "stop_sequence":
56667
+ return "stop";
56668
+ case "tool_use":
56669
+ return "tool_calls";
56670
+ default:
56671
+ return stopReason;
56672
+ }
56673
+ }
56674
+ }
56675
+ });
56676
+
56522
56677
  // ../shared-providers/dist/providers/anthropic-cli.js
56523
56678
  var require_anthropic_cli = __commonJS({
56524
56679
  "../shared-providers/dist/providers/anthropic-cli.js"(exports2) {
@@ -56527,6 +56682,7 @@ var require_anthropic_cli = __commonJS({
56527
56682
  exports2.AnthropicCliProvider = void 0;
56528
56683
  var base_1 = require_base();
56529
56684
  var claude_cli_spawn_1 = require_claude_cli_spawn();
56685
+ var anthropic_stop_reason_1 = require_anthropic_stop_reason();
56530
56686
  var AnthropicCliProvider = class extends base_1.AbstractProvider {
56531
56687
  id = "claude-cli";
56532
56688
  defaultModel;
@@ -56588,6 +56744,7 @@ var require_anthropic_cli = __commonJS({
56588
56744
  inputTokens: parsed.usage.input_tokens ?? 0,
56589
56745
  outputTokens: parsed.usage.output_tokens ?? 0
56590
56746
  } : void 0,
56747
+ finishReason: (0, anthropic_stop_reason_1.mapAnthropicStopReason)(parsed.stop_reason),
56591
56748
  rawResponse: {
56592
56749
  status: 200,
56593
56750
  body: stdout
@@ -56859,6 +57016,7 @@ var require_openai_emulator = __commonJS({
56859
57016
  inputTokens,
56860
57017
  outputTokens
56861
57018
  },
57019
+ finishReason: "stop",
56862
57020
  rawResponse: {
56863
57021
  status: 200,
56864
57022
  body: JSON.stringify(rawBody)
@@ -56913,6 +57071,7 @@ var require_openrouter_emulator = __commonJS({
56913
57071
  inputTokens,
56914
57072
  outputTokens
56915
57073
  },
57074
+ finishReason: "stop",
56916
57075
  rawResponse: {
56917
57076
  status: 200,
56918
57077
  body: JSON.stringify(rawBody)
@@ -56933,6 +57092,7 @@ var require_claude_cli_emulator = __commonJS({
56933
57092
  var node_child_process_1 = require("node:child_process");
56934
57093
  var node_path_1 = require("node:path");
56935
57094
  var base_1 = require_base();
57095
+ var anthropic_stop_reason_1 = require_anthropic_stop_reason();
56936
57096
  var EMULATOR_SCRIPT = `#!/bin/bash
56937
57097
  # Claude CLI Emulator Script
56938
57098
  STATE_FILE="\${SIDEKICK_EMULATOR_STATE_PATH:-.sidekick/emulator-state/call-counts.json}"
@@ -57020,6 +57180,7 @@ echo "{\\"content\\":\\"\${CONTENT}\\",\\"message\\":\\"\${CONTENT}\\",\\"model\
57020
57180
  inputTokens,
57021
57181
  outputTokens
57022
57182
  },
57183
+ finishReason: (0, anthropic_stop_reason_1.mapAnthropicStopReason)(parsed.stop_reason),
57023
57184
  rawResponse: {
57024
57185
  status: 0,
57025
57186
  // Exit code
@@ -57156,7 +57317,8 @@ var require_factory = __commonJS({
57156
57317
  temperature: this.config.temperature,
57157
57318
  maxTokens: this.config.maxTokens,
57158
57319
  providerAllowlist: this.config.providerAllowlist,
57159
- providerBlocklist: this.config.providerBlocklist
57320
+ providerBlocklist: this.config.providerBlocklist,
57321
+ reasoning: this.config.reasoning
57160
57322
  };
57161
57323
  return new openai_native_1.OpenAINativeProvider(openrouterConfig, this.logger);
57162
57324
  }
@@ -57333,7 +57495,9 @@ var require_profile_factory = __commonJS({
57333
57495
  maxTokens: profile.maxTokens,
57334
57496
  // OpenRouter-specific provider routing
57335
57497
  providerAllowlist: profile.providerAllowlist ? [...profile.providerAllowlist] : void 0,
57336
- providerBlocklist: profile.providerBlocklist ? [...profile.providerBlocklist] : void 0
57498
+ providerBlocklist: profile.providerBlocklist ? [...profile.providerBlocklist] : void 0,
57499
+ // OpenRouter-specific reasoning toggle
57500
+ reasoning: profile.reasoning
57337
57501
  }, this.logger);
57338
57502
  return factory.create();
57339
57503
  }
@@ -57388,7 +57552,7 @@ var require_dist3 = __commonJS({
57388
57552
  "../shared-providers/dist/index.js"(exports2) {
57389
57553
  "use strict";
57390
57554
  Object.defineProperty(exports2, "__esModule", { value: true });
57391
- exports2.spawnClaudeCli = exports2.ClaudeCliEmulator = exports2.OpenRouterEmulator = exports2.OpenAIEmulator = exports2.EmulatorStateManager = exports2.AbstractEmulator = exports2.validateOpenAIKey = exports2.validateOpenRouterKey = exports2.AbstractProvider = exports2.AnthropicCliProvider = exports2.OpenAINativeProvider = exports2.FallbackProvider = exports2.ProfileProviderFactory = exports2.ProviderFactory = exports2.TimeoutError = exports2.AuthError = exports2.RateLimitError = exports2.ProviderError = void 0;
57555
+ exports2.spawnClaudeCli = exports2.ClaudeCliEmulator = exports2.OpenRouterEmulator = exports2.OpenAIEmulator = exports2.EmulatorStateManager = exports2.AbstractEmulator = exports2.validateOpenAIKey = exports2.validateOpenRouterKey = exports2.AbstractProvider = exports2.AnthropicCliProvider = exports2.OpenAINativeProvider = exports2.FallbackProvider = exports2.ProfileProviderFactory = exports2.ProviderFactory = exports2.MalformedResponseError = exports2.TimeoutError = exports2.AuthError = exports2.RateLimitError = exports2.ProviderError = void 0;
57392
57556
  var errors_1 = require_errors4();
57393
57557
  Object.defineProperty(exports2, "ProviderError", { enumerable: true, get: function() {
57394
57558
  return errors_1.ProviderError;
@@ -57402,6 +57566,9 @@ var require_dist3 = __commonJS({
57402
57566
  Object.defineProperty(exports2, "TimeoutError", { enumerable: true, get: function() {
57403
57567
  return errors_1.TimeoutError;
57404
57568
  } });
57569
+ Object.defineProperty(exports2, "MalformedResponseError", { enumerable: true, get: function() {
57570
+ return errors_1.MalformedResponseError;
57571
+ } });
57405
57572
  var factory_1 = require_factory();
57406
57573
  Object.defineProperty(exports2, "ProviderFactory", { enumerable: true, get: function() {
57407
57574
  return factory_1.ProviderFactory;
@@ -57691,6 +57858,7 @@ var require_plugin_detector = __commonJS({
57691
57858
  var crypto2 = __importStar(require("node:crypto"));
57692
57859
  var node_child_process_1 = require("node:child_process");
57693
57860
  var api_key_detector_js_1 = require_api_key_detector();
57861
+ var error_utils_js_1 = require_error_utils();
57694
57862
  function isSidekickStatuslineCommand(command) {
57695
57863
  return command?.toLowerCase().includes("sidekick") ?? false;
57696
57864
  }
@@ -57820,7 +57988,7 @@ var require_plugin_detector = __commonJS({
57820
57988
  return result;
57821
57989
  } catch (err) {
57822
57990
  logger?.warn("Failed to parse plugin list JSON", {
57823
- error: err instanceof Error ? err.message : String(err)
57991
+ error: (0, error_utils_js_1.toErrorMessage)(err)
57824
57992
  });
57825
57993
  logger?.info("Plugin detection completed", { result: "error" });
57826
57994
  return "error";
@@ -58024,7 +58192,16 @@ var require_doctor_engine = __commonJS({
58024
58192
  const expectedUserStatus = (0, api_key_detector_js_1.buildUserApiKeyStatus)(detection);
58025
58193
  const currentUserEntry = currentUserStatus.apiKeys[keyName];
58026
58194
  const currentStatus = typeof currentUserEntry === "object" ? currentUserEntry.status : currentUserEntry ?? "missing";
58027
- if (currentStatus !== "not-required" && (0, api_key_detector_js_1.toScopeStatus)(currentStatus) !== (0, api_key_detector_js_1.toScopeStatus)(expectedUserStatus.status)) {
58195
+ if (currentStatus === "not-required")
58196
+ continue;
58197
+ const isLegacyString = typeof currentUserEntry === "string";
58198
+ if (isLegacyString) {
58199
+ updatedUserApiKeys[keyName] = expectedUserStatus;
58200
+ userNeedsUpdate = true;
58201
+ } else if ((0, api_key_detector_js_1.toScopeStatus)(currentStatus) !== (0, api_key_detector_js_1.toScopeStatus)(expectedUserStatus.status)) {
58202
+ updatedUserApiKeys[keyName] = expectedUserStatus;
58203
+ userNeedsUpdate = true;
58204
+ } else if (typeof currentUserEntry === "object" && (currentUserEntry.used !== expectedUserStatus.used || JSON.stringify(currentUserEntry.scopes) !== JSON.stringify(expectedUserStatus.scopes))) {
58028
58205
  updatedUserApiKeys[keyName] = expectedUserStatus;
58029
58206
  userNeedsUpdate = true;
58030
58207
  }
@@ -58099,7 +58276,7 @@ var require_setup_status_service = __commonJS({
58099
58276
  };
58100
58277
  })();
58101
58278
  Object.defineProperty(exports2, "__esModule", { value: true });
58102
- exports2.SetupStatusService = exports2.LEGACY_USER_STATUS_FILENAME = exports2.PROJECT_STATUS_FILENAME = exports2.USER_STATUS_FILENAME = void 0;
58279
+ exports2.SetupStatusService = exports2.PROJECT_STATUS_FILENAME = exports2.USER_STATUS_FILENAME = void 0;
58103
58280
  exports2.createSetupStatusService = createSetupStatusService;
58104
58281
  var fs = __importStar(require("node:fs/promises"));
58105
58282
  var path = __importStar(require("node:path"));
@@ -58111,7 +58288,6 @@ var require_setup_status_service = __commonJS({
58111
58288
  var doctor_engine_js_1 = require_doctor_engine();
58112
58289
  exports2.USER_STATUS_FILENAME = "user-setup-status.json";
58113
58290
  exports2.PROJECT_STATUS_FILENAME = "setup-status.json";
58114
- exports2.LEGACY_USER_STATUS_FILENAME = exports2.PROJECT_STATUS_FILENAME;
58115
58291
  var SetupStatusService = class {
58116
58292
  projectDir;
58117
58293
  homeDir;
@@ -58125,10 +58301,6 @@ var require_setup_status_service = __commonJS({
58125
58301
  get userStatusPath() {
58126
58302
  return path.join(this.homeDir, ".sidekick", exports2.USER_STATUS_FILENAME);
58127
58303
  }
58128
- /** Legacy path for migration: old user-scope file that collided with project-scope */
58129
- get legacyUserStatusPath() {
58130
- return path.join(this.homeDir, ".sidekick", exports2.LEGACY_USER_STATUS_FILENAME);
58131
- }
58132
58304
  get projectStatusPath() {
58133
58305
  return path.join(this.projectDir, ".sidekick", exports2.PROJECT_STATUS_FILENAME);
58134
58306
  }
@@ -58162,7 +58334,7 @@ var require_setup_status_service = __commonJS({
58162
58334
  return parsed.data;
58163
58335
  } catch (err) {
58164
58336
  if (err.code === "ENOENT") {
58165
- return this.migrateFromLegacyUserStatus();
58337
+ return null;
58166
58338
  }
58167
58339
  if (err instanceof SyntaxError) {
58168
58340
  this.logger?.warn(`Corrupt ${exports2.USER_STATUS_FILENAME}, treating as missing`, {
@@ -58174,54 +58346,6 @@ var require_setup_status_service = __commonJS({
58174
58346
  throw err;
58175
58347
  }
58176
58348
  }
58177
- /**
58178
- * Migration: read user status from the legacy `setup-status.json` location,
58179
- * write it to the new `user-setup-status.json`, and remove the old file.
58180
- *
58181
- * Only migrates if the legacy file contains valid UserSetupStatus data
58182
- * (not project-format data that may have been written by the collision bug).
58183
- */
58184
- async migrateFromLegacyUserStatus() {
58185
- try {
58186
- const legacyContent = await fs.readFile(this.legacyUserStatusPath, "utf-8");
58187
- const parsed = types_1.UserSetupStatusSchema.safeParse(JSON.parse(legacyContent));
58188
- if (!parsed.success) {
58189
- this.logger?.debug("Legacy user status file exists but is not valid user format, skipping migration", {
58190
- path: this.legacyUserStatusPath
58191
- });
58192
- return null;
58193
- }
58194
- this.logger?.info("Migrating user status from legacy location", {
58195
- from: this.legacyUserStatusPath,
58196
- to: this.userStatusPath
58197
- });
58198
- await this.writeUserStatus(parsed.data);
58199
- try {
58200
- await fs.unlink(this.legacyUserStatusPath);
58201
- } catch (unlinkErr) {
58202
- if (unlinkErr.code !== "ENOENT") {
58203
- this.logger?.warn("Migrated user status but failed to remove legacy file", {
58204
- path: this.legacyUserStatusPath,
58205
- error: unlinkErr instanceof Error ? unlinkErr.message : String(unlinkErr)
58206
- });
58207
- }
58208
- }
58209
- this.logger?.info("Legacy user status migration complete");
58210
- return parsed.data;
58211
- } catch (err) {
58212
- if (err.code === "ENOENT") {
58213
- return null;
58214
- }
58215
- if (err instanceof SyntaxError) {
58216
- this.logger?.warn(`Corrupt legacy ${exports2.LEGACY_USER_STATUS_FILENAME}, treating as missing`, {
58217
- path: this.legacyUserStatusPath,
58218
- error: err.message
58219
- });
58220
- return null;
58221
- }
58222
- throw err;
58223
- }
58224
- }
58225
58349
  async getProjectStatus() {
58226
58350
  if (path.resolve(this.projectDir) === path.resolve(this.homeDir)) {
58227
58351
  this.logger?.debug("Skipping project status read: projectDir is the home directory", {
@@ -58602,6 +58726,7 @@ var require_staging_service = __commonJS({
58602
58726
  var structured_logging_1 = require_structured_logging();
58603
58727
  var errors_js_1 = require_errors6();
58604
58728
  var staging_paths_js_1 = require_staging_paths();
58729
+ var error_utils_js_1 = require_error_utils();
58605
58730
  var StagingServiceCore = class {
58606
58731
  options;
58607
58732
  constructor(options) {
@@ -58705,7 +58830,7 @@ var require_staging_service = __commonJS({
58705
58830
  hookName,
58706
58831
  reminderName,
58707
58832
  path: reminderPath,
58708
- error: err instanceof Error ? err.message : String(err)
58833
+ error: (0, error_utils_js_1.toErrorMessage)(err)
58709
58834
  });
58710
58835
  return null;
58711
58836
  }
@@ -58736,7 +58861,7 @@ var require_staging_service = __commonJS({
58736
58861
  }
58737
58862
  this.options.logger.warn("Skipping invalid reminder file", {
58738
58863
  path: reminderPath,
58739
- error: err instanceof Error ? err.message : String(err)
58864
+ error: (0, error_utils_js_1.toErrorMessage)(err)
58740
58865
  });
58741
58866
  }
58742
58867
  }
@@ -58797,7 +58922,7 @@ var require_staging_service = __commonJS({
58797
58922
  }
58798
58923
  this.options.logger.warn("Skipping invalid consumed reminder file", {
58799
58924
  path: reminderPath,
58800
- error: err instanceof Error ? err.message : String(err)
58925
+ error: (0, error_utils_js_1.toErrorMessage)(err)
58801
58926
  });
58802
58927
  }
58803
58928
  }
@@ -58949,6 +59074,7 @@ var require_handler_registry2 = __commonJS({
58949
59074
  exports2.HandlerRegistryImpl = void 0;
58950
59075
  var transcript_content_js_1 = require_transcript_content();
58951
59076
  var structured_logging_js_1 = require_structured_logging();
59077
+ var error_utils_js_1 = require_error_utils();
58952
59078
  var HandlerRegistryImpl = class {
58953
59079
  options;
58954
59080
  handlers = [];
@@ -59059,7 +59185,7 @@ var require_handler_registry2 = __commonJS({
59059
59185
  log.error("Handler execution failed", {
59060
59186
  handlerId: handler.id,
59061
59187
  hook,
59062
- error: err instanceof Error ? err.message : String(err)
59188
+ error: (0, error_utils_js_1.toErrorMessage)(err)
59063
59189
  });
59064
59190
  }
59065
59191
  }
@@ -59105,7 +59231,7 @@ var require_handler_registry2 = __commonJS({
59105
59231
  (0, structured_logging_js_1.logEvent)(this.options.logger, structured_logging_js_1.LogEvents.eventProcessed(logContext, { handlerId: handler.id, success: true }, { durationMs }));
59106
59232
  } catch (err) {
59107
59233
  const durationMs = Date.now() - startTime;
59108
- const errorMsg = err instanceof Error ? err.message : String(err);
59234
+ const errorMsg = (0, error_utils_js_1.toErrorMessage)(err);
59109
59235
  (0, structured_logging_js_1.logEvent)(this.options.logger, structured_logging_js_1.LogEvents.eventProcessed(logContext, { handlerId: handler.id, success: false }, { durationMs, error: errorMsg }));
59110
59236
  this.options.logger.error("Transcript handler failed", {
59111
59237
  handlerId: handler.id,
@@ -59536,6 +59662,7 @@ var require_state_service = __commonJS({
59536
59662
  var node_path_1 = require("node:path");
59537
59663
  var path_resolver_js_1 = require_path_resolver();
59538
59664
  var errors_js_1 = require_errors6();
59665
+ var error_utils_js_1 = require_error_utils();
59539
59666
  var errors_js_2 = require_errors6();
59540
59667
  Object.defineProperty(exports2, "StateNotFoundError", { enumerable: true, get: function() {
59541
59668
  return errors_js_2.StateNotFoundError;
@@ -59647,7 +59774,7 @@ var require_state_service = __commonJS({
59647
59774
  } catch (cleanupErr) {
59648
59775
  this.logger?.trace("Failed to cleanup temp file", {
59649
59776
  tmpPath,
59650
- error: cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr)
59777
+ error: (0, error_utils_js_1.toErrorMessage)(cleanupErr)
59651
59778
  });
59652
59779
  }
59653
59780
  throw err;
@@ -59773,7 +59900,7 @@ var require_state_service = __commonJS({
59773
59900
  } catch (err) {
59774
59901
  this.logger?.warn("Failed to preload state file", {
59775
59902
  file,
59776
- error: err instanceof Error ? err.message : String(err)
59903
+ error: (0, error_utils_js_1.toErrorMessage)(err)
59777
59904
  });
59778
59905
  }
59779
59906
  }
@@ -59799,7 +59926,7 @@ var require_state_service = __commonJS({
59799
59926
  this.logger?.warn("Corrupt state file detected", {
59800
59927
  path,
59801
59928
  reason,
59802
- error: error instanceof Error ? error.message : String(error)
59929
+ error: (0, error_utils_js_1.toErrorMessage)(error)
59803
59930
  });
59804
59931
  try {
59805
59932
  await fs.rename(path, bakPath);
@@ -59829,7 +59956,7 @@ var require_state_service = __commonJS({
59829
59956
  } catch (err) {
59830
59957
  this.logger?.warn("Failed to create dev mode backup", {
59831
59958
  path,
59832
- error: err instanceof Error ? err.message : String(err)
59959
+ error: (0, error_utils_js_1.toErrorMessage)(err)
59833
59960
  });
59834
59961
  }
59835
59962
  }
@@ -59892,12 +60019,17 @@ var require_typed_accessor = __commonJS({
59892
60019
  var SessionStateAccessor = class {
59893
60020
  stateService;
59894
60021
  descriptor;
59895
- constructor(stateService, descriptor) {
60022
+ journal;
60023
+ /** Descriptor filename without .json extension — used as journal file key */
60024
+ fileKey;
60025
+ constructor(stateService, descriptor, journal) {
59896
60026
  this.stateService = stateService;
59897
60027
  this.descriptor = descriptor;
60028
+ this.journal = journal;
59898
60029
  if (descriptor.scope !== "session") {
59899
60030
  throw new Error(`SessionStateAccessor requires a session-scoped descriptor, got: ${descriptor.scope}`);
59900
60031
  }
60032
+ this.fileKey = descriptor.filename.replace(/\.json$/, "");
59901
60033
  }
59902
60034
  /**
59903
60035
  * Read session state file.
@@ -59915,9 +60047,15 @@ var require_typed_accessor = __commonJS({
59915
60047
  */
59916
60048
  async write(sessionId, data) {
59917
60049
  const path = this.stateService.sessionStatePath(sessionId, this.descriptor.filename);
59918
- return this.stateService.write(path, data, this.descriptor.schema, {
60050
+ await this.stateService.write(path, data, this.descriptor.schema, {
59919
60051
  trackHistory: this.descriptor.trackHistory
59920
60052
  });
60053
+ if (this.journal) {
60054
+ try {
60055
+ await this.journal.appendIfChanged(sessionId, this.fileKey, data);
60056
+ } catch {
60057
+ }
60058
+ }
59921
60059
  }
59922
60060
  /**
59923
60061
  * Delete session state file.
@@ -59925,6 +60063,12 @@ var require_typed_accessor = __commonJS({
59925
60063
  async delete(sessionId) {
59926
60064
  const path = this.stateService.sessionStatePath(sessionId, this.descriptor.filename);
59927
60065
  await this.stateService.delete(path);
60066
+ if (this.journal) {
60067
+ try {
60068
+ await this.journal.appendDeletion(sessionId, this.fileKey);
60069
+ } catch {
60070
+ }
60071
+ }
59928
60072
  }
59929
60073
  /**
59930
60074
  * Get the path for a session state file.
@@ -60190,8 +60334,51 @@ var require_transcript_normalizer = __commonJS({
60190
60334
  exports2.parseUuid = parseUuid;
60191
60335
  exports2.renderTranscriptString = renderTranscriptString;
60192
60336
  var index_js_1 = require_state3();
60337
+ function buildRecapEntry(params) {
60338
+ const text = typeof params.rawText === "string" ? params.rawText.trim() : "";
60339
+ if (!text)
60340
+ return null;
60341
+ return {
60342
+ id: params.uuid ?? `line-${params.lineNumber}`,
60343
+ timestamp: new Date(params.timestamp ?? Date.now()),
60344
+ role: "system",
60345
+ type: "recap",
60346
+ content: text,
60347
+ metadata: {
60348
+ provider: "claude",
60349
+ lineNumber: params.lineNumber,
60350
+ recapSource: params.recapSource,
60351
+ leafUuid: params.leafUuid
60352
+ }
60353
+ };
60354
+ }
60193
60355
  function normalizeEntry(rawEntry, lineNumber) {
60194
60356
  const entryType = rawEntry.type;
60357
+ if (entryType === "summary") {
60358
+ const raw = rawEntry;
60359
+ const recap = buildRecapEntry({
60360
+ rawText: raw.summary,
60361
+ uuid: raw.uuid,
60362
+ timestamp: raw.timestamp,
60363
+ lineNumber,
60364
+ recapSource: "compaction",
60365
+ leafUuid: typeof raw.leafUuid === "string" ? raw.leafUuid : void 0
60366
+ });
60367
+ return recap ? [recap] : null;
60368
+ }
60369
+ if (entryType === "system") {
60370
+ const raw = rawEntry;
60371
+ if (raw.subtype !== "away_summary")
60372
+ return null;
60373
+ const recap = buildRecapEntry({
60374
+ rawText: raw.content,
60375
+ uuid: raw.uuid,
60376
+ timestamp: raw.timestamp,
60377
+ lineNumber,
60378
+ recapSource: "away"
60379
+ });
60380
+ return recap ? [recap] : null;
60381
+ }
60195
60382
  if (entryType !== "user" && entryType !== "assistant") {
60196
60383
  return null;
60197
60384
  }
@@ -60325,6 +60512,9 @@ var require_transcript_normalizer = __commonJS({
60325
60512
  return `[${timestamp}] ${role} TOOL_USE: ${String(toolContent.name)}`;
60326
60513
  } else if (type === "tool_result") {
60327
60514
  return `[${timestamp}] ${role} TOOL_RESULT`;
60515
+ } else if (type === "recap") {
60516
+ const content = typeof entry.content === "string" ? entry.content : "";
60517
+ return `[${timestamp}] RECAP: ${content}`;
60328
60518
  }
60329
60519
  return `[${timestamp}] ${role}: ${JSON.stringify(entry.content)}`;
60330
60520
  }).join("\n");
@@ -60343,6 +60533,7 @@ var require_transcript_excerpt_builder = __commonJS({
60343
60533
  exports2.extractTextContent = extractTextContent;
60344
60534
  exports2.getRawContentString = getRawContentString;
60345
60535
  var transcript_helpers_js_1 = require_transcript_helpers();
60536
+ var error_utils_js_1 = require_error_utils();
60346
60537
  function getBufferedEntries(buffer, head, count, bufferSize) {
60347
60538
  if (count === 0)
60348
60539
  return [];
@@ -60397,7 +60588,7 @@ var require_transcript_excerpt_builder = __commonJS({
60397
60588
  };
60398
60589
  } catch (err) {
60399
60590
  logger.error("Failed to extract transcript excerpt from buffer", {
60400
- error: err instanceof Error ? err.message : String(err)
60591
+ error: (0, error_utils_js_1.toErrorMessage)(err)
60401
60592
  });
60402
60593
  return {
60403
60594
  content: "",
@@ -60458,6 +60649,14 @@ var require_transcript_excerpt_builder = __commonJS({
60458
60649
  return null;
60459
60650
  }
60460
60651
  return `[SESSION_HINT]: ${entry.summary ?? ""}`;
60652
+ case "system": {
60653
+ if (entry.subtype !== "away_summary")
60654
+ return null;
60655
+ const content = entry.content;
60656
+ if (typeof content !== "string" || !content.trim())
60657
+ return null;
60658
+ return `[SESSION_RECAP]: ${content}`;
60659
+ }
60461
60660
  default:
60462
60661
  return null;
60463
60662
  }
@@ -63316,6 +63515,7 @@ var require_instrumented_llm_provider = __commonJS({
63316
63515
  var node_path_1 = require("node:path");
63317
63516
  var yaml_1 = __importDefault2(require_dist2());
63318
63517
  var types_1 = require_dist();
63518
+ var error_utils_js_1 = require_error_utils();
63319
63519
  var STATE_FILE = "llm-metrics.json";
63320
63520
  var DEFAULT_DEBOUNCE_MS = 500;
63321
63521
  function hasFallbackTracking(provider) {
@@ -63366,7 +63566,7 @@ var require_instrumented_llm_provider = __commonJS({
63366
63566
  }
63367
63567
  } catch (err) {
63368
63568
  this.config.logger.warn("Failed to load LLM metrics, starting fresh", {
63369
- error: err instanceof Error ? err.message : String(err)
63569
+ error: (0, error_utils_js_1.toErrorMessage)(err)
63370
63570
  });
63371
63571
  }
63372
63572
  }
@@ -63453,7 +63653,7 @@ var require_instrumented_llm_provider = __commonJS({
63453
63653
  this.config.logger.debug("Debug dump written", { path: basePath });
63454
63654
  } catch (dumpError) {
63455
63655
  this.config.logger.warn("Failed to write debug dump", {
63456
- error: dumpError instanceof Error ? dumpError.message : String(dumpError)
63656
+ error: (0, error_utils_js_1.toErrorMessage)(dumpError)
63457
63657
  });
63458
63658
  }
63459
63659
  }
@@ -63678,7 +63878,7 @@ var require_instrumented_llm_provider = __commonJS({
63678
63878
  });
63679
63879
  } catch (err) {
63680
63880
  this.config.logger.warn("Failed to persist LLM metrics", {
63681
- error: err instanceof Error ? err.message : String(err)
63881
+ error: (0, error_utils_js_1.toErrorMessage)(err)
63682
63882
  });
63683
63883
  }
63684
63884
  }
@@ -63954,6 +64154,7 @@ var require_daemon_health = __commonJS({
63954
64154
  var fs = __importStar(require("node:fs/promises"));
63955
64155
  var node_path_1 = require("node:path");
63956
64156
  var types_1 = require_dist();
64157
+ var error_utils_js_1 = require_error_utils();
63957
64158
  function healthFilePath(projectDir) {
63958
64159
  return (0, node_path_1.join)(projectDir, ".sidekick", "state", "daemon-health.json");
63959
64160
  }
@@ -64012,7 +64213,7 @@ var require_daemon_health = __commonJS({
64012
64213
  logger.warn("Failed to write daemon health", {
64013
64214
  from,
64014
64215
  to,
64015
- error: err instanceof Error ? err.message : String(err)
64216
+ error: (0, error_utils_js_1.toErrorMessage)(err)
64016
64217
  });
64017
64218
  return false;
64018
64219
  }
@@ -64099,6 +64300,7 @@ var require_user_profile_loader = __commonJS({
64099
64300
  var node_path_1 = require("node:path");
64100
64301
  var yaml_1 = require_dist2();
64101
64302
  var types_1 = require_dist();
64303
+ var error_utils_js_1 = require_error_utils();
64102
64304
  function loadUserProfile(options) {
64103
64305
  const home = options?.homeDir ?? (0, node_os_1.homedir)();
64104
64306
  const filePath = (0, node_path_1.join)(home, ".sidekick", "user.yaml");
@@ -64120,7 +64322,7 @@ var require_user_profile_loader = __commonJS({
64120
64322
  } catch (err) {
64121
64323
  options?.logger?.warn("Failed to read user profile", {
64122
64324
  path: filePath,
64123
- error: err instanceof Error ? err.message : String(err)
64325
+ error: (0, error_utils_js_1.toErrorMessage)(err)
64124
64326
  });
64125
64327
  return null;
64126
64328
  }
@@ -64187,9 +64389,9 @@ var require_dist4 = __commonJS({
64187
64389
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
64188
64390
  };
64189
64391
  Object.defineProperty(exports2, "__esModule", { value: true });
64190
- exports2.toScopeStatus = exports2.LEGACY_USER_STATUS_FILENAME = exports2.PROJECT_STATUS_FILENAME = exports2.USER_STATUS_FILENAME = exports2.createSetupStatusService = exports2.SetupStatusService = exports2.DaemonClient = exports2.findZombieDaemons = exports2.killZombieDaemons = exports2.killAllDaemons = exports2.SessionLogWriter = exports2.setSessionLogWriter = exports2.logEvent = exports2.LogEvents = exports2.DEFAULT_MAX_FILES = exports2.DEFAULT_ROTATE_SIZE_BYTES = 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;
64191
- 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 = 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.runDoctorCheck = exports2.detectPluginLiveness = exports2.detectPluginInstallation = exports2.detectActualStatusline = exports2.spawnWithTimeout = exports2.getDoctorTimeout = exports2.DOCTOR_TIMEOUTS = exports2.projectApiKeyStatusFromHealth = exports2.userApiKeyStatusFromHealth = exports2.buildProjectApiKeyStatus = exports2.buildUserApiKeyStatus = exports2.detectAllApiKeys = exports2.detectActualApiKey = exports2.readKeyFromEnvFile = exports2.determineOverallStatus = void 0;
64192
- exports2.CoalescingGuard = exports2.loadUserProfile = exports2.parseGitStatusOutput = exports2.getGitFileStatus = exports2.isInSandbox = exports2.updateDaemonHealth = exports2.readDaemonHealth = exports2.ProjectRegistryService = exports2.encodeProjectDir = 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 = void 0;
64392
+ exports2.PROJECT_STATUS_FILENAME = exports2.USER_STATUS_FILENAME = exports2.createSetupStatusService = exports2.SetupStatusService = exports2.DaemonClient = exports2.findZombieDaemons = exports2.killZombieDaemons = exports2.killAllDaemons = exports2.SessionLogWriter = exports2.setSessionLogWriter = exports2.logEvent = exports2.LogEvents = exports2.DEFAULT_MAX_FILES = exports2.DEFAULT_ROTATE_SIZE_BYTES = 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.isSubagentStopEvent = exports2.isSubagentStartEvent = 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;
64393
+ 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 = exports2.SessionScopedStagingService = exports2.StagingServiceCore = exports2.GITIGNORE_ENTRIES = exports2.SIDEKICK_GITIGNORE_HEADER = exports2.SIDEKICK_SECTION_END = exports2.SIDEKICK_SECTION_START = exports2.removeLegacyGitignoreSection = exports2.detectLegacyGitignoreSection = exports2.detectGitignoreStatus = exports2.removeGitignoreSection = exports2.installGitignoreSection = exports2.validateOpenAIKey = exports2.validateOpenRouterKey = exports2.runDoctorCheck = exports2.detectPluginLiveness = exports2.detectPluginInstallation = exports2.detectActualStatusline = exports2.spawnWithTimeout = exports2.getDoctorTimeout = exports2.DOCTOR_TIMEOUTS = exports2.projectApiKeyStatusFromHealth = exports2.userApiKeyStatusFromHealth = exports2.buildProjectApiKeyStatus = exports2.buildUserApiKeyStatus = exports2.detectAllApiKeys = exports2.detectActualApiKey = exports2.readKeyFromEnvFile = exports2.determineOverallStatus = exports2.toScopeStatus = void 0;
64394
+ exports2.CoalescingGuard = exports2.loadUserProfile = exports2.parseGitStatusOutput = exports2.getGitFileStatus = exports2.toErrorMessage = exports2.isInSandbox = exports2.updateDaemonHealth = exports2.readDaemonHealth = exports2.ProjectRegistryService = exports2.encodeProjectDir = 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 = void 0;
64193
64395
  var types_1 = require_dist();
64194
64396
  Object.defineProperty(exports2, "TaskTypes", { enumerable: true, get: function() {
64195
64397
  return types_1.TaskTypes;
@@ -64234,6 +64436,12 @@ var require_dist4 = __commonJS({
64234
64436
  Object.defineProperty(exports2, "isPreCompactEvent", { enumerable: true, get: function() {
64235
64437
  return types_2.isPreCompactEvent;
64236
64438
  } });
64439
+ Object.defineProperty(exports2, "isSubagentStartEvent", { enumerable: true, get: function() {
64440
+ return types_2.isSubagentStartEvent;
64441
+ } });
64442
+ Object.defineProperty(exports2, "isSubagentStopEvent", { enumerable: true, get: function() {
64443
+ return types_2.isSubagentStopEvent;
64444
+ } });
64237
64445
  __exportStar(require_assets(), exports2);
64238
64446
  var claude_paths_1 = require_claude_paths();
64239
64447
  Object.defineProperty(exports2, "encodeProjectPath", { enumerable: true, get: function() {
@@ -64354,9 +64562,6 @@ var require_dist4 = __commonJS({
64354
64562
  Object.defineProperty(exports2, "PROJECT_STATUS_FILENAME", { enumerable: true, get: function() {
64355
64563
  return setup_status_service_1.PROJECT_STATUS_FILENAME;
64356
64564
  } });
64357
- Object.defineProperty(exports2, "LEGACY_USER_STATUS_FILENAME", { enumerable: true, get: function() {
64358
- return setup_status_service_1.LEGACY_USER_STATUS_FILENAME;
64359
- } });
64360
64565
  var api_key_detector_1 = require_api_key_detector();
64361
64566
  Object.defineProperty(exports2, "toScopeStatus", { enumerable: true, get: function() {
64362
64567
  return api_key_detector_1.toScopeStatus;
@@ -64425,12 +64630,21 @@ var require_dist4 = __commonJS({
64425
64630
  Object.defineProperty(exports2, "detectGitignoreStatus", { enumerable: true, get: function() {
64426
64631
  return gitignore_1.detectGitignoreStatus;
64427
64632
  } });
64633
+ Object.defineProperty(exports2, "detectLegacyGitignoreSection", { enumerable: true, get: function() {
64634
+ return gitignore_1.detectLegacyGitignoreSection;
64635
+ } });
64636
+ Object.defineProperty(exports2, "removeLegacyGitignoreSection", { enumerable: true, get: function() {
64637
+ return gitignore_1.removeLegacyGitignoreSection;
64638
+ } });
64428
64639
  Object.defineProperty(exports2, "SIDEKICK_SECTION_START", { enumerable: true, get: function() {
64429
64640
  return gitignore_1.SIDEKICK_SECTION_START;
64430
64641
  } });
64431
64642
  Object.defineProperty(exports2, "SIDEKICK_SECTION_END", { enumerable: true, get: function() {
64432
64643
  return gitignore_1.SIDEKICK_SECTION_END;
64433
64644
  } });
64645
+ Object.defineProperty(exports2, "SIDEKICK_GITIGNORE_HEADER", { enumerable: true, get: function() {
64646
+ return gitignore_1.SIDEKICK_GITIGNORE_HEADER;
64647
+ } });
64434
64648
  Object.defineProperty(exports2, "GITIGNORE_ENTRIES", { enumerable: true, get: function() {
64435
64649
  return gitignore_1.GITIGNORE_ENTRIES;
64436
64650
  } });
@@ -64583,6 +64797,10 @@ var require_dist4 = __commonJS({
64583
64797
  Object.defineProperty(exports2, "isInSandbox", { enumerable: true, get: function() {
64584
64798
  return sandbox_1.isInSandbox;
64585
64799
  } });
64800
+ var error_utils_1 = require_error_utils();
64801
+ Object.defineProperty(exports2, "toErrorMessage", { enumerable: true, get: function() {
64802
+ return error_utils_1.toErrorMessage;
64803
+ } });
64586
64804
  var git_status_1 = require_git_status();
64587
64805
  Object.defineProperty(exports2, "getGitFileStatus", { enumerable: true, get: function() {
64588
64806
  return git_status_1.getGitFileStatus;
@@ -64641,7 +64859,7 @@ var require_runtime = __commonJS({
64641
64859
  });
64642
64860
  } catch (err) {
64643
64861
  loggerFacade.error("Failed to load configuration", {
64644
- error: err instanceof Error ? err.message : String(err)
64862
+ error: (0, core_1.toErrorMessage)(err)
64645
64863
  });
64646
64864
  throw err;
64647
64865
  }
@@ -64809,7 +65027,7 @@ var require_dev_mode_guard = __commonJS({
64809
65027
  }
64810
65028
  } catch (err) {
64811
65029
  logger.warn(`Failed to auto-correct devMode flag for ${callerLabel}`, {
64812
- error: err instanceof Error ? err.message : String(err),
65030
+ error: (0, core_1.toErrorMessage)(err),
64813
65031
  caller: callerLabel
64814
65032
  });
64815
65033
  }
@@ -64827,7 +65045,7 @@ var require_dev_mode_guard = __commonJS({
64827
65045
  }
64828
65046
  } catch (err) {
64829
65047
  logger.warn(`Failed to check plugin/dev-mode status for ${callerLabel}, proceeding normally`, {
64830
- error: err instanceof Error ? err.message : String(err),
65048
+ error: (0, core_1.toErrorMessage)(err),
64831
65049
  caller: callerLabel
64832
65050
  });
64833
65051
  }
@@ -71853,6 +72071,7 @@ var require_reminder_utils = __commonJS({
71853
72071
  var node_path_1 = require("node:path");
71854
72072
  var yaml = __importStar(require_js_yaml());
71855
72073
  var zod_1 = require_zod2();
72074
+ var core_1 = require_dist4();
71856
72075
  var ReminderDefinitionSchema = zod_1.z.object({
71857
72076
  id: zod_1.z.string(),
71858
72077
  blocking: zod_1.z.boolean(),
@@ -71905,7 +72124,7 @@ var require_reminder_utils = __commonJS({
71905
72124
  if (logger) {
71906
72125
  logger.error("Failed to load reminder", {
71907
72126
  reminderId,
71908
- error: err instanceof Error ? err.message : String(err)
72127
+ error: (0, core_1.toErrorMessage)(err)
71909
72128
  });
71910
72129
  } else {
71911
72130
  console.error(`Failed to load reminder ${reminderId}:`, err);
@@ -72645,7 +72864,7 @@ var require_stage_pause_and_reflect = __commonJS({
72645
72864
  (0, staging_handler_utils_js_1.createStagingHandler)(context, {
72646
72865
  id: "reminders:stage-pause-and-reflect",
72647
72866
  priority: 80,
72648
- filter: { kind: "transcript", eventTypes: ["ToolCall"] },
72867
+ filter: { kind: "transcript", eventTypes: ["ToolResult"] },
72649
72868
  execute: async (event, ctx) => {
72650
72869
  if (!(0, types_1.isTranscriptEvent)(event))
72651
72870
  return void 0;
@@ -74328,17 +74547,15 @@ var require_track_verification_tools = __commonJS({
74328
74547
  var state_js_1 = require_state4();
74329
74548
  var FILE_EDIT_TOOLS = ["Write", "Edit", "MultiEdit"];
74330
74549
  var VC_TOOL_NAME_SET = new Set(types_js_1.VC_TOOL_REMINDER_IDS);
74331
- function extractToolInput(event) {
74332
- const entry = event.payload.entry;
74333
- return entry?.input;
74334
- }
74550
+ var MAX_PENDING_TOOL_CALLS = 100;
74335
74551
  function registerTrackVerificationTools(context) {
74336
74552
  if (!(0, types_1.isDaemonContext)(context))
74337
74553
  return;
74554
+ const pendingBySession = /* @__PURE__ */ new Map();
74338
74555
  context.handlers.register({
74339
74556
  id: "reminders:track-verification-tools",
74340
74557
  priority: 60,
74341
- filter: { kind: "transcript", eventTypes: ["ToolCall"] },
74558
+ filter: { kind: "transcript", eventTypes: ["ToolCall", "ToolResult"] },
74342
74559
  handler: async (event, ctx) => {
74343
74560
  if (!(0, types_1.isTranscriptEvent)(event))
74344
74561
  return;
@@ -74350,22 +74567,66 @@ var require_track_verification_tools = __commonJS({
74350
74567
  const sessionId = event.context?.sessionId;
74351
74568
  if (!sessionId)
74352
74569
  return;
74353
- const toolName = event.payload.toolName;
74354
- if (!toolName)
74570
+ if (event.eventType === "ToolCall") {
74571
+ const toolUseId = event.payload.entry.id;
74572
+ const toolName = event.payload.toolName;
74573
+ if (!toolUseId || !toolName)
74574
+ return;
74575
+ const entry = event.payload.entry;
74576
+ const input = entry?.input ?? {};
74577
+ let sessionMap = pendingBySession.get(sessionId);
74578
+ if (!sessionMap) {
74579
+ sessionMap = /* @__PURE__ */ new Map();
74580
+ pendingBySession.set(sessionId, sessionMap);
74581
+ }
74582
+ if (sessionMap.size >= MAX_PENDING_TOOL_CALLS) {
74583
+ const oldest = sessionMap.keys().next().value;
74584
+ if (oldest)
74585
+ sessionMap.delete(oldest);
74586
+ }
74587
+ sessionMap.set(toolUseId, { toolName, input });
74355
74588
  return;
74356
- const config = (0, types_js_1.getRemindersConfig)(context.config);
74357
- const verificationTools = config.verification_tools ?? {};
74358
- const runners = config.command_runners ?? [];
74359
- const remindersState = (0, state_js_1.createRemindersState)(daemonCtx.stateService);
74360
- const stateResult = await remindersState.verificationTools.read(sessionId);
74361
- const toolsState = { ...stateResult.data };
74362
- if (FILE_EDIT_TOOLS.includes(toolName)) {
74363
- await handleFileEdit(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState);
74364
- } else if (toolName === "Bash") {
74365
- await handleBashCommand(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState, runners);
74589
+ }
74590
+ if (event.eventType === "ToolResult") {
74591
+ const toolUseId = event.payload.entry.tool_use_id;
74592
+ if (!toolUseId)
74593
+ return;
74594
+ const sessionMap = pendingBySession.get(sessionId);
74595
+ const pending = sessionMap?.get(toolUseId);
74596
+ if (!pending)
74597
+ return;
74598
+ sessionMap.delete(toolUseId);
74599
+ if (sessionMap.size === 0)
74600
+ pendingBySession.delete(sessionId);
74601
+ const { toolName, input } = pending;
74602
+ const config = (0, types_js_1.getRemindersConfig)(context.config);
74603
+ const verificationTools = config.verification_tools ?? {};
74604
+ const runners = config.command_runners ?? [];
74605
+ const remindersState = (0, state_js_1.createRemindersState)(daemonCtx.stateService);
74606
+ const stateResult = await remindersState.verificationTools.read(sessionId);
74607
+ const toolsState = { ...stateResult.data };
74608
+ if (FILE_EDIT_TOOLS.includes(toolName)) {
74609
+ await handleFileEdit(input, daemonCtx, sessionId, verificationTools, toolsState, remindersState);
74610
+ } else if (toolName === "Bash") {
74611
+ await handleBashCommand(input, daemonCtx, sessionId, verificationTools, toolsState, remindersState, runners);
74612
+ }
74366
74613
  }
74367
74614
  }
74368
74615
  });
74616
+ context.handlers.register({
74617
+ id: "reminders:track-verification-tools-cleanup",
74618
+ priority: 60,
74619
+ filter: { kind: "hook", hooks: ["UserPromptSubmit", "Stop"] },
74620
+ // eslint-disable-next-line @typescript-eslint/require-await -- sync cleanup, async required by EventHandler type
74621
+ handler: async (event, _ctx) => {
74622
+ if (!(0, types_1.isHookEvent)(event))
74623
+ return;
74624
+ const sessionId = event.context?.sessionId;
74625
+ if (!sessionId)
74626
+ return;
74627
+ pendingBySession.delete(sessionId);
74628
+ }
74629
+ });
74369
74630
  }
74370
74631
  async function stageToolsForFiles(filePaths, daemonCtx, sessionId, verificationTools, toolsState, remindersState, triggeredBy = "file_edit") {
74371
74632
  const existingReminders = await daemonCtx.staging.listReminders("Stop");
@@ -74470,7 +74731,7 @@ var require_track_verification_tools = __commonJS({
74470
74731
  toolName,
74471
74732
  reminderId,
74472
74733
  sessionId,
74473
- error: error instanceof Error ? error.message : String(error)
74734
+ error: (0, core_1.toErrorMessage)(error)
74474
74735
  });
74475
74736
  }
74476
74737
  }
@@ -74484,8 +74745,8 @@ var require_track_verification_tools = __commonJS({
74484
74745
  await remindersState.verificationTools.write(sessionId, toolsState);
74485
74746
  return anyStaged;
74486
74747
  }
74487
- async function handleFileEdit(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState) {
74488
- const filePath = extractToolInput(event)?.file_path;
74748
+ async function handleFileEdit(input, daemonCtx, sessionId, verificationTools, toolsState, remindersState) {
74749
+ const filePath = input.file_path;
74489
74750
  if (!filePath)
74490
74751
  return;
74491
74752
  const projectDir = daemonCtx.paths?.projectDir;
@@ -74493,8 +74754,8 @@ var require_track_verification_tools = __commonJS({
74493
74754
  return;
74494
74755
  await stageToolsForFiles([filePath], daemonCtx, sessionId, verificationTools, toolsState, remindersState);
74495
74756
  }
74496
- async function handleBashCommand(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState, runners = []) {
74497
- const command = extractToolInput(event)?.command;
74757
+ async function handleBashCommand(input, daemonCtx, sessionId, verificationTools, toolsState, remindersState, runners = []) {
74758
+ const command = input.command;
74498
74759
  if (!command)
74499
74760
  return;
74500
74761
  let anyUnstaged = false;
@@ -74923,7 +75184,7 @@ var require_stage_persona_reminders = __commonJS({
74923
75184
  } catch (err) {
74924
75185
  logger.error("Failed to restage persona reminders", {
74925
75186
  sessionId,
74926
- error: err instanceof Error ? err.message : String(err)
75187
+ error: (0, core_1.toErrorMessage)(err)
74927
75188
  });
74928
75189
  }
74929
75190
  }
@@ -75159,6 +75420,38 @@ var require_stage_user_profile_reminders = __commonJS({
75159
75420
  }
75160
75421
  });
75161
75422
 
75423
+ // ../feature-reminders/dist/handlers/staging/cleanup-on-stop.js
75424
+ var require_cleanup_on_stop = __commonJS({
75425
+ "../feature-reminders/dist/handlers/staging/cleanup-on-stop.js"(exports2) {
75426
+ "use strict";
75427
+ Object.defineProperty(exports2, "__esModule", { value: true });
75428
+ exports2.registerCleanupOnStop = registerCleanupOnStop;
75429
+ var types_1 = require_dist();
75430
+ function registerCleanupOnStop(context) {
75431
+ if (!(0, types_1.isDaemonContext)(context))
75432
+ return;
75433
+ context.handlers.register({
75434
+ id: "reminders:cleanup-on-stop",
75435
+ priority: 50,
75436
+ filter: { kind: "hook", hooks: ["Stop"] },
75437
+ handler: async (event, ctx) => {
75438
+ if (!(0, types_1.isHookEvent)(event))
75439
+ return;
75440
+ if (!(0, types_1.isDaemonContext)(ctx))
75441
+ return;
75442
+ const daemonCtx = ctx;
75443
+ const sessionId = event.context?.sessionId;
75444
+ if (!sessionId)
75445
+ return;
75446
+ if (daemonCtx.orchestrator) {
75447
+ await daemonCtx.orchestrator.onStop(sessionId);
75448
+ }
75449
+ }
75450
+ });
75451
+ }
75452
+ }
75453
+ });
75454
+
75162
75455
  // ../feature-reminders/dist/handlers/staging/index.js
75163
75456
  var require_staging2 = __commonJS({
75164
75457
  "../feature-reminders/dist/handlers/staging/index.js"(exports2) {
@@ -75172,6 +75465,7 @@ var require_staging2 = __commonJS({
75172
75465
  var unstage_verify_completion_1 = require_unstage_verify_completion();
75173
75466
  var stage_persona_reminders_1 = require_stage_persona_reminders();
75174
75467
  var stage_user_profile_reminders_1 = require_stage_user_profile_reminders();
75468
+ var cleanup_on_stop_1 = require_cleanup_on_stop();
75175
75469
  function registerStagingHandlers(context) {
75176
75470
  (0, stage_default_user_prompt_1.registerStageDefaultUserPrompt)(context);
75177
75471
  (0, stage_pause_and_reflect_1.registerStagePauseAndReflect)(context);
@@ -75180,6 +75474,7 @@ var require_staging2 = __commonJS({
75180
75474
  (0, unstage_verify_completion_1.registerUnstageVerifyCompletion)(context);
75181
75475
  (0, stage_persona_reminders_1.registerStagePersonaReminders)(context);
75182
75476
  (0, stage_user_profile_reminders_1.registerStageUserProfileReminders)(context);
75477
+ (0, cleanup_on_stop_1.registerCleanupOnStop)(context);
75183
75478
  }
75184
75479
  }
75185
75480
  });
@@ -75900,7 +76195,7 @@ var require_orchestrator = __commonJS({
75900
76195
  } catch (err) {
75901
76196
  this.deps.logger.warn("Failed to unstage VC reminders after P&R staged", {
75902
76197
  sessionId,
75903
- error: err instanceof Error ? err.message : String(err)
76198
+ error: (0, core_1.toErrorMessage)(err)
75904
76199
  });
75905
76200
  }
75906
76201
  }
@@ -75924,27 +76219,10 @@ var require_orchestrator = __commonJS({
75924
76219
  } catch (err) {
75925
76220
  this.deps.logger.warn("Failed to reset P&R baseline after VC consumed", {
75926
76221
  sessionId,
75927
- error: err instanceof Error ? err.message : String(err)
75928
- });
75929
- }
75930
- try {
75931
- const staging = this.deps.getStagingService(sessionId);
75932
- const deleted = await staging.deleteReminder("PreToolUse", types_js_1.ReminderIds.PAUSE_AND_REFLECT);
75933
- if (deleted) {
75934
- (0, core_1.logEvent)(this.deps.logger.child({ context: { sessionId } }), events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
75935
- reminderName: types_js_1.ReminderIds.PAUSE_AND_REFLECT,
75936
- hookName: "PreToolUse",
75937
- reason: "vc_consumed_cascade",
75938
- triggeredBy: "cascade_from_verify_completion"
75939
- }));
75940
- }
75941
- this.deps.logger.debug("VC unstage: P&R cascade from VC consumed", { sessionId, deleted });
75942
- } catch (err) {
75943
- this.deps.logger.warn("Failed to unstage P&R after VC consumed", {
75944
- sessionId,
75945
- error: err instanceof Error ? err.message : String(err)
76222
+ error: (0, core_1.toErrorMessage)(err)
75946
76223
  });
75947
76224
  }
76225
+ await this.unstagePauseAndReflect(sessionId, "vc_consumed_cascade", "cascade_from_verify_completion");
75948
76226
  }
75949
76227
  }
75950
76228
  /**
@@ -75961,7 +76239,43 @@ var require_orchestrator = __commonJS({
75961
76239
  } catch (err) {
75962
76240
  this.deps.logger.warn("Failed to clear P&R baseline on UserPromptSubmit", {
75963
76241
  sessionId,
75964
- error: err instanceof Error ? err.message : String(err)
76242
+ error: (0, core_1.toErrorMessage)(err)
76243
+ });
76244
+ }
76245
+ }
76246
+ /**
76247
+ * Called when Stop hook fires.
76248
+ *
76249
+ * P&R is designed to interrupt runaway execution — once the agent stops,
76250
+ * it's irrelevant. This is defensive: Rule 4 (VC consumed → unstage P&R)
76251
+ * covers the VC case, but this handles the no-VC case where P&R would
76252
+ * otherwise linger on PreToolUse.
76253
+ */
76254
+ async onStop(sessionId) {
76255
+ await this.unstagePauseAndReflect(sessionId, "agent_stopping", "stop_hook");
76256
+ }
76257
+ /**
76258
+ * Delete P&R from PreToolUse staging and log the event.
76259
+ * Shared by Rule 4 (VC consumed → unstage P&R) and onStop (agent stopping).
76260
+ */
76261
+ async unstagePauseAndReflect(sessionId, reason, triggeredBy) {
76262
+ try {
76263
+ const staging = this.deps.getStagingService(sessionId);
76264
+ const deleted = await staging.deleteReminder("PreToolUse", types_js_1.ReminderIds.PAUSE_AND_REFLECT);
76265
+ if (deleted) {
76266
+ (0, core_1.logEvent)(this.deps.logger.child({ context: { sessionId } }), events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
76267
+ reminderName: types_js_1.ReminderIds.PAUSE_AND_REFLECT,
76268
+ hookName: "PreToolUse",
76269
+ reason,
76270
+ triggeredBy
76271
+ }));
76272
+ }
76273
+ this.deps.logger.debug("P&R unstaged", { sessionId, deleted, reason });
76274
+ } catch (err) {
76275
+ this.deps.logger.warn("Failed to unstage P&R", {
76276
+ sessionId,
76277
+ reason,
76278
+ error: (0, core_1.toErrorMessage)(err)
75965
76279
  });
75966
76280
  }
75967
76281
  }
@@ -76130,6 +76444,7 @@ var require_hook = __commonJS({
76130
76444
  exports2.isHookCommand = isHookCommand;
76131
76445
  exports2.getHookName = getHookName;
76132
76446
  var core_1 = require_dist4();
76447
+ var types_1 = require_dist();
76133
76448
  var context_js_1 = require_context2();
76134
76449
  function truncateForLog(raw) {
76135
76450
  const entries = Object.entries(raw);
@@ -76158,15 +76473,7 @@ var require_hook = __commonJS({
76158
76473
  }
76159
76474
  return truncateForLog(filtered);
76160
76475
  }
76161
- var VALID_HOOK_NAMES = /* @__PURE__ */ new Set([
76162
- "SessionStart",
76163
- "SessionEnd",
76164
- "UserPromptSubmit",
76165
- "PreToolUse",
76166
- "PostToolUse",
76167
- "Stop",
76168
- "PreCompact"
76169
- ]);
76476
+ var VALID_HOOK_NAMES = new Set(types_1.HOOK_NAMES);
76170
76477
  function validateHookName(hookEventName) {
76171
76478
  return VALID_HOOK_NAMES.has(hookEventName) ? hookEventName : void 0;
76172
76479
  }
@@ -76177,7 +76484,9 @@ var require_hook = __commonJS({
76177
76484
  "pre-tool-use": "PreToolUse",
76178
76485
  "post-tool-use": "PostToolUse",
76179
76486
  stop: "Stop",
76180
- "pre-compact": "PreCompact"
76487
+ "pre-compact": "PreCompact",
76488
+ "subagent-start": "SubagentStart",
76489
+ "subagent-stop": "SubagentStop"
76181
76490
  };
76182
76491
  function extractToolFields(raw) {
76183
76492
  const toolName = typeof raw.tool_name === "string" ? raw.tool_name : "unknown";
@@ -76279,11 +76588,46 @@ var require_hook = __commonJS({
76279
76588
  }
76280
76589
  };
76281
76590
  }
76591
+ function buildSubagentStartEvent(context, input) {
76592
+ return {
76593
+ kind: "hook",
76594
+ hook: "SubagentStart",
76595
+ context,
76596
+ payload: {
76597
+ transcriptPath: input.transcriptPath,
76598
+ agentId: context.agentId,
76599
+ agentType: context.agentType
76600
+ }
76601
+ };
76602
+ }
76603
+ function buildSubagentStopEvent(context, input) {
76604
+ const raw = input.raw;
76605
+ const agentTranscriptPath = typeof raw.agent_transcript_path === "string" ? raw.agent_transcript_path : "";
76606
+ const lastAssistantMessage = typeof raw.last_assistant_message === "string" ? raw.last_assistant_message : "";
76607
+ const permissionMode = input.permissionMode ?? "default";
76608
+ const stopHookActive = typeof raw.stop_hook_active === "boolean" ? raw.stop_hook_active : void 0;
76609
+ return {
76610
+ kind: "hook",
76611
+ hook: "SubagentStop",
76612
+ context,
76613
+ payload: {
76614
+ transcriptPath: input.transcriptPath,
76615
+ permissionMode,
76616
+ agentId: context.agentId,
76617
+ agentType: context.agentType,
76618
+ agentTranscriptPath,
76619
+ lastAssistantMessage,
76620
+ ...stopHookActive !== void 0 && { stopHookActive }
76621
+ }
76622
+ };
76623
+ }
76282
76624
  function buildHookEvent(hookName, input, correlationId) {
76283
76625
  const context = {
76284
76626
  sessionId: input.sessionId,
76285
76627
  timestamp: Date.now(),
76286
- correlationId
76628
+ correlationId,
76629
+ ...input.agentId !== void 0 && { agentId: input.agentId },
76630
+ ...input.agentType !== void 0 && { agentType: input.agentType }
76287
76631
  };
76288
76632
  switch (hookName) {
76289
76633
  case "SessionStart":
@@ -76300,6 +76644,22 @@ var require_hook = __commonJS({
76300
76644
  return buildStopEvent(context, input);
76301
76645
  case "PreCompact":
76302
76646
  return buildPreCompactEvent(context, input);
76647
+ case "SubagentStart": {
76648
+ const subagentContext = {
76649
+ ...context,
76650
+ agentId: input.agentId ?? "",
76651
+ agentType: input.agentType ?? ""
76652
+ };
76653
+ return buildSubagentStartEvent(subagentContext, input);
76654
+ }
76655
+ case "SubagentStop": {
76656
+ const subagentContext = {
76657
+ ...context,
76658
+ agentId: input.agentId ?? "",
76659
+ agentType: input.agentType ?? ""
76660
+ };
76661
+ return buildSubagentStopEvent(subagentContext, input);
76662
+ }
76303
76663
  }
76304
76664
  }
76305
76665
  function mergeHookResponses(daemonResponse, cliResponse) {
@@ -76321,6 +76681,10 @@ ${daemonResponse.additionalContext}` : cliResponse.additionalContext;
76321
76681
  return merged;
76322
76682
  }
76323
76683
  async function handleHookCommand(hookName, options, logger, stdout) {
76684
+ if (process.env.SIDEKICK_SUBPROCESS === "1") {
76685
+ stdout.write("{}\n");
76686
+ return { exitCode: 0, output: "{}" };
76687
+ }
76324
76688
  const { projectRoot, hookInput, correlationId, runtime } = options;
76325
76689
  const startTime = Date.now();
76326
76690
  const logContext = {
@@ -76429,7 +76793,7 @@ var require_hook_command = __commonJS({
76429
76793
  return void 0;
76430
76794
  } catch (err) {
76431
76795
  logger.error("Failed to load safe-word-liveness.yaml", {
76432
- error: err instanceof Error ? err.message : String(err),
76796
+ error: (0, core_1.toErrorMessage)(err),
76433
76797
  projectRoot
76434
76798
  });
76435
76799
  return void 0;
@@ -76512,6 +76876,17 @@ var require_hook_command = __commonJS({
76512
76876
  addUserMessage(response, internal.userMessage);
76513
76877
  return response;
76514
76878
  }
76879
+ function translateSubagentStart(internal) {
76880
+ const response = {};
76881
+ if (internal.additionalContext) {
76882
+ response.hookSpecificOutput = {
76883
+ hookEventName: "SubagentStart",
76884
+ additionalContext: internal.additionalContext
76885
+ };
76886
+ }
76887
+ addUserMessage(response, internal.userMessage);
76888
+ return response;
76889
+ }
76515
76890
  var TRANSLATORS = {
76516
76891
  SessionStart: translateSessionStart,
76517
76892
  SessionEnd: () => ({}),
@@ -76519,7 +76894,10 @@ var require_hook_command = __commonJS({
76519
76894
  PreToolUse: translatePreToolUse,
76520
76895
  PostToolUse: translatePostToolUse,
76521
76896
  Stop: translateStop,
76522
- PreCompact: () => ({})
76897
+ PreCompact: () => ({}),
76898
+ SubagentStart: translateSubagentStart,
76899
+ // SubagentStop shares Stop's blocking semantics verbatim per Claude Code docs.
76900
+ SubagentStop: translateStop
76523
76901
  };
76524
76902
  function translateToClaudeCodeFormat(hookName, internal) {
76525
76903
  return TRANSLATORS[hookName](internal);
@@ -76532,13 +76910,17 @@ var require_hook_command = __commonJS({
76532
76910
  "post-tool-use": "PostToolUse",
76533
76911
  stop: "Stop",
76534
76912
  "pre-compact": "PreCompact",
76913
+ "subagent-start": "SubagentStart",
76914
+ "subagent-stop": "SubagentStop",
76535
76915
  SessionStart: "SessionStart",
76536
76916
  SessionEnd: "SessionEnd",
76537
76917
  UserPromptSubmit: "UserPromptSubmit",
76538
76918
  PreToolUse: "PreToolUse",
76539
76919
  PostToolUse: "PostToolUse",
76540
76920
  Stop: "Stop",
76541
- PreCompact: "PreCompact"
76921
+ PreCompact: "PreCompact",
76922
+ SubagentStart: "SubagentStart",
76923
+ SubagentStop: "SubagentStop"
76542
76924
  };
76543
76925
  function parseHookArg(arg) {
76544
76926
  return arg ? HOOK_ARG_TO_NAME[arg] : void 0;
@@ -76571,7 +76953,7 @@ var require_hook_command = __commonJS({
76571
76953
  return configured;
76572
76954
  } catch (err) {
76573
76955
  logger.warn("Failed to auto-configure project", {
76574
- error: err instanceof Error ? err.message : String(err),
76956
+ error: (0, core_1.toErrorMessage)(err),
76575
76957
  projectRoot
76576
76958
  });
76577
76959
  return false;
@@ -76584,7 +76966,7 @@ var require_hook_command = __commonJS({
76584
76966
  state = await setupService.getSetupState();
76585
76967
  } catch (err) {
76586
76968
  logger.warn("Failed to check setup state, assuming healthy", {
76587
- error: err instanceof Error ? err.message : String(err),
76969
+ error: (0, core_1.toErrorMessage)(err),
76588
76970
  hookName,
76589
76971
  projectRoot
76590
76972
  });
@@ -76622,7 +77004,7 @@ var require_hook_command = __commonJS({
76622
77004
  }
76623
77005
  } catch (err) {
76624
77006
  logger.warn("Failed to check setup status for daemon start, proceeding anyway", {
76625
- error: err instanceof Error ? err.message : String(err)
77007
+ error: (0, core_1.toErrorMessage)(err)
76626
77008
  });
76627
77009
  }
76628
77010
  try {
@@ -76632,7 +77014,7 @@ var require_hook_command = __commonJS({
76632
77014
  await (0, core_1.updateDaemonHealth)(projectRoot, "healthy", logger);
76633
77015
  return true;
76634
77016
  } catch (err) {
76635
- const errorMessage = err instanceof Error ? err.message : String(err);
77017
+ const errorMessage = (0, core_1.toErrorMessage)(err);
76636
77018
  await (0, core_1.updateDaemonHealth)(projectRoot, "failed", logger, errorMessage);
76637
77019
  return false;
76638
77020
  }
@@ -76645,13 +77027,17 @@ var require_hook_command = __commonJS({
76645
77027
  } catch (err) {
76646
77028
  logger.warn("Failed to parse internal hook response", {
76647
77029
  hookName,
76648
- error: err instanceof Error ? err.message : String(err),
77030
+ error: (0, core_1.toErrorMessage)(err),
76649
77031
  output
76650
77032
  });
76651
77033
  return {};
76652
77034
  }
76653
77035
  }
76654
77036
  async function handleUnifiedHookCommand(hookName, options, logger, stdout) {
77037
+ if (process.env.SIDEKICK_SUBPROCESS === "1") {
77038
+ stdout.write("{}\n");
77039
+ return { exitCode: 0, output: "{}" };
77040
+ }
76655
77041
  const { projectRoot, hookInput, correlationId, runtime, forceDevMode } = options;
76656
77042
  logger.debug("Unified hook command invoked", { hookName, sessionId: hookInput.sessionId });
76657
77043
  const devModeGuard = await (0, dev_mode_guard_js_1.checkDevModeConflict)(projectRoot, forceDevMode, logger, hookName);
@@ -77420,7 +77806,7 @@ var require_persona_selection = __commonJS({
77420
77806
  } catch (err) {
77421
77807
  ctx.logger.warn("Failed to ensure persona for session", {
77422
77808
  sessionId,
77423
- error: err instanceof Error ? err.message : String(err)
77809
+ error: (0, core_1.toErrorMessage)(err)
77424
77810
  });
77425
77811
  }
77426
77812
  }
@@ -78180,7 +78566,7 @@ var require_update_summary = __commonJS({
78180
78566
  ctx.logger.error("performAnalysis failed", {
78181
78567
  sessionId,
78182
78568
  reason,
78183
- error: err instanceof Error ? err.message : String(err)
78569
+ error: (0, core_1.toErrorMessage)(err)
78184
78570
  });
78185
78571
  }
78186
78572
  }
@@ -78582,7 +78968,7 @@ var require_resume_discovery = __commonJS({
78582
78968
  }
78583
78969
  config.logger?.warn("Failed to discover previous resume message", {
78584
78970
  sessionsDir: config.sessionsDir,
78585
- error: error instanceof Error ? error.message : String(error)
78971
+ error: (0, core_1.toErrorMessage)(error)
78586
78972
  });
78587
78973
  return NOT_FOUND;
78588
78974
  }
@@ -80339,7 +80725,7 @@ Examples:
80339
80725
  }
80340
80726
  const event = core_1.LogEvents.statuslineError(eventContext, "unknown", {
80341
80727
  fallbackUsed: true,
80342
- error: error instanceof Error ? error.message : String(error)
80728
+ error: (0, core_1.toErrorMessage)(error)
80343
80729
  });
80344
80730
  (0, core_1.logEvent)(logger, event);
80345
80731
  logger.warn("Statusline render failed", { durationMs });
@@ -80357,6 +80743,7 @@ var require_ui = __commonJS({
80357
80743
  exports2.handleUiCommand = handleUiCommand;
80358
80744
  var node_child_process_1 = require("node:child_process");
80359
80745
  var node_path_1 = require("node:path");
80746
+ var core_1 = require_dist4();
80360
80747
  function resolveUiPackageDir() {
80361
80748
  const cliCommandsDir = __dirname;
80362
80749
  const cliPackageDir = (0, node_path_1.resolve)(cliCommandsDir, "..", "..");
@@ -80386,7 +80773,7 @@ var require_ui = __commonJS({
80386
80773
  logger.debug("Browser open command executed", { command, url });
80387
80774
  } catch (err) {
80388
80775
  logger.warn("Failed to open browser", {
80389
- error: err instanceof Error ? err.message : String(err)
80776
+ error: (0, core_1.toErrorMessage)(err)
80390
80777
  });
80391
80778
  }
80392
80779
  }
@@ -80692,7 +81079,7 @@ var require_persona2 = __commonJS({
80692
81079
  }
80693
81080
  return writeJsonResponse(stdout, { success: true, personaId, previousPersonaId }, 0);
80694
81081
  } catch (err) {
80695
- const errorMsg = err instanceof Error ? err.message : String(err);
81082
+ const errorMsg = (0, core_1.toErrorMessage)(err);
80696
81083
  logger.error("Failed to set persona", { error: errorMsg });
80697
81084
  return writeJsonResponse(stdout, { success: false, error: errorMsg }, 1);
80698
81085
  }
@@ -80716,7 +81103,7 @@ var require_persona2 = __commonJS({
80716
81103
  logger.info("Persona cleared", { previousPersonaId: previousPersonaId ?? "(none)" });
80717
81104
  return writeJsonResponse(stdout, { success: true, personaId: null, previousPersonaId }, 0);
80718
81105
  } catch (err) {
80719
- const errorMsg = err instanceof Error ? err.message : String(err);
81106
+ const errorMsg = (0, core_1.toErrorMessage)(err);
80720
81107
  logger.error("Failed to clear persona", { error: errorMsg });
80721
81108
  return writeJsonResponse(stdout, { success: false, error: errorMsg }, 1);
80722
81109
  }
@@ -80761,7 +81148,7 @@ var require_persona2 = __commonJS({
80761
81148
  return writeJsonResponse(stdout, { error: `Failed to read generated file: ${statePath}` }, 1);
80762
81149
  }
80763
81150
  } catch (err) {
80764
- const errorMsg = err instanceof Error ? err.message : String(err);
81151
+ const errorMsg = (0, core_1.toErrorMessage)(err);
80765
81152
  logger.error("Persona test failed", { error: errorMsg });
80766
81153
  return writeJsonResponse(stdout, { error: errorMsg }, 1);
80767
81154
  } finally {
@@ -80789,7 +81176,7 @@ var require_persona2 = __commonJS({
80789
81176
  filePath: result.filePath
80790
81177
  }, 0);
80791
81178
  } catch (err) {
80792
- const errorMsg = err instanceof Error ? err.message : String(err);
81179
+ const errorMsg = (0, core_1.toErrorMessage)(err);
80793
81180
  logger.error("Failed to pin persona", { error: errorMsg });
80794
81181
  return writeJsonResponse(stdout, { success: false, error: errorMsg }, 1);
80795
81182
  }
@@ -80813,7 +81200,7 @@ var require_persona2 = __commonJS({
80813
81200
  previousPersonaId
80814
81201
  }, 0);
80815
81202
  } catch (err) {
80816
- const errorMsg = err instanceof Error ? err.message : String(err);
81203
+ const errorMsg = (0, core_1.toErrorMessage)(err);
80817
81204
  logger.error("Failed to unpin persona", { error: errorMsg });
80818
81205
  return writeJsonResponse(stdout, { success: false, error: errorMsg }, 1);
80819
81206
  }
@@ -80924,7 +81311,7 @@ var require_config3 = __commonJS({
80924
81311
  logger
80925
81312
  });
80926
81313
  } catch (err) {
80927
- const message = err instanceof Error ? err.message : String(err);
81314
+ const message = (0, core_1.toErrorMessage)(err);
80928
81315
  const error = `Error: ${message}`;
80929
81316
  stdout.write(error + "\n");
80930
81317
  return { exitCode: 1, output: error };
@@ -80970,7 +81357,7 @@ var require_config3 = __commonJS({
80970
81357
  stdout.write(output + "\n");
80971
81358
  return { exitCode: 0, output };
80972
81359
  } catch (err) {
80973
- const message = err instanceof Error ? err.message : String(err);
81360
+ const message = (0, core_1.toErrorMessage)(err);
80974
81361
  const error = `Error: ${message}`;
80975
81362
  stdout.write(error + "\n");
80976
81363
  return { exitCode: 1, output: error };
@@ -80999,7 +81386,7 @@ var require_config3 = __commonJS({
80999
81386
  stdout.write(output + "\n");
81000
81387
  return { exitCode: 0, output };
81001
81388
  } catch (err) {
81002
- const message = err instanceof Error ? err.message : String(err);
81389
+ const message = (0, core_1.toErrorMessage)(err);
81003
81390
  const error = `Error: ${message}`;
81004
81391
  stdout.write(error + "\n");
81005
81392
  return { exitCode: 1, output: error };
@@ -81028,7 +81415,7 @@ var require_config3 = __commonJS({
81028
81415
  stdout.write(output + "\n");
81029
81416
  return { exitCode: 0, output };
81030
81417
  } catch (err) {
81031
- const message = err instanceof Error ? err.message : String(err);
81418
+ const message = (0, core_1.toErrorMessage)(err);
81032
81419
  const error = `Error: ${message}`;
81033
81420
  stdout.write(error + "\n");
81034
81421
  return { exitCode: 1, output: error };
@@ -81254,7 +81641,7 @@ Examples:
81254
81641
  logger.info("Listed sessions", { count: sessions.length });
81255
81642
  return { exitCode: 0, output: JSON.stringify({ count: sessions.length }) };
81256
81643
  } catch (err) {
81257
- const errorMsg = err instanceof Error ? err.message : String(err);
81644
+ const errorMsg = (0, core_1.toErrorMessage)(err);
81258
81645
  logger.error("Failed to list sessions", { error: errorMsg });
81259
81646
  stdout.write(JSON.stringify({ error: errorMsg }, null, 2) + "\n");
81260
81647
  return { exitCode: 1, output: errorMsg };
@@ -81907,14 +82294,63 @@ var require_dev_mode = __commonJS({
81907
82294
  log(stdout, "info", "Full clean complete.");
81908
82295
  return { exitCode: 0 };
81909
82296
  }
82297
+ async function doCleanAllProjects(logger, stdout, options = {}) {
82298
+ const { force = false, stdin = process.stdin } = options;
82299
+ const registryRoot = node_path_1.default.join(node_os_1.default.homedir(), ".sidekick", "projects");
82300
+ const registry = new core_1.ProjectRegistryService(registryRoot);
82301
+ const projects = await registry.list();
82302
+ if (projects.length === 0) {
82303
+ log(stdout, "info", `No registered projects found in ${registryRoot}`);
82304
+ return { exitCode: 0 };
82305
+ }
82306
+ log(stdout, "step", `Found ${projects.length} registered project(s):`);
82307
+ for (const project of projects) {
82308
+ stdout.write(` - ${project.displayName} (${project.path})
82309
+ `);
82310
+ }
82311
+ stdout.write("\n");
82312
+ let cleanedCount = 0;
82313
+ let skippedCount = 0;
82314
+ for (const project of projects) {
82315
+ let projectStats;
82316
+ try {
82317
+ projectStats = await (0, promises_12.stat)(project.path);
82318
+ } catch {
82319
+ log(stdout, "warn", `${project.displayName}: directory not found at ${project.path}, skipping`);
82320
+ skippedCount++;
82321
+ continue;
82322
+ }
82323
+ if (!projectStats.isDirectory()) {
82324
+ log(stdout, "warn", `${project.displayName}: path is not a directory at ${project.path}, skipping`);
82325
+ skippedCount++;
82326
+ continue;
82327
+ }
82328
+ if (!force) {
82329
+ const shouldClean = await (0, prompt_js_1.promptConfirm)({ stdin, stdout }, `Clean ${project.displayName} (${project.path})?`);
82330
+ if (!shouldClean) {
82331
+ log(stdout, "info", `Skipping ${project.displayName}`);
82332
+ skippedCount++;
82333
+ continue;
82334
+ }
82335
+ }
82336
+ stdout.write("\n");
82337
+ log(stdout, "step", `Cleaning ${project.displayName}...`);
82338
+ await doClean(project.path, logger, stdout, { force, stdin });
82339
+ cleanedCount++;
82340
+ }
82341
+ stdout.write("\n");
82342
+ log(stdout, "info", `Clean-all-projects complete: cleaned ${cleanedCount} project(s), skipped ${skippedCount}.`);
82343
+ return { exitCode: 0 };
82344
+ }
81910
82345
  var USAGE_TEXT = `Usage: sidekick dev-mode <command> [options]
81911
82346
 
81912
82347
  Commands:
81913
- enable Add dev-sidekick to .claude/settings.local.json
81914
- disable Remove dev-sidekick from settings.local.json
81915
- status Show current dev-mode state
81916
- clean Truncate logs, kill daemon, clean state folders
81917
- clean-all Full cleanup: clean + remove logs/sessions/state dirs
82348
+ enable Add dev-sidekick to .claude/settings.local.json
82349
+ disable Remove dev-sidekick from settings.local.json
82350
+ status Show current dev-mode state
82351
+ clean Truncate logs, kill daemon, clean state folders
82352
+ clean-all Full cleanup: clean + remove logs/sessions/state dirs
82353
+ clean-all-projects Clean all registered projects in ~/.sidekick/projects/
81918
82354
 
81919
82355
  Options:
81920
82356
  --force Skip confirmation prompts for destructive operations
@@ -81931,6 +82367,8 @@ Options:
81931
82367
  return doClean(projectDir, logger, stdout, options);
81932
82368
  case "clean-all":
81933
82369
  return doCleanAll(projectDir, logger, stdout, options);
82370
+ case "clean-all-projects":
82371
+ return doCleanAllProjects(logger, stdout, options);
81934
82372
  case "help":
81935
82373
  case "--help":
81936
82374
  case "-h":
@@ -82702,6 +83140,7 @@ var require_helpers = __commonJS({
82702
83140
  exports2.getPluginStatusLabel = getPluginStatusLabel;
82703
83141
  exports2.getApiKeyStatusType = getApiKeyStatusType;
82704
83142
  exports2.getPluginStatusIcon = getPluginStatusIcon;
83143
+ exports2.isPluginPresent = isPluginPresent;
82705
83144
  exports2.getLivenessIcon = getLivenessIcon;
82706
83145
  exports2.getLivenessLabel = getLivenessLabel;
82707
83146
  exports2.formatApiKeyScopes = formatApiKeyScopes;
@@ -82784,7 +83223,7 @@ var require_helpers = __commonJS({
82784
83223
  case "dev-mode":
82785
83224
  return "dev-mode (local)";
82786
83225
  case "both":
82787
- return "conflict (both plugin and dev-mode detected!)";
83226
+ return "plugin and dev-mode both active";
82788
83227
  case "none":
82789
83228
  return "not installed";
82790
83229
  case "timeout":
@@ -82809,6 +83248,7 @@ var require_helpers = __commonJS({
82809
83248
  case "dev-mode":
82810
83249
  return "\u2713";
82811
83250
  case "both":
83251
+ return "\u2022";
82812
83252
  case "timeout":
82813
83253
  case "error":
82814
83254
  return "\u26A0";
@@ -82816,6 +83256,9 @@ var require_helpers = __commonJS({
82816
83256
  return "\u2717";
82817
83257
  }
82818
83258
  }
83259
+ function isPluginPresent(status) {
83260
+ return status === "plugin" || status === "dev-mode" || status === "both";
83261
+ }
82819
83262
  function getLivenessIcon(status) {
82820
83263
  switch (status) {
82821
83264
  case "active":
@@ -82919,8 +83362,74 @@ var require_doctor = __commonJS({
82919
83362
  "liveness",
82920
83363
  "zombies",
82921
83364
  "auto-config",
82922
- "shell-alias"
83365
+ "shell-alias",
83366
+ "llm-config"
82923
83367
  ];
83368
+ var DEPRECATED_LLM_MODELS = [
83369
+ {
83370
+ model: "google/gemini-2.0-flash-lite-001",
83371
+ message: "Your llm.yaml references google/gemini-2.0-flash-lite-001, which Google deprecates in June 2026. Sidekick's default has moved to google/gemini-2.5-flash-lite. Update your override or accept the new default."
83372
+ }
83373
+ ];
83374
+ function collectLlmYamlModels(parsed) {
83375
+ if (!parsed)
83376
+ return [];
83377
+ const models = [];
83378
+ for (const key of ["profiles", "fallbackProfiles"]) {
83379
+ const section = parsed[key];
83380
+ if (!section || typeof section !== "object")
83381
+ continue;
83382
+ for (const profile of Object.values(section)) {
83383
+ if (profile && typeof profile === "object") {
83384
+ const model = profile.model;
83385
+ if (typeof model === "string") {
83386
+ models.push(model);
83387
+ }
83388
+ }
83389
+ }
83390
+ }
83391
+ return models;
83392
+ }
83393
+ function runLlmConfigCheck(projectDir, homeDir, stdout, logger) {
83394
+ const candidatePaths = [path.join(homeDir, ".sidekick", "llm.yaml"), path.join(projectDir, ".sidekick", "llm.yaml")];
83395
+ const matched = /* @__PURE__ */ new Set();
83396
+ const parseFailures = [];
83397
+ for (const yamlPath of candidatePaths) {
83398
+ let parsed;
83399
+ try {
83400
+ parsed = (0, core_1.tryReadYaml)(yamlPath);
83401
+ } catch (err) {
83402
+ logger.warn("Failed to parse llm.yaml during migration check", {
83403
+ path: yamlPath,
83404
+ error: (0, core_1.toErrorMessage)(err)
83405
+ });
83406
+ parseFailures.push(yamlPath);
83407
+ continue;
83408
+ }
83409
+ if (!parsed)
83410
+ continue;
83411
+ const models = collectLlmYamlModels(parsed);
83412
+ for (const { model, message } of DEPRECATED_LLM_MODELS) {
83413
+ if (models.includes(model) && !matched.has(model)) {
83414
+ matched.add(model);
83415
+ logger.warn("Deprecated LLM model referenced in user override", {
83416
+ path: yamlPath,
83417
+ model
83418
+ });
83419
+ stdout.write(`\u26A0 ${message}
83420
+ `);
83421
+ }
83422
+ }
83423
+ }
83424
+ if (parseFailures.length > 0) {
83425
+ stdout.write(`\u26A0 LLM Config: could not be parsed (${parseFailures.join(", ")}) \u2014 deprecation check skipped
83426
+ `);
83427
+ return;
83428
+ }
83429
+ if (matched.size === 0) {
83430
+ stdout.write("\u2713 LLM Config: no deprecated models referenced\n");
83431
+ }
83432
+ }
82924
83433
  function parseDoctorOnly(only) {
82925
83434
  if (!only)
82926
83435
  return null;
@@ -82931,6 +83440,13 @@ var require_doctor = __commonJS({
82931
83440
  }
82932
83441
  return new Set(requested);
82933
83442
  }
83443
+ async function tryRemoveLegacySection(projectDir) {
83444
+ try {
83445
+ return await (0, core_1.removeLegacyGitignoreSection)(projectDir);
83446
+ } catch {
83447
+ return false;
83448
+ }
83449
+ }
82934
83450
  async function runDoctorFixes(projectDir, logger, stdout, context) {
82935
83451
  const { homeDir, filter, doctorResult, gitignore, pluginStatus, liveness } = context;
82936
83452
  const isFullMode = filter === null;
@@ -82972,15 +83488,40 @@ var require_doctor = __commonJS({
82972
83488
  stdout.write(" \u26A0 Statusline managed by dev-mode (skipped)\n");
82973
83489
  }
82974
83490
  }
82975
- if (shouldFix("gitignore") && gitignore !== null && gitignore !== "installed") {
82976
- stdout.write("Fixing: Gitignore\n");
82977
- const result = await (0, core_1.installGitignoreSection)(projectDir);
82978
- if (result.status === "error") {
82979
- stdout.write(` \u26A0 Failed to update .gitignore: ${result.error}
83491
+ if (shouldFix("gitignore") && gitignore !== null) {
83492
+ if (gitignore === "legacy") {
83493
+ stdout.write("Fixing: Gitignore (migrating legacy format)\n");
83494
+ const result = await (0, core_1.installGitignoreSection)(projectDir);
83495
+ if (result.status === "error") {
83496
+ stdout.write(` \u26A0 Failed to create .sidekick/.gitignore: ${result.error}
82980
83497
  `);
83498
+ } else {
83499
+ const legacyRemoved = await tryRemoveLegacySection(projectDir);
83500
+ stdout.write(legacyRemoved ? " \u2713 Migrated to .sidekick/.gitignore and removed legacy root section\n" : " \u26A0 Created .sidekick/.gitignore, but legacy root section could not be removed\n");
83501
+ fixedCount++;
83502
+ }
83503
+ } else if (gitignore === "installed") {
83504
+ const hasLegacy = await (0, core_1.detectLegacyGitignoreSection)(projectDir);
83505
+ if (hasLegacy) {
83506
+ stdout.write("Fixing: Gitignore (removing redundant legacy section)\n");
83507
+ const legacyRemoved = await tryRemoveLegacySection(projectDir);
83508
+ if (legacyRemoved) {
83509
+ stdout.write(" \u2713 Removed legacy section from root .gitignore\n");
83510
+ fixedCount++;
83511
+ } else {
83512
+ stdout.write(" \u26A0 Legacy section detected but could not be removed from root .gitignore\n");
83513
+ }
83514
+ }
82981
83515
  } else {
82982
- stdout.write(" \u2713 Gitignore configured\n");
82983
- fixedCount++;
83516
+ stdout.write("Fixing: Gitignore\n");
83517
+ const result = await (0, core_1.installGitignoreSection)(projectDir);
83518
+ if (result.status === "error") {
83519
+ stdout.write(` \u26A0 Failed to update .sidekick/.gitignore: ${result.error}
83520
+ `);
83521
+ } else {
83522
+ stdout.write(" \u2713 Gitignore configured\n");
83523
+ fixedCount++;
83524
+ }
82984
83525
  }
82985
83526
  }
82986
83527
  if (shouldFix("plugin") && pluginStatus === "none") {
@@ -83002,7 +83543,7 @@ var require_doctor = __commonJS({
83002
83543
  fixedCount++;
83003
83544
  }
83004
83545
  } catch (err) {
83005
- stdout.write(` \u26A0 Plugin installation failed: ${err instanceof Error ? err.message : String(err)}
83546
+ stdout.write(` \u26A0 Plugin installation failed: ${(0, core_1.toErrorMessage)(err)}
83006
83547
  `);
83007
83548
  }
83008
83549
  }
@@ -83072,7 +83613,7 @@ var require_doctor = __commonJS({
83072
83613
  try {
83073
83614
  filter = parseDoctorOnly(options?.only);
83074
83615
  } catch (err) {
83075
- stdout.write(`${err instanceof Error ? err.message : String(err)}
83616
+ stdout.write(`${(0, core_1.toErrorMessage)(err)}
83076
83617
  `);
83077
83618
  return { exitCode: 1 };
83078
83619
  }
@@ -83122,7 +83663,12 @@ var require_doctor = __commonJS({
83122
83663
  promises.push((0, core_1.detectGitignoreStatus)(projectDir).then((result) => {
83123
83664
  gitignore = result;
83124
83665
  const gitignoreIcon = result === "installed" ? "\u2713" : "\u26A0";
83125
- stdout.write(`${gitignoreIcon} Gitignore: ${result}
83666
+ const gitignoreMessage = result === "legacy" ? `legacy section found in root .gitignore \u2014 run sidekick doctor --fix --only=gitignore to migrate` : result;
83667
+ stdout.write(`${gitignoreIcon} Gitignore: ${gitignoreMessage}
83668
+ `);
83669
+ }).catch((err) => {
83670
+ gitignore = "unknown";
83671
+ stdout.write(`\u26A0 Gitignore: could not read status \u2014 ${err.message}
83126
83672
  `);
83127
83673
  }));
83128
83674
  }
@@ -83137,8 +83683,7 @@ var require_doctor = __commonJS({
83137
83683
  stdout.write(`${pluginIcon} Plugin: ${pluginLabel}
83138
83684
  `);
83139
83685
  }
83140
- const isPluginPresent = status === "plugin" || status === "dev-mode" || status === "both";
83141
- if (shouldRun("liveness") && isPluginPresent) {
83686
+ if (shouldRun("liveness") && (0, helpers_js_1.isPluginPresent)(status)) {
83142
83687
  logger.info("Starting plugin liveness check");
83143
83688
  liveness = await setupService.detectPluginLiveness();
83144
83689
  const livenessIcon = (0, helpers_js_1.getLivenessIcon)(liveness);
@@ -83160,6 +83705,9 @@ var require_doctor = __commonJS({
83160
83705
  }));
83161
83706
  }
83162
83707
  await Promise.all(promises);
83708
+ if (shouldRun("llm-config")) {
83709
+ runLlmConfigCheck(projectDir, homeDir, stdout, logger);
83710
+ }
83163
83711
  if (shouldRun("auto-config")) {
83164
83712
  const userStatus = await setupService.getUserStatus();
83165
83713
  if (userStatus?.preferences.autoConfigureProjects) {
@@ -83185,7 +83733,7 @@ var require_doctor = __commonJS({
83185
83733
  }
83186
83734
  }
83187
83735
  if (filter === null) {
83188
- const isPluginOk = pluginStatus === "plugin" || pluginStatus === "dev-mode";
83736
+ const isPluginOk = (0, helpers_js_1.isPluginPresent)(pluginStatus);
83189
83737
  const isPluginLive = liveness === null || liveness === "active";
83190
83738
  const isHealthy = doctorResult.overallHealth === "healthy" && gitignore === "installed" && isPluginOk && isPluginLive && zombieCount === 0;
83191
83739
  const overallIcon = isHealthy ? "\u2713" : "\u26A0";
@@ -83625,12 +84173,18 @@ Examples:
83625
84173
  }
83626
84174
  async function runStep3Gitignore(wctx, force) {
83627
84175
  const { ctx, projectDir } = wctx;
83628
- const currentStatus = await (0, core_1.detectGitignoreStatus)(projectDir);
83629
- if (currentStatus === "installed") {
84176
+ let currentStatus;
84177
+ try {
84178
+ currentStatus = await (0, core_1.detectGitignoreStatus)(projectDir);
84179
+ } catch {
84180
+ currentStatus = "missing";
84181
+ }
84182
+ if (currentStatus === "installed" || currentStatus === "legacy") {
83630
84183
  if (!force) {
83631
- (0, prompts_js_1.printStatus)(ctx, "success", "Sidekick entries already present in .gitignore");
84184
+ const message2 = currentStatus === "legacy" ? "Sidekick entries already present in root .gitignore (legacy \u2014 run doctor --fix to migrate)" : "Sidekick already configured (.sidekick/.gitignore)";
84185
+ (0, prompts_js_1.printStatus)(ctx, "success", message2);
83632
84186
  }
83633
- return "installed";
84187
+ return currentStatus;
83634
84188
  }
83635
84189
  const needsRepair = currentStatus === "incomplete";
83636
84190
  if (force) {
@@ -84103,7 +84657,6 @@ var require_uninstall = __commonJS({
84103
84657
  await removeFile(path.join(userHome, ".sidekick", core_1.USER_STATUS_FILENAME), "user", core_1.USER_STATUS_FILENAME, actions, {
84104
84658
  dryRun
84105
84659
  });
84106
- await removeFile(path.join(userHome, ".sidekick", core_1.LEGACY_USER_STATUS_FILENAME), "user", core_1.LEGACY_USER_STATUS_FILENAME, actions, { dryRun });
84107
84660
  await removeFile(path.join(userHome, ".sidekick", "features.yaml"), "user", "features.yaml", actions, { dryRun });
84108
84661
  }
84109
84662
  if (projectDetected) {
@@ -84200,11 +84753,6 @@ var require_uninstall = __commonJS({
84200
84753
  try {
84201
84754
  await fs.access(path.join(userHome, ".sidekick", core_1.USER_STATUS_FILENAME));
84202
84755
  return true;
84203
- } catch {
84204
- }
84205
- try {
84206
- await fs.access(path.join(userHome, ".sidekick", core_1.LEGACY_USER_STATUS_FILENAME));
84207
- return true;
84208
84756
  } catch {
84209
84757
  try {
84210
84758
  const content = await fs.readFile(path.join(userHome, ".claude", "settings.json"), "utf-8");
@@ -84275,8 +84823,12 @@ var require_uninstall = __commonJS({
84275
84823
  summary.project.push({ label: ".env", details: envDetail });
84276
84824
  }
84277
84825
  if (!devModeActive) {
84278
- const gitignore = await (0, fs_js_1.readFileOrNull)(path.join(projectDir, ".gitignore"));
84279
- if (gitignore?.includes("# >>> sidekick")) {
84826
+ const sidekickGitignore = await (0, fs_js_1.readFileOrNull)(path.join(projectDir, ".sidekick", ".gitignore"));
84827
+ const rootGitignore = await (0, fs_js_1.readFileOrNull)(path.join(projectDir, ".gitignore"));
84828
+ if (sidekickGitignore !== null) {
84829
+ summary.project.push({ label: ".sidekick/.gitignore", details: "sidekick managed file" });
84830
+ }
84831
+ if (rootGitignore?.includes("# >>> sidekick")) {
84280
84832
  summary.project.push({ label: ".gitignore", details: "sidekick section" });
84281
84833
  }
84282
84834
  }
@@ -84293,11 +84845,7 @@ var require_uninstall = __commonJS({
84293
84845
  } catch {
84294
84846
  }
84295
84847
  }
84296
- const userConfigFiles = await detectExistingItems(userHome, [
84297
- core_1.USER_STATUS_FILENAME,
84298
- core_1.LEGACY_USER_STATUS_FILENAME,
84299
- "features.yaml"
84300
- ]);
84848
+ const userConfigFiles = await detectExistingItems(userHome, [core_1.USER_STATUS_FILENAME, "features.yaml"]);
84301
84849
  if (userConfigFiles.length > 0) {
84302
84850
  summary.user.push({ label: "Config", details: userConfigFiles.join(", ") });
84303
84851
  }
@@ -84675,7 +85223,7 @@ var require_cli = __commonJS({
84675
85223
  var promises_12 = require("node:fs/promises");
84676
85224
  var node_stream_1 = require("node:stream");
84677
85225
  var yargs_parser_1 = __importDefault2(require_build());
84678
- var VERSION = true ? "0.1.19" : "dev";
85226
+ var VERSION = true ? "0.1.20" : "dev";
84679
85227
  var SANDBOX_ERROR_MESSAGE = `Error: Daemon commands cannot run in sandbox mode.
84680
85228
 
84681
85229
  Claude Code's sandbox blocks Unix socket operations required for daemon IPC.
@@ -84808,6 +85356,8 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
84808
85356
  const cwd = typeof raw.cwd === "string" ? raw.cwd : void 0;
84809
85357
  const hookEventName = typeof raw.hook_event_name === "string" ? raw.hook_event_name : void 0;
84810
85358
  const permissionMode = typeof raw.permission_mode === "string" ? raw.permission_mode : void 0;
85359
+ const agentId = typeof raw.agent_id === "string" ? raw.agent_id : void 0;
85360
+ const agentType = typeof raw.agent_type === "string" ? raw.agent_type : void 0;
84811
85361
  if (!sessionId) {
84812
85362
  return void 0;
84813
85363
  }
@@ -84818,6 +85368,8 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
84818
85368
  // Optional - some hooks (Stop, SessionStart) may not include cwd
84819
85369
  hookEventName: hookEventName ?? "unknown",
84820
85370
  permissionMode,
85371
+ agentId,
85372
+ agentType,
84821
85373
  raw
84822
85374
  };
84823
85375
  } catch {
@@ -85115,7 +85667,7 @@ Run 'sidekick help' for available commands.
85115
85667
  } catch (err) {
85116
85668
  logger.warn("Failed to persist CLI log metrics", {
85117
85669
  sessionId,
85118
- error: err instanceof Error ? err.message : String(err)
85670
+ error: (0, core_1.toErrorMessage)(err)
85119
85671
  });
85120
85672
  }
85121
85673
  }