@baizor/cc-switch 0.1.0

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.
@@ -0,0 +1,83 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { spawnSync } from "node:child_process";
4
+ import { defaultClaudeSettingsPath } from "./paths.js";
5
+ import { snapshotFromStatusLineInput } from "./telemetry.js";
6
+ import { recordSnapshot, saveState } from "./state.js";
7
+ export function installStatusLineCollector(config, state, settingsPath = defaultClaudeSettingsPath()) {
8
+ const settings = readJsonObject(settingsPath);
9
+ const previous = settings.statusLine;
10
+ const previousCommand = commandFromStatusLine(previous);
11
+ const forward = previousCommand ? Buffer.from(previousCommand, "utf8").toString("base64") : "";
12
+ const cliPath = process.argv[1] || "cc-switch";
13
+ const command = [
14
+ JSON.stringify(process.execPath),
15
+ JSON.stringify(cliPath),
16
+ "collect-status-line",
17
+ "--config",
18
+ JSON.stringify(config.configPath),
19
+ forward ? `--forward ${forward}` : ""
20
+ ]
21
+ .filter(Boolean)
22
+ .join(" ");
23
+ settings.statusLine = {
24
+ type: "command",
25
+ command
26
+ };
27
+ fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
28
+ fs.writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`, "utf8");
29
+ const nextState = {
30
+ ...state,
31
+ statusLine: {
32
+ installed: true,
33
+ settingsPath,
34
+ previousStatusLine: previous,
35
+ installedAt: new Date().toISOString()
36
+ }
37
+ };
38
+ saveState(config.statePath, nextState);
39
+ return nextState;
40
+ }
41
+ export function collectStatusLine(config, state, input, forwardBase64) {
42
+ let nextState = state;
43
+ const activeIndex = state.activeTokenIndex ?? 0;
44
+ const activeToken = config.tokens[activeIndex];
45
+ if (activeToken) {
46
+ const snapshot = snapshotFromStatusLineInput(input, activeToken);
47
+ if (snapshot) {
48
+ nextState = recordSnapshot(state, snapshot);
49
+ saveState(config.statePath, nextState);
50
+ }
51
+ }
52
+ let forwardedOutput = "";
53
+ if (forwardBase64) {
54
+ const command = Buffer.from(forwardBase64, "base64").toString("utf8");
55
+ const result = spawnSync(command, {
56
+ input,
57
+ shell: true,
58
+ encoding: "utf8"
59
+ });
60
+ forwardedOutput = result.stdout || "";
61
+ }
62
+ return { state: nextState, forwardedOutput };
63
+ }
64
+ function readJsonObject(filePath) {
65
+ if (!fs.existsSync(filePath))
66
+ return {};
67
+ const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
68
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
69
+ throw new Error(`${filePath} must contain a JSON object`);
70
+ }
71
+ return parsed;
72
+ }
73
+ function commandFromStatusLine(statusLine) {
74
+ if (!statusLine)
75
+ return undefined;
76
+ if (typeof statusLine === "string")
77
+ return statusLine;
78
+ if (typeof statusLine === "object" && typeof statusLine.command === "string") {
79
+ return statusLine.command;
80
+ }
81
+ return undefined;
82
+ }
83
+ //# sourceMappingURL=statusLine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statusLine.js","sourceRoot":"","sources":["../src/statusLine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { AppConfig, AppState, QuotaSnapshot, TokenView } from "./types.js";
2
+ export interface SwitchDecision {
3
+ shouldSwitch: boolean;
4
+ toIndex: number | null;
5
+ reason: string;
6
+ }
7
+ export declare function decideSwitch(config: AppConfig, state: AppState, now?: Date): SwitchDecision;
8
+ export declare function tokenViews(config: AppConfig, state: AppState, now?: Date): TokenView[];
9
+ export declare function switchToToken(config: AppConfig, state: AppState, toIndex: number, reason: string): AppState;
10
+ export declare function snapshotForIndex(config: AppConfig, state: AppState, index: number): QuotaSnapshot | undefined;
11
+ export declare function isBelowThreshold(config: AppConfig, snapshot: QuotaSnapshot): boolean;
@@ -0,0 +1,137 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+ import { activeEnvPath, activePowerShellEnvPath } from "./paths.js";
6
+ import { etaFromNow, percentUsed, tokenFingerprint } from "./util.js";
7
+ import { recordSwitch, saveState } from "./state.js";
8
+ export function decideSwitch(config, state, now = new Date()) {
9
+ if (!config.tokens.length) {
10
+ return { shouldSwitch: false, toIndex: null, reason: "No subscriptions are configured" };
11
+ }
12
+ const activeIndex = state.activeTokenIndex ?? 0;
13
+ const activeSnapshot = snapshotForIndex(config, state, activeIndex);
14
+ if (!activeSnapshot) {
15
+ return {
16
+ shouldSwitch: false,
17
+ toIndex: activeIndex,
18
+ reason: "Active subscription has no official telemetry snapshot yet"
19
+ };
20
+ }
21
+ const activeLow = isBelowThreshold(config, activeSnapshot);
22
+ if (!activeLow) {
23
+ return { shouldSwitch: false, toIndex: activeIndex, reason: "Active subscription is above thresholds" };
24
+ }
25
+ const knownCandidates = config.tokens
26
+ .map((_, index) => ({ index, snapshot: snapshotForIndex(config, state, index) }))
27
+ .filter((item) => Boolean(item.snapshot))
28
+ .filter((item) => !isBelowThreshold(config, item.snapshot))
29
+ .sort((a, b) => limitingResetMs(a.snapshot, now) - limitingResetMs(b.snapshot, now));
30
+ const knownCandidate = knownCandidates.find((item) => item.index !== activeIndex) || knownCandidates[0];
31
+ if (knownCandidate) {
32
+ return {
33
+ shouldSwitch: knownCandidate.index !== activeIndex,
34
+ toIndex: knownCandidate.index,
35
+ reason: "Active subscription crossed a configured quota threshold"
36
+ };
37
+ }
38
+ const unknownIndex = config.tokens.findIndex((_, index) => index !== activeIndex && !snapshotForIndex(config, state, index));
39
+ if (unknownIndex >= 0) {
40
+ return {
41
+ shouldSwitch: true,
42
+ toIndex: unknownIndex,
43
+ reason: "All known subscriptions are below threshold; using an unknown subscription conservatively"
44
+ };
45
+ }
46
+ return {
47
+ shouldSwitch: false,
48
+ toIndex: activeIndex,
49
+ reason: "All known subscriptions are below threshold"
50
+ };
51
+ }
52
+ export function tokenViews(config, state, now = new Date()) {
53
+ return config.tokens.map((token, index) => {
54
+ const snapshot = snapshotForIndex(config, state, index);
55
+ const fiveLeft = 100 - (snapshot?.fiveHour?.usedPercentage ?? Number.NaN);
56
+ const weeklyLeft = 100 - (snapshot?.weekly?.usedPercentage ?? Number.NaN);
57
+ const low = Number.isFinite(fiveLeft) &&
58
+ Number.isFinite(weeklyLeft) &&
59
+ (fiveLeft < config.fiveHourMinLeftPercent || weeklyLeft < config.weeklyMinLeftPercent);
60
+ const resets = [snapshot?.fiveHour?.resetsAt, snapshot?.weekly?.resetsAt].filter(Boolean);
61
+ const soonestReset = resets.sort((a, b) => new Date(a).getTime() - new Date(b).getTime())[0];
62
+ return {
63
+ index,
64
+ label: config.tokenLabels[index] || `Subscription ${index}`,
65
+ fingerprint: tokenFingerprint(token),
66
+ active: (state.activeTokenIndex ?? 0) === index,
67
+ fiveHourUsed: percentUsed(snapshot?.fiveHour?.usedPercentage),
68
+ weeklyUsed: percentUsed(snapshot?.weekly?.usedPercentage),
69
+ resetEta: etaFromNow(soonestReset, now),
70
+ health: snapshot ? (low ? "low" : "ok") : "unknown",
71
+ lastTelemetry: snapshot ? etaFromNow(snapshot.capturedAt, now) : "never"
72
+ };
73
+ });
74
+ }
75
+ export function switchToToken(config, state, toIndex, reason) {
76
+ if (!Number.isInteger(toIndex) || toIndex < 0 || toIndex >= config.tokens.length) {
77
+ throw new Error(`Invalid token index ${toIndex}`);
78
+ }
79
+ const token = config.tokens[toIndex];
80
+ if (config.switchingMode === "credentials-file") {
81
+ writeCredentialsFile(config, token);
82
+ }
83
+ else {
84
+ writeEnvironmentFiles(token);
85
+ if (process.platform === "win32") {
86
+ spawnSync("setx", ["CLAUDE_CODE_OAUTH_TOKEN", token], { stdio: "ignore" });
87
+ }
88
+ }
89
+ const nextState = recordSwitch(state, {
90
+ fromIndex: state.activeTokenIndex,
91
+ toIndex,
92
+ reason,
93
+ switchedAt: new Date().toISOString()
94
+ });
95
+ saveState(config.statePath, nextState);
96
+ return nextState;
97
+ }
98
+ export function snapshotForIndex(config, state, index) {
99
+ const token = config.tokens[index];
100
+ return token ? state.snapshots[tokenFingerprint(token)] : undefined;
101
+ }
102
+ export function isBelowThreshold(config, snapshot) {
103
+ const fiveLeft = remaining(snapshot.fiveHour?.usedPercentage);
104
+ const weeklyLeft = remaining(snapshot.weekly?.usedPercentage);
105
+ return fiveLeft < config.fiveHourMinLeftPercent || weeklyLeft < config.weeklyMinLeftPercent;
106
+ }
107
+ function remaining(used) {
108
+ return typeof used === "number" ? 100 - used : 100;
109
+ }
110
+ function limitingResetMs(snapshot, now) {
111
+ const resetTimes = [snapshot.fiveHour?.resetsAt, snapshot.weekly?.resetsAt]
112
+ .filter(Boolean)
113
+ .map((value) => new Date(value).getTime())
114
+ .filter((value) => Number.isFinite(value));
115
+ if (!resetTimes.length)
116
+ return Number.MAX_SAFE_INTEGER;
117
+ const future = resetTimes.filter((value) => value >= now.getTime());
118
+ return Math.min(...(future.length ? future : resetTimes));
119
+ }
120
+ function writeEnvironmentFiles(token) {
121
+ const envPath = activeEnvPath();
122
+ const psPath = activePowerShellEnvPath();
123
+ fs.mkdirSync(path.dirname(envPath), { recursive: true });
124
+ fs.writeFileSync(envPath, `export CLAUDE_CODE_OAUTH_TOKEN=${JSON.stringify(token)}\n`, "utf8");
125
+ fs.writeFileSync(psPath, `$env:CLAUDE_CODE_OAUTH_TOKEN = ${JSON.stringify(token)}\n`, "utf8");
126
+ process.env.CLAUDE_CODE_OAUTH_TOKEN = token;
127
+ }
128
+ function writeCredentialsFile(config, token) {
129
+ const credentialsPath = config.credentialsPath || path.join(os.homedir(), ".cc-switch", "experimental-claude-credentials.json");
130
+ fs.mkdirSync(path.dirname(credentialsPath), { recursive: true });
131
+ fs.writeFileSync(credentialsPath, `${JSON.stringify({
132
+ warning: "Experimental cc-switch credentials-file mode. Verify Claude Code compatibility before relying on it.",
133
+ CLAUDE_CODE_OAUTH_TOKEN: token,
134
+ updatedAt: new Date().toISOString()
135
+ }, null, 2)}\n`, "utf8");
136
+ }
137
+ //# sourceMappingURL=switcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switcher.js","sourceRoot":"","sources":["../src/switcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { QuotaSnapshot } from "./types.js";
2
+ export declare function snapshotFromStatusLineInput(input: unknown, token: string, capturedAt?: Date): QuotaSnapshot | null;
@@ -0,0 +1,43 @@
1
+ import { tokenFingerprint } from "./util.js";
2
+ export function snapshotFromStatusLineInput(input, token, capturedAt = new Date()) {
3
+ const payload = typeof input === "string" ? safeJsonParse(input) : input;
4
+ if (!payload || typeof payload !== "object")
5
+ return null;
6
+ const status = payload;
7
+ if (!status.rate_limits)
8
+ return null;
9
+ const fiveHour = normalizeWindow(status.rate_limits.five_hour);
10
+ const weekly = normalizeWindow(status.rate_limits.seven_day);
11
+ if (!fiveHour && !weekly)
12
+ return null;
13
+ return {
14
+ tokenFingerprint: tokenFingerprint(token),
15
+ fiveHour,
16
+ weekly,
17
+ capturedAt: capturedAt.toISOString()
18
+ };
19
+ }
20
+ function normalizeWindow(value) {
21
+ if (!value || typeof value !== "object")
22
+ return undefined;
23
+ const record = value;
24
+ const used = record.used_percentage;
25
+ const resets = record.resets_at;
26
+ const window = {};
27
+ if (typeof used === "number" && Number.isFinite(used)) {
28
+ window.usedPercentage = Math.max(0, Math.min(100, used));
29
+ }
30
+ if (typeof resets === "string" && !Number.isNaN(new Date(resets).getTime())) {
31
+ window.resetsAt = resets;
32
+ }
33
+ return Object.keys(window).length ? window : undefined;
34
+ }
35
+ function safeJsonParse(text) {
36
+ try {
37
+ return JSON.parse(text);
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ //# sourceMappingURL=telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAgB7C,MAAM,UAAU,2BAA2B,CAAC,KAAc,EAAE,KAAa,EAAE,UAAU,GAAG,IAAI,IAAI,EAAE;IAChG,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACzE,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzD,MAAM,MAAM,GAAG,OAAgC,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAErC,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAC7D,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEtC,OAAO;QACL,gBAAgB,EAAE,gBAAgB,CAAC,KAAK,CAAC;QACzC,QAAQ;QACR,MAAM;QACN,UAAU,EAAE,UAAU,CAAC,WAAW,EAAE;KACrC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC1D,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,IAAI,GAAG,MAAM,CAAC,eAAe,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC;IAChC,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAC5E,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC;IAC3B,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACzD,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
package/dist/tui.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { AppConfig } from "./types.js";
2
+ export declare function dashboard(configPath?: string): Promise<void>;
3
+ export declare function configScreen(configPath?: string): Promise<void>;
4
+ export declare function addTokenScreen(configPath?: string): Promise<void>;
5
+ export declare function removeTokenScreen(configPath?: string): Promise<void>;
6
+ export declare function switchScreen(configPath?: string): Promise<void>;
7
+ export declare function renderDashboard(config: AppConfig, state?: import("./types.js").AppState): void;
package/dist/tui.js ADDED
@@ -0,0 +1,300 @@
1
+ import { confirm, input, number, password, select } from "@inquirer/prompts";
2
+ import chalk from "chalk";
3
+ import { addToken, readConfig, removeToken, validateConfig, writeConfig } from "./config.js";
4
+ import { recentLogs } from "./logger.js";
5
+ import { recordServiceStatus, loadState, saveState } from "./state.js";
6
+ import { installService, serviceStatus, uninstallService } from "./service.js";
7
+ import { decideSwitch, switchToToken, tokenViews } from "./switcher.js";
8
+ import { maskToken } from "./util.js";
9
+ export async function dashboard(configPath) {
10
+ let done = false;
11
+ while (!done) {
12
+ const config = readConfig(configPath);
13
+ const state = loadState(config.statePath);
14
+ renderDashboard(config, state);
15
+ const action = await select({
16
+ message: "Action",
17
+ choices: [
18
+ { name: "Config", value: "config" },
19
+ { name: "Add Token", value: "add" },
20
+ { name: "Remove Token", value: "remove" },
21
+ { name: "Switch Now", value: "switch" },
22
+ {
23
+ name: state.serviceStatusCache?.installed ? "Uninstall Service" : "Install Service",
24
+ value: state.serviceStatusCache?.installed ? "uninstall-service" : "install-service"
25
+ },
26
+ { name: "Refresh", value: "refresh" },
27
+ { name: "Logs", value: "logs" },
28
+ { name: "Quit", value: "quit" }
29
+ ]
30
+ });
31
+ if (action === "config")
32
+ await configScreen(configPath);
33
+ if (action === "add")
34
+ await addTokenScreen(configPath);
35
+ if (action === "remove")
36
+ await removeTokenScreen(configPath);
37
+ if (action === "switch")
38
+ await switchScreen(configPath);
39
+ if (action === "install-service") {
40
+ const next = recordServiceStatus(state, installService(config));
41
+ saveState(config.statePath, next);
42
+ }
43
+ if (action === "uninstall-service") {
44
+ const next = recordServiceStatus(state, uninstallService());
45
+ saveState(config.statePath, next);
46
+ }
47
+ if (action === "logs") {
48
+ console.log(`\n${recentLogs()}\n`);
49
+ await input({ message: "Press Enter to continue" });
50
+ }
51
+ done = action === "quit";
52
+ }
53
+ }
54
+ export async function configScreen(configPath) {
55
+ let config = readConfig(configPath);
56
+ let dirty = false;
57
+ let done = false;
58
+ while (!done) {
59
+ console.log(`\n${chalk.bold("cc-switch config")}${dirty ? chalk.yellow(" *unsaved") : ""}`);
60
+ console.log(`Config: ${config.configPath}`);
61
+ const action = await select({
62
+ message: "Edit setting",
63
+ choices: [
64
+ { name: `Poll interval: ${config.pollSeconds}s`, value: "poll" },
65
+ { name: `5-hour min remaining: ${config.fiveHourMinLeftPercent}%`, value: "five" },
66
+ { name: `Weekly min remaining: ${config.weeklyMinLeftPercent}%`, value: "weekly" },
67
+ { name: `Switching mode: ${config.switchingMode}`, value: "mode" },
68
+ { name: `Log level: ${config.logLevel}`, value: "log" },
69
+ { name: `Service autostart: ${config.serviceAutostart}`, value: "autostart" },
70
+ { name: `State path: ${config.statePath}`, value: "state-path" },
71
+ { name: `Credentials path: ${config.credentialsPath || "(default experimental path)"}`, value: "credentials-path" },
72
+ { name: "Token labels", value: "labels" },
73
+ { name: "Token order", value: "order" },
74
+ { name: "Add subscription", value: "add" },
75
+ { name: "Remove subscription", value: "remove" },
76
+ { name: "Save", value: "save" },
77
+ { name: "Reset to current file", value: "reset" },
78
+ { name: "Cancel", value: "cancel" }
79
+ ]
80
+ });
81
+ if (action === "poll") {
82
+ config = {
83
+ ...config,
84
+ pollSeconds: requireNumber(await number({ message: "Poll seconds", default: config.pollSeconds, min: 5 }))
85
+ };
86
+ dirty = true;
87
+ }
88
+ else if (action === "five") {
89
+ config = {
90
+ ...config,
91
+ fiveHourMinLeftPercent: requireNumber(await number({
92
+ message: "Minimum remaining 5-hour quota percent",
93
+ default: config.fiveHourMinLeftPercent,
94
+ min: 0,
95
+ max: 100
96
+ }))
97
+ };
98
+ dirty = true;
99
+ }
100
+ else if (action === "weekly") {
101
+ config = {
102
+ ...config,
103
+ weeklyMinLeftPercent: requireNumber(await number({
104
+ message: "Minimum remaining weekly quota percent",
105
+ default: config.weeklyMinLeftPercent,
106
+ min: 0,
107
+ max: 100
108
+ }))
109
+ };
110
+ dirty = true;
111
+ }
112
+ else if (action === "mode") {
113
+ config = {
114
+ ...config,
115
+ switchingMode: await select({
116
+ message: "Switching mode",
117
+ choices: [
118
+ { name: "env", value: "env" },
119
+ { name: "credentials-file (experimental)", value: "credentials-file" }
120
+ ]
121
+ })
122
+ };
123
+ dirty = true;
124
+ }
125
+ else if (action === "log") {
126
+ config = {
127
+ ...config,
128
+ logLevel: await select({
129
+ message: "Log level",
130
+ choices: [
131
+ { name: "debug", value: "debug" },
132
+ { name: "info", value: "info" },
133
+ { name: "warn", value: "warn" },
134
+ { name: "error", value: "error" }
135
+ ]
136
+ })
137
+ };
138
+ dirty = true;
139
+ }
140
+ else if (action === "autostart") {
141
+ config = { ...config, serviceAutostart: await confirm({ message: "Start service automatically?", default: true }) };
142
+ dirty = true;
143
+ }
144
+ else if (action === "state-path") {
145
+ config = {
146
+ ...config,
147
+ statePath: await input({ message: "State file path", default: config.statePath, required: true })
148
+ };
149
+ dirty = true;
150
+ }
151
+ else if (action === "credentials-path") {
152
+ const value = await input({
153
+ message: "Experimental credentials file path",
154
+ default: config.credentialsPath || ""
155
+ });
156
+ config = { ...config, credentialsPath: value.trim() || undefined };
157
+ dirty = true;
158
+ }
159
+ else if (action === "labels") {
160
+ const tokenLabels = [...config.tokenLabels];
161
+ for (let index = 0; index < config.tokens.length; index += 1) {
162
+ tokenLabels[index] = await input({
163
+ message: `Label for ${index} ${maskToken(config.tokens[index])}`,
164
+ default: tokenLabels[index] || `Subscription ${index}`
165
+ });
166
+ }
167
+ config = { ...config, tokenLabels };
168
+ dirty = true;
169
+ }
170
+ else if (action === "order") {
171
+ if (config.tokens.length < 2) {
172
+ console.log("At least two subscriptions are required to reorder.");
173
+ }
174
+ else {
175
+ const from = await pickTokenIndex(config, "Move which subscription?");
176
+ const to = requireNumber(await number({
177
+ message: `New zero-based index for ${from}`,
178
+ default: from,
179
+ min: 0,
180
+ max: config.tokens.length - 1
181
+ }));
182
+ config = moveToken(config, from, to);
183
+ dirty = true;
184
+ }
185
+ }
186
+ else if (action === "add") {
187
+ const token = await password({ message: "Claude Code OAuth token", mask: "*" });
188
+ const label = await input({ message: "Label", default: `Subscription ${config.tokens.length}` });
189
+ config = addToken(config, token, label);
190
+ dirty = true;
191
+ }
192
+ else if (action === "remove") {
193
+ if (!config.tokens.length) {
194
+ console.log("No subscriptions configured.");
195
+ }
196
+ else {
197
+ const index = await pickTokenIndex(config, "Remove which subscription?");
198
+ const ok = await confirm({ message: `Remove ${maskToken(config.tokens[index])}?`, default: false });
199
+ if (ok) {
200
+ config = removeToken(config, index);
201
+ dirty = true;
202
+ }
203
+ }
204
+ }
205
+ else if (action === "save") {
206
+ validateConfig(config);
207
+ writeConfig(config);
208
+ dirty = false;
209
+ done = true;
210
+ }
211
+ else if (action === "reset") {
212
+ config = readConfig(configPath);
213
+ dirty = false;
214
+ }
215
+ else if (action === "cancel") {
216
+ if (!dirty || (await confirm({ message: "Discard unsaved changes?", default: false }))) {
217
+ done = true;
218
+ }
219
+ }
220
+ }
221
+ }
222
+ export async function addTokenScreen(configPath) {
223
+ const config = readConfig(configPath);
224
+ const token = await password({ message: "Claude Code OAuth token", mask: "*" });
225
+ const label = await input({ message: "Label", default: `Subscription ${config.tokens.length}` });
226
+ writeConfig(addToken(config, token, label));
227
+ }
228
+ export async function removeTokenScreen(configPath) {
229
+ const config = readConfig(configPath);
230
+ if (!config.tokens.length) {
231
+ console.log("No subscriptions configured.");
232
+ return;
233
+ }
234
+ const index = await pickTokenIndex(config, "Remove which subscription?");
235
+ const ok = await confirm({ message: `Remove ${maskToken(config.tokens[index])}?`, default: false });
236
+ if (ok)
237
+ writeConfig(removeToken(config, index));
238
+ }
239
+ export async function switchScreen(configPath) {
240
+ const config = readConfig(configPath);
241
+ const state = loadState(config.statePath);
242
+ const index = await pickTokenIndex(config, "Switch to which subscription?");
243
+ switchToToken(config, state, index, "Manual switch from dashboard");
244
+ }
245
+ export function renderDashboard(config, state = loadState(config.statePath)) {
246
+ console.clear();
247
+ console.log(chalk.bold("cc-switch"));
248
+ console.log(`Config: ${config.configPath}`);
249
+ console.log(`State: ${config.statePath}`);
250
+ console.table(tokenViews(config, state).map((view) => ({
251
+ idx: view.index,
252
+ active: view.active ? "*" : "",
253
+ label: view.label,
254
+ fingerprint: view.fingerprint,
255
+ "5h used": view.fiveHourUsed,
256
+ "7d used": view.weeklyUsed,
257
+ reset: view.resetEta,
258
+ health: view.health,
259
+ telemetry: view.lastTelemetry
260
+ })));
261
+ const service = state.serviceStatusCache || serviceStatus();
262
+ console.log(`Service: ${service.installed ? "installed" : "not installed"} / ${service.running ? "running" : "stopped"}`);
263
+ const decision = decideSwitch(config, state);
264
+ console.log(`Decision: ${decision.reason}`);
265
+ const history = state.switchHistory.slice(0, 5);
266
+ if (history.length) {
267
+ console.log("\nRecent switches:");
268
+ for (const entry of history) {
269
+ console.log(`- ${entry.switchedAt}: ${entry.fromIndex ?? "none"} -> ${entry.toIndex} (${entry.reason})`);
270
+ }
271
+ }
272
+ }
273
+ async function pickTokenIndex(config, message) {
274
+ return select({
275
+ message,
276
+ choices: config.tokens.map((token, index) => ({
277
+ name: `${index}: ${config.tokenLabels[index] || `Subscription ${index}`} ${maskToken(token)}`,
278
+ value: index
279
+ }))
280
+ });
281
+ }
282
+ function requireNumber(value) {
283
+ if (typeof value !== "number" || !Number.isFinite(value)) {
284
+ throw new Error("A numeric value is required");
285
+ }
286
+ return value;
287
+ }
288
+ function moveToken(config, from, to) {
289
+ const tokens = [...config.tokens];
290
+ const labels = [...config.tokenLabels];
291
+ const [token] = tokens.splice(from, 1);
292
+ const [label] = labels.splice(from, 1);
293
+ if (!token)
294
+ throw new Error(`Invalid token index ${from}`);
295
+ tokens.splice(to, 0, token);
296
+ if (label !== undefined)
297
+ labels.splice(to, 0, label);
298
+ return { ...config, tokens, tokenLabels: labels };
299
+ }
300
+ //# sourceMappingURL=tui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"}