wezterm-codex-status-line 0.1.1__tar.gz
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.
- wezterm_codex_status_line-0.1.1/.gitignore +5 -0
- wezterm_codex_status_line-0.1.1/LICENSE +21 -0
- wezterm_codex_status_line-0.1.1/PKG-INFO +52 -0
- wezterm_codex_status_line-0.1.1/README.md +37 -0
- wezterm_codex_status_line-0.1.1/pyproject.toml +34 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/__init__.py +1 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/config.lua +456 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/domain/common.lua +28 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/domain/prices.lua +16 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/domain/pricing.lua +87 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/domain/process.lua +260 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/domain/render.lua +511 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/domain/session.lua +449 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/formatting.lua +268 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/git.lua +72 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/layout.lua +53 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/legacy_renderer.lua +342 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/lifecycle.lua +421 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/process.lua +216 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/renderer.lua +342 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/rollout.lua +390 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/session_index.lua +563 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/state.lua +62 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/util.lua +244 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/version.lua +4 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/wezterm_adapter.lua +211 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline.lua +44 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline_bridge.js +69 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline_bridge.ps1 +285 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline_bridge.py +255 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline_core.lua +8 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/contract/config.schema.json +281 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/contract/default-config.json +180 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/contract/model-pricing.json +21 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/contract/render-cases.json +198 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/contract/sample-state.json +34 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/contract/usage-cases.json +23 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/install.ps1 +822 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/cli.py +677 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/pricing.py +75 -0
- wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/render.py +338 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lambda
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: wezterm-codex-status-line
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Install and configure the WezTerm Codex status line
|
|
5
|
+
Project-URL: Documentation, https://un4gt.github.io/wezterm-codex-status-line/
|
|
6
|
+
Project-URL: Repository, https://github.com/un4gt/wezterm-codex-status-line
|
|
7
|
+
Author: un4gt
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Requires-Dist: jsonschema<5,>=4.23
|
|
12
|
+
Requires-Dist: questionary<3,>=2.1
|
|
13
|
+
Requires-Dist: typer<1,>=0.16
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# WezTerm Codex Status Line
|
|
17
|
+
|
|
18
|
+
为 WezTerm 中的 Codex CLI 添加底部状态栏,显示模型、推理强度、Git 分支和 Token 用量。
|
|
19
|
+
|
|
20
|
+
## 安装
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
uvx wezterm-codex-status-line install --no-title-bridge
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
安装后,在 WezTerm 配置的 `return config` 之前加入:
|
|
27
|
+
|
|
28
|
+
```lua
|
|
29
|
+
require("codex_statusline").setup()
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
重新加载 WezTerm 配置,然后启动 Codex。平台要求见[安装指南](https://un4gt.github.io/wezterm-codex-status-line/docs/getting-started/installation/);macOS 暂未完成实机验证,Linux 暂未完成 Wayland/X11 桌面验证。
|
|
33
|
+
|
|
34
|
+
## 配置
|
|
35
|
+
|
|
36
|
+
在[交互预览](https://un4gt.github.io/wezterm-codex-status-line/preview/)中调整显示并下载 JSON,然后导入:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
uvx wezterm-codex-status-line configure --from ./codex_statusline_config.json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
重新加载 WezTerm 配置以应用修改。完整步骤见[配置指南](https://un4gt.github.io/wezterm-codex-status-line/docs/guides/configuration/)。
|
|
43
|
+
|
|
44
|
+
## 命令
|
|
45
|
+
|
|
46
|
+
`install` 安装,`configure` 配置,`preview` 预览,`doctor` 检查,`update` 更新,`uninstall` 卸载。
|
|
47
|
+
|
|
48
|
+
参数见[命令行参考](https://un4gt.github.io/wezterm-codex-status-line/docs/guides/cli-reference/)。卸载前先移除 WezTerm 配置中的模块引用并重新加载配置。
|
|
49
|
+
|
|
50
|
+
## 许可证
|
|
51
|
+
|
|
52
|
+
MIT
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# WezTerm Codex Status Line
|
|
2
|
+
|
|
3
|
+
为 WezTerm 中的 Codex CLI 添加底部状态栏,显示模型、推理强度、Git 分支和 Token 用量。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
uvx wezterm-codex-status-line install --no-title-bridge
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
安装后,在 WezTerm 配置的 `return config` 之前加入:
|
|
12
|
+
|
|
13
|
+
```lua
|
|
14
|
+
require("codex_statusline").setup()
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
重新加载 WezTerm 配置,然后启动 Codex。平台要求见[安装指南](https://un4gt.github.io/wezterm-codex-status-line/docs/getting-started/installation/);macOS 暂未完成实机验证,Linux 暂未完成 Wayland/X11 桌面验证。
|
|
18
|
+
|
|
19
|
+
## 配置
|
|
20
|
+
|
|
21
|
+
在[交互预览](https://un4gt.github.io/wezterm-codex-status-line/preview/)中调整显示并下载 JSON,然后导入:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
uvx wezterm-codex-status-line configure --from ./codex_statusline_config.json
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
重新加载 WezTerm 配置以应用修改。完整步骤见[配置指南](https://un4gt.github.io/wezterm-codex-status-line/docs/guides/configuration/)。
|
|
28
|
+
|
|
29
|
+
## 命令
|
|
30
|
+
|
|
31
|
+
`install` 安装,`configure` 配置,`preview` 预览,`doctor` 检查,`update` 更新,`uninstall` 卸载。
|
|
32
|
+
|
|
33
|
+
参数见[命令行参考](https://un4gt.github.io/wezterm-codex-status-line/docs/guides/cli-reference/)。卸载前先移除 WezTerm 配置中的模块引用并重新加载配置。
|
|
34
|
+
|
|
35
|
+
## 许可证
|
|
36
|
+
|
|
37
|
+
MIT
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "wezterm-codex-status-line"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Install and configure the WezTerm Codex status line"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{name = "un4gt"}]
|
|
14
|
+
dependencies = [
|
|
15
|
+
"jsonschema>=4.23,<5",
|
|
16
|
+
"questionary>=2.1,<3",
|
|
17
|
+
"typer>=0.16,<1"
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
Documentation = "https://un4gt.github.io/wezterm-codex-status-line/"
|
|
22
|
+
Repository = "https://github.com/un4gt/wezterm-codex-status-line"
|
|
23
|
+
|
|
24
|
+
[project.scripts]
|
|
25
|
+
wezterm-codex-status-line = "wezterm_codex_status_line.cli:main"
|
|
26
|
+
|
|
27
|
+
[tool.hatch.build]
|
|
28
|
+
artifacts = ["/src/wezterm_codex_status_line/assets/**", "/LICENSE"]
|
|
29
|
+
|
|
30
|
+
[tool.hatch.build.targets.wheel]
|
|
31
|
+
packages = ["src/wezterm_codex_status_line"]
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.sdist]
|
|
34
|
+
include = ["src", "README.md", "LICENSE", "pyproject.toml"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.1"
|
wezterm_codex_status_line-0.1.1/src/wezterm_codex_status_line/assets/codex_statusline/config.lua
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
local core = require("codex_statusline_core")
|
|
2
|
+
local util = require("codex_statusline.util")
|
|
3
|
+
local M = {}
|
|
4
|
+
|
|
5
|
+
function M.new(wezterm, adapter)
|
|
6
|
+
local trim = util.trim
|
|
7
|
+
local path_join = util.path_join
|
|
8
|
+
local read_file = util.read_file
|
|
9
|
+
local shallow_merge = util.shallow_merge
|
|
10
|
+
local resolved_module_path = util.resolved_module_path
|
|
11
|
+
local safe_json_parse = adapter.safe_json_parse
|
|
12
|
+
local CONFIG_CACHE = {
|
|
13
|
+
at = 0,
|
|
14
|
+
loaded = false,
|
|
15
|
+
values = nil,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
local function strip_toml_comment(line)
|
|
19
|
+
local in_single = false
|
|
20
|
+
local in_double = false
|
|
21
|
+
|
|
22
|
+
local i = 1
|
|
23
|
+
while i <= #line do
|
|
24
|
+
local ch = line:sub(i, i)
|
|
25
|
+
|
|
26
|
+
if ch == "'" and not in_double then
|
|
27
|
+
in_single = not in_single
|
|
28
|
+
elseif ch == '"' and not in_single then
|
|
29
|
+
local backslashes = 0
|
|
30
|
+
local j = i - 1
|
|
31
|
+
while j >= 1 and line:sub(j, j) == "\\" do
|
|
32
|
+
backslashes = backslashes + 1
|
|
33
|
+
j = j - 1
|
|
34
|
+
end
|
|
35
|
+
if backslashes % 2 == 0 then
|
|
36
|
+
in_double = not in_double
|
|
37
|
+
end
|
|
38
|
+
elseif ch == "#" and not in_single and not in_double then
|
|
39
|
+
return line:sub(1, i - 1)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
i = i + 1
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
return line
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
local function parse_toml_scalar(value)
|
|
49
|
+
local v = trim(value)
|
|
50
|
+
if not v then
|
|
51
|
+
return nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if v:sub(1, 1) == '"' and v:sub(-1) == '"' and #v >= 2 then
|
|
55
|
+
local inner = v:sub(2, -2)
|
|
56
|
+
inner = inner:gsub("\\\\", "\\"):gsub('\\"', '"')
|
|
57
|
+
return inner
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if v:sub(1, 1) == "'" and v:sub(-1) == "'" and #v >= 2 then
|
|
61
|
+
return v:sub(2, -2)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
return v
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
local function default_codex_config_paths()
|
|
68
|
+
local home = wezterm.home_dir or os.getenv("USERPROFILE") or os.getenv("HOME")
|
|
69
|
+
if not home then
|
|
70
|
+
return nil
|
|
71
|
+
end
|
|
72
|
+
local codex_dir = path_join({ home, ".codex" })
|
|
73
|
+
return {
|
|
74
|
+
path_join({ codex_dir, "config.toml" }),
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
local function default_codex_home()
|
|
79
|
+
local explicit = trim(os.getenv("CODEX_HOME"))
|
|
80
|
+
if explicit then
|
|
81
|
+
return explicit
|
|
82
|
+
end
|
|
83
|
+
local home = wezterm.home_dir or os.getenv("USERPROFILE") or os.getenv("HOME")
|
|
84
|
+
if not home then
|
|
85
|
+
return nil
|
|
86
|
+
end
|
|
87
|
+
return path_join({ home, ".codex" })
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
local function codex_home_for_opts(opts)
|
|
91
|
+
return trim(opts and opts.codex_home) or default_codex_home()
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
local function bridge_root_for_opts(opts)
|
|
95
|
+
local configured = opts and opts.sessions and trim(opts.sessions.bridge_dir) or nil
|
|
96
|
+
if configured then
|
|
97
|
+
return configured
|
|
98
|
+
end
|
|
99
|
+
local codex_home = codex_home_for_opts(opts)
|
|
100
|
+
if not codex_home then
|
|
101
|
+
return nil
|
|
102
|
+
end
|
|
103
|
+
return path_join({ codex_home, "wezterm-statusline" })
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
local function load_codex_config(opts)
|
|
107
|
+
if not opts.codex_config.enabled then
|
|
108
|
+
return nil
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
local now = os.time()
|
|
112
|
+
if CONFIG_CACHE.loaded and (now - CONFIG_CACHE.at) < opts.codex_config.cache_ttl_seconds then
|
|
113
|
+
return CONFIG_CACHE.values
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
local paths = {}
|
|
117
|
+
if trim(opts.codex_config.path) then
|
|
118
|
+
table.insert(paths, opts.codex_config.path)
|
|
119
|
+
else
|
|
120
|
+
local defaults = default_codex_config_paths()
|
|
121
|
+
if defaults then
|
|
122
|
+
for _, p in ipairs(defaults) do
|
|
123
|
+
table.insert(paths, p)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
if #paths == 0 then
|
|
128
|
+
CONFIG_CACHE.values = nil
|
|
129
|
+
CONFIG_CACHE.at = now
|
|
130
|
+
CONFIG_CACHE.loaded = true
|
|
131
|
+
return nil
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
local text = nil
|
|
135
|
+
for _, p in ipairs(paths) do
|
|
136
|
+
text = read_file(p)
|
|
137
|
+
if text then
|
|
138
|
+
break
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
if not text then
|
|
142
|
+
CONFIG_CACHE.values = nil
|
|
143
|
+
CONFIG_CACHE.at = now
|
|
144
|
+
CONFIG_CACHE.loaded = true
|
|
145
|
+
return nil
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
local values = {}
|
|
149
|
+
for line in text:gmatch("[^\r\n]+") do
|
|
150
|
+
local raw = trim(line)
|
|
151
|
+
if raw and raw:sub(1, 1) ~= "#" then
|
|
152
|
+
if raw:sub(1, 1) == "[" then
|
|
153
|
+
break
|
|
154
|
+
end
|
|
155
|
+
local eq = raw:find("=", 1, true)
|
|
156
|
+
if eq then
|
|
157
|
+
local key = trim(raw:sub(1, eq - 1))
|
|
158
|
+
local rhs = strip_toml_comment(raw:sub(eq + 1))
|
|
159
|
+
local val = parse_toml_scalar(rhs)
|
|
160
|
+
if key and val then
|
|
161
|
+
values[key] = val
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
CONFIG_CACHE.values = {
|
|
168
|
+
model = trim(values.model),
|
|
169
|
+
thinking = trim(values.model_reasoning_effort or values.reasoning_effort),
|
|
170
|
+
provider = trim(values.model_provider or values.provider),
|
|
171
|
+
service_tier = trim(values.service_tier),
|
|
172
|
+
}
|
|
173
|
+
CONFIG_CACHE.at = now
|
|
174
|
+
CONFIG_CACHE.loaded = true
|
|
175
|
+
|
|
176
|
+
return CONFIG_CACHE.values
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
local DEFAULTS = {
|
|
180
|
+
debug = false,
|
|
181
|
+
label = "CODEX",
|
|
182
|
+
log = {
|
|
183
|
+
enabled = true,
|
|
184
|
+
marker = "CODEX_STATUSLINE_LOADED",
|
|
185
|
+
},
|
|
186
|
+
compat = {
|
|
187
|
+
-- Older WezTerm builds used `update-right-status` instead of `update-status`.
|
|
188
|
+
-- Enable if you don't see `update-status` events firing.
|
|
189
|
+
update_right_status = false,
|
|
190
|
+
},
|
|
191
|
+
codex_config = {
|
|
192
|
+
enabled = true,
|
|
193
|
+
path = nil,
|
|
194
|
+
cache_ttl_seconds = 5,
|
|
195
|
+
},
|
|
196
|
+
title_bridge = {
|
|
197
|
+
enabled = true,
|
|
198
|
+
app_name = "codex",
|
|
199
|
+
},
|
|
200
|
+
git = {
|
|
201
|
+
enabled = true,
|
|
202
|
+
cache_ttl_seconds = 5,
|
|
203
|
+
},
|
|
204
|
+
codex_home = nil, -- defaults to $CODEX_HOME or ~/.codex
|
|
205
|
+
user_vars = {
|
|
206
|
+
model = { "codex_model", "CODEX_MODEL" },
|
|
207
|
+
thinking = { "codex_thinking", "CODEX_THINKING", "codex_reasoning", "CODEX_REASONING" },
|
|
208
|
+
provider = { "codex_provider", "CODEX_PROVIDER", "codex_model_provider", "CODEX_MODEL_PROVIDER" },
|
|
209
|
+
active = { "codex_active", "CODEX_ACTIVE" },
|
|
210
|
+
},
|
|
211
|
+
process_match = {
|
|
212
|
+
enabled = true,
|
|
213
|
+
names = { "codex", "codex.exe" },
|
|
214
|
+
argv_markers = { "/@openai/codex/bin/codex.js" },
|
|
215
|
+
terminal_names = {
|
|
216
|
+
"wezterm",
|
|
217
|
+
"wezterm.exe",
|
|
218
|
+
"wezterm-gui",
|
|
219
|
+
"wezterm-gui.exe",
|
|
220
|
+
"wezterm-mux-server-impl",
|
|
221
|
+
"wezterm-mux-server-impl.exe",
|
|
222
|
+
},
|
|
223
|
+
-- Keep the status visible briefly only when process inspection is unavailable.
|
|
224
|
+
grace_seconds = 5,
|
|
225
|
+
tree_cache_ttl_seconds = 1,
|
|
226
|
+
},
|
|
227
|
+
sessions = {
|
|
228
|
+
enabled = true,
|
|
229
|
+
binding_mode = "auto", -- "auto" | "hook" | "heuristic"
|
|
230
|
+
bridge_dir = nil, -- defaults to $CODEX_HOME/wezterm-statusline
|
|
231
|
+
allow_fallback_latest = false,
|
|
232
|
+
resume_fallback_enabled = true,
|
|
233
|
+
resume_fallback_max_age_seconds = 30,
|
|
234
|
+
resume_fallback_clock_skew_seconds = 5,
|
|
235
|
+
resume_fallback_scan_ttl_seconds = 2,
|
|
236
|
+
cache_ttl_seconds = 5,
|
|
237
|
+
full_scan_ttl_seconds = 300,
|
|
238
|
+
tail_ttl_seconds = 1,
|
|
239
|
+
open_fail_clear_seconds = 30,
|
|
240
|
+
initial_seek_bytes = 131072,
|
|
241
|
+
activity_seek_bytes = 65536,
|
|
242
|
+
activity_max_seek_bytes = 8388608,
|
|
243
|
+
max_meta_lines = 40,
|
|
244
|
+
max_tail_lines = 200,
|
|
245
|
+
},
|
|
246
|
+
bottom_pane = {
|
|
247
|
+
enabled = true,
|
|
248
|
+
rows = 1,
|
|
249
|
+
layout_debounce_ms = 1000,
|
|
250
|
+
close_grace_seconds = 2,
|
|
251
|
+
prevent_focus = true,
|
|
252
|
+
},
|
|
253
|
+
render = {
|
|
254
|
+
powerline = true,
|
|
255
|
+
plain_fallback = true,
|
|
256
|
+
model_display = "name", -- "name" | "icon_name" | "icon"
|
|
257
|
+
segment_order = {
|
|
258
|
+
"label",
|
|
259
|
+
"model",
|
|
260
|
+
"reasoning",
|
|
261
|
+
"activity",
|
|
262
|
+
"provider",
|
|
263
|
+
"personality",
|
|
264
|
+
"service_tier",
|
|
265
|
+
"cwd",
|
|
266
|
+
"project",
|
|
267
|
+
"git",
|
|
268
|
+
"permissions",
|
|
269
|
+
"approval",
|
|
270
|
+
"context",
|
|
271
|
+
"context_used",
|
|
272
|
+
"context_window",
|
|
273
|
+
"used_tokens",
|
|
274
|
+
"cache_rate",
|
|
275
|
+
"cost",
|
|
276
|
+
"input_tokens",
|
|
277
|
+
"cached_tokens",
|
|
278
|
+
"output_tokens",
|
|
279
|
+
"reasoning_tokens",
|
|
280
|
+
"thread_id",
|
|
281
|
+
"task_progress",
|
|
282
|
+
"codex_version",
|
|
283
|
+
"icon",
|
|
284
|
+
},
|
|
285
|
+
disabled_segments = {
|
|
286
|
+
"personality",
|
|
287
|
+
"service_tier",
|
|
288
|
+
"project",
|
|
289
|
+
"permissions",
|
|
290
|
+
"approval",
|
|
291
|
+
"context_used",
|
|
292
|
+
"context_window",
|
|
293
|
+
"input_tokens",
|
|
294
|
+
"cached_tokens",
|
|
295
|
+
"output_tokens",
|
|
296
|
+
"reasoning_tokens",
|
|
297
|
+
"thread_id",
|
|
298
|
+
"task_progress",
|
|
299
|
+
"codex_version",
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
activity = {
|
|
303
|
+
labels = {
|
|
304
|
+
plan = "PLAN",
|
|
305
|
+
review = "REVIEW",
|
|
306
|
+
goal_active = "GOAL",
|
|
307
|
+
goal_paused = "GOAL PAUSED",
|
|
308
|
+
goal_blocked = "GOAL BLOCKED",
|
|
309
|
+
goal_usage_limited = "GOAL LIMITED",
|
|
310
|
+
goal_budget_limited = "GOAL BUDGET",
|
|
311
|
+
goal_complete = "GOAL DONE",
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
icon = {
|
|
315
|
+
text = "",
|
|
316
|
+
},
|
|
317
|
+
pricing = { models = {} },
|
|
318
|
+
theme = {
|
|
319
|
+
bg = "#11151a",
|
|
320
|
+
fg = "#d5dbe3",
|
|
321
|
+
dim = "#82909f",
|
|
322
|
+
segments = {
|
|
323
|
+
label = { bg = "#1d4ed8", fg = "#ffffff" },
|
|
324
|
+
model = { bg = "#11151a", fg = "#d5dbe3" },
|
|
325
|
+
reasoning = { bg = "#11151a", fg = "#fbbf24" },
|
|
326
|
+
activity = { bg = "#6d28d9", fg = "#ffffff" },
|
|
327
|
+
provider = { bg = "#11151a", fg = "#aab2bf" },
|
|
328
|
+
personality = { bg = "#11151a", fg = "#c4b5fd" },
|
|
329
|
+
service_tier = { bg = "#11151a", fg = "#f0abfc" },
|
|
330
|
+
cwd = { bg = "#11151a", fg = "#d5dbe3" },
|
|
331
|
+
project = { bg = "#11151a", fg = "#93c5fd" },
|
|
332
|
+
git = { bg = "#11151a", fg = "#4ade80" },
|
|
333
|
+
permissions = { bg = "#11151a", fg = "#fca5a5" },
|
|
334
|
+
approval = { bg = "#11151a", fg = "#fdba74" },
|
|
335
|
+
context = { bg = "#11151a", fg = "#7dd3fc" },
|
|
336
|
+
context_used = { bg = "#11151a", fg = "#67e8f9" },
|
|
337
|
+
context_window = { bg = "#11151a", fg = "#a5b4fc" },
|
|
338
|
+
used_tokens = { bg = "#11151a", fg = "#d5dbe3" },
|
|
339
|
+
cache_rate = { bg = "#11151a", fg = "#67e8f9" },
|
|
340
|
+
cost = { bg = "#11151a", fg = "#fbbf24" },
|
|
341
|
+
input_tokens = { bg = "#11151a", fg = "#86efac" },
|
|
342
|
+
cached_tokens = { bg = "#11151a", fg = "#94a3b8" },
|
|
343
|
+
output_tokens = { bg = "#11151a", fg = "#fde68a" },
|
|
344
|
+
reasoning_tokens = { bg = "#11151a", fg = "#f0abfc" },
|
|
345
|
+
thread_id = { bg = "#11151a", fg = "#94a3b8" },
|
|
346
|
+
task_progress = { bg = "#11151a", fg = "#5eead4" },
|
|
347
|
+
codex_version = { bg = "#11151a", fg = "#aab2bf" },
|
|
348
|
+
icon = { bg = "#11151a", fg = "#58d6c5" },
|
|
349
|
+
-- Backward-compatible theme keys for existing setup() overrides.
|
|
350
|
+
thinking = { bg = "#11151a", fg = "#fbbf24" },
|
|
351
|
+
tokens = { bg = "#11151a", fg = "#d5dbe3" },
|
|
352
|
+
},
|
|
353
|
+
glyphs = {
|
|
354
|
+
sep = "",
|
|
355
|
+
branch = "",
|
|
356
|
+
folder = "",
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
local function managed_config_path()
|
|
362
|
+
local module_path = resolved_module_path()
|
|
363
|
+
if not module_path then
|
|
364
|
+
return nil
|
|
365
|
+
end
|
|
366
|
+
local directory = module_path:match("^(.*)[/\\][^/\\]+$")
|
|
367
|
+
if not directory then
|
|
368
|
+
return nil
|
|
369
|
+
end
|
|
370
|
+
return path_join({ directory, "codex_statusline_config.json" })
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
local function load_managed_config()
|
|
374
|
+
if type(io) ~= "table" or type(io.open) ~= "function" then
|
|
375
|
+
return nil
|
|
376
|
+
end
|
|
377
|
+
local path = managed_config_path()
|
|
378
|
+
if not path then
|
|
379
|
+
return nil
|
|
380
|
+
end
|
|
381
|
+
local handle = io.open(path, "r")
|
|
382
|
+
if not handle then
|
|
383
|
+
return nil
|
|
384
|
+
end
|
|
385
|
+
local content = handle:read("*a")
|
|
386
|
+
handle:close()
|
|
387
|
+
local value = safe_json_parse(content)
|
|
388
|
+
if type(value) ~= "table" or tonumber(value.schema) ~= 1 or type(value.options) ~= "table" then
|
|
389
|
+
wezterm.log_error("codex_statusline: ignoring invalid managed config " .. tostring(path))
|
|
390
|
+
return nil
|
|
391
|
+
end
|
|
392
|
+
return value.options
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
local function resolve(user_opts)
|
|
396
|
+
local opts = shallow_merge(DEFAULTS, load_managed_config())
|
|
397
|
+
opts = shallow_merge(opts, user_opts)
|
|
398
|
+
|
|
399
|
+
for _, name in ipairs({
|
|
400
|
+
"log",
|
|
401
|
+
"compat",
|
|
402
|
+
"codex_config",
|
|
403
|
+
"title_bridge",
|
|
404
|
+
"git",
|
|
405
|
+
"user_vars",
|
|
406
|
+
"process_match",
|
|
407
|
+
"sessions",
|
|
408
|
+
"bottom_pane",
|
|
409
|
+
"activity",
|
|
410
|
+
"icon",
|
|
411
|
+
"pricing",
|
|
412
|
+
"render",
|
|
413
|
+
"theme",
|
|
414
|
+
}) do
|
|
415
|
+
if type(opts[name]) ~= "table" then
|
|
416
|
+
error("invalid option table: " .. name)
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
if type(opts.theme.segments) ~= "table" or type(opts.theme.glyphs) ~= "table" then
|
|
420
|
+
error("invalid theme configuration")
|
|
421
|
+
end
|
|
422
|
+
local model_display = opts.render.model_display
|
|
423
|
+
if model_display ~= "name" and model_display ~= "icon_name" and model_display ~= "icon" then
|
|
424
|
+
error("render.model_display must be name, icon_name, or icon")
|
|
425
|
+
end
|
|
426
|
+
local pricing = require("codex_statusline.domain.pricing")
|
|
427
|
+
if type(opts.pricing.models) ~= "table" then error("pricing.models must be a table") end
|
|
428
|
+
local price_count = 0
|
|
429
|
+
for model, price in pairs(opts.pricing.models) do
|
|
430
|
+
price_count = price_count + 1
|
|
431
|
+
if not pricing.valid_model(model) or not pricing.valid_price(price) then
|
|
432
|
+
error("invalid pricing.models entry: " .. tostring(model))
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
if price_count > 64 then error("pricing.models supports at most 64 entries") end
|
|
436
|
+
|
|
437
|
+
local delay = opts.bottom_pane.layout_debounce_ms
|
|
438
|
+
if type(delay) ~= "number" or delay % 1 ~= 0 or delay < 250 or delay > 5000 then
|
|
439
|
+
error("bottom_pane.layout_debounce_ms must be an integer between 250 and 5000")
|
|
440
|
+
end
|
|
441
|
+
if opts.bottom_pane.rows ~= 1 and opts.bottom_pane.rows ~= 2 then
|
|
442
|
+
error("bottom_pane.rows must be 1 or 2")
|
|
443
|
+
end
|
|
444
|
+
return opts
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
return {
|
|
448
|
+
resolve = resolve,
|
|
449
|
+
load_codex_config = load_codex_config,
|
|
450
|
+
codex_home_for_opts = codex_home_for_opts,
|
|
451
|
+
bridge_root_for_opts = bridge_root_for_opts,
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
return M
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
local M = {}
|
|
2
|
+
|
|
3
|
+
local function trim(value)
|
|
4
|
+
if value == nil then
|
|
5
|
+
return nil
|
|
6
|
+
end
|
|
7
|
+
local text = tostring(value):gsub("^%s+", ""):gsub("%s+$", "")
|
|
8
|
+
if text == "" then
|
|
9
|
+
return nil
|
|
10
|
+
end
|
|
11
|
+
return text
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
local function to_number(value)
|
|
15
|
+
if type(value) == "number" then
|
|
16
|
+
return value
|
|
17
|
+
end
|
|
18
|
+
if type(value) == "string" then
|
|
19
|
+
local normalized = value:gsub(",", "")
|
|
20
|
+
return tonumber(normalized)
|
|
21
|
+
end
|
|
22
|
+
return nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
trim = trim,
|
|
27
|
+
to_number = to_number,
|
|
28
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- Generated from contract/model-pricing.json by scripts/sync-model-pricing.mjs.
|
|
2
|
+
-- https://developers.openai.com/api/docs/pricing (verified 2026-09-14; USD / 1M tokens, standard short context)
|
|
3
|
+
return {
|
|
4
|
+
["gpt-6-astra"] = { input = 10, cached_input = 1, output = 50 },
|
|
5
|
+
["gpt-5.6-sol"] = { input = 4, cached_input = 0.4, output = 20 },
|
|
6
|
+
["gpt-5.6-terra"] = { input = 2, cached_input = 0.2, output = 12 },
|
|
7
|
+
["gpt-5.6-luna"] = { input = 0.2, cached_input = 0.02, output = 1.2 },
|
|
8
|
+
["gpt-5.5"] = { input = 5, cached_input = 0.5, output = 30 },
|
|
9
|
+
["gpt-5.4"] = { input = 2.5, cached_input = 0.25, output = 15 },
|
|
10
|
+
["gpt-5.4-mini"] = { input = 0.75, cached_input = 0.075, output = 4.5 },
|
|
11
|
+
["gpt-5.4-nano"] = { input = 0.2, cached_input = 0.02, output = 1.25 },
|
|
12
|
+
["gpt-5.3-codex"] = { input = 1.75, cached_input = 0.175, output = 14 },
|
|
13
|
+
["gpt-5.2"] = { input = 1.75, cached_input = 0.175, output = 14 },
|
|
14
|
+
["gpt-5.1"] = { input = 1.25, cached_input = 0.125, output = 10 },
|
|
15
|
+
["gpt-5"] = { input = 1.25, cached_input = 0.125, output = 10 },
|
|
16
|
+
}
|