@jukanntenn/glm-plan-usage 0.0.2
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/README.md +81 -0
- package/bin/glm-plan-usage.js +114 -0
- package/package.json +38 -0
- package/scripts/postinstall.js +181 -0
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# @jukanntenn/glm-plan-usage
|
|
2
|
+
|
|
3
|
+
GLM Plan Usage - StatusLine plugin for Claude Code
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @jukanntenn/glm-plan-usage
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For users experiencing network issues, use npm mirror for faster installation:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @jukanntenn/glm-plan-usage --registry https://registry.npmmirror.com
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- 📊 **Monitor**: Display GLM (ZHIPU/ZAI) coding plan usage statistics
|
|
20
|
+
- 🌍 **Cross-platform**: Works on Windows, macOS, and Linux
|
|
21
|
+
- 📦 **Easy installation**: One command via npm
|
|
22
|
+
- 🎨 **Beautiful**: Color-coded warning levels based on usage percentage
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
Add to your Claude Code `settings.json`:
|
|
27
|
+
|
|
28
|
+
**Linux/macOS:**
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"statusLine": {
|
|
33
|
+
"type": "command",
|
|
34
|
+
"command": "~/.claude/glm-plan-usage/glm-plan-usage",
|
|
35
|
+
"padding": 0
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Windows:**
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"statusLine": {
|
|
45
|
+
"type": "command",
|
|
46
|
+
"command": "%USERPROFILE%\\.claude\\glm-plan-usage\\glm-plan-usage.exe",
|
|
47
|
+
"padding": 0
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Environment Variables
|
|
53
|
+
|
|
54
|
+
**Note:** These variables are typically already configured in your Claude Code `settings.json`. If not, you can set them manually:
|
|
55
|
+
|
|
56
|
+
**Linux/macOS:**
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
export ANTHROPIC_AUTH_TOKEN="your-token-here"
|
|
60
|
+
export ANTHROPIC_BASE_URL="https://open.bigmodel.cn/api/anthropic"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Windows (Command Prompt):**
|
|
64
|
+
|
|
65
|
+
```cmd
|
|
66
|
+
set ANTHROPIC_AUTH_TOKEN=your-token-here
|
|
67
|
+
set ANTHROPIC_BASE_URL=https://open.bigmodel.cn/api/anthropic
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Windows (PowerShell):**
|
|
71
|
+
|
|
72
|
+
```powershell
|
|
73
|
+
$env:ANTHROPIC_AUTH_TOKEN="your-token-here"
|
|
74
|
+
$env:ANTHROPIC_BASE_URL="https://open.bigmodel.cn/api/anthropic"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## More Information
|
|
78
|
+
|
|
79
|
+
- GitHub: https://github.com/jukanntenn/glm-plan-usage
|
|
80
|
+
- Issues: https://github.com/jukanntenn/glm-plan-usage/issues
|
|
81
|
+
- License: MIT
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { spawnSync } = require('child_process');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
// 1. Priority: Use ~/.claude/glm-plan-usage/glm-plan-usage if exists
|
|
8
|
+
const claudePath = path.join(
|
|
9
|
+
os.homedir(),
|
|
10
|
+
'.claude',
|
|
11
|
+
'glm-plan-usage',
|
|
12
|
+
process.platform === 'win32' ? 'glm-plan-usage.exe' : 'glm-plan-usage'
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
if (fs.existsSync(claudePath)) {
|
|
16
|
+
const result = spawnSync(claudePath, process.argv.slice(2), {
|
|
17
|
+
stdio: 'inherit',
|
|
18
|
+
shell: false
|
|
19
|
+
});
|
|
20
|
+
process.exit(result.status || 0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 2. Fallback: Use npm package binary
|
|
24
|
+
const platform = process.platform;
|
|
25
|
+
const arch = process.arch;
|
|
26
|
+
|
|
27
|
+
// Handle special cases
|
|
28
|
+
let platformKey = `${platform}-${arch}`;
|
|
29
|
+
if (platform === 'linux') {
|
|
30
|
+
// Detect libc type and version
|
|
31
|
+
function getLibcInfo() {
|
|
32
|
+
try {
|
|
33
|
+
const { execSync } = require('child_process');
|
|
34
|
+
const lddOutput = execSync('ldd --version 2>/dev/null || echo ""', {
|
|
35
|
+
encoding: 'utf8',
|
|
36
|
+
timeout: 1000
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Check for musl explicitly
|
|
40
|
+
if (lddOutput.includes('musl')) {
|
|
41
|
+
return { type: 'musl' };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Parse glibc version: "ldd (GNU libc) 2.35" format
|
|
45
|
+
const match = lddOutput.match(/(?:GNU libc|GLIBC).*?(\d+)\.(\d+)/);
|
|
46
|
+
if (match) {
|
|
47
|
+
const major = parseInt(match[1]);
|
|
48
|
+
const minor = parseInt(match[2]);
|
|
49
|
+
return { type: 'glibc', major, minor };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// If we can't detect, default to musl for safety (more portable)
|
|
53
|
+
return { type: 'musl' };
|
|
54
|
+
} catch (e) {
|
|
55
|
+
// If detection fails, default to musl (more portable)
|
|
56
|
+
return { type: 'musl' };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const libcInfo = getLibcInfo();
|
|
61
|
+
|
|
62
|
+
if (arch === 'arm64') {
|
|
63
|
+
// ARM64 Linux: choose based on libc type and version
|
|
64
|
+
if (libcInfo.type === 'musl' ||
|
|
65
|
+
(libcInfo.type === 'glibc' && (libcInfo.major < 2 || (libcInfo.major === 2 && libcInfo.minor < 35)))) {
|
|
66
|
+
platformKey = 'linux-arm64-musl';
|
|
67
|
+
} else {
|
|
68
|
+
platformKey = 'linux-arm64';
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
// x64 Linux: choose based on libc type and version
|
|
72
|
+
if (libcInfo.type === 'musl' ||
|
|
73
|
+
(libcInfo.type === 'glibc' && (libcInfo.major < 2 || (libcInfo.major === 2 && libcInfo.minor < 35)))) {
|
|
74
|
+
platformKey = 'linux-x64-musl';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const packageMap = {
|
|
80
|
+
'darwin-x64': '@jukanntenn/glm-plan-usage-darwin-x64',
|
|
81
|
+
'darwin-arm64': '@jukanntenn/glm-plan-usage-darwin-arm64',
|
|
82
|
+
'linux-x64': '@jukanntenn/glm-plan-usage-linux-x64',
|
|
83
|
+
'linux-x64-musl': '@jukanntenn/glm-plan-usage-linux-x64-musl',
|
|
84
|
+
'linux-arm64': '@jukanntenn/glm-plan-usage-linux-arm64',
|
|
85
|
+
'linux-arm64-musl': '@jukanntenn/glm-plan-usage-linux-arm64-musl',
|
|
86
|
+
'win32-x64': '@jukanntenn/glm-plan-usage-win32-x64',
|
|
87
|
+
'win32-ia32': '@jukanntenn/glm-plan-usage-win32-x64', // Use 64-bit for 32-bit systems
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const packageName = packageMap[platformKey];
|
|
91
|
+
if (!packageName) {
|
|
92
|
+
console.error(`Error: Unsupported platform ${platformKey}`);
|
|
93
|
+
console.error('Supported platforms: darwin (x64/arm64), linux (x64/arm64), win32 (x64)');
|
|
94
|
+
console.error('Please visit https://github.com/jukanntenn/glm-plan-usage for manual installation');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const binaryName = platform === 'win32' ? 'glm-plan-usage.exe' : 'glm-plan-usage';
|
|
99
|
+
const binaryPath = path.join(__dirname, '..', 'node_modules', packageName, binaryName);
|
|
100
|
+
|
|
101
|
+
if (!fs.existsSync(binaryPath)) {
|
|
102
|
+
console.error(`Error: Binary not found at ${binaryPath}`);
|
|
103
|
+
console.error('This might indicate a failed installation or unsupported platform.');
|
|
104
|
+
console.error('Please try reinstalling: npm install -g @jukanntenn/glm-plan-usage');
|
|
105
|
+
console.error(`Expected package: ${packageName}`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const result = spawnSync(binaryPath, process.argv.slice(2), {
|
|
110
|
+
stdio: 'inherit',
|
|
111
|
+
shell: false
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
process.exit(result.status || 0);
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jukanntenn/glm-plan-usage",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "GLM Plan Usage - StatusLine plugin for Claude Code",
|
|
5
|
+
"bin": {
|
|
6
|
+
"glm-plan-usage": "bin/glm-plan-usage.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"postinstall": "node scripts/postinstall.js"
|
|
10
|
+
},
|
|
11
|
+
"optionalDependencies": {
|
|
12
|
+
"@jukanntenn/glm-plan-usage-darwin-x64": "0.0.2",
|
|
13
|
+
"@jukanntenn/glm-plan-usage-darwin-arm64": "0.0.2",
|
|
14
|
+
"@jukanntenn/glm-plan-usage-linux-x64": "0.0.2",
|
|
15
|
+
"@jukanntenn/glm-plan-usage-linux-x64-musl": "0.0.2",
|
|
16
|
+
"@jukanntenn/glm-plan-usage-linux-arm64": "0.0.2",
|
|
17
|
+
"@jukanntenn/glm-plan-usage-linux-arm64-musl": "0.0.2",
|
|
18
|
+
"@jukanntenn/glm-plan-usage-win32-x64": "0.0.2"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/jukanntenn/glm-plan-usage.git"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"claude",
|
|
26
|
+
"statusline",
|
|
27
|
+
"claude-code",
|
|
28
|
+
"rust",
|
|
29
|
+
"cli",
|
|
30
|
+
"glm",
|
|
31
|
+
"zhipu"
|
|
32
|
+
],
|
|
33
|
+
"author": "Alice",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=14.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
// Silent mode detection
|
|
6
|
+
const silent = process.env.npm_config_loglevel === 'silent' ||
|
|
7
|
+
process.env.GLM_PLAN_USAGE_SKIP_POSTINSTALL === '1';
|
|
8
|
+
|
|
9
|
+
if (!silent) {
|
|
10
|
+
console.log('🚀 Setting up GLM Plan Usage for Claude Code...');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const platform = process.platform;
|
|
15
|
+
const arch = process.arch;
|
|
16
|
+
const homeDir = os.homedir();
|
|
17
|
+
const claudeDir = path.join(homeDir, '.claude', 'glm-plan-usage');
|
|
18
|
+
|
|
19
|
+
// Create directory
|
|
20
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
21
|
+
|
|
22
|
+
// Determine platform key
|
|
23
|
+
let platformKey = `${platform}-${arch}`;
|
|
24
|
+
if (platform === 'linux') {
|
|
25
|
+
// Detect libc type and version
|
|
26
|
+
function getLibcInfo() {
|
|
27
|
+
try {
|
|
28
|
+
const { execSync } = require('child_process');
|
|
29
|
+
const lddOutput = execSync('ldd --version 2>/dev/null || echo ""', {
|
|
30
|
+
encoding: 'utf8',
|
|
31
|
+
timeout: 1000
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Check for musl explicitly
|
|
35
|
+
if (lddOutput.includes('musl')) {
|
|
36
|
+
return { type: 'musl' };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Parse glibc version: "ldd (GNU libc) 2.35" format
|
|
40
|
+
const match = lddOutput.match(/(?:GNU libc|GLIBC).*?(\d+)\.(\d+)/);
|
|
41
|
+
if (match) {
|
|
42
|
+
const major = parseInt(match[1]);
|
|
43
|
+
const minor = parseInt(match[2]);
|
|
44
|
+
return { type: 'glibc', major, minor };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// If we can't detect, default to musl for safety (more portable)
|
|
48
|
+
return { type: 'musl' };
|
|
49
|
+
} catch (e) {
|
|
50
|
+
// If detection fails, default to musl (more portable)
|
|
51
|
+
return { type: 'musl' };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const libcInfo = getLibcInfo();
|
|
56
|
+
|
|
57
|
+
if (arch === 'arm64') {
|
|
58
|
+
// ARM64 Linux: choose based on libc type and version
|
|
59
|
+
if (libcInfo.type === 'musl' ||
|
|
60
|
+
(libcInfo.type === 'glibc' && (libcInfo.major < 2 || (libcInfo.major === 2 && libcInfo.minor < 35)))) {
|
|
61
|
+
platformKey = 'linux-arm64-musl';
|
|
62
|
+
} else {
|
|
63
|
+
platformKey = 'linux-arm64';
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
// x64 Linux: choose based on libc type and version
|
|
67
|
+
if (libcInfo.type === 'musl' ||
|
|
68
|
+
(libcInfo.type === 'glibc' && (libcInfo.major < 2 || (libcInfo.major === 2 && libcInfo.minor < 35)))) {
|
|
69
|
+
platformKey = 'linux-x64-musl';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const packageMap = {
|
|
75
|
+
'darwin-x64': '@jukanntenn/glm-plan-usage-darwin-x64',
|
|
76
|
+
'darwin-arm64': '@jukanntenn/glm-plan-usage-darwin-arm64',
|
|
77
|
+
'linux-x64': '@jukanntenn/glm-plan-usage-linux-x64',
|
|
78
|
+
'linux-x64-musl': '@jukanntenn/glm-plan-usage-linux-x64-musl',
|
|
79
|
+
'linux-arm64': '@jukanntenn/glm-plan-usage-linux-arm64',
|
|
80
|
+
'linux-arm64-musl': '@jukanntenn/glm-plan-usage-linux-arm64-musl',
|
|
81
|
+
'win32-x64': '@jukanntenn/glm-plan-usage-win32-x64',
|
|
82
|
+
'win32-ia32': '@jukanntenn/glm-plan-usage-win32-x64', // Use 64-bit for 32-bit
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const packageName = packageMap[platformKey];
|
|
86
|
+
if (!packageName) {
|
|
87
|
+
if (!silent) {
|
|
88
|
+
console.log(`Platform ${platformKey} not supported for auto-setup`);
|
|
89
|
+
}
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const binaryName = platform === 'win32' ? 'glm-plan-usage.exe' : 'glm-plan-usage';
|
|
94
|
+
const targetPath = path.join(claudeDir, binaryName);
|
|
95
|
+
|
|
96
|
+
// Multiple path search strategies for different package managers
|
|
97
|
+
const findBinaryPath = () => {
|
|
98
|
+
const possiblePaths = [
|
|
99
|
+
// npm/yarn: nested in node_modules
|
|
100
|
+
path.join(__dirname, '..', 'node_modules', packageName, binaryName),
|
|
101
|
+
// pnpm: try require.resolve first
|
|
102
|
+
(() => {
|
|
103
|
+
try {
|
|
104
|
+
const packagePath = require.resolve(packageName + '/package.json');
|
|
105
|
+
return path.join(path.dirname(packagePath), binaryName);
|
|
106
|
+
} catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
})(),
|
|
110
|
+
// pnpm: flat structure fallback with version detection
|
|
111
|
+
(() => {
|
|
112
|
+
const currentPath = __dirname;
|
|
113
|
+
const pnpmMatch = currentPath.match(/(.+\.pnpm)[\\/]([^\\//]+)[\\/]/);
|
|
114
|
+
if (pnpmMatch) {
|
|
115
|
+
const pnpmRoot = pnpmMatch[1];
|
|
116
|
+
const packageNameEncoded = packageName.replace('/', '+');
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
// Try to find any version of the package
|
|
120
|
+
const pnpmContents = fs.readdirSync(pnpmRoot);
|
|
121
|
+
const packagePattern = new RegExp(`^${packageNameEncoded.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}@`);
|
|
122
|
+
const matchingPackage = pnpmContents.find(dir => packagePattern.test(dir));
|
|
123
|
+
|
|
124
|
+
if (matchingPackage) {
|
|
125
|
+
return path.join(pnpmRoot, matchingPackage, 'node_modules', packageName, binaryName);
|
|
126
|
+
}
|
|
127
|
+
} catch {
|
|
128
|
+
// Fallback to current behavior if directory reading fails
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
})()
|
|
133
|
+
].filter(p => p !== null);
|
|
134
|
+
|
|
135
|
+
for (const testPath of possiblePaths) {
|
|
136
|
+
if (fs.existsSync(testPath)) {
|
|
137
|
+
return testPath;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const sourcePath = findBinaryPath();
|
|
144
|
+
if (!sourcePath) {
|
|
145
|
+
if (!silent) {
|
|
146
|
+
console.log('Binary package not installed, skipping Claude Code setup');
|
|
147
|
+
console.log('The global glm-plan-usage command will still work via npm');
|
|
148
|
+
}
|
|
149
|
+
process.exit(0);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Copy or link the binary
|
|
153
|
+
if (platform === 'win32') {
|
|
154
|
+
// Windows: Copy file
|
|
155
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
156
|
+
} else {
|
|
157
|
+
// Unix: Try hard link first, fallback to copy
|
|
158
|
+
try {
|
|
159
|
+
if (fs.existsSync(targetPath)) {
|
|
160
|
+
fs.unlinkSync(targetPath);
|
|
161
|
+
}
|
|
162
|
+
fs.linkSync(sourcePath, targetPath);
|
|
163
|
+
} catch {
|
|
164
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
165
|
+
}
|
|
166
|
+
fs.chmodSync(targetPath, '755');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!silent) {
|
|
170
|
+
console.log('✨ GLM Plan Usage is ready for Claude Code!');
|
|
171
|
+
console.log(`📍 Location: ${targetPath}`);
|
|
172
|
+
console.log('🎉 You can now use: glm-plan-usage --help');
|
|
173
|
+
}
|
|
174
|
+
} catch (error) {
|
|
175
|
+
// Silent failure - don't break installation
|
|
176
|
+
if (!silent) {
|
|
177
|
+
console.log('Note: Could not auto-configure for Claude Code');
|
|
178
|
+
console.log('The global glm-plan-usage command will still work.');
|
|
179
|
+
console.log('You can manually copy glm-plan-usage to ~/.claude/glm-plan-usage/ if needed');
|
|
180
|
+
}
|
|
181
|
+
}
|