cc-usage-bar 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,215 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SettingsError = exports.FETCH_BIN = exports.BACKUP_PREFIX = exports.SETTINGS_PATH = exports.CLAUDE_DIR = void 0;
37
+ exports.claudeDirExists = claudeDirExists;
38
+ exports.readSettings = readSettings;
39
+ exports.writeSettings = writeSettings;
40
+ exports.backupSettings = backupSettings;
41
+ exports.findBackups = findBackups;
42
+ exports.findLatestBackup = findLatestBackup;
43
+ exports.isInstalled = isInstalled;
44
+ exports.applyInstall = applyInstall;
45
+ exports.applyUninstallSurgical = applyUninstallSurgical;
46
+ exports.restoreFromBackup = restoreFromBackup;
47
+ exports.deleteBackups = deleteBackups;
48
+ const fs = __importStar(require("node:fs"));
49
+ const os = __importStar(require("node:os"));
50
+ const path = __importStar(require("node:path"));
51
+ exports.CLAUDE_DIR = path.join(os.homedir(), '.claude');
52
+ exports.SETTINGS_PATH = path.join(exports.CLAUDE_DIR, 'settings.json');
53
+ exports.BACKUP_PREFIX = 'settings.json.backup-cc-usage-';
54
+ exports.FETCH_BIN = 'cc-usage-fetch';
55
+ class SettingsError extends Error {
56
+ hint;
57
+ constructor(message, hint) {
58
+ super(message);
59
+ this.hint = hint;
60
+ }
61
+ }
62
+ exports.SettingsError = SettingsError;
63
+ function claudeDirExists() {
64
+ return fs.existsSync(exports.CLAUDE_DIR);
65
+ }
66
+ function readSettings() {
67
+ if (!fs.existsSync(exports.SETTINGS_PATH))
68
+ return {};
69
+ let raw;
70
+ try {
71
+ raw = fs.readFileSync(exports.SETTINGS_PATH, 'utf8');
72
+ }
73
+ catch {
74
+ throw new SettingsError(`Cannot read ${exports.SETTINGS_PATH}`, 'check file permissions');
75
+ }
76
+ if (!raw.trim())
77
+ return {};
78
+ try {
79
+ return JSON.parse(raw);
80
+ }
81
+ catch {
82
+ throw new SettingsError('Existing settings.json is not valid JSON', 'fix the file manually before running install');
83
+ }
84
+ }
85
+ function writeSettings(s) {
86
+ fs.mkdirSync(exports.CLAUDE_DIR, { recursive: true });
87
+ fs.writeFileSync(exports.SETTINGS_PATH, JSON.stringify(s, null, 2) + '\n');
88
+ }
89
+ function backupSettings() {
90
+ if (!fs.existsSync(exports.SETTINGS_PATH))
91
+ return null;
92
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
93
+ const backupPath = path.join(exports.CLAUDE_DIR, `${exports.BACKUP_PREFIX}${ts}`);
94
+ fs.copyFileSync(exports.SETTINGS_PATH, backupPath);
95
+ return backupPath;
96
+ }
97
+ function findBackups() {
98
+ if (!fs.existsSync(exports.CLAUDE_DIR))
99
+ return [];
100
+ return fs
101
+ .readdirSync(exports.CLAUDE_DIR)
102
+ .filter((f) => f.startsWith(exports.BACKUP_PREFIX))
103
+ .map((f) => path.join(exports.CLAUDE_DIR, f))
104
+ .sort();
105
+ }
106
+ function findLatestBackup() {
107
+ const all = findBackups();
108
+ return all.length ? all[all.length - 1] : null;
109
+ }
110
+ function isInstalled(s) {
111
+ return !!s.statusLine?._ccUsageInstalled;
112
+ }
113
+ function unwrapPrior(existing) {
114
+ if (!existing?._ccUsageInstalled)
115
+ return existing;
116
+ if (existing._ccUsageOriginal !== undefined) {
117
+ const restored = { ...existing, command: existing._ccUsageOriginal };
118
+ delete restored._ccUsageInstalled;
119
+ delete restored._ccUsageOriginal;
120
+ return restored;
121
+ }
122
+ return undefined;
123
+ }
124
+ function shellQuote(s) {
125
+ return `'${s.replace(/'/g, `'\\''`)}'`;
126
+ }
127
+ function buildFetchCommand(opts) {
128
+ const parts = [exports.FETCH_BIN];
129
+ if (opts.format)
130
+ parts.push(`--format=${opts.format}`);
131
+ if (typeof opts.barWidth === 'number')
132
+ parts.push(`--bar-width=${opts.barWidth}`);
133
+ if (opts.barSpec)
134
+ parts.push(`--bar-spec=${shellQuote(opts.barSpec)}`);
135
+ return parts.join(' ');
136
+ }
137
+ function applyInstall(s, opts = {}) {
138
+ const next = { ...s };
139
+ const baseExisting = unwrapPrior(next.statusLine);
140
+ const fetchCmd = buildFetchCommand(opts);
141
+ if (!baseExisting || !baseExisting.command) {
142
+ next.statusLine = {
143
+ ...(baseExisting ?? {}),
144
+ type: baseExisting?.type ?? 'command',
145
+ command: fetchCmd,
146
+ refreshInterval: baseExisting?.refreshInterval ?? 30,
147
+ _ccUsageInstalled: true,
148
+ };
149
+ return next;
150
+ }
151
+ const original = baseExisting.command;
152
+ const escaped = original.replace(/'/g, `'\\''`);
153
+ const escapedFetchCmd = fetchCmd.replace(/'/g, `'\\''`);
154
+ const wrapped = `sh -c 'printf "%s " "$(${escaped})"; ${escapedFetchCmd}'`;
155
+ next.statusLine = {
156
+ ...baseExisting,
157
+ command: wrapped,
158
+ refreshInterval: baseExisting.refreshInterval ?? 30,
159
+ _ccUsageInstalled: true,
160
+ _ccUsageOriginal: original,
161
+ };
162
+ return next;
163
+ }
164
+ function applyUninstallSurgical(s) {
165
+ if (!s.statusLine?.command)
166
+ return s;
167
+ const cmd = s.statusLine.command;
168
+ if (!cmd.includes(exports.FETCH_BIN))
169
+ return s;
170
+ const currentWrapMatch = cmd.match(/^sh -c 'printf "%s " "\$\((.*)\)"; cc-usage-fetch.*'$/s);
171
+ if (currentWrapMatch) {
172
+ const inner = currentWrapMatch[1].replace(/'\\''/g, "'");
173
+ const next = { ...s };
174
+ const sl = { ...s.statusLine, command: inner };
175
+ delete sl._ccUsageInstalled;
176
+ delete sl._ccUsageOriginal;
177
+ next.statusLine = sl;
178
+ return next;
179
+ }
180
+ const wrapMatch = cmd.match(/^sh -c '(.*); (?:echo -n|printf) " "; cc-usage-fetch[^']*'$/s);
181
+ if (wrapMatch) {
182
+ const inner = wrapMatch[1].replace(/'\\''/g, "'");
183
+ const next = { ...s };
184
+ const sl = { ...s.statusLine, command: inner };
185
+ delete sl._ccUsageInstalled;
186
+ delete sl._ccUsageOriginal;
187
+ next.statusLine = sl;
188
+ return next;
189
+ }
190
+ const trimmed = cmd.trim();
191
+ if (trimmed === exports.FETCH_BIN || trimmed.startsWith(exports.FETCH_BIN + ' ')) {
192
+ const next = { ...s };
193
+ delete next.statusLine;
194
+ return next;
195
+ }
196
+ return s;
197
+ }
198
+ function restoreFromBackup(backupPath) {
199
+ const raw = fs.readFileSync(backupPath, 'utf8');
200
+ const parsed = JSON.parse(raw);
201
+ writeSettings(parsed);
202
+ }
203
+ function deleteBackups() {
204
+ const backups = findBackups();
205
+ let count = 0;
206
+ for (const b of backups) {
207
+ try {
208
+ fs.unlinkSync(b);
209
+ count++;
210
+ }
211
+ catch {
212
+ }
213
+ }
214
+ return count;
215
+ }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getToken = getToken;
37
+ const node_child_process_1 = require("node:child_process");
38
+ const fs = __importStar(require("node:fs"));
39
+ const os = __importStar(require("node:os"));
40
+ const path = __importStar(require("node:path"));
41
+ function extractToken(raw) {
42
+ const trimmed = raw.trim();
43
+ if (!trimmed)
44
+ return null;
45
+ try {
46
+ const parsed = JSON.parse(trimmed);
47
+ return parsed.claudeAiOauth?.accessToken ?? null;
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ function tryKeychain() {
54
+ if (process.platform !== 'darwin')
55
+ return null;
56
+ try {
57
+ const out = (0, node_child_process_1.execFileSync)('security', ['find-generic-password', '-s', 'Claude Code-credentials', '-w'], { stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000, encoding: 'utf8' });
58
+ return extractToken(out);
59
+ }
60
+ catch {
61
+ return null;
62
+ }
63
+ }
64
+ function tryFile() {
65
+ const credPath = path.join(os.homedir(), '.claude', '.credentials.json');
66
+ try {
67
+ return extractToken(fs.readFileSync(credPath, 'utf8'));
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ function getToken() {
74
+ const fromKeychain = tryKeychain();
75
+ if (fromKeychain)
76
+ return { token: fromKeychain, source: 'keychain' };
77
+ const fromFile = tryFile();
78
+ if (fromFile)
79
+ return { token: fromFile, source: 'file' };
80
+ return {
81
+ token: null,
82
+ source: 'none',
83
+ error: 'No Claude Code credentials found. Run `claude` to log in first.',
84
+ };
85
+ }
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "cc-usage-bar",
3
+ "version": "0.1.0",
4
+ "description": "Show your Claude Code subscription usage (5h / 7d, or balance) in the statusline. Supports Anthropic, Kimi, GLM, MiniMax, DeepSeek, StepFun, SiliconFlow, OpenRouter, Novita.",
5
+ "keywords": [
6
+ "claude",
7
+ "claude-code",
8
+ "statusline",
9
+ "usage",
10
+ "quota",
11
+ "anthropic",
12
+ "kimi",
13
+ "glm",
14
+ "zhipu",
15
+ "minimax",
16
+ "deepseek",
17
+ "openrouter",
18
+ "siliconflow",
19
+ "novita",
20
+ "stepfun"
21
+ ],
22
+ "license": "MIT",
23
+ "author": "ty861506831@gmail.com",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/TuYv/cc-usage-bar.git"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/TuYv/cc-usage-bar/issues"
30
+ },
31
+ "homepage": "https://github.com/TuYv/cc-usage-bar#readme",
32
+ "bin": {
33
+ "cc-usage-bar": "bin/cc-usage-statusline.js",
34
+ "cc-usage-statusline": "bin/cc-usage-statusline.js",
35
+ "cc-usage-fetch": "bin/cc-usage-fetch.js"
36
+ },
37
+ "files": [
38
+ "dist/src",
39
+ "bin",
40
+ "README.md",
41
+ "README.zh-CN.md",
42
+ "LICENSE"
43
+ ],
44
+ "engines": {
45
+ "node": ">=18"
46
+ },
47
+ "scripts": {
48
+ "build": "tsc",
49
+ "clean": "rm -rf dist",
50
+ "test": "node --test 'dist/test/**/*.test.js'",
51
+ "prepublishOnly": "npm run clean && npm run build && npm test"
52
+ },
53
+ "dependencies": {
54
+ "commander": "^12.1.0"
55
+ },
56
+ "devDependencies": {
57
+ "@types/node": "^20.14.0",
58
+ "typescript": "^5.5.0"
59
+ }
60
+ }