@mobileai/react-native 0.9.4 → 0.9.9

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 (69) hide show
  1. package/README.md +73 -131
  2. package/ios/MobileAIPilotIntents.swift +51 -0
  3. package/lib/module/__cli_tmp__.js +21 -0
  4. package/lib/module/__cli_tmp__.js.map +1 -0
  5. package/lib/module/components/AIAgent.js.map +1 -1
  6. package/lib/module/components/AgentChatBar.js +2 -3
  7. package/lib/module/components/AgentChatBar.js.map +1 -1
  8. package/lib/module/components/HighlightOverlay.js +1 -0
  9. package/lib/module/components/HighlightOverlay.js.map +1 -1
  10. package/lib/module/core/ActionRegistry.js +102 -0
  11. package/lib/module/core/ActionRegistry.js.map +1 -0
  12. package/lib/module/core/AgentRuntime.js +25 -22
  13. package/lib/module/core/AgentRuntime.js.map +1 -1
  14. package/lib/module/core/MCPBridge.js +77 -14
  15. package/lib/module/core/MCPBridge.js.map +1 -1
  16. package/lib/module/hooks/useAction.js +47 -11
  17. package/lib/module/hooks/useAction.js.map +1 -1
  18. package/lib/module/index.js +3 -10
  19. package/lib/module/index.js.map +1 -1
  20. package/lib/module/plugin/withAppIntents.js +71 -0
  21. package/lib/module/plugin/withAppIntents.js.map +1 -0
  22. package/lib/module/services/AudioInputService.js +2 -2
  23. package/lib/module/services/AudioInputService.js.map +1 -1
  24. package/lib/module/services/AudioOutputService.js +3 -2
  25. package/lib/module/services/AudioOutputService.js.map +1 -1
  26. package/lib/module/tools/guideTool.js +11 -2
  27. package/lib/module/tools/guideTool.js.map +1 -1
  28. package/lib/module/tools/typeTool.js +53 -63
  29. package/lib/module/tools/typeTool.js.map +1 -1
  30. package/lib/typescript/src/__cli_tmp__.d.ts +2 -0
  31. package/lib/typescript/src/__cli_tmp__.d.ts.map +1 -0
  32. package/lib/typescript/src/components/AIAgent.d.ts +0 -3
  33. package/lib/typescript/src/components/AIAgent.d.ts.map +1 -1
  34. package/lib/typescript/src/components/AgentChatBar.d.ts.map +1 -1
  35. package/lib/typescript/src/core/ActionRegistry.d.ts +43 -0
  36. package/lib/typescript/src/core/ActionRegistry.d.ts.map +1 -0
  37. package/lib/typescript/src/core/AgentRuntime.d.ts +2 -4
  38. package/lib/typescript/src/core/AgentRuntime.d.ts.map +1 -1
  39. package/lib/typescript/src/core/MCPBridge.d.ts.map +1 -1
  40. package/lib/typescript/src/core/types.d.ts +20 -2
  41. package/lib/typescript/src/core/types.d.ts.map +1 -1
  42. package/lib/typescript/src/hooks/useAction.d.ts +34 -2
  43. package/lib/typescript/src/hooks/useAction.d.ts.map +1 -1
  44. package/lib/typescript/src/index.d.ts +3 -1
  45. package/lib/typescript/src/index.d.ts.map +1 -1
  46. package/lib/typescript/src/plugin/withAppIntents.d.ts +10 -0
  47. package/lib/typescript/src/plugin/withAppIntents.d.ts.map +1 -0
  48. package/lib/typescript/src/services/AudioOutputService.d.ts.map +1 -1
  49. package/lib/typescript/src/tools/guideTool.d.ts.map +1 -1
  50. package/lib/typescript/src/tools/typeTool.d.ts +9 -18
  51. package/lib/typescript/src/tools/typeTool.d.ts.map +1 -1
  52. package/package.json +4 -1
  53. package/src/__cli_tmp__.tsx +9 -0
  54. package/src/cli/generate-intents.ts +140 -0
  55. package/src/cli/generate-swift.ts +116 -0
  56. package/src/components/AIAgent.tsx +1 -4
  57. package/src/components/AgentChatBar.tsx +2 -3
  58. package/src/components/HighlightOverlay.tsx +1 -1
  59. package/src/core/ActionRegistry.ts +105 -0
  60. package/src/core/AgentRuntime.ts +23 -25
  61. package/src/core/MCPBridge.ts +68 -15
  62. package/src/core/types.ts +23 -2
  63. package/src/hooks/useAction.ts +51 -10
  64. package/src/index.ts +7 -9
  65. package/src/plugin/withAppIntents.ts +82 -0
  66. package/src/services/AudioInputService.ts +2 -2
  67. package/src/services/AudioOutputService.ts +3 -2
  68. package/src/tools/guideTool.ts +11 -2
  69. package/src/tools/typeTool.ts +55 -67
