@appilots/cli 0.11.3 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -11
- package/dist/cli/index.js +1015 -390
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +549 -71
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +547 -69
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var fs = require('fs/promises');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var crypto = require('crypto');
|
|
5
|
+
var traverse5 = require('@babel/traverse');
|
|
6
6
|
var BabelTypes = require('@babel/types');
|
|
7
|
+
var path2 = require('path');
|
|
7
8
|
var fastGlob = require('fast-glob');
|
|
8
9
|
var parser = require('@babel/parser');
|
|
9
10
|
var fs$1 = require('fs');
|
|
10
|
-
var crypto = require('crypto');
|
|
11
11
|
|
|
12
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
13
|
|
|
@@ -30,9 +30,9 @@ function _interopNamespace(e) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
33
|
-
var
|
|
34
|
-
var traverse4__default = /*#__PURE__*/_interopDefault(traverse4);
|
|
33
|
+
var traverse5__default = /*#__PURE__*/_interopDefault(traverse5);
|
|
35
34
|
var BabelTypes__namespace = /*#__PURE__*/_interopNamespace(BabelTypes);
|
|
35
|
+
var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
|
|
36
36
|
var fastGlob__default = /*#__PURE__*/_interopDefault(fastGlob);
|
|
37
37
|
var parser__namespace = /*#__PURE__*/_interopNamespace(parser);
|
|
38
38
|
|
|
@@ -41,6 +41,343 @@ var __export = (target, all) => {
|
|
|
41
41
|
for (var name in all)
|
|
42
42
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
43
43
|
};
|
|
44
|
+
var MAX_HOPS = 8;
|
|
45
|
+
function unwrap(path11) {
|
|
46
|
+
while (path11.isTSAsExpression() || path11.isTSTypeAssertion() || path11.isTSNonNullExpression() || path11.isTSSatisfiesExpression() || path11.isParenthesizedExpression())
|
|
47
|
+
path11 = path11.get("expression");
|
|
48
|
+
return path11;
|
|
49
|
+
}
|
|
50
|
+
function constantValue(path11, depth = 0) {
|
|
51
|
+
if (depth > MAX_HOPS) return void 0;
|
|
52
|
+
path11 = unwrap(path11);
|
|
53
|
+
if (!path11.isIdentifier()) return path11;
|
|
54
|
+
const binding = path11.scope.getBinding(path11.node.name);
|
|
55
|
+
if (!binding?.constant || !binding.path.isVariableDeclarator()) return path11;
|
|
56
|
+
const init = binding.path.get("init");
|
|
57
|
+
const resolved = init.node ? constantValue(init, depth + 1) : void 0;
|
|
58
|
+
if (resolved?.isObjectExpression() && binding.referencePaths.some(
|
|
59
|
+
(reference) => !reference.parentPath?.isJSXSpreadAttribute() && !reference.parentPath?.isSpreadElement()
|
|
60
|
+
))
|
|
61
|
+
return void 0;
|
|
62
|
+
return resolved;
|
|
63
|
+
}
|
|
64
|
+
function propValue(path11, name) {
|
|
65
|
+
const readObject = (path12) => {
|
|
66
|
+
const resolved = constantValue(path12);
|
|
67
|
+
if (!resolved?.isObjectExpression()) return { blocked: true };
|
|
68
|
+
for (const property of [...resolved.get("properties")].reverse()) {
|
|
69
|
+
if (property.isSpreadElement()) {
|
|
70
|
+
const found = readObjectBounded(property.get("argument"));
|
|
71
|
+
if (found.value || found.blocked) return found;
|
|
72
|
+
} else if (property.isObjectProperty() || property.isObjectMethod()) {
|
|
73
|
+
if (property.node.computed) return { blocked: true };
|
|
74
|
+
const key = property.node.key;
|
|
75
|
+
if ((BabelTypes__namespace.isIdentifier(key) ? key.name : BabelTypes__namespace.isStringLiteral(key) ? key.value : "") === name)
|
|
76
|
+
return property.isObjectProperty() ? { value: property.get("value") } : { value: property };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {};
|
|
80
|
+
};
|
|
81
|
+
let objectBudget = MAX_HOPS;
|
|
82
|
+
const readObjectBounded = (path12) => objectBudget-- > 0 ? readObject(path12) : { blocked: true };
|
|
83
|
+
for (const attr of [...path11.get("attributes")].reverse()) {
|
|
84
|
+
if (attr.isJSXAttribute() && BabelTypes__namespace.isJSXIdentifier(attr.node.name, { name })) {
|
|
85
|
+
const value = attr.get("value");
|
|
86
|
+
return value.isJSXExpressionContainer() ? unwrap(value.get("expression")) : value.node ? value : void 0;
|
|
87
|
+
}
|
|
88
|
+
if (attr.isJSXSpreadAttribute()) {
|
|
89
|
+
const found = readObjectBounded(attr.get("argument"));
|
|
90
|
+
if (found.value || found.blocked) return found.value;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return void 0;
|
|
94
|
+
}
|
|
95
|
+
function importIdentity(path11, depth = 0) {
|
|
96
|
+
if (depth > MAX_HOPS) return void 0;
|
|
97
|
+
path11 = unwrap(path11);
|
|
98
|
+
if (path11.isIdentifier() || path11.isJSXIdentifier()) {
|
|
99
|
+
const binding = path11.scope.getBinding(path11.node.name);
|
|
100
|
+
if (!binding?.constant) return void 0;
|
|
101
|
+
const declaration = binding.path;
|
|
102
|
+
if (declaration.parentPath?.isImportDeclaration()) {
|
|
103
|
+
const module = declaration.parentPath.node.source.value;
|
|
104
|
+
if (declaration.isImportSpecifier()) {
|
|
105
|
+
const imported = declaration.node.imported;
|
|
106
|
+
return { module, imported: BabelTypes__namespace.isIdentifier(imported) ? imported.name : imported.value };
|
|
107
|
+
}
|
|
108
|
+
if (declaration.isImportDefaultSpecifier()) return { module, imported: "default" };
|
|
109
|
+
if (declaration.isImportNamespaceSpecifier()) return { module, imported: "*" };
|
|
110
|
+
}
|
|
111
|
+
if (declaration.isVariableDeclarator() && declaration.get("init").node)
|
|
112
|
+
return importIdentity(declaration.get("init"), depth + 1);
|
|
113
|
+
}
|
|
114
|
+
if (path11.isJSXMemberExpression() || path11.isMemberExpression() && !path11.node.computed) {
|
|
115
|
+
const origin = importIdentity(path11.get("object"), depth + 1);
|
|
116
|
+
const key = path11.node.property;
|
|
117
|
+
if (origin && (BabelTypes__namespace.isIdentifier(key) || BabelTypes__namespace.isJSXIdentifier(key)) && (origin.imported === "*" || origin.module === "react" && origin.imported === "default"))
|
|
118
|
+
return { module: origin.module, imported: key.name };
|
|
119
|
+
}
|
|
120
|
+
return void 0;
|
|
121
|
+
}
|
|
122
|
+
function handlerFunction(path11, depth = 0) {
|
|
123
|
+
if (depth > MAX_HOPS) return void 0;
|
|
124
|
+
path11 = unwrap(path11);
|
|
125
|
+
if (path11.isFunction()) return path11;
|
|
126
|
+
if (path11.isIdentifier()) {
|
|
127
|
+
const binding = path11.scope.getBinding(path11.node.name);
|
|
128
|
+
if (!binding?.constant) return void 0;
|
|
129
|
+
if (binding.path.isFunctionDeclaration()) return binding.path;
|
|
130
|
+
if (binding.path.isVariableDeclarator() && binding.path.get("init").node)
|
|
131
|
+
return handlerFunction(binding.path.get("init"), depth + 1);
|
|
132
|
+
}
|
|
133
|
+
if (path11.isCallExpression()) {
|
|
134
|
+
const origin = importIdentity(path11.get("callee"));
|
|
135
|
+
if (origin?.module === "react" && origin.imported === "useCallback") {
|
|
136
|
+
const callback = path11.get("arguments")[0];
|
|
137
|
+
if (callback) return handlerFunction(callback, depth + 1);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (path11.isMemberExpression() && !path11.node.computed && BabelTypes__namespace.isThisExpression(path11.node.object)) {
|
|
141
|
+
const key = path11.node.property;
|
|
142
|
+
if (!BabelTypes__namespace.isIdentifier(key)) return void 0;
|
|
143
|
+
const owner = path11.findParent((p) => p.isClassDeclaration() || p.isClassExpression());
|
|
144
|
+
if (!owner || !(owner.isClassDeclaration() || owner.isClassExpression())) return void 0;
|
|
145
|
+
for (const member of owner.get("body").get("body")) {
|
|
146
|
+
if (!(member.isClassMethod() || member.isClassProperty()) || member.node.computed || member.node.static)
|
|
147
|
+
continue;
|
|
148
|
+
if (!BabelTypes__namespace.isIdentifier(member.node.key, { name: key.name })) continue;
|
|
149
|
+
if (member.isClassMethod() && member.node.kind === "method") return member;
|
|
150
|
+
if (member.isClassProperty() && member.get("value").node)
|
|
151
|
+
return handlerFunction(member.get("value"), depth + 1);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return void 0;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/extractors/control-evidence.ts
|
|
158
|
+
function symbol(node) {
|
|
159
|
+
if (BabelTypes__namespace.isTSAsExpression(node) || BabelTypes__namespace.isTSTypeAssertion(node) || BabelTypes__namespace.isTSNonNullExpression(node) || BabelTypes__namespace.isTSSatisfiesExpression(node))
|
|
160
|
+
return symbol(node.expression);
|
|
161
|
+
if (BabelTypes__namespace.isIdentifier(node) || BabelTypes__namespace.isJSXIdentifier(node)) return node.name;
|
|
162
|
+
if (BabelTypes__namespace.isThisExpression(node)) return "this";
|
|
163
|
+
if (BabelTypes__namespace.isMemberExpression(node) && !node.computed || BabelTypes__namespace.isJSXMemberExpression(node)) {
|
|
164
|
+
const object = symbol(node.object), property = symbol(node.property);
|
|
165
|
+
return object && property ? `${object}.${property}` : void 0;
|
|
166
|
+
}
|
|
167
|
+
if (BabelTypes__namespace.isUnaryExpression(node) && node.operator === "!") {
|
|
168
|
+
const value = symbol(node.argument);
|
|
169
|
+
return value ? `!${value}` : void 0;
|
|
170
|
+
}
|
|
171
|
+
return void 0;
|
|
172
|
+
}
|
|
173
|
+
function attribute(node, name) {
|
|
174
|
+
return node.attributes.find(
|
|
175
|
+
(a) => BabelTypes__namespace.isJSXAttribute(a) && BabelTypes__namespace.isJSXIdentifier(a.name, { name })
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
var ICON_LIBRARIES = [
|
|
179
|
+
"lucide-react-native",
|
|
180
|
+
"lucide-react",
|
|
181
|
+
"@tamagui/lucide-icons",
|
|
182
|
+
"@expo/vector-icons",
|
|
183
|
+
"@react-native-vector-icons/",
|
|
184
|
+
"react-native-vector-icons/"
|
|
185
|
+
];
|
|
186
|
+
function iconLibrary(module) {
|
|
187
|
+
return ICON_LIBRARIES.some(
|
|
188
|
+
(name) => name.endsWith("/") ? module.startsWith(name) : module === name || module.startsWith(name + "/")
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
function add(values, value, max = 12) {
|
|
192
|
+
if (value && value.length <= 240 && values.length < max && !values.includes(value))
|
|
193
|
+
values.push(value);
|
|
194
|
+
}
|
|
195
|
+
function iconName(path11, explicitIcon = false) {
|
|
196
|
+
const origin = importIdentity(path11);
|
|
197
|
+
if (origin && iconLibrary(origin.module) && origin.imported !== "*")
|
|
198
|
+
return origin.imported === "default" ? origin.module : `${origin.module}:${origin.imported}`;
|
|
199
|
+
const name = symbol(path11.node);
|
|
200
|
+
return name && (explicitIcon || /icon/i.test(name)) ? name : void 0;
|
|
201
|
+
}
|
|
202
|
+
function iconsInElement(path11, explicitIcon = false) {
|
|
203
|
+
const name = iconName(path11.get("name"), explicitIcon);
|
|
204
|
+
if (!name) return void 0;
|
|
205
|
+
const glyph = propValue(path11, "name");
|
|
206
|
+
const value = glyph && constantValue(glyph);
|
|
207
|
+
return value?.isStringLiteral() ? `${name}:${value.node.value}` : name;
|
|
208
|
+
}
|
|
209
|
+
function hasInteraction(path11) {
|
|
210
|
+
return ["onPress", "onLongPress", "onClick"].some(
|
|
211
|
+
(name) => attribute(path11.node, name) || propValue(path11, name)
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
function collectPresentationIcons(path11, icons) {
|
|
215
|
+
const namedIconProps = [
|
|
216
|
+
"icon",
|
|
217
|
+
"prefix",
|
|
218
|
+
"suffix",
|
|
219
|
+
"left",
|
|
220
|
+
"right",
|
|
221
|
+
"leadingIcon",
|
|
222
|
+
"trailingIcon",
|
|
223
|
+
"startIcon",
|
|
224
|
+
"endIcon",
|
|
225
|
+
"renderIcon"
|
|
226
|
+
];
|
|
227
|
+
const props = new Set(namedIconProps);
|
|
228
|
+
for (const attr of path11.node.attributes)
|
|
229
|
+
if (BabelTypes__namespace.isJSXAttribute(attr) && BabelTypes__namespace.isJSXIdentifier(attr.name) && !/^on[A-Z]/.test(attr.name.name))
|
|
230
|
+
props.add(attr.name.name);
|
|
231
|
+
for (const prop of props) {
|
|
232
|
+
const icon = propValue(path11, prop);
|
|
233
|
+
if (icon) {
|
|
234
|
+
const value = constantValue(icon);
|
|
235
|
+
if (value?.isStringLiteral()) {
|
|
236
|
+
if (prop.toLowerCase().includes("icon")) add(icons, value.node.value, 8);
|
|
237
|
+
} else {
|
|
238
|
+
const explicitIcon = prop.toLowerCase() === "icon";
|
|
239
|
+
if (icon.isJSXElement()) {
|
|
240
|
+
if (hasInteraction(icon.get("openingElement"))) continue;
|
|
241
|
+
add(icons, iconsInElement(icon.get("openingElement"), explicitIcon), 8);
|
|
242
|
+
}
|
|
243
|
+
icon.traverse({
|
|
244
|
+
JSXAttribute(attr) {
|
|
245
|
+
if (BabelTypes__namespace.isJSXIdentifier(attr.node.name) && /^on[A-Z]/.test(attr.node.name.name))
|
|
246
|
+
attr.skip();
|
|
247
|
+
},
|
|
248
|
+
JSXElement(child) {
|
|
249
|
+
const opening = child.get("openingElement");
|
|
250
|
+
if (hasInteraction(opening)) {
|
|
251
|
+
child.skip();
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
add(icons, iconsInElement(opening, explicitIcon), 8);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
if (!icons.length && (namedIconProps.includes(prop) || explicitIcon))
|
|
258
|
+
add(icons, iconName(icon, explicitIcon), 8);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function collectIcons(path11) {
|
|
264
|
+
const icons = [];
|
|
265
|
+
collectPresentationIcons(path11, icons);
|
|
266
|
+
const jsx = path11.parentPath;
|
|
267
|
+
if (jsx.isJSXElement())
|
|
268
|
+
jsx.traverse({
|
|
269
|
+
// JSX mentioned inside an event callback is not a rendered child icon.
|
|
270
|
+
JSXAttribute(attr) {
|
|
271
|
+
attr.skip();
|
|
272
|
+
},
|
|
273
|
+
JSXElement(child) {
|
|
274
|
+
const opening = child.get("openingElement");
|
|
275
|
+
if (hasInteraction(opening)) {
|
|
276
|
+
child.skip();
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
add(icons, iconsInElement(opening), 8);
|
|
280
|
+
collectPresentationIcons(opening, icons);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
return icons;
|
|
284
|
+
}
|
|
285
|
+
function conditionsAt(path11) {
|
|
286
|
+
const conditions = [];
|
|
287
|
+
let child = path11;
|
|
288
|
+
for (let parent = child.parentPath; parent && !parent.isFunction(); child = parent, parent = parent.parentPath) {
|
|
289
|
+
let test;
|
|
290
|
+
let negated = false;
|
|
291
|
+
if (parent.isLogicalExpression() && parent.node.right === child.node) {
|
|
292
|
+
if (parent.node.operator === "&&") test = parent.node.left;
|
|
293
|
+
if (parent.node.operator === "||") {
|
|
294
|
+
test = parent.node.left;
|
|
295
|
+
negated = true;
|
|
296
|
+
}
|
|
297
|
+
} else if (parent.isConditionalExpression() && parent.node.test !== child.node) {
|
|
298
|
+
test = parent.node.test;
|
|
299
|
+
negated = parent.node.alternate === child.node;
|
|
300
|
+
} else if (parent.isIfStatement() && parent.node.test !== child.node) {
|
|
301
|
+
test = parent.node.test;
|
|
302
|
+
negated = parent.node.alternate === child.node;
|
|
303
|
+
}
|
|
304
|
+
const name = symbol(test);
|
|
305
|
+
if (name) add(conditions, negated ? name.startsWith("!") ? name.slice(1) : `!${name}` : name);
|
|
306
|
+
}
|
|
307
|
+
return conditions;
|
|
308
|
+
}
|
|
309
|
+
function collectHandlerEvidence(expression, evidence) {
|
|
310
|
+
const seen = /* @__PURE__ */ new Set();
|
|
311
|
+
let budget = 100;
|
|
312
|
+
const visit = (path11, depth) => {
|
|
313
|
+
if (depth > 4 || budget-- <= 0) return;
|
|
314
|
+
const fn = handlerFunction(path11);
|
|
315
|
+
if (!fn || seen.has(fn.node)) return;
|
|
316
|
+
seen.add(fn.node);
|
|
317
|
+
fn.traverse({
|
|
318
|
+
// Ignore uncalled helper definitions; inline callbacks remain source evidence.
|
|
319
|
+
Function(nested) {
|
|
320
|
+
if (!nested.parentPath.isCallExpression() && !nested.parentPath.isObjectProperty())
|
|
321
|
+
nested.skip();
|
|
322
|
+
},
|
|
323
|
+
CallExpression(call) {
|
|
324
|
+
if (budget-- <= 0) {
|
|
325
|
+
call.skip();
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
add(evidence.calls, symbol(call.node.callee));
|
|
329
|
+
for (const arg of call.node.arguments) add(evidence.argumentBindings, symbol(arg));
|
|
330
|
+
visit(call.get("callee"), depth + 1);
|
|
331
|
+
if (!BabelTypes__namespace.isMemberExpression(call.node.callee) || call.node.callee.computed || !BabelTypes__namespace.isIdentifier(call.node.callee.property, { name: "alert" }))
|
|
332
|
+
return;
|
|
333
|
+
const callee = call.get("callee");
|
|
334
|
+
if (!callee.isMemberExpression()) return;
|
|
335
|
+
const origin = importIdentity(callee.get("object"));
|
|
336
|
+
if (origin?.module !== "react-native" || origin.imported !== "Alert") return;
|
|
337
|
+
const options = call.node.arguments[2];
|
|
338
|
+
const destructiveOption = BabelTypes__namespace.isArrayExpression(options) && options.elements.some(
|
|
339
|
+
(option) => BabelTypes__namespace.isObjectExpression(option) && option.properties.some(
|
|
340
|
+
(p) => BabelTypes__namespace.isObjectProperty(p) && !p.computed && symbol(p.key) === "style" && BabelTypes__namespace.isStringLiteral(p.value, { value: "destructive" })
|
|
341
|
+
)
|
|
342
|
+
);
|
|
343
|
+
if (destructiveOption)
|
|
344
|
+
evidence.nativeConfirmation = {
|
|
345
|
+
title: symbol(call.node.arguments[0]),
|
|
346
|
+
destructiveOption
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
visit(unwrap(expression), 0);
|
|
352
|
+
}
|
|
353
|
+
function extractControlEvidence(ast, source, file) {
|
|
354
|
+
const candidates = [];
|
|
355
|
+
const sourceHash = crypto.createHash("sha256").update(source).digest("hex");
|
|
356
|
+
traverse5__default.default(ast, {
|
|
357
|
+
JSXOpeningElement(path11) {
|
|
358
|
+
const node = path11.node;
|
|
359
|
+
if (attribute(node, "__appilotsControl")) return;
|
|
360
|
+
const value = propValue(path11, "onPress");
|
|
361
|
+
if (!value && !attribute(node, "onPress") || value?.isNullLiteral() || value?.isJSXEmptyExpression())
|
|
362
|
+
return;
|
|
363
|
+
const icons = collectIcons(path11);
|
|
364
|
+
if (!icons.length || node.end == null) return;
|
|
365
|
+
const evidence = {
|
|
366
|
+
version: 1,
|
|
367
|
+
siteId: crypto.createHash("sha256").update(`${file}:${sourceHash}:${node.start}`).digest("hex").slice(0, 20),
|
|
368
|
+
component: symbol(node.name) ?? "unknown",
|
|
369
|
+
icons,
|
|
370
|
+
...value && symbol(value.node) ? { handler: symbol(value.node) } : {},
|
|
371
|
+
calls: [],
|
|
372
|
+
argumentBindings: [],
|
|
373
|
+
conditions: conditionsAt(path11)
|
|
374
|
+
};
|
|
375
|
+
if (value) collectHandlerEvidence(value, evidence);
|
|
376
|
+
candidates.push({ evidence, sourceHash, offset: node.end - (node.selfClosing ? 2 : 1) });
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
return candidates;
|
|
380
|
+
}
|
|
44
381
|
function byCodeUnit(a, b) {
|
|
45
382
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
46
383
|
}
|
|
@@ -162,7 +499,7 @@ function classifyJsxComponent(name, element) {
|
|
|
162
499
|
}
|
|
163
500
|
function collectFunctions(ast) {
|
|
164
501
|
const handlers = /* @__PURE__ */ new Map();
|
|
165
|
-
|
|
502
|
+
traverse5__default.default(ast, {
|
|
166
503
|
FunctionDeclaration: (nodePath) => {
|
|
167
504
|
if (nodePath.node.id?.name) handlers.set(nodePath.node.id.name, nodePath.node);
|
|
168
505
|
},
|
|
@@ -265,7 +602,7 @@ function analyzeFunctionBehavior(name, fn, handlers, seen = /* @__PURE__ */ new
|
|
|
265
602
|
}
|
|
266
603
|
};
|
|
267
604
|
if (fn.body) {
|
|
268
|
-
|
|
605
|
+
traverse5__default.default(fn.body, {
|
|
269
606
|
noScope: true,
|
|
270
607
|
enter: (nodePath) => inspectNode(nodePath.node)
|
|
271
608
|
});
|
|
@@ -293,7 +630,7 @@ function setterToStateName(setterName) {
|
|
|
293
630
|
}
|
|
294
631
|
function extractNavigationCalls(ast) {
|
|
295
632
|
const calls = [];
|
|
296
|
-
|
|
633
|
+
traverse5__default.default(ast, {
|
|
297
634
|
noScope: !BabelTypes__namespace.isFile(ast),
|
|
298
635
|
CallExpression: (nodePath) => {
|
|
299
636
|
const node = nodePath.node;
|
|
@@ -444,6 +781,7 @@ var ScreenAnalyzer = class {
|
|
|
444
781
|
routeTargetFiles;
|
|
445
782
|
/** §D: Count of screens filtered out in strict mode (available after analyze()) */
|
|
446
783
|
screensFilteredOut = 0;
|
|
784
|
+
controlEvidenceFiles = {};
|
|
447
785
|
constructor(config, options) {
|
|
448
786
|
this.config = config;
|
|
449
787
|
this.routeTargetFiles = options?.routeTargetFiles ?? /* @__PURE__ */ new Set();
|
|
@@ -544,6 +882,11 @@ var ScreenAnalyzer = class {
|
|
|
544
882
|
title: registerScreenMeta?.title,
|
|
545
883
|
description: registerScreenMeta?.description,
|
|
546
884
|
components,
|
|
885
|
+
controlCandidates: extractControlEvidence(
|
|
886
|
+
ast,
|
|
887
|
+
source,
|
|
888
|
+
path2__namespace.default.relative(this.config.rootDir, filePath)
|
|
889
|
+
),
|
|
547
890
|
forms,
|
|
548
891
|
actions,
|
|
549
892
|
navigationTargets,
|
|
@@ -554,6 +897,8 @@ var ScreenAnalyzer = class {
|
|
|
554
897
|
...permissionsFromJsDoc.isPii ? { isPii: true } : {}
|
|
555
898
|
} : {}
|
|
556
899
|
};
|
|
900
|
+
if (descriptor.controlCandidates?.length)
|
|
901
|
+
this.controlEvidenceFiles[path2__namespace.default.relative(this.config.rootDir, filePath).split(path2__namespace.default.sep).join("/")] = descriptor.controlCandidates;
|
|
557
902
|
descriptor.__hasRegisterScreen = hasRegisterScreenCall;
|
|
558
903
|
return descriptor;
|
|
559
904
|
}
|
|
@@ -563,7 +908,7 @@ var ScreenAnalyzer = class {
|
|
|
563
908
|
*/
|
|
564
909
|
detectRegisterScreenCall(ast) {
|
|
565
910
|
let found = false;
|
|
566
|
-
|
|
911
|
+
traverse5__default.default(ast, {
|
|
567
912
|
CallExpression: (nodePath) => {
|
|
568
913
|
if (found) return;
|
|
569
914
|
const callee = nodePath.node.callee;
|
|
@@ -580,7 +925,7 @@ var ScreenAnalyzer = class {
|
|
|
580
925
|
*/
|
|
581
926
|
extractRegisterScreenMetadata(ast) {
|
|
582
927
|
let metadata = null;
|
|
583
|
-
|
|
928
|
+
traverse5__default.default(ast, {
|
|
584
929
|
CallExpression: (nodePath) => {
|
|
585
930
|
const callee = nodePath.node.callee;
|
|
586
931
|
if (BabelTypes__namespace.isIdentifier(callee) && callee.name === "registerScreen" || BabelTypes__namespace.isMemberExpression(callee) && BabelTypes__namespace.isIdentifier(callee.property) && callee.property.name === "registerScreen") {
|
|
@@ -877,7 +1222,7 @@ var ScreenAnalyzer = class {
|
|
|
877
1222
|
*/
|
|
878
1223
|
extractDefaultComponentName(ast) {
|
|
879
1224
|
let componentName = "";
|
|
880
|
-
|
|
1225
|
+
traverse5__default.default(ast, {
|
|
881
1226
|
ExportDefaultDeclaration: (nodePath) => {
|
|
882
1227
|
const declaration = nodePath.node.declaration;
|
|
883
1228
|
if (BabelTypes__namespace.isFunctionDeclaration(declaration) && declaration.id?.name) {
|
|
@@ -902,7 +1247,7 @@ var ScreenAnalyzer = class {
|
|
|
902
1247
|
*/
|
|
903
1248
|
extractNavigationTargets(ast) {
|
|
904
1249
|
const targets = /* @__PURE__ */ new Set();
|
|
905
|
-
|
|
1250
|
+
traverse5__default.default(ast, {
|
|
906
1251
|
CallExpression: (nodePath) => {
|
|
907
1252
|
const callee = nodePath.node.callee;
|
|
908
1253
|
if (BabelTypes__namespace.isMemberExpression(callee) && BabelTypes__namespace.isIdentifier(callee.object) && callee.object.name === "navigation" && BabelTypes__namespace.isIdentifier(callee.property) && callee.property.name === "navigate") {
|
|
@@ -921,7 +1266,7 @@ var ScreenAnalyzer = class {
|
|
|
921
1266
|
extractForms(ast) {
|
|
922
1267
|
const forms = [];
|
|
923
1268
|
const fields = /* @__PURE__ */ new Map();
|
|
924
|
-
|
|
1269
|
+
traverse5__default.default(ast, {
|
|
925
1270
|
JSXOpeningElement: (nodePath) => {
|
|
926
1271
|
const element = nodePath.node;
|
|
927
1272
|
if (BabelTypes__namespace.isJSXIdentifier(element.name)) {
|
|
@@ -1042,7 +1387,7 @@ var ScreenAnalyzer = class {
|
|
|
1042
1387
|
extractComponents(ast) {
|
|
1043
1388
|
const components = [];
|
|
1044
1389
|
const seen = /* @__PURE__ */ new Set();
|
|
1045
|
-
|
|
1390
|
+
traverse5__default.default(ast, {
|
|
1046
1391
|
JSXOpeningElement: (nodePath) => {
|
|
1047
1392
|
const element = nodePath.node;
|
|
1048
1393
|
if (BabelTypes__namespace.isJSXIdentifier(element.name)) {
|
|
@@ -1106,7 +1451,7 @@ var ScreenAnalyzer = class {
|
|
|
1106
1451
|
const actionLabels = new Map(
|
|
1107
1452
|
actions.filter((a) => a.label).map((a) => [this.normalizeLabel(a.label), a])
|
|
1108
1453
|
);
|
|
1109
|
-
|
|
1454
|
+
traverse5__default.default(ast, {
|
|
1110
1455
|
JSXOpeningElement: (nodePath) => {
|
|
1111
1456
|
const element = nodePath.node;
|
|
1112
1457
|
if (BabelTypes__namespace.isJSXIdentifier(element.name)) {
|
|
@@ -1175,7 +1520,7 @@ var ScreenAnalyzer = class {
|
|
|
1175
1520
|
}
|
|
1176
1521
|
collectButtonHandlersByLabel(ast) {
|
|
1177
1522
|
const out = /* @__PURE__ */ new Map();
|
|
1178
|
-
|
|
1523
|
+
traverse5__default.default(ast, {
|
|
1179
1524
|
JSXOpeningElement: (nodePath) => {
|
|
1180
1525
|
const element = nodePath.node;
|
|
1181
1526
|
if (!BabelTypes__namespace.isJSXIdentifier(element.name)) return;
|
|
@@ -1257,7 +1602,7 @@ var ScreenAnalyzer = class {
|
|
|
1257
1602
|
}
|
|
1258
1603
|
};
|
|
1259
1604
|
if (fn.body) {
|
|
1260
|
-
|
|
1605
|
+
traverse5__default.default(
|
|
1261
1606
|
fn.body,
|
|
1262
1607
|
{
|
|
1263
1608
|
noScope: true,
|
|
@@ -1454,7 +1799,7 @@ var ScreenAnalyzer = class {
|
|
|
1454
1799
|
extractCollections(ast) {
|
|
1455
1800
|
const renderItemFns = this.collectRenderItemFunctions(ast);
|
|
1456
1801
|
const collections = [];
|
|
1457
|
-
|
|
1802
|
+
traverse5__default.default(ast, {
|
|
1458
1803
|
JSXOpeningElement: (nodePath) => {
|
|
1459
1804
|
const element = nodePath.node;
|
|
1460
1805
|
if (!BabelTypes__namespace.isJSXIdentifier(element.name)) return;
|
|
@@ -1491,7 +1836,7 @@ var ScreenAnalyzer = class {
|
|
|
1491
1836
|
}
|
|
1492
1837
|
collectRenderItemFunctions(ast) {
|
|
1493
1838
|
const out = /* @__PURE__ */ new Map();
|
|
1494
|
-
|
|
1839
|
+
traverse5__default.default(ast, {
|
|
1495
1840
|
VariableDeclarator: (nodePath) => {
|
|
1496
1841
|
if (!BabelTypes__namespace.isIdentifier(nodePath.node.id)) return;
|
|
1497
1842
|
const init = nodePath.node.init;
|
|
@@ -1534,7 +1879,7 @@ var ScreenAnalyzer = class {
|
|
|
1534
1879
|
}
|
|
1535
1880
|
extractRowAction(fn) {
|
|
1536
1881
|
let action;
|
|
1537
|
-
|
|
1882
|
+
traverse5__default.default(
|
|
1538
1883
|
fn.body,
|
|
1539
1884
|
{
|
|
1540
1885
|
noScope: true,
|
|
@@ -1587,7 +1932,7 @@ var ScreenAnalyzer = class {
|
|
|
1587
1932
|
} else if (BabelTypes__namespace.isIdentifier(firstParam)) {
|
|
1588
1933
|
itemNames.add(firstParam.name);
|
|
1589
1934
|
}
|
|
1590
|
-
|
|
1935
|
+
traverse5__default.default(
|
|
1591
1936
|
fn.body,
|
|
1592
1937
|
{
|
|
1593
1938
|
noScope: true,
|
|
@@ -1629,7 +1974,7 @@ var ScreenAnalyzer = class {
|
|
|
1629
1974
|
inferSearchField(ast, dataSource) {
|
|
1630
1975
|
if (!dataSource) return void 0;
|
|
1631
1976
|
let queryBinding;
|
|
1632
|
-
|
|
1977
|
+
traverse5__default.default(ast, {
|
|
1633
1978
|
CallExpression: (nodePath) => {
|
|
1634
1979
|
const node = nodePath.node;
|
|
1635
1980
|
if (!BabelTypes__namespace.isMemberExpression(node.callee)) return;
|
|
@@ -1640,7 +1985,7 @@ var ScreenAnalyzer = class {
|
|
|
1640
1985
|
const fn = node.arguments[0];
|
|
1641
1986
|
if (!BabelTypes__namespace.isArrowFunctionExpression(fn) && !BabelTypes__namespace.isFunctionExpression(fn))
|
|
1642
1987
|
return;
|
|
1643
|
-
|
|
1988
|
+
traverse5__default.default(
|
|
1644
1989
|
fn.body,
|
|
1645
1990
|
{
|
|
1646
1991
|
noScope: true,
|
|
@@ -1682,7 +2027,7 @@ var ScreenAnalyzer = class {
|
|
|
1682
2027
|
}
|
|
1683
2028
|
};
|
|
1684
2029
|
var EXTENSIONS = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"];
|
|
1685
|
-
var
|
|
2030
|
+
var MAX_HOPS2 = 8;
|
|
1686
2031
|
var ModuleGraph = class {
|
|
1687
2032
|
asts = /* @__PURE__ */ new Map();
|
|
1688
2033
|
resolved = /* @__PURE__ */ new Map();
|
|
@@ -1801,7 +2146,7 @@ var ModuleGraph = class {
|
|
|
1801
2146
|
* Devolve o arquivo e o nome sob o qual ele é definido lá.
|
|
1802
2147
|
*/
|
|
1803
2148
|
resolveBinding(file, name, hops = 0) {
|
|
1804
|
-
if (hops >
|
|
2149
|
+
if (hops > MAX_HOPS2) return null;
|
|
1805
2150
|
if (this.topLevelInit(file, name) !== null) return { file, name };
|
|
1806
2151
|
const binding = this.imports(file).get(name);
|
|
1807
2152
|
if (binding) {
|
|
@@ -1855,7 +2200,7 @@ var ModuleGraph = class {
|
|
|
1855
2200
|
* com interpolação nem valor calculado, de propósito.
|
|
1856
2201
|
*/
|
|
1857
2202
|
stringConstant(file, node, hops = 0) {
|
|
1858
|
-
if (!node || hops >
|
|
2203
|
+
if (!node || hops > MAX_HOPS2) return null;
|
|
1859
2204
|
if (BabelTypes__namespace.isStringLiteral(node)) return node.value;
|
|
1860
2205
|
if (BabelTypes__namespace.isTemplateLiteral(node)) {
|
|
1861
2206
|
return node.expressions.length === 0 ? node.quasis[0]?.value.cooked ?? null : null;
|
|
@@ -1884,7 +2229,7 @@ var ModuleGraph = class {
|
|
|
1884
2229
|
* que é como o `pocketpal` monta todas as telas do Drawer).
|
|
1885
2230
|
*/
|
|
1886
2231
|
componentFile(file, node, hops = 0) {
|
|
1887
|
-
if (!node || hops >
|
|
2232
|
+
if (!node || hops > MAX_HOPS2) return null;
|
|
1888
2233
|
if (BabelTypes__namespace.isCallExpression(node)) {
|
|
1889
2234
|
for (const arg of node.arguments) {
|
|
1890
2235
|
if (BabelTypes__namespace.isIdentifier(arg) || BabelTypes__namespace.isMemberExpression(arg)) {
|
|
@@ -2080,7 +2425,7 @@ function workspaceGlobs(dir) {
|
|
|
2080
2425
|
}
|
|
2081
2426
|
function expandWorkspaceGlobs(root, globs) {
|
|
2082
2427
|
const out = [];
|
|
2083
|
-
const
|
|
2428
|
+
const add2 = (dir) => {
|
|
2084
2429
|
const pkgPath = path2__namespace.default.join(dir, "package.json");
|
|
2085
2430
|
if (!fs$1.existsSync(pkgPath)) return;
|
|
2086
2431
|
try {
|
|
@@ -2101,12 +2446,12 @@ function expandWorkspaceGlobs(root, globs) {
|
|
|
2101
2446
|
for (const entry of entries) {
|
|
2102
2447
|
const dir = path2__namespace.default.join(parent, entry);
|
|
2103
2448
|
try {
|
|
2104
|
-
if (fs$1.statSync(dir).isDirectory())
|
|
2449
|
+
if (fs$1.statSync(dir).isDirectory()) add2(dir);
|
|
2105
2450
|
} catch {
|
|
2106
2451
|
}
|
|
2107
2452
|
}
|
|
2108
2453
|
} else if (!glob.includes("*")) {
|
|
2109
|
-
|
|
2454
|
+
add2(path2__namespace.default.join(root, glob));
|
|
2110
2455
|
}
|
|
2111
2456
|
}
|
|
2112
2457
|
return out.sort((a, b) => b.name.length - a.name.length);
|
|
@@ -2426,7 +2771,7 @@ var NavigationAnalyzer = class {
|
|
|
2426
2771
|
const ast = this.graph.parse(filePath);
|
|
2427
2772
|
if (!ast) return [];
|
|
2428
2773
|
const out = /* @__PURE__ */ new Map();
|
|
2429
|
-
|
|
2774
|
+
traverse5__default.default(ast, {
|
|
2430
2775
|
CallExpression: (nodePath) => {
|
|
2431
2776
|
const callee = nodePath.node.callee;
|
|
2432
2777
|
if (!BabelTypes__namespace.isIdentifier(callee)) return;
|
|
@@ -2587,7 +2932,7 @@ var NavigationAnalyzer = class {
|
|
|
2587
2932
|
const ast = this.graph.parse(filePath);
|
|
2588
2933
|
if (!ast) return [];
|
|
2589
2934
|
const found = /* @__PURE__ */ new Map();
|
|
2590
|
-
|
|
2935
|
+
traverse5__default.default(ast, {
|
|
2591
2936
|
JSXElement: (nodePath) => {
|
|
2592
2937
|
const { node } = nodePath;
|
|
2593
2938
|
const openingElement = node.openingElement;
|
|
@@ -2659,7 +3004,7 @@ var NavigationAnalyzer = class {
|
|
|
2659
3004
|
if (!ast) return [];
|
|
2660
3005
|
const byNavigator = /* @__PURE__ */ new Map();
|
|
2661
3006
|
const resolved = /* @__PURE__ */ new Map();
|
|
2662
|
-
|
|
3007
|
+
traverse5__default.default(ast, {
|
|
2663
3008
|
JSXElement: (nodePath) => {
|
|
2664
3009
|
const name = nodePath.node.openingElement.name;
|
|
2665
3010
|
if (!BabelTypes__namespace.isJSXMemberExpression(name) || !BabelTypes__namespace.isJSXIdentifier(name.object)) return;
|
|
@@ -2892,7 +3237,7 @@ var NavigationAnalyzer = class {
|
|
|
2892
3237
|
...this.config.parserPlugins || []
|
|
2893
3238
|
]
|
|
2894
3239
|
});
|
|
2895
|
-
|
|
3240
|
+
traverse5__default.default(ast, {
|
|
2896
3241
|
TSTypeAliasDeclaration: (nodePath) => {
|
|
2897
3242
|
const { node } = nodePath;
|
|
2898
3243
|
const typeName = node.id.name;
|
|
@@ -2965,7 +3310,7 @@ var NavigationAnalyzer = class {
|
|
|
2965
3310
|
if (type.type === "TSUndefinedKeyword") return "undefined";
|
|
2966
3311
|
if (type.type === "TSNullKeyword") return "null";
|
|
2967
3312
|
if (type.type === "TSUnionType") {
|
|
2968
|
-
return type.types.map((
|
|
3313
|
+
return type.types.map((t15) => this.typeToString(t15)).join(" | ");
|
|
2969
3314
|
}
|
|
2970
3315
|
if (type.type === "TSTypeLiteral") {
|
|
2971
3316
|
return "object";
|
|
@@ -2986,7 +3331,7 @@ var NavigationAnalyzer = class {
|
|
|
2986
3331
|
/** Attach parsed type params to navigator screens */
|
|
2987
3332
|
attachParamsToNavigators(navigators, types) {
|
|
2988
3333
|
for (const navigator of navigators) {
|
|
2989
|
-
const matchingType = types.find((
|
|
3334
|
+
const matchingType = types.find((t15) => t15.type === navigator.type);
|
|
2990
3335
|
if (matchingType) {
|
|
2991
3336
|
for (const screen of navigator.screens) {
|
|
2992
3337
|
const screenParams = matchingType.paramEntries.get(screen.name);
|
|
@@ -3075,7 +3420,7 @@ var ComponentAnalyzer = class {
|
|
|
3075
3420
|
plugins: ["jsx", "typescript", ["decorators", { decoratorsBeforeExport: true }]]
|
|
3076
3421
|
});
|
|
3077
3422
|
const components = [];
|
|
3078
|
-
|
|
3423
|
+
traverse5__default.default(ast, {
|
|
3079
3424
|
JSXElement: (path11) => {
|
|
3080
3425
|
const component = this.extractComponentFromJSXElement(path11.node);
|
|
3081
3426
|
if (component) {
|
|
@@ -3203,12 +3548,12 @@ var FormAnalyzer = class {
|
|
|
3203
3548
|
this.stateVariables.clear();
|
|
3204
3549
|
this.inputElements = [];
|
|
3205
3550
|
this.submitButtons = [];
|
|
3206
|
-
|
|
3551
|
+
traverse5__default.default(ast, {
|
|
3207
3552
|
CallExpression: (path11) => {
|
|
3208
3553
|
this.extractStateVariables(path11.node);
|
|
3209
3554
|
}
|
|
3210
3555
|
});
|
|
3211
|
-
|
|
3556
|
+
traverse5__default.default(ast, {
|
|
3212
3557
|
JSXElement: (path11) => {
|
|
3213
3558
|
this.extractFormElements(path11.node);
|
|
3214
3559
|
}
|
|
@@ -3244,23 +3589,23 @@ var FormAnalyzer = class {
|
|
|
3244
3589
|
for (const attr of openingElement.attributes) {
|
|
3245
3590
|
if (BabelTypes__namespace.isJSXAttribute(attr) && BabelTypes__namespace.isJSXIdentifier(attr.name)) {
|
|
3246
3591
|
const propName = attr.name.name;
|
|
3247
|
-
const
|
|
3592
|
+
const propValue2 = this.extractAttributeValue(attr.value);
|
|
3248
3593
|
switch (propName) {
|
|
3249
3594
|
case "label":
|
|
3250
|
-
info.label =
|
|
3595
|
+
info.label = propValue2;
|
|
3251
3596
|
break;
|
|
3252
3597
|
case "placeholder":
|
|
3253
|
-
info.placeholder =
|
|
3598
|
+
info.placeholder = propValue2;
|
|
3254
3599
|
break;
|
|
3255
3600
|
case "keyboardType":
|
|
3256
|
-
info.keyboardType =
|
|
3601
|
+
info.keyboardType = propValue2;
|
|
3257
3602
|
break;
|
|
3258
3603
|
case "testID":
|
|
3259
|
-
info.testID =
|
|
3604
|
+
info.testID = propValue2;
|
|
3260
3605
|
break;
|
|
3261
3606
|
case "appilotsId":
|
|
3262
|
-
info.appilotsId =
|
|
3263
|
-
if (
|
|
3607
|
+
info.appilotsId = propValue2;
|
|
3608
|
+
if (propValue2) info.varName = propValue2;
|
|
3264
3609
|
break;
|
|
3265
3610
|
case "value":
|
|
3266
3611
|
if (attr.value && BabelTypes__namespace.isJSXExpressionContainer(attr.value) && BabelTypes__namespace.isIdentifier(attr.value.expression)) {
|
|
@@ -3309,7 +3654,7 @@ var FormAnalyzer = class {
|
|
|
3309
3654
|
}
|
|
3310
3655
|
extractValidationRules(ast) {
|
|
3311
3656
|
const rules = {};
|
|
3312
|
-
|
|
3657
|
+
traverse5__default.default(ast, {
|
|
3313
3658
|
IfStatement: (path11) => {
|
|
3314
3659
|
const test = path11.node.test;
|
|
3315
3660
|
const rule = this.extractRuleFromCondition(test);
|
|
@@ -3463,7 +3808,7 @@ async function composeAffordances(options) {
|
|
|
3463
3808
|
const exclusive = children.filter((c) => (fanIn.get(c) ?? 0) <= MAX_FAN_IN);
|
|
3464
3809
|
if (exclusive.length === 0) continue;
|
|
3465
3810
|
const actionIds = new Set(screen.actions.map((a) => a.id));
|
|
3466
|
-
const targetIds = new Set((screen.targets ?? []).map((
|
|
3811
|
+
const targetIds = new Set((screen.targets ?? []).map((t15) => t15.id));
|
|
3467
3812
|
const formIds = new Set(screen.forms.map((f) => f.id));
|
|
3468
3813
|
let gained = false;
|
|
3469
3814
|
for (const file of exclusive) {
|
|
@@ -3605,6 +3950,7 @@ var ReactNativePlatformAnalyzer = class {
|
|
|
3605
3950
|
});
|
|
3606
3951
|
return {
|
|
3607
3952
|
screens: enrichedScreens,
|
|
3953
|
+
controlEvidenceFiles: screenAnalyzer.controlEvidenceFiles,
|
|
3608
3954
|
navigation,
|
|
3609
3955
|
analyzedFiles: screenFiles.length,
|
|
3610
3956
|
...screenAnalyzer.screensFilteredOut > 0 ? { screensFilteredOut: screenAnalyzer.screensFilteredOut } : {},
|
|
@@ -3869,7 +4215,7 @@ function extractWebNavigationCalls(ast) {
|
|
|
3869
4215
|
calls.push({ method: "navigate", targetPath: node.right.value });
|
|
3870
4216
|
}
|
|
3871
4217
|
};
|
|
3872
|
-
|
|
4218
|
+
traverse5__default.default(ast, {
|
|
3873
4219
|
noScope: !BabelTypes__namespace.isFile(ast),
|
|
3874
4220
|
enter: (nodePath) => inspect(nodePath.node)
|
|
3875
4221
|
});
|
|
@@ -3991,7 +4337,7 @@ var WebScreenAnalyzer = class {
|
|
|
3991
4337
|
// ── registerScreen ────────────────────────────────────────────────
|
|
3992
4338
|
detectRegisterScreenCall(ast) {
|
|
3993
4339
|
let found = false;
|
|
3994
|
-
|
|
4340
|
+
traverse5__default.default(ast, {
|
|
3995
4341
|
CallExpression: (nodePath) => {
|
|
3996
4342
|
if (found) return;
|
|
3997
4343
|
if (isRegisterScreenCallee(nodePath.node.callee)) {
|
|
@@ -4004,7 +4350,7 @@ var WebScreenAnalyzer = class {
|
|
|
4004
4350
|
}
|
|
4005
4351
|
extractRegisterScreenMetadata(ast) {
|
|
4006
4352
|
let plain = null;
|
|
4007
|
-
|
|
4353
|
+
traverse5__default.default(ast, {
|
|
4008
4354
|
CallExpression: (nodePath) => {
|
|
4009
4355
|
if (!isRegisterScreenCallee(nodePath.node.callee)) return;
|
|
4010
4356
|
const arg = nodePath.node.arguments[0];
|
|
@@ -4052,7 +4398,7 @@ var WebScreenAnalyzer = class {
|
|
|
4052
4398
|
extractComponentName(ast) {
|
|
4053
4399
|
let defaultName = "";
|
|
4054
4400
|
let firstExported = "";
|
|
4055
|
-
|
|
4401
|
+
traverse5__default.default(ast, {
|
|
4056
4402
|
ExportDefaultDeclaration: (nodePath) => {
|
|
4057
4403
|
const declaration = nodePath.node.declaration;
|
|
4058
4404
|
if (BabelTypes__namespace.isFunctionDeclaration(declaration) && declaration.id?.name) {
|
|
@@ -4081,7 +4427,7 @@ var WebScreenAnalyzer = class {
|
|
|
4081
4427
|
extractComponents(ast) {
|
|
4082
4428
|
const components = [];
|
|
4083
4429
|
const seen = /* @__PURE__ */ new Set();
|
|
4084
|
-
|
|
4430
|
+
traverse5__default.default(ast, {
|
|
4085
4431
|
JSXOpeningElement: (nodePath) => {
|
|
4086
4432
|
const element = nodePath.node;
|
|
4087
4433
|
const name = getJsxElementName(element);
|
|
@@ -4102,7 +4448,7 @@ var WebScreenAnalyzer = class {
|
|
|
4102
4448
|
// ── <label htmlFor> association ───────────────────────────────────
|
|
4103
4449
|
collectHtmlForLabels(ast) {
|
|
4104
4450
|
const labels = /* @__PURE__ */ new Map();
|
|
4105
|
-
|
|
4451
|
+
traverse5__default.default(ast, {
|
|
4106
4452
|
JSXElement: (nodePath) => {
|
|
4107
4453
|
const element = nodePath.node;
|
|
4108
4454
|
if (getJsxElementName(element.openingElement) !== "label") return;
|
|
@@ -4145,7 +4491,7 @@ var WebScreenAnalyzer = class {
|
|
|
4145
4491
|
formBuckets.set(formElement, bucket);
|
|
4146
4492
|
return bucket;
|
|
4147
4493
|
};
|
|
4148
|
-
|
|
4494
|
+
traverse5__default.default(ast, {
|
|
4149
4495
|
JSXElement: (nodePath) => {
|
|
4150
4496
|
const element = nodePath.node;
|
|
4151
4497
|
const name = getJsxElementName(element.openingElement);
|
|
@@ -4162,7 +4508,7 @@ var WebScreenAnalyzer = class {
|
|
|
4162
4508
|
if (!bucket.fields.has(field.name)) bucket.fields.set(field.name, field);
|
|
4163
4509
|
}
|
|
4164
4510
|
});
|
|
4165
|
-
|
|
4511
|
+
traverse5__default.default(ast, {
|
|
4166
4512
|
JSXElement: (nodePath) => {
|
|
4167
4513
|
const element = nodePath.node;
|
|
4168
4514
|
const name = getJsxElementName(element.openingElement);
|
|
@@ -4340,7 +4686,7 @@ var WebScreenAnalyzer = class {
|
|
|
4340
4686
|
const actionLabels = new Map(
|
|
4341
4687
|
actions.filter((a) => a.label).map((a) => [normalizeLabel(a.label), a])
|
|
4342
4688
|
);
|
|
4343
|
-
|
|
4689
|
+
traverse5__default.default(ast, {
|
|
4344
4690
|
JSXElement: (nodePath) => {
|
|
4345
4691
|
const element = nodePath.node;
|
|
4346
4692
|
const name = getJsxElementName(element.openingElement);
|
|
@@ -4571,7 +4917,7 @@ var WebScreenAnalyzer = class {
|
|
|
4571
4917
|
for (const call of extractWebNavigationCalls(ast)) {
|
|
4572
4918
|
if (call.targetPath && call.targetPath.startsWith("/")) targets.add(call.targetPath);
|
|
4573
4919
|
}
|
|
4574
|
-
|
|
4920
|
+
traverse5__default.default(ast, {
|
|
4575
4921
|
JSXOpeningElement: (nodePath) => {
|
|
4576
4922
|
const element = nodePath.node;
|
|
4577
4923
|
const name = getJsxElementName(element);
|
|
@@ -4591,7 +4937,7 @@ var WebScreenAnalyzer = class {
|
|
|
4591
4937
|
extractCollections(ast) {
|
|
4592
4938
|
const collections = [];
|
|
4593
4939
|
const seen = /* @__PURE__ */ new Set();
|
|
4594
|
-
|
|
4940
|
+
traverse5__default.default(ast, {
|
|
4595
4941
|
JSXExpressionContainer: (nodePath) => {
|
|
4596
4942
|
const expr = nodePath.node.expression;
|
|
4597
4943
|
if (!BabelTypes__namespace.isCallExpression(expr) || !BabelTypes__namespace.isMemberExpression(expr.callee) || !BabelTypes__namespace.isIdentifier(expr.callee.object) || !BabelTypes__namespace.isIdentifier(expr.callee.property) || expr.callee.property.name !== "map") {
|
|
@@ -4703,7 +5049,7 @@ function firstCalledFunctionName(node) {
|
|
|
4703
5049
|
}
|
|
4704
5050
|
function containsWindowConfirm(body) {
|
|
4705
5051
|
let found = false;
|
|
4706
|
-
|
|
5052
|
+
traverse5__default.default(
|
|
4707
5053
|
body,
|
|
4708
5054
|
{
|
|
4709
5055
|
noScope: true,
|
|
@@ -4755,7 +5101,7 @@ function collectionItemNames(callback) {
|
|
|
4755
5101
|
function collectionDisplayFields(callback, itemNames) {
|
|
4756
5102
|
const fields = /* @__PURE__ */ new Set();
|
|
4757
5103
|
if (!callback.body) return [];
|
|
4758
|
-
|
|
5104
|
+
traverse5__default.default(
|
|
4759
5105
|
callback.body,
|
|
4760
5106
|
{
|
|
4761
5107
|
noScope: true,
|
|
@@ -4772,7 +5118,7 @@ function collectionDisplayFields(callback, itemNames) {
|
|
|
4772
5118
|
function collectionKeyField(callback, itemNames) {
|
|
4773
5119
|
let keyField;
|
|
4774
5120
|
if (!callback.body) return void 0;
|
|
4775
|
-
|
|
5121
|
+
traverse5__default.default(
|
|
4776
5122
|
callback.body,
|
|
4777
5123
|
{
|
|
4778
5124
|
noScope: true,
|
|
@@ -4915,7 +5261,7 @@ var WebNavigationAnalyzer = class {
|
|
|
4915
5261
|
if (BabelTypes__namespace.isJSXElement(child)) visitRoute(child, fullPath);
|
|
4916
5262
|
}
|
|
4917
5263
|
};
|
|
4918
|
-
|
|
5264
|
+
traverse5__default.default(ast, {
|
|
4919
5265
|
JSXElement: (nodePath) => {
|
|
4920
5266
|
const name = getJsxElementName(nodePath.node.openingElement);
|
|
4921
5267
|
if (name !== "Routes" && name !== "Route") return;
|
|
@@ -4954,7 +5300,7 @@ var WebNavigationAnalyzer = class {
|
|
|
4954
5300
|
"createMemoryRouter",
|
|
4955
5301
|
"useRoutes"
|
|
4956
5302
|
]);
|
|
4957
|
-
|
|
5303
|
+
traverse5__default.default(ast, {
|
|
4958
5304
|
CallExpression: (nodePath) => {
|
|
4959
5305
|
const callee = nodePath.node.callee;
|
|
4960
5306
|
if (!BabelTypes__namespace.isIdentifier(callee) || !ROUTER_FACTORIES.has(callee.name)) return;
|
|
@@ -5387,8 +5733,8 @@ var ZodParsedType = util.arrayToEnum([
|
|
|
5387
5733
|
"set"
|
|
5388
5734
|
]);
|
|
5389
5735
|
var getParsedType = (data) => {
|
|
5390
|
-
const
|
|
5391
|
-
switch (
|
|
5736
|
+
const t15 = typeof data;
|
|
5737
|
+
switch (t15) {
|
|
5392
5738
|
case "undefined":
|
|
5393
5739
|
return ZodParsedType.undefined;
|
|
5394
5740
|
case "string":
|
|
@@ -9233,7 +9579,25 @@ function isSafeImageUrl(value) {
|
|
|
9233
9579
|
return SAFE_IMAGE_URL_RE.test(trimmed);
|
|
9234
9580
|
}
|
|
9235
9581
|
|
|
9236
|
-
// ../shared/dist/chunk-
|
|
9582
|
+
// ../shared/dist/chunk-KUMPS6RH.mjs
|
|
9583
|
+
var SUPPORTED_APPILOTS_LOCALES = ["pt-BR", "en", "es", "fr"];
|
|
9584
|
+
|
|
9585
|
+
// ../shared/dist/chunk-2GTRKNPJ.mjs
|
|
9586
|
+
var symbols = external_exports.array(external_exports.string().max(240)).max(12);
|
|
9587
|
+
var controlEvidenceSchema = external_exports.object({
|
|
9588
|
+
version: external_exports.literal(1),
|
|
9589
|
+
siteId: external_exports.string().regex(/^[a-f0-9]{20}$/),
|
|
9590
|
+
component: external_exports.string().max(240),
|
|
9591
|
+
icons: symbols,
|
|
9592
|
+
handler: external_exports.string().max(240).optional(),
|
|
9593
|
+
calls: symbols,
|
|
9594
|
+
argumentBindings: symbols,
|
|
9595
|
+
conditions: symbols,
|
|
9596
|
+
nativeConfirmation: external_exports.object({
|
|
9597
|
+
title: external_exports.string().max(240).optional(),
|
|
9598
|
+
destructiveOption: external_exports.boolean()
|
|
9599
|
+
}).optional()
|
|
9600
|
+
});
|
|
9237
9601
|
var locatorSourceSchema = external_exports.enum([
|
|
9238
9602
|
"appilotsId",
|
|
9239
9603
|
"testID",
|
|
@@ -9660,7 +10024,9 @@ var snapshotInputSchema = external_exports.object({
|
|
|
9660
10024
|
inModal: external_exports.boolean().optional()
|
|
9661
10025
|
}).passthrough();
|
|
9662
10026
|
var snapshotButtonSchema = external_exports.object({
|
|
10027
|
+
controlEvidence: controlEvidenceSchema.optional(),
|
|
9663
10028
|
id: boundedString(160).optional(),
|
|
10029
|
+
dispatchable: external_exports.boolean().optional(),
|
|
9664
10030
|
provenance: identityProvenanceSchema.optional(),
|
|
9665
10031
|
/**
|
|
9666
10032
|
* False when the control is mounted but currently OUTSIDE the window —
|
|
@@ -9721,7 +10087,36 @@ var snapshotListSchema = external_exports.object({
|
|
|
9721
10087
|
*/
|
|
9722
10088
|
source: boundedString(40).optional(),
|
|
9723
10089
|
itemCount: external_exports.number().int().optional(),
|
|
10090
|
+
/**
|
|
10091
|
+
* Size of the whole collection when the app declared it, for a list
|
|
10092
|
+
* that is a WINDOW onto more data than it holds.
|
|
10093
|
+
*
|
|
10094
|
+
* `itemCount` is how many rows the list is rendering from and
|
|
10095
|
+
* `visibleItemCount` how many of those are mounted; neither can
|
|
10096
|
+
* express "there are 36 and you are looking at the first 20",
|
|
10097
|
+
* because a paginated list's `data` is the page. Absent means
|
|
10098
|
+
* unknown — never "same as itemCount".
|
|
10099
|
+
*/
|
|
10100
|
+
totalItemCount: external_exports.number().int().optional(),
|
|
9724
10101
|
visibleItemCount: external_exports.number().int().optional(),
|
|
10102
|
+
viewportItemCount: external_exports.number().int().nonnegative().optional(),
|
|
10103
|
+
exploration: external_exports.object({
|
|
10104
|
+
revision: external_exports.number().int().nonnegative(),
|
|
10105
|
+
observedItemCount: external_exports.number().int().min(0).max(5e3),
|
|
10106
|
+
observedRanges: external_exports.array(
|
|
10107
|
+
external_exports.object({
|
|
10108
|
+
start: external_exports.number().int().nonnegative(),
|
|
10109
|
+
end: external_exports.number().int().nonnegative()
|
|
10110
|
+
})
|
|
10111
|
+
).max(32),
|
|
10112
|
+
rangesTruncated: external_exports.boolean(),
|
|
10113
|
+
coverage: external_exports.enum(["partial", "all-loaded"]),
|
|
10114
|
+
pagination: external_exports.enum(["possible", "not-declared"]),
|
|
10115
|
+
scrollSteps: external_exports.number().int().nonnegative(),
|
|
10116
|
+
remainingScrollSteps: external_exports.number().int().nonnegative(),
|
|
10117
|
+
consecutiveNoProgress: external_exports.number().int().nonnegative(),
|
|
10118
|
+
lastScroll: external_exports.enum(["moved", "no-progress", "boundary", "unverified"]).optional()
|
|
10119
|
+
}).optional(),
|
|
9725
10120
|
refreshing: external_exports.boolean().optional(),
|
|
9726
10121
|
empty: external_exports.boolean().optional(),
|
|
9727
10122
|
label: boundedString(300).optional(),
|
|
@@ -9769,6 +10164,7 @@ var snapshotChoiceGroupSchema = external_exports.object({
|
|
|
9769
10164
|
}).passthrough();
|
|
9770
10165
|
var snapshotElementSchema = external_exports.object({
|
|
9771
10166
|
id: boundedString(160).optional(),
|
|
10167
|
+
dispatchable: external_exports.boolean().optional(),
|
|
9772
10168
|
role: boundedString(40).optional(),
|
|
9773
10169
|
label: boundedString(300).optional(),
|
|
9774
10170
|
texts: external_exports.array(boundedString(500)).max(50).optional(),
|
|
@@ -9831,6 +10227,8 @@ var agentSnapshotSchema = external_exports.object({
|
|
|
9831
10227
|
loadingFinished: external_exports.boolean().optional(),
|
|
9832
10228
|
textsAdded: external_exports.number().int().nonnegative().optional(),
|
|
9833
10229
|
textsRemoved: external_exports.number().int().nonnegative().optional(),
|
|
10230
|
+
buttonsAddedIndices: external_exports.array(external_exports.number().int().nonnegative()).max(12).optional(),
|
|
10231
|
+
buttonsRemoved: external_exports.number().int().nonnegative().optional(),
|
|
9834
10232
|
visibleRowsDelta: external_exports.number().int().optional(),
|
|
9835
10233
|
totalRowsDelta: external_exports.number().int().optional(),
|
|
9836
10234
|
fieldsNewlyFilled: external_exports.array(boundedString(160)).max(12).optional(),
|
|
@@ -9856,6 +10254,10 @@ var agentSnapshotSchema = external_exports.object({
|
|
|
9856
10254
|
}).passthrough().optional()
|
|
9857
10255
|
}).passthrough();
|
|
9858
10256
|
var agentContextSchema = external_exports.object({
|
|
10257
|
+
missionProtocol: external_exports.literal(1).optional(),
|
|
10258
|
+
missionId: boundedString(160).optional(),
|
|
10259
|
+
/** Preferred supported device language, reported by the SDK independently of map/UI labels. */
|
|
10260
|
+
deviceLocale: external_exports.enum(SUPPORTED_APPILOTS_LOCALES).optional(),
|
|
9859
10261
|
/**
|
|
9860
10262
|
* Client platform this observation was captured on. Optional and
|
|
9861
10263
|
* additive (see `clientPlatformSchema`) — absent means
|
|
@@ -10106,6 +10508,12 @@ var actionDiagnoseSchema = external_exports.object({
|
|
|
10106
10508
|
requiresUserInput: external_exports.boolean().optional()
|
|
10107
10509
|
});
|
|
10108
10510
|
var actionResultSchema = external_exports.object({
|
|
10511
|
+
nativeConfirmation: external_exports.object({
|
|
10512
|
+
title: external_exports.string().max(300),
|
|
10513
|
+
message: external_exports.string().max(1e3).optional(),
|
|
10514
|
+
buttonLabel: external_exports.string().max(160).optional(),
|
|
10515
|
+
handlerCompleted: external_exports.boolean()
|
|
10516
|
+
}).optional(),
|
|
10109
10517
|
actionId: external_exports.string(),
|
|
10110
10518
|
type: external_exports.string(),
|
|
10111
10519
|
success: external_exports.boolean(),
|
|
@@ -10233,7 +10641,7 @@ external_exports.object({
|
|
|
10233
10641
|
/** null = remove webhook, undefined = leave unchanged. */
|
|
10234
10642
|
budgetWebhookUrl: external_exports.string().url().nullable().optional()
|
|
10235
10643
|
}).strict();
|
|
10236
|
-
var localeSchema = external_exports.enum(
|
|
10644
|
+
var localeSchema = external_exports.enum(SUPPORTED_APPILOTS_LOCALES);
|
|
10237
10645
|
var hexColorSchema = external_exports.string().regex(/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/, {
|
|
10238
10646
|
message: "Must be a hex color like #6366f1"
|
|
10239
10647
|
});
|
|
@@ -11244,9 +11652,22 @@ var MCPGenerator = class _MCPGenerator {
|
|
|
11244
11652
|
const filePath = path2__namespace.default.resolve(outputDir, `mcp-document.${this.options.format}`);
|
|
11245
11653
|
await fs.writeFile(filePath, serialized, "utf-8");
|
|
11246
11654
|
console.log(`[MCPGenerator] Document written to: ${filePath}`);
|
|
11655
|
+
const controlFiles = analyzed.controlEvidenceFiles ?? {};
|
|
11656
|
+
await fs.writeFile(
|
|
11657
|
+
path2__namespace.default.resolve(outputDir, "control-evidence.json"),
|
|
11658
|
+
JSON.stringify({ version: 1, files: controlFiles }, null, 2),
|
|
11659
|
+
"utf-8"
|
|
11660
|
+
);
|
|
11247
11661
|
const checksumFilePath = path2__namespace.default.resolve(outputDir, ".appilots-checksum");
|
|
11248
11662
|
await fs.writeFile(checksumFilePath, checksum, "utf-8");
|
|
11249
11663
|
console.log(`[MCPGenerator] Checksum written to: ${checksumFilePath}`);
|
|
11664
|
+
const evidenceCount = Object.values(controlFiles).reduce(
|
|
11665
|
+
(sum, entries) => sum + entries.length,
|
|
11666
|
+
0
|
|
11667
|
+
);
|
|
11668
|
+
console.log(
|
|
11669
|
+
`[MCPGenerator] Source evidence: ${evidenceCount} icon controls across ${Object.keys(controlFiles).length} files (runtime binding required)`
|
|
11670
|
+
);
|
|
11250
11671
|
console.log("[MCPGenerator] Generation complete!");
|
|
11251
11672
|
return {
|
|
11252
11673
|
document,
|
|
@@ -11312,7 +11733,8 @@ var KNOWN_CONFIG_KEYS = [
|
|
|
11312
11733
|
"navigationExclude",
|
|
11313
11734
|
"platform",
|
|
11314
11735
|
"manifestPath",
|
|
11315
|
-
"eval"
|
|
11736
|
+
"eval",
|
|
11737
|
+
"knowledge"
|
|
11316
11738
|
];
|
|
11317
11739
|
var KEY_ALIASES = {
|
|
11318
11740
|
apiUrl: "serverUrl",
|
|
@@ -11460,7 +11882,8 @@ function saveConfig(dir, config) {
|
|
|
11460
11882
|
navigationExclude: config.navigationExclude || existingConfig?.navigationExclude,
|
|
11461
11883
|
platform: config.platform || existingConfig?.platform,
|
|
11462
11884
|
manifestPath: config.manifestPath || existingConfig?.manifestPath,
|
|
11463
|
-
eval: config.eval || existingConfig?.eval
|
|
11885
|
+
eval: config.eval || existingConfig?.eval,
|
|
11886
|
+
knowledge: config.knowledge || existingConfig?.knowledge
|
|
11464
11887
|
};
|
|
11465
11888
|
try {
|
|
11466
11889
|
fs$1.writeFileSync(configPath, JSON.stringify(mergedConfig, null, 2), "utf-8");
|
|
@@ -11553,6 +11976,19 @@ function validateConfig(config) {
|
|
|
11553
11976
|
if (config.manifestPath !== void 0 && typeof config.manifestPath !== "string") {
|
|
11554
11977
|
errors.push("manifestPath must be a string");
|
|
11555
11978
|
}
|
|
11979
|
+
if (config.knowledge !== void 0) {
|
|
11980
|
+
if (typeof config.knowledge !== "object" || config.knowledge === null || Array.isArray(config.knowledge)) {
|
|
11981
|
+
errors.push("knowledge must be an object");
|
|
11982
|
+
} else {
|
|
11983
|
+
const kc = config.knowledge;
|
|
11984
|
+
for (const field of ["sources", "exclude"]) {
|
|
11985
|
+
const value = kc[field];
|
|
11986
|
+
if (value !== void 0 && (!Array.isArray(value) || !value.every((item) => typeof item === "string"))) {
|
|
11987
|
+
errors.push(`knowledge.${field} must be an array of strings`);
|
|
11988
|
+
}
|
|
11989
|
+
}
|
|
11990
|
+
}
|
|
11991
|
+
}
|
|
11556
11992
|
if (config.eval !== void 0) {
|
|
11557
11993
|
if (typeof config.eval !== "object" || config.eval === null || Array.isArray(config.eval)) {
|
|
11558
11994
|
errors.push("eval must be an object");
|
|
@@ -11829,6 +12265,48 @@ var AppilotsAPIClient = class {
|
|
|
11829
12265
|
};
|
|
11830
12266
|
}
|
|
11831
12267
|
}
|
|
12268
|
+
/**
|
|
12269
|
+
* Syncs knowledge documents with the Appilots backend.
|
|
12270
|
+
*
|
|
12271
|
+
* @param documents Array of documents to sync (filename, base64 content, mimeType, checksum)
|
|
12272
|
+
* @returns KnowledgeSyncResult with counts of uploaded, skipped, and errored docs
|
|
12273
|
+
*/
|
|
12274
|
+
async knowledgeSync(documents) {
|
|
12275
|
+
try {
|
|
12276
|
+
const response = await this.request(`${this.baseUrl}/cli/knowledge/sync`, {
|
|
12277
|
+
method: "POST",
|
|
12278
|
+
headers: {
|
|
12279
|
+
"Content-Type": "application/json",
|
|
12280
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
12281
|
+
},
|
|
12282
|
+
body: JSON.stringify({ documents })
|
|
12283
|
+
});
|
|
12284
|
+
if (!response.ok) {
|
|
12285
|
+
const errorData = await response.json().catch(() => ({}));
|
|
12286
|
+
return {
|
|
12287
|
+
success: false,
|
|
12288
|
+
uploaded: 0,
|
|
12289
|
+
skipped: 0,
|
|
12290
|
+
errors: 0,
|
|
12291
|
+
error: describeApiError(errorData, `HTTP ${response.status}: ${response.statusText}`)
|
|
12292
|
+
};
|
|
12293
|
+
}
|
|
12294
|
+
const json = await response.json();
|
|
12295
|
+
const inner = json.data ?? json;
|
|
12296
|
+
return {
|
|
12297
|
+
success: true,
|
|
12298
|
+
...inner
|
|
12299
|
+
};
|
|
12300
|
+
} catch (error) {
|
|
12301
|
+
return {
|
|
12302
|
+
success: false,
|
|
12303
|
+
uploaded: 0,
|
|
12304
|
+
skipped: 0,
|
|
12305
|
+
errors: 0,
|
|
12306
|
+
error: error instanceof Error ? error.message : "Failed to sync knowledge with Appilots API"
|
|
12307
|
+
};
|
|
12308
|
+
}
|
|
12309
|
+
}
|
|
11832
12310
|
/**
|
|
11833
12311
|
* Checks if the Appilots API server is healthy
|
|
11834
12312
|
*
|
|
@@ -11847,7 +12325,7 @@ var AppilotsAPIClient = class {
|
|
|
11847
12325
|
};
|
|
11848
12326
|
|
|
11849
12327
|
// src/version.ts
|
|
11850
|
-
var CLI_VERSION = "0.
|
|
12328
|
+
var CLI_VERSION = "0.13.0";
|
|
11851
12329
|
|
|
11852
12330
|
exports.AppilotsAPIClient = AppilotsAPIClient;
|
|
11853
12331
|
exports.CLI_VERSION = CLI_VERSION;
|