<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Electron on OHTLY Blog</title>
    <link>https://blog.ohtly.com/tags/electron/</link>
    <description>Recent content in Electron on OHTLY Blog</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Mon, 13 Jul 2026 19:42:06 +0800</lastBuildDate>
    <atom:link href="https://blog.ohtly.com/tags/electron/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Electron 集成 PI SDK 桌面聊天实践</title>
      <link>https://blog.ohtly.com/posts/2026-07-13-electron-pi-coding-agent/</link>
      <pubDate>Mon, 13 Jul 2026 19:41:23 +0800</pubDate>
      <guid>https://blog.ohtly.com/posts/2026-07-13-electron-pi-coding-agent/</guid>
      <description>&lt;h2 id=&#34;项目背景&#34;&gt;&#xA;  项目背景&#xA;  &lt;a class=&#34;heading-link&#34; href=&#34;#%e9%a1%b9%e7%9b%ae%e8%83%8c%e6%99%af&#34;&gt;&#xA;    &lt;i class=&#34;fa-solid fa-link&#34; aria-hidden=&#34;true&#34; title=&#34;链接到标题&#34;&gt;&lt;/i&gt;&#xA;    &lt;span class=&#34;sr-only&#34;&gt;链接到标题&lt;/span&gt;&#xA;  &lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;用 Electron 封装 PI Coding Agent SDK，做一个轻量桌面 AI 聊天客户端。目标是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;提供 GUI 界面替代终端交互&lt;/li&gt;&#xA;&lt;li&gt;跨平台（macOS + Windows）&lt;/li&gt;&#xA;&lt;li&gt;集成 PI SDK 的 tool calling、流式回复能力&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;源码：&lt;a href=&#34;https://github.com/MarshalW/electron-pi&#34;  class=&#34;external-link&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;MarshalW/electron-pi&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;架构&#34;&gt;&#xA;  架构&#xA;  &lt;a class=&#34;heading-link&#34; href=&#34;#%e6%9e%b6%e6%9e%84&#34;&gt;&#xA;    &lt;i class=&#34;fa-solid fa-link&#34; aria-hidden=&#34;true&#34; title=&#34;链接到标题&#34;&gt;&lt;/i&gt;&#xA;    &lt;span class=&#34;sr-only&#34;&gt;链接到标题&lt;/span&gt;&#xA;  &lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Renderer (index.html)&#xA;    ↕ contextBridge (preload.js)&#xA;Main Process (main.js)&#xA;    ↕ @earendil-works/pi-coding-agent&#xA;AgentSession (Tool calling, LLM 通信)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;三进程架构：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Renderer&lt;/strong&gt;：纯前端 HTML/CSS/JS，显示聊天界面&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Preload&lt;/strong&gt;：contextBridge 暴露 &lt;code&gt;window.pi.*&lt;/code&gt; API&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Main&lt;/strong&gt;：Electron 主进程，管理窗口、PI SDK、IPC 通道&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;IPC 通道设计：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Channel&lt;/th&gt;&#xA;          &lt;th&gt;方向&lt;/th&gt;&#xA;          &lt;th&gt;说明&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;config:get&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Renderer → Main&lt;/td&gt;&#xA;          &lt;td&gt;读取配置&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;config:save&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Renderer → Main&lt;/td&gt;&#xA;          &lt;td&gt;保存配置&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;session:create&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Renderer → Main&lt;/td&gt;&#xA;          &lt;td&gt;创建 AgentSession&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;session:send&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Renderer → Main&lt;/td&gt;&#xA;          &lt;td&gt;发送 prompt&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;session:abort&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Renderer → Main&lt;/td&gt;&#xA;          &lt;td&gt;中止回复&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;pi:event&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Main → Renderer&lt;/td&gt;&#xA;          &lt;td&gt;推送流式事件&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;pi-sdk-集成&#34;&gt;&#xA;  PI SDK 集成&#xA;  &lt;a class=&#34;heading-link&#34; href=&#34;#pi-sdk-%e9%9b%86%e6%88%90&#34;&gt;&#xA;    &lt;i class=&#34;fa-solid fa-link&#34; aria-hidden=&#34;true&#34; title=&#34;链接到标题&#34;&gt;&lt;/i&gt;&#xA;    &lt;span class=&#34;sr-only&#34;&gt;链接到标题&lt;/span&gt;&#xA;  &lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;h3 id=&#34;模型解析&#34;&gt;&#xA;  模型解析&#xA;  &lt;a class=&#34;heading-link&#34; href=&#34;#%e6%a8%a1%e5%9e%8b%e8%a7%a3%e6%9e%90&#34;&gt;&#xA;    &lt;i class=&#34;fa-solid fa-link&#34; aria-hidden=&#34;true&#34; title=&#34;链接到标题&#34;&gt;&lt;/i&gt;&#xA;    &lt;span class=&#34;sr-only&#34;&gt;链接到标题&lt;/span&gt;&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;createAgentSession&lt;/code&gt; 需要完整的模型对象（含 &lt;code&gt;baseUrl&lt;/code&gt;、&lt;code&gt;api&lt;/code&gt; 等字段），不能只传 &lt;code&gt;{ provider, model }&lt;/code&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Electron 项目 macOS 构建配置</title>
      <link>https://blog.ohtly.com/posts/2026-07-13-electron-macos-build/</link>
      <pubDate>Mon, 13 Jul 2026 10:46:12 +0800</pubDate>
      <guid>https://blog.ohtly.com/posts/2026-07-13-electron-macos-build/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;&#xA;  背景&#xA;  &lt;a class=&#34;heading-link&#34; href=&#34;#%e8%83%8c%e6%99%af&#34;&gt;&#xA;    &lt;i class=&#34;fa-solid fa-link&#34; aria-hidden=&#34;true&#34; title=&#34;链接到标题&#34;&gt;&lt;/i&gt;&#xA;    &lt;span class=&#34;sr-only&#34;&gt;链接到标题&lt;/span&gt;&#xA;  &lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Electron 是用 Web 技术构建跨平台桌面应用的主流方案。本文记录从零搭建 Electron 项目并通过 electron-builder 构建 macOS 安装包的过程。无需 Apple Developer 账号，构建出的 &lt;code&gt;.dmg&lt;/code&gt; 可在本机安装运行。&lt;/p&gt;&#xA;&lt;h2 id=&#34;项目结构&#34;&gt;&#xA;  项目结构&#xA;  &lt;a class=&#34;heading-link&#34; href=&#34;#%e9%a1%b9%e7%9b%ae%e7%bb%93%e6%9e%84&#34;&gt;&#xA;    &lt;i class=&#34;fa-solid fa-link&#34; aria-hidden=&#34;true&#34; title=&#34;链接到标题&#34;&gt;&lt;/i&gt;&#xA;    &lt;span class=&#34;sr-only&#34;&gt;链接到标题&lt;/span&gt;&#xA;  &lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;electron-proto/&#xA;├── package.json&#xA;├── src/&#xA;│   ├── main.js          # 主进程&#xA;│   └── index.html       # 渲染页面&#xA;└── release/             # 构建产物&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;配置&#34;&gt;&#xA;  配置&#xA;  &lt;a class=&#34;heading-link&#34; href=&#34;#%e9%85%8d%e7%bd%ae&#34;&gt;&#xA;    &lt;i class=&#34;fa-solid fa-link&#34; aria-hidden=&#34;true&#34; title=&#34;链接到标题&#34;&gt;&lt;/i&gt;&#xA;    &lt;span class=&#34;sr-only&#34;&gt;链接到标题&lt;/span&gt;&#xA;  &lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;h3 id=&#34;packagejson&#34;&gt;&#xA;  package.json&#xA;  &lt;a class=&#34;heading-link&#34; href=&#34;#packagejson&#34;&gt;&#xA;    &lt;i class=&#34;fa-solid fa-link&#34; aria-hidden=&#34;true&#34; title=&#34;链接到标题&#34;&gt;&lt;/i&gt;&#xA;    &lt;span class=&#34;sr-only&#34;&gt;链接到标题&lt;/span&gt;&#xA;  &lt;/a&gt;&#xA;&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;electron-proto&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1.0.0&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;src/main.js&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;scripts&amp;#34;&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;start&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;electron .&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;build:mac&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;electron-builder --mac&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;devDependencies&amp;#34;&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;electron&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^33.0.0&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;electron-builder&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^25.1.0&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;build&amp;#34;&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;appId&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;com.electron.proto&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;productName&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ElectronProto&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;directories&amp;#34;&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;output&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;release&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;mac&amp;#34;&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;category&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;public.app-category.utilities&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;target&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dmg&amp;#34;&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;identity&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;identity: null&lt;/code&gt; 是关键——告诉 electron-builder 跳过代码签名，否则没有开发者证书时会构建失败。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
