@mobileaidev/ai-app-bridge 0.4.0 → 0.4.1

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
@@ -7,7 +7,9 @@ discovery. Every request checks the mapping before dispatch. Mutating requests
7
7
  are never replayed after a missing route or uncertain result. For manual cleanup,
8
8
  pass the exact serial and returned Host port to `remove-forward`.
9
9
 
10
- This source version is `0.4.0`; registry publication is a separate release step.
10
+ This source version is `0.4.1`; registry publication is a separate release step.
11
+ It fixes iOS observation ownership and preserves extraction results when
12
+ temporary cleanup fails. Device and Web SDKs share version `0.4.1`; their execution contracts are unchanged.
11
13
  The default installation includes the Script/Intent and capture contracts below.
12
14
  Local package verification does not change npm dist-tags.
13
15
  The supported Node range is `>=26.3.0 <27`; this release was checked on 26.3.0.
@@ -65,7 +67,7 @@ domains, commands, and options, then call `run` with the selected command.
65
67
 
66
68
  ```bash
67
69
  # Install the current stable release; see docs/RELEASE.md for packaging.
68
- npm install -g @mobileaidev/ai-app-bridge@0.4.0
70
+ npm install -g @mobileaidev/ai-app-bridge@0.4.1
69
71
 
70
72
  ai-app-bridge status --extract null --package-name io.github.mobileaidev.aiappbridge.sample
71
73
  ai-app-bridge tree --extract null --package-name io.github.mobileaidev.aiappbridge.sample
@@ -245,6 +245,8 @@ const commandByName = new Map(commandDefinitions.map(d => [d.command, d]));
245
245
  const isolatedByName = new Map(isolatedCommandDefinitions.map(d => [d.command, d]));
246
246
 
247
247
  function isMutationCommand(command, args = {}) {
248
+ // iOS observation controls only a bounded SDK capture lease, not a UI action.
249
+ if (command === 'ios-ui-observation') return false;
248
250
  if (require('./ui-observation').commands.has(command)) return args.operation !== 'status';
249
251
  if (['android-executor', 'flutter-executor'].includes(command)) return ['open', 'act', 'close'].includes(args.operation);
250
252
  if (command === 'web-executor') return ['prepare', 'open', 'act', 'navigate', 'close'].includes(args.operation);
@@ -66,7 +66,7 @@ async function runExtraction(prepared, inputs) {
66
66
  // every descendant to close its copies of stdout/stderr.
67
67
  child?.stdin?.destroy(); child?.stdout?.destroy(); child?.stderr?.destroy();
68
68
  try { if (directory) fs.rmSync(directory, { recursive: true, force: true }); }
69
- catch (error) { result = { ok: false, error: 'extraction_cleanup_failed', message: error.message }; }
69
+ catch (error) { result.cleanupError = error.code || 'extraction_cleanup_failed'; }
70
70
  finally { active--; }
71
71
  }
72
72
  const diagnostics = channel?.diagnostics();
@@ -93,6 +93,12 @@ async function reconcileIOS({ lease, device, args, createPort, readWdaTestSummar
93
93
  } catch (error) { return { settled: false, error: 'ios_wda_startup_completion_unavailable', cause: error.code || 'invalid_result' }; }
94
94
  }
95
95
  if (args.setupResultPath) return { settled: false, error: 'ios_original_completion_identity_required' };
96
+ if (pending.kind === 'ios-command' && pending.command === 'ios-ui-observation') {
97
+ // Older Hosts incorrectly journaled bounded capture control as a device
98
+ // action. Retire only that marker; its observation outcome remains unknown.
99
+ return { kind: 'ios-ui-observation', settled: true, dispatched: null,
100
+ reason: 'observation_control_not_device_mutation', observationOutcome: 'unknown' };
101
+ }
96
102
  if (pending.kind === 'ios-command') {
97
103
  const invocation = pending.invocation;
98
104
  const index = Array.isArray(invocation?.arguments) ? invocation.arguments.indexOf('--json-output') : -1;
@@ -96,7 +96,7 @@ class IOSBridgeProvider {
96
96
  case 'ios-status':
97
97
  return await this.runtimeGet(args, '/v1/status');
98
98
  case 'ios-ui-observation': {
99
- const port = await this.runtimePort(args, context);
99
+ const port = await this.runtimePort(args, { ...context, mutation: false });
100
100
  const result = await port.post(require('./ui-observation').path(args), require('./ui-observation').request(args));
101
101
  return { ...result, endpoint: port.endpoint.baseUrl, device: port.endpoint.device, runtimeBinding: port.endpoint.runtimeBinding };
102
102
  }
@@ -445,7 +445,8 @@ class IOSBridgeProvider {
445
445
 
446
446
  async runtimePort(args, options = {}) {
447
447
  const endpoint = await this.resolveRuntimeEndpoint(args, options);
448
- const httpOptions = { timeoutMs: this.context(args).httpTimeoutMs, headers: bindingHeaders(endpoint.runtimeBinding) };
448
+ const httpOptions = { timeoutMs: this.context(args).httpTimeoutMs, headers: bindingHeaders(endpoint.runtimeBinding),
449
+ ...(options.mutation === false ? { mutation: false } : {}) };
449
450
  const request = async (method, endpointPath, payload) => {
450
451
  let response;
451
452
  try {
@@ -1743,6 +1743,17 @@ tree or publish cached layout as current UI. Query a provider's observation
1743
1743
  command for its live lease state. These endpoints require rebuilt SDKs;
1744
1744
  installing a new CLI cannot patch an installed application's old SDK.
1745
1745
 
1746
+ iOS observation control uses the SDK's bounded capture lease, not physical-device
1747
+ action ownership. A rejected control or lost response cannot block later UI
1748
+ actions, and its HTTP request does not mark an enclosing UI action dispatched.
1749
+ An older Host may have left an `ios-command` / `ios-ui-observation` ownership
1750
+ marker. Explicit `ios-execution --operation reconcile` retires only that marker
1751
+ after checking the recorded device and any supplied bundle identity. Its receipt
1752
+ reports `reason: observation_control_not_device_mutation` and
1753
+ `observationOutcome: unknown`; it does not claim that observation started or
1754
+ stopped successfully. Other unresolved actions still require their original
1755
+ completion proof. Runtime restart alone does not erase the durable journal.
1756
+
1746
1757
  Ordinary CLI/MCP `feedback=full` opens a window before the action and releases
1747
1758
  it in finally. If observation is unavailable, the action is rejected before
1748
1759
  dispatch; acquiring evidence does not mark the enclosing UI action dispatched.
@@ -5,7 +5,8 @@ The same npm package contains CLI and MCP; running only MCP is supported.
5
5
  FactStore is an embedded library bundled in that package. There is no separate
6
6
  database, FactStore service or CLI process to install first.
7
7
 
8
- This source targets 0.4.0. Registry publication is a separate step; before
8
+ This source targets the coordinated 0.4.1 release.
9
+ Registry publication is a separate step; before
9
10
  publication, use the reviewed local tarball instead of expecting this registry
10
11
  version to resolve.
11
12
 
@@ -14,7 +15,7 @@ version to resolve.
14
15
  "mcpServers": {
15
16
  "ai-app-bridge": {
16
17
  "command": "npx",
17
- "args": ["--yes", "--package", "@mobileaidev/ai-app-bridge@0.4.0", "ai-app-bridge-mcp"]
18
+ "args": ["--yes", "--package", "@mobileaidev/ai-app-bridge@0.4.1", "ai-app-bridge-mcp"]
18
19
  }
19
20
  }
20
21
  }
@@ -1,4 +1,4 @@
1
- # Optional UI executors (0.4.0)
1
+ # Optional UI executors (0.4.1)
2
2
 
3
3
  Bridge keeps its existing SDK paths and exposes optional executors through `capabilities`, `run`, and JavaScript/Python Script. Select an executor explicitly. No command silently changes a touch into a setter, switches framework after failure, or repeats an uncertain action.
4
4
 
@@ -52,9 +52,9 @@ android {
52
52
  }
53
53
  }
54
54
  dependencies {
55
- androidTestImplementation("com.github.mobileAiDev.ai-app-bridge:ai-app-bridge-test-instrumentation:0.4.0")
55
+ androidTestImplementation("com.github.mobileAiDev.ai-app-bridge:ai-app-bridge-test-instrumentation:0.4.1")
56
56
  // Optional H5 adapter:
57
- androidTestImplementation("com.github.mobileAiDev.ai-app-bridge:ai-app-bridge-test-espresso-web:0.4.0")
57
+ androidTestImplementation("com.github.mobileAiDev.ai-app-bridge:ai-app-bridge-test-espresso-web:0.4.1")
58
58
  }
59
59
  ```
