codexmate 0.0.7 → 0.0.8

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.
@@ -1,11 +1,12 @@
1
1
  name: release
2
- run-name: "${{ github.event.repository.name }} ${{ inputs.tag }}"
2
+ run-name: "${{ github.event.repository.name }} ${{ inputs.tag || 'auto' }}"
3
3
  on:
4
4
  workflow_dispatch:
5
5
  inputs:
6
6
  tag:
7
- description: 'Tag to release (e.g., v0.0.1)'
8
- required: true
7
+ description: 'Tag (e.g., v0.0.1). Empty = latest tag.'
8
+ required: false
9
+ default: ''
9
10
  permissions:
10
11
  contents: write
11
12
 
@@ -13,21 +14,134 @@ jobs:
13
14
  release:
14
15
  runs-on: ubuntu-latest
15
16
  steps:
16
- - name: Checkout tag
17
+ - name: Checkout
17
18
  uses: actions/checkout@v4
18
19
  with:
19
- ref: ${{ inputs.tag }}
20
20
  fetch-depth: 0
21
+ fetch-tags: true
22
+ - name: Fetch tags
23
+ run: git fetch --tags --force
21
24
  - uses: actions/setup-node@v4
22
25
  with:
23
26
  node-version: '18'
24
27
  cache: 'npm'
28
+ - name: Resolve release tag
29
+ id: resolve
30
+ env:
31
+ INPUT_TAG: ${{ inputs.tag }}
32
+ run: |
33
+ node - <<'NODE'
34
+ const { execSync } = require('child_process');
35
+ const fs = require('fs');
36
+
37
+ const inputTagRaw = (process.env.INPUT_TAG || '').trim();
38
+ const normalizeTag = (tag) => tag.startsWith('v') ? tag.slice(1) : tag;
39
+ const isSemver = (version) => /^\d+\.\d+\.\d+$/.test(version);
40
+ const parseSemver = (version) => {
41
+ if (!isSemver(version)) return null;
42
+ const [major, minor, patch] = version.split('.').map(n => Number(n));
43
+ return { major, minor, patch };
44
+ };
45
+
46
+ let latestTag = '';
47
+ try {
48
+ latestTag = execSync("git tag --list 'v*' --sort=-v:refname | head -n 1", { encoding: 'utf8' }).trim();
49
+ } catch (e) {
50
+ latestTag = '';
51
+ }
52
+
53
+ const pkg = require('./package.json');
54
+ const pkgVersion = pkg.version;
55
+ if (!isSemver(pkgVersion)) {
56
+ console.error(`package.json version ${pkgVersion} is not a valid semver.`);
57
+ process.exit(1);
58
+ }
59
+
60
+ const latestVersion = latestTag ? normalizeTag(latestTag) : '';
61
+ const latestSemver = latestVersion ? parseSemver(latestVersion) : null;
62
+
63
+ let resolvedTag = '';
64
+ let expectedVersion = '';
65
+ let mode = '';
66
+ let baseVersion = '';
67
+ let baseSource = '';
68
+
69
+ if (inputTagRaw) {
70
+ if (!/^v?\d+\.\d+\.\d+$/.test(inputTagRaw)) {
71
+ console.error('Invalid tag format. Use vX.Y.Z or X.Y.Z.');
72
+ process.exit(1);
73
+ }
74
+ resolvedTag = inputTagRaw.startsWith('v') ? inputTagRaw : `v${inputTagRaw}`;
75
+ expectedVersion = normalizeTag(resolvedTag);
76
+ mode = 'manual';
77
+ } else {
78
+ mode = 'auto';
79
+ if (!latestTag) {
80
+ console.error('No git tag found. Please create an initial tag or use manual tag input.');
81
+ process.exit(1);
82
+ }
83
+ if (!latestSemver) {
84
+ console.error(`Latest tag ${latestTag} is not a valid semver.`);
85
+ process.exit(1);
86
+ }
87
+ resolvedTag = latestTag;
88
+ expectedVersion = latestVersion;
89
+ baseVersion = latestVersion;
90
+ baseSource = 'latest_tag';
91
+ }
92
+
93
+ const envLines = [
94
+ `RELEASE_TAG=${resolvedTag}`,
95
+ `RELEASE_VERSION=${expectedVersion}`,
96
+ `RELEASE_MODE=${mode}`,
97
+ `LATEST_TAG=${latestTag}`,
98
+ `PACKAGE_VERSION=${pkgVersion}`,
99
+ `BASE_VERSION=${baseVersion}`,
100
+ `BASE_SOURCE=${baseSource}`
101
+ ].join('\n') + '\n';
102
+ fs.appendFileSync(process.env.GITHUB_ENV, envLines);
103
+
104
+ const outputLines = [
105
+ `release_tag=${resolvedTag}`,
106
+ `release_version=${expectedVersion}`,
107
+ `release_mode=${mode}`,
108
+ `latest_tag=${latestTag}`,
109
+ `package_version=${pkgVersion}`,
110
+ `base_version=${baseVersion}`,
111
+ `base_source=${baseSource}`
112
+ ].join('\n') + '\n';
113
+ fs.appendFileSync(process.env.GITHUB_OUTPUT, outputLines);
114
+
115
+ const summaryLines = [
116
+ '### Release Preview',
117
+ `- mode: ${mode}`,
118
+ `- input_tag: ${inputTagRaw || '(empty)'}`,
119
+ `- latest_tag: ${latestTag || '(none)'}`,
120
+ `- package_version: ${pkgVersion}`,
121
+ `- base_version: ${baseVersion || '(none)'}`,
122
+ `- base_source: ${baseSource || '(none)'}`,
123
+ `- resolved_tag: ${resolvedTag}`,
124
+ `- expected_version: ${expectedVersion}`
125
+ ].join('\n');
126
+ fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, summaryLines + '\n');
127
+ console.log(`::notice title=Resolved Tag::${resolvedTag}`);
128
+ NODE
129
+ - name: Checkout target tag
130
+ env:
131
+ RELEASE_TAG: ${{ steps.resolve.outputs.release_tag }}
132
+ run: |
133
+ git rev-parse "refs/tags/${RELEASE_TAG}" >/dev/null 2>&1
134
+ git checkout "${RELEASE_TAG}"
25
135
  - name: Verify tag matches package.json version
