@scotthamilton77/sidekick 0.1.19 → 0.1.21

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);
@@ -46533,22 +46608,27 @@ var require_package3 = __commonJS({
46533
46608
  pnpm: {
46534
46609
  overrides: {
46535
46610
  ajv: ">=6.14.0 <7",
46536
- minimatch: ">=10.2.1"
46611
+ minimatch: ">=10.2.1",
46612
+ "vite@^7.0.0": "^7.3.2",
46613
+ "picomatch@^4.0.0": "^4.0.4",
46614
+ "picomatch@^2.0.0": "^2.3.2",
46615
+ "flatted@^3.0.0": "^3.4.2",
46616
+ "postcss@^8.0.0": "^8.5.10"
46537
46617
  }
46538
46618
  },
46539
46619
  devDependencies: {
46540
46620
  "@eslint/js": "^10.0.1",
46541
- "@types/node": "^22.7.4",
46542
- "@typescript-eslint/eslint-plugin": "^8.56.0",
46543
- "@typescript-eslint/parser": "^8.56.0",
46544
- "@vitest/coverage-v8": "^4.0.18",
46545
- eslint: "^10.0.1",
46546
- "eslint-config-prettier": "^9.1.0",
46547
- "eslint-plugin-prettier": "^5.1.3",
46548
- prettier: "^3.2.5",
46621
+ "@types/node": "^22.19.17",
46622
+ "@typescript-eslint/eslint-plugin": "^8.59.1",
46623
+ "@typescript-eslint/parser": "^8.59.1",
46624
+ "@vitest/coverage-v8": "^4.1.5",
46625
+ eslint: "^10.3.0",
46626
+ "eslint-config-prettier": "^9.1.2",
46627
+ "eslint-plugin-prettier": "^5.5.5",
46628
+ prettier: "^3.8.3",
46549
46629
  typescript: "^5.9.3",
46550
- "typescript-eslint": "^8.56.0",
46551
- vitest: "^4.0.18"
46630
+ "typescript-eslint": "^8.59.1",
46631
+ vitest: "^4.1.5"
46552
46632
  }
46553
46633
  };
46554
46634
  }
@@ -46573,13 +46653,11 @@ var require_daemon_client2 = __commonJS({
46573
46653
  var client_js_1 = require_client();
46574
46654
  var transport_js_1 = require_transport();
46575
46655
  var sandbox_js_1 = require_sandbox();
46656
+ var error_utils_js_1 = require_error_utils();
46576
46657
  var LOCK_TIMEOUT_MS = 1e4;
46577
46658
  var LOCK_RETRY_INTERVAL_MS = 100;
46578
46659
  var LOCK_STALE_THRESHOLD_MS = 3e4;
46579
46660
  var CLIENT_VERSION = require_package3().version;
46580
- function toErrorMsg(err) {
46581
- return err instanceof Error ? err.message : String(err);
46582
- }
46583
46661
  var DaemonClient = class {
46584
46662
  projectDir;
46585
46663
  logger;
@@ -46945,7 +47023,7 @@ var require_daemon_client2 = __commonJS({
46945
47023
  } catch (err) {
46946
47024
  logger.debug("Graceful stop failed, falling back to SIGKILL", {
46947
47025
  pid: info.pid,
46948
- error: toErrorMsg(err)
47026
+ error: (0, error_utils_js_1.toErrorMessage)(err)
46949
47027
  });
46950
47028
  }
46951
47029
  }
@@ -46954,7 +47032,7 @@ var require_daemon_client2 = __commonJS({
46954
47032
  logger.info("Killed daemon", { pid: info.pid, projectDir: info.projectDir });
46955
47033
  results.push({ projectDir: info.projectDir, pid: info.pid, killed: true });
46956
47034
  } catch (err) {
46957
- const msg = toErrorMsg(err);
47035
+ const msg = (0, error_utils_js_1.toErrorMessage)(err);
46958
47036
  logger.warn("Failed to kill daemon", { pid: info.pid, error: msg });
46959
47037
  results.push({ projectDir: info.projectDir, pid: info.pid, killed: false, error: msg });
46960
47038
  }
@@ -46966,7 +47044,7 @@ var require_daemon_client2 = __commonJS({
46966
47044
  });
46967
47045
  }
46968
47046
  } catch (err) {
46969
- logger.warn("Invalid PID file, removing", { pidFile, error: toErrorMsg(err) });
47047
+ logger.warn("Invalid PID file, removing", { pidFile, error: (0, error_utils_js_1.toErrorMessage)(err) });
46970
47048
  await promises_12.default.unlink(pidPath).catch(() => {
46971
47049
  });
46972
47050
  }
@@ -46987,7 +47065,7 @@ var require_daemon_client2 = __commonJS({
46987
47065
  });
46988
47066
  } catch (err) {
46989
47067
  logger.warn("Failed to run ps \u2014 cannot detect zombie daemons", {
46990
- error: toErrorMsg(err)
47068
+ error: (0, error_utils_js_1.toErrorMessage)(err)
46991
47069
  });
46992
47070
  return [];
46993
47071
  }
@@ -47048,7 +47126,7 @@ var require_daemon_client2 = __commonJS({
47048
47126
  logger.info("Killed zombie daemon", { pid: zombie.pid, command: zombie.command });
47049
47127
  results.push({ projectDir: "unknown", pid: zombie.pid, killed: true });
47050
47128
  } catch (err) {
47051
- const msg = toErrorMsg(err);
47129
+ const msg = (0, error_utils_js_1.toErrorMessage)(err);
47052
47130
  logger.warn("Failed to kill zombie daemon", { pid: zombie.pid, error: msg });
47053
47131
  results.push({ projectDir: "unknown", pid: zombie.pid, killed: false, error: msg });
47054
47132
  }
@@ -47100,60 +47178,94 @@ var require_gitignore = __commonJS({
47100
47178
  };
47101
47179
  })();
47102
47180
  Object.defineProperty(exports2, "__esModule", { value: true });
47103
- exports2.GITIGNORE_ENTRIES = exports2.SIDEKICK_SECTION_END = exports2.SIDEKICK_SECTION_START = void 0;
47181
+ exports2.GITIGNORE_ENTRIES = exports2.SIDEKICK_GITIGNORE_HEADER = exports2.SIDEKICK_SECTION_END = exports2.SIDEKICK_SECTION_START = void 0;
47104
47182
  exports2.installGitignoreSection = installGitignoreSection;
47105
- exports2.removeGitignoreSection = removeGitignoreSection;
47106
47183
  exports2.detectGitignoreStatus = detectGitignoreStatus;
47184
+ exports2.removeGitignoreSection = removeGitignoreSection;
47185
+ exports2.detectLegacyGitignoreSection = detectLegacyGitignoreSection;
47186
+ exports2.removeLegacyGitignoreSection = removeLegacyGitignoreSection;
47107
47187
  var fs = __importStar(require("node:fs/promises"));
47108
47188
  var path = __importStar(require("node:path"));
47109
47189
  exports2.SIDEKICK_SECTION_START = "# >>> sidekick";
47110
47190
  exports2.SIDEKICK_SECTION_END = "# <<< sidekick";
47191
+ exports2.SIDEKICK_GITIGNORE_HEADER = "# Sidekick \u2014 managed file, do not edit manually";
47111
47192
  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"
47193
+ "logs/",
47194
+ "sessions/",
47195
+ "state/",
47196
+ "setup-status.json",
47197
+ ".env",
47198
+ ".env.local",
47199
+ "sidekick*.pid",
47200
+ "sidekick*.token",
47201
+ "*.local.yaml"
47121
47202
  ];
