@appilots/cli 0.11.3 → 0.14.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.14.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
  }
@@ -1426,6 +1830,9 @@ function sanitisePermissionsObject(obj) {
1426
1830
  if (typeof obj.isPii === "boolean") {
1427
1831
  out.isPii = obj.isPii;
1428
1832
  }
1833
+ if (typeof obj.assessment === "boolean") {
1834
+ out.assessment = obj.assessment;
1835
+ }
1429
1836
  if (Array.isArray(obj.blockedActions)) {
1430
1837
  const ids = obj.blockedActions.filter((x) => typeof x === "string" && !!x);
1431
1838
  if (ids.length > 0) out.blockedActions = ids;
@@ -1453,6 +1860,7 @@ var ScreenAnalyzer = class {
1453
1860
  routeTargetFiles;
1454
1861
  /** §D: Count of screens filtered out in strict mode (available after analyze()) */
1455
1862
  screensFilteredOut = 0;
1863
+ controlEvidenceFiles = {};
1456
1864
  constructor(config, options) {
1457
1865
  this.config = config;
1458
1866
  this.routeTargetFiles = options?.routeTargetFiles ?? /* @__PURE__ */ new Set();
@@ -1553,6 +1961,11 @@ var ScreenAnalyzer = class {
1553
1961
  title: registerScreenMeta?.title,
1554
1962
  description: registerScreenMeta?.description,
1555
1963
  components,
1964
+ controlCandidates: extractControlEvidence(
1965
+ ast,
1966
+ source,
1967
+ import_path3.default.relative(this.config.rootDir, filePath)
1968
+ ),
1556
1969
  forms,
1557
1970
  actions,
1558
1971
  navigationTargets,
@@ -1563,6 +1976,8 @@ var ScreenAnalyzer = class {
1563
1976
  ...permissionsFromJsDoc.isPii ? { isPii: true } : {}
1564
1977
  } : {}
1565
1978
  };
1979
+ if (descriptor.controlCandidates?.length)
1980
+ this.controlEvidenceFiles[import_path3.default.relative(this.config.rootDir, filePath).split(import_path3.default.sep).join("/")] = descriptor.controlCandidates;
1566
1981
  descriptor.__hasRegisterScreen = hasRegisterScreenCall;
1567
1982
  return descriptor;
1568
1983
  }
@@ -1572,7 +1987,7 @@ var ScreenAnalyzer = class {
1572
1987
  */
1573
1988
  detectRegisterScreenCall(ast) {
1574
1989
  let found = false;
1575
- (0, import_traverse4.default)(ast, {
1990
+ (0, import_traverse5.default)(ast, {
1576
1991
  CallExpression: (nodePath) => {
1577
1992
  if (found) return;
1578
1993
  const callee = nodePath.node.callee;
@@ -1589,7 +2004,7 @@ var ScreenAnalyzer = class {
1589
2004
  */
1590
2005
  extractRegisterScreenMetadata(ast) {
1591
2006
  let metadata = null;
1592
- (0, import_traverse4.default)(ast, {
2007
+ (0, import_traverse5.default)(ast, {
1593
2008
  CallExpression: (nodePath) => {
1594
2009
  const callee = nodePath.node.callee;
1595
2010
  if (BabelTypes.isIdentifier(callee) && callee.name === "registerScreen" || BabelTypes.isMemberExpression(callee) && BabelTypes.isIdentifier(callee.property) && callee.property.name === "registerScreen") {
@@ -1886,7 +2301,7 @@ var ScreenAnalyzer = class {
1886
2301
  */
1887
2302
  extractDefaultComponentName(ast) {
1888
2303
  let componentName = "";
1889
- (0, import_traverse4.default)(ast, {
2304
+ (0, import_traverse5.default)(ast, {
1890
2305
  ExportDefaultDeclaration: (nodePath) => {
1891
2306
  const declaration = nodePath.node.declaration;
1892
2307
  if (BabelTypes.isFunctionDeclaration(declaration) && declaration.id?.name) {
@@ -1911,7 +2326,7 @@ var ScreenAnalyzer = class {
1911
2326
  */
1912
2327
  extractNavigationTargets(ast) {
1913
2328
  const targets = /* @__PURE__ */ new Set();
1914
- (0, import_traverse4.default)(ast, {
2329
+ (0, import_traverse5.default)(ast, {
1915
2330
  CallExpression: (nodePath) => {
1916
2331
  const callee = nodePath.node.callee;
1917
2332
  if (BabelTypes.isMemberExpression(callee) && BabelTypes.isIdentifier(callee.object) && callee.object.name === "navigation" && BabelTypes.isIdentifier(callee.property) && callee.property.name === "navigate") {
@@ -1930,7 +2345,7 @@ var ScreenAnalyzer = class {
1930
2345
  extractForms(ast) {
1931
2346
  const forms = [];
1932
2347
  const fields = /* @__PURE__ */ new Map();
1933
- (0, import_traverse4.default)(ast, {
2348
+ (0, import_traverse5.default)(ast, {
1934
2349
  JSXOpeningElement: (nodePath) => {
1935
2350
  const element = nodePath.node;
1936
2351
  if (BabelTypes.isJSXIdentifier(element.name)) {
@@ -2051,7 +2466,7 @@ var ScreenAnalyzer = class {
2051
2466
  extractComponents(ast) {
2052
2467
  const components = [];
2053
2468
  const seen = /* @__PURE__ */ new Set();
2054
- (0, import_traverse4.default)(ast, {
2469
+ (0, import_traverse5.default)(ast, {
2055
2470
  JSXOpeningElement: (nodePath) => {
2056
2471
  const element = nodePath.node;
2057
2472
  if (BabelTypes.isJSXIdentifier(element.name)) {
@@ -2115,7 +2530,7 @@ var ScreenAnalyzer = class {
2115
2530
  const actionLabels = new Map(
2116
2531
  actions.filter((a) => a.label).map((a) => [this.normalizeLabel(a.label), a])
2117
2532
  );
2118
- (0, import_traverse4.default)(ast, {
2533
+ (0, import_traverse5.default)(ast, {
2119
2534
  JSXOpeningElement: (nodePath) => {
2120
2535
  const element = nodePath.node;
2121
2536
  if (BabelTypes.isJSXIdentifier(element.name)) {
@@ -2184,7 +2599,7 @@ var ScreenAnalyzer = class {
2184
2599
  }
2185
2600
  collectButtonHandlersByLabel(ast) {
2186
2601
  const out = /* @__PURE__ */ new Map();
2187
- (0, import_traverse4.default)(ast, {
2602
+ (0, import_traverse5.default)(ast, {
2188
2603
  JSXOpeningElement: (nodePath) => {
2189
2604
  const element = nodePath.node;
2190
2605
  if (!BabelTypes.isJSXIdentifier(element.name)) return;
@@ -2266,7 +2681,7 @@ var ScreenAnalyzer = class {
2266
2681
  }
2267
2682
  };
2268
2683
  if (fn.body) {
2269
- (0, import_traverse4.default)(
2684
+ (0, import_traverse5.default)(
2270
2685
  fn.body,
2271
2686
  {
2272
2687
  noScope: true,
@@ -2463,7 +2878,7 @@ var ScreenAnalyzer = class {
2463
2878
  extractCollections(ast) {
2464
2879
  const renderItemFns = this.collectRenderItemFunctions(ast);
2465
2880
  const collections = [];
2466
- (0, import_traverse4.default)(ast, {
2881
+ (0, import_traverse5.default)(ast, {
2467
2882
  JSXOpeningElement: (nodePath) => {
2468
2883
  const element = nodePath.node;
2469
2884
  if (!BabelTypes.isJSXIdentifier(element.name)) return;
@@ -2500,7 +2915,7 @@ var ScreenAnalyzer = class {
2500
2915
  }
2501
2916
  collectRenderItemFunctions(ast) {
2502
2917
  const out = /* @__PURE__ */ new Map();
2503
- (0, import_traverse4.default)(ast, {
2918
+ (0, import_traverse5.default)(ast, {
2504
2919
  VariableDeclarator: (nodePath) => {
2505
2920
  if (!BabelTypes.isIdentifier(nodePath.node.id)) return;
2506
2921
  const init = nodePath.node.init;
@@ -2543,7 +2958,7 @@ var ScreenAnalyzer = class {
2543
2958
  }
2544
2959
  extractRowAction(fn) {
2545
2960
  let action;
2546
- (0, import_traverse4.default)(
2961
+ (0, import_traverse5.default)(
2547
2962
  fn.body,
2548
2963
  {
2549
2964
  noScope: true,
@@ -2596,7 +3011,7 @@ var ScreenAnalyzer = class {
2596
3011
  } else if (BabelTypes.isIdentifier(firstParam)) {
2597
3012
  itemNames.add(firstParam.name);
2598
3013
  }
2599
- (0, import_traverse4.default)(
3014
+ (0, import_traverse5.default)(
2600
3015
  fn.body,
2601
3016
  {
2602
3017
  noScope: true,
@@ -2638,7 +3053,7 @@ var ScreenAnalyzer = class {
2638
3053
  inferSearchField(ast, dataSource) {
2639
3054
  if (!dataSource) return void 0;
2640
3055
  let queryBinding;
2641
- (0, import_traverse4.default)(ast, {
3056
+ (0, import_traverse5.default)(ast, {
2642
3057
  CallExpression: (nodePath) => {
2643
3058
  const node = nodePath.node;
2644
3059
  if (!BabelTypes.isMemberExpression(node.callee)) return;
@@ -2649,7 +3064,7 @@ var ScreenAnalyzer = class {
2649
3064
  const fn = node.arguments[0];
2650
3065
  if (!BabelTypes.isArrowFunctionExpression(fn) && !BabelTypes.isFunctionExpression(fn))
2651
3066
  return;
2652
- (0, import_traverse4.default)(
3067
+ (0, import_traverse5.default)(
2653
3068
  fn.body,
2654
3069
  {
2655
3070
  noScope: true,
@@ -2695,16 +3110,16 @@ var ScreenAnalyzer = class {
2695
3110
  var import_fs4 = require("fs");
2696
3111
  var import_path4 = __toESM(require("path"));
2697
3112
  var parser2 = __toESM(require("@babel/parser"));
2698
- var import_traverse5 = __toESM(require("@babel/traverse"));
2699
- var t6 = __toESM(require("@babel/types"));
3113
+ var import_traverse6 = __toESM(require("@babel/traverse"));
3114
+ var t8 = __toESM(require("@babel/types"));
2700
3115
 
2701
3116
  // src/ast/navigation/module-graph.ts
2702
3117
  var import_node_fs = require("fs");
2703
3118
  var import_node_path = __toESM(require("path"));
2704
3119
  var parser = __toESM(require("@babel/parser"));
2705
- var t5 = __toESM(require("@babel/types"));
3120
+ var t7 = __toESM(require("@babel/types"));
2706
3121
  var EXTENSIONS = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"];
2707
- var MAX_HOPS = 8;
3122
+ var MAX_HOPS2 = 8;
2708
3123
  var ModuleGraph = class {
2709
3124
  asts = /* @__PURE__ */ new Map();
2710
3125
  resolved = /* @__PURE__ */ new Map();
@@ -2788,15 +3203,15 @@ var ModuleGraph = class {
2788
3203
  const ast = this.parse(file2);
2789
3204
  if (!ast) return out;
2790
3205
  for (const stmt of ast.program.body) {
2791
- if (!t5.isImportDeclaration(stmt)) continue;
3206
+ if (!t7.isImportDeclaration(stmt)) continue;
2792
3207
  const source = stmt.source.value;
2793
3208
  for (const spec of stmt.specifiers) {
2794
- if (t5.isImportDefaultSpecifier(spec)) {
3209
+ if (t7.isImportDefaultSpecifier(spec)) {
2795
3210
  out.set(spec.local.name, { source, imported: "default" });
2796
- } else if (t5.isImportNamespaceSpecifier(spec)) {
3211
+ } else if (t7.isImportNamespaceSpecifier(spec)) {
2797
3212
  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;
3213
+ } else if (t7.isImportSpecifier(spec)) {
3214
+ const imported = t7.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
2800
3215
  out.set(spec.local.name, { source, imported });
2801
3216
  }
2802
3217
  }
@@ -2808,11 +3223,11 @@ var ModuleGraph = class {
2808
3223
  const ast = this.parse(file2);
2809
3224
  if (!ast) return null;
2810
3225
  for (const stmt of ast.program.body) {
2811
- const decl = t5.isExportNamedDeclaration(stmt) ? stmt.declaration : stmt;
2812
- if (!t5.isVariableDeclaration(decl)) continue;
3226
+ const decl = t7.isExportNamedDeclaration(stmt) ? stmt.declaration : stmt;
3227
+ if (!t7.isVariableDeclaration(decl)) continue;
2813
3228
  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;
3229
+ if (t7.isIdentifier(d.id) && d.id.name === name && d.init) {
3230
+ return t7.isTSAsExpression(d.init) ? d.init.expression : d.init;
2816
3231
  }
2817
3232
  }
2818
3233
  }
@@ -2823,7 +3238,7 @@ var ModuleGraph = class {
2823
3238
  * Devolve o arquivo e o nome sob o qual ele é definido lá.
2824
3239
  */
2825
3240
  resolveBinding(file2, name, hops = 0) {
2826
- if (hops > MAX_HOPS) return null;
3241
+ if (hops > MAX_HOPS2) return null;
2827
3242
  if (this.topLevelInit(file2, name) !== null) return { file: file2, name };
2828
3243
  const binding = this.imports(file2).get(name);
2829
3244
  if (binding) {
@@ -2836,10 +3251,10 @@ var ModuleGraph = class {
2836
3251
  const ast = this.parse(file2);
2837
3252
  if (ast) {
2838
3253
  for (const stmt of ast.program.body) {
2839
- if (!t5.isExportNamedDeclaration(stmt) || !stmt.source) continue;
3254
+ if (!t7.isExportNamedDeclaration(stmt) || !stmt.source) continue;
2840
3255
  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;
3256
+ if (!t7.isExportSpecifier(spec)) continue;
3257
+ const exported = t7.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value;
2843
3258
  if (exported !== name) continue;
2844
3259
  const target = this.resolve(file2, stmt.source.value);
2845
3260
  if (!target) return null;
@@ -2850,7 +3265,7 @@ var ModuleGraph = class {
2850
3265
  }
2851
3266
  if (ast) {
2852
3267
  for (const stmt of ast.program.body) {
2853
- if (!t5.isExportAllDeclaration(stmt)) continue;
3268
+ if (!t7.isExportAllDeclaration(stmt)) continue;
2854
3269
  const target = this.resolve(file2, stmt.source.value);
2855
3270
  if (!target || target === file2) continue;
2856
3271
  const deeper = this.resolveBinding(target, name, hops + 1);
@@ -2859,8 +3274,8 @@ var ModuleGraph = class {
2859
3274
  }
2860
3275
  if (ast) {
2861
3276
  for (const stmt of ast.program.body) {
2862
- if (!t5.isExportDefaultDeclaration(stmt)) continue;
2863
- if (t5.isIdentifier(stmt.declaration)) {
3277
+ if (!t7.isExportDefaultDeclaration(stmt)) continue;
3278
+ if (t7.isIdentifier(stmt.declaration)) {
2864
3279
  const local = stmt.declaration.name;
2865
3280
  if (local === name) return null;
2866
3281
  return this.resolveBinding(file2, local, hops + 1) ?? { file: file2, name: local };
@@ -2877,12 +3292,12 @@ var ModuleGraph = class {
2877
3292
  * com interpolação nem valor calculado, de propósito.
2878
3293
  */
2879
3294
  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)) {
3295
+ if (!node || hops > MAX_HOPS2) return null;
3296
+ if (t7.isStringLiteral(node)) return node.value;
3297
+ if (t7.isTemplateLiteral(node)) {
2883
3298
  return node.expressions.length === 0 ? node.quasis[0]?.value.cooked ?? null : null;
2884
3299
  }
2885
- if (t5.isTSAsExpression(node)) return this.stringConstant(file2, node.expression, hops + 1);
3300
+ if (t7.isTSAsExpression(node)) return this.stringConstant(file2, node.expression, hops + 1);
2886
3301
  const chain = memberChain(node);
2887
3302
  if (!chain) return null;
2888
3303
  const origin = this.resolveBinding(file2, chain.root);
@@ -2890,12 +3305,12 @@ var ModuleGraph = class {
2890
3305
  let current = this.topLevelInit(origin.file, origin.name);
2891
3306
  if (!current) return null;
2892
3307
  for (const key of chain.path) {
2893
- if (!t5.isObjectExpression(current)) return null;
3308
+ if (!t7.isObjectExpression(current)) return null;
2894
3309
  const prop = objectProperty(current, key);
2895
3310
  if (!prop) return null;
2896
- current = t5.isTSAsExpression(prop) ? prop.expression : prop;
3311
+ current = t7.isTSAsExpression(prop) ? prop.expression : prop;
2897
3312
  }
2898
- return t5.isStringLiteral(current) ? current.value : null;
3313
+ return t7.isStringLiteral(current) ? current.value : null;
2899
3314
  }
2900
3315
  /**
2901
3316
  * O ARQUIVO onde vive o componente de uma rota, ou `null`.
@@ -2906,24 +3321,24 @@ var ModuleGraph = class {
2906
3321
  * que é como o `pocketpal` monta todas as telas do Drawer).
2907
3322
  */
2908
3323
  componentFile(file2, node, hops = 0) {
2909
- if (!node || hops > MAX_HOPS) return null;
2910
- if (t5.isCallExpression(node)) {
3324
+ if (!node || hops > MAX_HOPS2) return null;
3325
+ if (t7.isCallExpression(node)) {
2911
3326
  for (const arg of node.arguments) {
2912
- if (t5.isIdentifier(arg) || t5.isMemberExpression(arg)) {
3327
+ if (t7.isIdentifier(arg) || t7.isMemberExpression(arg)) {
2913
3328
  const inner = this.componentFile(file2, arg, hops + 1);
2914
3329
  if (inner) return inner;
2915
3330
  }
2916
3331
  }
2917
3332
  return null;
2918
3333
  }
2919
- if (t5.isTSAsExpression(node)) return this.componentFile(file2, node.expression, hops + 1);
3334
+ if (t7.isTSAsExpression(node)) return this.componentFile(file2, node.expression, hops + 1);
2920
3335
  const chain = memberChain(node);
2921
3336
  if (!chain) return null;
2922
3337
  const origin = this.resolveBinding(file2, chain.root);
2923
3338
  if (!origin) return null;
2924
3339
  if (chain.path.length === 0) return origin.file;
2925
3340
  const init = this.topLevelInit(origin.file, origin.name);
2926
- if (init && t5.isObjectExpression(init)) {
3341
+ if (init && t7.isObjectExpression(init)) {
2927
3342
  const prop = objectProperty(init, chain.path[0]);
2928
3343
  if (prop) return this.componentFile(origin.file, prop, hops + 1);
2929
3344
  }
@@ -2946,7 +3361,7 @@ var ModuleGraph = class {
2946
3361
  const names = /* @__PURE__ */ new Set();
2947
3362
  const visit = (node) => {
2948
3363
  if (!node || typeof node !== "object") return;
2949
- if (t5.isJSXOpeningElement(node) && t5.isJSXIdentifier(node.name)) {
3364
+ if (t7.isJSXOpeningElement(node) && t7.isJSXIdentifier(node.name)) {
2950
3365
  const n = node.name.name;
2951
3366
  if (/^[A-Z]/.test(n)) names.add(n);
2952
3367
  }
@@ -2971,24 +3386,24 @@ var ModuleGraph = class {
2971
3386
  function memberChain(node) {
2972
3387
  const chain = [];
2973
3388
  let current = node;
2974
- while (t5.isMemberExpression(current)) {
3389
+ while (t7.isMemberExpression(current)) {
2975
3390
  if (current.computed) {
2976
- if (!t5.isStringLiteral(current.property)) return null;
3391
+ if (!t7.isStringLiteral(current.property)) return null;
2977
3392
  chain.unshift(current.property.value);
2978
- } else if (t5.isIdentifier(current.property)) {
3393
+ } else if (t7.isIdentifier(current.property)) {
2979
3394
  chain.unshift(current.property.name);
2980
3395
  } else {
2981
3396
  return null;
2982
3397
  }
2983
3398
  current = current.object;
2984
3399
  }
2985
- return t5.isIdentifier(current) ? { root: current.name, path: chain } : null;
3400
+ return t7.isIdentifier(current) ? { root: current.name, path: chain } : null;
2986
3401
  }
2987
3402
  function objectProperty(obj, key) {
2988
3403
  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;
3404
+ if (!t7.isObjectProperty(prop)) continue;
3405
+ const name = t7.isIdentifier(prop.key) ? prop.key.name : t7.isStringLiteral(prop.key) ? prop.key.value : null;
3406
+ if (name === key && t7.isExpression(prop.value)) return prop.value;
2992
3407
  }
2993
3408
  return null;
2994
3409
  }
@@ -3102,7 +3517,7 @@ function workspaceGlobs(dir) {
3102
3517
  }
3103
3518
  function expandWorkspaceGlobs(root, globs) {
3104
3519
  const out = [];
3105
- const add = (dir) => {
3520
+ const add2 = (dir) => {
3106
3521
  const pkgPath = import_node_path.default.join(dir, "package.json");
3107
3522
  if (!(0, import_node_fs.existsSync)(pkgPath)) return;
3108
3523
  try {
@@ -3111,9 +3526,9 @@ function expandWorkspaceGlobs(root, globs) {
3111
3526
  } catch {
3112
3527
  }
3113
3528
  };
3114
- for (const glob of globs) {
3115
- if (glob.endsWith("/*")) {
3116
- const parent = import_node_path.default.join(root, glob.slice(0, -2));
3529
+ for (const glob2 of globs) {
3530
+ if (glob2.endsWith("/*")) {
3531
+ const parent = import_node_path.default.join(root, glob2.slice(0, -2));
3117
3532
  let entries = [];
3118
3533
  try {
3119
3534
  entries = (0, import_node_fs.readdirSync)(parent);
@@ -3123,12 +3538,12 @@ function expandWorkspaceGlobs(root, globs) {
3123
3538
  for (const entry of entries) {
3124
3539
  const dir = import_node_path.default.join(parent, entry);
3125
3540
  try {
3126
- if ((0, import_node_fs.statSync)(dir).isDirectory()) add(dir);
3541
+ if ((0, import_node_fs.statSync)(dir).isDirectory()) add2(dir);
3127
3542
  } catch {
3128
3543
  }
3129
3544
  }
3130
- } else if (!glob.includes("*")) {
3131
- add(import_node_path.default.join(root, glob));
3545
+ } else if (!glob2.includes("*")) {
3546
+ add2(import_node_path.default.join(root, glob2));
3132
3547
  }
3133
3548
  }
3134
3549
  return out.sort((a, b) => b.name.length - a.name.length);
@@ -3249,19 +3664,19 @@ var NAVIGATOR_FACTORIES = {
3249
3664
  };
3250
3665
  var CUSTOM_FACTORY = /^create[A-Za-z0-9]*(Navigator|Stack|Tabs?|Drawer)$/;
3251
3666
  function unwrapStaticScreen(value) {
3252
- if (t6.isCallExpression(value)) {
3667
+ if (t8.isCallExpression(value)) {
3253
3668
  const arg = value.arguments[0];
3254
3669
  return arg ? unwrapStaticScreen(arg) : null;
3255
3670
  }
3256
- if (t6.isObjectExpression(value)) {
3671
+ if (t8.isObjectExpression(value)) {
3257
3672
  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;
3673
+ if (!t8.isObjectProperty(prop)) continue;
3674
+ const key = t8.isIdentifier(prop.key) ? prop.key.name : null;
3675
+ if (key === "screen" && t8.isExpression(prop.value)) return prop.value;
3261
3676
  }
3262
3677
  return null;
3263
3678
  }
3264
- return t6.isExpression(value) ? value : null;
3679
+ return t8.isExpression(value) ? value : null;
3265
3680
  }
3266
3681
  function inferNavigatorType(factoryName) {
3267
3682
  if (/drawer/i.test(factoryName)) return "drawer";
@@ -3452,24 +3867,24 @@ var NavigationAnalyzer = class {
3452
3867
  const ast = this.graph.parse(filePath);
3453
3868
  if (!ast) return [];
3454
3869
  const out = /* @__PURE__ */ new Map();
3455
- (0, import_traverse5.default)(ast, {
3870
+ (0, import_traverse6.default)(ast, {
3456
3871
  CallExpression: (nodePath) => {
3457
3872
  const callee = nodePath.node.callee;
3458
- if (!t6.isIdentifier(callee)) return;
3873
+ if (!t8.isIdentifier(callee)) return;
3459
3874
  const known = NAVIGATOR_FACTORIES[callee.name] ?? (CUSTOM_FACTORY.test(callee.name) ? inferNavigatorType(callee.name) : null);
3460
3875
  const type = known ?? inferNavigatorType(callee.name);
3461
3876
  const confident = known !== null;
3462
3877
  let up = nodePath.parentPath;
3463
3878
  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)) {
3879
+ if (t8.isVariableDeclarator(up.node)) break;
3880
+ if (!t8.isMemberExpression(up.node) && !t8.isCallExpression(up.node)) {
3466
3881
  up = null;
3467
3882
  break;
3468
3883
  }
3469
3884
  up = up.parentPath;
3470
3885
  }
3471
3886
  const declarator = up?.node;
3472
- if (!declarator || !t6.isVariableDeclarator(declarator) || !t6.isIdentifier(declarator.id)) {
3887
+ if (!declarator || !t8.isVariableDeclarator(declarator) || !t8.isIdentifier(declarator.id)) {
3473
3888
  return;
3474
3889
  }
3475
3890
  const name = declarator.id.name;
@@ -3499,15 +3914,15 @@ var NavigationAnalyzer = class {
3499
3914
  * e agrupar rotas não muda o que elas são.
3500
3915
  */
3501
3916
  parseStaticScreens(filePath, config, navigatorName, navigatorType, depth = 0) {
3502
- if (!config || !t6.isObjectExpression(config) || depth > 4) return [];
3917
+ if (!config || !t8.isObjectExpression(config) || depth > 4) return [];
3503
3918
  const out = [];
3504
3919
  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;
3920
+ if (!t8.isObjectProperty(prop)) continue;
3921
+ const key = t8.isIdentifier(prop.key) ? prop.key.name : t8.isStringLiteral(prop.key) ? prop.key.value : null;
3507
3922
  if (!key) continue;
3508
- if (key === "groups" && t6.isObjectExpression(prop.value)) {
3923
+ if (key === "groups" && t8.isObjectExpression(prop.value)) {
3509
3924
  for (const group of prop.value.properties) {
3510
- if (!t6.isObjectProperty(group) || !t6.isExpression(group.value)) continue;
3925
+ if (!t8.isObjectProperty(group) || !t8.isExpression(group.value)) continue;
3511
3926
  out.push(
3512
3927
  ...this.parseStaticScreens(
3513
3928
  filePath,
@@ -3520,10 +3935,10 @@ var NavigationAnalyzer = class {
3520
3935
  }
3521
3936
  continue;
3522
3937
  }
3523
- if (key !== "screens" || !t6.isObjectExpression(prop.value)) continue;
3938
+ if (key !== "screens" || !t8.isObjectExpression(prop.value)) continue;
3524
3939
  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;
3940
+ if (!t8.isObjectProperty(entry)) continue;
3941
+ const routeName = t8.isIdentifier(entry.key) ? entry.key.name : t8.isStringLiteral(entry.key) ? entry.key.value : null;
3527
3942
  if (!routeName) continue;
3528
3943
  const componentExpr = unwrapStaticScreen(entry.value);
3529
3944
  const componentFile = componentExpr ? this.graph.componentFile(filePath, componentExpr) : null;
@@ -3613,15 +4028,15 @@ var NavigationAnalyzer = class {
3613
4028
  const ast = this.graph.parse(filePath);
3614
4029
  if (!ast) return [];
3615
4030
  const found = /* @__PURE__ */ new Map();
3616
- (0, import_traverse5.default)(ast, {
4031
+ (0, import_traverse6.default)(ast, {
3617
4032
  JSXElement: (nodePath) => {
3618
4033
  const { node } = nodePath;
3619
4034
  const openingElement = node.openingElement;
3620
- if (!t6.isJSXMemberExpression(openingElement.name) || !t6.isJSXIdentifier(openingElement.name.object)) {
4035
+ if (!t8.isJSXMemberExpression(openingElement.name) || !t8.isJSXIdentifier(openingElement.name.object)) {
3621
4036
  return;
3622
4037
  }
3623
4038
  const objectName = openingElement.name.object.name;
3624
- const propertyName = t6.isJSXIdentifier(openingElement.name.property) ? openingElement.name.property.name : null;
4039
+ const propertyName = t8.isJSXIdentifier(openingElement.name.property) ? openingElement.name.property.name : null;
3625
4040
  if (propertyName !== "Navigator") return;
3626
4041
  const decl = this.resolveNavigator(filePath, objectName, declarations);
3627
4042
  if (!decl) return;
@@ -3631,9 +4046,9 @@ var NavigationAnalyzer = class {
3631
4046
  screens: []
3632
4047
  };
3633
4048
  const initialRouteAttr = openingElement.attributes.find(
3634
- (attr) => t6.isJSXAttribute(attr) && t6.isJSXIdentifier(attr.name) && attr.name.name === "initialRouteName"
4049
+ (attr) => t8.isJSXAttribute(attr) && t8.isJSXIdentifier(attr.name) && attr.name.name === "initialRouteName"
3635
4050
  );
3636
- if (t6.isJSXAttribute(initialRouteAttr)) {
4051
+ if (t8.isJSXAttribute(initialRouteAttr)) {
3637
4052
  const initial = this.attributeString(filePath, initialRouteAttr);
3638
4053
  if (initial) navigator.initialRouteName = initial;
3639
4054
  }
@@ -3685,15 +4100,15 @@ var NavigationAnalyzer = class {
3685
4100
  if (!ast) return [];
3686
4101
  const byNavigator = /* @__PURE__ */ new Map();
3687
4102
  const resolved = /* @__PURE__ */ new Map();
3688
- (0, import_traverse5.default)(ast, {
4103
+ (0, import_traverse6.default)(ast, {
3689
4104
  JSXElement: (nodePath) => {
3690
4105
  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;
4106
+ if (!t8.isJSXMemberExpression(name) || !t8.isJSXIdentifier(name.object)) return;
4107
+ if (!t8.isJSXIdentifier(name.property) || name.property.name !== "Screen") return;
3693
4108
  const insideNavigator = nodePath.findParent((parent) => {
3694
4109
  if (!parent.isJSXElement()) return false;
3695
4110
  const parentName = parent.node.openingElement.name;
3696
- return t6.isJSXMemberExpression(parentName) && t6.isJSXIdentifier(parentName.property) && parentName.property.name === "Navigator";
4111
+ return t8.isJSXMemberExpression(parentName) && t8.isJSXIdentifier(parentName.property) && parentName.property.name === "Navigator";
3697
4112
  });
3698
4113
  if (insideNavigator) return;
3699
4114
  const local = name.object.name;
@@ -3732,9 +4147,9 @@ var NavigationAnalyzer = class {
3732
4147
  const binding = nodePath.scope.getBinding(localName);
3733
4148
  if (!binding || binding.kind !== "param") return null;
3734
4149
  const param = binding.path.node;
3735
- if (!t6.isIdentifier(param) || !t6.isTSTypeAnnotation(param.typeAnnotation)) return null;
4150
+ if (!t8.isIdentifier(param) || !t8.isTSTypeAnnotation(param.typeAnnotation)) return null;
3736
4151
  const annotation = param.typeAnnotation.typeAnnotation;
3737
- if (!t6.isTSTypeQuery(annotation) || !t6.isIdentifier(annotation.exprName)) return null;
4152
+ if (!t8.isTSTypeQuery(annotation) || !t8.isIdentifier(annotation.exprName)) return null;
3738
4153
  return this.resolveNavigator(filePath, annotation.exprName.name, declarations);
3739
4154
  }
3740
4155
  /**
@@ -3755,8 +4170,8 @@ var NavigationAnalyzer = class {
3755
4170
  /** O valor string de um atributo JSX, resolvendo constante importada. */
3756
4171
  attributeString(filePath, attr) {
3757
4172
  const value = attr.value;
3758
- if (t6.isStringLiteral(value)) return value.value;
3759
- if (t6.isJSXExpressionContainer(value) && t6.isExpression(value.expression)) {
4173
+ if (t8.isStringLiteral(value)) return value.value;
4174
+ if (t8.isJSXExpressionContainer(value) && t8.isExpression(value.expression)) {
3760
4175
  return this.graph.stringConstant(filePath, value.expression);
3761
4176
  }
3762
4177
  return null;
@@ -3770,9 +4185,9 @@ var NavigationAnalyzer = class {
3770
4185
  // `never`. It is a question about the member name, not about the node
3771
4186
  // kind.
3772
4187
  isNavigatorMember(node, navigatorVarName, member) {
3773
- if (!t6.isJSXElement(node)) return false;
4188
+ if (!t8.isJSXElement(node)) return false;
3774
4189
  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;
4190
+ return t8.isJSXMemberExpression(name) && t8.isJSXIdentifier(name.object) && name.object.name === navigatorVarName && t8.isJSXIdentifier(name.property) && name.property.name === member;
3776
4191
  }
3777
4192
  /**
3778
4193
  * Flatten a navigator's JSX children into the `<X.Screen>` elements they
@@ -3803,37 +4218,37 @@ var NavigationAnalyzer = class {
3803
4218
  found.push(...this.collectScreenElements(group.children, navigatorVarName, depth + 1));
3804
4219
  return;
3805
4220
  }
3806
- if (t6.isJSXElement(node)) {
4221
+ if (t8.isJSXElement(node)) {
3807
4222
  const name = node.openingElement.name;
3808
- const isForeignNavigator = t6.isJSXMemberExpression(name) && t6.isJSXIdentifier(name.property) && name.property.name === "Navigator";
4223
+ const isForeignNavigator = t8.isJSXMemberExpression(name) && t8.isJSXIdentifier(name.property) && name.property.name === "Navigator";
3809
4224
  if (isForeignNavigator) return;
3810
4225
  found.push(...this.collectScreenElements(node.children, navigatorVarName, depth + 1));
3811
4226
  return;
3812
4227
  }
3813
- if (t6.isJSXFragment(node)) {
4228
+ if (t8.isJSXFragment(node)) {
3814
4229
  found.push(...this.collectScreenElements(node.children, navigatorVarName, depth + 1));
3815
4230
  return;
3816
4231
  }
3817
- if (t6.isJSXExpressionContainer(node)) {
4232
+ if (t8.isJSXExpressionContainer(node)) {
3818
4233
  visit(node.expression);
3819
4234
  return;
3820
4235
  }
3821
- if (t6.isConditionalExpression(node)) {
4236
+ if (t8.isConditionalExpression(node)) {
3822
4237
  visit(node.consequent);
3823
4238
  visit(node.alternate);
3824
4239
  return;
3825
4240
  }
3826
- if (t6.isLogicalExpression(node)) {
4241
+ if (t8.isLogicalExpression(node)) {
3827
4242
  visit(node.left);
3828
4243
  visit(node.right);
3829
4244
  return;
3830
4245
  }
3831
- if (t6.isCallExpression(node)) {
4246
+ if (t8.isCallExpression(node)) {
3832
4247
  for (const arg of node.arguments) {
3833
- if (t6.isArrowFunctionExpression(arg) || t6.isFunctionExpression(arg)) {
3834
- if (t6.isBlockStatement(arg.body)) {
4248
+ if (t8.isArrowFunctionExpression(arg) || t8.isFunctionExpression(arg)) {
4249
+ if (t8.isBlockStatement(arg.body)) {
3835
4250
  for (const stmt of arg.body.body) {
3836
- if (t6.isReturnStatement(stmt)) visit(stmt.argument);
4251
+ if (t8.isReturnStatement(stmt)) visit(stmt.argument);
3837
4252
  }
3838
4253
  } else {
3839
4254
  visit(arg.body);
@@ -3842,11 +4257,11 @@ var NavigationAnalyzer = class {
3842
4257
  }
3843
4258
  return;
3844
4259
  }
3845
- if (t6.isArrayExpression(node)) {
4260
+ if (t8.isArrayExpression(node)) {
3846
4261
  for (const el of node.elements) visit(el);
3847
4262
  return;
3848
4263
  }
3849
- if (t6.isTSAsExpression(node) || t6.isTSNonNullExpression(node)) {
4264
+ if (t8.isTSAsExpression(node) || t8.isTSNonNullExpression(node)) {
3850
4265
  visit(node.expression);
3851
4266
  }
3852
4267
  };
@@ -3876,17 +4291,17 @@ var NavigationAnalyzer = class {
3876
4291
  parseScreenElement(filePath, element, navigatorName, navigatorType) {
3877
4292
  const attrs = element.openingElement.attributes;
3878
4293
  const nameAttr = attrs.find(
3879
- (a) => t6.isJSXAttribute(a) && t6.isJSXIdentifier(a.name) && a.name.name === "name"
4294
+ (a) => t8.isJSXAttribute(a) && t8.isJSXIdentifier(a.name) && a.name.name === "name"
3880
4295
  );
3881
- const screenName = t6.isJSXAttribute(nameAttr) ? this.attributeString(filePath, nameAttr) : null;
4296
+ const screenName = t8.isJSXAttribute(nameAttr) ? this.attributeString(filePath, nameAttr) : null;
3882
4297
  if (!screenName) return null;
3883
4298
  const componentAttr = attrs.find(
3884
- (a) => t6.isJSXAttribute(a) && t6.isJSXIdentifier(a.name) && a.name.name === "component"
4299
+ (a) => t8.isJSXAttribute(a) && t8.isJSXIdentifier(a.name) && a.name.name === "component"
3885
4300
  );
3886
4301
  let componentFile = null;
3887
- if (t6.isJSXAttribute(componentAttr) && t6.isJSXExpressionContainer(componentAttr.value)) {
4302
+ if (t8.isJSXAttribute(componentAttr) && t8.isJSXExpressionContainer(componentAttr.value)) {
3888
4303
  const expr = componentAttr.value.expression;
3889
- if (t6.isExpression(expr)) componentFile = this.graph.componentFile(filePath, expr);
4304
+ if (t8.isExpression(expr)) componentFile = this.graph.componentFile(filePath, expr);
3890
4305
  }
3891
4306
  if (componentFile) this.routeTargets.set(screenName, componentFile);
3892
4307
  return {
@@ -3899,9 +4314,9 @@ var NavigationAnalyzer = class {
3899
4314
  /** Extract string attribute value from JSX attributes */
3900
4315
  extractAttributeValue(attributes, attrName) {
3901
4316
  const attr = attributes.find(
3902
- (a) => t6.isJSXAttribute(a) && t6.isJSXIdentifier(a.name) && a.name.name === attrName
4317
+ (a) => t8.isJSXAttribute(a) && t8.isJSXIdentifier(a.name) && a.name.name === attrName
3903
4318
  );
3904
- if (t6.isJSXAttribute(attr) && t6.isStringLiteral(attr.value)) {
4319
+ if (t8.isJSXAttribute(attr) && t8.isStringLiteral(attr.value)) {
3905
4320
  return attr.value.value;
3906
4321
  }
3907
4322
  return null;
@@ -3918,7 +4333,7 @@ var NavigationAnalyzer = class {
3918
4333
  ...this.config.parserPlugins || []
3919
4334
  ]
3920
4335
  });
3921
- (0, import_traverse5.default)(ast, {
4336
+ (0, import_traverse6.default)(ast, {
3922
4337
  TSTypeAliasDeclaration: (nodePath) => {
3923
4338
  const { node } = nodePath;
3924
4339
  const typeName = node.id.name;
@@ -3991,7 +4406,7 @@ var NavigationAnalyzer = class {
3991
4406
  if (type.type === "TSUndefinedKeyword") return "undefined";
3992
4407
  if (type.type === "TSNullKeyword") return "null";
3993
4408
  if (type.type === "TSUnionType") {
3994
- return type.types.map((t16) => this.typeToString(t16)).join(" | ");
4409
+ return type.types.map((t18) => this.typeToString(t18)).join(" | ");
3995
4410
  }
3996
4411
  if (type.type === "TSTypeLiteral") {
3997
4412
  return "object";
@@ -4012,7 +4427,7 @@ var NavigationAnalyzer = class {
4012
4427
  /** Attach parsed type params to navigator screens */
4013
4428
  attachParamsToNavigators(navigators, types) {
4014
4429
  for (const navigator of navigators) {
4015
- const matchingType = types.find((t16) => t16.type === navigator.type);
4430
+ const matchingType = types.find((t18) => t18.type === navigator.type);
4016
4431
  if (matchingType) {
4017
4432
  for (const screen of navigator.screens) {
4018
4433
  const screenParams = matchingType.paramEntries.get(screen.name);
@@ -4091,8 +4506,8 @@ var NavigationAnalyzer = class {
4091
4506
  // src/analyzers/ComponentAnalyzer.ts
4092
4507
  var import_fs5 = require("fs");
4093
4508
  var parser3 = __toESM(require("@babel/parser"));
4094
- var import_traverse6 = __toESM(require("@babel/traverse"));
4095
- var t7 = __toESM(require("@babel/types"));
4509
+ var import_traverse7 = __toESM(require("@babel/traverse"));
4510
+ var t9 = __toESM(require("@babel/types"));
4096
4511
  var ComponentAnalyzer = class {
4097
4512
  config;
4098
4513
  constructor(config) {
@@ -4107,7 +4522,7 @@ var ComponentAnalyzer = class {
4107
4522
  plugins: ["jsx", "typescript", ["decorators", { decoratorsBeforeExport: true }]]
4108
4523
  });
4109
4524
  const components = [];
4110
- (0, import_traverse6.default)(ast, {
4525
+ (0, import_traverse7.default)(ast, {
4111
4526
  JSXElement: (path13) => {
4112
4527
  const component = this.extractComponentFromJSXElement(path13.node);
4113
4528
  if (component) {
@@ -4138,19 +4553,19 @@ var ComponentAnalyzer = class {
4138
4553
  };
4139
4554
  }
4140
4555
  getElementName(openingElement) {
4141
- if (t7.isJSXIdentifier(openingElement.name)) {
4556
+ if (t9.isJSXIdentifier(openingElement.name)) {
4142
4557
  return openingElement.name.name;
4143
4558
  }
4144
- if (t7.isJSXMemberExpression(openingElement.name)) {
4559
+ if (t9.isJSXMemberExpression(openingElement.name)) {
4145
4560
  const parts = [];
4146
4561
  let current = openingElement.name;
4147
- while (t7.isJSXMemberExpression(current)) {
4148
- if (t7.isJSXIdentifier(current.property)) {
4562
+ while (t9.isJSXMemberExpression(current)) {
4563
+ if (t9.isJSXIdentifier(current.property)) {
4149
4564
  parts.unshift(current.property.name);
4150
4565
  }
4151
4566
  current = current.object;
4152
4567
  }
4153
- if (t7.isJSXIdentifier(current)) {
4568
+ if (t9.isJSXIdentifier(current)) {
4154
4569
  parts.unshift(current.name);
4155
4570
  }
4156
4571
  return parts.join(".");
@@ -4173,13 +4588,13 @@ var ComponentAnalyzer = class {
4173
4588
  extractProps(openingElement) {
4174
4589
  const props = {};
4175
4590
  for (const attr of openingElement.attributes) {
4176
- if (t7.isJSXAttribute(attr) && t7.isJSXIdentifier(attr.name)) {
4591
+ if (t9.isJSXAttribute(attr) && t9.isJSXIdentifier(attr.name)) {
4177
4592
  const propName = attr.name.name;
4178
4593
  if (attr.value === null) {
4179
4594
  props[propName] = "true";
4180
- } else if (t7.isStringLiteral(attr.value)) {
4595
+ } else if (t9.isStringLiteral(attr.value)) {
4181
4596
  props[propName] = attr.value.value;
4182
- } else if (t7.isJSXExpressionContainer(attr.value) && t7.isStringLiteral(attr.value.expression)) {
4597
+ } else if (t9.isJSXExpressionContainer(attr.value) && t9.isStringLiteral(attr.value.expression)) {
4183
4598
  props[propName] = attr.value.expression.value;
4184
4599
  }
4185
4600
  }
@@ -4189,12 +4604,12 @@ var ComponentAnalyzer = class {
4189
4604
  extractAccessibilityProps(openingElement) {
4190
4605
  const result = {};
4191
4606
  for (const attr of openingElement.attributes) {
4192
- if (t7.isJSXAttribute(attr) && t7.isJSXIdentifier(attr.name)) {
4607
+ if (t9.isJSXAttribute(attr) && t9.isJSXIdentifier(attr.name)) {
4193
4608
  const propName = attr.name.name;
4194
4609
  if ((propName === "testID" || propName === "accessibilityLabel") && attr.value) {
4195
- if (t7.isStringLiteral(attr.value)) {
4610
+ if (t9.isStringLiteral(attr.value)) {
4196
4611
  result[propName] = attr.value.value;
4197
- } else if (t7.isJSXExpressionContainer(attr.value) && t7.isStringLiteral(attr.value.expression)) {
4612
+ } else if (t9.isJSXExpressionContainer(attr.value) && t9.isStringLiteral(attr.value.expression)) {
4198
4613
  result[propName] = attr.value.expression.value;
4199
4614
  }
4200
4615
  }
@@ -4206,7 +4621,7 @@ var ComponentAnalyzer = class {
4206
4621
  if (depth >= maxDepth) return [];
4207
4622
  const extracted = [];
4208
4623
  for (const child of children) {
4209
- if (t7.isJSXElement(child)) {
4624
+ if (t9.isJSXElement(child)) {
4210
4625
  const component = this.extractComponentFromJSXElement(child);
4211
4626
  if (component) {
4212
4627
  extracted.push(component);
@@ -4220,8 +4635,8 @@ var ComponentAnalyzer = class {
4220
4635
  // src/analyzers/FormAnalyzer.ts
4221
4636
  var import_fs6 = require("fs");
4222
4637
  var parser4 = __toESM(require("@babel/parser"));
4223
- var import_traverse7 = __toESM(require("@babel/traverse"));
4224
- var t8 = __toESM(require("@babel/types"));
4638
+ var import_traverse8 = __toESM(require("@babel/traverse"));
4639
+ var t10 = __toESM(require("@babel/types"));
4225
4640
  var path5 = __toESM(require("path"));
4226
4641
  var FormAnalyzer = class {
4227
4642
  config;
@@ -4242,12 +4657,12 @@ var FormAnalyzer = class {
4242
4657
  this.stateVariables.clear();
4243
4658
  this.inputElements = [];
4244
4659
  this.submitButtons = [];
4245
- (0, import_traverse7.default)(ast, {
4660
+ (0, import_traverse8.default)(ast, {
4246
4661
  CallExpression: (path13) => {
4247
4662
  this.extractStateVariables(path13.node);
4248
4663
  }
4249
4664
  });
4250
- (0, import_traverse7.default)(ast, {
4665
+ (0, import_traverse8.default)(ast, {
4251
4666
  JSXElement: (path13) => {
4252
4667
  this.extractFormElements(path13.node);
4253
4668
  }
@@ -4260,7 +4675,7 @@ var FormAnalyzer = class {
4260
4675
  }
4261
4676
  }
4262
4677
  extractStateVariables(node) {
4263
- if (t8.isIdentifier(node.callee) && node.callee.name === "useState" && node.arguments.length > 0) {
4678
+ if (t10.isIdentifier(node.callee) && node.callee.name === "useState" && node.arguments.length > 0) {
4264
4679
  return;
4265
4680
  }
4266
4681
  }
@@ -4281,28 +4696,28 @@ var FormAnalyzer = class {
4281
4696
  extractInputInfo(openingElement) {
4282
4697
  const info2 = { varName: "" };
4283
4698
  for (const attr of openingElement.attributes) {
4284
- if (t8.isJSXAttribute(attr) && t8.isJSXIdentifier(attr.name)) {
4699
+ if (t10.isJSXAttribute(attr) && t10.isJSXIdentifier(attr.name)) {
4285
4700
  const propName = attr.name.name;
4286
- const propValue = this.extractAttributeValue(attr.value);
4701
+ const propValue2 = this.extractAttributeValue(attr.value);
4287
4702
  switch (propName) {
4288
4703
  case "label":
4289
- info2.label = propValue;
4704
+ info2.label = propValue2;
4290
4705
  break;
4291
4706
  case "placeholder":
4292
- info2.placeholder = propValue;
4707
+ info2.placeholder = propValue2;
4293
4708
  break;
4294
4709
  case "keyboardType":
4295
- info2.keyboardType = propValue;
4710
+ info2.keyboardType = propValue2;
4296
4711
  break;
4297
4712
  case "testID":
4298
- info2.testID = propValue;
4713
+ info2.testID = propValue2;
4299
4714
  break;
4300
4715
  case "appilotsId":
4301
- info2.appilotsId = propValue;
4302
- if (propValue) info2.varName = propValue;
4716
+ info2.appilotsId = propValue2;
4717
+ if (propValue2) info2.varName = propValue2;
4303
4718
  break;
4304
4719
  case "value":
4305
- if (attr.value && t8.isJSXExpressionContainer(attr.value) && t8.isIdentifier(attr.value.expression)) {
4720
+ if (attr.value && t10.isJSXExpressionContainer(attr.value) && t10.isIdentifier(attr.value.expression)) {
4306
4721
  info2.varName = attr.value.expression.name;
4307
4722
  }
4308
4723
  break;
@@ -4314,16 +4729,16 @@ var FormAnalyzer = class {
4314
4729
  extractButtonInfo(openingElement) {
4315
4730
  const info2 = {};
4316
4731
  for (const attr of openingElement.attributes) {
4317
- if (t8.isJSXAttribute(attr) && t8.isJSXIdentifier(attr.name)) {
4732
+ if (t10.isJSXAttribute(attr) && t10.isJSXIdentifier(attr.name)) {
4318
4733
  const propName = attr.name.name;
4319
4734
  if (propName === "title" || propName === "label") {
4320
4735
  info2.label = this.extractAttributeValue(attr.value);
4321
4736
  }
4322
4737
  if (propName === "onPress") {
4323
- if (attr.value && t8.isJSXExpressionContainer(attr.value)) {
4324
- if (t8.isIdentifier(attr.value.expression)) {
4738
+ if (attr.value && t10.isJSXExpressionContainer(attr.value)) {
4739
+ if (t10.isIdentifier(attr.value.expression)) {
4325
4740
  info2.handler = attr.value.expression.name;
4326
- } else if (t8.isArrowFunctionExpression(attr.value.expression) || t8.isFunctionExpression(attr.value.expression)) {
4741
+ } else if (t10.isArrowFunctionExpression(attr.value.expression) || t10.isFunctionExpression(attr.value.expression)) {
4327
4742
  info2.handler = "anonymous";
4328
4743
  }
4329
4744
  }
@@ -4334,21 +4749,21 @@ var FormAnalyzer = class {
4334
4749
  }
4335
4750
  extractAttributeValue(value) {
4336
4751
  if (value === null) return void 0;
4337
- if (t8.isStringLiteral(value)) return value.value;
4338
- if (t8.isJSXExpressionContainer(value) && t8.isStringLiteral(value.expression)) {
4752
+ if (t10.isStringLiteral(value)) return value.value;
4753
+ if (t10.isJSXExpressionContainer(value) && t10.isStringLiteral(value.expression)) {
4339
4754
  return value.expression.value;
4340
4755
  }
4341
4756
  return void 0;
4342
4757
  }
4343
4758
  getElementName(openingElement) {
4344
- if (t8.isJSXIdentifier(openingElement.name)) {
4759
+ if (t10.isJSXIdentifier(openingElement.name)) {
4345
4760
  return openingElement.name.name;
4346
4761
  }
4347
4762
  return null;
4348
4763
  }
4349
4764
  extractValidationRules(ast) {
4350
4765
  const rules = {};
4351
- (0, import_traverse7.default)(ast, {
4766
+ (0, import_traverse8.default)(ast, {
4352
4767
  IfStatement: (path13) => {
4353
4768
  const test = path13.node.test;
4354
4769
  const rule = this.extractRuleFromCondition(test);
@@ -4365,36 +4780,36 @@ var FormAnalyzer = class {
4365
4780
  extractRuleFromCondition(test) {
4366
4781
  let fieldName = "";
4367
4782
  let description = "";
4368
- if (t8.isUnaryExpression(test) && test.operator === "!") {
4369
- if (t8.isCallExpression(test.argument)) {
4783
+ if (t10.isUnaryExpression(test) && test.operator === "!") {
4784
+ if (t10.isCallExpression(test.argument)) {
4370
4785
  const callExpr = test.argument;
4371
- if (t8.isMemberExpression(callExpr.callee)) {
4786
+ if (t10.isMemberExpression(callExpr.callee)) {
4372
4787
  const memberExpr = callExpr.callee;
4373
- if (t8.isIdentifier(memberExpr.object)) {
4788
+ if (t10.isIdentifier(memberExpr.object)) {
4374
4789
  fieldName = memberExpr.object.name;
4375
4790
  description = `${fieldName} is required`;
4376
4791
  }
4377
4792
  }
4378
- } else if (t8.isIdentifier(test.argument)) {
4793
+ } else if (t10.isIdentifier(test.argument)) {
4379
4794
  fieldName = test.argument.name;
4380
4795
  description = `${fieldName} is required`;
4381
4796
  }
4382
4797
  }
4383
- if (t8.isBinaryExpression(test) && (test.operator === "<" || test.operator === "<=")) {
4384
- if (t8.isMemberExpression(test.left)) {
4798
+ if (t10.isBinaryExpression(test) && (test.operator === "<" || test.operator === "<=")) {
4799
+ if (t10.isMemberExpression(test.left)) {
4385
4800
  const memberExpr = test.left;
4386
- if (t8.isIdentifier(memberExpr.object)) {
4801
+ if (t10.isIdentifier(memberExpr.object)) {
4387
4802
  fieldName = memberExpr.object.name;
4388
- if (t8.isNumericLiteral(test.right)) {
4803
+ if (t10.isNumericLiteral(test.right)) {
4389
4804
  description = `${fieldName} must be at least ${test.right.value} characters`;
4390
4805
  }
4391
4806
  }
4392
4807
  }
4393
4808
  }
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)) {
4809
+ if (t10.isUnaryExpression(test) && test.operator === "!") {
4810
+ if (t10.isCallExpression(test.argument) && t10.isMemberExpression(test.argument.callee)) {
4811
+ const methodName = t10.isIdentifier(test.argument.callee.property) ? test.argument.callee.property.name : null;
4812
+ if (methodName === "includes" && t10.isIdentifier(test.argument.callee.object)) {
4398
4813
  fieldName = test.argument.callee.object.name;
4399
4814
  description = `${fieldName} format is invalid`;
4400
4815
  }
@@ -4502,7 +4917,7 @@ async function composeAffordances(options) {
4502
4917
  const exclusive = children.filter((c) => (fanIn.get(c) ?? 0) <= MAX_FAN_IN);
4503
4918
  if (exclusive.length === 0) continue;
4504
4919
  const actionIds = new Set(screen.actions.map((a) => a.id));
4505
- const targetIds = new Set((screen.targets ?? []).map((t16) => t16.id));
4920
+ const targetIds = new Set((screen.targets ?? []).map((t18) => t18.id));
4506
4921
  const formIds = new Set(screen.forms.map((f) => f.id));
4507
4922
  let gained = false;
4508
4923
  for (const file2 of exclusive) {
@@ -4644,6 +5059,7 @@ var ReactNativePlatformAnalyzer = class {
4644
5059
  });
4645
5060
  return {
4646
5061
  screens: enrichedScreens,
5062
+ controlEvidenceFiles: screenAnalyzer.controlEvidenceFiles,
4647
5063
  navigation,
4648
5064
  analyzedFiles: screenFiles.length,
4649
5065
  ...screenAnalyzer.screensFilteredOut > 0 ? { screensFilteredOut: screenAnalyzer.screensFilteredOut } : {},
@@ -4732,8 +5148,8 @@ var GenericPlatformAnalyzer = class {
4732
5148
  // src/analyzers/web/WebScreenAnalyzer.ts
4733
5149
  var import_promises2 = __toESM(require("fs/promises"));
4734
5150
  var import_path5 = __toESM(require("path"));
4735
- var import_traverse9 = __toESM(require("@babel/traverse"));
4736
- var t11 = __toESM(require("@babel/types"));
5151
+ var import_traverse10 = __toESM(require("@babel/traverse"));
5152
+ var t13 = __toESM(require("@babel/types"));
4737
5153
 
4738
5154
  // src/ast/jsx/web/classify.ts
4739
5155
  var VIEW_TAGS = /* @__PURE__ */ new Set([
@@ -4849,29 +5265,29 @@ function classifyWebJsxComponent(name, element) {
4849
5265
  }
4850
5266
 
4851
5267
  // src/ast/jsx/names.ts
4852
- var t9 = __toESM(require("@babel/types"));
5268
+ var t11 = __toESM(require("@babel/types"));
4853
5269
  function getJsxElementName(openingElement) {
4854
5270
  return getJsxName(openingElement.name);
4855
5271
  }
4856
5272
  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)) {
5273
+ if (t11.isJSXIdentifier(name)) return name.name;
5274
+ if (t11.isJSXNamespacedName(name)) return `${name.namespace.name}:${name.name.name}`;
5275
+ if (t11.isJSXMemberExpression(name)) {
4860
5276
  const objectName = getJsxName(name.object);
4861
- const propertyName = t9.isJSXIdentifier(name.property) ? name.property.name : null;
5277
+ const propertyName = t11.isJSXIdentifier(name.property) ? name.property.name : null;
4862
5278
  return objectName && propertyName ? `${objectName}.${propertyName}` : null;
4863
5279
  }
4864
5280
  return null;
4865
5281
  }
4866
5282
 
4867
5283
  // src/ast/navigation/web-calls.ts
4868
- var import_traverse8 = __toESM(require("@babel/traverse"));
4869
- var t10 = __toESM(require("@babel/types"));
5284
+ var import_traverse9 = __toESM(require("@babel/traverse"));
5285
+ var t12 = __toESM(require("@babel/types"));
4870
5286
  var ROUTERISH_OBJECTS = /^(router|history|navigation)$/;
4871
5287
  function staticRoutePath(node) {
4872
5288
  if (!node) return void 0;
4873
- if (t10.isStringLiteral(node)) return node.value;
4874
- if (t10.isTemplateLiteral(node)) {
5289
+ if (t12.isStringLiteral(node)) return node.value;
5290
+ if (t12.isTemplateLiteral(node)) {
4875
5291
  let path13 = "";
4876
5292
  node.quasis.forEach((quasi, index) => {
4877
5293
  path13 += quasi.value.cooked ?? quasi.value.raw;
@@ -4883,15 +5299,15 @@ function staticRoutePath(node) {
4883
5299
  return void 0;
4884
5300
  }
4885
5301
  function paramNameOf(expr) {
4886
- if (t10.isIdentifier(expr)) return expr.name;
4887
- if (t10.isMemberExpression(expr) && t10.isIdentifier(expr.property)) return expr.property.name;
5302
+ if (t12.isIdentifier(expr)) return expr.name;
5303
+ if (t12.isMemberExpression(expr) && t12.isIdentifier(expr.property)) return expr.property.name;
4888
5304
  return "param";
4889
5305
  }
4890
5306
  function extractWebNavigationCalls(ast) {
4891
5307
  const calls = [];
4892
5308
  const inspect = (node) => {
4893
- if (t10.isCallExpression(node)) {
4894
- if (t10.isIdentifier(node.callee) && node.callee.name === "navigate") {
5309
+ if (t12.isCallExpression(node)) {
5310
+ if (t12.isIdentifier(node.callee) && node.callee.name === "navigate") {
4895
5311
  const first = node.arguments[0];
4896
5312
  const targetPath = staticRoutePath(first);
4897
5313
  if (targetPath !== void 0) {
@@ -4899,12 +5315,12 @@ function extractWebNavigationCalls(ast) {
4899
5315
  method: hasReplaceOption(node.arguments[1]) ? "replace" : "navigate",
4900
5316
  targetPath
4901
5317
  });
4902
- } else if (t10.isNumericLiteral(first) || t10.isUnaryExpression(first) && first.operator === "-") {
5318
+ } else if (t12.isNumericLiteral(first) || t12.isUnaryExpression(first) && first.operator === "-") {
4903
5319
  calls.push({ method: "goBack" });
4904
5320
  }
4905
5321
  return;
4906
5322
  }
4907
- if (t10.isMemberExpression(node.callee) && t10.isIdentifier(node.callee.object) && ROUTERISH_OBJECTS.test(node.callee.object.name) && t10.isIdentifier(node.callee.property)) {
5323
+ if (t12.isMemberExpression(node.callee) && t12.isIdentifier(node.callee.object) && ROUTERISH_OBJECTS.test(node.callee.object.name) && t12.isIdentifier(node.callee.property)) {
4908
5324
  const method = node.callee.property.name;
4909
5325
  const targetPath = staticRoutePath(node.arguments[0]);
4910
5326
  if ((method === "push" || method === "navigate") && targetPath !== void 0) {
@@ -4917,25 +5333,25 @@ function extractWebNavigationCalls(ast) {
4917
5333
  }
4918
5334
  return;
4919
5335
  }
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("/")) {
5336
+ 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
5337
  calls.push({ method: "navigate", targetPath: node.right.value });
4922
5338
  }
4923
5339
  };
4924
- (0, import_traverse8.default)(ast, {
4925
- noScope: !t10.isFile(ast),
5340
+ (0, import_traverse9.default)(ast, {
5341
+ noScope: !t12.isFile(ast),
4926
5342
  enter: (nodePath) => inspect(nodePath.node)
4927
5343
  });
4928
5344
  return calls;
4929
5345
  }
4930
5346
  function hasReplaceOption(arg) {
4931
- if (!arg || !t10.isObjectExpression(arg)) return false;
5347
+ if (!arg || !t12.isObjectExpression(arg)) return false;
4932
5348
  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
5349
+ (prop) => t12.isObjectProperty(prop) && t12.isIdentifier(prop.key) && prop.key.name === "replace" && t12.isBooleanLiteral(prop.value) && prop.value.value === true
4934
5350
  );
4935
5351
  }
4936
5352
  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";
5353
+ if (t12.isIdentifier(node)) return node.name === "location";
5354
+ return t12.isMemberExpression(node) && t12.isIdentifier(node.object) && node.object.name === "window" && t12.isIdentifier(node.property) && node.property.name === "location";
4939
5355
  }
4940
5356
 
4941
5357
  // src/analyzers/web/WebScreenAnalyzer.ts
@@ -5043,7 +5459,7 @@ var WebScreenAnalyzer = class {
5043
5459
  // ── registerScreen ────────────────────────────────────────────────
5044
5460
  detectRegisterScreenCall(ast) {
5045
5461
  let found = false;
5046
- (0, import_traverse9.default)(ast, {
5462
+ (0, import_traverse10.default)(ast, {
5047
5463
  CallExpression: (nodePath) => {
5048
5464
  if (found) return;
5049
5465
  if (isRegisterScreenCallee(nodePath.node.callee)) {
@@ -5056,11 +5472,11 @@ var WebScreenAnalyzer = class {
5056
5472
  }
5057
5473
  extractRegisterScreenMetadata(ast) {
5058
5474
  let plain = null;
5059
- (0, import_traverse9.default)(ast, {
5475
+ (0, import_traverse10.default)(ast, {
5060
5476
  CallExpression: (nodePath) => {
5061
5477
  if (!isRegisterScreenCallee(nodePath.node.callee)) return;
5062
5478
  const arg = nodePath.node.arguments[0];
5063
- if (t11.isObjectExpression(arg)) {
5479
+ if (t13.isObjectExpression(arg)) {
5064
5480
  plain = literalToPlain(arg);
5065
5481
  }
5066
5482
  }
@@ -5104,23 +5520,23 @@ var WebScreenAnalyzer = class {
5104
5520
  extractComponentName(ast) {
5105
5521
  let defaultName = "";
5106
5522
  let firstExported = "";
5107
- (0, import_traverse9.default)(ast, {
5523
+ (0, import_traverse10.default)(ast, {
5108
5524
  ExportDefaultDeclaration: (nodePath) => {
5109
5525
  const declaration = nodePath.node.declaration;
5110
- if (t11.isFunctionDeclaration(declaration) && declaration.id?.name) {
5526
+ if (t13.isFunctionDeclaration(declaration) && declaration.id?.name) {
5111
5527
  defaultName = declaration.id.name;
5112
- } else if (t11.isIdentifier(declaration)) {
5528
+ } else if (t13.isIdentifier(declaration)) {
5113
5529
  defaultName = declaration.name;
5114
5530
  }
5115
5531
  },
5116
5532
  ExportNamedDeclaration: (nodePath) => {
5117
5533
  if (firstExported) return;
5118
5534
  const declaration = nodePath.node.declaration;
5119
- if (t11.isFunctionDeclaration(declaration) && declaration.id && /^[A-Z]/.test(declaration.id.name)) {
5535
+ if (t13.isFunctionDeclaration(declaration) && declaration.id && /^[A-Z]/.test(declaration.id.name)) {
5120
5536
  firstExported = declaration.id.name;
5121
- } else if (t11.isVariableDeclaration(declaration)) {
5537
+ } else if (t13.isVariableDeclaration(declaration)) {
5122
5538
  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))) {
5539
+ if (t13.isIdentifier(declarator.id) && /^[A-Z]/.test(declarator.id.name) && (t13.isArrowFunctionExpression(declarator.init) || t13.isFunctionExpression(declarator.init))) {
5124
5540
  firstExported = declarator.id.name;
5125
5541
  break;
5126
5542
  }
@@ -5133,7 +5549,7 @@ var WebScreenAnalyzer = class {
5133
5549
  extractComponents(ast) {
5134
5550
  const components = [];
5135
5551
  const seen = /* @__PURE__ */ new Set();
5136
- (0, import_traverse9.default)(ast, {
5552
+ (0, import_traverse10.default)(ast, {
5137
5553
  JSXOpeningElement: (nodePath) => {
5138
5554
  const element = nodePath.node;
5139
5555
  const name = getJsxElementName(element);
@@ -5154,7 +5570,7 @@ var WebScreenAnalyzer = class {
5154
5570
  // ── <label htmlFor> association ───────────────────────────────────
5155
5571
  collectHtmlForLabels(ast) {
5156
5572
  const labels = /* @__PURE__ */ new Map();
5157
- (0, import_traverse9.default)(ast, {
5573
+ (0, import_traverse10.default)(ast, {
5158
5574
  JSXElement: (nodePath) => {
5159
5575
  const element = nodePath.node;
5160
5576
  if (getJsxElementName(element.openingElement) !== "label") return;
@@ -5197,7 +5613,7 @@ var WebScreenAnalyzer = class {
5197
5613
  formBuckets.set(formElement, bucket);
5198
5614
  return bucket;
5199
5615
  };
5200
- (0, import_traverse9.default)(ast, {
5616
+ (0, import_traverse10.default)(ast, {
5201
5617
  JSXElement: (nodePath) => {
5202
5618
  const element = nodePath.node;
5203
5619
  const name = getJsxElementName(element.openingElement);
@@ -5214,7 +5630,7 @@ var WebScreenAnalyzer = class {
5214
5630
  if (!bucket.fields.has(field.name)) bucket.fields.set(field.name, field);
5215
5631
  }
5216
5632
  });
5217
- (0, import_traverse9.default)(ast, {
5633
+ (0, import_traverse10.default)(ast, {
5218
5634
  JSXElement: (nodePath) => {
5219
5635
  const element = nodePath.node;
5220
5636
  const name = getJsxElementName(element.openingElement);
@@ -5292,15 +5708,15 @@ var WebScreenAnalyzer = class {
5292
5708
  });
5293
5709
  }
5294
5710
  for (const attr of opening.attributes) {
5295
- if (!t11.isJSXAttribute(attr) || !t11.isJSXIdentifier(attr.name)) continue;
5711
+ if (!t13.isJSXAttribute(attr) || !t13.isJSXIdentifier(attr.name)) continue;
5296
5712
  const attrName = attr.name.name;
5297
5713
  if (attrName === "required") {
5298
5714
  if (attr.value === null) field.required = true;
5299
- else if (t11.isJSXExpressionContainer(attr.value) && t11.isBooleanLiteral(attr.value.expression)) {
5715
+ else if (t13.isJSXExpressionContainer(attr.value) && t13.isBooleanLiteral(attr.value.expression)) {
5300
5716
  field.required = attr.value.expression.value;
5301
5717
  }
5302
5718
  }
5303
- if ((attrName === "value" || attrName === "checked") && attr.value && t11.isJSXExpressionContainer(attr.value) && t11.isIdentifier(attr.value.expression)) {
5719
+ if ((attrName === "value" || attrName === "checked") && attr.value && t13.isJSXExpressionContainer(attr.value) && t13.isIdentifier(attr.value.expression)) {
5304
5720
  field.valueBinding = attr.value.expression.name;
5305
5721
  if (!field.name) field.name = attr.value.expression.name;
5306
5722
  }
@@ -5350,7 +5766,7 @@ var WebScreenAnalyzer = class {
5350
5766
  extractSelectOptions(selectElement) {
5351
5767
  const options = [];
5352
5768
  for (const child of selectElement.children) {
5353
- if (!t11.isJSXElement(child)) continue;
5769
+ if (!t13.isJSXElement(child)) continue;
5354
5770
  if (getJsxElementName(child.openingElement) !== "option") continue;
5355
5771
  const value = getStringAttr(child.openingElement, "value");
5356
5772
  const label = jsxTextContent(child) || value || "";
@@ -5392,7 +5808,7 @@ var WebScreenAnalyzer = class {
5392
5808
  const actionLabels = new Map(
5393
5809
  actions.filter((a) => a.label).map((a) => [normalizeLabel(a.label), a])
5394
5810
  );
5395
- (0, import_traverse9.default)(ast, {
5811
+ (0, import_traverse10.default)(ast, {
5396
5812
  JSXElement: (nodePath) => {
5397
5813
  const element = nodePath.node;
5398
5814
  const name = getJsxElementName(element.openingElement);
@@ -5461,14 +5877,14 @@ var WebScreenAnalyzer = class {
5461
5877
  }
5462
5878
  let handlerName;
5463
5879
  const onClickAttr = opening.attributes.find(
5464
- (attr) => t11.isJSXAttribute(attr) && t11.isJSXIdentifier(attr.name) && attr.name.name === "onClick"
5880
+ (attr) => t13.isJSXAttribute(attr) && t13.isJSXIdentifier(attr.name) && attr.name.name === "onClick"
5465
5881
  );
5466
- if (onClickAttr?.value && t11.isJSXExpressionContainer(onClickAttr.value)) {
5882
+ if (onClickAttr?.value && t13.isJSXExpressionContainer(onClickAttr.value)) {
5467
5883
  const expr = onClickAttr.value.expression;
5468
- if (t11.isIdentifier(expr)) {
5884
+ if (t13.isIdentifier(expr)) {
5469
5885
  handlerName = expr.name;
5470
5886
  action.handler = expr.name;
5471
- } else if (!t11.isJSXEmptyExpression(expr)) {
5887
+ } else if (!t13.isJSXEmptyExpression(expr)) {
5472
5888
  const inlineNavCalls = extractWebNavigationCalls(expr);
5473
5889
  const inlineNav = inlineNavCalls.find((call) => call.targetPath);
5474
5890
  if (inlineNav?.targetPath) {
@@ -5607,12 +6023,12 @@ var WebScreenAnalyzer = class {
5607
6023
  }
5608
6024
  handlerNameFromAttr(opening, attrName) {
5609
6025
  const attr = opening.attributes.find(
5610
- (candidate) => t11.isJSXAttribute(candidate) && t11.isJSXIdentifier(candidate.name) && candidate.name.name === attrName
6026
+ (candidate) => t13.isJSXAttribute(candidate) && t13.isJSXIdentifier(candidate.name) && candidate.name.name === attrName
5611
6027
  );
5612
- if (!attr?.value || !t11.isJSXExpressionContainer(attr.value)) return void 0;
6028
+ if (!attr?.value || !t13.isJSXExpressionContainer(attr.value)) return void 0;
5613
6029
  const expr = attr.value.expression;
5614
- if (t11.isIdentifier(expr)) return expr.name;
5615
- if (t11.isArrowFunctionExpression(expr) || t11.isFunctionExpression(expr)) {
6030
+ if (t13.isIdentifier(expr)) return expr.name;
6031
+ if (t13.isArrowFunctionExpression(expr) || t13.isFunctionExpression(expr)) {
5616
6032
  return firstCalledFunctionName(expr) ?? "anonymous";
5617
6033
  }
5618
6034
  return void 0;
@@ -5623,7 +6039,7 @@ var WebScreenAnalyzer = class {
5623
6039
  for (const call of extractWebNavigationCalls(ast)) {
5624
6040
  if (call.targetPath && call.targetPath.startsWith("/")) targets.add(call.targetPath);
5625
6041
  }
5626
- (0, import_traverse9.default)(ast, {
6042
+ (0, import_traverse10.default)(ast, {
5627
6043
  JSXOpeningElement: (nodePath) => {
5628
6044
  const element = nodePath.node;
5629
6045
  const name = getJsxElementName(element);
@@ -5643,14 +6059,14 @@ var WebScreenAnalyzer = class {
5643
6059
  extractCollections(ast) {
5644
6060
  const collections = [];
5645
6061
  const seen = /* @__PURE__ */ new Set();
5646
- (0, import_traverse9.default)(ast, {
6062
+ (0, import_traverse10.default)(ast, {
5647
6063
  JSXExpressionContainer: (nodePath) => {
5648
6064
  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") {
6065
+ if (!t13.isCallExpression(expr) || !t13.isMemberExpression(expr.callee) || !t13.isIdentifier(expr.callee.object) || !t13.isIdentifier(expr.callee.property) || expr.callee.property.name !== "map") {
5650
6066
  return;
5651
6067
  }
5652
6068
  const callback = expr.arguments[0];
5653
- if (!t11.isArrowFunctionExpression(callback) && !t11.isFunctionExpression(callback)) return;
6069
+ if (!t13.isArrowFunctionExpression(callback) && !t13.isFunctionExpression(callback)) return;
5654
6070
  const enclosing = nodePath.findParent(
5655
6071
  (p) => p.isJSXElement()
5656
6072
  );
@@ -5685,22 +6101,22 @@ var WebScreenAnalyzer = class {
5685
6101
  }
5686
6102
  };
5687
6103
  function isRegisterScreenCallee(callee) {
5688
- return t11.isIdentifier(callee) && callee.name === "registerScreen" || t11.isMemberExpression(callee) && t11.isIdentifier(callee.property) && callee.property.name === "registerScreen";
6104
+ return t13.isIdentifier(callee) && callee.name === "registerScreen" || t13.isMemberExpression(callee) && t13.isIdentifier(callee.property) && callee.property.name === "registerScreen";
5689
6105
  }
5690
6106
  function literalToPlain(node) {
5691
- if (t11.isStringLiteral(node) || t11.isNumericLiteral(node) || t11.isBooleanLiteral(node)) {
6107
+ if (t13.isStringLiteral(node) || t13.isNumericLiteral(node) || t13.isBooleanLiteral(node)) {
5692
6108
  return node.value;
5693
6109
  }
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);
6110
+ if (t13.isNullLiteral(node)) return null;
6111
+ if (t13.isArrayExpression(node)) {
6112
+ return node.elements.filter((el) => el !== null && t13.isExpression(el)).map((el) => literalToPlain(el)).filter((value) => value !== void 0);
5697
6113
  }
5698
- if (t11.isObjectExpression(node)) {
6114
+ if (t13.isObjectExpression(node)) {
5699
6115
  const out = {};
5700
6116
  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;
6117
+ if (!t13.isObjectProperty(prop)) continue;
6118
+ const key = t13.isIdentifier(prop.key) ? prop.key.name : t13.isStringLiteral(prop.key) ? prop.key.value : void 0;
6119
+ if (!key || !t13.isExpression(prop.value)) continue;
5704
6120
  const value = literalToPlain(prop.value);
5705
6121
  if (value !== void 0) out[key] = value;
5706
6122
  }
@@ -5712,12 +6128,12 @@ function jsxTextContent(element) {
5712
6128
  const parts = [];
5713
6129
  const walk = (children) => {
5714
6130
  for (const child of children) {
5715
- if (t11.isJSXText(child)) {
6131
+ if (t13.isJSXText(child)) {
5716
6132
  const trimmed = child.value.replace(/\s+/g, " ").trim();
5717
6133
  if (trimmed) parts.push(trimmed);
5718
- } else if (t11.isJSXExpressionContainer(child) && t11.isStringLiteral(child.expression)) {
6134
+ } else if (t13.isJSXExpressionContainer(child) && t13.isStringLiteral(child.expression)) {
5719
6135
  parts.push(child.expression.value);
5720
- } else if (t11.isJSXElement(child)) {
6136
+ } else if (t13.isJSXElement(child)) {
5721
6137
  walk(child.children);
5722
6138
  }
5723
6139
  }
@@ -5727,26 +6143,26 @@ function jsxTextContent(element) {
5727
6143
  return text.length > 0 ? text : void 0;
5728
6144
  }
5729
6145
  function firstCalledFunctionName(node) {
5730
- if (t11.isIdentifier(node)) return node.name;
5731
- if (t11.isArrowFunctionExpression(node) || t11.isFunctionExpression(node)) {
6146
+ if (t13.isIdentifier(node)) return node.name;
6147
+ if (t13.isArrowFunctionExpression(node) || t13.isFunctionExpression(node)) {
5732
6148
  return firstCalledFunctionName(node.body);
5733
6149
  }
5734
- if (t11.isBlockStatement(node)) {
6150
+ if (t13.isBlockStatement(node)) {
5735
6151
  for (const statement of node.body) {
5736
6152
  const handler = firstCalledFunctionName(statement);
5737
6153
  if (handler) return handler;
5738
6154
  }
5739
6155
  return void 0;
5740
6156
  }
5741
- if (t11.isExpressionStatement(node)) return firstCalledFunctionName(node.expression);
5742
- if (t11.isReturnStatement(node)) {
6157
+ if (t13.isExpressionStatement(node)) return firstCalledFunctionName(node.expression);
6158
+ if (t13.isReturnStatement(node)) {
5743
6159
  return node.argument ? firstCalledFunctionName(node.argument) : void 0;
5744
6160
  }
5745
- if (t11.isAwaitExpression(node) || t11.isUnaryExpression(node)) {
6161
+ if (t13.isAwaitExpression(node) || t13.isUnaryExpression(node)) {
5746
6162
  return firstCalledFunctionName(node.argument);
5747
6163
  }
5748
- if (t11.isCallExpression(node)) {
5749
- if (t11.isIdentifier(node.callee) && !/^(navigate|confirm|alert)$/.test(node.callee.name)) {
6164
+ if (t13.isCallExpression(node)) {
6165
+ if (t13.isIdentifier(node.callee) && !/^(navigate|confirm|alert)$/.test(node.callee.name)) {
5750
6166
  return node.callee.name;
5751
6167
  }
5752
6168
  return void 0;
@@ -5755,14 +6171,14 @@ function firstCalledFunctionName(node) {
5755
6171
  }
5756
6172
  function containsWindowConfirm(body) {
5757
6173
  let found = false;
5758
- (0, import_traverse9.default)(
6174
+ (0, import_traverse10.default)(
5759
6175
  body,
5760
6176
  {
5761
6177
  noScope: true,
5762
6178
  CallExpression: (nodePath) => {
5763
6179
  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") {
6180
+ if (t13.isIdentifier(callee) && callee.name === "confirm") found = true;
6181
+ if (t13.isMemberExpression(callee) && t13.isIdentifier(callee.object) && callee.object.name === "window" && t13.isIdentifier(callee.property) && callee.property.name === "confirm") {
5766
6182
  found = true;
5767
6183
  }
5768
6184
  }
@@ -5777,9 +6193,9 @@ function routePathAttr(opening, attrName) {
5777
6193
  const literal = getStringAttr(opening, attrName);
5778
6194
  if (literal) return literal;
5779
6195
  const attr = opening.attributes.find(
5780
- (candidate) => t11.isJSXAttribute(candidate) && t11.isJSXIdentifier(candidate.name) && candidate.name.name === attrName
6196
+ (candidate) => t13.isJSXAttribute(candidate) && t13.isJSXIdentifier(candidate.name) && candidate.name.name === attrName
5781
6197
  );
5782
- if (!attr?.value || !t11.isJSXExpressionContainer(attr.value)) return void 0;
6198
+ if (!attr?.value || !t13.isJSXExpressionContainer(attr.value)) return void 0;
5783
6199
  return staticRoutePath(attr.value.expression);
5784
6200
  }
5785
6201
  function slugify(label) {
@@ -5794,10 +6210,10 @@ function isWeakInferredFieldName(name) {
5794
6210
  function collectionItemNames(callback) {
5795
6211
  const names = /* @__PURE__ */ new Set(["item"]);
5796
6212
  const firstParam = callback.params[0];
5797
- if (t11.isIdentifier(firstParam)) names.add(firstParam.name);
5798
- if (t11.isObjectPattern(firstParam)) {
6213
+ if (t13.isIdentifier(firstParam)) names.add(firstParam.name);
6214
+ if (t13.isObjectPattern(firstParam)) {
5799
6215
  for (const prop of firstParam.properties) {
5800
- if (t11.isObjectProperty(prop) && t11.isIdentifier(prop.key) && t11.isIdentifier(prop.value)) {
6216
+ if (t13.isObjectProperty(prop) && t13.isIdentifier(prop.key) && t13.isIdentifier(prop.value)) {
5801
6217
  names.add(prop.value.name);
5802
6218
  }
5803
6219
  }
@@ -5807,13 +6223,13 @@ function collectionItemNames(callback) {
5807
6223
  function collectionDisplayFields(callback, itemNames) {
5808
6224
  const fields = /* @__PURE__ */ new Set();
5809
6225
  if (!callback.body) return [];
5810
- (0, import_traverse9.default)(
6226
+ (0, import_traverse10.default)(
5811
6227
  callback.body,
5812
6228
  {
5813
6229
  noScope: true,
5814
6230
  MemberExpression: (nodePath) => {
5815
6231
  const node = nodePath.node;
5816
- if (t11.isIdentifier(node.object) && itemNames.has(node.object.name) && t11.isIdentifier(node.property)) {
6232
+ if (t13.isIdentifier(node.object) && itemNames.has(node.object.name) && t13.isIdentifier(node.property)) {
5817
6233
  fields.add(node.property.name);
5818
6234
  }
5819
6235
  }
@@ -5824,16 +6240,16 @@ function collectionDisplayFields(callback, itemNames) {
5824
6240
  function collectionKeyField(callback, itemNames) {
5825
6241
  let keyField;
5826
6242
  if (!callback.body) return void 0;
5827
- (0, import_traverse9.default)(
6243
+ (0, import_traverse10.default)(
5828
6244
  callback.body,
5829
6245
  {
5830
6246
  noScope: true,
5831
6247
  JSXAttribute: (nodePath) => {
5832
6248
  const attr = nodePath.node;
5833
- if (!t11.isJSXIdentifier(attr.name) || attr.name.name !== "key") return;
5834
- if (!attr.value || !t11.isJSXExpressionContainer(attr.value)) return;
6249
+ if (!t13.isJSXIdentifier(attr.name) || attr.name.name !== "key") return;
6250
+ if (!attr.value || !t13.isJSXExpressionContainer(attr.value)) return;
5835
6251
  const expr = attr.value.expression;
5836
- if (t11.isMemberExpression(expr) && t11.isIdentifier(expr.object) && itemNames.has(expr.object.name) && t11.isIdentifier(expr.property)) {
6252
+ if (t13.isMemberExpression(expr) && t13.isIdentifier(expr.object) && itemNames.has(expr.object.name) && t13.isIdentifier(expr.property)) {
5837
6253
  keyField = keyField ?? expr.property.name;
5838
6254
  }
5839
6255
  }
@@ -5856,18 +6272,18 @@ function callbackReturnsTag(callback, tags) {
5856
6272
  let found = false;
5857
6273
  const inspect = (node) => {
5858
6274
  if (!node || found) return;
5859
- if (t11.isJSXElement(node)) {
6275
+ if (t13.isJSXElement(node)) {
5860
6276
  const name = getJsxElementName(node.openingElement);
5861
6277
  if (name && tags.has(name)) found = true;
5862
6278
  return;
5863
6279
  }
5864
- if (t11.isBlockStatement(node)) {
6280
+ if (t13.isBlockStatement(node)) {
5865
6281
  for (const statement of node.body) {
5866
- if (t11.isReturnStatement(statement)) inspect(statement.argument);
6282
+ if (t13.isReturnStatement(statement)) inspect(statement.argument);
5867
6283
  }
5868
6284
  }
5869
- if (t11.isParenthesizedExpression(node)) inspect(node.expression);
5870
- if (t11.isConditionalExpression(node)) {
6285
+ if (t13.isParenthesizedExpression(node)) inspect(node.expression);
6286
+ if (t13.isConditionalExpression(node)) {
5871
6287
  inspect(node.consequent);
5872
6288
  inspect(node.alternate);
5873
6289
  }
@@ -5894,8 +6310,8 @@ function inferIdentityFields(keyField, displayFields) {
5894
6310
  // src/analyzers/web/WebNavigationAnalyzer.ts
5895
6311
  var import_fs7 = require("fs");
5896
6312
  var import_path6 = __toESM(require("path"));
5897
- var import_traverse10 = __toESM(require("@babel/traverse"));
5898
- var t12 = __toESM(require("@babel/types"));
6313
+ var import_traverse11 = __toESM(require("@babel/traverse"));
6314
+ var t14 = __toESM(require("@babel/types"));
5899
6315
  var WEB_NAVIGATOR_TYPE = "route";
5900
6316
  var WebNavigationAnalyzer = class {
5901
6317
  config;
@@ -5955,7 +6371,7 @@ var WebNavigationAnalyzer = class {
5955
6371
  const name = getJsxElementName(opening);
5956
6372
  if (name !== "Route") {
5957
6373
  for (const child of element.children) {
5958
- if (t12.isJSXElement(child)) visitRoute(child, parentPath);
6374
+ if (t14.isJSXElement(child)) visitRoute(child, parentPath);
5959
6375
  }
5960
6376
  return;
5961
6377
  }
@@ -5964,16 +6380,16 @@ var WebNavigationAnalyzer = class {
5964
6380
  const fullPath = this.joinPaths(parentPath, segment, isIndex);
5965
6381
  const componentName = this.componentNameFromElementAttr(opening) ?? void 0;
5966
6382
  const isLeaf = !element.children.some(
5967
- (child) => t12.isJSXElement(child) && getJsxElementName(child.openingElement) === "Route"
6383
+ (child) => t14.isJSXElement(child) && getJsxElementName(child.openingElement) === "Route"
5968
6384
  );
5969
6385
  if ((segment || isIndex) && (componentName || isLeaf)) {
5970
6386
  routes.push(this.buildRoute(fullPath, componentName, isIndex, !isLeaf));
5971
6387
  }
5972
6388
  for (const child of element.children) {
5973
- if (t12.isJSXElement(child)) visitRoute(child, fullPath);
6389
+ if (t14.isJSXElement(child)) visitRoute(child, fullPath);
5974
6390
  }
5975
6391
  };
5976
- (0, import_traverse10.default)(ast, {
6392
+ (0, import_traverse11.default)(ast, {
5977
6393
  JSXElement: (nodePath) => {
5978
6394
  const name = getJsxElementName(nodePath.node.openingElement);
5979
6395
  if (name !== "Routes" && name !== "Route") return;
@@ -5992,13 +6408,13 @@ var WebNavigationAnalyzer = class {
5992
6408
  /** `element={<VehicleList/>}` or `Component={VehicleList}`. */
5993
6409
  componentNameFromElementAttr(opening) {
5994
6410
  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)) {
6411
+ if (!t14.isJSXAttribute(attr) || !t14.isJSXIdentifier(attr.name)) continue;
6412
+ if (attr.name.name === "element" && t14.isJSXExpressionContainer(attr.value)) {
5997
6413
  const expr = attr.value.expression;
5998
- if (t12.isJSXElement(expr)) return getJsxElementName(expr.openingElement);
6414
+ if (t14.isJSXElement(expr)) return getJsxElementName(expr.openingElement);
5999
6415
  }
6000
- if (attr.name.name === "Component" && t12.isJSXExpressionContainer(attr.value)) {
6001
- if (t12.isIdentifier(attr.value.expression)) return attr.value.expression.name;
6416
+ if (attr.name.name === "Component" && t14.isJSXExpressionContainer(attr.value)) {
6417
+ if (t14.isIdentifier(attr.value.expression)) return attr.value.expression.name;
6002
6418
  }
6003
6419
  }
6004
6420
  return null;
@@ -6012,12 +6428,12 @@ var WebNavigationAnalyzer = class {
6012
6428
  "createMemoryRouter",
6013
6429
  "useRoutes"
6014
6430
  ]);
6015
- (0, import_traverse10.default)(ast, {
6431
+ (0, import_traverse11.default)(ast, {
6016
6432
  CallExpression: (nodePath) => {
6017
6433
  const callee = nodePath.node.callee;
6018
- if (!t12.isIdentifier(callee) || !ROUTER_FACTORIES.has(callee.name)) return;
6434
+ if (!t14.isIdentifier(callee) || !ROUTER_FACTORIES.has(callee.name)) return;
6019
6435
  const first = nodePath.node.arguments[0];
6020
- if (!t12.isArrayExpression(first)) return;
6436
+ if (!t14.isArrayExpression(first)) return;
6021
6437
  this.visitRouteObjects(first, "", routes);
6022
6438
  }
6023
6439
  });
@@ -6025,21 +6441,21 @@ var WebNavigationAnalyzer = class {
6025
6441
  }
6026
6442
  visitRouteObjects(arr, parentPath, out) {
6027
6443
  for (const element of arr.elements) {
6028
- if (!t12.isObjectExpression(element)) continue;
6444
+ if (!t14.isObjectExpression(element)) continue;
6029
6445
  let segment;
6030
6446
  let isIndex = false;
6031
6447
  let componentName;
6032
6448
  let children;
6033
6449
  for (const prop of element.properties) {
6034
- if (!t12.isObjectProperty(prop) || !t12.isIdentifier(prop.key)) continue;
6450
+ if (!t14.isObjectProperty(prop) || !t14.isIdentifier(prop.key)) continue;
6035
6451
  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)) {
6452
+ if (key === "path" && t14.isStringLiteral(prop.value)) segment = prop.value.value;
6453
+ if (key === "index" && t14.isBooleanLiteral(prop.value)) isIndex = prop.value.value;
6454
+ if (key === "element" && t14.isJSXElement(prop.value)) {
6039
6455
  componentName = getJsxElementName(prop.value.openingElement) ?? void 0;
6040
6456
  }
6041
- if (key === "Component" && t12.isIdentifier(prop.value)) componentName = prop.value.name;
6042
- if (key === "children" && t12.isArrayExpression(prop.value)) children = prop.value;
6457
+ if (key === "Component" && t14.isIdentifier(prop.value)) componentName = prop.value.name;
6458
+ if (key === "children" && t14.isArrayExpression(prop.value)) children = prop.value;
6043
6459
  }
6044
6460
  const fullPath = this.joinPaths(parentPath, segment, isIndex);
6045
6461
  if ((segment !== void 0 || isIndex) && (componentName || !children)) {
@@ -6200,23 +6616,23 @@ var ReactWebPlatformAnalyzer = class {
6200
6616
  }
6201
6617
  /** Replace route-path references with screen names where the route table resolves them. */
6202
6618
  resolveRoutePaths(screen, routes) {
6203
- const resolve2 = (target) => {
6619
+ const resolve3 = (target) => {
6204
6620
  if (!target || !target.startsWith("/")) return target;
6205
6621
  return resolvePathToScreen(routes, target) ?? target;
6206
6622
  };
6207
6623
  const navigationTargets = Array.from(
6208
6624
  new Set(
6209
- screen.navigationTargets.map((target) => resolve2(target)).filter((target) => target !== screen.name)
6625
+ screen.navigationTargets.map((target) => resolve3(target)).filter((target) => target !== screen.name)
6210
6626
  )
6211
6627
  ).sort();
6212
6628
  const actions = screen.actions.map((action) => {
6213
- const resolved = resolve2(action.targetScreen);
6629
+ const resolved = resolve3(action.targetScreen);
6214
6630
  return resolved === action.targetScreen ? action : { ...action, targetScreen: resolved };
6215
6631
  });
6216
6632
  const collections = screen.collections?.map((collection) => {
6217
6633
  const resolveRow = (row) => {
6218
6634
  if (!row?.targetScreen) return row;
6219
- const resolved = resolve2(row.targetScreen);
6635
+ const resolved = resolve3(row.targetScreen);
6220
6636
  if (resolved === row.targetScreen) return row;
6221
6637
  return {
6222
6638
  ...row,
@@ -6449,8 +6865,8 @@ var ZodParsedType = util.arrayToEnum([
6449
6865
  "set"
6450
6866
  ]);
6451
6867
  var getParsedType = (data) => {
6452
- const t16 = typeof data;
6453
- switch (t16) {
6868
+ const t18 = typeof data;
6869
+ switch (t18) {
6454
6870
  case "undefined":
6455
6871
  return ZodParsedType.undefined;
6456
6872
  case "string":
@@ -10296,7 +10712,25 @@ function isSafeImageUrl(value) {
10296
10712
  return SAFE_IMAGE_URL_RE.test(trimmed);
10297
10713
  }
10298
10714
 
10299
- // ../shared/dist/chunk-NMQNNPSJ.mjs
10715
+ // ../shared/dist/chunk-KUMPS6RH.mjs
10716
+ var SUPPORTED_APPILOTS_LOCALES = ["pt-BR", "en", "es", "fr"];
10717
+
10718
+ // ../shared/dist/chunk-4RYPNBBY.mjs
10719
+ var symbols = external_exports.array(external_exports.string().max(240)).max(12);
10720
+ var controlEvidenceSchema = external_exports.object({
10721
+ version: external_exports.literal(1),
10722
+ siteId: external_exports.string().regex(/^[a-f0-9]{20}$/),
10723
+ component: external_exports.string().max(240),
10724
+ icons: symbols,
10725
+ handler: external_exports.string().max(240).optional(),
10726
+ calls: symbols,
10727
+ argumentBindings: symbols,
10728
+ conditions: symbols,
10729
+ nativeConfirmation: external_exports.object({
10730
+ title: external_exports.string().max(240).optional(),
10731
+ destructiveOption: external_exports.boolean()
10732
+ }).optional()
10733
+ });
10300
10734
  var locatorSourceSchema = external_exports.enum([
10301
10735
  "appilotsId",
10302
10736
  "testID",
@@ -10498,7 +10932,9 @@ var screenPermissionDescriptorSchema = external_exports.object({
10498
10932
  agentAccess: external_exports.enum(["read", "write", "none"]).optional(),
10499
10933
  requiresConfirmation: external_exports.boolean().optional(),
10500
10934
  blockedActions: external_exports.array(external_exports.string()).optional(),
10501
- isPii: external_exports.boolean().optional()
10935
+ isPii: external_exports.boolean().optional(),
10936
+ /** Graded assessment — see `screenPermissionSchema.assessment`. */
10937
+ assessment: external_exports.boolean().optional()
10502
10938
  }).passthrough();
10503
10939
  var screenDescriptorSchema = external_exports.object({
10504
10940
  name: external_exports.string(),
@@ -10723,7 +11159,9 @@ var snapshotInputSchema = external_exports.object({
10723
11159
  inModal: external_exports.boolean().optional()
10724
11160
  }).passthrough();
10725
11161
  var snapshotButtonSchema = external_exports.object({
11162
+ controlEvidence: controlEvidenceSchema.optional(),
10726
11163
  id: boundedString(160).optional(),
11164
+ dispatchable: external_exports.boolean().optional(),
10727
11165
  provenance: identityProvenanceSchema.optional(),
10728
11166
  /**
10729
11167
  * False when the control is mounted but currently OUTSIDE the window —
@@ -10784,7 +11222,36 @@ var snapshotListSchema = external_exports.object({
10784
11222
  */
10785
11223
  source: boundedString(40).optional(),
10786
11224
  itemCount: external_exports.number().int().optional(),
11225
+ /**
11226
+ * Size of the whole collection when the app declared it, for a list
11227
+ * that is a WINDOW onto more data than it holds.
11228
+ *
11229
+ * `itemCount` is how many rows the list is rendering from and
11230
+ * `visibleItemCount` how many of those are mounted; neither can
11231
+ * express "there are 36 and you are looking at the first 20",
11232
+ * because a paginated list's `data` is the page. Absent means
11233
+ * unknown — never "same as itemCount".
11234
+ */
11235
+ totalItemCount: external_exports.number().int().optional(),
10787
11236
  visibleItemCount: external_exports.number().int().optional(),
11237
+ viewportItemCount: external_exports.number().int().nonnegative().optional(),
11238
+ exploration: external_exports.object({
11239
+ revision: external_exports.number().int().nonnegative(),
11240
+ observedItemCount: external_exports.number().int().min(0).max(5e3),
11241
+ observedRanges: external_exports.array(
11242
+ external_exports.object({
11243
+ start: external_exports.number().int().nonnegative(),
11244
+ end: external_exports.number().int().nonnegative()
11245
+ })
11246
+ ).max(32),
11247
+ rangesTruncated: external_exports.boolean(),
11248
+ coverage: external_exports.enum(["partial", "all-loaded"]),
11249
+ pagination: external_exports.enum(["possible", "not-declared"]),
11250
+ scrollSteps: external_exports.number().int().nonnegative(),
11251
+ remainingScrollSteps: external_exports.number().int().nonnegative(),
11252
+ consecutiveNoProgress: external_exports.number().int().nonnegative(),
11253
+ lastScroll: external_exports.enum(["moved", "no-progress", "boundary", "unverified"]).optional()
11254
+ }).optional(),
10788
11255
  refreshing: external_exports.boolean().optional(),
10789
11256
  empty: external_exports.boolean().optional(),
10790
11257
  label: boundedString(300).optional(),
@@ -10832,6 +11299,7 @@ var snapshotChoiceGroupSchema = external_exports.object({
10832
11299
  }).passthrough();
10833
11300
  var snapshotElementSchema = external_exports.object({
10834
11301
  id: boundedString(160).optional(),
11302
+ dispatchable: external_exports.boolean().optional(),
10835
11303
  role: boundedString(40).optional(),
10836
11304
  label: boundedString(300).optional(),
10837
11305
  texts: external_exports.array(boundedString(500)).max(50).optional(),
@@ -10894,6 +11362,8 @@ var agentSnapshotSchema = external_exports.object({
10894
11362
  loadingFinished: external_exports.boolean().optional(),
10895
11363
  textsAdded: external_exports.number().int().nonnegative().optional(),
10896
11364
  textsRemoved: external_exports.number().int().nonnegative().optional(),
11365
+ buttonsAddedIndices: external_exports.array(external_exports.number().int().nonnegative()).max(12).optional(),
11366
+ buttonsRemoved: external_exports.number().int().nonnegative().optional(),
10897
11367
  visibleRowsDelta: external_exports.number().int().optional(),
10898
11368
  totalRowsDelta: external_exports.number().int().optional(),
10899
11369
  fieldsNewlyFilled: external_exports.array(boundedString(160)).max(12).optional(),
@@ -10919,6 +11389,16 @@ var agentSnapshotSchema = external_exports.object({
10919
11389
  }).passthrough().optional()
10920
11390
  }).passthrough();
10921
11391
  var agentContextSchema = external_exports.object({
11392
+ missionProtocol: external_exports.literal(1).optional(),
11393
+ missionId: boundedString(160).optional(),
11394
+ /** Preferred supported device language, reported by the SDK independently of map/UI labels. */
11395
+ deviceLocale: external_exports.enum(SUPPORTED_APPILOTS_LOCALES).optional(),
11396
+ /**
11397
+ * Per-session plain-language override (short sentences, no jargon,
11398
+ * numbered steps). Absent → the project's `plainLanguage` setting.
11399
+ * Changes how the reply is WORDED only — see `PLAIN_LANGUAGE_PROMPT`.
11400
+ */
11401
+ plainLanguage: external_exports.boolean().optional(),
10922
11402
  /**
10923
11403
  * Client platform this observation was captured on. Optional and
10924
11404
  * additive (see `clientPlatformSchema`) — absent means
@@ -11169,6 +11649,12 @@ var actionDiagnoseSchema = external_exports.object({
11169
11649
  requiresUserInput: external_exports.boolean().optional()
11170
11650
  });
11171
11651
  var actionResultSchema = external_exports.object({
11652
+ nativeConfirmation: external_exports.object({
11653
+ title: external_exports.string().max(300),
11654
+ message: external_exports.string().max(1e3).optional(),
11655
+ buttonLabel: external_exports.string().max(160).optional(),
11656
+ handlerCompleted: external_exports.boolean()
11657
+ }).optional(),
11172
11658
  actionId: external_exports.string(),
11173
11659
  type: external_exports.string(),
11174
11660
  success: external_exports.boolean(),
@@ -11235,7 +11721,14 @@ var screenPermissionSchema = external_exports.object({
11235
11721
  agentAccess: agentAccessLevelSchema.optional(),
11236
11722
  requiresConfirmation: external_exports.boolean().optional(),
11237
11723
  blockedActions: external_exports.array(external_exports.string().min(1)).optional(),
11238
- isPii: external_exports.boolean().optional()
11724
+ isPii: external_exports.boolean().optional(),
11725
+ /**
11726
+ * Graded assessment (exam, quiz, graded activity). The agent may
11727
+ * explain the screen and navigate away, never write: every action
11728
+ * except navigate/scroll is blocked server-side, and the model is told
11729
+ * to refuse up front instead of trying. Wins over `agentAccess: 'write'`.
11730
+ */
11731
+ assessment: external_exports.boolean().optional()
11239
11732
  }).strict();
11240
11733
  var projectPermissionsSchema = external_exports.object({
11241
11734
  agentCanWrite: external_exports.boolean(),
@@ -11243,6 +11736,10 @@ var projectPermissionsSchema = external_exports.object({
11243
11736
  confirmDestructive: external_exports.boolean(),
11244
11737
  /**
11245
11738
  * Map of screenName → override. Keys must be non-empty strings.
11739
+ * A key containing `*` or starting with `/` is a PATTERN, matched
11740
+ * case-insensitively against the screen name and the navigation path
11741
+ * (`*Quiz*`; a path key uses `*` per segment, see docs/permissions).
11742
+ * An exact key beats patterns.
11246
11743
  * Limited to 200 entries to keep the JSON column small and editable
11247
11744
  * in the dashboard table view.
11248
11745
  */
@@ -11296,7 +11793,7 @@ var updateProjectBudgetSchema = external_exports.object({
11296
11793
  /** null = remove webhook, undefined = leave unchanged. */
11297
11794
  budgetWebhookUrl: external_exports.string().url().nullable().optional()
11298
11795
  }).strict();
11299
- var localeSchema = external_exports.enum(["pt-BR", "en", "es"]);
11796
+ var localeSchema = external_exports.enum(SUPPORTED_APPILOTS_LOCALES);
11300
11797
  var hexColorSchema = external_exports.string().regex(/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/, {
11301
11798
  message: "Must be a hex color like #6366f1"
11302
11799
  });
@@ -11340,6 +11837,13 @@ var imageSourceField = external_exports.string().max(500).refine(isSafeImageUrl,
11340
11837
  var projectPersonalizationSchema = external_exports.object({
11341
11838
  /** Tone / persona instructions appended to the system prompt. */
11342
11839
  personaPrompt: external_exports.string().max(2048).nullable(),
11840
+ /**
11841
+ * Accessibility: reply in plain language (short sentences, everyday
11842
+ * words, numbered steps, one question at a time). Server-side only,
11843
+ * like `personaPrompt`; a session can override it via
11844
+ * `context.plainLanguage`.
11845
+ */
11846
+ plainLanguage: external_exports.boolean(),
11343
11847
  /** Display name in the chat header (e.g. "Aria"). */
11344
11848
  assistantName: external_exports.string().max(60).nullable(),
11345
11849
  /** URL or remote asset id for the avatar shown next to assistant turns. */
@@ -11363,6 +11867,7 @@ var projectPersonalizationSchema = external_exports.object({
11363
11867
  });
11364
11868
  var updateProjectPersonalizationSchema = external_exports.object({
11365
11869
  personaPrompt: external_exports.string().max(2048).nullable().optional(),
11870
+ plainLanguage: external_exports.boolean().optional(),
11366
11871
  assistantName: external_exports.string().max(60).nullable().optional(),
11367
11872
  assistantAvatar: imageSourceField.nullable().optional(),
11368
11873
  emptyStateIcon: imageSourceField.nullable().optional(),
@@ -11520,6 +12025,8 @@ var sandboxRunRequestSchema = external_exports.object({
11520
12025
  * the dev doesn't want their tokens metered.
11521
12026
  */
11522
12027
  silent: external_exports.boolean().optional(),
12028
+ /** Run with the plain-language reply style on/off, overriding the project. */
12029
+ plainLanguage: external_exports.boolean().optional(),
11523
12030
  /**
11524
12031
  * Prior turns of the conversation, in order, that precede `prompt`.
11525
12032
  * Lets a driver run the agent loop hop-by-hop headlessly (the multi-
@@ -12039,9 +12546,22 @@ var MCPGenerator = class _MCPGenerator {
12039
12546
  const filePath = import_node_path5.default.resolve(outputDir, `mcp-document.${this.options.format}`);
12040
12547
  await (0, import_promises4.writeFile)(filePath, serialized, "utf-8");
12041
12548
  console.log(`[MCPGenerator] Document written to: ${filePath}`);
12549
+ const controlFiles = analyzed.controlEvidenceFiles ?? {};
12550
+ await (0, import_promises4.writeFile)(
12551
+ import_node_path5.default.resolve(outputDir, "control-evidence.json"),
12552
+ JSON.stringify({ version: 1, files: controlFiles }, null, 2),
12553
+ "utf-8"
12554
+ );
12042
12555
  const checksumFilePath = import_node_path5.default.resolve(outputDir, ".appilots-checksum");
12043
12556
  await (0, import_promises4.writeFile)(checksumFilePath, checksum, "utf-8");
12044
12557
  console.log(`[MCPGenerator] Checksum written to: ${checksumFilePath}`);
12558
+ const evidenceCount = Object.values(controlFiles).reduce(
12559
+ (sum, entries) => sum + entries.length,
12560
+ 0
12561
+ );
12562
+ console.log(
12563
+ `[MCPGenerator] Source evidence: ${evidenceCount} icon controls across ${Object.keys(controlFiles).length} files (runtime binding required)`
12564
+ );
12045
12565
  console.log("[MCPGenerator] Generation complete!");
12046
12566
  return {
12047
12567
  document,
@@ -12072,7 +12592,7 @@ var MCPGenerator = class _MCPGenerator {
12072
12592
  * Calculate SHA-256 checksum of content
12073
12593
  */
12074
12594
  calculateChecksum(content) {
12075
- return (0, import_node_crypto.createHash)("sha256").update(content).digest("hex");
12595
+ return (0, import_node_crypto2.createHash)("sha256").update(content).digest("hex");
12076
12596
  }
12077
12597
  /**
12078
12598
  * Get project name and version from package.json in rootDir
@@ -12688,15 +13208,15 @@ var import_node_path9 = __toESM(require("path"));
12688
13208
  var import_commander5 = require("commander");
12689
13209
 
12690
13210
  // src/annotate/sites.ts
12691
- var import_traverse12 = __toESM(require("@babel/traverse"));
12692
- var t14 = __toESM(require("@babel/types"));
13211
+ var import_traverse13 = __toESM(require("@babel/traverse"));
13212
+ var t16 = __toESM(require("@babel/types"));
12693
13213
 
12694
13214
  // src/annotate/forwarding.ts
12695
13215
  var import_node_path8 = __toESM(require("path"));
12696
13216
  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;
13217
+ var import_traverse12 = __toESM(require("@babel/traverse"));
13218
+ var t15 = __toESM(require("@babel/types"));
13219
+ var traverse12 = import_traverse12.default.default ?? import_traverse12.default;
12700
13220
  var RN_TESTID_CARRIERS = /* @__PURE__ */ new Set([
12701
13221
  "View",
12702
13222
  "Text",
@@ -12723,14 +13243,14 @@ var RN_TESTID_CARRIERS = /* @__PURE__ */ new Set([
12723
13243
  ]);
12724
13244
  function collectImports(ast) {
12725
13245
  const out = /* @__PURE__ */ new Map();
12726
- traverse11(ast, {
13246
+ traverse12(ast, {
12727
13247
  ImportDeclaration(nodePath) {
12728
13248
  const source = nodePath.node.source.value;
12729
13249
  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;
13250
+ if (t15.isImportSpecifier(spec)) {
13251
+ const imported = t15.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;
12732
13252
  out.set(spec.local.name, { source, local: spec.local.name, imported });
12733
- } else if (t13.isImportDefaultSpecifier(spec)) {
13253
+ } else if (t15.isImportDefaultSpecifier(spec)) {
12734
13254
  out.set(spec.local.name, { source, local: spec.local.name, imported: "default" });
12735
13255
  }
12736
13256
  }
@@ -12778,13 +13298,13 @@ function inspectModule(file2, exportName, depth = 0) {
12778
13298
  let forwards = false;
12779
13299
  let derives = false;
12780
13300
  let barrelTarget;
12781
- traverse11(ast, {
13301
+ traverse12(ast, {
12782
13302
  // `export { Card } from './Card'` — follow one hop.
12783
13303
  ExportNamedDeclaration(nodePath) {
12784
13304
  const from = nodePath.node.source?.value;
12785
13305
  if (!from) return;
12786
13306
  const named = nodePath.node.specifiers.some(
12787
- (spec) => t13.isExportSpecifier(spec) && (t13.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value) === exportName
13307
+ (spec) => t15.isExportSpecifier(spec) && (t15.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value) === exportName
12788
13308
  );
12789
13309
  if (named) barrelTarget = from;
12790
13310
  },
@@ -12793,11 +13313,11 @@ function inspectModule(file2, exportName, depth = 0) {
12793
13313
  },
12794
13314
  // `interface CardProps { testID?: string }` / `type Props = { testID… }`
12795
13315
  TSPropertySignature(nodePath) {
12796
- if (t13.isIdentifier(nodePath.node.key) && nodePath.node.key.name === "testID") forwards = true;
13316
+ if (t15.isIdentifier(nodePath.node.key) && nodePath.node.key.name === "testID") forwards = true;
12797
13317
  },
12798
13318
  // `function Card({ testID }) {}` — the destructured parameter.
12799
13319
  ObjectProperty(nodePath) {
12800
- if (t13.isIdentifier(nodePath.node.key) && nodePath.node.key.name === "testID") forwards = true;
13320
+ if (t15.isIdentifier(nodePath.node.key) && nodePath.node.key.name === "testID") forwards = true;
12801
13321
  },
12802
13322
  // `<View {...props} />` — anything spread onto JSX carries it along.
12803
13323
  JSXSpreadAttribute() {
@@ -12808,17 +13328,17 @@ function inspectModule(file2, exportName, depth = 0) {
12808
13328
  // that is one hardcoded name shared by every instance, which is the
12809
13329
  // duplicate-id problem rather than a solution to it.
12810
13330
  JSXAttribute(nodePath) {
12811
- const name = t13.isJSXIdentifier(nodePath.node.name) ? nodePath.node.name.name : "";
13331
+ const name = t15.isJSXIdentifier(nodePath.node.name) ? nodePath.node.name.name : "";
12812
13332
  if (name !== "testID" && name !== "accessibilityLabel") return;
12813
13333
  const value = nodePath.node.value;
12814
- if (!t13.isJSXExpressionContainer(value)) return;
12815
- if (t13.isStringLiteral(value.expression)) return;
13334
+ if (!t15.isJSXExpressionContainer(value)) return;
13335
+ if (t15.isStringLiteral(value.expression)) return;
12816
13336
  derives = true;
12817
13337
  },
12818
13338
  // `useAppilotsTarget(`${groupId}-${option.value}`, …)`
12819
13339
  CallExpression(nodePath) {
12820
13340
  const callee = nodePath.node.callee;
12821
- if (t13.isIdentifier(callee) && IDENTITY_HOOKS.has(callee.name)) derives = true;
13341
+ if (t15.isIdentifier(callee) && IDENTITY_HOOKS.has(callee.name)) derives = true;
12822
13342
  }
12823
13343
  });
12824
13344
  if (forwards || derives) return { forwards, derives };
@@ -12852,7 +13372,7 @@ function resetForwardingCache() {
12852
13372
  }
12853
13373
 
12854
13374
  // src/annotate/sites.ts
12855
- var traverse12 = import_traverse12.default.default ?? import_traverse12.default;
13375
+ var traverse13 = import_traverse13.default.default ?? import_traverse13.default;
12856
13376
  var LABEL_PROPS = ["title", "label", "placeholder"];
12857
13377
  var IDENTITY_PROPS = ["testID", "appilotsId", "accessibilityLabel"];
12858
13378
  function kebab(text) {
@@ -12903,18 +13423,18 @@ function hasLabelText(element) {
12903
13423
  function namedHandler(element, prop) {
12904
13424
  if (!prop) return void 0;
12905
13425
  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;
13426
+ if (!attr || !t16.isJSXExpressionContainer(attr.value)) return void 0;
13427
+ return t16.isIdentifier(attr.value.expression) ? attr.value.expression.name : void 0;
12908
13428
  }
12909
13429
  var ANNOTATABLE_ROLES = /* @__PURE__ */ new Set(["button", "input", "select", "toggle", "date", "list"]);
12910
13430
  function isPerItemRender(nodePath) {
12911
13431
  let current = nodePath.parentPath;
12912
13432
  while (current) {
12913
13433
  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")) {
13434
+ if (t16.isCallExpression(node) && t16.isMemberExpression(node.callee) && t16.isIdentifier(node.callee.property) && (node.callee.property.name === "map" || node.callee.property.name === "flatMap")) {
12915
13435
  return true;
12916
13436
  }
12917
- if (t14.isJSXAttribute(node) && t14.isJSXIdentifier(node.name) && /^render[A-Z]|^ListHeaderComponent$|^ListFooterComponent$/.test(node.name.name) && node.name.name !== "renderScrollComponent") {
13437
+ if (t16.isJSXAttribute(node) && t16.isJSXIdentifier(node.name) && /^render[A-Z]|^ListHeaderComponent$|^ListFooterComponent$/.test(node.name.name) && node.name.name !== "renderScrollComponent") {
12918
13438
  return /^renderItem$|^renderSectionHeader$|^renderSectionFooter$/.test(node.name.name);
12919
13439
  }
12920
13440
  current = current.parentPath;
@@ -12933,7 +13453,7 @@ function findAnnotationSites(source, file2) {
12933
13453
  const sites = [];
12934
13454
  const perComponent = /* @__PURE__ */ new Map();
12935
13455
  const usedIds = /* @__PURE__ */ new Set();
12936
- traverse12(ast, {
13456
+ traverse13(ast, {
12937
13457
  JSXOpeningElement(nodePath) {
12938
13458
  for (const prop of IDENTITY_PROPS) {
12939
13459
  const existing = getStringAttr(nodePath.node, prop);
@@ -12941,10 +13461,10 @@ function findAnnotationSites(source, file2) {
12941
13461
  }
12942
13462
  }
12943
13463
  });
12944
- traverse12(ast, {
13464
+ traverse13(ast, {
12945
13465
  JSXOpeningElement(nodePath) {
12946
13466
  const element = nodePath.node;
12947
- if (!t14.isJSXIdentifier(element.name)) return;
13467
+ if (!t16.isJSXIdentifier(element.name)) return;
12948
13468
  const component = element.name.name;
12949
13469
  const role = classifyJsxComponent(component, element);
12950
13470
  if (!ANNOTATABLE_ROLES.has(role)) return;
@@ -13028,21 +13548,21 @@ function applyToFile(source, sites) {
13028
13548
  // src/annotate/forward.ts
13029
13549
  var import_node_fs6 = require("fs");
13030
13550
  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;
13551
+ var import_traverse14 = __toESM(require("@babel/traverse"));
13552
+ var t17 = __toESM(require("@babel/types"));
13553
+ var traverse14 = import_traverse14.default.default ?? import_traverse14.default;
13034
13554
  function findComponent(ast, name) {
13035
13555
  let found;
13036
- traverse13(ast, {
13556
+ traverse14(ast, {
13037
13557
  FunctionDeclaration(nodePath) {
13038
13558
  if (nodePath.node.id?.name === name) {
13039
13559
  found ??= { params: nodePath.node.params, body: nodePath.node.body };
13040
13560
  }
13041
13561
  },
13042
13562
  VariableDeclarator(nodePath) {
13043
- if (!t15.isIdentifier(nodePath.node.id) || nodePath.node.id.name !== name) return;
13563
+ if (!t17.isIdentifier(nodePath.node.id) || nodePath.node.id.name !== name) return;
13044
13564
  const init = nodePath.node.init;
13045
- if (t15.isArrowFunctionExpression(init) || t15.isFunctionExpression(init)) {
13565
+ if (t17.isArrowFunctionExpression(init) || t17.isFunctionExpression(init)) {
13046
13566
  found ??= { params: init.params, body: init.body };
13047
13567
  }
13048
13568
  }
@@ -13054,26 +13574,26 @@ function findReturnedRoots(body) {
13054
13574
  let unsupported = false;
13055
13575
  const record = (node) => {
13056
13576
  if (!node) return;
13057
- if (t15.isParenthesizedExpression(node)) return record(node.expression);
13058
- if (t15.isJSXElement(node)) {
13577
+ if (t17.isParenthesizedExpression(node)) return record(node.expression);
13578
+ if (t17.isJSXElement(node)) {
13059
13579
  roots.push(node.openingElement);
13060
13580
  return;
13061
13581
  }
13062
- if (t15.isConditionalExpression(node)) {
13582
+ if (t17.isConditionalExpression(node)) {
13063
13583
  record(node.consequent);
13064
13584
  record(node.alternate);
13065
13585
  return;
13066
13586
  }
13067
- if (t15.isJSXFragment(node)) {
13587
+ if (t17.isJSXFragment(node)) {
13068
13588
  unsupported = true;
13069
13589
  return;
13070
13590
  }
13071
- if (t15.isNullLiteral(node)) return;
13591
+ if (t17.isNullLiteral(node)) return;
13072
13592
  unsupported = true;
13073
13593
  };
13074
- if (t15.isBlockStatement(body)) {
13075
- traverse13(
13076
- t15.file(t15.program([t15.expressionStatement(t15.functionExpression(null, [], body))])),
13594
+ if (t17.isBlockStatement(body)) {
13595
+ traverse14(
13596
+ t17.file(t17.program([t17.expressionStatement(t17.functionExpression(null, [], body))])),
13077
13597
  {
13078
13598
  ReturnStatement(nodePath) {
13079
13599
  record(nodePath.node.argument);
@@ -13087,7 +13607,7 @@ function findReturnedRoots(body) {
13087
13607
  return roots;
13088
13608
  }
13089
13609
  function isCarrierRoot(element, imports) {
13090
- if (!t15.isJSXIdentifier(element.name)) return false;
13610
+ if (!t17.isJSXIdentifier(element.name)) return false;
13091
13611
  const name = element.name.name;
13092
13612
  const origin = imports.get(name);
13093
13613
  if (origin?.source !== "react-native") return false;
@@ -13095,7 +13615,7 @@ function isCarrierRoot(element, imports) {
13095
13615
  }
13096
13616
  function hasProp(element, name) {
13097
13617
  return element.attributes.some(
13098
- (attr) => t15.isJSXAttribute(attr) && t15.isJSXIdentifier(attr.name) && attr.name.name === name
13618
+ (attr) => t17.isJSXAttribute(attr) && t17.isJSXIdentifier(attr.name) && attr.name.name === name
13099
13619
  );
13100
13620
  }
13101
13621
  function indentOf(source, offset) {
@@ -13121,12 +13641,12 @@ ${indent}${text}` };
13121
13641
  }
13122
13642
  function followBarrel(file2, ast, component) {
13123
13643
  let target;
13124
- traverse13(ast, {
13644
+ traverse14(ast, {
13125
13645
  ExportNamedDeclaration(nodePath) {
13126
13646
  const from = nodePath.node.source?.value;
13127
13647
  if (!from) return;
13128
13648
  const named = nodePath.node.specifiers.some(
13129
- (spec) => t15.isExportSpecifier(spec) && (t15.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value) === component
13649
+ (spec) => t17.isExportSpecifier(spec) && (t17.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value) === component
13130
13650
  );
13131
13651
  if (named) target ??= from;
13132
13652
  }
@@ -13154,7 +13674,7 @@ function planForward(file2, component, depth = 0) {
13154
13674
  return { ...base, refusal: `no function named ${component} in this file` };
13155
13675
  }
13156
13676
  const param = found.params[0];
13157
- if (!t15.isObjectPattern(param)) {
13677
+ if (!t17.isObjectPattern(param)) {
13158
13678
  return {
13159
13679
  ...base,
13160
13680
  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 +13690,7 @@ function planForward(file2, component, depth = 0) {
13170
13690
  const imports = collectImports(ast);
13171
13691
  const nonCarrier = roots.find((root) => !isCarrierRoot(root, imports));
13172
13692
  if (nonCarrier) {
13173
- const name = t15.isJSXIdentifier(nonCarrier.name) ? nonCarrier.name.name : "its root";
13693
+ const name = t17.isJSXIdentifier(nonCarrier.name) ? nonCarrier.name.name : "its root";
13174
13694
  return {
13175
13695
  ...base,
13176
13696
  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 +13698,30 @@ function planForward(file2, component, depth = 0) {
13178
13698
  }
13179
13699
  const edits = [];
13180
13700
  const alreadyDestructured = param.properties.some(
13181
- (prop) => t15.isObjectProperty(prop) && t15.isIdentifier(prop.key) && prop.key.name === "testID"
13701
+ (prop) => t17.isObjectProperty(prop) && t17.isIdentifier(prop.key) && prop.key.name === "testID"
13182
13702
  );
13183
13703
  if (!alreadyDestructured) {
13184
13704
  const insert = insertAfterLastMember(source, param.properties, "testID", param.end ?? 0, ",");
13185
13705
  edits.push({ ...insert, what: "parameter" });
13186
13706
  }
13187
13707
  const annotation = param.typeAnnotation;
13188
- if (t15.isTSTypeAnnotation(annotation)) {
13708
+ if (t17.isTSTypeAnnotation(annotation)) {
13189
13709
  const declared = annotation.typeAnnotation;
13190
13710
  let body;
13191
13711
  let closing = 0;
13192
- if (t15.isTSTypeLiteral(declared)) {
13712
+ if (t17.isTSTypeLiteral(declared)) {
13193
13713
  body = declared.members;
13194
13714
  closing = declared.end ?? 0;
13195
- } else if (t15.isTSTypeReference(declared) && t15.isIdentifier(declared.typeName)) {
13715
+ } else if (t17.isTSTypeReference(declared) && t17.isIdentifier(declared.typeName)) {
13196
13716
  const typeName = declared.typeName.name;
13197
- traverse13(ast, {
13717
+ traverse14(ast, {
13198
13718
  TSInterfaceDeclaration(nodePath) {
13199
13719
  if (nodePath.node.id.name !== typeName) return;
13200
13720
  body = nodePath.node.body.body;
13201
13721
  closing = nodePath.node.body.end ?? 0;
13202
13722
  },
13203
13723
  TSTypeAliasDeclaration(nodePath) {
13204
- if (nodePath.node.id.name !== typeName || !t15.isTSTypeLiteral(nodePath.node.typeAnnotation))
13724
+ if (nodePath.node.id.name !== typeName || !t17.isTSTypeLiteral(nodePath.node.typeAnnotation))
13205
13725
  return;
13206
13726
  body = nodePath.node.typeAnnotation.members;
13207
13727
  closing = nodePath.node.typeAnnotation.end ?? 0;
@@ -13216,7 +13736,7 @@ function planForward(file2, component, depth = 0) {
13216
13736
  }
13217
13737
  if (body) {
13218
13738
  const declaresTestId = body.some(
13219
- (member) => t15.isTSPropertySignature(member) && t15.isIdentifier(member.key) && member.key.name === "testID"
13739
+ (member) => t17.isTSPropertySignature(member) && t17.isIdentifier(member.key) && member.key.name === "testID"
13220
13740
  );
13221
13741
  if (!declaresTestId) {
13222
13742
  const insert = insertAfterLastMember(source, body, "testID?: string;", closing, ";");
@@ -14009,9 +14529,145 @@ Pass rate: ${passed}/${total} (${passRatePct}%) \u2014 threshold ${minPassRatePc
14009
14529
  });
14010
14530
  }
14011
14531
 
14532
+ // src/cli/commands/knowledge.ts
14533
+ var import_commander8 = require("commander");
14534
+ var import_promises7 = require("fs/promises");
14535
+ var import_node_path10 = require("path");
14536
+ var import_node_crypto3 = require("crypto");
14537
+ var import_fast_glob2 = __toESM(require("fast-glob"));
14538
+ var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".txt", ".html", ".htm", ".pdf"]);
14539
+ var MIME_MAP = {
14540
+ ".md": "text/markdown",
14541
+ ".txt": "text/plain",
14542
+ ".html": "text/html",
14543
+ ".htm": "text/html",
14544
+ ".pdf": "application/pdf"
14545
+ };
14546
+ function knowledgeCommand() {
14547
+ const cmd = new import_commander8.Command("knowledge").description("Manage the project knowledge base (RAG)");
14548
+ 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) => {
14549
+ if (options.json) setLogMode("json");
14550
+ else if (options.quiet) setLogMode("quiet");
14551
+ try {
14552
+ banner();
14553
+ const loaded = loadConfig(warn);
14554
+ const apiKey = options.apiKey || loaded?.apiKey;
14555
+ if (!apiKey) {
14556
+ error("No .appilotsrc configuration found");
14557
+ info("Run: appilots init --api-key <your-key>");
14558
+ jsonOutput({ success: false, error: "No configuration found (missing API key)" });
14559
+ process.exit(1);
14560
+ return;
14561
+ }
14562
+ const config = {
14563
+ serverUrl: DEFAULT_SERVER_URL,
14564
+ ...loaded,
14565
+ apiKey,
14566
+ ...options.server ? { serverUrl: options.server } : {}
14567
+ };
14568
+ const sources = config.knowledge?.sources;
14569
+ if (!sources || sources.length === 0) {
14570
+ error("No knowledge sources configured");
14571
+ info("Add knowledge.sources to .appilotsrc:");
14572
+ info(' { "knowledge": { "sources": ["docs/**/*.md"] } }');
14573
+ jsonOutput({ success: false, error: "No knowledge sources configured" });
14574
+ process.exit(1);
14575
+ return;
14576
+ }
14577
+ const spinner = createSpinner("Scanning for knowledge documents...");
14578
+ spinner.start();
14579
+ const rootDir = process.cwd();
14580
+ const excludePatterns = config.knowledge?.exclude ?? [];
14581
+ const allFiles = [];
14582
+ for (const pattern of sources) {
14583
+ const matches = await (0, import_fast_glob2.default)(pattern, {
14584
+ cwd: rootDir,
14585
+ ignore: ["node_modules/**", ...excludePatterns],
14586
+ onlyFiles: true
14587
+ });
14588
+ for (const match of matches) {
14589
+ const ext = (0, import_node_path10.extname)(match).toLowerCase();
14590
+ if (SUPPORTED_EXTENSIONS.has(ext) && !allFiles.includes(match)) {
14591
+ allFiles.push(match);
14592
+ }
14593
+ }
14594
+ }
14595
+ spinner.stop();
14596
+ if (allFiles.length === 0) {
14597
+ warn("No supported files found matching knowledge.sources patterns");
14598
+ info(`Supported: ${[...SUPPORTED_EXTENSIONS].join(", ")}`);
14599
+ jsonOutput({ success: true, uploaded: 0, skipped: 0, errors: 0, files: 0 });
14600
+ return;
14601
+ }
14602
+ info(`Found ${allFiles.length} document${allFiles.length === 1 ? "" : "s"}`);
14603
+ const documents = [];
14604
+ for (const filePath of allFiles) {
14605
+ const absolutePath = (0, import_node_path10.resolve)(rootDir, filePath);
14606
+ const buffer = await (0, import_promises7.readFile)(absolutePath);
14607
+ const checksum = (0, import_node_crypto3.createHash)("sha256").update(buffer).digest("hex");
14608
+ const ext = (0, import_node_path10.extname)(filePath).toLowerCase();
14609
+ const mimeType = MIME_MAP[ext] ?? "text/plain";
14610
+ documents.push({
14611
+ filename: (0, import_node_path10.relative)(rootDir, absolutePath),
14612
+ content: buffer.toString("base64"),
14613
+ mimeType,
14614
+ checksum
14615
+ });
14616
+ }
14617
+ const uploadSpinner = createSpinner(
14618
+ `Uploading ${documents.length} document${documents.length === 1 ? "" : "s"}...`
14619
+ );
14620
+ uploadSpinner.start();
14621
+ const apiClient = new AppilotsAPIClient({
14622
+ serverUrl: config.serverUrl,
14623
+ apiKey: config.apiKey,
14624
+ timeoutMs: 12e4
14625
+ // Knowledge sync can take longer (embedding)
14626
+ });
14627
+ const result = await apiClient.knowledgeSync(documents);
14628
+ uploadSpinner.stop();
14629
+ if (!result.success) {
14630
+ error(`Knowledge sync failed: ${result.error}`);
14631
+ jsonOutput({ success: false, error: result.error });
14632
+ process.exit(1);
14633
+ return;
14634
+ }
14635
+ success(
14636
+ `Knowledge sync complete: ${result.uploaded} uploaded, ${result.skipped} skipped, ${result.errors} errors`
14637
+ );
14638
+ if (options.verbose && result.details) {
14639
+ for (const detail of result.details) {
14640
+ if (detail.status === "uploaded") {
14641
+ info(` + ${detail.filename}`);
14642
+ } else if (detail.status === "skipped") {
14643
+ info(` = ${detail.filename} (unchanged)`);
14644
+ } else {
14645
+ warn(` ! ${detail.filename}: ${detail.error}`);
14646
+ }
14647
+ }
14648
+ }
14649
+ jsonOutput({
14650
+ success: true,
14651
+ uploaded: result.uploaded,
14652
+ skipped: result.skipped,
14653
+ errors: result.errors,
14654
+ details: result.details
14655
+ });
14656
+ } catch (err) {
14657
+ error(`Knowledge sync failed: ${stringifyUnknown(err)}`);
14658
+ jsonOutput({ success: false, error: stringifyUnknown(err) });
14659
+ if (options.verbose) {
14660
+ console.error(err);
14661
+ }
14662
+ process.exit(1);
14663
+ }
14664
+ });
14665
+ return cmd;
14666
+ }
14667
+
14012
14668
  // src/cli/index.ts
14013
14669
  async function main() {
14014
- const program2 = new import_commander8.Command();
14670
+ const program2 = new import_commander9.Command();
14015
14671
  program2.name("appilots").description(
14016
14672
  "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
14673
  ).version(CLI_VERSION).option("--verbose", "Enable verbose logging");
@@ -14022,6 +14678,7 @@ async function main() {
14022
14678
  program2.addCommand(annotateCommand());
14023
14679
  program2.addCommand(statusCommand());
14024
14680
  program2.addCommand(evalCommand());
14681
+ program2.addCommand(knowledgeCommand());
14025
14682
  const args = process.argv.slice(2);
14026
14683
  const firstArg = args[0];
14027
14684
  const hasCommand = firstArg !== void 0 && args.length > 0 && !firstArg.startsWith("-");