@praeviso/code-env-switch 0.1.5 → 0.1.7
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 +12 -0
- package/README_zh.md +12 -0
- package/bin/cli/args.js +13 -0
- package/bin/cli/help.js +5 -0
- package/bin/cli/index.js +2 -1
- package/bin/commands/index.js +3 -1
- package/bin/commands/usage.js +41 -0
- package/bin/index.js +7 -0
- package/bin/statusline/debug.js +1 -0
- package/bin/statusline/usage/codex.js +29 -20
- package/bin/usage/index.js +280 -22
- package/docs/README.md +3 -0
- package/docs/README_zh.md +3 -0
- package/docs/usage.md +126 -0
- package/docs/usage_zh.md +126 -0
- package/package.json +1 -1
- package/src/cli/args.ts +14 -0
- package/src/cli/help.ts +5 -0
- package/src/cli/index.ts +7 -1
- package/src/commands/index.ts +1 -0
- package/src/commands/usage.ts +53 -0
- package/src/index.ts +11 -0
- package/src/statusline/debug.ts +1 -1
- package/src/statusline/usage/codex.ts +26 -31
- package/src/types.ts +4 -0
- package/src/usage/index.ts +293 -25
package/README.md
CHANGED
|
@@ -67,6 +67,8 @@ npm link
|
|
|
67
67
|
> `codenv init`, the shell wrapper applies them automatically.
|
|
68
68
|
> The snippet also wraps `codex`/`claude` to bind sessions to profiles; use
|
|
69
69
|
> `command codex` / `command claude` to bypass.
|
|
70
|
+
> When you switch profiles within the same session, usage tracking and cost
|
|
71
|
+
> display follow the most recently applied profile for subsequent tokens.
|
|
70
72
|
|
|
71
73
|
### Common commands
|
|
72
74
|
|
|
@@ -80,6 +82,16 @@ codenv remove codex primary
|
|
|
80
82
|
`codenv list` (or `codenv ls`) prints a table with `PROFILE`, `TYPE`, and `NOTE`. Default profiles are labeled in the `NOTE` column, and the active profile is shown in green.
|
|
81
83
|
If `profile.name` is set, it is shown in `PROFILE`. Otherwise the profile key is shown (with legacy `type-` prefixes stripped when possible).
|
|
82
84
|
|
|
85
|
+
### Reset usage history
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
codenv usage-reset
|
|
89
|
+
# skip confirmation
|
|
90
|
+
codenv usage-reset --yes
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
This deletes usage history files (`usage.jsonl`, usage state, `profile-log.jsonl`, `statusline-debug.jsonl`) plus any backup variants in the config directory.
|
|
94
|
+
|
|
83
95
|
### Add / update a profile
|
|
84
96
|
|
|
85
97
|
```bash
|
package/README_zh.md
CHANGED
|
@@ -67,6 +67,8 @@ npm link
|
|
|
67
67
|
> shell 包装函数会自动在当前终端生效。
|
|
68
68
|
> 该片段还会包装 `codex`/`claude` 以绑定会话到 profile;如需绕过,
|
|
69
69
|
> 可使用 `command codex` / `command claude`。
|
|
70
|
+
> 同一个 session 内切换 profile 时,后续用量与金额会跟随最新应用的
|
|
71
|
+
> profile 统计。
|
|
70
72
|
|
|
71
73
|
### 常用命令
|
|
72
74
|
|
|
@@ -80,6 +82,16 @@ codenv remove codex primary
|
|
|
80
82
|
`codenv list`(或 `codenv ls`)会输出 `PROFILE` / `TYPE` / `NOTE` 的表格。默认项会标注在 `NOTE` 列,当前激活的配置会用绿色显示。
|
|
81
83
|
如果设置了 `profile.name`,`PROFILE` 列会显示该名称;否则显示 profile 的 key(会尽量去掉旧的 `type-` 前缀)。
|
|
82
84
|
|
|
85
|
+
### 清理用量历史
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
codenv usage-reset
|
|
89
|
+
# 跳过确认
|
|
90
|
+
codenv usage-reset --yes
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
该命令会删除用量历史文件(`usage.jsonl`、用量 state、`profile-log.jsonl`、`statusline-debug.jsonl`)以及配置目录中的相关备份文件。
|
|
94
|
+
|
|
83
95
|
### 添加 / 更新 profile
|
|
84
96
|
|
|
85
97
|
```bash
|
package/bin/cli/args.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseArgs = parseArgs;
|
|
4
4
|
exports.parseInitArgs = parseInitArgs;
|
|
5
5
|
exports.parseAddArgs = parseAddArgs;
|
|
6
|
+
exports.parseUsageResetArgs = parseUsageResetArgs;
|
|
6
7
|
exports.parseStatuslineArgs = parseStatuslineArgs;
|
|
7
8
|
const type_1 = require("../profile/type");
|
|
8
9
|
function parseArgs(argv) {
|
|
@@ -150,6 +151,18 @@ function parseAddArgs(args) {
|
|
|
150
151
|
}
|
|
151
152
|
return result;
|
|
152
153
|
}
|
|
154
|
+
function parseUsageResetArgs(args) {
|
|
155
|
+
const result = { yes: false };
|
|
156
|
+
for (let i = 0; i < args.length; i++) {
|
|
157
|
+
const arg = args[i];
|
|
158
|
+
if (arg === "-y" || arg === "--yes") {
|
|
159
|
+
result.yes = true;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
throw new Error(`Unknown usage-reset argument: ${arg}`);
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
153
166
|
function parseNumberFlag(value, flag) {
|
|
154
167
|
if (value === null || value === undefined || value === "") {
|
|
155
168
|
throw new Error(`Missing value for ${flag}.`);
|
package/bin/cli/help.js
CHANGED
|
@@ -29,6 +29,7 @@ Usage:
|
|
|
29
29
|
codenv launch <codex|claude> [--] [args...]
|
|
30
30
|
codenv init
|
|
31
31
|
codenv statusline [options]
|
|
32
|
+
codenv usage-reset [--yes]
|
|
32
33
|
|
|
33
34
|
Options:
|
|
34
35
|
-c, --config <path> Path to config JSON
|
|
@@ -59,6 +60,9 @@ Statusline options:
|
|
|
59
60
|
--usage-output <n> Set output token usage
|
|
60
61
|
--sync-usage Sync usage from sessions before reading
|
|
61
62
|
|
|
63
|
+
Usage reset options:
|
|
64
|
+
-y, --yes Skip confirmation prompt
|
|
65
|
+
|
|
62
66
|
Examples:
|
|
63
67
|
codenv init
|
|
64
68
|
codenv use codex primary
|
|
@@ -69,6 +73,7 @@ Examples:
|
|
|
69
73
|
codenv remove --all
|
|
70
74
|
codenv launch codex -- --help
|
|
71
75
|
codenv statusline --format json
|
|
76
|
+
codenv usage-reset --yes
|
|
72
77
|
CODE_ENV_CONFIG=~/.config/code-env/config.json codenv use claude default
|
|
73
78
|
codenv add --type codex primary OPENAI_BASE_URL=https://api.example.com/v1 OPENAI_API_KEY=YOUR_API_KEY
|
|
74
79
|
codenv add
|
package/bin/cli/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.printHelp = exports.parseStatuslineArgs = exports.parseAddArgs = exports.parseInitArgs = exports.parseArgs = void 0;
|
|
3
|
+
exports.printHelp = exports.parseStatuslineArgs = exports.parseUsageResetArgs = exports.parseAddArgs = exports.parseInitArgs = exports.parseArgs = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* CLI module exports
|
|
6
6
|
*/
|
|
@@ -8,6 +8,7 @@ var args_1 = require("./args");
|
|
|
8
8
|
Object.defineProperty(exports, "parseArgs", { enumerable: true, get: function () { return args_1.parseArgs; } });
|
|
9
9
|
Object.defineProperty(exports, "parseInitArgs", { enumerable: true, get: function () { return args_1.parseInitArgs; } });
|
|
10
10
|
Object.defineProperty(exports, "parseAddArgs", { enumerable: true, get: function () { return args_1.parseAddArgs; } });
|
|
11
|
+
Object.defineProperty(exports, "parseUsageResetArgs", { enumerable: true, get: function () { return args_1.parseUsageResetArgs; } });
|
|
11
12
|
Object.defineProperty(exports, "parseStatuslineArgs", { enumerable: true, get: function () { return args_1.parseStatuslineArgs; } });
|
|
12
13
|
var help_1 = require("./help");
|
|
13
14
|
Object.defineProperty(exports, "printHelp", { enumerable: true, get: function () { return help_1.printHelp; } });
|
package/bin/commands/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.printStatusline = exports.runLaunch = exports.printUnset = exports.printShow = exports.addConfig = exports.printList = exports.printUse = exports.buildUseLines = void 0;
|
|
3
|
+
exports.runUsageReset = exports.printStatusline = exports.runLaunch = exports.printUnset = exports.printShow = exports.addConfig = exports.printList = exports.printUse = exports.buildUseLines = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Commands module exports
|
|
6
6
|
*/
|
|
@@ -19,3 +19,5 @@ var launch_1 = require("./launch");
|
|
|
19
19
|
Object.defineProperty(exports, "runLaunch", { enumerable: true, get: function () { return launch_1.runLaunch; } });
|
|
20
20
|
var statusline_1 = require("./statusline");
|
|
21
21
|
Object.defineProperty(exports, "printStatusline", { enumerable: true, get: function () { return statusline_1.printStatusline; } });
|
|
22
|
+
var usage_1 = require("./usage");
|
|
23
|
+
Object.defineProperty(exports, "runUsageReset", { enumerable: true, get: function () { return usage_1.runUsageReset; } });
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runUsageReset = runUsageReset;
|
|
4
|
+
const usage_1 = require("../usage");
|
|
5
|
+
const ui_1 = require("../ui");
|
|
6
|
+
async function runUsageReset(config, configPath, args) {
|
|
7
|
+
if (!args.yes) {
|
|
8
|
+
const rl = (0, ui_1.createReadline)();
|
|
9
|
+
try {
|
|
10
|
+
const confirmed = await (0, ui_1.askConfirm)(rl, "Clear all usage history files? This cannot be undone. (y/N): ");
|
|
11
|
+
if (!confirmed)
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
finally {
|
|
15
|
+
rl.close();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const result = (0, usage_1.clearUsageHistory)(config, configPath);
|
|
19
|
+
const removed = result.removed.sort();
|
|
20
|
+
const missing = result.missing.sort();
|
|
21
|
+
const failed = result.failed.sort((a, b) => a.path.localeCompare(b.path));
|
|
22
|
+
if (removed.length === 0 && failed.length === 0) {
|
|
23
|
+
console.log("No usage files found.");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (removed.length > 0) {
|
|
27
|
+
console.log(`Removed ${removed.length} file(s):`);
|
|
28
|
+
for (const filePath of removed) {
|
|
29
|
+
console.log(`- ${filePath}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (missing.length > 0) {
|
|
33
|
+
console.log(`Skipped ${missing.length} missing file(s).`);
|
|
34
|
+
}
|
|
35
|
+
if (failed.length > 0) {
|
|
36
|
+
for (const failure of failed) {
|
|
37
|
+
console.error(`Failed to remove ${failure.path}: ${failure.error}`);
|
|
38
|
+
}
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
}
|
|
41
|
+
}
|
package/bin/index.js
CHANGED
|
@@ -111,6 +111,13 @@ async function main() {
|
|
|
111
111
|
(0, commands_1.printStatusline)(config, configPath, statuslineArgs);
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
|
+
if (cmd === "usage-reset" || cmd === "reset-usage") {
|
|
115
|
+
const resetArgs = (0, cli_1.parseUsageResetArgs)(args.slice(1));
|
|
116
|
+
const configPath = process.env.CODE_ENV_CONFIG_PATH || (0, config_1.findConfigPath)(parsed.configPath);
|
|
117
|
+
const config = (0, config_1.readConfigIfExists)(configPath);
|
|
118
|
+
await (0, commands_1.runUsageReset)(config, configPath, resetArgs);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
114
121
|
const configPath = (0, config_1.findConfigPath)(parsed.configPath);
|
|
115
122
|
const config = (0, config_1.readConfig)(configPath);
|
|
116
123
|
if (cmd === "default") {
|
package/bin/statusline/debug.js
CHANGED
|
@@ -7,19 +7,33 @@ function resolveOutputTokens(record) {
|
|
|
7
7
|
var _a, _b;
|
|
8
8
|
const outputTokens = (_a = (0, utils_1.firstNumber)(record.outputTokens, record.output, record.output_tokens)) !== null && _a !== void 0 ? _a : null;
|
|
9
9
|
const reasoningTokens = (_b = (0, utils_1.firstNumber)(record.reasoning_output_tokens, record.reasoningOutputTokens, record.reasoning_output)) !== null && _b !== void 0 ? _b : null;
|
|
10
|
-
if (outputTokens
|
|
11
|
-
return null;
|
|
12
|
-
if (reasoningTokens === null)
|
|
10
|
+
if (outputTokens !== null)
|
|
13
11
|
return outputTokens;
|
|
14
|
-
|
|
12
|
+
if (reasoningTokens !== null)
|
|
13
|
+
return reasoningTokens;
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
function splitInputTokens(record) {
|
|
17
|
+
var _a, _b;
|
|
18
|
+
const rawInput = (_a = (0, utils_1.firstNumber)(record.inputTokens, record.input, record.input_tokens)) !== null && _a !== void 0 ? _a : null;
|
|
19
|
+
const cacheRead = (_b = (0, utils_1.firstNumber)(record.cached_input_tokens, record.cachedInputTokens, record.cache_read_input_tokens, record.cacheReadInputTokens, record.cache_read, record.cacheRead)) !== null && _b !== void 0 ? _b : null;
|
|
20
|
+
if (rawInput === null) {
|
|
21
|
+
return { inputTokens: null, cacheReadTokens: cacheRead };
|
|
22
|
+
}
|
|
23
|
+
if (cacheRead === null) {
|
|
24
|
+
return { inputTokens: rawInput, cacheReadTokens: null };
|
|
25
|
+
}
|
|
26
|
+
const nonCachedInput = Math.max(0, rawInput - cacheRead);
|
|
27
|
+
return { inputTokens: nonCachedInput, cacheReadTokens: cacheRead };
|
|
15
28
|
}
|
|
16
29
|
function parseCodexUsageTotalsRecord(record) {
|
|
17
|
-
var _a, _b
|
|
18
|
-
const
|
|
30
|
+
var _a, _b;
|
|
31
|
+
const split = splitInputTokens(record);
|
|
32
|
+
const inputTokens = split.inputTokens;
|
|
19
33
|
const outputTokens = resolveOutputTokens(record);
|
|
20
|
-
const cacheRead =
|
|
21
|
-
const cacheWrite = (
|
|
22
|
-
const totalTokens = (
|
|
34
|
+
const cacheRead = split.cacheReadTokens;
|
|
35
|
+
const cacheWrite = (_a = (0, utils_1.firstNumber)(record.cache_creation_input_tokens, record.cacheCreationInputTokens, record.cache_write_input_tokens, record.cacheWriteInputTokens, record.cache_write, record.cacheWrite)) !== null && _a !== void 0 ? _a : null;
|
|
36
|
+
const totalTokens = (_b = (0, utils_1.firstNumber)(record.totalTokens, record.total, record.total_tokens)) !== null && _b !== void 0 ? _b : null;
|
|
23
37
|
let computedTotal = null;
|
|
24
38
|
if (inputTokens !== null ||
|
|
25
39
|
outputTokens !== null ||
|
|
@@ -48,13 +62,14 @@ function parseCodexUsageTotalsRecord(record) {
|
|
|
48
62
|
};
|
|
49
63
|
}
|
|
50
64
|
function parseCodexInputUsageRecord(record) {
|
|
51
|
-
var _a, _b, _c, _d
|
|
65
|
+
var _a, _b, _c, _d;
|
|
52
66
|
const todayTokens = (_a = (0, utils_1.firstNumber)(record.todayTokens, record.today, record.today_tokens, record.daily, record.daily_tokens)) !== null && _a !== void 0 ? _a : null;
|
|
53
67
|
const totalTokens = (_b = (0, utils_1.firstNumber)(record.totalTokens, record.total, record.total_tokens)) !== null && _b !== void 0 ? _b : null;
|
|
54
|
-
const
|
|
68
|
+
const split = splitInputTokens(record);
|
|
69
|
+
const inputTokens = split.inputTokens;
|
|
55
70
|
const outputTokens = resolveOutputTokens(record);
|
|
56
|
-
const cacheRead =
|
|
57
|
-
const cacheWrite = (
|
|
71
|
+
const cacheRead = split.cacheReadTokens;
|
|
72
|
+
const cacheWrite = (_c = (0, utils_1.firstNumber)(record.cache_creation_input_tokens, record.cacheCreationInputTokens, record.cache_write_input_tokens, record.cacheWriteInputTokens, record.cache_write, record.cacheWrite)) !== null && _c !== void 0 ? _c : null;
|
|
58
73
|
if (todayTokens === null &&
|
|
59
74
|
totalTokens === null &&
|
|
60
75
|
inputTokens === null &&
|
|
@@ -71,7 +86,7 @@ function parseCodexInputUsageRecord(record) {
|
|
|
71
86
|
(cacheWrite || 0)
|
|
72
87
|
: null;
|
|
73
88
|
const resolvedTodayTokens = hasCacheTokens
|
|
74
|
-
? (
|
|
89
|
+
? (_d = todayTokens !== null && todayTokens !== void 0 ? todayTokens : totalTokens) !== null && _d !== void 0 ? _d : computedTotal
|
|
75
90
|
: todayTokens;
|
|
76
91
|
return {
|
|
77
92
|
todayTokens: resolvedTodayTokens,
|
|
@@ -110,12 +125,6 @@ function getCodexUsageTotalsFromInput(input) {
|
|
|
110
125
|
if (parsed)
|
|
111
126
|
return parsed;
|
|
112
127
|
}
|
|
113
|
-
const lastUsage = resolveNestedRecord(tokenUsage, "last_token_usage", "lastTokenUsage");
|
|
114
|
-
if (lastUsage) {
|
|
115
|
-
const parsed = parseCodexUsageTotalsRecord(lastUsage);
|
|
116
|
-
if (parsed)
|
|
117
|
-
return parsed;
|
|
118
|
-
}
|
|
119
128
|
const parsed = parseCodexUsageTotalsRecord(tokenUsage);
|
|
120
129
|
if (parsed)
|
|
121
130
|
return parsed;
|