Files
ETTerms/ARCHITECTURE.md
T
etwen 1263514586 feat(status): add Status page with PDU outlet on/off buttons (v0.3.2)
- New left-rail Status view (StatusView.cs) hosting the PDU tab; PDU panel moved out of SettingsView and auto-polls all 12 outlets every 3s on a background thread (no manual Refresh).

- Each outlet row gets a Control button (DataGridViewButtonColumn) that toggles the port via SNMP off the UI thread, re-reads after ~400ms, and resets the grid on disconnect.

- fix(shell): ShellChannel falls back to the user home folder when StartupDirectory no longer exists (avoids CreateProcess 267).

- docs: update ARCHITECTURE / CLAUDE / README / README.zh-TW and About changelog; bump version to 0.3.2.
2026-06-11 09:03:32 +08:00

51 KiB
Raw Blame History

ETTerms — Architecture

A native Windows terminal workspace for SSH and Serial Port connections, with a TeraTerm-compatible TTL scripting engine. UI inspired by KKTerm (activity rail + tabbed session workspace + saved-connection sidebar); script engine ported and extended from MyTeraTerm (TTLInterpreter).


Overview

ETTerms 是一個給工程師 / 韌體 / 硬體驗證人員用的單一視窗終端機工作台。它把日常會用到的兩種連線——SSH(連伺服器 / 嵌入式 Linux)與 Serial Port(連 UART / console / 開發板)——收進同一個 WinForms 視窗裡,用分頁(Tab)管理多條連線,左側有可存檔的連線清單(Saved Connections)。

核心差異化價值是腳本自動化:沿用並擴充 MyTeraTerm 既有的 TTLTera Term Language)直譯器,讓使用者既有的 .ttl 腳本(send / sendln / wait / if / while / logopen / sprintf2 / pductrl…)可以直接重用,直接驅動原生 SSH / Serial channel,做到登入自動化、批次下命令、log 收集、PDU 電源控制等。

開發策略採「GUI 先行」:先把 KKTerm 風格的視窗外殼與分頁工作區做出來(可見、可切換、可關閉),再逐步把 Serial → SSH → VT100 渲染 → 腳本引擎一層層補上。

目標使用者: 單機桌面使用者(無多人 / 無登入系統)。所有連線資料存在本機 SQLite,密碼存在 Windows Credential Manager,不上雲、不回傳。


Tech Stack

Layer Technology 備註
UI Framework C# .NET 8 WinFormsnet8.0-windows 與 MyTeraTerm 同框架;本機已裝 .NET 8 Desktop Runtime + SDK 9/10net8 targeting pack 自動還原)
SSH SSH.NETRenci.SshNet 原生 SSH,支援 password / key / keyboard-interactive
Serial System.IO.Ports 沿用 MyTeraTerm ComPortBridge 經驗
Terminal 渲染 自繪 VT100 / ANSI 控制項owner-drawn Control 解析 ANSI escape,雙緩衝繪字格
Script 引擎 TTLInterpreterLib(從 MyTeraTerm 移植 + 擴充) 改為驅動 ISessionChannel 而非 com0com bridge
連線儲存 SQLiteMicrosoft.Data.Sqlite 取代 KKTerm 的 SQLite store;存連線 metadata
祕密儲存 Windows Credential ManagerDPAPI / CredMan 連線密碼、SSH key passphrase,不落地明碼
PDU 控制(選用) SnmpSharpNet 沿用 MyTeraTerm PDU 控制(pductrl / pduconnect
日誌 自製 AppLogger(從 MyTeraTerm 移植) 檔案 + Debug 雙輸出
AI / MCP 整合(選用) stdio MCP server(官方 C# SDK ModelContextProtocol 兩個獨立 serverETTerms.SerialMcp(不自己開 port,經本機 named pipe 橋接 GUI 持有的 serial session)與 ETTerms.PduMcp(直接打 SNMP 控制 PDU 插座,不需 GUI);把收發 / 電源控制暴露成 AI 可呼叫工具(Kiro CLI / Claude CLI),見 AI / MCP Integration
打包 dotnet publish + (選用)Inno Setup / MSIX 單機安裝,current-user

與舊版 MyTeraTerm 的關鍵差異: 舊版是把真正的 ttermpro.exeTeraTerm)嵌進 Panel,靠 com0com 虛擬 COM 對攔截 serial 來跑腳本。ETTerms 改走全原生SSH.NET 做 SSH、System.IO.Ports 做 serial、自繪 VT100 控制項做終端機畫面,不再依賴外部 TeraTerm exe,也不再需要 com0com。腳本引擎從「驅動 com0com bridge」改成「驅動原生 ISessionChannel」。


Architecture Diagram

┌──────────────────────────────────────────────────────────────────────┐
│  MainForm (WinForms Shell)                                             │
│                                                                        │
│  ┌────────────┐ ┌──────────────────┐ ┌────────────────────────────┐  │
│  │ Activity   │ │ Connection       │ │  Tabbed Workspace          │  │
│  │ Rail       │ │ Sidebar          │ │  (一個 Tab = 一條 Session) │  │
│  │ (左側圖示) │ │ (Saved           │ │                            │  │
│  │            │ │  Connections)    │ │  ┌──────────────────────┐  │  │
│  │ ▣ Terminal │ │  ▸ SSH: srv-01   │ │  │ TerminalView         │  │  │
│  │ ▣ Scripts  │ │  ▸ SSH: nas      │ │  │ (自繪 VT100 控制項)  │  │  │
│  │ ▣ Settings │ │  ▸ COM3 @115200  │ │  │                      │  │  │
│  │            │ │  ▸ COM7 @9600    │ │  │  bytes ↑↓            │  │  │
│  └────────────┘ └──────────────────┘ │  └──────────┬───────────┘  │  │
│                                       └─────────────┼──────────────┘  │
└─────────────────────────────────────────────────────┼─────────────────┘
                                                       │
                          ┌────────────────────────────┼───────────────┐
                          │  ISessionChannel (抽象)     │               │
                          │   ├─ SshChannel  (SSH.NET) ─┘               │
                          │   └─ SerialChannel (System.IO.Ports)        │
                          └──────────────┬──────────────────────────────┘
                                         │ Write(bytes) / DataReceived(bytes)
                          ┌──────────────┴──────────────────────────────┐
                          │  ScriptEngine (TTLInterpreter, ported)       │
                          │   send / sendln / wait / if / while /        │
                          │   logopen / messagebox / pductrl ...         │
                          └──────────────┬──────────────────────────────┘
                                         │ (選用)
                                  ┌──────┴───────┐
                                  │ SNMP PDU     │ (SnmpSharpNet)
                                  └──────────────┘

資料流核心抽象: 所有連線都實作 ISessionChannelWrite(byte[]) + event DataReceived)。TerminalViewScriptEngine 都只認得這個抽象,因此 SSH 與 Serial 對上層完全一致——這是讓「同一套腳本引擎驅動兩種連線」的關鍵設計。


