autowonder 0.3.30 → 0.3.32

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,10 +6,10 @@ AutoWonder 本地 agent runtime。安装后启动 daemon,持续轮询本地 as
6
6
 
7
7
  ```bash
8
8
  # Qoder CLI(模型使用 provider model ID;Context Window 使用固定档位)
9
- npx -y autowonder@0.3.30 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.3.32 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.3.30 connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider qodercn
12
+ npx -y autowonder@0.3.32 connect --ws-url <wss-endpoint> --token <executor-token> --executor-id <executor-id> --provider qodercn
13
13
  ```
14
14
 
15
15
  `connect` 会安装当前 npm 包内置的 daemon,并使用页面生成的 WebSocket endpoint、Token 和执行器 ID 建立连接。客户端只支持通过 Qoder 系列 CLI 启动(`qoder` 对应 `qodercli`,`qodercn` 对应 `qodercn`),其他 `--provider` 取值会在启动 daemon 前直接报错拦截并提示 `Unsupported provider`。选择 Qoder CLI 或 Qoder CLI CN 时需要 Node.js 20+;runtime 会在缺少对应 CLI 时自动通过 npm 安装,并在尚未登录时打开浏览器登录。runtime 会继承当前用户的 HOME、环境变量和 CLI 登录状态。
@@ -39,7 +39,7 @@ daemon 还在协议能力位里声明 `TASK_MODEL_SELECTION_V1`:服务端可
39
39
 
40
40
  daemon 建立执行器接入连接时会在 WebSocket URL 上附带本机主机名(取不到时不带该参数,服务端按未上报处理),服务端据此在执行器列表区分同一数字员工在多台机器上的执行器。对执行机用户无新增参数或环境变量。
41
41
 
42
- daemon 还在协议能力位里声明 `terminal_steer_v1`:服务端可对当前正在执行的派单下发 `TASK_STEER` 终端插话(含 `guidanceId`、`dispatchId` 与内容)。daemon 只在该派单存在活跃 provider 回合时受理:协作式取消当前回合、等待退出后在同一 agent 会话内携带插话内容继续执行,并经 `TASK_STEER_ACK` 回传受理状态;无活跃回合、回合已结束或接收队列已满时明确返回失败,不影响原任务状态。插话与评论投递、工作流回复路由相互独立(重复投递去重、回执可重放)。该能力对执行机用户无新增参数或环境变量。
42
+ daemon 还在协议能力位里声明 `terminal_steer_v1`:服务端可对当前正在执行的派单下发 `TASK_STEER` 终端插话(含 `guidanceId`、`dispatchId` 与内容)。daemon 只在该派单存在活跃 provider 回合时受理:协作式取消当前回合、等待退出后在同一 agent 会话内携带插话内容继续执行。终端插话的回执时机是「已交给 ACP 会话」而不是「插话回合执行成功」:插话内容写入 `session/prompt` 后立即回传 `TASK_STEER_ACK`(`APPLIED`),同一批插话只回执一次,插话回合随后失败、取消或超时都不会改写这条回执;提交本身失败时仍按回合结果回传 `FAILED`。评论续接等非终端插话批次仍在回合结束后回执。无活跃回合、回合已结束或接收队列已满时明确返回失败,不影响原任务状态。插话与评论投递、工作流回复路由相互独立(重复投递去重、回执可重放)。该能力对执行机用户无新增参数或环境变量。
43
43
 
44
44
  daemon 还会响应服务端的 `CONVERSATION_COMMANDS_PROBE` 帧,用独立会话抓取该会话工作目录下可用的斜杠命令,回传 `CONVERSATION_COMMANDS_RESULT` 帧,让会话面板在用户输入 `/` 时列出真实可用的命令。该探测与回合执行完全隔离:任何失败只产生 `FAILED` / `TIMEOUT` 帧,不影响进行中的会话;provider 后端不支持抓取时同样降级为 `FAILED` 帧。帧里的 `executorId` 与本机不一致或非正数时直接忽略,避免在别的执行器工作区里建目录或启动 CLI。daemon 侧给整个探测 25 秒硬上限,刻意长于 agent 侧的 20 秒预算,使 agent 自己的超时先触发并可被归类。
45
45
 
@@ -105,6 +105,8 @@ daemon 重启或崩溃后重新接管未完成的派单时,runtime 不会直
105
105
 
