@scotthamilton77/sidekick 0.0.2-alpha → 0.0.5-alpha

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 +1234 -16
  2. package/dist/daemon.js +70160 -0
  3. package/package.json +2 -5
package/dist/bin.js CHANGED
@@ -16699,6 +16699,72 @@ var require_hook_input = __commonJS({
16699
16699
  }
16700
16700
  });
16701
16701
 
16702
+ // ../types/dist/setup-status.js
16703
+ var require_setup_status = __commonJS({
16704
+ "../types/dist/setup-status.js"(exports2) {
16705
+ "use strict";
16706
+ Object.defineProperty(exports2, "__esModule", { value: true });
16707
+ exports2.ProjectSetupStatusSchema = exports2.GitignoreStatusSchema = exports2.UserSetupStatusSchema = exports2.ProjectApiKeyHealthSchema = exports2.ApiKeyHealthSchema = void 0;
16708
+ var zod_1 = require_zod();
16709
+ exports2.ApiKeyHealthSchema = zod_1.z.enum([
16710
+ "missing",
16711
+ // Key needed but not found
16712
+ "not-required",
16713
+ // No LLM profiles configured for provider
16714
+ "pending-validation",
16715
+ // Key exists but not validated
16716
+ "invalid",
16717
+ // Validation failed
16718
+ "healthy"
16719
+ // Validation succeeded
16720
+ ]);
16721
+ exports2.ProjectApiKeyHealthSchema = zod_1.z.enum([
16722
+ "missing",
16723
+ "not-required",
16724
+ "pending-validation",
16725
+ "invalid",
16726
+ "healthy",
16727
+ "user"
16728
+ // Deferring to user-level
16729
+ ]);
16730
+ exports2.UserSetupStatusSchema = zod_1.z.object({
16731
+ version: zod_1.z.literal(1),
16732
+ lastUpdatedAt: zod_1.z.string(),
16733
+ // ISO timestamp
16734
+ preferences: zod_1.z.object({
16735
+ autoConfigureProjects: zod_1.z.boolean(),
16736
+ defaultStatuslineScope: zod_1.z.enum(["user", "project"]),
16737
+ defaultApiKeyScope: zod_1.z.enum(["user", "project", "skip"])
16738
+ }),
16739
+ statusline: zod_1.z.enum(["configured", "skipped"]),
16740
+ apiKeys: zod_1.z.object({
16741
+ OPENROUTER_API_KEY: exports2.ApiKeyHealthSchema,
16742
+ OPENAI_API_KEY: exports2.ApiKeyHealthSchema
16743
+ })
16744
+ });
16745
+ exports2.GitignoreStatusSchema = zod_1.z.enum([
16746
+ "unknown",
16747
+ // Setup hasn't checked yet (legacy projects)
16748
+ "missing",
16749
+ // User declined or entries not present
16750
+ "installed"
16751
+ // Sidekick section present in .gitignore
16752
+ ]);
16753
+ exports2.ProjectSetupStatusSchema = zod_1.z.object({
16754
+ version: zod_1.z.literal(1),
16755
+ lastUpdatedAt: zod_1.z.string(),
16756
+ // ISO timestamp
16757
+ autoConfigured: zod_1.z.boolean(),
16758
+ statusline: zod_1.z.enum(["configured", "skipped", "user"]),
16759
+ apiKeys: zod_1.z.object({
16760
+ OPENROUTER_API_KEY: exports2.ProjectApiKeyHealthSchema,
16761
+ OPENAI_API_KEY: exports2.ProjectApiKeyHealthSchema
16762
+ }),
16763
+ gitignore: exports2.GitignoreStatusSchema.optional().default("unknown")
16764
+ });
16765
+ }
16766
+ });
16767
+
16702
16768
  // ../types/dist/index.js