Project Structure

ETTerms/
│
├── CLAUDE.md                       # 專案記憶 & 給 Claude 的指令
├── README.md                       # 快速上手、打包說明
├── ARCHITECTURE.md                 # 本文件
├── .gitignore                      # 含 For_AI/ 與 build 產物規則
├── ETTerms.sln
│
├── docs/
│   ├── architecture.md             # (本文件副本 / 連結)
│   ├── ttl-script-reference.md     # TTL 指令對照表(移植自 MyTeraTerm
│   ├── decisions/                  # ADR:為何走原生而非嵌 TeraTerm
│   └── runbooks/                   # 操作手冊、常見問題(無實際密碼)
│
├── .claude/
│   ├── settings.json
│   └── skills/
│
├── tools/
│   ├── scripts/                    # 建置 / 打包腳本
│   └── prompts/
│
├── For_AI/                         # 🚫 gitignored — AI 協作素材
│   ├── KKTerm-main/                #   UI 參考專案(Tauri/React 工作台)
│   └── MyTeraTerm/                 #   Script 參考專案(舊版 WinForms
│
└── src/
    ├── ETTerms/                    # 主應用程式(WinForms
        │
        ├── Program.cs              # 進入點
        ├── ETTerms.csproj          # net8.0-windows, UseWindowsForms
        │
        ├── App/                    # ── 視窗外殼 (UI Shell) ──
        │   ├── MainForm.cs         #   主視窗:Rail + Sidebar + Workspace(含深色標題列 DWM
        │   ├── MainForm.Designer.cs
        │   ├── Theme.cs            #   全域深色配色 (KKTerm 風格)
        │   ├── ActivityRail.cs     #   左側圖示列 (Terminal/Status/Settings/About)
        │   ├── ConnectionSidebar.cs#   仿 KKTerm 可編輯資料夾樹(搜尋/CRUD/拖曳分類)
        │   ├── StatusView.cs       #   Status 檢視:分頁式(PDU…),PDU 連線後每 3 秒背景輪詢插座狀態,並可用表格內 Control 鈕直接開關各 Port
        │   ├── SettingsView.cs     #   Settings 檢視:分頁式(Terminal / AI MCP
        │   ├── AboutView.cs        #   About 檢視(版本 / 連結)
        │   ├── Dialogs/            #   ── 深色對話框 ──
        │   │   ├── DarkDialog.cs       #   對話框基底(深色 + DWM 標題列)
        │   │   ├── TextPromptDialog.cs #   單行輸入(資料夾命名 / 改名)
        │   │   └── ConnectionEditDialog.cs # 連線新增/編輯(名稱+類型+詳細,Phase 2 擴充)
        │   └── Workspace/          #   ── 可平鋪 (tiling) 的工作區 ──
        │       ├── WorkspaceView.cs    #   工具列(grid 預設) + split 樹管理 + active pane 路由
        │       ├── PaneControl.cs      #   單一格子:自繪迷你分頁列 + 內容 + +↔↕✕ 動作鈕
        │       └── ProportionalSplit.cs#   按比例縮放的 SplitContainer (巢狀組成任意佈局)
        │
        ├── Terminal/               # ── 終端機渲染 ──
        │   ├── TerminalView.cs     #   自繪 VT100 控制項 (owner-drawn)
        │   ├── DarkScrollBar.cs    #   自繪深色垂直捲軸 (細長/圓角滑塊, 配深色主題)
        │   ├── AnsiParser.cs       #   ANSI/VT100 escape 解析狀態機 (含 DEC 2004 bracketed paste)
        │   ├── ScreenBuffer.cs     #   字格緩衝 (rows×cols, 屬性/顏色)
        │   └── TerminalInput.cs    #   鍵盤 → byte 序列 (含特殊鍵)
        │
        ├── Sessions/               # ── 連線抽象 ──
        │   ├── ISessionChannel.cs  #   Write(byte[]) + event DataReceived
        │   ├── SshChannel.cs       #   SSH.NET 實作 (ShellStream)
        │   ├── SerialChannel.cs    #   System.IO.Ports 實作
        │   ├── ShellChannel.cs     #   Windows ConPTY 本機 ShellStartupDirectory 不存在時 fallback 使用者家目錄)
        │   ├── SessionPage.cs      #   一個分頁 = TerminalView + Channel + 狀態
        │   ├── SessionManager.cs   #   開 / 關 / 列舉所有 active session
        │   ├── SerialBridgeServer.cs# ✅ 本機 named pipe server:把 serial session 的讀寫橋接給 MCPPhase 9
        │   └── SerialBridge.cs     # ✅ SerialBridgeEndpoint:單一 serial session 與 pipe 的橋接點
        │
        ├── Connections/            # ── 連線資料 ──
        │   ├── Connection.cs       #   連線 metadata 模型
        │   ├── ConnectionStore.cs  #   SQLite CRUD
        │   └── CredentialVault.cs  #   Windows Credential Manager 封裝
        │
        ├── Scripting/              # ── TTL 腳本引擎(移植 + 擴充)──
        │   ├── TTLInterpreter.cs   #   主直譯器 (port 自 MyTeraTerm)
        │   ├── ScriptRunner.cs     #   非同步執行 + 取消 + 進度事件
        │   ├── GroupSyncContext.cs  #   Group 同步 (Barrier)waitall / sendlnall / sendlngroup
        │   └── Pdu/
        │       └── PduController.cs#   SnmpSharpNet PDU 控制 (pductrl / pduconnect)
        │
        └── Infrastructure/
            ├── AppLogger.cs        #   日誌 (port 自 MyTeraTerm)
            ├── AppSettings.cs      #   使用者偏好 (JSON, %LocalAppData%\ETTerms\settings.json)
            ├── McpRegistrar.cs     # ✅ 一鍵把 Serial MCP 註冊/移除到 Claude Code / Kiro 設定檔(Settings → AI MCP
            └── NativeTheme.cs      #   深色標題列 (DWM)
    │
    └── ETTerms.SerialMcp/          # ✅ Serial MCP serverstdio)——不自己開 port,經 named pipe 橋接 GUI
        ├── Program.cs              #   stdio MCP host 進入點
        ├── SerialBridgeClient.cs   #   連 GUI 的 named pipe,轉發 write / 接收 RX
        ├── SerialTools.cs          #   serial_list / attach / write / read / detach 工具(轉發到 pipe
        └── ETTerms.SerialMcp.csproj#   net8.0 console + ModelContextProtocol SDK

For_AI/ 內含兩份參考專案KKTerm-mainUI 參考,Tauri+React 的 Windows 工作台)與 MyTeraTermScript 參考,舊版嵌 TeraTerm 的 WinForms)。整個 For_AI/ 已 gitignore,僅供開發時對照,不進 repo。

