glm-quota-line 0.6.0 → 0.8.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.
- package/CHANGELOG.md +17 -0
- package/README.en.md +122 -0
- package/README.md +53 -98
- package/package.json +7 -5
- package/src/claude/install.js +27 -43
- package/src/claude/sessionStart.js +2 -5
- package/src/claude/settings.js +2 -10
- package/src/cli/args.js +5 -1
- package/src/cli/commands.js +30 -1
- package/src/cli/index.js +15 -25
- package/src/cli/update.js +120 -0
- package/src/core/quota/cache.js +19 -29
- package/src/core/quota/parse.js +1 -1
- package/src/core/quota/service.js +49 -37
- package/src/core/status/bar.js +1 -1
- package/src/core/status/format.js +5 -11
- package/src/core/status/theme.js +1 -11
- package/src/shared/config.js +9 -22
- package/src/shared/constants.js +14 -14
- package/src/shared/packageInfo.js +29 -0
- package/README.zh-CN.md +0 -171
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
- Added progressive refresh backoff: new sessions start at 3-minute intervals, advance to 5 minutes after 5 refreshes, and cap at 10 minutes after 5 more — giving new users fast feedback while reducing API pressure in long sessions
|
|
6
|
+
- Added low-quota override: when remaining quota drops below 30%, the refresh interval is forced back to 3 minutes regardless of current tier, so users see accurate data when it matters most
|
|
7
|
+
- Low-quota refreshes do not advance the tier counter, preserving the previous tier when quota recovers
|
|
8
|
+
- SessionStart (startup / resume / clear) resets the tier to level 0, ensuring fresh sessions always start responsive
|
|
9
|
+
- Rate-limited and failed responses no longer advance the tier counter
|
|
10
|
+
- Old cache files without tier fields automatically migrate to tier 0
|
|
11
|
+
- Simplified README quick start to two commands with style config clearly marked as optional
|
|
12
|
+
|
|
13
|
+
## 0.7.0
|
|
14
|
+
|
|
15
|
+
- Added `--version` and `version` so the installed CLI version is visible directly from the command line
|
|
16
|
+
- Added `check-update` to compare the installed version with npm and print a suggested upgrade command without auto-updating
|
|
17
|
+
- Improved CLI help and README docs with upgrade and version-check examples
|
|
18
|
+
- Corrected published package metadata to include `README.en.md` in the npm file list
|
|
19
|
+
|
|
3
20
|
## 0.6.0
|
|
4
21
|
|
|
5
22
|
- Added official international GLM quota endpoint support for `api.z.ai` while preserving domestic `open.bigmodel.cn` detection
|
package/README.en.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<h1 align="center">glm-quota-line</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
One-command install, zero dependencies. Shows accurate Zhipu GLM Coding Plan quota balance and reset time in the Claude Code status line — data from the official API, not estimated.
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/glm-quota-line"><img alt="npm version" src="https://img.shields.io/npm/v/glm-quota-line?logo=npm&color=cb3837"></a>
|
|
9
|
+
<a href="https://www.npmjs.com/package/glm-quota-line"><img alt="node version" src="https://img.shields.io/node/v/glm-quota-line?logo=node.js&color=339933"></a>
|
|
10
|
+
<a href="./LICENSE"><img alt="license" src="https://img.shields.io/npm/l/glm-quota-line"></a>
|
|
11
|
+
<img alt="dependencies" src="https://img.shields.io/badge/dependencies-0-2ea44f">
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="./README.md">简体中文</a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
`glm-quota-line` reads the Zhipu GLM Coding Plan quota API, caches results, and prints a short status line for Claude Code's `statusLine.command`. A `SessionStart` hook pre-refreshes the cache so new sessions never show stale data.
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
- **One-command install** — `glm-quota-line install` wires status line and `SessionStart` hooks into Claude Code automatically
|
|
23
|
+
- **Accurate quota display** — reads directly from the official GLM quota API, not estimated; shows both 5-hour and weekly token quotas
|
|
24
|
+
- **Domestic + international endpoints** — auto-detects `open.bigmodel.cn` and `api.z.ai`
|
|
25
|
+
- **Zero dependencies** — no runtime deps, single-purpose CLI
|
|
26
|
+
- **Smart caching** — refreshes by session, TTL, and token usage; supports manual auth overrides for proxy/gateway setups
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install -g glm-quota-line
|
|
32
|
+
glm-quota-line install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
That's it — works out of the box. Default output (`style=text`, `theme=ansi`, `palette=dark`):
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
GLM Lite | 5h 91% | week 47% | reset 14:47
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Both the 5-hour quota (primary) and weekly quota (secondary) are shown with automatic reset time.
|
|
42
|
+
|
|
43
|
+
Upgrade:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install -g glm-quota-line
|
|
47
|
+
glm-quota-line check-update
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Custom Styles
|
|
51
|
+
|
|
52
|
+
All style options are optional — adjust only if needed:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
glm-quota-line config set style bar # layout: text / compact / bar
|
|
56
|
+
glm-quota-line config set theme ansi # color: plain / ansi
|
|
57
|
+
glm-quota-line config set palette dark # palette: dark / mono (only when theme=ansi)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Different `style` outputs:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
# style=text (default)
|
|
64
|
+
GLM Lite | 5h 91% | week 47% | reset 14:47
|
|
65
|
+
|
|
66
|
+
# style=compact
|
|
67
|
+
GLM 5h 91% W 47% | 14:47
|
|
68
|
+
|
|
69
|
+
# style=bar
|
|
70
|
+
GLM Lite █░░░░░░░░░ 91% | W 47% | 14:47
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Recommended combinations:
|
|
74
|
+
|
|
75
|
+
| Use case | Config |
|
|
76
|
+
| -------------- | --------------------------------------------- |
|
|
77
|
+
| Dark terminal | `style=bar`, `theme=ansi`, `palette=dark` |
|
|
78
|
+
| Light terminal | `style=compact`, `theme=ansi`, `palette=mono` |
|
|
79
|
+
| Plain fallback | any `style`, `theme=plain` |
|
|
80
|
+
|
|
81
|
+
## Custom Auth
|
|
82
|
+
|
|
83
|
+
If Claude Code runs behind a gateway or proxy and the injected `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_BASE_URL` are not the real values:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
glm-quota-line config set auth-token <your-real-token>
|
|
87
|
+
glm-quota-line config set base-url https://open.bigmodel.cn/api/anthropic
|
|
88
|
+
# or
|
|
89
|
+
glm-quota-line config set base-url https://api.z.ai/api/anthropic
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Clear with `glm-quota-line config unset auth-token` / `base-url`. Stored overrides take precedence over Claude-injected environment variables.
|
|
93
|
+
|
|
94
|
+
## Commands
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
glm-quota-line [--style text|compact|bar] [--display left|used|both]
|
|
98
|
+
[--theme plain|ansi] [--palette dark|mono]
|
|
99
|
+
|
|
100
|
+
glm-quota-line install [--force]
|
|
101
|
+
glm-quota-line uninstall
|
|
102
|
+
glm-quota-line version
|
|
103
|
+
glm-quota-line check-update
|
|
104
|
+
glm-quota-line config show
|
|
105
|
+
glm-quota-line config set <style|display|theme|palette|auth-token|base-url> <value>
|
|
106
|
+
glm-quota-line config unset <key>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Run `glm-quota-line --help` for full descriptions.
|
|
110
|
+
|
|
111
|
+
Use `glm-quota-line --version` to print the installed version. `check-update` only checks and prints the suggested upgrade command; it does not modify your environment.
|
|
112
|
+
|
|
113
|
+
## Notes
|
|
114
|
+
|
|
115
|
+
- Only `TOKENS_LIMIT` quotas are shown; `TIME_LIMIT` / MCP usage is ignored
|
|
116
|
+
- Missing auth returns `GLM | auth expired`; API failures return `GLM | quota unavailable`
|
|
117
|
+
- `install` does not replace an unmanaged status line unless `--force` is used
|
|
118
|
+
- `install --force` backs up the previous entry; `uninstall` restores it when possible
|
|
119
|
+
|
|
120
|
+
## License
|
|
121
|
+
|
|
122
|
+
[MIT](./LICENSE)
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<h1 align="center">glm-quota-line</h1>
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
|
|
4
|
+
一行命令安装、零依赖,在 Claude Code 状态栏实时显示智谱(Zhipu)GLM Coding Plan 配额余额与重置时间。数据来自官方接口,精准非估算。
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
@@ -12,127 +12,86 @@
|
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
<p align="center">
|
|
15
|
-
<a href="./README.
|
|
15
|
+
<a href="./README.en.md">English</a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
`glm-quota-line` 读取智谱(Zhipu)GLM Coding Plan 配额接口、缓存结果,并输出一行适合 Claude Code `statusLine.command` 的状态文本。通过 `SessionStart` hook 预刷新缓存,新会话不会显示旧配额。
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
## 功能
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
- **一行命令安装** — `glm-quota-line install` 自动接入 Claude Code 状态栏和 `SessionStart` hook
|
|
23
|
+
- **精准配额显示** — 数据来自官方配额接口,非估算;同时展示 5 小时和周 token 配额
|
|
24
|
+
- **国内 + 国际端点** — 自动识别 `open.bigmodel.cn` 和 `api.z.ai`
|
|
25
|
+
- **零依赖** — 无运行时依赖,单一用途
|
|
26
|
+
- **智能缓存** — 按会话、TTL 和 token 用量刷新;支持代理/网关手动覆盖鉴权
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
## Why
|
|
27
|
-
|
|
28
|
-
- Built for a single purpose: show GLM quota clearly in Claude Code
|
|
29
|
-
- Small and predictable: no runtime dependencies, no unnecessary abstraction
|
|
30
|
-
- Practical for real usage: cache-aware, session-aware, and easy to install
|
|
31
|
-
|
|
32
|
-
## Features
|
|
33
|
-
|
|
34
|
-
- Built for Claude Code `statusLine.command`
|
|
35
|
-
- No runtime dependencies
|
|
36
|
-
- Optional `text`, `compact`, and `bar` layouts
|
|
37
|
-
- Optional ANSI color themes for dark and light terminals
|
|
38
|
-
- Manual `auth-token` and `base-url` overrides for proxy or gateway setups
|
|
39
|
-
- Automatic install and uninstall for Claude Code status line integration
|
|
40
|
-
- SessionStart pre-refresh so a new Claude session does not briefly show stale quota
|
|
41
|
-
|
|
42
|
-
## Installation
|
|
43
|
-
|
|
44
|
-
Recommended:
|
|
28
|
+
## 快速开始
|
|
45
29
|
|
|
46
30
|
```bash
|
|
47
31
|
npm install -g glm-quota-line
|
|
32
|
+
glm-quota-line install
|
|
48
33
|
```
|
|
49
34
|
|
|
50
|
-
|
|
35
|
+
两步完成,开箱即用。默认输出(`style=text`,`theme=ansi`,`palette=dark`):
|
|
51
36
|
|
|
52
|
-
```
|
|
53
|
-
|
|
37
|
+
```text
|
|
38
|
+
GLM Lite | 5h 91% | week 47% | reset 14:47
|
|
54
39
|
```
|
|
55
40
|
|
|
56
|
-
|
|
41
|
+
同时显示 5 小时配额(主要)和周配额(次要),并自动展示重置时间。
|
|
57
42
|
|
|
58
|
-
|
|
43
|
+
升级版本:
|
|
59
44
|
|
|
60
45
|
```bash
|
|
61
|
-
glm-quota-line
|
|
62
|
-
glm-quota-line
|
|
63
|
-
glm-quota-line config set theme ansi
|
|
64
|
-
glm-quota-line config set palette dark
|
|
46
|
+
npm install -g glm-quota-line
|
|
47
|
+
glm-quota-line check-update
|
|
65
48
|
```
|
|
66
49
|
|
|
67
|
-
|
|
50
|
+
## 自定义样式
|
|
51
|
+
|
|
52
|
+
所有样式配置均为可选,按需调整:
|
|
68
53
|
|
|
69
54
|
```bash
|
|
70
|
-
glm-quota-line
|
|
55
|
+
glm-quota-line config set style bar # 布局: text / compact / bar
|
|
56
|
+
glm-quota-line config set theme ansi # 配色: plain / ansi
|
|
57
|
+
glm-quota-line config set palette dark # 色板: dark / mono(仅 theme=ansi 时生效)
|
|
71
58
|
```
|
|
72
59
|
|
|
73
|
-
|
|
60
|
+
不同 style 效果:
|
|
74
61
|
|
|
75
62
|
```text
|
|
76
|
-
|
|
63
|
+
# style=text(默认)
|
|
64
|
+
GLM Lite | 5h 91% | week 47% | reset 14:47
|
|
77
65
|
|
|
66
|
+
# style=compact
|
|
78
67
|
GLM 5h 91% W 47% | 14:47
|
|
79
68
|
|
|
69
|
+
# style=bar
|
|
80
70
|
GLM Lite █░░░░░░░░░ 91% | W 47% | 14:47
|
|
81
71
|
```
|
|
82
72
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
| Use case | Config |
|
|
86
|
-
| -------------- | --------------------------------------------- |
|
|
87
|
-
| Dark terminal | `style=bar`, `theme=ansi`, `palette=dark` |
|
|
88
|
-
| Light terminal | `style=compact`, `theme=ansi`, `palette=mono` |
|
|
89
|
-
| Plain fallback | any `style`, `theme=plain` |
|
|
90
|
-
|
|
91
|
-
## Color Presets
|
|
73
|
+
推荐搭配:
|
|
92
74
|
|
|
93
|
-
|
|
75
|
+
| 使用场景 | 配置 |
|
|
76
|
+
| ---------- | --------------------------------------------- |
|
|
77
|
+
| 深色终端 | `style=bar`, `theme=ansi`, `palette=dark` |
|
|
78
|
+
| 浅色终端 | `style=compact`, `theme=ansi`, `palette=mono` |
|
|
79
|
+
| 纯文本回退 | 任意 `style`,`theme=plain` |
|
|
94
80
|
|
|
95
|
-
|
|
96
|
-
- Light terminal: `theme=ansi` + `palette=mono`
|
|
97
|
-
- Maximum compatibility: `theme=plain`
|
|
81
|
+
## 自定义鉴权
|
|
98
82
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
```bash
|
|
102
|
-
glm-quota-line config set style text
|
|
103
|
-
glm-quota-line config set theme ansi
|
|
104
|
-
glm-quota-line config set palette dark
|
|
105
|
-
|
|
106
|
-
glm-quota-line config set style compact
|
|
107
|
-
glm-quota-line config set theme ansi
|
|
108
|
-
glm-quota-line config set palette mono
|
|
109
|
-
|
|
110
|
-
glm-quota-line config set theme plain
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
Set `NO_COLOR=1` to force plain output.
|
|
114
|
-
|
|
115
|
-
## Manual Credential Overrides
|
|
116
|
-
|
|
117
|
-
If Claude Code is running behind a gateway or proxy and the injected `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_BASE_URL` are not the real values, store explicit overrides:
|
|
83
|
+
如果 Claude Code 运行在代理或网关后面,注入的 `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_BASE_URL` 不是实际值:
|
|
118
84
|
|
|
119
85
|
```bash
|
|
120
86
|
glm-quota-line config set auth-token <your-real-token>
|
|
121
87
|
glm-quota-line config set base-url https://open.bigmodel.cn/api/anthropic
|
|
122
|
-
#
|
|
88
|
+
# 或
|
|
123
89
|
glm-quota-line config set base-url https://api.z.ai/api/anthropic
|
|
124
90
|
```
|
|
125
91
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
glm-quota-line config unset auth-token
|
|
130
|
-
glm-quota-line config unset base-url
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Stored overrides take precedence over Claude-injected environment variables. `config show` redacts the token, but the local config file still stores the real value in plain text.
|
|
92
|
+
清除:`glm-quota-line config unset auth-token` / `base-url`。手动保存的值优先于 Claude 注入的环境变量。
|
|
134
93
|
|
|
135
|
-
##
|
|
94
|
+
## 命令
|
|
136
95
|
|
|
137
96
|
```bash
|
|
138
97
|
glm-quota-line [--style text|compact|bar] [--display left|used|both]
|
|
@@ -140,28 +99,24 @@ glm-quota-line [--style text|compact|bar] [--display left|used|both]
|
|
|
140
99
|
|
|
141
100
|
glm-quota-line install [--force]
|
|
142
101
|
glm-quota-line uninstall
|
|
102
|
+
glm-quota-line version
|
|
103
|
+
glm-quota-line check-update
|
|
143
104
|
glm-quota-line config show
|
|
144
|
-
glm-quota-line config set style
|
|
145
|
-
glm-quota-line config
|
|
146
|
-
glm-quota-line config set theme <plain|ansi>
|
|
147
|
-
glm-quota-line config set palette <dark|mono>
|
|
148
|
-
glm-quota-line config set auth-token <token>
|
|
149
|
-
glm-quota-line config set base-url <url>
|
|
150
|
-
glm-quota-line config unset <style|display|theme|palette|auth-token|base-url>
|
|
105
|
+
glm-quota-line config set <style|display|theme|palette|auth-token|base-url> <value>
|
|
106
|
+
glm-quota-line config unset <key>
|
|
151
107
|
```
|
|
152
108
|
|
|
153
|
-
|
|
109
|
+
完整说明运行 `glm-quota-line --help`。
|
|
110
|
+
|
|
111
|
+
`glm-quota-line --version` 可直接查看当前安装版本;`check-update` 只检查并提示升级命令,不会自动修改环境。
|
|
154
112
|
|
|
155
|
-
##
|
|
113
|
+
## 说明
|
|
156
114
|
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
-
|
|
161
|
-
- `install` wires both the status line command and managed `SessionStart` hooks
|
|
162
|
-
- `install` does not replace an unmanaged Claude status line unless `--force` is used
|
|
163
|
-
- `install --force` backs up the previous entry and `uninstall` restores it when possible
|
|
115
|
+
- 只展示 `TOKENS_LIMIT` 配额,忽略 `TIME_LIMIT` / MCP 使用量
|
|
116
|
+
- 鉴权缺失返回 `GLM | auth expired`;接口异常返回 `GLM | quota unavailable`
|
|
117
|
+
- `install` 默认不会覆盖非本工具管理的状态栏,除非使用 `--force`
|
|
118
|
+
- `install --force` 会备份旧配置,`uninstall` 会在可能时恢复
|
|
164
119
|
|
|
165
|
-
##
|
|
120
|
+
## 许可证
|
|
166
121
|
|
|
167
122
|
[MIT](./LICENSE)
|
package/package.json
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glm-quota-line",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "Zhipu GLM Coding Plan quota monitor for Claude Code status line.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "caojian",
|
|
8
8
|
"preferGlobal": true,
|
|
9
9
|
"keywords": [
|
|
10
10
|
"claude-code",
|
|
11
|
-
"statusline",
|
|
12
11
|
"glm",
|
|
12
|
+
"zhipu",
|
|
13
|
+
"z.ai",
|
|
14
|
+
"coding-plan",
|
|
13
15
|
"quota",
|
|
14
|
-
"
|
|
16
|
+
"statusline"
|
|
15
17
|
],
|
|
16
18
|
"repository": {
|
|
17
19
|
"type": "git",
|
|
@@ -27,7 +29,7 @@
|
|
|
27
29
|
"files": [
|
|
28
30
|
"src",
|
|
29
31
|
"README.md",
|
|
30
|
-
"README.
|
|
32
|
+
"README.en.md",
|
|
31
33
|
"LICENSE",
|
|
32
34
|
"CHANGELOG.md"
|
|
33
35
|
],
|
package/src/claude/install.js
CHANGED
|
@@ -32,7 +32,7 @@ function isToolManagedStatusLine(statusLine) {
|
|
|
32
32
|
return isToolManagedCommand(statusLine?.command);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
function getStatusLineEntryPath() {
|
|
36
36
|
return path.resolve(__dirname, "..", "cli", "index.js");
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -53,38 +53,41 @@ function isToolManagedHook(hook) {
|
|
|
53
53
|
return hook?.type === "command" && isToolManagedCommand(hook.command);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
function
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const existingGroups = Array.isArray(settings.hooks.SessionStart) ? settings.hooks.SessionStart : null;
|
|
62
|
-
if (!existingGroups) {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
56
|
+
function filterManagedHooksFromGroups(groups) {
|
|
57
|
+
let hadManaged = false;
|
|
58
|
+
const filtered = [];
|
|
65
59
|
|
|
66
|
-
|
|
67
|
-
const nextGroups = [];
|
|
68
|
-
|
|
69
|
-
for (const group of existingGroups) {
|
|
60
|
+
for (const group of groups) {
|
|
70
61
|
if (!group || typeof group !== "object" || !Array.isArray(group.hooks)) {
|
|
71
|
-
|
|
62
|
+
filtered.push(group);
|
|
72
63
|
continue;
|
|
73
64
|
}
|
|
74
65
|
|
|
75
66
|
const nextHooks = group.hooks.filter((hook) => !isToolManagedHook(hook));
|
|
76
67
|
if (nextHooks.length !== group.hooks.length) {
|
|
77
|
-
|
|
68
|
+
hadManaged = true;
|
|
78
69
|
}
|
|
79
70
|
|
|
80
71
|
if (nextHooks.length > 0) {
|
|
81
|
-
|
|
82
|
-
...group,
|
|
83
|
-
hooks: nextHooks
|
|
84
|
-
});
|
|
72
|
+
filtered.push({ ...group, hooks: nextHooks });
|
|
85
73
|
}
|
|
86
74
|
}
|
|
87
75
|
|
|
76
|
+
return { groups: filtered, hadManaged };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function removeManagedSessionStartHooks(settings) {
|
|
80
|
+
if (!settings.hooks || typeof settings.hooks !== "object") {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const existingGroups = Array.isArray(settings.hooks.SessionStart) ? settings.hooks.SessionStart : null;
|
|
85
|
+
if (!existingGroups) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const { groups: nextGroups, hadManaged: removed } = filterManagedHooksFromGroups(existingGroups);
|
|
90
|
+
|
|
88
91
|
if (nextGroups.length > 0) {
|
|
89
92
|
settings.hooks.SessionStart = nextGroups;
|
|
90
93
|
} else {
|
|
@@ -101,21 +104,10 @@ function removeManagedSessionStartHooks(settings) {
|
|
|
101
104
|
function installManagedSessionStartHooks(settings, command) {
|
|
102
105
|
const existingGroups =
|
|
103
106
|
settings.hooks && typeof settings.hooks === "object" && Array.isArray(settings.hooks.SessionStart)
|
|
104
|
-
? settings.hooks.SessionStart
|
|
105
|
-
group && typeof group === "object" ? { ...group, hooks: Array.isArray(group.hooks) ? [...group.hooks] : group.hooks } : group
|
|
106
|
-
)
|
|
107
|
+
? settings.hooks.SessionStart
|
|
107
108
|
: [];
|
|
108
109
|
|
|
109
|
-
const nextGroups = existingGroups
|
|
110
|
-
if (!group || typeof group !== "object" || !Array.isArray(group.hooks)) {
|
|
111
|
-
return group;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
...group,
|
|
116
|
-
hooks: group.hooks.filter((hook) => !isToolManagedHook(hook))
|
|
117
|
-
};
|
|
118
|
-
});
|
|
110
|
+
const { groups: nextGroups } = filterManagedHooksFromGroups(existingGroups);
|
|
119
111
|
|
|
120
112
|
for (const matcher of SESSION_START_MATCHERS) {
|
|
121
113
|
const targetGroup = nextGroups.find(
|
|
@@ -123,21 +115,13 @@ function installManagedSessionStartHooks(settings, command) {
|
|
|
123
115
|
);
|
|
124
116
|
|
|
125
117
|
if (targetGroup) {
|
|
126
|
-
targetGroup.hooks.push({
|
|
127
|
-
type: "command",
|
|
128
|
-
command
|
|
129
|
-
});
|
|
118
|
+
targetGroup.hooks.push({ type: "command", command });
|
|
130
119
|
continue;
|
|
131
120
|
}
|
|
132
121
|
|
|
133
122
|
nextGroups.push({
|
|
134
123
|
matcher,
|
|
135
|
-
hooks: [
|
|
136
|
-
{
|
|
137
|
-
type: "command",
|
|
138
|
-
command
|
|
139
|
-
}
|
|
140
|
-
]
|
|
124
|
+
hooks: [{ type: "command", command }]
|
|
141
125
|
});
|
|
142
126
|
}
|
|
143
127
|
|
|
@@ -3,7 +3,7 @@ import { resolveQuotaStatus } from "../core/quota/service.js";
|
|
|
3
3
|
import { readStatusLineInput } from "./input.js";
|
|
4
4
|
import { readToolConfig } from "./settings.js";
|
|
5
5
|
|
|
6
|
-
export const SESSION_START_MATCHERS = ["startup", "resume", "clear"
|
|
6
|
+
export const SESSION_START_MATCHERS = ["startup", "resume", "clear"];
|
|
7
7
|
|
|
8
8
|
export async function refreshQuotaOnSessionStart(options = {}) {
|
|
9
9
|
const hookInput = await readStatusLineInput(options.stdin ?? process.stdin);
|
|
@@ -12,10 +12,7 @@ export async function refreshQuotaOnSessionStart(options = {}) {
|
|
|
12
12
|
const resolveQuotaStatusFn = options.resolveQuotaStatusFn ?? resolveQuotaStatus;
|
|
13
13
|
const config = {
|
|
14
14
|
...loadConfigFn(options.env ?? process.env, userConfig),
|
|
15
|
-
sessionId: hookInput?.session_id || ""
|
|
16
|
-
// SessionStart runs before statusLine has token totals, so treat a new session
|
|
17
|
-
// as starting from zero to preserve later token-threshold refreshes.
|
|
18
|
-
observedTokens: 0
|
|
15
|
+
sessionId: hookInput?.session_id || ""
|
|
19
16
|
};
|
|
20
17
|
|
|
21
18
|
return resolveQuotaStatusFn(config, {
|
package/src/claude/settings.js
CHANGED
|
@@ -10,8 +10,9 @@ import {
|
|
|
10
10
|
isValidTheme
|
|
11
11
|
} from "../shared/constants.js";
|
|
12
12
|
import { readJsonFile, writeJsonFile } from "../shared/jsonFile.js";
|
|
13
|
+
import { normalizeOptionalString } from "../shared/config.js";
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
function getClaudeDir() {
|
|
15
16
|
return path.join(os.homedir(), ".claude");
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -23,15 +24,6 @@ export function getToolConfigPath() {
|
|
|
23
24
|
return path.join(getClaudeDir(), "glm-quota-line.json");
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
function normalizeOptionalString(value) {
|
|
27
|
-
if (typeof value !== "string") {
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const trimmed = value.trim();
|
|
32
|
-
return trimmed || undefined;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
27
|
function redactSecret(value) {
|
|
36
28
|
if (!value) {
|
|
37
29
|
return value;
|
package/src/cli/args.js
CHANGED
|
@@ -26,6 +26,11 @@ export function parseArgs(argv = process.argv.slice(2)) {
|
|
|
26
26
|
continue;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
if (arg === "--version" || arg === "-v") {
|
|
30
|
+
options.version = true;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
if (arg === "--force") {
|
|
30
35
|
options.force = true;
|
|
31
36
|
continue;
|
|
@@ -67,4 +72,3 @@ export function parseArgs(argv = process.argv.slice(2)) {
|
|
|
67
72
|
options.positionals = positionals;
|
|
68
73
|
return options;
|
|
69
74
|
}
|
|
70
|
-
|
package/src/cli/commands.js
CHANGED
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
} from "../claude/settings.js";
|
|
14
14
|
import { installClaudeStatusLine, uninstallClaudeStatusLine } from "../claude/install.js";
|
|
15
15
|
import { refreshQuotaOnSessionStart } from "../claude/sessionStart.js";
|
|
16
|
+
import { checkForUpdates } from "./update.js";
|
|
17
|
+
import { getPackageVersion } from "../shared/packageInfo.js";
|
|
16
18
|
|
|
17
19
|
function isNonEmptyString(value) {
|
|
18
20
|
return typeof value === "string" && value.trim().length > 0;
|
|
@@ -66,9 +68,36 @@ const CONFIG_KEYS = {
|
|
|
66
68
|
}
|
|
67
69
|
};
|
|
68
70
|
|
|
69
|
-
export async function handleCommand(args, output = process.stdout) {
|
|
71
|
+
export async function handleCommand(args, output = process.stdout, dependencies = {}) {
|
|
72
|
+
const getVersion = dependencies.getVersion || getPackageVersion;
|
|
73
|
+
const runUpdateCheck = dependencies.runUpdateCheck || checkForUpdates;
|
|
70
74
|
const [command, subcommand, key, value] = args.positionals;
|
|
71
75
|
|
|
76
|
+
if (command === "version") {
|
|
77
|
+
output.write(`glm-quota-line ${await getVersion()}\n`);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (command === "check-update") {
|
|
82
|
+
const result = await runUpdateCheck();
|
|
83
|
+
output.write(`glm-quota-line ${result.currentVersion}\n`);
|
|
84
|
+
|
|
85
|
+
if (result.status === "up-to-date") {
|
|
86
|
+
output.write(`latest: ${result.latestVersion}\nstatus: up to date\n`);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (result.status === "update-available") {
|
|
91
|
+
output.write(
|
|
92
|
+
`latest: ${result.latestVersion}\nstatus: update available\nupgrade: ${result.upgradeCommand}\n`
|
|
93
|
+
);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
output.write(`status: unable to check updates\nreason: ${result.errorMessage}\n`);
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
72
101
|
if (command === "install") {
|
|
73
102
|
const result = await installClaudeStatusLine(undefined, undefined, undefined, {
|
|
74
103
|
force: Boolean(args.force)
|