# v0.2 hwlab-cli 短连接 Client 规格

> **Code Agent 操作见 `hwlab-code-agent` skill**（`~/.agents/skills/hwlab-code-agent/SKILL.md`），包含 session 管理、send、trace/result/inspect、steer、Web 等价路径和 auth。以下仅保留架构和行为规范。

`hwlab-cli` 是 v0.2 固定开发目录里的短连接业务 client。它用于让 Codex 和人工在 `G14:/root/hwlab-v02` 直接调用与 Cloud Web 相同的 HTTP API，完成除视觉展示以外的真实业务交互和 E2E 排障。

`hwlab-cli` 不属于常驻服务，不发布镜像，不创建 Kubernetes Service、Deployment、CronJob 或 suspended Job template，不进入 GitOps desired state，不作为 CI/CD artifact 构建对象。CLI 源码变更仍属于 `origin/v0.2` source branch：开发时在 `G14:/root/hwlab-v02` 的独立 worktree 修改并提交，按变更风险运行最小单元测试和 `git diff --check`；推送后 v0.2 CI/CD 只应把它识别为 source-only/CLI-only 变化，复用所有 runtime artifact，不新增 `hwlab-cli` image、TaskRun、Deployment 或 Job。

标准调用入口是直接使用 Bun 运行 TypeScript 入口：`bun tools/hwlab-cli/bin/hwlab-cli.ts client ...`。不要把 `node scripts/run-bun.mjs ...` 作为 v0.2 手动验收入口；该 wrapper 只保留历史兼容价值，曾经在远端交互中输出 wrapper usage 并遮蔽真实 CLI 行为。长期文档、issue 复现步骤和手动验收命令都应使用直接 Bun 入口。

登录鉴权目标见 [spec-v02-auth.md](spec-v02-auth.md)：CLI 必须是一等纯 CLI 体验，默认且唯一从环境变量 `HWLAB_API_KEY` 读取用户 API key，并发送 `Authorization: Bearer hwl_live_...`。`Authorization: Bearer` 是 HTTP 协议 header，不是第二个配置入口；不得支持或新增 `API_KEY`、`HWLAB_BEARER_TOKEN`、`--api-key`、`--bearer-token` 等别名。受保护的 `client request`、`client access`、`client agent`、provider 管理和 workbench 命令不得默认复用 `.state/hwlab-cli/session.json`、profile cookie 或 `client auth login` 产生的 Web session；缺少 API key 时应返回结构化 `api_key_required`，遇到 API key 别名时应返回结构化 `unsupported_api_key_source`，同时在 `auth.requiredAuthMethod=api-key`、`auth.webSessionIgnoredReason=cli_requires_api_key` 和 `client auth status.authBoundary` 中暴露边界。`client auth session --web-session`、`client auth logout --web-session` 和显式 `--cookie`/`HWLAB_SESSION_COOKIE` 只作为浏览器同路径诊断入口；后续目标验收不得要求 CLI 打开浏览器、跳转 Web 或输入 Keycloak 密码。

正式复现和验收必须通过运行时装配解析 endpoint，而不是在命令里手动传 URL。标准环境是 `HWLAB_RUNTIME_NAMESPACE=hwlab-v02`、`HWLAB_RUNTIME_LANE=v02`、`HWLAB_RUNTIME_ENDPOINT_LOCKED=1` 和 `HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME=1`；CLI 输出必须包含 `runtimeEndpoint.source=runtime-namespace`、`runtimeEndpoint.explicitOverride=false` 和解析出的 `baseUrl`。`--base-url`、`--api-base-url`、`HWLAB_CLIENT_BASE_URL` 或等价显式 URL 只允许在本地 debug 且未设置 endpoint locked 时使用；issue 复现、最终验收、Web 等价 CLI、AgentRun runner 和 `hwpod` 都不得靠人工判断 17666/19666/19667。

当前阶段的 Web 等价 CLI 验收默认使用 `admin` 的默认账号 workspace：不要为了避免污染而临时创建测试账号、切换 profile、指定临时 `projectId` 或隔离 workspace。需要清理上下文时直接通过 `client workbench restore/status/reset --confirm` 作用于 admin 默认 workspace，并在 issue 评论记录 reset、traceId、workspace revision 和恢复结果。只有用户明确要求多账号/多 profile 隔离验证，或目标功能本身就是账号隔离/profile 行为时，才使用 `--profile`、新增账号或非默认 `projectId`。

## Code Agent session 手动化

Code Agent session 是显式资源，不再由普通 `client agent send`、Workbench composer、`--from-trace` 或账号 workspace 自动创建、滚动或替换。账号 workspace 只能记录当前显式选中的 session、最近 trace 和展示状态；它不是隐式 session factory。