secret/ 資料夾: ETTerms 是桌面單機 App沒有 DB 密碼 / 連線字串 / API key 之類的伺服端祕密,也無 compile-time secret。連線密碼一律存 Windows Credential Manager(不落地明碼),因此不需要 secret/ 集中管理機制。


Data Models

連線 metadata 存在本機 SQLite%LocalAppData%\ETTerms\ettermsdb.sqlite)。密碼 / passphrase 不存在這裡,只存一個指向 Windows Credential Manager 的 CredentialKey

public enum ConnectionType
{
    Ssh = 0,
    Serial = 1
}

// 主連線模型
public class Connection
{
    public Guid Id { get; set; }
    public string Name { get; set; } = "";        // 顯示名稱,例:srv-01 / COM3 board
    public ConnectionType Type { get; set; }
    public int SortOrder { get; set; }              // sidebar 排序
    public string? GroupName { get; set; }          // 選用:分組 (folder)
    public DateTime LastUsedUtc { get; set; }

    // SSH 專用(Type == Ssh 時有效)
    public SshSettings? Ssh { get; set; }
    // Serial 專用(Type == Serial 時有效)
    public SerialSettings? Serial { get; set; }

    // 指向 Windows Credential Manager 的 key,例:"ETTerms/{Id}"
    // 明碼密碼絕不存進 SQLite
    public string? CredentialKey { get; set; }
}

public class SshSettings
{
    public string Host { get; set; } = "";
    public int Port { get; set; } = 22;
    public string Username { get; set; } = "";
    public SshAuthMethod AuthMethod { get; set; }   // Password / PrivateKey / KeyboardInteractive
    public string? PrivateKeyPath { get; set; }     // key 檔路徑(passphrase 走 CredentialVault
}

public enum SshAuthMethod { Password = 0, PrivateKey = 1, KeyboardInteractive = 2 }

public class SerialSettings
{
    public string PortName { get; set; } = "COM1";  // COM3, COM7...
    public int BaudRate { get; set; } = 115200;
    public int DataBits { get; set; } = 8;
    public Parity Parity { get; set; } = Parity.None;     // System.IO.Ports.Parity
    public StopBits StopBits { get; set; } = StopBits.One;
    public Handshake Handshake { get; set; } = Handshake.None;
    public string NewLine { get; set; } = "\r\n";   // 送出換行序列
}

// 終端機偏好(存 AppSettings,非每連線)
public class TerminalProfile
{
    public string FontFamily { get; set; } = "Cascadia Mono";
    public float FontSize { get; set; } = 11f;
    public int Cols { get; set; } = 80;
    public int Rows { get; set; } = 24;
    public string Theme { get; set; } = "dark";      // 配色名稱
    public int ScrollbackLines { get; set; } = 5000;
}

SQLite Schema(單表即可起步):

欄位 型別 說明
Id TEXT (GUID) 主鍵
Name TEXT 顯示名稱
Type INTEGER 0=Ssh, 1=Serial
SortOrder INTEGER sidebar 排序
GroupName TEXT NULL 分組
LastUsedUtc TEXT ISO8601
SettingsJson TEXT SshSettings / SerialSettings 序列化
CredentialKey TEXT NULL Credential Manager 索引鍵

Authentication & Authorization

不適用。 ETTerms 是單機桌面工具,沒有使用者帳號 / 登入 / 角色系統。

唯一相關的「認證」是對外連線時的 SSH 認證password / private key / keyboard-interactive),其憑證透過 Windows Credential Manager 儲存與讀取,由 CredentialVault.cs 封裝。詳見 Security Considerations


Key Pages / Features

ETTerms 是單視窗多分頁,沒有「路由」,以下以功能面板為單位描述。

Activity Rail(左側圖示列)

  • 切換主檢視:Terminal(連線工作區)/ Scripts(腳本編輯與執行)/ Settings(偏好設定)
  • 仿 KKTerm 的 ActivityRailhover 顯示 tooltip

Connection SidebarSaved Connections,仿 KKTerm 資料夾樹)

  • 使用者可自建資料夾,把連線分類組織成任意層的目錄樹(資料夾可巢狀)
  • 每個資料夾顯示連線數量徽章、可展開 / 收合(工具列有「全部展開 / 收合」)
  • 搜尋框:依名稱 / 主機即時過濾,命中的分支自動展開
  • 圖示區分 SSH / Serial,顯示主機或 COM port + baud
  • 操作(右鍵選單 + 工具列按鈕):新增資料夾 / 新增連線 / 重新命名 / 刪除
  • 拖曳分類:把連線或資料夾拖進別的資料夾(禁止拖進自己的子孫)
  • 雙擊連線 → 在 active pane 開啟;「快速連線」→ 不存檔的 ad-hoc 連線
  • Phase 1 資料存記憶體;Phase 2 換成 ConnectionStoreSQLite)持久化

Workspace(可平鋪 tiling 的工作區)

  • 工作區可分割成多個 pane(格子),自由排列(仿 KKTerm grid):
    • Grid 預設:工具列一鍵切 1×1 / 1×2 / 2×1 / 2×2 / 2×3 / 3×3
    • 手動分割:每個 pane 右上角 (左右分割)/ (上下分割),拖格線(ProportionalSplit)按比例調整大小
    • 關閉某格時,兄弟節點自動補位(collapse split);保留至少一格
  • 每個 pane 內可再開多條連線分頁pane 自己的迷你 tab strip
  • active pane 以強調色外框標示;側欄雙擊連線會開進 active pane
  • 一條連線分頁 = SessionPageTerminalView + ISessionChannelPhase 3+ 接上)

