Files
pikasTech-HWLAB/skills/device-pod-cli/SKILL.md
T
2026-05-28 10:18:36 +08:00

23 KiB

name, description, version
name description version
device-pod-cli Use the HWLAB internal device-pod CLI from a HWLAB code agent runner to create/register device-pod profiles and operate a profiled target workspace, debug probe, and I/O probe through hwlab-gateway and device-host-cli. 0.1.0-mvp

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 or PROD images. It does not apply to external UniDesk developer workspaces or third-party machines; those environments must not treat this skill as a general hardware control contract.

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

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

DeepSeek Operation Friction Rules

  • For build, download, UART, and workspace actions, use device-pod-cli first. Do not start by calling /app/tools/hwlab-gateway-tran.mjs directly, do not hunt for Windows-side Keil skills, and do not call keil-cli.py directly when a matching device-pod profile exists.
  • The profile already carries hostWorkspaceRoot, projectWorkspace, debugInterface.uv4Path, probe UID, UART port, and gateway route. Let device-pod-cli -> device-host-cli apply those values; do not rediscover the Windows project path with dir, Get-ChildItem, or ad hoc cmd probes.
  • If a command returns profile-missing, run profile bootstrap. If it returns a device-host-cli JSON failure, fix the named device-pod operation or host CLI; do not bypass the profile with generic gateway shell.
  • Workspace search follows a compact ripgrep-like shape: device-pod-71-freq:workspace:/ rg "printf|main" projects/01_baseline -g "*.c" -g "*.h" -l. The optional path after the pattern is honored as the search root; use it to avoid scanning vendor PDFs or generated text outside the project under test.
  • For debug probe jobs, download start is mutating and requires --approved --reason, but download status <jobId> is read-only and must be queried without approval friction. If download status includes UART capture, read the top-level hostUartCapture field first before falling back to job files or direct tran.
  • I/O probe selectors are strict path tokens. Always write device-pod-71-freq:io-probe:/uart/1 read as one selector token; do not write io-probe:/uart / 1 read, io-probe:/uart/ 1 read, or other spaced path variants. The CLI should fail these forms with an invalid-request hint instead of normalizing the path or forwarding the malformed command to the Windows host.

Fast build smoke for device-pod-71-freq:

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs profile show --pod-id device-pod-71-freq
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ build start
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ build status <jobId>

The build status JSON must be treated as the evidence. Report hostJson.status, hostJson.result.success, hostJson.result.exitCode, hostJson.result.project, hostJson.result.target, and the output artifact paths from the profile; do not describe Windows Keil skill config as the source of truth for a device-pod build.

DeepSeek Profile-Recreate Task

When a HWLAB runner asks DeepSeek or another code agent to delete and recreate a profile, this SKILL.md is the operating procedure. Do not stop after listing the workspace or describing files. Execute the profile bootstrap and validation commands, then report the resulting JSON evidence.

For device-pod-71-00075-11, the required order is:

  1. Prove the profile is missing with node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs health --pod-id device-pod-71-00075-11.
  2. Create /workspace/hwlab/.device-pod/device-pod-71-00075-11.json with node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs profile create --pod-id device-pod-71-00075-11 --force.
  3. Upload /app/skills/device-pod-cli/assets/device-host-cli.mjs and the new profile to gws_DESKTOP-1MHOD9I:/f/Work/ConStart/projects/71-00075-11 using /app/tools/tran.mjs.
  4. Verify Windows host health through node tools\device-host-cli.mjs --profile .device-pod\device-pod-71-00075-11.json --pod-id device-pod-71-00075-11 health.
  5. Run node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs profile list and report the profile count plus the hash of each profile.
  6. Verify runner health, selector dry-runs, workspace ls, build start/status, download start/status, and UART read/write/read through device-pod-cli.

Any failure must be reported as FAIL with the exact command and the JSON blocker or stderr/stdout summary. A successful bootstrap report must include runner profile path, profile SHA-256, profile list count, host health or the observed gateway blocker, runner health, and both selector dry-run results. Full hardware validation reports must additionally include build job id, download job id, download Verify OK evidence, and UART byte count/summary.

