@shaykec/app-agent 1.0.10 → 1.0.11
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/.cursor/skills/web-analyzer/SKILL.md +310 -0
- package/.cursor/skills/web-crawler/SKILL.md +252 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +32 -10
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +6 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -1
- package/dist/config.js.map +1 -1
- package/dist/index.js +79 -9
- package/dist/index.js.map +1 -1
- package/dist/prompt-builder.d.ts +6 -0
- package/dist/prompt-builder.d.ts.map +1 -1
- package/dist/prompt-builder.js +56 -0
- package/dist/prompt-builder.js.map +1 -1
- package/dist/validator.d.ts +1 -1
- package/dist/validator.d.ts.map +1 -1
- package/package.json +1 -3
- package/prompts/web-clone-agent-prompt.md +179 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Web Analyzer Skill
|
|
2
|
+
|
|
3
|
+
Analyze the web crawl report and website screenshots to produce a structured app specification (web-to-app manifest) that drives the rest of the build pipeline.
|
|
4
|
+
|
|
5
|
+
## Inputs
|
|
6
|
+
|
|
7
|
+
- **Web crawl report**: `output/{app-name}/reports/02-web-crawl-report.md`
|
|
8
|
+
- **Website screenshots**: `output/{app-name}/web-crawl/screenshots/*.png` (passed as image attachments)
|
|
9
|
+
- **Focus directive** (optional): User's description of what to prioritize
|
|
10
|
+
- **Platform**: ios, android, or react-native
|
|
11
|
+
|
|
12
|
+
## Process
|
|
13
|
+
|
|
14
|
+
### 1. Read the Crawl Report
|
|
15
|
+
|
|
16
|
+
Read `reports/02-web-crawl-report.md` to understand:
|
|
17
|
+
- Site map (all pages discovered)
|
|
18
|
+
- Navigation structure
|
|
19
|
+
- Brand palette (colors, typography, layout patterns)
|
|
20
|
+
- Content model (entities, fields, categories)
|
|
21
|
+
- Functionality inventory (search, forms, filters, auth, CRUD)
|
|
22
|
+
|
|
23
|
+
### 2. View the Screenshots
|
|
24
|
+
|
|
25
|
+
Examine all saved screenshots to visually verify and refine:
|
|
26
|
+
- Color accuracy (screenshots show the actual rendered colors)
|
|
27
|
+
- Layout patterns (card grids, list styles, hero sections, spacing)
|
|
28
|
+
- Visual hierarchy (what's prominent, what's secondary)
|
|
29
|
+
- Overall brand "feel" (modern, classic, playful, corporate, etc.)
|
|
30
|
+
- Typography style (even if exact fonts can't be extracted)
|
|
31
|
+
|
|
32
|
+
### 3. Map Pages to Mobile Screens
|
|
33
|
+
|
|
34
|
+
Apply these mapping rules:
|
|
35
|
+
|
|
36
|
+
| Web Pattern | Mobile Pattern |
|
|
37
|
+
|-------------|---------------|
|
|
38
|
+
| Home/landing page | Home tab (main tab) |
|
|
39
|
+
| List/catalog page (products, articles) | List screen (scrollable, searchable) |
|
|
40
|
+
| Detail page (product detail, article) | Detail screen (push navigation) |
|
|
41
|
+
| Search page / search results | Search/Explore tab or search overlay |
|
|
42
|
+
| Category/filter page | Filter sheet or Explore tab |
|
|
43
|
+
| User profile / account | Profile tab |
|
|
44
|
+
| Favorites / wishlist / saved | Favorites tab |
|
|
45
|
+
| Contact / about / info | Info section in Profile or separate screen |
|
|
46
|
+
| Form (create, submit) | Create/Compose screen (modal or push) |
|
|
47
|
+
| Cart / checkout | Cart tab or sheet (if e-commerce) |
|
|
48
|
+
| Settings / preferences | Settings screen (in Profile tab) |
|
|
49
|
+
|
|
50
|
+
**Tab Bar Strategy** (max 4-5 tabs):
|
|
51
|
+
1. **Home** — always the first tab (mirrors home page)
|
|
52
|
+
2. **Explore/Search** — if the site has search, catalog, or browse functionality
|
|
53
|
+
3. **Favorites** — if the site has save/wishlist/bookmark functionality
|
|
54
|
+
4. **Profile** — if the site has user accounts, settings, or contact info
|
|
55
|
+
5. **Extra tab** — only if the site has a major section that doesn't fit above (e.g., Cart for e-commerce)
|
|
56
|
+
|
|
57
|
+
### 4. Map Navigation
|
|
58
|
+
|
|
59
|
+
| Web Navigation | Mobile Navigation |
|
|
60
|
+
|----------------|-------------------|
|
|
61
|
+
| Top nav bar links | Tab bar items |
|
|
62
|
+
| Sub-menu / dropdown | Navigation stack (push screens) |
|
|
63
|
+
| Breadcrumbs | Back button (automatic in nav stack) |
|
|
64
|
+
| Pagination | Infinite scroll or load-more |
|
|
65
|
+
| Modal / popup | Sheet or modal presentation |
|
|
66
|
+
| Sidebar / drawer | Not recommended — flatten into tabs |
|
|
67
|
+
|
|
68
|
+
### 5. Extract Brand Tokens
|
|
69
|
+
|
|
70
|
+
From the crawl report and screenshots, produce exact brand tokens:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
Primary Color: #XXXXXX (main CTA / button color)
|
|
74
|
+
Secondary Color: #XXXXXX (accent / highlight color)
|
|
75
|
+
Background: #XXXXXX (page background)
|
|
76
|
+
Surface: #XXXXXX (card / section background)
|
|
77
|
+
Text Primary: #XXXXXX (headings, main text)
|
|
78
|
+
Text Secondary: #XXXXXX (captions, secondary text)
|
|
79
|
+
Error: #FF3B30 (default if not visible on site)
|
|
80
|
+
Success: #34C759 (default if not visible on site)
|
|
81
|
+
|
|
82
|
+
Corner Radius: {small/medium/large} → {4/8/12}pt
|
|
83
|
+
Shadow Style: {none/subtle/prominent}
|
|
84
|
+
Spacing Scale: {tight/medium/generous}
|
|
85
|
+
|
|
86
|
+
Typography Style: {sans-serif/serif/rounded} → map to system fonts
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 6. Define Data Model
|
|
90
|
+
|
|
91
|
+
From the content model in the crawl report:
|
|
92
|
+
- Map each entity to a Swift struct / Kotlin data class / TypeScript interface
|
|
93
|
+
- Define fields with types (String, Int, Double, URL, Date, Bool)
|
|
94
|
+
- Identify primary entity (the main "item" the app displays)
|
|
95
|
+
- Identify relationships (entity A has many entity B)
|
|
96
|
+
|
|
97
|
+
### 7. Generate Content Brief
|
|
98
|
+
|
|
99
|
+
Adapt website copy for mobile:
|
|
100
|
+
- App display name (from website name/logo)
|
|
101
|
+
- Tab labels (short, 1-2 words)
|
|
102
|
+
- Screen titles
|
|
103
|
+
- Empty state messages
|
|
104
|
+
- Search placeholder text
|
|
105
|
+
- CTA button labels
|
|
106
|
+
- Onboarding text (if the site has a value proposition)
|
|
107
|
+
- Category names
|
|
108
|
+
|
|
109
|
+
### 8. Decide: Template or Scratch
|
|
110
|
+
|
|
111
|
+
Compare the web-to-app mapping against available templates in CATALOG.md:
|
|
112
|
+
- If a template matches 70%+ of the required screens/features → use template mode
|
|
113
|
+
- If no template is a good fit → recommend scratch mode
|
|
114
|
+
- Always prefer template mode for reliability
|
|
115
|
+
|
|
116
|
+
### 9. Generate Parallel Batches
|
|
117
|
+
|
|
118
|
+
Divide screens into 2-3 batches for parallel customization and testing:
|
|
119
|
+
- **Batch 1**: Home + Explore/Search screens
|
|
120
|
+
- **Batch 2**: Detail + Create/Form screens
|
|
121
|
+
- **Batch 3**: Profile + Settings + Favorites screens
|
|
122
|
+
|
|
123
|
+
## Output
|
|
124
|
+
|
|
125
|
+
Write `output/{app-name}/reports/03-web-to-app-manifest.md` with this structure:
|
|
126
|
+
|
|
127
|
+
```markdown
|
|
128
|
+
# Web-to-App Manifest
|
|
129
|
+
|
|
130
|
+
## Source
|
|
131
|
+
- **URL**: {url}
|
|
132
|
+
- **App Name**: {derived from website name}
|
|
133
|
+
- **Bundle ID**: com.appship.{appname}
|
|
134
|
+
- **Platform**: {platform}
|
|
135
|
+
- **Build Mode**: {template/scratch}
|
|
136
|
+
- **Selected Template**: {template name or "N/A for scratch mode"}
|
|
137
|
+
|
|
138
|
+
## Screen Mapping
|
|
139
|
+
|
|
140
|
+
| # | Web Page | Mobile Screen | Tab | Navigation |
|
|
141
|
+
|---|----------|--------------|-----|------------|
|
|
142
|
+
| 1 | Home | HomeView | Home | Root |
|
|
143
|
+
| 2 | Products | ProductListView | Explore | Root |
|
|
144
|
+
| 3 | Product Detail | ProductDetailView | — | Push from ProductList |
|
|
145
|
+
| 4 | Search Results | SearchView | Explore | Overlay |
|
|
146
|
+
| 5 | Cart | CartView | Cart | Root |
|
|
147
|
+
| 6 | Profile | ProfileView | Profile | Root |
|
|
148
|
+
|
|
149
|
+
## Tab Bar
|
|
150
|
+
|
|
151
|
+
| # | Tab | Label | Icon (SF Symbol / Material) | Root Screen |
|
|
152
|
+
|---|-----|-------|---------------------------|-------------|
|
|
153
|
+
| 1 | Home | Home | house.fill / home | HomeView |
|
|
154
|
+
| 2 | Explore | Explore | magnifyingglass / search | ProductListView |
|
|
155
|
+
| 3 | Favorites | Saved | heart.fill / favorite | FavoritesView |
|
|
156
|
+
| 4 | Profile | Profile | person.fill / person | ProfileView |
|
|
157
|
+
|
|
158
|
+
## Brand Tokens
|
|
159
|
+
|
|
160
|
+
### Colors (Light Mode)
|
|
161
|
+
- primary: #{hex}
|
|
162
|
+
- secondary: #{hex}
|
|
163
|
+
- background: #{hex}
|
|
164
|
+
- surface: #{hex}
|
|
165
|
+
- textPrimary: #{hex}
|
|
166
|
+
- textSecondary: #{hex}
|
|
167
|
+
- error: #{hex}
|
|
168
|
+
- success: #{hex}
|
|
169
|
+
|
|
170
|
+
### Colors (Dark Mode)
|
|
171
|
+
- primary: #{hex} (lightened for dark bg)
|
|
172
|
+
- secondary: #{hex}
|
|
173
|
+
- background: #1C1C1E
|
|
174
|
+
- surface: #2C2C2E
|
|
175
|
+
- textPrimary: #FFFFFF
|
|
176
|
+
- textSecondary: #8E8E93
|
|
177
|
+
|
|
178
|
+
### Layout
|
|
179
|
+
- cornerRadius: {value}
|
|
180
|
+
- shadowStyle: {none/subtle/prominent}
|
|
181
|
+
- spacingScale: {tight/medium/generous}
|
|
182
|
+
|
|
183
|
+
### Typography
|
|
184
|
+
- fontStyle: {sans-serif/serif/rounded}
|
|
185
|
+
- iOS: {system font recommendation}
|
|
186
|
+
- Android: {font recommendation}
|
|
187
|
+
|
|
188
|
+
## Data Model
|
|
189
|
+
|
|
190
|
+
### {PrimaryEntity} (e.g., Product)
|
|
191
|
+
```
|
|
192
|
+
id: String (UUID)
|
|
193
|
+
name: String
|
|
194
|
+
description: String
|
|
195
|
+
imageUrl: URL
|
|
196
|
+
price: Double (optional)
|
|
197
|
+
category: String
|
|
198
|
+
rating: Double (optional)
|
|
199
|
+
isFavorite: Bool
|
|
200
|
+
createdAt: Date
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Categories
|
|
204
|
+
- {Category 1}
|
|
205
|
+
- {Category 2}
|
|
206
|
+
- ...
|
|
207
|
+
|
|
208
|
+
## Content Brief
|
|
209
|
+
|
|
210
|
+
### App Name & Branding
|
|
211
|
+
- **Display Name**: {name}
|
|
212
|
+
- **Tagline**: {from website}
|
|
213
|
+
|
|
214
|
+
### Tab Labels
|
|
215
|
+
- Home, Explore, Saved, Profile
|
|
216
|
+
|
|
217
|
+
### Screen Titles
|
|
218
|
+
- Home: "{title}"
|
|
219
|
+
- Explore: "{title}"
|
|
220
|
+
- ...
|
|
221
|
+
|
|
222
|
+
### Empty States
|
|
223
|
+
- No items: "{message}"
|
|
224
|
+
- No favorites: "{message}"
|
|
225
|
+
- No search results: "{message}"
|
|
226
|
+
|
|
227
|
+
### CTAs
|
|
228
|
+
- Primary CTA: "{label}"
|
|
229
|
+
- Secondary CTA: "{label}"
|
|
230
|
+
|
|
231
|
+
## Mock Data Spec
|
|
232
|
+
|
|
233
|
+
### {PrimaryEntity} (generate 12-15 items)
|
|
234
|
+
Use realistic content observed on the website:
|
|
235
|
+
- Item 1: {name}, {category}, {description snippet}
|
|
236
|
+
- Item 2: ...
|
|
237
|
+
(list 5-6 examples, agent generates the rest)
|
|
238
|
+
|
|
239
|
+
### Categories (4-6)
|
|
240
|
+
- {name}: {description}
|
|
241
|
+
|
|
242
|
+
## AppConfig Values
|
|
243
|
+
|
|
244
|
+
Map to CUSTOMIZE markers in the template:
|
|
245
|
+
- `appName`: "{value}"
|
|
246
|
+
- `primaryColor`: "#{hex}"
|
|
247
|
+
- `accentColor`: "#{hex}"
|
|
248
|
+
- `tabTitles`: ["{tab1}", "{tab2}", "{tab3}", "{tab4}"]
|
|
249
|
+
- `categories`: ["{cat1}", "{cat2}", ...]
|
|
250
|
+
- `entityName`: "{name}"
|
|
251
|
+
- `entityNamePlural`: "{names}"
|
|
252
|
+
(continue for all CUSTOMIZE markers)
|
|
253
|
+
|
|
254
|
+
## Screen Changes
|
|
255
|
+
|
|
256
|
+
### HomeView
|
|
257
|
+
- Replace hero section with: {description from website}
|
|
258
|
+
- Cards should display: {entity fields}
|
|
259
|
+
- Style: {layout pattern from website}
|
|
260
|
+
- Reference screenshot: page-home.png
|
|
261
|
+
|
|
262
|
+
### {ScreenName}
|
|
263
|
+
- Changes: {description}
|
|
264
|
+
- Reference screenshot: page-{slug}.png
|
|
265
|
+
|
|
266
|
+
(repeat for each screen)
|
|
267
|
+
|
|
268
|
+
## Parallel Batches
|
|
269
|
+
|
|
270
|
+
### Screen Customization Batches
|
|
271
|
+
- **Batch 1** (Simulator 1): HomeView, ExploreView, SearchView
|
|
272
|
+
- **Batch 2** (Simulator 2): DetailView, CreateView, FavoritesView
|
|
273
|
+
- **Batch 3** (Simulator 3): ProfileView, SettingsView
|
|
274
|
+
|
|
275
|
+
### UI Testing Batches
|
|
276
|
+
- **Batch 1** (Simulator 1): Home tab, Explore tab
|
|
277
|
+
- **Batch 2** (Simulator 2): Detail screen, Create flow, Favorites tab
|
|
278
|
+
- **Batch 3** (Simulator 3): Profile tab, Settings
|
|
279
|
+
|
|
280
|
+
### Maestro Test Batches
|
|
281
|
+
- **Batch 1**: launch.yaml, home-tab.yaml, explore-tab.yaml
|
|
282
|
+
- **Batch 2**: detail-screen.yaml, create-flow.yaml, search-flow.yaml
|
|
283
|
+
- **Batch 3**: profile-tab.yaml, favorites-tab.yaml, e2e-navigation.yaml
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Template Selection Heuristics
|
|
287
|
+
|
|
288
|
+
When deciding which template to use, consider:
|
|
289
|
+
|
|
290
|
+
| Website Type | Best Template Match |
|
|
291
|
+
|-------------|-------------------|
|
|
292
|
+
| E-commerce / Shop | ShopTemplate |
|
|
293
|
+
| Blog / News / Content | SocialTemplate |
|
|
294
|
+
| Booking / Appointments | BookTemplate |
|
|
295
|
+
| Fitness / Health tracking | TrackTemplate |
|
|
296
|
+
| Finance / Banking | FinanceTemplate |
|
|
297
|
+
| Social / Community | SocialTemplate |
|
|
298
|
+
| Chat / Messaging | ChatTemplate |
|
|
299
|
+
| General / Mixed | Skeleton (or scratch) |
|
|
300
|
+
|
|
301
|
+
If the web-to-app manifest matches a template at 70%+ screen overlap, use it. Otherwise, recommend scratch mode or the Skeleton template.
|
|
302
|
+
|
|
303
|
+
## Key Principles
|
|
304
|
+
|
|
305
|
+
1. **Mobile-first thinking**: websites have infinite scroll space; mobile apps need concise, focused screens
|
|
306
|
+
2. **Tab bar is the backbone**: map the site's main sections to 4-5 tabs maximum
|
|
307
|
+
3. **Progressive disclosure**: detail pages are push-navigated from list pages, not shown inline
|
|
308
|
+
4. **Brand fidelity**: match the website's colors, typography feel, and card/layout patterns as closely as the native platform allows
|
|
309
|
+
5. **Content fidelity**: use actual content from the website (entity names, categories, descriptions) not generic placeholders
|
|
310
|
+
6. **Platform conventions**: respect iOS HIG and Material Design guidelines even while matching the web brand
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Web Crawler Skill
|
|
2
|
+
|
|
3
|
+
Systematically crawl a website using ai-tester MCP tools to capture its structure, brand, content, and functionality. Produce a structured crawl report that feeds into the web-analyzer skill.
|
|
4
|
+
|
|
5
|
+
## Inputs
|
|
6
|
+
|
|
7
|
+
- **URL**: The website URL to crawl
|
|
8
|
+
- **Focus directive** (optional): Which sections to prioritize
|
|
9
|
+
|
|
10
|
+
## Tools
|
|
11
|
+
|
|
12
|
+
Use ONLY ai-tester MCP tools for all web interaction:
|
|
13
|
+
- `inspect({ platform: "web", url: "...", saveBaseline: "...", label: "..." })` — load page, get screenshot + element tree
|
|
14
|
+
- `navigate({ url: "..." })` — navigate to a page
|
|
15
|
+
- `act({ action: "tap", selector: "..." })` — click elements (menus, dropdowns, modals)
|
|
16
|
+
- `act({ action: "swipe", direction: "down" })` — scroll the page
|
|
17
|
+
- `wait({ for: "duration", duration: 2000 })` — wait for content to load
|
|
18
|
+
|
|
19
|
+
## Crawl Strategy
|
|
20
|
+
|
|
21
|
+
### Phase 1: Home Page Analysis
|
|
22
|
+
|
|
23
|
+
1. Load the home page:
|
|
24
|
+
```
|
|
25
|
+
inspect({ platform: "web", url: "{url}", saveBaseline: "page-home", label: "Home" })
|
|
26
|
+
```
|
|
27
|
+
2. Save the screenshot path: `output/{app-name}/web-crawl/screenshots/page-home.png`
|
|
28
|
+
3. Analyze the element tree for:
|
|
29
|
+
- **Navigation elements**: `<nav>`, header links, hamburger menus, footer links
|
|
30
|
+
- **Hero/banner sections**: main call-to-action areas
|
|
31
|
+
- **Content sections**: cards, lists, grids
|
|
32
|
+
- **Brand signals**: logo, primary colors in buttons/headers, font styles
|
|
33
|
+
|
|
34
|
+
### Phase 2: Navigation Discovery
|
|
35
|
+
|
|
36
|
+
From the home page element tree, identify all major navigation links:
|
|
37
|
+
- Primary navigation (top nav bar, main menu)
|
|
38
|
+
- Secondary navigation (sidebar, sub-menus)
|
|
39
|
+
- Footer navigation (about, contact, legal)
|
|
40
|
+
- Call-to-action links (sign up, get started, shop now)
|
|
41
|
+
|
|
42
|
+
Build a **page queue** of URLs to visit. Prioritize:
|
|
43
|
+
1. Primary nav links (always visit)
|
|
44
|
+
2. Pages mentioned in the focus directive (if provided)
|
|
45
|
+
3. Secondary nav links (visit if under 10 pages total)
|
|
46
|
+
4. Skip: external links, auth/login pages, legal/privacy pages
|
|
47
|
+
|
|
48
|
+
### Phase 3: Page-by-Page Crawl
|
|
49
|
+
|
|
50
|
+
For each page in the queue (max 10 pages, depth 2 from home):
|
|
51
|
+
|
|
52
|
+
1. Navigate to the page:
|
|
53
|
+
```
|
|
54
|
+
navigate({ url: "{pageUrl}" })
|
|
55
|
+
```
|
|
56
|
+
2. Wait for content to load:
|
|
57
|
+
```
|
|
58
|
+
wait({ for: "duration", duration: 2000 })
|
|
59
|
+
```
|
|
60
|
+
3. Capture screenshot + element tree:
|
|
61
|
+
```
|
|
62
|
+
inspect({ saveBaseline: "page-{slug}", label: "{Page Title}" })
|
|
63
|
+
```
|
|
64
|
+
4. Scroll down to capture below-fold content:
|
|
65
|
+
```
|
|
66
|
+
act({ action: "swipe", direction: "down" })
|
|
67
|
+
wait({ for: "duration", duration: 1000 })
|
|
68
|
+
inspect({ saveBaseline: "page-{slug}-scroll", label: "{Page Title} (scrolled)" })
|
|
69
|
+
```
|
|
70
|
+
5. Check for interactive elements:
|
|
71
|
+
- **Forms**: identify input fields, textareas, submit buttons
|
|
72
|
+
- **Dropdowns/modals**: tap to open, capture expanded state
|
|
73
|
+
- **Tabs/accordions**: click to reveal hidden content
|
|
74
|
+
- **Search**: identify search inputs and their behavior
|
|
75
|
+
|
|
76
|
+
Record for each page:
|
|
77
|
+
- URL
|
|
78
|
+
- Page title
|
|
79
|
+
- Screenshot file paths (above-fold + scrolled)
|
|
80
|
+
- Element tree summary (interactive elements count, content sections)
|
|
81
|
+
- Content type (list page, detail page, form page, informational page)
|
|
82
|
+
- Key entities displayed (products, articles, users, events, etc.)
|
|
83
|
+
|
|
84
|
+
### Phase 4: Brand Extraction
|
|
85
|
+
|
|
86
|
+
From the collected screenshots and element trees, extract:
|
|
87
|
+
|
|
88
|
+
**Colors**:
|
|
89
|
+
- Primary color: dominant color in buttons, headers, and CTAs
|
|
90
|
+
- Secondary color: accent color used for highlights, links, hover states
|
|
91
|
+
- Background: main page background color
|
|
92
|
+
- Surface: card/section background color
|
|
93
|
+
- Text colors: heading color, body text color
|
|
94
|
+
- Error/success colors if visible in any forms
|
|
95
|
+
|
|
96
|
+
**Typography**:
|
|
97
|
+
- Heading font style (serif, sans-serif, monospace)
|
|
98
|
+
- Body text font style
|
|
99
|
+
- Relative sizes (large headings, medium subheads, regular body)
|
|
100
|
+
|
|
101
|
+
**Layout Patterns**:
|
|
102
|
+
- Card style (rounded corners, shadows, borders)
|
|
103
|
+
- Grid layout (2-column, 3-column, masonry)
|
|
104
|
+
- List layout (compact, spacious, with thumbnails)
|
|
105
|
+
- Spacing rhythm (tight, medium, generous)
|
|
106
|
+
|
|
107
|
+
**Logo & Imagery**:
|
|
108
|
+
- Logo description (text-based, icon, combination mark)
|
|
109
|
+
- Image style (photos, illustrations, icons)
|
|
110
|
+
- Hero section pattern (full-width image, gradient, video)
|
|
111
|
+
|
|
112
|
+
### Phase 5: Functionality Inventory
|
|
113
|
+
|
|
114
|
+
Catalog all interactive functionality discovered:
|
|
115
|
+
|
|
116
|
+
- **Search**: search bar location, search behavior (instant, page-based)
|
|
117
|
+
- **Forms**: sign up, contact, create/edit forms — list all fields
|
|
118
|
+
- **Filters**: category filters, sort options, tag filters
|
|
119
|
+
- **Navigation patterns**: pagination, infinite scroll, back/forward
|
|
120
|
+
- **Authentication**: login/signup forms (note: do NOT attempt to log in)
|
|
121
|
+
- **CRUD indicators**: create buttons, edit icons, delete actions
|
|
122
|
+
- **E-commerce**: cart, checkout, product selection
|
|
123
|
+
- **Social**: comments, likes, sharing, user profiles
|
|
124
|
+
|
|
125
|
+
## Output
|
|
126
|
+
|
|
127
|
+
Write `output/{app-name}/reports/02-web-crawl-report.md` with this structure:
|
|
128
|
+
|
|
129
|
+
```markdown
|
|
130
|
+
# Web Crawl Report
|
|
131
|
+
|
|
132
|
+
## Source
|
|
133
|
+
- **URL**: {url}
|
|
134
|
+
- **Crawl date**: {date}
|
|
135
|
+
- **Pages crawled**: {count}
|
|
136
|
+
- **Focus directive**: {description or "none"}
|
|
137
|
+
|
|
138
|
+
## Site Map
|
|
139
|
+
|
|
140
|
+
| # | Page | URL | Type | Screenshot |
|
|
141
|
+
|---|------|-----|------|------------|
|
|
142
|
+
| 1 | Home | {url} | Landing | page-home.png |
|
|
143
|
+
| 2 | Products | {url}/products | List | page-products.png |
|
|
144
|
+
| ... | | | | |
|
|
145
|
+
|
|
146
|
+
## Navigation Structure
|
|
147
|
+
|
|
148
|
+
### Primary Navigation
|
|
149
|
+
- Home
|
|
150
|
+
- Products → /products
|
|
151
|
+
- About → /about
|
|
152
|
+
- Contact → /contact
|
|
153
|
+
|
|
154
|
+
### Secondary Navigation
|
|
155
|
+
(sub-menus, sidebar links)
|
|
156
|
+
|
|
157
|
+
### Footer Navigation
|
|
158
|
+
(footer links)
|
|
159
|
+
|
|
160
|
+
## Brand Palette
|
|
161
|
+
|
|
162
|
+
### Colors
|
|
163
|
+
- **Primary**: #{hex} (from: buttons, headers)
|
|
164
|
+
- **Secondary**: #{hex} (from: links, accents)
|
|
165
|
+
- **Background**: #{hex}
|
|
166
|
+
- **Surface**: #{hex} (cards, sections)
|
|
167
|
+
- **Text Primary**: #{hex}
|
|
168
|
+
- **Text Secondary**: #{hex}
|
|
169
|
+
|
|
170
|
+
### Typography
|
|
171
|
+
- **Headings**: {font style description}
|
|
172
|
+
- **Body**: {font style description}
|
|
173
|
+
- **Size scale**: {relative sizes}
|
|
174
|
+
|
|
175
|
+
### Layout Patterns
|
|
176
|
+
- **Cards**: {description — rounded corners, shadow, border}
|
|
177
|
+
- **Grid**: {column count, gap}
|
|
178
|
+
- **Spacing**: {tight/medium/generous}
|
|
179
|
+
|
|
180
|
+
### Logo & Imagery
|
|
181
|
+
- **Logo**: {description}
|
|
182
|
+
- **Image style**: {photos/illustrations/icons}
|
|
183
|
+
|
|
184
|
+
## Content Model
|
|
185
|
+
|
|
186
|
+
### Entities
|
|
187
|
+
1. **{Entity Name}** (e.g., Product)
|
|
188
|
+
- Fields: name, price, image, description, category, rating
|
|
189
|
+
- Seen on: /products, /products/{id}
|
|
190
|
+
- Count: ~{n} items visible
|
|
191
|
+
|
|
192
|
+
2. **{Entity Name}** (e.g., Blog Post)
|
|
193
|
+
- Fields: title, author, date, excerpt, image
|
|
194
|
+
- Seen on: /blog, /blog/{slug}
|
|
195
|
+
|
|
196
|
+
### Categories
|
|
197
|
+
- {Category 1}: {description}
|
|
198
|
+
- {Category 2}: {description}
|
|
199
|
+
|
|
200
|
+
## Functionality Inventory
|
|
201
|
+
|
|
202
|
+
### Search
|
|
203
|
+
- Location: {header/page}
|
|
204
|
+
- Type: {instant/page-based}
|
|
205
|
+
|
|
206
|
+
### Forms
|
|
207
|
+
1. **{Form Name}** (e.g., Contact Form)
|
|
208
|
+
- Fields: name, email, message
|
|
209
|
+
- Location: /contact
|
|
210
|
+
|
|
211
|
+
### Filters & Sorting
|
|
212
|
+
- {description of filter/sort options}
|
|
213
|
+
|
|
214
|
+
### Authentication
|
|
215
|
+
- Login: {yes/no, location}
|
|
216
|
+
- Sign up: {yes/no, location}
|
|
217
|
+
|
|
218
|
+
### Other Features
|
|
219
|
+
- {feature}: {description}
|
|
220
|
+
|
|
221
|
+
## Page Details
|
|
222
|
+
|
|
223
|
+
### Page: {Page Name}
|
|
224
|
+
- **URL**: {url}
|
|
225
|
+
- **Type**: {list/detail/form/landing}
|
|
226
|
+
- **Screenshot**: page-{slug}.png
|
|
227
|
+
- **Key elements**: {description}
|
|
228
|
+
- **Interactive elements**: {count} buttons, {count} links, {count} inputs
|
|
229
|
+
- **Content**: {summary of what's displayed}
|
|
230
|
+
|
|
231
|
+
(repeat for each page)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Limits & Safety
|
|
235
|
+
|
|
236
|
+
- **Max pages**: 10 (prioritize primary nav and focus directive pages)
|
|
237
|
+
- **Max depth**: 2 levels from home page
|
|
238
|
+
- **Timeout**: 5 seconds per page load — skip pages that don't load
|
|
239
|
+
- **No authentication**: do NOT attempt to log in or create accounts
|
|
240
|
+
- **No form submission**: inspect forms but do NOT submit them
|
|
241
|
+
- **No payments**: do NOT interact with payment flows
|
|
242
|
+
- **External links**: skip links to other domains
|
|
243
|
+
- **Rate limiting**: wait 1-2 seconds between page navigations
|
|
244
|
+
|
|
245
|
+
## Focus Directive Handling
|
|
246
|
+
|
|
247
|
+
If a focus directive is provided:
|
|
248
|
+
1. Still crawl the home page first (for brand extraction)
|
|
249
|
+
2. Prioritize pages related to the directive
|
|
250
|
+
3. Explore those sections more deeply (depth 2)
|
|
251
|
+
4. Other sections: capture at depth 1 only (screenshot + basic element tree)
|
|
252
|
+
5. In the crawl report, mark which pages are "primary" (from directive) vs "secondary"
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA2B,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIrF,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAE9B,mDAAmD;AACnD,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,QAAQ,CAAC;CACjB;AAED,qIAAqI;AACrI,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,CAAC;IAChG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,iFAAiF;AACjF,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAEvD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,iBAAiB,GAAG,IAAI,CAqKjE;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,cAAc,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA2B,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIrF,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAE9B,mDAAmD;AACnD,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,QAAQ,CAAC;CACjB;AAED,qIAAqI;AACrI,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,CAAC;IAChG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,iFAAiF;AACjF,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAEvD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,iBAAiB,GAAG,IAAI,CAqKjE;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,cAAc,GAAG,IAAI,CAuHpD;AAED;;;GAGG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CA4D/C;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAoNnE;AAoHD,uEAAuE;AACvE,wBAAsB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAwDrE"}
|
package/dist/cli.js
CHANGED
|
@@ -184,6 +184,7 @@ export function parseCliArgs() {
|
|
|
184
184
|
let quick = false;
|
|
185
185
|
let update = false;
|
|
186
186
|
let updateTarget;
|
|
187
|
+
let url;
|
|
187
188
|
let noPreview = false;
|
|
188
189
|
let keysFile;
|
|
189
190
|
let keepSimulator = true;
|
|
@@ -224,6 +225,10 @@ export function parseCliArgs() {
|
|
|
224
225
|
update = true;
|
|
225
226
|
updateTarget = args[++i];
|
|
226
227
|
break;
|
|
228
|
+
case "--url":
|
|
229
|
+
case "--web":
|
|
230
|
+
url = args[++i];
|
|
231
|
+
break;
|
|
227
232
|
case "--no-preview":
|
|
228
233
|
noPreview = true;
|
|
229
234
|
break;
|
|
@@ -241,8 +246,12 @@ export function parseCliArgs() {
|
|
|
241
246
|
break;
|
|
242
247
|
}
|
|
243
248
|
}
|
|
244
|
-
//
|
|
245
|
-
if (
|
|
249
|
+
// Web clone mode: --url triggers non-interactive mode even without --description
|
|
250
|
+
if (url && !description) {
|
|
251
|
+
description = ""; // description is optional in web-clone mode
|
|
252
|
+
}
|
|
253
|
+
// Non-interactive mode: description (or url) is required; platform defaults to ios if not provided
|
|
254
|
+
if ((description != null || url) && (PLATFORM_INPUTS.includes(platform) || update)) {
|
|
246
255
|
if (!PLATFORM_INPUTS.includes(platform)) {
|
|
247
256
|
console.error(`Invalid platform: ${platform}. Available: ${PLATFORM_INPUTS.join(", ")}`);
|
|
248
257
|
process.exit(1);
|
|
@@ -263,11 +272,15 @@ export function parseCliArgs() {
|
|
|
263
272
|
console.error("--update requires a GitHub URL, local path, or app name.");
|
|
264
273
|
process.exit(1);
|
|
265
274
|
}
|
|
275
|
+
if (url && !description) {
|
|
276
|
+
// Ensure description is non-empty for downstream code that expects it
|
|
277
|
+
description = `Clone website: ${url}`;
|
|
278
|
+
}
|
|
266
279
|
if (!platformSet && !update) {
|
|
267
280
|
console.log(`Using default platform: ${platform}`);
|
|
268
281
|
}
|
|
269
282
|
return {
|
|
270
|
-
input: { description, platform, model, engine, scratch, quick, update, updateTarget, keysFile, keepSimulator },
|
|
283
|
+
input: { description: description, platform, model, engine, scratch, quick, update, updateTarget, url, keysFile, keepSimulator },
|
|
271
284
|
flags: { push, repoName, engine, noPreview },
|
|
272
285
|
};
|
|
273
286
|
}
|
|
@@ -648,13 +661,22 @@ export async function confirmInput(input) {
|
|
|
648
661
|
}
|
|
649
662
|
const platLabel = input.platform === "both" ? "Both (iOS + Android)"
|
|
650
663
|
: platformLabel(input.platform);
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
`
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
664
|
+
const modeLabel = input.url ? "Web Clone" : input.quick ? "Quick" : input.scratch ? "From scratch" : "Template";
|
|
665
|
+
const summaryLines = [];
|
|
666
|
+
if (input.url) {
|
|
667
|
+
summaryLines.push(`URL: ${input.url}`);
|
|
668
|
+
if (input.description && !input.description.startsWith("Clone website:")) {
|
|
669
|
+
summaryLines.push(`Focus: ${input.description}`);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
summaryLines.push(`App: ${input.description}`);
|
|
674
|
+
}
|
|
675
|
+
summaryLines.push(`Platform: ${platLabel}`);
|
|
676
|
+
summaryLines.push(`Engine: ${input.engine === "claude" ? "Claude Code" : "Cursor CLI"}`);
|
|
677
|
+
summaryLines.push(`Model: ${input.model}`);
|
|
678
|
+
summaryLines.push(`Mode: ${modeLabel}`);
|
|
679
|
+
p.note(summaryLines.join("\n"), "Build Summary");
|
|
658
680
|
const confirmed = await p.confirm({
|
|
659
681
|
message: "Proceed with building this app?",
|
|
660
682
|
});
|