Terminal View(自繪 VT100

  • 接收 channel bytes → AnsiParserScreenBuffer → 繪製
  • 鍵盤輸入 → TerminalInput → byte 序列 → channel
  • 支援:scrollback、選取 / 複製、貼上、字型 / 配色(從 TerminalProfile
  • 捲動: 滑鼠滾輪或右側自繪深色捲軸 DarkScrollBar(拖曳滑塊 / 點軌道翻頁);ContentWidth 扣掉捲軸寬避免文字被蓋,捲軸範圍 / 位置在 Feed / 滾輪 / resize 時同步
  • 貼上: 對方啟用 bracketed pasteDEC mode 2004,如 PSReadLine / Kiro CLI)時,整段以 ESC[200~ … ESC[201~ 包夾送出,避免多行貼上被逐行 Enter 立即送出;未啟用則逐字送出
  • 複製: 右鍵複製選取內容後自動清除反白(提示已複製)

Script Editor / RunnerScripts 檢視)

  • 載入 / 編輯 .ttl 腳本(語法沿用 MyTeraTerm
  • 對「目前 active session」執行腳本;顯示執行進度(檔名 / 行號 / 當前指令)
  • 可取消執行(Cancel());logopen 將輸出寫檔
  • sprintf2C printf 風格格式化輸出到變數(TeraTerm 相容)
  • wait:命中關鍵字後會等裝置安靜(SettleMs,預設 300ms)再接受並取最後一次出現,避免比對到輸出中途的指令回顯
  • 選用:PDU 控制指令(pductrl / pduconnect)走 SNMP

Group 同步執行

  • 分頁可透過右鍵 Tab → 設為 Group 1 / 2 / 3(或取消),cell footer 顯示 [Group1-A] 標籤
  • Toolbar 的 ▶ Group1 / ▶ Group2 / ▶ Group3 按鈕對整個 Group 同時跑同一份 .ttl 腳本
  • Group 模式支援同步指令:waitall(全員 wait 到關鍵字再繼續)、sendlnall(全員到齊後各自 sendln)、sendlngroup(指定 member 才送)
  • ▶ Run All 和分頁 ▶ Script 會拒絕含 Group 指令的腳本(彈 Warning
  • 同步機制使用 System.Threading.BarrierGroupSyncContext),確保成員在同步點等齊

Settings

  • 終端機字型 / 字級 / 配色 / scrollback 行數
  • 預設換行序列、編碼
  • 視窗位置記憶

Data Flow

SSH session 端到端:

使用者雙擊 Sidebar 連線
  → SessionManager.Open(connection)
  → CredentialVault.Get(connection.CredentialKey)         讀密碼
  → new SshChannel(SshSettings, credential)
      → SSH.NET SshClient.Connect()
      → ShellStream 建立
  → new SessionPage(TerminalView, channel)  加入 WorkspaceTabs

執行期雙向資料流:
  鍵盤 → TerminalInput → bytes → SshChannel.Write() → ShellStream
  ShellStream → SshChannel.DataReceived(bytes) → TerminalView
      → AnsiParser → ScreenBuffer → Invalidate() → 繪製

腳本驅動流(與互動式共用同一 channel):

ScriptRunner.RunAsync(scriptText, activeChannel)
  → TTLInterpreter(channel)
      send/sendln  → channel.Write(bytes)
      wait "xxx"   → 監聽 channel.DataReceived,比對到關鍵字後再等裝置「安靜」(~300ms 無新資料) 才接受,
                     並消費到該字串「最後一次」出現處 → 避免命中輸出中途的指令回顯(如 SVOS> help
      sprintf2     → C printf 風格格式化字串存入變數(與 TeraTerm 相容,設定 result
      logopen/write→ StreamWriter 寫檔
      pductrl      → PduControllerSNMP set)→ PDU
      if/while     → 依 result / 變數做流程控制
  → StatusChanged 事件 → UI 顯示「檔名 第N行 指令」

Serial session 與 SSH 相同,只是 ISessionChannel 換成 SerialChannelSystem.IO.Ports.SerialPortDataReceived / Write)。上層 TerminalViewTTLInterpreter 完全不需改動——這正是 ISessionChannel 抽象的價值。


AI / MCP IntegrationSerial MCP + PDU MCP Server

ETTerms 提供兩個獨立的 stdio MCP server給 AI agentKiro CLI / Claude CLI):

  • ETTerms.SerialMcp — 收發 serial。COM port 獨佔,故由 GUI 唯一持有、MCP 經本機 named pipe 橋接(見下方)。
  • ETTerms.PduMcp — 控制 SNMP PDU 電源插座。SNMP(UDP) 非獨佔,故 MCP 直接打 SNMP,不需 GUI 在跑、也不經 pipe。

兩者都能用 GUI Settings → AI MCP 一鍵 SetupMcpRegistrar 會同時註冊 etterms-serialetterms-pdu)。

Serial MCP Server

Kiro CLI / Claude CLI 等 AI agent 收發 serial且使用者能在 ETTerms GUI 即時看到 AI 的每筆收發

關鍵設計:COM port 由 GUI 唯一持有,MCP server 不自己開 port。 一個 COM port 同一時間只能被一個行程開啟;若讓 MCP server 自己開,GUI 就無法同時開、使用者也看不到。因此改成 GUI 當 port 的唯一擁有者,在 GUI 內跑一支本機 named pipe serverSerialBridgeServer);獨立的 ETTerms.SerialMcp(由 Kiro/Claude CLI 啟動)退化成瘦客戶端,所有 write / read 都經 pipe 轉發給 GUI,由 GUI 代為讀寫實體 port。

全閉迴路(推薦用法)

整個迴路可全部跑在 ETTerms GUI 內,使用者一邊看、AI 一邊操作:

ETTerms GUI(單一行程,唯一開 COM3 的人)
│
├─ Tab1: Serial 連線 ── SerialChannel 實體持有 COM3
│        TerminalView 即時顯示(AI 的 TX 以 [AI] 標色,RX 照常顯示)
│
├─ SerialBridgeServer(本機 named pipe: \\.\pipe\etterms-serial
│        ▲  write 轉發 / RX 廣播
│        │
└─ Tab2: PowerShell (ConPTY) 跑 kiro-cli
         └─ kiro 啟動子行程 ETTerms.SerialMcpstdio / JSON-RPC
                └─ 不開 COM,連上面的 pipe → 收發都流經 GUI 的 channel

資料流:

  • AI 送資料: serial_write → pipe → GUI SerialChannel.Write() 送出 COM3同時把這段 echo 進 Tab1 TerminalView[AI] 標色) → 使用者看得到 AI 打了什麼。
  • 裝置回資料: COM3 RX → GUI 一邊顯示在 Tab1、一邊經 pipe 廣播 → serial_read 取出 → AI 讀到。

因為 RX/TX 物理上都流經 GUI 的 channel使用者在 GUI 看到的就是 AI 看到的,完全同步。

暴露的工具

工具 參數 說明
serial_list 列出 GUI 目前開著的 serial session(名稱 + COM port + baud),供 AI 選定要操作哪一個
serial_attach portName | sessionName 經 pipe 綁定到 GUI 某個已開啟的 serial session(之後 read/write 都對它)
serial_write text, appendNewLine? 經 pipe 請 GUI 對綁定的 session 送出文字(GUI 同步 echo 到 TerminalView
serial_read waitFor?, timeoutMs? 取出該 session 累積的 RX;可等待特定字串或逾時
serial_detach 解除綁定(不關閉 GUI 的 portGUI 仍持有)

與舊版規劃的差異:不再有「MCP 自己 serial_open / serial_close 實體 port」;改為 serial_attach / serial_detach 綁定 / 解除 GUI 既有 session。port 的開關一律在 GUI 操作。

named pipe 協議(精簡)

  • 傳輸: Windows named pipe\\.\pipe\etterms-serial),純本機、不開網路埠。
  • 訊息: 換行分隔的 JSON,例:{"op":"write","session":"COM3","data":"...","newline":true} / {"op":"read","session":"COM3","waitFor":"OK","timeoutMs":3000} / {"op":"list"}
  • RX 推送: GUI 主動把 RX 以 {"op":"rx","session":"COM3","data":"..."} 推給已連線的 clientclient 端累積成 buffer 供 serial_read 消費。
  • 找不到 session AI attach / write 一個 GUI 沒開的 port 時,回明確錯誤(要求使用者先在 GUI 開啟)。

