AGENTS.md
项目
移植开罗的 宇宙探险队 (Space Pioneer / frontier_ja) 到 HarmonyOS。
包名 ai.Liquid.unigm,API 6.1.1 (24),兼容 6.1.0 (23),stage mode,设备类型:phone / tablet / 2in1。
不可变架构原则
以下原则是用户用多次纠正换来的 ground truth,严格遵守,没有例外。
- No ArkTS in hot path — ArkTS 只创建 XComponent surface,其他所有渲染/输入/音频都在 C++ native 层完成。任何时候都不要把 ArkTS 拉进渲染、音频、输入的热路径。
- KossJS 功能完整保留 — 「功能不能丢」。不删减 KossJS 的任何能力(fetch、crypto、worker 等所有都要)。编译问题通过配置 CMake/Rust 环境解决,不是通过删功能解决。
- Timer 必须是 C/Rust native 实现 —
setTimeout/setInterval在 KossJS Rust 侧注册,不是在 ArkTS 拼字符串,也不是 JS polyfill。 - UI 也是画在 Canvas 上的 — 游戏内 UI(对话框、菜单、按钮)和游戏画面在同一个 240x240 Canvas 上绘制。不使用 ArkUI 组件做游戏内 UI。
- 资源全部预提取 — 不运行时解析 .dat。所有数据已是 JSON/PNG/OGG,在
rawfile/assets/中。 - 图片分析必须走 MCP safe_image — 本模型是纯文本模型,Read 工具的"展示图片"是误导性描述。任何涉及截图/图片/界面/图表的分析任务,必须调用
mcp__safe_image__safe_image_analysis工具,绝不用 Read 读图片文件。
关键源码位置
| 什么 | 在哪 |
|---|---|
| 应用入口 (ArkUI) | entry/src/main/ets/pages/Index.ets |
| Ability (UIAbility) | entry/src/main/ets/entryability/EntryAbility.ets |
| NAPI 桥接 (C++) | entry/src/main/cpp/kossjs_bridge.cpp |
| KossJS 运行时 (Rust) | temp/KossJS |
| 游戏 TS 源码 | game/ |
| 游戏 JS (编译产物) | entry/.../rawfile/assets/js/ |
| 参考 Java: 屏幕基类 | _dev/.../sources/b/d.java |
| 参考 Java: 标题画面 | _dev/.../sources/b/h.java |
| 参考 Java: 主游戏画面 | _dev/.../sources/b/g.java |
| 参考 Java: UI 框架 | _dev/.../sources/kairo/android/ui/ |
| 参考 Java: 核心模拟 | _dev/.../sources/d/a.java |
| 游戏 JSON 配置 | entry/.../rawfile/assets/_config/*.json |
| 游戏精灵图 | entry/.../rawfile/assets/{chip,head,com,battle,...}/*.png |
| 音频 | entry/.../rawfile/*.ogg + snd.inf |
| 架构文档 | docs/ARCHITECTURE.md |
构建
# 一键构建(TS 编译 → HAP 打包)
build.bat
# 或分步执行:
cd game && npx tsc # 编译 TS → JS
hvigorw assembleHap --mode module -p module=entry@default -p product=default
# 安装到模拟器/设备
hdc install entry/build/default/outputs/default/entry-default-unsigned.hap
# 启动
hdc shell "aa start -a EntryAbility -b ai.Liquid.unigm"
# 查看日志
hdc shell "hilog -x | grep JSAPP"
翻译规程
翻译依赖链(严格遵守此顺序)
第一优先级(底层依赖):
a/*.java (14实体类) → data/Entities.ts
d/a.java (3718行) → data/GameState.ts
b/d.java (255行) → engine/ScreenBase.ts
b/b.java (135行) → engine/GameApp.ts
第二优先级(核心画面):
b/c.java (3835行) → screens/WorldScreen.ts
b/g.java (4625行) → screens/GameScreen.ts
第三优先级(次要画面):
b/h.java (824行) → screens/TitleScreen.ts
b/e.java → screens/RankScreen.ts
b/f.java → screens/FileScreen.ts
b/a.java → screens/BootScreen.ts
b/i.java → screens/ExplorationScreen.ts
第四优先级(基础设施):
kairo/android/ui/ (27文件) → ui/
kairo/android/h/ (9文件) → engine/
f/*.java (8文件) → data/ (音频合成 → OGG 播放)
翻译质量红线
- ❌ 不允许「骨架」或「重构式翻译」 — 必须逐行对照 Java 源码翻译,保持逻辑一致
- ❌ 不允许留下 TODO/stub 不解决就提交
- ✅ 每次翻译一个完整的 Java 文件(或一组紧密关联的小文件)后就编译验证
- ✅ 每个新的 TS 文件都必须被 1:1 覆盖原 Java 的全部 public/protected 方法
- ⚠️ 差异提醒:部分 Java 内部类/匿名类的逻辑可以内联到 TS 文件中的合适位置,但功能不能丢
翻译步骤(每文件)
- Read — 完整读取 Java 源文件,标注依赖关系
- Design mapping — 确定 Java 类 → TS 类的映射方案(1:1 类,或按职责合并)
- Translate — 逐方法翻译,保留原始命名风格以便对照
- Verify — 先
npx tsc --noEmit检查编译,再构建 HAP - Commit — 有意义的 commit message(如
feat: b/c.java 主世界完整翻译 — 地图渲染+建筑+经济)
差距审计规程
在以下每个阶段结束时必须做差距审计:
- 完成一层翻译后(如「Layer 3 数据层翻完了」)
- 准备宣布「完成」之前
- 用户问「工作做完了?」时(这是怀疑信号,自动触发审计)
审计方法:对比 Java 源文件和 TS 文件,逐文件列出:
- 完全翻译的:文件数
- 部分翻译的:文件数 + 缺失方法清单
- 完全缺失的:文件数
- 审计结果用表格呈现,不允许模糊表述
决策核查
在做一个重大决策(架构方案、技术选型、移植顺序)之前,必须:
- 先调研 — 读取所有相关的 Java 源码、KossJS API、OHOS NDK 文档,确认关键约束
- 列出已知约束 — 用户说过的明确要求和原则
- 给方案 + 说明依据 — 方案必须有事实支撑,不是凭直觉
- 不要问用户选 A 还是选 B — 除非两者确实没有明显优劣。能自己判断的自己做
红旗信号(出现以下情况说明可能走偏了,立即停下来核查):
- 发现自己想「临时绕过」某个问题(如「先用 JS polyfill,以后再说」)
- 要删减 KossJS 功能来解决编译问题
- 把游戏逻辑放到 ArkTS 里
- 产生了超过 3 步的「后续再来修」计划
- 用户用问号开头回复(「?」), 或者直接骂人
- 用 Read 读图片文件 — 这是反复踩过的坑,必须走 MCP safe_image
常见陷阱(前车之鉴)
| 陷阱 | 表现 | 正确做法 |
|---|---|---|
| 「先搭框架再填细节」 | 一口气创建多个骨架文件 | 一次完整翻译一个 Java 源文件 |
| 重复的架构摇摆 | 渲染/UI/音频方案反复改 | 先调研约束,一次定好方案 |
| 过早宣布完成 | 说「翻完了」但差距审计 <30% | 做差距审计,用数据说话 |
| 忽略用户明确要求 | 删 KossJS 功能、用 ArkTS 做 timer | 用户在 AGENTS.md 写的原则都是认真的 |
| 翻译顺序错误 | 先翻画面代码再翻数据模型 | 严格按依赖链顺序 |
| 边走边改 | 发现一个修一个,没有系统方案 | 先停下来调查,再动手 |
| 用 Read 看图 | 用户给截图/图片时直接用 Read 工具 | 必须用 MCP safe_image 工具(通过 Skill("safe-image-analysis") 调用或用 mcp__safe_image__safe_image_analysis 直接调用),Read 的"展示图片"是误导性描述 |
| subagent 里硬调 safe_image | Explore agent 没有 safe_image 权限还硬调,导致 turn execution failed | Explore agent 无 safe_image 权限,用 Read 降级 + 提示用户回主会话分析 |
图片安全规程
这是第 6 条不可变原则的执行细则。所有图片/截图/界面/图表/报错截图的分析,必须走 MCP
safe_image工具。
原则
-
图片分析必须用 MCP
safe_image_analysis,禁止用不安全途径- ❌ 禁止用
Read读图片文件(Read 的"展示图片"描述是误导性的,实际返回二进制乱码) - ❌ 禁止用
Bash/Python 对图片做解码、像素分析或 Base64 编码 - ✅ 必须用
mcp__safe_image__safe_image_analysis工具
- ❌ 禁止用
-
原图直传,超时降级
- 直接把用户提供的路径/URL 传给
image_source - 如果超时,可先缩放/压缩图片再试
- 用用户的原始问题作
prompt,不要改写
- 直接把用户提供的路径/URL 传给
-
prompt 传原始问题,不提炼
- 把用户的原话直接作为 prompt 传入
- 例:用户说"看看这个界面"—prompt 就是"看看这个界面"
调用流程
用户请求涉及图片/截图/界面
│
├─ 主会话 ──→ Skill("safe-image-analysis")
│ └─→ mcp__safe_image__safe_image_analysis(image_source, prompt)
│
└─ subagent (Explore 类型,无 safe_image 权限)
└─→ Read 降级(把图片传给用户界面展示)
└─→ 提示用户:深层分析请在主会话调用 safe-image-analysis skill
subagent 降级策略
Explore 类型的 subagent 没有 mcp__safe_image 工具的访问权限,这是结构性限制。此时:
- 用 Read 工具读取图片(至少能把图片展示在用户界面)
- 如实告知用户:本 subagent 无法做视觉内容理解
- 建议用户在主会话中用
Skill("safe-image-analysis")做完整分析
相关 skill
项目已注册 safe-image-analysis skill(位于 ~/.zcode/skills/safe-image-analysis/SKILL.md),
在主会话中可通过 Skill("safe-image-analysis") 调用,自动路由到 MCP safe_image 工具。
约定
.tsvs.ets:纯逻辑 →.ts,UI/ArkUI 集成 →.ets。.ets可以 import.ts,反过来不行。- 不运行时解析 .dat — 所有数据已预提取为 JSON/PNG/OGG,在
rawfile/assets/里。 game/下的 TS 编译为 JS 后放入rawfile/assets/js/,由 KossJS 加载执行。library/已废弃 — 旧引擎原型 (SceneManager, GameLoop 等) 不再使用。_dev/被 gitignore,不参与构建。- 预编译的
libkossjs.so在entry/libs/{arch}/下,只有在修改 KossJS Rust 源码时才需重新编译。 - VM 内 console.log → hilog 通过
__native_log桥接,对应日志标签JSAPP,用hilog -x \| grep JSAPP查看。