@appilots/cli 0.1.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.
@@ -0,0 +1,891 @@
1
+ /**
2
+ * Core types for the MCP Generator.
3
+ */
4
+ interface AnalyzerConfig {
5
+ /** Root directory of the React Native project */
6
+ rootDir: string;
7
+ /** Glob patterns for source files */
8
+ include?: string[];
9
+ /** Glob patterns to exclude */
10
+ exclude?: string[];
11
+ /** TypeScript/JavaScript parser options */
12
+ parserPlugins?: string[];
13
+ }
14
+ interface ScreenDescriptor {
15
+ name: string;
16
+ filePath: string;
17
+ title?: string;
18
+ description?: string;
19
+ components: ComponentDescriptor[];
20
+ forms: FormDescriptor[];
21
+ actions: ActionDescriptor[];
22
+ navigationTargets: string[];
23
+ /**
24
+ * Compact operational hints derived from the structured map. These are
25
+ * designed for the agent prompt, not as the canonical source of truth.
26
+ */
27
+ agentHints?: ScreenAgentHints;
28
+ /** Stable, addressable UI targets the agent can interact with. */
29
+ targets?: TargetDescriptor[];
30
+ /** Common multi-step tasks inferred from forms, lists, actions and navigation. */
31
+ flows?: FlowDescriptor[];
32
+ collections?: CollectionDescriptor[];
33
+ /**
34
+ * Dev-defined prompts to surface as chips in the chat when the user lands
35
+ * on this screen. Extracted from `registerScreen({ suggestedPrompts: [...] })`.
36
+ * Persists into the MCP doc so the dashboard can render them and the SDK
37
+ * can fall back to them on first run before any popular history exists.
38
+ */
39
+ suggestedPrompts?: string[];
40
+ /**
41
+ * Permission/safety metadata extracted from a `@appilots-permissions`
42
+ * JSDoc tag on the screen component. Layered under the dashboard
43
+ * configuration at runtime — see `apps/api/src/common/services/permissions.ts`.
44
+ */
45
+ permissions?: ScreenPermissionDescriptor;
46
+ /**
47
+ * Convenience flag for screens marked PII via JSDoc (e.g.
48
+ * `@appilots-pii` or `permissions.isPii: true`). Lifted up so the
49
+ * runtime can apply project-wide PII guards without re-parsing
50
+ * the permissions object.
51
+ */
52
+ isPii?: boolean;
53
+ }
54
+ interface ScreenPermissionDescriptor {
55
+ agentAccess?: 'read' | 'write' | 'none';
56
+ requiresConfirmation?: boolean;
57
+ blockedActions?: string[];
58
+ isPii?: boolean;
59
+ }
60
+ interface NavigationGraph {
61
+ screens: Record<string, NavigationNode>;
62
+ initialScreen: string;
63
+ navigators: NavigatorDescriptor[];
64
+ }
65
+ interface NavigationNode {
66
+ screenName: string;
67
+ navigatorType: 'stack' | 'tab' | 'drawer';
68
+ parentNavigator?: string;
69
+ reachableFrom: string[];
70
+ reachableTo: string[];
71
+ params?: ParamDescriptor[];
72
+ }
73
+ interface NavigatorDescriptor {
74
+ name: string;
75
+ type: 'stack' | 'tab' | 'drawer';
76
+ screens: string[];
77
+ parentNavigator?: string;
78
+ }
79
+ interface ParamDescriptor {
80
+ name: string;
81
+ type: string;
82
+ required: boolean;
83
+ defaultValue?: unknown;
84
+ }
85
+ interface ComponentDescriptor {
86
+ name: string;
87
+ type: 'view' | 'input' | 'button' | 'list' | 'modal' | 'custom';
88
+ props?: Record<string, string>;
89
+ children?: ComponentDescriptor[];
90
+ testID?: string;
91
+ accessibilityLabel?: string;
92
+ }
93
+ interface FormDescriptor {
94
+ id: string;
95
+ fields: FormFieldDescriptor[];
96
+ submitAction?: string;
97
+ validationRules?: Record<string, string>;
98
+ }
99
+ interface FormFieldDescriptor {
100
+ name: string;
101
+ label?: string;
102
+ type: 'text' | 'number' | 'email' | 'phone' | 'select' | 'toggle' | 'date' | 'custom';
103
+ required: boolean;
104
+ placeholder?: string;
105
+ options?: {
106
+ label: string;
107
+ value: string;
108
+ }[];
109
+ defaultValue?: unknown;
110
+ locator?: LocatorDescriptor;
111
+ sourceComponent?: string;
112
+ valueBinding?: string;
113
+ errorBinding?: string;
114
+ }
115
+ interface CollectionDescriptor {
116
+ id: string;
117
+ component: 'FlatList' | 'SectionList' | 'VirtualizedList' | 'FlashList' | 'ScrollView' | string;
118
+ itemType?: string;
119
+ dataSource?: string;
120
+ keyField?: string;
121
+ renderItem?: string;
122
+ displayFields?: string[];
123
+ rowAction?: RowActionDescriptor;
124
+ rowActions?: RowActionDescriptor[];
125
+ identityFields?: string[];
126
+ searchField?: string;
127
+ }
128
+ interface RowActionDescriptor {
129
+ type: 'navigation' | 'custom';
130
+ targetScreen?: string;
131
+ params?: Record<string, string>;
132
+ handler?: string;
133
+ description?: string;
134
+ }
135
+ interface ActionDescriptor {
136
+ id: string;
137
+ type: 'navigation' | 'submit' | 'api_call' | 'state_change' | 'custom';
138
+ label?: string;
139
+ description?: string;
140
+ targetScreen?: string;
141
+ handler?: string;
142
+ locator?: LocatorDescriptor;
143
+ sourceComponent?: string;
144
+ opensModal?: string;
145
+ opensBottomSheet?: string;
146
+ successSignal?: SignalDescriptor;
147
+ failureSignal?: SignalDescriptor;
148
+ nativeConfirmationExpected?: boolean;
149
+ /**
150
+ * BACKLOG 2.2 — Destructive flag.
151
+ * Set to `true` when:
152
+ * - the dev annotated the call site with `@appilots-destructive`,
153
+ * - the handler name matches a destructive verb (delete/destroy/
154
+ * remove/discard/wipe/revoke/etc.),
155
+ * - or a sibling JSX `destructive` prop / `aria-destructive`
156
+ * attribute is true.
157
+ * The runtime auto-injects a `confirm` action before executing
158
+ * any action carrying `destructive: true` (unless the project
159
+ * has whitelisted the action id in `neverConfirmActions`).
160
+ */
161
+ destructive?: boolean;
162
+ /**
163
+ * Structured action semantics for runtimes that need to enforce
164
+ * policy in multilingual apps without parsing labels. Prefer these
165
+ * fields when the app/developer can declare them explicitly.
166
+ */
167
+ effect?: 'read' | 'write' | 'destructive' | string;
168
+ riskLevel?: 'low' | 'medium' | 'high' | string;
169
+ requiresConfirmation?: boolean;
170
+ /**
171
+ * Static-analysis hints derived by the MCP generator from the
172
+ * action's handler body. Used by the SDK to refine waiting and
173
+ * loading heuristics. None of these fields are guessed by the LLM
174
+ * — the generator either has enough evidence to populate the
175
+ * field or leaves it undefined. When all three are undefined, the
176
+ * SDK falls back to the agnostic runtime signals (ActivityIndicator,
177
+ * pressed-button-still-disabled, fingerprint quiescence).
178
+ *
179
+ * See packages/mcp-generator/docs/INFERRED_ACTION_FIELDS.md for the
180
+ * detection rules.
181
+ */
182
+ appilotsInferred?: AppilotsInferredAction;
183
+ }
184
+ interface LocatorDescriptor {
185
+ id?: string;
186
+ appilotsId?: string;
187
+ testID?: string;
188
+ accessibilityLabel?: string;
189
+ label?: string;
190
+ source?: 'appilotsId' | 'testID' | 'accessibilityLabel' | 'label' | 'inferred' | string;
191
+ }
192
+ interface SignalDescriptor {
193
+ type: 'navigation' | 'goBack' | 'toast' | 'modal' | 'inline-error' | 'data-arrival' | 'loading' | 'none' | string;
194
+ target?: string;
195
+ description?: string;
196
+ }
197
+ interface TargetDescriptor {
198
+ id: string;
199
+ role: 'button' | 'submit' | 'input' | 'toggle' | 'select' | 'date' | 'list' | 'row' | 'menuItem' | 'modal' | 'custom' | string;
200
+ label?: string;
201
+ locator?: LocatorDescriptor;
202
+ handler?: string;
203
+ actionId?: string;
204
+ fieldName?: string;
205
+ targetScreen?: string;
206
+ destructive?: boolean;
207
+ requiresConfirmation?: boolean;
208
+ opensModal?: string;
209
+ opensBottomSheet?: string;
210
+ sourceComponent?: string;
211
+ }
212
+ interface FlowDescriptor {
213
+ id: string;
214
+ title: string;
215
+ intent: 'navigate' | 'form_submit' | 'list_action' | 'destructive_action' | 'inline_action' | string;
216
+ steps: FlowStepDescriptor[];
217
+ waitPolicy?: WaitPolicyDescriptor;
218
+ safetyNotes?: string[];
219
+ }
220
+ interface FlowStepDescriptor {
221
+ type: 'navigate' | 'fill' | 'press' | 'select' | 'toggle' | 'wait' | 'confirm' | 'choose-list-item' | string;
222
+ target?: string;
223
+ label?: string;
224
+ description?: string;
225
+ required?: boolean;
226
+ }
227
+ interface WaitPolicyDescriptor {
228
+ expectedOutcome?: AppilotsInferredAction['expectedOutcome'] | 'goBack' | 'toast' | 'modal' | string;
229
+ signals?: SignalDescriptor[];
230
+ maxMs?: number;
231
+ }
232
+ interface ScreenAgentHints {
233
+ primaryGoal?: string;
234
+ commonTasks?: string[];
235
+ preferredTargets?: string[];
236
+ waitPolicy?: WaitPolicyDescriptor;
237
+ safetyNotes?: string[];
238
+ }
239
+ /**
240
+ * Inferred metadata about an action's expected async behavior.
241
+ *
242
+ * Emitted by the MCP generator when it can statically prove (from
243
+ * the handler source) one of the following — never from heuristic
244
+ * guessing on labels or props alone.
245
+ */
246
+ interface AppilotsInferredAction {
247
+ /**
248
+ * True when the handler awaits a Promise (await fetch, axios,
249
+ * useMutation.mutateAsync, etc.) or contains `.then(`/`.catch(`
250
+ * on a returned Promise. Tells the SDK that pressing this button
251
+ * is expected to trigger async work, and the runtime wait window
252
+ * should be more generous (10s instead of 6s).
253
+ */
254
+ isAsyncTrigger?: boolean;
255
+ /**
256
+ * The most-likely observable outcome of the action, when the
257
+ * generator can detect one:
258
+ * - 'navigation' : handler calls navigation.navigate /
259
+ * push / replace AFTER the await. SDK
260
+ * expects a route change.
261
+ * - 'inline-feedback' : handler updates local state (toast,
262
+ * validation, list re-render) without
263
+ * navigating. SDK waits for fingerprint
264
+ * quiescence only.
265
+ * - 'data-arrival' : handler triggers a data load whose
266
+ * result is rendered into the current
267
+ * screen (e.g. fetching list items into
268
+ * a FlatList). SDK waits for the
269
+ * fingerprint to change AND then settle.
270
+ * - 'mixed' : generator detected more than one of
271
+ * the above. SDK uses the most generous
272
+ * (data-arrival) waiting policy.
273
+ * - 'none' : handler is synchronous local state
274
+ * update only. SDK waits minimally.
275
+ */
276
+ expectedOutcome?: 'navigation' | 'inline-feedback' | 'data-arrival' | 'mixed' | 'none';
277
+ /**
278
+ * Names of boolean state variables the generator found being set
279
+ * to `true` immediately before the await and `false` immediately
280
+ * after. Names only — not runtime values; the SDK can't observe
281
+ * React state directly, so this field is currently informational
282
+ * (surfaced in dashboards and used by future tooling). Common
283
+ * shapes: `['isSubmitting']`, `['isLoading', 'isFetching']`.
284
+ */
285
+ loadingStateBindings?: string[];
286
+ }
287
+
288
+ /**
289
+ * Analyzes React Native source files to extract screen definitions,
290
+ * their components, forms, and available actions.
291
+ *
292
+ * The analyzer uses Babel AST to:
293
+ * 1. Extract optional registerScreen() calls (developer-provided metadata)
294
+ * 2. Detect exported component names
295
+ * 3. Find navigation patterns (navigation.navigate calls)
296
+ * 4. Identify form inputs (TextInput, Input components)
297
+ * 5. Extract button/action handlers
298
+ *
299
+ * §1 Strict mode: when `strictScreens` is enabled in config, only files
300
+ * containing a `registerScreen()` call or matching `screenPatterns` globs
301
+ * are included in the output. This avoids components/hooks/utils being
302
+ * listed as screens.
303
+ */
304
+ declare class ScreenAnalyzer {
305
+ private config;
306
+ private verbose;
307
+ /** When true, only files with registerScreen or matching screen patterns are included */
308
+ private strictScreens;
309
+ /** Glob patterns that identify screen files in strict mode */
310
+ private screenPatterns;
311
+ /** §D: Count of screens filtered out in strict mode (available after analyze()) */
312
+ screensFilteredOut: number;
313
+ constructor(config: AnalyzerConfig, options?: {
314
+ strictScreens?: boolean;
315
+ screenPatterns?: string[];
316
+ });
317
+ /** Analyze all screens in the project */
318
+ analyze(): Promise<ScreenDescriptor[]>;
319
+ /** Analyze a single file. Returns descriptor + whether registerScreen was found. */
320
+ analyzeFile(filePath: string): Promise<ScreenDescriptor | null>;
321
+ /**
322
+ * §B: Detect actual presence of registerScreen() call in the AST.
323
+ * This is more reliable than checking for title/description which are optional.
324
+ */
325
+ private detectRegisterScreenCall;
326
+ /**
327
+ * Extract metadata from registerScreen() call
328
+ */
329
+ private extractRegisterScreenMetadata;
330
+ /**
331
+ * Parse the object passed to registerScreen()
332
+ */
333
+ private parseRegisterScreenObject;
334
+ /**
335
+ * Parse actions array from registerScreen
336
+ */
337
+ private parseActionsArray;
338
+ /**
339
+ * Parse a single action object
340
+ */
341
+ private parseActionObject;
342
+ private parseAppilotsInferredObject;
343
+ /**
344
+ * Parse fields array from registerScreen
345
+ */
346
+ private parseFieldsArray;
347
+ /**
348
+ * Parse a single field object
349
+ */
350
+ private parseFieldObject;
351
+ /**
352
+ * Parse options array for select fields
353
+ */
354
+ private parseOptionsArray;
355
+ private mergeForms;
356
+ private findEquivalentField;
357
+ private namedSubmitAction;
358
+ private mergeFieldMetadata;
359
+ private findFormWithSharedFields;
360
+ /**
361
+ * Extract the name of the default exported component
362
+ */
363
+ private extractDefaultComponentName;
364
+ /**
365
+ * Extract navigation targets from navigation.navigate() calls
366
+ */
367
+ private extractNavigationTargets;
368
+ /**
369
+ * Extract form information from JSX
370
+ */
371
+ private extractForms;
372
+ /**
373
+ * Extract field metadata from a TextInput/Input element
374
+ */
375
+ private extractFieldFromInputElement;
376
+ private isWeakInferredFieldName;
377
+ /**
378
+ * Extract component structure from JSX
379
+ */
380
+ private extractComponents;
381
+ /**
382
+ * Infer component type from component name
383
+ */
384
+ private inferComponentType;
385
+ /**
386
+ * Extract actions from button/touchable elements
387
+ */
388
+ private extractActions;
389
+ private normalizeLabel;
390
+ private mergeActionMetadata;
391
+ private enrichActionsFromHandlers;
392
+ private collectButtonHandlersByLabel;
393
+ private collectHandlerInfo;
394
+ private analyzeHandlerFunction;
395
+ /**
396
+ * BACKLOG 2.2 — heuristic destructive detection.
397
+ *
398
+ * Combines several signals:
399
+ * - JSX `destructive` boolean prop (`<Pressable destructive />`)
400
+ * - JSX `aria-destructive` attribute
401
+ * - Handler name contains a generic destructive verb
402
+ * (delete/destroy/remove/discard/wipe/revoke/etc.). `cancel` is intentionally excluded —
403
+ * too many "Cancelar" buttons that just dismiss modals.
404
+ * - testID / id contains a destructive verb
405
+ *
406
+ * Default-allow with explicit opt-out via `@appilots-non-destructive`
407
+ * is more dangerous than the inverse, so we default-deny: the
408
+ * heuristic must hit OR the JSDoc tag must be present.
409
+ */
410
+ private isElementDestructive;
411
+ /**
412
+ * Extract action metadata from a button element
413
+ */
414
+ private extractActionFromButton;
415
+ private extractInlineOnPressMetadata;
416
+ private extractFirstHandlerName;
417
+ private mergeLocator;
418
+ private expressionToBinding;
419
+ private slugifyActionId;
420
+ private extractCollections;
421
+ private collectRenderItemFunctions;
422
+ private jsxExpressionIdentifier;
423
+ private extractKeyField;
424
+ private extractRowAction;
425
+ private extractNavigationParams;
426
+ private extractItemFields;
427
+ private inferItemType;
428
+ private inferIdentityFields;
429
+ private inferSearchField;
430
+ /**
431
+ * Extract literal values from AST nodes
432
+ */
433
+ private extractLiteralValue;
434
+ /**
435
+ * Extract screen name from file path
436
+ * E.g., /src/screens/ItemListScreen.tsx -> ItemListScreen
437
+ */
438
+ private extractScreenName;
439
+ }
440
+
441
+ /**
442
+ * Analyzes React Navigation configuration to build a navigation graph.
443
+ */
444
+ declare class NavigationAnalyzer {
445
+ private config;
446
+ /** Extra glob patterns for navigation file discovery (added to defaults) */
447
+ private navigationInclude;
448
+ /** Extra glob patterns to exclude from navigation analysis */
449
+ private navigationExclude;
450
+ constructor(config: AnalyzerConfig, options?: {
451
+ navigationInclude?: string[];
452
+ navigationExclude?: string[];
453
+ });
454
+ /** Build the full navigation graph */
455
+ analyze(): Promise<NavigationGraph>;
456
+ /** Find all navigation-related files */
457
+ private findNavigationFiles;
458
+ /** Parse navigator definitions from a file */
459
+ private parseNavigators;
460
+ /** Extract screens from a navigator JSX element */
461
+ private extractScreensFromNavigator;
462
+ /** Extract string attribute value from JSX attributes */
463
+ private extractAttributeValue;
464
+ /** Parse TypeScript type exports (ParamList types) */
465
+ private parseParamTypes;
466
+ /** Extract param entries from a TypeScript type literal */
467
+ private extractParamListEntries;
468
+ /** Extract param descriptors from a TypeScript type */
469
+ private extractParamsFromType;
470
+ /** Convert TypeScript type annotation to string */
471
+ private typeToString;
472
+ /** Infer navigator type from type name */
473
+ private inferTypeFromName;
474
+ /** Attach parsed type params to navigator screens */
475
+ private attachParamsToNavigators;
476
+ /** Build the complete navigation graph */
477
+ private buildNavigationGraph;
478
+ }
479
+
480
+ /**
481
+ * Analyzes React Native components to extract their semantic meaning,
482
+ * props, and interaction points.
483
+ */
484
+ declare class ComponentAnalyzer {
485
+ private config;
486
+ constructor(config: AnalyzerConfig);
487
+ /** Analyze components in a file */
488
+ analyzeFile(filePath: string): Promise<ComponentDescriptor[]>;
489
+ private extractComponentFromJSXElement;
490
+ private getElementName;
491
+ private determineComponentType;
492
+ private extractProps;
493
+ private extractAccessibilityProps;
494
+ private extractChildren;
495
+ }
496
+
497
+ /**
498
+ * Analyzes form structures in React Native screens, extracting
499
+ * field definitions, validation rules, and submit actions.
500
+ */
501
+ declare class FormAnalyzer {
502
+ private config;
503
+ private stateVariables;
504
+ private inputElements;
505
+ private submitButtons;
506
+ constructor(config: AnalyzerConfig);
507
+ /** Analyze forms in a file */
508
+ analyzeFile(filePath: string): Promise<FormDescriptor[]>;
509
+ private extractStateVariables;
510
+ private extractFormElements;
511
+ private extractInputInfo;
512
+ private extractButtonInfo;
513
+ private extractAttributeValue;
514
+ private getElementName;
515
+ private extractValidationRules;
516
+ private extractRuleFromCondition;
517
+ private buildForms;
518
+ private inferFieldType;
519
+ private isFieldRequired;
520
+ }
521
+
522
+ interface MCPGeneratorOptions {
523
+ /** Output format (only 'json' supported currently) */
524
+ format: 'json';
525
+ /** Output directory */
526
+ outputDir: string;
527
+ /** Whether to include source file paths */
528
+ includeSourcePaths?: boolean;
529
+ /** Whether to generate a single file or per-screen files */
530
+ splitOutput?: boolean;
531
+ /** MCP document version */
532
+ version?: string;
533
+ }
534
+ interface MCPDocument {
535
+ version: string;
536
+ generatedAt: string;
537
+ projectName: string;
538
+ screens: ScreenDescriptor[];
539
+ navigation: NavigationGraph;
540
+ metadata: MCPMetadata;
541
+ }
542
+ interface MCPMetadata {
543
+ generatorVersion: string;
544
+ /**
545
+ * Host app version read from the project's package.json. Lets the
546
+ * backend match the MCP document to the app build that generated it
547
+ * (B.4 — OTA fleets run several app versions at once).
548
+ */
549
+ appVersion?: string;
550
+ totalScreens: number;
551
+ totalForms: number;
552
+ totalActions: number;
553
+ /** Number of source files matched by glob (before screen filtering) */
554
+ analyzedFiles: number;
555
+ /** Number of files excluded by strict screen filtering (only set when strictScreens is on) */
556
+ screensFilteredOut?: number;
557
+ }
558
+ interface MCPOutput {
559
+ document: MCPDocument;
560
+ filePath: string;
561
+ format: 'json';
562
+ checksum: string;
563
+ }
564
+
565
+ /**
566
+ * Main generator that orchestrates analyzers and produces MCP documents.
567
+ *
568
+ * @example
569
+ * ```ts
570
+ * const generator = new MCPGenerator({
571
+ * rootDir: './my-rn-app',
572
+ * outputDir: '.appilots',
573
+ * format: 'json',
574
+ * });
575
+ *
576
+ * const output = await generator.generate();
577
+ * console.log(`Generated MCP at: ${output.filePath}`);
578
+ * ```
579
+ */
580
+ interface MCPGeneratorConfig {
581
+ rootDir: string;
582
+ outputDir?: string;
583
+ format?: 'json';
584
+ version?: string;
585
+ includeSourcePaths?: boolean;
586
+ splitOutput?: boolean;
587
+ /** §1: Only include files with registerScreen() or matching screen patterns */
588
+ strictScreens?: boolean;
589
+ /** §1: Custom glob patterns for screen file detection */
590
+ screenPatterns?: string[];
591
+ /** §5: Additional navigation file patterns (added to defaults) */
592
+ navigationInclude?: string[];
593
+ /** §5: Exclude patterns for navigation analysis */
594
+ navigationExclude?: string[];
595
+ /** Source include patterns */
596
+ include?: string[];
597
+ /** Source exclude patterns */
598
+ exclude?: string[];
599
+ }
600
+ declare class MCPGenerator {
601
+ private analyzerConfig;
602
+ private options;
603
+ private generatorConfig;
604
+ constructor(config: MCPGeneratorConfig);
605
+ /** Generate MCP documents from the project */
606
+ generate(): Promise<MCPOutput>;
607
+ /**
608
+ * Read the previously stored checksum from disk.
609
+ * Returns null if no checksum file exists (first run).
610
+ *
611
+ * §4: This replaces the incomplete `hasChanged` static method.
612
+ * To detect actual changes, compare this value with `output.checksum`
613
+ * after calling `generate()`.
614
+ */
615
+ static readPreviousChecksum(outputDir: string): Promise<string | null>;
616
+ /**
617
+ * Calculate SHA-256 checksum of content
618
+ */
619
+ private calculateChecksum;
620
+ private mergeForm;
621
+ private findEquivalentField;
622
+ private mergeField;
623
+ private namedSubmitAction;
624
+ private isWeakInferredFieldName;
625
+ private findFormWithSharedFields;
626
+ /**
627
+ * Get project name and version from package.json in rootDir
628
+ */
629
+ private getProjectInfo;
630
+ }
631
+
632
+ /**
633
+ * Appilots configuration interface
634
+ */
635
+ interface AppilotsConfig {
636
+ /** API key for authenticating with Appilots backend */
637
+ apiKey: string;
638
+ /**
639
+ * Project ID on Appilots dashboard. Optional at load time — the API key
640
+ * already identifies the project server-side (env-only CI workflows run
641
+ * without a .appilotsrc), so commands must not assume it is present.
642
+ */
643
+ projectId?: string;
644
+ /** Server URL for Appilots API */
645
+ serverUrl: string;
646
+ /** Output directory for generated files */
647
+ outputDir?: string;
648
+ /** Glob patterns to include in analysis */
649
+ include?: string[];
650
+ /** Glob patterns to exclude from analysis */
651
+ exclude?: string[];
652
+ /** Automatically activate generated MCP on sync */
653
+ autoActivate?: boolean;
654
+ /**
655
+ * Strict screen filtering (§1).
656
+ * When true, only files with registerScreen() calls or matching
657
+ * screenPatterns are included as screens in the MCP document.
658
+ * Default: true (exclude components/hooks/config files from the MCP screen map)
659
+ */
660
+ strictScreens?: boolean;
661
+ /**
662
+ * Glob patterns that identify screen files (used with strictScreens).
663
+ * Default: ['**\/*Screen.{ts,tsx}', '**\/screens/**\/*.{ts,tsx}']
664
+ */
665
+ screenPatterns?: string[];
666
+ /**
667
+ * Additional glob patterns for navigation file discovery (§5).
668
+ * These are ADDED to the default patterns, not replacing them.
669
+ */
670
+ navigationInclude?: string[];
671
+ /**
672
+ * Glob patterns to exclude from navigation analysis (§5).
673
+ */
674
+ navigationExclude?: string[];
675
+ /** `appilots eval` settings — see docs: Testing your agent between releases. */
676
+ eval?: EvalConfig;
677
+ }
678
+ interface EvalConfig {
679
+ /** Directory of `*.json` scenario files. Default: `<outputDir>/scenarios`. */
680
+ scenariosDir?: string;
681
+ /** Committed baseline file. Default: `<outputDir>/eval-baseline.json`. */
682
+ baselinePath?: string;
683
+ /** Minimum fraction of scenarios that must pass (0-1). Default: 0.95. */
684
+ minPassRate?: number;
685
+ /** Max fractional token increase vs baseline before it's flagged as a
686
+ * regression on an otherwise-passing scenario. Default: 0.25 (+25%). */
687
+ maxTokenRegression?: number;
688
+ }
689
+ /**
690
+ * Validation result type
691
+ */
692
+ interface ValidationResult {
693
+ valid: boolean;
694
+ errors: string[];
695
+ }
696
+ /**
697
+ * Environment overrides recognized by the CLI. Precedence when loading:
698
+ * command-line flags (applied by each command) > env vars > .appilotsrc.
699
+ */
700
+ interface EnvOverrides {
701
+ apiKey?: string;
702
+ projectId?: string;
703
+ serverUrl?: string;
704
+ }
705
+ /**
706
+ * Reads APPILOTS_* environment variables, treating blank values as unset.
707
+ */
708
+ declare function getEnvOverrides(env?: NodeJS.ProcessEnv): EnvOverrides;
709
+ /**
710
+ * Loads configuration from the nearest .appilotsrc merged with APPILOTS_*
711
+ * environment variables (env wins). Works without a .appilotsrc when
712
+ * APPILOTS_API_KEY is set, so CI can run `appilots sync` with env vars only.
713
+ *
714
+ * @returns AppilotsConfig if a file or APPILOTS_API_KEY exists, null otherwise
715
+ * @throws when the file is unparseable or the merged config fails validation
716
+ */
717
+ declare function loadConfig(): AppilotsConfig | null;
718
+ /**
719
+ * Saves configuration to .appilotsrc in the given directory
720
+ *
721
+ * @param dir Directory to write .appilotsrc to
722
+ * @param config Partial config to merge with defaults
723
+ */
724
+ declare function saveConfig(dir: string, config: Partial<AppilotsConfig>): void;
725
+ /**
726
+ * Finds and returns the path to the nearest .appilotsrc file by walking up
727
+ * the directory tree from cwd. Follows the same logic as .npmrc lookup.
728
+ *
729
+ * @returns Path to .appilotsrc if found, null otherwise
730
+ */
731
+ declare function getConfigPath(): string | null;
732
+ /**
733
+ * Validates an Appilots configuration object for required fields and types
734
+ *
735
+ * @param config Configuration object to validate
736
+ * @returns ValidationResult with valid flag and array of error messages
737
+ */
738
+ declare function validateConfig(config: any): ValidationResult;
739
+
740
+ /**
741
+ * Metadata lint (OKR-005 KR4) — every mutating action registered in the
742
+ * MCP document should declare `effect` and `riskLevel` so the runtime can
743
+ * enforce safety policy without parsing labels. The generator extracts
744
+ * these fields when declared in registerScreen(); this lint surfaces the
745
+ * ones that were not, instead of letting them pass silently.
746
+ */
747
+ interface MetadataLintWarning {
748
+ screen: string;
749
+ actionId: string;
750
+ actionType: ActionDescriptor['type'];
751
+ missing: ('effect' | 'riskLevel')[];
752
+ reason: string;
753
+ }
754
+ /**
755
+ * Scans every screen action and returns one warning per mutating action
756
+ * that is missing `effect` and/or `riskLevel`.
757
+ */
758
+ declare function lintActionMetadata(document: MCPDocument): MetadataLintWarning[];
759
+ /**
760
+ * Formats lint warnings for terminal output: one line per action plus an
761
+ * aggregate line, e.g.
762
+ * VehicleDetails.deleteVehicle (submit): missing effect, riskLevel
763
+ */
764
+ declare function formatMetadataWarnings(warnings: MetadataLintWarning[]): string[];
765
+
766
+ /**
767
+ * HTTP client for communicating with the Appilots API backend
768
+ */
769
+ /**
770
+ * Result from a sync operation
771
+ */
772
+ interface SyncResult {
773
+ success: boolean;
774
+ unchanged: boolean;
775
+ id?: string;
776
+ checksum?: string;
777
+ screensCount?: number;
778
+ formsCount?: number;
779
+ actionsCount?: number;
780
+ error?: string;
781
+ }
782
+ /**
783
+ * One eval scenario as sent to `POST /cli/eval/run`. Shape mirrors the
784
+ * server's `evalScenarioRequestSchema` — kept as a plain interface here
785
+ * (no @appilots/shared import) since this package publishes standalone.
786
+ */
787
+ interface EvalScenarioRequest {
788
+ id: string;
789
+ screen?: string;
790
+ observation?: unknown;
791
+ prompt: string;
792
+ modelOverride?: string;
793
+ }
794
+ interface EvalScenarioResult {
795
+ id: string;
796
+ content: string;
797
+ actions: Array<{
798
+ id: string;
799
+ type: string;
800
+ payload: Record<string, unknown>;
801
+ }>;
802
+ totalTokens: number;
803
+ totalCostUsd: number;
804
+ totalLatencyMs: number;
805
+ modelUsed: string;
806
+ }
807
+ /**
808
+ * Result from an eval run
809
+ */
810
+ interface EvalRunResult {
811
+ results?: EvalScenarioResult[];
812
+ error?: string;
813
+ }
814
+ /**
815
+ * Result from a status query
816
+ */
817
+ interface StatusResult {
818
+ project?: {
819
+ id: string;
820
+ name: string;
821
+ };
822
+ activeMcp?: {
823
+ id: string;
824
+ version: string;
825
+ screensCount: number;
826
+ formsCount: number;
827
+ actionsCount: number;
828
+ };
829
+ error?: string;
830
+ }
831
+ /**
832
+ * Appilots API client configuration
833
+ */
834
+ interface APIClientConfig {
835
+ serverUrl: string;
836
+ apiKey: string;
837
+ /** Per-request timeout in ms (default 30s) */
838
+ timeoutMs?: number;
839
+ /** Retries on network errors / 5xx (default 2) */
840
+ maxRetries?: number;
841
+ }
842
+ /**
843
+ * HTTP client for communicating with Appilots API
844
+ */
845
+ declare class AppilotsAPIClient {
846
+ private serverUrl;
847
+ private apiKey;
848
+ private timeoutMs;
849
+ private maxRetries;
850
+ constructor(config: APIClientConfig);
851
+ /**
852
+ * fetch with a hard timeout and exponential-backoff retries. Retries
853
+ * only on network failures and 5xx responses — 4xx are the caller's
854
+ * problem and retrying them would just spam the server.
855
+ */
856
+ private request;
857
+ /**
858
+ * Syncs content with the Appilots backend
859
+ *
860
+ * @param content The MCP content object to sync
861
+ * @param version Version string for the content
862
+ * @param appVersion Host app version (package.json) — sent as
863
+ * X-App-Version so the backend can associate the MCP
864
+ * document with the app build that produced it
865
+ * @returns SyncResult with success status and metadata
866
+ */
867
+ sync(content: object, version: string, appVersion?: string): Promise<SyncResult>;
868
+ /**
869
+ * Gets the status of the Appilots project and active MCP
870
+ *
871
+ * @returns StatusResult with project and active MCP information
872
+ */
873
+ status(): Promise<StatusResult>;
874
+ /**
875
+ * Runs a batch of eval scenarios against the project's MCP document in
876
+ * decision/dry-run mode — no side effects, same relay path as the
877
+ * dashboard's sandbox, authenticated with this client's API key.
878
+ *
879
+ * @param scenarios Scenarios to run, capped server-side at
880
+ * EVAL_MAX_SCENARIOS_PER_RUN (currently 20) as a cost guard.
881
+ */
882
+ evalRun(scenarios: EvalScenarioRequest[]): Promise<EvalRunResult>;
883
+ /**
884
+ * Checks if the Appilots API server is healthy
885
+ *
886
+ * @returns true if server is healthy, false otherwise
887
+ */
888
+ health(): Promise<boolean>;
889
+ }
890
+
891
+ export { type ActionDescriptor, type AnalyzerConfig, AppilotsAPIClient, type AppilotsConfig, ComponentAnalyzer, type ComponentDescriptor, type EnvOverrides, type FlowDescriptor, type FlowStepDescriptor, FormAnalyzer, type FormDescriptor, type FormFieldDescriptor, type LocatorDescriptor, type MCPDocument, MCPGenerator, type MCPGeneratorConfig, type MCPGeneratorOptions, type MCPOutput, type MetadataLintWarning, NavigationAnalyzer, type NavigationGraph, type NavigationNode, type NavigatorDescriptor, type ParamDescriptor, type ScreenAgentHints, ScreenAnalyzer, type ScreenDescriptor, type SignalDescriptor, type StatusResult, type SyncResult, type TargetDescriptor, type WaitPolicyDescriptor, formatMetadataWarnings, getConfigPath, getEnvOverrides, lintActionMetadata, loadConfig, saveConfig, validateConfig };