openhanako-personal-ai-agent

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OpenHanako Personal AI Agent

OpenHanako 个人AI Agent

Skill by ara.so — Daily 2026 Skills collection.
OpenHanako is a desktop AI agent platform built on Electron that gives each agent persistent memory, a distinct personality, and the ability to autonomously operate your computer — read/write files, run terminal commands, browse the web, execute JavaScript, and manage schedules. Multiple agents can collaborate via channel group chats or task delegation.

ara.so开发的Skill — 2026每日技能合集。
OpenHanako是一个基于Electron构建的桌面AI Agent平台,可为每个Agent提供持久记忆、独特个性,以及自主操作电脑的能力——包括读写文件、运行终端命令、浏览网页、执行JavaScript、管理日程等。多个Agent可通过频道群聊或任务委派进行协作。

Installation

安装

Download & Run

下载并运行

bash
undefined
bash
undefined

macOS Apple Silicon — download from releases page

macOS Apple Silicon — 从发布页面下载

Mount the .dmg and drag to Applications

挂载.dmg文件并拖拽至应用程序文件夹

First launch — bypass Gatekeeper (one-time):

首次启动 — 绕过Gatekeeper(仅需一次):

Right-click app → Open → Open

右键点击应用 → 打开 → 打开


```powershell

```powershell

Windows — run the .exe installer from releases

Windows — 从发布页面运行.exe安装程序

SmartScreen warning: click "More info" → "Run anyway"

SmartScreen警告:点击“更多信息” → “仍要运行”

undefined
undefined

Build from Source

从源码构建

bash
git clone https://github.com/liliMozi/openhanako.git
cd openhanako
npm install
bash
git clone https://github.com/liliMozi/openhanako.git
cd openhanako
npm install

Development mode

开发模式

npm run dev
npm run dev

Build for production

生产环境构建

npm run build
npm run build

Run tests

运行测试

npm test

---
npm test

---

First-Run Onboarding

首次启动引导

On first launch, the wizard asks for:
  1. Language — UI language preference
  2. Your name — used by agents when addressing you
  3. Model provider — any OpenAI-compatible endpoint
  4. Three models:
    • chat model
      — main conversation (e.g.
      gpt-4o
      ,
      deepseek-chat
      )
    • utility model
      — lightweight tasks, summarization (e.g.
      gpt-4o-mini
      )
    • utility large model
      — memory compilation, deep analysis (e.g.
      gpt-4o
      )