47122
47203
  async function installGitignoreSection(projectDir) {
47123
- const gitignorePath = path.join(projectDir, ".gitignore");
47124
- let content = "";
47204
+ let status;
47125
47205
  try {
47126
- content = await fs.readFile(gitignorePath, "utf-8");
47206
+ status = await detectGitignoreStatus(projectDir);
47127
47207
  } catch (err) {
47128
- if (err.code !== "ENOENT") {
47129
- return { status: "error", error: `Failed to read .gitignore: ${err.message}` };
47130
- }
47208
+ return { status: "error", error: `Failed to check gitignore status: ${err.message}` };
47131
47209
  }
47132
- const status = await detectGitignoreStatus(projectDir);
47133
47210
  if (status === "installed") {
47134
47211
  return { status: "already-installed" };
47135
47212
  }
47136
- if (status === "incomplete") {
47137
- await removeGitignoreSection(projectDir);
47138
- try {
47139
- content = await fs.readFile(gitignorePath, "utf-8");
47140
- } catch {
47141
- content = "";
47142
- }
47213
+ const sidekickDir = path.join(projectDir, ".sidekick");
47214
+ try {
47215
+ await fs.mkdir(sidekickDir, { recursive: true });
47216
+ } catch (err) {
47217
+ return { status: "error", error: `Failed to create .sidekick directory: ${err.message}` };
47143
47218
  }
47144
- const section = ["", exports2.SIDEKICK_SECTION_START, ...exports2.GITIGNORE_ENTRIES, exports2.SIDEKICK_SECTION_END].join("\n");
47145
- const newContent = content.trimEnd() + section + "\n";
47219
+ const content = [exports2.SIDEKICK_GITIGNORE_HEADER, ...exports2.GITIGNORE_ENTRIES].join("\n") + "\n";
47146
47220
  try {
47147
- await fs.writeFile(gitignorePath, newContent);
47221
+ await fs.writeFile(path.join(sidekickDir, ".gitignore"), content);
47148
47222
  return { status: "installed", entriesAdded: exports2.GITIGNORE_ENTRIES };
47149
47223
  } catch (err) {
47150
- return { status: "error", error: `Failed to write .gitignore: ${err.message}` };
47224
+ return { status: "error", error: `Failed to write .sidekick/.gitignore: ${err.message}` };
47151
47225
  }
47152
47226
  }
47227
+ async function detectGitignoreStatus(projectDir) {
47228
+ const sidekickGitignorePath = path.join(projectDir, ".sidekick", ".gitignore");
47229
+ try {
47230
+ const content = await fs.readFile(sidekickGitignorePath, "utf-8");
47231
+ const missingEntries = exports2.GITIGNORE_ENTRIES.filter((entry) => !content.includes(entry));
47232
+ return missingEntries.length === 0 ? "installed" : "incomplete";
47233
+ } catch (err) {
47234
+ if (err.code !== "ENOENT") {
47235
+ throw err;
47236
+ }
47237
+ }
47238
+ const hasLegacy = await detectLegacyGitignoreSection(projectDir);
47239
+ return hasLegacy ? "legacy" : "missing";
47240
+ }
47153
47241
  async function removeGitignoreSection(projectDir) {
47154
- const gitignorePath = path.join(projectDir, ".gitignore");
47242
+ let removed = false;
47243
+ try {
47244
+ await fs.unlink(path.join(projectDir, ".sidekick", ".gitignore"));
47245
+ removed = true;
47246
+ } catch (err) {
47247
+ if (err.code !== "ENOENT") {
47248
+ throw err;
47249
+ }
47250
+ }
47251
+ const legacyRemoved = await removeLegacyGitignoreSection(projectDir);
47252
+ return removed || legacyRemoved;
47253
+ }
47254
+ async function detectLegacyGitignoreSection(projectDir) {
47155
47255
  try {
47156
- const content = await fs.readFile(gitignorePath, "utf-8");
47256
+ const content = await fs.readFile(path.join(projectDir, ".gitignore"), "utf-8");
47257
+ return content.includes(exports2.SIDEKICK_SECTION_START);
47258
+ } catch (err) {
47259
+ if (err.code === "ENOENT") {
47260
+ return false;
47261
+ }
47262
+ throw err;
47263
+ }
47264
+ }
47265
+ async function removeLegacyGitignoreSection(projectDir) {
47266
+ const rootGitignorePath = path.join(projectDir, ".gitignore");
47267
+ try {
47268
+ const content = await fs.readFile(rootGitignorePath, "utf-8");
47157
47269
  const startIdx = content.indexOf(exports2.SIDEKICK_SECTION_START);
47158
47270
  const endIdx = content.indexOf(exports2.SIDEKICK_SECTION_END);
47159
47271
  if (startIdx === -1 || endIdx === -1 || endIdx < startIdx) {
@@ -47165,37 +47277,13 @@ var require_gitignore = __commonJS({
47165
47277
  const before = content.slice(0, lineStartIdx).trimEnd();
47166
47278
  const after = content.slice(actualEndIdx).trimStart();
47167
47279
  const newContent = before + (after ? "\n" + after : "") + "\n";
47168
- await fs.writeFile(gitignorePath, newContent);
47280
+ await fs.writeFile(rootGitignorePath, newContent);
47169
47281
  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";
47282
+ } catch (err) {
47283
+ if (err.code === "ENOENT") {
47284
+ return false;
47195
47285
  }
47196
- return "installed";
47197
- } catch {
47198
- return "missing";
47286
+ throw err;
47199
47287
  }
47200
47288
  }
47201
47289
  }
@@ -47206,7 +47294,7 @@ var require_errors4 = __commonJS({
47206
47294
  "../shared-providers/dist/errors.js"(exports2) {
47207
47295
  "use strict";
47208
47296
  Object.defineProperty(exports2, "__esModule", { value: true });
47209
- exports2.TimeoutError = exports2.AuthError = exports2.RateLimitError = exports2.ProviderError = void 0;
47297
+ exports2.MalformedResponseError = exports2.TimeoutError = exports2.AuthError = exports2.RateLimitError = exports2.ProviderError = void 0;
47210
47298
  var ProviderError = class _ProviderError extends Error {
47211
47299
  provider;
47212
47300
  retryable;
@@ -47247,6 +47335,18 @@ var require_errors4 = __commonJS({
47247
47335
  }
47248
47336
  };
47249
47337
  exports2.TimeoutError = TimeoutError;
47338
+ var MalformedResponseError = class _MalformedResponseError extends ProviderError {
47339
+ code;
47340
+ providerMessage;
47341
+ constructor(provider, code, providerMessage, cause) {
47342
+ super(`Malformed response from ${provider}: ${code ?? "unknown"} - ${providerMessage ?? "no message"}`, provider, false, cause);
47343
+ this.name = "MalformedResponseError";
47344
+ this.code = code;
47345
+ this.providerMessage = providerMessage;
47346
+ Object.setPrototypeOf(this, _MalformedResponseError.prototype);
47347
+ }
47348
+ };
47349
+ exports2.MalformedResponseError = MalformedResponseError;
47250
47350
  }
47251
47351
  });
47252
47352
 
@@ -56225,6 +56325,7 @@ var require_base = __commonJS({
56225
56325
  model: response.model,
56226
56326
  durationMs,
56227
56327
  usage: response.usage,
56328
+ finishReason: response.finishReason,
56228
56329
  status: response.rawResponse.status,
56229
56330
  contentLength: response.content.length
56230
56331
  });
@@ -56272,6 +56373,7 @@ var require_openai_native = __commonJS({
56272
56373
  maxTokens;
56273
56374
  providerAllowlist;
56274
56375
  providerBlocklist;
56376
+ reasoning;
56275
56377
  constructor(config, logger) {
56276
56378
  super(logger);
56277
56379
  this.id = config.baseURL?.includes("openrouter") ? "openrouter" : "openai";
@@ -56280,6 +56382,7 @@ var require_openai_native = __commonJS({
56280
56382
  this.maxTokens = config.maxTokens;
56281
56383
  this.providerAllowlist = config.providerAllowlist;
56282
56384
  this.providerBlocklist = config.providerBlocklist;
56385
+ this.reasoning = config.reasoning;
56283
56386
  this.client = new openai_1.default({
56284
56387
  apiKey: config.apiKey,
56285
56388
  baseURL: config.baseURL,
@@ -56295,6 +56398,7 @@ var require_openai_native = __commonJS({
56295
56398
  maxTokens: this.maxTokens,
56296
56399
  providerAllowlist: this.providerAllowlist,
56297
56400
  providerBlocklist: this.providerBlocklist,
56401
+ reasoning: this.reasoning,
56298
56402
  apiKey: this.redactApiKey(config.apiKey)
56299
56403
  });
56300
56404
  }
@@ -56312,6 +56416,7 @@ var require_openai_native = __commonJS({
56312
56416
  }
56313
56417
  } : void 0;
56314
56418
  const providerRouting = this.buildProviderRouting();
56419
+ const reasoningParam = this.buildReasoningParam();
56315
56420
  const completion = await this.client.chat.completions.create({
56316
56421
  model: request.model ?? this.defaultModel,
56317
56422
  messages,
@@ -56319,8 +56424,13 @@ var require_openai_native = __commonJS({
56319
56424
  max_tokens: this.maxTokens,
56320
56425
  response_format: responseFormat,
56321
56426
  ...providerRouting,
56427
+ ...reasoningParam,
56322
56428
  ...request.additionalParams
56323
56429
  });
56430
+ if (!completion.choices || completion.choices.length === 0) {
56431
+ const errorPayload = completion.error;
56432
+ throw new errors_1.MalformedResponseError(this.id, errorPayload?.code, errorPayload?.message);
56433
+ }
56324
56434
  const response = {
56325
56435
  content: completion.choices[0]?.message?.content ?? "",
56326
56436
  model: completion.model,
@@ -56328,6 +56438,7 @@ var require_openai_native = __commonJS({
56328
56438
  inputTokens: completion.usage.prompt_tokens,
56329
56439
  outputTokens: completion.usage.completion_tokens
56330
56440
  } : void 0,
56441
+ finishReason: completion.choices[0]?.finish_reason ?? void 0,
56331
56442
  rawResponse: {
56332
56443
  status: 200,
56333
56444
  body: JSON.stringify(completion)
@@ -56363,7 +56474,25 @@ var require_openai_native = __commonJS({
56363
56474
  }
56364
56475
  return { provider: providerObj };
56365
56476
  }
56477
+ /**
56478
+ * Build OpenRouter reasoning param object.
56479
+ * Returns empty object if reasoning is unset or provider is not OpenRouter.
56480
+ * Maps `reasoning?: boolean` to OpenRouter's `reasoning: { enabled: <bool> }`.
56481
+ * @see https://openrouter.ai/docs/use-cases/reasoning-tokens
56482
+ */
56483
+ buildReasoningParam() {
56484
+ if (this.id !== "openrouter") {
56485
+ return {};
56486
+ }
56487
+ if (this.reasoning === void 0) {
56488
+ return {};
56489
+ }
56490
+ return { reasoning: { enabled: this.reasoning } };
56491
+ }
56366
56492
  mapError(error) {
56493
+ if (error instanceof errors_1.ProviderError) {
56494
+ return error;
56495
+ }
56367
56496
  if (error instanceof openai_1.default.APIError) {
56368
56497
  if (error.status === 401 || error.status === 403) {
56369
56498
  return new errors_1.AuthError(this.id, error);
@@ -56457,7 +56586,13 @@ var require_claude_cli_spawn = __commonJS({
56457
56586
  });
56458
56587
  const child = (0, node_child_process_1.spawn)(cliPath, args, {
56459
56588
  cwd,
56460
- stdio: ["pipe", "pipe", "pipe"]
56589
+ stdio: ["pipe", "pipe", "pipe"],
56590
+ // Recursion guard: Sidekick's own Claude Code hooks fire inside any
56591
+ // `claude -p` subprocess we spawn. Without this flag, the subprocess
56592
+ // hook handler would dispatch to the daemon, trigger another LLM call,
56593
+ // spawn another subprocess, and so on. handleHookCommand short-circuits
56594
+ // when SIDEKICK_SUBPROCESS=1 is set. See packages/sidekick-cli/src/commands/hook.ts.
56595
+ env: { ...process.env, SIDEKICK_SUBPROCESS: "1" }
56461
56596
  });
56462
56597
  let stdout = "";
56463
56598
  let stderr = "";
@@ -56519,6 +56654,31 @@ var require_claude_cli_spawn = __commonJS({
56519
56654
  }
56520
56655
  });
56521
56656
 
56657
+ // ../shared-providers/dist/providers/anthropic-stop-reason.js
56658
+ var require_anthropic_stop_reason = __commonJS({
56659
+ "../shared-providers/dist/providers/anthropic-stop-reason.js"(exports2) {
56660
+ "use strict";
56661
+ Object.defineProperty(exports2, "__esModule", { value: true });
56662
+ exports2.mapAnthropicStopReason = mapAnthropicStopReason;
56663
+ function mapAnthropicStopReason(stopReason) {
56664
+ if (!stopReason)
56665
+ return void 0;
56666
+ switch (stopReason) {
56667
+ case "end_turn":
56668
+ return "stop";
56669
+ case "max_tokens":
56670
+ return "length";
56671
+ case "stop_sequence":
56672
+ return "stop";
56673
+ case "tool_use":
56674
+ return "tool_calls";
56675
+ default:
56676
+ return stopReason;
56677
+ }
56678
+ }
56679
+ }
56680
+ });
56681
+
56522
56682
  // ../shared-providers/dist/providers/anthropic-cli.js
56523
56683
  var require_anthropic_cli = __commonJS({
56524
56684
  "../shared-providers/dist/providers/anthropic-cli.js"(exports2) {
@@ -56527,6 +56687,7 @@ var require_anthropic_cli = __commonJS({
56527
56687
  exports2.AnthropicCliProvider = void 0;
56528
56688
  var base_1 = require_base();
56529
56689
  var claude_cli_spawn_1 = require_claude_cli_spawn();
56690
+ var anthropic_stop_reason_1 = require_anthropic_stop_reason();
56530
56691
  var AnthropicCliProvider = class extends base_1.AbstractProvider {
56531
56692
  id = "claude-cli";
56532
56693
  defaultModel;
@@ -56588,6 +56749,7 @@ var require_anthropic_cli = __commonJS({
56588
56749
  inputTokens: parsed.usage.input_tokens ?? 0,
56589
56750
  outputTokens: parsed.usage.output_tokens ?? 0
56590
56751
  } : void 0,
56752
+ finishReason: (0, anthropic_stop_reason_1.mapAnthropicStopReason)(parsed.stop_reason),
56591
56753
  rawResponse: {
56592
56754
  status: 200,
56593
56755
  body: stdout
@@ -56859,6 +57021,7 @@ var require_openai_emulator = __commonJS({
56859
57021
  inputTokens,
56860
57022
  outputTokens
56861
57023
  },
57024
+ finishReason: "stop",
56862
57025
  rawResponse: {
56863
57026
  status: 200,
56864
57027
  body: JSON.stringify(rawBody)
@@ -56913,6 +57076,7 @@ var require_openrouter_emulator = __commonJS({
56913
57076
  inputTokens,
56914
57077
  outputTokens
56915
57078
  },
57079
+ finishReason: "stop",
56916
57080
  rawResponse: {
56917
57081
  status: 200,
56918
57082
  body: JSON.stringify(rawBody)
@@ -56933,6 +57097,7 @@ var require_claude_cli_emulator = __commonJS({
56933
57097
  var node_child_process_1 = require("node:child_process");
56934
57098
  var node_path_1 = require("node:path");
56935
57099
  var base_1 = require_base();
57100
+ var anthropic_stop_reason_1 = require_anthropic_stop_reason();
56936
57101
  var EMULATOR_SCRIPT = `#!/bin/bash
56937
57102
  # Claude CLI Emulator Script
56938
57103
  STATE_FILE="\${SIDEKICK_EMULATOR_STATE_PATH:-.sidekick/emulator-state/call-counts.json}"
@@ -57020,6 +57185,7 @@ echo "{\\"content\\":\\"\${CONTENT}\\",\\"message\\":\\"\${CONTENT}\\",\\"model\
57020
57185
  inputTokens,
57021
57186
  outputTokens
57022
57187
  },
57188
+ finishReason: (0, anthropic_stop_reason_1.mapAnthropicStopReason)(parsed.stop_reason),
57023
57189
  rawResponse: {
57024
57190
  status: 0,
57025
57191
  // Exit code
@@ -57156,7 +57322,8 @@ var require_factory = __commonJS({
57156
57322
  temperature: this.config.temperature,
57157
57323
  maxTokens: this.config.maxTokens,
57158
57324
  providerAllowlist: this.config.providerAllowlist,
57159
- providerBlocklist: this.config.providerBlocklist
57325
+ providerBlocklist: this.config.providerBlocklist,
57326
+ reasoning: this.config.reasoning
57160
57327
  };
57161
57328
  return new openai_native_1.OpenAINativeProvider(openrouterConfig, this.logger);
57162
57329
  }
@@ -57333,7 +57500,9 @@ var require_profile_factory = __commonJS({
57333
57500
  maxTokens: profile.maxTokens,
57334
57501
  // OpenRouter-specific provider routing
57335
57502
  providerAllowlist: profile.providerAllowlist ? [...profile.providerAllowlist] : void 0,
57336
- providerBlocklist: profile.providerBlocklist ? [...profile.providerBlocklist] : void 0
57503
+ providerBlocklist: profile.providerBlocklist ? [...profile.providerBlocklist] : void 0,
57504
+ // OpenRouter-specific reasoning toggle
57505
+ reasoning: profile.reasoning
57337
57506
  }, this.logger);
57338
57507
  return factory.create();
57339
57508
  }
@@ -57388,7 +57557,7 @@ var require_dist3 = __commonJS({
57388
57557
  "../shared-providers/dist/index.js"(exports2) {
57389
57558
  "use strict";
57390
57559
  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;
57560
+ 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
57561
  var errors_1 = require_errors4();
57393
57562
  Object.defineProperty(exports2, "ProviderError", { enumerable: true, get: function() {
57394
57563
  return errors_1.ProviderError;
@@ -57402,6 +57571,9 @@ var require_dist3 = __commonJS({
57402
57571
  Object.defineProperty(exports2, "TimeoutError", { enumerable: true, get: function() {
57403
57572
  return errors_1.TimeoutError;
57404
57573
  } });
57574
+ Object.defineProperty(exports2, "MalformedResponseError", { enumerable: true, get: function() {
57575
+ return errors_1.MalformedResponseError;
57576
+ } });
57405
57577
  var factory_1 = require_factory();
57406
57578
  Object.defineProperty(exports2, "ProviderFactory", { enumerable: true, get: function() {
57407
57579
  return factory_1.ProviderFactory;
@@ -57691,6 +57863,7 @@ var require_plugin_detector = __commonJS({
57691
57863
  var crypto2 = __importStar(require("node:crypto"));
57692
57864
  var node_child_process_1 = require("node:child_process");
57693
57865
  var api_key_detector_js_1 = require_api_key_detector();
57866
+ var error_utils_js_1 = require_error_utils();
57694
57867
  function isSidekickStatuslineCommand(command) {
57695
57868
  return command?.toLowerCase().includes("sidekick") ?? false;
57696
57869
  }
@@ -57820,7 +57993,7 @@ var require_plugin_detector = __commonJS({
57820
57993
  return result;
57821
57994
  } catch (err) {
57822
57995
  logger?.warn("Failed to parse plugin list JSON", {
57823
- error: err instanceof Error ? err.message : String(err)
57996
+ error: (0, error_utils_js_1.toErrorMessage)(err)
57824
57997
  });
57825
57998
  logger?.info("Plugin detection completed", { result: "error" });
57826
57999
  return "error";
@@ -58024,7 +58197,16 @@ var require_doctor_engine = __commonJS({
58024
58197
  const expectedUserStatus = (0, api_key_detector_js_1.buildUserApiKeyStatus)(detection);
58025
58198
  const currentUserEntry = currentUserStatus.apiKeys[keyName];
58026
58199
  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)) {
58200
+ if (currentStatus === "not-required")
58201
+ continue;
58202
+ const isLegacyString = typeof currentUserEntry === "string";
58203
+ if (isLegacyString) {
58204
+ updatedUserApiKeys[keyName] = expectedUserStatus;
58205
+ userNeedsUpdate = true;
58206
+ } else if ((0, api_key_detector_js_1.toScopeStatus)(currentStatus) !== (0, api_key_detector_js_1.toScopeStatus)(expectedUserStatus.status)) {
58207
+ updatedUserApiKeys[keyName] = expectedUserStatus;
58208
+ userNeedsUpdate = true;
58209
+ } else if (typeof currentUserEntry === "object" && (currentUserEntry.used !== expectedUserStatus.used || JSON.stringify(currentUserEntry.scopes) !== JSON.stringify(expectedUserStatus.scopes))) {
58028
58210
  updatedUserApiKeys[keyName] = expectedUserStatus;
58029
58211
  userNeedsUpdate = true;
58030
58212
  }
@@ -58099,7 +58281,7 @@ var require_setup_status_service = __commonJS({
58099
58281
  };
58100
58282
  })();
58101
58283
  Object.defineProperty(exports2, "__esModule", { value: true });
58102
- exports2.SetupStatusService = exports2.LEGACY_USER_STATUS_FILENAME = exports2.PROJECT_STATUS_FILENAME = exports2.USER_STATUS_FILENAME = void 0;
58284
+ exports2.SetupStatusService = exports2.PROJECT_STATUS_FILENAME = exports2.USER_STATUS_FILENAME = void 0;
58103
58285
  exports2.createSetupStatusService = createSetupStatusService;
58104
58286
  var fs = __importStar(require("node:fs/promises"));
58105
58287
  var path = __importStar(require("node:path"));
@@ -58111,7 +58293,6 @@ var require_setup_status_service = __commonJS({
58111
58293
  var doctor_engine_js_1 = require_doctor_engine();
58112
58294
  exports2.USER_STATUS_FILENAME = "user-setup-status.json";
58113
58295
  exports2.PROJECT_STATUS_FILENAME = "setup-status.json";
58114
- exports2.LEGACY_USER_STATUS_FILENAME = exports2.PROJECT_STATUS_FILENAME;
58115
58296
  var SetupStatusService = class {
58116
58297
  projectDir;
58117
58298
  homeDir;
@@ -58125,10 +58306,6 @@ var require_setup_status_service = __commonJS({
58125
58306
  get userStatusPath() {
58126
58307
  return path.join(this.homeDir, ".sidekick", exports2.USER_STATUS_FILENAME);
58127
58308
  }
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
58309
  get projectStatusPath() {
58133
58310
  return path.join(this.projectDir, ".sidekick", exports2.PROJECT_STATUS_FILENAME);
58134
58311
  }
@@ -58162,7 +58339,7 @@ var require_setup_status_service = __commonJS({
58162
58339
  return parsed.data;
58163
58340
  } catch (err) {
58164
58341
  if (err.code === "ENOENT") {
58165
- return this.migrateFromLegacyUserStatus();
58342
+ return null;
58166
58343
  }
58167
58344
  if (err instanceof SyntaxError) {
58168
58345
  this.logger?.warn(`Corrupt ${exports2.USER_STATUS_FILENAME}, treating as missing`, {
@@ -58174,54 +58351,6 @@ var require_setup_status_service = __commonJS({
58174
58351
  throw err;
58175
58352
  }
58176
58353
  }
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
58354
  async getProjectStatus() {
58226
58355
  if (path.resolve(this.projectDir) === path.resolve(this.homeDir)) {
58227
58356
  this.logger?.debug("Skipping project status read: projectDir is the home directory", {
@@ -58602,6 +58731,7 @@ var require_staging_service = __commonJS({
58602
58731
  var structured_logging_1 = require_structured_logging();
58603
58732
  var errors_js_1 = require_errors6();
58604
58733
  var staging_paths_js_1 = require_staging_paths();
58734
+ var error_utils_js_1 = require_error_utils();
58605
58735
  var StagingServiceCore = class {
58606
58736
  options;
58607
58737
  constructor(options) {
@@ -58705,7 +58835,7 @@ var require_staging_service = __commonJS({
58705
58835
  hookName,
58706
58836
  reminderName,
58707
58837
  path: reminderPath,
58708
- error: err instanceof Error ? err.message : String(err)
58838
+ error: (0, error_utils_js_1.toErrorMessage)(err)
58709
58839
  });
58710
58840
  return null;
58711
58841
  }
@@ -58736,7 +58866,7 @@ var require_staging_service = __commonJS({
58736
58866
  }
58737
58867
  this.options.logger.warn("Skipping invalid reminder file", {
58738
58868
  path: reminderPath,
58739
- error: err instanceof Error ? err.message : String(err)
58869
+ error: (0, error_utils_js_1.toErrorMessage)(err)
58740
58870
  });
58741
58871
  }
58742
58872
  }
@@ -58797,7 +58927,7 @@ var require_staging_service = __commonJS({
58797
58927
  }
58798
58928
  this.options.logger.warn("Skipping invalid consumed reminder file", {
58799
58929
  path: reminderPath,
58800
- error: err instanceof Error ? err.message : String(err)
58930
+ error: (0, error_utils_js_1.toErrorMessage)(err)
58801
58931
  });
58802
58932
  }
58803
58933
  }
@@ -58949,6 +59079,7 @@ var require_handler_registry2 = __commonJS({
58949
59079
  exports2.HandlerRegistryImpl = void 0;
58950
59080
  var transcript_content_js_1 = require_transcript_content();
58951
59081
  var structured_logging_js_1 = require_structured_logging();
59082
+ var error_utils_js_1 = require_error_utils();
58952
59083
  var HandlerRegistryImpl = class {
58953
59084
  options;
58954
59085
  handlers = [];
@@ -59059,7 +59190,7 @@ var require_handler_registry2 = __commonJS({
59059
59190
  log.error("Handler execution failed", {
59060
59191
  handlerId: handler.id,
59061
59192
  hook,
59062
- error: err instanceof Error ? err.message : String(err)
59193
+ error: (0, error_utils_js_1.toErrorMessage)(err)
59063
59194
  });
59064
59195
  }
59065
59196
  }
@@ -59105,7 +59236,7 @@ var require_handler_registry2 = __commonJS({
59105
59236
  (0, structured_logging_js_1.logEvent)(this.options.logger, structured_logging_js_1.LogEvents.eventProcessed(logContext, { handlerId: handler.id, success: true }, { durationMs }));
59106
59237
  } catch (err) {
59107
59238
  const durationMs = Date.now() - startTime;
59108
- const errorMsg = err instanceof Error ? err.message : String(err);
59239
+ const errorMsg = (0, error_utils_js_1.toErrorMessage)(err);
59109
59240
  (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
59241
  this.options.logger.error("Transcript handler failed", {
59111
59242
  handlerId: handler.id,
@@ -59536,6 +59667,7 @@ var require_state_service = __commonJS({
59536
59667
  var node_path_1 = require("node:path");
59537
59668
  var path_resolver_js_1 = require_path_resolver();
59538
59669
  var errors_js_1 = require_errors6();
59670
+ var error_utils_js_1 = require_error_utils();
59539
59671
  var errors_js_2 = require_errors6();
59540
59672
  Object.defineProperty(exports2, "StateNotFoundError", { enumerable: true, get: function() {
59541
59673
  return errors_js_2.StateNotFoundError;
@@ -59647,7 +59779,7 @@ var require_state_service = __commonJS({
59647
59779
  } catch (cleanupErr) {
59648
59780
  this.logger?.trace("Failed to cleanup temp file", {
59649
59781
  tmpPath,
59650
- error: cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr)
59782
+ error: (0, error_utils_js_1.toErrorMessage)(cleanupErr)
59651
59783
  });
59652
59784
  }
59653
59785
  throw err;
@@ -59773,7 +59905,7 @@ var require_state_service = __commonJS({
59773
59905
  } catch (err) {
59774
59906
  this.logger?.warn("Failed to preload state file", {
59775
59907
  file,
59776
- error: err instanceof Error ? err.message : String(err)
59908
+ error: (0, error_utils_js_1.toErrorMessage)(err)
59777
59909
  });
59778
59910
  }
59779
59911
  }
@@ -59799,7 +59931,7 @@ var require_state_service = __commonJS({
59799
59931
  this.logger?.warn("Corrupt state file detected", {
59800
59932
  path,
59801
59933
  reason,
59802
- error: error instanceof Error ? error.message : String(error)
59934
+ error: (0, error_utils_js_1.toErrorMessage)(error)
59803
59935
  });
59804
59936
  try {
59805
59937
  await fs.rename(path, bakPath);
@@ -59829,7 +59961,7 @@ var require_state_service = __commonJS({
59829
59961
  } catch (err) {
59830
59962
  this.logger?.warn("Failed to create dev mode backup", {
59831
59963
  path,
59832
- error: err instanceof Error ? err.message : String(err)
59964
+ error: (0, error_utils_js_1.toErrorMessage)(err)
59833
59965
  });
59834
59966
  }
59835
59967
  }
@@ -59892,12 +60024,17 @@ var require_typed_accessor = __commonJS({
59892
60024
  var SessionStateAccessor = class {
59893
60025
  stateService;
59894
60026
  descriptor;
59895
- constructor(stateService, descriptor) {
60027
+ journal;
60028
+ /** Descriptor filename without .json extension — used as journal file key */
60029
+ fileKey;
60030
+ constructor(stateService, descriptor, journal) {
59896
60031
  this.stateService = stateService;
59897
60032
  this.descriptor = descriptor;
60033
+ this.journal = journal;
59898
60034
  if (descriptor.scope !== "session") {
59899
60035
  throw new Error(`SessionStateAccessor requires a session-scoped descriptor, got: ${descriptor.scope}`);
59900
60036
  }
60037
+ this.fileKey = descriptor.filename.replace(/\.json$/, "");
59901
60038
  }
59902
60039
  /**
59903
60040
  * Read session state file.
@@ -59915,9 +60052,15 @@ var require_typed_accessor = __commonJS({
59915
60052
  */
59916
60053
  async write(sessionId, data) {
59917
60054
  const path = this.stateService.sessionStatePath(sessionId, this.descriptor.filename);
59918
- return this.stateService.write(path, data, this.descriptor.schema, {
60055
+ await this.stateService.write(path, data, this.descriptor.schema, {
59919
60056
  trackHistory: this.descriptor.trackHistory
59920
60057
  });
60058
+ if (this.journal) {
60059
+ try {
60060
+ await this.journal.appendIfChanged(sessionId, this.fileKey, data);
60061
+ } catch {
60062
+ }
60063
+ }
59921
60064
  }
59922
60065
  /**
59923
60066
  * Delete session state file.
@@ -59925,6 +60068,12 @@ var require_typed_accessor = __commonJS({
59925
60068
  async delete(sessionId) {
59926
60069
  const path = this.stateService.sessionStatePath(sessionId, this.descriptor.filename);
59927
60070
  await this.stateService.delete(path);
60071
+ if (this.journal) {
60072
+ try {
60073
+ await this.journal.appendDeletion(sessionId, this.fileKey);
60074
+ } catch {
60075
+ }
60076
+ }
59928
60077
  }
59929
60078
  /**
59930
60079
  * Get the path for a session state file.
@@ -60190,8 +60339,51 @@ var require_transcript_normalizer = __commonJS({
60190
60339
  exports2.parseUuid = parseUuid;
60191
60340
  exports2.renderTranscriptString = renderTranscriptString;
60192
60341
  var index_js_1 = require_state3();
60342
+ function buildRecapEntry(params) {
60343
+ const text = typeof params.rawText === "string" ? params.rawText.trim() : "";
60344
+ if (!text)
60345
+ return null;
60346
+ return {
60347
+ id: params.uuid ?? `line-${params.lineNumber}`,
60348
+ timestamp: new Date(params.timestamp ?? Date.now()),
60349
+ role: "system",
60350
+ type: "recap",
60351
+ content: text,
60352
+ metadata: {
60353
+ provider: "claude",
60354
+ lineNumber: params.lineNumber,
60355
+ recapSource: params.recapSource,
60356
+ leafUuid: params.leafUuid
60357
+ }
60358
+ };
60359
+ }
60193
60360
  function normalizeEntry(rawEntry, lineNumber) {
60194
60361
  const entryType = rawEntry.type;
60362
+ if (entryType === "summary") {
60363
+ const raw = rawEntry;
60364
+ const recap = buildRecapEntry({
60365
+ rawText: raw.summary,
60366
+ uuid: raw.uuid,
60367
+ timestamp: raw.timestamp,
60368
+ lineNumber,
60369
+ recapSource: "compaction",
60370
+ leafUuid: typeof raw.leafUuid === "string" ? raw.leafUuid : void 0
60371
+ });
60372
+ return recap ? [recap] : null;
60373
+ }
60374
+ if (entryType === "system") {
60375
+ const raw = rawEntry;
60376
+ if (raw.subtype !== "away_summary")
60377
+ return null;
60378
+ const recap = buildRecapEntry({
60379
+ rawText: raw.content,
60380
+ uuid: raw.uuid,
60381
+ timestamp: raw.timestamp,
60382
+ lineNumber,
60383
+ recapSource: "away"
60384
+ });
60385
+ return recap ? [recap] : null;
60386
+ }
60195
60387
  if (entryType !== "user" && entryType !== "assistant") {
60196
60388
  return null;
60197
60389
  }
@@ -60325,6 +60517,9 @@ var require_transcript_normalizer = __commonJS({
60325
60517
  return `[${timestamp}] ${role} TOOL_USE: ${String(toolContent.name)}`;
60326
60518
  } else if (type === "tool_result") {
60327
60519
  return `[${timestamp}] ${role} TOOL_RESULT`;
60520
+ } else if (type === "recap") {
60521
+ const content = typeof entry.content === "string" ? entry.content : "";
60522
+ return `[${timestamp}] RECAP: ${content}`;
60328
60523
  }
60329
60524
  return `[${timestamp}] ${role}: ${JSON.stringify(entry.content)}`;
60330
60525
  }).join("\n");
@@ -60343,6 +60538,7 @@ var require_transcript_excerpt_builder = __commonJS({
60343
60538
  exports2.extractTextContent = extractTextContent;
60344
60539
  exports2.getRawContentString = getRawContentString;
60345
60540
  var transcript_helpers_js_1 = require_transcript_helpers();
60541
+ var error_utils_js_1 = require_error_utils();
60346
60542
  function getBufferedEntries(buffer, head, count, bufferSize) {
60347
60543
  if (count === 0)
60348
60544
  return [];
@@ -60397,7 +60593,7 @@ var require_transcript_excerpt_builder = __commonJS({
60397
60593
  };
60398
60594
  } catch (err) {
60399
60595
  logger.error("Failed to extract transcript excerpt from buffer", {
60400
- error: err instanceof Error ? err.message : String(err)
60596
+ error: (0, error_utils_js_1.toErrorMessage)(err)
60401
60597
  });
60402
60598
  return {
60403
60599
  content: "",
@@ -60458,6 +60654,14 @@ var require_transcript_excerpt_builder = __commonJS({
60458
60654
  return null;
60459
60655
  }
60460
60656
  return `[SESSION_HINT]: ${entry.summary ?? ""}`;
60657
+ case "system": {
60658
+ if (entry.subtype !== "away_summary")
60659
+ return null;
60660
+ const content = entry.content;
60661
+ if (typeof content !== "string" || !content.trim())
60662
+ return null;
60663
+ return `[SESSION_RECAP]: ${content}`;
60664
+ }
60461
60665
  default:
60462
60666
  return null;
60463
60667
  }
@@ -63316,6 +63520,7 @@ var require_instrumented_llm_provider = __commonJS({
63316
63520
  var node_path_1 = require("node:path");
63317
63521
  var yaml_1 = __importDefault2(require_dist2());
63318
63522
  var types_1 = require_dist();
63523
+ var error_utils_js_1 = require_error_utils();
63319
63524
  var STATE_FILE = "llm-metrics.json";
63320
63525
  var DEFAULT_DEBOUNCE_MS = 500;
63321
63526
  function hasFallbackTracking(provider) {
@@ -63366,7 +63571,7 @@ var require_instrumented_llm_provider = __commonJS({
63366
63571
  }
63367
63572
  } catch (err) {
63368
63573
  this.config.logger.warn("Failed to load LLM metrics, starting fresh", {
63369
- error: err instanceof Error ? err.message : String(err)
63574
+ error: (0, error_utils_js_1.toErrorMessage)(err)
63370
63575
  });
63371
63576
  }
63372
63577
  }
@@ -63453,7 +63658,7 @@ var require_instrumented_llm_provider = __commonJS({
63453
63658
  this.config.logger.debug("Debug dump written", { path: basePath });
63454
63659
  } catch (dumpError) {
63455
63660
  this.config.logger.warn("Failed to write debug dump", {
63456
- error: dumpError instanceof Error ? dumpError.message : String(dumpError)
63661
+ error: (0, error_utils_js_1.toErrorMessage)(dumpError)
63457
63662
  });
63458
63663
  }
63459
63664
  }
@@ -63678,7 +63883,7 @@ var require_instrumented_llm_provider = __commonJS({
63678
63883
  });
63679
63884
  } catch (err) {
63680
63885
  this.config.logger.warn("Failed to persist LLM metrics", {
63681
- error: err instanceof Error ? err.message : String(err)
63886
+ error: (0, error_utils_js_1.toErrorMessage)(err)
63682
63887
  });
63683
63888
  }
63684
63889
  }
@@ -63954,6 +64159,7 @@ var require_daemon_health = __commonJS({
63954
64159
  var fs = __importStar(require("node:fs/promises"));
63955
64160
  var node_path_1 = require("node:path");
63956
64161
  var types_1 = require_dist();
64162
+ var error_utils_js_1 = require_error_utils();
63957
64163
  function healthFilePath(projectDir) {
63958
64164
  return (0, node_path_1.join)(projectDir, ".sidekick", "state", "daemon-health.json");
63959
64165
  }
@@ -64012,7 +64218,7 @@ var require_daemon_health = __commonJS({
64012
64218
  logger.warn("Failed to write daemon health", {
64013
64219
  from,
64014
64220
  to,
64015
- error: err instanceof Error ? err.message : String(err)
64221
+ error: (0, error_utils_js_1.toErrorMessage)(err)
64016
64222
  });
64017
64223
  return false;
64018
64224
  }
@@ -64099,6 +64305,7 @@ var require_user_profile_loader = __commonJS({
64099
64305
  var node_path_1 = require("node:path");
64100
64306
  var yaml_1 = require_dist2();
64101
64307
  var types_1 = require_dist();
64308
+ var error_utils_js_1 = require_error_utils();
64102
64309
  function loadUserProfile(options) {
64103
64310
  const home = options?.homeDir ?? (0, node_os_1.homedir)();
64104
64311
  const filePath = (0, node_path_1.join)(home, ".sidekick", "user.yaml");
@@ -64120,7 +64327,7 @@ var require_user_profile_loader = __commonJS({
64120
64327
  } catch (err) {
64121
64328
  options?.logger?.warn("Failed to read user profile", {
64122
64329
  path: filePath,
64123
- error: err instanceof Error ? err.message : String(err)
64330
+ error: (0, error_utils_js_1.toErrorMessage)(err)
64124
64331
  });
64125
64332
  return null;
64126
64333
  }
@@ -64187,9 +64394,9 @@ var require_dist4 = __commonJS({
64187
64394
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
64188
64395
  };
64189
64396
  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;
64397
+ 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;
64398
+ 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;
64399
+ 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
64400
  var types_1 = require_dist();
64194
64401
  Object.defineProperty(exports2, "TaskTypes", { enumerable: true, get: function() {
64195
64402
  return types_1.TaskTypes;
@@ -64234,6 +64441,12 @@ var require_dist4 = __commonJS({
64234
64441
  Object.defineProperty(exports2, "isPreCompactEvent", { enumerable: true, get: function() {
64235
64442
  return types_2.isPreCompactEvent;
64236
64443
  } });
64444
+ Object.defineProperty(exports2, "isSubagentStartEvent", { enumerable: true, get: function() {
64445
+ return types_2.isSubagentStartEvent;
64446
+ } });
64447
+ Object.defineProperty(exports2, "isSubagentStopEvent", { enumerable: true, get: function() {
64448
+ return types_2.isSubagentStopEvent;
64449
+ } });
64237
64450
  __exportStar(require_assets(), exports2);
64238
64451
  var claude_paths_1 = require_claude_paths();
64239
64452
  Object.defineProperty(exports2, "encodeProjectPath", { enumerable: true, get: function() {
@@ -64354,9 +64567,6 @@ var require_dist4 = __commonJS({
64354
64567
  Object.defineProperty(exports2, "PROJECT_STATUS_FILENAME", { enumerable: true, get: function() {
64355
64568
  return setup_status_service_1.PROJECT_STATUS_FILENAME;
64356
64569
  } });
64357
- Object.defineProperty(exports2, "LEGACY_USER_STATUS_FILENAME", { enumerable: true, get: function() {
64358
- return setup_status_service_1.LEGACY_USER_STATUS_FILENAME;
64359
- } });
64360
64570
  var api_key_detector_1 = require_api_key_detector();
64361
64571
  Object.defineProperty(exports2, "toScopeStatus", { enumerable: true, get: function() {
64362
64572
  return api_key_detector_1.toScopeStatus;
@@ -64425,12 +64635,21 @@ var require_dist4 = __commonJS({
64425
64635
  Object.defineProperty(exports2, "detectGitignoreStatus", { enumerable: true, get: function() {
64426
64636
  return gitignore_1.detectGitignoreStatus;
64427
64637
  } });
64638
+ Object.defineProperty(exports2, "detectLegacyGitignoreSection", { enumerable: true, get: function() {
64639
+ return gitignore_1.detectLegacyGitignoreSection;
64640
+ } });
64641
+ Object.defineProperty(exports2, "removeLegacyGitignoreSection", { enumerable: true, get: function() {
64642
+ return gitignore_1.removeLegacyGitignoreSection;
64643
+ } });
64428
64644
  Object.defineProperty(exports2, "SIDEKICK_SECTION_START", { enumerable: true, get: function() {
64429
64645
  return gitignore_1.SIDEKICK_SECTION_START;
64430
64646
  } });
64431
64647
  Object.defineProperty(exports2, "SIDEKICK_SECTION_END", { enumerable: true, get: function() {
64432
64648
  return gitignore_1.SIDEKICK_SECTION_END;
64433
64649
  } });
64650
+ Object.defineProperty(exports2, "SIDEKICK_GITIGNORE_HEADER", { enumerable: true, get: function() {
64651
+ return gitignore_1.SIDEKICK_GITIGNORE_HEADER;
64652
+ } });
64434
64653
  Object.defineProperty(exports2, "GITIGNORE_ENTRIES", { enumerable: true, get: function() {
64435
64654
  return gitignore_1.GITIGNORE_ENTRIES;
64436
64655
  } });
@@ -64583,6 +64802,10 @@ var require_dist4 = __commonJS({
64583
64802
  Object.defineProperty(exports2, "isInSandbox", { enumerable: true, get: function() {
64584
64803
  return sandbox_1.isInSandbox;
64585
64804
  } });
64805
+ var error_utils_1 = require_error_utils();
64806
+ Object.defineProperty(exports2, "toErrorMessage", { enumerable: true, get: function() {
64807
+ return error_utils_1.toErrorMessage;
64808
+ } });
64586
64809
  var git_status_1 = require_git_status();
64587
64810
  Object.defineProperty(exports2, "getGitFileStatus", { enumerable: true, get: function() {
64588
64811
  return git_status_1.getGitFileStatus;
@@ -64641,7 +64864,7 @@ var require_runtime = __commonJS({
64641
64864
  });
64642
64865
  } catch (err) {
64643
64866
  loggerFacade.error("Failed to load configuration", {
64644
- error: err instanceof Error ? err.message : String(err)
64867
+ error: (0, core_1.toErrorMessage)(err)
64645
64868
  });
64646
64869
  throw err;
64647
64870
  }
@@ -64809,7 +65032,7 @@ var require_dev_mode_guard = __commonJS({
64809
65032
  }
64810
65033
  } catch (err) {
64811
65034
  logger.warn(`Failed to auto-correct devMode flag for ${callerLabel}`, {
64812
- error: err instanceof Error ? err.message : String(err),
65035
+ error: (0, core_1.toErrorMessage)(err),
64813
65036
  caller: callerLabel
64814
65037
  });
64815
65038
  }
@@ -64827,7 +65050,7 @@ var require_dev_mode_guard = __commonJS({
64827
65050
  }
64828
65051
  } catch (err) {
64829
65052
  logger.warn(`Failed to check plugin/dev-mode status for ${callerLabel}, proceeding normally`, {
64830
- error: err instanceof Error ? err.message : String(err),
65053
+ error: (0, core_1.toErrorMessage)(err),
64831
65054
  caller: callerLabel
64832
65055
  });
64833
65056
  }
@@ -71853,6 +72076,7 @@ var require_reminder_utils = __commonJS({
71853
72076
  var node_path_1 = require("node:path");
71854
72077
  var yaml = __importStar(require_js_yaml());
71855
72078
  var zod_1 = require_zod2();
72079
+ var core_1 = require_dist4();
71856
72080
  var ReminderDefinitionSchema = zod_1.z.object({
71857
72081
  id: zod_1.z.string(),
71858
72082
  blocking: zod_1.z.boolean(),
@@ -71905,7 +72129,7 @@ var require_reminder_utils = __commonJS({
71905
72129
  if (logger) {
71906
72130
  logger.error("Failed to load reminder", {
71907
72131
  reminderId,
71908
- error: err instanceof Error ? err.message : String(err)
72132
+ error: (0, core_1.toErrorMessage)(err)
71909
72133
  });
71910
72134
  } else {
71911
72135
  console.error(`Failed to load reminder ${reminderId}:`, err);
@@ -72645,7 +72869,7 @@ var require_stage_pause_and_reflect = __commonJS({
72645
72869
  (0, staging_handler_utils_js_1.createStagingHandler)(context, {
72646
72870
  id: "reminders:stage-pause-and-reflect",
72647
72871
  priority: 80,
72648
- filter: { kind: "transcript", eventTypes: ["ToolCall"] },
72872
+ filter: { kind: "transcript", eventTypes: ["ToolResult"] },
72649
72873
  execute: async (event, ctx) => {
72650
72874
  if (!(0, types_1.isTranscriptEvent)(event))
72651
72875
  return void 0;
@@ -74328,17 +74552,15 @@ var require_track_verification_tools = __commonJS({
74328
74552
  var state_js_1 = require_state4();
74329
74553
  var FILE_EDIT_TOOLS = ["Write", "Edit", "MultiEdit"];
74330
74554
  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
- }
74555
+ var MAX_PENDING_TOOL_CALLS = 100;
74335
74556
  function registerTrackVerificationTools(context) {
74336
74557
  if (!(0, types_1.isDaemonContext)(context))
74337
74558
  return;
74559
+ const pendingBySession = /* @__PURE__ */ new Map();
74338
74560
  context.handlers.register({
74339
74561
  id: "reminders:track-verification-tools",
74340
74562
  priority: 60,
74341
- filter: { kind: "transcript", eventTypes: ["ToolCall"] },
74563
+ filter: { kind: "transcript", eventTypes: ["ToolCall", "ToolResult"] },
74342
74564
  handler: async (event, ctx) => {
74343
74565
  if (!(0, types_1.isTranscriptEvent)(event))
74344
74566
  return;
@@ -74350,22 +74572,66 @@ var require_track_verification_tools = __commonJS({
74350
74572
  const sessionId = event.context?.sessionId;
74351
74573
  if (!sessionId)
74352
74574
  return;
74353
- const toolName = event.payload.toolName;
74354
- if (!toolName)
74575
+ if (event.eventType === "ToolCall") {
74576
+ const toolUseId = event.payload.entry.id;
74577
+ const toolName = event.payload.toolName;
74578
+ if (!toolUseId || !toolName)
74579
+ return;
74580
+ const entry = event.payload.entry;
74581
+ const input = entry?.input ?? {};
74582
+ let sessionMap = pendingBySession.get(sessionId);
74583
+ if (!sessionMap) {
74584
+ sessionMap = /* @__PURE__ */ new Map();
74585
+ pendingBySession.set(sessionId, sessionMap);
74586
+ }
74587
+ if (sessionMap.size >= MAX_PENDING_TOOL_CALLS) {
74588
+ const oldest = sessionMap.keys().next().value;
74589
+ if (oldest)
74590
+ sessionMap.delete(oldest);
74591
+ }
74592
+ sessionMap.set(toolUseId, { toolName, input });
74355
74593
  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);
74594
+ }
74595
+ if (event.eventType === "ToolResult") {
74596
+ const toolUseId = event.payload.entry.tool_use_id;
74597
+ if (!toolUseId)
74598
+ return;
74599
+ const sessionMap = pendingBySession.get(sessionId);
74600
+ const pending = sessionMap?.get(toolUseId);
74601
+ if (!pending)
74602
+ return;
74603
+ sessionMap.delete(toolUseId);
74604
+ if (sessionMap.size === 0)
74605
+ pendingBySession.delete(sessionId);
74606
+ const { toolName, input } = pending;
74607
+ const config = (0, types_js_1.getRemindersConfig)(context.config);
74608
+ const verificationTools = config.verification_tools ?? {};
74609
+ const runners = config.command_runners ?? [];
74610
+ const remindersState = (0, state_js_1.createRemindersState)(daemonCtx.stateService);
74611
+ const stateResult = await remindersState.verificationTools.read(sessionId);
74612
+ const toolsState = { ...stateResult.data };
74613
+ if (FILE_EDIT_TOOLS.includes(toolName)) {
74614
+ await handleFileEdit(input, daemonCtx, sessionId, verificationTools, toolsState, remindersState);
74615
+ } else if (toolName === "Bash") {
74616
+ await handleBashCommand(input, daemonCtx, sessionId, verificationTools, toolsState, remindersState, runners);
74617
+ }
74366
74618
  }
74367
74619
  }
74368
74620
  });
74621
+ context.handlers.register({
74622
+ id: "reminders:track-verification-tools-cleanup",
74623
+ priority: 60,
74624
+ filter: { kind: "hook", hooks: ["UserPromptSubmit", "Stop"] },
74625
+ // eslint-disable-next-line @typescript-eslint/require-await -- sync cleanup, async required by EventHandler type
74626
+ handler: async (event, _ctx) => {
74627
+ if (!(0, types_1.isHookEvent)(event))
74628
+ return;
74629
+ const sessionId = event.context?.sessionId;
74630
+ if (!sessionId)
74631
+ return;
74632
+ pendingBySession.delete(sessionId);
74633
+ }
74634
+ });
74369
74635
  }
74370
74636
  async function stageToolsForFiles(filePaths, daemonCtx, sessionId, verificationTools, toolsState, remindersState, triggeredBy = "file_edit") {
74371
74637
  const existingReminders = await daemonCtx.staging.listReminders("Stop");
@@ -74470,7 +74736,7 @@ var require_track_verification_tools = __commonJS({
74470
74736
  toolName,
74471
74737
  reminderId,
74472
74738
  sessionId,
74473
- error: error instanceof Error ? error.message : String(error)
74739
+ error: (0, core_1.toErrorMessage)(error)
74474
74740
  });
74475
74741
  }
74476
74742
  }
@@ -74484,8 +74750,8 @@ var require_track_verification_tools = __commonJS({
74484
74750
  await remindersState.verificationTools.write(sessionId, toolsState);
74485
74751
  return anyStaged;
74486
74752
  }
74487
- async function handleFileEdit(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState) {
74488
- const filePath = extractToolInput(event)?.file_path;
74753
+ async function handleFileEdit(input, daemonCtx, sessionId, verificationTools, toolsState, remindersState) {
74754
+ const filePath = input.file_path;
74489
74755
  if (!filePath)
74490
74756
  return;
74491
74757
  const projectDir = daemonCtx.paths?.projectDir;
@@ -74493,8 +74759,8 @@ var require_track_verification_tools = __commonJS({
74493
74759
  return;
74494
74760
  await stageToolsForFiles([filePath], daemonCtx, sessionId, verificationTools, toolsState, remindersState);
74495
74761
  }
74496
- async function handleBashCommand(event, daemonCtx, sessionId, verificationTools, toolsState, remindersState, runners = []) {
74497
- const command = extractToolInput(event)?.command;
74762
+ async function handleBashCommand(input, daemonCtx, sessionId, verificationTools, toolsState, remindersState, runners = []) {
74763
+ const command = input.command;
74498
74764
  if (!command)
74499
74765
  return;
74500
74766
  let anyUnstaged = false;
@@ -74923,7 +75189,7 @@ var require_stage_persona_reminders = __commonJS({
74923
75189
  } catch (err) {
74924
75190
  logger.error("Failed to restage persona reminders", {
74925
75191
  sessionId,
74926
- error: err instanceof Error ? err.message : String(err)
75192
+ error: (0, core_1.toErrorMessage)(err)
74927
75193
  });
74928
75194
  }
74929
75195
  }
@@ -75159,6 +75425,38 @@ var require_stage_user_profile_reminders = __commonJS({
75159
75425
  }
75160
75426
  });
75161
75427
 
75428
+ // ../feature-reminders/dist/handlers/staging/cleanup-on-stop.js
75429
+ var require_cleanup_on_stop = __commonJS({
75430
+ "../feature-reminders/dist/handlers/staging/cleanup-on-stop.js"(exports2) {
75431
+ "use strict";
75432
+ Object.defineProperty(exports2, "__esModule", { value: true });
75433
+ exports2.registerCleanupOnStop = registerCleanupOnStop;
75434
+ var types_1 = require_dist();
75435
+ function registerCleanupOnStop(context) {
75436
+ if (!(0, types_1.isDaemonContext)(context))
75437
+ return;
75438
+ context.handlers.register({
75439
+ id: "reminders:cleanup-on-stop",
75440
+ priority: 50,
75441
+ filter: { kind: "hook", hooks: ["Stop"] },
75442
+ handler: async (event, ctx) => {
75443
+ if (!(0, types_1.isHookEvent)(event))
75444
+ return;
75445
+ if (!(0, types_1.isDaemonContext)(ctx))
75446
+ return;
75447
+ const daemonCtx = ctx;
75448
+ const sessionId = event.context?.sessionId;
75449
+ if (!sessionId)
75450
+ return;
75451
+ if (daemonCtx.orchestrator) {
75452
+ await daemonCtx.orchestrator.onStop(sessionId);
75453
+ }
75454
+ }
75455
+ });
75456
+ }
75457
+ }
75458
+ });
75459
+
75162
75460
  // ../feature-reminders/dist/handlers/staging/index.js
75163
75461
  var require_staging2 = __commonJS({
75164
75462
  "../feature-reminders/dist/handlers/staging/index.js"(exports2) {
@@ -75172,6 +75470,7 @@ var require_staging2 = __commonJS({
75172
75470
  var unstage_verify_completion_1 = require_unstage_verify_completion();
75173
75471
  var stage_persona_reminders_1 = require_stage_persona_reminders();
75174
75472
  var stage_user_profile_reminders_1 = require_stage_user_profile_reminders();
75473
+ var cleanup_on_stop_1 = require_cleanup_on_stop();
75175
75474
  function registerStagingHandlers(context) {
75176
75475
  (0, stage_default_user_prompt_1.registerStageDefaultUserPrompt)(context);
75177
75476
  (0, stage_pause_and_reflect_1.registerStagePauseAndReflect)(context);
@@ -75180,6 +75479,7 @@ var require_staging2 = __commonJS({
75180
75479
  (0, unstage_verify_completion_1.registerUnstageVerifyCompletion)(context);
75181
75480
  (0, stage_persona_reminders_1.registerStagePersonaReminders)(context);
75182
75481
  (0, stage_user_profile_reminders_1.registerStageUserProfileReminders)(context);
75482
+ (0, cleanup_on_stop_1.registerCleanupOnStop)(context);
75183
75483
  }
75184
75484
  }
75185
75485
  });
@@ -75900,7 +76200,7 @@ var require_orchestrator = __commonJS({
75900
76200
  } catch (err) {
75901
76201
  this.deps.logger.warn("Failed to unstage VC reminders after P&R staged", {
75902
76202
  sessionId,
75903
- error: err instanceof Error ? err.message : String(err)
76203
+ error: (0, core_1.toErrorMessage)(err)
75904
76204
  });
75905
76205
  }
75906
76206
  }
@@ -75924,27 +76224,10 @@ var require_orchestrator = __commonJS({
75924
76224
  } catch (err) {
75925
76225
  this.deps.logger.warn("Failed to reset P&R baseline after VC consumed", {
75926
76226
  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)
76227
+ error: (0, core_1.toErrorMessage)(err)
75946
76228
  });
75947
76229
  }
76230
+ await this.unstagePauseAndReflect(sessionId, "vc_consumed_cascade", "cascade_from_verify_completion");
75948
76231
  }
75949
76232
  }
75950
76233
  /**
@@ -75961,7 +76244,43 @@ var require_orchestrator = __commonJS({
75961
76244
  } catch (err) {
75962
76245
  this.deps.logger.warn("Failed to clear P&R baseline on UserPromptSubmit", {
75963
76246
  sessionId,
75964
- error: err instanceof Error ? err.message : String(err)
76247
+ error: (0, core_1.toErrorMessage)(err)
76248
+ });
76249
+ }
76250
+ }
76251
+ /**
76252
+ * Called when Stop hook fires.
76253
+ *
76254
+ * P&R is designed to interrupt runaway execution — once the agent stops,
76255
+ * it's irrelevant. This is defensive: Rule 4 (VC consumed → unstage P&R)
76256
+ * covers the VC case, but this handles the no-VC case where P&R would
76257
+ * otherwise linger on PreToolUse.
76258
+ */
76259
+ async onStop(sessionId) {
76260
+ await this.unstagePauseAndReflect(sessionId, "agent_stopping", "stop_hook");
76261
+ }
76262
+ /**
76263
+ * Delete P&R from PreToolUse staging and log the event.
76264
+ * Shared by Rule 4 (VC consumed → unstage P&R) and onStop (agent stopping).
76265
+ */
76266
+ async unstagePauseAndReflect(sessionId, reason, triggeredBy) {
76267
+ try {
76268
+ const staging = this.deps.getStagingService(sessionId);
76269
+ const deleted = await staging.deleteReminder("PreToolUse", types_js_1.ReminderIds.PAUSE_AND_REFLECT);
76270
+ if (deleted) {
76271
+ (0, core_1.logEvent)(this.deps.logger.child({ context: { sessionId } }), events_js_1.ReminderEvents.reminderUnstaged({ sessionId }, {
76272
+ reminderName: types_js_1.ReminderIds.PAUSE_AND_REFLECT,
76273
+ hookName: "PreToolUse",
76274
+ reason,
76275
+ triggeredBy
76276
+ }));
76277
+ }
76278
+ this.deps.logger.debug("P&R unstaged", { sessionId, deleted, reason });
76279
+ } catch (err) {
76280
+ this.deps.logger.warn("Failed to unstage P&R", {
76281
+ sessionId,
76282
+ reason,
76283
+ error: (0, core_1.toErrorMessage)(err)
75965
76284
  });
75966
76285
  }
75967
76286
  }
@@ -76130,6 +76449,7 @@ var require_hook = __commonJS({
76130
76449
  exports2.isHookCommand = isHookCommand;
76131
76450
  exports2.getHookName = getHookName;
76132
76451
  var core_1 = require_dist4();
76452
+ var types_1 = require_dist();
76133
76453
  var context_js_1 = require_context2();
76134
76454
  function truncateForLog(raw) {
76135
76455
  const entries = Object.entries(raw);
@@ -76158,15 +76478,7 @@ var require_hook = __commonJS({
76158
76478
  }
76159
76479
  return truncateForLog(filtered);
76160
76480
  }
76161
- var VALID_HOOK_NAMES = /* @__PURE__ */ new Set([
76162
- "SessionStart",
76163
- "SessionEnd",
76164
- "UserPromptSubmit",
76165
- "PreToolUse",
76166
- "PostToolUse",
76167
- "Stop",
76168
- "PreCompact"
76169
- ]);
76481
+ var VALID_HOOK_NAMES = new Set(types_1.HOOK_NAMES);
76170
76482
  function validateHookName(hookEventName) {
76171
76483
  return VALID_HOOK_NAMES.has(hookEventName) ? hookEventName : void 0;
76172
76484
  }
@@ -76177,7 +76489,9 @@ var require_hook = __commonJS({
76177
76489
  "pre-tool-use": "PreToolUse",
76178
76490
  "post-tool-use": "PostToolUse",
76179
76491
  stop: "Stop",
76180
- "pre-compact": "PreCompact"
76492
+ "pre-compact": "PreCompact",
76493
+ "subagent-start": "SubagentStart",
76494
+ "subagent-stop": "SubagentStop"
76181
76495
  };
76182
76496
  function extractToolFields(raw) {
76183
76497
  const toolName = typeof raw.tool_name === "string" ? raw.tool_name : "unknown";
@@ -76279,11 +76593,46 @@ var require_hook = __commonJS({
76279
76593
  }
76280
76594
  };
76281
76595
  }
76596
+ function buildSubagentStartEvent(context, input) {
76597
+ return {
76598
+ kind: "hook",
76599
+ hook: "SubagentStart",
76600
+ context,
76601
+ payload: {
76602
+ transcriptPath: input.transcriptPath,
76603
+ agentId: context.agentId,
76604
+ agentType: context.agentType
76605
+ }
76606
+ };
76607
+ }
76608
+ function buildSubagentStopEvent(context, input) {
76609
+ const raw = input.raw;
76610
+ const agentTranscriptPath = typeof raw.agent_transcript_path === "string" ? raw.agent_transcript_path : "";
76611
+ const lastAssistantMessage = typeof raw.last_assistant_message === "string" ? raw.last_assistant_message : "";
76612
+ const permissionMode = input.permissionMode ?? "default";
76613
+ const stopHookActive = typeof raw.stop_hook_active === "boolean" ? raw.stop_hook_active : void 0;
76614
+ return {
76615
+ kind: "hook",
76616
+ hook: "SubagentStop",
76617
+ context,
76618
+ payload: {
76619
+ transcriptPath: input.transcriptPath,
76620
+ permissionMode,
76621
+ agentId: context.agentId,
76622
+ agentType: context.agentType,
76623
+ agentTranscriptPath,
76624
+ lastAssistantMessage,
76625
+ ...stopHookActive !== void 0 && { stopHookActive }
76626
+ }
76627
+ };
76628
+ }
76282
76629
  function buildHookEvent(hookName, input, correlationId) {
76283
76630
  const context = {
76284
76631
  sessionId: input.sessionId,
76285
76632
  timestamp: Date.now(),
76286
- correlationId
76633
+ correlationId,
76634
+ ...input.agentId !== void 0 && { agentId: input.agentId },
76635
+ ...input.agentType !== void 0 && { agentType: input.agentType }
76287
76636
  };
76288
76637
  switch (hookName) {
76289
76638
  case "SessionStart":
@@ -76300,6 +76649,22 @@ var require_hook = __commonJS({
76300
76649
  return buildStopEvent(context, input);
76301
76650
  case "PreCompact":
76302
76651
  return buildPreCompactEvent(context, input);
76652
+ case "SubagentStart": {
76653
+ const subagentContext = {
76654
+ ...context,
76655
+ agentId: input.agentId ?? "",
76656
+ agentType: input.agentType ?? ""
76657
+ };
76658
+ return buildSubagentStartEvent(subagentContext, input);
76659
+ }
76660
+ case "SubagentStop": {
76661
+ const subagentContext = {
76662
+ ...context,
76663
+ agentId: input.agentId ?? "",
76664
+ agentType: input.agentType ?? ""
76665
+ };
76666
+ return buildSubagentStopEvent(subagentContext, input);
76667
+ }
76303
76668
  }
76304
76669
  }
76305
76670
  function mergeHookResponses(daemonResponse, cliResponse) {
@@ -76321,6 +76686,10 @@ ${daemonResponse.additionalContext}` : cliResponse.additionalContext;
76321
76686
  return merged;
76322
76687
  }
76323
76688
  async function handleHookCommand(hookName, options, logger, stdout) {
76689
+ if (process.env.SIDEKICK_SUBPROCESS === "1") {
76690
+ stdout.write("{}\n");
76691
+ return { exitCode: 0, output: "{}" };
76692
+ }
76324
76693
  const { projectRoot, hookInput, correlationId, runtime } = options;
76325
76694
  const startTime = Date.now();
76326
76695
  const logContext = {
@@ -76429,7 +76798,7 @@ var require_hook_command = __commonJS({
76429
76798
  return void 0;
76430
76799
  } catch (err) {
76431
76800
  logger.error("Failed to load safe-word-liveness.yaml", {
76432
- error: err instanceof Error ? err.message : String(err),
76801
+ error: (0, core_1.toErrorMessage)(err),
76433
76802
  projectRoot
76434
76803
  });
76435
76804
  return void 0;
@@ -76512,6 +76881,17 @@ var require_hook_command = __commonJS({
76512
76881
  addUserMessage(response, internal.userMessage);
76513
76882
  return response;
76514
76883
  }
76884
+ function translateSubagentStart(internal) {
76885
+ const response = {};
76886
+ if (internal.additionalContext) {
76887
+ response.hookSpecificOutput = {
76888
+ hookEventName: "SubagentStart",
76889
+ additionalContext: internal.additionalContext
76890
+ };
76891
+ }
76892
+ addUserMessage(response, internal.userMessage);
76893
+ return response;
76894
+ }
76515
76895
  var TRANSLATORS = {
76516
76896
  SessionStart: translateSessionStart,
76517
76897
  SessionEnd: () => ({}),
@@ -76519,7 +76899,10 @@ var require_hook_command = __commonJS({
76519
76899
  PreToolUse: translatePreToolUse,
76520
76900
  PostToolUse: translatePostToolUse,
76521
76901
  Stop: translateStop,
76522
- PreCompact: () => ({})
76902
+ PreCompact: () => ({}),
76903
+ SubagentStart: translateSubagentStart,
76904
+ // SubagentStop shares Stop's blocking semantics verbatim per Claude Code docs.
76905
+ SubagentStop: translateStop
76523
76906
  };
76524
76907
  function translateToClaudeCodeFormat(hookName, internal) {
76525
76908
  return TRANSLATORS[hookName](internal);
@@ -76532,13 +76915,17 @@ var require_hook_command = __commonJS({
76532
76915
  "post-tool-use": "PostToolUse",
76533
76916
  stop: "Stop",
76534
76917
  "pre-compact": "PreCompact",
76918
+ "subagent-start": "SubagentStart",
76919
+ "subagent-stop": "SubagentStop",
76535
76920
  SessionStart: "SessionStart",
76536
76921
  SessionEnd: "SessionEnd",
76537
76922
  UserPromptSubmit: "UserPromptSubmit",
76538
76923
  PreToolUse: "PreToolUse",
76539
76924
  PostToolUse: "PostToolUse",
76540
76925
  Stop: "Stop",
76541
- PreCompact: "PreCompact"
76926
+ PreCompact: "PreCompact",
76927
+ SubagentStart: "SubagentStart",
76928
+ SubagentStop: "SubagentStop"
76542
76929
  };
76543
76930
  function parseHookArg(arg) {
76544
76931
  return arg ? HOOK_ARG_TO_NAME[arg] : void 0;
@@ -76571,7 +76958,7 @@ var require_hook_command = __commonJS({
76571
76958
  return configured;
76572
76959
  } catch (err) {
76573
76960
  logger.warn("Failed to auto-configure project", {
76574
- error: err instanceof Error ? err.message : String(err),
76961
+ error: (0, core_1.toErrorMessage)(err),
76575
76962
  projectRoot
76576
76963
  });
76577
76964
  return false;
@@ -76584,7 +76971,7 @@ var require_hook_command = __commonJS({
76584
76971
  state = await setupService.getSetupState();
76585
76972
  } catch (err) {
76586
76973
  logger.warn("Failed to check setup state, assuming healthy", {
76587
- error: err instanceof Error ? err.message : String(err),
76974
+ error: (0, core_1.toErrorMessage)(err),
76588
76975
  hookName,
76589
76976
  projectRoot
76590
76977
  });
@@ -76622,7 +77009,7 @@ var require_hook_command = __commonJS({
76622
77009
  }
76623
77010
  } catch (err) {
76624
77011
  logger.warn("Failed to check setup status for daemon start, proceeding anyway", {
76625
- error: err instanceof Error ? err.message : String(err)
77012
+ error: (0, core_1.toErrorMessage)(err)
76626
77013
  });
76627
77014
  }
76628
77015
  try {
@@ -76632,7 +77019,7 @@ var require_hook_command = __commonJS({
76632
77019
  await (0, core_1.updateDaemonHealth)(projectRoot, "healthy", logger);
76633
77020
  return true;
76634
77021
  } catch (err) {
76635
- const errorMessage = err instanceof Error ? err.message : String(err);
77022
+ const errorMessage = (0, core_1.toErrorMessage)(err);
76636
77023
  await (0, core_1.updateDaemonHealth)(projectRoot, "failed", logger, errorMessage);
76637
77024
  return false;
76638
77025
  }
@@ -76645,13 +77032,17 @@ var require_hook_command = __commonJS({
76645
77032
  } catch (err) {
76646
77033
  logger.warn("Failed to parse internal hook response", {
76647
77034
  hookName,
76648
- error: err instanceof Error ? err.message : String(err),
77035
+ error: (0, core_1.toErrorMessage)(err),
76649
77036
  output
76650
77037
  });
76651
77038
  return {};
76652
77039
  }
76653
77040
  }
76654
77041
  async function handleUnifiedHookCommand(hookName, options, logger, stdout) {
77042
+ if (process.env.SIDEKICK_SUBPROCESS === "1") {
77043
+ stdout.write("{}\n");
77044
+ return { exitCode: 0, output: "{}" };
77045
+ }
76655
77046
  const { projectRoot, hookInput, correlationId, runtime, forceDevMode } = options;
76656
77047
  logger.debug("Unified hook command invoked", { hookName, sessionId: hookInput.sessionId });
76657
77048
  const devModeGuard = await (0, dev_mode_guard_js_1.checkDevModeConflict)(projectRoot, forceDevMode, logger, hookName);
@@ -77420,7 +77811,7 @@ var require_persona_selection = __commonJS({
77420
77811
  } catch (err) {
77421
77812
  ctx.logger.warn("Failed to ensure persona for session", {
77422
77813
  sessionId,
77423
- error: err instanceof Error ? err.message : String(err)
77814
+ error: (0, core_1.toErrorMessage)(err)
77424
77815
  });
77425
77816
  }
77426
77817
  }
@@ -78180,7 +78571,7 @@ var require_update_summary = __commonJS({
78180
78571
  ctx.logger.error("performAnalysis failed", {
78181
78572
  sessionId,
78182
78573
  reason,
78183
- error: err instanceof Error ? err.message : String(err)
78574
+ error: (0, core_1.toErrorMessage)(err)
78184
78575
  });
78185
78576
  }
78186
78577
  }
@@ -78582,7 +78973,7 @@ var require_resume_discovery = __commonJS({
78582
78973
  }
78583
78974
  config.logger?.warn("Failed to discover previous resume message", {
78584
78975
  sessionsDir: config.sessionsDir,
78585
- error: error instanceof Error ? error.message : String(error)
78976
+ error: (0, core_1.toErrorMessage)(error)
78586
78977
  });
78587
78978
  return NOT_FOUND;
78588
78979
  }
@@ -80339,7 +80730,7 @@ Examples:
80339
80730
  }
80340
80731
  const event = core_1.LogEvents.statuslineError(eventContext, "unknown", {
80341
80732
  fallbackUsed: true,
80342
- error: error instanceof Error ? error.message : String(error)
80733
+ error: (0, core_1.toErrorMessage)(error)
80343
80734
  });
80344
80735
  (0, core_1.logEvent)(logger, event);
80345
80736
  logger.warn("Statusline render failed", { durationMs });
@@ -80357,6 +80748,7 @@ var require_ui = __commonJS({
80357
80748
  exports2.handleUiCommand = handleUiCommand;
80358
80749
  var node_child_process_1 = require("node:child_process");
80359
80750
  var node_path_1 = require("node:path");
80751
+ var core_1 = require_dist4();
80360
80752
  function resolveUiPackageDir() {
80361
80753
  const cliCommandsDir = __dirname;
80362
80754
  const cliPackageDir = (0, node_path_1.resolve)(cliCommandsDir, "..", "..");
@@ -80386,7 +80778,7 @@ var require_ui = __commonJS({
80386
80778
  logger.debug("Browser open command executed", { command, url });
80387
80779
  } catch (err) {
80388
80780
  logger.warn("Failed to open browser", {
80389
- error: err instanceof Error ? err.message : String(err)
80781
+ error: (0, core_1.toErrorMessage)(err)
80390
80782
  });
80391
80783
  }
80392
80784
  }
@@ -80692,7 +81084,7 @@ var require_persona2 = __commonJS({
80692
81084
  }
80693
81085
  return writeJsonResponse(stdout, { success: true, personaId, previousPersonaId }, 0);
80694
81086
  } catch (err) {
80695
- const errorMsg = err instanceof Error ? err.message : String(err);
81087
+ const errorMsg = (0, core_1.toErrorMessage)(err);
80696
81088
  logger.error("Failed to set persona", { error: errorMsg });
80697
81089
  return writeJsonResponse(stdout, { success: false, error: errorMsg }, 1);
80698
81090
  }
@@ -80716,7 +81108,7 @@ var require_persona2 = __commonJS({
80716
81108
  logger.info("Persona cleared", { previousPersonaId: previousPersonaId ?? "(none)" });
80717
81109
  return writeJsonResponse(stdout, { success: true, personaId: null, previousPersonaId }, 0);
80718
81110
  } catch (err) {
80719
- const errorMsg = err instanceof Error ? err.message : String(err);
81111
+ const errorMsg = (0, core_1.toErrorMessage)(err);
80720
81112
  logger.error("Failed to clear persona", { error: errorMsg });
80721
81113
  return writeJsonResponse(stdout, { success: false, error: errorMsg }, 1);
80722
81114
  }
@@ -80761,7 +81153,7 @@ var require_persona2 = __commonJS({
80761
81153
  return writeJsonResponse(stdout, { error: `Failed to read generated file: ${statePath}` }, 1);
80762
81154
  }
80763
81155
  } catch (err) {
80764
- const errorMsg = err instanceof Error ? err.message : String(err);
81156
+ const errorMsg = (0, core_1.toErrorMessage)(err);
80765
81157
  logger.error("Persona test failed", { error: errorMsg });
80766
81158
  return writeJsonResponse(stdout, { error: errorMsg }, 1);
80767
81159
  } finally {
@@ -80789,7 +81181,7 @@ var require_persona2 = __commonJS({
80789
81181
  filePath: result.filePath
80790
81182
  }, 0);
80791
81183
  } catch (err) {
80792
- const errorMsg = err instanceof Error ? err.message : String(err);
81184
+ const errorMsg = (0, core_1.toErrorMessage)(err);
80793
81185
  logger.error("Failed to pin persona", { error: errorMsg });
80794
81186
  return writeJsonResponse(stdout, { success: false, error: errorMsg }, 1);
80795
81187
  }
@@ -80813,7 +81205,7 @@ var require_persona2 = __commonJS({
80813
81205
  previousPersonaId
80814
81206
  }, 0);
80815
81207
  } catch (err) {
80816
- const errorMsg = err instanceof Error ? err.message : String(err);
81208
+ const errorMsg = (0, core_1.toErrorMessage)(err);
80817
81209
  logger.error("Failed to unpin persona", { error: errorMsg });
80818
81210
  return writeJsonResponse(stdout, { success: false, error: errorMsg }, 1);
80819
81211
  }
@@ -80924,7 +81316,7 @@ var require_config3 = __commonJS({
80924
81316
  logger
80925
81317
  });
80926
81318
  } catch (err) {
80927
- const message = err instanceof Error ? err.message : String(err);
81319
+ const message = (0, core_1.toErrorMessage)(err);
80928
81320
  const error = `Error: ${message}`;
80929
81321
  stdout.write(error + "\n");
80930
81322
  return { exitCode: 1, output: error };
@@ -80970,7 +81362,7 @@ var require_config3 = __commonJS({
80970
81362
  stdout.write(output + "\n");
80971
81363
  return { exitCode: 0, output };
80972
81364
  } catch (err) {
80973
- const message = err instanceof Error ? err.message : String(err);
81365
+ const message = (0, core_1.toErrorMessage)(err);
80974
81366
  const error = `Error: ${message}`;
80975
81367
  stdout.write(error + "\n");
80976
81368
  return { exitCode: 1, output: error };
@@ -80999,7 +81391,7 @@ var require_config3 = __commonJS({
80999
81391
  stdout.write(output + "\n");
81000
81392
  return { exitCode: 0, output };
81001
81393
  } catch (err) {
81002
- const message = err instanceof Error ? err.message : String(err);
81394
+ const message = (0, core_1.toErrorMessage)(err);
81003
81395
  const error = `Error: ${message}`;
81004
81396
  stdout.write(error + "\n");
81005
81397
  return { exitCode: 1, output: error };
@@ -81028,7 +81420,7 @@ var require_config3 = __commonJS({
81028
81420
  stdout.write(output + "\n");
81029
81421
  return { exitCode: 0, output };
81030
81422
  } catch (err) {
81031
- const message = err instanceof Error ? err.message : String(err);
81423
+ const message = (0, core_1.toErrorMessage)(err);
81032
81424
  const error = `Error: ${message}`;
81033
81425
  stdout.write(error + "\n");
81034
81426
  return { exitCode: 1, output: error };
@@ -81254,7 +81646,7 @@ Examples:
81254
81646
  logger.info("Listed sessions", { count: sessions.length });
81255
81647
  return { exitCode: 0, output: JSON.stringify({ count: sessions.length }) };
81256
81648
  } catch (err) {
81257
- const errorMsg = err instanceof Error ? err.message : String(err);
81649
+ const errorMsg = (0, core_1.toErrorMessage)(err);
81258
81650
  logger.error("Failed to list sessions", { error: errorMsg });
81259
81651
  stdout.write(JSON.stringify({ error: errorMsg }, null, 2) + "\n");
81260
81652
  return { exitCode: 1, output: errorMsg };
@@ -81907,14 +82299,63 @@ var require_dev_mode = __commonJS({
81907
82299
  log(stdout, "info", "Full clean complete.");
81908
82300
  return { exitCode: 0 };
81909
82301
  }
82302
+ async function doCleanAllProjects(logger, stdout, options = {}) {
82303
+ const { force = false, stdin = process.stdin } = options;
82304
+ const registryRoot = node_path_1.default.join(node_os_1.default.homedir(), ".sidekick", "projects");
82305
+ const registry = new core_1.ProjectRegistryService(registryRoot);
82306
+ const projects = await registry.list();
82307
+ if (projects.length === 0) {
82308
+ log(stdout, "info", `No registered projects found in ${registryRoot}`);
82309
+ return { exitCode: 0 };
82310
+ }
82311
+ log(stdout, "step", `Found ${projects.length} registered project(s):`);
82312
+ for (const project of projects) {
82313
+ stdout.write(` - ${project.displayName} (${project.path})
82314
+ `);
82315
+ }
82316
+ stdout.write("\n");
82317
+ let cleanedCount = 0;
82318
+ let skippedCount = 0;
82319
+ for (const project of projects) {
82320
+ let projectStats;
82321
+ try {
82322
+ projectStats = await (0, promises_12.stat)(project.path);
82323
+ } catch {
82324
+ log(stdout, "warn", `${project.displayName}: directory not found at ${project.path}, skipping`);
82325
+ skippedCount++;
82326
+ continue;
82327
+ }
82328
+ if (!projectStats.isDirectory()) {
82329
+ log(stdout, "warn", `${project.displayName}: path is not a directory at ${project.path}, skipping`);
82330
+ skippedCount++;
82331
+ continue;
82332
+ }
82333
+ if (!force) {
82334
+ const shouldClean = await (0, prompt_js_1.promptConfirm)({ stdin, stdout }, `Clean ${project.displayName} (${project.path})?`);
82335
+ if (!shouldClean) {
82336
+ log(stdout, "info", `Skipping ${project.displayName}`);
82337
+ skippedCount++;
82338
+ continue;
82339
+ }
82340
+ }
82341
+ stdout.write("\n");
82342
+ log(stdout, "step", `Cleaning ${project.displayName}...`);
82343
+ await doClean(project.path, logger, stdout, { force, stdin });
82344
+ cleanedCount++;
82345
+ }
82346
+ stdout.write("\n");
82347
+ log(stdout, "info", `Clean-all-projects complete: cleaned ${cleanedCount} project(s), skipped ${skippedCount}.`);
82348
+ return { exitCode: 0 };
82349
+ }
81910
82350
  var USAGE_TEXT = `Usage: sidekick dev-mode <command> [options]
81911
82351
 
81912
82352
  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
82353
+ enable Add dev-sidekick to .claude/settings.local.json
82354
+ disable Remove dev-sidekick from settings.local.json
82355
+ status Show current dev-mode state
82356
+ clean Truncate logs, kill daemon, clean state folders
82357
+ clean-all Full cleanup: clean + remove logs/sessions/state dirs
82358
+ clean-all-projects Clean all registered projects in ~/.sidekick/projects/
81918
82359
 
81919
82360
  Options:
81920
82361
  --force Skip confirmation prompts for destructive operations
@@ -81931,6 +82372,8 @@ Options:
81931
82372
  return doClean(projectDir, logger, stdout, options);
81932
82373
  case "clean-all":
81933
82374
  return doCleanAll(projectDir, logger, stdout, options);
82375
+ case "clean-all-projects":
82376
+ return doCleanAllProjects(logger, stdout, options);
81934
82377
  case "help":
81935
82378
  case "--help":
81936
82379
  case "-h":
@@ -82702,6 +83145,7 @@ var require_helpers = __commonJS({
82702
83145
  exports2.getPluginStatusLabel = getPluginStatusLabel;
82703
83146
  exports2.getApiKeyStatusType = getApiKeyStatusType;
82704
83147
  exports2.getPluginStatusIcon = getPluginStatusIcon;
83148
+ exports2.isPluginPresent = isPluginPresent;
82705
83149
  exports2.getLivenessIcon = getLivenessIcon;
82706
83150
  exports2.getLivenessLabel = getLivenessLabel;
82707
83151
  exports2.formatApiKeyScopes = formatApiKeyScopes;
@@ -82784,7 +83228,7 @@ var require_helpers = __commonJS({
82784
83228
  case "dev-mode":
82785
83229
  return "dev-mode (local)";
82786
83230
  case "both":
82787
- return "conflict (both plugin and dev-mode detected!)";
83231
+ return "plugin and dev-mode both active";
82788
83232
  case "none":
82789
83233
  return "not installed";
82790
83234
  case "timeout":
@@ -82809,6 +83253,7 @@ var require_helpers = __commonJS({
82809
83253
  case "dev-mode":
82810
83254
  return "\u2713";
82811
83255
  case "both":
83256
+ return "\u2022";
82812
83257
  case "timeout":
82813
83258
  case "error":
82814
83259
  return "\u26A0";
@@ -82816,6 +83261,9 @@ var require_helpers = __commonJS({
82816
83261
  return "\u2717";
82817
83262
  }
82818
83263
  }
83264
+ function isPluginPresent(status) {
83265
+ return status === "plugin" || status === "dev-mode" || status === "both";
83266
+ }
82819
83267
  function getLivenessIcon(status) {
82820
83268
  switch (status) {
82821
83269
  case "active":
@@ -82919,8 +83367,74 @@ var require_doctor = __commonJS({
82919
83367
  "liveness",
82920
83368
  "zombies",
82921
83369
  "auto-config",
82922
- "shell-alias"
83370
+ "shell-alias",
83371
+ "llm-config"
82923
83372
  ];
83373
+ var DEPRECATED_LLM_MODELS = [
83374
+ {
83375
+ model: "google/gemini-2.0-flash-lite-001",
83376
+ 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."
83377
+ }
83378
+ ];
83379
+ function collectLlmYamlModels(parsed) {
83380
+ if (!parsed)
83381
+ return [];
83382
+ const models = [];
83383
+ for (const key of ["profiles", "fallbackProfiles"]) {
83384
+ const section = parsed[key];
83385
+ if (!section || typeof section !== "object")
83386
+ continue;
83387
+ for (const profile of Object.values(section)) {
83388
+ if (profile && typeof profile === "object") {
83389
+ const model = profile.model;
83390
+ if (typeof model === "string") {
83391
+ models.push(model);
83392
+ }
83393
+ }
83394
+ }
83395
+ }
83396
+ return models;
83397
+ }
83398
+ function runLlmConfigCheck(projectDir, homeDir, stdout, logger) {
83399
+ const candidatePaths = [path.join(homeDir, ".sidekick", "llm.yaml"), path.join(projectDir, ".sidekick", "llm.yaml")];
83400
+ const matched = /* @__PURE__ */ new Set();
83401
+ const parseFailures = [];
83402
+ for (const yamlPath of candidatePaths) {
83403
+ let parsed;
83404
+ try {
83405
+ parsed = (0, core_1.tryReadYaml)(yamlPath);
83406
+ } catch (err) {
83407
+ logger.warn("Failed to parse llm.yaml during migration check", {
83408
+ path: yamlPath,
83409
+ error: (0, core_1.toErrorMessage)(err)
83410
+ });
83411
+ parseFailures.push(yamlPath);
83412
+ continue;
83413
+ }
83414
+ if (!parsed)
83415
+ continue;
83416
+ const models = collectLlmYamlModels(parsed);
83417
+ for (const { model, message } of DEPRECATED_LLM_MODELS) {
83418
+ if (models.includes(model) && !matched.has(model)) {
83419
+ matched.add(model);
83420
+ logger.warn("Deprecated LLM model referenced in user override", {
83421
+ path: yamlPath,
83422
+ model
83423
+ });
83424
+ stdout.write(`\u26A0 ${message}
83425
+ `);
83426
+ }
83427
+ }
83428
+ }
83429
+ if (parseFailures.length > 0) {
83430
+ stdout.write(`\u26A0 LLM Config: could not be parsed (${parseFailures.join(", ")}) \u2014 deprecation check skipped
83431
+ `);
83432
+ return;
83433
+ }
83434
+ if (matched.size === 0) {
83435
+ stdout.write("\u2713 LLM Config: no deprecated models referenced\n");
83436
+ }
83437
+ }
82924
83438
  function parseDoctorOnly(only) {
82925
83439
  if (!only)
82926
83440
  return null;
@@ -82931,6 +83445,13 @@ var require_doctor = __commonJS({
82931
83445
  }
82932
83446
  return new Set(requested);
82933
83447
  }
83448
+ async function tryRemoveLegacySection(projectDir) {
83449
+ try {
83450
+ return await (0, core_1.removeLegacyGitignoreSection)(projectDir);
83451
+ } catch {
83452
+ return false;
83453
+ }
83454
+ }
82934
83455
  async function runDoctorFixes(projectDir, logger, stdout, context) {
82935
83456
  const { homeDir, filter, doctorResult, gitignore, pluginStatus, liveness } = context;
82936
83457
  const isFullMode = filter === null;
@@ -82972,15 +83493,40 @@ var require_doctor = __commonJS({
82972
83493
  stdout.write(" \u26A0 Statusline managed by dev-mode (skipped)\n");
82973
83494
  }
82974
83495
  }
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}
83496
+ if (shouldFix("gitignore") && gitignore !== null) {
83497
+ if (gitignore === "legacy") {
83498
+ stdout.write("Fixing: Gitignore (migrating legacy format)\n");
83499
+ const result = await (0, core_1.installGitignoreSection)(projectDir);
83500
+ if (result.status === "error") {
83501
+ stdout.write(` \u26A0 Failed to create .sidekick/.gitignore: ${result.error}
82980
83502
  `);
83503
+ } else {
83504
+ const legacyRemoved = await tryRemoveLegacySection(projectDir);
83505
+ 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");
83506
+ fixedCount++;
83507
+ }
83508
+ } else if (gitignore === "installed") {
83509
+ const hasLegacy = await (0, core_1.detectLegacyGitignoreSection)(projectDir);
83510
+ if (hasLegacy) {
83511
+ stdout.write("Fixing: Gitignore (removing redundant legacy section)\n");
83512
+ const legacyRemoved = await tryRemoveLegacySection(projectDir);
83513
+ if (legacyRemoved) {
83514
+ stdout.write(" \u2713 Removed legacy section from root .gitignore\n");
83515
+ fixedCount++;
83516
+ } else {
83517
+ stdout.write(" \u26A0 Legacy section detected but could not be removed from root .gitignore\n");
83518
+ }
83519
+ }
82981
83520
  } else {
82982
- stdout.write(" \u2713 Gitignore configured\n");
82983
- fixedCount++;
83521
+ stdout.write("Fixing: Gitignore\n");
83522
+ const result = await (0, core_1.installGitignoreSection)(projectDir);
83523
+ if (result.status === "error") {
83524
+ stdout.write(` \u26A0 Failed to update .sidekick/.gitignore: ${result.error}
83525
+ `);
83526
+ } else {
83527
+ stdout.write(" \u2713 Gitignore configured\n");
83528
+ fixedCount++;
83529
+ }
82984
83530
  }
82985
83531
  }
82986
83532
  if (shouldFix("plugin") && pluginStatus === "none") {
@@ -83002,7 +83548,7 @@ var require_doctor = __commonJS({
83002
83548
  fixedCount++;
83003
83549
  }
83004
83550
  } catch (err) {
83005
- stdout.write(` \u26A0 Plugin installation failed: ${err instanceof Error ? err.message : String(err)}
83551
+ stdout.write(` \u26A0 Plugin installation failed: ${(0, core_1.toErrorMessage)(err)}
83006
83552
  `);
83007
83553
  }
83008
83554
  }
@@ -83072,7 +83618,7 @@ var require_doctor = __commonJS({
83072
83618
  try {
83073
83619
  filter = parseDoctorOnly(options?.only);
83074
83620
  } catch (err) {
83075
- stdout.write(`${err instanceof Error ? err.message : String(err)}
83621
+ stdout.write(`${(0, core_1.toErrorMessage)(err)}
83076
83622
  `);
83077
83623
  return { exitCode: 1 };
83078
83624
  }
@@ -83122,7 +83668,12 @@ var require_doctor = __commonJS({
83122
83668
  promises.push((0, core_1.detectGitignoreStatus)(projectDir).then((result) => {
83123
83669
  gitignore = result;
83124
83670
  const gitignoreIcon = result === "installed" ? "\u2713" : "\u26A0";
83125
- stdout.write(`${gitignoreIcon} Gitignore: ${result}
83671
+ const gitignoreMessage = result === "legacy" ? `legacy section found in root .gitignore \u2014 run sidekick doctor --fix --only=gitignore to migrate` : result;
83672
+ stdout.write(`${gitignoreIcon} Gitignore: ${gitignoreMessage}
83673
+ `);
83674
+ }).catch((err) => {
83675
+ gitignore = "unknown";
83676
+ stdout.write(`\u26A0 Gitignore: could not read status \u2014 ${err.message}
83126
83677
  `);
83127
83678
  }));
83128
83679
  }
@@ -83137,8 +83688,7 @@ var require_doctor = __commonJS({
83137
83688
  stdout.write(`${pluginIcon} Plugin: ${pluginLabel}
83138
83689
  `);
83139
83690
  }
83140
- const isPluginPresent = status === "plugin" || status === "dev-mode" || status === "both";
83141
- if (shouldRun("liveness") && isPluginPresent) {
83691
+ if (shouldRun("liveness") && (0, helpers_js_1.isPluginPresent)(status)) {
83142
83692
  logger.info("Starting plugin liveness check");
83143
83693
  liveness = await setupService.detectPluginLiveness();
83144
83694
  const livenessIcon = (0, helpers_js_1.getLivenessIcon)(liveness);
@@ -83160,6 +83710,9 @@ var require_doctor = __commonJS({
83160
83710
  }));
83161
83711
  }
83162
83712
  await Promise.all(promises);
83713
+ if (shouldRun("llm-config")) {
83714
+ runLlmConfigCheck(projectDir, homeDir, stdout, logger);
83715
+ }
83163
83716
  if (shouldRun("auto-config")) {
83164
83717
  const userStatus = await setupService.getUserStatus();
83165
83718
  if (userStatus?.preferences.autoConfigureProjects) {
@@ -83185,7 +83738,7 @@ var require_doctor = __commonJS({
83185
83738
  }
83186
83739
  }
83187
83740
  if (filter === null) {
83188
- const isPluginOk = pluginStatus === "plugin" || pluginStatus === "dev-mode";
83741
+ const isPluginOk = (0, helpers_js_1.isPluginPresent)(pluginStatus);
83189
83742
  const isPluginLive = liveness === null || liveness === "active";
83190
83743
  const isHealthy = doctorResult.overallHealth === "healthy" && gitignore === "installed" && isPluginOk && isPluginLive && zombieCount === 0;
83191
83744
  const overallIcon = isHealthy ? "\u2713" : "\u26A0";
@@ -83625,12 +84178,18 @@ Examples:
83625
84178
  }
83626
84179
  async function runStep3Gitignore(wctx, force) {
83627
84180
  const { ctx, projectDir } = wctx;
83628
- const currentStatus = await (0, core_1.detectGitignoreStatus)(projectDir);
83629
- if (currentStatus === "installed") {
84181
+ let currentStatus;
84182
+ try {
84183
+ currentStatus = await (0, core_1.detectGitignoreStatus)(projectDir);
84184
+ } catch {
84185
+ currentStatus = "missing";
84186
+ }
84187
+ if (currentStatus === "installed" || currentStatus === "legacy") {
83630
84188
  if (!force) {
83631
- (0, prompts_js_1.printStatus)(ctx, "success", "Sidekick entries already present in .gitignore");
84189
+ const message2 = currentStatus === "legacy" ? "Sidekick entries already present in root .gitignore (legacy \u2014 run doctor --fix to migrate)" : "Sidekick already configured (.sidekick/.gitignore)";
84190
+ (0, prompts_js_1.printStatus)(ctx, "success", message2);
83632
84191
  }
83633
- return "installed";
84192
+ return currentStatus;
83634
84193
  }
83635
84194
  const needsRepair = currentStatus === "incomplete";
83636
84195
  if (force) {
@@ -84103,7 +84662,6 @@ var require_uninstall = __commonJS({
84103
84662
  await removeFile(path.join(userHome, ".sidekick", core_1.USER_STATUS_FILENAME), "user", core_1.USER_STATUS_FILENAME, actions, {
84104
84663
  dryRun
84105
84664
  });
84106
- await removeFile(path.join(userHome, ".sidekick", core_1.LEGACY_USER_STATUS_FILENAME), "user", core_1.LEGACY_USER_STATUS_FILENAME, actions, { dryRun });
84107
84665
  await removeFile(path.join(userHome, ".sidekick", "features.yaml"), "user", "features.yaml", actions, { dryRun });
84108
84666
  }
84109
84667
  if (projectDetected) {
@@ -84200,11 +84758,6 @@ var require_uninstall = __commonJS({
84200
84758
  try {
84201
84759
  await fs.access(path.join(userHome, ".sidekick", core_1.USER_STATUS_FILENAME));
84202
84760
  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
84761
  } catch {
84209
84762
  try {
84210
84763
  const content = await fs.readFile(path.join(userHome, ".claude", "settings.json"), "utf-8");
@@ -84275,8 +84828,12 @@ var require_uninstall = __commonJS({
84275
84828
  summary.project.push({ label: ".env", details: envDetail });
84276
84829
  }
84277
84830
  if (!devModeActive) {
84278
- const gitignore = await (0, fs_js_1.readFileOrNull)(path.join(projectDir, ".gitignore"));
84279
- if (gitignore?.includes("# >>> sidekick")) {
84831
+ const sidekickGitignore = await (0, fs_js_1.readFileOrNull)(path.join(projectDir, ".sidekick", ".gitignore"));
84832
+ const rootGitignore = await (0, fs_js_1.readFileOrNull)(path.join(projectDir, ".gitignore"));
84833
+ if (sidekickGitignore !== null) {
84834
+ summary.project.push({ label: ".sidekick/.gitignore", details: "sidekick managed file" });
84835
+ }
84836
+ if (rootGitignore?.includes("# >>> sidekick")) {
84280
84837
  summary.project.push({ label: ".gitignore", details: "sidekick section" });
84281
84838
  }
84282
84839
  }
@@ -84293,11 +84850,7 @@ var require_uninstall = __commonJS({
84293
84850
  } catch {
84294
84851
  }
84295
84852
  }
84296
- const userConfigFiles = await detectExistingItems(userHome, [
84297
- core_1.USER_STATUS_FILENAME,
84298
- core_1.LEGACY_USER_STATUS_FILENAME,
84299
- "features.yaml"
84300
- ]);
84853
+ const userConfigFiles = await detectExistingItems(userHome, [core_1.USER_STATUS_FILENAME, "features.yaml"]);
84301
84854
  if (userConfigFiles.length > 0) {
84302
84855
  summary.user.push({ label: "Config", details: userConfigFiles.join(", ") });
84303
84856
  }
@@ -84675,7 +85228,7 @@ var require_cli = __commonJS({
84675
85228
  var promises_12 = require("node:fs/promises");
84676
85229
  var node_stream_1 = require("node:stream");
84677
85230
  var yargs_parser_1 = __importDefault2(require_build());
84678
- var VERSION = true ? "0.1.19" : "dev";
85231
+ var VERSION = true ? "0.1.21" : "dev";
84679
85232
  var SANDBOX_ERROR_MESSAGE = `Error: Daemon commands cannot run in sandbox mode.
84680
85233
 
84681
85234
  Claude Code's sandbox blocks Unix socket operations required for daemon IPC.
@@ -84808,6 +85361,8 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
84808
85361
  const cwd = typeof raw.cwd === "string" ? raw.cwd : void 0;
84809
85362
  const hookEventName = typeof raw.hook_event_name === "string" ? raw.hook_event_name : void 0;
84810
85363
  const permissionMode = typeof raw.permission_mode === "string" ? raw.permission_mode : void 0;
85364
+ const agentId = typeof raw.agent_id === "string" ? raw.agent_id : void 0;
85365
+ const agentType = typeof raw.agent_type === "string" ? raw.agent_type : void 0;
84811
85366
  if (!sessionId) {
84812
85367
  return void 0;
84813
85368
  }
@@ -84818,6 +85373,8 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
84818
85373
  // Optional - some hooks (Stop, SessionStart) may not include cwd
84819
85374
  hookEventName: hookEventName ?? "unknown",
84820
85375
  permissionMode,
85376
+ agentId,
85377
+ agentType,
84821
85378
  raw
84822
85379
  };
84823
85380
  } catch {
@@ -85115,7 +85672,7 @@ Run 'sidekick help' for available commands.
85115
85672
  } catch (err) {
85116
85673
  logger.warn("Failed to persist CLI log metrics", {
85117
85674
  sessionId,
85118
- error: err instanceof Error ? err.message : String(err)
85675
+ error: (0, core_1.toErrorMessage)(err)
85119
85676
  });
85120
85677
  }
85121
85678
  }