- 无 Code Agent session 时，必须先显式创建 session，再发送 turn。CLI 目标入口为 `client agent session create`；Web 目标入口为“新建 session”显式动作；Cloud API 目标入口为 `POST /v1/agent/sessions`。session 创建返回 `conversationId/sessionId`，`threadId` 可以在首轮 turn 被 provider/AgentRun 建立后回写。
- `client agent session create|select|status` 的默认 JSON 输出必须在顶层直接暴露 `sessionId`、`conversationId`、`threadId`、`providerProfile`、`sessionStatus` 和 `sessionUsable` 这类短连接脚本高频字段；完整原始响应仍保留在 `session` 或 `body` 中。人工和 agent 不应为了拿 sessionId 手写一次性 JSON 深挖脚本，也不应依赖 `sed`/`grep` 解析 JSON。
- 显式 session 是用户入口的 provider profile authority。`client agent session create --provider-profile <profile>` 创建 session 后，`client agent send --session-id <sessionId>` 在未传 `--provider-profile` 时必须继承该 session 的 `providerProfile`；显式覆盖必须在输出和 trace 中可见。AgentRun dispatch、dynamic profile slug 和 nested child `spawn` env-only 继承的权威规则见 [agentrun-code-agent-dispatch.md](agentrun-code-agent-dispatch.md)。
- `client agent send` 必须携带显式 `--session-id`，或使用此前通过 `client agent session create|select` 明确选中的 workspace session；没有显式或已选 session 时返回结构化 `session_required`，不能自动生成 `conversationId/sessionId/threadId`。
- 显式传入新的 `--conversation-id` 时，如果没有同时显式 `--session-id` 或 `--from-trace` 恢复出的 session，CLI 不得从账号 workspace 继承旧 session；这种情况必须返回 `session_required`，提示先为该 conversation 创建或选择 session。只有显式 conversation 与 workspace 当前 conversation 完全一致时，才允许使用 workspace 中已显式选中的 session。
- session 失败、`thread-resume-failed`、provider continuation 失效、用户取消或运行面中断时，当前 session 必须保留为 failed/stale/canceled 证据；系统不得自动滚动到新 session、不得隐式清理后继续，也不得把下一条普通消息路由到新 session。继续工作前必须显式创建或选择另一个 session。
- `--from-trace` 只用于 inspect 和显式复现 trace 所属 session；如果 trace 所属 session 已失败或 stale，CLI/Web/API 必须返回该失败 session 的证据和“请显式创建新 session”建议，不能自动替换 continuation。
- 最终 CLI 交互验收必须使用 HWLAB CLI 原入口，并按“登录 -> 显式创建或选择 session -> 至少一次 `client agent send --session-id ... --message "在吗?"` 不传 `--provider-profile` -> result/trace”的顺序执行，证明 send 继承显式 session 的 provider profile；MiniMax-M3 验收应先在 `session create` 传 `--provider-profile minimax-m3`。不得用 UniDesk CLI 包装测试，也不得用 fresh auto session 掩盖失败 session 问题。

## 在系统中的职责划分

