@praeviso/code-env-switch 0.1.0 → 0.1.2

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.
Files changed (78) hide show
  1. package/.eslintrc.cjs +18 -0
  2. package/.github/workflows/npm-publish.yml +25 -0
  3. package/.vscode/settings.json +4 -0
  4. package/AGENTS.md +32 -0
  5. package/LICENSE +21 -0
  6. package/PLAN.md +33 -0
  7. package/README.md +208 -32
  8. package/README_zh.md +265 -0
  9. package/bin/cli/args.js +303 -0
  10. package/bin/cli/help.js +77 -0
  11. package/bin/cli/index.js +13 -0
  12. package/bin/commands/add.js +81 -0
  13. package/bin/commands/index.js +21 -0
  14. package/bin/commands/launch.js +330 -0
  15. package/bin/commands/list.js +57 -0
  16. package/bin/commands/show.js +10 -0
  17. package/bin/commands/statusline.js +12 -0
  18. package/bin/commands/unset.js +20 -0
  19. package/bin/commands/use.js +92 -0
  20. package/bin/config/defaults.js +85 -0
  21. package/bin/config/index.js +20 -0
  22. package/bin/config/io.js +72 -0
  23. package/bin/constants.js +27 -0
  24. package/bin/index.js +279 -0
  25. package/bin/profile/display.js +78 -0
  26. package/bin/profile/index.js +26 -0
  27. package/bin/profile/match.js +40 -0
  28. package/bin/profile/resolve.js +79 -0
  29. package/bin/profile/type.js +90 -0
  30. package/bin/shell/detect.js +40 -0
  31. package/bin/shell/index.js +18 -0
  32. package/bin/shell/snippet.js +92 -0
  33. package/bin/shell/utils.js +35 -0
  34. package/bin/statusline/claude.js +153 -0
  35. package/bin/statusline/codex.js +356 -0
  36. package/bin/statusline/index.js +469 -0
  37. package/bin/types.js +5 -0
  38. package/bin/ui/index.js +16 -0
  39. package/bin/ui/interactive.js +189 -0
  40. package/bin/ui/readline.js +76 -0
  41. package/bin/usage/index.js +709 -0
  42. package/code-env.example.json +36 -23
  43. package/package.json +14 -2
  44. package/src/cli/args.ts +318 -0
  45. package/src/cli/help.ts +75 -0
  46. package/src/cli/index.ts +5 -0
  47. package/src/commands/add.ts +91 -0
  48. package/src/commands/index.ts +10 -0
  49. package/src/commands/launch.ts +395 -0
  50. package/src/commands/list.ts +91 -0
  51. package/src/commands/show.ts +12 -0
  52. package/src/commands/statusline.ts +18 -0
  53. package/src/commands/unset.ts +19 -0
  54. package/src/commands/use.ts +121 -0
  55. package/src/config/defaults.ts +88 -0
  56. package/src/config/index.ts +19 -0
  57. package/src/config/io.ts +69 -0
  58. package/src/constants.ts +28 -0
  59. package/src/index.ts +359 -0
  60. package/src/profile/display.ts +77 -0
  61. package/src/profile/index.ts +12 -0
  62. package/src/profile/match.ts +41 -0
  63. package/src/profile/resolve.ts +84 -0
  64. package/src/profile/type.ts +83 -0
  65. package/src/shell/detect.ts +30 -0
  66. package/src/shell/index.ts +6 -0
  67. package/src/shell/snippet.ts +92 -0
  68. package/src/shell/utils.ts +30 -0
  69. package/src/statusline/claude.ts +172 -0
  70. package/src/statusline/codex.ts +393 -0
  71. package/src/statusline/index.ts +626 -0
  72. package/src/types.ts +95 -0
  73. package/src/ui/index.ts +5 -0
  74. package/src/ui/interactive.ts +220 -0
  75. package/src/ui/readline.ts +85 -0
  76. package/src/usage/index.ts +833 -0
  77. package/tsconfig.json +12 -0
  78. package/bin/codenv.js +0 -377
