autowonder 0.2.140 → 0.2.142

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
@@ -6,16 +6,16 @@ AutoWonder 本地 agent runtime。安装后启动 daemon,持续轮询本地 as
6
6
 
7
7
  ```bash
8
8
  # Qoder CLI(模型使用 provider model ID;Context Window 使用固定档位)
9
- npx -y autowonder@0.2.140 connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider qoder --model qmodel_latest --reasoning-effort medium --context-window 260000
9
+ npx -y autowonder@0.2.142 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
  # Qoder CLI CN
12
- npx -y autowonder@0.2.140 connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider qodercn
12
+ npx -y autowonder@0.2.142 connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider qodercn
13
13
 
14
14
  # Claude Code
15
- npx -y autowonder@0.2.140 connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider claude
15
+ npx -y autowonder@0.2.142 connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider claude
16
16
 
17
17
  # Codex CLI
18
- npx -y autowonder@0.2.140 connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider codex --model gpt-5.5 --reasoning-effort medium
18
+ npx -y autowonder@0.2.142 connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider codex --model gpt-5.5 --reasoning-effort medium
19
19
  ```
20
20
 
21
21
  `connect` 会安装当前 npm 包内置的 daemon,并使用页面生成的 WebSocket endpoint、Token 和执行器 ID 建立连接。选择 Qoder 时需要 Node.js 20+;runtime 会在缺少 `qodercli` 时自动通过 npm 安装,并在尚未登录时打开 Qoder 浏览器登录。Claude Code 和 Codex CLI 仍需提前安装并登录。runtime 会继承当前用户的 HOME、环境变量和 CLI 登录状态。
@@ -26,6 +26,8 @@ Qoder 的 Context Window 只能使用 `1000000`、`400000` 或 `260000`,Reason
26
26
 
27
27
  给 `connect` 追加 `--token-aware-enable` 可开启 qoder / qodercn 的 token 用量采集:CLI 会以 sidecar 方式启动本地 HTTPS 转发代理(`bin/token-proxy.js`),从 Qoder API 的 SSE 响应流中提取 usage 数据并按 dispatch ID 归属上报。该功能旁路设计、不阻塞任务执行,代理启动失败时仅告警并继续。代理端口可用 `TOKEN_PROXY_PORT` 环境变量调整(默认 19876);CA 证书位于 `~/.autowonder/token-tap/ca-cert.pem`。daemon 退出时 sidecar 一并停止。
28
28
 
29
+ `connect` 支持 `--workspace-root <path>` 指定 dispatch 仓库与任务工作区所在目录(默认 `~/autowonder_workspaces`)。该参数会转发给 daemon,等价于设置 `AUTOWONDER_WORKSPACE_ROOT` 环境变量,适合把工作区放在非默认路径的执行机上(如 Windows 的 `D:\autowonder`)。
30
+
29
31
  ## 自动更新
30
32
 
31
33
  安装首个支持自动更新的正式版本后,daemon 会直接查询 npm 的 `autowonder/latest`。首次检查会随机分散在启动后的 30~90 秒,之后约每 5 分钟检查一次并加入随机抖动;npm 临时错误会指数退避,HTTP 429/503 的 `Retry-After` 会被遵循。发现更高的稳定版本时,它会在后台下载 npm tarball,校验 SHA-512 SRI、包版本和平台二进制;只有在没有运行/恢复任务且结果 outbox 已收到服务端确认时,才会暂停接单、原子切换二进制并自动重启。启动失败会恢复上一个二进制。
@@ -46,7 +48,7 @@ npx -y autowonder@latest connect ...
46
48
 
47
49
  ## 发布构建
48
50
 
49
- `npm run build` 和发布脚本只接受没有已跟踪或未跟踪改动的 Git worktree。脚本会把准确的 release commit 克隆到仓库外的 detached checkout,再从该目录构建四个平台的 daemon。
51
+ `npm run build` 和发布脚本只接受没有已跟踪或未跟踪改动的 Git worktree。脚本会把准确的 release commit 克隆到仓库外的 detached checkout,再从该目录构建六个平台(darwin/linux/windows × amd64/arm64)的 daemon。
50
52
 
51
53
  每个产物都必须在 Go BuildInfo 中报告相同的完整 commit、`vcs.modified=false` 和目标平台;本机产物的 `--self-check` 还必须与 npm 包版本、短 commit 和平台一致。任一检查失败都会在替换 `vendor` 或执行 `npm publish` 前终止。
