qwenproxy-cli 1.0.28 → 1.0.29
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/package.json +3 -3
- package/src/sync/aider.ts +118 -0
- package/src/sync/cline.ts +110 -0
- package/src/sync/hermes.ts +105 -0
- package/src/sync/index.ts +323 -8
- package/src/sync/kilo.ts +230 -0
- package/src/sync/openclaw.ts +237 -0
- package/src/sync/types.ts +29 -3
- package/src/sync/zed.ts +210 -0
- package/src/sync-clients.ts +32 -18
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import type { ClientSyncResult, SyncOptions } from "./types.ts";
|
|
4
|
+
import { createTimestampBackup, restoreFromBackup } from "./utils.ts";
|
|
5
|
+
|
|
6
|
+
function findKeyObjectSpan(content: string, key: string): { start: number; end: number; hasTrailingComma: boolean } | null {
|
|
7
|
+
const regex = new RegExp(`"${key}"\\s*:\\s*\\{`);
|
|
8
|
+
const match = content.match(regex);
|
|
9
|
+
if (!match || match.index === undefined) return null;
|
|
10
|
+
|
|
11
|
+
const startIndex = match.index;
|
|
12
|
+
const braceIndex = content.indexOf("{", startIndex + match[0].length - 1);
|
|
13
|
+
if (braceIndex === -1) return null;
|
|
14
|
+
|
|
15
|
+
let depth = 0;
|
|
16
|
+
let inString = false;
|
|
17
|
+
let inLineComment = false;
|
|
18
|
+
let inBlockComment = false;
|
|
19
|
+
let escape = false;
|
|
20
|
+
|
|
21
|
+
for (let i = braceIndex; i < content.length; i++) {
|
|
22
|
+
const ch = content[i];
|
|
23
|
+
const nextCh = content[i + 1] || "";
|
|
24
|
+
|
|
25
|
+
if (inLineComment) {
|
|
26
|
+
if (ch === "\n") inLineComment = false;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (inBlockComment) {
|
|
30
|
+
if (ch === "*" && nextCh === "/") {
|
|
31
|
+
inBlockComment = false;
|
|
32
|
+
i++;
|
|
33
|
+
}
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (inString) {
|
|
37
|
+
if (escape) {
|
|
38
|
+
escape = false;
|
|
39
|
+
} else if (ch === "\\") {
|
|
40
|
+
escape = true;
|
|
41
|
+
} else if (ch === '"') {
|
|
42
|
+
inString = false;
|
|
43
|
+
}
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (ch === "/" && nextCh === "/") {
|
|
48
|
+
inLineComment = true;
|
|
49
|
+
i++;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (ch === "/" && nextCh === "*") {
|
|
53
|
+
inBlockComment = true;
|
|
54
|
+
i++;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (ch === '"') {
|
|
59
|
+
inString = true;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (ch === "{") {
|
|
64
|
+
depth++;
|
|
65
|
+
} else if (ch === "}") {
|
|
66
|
+
depth--;
|
|
67
|
+
if (depth === 0) {
|
|
68
|
+
let endIndex = i + 1;
|
|
69
|
+
let hasTrailingComma = false;
|
|
70
|
+
while (endIndex < content.length && /[\s,]/.test(content[endIndex])) {
|
|
71
|
+
if (content[endIndex] === ",") {
|
|
72
|
+
hasTrailingComma = true;
|
|
73
|
+
endIndex++;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
if (content[endIndex] === "\n") {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
endIndex++;
|
|
80
|
+
}
|
|
81
|
+
return { start: startIndex, end: endIndex, hasTrailingComma };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function buildOpenClawProviderObject(
|
|
90
|
+
baseUrl: string,
|
|
91
|
+
apiKey: string,
|
|
92
|
+
model: string = "qwen3.8-max",
|
|
93
|
+
): Record<string, any> {
|
|
94
|
+
const models = [
|
|
95
|
+
{
|
|
96
|
+
id: model,
|
|
97
|
+
name: model === "qwen3.8-max" ? "Qwen 3.8 Max" : model,
|
|
98
|
+
reasoning: true,
|
|
99
|
+
supportsReasoningEffort: true,
|
|
100
|
+
supportedReasoningEfforts: ["low", "medium", "high"],
|
|
101
|
+
contextWindow: 1000000,
|
|
102
|
+
maxTokens: 65536,
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
if (model !== "qwen3.7-plus") {
|
|
107
|
+
models.push({
|
|
108
|
+
id: "qwen3.7-plus",
|
|
109
|
+
name: "Qwen 3.7 Plus",
|
|
110
|
+
reasoning: true,
|
|
111
|
+
supportsReasoningEffort: true,
|
|
112
|
+
supportedReasoningEfforts: ["low", "medium", "high"],
|
|
113
|
+
contextWindow: 1000000,
|
|
114
|
+
maxTokens: 65536,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
baseUrl,
|
|
120
|
+
apiKey,
|
|
121
|
+
api: "openai-completions",
|
|
122
|
+
models,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function syncOpenClaw(options: SyncOptions): ClientSyncResult {
|
|
127
|
+
const { filePath, apiKey, baseUrl, model = "qwen3.8-max", reasoningEffort = "high" } = options;
|
|
128
|
+
try {
|
|
129
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
130
|
+
|
|
131
|
+
let backupPath: string | undefined;
|
|
132
|
+
let content = "";
|
|
133
|
+
|
|
134
|
+
if (fs.existsSync(filePath)) {
|
|
135
|
+
backupPath = createTimestampBackup(filePath);
|
|
136
|
+
content = fs.readFileSync(filePath, "utf-8");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const providerObj = buildOpenClawProviderObject(baseUrl, apiKey, model);
|
|
140
|
+
const providerJson = JSON.stringify(providerObj, null, 6)
|
|
141
|
+
.split("\n")
|
|
142
|
+
.map((line, idx) => (idx === 0 ? line : ` ${line}`))
|
|
143
|
+
.join("\n");
|
|
144
|
+
|
|
145
|
+
const qwenEntry = ` "qwenproxy": ${providerJson}`;
|
|
146
|
+
|
|
147
|
+
if (!content.trim()) {
|
|
148
|
+
const initial = {
|
|
149
|
+
models: {
|
|
150
|
+
mode: "merge",
|
|
151
|
+
providers: {
|
|
152
|
+
qwenproxy: providerObj,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
agents: {
|
|
156
|
+
defaults: {
|
|
157
|
+
model: {
|
|
158
|
+
primary: `qwenproxy/${model}`,
|
|
159
|
+
},
|
|
160
|
+
thinking: {
|
|
161
|
+
effort: reasoningEffort,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
fs.writeFileSync(filePath, JSON.stringify(initial, null, 2) + "\n", "utf-8");
|
|
167
|
+
} else {
|
|
168
|
+
// Check if "qwenproxy" already exists under providers
|
|
169
|
+
const existingSpan = findKeyObjectSpan(content, "qwenproxy");
|
|
170
|
+
if (existingSpan) {
|
|
171
|
+
const comma = existingSpan.hasTrailingComma ? "," : "";
|
|
172
|
+
content =
|
|
173
|
+
content.slice(0, existingSpan.start) +
|
|
174
|
+
`"qwenproxy": ${providerJson}${comma}` +
|
|
175
|
+
content.slice(existingSpan.end);
|
|
176
|
+
} else {
|
|
177
|
+
const providersMatch = content.match(/"providers"\s*:\s*\{/);
|
|
178
|
+
if (providersMatch && providersMatch.index !== undefined) {
|
|
179
|
+
const insertIdx = providersMatch.index + providersMatch[0].length;
|
|
180
|
+
content =
|
|
181
|
+
content.slice(0, insertIdx) +
|
|
182
|
+
"\n" +
|
|
183
|
+
qwenEntry +
|
|
184
|
+
"," +
|
|
185
|
+
content.slice(insertIdx);
|
|
186
|
+
} else {
|
|
187
|
+
// If "providers" does not exist, check if "models" exists
|
|
188
|
+
const modelsMatch = content.match(/"models"\s*:\s*\{/);
|
|
189
|
+
if (modelsMatch && modelsMatch.index !== undefined) {
|
|
190
|
+
const insertIdx = modelsMatch.index + modelsMatch[0].length;
|
|
191
|
+
const providersBlock = `\n "providers": {\n${qwenEntry}\n },`;
|
|
192
|
+
content = content.slice(0, insertIdx) + providersBlock + content.slice(insertIdx);
|
|
193
|
+
} else {
|
|
194
|
+
// Append models before the last closing brace
|
|
195
|
+
const lastBraceIdx = content.lastIndexOf("}");
|
|
196
|
+
if (lastBraceIdx !== -1) {
|
|
197
|
+
const comma = content.slice(0, lastBraceIdx).trimEnd().endsWith("{") ? "" : ",";
|
|
198
|
+
const modelsBlock = `${comma}\n "models": {\n "mode": "merge",\n "providers": {\n${qwenEntry}\n }\n }\n`;
|
|
199
|
+
content = content.slice(0, lastBraceIdx).trimEnd() + modelsBlock + "}\n";
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
client: "openclaw",
|
|
210
|
+
filePath,
|
|
211
|
+
backupPath,
|
|
212
|
+
success: true,
|
|
213
|
+
action: backupPath ? "updated" : "created",
|
|
214
|
+
message: `Configured OpenClaw with provider qwenproxy (${baseUrl}) and reasoning effort ${reasoningEffort}`,
|
|
215
|
+
};
|
|
216
|
+
} catch (err: any) {
|
|
217
|
+
return {
|
|
218
|
+
client: "openclaw",
|
|
219
|
+
filePath,
|
|
220
|
+
success: false,
|
|
221
|
+
action: "failed",
|
|
222
|
+
error: err?.message || String(err),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export function restoreOpenClaw(filePath: string, backupPath?: string): ClientSyncResult {
|
|
228
|
+
const restored = restoreFromBackup(filePath, backupPath);
|
|
229
|
+
return {
|
|
230
|
+
client: "openclaw",
|
|
231
|
+
filePath,
|
|
232
|
+
backupPath,
|
|
233
|
+
success: restored,
|
|
234
|
+
action: restored ? "restored" : "failed",
|
|
235
|
+
message: restored ? "Restored OpenClaw config from backup" : "Backup file not found",
|
|
236
|
+
};
|
|
237
|
+
}
|
package/src/sync/types.ts
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
|
+
export type SyncClientName =
|
|
2
|
+
| "claude-code"
|
|
3
|
+
| "codex"
|
|
4
|
+
| "opencode"
|
|
5
|
+
| "omp"
|
|
6
|
+
| "hermes"
|
|
7
|
+
| "openclaw"
|
|
8
|
+
| "kilo"
|
|
9
|
+
| "cline"
|
|
10
|
+
| "zed"
|
|
11
|
+
| "aider";
|
|
12
|
+
|
|
1
13
|
export interface ClientSyncResult {
|
|
2
|
-
client:
|
|
14
|
+
client: SyncClientName;
|
|
3
15
|
filePath: string;
|
|
4
16
|
backupPath?: string;
|
|
17
|
+
extraBackupPath?: string;
|
|
5
18
|
success: boolean;
|
|
6
19
|
action: "updated" | "created" | "skipped" | "restored" | "failed";
|
|
7
20
|
message?: string;
|
|
@@ -14,6 +27,8 @@ export interface SyncOptions {
|
|
|
14
27
|
baseUrl: string;
|
|
15
28
|
model?: string;
|
|
16
29
|
setActive?: boolean;
|
|
30
|
+
reasoningEffort?: "low" | "medium" | "high" | "none";
|
|
31
|
+
modelSettingsPath?: string;
|
|
17
32
|
}
|
|
18
33
|
|
|
19
34
|
export interface SyncAllOptions {
|
|
@@ -22,15 +37,20 @@ export interface SyncAllOptions {
|
|
|
22
37
|
host?: string;
|
|
23
38
|
setActive?: boolean;
|
|
24
39
|
stateFilePath?: string;
|
|
25
|
-
targets?:
|
|
40
|
+
targets?: SyncClientName[];
|
|
26
41
|
customPaths?: {
|
|
27
42
|
claudeCode?: string;
|
|
28
43
|
codex?: string;
|
|
29
44
|
openCode?: string;
|
|
30
45
|
omp?: string;
|
|
46
|
+
hermes?: string;
|
|
47
|
+
openClaw?: string;
|
|
48
|
+
kilo?: string;
|
|
49
|
+
cline?: string;
|
|
50
|
+
zed?: string;
|
|
51
|
+
aider?: string;
|
|
31
52
|
};
|
|
32
53
|
}
|
|
33
|
-
|
|
34
54
|
export interface SyncRecord {
|
|
35
55
|
filePath: string;
|
|
36
56
|
backupPath: string;
|
|
@@ -49,5 +69,11 @@ export interface SyncStateFile {
|
|
|
49
69
|
codex?: SyncRecord;
|
|
50
70
|
openCode?: SyncRecord;
|
|
51
71
|
omp?: SyncRecord;
|
|
72
|
+
hermes?: SyncRecord;
|
|
73
|
+
openClaw?: SyncRecord;
|
|
74
|
+
kilo?: SyncRecord;
|
|
75
|
+
cline?: SyncRecord;
|
|
76
|
+
zed?: SyncRecord;
|
|
77
|
+
aider?: SyncRecord;
|
|
52
78
|
};
|
|
53
79
|
}
|
package/src/sync/zed.ts
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import type { ClientSyncResult, SyncOptions } from "./types.ts";
|
|
4
|
+
import { createTimestampBackup, restoreFromBackup } from "./utils.ts";
|
|
5
|
+
|
|
6
|
+
function parseJsonWithComments(raw: string): Record<string, any> {
|
|
7
|
+
let result = "";
|
|
8
|
+
let inString = false;
|
|
9
|
+
let inLineComment = false;
|
|
10
|
+
let inBlockComment = false;
|
|
11
|
+
let escape = false;
|
|
12
|
+
|
|
13
|
+
for (let i = 0; i < raw.length; i++) {
|
|
14
|
+
const ch = raw[i];
|
|
15
|
+
const nextCh = raw[i + 1] || "";
|
|
16
|
+
|
|
17
|
+
if (inLineComment) {
|
|
18
|
+
if (ch === "\n") {
|
|
19
|
+
inLineComment = false;
|
|
20
|
+
result += ch;
|
|
21
|
+
}
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (inBlockComment) {
|
|
25
|
+
if (ch === "*" && nextCh === "/") {
|
|
26
|
+
inBlockComment = false;
|
|
27
|
+
i++;
|
|
28
|
+
}
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (inString) {
|
|
32
|
+
result += ch;
|
|
33
|
+
if (escape) {
|
|
34
|
+
escape = false;
|
|
35
|
+
} else if (ch === "\\") {
|
|
36
|
+
escape = true;
|
|
37
|
+
} else if (ch === '"') {
|
|
38
|
+
inString = false;
|
|
39
|
+
}
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (ch === "/" && nextCh === "/") {
|
|
44
|
+
inLineComment = true;
|
|
45
|
+
i++;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (ch === "/" && nextCh === "*") {
|
|
49
|
+
inBlockComment = true;
|
|
50
|
+
i++;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (ch === '"') {
|
|
55
|
+
inString = true;
|
|
56
|
+
result += ch;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
result += ch;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const cleaned = result.replace(/,\s*([\}\]])/g, "$1");
|
|
64
|
+
return JSON.parse(cleaned);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function buildZedAvailableModels(primaryModel: string = "qwen3.8-max"): any[] {
|
|
68
|
+
const models = [
|
|
69
|
+
{
|
|
70
|
+
name: primaryModel,
|
|
71
|
+
max_tokens: 1000000,
|
|
72
|
+
max_output_tokens: 131072,
|
|
73
|
+
max_completion_tokens: 131072,
|
|
74
|
+
capabilities: {
|
|
75
|
+
tools: true,
|
|
76
|
+
images: true,
|
|
77
|
+
parallel_tool_calls: true,
|
|
78
|
+
prompt_cache_key: true,
|
|
79
|
+
chat_completions: true,
|
|
80
|
+
interleaved_reasoning: true,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: `${primaryModel}-thinking`,
|
|
85
|
+
max_tokens: 1000000,
|
|
86
|
+
max_output_tokens: 131072,
|
|
87
|
+
max_completion_tokens: 131072,
|
|
88
|
+
capabilities: {
|
|
89
|
+
tools: true,
|
|
90
|
+
images: true,
|
|
91
|
+
parallel_tool_calls: true,
|
|
92
|
+
prompt_cache_key: true,
|
|
93
|
+
chat_completions: true,
|
|
94
|
+
interleaved_reasoning: true,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: `${primaryModel}-fast`,
|
|
99
|
+
max_tokens: 1000000,
|
|
100
|
+
max_output_tokens: 131072,
|
|
101
|
+
max_completion_tokens: 131072,
|
|
102
|
+
capabilities: {
|
|
103
|
+
tools: true,
|
|
104
|
+
images: true,
|
|
105
|
+
parallel_tool_calls: true,
|
|
106
|
+
prompt_cache_key: true,
|
|
107
|
+
chat_completions: true,
|
|
108
|
+
interleaved_reasoning: true,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
if (primaryModel !== "qwen3.7-plus") {
|
|
114
|
+
models.push({
|
|
115
|
+
name: "qwen3.7-plus",
|
|
116
|
+
max_tokens: 1000000,
|
|
117
|
+
max_output_tokens: 65536,
|
|
118
|
+
max_completion_tokens: 65536,
|
|
119
|
+
capabilities: {
|
|
120
|
+
tools: true,
|
|
121
|
+
images: true,
|
|
122
|
+
parallel_tool_calls: true,
|
|
123
|
+
prompt_cache_key: true,
|
|
124
|
+
chat_completions: true,
|
|
125
|
+
interleaved_reasoning: true,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return models;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function syncZed(options: SyncOptions): ClientSyncResult {
|
|
134
|
+
const { filePath, baseUrl, model = "qwen3.8-max", setActive = true } = options;
|
|
135
|
+
try {
|
|
136
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
137
|
+
|
|
138
|
+
let backupPath: string | undefined;
|
|
139
|
+
let existingSettings: Record<string, any> = {};
|
|
140
|
+
|
|
141
|
+
if (fs.existsSync(filePath)) {
|
|
142
|
+
backupPath = createTimestampBackup(filePath);
|
|
143
|
+
try {
|
|
144
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
145
|
+
existingSettings = parseJsonWithComments(content);
|
|
146
|
+
} catch {
|
|
147
|
+
existingSettings = {};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const languageModels = existingSettings.language_models || {};
|
|
152
|
+
const openaiCompatible = languageModels.openai_compatible || {};
|
|
153
|
+
|
|
154
|
+
openaiCompatible.QwenProxy = {
|
|
155
|
+
api_url: baseUrl,
|
|
156
|
+
available_models: buildZedAvailableModels(model),
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const updatedSettings: Record<string, any> = {
|
|
160
|
+
...existingSettings,
|
|
161
|
+
language_models: {
|
|
162
|
+
...languageModels,
|
|
163
|
+
openai_compatible: openaiCompatible,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
if (setActive) {
|
|
168
|
+
const existingAgent = existingSettings.agent || {};
|
|
169
|
+
updatedSettings.agent = {
|
|
170
|
+
...existingAgent,
|
|
171
|
+
default_model: {
|
|
172
|
+
provider: "QwenProxy",
|
|
173
|
+
model,
|
|
174
|
+
enable_thinking: true,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
fs.writeFileSync(filePath, JSON.stringify(updatedSettings, null, 2) + "\n", "utf-8");
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
client: "zed",
|
|
183
|
+
filePath,
|
|
184
|
+
backupPath,
|
|
185
|
+
success: true,
|
|
186
|
+
action: backupPath ? "updated" : "created",
|
|
187
|
+
message: `Configured Zed Editor with QwenProxy (${baseUrl}) and model ${model}`,
|
|
188
|
+
};
|
|
189
|
+
} catch (err: any) {
|
|
190
|
+
return {
|
|
191
|
+
client: "zed",
|
|
192
|
+
filePath,
|
|
193
|
+
success: false,
|
|
194
|
+
action: "failed",
|
|
195
|
+
error: err?.message || String(err),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function restoreZed(filePath: string, backupPath?: string): ClientSyncResult {
|
|
201
|
+
const restored = restoreFromBackup(filePath, backupPath);
|
|
202
|
+
return {
|
|
203
|
+
client: "zed",
|
|
204
|
+
filePath,
|
|
205
|
+
backupPath,
|
|
206
|
+
success: restored,
|
|
207
|
+
action: restored ? "restored" : "failed",
|
|
208
|
+
message: restored ? "Restored Zed settings from backup" : "Backup file not found",
|
|
209
|
+
};
|
|
210
|
+
}
|
package/src/sync-clients.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getDefaultPaths,
|
|
7
7
|
inspectClientSyncStatus,
|
|
8
8
|
} from "./sync/index.ts";
|
|
9
|
-
import
|
|
9
|
+
import type { SyncClientName } from "./sync/types.ts";
|
|
10
10
|
|
|
11
11
|
function parseArgs() {
|
|
12
12
|
const args = process.argv.slice(2);
|
|
@@ -18,7 +18,7 @@ function parseArgs() {
|
|
|
18
18
|
port?: number;
|
|
19
19
|
host?: string;
|
|
20
20
|
setActive: boolean;
|
|
21
|
-
targets:
|
|
21
|
+
targets: SyncClientName[];
|
|
22
22
|
} = {
|
|
23
23
|
restore: false,
|
|
24
24
|
list: false,
|
|
@@ -61,20 +61,27 @@ Uso:
|
|
|
61
61
|
npm run sync [clientes...] [opções]
|
|
62
62
|
|
|
63
63
|
Exemplos:
|
|
64
|
-
npm run sync # Sincroniza todos os clientes detectados
|
|
65
|
-
npm run sync
|
|
66
|
-
npm run sync codex # Sincroniza apenas o Codex CLI
|
|
64
|
+
npm run sync # Sincroniza todos os 10 clientes detectados
|
|
65
|
+
npm run sync hermes # Sincroniza apenas o Hermes Agent
|
|
67
66
|
npm run sync opencode # Sincroniza apenas o OpenCode
|
|
67
|
+
npm run sync claude # Sincroniza apenas o Claude Code
|
|
68
|
+
npm run sync openclaw # Sincroniza apenas o OpenClaw
|
|
69
|
+
npm run sync kilo # Sincroniza apenas o Kilo Code
|
|
70
|
+
npm run sync cline # Sincroniza Cline & Zoo Code
|
|
68
71
|
npm run sync omp # Sincroniza apenas o OMP (Oh My Pi)
|
|
69
|
-
npm run sync
|
|
70
|
-
npm run sync
|
|
72
|
+
npm run sync codex # Sincroniza apenas o Codex CLI
|
|
73
|
+
npm run sync zed # Sincroniza apenas o Zed Editor
|
|
74
|
+
npm run sync aider # Sincroniza apenas o Aider
|
|
75
|
+
npm run sync claude codex # Sincroniza múltiplos clientes específicos
|
|
76
|
+
npm run sync -- --list # Lista status de detecção de todos os 10 clientes
|
|
71
77
|
npm run sync -- --restore # Restaura as configurações originais (rollback)
|
|
78
|
+
|
|
72
79
|
Opções:
|
|
73
|
-
--client <nome> Nome do cliente (claude, codex,
|
|
80
|
+
--client <nome> Nome do cliente (hermes, opencode, claude, openclaw, kilo, cline, omp, codex, zed, aider)
|
|
74
81
|
--api-key <chave> Sobrescrever chave de API (padrão: lê do .env ou usa sk-qwenproxy-local)
|
|
75
82
|
--port <porta> Sobrescrever porta do servidor (padrão: lê do .env ou usa 7936)
|
|
76
83
|
--host <host> Sobrescrever host do servidor (padrão: 127.0.0.1)
|
|
77
|
-
--no-active Não definir o modelo ativo
|
|
84
|
+
--no-active Não definir o modelo ativo como padrão (apenas adiciona o provider)
|
|
78
85
|
--restore Desfaz alterações restaurando backups
|
|
79
86
|
--list Mostra status de detecção dos arquivos de configuração
|
|
80
87
|
`);
|
|
@@ -84,7 +91,7 @@ async function main() {
|
|
|
84
91
|
const options = parseArgs();
|
|
85
92
|
|
|
86
93
|
console.log("==================================================");
|
|
87
|
-
console.log(" 🚀 QwenProxy - Client Configuration Sync");
|
|
94
|
+
console.log(" 🚀 QwenProxy - Top 10 Client Configuration Sync");
|
|
88
95
|
console.log("==================================================");
|
|
89
96
|
|
|
90
97
|
if (options.help) {
|
|
@@ -93,13 +100,19 @@ async function main() {
|
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
if (options.list) {
|
|
96
|
-
console.log("\n📁 Status de detecção dos clientes no seu computador:\n");
|
|
103
|
+
console.log("\n📁 Status de detecção dos 10 clientes no seu computador:\n");
|
|
97
104
|
const defaultPaths = getDefaultPaths();
|
|
98
|
-
const clients = [
|
|
99
|
-
{ id: "
|
|
100
|
-
{ id: "
|
|
101
|
-
{ id: "
|
|
102
|
-
{ id: "
|
|
105
|
+
const clients: { id: SyncClientName; name: string; path: string }[] = [
|
|
106
|
+
{ id: "hermes", name: "1. Hermes Agent", path: defaultPaths.hermes },
|
|
107
|
+
{ id: "opencode", name: "2. OpenCode", path: defaultPaths.openCode },
|
|
108
|
+
{ id: "claude-code", name: "3. Claude Code", path: defaultPaths.claudeCode },
|
|
109
|
+
{ id: "openclaw", name: "4. OpenClaw", path: defaultPaths.openClaw },
|
|
110
|
+
{ id: "kilo", name: "5. Kilo Code", path: defaultPaths.kilo },
|
|
111
|
+
{ id: "cline", name: "6. Cline & Zoo", path: defaultPaths.cline },
|
|
112
|
+
{ id: "omp", name: "7. OMP (Oh My Pi)", path: defaultPaths.omp },
|
|
113
|
+
{ id: "codex", name: "8. Codex CLI", path: defaultPaths.codex },
|
|
114
|
+
{ id: "zed", name: "9. Zed Editor", path: defaultPaths.zed },
|
|
115
|
+
{ id: "aider", name: "10. Aider", path: defaultPaths.aider },
|
|
103
116
|
];
|
|
104
117
|
|
|
105
118
|
for (const c of clients) {
|
|
@@ -116,12 +129,13 @@ async function main() {
|
|
|
116
129
|
icon = "⚪";
|
|
117
130
|
badge = "[Não instalado]";
|
|
118
131
|
}
|
|
119
|
-
console.log(` ${icon} ${c.name.padEnd(
|
|
132
|
+
console.log(` ${icon} ${c.name.padEnd(20)} ${badge}`);
|
|
120
133
|
console.log(` ${c.path}`);
|
|
121
134
|
}
|
|
122
135
|
console.log("\nPara sincronizar um ou todos, execute:");
|
|
123
136
|
console.log(" npm run sync");
|
|
124
|
-
console.log(" npm run sync
|
|
137
|
+
console.log(" npm run sync hermes");
|
|
138
|
+
console.log(" npm run sync claude cline zed\n");
|
|
125
139
|
return;
|
|
126
140
|
}
|
|
127
141
|
|