@minniexcode/codex-switch 0.0.2 → 0.0.3

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.AI.md ADDED
@@ -0,0 +1,105 @@
1
+ # AI README
2
+
3
+ This file is for AI agents, automation scripts, and contributors who need a compact operational summary of the repository.
4
+
5
+ ## Repository Purpose
6
+
7
+ `@minniexcode/codex-switch` is a local-first TypeScript CLI for managing provider/profile state for Codex under `~/.codex/`.
8
+
9
+ Primary goals:
10
+
11
+ - safe local profile switching
12
+ - backup-before-write mutation flows
13
+ - rollback on failure
14
+ - stable machine-readable CLI output
15
+ - support for both human TTY usage and agent automation
16
+
17
+ ## Main Command Surface
18
+
19
+ ```bash
20
+ codexs list
21
+ codexs current
22
+ codexs switch <provider>
23
+ codexs status
24
+ codexs import <file>
25
+ codexs export <file>
26
+ codexs add <provider>
27
+ codexs remove <provider>
28
+ codexs doctor
29
+ codexs rollback
30
+ ```
31
+
32
+ Shared flags:
33
+
34
+ ```bash
35
+ --json
36
+ --codex-dir <path>
37
+ ```
38
+
39
+ ## Important Runtime Files
40
+
41
+ ```text
42
+ ~/.codex/
43
+ config.toml
44
+ auth.json
45
+ providers.json
46
+ backups/
47
+ ```
48
+
49
+ Operational model:
50
+
51
+ - `providers.json` is the management-state source of truth
52
+ - `config.toml` and `auth.json` are runtime mirrors
53
+ - `backups/latest.json` tracks the latest rollback state
54
+ - mutating commands should back up first and run under a lightweight file lock
55
+
56
+ ## Project Structure
57
+
58
+ ```text
59
+ src/
60
+ app/
61
+ cli/
62
+ domain/
63
+ infra/
64
+ tests/
65
+ docs/
66
+ dist/
67
+ ```
68
+
69
+ Layer intent:
70
+
71
+ - `cli`: argument parsing, help, TTY flows, output shaping
72
+ - `app`: command orchestration and use-case logic
73
+ - `domain`: pure domain rules and shared models
74
+ - `infra`: filesystem, lock, backup, config, and Codex integration code
75
+
76
+ ## Command Entry Point
77
+
78
+ Use `codexs` directly for runtime interaction:
79
+
80
+ ```bash
81
+ codexs --help
82
+ codexs list --json
83
+ codexs status --json
84
+ ```
85
+
86
+ ## Current Version Context
87
+
88
+ Current package version in this repository:
89
+
90
+ ```text
91
+ 0.0.3
92
+ ```
93
+
94
+ Recent version summary:
95
+
96
+ - `0.0.3`: interactive TTY flows and improved help
97
+ - `0.0.2`: mutation orchestration, backups, rollback, locks, drift detection improvements
98
+ - `0.0.1`: initial TypeScript CLI and baseline docs
99
+
100
+ ## Notes For Agents
101
+
102
+ - Prefer `--json` when invoking commands programmatically
103
+ - Treat `providers.json` as sensitive because it may contain API keys
104
+ - Do not assume silent write-back from runtime files into `providers.json`
105
+ - Use `docs/` for deeper product and architecture context
package/README.CN.md ADDED
@@ -0,0 +1,160 @@
1
+ # @minniexcode/codex-switch
2
+
3
+ `@minniexcode/codex-switch` 是一个本地优先的 CLI,用来安全地管理和切换 Codex 的 provider/profile 配置。
4
+
5
+ 它主要解决这样一个问题:如果你同时使用多个 Codex provider、API key 或 profile,不想再手动改 `~/.codex/` 里的文件,就可以用这个工具做统一管理和安全切换。
6
+
7
+ ## 这个仓库是做什么的
8
+
9
+ 这个仓库包含 `codex-switch` 的 CLI 实现、npm 包配置,以及相关产品和技术文档。
10
+
11
+ 项目目标很明确:
12
+
13
+ - 在本地完成 Codex 配置切换
14
+ - 写入前先备份
15
+ - 出错时可回滚
16
+ - 同时兼顾终端用户和 AI/自动化调用
17
+
18
+ ## 现在可以做什么
19
+
20
+ 当前 MVP 命令如下:
21
+
22
+ ```bash
23
+ codexs list
24
+ codexs current
25
+ codexs switch <provider>
26
+ codexs status
27
+ codexs import <file>
28
+ codexs export <file>
29
+ codexs add <provider>
30
+ codexs remove <provider>
31
+ codexs doctor
32
+ codexs rollback
33
+ ```
34
+
35
+ 对应能力包括:
36
+
37
+ - 查看本地已管理的 provider
38
+ - 查看当前激活的 profile
39
+ - 安全切换 provider
40
+ - 导入和导出 provider 映射
41
+ - 新增和删除 provider
42
+ - 检查配置漂移和常见本地问题
43
+ - 在变更前自动备份,并在失败时回滚
44
+
45
+ ## 简单用法
46
+
47
+ 全局安装:
48
+
49
+ ```bash
50
+ npm install -g @minniexcode/codex-switch
51
+ ```
52
+
53
+ 或者直接执行:
54
+
55
+ ```bash
56
+ npx @minniexcode/codex-switch --help
57
+ ```
58
+
59
+ 检查 CLI 是否可用:
60
+
61
+ ```bash
62
+ codexs --help
63
+ ```
64
+
65
+ 典型使用方式:
66
+
67
+ ```bash
68
+ codexs list
69
+ codexs current
70
+ codexs add my-provider --profile my-provider --api-key sk-xxx
71
+ codexs switch my-provider
72
+ codexs status
73
+ ```
74
+
75
+ 给脚本或 AI 使用时建议加上:
76
+
77
+ ```bash
78
+ codexs list --json
79
+ codexs status --json
80
+ ```
81
+
82
+ 通用参数:
83
+
84
+ ```bash
85
+ --json
86
+ --codex-dir <path>
87
+ ```
88
+
89
+ ## 交互式体验
90
+
91
+ 这个 CLI 同时支持显式命令和交互式终端流程。
92
+
93
+ - `codexs add` 在 TTY 里会补问缺失的必填项
94
+ - `codexs switch` 在未传 provider 时可以弹出选择列表
95
+ - `codexs remove` 支持交互式选择和确认删除
96
+ - `import`、`export`、`rollback` 在交互模式下会要求确认
97
+ - `--json` 模式保持非交互,适合自动化
98
+
99
+ ## 管理哪些文件
100
+
101
+ `codex-switch` 主要围绕 `~/.codex/` 下的这些文件工作:
102
+
103
+ ```text
104
+ ~/.codex/
105
+ config.toml
106
+ auth.json
107
+ providers.json
108
+ backups/
109
+ ```
110
+
111
+ 存储模型:
112
+
113
+ - `providers.json` 是管理态的单一事实来源
114
+ - `config.toml` 和 `auth.json` 是运行态文件
115
+ - `backups/latest.json` 记录最近一次可回滚窗口
116
+
117
+ 注意:`providers.json` 可能包含 API key,应视为本地敏感文件。
118
+
119
+ ## 相关文档
120
+
121
+ - [English README](./README.md)
122
+ - [AI README](./README.AI.md)
123
+ - [产品概览](./docs/codex-switch-product-overview.md)
124
+ - [产品调研](./docs/codex-switch-product-research.md)
125
+ - [PRD](./docs/codex-switch-prd.md)
126
+ - [技术架构](./docs/codex-switch-technical-architecture.md)
127
+ - [命令设计](./docs/codex-switch-command-design.md)
128
+
129
+ ## 最近 3 个版本更新
130
+
131
+ ### 0.0.3
132
+
133
+ - 为 `add`、`switch`、`remove`、`import`、`export`、`rollback` 增加了交互式 TTY 流程
134
+ - 改进了帮助信息和命令级使用说明
135
+ - 增强了交互行为和参数处理相关测试覆盖
136
+
137
+ ### 0.0.2
138
+
139
+ - 增加了统一的变更编排能力,包括写前备份、失败回滚和单进程锁
140
+ - 改进了 `status` 和 `doctor`,更清晰地识别运行态漂移
141
+ - 加强了底层仓储层和领域层,使配置写入更安全
142
+
143
+ ### 0.0.1
144
+
145
+ - 发布了第一版 TypeScript CLI 实现
146
+ - 落地了核心 MVP 命令和基于文件的 provider 管理模型
147
+ - 补齐了首批产品、架构和命令设计文档
148
+
149
+ ## 本地开发
150
+
151
+ ```bash
152
+ npm install
153
+ npm run build
154
+ npm test
155
+ node dist/cli.js --help
156
+ ```
157
+
158
+ ## License
159
+
160
+ MIT
package/README.md CHANGED
@@ -2,67 +2,22 @@
2
2
 
