fix: align hwpod lease guidance

This commit is contained in:
Codex
2026-06-02 21:30:33 +08:00
parent 4f0a983db7
commit bf7a8bfd49
4 changed files with 38 additions and 11 deletions
@@ -24,6 +24,7 @@
- `commitId` 必须是完整 40 字符小写 SHA,不接受 branch、tag、`HEAD` 或短 SHA。
- `workspaceRef` 只描述目标 repo/branch,默认 branch 是 `v0.2`;实际 checkout 身份以 `resourceBundleRef.repoUrl + commitId` 为准。
- 默认 `toolAliases` 会把 `tools/device-pod-cli.mjs` 暴露为 `hwpod`,并把 `tools/unidesk-ssh.mjs` 暴露为 runner shell 内的 `unidesk-ssh` 命令。Device Pod、D601-F103-V2、Keil build/download、job status/output 和 UART/debug-probe 操作必须优先走 `hwpod``unidesk-ssh` 只用于 UniDesk passthrough 任务,不能替代 Device Pod 正式路径。
- Device Pod lease 不是独立 runner 控制命令;标准 `hwpod` surface 只提交命名 Device Pod job。需要 lease 时,token 只能作为 `--lease-token` 跟随实际 mutating job 请求转发给 cloud-api。Agent 不得调用 `hwpod lease ...`,也不得新增 gateway shell 或其他 fallback 来绕过 job authority。
- 默认 `promptRefs` 指向 `internal/agent/prompts/hwlab-v02-runtime.md``inject=thread-start``required=true`。该 prompt 只在 AgentRun/Codex stdio 新 thread 首轮注入;后续 turn 必须依赖原生 `thread/resume`,不得在 command payload 中拼接历史、旧 skill 列表或长业务 prompt。
- 默认 `skillRefs` 指向 `skills/device-pod-cli/SKILL.md``skills/hwlab-agent-runtime/SKILL.md`,都为 `required=true`,由 AgentRun 聚合到当前 workspace `.agents/skills/<name>/SKILL.md`。HWLAB 不再依赖 `/app/skills`、hostPath、默认 Codex skill registry、ConfigMap 或用户长 prompt 作为 skill 注入 fallback。
- AgentRun runtime image 已预装 `gh`,结合 `tool=github` 注入的 `GH_TOKEN` 即可访问 HWLAB/UniDesk PR 与 issue;不得把 GitHub token 放入 prompt 或 `transientEnv`
+6 -11
View File
@@ -1,6 +1,6 @@
---
name: device-pod-cli
description: Use the HWLAB v0.2 internal device-pod CLI from a HWLAB code agent runner to operate authorized Device Pods through cloud-api REST, leases, hwlab-device-pod, gateway, and device-host-cli.
description: Use the HWLAB v0.2 internal device-pod CLI from a HWLAB code agent runner to operate authorized Device Pods through cloud-api REST jobs, hwlab-device-pod, gateway, and device-host-cli.
version: 0.2.0-rest
---
@@ -20,7 +20,7 @@ Canonical AgentRun skill location: `.agents/skills/device-pod-cli/SKILL.md` insi
- The canonical implementation is `tools/device-pod-cli.mjs` from the same ResourceBundleRef commit, exposed through the `hwpod` tool alias.
- All commands emit JSON. A command with no output is a failure.
- Formal v0.2 mode is cloud-api authority: the CLI calls `/v1/device-pods...` REST APIs and must not read `.device-pod/*.json` as the source of truth for gateway session, workspace root, probe UID, UART port, or host CLI.
- Server-side profile, grant, lease, job authority, and profile hash are owned by `hwlab-cloud-api`; `hwlab-device-pod` and `device-host-cli` execute only after cloud-api authorization.
- Server-side profile, grant, job authority, profile hash, and any lease enforcement are owned by `hwlab-cloud-api`; `hwlab-device-pod` and `device-host-cli` execute only after cloud-api authorization.
## Configuration
@@ -62,19 +62,13 @@ hwpod <devicePodId>:workspace:/ bootsharp
For the D601 F103 v2 board, the registered `devicePodId` is `D601-F103-V2`; its server-side profile points to `F:\Work\D601-HWLAB`, Keil project `projects/01_baseline/Projects/MDK-ARM/atk_f103.uvprojx`, target `USART`, `C:\Keil_v5\UV4\UV4.exe`, and UART `COM9` at `115200`.
Diagnose auth, grant, lease, and gateway blockers without touching local profiles:
Diagnose auth, grant, job-authority, and gateway blockers without touching local profiles:
```sh
hwpod doctor --pod-id device-pod-71-freq
```
Acquire and inspect a lease for mutating jobs:
```sh
hwpod lease acquire --pod-id device-pod-71-freq --reason "build smoke"
hwpod lease current --pod-id device-pod-71-freq
hwpod lease release --pod-id device-pod-71-freq --lease-token <lease-token>
```
There is no standalone `hwpod lease acquire/current/release` command in the current v0.2 standard path. Do not preflight a Device Pod task by calling `hwpod lease ...`. When cloud-api requires a lease token, pass the provided token on the actual mutating job; otherwise omit `--lease-token`.
Run read-only workspace, debug, and I/O jobs:
@@ -157,6 +151,7 @@ Do not treat local files such as `.device-pod/device-pod-71-freq.json` or `DEVIC
- If apply-patch fails, read the returned `patchHint`, re-read the current file with `workspace cat` or `workspace rg`, and retry a smaller exact-context hunk before using whole-file write.
- Do not start by calling `/app/tools/hwlab-gateway-tran.mjs`, Windows-side Keil skills, serial-monitor skills, `keil-cli.py`, or generic shell when the Device Pod REST path is available.
- If the CLI returns an auth, grant, lease, executor, or gateway blocker, fix that named blocker in the cloud-api/device-pod path; do not bypass the profile with generic gateway shell.
- If the CLI returns `standalone_lease_command_removed`, use the actual Device Pod job command with `--reason` and optional `--lease-token`; do not call `hwpod lease acquire/current/release` or switch to a fallback transport.
- The server-side profile already carries `hostWorkspaceRoot`, `projectWorkspace`, `debugInterface.uv4Path`, probe UID, UART port, and gateway route. Let `cloud-api -> hwlab-device-pod -> device-host-cli` apply those values.
- Keep I/O selectors as strict path tokens, for example `device-pod-71-freq:io-probe:/uart/1 read`; do not split `/uart/1` across argv.
- Use `--dry-run` to inspect the REST job request without dispatching it.
@@ -169,7 +164,7 @@ Do not upload or recreate runner-side `.device-pod/*.json` as the formal profile
## Safety
- Mutating operations require a human/business reason and may require an active lease. Cloud-api is the enforcement point; the CLI only forwards `reason` and `leaseToken`.
- Mutating operations require a human/business reason and may require a lease token supplied by the cloud-api/business flow. Cloud-api is the enforcement point; the CLI only forwards `reason` and `leaseToken` on the named job request.
- `hwlab-gateway` is transport only. Do not add a generic `cmd` operation to `device-pod-cli`; add a named Device Pod operation instead.
- `SOURCE`, `LOCAL`, `DRY-RUN`, fixture data, and local profile files cannot be reported as `DEV-LIVE` hardware evidence.
+16
View File
@@ -322,6 +322,22 @@ test("device-pod-cli sends reason without extra token for mutating jobs", async
assert.deepEqual(seen[0].body, { intent: "debug.reset", args: {}, reason: "reset smoke" });
});
test("device-pod-cli rejects standalone lease command with standard path guidance", async () => {
let called = false;
const result = await runAssembledDevicePodCli(["lease", "current", "--pod-id", "D601-F103-V2"], {
fetchImpl: async () => {
called = true;
return jsonResponse(500, { ok: false });
},
now: () => "2026-06-02T00:00:00.000Z"
});
assert.equal(result.exitCode, 1);
assert.equal(called, false);
assert.equal(result.payload.error.code, "standalone_lease_command_removed");
assert.match(result.payload.error.message, /Device Pod jobs through cloud-api/);
assert.equal(JSON.stringify(result.payload.error.details.next).includes("hwpod lease acquire/current/release"), true);
});
test("device-pod-cli preserves common v0.1 hardware options in REST job args", async () => {
const seen: any[] = [];
const result = await runAssembledDevicePodCli([
+15
View File
@@ -45,6 +45,7 @@ async function dispatch(target: string, context: any) {
if (target === "health") return health(context);
if (target === "bootsharp") return bootsharpCommand(context);
if (target === "profile") return profileCommand(context);
if (target === "lease" || target === "leases") return removedStandaloneLeaseCommand();
if (target === "job" || target === "jobs") return jobCommand(context);
const selector = parseSelector(target);
if (!selector) throw cliError("invalid_target_selector", `invalid target selector: ${target}`);
@@ -169,6 +170,20 @@ async function profileCommand({ parsed, rest, env, fetchImpl }: any) {
throw cliError("unsupported_profile_command", `unsupported profile command: ${subcommand}`);
}
function removedStandaloneLeaseCommand() {
throw cliError(
"standalone_lease_command_removed",
"standalone hwpod lease commands are not part of the v0.2 standard path; send named Device Pod jobs through cloud-api with --reason and, only when cloud-api requires it, --lease-token",
{
next: [
"Run hwpod bootsharp --pod-id <devicePodId> before operating a pod.",
"Run the actual Device Pod job, for example hwpod <devicePodId>:workspace:/ build start --reason TEXT.",
"Do not call hwpod lease acquire/current/release or switch to a generic gateway shell."
]
}
);
}
async function jobCommand({ parsed, rest, env, fetchImpl }: any) {
const subcommand = rest[0] || "status";
const podId = requiredText(parsed.podId, "podId");