feat: Phase 9 Serial MCP server + app icon & version title (v0.2.0)

Phase 9 (AI integration) complete -- AI agents can send/receive serial
while the user watches live in the GUI, with the GUI as sole COM-port owner.

- ETTerms.SerialMcp: stdio MCP server (net8.0 + ModelContextProtocol SDK)
  exposing serial_list / serial_attach / serial_write / serial_read
  (waitFor + timeoutMs) / serial_detach; forwards over named pipe.
- GUI SerialBridgeServer (pipe etterms-serial) + SerialBridge endpoint;
  SessionPage.WriteFromAi echoes MCP-sourced TX tagged [AI] (magenta).
- App icon: window title bar / taskbar / exe now use Choco_256x256.ico
  (embedded via AppAssets); title bar shows ETTerms Version vX.Y.Z.
- About page: large Choco icon (Zoom, no crop).
- Docs: ARCHITECTURE.md + CLAUDE.md mark Phase 9 done; docs/serial-mcp-guide.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-04 21:25:30 +08:00
co-authored by Claude Opus 4.8
parent f4207f8586
commit 28538594d7
21 changed files with 777 additions and 51 deletions
+35
View File
@@ -0,0 +1,35 @@
using System.ComponentModel;
using ModelContextProtocol.Server;
namespace ETTerms.SerialMcp;
/// <summary>
/// 暴露給 AI 的 serial 工具。COM port 由 ETTerms GUI 持有,這些工具經 named pipe 橋接過去;
/// AI 的寫入會即時顯示在 GUI 終端機(標 [AI])。使用前須先在 GUI 開好該 serial 連線。
/// </summary>
[McpServerToolType]
public static class SerialTools
{
[McpServerTool, Description("List serial sessions currently open in the ETTerms GUI (name + baud). The GUI owns the COM port.")]
public static Task<string> serial_list() => SerialBridgeClient.Instance.List();
[McpServerTool, Description("Attach to a serial session already open in the ETTerms GUI by COM port name (e.g. COM3). Required before write/read. Does not open the port itself.")]
public static Task<string> serial_attach(
[Description("COM port name of an already-open GUI session, e.g. COM3")] string portName)
=> SerialBridgeClient.Instance.Attach(portName);
[McpServerTool, Description("Send text to the attached serial session. The GUI displays it live tagged [AI].")]
public static Task<string> serial_write(
[Description("Text to send")] string text,
[Description("Append the session newline (acts like pressing Enter)")] bool appendNewline = true)
=> SerialBridgeClient.Instance.Write(text, appendNewline);
[McpServerTool, Description("Read output accumulated from the attached serial session. Optionally wait for a substring up to timeoutMs. Returns and clears the buffer.")]
public static Task<string> serial_read(
[Description("Substring to wait for; null/empty returns whatever has arrived")] string? waitFor = null,
[Description("Max time to wait in milliseconds")] int timeoutMs = 3000)
=> SerialBridgeClient.Instance.Read(waitFor, timeoutMs);
[McpServerTool, Description("Detach from the serial session. Does NOT close the GUI's port (the GUI keeps owning it).")]
public static Task<string> serial_detach() => SerialBridgeClient.Instance.Detach();
}