136
+ env:
137
+ RELEASE_TAG: ${{ steps.resolve.outputs.release_tag }}
26
138
  run: |
27
- node -e "const pkg=require('./package.json'); const tag='${{ inputs.tag }}'; const expected='v'+pkg.version; if(tag!==expected){ console.error('Tag '+tag+' does not match package.json version '+expected); process.exit(1);} console.log('Tag matches '+expected);"
139
+ node -e "const pkg=require('./package.json'); const tag=process.env.RELEASE_TAG; const expected='v'+pkg.version; if(tag!==expected){ console.error('Tag '+tag+' does not match package.json version '+expected); process.exit(1);} console.log('Tag matches '+expected);"
28
140
  - name: Compute release name
141
+ env:
142
+ RELEASE_TAG: ${{ steps.resolve.outputs.release_tag }}
29
143
  run: |
30
- node -e "const p=require('./package.json'); const tag='${{ inputs.tag }}'; const name=p.name.includes('/')? p.name.split('/')[1]: p.name; const value=name+' '+tag; console.log('RELEASE_NAME='+value);" >> "$GITHUB_ENV"
144
+ node -e "const p=require('./package.json'); const tag=process.env.RELEASE_TAG; const name=p.name.includes('/')? p.name.split('/')[1]: p.name; const value=name+' '+tag; console.log('RELEASE_NAME='+value);" >> "$GITHUB_ENV"
31
145
  - name: Pack npm artifact
32
146
  run: |
33
147
  name=$(node -e "const p=require('./package.json'); const n=p.name.replace('@','').replace('/','-'); process.stdout.write(n+'-'+p.version+'.tgz');")
@@ -37,7 +151,7 @@ jobs:
37
151
  - name: Create GitHub Release
38
152
  uses: softprops/action-gh-release@v2
39
153
  with:
40
- tag_name: ${{ inputs.tag }}
154
+ tag_name: ${{ steps.resolve.outputs.release_tag }}
41
155
  name: ${{ env.RELEASE_NAME }}
42
156
  prerelease: false
43
157
  draft: false
package/README.md CHANGED
@@ -49,7 +49,7 @@ Codex Mate makes frequent provider/model switching for Codex and Claude Code a s
49
49
 
50
50
  - Only configuration management for Codex, Claude Code, and OpenClaw, not a full all-in-one tool suite
51
51
  - No built-in proxy/relay/billing dashboard/cloud sync (kept lightweight)
52
- - Web UI runs only when you start it (`codexmate start`)
52
+ - Web UI runs only when you start it (`codexmate run`)
53
53
 
