glm-quota-line 1.1.0 → 1.2.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 CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.0
4
+
5
+ - Added interactive TUI configuration: `glm-quota-line configure` — live preview, per-component toggle and style, global options
6
+ - Added component-level control: each display component (plan, 5h, week, reset, context) can be individually toggled and styled
7
+ - Added `minimalist` config to hide all labels, showing only progress bars and values
8
+ - Added `raw-values` config to hide labels and show raw values
9
+ - Added `--json` flag for structured JSON output in terminal mode (useful for scripting and automation)
10
+ - Added `work-days` config (1-7) to customize weekly working days for quota pacing calculation
11
+ - Added one-time query via `npx glm-quota-line` without global install
12
+ - Context window now displays model ID and window size (e.g., `glm-4.7 (200K)`)
13
+ - Context window usage is now calculated from raw tokens when model mapping is available
14
+ - Weekly quota bar now shows theoretical budget with shade segments (▒) when pacing data is available
15
+ - Weekly quota severity now uses pacing-based calculation: good (≤1.1x), warn (1.1-1.3x), danger (>1.3x)
16
+ - Added GLM provider detection to disable quota for non-Zhipu API endpoints
17
+ - Replaced `--ctx on|off` CLI flag and `config set/unset ctx` with TUI component config
18
+ - Consolidated duplicate utility functions into shared `utils.js` module
19
+
20
+ ## 1.1.1
21
+
22
+ - Fixed MCP quota not displaying when API returns `TIME_LIMIT` type instead of `MCP_LIMIT`
23
+ - Updated severity colors: good `#4694AF`, warn `#FF8200`, danger `#DC3513`
24
+
3
25
  ## 1.1.0
4
26
 
5
27
  - Added MCP quota extraction from API response (`MCP_LIMIT` type), shown in CLI query output alongside token quotas
package/README.en.md CHANGED
@@ -19,13 +19,25 @@
19
19
 
20
20
  - **Terminal quick check** — run `glm-quota-line` in any terminal to view your quota (including MCP) without launching Claude Code
21
21
  - **Claude Code status line** — auto-embeds in the status bar after install, shows quota balance, reset time, and context window usage in real time
22
- - **Bar visualization** — default bar style shows remaining quota at a glance
22
+ - **Bar visualization** — default bar style shows remaining quota at a glance; weekly quota shows theoretical budget shadow
23
+ - **Weekly pacing analysis** — calculates usage speed based on work days, auto-highlights when exceeding theoretical budget
24
+ - **JSON output** — `--json` flag outputs structured data for scripting
25
+ - **Interactive configuration** — `glm-quota-line configure` launches a TUI with live preview and per-component controls
26
+ - **Component-level control** — each display component (plan, 5h, week, reset, context) can be individually toggled and styled
23
27
  - **Smart caching** — tiered refresh by session, TTL, and token usage; `SessionStart` hook pre-refreshes so new sessions never show stale data
24
28
  - **Domestic + international endpoints** — auto-detects `open.bigmodel.cn` and `api.z.ai`
25
29
  - **Zero dependencies** — no runtime deps, single-purpose CLI
26
30
 
27
31
  ## Quick Start
28
32
 
33
+ **One-time query (no install needed):**
34
+
35
+ ```bash
36
+ npx glm-quota-line
37
+ ```
38
+
39
+ **Status line integration (global install required):**
40
+
29
41
  ```bash
30
42
  npm install -g glm-quota-line
31
43
  glm-quota-line install
@@ -34,7 +46,7 @@ glm-quota-line install
34
46
  Done. Your Claude Code status bar will now show the quota:
35
47
 
36
48
  ```
37
- GLM Lite █████████░ 91% | W 47% | 14:47 | ctx ███░░░ 45%
49
+ GLM Lite █████████░ 91% | W ▒▒▒▒░░░░░ 47% | 14:47 | ctx ███░░░ 45% (glm-4.7/200K)
38
50
  ```
39
51
 
40
52
  You can also run `glm-quota-line` directly in the terminal to check your quota without launching Claude Code.
@@ -54,7 +66,7 @@ All options are optional. Persist with `glm-quota-line config set`, or override
54
66
 
55
67
  | Value | Description | Example |
56
68
  |---|---|---|
57
- | `bar` (default) | Progress bar | `GLM Lite █████████░ 91% \| W 47% \| 14:47 \| ctx ███░░░ 45%` |
69
+ | `bar` (default) | Progress bar | `GLM Lite █████████░ 91% \| W ▒▒▒▒░░░░░ 47% \| 14:47 \| ctx ███░░░ 45%` |
58
70
  | `text` | Full text | `GLM Lite \| 5h 91% \| week 47% \| reset 14:47 \| ctx 45%` |
59
71
  | `compact` | Compact mode | `GLM 5h 91% W 47% \| 14:47` |
60
72
 
@@ -91,24 +103,71 @@ Quota percentage colors change automatically based on remaining amount:
91
103
  glm-quota-line config set display used
92
104
  ```