106
106
  暂停也走同一条持久化回执链路:`TASK_PAUSED` 只有在服务端确认接受后才从结果 outbox 删除,未接受时保留并可重发;服务端再次下发同一派单的暂停指令时,runtime 直接从 capsule 中已落盘的暂停结果(`runtime-result.json`,先校验租户、工单、派单、attempt 与 checkpoint 回执)重放该回执,而不要求暂停协调器仍留在内存里等待,因此 daemon 重启或回执丢失都不会让等待该派单返工的一方永久挂起。
107
107
 
108
+ 暂停边界本身是冻结的:收到暂停指令后 runtime 先停掉普通检查点保存,再把结果与归档(含检查点序号与 SHA-256)原子写入 capsule 的 `state/pause-checkpoint.json`(0600),此后该派单不再落新检查点。服务端确认暂停并回传同一序号与 SHA-256 后,runtime 先写小而持久的确认凭据 `state/pause-checkpoint-confirmed.json`(仅当身份与回执匹配),再删除体积较大的归档;未被确认的暂停结果与归档一直保留,因此暂停 ACK 丢失只会占盘,不会让暂停事实消失。等待恢复期间若本地归档已缺失但确认凭据存在,runtime 会按 capsule 中保留的仓库状态重建检查点并回写新的序号与 SHA-256;恢复只上传冻结的本地状态,不会重新启动 provider 或执行 hooks。工作区 GC 只有在暂停归档已释放且存在与租户、工单、派单、attempt 完全匹配的确认凭据时才把暂停尝试视为终态并回收 capsule,避免提前删除仍可重建的暂停现场。
109
+
108
110
  派单回合以 Qoder 自报的 `cancelled the prompt` 结束、而 runtime 并未发起取消,且本轮既无助手输出也无工具/提问活动时,不再直接判为失败:runtime 最多做 2 次有界恢复,第二次改用新会话并重建同一 workflow 上下文,重试前按退避等待,期间的暂停请求仍即时生效。只要已产生输出或工具副作用、存在待处理插话,或取消来自外部上下文,就不会重试;由多次调用组合而成的回合也不会授权重放其前置轮次。
109
111
 
110
112
  Qoder 取消会在失败历史里附带 runtime 侧上下文诊断(是否尝试过取消、上下文状态),随 telemetry 一起导出,用于区分「模型自行中止」与「真实取消」。该诊断对执行机用户无新增参数或环境变量。
@@ -195,7 +197,7 @@ mv "$queue/.assignment.tmp" "$queue/assignment.json"
195
197
  也可以直接提交到本地 API:
196
198
 
197
199
  ```bash
198
- npx -y autowonder@0.3.30 dispatch ./assignment.json
200
+ npx -y autowonder@0.3.32 dispatch ./assignment.json
199
201
  ```
200
202
 
201
203
  ## 上传工单附件
@@ -203,7 +205,7 @@ npx -y autowonder@0.3.30 dispatch ./assignment.json
203
205
  把本地需求/设计文档直接上传到工单,避免在会话里传递大文件:
204
206
 
205
207
  ```bash
206
- npx -y autowonder@0.3.30 workitem upload --server-url <autowonder-server-url> --workitem-id <id> --file <filepath-1> --file <filepath-2> --json
208
+ npx -y autowonder@0.3.32 workitem upload --server-url <autowonder-server-url> --workitem-id <id> --file <filepath-1> --file <filepath-2> --json
207
209
  ```
208
210
 
209
211
  上传令牌通过 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)。
@@ -213,7 +215,7 @@ npx -y autowonder@0.3.30 workitem upload --server-url <autowonder-server-url> --
213
215
  把工单上已有的需求/设计文档下载到本地目录,再用本地文件工具阅读,避免把大文件或二进制附件搬进会话上下文:
214
216
 
215
217
  ```bash
216
- npx -y autowonder@0.3.30 workitem download --server-url <autowonder-server-url> --workitem-id <id> --file <name-or-id> --output-dir <dir> --json
218
+ npx -y autowonder@0.3.32 workitem download --server-url <autowonder-server-url> --workitem-id <id> --file <name-or-id> --output-dir <dir> --json
217
219
  ```
218
220
 
219
221
  下载令牌通过 MCP 工具 `autowonder.workitem_cli_download_token` 签发(与上传令牌相互独立),经 `--token` 或 `AUTOWONDER_DOWNLOAD_TOKEN` 环境变量传入。`--file` 可重复指定文档名或 artifact id,省略则下载该工单的全部附件;`--output-dir` 默认为当前目录;`--json` 输出机器可读结果,含每个文件的 `id`、`name`、`path`、`size`。退出码约定与 `workitem upload` 相同(401→3、403→4、404→5、409→6、413→7、其他 4xx→8、网络/重定向→9)。
