@scotthamilton77/sidekick 0.1.18 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/bin.js +231 -62
  2. package/dist/daemon.js +231 -61
  3. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -33736,7 +33736,12 @@ var require_log_events = __commonJS({
33736
33736
  "use strict";
33737
33737
  Object.defineProperty(exports2, "__esModule", { value: true });
33738
33738
  exports2.LogEvents = void 0;
33739
+ exports2.setSessionLogWriter = setSessionLogWriter;
33739
33740
  exports2.logEvent = logEvent;
33741
+ var sessionLogWriter = null;
33742
+ function setSessionLogWriter(writer) {
33743
+ sessionLogWriter = writer;
33744
+ }
33740
33745
  function buildContext(ctx) {
33741
33746
  return {
33742
33747
  sessionId: ctx.sessionId,
@@ -34143,10 +34148,202 @@ var require_log_events = __commonJS({
34143
34148
  source: event.source,
34144
34149
  ...meta
34145
34150
  });
34151
+ if (sessionLogWriter && event.context.sessionId) {
34152
+ const logFile = event.source === "cli" ? "sidekick.log" : "sidekickd.log";
34153
+ const line = JSON.stringify({
34154
+ time: event.time,
34155
+ type: event.type,
34156
+ source: event.source,
34157
+ context: event.context,
34158
+ ...meta
34159
+ }) + "\n";
34160
+ sessionLogWriter.write(event.context.sessionId, logFile, line).catch(() => {
34161
+ });
34162
+ }
34146
34163
  }
34147
34164
  }
34148
34165
  });
34149
34166
 