93
105
 
94
- ### ctx — Context window usage
106
+ ### work-days — Work days per week
95
107
 
96
- Show the current Claude Code context window usage percentage in the status line (status line mode only).
108
+ Set the number of work days per week (1–7) for weekly quota theoretical budget and pacing analysis. Default: 5.
97
109
 
98
- | Value | Description |
99
- |---|---|
100
- | `on` (default) | Show context window usage |
101
- | `off` | Hide context window usage |
110
+ ```bash
111
+ glm-quota-line config set work-days 6
112
+ ```
113
+
114
+ Pacing analysis calculates theoretical budget based on elapsed work days:
115
+ - Green — usage speed ≤ 1.1x theoretical
116
+ - Yellow — usage speed 1.1x–1.3x theoretical
117
+ - Red — usage speed > 1.3x theoretical
118
+
119
+ ### --json — JSON output
120
+
121
+ Output structured JSON format (terminal mode only, ignored in status line mode):
102
122
 
103
123
  ```bash
104
- glm-quota-line config set ctx off
124
+ glm-quota-line --json
105
125
  ```
106
126
 
107
- Context usage colors change automatically based on used percentage:
127
+ Example output:
128
+ ```json
129
+ {
130
+ "level": "Lite",
131
+ "quotas": [
132
+ {
133
+ "label": "5h",
134
+ "leftPercent": 91,
135
+ "usedPercent": 9,
136
+ "nextResetTime": 1715257200000
137
+ },
138
+ {
139
+ "label": "week",
140
+ "leftPercent": 47,
141
+ "usedPercent": 53,
142
+ "nextResetTime": 1715744400000
143
+ }
144
+ ],
145
+ "mcp": {
146
+ "leftPercent": 85,
147
+ "usedPercent": 15
148
+ }
149
+ }
150
+ ```
151
+
152
+ ### minimalist — Minimal mode
108
153
 
109
- - Green — used < 60%
110
- - Yellow — used 60%–79%
111
- - Red — used >= 80%
154
+ Hide all labels, show only progress bars and values.
155
+
156
+ ```bash
157
+ glm-quota-line config set minimalist true
158
+ ```
159
+
160
+ Effect:
161
+ - Off: `GLM Lite █████████░ 91% | W ▒▒▒▒░░░░░ 47% | 14:47`
162
+ - On: `█████████░ 91% | ▒▒▒▒░░░░░ 47% | 14:47`
163
+
164
+ ### raw-values — Raw values
165
+
166
+ Hide all labels and show raw values directly.
167
+
168
+ ```bash
169
+ glm-quota-line config set raw-values true
170
+ ```
112
171
 
113
172
  ### auth-token / base-url — Custom auth
114
173
 
@@ -129,6 +188,29 @@ Auth source priority (highest to lowest):
129
188
  2. Environment variables `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_BASE_URL`
130
189
  3. `env` field in `~/.claude/settings.json`
131
190
 
191
+ ### configure — Interactive TUI setup
192
+
193
+ Launch a terminal UI with live preview to adjust component toggles, styles, and global options.
194
+
195
+ ```bash
196
+ glm-quota-line configure
197
+ ```
198
+
199
+ Key bindings:
200
+ - `↑↓` select component, `Enter` to edit, `Tab` to cycle style, `Space` to toggle
201
+ - `g` to enter global options (theme, display mode, minimalist, raw-values)
202
+ - `s` to save, `q` to quit
203
+
204
+ Components:
205
+
206
+ | Component | Description | Styleable | Hideable |
207
+ |---|---|---|---|
208
+ | `level` | Plan level (e.g. GLM Lite) | — | ✓ |
209
+ | `5h` | 5-hour quota | ✓ (bar/text) | — (required) |
210
+ | `week` | Weekly quota | ✓ (bar/text) | ✓ |
211
+ | `reset` | Reset time | — | ✓ |
212
+ | `ctx` | Context window usage | ✓ (bar/text) | ✓ |
213
+
132
214
  ## Recommended Combinations