- 提供 WEB 等价的非视觉业务入口：登录鉴权、显式 Code Agent session 管理、HWPOD node-ops 状态、Admin Access 授权管理、Code Agent 对话、trace/result 轮询、logout 和工作台 live summary。
- 只走 Cloud Web 同源 API surface；正式运行时由 `HWLAB_RUNTIME_*` 装配出当前 lane 的 Web/API endpoint，失败时必须 fail closed，不能静默退回 legacy DEV 入口。
- Web/CLI 路径一致性优先于继续 Web 修复。Cloud Web 暴露 Code Agent、AgentRun、continuation、steer、trace/result 或 provider 问题后，必须先能用 runtime namespace/lane 装配出的 `bun tools/hwlab-cli/bin/hwlab-cli.ts client agent send/result/trace/inspect/steer ...` 对同一 Cloud Web origin、同一 `/v1/agent/chat*`、同一 `conversationId/sessionId/threadId/retryOf` 复现或解释，再继续修 Web 状态机。Cloud API 只用于显式 admin/setup/gateway 诊断，不得替代 WEB 同源路径验收。
- 从 Web trace 回放 Code Agent 问题时，优先用 `client agent inspect --trace-id <traceId>` 读取 Cloud Web 的 `/v1/agent/chat/inspect`，输出 trace 所属 `conversationId/sessionId/threadId`、session 状态和 `retryOf` 建议；`client agent send --from-trace <traceId>` 只能作为显式复现该 trace 所属 session 的入口，不能自动创建、滚动或替换 session。inspect 缺失或 session 已 failed/stale 时，CLI 必须返回结构化 blocker 和显式新建 session 建议。
- 默认业务子命令不直连 Postgres、Kubernetes Service、Secret、内部执行 Service、gateway RPC 或本地 fixture；需要鉴权的请求优先使用 `HWLAB_API_KEY` 生成的 `Authorization: Bearer hwl_live_...`，legacy/debug 才使用 `/auth/*` 返回的 cookie 或显式 `--cookie`。唯一例外是 `client gateway` 诊断族：它使用同一 runtime endpoint resolver 定位 Cloud API，用于短连接观测 gateway session、单次 shell invoke 和 transport 压测；该入口只验证底层传输稳定性，不替代 Web 用户流程授权，也不发布镜像或常驻服务。显式 API URL 只作为 unlocked local debug 入口。
- Pod 内透传执行不放进 `hwlab-cli`；需要进入正在工作的 Code Agent/Cloud API pod 时，`hwlab-cli` 只查询并输出 UniDesk 标准 route，实际透传由 UniDesk `bun scripts/cli.ts ssh 'G14:k3s:hwlab-v02:pod:<pod>:<container>' ...` 完成。`pod:` 是 route 语法，`/` 只用于 pod 内文件系统路径。
- `client runtime routes` 必须按当前运行 profile/lane 的数据生成 UniDesk `pod:` route；实现不得硬编码 `dev`、`v0.2`、`v0.3`、namespace 或 catalog path。新增版本只允许通过 `deploy.yaml.lanes[profile]` 声明 namespace、artifact catalog 和 service overrides，不为每个版本新增代码分支。
- 运行时不做内部证明型校验、旧健康诊断或重断言；CI/CD 只保留能证明代码可构建、语法正确和最小冒烟可用的校验。功能正确性通过 `hwlab-cli client` 短连接真实业务 E2E 暴露和修复。
- 专用子命令覆盖高频用户工作台；`client request METHOD /path` 覆盖 WEB 同源代理允许的其他非视觉 API。`client request` 只接受以 `/` 开头的 Cloud Web 相对路径，禁止绝对 URL，避免绕过 Cloud Web 直接打内部服务。
- `client access ...` 是 Admin Access 页面的同路径 CLI，不直连 OpenFGA，不手动传 OpenFGA token，不把 `19667` Cloud API 当作 Web 等价验收路径。所有授权读写都必须输出 runtimeEndpoint、route、actor、mode、decision 和 effective matrix 摘要。
- `client gateway pressure` 是 gateway/transport 高频故障的真实业务传输压测入口；必须覆盖 small stdout、大 stdout、长单行 stdout、stderr flood、结构化 timeout 和超出 gateway inflight 上限的并发请求。所有场景必须返回 JSON、HTTP/route/traceId/requestId、字节数、truncated 标记、sha256 和 bounded preview；失败必须明确是 `http_*`、`stdout_not_truncated`、`stderr_not_truncated`、`timeout_not_observed`、`structured_gateway_busy` 等可定位原因，禁止无输出、长时间黑洞或只靠 shell pipe 截断。
- 输出默认是 JSON；任何失败都要有 `ok:false`、`action`、`status`、HTTP 状态、route 和可定位错误，不允许无 stdout 成功。可能返回大对象的 `client` 子命令默认返回紧凑摘要，避免高频排障输出爆炸；需要完整响应体时显式加 `--full`。
- `hwpod` 在 AgentRun runner 中是设备 API 标准短入口，必须自动使用装配的 `HWLAB_RUNTIME_API_URL` 直达 `hwlab-cloud-api`，并使用映射到当前 Code Agent session owner 的 `HWLAB_API_KEY`；不能把 Cloud Web 同源代理当作设备 API 通道，也不能手动传 URL 或 session token。HWPOD CLI 默认必须返回紧凑 JSON：保留 action/status/blocker/nodeOps/trace 摘要，省略长输出；需要完整 payload 时显式加 `--full`。Code Agent 和人工不得用 `| head`、`grep` 或 shell 管道作为默认输出压缩方式，避免 stdout pipe、子进程信号转发或长输出造成 commandExecution 黑洞。
- Code Agent 交互必须默认暴露 `traceId`、`resultUrl`、终态和 assistant 回复文本摘要；不能要求用户先拉全量 trace 再手工查找回复。
- CLI 本地登录态必须支持 `--profile NAME` 隔离，同一 base URL 下不同 profile 写入 `.state/hwlab-cli/profiles/<base-url-hash>/<profile>.json`。切换到其他账号再切回原账号时，`client workbench restore/status` 必须从服务端账号 workspace 恢复之前的 `workspaceId`、`conversationId`、`sessionId`、`threadId`、`activeTraceId` 和 revision，而不是只依赖本地文件。
- `client workbench restore/status/watch/reset` 是账号 workspace 的非视觉入口：`restore/status` 对应 `GET /v1/workbench/workspace`，`watch` 对应 `/events?afterRevision=`，`reset --confirm` 对应服务端 reset。输出必须显示 workspace revision、selected conversation/session、active trace 和本地 state file，且不得保存 password、session token 原文以外的 Secret 值。
- `client agent send` 是 Cloud Web Code Agent composer 的非视觉等价入口。它必须支持 `--session-id`、`--thread-id`、`--conversation-id`、`--from-trace` 和 `--retry-of`，并在输出中返回 redacted continuation 摘要。`send` 只能向显式传入或已显式选中的 session 提交 turn；没有 session 时返回 `session_required`，session failed/stale 时返回 `session_not_usable`，不能隐式创建或滚动 session。浏览器 issue 中已经给出 traceId 时，复现命令先 `inspect`，再由用户显式确认要复现原 session 或创建新 session。
- `client agent send --from-trace` 只能用 inspect 恢复 `conversationId/sessionId/threadId/retryOf` 和提交本轮原始消息；不得把 inspect 的 messages/facts 作为 `conversationContext`、`messages` 或 prompt 前缀提交。CLI 的 continuation 摘要只用于可见性，不是模型上下文。
- `client agent composer status|submit` 是 Cloud Web composer 的状态机等价入口。`status` 必须先恢复账号 workspace，再输出 `sessionRequired`、`sessionUsable`、`submitMode`、`route`、`targetTraceId`、conversation/session/thread 和 workspace revision；没有已选 session 时必须显示 `sessionRequired=true`。`submit` 只能在已显式选中可用 session 时提交 turn；运行中 trace 的 steer 仍走同源 `/v1/agent/chat/steer`，但不能借 steer/turn policy 自动创建或滚动 session。
- Code Agent continuation 的 thread 字段只有 `threadId` 一个标准名称。CLI 读取 inspect、`--from-trace` 回放、手动 `--thread-id` 提交和输出摘要都必须以该字段为唯一 thread identity；服务端响应也应保持同一字段口径。
- `client agent send` 可以恢复账号 workspace 来读取“已显式选中”的 session，但 workspace 只代表 selection，不代表自动创建或自动恢复。`send` 只发送该 session 的 `conversationId/sessionId/threadId`、`workspaceId` 和 `expectedWorkspaceRevision`；终态轮询后 PATCH workspace 只能更新 session 状态、active trace 和 evidence。默认 workspace 恢复不恢复 messages/facts，不生成 `conversationContext`，也不得把历史文本拼入 prompt。显式传入新的 `--conversation-id` 不能隐式继承旧 session/thread，CLI 层应在发出 `/v1/agent/chat` 前返回 `session_required`；需要新 session 时必须先 `client agent session create --conversation-id <ID>`。
- 架构混乱排查时，CLI 输出必须把 `sessionId`、`conversationId`、`threadId`、`providerProfile`、`runtimeEndpoint`、`traceId`、`runId`、`commandId` 和 `jobName` 分开显示。临时处理以显式 session status、AgentRun run/job env、`SessionRef` 和 PVC phase 为证据；长期收敛见 [agentrun-code-agent-dispatch.md](agentrun-code-agent-dispatch.md) 的会话和执行边界。
- `client agent steer <traceId>` 是运行中引导入口，必须调用 Cloud Web 同源 `POST /v1/agent/chat/steer`，把 steer 文本装配成 AgentRun `type=steer` command 作用到目标 trace 的 active turn。CLI 不手动穿内部 URL；验收使用当前 runtime namespace/lane 自动解析的 `19666` Web 入口，并通过原 trace 的 result/trace 观察 steer 是否被 runner 接收和应用。
- `client agent steer` 的成功输出必须适合 issue closeout 直接审计：顶层或 compact body 中必须暴露 HTTP 202、`request.elapsedMs`、route、`traceId`、`steerTraceId`、`accepted=true`、`shortConnection=true`、`agentRun.runId`、`agentRun.targetCommandId` 和 `agentRun.steerCommandId`。该命令默认不等待原 trace terminal；后续用 `client agent result <traceId>` 和 `client agent trace <traceId> --render web` 验证目标 trace 中的 steer events。目标 turn 后续 provider/backend terminal failure 是另一类终态，不能倒推为 steer POST 短请求失败。
- `client agent trace <traceId> --render web` 必须调用 Cloud Web trace row 的同一纯转换路径，输出 `render="web"`、renderer 标识、source event count、rendered row count、默认压制的 noise event count 和 row 摘要。浏览器 trace 展示错乱时，必须先用该 CLI 入口确认 Web 渲染转换是否已经乱序、重复、缺 final response、吞掉关键 row 或只显示泛化 tool call，再继续修浏览器 DOM/CSS。
- AgentRun v0.1 短连接 runner 已要求支持同 run/runner 多轮 command。CLI 仍应把 Web 提交的 `conversationId/sessionId/threadId` 原样送到 Cloud Web API，用于验证 adapter 是否在 runner reuse window 有效时复用同一个 AgentRun `runId` / `jobName` 并创建新 `commandId`；每轮都新建 runner 或重新 bundle 不是通过状态，trace 中的原因说明只能用于定位。
- `client harness`、`client harness-ops` 和 `client harness-opt` 吸收 G14 harness-ops 的短连接业务能力：health、submit、result、trace、wait 和 audit。
- harness 系列命令只调用 Cloud Web/Code Agent 同源 API，不创建镜像、Job、常驻服务，也不执行 hot-sync、kubectl cp 或硬编码 namespace/pod 的运行面写路径。
- 旧 `hwlab-cli cicd`、fixture MVP gate 和 CLI 镜像/Job 口径属于废弃路径；开发中遇到这些旧门禁、旧测试或旧预检时直接删除，不再维护兼容。