package/.eslintrc.cjs ADDED
@@ -0,0 +1,18 @@
1
+ module.exports = {
2
+ root: true,
3
+ env: {
4
+ node: true,
5
+ es2021: true,
6
+ },
7
+ parser: "@typescript-eslint/parser",
8
+ parserOptions: {
9
+ ecmaVersion: 2021,
10
+ sourceType: "module",
11
+ },
12
+ plugins: ["@typescript-eslint"],
13
+ extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
14
+ ignorePatterns: ["bin/", "node_modules/"],
15
+ rules: {
16
+ "no-constant-condition": ["error", { "checkLoops": false }]
17
+ }
18
+ };
@@ -0,0 +1,25 @@
1
+ name: Publish to npm
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ publish:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: read
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-node@v4
17
+ with:
18
+ node-version: "20"
19
+ registry-url: "https://registry.npmjs.org"
20
+ cache: "npm"
21
+ - run: npm ci
22
+ - run: npm run build
23
+ - run: npm publish --access public
24
+ env:
25
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,4 @@
1
+ {
2
+ "typescript.tsdk": "node_modules/typescript/lib",
3
+ "typescript.enablePromptUseWorkspaceTsdk": true
4
+ }
package/AGENTS.md ADDED
@@ -0,0 +1,32 @@
1
+ # Repository Guidelines
2
+
3
+ ## Project Structure & Module Organization
4
+ - `src/` holds TypeScript sources. Key areas: `src/cli/` argument parsing, `src/commands/` CLI actions, `src/config/` config IO, `src/profile/` profile resolution, `src/shell/` shell integration, `src/ui/` prompts, `src/usage/` logging.
5
+ - `bin/` contains compiled JavaScript from `tsc`; treat it as generated output.
6
+ - `code-env.example.json` is the public config template; `README.md` and `README_zh.md` are user docs.
7
+
8
+ ## Build, Test, and Development Commands
9
+ - `npm install` installs dependencies.
10
+ - `npm run build` compiles `src/` to `bin/` using `tsconfig.json`.
11
+ - `npm run lint` runs ESLint; `npm run lint:fix` auto-fixes.
12
+ - `npm link` (or `npm install -g .`) installs the CLI locally for manual testing.
13
+ - No automated test script is configured yet.
14
+
15
+ ## Coding Style & Naming Conventions
16
+ - Follow existing formatting: 4-space indentation, double quotes, and semicolons.
17
+ - Use `camelCase` for variables/functions and `PascalCase` for types/interfaces.
18
+ - CLI commands are single verbs (`add`, `use`, `unset`); flags are `--kebab-case` (e.g., `--config`, `--shell`).
19
+ - Keep changes ESLint-clean.
20
+
21
+ ## Testing Guidelines
22
+ - There is no test framework configured. If you add tests, also add a `npm test` script and document the framework in `README.md`.
23
+ - Prefer a top-level `tests/` folder or `src/**/__tests__` for discoverable structure.
24
+
25
+ ## Commit & Pull Request Guidelines
26
+ - Git history shows Conventional Commit-style prefixes (e.g., `feat:`) plus simple descriptive messages; release commits use version numbers like `0.1.1`.
27
+ - Use short, imperative subjects and include a brief body for non-trivial changes.
28
+ - PRs should include: summary, rationale, manual test commands run (e.g., `npm run build`, `codenv use`), and any config or shell-rc impacts; link related issues.
29
+
30
+ ## Configuration & Security Notes
31
+ - Config is loaded via `--config`, `CODE_ENV_CONFIG`, or `~/.config/code-env/config.json`; use `code-env.example.json` for sanitized examples.
32
+ - Never commit real API keys or user-specific config.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Krito.
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.
package/PLAN.md ADDED
@@ -0,0 +1,33 @@
1
+ # Statusline Plan (Simplified)
2
+
3
+ ## Goals
4
+ - Provide a host-agnostic statusline outputter for Codex CLI and Claude Code.
5
+ - Show Git status, model label, and usage in a single line.
6
+ - Auto-enable a bottom statusline when launching via `codenv`.
7
+
8
+ ## Done (implemented)
9
+ - `codenv statusline` outputs text/JSON with Git + model + usage.
10
+ - ANSI bottom-bar renderer added with forced redraw support (for Codex UI repaint).
11
+ - `codenv launch codex` auto-starts the renderer.
12
+ - `codenv launch claude` ensures `.claude/settings.json` uses a `statusLine` command object.
13
+ - Env knobs added for enable/disable, interval, offset/reserve, and force redraw.
14
+
15
+ ## Next plan (overall)
16
+ ### Phase 1 — Stabilize behavior
17
+ - Verify Codex overlay behavior across terminals; tune default interval/offset as needed.
18
+ - Add a simple “compatibility fallback” note for terminals that don’t support scroll regions.
19
+ - Confirm Claude statusLine object format across versions (no string form).
20
+
21
+ ### Phase 2 — Data quality
22
+ - Optional: resolve model from session logs if not provided by env/stdin.
23
+ - Clarify usage sync strategy (per-session vs aggregate) and align with `src/usage/`.
24
+
25
+ ### Phase 3 — Integrations & ergonomics
26
+ - Provide generic wrapper example for other CLIs (stdin JSON contract).
27
+ - Optional tmux statusline snippet as alternative for Codex.
28
+ - Add minimal config knobs to `code-env.example.json` if needed.
29
+
30
+ ### Phase 4 — QA & polish
31
+ - Manual test checklist (bash/zsh/fish, macOS/Linux).
32
+ - Performance check target (<50ms typical render).
33
+ - Harden error handling and safe fallbacks.
package/README.md CHANGED
@@ -2,19 +2,60 @@
2
2
 