133
215
 
134
216
  | Use case | Config |
@@ -137,17 +219,22 @@ Auth source priority (highest to lowest):
137
219
  | Light terminal | `style=bar`, `theme=light` |
138
220
  | Minimal setup | `style=compact`, `theme=mono` |
139
221
  | Track usage | `style=bar`, `display=used` |
222
+ | Scripting | `--json` |
223
+ | 6-day work week | `work-days=6` |
224
+ | Minimal values | `minimalist=true` |
225
+ | Interactive setup | `glm-quota-line configure` |
140
226
 
141
227
  ## Command Reference
142
228
 
143
229
  ```bash
144
- glm-quota-line [--style text|compact|bar] [--display left|used] [--theme dark|light|mono] [--ctx on|off]
230
+ glm-quota-line [--style text|compact|bar] [--display left|used] [--theme dark|light|mono] [--json]
145
231
  glm-quota-line install [--force]
146
232
  glm-quota-line uninstall
147
233
  glm-quota-line version
148
234
  glm-quota-line check-update
235
+ glm-quota-line configure
149
236
  glm-quota-line config show
150
- glm-quota-line config set <style|display|theme|ctx|auth-token|base-url> <value>
237
+ glm-quota-line config set <style|display|theme|auth-token|base-url|work-days|minimalist|raw-values> <value>
151
238
  glm-quota-line config unset <key>
152
239
  ```
153
240
 
@@ -155,11 +242,15 @@ Run `glm-quota-line --help` for full descriptions.
155
242
 
156
243
  ## Notes
157
244
 
158
- - Shows `TOKENS_LIMIT` and `MCP_LIMIT` quotas; `TIME_LIMIT` is ignored
159
- - Context window usage is shown by default; disable with `--ctx off` or `config set ctx off`
245
+ - Shows `TOKENS_LIMIT` and `MCP_LIMIT` / `TIME_LIMIT` quotas
246
+ - Weekly quota progress bar shadow (▒) is a daily pacing baseline: the theoretical budget based on elapsed work days — the more the filled bar (█) extends past the shadow, the faster you're consuming
247
+ - Context window usage is shown by default; toggle via `glm-quota-line configure`
248
+ - Context window usage is calculated from raw tokens when model mapping is available, falls back to API-provided percentages
249
+ - Each component can be individually toggled and styled via `glm-quota-line configure`
160
250
  - Missing auth returns `GLM | auth expired`; API failures return `GLM | quota unavailable`
161
251
  - `install` does not replace an unmanaged status line unless `--force` is used
162
252
  - `install --force` backs up the previous entry; `uninstall` restores it when possible
253
+ - Set `GLM_QUOTA_DEBUG=1` to output context window debug info to stderr
163
254
 
164
255
  ## License
165
256
 
package/README.md CHANGED
@@ -19,13 +19,25 @@
19
19
 
20
20
  - **终端快速查询** — 直接运行 `glm-quota-line` 即可在终端查看配额(含 MCP),无需启动 Claude Code
21
21
  - **Claude Code 状态栏** — 安装后自动嵌入状态栏,实时显示配额余额、重置时间和上下文窗口用量
22
- - **进度条可视化** — 默认 bar 风格,一眼看清剩余比例
22
+ - **进度条可视化** — 默认 bar 风格,一眼看清剩余比例;周配额显示理论预算阴影
23
+ - **智能配速分析** — 根据工作日和已过时间计算配额使用速度,超速时自动变色警示
24
+ - **JSON 输出** — 支持 `--json` 参数输出结构化数据,便于脚本调用
25
+ - **交互式配置** — `glm-quota-line configure` 启动 TUI 界面,实时预览、逐项调整组件开关与样式
26
+ - **组件级控制** — 每个显示组件(套餐、5h、周、重置、上下文)可单独开关和设置样式
23
27
  - **智能缓存** — 按会话、TTL 和 token 用量分级刷新;`SessionStart` hook 预刷新,新会话不显示旧数据
24
28
  - **国内 + 国际端点** — 自动识别 `open.bigmodel.cn` 和 `api.z.ai`
25
29
  - **零依赖** — 无运行时依赖,单一用途