@@ -223,7 +225,7 @@ npx -y autowonder@0.3.30 workitem download --server-url <autowonder-server-url>
223
225
  把需求/设计文档上传到 7x24 定时任务,用法与工单附件一致(同一套上传令牌与预检规则):
224
226
 
225
227
  ```bash
226
- npx -y autowonder@0.3.30 scheduled-task upload --server-url <autowonder-server-url> --scheduled-task-id <id> --file <filepath-1> --file <filepath-2> --json
228
+ npx -y autowonder@0.3.32 scheduled-task upload --server-url <autowonder-server-url> --scheduled-task-id <id> --file <filepath-1> --file <filepath-2> --json
227
229
  ```
228
230
 
229
231
  上传令牌同样通过 `autowonder.workitem_cli_upload_token` 签发(令牌为用户级,对当前可修改的任意定时任务生效),经 `--token` 或 `AUTOWONDER_UPLOAD_TOKEN` 传入;退出码约定与 `workitem upload` 相同。
@@ -231,8 +233,8 @@ npx -y autowonder@0.3.30 scheduled-task upload --server-url <autowonder-server-u
231
233
  ## 管理 daemon
232
234
 
233
235
  ```bash
234
- npx -y autowonder@0.3.30 status
235
- npx -y autowonder@0.3.30 stop
236
+ npx -y autowonder@0.3.32 status
237
+ npx -y autowonder@0.3.32 stop
236
238
  ```
237
239
 
238
240
  默认 API 是 `http://127.0.0.1:34989`,日志位于 `~/.autowonder/daemon.log`。npm 包不包含任何 agent、MCP 或服务端凭证。
@@ -255,7 +257,7 @@ daemon 内置独立于工作区 GC 的保留清扫:默认每小时运行一次
255
257
  ## 调试
256
258
 
257
259
  ```bash
258
- npx -y autowonder@0.3.30 connect ... --debug
260
+ npx -y autowonder@0.3.32 connect ... --debug
259
261
  ```
260
262
 
261
263
  `--debug` 会让 CLI 以 `AUTOWONDER_DEBUG=1` 启动 daemon,把完整的 daemon 与 agent 活动(runtime 事件流、provider 事件解码、重试退避与会话门等待、空闲时的阻塞点)同时输出到控制台和会话调试日志。调试日志不做脱敏,仅用于本机排障;不传 `--debug` 时该环境变量不会注入。
@@ -24,12 +24,14 @@ const WINDOWS_JOB_RUNNER = path.join(__dirname, "windows-job-runner.ps1");
24
24
 
25
25
  function spawnSyncWithTreeTimeout(executable, args, options) {
26
26
  const timeout = options.timeout;
27
- const runnerOptions = { ...options, timeout: timeout + 30000 };
27
+ const { windowsVerbatimArguments, ...childOptions } = options;
28
+ const runnerOptions = { ...childOptions, timeout: timeout + 30000 };
28
29
  if (IS_WIN32) {
29
30
  const powershell = path.join(process.env.SystemRoot || "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
30
31
  const encodedArgs = Buffer.from(JSON.stringify(args), "utf8").toString("base64");
31
32
  return spawnSync(powershell, ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File",
32
- WINDOWS_JOB_RUNNER, "-TimeoutMs", String(timeout), "-Executable", executable, "-ArgsBase64", encodedArgs], runnerOptions);
33
+ WINDOWS_JOB_RUNNER, "-TimeoutMs", String(timeout), "-Executable", executable, "-ArgsBase64", encodedArgs,
34
+ ...(windowsVerbatimArguments ? ["-VerbatimArguments"] : [])], runnerOptions);
33
35
  }
34
36
  return spawnSync(process.execPath, [PROCESS_TREE_RUNNER, String(timeout), executable, JSON.stringify(args)], runnerOptions);
35
37
  }
@@ -136,9 +138,9 @@ function spawnQoderSync(executable, args, options = {}) {
136
138
  const spawnArgs = ["/d", "/v:off", "/s", "/c", invocation.command];
137
139
  if (options.treeTimeout) {
138
140
  const { treeTimeout: _, ...treeOptions } = options;
139
- return spawnSyncWithTreeTimeout(comspec, spawnArgs, { ...treeOptions, env: invocation.env });
141
+ return spawnSyncWithTreeTimeout(comspec, spawnArgs, { ...treeOptions, env: invocation.env, windowsVerbatimArguments: true });
140
142
  }
141
- return spawnSync(comspec, spawnArgs, { ...options, env: invocation.env });
143
+ return spawnSync(comspec, spawnArgs, { ...options, env: invocation.env, windowsVerbatimArguments: true });
142
144
  }
