@scotthamilton77/sidekick 0.0.8-alpha.3 → 0.0.8-alpha.5

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 +496 -13
  2. package/dist/daemon.js +12 -4
  3. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -51667,6 +51667,7 @@ var require_setup_status_service = __commonJS({
51667
51667
  }
51668
51668
  };
51669
51669
  const child = (0, node_child_process_1.spawn)("claude", ["plugin", "list", "--json"], {
51670
+ cwd: this.projectDir,
51670
51671
  stdio: ["ignore", "pipe", "pipe"]
51671
51672
  });
51672
51673
  let stdout = "";
@@ -51875,6 +51876,7 @@ var require_setup_status_service = __commonJS({
51875
51876
  this.logger?.info("Auto-configuring project with user defaults", {
51876
51877
  projectDir: this.projectDir
51877
51878
  });
51879
+ const existing = await this.getProjectStatus();
51878
51880
  const projectStatus = {
51879
51881
  version: 1,
51880
51882
  lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -51884,7 +51886,8 @@ var require_setup_status_service = __commonJS({
51884
51886
  OPENROUTER_API_KEY: "user",
51885
51887
  OPENAI_API_KEY: "user"
51886
51888
  },
51887
- gitignore: "unknown"
51889
+ gitignore: "unknown",
51890
+ ...existing?.devMode !== void 0 && { devMode: existing.devMode }
51888
51891
  };
51889
51892
  await this.writeProjectStatus(projectStatus);
51890
51893
  this.logger?.info("Project auto-configured successfully", {
@@ -51928,6 +51931,7 @@ var require_setup_status_service = __commonJS({
51928
51931
  if (projectStatus) {
51929
51932
  await this.updateProjectStatus({ statusline: actualStatusline });
51930
51933
  } else {
51934
+ const existingForDevMode = await this.getProjectStatus();
51931
51935
  await this.writeProjectStatus({
51932
51936
  version: 1,
51933
51937
  lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -51937,7 +51941,8 @@ var require_setup_status_service = __commonJS({
51937
51941
  OPENROUTER_API_KEY: "user",
51938
51942
  OPENAI_API_KEY: "user"
51939
51943
  },
51940
- gitignore: "unknown"
51944
+ gitignore: "unknown",
51945
+ ...existingForDevMode?.devMode !== void 0 && { devMode: existingForDevMode.devMode }
51941
51946
  });
51942
51947
  }
51943
51948
  } else {
@@ -51987,6 +51992,7 @@ var require_setup_status_service = __commonJS({
51987
51992
  });
51988
51993
  } else {
51989
51994
  const userApiKeyStatus = this.buildUserApiKeyStatus(detection);
51995
+ const existingForDevMode = await this.getProjectStatus();
51990
51996
  await this.writeProjectStatus({
51991
51997
  version: 1,
51992
51998
  lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -51996,7 +52002,8 @@ var require_setup_status_service = __commonJS({
51996
52002
  OPENROUTER_API_KEY: keyName === "OPENROUTER_API_KEY" ? projectApiKeyStatus : "user",
51997
52003
  OPENAI_API_KEY: keyName === "OPENAI_API_KEY" ? projectApiKeyStatus : "user"
51998
52004
  },
51999
- gitignore: "unknown"
52005
+ gitignore: "unknown",
52006
+ ...existingForDevMode?.devMode !== void 0 && { devMode: existingForDevMode.devMode }
52000
52007
  });
52001
52008
  const userStatus = await this.getUserStatus();
52002
52009
  if (!userStatus) {
@@ -52086,7 +52093,8 @@ var require_setup_status_service = __commonJS({
52086
52093
  }
52087
52094
  };
52088
52095
  const child = (0, node_child_process_1.spawn)("claude", ["-p", prompt], {
52089
- env: { ...process.env, SIDEKICK_SAFE_WORD: safeWord },
52096
+ cwd: this.projectDir,
52097
+ env: { ...process.env, SIDEKICK_LIVENESS_CHECK: safeWord },
52090
52098
  stdio: ["ignore", "pipe", "pipe"]
52091
52099
  });
52092
52100
  let stdout = "";
@@ -68288,9 +68296,23 @@ var require_hook_command = __commonJS({
68288
68296
  }
68289
68297
  }
68290
68298
  async function handleUnifiedHookCommand(hookName, options, logger, stdout) {
68291
- const { projectRoot, hookInput, correlationId, runtime, force } = options;
68299
+ const { projectRoot, hookInput, correlationId, runtime, forceDevMode } = options;
68292
68300
  logger.debug("Unified hook command invoked", { hookName, sessionId: hookInput.sessionId });
68293
- if (!force) {
68301
+ if (forceDevMode) {
68302
+ try {
68303
+ const setupService = new core_1.SetupStatusService(projectRoot);
68304
+ const devMode = await setupService.getDevMode();
68305
+ if (!devMode) {
68306
+ logger.warn("Dev-mode hooks running but devMode flag is off \u2014 auto-correcting", { hookName });
68307
+ await setupService.setDevMode(true);
68308
+ }
68309
+ } catch (err) {
68310
+ logger.warn("Failed to auto-correct devMode flag", {
68311
+ error: err instanceof Error ? err.message : String(err),
68312
+ hookName
68313
+ });
68314
+ }
68315
+ } else {
68294
68316
  try {
68295
68317
  const setupService = new core_1.SetupStatusService(projectRoot);
68296
68318
  const devMode = await setupService.getDevMode();
@@ -68313,7 +68335,8 @@ var require_hook_command = __commonJS({
68313
68335
  await maybeAutoConfigureProject(projectRoot, logger);
68314
68336
  }
68315
68337
  await ensureDaemonForHook(projectRoot, logger);
68316
- const degradedResponse = await checkSetupState(projectRoot, hookName, logger);
68338
+ const isLivenessCheck = !!process.env.SIDEKICK_LIVENESS_CHECK;
68339
+ const degradedResponse = isLivenessCheck ? null : await checkSetupState(projectRoot, hookName, logger);
68317
68340
  if (degradedResponse !== null) {
68318
68341
  const claudeResponse2 = translateToClaudeCodeFormat(hookName, degradedResponse);
68319
68342
  const outputStr2 = JSON.stringify(claudeResponse2);
@@ -68338,7 +68361,7 @@ var require_hook_command = __commonJS({
68338
68361
  }, logger, captureStream);
68339
68362
  const internalResponse = parseInternalResponse(internalOutput.trim(), hookName, logger);
68340
68363
  if (hookName === "SessionStart") {
68341
- const safeWord = process.env.SIDEKICK_SAFE_WORD ?? "nope";
68364
+ const safeWord = process.env.SIDEKICK_LIVENESS_CHECK ?? "nope";
68342
68365
  const safeWordContext = loadSafeWordContext(safeWord, projectRoot, logger);
68343
68366
  if (safeWordContext) {
68344
68367
  internalResponse.additionalContext = internalResponse.additionalContext ? `${internalResponse.additionalContext}
@@ -71155,7 +71178,20 @@ Examples:
71155
71178
  stdout.write(USAGE_TEXT);
71156
71179
  return { exitCode: 0 };
71157
71180
  }
71158
- if (!options.force) {
71181
+ if (options.forceDevMode) {
71182
+ try {
71183
+ const setupService = new core_1.SetupStatusService(projectDir);
71184
+ const devMode = await setupService.getDevMode();
71185
+ if (!devMode) {
71186
+ logger.warn("Dev-mode statusline running but devMode flag is off \u2014 auto-correcting");
71187
+ await setupService.setDevMode(true);
71188
+ }
71189
+ } catch (err) {
71190
+ logger.warn("Failed to auto-correct devMode flag in statusline", {
71191
+ error: err instanceof Error ? err.message : String(err)
71192
+ });
71193
+ }
71194
+ } else {
71159
71195
  try {
71160
71196
  const setupService = new core_1.SetupStatusService(projectDir);
71161
71197
  const devMode = await setupService.getDevMode();
@@ -73245,6 +73281,22 @@ Examples:
73245
73281
  `);
73246
73282
  configuredCount++;
73247
73283
  }
73284
+ if (configuredCount > 0) {
73285
+ const existingProject = await setupService.getProjectStatus();
73286
+ const projectStatus = {
73287
+ version: 1,
73288
+ lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
73289
+ autoConfigured: false,
73290
+ statusline: options.statuslineScope ?? existingProject?.statusline ?? "none",
73291
+ apiKeys: existingProject?.apiKeys ?? {
73292
+ OPENROUTER_API_KEY: core_1.SetupStatusService.projectApiKeyStatusFromHealth("not-required"),
73293
+ OPENAI_API_KEY: core_1.SetupStatusService.projectApiKeyStatusFromHealth("not-required")
73294
+ },
73295
+ gitignore: options.gitignore ? "installed" : existingProject?.gitignore ?? "unknown",
73296
+ ...existingProject?.devMode !== void 0 && { devMode: existingProject.devMode }
73297
+ };
73298
+ await setupService.writeProjectStatus(projectStatus);
73299
+ }
73248
73300
  if (configuredCount === 0) {
73249
73301
  stdout.write("No configuration changes made. Use --help to see available options.\n");
73250
73302
  } else {
@@ -73342,6 +73394,413 @@ var require_setup2 = __commonJS({
73342
73394
  }
73343
73395
  });
73344
73396
 
73397
+ // ../sidekick-cli/dist/commands/uninstall.js
73398
+ var require_uninstall = __commonJS({
73399
+ "../sidekick-cli/dist/commands/uninstall.js"(exports2) {
73400
+ "use strict";
73401
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
73402
+ if (k2 === void 0) k2 = k;
73403
+ var desc = Object.getOwnPropertyDescriptor(m, k);
73404
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
73405
+ desc = { enumerable: true, get: function() {
73406
+ return m[k];
73407
+ } };
73408
+ }
73409
+ Object.defineProperty(o, k2, desc);
73410
+ }) : (function(o, m, k, k2) {
73411
+ if (k2 === void 0) k2 = k;
73412
+ o[k2] = m[k];
73413
+ }));
73414
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {
73415
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
73416
+ }) : function(o, v) {
73417
+ o["default"] = v;
73418
+ });
73419
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ (function() {
73420
+ var ownKeys = function(o) {
73421
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
73422
+ var ar = [];
73423
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
73424
+ return ar;
73425
+ };
73426
+ return ownKeys(o);
73427
+ };
73428
+ return function(mod) {
73429
+ if (mod && mod.__esModule) return mod;
73430
+ var result = {};
73431
+ if (mod != null) {
73432
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
73433
+ }
73434
+ __setModuleDefault(result, mod);
73435
+ return result;
73436
+ };
73437
+ })();
73438
+ Object.defineProperty(exports2, "__esModule", { value: true });
73439
+ exports2.handleUninstallCommand = handleUninstallCommand;
73440
+ var fs = __importStar(require("node:fs/promises"));
73441
+ var path = __importStar(require("node:path"));
73442
+ var node_child_process_1 = require("node:child_process");
73443
+ var core_1 = require_dist4();
73444
+ async function handleUninstallCommand(projectDir, logger, stdout, options = {}) {
73445
+ const { force = false, dryRun = false, scope, userHome = process.env.HOME || "", stdin = process.stdin } = options;
73446
+ const actions = [];
73447
+ const projectDetected = scope !== "user" && await detectProjectScope(projectDir);
73448
+ const userDetected = scope !== "project" && await detectUserScope(userHome);
73449
+ if (!projectDetected && !userDetected) {
73450
+ stdout.write("No sidekick installation detected.\n");
73451
+ return { exitCode: 0, output: "" };
73452
+ }
73453
+ if (userDetected || projectDetected) {
73454
+ await uninstallPlugin(logger, stdout, actions, { force, dryRun });
73455
+ }
73456
+ if (projectDetected) {
73457
+ await killDaemon(projectDir, logger, stdout, actions, { dryRun });
73458
+ }
73459
+ if (projectDetected) {
73460
+ await cleanSettingsFile(path.join(projectDir, ".claude", "settings.local.json"), "project", logger, actions, {
73461
+ dryRun,
73462
+ removeHooks: true
73463
+ });
73464
+ }
73465
+ if (userDetected) {
73466
+ await cleanSettingsFile(path.join(userHome, ".claude", "settings.json"), "user", logger, actions, {
73467
+ dryRun,
73468
+ removeHooks: false
73469
+ });
73470
+ }
73471
+ if (projectDetected) {
73472
+ await removeFile(path.join(projectDir, ".sidekick", "setup-status.json"), "project", "setup-status.json", actions, {
73473
+ dryRun
73474
+ });
73475
+ }
73476
+ if (userDetected) {
73477
+ await removeFile(path.join(userHome, ".sidekick", "setup-status.json"), "user", "setup-status.json", actions, {
73478
+ dryRun
73479
+ });
73480
+ await removeFile(path.join(userHome, ".sidekick", "features.yaml"), "user", "features.yaml", actions, { dryRun });
73481
+ }
73482
+ if (projectDetected) {
73483
+ await handleEnvFile(path.join(projectDir, ".sidekick", ".env"), "project", stdout, actions, {
73484
+ force,
73485
+ dryRun,
73486
+ stdin
73487
+ });
73488
+ }
73489
+ if (userDetected) {
73490
+ await handleEnvFile(path.join(userHome, ".sidekick", ".env"), "user", stdout, actions, { force, dryRun, stdin });
73491
+ }
73492
+ if (projectDetected) {
73493
+ await removeDir(path.join(projectDir, ".sidekick", "logs"), "project", "logs/", actions, { dryRun });
73494
+ await removeDir(path.join(projectDir, ".sidekick", "sessions"), "project", "sessions/", actions, { dryRun });
73495
+ await removeDir(path.join(projectDir, ".sidekick", "state"), "project", "state/", actions, { dryRun });
73496
+ await removeFile(path.join(projectDir, ".sidekick", "sidekickd.pid"), "project", "sidekickd.pid", actions, {
73497
+ dryRun
73498
+ });
73499
+ await removeFile(path.join(projectDir, ".sidekick", "sidekickd.token"), "project", "sidekickd.token", actions, {
73500
+ dryRun
73501
+ });
73502
+ await removeFile(path.join(projectDir, ".sidekick", "sidekickd.lock"), "project", "sidekickd.lock", actions, {
73503
+ dryRun
73504
+ });
73505
+ }
73506
+ if (userDetected) {
73507
+ await removeDir(path.join(userHome, ".sidekick", "state"), "user", "state/", actions, { dryRun });
73508
+ await removeDir(path.join(userHome, ".sidekick", "daemons"), "user", "daemons/", actions, { dryRun });
73509
+ }
73510
+ if (projectDetected) {
73511
+ if (dryRun) {
73512
+ actions.push({
73513
+ scope: "project",
73514
+ artifact: ".gitignore section",
73515
+ path: path.join(projectDir, ".gitignore"),
73516
+ action: "would-remove"
73517
+ });
73518
+ } else {
73519
+ const removed = await (0, core_1.removeGitignoreSection)(projectDir);
73520
+ actions.push({
73521
+ scope: "project",
73522
+ artifact: ".gitignore section",
73523
+ path: path.join(projectDir, ".gitignore"),
73524
+ action: removed ? "removed" : "not-found"
73525
+ });
73526
+ }
73527
+ }
73528
+ printReport(stdout, actions, dryRun);
73529
+ return { exitCode: 0, output: "" };
73530
+ }
73531
+ async function detectProjectScope(projectDir) {
73532
+ try {
73533
+ await fs.access(path.join(projectDir, ".sidekick", "setup-status.json"));
73534
+ return true;
73535
+ } catch {
73536
+ try {
73537
+ const content = await fs.readFile(path.join(projectDir, ".claude", "settings.local.json"), "utf-8");
73538
+ return content.includes("sidekick");
73539
+ } catch {
73540
+ return false;
73541
+ }
73542
+ }
73543
+ }
73544
+ async function detectUserScope(userHome) {
73545
+ try {
73546
+ await fs.access(path.join(userHome, ".sidekick", "setup-status.json"));
73547
+ return true;
73548
+ } catch {
73549
+ try {
73550
+ const content = await fs.readFile(path.join(userHome, ".claude", "settings.json"), "utf-8");
73551
+ return content.includes("sidekick");
73552
+ } catch {
73553
+ return false;
73554
+ }
73555
+ }
73556
+ }
73557
+ async function uninstallPlugin(logger, stdout, actions, options) {
73558
+ try {
73559
+ const plugins = await execFileAsync("claude", ["plugin", "list", "--json"]);
73560
+ const pluginList = JSON.parse(plugins);
73561
+ const sidekickPlugin = pluginList.find((p) => p.id.startsWith("sidekick@"));
73562
+ if (!sidekickPlugin) {
73563
+ logger.debug("No sidekick plugin found in claude plugin list");
73564
+ return;
73565
+ }
73566
+ if (options.dryRun) {
73567
+ actions.push({
73568
+ scope: sidekickPlugin.scope,
73569
+ artifact: `Plugin (${sidekickPlugin.id})`,
73570
+ path: "claude plugin",
73571
+ action: "would-remove"
73572
+ });
73573
+ return;
73574
+ }
73575
+ logger.info("Uninstalling sidekick plugin", { id: sidekickPlugin.id, scope: sidekickPlugin.scope });
73576
+ await execFileAsync("claude", ["plugin", "uninstall", "sidekick", "--scope", sidekickPlugin.scope]);
73577
+ actions.push({
73578
+ scope: sidekickPlugin.scope,
73579
+ artifact: `Plugin (${sidekickPlugin.id})`,
73580
+ path: "claude plugin",
73581
+ action: "removed"
73582
+ });
73583
+ stdout.write(`Plugin ${sidekickPlugin.id} uninstalled.
73584
+ `);
73585
+ } catch (err) {
73586
+ logger.warn("Could not detect/uninstall claude plugin (claude CLI may not be available)", {
73587
+ error: err.message
73588
+ });
73589
+ }
73590
+ }
73591
+ function execFileAsync(cmd, args) {
73592
+ return new Promise((resolve3, reject) => {
73593
+ (0, node_child_process_1.execFile)(cmd, args, (error, stdout) => {
73594
+ if (error)
73595
+ reject(error);
73596
+ else
73597
+ resolve3(stdout);
73598
+ });
73599
+ });
73600
+ }
73601
+ async function killDaemon(projectDir, logger, _stdout, actions, options) {
73602
+ if (options.dryRun) {
73603
+ actions.push({ scope: "project", artifact: "Daemon process", path: projectDir, action: "would-remove" });
73604
+ return;
73605
+ }
73606
+ try {
73607
+ const client = new core_1.DaemonClient(projectDir, logger);
73608
+ const result = await client.kill();
73609
+ logger.info("Daemon kill result", { result });
73610
+ } catch (err) {
73611
+ logger.debug("Daemon kill failed (may not be running)", { error: err.message });
73612
+ }
73613
+ }
73614
+ async function cleanSettingsFile(settingsPath, scope, logger, actions, options) {
73615
+ let content;
73616
+ try {
73617
+ content = await fs.readFile(settingsPath, "utf-8");
73618
+ } catch {
73619
+ return;
73620
+ }
73621
+ let settings;
73622
+ try {
73623
+ settings = JSON.parse(content);
73624
+ } catch {
73625
+ logger.warn("Could not parse settings file", { path: settingsPath });
73626
+ return;
73627
+ }
73628
+ let modified = false;
73629
+ const statusLine = settings.statusLine;
73630
+ if (statusLine?.command?.includes("sidekick")) {
73631
+ if (options.dryRun) {
73632
+ actions.push({ scope, artifact: "statusLine", path: settingsPath, action: "would-remove" });
73633
+ } else {
73634
+ delete settings.statusLine;
73635
+ modified = true;
73636
+ actions.push({ scope, artifact: "statusLine", path: settingsPath, action: "removed" });
73637
+ }
73638
+ }
73639
+ if (options.removeHooks && settings.hooks) {
73640
+ const hooks = settings.hooks;
73641
+ let hooksModified = false;
73642
+ for (const [eventName, eventHandlers] of Object.entries(hooks)) {
73643
+ if (!Array.isArray(eventHandlers))
73644
+ continue;
73645
+ const filtered = eventHandlers.filter((handler) => {
73646
+ const h = handler;
73647
+ if (!h.hooks?.length)
73648
+ return true;
73649
+ return h.hooks.some((hook) => !hook.command?.includes("sidekick") && !hook.command?.includes("dev-sidekick"));
73650
+ });
73651
+ if (filtered.length !== eventHandlers.length) {
73652
+ if (options.dryRun) {
73653
+ actions.push({ scope, artifact: `hooks.${eventName}`, path: settingsPath, action: "would-remove" });
73654
+ } else {
73655
+ if (filtered.length === 0) {
73656
+ delete hooks[eventName];
73657
+ } else {
73658
+ hooks[eventName] = filtered;
73659
+ }
73660
+ hooksModified = true;
73661
+ }
73662
+ }
73663
+ }
73664
+ if (hooksModified) {
73665
+ if (Object.keys(hooks).length === 0) {
73666
+ delete settings.hooks;
73667
+ }
73668
+ modified = true;
73669
+ actions.push({ scope, artifact: "hooks", path: settingsPath, action: "removed" });
73670
+ }
73671
+ }
73672
+ if (modified && !options.dryRun) {
73673
+ if (Object.keys(settings).length === 0) {
73674
+ await fs.unlink(settingsPath);
73675
+ logger.info("Deleted empty settings file", { path: settingsPath });
73676
+ } else {
73677
+ await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2) + "\n");
73678
+ logger.info("Updated settings file", { path: settingsPath });
73679
+ }
73680
+ }
73681
+ }
73682
+ async function removeFile(filePath, scope, artifact, actions, options) {
73683
+ try {
73684
+ await fs.access(filePath);
73685
+ } catch {
73686
+ return;
73687
+ }
73688
+ if (options.dryRun) {
73689
+ actions.push({ scope, artifact, path: filePath, action: "would-remove" });
73690
+ return;
73691
+ }
73692
+ try {
73693
+ await fs.unlink(filePath);
73694
+ actions.push({ scope, artifact, path: filePath, action: "removed" });
73695
+ } catch {
73696
+ actions.push({ scope, artifact, path: filePath, action: "skipped" });
73697
+ }
73698
+ }
73699
+ async function removeDir(dirPath, scope, artifact, actions, options) {
73700
+ try {
73701
+ await fs.access(dirPath);
73702
+ } catch {
73703
+ return;
73704
+ }
73705
+ if (options.dryRun) {
73706
+ actions.push({ scope, artifact, path: dirPath, action: "would-remove" });
73707
+ return;
73708
+ }
73709
+ try {
73710
+ await fs.rm(dirPath, { recursive: true, force: true });
73711
+ actions.push({ scope, artifact, path: dirPath, action: "removed" });
73712
+ } catch {
73713
+ actions.push({ scope, artifact, path: dirPath, action: "skipped" });
73714
+ }
73715
+ }
73716
+ async function handleEnvFile(envPath, scope, stdout, actions, options) {
73717
+ let content;
73718
+ try {
73719
+ content = await fs.readFile(envPath, "utf-8");
73720
+ } catch {
73721
+ return;
73722
+ }
73723
+ if (options.dryRun) {
73724
+ actions.push({ scope, artifact: ".env", path: envPath, action: "would-remove" });
73725
+ return;
73726
+ }
73727
+ const keyNames = content.split("\n").filter((line) => line.includes("=") && !line.startsWith("#")).map((line) => {
73728
+ const [key, val] = line.split("=", 2);
73729
+ const masked = val ? val.slice(0, 4) + "****" : "****";
73730
+ return ` ${key}=${masked}`;
73731
+ });
73732
+ if (keyNames.length > 0 && !options.force) {
73733
+ stdout.write(`
73734
+ ${scope} scope .env contains API keys:
73735
+ `);
73736
+ stdout.write(keyNames.join("\n") + "\n");
73737
+ const answer = await promptYesNo(`Remove ${scope} .env file?`, stdout, options.stdin);
73738
+ if (!answer) {
73739
+ actions.push({ scope, artifact: ".env", path: envPath, action: "kept" });
73740
+ return;
73741
+ }
73742
+ }
73743
+ await fs.unlink(envPath);
73744
+ actions.push({ scope, artifact: ".env", path: envPath, action: "removed" });
73745
+ }
73746
+ function promptYesNo(question, stdout, stdin) {
73747
+ return new Promise((resolve3) => {
73748
+ stdout.write(`${question} [y/N] `);
73749
+ let data = "";
73750
+ const onData = (chunk) => {
73751
+ data += chunk.toString();
73752
+ if (data.includes("\n")) {
73753
+ stdin.removeListener("data", onData);
73754
+ const answer = data.trim().toLowerCase();
73755
+ resolve3(answer === "y" || answer === "yes");
73756
+ }
73757
+ };
73758
+ stdin.on("data", onData);
73759
+ });
73760
+ }
73761
+ function printReport(stdout, actions, dryRun) {
73762
+ if (actions.length === 0)
73763
+ return;
73764
+ const sortByArtifact = (a, b) => a.artifact.localeCompare(b.artifact);
73765
+ if (dryRun) {
73766
+ stdout.write("\n[dry-run] Would perform the following actions:\n");
73767
+ printScopeGrouped(stdout, actions, (a) => a.artifact, sortByArtifact);
73768
+ return;
73769
+ }
73770
+ const removed = actions.filter((a) => a.action === "removed");
73771
+ const kept = actions.filter((a) => a.action === "kept");
73772
+ const skipped = actions.filter((a) => a.action === "skipped");
73773
+ if (removed.length > 0) {
73774
+ stdout.write("\nRemoved:\n");
73775
+ printScopeGrouped(stdout, removed, (a) => a.artifact, sortByArtifact);
73776
+ }
73777
+ if (kept.length > 0) {
73778
+ stdout.write("\nKept (by request):\n");
73779
+ printScopeGrouped(stdout, kept, (a) => a.artifact, sortByArtifact);
73780
+ }
73781
+ if (skipped.length > 0) {
73782
+ stdout.write("\nSkipped (errors):\n");
73783
+ printScopeGrouped(stdout, skipped, (a) => a.artifact, sortByArtifact);
73784
+ }
73785
+ stdout.write("\nSidekick uninstalled. Restart Claude Code to apply changes.\n");
73786
+ }
73787
+ function printScopeGrouped(stdout, actions, label, sort) {
73788
+ const scopes = ["user", "project"];
73789
+ for (const scope of scopes) {
73790
+ const group = actions.filter((a) => a.scope === scope).sort(sort);
73791
+ if (group.length === 0)
73792
+ continue;
73793
+ stdout.write(` ${scope}:
73794
+ `);
73795
+ for (const action of group) {
73796
+ stdout.write(` ${label(action)}
73797
+ `);
73798
+ }
73799
+ }
73800
+ }
73801
+ }
73802
+ });
73803
+
73345
73804
  // ../sidekick-cli/dist/cli.js
73346
73805
  var require_cli = __commonJS({
73347
73806
  "../sidekick-cli/dist/cli.js"(exports2) {
@@ -73396,7 +73855,7 @@ var require_cli = __commonJS({
73396
73855
  var promises_12 = require("node:fs/promises");
73397
73856
  var node_stream_1 = require("node:stream");
73398
73857
  var yargs_parser_1 = __importDefault2(require_build());
73399
- var VERSION = true ? "0.0.8-alpha.3" : "dev";
73858
+ var VERSION = true ? "0.0.8-alpha.5" : "dev";
73400
73859
  function isInSandbox() {
73401
73860
  return process.env.SANDBOX_RUNTIME === "1";
73402
73861
  }
@@ -73419,7 +73878,19 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
73419
73878
  };
73420
73879
  exports2.UnknownOptionError = UnknownOptionError;
73421
73880
  var CLI_OPTIONS = {
73422
- boolean: ["wait", "open", "prefer-project", "help", "version", "kill", "force", "gitignore", "personas"],
73881
+ boolean: [
73882
+ "wait",
73883
+ "open",
73884
+ "prefer-project",
73885
+ "help",
73886
+ "version",
73887
+ "kill",
73888
+ "force",
73889
+ "force-dev-mode",
73890
+ "dry-run",
73891
+ "gitignore",
73892
+ "personas"
73893
+ ],
73423
73894
  string: [
73424
73895
  "project-dir",
73425
73896
  "log-level",
@@ -73427,6 +73898,7 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
73427
73898
  "host",
73428
73899
  "session-id",
73429
73900
  "type",
73901
+ "scope",
73430
73902
  "statusline-scope",
73431
73903
  "api-key-scope",
73432
73904
  "auto-config"
@@ -73476,6 +73948,7 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
73476
73948
  version: Boolean(parsed.version),
73477
73949
  kill: Boolean(parsed.kill),
73478
73950
  force: Boolean(parsed.force),
73951
+ forceDevMode: Boolean(parsed["force-dev-mode"]),
73479
73952
  _: parsed._,
73480
73953
  // Setup command scripting flags - only set if explicitly provided
73481
73954
  statuslineScope: parsed["statusline-scope"],
@@ -73640,7 +74113,7 @@ Run 'sidekick hook --help' for available hooks.
73640
74113
  hookInput,
73641
74114
  correlationId: runtime.correlationId,
73642
74115
  runtime,
73643
- force: parsed.force
74116
+ forceDevMode: parsed.forceDevMode
73644
74117
  }, runtime.logger, stdout);
73645
74118
  return { exitCode: result.exitCode, stdout: result.output, stderr: "" };
73646
74119
  }
@@ -73668,7 +74141,7 @@ Run 'sidekick hook --help' for available hooks.
73668
74141
  configService: runtime.config,
73669
74142
  assets: runtime.assets,
73670
74143
  help: parsed.help,
73671
- force: parsed.force
74144
+ forceDevMode: parsed.forceDevMode
73672
74145
  });
73673
74146
  return { exitCode: result.exitCode, stdout: "", stderr: "" };
73674
74147
  }
@@ -73724,6 +74197,16 @@ Run 'sidekick hook --help' for available hooks.
73724
74197
  });
73725
74198
  return { exitCode: result.exitCode, stdout: "", stderr: "" };
73726
74199
  }
74200
+ if (parsed.command === "uninstall") {
74201
+ const { handleUninstallCommand } = await Promise.resolve().then(() => __importStar(require_uninstall()));
74202
+ const result = await handleUninstallCommand(runtime.projectRoot || process.cwd(), runtime.logger, stdout, {
74203
+ force: Boolean(parsed.force),
74204
+ dryRun: Boolean(parsed["dry-run"]),
74205
+ scope: parsed.scope,
74206
+ stdin: process.stdin
74207
+ });
74208
+ return { exitCode: result.exitCode, stdout: "", stderr: "" };
74209
+ }
73727
74210
  if (parsed.command === "doctor") {
73728
74211
  const { handleSetupCommand } = await Promise.resolve().then(() => __importStar(require_setup2()));
73729
74212
  const result = await handleSetupCommand(runtime.projectRoot || process.cwd(), runtime.logger, stdout, {
package/dist/daemon.js CHANGED
@@ -50691,6 +50691,7 @@ var require_setup_status_service = __commonJS({
50691
50691
  }
50692
50692
  };
50693
50693
  const child = (0, node_child_process_1.spawn)("claude", ["plugin", "list", "--json"], {
50694
+ cwd: this.projectDir,
50694
50695
  stdio: ["ignore", "pipe", "pipe"]
50695
50696
  });
50696
50697
  let stdout = "";
@@ -50899,6 +50900,7 @@ var require_setup_status_service = __commonJS({
50899
50900
  this.logger?.info("Auto-configuring project with user defaults", {
50900
50901
  projectDir: this.projectDir
50901
50902
  });
50903
+ const existing = await this.getProjectStatus();
50902
50904
  const projectStatus = {
50903
50905
  version: 1,
50904
50906
  lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -50908,7 +50910,8 @@ var require_setup_status_service = __commonJS({
50908
50910
  OPENROUTER_API_KEY: "user",
50909
50911
  OPENAI_API_KEY: "user"
50910
50912
  },
50911
- gitignore: "unknown"
50913
+ gitignore: "unknown",
50914
+ ...existing?.devMode !== void 0 && { devMode: existing.devMode }
50912
50915
  };
50913
50916
  await this.writeProjectStatus(projectStatus);
50914
50917
  this.logger?.info("Project auto-configured successfully", {
@@ -50952,6 +50955,7 @@ var require_setup_status_service = __commonJS({
50952
50955
  if (projectStatus) {
50953
50956
  await this.updateProjectStatus({ statusline: actualStatusline });
50954
50957
  } else {
50958
+ const existingForDevMode = await this.getProjectStatus();
50955
50959
  await this.writeProjectStatus({
50956
50960
  version: 1,
50957
50961
  lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -50961,7 +50965,8 @@ var require_setup_status_service = __commonJS({
50961
50965
  OPENROUTER_API_KEY: "user",
50962
50966
  OPENAI_API_KEY: "user"
50963
50967
  },
50964
- gitignore: "unknown"
50968
+ gitignore: "unknown",
50969
+ ...existingForDevMode?.devMode !== void 0 && { devMode: existingForDevMode.devMode }
50965
50970
  });
50966
50971
  }
50967
50972
  } else {
@@ -51011,6 +51016,7 @@ var require_setup_status_service = __commonJS({
51011
51016
  });
51012
51017
  } else {
51013
51018
  const userApiKeyStatus = this.buildUserApiKeyStatus(detection);
51019
+ const existingForDevMode = await this.getProjectStatus();
51014
51020
  await this.writeProjectStatus({
51015
51021
  version: 1,
51016
51022
  lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -51020,7 +51026,8 @@ var require_setup_status_service = __commonJS({
51020
51026
  OPENROUTER_API_KEY: keyName === "OPENROUTER_API_KEY" ? projectApiKeyStatus : "user",
51021
51027
  OPENAI_API_KEY: keyName === "OPENAI_API_KEY" ? projectApiKeyStatus : "user"
51022
51028
  },
51023
- gitignore: "unknown"
51029
+ gitignore: "unknown",
51030
+ ...existingForDevMode?.devMode !== void 0 && { devMode: existingForDevMode.devMode }
51024
51031
  });
51025
51032
  const userStatus = await this.getUserStatus();
51026
51033
  if (!userStatus) {
@@ -51110,7 +51117,8 @@ var require_setup_status_service = __commonJS({
51110
51117
  }
51111
51118
  };
51112
51119
  const child = (0, node_child_process_1.spawn)("claude", ["-p", prompt], {
51113
- env: { ...process.env, SIDEKICK_SAFE_WORD: safeWord },
51120
+ cwd: this.projectDir,
51121
+ env: { ...process.env, SIDEKICK_LIVENESS_CHECK: safeWord },
51114
51122
  stdio: ["ignore", "pipe", "pipe"]
51115
51123
  });
51116
51124
  let stdout = "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scotthamilton77/sidekick",
3
- "version": "0.0.8-alpha.3",
3
+ "version": "0.0.8-alpha.5",
4
4
  "description": "AI pair programming assistant with personas, session tracking, and contextual nudges",
5
5
  "bin": {
6
6
  "sidekick": "dist/bin.js"