## 内部架构

- `tools/hwlab-cli/bin/hwlab-cli.ts` 是唯一可执行入口，使用 Bun 运行。
- `tools/src/hwlab-cli-lib.ts` 承载参数解析、cookie jar、HTTP 请求、轮询和 JSON 输出。
- `tools/hwlab-cli/bin/hwlab-cli.mjs` 只允许作为兼容 shim 调用 Bun TS 入口；新功能不得继续写入 `.mjs` 旧库。
- 目标认证状态只来自 `HWLAB_API_KEY` 环境变量；CLI 不默认把用户 API key 写入 `.state/hwlab-cli/session.json`，也不接受 API key 环境变量或 flag 别名。本地状态只保存 base URL、cookie、actor 摘要和过期时间，不保存 password、完整 API key 或 Secret 原文。
- 所有 `client` 子命令都是短连接；长耗时 Code Agent 只提交 async request 并短轮询 result/trace，单次命令必须有 timeout 和中间状态输出。

## API 接口说明

| CLI 接口 | WEB 等价 API | 说明 |
| --- | --- | --- |
| `hwlab-cli client auth status` | 本地 env + `GET /v1/users/me` | 显示 runtime endpoint、是否检测到 `HWLAB_API_KEY`、key prefix 和当前 actor 摘要；不得输出完整 key。 |
| `hwlab-cli client auth whoami` | `GET /v1/users/me` | 使用 `HWLAB_API_KEY` 恢复当前 actor/AuthPrincipal；纯 CLI，无浏览器跳转。 |
| `hwlab-cli client auth session` | `GET /auth/session` | Web session debug。 |
| `hwlab-cli client auth profiles` | 本地状态读取 | 列出同一 base URL 下的本地 profile state，用于账号切换可见性。 |
| `hwlab-cli client auth logout` | `POST /auth/logout` | 撤销 server session 并清理本地 cookie。 |
| `hwlab-cli client access summary` | `GET /v1/admin/access/summary` | Admin Access 总览，显示 OpenFGA mode/readiness/store/model、用户/tool 数量和 mismatch 摘要。 |
| `hwlab-cli client access users list` | `GET /v1/admin/access/users` | 列出用户、role/status、Keycloak 绑定摘要和 effective capability 摘要。 |
| `hwlab-cli client access users inspect USER` | `GET /v1/admin/access/users/{userId}` | 查看单个用户的 agent session 和 tool 权限矩阵。 |
| `hwlab-cli client access users set-role USER --role admin|user` | `PATCH /v1/admin/access/users/{userId}` | 更新用户 role/status，并同步 OpenFGA admin tuple。 |
| `hwlab-cli client access tools grant/revoke USER TOOL` | `PUT/DELETE /v1/admin/access/users/{userId}/tools/{toolId}/can-use` | 授予或撤销 `hwpod`、`unidesk_ssh`、`trans_cmd`、GitHub 写工具等 capability。 |
| `hwlab-cli client access check --user USER --relation REL --object OBJECT` | `POST /v1/admin/access/check` | 管理员调试单次 authorization check，输出 decision 和 redacted actor/object。 |
| `hwlab-cli client provider-profiles list` | `GET /v1/admin/provider-profiles` | 管理页的非视觉状态入口；输出 actor、profile、SecretRef、resourceVersion、hash 后缀和最近验证结果，不输出 API Key 或 Secret data。 |
| `hwlab-cli client provider-profiles config PROFILE` | `GET /v1/admin/provider-profiles/{profile}/config` | 显式读取 AgentRun profile config 文本；不输出 credential value。 |
| `hwlab-cli client provider-profiles set-config PROFILE --config-file FILE` | `PUT /v1/admin/provider-profiles/{profile}/config` | 写入 AgentRun profile config；新增动态 slug 不要求修改 Cloud API/Web 静态枚举。 |
| `hwlab-cli client provider-profiles remove PROFILE` | `DELETE /v1/admin/provider-profiles/{profile}` | 删除遗留 provider profile；Cloud API 鉴权后委托 AgentRun 删除对应 Secret/配置，内建 profile capability 保留、动态 slug 从列表消失。 |
| `hwlab-cli client provider-profiles set-key PROFILE --key-stdin` | `PUT /v1/admin/provider-profiles/{profile}/credential` | 从 stdin 写入 provider API Key，Cloud API 鉴权后委托 AgentRun；默认只输出 resourceVersion/hash 后缀和 failureKind。 |
| `hwlab-cli client provider-profiles validate PROFILE --wait` | `POST /v1/admin/provider-profiles/{profile}/validate` + `GET /validations/{id}` | 触发 provider canary 并短连接轮询，输出 validationId、runId、commandId、jobName、traceId、status、failureKind 和 redacted bridge 摘要。 |
| `hwlab-cli client request POST /v1/hwpod-node-ops` | `POST /v1/hwpod-node-ops` | HWPOD node-ops 同路径 smoke；Code Agent 侧正式业务入口仍是 `hwpod`，由 `hwpod-compiler-cli` 生成 node-ops。 |
| `hwlab-cli client runtime routes` | `GET /v1/live-builds` | 查询当前工作面 pod，并输出 UniDesk 标准 `pod:` route；不执行透传、不调用 kubectl、不内嵌 UniDesk。 |
| `hwlab-cli client gateway sessions` | `GET Cloud API /v1/gateway/sessions` | 显式 Cloud API 诊断入口，观察 gateway online/stale、inflight 和 capability；默认不带 Web cookie。 |
| `hwlab-cli client gateway invoke` | `POST Cloud API /v1/rpc/hardware.invoke.shell` | 显式 Cloud API 诊断入口，执行一次 bounded shell dispatch 并返回结构化 dispatch 摘要。 |
| `hwlab-cli client gateway pressure` | `POST Cloud API /v1/rpc/hardware.invoke.shell` | 显式 Cloud API 压测入口，真实验证大输出、长单行、stderr、timeout 和并发超容量不会造成黑洞。 |
| `hwlab-cli client agent session create|select|status|list` | `POST/GET/PATCH /v1/agent/sessions*` + `GET/PATCH /v1/workbench/workspace*` | 显式创建、选择和观察 Code Agent session；session 创建或选择是 `send` 前置条件。 |
| `hwlab-cli client session final-response CONVERSATION_ID` | `GET /v1/agent/conversations/{conversation}` + `GET /v1/agent/conversations?projectId=...` + `GET /v1/agent/chat/result/{trace}` | 持久化 final response 展示回归的低噪声 closeout 验证入口；先 inspect 自动发现正确 `projectId`，再用 list/inspect/result 对齐 latest agent text、`lastTraceId` 和旧 fallback 缺失状态。 |
| `hwlab-cli client agent send` | `GET /v1/agent/chat/inspect` + `POST /v1/agent/chat` + `GET /result/{trace}` | 以 short connection 向显式 session 提交 Code Agent turn 并轮询结果，默认输出 assistant 回复文本摘要；支持 `--from-trace` 显式复现 Web continuation，但不自动创建或滚动 session。 |
| `hwlab-cli client agent composer status|submit` | `GET /v1/workbench/workspace` + `POST /v1/agent/chat` 或 `POST /v1/agent/chat/steer` | 使用 Web 共享 composer policy 探测输入框锁定状态和 turn/steer 分流；运行中应显示无锁 steer，并自动提交 steer。 |
| `hwlab-cli client agent trace TRACE [--render web]` | `GET /v1/agent/chat/trace/{trace}` | 回放 trace，默认输出状态、事件摘要和 assistant stream 文本；`--render web` 复用 Cloud Web trace row 转换，便于 CLI 复现 Web trace 渲染问题。 |
| `hwlab-cli client agent steer TRACE` | `POST /v1/agent/chat/steer` | 对目标 trace 的运行中 Code Agent turn 发送 steer 文本；默认短连接返回 HTTP 202、request elapsed、accepted、steerTraceId 和 steer command 摘要，后续观察原 trace 的 result/trace。 |
| `hwlab-cli client agent cancel TRACE` | `POST /v1/agent/chat/cancel` | 取消当前 Code Agent 请求。 |
| `hwlab-cli client harness submit` | `POST /v1/agent/chat` | G14 harness-ops 的短连接提交入口，默认 provider profile 为 `deepseek`，返回 trace/result URL；`harness-ops` 和 `harness-opt` 是同义别名。 |
| `hwlab-cli client harness wait/result/trace` | `GET /v1/agent/chat/result/{trace}`、`GET /trace/{trace}` | 轮询或读取一次 Code Agent 结果和 trace；单次 wait 最长 60 秒。 |
| `hwlab-cli client harness audit` | `GET /v1/agent/chat/trace/{trace}` 或本地 trace file | 只输出工具摩擦信号，辅助发现应补的主 CLI/HWPOD 操作；不是运行时 gate。 |
| `hwlab-cli client workbench summary` | `/health/live`、`/v1`、`/v1/live-builds`、`/v1/hwpod-node-ops` | 汇总 Cloud Workbench 非视觉功能面。 |
| `hwlab-cli client workbench restore/status/watch/reset` | `GET/PATCH /v1/workbench/workspace*` | 恢复、观察或重置账号级共享 workspace，支持 Web/CLI 和多 profile 共享同一账号状态。 |
| `hwlab-cli client rpc METHOD [--full]` | `POST /json-rpc` | 像 Web `callRpc` 一样自动生成 `id`、`traceId` 和 `meta`，覆盖 `system.health`、`cloud.adapter.describe` 等 JSON-RPC 非视觉能力。 |
| `hwlab-cli client request METHOD /path [--full]` | Cloud Web 同源相对路径 | 覆盖 `/v1/access/status`、`/v1/setup/status`、`/v1/diagnostics/gate`、`/v1/m3/status`、`/v1/m3/io` 等低频或新增 WEB API；`/json-rpc` 优先使用 `client rpc`。 |
| `hwlab-cli client request GET /v1/web-performance/summary [--full]` | `GET /v1/web-performance/summary` | 性能监控页同路径非视觉验收入口；输出 WebUI RUM 样本、慢 API route p95、Web Vitals、long task 和问题队列摘要，不访问 Prometheus 公网地址，不读取 `/metrics` 原始文本。 |