設計重點

  • 技術: ETTerms.SerialMcp 為 .NET 8 consolenet8.0,無 WinForms+ 官方 C# MCP SDKModelContextProtocol),stdio / JSON-RPCGUI 端的 SerialBridgeServerSystem.IO.Pipes
  • port 擁有權單一化: 實體 SerialPort 只有 GUI 開,根除「兩個行程搶同一 COM」的問題。
  • 可視性: AI 的 TX 在 GUI 以 [AI] 標色,與使用者手打的輸入區分;RX 兩邊同源。
  • 安全: 本機、無雲、不碰 credential;pipe 僅限本機行程,只搬 serial bytes。

註冊(兩種方式)

方式 A — 一鍵設定(推薦,v0.2.1): GUI Settings → AI MCP 分頁,對 Claude Code / Kiro 各按 Setup 即可。McpRegistrar 以 read-modify-write 把 etterms-serial 寫進該 CLI 的使用者層級設定檔(Claude Code:~/.claude.jsonKiro~/.kiro/settings/mcp.json),保留檔內其他既有 MCP server,原子寫回避免壞檔。註冊的執行檔路徑指向 <ETTerms.exe>\ETTerms.SerialMcp\ETTerms.SerialMcp.exe(與 publish 慣例對齊,必定存在);卡片同時顯示 CLI 驗證指令,按 Remove 可移除。

方式 B — 手動 CLI

kiro-cli mcp add --name serial --command dotnet `
  --args "run --project src\ETTerms.SerialMcp\ETTerms.SerialMcp.csproj"

或寫進 agent.json 的 mcpServersClaude CLI 則用其對應的 mcpServers 設定。使用前提:先在 ETTerms GUI 開好要操作的 serial 連線AI 才能 serial_attach 上去。註冊後即可對 AI 說「列出目前 serial session → 接上 COM3 → 送指令看回應」。

PDU MCP Serverv0.3.0

讓 AI agent 直接控制 SNMP PDU 的電源插座,典型用途:測試中自動 power-cycle DUT

關鍵設計:直接打 SNMP,不經 GUI 橋接。 與 serial 不同,PDU 走 SNMPUDP非獨佔——多個行程可同時對同一台 PDU 下命令。因此 ETTerms.PduMcp 不需要像 serial 那樣繞 GUI 的 named pipe,而是內含一份精簡版 PduControllerOID 邏輯複製自 GUI 的 Scripting/Pdu/PduController,診斷改走 stderr 以免污染 stdio JSON-RPC)直接與 PDU 對話。好處:GUI 不必開著,AI 也能控制 PDU;最少程式碼、最穩。

Kiro/Claude CLI ── 啟動子行程 ETTerms.PduMcpstdio / JSON-RPC
                        └─ SnmpSharpNet ──(SNMP/UDP 161)──► PDUiPoMan II/III

連線狀態(device IP → controller)以行程內單例 PduRegistry 保存,跨工具呼叫保留,直到 pdu_disconnect 或行程結束。

暴露的工具:

工具 參數 說明
pdu_connect ip 以 SNMP 連線並驗證 PDU 回應,成功回傳 model name;控制前必須先呼叫
pdu_list 列出本 session 已連線的 PDU(依 IP
pdu_set_port ip, port, on 將某插座開(on=true)/關(off=false)
pdu_get_port ip, port 讀單一插座的狀態 / 電流(mA) / 功率(W)
pdu_status ip 讀全部 12 個插座的狀態 / 電流 / 功率
pdu_power_cycle ip, port, offSeconds? 關 → 等 offSeconds → 開(重啟 DUT
pdu_disconnect ip 解除本 session 的 PDU 連線(不改變插座狀態)

所有工具回傳統一的 { "ok": bool, "result"/"error": ... } JSON。SNMP community 目前沿用 GUI 版的 "private"


Key Constraints & Business Rules

  1. 單機、無雲: 所有連線 metadata 存本機 SQLite,密碼存 Windows Credential Manager,不回傳任何遙測。
  2. 密碼絕不落地明碼: SQLite 只存 CredentialKey,實際密碼 / passphrase 一律走 Credential Manager。
  3. 一條連線一個分頁: 同一連線可開多個分頁(各自獨立 session),但每個分頁綁定一個 ISessionChannel
  4. 腳本對 active session 執行: TTL 腳本只作用在目前選定的分頁 channel,不會跨分頁亂送。例外:Group 模式waitall / sendlnall / sendlngroup 可跨同 Group 成員同步。
  5. 腳本可取消: 長時間 wait / while 必須能被使用者中止(isCancelled 旗標 + OperationCanceledException)。
  6. Serial port 互斥: 一個 COM port 同時只能被一個 session 開啟;開啟前需檢查可用性。
  7. VT 相容性以常見情境為準: VT100 / 常見 ANSI 序列優先;冷門 escape 可後補,不阻塞 GUI 進度。
  8. GUI 先行: Phase 1–2 必須先讓視窗外殼 + 分頁 + 假連線可見可操作,再接真實 channel。
  9. 不依賴外部 exe 不嵌 TeraTerm、不需 com0com;全原生 .NET 元件。
  10. UI 不可被 channel I/O 阻塞: channel 讀寫在背景,UI 更新一律 Invoke 回 UI thread。

Security Considerations

  • 密碼儲存: 一律使用 Windows Credential Manager(透過 CredentialVault.cs)。SQLite 內只存索引 CredentialKey,無明碼。SSH private key passphrase 同理。
  • SSH host key 驗證: 首次連線顯示 host key 指紋供使用者確認(trust-on-first-use),記錄已信任的指紋,之後比對;指紋不符要警告。
  • 私鑰檔保護: private key 路徑存設定,但不複製 key 內容進 repo / SQLite。
  • 輸入處理: 終端機輸入直接透傳給遠端,不做 shell 注入解讀(本來就是終端機);但 UI 載入腳本檔時要防路徑穿越 / 過大檔。
  • 日誌不含密碼: AppLoggerlogopen 輸出不可寫入密碼 / passphrase;連線資訊只記主機 / port,不記 credential。
  • secret/ 資料夾: ETTerms 無伺服端祕密 / DB 密碼 / compile-time secret,連線密碼一律走 Windows Credential Manager,因此不設 secret/ 集中目錄,也不需要 publish 類腳本。若日後做 Release 程式碼簽章,簽章 .pfx 請放在 repo 外並以環境變數 / CI secret 傳入。
  • 設定檔權限: SQLite 與設定檔放在 %LocalAppData%\ETTerms\,跟隨使用者帳號 ACL。

Build & Setup Steps

# 0. 前置:.NET 8 SDK(或 SDK 9/10 + .NET 8 Desktop Runtime)。確認:
dotnet --list-sdks
dotnet --list-runtimes | findstr WindowsDesktop   # 需有 8.0.x

# 1. 建立方案與專案(Phase 1)
cd F:\10_AI\ETTerms
dotnet new sln -n ETTerms
dotnet new winforms -n ETTerms -o src\ETTerms -f net8.0
dotnet sln add src\ETTerms\ETTerms.csproj

# 2. 安裝 NuGet 套件
cd src\ETTerms
dotnet add package SSH.NET                      # 原生 SSH
dotnet add package System.IO.Ports              # Serial
dotnet add package Microsoft.Data.Sqlite        # 連線 metadata
dotnet add package SnmpSharpNet                 # 選用:PDU 控制
# Windows Credential Manager:用 CredentialManagement 套件或 P/Invoke advapi32

# 3. 設定 csproj(手動確認)
#    <TargetFramework>net8.0-windows</TargetFramework>
#    <UseWindowsForms>true</UseWindowsForms>
#    <Nullable>enable</Nullable>

# 4. 建置與執行
cd F:\10_AI\ETTerms
dotnet build
dotnet run --project src\ETTerms\ETTerms.csproj

# 5. 打包(見下方「Publish / 打包慣例」)
dotnet publish src\ETTerms\ETTerms.csproj -c Release -r win-x64 --self-contained false `
    -o src\ETTerms\Publish\ETTerms_v<Version>