首次启动时,向导会要求您设置:
  1. 语言 — UI语言偏好
  2. 您的姓名 — Agent与您交流时会使用该名称
  3. 模型提供商 — 任何兼容OpenAI的端点
  4. 三个模型:
    • chat model
      — 主对话模型(例如
      gpt-4o
      deepseek-chat
    • utility model
      — 轻量任务、总结模型(例如
      gpt-4o-mini
    • utility large model
      — 记忆编译、深度分析模型(例如
      gpt-4o

Provider Configuration Examples

提供商配置示例

json
// OpenAI
{
  "baseURL": "https://api.openai.com/v1",
  "apiKey": "process.env.OPENAI_API_KEY"
}

// DeepSeek
{
  "baseURL": "https://api.deepseek.com/v1",
  "apiKey": "process.env.DEEPSEEK_API_KEY"
}

// Local Ollama
{
  "baseURL": "http://localhost:11434/v1",
  "apiKey": "ollama"
}

// Qwen (Alibaba Cloud)
{
  "baseURL": "https://dashscope.aliyuncs.com/compatible-mode/v1",
  "apiKey": "process.env.DASHSCOPE_API_KEY"
}

json
// OpenAI
{
  "baseURL": "https://api.openai.com/v1",
  "apiKey": "process.env.OPENAI_API_KEY"
}

// DeepSeek
{
  "baseURL": "https://api.deepseek.com/v1",
  "apiKey": "process.env.DEEPSEEK_API_KEY"
}

// 本地Ollama
{
  "baseURL": "http://localhost:11434/v1",
  "apiKey": "ollama"
}

// Qwen(阿里云)
{
  "baseURL": "https://dashscope.aliyuncs.com/compatible-mode/v1",
  "apiKey": "process.env.DASHSCOPE_API_KEY"
}

Project Architecture

项目架构

openhanako/
├── core/           # Engine orchestration + Managers (Agent, Session, Model, Preferences, Skill)
├── lib/            # Core libraries
│   ├── memory/     # Custom memory system (recency decay)
│   ├── tools/      # Built-in tools (files, terminal, browser, screenshot, canvas)
│   ├── sandbox/    # PathGuard + OS-level isolation (Seatbelt/Bubblewrap)
│   └── bridge/     # Multi-platform adapters (Telegram, Feishu, QQ)
├── server/         # Fastify 5 HTTP + WebSocket server
├── hub/            # Scheduler, ChannelRouter, EventBus
├── desktop/        # Electron 38 main process + React 19 frontend
├── tests/          # Vitest test suite
└── skills2set/     # Built-in skill definitions
openhanako/
├── core/           # 引擎编排 + 管理器(Agent、Session、Model、Preferences、Skill)
├── lib/            # 核心库
│   ├── memory/     # 自定义记忆系统(近因衰减)
│   ├── tools/      # 内置工具(文件、终端、浏览器、截图、画布)
│   ├── sandbox/    # PathGuard + 系统级隔离(Seatbelt/Bubblewrap)
│   └── bridge/     # 多平台适配器(Telegram、飞书、QQ)
├── server/         # Fastify 5 HTTP + WebSocket服务器
├── hub/            # 调度器、ChannelRouter、EventBus
├── desktop/        # Electron 38主进程 + React 19前端
├── tests/          # Vitest测试套件
└── skills2set/     # 内置Skill定义

Key Managers (via unified engine facade)

核心管理器(通过统一引擎门面)

ManagerResponsibility
AgentManager
Create, load, delete agents
SessionManager
Conversation sessions per agent
ModelManager
Route requests to configured providers
PreferencesManager
User/global settings
SkillManager
Install, enable, disable, sandbox skills

管理器职责
AgentManager
创建、加载、删除Agent
SessionManager
每个Agent的对话会话管理
ModelManager
将请求路由至已配置的提供商
PreferencesManager
用户/全局设置管理
SkillManager
安装、启用、禁用、沙箱化Skill

Agent Configuration

Agent配置

Each agent is a self-contained folder you can back up:
~/.openhanako/agents/<agent-id>/
├── personality.md      # Personality template (free-form prose or structured)
├── memory/
│   ├── working.db      # Recent events (SQLite WAL)
│   └── compiled.md     # Long-term compiled memory
├── desk/               # Agent's file workspace
│   └── notes/          # Jian notes
└── skills/             # Agent-local installed skills
每个Agent是一个独立的文件夹,您可以对其进行备份:
~/.openhanako/agents/<agent-id>/
├── personality.md      # 个性模板(自由格式文本或结构化内容)
├── memory/
│   ├── working.db      # 近期事件(SQLite WAL)
│   └── compiled.md     # 长期编译记忆
├── desk/               # Agent的文件工作区
│   └── notes/          # 简记
└── skills/             # Agent本地安装的Skill

Personality Template Example

个性模板示例

markdown
undefined
markdown
undefined

Hanako

Hanako

You are Hanako, a calm and thoughtful assistant who prefers directness over verbosity. You remember past conversations and refer to them naturally. You ask clarifying questions before starting large tasks. When writing code, you always add brief inline comments.
您是Hanako,一位冷静、体贴的助手,相比冗长的表述更倾向于直接沟通。 您会记住过往对话,并自然地在交流中提及。 在开始大型任务前,您会先提出澄清问题。 编写代码时,您总会添加简短的行内注释。

Tone

语气

  • Warm but professional
  • Uses occasional dry humor
  • Never uses hollow affirmations ("Great question!")
  • 温暖但专业
  • 偶尔使用冷幽默
  • 从不使用空洞的肯定语(例如“好问题!”)

Constraints

约束

  • Always confirm before deleting files
  • Summarize long terminal output rather than dumping it raw

---
  • 删除文件前始终确认
  • 对冗长的终端输出进行总结,而非直接完整输出

---

Skills System

Skill系统

Skills extend agent capabilities. They live in
skills2set/
(built-in) or are installed per-agent.
Skill可扩展Agent的能力。它们位于
skills2set/
(内置)或按Agent单独安装。

Install a Skill from GitHub

从GitHub安装Skill

javascript
// Via the Skills UI in the app, or programmatically:
const { skillManager } = engine;

await skillManager.installFromGitHub({
  repo: 'some-user/hanako-skill-weather',
  agentId: 'agent-abc123',
  safetyReview: true   // strict review enabled by default
});
javascript
// 通过应用内的Skill UI,或编程方式:
const { skillManager } = engine;

await skillManager.installFromGitHub({
  repo: 'some-user/hanako-skill-weather',
  agentId: 'agent-abc123',
  safetyReview: true   // 默认启用严格审核
});

Skill Definition Format (SKILL.md → skills2set)

Skill定义格式(SKILL.md → skills2set)

markdown
---
name: web-scraper
version: 1.0.0
description: Scrape structured data from web pages
tools:
  - browser
  - javascript
permissions:
  - network
---
markdown
---
name: web-scraper
version: 1.0.0
description: 从网页提取结构化数据
tools:
  - browser
  - javascript
permissions:
  - network
---

Instructions for Agent

Agent使用说明

When asked to scrape a page:
  1. Use the
    browser
    tool to navigate to the URL
  2. Use
    executeJavaScript
    to extract structured data
  3. Save results to the desk as JSON
undefined
当需要抓取页面时:
  1. 使用
    browser
    工具导航至目标URL
  2. 使用
    executeJavaScript
    提取结构化数据
  3. 将结果以JSON格式保存至工作区
undefined

Writing a Custom Skill (JavaScript)

编写自定义Skill(JavaScript)

javascript
// skills/my-skill/index.js
export default {
  name: 'my-skill',
  version: '1.0.0',
  description: 'Does something useful',

  // Tools this skill adds to the agent
  tools: [
    {
      name: 'fetch_weather',
      description: 'Fetch current weather for a city',
      parameters: {
        type: 'object',
        properties: {
          city: { type: 'string', description: 'City name' }
        },
        required: ['city']
      },
      async execute({ city }) {
        const res = await fetch(
          `https://wttr.in/${encodeURIComponent(city)}?format=j1`
        );
        const data = await res.json();
        return {
          temp_c: data.current_condition[0].temp_C,
          description: data.current_condition[0].weatherDesc[0].value
        };
      }
    }
  ]
};

javascript
// skills/my-skill/index.js
export default {
  name: 'my-skill',
  version: '1.0.0',
  description: 实现实用功能,

  // 该Skill为Agent添加的工具
  tools: [
    {
      name: 'fetch_weather',
      description: 获取指定城市的当前天气,
      parameters: {
        type: 'object',
        properties: {
          city: { type: 'string', description: 城市名称 }
        },
        required: ['city']
      },
      async execute({ city }) {
        const res = await fetch(
          `https://wttr.in/${encodeURIComponent(city)}?format=j1`
        );
        const data = await res.json();
        return {
          temp_c: data.current_condition[0].temp_C,
          description: data.current_condition[0].weatherDesc[0].value
        };
      }
    }
  ]
};

Memory System

记忆系统

OpenHanako uses a recency-decay memory model: recent events stay sharp, older ones fade.
javascript
// Accessing memory programmatically (core/lib/memory)
import { MemoryManager } from './lib/memory/index.js';

const memory = new MemoryManager({ agentId: 'agent-abc123' });

// Store a memory event
await memory.store({
  type: 'conversation',
  content: 'User prefers dark mode and terse responses',
  importance: 0.8   // 0.0–1.0; higher = decays slower
});

// Retrieve relevant memories
const relevant = await memory.query({
  query: 'user preferences',
  limit: 10,
  minRelevance: 0.5
});

// Trigger manual compilation (normally runs automatically)
await memory.compile();
OpenHanako采用近因衰减记忆模型:近期事件记忆清晰,远期事件记忆逐渐淡化。
javascript
// 编程方式访问记忆(core/lib/memory)
import { MemoryManager } from './lib/memory/index.js';

const memory = new MemoryManager({ agentId: 'agent-abc123' });

// 存储记忆事件
await memory.store({
  type: 'conversation',
  content: '用户偏好深色模式和简洁回复',
  importance: 0.8   // 0.0–1.0;值越高,衰减越慢
});

// 检索相关记忆
const relevant = await memory.query({
  query: '用户偏好',
  limit: 10,
  minRelevance: 0.5
});

// 触发手动编译(通常自动运行)
await memory.compile();

Memory Tiers

记忆层级

TierStorageDecay
Working memory
working.db
(SQLite)
Fast — recent N turns
Compiled memory
compiled.md
Slow — summarized by utility-large model
Desk notes (Jian)Files on deskManual / no decay

层级存储方式衰减速度
工作记忆
working.db
(SQLite)
快 — 仅保留最近N轮对话
编译记忆
compiled.md
慢 — 由utility-large模型总结
工作区笔记(简记)工作区文件手动 / 无衰减

Built-in Tools

内置工具

Tools available to agents out of the box:
javascript
// File operations
{ tool: 'read_file',   args: { path: '/Users/me/notes.txt' } }
{ tool: 'write_file',  args: { path: '/Users/me/out.txt', content: '...' } }

// Terminal
{ tool: 'run_command', args: { command: 'ls -la', cwd: '/Users/me' } }

// Browser & web
{ tool: 'browse',      args: { url: 'https://example.com' } }
{ tool: 'web_search',  args: { query: 'OpenHanako latest release' } }

// Screen
{ tool: 'screenshot',  args: {} }

// Canvas
{ tool: 'draw',        args: { instructions: '...' } }

// Code execution
{ tool: 'execute_js',  args: { code: 'return 2 + 2' } }
Agent默认可用的工具:
javascript
// 文件操作
{ tool: 'read_file',   args: { path: '/Users/me/notes.txt' } }
{ tool: 'write_file',  args: { path: '/Users/me/out.txt', content: '...' } }

// 终端
{ tool: 'run_command', args: { command: 'ls -la', cwd: '/Users/me' } }

// 浏览器与网页
{ tool: 'browse',      args: { url: 'https://example.com' } }
{ tool: 'web_search',  args: { query: 'OpenHanako latest release' } }

// 屏幕
{ tool: 'screenshot',  args: {} }

// 画布
{ tool: 'draw',        args: { instructions: '...' } }

// 代码执行
{ tool: 'execute_js',  args: { code: 'return 2 + 2' } }

Sandbox Access Tiers (PathGuard)

沙箱访问层级(PathGuard)

Tier 0 — Denied:     System paths (/System, /usr, registry hives)
Tier 1 — Read-only:  Home directory files outside agent desk
Tier 2 — Read-write: Agent desk folder only
Tier 3 — Full:       Explicitly granted paths (user confirms)
OS-level sandbox: macOS Seatbelt / Linux Bubblewrap wraps the skill process.

层级0 — 禁止访问: 系统路径(/System、/usr、注册表项)
层级1 — 只读: 用户目录中Agent工作区外的文件
层级2 — 读写: 仅Agent工作区文件夹
层级3 — 完全访问: 明确授权的路径(需用户确认)
系统级沙箱:macOS Seatbelt / Linux Bubblewrap 包裹Skill进程。

Multi-Agent Setup

多Agent设置

javascript
// core/AgentManager usage example
import { createEngine } from './core/engine.js';

const engine = await createEngine();

// Create a second agent
const researchAgent = await engine.agentManager.create({
  name: 'Researcher',
  personalityTemplate: 'researcher.md',
  models: {
    chat: 'deepseek-chat',
    utility: 'gpt-4o-mini',
    utilityLarge: 'gpt-4o'
  }
});

// Delegate a task from one agent to another via channel
await engine.hub.channelRouter.delegate({
  fromAgent: 'agent-abc123',
  toAgent: researchAgent.id,
  task: 'Find the top 5 papers on mixture-of-experts published in 2025',
  returnTo: 'agent-abc123'   // result routed back automatically
});

javascript
// core/AgentManager使用示例
import { createEngine } from './core/engine.js';

const engine = await createEngine();

// 创建第二个Agent
const researchAgent = await engine.agentManager.create({
  name: 'Researcher',
  personalityTemplate: 'researcher.md',
  models: {
    chat: 'deepseek-chat',
    utility: 'gpt-4o-mini',
    utilityLarge: 'gpt-4o'
  }
});

// 通过频道将任务从一个Agent委派给另一个
await engine.hub.channelRouter.delegate({
  fromAgent: 'agent-abc123',
  toAgent: researchAgent.id,
  task: '查找2025年发表的前5篇混合专家模型相关论文',
  returnTo: 'agent-abc123'   // 结果会自动路由回原Agent
});

Scheduled Tasks (Cron & Heartbeat)

定时任务(Cron与心跳)

javascript
// hub/scheduler usage
import { Scheduler } from './hub/scheduler.js';

const scheduler = new Scheduler({ agentId: 'agent-abc123' });

// Run a task every day at 9am
scheduler.cron('daily-briefing', '0 9 * * *', async () => {
  await agent.run('Summarize my desk notes from yesterday and post to #briefing channel');
});

// Heartbeat — check desk for new files every 5 minutes
scheduler.heartbeat('desk-watch', 300_000, async () => {
  const changed = await agent.desk.checkChanges();
  if (changed.length > 0) {
    await agent.run(`New files on desk: ${changed.join(', ')} — summarize and notify me`);
  }
});

scheduler.start();

javascript
// hub/scheduler使用示例
import { Scheduler } from './hub/scheduler.js';

const scheduler = new Scheduler({ agentId: 'agent-abc123' });

// 每天上午9点执行任务
scheduler.cron('daily-briefing', '0 9 * * *', async () => {
  await agent.run('总结我昨天的工作区笔记并发布到#briefing频道');
});

// 心跳任务 — 每5分钟检查工作区是否有新文件
scheduler.heartbeat('desk-watch', 300_000, async () => {
  const changed = await agent.desk.checkChanges();
  if (changed.length > 0) {
    await agent.run(`工作区新增文件:${changed.join(', ')} — 请总结并通知我`);
  }
});

scheduler.start();

Multi-Platform Bridge

多平台桥接

Connect one agent to Telegram, Feishu, and QQ simultaneously:
javascript
// lib/bridge configuration
const bridgeConfig = {
  telegram: {
    enabled: true,
    token: process.env.TELEGRAM_BOT_TOKEN,
    allowedUsers: [process.env.TELEGRAM_ALLOWED_USER_ID]
  },
  feishu: {
    enabled: true,
    appId: process.env.FEISHU_APP_ID,
    appSecret: process.env.FEISHU_APP_SECRET
  },
  qq: {
    enabled: false
  }
};

await engine.agentManager.setBridges('agent-abc123', bridgeConfig);

同时将一个Agent连接至Telegram、飞书和QQ:
javascript
// lib/bridge配置
const bridgeConfig = {
  telegram: {
    enabled: true,
    token: process.env.TELEGRAM_BOT_TOKEN,
    allowedUsers: [process.env.TELEGRAM_ALLOWED_USER_ID]
  },
  feishu: {
    enabled: true,
    appId: process.env.FEISHU_APP_ID,
    appSecret: process.env.FEISHU_APP_SECRET
  },
  qq: {
    enabled: false
  }
};

await engine.agentManager.setBridges('agent-abc123', bridgeConfig);

Server API (Fastify + WebSocket)

服务器API(Fastify + WebSocket)

The embedded Fastify server runs locally and the Electron main process communicates via stdio bridge.
javascript
// WebSocket — real-time chat stream
const ws = new WebSocket('ws://localhost:PORT/ws/agent-abc123');

ws.send(JSON.stringify({
  type: 'chat',
  content: 'Summarize my project folder'
}));

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  // msg.type: 'chunk' | 'tool_call' | 'tool_result' | 'done'
  console.log(msg);
};

// HTTP — one-shot task
const res = await fetch('http://localhost:PORT/api/agent/agent-abc123/run', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ task: 'List all .md files on my desk' })
});
const result = await res.json();

