prd-to-flutter 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.
Files changed (85) hide show
  1. package/README.md +149 -0
  2. package/bin/p2f.mjs +18 -0
  3. package/dist/cli.js +203 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/clean.js +35 -0
  6. package/dist/commands/clean.js.map +1 -0
  7. package/dist/commands/doctor.js +148 -0
  8. package/dist/commands/doctor.js.map +1 -0
  9. package/dist/commands/generate.js +120 -0
  10. package/dist/commands/generate.js.map +1 -0
  11. package/dist/commands/init.js +46 -0
  12. package/dist/commands/init.js.map +1 -0
  13. package/dist/commands/paths.js +58 -0
  14. package/dist/commands/paths.js.map +1 -0
  15. package/dist/commands/remove.js +23 -0
  16. package/dist/commands/remove.js.map +1 -0
  17. package/dist/commands/screenshots-audit.js +39 -0
  18. package/dist/commands/screenshots-audit.js.map +1 -0
  19. package/dist/commands/skills-install.js +21 -0
  20. package/dist/commands/skills-install.js.map +1 -0
  21. package/dist/commands/sync.js +84 -0
  22. package/dist/commands/sync.js.map +1 -0
  23. package/dist/commands/update.js +93 -0
  24. package/dist/commands/update.js.map +1 -0
  25. package/dist/core/existing-page-detector.js +463 -0
  26. package/dist/core/existing-page-detector.js.map +1 -0
  27. package/dist/core/fail-fast.js +50 -0
  28. package/dist/core/fail-fast.js.map +1 -0
  29. package/dist/core/feature-coverage-builder.js +667 -0
  30. package/dist/core/feature-coverage-builder.js.map +1 -0
  31. package/dist/core/flutter-project-scanner.js +393 -0
  32. package/dist/core/flutter-project-scanner.js.map +1 -0
  33. package/dist/core/implementation-plan-writer.js +190 -0
  34. package/dist/core/implementation-plan-writer.js.map +1 -0
  35. package/dist/core/logger.js +39 -0
  36. package/dist/core/logger.js.map +1 -0
  37. package/dist/core/package-info.js +33 -0
  38. package/dist/core/package-info.js.map +1 -0
  39. package/dist/core/paths.js +37 -0
  40. package/dist/core/paths.js.map +1 -0
  41. package/dist/core/playwright-capture.js +539 -0
  42. package/dist/core/playwright-capture.js.map +1 -0
  43. package/dist/core/playwright-cli.js +26 -0
  44. package/dist/core/playwright-cli.js.map +1 -0
  45. package/dist/core/playwright-install.js +40 -0
  46. package/dist/core/playwright-install.js.map +1 -0
  47. package/dist/core/prd-clone.js +131 -0
  48. package/dist/core/prd-clone.js.map +1 -0
  49. package/dist/core/prd-install.js +108 -0
  50. package/dist/core/prd-install.js.map +1 -0
  51. package/dist/core/profile.js +149 -0
  52. package/dist/core/profile.js.map +1 -0
  53. package/dist/core/project-doc-reader.js +252 -0
  54. package/dist/core/project-doc-reader.js.map +1 -0
  55. package/dist/core/report-writer.js +90 -0
  56. package/dist/core/report-writer.js.map +1 -0
  57. package/dist/core/route-name.js +60 -0
  58. package/dist/core/route-name.js.map +1 -0
  59. package/dist/core/run-context.js +160 -0
  60. package/dist/core/run-context.js.map +1 -0
  61. package/dist/core/screenshot-auditor.js +405 -0
  62. package/dist/core/screenshot-auditor.js.map +1 -0
  63. package/dist/core/screenshot-exploration-plan-writer.js +200 -0
  64. package/dist/core/screenshot-exploration-plan-writer.js.map +1 -0
  65. package/dist/core/semantic-model-builder.js +922 -0
  66. package/dist/core/semantic-model-builder.js.map +1 -0
  67. package/dist/core/skill-install.js +78 -0
  68. package/dist/core/skill-install.js.map +1 -0
  69. package/dist/core/stage-stub.js +24 -0
  70. package/dist/core/stage-stub.js.map +1 -0
  71. package/dist/core/task-index-writer.js +149 -0
  72. package/dist/core/task-index-writer.js.map +1 -0
  73. package/dist/core/update-checker.js +155 -0
  74. package/dist/core/update-checker.js.map +1 -0
  75. package/dist/core/vue-page-locator.js +748 -0
  76. package/dist/core/vue-page-locator.js.map +1 -0
  77. package/dist/core/vue-project-reader.js +116 -0
  78. package/dist/core/vue-project-reader.js.map +1 -0
  79. package/docs/artifacts-and-agent.md +203 -0
  80. package/docs/development.md +118 -0
  81. package/docs/usage.md +246 -0
  82. package/package.json +50 -0
  83. package/skills/p2f/SKILL.md +303 -0
  84. package/skills/p2f/references/page-layout-patterns.md +120 -0
  85. package/skills/p2f/references/youfi-flutter-guidelines.md +71 -0
