{"record":{"id":"2d440068803ace32","repo":"can1357/oh-my-pi","slug":"unsupported-launch-key-rawkey","errorCode":null,"errorMessage":"Unsupported launch key ${rawKey}","messagePattern":"Unsupported launch key (.+?)","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/hub/launch.ts","lineNumber":218,"sourceCode":"\t\t\t\t\tlog: ready.log,\n\t\t\t\t\tport: ready.port,\n\t\t\t\t\thost: ready.host,\n\t\t\t\t\ttimeoutMs: timeoutMs(ready.timeout, 30),\n\t\t\t\t}\n\t\t\t: undefined,\n\t\trestart: params.restart ?? \"no\",\n\t\tpersist: (params.persist ?? false) || detached,\n\t\tdetached,\n\t};\n}\n\nfunction sendData(params: LaunchParams): string | undefined {\n\tlet data = params.text ?? \"\";\n\tif (params.text && (params.enter ?? true)) data += KEY_INPUT.ENTER;\n\tfor (const rawKey of params.keys ?? []) {\n\t\tconst key = rawKey.trim().toUpperCase();\n\t\tconst input = KEY_INPUT[key];\n\t\tif (input === undefined) throw new ToolError(`Unsupported launch key ${rawKey}`);\n\t\tdata += input;\n\t}\n\treturn data || undefined;\n}\n\nfunction operationFor(params: LaunchParams, session: ToolSession): DaemonOperation {\n\tswitch (params.op) {\n\t\tcase \"start\":\n\t\t\treturn { op: \"start\", spec: commandSpec(params, session), owner: session.getSessionId?.() ?? undefined };\n\t\tcase \"list\":\n\t\t\treturn { op: \"list\" };\n\t\tcase \"logs\":\n\t\t\treturn {\n\t\t\t\top: \"logs\",\n\t\t\t\tname: requiredName(params),\n\t\t\t\tlines: Math.min(1_000, Math.floor(params.lines ?? 100)),\n\t\t\t\thead: params.head ?? false,\n\t\t\t\tgrep: params.grep,","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/hub/launch.ts#L200-L236","documentation":"The send operation lets you inject key presses via `params.keys`; each key is uppercased and looked up in the KEY_INPUT table. If a key name is not in that table, sendData() throws ToolError 'Unsupported launch key <key>', listing the offending key verbatim.","triggerScenarios":"launch({ op: \"send\", name, keys: [\"CTRL+SHIFT+T\"] }) or keys: [\"ESC\"] if the table only defines \"ESCAPE\"; any non-canonical key name like \"RETURN\", \"CMD\", or a multi-key chord not present in KEY_INPUT.","commonSituations":"Guessing key names instead of using the tool's supported set (ENTER, TAB, ESCAPE, arrow keys, CTRL-letter combos as defined); lowercase/abbreviated spellings; sending chords the KEY_INPUT table does not encode.","solutions":["Use canonical key names supported by the launch tool's KEY_INPUT table (e.g. \"ENTER\", \"ESCAPE\", \"TAB\", \"UP\", \"C-c\"-style ctrl combos as documented).","Check the tool's parameter schema/description for the exact accepted key list.","Send the text directly via `text` for printable input and reserve `keys` for control keys."],"exampleFix":"// before\nlaunch({ op: \"send\", name: \"cli\", keys: [\"RETURN\"] })\n// throws: Unsupported launch key RETURN\n\n// after\nlaunch({ op: \"send\", name: \"cli\", keys: [\"ENTER\"] })","handlingStrategy":"validation","validationCode":"const SUPPORTED_KEYS = new Set([\"ENTER\", \"TAB\", \"ESCAPE\", \"UP\", \"DOWN\", \"LEFT\", \"RIGHT\" /* per KEY_INPUT table */]);\nfor (const k of params.keys ?? []) {\n  if (!SUPPORTED_KEYS.has(k.trim().toUpperCase())) throw new Error(`Unsupported launch key ${k}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await launchTool.run({ op: \"send\", name, keys });\n} catch (err) {\n  if (err instanceof ToolError && err.message.startsWith(\"Unsupported launch key\")) {\n    // correct the key name against the supported set and retry\n  } else throw err;\n}","preventionTips":["Use the exact canonical key names from the launch tool docs, not abbreviations (ESCAPE not ESC).","Send printable characters via text instead of keys.","Keep a whitelist of valid keys in any automation layer."],"tags":["validation","tool-args","enum-value"],"backgroundTag":"unsupported-enum-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}