mingdao-harness 0.1.57 → 0.1.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # MingDao-Harness(明道)
1
+ # MingDao Harness
2
2
 
3
3
  > 开源智能体框架(Agent Harness):**零运行时依赖、开箱即用**,针对 DeepSeek-V4 首发深度优化,开放主流模型接入。一条命令安装,终端与浏览器双界面,命令:`mingdao`(简写 `mdh`)。
4
4
 
@@ -0,0 +1,92 @@
1
+ # 桌面版代码签名与公证指南
2
+
3
+ 消除 Windows SmartScreen 警告与 macOS Gatekeeper「仍要打开」提示的完整流程。
4
+ **当前构建为未签名**(官网已注明绕过方法);按本指南拿到证书后,把对应密钥配成
5
+ 环境变量即可,无需改代码。
6
+
7
+ ---
8
+
9
+ ## 一、Windows 代码签名(二选一)
10
+
11
+ ### 方案 A:OV/EV 代码签名证书(传统方式)
12
+
13
+ | 项 | OV(组织验证) | EV(扩展验证) |
14
+ | --- | --- | --- |
15
+ | SmartScreen 效果 | 新证书初期仍提示,随下载量积累信誉后消失 | **签发即过**(即时信誉) |
16
+ | 价格 | 约 ¥1000–2500/年 | 约 ¥3000–6000/年 |
17
+ | 主体要求 | 需要**企业/个体工商户**营业执照(个人买不到) | 同左 |
18
+
19
+ 购买渠道(国内可直接开票):亚洲诚信(TrustAsia)/ Sectigo / DigiCert / GlobalSign 的
20
+ 国内代理,搜索「OV 代码签名证书」即可。CA 会发 **USB Key(U 盾)或加密后的 .pfx**。
21
+
22
+ 拿到证书后导出为 **.pfx(含私钥)**,转成 base64 配置环境变量:
23
+
24
+ ```bash
25
+ base64 -w0 your-cert.pfx > cert.b64 # Windows 用 certutil -encode
26
+ # GitHub Secrets → CSC_LINK = cert.b64 内容(含换行也可)
27
+ # → CSC_KEY_PASSWORD = pfx 导出密码
28
+ ```
29
+
30
+ ### 方案 B:Azure Trusted Signing(个人开发者推荐)
31
+
32
+ 个人无法申请 OV/EV 时的官方方案(微软 2024 年推出,**$9.99/月**,无需企业主体、无硬件):
33
+
34
+ 1. 注册 Azure 账号 → 订阅 → 搜索「**Trusted Signing**」服务创建签名账户;
35
+ 2. 创建 **Certificate Profile**(类型 Public Trust),记录 endpoint(形如
36
+ `https://xxx.codesigning.azure.net/`)与 `CertificateProfileName`;
37
+ 3. 在 Azure Entra 注册一个应用并给其签名账户的
38
+ `Code Signing Certificate Profile Signer` 角色,取得 tenant/client/secret;
39
+ 4. 配置 `desktop/electron-builder.yml` 的 `win.azureSignOptions`(见该文件注释)并设置
40
+ 环境变量 `AZURE_TENANT_ID` / `AZURE_CLIENT_ID` / `AZURE_CLIENT_SECRET`。
41
+
42
+ > 提示:Azure Trusted Signing 签出的也是可信证书,SmartScreen 信誉随使用积累。
43
+
44
+ ---
45
+
46
+ ## 二、macOS 签名 + 公证
47
+
48
+ 1. 注册 [Apple Developer Program](https://developer.apple.com/programs/)(**$99/年**,个人即可);
49
+ 2. 在 https://developer.apple.com/account/resources/certificates 创建
50
+ **Developer ID Application** 证书 → 下载后在「钥匙串访问」导出为 **.p12(含私钥)**;
51
+ 3. 在 https://appleid.apple.com 的「登录与安全」生成 **App 专用密码**;
52
+ 4. 配置环境变量(electron-builder 检测到后自动签名 + 公证,零代码改动):
53
+
54
+ | 环境变量 | 值 |
55
+ | --- | --- |
56
+ | `CSC_LINK` | p12 的 base64(`base64 -w0 cert.p12`) |
57
+ | `CSC_KEY_PASSWORD` | p12 导出密码 |
58
+ | `APPLE_ID` | 你的 Apple ID 邮箱 |
59
+ | `APPLE_APP_SPECIFIC_PASSWORD` | 第 3 步生成的 App 专用密码 |
60
+ | `APPLE_TEAM_ID` | https://developer.apple.com/account 右上角显示的 Team ID |
61
+
62
+ ---
63
+
64
+ ## 三、CI(GitHub Actions)接线
65
+
66
+ 把上述环境变量按名字建到仓库 **Settings → Secrets and variables → Actions**
67
+ (`CSC_LINK` 直接贴 base64 全文)。`desktop.yml` 已预留 env 引用(见 `env:` 段),
68
+ 密钥存在后**下次打 tag 自动签名/公证**。密钥只进 GitHub Secrets,绝不进仓库。
69
+
70
+ macOS 作业的 `--mac dmg` 在检测到 `CSC_LINK` + Apple 凭证时自动完成签名与
71
+ `notarytool` 公证(`hardenedRuntime` 由 electron-builder 默认开启)。
72
+
73
+ ---
74
+
75
+ ## 四、常见问题
76
+
77
+ - **签了名 SmartScreen 还提示**:OV/新证书需积累下载信誉(通常数周);EV 即时生效。
78
+ 也可到微软 [Windows Defender SmartScreen](https://www.microsoft.com/wdsi/filesubmission)
79
+ 提交文件加快信誉建立。
80
+ - **公证失败**:常见原因是 p12 不含私钥、App 专用密码错误、或 hardened runtime 缺少
81
+ entitlements。electron-builder 会在 CI 日志打印 notarytool 完整输出。
82
+ - **验证是否签上**:Windows 右键 exe →「数字签名」;macOS `codesign -dv
83
+ --verbose=4 MingDao.app` 与 `spctl -a -vv MingDao.app`。
84
+ - **「代码签名 OV」与「域名 OV」是同一个证书吗?** 不是。两者只共享 OV(组织验证)
85
+ 概念:域名 OV 是 SSL/TLS 证书(绑定域名、EKU=Server Authentication、给 HTTPS 用);
86
+ 代码签名 OV 绑定组织身份(EKU=Code Signing 1.3.6.1.5.5.7.3.3、给软件签名用),
87
+ 常以 USB Key 交付,互不可替代。下单务必确认 EKU 为 Code Signing。
88
+ - **不想签**:现状即可用(官网已附绕过说明),仅多一步手动确认。
89
+
90
+ ---
91
+
92
+ *配置文件位置:`desktop/electron-builder.yml`(azureSignOptions 注释)、`.github/workflows/desktop.yml`(env 段)。*
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mingdao-harness",
3
- "version": "0.1.57",
4
- "description": "明道 MingDao —— 开源智能体框架(Agent Harness)。零依赖、开箱即用,针对 DeepSeek-V4 系列优化,开放主流模型接入。",
3
+ "version": "0.1.59",
4
+ "description": "MingDao Harness —— 开源智能体框架(Agent Harness)。零依赖、开箱即用,针对 DeepSeek-V4 系列优化,开放主流模型接入。",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "mingdao": "src/cli.js",
package/src/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // MingDao(明道)CLI 入口:初始化向导、凭证管理、单次提问、交互式 TUI 会话。
2
+ // MingDao Harness CLI 入口:初始化向导、凭证管理、单次提问、交互式 TUI 会话。
3
3
  // 会话能力:/plan 计划模式、/compact 上下文压缩、/init、/memory、/skills、
4
4
  // /mode 模型快捷切换、/verbose 思考开关、/status、/cost、会话选择恢复。
5
5
 
@@ -65,7 +65,7 @@ import {
65
65
  const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
66
66
 
67
67
  const HELP_LINES = [
68
- [`MingDao 明道 · AI 智能体框架 v${pkg.version}(命令:mingdao,简写 mdh)`, C.bold + C.cyan],
68
+ [`MingDao Harness · AI 智能体框架 v${pkg.version}(命令:mingdao,简写 mdh)`, C.bold + C.cyan],
69
69
  ['', null],
70
70
  ['用法', C.bold + C.yellow],
71
71
  [' mingdao 交互式对话(TUI)', null],
@@ -600,7 +600,7 @@ async function main() {
600
600
  const routing = routingConfig(cfg);
601
601
  const wsNow = currentWorkspace(workingDir);
602
602
  io.print('');
603
- io.box(`MingDao 明道 v${pkg.version}`, [
603
+ io.box(`MingDao Harness v${pkg.version}`, [
604
604
  `模型 ${modelName}${preset?.label ? '(' + preset.label + ')' : ''}`,
605
605
  `权限 ${permission.mode} · 密钥 ${keySource}`,
606
606
  `沙箱 ${sandboxLabel}${routing ? ` · 路由 ${routing.planner}⇄${routing.executor}` : ''}`,
@@ -1090,7 +1090,7 @@ async function main() {
1090
1090
  try {
1091
1091
  await maybeAutoSync();
1092
1092
  } catch {}
1093
- io.print('再见,明道与你同行。');
1093
+ io.print('再见,MingDao Harness 与你同行。');
1094
1094
  io.close();
1095
1095
  }
1096
1096
 
@@ -31,7 +31,7 @@ export async function handleDesktop(args) {
31
31
  process.exitCode = 1;
32
32
  return true;
33
33
  }
34
- console.log('正在启动 明道 MingDao 桌面版…(窗口弹出即成功;托盘常驻,关闭窗口 = 最小化到托盘)');
34
+ console.log('正在启动 MingDao Harness 桌面版…(窗口弹出即成功;托盘常驻,关闭窗口 = 最小化到托盘)');
35
35
  const child = spawn(localBin, [desktopDir], { cwd: desktopDir, stdio: 'ignore', detached: true });
36
36
  child.on('error', (err) => {
37
37
  console.log('[错误] 启动 Electron 失败:' + (err?.message || err));
@@ -0,0 +1,5 @@
1
+ {
2
+ "type": "module",
3
+ "private": true,
4
+ "description": "显式声明 src/ 为 ESM:桌面版打包后 resources/src/ 上方无 package.json,Electron 31(Node 20.14,无语法探测)会把 .js 当 CJS 加载报「Cannot use import statement outside a module」。此文件随 extraResources 一并打包。"
5
+ }
package/src/prompts.js CHANGED
@@ -7,7 +7,7 @@ import { skillsRegistryBlock } from './skills.js';
7
7
  import { mingdaoHome } from './config.js';
8
8
  import { recentJournalBlock } from './memory.js';
9
9
 
10
- const BASE = `你是 MingDao(明道),一个由 MingDao-Harness 驱动的 AI 编程助手。你在用户的电脑上工作:通过工具读写文件、搜索代码、执行命令,帮助用户完成编程、调试与自动化任务。
10
+ const BASE = `你是 MingDao Harness,一个由 MingDao Harness 驱动的 AI 编程助手。你在用户的电脑上工作:通过工具读写文件、搜索代码、执行命令,帮助用户完成编程、调试与自动化任务。
11
11
 
12
12
  工作准则:
13
13
  1. 先了解再动手:修改或创建代码前,先用 read / ls / glob / grep 查看相关文件,不要凭空猜测。
Binary file
Binary file
@@ -3,9 +3,9 @@
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>MingDao 明道</title>
6
+ <title>MingDao Harness</title>
7
7
  <link rel="manifest" href="/manifest.webmanifest">
8
- <link rel="icon" href="/icon.svg" type="image/svg+xml">
8
+ <link rel="icon" href="/icon-192.png" type="image/png">
9
9
  <meta name="theme-color" content="#0f1115">
10
10
  <style>
11
11
  :root{
@@ -124,7 +124,7 @@ footer{flex:none;border-top:1px solid var(--border);background:var(--bg2);paddin
124
124
  </head>
125
125
  <body>
126
126
  <header>
127
- <div class="logo">MingDao <span>明道</span></div>
127
+ <div class="logo">MingDao <span>Harness</span></div>
128
128
  <select id="modelSel" title="切换模型"></select>
129
129
  <select id="permSel" title="权限模式">
130
130
  <option value="ask">权限 ask</option>
package/src/web/server.js CHANGED
@@ -402,7 +402,7 @@ export async function runWebServer({ host = '127.0.0.1', port = 3820, authToken
402
402
  // 访问控制(P1-3/P1-4):token 校验覆盖数据与操作接口;壳页面与 PWA 静态资源公开
403
403
  // (壳不含任何数据,SPA 需要先加载才能读取 ?token=);Host 白名单覆盖一切请求
404
404
  const isStaticAsset =
405
- p === '/' || p === '/index.html' || p === '/favicon.ico' || p === '/icon.svg' || p === '/manifest.webmanifest' || p === '/sw.js';
405
+ p === '/' || p === '/index.html' || p === '/favicon.ico' || p === '/icon.svg' || p === '/icon-192.png' || p === '/icon-512.png' || p === '/manifest.webmanifest' || p === '/sw.js';
406
406
  if (authEnabled && !isStaticAsset && !tokenMatches(requestToken(req, url))) {
407
407
  return json(res, 401, { error: '未授权:缺少或无效的访问令牌(地址需带 ?token=…,或请求头携带 X-MingDao-Token)' });
408
408
  }
@@ -440,9 +440,16 @@ export async function runWebServer({ host = '127.0.0.1', port = 3820, authToken
440
440
  }
441
441
  return;
442
442
  }
443
- if (req.method === 'GET' && p === '/favicon.ico') {
444
- res.writeHead(204);
445
- res.end();
443
+ // 统一品牌图标:浏览器标签页 /favicon.ico 直接返回 192 PNG
444
+ if (req.method === 'GET' && (p === '/favicon.ico' || p === '/icon-192.png' || p === '/icon-512.png')) {
445
+ try {
446
+ const file = path.join(path.dirname(fileURLToPath(import.meta.url)), 'icons', p === '/icon-512.png' ? 'icon-512.png' : 'icon-192.png');
447
+ const buf = fs.readFileSync(file);
448
+ res.writeHead(200, { 'Content-Type': 'image/png', 'Cache-Control': 'public, max-age=86400' });
449
+ res.end(buf);
450
+ } catch {
451
+ json(res, 404, { error: 'icon missing' });
452
+ }
446
453
  return;
447
454
  }
448
455
  if (req.method === 'GET' && p === '/api/state') {
@@ -1087,14 +1094,17 @@ export async function runWebServer({ host = '127.0.0.1', port = 3820, authToken
1087
1094
  res.writeHead(200, { 'Content-Type': 'application/manifest+json; charset=utf-8' });
1088
1095
  res.end(
1089
1096
  JSON.stringify({
1090
- name: 'MingDao 明道',
1097
+ name: 'MingDao Harness',
1091
1098
  short_name: 'MingDao',
1092
1099
  description: 'MingDao-Harness 智能体框架 WebUI',
1093
1100
  start_url: '/',
1094
1101
  display: 'standalone',
1095
1102
  background_color: '#0f1115',
1096
1103
  theme_color: '#0f1115',
1097
- icons: [{ src: '/icon.svg', sizes: 'any', type: 'image/svg+xml', purpose: 'any' }],
1104
+ icons: [
1105
+ { src: '/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any' },
1106
+ { src: '/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable' },
1107
+ ],
1098
1108
  })
1099
1109
  );
1100
1110
  return;