@wavespeed/cli 0.4.17 → 0.4.18
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 +1 -1
- package/dist/commands/setup.js +20 -3
- package/dist/lib/setup-agents.js +60 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -141,7 +141,7 @@ wavespeed logout Clear stored API key
|
|
|
141
141
|
wavespeed status Show masked key, base URL, useful links
|
|
142
142
|
wavespeed config [--default-model …] View / update CLI defaults
|
|
143
143
|
wavespeed upgrade [--check] [--json] Upgrade to the latest version (--check only reports)
|
|
144
|
-
wavespeed setup [agent] Point claude, codex, opencode, openclaw, hermes or
|
|
144
|
+
wavespeed setup [agent] Point claude, codex, opencode, openclaw, hermes, cline, qwen or miniagent at the WaveSpeed LLM gateway (--dry-run, --undo, --model)
|
|
145
145
|
|
|
146
146
|
# generation
|
|
147
147
|
wavespeed run [model|alias] -p "…" Run any model or alias (uses defaultModel if omitted)
|
package/dist/commands/setup.js
CHANGED
|
@@ -8,7 +8,7 @@ import JSON5 from 'json5';
|
|
|
8
8
|
import { getApiKey, userConfig } from '../lib/config.js';
|
|
9
9
|
import { clientAttributionHeaders } from '../lib/client-headers.js';
|
|
10
10
|
import { emitJson, emitJsonError, info, setJsonMode } from '../lib/log.js';
|
|
11
|
-
import { DEFAULT_MODEL, KEY_ENV, LLM_BASE_URL, applyCodexToml, applyHermesYaml, applyJson, claudeEdits, openclawEdits, opencodeEdits, revertCodexToml, revertHermesYaml, revertJson, validateModel, } from '../lib/setup-agents.js';
|
|
11
|
+
import { DEFAULT_MODEL, KEY_ENV, LLM_BASE_URL, applyCodexToml, applyHermesYaml, applyJson, applyYamlScalars, claudeEdits, miniAgentValues, openclawEdits, opencodeEdits, qwenEdits, revertCodexToml, revertHermesYaml, revertJson, revertYamlScalars, validateModel, } from '../lib/setup-agents.js';
|
|
12
12
|
const home = os.homedir();
|
|
13
13
|
const AGENTS = [
|
|
14
14
|
{ id: 'claude', name: 'Claude Code', file: path.join(home, '.claude', 'settings.json'), command: 'claude', kind: 'json', keyInFile: true },
|
|
@@ -16,6 +16,8 @@ const AGENTS = [
|
|
|
16
16
|
{ id: 'opencode', name: 'OpenCode', file: path.join(home, '.config', 'opencode', 'opencode.json'), command: 'opencode', kind: 'json', keyInFile: false },
|
|
17
17
|
{ id: 'openclaw', name: 'OpenClaw', file: path.join(home, '.openclaw', 'openclaw.json'), command: 'openclaw', kind: 'json5', keyInFile: false },
|
|
18
18
|
{ id: 'hermes', name: 'Hermes', file: path.join(home, '.hermes', 'config.yaml'), command: 'hermes', kind: 'yaml', keyInFile: false },
|
|
19
|
+
{ id: 'qwen', name: 'Qwen Code', file: path.join(home, '.qwen', 'settings.json'), command: 'qwen', kind: 'json', keyInFile: false },
|
|
20
|
+
{ id: 'miniagent', name: 'Mini-Agent', file: path.join(home, '.mini-agent', 'config', 'config.yaml'), command: 'mini-agent', kind: 'yamlscalars', keyInFile: true },
|
|
19
21
|
// Cline's CLI keeps provider settings (including the key) in this file; we write it only through `cline auth`.
|
|
20
22
|
{ id: 'cline', name: 'Cline', file: path.join(home, '.cline', 'data', 'settings', 'providers.json'), command: 'cline', kind: 'cline', keyInFile: true },
|
|
21
23
|
];
|
|
@@ -82,7 +84,7 @@ function envHint() {
|
|
|
82
84
|
export function registerSetup(program) {
|
|
83
85
|
program
|
|
84
86
|
.command('setup [agent]')
|
|
85
|
-
.description('Point a coding agent (claude, codex, opencode, openclaw, hermes, cline) at the WaveSpeed LLM gateway')
|
|
87
|
+
.description('Point a coding agent (claude, codex, opencode, openclaw, hermes, cline, qwen, miniagent) at the WaveSpeed LLM gateway')
|
|
86
88
|
.option('--model <id>', `Model to use (default: ${DEFAULT_MODEL})`)
|
|
87
89
|
.option('--dry-run', 'Show what would change without writing anything')
|
|
88
90
|
.option('--undo', "Restore the agent's config to what it was before setup")
|
|
@@ -142,6 +144,16 @@ export function registerSetup(program) {
|
|
|
142
144
|
forget();
|
|
143
145
|
}
|
|
144
146
|
}
|
|
147
|
+
else if (agent.kind === 'yamlscalars') {
|
|
148
|
+
const after = revertYamlScalars(fs.readFileSync(state.file, 'utf8'), state.previous);
|
|
149
|
+
if (!opts.dryRun) {
|
|
150
|
+
if (after.trim() === '')
|
|
151
|
+
fs.rmSync(state.file, { force: true });
|
|
152
|
+
else
|
|
153
|
+
fs.writeFileSync(state.file, after);
|
|
154
|
+
forget();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
145
157
|
else if (agent.kind === 'yaml') {
|
|
146
158
|
const after = revertHermesYaml(fs.readFileSync(state.file, 'utf8'), state.previous);
|
|
147
159
|
if (!opts.dryRun) {
|
|
@@ -188,6 +200,11 @@ export function registerSetup(program) {
|
|
|
188
200
|
next = r.text;
|
|
189
201
|
previous = r.previous;
|
|
190
202
|
}
|
|
203
|
+
else if (agent.kind === 'yamlscalars') {
|
|
204
|
+
const r = applyYamlScalars(fs.existsSync(agent.file) ? fs.readFileSync(agent.file, 'utf8') : '', miniAgentValues(model, apiKey));
|
|
205
|
+
next = r.text;
|
|
206
|
+
previous = r.previous;
|
|
207
|
+
}
|
|
191
208
|
else if (agent.kind === 'cline') {
|
|
192
209
|
previous = { existed: fs.existsSync(agent.file) };
|
|
193
210
|
if (!onPath('cline'))
|
|
@@ -195,7 +212,7 @@ export function registerSetup(program) {
|
|
|
195
212
|
}
|
|
196
213
|
else {
|
|
197
214
|
const base = readJson(agent.file, agent.kind === 'json5');
|
|
198
|
-
const edits = agent.id === 'claude' ? claudeEdits(model, apiKey) : agent.id === 'openclaw' ? openclawEdits(model, base) : opencodeEdits(model);
|
|
215
|
+
const edits = agent.id === 'claude' ? claudeEdits(model, apiKey) : agent.id === 'openclaw' ? openclawEdits(model, base) : agent.id === 'qwen' ? qwenEdits(model) : opencodeEdits(model);
|
|
199
216
|
const r = applyJson(base, edits);
|
|
200
217
|
previous = r.previous;
|
|
201
218
|
next = JSON.stringify(r.doc, null, 2) + '\n';
|
package/dist/lib/setup-agents.js
CHANGED
|
@@ -109,6 +109,66 @@ export function openclawEdits(model, doc) {
|
|
|
109
109
|
edits.push({ path: ['agents', 'defaults', 'models', `wavespeed/${m}`], value: {} });
|
|
110
110
|
return edits;
|
|
111
111
|
}
|
|
112
|
+
export function qwenEdits(model) {
|
|
113
|
+
const m = validateModel(model);
|
|
114
|
+
return [
|
|
115
|
+
{ path: ['modelProviders', 'wavespeed'], value: [{ id: m, name: m, envKey: KEY_ENV, baseUrl: LLM_BASE_URL }] },
|
|
116
|
+
{ path: ['providerProtocol', 'wavespeed'], value: 'openai' },
|
|
117
|
+
{ path: ['security', 'auth', 'selectedType'], value: 'openai' },
|
|
118
|
+
{ path: ['model', 'name'], value: m },
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
// ---------- Mini-Agent (flat YAML scalars; the key lives in the file) ----------
|
|
122
|
+
export function miniAgentValues(model, apiKey) {
|
|
123
|
+
return { api_key: apiKey, api_base: LLM_BASE_URL, model: validateModel(model), provider: 'openai' };
|
|
124
|
+
}
|
|
125
|
+
/** Set top-level `key: "value"` pairs in place. Returns the raw text each key held before (null = absent). */
|
|
126
|
+
export function applyYamlScalars(input, values) {
|
|
127
|
+
let text = input;
|
|
128
|
+
if (text !== '' && !text.endsWith('\n'))
|
|
129
|
+
text += '\n';
|
|
130
|
+
const doc = parseDocument(text);
|
|
131
|
+
if (doc.errors.length)
|
|
132
|
+
throw new Error(`config.yaml is not valid YAML: ${doc.errors[0].message}`);
|
|
133
|
+
const root = doc.contents;
|
|
134
|
+
// null (not undefined) marks "absent": the state is stored as JSON, which drops undefined values.
|
|
135
|
+
const previous = {};
|
|
136
|
+
const edits = [];
|
|
137
|
+
let tail = '';
|
|
138
|
+
for (const [key, value] of Object.entries(values)) {
|
|
139
|
+
const node = root?.get?.(key, true);
|
|
140
|
+
const quoted = JSON.stringify(value);
|
|
141
|
+
if (node?.range) {
|
|
142
|
+
previous[key] = text.slice(node.range[0], node.range[1]);
|
|
143
|
+
edits.push({ start: node.range[0], end: node.range[1], text: quoted });
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
previous[key] = null;
|
|
147
|
+
tail += `${key}: ${quoted}\n`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return { text: [...edits].sort((a, b) => b.start - a.start).reduce((t, e) => t.slice(0, e.start) + e.text + t.slice(e.end), text) + tail, previous };
|
|
151
|
+
}
|
|
152
|
+
export function revertYamlScalars(input, previous) {
|
|
153
|
+
let text = input;
|
|
154
|
+
const doc = parseDocument(text);
|
|
155
|
+
const root = doc.contents;
|
|
156
|
+
const edits = [];
|
|
157
|
+
for (const [key, raw] of Object.entries(previous)) {
|
|
158
|
+
const node = root?.get?.(key, true);
|
|
159
|
+
if (!node?.range)
|
|
160
|
+
continue;
|
|
161
|
+
if (raw !== null) {
|
|
162
|
+
edits.push({ start: node.range[0], end: node.range[1], text: raw });
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
const pair = root.items.find((p) => p.key?.value === key);
|
|
166
|
+
const ks = pair.key.range[0];
|
|
167
|
+
edits.push({ start: lineStart(text, ks), end: lineEnd(text, node.range[1]), text: '' });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return [...edits].sort((a, b) => b.start - a.start).reduce((t, e) => t.slice(0, e.start) + e.text + t.slice(e.end), text);
|
|
171
|
+
}
|
|
112
172
|
const lineStart = (t, off) => t.lastIndexOf('\n', off - 1) + 1;
|
|
113
173
|
const lineEnd = (t, off) => {
|
|
114
174
|
const i = t.indexOf('\n', off);
|