3
3
  A tiny CLI to switch between Claude Code and Codex environment variables.
4
4
 
5
- ## Setup
5
+ [中文说明](README_zh.md)
6
6
 
7
- 1) Copy the example config and fill in your keys:
7
+ ## Features
8
+
9
+ - Manage multiple profiles and switch by name or type
10
+ - `codenv use` prints shell commands for the current terminal
11
+ - Interactive profile creation and selection
12
+ - Optional cleanup via `removeFiles` and post-switch `commands`
13
+ - Config auto-discovery and type-based default `unset` keys
14
+
15
+ ## Quick start
16
+
17
+ 1) Install:
8
18
 
9
19
  ```bash
10
- cp code-env.example.json code-env.json
20
+ npm install -g @praeviso/code-env-switch
11
21
  ```
12
22
 
13
- 2) Install from npm (after publish) or locally:
23
+ 2) Add profiles interactively (this creates `~/.config/code-env/config.json` if missing):
24
+
25
+ ```bash
26
+ codenv add
27
+ # run it again to add the second type
28
+ codenv add
29
+ ```
30
+
31
+ Example session:
32
+
33
+ ```text
34
+ $ codenv add
35
+ Select type (1=codex, 2=claude): 1
36
+ Profile name (default: default): primary
37
+ Base URL (required): https://api.example.com/v1
38
+ API key (required): YOUR_API_KEY
39
+ ```
40
+
41
+ 3) Set defaults per type:
42
+
43
+ ```bash
44
+ codenv default codex primary
45
+ codenv default claude default
46
+ ```
47
+
48
+ 4) Enable auto-apply in your shell:
49
+
50
+ ```bash
51
+ codenv init
52
+ ```
53
+
54
+ Open a new terminal (or `source ~/.bashrc` / `source ~/.zshrc`) to auto-apply the defaults.
55
+
56
+ For local development install:
14
57
 
15
58
  ```bash
16
- npm install -g code-env-switch
17
- # or local dev
18
59
  npm install -g .
19
60
  # or
20
61
  npm link
@@ -22,69 +63,204 @@ npm link
22
63
 
23
64
  ## Usage
24
65
 
25
- List profiles:
66
+ > By default, `codenv use` only outputs shell commands. After running
67
+ > `codenv init`, the shell wrapper applies them automatically.
68
+ > The snippet also wraps `codex`/`claude` to bind sessions to profiles; use
69
+ > `command codex` / `command claude` to bypass.
70
+
71
+ ### Common commands
26
72
 
27
73
  ```bash
28
74
  codenv list
75
+ codenv show codex primary
76
+ codenv default codex primary
77
+ codenv remove codex primary
78
+ ```
79
+
80
+ `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
+ If `profile.name` is set, it is shown in `PROFILE`. Otherwise the profile key is shown (with legacy `type-` prefixes stripped when possible).
82
+
83
+ ### Add / update a profile
84
+
85
+ ```bash
86
+ codenv add primary OPENAI_BASE_URL=https://api.example.com/v1 OPENAI_API_KEY=YOUR_API_KEY --note "Primary endpoint"
87
+ # with explicit type (codex/claude, claude also accepts cc)
88
+ codenv add --type codex primary OPENAI_BASE_URL=https://api.example.com/v1 OPENAI_API_KEY=YOUR_API_KEY
29
89
  ```