#    後續可用 Inno Setup / MSIX 做安裝程式

Publish / 打包慣例

每次發 Release 都依此規則產出,方便辨識版本與一併攜帶 MCP server。

輸出位置(固定): src\ETTerms\Publish\ETTerms_v{Version}\

  • {Version} 取自 src\ETTerms\ETTerms.csproj<Version>(例:0.2.0)。
  • 資料夾命名:ETTerms_v{Version}(前綴 v,例:ETTerms_v0.2.0)。
  • Publish/ 已 gitignorepublish/),不入 git

內容結構:

ETTerms_v0.3.0\
├── ETTerms v0.3.0.exe        # 主程式 apphost,改名為「ETTerms v{Version}.exe」
├── ETTerms.dll + 各相依 dll  # SSH.NET / SQLite / SnmpSharpNet / System.IO.Ports …
├── ETTerms.SerialMcp\        # Serial MCP server,獨立發佈到子資料夾(相依 dll 與 GUI 隔離)
│   ├── ETTerms.SerialMcp.exe
│   └── ETTerms.SerialMcp.dll + 相依
└── ETTerms.PduMcp\           # PDU MCP serverv0.3.0),同樣獨立發佈到子資料夾
    ├── ETTerms.PduMcp.exe
    └── ETTerms.PduMcp.dll + 相依(含 SnmpSharpNet

規則:

  1. GUI publish 會自動帶上兩個 MCP serverETTerms.csprojPublishMcpServers targetAfterTargets="Publish"),會把 ETTerms.SerialMcpETTerms.PduMcp 一併發佈到各自的 <publish>\<server>\ 子資料夾(與 GUI 相依 dll 隔離)。因此只要發佈 GUI 一個指令即可,不必再單獨發 MCP。
    • 對齊 McpRegistrar.ResolveServerExe():它解析的 <ETTerms.exe>\<server>\<server>.exe 因此必定存在,AI MCP 一鍵設定寫進去的路徑才不會落空。
    • MCP 子發佈會跟隨 GUI 的 SelfContained 設定target 內以 $(SelfContained) 傳入):框架相依版的 MCP 也框架相依;portable 版的 MCP 也免 runtime。
  2. 主 exe 改名dotnet publish 產生的 ETTerms.exe 重新命名為 ETTerms v{Version}.exe
    • 可安全改名:.NET apphost 內部記錄要載入的 ETTerms.dll不靠自身檔名,改名後仍正常啟動。

兩種發佈版本(兩個都要產出)

版本 資料夾 指令旗標 需 .NET Runtime 用途
A. 框架相依(預設) ETTerms_v{Version}\ --self-contained false 需先裝 .NET 8 Desktop Runtime 體積小;給已具備 runtime 的環境
B. Portable(免安裝) ETTerms_v{Version}_portable\ --self-contained true 不需要,runtime 已內含 體積大(約 240MB);給受 MIS 管控、不便裝 runtime 的環境,解壓即用、免系統管理員權限

⚠️ 不要開 trimmingPublishTrimmed):WinForms 大量用反射,trim 後易在執行時出錯。

PowerShell 範例(一次產出兩種):

$ver = ([regex]::Match((Get-Content src\ETTerms\ETTerms.csproj -Raw), '<Version>([^<]+)</Version>')).Groups[1].Value

# A. 框架相依版 → ETTerms_v{Version}\
$root = "src\ETTerms\Publish\ETTerms_v$ver"
if (Test-Path $root) { Remove-Item $root -Recurse -Force }
dotnet publish src\ETTerms\ETTerms.csproj -c Release -r win-x64 --self-contained false -o $root
Rename-Item (Join-Path $root "ETTerms.exe") "ETTerms v$ver.exe"

# B. Portable 免安裝版 → ETTerms_v{Version}_portable\runtime 已內含;MCP 也跟著 self-contained
$proot = "src\ETTerms\Publish\ETTerms_v${ver}_portable"
if (Test-Path $proot) { Remove-Item $proot -Recurse -Force }
dotnet publish src\ETTerms\ETTerms.csproj -c Release -r win-x64 --self-contained true -o $proot
Rename-Item (Join-Path $proot "ETTerms.exe") "ETTerms v$ver.exe"

兩版的 ETTerms.SerialMcp\ETTerms.PduMcp\ 子資料夾都由 PublishMcpServers target 自動產生;portable 版的 MCP 也是 self-contained,故 AI MCP 功能在無 runtime 環境同樣可用。


Development Phases

依使用者要求「前面先把 GUI 做出來,後面再慢慢補功能」排序: Phase 1–2 先把 KKTerm 風格的視窗外殼、分頁、假連線清單做到「看得到、點得動」, Phase 3 起才接真實 Serial / SSH channel,最後補腳本引擎與打包。

Phase 1 — 專案骨架 + UI Shell(工作量:S) 已完成