60
60
 
@@ -109,7 +109,7 @@ Espresso text actions have different semantics. `replaceText` is the framework's
109
109
 
110
110
  ## Flutter
111
111
 
112
- Add `ai_app_bridge_test: 0.4.0` to the application's `dev_dependencies`. The helper takes `flutter_test` and `integration_test` from the **same Flutter SDK** as the application. It is a Dart test helper, not an additional Android plugin with its own AGP/Kotlin versions.
112
+ Add `ai_app_bridge_test: 0.4.1` to the application's `dev_dependencies`. The helper takes `flutter_test` and `integration_test` from the **same Flutter SDK** as the application. It is a Dart test helper, not an additional Android plugin with its own AGP/Kotlin versions.
113
113
 
114
114
  The helper declares Flutter **>=3.41.0** and Dart **>=3.11.0 <4.0.0**. The 0.3.8 automatic preparation was exercised with LocalSend on Flutter **3.41.9 / Android API 36**, preserving all 214 production dependency versions. Earlier executor validation covered Flutter 3.41.9 / API 25 and 3.44.8 / API 36. These are specific verified combinations; other SDK versions still need validation with the application's plugin graph.
115
115
 
package/docs/RELEASE.md CHANGED
@@ -1,9 +1,15 @@
1
- # 0.4.0 改善版发行检查
1
+ # 0.4.1 统一补丁发行检查
2
2
 
