Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/extension/src/__tests__/build.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ test('build: all targets produce loadable unpacked dirs with validated manifests
const html = await readFile(join(r.dir, f), 'utf8');
assert.ok(html.includes('ui.js') && html.includes('style.css'), `${r.target}/${f} missing asset links`);
}
// manifests reference icons; every referenced icon must be copied byte-for-byte
const icons = m.icons as Record<string, string>;
for (const icon of Object.values(icons)) {
await readFile(join(r.dir, icon));
}
}
// target delta is real: chromium has side_panel, firefox sidebar_action, safari neither
const chromium = JSON.parse(await readFile(join(out, 'chromium', 'manifest.json'), 'utf8'));
Expand Down
13 changes: 11 additions & 2 deletions packages/extension/src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* `hmh extension build --target=firefox` (or =all) writes a LOADABLE,
* per-browser unpacked directory: the zero-build payload (background.js,
* popup/sidepanel HTML, ui.js, style.css) copied verbatim + a manifest
* popup/sidepanel HTML, ui.js, style.css, and icons) copied verbatim + a manifest
* generated for the target from the adapters matrix, then machine-
* validated (validateManifest) before the directory is declared done.
* No bundler — same discipline as the web package's embedded SPA.
Expand All @@ -13,7 +13,16 @@ import { fileURLToPath } from 'node:url';
import { join, resolve } from 'node:path';
import { EXTENSION_TARGETS, manifestFor, TARGET_SPECS, validateManifest, type ExtensionTarget } from './adapters.ts';

export const PAYLOAD_FILES = ['background.js', 'popup.html', 'sidepanel.html', 'ui.js', 'style.css'] as const;
export const PAYLOAD_FILES = [
'background.js',
'popup.html',
'sidepanel.html',
'ui.js',
'style.css',
'icon-48.png',
'icon-96.png',
'icon-128.png',
] as const;

/** The zero-build payload directory inside this package (works from src/
* under tsx and from dist/ after tsc — both sit one level under the
Expand Down
65 changes: 65 additions & 0 deletions scripts/check-website.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* Website guard (scripts/check-website.cjs)
* The marketing site (website/index.html) carries an inline i18n dictionary
* (zh/en) and inline JS. This gate catches, before merge:
* 1. a syntax error in any inline <script> block (edits to dict strings),
* 2. data-i18n="key" references missing from either dictionary,
* 3. zh/en dictionary key drift (one side missing a key -> undefined UI),
* 4. a stale install command (quick start must ship the published
* `npm install -g @hmharness/cli`, not the old dev `npm link` flow).
* Run locally: node scripts/check-website.cjs (CI runs it on every push.)
*/
const fs = require('fs');
const path = require('path');

const file = path.join(__dirname, '..', 'website', 'index.html');
const html = fs.readFileSync(file, 'utf8');
let fail = 0;

