@scotthamilton77/sidekick 0.0.8-alpha.7 → 0.0.8-alpha.9

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 +508 -52
  2. package/dist/daemon.js +47 -4
  3. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -17842,9 +17842,11 @@ var require_setup_status = __commonJS({
17842
17842
  "user",
17843
17843
  // Configured in ~/.claude/settings.json
17844
17844
  "project",
17845
- // Configured in .claude/settings.local.json
17845
+ // Configured in .claude/settings.json (shared via git)
17846
+ "local",
17847
+ // Configured in .claude/settings.local.json (not shared)
17846
17848
  "both",
17847
- // Configured in both (project overrides user)
17849
+ // Configured in multiple locations
17848
17850
  "none"
17849
17851
  // Not configured anywhere
17850
17852
  ]);
@@ -17855,7 +17857,7 @@ var require_setup_status = __commonJS({
17855
17857
  // ISO timestamp
17856
17858
  preferences: zod_1.z.object({
17857
17859
  autoConfigureProjects: zod_1.z.boolean(),
17858
- defaultStatuslineScope: zod_1.z.enum(["user", "project"]),
17860
+ defaultStatuslineScope: zod_1.z.enum(["user", "project", "local"]),
17859
17861
  defaultApiKeyScope: zod_1.z.enum(["user", "project", "skip"])
17860
17862
  }),
17861
17863
  statusline: exports2.StatuslineStatusSchema,
@@ -33950,6 +33952,18 @@ var require_structured_logging = __commonJS({
33950
33952
  }
33951
33953
  });
33952
33954
 
33955
+ // ../sidekick-core/dist/sandbox.js
33956
+ var require_sandbox = __commonJS({
33957
+ "../sidekick-core/dist/sandbox.js"(exports2) {
33958
+ "use strict";
33959
+ Object.defineProperty(exports2, "__esModule", { value: true });
33960
+ exports2.isInSandbox = isInSandbox;
33961
+ function isInSandbox() {
33962
+ return process.env.SANDBOX_RUNTIME === "1";
33963
+ }
33964
+ }
33965
+ });
33966
+
33953
33967
  // ../../package.json
33954
33968
  var require_package3 = __commonJS({
33955
33969
  "../../package.json"(exports2, module2) {
@@ -34009,6 +34023,7 @@ var require_daemon_client2 = __commonJS({
34009
34023
  var path_1 = __importDefault2(require("path"));
34010
34024
  var client_js_1 = require_client();
34011
34025
  var transport_js_1 = require_transport();
34026
+ var sandbox_js_1 = require_sandbox();
34012
34027
  var LOCK_TIMEOUT_MS = 1e4;
34013
34028
  var LOCK_RETRY_INTERVAL_MS = 100;
34014
34029
  var LOCK_STALE_THRESHOLD_MS = 3e4;
@@ -34021,6 +34036,10 @@ var require_daemon_client2 = __commonJS({
34021
34036
  this.ipcClient = new client_js_1.IpcClient((0, transport_js_1.getSocketPath)(projectDir), logger);
34022
34037
  }
34023
34038
  async start() {
34039
+ if ((0, sandbox_js_1.isInSandbox)()) {
34040
+ this.logger.debug("Skipping daemon start \u2014 sandbox mode detected");
34041
+ return;
34042
+ }
34024
34043
  await this.withStartupLock(async () => {
34025
34044
  await this.cleanupStaleFiles();
34026
34045
  if (await this.isRunning()) {
@@ -57524,7 +57543,7 @@ var require_dist4 = __commonJS({
57524
57543
  };
57525
57544
  Object.defineProperty(exports2, "__esModule", { value: true });
57526
57545
  exports2.SessionScopedStagingService = exports2.StagingServiceCore = exports2.GITIGNORE_ENTRIES = exports2.SIDEKICK_SECTION_END = exports2.SIDEKICK_SECTION_START = exports2.detectGitignoreStatus = exports2.removeGitignoreSection = exports2.installGitignoreSection = exports2.validateOpenAIKey = exports2.validateOpenRouterKey = exports2.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;
57527
- 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 = exports2.getHookDir = exports2.getStagingRoot = void 0;
57546
+ exports2.isInSandbox = 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 = exports2.getHookDir = exports2.getStagingRoot = void 0;
57528
57547
  var types_1 = require_dist();
57529
57548
  Object.defineProperty(exports2, "TaskTypes", { enumerable: true, get: function() {
57530
57549
  return types_1.TaskTypes;
@@ -57821,6 +57840,10 @@ var require_dist4 = __commonJS({
57821
57840
  Object.defineProperty(exports2, "DaemonGlobalLogMetricsDescriptor", { enumerable: true, get: function() {
57822
57841
  return index_js_1.DaemonGlobalLogMetricsDescriptor;
57823
57842
  } });
57843
+ var sandbox_1 = require_sandbox();
57844
+ Object.defineProperty(exports2, "isInSandbox", { enumerable: true, get: function() {
57845
+ return sandbox_1.isInSandbox;
57846
+ } });
57824
57847
  }
57825
57848
  });
57826
57849
 
@@ -68286,6 +68309,10 @@ var require_hook_command = __commonJS({
68286
68309
  };
68287
68310
  }
68288
68311
  async function ensureDaemonForHook(projectRoot, logger) {
68312
+ if ((0, core_1.isInSandbox)()) {
68313
+ logger.debug("Skipping daemon start \u2014 sandbox mode");
68314
+ return false;
68315
+ }
68289
68316
  try {
68290
68317
  const setupService = new core_1.SetupStatusService(projectRoot);
68291
68318
  const setupState = await setupService.getSetupState();
@@ -68801,6 +68828,7 @@ var require_persona_selection = __commonJS({
68801
68828
  exports2.filterPersonasByAllowList = filterPersonasByAllowList;
68802
68829
  exports2.selectRandomPersona = selectRandomPersona;
68803
68830
  exports2.selectPersonaForSession = selectPersonaForSession;
68831
+ exports2.ensurePersonaForSession = ensurePersonaForSession;
68804
68832
  var core_1 = require_dist4();
68805
68833
  var state_js_1 = require_state4();
68806
68834
  var types_js_1 = require_types4();
@@ -68873,6 +68901,23 @@ var require_persona_selection = __commonJS({
68873
68901
  });
68874
68902
  return selected.id;
68875
68903
  }
68904
+ async function ensurePersonaForSession(sessionId, ctx) {
68905
+ try {
68906
+ const summaryState = (0, state_js_1.createSessionSummaryState)(ctx.stateService);
68907
+ const result = await summaryState.sessionPersona.read(sessionId);
68908
+ if (result.data)
68909
+ return;
68910
+ ctx.logger.info("Persona state missing for active session, re-selecting", { sessionId });
68911
+ const featureConfig = ctx.config.getFeature("session-summary");
68912
+ const config = { ...types_js_1.DEFAULT_SESSION_SUMMARY_CONFIG, ...featureConfig.settings };
68913
+ await selectPersonaForSession(sessionId, config, ctx);
68914
+ } catch (err) {
68915
+ ctx.logger.warn("Failed to ensure persona for session", {
68916
+ sessionId,
68917
+ error: err instanceof Error ? err.message : String(err)
68918
+ });
68919
+ }
68920
+ }
68876
68921
  }
68877
68922
  });
68878
68923
 
@@ -69048,6 +69093,7 @@ var require_update_summary = __commonJS({
69048
69093
  var types_js_1 = require_types4();
69049
69094
  var state_js_1 = require_state4();
69050
69095
  var persona_utils_js_1 = require_persona_utils();
69096
+ var persona_selection_js_1 = require_persona_selection();
69051
69097
  var PROMPT_FILE = "prompts/session-summary.prompt.txt";
69052
69098
  var SNARKY_PROMPT_FILE = "prompts/snarky-message.prompt.txt";
69053
69099
  var RESUME_PROMPT_FILE = "prompts/resume-message.prompt.txt";
@@ -69095,6 +69141,7 @@ var require_update_summary = __commonJS({
69095
69141
  return;
69096
69142
  }
69097
69143
  if (event.eventType === "BulkProcessingComplete") {
69144
+ await (0, persona_selection_js_1.ensurePersonaForSession)(sessionId, ctx);
69098
69145
  const metrics = ctx.transcript.getMetrics();
69099
69146
  if (metrics.turnCount === 0) {
69100
69147
  ctx.logger.info("LLM call: session-summary analysis", {
@@ -70517,6 +70564,7 @@ var require_statusline_service = __commonJS({
70517
70564
  Object.defineProperty(exports2, "__esModule", { value: true });
70518
70565
  exports2.StatuslineService = void 0;
70519
70566
  exports2.createStatuslineService = createStatuslineService;
70567
+ exports2.deterministicIndex = deterministicIndex;
70520
70568
  var core_1 = require_dist4();
70521
70569
  var formatter_js_1 = require_formatter();
70522
70570
  var git_provider_js_1 = require_git_provider();
@@ -70603,8 +70651,7 @@ var require_statusline_service = __commonJS({
70603
70651
  return types_js_1.DEFAULT_PLACEHOLDERS.newSession;
70604
70652
  }
70605
70653
  if (persona.statusline_empty_messages && persona.statusline_empty_messages.length > 0) {
70606
- const randomIndex = Math.floor(Math.random() * persona.statusline_empty_messages.length);
70607
- return persona.statusline_empty_messages[randomIndex];
70654
+ return persona.statusline_empty_messages[deterministicIndex(this.sessionId, persona.statusline_empty_messages.length)];
70608
70655
  }
70609
70656
  return this.loadRandomEmptyMessageFromAssets();
70610
70657
  }
@@ -70625,8 +70672,7 @@ var require_statusline_service = __commonJS({
70625
70672
  if (messages.length === 0) {
70626
70673
  return types_js_1.DEFAULT_PLACEHOLDERS.newSession;
70627
70674
  }
70628
- const randomIndex = Math.floor(Math.random() * messages.length);
70629
- return messages[randomIndex];
70675
+ return messages[deterministicIndex(this.sessionId, messages.length)];
70630
70676
  }
70631
70677
  /**
70632
70678
  * Check if resume message is still fresh based on timestamp.
@@ -71002,6 +71048,15 @@ var require_statusline_service = __commonJS({
71002
71048
  function createStatuslineService(config) {
71003
71049
  return new StatuslineService(config);
71004
71050
  }
71051
+ function deterministicIndex(seed, arrayLength) {
71052
+ if (arrayLength <= 1)
71053
+ return 0;
71054
+ let hash = 5381;
71055
+ for (let i = 0; i < seed.length; i++) {
71056
+ hash = (hash << 5) + hash + seed.charCodeAt(i) | 0;
71057
+ }
71058
+ return Math.abs(hash) % arrayLength;
71059
+ }
71005
71060
  }
71006
71061
  });
71007
71062
 
@@ -72730,6 +72785,341 @@ var require_prompts = __commonJS({
72730
72785
  }
72731
72786
  });
72732
72787
 
72788
+ // ../sidekick-cli/dist/commands/setup/plugin-installer.js
72789
+ var require_plugin_installer = __commonJS({
72790
+ "../sidekick-cli/dist/commands/setup/plugin-installer.js"(exports2) {
72791
+ "use strict";
72792
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
72793
+ if (k2 === void 0) k2 = k;
72794
+ var desc = Object.getOwnPropertyDescriptor(m, k);
72795
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
72796
+ desc = { enumerable: true, get: function() {
72797
+ return m[k];
72798
+ } };
72799
+ }
72800
+ Object.defineProperty(o, k2, desc);
72801
+ }) : (function(o, m, k, k2) {
72802
+ if (k2 === void 0) k2 = k;
72803
+ o[k2] = m[k];
72804
+ }));
72805
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {
72806
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
72807
+ }) : function(o, v) {
72808
+ o["default"] = v;
72809
+ });
72810
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ (function() {
72811
+ var ownKeys = function(o) {
72812
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
72813
+ var ar = [];
72814
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
72815
+ return ar;
72816
+ };
72817
+ return ownKeys(o);
72818
+ };
72819
+ return function(mod) {
72820
+ if (mod && mod.__esModule) return mod;
72821
+ var result = {};
72822
+ if (mod != null) {
72823
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
72824
+ }
72825
+ __setModuleDefault(result, mod);
72826
+ return result;
72827
+ };
72828
+ })();
72829
+ Object.defineProperty(exports2, "__esModule", { value: true });
72830
+ exports2.PLUGIN_NAME = exports2.MARKETPLACE_SOURCE = exports2.MARKETPLACE_NAME = void 0;
72831
+ exports2.getValidPluginScopes = getValidPluginScopes;
72832
+ exports2.isScopeValid = isScopeValid;
72833
+ exports2.mergeMarketplaceSettings = mergeMarketplaceSettings;
72834
+ exports2.ensurePluginInstalled = ensurePluginInstalled;
72835
+ var fs = __importStar(require("node:fs/promises"));
72836
+ var path = __importStar(require("node:path"));
72837
+ var node_child_process_1 = require("node:child_process");
72838
+ var prompts_js_1 = require_prompts();
72839
+ exports2.MARKETPLACE_NAME = "claude-code-sidekick";
72840
+ exports2.MARKETPLACE_SOURCE = "github:scotthamilton77/claude-code-sidekick";
72841
+ exports2.PLUGIN_NAME = "sidekick";
72842
+ var ALL_SCOPES = ["user", "project", "local"];
72843
+ var SCOPE_ORDER = { user: 0, project: 1, local: 2 };
72844
+ function getValidPluginScopes(marketplaceScope) {
72845
+ const minOrder = SCOPE_ORDER[marketplaceScope];
72846
+ return ALL_SCOPES.filter((s) => SCOPE_ORDER[s] >= minOrder);
72847
+ }
72848
+ function isScopeValid(marketplaceScope, pluginScope) {
72849
+ return SCOPE_ORDER[pluginScope] >= SCOPE_ORDER[marketplaceScope];
72850
+ }
72851
+ function mergeMarketplaceSettings(existing) {
72852
+ const result = { ...existing };
72853
+ const marketplaces = Array.isArray(result.extraKnownMarketplaces) ? [...result.extraKnownMarketplaces] : [];
72854
+ if (!marketplaces.some((m) => m.name === exports2.MARKETPLACE_NAME)) {
72855
+ marketplaces.push({ name: exports2.MARKETPLACE_NAME, source: exports2.MARKETPLACE_SOURCE });
72856
+ }
72857
+ result.extraKnownMarketplaces = marketplaces;
72858
+ const plugins = Array.isArray(result.enabledPlugins) ? [...result.enabledPlugins] : [];
72859
+ const pluginEntry = `${exports2.PLUGIN_NAME}@${exports2.MARKETPLACE_NAME}`;
72860
+ if (!plugins.includes(pluginEntry)) {
72861
+ plugins.push(pluginEntry);
72862
+ }
72863
+ result.enabledPlugins = plugins;
72864
+ return result;
72865
+ }
72866
+ function createDefaultExecutor() {
72867
+ return {
72868
+ exec(cmd, args) {
72869
+ return new Promise((resolve3, reject) => {
72870
+ (0, node_child_process_1.execFile)(cmd, args, (error, stdout) => {
72871
+ if (!error) {
72872
+ resolve3({ stdout, exitCode: 0 });
72873
+ return;
72874
+ }
72875
+ if (error.code === "ENOENT") {
72876
+ reject(error);
72877
+ return;
72878
+ }
72879
+ resolve3({ stdout: stdout ?? "", exitCode: error.code ? Number(error.code) : 1 });
72880
+ });
72881
+ });
72882
+ }
72883
+ };
72884
+ }
72885
+ function settingsFilename(scope) {
72886
+ return scope === "project" ? "settings.json" : "settings.local.json";
72887
+ }
72888
+ function isCliMissing(err) {
72889
+ return err.code === "ENOENT" || (err.message ?? "").includes("ENOENT");
72890
+ }
72891
+ async function detectMarketplaceFromCLI(executor, logger) {
72892
+ const { stdout, exitCode } = await executor.exec("claude", ["plugin", "marketplace", "list", "--json"]);
72893
+ if (exitCode !== 0) {
72894
+ logger.warn("claude plugin marketplace list failed", { exitCode });
72895
+ return false;
72896
+ }
72897
+ const marketplaces = JSON.parse(stdout);
72898
+ return marketplaces.some((m) => m.name === exports2.MARKETPLACE_NAME);
72899
+ }
72900
+ async function detectMarketplaceFromSettings(projectDir, scope, logger) {
72901
+ const settingsPath = path.join(projectDir, ".claude", settingsFilename(scope));
72902
+ try {
72903
+ const content = await fs.readFile(settingsPath, "utf-8");
72904
+ const settings = JSON.parse(content);
72905
+ const marketplaces = settings.extraKnownMarketplaces;
72906
+ if (!Array.isArray(marketplaces))
72907
+ return false;
72908
+ return marketplaces.some((m) => m.name === exports2.MARKETPLACE_NAME);
72909
+ } catch {
72910
+ logger.debug("Settings file not found or unreadable", { path: settingsPath });
72911
+ return false;
72912
+ }
72913
+ }
72914
+ async function detectPluginFromCLI(executor, logger) {
72915
+ const { stdout, exitCode } = await executor.exec("claude", ["plugin", "list", "--json"]);
72916
+ if (exitCode !== 0) {
72917
+ logger.warn("claude plugin list failed", { exitCode });
72918
+ return false;
72919
+ }
72920
+ const plugins = JSON.parse(stdout);
72921
+ return plugins.some((p) => p.id.startsWith(`${exports2.PLUGIN_NAME}@`));
72922
+ }
72923
+ async function detectMarketplaceAnywhere(executor, projectDir, logger) {
72924
+ let cliAvailable = true;
72925
+ try {
72926
+ if (await detectMarketplaceFromCLI(executor, logger)) {
72927
+ return { scope: "user", cliAvailable };
72928
+ }
72929
+ } catch (err) {
72930
+ if (isCliMissing(err)) {
72931
+ cliAvailable = false;
72932
+ }
72933
+ logger.warn("Failed to detect marketplace via CLI", { error: err.message });
72934
+ }
72935
+ if (await detectMarketplaceFromSettings(projectDir, "project", logger)) {
72936
+ return { scope: "project", cliAvailable };
72937
+ }
72938
+ if (await detectMarketplaceFromSettings(projectDir, "local", logger)) {
72939
+ return { scope: "local", cliAvailable };
72940
+ }
72941
+ return { scope: null, cliAvailable };
72942
+ }
72943
+ async function installMarketplaceViaCLI(executor, logger) {
72944
+ logger.info("Installing marketplace via CLI", { source: exports2.MARKETPLACE_SOURCE });
72945
+ const { exitCode } = await executor.exec("claude", ["plugin", "marketplace", "add", exports2.MARKETPLACE_SOURCE]);
72946
+ return exitCode === 0;
72947
+ }
72948
+ async function installMarketplaceViaSettings(projectDir, scope, logger) {
72949
+ const settingsPath = path.join(projectDir, ".claude", settingsFilename(scope));
72950
+ logger.info("Installing marketplace via settings file", { path: settingsPath });
72951
+ let existing = {};
72952
+ try {
72953
+ const content = await fs.readFile(settingsPath, "utf-8");
72954
+ existing = JSON.parse(content);
72955
+ } catch {
72956
+ }
72957
+ const merged = mergeMarketplaceSettings(existing);
72958
+ await fs.mkdir(path.dirname(settingsPath), { recursive: true });
72959
+ await fs.writeFile(settingsPath, JSON.stringify(merged, null, 2) + "\n");
72960
+ }
72961
+ async function installPlugin(executor, scope, logger) {
72962
+ logger.info("Installing sidekick plugin", { scope });
72963
+ const { exitCode } = await executor.exec("claude", ["plugin", "install", exports2.PLUGIN_NAME, "-s", scope]);
72964
+ return exitCode === 0;
72965
+ }
72966
+ var SCOPE_LABELS = {
72967
+ user: { label: "User (recommended)", description: "Available to all your projects" },
72968
+ project: { label: "Project", description: "Only this project" },
72969
+ local: { label: "Local", description: "Local-only, not shared via git" }
72970
+ };
72971
+ async function promptMarketplaceScope(ctx) {
72972
+ return (0, prompts_js_1.promptSelect)(ctx, "Where should the sidekick marketplace be installed?", [
72973
+ { value: "user", ...SCOPE_LABELS.user },
72974
+ { value: "project", ...SCOPE_LABELS.project },
72975
+ { value: "local", ...SCOPE_LABELS.local }
72976
+ ]);
72977
+ }
72978
+ async function promptPluginScope(ctx, validScopes) {
72979
+ const options = validScopes.map((scope) => ({
72980
+ value: scope,
72981
+ ...SCOPE_LABELS[scope]
72982
+ }));
72983
+ return (0, prompts_js_1.promptSelect)(ctx, "Where should the sidekick plugin be installed?", options);
72984
+ }
72985
+ function printManualInstructions(stdout) {
72986
+ stdout.write("\nThe claude CLI is not available. Install sidekick manually:\n");
72987
+ stdout.write(` 1. claude plugin marketplace add ${exports2.MARKETPLACE_SOURCE}
72988
+ `);
72989
+ stdout.write(` 2. claude plugin install ${exports2.PLUGIN_NAME}
72990
+ `);
72991
+ stdout.write("\nSee https://github.com/scotthamilton77/claude-code-sidekick for details.\n\n");
72992
+ }
72993
+ async function ensurePluginInstalled(options) {
72994
+ const { logger, stdout, force, projectDir } = options;
72995
+ const executor = options.executor ?? createDefaultExecutor();
72996
+ if (options.marketplaceScope && options.pluginScope) {
72997
+ if (!isScopeValid(options.marketplaceScope, options.pluginScope)) {
72998
+ const msg = `Plugin scope '${options.pluginScope}' is broader than marketplace scope '${options.marketplaceScope}'. Plugin scope must be equal to or narrower than marketplace scope.`;
72999
+ stdout.write(`\u2717 ${msg}
73000
+ `);
73001
+ return {
73002
+ marketplaceScope: options.marketplaceScope,
73003
+ pluginScope: options.pluginScope,
73004
+ marketplaceAction: "failed",
73005
+ pluginAction: "failed",
73006
+ error: msg
73007
+ };
73008
+ }
73009
+ }
73010
+ const { scope: detectedMktScope, cliAvailable } = await detectMarketplaceAnywhere(executor, projectDir, logger);
73011
+ let pluginDetected = false;
73012
+ if (cliAvailable) {
73013
+ try {
73014
+ pluginDetected = await detectPluginFromCLI(executor, logger);
73015
+ } catch {
73016
+ }
73017
+ }
73018
+ if (detectedMktScope && pluginDetected) {
73019
+ stdout.write(`\u2713 Marketplace: already installed (${detectedMktScope})
73020
+ `);
73021
+ stdout.write(`\u2713 Plugin: already installed
73022
+ `);
73023
+ return {
73024
+ marketplaceScope: options.marketplaceScope ?? detectedMktScope,
73025
+ pluginScope: options.pluginScope ?? detectedMktScope,
73026
+ marketplaceAction: "already-installed",
73027
+ pluginAction: "already-installed"
73028
+ };
73029
+ }
73030
+ if (!cliAvailable) {
73031
+ printManualInstructions(stdout);
73032
+ const error = "claude CLI not available";
73033
+ stdout.write(`\u2717 Marketplace: ${error}
73034
+ `);
73035
+ return {
73036
+ marketplaceScope: options.marketplaceScope ?? "user",
73037
+ pluginScope: options.pluginScope ?? "user",
73038
+ marketplaceAction: detectedMktScope ? "already-installed" : "failed",
73039
+ pluginAction: "failed",
73040
+ error
73041
+ };
73042
+ }
73043
+ let marketplaceScope;
73044
+ let pluginScope;
73045
+ if (options.marketplaceScope && options.pluginScope) {
73046
+ marketplaceScope = options.marketplaceScope;
73047
+ pluginScope = options.pluginScope;
73048
+ } else if (force) {
73049
+ marketplaceScope = options.marketplaceScope ?? detectedMktScope ?? "user";
73050
+ pluginScope = options.pluginScope ?? "user";
73051
+ } else if (options.ctx) {
73052
+ (0, prompts_js_1.printHeader)(options.ctx, "Step 1: Plugin Installation", "Sidekick needs the marketplace and plugin installed in Claude Code.");
73053
+ if (detectedMktScope) {
73054
+ marketplaceScope = detectedMktScope;
73055
+ (0, prompts_js_1.printStatus)(options.ctx, "info", `Marketplace already installed (${detectedMktScope})`);
73056
+ } else {
73057
+ marketplaceScope = await promptMarketplaceScope(options.ctx);
73058
+ }
73059
+ if (pluginDetected) {
73060
+ pluginScope = marketplaceScope;
73061
+ (0, prompts_js_1.printStatus)(options.ctx, "info", "Plugin already installed");
73062
+ } else {
73063
+ const validPluginScopes = getValidPluginScopes(marketplaceScope);
73064
+ if (validPluginScopes.length === 1) {
73065
+ pluginScope = validPluginScopes[0];
73066
+ (0, prompts_js_1.printStatus)(options.ctx, "info", `Plugin scope auto-selected: ${pluginScope} (constrained by marketplace scope)`);
73067
+ } else {
73068
+ pluginScope = await promptPluginScope(options.ctx, validPluginScopes);
73069
+ }
73070
+ }
73071
+ } else {
73072
+ marketplaceScope = detectedMktScope ?? "user";
73073
+ pluginScope = "user";
73074
+ }
73075
+ let marketplaceAction;
73076
+ if (detectedMktScope) {
73077
+ marketplaceAction = "already-installed";
73078
+ stdout.write(`\u2713 Marketplace: already installed (${detectedMktScope})
73079
+ `);
73080
+ } else if (marketplaceScope === "user") {
73081
+ const success = await installMarketplaceViaCLI(executor, logger);
73082
+ if (success) {
73083
+ marketplaceAction = "installed";
73084
+ stdout.write(`\u2713 Marketplace: installed (${marketplaceScope})
73085
+ `);
73086
+ } else {
73087
+ marketplaceAction = "failed";
73088
+ const error = "Failed to install marketplace via CLI";
73089
+ stdout.write(`\u2717 Marketplace: ${error}
73090
+ `);
73091
+ return { marketplaceScope, pluginScope, marketplaceAction, pluginAction: "failed", error };
73092
+ }
73093
+ } else {
73094
+ await installMarketplaceViaSettings(projectDir, marketplaceScope, logger);
73095
+ marketplaceAction = "installed";
73096
+ stdout.write(`\u2713 Marketplace: installed via settings (${marketplaceScope})
73097
+ `);
73098
+ }
73099
+ let pluginAction;
73100
+ if (pluginDetected) {
73101
+ pluginAction = "already-installed";
73102
+ stdout.write(`\u2713 Plugin: already installed
73103
+ `);
73104
+ } else {
73105
+ const success = await installPlugin(executor, pluginScope, logger);
73106
+ if (success) {
73107
+ pluginAction = "installed";
73108
+ stdout.write(`\u2713 Plugin: installed (${pluginScope})
73109
+ `);
73110
+ } else {
73111
+ pluginAction = "failed";
73112
+ const error = "Failed to install sidekick plugin";
73113
+ stdout.write(`\u2717 Plugin: ${error}
73114
+ `);
73115
+ return { marketplaceScope, pluginScope, marketplaceAction, pluginAction, error };
73116
+ }
73117
+ }
73118
+ return { marketplaceScope, pluginScope, marketplaceAction, pluginAction };
73119
+ }
73120
+ }
73121
+ });
73122
+
72733
73123
  // ../sidekick-cli/dist/commands/setup/index.js
72734
73124
  var require_setup = __commonJS({
72735
73125
  "../sidekick-cli/dist/commands/setup/index.js"(exports2) {
@@ -72778,6 +73168,7 @@ var require_setup = __commonJS({
72778
73168
  var os = __importStar(require("node:os"));
72779
73169
  var core_1 = require_dist4();
72780
73170
  var prompts_js_1 = require_prompts();
73171
+ var plugin_installer_js_1 = require_plugin_installer();
72781
73172
  var USAGE_TEXT = `Usage: sidekick setup [options]
72782
73173
 
72783
73174
  Run the interactive setup wizard to configure sidekick for Claude Code.
@@ -72791,7 +73182,9 @@ Options:
72791
73182
  --help Show this help message
72792
73183
 
72793
73184
  Scripting Flags (for non-interactive/partial setup):
72794
- --statusline-scope=<scope> Configure statusline: user | project
73185
+ --marketplace-scope=<scope> Install marketplace: user | project | local
73186
+ --plugin-scope=<scope> Install plugin: user | project | local
73187
+ --statusline-scope=<scope> Configure statusline: user | project | local
72795
73188
  --gitignore Update .gitignore to exclude sidekick files
72796
73189
  --no-gitignore Skip .gitignore configuration
72797
73190
  --personas Enable persona features
@@ -72809,6 +73202,16 @@ Examples:
72809
73202
  OPENROUTER_API_KEY=sk-xxx sidekick setup --personas --api-key-scope=user
72810
73203
  `;
72811
73204
  var STATUSLINE_COMMAND = "npx @scotthamilton77/sidekick statusline --project-dir=$CLAUDE_PROJECT_DIR";
73205
+ function statuslineSettingsPath(scope, homeDir, projectDir) {
73206
+ switch (scope) {
73207
+ case "user":
73208
+ return path.join(homeDir, ".claude", "settings.json");
73209
+ case "project":
73210
+ return path.join(projectDir, ".claude", "settings.json");
73211
+ case "local":
73212
+ return path.join(projectDir, ".claude", "settings.local.json");
73213
+ }
73214
+ }
72812
73215
  function getPluginStatusLabel(status) {
72813
73216
  switch (status) {
72814
73217
  case "plugin":
@@ -72966,27 +73369,36 @@ Examples:
72966
73369
  stdout.write("\u2502 Run 'sidekick setup' again anytime to reconfigure. \u2502\n");
72967
73370
  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");
72968
73371
  }
72969
- async function runStep1Statusline(wctx) {
73372
+ async function runStep2Statusline(wctx, pluginScope) {
72970
73373
  const { ctx, homeDir, projectDir, logger } = wctx;
72971
- (0, prompts_js_1.printHeader)(ctx, "Step 1: Statusline Configuration", "Claude Code plugins cannot provide statusline config directly.");
72972
- const statuslineScope = await (0, prompts_js_1.promptSelect)(ctx, "Where should sidekick configure your statusline?", [
72973
- { value: "user", label: "User-level (~/.claude/settings.json)", description: "Works in all projects" },
72974
- {
72975
- value: "project",
72976
- label: "Project-level (.claude/settings.local.json)",
72977
- description: "This project only"
72978
- }
72979
- ]);
72980
- const statuslinePath = statuslineScope === "user" ? path.join(homeDir, ".claude", "settings.json") : path.join(projectDir, ".claude", "settings.local.json");
72981
- const wrote = await configureStatusline(statuslinePath, logger);
73374
+ (0, prompts_js_1.printHeader)(ctx, "Step 2: Statusline Configuration", "Claude Code plugins cannot provide statusline config directly.");
73375
+ const STATUSLINE_SCOPE_OPTIONS = {
73376
+ user: { label: "User-level (~/.claude/settings.json)", description: "Works in all projects" },
73377
+ project: { label: "Project-level (.claude/settings.json)", description: "Shared via git" },
73378
+ local: { label: "Local (.claude/settings.local.json)", description: "This machine only, not shared via git" }
73379
+ };
73380
+ const validScopes = (0, plugin_installer_js_1.getValidPluginScopes)(pluginScope);
73381
+ let statuslineScope;
73382
+ if (validScopes.length === 1) {
73383
+ statuslineScope = validScopes[0];
73384
+ (0, prompts_js_1.printStatus)(ctx, "info", `Statusline scope auto-selected: ${statuslineScope} (constrained by plugin scope)`);
73385
+ } else {
73386
+ const options = validScopes.map((scope) => ({
73387
+ value: scope,
73388
+ ...STATUSLINE_SCOPE_OPTIONS[scope]
73389
+ }));
73390
+ statuslineScope = await (0, prompts_js_1.promptSelect)(ctx, "Where should sidekick configure your statusline?", options);
73391
+ }
73392
+ const settingsPath = statuslineSettingsPath(statuslineScope, homeDir, projectDir);
73393
+ const wrote = await configureStatusline(settingsPath, logger);
72982
73394
  if (wrote) {
72983
- (0, prompts_js_1.printStatus)(ctx, "success", `Statusline configured in ${statuslinePath}`);
73395
+ (0, prompts_js_1.printStatus)(ctx, "success", `Statusline configured in ${settingsPath}`);
72984
73396
  } else {
72985
73397
  (0, prompts_js_1.printStatus)(ctx, "warning", "Statusline managed by dev-mode (skipped)");
72986
73398
  }
72987
73399
  return statuslineScope;
72988
73400
  }
72989
- async function runStep2Gitignore(wctx, force) {
73401
+ async function runStep3Gitignore(wctx, force) {
72990
73402
  const { ctx, projectDir } = wctx;
72991
73403
  const currentStatus = await (0, core_1.detectGitignoreStatus)(projectDir);
72992
73404
  if (currentStatus === "installed") {
@@ -73000,7 +73412,7 @@ Examples:
73000
73412
  const result2 = await (0, core_1.installGitignoreSection)(projectDir);
73001
73413
  return result2.status === "error" ? "missing" : "installed";
73002
73414
  }
73003
- (0, prompts_js_1.printHeader)(ctx, "Step 2: Git Configuration", "Sidekick creates logs and session data that should not be committed.");
73415
+ (0, prompts_js_1.printHeader)(ctx, "Step 3: Git Configuration", "Sidekick creates logs and session data that should not be committed.");
73004
73416
  if (needsRepair) {
73005
73417
  (0, prompts_js_1.printStatus)(ctx, "warning", "Existing .gitignore section is incomplete and needs repair");
73006
73418
  }
@@ -73026,10 +73438,10 @@ Examples:
73026
73438
  (0, prompts_js_1.printStatus)(ctx, "success", message);
73027
73439
  return "installed";
73028
73440
  }
73029
- async function runStep3Personas(wctx) {
73441
+ async function runStep4Personas(wctx) {
73030
73442
  const { ctx, homeDir } = wctx;
73031
73443
  const stdout = ctx.stdout;
73032
- (0, prompts_js_1.printHeader)(ctx, "Step 3: Persona Features", "Sidekick includes AI personas (Marvin, Skippy, etc.) that add\npersonality to your coding sessions with snarky messages and contextual nudges.");
73444
+ (0, prompts_js_1.printHeader)(ctx, "Step 4: Persona Features", "Sidekick includes AI personas (Marvin, Skippy, etc.) that add\npersonality to your coding sessions with snarky messages and contextual nudges.");
73033
73445
  stdout.write("These require an OpenRouter API key (small cost per message).\n\n");
73034
73446
  const wantPersonas = await (0, prompts_js_1.promptConfirm)(ctx, "Enable persona features?", true);
73035
73447
  let apiKeyHealth = "not-required";
@@ -73105,9 +73517,9 @@ Examples:
73105
73517
  const postDetection = await setupService.detectAllApiKeys("OPENROUTER_API_KEY", true);
73106
73518
  return { health: result.valid ? "healthy" : "invalid", detection: postDetection };
73107
73519
  }
73108
- async function runStep4AutoConfig(wctx) {
73520
+ async function runStep5AutoConfig(wctx) {
73109
73521
  const { ctx } = wctx;
73110
- (0, prompts_js_1.printHeader)(ctx, "Step 4: Project Auto-Configuration");
73522
+ (0, prompts_js_1.printHeader)(ctx, "Step 5: Project Auto-Configuration");
73111
73523
  const autoConfig = await (0, prompts_js_1.promptSelect)(ctx, "When sidekick runs in a new project for the first time:", [
73112
73524
  { value: "auto", label: "Auto-configure using my defaults", description: "Recommended" },
73113
73525
  { value: "manual", label: "Do nothing", description: "Manual setup only" }
@@ -73153,7 +73565,8 @@ Examples:
73153
73565
  const { statuslineScope, gitignoreStatus, wantPersonas, apiKeyHealth, autoConfig } = state;
73154
73566
  const stdout = ctx.stdout;
73155
73567
  (0, prompts_js_1.printHeader)(ctx, "Summary");
73156
- (0, prompts_js_1.printStatus)(ctx, "success", `Statusline: ${statuslineScope === "user" ? "User-level" : "Project-level"}`);
73568
+ const scopeLabel = { user: "User-level", project: "Project-level", local: "Local" }[statuslineScope];
73569
+ (0, prompts_js_1.printStatus)(ctx, "success", `Statusline: ${scopeLabel}`);
73157
73570
  let gitignoreStatusType;
73158
73571
  let gitignoreLabel;
73159
73572
  switch (gitignoreStatus) {
@@ -73202,13 +73615,26 @@ Examples:
73202
73615
  if (!force) {
73203
73616
  printWizardHeader(stdout);
73204
73617
  }
73205
- const statuslineScope = force ? "user" : await runStep1Statusline(wctx);
73206
- const gitignoreStatus = await runStep2Gitignore(wctx, force);
73207
- const { wantPersonas, apiKeyHealth, apiKeyDetection } = force ? { wantPersonas: true, apiKeyHealth: "not-required", apiKeyDetection: null } : await runStep3Personas(wctx);
73208
- const autoConfig = force ? "auto" : await runStep4AutoConfig(wctx);
73618
+ const pluginResult = await (0, plugin_installer_js_1.ensurePluginInstalled)({
73619
+ logger,
73620
+ stdout,
73621
+ force,
73622
+ projectDir,
73623
+ ctx: wctx.ctx,
73624
+ marketplaceScope: options.marketplaceScope,
73625
+ pluginScope: options.pluginScope
73626
+ });
73627
+ if (pluginResult.error) {
73628
+ logger.warn("Plugin installation had issues, continuing with setup", { error: pluginResult.error });
73629
+ }
73630
+ const forceStatuslineScope = pluginResult.pluginScope;
73631
+ const statuslineScope = force ? forceStatuslineScope : await runStep2Statusline(wctx, pluginResult.pluginScope);
73632
+ const gitignoreStatus = await runStep3Gitignore(wctx, force);
73633
+ const { wantPersonas, apiKeyHealth, apiKeyDetection } = force ? { wantPersonas: true, apiKeyHealth: "not-required", apiKeyDetection: null } : await runStep4Personas(wctx);
73634
+ const autoConfig = force ? "auto" : await runStep5AutoConfig(wctx);
73209
73635
  if (force) {
73210
- const statuslinePath = path.join(homeDir, ".claude", "settings.json");
73211
- const wrote = await configureStatusline(statuslinePath, logger);
73636
+ const settingsPath = statuslineSettingsPath(forceStatuslineScope, homeDir, projectDir);
73637
+ const wrote = await configureStatusline(settingsPath, logger);
73212
73638
  if (!wrote) {
73213
73639
  stdout.write("\u26A0 Statusline managed by dev-mode (skipped)\n");
73214
73640
  }
@@ -73226,7 +73652,9 @@ Examples:
73226
73652
  printSummary(wctx, state);
73227
73653
  } else {
73228
73654
  stdout.write("Setup complete (force mode):\n");
73229
- stdout.write(` Statusline: user-level (~/.claude/settings.json)
73655
+ stdout.write(` Plugin: ${pluginResult.pluginAction} (${pluginResult.pluginScope})
73656
+ `);
73657
+ stdout.write(` Statusline: ${forceStatuslineScope} (${statuslineSettingsPath(forceStatuslineScope, homeDir, projectDir)})
73230
73658
  `);
73231
73659
  stdout.write(` Gitignore: ${gitignoreStatus === "installed" ? "configured" : "skipped"}
73232
73660
  `);
@@ -73238,15 +73666,32 @@ Examples:
73238
73666
  return { exitCode: 0 };
73239
73667
  }
73240
73668
  function hasScriptingFlags(options) {
73241
- return options.statuslineScope !== void 0 || options.gitignore !== void 0 || options.personas !== void 0 || options.apiKeyScope !== void 0 || options.autoConfig !== void 0;
73669
+ return options.marketplaceScope !== void 0 || options.pluginScope !== void 0 || options.statuslineScope !== void 0 || options.gitignore !== void 0 || options.personas !== void 0 || options.apiKeyScope !== void 0 || options.autoConfig !== void 0;
73242
73670
  }
73243
73671
  async function runScripted(projectDir, logger, stdout, options) {
73244
73672
  const homeDir = options.homeDir ?? os.homedir();
73245
73673
  const setupService = new core_1.SetupStatusService(projectDir, { homeDir, logger });
73246
73674
  let configuredCount = 0;
73675
+ if (options.marketplaceScope !== void 0 || options.pluginScope !== void 0) {
73676
+ const pluginResult = await (0, plugin_installer_js_1.ensurePluginInstalled)({
73677
+ logger,
73678
+ stdout,
73679
+ force: true,
73680
+ // scripted mode never prompts
73681
+ projectDir,
73682
+ marketplaceScope: options.marketplaceScope,
73683
+ pluginScope: options.pluginScope
73684
+ });
73685
+ if (pluginResult.error) {
73686
+ stdout.write(`\u26A0 Plugin installation issue: ${pluginResult.error}
73687
+ `);
73688
+ } else {
73689
+ configuredCount++;
73690
+ }
73691
+ }
73247
73692
  if (options.statuslineScope) {
73248
- const statuslinePath = options.statuslineScope === "user" ? path.join(homeDir, ".claude", "settings.json") : path.join(projectDir, ".claude", "settings.local.json");
73249
- const wrote = await configureStatusline(statuslinePath, logger);
73693
+ const settingsPath = statuslineSettingsPath(options.statuslineScope, homeDir, projectDir);
73694
+ const wrote = await configureStatusline(settingsPath, logger);
73250
73695
  if (wrote) {
73251
73696
  stdout.write(`\u2713 Statusline configured (${options.statuslineScope}-level)
73252
73697
  `);
@@ -73549,6 +73994,10 @@ var require_uninstall = __commonJS({
73549
73994
  dryRun,
73550
73995
  removeHooks: true
73551
73996
  });
73997
+ await cleanSettingsFile(path.join(projectDir, ".claude", "settings.json"), "project", logger, actions, {
73998
+ dryRun,
73999
+ removeHooks: true
74000
+ });
73552
74001
  }
73553
74002
  if (userDetected) {
73554
74003
  await cleanSettingsFile(path.join(userHome, ".claude", "settings.json"), "user", logger, actions, {
@@ -73621,12 +74070,15 @@ var require_uninstall = __commonJS({
73621
74070
  await fs.access(path.join(projectDir, ".sidekick", "setup-status.json"));
73622
74071
  return true;
73623
74072
  } catch {
73624
- try {
73625
- const content = await fs.readFile(path.join(projectDir, ".claude", "settings.local.json"), "utf-8");
73626
- return content.includes("sidekick");
73627
- } catch {
73628
- return false;
74073
+ for (const file of ["settings.local.json", "settings.json"]) {
74074
+ try {
74075
+ const content = await fs.readFile(path.join(projectDir, ".claude", file), "utf-8");
74076
+ if (content.includes("sidekick"))
74077
+ return true;
74078
+ } catch {
74079
+ }
73629
74080
  }
74081
+ return false;
73630
74082
  }
73631
74083
  }
73632
74084
  async function detectUserScope(userHome) {
@@ -73943,10 +74395,7 @@ var require_cli = __commonJS({
73943
74395
  var promises_12 = require("node:fs/promises");
73944
74396
  var node_stream_1 = require("node:stream");
73945
74397
  var yargs_parser_1 = __importDefault2(require_build());
73946
- var VERSION = true ? "0.0.8-alpha.7" : "dev";
73947
- function isInSandbox() {
73948
- return process.env.SANDBOX_RUNTIME === "1";
73949
- }
74398
+ var VERSION = true ? "0.0.8-alpha.9" : "dev";
73950
74399
  var SANDBOX_ERROR_MESSAGE = `Error: Daemon commands cannot run in sandbox mode.
73951
74400
 
73952
74401
  Claude Code's sandbox blocks Unix socket operations required for daemon IPC.
@@ -73955,6 +74404,7 @@ To run this command, use dangerouslyDisableSandbox: true in the Bash tool call.
73955
74404
  Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox": true }
73956
74405
  `;
73957
74406
  var types_1 = require_dist();
74407
+ var core_1 = require_dist4();
73958
74408
  var runtime_1 = require_runtime();
73959
74409
  var UnknownOptionError = class extends Error {
73960
74410
  constructor(unknownOptions) {
@@ -73990,7 +74440,9 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
73990
74440
  "statusline-scope",
73991
74441
  "api-key-scope",
73992
74442
  "auto-config",
73993
- "only"
74443
+ "only",
74444
+ "marketplace-scope",
74445
+ "plugin-scope"
73994
74446
  ],
73995
74447
  number: ["port", "width"],
73996
74448
  alias: { h: "help", v: "version" }
@@ -74045,7 +74497,9 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
74045
74497
  personas: hasPersonasFlag ? Boolean(parsed.personas) : void 0,
74046
74498
  apiKeyScope: parsed["api-key-scope"],
74047
74499
  autoConfig: parsed["auto-config"],
74048
- only: parsed.only
74500
+ only: parsed.only,
74501
+ marketplaceScope: parsed["marketplace-scope"],
74502
+ pluginScope: parsed["plugin-scope"]
74049
74503
  };
74050
74504
  }
74051
74505
  function parseHookInput(stdinData) {
@@ -74209,7 +74663,7 @@ Run 'sidekick hook --help' for available hooks.
74209
74663
  }
74210
74664
  if (parsed.command === "daemon") {
74211
74665
  const subcommand = parsed.help ? "--help" : parsed.kill ? "kill" : parsed._ && parsed._[1] || "status";
74212
- if (isInSandbox() && subcommand !== "--help") {
74666
+ if ((0, core_1.isInSandbox)() && subcommand !== "--help") {
74213
74667
  stdout.write(SANDBOX_ERROR_MESSAGE);
74214
74668
  return { exitCode: 1, stdout: SANDBOX_ERROR_MESSAGE, stderr: "" };
74215
74669
  }
@@ -74283,7 +74737,9 @@ Run 'sidekick hook --help' for available hooks.
74283
74737
  gitignore: parsed.gitignore,
74284
74738
  personas: parsed.personas,
74285
74739
  apiKeyScope: parsed.apiKeyScope,
74286
- autoConfig: parsed.autoConfig
74740
+ autoConfig: parsed.autoConfig,
74741
+ marketplaceScope: parsed.marketplaceScope,
74742
+ pluginScope: parsed.pluginScope
74287
74743
  });
74288
74744
  return { exitCode: result.exitCode, stdout: "", stderr: "" };
74289
74745
  }
package/dist/daemon.js CHANGED
@@ -16866,9 +16866,11 @@ var require_setup_status = __commonJS({
16866
16866
  "user",
16867
16867
  // Configured in ~/.claude/settings.json
16868
16868
  "project",
16869
- // Configured in .claude/settings.local.json
16869
+ // Configured in .claude/settings.json (shared via git)
16870
+ "local",
16871
+ // Configured in .claude/settings.local.json (not shared)
16870
16872
  "both",
16871
- // Configured in both (project overrides user)
16873
+ // Configured in multiple locations
16872
16874
  "none"
16873
16875
  // Not configured anywhere
16874
16876
  ]);
@@ -16879,7 +16881,7 @@ var require_setup_status = __commonJS({
16879
16881
  // ISO timestamp
16880
16882
  preferences: zod_1.z.object({
16881
16883
  autoConfigureProjects: zod_1.z.boolean(),
16882
- defaultStatuslineScope: zod_1.z.enum(["user", "project"]),
16884
+ defaultStatuslineScope: zod_1.z.enum(["user", "project", "local"]),
16883
16885
  defaultApiKeyScope: zod_1.z.enum(["user", "project", "skip"])
16884
16886
  }),
16885
16887
  statusline: exports2.StatuslineStatusSchema,
@@ -32974,6 +32976,18 @@ var require_structured_logging = __commonJS({
32974
32976
  }
32975
32977
  });
32976
32978
 
32979
+ // ../sidekick-core/dist/sandbox.js
32980
+ var require_sandbox = __commonJS({
32981
+ "../sidekick-core/dist/sandbox.js"(exports2) {
32982
+ "use strict";
32983
+ Object.defineProperty(exports2, "__esModule", { value: true });
32984
+ exports2.isInSandbox = isInSandbox;
32985
+ function isInSandbox() {
32986
+ return process.env.SANDBOX_RUNTIME === "1";
32987
+ }
32988
+ }
32989
+ });
32990
+
32977
32991
  // ../../package.json
32978
32992
  var require_package3 = __commonJS({
32979
32993
  "../../package.json"(exports2, module2) {
@@ -33033,6 +33047,7 @@ var require_daemon_client2 = __commonJS({
33033
33047
  var path_1 = __importDefault(require("path"));
33034
33048
  var client_js_1 = require_client();
33035
33049
  var transport_js_1 = require_transport();
33050
+ var sandbox_js_1 = require_sandbox();
33036
33051
  var LOCK_TIMEOUT_MS = 1e4;
33037
33052
  var LOCK_RETRY_INTERVAL_MS = 100;
33038
33053
  var LOCK_STALE_THRESHOLD_MS = 3e4;
@@ -33045,6 +33060,10 @@ var require_daemon_client2 = __commonJS({
33045
33060
  this.ipcClient = new client_js_1.IpcClient((0, transport_js_1.getSocketPath)(projectDir2), logger);
33046
33061
  }
33047
33062
  async start() {
33063
+ if ((0, sandbox_js_1.isInSandbox)()) {
33064
+ this.logger.debug("Skipping daemon start \u2014 sandbox mode detected");
33065
+ return;
33066
+ }
33048
33067
  await this.withStartupLock(async () => {
33049
33068
  await this.cleanupStaleFiles();
33050
33069
  if (await this.isRunning()) {
@@ -56548,7 +56567,7 @@ var require_dist4 = __commonJS({
56548
56567
  };
56549
56568
  Object.defineProperty(exports2, "__esModule", { value: true });
56550
56569
  exports2.SessionScopedStagingService = exports2.StagingServiceCore = exports2.GITIGNORE_ENTRIES = exports2.SIDEKICK_SECTION_END = exports2.SIDEKICK_SECTION_START = exports2.detectGitignoreStatus = exports2.removeGitignoreSection = exports2.installGitignoreSection = exports2.validateOpenAIKey = exports2.validateOpenRouterKey = exports2.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;
56551
- 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 = exports2.getHookDir = exports2.getStagingRoot = void 0;
56570
+ exports2.isInSandbox = 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 = exports2.getHookDir = exports2.getStagingRoot = void 0;
56552
56571
  var types_1 = require_dist();
56553
56572
  Object.defineProperty(exports2, "TaskTypes", { enumerable: true, get: function() {
56554
56573
  return types_1.TaskTypes;
@@ -56845,6 +56864,10 @@ var require_dist4 = __commonJS({
56845
56864
  Object.defineProperty(exports2, "DaemonGlobalLogMetricsDescriptor", { enumerable: true, get: function() {
56846
56865
  return index_js_1.DaemonGlobalLogMetricsDescriptor;
56847
56866
  } });
56867
+ var sandbox_1 = require_sandbox();
56868
+ Object.defineProperty(exports2, "isInSandbox", { enumerable: true, get: function() {
56869
+ return sandbox_1.isInSandbox;
56870
+ } });
56848
56871
  }
56849
56872
  });
56850
56873
 
@@ -66739,6 +66762,7 @@ var require_persona_selection = __commonJS({
66739
66762
  exports2.filterPersonasByAllowList = filterPersonasByAllowList;
66740
66763
  exports2.selectRandomPersona = selectRandomPersona;
66741
66764
  exports2.selectPersonaForSession = selectPersonaForSession;
66765
+ exports2.ensurePersonaForSession = ensurePersonaForSession;
66742
66766
  var core_1 = require_dist4();
66743
66767
  var state_js_1 = require_state4();
66744
66768
  var types_js_1 = require_types3();
@@ -66811,6 +66835,23 @@ var require_persona_selection = __commonJS({
66811
66835
  });
66812
66836
  return selected.id;
66813
66837
  }
66838
+ async function ensurePersonaForSession(sessionId, ctx) {
66839
+ try {
66840
+ const summaryState = (0, state_js_1.createSessionSummaryState)(ctx.stateService);
66841
+ const result = await summaryState.sessionPersona.read(sessionId);
66842
+ if (result.data)
66843
+ return;
66844
+ ctx.logger.info("Persona state missing for active session, re-selecting", { sessionId });
66845
+ const featureConfig = ctx.config.getFeature("session-summary");
66846
+ const config = { ...types_js_1.DEFAULT_SESSION_SUMMARY_CONFIG, ...featureConfig.settings };
66847
+ await selectPersonaForSession(sessionId, config, ctx);
66848
+ } catch (err) {
66849
+ ctx.logger.warn("Failed to ensure persona for session", {
66850
+ sessionId,
66851
+ error: err instanceof Error ? err.message : String(err)
66852
+ });
66853
+ }
66854
+ }
66814
66855
  }
66815
66856
  });
66816
66857
 
@@ -66986,6 +67027,7 @@ var require_update_summary = __commonJS({
66986
67027
  var types_js_1 = require_types3();
66987
67028
  var state_js_1 = require_state4();
66988
67029
  var persona_utils_js_1 = require_persona_utils();
67030
+ var persona_selection_js_1 = require_persona_selection();
66989
67031
  var PROMPT_FILE = "prompts/session-summary.prompt.txt";
66990
67032
  var SNARKY_PROMPT_FILE = "prompts/snarky-message.prompt.txt";
66991
67033
  var RESUME_PROMPT_FILE = "prompts/resume-message.prompt.txt";
@@ -67033,6 +67075,7 @@ var require_update_summary = __commonJS({
67033
67075
  return;
67034
67076
  }
67035
67077
  if (event.eventType === "BulkProcessingComplete") {
67078
+ await (0, persona_selection_js_1.ensurePersonaForSession)(sessionId, ctx);
67036
67079
  const metrics = ctx.transcript.getMetrics();
67037
67080
  if (metrics.turnCount === 0) {
67038
67081
  ctx.logger.info("LLM call: session-summary analysis", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scotthamilton77/sidekick",
3
- "version": "0.0.8-alpha.7",
3
+ "version": "0.0.8-alpha.9",
4
4
  "description": "AI pair programming assistant with personas, session tracking, and contextual nudges",
5
5
  "bin": {
6
6
  "sidekick": "dist/bin.js"