`client` 之外的历史命令不作为 v0.2 验收入口。保留旧命令时只能返回废弃说明或转向 `client`，不得把 fixture 或 dry-run 结果当作 WEB 功能通过证据。

## 测试规格

## T1

阅读 docs/reference/spec-v02-hwlab-cli.md 和 docs/reference/spec-v02-auth.md，然后在 `G14:/root/hwlab-v02` 或当前 v0.2 worktree 用 cli 手动测试以下内容：先设置 `HWLAB_RUNTIME_NAMESPACE=hwlab-v02 HWLAB_RUNTIME_LANE=v02 HWLAB_RUNTIME_ENDPOINT_LOCKED=1 HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME=1 HWLAB_API_KEY=<用户API_KEY>`，再运行 `bun tools/hwlab-cli/bin/hwlab-cli.ts client auth whoami`，确认返回 JSON、HTTP 200、当前 actor 摘要、`authMethod=api-key`、`runtimeEndpoint.source=runtime-namespace` 和 `runtimeEndpoint.explicitOverride=false`，输出不包含完整 API key、password 或 Secret 原文。随后去掉 `HWLAB_API_KEY` 运行 `client request GET /v1/users/me`，即使本地存在 Web session state，也必须返回 `api_key_required`，不得自动登录或发送 cookie。最后设置任意 API key 别名或传入 API key flag，必须返回 `unsupported_api_key_source`，不能发送请求。