16703
16769
  var require_dist = __commonJS({
16704
16770
  "../types/dist/index.js"(exports2) {
@@ -16729,6 +16795,7 @@ var require_dist = __commonJS({
16729
16795
  __exportStar(require_context(), exports2);
16730
16796
  __exportStar(require_tasks(), exports2);
16731
16797
  __exportStar(require_hook_input(), exports2);
16798
+ __exportStar(require_setup_status(), exports2);
16732
16799
  }
16733
16800
  });
16734
16801
 
@@ -32722,7 +32789,10 @@ var require_package3 = __commonJS({
32722
32789
  lint: "eslint packages",
32723
32790
  "lint:fix": "eslint packages --fix",
32724
32791
  format: 'prettier --write "packages/**/*.ts"',
32725
- sidekick: "node packages/sidekick-cli/dist/bin.js"
32792
+ sidekick: "node packages/sidekick-cli/dist/bin.js",
32793
+ "test:dist:setup": "./scripts/test-dist.sh setup",
32794
+ "test:dist:teardown": "./scripts/test-dist.sh teardown",
32795
+ "test:dist:rebuild": "./scripts/test-dist.sh rebuild"
32726
32796
  },
32727
32797
  devDependencies: {
32728
32798
  "@eslint/js": "^9.39.1",
@@ -32785,15 +32855,7 @@ var require_daemon_client2 = __commonJS({
32785
32855
  await this.waitForShutdown();
32786
32856
  }
32787
32857
  this.logger.info("Starting daemon...");
32788
- let daemonPath;
32789
- try {
32790
- const pkgPath = require.resolve("@sidekick/daemon/package.json");
32791
- const pkg = require(pkgPath);
32792
- const binPath = pkg.bin ? typeof pkg.bin === "string" ? pkg.bin : pkg.bin["sidekickd"] : pkg.main;
32793
- daemonPath = path_1.default.resolve(path_1.default.dirname(pkgPath), binPath ?? "dist/index.js");
32794
- } catch {
32795
- daemonPath = path_1.default.resolve(__dirname, "../../sidekick-daemon/dist/index.js");
32796
- }
32858
+ const daemonPath = await this.resolveDaemonPath();
32797
32859
  const child = (0, child_process_1.spawn)("node", [daemonPath, this.projectDir], {
32798
32860
  detached: true,
32799
32861
  stdio: "ignore",
@@ -32872,6 +32934,33 @@ var require_daemon_client2 = __commonJS({
32872
32934
  } catch {
32873
32935
  }
32874
32936
  }
32937
+ /**
32938
+ * Resolve the daemon entry point path.
32939
+ * Checks in order:
32940
+ * 1. Bundled context: daemon.js as sibling file (npm distribution)
32941
+ * 2. Dev mode: workspace package resolution
32942
+ */
32943
+ async resolveDaemonPath() {
32944
+ const bundledPath = path_1.default.resolve(__dirname, "daemon.js");
32945
+ try {
32946
+ await promises_12.default.access(bundledPath);
32947
+ this.logger.debug("Using bundled daemon", { path: bundledPath });
32948
+ return bundledPath;
32949
+ } catch {
32950
+ }
32951
+ try {
32952
+ const pkgPath = require.resolve("@sidekick/daemon/package.json");
32953
+ const pkg = require(pkgPath);
32954
+ const binPath = pkg.bin ? typeof pkg.bin === "string" ? pkg.bin : pkg.bin["sidekickd"] : pkg.main;
32955
+ const daemonPath = path_1.default.resolve(path_1.default.dirname(pkgPath), binPath ?? "dist/index.js");
32956
+ this.logger.debug("Using workspace daemon", { path: daemonPath });
32957
+ return daemonPath;
32958
+ } catch {
32959
+ const fallbackPath = path_1.default.resolve(__dirname, "../../sidekick-daemon/dist/index.js");
32960
+ this.logger.debug("Using fallback daemon path", { path: fallbackPath });
32961
+ return fallbackPath;
32962
+ }
32963
+ }
32875
32964
  /**
32876
32965
  * Request daemon shutdown (fire-and-forget).
32877
32966
  * Sends shutdown request, receives ack, closes connection immediately.
@@ -33113,6 +33202,346 @@ var require_daemon_client2 = __commonJS({
33113
33202
  }
33114
33203
  });
33115
33204
 
33205
+ // ../sidekick-core/dist/setup-status-service.js
33206
+ var require_setup_status_service = __commonJS({
33207
+ "../sidekick-core/dist/setup-status-service.js"(exports2) {
33208
+ "use strict";
33209
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
33210
+ if (k2 === void 0) k2 = k;
33211
+ var desc = Object.getOwnPropertyDescriptor(m, k);
33212
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
33213
+ desc = { enumerable: true, get: function() {
33214
+ return m[k];
33215
+ } };
33216
+ }
33217
+ Object.defineProperty(o, k2, desc);
33218
+ } : function(o, m, k, k2) {
33219
+ if (k2 === void 0) k2 = k;
33220
+ o[k2] = m[k];
33221
+ });
33222
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
33223
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
33224
+ } : function(o, v) {
33225
+ o["default"] = v;
33226
+ });
33227
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
33228
+ var ownKeys = function(o) {
33229
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
33230
+ var ar = [];
33231
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
33232
+ return ar;
33233
+ };
33234
+ return ownKeys(o);
33235
+ };
33236
+ return function(mod) {
33237
+ if (mod && mod.__esModule) return mod;
33238
+ var result = {};
33239
+ if (mod != null) {
33240
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33241
+ }
33242
+ __setModuleDefault(result, mod);
33243
+ return result;
33244
+ };
33245
+ }();
33246
+ Object.defineProperty(exports2, "__esModule", { value: true });
33247
+ exports2.SetupStatusService = void 0;
33248
+ exports2.createSetupStatusService = createSetupStatusService;
33249
+ var fs = __importStar(require("node:fs/promises"));
33250
+ var path = __importStar(require("node:path"));
33251
+ var os = __importStar(require("node:os"));
33252
+ var types_1 = require_dist();
33253
+ var SetupStatusService = class {
33254
+ constructor(projectDir, options) {
33255
+ this.projectDir = projectDir;
33256
+ this.homeDir = options?.homeDir ?? os.homedir();
33257
+ this.logger = options?.logger;
33258
+ }
33259
+ // === Paths ===
33260
+ get userStatusPath() {
33261
+ return path.join(this.homeDir, ".sidekick", "setup-status.json");
33262
+ }
33263
+ get projectStatusPath() {
33264
+ return path.join(this.projectDir, ".sidekick", "setup-status.json");
33265
+ }
33266
+ // === Low-level read/write ===
33267
+ async getUserStatus() {
33268
+ try {
33269
+ const content = await fs.readFile(this.userStatusPath, "utf-8");
33270
+ const parsed = types_1.UserSetupStatusSchema.safeParse(JSON.parse(content));
33271
+ if (!parsed.success) {
33272
+ this.logger?.warn("Invalid user setup status", { error: parsed.error });
33273
+ return null;
33274
+ }
33275
+ return parsed.data;
33276
+ } catch (err) {
33277
+ if (err.code === "ENOENT") {
33278
+ return null;
33279
+ }
33280
+ throw err;
33281
+ }
33282
+ }
33283
+ async getProjectStatus() {
33284
+ try {
33285
+ const content = await fs.readFile(this.projectStatusPath, "utf-8");
33286
+ const parsed = types_1.ProjectSetupStatusSchema.safeParse(JSON.parse(content));
33287
+ if (!parsed.success) {
33288
+ this.logger?.warn("Invalid project setup status", { error: parsed.error });
33289
+ return null;
33290
+ }
33291
+ return parsed.data;
33292
+ } catch (err) {
33293
+ if (err.code === "ENOENT") {
33294
+ return null;
33295
+ }
33296
+ throw err;
33297
+ }
33298
+ }
33299
+ async writeUserStatus(status) {
33300
+ const validated = types_1.UserSetupStatusSchema.parse(status);
33301
+ const dir = path.dirname(this.userStatusPath);
33302
+ await fs.mkdir(dir, { recursive: true });
33303
+ await fs.writeFile(this.userStatusPath, JSON.stringify(validated, null, 2) + "\n");
33304
+ this.logger?.debug("User setup status written", { path: this.userStatusPath });
33305
+ }
33306
+ async writeProjectStatus(status) {
33307
+ const validated = types_1.ProjectSetupStatusSchema.parse(status);
33308
+ const dir = path.dirname(this.projectStatusPath);
33309
+ await fs.mkdir(dir, { recursive: true });
33310
+ await fs.writeFile(this.projectStatusPath, JSON.stringify(validated, null, 2) + "\n");
33311
+ this.logger?.debug("Project setup status written", { path: this.projectStatusPath });
33312
+ }
33313
+ async updateUserStatus(updates) {
33314
+ const current = await this.getUserStatus();
33315
+ if (!current) {
33316
+ throw new Error("Cannot update user status: no existing status found");
33317
+ }
33318
+ const updated = {
33319
+ ...current,
33320
+ ...updates,
33321
+ lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
33322
+ };
33323
+ await this.writeUserStatus(updated);
33324
+ }
33325
+ async updateProjectStatus(updates) {
33326
+ const current = await this.getProjectStatus();
33327
+ if (!current) {
33328
+ throw new Error("Cannot update project status: no existing status found");
33329
+ }
33330
+ const updated = {
33331
+ ...current,
33332
+ ...updates,
33333
+ lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
33334
+ };
33335
+ await this.writeProjectStatus(updated);
33336
+ }
33337
+ // === Merged getters ===
33338
+ async getStatuslineHealth() {
33339
+ const project = await this.getProjectStatus();
33340
+ if (project?.statusline === "configured")
33341
+ return "configured";
33342
+ if (project?.statusline === "skipped")
33343
+ return "skipped";
33344
+ if (project?.statusline === "user") {
33345
+ const user2 = await this.getUserStatus();
33346
+ return user2?.statusline ?? "not-setup";
33347
+ }
33348
+ const user = await this.getUserStatus();
33349
+ return user?.statusline ?? "not-setup";
33350
+ }
33351
+ async getApiKeyHealth(key) {
33352
+ const project = await this.getProjectStatus();
33353
+ const projectHealth = project?.apiKeys[key];
33354
+ if (projectHealth && projectHealth !== "user") {
33355
+ return projectHealth;
33356
+ }
33357
+ const user = await this.getUserStatus();
33358
+ return user?.apiKeys[key] ?? "missing";
33359
+ }
33360
+ async getEffectiveApiKeyHealth(key) {
33361
+ const health = await this.getApiKeyHealth(key);
33362
+ return health === "user" ? "missing" : health;
33363
+ }
33364
+ async isHealthy() {
33365
+ const statusline = await this.getStatuslineHealth();
33366
+ const openrouterKey = await this.getEffectiveApiKeyHealth("OPENROUTER_API_KEY");
33367
+ return statusline === "configured" && (openrouterKey === "healthy" || openrouterKey === "not-required");
33368
+ }
33369
+ // === Auto-config helpers ===
33370
+ async isUserSetupComplete() {
33371
+ const user = await this.getUserStatus();
33372
+ return user !== null;
33373
+ }
33374
+ async isProjectConfigured() {
33375
+ const project = await this.getProjectStatus();
33376
+ return project !== null;
33377
+ }
33378
+ async shouldAutoConfigureProject() {
33379
+ const user = await this.getUserStatus();
33380
+ if (!user?.preferences.autoConfigureProjects) {
33381
+ return false;
33382
+ }
33383
+ return !await this.isProjectConfigured();
33384
+ }
33385
+ async setApiKeyHealth(key, health, scope) {
33386
+ if (scope === "user") {
33387
+ const current = await this.getUserStatus();
33388
+ if (!current) {
33389
+ throw new Error("Cannot update API key health: no user status found");
33390
+ }
33391
+ await this.updateUserStatus({
33392
+ apiKeys: { ...current.apiKeys, [key]: health }
33393
+ });
33394
+ } else {
33395
+ const current = await this.getProjectStatus();
33396
+ if (!current) {
33397
+ throw new Error("Cannot update API key health: no project status found");
33398
+ }
33399
+ await this.updateProjectStatus({
33400
+ apiKeys: { ...current.apiKeys, [key]: health }
33401
+ });
33402
+ }
33403
+ }
33404
+ // === Backward compatibility (for statusline service) ===
33405
+ /**
33406
+ * Get the overall setup state for statusline display.
33407
+ *
33408
+ * - `not-run` - Setup has never been run
33409
+ * - `partial` - User setup done, project not configured
33410
+ * - `healthy` - All configured and working
33411
+ * - `unhealthy` - Setup exists but has issues (invalid keys, etc)
33412
+ */
33413
+ async getSetupState() {
33414
+ const userStatus = await this.getUserStatus();
33415
+ const projectStatus = await this.getProjectStatus();
33416
+ if (!userStatus) {
33417
+ return "not-run";
33418
+ }
33419
+ if (!projectStatus) {
33420
+ return "partial";
33421
+ }
33422
+ const isHealthy = await this.isHealthy();
33423
+ return isHealthy ? "healthy" : "unhealthy";
33424
+ }
33425
+ };
33426
+ exports2.SetupStatusService = SetupStatusService;
33427
+ function createSetupStatusService(projectDir, homeDir) {
33428
+ return new SetupStatusService(projectDir, { homeDir });
33429
+ }
33430
+ }
33431
+ });
33432
+
33433
+ // ../sidekick-core/dist/gitignore.js
33434
+ var require_gitignore = __commonJS({
33435
+ "../sidekick-core/dist/gitignore.js"(exports2) {
33436
+ "use strict";
33437
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
33438
+ if (k2 === void 0) k2 = k;
33439
+ var desc = Object.getOwnPropertyDescriptor(m, k);
33440
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
33441
+ desc = { enumerable: true, get: function() {
33442
+ return m[k];
33443
+ } };
33444
+ }
33445
+ Object.defineProperty(o, k2, desc);
33446
+ } : function(o, m, k, k2) {
33447
+ if (k2 === void 0) k2 = k;
33448
+ o[k2] = m[k];
33449
+ });
33450
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
33451
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
33452
+ } : function(o, v) {
33453
+ o["default"] = v;
33454
+ });
33455
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
33456
+ var ownKeys = function(o) {
33457
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
33458
+ var ar = [];
33459
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
33460
+ return ar;
33461
+ };
33462
+ return ownKeys(o);
33463
+ };
33464
+ return function(mod) {
33465
+ if (mod && mod.__esModule) return mod;
33466
+ var result = {};
33467
+ if (mod != null) {
33468
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33469
+ }
33470
+ __setModuleDefault(result, mod);
33471
+ return result;
33472
+ };
33473
+ }();
33474
+ Object.defineProperty(exports2, "__esModule", { value: true });
33475
+ exports2.GITIGNORE_ENTRIES = exports2.SIDEKICK_SECTION_END = exports2.SIDEKICK_SECTION_START = void 0;
33476
+ exports2.installGitignoreSection = installGitignoreSection;
33477
+ exports2.removeGitignoreSection = removeGitignoreSection;
33478
+ exports2.detectGitignoreStatus = detectGitignoreStatus;
33479
+ var fs = __importStar(require("node:fs/promises"));
33480
+ var path = __importStar(require("node:path"));
33481
+ exports2.SIDEKICK_SECTION_START = "# >>> sidekick";
33482
+ exports2.SIDEKICK_SECTION_END = "# <<< sidekick";
33483
+ exports2.GITIGNORE_ENTRIES = [
33484
+ ".sidekick/logs/",
33485
+ ".sidekick/sessions/",
33486
+ ".sidekick/state/",
33487
+ ".sidekick/.env",
33488
+ ".sidekick/.env.local"
33489
+ ];
33490
+ async function installGitignoreSection(projectDir) {
33491
+ const gitignorePath = path.join(projectDir, ".gitignore");
33492
+ let content = "";
33493
+ try {
33494
+ content = await fs.readFile(gitignorePath, "utf-8");
33495
+ } catch (err) {
33496
+ if (err.code !== "ENOENT") {
33497
+ return { status: "error", error: `Failed to read .gitignore: ${err.message}` };
33498
+ }
33499
+ }
33500
+ if (content.includes(exports2.SIDEKICK_SECTION_START)) {
33501
+ return { status: "already-installed" };
33502
+ }
33503
+ const section = ["", exports2.SIDEKICK_SECTION_START, ...exports2.GITIGNORE_ENTRIES, exports2.SIDEKICK_SECTION_END].join("\n");
33504
+ const newContent = content.trimEnd() + section + "\n";
33505
+ try {
33506
+ await fs.writeFile(gitignorePath, newContent);
33507
+ return { status: "installed", entriesAdded: exports2.GITIGNORE_ENTRIES };
33508
+ } catch (err) {
33509
+ return { status: "error", error: `Failed to write .gitignore: ${err.message}` };
33510
+ }
33511
+ }
33512
+ async function removeGitignoreSection(projectDir) {
33513
+ const gitignorePath = path.join(projectDir, ".gitignore");
33514
+ try {
33515
+ const content = await fs.readFile(gitignorePath, "utf-8");
33516
+ const startIdx = content.indexOf(exports2.SIDEKICK_SECTION_START);
33517
+ const endIdx = content.indexOf(exports2.SIDEKICK_SECTION_END);
33518
+ if (startIdx === -1 || endIdx === -1 || endIdx < startIdx) {
33519
+ return false;
33520
+ }
33521
+ const lineStartIdx = content.lastIndexOf("\n", startIdx - 1) + 1;
33522
+ const lineEndIdx = content.indexOf("\n", endIdx);
33523
+ const actualEndIdx = lineEndIdx === -1 ? content.length : lineEndIdx + 1;
33524
+ const before = content.slice(0, lineStartIdx).trimEnd();
33525
+ const after = content.slice(actualEndIdx).trimStart();
33526
+ const newContent = before + (after ? "\n" + after : "") + "\n";
33527
+ await fs.writeFile(gitignorePath, newContent);
33528
+ return true;
33529
+ } catch {
33530
+ return false;
33531
+ }
33532
+ }
33533
+ async function detectGitignoreStatus(projectDir) {
33534
+ const gitignorePath = path.join(projectDir, ".gitignore");
33535
+ try {
33536
+ const content = await fs.readFile(gitignorePath, "utf-8");
33537
+ return content.includes(exports2.SIDEKICK_SECTION_START) ? "installed" : "missing";
33538
+ } catch {
33539
+ return "missing";
33540
+ }
33541
+ }
33542
+ }
33543
+ });
33544
+
33116
33545
  // ../sidekick-core/dist/state/errors.js