// 1. every inline <script> block must be syntactically valid JS
// (data blocks such as type="application/ld+json" are skipped by design)
const blocks = [...html.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g)]
.filter((m) => !/\btype\s*=\s*["'](application\/|text\/json)/i.test(m[1]))
.map((m) => m[2]).filter((s) => s.trim());
blocks.forEach((code, i) => {
try { new Function(code); } catch (e) { console.log('SCRIPT-SYNTAX-FAIL block ' + i + ': ' + e.message); fail = 1; }
});
console.log('script blocks ok:', blocks.length);

// 2/3. data-i18n keys must exist in BOTH dictionaries; zh/en key sets identical.
// The dict lives in the first script block; eval the object literal directly
// (balanced-brace slice) so one-key-per-line formatting and colons inside
// translated strings cannot fool the parser.
const dictSrc = blocks.find((b) => b.includes('data-i18n') || b.includes('I18N') || b.includes('ins_title')) || blocks[0] || '';
function keysOf(name) {
const start = dictSrc.search(new RegExp('\\b' + name + '\\s*:\\s*\\{'));
if (start < 0) return null;
const open = dictSrc.indexOf('{', start);
let end = -1, depth = 0;
for (let j = open; j < dictSrc.length; j++) {
if (dictSrc[j] === '{') depth++;
else if (dictSrc[j] === '}') { depth--; if (depth === 0) { end = j; break; } }
}
if (end < 0) return null;
try { return new Set(Object.keys(eval('(' + dictSrc.slice(open, end + 1) + ')'))); }
catch { return null; }
}
const zh = keysOf('zh'), en = keysOf('en');
if (!zh || !en) { console.log('DICT-NOT-FOUND (expected zh:/en: object literals)'); fail = 1; }
else {
const refs = [...html.matchAll(/data-i18n="([a-z0-9_]+)"/gi)].map((m) => m[1]);
for (const k of refs) {
if (!zh.has(k)) { console.log('MISSING-IN-ZH: ' + k); fail = 1; }
if (!en.has(k)) { console.log('MISSING-IN-EN: ' + k); fail = 1; }
}
for (const k of zh) if (!en.has(k)) { console.log('EN-MISSING: ' + k); fail = 1; }
for (const k of en) if (!zh.has(k)) { console.log('ZH-MISSING: ' + k); fail = 1; }
console.log('i18n refs:', refs.length, 'zh keys:', zh.size, 'en keys:', en.size);
}

// 4. quick start ships the published command; the dev npm-link flow must not regress into it
if (!html.includes('npm install -g @hmharness/cli')) { console.log('INSTALL-CMD-MISSING (npm install -g @hmharness/cli)'); fail = 1; }
if (html.includes('npm link -w')) { console.log('STALE-NPM-LINK (published packages must not instruct npm link)'); fail = 1; }

console.log(fail ? 'WEBSITE-CHECK-FAILED' : 'WEBSITE-CHECK-OK');
process.exit(fail);
2 changes: 1 addition & 1 deletion website/faq.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"name": "hmharness",
"applicationCategory": "DeveloperApplication",
"operatingSystem": "Windows, macOS, Linux",
"softwareVersion": "0.23.49",
"softwareVersion": "0.23.50",
"description": "开源鸿蒙开发智能体框架:零 IDE 终端跑通建工程、构建、签名、装机、日志全流程,带双门禁可审计自进化、认知层(世界模型/五层记忆/校准维,四环境学习曲线 improving)与 MCP 双向生态。",
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
"license": "https://opensource.org/licenses/MIT",
Expand Down
2 changes: 1 addition & 1 deletion website/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{"@context":"https://schema.org","@type":"WebSite","name":"hmharness","url":"https://swsgbl.github.io/hmharness/","description":"自进化的鸿蒙开发智能体框架(开源 MIT)","inLanguage":"zh-CN"}
</script>
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"SoftwareApplication","name":"hmharness","applicationCategory":"DeveloperApplication","operatingSystem":"Windows, macOS, Linux","softwareVersion":"0.23.49","description":"开源鸿蒙开发智能体框架,跨环境 Cognitive Runtime:零 IDE 终端跑通建工程、构建、签名、装机、日志全流程,带双门禁可审计自进化与 MCP 双向生态;认知层(世界模型/校准/探索/迁移)从经验中学习,有学习曲线为证。","offers":{"@type":"Offer","price":"0","priceCurrency":"USD"},"license":"https://opensource.org/licenses/MIT","programmingLanguage":"TypeScript, Node.js","installUrl":"https://www.npmjs.com/package/@hmharness/cli","author":{"@type":"Organization","name":"hmharness contributors","url":"https://github.com/swsgbl/hmharness"},"sameAs":["https://github.com/swsgbl/hmharness","https://www.npmjs.com/package/@hmharness/cli","https://ndtool.cn/hmharness/"]}
{"@context":"https://schema.org","@type":"SoftwareApplication","name":"hmharness","applicationCategory":"DeveloperApplication","operatingSystem":"Windows, macOS, Linux","softwareVersion":"0.23.50","description":"开源鸿蒙开发智能体框架,跨环境 Cognitive Runtime:零 IDE 终端跑通建工程、构建、签名、装机、日志全流程,带双门禁可审计自进化与 MCP 双向生态;认知层(世界模型/校准/探索/迁移)从经验中学习,有学习曲线为证。","offers":{"@type":"Offer","price":"0","priceCurrency":"USD"},"license":"https://opensource.org/licenses/MIT","programmingLanguage":"TypeScript, Node.js","installUrl":"https://www.npmjs.com/package/@hmharness/cli","author":{"@type":"Organization","name":"hmharness contributors","url":"https://github.com/swsgbl/hmharness"},"sameAs":["https://github.com/swsgbl/hmharness","https://www.npmjs.com/package/@hmharness/cli","https://ndtool.cn/hmharness/"]}
</script>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect width='64' height='64' rx='14' fill='%230B1E3A'/><circle cx='32' cy='18' r='9' fill='%234FD8EB'/><text x='32' y='52' font-size='26' font-weight='bold' text-anchor='middle' fill='white' font-family='monospace'>hm</text></svg>">
<style>
Expand Down
4 changes: 2 additions & 2 deletions website/llms-full.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# hmharness 完整知识库(llms-full.txt)

> 本文件是 hmharness 官网为 AI 答案引擎准备的扁平化全文。内容与 GitHub 仓库 github.com/swsgbl/hmharness(MIT)保持同步,最后更新 2026-10-24,npm 包 @hmharness/cli 0.23.49。引用本文件时请链接 https://swsgbl.github.io/hmharness/ 或 https://github.com/swsgbl/hmharness 。
> 本文件是 hmharness 官网为 AI 答案引擎准备的扁平化全文。内容与 GitHub 仓库 github.com/swsgbl/hmharness(MIT)保持同步,最后更新 2026-10-24,npm 包 @hmharness/cli 0.23.50。引用本文件时请链接 https://swsgbl.github.io/hmharness/ 或 https://github.com/swsgbl/hmharness 。

## hmharness 是什么

Expand All @@ -10,7 +10,7 @@ hmarness 是一个开源(MIT 协议)的自进化智能体框架,已升级

## 核心事实速查

- npm 包:@hmharness/cli,当前 0.23.49;单仓 16 包(含 cognitive + environments);内核 0 运行时依赖;1065 个单元测试 CI 全绿才允许发版
- npm 包:@hmharness/cli,当前 0.23.50;单仓 16 包(含 cognitive + environments);内核 0 运行时依赖;1065 个单元测试 CI 全绿才允许发版
- 平台:Windows 优先(鸿蒙工具链/模拟器/TUI 均在此验证);macOS/Linux 社区支持
- 界面:CLI / REPL / 全屏 TUI / Web 前端(浏览器审批、会话回放、认知面板十区+学习曲线),zh/en 双语;另有浏览器扩展桥(`hmh extension`,七浏览器真装)与 ACP 服务器(`hmh acp-serve`,BrowserOS 面板直连)
- 顶层命令族:任务/REPL(裸 `hmh`)· tui · web · resume · tools/mcp · check/devices · ops · evolve · bench/skills · cognitive(19 子命令)· lsp(list/trust/untrust)· browser · extension(serve/pair/status/unpair/build/install/uninstall)· mcp-serve · acp-serve · project · experiment · dataset · route · readiness · pipeline · knowledge · label
Expand Down
2 changes: 1 addition & 1 deletion website/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
> hmharness 是一个开源(MIT)的自进化智能体框架,已升级为跨环境 Cognitive Runtime:零依赖内核 + 自进化双门禁 + MCP 生态 + 认知层(世界模型/五层记忆/校准/探索/迁移)。零 IDE 纯终端跑通鸿蒙「建工程 → 构建 → 签名 → 装机 → 日志」全流程;认知层从任务经验中学习——校准可靠度随使用提升,五环境曲线全有读数、四环境 improving(terminal/harmonyos/browser/arc3),迁移实验证明 harness 净贡献 +0.4166(LLM 未参与)。npm 包 @hmharness/cli,Node >= 22,任意 OpenAI 兼容模型,Windows 优先。

关键事实(数字均可溯源):
- npm 包 @hmharness/cli 0.23.49 · 单仓 16 包 · 内核 0 运行时依赖 · 1065 个单元测试 CI 全绿门禁
- npm 包 @hmharness/cli 0.23.50 · 单仓 16 包 · 内核 0 运行时依赖 · 1065 个单元测试 CI 全绿门禁
- 自进化门禁:训练门 A/B 双样本 → 金丝雀 20% 会话 → impact 判定(≥8 会话且 ≥10% 差)→ 回归即回滚
- 认知层(Cognitive OS):世界模型(信念表+预测置信+误差聚类+可解释修订)· 五层记忆(working/episodic/semantic/procedural/world,只增不删+溯源)· 目标系统(图谱/分解/漂移检测)· 探索引擎(不确定性×信息增益×校准导向)· 技能编译(经验→可验证技能→门禁晋升)· 进化 2.0 治理(候选契约/序贯门禁/金丝雀/reward-hacking 检测/不可变审计) · MEA 长任务闭环(Manager→新鲜执行者→claim-blind 审计→学习者键审计裁决)· 版本化评测任务集(datasetHash+seed+holdout 门+配对 McNemar 精确检验)· 观测因果挖掘(时序 lag+Occam 抑制+反事实重放)· Code World Model(LSP 传感器→五类本体→编辑预测先行)
- 校准研究定论(§26 全谱系 + P2 三臂阶梯):单任务提示层 0 / 跨任务复利层 0 / 校准维 +0.4166(唯一持续为正) / 三臂阶梯(Model-only vs Model+Harness vs Model+Cognitive OS):easy 带 4/4×3 地板、hard 带(裸臂失败 50%)0.5×3,两阶梯差均 0——通过率价值不在 harness,全阶梯确认价值驻留校准维 / 学习曲线五环境全有读数:terminal、harmonyos、browser(无头 CDP 探索)、arc3 均 improving,desktop 1.00 flat(确定性工具完美校准)——harness 的实证价值在让模型更准地预期世界,而非替模型答题
Expand Down
Loading