Visitar URL original
Merge pull request #138 from tmoonlight/claude/release-v1.0.8-integra… · tmoonlight/acecode@0da39f3 · GitHub
Skip to content

Commit 0da39f3

Browse files
Merge pull request #138 from tmoonlight/claude/release-v1.0.8-integration
Release v1.0.8: merge iOS Simulator control and bump the version
2 parents 7dff491 + 7c1e846 commit 0da39f3

93 files changed

Lines changed: 9951 additions & 26 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.acecode/skills/verify-package/scripts/verify_package.py‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ def print_dry_run(repo: Path, build_dir: Path, staging: Path, platform: str,
262262
components = ["models_dev_registry", "default_seed_bundle"]
263263
if platform in ("windows", "darwin"):
264264
components.append("computer_use_runtime")
265+
if platform == "darwin":
266+
components.append("ios_simulator_runtime")
265267
for component in components:
266268
print(" " + " ".join([
267269
cmake_command, "--install", str(build_dir), "--config", "MinSizeRel",
@@ -347,6 +349,8 @@ def stage(report: Report, repo: Path, build_dir: Path, staging: Path,
347349
components = ["models_dev_registry", "default_seed_bundle"]
348350
if platform in ("windows", "darwin"):
349351
components.append("computer_use_runtime")
352+
if platform == "darwin":
353+
components.append("ios_simulator_runtime")
350354
for component in components:
351355
if not run_tool(report, f"cmake install {component}",
352356
[cmake, "--install", str(build_dir),
@@ -364,6 +368,12 @@ def structural_checks(report: Report, repo: Path, staging: Path,
364368
report.add("computer use runtime adjacency", "pass")
365369
else:
366370
report.add("computer use runtime adjacency", "fail", f"missing or empty {helper}")
371+
if platform == "darwin" and "tui" in targets:
372+
simulator = staging / "acecode-ios-sim"
373+
if simulator.is_file() and simulator.stat().st_size > 0 and os.access(simulator, os.X_OK):
374+
report.add("iOS Simulator runtime adjacency", "pass")
375+
else:
376+
report.add("iOS Simulator runtime adjacency", "fail", f"missing or empty {simulator}")
367377
if "tui" in targets or platform != "darwin":
368378
check_models_dev(report, "models_dev registry (staged share/)",
369379
staging / "share" / "acecode" / "models_dev",
@@ -377,7 +387,8 @@ def structural_checks(report: Report, repo: Path, staging: Path,
377387
contents = bundle / "Contents"
378388
for required in (contents / "MacOS" / "ACECode",
379389
contents / "MacOS" / "acecode-daemon",
380-
contents / "MacOS" / "acecode-computer-use"):
390+
contents / "MacOS" / "acecode-computer-use",
391+
contents / "MacOS" / "acecode-ios-sim"):
381392
if required.is_file() and required.stat().st_size > 0 and os.access(required, os.X_OK):
382393
report.add(f"app bundle {required.name}", "pass")
383394
else:

‎.agents/skills/verify-package/scripts/verify_package.py‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ def print_dry_run(repo: Path, build_dir: Path, staging: Path, platform: str,
262262
components = ["models_dev_registry", "default_seed_bundle"]
263263
if platform in ("windows", "darwin"):
264264
components.append("computer_use_runtime")
265+
if platform == "darwin":
266+
components.append("ios_simulator_runtime")
265267
for component in components:
266268
print(" " + " ".join([
267269
cmake_command, "--install", str(build_dir), "--config", "MinSizeRel",
@@ -347,6 +349,8 @@ def stage(report: Report, repo: Path, build_dir: Path, staging: Path,
347349
components = ["models_dev_registry", "default_seed_bundle"]
348350
if platform in ("windows", "darwin"):
349351
components.append("computer_use_runtime")
352+
if platform == "darwin":
353+
components.append("ios_simulator_runtime")
350354
for component in components:
351355
if not run_tool(report, f"cmake install {component}",
352356
[cmake, "--install", str(build_dir),
@@ -364,6 +368,12 @@ def structural_checks(report: Report, repo: Path, staging: Path,
364368
report.add("computer use runtime adjacency", "pass")
365369
else:
366370
report.add("computer use runtime adjacency", "fail", f"missing or empty {helper}")
371+
if platform == "darwin" and "tui" in targets:
372+
simulator = staging / "acecode-ios-sim"
373+
if simulator.is_file() and simulator.stat().st_size > 0 and os.access(simulator, os.X_OK):
374+
report.add("iOS Simulator runtime adjacency", "pass")
375+
else:
376+
report.add("iOS Simulator runtime adjacency", "fail", f"missing or empty {simulator}")
367377
if "tui" in targets or platform != "darwin":
368378
check_models_dev(report, "models_dev registry (staged share/)",
369379
staging / "share" / "acecode" / "models_dev",
@@ -377,7 +387,8 @@ def structural_checks(report: Report, repo: Path, staging: Path,
377387
contents = bundle / "Contents"
378388
for required in (contents / "MacOS" / "ACECode",
379389
contents / "MacOS" / "acecode-daemon",
380-
contents / "MacOS" / "acecode-computer-use"):
390+
contents / "MacOS" / "acecode-computer-use",
391+
contents / "MacOS" / "acecode-ios-sim"):
381392
if required.is_file() and required.stat().st_size > 0 and os.access(required, os.X_OK):
382393
report.add(f"app bundle {required.name}", "pass")
383394
else:

‎.claude/skills/verify-package/scripts/verify_package.py‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ def print_dry_run(repo: Path, build_dir: Path, staging: Path, platform: str,
262262
components = ["models_dev_registry", "default_seed_bundle"]
263263
if platform in ("windows", "darwin"):
264264
components.append("computer_use_runtime")
265+
if platform == "darwin":
266+
components.append("ios_simulator_runtime")
265267
for component in components:
266268
print(" " + " ".join([
267269
cmake_command, "--install", str(build_dir), "--config", "MinSizeRel",
@@ -347,6 +349,8 @@ def stage(report: Report, repo: Path, build_dir: Path, staging: Path,
347349
components = ["models_dev_registry", "default_seed_bundle"]
348350
if platform in ("windows", "darwin"):
349351
components.append("computer_use_runtime")
352+
if platform == "darwin":
353+
components.append("ios_simulator_runtime")
350354
for component in components:
351355
if not run_tool(report, f"cmake install {component}",
352356
[cmake, "--install", str(build_dir),
@@ -364,6 +368,12 @@ def structural_checks(report: Report, repo: Path, staging: Path,
364368
report.add("computer use runtime adjacency", "pass")
365369
else:
366370
report.add("computer use runtime adjacency", "fail", f"missing or empty {helper}")
371+
if platform == "darwin" and "tui" in targets:
372+
simulator = staging / "acecode-ios-sim"
373+
if simulator.is_file() and simulator.stat().st_size > 0 and os.access(simulator, os.X_OK):
374+
report.add("iOS Simulator runtime adjacency", "pass")
375+
else:
376+
report.add("iOS Simulator runtime adjacency", "fail", f"missing or empty {simulator}")
367377
if "tui" in targets or platform != "darwin":
368378
check_models_dev(report, "models_dev registry (staged share/)",
369379
staging / "share" / "acecode" / "models_dev",
@@ -377,7 +387,8 @@ def structural_checks(report: Report, repo: Path, staging: Path,
377387
contents = bundle / "Contents"
378388
for required in (contents / "MacOS" / "ACECode",
379389
contents / "MacOS" / "acecode-daemon",
380-
contents / "MacOS" / "acecode-computer-use"):
390+
contents / "MacOS" / "acecode-computer-use",
391+
contents / "MacOS" / "acecode-ios-sim"):
381392
if required.is_file() and required.stat().st_size > 0 and os.access(required, os.X_OK):
382393
report.add(f"app bundle {required.name}", "pass")
383394
else:

‎.codex/skills/verify-package/scripts/verify_package.py‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ def print_dry_run(repo: Path, build_dir: Path, staging: Path, platform: str,
262262
components = ["models_dev_registry", "default_seed_bundle"]
263263
if platform in ("windows", "darwin"):
264264
components.append("computer_use_runtime")
265+
if platform == "darwin":
266+
components.append("ios_simulator_runtime")
265267
for component in components:
266268
print(" " + " ".join([
267269
cmake_command, "--install", str(build_dir), "--config", "MinSizeRel",
@@ -347,6 +349,8 @@ def stage(report: Report, repo: Path, build_dir: Path, staging: Path,
347349
components = ["models_dev_registry", "default_seed_bundle"]
348350
if platform in ("windows", "darwin"):
349351
components.append("computer_use_runtime")
352+
if platform == "darwin":
353+
components.append("ios_simulator_runtime")
350354
for component in components:
351355
if not run_tool(report, f"cmake install {component}",
352356
[cmake, "--install", str(build_dir),
@@ -364,6 +368,12 @@ def structural_checks(report: Report, repo: Path, staging: Path,
364368
report.add("computer use runtime adjacency", "pass")
365369
else:
366370
report.add("computer use runtime adjacency", "fail", f"missing or empty {helper}")
371+
if platform == "darwin" and "tui" in targets:
372+
simulator = staging / "acecode-ios-sim"
373+
if simulator.is_file() and simulator.stat().st_size > 0 and os.access(simulator, os.X_OK):
374+
report.add("iOS Simulator runtime adjacency", "pass")
375+
else:
376+
report.add("iOS Simulator runtime adjacency", "fail", f"missing or empty {simulator}")
367377
if "tui" in targets or platform != "darwin":
368378
check_models_dev(report, "models_dev registry (staged share/)",
369379
staging / "share" / "acecode" / "models_dev",
@@ -377,7 +387,8 @@ def structural_checks(report: Report, repo: Path, staging: Path,
377387
contents = bundle / "Contents"
378388
for required in (contents / "MacOS" / "ACECode",
379389
contents / "MacOS" / "acecode-daemon",
380-
contents / "MacOS" / "acecode-computer-use"):
390+
contents / "MacOS" / "acecode-computer-use",
391+
contents / "MacOS" / "acecode-ios-sim"):
381392
if required.is_file() and required.stat().st_size > 0 and os.access(required, os.X_OK):
382393
report.add(f"app bundle {required.name}", "pass")
383394
else:

‎.github/workflows/package.yml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ jobs:
504504
--keychain "${{ steps.macos-keychain.outputs.keychain }}" \
505505
--binary "build/${{ matrix.executable }}" \
506506
--binary "build/acecode-computer-use" \
507+
--binary "build/acecode-ios-sim" \
507508
--app "build/ACECode.app"
508509
509510
- name: Notarize and staple macOS app
@@ -629,8 +630,11 @@ jobs:
629630
cmake --install build --config MinSizeRel --prefix "$PWD/$package_dir" --component whatsapp_channel
630631
if [ "$RUNNER_OS" = "macOS" ]; then
631632
cmake --install build --config MinSizeRel --prefix "$PWD/$package_dir" --component computer_use_runtime
633+
cmake --install build --config MinSizeRel --prefix "$PWD/$package_dir" --component ios_simulator_runtime
632634
test -x "$package_dir/acecode-computer-use"
635+
test -x "$package_dir/acecode-ios-sim"
633636
test -x "build/ACECode.app/Contents/MacOS/acecode-computer-use"
637+
test -x "build/ACECode.app/Contents/MacOS/acecode-ios-sim"
634638
fi
635639
validate_models_dev_registry "$package_dir/share/acecode/models_dev"
636640
python3 scripts/verify_seed_bundle.py \
@@ -669,7 +673,9 @@ jobs:
669673
--packaged "$extracted_package/share/acecode/seed"
670674
if [ "$RUNNER_OS" = "macOS" ]; then
671675
test -x "$extracted_package/acecode-computer-use"
676+
test -x "$extracted_package/acecode-ios-sim"
672677
test -x "$extracted_package/ACECode.app/Contents/MacOS/acecode-computer-use"
678+
test -x "$extracted_package/ACECode.app/Contents/MacOS/acecode-ios-sim"
673679
validate_models_dev_registry \
674680
"$extracted_package/ACECode.app/Contents/Resources/share/acecode/models_dev"
675681
python3 scripts/verify_seed_bundle.py \

‎CLAUDE.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,20 @@ JS↔C++ bridge(同进程,webview `bind`,无 HTTP):
737737
- **前端页签只有一个来源**:`web/src/lib/agentBrowserPages.js`(App 级单写者登记表,`App.jsx` 挂载时 `installAgentBrowserPageListener()` + 全量 `reconcileAgentBrowserPageStore()`,ChatView 切会话再按会话对账)→ `previewTabs.js::syncBrowserTabsForSession` 派生页签;本 ChatView 首次见到的页面自动打开并激活(`revealedBrowserPagesRef` 按会话记)。**不要**再从 `agentBrowserActivityFromItems` 创建页签或调无参 `getAgentBrowserState()` 猜全局活动页,活动推断现在只决定彩虹边框与「Agent 切目标页时前置该页签」。旧 Desktop 不带 owner 的事件走 `claimUnownedAgentBrowserPage` 本地认领兜底。
738738
- 回归测试:`tests/desktop/agent_browser_page_directory_test.cpp`、`tests/tool/agent_browser_tools_test.cpp` 的 owner 两条、Windows smoke 的 `SMOKE_OWNERSHIP_OK` 段、前端 `agentBrowserPages.test.js` + `previewTabs.test.js::syncBrowserTabsForSession` + `agentBrowserArchitecture.test.js` 的归属合同。设计全文见 [docs/agent-browser.md](docs/agent-browser.md)「页面归属」。
739739

740+
### iOS 模拟器(openspec add-ios-simulator,仅 macOS)
741+
742+
逆向 Claude Desktop 的同类功能后自研复刻:Claude 用 FBSimulatorControl 的 Swift helper 且要求 xcode-select 指向完整 Xcode;我们的 iOS 同事常用绿色安装的 Xcode,所以 Xcode 必须自动发现 + 可配置。用户文档 [docs/ios-simulator.md](docs/ios-simulator.md),接口 [docs/daemon-api.md](docs/daemon-api.md) 第 20 节。
743+
744+
- **helper `acecode-ios-sim`**(`src/adapters/tool/ios_simulator/helper/*.mm`,CMake 只在 `if(APPLE)` 建,Desktop 拷进 `ACECode.app/Contents/MacOS`,便携包装 `ios_simulator_runtime` 组件;其它平台不构建不打包)。私有 CoreSimulator / SimulatorKit / AccessibilityPlatformTranslation 一律运行期 `NSClassFromString` / `dlsym` + 协议转发,每次调用 `@try` 兜底,不产生链接期符号;Indigo 结构与 DTUHID 报文形状取自 idb(MIT,`helper/LICENSE-idb.txt`)。协议是 header-only 的 `wire.hpp`:`u32le body | u32le json_len | json | binary`,daemon 与 helper 共用。
745+
- **Xcode 选择**(`xcode_locator.cpp`):配置路径 > `DEVELOPER_DIR` > xcode-select(必须是完整 Xcode)> /Applications、~/Applications、Spotlight 里最新的。simctl / xcodebuild 直接执行 `<Developer>/usr/bin/…`,它们按自身位置解析 Xcode,所以**不要**改成 `xcrun`(那会回到 xcode-select)。SimulatorKit 在 Xcode 27 挪到 `Contents/SharedFrameworks`,两处都要找。
746+
- **HID**:CoreSimulator < 1155.4 走 Indigo(`SimDeviceLegacyHIDClient` + `IndigoHIDMessageFor*`;单指触摸要手工重封成 0x140 字节两 payload 消息,第二个 payload 在 0xB0、field1=1/field2=2);≥ 1155.4(Xcode 27)走 dtuhidd 数字化器 XPC(`xpc_endpoint_create_mach_port_4sim`),guest 不再可靠接收 Indigo。手势/按键规划在 daemon(`input_plan.cpp`,纯函数有单测),时序在 helper 里执行。非 ASCII 文本走 `simctl pbcopy` + Cmd+V。
747+
- **坐标 = 界面方向下的 point**:给模型的截图 1 像素 = 1 point 且转正,触摸在 helper 里反旋转。朝向来源:Xcode 27 runtime 用 guest 的 CoreDevice display-info(`com.apple.coredevice.feature.getdisplayinfo`);更老的 runtime 没有这个服务(405),退回 Simulator.app 偏好 `DevicePreferences.<udid>.SimulatorWindowOrientation`。无障碍坐标本来就是界面方向。
748+
- **帧缓冲读取必须同步加锁**:`kIOSurfaceLockAvoidSync` 返回 `kIOReturnCannotLock`,无锁读到的是陈旧 CPU 副本(实测连续帧逐字节相同)。Intel Mac 上同步锁会等模拟器 GPU,动画期间能卡数秒 —— `simctl io screenshot` 同样卡,是平台特性;所以截图/推流在每设备独立队列,和输入互不阻塞;缩放旋转用 vImage(CPU),Core Image / VTPixelTransfer 同样被 GPU 同步拖住。原生零拷贝视图(IOSurface 进 CALayer)是后续项。
749+
- **无障碍**:必须把 bridge token 代理装在 `AXPTranslator.sharedInstance`(装在 `sharediOSInstance` 上元素读属性时收不到回调,只剩根节点);属性用私有 `accessibilityMultipleAttributes:` 批量读(一元素一次往返);开机/启动 App 后头几次 frontmost 请求常为空,重试 3 次。
750+
- **权限**:`ios_simulator` 进 `PermissionManager::should_auto_allow` 免确认名单(同 Agent Browser),但每台模拟器首次使用经 `ctx.ask_user_questions` 征求同意,记在 state.json `ios_simulator.device_consent`,超时/取消/未选一律算拒绝,yolo 隐式授权,设置页可撤销;`ios_simulator_build` 会执行工程脚本,走普通权限确认。plan 模式只允许观察类动作。
751+
- **面板**:`WS /ws/ios-simulator/<udid>` 推 JPEG 二进制帧(带 JSON 头),收触摸/按键/文本;同一设备多个观看者共用一路 helper 流;订阅在后台线程里做,别放回 Crow IO 线程(首次要做 Xcode 发现 + 起 helper)。用户在面板里的操作不需要设备授权(授权约束的是 AI)。
752+
- **验证现状**:本机 Xcode 26.6(绿色安装于 ~/Downloads)+ iOS 26.5 实测通过 describe / 截图(竖横屏)/ 点击 / 滑动 / 键盘 / 无障碍 / 推流;DTUHID 通道待 Xcode 27 机器验证。回归:`tests/tool/ios_simulator/*`、打包脚本测试(`tests/scripts/*` 中的 acecode-ios-sim 断言)。
753+
740754
### Web UI: 控制台停靠区(ConsoleDock)
741755

742756
`add-console-dock`:TopBar `>_` 按钮(icon `terminal` = TerminalReadWrite.svg)或 ``Ctrl+` `` toggle 主内容列底部的终端停靠区(横跨 ChatView+SidePanel,不动 Sidebar/TopBar)。前端 xterm.js(`@xterm/xterm` + `@xterm/addon-fit`,bundle +~190KB gzip);多 tab(+ 新建 / 逐 tab × 杀会话 / 整体收起保活);顶边拖高(`clampDockHeight`,[120, 视口 80%]);偏好 `acecode.consoleDock.v1` `{open, height}`。纯函数层 `web/src/lib/consoleDock.js`(tab 状态机/帧分流/退避/URL,Node 单测)。**xterm 聚焦时 ``Ctrl+` `` 靠 `attachCustomKeyEventHandler` 放行冒泡** — 删掉它快捷键在终端内失灵。

‎CMakeLists.txt‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ if(CMAKE_HOST_WIN32 AND DEFINED CMAKE_TOOLCHAIN_FILE AND CMAKE_TOOLCHAIN_FILE MA
77
set(VCPKG_TARGET_TRIPLET "x64-windows-static" CACHE STRING "Vcpkg target triplet" FORCE)
88
endif()
99

10-
project(acecode VERSION 1.0.7 LANGUAGES C CXX)
10+
project(acecode VERSION 1.0.8 LANGUAGES C CXX)
1111

1212
include(${CMAKE_SOURCE_DIR}/cmake/acecode_source_guards.cmake)
1313

@@ -240,6 +240,20 @@ elseif(APPLE)
240240
install(TARGETS acecode-computer-use RUNTIME DESTINATION . COMPONENT computer_use_runtime)
241241
endif()
242242

243+
if(APPLE)
244+
# iOS Simulator helper. It is a macOS-only payload: other platforms never
245+
# build or package it.
246+
add_executable(acecode-ios-sim ${ACECODE_IOS_SIM_HELPER_SOURCES})
247+
set_target_properties(acecode-ios-sim PROPERTIES OBJCXX_STANDARD 17 OBJCXX_STANDARD_REQUIRED YES)
248+
target_compile_options(acecode-ios-sim PRIVATE -fobjc-arc -mmacosx-version-min=14.0)
249+
target_link_options(acecode-ios-sim PRIVATE -mmacosx-version-min=14.0)
250+
target_include_directories(acecode-ios-sim PRIVATE ${CMAKE_SOURCE_DIR}/src/adapters)
251+
target_link_libraries(acecode-ios-sim PRIVATE nlohmann_json::nlohmann_json
252+
"-framework Foundation" "-framework CoreGraphics" "-framework Accelerate"
253+
"-framework ImageIO" "-framework IOSurface")
254+
install(TARGETS acecode-ios-sim RUNTIME DESTINATION . COMPONENT ios_simulator_runtime)
255+
endif()
256+
243257
add_executable(acecode
244258
${ACECODE_MAIN_SOURCE}
245259
${ACECODE_WINDOWS_RESOURCES}
@@ -248,6 +262,9 @@ target_link_libraries(acecode PRIVATE acecode_cli)
248262
if(WIN32 OR APPLE)
249263
add_dependencies(acecode acecode-computer-use)
250264
endif()
265+
if(APPLE)
266+
add_dependencies(acecode acecode-ios-sim)
267+
endif()
251268

252269
add_custom_command(TARGET acecode POST_BUILD
253270
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:acecode>/channels/whatsapp"

0 commit comments

Comments
 (0)