52
54
 
@@ -64,7 +66,7 @@ mv "$queue/.assignment.tmp" "$queue/assignment.json"
64
66
  也可以直接提交到本地 API:
65
67
 
66
68
  ```bash
67
- npx -y autowonder@0.2.140 dispatch ./assignment.json
69
+ npx -y autowonder@0.2.142 dispatch ./assignment.json
68
70
  ```
69
71
 
70
72
  ## 上传工单附件
@@ -72,16 +74,26 @@ npx -y autowonder@0.2.140 dispatch ./assignment.json
72
74
  把本地需求/设计文档直接上传到工单,避免在会话里传递大文件:
73
75
 
74
76
  ```bash
75
- npx -y autowonder@0.2.140 workitem upload --server-url <autowonder-server-url> --workitem-id <id> --file <filepath-1> --file <filepath-2> --json
77
+ npx -y autowonder@0.2.142 workitem upload --server-url <autowonder-server-url> --workitem-id <id> --file <filepath-1> --file <filepath-2> --json
76
78
  ```
77
79
 
78
80
  上传令牌通过 MCP 工具 `autowonder.workitem_cli_upload_token` 签发,经 `--token` 或 `AUTOWONDER_UPLOAD_TOKEN` 环境变量传入。`--file` 可重复指定多个文件;`--json` 输出机器可读结果。失败时按错误类型返回不同退出码(401→3、403→4、404→5、409→6、413→7、其他 4xx→8、网络/重定向→9)。
79
81
 
82
+ ## 上传定时任务附件
83
+
84
+ 把需求/设计文档上传到 7x24 定时任务,用法与工单附件一致(同一套上传令牌与预检规则):
85
+
86
+ ```bash
87
+ npx -y autowonder@0.2.142 scheduled-task upload --server-url <autowonder-server-url> --scheduled-task-id <id> --file <filepath-1> --file <filepath-2> --json
88
+ ```
89
+
90
+ 上传令牌同样通过 `autowonder.workitem_cli_upload_token` 签发(令牌为用户级,对当前可修改的任意定时任务生效),经 `--token` 或 `AUTOWONDER_UPLOAD_TOKEN` 传入;退出码约定与 `workitem upload` 相同。
91
+
80
92
  ## 管理 daemon
81
93
 
82
94
  ```bash
83
- npx -y autowonder@0.2.140 status
84
- npx -y autowonder@0.2.140 stop
95
+ npx -y autowonder@0.2.142 status
96
+ npx -y autowonder@0.2.142 stop
85
97
  ```
86
98
 
87
99
  默认 API 是 `http://127.0.0.1:34989`,日志位于 `~/.autowonder/daemon.log`。npm 包不包含任何 agent、MCP 或服务端凭证。
@@ -89,7 +101,7 @@ npx -y autowonder@0.2.140 stop
89
101
  ## 调试
90
102
 
91
103
  ```bash
92
- npx -y autowonder@0.2.140 connect ... --debug
104
+ npx -y autowonder@0.2.142 connect ... --debug
93
105
  ```
94
106
 
95
107
  `--debug` 会让 CLI 以 `AUTOWONDER_DEBUG=1` 启动 daemon,把完整的 daemon 与 agent 活动(runtime 事件流、provider 事件解码、重试退避与会话门等待、空闲时的阻塞点)同时输出到控制台和会话调试日志。调试日志不做脱敏,仅用于本机排障;不传 `--debug` 时该环境变量不会注入。