54
54
  ## 30-Second Start (No Install)
55
55
 
@@ -58,7 +58,7 @@ npx codexmate@latest status
58
58
  ```
59
59
 
60
60
  ```bash
61
- npx codexmate@latest start
61
+ npx codexmate@latest run
62
62
  ```
63
63
 
64
64
  Then open `http://localhost:3737` in your browser.
@@ -87,7 +87,7 @@ codexmate status
87
87
 
88
88
  4. Start the Web UI:
89
89
  ```bash
90
- codexmate start
90
+ codexmate run
91
91
  ```
92
92
 
93
93
  Then open `http://localhost:3737` in your browser.
@@ -123,7 +123,7 @@ npx codexmate@latest status
123
123
  ```
124
124
 
125
125
  ```bash
126
- npx codexmate@latest start
126
+ npx codexmate@latest run
127
127
  ```
128
128
 
129
129
  ### From Source
@@ -152,18 +152,19 @@ npm link
152
152
  | `codexmate use <model>` | Switch model |
153
153
  | `codexmate add <name> <URL> [API key]` | Add a provider |
154
154
  | `codexmate delete <provider>` | Delete a provider |
155
+ | `codexmate claude <BaseURL> <API key> [model]` | Write Claude Code config to `~/.claude/settings.json` |
155
156
  | `codexmate models` | List all models |
156
- | `codexmate add-model <model>` | Add a model |
157
- | `codexmate delete-model <model>` | Delete a model |
158
- | `codexmate start` | Start the Web UI |
159
- | `codexmate export-session --source <codex|claude> (--session-id <ID>|--file <PATH>) [--output <PATH>] [--max-messages <N|all|Infinity>]` | Export a session to Markdown |
157
+ | `codexmate add-model <model>` | Add a model |
158
+ | `codexmate delete-model <model>` | Delete a model |
159
+ | `codexmate run` | Start the Web UI |
160
+ | `codexmate export-session --source <codex|claude> (--session-id <ID>|--file <PATH>) [--output <PATH>] [--max-messages <N|all|Infinity>]` | Export a session to Markdown |
160
161
 
161
162
  ## Web UI
162
163
 
163
164
  Start the Web UI (auto opens browser):
164
165
 
165
166
  ```bash
166
- codexmate start
167
+ codexmate run
167
168
  ```
168
169
 
169
170
  ### Codex Config Mode
@@ -180,6 +181,13 @@ codexmate start
180
181
  - Manage multiple Claude Code profiles
181
182
  - Configure API key, Base URL, and model
182
183
  - Default write to `env` in `~/.claude/settings.json`: `env.ANTHROPIC_API_KEY` / `env.ANTHROPIC_BASE_URL` / `env.ANTHROPIC_MODEL`
184
+ - One-liner apply via CLI:
185
+
186
+ ```bash
187
+ codexmate claude https://api.example.com/v1 sk-ant-xxx claude-3-7-sonnet
188
+ ```
189
+
190
+ - In the Web UI, each Claude configuration card now has a "Share Import Command" button that copies a one-click import command (for example: `codexmate claude <BaseURL> <API Key> <Model>`).
183
191
 
184
192
  ### OpenClaw Config Mode
185
193
 
@@ -243,43 +251,43 @@ codexmate add myapi https://api.example.com/v1 sk-your-api-key
243
251
  codexmate switch myapi
244
252
  ```
245
253
 
246
- ### Switch to a Different Model
247
-
248
- ```bash
249
- codexmate use gpt-4-turbo
250
- ```
251
-
252
- ### Export a Session (CLI)
253
-
254
- ```bash
255
- codexmate export-session --source codex --session-id 123456
256
- codexmate export-session --source claude --file "~/.claude/projects/demo/session.jsonl" --max-messages=all
257
- ```
258
-
259
- By default, exports are capped at 1000 messages. Use `--max-messages=all` (or `Infinity`) to export everything.
260
-
261
- ### Configure Claude Code (Cross-Platform)
262
-
263
- 1. Start the Web UI: `codexmate start`
254
+ ### Switch to a Different Model
255
+
256
+ ```bash
257
+ codexmate use gpt-4-turbo
258
+ ```
259
+
260
+ ### Export a Session (CLI)
261
+
262
+ ```bash
263
+ codexmate export-session --source codex --session-id 123456
264
+ codexmate export-session --source claude --file "~/.claude/projects/demo/session.jsonl" --max-messages=all
265
+ ```
266
+
267
+ By default, exports are capped at 1000 messages. Use `--max-messages=all` (or `Infinity`) to export everything.
268
+
269
+ ### Configure Claude Code (Cross-Platform)
270
+
271
+ 1. Start the Web UI: `codexmate run`
264
272
  2. Switch to "Claude Code Config" mode in the browser