@@ -1,60 +1,33 @@
1
1
  /**
2
2
  * Type Tool — Reliable multi-strategy text input.
3
3
  *
4
- * Strategy chain (tried in order, first success wins):
4
+ * For uncontrolled TextInputs (defaultValue, no onChangeText):
5
+ * 1. Walk fiber subtree (BFS) to find the native host view whose
6
+ * memoizedProps has `onChange` — this is RN's internal `_onChange`.
7
+ * 2. ALSO walk to find the native stateNode with `setNativeProps` to
8
+ * update the VISUAL text in the native view.
5
9
  *
6
- * 1. onChangeText developer's controlled component wired React state.
7
- * calls element.props.onChangeText(text) directly.
10
+ * Both steps are needed:
11
+ * - `onChange` updates React's internal lastNativeText state
12
+ * - `setNativeProps` → updates what the user sees on screen
8
13
  *
9
- * 2. Fiber subtree walk for uncontrolled TextInputs (defaultValue only).
10
- * React Native's TextInput.js always creates an internal `_onChange` handler
11
- * and passes it as `onChange` to the native host view (RCTTextInputView /
12
- * AndroidTextInput). That `_onChange` internally calls `props.onChangeText`
13
- * and updates native text state.
14
- *
15
- * We walk the fiber subtree (behavior-based, no tag numbers) to find any
16
- * descendant node whose memoizedProps.onChange is a function. Then we call
17
- * it with a synthetic TextInputChangeEvent. This triggers RN's internal
18
- * `_onChange` which calls `setLastNativeText` and updates the native view.
19
- *
20
- * Why this is robust:
21
- * - No hardcoded fiber tag numbers (host component tags can change across versions)
22
- * - No dependency on setNativeProps (deprecated in New Architecture / Fabric)
23
- * - Uses the same code path as a real user typing — RN's own _onChange handler
14
+ * No hardcoded fiber tag numbers. Detection is purely behavior-based.
24
15
  */
25
16
 
26
17
  import { walkFiberTree } from '../core/FiberTreeWalker';
27
18
  import type { AgentTool, ToolContext } from './types';
28
19
 
