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,120 @@
1
+ import { logger } from '../core/logger.js';
2
+ import { FailFastError, reportFailure } from '../core/fail-fast.js';
3
+ import { createRunContext, } from '../core/run-context.js';
4
+ import { prdClone } from '../core/prd-clone.js';
5
+ import { readFlutterProjectDocs } from '../core/project-doc-reader.js';
6
+ import { readVueProjectDocs } from '../core/vue-project-reader.js';
7
+ import { locateVuePage } from '../core/vue-page-locator.js';
8
+ import { capturePrototypeRuntime } from '../core/playwright-capture.js';
9
+ import { buildSemanticModel } from '../core/semantic-model-builder.js';
10
+ import { buildFeatureCoverage, mergeFeatureCoverageIntoSemanticModel, } from '../core/feature-coverage-builder.js';
11
+ import { writeScreenshotExplorationPlan } from '../core/screenshot-exploration-plan-writer.js';
12
+ import { scanFlutterProject } from '../core/flutter-project-scanner.js';
13
+ import { detectExistingFlutterPage } from '../core/existing-page-detector.js';
14
+ import { writeImplementationPlan } from '../core/implementation-plan-writer.js';
15
+ import { writeReport } from '../core/report-writer.js';
16
+ import { writeTaskIndex } from '../core/task-index-writer.js';
17
+ import { loadProjectProfile, ProfileConfigError } from '../core/profile.js';
18
+ export async function generateCommand(options) {
19
+ const ctx = createRunContext(options);
20
+ logger.stage(`p2f generate · ${options.pageName}`);
21
+ logger.info(`prototypeUrl: ${options.prototypeUrl}`);
22
+ logger.info(`workspace : ${ctx.paths.root}`);
23
+ logger.info(`taskDir : ${ctx.taskDir}`);
24
+ logger.info(`runDir : ${ctx.runDir}`);
25
+ try {
26
+ const { profile, configPath } = loadProjectProfile(ctx.paths.root);
27
+ logger.info(`profile : ${profile.name}${configPath ? ` (${configPath})` : ' (builtin)'}`);
28
+ // --- Phase 2 stages implemented now --------------------------------
29
+ logger.stage('Stage: sync-prd-source');
30
+ const sync = await prdClone(ctx);
31
+ logger.stage('Stage: read-flutter-docs');
32
+ readFlutterProjectDocs(ctx, profile, configPath);
33
+ const snapshot = scanFlutterProject(ctx, profile, configPath);
34
+ logger.stage('Stage: read-vue-docs');
35
+ const vueDocs = readVueProjectDocs(ctx, sync.path, profile);
36
+ // --- Phase 3+ stages still stubbed ---------------------------------
37
+ logger.stage('Stage: locate-vue-page');
38
+ const page = locateVuePage(ctx, vueDocs, options.prototypeUrl, profile);
39
+ writeTaskIndex(ctx, {
40
+ located: page,
41
+ vueDocs,
42
+ stage: 'located',
43
+ });
44
+ logger.stage('Stage: build-feature-coverage');
45
+ const coverage = buildFeatureCoverage(ctx, page, vueDocs);
46
+ logger.stage('Stage: capture-runtime');
47
+ const capture = await capturePrototypeRuntime(ctx, options.prototypeUrl, page);
48
+ logger.stage('Stage: build-semantic-model');
49
+ const model = buildSemanticModel(ctx, page, capture);
50
+ logger.stage('Stage: merge-feature-coverage');
51
+ mergeFeatureCoverageIntoSemanticModel(ctx, model, coverage);
52
+ logger.stage('Stage: write-screenshot-exploration-plan');
53
+ const screenshotPlan = writeScreenshotExplorationPlan(ctx, model, coverage, capture);
54
+ logger.stage('Stage: detect-existing-page');
55
+ const verdict = detectExistingFlutterPage(ctx, snapshot, model);
56
+ writeTaskIndex(ctx, {
57
+ located: page,
58
+ vueDocs,
59
+ snapshot,
60
+ verdict,
61
+ model,
62
+ stage: 'planned',
63
+ });
64
+ logger.stage('Stage: write-implementation-plan');
65
+ const plan = writeImplementationPlan(ctx, model, verdict, snapshot);
66
+ const report = writeReport(ctx, {
67
+ status: 'ready',
68
+ flutter: {
69
+ pageExisted: verdict.pageExists,
70
+ pageStatus: verdict.status,
71
+ confidence: verdict.confidence,
72
+ reviewRequired: verdict.agentReview.required,
73
+ targetModule: verdict.targetModule,
74
+ targetPageFile: verdict.targetPageFile ?? undefined,
75
+ },
76
+ risks: plan.highRisk,
77
+ reviewHints: plan.unknowns,
78
+ });
79
+ writeTaskIndex(ctx, {
80
+ located: page,
81
+ vueDocs,
82
+ snapshot,
83
+ verdict,
84
+ model,
85
+ stage: 'planned',
86
+ });
87
+ logger.success(`数据采集完成 · 报告:${report.pageMarkdown}`);
88
+ logger.info(`下一步:让 agent 读取 ${ctx.taskDir}/main.md,先按 ${screenshotPlan.markdownPath} 自动探索补全截图,再实现页面。`);
89
+ return 0;
90
+ }
91
+ catch (err) {
92
+ if (err instanceof ProfileConfigError) {
93
+ logger.error(err.message);
94
+ return 1;
95
+ }
96
+ if (err instanceof FailFastError) {
97
+ reportFailure(err);
98
+ try {
99
+ writeReport(ctx, {
100
+ status: 'stopped',
101
+ failure: {
102
+ stage: err.detail.stage,
103
+ action: err.detail.action,
104
+ reason: err.detail.reason,
105
+ completedSteps: err.detail.completedSteps,
106
+ pendingSteps: err.detail.pendingSteps,
107
+ suggestions: err.detail.suggestions,
108
+ },
109
+ });
110
+ }
111
+ catch (reportErr) {
112
+ logger.warn(`报告写入失败(忽略):${reportErr.message}`);
113
+ }
114
+ return 1;
115
+ }
116
+ logger.error(`意外错误:${err.stack ?? String(err)}`);
117
+ return 1;
118
+ }
119
+ }
120
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { mkdirSync } from 'node:fs';
2
+ import { logger } from '../core/logger.js';
3
+ import { FailFastError, reportFailure } from '../core/fail-fast.js';
4
+ import { createRunContext, markComplete } from '../core/run-context.js';
5
+ import { skillInstall } from '../core/skill-install.js';
6
+ import { prdClone } from '../core/prd-clone.js';
7
+ import { prdInstall } from '../core/prd-install.js';
8
+ import { playwrightInstall } from '../core/playwright-install.js';
9
+ export async function initCommand(opts) {
10
+ // init does not have a target page; we reuse RunContext with a synthetic one.
11
+ const runOpts = {
12
+ pageName: '__bootstrap__',
13
+ prototypeUrl: '(bootstrap)',
14
+ workspace: opts.workspace,
15
+ kind: 'system',
16
+ stagePlan: ['sync-prd-source', 'prd-install', 'playwright-install', 'skill-install'],
17
+ };
18
+ const ctx = createRunContext(runOpts);
19
+ mkdirSync(ctx.paths.workspaceDir, { recursive: true });
20
+ mkdirSync(ctx.paths.pagesDir, { recursive: true });
21
+ mkdirSync(ctx.paths.projectDir, { recursive: true });
22
+ mkdirSync(ctx.paths.logsDir, { recursive: true });
23
+ try {
24
+ logger.stage('Stage: sync-prd-source');
25
+ const clone = await prdClone(ctx);
26
+ logger.stage('Stage: prd-install');
27
+ const deps = await prdInstall(ctx, clone.path);
28
+ logger.stage('Stage: playwright-install');
29
+ await playwrightInstall(ctx);
30
+ logger.stage(`Stage: skill-install · target ${ctx.paths.root}`);
31
+ const skill = skillInstall({ workspace: ctx.paths.root });
32
+ markComplete(ctx, 'skill-install');
33
+ logger.success(`init OK. prototype commit=${clone.commit.slice(0, 7)} source=${clone.source} ` +
34
+ `deps=${deps.packageManager}${deps.ran ? '(installed)' : '(cached)'} ` +
35
+ `chromium=ready skill=${skill.installed.length}/2`);
36
+ return 0;
37
+ }
38
+ catch (err) {
39
+ if (err instanceof FailFastError) {
40
+ reportFailure(err);
41
+ return 1;
42
+ }
43
+ throw err;
44
+ }
45
+ }
46
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAwB,MAAM,wBAAwB,CAAC;AAC9F,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAMlE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAiB;IACjD,8EAA8E;IAC9E,MAAM,OAAO,GAAoB;QAC/B,QAAQ,EAAE,eAAe;QACzB,YAAY,EAAE,aAAa;QAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,IAAI,EAAE,QAAQ;QACd,SAAS,EAAE,CAAC,iBAAiB,EAAE,aAAa,EAAE,oBAAoB,EAAE,eAAe,CAAC;KACrF,CAAC;IACF,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACtC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;QAElC,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAE/C,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC1C,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAE7B,MAAM,CAAC,KAAK,CAAC,iCAAiC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1D,YAAY,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;QAEnC,MAAM,CAAC,OAAO,CACZ,6BAA6B,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,KAAK,CAAC,MAAM,GAAG;YAC7E,QAAQ,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,GAAG;YACtE,wBAAwB,KAAK,CAAC,SAAS,CAAC,MAAM,IAAI,CACrD,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,aAAa,EAAE,CAAC;YACjC,aAAa,CAAC,GAAG,CAAC,CAAC;YACnB,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { join } from 'node:path';
2
+ import { logger } from '../core/logger.js';
3
+ import { buildWorkspacePaths } from '../core/paths.js';
4
+ import { deriveTaskName } from '../core/route-name.js';
5
+ export async function pathsCommand(opts) {
6
+ if (!opts.json)
7
+ logger.stage('Stage: resolve-paths');
8
+ const paths = buildWorkspacePaths(opts.workspace);
9
+ const taskName = opts.pageName || opts.prototypeUrl
10
+ ? deriveTaskName({ pageName: opts.pageName, prototypeUrl: opts.prototypeUrl })
11
+ : undefined;
12
+ const payload = {
13
+ workspaceRoot: paths.root,
14
+ p2fWorkspace: paths.workspaceDir,
15
+ prdSource: paths.prdSourceDir,
16
+ pages: paths.pagesDir,
17
+ project: paths.projectDir,
18
+ flutterProjectJson: join(paths.projectDir, 'flutter-project.json'),
19
+ logs: paths.logsDir,
20
+ ...(taskName
21
+ ? {
22
+ taskName,
23
+ taskDir: join(paths.pagesDir, taskName),
24
+ cliDir: join(paths.pagesDir, taskName, 'cli'),
25
+ agentDir: join(paths.pagesDir, taskName, 'agent'),
26
+ cliRuntimeDir: join(paths.pagesDir, taskName, 'cli', 'runtime'),
27
+ agentRuntimeDir: join(paths.pagesDir, taskName, 'agent', 'runtime'),
28
+ screenshotsDir: join(paths.pagesDir, taskName, 'agent', 'screenshots'),
29
+ agentManifest: join(paths.pagesDir, taskName, 'agent', 'manifest.json'),
30
+ mainMd: join(paths.pagesDir, taskName, 'main.md'),
31
+ }
32
+ : {}),
33
+ };
34
+ if (opts.json) {
35
+ process.stdout.write(JSON.stringify(payload, null, 2) + '\n');
36
+ return 0;
37
+ }
38
+ logger.info(`workspaceRoot : ${payload.workspaceRoot}`);
39
+ logger.info(`p2fWorkspace : ${payload.p2fWorkspace}`);
40
+ logger.info(`prdSource : ${payload.prdSource}`);
41
+ logger.info(`pages : ${payload.pages}`);
42
+ logger.info(`project : ${payload.project}`);
43
+ logger.info(`flutterProject: ${payload.flutterProjectJson}`);
44
+ logger.info(`logs : ${payload.logs}`);
45
+ if (taskName) {
46
+ logger.info(`taskName : ${payload.taskName}`);
47
+ logger.info(`taskDir : ${payload.taskDir}`);
48
+ logger.info(`cliDir : ${payload.cliDir}`);
49
+ logger.info(`agentDir : ${payload.agentDir}`);
50
+ logger.info(`cliRuntimeDir : ${payload.cliRuntimeDir}`);
51
+ logger.info(`agentRuntime : ${payload.agentRuntimeDir}`);
52
+ logger.info(`screenshotsDir: ${payload.screenshotsDir}`);
53
+ logger.info(`agentManifest : ${payload.agentManifest}`);
54
+ logger.info(`mainMd : ${payload.mainMd}`);
55
+ }
56
+ return 0;
57
+ }
58
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/commands/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { existsSync, rmSync } from 'node:fs';
2
+ import { logger } from '../core/logger.js';
3
+ import { buildWorkspacePaths } from '../core/paths.js';
4
+ import { listSkillTargets } from '../core/skill-install.js';
5
+ export async function removeCommand(opts) {
6
+ logger.stage('Stage: remove');
7
+ const paths = buildWorkspacePaths(opts.workspace);
8
+ const targets = [paths.workspaceDir, ...listSkillTargets(paths.root)];
9
+ let removed = 0;
10
+ logger.info(`workspace: ${paths.root}`);
11
+ for (const target of targets) {
12
+ if (!existsSync(target)) {
13
+ logger.info(`already removed: ${target}`);
14
+ continue;
15
+ }
16
+ rmSync(target, { recursive: true, force: true });
17
+ logger.success(`removed: ${target}`);
18
+ removed += 1;
19
+ }
20
+ logger.success(`remove OK · removed=${removed}/${targets.length}`);
21
+ return 0;
22
+ }
23
+ //# sourceMappingURL=remove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.js","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAM5D,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAmB;IACrD,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACtE,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,MAAM,CAAC,IAAI,CAAC,cAAc,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACxC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,oBAAoB,MAAM,EAAE,CAAC,CAAC;YAC1C,SAAS;QACX,CAAC;QACD,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,MAAM,CAAC,OAAO,CAAC,YAAY,MAAM,EAAE,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,CAAC;IACf,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,uBAAuB,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { logger } from '../core/logger.js';
4
+ import { auditAgentScreenshots } from '../core/screenshot-auditor.js';
5
+ import { buildWorkspacePaths } from '../core/paths.js';
6
+ import { deriveTaskName } from '../core/route-name.js';
7
+ export async function screenshotsAuditCommand(opts) {
8
+ if (!opts.json)
9
+ logger.stage('Stage: screenshots-audit');
10
+ if (!opts.pageName && !opts.prototypeUrl) {
11
+ logger.error('必须提供 --url "<页面链接>" 或 --page "<页面名>" 来定位任务目录。');
12
+ return 2;
13
+ }
14
+ const paths = buildWorkspacePaths(opts.workspace);
15
+ const taskName = deriveTaskName({ pageName: opts.pageName, prototypeUrl: opts.prototypeUrl });
16
+ const pageDir = join(paths.pagesDir, taskName);
17
+ if (!existsSync(pageDir)) {
18
+ logger.error(`任务目录不存在:${pageDir}`);
19
+ return 2;
20
+ }
21
+ const audit = auditAgentScreenshots({
22
+ pageDir,
23
+ pageKey: taskName,
24
+ pageName: opts.pageName || taskName,
25
+ });
26
+ if (opts.json) {
27
+ process.stdout.write(JSON.stringify(audit, null, 2) + '\n');
28
+ return audit.summary.suspectedPlatformShell > 0 ? 1 : 0;
29
+ }
30
+ logger.success(`agent screenshot audit → ${audit.markdownPath}`);
31
+ logger.info(`screenshots=${audit.summary.total} exactGroups=${audit.summary.exactDuplicateGroups} ` +
32
+ `nearGroups=${audit.summary.nearDuplicateGroups} platformShell=${audit.summary.suspectedPlatformShell}`);
33
+ if (audit.summary.suspectedPlatformShell > 0) {
34
+ logger.error('发现疑似原型平台壳层截图,请删除并按 `.phone-screen` 元素重新截图。');
35
+ return 1;
36
+ }
37
+ return 0;
38
+ }
39
+ //# sourceMappingURL=screenshots-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshots-audit.js","sourceRoot":"","sources":["../../src/commands/screenshots-audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AASvD,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,IAA6B;IACzE,IAAI,CAAC,IAAI,CAAC,IAAI;QAAE,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACzD,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;QAC9D,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;IAC9F,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,KAAK,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;QACnC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,KAAK,GAAG,qBAAqB,CAAC;QAClC,OAAO;QACP,OAAO,EAAE,QAAQ;QACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,QAAQ;KACpC,CAAC,CAAC;IAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC5D,OAAO,KAAK,CAAC,OAAO,CAAC,sBAAsB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,4BAA4B,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;IACjE,MAAM,CAAC,IAAI,CACT,eAAe,KAAK,CAAC,OAAO,CAAC,KAAK,gBAAgB,KAAK,CAAC,OAAO,CAAC,oBAAoB,GAAG;QACrF,cAAc,KAAK,CAAC,OAAO,CAAC,mBAAmB,kBAAkB,KAAK,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAC1G,CAAC;IACF,IAAI,KAAK,CAAC,OAAO,CAAC,sBAAsB,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC3D,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { resolve } from 'node:path';
2
+ import { logger } from '../core/logger.js';
3
+ import { FailFastError, reportFailure } from '../core/fail-fast.js';
4
+ import { skillInstall } from '../core/skill-install.js';
5
+ export async function skillsInstallCommand(opts) {
6
+ const workspace = opts.workspace ? resolve(opts.workspace) : process.cwd();
7
+ logger.stage(`Stage: skill-install · target ${workspace}`);
8
+ try {
9
+ const res = skillInstall({ workspace });
10
+ logger.success(`内置 p2f skill 已安装/更新:${res.installed.length} 个目标目录。`);
11
+ return 0;
12
+ }
13
+ catch (err) {
14
+ if (err instanceof FailFastError) {
15
+ reportFailure(err);
16
+ return 1;
17
+ }
18
+ throw err;
19
+ }
20
+ }
21
+ //# sourceMappingURL=skills-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-install.js","sourceRoot":"","sources":["../../src/commands/skills-install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAMxD,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAA0B;IACnE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;IAC3E,MAAM,CAAC,KAAK,CAAC,iCAAiC,SAAS,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;QACxC,MAAM,CAAC,OAAO,CACZ,uBAAuB,GAAG,CAAC,SAAS,CAAC,MAAM,SAAS,CACrD,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,aAAa,EAAE,CAAC;YACjC,aAAa,CAAC,GAAG,CAAC,CAAC;YACnB,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,84 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { logger } from '../core/logger.js';
3
+ import { FailFastError, failFast, reportFailure } from '../core/fail-fast.js';
4
+ import { createRunContext, markComplete } from '../core/run-context.js';
5
+ import { checkPrdFreshness, prdClone } from '../core/prd-clone.js';
6
+ import { PROTOTYPE_BRANCH } from '../core/paths.js';
7
+ /**
8
+ * Check whether the local PRD prototype clone matches origin/<branch>; if not,
9
+ * pull the latest revision and force-reset the working tree (delegates to the
10
+ * existing `prdClone` update path).
11
+ *
12
+ * Designed to be safe to run repeatedly: idempotent when already up-to-date.
13
+ */
14
+ export async function syncCommand(opts) {
15
+ const runOpts = {
16
+ pageName: '__sync__',
17
+ prototypeUrl: '(sync)',
18
+ workspace: opts.workspace,
19
+ kind: 'system',
20
+ stagePlan: ['prd-sync-check', 'prd-sync-update'],
21
+ };
22
+ const ctx = createRunContext(runOpts);
23
+ try {
24
+ if (!existsSync(ctx.paths.prdSourceDir)) {
25
+ failFast({
26
+ stage: 'prd-sync-check',
27
+ action: `stat ${ctx.paths.prdSourceDir}`,
28
+ reason: 'PRD 仓库尚未初始化,无法检查或拉取最新代码。',
29
+ completedSteps: [...ctx.completedSteps],
30
+ pendingSteps: [...ctx.pendingSteps],
31
+ suggestions: [
32
+ '先执行 `p2f init` 完成首次克隆。',
33
+ ],
34
+ });
35
+ }
36
+ logger.stage('Stage: prd-sync-check');
37
+ const fresh = await runFreshnessCheck(ctx.paths.prdSourceDir);
38
+ if (fresh.upToDate) {
39
+ logger.success(`最新 · ${fresh.localCommit.slice(0, 7)} (origin/${PROTOTYPE_BRANCH})`);
40
+ markComplete(ctx, 'prd-sync-check');
41
+ markComplete(ctx, 'prd-sync-update');
42
+ return 0;
43
+ }
44
+ logger.warn(`PRD 本地副本不是最新:local ${fresh.localCommit.slice(0, 7)} != ` +
45
+ `origin/${PROTOTYPE_BRANCH} ${fresh.remoteCommit.slice(0, 7)} ` +
46
+ `(behind ${fresh.behind}, ahead ${fresh.ahead})`);
47
+ markComplete(ctx, 'prd-sync-check');
48
+ logger.stage('Stage: prd-sync-update');
49
+ const result = await prdClone(ctx);
50
+ markComplete(ctx, 'prd-sync-update');
51
+ logger.success(`PRD 本地副本已更新到 origin/${result.branch} · ${result.commit.slice(0, 7)}`);
52
+ return 0;
53
+ }
54
+ catch (err) {
55
+ if (err instanceof FailFastError) {
56
+ reportFailure(err);
57
+ return 1;
58
+ }
59
+ throw err;
60
+ }
61
+ }
62
+ async function runFreshnessCheck(prototypeDir) {
63
+ if (!process.env.GIT_SSH_COMMAND) {
64
+ process.env.GIT_SSH_COMMAND = 'ssh -o ConnectTimeout=5 -o BatchMode=yes';
65
+ }
66
+ try {
67
+ return await checkPrdFreshness(prototypeDir);
68
+ }
69
+ catch (err) {
70
+ const msg = err.shortMessage ?? err.message;
71
+ failFast({
72
+ stage: 'prd-sync-check',
73
+ action: `git fetch origin ${PROTOTYPE_BRANCH} && git rev-parse`,
74
+ reason: `检查 PRD 仓库新鲜度失败:${msg}`,
75
+ suggestions: [
76
+ '检查网络是否可以访问 code.nexita.net。',
77
+ '确认当前账号有 TradeAppPrd 仓库 SSH 权限。',
78
+ '如有 GIT_SSH_COMMAND 自定义,确认其参数有效。',
79
+ ],
80
+ needsUserDecision: ['请解决网络或仓库权限后重试。'],
81
+ });
82
+ }
83
+ }
84
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import { execa } from 'execa';
2
+ import { logger } from '../core/logger.js';
3
+ import { checkForUpdates } from '../core/update-checker.js';
4
+ export async function updateCommand(opts) {
5
+ const json = Boolean(opts.json);
6
+ let result;
7
+ try {
8
+ if (!json)
9
+ logger.stage('Stage: update-check');
10
+ result = await checkForUpdates({ repo: opts.repo });
11
+ }
12
+ catch (err) {
13
+ const message = errorMessage(err);
14
+ if (json) {
15
+ printJson({ ok: false, error: message });
16
+ }
17
+ else {
18
+ logger.error(`检查更新失败:${message}`);
19
+ }
20
+ return 1;
21
+ }
22
+ const shouldInstall = !opts.check && (result.updateAvailable || opts.force);
23
+ if (opts.check) {
24
+ if (json) {
25
+ printJson({ ok: true, installed: false, ...result });
26
+ }
27
+ else {
28
+ printCheckResult(result);
29
+ }
30
+ return 0;
31
+ }
32
+ if (!shouldInstall) {
33
+ if (json) {
34
+ printJson({ ok: true, installed: false, ...result });
35
+ }
36
+ else {
37
+ logger.success(`已是最新版本 · v${result.currentVersion}`);
38
+ }
39
+ return 0;
40
+ }
41
+ try {
42
+ if (!json) {
43
+ logger.stage(`Stage: update-install · ${result.latestTag}`);
44
+ }
45
+ await installLatest(result.installSpec, json);
46
+ if (json) {
47
+ printJson({ ok: true, installed: true, ...result });
48
+ }
49
+ else {
50
+ logger.success(`已更新到 ${result.latestTag}`);
51
+ }
52
+ return 0;
53
+ }
54
+ catch (err) {
55
+ const message = errorMessage(err);
56
+ if (json) {
57
+ printJson({ ok: false, installed: false, error: message, ...result });
58
+ }
59
+ else {
60
+ logger.error(`安装更新失败:${message}`);
61
+ }
62
+ return 1;
63
+ }
64
+ }
65
+ function printCheckResult(result) {
66
+ if (result.updateAvailable) {
67
+ logger.warn(`发现新版本 · 当前 v${result.currentVersion},最新 ${result.latestTag}`);
68
+ return;
69
+ }
70
+ logger.success(`已是最新版本 · v${result.currentVersion}`);
71
+ }
72
+ async function installLatest(installSpec, quiet) {
73
+ const args = ['install', '-g', installSpec];
74
+ const env = {
75
+ ...process.env,
76
+ GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND ?? 'ssh -o ConnectTimeout=5 -o BatchMode=yes',
77
+ };
78
+ if (quiet) {
79
+ await execa('npm', args, { stdout: 'pipe', stderr: 'pipe', env });
80
+ return;
81
+ }
82
+ await execa('npm', args, { stdio: 'inherit', env });
83
+ }
84
+ function printJson(value) {
85
+ console.log(JSON.stringify(value, null, 2));
86
+ }
87
+ function errorMessage(err) {
88
+ const execaError = err;
89
+ const message = execaError.shortMessage ?? err.message;
90
+ const stderr = typeof execaError.stderr === 'string' ? execaError.stderr.trim() : '';
91
+ return stderr ? `${message}\n${stderr}` : message;
92
+ }
93
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}