autowonder 0.2.85 → 0.2.87
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
CHANGED
|
@@ -5,17 +5,19 @@ AutoWonder 本地 agent runtime。安装后启动 daemon,持续轮询本地 as
|
|
|
5
5
|
## 连接 AutoWonder 服务
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
# Qoder CLI
|
|
9
|
-
npx -y autowonder@
|
|
8
|
+
# Qoder CLI(模型使用 provider model ID;Context Window 使用固定档位)
|
|
9
|
+
npx -y autowonder@latest connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider qoder --model qmodel_latest --reasoning-effort medium --context-window 260000
|
|
10
10
|
|
|
11
11
|
# Claude Code
|
|
12
|
-
npx -y autowonder@0.2.
|
|
12
|
+
npx -y autowonder@0.2.87 connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider claude
|
|
13
13
|
|
|
14
14
|
# Codex CLI
|
|
15
|
-
npx -y autowonder@0.2.
|
|
15
|
+
npx -y autowonder@0.2.87 connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider codex --model gpt-5.5 --reasoning-effort medium
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
`connect` 会安装当前 npm 包内置的 daemon,并使用页面生成的 WebSocket endpoint、Token 和执行器 ID
|
|
18
|
+
`connect` 会安装当前 npm 包内置的 daemon,并使用页面生成的 WebSocket endpoint、Token 和执行器 ID 建立连接。选择 Qoder 时需要 Node.js 20+;runtime 会在缺少 `qodercli` 时自动通过 npm 安装,并在尚未登录时打开 Qoder 浏览器登录。Claude Code 和 Codex CLI 仍需提前安装并登录。runtime 会继承当前用户的 HOME、环境变量和 CLI 登录状态。
|
|
19
|
+
|
|
20
|
+
Qoder 的 Context Window 只能使用 `1000000`、`400000` 或 `260000`,Reasoning Effort 只能使用 `none`、`low`、`medium`、`high`、`xhigh` 或 `max`。建议直接复制 AutoWonder 执行器页面生成的命令,避免把模型展示名称误当成 provider model ID。
|
|
19
21
|
|
|
20
22
|
## 自动更新
|
|
21
23
|
|
|
@@ -55,14 +57,14 @@ mv "$queue/.assignment.tmp" "$queue/assignment.json"
|
|
|
55
57
|
也可以直接提交到本地 API:
|
|
56
58
|
|
|
57
59
|
```bash
|
|
58
|
-
npx -y autowonder@0.2.
|
|
60
|
+
npx -y autowonder@0.2.87 dispatch ./assignment.json
|
|
59
61
|
```
|
|
60
62
|
|
|
61
63
|
## 管理 daemon
|
|
62
64
|
|
|
63
65
|
```bash
|
|
64
|
-
npx -y autowonder@0.2.
|
|
65
|
-
npx -y autowonder@0.2.
|
|
66
|
+
npx -y autowonder@0.2.87 status
|
|
67
|
+
npx -y autowonder@0.2.87 stop
|
|
66
68
|
```
|
|
67
69
|
|
|
68
70
|
默认 API 是 `http://127.0.0.1:34989`,日志位于 `~/.autowonder/daemon.log`。npm 包不包含任何 agent、MCP 或服务端凭证。
|
package/bin/cli.js
CHANGED
|
@@ -17,6 +17,7 @@ const CONFIG_PATH = path.join(AUTOWONDER_HOME, "config.json");
|
|
|
17
17
|
const PID_PATH = path.join(AUTOWONDER_HOME, "daemon.pid");
|
|
18
18
|
const STATE_PATH = path.join(AUTOWONDER_HOME, "daemon-state.json");
|
|
19
19
|
const LOG_PATH = path.join(AUTOWONDER_HOME, "daemon.log");
|
|
20
|
+
const MANAGED_QODER_DIR = path.join(AUTOWONDER_HOME, "qoder-cli");
|
|
20
21
|
|
|
21
22
|
const BINARY_BASE_URL = process.env.AUTOWONDER_BINARY_URL || "";
|
|
22
23
|
const SOURCE_REPO = process.env.AUTOWONDER_SOURCE_REPO || "";
|
|
@@ -40,14 +41,126 @@ function error(msg) {
|
|
|
40
41
|
|
|
41
42
|
function detectProvider() {
|
|
42
43
|
const providers = [];
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
try { execFileSync("which", ["qoder"], { stdio: "ignore" }); providers.push("qoder"); } catch {}
|
|
47
|
-
}
|
|
44
|
+
if (findExecutable("claude")) providers.push("claude");
|
|
45
|
+
if (findExecutable("codex")) providers.push("codex");
|
|
46
|
+
if (findExecutable("qodercli")) providers.push("qoder");
|
|
48
47
|
return providers;
|
|
49
48
|
}
|
|
50
49
|
|
|
50
|
+
function findExecutable(name) {
|
|
51
|
+
if (name === "qodercli" && process.env.AUTOWONDER_QODER_CLI) {
|
|
52
|
+
const configured = resolveUserPath(process.env.AUTOWONDER_QODER_CLI);
|
|
53
|
+
try { fs.accessSync(configured, fs.constants.X_OK); return configured; } catch {}
|
|
54
|
+
}
|
|
55
|
+
const finder = process.platform === "win32" ? "where" : "which";
|
|
56
|
+
const found = spawnSync(finder, [name], { encoding: "utf8", timeout: 3000 });
|
|
57
|
+
if (found.status === 0) {
|
|
58
|
+
const first = (found.stdout || "").split(/\r?\n/).map((value) => value.trim()).find(Boolean);
|
|
59
|
+
if (first) return first;
|
|
60
|
+
}
|
|
61
|
+
if (name === "qodercli" && process.platform !== "win32") {
|
|
62
|
+
for (const candidate of [
|
|
63
|
+
path.join(MANAGED_QODER_DIR, "node_modules", ".bin", "qodercli"),
|
|
64
|
+
path.join(os.homedir(), ".local", "bin", "qodercli"),
|
|
65
|
+
path.join(os.homedir(), ".qoder", "bin", "qodercli", "qodercli"),
|
|
66
|
+
]) {
|
|
67
|
+
try { fs.accessSync(candidate, fs.constants.X_OK); return candidate; } catch {}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (name === "qodercli" && process.platform === "win32") {
|
|
71
|
+
const candidate = path.join(MANAGED_QODER_DIR, "node_modules", ".bin", "qodercli.cmd");
|
|
72
|
+
try { fs.accessSync(candidate, fs.constants.F_OK); return candidate; } catch {}
|
|
73
|
+
}
|
|
74
|
+
return "";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function qoderAuthenticated(executable) {
|
|
78
|
+
const result = spawnSync(executable, ["--list-models"], {
|
|
79
|
+
encoding: "utf8",
|
|
80
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
81
|
+
timeout: 20000,
|
|
82
|
+
});
|
|
83
|
+
return result.status === 0 && Boolean((result.stdout || "").trim());
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function installQoderCLI() {
|
|
87
|
+
log("Qoder CLI is not installed. Installing @qoder-ai/qodercli...");
|
|
88
|
+
const result = spawnSync(process.platform === "win32" ? "npm.cmd" : "npm", [
|
|
89
|
+
"install", "--prefix", MANAGED_QODER_DIR, "@qoder-ai/qodercli@latest", "--no-audit", "--no-fund",
|
|
90
|
+
], { stdio: "inherit" });
|
|
91
|
+
if (result.status !== 0) {
|
|
92
|
+
error(`Failed to install Qoder CLI into ${MANAGED_QODER_DIR}.`);
|
|
93
|
+
return "";
|
|
94
|
+
}
|
|
95
|
+
const executable = findExecutable("qodercli");
|
|
96
|
+
if (!executable) error("Qoder CLI was installed but qodercli is not available on PATH.");
|
|
97
|
+
return executable;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function qoderNodeVersion() {
|
|
101
|
+
if (process.env.NODE_ENV === "test" && process.env.AUTOWONDER_TEST_NODE_VERSION) {
|
|
102
|
+
return process.env.AUTOWONDER_TEST_NODE_VERSION;
|
|
103
|
+
}
|
|
104
|
+
return process.versions.node;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function ensureQoderReady() {
|
|
108
|
+
if (process.env.AUTOWONDER_SKIP_QODER_BOOTSTRAP === "1") return true;
|
|
109
|
+
const nodeVersion = qoderNodeVersion();
|
|
110
|
+
const nodeMajor = Number.parseInt(nodeVersion.split(".")[0], 10);
|
|
111
|
+
if (!Number.isInteger(nodeMajor) || nodeMajor < 20) {
|
|
112
|
+
error(`Qoder CLI requires Node.js 20 or newer; current version is ${nodeVersion}. Upgrade Node.js and retry.`);
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
let executable = findExecutable("qodercli");
|
|
116
|
+
if (!executable) executable = installQoderCLI();
|
|
117
|
+
if (!executable) return false;
|
|
118
|
+
if (!qoderAuthenticated(executable)) {
|
|
119
|
+
log("Qoder login is required. Opening browser login...");
|
|
120
|
+
const login = spawnSync(executable, ["login"], { stdio: "inherit" });
|
|
121
|
+
if (login.status !== 0 || !qoderAuthenticated(executable)) {
|
|
122
|
+
error("Qoder login did not complete. Run `qodercli login` and retry.");
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
process.env.AUTOWONDER_QODER_CLI = executable;
|
|
127
|
+
const executableDir = path.dirname(executable);
|
|
128
|
+
const pathEntries = (process.env.PATH || "").split(path.delimiter);
|
|
129
|
+
if (!pathEntries.includes(executableDir)) {
|
|
130
|
+
process.env.PATH = `${executableDir}${path.delimiter}${process.env.PATH || ""}`;
|
|
131
|
+
}
|
|
132
|
+
log("Qoder CLI is installed and authenticated.");
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const QODER_MODELS = new Set([
|
|
137
|
+
"auto", "ultimate", "performance", "efficient", "lite", "cmodel",
|
|
138
|
+
"qmodel_preview", "qmodel_latest", "qmodel", "kmodel_latest", "kmodel",
|
|
139
|
+
"gm51model", "dmodel", "dfmodel", "mmodel", "qwen3.8-max-preview",
|
|
140
|
+
]);
|
|
141
|
+
const QODER_CONTEXT_WINDOWS = new Set(["1000000", "400000", "260000"]);
|
|
142
|
+
const QODER_REASONING_EFFORTS = new Set(["none", "low", "medium", "high", "xhigh", "max"]);
|
|
143
|
+
|
|
144
|
+
function validateQoderOptions(flags) {
|
|
145
|
+
if (flags.model && !QODER_MODELS.has(flags.model)) {
|
|
146
|
+
error(`Unsupported Qoder model ID: ${flags.model}. Use a provider model ID shown in the executor form.`);
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
if (flags["reasoning-effort"] && !QODER_REASONING_EFFORTS.has(flags["reasoning-effort"])) {
|
|
150
|
+
error("--reasoning-effort must be one of: none, low, medium, high, xhigh, max");
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
if (flags["context-window"] && !/^[1-9][0-9]*$/.test(flags["context-window"])) {
|
|
154
|
+
error("--context-window must be a positive integer");
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
if (flags["context-window"] && !QODER_CONTEXT_WINDOWS.has(flags["context-window"])) {
|
|
158
|
+
error("--context-window must be one of: 1000000, 400000, 260000");
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
51
164
|
function daemonRunning() {
|
|
52
165
|
const pid = readPid();
|
|
53
166
|
return Boolean(pid && processRunning(pid) && ownsDaemonProcess(pid));
|
|
@@ -289,16 +402,20 @@ async function cmdConnect(args) {
|
|
|
289
402
|
process.exit(1);
|
|
290
403
|
}
|
|
291
404
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (!installed) process.exit(1);
|
|
405
|
+
const requestedProvider = flags.provider;
|
|
406
|
+
if (requestedProvider === "qoder" && !validateQoderOptions(flags)) process.exit(1);
|
|
295
407
|
|
|
296
408
|
const providers = detectProvider();
|
|
297
|
-
const provider =
|
|
409
|
+
const provider = requestedProvider || providers[0];
|
|
298
410
|
if (!provider) {
|
|
299
411
|
error(`No agent CLI detected. Install one of: claude, codex, qodercli`);
|
|
300
412
|
process.exit(1);
|
|
301
413
|
}
|
|
414
|
+
if (provider === "qoder" && !ensureQoderReady()) process.exit(1);
|
|
415
|
+
|
|
416
|
+
// A version-pinned npx command must always run the binary bundled with that package.
|
|
417
|
+
const installed = await installBinary({ force: true });
|
|
418
|
+
if (!installed) process.exit(1);
|
|
302
419
|
|
|
303
420
|
const hasProviderSettings = Boolean(flags.model || flags["reasoning-effort"]);
|
|
304
421
|
if (hasProviderSettings && provider !== "codex" && provider !== "qoder") {
|
|
@@ -309,10 +426,7 @@ async function cmdConnect(args) {
|
|
|
309
426
|
error("--context-window is supported only for qoder");
|
|
310
427
|
process.exit(1);
|
|
311
428
|
}
|
|
312
|
-
if (
|
|
313
|
-
error("--context-window must be a positive integer");
|
|
314
|
-
process.exit(1);
|
|
315
|
-
}
|
|
429
|
+
if (provider === "qoder" && !validateQoderOptions(flags)) process.exit(1);
|
|
316
430
|
let claudeSettingsPath = "";
|
|
317
431
|
if (flags.settings) {
|
|
318
432
|
if (provider !== "claude") {
|
|
@@ -577,7 +691,7 @@ function cmdHelp() {
|
|
|
577
691
|
--executor-id <id> Executor ID
|
|
578
692
|
--model <model> Default model for Codex or Qoder
|
|
579
693
|
--reasoning-effort <level> Default reasoning effort for Codex or Qoder
|
|
580
|
-
--context-window <n> Qoder context window
|
|
694
|
+
--context-window <n> Qoder context window: 1000000, 400000, or 260000
|
|
581
695
|
--settings <file> Claude settings JSON file
|
|
582
696
|
--memory-mode <mode> Memory: platform, provider-local, or none (default: platform)
|
|
583
697
|
--name <name> Runtime name (default: provider + executor ID)
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|