29
- /**
30
- * Walk a fiber subtree to find the first descendant whose memoizedProps
31
- * has an `onChange` function. This is behavior-based — we don't check
32
- * fiber tags, component names, or any React internal that could change.
33
- * We just look for the prop that RN's TextInput always wires.
34
- */
35
- function findNativeOnChange(fiber: any, maxDepth = 8): ((event: any) => void) | null {
36
- if (!fiber) return null;
37
-
38
- let current: any = fiber.child;
39
-
40
- // BFS-style walk through the fiber children
41
- const queue: { node: any; depth: number }[] = [];
42
- if (current) queue.push({ node: current, depth: 0 });
43
-
20
+ /** BFS through fiber children. Returns first node where predicate matches. */
21
+ function findFiberNode(rootFiber: any, predicate: (node: any) => boolean, maxDepth = 10): any | null {
22
+ if (!rootFiber?.child) return null;
23
+ const queue: { node: any; depth: number }[] = [{ node: rootFiber.child, depth: 0 }];
44
24
  while (queue.length > 0) {
45
- const { node, depth: d } = queue.shift()!;
46
- if (d > maxDepth) continue;
47
-
48
- const props = node.memoizedProps;
49
- if (props && typeof props.onChange === 'function') {
50
- return props.onChange;
51
- }
52
-
53
- // Add child and sibling
54
- if (node.child) queue.push({ node: node.child, depth: d + 1 });
55
- if (node.sibling) queue.push({ node: node.sibling, depth: d + 1 });
25
+ const { node, depth } = queue.shift()!;
26
+ if (!node || depth > maxDepth) continue;
27
+ if (predicate(node)) return node;
28
+ if (node.child) queue.push({ node: node.child, depth: depth + 1 });
29
+ if (node.sibling) queue.push({ node: node.sibling, depth: depth + 1 });
56
30
  }
57
-
58
31
  return null;
59
32
  }
60
33
 
@@ -76,9 +49,9 @@ export function createTypeTool(context: ToolContext): AgentTool {
76
49
 
77
50
  const props = element.props;
78
51
  const label = element.label || `[${element.type}]`;
52
+ const fiberNode = element.fiberNode;
79
53
 
80
54
  // ── Strategy 1: controlled via onChangeText ───────────────────────────
81
- // App developer wired onChangeText={setText} — most reliable.
82
55
  if (typeof props.onChangeText === 'function') {
83
56
  try {
84
57
  props.onChangeText(args.text);
@@ -89,37 +62,52 @@ export function createTypeTool(context: ToolContext): AgentTool {
89
62
  }
90
63
  }
91
64
 
92
- // ── Strategy 2: fiber subtree walk for native onChange ─────────────────
93
- // For uncontrolled TextInputs (defaultValue only, no onChangeText).
94
- // RN's TextInput.js creates _onChange internally and passes it as
95
- // onChange to the native host view. We find that handler and call it
96
- // with a synthetic TextInputChangeEvent.
97
- const fiberNode = element.fiberNode;
65
+ // ── Strategy 2: uncontrolled find native onChange + setNativeProps ──
66
+ // For TextInputs with defaultValue only.
67
+ // We need BOTH:
68
+ // a) find the onChange handler (RN's internal _onChange) to update React state
69
+ // b) find the native stateNode to call setNativeProps to update visual display
98
70
  if (fiberNode) {
99
- // First check the matched fiber itself
100
- const directOnChange = fiberNode.memoizedProps?.onChange;
101
- const onChange = typeof directOnChange === 'function'
102
- ? directOnChange
103
- : findNativeOnChange(fiberNode);
71
+ // Find native onChange handler (behavior-based, no tag numbers)
72
+ const nativeOnChangeFiber = fiberNode.memoizedProps?.onChange
73
+ ? fiberNode
74
+ : findFiberNode(fiberNode, n => typeof n.memoizedProps?.onChange === 'function');
104
75
 
105
- if (onChange) {
76
+ // Find native stateNode (host component with setNativeProps)
77
+ const nativeStateFiber = fiberNode.stateNode?.setNativeProps
78
+ ? fiberNode
79
+ : findFiberNode(fiberNode, n => n.stateNode && typeof n.stateNode.setNativeProps === 'function');
80
+
81
+ const onChange = nativeOnChangeFiber?.memoizedProps?.onChange;
82
+ const nativeInstance = nativeStateFiber?.stateNode;
83
+
84
+ if (onChange || nativeInstance) {
106
85
  try {
107
- onChange({
108
- nativeEvent: {
109
- text: args.text,
110
- eventCount: 0,
111
- target: 0,
112
- },
113
- });
86
+ // Step 1: Update visual text in native view
87
+ if (nativeInstance && typeof nativeInstance.setNativeProps === 'function') {
88
+ nativeInstance.setNativeProps({ text: args.text });
89
+ }
90
+
91
+ // Step 2: Notify React's internal onChange so lastNativeText stays in sync
92
+ if (typeof onChange === 'function') {
93
+ onChange({
94
+ nativeEvent: {
95
+ text: args.text,
96
+ eventCount: 1,
97
+ target: 0,
98
+ },
99
+ });
100
+ }
101
+
114
102
  await new Promise(resolve => setTimeout(resolve, 300));
115
103
  return `✅ Typed "${args.text}" into [${args.index}] "${label}"`;
116
104
  } catch (err: any) {
117
- return `❌ onChange failed: ${err.message}`;
105
+ return `❌ Type failed: ${err.message}`;
118
106
  }
119
107
  }
120
108
  }
121
109
 
122
- return `❌ Element [${args.index}] "${label}" is not a typeable text input. No onChangeText or onChange handler found in fiber tree.`;
110
+ return `❌ Element [${args.index}] "${label}" is not a typeable text input. No onChange or native stateNode found in fiber tree.`;
123
111
  },
124
112
  };
125
113
  }