@appilots/cli 0.11.3 → 0.13.0

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/dist/cli/index.js CHANGED
@@ -28,10 +28,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  ));
29
29
 
30
30
  // src/cli/index.ts
31
- var import_commander8 = require("commander");
31
+ var import_commander9 = require("commander");
32
32
 
33
33
  // src/version.ts
34
- var CLI_VERSION = "0.11.3";
34
+ var CLI_VERSION = "0.13.0";
35
35
 
36
36
  // src/config/index.ts
37
37
  var import_fs = require("fs");
@@ -52,7 +52,8 @@ var KNOWN_CONFIG_KEYS = [
52
52
  "navigationExclude",
53
53
  "platform",
54
54
  "manifestPath",
55
- "eval"
55
+ "eval",
56
+ "knowledge"
56
57
  ];
57
58
  var KEY_ALIASES = {
58
59
  apiUrl: "serverUrl",
@@ -200,7 +201,8 @@ function saveConfig(dir, config) {
200
201
  navigationExclude: config.navigationExclude || existingConfig?.navigationExclude,
201
202
  platform: config.platform || existingConfig?.platform,
202
203
  manifestPath: config.manifestPath || existingConfig?.manifestPath,
203
- eval: config.eval || existingConfig?.eval
204
+ eval: config.eval || existingConfig?.eval,
205
+ knowledge: config.knowledge || existingConfig?.knowledge
204
206
  };
205
207
  try {
206
208
  (0, import_fs.writeFileSync)(configPath, JSON.stringify(mergedConfig, null, 2), "utf-8");
@@ -293,6 +295,19 @@ function validateConfig(config) {
293
295
  if (config.manifestPath !== void 0 && typeof config.manifestPath !== "string") {
294
296
  errors.push("manifestPath must be a string");
295
297
  }
298
+ if (config.knowledge !== void 0) {
299
+ if (typeof config.knowledge !== "object" || config.knowledge === null || Array.isArray(config.knowledge)) {
300
+ errors.push("knowledge must be an object");
301
+ } else {
302
+ const kc = config.knowledge;
303
+ for (const field of ["sources", "exclude"]) {
304
+ const value = kc[field];
305
+ if (value !== void 0 && (!Array.isArray(value) || !value.every((item) => typeof item === "string"))) {
306
+ errors.push(`knowledge.${field} must be an array of strings`);
307
+ }
308
+ }
309
+ }
310
+ }
296
311
  if (config.eval !== void 0) {
297
312
  if (typeof config.eval !== "object" || config.eval === null || Array.isArray(config.eval)) {
298
313
  errors.push("eval must be an object");
@@ -634,6 +649,48 @@ var AppilotsAPIClient = class {
634
649
  };
635
650
  }
636
651
  }
652
+ /**
653
+ * Syncs knowledge documents with the Appilots backend.
654
+ *
655
+ * @param documents Array of documents to sync (filename, base64 content, mimeType, checksum)
656
+ * @returns KnowledgeSyncResult with counts of uploaded, skipped, and errored docs
657
+ */
658
+ async knowledgeSync(documents) {
659
+ try {
660
+ const response = await this.request(`${this.baseUrl}/cli/knowledge/sync`, {
661
+ method: "POST",
662
+ headers: {
663
+ "Content-Type": "application/json",
664
+ Authorization: `Bearer ${this.apiKey}`
665
+ },
666
+ body: JSON.stringify({ documents })
667
+ });
668
+ if (!response.ok) {
669
+ const errorData = await response.json().catch(() => ({}));
670
+ return {
671
+ success: false,
672
+ uploaded: 0,
673
+ skipped: 0,
674
+ errors: 0,
675
+ error: describeApiError(errorData, `HTTP ${response.status}: ${response.statusText}`)
676
+ };
677
+ }
678
+ const json = await response.json();
679
+ const inner = json.data ?? json;
680
+ return {
681
+ success: true,
682
+ ...inner
683
+ };
684
+ } catch (error2) {
685
+ return {
686
+ success: false,
687
+ uploaded: 0,
688
+ skipped: 0,
689
+ errors: 0,
690
+ error: error2 instanceof Error ? error2.message : "Failed to sync knowledge with Appilots API"
691
+ };
692
+ }
693
+ }
637
694
  /**
638
695
  * Checks if the Appilots API server is healthy
639
696
  *
@@ -771,7 +828,7 @@ var import_node_path7 = require("path");
771
828
 
772
829
  // src/generators/MCPGenerator.ts
773
830
  var import_promises4 = require("fs/promises");
774
- var import_node_crypto = require("crypto");
831
+ var import_node_crypto2 = require("crypto");
775
832
  var import_node_path5 = __toESM(require("path"));
776
833
 
777
834
  // src/generators/checksum.ts
@@ -1036,8 +1093,355 @@ async function globSorted(patterns, options) {
1036
1093
 
1037
1094
  // src/analyzers/ScreenAnalyzer.ts
1038
1095
  var import_promises = __toESM(require("fs/promises"));
1096
+
1097
+ // src/extractors/control-evidence.ts
1098
+ var import_node_crypto = require("crypto");
1099
+ var import_traverse = __toESM(require("@babel/traverse"));
1100
+ var t2 = __toESM(require("@babel/types"));
1101
+
1102
+ // src/extractors/control-evidence-bindings.ts
1103
+ var t = __toESM(require("@babel/types"));
1104
+ var MAX_HOPS = 8;
1105
+ function unwrap(path13) {
1106
+ while (path13.isTSAsExpression() || path13.isTSTypeAssertion() || path13.isTSNonNullExpression() || path13.isTSSatisfiesExpression() || path13.isParenthesizedExpression())
1107
+ path13 = path13.get("expression");
1108
+ return path13;
1109
+ }
1110
+ function constantValue(path13, depth = 0) {
1111
+ if (depth > MAX_HOPS) return void 0;
1112
+ path13 = unwrap(path13);
1113
+ if (!path13.isIdentifier()) return path13;
1114
+ const binding = path13.scope.getBinding(path13.node.name);
1115
+ if (!binding?.constant || !binding.path.isVariableDeclarator()) return path13;
1116
+ const init = binding.path.get("init");
1117
+ const resolved = init.node ? constantValue(init, depth + 1) : void 0;
1118
+ if (resolved?.isObjectExpression() && binding.referencePaths.some(
1119
+ (reference) => !reference.parentPath?.isJSXSpreadAttribute() && !reference.parentPath?.isSpreadElement()
1120
+ ))
1121
+ return void 0;
1122
+ return resolved;
1123
+ }
1124
+ function propValue(path13, name) {
1125
+ const readObject = (path14) => {
1126
+ const resolved = constantValue(path14);
1127
+ if (!resolved?.isObjectExpression()) return { blocked: true };
1128
+ for (const property of [...resolved.get("properties")].reverse()) {
1129
+ if (property.isSpreadElement()) {
1130
+ const found = readObjectBounded(property.get("argument"));
1131
+ if (found.value || found.blocked) return found;
1132
+ } else if (property.isObjectProperty() || property.isObjectMethod()) {
1133
+ if (property.node.computed) return { blocked: true };
1134
+ const key = property.node.key;
1135
+ if ((t.isIdentifier(key) ? key.name : t.isStringLiteral(key) ? key.value : "") === name)
1136
+ return property.isObjectProperty() ? { value: property.get("value") } : { value: property };
1137
+ }
1138
+ }
1139
+ return {};
1140
+ };
1141
+ let objectBudget = MAX_HOPS;
1142
+ const readObjectBounded = (path14) => objectBudget-- > 0 ? readObject(path14) : { blocked: true };
1143
+ for (const attr of [...path13.get("attributes")].reverse()) {
1144
+ if (attr.isJSXAttribute() && t.isJSXIdentifier(attr.node.name, { name })) {
1145
+ const value = attr.get("value");
1146
+ return value.isJSXExpressionContainer() ? unwrap(value.get("expression")) : value.node ? value : void 0;
1147
+ }
1148
+ if (attr.isJSXSpreadAttribute()) {
1149
+ const found = readObjectBounded(attr.get("argument"));
1150
+ if (found.value || found.blocked) return found.value;
1151
+ }
1152
+ }
1153
+ return void 0;
1154
+ }
1155
+ function importIdentity(path13, depth = 0) {
1156
+ if (depth > MAX_HOPS) return void 0;
1157
+ path13 = unwrap(path13);
1158
+ if (path13.isIdentifier() || path13.isJSXIdentifier()) {
1159
+ const binding = path13.scope.getBinding(path13.node.name);
1160
+ if (!binding?.constant) return void 0;
1161
+ const declaration = binding.path;
1162
+ if (declaration.parentPath?.isImportDeclaration()) {
1163
+ const module2 = declaration.parentPath.node.source.value;
1164
+ if (declaration.isImportSpecifier()) {
1165
+ const imported = declaration.node.imported;
1166
+ return { module: module2, imported: t.isIdentifier(imported) ? imported.name : imported.value };
1167
+ }
1168
+ if (declaration.isImportDefaultSpecifier()) return { module: module2, imported: "default" };
1169
+ if (declaration.isImportNamespaceSpecifier()) return { module: module2, imported: "*" };
1170
+ }
1171
+ if (declaration.isVariableDeclarator() && declaration.get("init").node)
1172
+ return importIdentity(declaration.get("init"), depth + 1);
1173
+ }
1174
+ if (path13.isJSXMemberExpression() || path13.isMemberExpression() && !path13.node.computed) {
1175
+ const origin = importIdentity(path13.get("object"), depth + 1);
1176
+ const key = path13.node.property;
1177
+ if (origin && (t.isIdentifier(key) || t.isJSXIdentifier(key)) && (origin.imported === "*" || origin.module === "react" && origin.imported === "default"))
1178
+ return { module: origin.module, imported: key.name };
1179
+ }
1180
+ return void 0;
1181
+ }
1182
+ function handlerFunction(path13, depth = 0) {
1183
+ if (depth > MAX_HOPS) return void 0;
1184
+ path13 = unwrap(path13);
1185
+ if (path13.isFunction()) return path13;
1186
+ if (path13.isIdentifier()) {
1187
+ const binding = path13.scope.getBinding(path13.node.name);
1188
+ if (!binding?.constant) return void 0;
1189
+ if (binding.path.isFunctionDeclaration()) return binding.path;
1190
+ if (binding.path.isVariableDeclarator() && binding.path.get("init").node)
1191
+ return handlerFunction(binding.path.get("init"), depth + 1);
1192
+ }
1193
+ if (path13.isCallExpression()) {
1194
+ const origin = importIdentity(path13.get("callee"));
1195
+ if (origin?.module === "react" && origin.imported === "useCallback") {
1196
+ const callback = path13.get("arguments")[0];
1197
+ if (callback) return handlerFunction(callback, depth + 1);
1198
+ }
1199
+ }
1200
+ if (path13.isMemberExpression() && !path13.node.computed && t.isThisExpression(path13.node.object)) {
1201
+ const key = path13.node.property;
1202
+ if (!t.isIdentifier(key)) return void 0;
1203
+ const owner = path13.findParent((p) => p.isClassDeclaration() || p.isClassExpression());
1204
+ if (!owner || !(owner.isClassDeclaration() || owner.isClassExpression())) return void 0;
1205
+ for (const member of owner.get("body").get("body")) {
1206
+ if (!(member.isClassMethod() || member.isClassProperty()) || member.node.computed || member.node.static)
1207
+ continue;
1208
+ if (!t.isIdentifier(member.node.key, { name: key.name })) continue;
1209
+ if (member.isClassMethod() && member.node.kind === "method") return member;
1210
+ if (member.isClassProperty() && member.get("value").node)
1211
+ return handlerFunction(member.get("value"), depth + 1);
1212
+ }
1213
+ }
1214
+ return void 0;
1215
+ }
1216
+
1217
+ // src/extractors/control-evidence.ts
1218
+ function symbol(node) {
1219
+ if (t2.isTSAsExpression(node) || t2.isTSTypeAssertion(node) || t2.isTSNonNullExpression(node) || t2.isTSSatisfiesExpression(node))
1220
+ return symbol(node.expression);
1221
+ if (t2.isIdentifier(node) || t2.isJSXIdentifier(node)) return node.name;
1222
+ if (t2.isThisExpression(node)) return "this";
1223
+ if (t2.isMemberExpression(node) && !node.computed || t2.isJSXMemberExpression(node)) {
1224
+ const object = symbol(node.object), property = symbol(node.property);
1225
+ return object && property ? `${object}.${property}` : void 0;
1226
+ }
1227
+ if (t2.isUnaryExpression(node) && node.operator === "!") {
1228
+ const value = symbol(node.argument);
1229
+ return value ? `!${value}` : void 0;
1230
+ }
1231
+ return void 0;
1232
+ }
1233
+ function attribute(node, name) {
1234
+ return node.attributes.find(
1235
+ (a) => t2.isJSXAttribute(a) && t2.isJSXIdentifier(a.name, { name })
1236
+ );
1237
+ }
1238
+ var ICON_LIBRARIES = [
1239
+ "lucide-react-native",
1240
+ "lucide-react",
1241
+ "@tamagui/lucide-icons",
1242
+ "@expo/vector-icons",
1243
+ "@react-native-vector-icons/",
1244
+ "react-native-vector-icons/"
1245
+ ];
1246
+ function iconLibrary(module2) {
1247
+ return ICON_LIBRARIES.some(
1248
+ (name) => name.endsWith("/") ? module2.startsWith(name) : module2 === name || module2.startsWith(name + "/")
1249
+ );
1250
+ }
1251
+ function add(values, value, max = 12) {
1252
+ if (value && value.length <= 240 && values.length < max && !values.includes(value))
1253
+ values.push(value);
1254
+ }
1255
+ function iconName(path13, explicitIcon = false) {
1256
+ const origin = importIdentity(path13);
1257
+ if (origin && iconLibrary(origin.module) && origin.imported !== "*")
1258
+ return origin.imported === "default" ? origin.module : `${origin.module}:${origin.imported}`;
1259
+ const name = symbol(path13.node);
1260
+ return name && (explicitIcon || /icon/i.test(name)) ? name : void 0;
1261
+ }
1262
+ function iconsInElement(path13, explicitIcon = false) {
1263
+ const name = iconName(path13.get("name"), explicitIcon);
1264
+ if (!name) return void 0;
1265
+ const glyph = propValue(path13, "name");
1266
+ const value = glyph && constantValue(glyph);
1267
+ return value?.isStringLiteral() ? `${name}:${value.node.value}` : name;
1268
+ }
1269
+ function hasInteraction(path13) {
1270
+ return ["onPress", "onLongPress", "onClick"].some(
1271
+ (name) => attribute(path13.node, name) || propValue(path13, name)
1272
+ );
1273
+ }
1274
+ function collectPresentationIcons(path13, icons) {
1275
+ const namedIconProps = [
1276
+ "icon",
1277
+ "prefix",
1278
+ "suffix",
1279
+ "left",
1280
+ "right",
1281
+ "leadingIcon",
1282
+ "trailingIcon",
1283
+ "startIcon",
1284
+ "endIcon",
1285
+ "renderIcon"
1286
+ ];
1287
+ const props = new Set(namedIconProps);
1288
+ for (const attr of path13.node.attributes)
1289
+ if (t2.isJSXAttribute(attr) && t2.isJSXIdentifier(attr.name) && !/^on[A-Z]/.test(attr.name.name))
1290
+ props.add(attr.name.name);
1291
+ for (const prop of props) {
1292
+ const icon = propValue(path13, prop);
1293
+ if (icon) {
1294
+ const value = constantValue(icon);
1295
+ if (value?.isStringLiteral()) {
1296
+ if (prop.toLowerCase().includes("icon")) add(icons, value.node.value, 8);
1297
+ } else {
1298
+ const explicitIcon = prop.toLowerCase() === "icon";
1299
+ if (icon.isJSXElement()) {
1300
+ if (hasInteraction(icon.get("openingElement"))) continue;
1301
+ add(icons, iconsInElement(icon.get("openingElement"), explicitIcon), 8);
1302
+ }
1303
+ icon.traverse({
1304
+ JSXAttribute(attr) {
1305
+ if (t2.isJSXIdentifier(attr.node.name) && /^on[A-Z]/.test(attr.node.name.name))
1306
+ attr.skip();
1307
+ },
1308
+ JSXElement(child) {
1309
+ const opening = child.get("openingElement");
1310
+ if (hasInteraction(opening)) {
1311
+ child.skip();
1312
+ return;
1313
+ }
1314
+ add(icons, iconsInElement(opening, explicitIcon), 8);
1315
+ }
1316
+ });
1317
+ if (!icons.length && (namedIconProps.includes(prop) || explicitIcon))
1318
+ add(icons, iconName(icon, explicitIcon), 8);
1319
+ }
1320
+ }
1321
+ }
1322
+ }
1323
+ function collectIcons(path13) {
1324
+ const icons = [];
1325
+ collectPresentationIcons(path13, icons);
1326
+ const jsx = path13.parentPath;
1327
+ if (jsx.isJSXElement())
1328
+ jsx.traverse({
1329
+ // JSX mentioned inside an event callback is not a rendered child icon.
1330
+ JSXAttribute(attr) {
1331
+ attr.skip();
1332
+ },
1333
+ JSXElement(child) {
1334
+ const opening = child.get("openingElement");
1335
+ if (hasInteraction(opening)) {
1336
+ child.skip();
1337
+ return;
1338
+ }
1339
+ add(icons, iconsInElement(opening), 8);
1340
+ collectPresentationIcons(opening, icons);
1341
+ }
1342
+ });
1343
+ return icons;
1344
+ }
1345
+ function conditionsAt(path13) {
1346
+ const conditions = [];
1347
+ let child = path13;
1348
+ for (let parent = child.parentPath; parent && !parent.isFunction(); child = parent, parent = parent.parentPath) {
1349
+ let test;
1350
+ let negated = false;
1351
+ if (parent.isLogicalExpression() && parent.node.right === child.node) {
1352
+ if (parent.node.operator === "&&") test = parent.node.left;
1353
+ if (parent.node.operator === "||") {
1354
+ test = parent.node.left;
1355
+ negated = true;
1356
+ }
1357
+ } else if (parent.isConditionalExpression() && parent.node.test !== child.node) {
1358
+ test = parent.node.test;
1359
+ negated = parent.node.alternate === child.node;
1360
+ } else if (parent.isIfStatement() && parent.node.test !== child.node) {
1361
+ test = parent.node.test;
1362
+ negated = parent.node.alternate === child.node;
1363
+ }
1364
+ const name = symbol(test);
1365
+ if (name) add(conditions, negated ? name.startsWith("!") ? name.slice(1) : `!${name}` : name);
1366
+ }
1367
+ return conditions;
1368
+ }
1369
+ function collectHandlerEvidence(expression, evidence) {
1370
+ const seen = /* @__PURE__ */ new Set();
1371
+ let budget = 100;
1372
+ const visit = (path13, depth) => {
1373
+ if (depth > 4 || budget-- <= 0) return;
1374
+ const fn = handlerFunction(path13);
1375
+ if (!fn || seen.has(fn.node)) return;
1376
+ seen.add(fn.node);
1377
+ fn.traverse({
1378
+ // Ignore uncalled helper definitions; inline callbacks remain source evidence.
1379
+ Function(nested) {
1380
+ if (!nested.parentPath.isCallExpression() && !nested.parentPath.isObjectProperty())
1381
+ nested.skip();
1382
+ },
1383
+ CallExpression(call) {
1384
+ if (budget-- <= 0) {
1385
+ call.skip();
1386
+ return;
1387
+ }
1388
+ add(evidence.calls, symbol(call.node.callee));
1389
+ for (const arg of call.node.arguments) add(evidence.argumentBindings, symbol(arg));
1390
+ visit(call.get("callee"), depth + 1);
1391
+ if (!t2.isMemberExpression(call.node.callee) || call.node.callee.computed || !t2.isIdentifier(call.node.callee.property, { name: "alert" }))
1392
+ return;
1393
+ const callee = call.get("callee");
1394
+ if (!callee.isMemberExpression()) return;
1395
+ const origin = importIdentity(callee.get("object"));
1396
+ if (origin?.module !== "react-native" || origin.imported !== "Alert") return;
1397
+ const options = call.node.arguments[2];
1398
+ const destructiveOption = t2.isArrayExpression(options) && options.elements.some(
1399
+ (option) => t2.isObjectExpression(option) && option.properties.some(
1400
+ (p) => t2.isObjectProperty(p) && !p.computed && symbol(p.key) === "style" && t2.isStringLiteral(p.value, { value: "destructive" })
1401
+ )
1402
+ );
1403
+ if (destructiveOption)
1404
+ evidence.nativeConfirmation = {
1405
+ title: symbol(call.node.arguments[0]),
1406
+ destructiveOption
1407
+ };
1408
+ }
1409
+ });
1410
+ };
1411
+ visit(unwrap(expression), 0);
1412
+ }
1413
+ function extractControlEvidence(ast, source, file2) {
1414
+ const candidates = [];
1415
+ const sourceHash = (0, import_node_crypto.createHash)("sha256").update(source).digest("hex");
1416
+ (0, import_traverse.default)(ast, {
1417
+ JSXOpeningElement(path13) {
1418
+ const node = path13.node;
1419
+ if (attribute(node, "__appilotsControl")) return;
1420
+ const value = propValue(path13, "onPress");
1421
+ if (!value && !attribute(node, "onPress") || value?.isNullLiteral() || value?.isJSXEmptyExpression())
1422
+ return;
1423
+ const icons = collectIcons(path13);
1424
+ if (!icons.length || node.end == null) return;
1425
+ const evidence = {
1426
+ version: 1,
1427
+ siteId: (0, import_node_crypto.createHash)("sha256").update(`${file2}:${sourceHash}:${node.start}`).digest("hex").slice(0, 20),
1428
+ component: symbol(node.name) ?? "unknown",
1429
+ icons,
1430
+ ...value && symbol(value.node) ? { handler: symbol(value.node) } : {},
1431
+ calls: [],
1432
+ argumentBindings: [],
1433
+ conditions: conditionsAt(path13)
1434
+ };
1435
+ if (value) collectHandlerEvidence(value, evidence);
1436
+ candidates.push({ evidence, sourceHash, offset: node.end - (node.selfClosing ? 2 : 1) });
1437
+ }
1438
+ });
1439
+ return candidates;
1440
+ }
1441
+
1442
+ // src/analyzers/ScreenAnalyzer.ts
1039
1443
  var import_path3 = __toESM(require("path"));
1040
- var import_traverse4 = __toESM(require("@babel/traverse"));
1444
+ var import_traverse5 = __toESM(require("@babel/traverse"));
1041
1445
  var BabelTypes = __toESM(require("@babel/types"));
1042
1446
 
1043
1447
  // src/ast/parse.ts
@@ -1062,25 +1466,25 @@ function parseSource(source, parserPlugins = []) {
1062
1466
  }
1063
1467
 
1064
1468
  // src/ast/jsx/attributes.ts
1065
- var t = __toESM(require("@babel/types"));
1469
+ var t3 = __toESM(require("@babel/types"));
1066
1470
  function findJsxAttribute(element, name) {
1067
1471
  return element.attributes.find(
1068
- (attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === name
1472
+ (attr) => t3.isJSXAttribute(attr) && t3.isJSXIdentifier(attr.name) && attr.name.name === name
1069
1473
  );
1070
1474
  }
1071
1475
  function getStringAttr(element, name) {
1072
1476
  const attr = findJsxAttribute(element, name);
1073
1477
  if (!attr || !attr.value) return void 0;
1074
- if (t.isStringLiteral(attr.value)) return attr.value.value;
1075
- if (t.isJSXExpressionContainer(attr.value) && t.isStringLiteral(attr.value.expression)) {
1478
+ if (t3.isStringLiteral(attr.value)) return attr.value.value;
1479
+ if (t3.isJSXExpressionContainer(attr.value) && t3.isStringLiteral(attr.value.expression)) {
1076
1480
  return attr.value.expression.value;
1077
1481
  }
1078
1482
  return void 0;
1079
1483
  }
1080
1484
  function getExpressionIdentifierAttr(element, name) {
1081
1485
  const attr = findJsxAttribute(element, name);
1082
- if (!attr?.value || !t.isJSXExpressionContainer(attr.value)) return void 0;
1083
- return t.isIdentifier(attr.value.expression) ? attr.value.expression.name : void 0;
1486
+ if (!attr?.value || !t3.isJSXExpressionContainer(attr.value)) return void 0;
1487
+ return t3.isIdentifier(attr.value.expression) ? attr.value.expression.name : void 0;
1084
1488
  }
1085
1489
  function hasJsxAttribute(element, name) {
1086
1490
  return Boolean(findJsxAttribute(element, name));
@@ -1159,18 +1563,18 @@ function classifyJsxComponent(name, element) {
1159
1563
  }
1160
1564
 
1161
1565
  // src/ast/functions/collect.ts
1162
- var import_traverse = __toESM(require("@babel/traverse"));
1163
- var t2 = __toESM(require("@babel/types"));
1566
+ var import_traverse2 = __toESM(require("@babel/traverse"));
1567
+ var t4 = __toESM(require("@babel/types"));
1164
1568
  function collectFunctions(ast) {
1165
1569
  const handlers = /* @__PURE__ */ new Map();
1166
- (0, import_traverse.default)(ast, {
1570
+ (0, import_traverse2.default)(ast, {
1167
1571
  FunctionDeclaration: (nodePath) => {
1168
1572
  if (nodePath.node.id?.name) handlers.set(nodePath.node.id.name, nodePath.node);
1169
1573
  },
1170
1574
  VariableDeclarator: (nodePath) => {
1171
- if (!t2.isIdentifier(nodePath.node.id)) return;
1575
+ if (!t4.isIdentifier(nodePath.node.id)) return;
1172
1576
  const init = nodePath.node.init;
1173
- if (t2.isArrowFunctionExpression(init) || t2.isFunctionExpression(init)) {
1577
+ if (t4.isArrowFunctionExpression(init) || t4.isFunctionExpression(init)) {
1174
1578
  handlers.set(nodePath.node.id.name, init);
1175
1579
  }
1176
1580
  }
@@ -1179,8 +1583,8 @@ function collectFunctions(ast) {
1179
1583
  }
1180
1584
 
1181
1585
  // src/ast/functions/analyze-async.ts
1182
- var import_traverse2 = __toESM(require("@babel/traverse"));
1183
- var t3 = __toESM(require("@babel/types"));
1586
+ var import_traverse3 = __toESM(require("@babel/traverse"));
1587
+ var t5 = __toESM(require("@babel/types"));
1184
1588
  var DESTRUCTIVE_VERB = /(delete|destroy|remove|discard|wipe|erase|drop|terminate|revoke|deactivate|disable)/i;
1185
1589
  function analyzeFunctionBehavior(name, fn, handlers, seen = /* @__PURE__ */ new Set()) {
1186
1590
  if (seen.has(name)) {
@@ -1202,41 +1606,41 @@ function analyzeFunctionBehavior(name, fn, handlers, seen = /* @__PURE__ */ new
1202
1606
  let destructive = DESTRUCTIVE_VERB.test(name);
1203
1607
  const loadingStateBindings = /* @__PURE__ */ new Set();
1204
1608
  const inspectCall = (node) => {
1205
- if (t3.isMemberExpression(node.callee) && t3.isIdentifier(node.callee.property)) {
1609
+ if (t5.isMemberExpression(node.callee) && t5.isIdentifier(node.callee.property)) {
1206
1610
  const method = node.callee.property.name;
1207
1611
  if (method === "then" || method === "catch" || method === "finally") hasThen = true;
1208
- if (t3.isIdentifier(node.callee.object) && node.callee.object.name === "navigation" && ["navigate", "push", "replace"].includes(method)) {
1612
+ if (t5.isIdentifier(node.callee.object) && node.callee.object.name === "navigation" && ["navigate", "push", "replace"].includes(method)) {
1209
1613
  const firstArg = node.arguments[0];
1210
- if (t3.isStringLiteral(firstArg)) {
1614
+ if (t5.isStringLiteral(firstArg)) {
1211
1615
  targetScreen = firstArg.value;
1212
1616
  successSignal = { type: "navigation", target: firstArg.value };
1213
1617
  }
1214
1618
  }
1215
- if (t3.isIdentifier(node.callee.object) && node.callee.object.name === "navigation" && method === "goBack") {
1619
+ if (t5.isIdentifier(node.callee.object) && node.callee.object.name === "navigation" && method === "goBack") {
1216
1620
  successSignal = { type: "goBack", description: "Action returns to the previous screen" };
1217
1621
  }
1218
- if (t3.isIdentifier(node.callee.object) && node.callee.object.name === "Alert" && method === "alert") {
1622
+ if (t5.isIdentifier(node.callee.object) && node.callee.object.name === "Alert" && method === "alert") {
1219
1623
  nativeConfirmationExpected = true;
1220
1624
  }
1221
- if (t3.isIdentifier(node.callee.object) && /(toast|notification|snackbar)/i.test(node.callee.object.name)) {
1625
+ if (t5.isIdentifier(node.callee.object) && /(toast|notification|snackbar)/i.test(node.callee.object.name)) {
1222
1626
  const firstArg = node.arguments[0];
1223
1627
  const secondArg = node.arguments[1];
1224
- const text = t3.isStringLiteral(secondArg) ? secondArg.value : t3.isStringLiteral(firstArg) ? firstArg.value : void 0;
1628
+ const text = t5.isStringLiteral(secondArg) ? secondArg.value : t5.isStringLiteral(firstArg) ? firstArg.value : void 0;
1225
1629
  const signal = { type: "toast", description: text };
1226
- if (/(error|danger|fail)/i.test(method) || t3.isStringLiteral(firstArg) && /error/i.test(firstArg.value)) {
1630
+ if (/(error|danger|fail)/i.test(method) || t5.isStringLiteral(firstArg) && /error/i.test(firstArg.value)) {
1227
1631
  failureSignal = signal;
1228
1632
  } else {
1229
1633
  successSignal = successSignal ?? signal;
1230
1634
  }
1231
1635
  }
1232
1636
  }
1233
- if (t3.isIdentifier(node.callee)) {
1637
+ if (t5.isIdentifier(node.callee)) {
1234
1638
  const calleeName = node.callee.name;
1235
1639
  if (/^set[A-Z]/.test(calleeName)) {
1236
1640
  hasStateSetter = true;
1237
1641
  const stateName = setterToStateName(calleeName);
1238
1642
  const firstArg = node.arguments[0];
1239
- if (stateName && t3.isBooleanLiteral(firstArg)) {
1643
+ if (stateName && t5.isBooleanLiteral(firstArg)) {
1240
1644
  if (/loading|submitting|saving|fetching|refreshing/i.test(stateName)) {
1241
1645
  loadingStateBindings.add(stateName);
1242
1646
  }
@@ -1263,14 +1667,14 @@ function analyzeFunctionBehavior(name, fn, handlers, seen = /* @__PURE__ */ new
1263
1667
  }
1264
1668
  };
1265
1669
  const inspectNode = (node) => {
1266
- if (t3.isAwaitExpression(node)) hasAwait = true;
1267
- if (t3.isCallExpression(node)) inspectCall(node);
1268
- if (t3.isMemberExpression(node) && t3.isIdentifier(node.property) && DESTRUCTIVE_VERB.test(node.property.name)) {
1670
+ if (t5.isAwaitExpression(node)) hasAwait = true;
1671
+ if (t5.isCallExpression(node)) inspectCall(node);
1672
+ if (t5.isMemberExpression(node) && t5.isIdentifier(node.property) && DESTRUCTIVE_VERB.test(node.property.name)) {
1269
1673
  destructive = true;
1270
1674
  }
1271
1675
  };
1272
1676
  if (fn.body) {
1273
- (0, import_traverse2.default)(fn.body, {
1677
+ (0, import_traverse3.default)(fn.body, {
1274
1678
  noScope: true,
1275
1679
  enter: (nodePath) => inspectNode(nodePath.node)
1276
1680
  });
@@ -1298,21 +1702,21 @@ function setterToStateName(setterName) {
1298
1702
  }
1299
1703
 
1300
1704
  // src/ast/navigation/calls.ts
1301
- var import_traverse3 = __toESM(require("@babel/traverse"));
1302
- var t4 = __toESM(require("@babel/types"));
1705
+ var import_traverse4 = __toESM(require("@babel/traverse"));
1706
+ var t6 = __toESM(require("@babel/types"));
1303
1707
  function extractNavigationCalls(ast) {
1304
1708
  const calls = [];
1305
- (0, import_traverse3.default)(ast, {
1306
- noScope: !t4.isFile(ast),
1709
+ (0, import_traverse4.default)(ast, {
1710
+ noScope: !t6.isFile(ast),
1307
1711
  CallExpression: (nodePath) => {
1308
1712
  const node = nodePath.node;
1309
- if (!t4.isMemberExpression(node.callee) || !t4.isIdentifier(node.callee.object) || node.callee.object.name !== "navigation" || !t4.isIdentifier(node.callee.property)) {
1713
+ if (!t6.isMemberExpression(node.callee) || !t6.isIdentifier(node.callee.object) || node.callee.object.name !== "navigation" || !t6.isIdentifier(node.callee.property)) {
1310
1714
  return;
1311
1715
  }
1312
1716
  const method = node.callee.property.name;
1313
1717
  if (!["navigate", "push", "replace", "goBack"].includes(method)) return;
1314
1718
  const firstArg = node.arguments[0];
1315
- const targetScreen = t4.isStringLiteral(firstArg) ? firstArg.value : void 0;
1719
+ const targetScreen = t6.isStringLiteral(firstArg) ? firstArg.value : void 0;
1316
1720
  calls.push({
1317
1721
  method,
1318
1722
  ...targetScreen ? { targetScreen } : {},
@@ -1324,16 +1728,16 @@ function extractNavigationCalls(ast) {
1324
1728
  }
1325
1729
  function extractNavigationParams(arg) {
1326
1730
  const params = {};
1327
- if (!arg || !t4.isObjectExpression(arg)) return params;
1731
+ if (!arg || !t6.isObjectExpression(arg)) return params;
1328
1732
  for (const prop of arg.properties) {
1329
- if (!t4.isObjectProperty(prop)) continue;
1330
- const key = t4.isIdentifier(prop.key) ? prop.key.name : t4.isStringLiteral(prop.key) ? prop.key.value : void 0;
1733
+ if (!t6.isObjectProperty(prop)) continue;
1734
+ const key = t6.isIdentifier(prop.key) ? prop.key.name : t6.isStringLiteral(prop.key) ? prop.key.value : void 0;
1331
1735
  if (!key) continue;
1332
- if (t4.isMemberExpression(prop.value) && t4.isIdentifier(prop.value.object) && t4.isIdentifier(prop.value.property)) {
1736
+ if (t6.isMemberExpression(prop.value) && t6.isIdentifier(prop.value.object) && t6.isIdentifier(prop.value.property)) {
1333
1737
  params[key] = `${prop.value.object.name}.${prop.value.property.name}`;
1334
- } else if (t4.isIdentifier(prop.value)) {
1738
+ } else if (t6.isIdentifier(prop.value)) {
1335
1739
  params[key] = prop.value.name;
1336
- } else if (t4.isStringLiteral(prop.value)) {
1740
+ } else if (t6.isStringLiteral(prop.value)) {
1337
1741
  params[key] = prop.value.value;
1338
1742
  }
1339
1743
  }
@@ -1453,6 +1857,7 @@ var ScreenAnalyzer = class {
1453
1857
  routeTargetFiles;
1454
1858
  /** §D: Count of screens filtered out in strict mode (available after analyze()) */
1455
1859
  screensFilteredOut = 0;
1860
+ controlEvidenceFiles = {};
1456
1861
  constructor(config, options) {
1457
1862
  this.config = config;
1458
1863
  this.routeTargetFiles = options?.routeTargetFiles ?? /* @__PURE__ */ new Set();
@@ -1553,6 +1958,11 @@ var ScreenAnalyzer = class {
1553
1958
  title: registerScreenMeta?.title,
1554
1959
  description: registerScreenMeta?.description,
1555
1960
  components,
1961
+ controlCandidates: extractControlEvidence(
1962
+ ast,
1963
+ source,
1964
+ import_path3.default.relative(this.config.rootDir, filePath)
1965
+ ),
1556
1966
  forms,
1557
1967
  actions,
1558
1968
  navigationTargets,
@@ -1563,6 +1973,8 @@ var ScreenAnalyzer = class {
1563
1973
  ...permissionsFromJsDoc.isPii ? { isPii: true } : {}
1564
1974
  } : {}
1565
1975
  };
1976
+ if (descriptor.controlCandidates?.length)
1977
+ this.controlEvidenceFiles[import_path3.default.relative(this.config.rootDir, filePath).split(import_path3.default.sep).join("/")] = descriptor.controlCandidates;
1566
1978
  descriptor.__hasRegisterScreen = hasRegisterScreenCall;
1567
1979
  return descriptor;
1568
1980
  }
@@ -1572,7 +1984,7 @@ var ScreenAnalyzer = class {
1572
1984
  */
1573
1985
  detectRegisterScreenCall(ast) {
1574
1986
  let found = false;
1575
- (0, import_traverse4.default)(ast, {
1987
+ (0, import_traverse5.default)(ast, {
1576
1988
  CallExpression: (nodePath) => {
1577
1989
  if (found) return;
1578
1990
  const callee = nodePath.node.callee;
@@ -1589,7 +2001,7 @@ var ScreenAnalyzer = class {
1589
2001
  */
1590
2002
  extractRegisterScreenMetadata(ast) {
1591
2003
  let metadata = null;
1592
- (0, import_traverse4.default)(ast, {
2004
+ (0, import_traverse5.default)(ast, {
1593
2005
  CallExpression: (nodePath) => {
1594
2006
  const callee = nodePath.node.callee;
1595
2007
  if (BabelTypes.isIdentifier(callee) && callee.name === "registerScreen" || BabelTypes.isMemberExpression(callee) && BabelTypes.isIdentifier(callee.property) && callee.property.name === "registerScreen") {
@@ -1886,7 +2298,7 @@ var ScreenAnalyzer = class {
1886
2298
  */
1887
2299
  extractDefaultComponentName(ast) {
1888
2300
  let componentName = "";
1889
- (0, import_traverse4.default)(ast, {
2301
+ (0, import_traverse5.default)(ast, {
1890
2302
  ExportDefaultDeclaration: (nodePath) => {
1891
2303
  const declaration = nodePath.node.declaration;
1892
2304
  if (BabelTypes.isFunctionDeclaration(declaration) && declaration.id?.name) {
@@ -1911,7 +2323,7 @@ var ScreenAnalyzer = class {
1911
2323
  */
1912
2324
  extractNavigationTargets(ast) {
1913
2325
  const targets = /* @__PURE__ */ new Set();
1914
- (0, import_traverse4.default)(ast, {
2326
+ (0, import_traverse5.default)(ast, {
1915
2327
  CallExpression: (nodePath) => {
1916
2328
  const callee = nodePath.node.callee;
1917
2329
  if (BabelTypes.isMemberExpression(callee) && BabelTypes.isIdentifier(callee.object) && callee.object.name === "navigation" && BabelTypes.isIdentifier(callee.property) && callee.property.name === "navigate") {
@@ -1930,7 +2342,7 @@ var ScreenAnalyzer = class {
1930
2342
  extractForms(ast) {
1931
2343
  const forms = [];
1932
2344
  const fields = /* @__PURE__ */ new Map();
1933
- (0, import_traverse4.default)(ast, {
2345
+ (0, import_traverse5.default)(ast, {
1934
2346
  JSXOpeningElement: (nodePath) => {
1935
2347
  const element = nodePath.node;
1936
2348
  if (BabelTypes.isJSXIdentifier(element.name)) {
@@ -2051,7 +2463,7 @@ var ScreenAnalyzer = class {
2051
2463
  extractComponents(ast) {
2052
2464
  const components = [];
2053
2465
  const seen = /* @__PURE__ */ new Set();
2054
- (0, import_traverse4.default)(ast, {
2466
+ (0, import_traverse5.default)(ast, {
2055
2467
  JSXOpeningElement: (nodePath) => {
2056
2468
  const element = nodePath.node;
2057
2469
  if (BabelTypes.isJSXIdentifier(element.name)) {
@@ -2115,7 +2527,7 @@ var ScreenAnalyzer = class {
2115
2527
  const actionLabels = new Map(
2116
2528
  actions.filter((a) => a.label).map((a) => [this.normalizeLabel(a.label), a])
2117
2529
  );
2118
- (0, import_traverse4.default)(ast, {
2530
+ (0, import_traverse5.default)(ast, {
2119
2531
  JSXOpeningElement: (nodePath) => {
2120
2532
  const element = nodePath.node;
2121
2533
  if (BabelTypes.isJSXIdentifier(element.name)) {
@@ -2184,7 +2596,7 @@ var ScreenAnalyzer = class {
2184
2596
  }
2185
2597
  collectButtonHandlersByLabel(ast) {
2186
2598
  const out = /* @__PURE__ */ new Map();
2187
- (0, import_traverse4.default)(ast, {
2599
+ (0, import_traverse5.default)(ast, {
2188
2600
  JSXOpeningElement: (nodePath) => {
2189
2601
  const element = nodePath.node;
2190
2602
  if (!BabelTypes.isJSXIdentifier(element.name)) return;
@@ -2266,7 +2678,7 @@ var ScreenAnalyzer = class {
2266
2678
  }
2267
2679
  };
2268
2680
  if (fn.body) {
2269
- (0, import_traverse4.default)(
2681
+ (0, import_traverse5.default)(
2270
2682
  fn.body,
2271
2683
  {
2272
2684
  noScope: true,
@@ -2463,7 +2875,7 @@ var ScreenAnalyzer = class {
2463
2875
  extractCollections(ast) {
2464
2876
  const renderItemFns = this.collectRenderItemFunctions(ast);
2465
2877
  const collections = [];
2466
- (0, import_traverse4.default)(ast, {
2878
+ (0, import_traverse5.default)(ast, {
2467
2879
  JSXOpeningElement: (nodePath) => {
2468
2880
  const element = nodePath.node;
2469
2881
  if (!BabelTypes.isJSXIdentifier(element.name)) return;
@@ -2500,7 +2912,7 @@ var ScreenAnalyzer = class {
2500
2912
  }
2501
2913
  collectRenderItemFunctions(ast) {
2502
2914
  const out = /* @__PURE__ */ new Map();
2503
- (0, import_traverse4.default)(ast, {
2915
+ (0, import_traverse5.default)(ast, {
2504
2916
  VariableDeclarator: (nodePath) => {
2505
2917
  if (!BabelTypes.isIdentifier(nodePath.node.id)) return;
2506
2918
  const init = nodePath.node.init;
@@ -2543,7 +2955,7 @@ var ScreenAnalyzer = class {
2543
2955
  }
2544
2956
  extractRowAction(fn) {
2545
2957
  let action;
2546
- (0, import_traverse4.default)(
2958
+ (0, import_traverse5.default)(
2547
2959
  fn.body,
2548
2960
  {
2549
2961
  noScope: true,
@@ -2596,7 +3008,7 @@ var ScreenAnalyzer = class {
2596
3008
  } else if (BabelTypes.isIdentifier(firstParam)) {
2597
3009
  itemNames.add(firstParam.name);
2598
3010
  }
2599
- (0, import_traverse4.default)(
3011
+ (0, import_traverse5.default)(
2600
3012
  fn.body,
2601
3013
  {
2602
3014
  noScope: true,
@@ -2638,7 +3050,7 @@ var ScreenAnalyzer = class {
2638
3050
  inferSearchField(ast, dataSource) {
2639
3051
  if (!dataSource) return void 0;
2640
3052
  let queryBinding;
2641
- (0, import_traverse4.default)(ast, {
3053
+ (0, import_traverse5.default)(ast, {
2642
3054
  CallExpression: (nodePath) => {
2643
3055
  const node = nodePath.node;
2644
3056
  if (!BabelTypes.isMemberExpression(node.callee)) return;
@@ -2649,7 +3061,7 @@ var ScreenAnalyzer = class {
2649
3061
  const fn = node.arguments[0];
2650
3062
  if (!BabelTypes.isArrowFunctionExpression(fn) && !BabelTypes.isFunctionExpression(fn))
2651
3063
  return;
2652
- (0, import_traverse4.default)(
3064
+ (0, import_traverse5.default)(
2653
3065
  fn.body,
2654
3066
  {
2655
3067
  noScope: true,
@@ -2695,16 +3107,16 @@ var ScreenAnalyzer = class {
2695
3107
  var import_fs4 = require("fs");
2696
3108
  var import_path4 = __toESM(require("path"));
2697
3109
  var parser2 = __toESM(require("@babel/parser"));
2698
- var import_traverse5 = __toESM(require("@babel/traverse"));
2699
- var t6 = __toESM(require("@babel/types"));
3110
+ var import_traverse6 = __toESM(require("@babel/traverse"));
3111
+ var t8 = __toESM(require("@babel/types"));
2700
3112
 
2701
3113
  // src/ast/navigation/module-graph.ts
2702
3114
  var import_node_fs = require("fs");
2703
3115
  var import_node_path = __toESM(require("path"));
2704
3116
  var parser = __toESM(require("@babel/parser"));
2705
- var t5 = __toESM(require("@babel/types"));
3117
+ var t7 = __toESM(require("@babel/types"));
2706
3118
  var EXTENSIONS = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"];
2707
- var MAX_HOPS = 8;
3119
+ var MAX_HOPS2 = 8;
2708
3120
  var ModuleGraph = class {
2709
3121
  asts = /* @__PURE__ */ new Map();
2710
3122
  resolved = /* @__PURE__ */ new Map();
@@ -2788,15 +3200,15 @@ var ModuleGraph = class {
2788
3200
  const ast = this.parse(file2);
2789
3201
  if (!ast) return out;
2790
3202
  for (const stmt of ast.program.body) {
2791
- if (!t5.isImportDeclaration(stmt)) continue;
3203
+ if (!t7.isImportDeclaration(stmt)) continue;
2792
3204
  const source = stmt.source.value;
2793
3205
  for (const spec of stmt.specifiers) {
2794
- if (t5.isImportDefaultSpecifier(spec)) {
3206
+ if (t7.isImportDefaultSpecifier(spec)) {
2795
3207
  out.set(spec.local.name, { source, imported: "default" });
2796
- } else if (t5.isImportNamespaceSpecifier(spec)) {
3208
+ } else if (t7.isImportNamespaceSpecifier(spec)) {
2797
3209
  out.set(spec.local.name, { source, imported: "*" });
2798
- } else if (t5.isImportSpecifier(spec)) {
2799
- const imported = t5.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
3210
+ } else if (t7.isImportSpecifier(spec)) {
3211
+ const imported = t7.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
2800
3212
  out.set(spec.local.name, { source, imported });
2801
3213
  }
2802
3214
  }
@@ -2808,11 +3220,11 @@ var ModuleGraph = class {
2808
3220
  const ast = this.parse(file2);
2809
3221
  if (!ast) return null;
2810
3222
  for (const stmt of ast.program.body) {
2811
- const decl = t5.isExportNamedDeclaration(stmt) ? stmt.declaration : stmt;
2812
- if (!t5.isVariableDeclaration(decl)) continue;
3223
+ const decl = t7.isExportNamedDeclaration(stmt) ? stmt.declaration : stmt;
3224
+ if (!t7.isVariableDeclaration(decl)) continue;
2813
3225
  for (const d of decl.declarations) {
2814
- if (t5.isIdentifier(d.id) && d.id.name === name && d.init) {
2815
- return t5.isTSAsExpression(d.init) ? d.init.expression : d.init;
3226
+ if (t7.isIdentifier(d.id) && d.id.name === name && d.init) {
3227
+ return t7.isTSAsExpression(d.init) ? d.init.expression : d.init;
2816
3228
  }
2817
3229
  }
2818
3230
  }
@@ -2823,7 +3235,7 @@ var ModuleGraph = class {
2823
3235
  * Devolve o arquivo e o nome sob o qual ele é definido lá.
2824
3236
  */
2825
3237
  resolveBinding(file2, name, hops = 0) {
2826
- if (hops > MAX_HOPS) return null;
3238
+ if (hops > MAX_HOPS2) return null;
2827
3239
  if (this.topLevelInit(file2, name) !== null) return { file: file2, name };
2828
3240
  const binding = this.imports(file2).get(name);
2829
3241
  if (binding) {
@@ -2836,10 +3248,10 @@ var ModuleGraph = class {
2836
3248
  const ast = this.parse(file2);
2837
3249
  if (ast) {
2838
3250
  for (const stmt of ast.program.body) {
2839
- if (!t5.isExportNamedDeclaration(stmt) || !stmt.source) continue;
3251
+ if (!t7.isExportNamedDeclaration(stmt) || !stmt.source) continue;
2840
3252
  for (const spec of stmt.specifiers) {
2841
- if (!t5.isExportSpecifier(spec)) continue;
2842
- const exported = t5.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value;
3253
+ if (!t7.isExportSpecifier(spec)) continue;
3254
+ const exported = t7.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value;
2843
3255
  if (exported !== name) continue;
2844
3256
  const target = this.resolve(file2, stmt.source.value);
2845
3257
  if (!target) return null;
@@ -2850,7 +3262,7 @@ var ModuleGraph = class {
2850
3262
  }
2851
3263
  if (ast) {
2852
3264
  for (const stmt of ast.program.body) {
2853
- if (!t5.isExportAllDeclaration(stmt)) continue;
3265
+ if (!t7.isExportAllDeclaration(stmt)) continue;
2854
3266
  const target = this.resolve(file2, stmt.source.value);
2855
3267
  if (!target || target === file2) continue;
2856
3268
  const deeper = this.resolveBinding(target, name, hops + 1);
@@ -2859,8 +3271,8 @@ var ModuleGraph = class {
2859
3271
  }
2860
3272
  if (ast) {
2861
3273
  for (const stmt of ast.program.body) {
2862
- if (!t5.isExportDefaultDeclaration(stmt)) continue;
2863
- if (t5.isIdentifier(stmt.declaration)) {
3274
+ if (!t7.isExportDefaultDeclaration(stmt)) continue;
3275
+ if (t7.isIdentifier(stmt.declaration)) {
2864
3276
  const local = stmt.declaration.name;
2865
3277
  if (local === name) return null;
2866
3278
  return this.resolveBinding(file2, local, hops + 1) ?? { file: file2, name: local };
@@ -2877,12 +3289,12 @@ var ModuleGraph = class {
2877
3289
  * com interpolação nem valor calculado, de propósito.
2878
3290
  */
2879
3291
  stringConstant(file2, node, hops = 0) {
2880
- if (!node || hops > MAX_HOPS) return null;
2881
- if (t5.isStringLiteral(node)) return node.value;
2882
- if (t5.isTemplateLiteral(node)) {
3292
+ if (!node || hops > MAX_HOPS2) return null;
3293
+ if (t7.isStringLiteral(node)) return node.value;
3294
+ if (t7.isTemplateLiteral(node)) {
2883
3295
  return node.expressions.length === 0 ? node.quasis[0]?.value.cooked ?? null : null;
2884
3296
  }
2885
- if (t5.isTSAsExpression(node)) return this.stringConstant(file2, node.expression, hops + 1);
3297
+ if (t7.isTSAsExpression(node)) return this.stringConstant(file2, node.expression, hops + 1);
2886
3298
  const chain = memberChain(node);
2887
3299
  if (!chain) return null;
2888
3300
  const origin = this.resolveBinding(file2, chain.root);
@@ -2890,12 +3302,12 @@ var ModuleGraph = class {
2890
3302
  let current = this.topLevelInit(origin.file, origin.name);
2891
3303
  if (!current) return null;
2892
3304
  for (const key of chain.path) {
2893
- if (!t5.isObjectExpression(current)) return null;
3305
+ if (!t7.isObjectExpression(current)) return null;
2894
3306
  const prop = objectProperty(current, key);
2895
3307
  if (!prop) return null;
2896
- current = t5.isTSAsExpression(prop) ? prop.expression : prop;
3308
+ current = t7.isTSAsExpression(prop) ? prop.expression : prop;
2897
3309
  }
2898
- return t5.isStringLiteral(current) ? current.value : null;
3310
+ return t7.isStringLiteral(current) ? current.value : null;
2899
3311
  }
2900
3312
  /**
2901
3313
  * O ARQUIVO onde vive o componente de uma rota, ou `null`.
@@ -2906,24 +3318,24 @@ var ModuleGraph = class {
2906
3318
  * que é como o `pocketpal` monta todas as telas do Drawer).
2907
3319
  */
2908
3320
  componentFile(file2, node, hops = 0) {
2909
- if (!node || hops > MAX_HOPS) return null;
2910
- if (t5.isCallExpression(node)) {
3321
+ if (!node || hops > MAX_HOPS2) return null;
3322
+ if (t7.isCallExpression(node)) {
2911
3323
  for (const arg of node.arguments) {
2912
- if (t5.isIdentifier(arg) || t5.isMemberExpression(arg)) {
3324
+ if (t7.isIdentifier(arg) || t7.isMemberExpression(arg)) {
2913
3325
  const inner = this.componentFile(file2, arg, hops + 1);
2914
3326
  if (inner) return inner;
2915
3327
  }
2916
3328
  }
2917
3329
  return null;
2918
3330
  }
2919
- if (t5.isTSAsExpression(node)) return this.componentFile(file2, node.expression, hops + 1);
3331
+ if (t7.isTSAsExpression(node)) return this.componentFile(file2, node.expression, hops + 1);
2920
3332
  const chain = memberChain(node);
2921
3333
  if (!chain) return null;
2922
3334
  const origin = this.resolveBinding(file2, chain.root);
2923
3335
  if (!origin) return null;
2924
3336
  if (chain.path.length === 0) return origin.file;
2925
3337
  const init = this.topLevelInit(origin.file, origin.name);
2926
- if (init && t5.isObjectExpression(init)) {
3338
+ if (init && t7.isObjectExpression(init)) {
2927
3339
  const prop = objectProperty(init, chain.path[0]);
2928
3340
  if (prop) return this.componentFile(origin.file, prop, hops + 1);
2929
3341
  }
@@ -2946,7 +3358,7 @@ var ModuleGraph = class {
2946
3358
  const names = /* @__PURE__ */ new Set();
2947
3359
  const visit = (node) => {
2948
3360
  if (!node || typeof node !== "object") return;
2949
- if (t5.isJSXOpeningElement(node) && t5.isJSXIdentifier(node.name)) {
3361
+ if (t7.isJSXOpeningElement(node) && t7.isJSXIdentifier(node.name)) {
2950
3362
  const n = node.name.name;
2951
3363
  if (/^[A-Z]/.test(n)) names.add(n);
2952
3364
  }
@@ -2971,24 +3383,24 @@ var ModuleGraph = class {
2971
3383
  function memberChain(node) {
2972
3384
  const chain = [];
2973
3385
  let current = node;
2974
- while (t5.isMemberExpression(current)) {
3386
+ while (t7.isMemberExpression(current)) {
2975
3387
  if (current.computed) {
2976
- if (!t5.isStringLiteral(current.property)) return null;
3388
+ if (!t7.isStringLiteral(current.property)) return null;
2977
3389
  chain.unshift(current.property.value);
2978
- } else if (t5.isIdentifier(current.property)) {
3390
+ } else if (t7.isIdentifier(current.property)) {
2979
3391
  chain.unshift(current.property.name);
2980
3392
  } else {
2981
3393
  return null;
2982
3394
  }
2983
3395
  current = current.object;
2984
3396
  }
2985
- return t5.isIdentifier(current) ? { root: current.name, path: chain } : null;
3397
+ return t7.isIdentifier(current) ? { root: current.name, path: chain } : null;
2986
3398
  }
2987
3399
  function objectProperty(obj, key) {
2988
3400
  for (const prop of obj.properties) {
2989
- if (!t5.isObjectProperty(prop)) continue;
2990
- const name = t5.isIdentifier(prop.key) ? prop.key.name : t5.isStringLiteral(prop.key) ? prop.key.value : null;
2991
- if (name === key && t5.isExpression(prop.value)) return prop.value;
3401
+ if (!t7.isObjectProperty(prop)) continue;
3402
+ const name = t7.isIdentifier(prop.key) ? prop.key.name : t7.isStringLiteral(prop.key) ? prop.key.value : null;
3403
+ if (name === key && t7.isExpression(prop.value)) return prop.value;
2992
3404
  }
2993
3405
  return null;
2994
3406
  }
@@ -3102,7 +3514,7 @@ function workspaceGlobs(dir) {
3102
3514
  }
3103
3515
  function expandWorkspaceGlobs(root, globs) {
3104
3516
  const out = [];
3105
- const add = (dir) => {
3517
+ const add2 = (dir) => {
3106
3518
  const pkgPath = import_node_path.default.join(dir, "package.json");
3107
3519
  if (!(0, import_node_fs.existsSync)(pkgPath)) return;
3108
3520
  try {
@@ -3111,9 +3523,9 @@ function expandWorkspaceGlobs(root, globs) {
3111
3523
  } catch {
3112
3524
  }
3113
3525
  };
3114
- for (const glob of globs) {
3115
- if (glob.endsWith("/*")) {
3116
- const parent = import_node_path.default.join(root, glob.slice(0, -2));
3526
+ for (const glob2 of globs) {
3527
+ if (glob2.endsWith("/*")) {
3528
+ const parent = import_node_path.default.join(root, glob2.slice(0, -2));
3117
3529
  let entries = [];
3118
3530
  try {
3119
3531
  entries = (0, import_node_fs.readdirSync)(parent);
@@ -3123,12 +3535,12 @@ function expandWorkspaceGlobs(root, globs) {
3123
3535
  for (const entry of entries) {
3124
3536
  const dir = import_node_path.default.join(parent, entry);
3125
3537
  try {
3126
- if ((0, import_node_fs.statSync)(dir).isDirectory()) add(dir);
3538
+ if ((0, import_node_fs.statSync)(dir).isDirectory()) add2(dir);
3127
3539
  } catch {
3128
3540
  }
3129
3541
  }
3130
- } else if (!glob.includes("*")) {
3131
- add(import_node_path.default.join(root, glob));
3542
+ } else if (!glob2.includes("*")) {
3543
+ add2(import_node_path.default.join(root, glob2));
3132
3544
  }
3133
3545
  }
3134
3546
  return out.sort((a, b) => b.name.length - a.name.length);
@@ -3249,19 +3661,19 @@ var NAVIGATOR_FACTORIES = {
3249
3661
  };
3250
3662
  var CUSTOM_FACTORY = /^create[A-Za-z0-9]*(Navigator|Stack|Tabs?|Drawer)$/;
3251
3663
  function unwrapStaticScreen(value) {
3252
- if (t6.isCallExpression(value)) {
3664
+ if (t8.isCallExpression(value)) {
3253
3665
  const arg = value.arguments[0];
3254
3666
  return arg ? unwrapStaticScreen(arg) : null;
3255
3667
  }
3256
- if (t6.isObjectExpression(value)) {
3668
+ if (t8.isObjectExpression(value)) {
3257
3669
  for (const prop of value.properties) {
3258
- if (!t6.isObjectProperty(prop)) continue;
3259
- const key = t6.isIdentifier(prop.key) ? prop.key.name : null;
3260
- if (key === "screen" && t6.isExpression(prop.value)) return prop.value;
3670
+ if (!t8.isObjectProperty(prop)) continue;
3671
+ const key = t8.isIdentifier(prop.key) ? prop.key.name : null;
3672
+ if (key === "screen" && t8.isExpression(prop.value)) return prop.value;
3261
3673
  }
3262
3674
  return null;
3263
3675
  }
3264
- return t6.isExpression(value) ? value : null;
3676
+ return t8.isExpression(value) ? value : null;
3265
3677
  }
3266
3678
  function inferNavigatorType(factoryName) {
3267
3679
  if (/drawer/i.test(factoryName)) return "drawer";
@@ -3452,24 +3864,24 @@ var NavigationAnalyzer = class {
3452
3864
  const ast = this.graph.parse(filePath);
3453
3865
  if (!ast) return [];
3454
3866
  const out = /* @__PURE__ */ new Map();
3455
- (0, import_traverse5.default)(ast, {
3867
+ (0, import_traverse6.default)(ast, {
3456
3868
  CallExpression: (nodePath) => {
3457
3869
  const callee = nodePath.node.callee;
3458
- if (!t6.isIdentifier(callee)) return;
3870
+ if (!t8.isIdentifier(callee)) return;
3459
3871
  const known = NAVIGATOR_FACTORIES[callee.name] ?? (CUSTOM_FACTORY.test(callee.name) ? inferNavigatorType(callee.name) : null);
3460
3872
  const type = known ?? inferNavigatorType(callee.name);
3461
3873
  const confident = known !== null;
3462
3874
  let up = nodePath.parentPath;
3463
3875
  for (let i = 0; i < 4 && up; i++) {
3464
- if (t6.isVariableDeclarator(up.node)) break;
3465
- if (!t6.isMemberExpression(up.node) && !t6.isCallExpression(up.node)) {
3876
+ if (t8.isVariableDeclarator(up.node)) break;
3877
+ if (!t8.isMemberExpression(up.node) && !t8.isCallExpression(up.node)) {
3466
3878
  up = null;
3467
3879
  break;
3468
3880
  }
3469
3881
  up = up.parentPath;
3470
3882
  }
3471
3883
  const declarator = up?.node;
3472
- if (!declarator || !t6.isVariableDeclarator(declarator) || !t6.isIdentifier(declarator.id)) {
3884
+ if (!declarator || !t8.isVariableDeclarator(declarator) || !t8.isIdentifier(declarator.id)) {
3473
3885
  return;
3474
3886
  }
3475
3887
  const name = declarator.id.name;
@@ -3499,15 +3911,15 @@ var NavigationAnalyzer = class {
3499
3911
  * e agrupar rotas não muda o que elas são.
3500
3912
  */
3501
3913
  parseStaticScreens(filePath, config, navigatorName, navigatorType, depth = 0) {
3502
- if (!config || !t6.isObjectExpression(config) || depth > 4) return [];
3914
+ if (!config || !t8.isObjectExpression(config) || depth > 4) return [];
3503
3915
  const out = [];
3504
3916
  for (const prop of config.properties) {
3505
- if (!t6.isObjectProperty(prop)) continue;
3506
- const key = t6.isIdentifier(prop.key) ? prop.key.name : t6.isStringLiteral(prop.key) ? prop.key.value : null;
3917
+ if (!t8.isObjectProperty(prop)) continue;
3918
+ const key = t8.isIdentifier(prop.key) ? prop.key.name : t8.isStringLiteral(prop.key) ? prop.key.value : null;
3507
3919
  if (!key) continue;
3508
- if (key === "groups" && t6.isObjectExpression(prop.value)) {
3920
+ if (key === "groups" && t8.isObjectExpression(prop.value)) {
3509
3921
  for (const group of prop.value.properties) {
3510
- if (!t6.isObjectProperty(group) || !t6.isExpression(group.value)) continue;
3922
+ if (!t8.isObjectProperty(group) || !t8.isExpression(group.value)) continue;
3511
3923
  out.push(
3512
3924
  ...this.parseStaticScreens(
3513
3925
  filePath,
@@ -3520,10 +3932,10 @@ var NavigationAnalyzer = class {
3520
3932
  }
3521
3933
  continue;
3522
3934
  }
3523
- if (key !== "screens" || !t6.isObjectExpression(prop.value)) continue;
3935
+ if (key !== "screens" || !t8.isObjectExpression(prop.value)) continue;
3524
3936
  for (const entry of prop.value.properties) {
3525
- if (!t6.isObjectProperty(entry)) continue;
3526
- const routeName = t6.isIdentifier(entry.key) ? entry.key.name : t6.isStringLiteral(entry.key) ? entry.key.value : null;
3937
+ if (!t8.isObjectProperty(entry)) continue;
3938
+ const routeName = t8.isIdentifier(entry.key) ? entry.key.name : t8.isStringLiteral(entry.key) ? entry.key.value : null;
3527
3939
  if (!routeName) continue;
3528
3940
  const componentExpr = unwrapStaticScreen(entry.value);
3529
3941
  const componentFile = componentExpr ? this.graph.componentFile(filePath, componentExpr) : null;
@@ -3613,15 +4025,15 @@ var NavigationAnalyzer = class {
3613
4025
  const ast = this.graph.parse(filePath);
3614
4026
  if (!ast) return [];
3615
4027
  const found = /* @__PURE__ */ new Map();
3616
- (0, import_traverse5.default)(ast, {
4028
+ (0, import_traverse6.default)(ast, {
3617
4029
  JSXElement: (nodePath) => {
3618
4030
  const { node } = nodePath;
3619
4031
  const openingElement = node.openingElement;
3620
- if (!t6.isJSXMemberExpression(openingElement.name) || !t6.isJSXIdentifier(openingElement.name.object)) {
4032
+ if (!t8.isJSXMemberExpression(openingElement.name) || !t8.isJSXIdentifier(openingElement.name.object)) {
3621
4033
  return;
3622
4034
  }
3623
4035
  const objectName = openingElement.name.object.name;
3624
- const propertyName = t6.isJSXIdentifier(openingElement.name.property) ? openingElement.name.property.name : null;
4036
+ const propertyName = t8.isJSXIdentifier(openingElement.name.property) ? openingElement.name.property.name : null;
3625
4037
  if (propertyName !== "Navigator") return;
3626
4038
  const decl = this.resolveNavigator(filePath, objectName, declarations);
3627
4039
  if (!decl) return;
@@ -3631,9 +4043,9 @@ var NavigationAnalyzer = class {
3631
4043
  screens: []
3632
4044
  };
3633
4045
  const initialRouteAttr = openingElement.attributes.find(
3634
- (attr) => t6.isJSXAttribute(attr) && t6.isJSXIdentifier(attr.name) && attr.name.name === "initialRouteName"
4046
+ (attr) => t8.isJSXAttribute(attr) && t8.isJSXIdentifier(attr.name) && attr.name.name === "initialRouteName"
3635
4047
  );
3636
- if (t6.isJSXAttribute(initialRouteAttr)) {
4048
+ if (t8.isJSXAttribute(initialRouteAttr)) {
3637
4049
  const initial = this.attributeString(filePath, initialRouteAttr);
3638
4050
  if (initial) navigator.initialRouteName = initial;
3639
4051
  }
@@ -3685,15 +4097,15 @@ var NavigationAnalyzer = class {
3685
4097
  if (!ast) return [];
3686
4098
  const byNavigator = /* @__PURE__ */ new Map();
3687
4099
  const resolved = /* @__PURE__ */ new Map();
3688
- (0, import_traverse5.default)(ast, {
4100
+ (0, import_traverse6.default)(ast, {
3689
4101
  JSXElement: (nodePath) => {
3690
4102
  const name = nodePath.node.openingElement.name;
3691
- if (!t6.isJSXMemberExpression(name) || !t6.isJSXIdentifier(name.object)) return;
3692
- if (!t6.isJSXIdentifier(name.property) || name.property.name !== "Screen") return;
4103
+ if (!t8.isJSXMemberExpression(name) || !t8.isJSXIdentifier(name.object)) return;
4104
+ if (!t8.isJSXIdentifier(name.property) || name.property.name !== "Screen") return;
3693
4105
  const insideNavigator = nodePath.findParent((parent) => {
3694
4106
  if (!parent.isJSXElement()) return false;
3695
4107
  const parentName = parent.node.openingElement.name;
3696
- return t6.isJSXMemberExpression(parentName) && t6.isJSXIdentifier(parentName.property) && parentName.property.name === "Navigator";
4108
+ return t8.isJSXMemberExpression(parentName) && t8.isJSXIdentifier(parentName.property) && parentName.property.name === "Navigator";
3697
4109
  });
3698
4110
  if (insideNavigator) return;
3699
4111
  const local = name.object.name;
@@ -3732,9 +4144,9 @@ var NavigationAnalyzer = class {
3732
4144
  const binding = nodePath.scope.getBinding(localName);
3733
4145
  if (!binding || binding.kind !== "param") return null;
3734
4146
  const param = binding.path.node;
3735
- if (!t6.isIdentifier(param) || !t6.isTSTypeAnnotation(param.typeAnnotation)) return null;
4147
+ if (!t8.isIdentifier(param) || !t8.isTSTypeAnnotation(param.typeAnnotation)) return null;
3736
4148
  const annotation = param.typeAnnotation.typeAnnotation;
3737
- if (!t6.isTSTypeQuery(annotation) || !t6.isIdentifier(annotation.exprName)) return null;
4149
+ if (!t8.isTSTypeQuery(annotation) || !t8.isIdentifier(annotation.exprName)) return null;
3738
4150
  return this.resolveNavigator(filePath, annotation.exprName.name, declarations);
3739
4151
  }
3740
4152
  /**
@@ -3755,8 +4167,8 @@ var NavigationAnalyzer = class {
3755
4167
  /** O valor string de um atributo JSX, resolvendo constante importada. */
3756
4168
  attributeString(filePath, attr) {
3757
4169
  const value = attr.value;
3758
- if (t6.isStringLiteral(value)) return value.value;
3759
- if (t6.isJSXExpressionContainer(value) && t6.isExpression(value.expression)) {
4170
+ if (t8.isStringLiteral(value)) return value.value;
4171
+ if (t8.isJSXExpressionContainer(value) && t8.isExpression(value.expression)) {
3760
4172
  return this.graph.stringConstant(filePath, value.expression);
3761
4173
  }
3762
4174
  return null;
@@ -3770,9 +4182,9 @@ var NavigationAnalyzer = class {
3770
4182
  // `never`. It is a question about the member name, not about the node
3771
4183
  // kind.
3772
4184
  isNavigatorMember(node, navigatorVarName, member) {
3773
- if (!t6.isJSXElement(node)) return false;
4185
+ if (!t8.isJSXElement(node)) return false;
3774
4186
  const name = node.openingElement.name;
3775
- return t6.isJSXMemberExpression(name) && t6.isJSXIdentifier(name.object) && name.object.name === navigatorVarName && t6.isJSXIdentifier(name.property) && name.property.name === member;
4187
+ return t8.isJSXMemberExpression(name) && t8.isJSXIdentifier(name.object) && name.object.name === navigatorVarName && t8.isJSXIdentifier(name.property) && name.property.name === member;
3776
4188
  }
3777
4189
  /**
3778
4190
  * Flatten a navigator's JSX children into the `<X.Screen>` elements they
@@ -3803,37 +4215,37 @@ var NavigationAnalyzer = class {
3803
4215
  found.push(...this.collectScreenElements(group.children, navigatorVarName, depth + 1));
3804
4216
  return;
3805
4217
  }
3806
- if (t6.isJSXElement(node)) {
4218
+ if (t8.isJSXElement(node)) {
3807
4219
  const name = node.openingElement.name;
3808
- const isForeignNavigator = t6.isJSXMemberExpression(name) && t6.isJSXIdentifier(name.property) && name.property.name === "Navigator";
4220
+ const isForeignNavigator = t8.isJSXMemberExpression(name) && t8.isJSXIdentifier(name.property) && name.property.name === "Navigator";
3809
4221
  if (isForeignNavigator) return;
3810
4222
  found.push(...this.collectScreenElements(node.children, navigatorVarName, depth + 1));
3811
4223
  return;
3812
4224
  }
3813
- if (t6.isJSXFragment(node)) {
4225
+ if (t8.isJSXFragment(node)) {
3814
4226
  found.push(...this.collectScreenElements(node.children, navigatorVarName, depth + 1));
3815
4227
  return;
3816
4228
  }
3817
- if (t6.isJSXExpressionContainer(node)) {
4229
+ if (t8.isJSXExpressionContainer(node)) {
3818
4230
  visit(node.expression);
3819
4231
  return;
3820
4232
  }
3821
- if (t6.isConditionalExpression(node)) {
4233
+ if (t8.isConditionalExpression(node)) {
3822
4234
  visit(node.consequent);
3823
4235
  visit(node.alternate);
3824
4236
  return;
3825
4237
  }
3826
- if (t6.isLogicalExpression(node)) {
4238
+ if (t8.isLogicalExpression(node)) {
3827
4239
  visit(node.left);
3828
4240
  visit(node.right);
3829
4241
  return;
3830
4242
  }
3831
- if (t6.isCallExpression(node)) {
4243
+ if (t8.isCallExpression(node)) {
3832
4244
  for (const arg of node.arguments) {
3833
- if (t6.isArrowFunctionExpression(arg) || t6.isFunctionExpression(arg)) {
3834
- if (t6.isBlockStatement(arg.body)) {
4245
+ if (t8.isArrowFunctionExpression(arg) || t8.isFunctionExpression(arg)) {
4246
+ if (t8.isBlockStatement(arg.body)) {
3835
4247
  for (const stmt of arg.body.body) {
3836
- if (t6.isReturnStatement(stmt)) visit(stmt.argument);
4248
+ if (t8.isReturnStatement(stmt)) visit(stmt.argument);
3837
4249
  }
3838
4250
  } else {
3839
4251
  visit(arg.body);
@@ -3842,11 +4254,11 @@ var NavigationAnalyzer = class {
3842
4254
  }
3843
4255
  return;
3844
4256
  }
3845
- if (t6.isArrayExpression(node)) {
4257
+ if (t8.isArrayExpression(node)) {
3846
4258
  for (const el of node.elements) visit(el);
3847
4259
  return;
3848
4260
  }
3849
- if (t6.isTSAsExpression(node) || t6.isTSNonNullExpression(node)) {
4261
+ if (t8.isTSAsExpression(node) || t8.isTSNonNullExpression(node)) {
3850
4262
  visit(node.expression);
3851
4263
  }
3852
4264
  };
@@ -3876,17 +4288,17 @@ var NavigationAnalyzer = class {
3876
4288
  parseScreenElement(filePath, element, navigatorName, navigatorType) {
3877
4289
  const attrs = element.openingElement.attributes;
3878
4290
  const nameAttr = attrs.find(
3879
- (a) => t6.isJSXAttribute(a) && t6.isJSXIdentifier(a.name) && a.name.name === "name"
4291
+ (a) => t8.isJSXAttribute(a) && t8.isJSXIdentifier(a.name) && a.name.name === "name"
3880
4292
  );
3881
- const screenName = t6.isJSXAttribute(nameAttr) ? this.attributeString(filePath, nameAttr) : null;
4293
+ const screenName = t8.isJSXAttribute(nameAttr) ? this.attributeString(filePath, nameAttr) : null;
3882
4294
  if (!screenName) return null;
3883
4295
  const componentAttr = attrs.find(
3884
- (a) => t6.isJSXAttribute(a) && t6.isJSXIdentifier(a.name) && a.name.name === "component"
4296
+ (a) => t8.isJSXAttribute(a) && t8.isJSXIdentifier(a.name) && a.name.name === "component"
3885
4297
  );
3886
4298
  let componentFile = null;
3887
- if (t6.isJSXAttribute(componentAttr) && t6.isJSXExpressionContainer(componentAttr.value)) {
4299
+ if (t8.isJSXAttribute(componentAttr) && t8.isJSXExpressionContainer(componentAttr.value)) {
3888
4300
  const expr = componentAttr.value.expression;
3889
- if (t6.isExpression(expr)) componentFile = this.graph.componentFile(filePath, expr);
4301
+ if (t8.isExpression(expr)) componentFile = this.graph.componentFile(filePath, expr);
3890
4302
  }
3891
4303
  if (componentFile) this.routeTargets.set(screenName, componentFile);
3892
4304
  return {
@@ -3899,9 +4311,9 @@ var NavigationAnalyzer = class {
3899
4311
  /** Extract string attribute value from JSX attributes */
3900
4312
  extractAttributeValue(attributes, attrName) {
3901
4313
  const attr = attributes.find(
3902
- (a) => t6.isJSXAttribute(a) && t6.isJSXIdentifier(a.name) && a.name.name === attrName
4314
+ (a) => t8.isJSXAttribute(a) && t8.isJSXIdentifier(a.name) && a.name.name === attrName
3903
4315
  );
3904
- if (t6.isJSXAttribute(attr) && t6.isStringLiteral(attr.value)) {
4316
+ if (t8.isJSXAttribute(attr) && t8.isStringLiteral(attr.value)) {
3905
4317
  return attr.value.value;
3906
4318
  }
3907
4319
  return null;
@@ -3918,7 +4330,7 @@ var NavigationAnalyzer = class {
3918
4330
  ...this.config.parserPlugins || []
3919
4331
  ]
3920
4332
  });
3921
- (0, import_traverse5.default)(ast, {
4333
+ (0, import_traverse6.default)(ast, {
3922
4334
  TSTypeAliasDeclaration: (nodePath) => {
3923
4335
  const { node } = nodePath;
3924
4336
  const typeName = node.id.name;
@@ -3991,7 +4403,7 @@ var NavigationAnalyzer = class {
3991
4403
  if (type.type === "TSUndefinedKeyword") return "undefined";
3992
4404
  if (type.type === "TSNullKeyword") return "null";
3993
4405
  if (type.type === "TSUnionType") {
3994
- return type.types.map((t16) => this.typeToString(t16)).join(" | ");
4406
+ return type.types.map((t18) => this.typeToString(t18)).join(" | ");
3995
4407
  }
3996
4408
  if (type.type === "TSTypeLiteral") {
3997
4409
  return "object";
@@ -4012,7 +4424,7 @@ var NavigationAnalyzer = class {
4012
4424
  /** Attach parsed type params to navigator screens */
4013
4425
  attachParamsToNavigators(navigators, types) {
4014
4426
  for (const navigator of navigators) {
4015
- const matchingType = types.find((t16) => t16.type === navigator.type);
4427
+ const matchingType = types.find((t18) => t18.type === navigator.type);
4016
4428
  if (matchingType) {
4017
4429
  for (const screen of navigator.screens) {
4018
4430
  const screenParams = matchingType.paramEntries.get(screen.name);
@@ -4091,8 +4503,8 @@ var NavigationAnalyzer = class {
4091
4503
  // src/analyzers/ComponentAnalyzer.ts
4092
4504
  var import_fs5 = require("fs");
4093
4505
  var parser3 = __toESM(require("@babel/parser"));
4094
- var import_traverse6 = __toESM(require("@babel/traverse"));
4095
- var t7 = __toESM(require("@babel/types"));
4506
+ var import_traverse7 = __toESM(require("@babel/traverse"));
4507
+ var t9 = __toESM(require("@babel/types"));
4096
4508
  var ComponentAnalyzer = class {
4097
4509
  config;
4098
4510
  constructor(config) {
@@ -4107,7 +4519,7 @@ var ComponentAnalyzer = class {
4107
4519
  plugins: ["jsx", "typescript", ["decorators", { decoratorsBeforeExport: true }]]
4108
4520
  });
4109
4521
  const components = [];
4110
- (0, import_traverse6.default)(ast, {
4522
+ (0, import_traverse7.default)(ast, {
4111
4523
  JSXElement: (path13) => {
4112
4524
  const component = this.extractComponentFromJSXElement(path13.node);
4113
4525
  if (component) {
@@ -4138,19 +4550,19 @@ var ComponentAnalyzer = class {
4138
4550
  };
4139
4551
  }
4140
4552
  getElementName(openingElement) {
4141
- if (t7.isJSXIdentifier(openingElement.name)) {
4553
+ if (t9.isJSXIdentifier(openingElement.name)) {
4142
4554
  return openingElement.name.name;
4143
4555
  }
4144
- if (t7.isJSXMemberExpression(openingElement.name)) {
4556
+ if (t9.isJSXMemberExpression(openingElement.name)) {
4145
4557
  const parts = [];
4146
4558
  let current = openingElement.name;
4147
- while (t7.isJSXMemberExpression(current)) {
4148
- if (t7.isJSXIdentifier(current.property)) {
4559
+ while (t9.isJSXMemberExpression(current)) {
4560
+ if (t9.isJSXIdentifier(current.property)) {
4149
4561
  parts.unshift(current.property.name);
4150
4562
  }
4151
4563
  current = current.object;
4152
4564
  }
4153
- if (t7.isJSXIdentifier(current)) {
4565
+ if (t9.isJSXIdentifier(current)) {
4154
4566
  parts.unshift(current.name);
4155
4567
  }
4156
4568
  return parts.join(".");
@@ -4173,13 +4585,13 @@ var ComponentAnalyzer = class {
4173
4585
  extractProps(openingElement) {
4174
4586
  const props = {};
4175
4587
  for (const attr of openingElement.attributes) {
4176
- if (t7.isJSXAttribute(attr) && t7.isJSXIdentifier(attr.name)) {
4588
+ if (t9.isJSXAttribute(attr) && t9.isJSXIdentifier(attr.name)) {
4177
4589
  const propName = attr.name.name;
4178
4590
  if (attr.value === null) {
4179
4591
  props[propName] = "true";
4180
- } else if (t7.isStringLiteral(attr.value)) {
4592
+ } else if (t9.isStringLiteral(attr.value)) {
4181
4593
  props[propName] = attr.value.value;
4182
- } else if (t7.isJSXExpressionContainer(attr.value) && t7.isStringLiteral(attr.value.expression)) {
4594
+ } else if (t9.isJSXExpressionContainer(attr.value) && t9.isStringLiteral(attr.value.expression)) {
4183
4595
  props[propName] = attr.value.expression.value;
4184
4596
  }
4185
4597
  }
@@ -4189,12 +4601,12 @@ var ComponentAnalyzer = class {
4189
4601
  extractAccessibilityProps(openingElement) {
4190
4602
  const result = {};
4191
4603
  for (const attr of openingElement.attributes) {
4192
- if (t7.isJSXAttribute(attr) && t7.isJSXIdentifier(attr.name)) {
4604
+ if (t9.isJSXAttribute(attr) && t9.isJSXIdentifier(attr.name)) {
4193
4605
  const propName = attr.name.name;
4194
4606
  if ((propName === "testID" || propName === "accessibilityLabel") && attr.value) {
4195
- if (t7.isStringLiteral(attr.value)) {
4607
+ if (t9.isStringLiteral(attr.value)) {
4196
4608
  result[propName] = attr.value.value;
4197
- } else if (t7.isJSXExpressionContainer(attr.value) && t7.isStringLiteral(attr.value.expression)) {
4609
+ } else if (t9.isJSXExpressionContainer(attr.value) && t9.isStringLiteral(attr.value.expression)) {
4198
4610
  result[propName] = attr.value.expression.value;
4199
4611
  }
4200
4612
  }
@@ -4206,7 +4618,7 @@ var ComponentAnalyzer = class {
4206
4618
  if (depth >= maxDepth) return [];
4207
4619
  const extracted = [];
4208
4620
  for (const child of children) {
4209
- if (t7.isJSXElement(child)) {
4621
+ if (t9.isJSXElement(child)) {
4210
4622
  const component = this.extractComponentFromJSXElement(child);
4211
4623
  if (component) {
4212
4624
  extracted.push(component);
@@ -4220,8 +4632,8 @@ var ComponentAnalyzer = class {
4220
4632
  // src/analyzers/FormAnalyzer.ts
4221
4633
  var import_fs6 = require("fs");
4222
4634
  var parser4 = __toESM(require("@babel/parser"));
4223
- var import_traverse7 = __toESM(require("@babel/traverse"));
4224
- var t8 = __toESM(require("@babel/types"));
4635
+ var import_traverse8 = __toESM(require("@babel/traverse"));
4636
+ var t10 = __toESM(require("@babel/types"));
4225
4637
  var path5 = __toESM(require("path"));
4226
4638
  var FormAnalyzer = class {
4227
4639
  config;
@@ -4242,12 +4654,12 @@ var FormAnalyzer = class {
4242
4654
  this.stateVariables.clear();
4243
4655
  this.inputElements = [];
4244
4656
  this.submitButtons = [];
4245
- (0, import_traverse7.default)(ast, {
4657
+ (0, import_traverse8.default)(ast, {
4246
4658
  CallExpression: (path13) => {
4247
4659
  this.extractStateVariables(path13.node);
4248
4660
  }
4249
4661
  });
4250
- (0, import_traverse7.default)(ast, {
4662
+ (0, import_traverse8.default)(ast, {
4251
4663
  JSXElement: (path13) => {
4252
4664
  this.extractFormElements(path13.node);
4253
4665
  }
@@ -4260,7 +4672,7 @@ var FormAnalyzer = class {
4260
4672
  }
4261
4673
  }
4262
4674
  extractStateVariables(node) {
4263
- if (t8.isIdentifier(node.callee) && node.callee.name === "useState" && node.arguments.length > 0) {
4675
+ if (t10.isIdentifier(node.callee) && node.callee.name === "useState" && node.arguments.length > 0) {
4264
4676
  return;
4265
4677
  }
4266
4678
  }
@@ -4281,28 +4693,28 @@ var FormAnalyzer = class {
4281
4693
  extractInputInfo(openingElement) {
4282
4694
  const info2 = { varName: "" };
4283
4695
  for (const attr of openingElement.attributes) {
4284
- if (t8.isJSXAttribute(attr) && t8.isJSXIdentifier(attr.name)) {
4696
+ if (t10.isJSXAttribute(attr) && t10.isJSXIdentifier(attr.name)) {
4285
4697
  const propName = attr.name.name;
4286
- const propValue = this.extractAttributeValue(attr.value);
4698
+ const propValue2 = this.extractAttributeValue(attr.value);
4287
4699
  switch (propName) {
4288
4700
  case "label":
4289
- info2.label = propValue;
4701
+ info2.label = propValue2;
4290
4702
  break;
4291
4703
  case "placeholder":
4292
- info2.placeholder = propValue;
4704
+ info2.placeholder = propValue2;
4293
4705
  break;
4294
4706
  case "keyboardType":
4295
- info2.keyboardType = propValue;
4707
+ info2.keyboardType = propValue2;
4296
4708
  break;
4297
4709
  case "testID":
4298
- info2.testID = propValue;
4710
+ info2.testID = propValue2;
4299
4711
  break;
4300
4712
  case "appilotsId":
4301
- info2.appilotsId = propValue;
4302
- if (propValue) info2.varName = propValue;
4713
+ info2.appilotsId = propValue2;
4714
+ if (propValue2) info2.varName = propValue2;
4303
4715
  break;
4304
4716
  case "value":
4305
- if (attr.value && t8.isJSXExpressionContainer(attr.value) && t8.isIdentifier(attr.value.expression)) {
4717
+ if (attr.value && t10.isJSXExpressionContainer(attr.value) && t10.isIdentifier(attr.value.expression)) {
4306
4718
  info2.varName = attr.value.expression.name;
4307
4719
  }
4308
4720
  break;
@@ -4314,16 +4726,16 @@ var FormAnalyzer = class {
4314
4726
  extractButtonInfo(openingElement) {
4315
4727
  const info2 = {};
4316
4728
  for (const attr of openingElement.attributes) {
4317
- if (t8.isJSXAttribute(attr) && t8.isJSXIdentifier(attr.name)) {
4729
+ if (t10.isJSXAttribute(attr) && t10.isJSXIdentifier(attr.name)) {
4318
4730
  const propName = attr.name.name;
4319
4731
  if (propName === "title" || propName === "label") {
4320
4732
  info2.label = this.extractAttributeValue(attr.value);
4321
4733
  }
4322
4734
  if (propName === "onPress") {
4323
- if (attr.value && t8.isJSXExpressionContainer(attr.value)) {
4324
- if (t8.isIdentifier(attr.value.expression)) {
4735
+ if (attr.value && t10.isJSXExpressionContainer(attr.value)) {
4736
+ if (t10.isIdentifier(attr.value.expression)) {
4325
4737
  info2.handler = attr.value.expression.name;
4326
- } else if (t8.isArrowFunctionExpression(attr.value.expression) || t8.isFunctionExpression(attr.value.expression)) {
4738
+ } else if (t10.isArrowFunctionExpression(attr.value.expression) || t10.isFunctionExpression(attr.value.expression)) {
4327
4739
  info2.handler = "anonymous";
4328
4740
  }
4329
4741
  }
@@ -4334,21 +4746,21 @@ var FormAnalyzer = class {
4334
4746
  }
4335
4747
  extractAttributeValue(value) {
4336
4748
  if (value === null) return void 0;
4337
- if (t8.isStringLiteral(value)) return value.value;
4338
- if (t8.isJSXExpressionContainer(value) && t8.isStringLiteral(value.expression)) {
4749
+ if (t10.isStringLiteral(value)) return value.value;
4750
+ if (t10.isJSXExpressionContainer(value) && t10.isStringLiteral(value.expression)) {
4339
4751
  return value.expression.value;
4340
4752
  }
4341
4753
  return void 0;
4342
4754
  }
4343
4755
  getElementName(openingElement) {
4344
- if (t8.isJSXIdentifier(openingElement.name)) {
4756
+ if (t10.isJSXIdentifier(openingElement.name)) {
4345
4757
  return openingElement.name.name;
4346
4758
  }
4347
4759
  return null;
4348
4760
  }
4349
4761
  extractValidationRules(ast) {
4350
4762
  const rules = {};
4351
- (0, import_traverse7.default)(ast, {
4763
+ (0, import_traverse8.default)(ast, {
4352
4764
  IfStatement: (path13) => {
4353
4765
  const test = path13.node.test;
4354
4766
  const rule = this.extractRuleFromCondition(test);
@@ -4365,36 +4777,36 @@ var FormAnalyzer = class {
4365
4777
  extractRuleFromCondition(test) {
4366
4778
  let fieldName = "";
4367
4779
  let description = "";
4368
- if (t8.isUnaryExpression(test) && test.operator === "!") {
4369
- if (t8.isCallExpression(test.argument)) {
4780
+ if (t10.isUnaryExpression(test) && test.operator === "!") {
4781
+ if (t10.isCallExpression(test.argument)) {
4370
4782
  const callExpr = test.argument;
4371
- if (t8.isMemberExpression(callExpr.callee)) {
4783
+ if (t10.isMemberExpression(callExpr.callee)) {
4372
4784
  const memberExpr = callExpr.callee;
4373
- if (t8.isIdentifier(memberExpr.object)) {
4785
+ if (t10.isIdentifier(memberExpr.object)) {
4374
4786
  fieldName = memberExpr.object.name;
4375
4787
  description = `${fieldName} is required`;
4376
4788
  }
4377
4789
  }
4378
- } else if (t8.isIdentifier(test.argument)) {
4790
+ } else if (t10.isIdentifier(test.argument)) {
4379
4791
  fieldName = test.argument.name;
4380
4792
  description = `${fieldName} is required`;
4381
4793
  }
4382
4794
  }
4383
- if (t8.isBinaryExpression(test) && (test.operator === "<" || test.operator === "<=")) {
4384
- if (t8.isMemberExpression(test.left)) {
4795
+ if (t10.isBinaryExpression(test) && (test.operator === "<" || test.operator === "<=")) {
4796
+ if (t10.isMemberExpression(test.left)) {
4385
4797
  const memberExpr = test.left;
4386
- if (t8.isIdentifier(memberExpr.object)) {
4798
+ if (t10.isIdentifier(memberExpr.object)) {
4387
4799
  fieldName = memberExpr.object.name;
4388
- if (t8.isNumericLiteral(test.right)) {
4800
+ if (t10.isNumericLiteral(test.right)) {
4389
4801
  description = `${fieldName} must be at least ${test.right.value} characters`;
4390
4802
  }
4391
4803
  }
4392
4804
  }
4393
4805
  }
4394
- if (t8.isUnaryExpression(test) && test.operator === "!") {
4395
- if (t8.isCallExpression(test.argument) && t8.isMemberExpression(test.argument.callee)) {
4396
- const methodName = t8.isIdentifier(test.argument.callee.property) ? test.argument.callee.property.name : null;
4397
- if (methodName === "includes" && t8.isIdentifier(test.argument.callee.object)) {
4806
+ if (t10.isUnaryExpression(test) && test.operator === "!") {
4807
+ if (t10.isCallExpression(test.argument) && t10.isMemberExpression(test.argument.callee)) {
4808
+ const methodName = t10.isIdentifier(test.argument.callee.property) ? test.argument.callee.property.name : null;
4809
+ if (methodName === "includes" && t10.isIdentifier(test.argument.callee.object)) {
4398
4810
  fieldName = test.argument.callee.object.name;
4399
4811
  description = `${fieldName} format is invalid`;
4400
4812
  }
@@ -4502,7 +4914,7 @@ async function composeAffordances(options) {
4502
4914
  const exclusive = children.filter((c) => (fanIn.get(c) ?? 0) <= MAX_FAN_IN);
4503
4915
  if (exclusive.length === 0) continue;
4504
4916
  const actionIds = new Set(screen.actions.map((a) => a.id));
4505
- const targetIds = new Set((screen.targets ?? []).map((t16) => t16.id));
4917
+ const targetIds = new Set((screen.targets ?? []).map((t18) => t18.id));
4506
4918
  const formIds = new Set(screen.forms.map((f) => f.id));
4507
4919
  let gained = false;
4508
4920
  for (const file2 of exclusive) {
@@ -4644,6 +5056,7 @@ var ReactNativePlatformAnalyzer = class {
4644
5056
  });
4645
5057
  return {
4646
5058
  screens: enrichedScreens,
5059
+ controlEvidenceFiles: screenAnalyzer.controlEvidenceFiles,
4647
5060
  navigation,
4648
5061
  analyzedFiles: screenFiles.length,
4649
5062
  ...screenAnalyzer.screensFilteredOut > 0 ? { screensFilteredOut: screenAnalyzer.screensFilteredOut } : {},
@@ -4732,8 +5145,8 @@ var GenericPlatformAnalyzer = class {
4732
5145
  // src/analyzers/web/WebScreenAnalyzer.ts
4733
5146
  var import_promises2 = __toESM(require("fs/promises"));
4734
5147
  var import_path5 = __toESM(require("path"));
4735
- var import_traverse9 = __toESM(require("@babel/traverse"));
4736
- var t11 = __toESM(require("@babel/types"));
5148
+ var import_traverse10 = __toESM(require("@babel/traverse"));
5149
+ var t13 = __toESM(require("@babel/types"));
4737
5150
 
4738
5151
  // src/ast/jsx/web/classify.ts
4739
5152
  var VIEW_TAGS = /* @__PURE__ */ new Set([
@@ -4849,29 +5262,29 @@ function classifyWebJsxComponent(name, element) {
4849
5262
  }
4850
5263
 
4851
5264
  // src/ast/jsx/names.ts
4852
- var t9 = __toESM(require("@babel/types"));
5265
+ var t11 = __toESM(require("@babel/types"));
4853
5266
  function getJsxElementName(openingElement) {
4854
5267
  return getJsxName(openingElement.name);
4855
5268
  }
4856
5269
  function getJsxName(name) {
4857
- if (t9.isJSXIdentifier(name)) return name.name;
4858
- if (t9.isJSXNamespacedName(name)) return `${name.namespace.name}:${name.name.name}`;
4859
- if (t9.isJSXMemberExpression(name)) {
5270
+ if (t11.isJSXIdentifier(name)) return name.name;
5271
+ if (t11.isJSXNamespacedName(name)) return `${name.namespace.name}:${name.name.name}`;
5272
+ if (t11.isJSXMemberExpression(name)) {
4860
5273
  const objectName = getJsxName(name.object);
4861
- const propertyName = t9.isJSXIdentifier(name.property) ? name.property.name : null;
5274
+ const propertyName = t11.isJSXIdentifier(name.property) ? name.property.name : null;
4862
5275
  return objectName && propertyName ? `${objectName}.${propertyName}` : null;
4863
5276
  }
4864
5277
  return null;
4865
5278
  }
4866
5279
 
4867
5280
  // src/ast/navigation/web-calls.ts
4868
- var import_traverse8 = __toESM(require("@babel/traverse"));
4869
- var t10 = __toESM(require("@babel/types"));
5281
+ var import_traverse9 = __toESM(require("@babel/traverse"));
5282
+ var t12 = __toESM(require("@babel/types"));
4870
5283
  var ROUTERISH_OBJECTS = /^(router|history|navigation)$/;
4871
5284
  function staticRoutePath(node) {
4872
5285
  if (!node) return void 0;
4873
- if (t10.isStringLiteral(node)) return node.value;
4874
- if (t10.isTemplateLiteral(node)) {
5286
+ if (t12.isStringLiteral(node)) return node.value;
5287
+ if (t12.isTemplateLiteral(node)) {
4875
5288
  let path13 = "";
4876
5289
  node.quasis.forEach((quasi, index) => {
4877
5290
  path13 += quasi.value.cooked ?? quasi.value.raw;
@@ -4883,15 +5296,15 @@ function staticRoutePath(node) {
4883
5296
  return void 0;
4884
5297
  }
4885
5298
  function paramNameOf(expr) {
4886
- if (t10.isIdentifier(expr)) return expr.name;
4887
- if (t10.isMemberExpression(expr) && t10.isIdentifier(expr.property)) return expr.property.name;
5299
+ if (t12.isIdentifier(expr)) return expr.name;
5300
+ if (t12.isMemberExpression(expr) && t12.isIdentifier(expr.property)) return expr.property.name;
4888
5301
  return "param";
4889
5302
  }
4890
5303
  function extractWebNavigationCalls(ast) {
4891
5304
  const calls = [];
4892
5305
  const inspect = (node) => {
4893
- if (t10.isCallExpression(node)) {
4894
- if (t10.isIdentifier(node.callee) && node.callee.name === "navigate") {
5306
+ if (t12.isCallExpression(node)) {
5307
+ if (t12.isIdentifier(node.callee) && node.callee.name === "navigate") {
4895
5308
  const first = node.arguments[0];
4896
5309
  const targetPath = staticRoutePath(first);
4897
5310
  if (targetPath !== void 0) {
@@ -4899,12 +5312,12 @@ function extractWebNavigationCalls(ast) {
4899
5312
  method: hasReplaceOption(node.arguments[1]) ? "replace" : "navigate",
4900
5313
  targetPath
4901
5314
  });
4902
- } else if (t10.isNumericLiteral(first) || t10.isUnaryExpression(first) && first.operator === "-") {
5315
+ } else if (t12.isNumericLiteral(first) || t12.isUnaryExpression(first) && first.operator === "-") {
4903
5316
  calls.push({ method: "goBack" });
4904
5317
  }
4905
5318
  return;
4906
5319
  }
4907
- if (t10.isMemberExpression(node.callee) && t10.isIdentifier(node.callee.object) && ROUTERISH_OBJECTS.test(node.callee.object.name) && t10.isIdentifier(node.callee.property)) {
5320
+ if (t12.isMemberExpression(node.callee) && t12.isIdentifier(node.callee.object) && ROUTERISH_OBJECTS.test(node.callee.object.name) && t12.isIdentifier(node.callee.property)) {
4908
5321
  const method = node.callee.property.name;
4909
5322
  const targetPath = staticRoutePath(node.arguments[0]);
4910
5323
  if ((method === "push" || method === "navigate") && targetPath !== void 0) {
@@ -4917,25 +5330,25 @@ function extractWebNavigationCalls(ast) {
4917
5330
  }
4918
5331
  return;
4919
5332
  }
4920
- if (t10.isAssignmentExpression(node) && t10.isMemberExpression(node.left) && t10.isIdentifier(node.left.property) && node.left.property.name === "href" && isLocationExpression(node.left.object) && t10.isStringLiteral(node.right) && node.right.value.startsWith("/")) {
5333
+ if (t12.isAssignmentExpression(node) && t12.isMemberExpression(node.left) && t12.isIdentifier(node.left.property) && node.left.property.name === "href" && isLocationExpression(node.left.object) && t12.isStringLiteral(node.right) && node.right.value.startsWith("/")) {
4921
5334
  calls.push({ method: "navigate", targetPath: node.right.value });
4922
5335
  }
4923
5336
  };
4924
- (0, import_traverse8.default)(ast, {
4925
- noScope: !t10.isFile(ast),
5337
+ (0, import_traverse9.default)(ast, {
5338
+ noScope: !t12.isFile(ast),
4926
5339
  enter: (nodePath) => inspect(nodePath.node)
4927
5340
  });
4928
5341
  return calls;
4929
5342
  }
4930
5343
  function hasReplaceOption(arg) {
4931
- if (!arg || !t10.isObjectExpression(arg)) return false;
5344
+ if (!arg || !t12.isObjectExpression(arg)) return false;
4932
5345
  return arg.properties.some(
4933
- (prop) => t10.isObjectProperty(prop) && t10.isIdentifier(prop.key) && prop.key.name === "replace" && t10.isBooleanLiteral(prop.value) && prop.value.value === true
5346
+ (prop) => t12.isObjectProperty(prop) && t12.isIdentifier(prop.key) && prop.key.name === "replace" && t12.isBooleanLiteral(prop.value) && prop.value.value === true
4934
5347
  );
4935
5348
  }
4936
5349
  function isLocationExpression(node) {
4937
- if (t10.isIdentifier(node)) return node.name === "location";
4938
- return t10.isMemberExpression(node) && t10.isIdentifier(node.object) && node.object.name === "window" && t10.isIdentifier(node.property) && node.property.name === "location";
5350
+ if (t12.isIdentifier(node)) return node.name === "location";
5351
+ return t12.isMemberExpression(node) && t12.isIdentifier(node.object) && node.object.name === "window" && t12.isIdentifier(node.property) && node.property.name === "location";
4939
5352
  }
4940
5353
 
4941
5354
  // src/analyzers/web/WebScreenAnalyzer.ts
@@ -5043,7 +5456,7 @@ var WebScreenAnalyzer = class {
5043
5456
  // ── registerScreen ────────────────────────────────────────────────
5044
5457
  detectRegisterScreenCall(ast) {
5045
5458
  let found = false;
5046
- (0, import_traverse9.default)(ast, {
5459
+ (0, import_traverse10.default)(ast, {
5047
5460
  CallExpression: (nodePath) => {
5048
5461
  if (found) return;
5049
5462
  if (isRegisterScreenCallee(nodePath.node.callee)) {
@@ -5056,11 +5469,11 @@ var WebScreenAnalyzer = class {
5056
5469
  }
5057
5470
  extractRegisterScreenMetadata(ast) {
5058
5471
  let plain = null;
5059
- (0, import_traverse9.default)(ast, {
5472
+ (0, import_traverse10.default)(ast, {
5060
5473
  CallExpression: (nodePath) => {
5061
5474
  if (!isRegisterScreenCallee(nodePath.node.callee)) return;
5062
5475
  const arg = nodePath.node.arguments[0];
5063
- if (t11.isObjectExpression(arg)) {
5476
+ if (t13.isObjectExpression(arg)) {
5064
5477
  plain = literalToPlain(arg);
5065
5478
  }
5066
5479
  }
@@ -5104,23 +5517,23 @@ var WebScreenAnalyzer = class {
5104
5517
  extractComponentName(ast) {
5105
5518
  let defaultName = "";
5106
5519
  let firstExported = "";
5107
- (0, import_traverse9.default)(ast, {
5520
+ (0, import_traverse10.default)(ast, {
5108
5521
  ExportDefaultDeclaration: (nodePath) => {
5109
5522
  const declaration = nodePath.node.declaration;
5110
- if (t11.isFunctionDeclaration(declaration) && declaration.id?.name) {
5523
+ if (t13.isFunctionDeclaration(declaration) && declaration.id?.name) {
5111
5524
  defaultName = declaration.id.name;
5112
- } else if (t11.isIdentifier(declaration)) {
5525
+ } else if (t13.isIdentifier(declaration)) {
5113
5526
  defaultName = declaration.name;
5114
5527
  }
5115
5528
  },
5116
5529
  ExportNamedDeclaration: (nodePath) => {
5117
5530
  if (firstExported) return;
5118
5531
  const declaration = nodePath.node.declaration;
5119
- if (t11.isFunctionDeclaration(declaration) && declaration.id && /^[A-Z]/.test(declaration.id.name)) {
5532
+ if (t13.isFunctionDeclaration(declaration) && declaration.id && /^[A-Z]/.test(declaration.id.name)) {
5120
5533
  firstExported = declaration.id.name;
5121
- } else if (t11.isVariableDeclaration(declaration)) {
5534
+ } else if (t13.isVariableDeclaration(declaration)) {
5122
5535
  for (const declarator of declaration.declarations) {
5123
- if (t11.isIdentifier(declarator.id) && /^[A-Z]/.test(declarator.id.name) && (t11.isArrowFunctionExpression(declarator.init) || t11.isFunctionExpression(declarator.init))) {
5536
+ if (t13.isIdentifier(declarator.id) && /^[A-Z]/.test(declarator.id.name) && (t13.isArrowFunctionExpression(declarator.init) || t13.isFunctionExpression(declarator.init))) {
5124
5537
  firstExported = declarator.id.name;
5125
5538
  break;
5126
5539
  }
@@ -5133,7 +5546,7 @@ var WebScreenAnalyzer = class {
5133
5546
  extractComponents(ast) {
5134
5547
  const components = [];
5135
5548
  const seen = /* @__PURE__ */ new Set();
5136
- (0, import_traverse9.default)(ast, {
5549
+ (0, import_traverse10.default)(ast, {
5137
5550
  JSXOpeningElement: (nodePath) => {
5138
5551
  const element = nodePath.node;
5139
5552
  const name = getJsxElementName(element);
@@ -5154,7 +5567,7 @@ var WebScreenAnalyzer = class {
5154
5567
  // ── <label htmlFor> association ───────────────────────────────────
5155
5568
  collectHtmlForLabels(ast) {
5156
5569
  const labels = /* @__PURE__ */ new Map();
5157
- (0, import_traverse9.default)(ast, {
5570
+ (0, import_traverse10.default)(ast, {
5158
5571
  JSXElement: (nodePath) => {
5159
5572
  const element = nodePath.node;
5160
5573
  if (getJsxElementName(element.openingElement) !== "label") return;
@@ -5197,7 +5610,7 @@ var WebScreenAnalyzer = class {
5197
5610
  formBuckets.set(formElement, bucket);
5198
5611
  return bucket;
5199
5612
  };
5200
- (0, import_traverse9.default)(ast, {
5613
+ (0, import_traverse10.default)(ast, {
5201
5614
  JSXElement: (nodePath) => {
5202
5615
  const element = nodePath.node;
5203
5616
  const name = getJsxElementName(element.openingElement);
@@ -5214,7 +5627,7 @@ var WebScreenAnalyzer = class {
5214
5627
  if (!bucket.fields.has(field.name)) bucket.fields.set(field.name, field);
5215
5628
  }
5216
5629
  });
5217
- (0, import_traverse9.default)(ast, {
5630
+ (0, import_traverse10.default)(ast, {
5218
5631
  JSXElement: (nodePath) => {
5219
5632
  const element = nodePath.node;
5220
5633
  const name = getJsxElementName(element.openingElement);
@@ -5292,15 +5705,15 @@ var WebScreenAnalyzer = class {
5292
5705
  });
5293
5706
  }
5294
5707
  for (const attr of opening.attributes) {
5295
- if (!t11.isJSXAttribute(attr) || !t11.isJSXIdentifier(attr.name)) continue;
5708
+ if (!t13.isJSXAttribute(attr) || !t13.isJSXIdentifier(attr.name)) continue;
5296
5709
  const attrName = attr.name.name;
5297
5710
  if (attrName === "required") {
5298
5711
  if (attr.value === null) field.required = true;
5299
- else if (t11.isJSXExpressionContainer(attr.value) && t11.isBooleanLiteral(attr.value.expression)) {
5712
+ else if (t13.isJSXExpressionContainer(attr.value) && t13.isBooleanLiteral(attr.value.expression)) {
5300
5713
  field.required = attr.value.expression.value;
5301
5714
  }
5302
5715
  }
5303
- if ((attrName === "value" || attrName === "checked") && attr.value && t11.isJSXExpressionContainer(attr.value) && t11.isIdentifier(attr.value.expression)) {
5716
+ if ((attrName === "value" || attrName === "checked") && attr.value && t13.isJSXExpressionContainer(attr.value) && t13.isIdentifier(attr.value.expression)) {
5304
5717
  field.valueBinding = attr.value.expression.name;
5305
5718
  if (!field.name) field.name = attr.value.expression.name;
5306
5719
  }
@@ -5350,7 +5763,7 @@ var WebScreenAnalyzer = class {
5350
5763
  extractSelectOptions(selectElement) {
5351
5764
  const options = [];
5352
5765
  for (const child of selectElement.children) {
5353
- if (!t11.isJSXElement(child)) continue;
5766
+ if (!t13.isJSXElement(child)) continue;
5354
5767
  if (getJsxElementName(child.openingElement) !== "option") continue;
5355
5768
  const value = getStringAttr(child.openingElement, "value");
5356
5769
  const label = jsxTextContent(child) || value || "";
@@ -5392,7 +5805,7 @@ var WebScreenAnalyzer = class {
5392
5805
  const actionLabels = new Map(
5393
5806
  actions.filter((a) => a.label).map((a) => [normalizeLabel(a.label), a])
5394
5807
  );
5395
- (0, import_traverse9.default)(ast, {
5808
+ (0, import_traverse10.default)(ast, {
5396
5809
  JSXElement: (nodePath) => {
5397
5810
  const element = nodePath.node;
5398
5811
  const name = getJsxElementName(element.openingElement);
@@ -5461,14 +5874,14 @@ var WebScreenAnalyzer = class {
5461
5874
  }
5462
5875
  let handlerName;
5463
5876
  const onClickAttr = opening.attributes.find(
5464
- (attr) => t11.isJSXAttribute(attr) && t11.isJSXIdentifier(attr.name) && attr.name.name === "onClick"
5877
+ (attr) => t13.isJSXAttribute(attr) && t13.isJSXIdentifier(attr.name) && attr.name.name === "onClick"
5465
5878
  );
5466
- if (onClickAttr?.value && t11.isJSXExpressionContainer(onClickAttr.value)) {
5879
+ if (onClickAttr?.value && t13.isJSXExpressionContainer(onClickAttr.value)) {
5467
5880
  const expr = onClickAttr.value.expression;
5468
- if (t11.isIdentifier(expr)) {
5881
+ if (t13.isIdentifier(expr)) {
5469
5882
  handlerName = expr.name;
5470
5883
  action.handler = expr.name;
5471
- } else if (!t11.isJSXEmptyExpression(expr)) {
5884
+ } else if (!t13.isJSXEmptyExpression(expr)) {
5472
5885
  const inlineNavCalls = extractWebNavigationCalls(expr);
5473
5886
  const inlineNav = inlineNavCalls.find((call) => call.targetPath);
5474
5887
  if (inlineNav?.targetPath) {
@@ -5607,12 +6020,12 @@ var WebScreenAnalyzer = class {
5607
6020
  }
5608
6021
  handlerNameFromAttr(opening, attrName) {
5609
6022
  const attr = opening.attributes.find(
5610
- (candidate) => t11.isJSXAttribute(candidate) && t11.isJSXIdentifier(candidate.name) && candidate.name.name === attrName
6023
+ (candidate) => t13.isJSXAttribute(candidate) && t13.isJSXIdentifier(candidate.name) && candidate.name.name === attrName
5611
6024
  );
5612
- if (!attr?.value || !t11.isJSXExpressionContainer(attr.value)) return void 0;
6025
+ if (!attr?.value || !t13.isJSXExpressionContainer(attr.value)) return void 0;
5613
6026
  const expr = attr.value.expression;
5614
- if (t11.isIdentifier(expr)) return expr.name;
5615
- if (t11.isArrowFunctionExpression(expr) || t11.isFunctionExpression(expr)) {
6027
+ if (t13.isIdentifier(expr)) return expr.name;
6028
+ if (t13.isArrowFunctionExpression(expr) || t13.isFunctionExpression(expr)) {
5616
6029
  return firstCalledFunctionName(expr) ?? "anonymous";
5617
6030
  }
5618
6031
  return void 0;
@@ -5623,7 +6036,7 @@ var WebScreenAnalyzer = class {
5623
6036
  for (const call of extractWebNavigationCalls(ast)) {
5624
6037
  if (call.targetPath && call.targetPath.startsWith("/")) targets.add(call.targetPath);
5625
6038
  }
5626
- (0, import_traverse9.default)(ast, {
6039
+ (0, import_traverse10.default)(ast, {
5627
6040
  JSXOpeningElement: (nodePath) => {
5628
6041
  const element = nodePath.node;
5629
6042
  const name = getJsxElementName(element);
@@ -5643,14 +6056,14 @@ var WebScreenAnalyzer = class {
5643
6056
  extractCollections(ast) {
5644
6057
  const collections = [];
5645
6058
  const seen = /* @__PURE__ */ new Set();
5646
- (0, import_traverse9.default)(ast, {
6059
+ (0, import_traverse10.default)(ast, {
5647
6060
  JSXExpressionContainer: (nodePath) => {
5648
6061
  const expr = nodePath.node.expression;
5649
- if (!t11.isCallExpression(expr) || !t11.isMemberExpression(expr.callee) || !t11.isIdentifier(expr.callee.object) || !t11.isIdentifier(expr.callee.property) || expr.callee.property.name !== "map") {
6062
+ if (!t13.isCallExpression(expr) || !t13.isMemberExpression(expr.callee) || !t13.isIdentifier(expr.callee.object) || !t13.isIdentifier(expr.callee.property) || expr.callee.property.name !== "map") {
5650
6063
  return;
5651
6064
  }
5652
6065
  const callback = expr.arguments[0];
5653
- if (!t11.isArrowFunctionExpression(callback) && !t11.isFunctionExpression(callback)) return;
6066
+ if (!t13.isArrowFunctionExpression(callback) && !t13.isFunctionExpression(callback)) return;
5654
6067
  const enclosing = nodePath.findParent(
5655
6068
  (p) => p.isJSXElement()
5656
6069
  );
@@ -5685,22 +6098,22 @@ var WebScreenAnalyzer = class {
5685
6098
  }
5686
6099
  };
5687
6100
  function isRegisterScreenCallee(callee) {
5688
- return t11.isIdentifier(callee) && callee.name === "registerScreen" || t11.isMemberExpression(callee) && t11.isIdentifier(callee.property) && callee.property.name === "registerScreen";
6101
+ return t13.isIdentifier(callee) && callee.name === "registerScreen" || t13.isMemberExpression(callee) && t13.isIdentifier(callee.property) && callee.property.name === "registerScreen";
5689
6102
  }
5690
6103
  function literalToPlain(node) {
5691
- if (t11.isStringLiteral(node) || t11.isNumericLiteral(node) || t11.isBooleanLiteral(node)) {
6104
+ if (t13.isStringLiteral(node) || t13.isNumericLiteral(node) || t13.isBooleanLiteral(node)) {
5692
6105
  return node.value;
5693
6106
  }
5694
- if (t11.isNullLiteral(node)) return null;
5695
- if (t11.isArrayExpression(node)) {
5696
- return node.elements.filter((el) => el !== null && t11.isExpression(el)).map((el) => literalToPlain(el)).filter((value) => value !== void 0);
6107
+ if (t13.isNullLiteral(node)) return null;
6108
+ if (t13.isArrayExpression(node)) {
6109
+ return node.elements.filter((el) => el !== null && t13.isExpression(el)).map((el) => literalToPlain(el)).filter((value) => value !== void 0);
5697
6110
  }
5698
- if (t11.isObjectExpression(node)) {
6111
+ if (t13.isObjectExpression(node)) {
5699
6112
  const out = {};
5700
6113
  for (const prop of node.properties) {
5701
- if (!t11.isObjectProperty(prop)) continue;
5702
- const key = t11.isIdentifier(prop.key) ? prop.key.name : t11.isStringLiteral(prop.key) ? prop.key.value : void 0;
5703
- if (!key || !t11.isExpression(prop.value)) continue;
6114
+ if (!t13.isObjectProperty(prop)) continue;
6115
+ const key = t13.isIdentifier(prop.key) ? prop.key.name : t13.isStringLiteral(prop.key) ? prop.key.value : void 0;
6116
+ if (!key || !t13.isExpression(prop.value)) continue;
5704
6117
  const value = literalToPlain(prop.value);
5705
6118
  if (value !== void 0) out[key] = value;
5706
6119
  }
@@ -5712,12 +6125,12 @@ function jsxTextContent(element) {
5712
6125
  const parts = [];
5713
6126
  const walk = (children) => {
5714
6127
  for (const child of children) {
5715
- if (t11.isJSXText(child)) {
6128
+ if (t13.isJSXText(child)) {
5716
6129
  const trimmed = child.value.replace(/\s+/g, " ").trim();
5717
6130
  if (trimmed) parts.push(trimmed);
5718
- } else if (t11.isJSXExpressionContainer(child) && t11.isStringLiteral(child.expression)) {
6131
+ } else if (t13.isJSXExpressionContainer(child) && t13.isStringLiteral(child.expression)) {
5719
6132
  parts.push(child.expression.value);
5720
- } else if (t11.isJSXElement(child)) {
6133
+ } else if (t13.isJSXElement(child)) {
5721
6134
  walk(child.children);
5722
6135
  }
5723
6136
  }
@@ -5727,26 +6140,26 @@ function jsxTextContent(element) {
5727
6140
  return text.length > 0 ? text : void 0;
5728
6141
  }
5729
6142
  function firstCalledFunctionName(node) {
5730
- if (t11.isIdentifier(node)) return node.name;
5731
- if (t11.isArrowFunctionExpression(node) || t11.isFunctionExpression(node)) {
6143
+ if (t13.isIdentifier(node)) return node.name;
6144
+ if (t13.isArrowFunctionExpression(node) || t13.isFunctionExpression(node)) {
5732
6145
  return firstCalledFunctionName(node.body);
5733
6146
  }
5734
- if (t11.isBlockStatement(node)) {
6147
+ if (t13.isBlockStatement(node)) {
5735
6148
  for (const statement of node.body) {
5736
6149
  const handler = firstCalledFunctionName(statement);
5737
6150
  if (handler) return handler;
5738
6151
  }
5739
6152
  return void 0;
5740
6153
  }
5741
- if (t11.isExpressionStatement(node)) return firstCalledFunctionName(node.expression);
5742
- if (t11.isReturnStatement(node)) {
6154
+ if (t13.isExpressionStatement(node)) return firstCalledFunctionName(node.expression);
6155
+ if (t13.isReturnStatement(node)) {
5743
6156
  return node.argument ? firstCalledFunctionName(node.argument) : void 0;
5744
6157
  }
5745
- if (t11.isAwaitExpression(node) || t11.isUnaryExpression(node)) {
6158
+ if (t13.isAwaitExpression(node) || t13.isUnaryExpression(node)) {
5746
6159
  return firstCalledFunctionName(node.argument);
5747
6160
  }
5748
- if (t11.isCallExpression(node)) {
5749
- if (t11.isIdentifier(node.callee) && !/^(navigate|confirm|alert)$/.test(node.callee.name)) {
6161
+ if (t13.isCallExpression(node)) {
6162
+ if (t13.isIdentifier(node.callee) && !/^(navigate|confirm|alert)$/.test(node.callee.name)) {
5750
6163
  return node.callee.name;
5751
6164
  }
5752
6165
  return void 0;
@@ -5755,14 +6168,14 @@ function firstCalledFunctionName(node) {
5755
6168
  }
5756
6169
  function containsWindowConfirm(body) {
5757
6170
  let found = false;
5758
- (0, import_traverse9.default)(
6171
+ (0, import_traverse10.default)(
5759
6172
  body,
5760
6173
  {
5761
6174
  noScope: true,
5762
6175
  CallExpression: (nodePath) => {
5763
6176
  const callee = nodePath.node.callee;
5764
- if (t11.isIdentifier(callee) && callee.name === "confirm") found = true;
5765
- if (t11.isMemberExpression(callee) && t11.isIdentifier(callee.object) && callee.object.name === "window" && t11.isIdentifier(callee.property) && callee.property.name === "confirm") {
6177
+ if (t13.isIdentifier(callee) && callee.name === "confirm") found = true;
6178
+ if (t13.isMemberExpression(callee) && t13.isIdentifier(callee.object) && callee.object.name === "window" && t13.isIdentifier(callee.property) && callee.property.name === "confirm") {
5766
6179
  found = true;
5767
6180
  }
5768
6181
  }
@@ -5777,9 +6190,9 @@ function routePathAttr(opening, attrName) {
5777
6190
  const literal = getStringAttr(opening, attrName);
5778
6191
  if (literal) return literal;
5779
6192
  const attr = opening.attributes.find(
5780
- (candidate) => t11.isJSXAttribute(candidate) && t11.isJSXIdentifier(candidate.name) && candidate.name.name === attrName
6193
+ (candidate) => t13.isJSXAttribute(candidate) && t13.isJSXIdentifier(candidate.name) && candidate.name.name === attrName
5781
6194
  );
5782
- if (!attr?.value || !t11.isJSXExpressionContainer(attr.value)) return void 0;
6195
+ if (!attr?.value || !t13.isJSXExpressionContainer(attr.value)) return void 0;
5783
6196
  return staticRoutePath(attr.value.expression);
5784
6197
  }
5785
6198
  function slugify(label) {
@@ -5794,10 +6207,10 @@ function isWeakInferredFieldName(name) {
5794
6207
  function collectionItemNames(callback) {
5795
6208
  const names = /* @__PURE__ */ new Set(["item"]);
5796
6209
  const firstParam = callback.params[0];
5797
- if (t11.isIdentifier(firstParam)) names.add(firstParam.name);
5798
- if (t11.isObjectPattern(firstParam)) {
6210
+ if (t13.isIdentifier(firstParam)) names.add(firstParam.name);
6211
+ if (t13.isObjectPattern(firstParam)) {
5799
6212
  for (const prop of firstParam.properties) {
5800
- if (t11.isObjectProperty(prop) && t11.isIdentifier(prop.key) && t11.isIdentifier(prop.value)) {
6213
+ if (t13.isObjectProperty(prop) && t13.isIdentifier(prop.key) && t13.isIdentifier(prop.value)) {
5801
6214
  names.add(prop.value.name);
5802
6215
  }
5803
6216
  }
@@ -5807,13 +6220,13 @@ function collectionItemNames(callback) {
5807
6220
  function collectionDisplayFields(callback, itemNames) {
5808
6221
  const fields = /* @__PURE__ */ new Set();
5809
6222
  if (!callback.body) return [];
5810
- (0, import_traverse9.default)(
6223
+ (0, import_traverse10.default)(
5811
6224
  callback.body,
5812
6225
  {
5813
6226
  noScope: true,
5814
6227
  MemberExpression: (nodePath) => {
5815
6228
  const node = nodePath.node;
5816
- if (t11.isIdentifier(node.object) && itemNames.has(node.object.name) && t11.isIdentifier(node.property)) {
6229
+ if (t13.isIdentifier(node.object) && itemNames.has(node.object.name) && t13.isIdentifier(node.property)) {
5817
6230
  fields.add(node.property.name);
5818
6231
  }
5819
6232
  }
@@ -5824,16 +6237,16 @@ function collectionDisplayFields(callback, itemNames) {
5824
6237
  function collectionKeyField(callback, itemNames) {
5825
6238
  let keyField;
5826
6239
  if (!callback.body) return void 0;
5827
- (0, import_traverse9.default)(
6240
+ (0, import_traverse10.default)(
5828
6241
  callback.body,
5829
6242
  {
5830
6243
  noScope: true,
5831
6244
  JSXAttribute: (nodePath) => {
5832
6245
  const attr = nodePath.node;
5833
- if (!t11.isJSXIdentifier(attr.name) || attr.name.name !== "key") return;
5834
- if (!attr.value || !t11.isJSXExpressionContainer(attr.value)) return;
6246
+ if (!t13.isJSXIdentifier(attr.name) || attr.name.name !== "key") return;
6247
+ if (!attr.value || !t13.isJSXExpressionContainer(attr.value)) return;
5835
6248
  const expr = attr.value.expression;
5836
- if (t11.isMemberExpression(expr) && t11.isIdentifier(expr.object) && itemNames.has(expr.object.name) && t11.isIdentifier(expr.property)) {
6249
+ if (t13.isMemberExpression(expr) && t13.isIdentifier(expr.object) && itemNames.has(expr.object.name) && t13.isIdentifier(expr.property)) {
5837
6250
  keyField = keyField ?? expr.property.name;
5838
6251
  }
5839
6252
  }
@@ -5856,18 +6269,18 @@ function callbackReturnsTag(callback, tags) {
5856
6269
  let found = false;
5857
6270
  const inspect = (node) => {
5858
6271
  if (!node || found) return;
5859
- if (t11.isJSXElement(node)) {
6272
+ if (t13.isJSXElement(node)) {
5860
6273
  const name = getJsxElementName(node.openingElement);
5861
6274
  if (name && tags.has(name)) found = true;
5862
6275
  return;
5863
6276
  }
5864
- if (t11.isBlockStatement(node)) {
6277
+ if (t13.isBlockStatement(node)) {
5865
6278
  for (const statement of node.body) {
5866
- if (t11.isReturnStatement(statement)) inspect(statement.argument);
6279
+ if (t13.isReturnStatement(statement)) inspect(statement.argument);
5867
6280
  }
5868
6281
  }
5869
- if (t11.isParenthesizedExpression(node)) inspect(node.expression);
5870
- if (t11.isConditionalExpression(node)) {
6282
+ if (t13.isParenthesizedExpression(node)) inspect(node.expression);
6283
+ if (t13.isConditionalExpression(node)) {
5871
6284
  inspect(node.consequent);
5872
6285
  inspect(node.alternate);
5873
6286
  }
@@ -5894,8 +6307,8 @@ function inferIdentityFields(keyField, displayFields) {
5894
6307
  // src/analyzers/web/WebNavigationAnalyzer.ts
5895
6308
  var import_fs7 = require("fs");
5896
6309
  var import_path6 = __toESM(require("path"));
5897
- var import_traverse10 = __toESM(require("@babel/traverse"));
5898
- var t12 = __toESM(require("@babel/types"));
6310
+ var import_traverse11 = __toESM(require("@babel/traverse"));
6311
+ var t14 = __toESM(require("@babel/types"));
5899
6312
  var WEB_NAVIGATOR_TYPE = "route";
5900
6313
  var WebNavigationAnalyzer = class {
5901
6314
  config;
@@ -5955,7 +6368,7 @@ var WebNavigationAnalyzer = class {
5955
6368
  const name = getJsxElementName(opening);
5956
6369
  if (name !== "Route") {
5957
6370
  for (const child of element.children) {
5958
- if (t12.isJSXElement(child)) visitRoute(child, parentPath);
6371
+ if (t14.isJSXElement(child)) visitRoute(child, parentPath);
5959
6372
  }
5960
6373
  return;
5961
6374
  }
@@ -5964,16 +6377,16 @@ var WebNavigationAnalyzer = class {
5964
6377
  const fullPath = this.joinPaths(parentPath, segment, isIndex);
5965
6378
  const componentName = this.componentNameFromElementAttr(opening) ?? void 0;
5966
6379
  const isLeaf = !element.children.some(
5967
- (child) => t12.isJSXElement(child) && getJsxElementName(child.openingElement) === "Route"
6380
+ (child) => t14.isJSXElement(child) && getJsxElementName(child.openingElement) === "Route"
5968
6381
  );
5969
6382
  if ((segment || isIndex) && (componentName || isLeaf)) {
5970
6383
  routes.push(this.buildRoute(fullPath, componentName, isIndex, !isLeaf));
5971
6384
  }
5972
6385
  for (const child of element.children) {
5973
- if (t12.isJSXElement(child)) visitRoute(child, fullPath);
6386
+ if (t14.isJSXElement(child)) visitRoute(child, fullPath);
5974
6387
  }
5975
6388
  };
5976
- (0, import_traverse10.default)(ast, {
6389
+ (0, import_traverse11.default)(ast, {
5977
6390
  JSXElement: (nodePath) => {
5978
6391
  const name = getJsxElementName(nodePath.node.openingElement);
5979
6392
  if (name !== "Routes" && name !== "Route") return;
@@ -5992,13 +6405,13 @@ var WebNavigationAnalyzer = class {
5992
6405
  /** `element={<VehicleList/>}` or `Component={VehicleList}`. */
5993
6406
  componentNameFromElementAttr(opening) {
5994
6407
  for (const attr of opening.attributes) {
5995
- if (!t12.isJSXAttribute(attr) || !t12.isJSXIdentifier(attr.name)) continue;
5996
- if (attr.name.name === "element" && t12.isJSXExpressionContainer(attr.value)) {
6408
+ if (!t14.isJSXAttribute(attr) || !t14.isJSXIdentifier(attr.name)) continue;
6409
+ if (attr.name.name === "element" && t14.isJSXExpressionContainer(attr.value)) {
5997
6410
  const expr = attr.value.expression;
5998
- if (t12.isJSXElement(expr)) return getJsxElementName(expr.openingElement);
6411
+ if (t14.isJSXElement(expr)) return getJsxElementName(expr.openingElement);
5999
6412
  }
6000
- if (attr.name.name === "Component" && t12.isJSXExpressionContainer(attr.value)) {
6001
- if (t12.isIdentifier(attr.value.expression)) return attr.value.expression.name;
6413
+ if (attr.name.name === "Component" && t14.isJSXExpressionContainer(attr.value)) {
6414
+ if (t14.isIdentifier(attr.value.expression)) return attr.value.expression.name;
6002
6415
  }
6003
6416
  }
6004
6417
  return null;
@@ -6012,12 +6425,12 @@ var WebNavigationAnalyzer = class {
6012
6425
  "createMemoryRouter",
6013
6426
  "useRoutes"
6014
6427
  ]);
6015
- (0, import_traverse10.default)(ast, {
6428
+ (0, import_traverse11.default)(ast, {
6016
6429
  CallExpression: (nodePath) => {
6017
6430
  const callee = nodePath.node.callee;
6018
- if (!t12.isIdentifier(callee) || !ROUTER_FACTORIES.has(callee.name)) return;
6431
+ if (!t14.isIdentifier(callee) || !ROUTER_FACTORIES.has(callee.name)) return;
6019
6432
  const first = nodePath.node.arguments[0];
6020
- if (!t12.isArrayExpression(first)) return;
6433
+ if (!t14.isArrayExpression(first)) return;
6021
6434
  this.visitRouteObjects(first, "", routes);
6022
6435
  }
6023
6436
  });
@@ -6025,21 +6438,21 @@ var WebNavigationAnalyzer = class {
6025
6438
  }
6026
6439
  visitRouteObjects(arr, parentPath, out) {
6027
6440
  for (const element of arr.elements) {
6028
- if (!t12.isObjectExpression(element)) continue;
6441
+ if (!t14.isObjectExpression(element)) continue;
6029
6442
  let segment;
6030
6443
  let isIndex = false;
6031
6444
  let componentName;
6032
6445
  let children;
6033
6446
  for (const prop of element.properties) {
6034
- if (!t12.isObjectProperty(prop) || !t12.isIdentifier(prop.key)) continue;
6447
+ if (!t14.isObjectProperty(prop) || !t14.isIdentifier(prop.key)) continue;
6035
6448
  const key = prop.key.name;
6036
- if (key === "path" && t12.isStringLiteral(prop.value)) segment = prop.value.value;
6037
- if (key === "index" && t12.isBooleanLiteral(prop.value)) isIndex = prop.value.value;
6038
- if (key === "element" && t12.isJSXElement(prop.value)) {
6449
+ if (key === "path" && t14.isStringLiteral(prop.value)) segment = prop.value.value;
6450
+ if (key === "index" && t14.isBooleanLiteral(prop.value)) isIndex = prop.value.value;
6451
+ if (key === "element" && t14.isJSXElement(prop.value)) {
6039
6452
  componentName = getJsxElementName(prop.value.openingElement) ?? void 0;
6040
6453
  }
6041
- if (key === "Component" && t12.isIdentifier(prop.value)) componentName = prop.value.name;
6042
- if (key === "children" && t12.isArrayExpression(prop.value)) children = prop.value;
6454
+ if (key === "Component" && t14.isIdentifier(prop.value)) componentName = prop.value.name;
6455
+ if (key === "children" && t14.isArrayExpression(prop.value)) children = prop.value;
6043
6456
  }
6044
6457
  const fullPath = this.joinPaths(parentPath, segment, isIndex);
6045
6458
  if ((segment !== void 0 || isIndex) && (componentName || !children)) {
@@ -6200,23 +6613,23 @@ var ReactWebPlatformAnalyzer = class {
6200
6613
  }
6201
6614
  /** Replace route-path references with screen names where the route table resolves them. */
6202
6615
  resolveRoutePaths(screen, routes) {
6203
- const resolve2 = (target) => {
6616
+ const resolve3 = (target) => {
6204
6617
  if (!target || !target.startsWith("/")) return target;
6205
6618
  return resolvePathToScreen(routes, target) ?? target;
6206
6619
  };
6207
6620
  const navigationTargets = Array.from(
6208
6621
  new Set(
6209
- screen.navigationTargets.map((target) => resolve2(target)).filter((target) => target !== screen.name)
6622
+ screen.navigationTargets.map((target) => resolve3(target)).filter((target) => target !== screen.name)
6210
6623
  )
6211
6624
  ).sort();
6212
6625
  const actions = screen.actions.map((action) => {
6213
- const resolved = resolve2(action.targetScreen);
6626
+ const resolved = resolve3(action.targetScreen);
6214
6627
  return resolved === action.targetScreen ? action : { ...action, targetScreen: resolved };
6215
6628
  });
6216
6629
  const collections = screen.collections?.map((collection) => {
6217
6630
  const resolveRow = (row) => {
6218
6631
  if (!row?.targetScreen) return row;
6219
- const resolved = resolve2(row.targetScreen);
6632
+ const resolved = resolve3(row.targetScreen);
6220
6633
  if (resolved === row.targetScreen) return row;
6221
6634
  return {
6222
6635
  ...row,
@@ -6449,8 +6862,8 @@ var ZodParsedType = util.arrayToEnum([
6449
6862
  "set"
6450
6863
  ]);
6451
6864
  var getParsedType = (data) => {
6452
- const t16 = typeof data;
6453
- switch (t16) {
6865
+ const t18 = typeof data;
6866
+ switch (t18) {
6454
6867
  case "undefined":
6455
6868
  return ZodParsedType.undefined;
6456
6869
  case "string":
@@ -10296,7 +10709,25 @@ function isSafeImageUrl(value) {
10296
10709
  return SAFE_IMAGE_URL_RE.test(trimmed);
10297
10710
  }
10298
10711
 
10299
- // ../shared/dist/chunk-NMQNNPSJ.mjs
10712
+ // ../shared/dist/chunk-KUMPS6RH.mjs
10713
+ var SUPPORTED_APPILOTS_LOCALES = ["pt-BR", "en", "es", "fr"];
10714
+
10715
+ // ../shared/dist/chunk-2GTRKNPJ.mjs
10716
+ var symbols = external_exports.array(external_exports.string().max(240)).max(12);
10717
+ var controlEvidenceSchema = external_exports.object({
10718
+ version: external_exports.literal(1),
10719
+ siteId: external_exports.string().regex(/^[a-f0-9]{20}$/),
10720
+ component: external_exports.string().max(240),
10721
+ icons: symbols,
10722
+ handler: external_exports.string().max(240).optional(),
10723
+ calls: symbols,
10724
+ argumentBindings: symbols,
10725
+ conditions: symbols,
10726
+ nativeConfirmation: external_exports.object({
10727
+ title: external_exports.string().max(240).optional(),
10728
+ destructiveOption: external_exports.boolean()
10729
+ }).optional()
10730
+ });
10300
10731
  var locatorSourceSchema = external_exports.enum([
10301
10732
  "appilotsId",
10302
10733
  "testID",
@@ -10723,7 +11154,9 @@ var snapshotInputSchema = external_exports.object({
10723
11154
  inModal: external_exports.boolean().optional()
10724
11155
  }).passthrough();
10725
11156
  var snapshotButtonSchema = external_exports.object({
11157
+ controlEvidence: controlEvidenceSchema.optional(),
10726
11158
  id: boundedString(160).optional(),
11159
+ dispatchable: external_exports.boolean().optional(),
10727
11160
  provenance: identityProvenanceSchema.optional(),
10728
11161
  /**
10729
11162
  * False when the control is mounted but currently OUTSIDE the window —
@@ -10784,7 +11217,36 @@ var snapshotListSchema = external_exports.object({
10784
11217
  */
10785
11218
  source: boundedString(40).optional(),
10786
11219
  itemCount: external_exports.number().int().optional(),
11220
+ /**
11221
+ * Size of the whole collection when the app declared it, for a list
11222
+ * that is a WINDOW onto more data than it holds.
11223
+ *
11224
+ * `itemCount` is how many rows the list is rendering from and
11225
+ * `visibleItemCount` how many of those are mounted; neither can
11226
+ * express "there are 36 and you are looking at the first 20",
11227
+ * because a paginated list's `data` is the page. Absent means
11228
+ * unknown — never "same as itemCount".
11229
+ */
11230
+ totalItemCount: external_exports.number().int().optional(),
10787
11231
  visibleItemCount: external_exports.number().int().optional(),
11232
+ viewportItemCount: external_exports.number().int().nonnegative().optional(),
11233
+ exploration: external_exports.object({
11234
+ revision: external_exports.number().int().nonnegative(),
11235
+ observedItemCount: external_exports.number().int().min(0).max(5e3),
11236
+ observedRanges: external_exports.array(
11237
+ external_exports.object({
11238
+ start: external_exports.number().int().nonnegative(),
11239
+ end: external_exports.number().int().nonnegative()
11240
+ })
11241
+ ).max(32),
11242
+ rangesTruncated: external_exports.boolean(),
11243
+ coverage: external_exports.enum(["partial", "all-loaded"]),
11244
+ pagination: external_exports.enum(["possible", "not-declared"]),
11245
+ scrollSteps: external_exports.number().int().nonnegative(),
11246
+ remainingScrollSteps: external_exports.number().int().nonnegative(),
11247
+ consecutiveNoProgress: external_exports.number().int().nonnegative(),
11248
+ lastScroll: external_exports.enum(["moved", "no-progress", "boundary", "unverified"]).optional()
11249
+ }).optional(),
10788
11250
  refreshing: external_exports.boolean().optional(),
10789
11251
  empty: external_exports.boolean().optional(),
10790
11252
  label: boundedString(300).optional(),
@@ -10832,6 +11294,7 @@ var snapshotChoiceGroupSchema = external_exports.object({
10832
11294
  }).passthrough();
10833
11295
  var snapshotElementSchema = external_exports.object({
10834
11296
  id: boundedString(160).optional(),
11297
+ dispatchable: external_exports.boolean().optional(),
10835
11298
  role: boundedString(40).optional(),
10836
11299
  label: boundedString(300).optional(),
10837
11300
  texts: external_exports.array(boundedString(500)).max(50).optional(),
@@ -10894,6 +11357,8 @@ var agentSnapshotSchema = external_exports.object({
10894
11357
  loadingFinished: external_exports.boolean().optional(),
10895
11358
  textsAdded: external_exports.number().int().nonnegative().optional(),
10896
11359
  textsRemoved: external_exports.number().int().nonnegative().optional(),
11360
+ buttonsAddedIndices: external_exports.array(external_exports.number().int().nonnegative()).max(12).optional(),
11361
+ buttonsRemoved: external_exports.number().int().nonnegative().optional(),
10897
11362
  visibleRowsDelta: external_exports.number().int().optional(),
10898
11363
  totalRowsDelta: external_exports.number().int().optional(),
10899
11364
  fieldsNewlyFilled: external_exports.array(boundedString(160)).max(12).optional(),
@@ -10919,6 +11384,10 @@ var agentSnapshotSchema = external_exports.object({
10919
11384
  }).passthrough().optional()
10920
11385
  }).passthrough();
10921
11386
  var agentContextSchema = external_exports.object({
11387
+ missionProtocol: external_exports.literal(1).optional(),
11388
+ missionId: boundedString(160).optional(),
11389
+ /** Preferred supported device language, reported by the SDK independently of map/UI labels. */
11390
+ deviceLocale: external_exports.enum(SUPPORTED_APPILOTS_LOCALES).optional(),
10922
11391
  /**
10923
11392
  * Client platform this observation was captured on. Optional and
10924
11393
  * additive (see `clientPlatformSchema`) — absent means
@@ -11169,6 +11638,12 @@ var actionDiagnoseSchema = external_exports.object({
11169
11638
  requiresUserInput: external_exports.boolean().optional()
11170
11639
  });
11171
11640
  var actionResultSchema = external_exports.object({
11641
+ nativeConfirmation: external_exports.object({
11642
+ title: external_exports.string().max(300),
11643
+ message: external_exports.string().max(1e3).optional(),
11644
+ buttonLabel: external_exports.string().max(160).optional(),
11645
+ handlerCompleted: external_exports.boolean()
11646
+ }).optional(),
11172
11647
  actionId: external_exports.string(),
11173
11648
  type: external_exports.string(),
11174
11649
  success: external_exports.boolean(),
@@ -11296,7 +11771,7 @@ var updateProjectBudgetSchema = external_exports.object({
11296
11771
  /** null = remove webhook, undefined = leave unchanged. */
11297
11772
  budgetWebhookUrl: external_exports.string().url().nullable().optional()
11298
11773
  }).strict();
11299
- var localeSchema = external_exports.enum(["pt-BR", "en", "es"]);
11774
+ var localeSchema = external_exports.enum(SUPPORTED_APPILOTS_LOCALES);
11300
11775
  var hexColorSchema = external_exports.string().regex(/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/, {
11301
11776
  message: "Must be a hex color like #6366f1"
11302
11777
  });
@@ -12039,9 +12514,22 @@ var MCPGenerator = class _MCPGenerator {
12039
12514
  const filePath = import_node_path5.default.resolve(outputDir, `mcp-document.${this.options.format}`);
12040
12515
  await (0, import_promises4.writeFile)(filePath, serialized, "utf-8");
12041
12516
  console.log(`[MCPGenerator] Document written to: ${filePath}`);
12517
+ const controlFiles = analyzed.controlEvidenceFiles ?? {};
12518
+ await (0, import_promises4.writeFile)(
12519
+ import_node_path5.default.resolve(outputDir, "control-evidence.json"),
12520
+ JSON.stringify({ version: 1, files: controlFiles }, null, 2),
12521
+ "utf-8"
12522
+ );
12042
12523
  const checksumFilePath = import_node_path5.default.resolve(outputDir, ".appilots-checksum");
12043
12524
  await (0, import_promises4.writeFile)(checksumFilePath, checksum, "utf-8");
12044
12525
  console.log(`[MCPGenerator] Checksum written to: ${checksumFilePath}`);
12526
+ const evidenceCount = Object.values(controlFiles).reduce(
12527
+ (sum, entries) => sum + entries.length,
12528
+ 0
12529
+ );
12530
+ console.log(
12531
+ `[MCPGenerator] Source evidence: ${evidenceCount} icon controls across ${Object.keys(controlFiles).length} files (runtime binding required)`
12532
+ );
12045
12533
  console.log("[MCPGenerator] Generation complete!");
12046
12534
  return {
12047
12535
  document,
@@ -12072,7 +12560,7 @@ var MCPGenerator = class _MCPGenerator {
12072
12560
  * Calculate SHA-256 checksum of content
12073
12561
  */
12074
12562
  calculateChecksum(content) {
12075
- return (0, import_node_crypto.createHash)("sha256").update(content).digest("hex");
12563
+ return (0, import_node_crypto2.createHash)("sha256").update(content).digest("hex");
12076
12564
  }
12077
12565
  /**
12078
12566
  * Get project name and version from package.json in rootDir
@@ -12688,15 +13176,15 @@ var import_node_path9 = __toESM(require("path"));
12688
13176
  var import_commander5 = require("commander");
12689
13177
 
12690
13178
  // src/annotate/sites.ts
12691
- var import_traverse12 = __toESM(require("@babel/traverse"));
12692
- var t14 = __toESM(require("@babel/types"));
13179
+ var import_traverse13 = __toESM(require("@babel/traverse"));
13180
+ var t16 = __toESM(require("@babel/types"));
12693
13181
 
12694
13182
  // src/annotate/forwarding.ts
12695
13183
  var import_node_path8 = __toESM(require("path"));
12696
13184
  var import_node_fs5 = require("fs");
12697
- var import_traverse11 = __toESM(require("@babel/traverse"));
12698
- var t13 = __toESM(require("@babel/types"));
12699
- var traverse11 = import_traverse11.default.default ?? import_traverse11.default;
13185
+ var import_traverse12 = __toESM(require("@babel/traverse"));
13186
+ var t15 = __toESM(require("@babel/types"));
13187
+ var traverse12 = import_traverse12.default.default ?? import_traverse12.default;
12700
13188
  var RN_TESTID_CARRIERS = /* @__PURE__ */ new Set([
12701
13189
  "View",
12702
13190
  "Text",
@@ -12723,14 +13211,14 @@ var RN_TESTID_CARRIERS = /* @__PURE__ */ new Set([
12723
13211
  ]);
12724
13212
  function collectImports(ast) {
12725
13213
  const out = /* @__PURE__ */ new Map();
12726
- traverse11(ast, {
13214
+ traverse12(ast, {
12727
13215
  ImportDeclaration(nodePath) {
12728
13216
  const source = nodePath.node.source.value;
12729
13217
  for (const spec of nodePath.node.specifiers) {
12730
- if (t13.isImportSpecifier(spec)) {
12731
- const imported = t13.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
13218
+ if (t15.isImportSpecifier(spec)) {
13219
+ const imported = t15.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
12732
13220
  out.set(spec.local.name, { source, local: spec.local.name, imported });
12733
- } else if (t13.isImportDefaultSpecifier(spec)) {
13221
+ } else if (t15.isImportDefaultSpecifier(spec)) {
12734
13222
  out.set(spec.local.name, { source, local: spec.local.name, imported: "default" });
12735
13223
  }
12736
13224
  }
@@ -12778,13 +13266,13 @@ function inspectModule(file2, exportName, depth = 0) {
12778
13266
  let forwards = false;
12779
13267
  let derives = false;
12780
13268
  let barrelTarget;
12781
- traverse11(ast, {
13269
+ traverse12(ast, {
12782
13270
  // `export { Card } from './Card'` — follow one hop.
12783
13271
  ExportNamedDeclaration(nodePath) {
12784
13272
  const from = nodePath.node.source?.value;
12785
13273
  if (!from) return;
12786
13274
  const named = nodePath.node.specifiers.some(
12787
- (spec) => t13.isExportSpecifier(spec) && (t13.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value) === exportName
13275
+ (spec) => t15.isExportSpecifier(spec) && (t15.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value) === exportName
12788
13276
  );
12789
13277
  if (named) barrelTarget = from;
12790
13278
  },
@@ -12793,11 +13281,11 @@ function inspectModule(file2, exportName, depth = 0) {
12793
13281
  },
12794
13282
  // `interface CardProps { testID?: string }` / `type Props = { testID… }`
12795
13283
  TSPropertySignature(nodePath) {
12796
- if (t13.isIdentifier(nodePath.node.key) && nodePath.node.key.name === "testID") forwards = true;
13284
+ if (t15.isIdentifier(nodePath.node.key) && nodePath.node.key.name === "testID") forwards = true;
12797
13285
  },
12798
13286
  // `function Card({ testID }) {}` — the destructured parameter.
12799
13287
  ObjectProperty(nodePath) {
12800
- if (t13.isIdentifier(nodePath.node.key) && nodePath.node.key.name === "testID") forwards = true;
13288
+ if (t15.isIdentifier(nodePath.node.key) && nodePath.node.key.name === "testID") forwards = true;
12801
13289
  },
12802
13290
  // `<View {...props} />` — anything spread onto JSX carries it along.
12803
13291
  JSXSpreadAttribute() {
@@ -12808,17 +13296,17 @@ function inspectModule(file2, exportName, depth = 0) {
12808
13296
  // that is one hardcoded name shared by every instance, which is the
12809
13297
  // duplicate-id problem rather than a solution to it.
12810
13298
  JSXAttribute(nodePath) {
12811
- const name = t13.isJSXIdentifier(nodePath.node.name) ? nodePath.node.name.name : "";
13299
+ const name = t15.isJSXIdentifier(nodePath.node.name) ? nodePath.node.name.name : "";
12812
13300
  if (name !== "testID" && name !== "accessibilityLabel") return;
12813
13301
  const value = nodePath.node.value;
12814
- if (!t13.isJSXExpressionContainer(value)) return;
12815
- if (t13.isStringLiteral(value.expression)) return;
13302
+ if (!t15.isJSXExpressionContainer(value)) return;
13303
+ if (t15.isStringLiteral(value.expression)) return;
12816
13304
  derives = true;
12817
13305
  },
12818
13306
  // `useAppilotsTarget(`${groupId}-${option.value}`, …)`
12819
13307
  CallExpression(nodePath) {
12820
13308
  const callee = nodePath.node.callee;
12821
- if (t13.isIdentifier(callee) && IDENTITY_HOOKS.has(callee.name)) derives = true;
13309
+ if (t15.isIdentifier(callee) && IDENTITY_HOOKS.has(callee.name)) derives = true;
12822
13310
  }
12823
13311
  });
12824
13312
  if (forwards || derives) return { forwards, derives };
@@ -12852,7 +13340,7 @@ function resetForwardingCache() {
12852
13340
  }
12853
13341
 
12854
13342
  // src/annotate/sites.ts
12855
- var traverse12 = import_traverse12.default.default ?? import_traverse12.default;
13343
+ var traverse13 = import_traverse13.default.default ?? import_traverse13.default;
12856
13344
  var LABEL_PROPS = ["title", "label", "placeholder"];
12857
13345
  var IDENTITY_PROPS = ["testID", "appilotsId", "accessibilityLabel"];
12858
13346
  function kebab(text) {
@@ -12903,18 +13391,18 @@ function hasLabelText(element) {
12903
13391
  function namedHandler(element, prop) {
12904
13392
  if (!prop) return void 0;
12905
13393
  const attr = findJsxAttribute(element, prop);
12906
- if (!attr || !t14.isJSXExpressionContainer(attr.value)) return void 0;
12907
- return t14.isIdentifier(attr.value.expression) ? attr.value.expression.name : void 0;
13394
+ if (!attr || !t16.isJSXExpressionContainer(attr.value)) return void 0;
13395
+ return t16.isIdentifier(attr.value.expression) ? attr.value.expression.name : void 0;
12908
13396
  }
12909
13397
  var ANNOTATABLE_ROLES = /* @__PURE__ */ new Set(["button", "input", "select", "toggle", "date", "list"]);
12910
13398
  function isPerItemRender(nodePath) {
12911
13399
  let current = nodePath.parentPath;
12912
13400
  while (current) {
12913
13401
  const node = current.node;
12914
- if (t14.isCallExpression(node) && t14.isMemberExpression(node.callee) && t14.isIdentifier(node.callee.property) && (node.callee.property.name === "map" || node.callee.property.name === "flatMap")) {
13402
+ if (t16.isCallExpression(node) && t16.isMemberExpression(node.callee) && t16.isIdentifier(node.callee.property) && (node.callee.property.name === "map" || node.callee.property.name === "flatMap")) {
12915
13403
  return true;
12916
13404
  }
12917
- if (t14.isJSXAttribute(node) && t14.isJSXIdentifier(node.name) && /^render[A-Z]|^ListHeaderComponent$|^ListFooterComponent$/.test(node.name.name) && node.name.name !== "renderScrollComponent") {
13405
+ if (t16.isJSXAttribute(node) && t16.isJSXIdentifier(node.name) && /^render[A-Z]|^ListHeaderComponent$|^ListFooterComponent$/.test(node.name.name) && node.name.name !== "renderScrollComponent") {
12918
13406
  return /^renderItem$|^renderSectionHeader$|^renderSectionFooter$/.test(node.name.name);
12919
13407
  }
12920
13408
  current = current.parentPath;
@@ -12933,7 +13421,7 @@ function findAnnotationSites(source, file2) {
12933
13421
  const sites = [];
12934
13422
  const perComponent = /* @__PURE__ */ new Map();
12935
13423
  const usedIds = /* @__PURE__ */ new Set();
12936
- traverse12(ast, {
13424
+ traverse13(ast, {
12937
13425
  JSXOpeningElement(nodePath) {
12938
13426
  for (const prop of IDENTITY_PROPS) {
12939
13427
  const existing = getStringAttr(nodePath.node, prop);
@@ -12941,10 +13429,10 @@ function findAnnotationSites(source, file2) {
12941
13429
  }
12942
13430
  }
12943
13431
  });
12944
- traverse12(ast, {
13432
+ traverse13(ast, {
12945
13433
  JSXOpeningElement(nodePath) {
12946
13434
  const element = nodePath.node;
12947
- if (!t14.isJSXIdentifier(element.name)) return;
13435
+ if (!t16.isJSXIdentifier(element.name)) return;
12948
13436
  const component = element.name.name;
12949
13437
  const role = classifyJsxComponent(component, element);
12950
13438
  if (!ANNOTATABLE_ROLES.has(role)) return;
@@ -13028,21 +13516,21 @@ function applyToFile(source, sites) {
13028
13516
  // src/annotate/forward.ts
13029
13517
  var import_node_fs6 = require("fs");
13030
13518
  var import_magic_string2 = __toESM(require("magic-string"));
13031
- var import_traverse13 = __toESM(require("@babel/traverse"));
13032
- var t15 = __toESM(require("@babel/types"));
13033
- var traverse13 = import_traverse13.default.default ?? import_traverse13.default;
13519
+ var import_traverse14 = __toESM(require("@babel/traverse"));
13520
+ var t17 = __toESM(require("@babel/types"));
13521
+ var traverse14 = import_traverse14.default.default ?? import_traverse14.default;
13034
13522
  function findComponent(ast, name) {
13035
13523
  let found;
13036
- traverse13(ast, {
13524
+ traverse14(ast, {
13037
13525
  FunctionDeclaration(nodePath) {
13038
13526
  if (nodePath.node.id?.name === name) {
13039
13527
  found ??= { params: nodePath.node.params, body: nodePath.node.body };
13040
13528
  }
13041
13529
  },
13042
13530
  VariableDeclarator(nodePath) {
13043
- if (!t15.isIdentifier(nodePath.node.id) || nodePath.node.id.name !== name) return;
13531
+ if (!t17.isIdentifier(nodePath.node.id) || nodePath.node.id.name !== name) return;
13044
13532
  const init = nodePath.node.init;
13045
- if (t15.isArrowFunctionExpression(init) || t15.isFunctionExpression(init)) {
13533
+ if (t17.isArrowFunctionExpression(init) || t17.isFunctionExpression(init)) {
13046
13534
  found ??= { params: init.params, body: init.body };
13047
13535
  }
13048
13536
  }
@@ -13054,26 +13542,26 @@ function findReturnedRoots(body) {
13054
13542
  let unsupported = false;
13055
13543
  const record = (node) => {
13056
13544
  if (!node) return;
13057
- if (t15.isParenthesizedExpression(node)) return record(node.expression);
13058
- if (t15.isJSXElement(node)) {
13545
+ if (t17.isParenthesizedExpression(node)) return record(node.expression);
13546
+ if (t17.isJSXElement(node)) {
13059
13547
  roots.push(node.openingElement);
13060
13548
  return;
13061
13549
  }
13062
- if (t15.isConditionalExpression(node)) {
13550
+ if (t17.isConditionalExpression(node)) {
13063
13551
  record(node.consequent);
13064
13552
  record(node.alternate);
13065
13553
  return;
13066
13554
  }
13067
- if (t15.isJSXFragment(node)) {
13555
+ if (t17.isJSXFragment(node)) {
13068
13556
  unsupported = true;
13069
13557
  return;
13070
13558
  }
13071
- if (t15.isNullLiteral(node)) return;
13559
+ if (t17.isNullLiteral(node)) return;
13072
13560
  unsupported = true;
13073
13561
  };
13074
- if (t15.isBlockStatement(body)) {
13075
- traverse13(
13076
- t15.file(t15.program([t15.expressionStatement(t15.functionExpression(null, [], body))])),
13562
+ if (t17.isBlockStatement(body)) {
13563
+ traverse14(
13564
+ t17.file(t17.program([t17.expressionStatement(t17.functionExpression(null, [], body))])),
13077
13565
  {
13078
13566
  ReturnStatement(nodePath) {
13079
13567
  record(nodePath.node.argument);
@@ -13087,7 +13575,7 @@ function findReturnedRoots(body) {
13087
13575
  return roots;
13088
13576
  }
13089
13577
  function isCarrierRoot(element, imports) {
13090
- if (!t15.isJSXIdentifier(element.name)) return false;
13578
+ if (!t17.isJSXIdentifier(element.name)) return false;
13091
13579
  const name = element.name.name;
13092
13580
  const origin = imports.get(name);
13093
13581
  if (origin?.source !== "react-native") return false;
@@ -13095,7 +13583,7 @@ function isCarrierRoot(element, imports) {
13095
13583
  }
13096
13584
  function hasProp(element, name) {
13097
13585
  return element.attributes.some(
13098
- (attr) => t15.isJSXAttribute(attr) && t15.isJSXIdentifier(attr.name) && attr.name.name === name
13586
+ (attr) => t17.isJSXAttribute(attr) && t17.isJSXIdentifier(attr.name) && attr.name.name === name
13099
13587
  );
13100
13588
  }
13101
13589
  function indentOf(source, offset) {
@@ -13121,12 +13609,12 @@ ${indent}${text}` };
13121
13609
  }
13122
13610
  function followBarrel(file2, ast, component) {
13123
13611
  let target;
13124
- traverse13(ast, {
13612
+ traverse14(ast, {
13125
13613
  ExportNamedDeclaration(nodePath) {
13126
13614
  const from = nodePath.node.source?.value;
13127
13615
  if (!from) return;
13128
13616
  const named = nodePath.node.specifiers.some(
13129
- (spec) => t15.isExportSpecifier(spec) && (t15.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value) === component
13617
+ (spec) => t17.isExportSpecifier(spec) && (t17.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value) === component
13130
13618
  );
13131
13619
  if (named) target ??= from;
13132
13620
  }
@@ -13154,7 +13642,7 @@ function planForward(file2, component, depth = 0) {
13154
13642
  return { ...base, refusal: `no function named ${component} in this file` };
13155
13643
  }
13156
13644
  const param = found.params[0];
13157
- if (!t15.isObjectPattern(param)) {
13645
+ if (!t17.isObjectPattern(param)) {
13158
13646
  return {
13159
13647
  ...base,
13160
13648
  refusal: `${component} does not destructure its props, so there is no safe place to add one without knowing what the parameter is called downstream`
@@ -13170,7 +13658,7 @@ function planForward(file2, component, depth = 0) {
13170
13658
  const imports = collectImports(ast);
13171
13659
  const nonCarrier = roots.find((root) => !isCarrierRoot(root, imports));
13172
13660
  if (nonCarrier) {
13173
- const name = t15.isJSXIdentifier(nonCarrier.name) ? nonCarrier.name.name : "its root";
13661
+ const name = t17.isJSXIdentifier(nonCarrier.name) ? nonCarrier.name.name : "its root";
13174
13662
  return {
13175
13663
  ...base,
13176
13664
  refusal: `${component} renders <${name}> at its root, which is not a React Native element known to accept testID. Forwarding into it would move the problem down a level, not fix it`
@@ -13178,30 +13666,30 @@ function planForward(file2, component, depth = 0) {
13178
13666
  }
13179
13667
  const edits = [];
13180
13668
  const alreadyDestructured = param.properties.some(
13181
- (prop) => t15.isObjectProperty(prop) && t15.isIdentifier(prop.key) && prop.key.name === "testID"
13669
+ (prop) => t17.isObjectProperty(prop) && t17.isIdentifier(prop.key) && prop.key.name === "testID"
13182
13670
  );
13183
13671
  if (!alreadyDestructured) {
13184
13672
  const insert = insertAfterLastMember(source, param.properties, "testID", param.end ?? 0, ",");
13185
13673
  edits.push({ ...insert, what: "parameter" });
13186
13674
  }
13187
13675
  const annotation = param.typeAnnotation;
13188
- if (t15.isTSTypeAnnotation(annotation)) {
13676
+ if (t17.isTSTypeAnnotation(annotation)) {
13189
13677
  const declared = annotation.typeAnnotation;
13190
13678
  let body;
13191
13679
  let closing = 0;
13192
- if (t15.isTSTypeLiteral(declared)) {
13680
+ if (t17.isTSTypeLiteral(declared)) {
13193
13681
  body = declared.members;
13194
13682
  closing = declared.end ?? 0;
13195
- } else if (t15.isTSTypeReference(declared) && t15.isIdentifier(declared.typeName)) {
13683
+ } else if (t17.isTSTypeReference(declared) && t17.isIdentifier(declared.typeName)) {
13196
13684
  const typeName = declared.typeName.name;
13197
- traverse13(ast, {
13685
+ traverse14(ast, {
13198
13686
  TSInterfaceDeclaration(nodePath) {
13199
13687
  if (nodePath.node.id.name !== typeName) return;
13200
13688
  body = nodePath.node.body.body;
13201
13689
  closing = nodePath.node.body.end ?? 0;
13202
13690
  },
13203
13691
  TSTypeAliasDeclaration(nodePath) {
13204
- if (nodePath.node.id.name !== typeName || !t15.isTSTypeLiteral(nodePath.node.typeAnnotation))
13692
+ if (nodePath.node.id.name !== typeName || !t17.isTSTypeLiteral(nodePath.node.typeAnnotation))
13205
13693
  return;
13206
13694
  body = nodePath.node.typeAnnotation.members;
13207
13695
  closing = nodePath.node.typeAnnotation.end ?? 0;
@@ -13216,7 +13704,7 @@ function planForward(file2, component, depth = 0) {
13216
13704
  }
13217
13705
  if (body) {
13218
13706
  const declaresTestId = body.some(
13219
- (member) => t15.isTSPropertySignature(member) && t15.isIdentifier(member.key) && member.key.name === "testID"
13707
+ (member) => t17.isTSPropertySignature(member) && t17.isIdentifier(member.key) && member.key.name === "testID"
13220
13708
  );
13221
13709
  if (!declaresTestId) {
13222
13710
  const insert = insertAfterLastMember(source, body, "testID?: string;", closing, ";");
@@ -14009,9 +14497,145 @@ Pass rate: ${passed}/${total} (${passRatePct}%) \u2014 threshold ${minPassRatePc
14009
14497
  });
14010
14498
  }
14011
14499
 
14500
+ // src/cli/commands/knowledge.ts
14501
+ var import_commander8 = require("commander");
14502
+ var import_promises7 = require("fs/promises");
14503
+ var import_node_path10 = require("path");
14504
+ var import_node_crypto3 = require("crypto");
14505
+ var import_fast_glob2 = __toESM(require("fast-glob"));
14506
+ var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".txt", ".html", ".htm", ".pdf"]);
14507
+ var MIME_MAP = {
14508
+ ".md": "text/markdown",
14509
+ ".txt": "text/plain",
14510
+ ".html": "text/html",
14511
+ ".htm": "text/html",
14512
+ ".pdf": "application/pdf"
14513
+ };
14514
+ function knowledgeCommand() {
14515
+ const cmd = new import_commander8.Command("knowledge").description("Manage the project knowledge base (RAG)");
14516
+ cmd.command("sync").description("Sync local documentation files to the knowledge base").option("--verbose", "Enable verbose logging", false).option("--api-key <key>", "Appilots API key (overrides .appilotsrc)").option("--server <url>", "Appilots server URL (overrides .appilotsrc)").option("--json", "Output a machine-readable JSON result (implies --quiet)", false).option("--quiet", "Suppress banner and informational output", false).action(async (options) => {
14517
+ if (options.json) setLogMode("json");
14518
+ else if (options.quiet) setLogMode("quiet");
14519
+ try {
14520
+ banner();
14521
+ const loaded = loadConfig(warn);
14522
+ const apiKey = options.apiKey || loaded?.apiKey;
14523
+ if (!apiKey) {
14524
+ error("No .appilotsrc configuration found");
14525
+ info("Run: appilots init --api-key <your-key>");
14526
+ jsonOutput({ success: false, error: "No configuration found (missing API key)" });
14527
+ process.exit(1);
14528
+ return;
14529
+ }
14530
+ const config = {
14531
+ serverUrl: DEFAULT_SERVER_URL,
14532
+ ...loaded,
14533
+ apiKey,
14534
+ ...options.server ? { serverUrl: options.server } : {}
14535
+ };
14536
+ const sources = config.knowledge?.sources;
14537
+ if (!sources || sources.length === 0) {
14538
+ error("No knowledge sources configured");
14539
+ info("Add knowledge.sources to .appilotsrc:");
14540
+ info(' { "knowledge": { "sources": ["docs/**/*.md"] } }');
14541
+ jsonOutput({ success: false, error: "No knowledge sources configured" });
14542
+ process.exit(1);
14543
+ return;
14544
+ }
14545
+ const spinner = createSpinner("Scanning for knowledge documents...");
14546
+ spinner.start();
14547
+ const rootDir = process.cwd();
14548
+ const excludePatterns = config.knowledge?.exclude ?? [];
14549
+ const allFiles = [];
14550
+ for (const pattern of sources) {
14551
+ const matches = await (0, import_fast_glob2.default)(pattern, {
14552
+ cwd: rootDir,
14553
+ ignore: ["node_modules/**", ...excludePatterns],
14554
+ onlyFiles: true
14555
+ });
14556
+ for (const match of matches) {
14557
+ const ext = (0, import_node_path10.extname)(match).toLowerCase();
14558
+ if (SUPPORTED_EXTENSIONS.has(ext) && !allFiles.includes(match)) {
14559
+ allFiles.push(match);
14560
+ }
14561
+ }
14562
+ }
14563
+ spinner.stop();
14564
+ if (allFiles.length === 0) {
14565
+ warn("No supported files found matching knowledge.sources patterns");
14566
+ info(`Supported: ${[...SUPPORTED_EXTENSIONS].join(", ")}`);
14567
+ jsonOutput({ success: true, uploaded: 0, skipped: 0, errors: 0, files: 0 });
14568
+ return;
14569
+ }
14570
+ info(`Found ${allFiles.length} document${allFiles.length === 1 ? "" : "s"}`);
14571
+ const documents = [];
14572
+ for (const filePath of allFiles) {
14573
+ const absolutePath = (0, import_node_path10.resolve)(rootDir, filePath);
14574
+ const buffer = await (0, import_promises7.readFile)(absolutePath);
14575
+ const checksum = (0, import_node_crypto3.createHash)("sha256").update(buffer).digest("hex");
14576
+ const ext = (0, import_node_path10.extname)(filePath).toLowerCase();
14577
+ const mimeType = MIME_MAP[ext] ?? "text/plain";
14578
+ documents.push({
14579
+ filename: (0, import_node_path10.relative)(rootDir, absolutePath),
14580
+ content: buffer.toString("base64"),
14581
+ mimeType,
14582
+ checksum
14583
+ });
14584
+ }
14585
+ const uploadSpinner = createSpinner(
14586
+ `Uploading ${documents.length} document${documents.length === 1 ? "" : "s"}...`
14587
+ );
14588
+ uploadSpinner.start();
14589
+ const apiClient = new AppilotsAPIClient({
14590
+ serverUrl: config.serverUrl,
14591
+ apiKey: config.apiKey,
14592
+ timeoutMs: 12e4
14593
+ // Knowledge sync can take longer (embedding)
14594
+ });
14595
+ const result = await apiClient.knowledgeSync(documents);
14596
+ uploadSpinner.stop();
14597
+ if (!result.success) {
14598
+ error(`Knowledge sync failed: ${result.error}`);
14599
+ jsonOutput({ success: false, error: result.error });
14600
+ process.exit(1);
14601
+ return;
14602
+ }
14603
+ success(
14604
+ `Knowledge sync complete: ${result.uploaded} uploaded, ${result.skipped} skipped, ${result.errors} errors`
14605
+ );
14606
+ if (options.verbose && result.details) {
14607
+ for (const detail of result.details) {
14608
+ if (detail.status === "uploaded") {
14609
+ info(` + ${detail.filename}`);
14610
+ } else if (detail.status === "skipped") {
14611
+ info(` = ${detail.filename} (unchanged)`);
14612
+ } else {
14613
+ warn(` ! ${detail.filename}: ${detail.error}`);
14614
+ }
14615
+ }
14616
+ }
14617
+ jsonOutput({
14618
+ success: true,
14619
+ uploaded: result.uploaded,
14620
+ skipped: result.skipped,
14621
+ errors: result.errors,
14622
+ details: result.details
14623
+ });
14624
+ } catch (err) {
14625
+ error(`Knowledge sync failed: ${stringifyUnknown(err)}`);
14626
+ jsonOutput({ success: false, error: stringifyUnknown(err) });
14627
+ if (options.verbose) {
14628
+ console.error(err);
14629
+ }
14630
+ process.exit(1);
14631
+ }
14632
+ });
14633
+ return cmd;
14634
+ }
14635
+
14012
14636
  // src/cli/index.ts
14013
14637
  async function main() {
14014
- const program2 = new import_commander8.Command();
14638
+ const program2 = new import_commander9.Command();
14015
14639
  program2.name("appilots").description(
14016
14640
  "Analyze your React Native app and generate MCP documents for AI-powered navigation.\n\nQuick start:\n $ appilots init --api-key ak_xxx\n $ appilots sync\n $ appilots watch"
14017
14641
  ).version(CLI_VERSION).option("--verbose", "Enable verbose logging");
@@ -14022,6 +14646,7 @@ async function main() {
14022
14646
  program2.addCommand(annotateCommand());
14023
14647
  program2.addCommand(statusCommand());
14024
14648
  program2.addCommand(evalCommand());
14649
+ program2.addCommand(knowledgeCommand());
14025
14650
  const args = process.argv.slice(2);
14026
14651
  const firstArg = args[0];
14027
14652
  const hasCommand = firstArg !== void 0 && args.length > 0 && !firstArg.startsWith("-");