@mobileaidev/ai-app-bridge 0.2.15 → 0.3.0-rc.2

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.
Files changed (156) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +7 -0
  3. package/README.md +306 -53
  4. package/bin/ai-app-bridge.js +51 -4504
  5. package/bin/android-permissions.js +152 -0
  6. package/bin/android-uia-xml.js +74 -0
  7. package/bin/artifact-paths.js +127 -1
  8. package/bin/bridge-forward.js +56 -0
  9. package/bin/command-discovery.js +86 -0
  10. package/bin/command-errors.js +60 -0
  11. package/bin/command-registry.js +504 -0
  12. package/bin/command-request.js +14 -0
  13. package/bin/command-router.js +80 -0
  14. package/bin/connection-cache.js +119 -0
  15. package/bin/device-provider.js +2934 -0
  16. package/bin/execution-host.js +596 -0
  17. package/bin/execution-runtime.js +101 -0
  18. package/bin/fact-codec.js +321 -0
  19. package/bin/fact-recorder.js +691 -0
  20. package/bin/fact-store.js +226 -0
  21. package/bin/feedback-probe.js +285 -0
  22. package/bin/intent/install-intent.js +267 -0
  23. package/bin/intent/intent-action-executor.js +129 -0
  24. package/bin/intent/intent-autonomous-adapter.js +46 -0
  25. package/bin/intent/intent-capture-port.js +64 -0
  26. package/bin/intent/intent-entry.js +226 -0
  27. package/bin/intent/intent-errors.js +28 -0
  28. package/bin/intent/intent-evidence-store.js +121 -0
  29. package/bin/intent/intent-lifetime.js +62 -0
  30. package/bin/intent/intent-observation-target.js +33 -0
  31. package/bin/intent/intent-observer.js +194 -0
  32. package/bin/intent/intent-production-adapter.js +334 -0
  33. package/bin/intent/intent-provider.js +27 -0
  34. package/bin/intent/intent-runtime.js +63 -0
  35. package/bin/intent/intent-worker.js +432 -0
  36. package/bin/intent/ios-intent-adapter.js +90 -0
  37. package/bin/intent/permission-intent.js +239 -0
  38. package/bin/intent/web-intent-adapter.js +31 -0
  39. package/bin/ios-device-outcome.js +47 -0
  40. package/bin/ios-execution.js +108 -0
  41. package/bin/ios-provider.js +497 -583
  42. package/bin/ios-runtime-binding.js +54 -0
  43. package/bin/ios-wda-execution.js +70 -0
  44. package/bin/ios-wda-port.js +98 -0
  45. package/bin/ios-wda-project.js +79 -0
  46. package/bin/mcp-server.js +83 -1040
  47. package/bin/mmap-scan-index.js +329 -0
  48. package/bin/observation-collector.js +862 -0
  49. package/bin/runtime-client.js +154 -0
  50. package/bin/runtime-directory.js +107 -0
  51. package/bin/runtime-protocol.js +36 -0
  52. package/bin/script/bounded-script-registry.js +103 -0
  53. package/bin/script/node-runtime-adapter.js +233 -0
  54. package/bin/script/progress-projector.js +63 -0
  55. package/bin/script/python-runtime-adapter.js +111 -0
  56. package/bin/script/rolling-summary.js +134 -0
  57. package/bin/script/script-agent-port.js +40 -0
  58. package/bin/script/script-assert.js +95 -0
  59. package/bin/script/script-capture-port.js +76 -0
  60. package/bin/script/script-catalog.js +85 -0
  61. package/bin/script/script-durable-restore.js +195 -0
  62. package/bin/script/script-entry-code.js +26 -0
  63. package/bin/script/script-entry-route.js +38 -0
  64. package/bin/script/script-entry.js +3 -0
  65. package/bin/script/script-errors.js +29 -0
  66. package/bin/script/script-evidence-store.js +22 -0
  67. package/bin/script/script-format-removed.js +26 -0
  68. package/bin/script/script-host-port.js +397 -0
  69. package/bin/script/script-ledger.js +64 -0
  70. package/bin/script/script-result.js +57 -0
  71. package/bin/script/script-sdk.js +152 -0
  72. package/bin/script/script-sdk.py +153 -0
  73. package/bin/script/script-session-channel.js +127 -0
  74. package/bin/script/script-spec.js +86 -0
  75. package/bin/script/script-supervisor.js +919 -0
  76. package/bin/script/templates/checkpoint-reentry.js +13 -0
  77. package/bin/segment-index.js +481 -0
  78. package/bin/segmented-fact-store.js +1571 -0
  79. package/bin/shared-kernel/android-h5-target.js +10 -0
  80. package/bin/shared-kernel/android-install-execution.js +176 -0
  81. package/bin/shared-kernel/android-sdk-endpoint.js +42 -0
  82. package/bin/shared-kernel/android-shell-execution.js +195 -0
  83. package/bin/shared-kernel/argument-schema.js +117 -0
  84. package/bin/shared-kernel/canonical-path.js +17 -0
  85. package/bin/shared-kernel/device-acknowledgements.js +53 -0
  86. package/bin/shared-kernel/device-completion-history.js +52 -0
  87. package/bin/shared-kernel/device-mutation-lease.js +219 -0
  88. package/bin/shared-kernel/device-ownership-recovery.js +95 -0
  89. package/bin/shared-kernel/device-ownership-store.js +94 -0
  90. package/bin/shared-kernel/evidence-adapters.js +251 -0
  91. package/bin/shared-kernel/evidence-archive.js +329 -0
  92. package/bin/shared-kernel/evidence-recording.js +131 -0
  93. package/bin/shared-kernel/evidence-schema.js +194 -0
  94. package/bin/shared-kernel/evidence-store.js +190 -0
  95. package/bin/shared-kernel/execution-admission.js +22 -0
  96. package/bin/shared-kernel/execution-contracts.js +171 -0
  97. package/bin/shared-kernel/execution-io.js +106 -0
  98. package/bin/shared-kernel/execution-ledger.js +125 -0
  99. package/bin/shared-kernel/execution-scope.js +87 -0
  100. package/bin/shared-kernel/execution-target.js +115 -0
  101. package/bin/shared-kernel/flutter-execution.js +13 -0
  102. package/bin/shared-kernel/flutter-h5-port.js +60 -0
  103. package/bin/shared-kernel/flutter-h5-target.js +9 -0
  104. package/bin/shared-kernel/flutter-target.js +75 -0
  105. package/bin/shared-kernel/h5-execution.js +11 -0
  106. package/bin/shared-kernel/h5-target.js +31 -0
  107. package/bin/shared-kernel/host-fact-store.js +49 -0
  108. package/bin/shared-kernel/ios-h5-target.js +9 -0
  109. package/bin/shared-kernel/ios-native-target.js +71 -0
  110. package/bin/shared-kernel/live-capture-query.js +115 -0
  111. package/bin/shared-kernel/managed-sdk-execution.js +78 -0
  112. package/bin/shared-kernel/native-execution.js +13 -0
  113. package/bin/shared-kernel/native-target.js +156 -0
  114. package/bin/shared-kernel/provider-command-contracts.js +55 -0
  115. package/bin/shared-kernel/recorded-payload-archive.js +195 -0
  116. package/bin/shared-kernel/request-context.js +35 -0
  117. package/bin/shared-kernel/semantic-node.js +55 -0
  118. package/bin/shared-kernel/summary-transformer.js +352 -0
  119. package/bin/shared-kernel/target-lease-protocol.js +47 -0
  120. package/bin/shared-kernel/text-wait.js +111 -0
  121. package/bin/shared-kernel/uia-execution.js +96 -0
  122. package/bin/shared-kernel/uia-protocol.js +214 -0
  123. package/bin/shared-kernel/uia-runtime-port.js +377 -0
  124. package/bin/shared-kernel/uia-target.js +39 -0
  125. package/bin/shared-kernel/web-dom-target.js +44 -0
  126. package/bin/shared-kernel/xml-attributes.js +25 -0
  127. package/bin/target-execution.js +275 -0
  128. package/bin/web/command-schema.js +60 -0
  129. package/bin/web/session-store.js +157 -0
  130. package/bin/web-provider.js +334 -553
  131. package/docs/COMMAND_CONTRACT.md +1563 -0
  132. package/docs/EVIDENCE_ARCHIVE.md +214 -0
  133. package/docs/INTENT_FOREGROUND.md +71 -0
  134. package/docs/INTENT_NATIVE_EDITING.md +79 -0
  135. package/docs/RELEASE.md +59 -0
  136. package/docs/SCRIPT_AUTHORING.md +489 -0
  137. package/node_modules/@mobileaidev/segmented-fact-store-native/LICENSE +201 -0
  138. package/node_modules/@mobileaidev/segmented-fact-store-native/NOTICE +7 -0
  139. package/node_modules/@mobileaidev/segmented-fact-store-native/binding.gyp +36 -0
  140. package/node_modules/@mobileaidev/segmented-fact-store-native/bindings/node/sfs_node.c +597 -0
  141. package/node_modules/@mobileaidev/segmented-fact-store-native/include/sfs.h +178 -0
  142. package/node_modules/@mobileaidev/segmented-fact-store-native/index.js +5 -0
  143. package/node_modules/@mobileaidev/segmented-fact-store-native/package.json +24 -0
  144. package/node_modules/@mobileaidev/segmented-fact-store-native/src/sfs.c +2349 -0
  145. package/package.json +60 -5
  146. package/runtime/ios-wda/AABWDABinding.h +19 -0
  147. package/runtime/ios-wda/AABWDABinding.m +97 -0
  148. package/runtime/ios-wda/AABWDAExecution.h +26 -0
  149. package/runtime/ios-wda/AABWDAExecution.m +172 -0
  150. package/runtime/ios-wda/AABWDAIntegration.h +71 -0
  151. package/runtime/ios-wda/AABWDAManagedRoutes.h +392 -0
  152. package/runtime/ios-wda/AABWDAReceiptStore.h +10 -0
  153. package/runtime/ios-wda/AABWDAReceiptStore.m +116 -0
  154. package/runtime/uia/ai-app-bridge-uia.jar +0 -0
  155. package/runtime/uia/manifest.json +22 -0
  156. package/skills/ai-app-bridge-use/SKILL.md +23 -360
