Skip to content
Go back

Windows Terminal + PowerShell 一键启动本地开发工作区

Edit page

本文记录如何在 Windows Terminal + PowerShell 下实现类似 tmux 的工作区自动化:一键打开窗口、按固定布局分屏、并在各 pane 中自动启动对应服务进程。

🎯 1. 目标效果


⚠️ 2. 常见坑与解决思路

在 Windows Terminal 中,wt 需要启动一个真实存在的“可执行文件”。如果把 yarn dev 直接交给 wt 当成 commandline,容易出现 0x80070002(系统找不到指定的文件),因为 wt 会把整段字符串当作 exe 名去查找。

💡 最稳方案:让 wt 只启动 cmd.exe,再由 cmd 执行 cd && <command>。这样 wt 启动的是始终存在的程序,命令解析由 shell 完成。


🛠️ 3. 前置条件

确保以下命令在 CMD 环境可用:

cmd /c where wt
cmd /c where node
cmd /c where yarn
cmd /c where assistant-cli

yarn 不存在,可尝试修复:

corepack enable
corepack prepare yarn@stable --activate

⚙️ 4. 自动化脚本 (Start-DevWorkspace.ps1)

将以下内容保存为 Start-DevWorkspace.ps1。你可以根据项目需求调整脚本开头的 可配置区

[CmdletBinding()]
param(
  [string]$RepoRoot = (Join-Path $HOME "repo"),
  [switch]$ReuseWindow,
  [string]$WindowName = "dev-workspace",
  [switch]$SelfCheck = $true,
  [switch]$PrintWtArgs
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

# ====== 可配置区:目录名与启动命令 ======
$WorkspaceTitle = "DevWorkspace"
$WebDirName     = "app-web"
$BackendDirName = "app-backend"
$WorkerDirName  = "app-worker"

$WebCommand     = "yarn dev"
$BackendCommand = "yarn start"
$WorkerCommand  = "yarn start"
$AssistantCommand = "assistant-cli"   # 可替换为 gemini / aider 等
# =============================================================

function Assert-Path([string]$Path, [string]$Hint) {
  if (-not (Test-Path -LiteralPath $Path)) {
    throw ("Path not found: {0}`nHint: {1}" -f $Path, $Hint)
  }
}

function Require-Command([string]$Cmd, [string]$Hint) {
  $c = Get-Command $Cmd -ErrorAction SilentlyContinue
  if (-not $c) { throw ("Command not found: {0}`nHint: {1}" -f $Cmd, $Hint) }
  return $c.Source
}

function CmdCapture([string]$cmd) {
  try {
    $out = cmd.exe /c $cmd 2>$null
    if ($null -eq $out) { return "" }
    return ($out | Out-String).Trim()
  } catch { return "" }
}

# --- 依赖检查 ---
$WtExe = Require-Command "wt" "Please install Windows Terminal."
$yarnWhere = CmdCapture "where yarn"
if (-not $yarnWhere) { throw "yarn not found in CMD PATH." }
$HasAssistant = [bool](CmdCapture ("where " + ($AssistantCommand.Split(" ")[0])))

# --- 工作区路径 ---
$WebPath     = Join-Path $RepoRoot $WebDirName
$BackendPath = Join-Path $RepoRoot $BackendDirName
$WorkerPath  = Join-Path $RepoRoot $WorkerDirName

Assert-Path $RepoRoot "Use -RepoRoot to point to your repo folder."
Assert-Path $WebPath  ("Missing folder: {0}" -f $WebPath)

# --- 生成 cmd.exe 参数 ---
function CmdArgs([string]$WorkDir, [string]$Run, [string]$PaneTitle) {
  $cmdLine = 'title {0} && cd /d "{1}" && {2}' -f $PaneTitle, $WorkDir, $Run
  return @("cmd.exe", "/k", $cmdLine)
}

$WebArgs    = CmdArgs $WebPath     $WebCommand     "web"
$BackArgs   = CmdArgs $BackendPath $BackendCommand "backend"
$WorkArgs   = CmdArgs $WorkerPath  $WorkerCommand  "worker"
$AssistArgs = if ($HasAssistant) { CmdArgs $WebPath $AssistantCommand "assistant" } 
              else { CmdArgs $WebPath "echo assistant not found & pause" "assistant" }

# --- 组装 wt 参数 ---
$wtArgs = New-Object System.Collections.Generic.List[string]
if ($ReuseWindow) { $wtArgs.Add("-w"); $wtArgs.Add($WindowName) } else { $wtArgs.Add("-w"); $wtArgs.Add("-1") }

# 1) 左上:web
$wtArgs.Add("new-tab"); $wtArgs.Add("-d"); $wtArgs.Add($WebPath); $wtArgs.Add("--title"); $wtArgs.Add($WorkspaceTitle)
foreach ($a in $WebArgs) { $wtArgs.Add($a) }

# 2) 右侧:assistant (垂直分割)
$wtArgs.Add(";"); $wtArgs.Add("split-pane"); $wtArgs.Add("-V"); $wtArgs.Add("-d"); $wtArgs.Add($WebPath); $wtArgs.Add("--title"); $wtArgs.Add("assistant")
foreach ($a in $AssistArgs) { $wtArgs.Add($a) }

# 3) 回到左侧并水平分割出 backend 和 worker
$wtArgs.Add(";"); $wtArgs.Add("move-focus"); $wtArgs.Add("left")
$wtArgs.Add(";"); $wtArgs.Add("split-pane"); $wtArgs.Add("-H"); $wtArgs.Add("-d"); $wtArgs.Add($BackendPath); $wtArgs.Add("--title"); $wtArgs.Add("backend")
foreach ($a in $BackArgs) { $wtArgs.Add($a) }

$wtArgs.Add(";"); $wtArgs.Add("move-focus"); $wtArgs.Add("down")
$wtArgs.Add(";"); $wtArgs.Add("split-pane"); $wtArgs.Add("-H"); $wtArgs.Add("-d"); $wtArgs.Add($WorkerPath); $wtArgs.Add("--title"); $wtArgs.Add("worker")
foreach ($a in $WorkArgs) { $wtArgs.Add($a) }

# 焦点回到 web
$wtArgs.Add(";"); $wtArgs.Add("move-focus"); $wtArgs.Add("up"); $wtArgs.Add(";"); $wtArgs.Add("move-focus"); $wtArgs.Add("up")

& $WtExe @($wtArgs.ToArray())

💡 使用技巧

🎨 定制建议


Created by Gemini CLI Assistant


Edit page

Previous Post
Kimi K2.5 锐评:多模态 + Agent 集群,这次月之暗面玩真的?
Next Post
WSL 2 极速开发环境配置指南 (2026 版)