Files
pikasTech-HWLAB/skills/device-pod-cli/SKILL.md
T
2026-05-31 05:07:16 +08:00

12 KiB

name, description, version
name description version
device-pod-cli 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. 0.2.0-rest

Device Pod CLI

Skill(cli-spec)

Scope: this skill is only for HWLAB-internal code agent runners inside the HWLAB runtime, such as /workspace/hwlab sessions running from the G14 DEV, PROD, or v0.2 images. It does not apply to external UniDesk developer workspaces or third-party machines.

Use this skill when the task mentions device-pod-cli, device-pod, device-host-cli, Keil build/download through a Device Pod, debug probe control, workspace operations, or I/O probe reads such as UART boot logs.

Canonical skill location: /app/skills/device-pod-cli/SKILL.md. Do not create duplicate skill copies under /root/.agents/skills, /home/ubuntu/.agents/skills, or /workspace/hwlab/skills; those locations cause stale instructions.

Runtime Contract

  • The stable runner entrypoint is node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs.
  • The canonical implementation is /app/tools/device-pod-cli.ts; /app/tools/device-pod-cli.mjs and the skill script are compatibility wrappers that launch the Bun+TypeScript CLI.
  • 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.

Configuration

Pass the API base URL with one of these sources:

--api-base-url http://hwlab-cloud-api.hwlab-v02.svc.cluster.local:6667
HWLAB_DEVICE_POD_API_URL=http://hwlab-cloud-api.hwlab-v02.svc.cluster.local:6667
HWLAB_CLOUD_API_URL=http://hwlab-cloud-api.hwlab-v02.svc.cluster.local:6667
HWLAB_CLI_ENDPOINT=http://74.48.78.17:19667

Pass authentication with one of these sources:

--session-token <token>
--cookie 'hwlab_session=<token>'
--bearer-token <token>
HWLAB_DEVICE_POD_SESSION_TOKEN=<token>
HWLAB_CLOUD_API_SESSION_TOKEN=<token>
HWLAB_SESSION_TOKEN=<token>
HWLAB_SESSION_COOKIE='hwlab_session=<token>'

Use login only when a username/password credential is explicitly available:

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs login --api-base-url <url> --username <user> --password <password>

The setCookie value in the JSON output can be passed back as --cookie or HWLAB_SESSION_COOKIE.

Primary Commands

List visible Device Pods through cloud-api authority:

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs profile list --api-base-url <url> --session-token <token>

Show one visible Device Pod status and redacted server profile summary:

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs profile show --pod-id device-pod-71-freq --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs health --pod-id device-pod-71-freq --api-base-url <url> --session-token <token>

Diagnose auth, grant, lease, and gateway blockers without touching local profiles:

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs doctor --pod-id device-pod-71-freq --api-base-url <url> --session-token <token>

Acquire and inspect a lease for mutating jobs:

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs lease acquire --pod-id device-pod-71-freq --reason "build smoke" --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs lease current --pod-id device-pod-71-freq --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs lease release --pod-id device-pod-71-freq --lease-token <lease-token> --api-base-url <url> --session-token <token>

Run read-only workspace, debug, and I/O jobs:

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ ls --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/src rg main --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:debug-probe chip-id --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:io-probe:/uart/1 read --duration-ms 5000 --api-base-url <url> --session-token <token>

Run mutating jobs only with reason and lease token when required by cloud-api:

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs \
  device-pod-71-freq:workspace:/ apply-patch \
  --reason "DEV edit" --lease-token <lease-token> \
  --api-base-url <url> --session-token <token> < patch.diff
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs \
  device-pod-71-freq:workspace:/ put User/new.c \
  --reason "DEV edit" --lease-token <lease-token> \
  --api-base-url <url> --session-token <token> < file
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs \
  device-pod-71-freq:workspace:/ rm User/old.c --missing-ok \
  --reason "remove obsolete source" --lease-token <lease-token> \
  --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs \
  device-pod-71-freq:workspace:/ rmdir User/empty \
  --reason "remove empty folder" --lease-token <lease-token> \
  --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs \
  device-pod-71-freq:workspace:/ keil add-source User/new.c --group User \
  --reason "sync Keil project" --lease-token <lease-token> \
  --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs \
  device-pod-71-freq:workspace:/ keil remove-source User/old.c \
  --reason "sync Keil project" --lease-token <lease-token> \
  --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs \
  device-pod-71-freq:workspace:/ build start \
  --reason "build smoke" --lease-token <lease-token> \
  --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs \
  device-pod-71-freq:debug-probe download start \
  --reason "DEV smoke" --lease-token <lease-token> \
  --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs \
  device-pod-71-freq:debug-probe reset \
  --reason "reset smoke" --lease-token <lease-token> \
  --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs \
  device-pod-71-freq:io-probe:/uart/1 write "AT" \
  --reason "UART write smoke" --lease-token <lease-token> \
  --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs \
  device-pod-71-freq:io-probe:/uart/1 jsonrpc gpio.read \
  --params-json '{"pin":"PB5"}' --expect-result-field value \
  --reason "UART JSON-RPC smoke" --lease-token <lease-token> \
  --api-base-url <url> --session-token <token>