26
30
 
27
31
  ## 快速开始
28
32
 
33
+ **一次性查询(无需安装):**
34
+
35
+ ```bash
36
+ npx glm-quota-line
37
+ ```
38
+
39
+ **状态栏集成(需要全局安装):**
40
+
29
41
  ```bash
30
42
  npm install -g glm-quota-line
31
43
  glm-quota-line install
@@ -34,7 +46,7 @@ glm-quota-line install
34
46
  安装完成。Claude Code 底部状态栏会自动显示配额:
35
47
 
36
48
  ```
37
- GLM Lite █████████░ 91% | W 47% | 14:47 | ctx ███░░░ 45%
49
+ GLM Lite █████████░ 91% | W ▒▒▒▒░░░░░ 47% | 14:47 | ctx ███░░░ 45% (glm-4.7/200K)
38
50
  ```
39
51
 
40
52
  也可以直接在终端运行 `glm-quota-line` 快速查看用量,无需启动 Claude Code。
@@ -54,7 +66,7 @@ glm-quota-line check-update
54
66
 
55
67
  | 值 | 说明 | 示例 |
56
68
  |---|---|---|
57
- | `bar`(默认) | 进度条可视化 | `GLM Lite █████████░ 91% \| W 47% \| 14:47 \| ctx ███░░░ 45%` |
69
+ | `bar`(默认) | 进度条可视化 | `GLM Lite █████████░ 91% \| W ▒▒▒▒░░░░░ 47% \| 14:47 \| ctx ███░░░ 45%` |
58
70
  | `text` | 完整文本 | `GLM Lite \| 5h 91% \| week 47% \| reset 14:47 \| ctx 45%` |
59
71
  | `compact` | 紧凑模式 | `GLM 5h 91% W 47% \| 14:47` |
60
72
 
@@ -91,24 +103,71 @@ glm-quota-line config set theme light
91
103
  glm-quota-line config set display used
92
104
  ```
93
105
 
94
- ### ctx — 上下文窗口用量
106
+ ### work-days — 每周工作日
95
107
 
96
- 在状态栏显示当前 Claude Code 上下文窗口的使用百分比(仅状态栏模式)。
108
+ 设置每周工作日数量(1-7),用于计算周配额的理论预算和配速分析。默认 5 天。
97
109
 
98
- | 值 | 说明 |
99
- |---|---|
100
- | `on`(默认) | 显示上下文窗口用量 |
101
- | `off` | 隐藏上下文窗口用量 |
110
+ ```bash
111
+ glm-quota-line config set work-days 6
112
+ ```
113
+
114
+ 配速分析会根据已过工作日计算理论预算,并判断使用速度:
115
+ - 绿色 — 使用速度 ≤ 1.1x 理论值
116
+ - 黄色 — 使用速度 1.1x–1.3x 理论值
117
+ - 红色 — 使用速度 > 1.3x 理论值
118
+
119
+ ### minimalist — 极简模式
120
+
121
+ 隐藏所有标签文字,只保留进度条和数值。
102
122
 
103
123
  ```bash
104
- glm-quota-line config set ctx off
124
+ glm-quota-line config set minimalist true
105
125
  ```
106
126
 
107
- 上下文用量会根据已用比例自动变色:
127
+ 效果对比:
128
+ - 关闭:`GLM Lite █████████░ 91% | W ▒▒▒▒░░░░░ 47% | 14:47`
129
+ - 开启:`█████████░ 91% | ▒▒▒▒░░░░░ 47% | 14:47`
108
130
 
109
- - 绿色 — 已用 < 60%
110
- - 黄色 — 已用 60%–79%
111
- - 红色 — 已用 >= 80%
131
+ ### raw-values — 原始数值
132
+
133
+ 隐藏所有标签文字,直接显示原始数值。
134
+
135
+ ```bash
136
+ glm-quota-line config set raw-values true
137
+ ```
138
+
139
+ ### --json — JSON 输出
140
+
141
+ 输出结构化 JSON 格式(仅终端模式,状态栏模式忽略):
142
+
143
+ ```bash
144
+ glm-quota-line --json
145
+ ```
146
+
147
+ 输出示例:
148
+ ```json
149
+ {
150
+ "level": "Lite",
151
+ "quotas": [
152
+ {
153
+ "label": "5h",
154
+ "leftPercent": 91,
155
+ "usedPercent": 9,
156
+ "nextResetTime": 1715257200000
157
+ },
158
+ {
159
+ "label": "week",
160
+ "leftPercent": 47,
161
+ "usedPercent": 53,
162
+ "nextResetTime": 1715744400000
163
+ }
164
+ ],
165
+ "mcp": {
166
+ "leftPercent": 85,
167
+ "usedPercent": 15
168
+ }
169
+ }
170
+ ```
112
171
 
