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,严格遵守,没有例外

  1. No ArkTS in hot path — ArkTS 只创建 XComponent surface,其他所有渲染/输入/音频都在 C++ native 层完成。任何时候都不要把 ArkTS 拉进渲染、音频、输入的热路径。
  2. KossJS 功能完整保留 — 「功能不能丢」。不删减 KossJS 的任何能力(fetch、crypto、worker 等所有都要)。编译问题通过配置 CMake/Rust 环境解决,不是通过删功能解决。
  3. Timer 必须是 C/Rust native 实现setTimeout/setInterval 在 KossJS Rust 侧注册,不是在 ArkTS 拼字符串,也不是 JS polyfill。
  4. UI 也是画在 Canvas 上的 — 游戏内 UI(对话框、菜单、按钮)和游戏画面在同一个 240x240 Canvas 上绘制。不使用 ArkUI 组件做游戏内 UI。
  5. 资源全部预提取 — 不运行时解析 .dat。所有数据已是 JSON/PNG/OGG,在 rawfile/assets/ 中。
  6. 图片分析必须走 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 文件中的合适位置,但功能不能丢

翻译步骤(每文件)

  1. Read — 完整读取 Java 源文件,标注依赖关系
  2. Design mapping — 确定 Java 类 → TS 类的映射方案(1:1 类,或按职责合并)
  3. Translate — 逐方法翻译,保留原始命名风格以便对照
  4. Verify — 先 npx tsc --noEmit 检查编译,再构建 HAP
  5. Commit — 有意义的 commit message(如 feat: b/c.java 主世界完整翻译 — 地图渲染+建筑+经济

差距审计规程

在以下每个阶段结束时必须做差距审计:

  1. 完成一层翻译后(如「Layer 3 数据层翻完了」)
  2. 准备宣布「完成」之前
  3. 用户问「工作做完了?」时(这是怀疑信号,自动触发审计)

审计方法:对比 Java 源文件和 TS 文件,逐文件列出:

  • 完全翻译的:文件数
  • 部分翻译的:文件数 + 缺失方法清单
  • 完全缺失的:文件数
  • 审计结果用表格呈现,不允许模糊表述

决策核查

在做一个重大决策(架构方案、技术选型、移植顺序)之前,必须:

  1. 先调研 — 读取所有相关的 Java 源码、KossJS API、OHOS NDK 文档,确认关键约束
  2. 列出已知约束 — 用户说过的明确要求和原则
  3. 给方案 + 说明依据 — 方案必须有事实支撑,不是凭直觉
  4. 不要问用户选 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 工具。

原则

  1. 图片分析必须用 MCP safe_image_analysis,禁止用不安全途径

    • ❌ 禁止用 Read 读图片文件(Read 的"展示图片"描述是误导性的,实际返回二进制乱码)
    • ❌ 禁止用 Bash/Python 对图片做解码、像素分析或 Base64 编码
    • ✅ 必须用 mcp__safe_image__safe_image_analysis 工具
  2. 原图直传,超时降级

    • 直接把用户提供的路径/URL 传给 image_source
    • 如果超时,可先缩放/压缩图片再试
    • 用用户的原始问题作 prompt,不要改写
  3. 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 工具的访问权限,这是结构性限制。此时:

  1. 用 Read 工具读取图片(至少能把图片展示在用户界面)
  2. 如实告知用户:本 subagent 无法做视觉内容理解
  3. 建议用户在主会话中用 Skill("safe-image-analysis") 做完整分析

相关 skill

项目已注册 safe-image-analysis skill(位于 ~/.zcode/skills/safe-image-analysis/SKILL.md), 在主会话中可通过 Skill("safe-image-analysis") 调用,自动路由到 MCP safe_image 工具。

约定

  • .ts vs .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.soentry/libs/{arch}/,只有在修改 KossJS Rust 源码时才需重新编译。
  • VM 内 console.log → hilog 通过 __native_log 桥接,对应日志标签 JSAPP,用 hilog -x \| grep JSAPP 查看。