For the first bootstrap turn, run this block exactly. It intentionally performs only missing-state proof, runner profile creation, host asset/profile upload, host health, runner health, and selector dry-run checks; run build/download/UART in a second turn after this block succeeds.

Preferred one-line flow for DeepSeek runners: use the CLI-owned profile template instead of hand-copying JSON. This avoids heredoc/quoting drift in model-run shells and still creates the same explicit profile under the persistent profile directory.

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs profile create --pod-id device-pod-71-00075-11 --force
node /app/tools/tran.mjs gws_DESKTOP-1MHOD9I:/f/Work/ConStart/projects/71-00075-11 upload /app/skills/device-pod-cli/assets/device-host-cli.mjs tools/device-host-cli.mjs
node /app/tools/tran.mjs gws_DESKTOP-1MHOD9I:/f/Work/ConStart/projects/71-00075-11 upload /workspace/hwlab/.device-pod/device-pod-71-00075-11.json .device-pod/device-pod-71-00075-11.json
node /app/tools/tran.mjs gws_DESKTOP-1MHOD9I:/f/Work/ConStart/projects/71-00075-11 cmd -- node tools\device-host-cli.mjs --profile .device-pod\device-pod-71-00075-11.json --pod-id device-pod-71-00075-11 health
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs health --pod-id device-pod-71-00075-11
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs profile list
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-00075-11:workspace:/ ls --dry-run
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ ls --dry-run

The lower-level JSON block below is a reference for the CLI template and for manual recovery only.

set -eu
skill_file=/app/skills/device-pod-cli/SKILL.md
grep -n "DeepSeek Profile-Recreate Task" "$skill_file"

set +e
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs health --pod-id device-pod-71-00075-11
missing_exit=$?
set -e
if [ "$missing_exit" -eq 0 ]; then
  echo "FAIL: expected profile-missing before bootstrap" >&2
  exit 10
fi

profile_dir="${DEVICE_POD_PROFILE_DIR:-/workspace/hwlab/.device-pod}"
profile_file="$profile_dir/device-pod-71-00075-11.json"
mkdir -p "$profile_dir"
cat > "$profile_file" <<'JSON'
{
  "schemaVersion": 1,
  "podId": "device-pod-71-00075-11",
  "devicePodId": "device-pod-71-00075-11",
  "workspaceRoot": "F:\\Work\\ConStart\\projects\\71-00075-11",
  "target": {
    "id": "constart-71-00075-11",
    "mcu": "STM32H723ZGTx",
    "flashBase": "0x08000000"
  },
  "projectWorkspace": {
    "projectPath": "FirmWare/MDK-ARM/FREQ_Controller_FW.uvprojx",
    "targetName": "FREQ_Controller_FW",
    "hexPath": "FirmWare/MDK-ARM/FREQ_Controller_FW/FREQ_Controller_FW.hex",
    "mapPath": "FirmWare/MDK-ARM/FREQ_Controller_FW/FREQ_Controller_FW.map"
  },
  "debugInterface": {
    "id": "debug-probe",
    "type": "cmsis-dap",
    "probeUid": "3FD750C63E342E24",
    "uv4Path": "C:\\Keil_v5\\UV4\\UV4.exe",
    "programBackend": "keil-headless",
    "autoBindUvoptx": true
  },
  "ioInterface": {
    "uart": [
      {
        "id": "uart/1",
        "scope": "external",
        "port": "COM4",
        "baudRate": 921600,
        "encoding": "utf8",
        "description": "ConStart debug USART1 via CMSIS-DAP CDC UART (verified COM4)"
      }
    ]
  },
  "cloudApiUrl": "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667",
  "gatewaySessionId": "gws_DESKTOP-1MHOD9I",
  "resourceId": "res_windows_host",
  "capabilityId": "cap_windows_cmd_exec",
  "hostWorkspaceRoot": "F:\\Work\\ConStart\\projects\\71-00075-11",
  "hostCli": "node tools\\device-host-cli.mjs"
}
JSON
sha256sum "$profile_file"