3
3
  `@minniexcode/codex-switch` is a local-first CLI for managing and switching Codex provider/profile configuration safely.
4
4
 
5
- Current product direction:
5
+ It is built for people who use multiple Codex providers, API keys, or profiles and want a repeatable way to switch between them without manually editing files under `~/.codex/`.
6
6
 
7
- - CLI-first
8
- - local-first
9
- - safe by default
10
- - AI-friendly
7
+ ## What This Repository Is For
11
8
 
12
- The intended command name is:
9
+ This repository contains the CLI implementation, package metadata, and product documents for `codex-switch`.
13
10
 
14
- ```bash
15
- codexs
16
- ```
17
-
18
- ## Status
19
-
20
- The repository now contains the first end-to-end modular CLI implementation for the MVP command set defined in `docs/`.
21
-
22
- The project is implemented as a TypeScript CLI, builds into `dist/`, and is organized into `cli`, `app`, `domain`, and `infra` layers for maintainability.
23
-
24
- ## Why This Exists
25
-
26
- Managing multiple Codex providers or profiles locally usually falls into two bad options:
27
-
28
- - ad hoc scripts that work once but are hard to maintain
29
- - heavier account or desktop tools that solve a broader problem than local switching
30
-
31
- `@minniexcode/codex-switch` sits between those extremes. It aims to provide a stable CLI interface for:
32
-
33
- - viewing the current Codex profile
34
- - listing locally configured providers
35
- - switching providers safely
36
- - backing up config before mutation
37
- - rolling back on failure
38
- - importing and exporting provider mappings
39
- - returning structured output for automation and AI agents
11
+ The project focuses on a simple idea:
40
12
 
