Firmware Task Manager
A VSCode extension that runs tasks defined in .vscode/tasks.json with
interactive parameter prompts — serial port pickers, file dialogs, and
validated text input — tailored for firmware development workflows.
Features
- Activity bar view that lists tasks defined in the workspace (
.vscode/tasks.json)
- Run / terminate / restart tasks directly from the tree
- Favorite frequently used tasks
- Interactive input commands usable from the standard
inputs array of
tasks.json:
- Auto-detected serial port picker (
pickSerialPort)
- Validated text prompt (
promptInput)
- File / folder pickers (
pickFile, pickFolder)
- Dynamic list picker (
pickFromList)
- Pre-configure inputs without running: a gear icon ⚙️ next to tasks with
${input:...} variables opens the input UI without launching the task; the
selected values are stored and reused on the next ▶ run (no re-prompt).
Current values appear as a description next to the task name
(e.g. flash port=/dev/cu.usbserial · cfg=debug).
- Remembers the last value entered per task and prefills it on the next run
Use these commands as "type": "command" inputs in your tasks.json.
| Command |
Purpose |
Args |
firmware-task.pickSerialPort |
Auto-detects and lets the user pick a serial port. Falls back to manual entry if none detected. |
placeholder, filter (regex) |
firmware-task.promptInput |
Free-form text prompt. |
prompt, placeholder, value, password, validateRegex, validateMessage |
firmware-task.pickFile |
File picker (showOpenDialog). |
title, openLabel, filters, defaultUri, canSelectMany, relative |
firmware-task.pickFolder |
Folder picker. |
title, openLabel, defaultUri, relative |
firmware-task.pickFromList |
QuickPick over a custom list. |
items (string[] or {label,value,description}[]), placeholder |
Example tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "Serial Monitor",
"type": "shell",
"command": "pyserial-miniterm ${input:port} ${input:baud}"
},
{
"label": "Flash Firmware",
"type": "shell",
"command": "openocd -f interface/stlink.cfg -c 'program ${input:bin} verify reset exit'"
}
],
"inputs": [
{ "id": "port", "type": "command", "command": "firmware-task.pickSerialPort" },
{
"id": "baud",
"type": "command",
"command": "firmware-task.promptInput",
"args": { "prompt": "Baud rate", "value": "115200", "validateRegex": "^\\d+$" }
},
{
"id": "bin",
"type": "command",
"command": "firmware-task.pickFile",
"args": { "filters": { "Firmware": ["bin", "hex", "elf"] } }
}
]
}
Variables (${input:port}, etc.) are substituted by Firmware Task Manager when
you launch the task from its tree view. Standard VSCode promptString and
pickString input types are also supported.
Run in an existing terminal
VSCode tasks always spawn a fresh task terminal, which does not inherit the
environment of a terminal you already set up (e.g. an ESP-IDF terminal where
export.sh / export.ps1 was sourced). To reuse such a terminal, add
"runInActiveTerminal": true to the task. When set, running the task types
the command into a terminal instead of launching a new task terminal:
{
"label": "build",
"type": "shell",
"command": "idf.py build",
"runInActiveTerminal": true, // type into a terminal instead of a new task terminal
"terminalName": "ESP-IDF" // optional: always target this named terminal (created if missing)
}
Terminal selection priority:
terminalName given → the terminal with that exact name (created if none exists).
Use this to pin sends to one terminal when several are open.
- Otherwise → the active terminal.
- If no terminal is open → a new one is created with the default profile (so a
configured terminal profile, e.g. one that sources the IDF environment, still applies).
The command is sent with a trailing newline, so it executes immediately.
Notes / limitations:
runInActiveTerminal and terminalName are custom keys, so VSCode's editor may
flag them with a "not allowed" warning. This is cosmetic — the extension reads
them directly from tasks.json and they work regardless.
- Commands sent this way are not tracked as VSCode task executions: the tree's
running indicator, Terminate, Restart, and the running-count badge do not
apply to them.
${input:...} substitution is still applied.
Build shortcut (Ctrl/Cmd+Shift+B)
VSCode's Run Build Task shortcut runs the default build task through its
native task system, which bypasses this extension — so runInActiveTerminal
would be ignored. To fix that, mark your build task as the default build task and
add runInActiveTerminal:
{
"label": "idf-build",
"type": "shell",
"command": "idf.py build",
"runInActiveTerminal": true,
"group": { "kind": "build", "isDefault": true }
}
When a workspace contains a default build task (group.kind = "build",
isDefault = true) with runInActiveTerminal: true, the extension reroutes
the build shortcut to itself so the command is sent to your terminal:
- macOS:
Cmd+Shift+B · Windows / Linux: Ctrl+Shift+B (matches the native bindings).
- The override is scoped by the
firmwareTask.hasBuildInTerminal context key — it
only takes effect in workspaces that actually have such a task. Other projects
keep the normal VSCode build behavior.
${input:...} is resolved exactly like a tree-view run. (Remembered input values
are cached per task; values entered via the tree are not shared with the shortcut
path, so the first shortcut run of an input-bearing task may prompt once.)
Configuration
| Setting |
Default |
Description |
firmwareTask.showOnlyWorkspaceTasks |
true |
Show only tasks defined in .vscode/tasks.json. Set to false to also show auto-detected tasks (CMake, npm, tsc, etc.). |
firmwareTask.rememberInputs |
true |
Remember last entered input values per task and prefill on subsequent runs. |
firmwareTask.serialPortFilter |
"" |
Regex applied to detected serial port device names. |
firmwareTask.exclude |
null |
Regex pattern for excluding tasks by name. |
firmwareTask.collapseLargeTaskTree |
true |
Collapse top-level groups when there are more than three groups and more than 30 tasks. |
firmwareTask.taskSortOrder |
"label" |
Sort order: "label", "group", or "provider". |
firmwareTask.favorites |
[] |
Saved favorite task ids (workspace settings). |
Installation (local VSIX)
pnpm install
pnpm run vsix
# → dist-vsix/firmware-task-manager-1.0.0.vsix
Install it in VSCode via Extensions: Install from VSIX... in the command
palette, or from the CLI:
code --install-extension dist-vsix/firmware-task-manager-1.0.0.vsix
Development
pnpm install
pnpm run watch # rolldown + tsc in watch mode
# Press F5 in VSCode to launch the Extension Development Host
Credits
This extension is based on
cnshenj/vscode-task-manager,
with modifications focused on firmware development workflows (serial port
picking, file dialogs, per-task remembered inputs, copy-command-line action,
etc.).
License
MIT