3
3
  源码版本、可发布验收、registry 发布和正在运行的客户端是四个不同状态。
4
4
  本文件描述发行操作;源码中的版本号不代表 npm/JitPack/pub.dev 已发布。
5
- 当前实施与放行证据统一记录于仓库 `docs/IMPROVEMENT_RELEASE_V1_2026-09-18.md`
6
- 及各 M1–M5 交付记录。最终 A01–A16 对账未全通过前不宣称完整发布验收。
5
+ 0.4.0 改善版的实施与放行证据记录于仓库
6
+ `docs/IMPROVEMENT_RELEASE_V1_2026-09-18.md` 及各 M1–M5 交付记录。
7
+ 0.4.1 统一发布全部 Bridge 组件,Host 修复与回归证据见
8
+ `docs/HOST_0.4.0_GROK_REVIEW_2026-09-19.md`;设备及 Web SDK 仅同步版本与依赖。
9
+
10
+ 本次修复 iOS 观察控制误占设备动作 ownership,并为旧误记 marker 提供
11
+ 显式 reconcile;提取临时目录清理失败改为 cleanupError,保留原提取结果。
12
+ 超预算 reference 交付和 extract 必填合同不变;设备端执行合同不变。
7
13
 
8
14
  ## 兼容与迁移
9
15
 