node /app/tools/tran.mjs gws_DESKTOP-1MHOD9I:/f/Work/ConStart/projects/71-00075-11 upload /app/skills/device-pod-cli/assets/device-host-cli.mjs tools/device-host-cli.mjs
node /app/tools/tran.mjs gws_DESKTOP-1MHOD9I:/f/Work/ConStart/projects/71-00075-11 upload "$profile_file" .device-pod/device-pod-71-00075-11.json
node /app/tools/tran.mjs gws_DESKTOP-1MHOD9I:/f/Work/ConStart/projects/71-00075-11 cmd -- node tools\device-host-cli.mjs --profile .device-pod\device-pod-71-00075-11.json --pod-id device-pod-71-00075-11 health

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs health --pod-id device-pod-71-00075-11
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs profile list
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-00075-11:workspace:/ ls --dry-run
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ ls --dry-run

Runtime Contract

  • The preinstalled CLI entrypoint is node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs.
  • The canonical implementation is /app/tools/device-pod-cli.mjs; the skill script is only a stable preinstalled wrapper for code agent runners.
  • The packaged Windows host CLI asset is /app/skills/device-pod-cli/assets/device-host-cli.mjs. It is bundled with this skill so a runner can send the exact tested host-side CLI to a new Windows hardware PC before the first device-pod operation.
  • Profiles are read from DEVICE_POD_PROFILE_DIR/<devicePodId>.json when that directory is set, otherwise from .device-pod/<devicePodId>.json in the current code agent workspace; DEVICE_POD_PROFILE may point to one explicit profile file. G14 device-agent runners should keep shared profiles in the persistent /workspace/hwlab/.device-pod directory rather than only in ephemeral /app/.device-pod.
  • Multiple profiles may coexist in the same runner workspace. Use the selector prefix, such as device-pod-71-freq:... or device-pod-71-00075-11:..., as the source of truth for the active pod. device-pod-cli automatically passes that selected profile to Windows device-host-cli as --profile .device-pod\\<devicePodId>.json --pod-id <devicePodId>, so host-side commands must not fall back to the default device-pod-71-freq profile when another pod is selected.
  • The CLI calls HWLAB cloud-api hardware.invoke.shell, which dispatches to an outbound hwlab-gateway session and then to the user PC side device-host-cli. Do not call gateway, serial ports, Keil, pyOCD, DAPLink, or Windows shell directly when the profiled device-pod path is available.
  • device-host-cli is expected to be self-contained on the user PC. Keil, serial-monitor, mklink, and other skills can be implementation references, but are not runtime dependencies of this HWLAB runner skill.
  • device-host-cli is not just a copied preinstall script. It is the hot development tool that HWLAB internal code agents, including DeepSeek-backed runners, may keep improving on the target Windows workspace when hardware, Keil, probe, UART, or filesystem operations are not smooth enough. Hot fixes are expected whenever host-side behavior is awkward or missing; validate them through the real device-pod/gateway route first, then copy the result back into the HWLAB repo asset for the next CI/CD preinstall.

Profile Bootstrap

A missing profile is a normal bootstrap state. Do not switch to another profile and do not guess defaults. Create the selected device-pod profile explicitly in both places below, then verify it before running build, download, or UART I/O.

  • Runner profile: /workspace/hwlab/.device-pod/<devicePodId>.json. This is the persistent HWLAB code agent workspace profile used by device-pod-cli.
  • Windows host profile: <hostWorkspaceRoot>\.device-pod\<devicePodId>.json. This is the matching profile loaded by device-host-cli after the gateway command reaches the Windows hardware PC.
  • Windows host CLI: <hostWorkspaceRoot>\tools\device-host-cli.mjs. Upload the packaged /app/skills/device-pod-cli/assets/device-host-cli.mjs asset when a new profile is bootstrapped or after the host CLI has been hot-fixed.

Minimum profile fields are schemaVersion, podId or devicePodId, target.id, cloudApiUrl, gatewaySessionId, resourceId, capabilityId, hostWorkspaceRoot, and hostCli. Keep the project, debug probe, and I/O probe sections explicit so later agents do not depend on hidden CLI overrides.