30
90
 
31
- Add or update a profile from the CLI:
91
+ When `--type` is set, the profile name is kept as-is and `type` is stored separately.
92
+ Profiles are keyed by an internal id; the human-facing name lives in `profile.name`.
93
+
94
+ Interactive add (default):
95
+
96
+ ```bash
97
+ codenv add
98
+ ```
99
+
100
+ ### Remove a profile
32
101
 
33
102
  ```bash
34
- codenv add codex-88 OPENAI_BASE_URL=https://api.openai.com/v1 OPENAI_API_KEY=sk-REPLACE_ME --note "OpenAI official"
103
+ codenv remove primary
104
+ # or by type + name (recommended when names overlap)
105
+ codenv remove codex primary
106
+ # multiple at once
107
+ codenv remove codex primary claude default
108
+ # (legacy keys like codex-primary also work)
109
+ codenv remove codex-primary claude-default
110
+ # remove all
111
+ codenv remove --all
35
112
  ```
36
113
 
37
- Switch in the current shell (bash/zsh):
114
+ ### Switch in the current shell (bash/zsh)
38
115
 
39
116
  ```bash
40
- eval "$(codenv use codex-88)"
117
+ codenv use
118
+ # use up/down then Enter (q to exit)
119
+ codenv use primary
120
+ # or by type + name (also matches legacy keys like codex-primary)
121
+ codenv use codex primary
122
+ codenv use cc primary
41
123
  ```
42
124
 
43
- Unset all known keys:
125
+ First run `codenv init` once to install the shell wrapper:
44
126
 
45
127
  ```bash
128
+ codenv init
129
+ # or target a specific shell
130
+ codenv init --shell zsh
131
+ ```
132
+
133
+ This wrapper makes `codenv use` and `codenv unset` apply automatically in the
134
+ current shell. To print the snippet without writing to rc, use
135
+ `codenv init --print`.
136
+
137
+ ### Auto-apply default profiles (per type)
138
+
139
+ Set a default per type (codex/claude) and re-run `codenv init`:
140
+
141
+ ```bash
142
+ codenv default codex primary
143
+ codenv default claude default
144
+ ```
145
+
146
+ ```json
147
+ {
148
+ "defaultProfiles": {
149
+ "codex": "primary",
150
+ "claude": "default"
151
+ }
152
+ }
153
+ ```
154
+
155
+ On new terminal sessions, `codenv` will auto-apply all defaults via `codenv auto`.
156
+ To clear all defaults, run `codenv default --clear` (with confirmation).
157
+
158
+ One-off without init:
159
+
160
+ ```bash
161
+ eval "$(codenv use codex primary)"
162
+ ```
163
+
164
+ Note: the change takes effect in new terminals. To apply immediately, run:
165
+
166
+ ```bash
167
+ source ~/.bashrc
168
+ # or for zsh
169
+ source ~/.zshrc
170
+ ```
171
+
172
+ ### Unset known keys
173
+
174
+ ```bash
175
+ codenv unset
176
+ # or one-off without init
46
177
  eval "$(codenv unset)"
47
178
  ```
48
179
 
49
- ### Config lookup order
180
+ ### Fish shell
181
+
182
+ ```fish
183
+ codenv use codex primary
184
+ # or one-off without init
185
+ codenv use codex primary | source
186
+ ```
187
+
188
+ ## Config lookup order
50
189
 
51
190
  `codenv` searches in this order:
52
191
 
53
192
  1) `--config <path>`
54
193
  2) `CODE_ENV_CONFIG`
55
- 3) `./code-env.json`
56
- 4) `./profiles.json`
57
- 5) `./code-env.config.json`
58
- 6) `~/.config/code-env/config.json`
194
+ 3) `~/.config/code-env/config.json`
195
+
196
+ Use `codenv config` to print the path selected for the current directory.
197
+
198
+ If nothing is found, `codenv add` writes to `~/.config/code-env/config.json`.
59
199
 
60
200
  ## Config format
61
201
 