@@ -20,12 +26,12 @@ read,不重放动作。详见 [公共提取合同与完整示例](RESPONSE_EXT
20
26
 
21
27
  | 资源 | 源码版本 | 发行渠道 |
22
28
  | --- | --- | --- |
23
- | Desktop CLI/MCP | 0.4.0 | npm @mobileaidev/ai-app-bridge |
29
+ | Desktop CLI/MCP | 0.4.1 | npm @mobileaidev/ai-app-bridge |
24
30
  | 嵌入式 native store | 0.2.0 | 随主包 bundleDependencies,包括四个预编译 addon |
25
- | Android SDK / Gradle plugin / executor modules | 0.4.0 | 同仓库 Git tag / JitPack |
26
- | iOS Swift 包 | Git tag 0.4.0 | 根 Package.swift |
27
- | Flutter SDK / test helper | 0.4.0 | pub.dev;Android 固定依赖同版 SDK |
28
- | Web SDK | 0.4.0 | npm @mobileaidev/ai-app-bridge-web |
31
+ | Android SDK / Gradle plugin / executor modules | 0.4.1 | 同仓库 Git tag / JitPack |
32
+ | iOS Swift 包 | Git tag 0.4.1 | 根 Package.swift |
33
+ | Flutter SDK / test helper | 0.4.1 | pub.dev;Android 固定依赖同版 SDK |
34
+ | Web SDK | 0.4.1 | npm @mobileaidev/ai-app-bridge-web |
29
35
 
30
36
  UIA bundle、WDA 14.1.1、iOS WDA 模板、Playwright helper 与三类范例随主包。
31
37
  未改变代码的设备组件不需要仅为 Host 返回合同重新安装;需要测试新发行
@@ -33,6 +39,10 @@ UIA bundle、WDA 14.1.1、iOS WDA 模板、Playwright helper 与三类范例随
33
39
 
34
40
  ## 发布前门禁
35
41
 
42
+ 本次必须通过新增缺陷回归、Host 完整功能/性能组、真实 iPhone 恢复验证及
43
+ 最终 tarball 安装检查。SDK 同步版本后重新验证构建与公开依赖;未变更的
44
+ 原生 addon 复用 0.4.0 四平台验收,并核实归档字节相同。
45
+
36
46
  1. 固定审核提交,核对工作包和 A01–A16,保留失败与未验证项。完整 npm
37
47
  功能组与安静环境串行性能组通过,范例由文档读取实际执行。
38
48
  2. 对 [Host 支持矩阵](INSTALLATION.md) 的四个 artifact 校验 checksum 和
@@ -49,11 +59,12 @@ UIA bundle、WDA 14.1.1、iOS WDA 模板、Playwright helper 与三类范例随
49
59
 
50
60
  ## 对外发布顺序
51
61
 
52
- 在已授权的发布操作中,维护者先推送已验收提交和 0.4.0 tag,核实 JitPack
53
- 公开坐标成功解析,再发布依赖它们的 Flutter SDK/helper。Web npm 与主
54
- CLI/MCP npm 分别发布,并核实 registry 实际返回的 tarball/checksum;设置
55
- 对应 dist-tag 和 GitHub Release。远端流水线成功与设备业务验收分别列明。
56
- 本地构建或 MavenLocal/path 替换不能证明公开坐标可安装。
62
+ 本次推送已验收提交与统一 `0.4.1` tag,核实 JitPack 公开坐标成功解析,
63
+ 再发布依赖它们的 Flutter SDK/helper。Web npm 与主 CLI/MCP npm 分别发布
64
+ 已经验证的 tarball,核实 `latest`/`next` 均为 0.4.1、公开下载 checksum
65
+ 与候选包一致,并创建对应 GitHub Release。保留旧 `0.4.0` tag 不动。远端流水线
66
+ 成功与设备业务验收分别列明。本地构建或 MavenLocal/path 替换不能证明公开
67
+ 坐标可安装。
57
68
 
58
69
  客户端升级时退出旧 MCP 再重新连接。若是旧客户端碰到新 Runtime,先升
59
70
  客户端;只有明确 Runtime 是待升级一侧时,在其任务结束后显式 stop。
@@ -70,6 +70,10 @@ requested delivery, 1 for validation/failed or unknown execution, and 2 when a
70
70
  known successful command could not be extracted/delivered. MCP uses `isError`
71
71
  consistently. A successful Script execution is separate from its business verdict.
72
72
 
73
+ A temporary-directory removal failure after the worker exits is reported as
74
+ `extraction.cleanupError`. It does not replace a successful value or the original
75
+ extraction error, change the exit code, or replay the command.
76
+
73
77
  Preserve source identity, timestamps, state and coverage needed by the actual
74
78
  assertion. A selected successful row does not prove complete business coverage.
75
79
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mobileaidev/ai-app-bridge",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Desktop CLI and MCP server for AI App Bridge across Android, iOS, Flutter, WebView, and Web targets.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "ai-app-bridge-playwright-runtime",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "ai-app-bridge-playwright-runtime",
9
- "version": "0.4.0",
9
+ "version": "0.4.1",
10
10
  "dependencies": {
11
11
  "playwright": "1.63.0"
12
12
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-app-bridge-playwright-runtime",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "private": true,
5
5
  "description": "Optional, isolated browser runtime managed by AI App Bridge.",
6
6
  "engines": { "node": ">=26.3.0 <27" },