34167
+ // ../sidekick-core/dist/staging-paths.js
34168
+ var require_staging_paths = __commonJS({
34169
+ "../sidekick-core/dist/staging-paths.js"(exports2) {
34170
+ "use strict";
34171
+ Object.defineProperty(exports2, "__esModule", { value: true });
34172
+ exports2.CONSUMED_FILE_PATTERN = void 0;
34173
+ exports2.getStagingRoot = getStagingRoot;
34174
+ exports2.getHookDir = getHookDir;
34175
+ exports2.getReminderPath = getReminderPath;
34176
+ exports2.isValidPathSegment = isValidPathSegment;
34177
+ exports2.validatePathSegment = validatePathSegment;
34178
+ exports2.filterActiveReminderFiles = filterActiveReminderFiles;
34179
+ exports2.createConsumedFilePattern = createConsumedFilePattern;
34180
+ exports2.extractConsumedTimestamp = extractConsumedTimestamp;
34181
+ var node_path_1 = require("node:path");
34182
+ function getStagingRoot(stateDir, sessionId) {
34183
+ return (0, node_path_1.join)(stateDir, "sessions", sessionId, "stage");
34184
+ }
34185
+ function getHookDir(stateDir, sessionId, hookName) {
34186
+ return (0, node_path_1.join)(getStagingRoot(stateDir, sessionId), hookName);
34187
+ }
34188
+ function getReminderPath(stateDir, sessionId, hookName, reminderName) {
34189
+ return (0, node_path_1.join)(getHookDir(stateDir, sessionId, hookName), `${reminderName}.json`);
34190
+ }
34191
+ function isValidPathSegment(s) {
34192
+ if (s === "")
34193
+ return false;
34194
+ if (s === "." || s === "..")
34195
+ return false;
34196
+ if (s.includes("/") || s.includes("\\"))
34197
+ return false;
34198
+ if ((0, node_path_1.basename)(s) !== s)
34199
+ return false;
34200
+ return /^[a-zA-Z0-9._-]+$/.test(s);
34201
+ }
34202
+ function validatePathSegment(segment, name) {
34203
+ if (!isValidPathSegment(segment)) {
34204
+ throw new Error(`Invalid ${name}: must be a non-empty alphanumeric string without path separators`);
34205
+ }
34206
+ }
34207
+ exports2.CONSUMED_FILE_PATTERN = /\.\d+\.json$/;
34208
+ function filterActiveReminderFiles(files) {
34209
+ return files.filter((f) => f.endsWith(".json") && !exports2.CONSUMED_FILE_PATTERN.test(f));
34210
+ }
34211
+ function createConsumedFilePattern(reminderName) {
34212
+ return new RegExp(`^${reminderName}\\.(\\d+)\\.json$`);
34213
+ }
34214
+ function extractConsumedTimestamp(filename, reminderName) {
34215
+ const pattern = createConsumedFilePattern(reminderName);
34216
+ const match = pattern.exec(filename);
34217
+ return match ? parseInt(match[1], 10) : null;
34218
+ }
34219
+ }
34220
+ });
34221
+
34222
+ // ../sidekick-core/dist/session-log-writer.js
34223
+ var require_session_log_writer = __commonJS({
34224
+ "../sidekick-core/dist/session-log-writer.js"(exports2) {
34225
+ "use strict";
34226
+ Object.defineProperty(exports2, "__esModule", { value: true });
34227
+ exports2.SessionLogWriter = void 0;
34228
+ var promises_12 = require("node:fs/promises");
34229
+ var node_path_1 = require("node:path");
34230
+ var node_fs_1 = require("node:fs");
34231
+ var staging_paths_js_1 = require_staging_paths();
34232
+ var SessionLogWriter = class {
34233
+ sessionsDir;
34234
+ maxHandles;
34235
+ idleTimeoutMs;
34236
+ /** Map key: `${sessionId}/${logFile}` */
34237
+ handles = /* @__PURE__ */ new Map();
34238
+ constructor(options) {
34239
+ this.sessionsDir = options.sessionsDir;
34240
+ this.maxHandles = options.maxHandles ?? 10;
34241
+ this.idleTimeoutMs = options.idleTimeoutMs ?? 30 * 60 * 1e3;
34242
+ }
34243
+ get handleCount() {
34244
+ return this.handles.size;
34245
+ }
34246
+ /**
34247
+ * Write an NDJSON line to a per-session log file.
34248
+ * Creates the directory and file handle lazily.
34249
+ * Skips if sessionId is empty (daemon lifecycle events before session exists).
34250
+ */
34251
+ async write(sessionId, logFile, line) {
34252
+ if (!sessionId)
34253
+ return;
34254
+ if (!(0, staging_paths_js_1.isValidPathSegment)(sessionId) || !(0, staging_paths_js_1.isValidPathSegment)(logFile))
34255
+ return;
34256
+ const key = `${sessionId}/${logFile}`;
34257
+ let entry = this.handles.get(key);
34258
+ if (!entry) {
34259
+ if (this.handles.size >= this.maxHandles) {
34260
+ this.evictLRU();
34261
+ }
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);
34281
+ }
34282
+ await entry.ready;
34283
+ entry.lastUsed = Date.now();
34284
+ this.resetIdleTimer(key, entry);
34285
+ return new Promise((resolve3, reject) => {
34286
+ entry.stream.write(line, (err) => {
34287
+ if (err) {
34288
+ void this.closeHandle(key);
34289
+ reject(err);
34290
+ } else {
34291
+ resolve3();
34292
+ }
34293
+ });
34294
+ });
34295
+ }
34296
+ /** Close all handles for a specific session. */
34297
+ async closeSession(sessionId) {
34298
+ const prefix = `${sessionId}/`;
34299
+ const toClose = [];
34300
+ for (const key of this.handles.keys()) {
34301
+ if (key.startsWith(prefix)) {
34302
+ toClose.push(key);
34303
+ }
34304
+ }
34305
+ await Promise.all(toClose.map((key) => this.closeHandle(key)));
34306
+ }
34307
+ /** Close all open handles. */
34308
+ async closeAll() {
34309
+ const keys = [...this.handles.keys()];
34310
+ await Promise.all(keys.map((key) => this.closeHandle(key)));
34311
+ }
34312
+ async closeHandle(key) {
34313
+ const entry = this.handles.get(key);
34314
+ if (!entry)
34315
+ return;
34316
+ if (entry.timer)
34317
+ clearTimeout(entry.timer);
34318
+ this.handles.delete(key);
34319
+ return new Promise((resolve3) => {
34320
+ entry.stream.end(() => resolve3());
34321
+ });
34322
+ }
34323
+ evictLRU() {
34324
+ let oldestKey = "";
34325
+ let oldestTime = Infinity;
34326
+ for (const [key, entry] of this.handles) {
34327
+ if (entry.lastUsed < oldestTime) {
34328
+ oldestTime = entry.lastUsed;
34329
+ oldestKey = key;
34330
+ }
34331
+ }
34332
+ void this.closeHandle(oldestKey);
34333
+ }
34334
+ resetIdleTimer(key, entry) {
34335
+ if (entry.timer)
34336
+ clearTimeout(entry.timer);
34337
+ entry.timer = setTimeout(() => {
34338
+ void this.closeHandle(key);
34339
+ }, this.idleTimeoutMs);
34340
+ entry.timer.unref();
34341
+ }
34342
+ };
34343
+ exports2.SessionLogWriter = SessionLogWriter;
34344
+ }
34345
+ });
34346
+
34150
34347
  // ../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/constants.cjs