113
172
  ### auth-token / base-url — 自定义鉴权
114
173
 
@@ -129,6 +188,29 @@ glm-quota-line config set base-url https://api.z.ai/api/anthropic
129
188
  2. 环境变量 `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_BASE_URL`
130
189
  3. `~/.claude/settings.json` 中的 `env` 字段
131
190
 
191
+ ### configure — 交互式 TUI 配置
192
+
193
+ 启动终端交互界面,实时预览状态栏效果,逐项调整组件开关、样式和全局选项。
194
+
195
+ ```bash
196
+ glm-quota-line configure
197
+ ```
198
+
199
+ 操作方式:
200
+ - `↑↓` 选择组件,`Enter` 进入编辑,`Tab` 切换样式,`Space` 开关显示
201
+ - `g` 进入全局选项(主题、显示模式、极简模式、原始数值)
202
+ - `s` 保存,`q` 退出
203
+
204
+ 组件列表:
205
+
206
+ | 组件 | 说明 | 可设置样式 | 可隐藏 |
207
+ |---|---|---|---|
208
+ | `level` | 套餐级别(如 GLM Lite) | — | ✓ |
209
+ | `5h` | 5 小时配额 | ✓ (bar/text) | —(必需) |
210
+ | `week` | 周配额 | ✓ (bar/text) | ✓ |
211
+ | `reset` | 重置时间 | — | ✓ |
212
+ | `ctx` | 上下文窗口用量 | ✓ (bar/text) | ✓ |
213
+
132
214
  ## 推荐搭配
133
215
 
134
216
  | 使用场景 | 配置 |
@@ -137,17 +219,22 @@ glm-quota-line config set base-url https://api.z.ai/api/anthropic
137
219
  | 浅色终端 | `style=bar`, `theme=light` |
138
220
  | 极简工作流 | `style=compact`, `theme=mono` |
139
221
  | 关注已用量 | `style=bar`, `display=used` |
222
+ | 脚本调用 | `--json` |
223
+ | 6 天工作制 | `work-days=6` |
224
+ | 极简数值 | `minimalist=true` |
225
+ | 交互式配置 | `glm-quota-line configure` |
140
226
 
141
227
  ## 命令参考
142
228
 
143
229
  ```bash
144
- glm-quota-line [--style text|compact|bar] [--display left|used] [--theme dark|light|mono] [--ctx on|off]
230
+ glm-quota-line [--style text|compact|bar] [--display left|used] [--theme dark|light|mono] [--json]
145
231
  glm-quota-line install [--force]
146
232
  glm-quota-line uninstall
147
233
  glm-quota-line version
148
234
  glm-quota-line check-update
235
+ glm-quota-line configure
149
236
  glm-quota-line config show
150
- glm-quota-line config set <style|display|theme|ctx|auth-token|base-url> <value>
237
+ glm-quota-line config set <style|display|theme|auth-token|base-url|work-days|minimalist|raw-values> <value>
151
238
  glm-quota-line config unset <key>
152
239
  ```
153
240
 
@@ -155,11 +242,16 @@ glm-quota-line config unset <key>
155
242
 
156
243
  ## 说明
157
244
 
158
- - 展示 `TOKENS_LIMIT` 配额和 `MCP_LIMIT` 配额,忽略 `TIME_LIMIT`
159
- - 状态栏默认显示上下文窗口用量,可通过 `--ctx off` 或 `config set ctx off` 关闭
245
+ - 展示 `TOKENS_LIMIT` 配额和 `MCP_LIMIT` / `TIME_LIMIT` 配额
246
+ - 周配额进度条中的阴影(▒)是每日应耗基准线:根据已过工作日计算的理论预算,已用部分(█)超过阴影越多,说明消耗越快
247
+ - 状态栏默认显示上下文窗口用量和模型信息,可通过 `glm-quota-line configure` 交互式关闭
248
+ - 每个组件可单独控制开关和样式,通过 `glm-quota-line configure` 交互式调整
249
+ - 上下文窗口使用率优先从原始 token 数计算,当模型映射不可用时回退到 API 提供的百分比
160
250
  - 鉴权缺失返回 `GLM | auth expired`;接口异常返回 `GLM | quota unavailable`