## T2

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 用 cli 手动测试以下内容：在 runtime endpoint locked 环境下运行 `client auth session`、`client request POST /v1/hwpod-node-ops --body '{"contractVersion":"hwpod-node-ops-v1","plan":{"steps":[{"op":"node.health"}]}}'` 和 `client workbench summary`，确认全部由 runtime namespace 解析到 Cloud Web 同源 API，未登录时返回认证 blocker，登录后返回真实 HWPOD node-ops payload，不读取本地 fixture，也不需要手动传 URL。

## T3

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 用 cli 手动测试以下内容：先运行 `client agent session create --provider-profile dsflash-go` 显式创建 session，再运行 `client agent send --session-id <sessionId> --message "在吗?" --wait --timeout-ms 120000`，确认 send 未传 `--provider-profile` 也继承 session 的 `providerProfile=dsflash-go`，响应包含 accepted/result/trace 信息、真实 `deepseek-v4-flash` 模型和 assistant 回复文本。未先创建或选择 session 时，`client agent send --message "在吗?"` 必须返回结构化 `session_required`，不能自动创建 session。Nested child `spawn` 继承验收见 [agentrun-code-agent-dispatch.md](agentrun-code-agent-dispatch.md)。

## T3.1

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 用 cli 手动测试以下内容：对一个来自 Cloud Web 的失败 trace 先运行 `client agent inspect --trace-id <traceId>`，确认 CLI 访问 `/v1/agent/chat/inspect?traceId=<traceId>` 并输出 trace 所属 `conversationId/sessionId/threadId/retryOf`、session 状态和 redacted continuation。若该 session 为 failed/stale，再运行 `client agent send --from-trace <traceId> --message "重试上一条" --provider-profile minimax-m3` 必须返回 `session_not_usable` 或等价 blocker，并提示显式创建新 session；不得自动滚动到新 session，也不得输出 cookie、token 或 secret 原文。