265
273
  3. Add a profile (example Zhipu GLM): Name=ZhipuGLM, API Key=your API key, Base URL=`https://open.bigmodel.cn/api/anthropic`, Model=`glm-4.7`
266
274
  4. Click the card to apply, or use "Save & Apply to Claude Config" in the editor
267
275
  5. Default write to `~/.claude/settings.json`
268
276
  6. Restart Claude Code to apply
269
277
 
270
- ### Start the Web UI
271
-
272
- ```bash
273
- codexmate start
274
- ```
275
-
276
- By default it binds to `127.0.0.1`. To expose on LAN, use `--host` or `CODEXMATE_HOST`:
277
-
278
- ```bash
279
- codexmate start --host 0.0.0.0
280
- ```
281
-
282
- Then open `http://localhost:3737` (or your chosen host). Note: binding to `0.0.0.0` is unsafe on untrusted networks.
278
+ ### Start the Web UI
279
+
280
+ ```bash
281
+ codexmate run
282
+ ```
283
+
284
+ By default it binds to `127.0.0.1`. To expose on LAN, use `--host` or `CODEXMATE_HOST`:
285
+
286
+ ```bash
287
+ codexmate run --host 0.0.0.0
288
+ ```
289
+
290
+ Then open `http://localhost:3737` (or your chosen host). Note: binding to `0.0.0.0` is unsafe on untrusted networks.
283
291
 
284
292
  ## FAQ
285
293
 
package/README.zh-CN.md CHANGED
@@ -49,7 +49,7 @@ Codex Mate 让 Codex 与 Claude Code 的提供商/模型切换变成“一条命
49
49
 
50
50
  - 只做 Codex、Claude Code 与 OpenClaw 的配置管理,不做全量多工具一体化
51
51
  - 不内置代理/转发/费用面板/云同步(保持轻量)
52
- - Web UI 仅在你启动时运行(`codexmate start`)
52
+ - Web UI 仅在你启动时运行(`codexmate run`)
53
53
 
54
54
  ## 30 秒上手(免安装)
55
55
 
@@ -58,7 +58,7 @@ npx codexmate@latest status
58
58
  ```
59
59
 
60
60
  ```bash
61
- npx codexmate@latest start
61
+ npx codexmate@latest run
62
62
  ```
63
63
 
64
64
  然后在浏览器中打开 `http://localhost:3737`。
@@ -87,7 +87,7 @@ codexmate status
87
87
 
88
88
  4. 启动 Web 界面:
89
89
  ```bash
90
- codexmate start
90
+ codexmate run
91
91
  ```
92
92
 
93
93
  然后在浏览器中打开 `http://localhost:3737`。
@@ -123,7 +123,7 @@ npx codexmate@latest status
123
123
  ```
124
124
 
125
125
  ```bash
126
- npx codexmate@latest start
126
+ npx codexmate@latest run
127
127
  ```
128
128
 
129
129
  ### 从源码安装
@@ -152,18 +152,19 @@ npm link
152
152
  | `codexmate use <模型名称>` | 切换模型 |
153
153
  | `codexmate add <名称> <URL> [API密钥]` | 添加新提供商 |
154
154
  | `codexmate delete <提供商名称>` | 删除提供商 |
155
+ | `codexmate claude <BaseURL> <API密钥> [模型]` | 一键写入 Claude Code 配置到 `~/.claude/settings.json` |
155
156
  | `codexmate models` | 列出所有模型 |
156
- | `codexmate add-model <模型名称>` | 添加模型 |
157
- | `codexmate delete-model <模型名称>` | 删除模型 |
158
- | `codexmate start` | 启动 Web 界面 |
159
- | `codexmate export-session --source <codex|claude> (--session-id <ID>|--file <PATH>) [--output <PATH>] [--max-messages <N|all|Infinity>]` | 导出指定会话为 Markdown |
157
+ | `codexmate add-model <模型名称>` | 添加模型 |
158
+ | `codexmate delete-model <模型名称>` | 删除模型 |
159
+ | `codexmate run` | 启动 Web 界面 |
160
+ | `codexmate export-session --source <codex|claude> (--session-id <ID>|--file <PATH>) [--output <PATH>] [--max-messages <N|all|Infinity>]` | 导出指定会话为 Markdown |
160
161
 
161
162
  ## Web 界面
162
163
 
163
164
  启动 Web 界面(自动打开浏览器):
164
165
 
165
166
  ```bash