@@ -0,0 +1,153 @@
1
+ import asyncio
2
+ import json
3
+ import sys
4
+
5
+
6
+ _real_stdout = sys.stdout
7
+ HELD = {
8
+ "pause_requested",
9
+ "paused_manual",
10
+ "paused_live",
11
+ "paused_ambiguous",
12
+ }
13
+
14
+
15
+ def send(message):
16
+ # Match the Host UTF-8 JSON byte budget; ASCII escaping can triple it.
17
+ frame = json.dumps(message, ensure_ascii=False, separators=(",", ":")) + "\n"
18
+ _real_stdout.buffer.write(frame.encode("utf-8", errors="backslashreplace"))
19
+ _real_stdout.buffer.flush()
20
+
21
+
22
+ def read_message():
23
+ line = sys.stdin.readline()
24
+ if not line:
25
+ return None
26
+ return json.loads(line)
27
+
28
+
29
+ class HostContext:
30
+ def __init__(self, inputs, control):
31
+ self.inputs = inputs
32
+ self._control = control
33
+ self._next_id = 0
34
+
35
+ def _id(self, prefix):
36
+ self._next_id += 1
37
+ return f"{prefix}{self._next_id}"
38
+
39
+ def _apply_control(self, payload):
40
+ if payload:
41
+ self._control = payload
42
+
43
+ def _hold_if_paused(self):
44
+ while self._control.get("status") in HELD:
45
+ message = read_message()
46
+ if message is None:
47
+ raise RuntimeError("channel_closed")
48
+ if message.get("type") == "control":
49
+ self._apply_control(message.get("control"))
50
+ continue
51
+ raise RuntimeError("unexpected_frame")
52
+
53
+ def _read_reply(self, message_id):
54
+ while True:
55
+ reply = read_message()
56
+ if reply is None:
57
+ raise RuntimeError("channel_closed")
58
+ if reply.get("type") == "control":
59
+ self._apply_control(reply.get("control"))
60
+ continue
61
+ if reply.get("id") == message_id:
62
+ self._apply_control(reply.get("control"))
63
+ return reply
64
+ raise RuntimeError("unexpected_frame")
65
+
66
+ def _sync_control(self):
67
+ message_id = self._id("s")
68
+ send({"type": "control-point", "id": message_id})
69
+ self._read_reply(message_id)
70
+
71
+ def _safe_point(self):
72
+ self._sync_control()
73
+ self._hold_if_paused()
74
+
75
+ def call(self, command, args=None, options=None):
76
+ self._safe_point()
77
+ message_id = self._id("c")
78
+ send({"type": "call", "id": message_id, "command": command, "args": args or {}, "options": options or {}})
79
+ reply = self._read_reply(message_id)
80
+ self._safe_point()
81
+ return reply["value"]
82
+
83
+ def assert_(self, assertion):
84
+ self._safe_point()
85
+ message_id = self._id("a")
86
+ send({"type": "assert", "id": message_id, "assertion": assertion})
87
+ reply = self._read_reply(message_id)
88
+ self._safe_point()
89
+ return reply["value"]
90
+
91
+ def progress(self, event):
92
+ self._safe_point()
93
+ send({"type": "progress", "event": event})
94
+ self._safe_point()
95
+
96
+ def checkpoint(self, name, state):
97
+ self._safe_point()
98
+ message_id = self._id("k")
99
+ send({"type": "checkpoint", "id": message_id, "name": name, "state": state})
100
+ reply = self._read_reply(message_id)
101
+ self._safe_point()
102
+ return reply["value"]
103
+
104
+ def askAgent(self, request):
105
+ self._safe_point()
106
+ message_id = self._id("q")
107
+ send({"type": "ask", "id": message_id, "request": request})
108
+ reply = self._read_reply(message_id)
109
+ self._safe_point()
110
+ return reply["value"]
111
+
112
+ def controlPoint(self):
113
+ self._sync_control()
114
+ return self._control
115
+
116
+ def resume(self):
117
+ checkpoint = self._control.get("checkpoint")
118
+ if not checkpoint:
119
+ return None
120
+ return checkpoint["state"]
121
+
122
+
123
+ def load_namespace(path):
124
+ namespace = {}
125
+ with open(path, "r", encoding="utf-8") as handle:
126
+ exec(handle.read(), namespace, namespace)
127
+ return namespace
128
+
129
+
130
+ def main():
131
+ artifact_path = sys.argv[1]
132
+ send({"type": "ready"})
133
+ start = read_message()
134
+ sys.stdout = sys.stderr
135
+ ctx = HostContext(start.get("inputs") or {}, start.get("control") or {"status": "running", "pauseReason": None})
136
+ entry = start.get("entrypoint") or "main"
137
+ try:
138
+ namespace = load_namespace(artifact_path)
139
+ loaded = namespace.get(entry)
140
+ if not callable(loaded):
141
+ send({"type": "fail", "error": "unsupported_entrypoint"})
142
+ sys.exit(1)
143
+ result = loaded(ctx)
144
+ if asyncio.iscoroutine(result):
145
+ result = asyncio.run(result)
146
+ send({"type": "return", "result": result})
147
+ except Exception as error:
148
+ send({"type": "fail", "error": str(error)})
149
+ sys.exit(1)
150
+
151
+
152
+ if __name__ == "__main__":
153
+ main()
@@ -0,0 +1,127 @@
1
+ 'use strict';
2
+
3
+ const MAX_FRAME_BYTES = 1024 * 1024;
4
+
5
+ function createScriptSessionChannel(child, { maxFrameBytes = MAX_FRAME_BYTES } = {}) {
6
+ let buffer = '';
7
+ let closed = false;
8
+ let failure = null;
9
+ let killTimer;
10
+ child.once('exit', () => clearTimeout(killTimer));
11
+ const waiters = [];
12
+ const pending = [];
13
+ const replies = new Map();
14
+ const maxPending = 32;
15
+
16
+ if (child.stderr) {
17
+ child.stderr.on('data', () => {});
18
+ }
19
+ child.stdout.setEncoding('utf8');
20
+ child.stdout.on('data', (chunk) => {
21
+ if (closed) return;
22
+ buffer += chunk;
23
+ let index = buffer.indexOf('\n');
24
+ while (index >= 0) {
25
+ const line = buffer.slice(0, index);
26
+ buffer = buffer.slice(index + 1);
27
+ index = buffer.indexOf('\n');
28
+ if (Buffer.byteLength(line, 'utf8') > maxFrameBytes) {
29
+ fail(new Error('frame_too_large'));
30
+ return;
31
+ }
32
+ if (!line) continue;
33
+ let message;
34
+ try {
35
+ message = JSON.parse(line);
36
+ } catch {
37
+ fail(new Error('malformed_frame'));
38
+ return;
39
+ }
40
+ if (message == null || typeof message !== 'object' || Array.isArray(message)) {
41
+ fail(new Error('malformed_frame'));
42
+ return;
43
+ }
44
+ if (message.id && replies.has(message.id)) {
45
+ const resolve = replies.get(message.id);
46
+ replies.delete(message.id);
47
+ resolve(message);
48
+ continue;
49
+ }
50
+ if (waiters.length > 0) {
51
+ waiters.shift()(message);
52
+ continue;
53
+ }
54
+ if (pending.length >= maxPending) {
55
+ fail(new Error('channel_backlog'));
56
+ return;
57
+ }
58
+ pending.push(message);
59
+ }
60
+ if (Buffer.byteLength(buffer, 'utf8') > maxFrameBytes) {
61
+ fail(new Error('frame_too_large'));
62
+ }
63
+ });
64
+ child.stdout.on('end', () => fail(new Error('channel_closed')));
65
+ child.on('error', (error) => fail(error));
66
+
67
+ function send(message) {
68
+ if (closed || !child.stdin.writable) return;
69
+ const line = `${JSON.stringify(message)}\n`;
70
+ if (Buffer.byteLength(line, 'utf8') > maxFrameBytes) {
71
+ fail(new Error('frame_too_large'));
72
+ return;
73
+ }
74
+ child.stdin.write(line);
75
+ }
76
+
77
+ function nextMessage() {
78
+ return new Promise((resolve) => {
79
+ if (closed) {
80
+ resolve(failure);
81
+ return;
82
+ }
83
+ if (pending.length > 0) {
84
+ resolve(pending.shift());
85
+ return;
86
+ }
87
+ waiters.push(resolve);
88
+ });
89
+ }
90
+
91
+ function waitReply(id) {
92
+ return new Promise((resolve) => {
93
+ if (closed) {
94
+ resolve(failure);
95
+ return;
96
+ }
97
+ if (replies.size >= maxPending) {
98
+ fail(new Error('channel_backlog'));
99
+ resolve({ type: 'fail', error: 'channel_backlog' });
100
+ return;
101
+ }
102
+ replies.set(id, resolve);
103
+ });
104
+ }
105
+
106
+ function fail(error) {
107
+ if (closed) return;
108
+ closed = true;
109
+ const frame = { type: 'fail', error: error.message || String(error) };
110
+ failure = frame;
111
+ pending.length = 0;
112
+ buffer = '';
113
+ while (waiters.length > 0) waiters.shift()(frame);
114
+ for (const resolve of replies.values()) resolve(frame);
115
+ replies.clear();
116
+ }
117
+
118
+ function stop() {
119
+ fail(new Error('stopped'));
120
+ if (!child.pid) return;
121
+ if (child.kill('SIGTERM') && !killTimer) killTimer = setTimeout(() => child.kill('SIGKILL'), 250);
122
+ }
123
+
124
+ return { send, nextMessage, waitReply, stop };
125
+ }
126
+
127
+ module.exports = { createScriptSessionChannel };
@@ -0,0 +1,86 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const { requestDirectory, resolveRequestPath } = require('../shared-kernel/request-context');
5
+ const { checksumOf } = require('../shared-kernel/evidence-schema');
6
+ const { scriptError } = require('./script-errors');
7
+ const { DEFAULT_PERMISSIONS } = require('./script-catalog');
8
+ const { scriptPermissions } = require('../command-registry');
9
+ const { validateValue } = require('../shared-kernel/argument-schema');
10
+ const { scriptSpecSchema } = require('../shared-kernel/execution-contracts');
11
+ const { CommandError } = require('../command-errors');
12
+ const { normalizeExecutionTarget } = require('../shared-kernel/execution-target');
13
+
14
+ const SCHEMA = 'aab.code-script/v1';
15
+ const SCRIPT_SDK_VERSION = 'aab.script-sdk/v1';
16
+
17
+ function isCodeScript(input) {
18
+ return Boolean(input && typeof input === 'object' && input.schemaVersion === SCHEMA);
19
+ }
20
+
21
+ function compileScriptSpec(input = {}) {
22
+ if (!isCodeScript(input)) return scriptError('invalid_script', { field: 'schemaVersion' });
23
+ try { validateValue(input, scriptSpecSchema(Object.keys(scriptPermissions))); }
24
+ catch (error) {
25
+ if (!(error instanceof CommandError)) throw error;
26
+ return scriptError(error.code, { field: error.field, message: error.message,
27
+ ...(error.details ? { details: error.details } : {}), dispatched: false, ambiguous: false });
28
+ }
29
+ let target;
30
+ try { target = normalizeExecutionTarget(input.target ?? null, { nullable: true }); }
31
+ catch (error) { return scriptError(error.code, { field: error.field, message: error.message, dispatched: false, ambiguous: false }); }
32
+ const language = input.language;
33
+ const hasPath = Object.hasOwn(input, 'sourcePath');
34
+ let source = input.source;
35
+ if (hasPath) {
36
+ try {
37
+ source = fs.readFileSync(input.sourcePath, 'utf8');
38
+ } catch (error) {
39
+ return scriptError('source_read_failed', { field: 'sourcePath', message: error.message });
40
+ }
41
+ if (!source) return scriptError('invalid_script', { field: 'sourcePath' });
42
+ }
43
+ const spec = {
44
+ schemaVersion: SCHEMA,
45
+ name: input.name ?? 'script',
46
+ language,
47
+ cwd: resolveRequestPath(input.cwd ?? requestDirectory()),
48
+ source,
49
+ sourcePath: hasPath ? input.sourcePath : null,
50
+ entrypoint: input.entrypoint ?? 'main',
51
+ target,
52
+ inputs: structuredClone(input.inputs ?? {}),
53
+ permissions: [...(input.permissions ?? DEFAULT_PERMISSIONS)],
54
+ policy: {
55
+ timeoutMs: input.policy?.timeoutMs ?? 600_000,
56
+ restartPolicy: input.policy?.restartPolicy ?? 'none',
57
+ maxOutputBytes: input.policy?.maxOutputBytes ?? 1_048_576,
58
+ maxProgressBytes: input.policy?.maxProgressBytes ?? 1_048_576,
59
+ },
60
+ };
61
+ if (Buffer.byteLength(JSON.stringify(spec.inputs), 'utf8') > spec.policy.maxOutputBytes) {
62
+ return scriptError('invalid_script', { field: 'inputs' });
63
+ }
64
+ return {
65
+ ok: true,
66
+ spec,
67
+ hash: scriptHash(spec),
68
+ };
69
+ }
70
+
71
+ function scriptHash(spec) {
72
+ return checksumOf({
73
+ source: spec.source,
74
+ sourcePath: spec.sourcePath,
75
+ cwd: spec.cwd,
76
+ inputs: spec.inputs,
77
+ policy: spec.policy,
78
+ language: spec.language,
79
+ entrypoint: spec.entrypoint,
80
+ sdkVersion: SCRIPT_SDK_VERSION,
81
+ target: spec.target,
82
+ permissions: spec.permissions,
83
+ });
84
+ }
85
+
86
+ module.exports = { SCHEMA, SCRIPT_SDK_VERSION, isCodeScript, compileScriptSpec, scriptHash };