41
- ## Product Definition
42
-
43
- `@minniexcode/codex-switch` is intended to manage files under `~/.codex/`:
44
-
45
- ```text
46
- ~/.codex/
47
- config.toml
48
- auth.json
49
- providers.json
50
- backups/
51
- ```
13
+ - keep Codex profile switching local
14
+ - back up config before writes
15
+ - roll back on failure
16
+ - support both humans in a terminal and AI/automation workflows
52
17
 
53
- Core design principles:
18
+ ## What It Can Do
54
19
 
55
- - `providers.json` is the management-state single source of truth for provider metadata and mappings
56
- - `config.toml` and `auth.json` are runtime mirrors that codex-switch synchronizes safely
57
- - `backups/latest.json` tracks rollback state for the latest managed mutation window
58
- - all writes should be backed up first
59
- - failures should trigger rollback
60
- - write operations should execute under a lightweight single-process file lock
61
- - CLI output should stay stable and machine-readable
62
-
63
- ## MVP Commands
64
-
65
- The current MVP command surface is:
20
+ Current MVP command set:
66
21
 
67
22
  ```bash
68
23
  codexs list
@@ -77,116 +32,130 @@ codexs doctor
77
32
  codexs rollback
78
33
  ```
79
34
 
80
- Shared flags:
35
+ What that means in practice:
81
36
 
