@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 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; } });
@@ -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") {
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getStatuslineDebugPath = getStatuslineDebugPath;
3
4
  exports.appendStatuslineDebug = appendStatuslineDebug;
4
5
  const fs = require("fs");
5
6
  const path = require("path");
@@ -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 === null && reasoningTokens === null)
11
- return null;
12
- if (reasoningTokens === null)
10
+ if (outputTokens !== null)
13
11
  return outputTokens;
14
- return (outputTokens || 0) + reasoningTokens;
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, _c, _d;
18
- const inputTokens = (_a = (0, utils_1.firstNumber)(record.inputTokens, record.input, record.input_tokens)) !== null && _a !== void 0 ? _a : null;
30
+ var _a, _b;
31
+ const split = splitInputTokens(record);
32
+ const inputTokens = split.inputTokens;
19
33
  const outputTokens = resolveOutputTokens(record);
20
- 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;
21
- 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;
22
- const totalTokens = (_d = (0, utils_1.firstNumber)(record.totalTokens, record.total, record.total_tokens)) !== null && _d !== void 0 ? _d : null;
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, _e, _f;
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 inputTokens = (_c = (0, utils_1.firstNumber)(record.inputTokens, record.input, record.input_tokens)) !== null && _c !== void 0 ? _c : null;
68
+ const split = splitInputTokens(record);
69
+ const inputTokens = split.inputTokens;
55
70
  const outputTokens = resolveOutputTokens(record);
56
- const cacheRead = (_d = (0, utils_1.firstNumber)(record.cached_input_tokens, record.cachedInputTokens, record.cache_read_input_tokens, record.cacheReadInputTokens, record.cache_read, record.cacheRead)) !== null && _d !== void 0 ? _d : null;
57
- const cacheWrite = (_e = (0, utils_1.firstNumber)(record.cache_creation_input_tokens, record.cacheCreationInputTokens, record.cache_write_input_tokens, record.cacheWriteInputTokens, record.cache_write, record.cacheWrite)) !== null && _e !== void 0 ? _e : null;
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
- ? (_f = todayTokens !== null && todayTokens !== void 0 ? todayTokens : totalTokens) !== null && _f !== void 0 ? _f : computedTotal
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;