嵌入式Fastify服务器在本地运行,Electron主进程通过stdio桥接与之通信。
javascript
// WebSocket — 实时聊天流
const ws = new WebSocket('ws://localhost:PORT/ws/agent-abc123');

ws.send(JSON.stringify({
  type: 'chat',
  content: '总结我的项目文件夹'
}));

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  // msg.type: 'chunk' | 'tool_call' | 'tool_result' | 'done'
  console.log(msg);
};

// HTTP — 一次性任务
const res = await fetch('http://localhost:PORT/api/agent/agent-abc123/run', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ task: '列出我工作区中所有.md文件' })
});
const result = await res.json();

Testing

测试

bash
undefined
bash
undefined

Run all tests

运行所有测试

npm test
npm test

Run a specific test file

运行指定测试文件

npx vitest run tests/memory.test.js
npx vitest run tests/memory.test.js

Watch mode

监听模式

npx vitest

```javascript
// tests/memory.test.js example pattern
import { describe, it, expect, beforeEach } from 'vitest';
import { MemoryManager } from '../lib/memory/index.js';

describe('MemoryManager', () => {
  let memory;

  beforeEach(async () => {
    memory = new MemoryManager({ agentId: 'test-agent', inMemory: true });
    await memory.init();
  });

  it('stores and retrieves a memory', async () => {
    await memory.store({ type: 'fact', content: 'User likes dark mode', importance: 0.9 });
    const results = await memory.query({ query: 'dark mode', limit: 5 });
    expect(results[0].content).toContain('dark mode');
  });
});

npx vitest

```javascript
// tests/memory.test.js示例模式
import { describe, it, expect, beforeEach } from 'vitest';
import { MemoryManager } from '../lib/memory/index.js';

