@realqiyan/agent-task 0.0.1-rc.3 → 0.1.0-rc.2

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.
Files changed (60) hide show
  1. package/CONTEXT.md +17 -0
  2. package/README.md +28 -6
  3. package/bin/agent-task.mjs +18 -6
  4. package/config.example.json +1 -1
  5. package/dist/application/launcher.js +30 -16
  6. package/dist/application/main.js +5 -2
  7. package/dist/application/mcp-entry.js +71 -0
  8. package/dist/application/task-runtime.js +3 -3
  9. package/dist/configuration/contract.js +2 -2
  10. package/dist/configuration/files.js +2 -3
  11. package/dist/configuration/management.js +1 -1
  12. package/dist/configuration/policy.js +3 -8
  13. package/dist/configuration/settings.js +10 -33
  14. package/dist/executors/ports.js +2 -0
  15. package/dist/executors/registry.js +117 -15
  16. package/dist/executors/validation.js +4 -5
  17. package/dist/infrastructure/lock.js +25 -13
  18. package/dist/infrastructure/workspace.js +4 -3
  19. package/dist/integrations/acp/connection.js +5 -5
  20. package/dist/integrations/acp/discovery.js +271 -0
  21. package/dist/integrations/acp/runtime.js +38 -23
  22. package/dist/integrations/acp/worker.js +5 -3
  23. package/dist/integrations/local-service/control.js +36 -11
  24. package/dist/protocol/cli/commands.js +41 -46
  25. package/dist/protocol/http/server.js +8 -0
  26. package/dist/protocol/http/web.js +7 -1
  27. package/dist/protocol/mcp-contract.js +194 -0
  28. package/dist/protocol/mcp.js +99 -32
  29. package/dist/protocol/settings-contract.js +4 -7
  30. package/dist/protocol/stdio.js +72 -0
  31. package/dist/protocol/task-contract.js +45 -18
  32. package/dist/shared/errors.js +15 -0
  33. package/dist/shared/limits.js +3 -0
  34. package/dist/tasks/definitions.js +19 -14
  35. package/dist/tasks/graph.js +5 -4
  36. package/dist/tasks/human-input.js +10 -9
  37. package/dist/tasks/runs.js +31 -30
  38. package/dist/tasks/schedule.js +2 -1
  39. package/dist/tasks/storage/records.js +6 -6
  40. package/dist/tasks/storage/store.js +8 -7
  41. package/dist/tasks/supervisor.js +10 -7
  42. package/dist/tasks/validation.js +3 -0
  43. package/dist/web/settings-view.js +43 -37
  44. package/docs/adr/0001-task-request-scope.md +3 -0
  45. package/docs/adr/0002-mcp-workspace-source.md +3 -0
  46. package/docs/adr/0003-adapter-installation.md +3 -0
  47. package/docs/architecture-guidelines.md +2 -2
  48. package/docs/cli.md +12 -4
  49. package/docs/deployment.md +52 -36
  50. package/docs/design-proposal.md +3 -0
  51. package/docs/release.md +27 -8
  52. package/docs/technical-design.md +5 -3
  53. package/docs/validation.md +59 -9
  54. package/docs/web-console.md +7 -4
  55. package/package.json +3 -1
  56. package/scripts/install-lib.mjs +5 -23
  57. package/scripts/probe-agent.mjs +10 -9
  58. package/scripts/service-runner.mjs +8 -3
  59. package/scripts/setup-wizard.mjs +38 -11
  60. package/scripts/setup.mjs +69 -95
@@ -1,31 +1,28 @@
1
1
  import { request } from "./api.js";
2
- import { element, field, select, button, submit, block, table, notice } from "./dom.js";
2
+ import { element, field, select, button, submit, block, table, notice, report } from "./dom.js";
3
3
 