For G14 DEV ConStart device-pod-71-00075-11, use this known hardware profile. This example is intentionally complete so a DeepSeek runner can recreate the profile after /workspace/hwlab/.device-pod/device-pod-71-00075-11.json and the matching Windows profile have been deleted.

profile_dir="${DEVICE_POD_PROFILE_DIR:-/workspace/hwlab/.device-pod}"
profile_file="$profile_dir/device-pod-71-00075-11.json"
mkdir -p "$profile_dir"
cat > "$profile_file" <<'JSON'
{
  "schemaVersion": 1,
  "podId": "device-pod-71-00075-11",
  "devicePodId": "device-pod-71-00075-11",
  "workspaceRoot": "F:\\Work\\ConStart\\projects\\71-00075-11",
  "target": {
    "id": "constart-71-00075-11",
    "mcu": "STM32H723ZGTx",
    "flashBase": "0x08000000"
  },
  "projectWorkspace": {
    "projectPath": "FirmWare/MDK-ARM/FREQ_Controller_FW.uvprojx",
    "targetName": "FREQ_Controller_FW",
    "hexPath": "FirmWare/MDK-ARM/FREQ_Controller_FW/FREQ_Controller_FW.hex",
    "mapPath": "FirmWare/MDK-ARM/FREQ_Controller_FW/FREQ_Controller_FW.map"
  },
  "debugInterface": {
    "id": "debug-probe",
    "type": "cmsis-dap",
    "probeUid": "3FD750C63E342E24",
    "uv4Path": "C:\\Keil_v5\\UV4\\UV4.exe",
    "programBackend": "keil-headless",
    "autoBindUvoptx": true
  },
  "ioInterface": {
    "uart": [
      {
        "id": "uart/1",
        "scope": "external",
        "port": "COM4",
        "baudRate": 921600,
        "encoding": "utf8",
        "description": "ConStart debug USART1 via CMSIS-DAP CDC UART (verified COM4)"
      }
    ]
  },
  "cloudApiUrl": "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667",
  "gatewaySessionId": "gws_DESKTOP-1MHOD9I",
  "resourceId": "res_windows_host",
  "capabilityId": "cap_windows_cmd_exec",
  "hostWorkspaceRoot": "F:\\Work\\ConStart\\projects\\71-00075-11",
  "hostCli": "node tools\\device-host-cli.mjs"
}
JSON

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs health --pod-id device-pod-71-00075-11
node /app/tools/tran.mjs gws_DESKTOP-1MHOD9I:/f/Work/ConStart/projects/71-00075-11 upload /app/skills/device-pod-cli/assets/device-host-cli.mjs tools/device-host-cli.mjs
node /app/tools/tran.mjs gws_DESKTOP-1MHOD9I:/f/Work/ConStart/projects/71-00075-11 upload "$profile_file" .device-pod/device-pod-71-00075-11.json
node /app/tools/tran.mjs gws_DESKTOP-1MHOD9I:/f/Work/ConStart/projects/71-00075-11 cmd -- node tools\\device-host-cli.mjs --profile .device-pod\\device-pod-71-00075-11.json --pod-id device-pod-71-00075-11 health

After bootstrap, validate selector isolation before touching hardware:

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-00075-11:workspace:/ ls --dry-run
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ ls --dry-run

The two dry-run outputs must reference different --profile .device-pod\<devicePodId>.json host arguments and different profile hashes.

Windows Host CLI Bootstrap

Do not run a separate installer. To bring up a new Windows hardware PC, send the packaged asset to the target workspace through the existing cmd passthrough path, then start it through the same cmd passthrough path.

Target layout:

<windows-workspace>\tools\device-host-cli.mjs
<windows-workspace>\.device-pod\<devicePodId>.json