describe('MemoryManager', () => {
  let memory;

  beforeEach(async () => {
    memory = new MemoryManager({ agentId: 'test-agent', inMemory: true });
    await memory.init();
  });

  it('存储并检索记忆', async () => {
    await memory.store({ type: 'fact', content: '用户喜欢深色模式', importance: 0.9 });
    const results = await memory.query({ query: '深色模式', limit: 5 });
    expect(results[0].content).toContain('深色模式');
  });
});

Troubleshooting

故障排查

App won't open on macOS

macOS上应用无法打开

bash
undefined
bash
undefined

Remove quarantine attribute if right-click → Open doesn't work

如果右键→打开无效,移除隔离属性

xattr -dr com.apple.quarantine /Applications/OpenHanako.app
undefined
xattr -dr com.apple.quarantine /Applications/OpenHanako.app
undefined

Agent not responding

Agent无响应

  • Check that the API key env var is set and the base URL is reachable
  • Open DevTools (
    Cmd+Option+I
    /
    Ctrl+Shift+I
    ) → Console for errors
  • Verify the model name matches exactly what your provider supports
  • 检查API key环境变量是否已设置,以及base URL是否可访问
  • 打开开发者工具(
    Cmd+Option+I
    /
    Ctrl+Shift+I
    )→ 控制台查看错误
  • 确认模型名称与提供商支持的名称完全匹配