## T5.1

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 用 cli 手动测试以下内容：复测取消后追问场景时，必须继续使用同一个显式 session；`client agent send/result/trace --render web` 输出只允许出现标准 `threadId`，不允许出现历史 thread 别名字段；第二轮必须是新 `commandId` 且 trace row 不包含上一 command 的尾部 assistant/tool/terminal 文本。取消后的 session 若被标记 failed/stale，则不能自动滚动，必须先显式创建新 session。

## T3A

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 用 cli 手动测试以下内容：在 runtime endpoint locked 环境下分别用 `--profile admin-a` 和 `--profile admin-a-second` 登录同一个账号，运行 `client workbench restore/status`，确认两个 profile 看到相同 `workspaceId` 和 revision；再用 `--profile other-user` 登录另一个账号，确认 workspace 不同；最后切回 `admin-a`，确认原 workspace、conversation/session/thread 仍能恢复。该验收必须使用真实 runtime namespace/lane 自动解析入口，不能 mock，不能手动传 URL。

## T3.2

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 用 cli 手动测试以下内容：对一个来自 Cloud Web 的真实 trace 运行 `client agent trace <traceId> --render web --limit 80`，确认输出 `renderer=web/hwlab-cloud-web/app-trace:traceDisplayRows`、source event count、rendered row count 和 row 摘要；如果 Web trace 展示错乱，应先用该命令复现并定位到 Web row 转换还是浏览器 DOM/CSS 层。

## T3.3

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 用 cli 手动测试以下内容：在 runtime endpoint locked 环境下先显式创建 Code Agent session，再运行 `client agent send --session-id <sessionId> --message "执行一个会持续运行的任务，等待后续 steer" --provider-profile minimax-m3` 获得运行中 trace；随后运行 `client agent steer <traceId> --message "请把最终回复包含 STEER_ACCEPTED 标记"`，确认 steer 命令本身短连接返回 HTTP 202、`request.elapsedMs`、`accepted=true`、`shortConnection=true` 和 `agentRun.steerCommandId`；最后用 `client agent result <traceId>` 和 `client agent trace <traceId> --render web` 确认同一 target trace 出现 `agentrun:steer:accepted` 和 `agentrun:steer:command-created`。该验收必须使用 runtime namespace/lane 自动解析出的同源 Web 入口，不能 mock，也不能用自动交互脚本，不能手动传 URL；若目标 turn 后续 provider/backend 失败，必须单独记录为目标 turn 终态，不得记为 steer 短请求失败。

## T3.4

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 用 cli 手动测试以下内容：未选择 session 时运行 `client agent composer status` 必须显示 `sessionRequired=true`；显式创建 session 并启动真实运行中的 Code Agent turn 后，再运行 `client agent composer status`，确认输出当前 `sessionId`、`submitMode=steer`、`composer.route=/v1/agent/chat/steer`、`composer.targetTraceId=<运行中 trace>`；随后运行 `client agent composer submit --message "请在最终回复或 trace 中体现 COMPOSER_STEER_OK"`，确认请求走 Cloud Web 同源 `/v1/agent/chat/steer`，最后用原 trace 的 `client agent result` 或 `client agent trace --render web` 验证 steer 可见。该验收必须使用 runtime namespace/lane 自动解析入口，不能手动传 URL、不能 mock、不能用自动交互脚本。

## T4

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 用 cli 手动测试以下内容：运行 `client request GET /v1/access/status`、`client request GET /v1/diagnostics/gate` 和 `client rpc system.health`，确认它们全部走 `19666` Cloud Web 同源 API，返回 JSON route/httpStatus/body，且 `client request` 传入绝对 URL 会被拒绝。

## T5

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 用 cli 手动测试以下内容：运行 `client harness health`、`client harness submit --message "你好" --provider-profile dsflash-go --timeout-ms 120000`、`client harness wait <traceId>` 和 `client harness audit <traceId>`。确认它们全部是短连接 JSON 输出，不创建镜像、Job、CronJob、Deployment 或 hot-sync 写路径。

