flutterflow-mcp 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.
- package/README.md +124 -0
- package/build/api/flutterflow.d.ts +11 -0
- package/build/api/flutterflow.js +61 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +54 -0
- package/build/prompts/dev-workflow.d.ts +2 -0
- package/build/prompts/dev-workflow.js +68 -0
- package/build/prompts/generate-page.d.ts +2 -0
- package/build/prompts/generate-page.js +36 -0
- package/build/prompts/inspect-project.d.ts +2 -0
- package/build/prompts/inspect-project.js +30 -0
- package/build/prompts/modify-component.d.ts +2 -0
- package/build/prompts/modify-component.js +39 -0
- package/build/resources/docs.d.ts +2 -0
- package/build/resources/docs.js +76 -0
- package/build/resources/projects.d.ts +3 -0
- package/build/resources/projects.js +60 -0
- package/build/tools/find-component-usages.d.ts +7 -0
- package/build/tools/find-component-usages.js +225 -0
- package/build/tools/find-page-navigations.d.ts +7 -0
- package/build/tools/find-page-navigations.js +228 -0
- package/build/tools/get-component-summary.d.ts +22 -0
- package/build/tools/get-component-summary.js +193 -0
- package/build/tools/get-page-by-name.d.ts +3 -0
- package/build/tools/get-page-by-name.js +56 -0
- package/build/tools/get-page-summary.d.ts +22 -0
- package/build/tools/get-page-summary.js +220 -0
- package/build/tools/get-yaml-docs.d.ts +6 -0
- package/build/tools/get-yaml-docs.js +217 -0
- package/build/tools/get-yaml.d.ts +3 -0
- package/build/tools/get-yaml.js +47 -0
- package/build/tools/list-files.d.ts +3 -0
- package/build/tools/list-files.js +30 -0
- package/build/tools/list-pages.d.ts +25 -0
- package/build/tools/list-pages.js +101 -0
- package/build/tools/list-projects.d.ts +3 -0
- package/build/tools/list-projects.js +19 -0
- package/build/tools/sync-project.d.ts +3 -0
- package/build/tools/sync-project.js +144 -0
- package/build/tools/update-yaml.d.ts +3 -0
- package/build/tools/update-yaml.js +24 -0
- package/build/tools/validate-yaml.d.ts +3 -0
- package/build/tools/validate-yaml.js +22 -0
- package/build/utils/cache.d.ts +48 -0
- package/build/utils/cache.js +162 -0
- package/build/utils/decode-yaml.d.ts +7 -0
- package/build/utils/decode-yaml.js +31 -0
- package/build/utils/page-summary/action-summarizer.d.ts +9 -0
- package/build/utils/page-summary/action-summarizer.js +291 -0
- package/build/utils/page-summary/formatter.d.ts +13 -0
- package/build/utils/page-summary/formatter.js +121 -0
- package/build/utils/page-summary/node-extractor.d.ts +17 -0
- package/build/utils/page-summary/node-extractor.js +207 -0
- package/build/utils/page-summary/tree-walker.d.ts +6 -0
- package/build/utils/page-summary/tree-walker.js +55 -0
- package/build/utils/page-summary/types.d.ts +56 -0
- package/build/utils/page-summary/types.js +4 -0
- package/build/utils/parse-folders.d.ts +9 -0
- package/build/utils/parse-folders.js +29 -0
- package/docs/ff-yaml/00-overview.md +137 -0
- package/docs/ff-yaml/01-project-files.md +513 -0
- package/docs/ff-yaml/02-pages.md +572 -0
- package/docs/ff-yaml/03-components.md +413 -0
- package/docs/ff-yaml/04-widgets/README.md +122 -0
- package/docs/ff-yaml/04-widgets/button.md +444 -0
- package/docs/ff-yaml/04-widgets/container.md +358 -0
- package/docs/ff-yaml/04-widgets/dropdown.md +579 -0
- package/docs/ff-yaml/04-widgets/form.md +256 -0
- package/docs/ff-yaml/04-widgets/image.md +276 -0
- package/docs/ff-yaml/04-widgets/layout.md +355 -0
- package/docs/ff-yaml/04-widgets/misc.md +553 -0
- package/docs/ff-yaml/04-widgets/text-field.md +326 -0
- package/docs/ff-yaml/04-widgets/text.md +302 -0
- package/docs/ff-yaml/05-actions.md +843 -0
- package/docs/ff-yaml/06-variables.md +834 -0
- package/docs/ff-yaml/07-data.md +591 -0
- package/docs/ff-yaml/08-custom-code.md +715 -0
- package/docs/ff-yaml/09-theming.md +592 -0
- package/docs/ff-yaml/10-editing-guide.md +454 -0
- package/docs/ff-yaml/README.md +105 -0
- package/package.json +55 -0
- package/skills/ff-widget-patterns.md +141 -0
- package/skills/ff-yaml-dev.md +58 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a page-widget-tree-outline YAML into a recursive OutlineNode tree.
|
|
3
|
+
*
|
|
4
|
+
* The outline YAML has a `node` root with named slots (body, appBar, header,
|
|
5
|
+
* collapsed, expanded) and `children` arrays. Each entry has a `key` field.
|
|
6
|
+
*/
|
|
7
|
+
import YAML from "yaml";
|
|
8
|
+
/** Named slots that can appear on a node alongside `children`. */
|
|
9
|
+
const SLOT_KEYS = [
|
|
10
|
+
"body",
|
|
11
|
+
"appBar",
|
|
12
|
+
"title",
|
|
13
|
+
"header",
|
|
14
|
+
"collapsed",
|
|
15
|
+
"expanded",
|
|
16
|
+
"floatingActionButton",
|
|
17
|
+
"drawer",
|
|
18
|
+
"endDrawer",
|
|
19
|
+
"bottomNavigationBar",
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Parse a raw outline node (from YAML) into an OutlineNode.
|
|
23
|
+
* `slot` indicates how this node was referenced by its parent.
|
|
24
|
+
*/
|
|
25
|
+
function parseNode(raw, slot) {
|
|
26
|
+
const key = raw.key ?? "unknown";
|
|
27
|
+
const children = [];
|
|
28
|
+
// Named slots
|
|
29
|
+
for (const s of SLOT_KEYS) {
|
|
30
|
+
const child = raw[s];
|
|
31
|
+
if (child && typeof child === "object" && child.key) {
|
|
32
|
+
children.push(parseNode(child, s));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Explicit children array
|
|
36
|
+
const rawChildren = raw.children;
|
|
37
|
+
if (Array.isArray(rawChildren)) {
|
|
38
|
+
for (const child of rawChildren) {
|
|
39
|
+
children.push(parseNode(child, "children"));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return { key, slot, children };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Parse the page-widget-tree-outline YAML string into an OutlineNode tree.
|
|
46
|
+
* Returns the root node (typically the Scaffold).
|
|
47
|
+
*/
|
|
48
|
+
export function parseTreeOutline(yamlContent) {
|
|
49
|
+
const doc = YAML.parse(yamlContent);
|
|
50
|
+
const root = doc.node;
|
|
51
|
+
if (!root || !root.key) {
|
|
52
|
+
throw new Error("Invalid tree outline: missing root node");
|
|
53
|
+
}
|
|
54
|
+
return parseNode(root, "root");
|
|
55
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the page summary tool.
|
|
3
|
+
*/
|
|
4
|
+
/** Summary of a single action in a trigger chain. */
|
|
5
|
+
export interface ActionSummary {
|
|
6
|
+
type: string;
|
|
7
|
+
detail: string;
|
|
8
|
+
}
|
|
9
|
+
/** Summary of a trigger (event handler) on a widget. */
|
|
10
|
+
export interface TriggerSummary {
|
|
11
|
+
trigger: string;
|
|
12
|
+
actions: ActionSummary[];
|
|
13
|
+
}
|
|
14
|
+
/** A node in the summarized widget tree. */
|
|
15
|
+
export interface SummaryNode {
|
|
16
|
+
key: string;
|
|
17
|
+
type: string;
|
|
18
|
+
name: string;
|
|
19
|
+
slot: string;
|
|
20
|
+
detail: string;
|
|
21
|
+
triggers: TriggerSummary[];
|
|
22
|
+
children: SummaryNode[];
|
|
23
|
+
}
|
|
24
|
+
/** Parameter metadata from the top-level page YAML. */
|
|
25
|
+
export interface ParamInfo {
|
|
26
|
+
name: string;
|
|
27
|
+
dataType: string;
|
|
28
|
+
defaultValue?: string;
|
|
29
|
+
}
|
|
30
|
+
/** State field metadata from the top-level page YAML. */
|
|
31
|
+
export interface StateFieldInfo {
|
|
32
|
+
name: string;
|
|
33
|
+
dataType: string;
|
|
34
|
+
defaultValue?: string;
|
|
35
|
+
}
|
|
36
|
+
/** Top-level page metadata. */
|
|
37
|
+
export interface PageMeta {
|
|
38
|
+
pageName: string;
|
|
39
|
+
scaffoldId: string;
|
|
40
|
+
folder: string;
|
|
41
|
+
params: ParamInfo[];
|
|
42
|
+
stateFields: StateFieldInfo[];
|
|
43
|
+
}
|
|
44
|
+
/** Top-level component metadata. */
|
|
45
|
+
export interface ComponentMeta {
|
|
46
|
+
componentName: string;
|
|
47
|
+
containerId: string;
|
|
48
|
+
description: string;
|
|
49
|
+
params: ParamInfo[];
|
|
50
|
+
}
|
|
51
|
+
/** Raw tree node from the widget tree outline YAML. */
|
|
52
|
+
export interface OutlineNode {
|
|
53
|
+
key: string;
|
|
54
|
+
slot: string;
|
|
55
|
+
children: OutlineNode[];
|
|
56
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse the FlutterFlow `folders` YAML file to build a
|
|
3
|
+
* scaffoldId → folderName mapping.
|
|
4
|
+
*
|
|
5
|
+
* The file has two sections:
|
|
6
|
+
* rootFolders: (nested tree of { key, name, children })
|
|
7
|
+
* widgetClassKeyToFolderKey: (flat Scaffold_XXX: folderKey)
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseFolderMapping(foldersYaml: string): Record<string, string>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse the FlutterFlow `folders` YAML file to build a
|
|
3
|
+
* scaffoldId → folderName mapping.
|
|
4
|
+
*
|
|
5
|
+
* The file has two sections:
|
|
6
|
+
* rootFolders: (nested tree of { key, name, children })
|
|
7
|
+
* widgetClassKeyToFolderKey: (flat Scaffold_XXX: folderKey)
|
|
8
|
+
*/
|
|
9
|
+
export function parseFolderMapping(foldersYaml) {
|
|
10
|
+
// 1. Build folderKey → name from the rootFolders tree
|
|
11
|
+
const keyToName = {};
|
|
12
|
+
const keyNameRegex = /key:\s*(\w+)\s*\n\s*name:\s*(.+)/g;
|
|
13
|
+
let match;
|
|
14
|
+
while ((match = keyNameRegex.exec(foldersYaml)) !== null) {
|
|
15
|
+
keyToName[match[1]] = match[2].trim();
|
|
16
|
+
}
|
|
17
|
+
// 2. Build scaffoldId → folderName from widgetClassKeyToFolderKey
|
|
18
|
+
const scaffoldToFolder = {};
|
|
19
|
+
const widgetSection = foldersYaml.split("widgetClassKeyToFolderKey:")[1];
|
|
20
|
+
if (widgetSection) {
|
|
21
|
+
const mappingRegex = /\s+(Scaffold_\w+):\s*(\w+)/g;
|
|
22
|
+
while ((match = mappingRegex.exec(widgetSection)) !== null) {
|
|
23
|
+
const scaffoldId = match[1];
|
|
24
|
+
const folderKey = match[2];
|
|
25
|
+
scaffoldToFolder[scaffoldId] = keyToName[folderKey] || folderKey;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return scaffoldToFolder;
|
|
29
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# FlutterFlow Project Structure
|
|
2
|
+
|
|
3
|
+
Every FlutterFlow project is a collection of YAML files accessed via file keys. This document maps every file type and explains how file keys work.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## File taxonomy
|
|
8
|
+
|
|
9
|
+
| File key pattern | Purpose |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `app-details` | App metadata: name, routing config, initial page, auth pages, theme mode, platform settings |
|
|
12
|
+
| `authentication` | Firebase/Supabase auth configuration, providers, login/signup page refs |
|
|
13
|
+
| `theme` | Typography definitions, color palette, breakpoints, widget defaults |
|
|
14
|
+
| `folders` | Page and component folder organization (scaffold-to-folder mapping) |
|
|
15
|
+
| `app-state` | App-wide persisted state variables (shared across all pages) |
|
|
16
|
+
| `app-constants` | Read-only constants available app-wide |
|
|
17
|
+
| `app-assets` | Uploaded asset references (images, fonts, files) |
|
|
18
|
+
| `nav-bar` | Bottom navigation bar configuration (pages, icons, labels) |
|
|
19
|
+
| `app-bar` | App bar configuration |
|
|
20
|
+
| `permissions` | Permission definitions and role-based access rules |
|
|
21
|
+
| `revenue-cat` | RevenueCat paywall and entitlement configuration |
|
|
22
|
+
| `languages` | Internationalization strings and locale mappings |
|
|
23
|
+
| `page/id-Scaffold_XXX` | Page metadata: name, params, classModel (state fields), route config |
|
|
24
|
+
| `page/id-Scaffold_XXX/page-widget-tree-outline` | Widget tree hierarchy for the page (key refs only, no props) |
|
|
25
|
+
| `page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Widget_YYY` | Individual widget node: type, props, parameterValues, valueKey |
|
|
26
|
+
| `page/.../node/id-Widget_YYY/trigger_actions/id-TRIGGER/action/id-ZZZ` | Action definition attached to a widget trigger |
|
|
27
|
+
| `component/id-Container_XXX` | Component metadata: name, params, classModel |
|
|
28
|
+
| `component/id-Container_XXX/component-widget-tree-outline` | Component widget tree hierarchy |
|
|
29
|
+
| `component/id-Container_XXX/component-widget-tree-outline/node/id-Widget_YYY` | Component widget node |
|
|
30
|
+
| `api-endpoint/id-XXX` | API endpoint: URL, method, headers, body, response schema |
|
|
31
|
+
| `custom-actions/id-XXX` | Custom Dart action: name, params, return type, code |
|
|
32
|
+
| `custom-functions/id-XXX` | Custom Dart function: name, params, return type, code |
|
|
33
|
+
| `custom-widgets/id-XXX` | Custom Flutter widget: name, params, code |
|
|
34
|
+
| `data-structs/id-XXX` | Data structure (struct/class) definition with typed fields |
|
|
35
|
+
| `enums/id-XXX` | Enum definition with named values |
|
|
36
|
+
| `collections/id-XXX` | Firestore collection schema: fields, types, subcollections |
|
|
37
|
+
| `agent/id-XXX` | AI agent configuration |
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## File key patterns
|
|
42
|
+
|
|
43
|
+
File keys are hierarchical paths used with the `get_project_yaml` and `update_project_yaml` MCP tools.
|
|
44
|
+
|
|
45
|
+
### Anatomy of a file key
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
page/id-Scaffold_tjgkshke/page-widget-tree-outline/node/id-Button_7c3kwr61
|
|
49
|
+
| | | | |
|
|
50
|
+
| | | | └─ Widget ID
|
|
51
|
+
| | | └─ node segment (fixed)
|
|
52
|
+
| | └─ Sub-file type
|
|
53
|
+
| └─ Page scaffold ID (prefixed with id-)
|
|
54
|
+
└─ Top-level category
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Depth levels
|
|
58
|
+
|
|
59
|
+
| Level | Example key | What it returns |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| 0 | `app-details` | Entire config file |
|
|
62
|
+
| 1 | `page/id-Scaffold_XXX` | Page metadata only (name, params, state, route) |
|
|
63
|
+
| 2 | `page/id-Scaffold_XXX/page-widget-tree-outline` | Widget tree structure (key refs, no props) |
|
|
64
|
+
| 3 | `page/.../page-widget-tree-outline/node/id-Widget_YYY` | Single widget with all props |
|
|
65
|
+
| 4 | `page/.../node/id-Widget_YYY/trigger_actions/id-ON_TAP/action/id-ZZZ` | Single action definition |
|
|
66
|
+
|
|
67
|
+
### Component keys follow the same pattern
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
component/id-Container_XXX
|
|
71
|
+
component/id-Container_XXX/component-widget-tree-outline
|
|
72
|
+
component/id-Container_XXX/component-widget-tree-outline/node/id-Widget_YYY
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Note: Components use `component-widget-tree-outline` (not `page-widget-tree-outline`).
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Critical rule: Node-level files
|
|
80
|
+
|
|
81
|
+
Widget children **must** be pushed as individual node files. They cannot be embedded inline in the page-level YAML.
|
|
82
|
+
|
|
83
|
+
### Why
|
|
84
|
+
|
|
85
|
+
The FlutterFlow API strips inline children from `page/id-Scaffold_XXX`. The page file only stores metadata (name, params, classModel, route). Widget data lives exclusively in the widget tree outline and node sub-files.
|
|
86
|
+
|
|
87
|
+
### What this means in practice
|
|
88
|
+
|
|
89
|
+
To add or modify widgets, you always push **multiple files** in a single `update_project_yaml` call:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
update_project_yaml(projectId, {
|
|
93
|
+
"page/id-Scaffold_XXX/page-widget-tree-outline": <tree outline YAML>,
|
|
94
|
+
"page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Column_YYY": <column node YAML>,
|
|
95
|
+
"page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Text_ZZZ": <text node YAML>,
|
|
96
|
+
"page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Button_AAA": <button node YAML>
|
|
97
|
+
})
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Tree outline format
|
|
101
|
+
|
|
102
|
+
The widget tree outline defines hierarchy via key references:
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
node:
|
|
106
|
+
key: Scaffold_XXX
|
|
107
|
+
body:
|
|
108
|
+
key: Column_YYY
|
|
109
|
+
children:
|
|
110
|
+
- key: Text_ZZZ
|
|
111
|
+
- key: Button_AAA
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Each `key` referenced here must have a corresponding `node/id-<key>` file pushed alongside it.
|
|
115
|
+
|
|
116
|
+
### Validation shortcut
|
|
117
|
+
|
|
118
|
+
Call `validate_yaml` on the tree outline first. It returns `"File is referenced but is empty"` for any node that is referenced but has no corresponding file -- telling you exactly which node files you need to create.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## ID generation
|
|
123
|
+
|
|
124
|
+
When creating new widgets, pages, or other entities, generate IDs following this pattern:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
<TypePrefix>_<8 lowercase alphanumeric characters>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Examples:
|
|
131
|
+
- `Scaffold_k7m2x9p1`
|
|
132
|
+
- `Column_ab3def45`
|
|
133
|
+
- `Button_zz9wq2r8`
|
|
134
|
+
- `Text_mn4kp7s6`
|
|
135
|
+
- `Container_xy1abc23`
|
|
136
|
+
|
|
137
|
+
The prefix must match the widget/entity type exactly. The suffix should be unique within the project.
|