package/bin/cli.js CHANGED
@@ -331,10 +331,10 @@ function buildFromSource() {
331
331
  // ─── Commands ────────────────────────────────────────────────────────
332
332
 
333
333
  async function cmdConnect(args) {
334
- const flags = parseFlags(args, ["ws-url", "token", "executor-id", "provider", "name", "max-tasks", "model", "reasoning-effort", "context-window", "memory-mode", "settings", "token-aware-enable"]);
334
+ const flags = parseFlags(args, ["ws-url", "token", "executor-id", "provider", "name", "max-tasks", "model", "reasoning-effort", "context-window", "memory-mode", "settings", "workspace-root", "token-aware-enable"]);
335
335
 
336
336
  if (!flags["ws-url"] || !flags.token || !flags["executor-id"]) {
337
- error("Usage: autowonder connect --ws-url <url> --token <token> --executor-id <id> [--provider qoder|qodercn]");
337
+ error("Usage: autowonder connect --ws-url <url> --token <token> --executor-id <id> [--provider qoder|qodercn] [--workspace-root <path>]");
338
338
  process.exit(1);
339
339
  }
340
340
 
@@ -408,13 +408,16 @@ async function cmdConnect(args) {
408
408
  log("");
409
409
 
410
410
  // Start daemon in foreground (like harness connect)
411
+ const workspaceRoot = flags["workspace-root"] && flags["workspace-root"] !== "true"
412
+ ? path.resolve(resolveUserPath(flags["workspace-root"]))
413
+ : path.join(os.homedir(), `autowonder_workspaces_${provider}_${executorId}`);
411
414
  const env = {
412
415
  ...process.env,
413
416
  AUTOWONDER_PROVIDER: config.provider,
414
417
  AUTOWONDER_MAX_CONCURRENT_DISPATCHES: String(config.maxTasks),
415
418
  AUTOWONDER_DAEMON_ID: config.name,
416
419
  AUTOWONDER_RUNTIME_ID: `rt_${provider}_${executorId}`,
417
- AUTOWONDER_WORKSPACE_ROOT: path.join(os.homedir(), `autowonder_workspaces_${provider}_${executorId}`),
420
+ AUTOWONDER_WORKSPACE_ROOT: workspaceRoot,
418
421
  AUTOWONDER_LOCAL_API_ADDR: "127.0.0.1:0",
419
422
  AUTOWONDER_SERVER_WS_URL: config.serverUrl,
420
423
  AUTOWONDER_EXECUTOR_TOKEN: config.token,
@@ -745,6 +748,66 @@ async function cmdWorkitemUpload(args) {
745
748
  }
746
749
  }
747
750
 
751
+ async function cmdScheduledTask(args) {
752
+ const sub = args[0];
753
+ if (sub === "upload") {
754
+ return cmdScheduledTaskUpload(args.slice(1));
755
+ }
756
+ error(`Unknown scheduled-task command: ${sub || "(none)"}`);
757
+ cmdHelp();
758
+ process.exit(1);
759
+ }
760
+
761
+ async function cmdScheduledTaskUpload(args) {
762
+ const upload = require("../lib/workitem-upload");
763
+ const json = args.includes("--json");
764
+ try {
765
+ const parsed = upload.parseUploadFlags(args, {
766
+ idFlag: "scheduled-task-id",
767
+ idKey: "scheduledTaskId",
768
+ });
769
+ const serverUrl = upload.validateServerUrl(parsed.serverUrl);
770
+ const scheduledTaskId = upload.validateScheduledTaskId(parsed.scheduledTaskId);
771
+ const token = parsed.token || process.env.AUTOWONDER_UPLOAD_TOKEN;
772
+ if (!token) {
773
+ throw new upload.UploadError(
774
+ "no upload token provided. Invoke the MCP tool autowonder.workitem_cli_upload_token to mint one, " +
775
+ "then pass it via --token or the AUTOWONDER_UPLOAD_TOKEN environment variable.",
776
+ { kind: "token" },
777
+ );
778
+ }
779
+ const files = upload.preflightFiles(parsed.files);
780
+
781
+ const { statusCode, body } = await upload.uploadScheduledTaskDocuments({
782
+ serverUrl, scheduledTaskId, files, token,
783
+ });
784
+
785
+ if (statusCode === 200) {
786
+ let parsedBody = null;
787
+ try { parsedBody = JSON.parse(body); } catch { /* non-JSON success bodies are ignored */ }
788
+ if (json) {
789
+ console.log(JSON.stringify({
790
+ success: true,
791
+ scheduledTaskId: Number(scheduledTaskId),
792
+ uploaded: files.map((f) => f.filename),
793
+ response: parsedBody,
794
+ }));
795
+ } else {
796
+ log(`Uploaded ${files.length} file(s) to scheduled task ${scheduledTaskId}: ${files.map((f) => f.filename).join(", ")}`);
797
+ }
798
+ return;
799
+ }
800
+
801
+ throw new upload.UploadError(
802
+ `server rejected the upload (HTTP ${statusCode})`,
803
+ { kind: "http", statusCode, serverError: upload.parseServerError(body) },
804
+ );
805
+ } catch (err) {
806
+ reportUploadFailure(err, json);
807
+ process.exit(uploadExitCode(err));
808
+ }
809
+ }
810
+
748
811
  async function cmdInstall(args) {
749
812
  const flags = parseFlags(args, ["force", "provider", "max-tasks", "addr"]);
750
813
  const force = flags.force === "true" || args.includes("--force");
@@ -769,6 +832,8 @@ function cmdHelp() {
769
832
  autowonder install [--force] Install/update and start daemon
770
833
  autowonder workitem upload --server-url <url> --workitem-id <id> --file <path> [--file <path>...]
771
834
  Upload local requirement/design files to a workitem
835
+ autowonder scheduled-task upload --server-url <url> --scheduled-task-id <id> --file <path> [--file <path>...]
836
+ Upload local requirement/design files to a scheduled task
772
837
 
773
838
  Options:
774
839
  --provider <name> Agent provider: claude, codex, qoder, qodercn (default: auto-detect; qodercn must be explicit)
@@ -783,17 +848,25 @@ function cmdHelp() {
783
848
  --settings <file> Claude settings JSON file
784
849
  --memory-mode <mode> Memory: platform, provider-local, or none (default: platform)
785
850
  --name <name> Runtime name (default: provider + executor ID)
851
+ --workspace-root <path> Workspace directory for dispatch repos
852
+ (default: ~/autowonder_workspaces_<provider>_<executor-id>;
853
+ also settable via AUTOWONDER_WORKSPACE_ROOT. On Windows use a
854
+ non-C drive path here when the default location is not writable)
786
855
  --debug Stream full daemon and agent activity to console + log file
787
- --server-url <url> AutoWonder server base URL (workitem upload)
856
+ --server-url <url> AutoWonder server base URL (workitem/scheduled-task upload)
788
857
  --workitem-id <id> Target workitem ID (workitem upload)
789
- --file <path> Local file to upload, repeatable (workitem upload)
790
- --json Machine-readable output (workitem upload)
858
+ --scheduled-task-id <id> Target scheduled task ID (scheduled-task upload)
859
+ --file <path> Local file to upload, repeatable (workitem/scheduled-task upload)
860
+ --json Machine-readable output (workitem/scheduled-task upload)
791
861
  -h, --help Show this help
792
862
 
793
863
  Examples:
794
864
  # Quick start — connect to server
795
865
  npx -y autowonder connect --ws-url wss://autowonder.example.com/ws/executor --token xxx --executor-id 10000 --provider qoder
796
866
 
867
+ # Use a custom workspace directory (e.g. a non-C drive on Windows)
868
+ npx -y autowonder connect --ws-url wss://autowonder.example.com/ws/executor --token xxx --executor-id 10000 --provider qoder --workspace-root D:\\autowonder
869
+
797
870
  # Local mode — start daemon, submit tasks manually
798
871
  npx -y autowonder start
799
872
  npx -y autowonder dispatch ./assignment.json
@@ -801,6 +874,9 @@ function cmdHelp() {
801
874
  # Upload requirement/design documents from local files
802
875
  npx -y autowonder@0.2.130 workitem upload --server-url https://private-autowonder.example.com --workitem-id 50063 --file <filepath-1> --file <filepath-2> --file <images-1> --json
803
876
 
877
+ # Upload requirement/design documents to a 7x24 scheduled task
878
+ npx -y autowonder scheduled-task upload --server-url https://auto-wonder.example.com --scheduled-task-id 123 --file <filepath-1> --file <filepath-2> --json
879
+
804
880
  # Check what's happening
805
881
  npx -y autowonder status
806
882
  `);
@@ -839,6 +915,7 @@ async function main() {
839
915
  case "dispatch": return cmdDispatch(commandArgs);
840
916
  case "install": return cmdInstall(commandArgs);
841
917
  case "workitem": return cmdWorkitem(commandArgs);
918
+ case "scheduled-task": return cmdScheduledTask(commandArgs);
842
919
  case "help":
843
920
  case "--help":
844
921
  case "-h": return cmdHelp();
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
 
3
- // Workitem requirement/design document upload: streaming multipart over
4
- // Node >= 16 built-ins only. Never Base64 encodes and never buffers whole
5
- // file bodies; the server is authoritative for validation.
3
+ // Workitem and scheduled-task requirement/design document upload: streaming
4
+ // multipart over Node >= 16 built-ins only. Never Base64 encodes and never
5
+ // buffers whole file bodies; the server is authoritative for validation.
6
6
 
7
7
  const crypto = require("node:crypto");
8
8
  const fs = require("node:fs");
@@ -34,10 +34,12 @@ class UploadError extends Error {
34
34
  }
35
35
  }
36
36
 
37
- function parseUploadFlags(args) {
37
+ function parseUploadFlags(args, flagOptions = {}) {
38
+ const idFlag = flagOptions.idFlag || "workitem-id";
39
+ const idKey = flagOptions.idKey || "workitemId";
38
40
  const FLAG_KEYS = {
39
41
  "server-url": "serverUrl",
40
- "workitem-id": "workitemId",
42
+ [idFlag]: idKey,
41
43
  token: "token",
42
44
  file: "file",
43
45
  };
@@ -97,13 +99,21 @@ function validateServerUrl(value) {
97
99
  return `${url.protocol}//${url.host}${url.pathname.replace(/\/+$/, "")}`;
98
100
  }
99
101
 
100
- function validateWorkitemId(value) {
102
+ function validatePositiveIntegerId(value, flagName) {
101
103
  if (value === undefined || value === null || !/^[1-9][0-9]*$/.test(String(value))) {
102
- throw new UploadError(`--workitem-id must be a positive integer: ${value}`, { kind: "usage" });
104
+ throw new UploadError(`--${flagName} must be a positive integer: ${value}`, { kind: "usage" });
103
105
  }
104
106
  return String(value);
105
107
  }
106
108
 
109
+ function validateWorkitemId(value) {
110
+ return validatePositiveIntegerId(value, "workitem-id");
111
+ }
112
+
113
+ function validateScheduledTaskId(value) {
114
+ return validatePositiveIntegerId(value, "scheduled-task-id");
115
+ }
116
+
107
117
  function preflightFiles(filePaths) {
108
118
  if (!filePaths.length) {
109
119
  throw new UploadError("at least one --file is required", { kind: "usage" });
@@ -196,9 +206,29 @@ function parseServerError(body) {
196
206
  }
197
207
 
198
208
  function uploadWorkitemDocuments({ serverUrl, workitemId, files, token }) {
209
+ return postMultipartUpload({
210
+ serverUrl,
211
+ uploadPath: `${UPLOAD_PATH_PREFIX}${workitemId}${UPLOAD_PATH_SUFFIX}`,
212
+ files,
213
+ token,
214
+ ownerLabel: "the workitem's",
215
+ });
216
+ }
217
+
218
+ function uploadScheduledTaskDocuments({ serverUrl, scheduledTaskId, files, token }) {
219
+ return postMultipartUpload({
220
+ serverUrl,
221
+ uploadPath: `/api/cli/scheduled-tasks/${scheduledTaskId}/documents`,
222
+ files,
223
+ token,
224
+ ownerLabel: "the scheduled task's",
225
+ });
226
+ }
227
+
228
+ function postMultipartUpload({ serverUrl, uploadPath, files, token, ownerLabel }) {
199
229
  return new Promise((resolve, reject) => {
200
230
  const boundary = `----autowonder${crypto.randomBytes(16).toString("hex")}`;
201
- const url = new URL(`${serverUrl}${UPLOAD_PATH_PREFIX}${workitemId}${UPLOAD_PATH_SUFFIX}`);
231
+ const url = new URL(`${serverUrl}${uploadPath}`);
202
232
  const client = url.protocol === "https:" ? https : http;
203
233
  let settled = false;
204
234
  let sentAny = false;
@@ -245,7 +275,7 @@ function uploadWorkitemDocuments({ serverUrl, workitemId, files, token }) {
245
275
  fail(new UploadError(
246
276
  sentAny
247
277
  ? "connection lost after part of the upload was sent; the outcome is ambiguous. " +
248
- "List the workitem's documents to see what arrived before retrying."
278
+ `List ${ownerLabel} documents to see what arrived before retrying.`
249
279
  : `connection failed: ${err.message}`,
250
280
  { kind: "network" },
251
281
  ));
@@ -279,7 +309,9 @@ module.exports = {
279
309
  parseUploadFlags,
280
310
  validateServerUrl,
281
311
  validateWorkitemId,
312
+ validateScheduledTaskId,
282
313
  preflightFiles,
283
314
  parseServerError,
284
315
  uploadWorkitemDocuments,
316
+ uploadScheduledTaskDocuments,
285
317
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autowonder",
3
- "version": "0.2.140",
3
+ "version": "0.2.142",
4
4
  "description": "AutoWonder local runtime — execute AI agent dispatch packages on your machine",
5
5
  "bin": {
6
6
  "autowonder": "bin/cli.js"