Memory compilation not triggering

记忆编译未触发

javascript
// Force a manual compile
await engine.agentManager.getAgent('agent-abc123').memory.compile({ force: true });
javascript
// 强制手动编译
await engine.agentManager.getAgent('agent-abc123').memory.compile({ force: true });

Skill installation blocked by safety review

Skill安装被安全审核阻止

javascript
// Temporarily disable safety review for trusted local skills only
await skillManager.installLocal({
  path: './my-skill',
  agentId: 'agent-abc123',
  safetyReview: false   // ⚠️ only for local dev, never for untrusted sources
});
javascript
// 仅对可信本地Skill临时禁用安全审核
await skillManager.installLocal({
  path: './my-skill',
  agentId: 'agent-abc123',
  safetyReview: false   // ⚠️仅用于本地开发,切勿用于不可信来源
});

Sandbox permission denied

沙箱权限被拒绝

  • Check the PathGuard tier for the path being accessed
  • Use the desktop UI: Agent Settings → Sandbox → Grant Path Access
  • Or programmatically request elevation to Tier 3 (prompts user confirmation)
  • 检查被访问路径的PathGuard层级
  • 使用桌面UI:Agent设置 → 沙箱 → 授予路径访问权限
  • 或通过编程方式请求提升至层级3(需用户确认)

Windows Defender false positive on built
.exe

Windows Defender对构建的.exe报误报

  • The installer is unsigned; click More info → Run anyway in SmartScreen
  • Add an exclusion in Windows Security if needed during development

  • 安装程序未签名;在SmartScreen中点击更多信息→仍要运行
  • 开发期间可在Windows安全中心添加排除项

Key Links

关键链接