34151
34348
  var require_constants2 = __commonJS({
34152
34349
  "../../node_modules/.pnpm/date-fns@4.1.0/node_modules/date-fns/constants.cjs"(exports2) {
@@ -45886,7 +46083,7 @@ var require_structured_logging = __commonJS({
45886
46083
  return mod && mod.__esModule ? mod : { "default": mod };
45887
46084
  };
45888
46085
  Object.defineProperty(exports2, "__esModule", { value: true });
45889
- exports2.DEFAULT_MAX_FILES = exports2.DEFAULT_ROTATE_SIZE_BYTES = exports2.LOG_LEVELS = exports2.logEvent = exports2.LogEvents = void 0;
46086
+ exports2.DEFAULT_MAX_FILES = exports2.DEFAULT_ROTATE_SIZE_BYTES = exports2.LOG_LEVELS = exports2.SessionLogWriter = exports2.setSessionLogWriter = exports2.logEvent = exports2.LogEvents = void 0;
45890
46087
  exports2.getComponentLogLevel = getComponentLogLevel;
45891
46088
  exports2.createLogManager = createLogManager;
45892
46089
  exports2.createContextLogger = createContextLogger;
@@ -45903,6 +46100,13 @@ var require_structured_logging = __commonJS({
45903
46100
  Object.defineProperty(exports2, "logEvent", { enumerable: true, get: function() {
45904
46101
  return log_events_1.logEvent;
45905
46102
  } });
46103
+ Object.defineProperty(exports2, "setSessionLogWriter", { enumerable: true, get: function() {
46104
+ return log_events_1.setSessionLogWriter;
46105
+ } });
46106
+ var session_log_writer_1 = require_session_log_writer();
46107
+ Object.defineProperty(exports2, "SessionLogWriter", { enumerable: true, get: function() {
46108
+ return session_log_writer_1.SessionLogWriter;
46109
+ } });
45906
46110
  exports2.LOG_LEVELS = {
45907
46111
  trace: 10,
45908
46112
  debug: 20,
@@ -58385,61 +58589,6 @@ var require_errors6 = __commonJS({
58385
58589
  }
58386
58590
  });
58387
58591
 
58388
- // ../sidekick-core/dist/staging-paths.js
58389
- var require_staging_paths = __commonJS({
58390
- "../sidekick-core/dist/staging-paths.js"(exports2) {
58391
- "use strict";
58392
- Object.defineProperty(exports2, "__esModule", { value: true });
58393
- exports2.CONSUMED_FILE_PATTERN = void 0;
58394
- exports2.getStagingRoot = getStagingRoot;
58395
- exports2.getHookDir = getHookDir;
58396
- exports2.getReminderPath = getReminderPath;
58397
- exports2.isValidPathSegment = isValidPathSegment;
58398
- exports2.validatePathSegment = validatePathSegment;
58399
- exports2.filterActiveReminderFiles = filterActiveReminderFiles;
58400
- exports2.createConsumedFilePattern = createConsumedFilePattern;
58401
- exports2.extractConsumedTimestamp = extractConsumedTimestamp;
58402
- var node_path_1 = require("node:path");
58403
- function getStagingRoot(stateDir, sessionId) {
58404
- return (0, node_path_1.join)(stateDir, "sessions", sessionId, "stage");
58405
- }
58406
- function getHookDir(stateDir, sessionId, hookName) {
58407
- return (0, node_path_1.join)(getStagingRoot(stateDir, sessionId), hookName);
58408
- }
58409
- function getReminderPath(stateDir, sessionId, hookName, reminderName) {
58410
- return (0, node_path_1.join)(getHookDir(stateDir, sessionId, hookName), `${reminderName}.json`);
58411
- }
58412
- function isValidPathSegment(s) {
58413
- if (s === "")
58414
- return false;
58415
- if (s === "." || s === "..")
58416
- return false;
58417
- if (s.includes("/") || s.includes("\\"))
58418
- return false;
58419
- if ((0, node_path_1.basename)(s) !== s)
58420
- return false;
58421
- return /^[a-zA-Z0-9._-]+$/.test(s);
58422
- }
58423
- function validatePathSegment(segment, name) {
58424
- if (!isValidPathSegment(segment)) {
58425
- throw new Error(`Invalid ${name}: must be a non-empty alphanumeric string without path separators`);
58426
- }
58427
- }
58428
- exports2.CONSUMED_FILE_PATTERN = /\.\d+\.json$/;
58429
- function filterActiveReminderFiles(files) {
58430
- return files.filter((f) => f.endsWith(".json") && !exports2.CONSUMED_FILE_PATTERN.test(f));
58431
- }
58432
- function createConsumedFilePattern(reminderName) {
58433
- return new RegExp(`^${reminderName}\\.(\\d+)\\.json$`);
58434
- }
58435
- function extractConsumedTimestamp(filename, reminderName) {
58436
- const pattern = createConsumedFilePattern(reminderName);
58437
- const match = pattern.exec(filename);
58438
- return match ? parseInt(match[1], 10) : null;
58439
- }
58440
- }
58441
- });
58442
-
58443
58592
  // ../sidekick-core/dist/staging-service.js
58444
58593
  var require_staging_service = __commonJS({
58445
58594
  "../sidekick-core/dist/staging-service.js"(exports2) {
@@ -59315,6 +59464,9 @@ var require_path_resolver = __commonJS({
59315
59464
  sessionStagingDir(sessionId) {
59316
59465
  return (0, node_path_1.join)(this.sessionRootDir(sessionId), "stage");
59317
59466
  }
59467
+ sessionLogsDir(sessionId) {
59468
+ return (0, node_path_1.join)(this.sessionRootDir(sessionId), "logs");
59469
+ }
59318
59470
  hookStagingDir(sessionId, hookName) {
59319
59471
  return (0, node_path_1.join)(this.sessionStagingDir(sessionId), hookName);
59320
59472
  }
@@ -64035,9 +64187,9 @@ var require_dist4 = __commonJS({
64035
64187
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
64036
64188
  };
64037
64189
  Object.defineProperty(exports2, "__esModule", { value: true });
64038
- exports2.readKeyFromEnvFile = exports2.determineOverallStatus = 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.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;
64039
- exports2.StateService = exports2.createHookableLogger = exports2.InstrumentedProfileProviderFactory = exports2.InstrumentedLLMProvider = exports2.ServiceFactoryImpl = exports2.TranscriptServiceImpl = exports2.createDefaultTokenUsage = exports2.createDefaultMetrics = exports2.copyWithTimestampSync = exports2.renameWithTimestampSync = exports2.renameWithTimestamp = exports2.copyWithTimestamp = exports2.getTimestampedPath = exports2.extractToolResultPreview = exports2.extractToolCallPreview = exports2.extractTextFromContent = exports2.extractContentPreview = exports2.HandlerRegistryImpl = exports2.extractConsumedTimestamp = exports2.createConsumedFilePattern = exports2.CONSUMED_FILE_PATTERN = exports2.filterActiveReminderFiles = exports2.validatePathSegment = exports2.isValidPathSegment = exports2.getReminderPath = exports2.getHookDir = exports2.getStagingRoot = 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 = void 0;
64040
- 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 = void 0;
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;
64041
64193
  var types_1 = require_dist();
64042
64194
  Object.defineProperty(exports2, "TaskTypes", { enumerable: true, get: function() {
64043
64195
  return types_1.TaskTypes;
@@ -64170,6 +64322,12 @@ var require_dist4 = __commonJS({
64170
64322
  Object.defineProperty(exports2, "logEvent", { enumerable: true, get: function() {
64171
64323
  return structured_logging_1.logEvent;
64172
64324
  } });
64325
+ Object.defineProperty(exports2, "setSessionLogWriter", { enumerable: true, get: function() {
64326
+ return structured_logging_1.setSessionLogWriter;
64327
+ } });
64328
+ Object.defineProperty(exports2, "SessionLogWriter", { enumerable: true, get: function() {
64329
+ return structured_logging_1.SessionLogWriter;
64330
+ } });
64173
64331
  var daemon_client_1 = require_daemon_client2();
64174
64332
  Object.defineProperty(exports2, "killAllDaemons", { enumerable: true, get: function() {
64175
64333
  return daemon_client_1.killAllDaemons;
@@ -64498,8 +64656,9 @@ var require_runtime = __commonJS({
64498
64656
  const rotation = config.core.logging.rotation;
64499
64657
  const fileDestination = enableFileLogging ? {
64500
64658
  path: logFilePath,
64501
- maxSizeBytes: rotation?.maxSizeBytes ?? 10485760,
64502
- maxFiles: rotation?.maxFiles ?? 5
64659
+ maxSizeBytes: rotation?.maxSizeBytes ?? 2097152,
64660
+ // 2MB (ephemeral debug window)
64661
+ maxFiles: rotation?.maxFiles ?? 2
64503
64662
  } : void 0;
64504
64663
  const logManager = (0, core_1.createLogManager)({
64505
64664
  name: "sidekick:cli",
@@ -64541,6 +64700,14 @@ var require_runtime = __commonJS({
64541
64700
  }
64542
64701
  });
64543
64702
  const telemetry = logManager.getTelemetry();
64703
+ const sessionsDir = projectRoot ? (0, node_path_1.join)(projectRoot, ".sidekick", "sessions") : (0, node_path_1.join)((0, node_os_1.homedir)(), ".sidekick", "sessions");
64704
+ const sessionLogWriter = new core_1.SessionLogWriter({
64705
+ sessionsDir,
64706
+ maxHandles: 2,
64707
+ // CLI typically has 1 session
64708
+ idleTimeoutMs: 10 * 60 * 1e3
64709
+ });
64710
+ (0, core_1.setSessionLogWriter)(sessionLogWriter);
64544
64711
  const cleanupErrorHandlers = (0, core_1.setupGlobalErrorHandlers)(logger);
64545
64712
  logger.debug("Runtime bootstrap complete", {
64546
64713
  projectRoot: projectRoot ?? null,
@@ -64563,6 +64730,8 @@ var require_runtime = __commonJS({
64563
64730
  stateService,
64564
64731
  correlationId,
64565
64732
  cleanup: () => {
64733
+ (0, core_1.setSessionLogWriter)(null);
64734
+ void sessionLogWriter.closeAll();
64566
64735
  cleanupErrorHandlers();
64567
64736
  },
64568
64737
  bindSessionId: (sessionId) => {
@@ -84506,7 +84675,7 @@ var require_cli = __commonJS({
84506
84675
  var promises_12 = require("node:fs/promises");
84507
84676
  var node_stream_1 = require("node:stream");
84508
84677
  var yargs_parser_1 = __importDefault2(require_build());
84509
- var VERSION = true ? "0.1.18" : "dev";
84678
+ var VERSION = true ? "0.1.19" : "dev";
84510
84679
  var SANDBOX_ERROR_MESSAGE = `Error: Daemon commands cannot run in sandbox mode.
84511
84680
 
84512
84681
  Claude Code's sandbox blocks Unix socket operations required for daemon IPC.
package/dist/daemon.js CHANGED
@@ -32760,7 +32760,12 @@ var require_log_events = __commonJS({
32760
32760
  "use strict";
32761
32761
  Object.defineProperty(exports2, "__esModule", { value: true });
32762
32762
  exports2.LogEvents = void 0;
32763
+ exports2.setSessionLogWriter = setSessionLogWriter;
32763
32764
  exports2.logEvent = logEvent;
32765
+ var sessionLogWriter = null;
32766
+ function setSessionLogWriter(writer) {
32767
+ sessionLogWriter = writer;
32768
+ }
32764
32769
  function buildContext(ctx) {
32765
32770
  return {
32766
32771
  sessionId: ctx.sessionId,
@@ -33167,7 +33172,199 @@ var require_log_events = __commonJS({
33167
33172
  source: event.source,
33168
33173
  ...meta
33169
33174
  });
33175
+ if (sessionLogWriter && event.context.sessionId) {
33176
+ const logFile = event.source === "cli" ? "sidekick.log" : "sidekickd.log";
33177
+ const line = JSON.stringify({
33178
+ time: event.time,
33179
+ type: event.type,
33180
+ source: event.source,
33181
+ context: event.context,
33182
+ ...meta
33183
+ }) + "\n";
33184
+ sessionLogWriter.write(event.context.sessionId, logFile, line).catch(() => {
33185
+ });
33186
+ }
33187
+ }
33188
+ }
33189
+ });
33190
+
33191
+ // ../sidekick-core/dist/staging-paths.js
33192
+ var require_staging_paths = __commonJS({
33193
+ "../sidekick-core/dist/staging-paths.js"(exports2) {
33194
+ "use strict";
33195
+ Object.defineProperty(exports2, "__esModule", { value: true });
33196
+ exports2.CONSUMED_FILE_PATTERN = void 0;
33197
+ exports2.getStagingRoot = getStagingRoot;
33198
+ exports2.getHookDir = getHookDir;
33199
+ exports2.getReminderPath = getReminderPath;
33200
+ exports2.isValidPathSegment = isValidPathSegment;
33201
+ exports2.validatePathSegment = validatePathSegment;
33202
+ exports2.filterActiveReminderFiles = filterActiveReminderFiles;
33203
+ exports2.createConsumedFilePattern = createConsumedFilePattern;
33204
+ exports2.extractConsumedTimestamp = extractConsumedTimestamp;
33205
+ var node_path_1 = require("node:path");
33206
+ function getStagingRoot(stateDir, sessionId) {
33207
+ return (0, node_path_1.join)(stateDir, "sessions", sessionId, "stage");
33208
+ }
33209
+ function getHookDir(stateDir, sessionId, hookName) {
33210
+ return (0, node_path_1.join)(getStagingRoot(stateDir, sessionId), hookName);
33211
+ }
33212
+ function getReminderPath(stateDir, sessionId, hookName, reminderName) {
33213
+ return (0, node_path_1.join)(getHookDir(stateDir, sessionId, hookName), `${reminderName}.json`);
33214
+ }
33215
+ function isValidPathSegment(s) {
33216
+ if (s === "")
33217
+ return false;
33218
+ if (s === "." || s === "..")
33219
+ return false;
33220
+ if (s.includes("/") || s.includes("\\"))
33221
+ return false;
33222
+ if ((0, node_path_1.basename)(s) !== s)
33223
+ return false;
33224
+ return /^[a-zA-Z0-9._-]+$/.test(s);
33170
33225
  }
33226
+ function validatePathSegment(segment, name) {
33227
+ if (!isValidPathSegment(segment)) {
33228
+ throw new Error(`Invalid ${name}: must be a non-empty alphanumeric string without path separators`);
33229
+ }
33230
+ }
33231
+ exports2.CONSUMED_FILE_PATTERN = /\.\d+\.json$/;
33232
+ function filterActiveReminderFiles(files) {
33233
+ return files.filter((f) => f.endsWith(".json") && !exports2.CONSUMED_FILE_PATTERN.test(f));
33234
+ }
33235
+ function createConsumedFilePattern(reminderName) {
33236
+ return new RegExp(`^${reminderName}\\.(\\d+)\\.json$`);
33237
+ }
33238
+ function extractConsumedTimestamp(filename, reminderName) {
33239
+ const pattern = createConsumedFilePattern(reminderName);
33240
+ const match = pattern.exec(filename);
33241
+ return match ? parseInt(match[1], 10) : null;
33242
+ }
33243
+ }
33244
+ });
33245
+
33246
+ // ../sidekick-core/dist/session-log-writer.js
33247
+ var require_session_log_writer = __commonJS({
33248
+ "../sidekick-core/dist/session-log-writer.js"(exports2) {
33249
+ "use strict";
33250
+ Object.defineProperty(exports2, "__esModule", { value: true });
33251
+ exports2.SessionLogWriter = void 0;
33252
+ var promises_1 = require("node:fs/promises");
33253
+ var node_path_1 = require("node:path");
33254
+ var node_fs_1 = require("node:fs");
33255
+ var staging_paths_js_1 = require_staging_paths();
33256
+ var SessionLogWriter = class {
33257
+ sessionsDir;
33258
+ maxHandles;
33259
+ idleTimeoutMs;
33260
+ /** Map key: `${sessionId}/${logFile}` */
33261
+ handles = /* @__PURE__ */ new Map();
33262
+ constructor(options) {
33263
+ this.sessionsDir = options.sessionsDir;
33264
+ this.maxHandles = options.maxHandles ?? 10;
33265
+ this.idleTimeoutMs = options.idleTimeoutMs ?? 30 * 60 * 1e3;
33266
+ }
33267
+ get handleCount() {
33268
+ return this.handles.size;
33269
+ }
33270
+ /**
33271
+ * Write an NDJSON line to a per-session log file.
33272
+ * Creates the directory and file handle lazily.
33273
+ * Skips if sessionId is empty (daemon lifecycle events before session exists).
33274
+ */
33275
+ async write(sessionId, logFile, line) {
33276
+ if (!sessionId)
33277
+ return;
33278
+ if (!(0, staging_paths_js_1.isValidPathSegment)(sessionId) || !(0, staging_paths_js_1.isValidPathSegment)(logFile))
33279
+ return;
33280
+ const key = `${sessionId}/${logFile}`;
33281
+ let entry = this.handles.get(key);
33282
+ if (!entry) {
33283
+ if (this.handles.size >= this.maxHandles) {
33284
+ this.evictLRU();
33285
+ }
33286
+ const logDir = (0, node_path_1.join)(this.sessionsDir, sessionId, "logs");
33287
+ await (0, promises_1.mkdir)(logDir, { recursive: true });
33288
+ const filePath = (0, node_path_1.join)(logDir, logFile);
33289
+ const stream = (0, node_fs_1.createWriteStream)(filePath, { flags: "a" });
33290
+ const ready = new Promise((resolve3, reject) => {
33291
+ stream.once("open", () => resolve3());
33292
+ stream.once("error", (err) => {
33293
+ this.handles.delete(key);
33294
+ stream.destroy();
33295
+ reject(err);
33296
+ });
33297
+ });
33298
+ entry = {
33299
+ stream,
33300
+ lastUsed: Date.now(),
33301
+ timer: null,
33302
+ ready
33303
+ };
33304
+ this.handles.set(key, entry);
33305
+ }
33306
+ await entry.ready;
33307
+ entry.lastUsed = Date.now();
33308
+ this.resetIdleTimer(key, entry);
33309
+ return new Promise((resolve3, reject) => {
33310
+ entry.stream.write(line, (err) => {
33311
+ if (err) {
33312
+ void this.closeHandle(key);
33313
+ reject(err);
33314
+ } else {
33315
+ resolve3();
33316
+ }
33317
+ });
33318
+ });
33319
+ }
33320
+ /** Close all handles for a specific session. */
33321
+ async closeSession(sessionId) {
33322
+ const prefix = `${sessionId}/`;
33323
+ const toClose = [];
33324
+ for (const key of this.handles.keys()) {
33325
+ if (key.startsWith(prefix)) {
33326
+ toClose.push(key);
33327
+ }
33328
+ }
33329
+ await Promise.all(toClose.map((key) => this.closeHandle(key)));
33330
+ }
33331
+ /** Close all open handles. */
33332
+ async closeAll() {
33333
+ const keys = [...this.handles.keys()];
33334
+ await Promise.all(keys.map((key) => this.closeHandle(key)));
33335
+ }
33336
+ async closeHandle(key) {
33337
+ const entry = this.handles.get(key);
33338
+ if (!entry)
33339
+ return;
33340
+ if (entry.timer)
33341
+ clearTimeout(entry.timer);
33342
+ this.handles.delete(key);
33343
+ return new Promise((resolve3) => {
33344
+ entry.stream.end(() => resolve3());
33345
+ });
33346
+ }
33347
+ evictLRU() {
33348
+ let oldestKey = "";
33349
+ let oldestTime = Infinity;
33350
+ for (const [key, entry] of this.handles) {
33351
+ if (entry.lastUsed < oldestTime) {
33352
+ oldestTime = entry.lastUsed;
33353
+ oldestKey = key;
33354
+ }
33355
+ }
33356
+ void this.closeHandle(oldestKey);
33357
+ }
33358
+ resetIdleTimer(key, entry) {
33359
+ if (entry.timer)
33360
+ clearTimeout(entry.timer);
33361
+ entry.timer = setTimeout(() => {
33362
+ void this.closeHandle(key);
33363
+ }, this.idleTimeoutMs);
33364
+ entry.timer.unref();
33365
+ }
33366
+ };
33367
+ exports2.SessionLogWriter = SessionLogWriter;
33171
33368
  }
33172
33369
  });
33173
33370
 
@@ -44910,7 +45107,7 @@ var require_structured_logging = __commonJS({
44910
45107
  return mod && mod.__esModule ? mod : { "default": mod };
44911
45108
  };
44912
45109
  Object.defineProperty(exports2, "__esModule", { value: true });
44913
- exports2.DEFAULT_MAX_FILES = exports2.DEFAULT_ROTATE_SIZE_BYTES = exports2.LOG_LEVELS = exports2.logEvent = exports2.LogEvents = void 0;
45110
+ exports2.DEFAULT_MAX_FILES = exports2.DEFAULT_ROTATE_SIZE_BYTES = exports2.LOG_LEVELS = exports2.SessionLogWriter = exports2.setSessionLogWriter = exports2.logEvent = exports2.LogEvents = void 0;
44914
45111
  exports2.getComponentLogLevel = getComponentLogLevel;
44915
45112
  exports2.createLogManager = createLogManager;
44916
45113
  exports2.createContextLogger = createContextLogger;
@@ -44927,6 +45124,13 @@ var require_structured_logging = __commonJS({
44927
45124
  Object.defineProperty(exports2, "logEvent", { enumerable: true, get: function() {
44928
45125
  return log_events_1.logEvent;
44929
45126
  } });
45127
+ Object.defineProperty(exports2, "setSessionLogWriter", { enumerable: true, get: function() {
45128
+ return log_events_1.setSessionLogWriter;
45129
+ } });
45130
+ var session_log_writer_1 = require_session_log_writer();
45131
+ Object.defineProperty(exports2, "SessionLogWriter", { enumerable: true, get: function() {
45132
+ return session_log_writer_1.SessionLogWriter;
45133
+ } });
44930
45134
  exports2.LOG_LEVELS = {
44931
45135
  trace: 10,
44932
45136
  debug: 20,
@@ -57409,61 +57613,6 @@ var require_errors6 = __commonJS({
57409
57613
  }
57410
57614
  });
57411
57615
 
57412
- // ../sidekick-core/dist/staging-paths.js
57413
- var require_staging_paths = __commonJS({
57414
- "../sidekick-core/dist/staging-paths.js"(exports2) {
57415
- "use strict";
57416
- Object.defineProperty(exports2, "__esModule", { value: true });
57417
- exports2.CONSUMED_FILE_PATTERN = void 0;
57418
- exports2.getStagingRoot = getStagingRoot;
57419
- exports2.getHookDir = getHookDir;
57420
- exports2.getReminderPath = getReminderPath;
57421
- exports2.isValidPathSegment = isValidPathSegment;
57422
- exports2.validatePathSegment = validatePathSegment;
57423
- exports2.filterActiveReminderFiles = filterActiveReminderFiles;
57424
- exports2.createConsumedFilePattern = createConsumedFilePattern;
57425
- exports2.extractConsumedTimestamp = extractConsumedTimestamp;
57426
- var node_path_1 = require("node:path");
57427
- function getStagingRoot(stateDir, sessionId) {
57428
- return (0, node_path_1.join)(stateDir, "sessions", sessionId, "stage");
57429
- }
57430
- function getHookDir(stateDir, sessionId, hookName) {
57431
- return (0, node_path_1.join)(getStagingRoot(stateDir, sessionId), hookName);
57432
- }
57433
- function getReminderPath(stateDir, sessionId, hookName, reminderName) {
57434
- return (0, node_path_1.join)(getHookDir(stateDir, sessionId, hookName), `${reminderName}.json`);
57435
- }
57436
- function isValidPathSegment(s) {
57437
- if (s === "")
57438
- return false;
57439
- if (s === "." || s === "..")
57440
- return false;
57441
- if (s.includes("/") || s.includes("\\"))
57442
- return false;
57443
- if ((0, node_path_1.basename)(s) !== s)
57444
- return false;
57445
- return /^[a-zA-Z0-9._-]+$/.test(s);
57446
- }
57447
- function validatePathSegment(segment, name) {
57448
- if (!isValidPathSegment(segment)) {
57449
- throw new Error(`Invalid ${name}: must be a non-empty alphanumeric string without path separators`);
57450
- }
57451
- }
57452
- exports2.CONSUMED_FILE_PATTERN = /\.\d+\.json$/;
57453
- function filterActiveReminderFiles(files) {
57454
- return files.filter((f) => f.endsWith(".json") && !exports2.CONSUMED_FILE_PATTERN.test(f));
57455
- }
57456
- function createConsumedFilePattern(reminderName) {
57457
- return new RegExp(`^${reminderName}\\.(\\d+)\\.json$`);
57458
- }
57459
- function extractConsumedTimestamp(filename, reminderName) {
57460
- const pattern = createConsumedFilePattern(reminderName);
57461
- const match = pattern.exec(filename);
57462
- return match ? parseInt(match[1], 10) : null;
57463
- }
57464
- }
57465
- });
57466
-
57467
57616
  // ../sidekick-core/dist/staging-service.js
57468
57617
  var require_staging_service = __commonJS({
57469
57618
  "../sidekick-core/dist/staging-service.js"(exports2) {
@@ -58339,6 +58488,9 @@ var require_path_resolver = __commonJS({
58339
58488
  sessionStagingDir(sessionId) {
58340
58489
  return (0, node_path_1.join)(this.sessionRootDir(sessionId), "stage");
58341
58490
  }
58491
+ sessionLogsDir(sessionId) {
58492
+ return (0, node_path_1.join)(this.sessionRootDir(sessionId), "logs");
58493
+ }
58342
58494
  hookStagingDir(sessionId, hookName) {
58343
58495
  return (0, node_path_1.join)(this.sessionStagingDir(sessionId), hookName);
58344
58496
  }
@@ -63059,9 +63211,9 @@ var require_dist4 = __commonJS({
63059
63211
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
63060
63212
  };
63061
63213
  Object.defineProperty(exports2, "__esModule", { value: true });
63062
- exports2.readKeyFromEnvFile = exports2.determineOverallStatus = 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.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;
63063
- exports2.StateService = exports2.createHookableLogger = exports2.InstrumentedProfileProviderFactory = exports2.InstrumentedLLMProvider = exports2.ServiceFactoryImpl = exports2.TranscriptServiceImpl = exports2.createDefaultTokenUsage = exports2.createDefaultMetrics = exports2.copyWithTimestampSync = exports2.renameWithTimestampSync = exports2.renameWithTimestamp = exports2.copyWithTimestamp = exports2.getTimestampedPath = exports2.extractToolResultPreview = exports2.extractToolCallPreview = exports2.extractTextFromContent = exports2.extractContentPreview = exports2.HandlerRegistryImpl = exports2.extractConsumedTimestamp = exports2.createConsumedFilePattern = exports2.CONSUMED_FILE_PATTERN = exports2.filterActiveReminderFiles = exports2.validatePathSegment = exports2.isValidPathSegment = exports2.getReminderPath = exports2.getHookDir = exports2.getStagingRoot = 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 = void 0;
63064
- 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 = void 0;
63214
+ 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;
63215
+ 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;
63216
+ 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;
63065
63217
  var types_1 = require_dist();
63066
63218
  Object.defineProperty(exports2, "TaskTypes", { enumerable: true, get: function() {
63067
63219
  return types_1.TaskTypes;
@@ -63194,6 +63346,12 @@ var require_dist4 = __commonJS({
63194
63346
  Object.defineProperty(exports2, "logEvent", { enumerable: true, get: function() {
63195
63347
  return structured_logging_1.logEvent;
63196
63348
  } });
63349
+ Object.defineProperty(exports2, "setSessionLogWriter", { enumerable: true, get: function() {
63350
+ return structured_logging_1.setSessionLogWriter;
63351
+ } });
63352
+ Object.defineProperty(exports2, "SessionLogWriter", { enumerable: true, get: function() {
63353
+ return structured_logging_1.SessionLogWriter;
63354
+ } });
63197
63355
  var daemon_client_1 = require_daemon_client2();
63198
63356
  Object.defineProperty(exports2, "killAllDaemons", { enumerable: true, get: function() {
63199
63357
  return daemon_client_1.killAllDaemons;
@@ -78138,6 +78296,7 @@ var require_daemon = __commonJS({
78138
78296
  token = "";
78139
78297
  registryService;
78140
78298
  timerManager;
78299
+ sessionLogWriter;
78141
78300
  /** Cache persona for handoff on clear. */
78142
78301
  cachePersonaForClear(personaId) {
78143
78302
  this.lastClearedPersona = { personaId, timestamp: Date.now() };
@@ -78180,8 +78339,9 @@ var require_daemon = __commonJS({
78180
78339
  destinations: {
78181
78340
  file: {
78182
78341
  path: path_1.default.join(logDir, "sidekickd.log"),
78183
- maxSizeBytes: this.configService.core.logging.rotation?.maxSizeBytes ?? 10485760,
78184
- maxFiles: this.configService.core.logging.rotation?.maxFiles ?? 5
78342
+ maxSizeBytes: this.configService.core.logging.rotation?.maxSizeBytes ?? 2097152,
78343
+ // 2MB (ephemeral debug window)
78344
+ maxFiles: this.configService.core.logging.rotation?.maxFiles ?? 2
78185
78345
  },
78186
78346
  console: { enabled: this.configService.core.logging.consoleEnabled }
78187
78347
  }
@@ -78193,6 +78353,13 @@ var require_daemon = __commonJS({
78193
78353
  getStartTime: () => this.timerManager.startTime
78194
78354
  });
78195
78355
  this.logger = this.logMetrics.createCountingLogger();
78356
+ const sessionsDir = path_1.default.join(projectDir2, ".sidekick", "sessions");
78357
+ this.sessionLogWriter = new core_1.SessionLogWriter({
78358
+ sessionsDir,
78359
+ maxHandles: 10,
78360
+ idleTimeoutMs: 30 * 60 * 1e3
78361
+ });
78362
+ (0, core_1.setSessionLogWriter)(this.sessionLogWriter);
78196
78363
  this.stateService = new core_1.StateService(projectDir2, {
78197
78364
  cache: true,
78198
78365
  logger: this.logger,
@@ -78300,6 +78467,8 @@ var require_daemon = __commonJS({
78300
78467
  }
78301
78468
  async stop() {
78302
78469
  this.logger.info("Daemon stopping");
78470
+ (0, core_1.setSessionLogWriter)(null);
78471
+ await this.sessionLogWriter.closeAll();
78303
78472
  this.timerManager.stopAll();
78304
78473
  this.configWatcher.stop();
78305
78474
  this.personaWatcher.stop();
@@ -78625,6 +78794,7 @@ var require_daemon = __commonJS({
78625
78794
  await this.llmManager.shutdownSessionProvider(sessionId, log);
78626
78795
  this.logMetrics.deleteSessionCounters(sessionId);
78627
78796
  await this.serviceFactory.shutdownSession(sessionId);
78797
+ await this.sessionLogWriter.closeSession(sessionId);
78628
78798
  log.info("Session ended");
78629
78799
  }
78630
78800
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scotthamilton77/sidekick",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "AI pair programming assistant with personas, session tracking, and contextual nudges",
5
5
  "bin": {
6
6
  "sidekick": "dist/bin.js"