@appilots/cli 0.4.0 → 0.11.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 +1932 -298
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +77 -9
- package/dist/index.d.ts +77 -9
- package/dist/index.js +829 -151
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +829 -152
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -83,6 +83,45 @@ function hasJsxAttribute(element, name) {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
// src/ast/jsx/classify.ts
|
|
86
|
+
var NON_INTERACTION_HANDLERS = /* @__PURE__ */ new Set([
|
|
87
|
+
"onLayout",
|
|
88
|
+
"onScroll",
|
|
89
|
+
"onScrollBeginDrag",
|
|
90
|
+
"onScrollEndDrag",
|
|
91
|
+
"onMomentumScrollBegin",
|
|
92
|
+
"onMomentumScrollEnd",
|
|
93
|
+
"onContentSizeChange",
|
|
94
|
+
"onEndReached",
|
|
95
|
+
"onViewableItemsChanged",
|
|
96
|
+
"onLoad",
|
|
97
|
+
"onLoadStart",
|
|
98
|
+
"onLoadEnd",
|
|
99
|
+
"onError",
|
|
100
|
+
"onProgress",
|
|
101
|
+
"onFocus",
|
|
102
|
+
"onBlur"
|
|
103
|
+
]);
|
|
104
|
+
var VALUE_HANDLERS = /* @__PURE__ */ new Set([
|
|
105
|
+
"onChange",
|
|
106
|
+
"onChangeText",
|
|
107
|
+
"onValueChange",
|
|
108
|
+
"onSelect",
|
|
109
|
+
"onSelectionChange",
|
|
110
|
+
"onSubmitEditing"
|
|
111
|
+
]);
|
|
112
|
+
function pressHandlerProp(element) {
|
|
113
|
+
let fallback;
|
|
114
|
+
for (const attr of element.attributes) {
|
|
115
|
+
if (attr.type !== "JSXAttribute" || attr.name.type !== "JSXIdentifier") continue;
|
|
116
|
+
const name = attr.name.name;
|
|
117
|
+
if (!/^on[A-Z]/.test(name)) continue;
|
|
118
|
+
if (attr.value?.type !== "JSXExpressionContainer") continue;
|
|
119
|
+
if (name === "onPress") return name;
|
|
120
|
+
if (NON_INTERACTION_HANDLERS.has(name) || VALUE_HANDLERS.has(name)) continue;
|
|
121
|
+
fallback ??= name;
|
|
122
|
+
}
|
|
123
|
+
return fallback;
|
|
124
|
+
}
|
|
86
125
|
var VIEW_COMPONENTS = /* @__PURE__ */ new Set(["View", "ScrollView", "SafeAreaView", "KeyboardAvoidingView"]);
|
|
87
126
|
var INPUT_COMPONENTS = /* @__PURE__ */ new Set(["TextInput", "Input", "HocInput"]);
|
|
88
127
|
var BUTTON_COMPONENTS = /* @__PURE__ */ new Set(["TouchableOpacity", "Pressable", "Button"]);
|
|
@@ -97,17 +136,16 @@ function classifyJsxComponent(name, element) {
|
|
|
97
136
|
if (INPUT_COMPONENTS.has(name)) return "input";
|
|
98
137
|
if (BUTTON_COMPONENTS.has(name)) return "button";
|
|
99
138
|
if (element) {
|
|
100
|
-
const hasOptions = hasJsxAttribute(element, "options");
|
|
139
|
+
const hasOptions = hasJsxAttribute(element, "options") || hasJsxAttribute(element, "segments") || hasJsxAttribute(element, "choices") || hasJsxAttribute(element, "tabs");
|
|
101
140
|
const hasValue = hasJsxAttribute(element, "value");
|
|
102
141
|
const hasChecked = hasJsxAttribute(element, "checked") || hasJsxAttribute(element, "selected");
|
|
103
142
|
const hasOnChange = hasJsxAttribute(element, "onChange") || hasJsxAttribute(element, "onValueChange") || hasJsxAttribute(element, "onChangeText");
|
|
104
|
-
const hasOnPress = hasJsxAttribute(element, "onPress");
|
|
105
143
|
if (hasOptions && (hasValue || hasOnChange)) return "select";
|
|
106
144
|
if (hasChecked && hasOnChange) return "toggle";
|
|
107
145
|
if (hasOnChange && (hasJsxAttribute(element, "label") || hasJsxAttribute(element, "placeholder"))) {
|
|
108
146
|
return "input";
|
|
109
147
|
}
|
|
110
|
-
if (
|
|
148
|
+
if (pressHandlerProp(element)) return "button";
|
|
111
149
|
if (getStringAttr(element, "visible") || getExpressionIdentifierAttr(element, "visible")) {
|
|
112
150
|
return "modal";
|
|
113
151
|
}
|
|
@@ -445,12 +483,17 @@ var ScreenAnalyzer = class {
|
|
|
445
483
|
}
|
|
446
484
|
} catch (error) {
|
|
447
485
|
if (this.verbose) {
|
|
448
|
-
console.warn(
|
|
486
|
+
console.warn(
|
|
487
|
+
`[ScreenAnalyzer] Failed to parse ${file}:`,
|
|
488
|
+
error instanceof Error ? error.message : error
|
|
489
|
+
);
|
|
449
490
|
}
|
|
450
491
|
}
|
|
451
492
|
}
|
|
452
493
|
if (this.verbose && this.strictScreens) {
|
|
453
|
-
console.log(
|
|
494
|
+
console.log(
|
|
495
|
+
`[ScreenAnalyzer] Strict mode: ${screens.length} included, ${this.screensFilteredOut} filtered out`
|
|
496
|
+
);
|
|
454
497
|
}
|
|
455
498
|
return screens;
|
|
456
499
|
}
|
|
@@ -738,7 +781,11 @@ var ScreenAnalyzer = class {
|
|
|
738
781
|
for (const form of secondary) {
|
|
739
782
|
const existing = out.find((candidate) => candidate.id === form.id) ?? this.findFormWithSharedFields(out, form);
|
|
740
783
|
if (!existing) {
|
|
741
|
-
out.push({
|
|
784
|
+
out.push({
|
|
785
|
+
...form,
|
|
786
|
+
fields: [...form.fields],
|
|
787
|
+
submitAction: this.namedSubmitAction(form.submitAction)
|
|
788
|
+
});
|
|
742
789
|
continue;
|
|
743
790
|
}
|
|
744
791
|
for (const field of form.fields) {
|
|
@@ -757,9 +804,12 @@ var ScreenAnalyzer = class {
|
|
|
757
804
|
findEquivalentField(fields, incoming) {
|
|
758
805
|
return fields.find((field) => {
|
|
759
806
|
if (field.name && incoming.name && field.name === incoming.name) return true;
|
|
760
|
-
if (field.valueBinding && incoming.valueBinding && field.valueBinding === incoming.valueBinding)
|
|
761
|
-
|
|
762
|
-
if (field.
|
|
807
|
+
if (field.valueBinding && incoming.valueBinding && field.valueBinding === incoming.valueBinding)
|
|
808
|
+
return true;
|
|
809
|
+
if (field.locator?.id && incoming.locator?.id && field.locator.id === incoming.locator.id)
|
|
810
|
+
return true;
|
|
811
|
+
if (field.placeholder && incoming.placeholder && field.placeholder === incoming.placeholder)
|
|
812
|
+
return true;
|
|
763
813
|
if (field.locator?.accessibilityLabel && incoming.locator?.accessibilityLabel && field.locator.accessibilityLabel === incoming.locator.accessibilityLabel) {
|
|
764
814
|
return true;
|
|
765
815
|
}
|
|
@@ -919,9 +969,11 @@ var ScreenAnalyzer = class {
|
|
|
919
969
|
source: field.locator?.source ?? "accessibilityLabel"
|
|
920
970
|
});
|
|
921
971
|
} else if (attrName === "keyboardType") {
|
|
922
|
-
if (attr.value.value === "email-address" || attr.value.value === "email")
|
|
972
|
+
if (attr.value.value === "email-address" || attr.value.value === "email")
|
|
973
|
+
field.type = "email";
|
|
923
974
|
if (attr.value.value === "phone-pad") field.type = "phone";
|
|
924
|
-
if (attr.value.value === "numeric" || attr.value.value === "number-pad")
|
|
975
|
+
if (attr.value.value === "numeric" || attr.value.value === "number-pad")
|
|
976
|
+
field.type = "number";
|
|
925
977
|
}
|
|
926
978
|
} else if (BabelTypes__namespace.isJSXExpressionContainer(attr.value)) {
|
|
927
979
|
if (attrName === "value" && BabelTypes__namespace.isIdentifier(attr.value.expression)) {
|
|
@@ -1087,8 +1139,10 @@ var ScreenAnalyzer = class {
|
|
|
1087
1139
|
};
|
|
1088
1140
|
if (handler.nativeConfirmationExpected) action.nativeConfirmationExpected = true;
|
|
1089
1141
|
if (handler.targetScreen && !action.targetScreen) action.targetScreen = handler.targetScreen;
|
|
1090
|
-
if (handler.successSignal && !action.successSignal)
|
|
1091
|
-
|
|
1142
|
+
if (handler.successSignal && !action.successSignal)
|
|
1143
|
+
action.successSignal = handler.successSignal;
|
|
1144
|
+
if (handler.failureSignal && !action.failureSignal)
|
|
1145
|
+
action.failureSignal = handler.failureSignal;
|
|
1092
1146
|
if (handler.opensModal && !action.opensModal) action.opensModal = handler.opensModal;
|
|
1093
1147
|
if (handler.destructive || action.destructive === true || action.requiresConfirmation === true || action.effect === "destructive" || action.riskLevel === "high") {
|
|
1094
1148
|
action.destructive = true;
|
|
@@ -1106,6 +1160,7 @@ var ScreenAnalyzer = class {
|
|
|
1106
1160
|
if (!BabelTypes__namespace.isJSXIdentifier(element.name)) return;
|
|
1107
1161
|
const componentName = element.name.name;
|
|
1108
1162
|
if (classifyJsxComponent(componentName, element) !== "button") return;
|
|
1163
|
+
const pressProp = pressHandlerProp(element);
|
|
1109
1164
|
let label;
|
|
1110
1165
|
let handler;
|
|
1111
1166
|
for (const attr of element.attributes) {
|
|
@@ -1115,7 +1170,7 @@ var ScreenAnalyzer = class {
|
|
|
1115
1170
|
if ((attrName === "title" || attrName === "accessibilityLabel" || attrName === "label") && BabelTypes__namespace.isStringLiteral(attr.value)) {
|
|
1116
1171
|
label = attr.value.value;
|
|
1117
1172
|
}
|
|
1118
|
-
if (attrName ===
|
|
1173
|
+
if (attrName === pressProp && BabelTypes__namespace.isJSXExpressionContainer(attr.value) && BabelTypes__namespace.isIdentifier(attr.value.expression)) {
|
|
1119
1174
|
handler = attr.value.expression.name;
|
|
1120
1175
|
}
|
|
1121
1176
|
}
|
|
@@ -1181,10 +1236,13 @@ var ScreenAnalyzer = class {
|
|
|
1181
1236
|
}
|
|
1182
1237
|
};
|
|
1183
1238
|
if (fn.body) {
|
|
1184
|
-
traverse4__default.default(
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1239
|
+
traverse4__default.default(
|
|
1240
|
+
fn.body,
|
|
1241
|
+
{
|
|
1242
|
+
noScope: true,
|
|
1243
|
+
enter: (nodePath) => inspectNode(nodePath.node)
|
|
1244
|
+
}
|
|
1245
|
+
);
|
|
1188
1246
|
}
|
|
1189
1247
|
const expectedOutcome = targetScreen ? "navigation" : hasStateSetter ? "inline-feedback" : hasAwait || hasThen ? "mixed" : "none";
|
|
1190
1248
|
return {
|
|
@@ -1242,6 +1300,7 @@ var ScreenAnalyzer = class {
|
|
|
1242
1300
|
};
|
|
1243
1301
|
const componentName = BabelTypes__namespace.isJSXIdentifier(element.name) ? element.name.name : void 0;
|
|
1244
1302
|
action.sourceComponent = componentName;
|
|
1303
|
+
const pressProp = pressHandlerProp(element) ?? "onPress";
|
|
1245
1304
|
let handlerName;
|
|
1246
1305
|
for (const attr of element.attributes) {
|
|
1247
1306
|
if (!BabelTypes__namespace.isJSXAttribute(attr)) continue;
|
|
@@ -1276,7 +1335,7 @@ var ScreenAnalyzer = class {
|
|
|
1276
1335
|
}
|
|
1277
1336
|
}
|
|
1278
1337
|
} else if (BabelTypes__namespace.isJSXExpressionContainer(attr.value)) {
|
|
1279
|
-
if (attrName ===
|
|
1338
|
+
if (attrName === pressProp && BabelTypes__namespace.isIdentifier(attr.value.expression)) {
|
|
1280
1339
|
handlerName = attr.value.expression.name.toLowerCase();
|
|
1281
1340
|
action.handler = attr.value.expression.name;
|
|
1282
1341
|
if (handlerName.includes("submit")) {
|
|
@@ -1284,7 +1343,7 @@ var ScreenAnalyzer = class {
|
|
|
1284
1343
|
} else if (handlerName.includes("navigate")) {
|
|
1285
1344
|
action.type = "navigation";
|
|
1286
1345
|
}
|
|
1287
|
-
} else if (attrName ===
|
|
1346
|
+
} else if (attrName === pressProp) {
|
|
1288
1347
|
const inline = this.extractInlineOnPressMetadata(attr.value.expression);
|
|
1289
1348
|
if (inline.handler) {
|
|
1290
1349
|
handlerName = inline.handler.toLowerCase();
|
|
@@ -1308,7 +1367,11 @@ var ScreenAnalyzer = class {
|
|
|
1308
1367
|
}
|
|
1309
1368
|
}
|
|
1310
1369
|
if (!action.locator && action.id) {
|
|
1311
|
-
action.locator = {
|
|
1370
|
+
action.locator = {
|
|
1371
|
+
id: action.id,
|
|
1372
|
+
label: action.label,
|
|
1373
|
+
source: action.label ? "label" : "inferred"
|
|
1374
|
+
};
|
|
1312
1375
|
}
|
|
1313
1376
|
if (this.isElementDestructive(element, handlerName, action.id)) {
|
|
1314
1377
|
action.destructive = true;
|
|
@@ -1450,24 +1513,27 @@ var ScreenAnalyzer = class {
|
|
|
1450
1513
|
}
|
|
1451
1514
|
extractRowAction(fn) {
|
|
1452
1515
|
let action;
|
|
1453
|
-
traverse4__default.default(
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1516
|
+
traverse4__default.default(
|
|
1517
|
+
fn.body,
|
|
1518
|
+
{
|
|
1519
|
+
noScope: true,
|
|
1520
|
+
CallExpression: (nodePath) => {
|
|
1521
|
+
const node = nodePath.node;
|
|
1522
|
+
if (!BabelTypes__namespace.isMemberExpression(node.callee) || !BabelTypes__namespace.isIdentifier(node.callee.object) || node.callee.object.name !== "navigation" || !BabelTypes__namespace.isIdentifier(node.callee.property) || !["navigate", "push", "replace"].includes(node.callee.property.name)) {
|
|
1523
|
+
return;
|
|
1524
|
+
}
|
|
1525
|
+
const firstArg = node.arguments[0];
|
|
1526
|
+
if (!BabelTypes__namespace.isStringLiteral(firstArg)) return;
|
|
1527
|
+
const params = this.extractNavigationParams(node.arguments[1]);
|
|
1528
|
+
action = {
|
|
1529
|
+
type: "navigation",
|
|
1530
|
+
targetScreen: firstArg.value,
|
|
1531
|
+
...Object.keys(params).length > 0 ? { params } : {},
|
|
1532
|
+
description: `Pressing a row opens ${firstArg.value}`
|
|
1533
|
+
};
|
|
1459
1534
|
}
|
|
1460
|
-
const firstArg = node.arguments[0];
|
|
1461
|
-
if (!BabelTypes__namespace.isStringLiteral(firstArg)) return;
|
|
1462
|
-
const params = this.extractNavigationParams(node.arguments[1]);
|
|
1463
|
-
action = {
|
|
1464
|
-
type: "navigation",
|
|
1465
|
-
targetScreen: firstArg.value,
|
|
1466
|
-
...Object.keys(params).length > 0 ? { params } : {},
|
|
1467
|
-
description: `Pressing a row opens ${firstArg.value}`
|
|
1468
|
-
};
|
|
1469
1535
|
}
|
|
1470
|
-
|
|
1536
|
+
);
|
|
1471
1537
|
return action;
|
|
1472
1538
|
}
|
|
1473
1539
|
extractNavigationParams(arg) {
|
|
@@ -1500,15 +1566,18 @@ var ScreenAnalyzer = class {
|
|
|
1500
1566
|
} else if (BabelTypes__namespace.isIdentifier(firstParam)) {
|
|
1501
1567
|
itemNames.add(firstParam.name);
|
|
1502
1568
|
}
|
|
1503
|
-
traverse4__default.default(
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1569
|
+
traverse4__default.default(
|
|
1570
|
+
fn.body,
|
|
1571
|
+
{
|
|
1572
|
+
noScope: true,
|
|
1573
|
+
MemberExpression: (nodePath) => {
|
|
1574
|
+
const node = nodePath.node;
|
|
1575
|
+
if (BabelTypes__namespace.isIdentifier(node.object) && itemNames.has(node.object.name) && BabelTypes__namespace.isIdentifier(node.property)) {
|
|
1576
|
+
fields.add(node.property.name);
|
|
1577
|
+
}
|
|
1509
1578
|
}
|
|
1510
1579
|
}
|
|
1511
|
-
|
|
1580
|
+
);
|
|
1512
1581
|
return Array.from(fields).sort();
|
|
1513
1582
|
}
|
|
1514
1583
|
inferItemType(dataSource, renderItem, displayFields) {
|
|
@@ -1520,11 +1589,19 @@ var ScreenAnalyzer = class {
|
|
|
1520
1589
|
if (displayFields.length > 0) return "Item";
|
|
1521
1590
|
return void 0;
|
|
1522
1591
|
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Identity comes from how a field is NAMED, not from what the app
|
|
1594
|
+
* sells: `id`/`uuid`/`key`/`slug` are conventions any codebase uses,
|
|
1595
|
+
* `name`/`title`/`email` are how any row introduces itself. `plate`
|
|
1596
|
+
* used to sit in this list and read like one of them — but it is the
|
|
1597
|
+
* example app's schema, and no other tenant ever got its equivalent
|
|
1598
|
+
* (`mrn`, `trackingNumber`, `sku`) added here.
|
|
1599
|
+
*/
|
|
1523
1600
|
inferIdentityFields(keyField, displayFields) {
|
|
1524
1601
|
const out = /* @__PURE__ */ new Set();
|
|
1525
1602
|
if (keyField) out.add(keyField);
|
|
1526
1603
|
for (const field of displayFields) {
|
|
1527
|
-
if (/^(id|uuid|key|name|title|
|
|
1604
|
+
if (/^(id|uuid|key|name|title|email|slug)$/i.test(field)) out.add(field);
|
|
1528
1605
|
}
|
|
1529
1606
|
return Array.from(out);
|
|
1530
1607
|
}
|
|
@@ -1535,17 +1612,23 @@ var ScreenAnalyzer = class {
|
|
|
1535
1612
|
CallExpression: (nodePath) => {
|
|
1536
1613
|
const node = nodePath.node;
|
|
1537
1614
|
if (!BabelTypes__namespace.isMemberExpression(node.callee)) return;
|
|
1538
|
-
if (!BabelTypes__namespace.isIdentifier(node.callee.property) || node.callee.property.name !== "filter")
|
|
1539
|
-
|
|
1615
|
+
if (!BabelTypes__namespace.isIdentifier(node.callee.property) || node.callee.property.name !== "filter")
|
|
1616
|
+
return;
|
|
1617
|
+
if (!BabelTypes__namespace.isIdentifier(node.callee.object) || node.callee.object.name !== dataSource)
|
|
1618
|
+
return;
|
|
1540
1619
|
const fn = node.arguments[0];
|
|
1541
|
-
if (!BabelTypes__namespace.isArrowFunctionExpression(fn) && !BabelTypes__namespace.isFunctionExpression(fn))
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1620
|
+
if (!BabelTypes__namespace.isArrowFunctionExpression(fn) && !BabelTypes__namespace.isFunctionExpression(fn))
|
|
1621
|
+
return;
|
|
1622
|
+
traverse4__default.default(
|
|
1623
|
+
fn.body,
|
|
1624
|
+
{
|
|
1625
|
+
noScope: true,
|
|
1626
|
+
Identifier: (innerPath) => {
|
|
1627
|
+
const name = innerPath.node.name;
|
|
1628
|
+
if (/query|search|filter/i.test(name)) queryBinding = queryBinding ?? name;
|
|
1629
|
+
}
|
|
1547
1630
|
}
|
|
1548
|
-
|
|
1631
|
+
);
|
|
1549
1632
|
}
|
|
1550
1633
|
});
|
|
1551
1634
|
return queryBinding;
|
|
@@ -1689,11 +1772,7 @@ var NavigationAnalyzer = class {
|
|
|
1689
1772
|
if (BabelTypes__namespace.isJSXAttribute(initialRouteAttr) && BabelTypes__namespace.isStringLiteral(initialRouteAttr.value)) {
|
|
1690
1773
|
navigator.initialRouteName = initialRouteAttr.value.value;
|
|
1691
1774
|
}
|
|
1692
|
-
const screens = this.extractScreensFromNavigator(
|
|
1693
|
-
node,
|
|
1694
|
-
objectName,
|
|
1695
|
-
navigator.type
|
|
1696
|
-
);
|
|
1775
|
+
const screens = this.extractScreensFromNavigator(node, objectName, navigator.type);
|
|
1697
1776
|
screensByNavigator.set(objectName, screens);
|
|
1698
1777
|
}
|
|
1699
1778
|
}
|
|
@@ -1710,27 +1789,112 @@ var NavigationAnalyzer = class {
|
|
|
1710
1789
|
}
|
|
1711
1790
|
return navigators;
|
|
1712
1791
|
}
|
|
1792
|
+
/**
|
|
1793
|
+
* Is this JSX element `<navigatorVarName.MEMBER …>`?
|
|
1794
|
+
*/
|
|
1795
|
+
// Deliberately NOT a type predicate (`node is t.JSXElement`): a false
|
|
1796
|
+
// result would then narrow `node` to "not a JSXElement", and the very
|
|
1797
|
+
// next check — the same node against a different member — would see
|
|
1798
|
+
// `never`. It is a question about the member name, not about the node
|
|
1799
|
+
// kind.
|
|
1800
|
+
isNavigatorMember(node, navigatorVarName, member) {
|
|
1801
|
+
if (!BabelTypes__namespace.isJSXElement(node)) return false;
|
|
1802
|
+
const name = node.openingElement.name;
|
|
1803
|
+
return BabelTypes__namespace.isJSXMemberExpression(name) && BabelTypes__namespace.isJSXIdentifier(name.object) && name.object.name === navigatorVarName && BabelTypes__namespace.isJSXIdentifier(name.property) && name.property.name === member;
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Flatten a navigator's JSX children into the `<X.Screen>` elements they
|
|
1807
|
+
* contain, unwrapping every container a real app puts in between.
|
|
1808
|
+
*
|
|
1809
|
+
* The old version compared `t.isJSXElement(child)` against the direct
|
|
1810
|
+
* children only. A ternary is a `JSXExpressionContainer`, so an
|
|
1811
|
+
* auth-gated root — the modal shape of a commercial app, and the shape
|
|
1812
|
+
* of this repo's own `apps/example-app` — contributed ZERO screens to
|
|
1813
|
+
* the graph while `appilots sync` reported success (#396).
|
|
1814
|
+
*
|
|
1815
|
+
* Both branches of a conditional are collected on purpose. The graph is
|
|
1816
|
+
* a design-time map of what routes EXIST, not a prediction of which one
|
|
1817
|
+
* a given session will render; the agent needs the destination name to
|
|
1818
|
+
* be there whether or not the user happens to be logged in right now.
|
|
1819
|
+
*/
|
|
1820
|
+
collectScreenElements(children, navigatorVarName, depth = 0) {
|
|
1821
|
+
if (depth > 12) return [];
|
|
1822
|
+
const found = [];
|
|
1823
|
+
const visit = (node) => {
|
|
1824
|
+
if (!node) return;
|
|
1825
|
+
if (this.isNavigatorMember(node, navigatorVarName, "Screen")) {
|
|
1826
|
+
found.push(node);
|
|
1827
|
+
return;
|
|
1828
|
+
}
|
|
1829
|
+
if (this.isNavigatorMember(node, navigatorVarName, "Group")) {
|
|
1830
|
+
const group = node;
|
|
1831
|
+
found.push(...this.collectScreenElements(group.children, navigatorVarName, depth + 1));
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
if (BabelTypes__namespace.isJSXElement(node)) {
|
|
1835
|
+
const name = node.openingElement.name;
|
|
1836
|
+
const isForeignNavigator = BabelTypes__namespace.isJSXMemberExpression(name) && BabelTypes__namespace.isJSXIdentifier(name.property) && name.property.name === "Navigator";
|
|
1837
|
+
if (isForeignNavigator) return;
|
|
1838
|
+
found.push(...this.collectScreenElements(node.children, navigatorVarName, depth + 1));
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
if (BabelTypes__namespace.isJSXFragment(node)) {
|
|
1842
|
+
found.push(...this.collectScreenElements(node.children, navigatorVarName, depth + 1));
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
if (BabelTypes__namespace.isJSXExpressionContainer(node)) {
|
|
1846
|
+
visit(node.expression);
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1849
|
+
if (BabelTypes__namespace.isConditionalExpression(node)) {
|
|
1850
|
+
visit(node.consequent);
|
|
1851
|
+
visit(node.alternate);
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
if (BabelTypes__namespace.isLogicalExpression(node)) {
|
|
1855
|
+
visit(node.left);
|
|
1856
|
+
visit(node.right);
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
if (BabelTypes__namespace.isCallExpression(node)) {
|
|
1860
|
+
for (const arg of node.arguments) {
|
|
1861
|
+
if (BabelTypes__namespace.isArrowFunctionExpression(arg) || BabelTypes__namespace.isFunctionExpression(arg)) {
|
|
1862
|
+
if (BabelTypes__namespace.isBlockStatement(arg.body)) {
|
|
1863
|
+
for (const stmt of arg.body.body) {
|
|
1864
|
+
if (BabelTypes__namespace.isReturnStatement(stmt)) visit(stmt.argument);
|
|
1865
|
+
}
|
|
1866
|
+
} else {
|
|
1867
|
+
visit(arg.body);
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
if (BabelTypes__namespace.isArrayExpression(node)) {
|
|
1874
|
+
for (const el of node.elements) visit(el);
|
|
1875
|
+
return;
|
|
1876
|
+
}
|
|
1877
|
+
if (BabelTypes__namespace.isTSAsExpression(node) || BabelTypes__namespace.isTSNonNullExpression(node)) {
|
|
1878
|
+
visit(node.expression);
|
|
1879
|
+
}
|
|
1880
|
+
};
|
|
1881
|
+
for (const child of children) visit(child);
|
|
1882
|
+
return found;
|
|
1883
|
+
}
|
|
1713
1884
|
/** Extract screens from a navigator JSX element */
|
|
1714
1885
|
extractScreensFromNavigator(navigatorElement, navigatorVarName, navigatorType) {
|
|
1715
1886
|
const screens = [];
|
|
1716
1887
|
if (!navigatorElement.children) return screens;
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
name: screenName,
|
|
1728
|
-
navigatorName: navigatorVarName,
|
|
1729
|
-
navigatorType
|
|
1730
|
-
});
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
}
|
|
1888
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1889
|
+
for (const element of this.collectScreenElements(navigatorElement.children, navigatorVarName)) {
|
|
1890
|
+
const screenName = this.extractAttributeValue(element.openingElement.attributes, "name");
|
|
1891
|
+
if (!screenName || seen.has(screenName)) continue;
|
|
1892
|
+
seen.add(screenName);
|
|
1893
|
+
screens.push({
|
|
1894
|
+
name: screenName,
|
|
1895
|
+
navigatorName: navigatorVarName,
|
|
1896
|
+
navigatorType
|
|
1897
|
+
});
|
|
1734
1898
|
}
|
|
1735
1899
|
return screens;
|
|
1736
1900
|
}
|
|
@@ -1789,9 +1953,7 @@ var NavigationAnalyzer = class {
|
|
|
1789
1953
|
if (member.type === "TSPropertySignature" && member.key) {
|
|
1790
1954
|
const keyName = member.key.type === "Identifier" ? member.key.name : null;
|
|
1791
1955
|
if (keyName && member.typeAnnotation) {
|
|
1792
|
-
const params = this.extractParamsFromType(
|
|
1793
|
-
member.typeAnnotation.typeAnnotation
|
|
1794
|
-
);
|
|
1956
|
+
const params = this.extractParamsFromType(member.typeAnnotation.typeAnnotation);
|
|
1795
1957
|
entries.set(keyName, params);
|
|
1796
1958
|
}
|
|
1797
1959
|
}
|
|
@@ -1870,6 +2032,11 @@ var NavigationAnalyzer = class {
|
|
|
1870
2032
|
let initialScreen = "";
|
|
1871
2033
|
for (const navigator of parsedNavigators) {
|
|
1872
2034
|
const screenNames = navigator.screens.map((s) => s.name);
|
|
2035
|
+
if (screenNames.length === 0) {
|
|
2036
|
+
console.warn(
|
|
2037
|
+
`[MCPGenerator] navigator "${navigator.name}" (${navigator.type}) declared no reachable screens. Its routes will be missing from the app map, so the agent will have no destination name for them. If the screens are there in the source, this is a parser gap \u2014 please report it with the file.`
|
|
2038
|
+
);
|
|
2039
|
+
}
|
|
1873
2040
|
navigators.push({
|
|
1874
2041
|
name: navigator.name,
|
|
1875
2042
|
type: navigator.type,
|
|
@@ -2657,7 +2824,9 @@ var WebScreenAnalyzer = class {
|
|
|
2657
2824
|
include = ["**/*.tsx", "**/*.ts", "**/*.jsx", "**/*.js"],
|
|
2658
2825
|
exclude = ["**/node_modules/**", "**/dist/**", "**/build/**"]
|
|
2659
2826
|
} = this.config;
|
|
2660
|
-
const files = await glob__default.default(include, { cwd: this.config.rootDir, ignore: exclude })
|
|
2827
|
+
const files = (await glob__default.default(include, { cwd: this.config.rootDir, ignore: exclude })).filter(
|
|
2828
|
+
(file) => !file.endsWith(".d.ts")
|
|
2829
|
+
);
|
|
2661
2830
|
const patternMatches = await glob__default.default(this.screenPatterns, {
|
|
2662
2831
|
cwd: this.config.rootDir,
|
|
2663
2832
|
ignore: exclude
|
|
@@ -3028,7 +3197,8 @@ var WebScreenAnalyzer = class {
|
|
|
3028
3197
|
if (type === "email") return "email";
|
|
3029
3198
|
if (type === "tel") return "phone";
|
|
3030
3199
|
if (type === "number") return "number";
|
|
3031
|
-
if (type === "date" || type === "datetime-local" || type === "month" || type === "week")
|
|
3200
|
+
if (type === "date" || type === "datetime-local" || type === "month" || type === "week")
|
|
3201
|
+
return "date";
|
|
3032
3202
|
const inputMode = getStringAttr(opening, "inputMode") ?? getStringAttr(opening, "inputmode");
|
|
3033
3203
|
if (inputMode === "email") return "email";
|
|
3034
3204
|
if (inputMode === "tel") return "phone";
|
|
@@ -3342,7 +3512,9 @@ var WebScreenAnalyzer = class {
|
|
|
3342
3512
|
}
|
|
3343
3513
|
const callback = expr.arguments[0];
|
|
3344
3514
|
if (!BabelTypes__namespace.isArrowFunctionExpression(callback) && !BabelTypes__namespace.isFunctionExpression(callback)) return;
|
|
3345
|
-
const enclosing = nodePath.findParent(
|
|
3515
|
+
const enclosing = nodePath.findParent(
|
|
3516
|
+
(p) => p.isJSXElement()
|
|
3517
|
+
);
|
|
3346
3518
|
const enclosingName = enclosing ? getJsxElementName(enclosing.node.openingElement) : null;
|
|
3347
3519
|
const enclosingRole = enclosing && enclosingName ? classifyWebJsxComponent(enclosingName, enclosing.node.openingElement) : null;
|
|
3348
3520
|
const returnsListItem = callbackReturnsTag(callback, /* @__PURE__ */ new Set(["li", "tr"]));
|
|
@@ -3444,16 +3616,19 @@ function firstCalledFunctionName(node) {
|
|
|
3444
3616
|
}
|
|
3445
3617
|
function containsWindowConfirm(body) {
|
|
3446
3618
|
let found = false;
|
|
3447
|
-
traverse4__default.default(
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
found = true;
|
|
3619
|
+
traverse4__default.default(
|
|
3620
|
+
body,
|
|
3621
|
+
{
|
|
3622
|
+
noScope: true,
|
|
3623
|
+
CallExpression: (nodePath) => {
|
|
3624
|
+
const callee = nodePath.node.callee;
|
|
3625
|
+
if (BabelTypes__namespace.isIdentifier(callee) && callee.name === "confirm") found = true;
|
|
3626
|
+
if (BabelTypes__namespace.isMemberExpression(callee) && BabelTypes__namespace.isIdentifier(callee.object) && callee.object.name === "window" && BabelTypes__namespace.isIdentifier(callee.property) && callee.property.name === "confirm") {
|
|
3627
|
+
found = true;
|
|
3628
|
+
}
|
|
3454
3629
|
}
|
|
3455
3630
|
}
|
|
3456
|
-
|
|
3631
|
+
);
|
|
3457
3632
|
return found;
|
|
3458
3633
|
}
|
|
3459
3634
|
function mergeLocator(current, next) {
|
|
@@ -3493,32 +3668,38 @@ function collectionItemNames(callback) {
|
|
|
3493
3668
|
function collectionDisplayFields(callback, itemNames) {
|
|
3494
3669
|
const fields = /* @__PURE__ */ new Set();
|
|
3495
3670
|
if (!callback.body) return [];
|
|
3496
|
-
traverse4__default.default(
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3671
|
+
traverse4__default.default(
|
|
3672
|
+
callback.body,
|
|
3673
|
+
{
|
|
3674
|
+
noScope: true,
|
|
3675
|
+
MemberExpression: (nodePath) => {
|
|
3676
|
+
const node = nodePath.node;
|
|
3677
|
+
if (BabelTypes__namespace.isIdentifier(node.object) && itemNames.has(node.object.name) && BabelTypes__namespace.isIdentifier(node.property)) {
|
|
3678
|
+
fields.add(node.property.name);
|
|
3679
|
+
}
|
|
3502
3680
|
}
|
|
3503
3681
|
}
|
|
3504
|
-
|
|
3682
|
+
);
|
|
3505
3683
|
return Array.from(fields).sort();
|
|
3506
3684
|
}
|
|
3507
3685
|
function collectionKeyField(callback, itemNames) {
|
|
3508
3686
|
let keyField;
|
|
3509
3687
|
if (!callback.body) return void 0;
|
|
3510
|
-
traverse4__default.default(
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3688
|
+
traverse4__default.default(
|
|
3689
|
+
callback.body,
|
|
3690
|
+
{
|
|
3691
|
+
noScope: true,
|
|
3692
|
+
JSXAttribute: (nodePath) => {
|
|
3693
|
+
const attr = nodePath.node;
|
|
3694
|
+
if (!BabelTypes__namespace.isJSXIdentifier(attr.name) || attr.name.name !== "key") return;
|
|
3695
|
+
if (!attr.value || !BabelTypes__namespace.isJSXExpressionContainer(attr.value)) return;
|
|
3696
|
+
const expr = attr.value.expression;
|
|
3697
|
+
if (BabelTypes__namespace.isMemberExpression(expr) && BabelTypes__namespace.isIdentifier(expr.object) && itemNames.has(expr.object.name) && BabelTypes__namespace.isIdentifier(expr.property)) {
|
|
3698
|
+
keyField = keyField ?? expr.property.name;
|
|
3699
|
+
}
|
|
3519
3700
|
}
|
|
3520
3701
|
}
|
|
3521
|
-
|
|
3702
|
+
);
|
|
3522
3703
|
return keyField;
|
|
3523
3704
|
}
|
|
3524
3705
|
function collectionRowAction(callback) {
|
|
@@ -3566,7 +3747,7 @@ function inferIdentityFields(keyField, displayFields) {
|
|
|
3566
3747
|
const out = /* @__PURE__ */ new Set();
|
|
3567
3748
|
if (keyField) out.add(keyField);
|
|
3568
3749
|
for (const field of displayFields) {
|
|
3569
|
-
if (/^(id|uuid|key|name|title|
|
|
3750
|
+
if (/^(id|uuid|key|name|title|email|slug)$/i.test(field)) out.add(field);
|
|
3570
3751
|
}
|
|
3571
3752
|
return Array.from(out);
|
|
3572
3753
|
}
|
|
@@ -7950,7 +8131,7 @@ var coerce = {
|
|
|
7950
8131
|
};
|
|
7951
8132
|
var NEVER = INVALID;
|
|
7952
8133
|
|
|
7953
|
-
// ../shared/dist/chunk-
|
|
8134
|
+
// ../shared/dist/chunk-MKT45LRA.mjs
|
|
7954
8135
|
var locatorSourceSchema = external_exports.enum([
|
|
7955
8136
|
"appilotsId",
|
|
7956
8137
|
"testID",
|
|
@@ -7976,7 +8157,16 @@ var locatorDescriptorSchema = external_exports.object({
|
|
|
7976
8157
|
source: locatorSourceSchema.optional()
|
|
7977
8158
|
}).passthrough();
|
|
7978
8159
|
var signalDescriptorSchema = external_exports.object({
|
|
7979
|
-
type: external_exports.enum([
|
|
8160
|
+
type: external_exports.enum([
|
|
8161
|
+
"navigation",
|
|
8162
|
+
"goBack",
|
|
8163
|
+
"toast",
|
|
8164
|
+
"modal",
|
|
8165
|
+
"inline-error",
|
|
8166
|
+
"data-arrival",
|
|
8167
|
+
"loading",
|
|
8168
|
+
"none"
|
|
8169
|
+
]).or(external_exports.string().min(1).max(60)),
|
|
7980
8170
|
target: external_exports.string().optional(),
|
|
7981
8171
|
description: external_exports.string().optional()
|
|
7982
8172
|
}).passthrough();
|
|
@@ -7990,7 +8180,20 @@ var waitPolicyDescriptorSchema = external_exports.object({
|
|
|
7990
8180
|
signals: external_exports.array(signalDescriptorSchema).optional(),
|
|
7991
8181
|
maxMs: external_exports.number().finite().optional()
|
|
7992
8182
|
}).passthrough();
|
|
7993
|
-
var targetDescriptorRoleSchema = external_exports.enum([
|
|
8183
|
+
var targetDescriptorRoleSchema = external_exports.enum([
|
|
8184
|
+
"button",
|
|
8185
|
+
"submit",
|
|
8186
|
+
"input",
|
|
8187
|
+
"toggle",
|
|
8188
|
+
"select",
|
|
8189
|
+
"date",
|
|
8190
|
+
"list",
|
|
8191
|
+
"row",
|
|
8192
|
+
"menuItem",
|
|
8193
|
+
"modal",
|
|
8194
|
+
"custom"
|
|
8195
|
+
]).or(external_exports.string().min(1).max(60));
|
|
8196
|
+
var targetOriginSchema = external_exports.enum(["analyzer", "manifest"]).or(external_exports.string().min(1).max(40));
|
|
7994
8197
|
var targetDescriptorSchema = external_exports.object({
|
|
7995
8198
|
id: external_exports.string(),
|
|
7996
8199
|
role: targetDescriptorRoleSchema,
|
|
@@ -8004,10 +8207,20 @@ var targetDescriptorSchema = external_exports.object({
|
|
|
8004
8207
|
requiresConfirmation: external_exports.boolean().optional(),
|
|
8005
8208
|
opensModal: external_exports.string().optional(),
|
|
8006
8209
|
opensBottomSheet: external_exports.string().optional(),
|
|
8007
|
-
sourceComponent: external_exports.string().optional()
|
|
8210
|
+
sourceComponent: external_exports.string().optional(),
|
|
8211
|
+
origin: targetOriginSchema.optional()
|
|
8008
8212
|
}).passthrough();
|
|
8009
8213
|
var flowStepDescriptorSchema = external_exports.object({
|
|
8010
|
-
type: external_exports.enum([
|
|
8214
|
+
type: external_exports.enum([
|
|
8215
|
+
"navigate",
|
|
8216
|
+
"fill",
|
|
8217
|
+
"press",
|
|
8218
|
+
"select",
|
|
8219
|
+
"toggle",
|
|
8220
|
+
"wait",
|
|
8221
|
+
"confirm",
|
|
8222
|
+
"choose-list-item"
|
|
8223
|
+
]).or(external_exports.string().min(1).max(60)),
|
|
8011
8224
|
target: external_exports.string().optional(),
|
|
8012
8225
|
label: external_exports.string().optional(),
|
|
8013
8226
|
description: external_exports.string().optional(),
|
|
@@ -8229,15 +8442,31 @@ external_exports.object({
|
|
|
8229
8442
|
password: external_exports.string().min(1, "Password is required"),
|
|
8230
8443
|
code: totpCodeSchema
|
|
8231
8444
|
});
|
|
8445
|
+
external_exports.object({
|
|
8446
|
+
password: external_exports.string().min(1, "Password is required"),
|
|
8447
|
+
code: totpCodeSchema.optional(),
|
|
8448
|
+
recoveryCode: recoveryCodeSchema.optional(),
|
|
8449
|
+
confirm: external_exports.literal("DELETE MY ACCOUNT")
|
|
8450
|
+
}).refine((v) => !(v.code && v.recoveryCode), {
|
|
8451
|
+
message: "Provide either a TOTP code or a recovery code, not both",
|
|
8452
|
+
path: ["code"]
|
|
8453
|
+
});
|
|
8232
8454
|
var createProjectSchema = external_exports.object({
|
|
8233
8455
|
name: external_exports.string().min(1).max(100),
|
|
8234
8456
|
description: external_exports.string().max(500).optional(),
|
|
8235
8457
|
// Reference to a tenant-scoped provider (preferred). Optional at
|
|
8236
8458
|
// creation so a project can be created and configured later.
|
|
8237
8459
|
providerId: external_exports.string().min(1).optional(),
|
|
8238
|
-
|
|
8460
|
+
// 16k chars (~4k tokens): um prompt de CS real não cabe em 4096 — o
|
|
8461
|
+
// primeiro cliente de produção chegou com 6.385 e tomou 'Invalid input'
|
|
8462
|
+
// sem saber por quê. O teto continua existindo porque o systemPrompt
|
|
8463
|
+
// entra em TODO hop do relay: é proteção de TPM, não de gosto.
|
|
8464
|
+
systemPrompt: external_exports.string().max(16e3).optional()
|
|
8465
|
+
});
|
|
8466
|
+
createProjectSchema.partial().extend({
|
|
8467
|
+
providerId: external_exports.string().min(1).nullable().optional(),
|
|
8468
|
+
systemPrompt: external_exports.string().max(16e3).nullable().optional()
|
|
8239
8469
|
});
|
|
8240
|
-
createProjectSchema.partial();
|
|
8241
8470
|
var providerKindSchema = external_exports.enum(["openai", "anthropic", "custom"]);
|
|
8242
8471
|
external_exports.object({
|
|
8243
8472
|
name: external_exports.string().min(1).max(100),
|
|
@@ -8264,6 +8493,7 @@ external_exports.object({
|
|
|
8264
8493
|
content: external_exports.record(external_exports.unknown())
|
|
8265
8494
|
});
|
|
8266
8495
|
var apiKeyScopeSchema = external_exports.enum(["sdk", "operator"]);
|
|
8496
|
+
var apiKeyEnvironmentSchema = external_exports.enum(["test", "live"]);
|
|
8267
8497
|
external_exports.object({
|
|
8268
8498
|
name: external_exports.string().min(1).max(100),
|
|
8269
8499
|
// Required for `sdk` (default), forbidden/ignored for `operator` —
|
|
@@ -8271,6 +8501,7 @@ external_exports.object({
|
|
|
8271
8501
|
// missing scope still validates as the pre-existing SDK shape.
|
|
8272
8502
|
projectId: external_exports.string().min(1).optional(),
|
|
8273
8503
|
scope: apiKeyScopeSchema.default("sdk"),
|
|
8504
|
+
environment: apiKeyEnvironmentSchema.optional(),
|
|
8274
8505
|
expiresAt: external_exports.string().datetime().optional()
|
|
8275
8506
|
}).refine((v) => v.scope !== "sdk" || !!v.projectId, {
|
|
8276
8507
|
message: 'projectId is required for scope "sdk"',
|
|
@@ -8278,13 +8509,23 @@ external_exports.object({
|
|
|
8278
8509
|
});
|
|
8279
8510
|
var boundedString = (max) => external_exports.string().max(max);
|
|
8280
8511
|
var clientPlatformSchema = external_exports.enum(["react-native", "web", "android", "ios"]).or(external_exports.string().min(1).max(40));
|
|
8512
|
+
var identityProvenanceSchema = external_exports.enum(["declared", "derived", "positional"]).or(external_exports.string().min(1).max(40));
|
|
8281
8513
|
var snapshotInputSchema = external_exports.object({
|
|
8282
8514
|
id: boundedString(160).optional(),
|
|
8515
|
+
provenance: identityProvenanceSchema.optional(),
|
|
8516
|
+
/**
|
|
8517
|
+
* False when the control is mounted but currently OUTSIDE the window —
|
|
8518
|
+
* below the fold, scrolled off, pushed sideways. Absent means the client
|
|
8519
|
+
* cannot tell (old React Native architecture, or any SDK published
|
|
8520
|
+
* before the field existed), which must never be read as `false`.
|
|
8521
|
+
*/
|
|
8522
|
+
onScreen: external_exports.boolean().optional(),
|
|
8283
8523
|
label: boundedString(300).optional(),
|
|
8284
8524
|
value: boundedString(4096).optional(),
|
|
8285
8525
|
placeholder: boundedString(300).optional(),
|
|
8286
8526
|
editable: external_exports.boolean().optional(),
|
|
8287
8527
|
secure: external_exports.boolean().optional(),
|
|
8528
|
+
submitsOnReturn: external_exports.boolean().optional(),
|
|
8288
8529
|
type: boundedString(40).optional(),
|
|
8289
8530
|
required: external_exports.boolean().optional(),
|
|
8290
8531
|
invalid: external_exports.boolean().optional(),
|
|
@@ -8292,6 +8533,14 @@ var snapshotInputSchema = external_exports.object({
|
|
|
8292
8533
|
}).passthrough();
|
|
8293
8534
|
var snapshotButtonSchema = external_exports.object({
|
|
8294
8535
|
id: boundedString(160).optional(),
|
|
8536
|
+
provenance: identityProvenanceSchema.optional(),
|
|
8537
|
+
/**
|
|
8538
|
+
* False when the control is mounted but currently OUTSIDE the window —
|
|
8539
|
+
* below the fold, scrolled off, pushed sideways. Absent means the client
|
|
8540
|
+
* cannot tell (old React Native architecture, or any SDK published
|
|
8541
|
+
* before the field existed), which must never be read as `false`.
|
|
8542
|
+
*/
|
|
8543
|
+
onScreen: external_exports.boolean().optional(),
|
|
8295
8544
|
label: boundedString(300).optional(),
|
|
8296
8545
|
disabled: external_exports.boolean().optional(),
|
|
8297
8546
|
inModal: external_exports.boolean().optional(),
|
|
@@ -8301,12 +8550,28 @@ var snapshotButtonSchema = external_exports.object({
|
|
|
8301
8550
|
}).passthrough();
|
|
8302
8551
|
var snapshotToggleSchema = external_exports.object({
|
|
8303
8552
|
id: boundedString(160).optional(),
|
|
8553
|
+
provenance: identityProvenanceSchema.optional(),
|
|
8554
|
+
/**
|
|
8555
|
+
* False when the control is mounted but currently OUTSIDE the window —
|
|
8556
|
+
* below the fold, scrolled off, pushed sideways. Absent means the client
|
|
8557
|
+
* cannot tell (old React Native architecture, or any SDK published
|
|
8558
|
+
* before the field existed), which must never be read as `false`.
|
|
8559
|
+
*/
|
|
8560
|
+
onScreen: external_exports.boolean().optional(),
|
|
8304
8561
|
label: boundedString(300).optional(),
|
|
8305
8562
|
value: external_exports.boolean().optional(),
|
|
8306
8563
|
inModal: external_exports.boolean().optional()
|
|
8307
8564
|
}).passthrough();
|
|
8308
8565
|
var snapshotSliderSchema = external_exports.object({
|
|
8309
8566
|
id: boundedString(160).optional(),
|
|
8567
|
+
provenance: identityProvenanceSchema.optional(),
|
|
8568
|
+
/**
|
|
8569
|
+
* False when the control is mounted but currently OUTSIDE the window —
|
|
8570
|
+
* below the fold, scrolled off, pushed sideways. Absent means the client
|
|
8571
|
+
* cannot tell (old React Native architecture, or any SDK published
|
|
8572
|
+
* before the field existed), which must never be read as `false`.
|
|
8573
|
+
*/
|
|
8574
|
+
onScreen: external_exports.boolean().optional(),
|
|
8310
8575
|
label: boundedString(300).optional(),
|
|
8311
8576
|
value: external_exports.number().finite().optional(),
|
|
8312
8577
|
min: external_exports.number().finite().optional(),
|
|
@@ -8347,6 +8612,26 @@ var snapshotListSchema = external_exports.object({
|
|
|
8347
8612
|
// should chase, and the relay only reads a known subset.
|
|
8348
8613
|
items: external_exports.array(external_exports.record(external_exports.unknown())).max(500).optional()
|
|
8349
8614
|
}).passthrough();
|
|
8615
|
+
var snapshotNativeDialogSchema = external_exports.object({
|
|
8616
|
+
id: boundedString(160),
|
|
8617
|
+
title: boundedString(300).optional(),
|
|
8618
|
+
message: boundedString(2e3).optional(),
|
|
8619
|
+
buttons: external_exports.array(
|
|
8620
|
+
external_exports.object({
|
|
8621
|
+
label: boundedString(160),
|
|
8622
|
+
style: external_exports.enum(["default", "cancel", "destructive"]).optional()
|
|
8623
|
+
}).passthrough()
|
|
8624
|
+
).max(10)
|
|
8625
|
+
}).passthrough();
|
|
8626
|
+
var snapshotScrollableSchema = external_exports.object({
|
|
8627
|
+
id: boundedString(160),
|
|
8628
|
+
containerType: boundedString(60).optional(),
|
|
8629
|
+
label: boundedString(300).optional(),
|
|
8630
|
+
scrollOffsetY: external_exports.number().finite().optional(),
|
|
8631
|
+
canScrollUp: external_exports.boolean().optional(),
|
|
8632
|
+
canScrollDown: external_exports.boolean().optional(),
|
|
8633
|
+
horizontal: external_exports.boolean().optional()
|
|
8634
|
+
}).passthrough();
|
|
8350
8635
|
var snapshotChoiceGroupSchema = external_exports.object({
|
|
8351
8636
|
index: external_exports.number().int().optional(),
|
|
8352
8637
|
id: boundedString(160).optional(),
|
|
@@ -8363,6 +8648,14 @@ var snapshotElementSchema = external_exports.object({
|
|
|
8363
8648
|
disabled: external_exports.boolean().optional(),
|
|
8364
8649
|
selected: external_exports.boolean().optional(),
|
|
8365
8650
|
source: boundedString(40).optional(),
|
|
8651
|
+
provenance: identityProvenanceSchema.optional(),
|
|
8652
|
+
/**
|
|
8653
|
+
* False when the control is mounted but currently OUTSIDE the window —
|
|
8654
|
+
* below the fold, scrolled off, pushed sideways. Absent means the client
|
|
8655
|
+
* cannot tell (old React Native architecture, or any SDK published
|
|
8656
|
+
* before the field existed), which must never be read as `false`.
|
|
8657
|
+
*/
|
|
8658
|
+
onScreen: external_exports.boolean().optional(),
|
|
8366
8659
|
targetId: boundedString(160).optional(),
|
|
8367
8660
|
listContext: external_exports.record(external_exports.unknown()).optional(),
|
|
8368
8661
|
inModal: external_exports.boolean().optional()
|
|
@@ -8379,7 +8672,34 @@ var agentSnapshotSchema = external_exports.object({
|
|
|
8379
8672
|
modalOpen: external_exports.boolean().optional(),
|
|
8380
8673
|
lists: external_exports.array(snapshotListSchema).max(100).optional(),
|
|
8381
8674
|
choiceGroups: external_exports.array(snapshotChoiceGroupSchema).max(100).optional(),
|
|
8382
|
-
|
|
8675
|
+
scrollables: external_exports.array(snapshotScrollableSchema).max(20).optional(),
|
|
8676
|
+
nativeDialog: snapshotNativeDialogSchema.optional(),
|
|
8677
|
+
elements: external_exports.array(snapshotElementSchema).max(1e3).optional(),
|
|
8678
|
+
/**
|
|
8679
|
+
* The client clamped this observation to the caps above and lost
|
|
8680
|
+
* data doing it (`clampSnapshotToWireLimits` in
|
|
8681
|
+
* `@appilots/client-core`). Read by the prompt serializer so the
|
|
8682
|
+
* model is told the view is partial — a screen truncated at 500
|
|
8683
|
+
* texts must not be read as a screen that only has 500 things on
|
|
8684
|
+
* it. Optional: older SDKs never clamp and never send it.
|
|
8685
|
+
*/
|
|
8686
|
+
truncated: external_exports.boolean().optional(),
|
|
8687
|
+
/**
|
|
8688
|
+
* How many of this screen's controls the client could name, split by
|
|
8689
|
+
* `identityProvenance`. Diagnostic only — the relay never grounds an
|
|
8690
|
+
* action on it — but it is the number that says whether an app needs
|
|
8691
|
+
* annotating, and comparing it between a debug and a release build is
|
|
8692
|
+
* the first direct measurement of what minification costs the agent.
|
|
8693
|
+
*/
|
|
8694
|
+
stats: external_exports.object({
|
|
8695
|
+
visitedFibers: external_exports.number().int().nonnegative().optional(),
|
|
8696
|
+
skippedHidden: external_exports.number().int().nonnegative().optional(),
|
|
8697
|
+
identity: external_exports.object({
|
|
8698
|
+
declared: external_exports.number().int().nonnegative().optional(),
|
|
8699
|
+
derived: external_exports.number().int().nonnegative().optional(),
|
|
8700
|
+
positional: external_exports.number().int().nonnegative().optional()
|
|
8701
|
+
}).passthrough().optional()
|
|
8702
|
+
}).passthrough().optional()
|
|
8383
8703
|
}).passthrough();
|
|
8384
8704
|
var agentContextSchema = external_exports.object({
|
|
8385
8705
|
/**
|
|
@@ -8429,6 +8749,19 @@ var agentContextSchema = external_exports.object({
|
|
|
8429
8749
|
).max(200).optional(),
|
|
8430
8750
|
loadingPending: external_exports.boolean().optional()
|
|
8431
8751
|
}).passthrough();
|
|
8752
|
+
var introspectionFailureReasonSchema = external_exports.enum([
|
|
8753
|
+
"sentinel-missing-internals",
|
|
8754
|
+
"never-mounted",
|
|
8755
|
+
"render-crashed",
|
|
8756
|
+
"names-mangled",
|
|
8757
|
+
"walk-recognized-nothing"
|
|
8758
|
+
]);
|
|
8759
|
+
var introspectionDiagnosticsSchema = external_exports.object({
|
|
8760
|
+
captured: external_exports.boolean(),
|
|
8761
|
+
failureReason: introspectionFailureReasonSchema.nullish(),
|
|
8762
|
+
reactVersion: boundedString(32).nullish(),
|
|
8763
|
+
failureCount: external_exports.number().int().min(0).max(1e6).optional()
|
|
8764
|
+
});
|
|
8432
8765
|
external_exports.object({
|
|
8433
8766
|
content: external_exports.string().min(1).max(4096),
|
|
8434
8767
|
sessionId: external_exports.string().optional(),
|
|
@@ -8438,7 +8771,20 @@ external_exports.object({
|
|
|
8438
8771
|
* the active MCP doc and emits `mcp_version_mismatch` telemetry when
|
|
8439
8772
|
* they differ. Optional — older SDKs simply skip the check.
|
|
8440
8773
|
*/
|
|
8441
|
-
mcpVersion: external_exports.string().max(64).optional()
|
|
8774
|
+
mcpVersion: external_exports.string().max(64).optional(),
|
|
8775
|
+
/**
|
|
8776
|
+
* SDK-side introspection health. Only sent when it FAILED — a client
|
|
8777
|
+
* that reached the React tree omits the field entirely, so the happy
|
|
8778
|
+
* path costs nothing on the wire.
|
|
8779
|
+
*
|
|
8780
|
+
* Without this, an app whose introspection is dead sends a snapshot
|
|
8781
|
+
* that is empty but perfectly well-formed, indistinguishable from a
|
|
8782
|
+
* genuinely empty screen. The server emits
|
|
8783
|
+
* `introspection_unavailable` so the failure is visible to us instead
|
|
8784
|
+
* of waiting for a bug report. Optional — older SDKs simply never
|
|
8785
|
+
* send it.
|
|
8786
|
+
*/
|
|
8787
|
+
introspection: introspectionDiagnosticsSchema.optional()
|
|
8442
8788
|
});
|
|
8443
8789
|
var agentActionTypeSchema = external_exports.enum([
|
|
8444
8790
|
"navigate",
|
|
@@ -8449,11 +8795,22 @@ var agentActionTypeSchema = external_exports.enum([
|
|
|
8449
8795
|
"custom"
|
|
8450
8796
|
]);
|
|
8451
8797
|
var navigationPayloadSchema = external_exports.object({
|
|
8452
|
-
|
|
8798
|
+
// Optional ONLY so `goBack` can exist (#398): it returns to whatever
|
|
8799
|
+
// is beneath on the stack and has no destination to name. Every other
|
|
8800
|
+
// action is still required to carry one — enforced by the refine
|
|
8801
|
+
// below rather than by the field, so the error names the real problem
|
|
8802
|
+
// ("navigate needs a screenName") instead of a missing key.
|
|
8803
|
+
screenName: external_exports.string().min(1).optional(),
|
|
8453
8804
|
params: external_exports.record(external_exports.unknown()).optional(),
|
|
8454
8805
|
navigationAction: external_exports.enum(["push", "navigate", "replace", "goBack", "reset"]).default("navigate").optional(),
|
|
8455
8806
|
path: external_exports.array(external_exports.string().min(1)).optional()
|
|
8456
|
-
}).passthrough()
|
|
8807
|
+
}).passthrough().refine(
|
|
8808
|
+
(payload) => payload.navigationAction === "goBack" || typeof payload.screenName === "string" && payload.screenName.length > 0,
|
|
8809
|
+
{
|
|
8810
|
+
message: 'screenName is required for every navigationAction except "goBack"',
|
|
8811
|
+
path: ["screenName"]
|
|
8812
|
+
}
|
|
8813
|
+
);
|
|
8457
8814
|
var formFillFieldSchema = external_exports.object({
|
|
8458
8815
|
fieldId: external_exports.string().min(1),
|
|
8459
8816
|
fieldType: external_exports.enum(["text", "select", "toggle", "date", "number", "custom"]).default("text").optional(),
|
|
@@ -8787,6 +9144,8 @@ var sandboxObservationSchema = external_exports.object({
|
|
|
8787
9144
|
inputs: external_exports.array(
|
|
8788
9145
|
external_exports.object({
|
|
8789
9146
|
id: external_exports.string().max(120),
|
|
9147
|
+
provenance: identityProvenanceSchema.optional(),
|
|
9148
|
+
onScreen: external_exports.boolean().optional(),
|
|
8790
9149
|
label: external_exports.string().max(200).optional(),
|
|
8791
9150
|
value: external_exports.string().max(2e3).optional(),
|
|
8792
9151
|
disabled: external_exports.boolean().optional(),
|
|
@@ -8800,6 +9159,8 @@ var sandboxObservationSchema = external_exports.object({
|
|
|
8800
9159
|
buttons: external_exports.array(
|
|
8801
9160
|
external_exports.object({
|
|
8802
9161
|
id: external_exports.string().max(120),
|
|
9162
|
+
provenance: identityProvenanceSchema.optional(),
|
|
9163
|
+
onScreen: external_exports.boolean().optional(),
|
|
8803
9164
|
label: external_exports.string().max(200).optional(),
|
|
8804
9165
|
disabled: external_exports.boolean().optional(),
|
|
8805
9166
|
/** Risk metadata (e.g. "high") the SDK forwards for danger UI. */
|
|
@@ -8821,6 +9182,8 @@ var sandboxObservationSchema = external_exports.object({
|
|
|
8821
9182
|
sliders: external_exports.array(
|
|
8822
9183
|
external_exports.object({
|
|
8823
9184
|
id: external_exports.string().max(120),
|
|
9185
|
+
provenance: identityProvenanceSchema.optional(),
|
|
9186
|
+
onScreen: external_exports.boolean().optional(),
|
|
8824
9187
|
label: external_exports.string().max(200).optional(),
|
|
8825
9188
|
value: external_exports.number().finite().optional(),
|
|
8826
9189
|
min: external_exports.number().finite().optional(),
|
|
@@ -8850,6 +9213,44 @@ var sandboxObservationSchema = external_exports.object({
|
|
|
8850
9213
|
).max(200).optional()
|
|
8851
9214
|
}).passthrough()
|
|
8852
9215
|
).max(20).optional(),
|
|
9216
|
+
/**
|
|
9217
|
+
* Toggles exactly as the SDK snapshot reports them (#390).
|
|
9218
|
+
*
|
|
9219
|
+
* Their absence is why `generality-component-control-smarthome`
|
|
9220
|
+
* came back `errored` with a 422 instead of measuring anything:
|
|
9221
|
+
* this schema is `.strict()`, so a scenario that declares a switch
|
|
9222
|
+
* is rejected before the agent is ever asked. Which means the
|
|
9223
|
+
* corpus could not express the single control behind failure 02 of
|
|
9224
|
+
* the functional audit — "disable an agent; the switch never
|
|
9225
|
+
* moves". The one defect the eval most needed to catch was the one
|
|
9226
|
+
* shape it could not describe.
|
|
9227
|
+
*/
|
|
9228
|
+
toggles: external_exports.array(
|
|
9229
|
+
external_exports.object({
|
|
9230
|
+
id: external_exports.string().max(120),
|
|
9231
|
+
provenance: identityProvenanceSchema.optional(),
|
|
9232
|
+
onScreen: external_exports.boolean().optional(),
|
|
9233
|
+
label: external_exports.string().max(200).optional(),
|
|
9234
|
+
value: external_exports.boolean().optional(),
|
|
9235
|
+
disabled: external_exports.boolean().optional()
|
|
9236
|
+
})
|
|
9237
|
+
).max(100).optional(),
|
|
9238
|
+
/**
|
|
9239
|
+
* The interaction graph — the `el:*` ids the prompt tells the model
|
|
9240
|
+
* to prefer over ordinal handles. Passthrough per entry for the
|
|
9241
|
+
* same reason `lists` is: the SDK adds fields faster than this
|
|
9242
|
+
* schema should chase them.
|
|
9243
|
+
*/
|
|
9244
|
+
elements: external_exports.array(
|
|
9245
|
+
external_exports.object({
|
|
9246
|
+
id: external_exports.string().max(160),
|
|
9247
|
+
role: external_exports.string().max(40).optional(),
|
|
9248
|
+
label: external_exports.string().max(300).optional()
|
|
9249
|
+
}).passthrough()
|
|
9250
|
+
).max(500).optional(),
|
|
9251
|
+
/** Screen-level state the relay renders and branches on. */
|
|
9252
|
+
loading: external_exports.boolean().optional(),
|
|
9253
|
+
modalOpen: external_exports.boolean().optional(),
|
|
8853
9254
|
extra: external_exports.record(external_exports.unknown()).optional()
|
|
8854
9255
|
}).strict();
|
|
8855
9256
|
external_exports.object({
|
|
@@ -8890,13 +9291,29 @@ external_exports.object({
|
|
|
8890
9291
|
* heuristics, forces tool choice when the last user message carries a
|
|
8891
9292
|
* failure marker). Only meaningful alongside `history`.
|
|
8892
9293
|
*/
|
|
8893
|
-
isRecoveryHop: external_exports.boolean().optional()
|
|
9294
|
+
isRecoveryHop: external_exports.boolean().optional(),
|
|
9295
|
+
/**
|
|
9296
|
+
* Run this call against the application structure supplied here
|
|
9297
|
+
* instead of the project's active MCP document.
|
|
9298
|
+
*
|
|
9299
|
+
* Sandbox-only, and the relay honours it only on a `dryRun` call —
|
|
9300
|
+
* see `resolveMcpOverride` in apps/api. It exists because the eval
|
|
9301
|
+
* corpus could otherwise only ever describe ONE app: every scenario
|
|
9302
|
+
* resolves to the same seeded project, so every navigate destination,
|
|
9303
|
+
* every screen title and every bit of domain priming in the prompt
|
|
9304
|
+
* came from the same vehicle-management demo. A suite that can only
|
|
9305
|
+
* pose questions about one app cannot measure whether the agent works
|
|
9306
|
+
* on another one.
|
|
9307
|
+
*
|
|
9308
|
+
* Deliberately loose (`z.record`): the MCP document's shape is owned
|
|
9309
|
+
* by the generator, and pinning it here would turn every additive
|
|
9310
|
+
* generator change into a 422 in the sandbox.
|
|
9311
|
+
*/
|
|
9312
|
+
applicationStructure: external_exports.record(external_exports.unknown()).optional()
|
|
8894
9313
|
}).strict();
|
|
8895
9314
|
var relayDiagnosticsSchema = external_exports.object({
|
|
8896
9315
|
unverifiedTargets: external_exports.array(external_exports.string()),
|
|
8897
|
-
guardsFired: external_exports.array(
|
|
8898
|
-
external_exports.object({ guard: external_exports.string(), detail: external_exports.string().optional() })
|
|
8899
|
-
),
|
|
9316
|
+
guardsFired: external_exports.array(external_exports.object({ guard: external_exports.string(), detail: external_exports.string().optional() })),
|
|
8900
9317
|
repairMode: external_exports.enum(["repair", "strict", "disabled"]),
|
|
8901
9318
|
promptVersion: external_exports.string(),
|
|
8902
9319
|
// Defaulted for producers that predate the field: before it existed
|
|
@@ -9155,6 +9572,30 @@ external_exports.object({
|
|
|
9155
9572
|
name: external_exports.string().min(1).max(200).optional(),
|
|
9156
9573
|
identifiers: endUserIdentifiersSchema.optional()
|
|
9157
9574
|
});
|
|
9575
|
+
var MAX_EXTERNAL_USER_ID_LENGTH = 128;
|
|
9576
|
+
function normalizeExternalUserId(value) {
|
|
9577
|
+
let raw;
|
|
9578
|
+
if (typeof value === "string") raw = value;
|
|
9579
|
+
else if (typeof value === "number" && Number.isFinite(value)) raw = String(value);
|
|
9580
|
+
else return void 0;
|
|
9581
|
+
const trimmed = raw.trim();
|
|
9582
|
+
if (!trimmed) return void 0;
|
|
9583
|
+
if (trimmed.length > MAX_EXTERNAL_USER_ID_LENGTH) return void 0;
|
|
9584
|
+
return trimmed;
|
|
9585
|
+
}
|
|
9586
|
+
var MAX_DEVICE_INFO_BYTES = 4096;
|
|
9587
|
+
var sessionDeviceInfoSchema = external_exports.object({
|
|
9588
|
+
platform: external_exports.string().max(64).optional(),
|
|
9589
|
+
osVersion: external_exports.string().max(64).optional(),
|
|
9590
|
+
appVersion: external_exports.string().max(64).optional(),
|
|
9591
|
+
sdkVersion: external_exports.string().max(64).optional()
|
|
9592
|
+
}).passthrough().refine((info) => JSON.stringify(info).length <= MAX_DEVICE_INFO_BYTES, {
|
|
9593
|
+
message: `device_info exceeds ${MAX_DEVICE_INFO_BYTES} bytes`
|
|
9594
|
+
});
|
|
9595
|
+
external_exports.object({
|
|
9596
|
+
userId: external_exports.preprocess(normalizeExternalUserId, external_exports.string().optional()),
|
|
9597
|
+
deviceInfo: sessionDeviceInfoSchema.optional().catch(void 0)
|
|
9598
|
+
});
|
|
9158
9599
|
external_exports.object({
|
|
9159
9600
|
projectId: external_exports.string().min(1).max(64),
|
|
9160
9601
|
externalId: external_exports.string().min(1).max(128),
|
|
@@ -9162,6 +9603,27 @@ external_exports.object({
|
|
|
9162
9603
|
identifiers: endUserIdentifiersSchema.optional()
|
|
9163
9604
|
});
|
|
9164
9605
|
|
|
9606
|
+
// src/utils/stringify.ts
|
|
9607
|
+
function stringifyUnknown(value) {
|
|
9608
|
+
if (value instanceof Error) {
|
|
9609
|
+
const message = value.message || value.name;
|
|
9610
|
+
const cause = value.cause;
|
|
9611
|
+
if (cause instanceof Error && cause.message && cause.message !== message) {
|
|
9612
|
+
return `${message} (${cause.message})`;
|
|
9613
|
+
}
|
|
9614
|
+
return message;
|
|
9615
|
+
}
|
|
9616
|
+
if (typeof value === "string") return value;
|
|
9617
|
+
if (value === null || value === void 0) return String(value);
|
|
9618
|
+
if (typeof value !== "object") return String(value);
|
|
9619
|
+
try {
|
|
9620
|
+
const json = JSON.stringify(value);
|
|
9621
|
+
if (json && json !== "{}") return json;
|
|
9622
|
+
} catch {
|
|
9623
|
+
}
|
|
9624
|
+
return String(value);
|
|
9625
|
+
}
|
|
9626
|
+
|
|
9165
9627
|
// src/manifest/loadManifest.ts
|
|
9166
9628
|
var DEFAULT_MANIFEST_FILENAME = "appilots.manifest.json";
|
|
9167
9629
|
var manifestSchema = external_exports.object({
|
|
@@ -9178,14 +9640,16 @@ async function loadManifest(rootDir, manifestPath) {
|
|
|
9178
9640
|
if (error?.code === "ENOENT") {
|
|
9179
9641
|
return { manifest: null, resolvedPath };
|
|
9180
9642
|
}
|
|
9181
|
-
throw new Error(
|
|
9643
|
+
throw new Error(
|
|
9644
|
+
`Failed to read Appilots manifest at ${resolvedPath}: ${stringifyUnknown(error)}`
|
|
9645
|
+
);
|
|
9182
9646
|
}
|
|
9183
9647
|
let parsedJson;
|
|
9184
9648
|
try {
|
|
9185
9649
|
parsedJson = JSON.parse(raw);
|
|
9186
9650
|
} catch (error) {
|
|
9187
9651
|
throw new Error(
|
|
9188
|
-
`Appilots manifest at ${resolvedPath} is not valid JSON: ${
|
|
9652
|
+
`Appilots manifest at ${resolvedPath} is not valid JSON: ${stringifyUnknown(error)}`
|
|
9189
9653
|
);
|
|
9190
9654
|
}
|
|
9191
9655
|
const result = manifestSchema.safeParse(parsedJson);
|
|
@@ -9199,11 +9663,47 @@ Each entry in "screens" must match the ScreenDescriptor shape (see docs/platform
|
|
|
9199
9663
|
}
|
|
9200
9664
|
return { manifest: result.data, resolvedPath };
|
|
9201
9665
|
}
|
|
9666
|
+
function mergeScreen(base, declared) {
|
|
9667
|
+
const fields = { ...base };
|
|
9668
|
+
for (const [key, value] of Object.entries(declared)) {
|
|
9669
|
+
if (value === void 0) continue;
|
|
9670
|
+
if (Array.isArray(value) && value.length === 0) continue;
|
|
9671
|
+
fields[key] = value;
|
|
9672
|
+
}
|
|
9673
|
+
const merged = fields;
|
|
9674
|
+
merged.targets = mergeById(base.targets, markManifestOrigin(declared.targets));
|
|
9675
|
+
merged.actions = mergeById(base.actions, declared.actions) ?? [];
|
|
9676
|
+
if (base.agentHints || declared.agentHints) {
|
|
9677
|
+
merged.agentHints = { ...base.agentHints, ...declared.agentHints };
|
|
9678
|
+
}
|
|
9679
|
+
return merged;
|
|
9680
|
+
}
|
|
9681
|
+
function mergeById(base, overlay) {
|
|
9682
|
+
if (!overlay || overlay.length === 0) return base;
|
|
9683
|
+
if (!base || base.length === 0) return overlay;
|
|
9684
|
+
const byId = /* @__PURE__ */ new Map();
|
|
9685
|
+
for (const entry of base) byId.set(entry.id, entry);
|
|
9686
|
+
for (const entry of overlay) {
|
|
9687
|
+
const existing = byId.get(entry.id);
|
|
9688
|
+
byId.set(entry.id, existing ? { ...existing, ...entry } : entry);
|
|
9689
|
+
}
|
|
9690
|
+
return Array.from(byId.values());
|
|
9691
|
+
}
|
|
9692
|
+
function markManifestOrigin(targets) {
|
|
9693
|
+
if (!targets || targets.length === 0) return targets;
|
|
9694
|
+
return targets.map((target) => ({ origin: "manifest", ...target }));
|
|
9695
|
+
}
|
|
9202
9696
|
function mergeManifestScreens(analyzerScreens, manifestScreens) {
|
|
9203
9697
|
if (!manifestScreens || manifestScreens.length === 0) return analyzerScreens;
|
|
9204
9698
|
const byName = /* @__PURE__ */ new Map();
|
|
9205
9699
|
for (const screen of analyzerScreens) byName.set(screen.name, screen);
|
|
9206
|
-
for (const
|
|
9700
|
+
for (const declared of manifestScreens) {
|
|
9701
|
+
const base = byName.get(declared.name);
|
|
9702
|
+
byName.set(
|
|
9703
|
+
declared.name,
|
|
9704
|
+
base ? mergeScreen(base, declared) : { ...declared, targets: markManifestOrigin(declared.targets) }
|
|
9705
|
+
);
|
|
9706
|
+
}
|
|
9207
9707
|
return Array.from(byName.values());
|
|
9208
9708
|
}
|
|
9209
9709
|
function mergeManifestNavigation(analyzerNavigation, manifestNavigation) {
|
|
@@ -9493,7 +9993,12 @@ var MCPGenerator = class _MCPGenerator {
|
|
|
9493
9993
|
}
|
|
9494
9994
|
const mergedScreens = mergeManifestScreens(analyzed.screens, manifest?.screens);
|
|
9495
9995
|
const navigation = mergeManifestNavigation(analyzed.navigation, manifest?.navigation);
|
|
9496
|
-
const agentReadyScreens = mergedScreens.map(
|
|
9996
|
+
const agentReadyScreens = mergedScreens.map(
|
|
9997
|
+
(screen) => enrichScreenForAgent({
|
|
9998
|
+
...screen,
|
|
9999
|
+
filePath: screen.filePath ? path8__namespace.default.relative(this.generatorConfig.rootDir, screen.filePath) : screen.filePath
|
|
10000
|
+
})
|
|
10001
|
+
);
|
|
9497
10002
|
const projectInfo = await this.getProjectInfo();
|
|
9498
10003
|
const projectName = projectInfo.name;
|
|
9499
10004
|
console.log(`[MCPGenerator] Project name: ${projectName}`);
|
|
@@ -9516,10 +10021,7 @@ var MCPGenerator = class _MCPGenerator {
|
|
|
9516
10021
|
};
|
|
9517
10022
|
const serialized = JSON.stringify(document, null, 2);
|
|
9518
10023
|
const checksum = this.calculateChecksum(serialized);
|
|
9519
|
-
const filePath = path8__namespace.default.resolve(
|
|
9520
|
-
outputDir,
|
|
9521
|
-
`mcp-document.${this.options.format}`
|
|
9522
|
-
);
|
|
10024
|
+
const filePath = path8__namespace.default.resolve(outputDir, `mcp-document.${this.options.format}`);
|
|
9523
10025
|
await fs.writeFile(filePath, serialized, "utf-8");
|
|
9524
10026
|
console.log(`[MCPGenerator] Document written to: ${filePath}`);
|
|
9525
10027
|
const checksumFilePath = path8__namespace.default.resolve(outputDir, ".appilots-checksum");
|
|
@@ -9574,6 +10076,70 @@ var MCPGenerator = class _MCPGenerator {
|
|
|
9574
10076
|
}
|
|
9575
10077
|
}
|
|
9576
10078
|
};
|
|
10079
|
+
var DEFAULT_SERVER_URL = "http://localhost:4000";
|
|
10080
|
+
var KNOWN_CONFIG_KEYS = [
|
|
10081
|
+
"apiKey",
|
|
10082
|
+
"projectId",
|
|
10083
|
+
"serverUrl",
|
|
10084
|
+
"outputDir",
|
|
10085
|
+
"include",
|
|
10086
|
+
"exclude",
|
|
10087
|
+
"autoActivate",
|
|
10088
|
+
"strictScreens",
|
|
10089
|
+
"screenPatterns",
|
|
10090
|
+
"navigationInclude",
|
|
10091
|
+
"navigationExclude",
|
|
10092
|
+
"platform",
|
|
10093
|
+
"manifestPath",
|
|
10094
|
+
"eval"
|
|
10095
|
+
];
|
|
10096
|
+
var KEY_ALIASES = {
|
|
10097
|
+
apiUrl: "serverUrl",
|
|
10098
|
+
// `@appilots/sdk`'s own name for this. One `.appilotsrc` feeds both
|
|
10099
|
+
// packages, so an integrator who wrote the SDK's key should not be told
|
|
10100
|
+
// it is unrecognized.
|
|
10101
|
+
apiBaseUrl: "serverUrl",
|
|
10102
|
+
apiURL: "serverUrl",
|
|
10103
|
+
baseUrl: "serverUrl",
|
|
10104
|
+
url: "serverUrl",
|
|
10105
|
+
host: "serverUrl",
|
|
10106
|
+
endpoint: "serverUrl",
|
|
10107
|
+
server: "serverUrl",
|
|
10108
|
+
key: "apiKey",
|
|
10109
|
+
token: "apiKey",
|
|
10110
|
+
project: "projectId",
|
|
10111
|
+
sourceDir: "include",
|
|
10112
|
+
srcDir: "include",
|
|
10113
|
+
source: "include",
|
|
10114
|
+
outDir: "outputDir"
|
|
10115
|
+
};
|
|
10116
|
+
function editDistance(a, b) {
|
|
10117
|
+
let previous = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
10118
|
+
for (let i = 1; i <= a.length; i++) {
|
|
10119
|
+
const current = [i];
|
|
10120
|
+
for (let j = 1; j <= b.length; j++) {
|
|
10121
|
+
const deletion = (previous[j] ?? 0) + 1;
|
|
10122
|
+
const insertion = (current[j - 1] ?? 0) + 1;
|
|
10123
|
+
const substitution = (previous[j - 1] ?? 0) + (a[i - 1] === b[j - 1] ? 0 : 1);
|
|
10124
|
+
current.push(Math.min(deletion, insertion, substitution));
|
|
10125
|
+
}
|
|
10126
|
+
previous = current;
|
|
10127
|
+
}
|
|
10128
|
+
return previous[b.length] ?? 0;
|
|
10129
|
+
}
|
|
10130
|
+
function suggestConfigKey(key) {
|
|
10131
|
+
const alias = KEY_ALIASES[key];
|
|
10132
|
+
if (alias) return alias;
|
|
10133
|
+
const lower = key.toLowerCase();
|
|
10134
|
+
let best;
|
|
10135
|
+
for (const known of KNOWN_CONFIG_KEYS) {
|
|
10136
|
+
const distance = editDistance(lower, known.toLowerCase());
|
|
10137
|
+
if (distance <= 2 && (!best || distance < best.distance)) {
|
|
10138
|
+
best = { key: known, distance };
|
|
10139
|
+
}
|
|
10140
|
+
}
|
|
10141
|
+
return best?.key;
|
|
10142
|
+
}
|
|
9577
10143
|
function getEnvOverrides(env = process.env) {
|
|
9578
10144
|
const clean = (value) => {
|
|
9579
10145
|
const trimmed = value?.trim();
|
|
@@ -9585,7 +10151,7 @@ function getEnvOverrides(env = process.env) {
|
|
|
9585
10151
|
serverUrl: clean(env.APPILOTS_SERVER_URL)
|
|
9586
10152
|
};
|
|
9587
10153
|
}
|
|
9588
|
-
function loadConfig() {
|
|
10154
|
+
function loadConfig(onWarn) {
|
|
9589
10155
|
const configPath = getConfigPath();
|
|
9590
10156
|
const env = getEnvOverrides();
|
|
9591
10157
|
let fileConfig = {};
|
|
@@ -9593,13 +10159,27 @@ function loadConfig() {
|
|
|
9593
10159
|
try {
|
|
9594
10160
|
fileConfig = JSON.parse(fs$1.readFileSync(configPath, "utf-8"));
|
|
9595
10161
|
} catch (error) {
|
|
9596
|
-
throw new Error(
|
|
10162
|
+
throw new Error(
|
|
10163
|
+
`Failed to parse .appilotsrc at ${configPath}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
10164
|
+
);
|
|
9597
10165
|
}
|
|
9598
10166
|
} else if (!env.apiKey) {
|
|
9599
10167
|
return null;
|
|
9600
10168
|
}
|
|
10169
|
+
const legacyWarnings = [];
|
|
10170
|
+
if (fileConfig.serverUrl === void 0) {
|
|
10171
|
+
for (const [alias, canonical] of Object.entries(KEY_ALIASES)) {
|
|
10172
|
+
if (canonical !== "serverUrl" || fileConfig[alias] === void 0) continue;
|
|
10173
|
+
fileConfig.serverUrl = fileConfig[alias];
|
|
10174
|
+
delete fileConfig[alias];
|
|
10175
|
+
legacyWarnings.push(
|
|
10176
|
+
`legacy key "${alias}" \u2014 using it as "serverUrl"; rename it in .appilotsrc`
|
|
10177
|
+
);
|
|
10178
|
+
break;
|
|
10179
|
+
}
|
|
10180
|
+
}
|
|
9601
10181
|
const merged = {
|
|
9602
|
-
serverUrl:
|
|
10182
|
+
serverUrl: DEFAULT_SERVER_URL,
|
|
9603
10183
|
outputDir: ".appilots",
|
|
9604
10184
|
autoActivate: true,
|
|
9605
10185
|
strictScreens: true,
|
|
@@ -9609,6 +10189,26 @@ function loadConfig() {
|
|
|
9609
10189
|
...env.serverUrl ? { serverUrl: env.serverUrl } : {}
|
|
9610
10190
|
};
|
|
9611
10191
|
const validation = validateConfig(merged);
|
|
10192
|
+
validation.warnings.unshift(...legacyWarnings);
|
|
10193
|
+
if (fileConfig.serverUrl === void 0 && env.serverUrl === void 0) {
|
|
10194
|
+
for (const key of Object.keys(fileConfig)) {
|
|
10195
|
+
if (KNOWN_CONFIG_KEYS.includes(key)) continue;
|
|
10196
|
+
if (suggestConfigKey(key) !== "serverUrl") continue;
|
|
10197
|
+
validation.warnings = validation.warnings.filter(
|
|
10198
|
+
(warning) => !warning.startsWith(`unknown key "${key}"`)
|
|
10199
|
+
);
|
|
10200
|
+
validation.errors.push(
|
|
10201
|
+
`unknown key "${key}" looks like "serverUrl" \u2014 not falling back to ${DEFAULT_SERVER_URL}; rename the key to "serverUrl"`
|
|
10202
|
+
);
|
|
10203
|
+
validation.valid = false;
|
|
10204
|
+
}
|
|
10205
|
+
}
|
|
10206
|
+
if (onWarn) {
|
|
10207
|
+
const source = configPath ?? "environment variables";
|
|
10208
|
+
for (const warning of validation.warnings) {
|
|
10209
|
+
onWarn(`${source}: ${warning}`);
|
|
10210
|
+
}
|
|
10211
|
+
}
|
|
9612
10212
|
if (!validation.valid) {
|
|
9613
10213
|
const source = configPath ?? "environment variables";
|
|
9614
10214
|
throw new Error(
|
|
@@ -9624,7 +10224,7 @@ function saveConfig(dir, config) {
|
|
|
9624
10224
|
const mergedConfig = {
|
|
9625
10225
|
apiKey: config.apiKey || existingConfig?.apiKey || "",
|
|
9626
10226
|
projectId: config.projectId || existingConfig?.projectId || "",
|
|
9627
|
-
serverUrl: config.serverUrl || existingConfig?.serverUrl ||
|
|
10227
|
+
serverUrl: config.serverUrl || existingConfig?.serverUrl || DEFAULT_SERVER_URL,
|
|
9628
10228
|
outputDir: config.outputDir || existingConfig?.outputDir || ".appilots",
|
|
9629
10229
|
autoActivate: config.autoActivate !== void 0 ? config.autoActivate : existingConfig?.autoActivate ?? true,
|
|
9630
10230
|
include: config.include || existingConfig?.include,
|
|
@@ -9640,7 +10240,9 @@ function saveConfig(dir, config) {
|
|
|
9640
10240
|
try {
|
|
9641
10241
|
fs$1.writeFileSync(configPath, JSON.stringify(mergedConfig, null, 2), "utf-8");
|
|
9642
10242
|
} catch (error) {
|
|
9643
|
-
throw new Error(
|
|
10243
|
+
throw new Error(
|
|
10244
|
+
`Failed to write .appilotsrc to ${configPath}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
10245
|
+
);
|
|
9644
10246
|
}
|
|
9645
10247
|
}
|
|
9646
10248
|
function getConfigPath() {
|
|
@@ -9667,14 +10269,25 @@ function getConfigPath() {
|
|
|
9667
10269
|
}
|
|
9668
10270
|
function validateConfig(config) {
|
|
9669
10271
|
const errors = [];
|
|
10272
|
+
const warnings = [];
|
|
9670
10273
|
if (!config || typeof config !== "object") {
|
|
9671
10274
|
return {
|
|
9672
10275
|
valid: false,
|
|
9673
|
-
errors: ["Configuration must be an object"]
|
|
10276
|
+
errors: ["Configuration must be an object"],
|
|
10277
|
+
warnings
|
|
9674
10278
|
};
|
|
9675
10279
|
}
|
|
10280
|
+
for (const key of Object.keys(config)) {
|
|
10281
|
+
if (KNOWN_CONFIG_KEYS.includes(key)) continue;
|
|
10282
|
+
const suggestion = suggestConfigKey(key);
|
|
10283
|
+
warnings.push(
|
|
10284
|
+
`unknown key "${key}" \u2014 ignored` + (suggestion ? ` (did you mean "${suggestion}"?)` : "")
|
|
10285
|
+
);
|
|
10286
|
+
}
|
|
9676
10287
|
if (!config.apiKey || typeof config.apiKey !== "string") {
|
|
9677
|
-
errors.push(
|
|
10288
|
+
errors.push(
|
|
10289
|
+
"apiKey is required and must be a string (set it in .appilotsrc or via APPILOTS_API_KEY)"
|
|
10290
|
+
);
|
|
9678
10291
|
} else if (!config.apiKey.startsWith("ak_")) {
|
|
9679
10292
|
errors.push('apiKey must start with "ak_"');
|
|
9680
10293
|
}
|
|
@@ -9736,7 +10349,8 @@ function validateConfig(config) {
|
|
|
9736
10349
|
}
|
|
9737
10350
|
return {
|
|
9738
10351
|
valid: errors.length === 0,
|
|
9739
|
-
errors
|
|
10352
|
+
errors,
|
|
10353
|
+
warnings
|
|
9740
10354
|
};
|
|
9741
10355
|
}
|
|
9742
10356
|
|
|
@@ -9782,19 +10396,76 @@ function formatMetadataWarnings(warnings) {
|
|
|
9782
10396
|
);
|
|
9783
10397
|
}
|
|
9784
10398
|
|
|
10399
|
+
// ../shared/dist/chunk-UEMUBXFH.mjs
|
|
10400
|
+
var DEFAULT_API_BASE_URL = "https://api.appilots.com";
|
|
10401
|
+
var APPILOTS_API_PATH_PREFIX = "/api/v1";
|
|
10402
|
+
function normalizeApiBaseUrl(configured) {
|
|
10403
|
+
const raw = (configured ?? DEFAULT_API_BASE_URL).trim().replace(/\/+$/, "");
|
|
10404
|
+
if (!raw) return `${DEFAULT_API_BASE_URL}${APPILOTS_API_PATH_PREFIX}`;
|
|
10405
|
+
if (new RegExp(`${APPILOTS_API_PATH_PREFIX}(/|$)`).test(raw)) return raw;
|
|
10406
|
+
return `${raw}${APPILOTS_API_PATH_PREFIX}`;
|
|
10407
|
+
}
|
|
10408
|
+
|
|
9785
10409
|
// src/services/api-client.ts
|
|
9786
|
-
var
|
|
10410
|
+
var DEFAULT_TIMEOUT_MS2 = 3e4;
|
|
9787
10411
|
var DEFAULT_MAX_RETRIES = 2;
|
|
9788
10412
|
var RETRY_BASE_DELAY_MS = 500;
|
|
10413
|
+
function describeNetworkError(url, err) {
|
|
10414
|
+
let origin = url;
|
|
10415
|
+
try {
|
|
10416
|
+
origin = new URL(url).origin;
|
|
10417
|
+
} catch {
|
|
10418
|
+
}
|
|
10419
|
+
const cause = err?.cause;
|
|
10420
|
+
const code = typeof cause?.code === "string" ? cause.code : void 0;
|
|
10421
|
+
const detail = code ?? stringifyUnknown(err);
|
|
10422
|
+
return new Error(`Cannot reach Appilots server at ${origin} (${detail})`);
|
|
10423
|
+
}
|
|
10424
|
+
function errorCodeOf(payload) {
|
|
10425
|
+
const error = payload?.error;
|
|
10426
|
+
if (error && typeof error === "object") {
|
|
10427
|
+
const { code } = error;
|
|
10428
|
+
if (typeof code === "string" && code.trim()) return code;
|
|
10429
|
+
}
|
|
10430
|
+
return void 0;
|
|
10431
|
+
}
|
|
10432
|
+
function describeApiError(payload, fallback) {
|
|
10433
|
+
const error = payload?.error;
|
|
10434
|
+
if (typeof error === "string" && error.trim()) return error;
|
|
10435
|
+
if (error && typeof error === "object") {
|
|
10436
|
+
const { code, message: message2 } = error;
|
|
10437
|
+
const text = typeof message2 === "string" && message2.trim() ? message2 : void 0;
|
|
10438
|
+
const tag = typeof code === "string" && code.trim() ? code : void 0;
|
|
10439
|
+
if (text && tag) return `${text} (${tag})`;
|
|
10440
|
+
if (text) return text;
|
|
10441
|
+
if (tag) return tag;
|
|
10442
|
+
}
|
|
10443
|
+
const message = payload?.message;
|
|
10444
|
+
if (typeof message === "string" && message.trim()) return message;
|
|
10445
|
+
return fallback;
|
|
10446
|
+
}
|
|
9789
10447
|
var AppilotsAPIClient = class {
|
|
9790
|
-
|
|
10448
|
+
/**
|
|
10449
|
+
* `serverUrl` with the API's mount prefix resolved — every path below
|
|
10450
|
+
* is relative to THIS, not to the configured origin.
|
|
10451
|
+
*
|
|
10452
|
+
* It used to be the raw `serverUrl` with `/api/v1` hardcoded into each
|
|
10453
|
+
* path, which made the field mean something different here than in the
|
|
10454
|
+
* SDK. Both read the same `.appilotsrc`: the SDK completes the prefix
|
|
10455
|
+
* when it is missing, so `https://api.appilots.com/api/v1` is correct
|
|
10456
|
+
* there — and here that same value produced
|
|
10457
|
+
* `/api/v1/api/v1/cli/sync`, a 404 whose body reads `Route not found`.
|
|
10458
|
+
* Sharing `normalizeApiBaseUrl` is what makes one file mean one thing:
|
|
10459
|
+
* with or without the prefix now works in both.
|
|
10460
|
+
*/
|
|
10461
|
+
baseUrl;
|
|
9791
10462
|
apiKey;
|
|
9792
10463
|
timeoutMs;
|
|
9793
10464
|
maxRetries;
|
|
9794
10465
|
constructor(config) {
|
|
9795
|
-
this.
|
|
10466
|
+
this.baseUrl = normalizeApiBaseUrl(config.serverUrl);
|
|
9796
10467
|
this.apiKey = config.apiKey;
|
|
9797
|
-
this.timeoutMs = config.timeoutMs ??
|
|
10468
|
+
this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
9798
10469
|
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
9799
10470
|
}
|
|
9800
10471
|
/**
|
|
@@ -9818,7 +10489,7 @@ var AppilotsAPIClient = class {
|
|
|
9818
10489
|
}
|
|
9819
10490
|
return response;
|
|
9820
10491
|
} catch (err) {
|
|
9821
|
-
lastError = controller.signal.aborted ? new Error(`Request timed out after ${this.timeoutMs}ms: ${url}`) : err;
|
|
10492
|
+
lastError = controller.signal.aborted ? new Error(`Request timed out after ${this.timeoutMs}ms: ${url}`) : describeNetworkError(url, err);
|
|
9822
10493
|
} finally {
|
|
9823
10494
|
clearTimeout(timer);
|
|
9824
10495
|
}
|
|
@@ -9837,7 +10508,7 @@ var AppilotsAPIClient = class {
|
|
|
9837
10508
|
*/
|
|
9838
10509
|
async sync(content, version, appVersion) {
|
|
9839
10510
|
try {
|
|
9840
|
-
const response = await this.request(`${this.
|
|
10511
|
+
const response = await this.request(`${this.baseUrl}/cli/sync`, {
|
|
9841
10512
|
method: "POST",
|
|
9842
10513
|
headers: {
|
|
9843
10514
|
"Content-Type": "application/json",
|
|
@@ -9851,7 +10522,9 @@ var AppilotsAPIClient = class {
|
|
|
9851
10522
|
return {
|
|
9852
10523
|
success: false,
|
|
9853
10524
|
unchanged: false,
|
|
9854
|
-
error: errorData
|
|
10525
|
+
error: describeApiError(errorData, `HTTP ${response.status}: ${response.statusText}`),
|
|
10526
|
+
errorCode: errorCodeOf(errorData),
|
|
10527
|
+
errorStatus: response.status
|
|
9855
10528
|
};
|
|
9856
10529
|
}
|
|
9857
10530
|
const json = await response.json();
|
|
@@ -9864,7 +10537,8 @@ var AppilotsAPIClient = class {
|
|
|
9864
10537
|
return {
|
|
9865
10538
|
success: false,
|
|
9866
10539
|
unchanged: false,
|
|
9867
|
-
error: error instanceof Error ? error.message : "Failed to sync with Appilots API"
|
|
10540
|
+
error: error instanceof Error ? error.message : "Failed to sync with Appilots API",
|
|
10541
|
+
errorStatus: 0
|
|
9868
10542
|
};
|
|
9869
10543
|
}
|
|
9870
10544
|
}
|
|
@@ -9875,7 +10549,7 @@ var AppilotsAPIClient = class {
|
|
|
9875
10549
|
*/
|
|
9876
10550
|
async status() {
|
|
9877
10551
|
try {
|
|
9878
|
-
const response = await this.request(`${this.
|
|
10552
|
+
const response = await this.request(`${this.baseUrl}/cli/status`, {
|
|
9879
10553
|
method: "GET",
|
|
9880
10554
|
headers: {
|
|
9881
10555
|
Authorization: `Bearer ${this.apiKey}`
|
|
@@ -9884,7 +10558,7 @@ var AppilotsAPIClient = class {
|
|
|
9884
10558
|
if (!response.ok) {
|
|
9885
10559
|
const errorData = await response.json().catch(() => ({}));
|
|
9886
10560
|
return {
|
|
9887
|
-
error: errorData
|
|
10561
|
+
error: describeApiError(errorData, `HTTP ${response.status}: ${response.statusText}`)
|
|
9888
10562
|
};
|
|
9889
10563
|
}
|
|
9890
10564
|
const json = await response.json();
|
|
@@ -9906,7 +10580,7 @@ var AppilotsAPIClient = class {
|
|
|
9906
10580
|
*/
|
|
9907
10581
|
async evalRun(scenarios) {
|
|
9908
10582
|
try {
|
|
9909
|
-
const response = await this.request(`${this.
|
|
10583
|
+
const response = await this.request(`${this.baseUrl}/cli/eval/run`, {
|
|
9910
10584
|
method: "POST",
|
|
9911
10585
|
headers: {
|
|
9912
10586
|
"Content-Type": "application/json",
|
|
@@ -9937,7 +10611,7 @@ var AppilotsAPIClient = class {
|
|
|
9937
10611
|
*/
|
|
9938
10612
|
async health() {
|
|
9939
10613
|
try {
|
|
9940
|
-
const response = await this.request(`${this.
|
|
10614
|
+
const response = await this.request(`${this.baseUrl}/health`, {
|
|
9941
10615
|
method: "GET"
|
|
9942
10616
|
});
|
|
9943
10617
|
return response.ok;
|
|
@@ -9947,7 +10621,11 @@ var AppilotsAPIClient = class {
|
|
|
9947
10621
|
}
|
|
9948
10622
|
};
|
|
9949
10623
|
|
|
10624
|
+
// src/version.ts
|
|
10625
|
+
var CLI_VERSION = "0.11.0";
|
|
10626
|
+
|
|
9950
10627
|
exports.AppilotsAPIClient = AppilotsAPIClient;
|
|
10628
|
+
exports.CLI_VERSION = CLI_VERSION;
|
|
9951
10629
|
exports.ComponentAnalyzer = ComponentAnalyzer;
|
|
9952
10630
|
exports.DEFAULT_MANIFEST_FILENAME = DEFAULT_MANIFEST_FILENAME;
|
|
9953
10631
|
exports.DEFAULT_WEB_SCREEN_PATTERNS = DEFAULT_WEB_SCREEN_PATTERNS;
|