82
- ```bash
83
- --json
84
- --codex-dir <path>
85
- ```
86
-
87
- ## Example Provider Model
88
-
89
- Planned `providers.json` shape:
90
-
91
- ```json
92
- {
93
- "providers": {
94
- "packycode": {
95
- "profile": "packycode",
96
- "apiKey": "sk-xxx",
97
- "baseUrl": "https://example.com/v1",
98
- "note": "primary free model route",
99
- "tags": ["free", "daily"]
100
- }
101
- }
102
- }
103
- ```
37
+ - list locally managed providers
38
+ - show the current active profile
39
+ - switch to another provider safely
40
+ - import and export provider mappings
41
+ - add or remove provider records
42
+ - detect config drift and common local issues
43
+ - back up managed files before mutation and roll back when needed
104
44
 
105
- `providers.json` should be treated as a local secret because it may contain API keys.
45
+ ## Quick Start
106
46
 
107
- ## Install
47
+ ### For Humans
108
48
 
109
- Global install:
49
+ Install globally:
110
50
 
111
- ```bash
51
+ ```text
112
52
  npm install -g @minniexcode/codex-switch
113
53
  ```
114
54
 
115
- One-off execution:
55
+ Or run without installing globally:
116
56
 
117
- ```bash
118
- npx @minniexcode/codex-switch
57
+ ```text
58
+ npx @minniexcode/codex-switch --help
119
59
  ```
120
60
 
121
- Current CLI entry check:
61
+ Check the CLI:
122
62
 
123
- ```bash
63
+ ```text
124
64
  codexs --help