166
- codexmate start
167
+ codexmate run
167
168
  ```
168
169
 
169
170
  ### Codex 配置模式
@@ -180,6 +181,13 @@ codexmate start
180
181
  - 管理多个 Claude Code 配置方案
181
182
  - 配置 API Key、Base URL 和模型
182
183
  - 默认写入 `~/.claude/settings.json` 的 `env` 字段:`env.ANTHROPIC_API_KEY` / `env.ANTHROPIC_BASE_URL` / `env.ANTHROPIC_MODEL`
184
+ - CLI 一行应用示例:
185
+
186
+ ```bash
187
+ codexmate claude https://api.example.com/v1 sk-ant-xxx claude-3-7-sonnet
188
+ ```
189
+
190
+ - Web 界面中每个 Claude 配置卡片新增“分享导入命令”按钮,可复制一条 `codexmate claude <BaseURL> <API Key> <模型>` 命令便于分享。
183
191
 
184
192
  ### OpenClaw 配置模式
185
193
 
@@ -243,43 +251,43 @@ codexmate add myapi https://api.example.com/v1 sk-your-api-key
243
251
  codexmate switch myapi
244
252
  ```
245
253
 
246
- ### 切换到不同的模型
247
-
248
- ```bash
249
- codexmate use gpt-4-turbo
250
- ```
251
-
252
- ### 导出会话(CLI)
253
-
254
- ```bash
255
- codexmate export-session --source codex --session-id 123456
256
- codexmate export-session --source claude --file "~/.claude/projects/demo/session.jsonl" --max-messages=all
257
- ```
258
-
259
- 默认最多导出 1000 条消息;如需完整导出可用 `--max-messages=all`(或 `Infinity`)。
260
-
261
- ### 配置 Claude Code(跨平台)
262
-
263
- 1. 启动 Web 界面:`codexmate start`
254
+ ### 切换到不同的模型
255
+
256
+ ```bash
257
+ codexmate use gpt-4-turbo
258
+ ```
259
+
260
+ ### 导出会话(CLI)
261
+
262
+ ```bash
263
+ codexmate export-session --source codex --session-id 123456
264
+ codexmate export-session --source claude --file "~/.claude/projects/demo/session.jsonl" --max-messages=all
265
+ ```
266
+
267
+ 默认最多导出 1000 条消息;如需完整导出可用 `--max-messages=all`(或 `Infinity`)。
268
+
269
+ ### 配置 Claude Code(跨平台)
270
+
271
+ 1. 启动 Web 界面:`codexmate run`
264
272
  2. 在浏览器中切换到 "Claude Code 配置" 模式
265
273
  3. 添加配置方案(例如智谱 GLM):配置名称=智谱GLM,API Key=你的 API Key,Base URL=`https://open.bigmodel.cn/api/anthropic`,模型=`glm-4.7`
266
274
  4. 点击配置卡片直接应用,或在编辑弹窗点击“保存并应用到 Claude 配置”
267
275
  5. 默认写入 `~/.claude/settings.json`
268
276
  6. 重启 Claude Code,新的配置即生效
269
277
 
270
- ### 启动 Web 界面
271
-
272
- ```bash
273
- codexmate start
274
- ```
275
-
276
- 默认仅监听 `127.0.0.1`。如需局域网访问,可用 `--host` 或 `CODEXMATE_HOST`:
277
-
278
- ```bash
279
- codexmate start --host 0.0.0.0
280
- ```
281
-
282
- 然后在浏览器中打开 `http://localhost:3737`(或你指定的地址)。注意:监听 `0.0.0.0` 在不可信网络下不安全。
278
+ ### 启动 Web 界面
279
+
280
+ ```bash
281
+ codexmate run
282
+ ```
283
+
284
+ 默认仅监听 `127.0.0.1`。如需局域网访问,可用 `--host` 或 `CODEXMATE_HOST`:
285
+
286
+ ```bash
287
+ codexmate run --host 0.0.0.0
288
+ ```
289
+
290
+ 然后在浏览器中打开 `http://localhost:3737`(或你指定的地址)。注意:监听 `0.0.0.0` 在不可信网络下不安全。
283
291
 
284
292
  ## 常见问题
285
293