143
145
  if (options.treeTimeout) {
144
146
  const { treeTimeout: _, ...treeOptions } = options;
package/bin/shared.js CHANGED
@@ -29,7 +29,8 @@ function resolveUserPath(value) {
29
29
  // spaces can never be split or misquoted by a shell.
30
30
  function findOnPath(name) {
31
31
  const isWin32 = process.platform === "win32";
32
- const suffixes = isWin32 ? ["", ".exe", ".cmd", ".bat", ".com"] : [""];
32
+ // npm also writes a POSIX shim without an extension; prefer Windows entries.
33
+ const suffixes = isWin32 ? [".exe", ".cmd", ".bat", ".com", ""] : [""];
33
34
  const entries = (process.env.PATH || process.env.Path || "").split(path.delimiter);
34
35
  for (const entry of entries) {
35
36
  if (!entry) continue;
@@ -1,12 +1,15 @@
1
1
  param(
2
2
  [Parameter(Mandatory = $true)][int]$TimeoutMs,
3
3
  [Parameter(Mandatory = $true)][string]$Executable,
4
- [Parameter(Mandatory = $true)][string]$ArgsBase64
4
+ [Parameter(Mandatory = $true)][string]$ArgsBase64,
5
+ [switch]$VerbatimArguments
5
6
  )
6
7
 
7
8
  $ErrorActionPreference = "Stop"
8
9
  $argumentJson = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($ArgsBase64))
9
- [string[]]$childArguments = @(ConvertFrom-Json $argumentJson)
10
+ # Windows PowerShell 5.1 emits the JSON array as one pipeline object.
11
+ # Capture it directly so string[] conversion preserves argument boundaries.
12
+ [string[]]$childArguments = ConvertFrom-Json $argumentJson
10
13
 
11
14
  if (-not ("AutoWonder.WindowsJobRunner" -as [type])) {
12
15
  Add-Type -TypeDefinition @'
@@ -76,7 +79,7 @@ namespace AutoWonder {
76
79
  result.Append('\\', slashes * 2).Append('"'); return result.ToString();
77
80
  }
78
81
 
79
- public static int Run(string executable, string[] args, int timeoutMs) {
82
+ public static int Run(string executable, string[] args, int timeoutMs, bool verbatimArguments) {
80
83
  IntPtr job = IntPtr.Zero; PROCESS_INFORMATION process = new PROCESS_INFORMATION();
81
84
  try {
82
85
  job = CreateJobObject(IntPtr.Zero, null);
@@ -91,7 +94,7 @@ namespace AutoWonder {
91
94
  } finally { Marshal.FreeHGlobal(limitsPtr); }
92
95
 
93
96
  var command = new StringBuilder(Quote(executable));
94
- foreach (string arg in args ?? new string[0]) command.Append(' ').Append(Quote(arg ?? ""));
97
+ foreach (string arg in args ?? new string[0]) command.Append(' ').Append(verbatimArguments ? (arg ?? "") : Quote(arg ?? ""));
95
98
  var startup = new STARTUPINFO(); startup.cb = Marshal.SizeOf(startup);
96
99
  startup.dwFlags = STARTF_USESTDHANDLES;
97
100
  startup.hStdInput = GetStdHandle(-10); startup.hStdOutput = GetStdHandle(-11); startup.hStdError = GetStdHandle(-12);
@@ -122,5 +125,5 @@ namespace AutoWonder {
122
125
  '@
123
126
  }
124
127
 
125
- try { exit [AutoWonder.WindowsJobRunner]::Run($Executable, $childArguments, $TimeoutMs) }
128
+ try { exit [AutoWonder.WindowsJobRunner]::Run($Executable, $childArguments, $TimeoutMs, $VerbatimArguments.IsPresent) }
126
129
  catch { [Console]::Error.WriteLine($_.Exception.ToString()); exit 125 }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autowonder",
3
- "version": "0.3.30",
3
+ "version": "0.3.32",
4
4
  "description": "AutoWonder local runtime — execute AI agent dispatch packages on your machine",
5
5
  "bin": {
6
6
  "autowonder": "bin/cli.js"