agentsw 0.10.1 → 0.10.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.
- package/README.md +58 -17
- package/README.zh-CN.md +53 -17
- package/dist/commands.js +4 -1
- package/dist/config-transaction.js +22 -17
- package/dist/targets/codex.js +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,20 +17,7 @@ without touching the settings you hand-tuned.
|
|
|
17
17
|
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
$ asw use myproxy -m glm-5.3-flash
|
|
22
|
-
switching to myproxy (openai) · default model glm-5.3-flash
|
|
23
|
-
|
|
24
|
-
skip claude Claude Code does not support openai-protocol providers
|
|
25
|
-
ok codex ~/.codex/config.toml, ~/.codex/auth.json
|
|
26
|
-
backup: ~/.config/agentsw/backups/transaction-<unique>
|
|
27
|
-
ok omp ~/.omp/agent/models.yml
|
|
28
|
-
select in omp with: omp --model myproxy/glm-5.3-flash
|
|
29
|
-
skip pi pi not detected (pass --apps pi to force)
|
|
30
|
-
ok opencode ~/.config/opencode/opencode.json
|
|
31
|
-
ok dsh ~/.dsh/settings.yaml, ~/.dsh/.credentials.yaml
|
|
32
|
-
select in dsh with the model picker, or run: dsh web
|
|
33
|
-
```
|
|
20
|
+

|
|
34
21
|
|
|
35
22
|
`agentsw` and the short `asw` are the same binary.
|
|
36
23
|
|
|
@@ -54,9 +41,37 @@ ok dsh ~/.dsh/settings.yaml, ~/.dsh/.credentials.yaml
|
|
|
54
41
|
- **Wire-aware.** `/v1/chat/completions` and `/v1/responses` are different endpoints;
|
|
55
42
|
agentsw tracks which one a provider speaks and never downgrades a working one.
|
|
56
43
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
44
|
+
## How it compares
|
|
45
|
+
|
|
46
|
+
Two projects do most of this better than agentsw does, and both are worth your time:
|
|
47
|
+
|
|
48
|
+
- **[cc-switch](https://github.com/farion1231/cc-switch)** — a desktop app (Tauri) for ten tools:
|
|
49
|
+
one-click switching, 90+ provider presets, MCP/Skills/Prompts management, local routing and
|
|
50
|
+
failover with API-format conversion, a usage and cost dashboard, a session manager, and
|
|
51
|
+
WebDAV/S3 sync.
|
|
52
|
+
- **[cc-switch-cli](https://github.com/SaladDay/cc-switch-cli)** — the community CLI fork of the
|
|
53
|
+
same idea: TUI plus scriptable subcommands, seven tools, MCP and skills, a daemon proxy with
|
|
54
|
+
token accounting, SQLite-backed state.
|
|
55
|
+
|
|
56
|
+
Between them they cover Claude Code, Claude Desktop, Codex, Gemini CLI, OpenCode, Hermes,
|
|
57
|
+
OpenClaw, Pi, Grok Build and MiniMax Code. agentsw covers a different nine — Claude Code, Codex,
|
|
58
|
+
omp, pi, prime-agent, opencode, Hermes, WorkBuddy and DeepSeek Harness — **four of which neither
|
|
59
|
+
other tool writes at all.**
|
|
60
|
+
|
|
61
|
+
| | agentsw | cc-switch | cc-switch-cli |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| Interface | CLI, `--json` for scripts | desktop GUI | TUI + CLI |
|
|
64
|
+
| Model metadata (models.dev + AI Gateway) written into each app's own fields | **yes** | no | no |
|
|
65
|
+
| MCP / Skills / Prompts management | — | yes | yes |
|
|
66
|
+
| Routing, API-format conversion, failover | — | yes | yes |
|
|
67
|
+
| Usage and cost dashboard | — | yes | yes |
|
|
68
|
+
| Presets, sessions, cloud sync, deep links | — | yes | partial |
|
|
69
|
+
| Reads the other tool's provider store | yes — read-only `import` | — | — |
|
|
70
|
+
|
|
71
|
+
The honest summary: **if you want a GUI, MCP management, or a failover proxy, use cc-switch.** If
|
|
72
|
+
you use omp, prime-agent, WorkBuddy or DeepSeek Harness, or you want each agent to receive real
|
|
73
|
+
model metadata instead of a bare id, that is what agentsw is for. It reads cc-switch's store
|
|
74
|
+
rather than competing with it.
|
|
60
75
|
|
|
61
76
|
## Install
|
|
62
77
|
|
|
@@ -104,6 +119,32 @@ opencode yes openai+anthropic myproxy/glm-5.3-flash ~/.co
|
|
|
104
119
|
dsh yes openai+anthropic myproxy · glm-5.3-flash ~/.dsh/settings.yaml
|
|
105
120
|
```
|
|
106
121
|
|
|
122
|
+
And the point of the whole thing — one command writes every detected agent (this is the run in
|
|
123
|
+
the animation at the top of this page, as text):
|
|
124
|
+
|
|
125
|
+
```console
|
|
126
|
+
$ asw use myproxy
|
|
127
|
+
switching to myproxy (openai) · default model glm-5.3-flash
|
|
128
|
+
|
|
129
|
+
skip claude Claude Code does not support openai-protocol providers
|
|
130
|
+
ok codex ~/.codex/config.toml, ~/.codex/auth.json
|
|
131
|
+
ok omp ~/.omp/agent/models.yml
|
|
132
|
+
select in omp with: omp --model myproxy/glm-5.3-flash
|
|
133
|
+
ok pi ~/.pi/agent/models.json, ~/.pi/agent/settings.json
|
|
134
|
+
ok prime ~/.prime/agent/models.json, ~/.prime/agent/settings.json
|
|
135
|
+
ok opencode ~/.config/opencode/opencode.json
|
|
136
|
+
ok hermes ~/.hermes/config.yaml, ~/.hermes/.env
|
|
137
|
+
ok workbuddy ~/.workbuddy/models.json, ~/.workbuddy/settings.json
|
|
138
|
+
WorkBuddy watches models.json; models appear in the selector's custom section without restart
|
|
139
|
+
ok dsh ~/.dsh/settings.yaml, ~/.dsh/.credentials.yaml
|
|
140
|
+
select in dsh with the model picker, or run: dsh web
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`claude` is the only skip: Claude Code speaks the Anthropic protocol, and `myproxy` is an
|
|
144
|
+
OpenAI-protocol provider. On a machine where an agent's config already exists, committing to it
|
|
145
|
+
also prints a `backup: ~/.config/agentsw/backups/transaction-<unique>` line; this sandbox starts
|
|
146
|
+
with empty configs, so there is nothing to back up and none appear.
|
|
147
|
+
|
|
107
148
|
## Supported apps
|
|
108
149
|
|
|
109
150
|
| App | Config written | Protocols |
|
package/README.zh-CN.md
CHANGED
|
@@ -17,20 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
$ asw use myproxy -m glm-5.3-flash
|
|
22
|
-
switching to myproxy (openai) · default model glm-5.3-flash
|
|
23
|
-
|
|
24
|
-
skip claude Claude Code does not support openai-protocol providers
|
|
25
|
-
ok codex ~/.codex/config.toml, ~/.codex/auth.json
|
|
26
|
-
backup: ~/.config/agentsw/backups/transaction-<unique>
|
|
27
|
-
ok omp ~/.omp/agent/models.yml
|
|
28
|
-
select in omp with: omp --model myproxy/glm-5.3-flash
|
|
29
|
-
skip pi pi not detected (pass --apps pi to force)
|
|
30
|
-
ok opencode ~/.config/opencode/opencode.json
|
|
31
|
-
ok dsh ~/.dsh/settings.yaml, ~/.dsh/.credentials.yaml
|
|
32
|
-
select in dsh with the model picker, or run: dsh web
|
|
33
|
-
```
|
|
20
|
+

