@scotthamilton77/sidekick 0.0.2-alpha → 0.0.4-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.
- package/dist/bin.js +1164 -15
- package/dist/daemon.js +70160 -0
- 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
|
-
|
|
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.
|
|
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;
|
|
@@ -51116,6 +51571,10 @@ var require_statusline_service = __commonJS({
|
|
|
51116
51571
|
theme: this.config.theme,
|
|
51117
51572
|
useColors: this.useColors
|
|
51118
51573
|
});
|
|
51574
|
+
this.setupService = serviceConfig.setupService ?? new core_1.SetupStatusService(serviceConfig.projectDir ?? serviceConfig.cwd, {
|
|
51575
|
+
homeDir: serviceConfig.homeDir,
|
|
51576
|
+
logger: serviceConfig.logger
|
|
51577
|
+
});
|
|
51119
51578
|
}
|
|
51120
51579
|
/**
|
|
51121
51580
|
* Load persona definition for the session.
|
|
@@ -51205,6 +51664,74 @@ var require_statusline_service = __commonJS({
|
|
|
51205
51664
|
}
|
|
51206
51665
|
return { ...types_js_2.DEFAULT_STATUSLINE_CONFIG, ...serviceConfig.config };
|
|
51207
51666
|
}
|
|
51667
|
+
/**
|
|
51668
|
+
* Check setup status and return warning message if unhealthy.
|
|
51669
|
+
* Returns empty warning for healthy state.
|
|
51670
|
+
*/
|
|
51671
|
+
async checkSetupStatus() {
|
|
51672
|
+
const state = await this.setupService.getSetupState();
|
|
51673
|
+
switch (state) {
|
|
51674
|
+
case "not-run":
|
|
51675
|
+
return {
|
|
51676
|
+
warning: "Sidekick not configured. Run 'sidekick setup' to get started.",
|
|
51677
|
+
state
|
|
51678
|
+
};
|
|
51679
|
+
case "partial":
|
|
51680
|
+
return {
|
|
51681
|
+
warning: "Project not configured. Run 'sidekick setup' for this project.",
|
|
51682
|
+
state
|
|
51683
|
+
};
|
|
51684
|
+
case "unhealthy": {
|
|
51685
|
+
const keyHealth = await this.setupService.getEffectiveApiKeyHealth("OPENROUTER_API_KEY");
|
|
51686
|
+
if (keyHealth === "missing") {
|
|
51687
|
+
return {
|
|
51688
|
+
warning: "OPENROUTER_API_KEY not found. Run 'sidekick doctor' or /sidekick-config",
|
|
51689
|
+
state
|
|
51690
|
+
};
|
|
51691
|
+
}
|
|
51692
|
+
if (keyHealth === "invalid") {
|
|
51693
|
+
return {
|
|
51694
|
+
warning: "API key invalid. Run 'sidekick doctor' to fix.",
|
|
51695
|
+
state
|
|
51696
|
+
};
|
|
51697
|
+
}
|
|
51698
|
+
return {
|
|
51699
|
+
warning: "Setup issue detected. Run 'sidekick doctor'.",
|
|
51700
|
+
state
|
|
51701
|
+
};
|
|
51702
|
+
}
|
|
51703
|
+
default:
|
|
51704
|
+
return { warning: "", state: "healthy" };
|
|
51705
|
+
}
|
|
51706
|
+
}
|
|
51707
|
+
/**
|
|
51708
|
+
* Build minimal view model for setup_warning display mode.
|
|
51709
|
+
* Only includes fields needed for warning display.
|
|
51710
|
+
*/
|
|
51711
|
+
buildMinimalViewModel(setupCheck) {
|
|
51712
|
+
return {
|
|
51713
|
+
model: "",
|
|
51714
|
+
contextWindow: "",
|
|
51715
|
+
tokenUsageActual: "",
|
|
51716
|
+
tokenUsageEffective: "",
|
|
51717
|
+
tokenPercentageActual: "",
|
|
51718
|
+
tokenPercentageEffective: "",
|
|
51719
|
+
tokensStatus: "normal",
|
|
51720
|
+
cost: "",
|
|
51721
|
+
costStatus: "normal",
|
|
51722
|
+
duration: "",
|
|
51723
|
+
cwd: "",
|
|
51724
|
+
branch: "",
|
|
51725
|
+
branchColor: "",
|
|
51726
|
+
displayMode: "setup_warning",
|
|
51727
|
+
summary: setupCheck.warning,
|
|
51728
|
+
title: "",
|
|
51729
|
+
warningCount: 0,
|
|
51730
|
+
errorCount: 0,
|
|
51731
|
+
logStatus: "normal",
|
|
51732
|
+
personaName: ""
|
|
51733
|
+
};
|
|
51734
|
+
}
|
|
51208
51735
|
/**
|
|
51209
51736
|
* Render the statusline by fetching all data in parallel and formatting.
|
|
51210
51737
|
*
|
|
@@ -51214,6 +51741,19 @@ var require_statusline_service = __commonJS({
|
|
|
51214
51741
|
* for model/tokens/cost/duration instead of reading from state files.
|
|
51215
51742
|
*/
|
|
51216
51743
|
async render() {
|
|
51744
|
+
const setupCheck = await this.checkSetupStatus();
|
|
51745
|
+
if (setupCheck.state !== "healthy") {
|
|
51746
|
+
const viewModel2 = this.buildMinimalViewModel(setupCheck);
|
|
51747
|
+
const ANSI_YELLOW = "\x1B[33m";
|
|
51748
|
+
const ANSI_RESET = "\x1B[0m";
|
|
51749
|
+
const text2 = this.useColors ? `${ANSI_YELLOW}${setupCheck.warning}${ANSI_RESET}` : setupCheck.warning;
|
|
51750
|
+
return {
|
|
51751
|
+
text: text2,
|
|
51752
|
+
displayMode: "setup_warning",
|
|
51753
|
+
staleData: false,
|
|
51754
|
+
viewModel: viewModel2
|
|
51755
|
+
};
|
|
51756
|
+
}
|
|
51217
51757
|
const hasHookInput = !!this.hookInput;
|
|
51218
51758
|
const [transcriptResult, summaryResult, resumeResult, snarkyResult, branchResult, baseline, logMetricsResult, personaResult] = await Promise.all([
|
|
51219
51759
|
this.stateReader.getTranscriptMetrics(),
|
|
@@ -53005,6 +53545,582 @@ ${USAGE_TEXT}`);
|
|
|
53005
53545
|
}
|
|
53006
53546
|
});
|
|
53007
53547
|
|
|
53548
|
+
// ../sidekick-cli/dist/commands/setup/prompts.js
|
|
53549
|
+
var require_prompts = __commonJS({
|
|
53550
|
+
"../sidekick-cli/dist/commands/setup/prompts.js"(exports2) {
|
|
53551
|
+
"use strict";
|
|
53552
|
+
var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
|
|
53553
|
+
if (k2 === void 0) k2 = k;
|
|
53554
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
53555
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
53556
|
+
desc = { enumerable: true, get: function() {
|
|
53557
|
+
return m[k];
|
|
53558
|
+
} };
|
|
53559
|
+
}
|
|
53560
|
+
Object.defineProperty(o, k2, desc);
|
|
53561
|
+
} : function(o, m, k, k2) {
|
|
53562
|
+
if (k2 === void 0) k2 = k;
|
|
53563
|
+
o[k2] = m[k];
|
|
53564
|
+
});
|
|
53565
|
+
var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
|
|
53566
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
53567
|
+
} : function(o, v) {
|
|
53568
|
+
o["default"] = v;
|
|
53569
|
+
});
|
|
53570
|
+
var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
|
|
53571
|
+
var ownKeys = function(o) {
|
|
53572
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
53573
|
+
var ar = [];
|
|
53574
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
53575
|
+
return ar;
|
|
53576
|
+
};
|
|
53577
|
+
return ownKeys(o);
|
|
53578
|
+
};
|
|
53579
|
+
return function(mod) {
|
|
53580
|
+
if (mod && mod.__esModule) return mod;
|
|
53581
|
+
var result = {};
|
|
53582
|
+
if (mod != null) {
|
|
53583
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
53584
|
+
}
|
|
53585
|
+
__setModuleDefault(result, mod);
|
|
53586
|
+
return result;
|
|
53587
|
+
};
|
|
53588
|
+
}();
|
|
53589
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
53590
|
+
exports2.printHeader = printHeader;
|
|
53591
|
+
exports2.printStatus = printStatus;
|
|
53592
|
+
exports2.promptSelect = promptSelect;
|
|
53593
|
+
exports2.promptConfirm = promptConfirm;
|
|
53594
|
+
exports2.promptInput = promptInput;
|
|
53595
|
+
var readline = __importStar(require("node:readline"));
|
|
53596
|
+
var colors = {
|
|
53597
|
+
reset: "\x1B[0m",
|
|
53598
|
+
bold: "\x1B[1m",
|
|
53599
|
+
dim: "\x1B[2m",
|
|
53600
|
+
green: "\x1B[32m",
|
|
53601
|
+
yellow: "\x1B[33m",
|
|
53602
|
+
blue: "\x1B[34m",
|
|
53603
|
+
cyan: "\x1B[36m"
|
|
53604
|
+
};
|
|
53605
|
+
function printHeader(ctx, title, description) {
|
|
53606
|
+
ctx.stdout.write("\n");
|
|
53607
|
+
ctx.stdout.write(`${colors.bold}${title}${colors.reset}
|
|
53608
|
+
`);
|
|
53609
|
+
ctx.stdout.write("\u2500".repeat(Math.min(title.length + 10, 60)) + "\n");
|
|
53610
|
+
if (description) {
|
|
53611
|
+
ctx.stdout.write(`${colors.dim}${description}${colors.reset}
|
|
53612
|
+
`);
|
|
53613
|
+
}
|
|
53614
|
+
ctx.stdout.write("\n");
|
|
53615
|
+
}
|
|
53616
|
+
function printStatus(ctx, type, message) {
|
|
53617
|
+
const icons = { success: "\u2713", warning: "\u26A0", info: "\u2022", error: "\u2717" };
|
|
53618
|
+
const colorMap = { success: colors.green, warning: colors.yellow, info: colors.blue, error: "\x1B[31m" };
|
|
53619
|
+
ctx.stdout.write(`${colorMap[type]}${icons[type]}${colors.reset} ${message}
|
|
53620
|
+
`);
|
|
53621
|
+
}
|
|
53622
|
+
async function promptSelect(ctx, question, options) {
|
|
53623
|
+
ctx.stdout.write(`${question}
|
|
53624
|
+
|
|
53625
|
+
`);
|
|
53626
|
+
options.forEach((opt, i) => {
|
|
53627
|
+
ctx.stdout.write(` ${colors.cyan}${i + 1})${colors.reset} ${opt.label}
|
|
53628
|
+
`);
|
|
53629
|
+
if (opt.description) {
|
|
53630
|
+
ctx.stdout.write(` ${colors.dim}${opt.description}${colors.reset}
|
|
53631
|
+
`);
|
|
53632
|
+
}
|
|
53633
|
+
});
|
|
53634
|
+
ctx.stdout.write("\n");
|
|
53635
|
+
const rl = readline.createInterface({
|
|
53636
|
+
input: ctx.stdin,
|
|
53637
|
+
output: ctx.stdout,
|
|
53638
|
+
terminal: false
|
|
53639
|
+
});
|
|
53640
|
+
return new Promise((resolve3) => {
|
|
53641
|
+
ctx.stdout.write(`Enter choice (1-${options.length}): `);
|
|
53642
|
+
rl.once("line", (answer) => {
|
|
53643
|
+
rl.close();
|
|
53644
|
+
const num = parseInt(answer.trim(), 10);
|
|
53645
|
+
if (num >= 1 && num <= options.length) {
|
|
53646
|
+
resolve3(options[num - 1].value);
|
|
53647
|
+
} else {
|
|
53648
|
+
resolve3(options[0].value);
|
|
53649
|
+
}
|
|
53650
|
+
});
|
|
53651
|
+
});
|
|
53652
|
+
}
|
|
53653
|
+
async function promptConfirm(ctx, question, defaultYes = true) {
|
|
53654
|
+
const hint = defaultYes ? "[Y/n]" : "[y/N]";
|
|
53655
|
+
const rl = readline.createInterface({
|
|
53656
|
+
input: ctx.stdin,
|
|
53657
|
+
output: ctx.stdout,
|
|
53658
|
+
terminal: false
|
|
53659
|
+
});
|
|
53660
|
+
return new Promise((resolve3) => {
|
|
53661
|
+
ctx.stdout.write(`${question} ${hint} `);
|
|
53662
|
+
rl.once("line", (answer) => {
|
|
53663
|
+
rl.close();
|
|
53664
|
+
const normalized = answer.trim().toLowerCase();
|
|
53665
|
+
if (normalized === "") {
|
|
53666
|
+
resolve3(defaultYes);
|
|
53667
|
+
} else {
|
|
53668
|
+
resolve3(normalized === "y" || normalized === "yes");
|
|
53669
|
+
}
|
|
53670
|
+
});
|
|
53671
|
+
});
|
|
53672
|
+
}
|
|
53673
|
+
async function promptInput(ctx, question) {
|
|
53674
|
+
const rl = readline.createInterface({
|
|
53675
|
+
input: ctx.stdin,
|
|
53676
|
+
output: ctx.stdout,
|
|
53677
|
+
terminal: false
|
|
53678
|
+
});
|
|
53679
|
+
return new Promise((resolve3) => {
|
|
53680
|
+
ctx.stdout.write(`${question}: `);
|
|
53681
|
+
rl.once("line", (answer) => {
|
|
53682
|
+
rl.close();
|
|
53683
|
+
resolve3(answer.trim());
|
|
53684
|
+
});
|
|
53685
|
+
});
|
|
53686
|
+
}
|
|
53687
|
+
}
|
|
53688
|
+
});
|
|
53689
|
+
|
|
53690
|
+
// ../sidekick-cli/dist/commands/setup/validate-api-key.js
|
|
53691
|
+
var require_validate_api_key = __commonJS({
|
|
53692
|
+
"../sidekick-cli/dist/commands/setup/validate-api-key.js"(exports2) {
|
|
53693
|
+
"use strict";
|
|
53694
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
53695
|
+
exports2.validateOpenRouterKey = validateOpenRouterKey;
|
|
53696
|
+
exports2.validateOpenAIKey = validateOpenAIKey;
|
|
53697
|
+
var API_ENDPOINTS = {
|
|
53698
|
+
openrouter: "https://openrouter.ai/api/v1/models",
|
|
53699
|
+
openai: "https://api.openai.com/v1/models"
|
|
53700
|
+
};
|
|
53701
|
+
async function validateApiKey(provider, apiKey, logger) {
|
|
53702
|
+
try {
|
|
53703
|
+
const response = await fetch(API_ENDPOINTS[provider], {
|
|
53704
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
53705
|
+
});
|
|
53706
|
+
if (response.ok) {
|
|
53707
|
+
return { valid: true };
|
|
53708
|
+
}
|
|
53709
|
+
if (response.status === 401) {
|
|
53710
|
+
return { valid: false, error: "Invalid API key" };
|
|
53711
|
+
}
|
|
53712
|
+
return { valid: false, error: `API returned status ${response.status}` };
|
|
53713
|
+
} catch (err) {
|
|
53714
|
+
logger?.warn("API key validation failed", { error: err });
|
|
53715
|
+
return { valid: false, error: err instanceof Error ? err.message : "Network error" };
|
|
53716
|
+
}
|
|
53717
|
+
}
|
|
53718
|
+
function validateOpenRouterKey(apiKey, logger) {
|
|
53719
|
+
return validateApiKey("openrouter", apiKey, logger);
|
|
53720
|
+
}
|
|
53721
|
+
function validateOpenAIKey(apiKey, logger) {
|
|
53722
|
+
return validateApiKey("openai", apiKey, logger);
|
|
53723
|
+
}
|
|
53724
|
+
}
|
|
53725
|
+
});
|
|
53726
|
+
|
|
53727
|
+
// ../sidekick-cli/dist/commands/setup/index.js
|
|
53728
|
+
var require_setup = __commonJS({
|
|
53729
|
+
"../sidekick-cli/dist/commands/setup/index.js"(exports2) {
|
|
53730
|
+
"use strict";
|
|
53731
|
+
var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
|
|
53732
|
+
if (k2 === void 0) k2 = k;
|
|
53733
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
53734
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
53735
|
+
desc = { enumerable: true, get: function() {
|
|
53736
|
+
return m[k];
|
|
53737
|
+
} };
|
|
53738
|
+
}
|
|
53739
|
+
Object.defineProperty(o, k2, desc);
|
|
53740
|
+
} : function(o, m, k, k2) {
|
|
53741
|
+
if (k2 === void 0) k2 = k;
|
|
53742
|
+
o[k2] = m[k];
|
|
53743
|
+
});
|
|
53744
|
+
var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
|
|
53745
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
53746
|
+
} : function(o, v) {
|
|
53747
|
+
o["default"] = v;
|
|
53748
|
+
});
|
|
53749
|
+
var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
|
|
53750
|
+
var ownKeys = function(o) {
|
|
53751
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
53752
|
+
var ar = [];
|
|
53753
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
53754
|
+
return ar;
|
|
53755
|
+
};
|
|
53756
|
+
return ownKeys(o);
|
|
53757
|
+
};
|
|
53758
|
+
return function(mod) {
|
|
53759
|
+
if (mod && mod.__esModule) return mod;
|
|
53760
|
+
var result = {};
|
|
53761
|
+
if (mod != null) {
|
|
53762
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
53763
|
+
}
|
|
53764
|
+
__setModuleDefault(result, mod);
|
|
53765
|
+
return result;
|
|
53766
|
+
};
|
|
53767
|
+
}();
|
|
53768
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
53769
|
+
exports2.handleSetupCommand = handleSetupCommand;
|
|
53770
|
+
var fs = __importStar(require("node:fs/promises"));
|
|
53771
|
+
var path = __importStar(require("node:path"));
|
|
53772
|
+
var os = __importStar(require("node:os"));
|
|
53773
|
+
var core_1 = require_dist3();
|
|
53774
|
+
var prompts_js_1 = require_prompts();
|
|
53775
|
+
var validate_api_key_js_1 = require_validate_api_key();
|
|
53776
|
+
var STATUSLINE_COMMAND = "npx @scotthamilton77/sidekick statusline --project-dir=$CLAUDE_PROJECT_DIR";
|
|
53777
|
+
function getApiKeyStatusType(health) {
|
|
53778
|
+
switch (health) {
|
|
53779
|
+
case "healthy":
|
|
53780
|
+
return "success";
|
|
53781
|
+
case "not-required":
|
|
53782
|
+
return "info";
|
|
53783
|
+
default:
|
|
53784
|
+
return "warning";
|
|
53785
|
+
}
|
|
53786
|
+
}
|
|
53787
|
+
async function configureStatusline(settingsPath, logger) {
|
|
53788
|
+
let settings = {};
|
|
53789
|
+
try {
|
|
53790
|
+
const content = await fs.readFile(settingsPath, "utf-8");
|
|
53791
|
+
settings = JSON.parse(content);
|
|
53792
|
+
} catch (err) {
|
|
53793
|
+
if (err.code !== "ENOENT") {
|
|
53794
|
+
throw err;
|
|
53795
|
+
}
|
|
53796
|
+
}
|
|
53797
|
+
settings.statusLine = {
|
|
53798
|
+
type: "command",
|
|
53799
|
+
command: STATUSLINE_COMMAND
|
|
53800
|
+
};
|
|
53801
|
+
const dir = path.dirname(settingsPath);
|
|
53802
|
+
await fs.mkdir(dir, { recursive: true });
|
|
53803
|
+
await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
53804
|
+
logger?.info("Statusline configured", { path: settingsPath });
|
|
53805
|
+
}
|
|
53806
|
+
async function writeApiKeyToEnv(envPath, key, value) {
|
|
53807
|
+
const dir = path.dirname(envPath);
|
|
53808
|
+
await fs.mkdir(dir, { recursive: true });
|
|
53809
|
+
let content = "";
|
|
53810
|
+
try {
|
|
53811
|
+
content = await fs.readFile(envPath, "utf-8");
|
|
53812
|
+
} catch {
|
|
53813
|
+
}
|
|
53814
|
+
const keyRegex = new RegExp(`^${key}=.*$`, "m");
|
|
53815
|
+
if (keyRegex.test(content)) {
|
|
53816
|
+
content = content.replace(keyRegex, `${key}=${value}`);
|
|
53817
|
+
} else {
|
|
53818
|
+
if (content && !content.endsWith("\n")) {
|
|
53819
|
+
content += "\n";
|
|
53820
|
+
}
|
|
53821
|
+
content += `${key}=${value}
|
|
53822
|
+
`;
|
|
53823
|
+
}
|
|
53824
|
+
await fs.writeFile(envPath, content);
|
|
53825
|
+
}
|
|
53826
|
+
async function findExistingApiKey(keyName, homeDir, projectDir) {
|
|
53827
|
+
if (process.env[keyName]) {
|
|
53828
|
+
return process.env[keyName];
|
|
53829
|
+
}
|
|
53830
|
+
const envPaths = [
|
|
53831
|
+
path.join(homeDir, ".sidekick", ".env"),
|
|
53832
|
+
path.join(projectDir, ".sidekick", ".env"),
|
|
53833
|
+
path.join(projectDir, ".sidekick", ".env.local")
|
|
53834
|
+
];
|
|
53835
|
+
for (const envPath of envPaths) {
|
|
53836
|
+
try {
|
|
53837
|
+
const content = await fs.readFile(envPath, "utf-8");
|
|
53838
|
+
const match = content.match(new RegExp(`^${keyName}=(.+)$`, "m"));
|
|
53839
|
+
if (match) {
|
|
53840
|
+
return match[1];
|
|
53841
|
+
}
|
|
53842
|
+
} catch {
|
|
53843
|
+
}
|
|
53844
|
+
}
|
|
53845
|
+
return null;
|
|
53846
|
+
}
|
|
53847
|
+
async function writePersonaConfig(_projectDir, homeDir, enabled) {
|
|
53848
|
+
const configDir = path.join(homeDir, ".sidekick");
|
|
53849
|
+
const configPath = path.join(configDir, "config.yaml");
|
|
53850
|
+
await fs.mkdir(configDir, { recursive: true });
|
|
53851
|
+
let content = "";
|
|
53852
|
+
try {
|
|
53853
|
+
content = await fs.readFile(configPath, "utf-8");
|
|
53854
|
+
} catch {
|
|
53855
|
+
}
|
|
53856
|
+
const personasRegex = /^features:\s*\n\s*personas:\s*\n\s*enabled:\s*(true|false)/m;
|
|
53857
|
+
const newPersonasBlock = `features:
|
|
53858
|
+
personas:
|
|
53859
|
+
enabled: ${enabled}`;
|
|
53860
|
+
if (personasRegex.test(content)) {
|
|
53861
|
+
content = content.replace(personasRegex, newPersonasBlock);
|
|
53862
|
+
} else {
|
|
53863
|
+
if (content && !content.endsWith("\n")) {
|
|
53864
|
+
content += "\n";
|
|
53865
|
+
}
|
|
53866
|
+
content += newPersonasBlock + "\n";
|
|
53867
|
+
}
|
|
53868
|
+
await fs.writeFile(configPath, content);
|
|
53869
|
+
}
|
|
53870
|
+
function printWizardHeader(stdout) {
|
|
53871
|
+
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");
|
|
53872
|
+
stdout.write("\u2502 Sidekick Setup Wizard \u2502\n");
|
|
53873
|
+
stdout.write("\u2502 \u2502\n");
|
|
53874
|
+
stdout.write("\u2502 This wizard configures sidekick for Claude Code. \u2502\n");
|
|
53875
|
+
stdout.write("\u2502 Run 'sidekick setup' again anytime to reconfigure. \u2502\n");
|
|
53876
|
+
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");
|
|
53877
|
+
}
|
|
53878
|
+
async function runStep1Statusline(wctx) {
|
|
53879
|
+
const { ctx, homeDir, projectDir, logger } = wctx;
|
|
53880
|
+
(0, prompts_js_1.printHeader)(ctx, "Step 1: Statusline Configuration", "Claude Code plugins cannot provide statusline config directly.");
|
|
53881
|
+
const statuslineScope = await (0, prompts_js_1.promptSelect)(ctx, "Where should sidekick configure your statusline?", [
|
|
53882
|
+
{ value: "user", label: "User-level (~/.claude/settings.json)", description: "Works in all projects" },
|
|
53883
|
+
{ value: "project", label: "Project-level (.claude/settings.local.json)", description: "This project only" }
|
|
53884
|
+
]);
|
|
53885
|
+
const statuslinePath = statuslineScope === "user" ? path.join(homeDir, ".claude", "settings.json") : path.join(projectDir, ".claude", "settings.local.json");
|
|
53886
|
+
await configureStatusline(statuslinePath, logger);
|
|
53887
|
+
(0, prompts_js_1.printStatus)(ctx, "success", `Statusline configured in ${statuslinePath}`);
|
|
53888
|
+
return statuslineScope;
|
|
53889
|
+
}
|
|
53890
|
+
async function runStep2Gitignore(wctx, force) {
|
|
53891
|
+
const { ctx, projectDir } = wctx;
|
|
53892
|
+
const currentStatus = await (0, core_1.detectGitignoreStatus)(projectDir);
|
|
53893
|
+
if (currentStatus === "installed") {
|
|
53894
|
+
if (!force) {
|
|
53895
|
+
(0, prompts_js_1.printStatus)(ctx, "success", "Sidekick entries already present in .gitignore");
|
|
53896
|
+
}
|
|
53897
|
+
return "installed";
|
|
53898
|
+
}
|
|
53899
|
+
if (force) {
|
|
53900
|
+
const result2 = await (0, core_1.installGitignoreSection)(projectDir);
|
|
53901
|
+
return result2.status === "error" ? "missing" : "installed";
|
|
53902
|
+
}
|
|
53903
|
+
(0, prompts_js_1.printHeader)(ctx, "Step 2: Git Configuration", "Sidekick creates logs and session data that should not be committed.");
|
|
53904
|
+
const shouldInstall = await (0, prompts_js_1.promptConfirm)(ctx, "Update .gitignore to exclude sidekick transient files?", true);
|
|
53905
|
+
if (!shouldInstall) {
|
|
53906
|
+
(0, prompts_js_1.printStatus)(ctx, "info", "Skipping .gitignore configuration (you can manage it manually)");
|
|
53907
|
+
return "missing";
|
|
53908
|
+
}
|
|
53909
|
+
const result = await (0, core_1.installGitignoreSection)(projectDir);
|
|
53910
|
+
if (result.status === "error") {
|
|
53911
|
+
(0, prompts_js_1.printStatus)(ctx, "warning", `Failed to update .gitignore: ${result.error}`);
|
|
53912
|
+
return "missing";
|
|
53913
|
+
}
|
|
53914
|
+
const message = result.status === "already-installed" ? "Sidekick entries already present in .gitignore" : "Added sidekick section to .gitignore";
|
|
53915
|
+
(0, prompts_js_1.printStatus)(ctx, "success", message);
|
|
53916
|
+
return "installed";
|
|
53917
|
+
}
|
|
53918
|
+
async function runStep3Personas(wctx) {
|
|
53919
|
+
const { ctx, homeDir, projectDir } = wctx;
|
|
53920
|
+
const stdout = ctx.stdout;
|
|
53921
|
+
(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.");
|
|
53922
|
+
stdout.write("These require an OpenRouter API key (small cost per message).\n\n");
|
|
53923
|
+
const wantPersonas = await (0, prompts_js_1.promptConfirm)(ctx, "Enable persona features?", true);
|
|
53924
|
+
let apiKeyHealth = "not-required";
|
|
53925
|
+
if (!wantPersonas) {
|
|
53926
|
+
await writePersonaConfig(projectDir, homeDir, false);
|
|
53927
|
+
(0, prompts_js_1.printStatus)(ctx, "info", "Personas disabled");
|
|
53928
|
+
} else {
|
|
53929
|
+
await writePersonaConfig(projectDir, homeDir, true);
|
|
53930
|
+
apiKeyHealth = await configureApiKey(wctx);
|
|
53931
|
+
}
|
|
53932
|
+
return { wantPersonas, apiKeyHealth };
|
|
53933
|
+
}
|
|
53934
|
+
async function configureApiKey(wctx) {
|
|
53935
|
+
const { ctx, homeDir, projectDir, logger } = wctx;
|
|
53936
|
+
const stdout = ctx.stdout;
|
|
53937
|
+
const existingKey = await findExistingApiKey("OPENROUTER_API_KEY", homeDir, projectDir);
|
|
53938
|
+
if (existingKey) {
|
|
53939
|
+
(0, prompts_js_1.printStatus)(ctx, "success", "OPENROUTER_API_KEY found");
|
|
53940
|
+
stdout.write("Validating... ");
|
|
53941
|
+
const result2 = await (0, validate_api_key_js_1.validateOpenRouterKey)(existingKey, logger);
|
|
53942
|
+
if (result2.valid) {
|
|
53943
|
+
stdout.write("valid!\n");
|
|
53944
|
+
return "healthy";
|
|
53945
|
+
} else {
|
|
53946
|
+
stdout.write(`invalid (${result2.error})
|
|
53947
|
+
`);
|
|
53948
|
+
return "invalid";
|
|
53949
|
+
}
|
|
53950
|
+
}
|
|
53951
|
+
(0, prompts_js_1.printStatus)(ctx, "warning", "OPENROUTER_API_KEY not found");
|
|
53952
|
+
const configureNow = await (0, prompts_js_1.promptConfirm)(ctx, "Configure API key now?", true);
|
|
53953
|
+
if (!configureNow) {
|
|
53954
|
+
stdout.write("\n");
|
|
53955
|
+
(0, prompts_js_1.printStatus)(ctx, "warning", "Persona features will show warnings in the statusline until an API key is configured.");
|
|
53956
|
+
stdout.write("Run 'sidekick setup' again or ask Claude to help configure API keys using /sidekick-config.\n");
|
|
53957
|
+
return "missing";
|
|
53958
|
+
}
|
|
53959
|
+
const keyScope = await (0, prompts_js_1.promptSelect)(ctx, "Where should the API key be stored?", [
|
|
53960
|
+
{ value: "user", label: "User-level (~/.sidekick/.env)", description: "Works in all projects" },
|
|
53961
|
+
{ value: "project", label: "Project-level (.sidekick/.env)", description: "This project only" }
|
|
53962
|
+
]);
|
|
53963
|
+
const apiKey = await (0, prompts_js_1.promptInput)(ctx, "Paste your OpenRouter API key");
|
|
53964
|
+
stdout.write("Validating... ");
|
|
53965
|
+
const result = await (0, validate_api_key_js_1.validateOpenRouterKey)(apiKey, logger);
|
|
53966
|
+
const envPath = keyScope === "user" ? path.join(homeDir, ".sidekick", ".env") : path.join(projectDir, ".sidekick", ".env");
|
|
53967
|
+
if (result.valid) {
|
|
53968
|
+
stdout.write("valid!\n");
|
|
53969
|
+
await writeApiKeyToEnv(envPath, "OPENROUTER_API_KEY", apiKey);
|
|
53970
|
+
(0, prompts_js_1.printStatus)(ctx, "success", `API key saved to ${envPath}`);
|
|
53971
|
+
return "healthy";
|
|
53972
|
+
} else {
|
|
53973
|
+
stdout.write(`invalid (${result.error})
|
|
53974
|
+
`);
|
|
53975
|
+
(0, prompts_js_1.printStatus)(ctx, "warning", "API key validation failed, saving anyway");
|
|
53976
|
+
await writeApiKeyToEnv(envPath, "OPENROUTER_API_KEY", apiKey);
|
|
53977
|
+
return "invalid";
|
|
53978
|
+
}
|
|
53979
|
+
}
|
|
53980
|
+
async function runStep4AutoConfig(wctx) {
|
|
53981
|
+
const { ctx } = wctx;
|
|
53982
|
+
(0, prompts_js_1.printHeader)(ctx, "Step 4: Project Auto-Configuration");
|
|
53983
|
+
const autoConfig = await (0, prompts_js_1.promptSelect)(ctx, "When sidekick runs in a new project for the first time:", [
|
|
53984
|
+
{ value: "auto", label: "Auto-configure using my defaults", description: "Recommended" },
|
|
53985
|
+
{ value: "ask", label: "Ask me each time" },
|
|
53986
|
+
{ value: "manual", label: "Do nothing", description: "Manual setup only" }
|
|
53987
|
+
]);
|
|
53988
|
+
return autoConfig;
|
|
53989
|
+
}
|
|
53990
|
+
async function writeStatusFiles(wctx, state) {
|
|
53991
|
+
const { setupService } = wctx;
|
|
53992
|
+
const { statuslineScope, gitignoreStatus, wantPersonas, apiKeyHealth, autoConfig } = state;
|
|
53993
|
+
const userStatus = {
|
|
53994
|
+
version: 1,
|
|
53995
|
+
lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
53996
|
+
preferences: {
|
|
53997
|
+
autoConfigureProjects: autoConfig === "auto",
|
|
53998
|
+
defaultStatuslineScope: statuslineScope,
|
|
53999
|
+
defaultApiKeyScope: wantPersonas ? "user" : "skip"
|
|
54000
|
+
},
|
|
54001
|
+
statusline: "configured",
|
|
54002
|
+
apiKeys: {
|
|
54003
|
+
OPENROUTER_API_KEY: apiKeyHealth,
|
|
54004
|
+
OPENAI_API_KEY: "not-required"
|
|
54005
|
+
}
|
|
54006
|
+
};
|
|
54007
|
+
await setupService.writeUserStatus(userStatus);
|
|
54008
|
+
const projectStatus = {
|
|
54009
|
+
version: 1,
|
|
54010
|
+
lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
54011
|
+
autoConfigured: false,
|
|
54012
|
+
statusline: statuslineScope === "project" ? "configured" : "user",
|
|
54013
|
+
apiKeys: {
|
|
54014
|
+
OPENROUTER_API_KEY: apiKeyHealth === "healthy" ? "user" : apiKeyHealth,
|
|
54015
|
+
OPENAI_API_KEY: "not-required"
|
|
54016
|
+
},
|
|
54017
|
+
gitignore: gitignoreStatus
|
|
54018
|
+
};
|
|
54019
|
+
await setupService.writeProjectStatus(projectStatus);
|
|
54020
|
+
}
|
|
54021
|
+
function printSummary(wctx, state) {
|
|
54022
|
+
const { ctx } = wctx;
|
|
54023
|
+
const { statuslineScope, gitignoreStatus, wantPersonas, apiKeyHealth, autoConfig } = state;
|
|
54024
|
+
const stdout = ctx.stdout;
|
|
54025
|
+
(0, prompts_js_1.printHeader)(ctx, "Summary");
|
|
54026
|
+
(0, prompts_js_1.printStatus)(ctx, "success", `Statusline: ${statuslineScope === "user" ? "User-level" : "Project-level"}`);
|
|
54027
|
+
(0, prompts_js_1.printStatus)(ctx, gitignoreStatus === "installed" ? "success" : "info", `Gitignore: ${gitignoreStatus === "installed" ? "Configured" : "Skipped"}`);
|
|
54028
|
+
(0, prompts_js_1.printStatus)(ctx, wantPersonas ? "success" : "info", `Personas: ${wantPersonas ? "Enabled" : "Disabled"}`);
|
|
54029
|
+
const apiKeyStatusType = getApiKeyStatusType(apiKeyHealth);
|
|
54030
|
+
(0, prompts_js_1.printStatus)(ctx, apiKeyStatusType, `API Key: ${apiKeyHealth}`);
|
|
54031
|
+
(0, prompts_js_1.printStatus)(ctx, "success", `Auto-configure: ${autoConfig === "auto" ? "Enabled" : "Disabled"}`);
|
|
54032
|
+
stdout.write("\n");
|
|
54033
|
+
stdout.write("Restart Claude Code to see your statusline: claude --continue\n");
|
|
54034
|
+
}
|
|
54035
|
+
async function runWizard(projectDir, logger, stdout, options) {
|
|
54036
|
+
const homeDir = os.homedir();
|
|
54037
|
+
const wctx = {
|
|
54038
|
+
ctx: {
|
|
54039
|
+
stdin: options.stdin ?? process.stdin,
|
|
54040
|
+
stdout
|
|
54041
|
+
},
|
|
54042
|
+
homeDir,
|
|
54043
|
+
projectDir,
|
|
54044
|
+
logger,
|
|
54045
|
+
setupService: new core_1.SetupStatusService(projectDir, { homeDir, logger })
|
|
54046
|
+
};
|
|
54047
|
+
const force = options.force ?? false;
|
|
54048
|
+
if (!force) {
|
|
54049
|
+
printWizardHeader(stdout);
|
|
54050
|
+
}
|
|
54051
|
+
const statuslineScope = force ? "user" : await runStep1Statusline(wctx);
|
|
54052
|
+
const gitignoreStatus = await runStep2Gitignore(wctx, force);
|
|
54053
|
+
const { wantPersonas, apiKeyHealth } = force ? { wantPersonas: true, apiKeyHealth: "not-required" } : await runStep3Personas(wctx);
|
|
54054
|
+
const autoConfig = force ? "auto" : await runStep4AutoConfig(wctx);
|
|
54055
|
+
if (force) {
|
|
54056
|
+
const statuslinePath = path.join(homeDir, ".claude", "settings.json");
|
|
54057
|
+
await configureStatusline(statuslinePath, logger);
|
|
54058
|
+
}
|
|
54059
|
+
const state = { statuslineScope, gitignoreStatus, wantPersonas, apiKeyHealth, autoConfig };
|
|
54060
|
+
await writeStatusFiles(wctx, state);
|
|
54061
|
+
if (!force) {
|
|
54062
|
+
printSummary(wctx, state);
|
|
54063
|
+
} else {
|
|
54064
|
+
stdout.write("Setup complete (force mode):\n");
|
|
54065
|
+
stdout.write(` Statusline: user-level (~/.claude/settings.json)
|
|
54066
|
+
`);
|
|
54067
|
+
stdout.write(` Gitignore: ${gitignoreStatus === "installed" ? "configured" : "skipped"}
|
|
54068
|
+
`);
|
|
54069
|
+
stdout.write(` Personas: enabled (API key not configured)
|
|
54070
|
+
`);
|
|
54071
|
+
stdout.write(` Auto-configure: enabled
|
|
54072
|
+
`);
|
|
54073
|
+
}
|
|
54074
|
+
return { exitCode: 0 };
|
|
54075
|
+
}
|
|
54076
|
+
async function runDoctor(projectDir, logger, stdout) {
|
|
54077
|
+
const homeDir = os.homedir();
|
|
54078
|
+
const setupService = new core_1.SetupStatusService(projectDir, { homeDir, logger });
|
|
54079
|
+
stdout.write("\nSidekick Doctor\n");
|
|
54080
|
+
stdout.write("===============\n\n");
|
|
54081
|
+
const statusline = await setupService.getStatuslineHealth();
|
|
54082
|
+
const gitignore = await (0, core_1.detectGitignoreStatus)(projectDir);
|
|
54083
|
+
const apiKey = await setupService.getEffectiveApiKeyHealth("OPENROUTER_API_KEY");
|
|
54084
|
+
const isHealthy = await setupService.isHealthy();
|
|
54085
|
+
const statuslineIcon = statusline === "configured" ? "\u2713" : "\u26A0";
|
|
54086
|
+
const gitignoreIcon = gitignore === "installed" ? "\u2713" : "\u26A0";
|
|
54087
|
+
const apiKeyIcon = apiKey === "healthy" || apiKey === "not-required" ? "\u2713" : "\u26A0";
|
|
54088
|
+
const overallIcon = isHealthy && gitignore === "installed" ? "\u2713" : "\u26A0";
|
|
54089
|
+
stdout.write(`${statuslineIcon} Statusline: ${statusline}
|
|
54090
|
+
`);
|
|
54091
|
+
stdout.write(`${gitignoreIcon} Gitignore: ${gitignore}
|
|
54092
|
+
`);
|
|
54093
|
+
stdout.write(`${apiKeyIcon} OpenRouter API Key: ${apiKey}
|
|
54094
|
+
`);
|
|
54095
|
+
stdout.write(`${overallIcon} Overall: ${isHealthy && gitignore === "installed" ? "healthy" : "needs attention"}
|
|
54096
|
+
`);
|
|
54097
|
+
if (!isHealthy || gitignore !== "installed") {
|
|
54098
|
+
stdout.write("\nRun 'sidekick setup' to configure.\n");
|
|
54099
|
+
}
|
|
54100
|
+
return { exitCode: isHealthy && gitignore === "installed" ? 0 : 1 };
|
|
54101
|
+
}
|
|
54102
|
+
async function handleSetupCommand(projectDir, logger, stdout, options = {}) {
|
|
54103
|
+
if (options.checkOnly) {
|
|
54104
|
+
return runDoctor(projectDir, logger, stdout);
|
|
54105
|
+
}
|
|
54106
|
+
return runWizard(projectDir, logger, stdout, options);
|
|
54107
|
+
}
|
|
54108
|
+
}
|
|
54109
|
+
});
|
|
54110
|
+
|
|
54111
|
+
// ../sidekick-cli/dist/commands/setup.js
|
|
54112
|
+
var require_setup2 = __commonJS({
|
|
54113
|
+
"../sidekick-cli/dist/commands/setup.js"(exports2) {
|
|
54114
|
+
"use strict";
|
|
54115
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
54116
|
+
exports2.handleSetupCommand = void 0;
|
|
54117
|
+
var index_js_1 = require_setup();
|
|
54118
|
+
Object.defineProperty(exports2, "handleSetupCommand", { enumerable: true, get: function() {
|
|
54119
|
+
return index_js_1.handleSetupCommand;
|
|
54120
|
+
} });
|
|
54121
|
+
}
|
|
54122
|
+
});
|
|
54123
|
+
|
|
53008
54124
|
// ../sidekick-cli/dist/cli.js
|
|
53009
54125
|
var require_cli = __commonJS({
|
|
53010
54126
|
"../sidekick-cli/dist/cli.js"(exports2) {
|
|
@@ -53059,6 +54175,7 @@ var require_cli = __commonJS({
|
|
|
53059
54175
|
var promises_12 = require("node:fs/promises");
|
|
53060
54176
|
var node_stream_1 = require("node:stream");
|
|
53061
54177
|
var yargs_parser_1 = __importDefault2(require_build());
|
|
54178
|
+
var VERSION = true ? "0.0.4-alpha" : "dev";
|
|
53062
54179
|
function isInSandbox() {
|
|
53063
54180
|
return process.env.SANDBOX_RUNTIME === "1";
|
|
53064
54181
|
}
|
|
@@ -53073,11 +54190,12 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
|
|
|
53073
54190
|
var runtime_1 = require_runtime();
|
|
53074
54191
|
function parseArgs(argv) {
|
|
53075
54192
|
const parsed = (0, yargs_parser_1.default)(argv, {
|
|
53076
|
-
boolean: ["wait", "open", "prefer-project", "help", "kill", "force"],
|
|
54193
|
+
boolean: ["wait", "open", "prefer-project", "help", "version", "kill", "force"],
|
|
53077
54194
|
string: ["project-dir", "log-level", "format", "host", "session-id", "type"],
|
|
53078
54195
|
number: ["port", "width"],
|
|
53079
54196
|
alias: {
|
|
53080
|
-
h: "help"
|
|
54197
|
+
h: "help",
|
|
54198
|
+
v: "version"
|
|
53081
54199
|
},
|
|
53082
54200
|
configuration: {
|
|
53083
54201
|
"camel-case-expansion": false
|
|
@@ -53098,6 +54216,7 @@ Example: { "command": "pnpm sidekick daemon status", "dangerouslyDisableSandbox"
|
|
|
53098
54216
|
sessionIdArg: parsed["session-id"],
|
|
53099
54217
|
messageType: parsed.type,
|
|
53100
54218
|
help: Boolean(parsed.help),
|
|
54219
|
+
version: Boolean(parsed.version),
|
|
53101
54220
|
kill: Boolean(parsed.kill),
|
|
53102
54221
|
force: Boolean(parsed.force),
|
|
53103
54222
|
_: parsed._
|
|
@@ -53198,9 +54317,12 @@ Commands:
|
|
|
53198
54317
|
statusline Render the status line (used by hooks)
|
|
53199
54318
|
dev-mode <subcommand> Manage development hooks (enable, disable, status, clean)
|
|
53200
54319
|
ui Launch the web UI
|
|
54320
|
+
setup Run the setup wizard (configure statusline, API keys)
|
|
54321
|
+
doctor Check sidekick health (alias: setup --check)
|
|
53201
54322
|
|
|
53202
54323
|
Global Options:
|
|
53203
54324
|
--help, -h Show this help message
|
|
54325
|
+
--version, -v Show version number
|
|
53204
54326
|
--format=<format> Output format: json or table (command-specific)
|
|
53205
54327
|
--width=<n> Table width in characters (default: 100)
|
|
53206
54328
|
--project-dir=<path> Override project directory
|
|
@@ -53284,7 +54406,9 @@ Run 'sidekick hook --help' for available hooks.
|
|
|
53284
54406
|
return { exitCode: 1, stdout: SANDBOX_ERROR_MESSAGE, stderr: "" };
|
|
53285
54407
|
}
|
|
53286
54408
|
const { handleDaemonCommand } = await Promise.resolve().then(() => __importStar(require_daemon()));
|
|
53287
|
-
const result = await handleDaemonCommand(subcommand, runtime.projectRoot || process.cwd(), runtime.logger, stdout, {
|
|
54409
|
+
const result = await handleDaemonCommand(subcommand, runtime.projectRoot || process.cwd(), runtime.logger, stdout, {
|
|
54410
|
+
wait: parsed.wait
|
|
54411
|
+
});
|
|
53288
54412
|
return { exitCode: result.exitCode, stdout: "", stderr: "" };
|
|
53289
54413
|
}
|
|
53290
54414
|
if (parsed.command === "statusline") {
|
|
@@ -53339,6 +54463,21 @@ Run 'sidekick hook --help' for available hooks.
|
|
|
53339
54463
|
const result = await handleDevModeCommand(subcommand, runtime.projectRoot || process.cwd(), runtime.logger, stdout, { force: Boolean(parsed.force) });
|
|
53340
54464
|
return { exitCode: result.exitCode, stdout: "", stderr: "" };
|
|
53341
54465
|
}
|
|
54466
|
+
if (parsed.command === "setup") {
|
|
54467
|
+
const { handleSetupCommand } = await Promise.resolve().then(() => __importStar(require_setup2()));
|
|
54468
|
+
const result = await handleSetupCommand(runtime.projectRoot || process.cwd(), runtime.logger, stdout, {
|
|
54469
|
+
checkOnly: parsed.help ? false : parsed._?.[1] === "--check",
|
|
54470
|
+
stdin: process.stdin
|
|
54471
|
+
});
|
|
54472
|
+
return { exitCode: result.exitCode, stdout: "", stderr: "" };
|
|
54473
|
+
}
|
|
54474
|
+
if (parsed.command === "doctor") {
|
|
54475
|
+
const { handleSetupCommand } = await Promise.resolve().then(() => __importStar(require_setup2()));
|
|
54476
|
+
const result = await handleSetupCommand(runtime.projectRoot || process.cwd(), runtime.logger, stdout, {
|
|
54477
|
+
checkOnly: true
|
|
54478
|
+
});
|
|
54479
|
+
return { exitCode: result.exitCode, stdout: "", stderr: "" };
|
|
54480
|
+
}
|
|
53342
54481
|
const errorMsg = `Unknown command: ${parsed.command}
|
|
53343
54482
|
Run 'sidekick help' for available commands.
|
|
53344
54483
|
`;
|
|
@@ -53365,6 +54504,16 @@ Run 'sidekick help' for available commands.
|
|
|
53365
54504
|
}
|
|
53366
54505
|
async function runCli(options) {
|
|
53367
54506
|
const stdout = options.stdout ?? new node_stream_1.PassThrough();
|
|
54507
|
+
const quickParsed = (0, yargs_parser_1.default)(options.argv, {
|
|
54508
|
+
boolean: ["version"],
|
|
54509
|
+
alias: { v: "version" }
|
|
54510
|
+
});
|
|
54511
|
+
if (quickParsed.version) {
|
|
54512
|
+
const versionOutput = `${VERSION}
|
|
54513
|
+
`;
|
|
54514
|
+
stdout.write(versionOutput);
|
|
54515
|
+
return { exitCode: 0, stdout: versionOutput, stderr: "" };
|
|
54516
|
+
}
|
|
53368
54517
|
const initResult = initializeRuntime(options);
|
|
53369
54518
|
if (initResult.shouldExit) {
|
|
53370
54519
|
return { exitCode: 0, stdout: "", stderr: "" };
|