目標: 專案能 dotnet run 啟動,KKTerm 風格的主視窗外殼可見:左側 Activity Rail、連線 Sidebar、右側分頁工作區(先放假分頁)。 包含:

  • dotnet new winforms 建立 src/ETTerms,設定 net8.0-windows / UseWindowsForms / Nullable
  • MainForm.cs + MainForm.Designer.cs:三欄佈局(Rail / Sidebar / Workspace
  • ActivityRail.csTerminal / Scripts / Settings 三個圖示按鈕(hover tooltip
  • ConnectionSidebar.cs:用假資料填 TreeViewSSH / Serial 圖示)+資料夾樹 / 搜尋 / CRUD / 拖曳分類(提前實作)
  • Workspace/WorkspaceView.cs(取代原訂 WorkspaceTabs.cs):可平鋪 tiling 工作區(grid 預設 + 手動分割 + pane 內迷你分頁),提前實作 Future Extension 的分割畫面
  • AppLogger.cs:從 MyTeraTerm 移植日誌
  • 深色主題:Theme.cs + NativeTheme.ApplyDarkTitleBar(DWM 深色標題列)+ 深色對話框基底 驗收條件: dotnet build 通過(0 警告 0 錯誤);主視窗出現,可在 Rail 切檢視、Sidebar 看到假連線、可開關分頁與分割工作區。

Phase 2 — 連線資料 + Sidebar 真資料(工作量:M) 已完成

目標: 連線清單改吃 SQLite 真資料,可新增 / 編輯 / 刪除連線,密碼存進 Credential Manager。 包含:

  • Connection.csConnection / SshSettings / SerialSettings / ConnectionType / SshAuthMethod 模型
  • ConnectionStore.csSQLite CRUD%LocalAppData%\ETTerms\ettermsdb.sqlite 自動建表,SettingsJson 存 Ssh/Serial
  • CredentialVault.csWindows Credential Manager 讀寫封裝(advapi32 P/InvokeCredWrite/CredRead/CredDelete
  • 連線編輯對話框:依類型切換 SSHhost/port/user/auth/key/password)與 SerialCOM/baud/databits/parity/stopbits/handshake)兩種表單
  • Sidebar 綁定 ConnectionStore,支援新增 / 編輯 / 刪除 / 拖曳分組 / SortOrder 排序持久化(資料夾路徑存於 GroupName 驗收條件: 新增一條 SSH 與一條 Serial 連線、重啟 App 後仍在;密碼存在 Credential ManagerSQLite 內看不到明碼)。

實作備註: 資料夾以連線的 GroupName/-join 路徑)持久化;含連線的資料夾會在重啟後由路徑重建,空資料夾為 session-only(不另設 folders 表)。密碼一律經 CredentialVault 寫入 Credential ManagerSQLite 僅存 CredentialKeyETTerms/{Id})。