|
|
34
21
|
|
|
35
22
|
`agentsw` 和短名 `asw` 是同一个可执行文件。
|
|
36
23
|
|
|
@@ -53,9 +40,33 @@ ok dsh ~/.dsh/settings.yaml, ~/.dsh/.credentials.yaml
|
|
|
53
40
|
- **区分接口形态。** `/v1/chat/completions` 与 `/v1/responses` 是两个不同端点;
|
|
54
41
|
agentsw 记录供应商说的是哪一种,并且绝不把可用的 responses 降级。
|
|
55
42
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
43
|
+
## 它和同类工具的关系
|
|
44
|
+
|
|
45
|
+
有两件事别人做得比 agentsw 好,而且都值得你去看:
|
|
46
|
+
|
|
47
|
+
- **[cc-switch](https://github.com/farion1231/cc-switch)**——桌面应用(Tauri),支持十个工具:一键切换、
|
|
48
|
+
90+ 供应商预设、MCP/Skills/Prompts 管理、本地路由与故障转移(含 API 格式转换)、用量与成本仪表盘、
|
|
49
|
+
会话管理、WebDAV/S3 同步。
|
|
50
|
+
- **[cc-switch-cli](https://github.com/SaladDay/cc-switch-cli)**——同一思路的社区 CLI 分支:TUI + 可脚本化子命令、
|
|
51
|
+
七个工具、MCP 与 Skills、带 token 统计的守护进程代理、SQLite 存储。
|
|
52
|
+
|
|
53
|
+
两者合起来覆盖 Claude Code、Claude Desktop、Codex、Gemini CLI、OpenCode、Hermes、OpenClaw、Pi、
|
|
54
|
+
Grok Build、MiniMax Code。agentsw 覆盖的是另外九个——Claude Code、Codex、omp、pi、prime-agent、
|
|
55
|
+
opencode、Hermes、WorkBuddy、DeepSeek Harness——**其中四个另外两个工具根本不写。**
|
|
56
|
+
|
|
57
|
+
| | agentsw | cc-switch | cc-switch-cli |
|
|
58
|
+
|---|---|---|---|
|
|
59
|
+
| 形态 | CLI,`--json` 可脚本化 | 桌面 GUI | TUI + CLI |
|
|
60
|
+
| 从 models.dev + AI Gateway 取元数据,写入各应用自己的字段 | **是** | 无 | 无 |
|
|
61
|
+
| MCP / Skills / Prompts 管理 | — | 有 | 有 |
|
|
62
|
+
| 路由、API 格式转换、故障转移 | — | 有 | 有 |
|
|
63
|
+
| 用量与成本仪表盘 | — | 有 | 有 |
|
|
64
|
+
| 预设、会话、云同步、deep link | — | 有 | 部分 |
|
|
65
|
+
| 读取对方的供应商库 | 有——只读 `import` | — | — |
|
|
66
|
+
|
|
67
|
+
说实话的结论:**想要 GUI、MCP 管理或故障转移代理,用 cc-switch。** 如果你在用 omp、prime-agent、
|
|
68
|
+
WorkBuddy 或 DeepSeek Harness,或者你希望每个智能体拿到的是真实模型参数而不是一个裸 id,
|
|
69
|
+
那才是 agentsw 的用处。它读 cc-switch 的库,而不是跟它抢。
|
|
59
70
|
|
|
60
71
|
## 安装
|
|
61
72
|
|
|
@@ -99,6 +110,31 @@ opencode yes openai+anthropic myproxy/glm-5.3-flash ~/.co
|
|
|
99
110
|
dsh yes openai+anthropic myproxy · glm-5.3-flash ~/.dsh/settings.yaml
|
|
100
111
|
```
|
|
101
112
|
|
|
113
|
+
而这个工具真正的用处是另一条——一条命令写进所有检测到的智能体
|
|
114
|
+
(也就是本页顶部那段动画里跑的东西,文字版):
|
|
115
|
+
|
|
116
|
+
```console
|
|
117
|
+
$ asw use myproxy
|
|
118
|
+
switching to myproxy (openai) · default model glm-5.3-flash
|
|
119
|
+
|
|
120
|
+
skip claude Claude Code does not support openai-protocol providers
|
|
121
|
+
ok codex ~/.codex/config.toml, ~/.codex/auth.json
|
|
122
|
+
ok omp ~/.omp/agent/models.yml
|
|
123
|
+
select in omp with: omp --model myproxy/glm-5.3-flash
|
|
124
|
+
ok pi ~/.pi/agent/models.json, ~/.pi/agent/settings.json
|
|
125
|
+
ok prime ~/.prime/agent/models.json, ~/.prime/agent/settings.json
|
|
126
|
+
ok opencode ~/.config/opencode/opencode.json
|
|
127
|
+
ok hermes ~/.hermes/config.yaml, ~/.hermes/.env
|
|
128
|
+
ok workbuddy ~/.workbuddy/models.json, ~/.workbuddy/settings.json
|
|
129
|
+
WorkBuddy watches models.json; models appear in the selector's custom section without restart
|
|
130
|
+
ok dsh ~/.dsh/settings.yaml, ~/.dsh/.credentials.yaml
|
|
131
|
+
select in dsh with the model picker, or run: dsh web
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
唯一被跳过的是 `claude`:Claude Code 说的是 Anthropic 协议,而 `myproxy` 是 OpenAI 协议的供应商。
|
|
135
|
+
在智能体的配置已经存在的机器上,提交它时还会打印一行 `backup: ~/.config/agentsw/backups/transaction-<unique>`;
|
|
136
|
+
本沙箱从空配置开始,无物可备,因此没有这行。
|
|
137
|
+
|
|
102
138
|
## 支持的应用
|
|
103
139
|
|
|
104
140
|
| 应用 | 写入的配置 | 协议 |
|
package/dist/commands.js
CHANGED
|
@@ -483,7 +483,10 @@ function reportResults(results) {
|
|
|
483
483
|
out(`${pc.yellow(t("common.skip"))} ${r.app.padEnd(9)} ${pc.dim(r.skipped)}`);
|
|
484
484
|
continue;
|
|
485
485
|
}
|
|
486
|
-
|
|
486
|
+
// An empty change list means the app was already in sync: say so rather than
|
|
487
|
+
// printing a bare "ok" with nothing after it.
|
|
488
|
+
const detail = r.changed.length ? r.changed.join(", ") : pc.dim(t("preview.unchanged"));
|
|
489
|
+
out(`${pc.green("ok ")} ${r.app.padEnd(9)} ${detail}`);
|
|
487
490
|
for (const note of r.notes)
|
|
488
491
|
out(` ${" ".repeat(9)} ${pc.dim(note)}`);
|
|
489
492
|
}
|
|
@@ -144,26 +144,31 @@ export function commitFileChanges(changes, opts = {}) {
|
|
|
144
144
|
return withWriteLock(() => {
|
|
145
145
|
// Another writer may have committed between planning and acquiring the lock.
|
|
146
146
|
validateReads();
|
|
147
|
+
// Only a file that already existed has anything to save. When every planned
|
|
148
|
+
// file is new, no transaction directory is created: an empty one (nothing but
|
|
149
|
+
// its manifest) would read as a backup that does not exist.
|
|
147
150
|
let backupDir;
|
|
148
151
|
let currentFile = backupsDir;
|
|
149
152
|
try {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
153
|
+
if (plan.some((change) => change.before !== undefined)) {
|
|
154
|
+
fs.mkdirSync(backupsDir, { recursive: true, mode: 0o700 });
|
|
155
|
+
backupDir = fs.mkdtempSync(path.join(backupsDir, "transaction-"));
|
|
156
|
+
fs.chmodSync(backupDir, 0o700);
|
|
157
|
+
for (const [index, change] of plan.entries()) {
|
|
158
|
+
currentFile = change.file;
|
|
159
|
+
if (change.before === undefined)
|
|
160
|
+
continue;
|
|
161
|
+
const backup = path.join(backupDir, `${index}-${path.basename(change.file)}`);
|
|
162
|
+
fs.writeFileSync(backup, change.before, { flag: "wx", mode: 0o600 });
|
|
163
|
+
fs.chmodSync(backup, 0o600);
|
|
164
|
+
}
|
|
165
|
+
fs.writeFileSync(path.join(backupDir, "manifest.json"), JSON.stringify(plan.map((change, index) => ({
|
|
166
|
+
file: change.file,
|
|
167
|
+
backup: change.before === undefined ? null : `${index}-${path.basename(change.file)}`,
|
|
168
|
+
mode: change.original.mode,
|
|
169
|
+
})), null, 2) + "\n", { flag: "wx", mode: 0o600 });
|
|
170
|
+
fs.chmodSync(path.join(backupDir, "manifest.json"), 0o600);
|
|
160
171
|
}
|
|
161
|
-
fs.writeFileSync(path.join(backupDir, "manifest.json"), JSON.stringify(plan.map((change, index) => ({
|
|
162
|
-
file: change.file,
|
|
163
|
-
backup: change.before === undefined ? null : `${index}-${path.basename(change.file)}`,
|
|
164
|
-
mode: change.original.mode,
|
|
165
|
-
})), null, 2) + "\n", { flag: "wx", mode: 0o600 });
|
|
166
|
-
fs.chmodSync(path.join(backupDir, "manifest.json"), 0o600);
|
|
167
172
|
validateReads();
|
|
168
173
|
}
|
|
169
174
|
catch {
|
|
@@ -216,7 +221,7 @@ export function commitFileChanges(changes, opts = {}) {
|
|
|
216
221
|
}
|
|
217
222
|
catch { /* Only remove empty directories created by this transaction. */ }
|
|
218
223
|
}
|
|
219
|
-
throw new Error(`${currentFile}: configuration transaction failed; ${failed.length ? `rollback incomplete for ${failed.join(", ")}` : "previous writes rolled back"}
|
|
224
|
+
throw new Error(`${currentFile}: configuration transaction failed; ${failed.length ? `rollback incomplete for ${failed.join(", ")}` : "previous writes rolled back"}${backupDir ? `; backups: ${backupDir}` : "; no files needed backing up"}`);
|
|
220
225
|
}
|
|
221
226
|
return { files, backupDir };
|
|
222
227
|
});
|
package/dist/targets/codex.js
CHANGED
|
@@ -82,7 +82,11 @@ export const codex = transactionalTarget({
|
|
|
82
82
|
wire_api: "responses",
|
|
83
83
|
requires_openai_auth: true,
|
|
84
84
|
};
|
|
85
|
-
|
|
85
|
+
// Only worth saying when the endpoint has not declared itself Responses-compatible:
|
|
86
|
+
// a provider the user already marked `responses` needs no caveat.
|
|
87
|
+
if (provider.openaiApi !== "responses") {
|
|
88
|
+
notes.push("codex requires an OpenAI Responses-compatible endpoint (/v1/responses); chat-completions-only endpoints will not work");
|
|
89
|
+
}
|
|
86
90
|
config.model_providers = providers;
|
|
87
91
|
const configBackup = backupFile(configFile);
|
|
88
92
|
if (configBackup)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentsw",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "CLI provider switcher for coding agents: manage OpenAI/Anthropic-protocol providers in one place and sync them, with models.dev metadata, into Claude Code, Codex, omp, pi, prime-agent, opencode, Hermes, WorkBuddy and DeepSeek Harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|