## T6

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 用 cli 手动测试以下内容：在 runtime endpoint locked 环境下让 Code Agent 执行 `hwpod inspect` 或等价只读 HWPOD 命令，确认 `hwpod` 自动定位当前 lane 的 Cloud API，先调用 `hwpod-compiler-cli` 生成 `hwpod-node-ops-v1` plan，再由 Cloud API 转发到 `hwpod-node` 执行；trace 中 commandExecution 必须完成，默认输出为紧凑 JSON，不需要 `| head`，也不需要手动传 URL。

## T7

阅读 docs/reference/spec-v02-hwlab-cli.md，然后在 `G14:/root/hwlab-v02` 或当前 v0.2 worktree 用 cli 手动测试以下内容：在 runtime endpoint locked 环境下运行 `bun tools/hwlab-cli/bin/hwlab-cli.ts client gateway pressure --gateway-session-id gws_D601_F103 --large-bytes 131072 --parallel 8 --request-timeout-ms 60000 --timeout-scenario-ms 1000 --no-auth --full`。确认 gateway CLI 自动定位当前 lane 的 Cloud API；small stdout、大 stdout、长单行 stdout、stderr flood、timeout 和并发超容量全部返回结构化 JSON；大输出应显示 `stdoutBytes` 或 `stderrBytes`、`stdoutTruncated` 或 `stderrTruncated`、sha256 和 preview，超出 `maxInflightRequests` 的请求必须显示 `structured_gateway_busy`，不能出现无输出或卡死。

## T8

阅读 docs/reference/spec-v02-hwlab-cli.md 和 docs/reference/spec-v02-openfga-authorization.md，然后在 runtime endpoint locked 环境下运行 `client access summary`、`client access users list`、`client access users inspect <user>`、`client access tools grant/revoke ...` 和 `client access check ...`。确认所有命令都走 Cloud Web 同源 `19666` path，输出 JSON、route、actor、OpenFGA mode/decision 和 effective matrix，不输出 OpenFGA token、完整 API key 或 Secret 值。

## T9

阅读 docs/reference/spec-v02-provider-management.md，然后在 runtime endpoint locked 环境下运行 `client provider-profiles list`、`client provider-profiles config dsflash-go`、`client provider-profiles set-config dsflash-go --config-file <config.toml>`、`client provider-profiles set-key dsflash-go --key-stdin` 和 `client provider-profiles validate dsflash-go --wait --timeout-ms 120000`。确认全部走 Cloud Web 同源 `19666` path，先由 HWLAB 鉴权再委托 AgentRun，输出 validationId/runId/commandId/jobName/traceId/resourceVersion/hash 后缀，不输出完整 API Key、Codex auth.json、Kubernetes Secret data 或 Authorization header；显式读取的 config 不得包含 credential value。

## 规格的实现情况

| 规格项 | 状态 | 说明 |
| --- | --- | --- |
| 固定 repo 短连接 client | 目标状态 | `hwlab-cli` 在 `G14:/root/hwlab-v02` 或当前 v0.2 worktree 直接用 Bun 运行，不作为 runtime service。 |
| WEB 等价 API client | 目标状态 | `client` 子命令覆盖 Cloud Web 非视觉业务面。 |
| Admin Access 同路径 CLI | 目标状态 | `client access ...` 覆盖 OpenFGA summary、user matrix、grant/revoke、tool capability 和 check，必须走 Cloud Web 同源 path。 |
| Provider profile 管理同路径 CLI | 已实现 | `client provider-profiles ...` 覆盖管理页状态、API Key 写入和 canary 验证，必须走 Cloud Web 同源 path 并委托 AgentRun。 |
| 显式 Code Agent session 管理 | 目标状态 | `client agent session create|select|status|list` 是 `send` 前置；普通 `send` 不自动创建或滚动 session。 |
| WEB composer 状态机等价 | 目标状态 | `client agent composer status|submit` 复用 Web composer policy，但必须显示 sessionRequired/sessionUsable，不能自动创建或滚动 session。 |
| JSON-RPC 同源 API | 目标状态 | `client rpc` 自动补齐 Web JSON-RPC envelope 的 `meta` 字段。 |
| 通用同源 API request | 目标状态 | `client request` 用于追平低频和新增 WEB API，禁止绝对 URL。 |
| G14 harness-ops 短连接能力 | 目标状态 | `client harness` / `client harness-ops` / `client harness-opt` 覆盖 submit/result/trace/wait/audit，只作为业务 API client。 |
| Gateway transport 压测 | 已实现 | `client gateway pressure` 只作为显式短连接诊断入口，覆盖大输出、timeout 和并发超容量的结构化返回。 |
| HWPOD CLI 紧凑输出 | 已实现 | `hwpod` 默认输出紧凑 JSON，包含 action/status/compilerInvocation/route/result 摘要，防止 Code Agent 通过 shell pipe 压输出。 |
| 用户 API key 登录 | 目标状态 | `HWLAB_API_KEY` 是 CLI 一等登录入口；完整 key 不写入默认输出或本地 state。 |
| 本地 cookie session | Legacy | `.state/hwlab-cli/session.json` 只作为现有 cookie/session 兼容，不再作为目标一等 CLI 登录体验。 |
| 账号 profile 与共享 workspace | 已实现 | `--profile` 隔离本地登录态，`client workbench` 通过服务端 `account_workspaces` 恢复同账号共享 workspace。 |
| 镜像/Service/Job template | 已废弃 | 相关 deploy、GitOps、artifact 和 Tekton 口径必须删除。 |
| PR/CI/CD/worktree 流程 | 已废弃 | CLI 变更不走常驻服务发布流程。 |