62
202
  ```json
63
203
  {
64
- "unset": ["OPENAI_BASE_URL", "OPENAI_API_KEY"],
204
+ "unset": [],
205
+ "defaultProfiles": {
206
+ "codex": "primary",
207
+ "claude": "default"
208
+ },
209
+ "codexStatusline": {
210
+ "command": ["codenv", "statusline", "--type", "codex", "--sync-usage"],
211
+ "showHints": false,
212
+ "updateIntervalMs": 300,
213
+ "timeoutMs": 1000
214
+ },
215
+ "claudeStatusline": {
216
+ "command": "codenv statusline --type claude --sync-usage",
217
+ "type": "command",
218
+ "padding": 0
219
+ },
65
220
  "profiles": {
66
- "codex-88": {
67
- "note": "OpenAI official",
221
+ "p_a1b2c3": {
222
+ "name": "primary",
223
+ "type": "codex",
224
+ "note": "Primary endpoint",
68
225
  "env": {
69
- "OPENAI_BASE_URL": "https://api.openai.com/v1",
70
- "OPENAI_API_KEY": "sk-REPLACE_ME",
71
- "CODEX_PROVIDER": "OpenAI"
226
+ "OPENAI_BASE_URL": "https://api.example.com/v1",
227
+ "OPENAI_API_KEY": "YOUR_API_KEY"
72
228
  },
73
- "removeFiles": ["$HOME/.config/openai/auth.json"],
74
- "commands": ["echo \"Switched to codex-88\""]
229
+ "removeFiles": ["$HOME/.config/example/auth.json"],
230
+ "commands": ["echo \"Switched to codex primary\""]
75
231
  }
76
232
  }
77
233
  }
78
234
  ```
79
235
 
80
236
  Notes:
81
- - `removeFiles` is optional; when present, `codenv use <profile>` emits `rm -f` lines for those paths.
82
- - `commands` is optional; any strings are emitted as-is.
83
- - `note` is shown in `codenv list` output.
84
- - `codenv add` creates the config file if it does not exist (default: `./code-env.json`).
237
+ - `unset`: global keys to clear. Type-specific defaults are applied only for the active type and won't clear the other type.
238
+ - `defaultProfiles`: optional; map of `codex`/`claude` to profile name or key used by `codenv auto`.
239
+ - `codexStatusline`: optional; config to inject Codex TUI status line settings when launching `codex`.
240
+ - `command`: string or string[]; command passed to Codex `tui.status_line.command`.
241
+ - `showHints`: boolean; whether Codex footer hints are appended when the status line is active.
242
+ - `updateIntervalMs`: number; update interval in ms for the status line command.
243
+ - `timeoutMs`: number; timeout in ms for the status line command.
244
+ - `configPath`: optional; override `~/.codex/config.toml` (also supports `CODE_ENV_CODEX_CONFIG_PATH`).
245
+ - `claudeStatusline`: optional; config to inject Claude Code statusLine settings when launching `claude`.
246
+ - `command`: string (or string[]; arrays are joined into a single command string).
247
+ - `type`: string; statusLine type (default: `command`).
248
+ - `padding`: number; statusLine padding (default: 0).
249
+ - `settingsPath`: optional; override `~/.claude/settings.json` (also supports `CODE_ENV_CLAUDE_SETTINGS_PATH`).
250
+ - `name`: human-facing profile name shown in `codenv list` and used by `codenv use <name>`.
251
+ - `type`: optional; `codex` or `claude` (alias `cc`) for `codenv use <type> <name>` matching.
252
+ - `note`: shown in `codenv list`.
253
+ - `removeFiles`: optional; `codenv use` emits `rm -f` for each path. Codex profiles also remove `~/.codex/auth.json`.
254
+ - `ANTHROPIC_AUTH_TOKEN`: when `ANTHROPIC_API_KEY` is set, `codenv use` also exports `ANTHROPIC_AUTH_TOKEN` with the same value.
255
+ - `commands`: optional; emitted as-is in the switch script.
85
256
 
86
- ## Fish shell
257
+ ## Security
87
258
 
88
- ```fish
89
- codenv use codex-88 | source
259
+ Your config contains API keys. Keep it private and out of public repositories.
260
+
261
+ ## Development
262
+
263
+ ```bash
264
+ npm install
265
+ npm run build
90
266
  ```