@@ -0,0 +1,539 @@
1
+ import { mkdirSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { chromium, } from 'playwright';
4
+ import { failFast } from './fail-fast.js';
5
+ import { logger } from './logger.js';
6
+ import { markComplete } from './run-context.js';
7
+ /** Mobile-sim viewport aligned with the design baseline. */
8
+ const MOBILE_VIEWPORT = { width: 375, height: 812 };
9
+ const DESKTOP_VIEWPORT = { width: 1280, height: 900 };
10
+ /** Selector to clip screenshots to the phone body, hiding the prototype chrome. */
11
+ const PHONE_SCREEN_SELECTOR = '.phone-screen';
12
+ /** Per-step timeout; keeps offline misconfigurations from stalling indefinitely. */
13
+ const NAV_TIMEOUT_MS = 30_000;
14
+ const ACTION_TIMEOUT_MS = 5_000;
15
+ export async function capturePrototypeRuntime(ctx, prototypeUrl, located) {
16
+ const screenshotDir = ctx.agentScreenshotsDir;
17
+ const runtimeDir = join(ctx.pageDir, 'runtime');
18
+ mkdirSync(screenshotDir, { recursive: true });
19
+ mkdirSync(runtimeDir, { recursive: true });
20
+ const kind = located.routeInfo.kind;
21
+ const useMobile = kind === 'prototype' || kind === 'design';
22
+ const viewport = useMobile ? MOBILE_VIEWPORT : DESKTOP_VIEWPORT;
23
+ const targetUrl = useMobile ? addMobileFlags(prototypeUrl) : prototypeUrl;
24
+ logger.info(`Playwright launching chromium (viewport=${viewport.width}x${viewport.height})...`);
25
+ let browser;
26
+ let context;
27
+ try {
28
+ browser = await chromium.launch({ headless: true });
29
+ }
30
+ catch (err) {
31
+ const msg = err.message ?? String(err);
32
+ failFast({
33
+ stage: 'capture',
34
+ action: 'chromium.launch',
35
+ reason: `Playwright 无法启动 Chromium:${msg}`,
36
+ completedSteps: [...ctx.completedSteps],
37
+ pendingSteps: [...ctx.pendingSteps],
38
+ suggestions: [
39
+ '在项目根目录执行 `p2f init` 自动安装 Playwright Chromium。',
40
+ '确认磁盘空间充足且具备写入权限。',
41
+ ],
42
+ });
43
+ }
44
+ try {
45
+ context = await browser.newContext({
46
+ viewport,
47
+ deviceScaleFactor: 2,
48
+ isMobile: useMobile,
49
+ hasTouch: useMobile,
50
+ });
51
+ const page = await context.newPage();
52
+ page.setDefaultTimeout(ACTION_TIMEOUT_MS);
53
+ page.setDefaultNavigationTimeout(NAV_TIMEOUT_MS);
54
+ const consoleLog = [];
55
+ page.on('console', (msg) => {
56
+ consoleLog.push(`[${msg.type()}] ${msg.text()}`);
57
+ });
58
+ const pageErrors = [];
59
+ page.on('pageerror', (err) => {
60
+ pageErrors.push(err.message);
61
+ });
62
+ try {
63
+ await page.goto(targetUrl, { waitUntil: 'load' });
64
+ }
65
+ catch (err) {
66
+ failFast({
67
+ stage: 'capture',
68
+ action: `page.goto ${targetUrl}`,
69
+ reason: `无法访问原型页面:${err.message}`,
70
+ completedSteps: [...ctx.completedSteps],
71
+ pendingSteps: [...ctx.pendingSteps],
72
+ suggestions: [
73
+ '确认原型页面链接可访问,必要时先启动 PRD 原型服务。',
74
+ '检查 URL 拼写,localhost 端口默认为 5173。',
75
+ '线上地址请确认 VPN / DNS。',
76
+ ],
77
+ });
78
+ }
79
+ // Vite SPA: wait for content to hydrate. Resolve either by selector or by
80
+ // timeout — don't treat selector miss as fatal yet; downstream capture
81
+ // will fail-fast if the target element never appears.
82
+ const phoneFound = await page
83
+ .waitForSelector(PHONE_SCREEN_SELECTOR, { timeout: ACTION_TIMEOUT_MS, state: 'visible' })
84
+ .catch(() => null);
85
+ if (useMobile && !phoneFound) {
86
+ failFast({
87
+ stage: 'capture',
88
+ action: `wait for ${PHONE_SCREEN_SELECTOR}`,
89
+ reason: '原型页面加载完成但未发现 .phone-screen 容器,无法定位手机屏。',
90
+ completedSteps: [...ctx.completedSteps],
91
+ pendingSteps: [...ctx.pendingSteps],
92
+ suggestions: [
93
+ '确认 URL 附带 is_mobile=1&app_simulator=1 两个 query。',
94
+ '确认页面属于 /prototype/* 或 /design/*(spec 页面无 phone frame)。',
95
+ '若原型项目结构变更,更新 capture 模块的选择器。',
96
+ ],
97
+ });
98
+ }
99
+ // 1) Let the network quiesce (SPA data fetches).
100
+ await page.waitForLoadState('networkidle', { timeout: NAV_TIMEOUT_MS }).catch(() => { });
101
+ // 2) Wait for common skeleton placeholders to disappear.
102
+ await waitForSkeletonsGone(page);
103
+ // 3) Wait for the DOM to stop mutating for a short window.
104
+ await waitForDomStable(page, 400, 3000);
105
+ // 4) Freeze animations so geometry, DOM text, and computed styles are deterministic.
106
+ await settleAnimations(page);
107
+ if (useMobile) {
108
+ await assertPrototypeScreenReady(ctx, page, targetUrl, located);
109
+ }
110
+ const states = [];
111
+ const fullPage = '';
112
+ // Persist DOM / a11y / computed styles / visible text.
113
+ const dom = await dumpDom(page, runtimeDir);
114
+ const accessibility = await dumpAccessibility(page, runtimeDir);
115
+ const computedStyles = await dumpComputedStyles(page, runtimeDir, PHONE_SCREEN_SELECTOR);
116
+ const visibleText = await dumpVisibleText(page, runtimeDir, useMobile ? PHONE_SCREEN_SELECTOR : 'body');
117
+ const interactionsJson = join(runtimeDir, 'interactions.json');
118
+ writeFileSync(interactionsJson, JSON.stringify({ pageKey: ctx.pageKey, interactions: [], _note: '交互模型待 analyze 阶段产出。' }, null, 2) + '\n', 'utf8');
119
+ if (consoleLog.length) {
120
+ writeFileSync(join(runtimeDir, 'console.log'), consoleLog.join('\n') + '\n', 'utf8');
121
+ }
122
+ if (pageErrors.length) {
123
+ writeFileSync(join(runtimeDir, 'page-errors.log'), pageErrors.join('\n') + '\n', 'utf8');
124
+ }
125
+ const finalUrl = page.url();
126
+ logger.success(`Runtime capture done · dom/styles/text ready · screenshots deferred to agent`);
127
+ markComplete(ctx, 'capture-runtime');
128
+ return {
129
+ captureMode: 'runtime-structure-only',
130
+ screenshotDir,
131
+ runtimeDir,
132
+ fullPage,
133
+ states,
134
+ dom,
135
+ accessibility,
136
+ computedStyles,
137
+ visibleText,
138
+ interactionsJson,
139
+ viewport,
140
+ targetUrl,
141
+ finalUrl,
142
+ screenshotsCaptured: false,
143
+ };
144
+ }
145
+ finally {
146
+ await context?.close().catch(() => { });
147
+ await browser?.close().catch(() => { });
148
+ }
149
+ }
150
+ // ---------------------------------------------------------------------------
151
+ // URL helpers
152
+ // ---------------------------------------------------------------------------
153
+ function addMobileFlags(raw) {
154
+ // Idempotent query string augmentation. Works with absolute URLs and
155
+ // plain path strings (for the latter we synthesize a localhost:5173 base
156
+ // so URL() is happy, then strip it back out).
157
+ const isAbsolute = /^https?:\/\//i.test(raw);
158
+ const base = isAbsolute ? undefined : 'http://localhost:5173';
159
+ let u;
160
+ try {
161
+ u = new URL(raw, base);
162
+ }
163
+ catch {
164
+ return raw;
165
+ }
166
+ normalizeHashRoute(u);
167
+ u.searchParams.set('is_mobile', '1');
168
+ u.searchParams.set('app_simulator', '1');
169
+ return isAbsolute ? u.toString() : u.pathname + u.search + u.hash;
170
+ }
171
+ function normalizeHashRoute(u) {
172
+ if (!u.hash.startsWith('#/'))
173
+ return;
174
+ const hashUrl = new URL(u.hash.slice(1), 'http://localhost:5173');
175
+ u.pathname = hashUrl.pathname;
176
+ const existing = new URLSearchParams(u.search);
177
+ u.search = hashUrl.search;
178
+ for (const [key, value] of existing) {
179
+ if (!u.searchParams.has(key))
180
+ u.searchParams.set(key, value);
181
+ }
182
+ u.hash = hashUrl.hash;
183
+ }
184
+ // ---------------------------------------------------------------------------
185
+ // Capture helpers
186
+ // ---------------------------------------------------------------------------
187
+ async function settleAnimations(page) {
188
+ // Stop CSS transitions & animations so screenshots are deterministic.
189
+ await page.addStyleTag({
190
+ content: `
191
+ *, *::before, *::after {
192
+ transition-duration: 0s !important;
193
+ animation-duration: 0s !important;
194
+ animation-delay: 0s !important;
195
+ }
196
+ `,
197
+ });
198
+ // Give the page one frame to absorb the override.
199
+ await page.waitForTimeout(150);
200
+ }
201
+ async function waitForSkeletonsGone(page) {
202
+ const selectors = ['.chart-skeleton', '.skeleton-container', '.van-skeleton', '[data-loading="true"]'];
203
+ // If any of them are present initially, wait until they are all hidden/absent
204
+ // (up to a small budget). Absent skeletons resolve instantly.
205
+ await page
206
+ .waitForFunction((sels) => {
207
+ for (const sel of sels) {
208
+ const nodes = document.querySelectorAll(sel);
209
+ for (const node of Array.from(nodes)) {
210
+ const rect = node.getBoundingClientRect();
211
+ if (rect.width > 0 && rect.height > 0)
212
+ return false;
213
+ }
214
+ }
215
+ return true;
216
+ }, selectors, { timeout: 5_000 })
217
+ .catch(() => {
218
+ /* best effort */
219
+ });
220
+ }
221
+ async function waitForDomStable(page, stableForMs, budgetMs) {
222
+ const start = Date.now();
223
+ let lastMark = await page.evaluate(() => ({
224
+ count: document.querySelectorAll('*').length,
225
+ text: document.body?.innerText?.length ?? 0,
226
+ }));
227
+ while (Date.now() - start < budgetMs) {
228
+ await page.waitForTimeout(stableForMs);
229
+ const mark = await page.evaluate(() => ({
230
+ count: document.querySelectorAll('*').length,
231
+ text: document.body?.innerText?.length ?? 0,
232
+ }));
233
+ if (mark.count === lastMark.count && mark.text === lastMark.text)
234
+ return;
235
+ lastMark = mark;
236
+ }
237
+ }
238
+ async function assertPrototypeScreenReady(ctx, page, targetUrl, located) {
239
+ const result = await page.evaluate(({ phoneSelector, expectedPath }) => {
240
+ const phone = document.querySelector(phoneSelector);
241
+ const appShell = document.querySelector('.app-shell');
242
+ const contentArea = document.querySelector('.content-area');
243
+ const bodyText = (document.body?.innerText ?? '').replace(/\s+/g, ' ').trim();
244
+ const phoneText = (phone?.innerText ?? '').replace(/\s+/g, ' ').trim();
245
+ const phoneRect = phone?.getBoundingClientRect();
246
+ const visiblePhoneNodes = phone
247
+ ? Array.from(phone.querySelectorAll('*')).filter((node) => {
248
+ const r = node.getBoundingClientRect();
249
+ if (r.width <= 0 || r.height <= 0)
250
+ return false;
251
+ const cs = getComputedStyle(node);
252
+ return cs.display !== 'none' && cs.visibility !== 'hidden' && Number(cs.opacity) !== 0;
253
+ }).length
254
+ : 0;
255
+ const params = new URLSearchParams(location.search);
256
+ const hashPath = location.hash.startsWith('#/')
257
+ ? new URL(location.hash.slice(1), location.origin).pathname
258
+ : '';
259
+ const normalizePath = (value) => value.replace(/\/+$/, '') || '/';
260
+ const pathMatches = (actual, target) => {
261
+ const current = normalizePath(actual);
262
+ const expected = normalizePath(target);
263
+ return current === expected || current.endsWith(expected);
264
+ };
265
+ const platformShellText = /TradeApp\s+Workflow\s+Hub|搜索页面\s*\/\s*路由\s*\/\s*Screen ID|App 模拟器|UI 规范|交互原型|设计稿/.test(bodyText);
266
+ const mobileFlagsReady = params.get('is_mobile') === '1' &&
267
+ params.get('app_simulator') === '1';
268
+ const routeMatches = pathMatches(location.pathname, expectedPath) ||
269
+ (hashPath ? pathMatches(hashPath, expectedPath) : false);
270
+ const isMobilePreviewShell = document.documentElement.classList.contains('mobile-preview-lock') ||
271
+ document.body.classList.contains('mobile-preview-lock') ||
272
+ Boolean(appShell?.classList.contains('mobile-preview-shell')) ||
273
+ Boolean(contentArea?.classList.contains('is-mobile-preview'));
274
+ const hasMeaningfulPhone = Boolean(phone) &&
275
+ Boolean(phoneRect) &&
276
+ phoneRect.width >= 300 &&
277
+ phoneRect.height >= 500 &&
278
+ (phoneText.length >= 2 || visiblePhoneNodes >= 3);
279
+ return {
280
+ hasPhone: Boolean(phone),
281
+ phoneTextLength: phoneText.length,
282
+ visiblePhoneNodes,
283
+ bodyText: bodyText.slice(0, 240),
284
+ phoneText: phoneText.slice(0, 240),
285
+ platformShellText,
286
+ mobileFlagsReady,
287
+ routeMatches,
288
+ isMobilePreviewShell,
289
+ hasMeaningfulPhone,
290
+ finalUrl: location.href,
291
+ currentPath: location.pathname,
292
+ hashPath,
293
+ };
294
+ }, { phoneSelector: PHONE_SCREEN_SELECTOR, expectedPath: located.routeInfo.path });
295
+ if (!result.hasPhone ||
296
+ !result.hasMeaningfulPhone ||
297
+ !result.mobileFlagsReady ||
298
+ !result.routeMatches ||
299
+ (result.platformShellText && !result.isMobilePreviewShell)) {
300
+ failFast({
301
+ stage: 'capture',
302
+ action: `validate prototype screen ${targetUrl}`,
303
+ reason: 'Playwright 加载到的不是有效原型手机页面,疑似停留在原型平台菜单 / 工作台壳层。',
304
+ completedSteps: [...ctx.completedSteps],
305
+ pendingSteps: [...ctx.pendingSteps],
306
+ suggestions: [
307
+ `确认目标 URL 是具体页面路由:${located.routeInfo.path}`,
308
+ '确认 URL 带有 is_mobile=1&app_simulator=1 后仍能直接进入页面,而不是进入 TradeApp Workflow Hub。',
309
+ `当前页面:${result.finalUrl}`,
310
+ `当前路由:${result.currentPath}${result.hashPath ? ` (hash: ${result.hashPath})` : ''}`,
311
+ `mobile flags: ${result.mobileFlagsReady ? 'ready' : 'missing'}`,
312
+ `phone visible nodes: ${result.visiblePhoneNodes}`,
313
+ `body 文案片段:${result.bodyText || '(empty)'}`,
314
+ `phone-screen 文案片段:${result.phoneText || '(empty)'}`,
315
+ ],
316
+ });
317
+ }
318
+ }
319
+ async function dumpDom(page, runtimeDir) {
320
+ const payload = await page.evaluate(() => {
321
+ function describe(el) {
322
+ const node = el;
323
+ const obj = {
324
+ tag: node.tagName.toLowerCase(),
325
+ };
326
+ if (node.id)
327
+ obj.id = node.id;
328
+ const cls = typeof node.className === 'string' ? node.className.trim() : '';
329
+ if (cls)
330
+ obj.class = cls;
331
+ const attrs = {};
332
+ for (const a of Array.from(node.attributes)) {
333
+ if (['class', 'id', 'style'].includes(a.name))
334
+ continue;
335
+ attrs[a.name] = a.value;
336
+ }
337
+ if (Object.keys(attrs).length)
338
+ obj.attrs = attrs;
339
+ const text = Array.from(node.childNodes)
340
+ .filter((c) => c.nodeType === Node.TEXT_NODE)
341
+ .map((c) => c.textContent?.trim())
342
+ .filter(Boolean)
343
+ .join(' ');
344
+ if (text)
345
+ obj.text = text;
346
+ // Clickable heuristic: cursor is pointer OR element has an onclick
347
+ // attribute OR tabindex is set. Vue compiles @click to an internal
348
+ // listener, but it also sets `cursor: pointer` via CSS on most themes
349
+ // (especially in YouFi's phone-preview prototype), which gives us a
350
+ // reliable signal without a Vue-specific inspector.
351
+ const computed = getComputedStyle(node);
352
+ const isClickable = computed.cursor === 'pointer' ||
353
+ node.hasAttribute('onclick') ||
354
+ node.hasAttribute('tabindex');
355
+ if (isClickable)
356
+ obj.clickable = true;
357
+ const rect = node.getBoundingClientRect();
358
+ if (rect.width || rect.height) {
359
+ obj.rect = {
360
+ x: Math.round(rect.x),
361
+ y: Math.round(rect.y),
362
+ w: Math.round(rect.width),
363
+ h: Math.round(rect.height),
364
+ };
365
+ }
366
+ const children = Array.from(node.children);
367
+ if (children.length) {
368
+ obj.children = children.slice(0, 200).map((c) => describe(c));
369
+ }
370
+ return obj;
371
+ }
372
+ const root = document.querySelector('.phone-screen') ?? document.body;
373
+ return describe(root);
374
+ });
375
+ const file = join(runtimeDir, 'dom.json');
376
+ writeFileSync(file, JSON.stringify(payload, null, 2) + '\n', 'utf8');
377
+ return file;
378
+ }
379
+ async function dumpAccessibility(page, runtimeDir) {
380
+ // Playwright 1.52 removed the `page.accessibility` namespace; build a
381
+ // lightweight semantic tree ourselves by walking the DOM and pulling
382
+ // role / aria-* / name signals that downstream Agent actually uses.
383
+ const tree = await page.evaluate(() => {
384
+ const MAX_NODES = 400;
385
+ let visited = 0;
386
+ const INTERESTING_ARIA = [
387
+ 'role', 'aria-label', 'aria-labelledby', 'aria-describedby',
388
+ 'aria-expanded', 'aria-selected', 'aria-checked', 'aria-hidden',
389
+ 'aria-pressed', 'aria-disabled', 'aria-current', 'aria-haspopup',
390
+ ];
391
+ function nameFor(el) {
392
+ const label = el.getAttribute('aria-label') || el.getAttribute('alt') || el.getAttribute('title');
393
+ if (label)
394
+ return label.trim();
395
+ if (el.tagName === 'BUTTON' || el.tagName === 'A') {
396
+ const t = (el.innerText || '').trim();
397
+ if (t)
398
+ return t.slice(0, 80);
399
+ }
400
+ if (el.tagName === 'INPUT') {
401
+ const placeholder = el.placeholder;
402
+ if (placeholder)
403
+ return placeholder;
404
+ }
405
+ return undefined;
406
+ }
407
+ function describe(el) {
408
+ if (visited >= MAX_NODES)
409
+ return null;
410
+ const node = el;
411
+ const rect = node.getBoundingClientRect();
412
+ const visible = rect.width > 0 && rect.height > 0;
413
+ const role = node.getAttribute('role') || implicitRole(node);
414
+ const out = { tag: node.tagName.toLowerCase() };
415
+ if (role)
416
+ out.role = role;
417
+ const name = nameFor(node);
418
+ if (name)
419
+ out.name = name;
420
+ const aria = {};
421
+ for (const a of INTERESTING_ARIA) {
422
+ const v = node.getAttribute(a);
423
+ if (v)
424
+ aria[a] = v;
425
+ }
426
+ if (Object.keys(aria).length)
427
+ out.aria = aria;
428
+ if (!visible)
429
+ out.hidden = true;
430
+ visited += 1;
431
+ const children = [];
432
+ for (const c of Array.from(node.children)) {
433
+ const childDesc = describe(c);
434
+ if (childDesc)
435
+ children.push(childDesc);
436
+ if (visited >= MAX_NODES)
437
+ break;
438
+ }
439
+ if (children.length)
440
+ out.children = children;
441
+ return out;
442
+ }
443
+ function implicitRole(node) {
444
+ const tag = node.tagName.toLowerCase();
445
+ const byTag = {
446
+ a: 'link', button: 'button', input: 'textbox', select: 'combobox',
447
+ textarea: 'textbox', nav: 'navigation', header: 'banner', footer: 'contentinfo',
448
+ main: 'main', aside: 'complementary', section: 'region', ul: 'list',
449
+ ol: 'list', li: 'listitem', img: 'img', h1: 'heading', h2: 'heading',
450
+ h3: 'heading', h4: 'heading', h5: 'heading', h6: 'heading',
451
+ };
452
+ return byTag[tag];
453
+ }
454
+ const root = document.querySelector('.phone-screen') ?? document.body;
455
+ return describe(root);
456
+ });
457
+ const file = join(runtimeDir, 'accessibility.json');
458
+ writeFileSync(file, JSON.stringify(tree, null, 2) + '\n', 'utf8');
459
+ return file;
460
+ }
461
+ async function dumpComputedStyles(page, runtimeDir, rootSelector) {
462
+ const wanted = [
463
+ 'color',
464
+ 'background-color',
465
+ 'font-size',
466
+ 'font-weight',
467
+ 'line-height',
468
+ 'border-radius',
469
+ 'border-color',
470
+ 'border-width',
471
+ 'padding',
472
+ 'margin',
473
+ 'box-shadow',
474
+ 'display',
475
+ 'flex-direction',
476
+ 'justify-content',
477
+ 'align-items',
478
+ 'gap',
479
+ 'opacity',
480
+ ];
481
+ const styles = await page.evaluate(({ root, wanted }) => {
482
+ const el = document.querySelector(root) ?? document.body;
483
+ const out = [];
484
+ const walker = document.createTreeWalker(el, NodeFilter.SHOW_ELEMENT);
485
+ let cur = walker.currentNode;
486
+ let visited = 0;
487
+ while (cur && visited < 200) {
488
+ if (cur.nodeType === Node.ELEMENT_NODE) {
489
+ const node = cur;
490
+ const cs = getComputedStyle(node);
491
+ const record = {
492
+ tag: node.tagName.toLowerCase(),
493
+ id: node.id || undefined,
494
+ class: typeof node.className === 'string' && node.className.trim()
495
+ ? node.className.trim()
496
+ : undefined,
497
+ };
498
+ const text = Array.from(node.childNodes)
499
+ .filter((c) => c.nodeType === Node.TEXT_NODE)
500
+ .map((c) => c.textContent?.trim())
501
+ .filter(Boolean)
502
+ .join(' ');
503
+ if (text)
504
+ record.text = text;
505
+ const rect = node.getBoundingClientRect();
506
+ if (rect.width || rect.height) {
507
+ record.rect = {
508
+ x: Math.round(rect.x),
509
+ y: Math.round(rect.y),
510
+ w: Math.round(rect.width),
511
+ h: Math.round(rect.height),
512
+ };
513
+ }
514
+ for (const k of wanted) {
515
+ const v = cs.getPropertyValue(k);
516
+ if (v)
517
+ record[k] = v.trim();
518
+ }
519
+ out.push(record);
520
+ visited += 1;
521
+ }
522
+ cur = walker.nextNode();
523
+ }
524
+ return out;
525
+ }, { root: rootSelector, wanted });
526
+ const file = join(runtimeDir, 'computed-styles.json');
527
+ writeFileSync(file, JSON.stringify(styles, null, 2) + '\n', 'utf8');
528
+ return file;
529
+ }
530
+ async function dumpVisibleText(page, runtimeDir, rootSelector) {
531
+ const text = await page.evaluate((sel) => {
532
+ const root = document.querySelector(sel) ?? document.body;
533
+ return root.innerText?.trim() ?? '';
534
+ }, rootSelector);
535
+ const file = join(runtimeDir, 'visible-text.txt');
536
+ writeFileSync(file, text + '\n', 'utf8');
537
+ return file;
538
+ }
539
+ //# sourceMappingURL=playwright-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright-capture.js","sourceRoot":"","sources":["../../src/core/playwright-capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { dirname, join } from 'node:path';
4
+ const require = createRequire(import.meta.url);
5
+ export function playwrightCliCommand(args) {
6
+ try {
7
+ const cli = join(dirname(require.resolve('playwright/package.json')), 'cli.js');
8
+ if (existsSync(cli)) {
9
+ return {
10
+ command: process.execPath,
11
+ args: [cli, ...args],
12
+ display: `playwright ${args.join(' ')}`,
13
+ };
14
+ }
15
+ }
16
+ catch {
17
+ // Fall through to npx for broken local installs; the caller will surface
18
+ // the actual command failure with stage context.
19
+ }
20
+ return {
21
+ command: 'npx',
22
+ args: ['--yes', 'playwright', ...args],
23
+ display: `npx --yes playwright ${args.join(' ')}`,
24
+ };
25
+ }
26
+ //# sourceMappingURL=playwright-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright-cli.js","sourceRoot":"","sources":["../../src/core/playwright-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAQ/C,MAAM,UAAU,oBAAoB,CAAC,IAAc;IACjD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAChF,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,OAAO;gBACL,OAAO,EAAE,OAAO,CAAC,QAAQ;gBACzB,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;gBACpB,OAAO,EAAE,cAAc,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;aACxC,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,iDAAiD;IACnD,CAAC;IACD,OAAO;QACL,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;QACtC,OAAO,EAAE,wBAAwB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;KAClD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { execa } from 'execa';
2
+ import { failFast } from './fail-fast.js';
3
+ import { logger } from './logger.js';
4
+ import { playwrightCliCommand } from './playwright-cli.js';
5
+ import { markComplete } from './run-context.js';
6
+ /**
7
+ * Pre-install the Playwright Chromium binary so each `generate` run does not
8
+ * have to. Playwright's installer is itself idempotent — it short-circuits on
9
+ * an already-present version — so we always invoke it.
10
+ */
11
+ export async function playwrightInstall(ctx) {
12
+ logger.info('正在安装 Playwright Chromium,后续 generate 可采集运行态数据。');
13
+ const cmd = playwrightCliCommand(['install', 'chromium']);
14
+ try {
15
+ await execa(cmd.command, cmd.args, {
16
+ stdout: 'inherit',
17
+ stderr: 'inherit',
18
+ });
19
+ }
20
+ catch (err) {
21
+ const msg = err.shortMessage ?? err.message;
22
+ failFast({
23
+ stage: 'playwright-install',
24
+ action: `p2f init · ${cmd.display}`,
25
+ reason: `Playwright Chromium 安装失败:${msg}`,
26
+ completedSteps: [...ctx.completedSteps],
27
+ pendingSteps: [...ctx.pendingSteps],
28
+ suggestions: [
29
+ '检查能否访问 playwright.azureedge.net / cdn.playwright.dev。',
30
+ '如需走代理,可设置 HTTPS_PROXY / PLAYWRIGHT_DOWNLOAD_HOST 后重试。',
31
+ '解决网络或代理问题后重新执行 `p2f init`。',
32
+ ],
33
+ needsUserDecision: ['请解决网络或代理问题后重新运行 `p2f init`。'],
34
+ });
35
+ }
36
+ logger.success('Playwright Chromium 已就绪。');
37
+ markComplete(ctx, 'playwright-install');
38
+ return { browser: 'chromium' };
39
+ }
40
+ //# sourceMappingURL=playwright-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright-install.js","sourceRoot":"","sources":["../../src/core/playwright-install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAmB,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAmB,MAAM,kBAAkB,CAAC;AAOjE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAe;IAEf,MAAM,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;IAC9D,MAAM,GAAG,GAAG,oBAAoB,CAAC,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE;YACjC,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,SAAS;SAClB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAI,GAAkB,CAAC,YAAY,IAAK,GAAa,CAAC,OAAO,CAAC;QACvE,QAAQ,CAAC;YACP,KAAK,EAAE,oBAAoB;YAC3B,MAAM,EAAE,cAAc,GAAG,CAAC,OAAO,EAAE;YACnC,MAAM,EAAE,4BAA4B,GAAG,EAAE;YACzC,cAAc,EAAE,CAAC,GAAG,GAAG,CAAC,cAAc,CAAC;YACvC,YAAY,EAAE,CAAC,GAAG,GAAG,CAAC,YAAY,CAAC;YACnC,WAAW,EAAE;gBACX,uDAAuD;gBACvD,uDAAuD;gBACvD,4BAA4B;aAC7B;YACD,iBAAiB,EAAE,CAAC,6BAA6B,CAAC;SACnD,CAAC,CAAC;IACL,CAAC;IACD,MAAM,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC3C,YAAY,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;IACxC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACjC,CAAC"}