Inspect or cancel jobs through cloud-api:

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs job status --pod-id device-pod-71-freq <jobId> --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs job output --pod-id device-pod-71-freq <jobId> --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs job cancel --pod-id device-pod-71-freq <jobId> --api-base-url <url> --session-token <token>

Selector aliases also support job status/output/cancel after build/download:

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ build status <jobId> --api-base-url <url> --session-token <token>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:debug-probe download output <jobId> --api-base-url <url> --session-token <token>

Removed Legacy Path

profile create is removed from formal v0.2 mode. If a profile is missing or wrong, an admin must update cloud-api with the admin Device Pod APIs and then grant users. The CLI returns legacy_profile_create_removed instead of creating .device-pod/<devicePodId>.json.

Do not treat local files such as .device-pod/device-pod-71-freq.json or DEVICE_POD_PROFILE_DIR as authority. They are ignored by the formal CLI and may only exist as obsolete caches or hardware-host bootstrap artifacts.

Operation Rules

  • Use device-pod-cli first for workspace, build, download, reset, UART, and debug-probe tasks.
  • Prefer workspace apply-patch for source edits. Use workspace put only for intentional whole-file writes or new files, because it bypasses hunk-level conflict detection.
  • 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.
  • 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.

Host Asset Bootstrap

The packaged Windows host CLI asset remains /app/skills/device-pod-cli/assets/device-host-cli.mjs. Upload it only when cloud-api/gateway dispatch reaches a Windows host and reports that tools\device-host-cli.mjs is missing or broken.

Do not upload or recreate runner-side .device-pod/*.json as the formal profile source. The profile must come from cloud-api. Host-side profile snapshots, when needed, are written by hwlab-device-pod from the cloud-api-provided server profile before invoking device-host-cli.

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.
  • 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.

Manual Tests

T1

阅读 /app/skills/device-pod-cli/SKILL.md,然后用 cli 手动测试以下内容:在未设置 API URL 时运行 profile list,确认输出 JSON 且错误码为 api_base_url_required

T2

阅读 /app/skills/device-pod-cli/SKILL.md,然后用 cli 手动测试以下内容:设置 HWLAB_DEVICE_POD_API_URL 和有效 session 后运行 profile listprofile show --pod-id <devicePodId>doctor --pod-id <devicePodId>,确认输出来自 cloud-api authority,并且没有泄露 gatewaySessionIdhostWorkspaceRoot、probe UID 或 UART port。

T3

阅读 /app/skills/device-pod-cli/SKILL.md,然后用 cli 手动测试以下内容:创建本地 .device-pod/<devicePodId>.json,写入假的 gatewaySessionId,再运行 profile list 和 selector --dry-run;确认 JSON 输出标记 localProfileAuthority=false 且没有读取本地 fake route。

T4

阅读 /app/skills/device-pod-cli/SKILL.md,然后用 cli 手动测试以下内容:运行 profile create --pod-id <devicePodId>,确认返回 legacy_profile_create_removed,并提示使用 cloud-api admin API 管理服务端 profile/grant。

T5

阅读 /app/skills/device-pod-cli/SKILL.md,然后用 cli 手动测试以下内容:运行 workspace put/rm/rmdir/keilio-probe jsonrpc--dry-run,确认 JSON plan 中 intent 分别为 workspace.putworkspace.rmworkspace.rmdirworkspace.keilio.uart.jsonrpc,且 contentB64textpatch 不以原文泄露。