Phase 3 — Serial Port Session(工作量:M 已完成

目標: 雙擊 Serial 連線可開分頁、收發資料;先用最陽春的文字框驗證資料流。 包含:

  • Sessions/ISessionChannel.csWrite(byte[]) + event Action<byte[]> DataReceived + Open() / Close(): IDisposable
  • Sessions/SerialChannel.csSystem.IO.Ports.SerialPort 實作(開啟前向 SessionManager 占用 COM port、互斥、錯誤釋放)
  • Sessions/SessionPage.cs + Sessions/SessionManager.cs:分頁內容(綁 channel+ 全域 session 登錄 / COM 互斥 / 列舉
  • 暫用 RichTextBoxReadOnly,靠遠端 echo 顯示)打通「鍵盤→送出、收到→顯示」
  • UI 跨執行緒安全:channel 在 handle 建立後才 OpenDataReceivedBeginInvoke 回 UI thread
  • 連線資料流改打通:ConnectionActivated 改傳完整 ConnectionWorkspaceView.BuildPage 依類型建 SessionPage(Serial) 或佔位(SSH);關分頁 / 關 pane 經 SessionPage.Dispose 釋放 COM port 驗收條件: 編譯通過(0 警告 0 錯誤)。接一塊開發板 / com0com loopback,打字送得出去、回傳看得到,關分頁能正確釋放 COM port(需實機 dotnet run 驗證硬體收發)。

Phase 4 — SSH Session(工作量:M 已完成

目標: 雙擊 SSH 連線可登入遠端、互動式 shell 可用。 包含:

  • Sessions/SshChannel.csSSH.NET SshClient + ShellStream(背景執行緒 Connect 避免凍 UI),實作 ISessionChannel
  • 三種認證:password / private keypassphrase 走 CredentialVault/ keyboard-interactive
  • Host key 指紋 TOFUSessions/HostKeyStore.csknown_hosts.txt)首次記錄 SHA256、之後比對、不符中止並警告
  • 連線錯誤(逾時 / 認證失敗 / 斷線)寫入終端機輸出 + AppLogger
  • PTY resize:反射呼叫 ShellStream 底層 _channel.SendWindowChangeRequestSSH.NET 未公開此 API 驗收條件: 編譯通過(0/0)。用 password 與 key 兩種方式各登入一台 SSH 主機,能跑 ls / top 等互動命令(需實機驗證)。

套件: SSH.NET 2024.2.0(含 BouncyCastle.Cryptography 2.4.0)。

Phase 5 — VT100 終端機控制項(工作量:L) 已完成

目標: 用自繪 VT100 控制項取代陽春文字框,正確顯示顏色 / 游標 / 清屏等 ANSI 行為。 包含:

  • Terminal/ScreenBuffer.csrows×cols 字格(Cell{Ch,Fg,Bg,Attr},含 Bold/Underline/Inverse+ scrollback + 滾動區(DECSTBM+ alt screen
  • Terminal/AnsiParser.cs:狀態機(Ground/Esc/CSI/OSC)—游標移動、SGR16 色 / 256 色 / truecolor)、清屏 / 清行、scroll region、insert/delete line/char、alt screen47/1047/1049)、DECTCEM(?25)/DECAWM(?7)/DECCKM(?1+ Palette
  • Terminal/TerminalView.csowner-drawn 雙緩衝、run 合併繪製、滾輪 scrollback、選取 / 複製(Ctrl+C、右鍵)/ 貼上(Ctrl+V、Shift+Insert、右鍵)
  • Terminal/TerminalInput.cs:鍵盤 → byte 序列(方向鍵含 appCursor、Fn、Home/End/PgUp/PgDn、Enter/Tab/Backspace/Esc
  • 套用 Terminal/TerminalProfile(字型 / 字級 / scrollback 行數);resize 由 OnSizeChanged 算 cols/rows 並 Resized 事件通知 channelPTY size 驗收條件: 編譯通過(0/0)。在 SSH 跑 vim / htop / top 顏色與版面正常、視窗 resize 通知遠端(需實機驗證)。

Phase 6 — TTL 腳本引擎移植 + 執行 UI(工作量:L)

目標: 移植 MyTeraTerm 的 TTLInterpreter,改為驅動 ISessionChannel,可對 active session 跑 .ttl 腳本。 包含:

  • TTLInterpreter.cs:從 MyTeraTerm 移植,建構子改吃 ISessionChannel(取代 ComPortBridge
  • 指令覆蓋:send / sendln / pause / wait / timeout / flushrecv / logopen / logwrite / logclose / messagebox / if-elseif-else-endif / while-endwhile / 變數指派
  • ScriptRunner.csasync 執行 + 取消(Cancel()+ StatusChanged(檔名 / 行號 / 指令)事件
  • Group 同步指令:waitall / sendlnall / sendlngroup + GroupSyncContextBarrier 同步)
  • ▶ Run All(對所有 Serial 個別跑)+ ▶ Group1/2/3Group 同步跑)
  • ▶ Script / ▶ Run All 拒絕含 Group 指令的腳本(彈 Warning
  • docs/ttl-script-reference.md:指令對照表(含 Group 指令)
  • SSH session 完整驗收(SSH 自動登入 + 下命令 + logopen 收 log 驗收條件: Serial 已驗收通過。SSH 尚待實機驗證:載入一支 .ttlSSH 自動登入 + 下命令 + logopen 收 log),對 active session 跑完並產生 log 檔,中途可按停止中止。

Phase 7 — Settings + About 頁面(工作量:S 已完成

目標: Activity Rail 加入 Settings / About 獨立頁面,提供偏好設定入口與版本紀錄。 包含:

  • ActivityRail 新增 Settings / About 兩個 view(三圖示:▤ / ⚙ / ℹ)
  • MainForm view 切換邏輯(Terminal / Settings / About 互斥顯示)
  • SettingsView.cs:偏好設定頁面骨架(Phase 8 擴充內容)
  • AboutView.cs:左側 App 資訊 + Developer + Tech Stack 卡片,右側 Changelog timeline
  • Changelog 資料結構,新版本只需加一筆 ChangelogEntry 驗收條件: 點 Activity Rail 可切換三個頁面;About 頁正確顯示版本、作者、changelog。

Phase 8 — PDU 控制 + Settings 擴充 + Shell + SFTP(工作量:M 已完成

目標: 補上 SNMP PDU 控制、偏好設定持久化、本機 Shell(ConPTY)、SFTP 瀏覽器。 包含:

  • Scripting/Pdu/PduController.csSnmpSharpNet 實作,接 TTLInterpreterpductrl / pduconnect
  • Infrastructure/AppSettings.cs:終端機偏好 / Shell 設定 / 視窗位置記憶(JSON 存 %LocalAppData%\ETTerms\
  • Settings 檢視 UITerminal 分頁(字型 / 配色 / scrollback / 預設換行 / Shell 設定 + 即時預覽)+ PDU 分頁(連線 / 狀態監控)
  • Sessions/ShellChannel.csWindows ConPTY 本機 ShellPowerShell / Bash / Cmd),完整 PTY 支援
  • Sidebar SFTP 分頁:SSH SFTP 檔案瀏覽器(連線 / 導航 / 目錄列表)
  • docs/runbooks/troubleshooting.md:常見問題(COM / SSH / TTL / PDU
  • dotnet publish + Inno Setup / MSIX 安裝程式(待使用者指示) 驗收條件: PDU 指令可用;Settings 重啟保留;Local Shell 行為正常(ConPTY);SFTP 可瀏覽遠端目錄。打包待後續。

Phase 9 — AI 整合:Serial MCP ServerGUI 橋接模式)(工作量:M) 已完成

目標: 讓 Kiro CLI / Claude CLI 等 AI agent 收發 serial,且使用者能在 GUI 即時看到 AI 的收發。COM port 由 GUI 唯一持有,MCP 經本機 named pipe 橋接(見 AI / MCP Integration)。 包含:

  • GUISessions/SerialBridgeServer.cs——本機 named pipe server\\.\pipe\etterms-serial),暴露 list / attach / write / read,並把 serial session 的 RX 廣播給 clientSerialBridge.cs 為單一 session 的橋接端點
  • GUISessionPage.WriteFromAi 把 MCP 來源的 TX 以 [AI] 標色(\x1b[35m)echo,使用者可區分 AI 與手打輸入
  • src/ETTerms.SerialMcp/.NET 8 console + 官方 C# MCP SDKModelContextProtocol),stdio / JSON-RPC
  • SerialBridgeClient.cs:連 GUI pipe、轉發 write、背景累積 RX
  • 工具:serial_list / serial_attach / serial_write / serial_read(含 waitFor + timeoutMs/ serial_detach
  • 註冊說明(kiro-cli mcp add / agent.json mcpServers)寫入 docs/serial-mcp-guide.md,含「需先在 GUI 開好 port」前提 驗收條件: GUI 開一條 SerialCOM3)→ 另一分頁 PowerShell 跑 kiro → AI 經 MCP serial_attach COM3 → serial_write 送指令、serial_read 讀回應,整個過程在 GUI Tab1 即時可見(AI 的 TX 有 [AI] 標色);全程只有 GUI 開該 port。

Future Extensions

這個版本不做、但未來可能加

  • AI / MCP 整合 已於 Phase 9 實作:Serial MCP Server,讓 AI agent 直接操作 serial;未來可再擴充 SSH / Shell MCP 工具)
  • SFTP 檔案瀏覽 已於 Phase 8 實作:sidebar SFTP 分頁)
  • Telnet session 類型(補一個 TelnetChannel : ISessionChannel
  • RDP / VNC 分頁(KKTerm 用 mstscax.dllETTerms 可後期評估)
  • tmux 自動 attach(SSH 斷線後自動回貼,仿 KKTerm)
  • 分割畫面 / 多 pane 已於 Phase 1 提前實作:WorkspaceView + PaneControl + ProportionalSplit
  • 拖曳 pane 重新排列(目前可分割 / 關閉 / 調大小,但還不能把 pane 拖到別處;未來可加 drag-drop 重排)
  • 佈局記憶(記住上次的 grid / split 佈局,重啟還原)
  • 全新腳本語言或內嵌 Lua / C# scripting(目前先沿用 TTL;未來可加第二引擎)
  • 連線分組 / 標籤 / 搜尋 強化
  • 跨平台WinForms 綁 Windows;若要跨平台需評估 Avalonia / MAUI 重寫 UI 層,但 Sessions / Scripting 層因抽象良好可重用)
  • macOS / Linux 終端機渲染 改用 WebView2 + xterm.js(若要與 KKTerm 視覺對齊)

Reference ProjectsFor_AI/

專案 角色 取用重點
KKTerm-main UI 參考 Activity Rail + 分頁工作區 + Saved Connections sidebar 的版面與互動;SQLite 存連線、Credential Manager 存密碼的 local-first 思路
MyTeraTerm Script 參考 lib/TTLInterpreter.cs 的 TTL 指令實作(直接移植)、AppLogger.cs 日誌、PDU/SNMP 控制(pductrl/pduconnect);ComPortBridge.cs 的 serial 經驗

注意:KKTerm 是 Tauri/React直接複製程式碼,只取 UI/UX 與資料架構概念;ETTerms 是純 WinForms。MyTeraTerm 的 TTLInterpreter 則可大段移植,主要改建構子從 ComPortBridge 換成 ISessionChannel