When the UniDesk Windows maintenance route is available, the file transfer may use the same remote channel that backs cmd passthrough. In HWLAB coder images, /app/tools/tran.mjs is the stable contract entrypoint; /app/tools/hwlab-gateway-tran.mjs is only the compatible explicit wrapper for the same transport. If the compatible wrapper exists but /app/tools/tran.mjs is missing, report a CI/CD preinstall gap instead of adding a device-pod workaround. In HWLAB k8s runner pods, tran.mjs auto-selects the in-cluster hwlab-cloud-api.<namespace>.svc.cluster.local:6667 API endpoint; outside k8s it falls back to local 127.0.0.1:6667, and non-standard deployments may still pass --api-base-url. tran.mjs upload uses bounded base64 chunks tuned for the Windows cmd passthrough limit; do not raise the chunk size above the documented default to hide slow transfers. If upload/download becomes awkward again, fix tran.mjs or the gateway transport first.

node /app/tools/tran.mjs <gatewaySessionId>:/d/Work/HWLAB-workspace upload /app/skills/device-pod-cli/assets/device-host-cli.mjs tools/device-host-cli.mjs
node /app/tools/tran.mjs <gatewaySessionId>:/d/Work/HWLAB-workspace cmd -- node tools\\device-host-cli.mjs --profile .device-pod\\<devicePodId>.json --pod-id <devicePodId> health

When only HWLAB gateway hardware.invoke.shell is available, send the asset bytes as bounded base64 chunks through cmd/PowerShell into tools\device-host-cli.mjs, then verify with:

node tools\device-host-cli.mjs --profile .device-pod\<devicePodId>.json --pod-id <devicePodId> health

After that, device-pod-cli should use the profile's hostCli, normally node tools\device-host-cli.mjs, and should not depend on any Windows skill directory at runtime.

Host CLI Hot Development

When a profiled operation is awkward or missing, prefer improving the Windows workspace copy of tools\device-host-cli.mjs instead of bypassing the device-pod model with arbitrary cmd snippets. The intended loop is:

edit tools\device-host-cli.mjs in the Windows device-pod workspace
node tools\device-host-cli.mjs health
node tools\device-host-cli.mjs <new named operation>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs <devicePodId>:... <same operation>
copy the validated change back to skills/device-pod-cli/assets/device-host-cli.mjs

The host CLI should stay self-contained and named-operation oriented: add debug-probe launch-flash or io-probe uart/1 read-after-launch-flash style device semantics, not a generic shell escape. If gateway/cmd transfer itself is the friction, fix tran.mjs or the gateway transport separately instead of embedding transport workarounds into device-host-cli.

Commands

All commands emit JSON and must remain short-running. Use build start / build status and download start / download status style host jobs for long operations instead of holding one gateway request open.

node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs health
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ ls
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ rg main
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ apply-patch --approved --reason "DEV edit" < patch.diff
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ build start
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:workspace:/ build status <jobId>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:debug-probe chip-id
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:debug-probe download start --approved --reason "DEV smoke"
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:debug-probe download status <jobId>
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:debug-probe download start --capture-uart uart/1 --capture-duration-ms 8000 --approved --reason "DEV boot log capture"
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:debug-probe launch-flash --approved --reason "manual flash-vector launch"
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:io-probe:/uart/1 ports
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:io-probe:/uart/1 read --duration-ms 5000
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:io-probe:/uart/1 read --port COM4 --baud-rate 921600 --duration-ms 5000
node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs device-pod-71-freq:io-probe:/uart/1 read-after-launch-flash --approved --reason "boot log capture"

Use --port COMx and --baud-rate N only as a short-lived UART discovery override. After the real port is proven, write the stable value back into the device-pod profile so later agents do not depend on a hidden command override.

For boot logs that only appear during reset/download, prefer debug-probe download start --capture-uart uart/1 --capture-duration-ms N so the host opens the UART before Keil starts flashing and stores the captured bytes in the download job status under result.uartCapture.

Safety

  • Mutating operations such as workspace patching, download, reset, launch-flash, read-after-launch-flash, and I/O write require --approved --reason <text> before the CLI dispatches anything.
  • io-probe:/inner/... is intentionally distinct from external physical I/O paths such as io-probe:/uart/1; do not use internal target state as evidence for external UART/GPIO observations.
  • Keep the gateway as transport only. Do not add a generic cmd operation to device-pod-cli; add a named device-pod operation instead.
  • If the CLI returns profile-missing, profile-invalid, or approval-required, fix that blocker first rather than guessing a default device or falling back to arbitrary shell commands.