4
- function executorEditor(host, executor) {
5
- const card = element("fieldset"), fields = {};
6
- card.append(element("legend", "ACP 执行端"));
7
- const type = select("类型", ["pi", "codex", "claude", "opencode"].map(value => [value, value]), executor.type ?? "pi");
8
- fields.type = type.input; card.append(type.row);
9
- for (const [key, label, kind, value] of [
10
- ["id", "注册 ID", "text", executor.id],
11
- ["note", "备注", "textarea", executor.note],
12
- ["cwd", "默认工作空间(绝对路径)", "text", executor.cwd],
13
- ]) {
14
- const item = field(label, value, kind); fields[key] = item.input; card.append(item.row);
15
- }
16
- const approved = field("已由管理员审核原生授权,允许无人值守执行", executor.unattendedApproved, "checkbox");
17
- let explicitlyApproved = false;
18
- approved.input.addEventListener("change", () => { explicitlyApproved = approved.input.checked; });
19
- for (const [key, input] of Object.entries(fields)) if (key !== "note") input.addEventListener("input", () => {
20
- approved.input.checked = false; explicitlyApproved = false;
21
- });
22
- card.append(approved.row, element("p", "按类型从用户原生 PATH 查找 ACP 适配器。继承用户原生环境,但过滤服务私密变量;额外 ACP 审批一律拒绝。结果固定保存在 dataDir/results,只向节点提供指定上游文件,不提供整个数据目录读取。"),
23
- button("从待保存配置中移除", () => { card.remove(); host.dispatchEvent(new Event("input", { bubbles: true })); }));
24
- host.append(card);
25
- return () => card.parentNode === host ? [{ explicitlyApproved, executor: {
26
- id: fields.id.value, type: fields.type.value, note: fields.note.value,
27
- cwd: fields.cwd.value, unattendedApproved: approved.input.checked,
28
- } }] : [];
4
+ function executorStatus(host, initial) {
5
+ let state = initial, timer;
6
+ const labels = { missing: "未安装", disabled: "已禁用", installing: "准备中", ready: "可派发", error: "准备失败" };
7
+ const draw = () => {
8
+ clearTimeout(timer);
9
+ host.replaceChildren(table(["执行端", "状态", "本机路径", "ACP 适配器版本", "错误", "操作"], state.executors.map(executor => [
10
+ executor.id, executor.state === "missing" && executor.nativePath ? "已发现,待准备" : labels[executor.state],
11
+ executor.nativePath, executor.adapterVersion ?? (executor.type === "opencode" ? "原生 ACP" : "—"), executor.error,
12
+ executor.type === "opencode" ? "通过原生 CLI 更新" : button("升级 ACP 适配器", async () => {
13
+ if (!confirm("升级 " + executor.id + " 的托管 ACP 适配器?准备期间暂停向此执行端派发新工作。")) return;
14
+ state = await request("/executors/upgrade", { id: executor.id }); draw();
15
+ notice("适配器升级已开始,完成后更新状态。");
16
+ }, !executor.nativePath || ["disabled", "installing"].includes(executor.state)),
17
+ ])));
18
+ if (state.executors.some(executor => executor.state === "installing")) timer = setTimeout(async () => {
19
+ if (!host.isConnected) return;
20
+ try { state = await request("/executors"); if (host.isConnected) draw(); }
21
+ catch (error) { if (host.isConnected) report(error); }
22
+ }, 2000);
23
+ };
24
+ draw();
25
+ return async () => { state = await request("/executors/refresh", {}); draw(); };
29
26
  }
30
27
  function coordinatorEditor(host, config) {
31
28
  const provider = select("协调模型提供方", [["", "未配置"], ["openai", "OpenAI"], ["anthropic", "Anthropic"],
@@ -56,12 +53,18 @@ function coordinatorEditor(host, config) {
56
53
  };
57
54
  }
58
55
  export async function renderSettings(root, navigate) {
59
- let state = await request("/settings");
56
+ const initial = await Promise.all([request("/settings"), request("/executors")]);
57
+ let state = initial[0];
60
58
  root.append(element("h2", "配置与凭据"), element("p", "配置和密钥分别保存。保存不修改当前进程;每次重新启动(包括故障后拉起)读取已保存值。"),
61
59
  element("p", "先保存新密钥,再保存引用它的配置。执行端原生登录和原生权限仍通过官方工具管理;这里不编辑其认证文件。"),
62
60
  block("当前运行配置(只读,无密钥值)", state.running));
63
61
  if (state.writeBlocked) root.append(element("p", "上次文件提交结果不确定。请停服核查;当前禁止继续保存。"));
64
- const form = element("form"), modelHost = element("fieldset"), executors = element("div"), readers = [];
62
+ const executorHost = element("div");
63
+ const refreshExecutors = executorStatus(executorHost, initial[1]);
64
+ root.append(element("h3", "本机执行端"),
65
+ element("p", "自动检测 pi、codex、claude 和 opencode。可派发表示启动依赖已准备,不代表原生认证或工具权限已验收。"),
66
+ button("重新检测并准备执行端", refreshExecutors), executorHost);
67
+ const form = element("form"), modelHost = element("fieldset"), executorOptions = element("fieldset");
65
68
  modelHost.append(element("legend", "协调模型"));
66
69
  const readModel = coordinatorEditor(modelHost, state.saved.coordinator);
67
70
  const startup = {
@@ -69,18 +72,21 @@ export async function renderSettings(root, navigate) {
69
72
  port: field("下次启动的监听端口(0 为自动分配)", state.saved.port, "number"),
70
73
  tokenEnv: field("MCP 令牌环境变量名(改名保留令牌值)", state.saved.tokenEnv),
71
74
  };
72
- form.append(element("h3", "启动配置"), ...Object.values(startup).map(item => item.row),
73
- modelHost, element("h3", "执行端注册与权限"), executors);
74
- for (const executor of state.saved.executors) readers.push(executorEditor(executors, executor));
75
- form.append(button("添加执行端", () => {
76
- readers.push(executorEditor(executors, { id: "", type: "pi", note: "", cwd: "", unattendedApproved: false }));
77
- }, state.writeBlocked));
75
+ executorOptions.append(element("legend", "下次启动启用的执行端"),
76
+ element("p", "默认使用所有检测到的执行端。取消勾选后保存并重启;已有任务不会自动改派。"));
77
+ const enabled = ["pi", "codex", "claude", "opencode"].map(type => {
78
+ const item = field(type, !state.saved.disabledExecutors.includes(type), "checkbox");
79
+ executorOptions.append(item.row); return { type, input: item.input };
80
+ });
81
+ const advanced = element("details"); advanced.dataset.key = "advanced-settings";
82
+ advanced.append(element("summary", "高级设置"), element("h3", "启动配置"),
83
+ ...Object.values(startup).map(item => item.row), executorOptions);
84
+ form.append(modelHost, advanced);
78
85
  const preview = element("div");
79
86
  const save = submit(form, "校验并预览配置变更", async () => {
80
- const entries = readers.flatMap(read => read());
81
- const input = { editToken: state.editToken, approveExecutors: entries.filter(item => item.explicitlyApproved).map(item => item.executor.id),
87
+ const input = { editToken: state.editToken,
82
88
  config: { dataDir: startup.dataDir.input.value, port: startup.port.input.valueAsNumber, tokenEnv: startup.tokenEnv.input.value,
83
- coordinator: readModel(), executors: entries.map(item => item.executor) } };
89
+ coordinator: readModel(), disabledExecutors: enabled.filter(item => !item.input.checked).map(item => item.type) } };
84
90
  const checked = await request("/settings/validate", input);
85
91
  preview.replaceChildren(block("校验后的待保存配置", checked.config),
86
92
  block("配置变更", checked.changes),
@@ -0,0 +1,3 @@
1
+ # 按任务工作目录区分创建请求
2
+
3
+ 多个项目共用本机后台时,调用方可能使用相同请求键。任务创建请求按最终规范工作目录和请求键确定身份,使不同目录的请求相互独立,同一目录中的重复提交仍能去重。
@@ -0,0 +1,3 @@
1
+ # 使用明确的任务工作目录来源
2
+
3
+ MCP 宿主不保证从当前项目目录启动接入进程,服务无法据此通用地识别宿主当前项目。任务显式提供的工作目录优先,否则使用本机 MCP 入口的启动目录;直接 HTTP 调用须显式提供目录。默认目录属于该 MCP 连接,避免多个项目误用共用后台的启动目录。
@@ -0,0 +1,3 @@
1
+ # 按需安装最新版适配器并复用已有安装
2
+
3
+ MCP 连接触发 ACP 适配器检测,缺失时安装当时最新版,已有安装继续复用。升级由显式操作触发,避免普通重连改变任务使用的执行环境。
@@ -34,8 +34,8 @@ CLI 覆盖 Web 的全部配置和管理操作,两端必须复用同一套底
34
34
  ## 权限与敏感数据
35
35
 
36
36
  - 执行端声明能力、管理员授权、真实验证证据分别表达,不能相互推导。
37
- - 只有管理员注册的执行端可启动。命令、凭据和能力端点属于管理员;任务可选择现有绝对工作空间,但路径校验不是授权或沙箱。
38
- - 授权须在可控制的实际操作入口检查。沿用执行端原生授权,额外 ACP 审批请求一律拒绝;`unattendedApproved` 不能证明所有原生工具已受控。
37
+ - 只有已发现、未禁用且 ACP 依赖就绪的本机执行端可启动。启动命令由系统控制,MCP 调用方不能提供命令、凭据或能力端点;任务目录在创建时确定,路径校验不是授权或沙箱。
38
+ - 授权须在可控制的实际操作入口检查。沿用执行端原生授权,额外 ACP 审批请求一律拒绝;发现与依赖就绪不能证明所有原生工具已受控。
39
39
  - Prompt、角色、技能、工具标题、协议成功和人工事实回复都不授予权限。取消、恢复和跨 Agent 传递不能扩大授权。
40
40
  - 无人值守执行不等待交互审批;授权不充分或元数据不足时拒绝,不退回更宽权限或自动永久允许。
41
41
  - MCP token、管理员 token、协调模型与执行端凭据分开;执行端继承用户原生环境前过滤服务私密变量,不有意记录秘密。Agent 输出和协调日志仍可能敏感。
package/docs/cli.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 本机管理 CLI
2
2
 
3
- CLI 覆盖 Web 的配置、凭据、任务查询、未来触发控制及重启操作。两端通过同一管理 API 使用配置和任务服务;重启由同一启动器处理。命令入口见 [命令实现](../src/protocol/cli/commands.ts),管理传输见 [admin-client.ts](../src/protocol/cli/admin-client.ts)。
3
+ CLI 覆盖 Web 的配置、凭据、执行端管理、任务查询、未来触发控制及重启操作。两端通过同一管理 API 使用配置、执行端和任务服务;重启由同一启动器处理。命令入口见 [命令实现](../src/protocol/cli/commands.ts),管理传输见 [admin-client.ts](../src/protocol/cli/admin-client.ts)。
4
4
 
5
5
  ## 连接与命令
6
6
 
@@ -16,9 +16,9 @@ agent-task task --help
16
16
  agent-task run --help
17
17
  ```
18
18
 
19
- 逐级帮助是命令与参数的完整入口。管理命令支持 `--json`,结果写入 stdout,预览和诊断写入 stderr;失败退出码非零。非交互保存与任务变更须使用 `--yes`,它只确认本次操作,不替代校验或执行端授权。
19
+ 逐级帮助是命令与参数的完整入口。管理命令支持 `--json`,结果写入 stdout,预览和诊断写入 stderr;失败退出码非零。非交互保存、适配器升级与任务变更须使用 `--yes`,它只确认本次操作,不授予执行端原生工具权限。
20
20
 
21
- 服务不可用时,管理命令失败,不自动离线写文件。首次安装仍使用 `setup`;启动故障按[部署说明](deployment.md#前台重启与健康检查)停服核查。CLI 不迁移数据或修复历史。
21
+ 服务不可用时,管理命令失败,不自动离线写文件。首次安装仍使用 `setup`;启动故障按[部署说明](deployment.md#后台前台与健康检查)停服核查。CLI 不迁移数据或修复历史。
22
22
 
23
23
  ## 配置流程
24
24
 
@@ -38,10 +38,18 @@ agent-task config show --running
38
38
 
39
39
  导出文件不包含密钥值,以私有权限创建,拒绝覆盖已有文件。编辑令牌过期、服务重启或任一客户端保存配置/凭据后,旧草稿不能提交;重新读取并人工核对,不自动合并。草稿契约见 [settings-contract.ts](../src/protocol/settings-contract.ts)。
40
40
 
41
- `executor` 和 `coordinator` 提供便捷操作,配置服务负责生成候选配置,再走同一预览、校验和保存流程。新执行端默认未批准;修改 ID、类型或工作空间后清除批准。原生授权审核完成后,显式运行 `executor approve ID`。完整草稿新增或变更已批准的执行端时,也须明确声明对候选配置的授权。
41
+ `executor enable/disable` 和 `coordinator` 提供便捷配置操作。配置服务生成候选配置,再走同一预览、校验和保存流程。执行端自动发现,无须手工注册、设置默认工作目录或另行批准。启用与禁用在下次启动生效,不改写已有任务的执行端指派。
42
42
 
43
43
  配置与凭据均在下次启动生效。影响预览不修改旧任务快照,也不证明模型认证或 ACP 执行成功。保存顺序、端点与凭据隔离、重启影响见[控制台说明](web-console.md#保存与重启)。
44
44
 
45
+ ## 执行端发现与更新
46
+
47
+ `agent-task executor list` 查看当前发现和准备结果;`executor show codex` 查看单个执行端。安装新的原生 CLI 后,运行 `executor refresh` 重新检测并在后台准备缺少的 ACP 适配器。该操作无需重启。准备失败时先检查报告的原因,修正后显式刷新或升级。
48
+
49
+ 已准备的适配器不会随普通启动或刷新自动升级。需要更新时运行 `agent-task executor upgrade codex --yes`,再用 `executor list` 检查结果。升级期间暂停向该执行端派发新工作;它不修改已有任务指派。OpenCode 使用原生 ACP 命令,通过原生 CLI 的安装渠道更新。
50
+
51
+ 就绪状态只表示启动依赖已准备。原生登录和权限仍由执行端管理;首次准备、版本来源及运行边界见[部署说明](deployment.md)。
52
+
45
53
  ## 凭据与任务
46
54
 
47
55
  `credential set NAME` 使用隐藏终端输入;自动化通过 `--stdin --yes` 从可信凭据工具或受保护文件传值,不把值写进命令参数。`credential list` 只显示设置状态。执行端原生登录和权限继续由其官方工具管理。
@@ -1,75 +1,91 @@
1
1
  # 安装与运行
2
2
 
3
- 支持 Linux 和 macOS,要求 Node.js **22.19+** 与 npm。安装包包含运行产物,不需要源码或 TypeScript。发布状态和平台证据见[验证说明](validation.md),发布操作见[发布说明](release.md)。
3
+ 支持 Linux 和 macOS,要求 Node.js **22.19+** 与 npm。安装包包含运行产物,不需要源码或 TypeScript。本文描述当前实现;已发布版本和平台证据见[验证说明](validation.md),发布操作见[发布说明](release.md)。
4
4
 
5
- ## 安装与交互配置
5
+ ## 安装与初始化
6
6
 
7
7
  ```bash
8
8
  npm install -g @realqiyan/agent-task
9
9
  agent-task setup
10
- agent-task start
11
10
  ```
12
11
 
13
- 使用当前用户可写的 npm prefix,不以 root 运行。
12
+ 使用当前用户可写的 npm prefix。向导要求确认安装目录、数据目录、端口、令牌配置及协调员 provider;选择 provider 后收集模型和凭据。令牌可以确认后随机生成,也可以从私有 JSON 文件提供。取消确认不写配置,密钥输入不回显。未配置 provider 时仍可管理服务,但不能接收可执行任务。
14
13
 
15
- 向导收集工作空间、可选执行端、可选协调模型及端口。取消确认不写配置。无终端环境须明确提供参数:
14
+ 无终端环境必须明确确认这些初始化选项。例如,私有凭据文件已包含协调员密钥时:
16
15
 
17
16
  ```bash
18
- agent-task setup --executors none --cwd /absolute/workspace
19
- # 另一个首次安装选择:安装 Pi ACP 组件,但不授权执行。
20
17
  agent-task setup --home /absolute/private/agent-task \
21
- --executors pi --cwd /absolute/workspace \
22
- --provider deepseek --model deepseek-flash
18
+ --data-dir /absolute/private/agent-task/data --port 8765 \
19
+ --provider deepseek --model deepseek-flash \
20
+ --credentials-file /absolute/private/coordinator.json \
21
+ --generate-tokens --yes
23
22
  ```
24
23
 
25
- 工作空间须预先存在,且位于安装目录及 npm 包之外。完整选项见 `agent-task setup --help`;组件版本及平台实现见 [install-lib.mjs](../scripts/install-lib.mjs)。安装不执行原生登录或批准任务。
24
+ 此例从文件读取协调员密钥,并生成独立的服务和管理员令牌。已有服务令牌和管理员令牌时,由同一私有文件提供,省略 `--generate-tokens`。不通过命令参数传密钥值。完整选项见 `agent-task setup --help`,凭据文件约束见 [environment.ts](../src/configuration/environment.ts)。
26
25
 
27
- 默认安装目录为 Linux 的 `~/.local/share/agent-task` 或 macOS 的 `~/Library/Application Support/agent-task`。自定义 `--home` 后,后续命令也传同一路径。setup 输出私有文件路径和控制台地址,**不打印 token**。
26
+ 安装目录和数据目录须属于当前用户,使用规范绝对路径和私有权限。setup 输出文件路径,不打印 token。自定义 `--home` 后,后续命令及 MCP 配置使用同一路径。初始化不安装执行 CLI 或 ACP 适配器,不执行原生登录。
28
27
 
29
- ## 数据目录与配置
28
+ ## MCP 接入与工作目录
30
29
 
31
- 初始 `dataDir` 是安装目录下的 `data/`。运行配置、私有环境文件、任务和协调会话记录、结果及服务文件日志均位于当前 `dataDir`。配置契约见 [配置契约](../src/configuration/contract.ts),路径选择与新目录准备见 [startup.ts](../src/application/startup.ts)。
30
+ 在宿主的 MCP 配置中添加命令,例如采用 `mcpServers` 格式的宿主:
32
31
 
33
- 安装目录保留固定的 `launch.json` 定位文件、安装清单、组件及启动器控制资源;它不是另一份运行配置。CLI 通过这个固定入口定位当前数据目录。npm 包、用户工作空间和执行端原生配置不随 `dataDir` 移动。
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "agent-task": {
36
+ "command": "agent-task",
37
+ "args": ["mcp"]
38
+ }
39
+ }
40
+ }
41
+ ```
34
42
 
35
- 在 Web 修改数据目录后,下次启动只在目标目录准备已保存的配置和私有环境,并切换定位文件;**不复制任务、会话、结果或日志,不删除旧目录**。目标已有不同启动文件时拒绝覆盖;须停服核对并显式准备目标,不自动合并或修复。新目录没有旧任务,不能把切换目录当成故障恢复或重放许可。
43
+ 自定义安装目录时,参数改为 `["mcp", "--home", "/absolute/private/agent-task"]`。宿主找不到命令时,使用已安装 `agent-task` 的绝对路径。配置文件位置和外层结构由宿主决定,本服务不自动修改宿主配置或识别宿主当前项目。
36
44
 
37
- 1. 运行 `agent-task start`,打开输出的本机控制台地址。用本地编辑器读取当前 `dataDir/environment.json` 的 `AGENT_TASK_ADMIN_TOKEN`,在连接表单输入。不要把 token 放进 URL、命令行、Git、截图或日志。
38
- 2. 在[控制台](web-console.md)或 [CLI](cli.md) 配置协调模型、单独保存模型密钥及注册执行端。两端使用同一管理服务。未配置协调模型时可管理服务,但不能接收可执行任务。
39
- 3. 按执行端官方方式准备原生认证及权限:[Pi](https://github.com/earendil-works/pi/tree/v1.3.0/packages/coding-agent/docs)、[Codex ACP](https://github.com/agentclientprotocol/codex-acp#readme)、[Claude ACP](https://github.com/zed-industries/claude-agent-acp)、[OpenCode](https://opencode.ai/docs/acp/)。运行进程与原生登录须使用同一 OS 用户及相应 HOME/配置目录。
40
- 4. 审核原生工具、沙箱、凭据和结果文件读取权限后,再明确批准无人值守执行。注册只选类型,不配置命令、参数、环境变量清单或 ACP 工具白名单;系统映射见 [命令映射](../src/integrations/acp/runtime.ts)。额外 ACP 审批请求被拒绝,不自动批准。
45
+ `agent-task mcp` 通过 stdio 接入,自动启动或连接同一安装目录的共用后台,并从私有文件读取内部服务 token。无需先执行 `start`,也无需把端口和 token 复制到 MCP 配置。stdout 仅传输 MCP 消息。
41
46
 
42
- 服务和协调员的秘密只从私有环境文件加载,不回退到 shell 模型密钥。执行端沿用启动上下文中的用户原生环境,但排除私有文件变量、服务/管理员令牌、协调员凭据及同值别名。不要把执行端原生凭据放入服务的私有环境文件。启动器不执行 shell 启动脚本,也不导入原生认证文件。隔离实现见 [服务环境校验](../src/configuration/environment.ts)、[执行端环境过滤](../src/executors/environment.ts)。这不是同一 OS 用户下的沙箱。
47
+ 任务显式提供 `workspace` 时使用该目录;省略时使用本次 stdio 进程的启动目录。宿主须从目标项目目录启动命令,或在创建任务时明确传目录。服务不使用共用后台的启动目录猜测项目,也不根据 MCP roots 或宿主名称推断。直接 HTTP 接入需自行携带服务 token,并在 `task_create` 中指定目录。
43
48
 
44
- 显式握手检查:
49
+ 创建时校验目录存在并规范化,随后固定到任务;周期执行也使用同一目录。需要修改目录时取消旧任务的未来触发,再创建新任务。创建请求按最终目录和 `requestKey` 去重,不同项目可独立使用同一请求键。契约见 [task-contract.ts](../src/protocol/task-contract.ts),决策原因见[目录来源](adr/0002-mcp-workspace-source.md)与[请求去重](adr/0001-task-request-scope.md)。
45
50
 
46
- ```bash
47
- agent-task setup --check --probe
48
- ```
51
+ ## 执行端发现与准备
52
+
53
+ 每次 MCP 连接初始化时,后台从自己的原生 PATH 检测 pi、codex、claude 和 opencode。四者均不存在时拒绝 MCP 连接,提示至少安装一种;CLI/Web 管理入口仍可使用。安装和认证由对应官方工具负责:[Pi](https://github.com/earendil-works/pi/tree/v1.3.0/packages/coding-agent/docs)、[Codex](https://github.com/openai/codex)、[Claude Code](https://code.claude.com/docs/en/overview)、[OpenCode](https://opencode.ai/docs/)。
54
+
55
+ 发现原生 CLI 后,后台为缺少 ACP 适配器的执行端安装当时最新版,已有安装直接复用;OpenCode 使用原生 ACP 命令。安装在后台进行,可用 MCP `executor_list`、`agent-task executor list` 或 Web 查看准备结果。任务只能选择就绪执行端。适配器安装失败时保留管理入口和其他就绪执行端,修正原因后显式刷新或升级。包映射和安装实现见 [discovery.ts](../src/integrations/acp/discovery.ts)。
49
56
 
50
- 这只做 ACP initialize,不验证模型认证、任务成功或原生工具权限。普通 Pi CLI 不是 ACP server,须配合 pi-acp。自行安装的受支持适配器也可使用,只要在服务的原生 PATH 中;无需填写绝对可执行文件路径。
57
+ 适配器保存在安装目录的私有 `adapters/` 中,不修改全局 npm 包或执行 CLI 的原生配置。普通重连不访问 registry 升级已有适配器。显式更新使用 `agent-task executor upgrade codex --yes`,再查询状态;新版本发布成功前保留原安装,活动 ACP 进程不因升级被重启。高级启停设置及 Web/CLI 操作见 [CLI 说明](cli.md#执行端发现与更新)。
51
58
 
52
- ## 前台、重启与健康检查
59
+ 后台的原生环境来自启动它的进程,不随不同 MCP 客户端切换。新 CLI 位于已有 PATH 时可用 `executor refresh` 重新检测;PATH 本身变化时先停止后台,再从正确环境连接或启动。原生登录须与后台使用同一 OS 用户及 HOME/配置目录。
60
+
61
+ 就绪只表示启动依赖已准备,不证明原生认证、模型或工具权限可用。服务沿用执行端原生授权,不另设手工批准开关;额外 ACP 审批请求一律拒绝,不自动扩大权限。服务和协调员秘密只从私有环境文件加载。执行端继承用户原生环境前,过滤私有文件变量、服务令牌、协调员凭据及同值别名;不要将执行端原生凭据放入服务的私有文件。过滤实现见 [environment.ts](../src/executors/environment.ts),它不构成同一用户下的沙箱。
62
+
63
+ ## 后台、前台与健康检查
53
64
 
54
65
  ```bash
55
- agent-task start
56
- # 另一个终端:
57
66
  agent-task status
58
67
  agent-task restart
68
+ agent-task stop
69
+ # 需要前台管理时:
70
+ agent-task start
59
71
  ```
60
72
 
61
- Ctrl-C 关闭前台启动器及其运行进程。`restart` 和 Web 的“重启并检查可用性”使用同一启动器:先停止新派发、关闭活动执行并释放数据所有权,再用已保存配置创建新进程。
73
+ stdio 退出只关闭当前连接。由 `mcp` 启动的后台使用独立进程组,宿主关闭或原终端退出后,已提交任务继续调度;没有自动空闲退出。`stop` 显式关闭后台和活动执行。`start` 是前台入口,Ctrl-C 关闭该启动器及其运行进程。
74
+
75
+ 独立后台不保证机器关机、系统清理用户进程或后台自身故障后继续运行,也不配置开机自启。再次启动后读取持久任务;已中断且结果不明的执行保持阻断,不自动重试、重放或改派。
76
+
77
+ `restart` 与 Web 的重启入口使用同一启动器,应用已保存配置。只有新实例通过带 MCP token 的健康检查才返回成功,并给出实例标识及地址。端口变化时以该地址为准。重启关闭 ACP 会话,不保证等待人工回复的运行能无损继续。请求超时先用 `status` 核对,不盲目重复操作。
62
78
 
63
- 只有新实例通过带 MCP token 的健康检查才返回成功,并给出新实例标识及地址。端口变化或自动分配端口时,以返回地址为准;Web 不通过链接传递管理员令牌,须重新连接。
79
+ MCP 接入不会自动重启一个已存在但不可用的后台。故障时查看安装目录的 `launcher.log` 和当前数据目录的 `service.log`;修正私有启动文件后显式重启,启动器已退出时重新连接或运行 `start`。启动失败不会回滚配置或重放工作。
64
80
 
65
- 重启会关闭 ACP 会话,不保证等待人工回复的运行能无损继续。结果不明的执行保持阻断,不自动重试、重放或改派执行端。请求超时不代表重启没发生,先用 `agent-task status` 核对;不要盲目重复操作。
81
+ ## 数据目录与管理
66
82
 
67
- 启动失败不会回滚配置或重放工作。查看当前 `dataDir/service.log`;确认没有运行实例持有数据后,修正私有文件,再显式 `agent-task restart`。启动器也已退出时,用原启动方式重新启动。
83
+ 运行配置、私有环境文件、任务和协调会话记录、结果及服务日志位于当前 `dataDir`。安装目录保留 `launch.json` 定位文件、初始化清单、适配器及启动器控制资源。npm 包、项目工作空间和执行端原生配置与数据目录分开。路径实现见 [startup.ts](../src/application/startup.ts)。
68
84
 
69
- 源码开发者执行 `npm ci --ignore-scripts && npm run build` 后,可用 `npm run setup -- ...` 和 `npm start -- --home ...`;npm 安装用户不需要构建。内部 `dist/application/main.js` 不是独立的重启入口。
85
+ 打开 `status` 返回地址同源的 `/admin/`,用本地编辑器读取当前 `dataDir/environment.json` 中的 `AGENT_TASK_ADMIN_TOKEN`,在连接表单输入。不要把 token 放入 URL、命令参数、Git 或截图。CLI 从私有文件读取管理员令牌。两端使用同一管理服务,见[控制台说明](web-console.md)和 [CLI 说明](cli.md)。
70
86
 
71
- ## 更新
87
+ 修改数据目录后,下次启动只准备目标配置和私有环境,并切换定位文件;不复制任务、会话、结果或日志,不删除旧目录。目标已有不同启动文件时拒绝覆盖,须停服核对并显式准备目标。新目录没有旧任务,目录切换不是恢复或重放许可。
72
88
 
73
- 重复 setup 保留配置和授权。中断安装只能显式执行 `agent-task setup --resume`;所有权或清单不明时停止核查。
89
+ 重复 setup 保留已有配置。初始化中断后须显式执行 `setup --resume`,它只接续已保存且一致的初始化文件;缺少凭据或所有权不明时停止核查,不猜测修复。更新前停止后台并备份安装目录和数据目录。调研阶段不保证旧配置或数据兼容,普通启动不迁移历史。
74
90
 
75
- 更新前停止运行进程,并备份安装目录和当前数据目录。调研阶段不保证旧数据兼容,普通启动不执行迁移。
91
+ 源码开发者执行 `npm ci --ignore-scripts && npm run build` 后,可用 `node bin/agent-task.mjs setup`、`node bin/agent-task.mjs mcp` 或 `npm start -- --home ...`。内部 `dist/application/main.js` 不是独立的重启入口。
@@ -2,10 +2,13 @@
2
2
 
3
3
  本文保留产品目标和架构取舍。实现入口见[代码导航](technical-design.md),实际证据见[验证说明](validation.md)。
4
4
 
5
+ 使用流程简化的决策原因见[请求去重范围](adr/0001-task-request-scope.md)、[工作目录来源](adr/0002-mcp-workspace-source.md)和[适配器安装](adr/0003-adapter-installation.md)。
6
+
5
7
  ## 产品目标
6
8
 
7
9
  - 调用方通过 MCP 提交整体目标、DAG 和每节点的 ACP 执行端指派,支持立即、定时及周期执行。
8
10
  - 任务不依赖发起客户端持续在线,保留执行、交付、失败和缺少用户事实的记录。
11
+ - 初始化由用户确认目录、端口、令牌及协调模型;执行端自动发现并按需准备适配器。stdio 接入连接独立后台,宿主退出后后台继续调度;宿主配置由用户添加,不自动识别宿主当前项目。
9
12
  - 协调员推进既定 DAG、解释中间结果、处理澄清并组织交付;领域分析和工具操作交给执行端。
10
13
  - 缺少用户事实时可持久等待,回复后续接原运行,不丢失已接受工作。
11
14
  - 提供本机 Web 控制台,管理配置、查看任务,并只控制任务的未来触发;CLI 覆盖全部 Web 管理能力,两端复用同一套服务。配置保存后通过 Web 或 CLI 重启生效;切换数据目录不搬迁或删除旧历史。
package/docs/release.md CHANGED
@@ -12,25 +12,43 @@ npm run check
12
12
  npm test
13
13
  git diff --check
14
14
  npm run pack:release
15
- npm run test:install -- ./realqiyan-agent-task-0.0.1-rc.3.tgz
15
+ VERSION=$(node -p "require('./package.json').version")
16
+ npm run test:install -- "./realqiyan-agent-task-$VERSION.tgz"
16
17
  ```
17
18
 
18
- 安装验证先检查当前 OS 和 Node.js 版本,再在独立临时目录执行真正的全局 npm 安装,禁用 lifecycle scripts,不使用项目源码或编译器;随后配置、前台启动、调用 Web 配置接口、重启、进行认证健康检查。验证脚本不调用模型或启动 ACP 工作。
19
+ 安装验证先检查当前 OS 和 Node.js 版本,再在独立临时目录执行真正的全局 npm 安装,禁用 lifecycle scripts,不使用项目源码或编译器;随后验证初始化、前台启动、Web 配置、重启和认证健康检查,再验证 stdio 自动启动后台、断开后后台仍可用及显式 stop。MCP 客户端使用安装包的 SDK 依赖。验证脚本不调用模型或启动 ACP 工作。
19
20
 
20
21
  输出报告只包含结果和证据目录,不包含 token;只将实际运行的宿主平台记为通过,其他平台明确记为未执行。临时目录权限为私有,内有验证专用随机凭据及空任务库,不上传这些目录。基础测试中的真实 PTY 用例先检查平台及 `script` 能否创建终端;能力不可用时明确跳过,不能把跳过当成终端验收通过。
21
22
 
22
23
  脚本只验证当前环境,不在 Linux 上推断 macOS 行为;需要 macOS 证据时,在相应环境单独运行同一命令。本地可设置 `npm_config_cache` 复用下载缓存,tarball 验证可用 `npm_config_registry` 指定依赖镜像,报告会记录其地址;`--registry` 发布后验收固定使用 npmjs。不能以复制项目的 node_modules 替代安装验证。
23
24
 
25
+ npm 接收发布后可能仍在处理包。发布后验收最多等待五分钟,确认公开 `latest` 指向目标版本,再执行默认全局安装;等待只读取 registry。超时先核对版本状态,不重复上传。
26
+
24
27
  ## GitHub Actions 门禁与受控发布
25
28
 
26
29
  - [Validate](../.github/workflows/ci.yml):PR/master 或手动触发时在 Ubuntu 执行 TypeScript 与依赖边界检查、基础测试及构建;检查包清单。安装任务**不 checkout 项目源码**,只接收 tarball 和验收脚本,在当前 Linux runner 验证启动、重启及认证检查。常规 CI 不再要求 macOS runner;这不代表 macOS 已验证或不受支持。
27
- - [Publish npm](../.github/workflows/publish.yml):仅手动触发,限制 master 和账号 realqiyan,输入须匹配已验收包版本。再次执行全部门禁,再发布同一 tarball,不重建、不执行包脚本。发布后核查 latest 并执行默认全局安装验证。
30
+ - [Publish npm](../.github/workflows/publish.yml):推送 `v*` tag 自动触发,也保留手动入口;仅账号 realqiyan 可发起或重跑。[发布准入](../scripts/check-release.mjs)要求 tag 与包版本一致、锁文件版本一致,且提交已进入远端 master。手动入口仅接受 master 或版本 tag,输入版本须匹配。通过全部门禁后发布同一 tarball,不重建、不执行包脚本;上传前确认版本未占用,发布后核查 latest 并执行默认全局安装验证。
28
31
  - 普通 CI 没有 npm 凭据。发布作业使用 npm Trusted Publisher 和 GitHub OIDC,不读取 `NPM_TOKEN`;并发发布被串行化。
29
32
 
33
+ ### 通过 tag 发布
34
+
35
+ 1. 核对 npm 中目标版本尚未发布。用 `npm version <新版本> --no-git-tag-version --ignore-scripts` 同步包版本和锁文件;完成上述候选验收后,提交并推送到 master。
36
+ 2. 给已验收的提交打版本 tag,并单独推送该 tag:
37
+
38
+ ```bash
39
+ VERSION=$(node -p "require('./package.json').version")
40
+ git tag -a "v$VERSION" -m "Release $VERSION"
41
+ git push origin "v$VERSION"
42
+ ```
43
+
44
+ 普通 master 推送只执行 CI,不发布 npm。不要移动或复用已推送的发布 tag;Git tag `v<版本号>` 触发工作流,npm dist-tag `latest` 决定默认安装版本,两者不同。
45
+
46
+ 包已发布但后续验收失败时,在 Actions 手动选择原版本 tag、填写相同版本并启用 `verify_only`。该模式仍执行验证门禁和公开安装验收,跳过上传;不要直接重跑上传作业。安装验收从本地 tarball 读取版本,`--registry` 模式必须提供 `EXPECTED_VERSION`,工作流会自动传入。
47
+
30
48
  首次启用前,由维护者完成以下配置:
31
- 1. 创建 GitHub Environment **npm**,仅允许 master 部署;按仓库需要配置审核人。工作流中的 environment 名称本身**不自动创建审核保护**。
49
+ 1. 创建 GitHub Environment **npm**,只允许 master 分支及 `v*` tag 部署;按仓库需要配置审核人。用 tag ruleset 限制发布 tag 的创建、更新和删除,仅仓库管理员可绕过。工作流中的 environment 名称本身**不自动创建审核保护**。
32
50
  2. 在 npm 包的 Trusted Publisher 设置中授权 GitHub 仓库 `realqiyan/agent-task`、工作流 `publish.yml`、Environment `npm`,允许 `npm publish`。认证与 2FA 在 npm 官方界面完成,不上传本机登录凭据。
33
- 3. 核查分支保护及工作流修改权限,再在 Actions 选择 Publish npm,输入已验收的版本(本次为 `0.0.1-rc.3`)。认证/权限失败须停止,不能换账号或跳过验证。
51
+ 3. 核查 master 与工作流修改权限,再推送版本 tag;需要手动发起时,在 Actions 选择 Publish npm 并输入已验收的版本。认证/权限失败须停止,不能换账号或跳过验证。
34
52
 
35
53
  发布作业使用 Node 24 与支持 OIDC 的 npm;命令明确传 `--tag latest --access public --provenance`。Trusted Publisher 授权和 provenance 是不同条件,设置工作流不等于 npm 已授权。首次配置和有效期限制以 [npm 官方说明](https://docs.npmjs.com/trusted-publishers/)为准。
36
54
 
@@ -42,11 +60,12 @@ npm run test:install -- ./realqiyan-agent-task-0.0.1-rc.3.tgz
42
60
  npm login --registry=https://registry.npmjs.org
43
61
  npm whoami --registry=https://registry.npmjs.org
44
62
  # 必须确认输出 realqiyan,再发布已检查的 tarball:
45
- npm publish ./realqiyan-agent-task-0.0.1-rc.3.tgz --ignore-scripts \
63
+ VERSION=$(node -p "require('./package.json').version")
64
+ npm publish "./realqiyan-agent-task-$VERSION.tgz" --ignore-scripts \
46
65
  --access public --tag latest --registry=https://registry.npmjs.org
47
- npm view @realqiyan/agent-task@0.0.1-rc.3 version license --registry=https://registry.npmjs.org
66
+ npm view "@realqiyan/agent-task@$VERSION" version license --registry=https://registry.npmjs.org
48
67
  npm view @realqiyan/agent-task dist-tags --json --registry=https://registry.npmjs.org
49
- node scripts/verify-install.mjs --registry
68
+ EXPECTED_VERSION="$VERSION" node scripts/verify-install.mjs --registry
50
69
  ```
51
70
 
52
71
  登录成功不等于发布授权已完成。若 registry 返回需要 2FA 的 E403,停止发布;维护者须在自己的终端完成发布时认证,或配置有目标包发布权限、短有效期且获准 bypass 2FA 的 granular token。不要关闭账号 2FA,不在聊天、命令参数或日志中传递一次性验证码或 token;不把本机登录凭据自动上传到 GitHub。
@@ -12,16 +12,16 @@
12
12
  | Run 与节点状态的业务修改入口、派发与提交顺序 | [TaskRuns](../src/tasks/runs.ts)、[数据模型](../src/tasks/model.ts)、[窄能力契约](../src/tasks/ports.ts) | [tasks.test.mjs](../tests/tasks.test.mjs)、[task-storage.test.mjs](../tests/task-storage.test.mjs) |
13
13
  | 时钟、协调会话监督、取消与收尾 | [RunSupervisor](../src/tasks/supervisor.ts)、[NodeSessions](../src/tasks/sessions.ts) | [tasks.test.mjs](../tests/tasks.test.mjs)、[restart.test.mjs](../tests/restart.test.mjs) |
14
14
  | 人工事实等待与回复 | [纯状态规则](../src/tasks/human-input.ts)、[TaskRuns](../src/tasks/runs.ts) | [human-input.test.mjs](../tests/human-input.test.mjs) |
15
- | 执行端注册、授权比较、凭据隔离 | [ExecutorRegistry](../src/executors/registry.ts)、[环境过滤](../src/executors/environment.ts)、[审批策略](../src/executors/permissions.ts) | [policy.test.mjs](../tests/policy.test.mjs)、[config-preflight.test.mjs](../tests/config-preflight.test.mjs) |
15
+ | 本机执行端目录、准入比较、凭据隔离 | [ExecutorRegistry](../src/executors/registry.ts)、[发现与安装](../src/integrations/acp/discovery.ts)、[环境过滤](../src/executors/environment.ts)、[审批策略](../src/executors/permissions.ts) | [executors.test.mjs](../tests/executors.test.mjs)、[policy.test.mjs](../tests/policy.test.mjs)、[config-preflight.test.mjs](../tests/config-preflight.test.mjs) |
16
16
  | 配置与凭据编辑、发布顺序、影响预览 | [Settings](../src/configuration/settings.ts)、[配置规则](../src/configuration/policy.ts)、[预览组合](../src/configuration/management.ts) | [settings.test.mjs](../tests/settings.test.mjs)、[web.test.mjs](../tests/web.test.mjs) |
17
17
  | 请求规范化、内部数据与严格记录校验 | [任务请求](../src/protocol/task-contract.ts)、[配置请求](../src/protocol/settings-contract.ts)、[内部数据校验](../src/tasks/validation.ts)、[持久记录](../src/tasks/storage/records.ts) | [task-storage.test.mjs](../tests/task-storage.test.mjs) |
18
18
  | 持久读写与事务 | [TaskStore](../src/tasks/storage/store.ts)、[配置文件](../src/configuration/files.ts)、[私有文件操作](../src/infrastructure/private-files.ts) | [task-storage.test.mjs](../tests/task-storage.test.mjs)、[settings.test.mjs](../tests/settings.test.mjs) |
19
19
  | 结果文件授权与文件持久化 | [Results](../src/results/service.ts)、[文件能力](../src/results/ports.ts)、[文件实现](../src/results/files.ts) | [results.test.mjs](../tests/results.test.mjs) |
20
20
  | ACP、worker 与进程协议 | [ACP 连接](../src/integrations/acp/connection.ts)、[worker 监督](../src/integrations/acp/execution.ts)、[worker 入口](../src/integrations/acp/worker.ts)、[命令映射](../src/integrations/acp/runtime.ts) | [execution.test.mjs](../tests/execution.test.mjs)、[tasks.test.mjs](../tests/tasks.test.mjs) |
21
21
  | durable 工具、模型与会话存储 | [协调适配](../src/integrations/coordinator/coordinator.ts)、[provider](../src/integrations/coordinator/provider.ts)、[存储](../src/integrations/coordinator/storage.ts) | [coordinator-provider.test.mjs](../tests/coordinator-provider.test.mjs)、[durable.test.mjs](../tests/durable.test.mjs) |
22
- | MCP、HTTP 与 Web | [MCP 工具](../src/protocol/mcp.ts)、[HTTP 服务](../src/protocol/http/server.ts)、[Web 路由](../src/protocol/http/web.ts)、[页面](../src/web/) | [service.test.mjs](../tests/service.test.mjs)、[web.test.mjs](../tests/web.test.mjs) |
22
+ | MCP、HTTP 与 Web | [MCP 工具](../src/protocol/mcp.ts)、[输出契约](../src/protocol/mcp-contract.ts)、[stdio 接入](../src/protocol/stdio.ts)、[HTTP 服务](../src/protocol/http/server.ts)、[Web 路由](../src/protocol/http/web.ts)、[页面](../src/web/) | [service.test.mjs](../tests/service.test.mjs)、[web.test.mjs](../tests/web.test.mjs) |
23
23
  | CLI 与本机控制协议 | [CLI](../src/protocol/cli/commands.ts)、[管理客户端](../src/protocol/cli/admin-client.ts)、[启动器客户端](../src/integrations/local-service/control.ts) | [web.test.mjs](../tests/web.test.mjs)、[restart.test.mjs](../tests/restart.test.mjs) |
24
- | 装配、启动、关闭与重启 | [main](../src/application/main.ts)、[业务运行实例](../src/application/task-runtime.ts)、[launcher](../src/application/launcher.ts)、[启动准备](../src/application/startup.ts) | [restart.test.mjs](../tests/restart.test.mjs)、[service.test.mjs](../tests/service.test.mjs) |
24
+ | 装配、启动、关闭与重启 | [main](../src/application/main.ts)、[MCP 后台启动](../src/application/mcp-entry.ts)、[业务运行实例](../src/application/task-runtime.ts)、[launcher](../src/application/launcher.ts)、[启动准备](../src/application/startup.ts) | [stdio.test.mjs](../tests/stdio.test.mjs)、[restart.test.mjs](../tests/restart.test.mjs)、[service.test.mjs](../tests/service.test.mjs) |
25
25
  | 安装与发布 | [命令入口](../bin/agent-task.mjs)、[setup](../scripts/setup.mjs)、[安装库](../scripts/install-lib.mjs)、[包门禁](../scripts/pack-release.mjs)、[工作流](../.github/workflows/) | [install.test.mjs](../tests/install.test.mjs)、[setup.test.mjs](../tests/setup.test.mjs)、[发布说明](release.md) |
26
26
 
27
27
  ## 依赖与一致性边界
@@ -42,6 +42,8 @@
42
42
  | 业务 SQLite 与业务服务 | `createTaskRuntime` 创建;关闭先停止业务入口与监督,再关闭存储 |
43
43
  | 协调调用、时钟与取消信号 | `RunSupervisor` 创建并等待其结束;`TaskRuns` 不持有进程或 SDK 对象 |
44
44
  | 节点会话句柄、超时与等待期间的会话 | `NodeSessions` 持有;关闭调用共用同一个完成结果 |
45
+ | 适配器安装进程与安装锁 | `ExecutorRegistry` 管理安装准入与取消,`LocalExecutors` 持有进程和锁;发布后保留旧组件,关闭时等待安装退出 |
46
+ | stdio 接入与共享后台 | `mcp-entry` 连接或启动独立 launcher;stdio 关闭只释放本连接,后台由显式 stop 或服务管理器关闭 |
45
47
  | worker 与 ACP 进程组 | ACP 接入创建与回收;监督器只持有窄会话能力 |
46
48
  | durable storage 与 Harness | 每次协调调用创建;打开失败关闭存储,成功后由 Harness 关闭其存储 |
47
49
  | HTTP listener 与 MCP transport/server | `HttpServer` 持有;请求断开只释放请求资源,应用关闭停止新请求并收尾 |
@@ -1,6 +1,6 @@
1
1
  # 验证导航与证据边界
2
2
 
3
- **模块化重构后,单节点与三节点 DAG 的真实模型 E2E 均一次通过,详见下文复验记录。** 项目不宣称生产可用或外部副作用 exactly-once。
3
+ **当前使用流程简化已通过本地基础测试、适配器安装、独立安装包验收,以及单节点与三节点 DAG 的真实模型复验。** 具体版本、环境和证据见下文。项目不宣称生产可用或外部副作用 exactly-once。
4
4
 
5
5
  ## 本地验证
6
6
 
@@ -12,34 +12,58 @@ git diff --check
12
12
 
13
13
  各职责的测试入口见[代码导航](technical-design.md)。基础测试使用真实本地文件、SQLite、进程和 SDK,不调用外部模型,不使用假模型或模拟 provider。失败进程和 no_model 只证明失败路径;结构化状态用例不证明模型语义判断。`check` 同时执行 TypeScript 与[依赖边界检查](../scripts/check-boundaries.mjs),后者检查模块依赖、循环、SDK 位置和 Run 写入口;它不证明运行时权限或模型语义。
14
14
 
15
- 2026-10-23,Linux x64、Node 24.15.0:模块化重构通过类型与依赖边界检查、42 项基础测试和本地包清单门禁。关键新增证据见 [存储测试](../tests/task-storage.test.mjs)与[任务测试](../tests/tasks.test.mjs):严格记录拒绝而不修复、事务失败回滚触发游标、派发提交先于真实进程执行,以及关闭、取消与迟到回调。临时源码副本中的越层导入、循环依赖和绕过 Run 写入口均被检查器拒绝。
15
+ [MCP 服务测试](../tests/service.test.mjs)还通过真实 HTTP `tools/list` 获取全部工具的输出契约,确认嵌套字段均有校验约束,并用 SDK 的 AJV 校验器验证每个工具的成功和参数错误响应、稳定错误 `code`、业务失败、分页、按状态过滤及紧凑任务/运行列表。反例验证缺失字段、错误类型和矛盾的成功/失败封装被拒绝。契约入口见 [mcp-contract.ts](../src/protocol/mcp-contract.ts)。这不替代原警告客户端的复验;其名称和版本尚未提供。
16
16
 
17
- 本地测试不证明真实模型或 ACP 成功路径;后续真实验收见[模块化重构后复验](#模块化重构后复验)。本次未重新执行跨平台安装验收。
17
+ 2026-10-23,Linux x64、Node 24.15.0:使用流程简化通过类型与依赖边界检查、49 项基础测试和包清单门禁。重点证据:
18
+
19
+ - [stdio 进程测试](../tests/stdio.test.mjs):两个项目并发连接只保留一个后台;目录默认值、显式覆盖及跨项目请求键独立。关闭 stdin 和向客户端进程组发送 SIGHUP 后,后台仍触发未来任务。这些运行因 `no_model` 失败,只证明持续调度与无误派发,不证明 ACP 成功。
20
+ - [MCP 服务测试](../tests/service.test.mjs):没有原生 CLI 时拒绝连接,管理接口可用;安装到已有 PATH 后,下次连接重新发现。直接 HTTP 提交缺少目录时拒绝。
21
+ - [执行端测试](../tests/executors.test.mjs):原生 CLI 与适配器分开检测,禁用不安装,已有安装离线复用;真实失败安装进程不替换已发布组件,关闭时取消等待且不释放其他进程的锁。
22
+ - [初始化 PTY 测试](../tests/setup.test.mjs):目录、端口和令牌须确认,取消不写文件;协调员密钥隐藏输入,生成令牌不输出。初始化不安装执行端。
23
+ - [启动锁测试](../tests/sqlite.test.mjs):四个真实进程同时争用全新锁文件时,只有一个取得所有权;持锁进程强杀后可重新取得锁。修复前曾复现所有启动器同时争锁失败,修复后使用有限的错开重试,不触发任务重放。
24
+ - [存储测试](../tests/task-storage.test.mjs)与[任务测试](../tests/tasks.test.mjs):固定规范工作目录、按目录去重、严格记录拒绝而不修复、事务失败回滚、先持久派发意图再启动真实进程,以及关闭与迟到回调。
25
+
26
+ 当前版本的真实模型证据见 [0.1.0-rc.1 复验](#010-rc1-复验)。本次未运行 macOS 验收。此前模块化重构的 42 项测试及临时源码副本中的依赖违规拒绝实验也已通过,属于本次改造前的证据。
18
27
 
19
28
  ## 控制台验证
20
29
 
21
- [Web/CLI 用例](../tests/web.test.mjs)使用真实本机服务进程验证两端查询与保存的互通、旧草稿拒绝、执行端授权清除、凭据引用保护、离线失败不写文件,以及独立管理员认证、Host/Origin/请求类型边界、有限任务写入、密钥不回显或进入日志。也验证重启后的配置差异和目录切换不复制历史。[重启用例](../tests/restart.test.mjs)验证前台 CLI、固定端口进程更换、绑定失败不能报成功,以及持久化的不确定派发在重复重启后仍被阻断。实际任务记录来自业务服务,不使用假模型输出。
30
+ [Web/CLI 用例](../tests/web.test.mjs)使用真实本机服务进程验证两端查询与保存的互通、旧草稿拒绝、发现状态和禁用策略一致、凭据引用保护、离线失败不写文件,以及独立管理员认证、Host/Origin/请求类型边界、有限任务写入、密钥不回显或进入日志。也验证重启后的配置差异和目录切换不复制历史。[重启用例](../tests/restart.test.mjs)验证前台 CLI、固定端口进程更换、绑定失败不能报成功,以及持久化的不确定派发在重复重启后仍被阻断。实际任务记录来自业务服务,不使用假模型输出。
22
31
 
23
32
  [配置用例](../tests/settings.test.mjs)验证私有文件边界、旧编辑拒绝、显式凭据环境、端点与密钥引用分离、服务令牌别名不能作为模型凭据、失败时保留文件,以及关闭后拒绝操作。这些用例不构成断电、磁盘满或目录同步失败窗口的完整证据。
24
33
 
25
34
  尚未完成真实浏览器交互、CSP 执行和跨浏览器缓存/自动填充验收;CLI 的编辑器交互和隐藏终端凭据输入也未做终端验收,凭据测试使用 stdin。需在浏览器核对:不可信任务文本不执行脚本或加载外链;离开、刷新和退出后无令牌残留;配置草稿不被轮询覆盖;密钥保存与配置保存的提示明确。HTTP 头检查不能替代这些验证,也不证明模型认证或 ACP 执行成功。
26
35
 
27
- ### 启动与注册调整
36
+ ### 执行端与安装包
37
+
38
+ 同日使用隔离 HOME,从 npm registry 真实安装 pi-acp 0.0.34、codex-acp 2.2.2 和 claude-agent-acp 0.94.0,再确认后续准备复用同一安装。报告位于 `/tmp/agent-task-adapter-install-T68wMA/report.json`。没有启动原生 CLI、发送 ACP 会话或调用模型;成功下载与准备不等于认证或任务成功。
28
39
 
29
- Web/CLI 重启证据见下文 [rc.2 发布验收](#001-rc2当前-latest)。四类执行端的固定命令映射和凭据过滤有本地契约测试;Claude ACP 新增注册目标没有真实握手、认证或任务证据。其他执行端的历史结果也不能代替新原生环境和审批策略下的真实复验。
40
+ 由当前源码打包的本地 tarball 通过独立 prefix 安装验收,不依赖源码或 TypeScript。前台启动、Web HTTP 保存、Web/CLI 重启、stdio 自动启动后台、执行端发现、客户端断开后后台健康,以及显式 stop 均通过。使用真实失败程序提供可发现的原生路径,未执行 ACP 或模型工作;捕获输出未发现验证凭据。报告位于 `/tmp/agent-task-npm-LD5GQJ/report.json`。临时目录可能被系统清理,长期证据需安全归档。
41
+
42
+ 当前候选的发布状态见下文;历史包验收不代替当前 macOS、真实宿主应用或四种执行端的模型任务复验。
30
43
 
31
44
  ## 真实模型验收入口
32
45
 
33
46
  仅在获准环境显式运行,会产生模型费用;不使用个人凭据或真实交易:
34
47
 
35
- - 单节点:`npm run test:e2e`。需安全注入 `DEEPSEEK_API_KEY`,并将 `AGENT_TASK_E2E_EXECUTOR` 指向已审核的 ACP profile。执行端须另行准备原生认证及无领域副作用的配置,不继承协调密钥。
36
- - DAG 与人工回复:`npm run test:e2e:human -- --quantity 4`。需已安装 Pi、pi-acp 和获准 DeepSeek 测试凭据;数量由测试客户端提供,不冒充真人回答。
48
+ - 单节点:`npm run test:e2e`。需安全注入 `DEEPSEEK_API_KEY`,并将 `AGENT_TASK_E2E_EXECUTOR` 设为获准的 `pi`、`codex`、`claude` 或 `opencode`。执行端须另行准备原生认证及无领域副作用的配置,不继承协调密钥。连接时准备缺少的适配器。
49
+ - DAG 与人工回复:`npm run test:e2e:human -- --quantity 4`。需已安装 Pi 和获准 DeepSeek 测试凭据;适配器在连接时准备。数量由测试客户端提供,不冒充真人回答。
37
50
  - 真人模式:`npm run test:e2e:human -- --answer-file /absolute/private/path/quantity.txt`。使用新文件,等待旁边的 `.question.json` 出现,再写入答案。
38
51
 
39
52
  完整前置检查、参数和断言见 [E2E 用例](../tests/e2e/)、[Pi 启动器](../scripts/run-pi-human-e2e.mjs)。Pi 启动器为两端共用获准测试密钥,创建独立原生配置,只启用 read;这不是 OS 沙箱或独立账户隔离。强杀或断电不能保证临时认证清理,需管理员核查。
40
53
 
41
54
  运行证据保留在命令输出的私有目录,可能包含敏感内容;不自动删除或将一次成功推广为普遍支持。
42
55
 
56
+ ### 0.1.0-rc.1 复验
57
+
58
+ 2026-10-23,Linux x64、Node 24.15.0,使用已有获准 DeepSeek 测试凭据、`deepseek-flash` 协调员、隔离的只读 Pi 原生配置及连接时安装的 pi-acp 0.0.34。现有单节点和三节点用例各执行一次,均通过;没有修改交付断言或重试任务。
59
+
60
+ - 单节点约 16.3 秒:真实 ACP 交付包含标识和结果 323,一个会话、一轮执行,结果文件持久化通过。证据:`/tmp/agent-task-real-e2e-Igj91J`;Run:`5d4f2b74-eb41-402c-874e-441b1fb29d91`。
61
+ - 三节点约 36.5 秒:测试客户端提供数量 4,结果 1292;同一 Run 等待并接受回复,节点轮数 1 / 2 / 1,已接受的上游不重放,三个交付均保留标识和必需数值。证据:`/tmp/agent-task-real-e2e-oreA3j`;Run:`3e6dd91b-35a5-4038-945c-c9d402d2829f`。
62
+
63
+ 两项测试均在提交任务后断开客户端,再由新连接观察结果。原始测试日志:`/tmp/agent-task-pi-human-6N0Zlj/test-1.log`。服务正常退出,临时原生认证和服务环境文件已清空,任务、会话、结果及验收摘要保留。临时目录可能被系统清理,长期证据需安全归档。
64
+
65
+ 此证据覆盖当前任务契约和适配器准备路径。系统级自启、真实 Pi 宿主退出、模型执行中重启及 Codex、Claude、OpenCode 模型任务未验收;stdio 后台生命周期由本地进程测试覆盖。只读配置不是 OS 沙箱。
66
+
43
67
  ### 本机三节点验收
44
68
 
45
69
  2026-10-22,Linux x64、Node 24.15.0,使用 DeepSeek 协调员和只读 Pi ACP 执行端,此前带 JSON 格式约束的用例运行 `npm run test:e2e:human -- --quantity 4` 一次通过,约 28 秒。数量由测试客户端提供,结果为 1292,不是真人输入。
@@ -98,7 +122,33 @@ Linux x64、Node 24.15.0 的本机记录:
98
122
 
99
123
  ## npm 发布候选验证
100
124
 
101
- ### 0.0.1-rc.2(当前 latest)
125
+ ### 0.1.0-rc.1(已发布)
126
+
127
+ 本候选包含 stdio 共用后台、本机执行端发现与适配器准备、固定任务目录和按目录去重,以及调度周期调整。初始化须确认目录、端口、令牌及协调模型;普通启动不转换旧配置或业务数据。
128
+
129
+ 2026-10-23,Linux x64、Node 24.15.0:锁定依赖重装、类型与依赖边界检查、49 项基础测试、两项真实模型测试、包清单门禁及独立安装验收均通过。真实模型范围见 [0.1.0-rc.1 复验](#010-rc1-复验)。
130
+
131
+ 本地候选包安装报告:`/tmp/agent-task-npm-SxC74r/report.json`。使用独立 prefix 与原生 HOME,不依赖源码或 TypeScript;前台、Web/CLI 重启、stdio 自动启动、断开后后台健康和 stop 均通过。此次依赖下载使用 npm 镜像;发布后的默认安装须另以 npmjs 验证。报告仅把本机 Linux 记为通过,未执行 macOS 验收。发布完成以工作流结果和 registry 核对为准。
132
+
133
+ [GitHub 发布运行 40005739943](https://github.com/realqiyan/agent-task/actions/runs/40005739943)验证提交 `b6d138d`:Node 22.19.0/24.x 检查与 49 项测试、包门禁及 Linux 独立安装全部通过。GitHub OIDC 发布步骤成功,npm 随后提示包正在处理;即时 latest 检查仍读到旧版本,导致该运行最终失败。此失败发生在发布后的校验阶段。
134
+
135
+ 后续匿名 npmjs 核对确认 **[@realqiyan/agent-task@0.1.0-rc.1](https://www.npmjs.com/package/@realqiyan/agent-task/v/0.1.0-rc.1)** 存在、`latest=0.1.0-rc.1`,并包含 GitHub provenance。未指定版本的默认全局安装及前台、Web/CLI、stdio 后台验收通过,报告:`/tmp/agent-task-npm-lTc9FG/report.json`。捕获输出未发现验证凭据,无模型或 ACP 工作。发布后校验现已加入有限等待和 `verify_only` 入口,后续复核无需再次上传同一版本。
136
+
137
+ [仅验证运行 40006683937](https://github.com/realqiyan/agent-task/actions/runs/40006683937)在提交 `3e8e7cd` 上全部通过:Node 22.19.0/24.x 检查和 49 项测试、打包、Linux 独立安装及 npmjs 默认安装复核。该运行跳过发布上传,未重复发布同一版本。
138
+
139
+ ### 0.0.1-rc.3(历史证据)
140
+
141
+ 2026-10-23,[GitHub 发布运行 39980466554](https://github.com/realqiyan/agent-task/actions/runs/39980466554)验证提交 `80b12de`:Node 22.19.0/24.x 类型与依赖检查、基础测试、包清单门禁,以及当前 Linux runner 的独立安装、启动、重启和认证检查均通过。当前发布门禁验证宿主环境;macOS 需在对应环境另行验收。安装报告明确标记其他平台未执行,PTY 用例在缺少终端能力时明确跳过。
142
+
143
+ 发布作业使用 Node 24.21.0、npm 11.19.0 和 GitHub OIDC。包版本检查及 provenance 签名成功,但上传包的 npm PUT 请求返回 E404;发布后的默认安装验证因此未执行。随后 registry 查询未发现 `0.0.1-rc.3`,不能把生成 provenance 当作包已发布。
144
+
145
+ 错误指向 npm 发布授权未生效,需核对该包的 Trusted Publisher 与仓库、工作流、Environment 和允许操作是否匹配。本机凭据读取 trust 设置返回 403,尚未确认具体缺失或不匹配项。GitHub 的 `npm` Environment 已限制为 master;工作流配置与 npm 端授权仍需分别核实,见[发布说明](release.md)。
146
+
147
+ 本机检查与 42 项基础测试通过;独立空工具 PATH 下的真实测试进程确认 PTY 用例明确跳过。发布诊断及已去除下载 URL 查询参数的日志保留于 `/tmp/agent-task-rc3-final-d4tqqpt9`,临时目录可能被系统清理。
148
+
149
+ 2026-10-23 后续匿名 registry 核对确认 `0.0.1-rc.3` 已存在,发布元数据包含 provenance;当时 `latest=0.0.1-rc.3`。上述失败运行是历史记录,不代表后续 registry 状态,也不能单凭元数据判定最终成功发布的操作渠道。
150
+
151
+ ### 0.0.1-rc.2(历史证据)
102
152
 
103
153
  2026-10-22,`realqiyan` 已将 **[@realqiyan/agent-task@0.0.1-rc.2](https://www.npmjs.com/package/@realqiyan/agent-task/v/0.0.1-rc.2)** 发布到 npmjs。匿名 registry 查询确认版本、发布账号、MIT 许可证及 `latest=0.0.1-rc.2`。本机直接发布了下述 CI 已验收的同一 tarball,没有重新构建,也没有 GitHub provenance。
104
154