251
+ - 非 GLM 提供商(非智谱 AI 端点)会自动禁用配额查询
161
252
  - `install` 默认不会覆盖非本工具管理的状态栏,除非使用 `--force`
162
253
  - `install --force` 会备份旧配置,`uninstall` 会在可能时恢复
254
+ - 设置 `GLM_QUOTA_DEBUG=1` 可输出上下文窗口调试信息到 stderr
163
255
 
164
256
  ## 许可证
165
257
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glm-quota-line",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Zhipu GLM Coding Plan quota monitor for Claude Code status line.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -13,7 +13,8 @@
13
13
  "z.ai",
14
14
  "coding-plan",
15
15
  "quota",
16
- "statusline"
16
+ "statusline",
17
+ "tui"
17
18
  ],
18
19
  "repository": {
19
20
  "type": "git",
@@ -1,9 +1,10 @@
1
1
  import { loadConfig } from "../shared/config.js";
2
+ import { clearCtxCache } from "../core/quota/cache.js";
2
3
  import { resolveQuotaStatus } from "../core/quota/service.js";
3
4
  import { readStatusLineInput } from "./input.js";
4
5
  import { readToolConfig } from "./settings.js";
5
6
 
6
- export const SESSION_START_MATCHERS = ["startup", "resume", "clear"];
7
+ export const SESSION_START_MATCHERS = ["startup", "resume", "clear", "compact"];
7
8
 
8
9
  export async function refreshQuotaOnSessionStart(options = {}) {
9
10
  const hookInput = await readStatusLineInput(options.stdin ?? process.stdin);
@@ -15,6 +16,10 @@ export async function refreshQuotaOnSessionStart(options = {}) {
15
16
  sessionId: hookInput?.session_id || ""
16
17
  };
17
18
 
19
+ if (hookInput?.source === "compact" || hookInput?.source === "clear" || hookInput?.source === "startup") {
20
+ await clearCtxCache(config.cacheFilePath).catch(() => {});
21
+ }
22
+
18
23
  return resolveQuotaStatusFn(config, {
19
24
  now: options.now,
20
25
  fetchImpl: options.fetchImpl,
@@ -6,10 +6,12 @@ import {
6
6
  TOOL_CONFIG_SCHEMA_VERSION,
7
7
  isValidDisplayMode,
8
8
  isValidStatusStyle,
9
- isValidTheme
9
+ isValidTheme,
10
+ isValidWorkDays
10
11
  } from "../shared/constants.js";
12
+ import { migrateOldConfig, needsMigration } from "../shared/migration.js";
13
+ import { normalizeOptionalString } from "../shared/utils.js";
11
14
  import { readJsonFile, writeJsonFile } from "../shared/jsonFile.js";
12
- import { normalizeOptionalString } from "../shared/config.js";
13
15
 
14
16
  function getClaudeDir() {
15
17
  return path.join(os.homedir(), ".claude");
@@ -55,8 +57,16 @@ function normalizeToolConfig(config) {
55
57
  normalized.theme = base.theme;
56
58
  }
57
59
 
58
- if (typeof base.ctxEnabled === "boolean") {
59
- normalized.ctxEnabled = base.ctxEnabled;
60
+ if (isValidWorkDays(base.workDays)) {
61
+ normalized.workDays = base.workDays;
62
+ }
63
+
64
+ if (typeof base.minimalist === "boolean") {
65
+ normalized.minimalist = base.minimalist;
66
+ }
67
+
68
+ if (typeof base.rawValues === "boolean") {
69
+ normalized.rawValues = base.rawValues;
60
70
  }
61
71
 
62
72
  const authToken = normalizeOptionalString(base.authToken);
@@ -69,12 +79,31 @@ function normalizeToolConfig(config) {
69
79
  normalized.baseUrl = baseUrl;
70
80
  }
71
81
 
82
+ // Preserve lines (component-level config) as-is
83
+ if (base.lines && Array.isArray(base.lines)) {
84
+ normalized.lines = base.lines;
85
+ }
86
+
72
87
  return normalized;
73
88
  }
74
89
 
75
90
  export async function readToolConfig(configPath = getToolConfigPath()) {
76
91
  const parsed = await readJsonFile(configPath, {});
77
- return normalizeToolConfig(parsed);
92
+ const normalized = normalizeToolConfig(parsed);
93
+
94
+ // Migrate legacy ctxEnabled to lines-based format
95
+ if (needsMigration(parsed)) {
96
+ const migrated = migrateOldConfig({
97
+ ctxEnabled: parsed.ctxEnabled,
98
+ theme: parsed.theme,
99
+ displayMode: parsed.displayMode,
100
+ style: parsed.style
101
+ });
102
+ normalized.lines = migrated.lines;
103
+ await writeJsonFile(configPath, normalizeToolConfig({ ...parsed, lines: migrated.lines }));
104
+ }
105
+
106
+ return normalized;
78
107
  }
79
108
 
80
109
  export async function writeToolConfig(config, configPath = getToolConfigPath()) {
package/src/cli/args.js CHANGED
@@ -9,6 +9,16 @@ function takeValue(args, index) {
9
9
  return next ?? "";
10
10
  }
11
11
 
12
+ const FLAGS = [
13
+ { names: ["--style"], dest: "style" },
14
+ { names: ["--display"], dest: "displayMode" },
15
+ { names: ["--theme"], dest: "theme" },
16
+ { names: ["--force"], dest: "force", boolean: true },
17
+ { names: ["--json"], dest: "json", boolean: true },
18
+ { names: ["--help", "-h"], dest: "help", boolean: true },
19
+ { names: ["--version", "-v"], dest: "version", boolean: true }
20
+ ];
21
+
12
22
  export function parseArgs(argv = process.argv.slice(2)) {
13
23
  const options = {};
14
24
  const positionals = [];
@@ -21,57 +31,44 @@ export function parseArgs(argv = process.argv.slice(2)) {
21
31
  continue;
22
32
  }
23
33
 
24
- if (arg === "--help" || arg === "-h") {
25
- options.help = true;
26
- continue;
27
- }
28
-
29
- if (arg === "--version" || arg === "-v") {
30
- options.version = true;
31
- continue;
32
- }
34
+ let matched = false;
35
+ for (const flag of FLAGS) {
36
+ const isMatch = flag.names.some(
37
+ (name) => arg === name || arg.startsWith(`${name}=`)
38
+ );
39
+ if (!isMatch) {
40
+ continue;
41
+ }
33
42
 
34
- if (arg === "--force") {
35
- options.force = true;
36
- continue;
37
- }
43
+ matched = true;
38
44
 
39
- if (arg === "--style" || arg.startsWith("--style=")) {
40
- options.style = takeValue(argv, index);
41
- if (!arg.includes("=")) {
42
- index += 1;
45
+ if (flag.boolean) {
46
+ options[flag.dest] = true;
47
+ break;
43
48
  }
44
- continue;
45
- }
46
49
 
47
- if (arg === "--display" || arg.startsWith("--display=")) {
48
- options.displayMode = takeValue(argv, index);
50
+ const rawValue = takeValue(argv, index);
49
51
  if (!arg.includes("=")) {
50
52
  index += 1;
51
53
  }
52
- continue;
53
- }
54
54
 
55
- if (arg === "--theme" || arg.startsWith("--theme=")) {
56
- options.theme = takeValue(argv, index);
57
- if (!arg.includes("=")) {
58
- index += 1;
55
+ if (flag.parse) {
56
+ const result = flag.parse(rawValue);
57
+ if (result.error) {
58
+ process.stderr.write(result.error);
59
+ process.exitCode = 1;
60
+ options.positionals = positionals;
61
+ return options;
62
+ }
63
+ options[flag.dest] = result.value;
64
+ } else {
65
+ options[flag.dest] = rawValue;
59
66
  }
60
- continue;
67
+ break;
61
68
  }
62
69
 
63
- if (arg === "--ctx" || arg.startsWith("--ctx=")) {
64
- const val = takeValue(argv, index);
65
- if (val !== "on" && val !== "off") {
66
- process.stderr.write("Error: --ctx requires on or off\n");
67
- process.exitCode = 1;
68
- return options;
69
- }
70
- options.ctxEnabled = val === "on";
71
- if (!arg.includes("=")) {
72
- index += 1;
73
- }
74
- continue;
70
+ if (!matched) {
71
+ // Unknown flags are ignored to allow forward-compatibility
75
72
  }
76
73
  }
77
74