125
65
  ```
126
66
 
127
- ## Current Repository Contents
67
+ Typical usage:
68
+
69
+ ```text
70
+ codexs list
71
+ codexs current
72
+ codexs add my-provider --profile my-provider --api-key sk-xxx
73
+ codexs switch my-provider
74
+ codexs status
75
+ ```
76
+
77
+ ### For LLM Agents
128
78
 
129
- This repository contains both the product documents and the CLI implementation:
79
+ Read this first:
130
80
 
131
- - [Product Overview](./docs/codex-switch-product-overview.md)
132
- - [Product Research](./docs/codex-switch-product-research.md)
133
- - [PRD](./docs/codex-switch-prd.md)
134
- - [Technical Architecture](./docs/codex-switch-technical-architecture.md)
135
- - [Command Design](./docs/codex-switch-command-design.md)
81
+ ```text
82
+ ./README.AI.md
83
+ ```
136
84
 
137
- ## Implementation Notes
85
+ Then install and use the project by following the agent-specific instructions in that file.
138
86
 
139
- Current implementation characteristics:
87
+ Reference:
140
88
 
141
- - modular TypeScript architecture split into `app`, `domain`, `infra`, and `cli`
142
- - repository-style infra modules for providers, config, backups, and write locks
143
- - a shared mutation orchestration contract that wraps backup, rollback, and lock handling
144
- - safe write flows with backup manifests under `backups/`
145
- - rollback support for `config.toml` and optional `auth.json`
146
- - `status` and `doctor` expose live-state drift so future backfill/edit/sync flows can reuse the same core model
147
- - stable `--json` envelopes for automation
148
- - test coverage in `tests/` using a custom serial runner (`tests/run-tests.js`) because the current environment hits `node --test` worker/spawn restrictions
89
+ - [AI README](./README.AI.md)
149
90
 
150
- ## Storage Model
91
+ Shared flags:
151
92
 
152
- The current storage model is intentionally split:
93
+ ```text
94
+ --json
95
+ --codex-dir <path>
96
+ ```
153
97
 
154
- - management state: `providers.json`
155
- - runtime state: `config.toml` and `auth.json`
156
- - rollback state: `backups/latest.json` and timestamped backup manifests
98
+ ## Interactive Use
157
99
 
158
- That keeps the MVP file-based while preserving the same boundary a future database-backed registry would use.
100
+ The CLI supports both explicit commands and guided terminal flows.
159
101
 
160
- ## Concurrency And Drift
102
+ - `codexs add` prompts for missing required values in a real TTY
103
+ - `codexs switch` can show a provider selector when no provider is passed
104
+ - `codexs remove` supports interactive selection and confirmation
105
+ - `import`, `export`, and `rollback` ask for confirmation in interactive mode
106
+ - `--json` remains non-interactive for scripts and agents
161
107
 
162
- Current write semantics are intentionally lightweight:
108
+ ## Files It Manages
163
109
 
164
- - every mutating command runs inside `~/.codex/.codex-switch.lock`
165
- - each mutation creates a backup first and rolls back on failure
166
- - `status` and `doctor` detect when the active runtime profile in `config.toml` is no longer mapped in `providers.json`
110
+ `codex-switch` is designed around files under `~/.codex/`:
167
111
 
168
- That drift signal is the contract for future `edit`, `sync`, and explicit backfill flows. The current version detects and reports drift, but does not silently write live runtime changes back into the management registry.
112
+ ```text
113
+ ~/.codex/
114
+ config.toml
115
+ auth.json
116
+ providers.json
117
+ backups/
118
+ ```
169
119
 
170
- ## Non-Goals for MVP
120
+ Storage model:
171
121
 
172
- The first version is not trying to be:
122
+ - `providers.json` is the management source of truth
123
+ - `config.toml` and `auth.json` are runtime state
124
+ - `backups/latest.json` tracks the latest rollback window
173
125
 
174
- - a GUI or desktop app
175
- - a background daemon
176
- - a full account management platform
177
- - a proxy/router layer
178
- - a remote sync service
126
+ `providers.json` may contain API keys, so it should be treated as a local secret.
179
127
 
180
- ## Development
128
+ ## Documentation
181
129
 
182
- Local development:
130
+ User-oriented project docs:
183
131
 
184
- ```bash
185
- npm install
186
- npm run build
187
- npm test
188
- node dist/cli.js --help
189
- ```
132
+ - [Chinese README](./README.CN.md)
133
+ - [AI README](./README.AI.md)
134
+ - [Product Overview](./docs/codex-switch-product-overview.md)
135
+ - [Product Research](./docs/codex-switch-product-research.md)
136
+ - [PRD](./docs/codex-switch-prd.md)
137
+ - [Technical Architecture](./docs/codex-switch-technical-architecture.md)
138
+ - [Command Design](./docs/codex-switch-command-design.md)
139
+
140
+ ## Latest 3 Versions
141
+
142
+ ### 0.0.3
143
+
144
+ - Added interactive TTY flows for high-frequency commands such as `add`, `switch`, `remove`, `import`, `export`, and `rollback`
145
+ - Improved help output and command-specific guidance
146
+ - Expanded CLI test coverage for interactive and argument handling behavior
147
+
148
+ ### 0.0.2
149
+
150
+ - Added mutation orchestration with backup-first writes, rollback handling, and single-process locking
151
+ - Improved `status` and `doctor` so they can detect runtime drift more clearly
152
+ - Strengthened repository and domain layers for safer config operations
153
+
154
+ ### 0.0.1
155
+
156
+ - Shipped the initial TypeScript CLI implementation
157
+ - Added the core MVP commands and file-based provider management model
158
+ - Added the first full set of product, architecture, and command design docs
190
159
 
191
160
  ## License
192
161
 
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.collectAddInput = collectAddInput;
4
+ exports.createNonInteractiveAddError = createNonInteractiveAddError;
5
+ const config_repo_1 = require("../infra/config-repo");
6
+ const errors_1 = require("../domain/errors");
7
+ /**
8
+ * Collects add command inputs interactively when required values are missing.
9
+ */
10
+ async function collectAddInput(runtime, defaults, providerExists, configPath) {
11
+ runtime.writeLine("Interactive add mode");
12
+ runtime.writeLine("Provide the missing required fields. Press Enter to skip optional fields.");
13
+ const providerName = defaults.providerName
14
+ ? normalizeRequiredValue(defaults.providerName)
15
+ : await promptProviderName(runtime, providerExists);
16
+ const profile = defaults.profile
17
+ ? normalizeRequiredValue(defaults.profile)
18
+ : await promptProfile(runtime, configPath);
19
+ const apiKey = defaults.apiKey
20
+ ? normalizeRequiredValue(defaults.apiKey)
21
+ : await promptConfirmedSecret(runtime, "API key", "Confirm API key");
22
+ const baseUrl = defaults.baseUrl ?? normalizeOptionalValue(await runtime.inputText("Base URL (optional)"));
23
+ const note = defaults.note ?? normalizeOptionalValue(await runtime.inputText("Note (optional)"));
24
+ const tags = defaults.tags.length > 0
25
+ ? defaults.tags
26
+ : parseTags(await runtime.inputText("Tags (optional, comma-separated)"));
27
+ return {
28
+ providerName,
29
+ profile,
30
+ apiKey,
31
+ baseUrl,
32
+ note,
33
+ tags,
34
+ };
35
+ }
36
+ /**
37
+ * Throws a consistent error when interactive add is unavailable.
38
+ */
39
+ function createNonInteractiveAddError() {
40
+ return (0, errors_1.cliError)("INVALID_IMPORT_FILE", "add requires <provider>, --profile, and --api-key when running without an interactive TTY.", {
41
+ suggestion: "Run in a terminal TTY or pass all required values explicitly.",
42
+ });
43
+ }
44
+ async function promptProviderName(runtime, providerExists) {
45
+ while (true) {
46
+ const providerName = await promptRequiredValue(runtime, "Provider name");
47
+ if (providerExists(providerName)) {
48
+ runtime.writeLine(`Provider "${providerName}" already exists. Choose a different name.`);
49
+ continue;
50
+ }
51
+ return providerName;
52
+ }
53
+ }
54
+ async function promptProfile(runtime, configPath) {
55
+ const profileChoices = loadProfileChoices(configPath);
56
+ if (profileChoices.length > 0) {
57
+ return runtime.selectOne("Profile", profileChoices);
58
+ }
59
+ return promptRequiredValue(runtime, "Profile");
60
+ }
61
+ function loadProfileChoices(configPath) {
62
+ try {
63
+ return Array.from((0, config_repo_1.listConfigProfiles)(configPath))
64
+ .sort()
65
+ .map((profileName) => ({
66
+ value: profileName,
67
+ label: profileName,
68
+ }));
69
+ }
70
+ catch {
71
+ return [];
72
+ }
73
+ }
74
+ async function promptRequiredValue(runtime, label) {
75
+ while (true) {
76
+ const value = normalizeRequiredValue(await runtime.inputText(label));
77
+ if (value.length > 0) {
78
+ return value;
79
+ }
80
+ runtime.writeLine(`${label} is required.`);
81
+ }
82
+ }
83
+ async function promptConfirmedSecret(runtime, label, confirmationLabel) {
84
+ while (true) {
85
+ const first = normalizeRequiredValue(await runtime.inputSecret(label));
86
+ if (first.length === 0) {
87
+ runtime.writeLine(`${label} is required.`);
88
+ continue;
89
+ }
90
+ const second = normalizeRequiredValue(await runtime.inputSecret(confirmationLabel));
91
+ if (second.length === 0) {
92
+ runtime.writeLine(`${confirmationLabel} is required.`);
93
+ continue;
94
+ }
95
+ if (first !== second) {
96
+ runtime.writeLine("API key entries did not match. Try again.");
97
+ continue;
98
+ }
99
+ return first;
100
+ }
101
+ }
102
+ function normalizeRequiredValue(value) {
103
+ return value.trim();
104
+ }
105
+ function normalizeOptionalValue(value) {
106
+ const normalized = value.trim();
107
+ return normalized === "" ? null : normalized;
108
+ }
109
+ function parseTags(value) {
110
+ return value
111
+ .split(",")
112
+ .map((tag) => tag.trim())
113
+ .filter((tag) => tag.length > 0);
114
+ }