33117
33546
  var require_errors4 = __commonJS({
33118
33547
  "../sidekick-core/dist/state/errors.js"(exports2) {
@@ -38303,8 +38732,8 @@ var require_dist3 = __commonJS({
38303
38732
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
38304
38733
  };
38305
38734
  Object.defineProperty(exports2, "__esModule", { value: true });
38306
- 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.DaemonClient = exports2.killAllDaemons = exports2.logEvent = exports2.LogEvents = exports2.getComponentLogLevel = exports2.setupGlobalErrorHandlers = exports2.createLoggerFacade = exports2.createLogManager = exports2.createConsoleLogger = exports2.getUserDaemonsDir = exports2.getUserPidPath = exports2.getTokenPath = exports2.getSocketPath = exports2.getProjectHash = exports2.getPidPath = exports2.getLockPath = exports2.IpcService = exports2.IpcServer = exports2.loadPersonaFile = exports2.getDefaultPersonasDir = exports2.discoverPersonas = exports2.createPersonaLoader = exports2.reconstructTranscriptPath = exports2.encodeProjectPath = exports2.isPreCompactEvent = exports2.isStopEvent = exports2.isPostToolUseEvent = exports2.isPreToolUseEvent = exports2.isUserPromptSubmitEvent = exports2.isSessionEndEvent = exports2.isSessionStartEvent = exports2.isTranscriptEvent = exports2.isHookEvent = exports2.MetricsPersistPayloadSchema = exports2.CleanupPayloadSchema = exports2.ResumeGenerationPayloadSchema = exports2.SessionSummaryPayloadSchema = exports2.TaskTypes = void 0;
38307
- exports2.DaemonGlobalLogMetricsDescriptor = exports2.CliLogMetricsDescriptor = exports2.DaemonLogMetricsDescriptor = exports2.CompactionHistoryDescriptor = exports2.TranscriptMetricsDescriptor = exports2.GlobalStateAccessor = exports2.SessionStateAccessor = exports2.globalState = exports2.sessionState = exports2.StateCorruptError = exports2.StateNotFoundError = exports2.StateService = exports2.createHookableLogger = exports2.InstrumentedProfileProviderFactory = exports2.InstrumentedLLMProvider = exports2.ServiceFactoryImpl = exports2.TranscriptServiceImpl = exports2.createDefaultTokenUsage = exports2.createDefaultMetrics = exports2.copyWithTimestampSync = exports2.renameWithTimestampSync = exports2.renameWithTimestamp = exports2.copyWithTimestamp = exports2.getTimestampedPath = exports2.extractToolResultPreview = exports2.extractToolCallPreview = exports2.extractTextFromContent = exports2.extractContentPreview = void 0;
38735
+ 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.createSetupStatusService = exports2.SetupStatusService = exports2.DaemonClient = exports2.killAllDaemons = exports2.logEvent = exports2.LogEvents = exports2.getComponentLogLevel = exports2.setupGlobalErrorHandlers = exports2.createLoggerFacade = exports2.createLogManager = exports2.createConsoleLogger = exports2.getUserDaemonsDir = exports2.getUserPidPath = exports2.getTokenPath = exports2.getSocketPath = exports2.getProjectHash = exports2.getPidPath = exports2.getLockPath = exports2.IpcService = exports2.IpcServer = exports2.loadPersonaFile = exports2.getDefaultPersonasDir = exports2.discoverPersonas = exports2.createPersonaLoader = exports2.reconstructTranscriptPath = exports2.encodeProjectPath = exports2.isPreCompactEvent = exports2.isStopEvent = exports2.isPostToolUseEvent = exports2.isPreToolUseEvent = exports2.isUserPromptSubmitEvent = exports2.isSessionEndEvent = exports2.isSessionStartEvent = exports2.isTranscriptEvent = exports2.isHookEvent = exports2.MetricsPersistPayloadSchema = exports2.CleanupPayloadSchema = exports2.ResumeGenerationPayloadSchema = exports2.SessionSummaryPayloadSchema = exports2.TaskTypes = void 0;
38736
+ exports2.DaemonGlobalLogMetricsDescriptor = exports2.CliLogMetricsDescriptor = exports2.DaemonLogMetricsDescriptor = exports2.CompactionHistoryDescriptor = exports2.TranscriptMetricsDescriptor = exports2.GlobalStateAccessor = exports2.SessionStateAccessor = exports2.globalState = exports2.sessionState = exports2.StateCorruptError = exports2.StateNotFoundError = exports2.StateService = exports2.createHookableLogger = exports2.InstrumentedProfileProviderFactory = exports2.InstrumentedLLMProvider = exports2.ServiceFactoryImpl = exports2.TranscriptServiceImpl = exports2.createDefaultTokenUsage = exports2.createDefaultMetrics = exports2.copyWithTimestampSync = exports2.renameWithTimestampSync = exports2.renameWithTimestamp = exports2.copyWithTimestamp = exports2.getTimestampedPath = exports2.extractToolResultPreview = exports2.extractToolCallPreview = exports2.extractTextFromContent = exports2.extractContentPreview = exports2.HandlerRegistryImpl = exports2.extractConsumedTimestamp = exports2.createConsumedFilePattern = exports2.CONSUMED_FILE_PATTERN = exports2.filterActiveReminderFiles = exports2.validatePathSegment = exports2.isValidPathSegment = exports2.getReminderPath = void 0;
38308
38737
  var types_1 = require_dist();
38309
38738
  Object.defineProperty(exports2, "TaskTypes", { enumerable: true, get: function() {
38310
38739
  return types_1.TaskTypes;
@@ -38437,6 +38866,32 @@ var require_dist3 = __commonJS({
38437
38866
  Object.defineProperty(exports2, "DaemonClient", { enumerable: true, get: function() {
38438
38867
  return daemon_client_1.DaemonClient;
38439
38868
  } });
38869
+ var setup_status_service_1 = require_setup_status_service();
38870
+ Object.defineProperty(exports2, "SetupStatusService", { enumerable: true, get: function() {
38871
+ return setup_status_service_1.SetupStatusService;
38872
+ } });
38873
+ Object.defineProperty(exports2, "createSetupStatusService", { enumerable: true, get: function() {
38874
+ return setup_status_service_1.createSetupStatusService;
38875
+ } });
38876
+ var gitignore_1 = require_gitignore();
38877
+ Object.defineProperty(exports2, "installGitignoreSection", { enumerable: true, get: function() {
38878
+ return gitignore_1.installGitignoreSection;
38879
+ } });
38880
+ Object.defineProperty(exports2, "removeGitignoreSection", { enumerable: true, get: function() {
38881
+ return gitignore_1.removeGitignoreSection;
38882
+ } });
38883
+ Object.defineProperty(exports2, "detectGitignoreStatus", { enumerable: true, get: function() {
38884
+ return gitignore_1.detectGitignoreStatus;
38885
+ } });
38886
+ Object.defineProperty(exports2, "SIDEKICK_SECTION_START", { enumerable: true, get: function() {
38887
+ return gitignore_1.SIDEKICK_SECTION_START;
38888
+ } });
38889
+ Object.defineProperty(exports2, "SIDEKICK_SECTION_END", { enumerable: true, get: function() {
38890
+ return gitignore_1.SIDEKICK_SECTION_END;
38891
+ } });
38892
+ Object.defineProperty(exports2, "GITIGNORE_ENTRIES", { enumerable: true, get: function() {
38893
+ return gitignore_1.GITIGNORE_ENTRIES;
38894
+ } });
38440
38895
  var staging_service_1 = require_staging_service();
38441
38896
  Object.defineProperty(exports2, "StagingServiceCore", { enumerable: true, get: function() {
38442
38897
  return staging_service_1.StagingServiceCore;
@@ -48831,6 +49286,7 @@ var require_hook_command = __commonJS({
48831
49286
  exports2.translateToClaudeCodeFormat = translateToClaudeCodeFormat;
48832
49287
  exports2.parseHookArg = parseHookArg;
48833
49288
  exports2.handleUnifiedHookCommand = handleUnifiedHookCommand;
49289
+ var core_1 = require_dist3();
48834
49290
  var hook_js_1 = require_hook();
48835
49291
  function combineReasonAndContext(reason, additionalContext, separator = "\n\n") {
48836
49292
  if (reason && additionalContext) {
@@ -48848,7 +49304,7 @@ var require_hook_command = __commonJS({
48848
49304
  response.systemMessage = internal.userMessage;
48849
49305
  }
48850
49306
  if (internal.additionalContext) {
48851
- response.hookSpecificOutput = { additionalContext: internal.additionalContext };
49307
+ response.hookSpecificOutput = { hookEventName: "SessionStart", additionalContext: internal.additionalContext };
48852
49308
  }
48853
49309
  return response;
48854
49310
  }
@@ -48953,6 +49409,52 @@ var require_hook_command = __commonJS({
48953
49409
  return void 0;
48954
49410
  return HOOK_ARG_TO_NAME[arg];
48955
49411
  }
49412
+ var DEGRADED_MODE_MESSAGES = {
49413
+ "not-run": {
49414
+ additionalContext: `Sidekick plugin detected but not configured. Features like reminders, personas, and statusline are unavailable until setup is complete. If you haven't already, ask the user if you should execute the sidekick-config skill.`,
49415
+ userMessage: `Sidekick is installed but not configured. Run 'sidekick setup' to configure.`
49416
+ },
49417
+ partial: {
49418
+ additionalContext: `Sidekick user setup is complete but this project is not configured. Features like reminders, personas, and statusline are unavailable until project setup is complete. If you haven't already, ask the user if you should execute the sidekick-config skill.`,
49419
+ userMessage: `Sidekick project setup incomplete. Run 'sidekick setup' in this project to configure.`
49420
+ },
49421
+ unhealthy: {
49422
+ additionalContext: `Sidekick is configured but unhealthy (possibly invalid API keys or missing configuration). Features are unavailable until issues are resolved. If you haven't already, ask the user if you should execute sidekick doctor.`,
49423
+ userMessage: `Sidekick configuration is unhealthy. Run 'sidekick doctor' to diagnose issues.`
49424
+ }
49425
+ };
49426
+ var VERBOSE_DEGRADED_HOOKS = /* @__PURE__ */ new Set(["SessionStart", "UserPromptSubmit"]);
49427
+ async function checkSetupState(projectRoot, hookName, logger) {
49428
+ let state;
49429
+ try {
49430
+ const setupService = new core_1.SetupStatusService(projectRoot);
49431
+ state = await setupService.getSetupState();
49432
+ } catch (err) {
49433
+ logger.warn("Failed to check setup state, assuming healthy", {
49434
+ error: err instanceof Error ? err.message : String(err),
49435
+ hookName,
49436
+ projectRoot
49437
+ });
49438
+ return null;
49439
+ }
49440
+ if (state === "healthy") {
49441
+ return null;
49442
+ }
49443
+ const logData = { setupState: state, hookName, projectRoot };
49444
+ if (state === "not-run") {
49445
+ logger.info("Hook operating in degraded mode - setup not run", logData);
49446
+ } else {
49447
+ logger.warn("Hook operating in degraded mode", logData);
49448
+ }
49449
+ if (!VERBOSE_DEGRADED_HOOKS.has(hookName)) {
49450
+ return {};
49451
+ }
49452
+ const messages = DEGRADED_MODE_MESSAGES[state];
49453
+ return {
49454
+ additionalContext: messages.additionalContext,
49455
+ userMessage: messages.userMessage
49456
+ };
49457
+ }
48956
49458
  function parseInternalResponse(output, hookName, logger) {
48957
49459
  if (!output)
48958
49460
  return {};
@@ -48970,6 +49472,15 @@ var require_hook_command = __commonJS({
48970
49472
  async function handleUnifiedHookCommand(hookName, options, logger, stdout) {
48971
49473
  const { projectRoot, hookInput, correlationId, runtime } = options;
48972
49474
  logger.debug("Unified hook command invoked", { hookName, sessionId: hookInput.sessionId });
49475
+ const degradedResponse = await checkSetupState(projectRoot, hookName, logger);
49476
+ if (degradedResponse !== null) {
49477
+ const claudeResponse2 = translateToClaudeCodeFormat(hookName, degradedResponse);
49478
+ const outputStr2 = JSON.stringify(claudeResponse2);
49479
+ stdout.write(`${outputStr2}
49480
+ `);
49481
+ logger.debug("Hook completed in degraded mode", { hookName });
49482
+ return { exitCode: 0, output: outputStr2 };
49483
+ }
48973
49484
  let internalOutput = "";
48974
49485
  const captureStream = {
48975
49486
  write(chunk) {
@@ -51116,6 +51627,10 @@ var require_statusline_service = __commonJS({
51116
51627
  theme: this.config.theme,
51117
51628
  useColors: this.useColors
51118
51629
  });
51630
+ this.setupService = serviceConfig.setupService ?? new core_1.SetupStatusService(serviceConfig.projectDir ?? serviceConfig.cwd, {
51631
+ homeDir: serviceConfig.homeDir,
51632
+ logger: serviceConfig.logger
51633
+ });
51119
51634
  }
51120
51635
  /**
51121
51636
  * Load persona definition for the session.
@@ -51205,6 +51720,74 @@ var require_statusline_service = __commonJS({
51205
51720
  }
51206
51721
  return { ...types_js_2.DEFAULT_STATUSLINE_CONFIG, ...serviceConfig.config };
51207
51722
  }
51723
+ /**
51724
+ * Check setup status and return warning message if unhealthy.
51725
+ * Returns empty warning for healthy state.
51726
+ */
51727
+ async checkSetupStatus() {
51728
+ const state = await this.setupService.getSetupState();
51729
+ switch (state) {
51730
+ case "not-run":
51731
+ return {
51732
+ warning: "Sidekick not configured. Run 'sidekick setup' to get started.",
51733
+ state
51734
+ };
51735
+ case "partial":
51736
+ return {
51737
+ warning: "Project not configured. Run 'sidekick setup' for this project.",
51738
+ state
51739
+ };
51740
+ case "unhealthy": {
51741
+ const keyHealth = await this.setupService.getEffectiveApiKeyHealth("OPENROUTER_API_KEY");
51742
+ if (keyHealth === "missing") {
51743
+ return {
51744
+ warning: "OPENROUTER_API_KEY not found. Run 'sidekick doctor' or /sidekick-config",
51745
+ state
51746
+ };
51747
+ }
51748
+ if (keyHealth === "invalid") {
51749
+ return {
51750
+ warning: "API key invalid. Run 'sidekick doctor' to fix.",
51751
+ state
51752
+ };
51753
+ }
51754
+ return {
51755
+ warning: "Setup issue detected. Run 'sidekick doctor'.",
51756
+ state
51757
+ };
51758
+ }
51759
+ default:
51760
+ return { warning: "", state: "healthy" };
51761
+ }
51762
+ }
51763
+ /**
51764
+ * Build minimal view model for setup_warning display mode.
51765
+ * Only includes fields needed for warning display.
51766
+ */
51767
+ buildMinimalViewModel(setupCheck) {
51768
+ return {
51769
+ model: "",
51770
+ contextWindow: "",
51771
+ tokenUsageActual: "",
51772
+ tokenUsageEffective: "",
51773
+ tokenPercentageActual: "",
51774
+ tokenPercentageEffective: "",
51775
+ tokensStatus: "normal",
51776
+ cost: "",
51777
+ costStatus: "normal",
51778
+ duration: "",
51779
+ cwd: "",
51780
+ branch: "",
51781
+ branchColor: "",
51782
+ displayMode: "setup_warning",
51783
+ summary: setupCheck.warning,
51784
+ title: "",
51785
+ warningCount: 0,
51786
+ errorCount: 0,
51787
+ logStatus: "normal",
51788
+ personaName: ""
51789
+ };
51790
+ }
51208
51791
  /**
51209
51792
  * Render the statusline by fetching all data in parallel and formatting.
51210
51793
  *
@@ -51214,6 +51797,19 @@ var require_statusline_service = __commonJS({
51214
51797
  * for model/tokens/cost/duration instead of reading from state files.
51215
51798
  */
51216
51799
  async render() {
51800
+ const setupCheck = await this.checkSetupStatus();
51801
+ if (setupCheck.state !== "healthy") {
51802
+ const viewModel2 = this.buildMinimalViewModel(setupCheck);
51803
+ const ANSI_YELLOW = "\x1B[33m";
51804
+ const ANSI_RESET = "\x1B[0m";
51805
+ const text2 = this.useColors ? `${ANSI_YELLOW}${setupCheck.warning}${ANSI_RESET}` : setupCheck.warning;
51806
+ return {
51807
+ text: text2,
51808
+ displayMode: "setup_warning",
51809
+ staleData: false,
51810
+ viewModel: viewModel2
51811
+ };
51812
+ }
51217
51813
  const hasHookInput = !!this.hookInput;
51218
51814
  const [transcriptResult, summaryResult, resumeResult, snarkyResult, branchResult, baseline, logMetricsResult, personaResult] = await Promise.all([
51219
51815
  this.stateReader.getTranscriptMetrics(),
@@ -53005,6 +53601,582 @@ ${USAGE_TEXT}`);
53005
53601
  }
53006
53602
  });
53007
53603
 
53604
+ // ../sidekick-cli/dist/commands/setup/prompts.js
53605
+ var require_prompts = __commonJS({
53606
+ "../sidekick-cli/dist/commands/setup/prompts.js"(exports2) {
53607
+ "use strict";
53608
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
53609
+ if (k2 === void 0) k2 = k;
53610
+ var desc = Object.getOwnPropertyDescriptor(m, k);
53611
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
53612
+ desc = { enumerable: true, get: function() {
53613
+ return m[k];
53614
+ } };
53615
+ }
53616
+ Object.defineProperty(o, k2, desc);
53617
+ } : function(o, m, k, k2) {
53618
+ if (k2 === void 0) k2 = k;
53619
+ o[k2] = m[k];
53620
+ });
53621
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
53622
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
53623
+ } : function(o, v) {
53624
+ o["default"] = v;
53625
+ });
53626
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
53627
+ var ownKeys = function(o) {
53628
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
53629
+ var ar = [];
53630
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
53631
+ return ar;
53632
+ };
53633
+ return ownKeys(o);
53634
+ };
53635
+ return function(mod) {
53636
+ if (mod && mod.__esModule) return mod;
53637
+ var result = {};
53638
+ if (mod != null) {
53639
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
53640
+ }
53641
+ __setModuleDefault(result, mod);
53642
+ return result;
53643
+ };
53644
+ }();
53645
+ Object.defineProperty(exports2, "__esModule", { value: true });
53646
+ exports2.printHeader = printHeader;
53647
+ exports2.printStatus = printStatus;
53648
+ exports2.promptSelect = promptSelect;
53649
+ exports2.promptConfirm = promptConfirm;
53650
+ exports2.promptInput = promptInput;
53651
+ var readline = __importStar(require("node:readline"));
53652
+ var colors = {
53653
+ reset: "\x1B[0m",
53654
+ bold: "\x1B[1m",
53655
+ dim: "\x1B[2m",
53656
+ green: "\x1B[32m",
53657
+ yellow: "\x1B[33m",
53658
+ blue: "\x1B[34m",
53659
+ cyan: "\x1B[36m"
53660
+ };
53661
+ function printHeader(ctx, title, description) {
53662
+ ctx.stdout.write("\n");
53663
+ ctx.stdout.write(`${colors.bold}${title}${colors.reset}
53664
+ `);
53665
+ ctx.stdout.write("\u2500".repeat(Math.min(title.length + 10, 60)) + "\n");
53666
+ if (description) {
53667
+ ctx.stdout.write(`${colors.dim}${description}${colors.reset}
53668
+ `);
53669
+ }
53670
+ ctx.stdout.write("\n");
53671
+ }
53672
+ function printStatus(ctx, type, message) {
53673
+ const icons = { success: "\u2713", warning: "\u26A0", info: "\u2022", error: "\u2717" };
53674
+ const colorMap = { success: colors.green, warning: colors.yellow, info: colors.blue, error: "\x1B[31m" };
53675
+ ctx.stdout.write(`${colorMap[type]}${icons[type]}${colors.reset} ${message}
53676
+ `);
53677
+ }
53678
+ async function promptSelect(ctx, question, options) {
53679
+ ctx.stdout.write(`${question}
53680
+
53681
+ `);
53682
+ options.forEach((opt, i) => {
53683
+ ctx.stdout.write(` ${colors.cyan}${i + 1})${colors.reset} ${opt.label}
53684
+ `);
53685
+ if (opt.description) {
53686
+ ctx.stdout.write(` ${colors.dim}${opt.description}${colors.reset}
53687
+ `);
53688
+ }
53689
+ });
53690
+ ctx.stdout.write("\n");
53691
+ const rl = readline.createInterface({
53692
+ input: ctx.stdin,
53693
+ output: ctx.stdout,
53694
+ terminal: false
53695
+ });
53696
+ return new Promise((resolve3) => {
53697
+ ctx.stdout.write(`Enter choice (1-${options.length}): `);
53698
+ rl.once("line", (answer) => {
53699
+ rl.close();
53700
+ const num = parseInt(answer.trim(), 10);
53701
+ if (num >= 1 && num <= options.length) {
53702
+ resolve3(options[num - 1].value);
53703
+ } else {
53704
+ resolve3(options[0].value);
53705
+ }
53706
+ });
53707
+ });
53708
+ }
53709
+ async function promptConfirm(ctx, question, defaultYes = true) {
53710
+ const hint = defaultYes ? "[Y/n]" : "[y/N]";
53711
+ const rl = readline.createInterface({
53712
+ input: ctx.stdin,
53713
+ output: ctx.stdout,
53714
+ terminal: false
53715
+ });
53716
+ return new Promise((resolve3) => {
53717
+ ctx.stdout.write(`${question} ${hint} `);
53718
+ rl.once("line", (answer) => {
53719
+ rl.close();
53720
+ const normalized = answer.trim().toLowerCase();
53721
+ if (normalized === "") {
53722
+ resolve3(defaultYes);
53723
+ } else {
53724
+ resolve3(normalized === "y" || normalized === "yes");
53725
+ }
53726
+ });
53727
+ });
53728
+ }
53729
+ async function promptInput(ctx, question) {
53730
+ const rl = readline.createInterface({
53731
+ input: ctx.stdin,
53732
+ output: ctx.stdout,
53733
+ terminal: false
53734
+ });
53735
+ return new Promise((resolve3) => {
53736
+ ctx.stdout.write(`${question}: `);
53737
+ rl.once("line", (answer) => {
53738
+ rl.close();
53739
+ resolve3(answer.trim());
53740
+ });
53741
+ });
53742
+ }
53743
+ }
53744
+ });
53745
+
53746
+ // ../sidekick-cli/dist/commands/setup/validate-api-key.js
53747
+ var require_validate_api_key = __commonJS({
53748
+ "../sidekick-cli/dist/commands/setup/validate-api-key.js"(exports2) {
53749
+ "use strict";
53750
+ Object.defineProperty(exports2, "__esModule", { value: true });
53751
+ exports2.validateOpenRouterKey = validateOpenRouterKey;
53752
+ exports2.validateOpenAIKey = validateOpenAIKey;
53753
+ var API_ENDPOINTS = {
53754
+ openrouter: "https://openrouter.ai/api/v1/models",
53755
+ openai: "https://api.openai.com/v1/models"
53756
+ };
53757
+ async function validateApiKey(provider, apiKey, logger) {
53758
+ try {
53759
+ const response = await fetch(API_ENDPOINTS[provider], {
53760
+ headers: { Authorization: `Bearer ${apiKey}` }
53761
+ });
53762
+ if (response.ok) {
53763
+ return { valid: true };
53764
+ }
53765
+ if (response.status === 401) {
53766
+ return { valid: false, error: "Invalid API key" };
53767
+ }
53768
+ return { valid: false, error: `API returned status ${response.status}` };
53769
+ } catch (err) {
53770
+ logger?.warn("API key validation failed", { error: err });
53771
+ return { valid: false, error: err instanceof Error ? err.message : "Network error" };
53772
+ }
53773
+ }
53774
+ function validateOpenRouterKey(apiKey, logger) {
53775
+ return validateApiKey("openrouter", apiKey, logger);
53776
+ }
53777
+ function validateOpenAIKey(apiKey, logger) {
53778
+ return validateApiKey("openai", apiKey, logger);
53779
+ }
53780
+ }
53781
+ });
53782
+
53783
+ // ../sidekick-cli/dist/commands/setup/index.js
53784
+ var require_setup = __commonJS({
53785
+ "../sidekick-cli/dist/commands/setup/index.js"(exports2) {
53786
+ "use strict";
53787
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
53788
+ if (k2 === void 0) k2 = k;
53789
+ var desc = Object.getOwnPropertyDescriptor(m, k);
53790
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
53791
+ desc = { enumerable: true, get: function() {
53792
+ return m[k];
53793
+ } };
53794
+ }
53795
+ Object.defineProperty(o, k2, desc);
53796
+ } : function(o, m, k, k2) {
53797
+ if (k2 === void 0) k2 = k;
53798
+ o[k2] = m[k];
53799
+ });
53800
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
53801
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
53802
+ } : function(o, v) {
53803
+ o["default"] = v;
53804
+ });
53805
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
53806
+ var ownKeys = function(o) {
53807
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
53808
+ var ar = [];
53809
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
53810
+ return ar;
53811
+ };
53812
+ return ownKeys(o);
53813
+ };
53814
+ return function(mod) {
53815
+ if (mod && mod.__esModule) return mod;
53816
+ var result = {};
53817
+ if (mod != null) {
53818
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
53819
+ }
53820
+ __setModuleDefault(result, mod);
53821
+ return result;
53822
+ };
53823
+ }();
53824
+ Object.defineProperty(exports2, "__esModule", { value: true });
53825
+ exports2.handleSetupCommand = handleSetupCommand;
53826
+ var fs = __importStar(require("node:fs/promises"));
53827
+ var path = __importStar(require("node:path"));
53828
+ var os = __importStar(require("node:os"));
53829
+ var core_1 = require_dist3();
53830
+ var prompts_js_1 = require_prompts();
53831
+ var validate_api_key_js_1 = require_validate_api_key();
53832
+ var STATUSLINE_COMMAND = "npx @scotthamilton77/sidekick statusline --project-dir=$CLAUDE_PROJECT_DIR";
53833
+ function getApiKeyStatusType(health) {
53834
+ switch (health) {
53835
+ case "healthy":
53836
+ return "success";
53837
+ case "not-required":
53838
+ return "info";
53839
+ default:
53840
+ return "warning";
53841
+ }
53842
+ }
53843
+ async function configureStatusline(settingsPath, logger) {
53844
+ let settings = {};
53845
+ try {
53846
+ const content = await fs.readFile(settingsPath, "utf-8");
53847
+ settings = JSON.parse(content);
53848
+ } catch (err) {
53849
+ if (err.code !== "ENOENT") {
53850
+ throw err;
53851
+ }
53852
+ }
53853
+ settings.statusLine = {
53854
+ type: "command",
53855
+ command: STATUSLINE_COMMAND
53856
+ };
53857
+ const dir = path.dirname(settingsPath);
53858
+ await fs.mkdir(dir, { recursive: true });
53859
+ await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2) + "\n");
53860
+ logger?.info("Statusline configured", { path: settingsPath });
53861
+ }
53862
+ async function writeApiKeyToEnv(envPath, key, value) {
53863
+ const dir = path.dirname(envPath);
53864
+ await fs.mkdir(dir, { recursive: true });
53865
+ let content = "";
53866
+ try {
53867
+ content = await fs.readFile(envPath, "utf-8");
53868
+ } catch {
53869
+ }
53870
+ const keyRegex = new RegExp(`^${key}=.*$`, "m");
53871
+ if (keyRegex.test(content)) {
53872
+ content = content.replace(keyRegex, `${key}=${value}`);
53873
+ } else {
53874
+ if (content && !content.endsWith("\n")) {
53875
+ content += "\n";
53876
+ }
53877
+ content += `${key}=${value}
53878
+ `;
53879
+ }
53880
+ await fs.writeFile(envPath, content);
53881
+ }
53882
+ async function findExistingApiKey(keyName, homeDir, projectDir) {
53883
+ if (process.env[keyName]) {
53884
+ return process.env[keyName];
53885
+ }
53886
+ const envPaths = [
53887
+ path.join(homeDir, ".sidekick", ".env"),
53888
+ path.join(projectDir, ".sidekick", ".env"),
53889
+ path.join(projectDir, ".sidekick", ".env.local")
53890
+ ];
53891
+ for (const envPath of envPaths) {
53892
+ try {
53893
+ const content = await fs.readFile(envPath, "utf-8");
53894
+ const match = content.match(new RegExp(`^${keyName}=(.+)$`, "m"));
53895
+ if (match) {
53896
+ return match[1];
53897
+ }
53898
+ } catch {
53899
+ }
53900
+ }
53901
+ return null;
53902
+ }
53903
+ async function writePersonaConfig(_projectDir, homeDir, enabled) {
53904
+ const configDir = path.join(homeDir, ".sidekick");
53905
+ const configPath = path.join(configDir, "config.yaml");
53906
+ await fs.mkdir(configDir, { recursive: true });
53907
+ let content = "";
53908
+ try {
53909
+ content = await fs.readFile(configPath, "utf-8");
53910
+ } catch {
53911
+ }
53912
+ const personasRegex = /^features:\s*\n\s*personas:\s*\n\s*enabled:\s*(true|false)/m;
53913
+ const newPersonasBlock = `features:
53914
+ personas:
53915
+ enabled: ${enabled}`;
53916
+ if (personasRegex.test(content)) {
53917
+ content = content.replace(personasRegex, newPersonasBlock);
53918
+ } else {
53919
+ if (content && !content.endsWith("\n")) {
53920
+ content += "\n";
53921
+ }
53922
+ content += newPersonasBlock + "\n";
53923
+ }
53924
+ await fs.writeFile(configPath, content);
53925
+ }
53926
+ function printWizardHeader(stdout) {
53927
+ stdout.write("\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n");
53928
+ stdout.write("\u2502 Sidekick Setup Wizard \u2502\n");
53929
+ stdout.write("\u2502 \u2502\n");
53930
+ stdout.write("\u2502 This wizard configures sidekick for Claude Code. \u2502\n");
53931
+ stdout.write("\u2502 Run 'sidekick setup' again anytime to reconfigure. \u2502\n");
53932
+ stdout.write("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n");
53933
+ }
53934
+ async function runStep1Statusline(wctx) {
53935
+ const { ctx, homeDir, projectDir, logger } = wctx;
53936
+ (0, prompts_js_1.printHeader)(ctx, "Step 1: Statusline Configuration", "Claude Code plugins cannot provide statusline config directly.");
53937
+ const statuslineScope = await (0, prompts_js_1.promptSelect)(ctx, "Where should sidekick configure your statusline?", [
53938
+ { value: "user", label: "User-level (~/.claude/settings.json)", description: "Works in all projects" },
53939
+ { value: "project", label: "Project-level (.claude/settings.local.json)", description: "This project only" }
53940
+ ]);
53941
+ const statuslinePath = statuslineScope === "user" ? path.join(homeDir, ".claude", "settings.json") : path.join(projectDir, ".claude", "settings.local.json");
53942
+ await configureStatusline(statuslinePath, logger);
53943
+ (0, prompts_js_1.printStatus)(ctx, "success", `Statusline configured in ${statuslinePath}`);
53944
+ return statuslineScope;
53945
+ }
53946
+ async function runStep2Gitignore(wctx, force) {
53947
+ const { ctx, projectDir } = wctx;
53948
+ const currentStatus = await (0, core_1.detectGitignoreStatus)(projectDir);
53949
+ if (currentStatus === "installed") {
53950
+ if (!force) {
53951
+ (0, prompts_js_1.printStatus)(ctx, "success", "Sidekick entries already present in .gitignore");
53952
+ }
53953
+ return "installed";
53954
+ }
53955
+ if (force) {
53956
+ const result2 = await (0, core_1.installGitignoreSection)(projectDir);
53957
+ return result2.status === "error" ? "missing" : "installed";
53958
+ }
53959
+ (0, prompts_js_1.printHeader)(ctx, "Step 2: Git Configuration", "Sidekick creates logs and session data that should not be committed.");
53960
+ const shouldInstall = await (0, prompts_js_1.promptConfirm)(ctx, "Update .gitignore to exclude sidekick transient files?", true);
53961
+ if (!shouldInstall) {
53962
+ (0, prompts_js_1.printStatus)(ctx, "info", "Skipping .gitignore configuration (you can manage it manually)");
53963
+ return "missing";
53964
+ }
53965
+ const result = await (0, core_1.installGitignoreSection)(projectDir);
53966
+ if (result.status === "error") {
53967
+ (0, prompts_js_1.printStatus)(ctx, "warning", `Failed to update .gitignore: ${result.error}`);
53968
+ return "missing";
53969
+ }
53970
+ const message = result.status === "already-installed" ? "Sidekick entries already present in .gitignore" : "Added sidekick section to .gitignore";
53971
+ (0, prompts_js_1.printStatus)(ctx, "success", message);
53972
+ return "installed";
53973
+ }
53974
+ async function runStep3Personas(wctx) {
53975
+ const { ctx, homeDir, projectDir } = wctx;
53976
+ const stdout = ctx.stdout;
53977
+ (0, prompts_js_1.printHeader)(ctx, "Step 3: Persona Features", "Sidekick includes AI personas (Marvin, GLaDOS, Skippy, etc.) that add\npersonality to your coding sessions with snarky messages and contextual nudges.");
53978
+ stdout.write("These require an OpenRouter API key (small cost per message).\n\n");
53979
+ const wantPersonas = await (0, prompts_js_1.promptConfirm)(ctx, "Enable persona features?", true);
53980
+ let apiKeyHealth = "not-required";
53981
+ if (!wantPersonas) {
53982
+ await writePersonaConfig(projectDir, homeDir, false);
53983
+ (0, prompts_js_1.printStatus)(ctx, "info", "Personas disabled");
53984
+ } else {
53985
+ await writePersonaConfig(projectDir, homeDir, true);
53986
+ apiKeyHealth = await configureApiKey(wctx);
53987
+ }
53988
+ return { wantPersonas, apiKeyHealth };
53989
+ }
53990
+ async function configureApiKey(wctx) {
53991
+ const { ctx, homeDir, projectDir, logger } = wctx;
53992
+ const stdout = ctx.stdout;
53993
+ const existingKey = await findExistingApiKey("OPENROUTER_API_KEY", homeDir, projectDir);
53994
+ if (existingKey) {
53995
+ (0, prompts_js_1.printStatus)(ctx, "success", "OPENROUTER_API_KEY found");
53996
+ stdout.write("Validating... ");
53997
+ const result2 = await (0, validate_api_key_js_1.validateOpenRouterKey)(existingKey, logger);
53998
+ if (result2.valid) {
53999
+ stdout.write("valid!\n");
54000
+ return "healthy";
54001
+ } else {
54002
+ stdout.write(`invalid (${result2.error})
54003
+ `);
54004
+ return "invalid";
54005
+ }
54006
+ }
54007
+ (0, prompts_js_1.printStatus)(ctx, "warning", "OPENROUTER_API_KEY not found");
54008
+ const configureNow = await (0, prompts_js_1.promptConfirm)(ctx, "Configure API key now?", true);
54009
+ if (!configureNow) {
54010
+ stdout.write("\n");
54011
+ (0, prompts_js_1.printStatus)(ctx, "warning", "Persona features will show warnings in the statusline until an API key is configured.");
54012
+ stdout.write("Run 'sidekick setup' again or ask Claude to help configure API keys using /sidekick-config.\n");
54013
+ return "missing";
54014
+ }
54015
+ const keyScope = await (0, prompts_js_1.promptSelect)(ctx, "Where should the API key be stored?", [
54016
+ { value: "user", label: "User-level (~/.sidekick/.env)", description: "Works in all projects" },
54017
+ { value: "project", label: "Project-level (.sidekick/.env)", description: "This project only" }
54018
+ ]);
54019
+ const apiKey = await (0, prompts_js_1.promptInput)(ctx, "Paste your OpenRouter API key");
54020
+ stdout.write("Validating... ");
54021
+ const result = await (0, validate_api_key_js_1.validateOpenRouterKey)(apiKey, logger);
54022
+ const envPath = keyScope === "user" ? path.join(homeDir, ".sidekick", ".env") : path.join(projectDir, ".sidekick", ".env");
54023
+ if (result.valid) {
54024
+ stdout.write("valid!\n");
54025
+ await writeApiKeyToEnv(envPath, "OPENROUTER_API_KEY", apiKey);
54026
+ (0, prompts_js_1.printStatus)(ctx, "success", `API key saved to ${envPath}`);
54027
+ return "healthy";
54028
+ } else {
54029
+ stdout.write(`invalid (${result.error})
54030
+ `);
54031
+ (0, prompts_js_1.printStatus)(ctx, "warning", "API key validation failed, saving anyway");
54032
+ await writeApiKeyToEnv(envPath, "OPENROUTER_API_KEY", apiKey);
54033
+ return "invalid";
54034
+ }
54035
+ }
54036
+ async function runStep4AutoConfig(wctx) {
54037
+ const { ctx } = wctx;
54038
+ (0, prompts_js_1.printHeader)(ctx, "Step 4: Project Auto-Configuration");
54039
+ const autoConfig = await (0, prompts_js_1.promptSelect)(ctx, "When sidekick runs in a new project for the first time:", [
54040
+ { value: "auto", label: "Auto-configure using my defaults", description: "Recommended" },
54041
+ { value: "ask", label: "Ask me each time" },
54042
+ { value: "manual", label: "Do nothing", description: "Manual setup only" }
54043
+ ]);
54044
+ return autoConfig;
54045
+ }
54046
+ async function writeStatusFiles(wctx, state) {
54047
+ const { setupService } = wctx;
54048
+ const { statuslineScope, gitignoreStatus, wantPersonas, apiKeyHealth, autoConfig } = state;
54049
+ const userStatus = {
54050
+ version: 1,
54051
+ lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
54052
+ preferences: {
54053
+ autoConfigureProjects: autoConfig === "auto",
54054
+ defaultStatuslineScope: statuslineScope,
54055
+ defaultApiKeyScope: wantPersonas ? "user" : "skip"
54056
+ },
54057
+ statusline: "configured",
54058
+ apiKeys: {
54059
+ OPENROUTER_API_KEY: apiKeyHealth,
54060
+ OPENAI_API_KEY: "not-required"
54061
+ }
54062
+ };
54063
+ await setupService.writeUserStatus(userStatus);
54064
+ const projectStatus = {
54065
+ version: 1,
54066
+ lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
54067
+ autoConfigured: false,
54068
+ statusline: statuslineScope === "project" ? "configured" : "user",
54069
+ apiKeys: {
54070
+ OPENROUTER_API_KEY: apiKeyHealth === "healthy" ? "user" : apiKeyHealth,
54071
+ OPENAI_API_KEY: "not-required"
54072
+ },
54073
+ gitignore: gitignoreStatus
54074
+ };
54075
+ await setupService.writeProjectStatus(projectStatus);
54076
+ }
54077
+ function printSummary(wctx, state) {
54078
+ const { ctx } = wctx;
54079
+ const { statuslineScope, gitignoreStatus, wantPersonas, apiKeyHealth, autoConfig } = state;
54080
+ const stdout = ctx.stdout;
54081
+ (0, prompts_js_1.printHeader)(ctx, "Summary");
54082
+ (0, prompts_js_1.printStatus)(ctx, "success", `Statusline: ${statuslineScope === "user" ? "User-level" : "Project-level"}`);
54083
+ (0, prompts_js_1.printStatus)(ctx, gitignoreStatus === "installed" ? "success" : "info", `Gitignore: ${gitignoreStatus === "installed" ? "Configured" : "Skipped"}`);
54084
+ (0, prompts_js_1.printStatus)(ctx, wantPersonas ? "success" : "info", `Personas: ${wantPersonas ? "Enabled" : "Disabled"}`);
54085
+ const apiKeyStatusType = getApiKeyStatusType(apiKeyHealth);
54086
+ (0, prompts_js_1.printStatus)(ctx, apiKeyStatusType, `API Key: ${apiKeyHealth}`);
54087
+ (0, prompts_js_1.printStatus)(ctx, "success", `Auto-configure: ${autoConfig === "auto" ? "Enabled" : "Disabled"}`);
54088
+ stdout.write("\n");
54089
+ stdout.write("Restart Claude Code to see your statusline: claude --continue\n");
54090
+ }
54091
+ async function runWizard(projectDir, logger, stdout, options) {
54092
+ const homeDir = os.homedir();
54093
+ const wctx = {
54094
+ ctx: {
54095
+ stdin: options.stdin ?? process.stdin,
54096
+ stdout
54097
+ },
54098
+ homeDir,
54099
+ projectDir,
54100
+ logger,
54101
+ setupService: new core_1.SetupStatusService(projectDir, { homeDir, logger })
54102
+ };
54103
+ const force = options.force ?? false;
54104
+ if (!force) {
54105
+ printWizardHeader(stdout);
54106
+ }
54107
+ const statuslineScope = force ? "user" : await runStep1Statusline(wctx);
54108
+ const gitignoreStatus = await runStep2Gitignore(wctx, force);
54109
+ const { wantPersonas, apiKeyHealth } = force ? { wantPersonas: true, apiKeyHealth: "not-required" } : await runStep3Personas(wctx);
54110
+ const autoConfig = force ? "auto" : await runStep4AutoConfig(wctx);
54111
+ if (force) {
54112
+ const statuslinePath = path.join(homeDir, ".claude", "settings.json");
54113
+ await configureStatusline(statuslinePath, logger);
54114
+ }
54115
+ const state = { statuslineScope, gitignoreStatus, wantPersonas, apiKeyHealth, autoConfig };
54116
+ await writeStatusFiles(wctx, state);
54117
+ if (!force) {
54118
+ printSummary(wctx, state);
54119
+ } else {
54120
+ stdout.write("Setup complete (force mode):\n");
54121
+ stdout.write(` Statusline: user-level (~/.claude/settings.json)
54122
+ `);
54123
+ stdout.write(` Gitignore: ${gitignoreStatus === "installed" ? "configured" : "skipped"}
54124
+ `);
54125
+ stdout.write(` Personas: enabled (API key not configured)
54126
+ `);
54127
+ stdout.write(` Auto-configure: enabled
54128
+ `);
54129
+ }
54130
+ return { exitCode: 0 };
54131
+ }
54132
+ async function runDoctor(projectDir, logger, stdout) {
54133
+ const homeDir = os.homedir();
54134
+ const setupService = new core_1.SetupStatusService(projectDir, { homeDir, logger });
54135
+ stdout.write("\nSidekick Doctor\n");
54136
+ stdout.write("===============\n\n");
54137
+ const statusline = await setupService.getStatuslineHealth();
54138
+ const gitignore = await (0, core_1.detectGitignoreStatus)(projectDir);
54139
+ const apiKey = await setupService.getEffectiveApiKeyHealth("OPENROUTER_API_KEY");
54140
+ const isHealthy = await setupService.isHealthy();
54141
+ const statuslineIcon = statusline === "configured" ? "\u2713" : "\u26A0";
54142
+ const gitignoreIcon = gitignore === "installed" ? "\u2713" : "\u26A0";
54143
+ const apiKeyIcon = apiKey === "healthy" || apiKey === "not-required" ? "\u2713" : "\u26A0";
54144
+ const overallIcon = isHealthy && gitignore === "installed" ? "\u2713" : "\u26A0";
54145
+ stdout.write(`${statuslineIcon} Statusline: ${statusline}
54146
+ `);
54147
+ stdout.write(`${gitignoreIcon} Gitignore: ${gitignore}
54148
+ `);
54149
+ stdout.write(`${apiKeyIcon} OpenRouter API Key: ${apiKey}
54150
+ `);
54151
+ stdout.write(`${overallIcon} Overall: ${isHealthy && gitignore === "installed" ? "healthy" : "needs attention"}
54152
+ `);
54153
+ if (!isHealthy || gitignore !== "installed") {
54154
+ stdout.write("\nRun 'sidekick setup' to configure.\n");
54155
+ }
54156
+ return { exitCode: isHealthy && gitignore === "installed" ? 0 : 1 };
54157
+ }
54158
+ async function handleSetupCommand(projectDir, logger, stdout, options = {}) {
54159
+ if (options.checkOnly) {
54160
+ return runDoctor(projectDir, logger, stdout);
54161
+ }
54162
+ return runWizard(projectDir, logger, stdout, options);
54163
+ }
54164
+ }
54165
+ });
54166
+
54167
+ // ../sidekick-cli/dist/commands/setup.js
54168
+ var require_setup2 = __commonJS({
54169
+ "../sidekick-cli/dist/commands/setup.js"(exports2) {
54170
+ "use strict";
54171
+ Object.defineProperty(exports2, "__esModule", { value: true });
54172
+ exports2.handleSetupCommand = void 0;
54173
+ var index_js_1 = require_setup();
54174
+ Object.defineProperty(exports2, "handleSetupCommand", { enumerable: true, get: function() {
54175
+ return index_js_1.handleSetupCommand;
54176
+ } });
54177
+ }
54178
+ });
54179
+
53008
54180
  // ../sidekick-cli/dist/cli.js
53009
54181
  var require_cli = __commonJS({
53010
54182
  "../sidekick-cli/dist/cli.js"(exports2) {
@@ -53059,6 +54231,7 @@ var require_cli = __commonJS({
53059
54231
  var promises_12 = require("node:fs/promises");
53060
54232
  var node_stream_1 = require("node:stream");
53061
54233
  var yargs_parser_1 = __importDefault2(require_build());
54234
+ var VERSION = true ? "0.0.5-alpha" : "dev";
53062
54235
  function isInSandbox() {
53063
54236
  return process.env.SANDBOX_RUNTIME === "1";
53064
54237
  }
@@ -53073,11 +54246,12 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
53073
54246
  var runtime_1 = require_runtime();
53074
54247
  function parseArgs(argv) {
53075
54248
  const parsed = (0, yargs_parser_1.default)(argv, {
53076
- boolean: ["wait", "open", "prefer-project", "help", "kill", "force"],
54249
+ boolean: ["wait", "open", "prefer-project", "help", "version", "kill", "force"],
53077
54250
  string: ["project-dir", "log-level", "format", "host", "session-id", "type"],
53078
54251
  number: ["port", "width"],
53079
54252
  alias: {
53080
- h: "help"
54253
+ h: "help",
54254
+ v: "version"
53081
54255
  },
53082
54256
  configuration: {
53083
54257
  "camel-case-expansion": false
@@ -53098,6 +54272,7 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
53098
54272
  sessionIdArg: parsed["session-id"],
53099
54273
  messageType: parsed.type,
53100
54274
  help: Boolean(parsed.help),
54275
+ version: Boolean(parsed.version),
53101
54276
  kill: Boolean(parsed.kill),
53102
54277
  force: Boolean(parsed.force),
53103
54278
  _: parsed._
@@ -53174,6 +54349,19 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
53174
54349
  if (!hookMode || !projectRoot) {
53175
54350
  return { started: false };
53176
54351
  }
54352
+ try {
54353
+ const { SetupStatusService } = await Promise.resolve().then(() => __importStar(require_dist3()));
54354
+ const setupService = new SetupStatusService(projectRoot);
54355
+ const setupState = await setupService.getSetupState();
54356
+ if (setupState !== "healthy") {
54357
+ logger.debug("Skipping daemon start - setup not healthy", { setupState });
54358
+ return { started: false };
54359
+ }
54360
+ } catch (err) {
54361
+ logger.warn("Failed to check setup status, proceeding with daemon start", {
54362
+ error: err instanceof Error ? err.message : String(err)
54363
+ });
54364
+ }
53177
54365
  try {
53178
54366
  const { DaemonClient } = await Promise.resolve().then(() => __importStar(require_dist3()));
53179
54367
  const daemonClient = new DaemonClient(projectRoot, logger);
@@ -53198,9 +54386,12 @@ Commands:
53198
54386
  statusline Render the status line (used by hooks)
53199
54387
  dev-mode <subcommand> Manage development hooks (enable, disable, status, clean)
53200
54388
  ui Launch the web UI
54389
+ setup Run the setup wizard (configure statusline, API keys)
54390
+ doctor Check sidekick health (alias: setup --check)
53201
54391
 
53202
54392
  Global Options:
53203
54393
  --help, -h Show this help message
54394
+ --version, -v Show version number
53204
54395
  --format=<format> Output format: json or table (command-specific)
53205
54396
  --width=<n> Table width in characters (default: 100)
53206
54397
  --project-dir=<path> Override project directory
@@ -53284,7 +54475,9 @@ Run 'sidekick hook --help' for available hooks.
53284
54475
  return { exitCode: 1, stdout: SANDBOX_ERROR_MESSAGE, stderr: "" };
53285
54476
  }
53286
54477
  const { handleDaemonCommand } = await Promise.resolve().then(() => __importStar(require_daemon()));
53287
- const result = await handleDaemonCommand(subcommand, runtime.projectRoot || process.cwd(), runtime.logger, stdout, { wait: parsed.wait });
54478
+ const result = await handleDaemonCommand(subcommand, runtime.projectRoot || process.cwd(), runtime.logger, stdout, {
54479
+ wait: parsed.wait
54480
+ });
53288
54481
  return { exitCode: result.exitCode, stdout: "", stderr: "" };
53289
54482
  }
53290
54483
  if (parsed.command === "statusline") {
@@ -53339,6 +54532,21 @@ Run 'sidekick hook --help' for available hooks.
53339
54532
  const result = await handleDevModeCommand(subcommand, runtime.projectRoot || process.cwd(), runtime.logger, stdout, { force: Boolean(parsed.force) });
53340
54533
  return { exitCode: result.exitCode, stdout: "", stderr: "" };
53341
54534
  }
54535
+ if (parsed.command === "setup") {
54536
+ const { handleSetupCommand } = await Promise.resolve().then(() => __importStar(require_setup2()));
54537
+ const result = await handleSetupCommand(runtime.projectRoot || process.cwd(), runtime.logger, stdout, {
54538
+ checkOnly: parsed.help ? false : parsed._?.[1] === "--check",
54539
+ stdin: process.stdin
54540
+ });
54541
+ return { exitCode: result.exitCode, stdout: "", stderr: "" };
54542
+ }
54543
+ if (parsed.command === "doctor") {
54544
+ const { handleSetupCommand } = await Promise.resolve().then(() => __importStar(require_setup2()));
54545
+ const result = await handleSetupCommand(runtime.projectRoot || process.cwd(), runtime.logger, stdout, {
54546
+ checkOnly: true
54547
+ });
54548
+ return { exitCode: result.exitCode, stdout: "", stderr: "" };
54549
+ }
53342
54550
  const errorMsg = `Unknown command: ${parsed.command}
53343
54551
  Run 'sidekick help' for available commands.
53344
54552
  `;
@@ -53365,6 +54573,16 @@ Run 'sidekick help' for available commands.
53365
54573
  }
53366
54574
  async function runCli(options) {
53367
54575
  const stdout = options.stdout ?? new node_stream_1.PassThrough();
54576
+ const quickParsed = (0, yargs_parser_1.default)(options.argv, {
54577
+ boolean: ["version"],
54578
+ alias: { v: "version" }
54579
+ });
54580
+ if (quickParsed.version) {
54581
+ const versionOutput = `${VERSION}
54582
+ `;
54583
+ stdout.write(versionOutput);
54584
+ return { exitCode: 0, stdout: versionOutput, stderr: "" };
54585
+ }
53368
54586
  const initResult = initializeRuntime(options);
53369
54587
  if (initResult.shouldExit) {
53370
54588
  return { exitCode: 0, stdout: "", stderr: "" };