{"record":{"id":"19e59966e466c87f","repo":"Hmbown/CodeWhale","slug":"scp-rel-failed-r-stderr-trim-slice-0-300","errorCode":null,"errorMessage":"scp ${rel} failed: ${r.stderr.trim().slice(0, 300)}","messagePattern":"scp (.+?) failed: (.+?)","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/transport.mjs","lineNumber":288,"sourceCode":"/** Push the self-contained remote agent + src tree to an ssh computer. */\nexport async function installRemoteAgent(computer) {\n  const ex = sshExec(computer);\n  const srcDir = path.join(PLUGIN_ROOT, \"src\");\n  const rels = [\"agent.mjs\"];\n  for (const dir of [\"\", \"backends\"]) {\n    const full = path.join(srcDir, dir);\n    for (const f of fs.readdirSync(full)) {\n      if (f.endsWith(\".mjs\") || f.endsWith(\".m\") || f.endsWith(\".h\")) rels.push(`src/${dir ? dir + \"/\" : \"\"}${f}`);\n    }\n  }\n  const marker = \".codewhale-cu/agent\";\n  let r = await run(\"ssh\", [...ex.base, \"mkdir\", \"-p\", `${marker}/src/backends`], { timeoutMs: 15_000 });\n  if (r.code !== 0) throw new ExecError(`ssh ${ex.userHost}: mkdir failed: ${r.stderr.trim().slice(0, 300)}`, r);\n  for (const rel of rels) {\n    const localPath = rel === \"agent.mjs\" ? path.join(PLUGIN_ROOT, \"agent.mjs\") : path.join(srcDir, rel.slice(4));\n    const dest = safeRemotePath(`${marker}/${rel}`);\n    r = await run(\"scp\", [...(computer.port ? [\"-P\", String(computer.port)] : []), localPath, `${ex.userHost}:${dest}`], { timeoutMs: 30_000 });\n    if (r.code !== 0) throw new ExecError(`scp ${rel} failed: ${r.stderr.trim().slice(0, 300)}`, r);\n  }\n  // Probe remote platform via the agent itself.\n  const reply = await ex.remote({ tool: \"platform\" });\n  return { installed: rels.length, remotePlatform: reply.platform, agentPath: `${marker}/agent.mjs` };\n}\n\n/** hdc (HarmonyOS) executor. Commands run on-device; files pull to local tmp. */\nexport function hdcExec(computer) {\n  const targetArgs = computer.target ? [\"-t\", computer.target] : [];\n  const shell = (args, opts = {}) => run(\"hdc\", [...targetArgs, \"shell\", ...args], opts);\n  return {\n    kind: \"hdc\",\n    targetArgs,\n    run,\n    runOk,\n    shell,\n    async pullFile(remotePath, localPath, opts = {}) {\n      // HDC device captures use absolute paths; SSH agent paths are relative.","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/transport.mjs#L270-L306","documentation":"During installRemoteAgent(), each agent file is uploaded with scp; when any scp invocation exits nonzero this ExecError is thrown with the relative file name and trimmed stderr (max 300 chars). It identifies exactly which agent file failed to copy and why.","triggerScenarios":"installRemoteAgent() loop hits an scp failure: local file missing (srcDir not built), remote dir removed between mkdir and scp, permission denied, scp binary absent, or connection drops mid-transfer.","commonSituations":"Plugin build output (srcDir) stale or deleted so localPath doesn't exist; remote .codewhale-cu wiped by another process; scp not installed on the local machine; custom ssh port mismatched (port not passed); network interruption on large transfers.","solutions":["Check the local file exists: the error's rel names it; rebuild the plugin srcDir if missing","Verify the remote directory still exists (.codewhale-cu/agent) after mkdir","Ensure scp is installed locally and the port flag (-P) matches the computer's port","Retry installRemoteAgent() — transient network drops are common","Read embedded stderr for cause (permission denied vs no such file)"],"exampleFix":"// before\nawait installRemoteAgent(ex, computer); // scp backends/screen.mjs failed: no such file\n// after\nfor (const rel of rels) {\n  const p = rel === \"agent.mjs\" ? path.join(PLUGIN_ROOT, \"agent.mjs\") : path.join(srcDir, rel.slice(4));\n  if (!fs.existsSync(p)) throw new Error(`missing local agent file: ${p}`); // detect before scp\n}\nawait installRemoteAgent(ex, computer);","handlingStrategy":"retry","validationCode":"// ensure every local file to upload exists before starting scp loop\nfor (const rel of rels) {\n  const p = rel === \"agent.mjs\" ? path.join(PLUGIN_ROOT, \"agent.mjs\") : path.join(srcDir, rel.slice(4));\n  if (!fs.existsSync(p)) throw new Error(`missing local file for ${rel}: ${p}`);\n}","typeGuard":"function isScpFailure(e) { return e instanceof ExecError && e.message.startsWith(\"scp \"); }","tryCatchPattern":"try {\n  await installRemoteAgent(ex, computer);\n} catch (e) {\n  if (e.message.startsWith(\"scp \")) {\n    // transient network drop is common — retry with backoff\n    return retryWithBackoff(() => installRemoteAgent(ex, computer), 3);\n  }\n  throw e;\n}","preventionTips":["Rebuild the plugin so srcDir contains all backend files before install","Pass the correct port (-P) when the computer uses a nonstandard ssh port","Verify scp exists on the local machine","Keep the remote .codewhale-cu tree intact between mkdir and scp"],"tags":["scp","file-transfer","installation"],"backgroundTag":"scp-command-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}