@autoview/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +407 -0
- package/lib/AutoViewAgent.d.ts +109 -0
- package/lib/AutoViewAgent.js +123 -0
- package/lib/AutoViewAgent.js.map +1 -0
- package/lib/agent/emitMcpServer.d.ts +15 -0
- package/lib/agent/emitMcpServer.js +157 -0
- package/lib/agent/emitMcpServer.js.map +1 -0
- package/lib/agent/emitReport.d.ts +14 -0
- package/lib/agent/emitReport.js +85 -0
- package/lib/agent/emitReport.js.map +1 -0
- package/lib/agent/toolSurface.d.ts +130 -0
- package/lib/agent/toolSurface.js +342 -0
- package/lib/agent/toolSurface.js.map +1 -0
- package/lib/agent/verifyAgentTasks.d.ts +87 -0
- package/lib/agent/verifyAgentTasks.js +126 -0
- package/lib/agent/verifyAgentTasks.js.map +1 -0
- package/lib/cli/main.d.ts +2 -0
- package/lib/cli/main.js +295 -0
- package/lib/cli/main.js.map +1 -0
- package/lib/compiler/AutoViewInterfaceCompiler.d.ts +27 -0
- package/lib/compiler/AutoViewInterfaceCompiler.js +68 -0
- package/lib/compiler/AutoViewInterfaceCompiler.js.map +1 -0
- package/lib/constants/AutoViewFrontendTemplate.d.ts +1 -0
- package/lib/constants/AutoViewFrontendTemplate.js +46 -0
- package/lib/constants/AutoViewFrontendTemplate.js.map +1 -0
- package/lib/constants/AutoViewSystemPromptConstant.d.ts +5 -0
- package/lib/constants/AutoViewSystemPromptConstant.js +4 -0
- package/lib/constants/AutoViewSystemPromptConstant.js.map +1 -0
- package/lib/context/IAutoViewAgentContext.d.ts +60 -0
- package/lib/context/IAutoViewAgentContext.js +3 -0
- package/lib/context/IAutoViewAgentContext.js.map +1 -0
- package/lib/fromSwagger.d.ts +53 -0
- package/lib/fromSwagger.js +513 -0
- package/lib/fromSwagger.js.map +1 -0
- package/lib/generateDeterministic.d.ts +26 -0
- package/lib/generateDeterministic.js +75 -0
- package/lib/generateDeterministic.js.map +1 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.js +41 -0
- package/lib/index.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoView.d.ts +17 -0
- package/lib/orchestrate/orchestrateAutoView.js +491 -0
- package/lib/orchestrate/orchestrateAutoView.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewProductPlan.d.ts +37 -0
- package/lib/orchestrate/orchestrateAutoViewProductPlan.js +109 -0
- package/lib/orchestrate/orchestrateAutoViewProductPlan.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewRender.d.ts +133 -0
- package/lib/orchestrate/orchestrateAutoViewRender.js +943 -0
- package/lib/orchestrate/orchestrateAutoViewRender.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.d.ts +24 -0
- package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.js +92 -0
- package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewReview.d.ts +48 -0
- package/lib/orchestrate/orchestrateAutoViewReview.js +328 -0
- package/lib/orchestrate/orchestrateAutoViewReview.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewScaffold.d.ts +45 -0
- package/lib/orchestrate/orchestrateAutoViewScaffold.js +586 -0
- package/lib/orchestrate/orchestrateAutoViewScaffold.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewSdkStudy.d.ts +26 -0
- package/lib/orchestrate/orchestrateAutoViewSdkStudy.js +85 -0
- package/lib/orchestrate/orchestrateAutoViewSdkStudy.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewProductPlan.d.ts +96 -0
- package/lib/orchestrate/structures/IAutoViewProductPlan.js +3 -0
- package/lib/orchestrate/structures/IAutoViewProductPlan.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewProductPlanApplication.d.ts +38 -0
- package/lib/orchestrate/structures/IAutoViewProductPlanApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewProductPlanApplication.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewRenderApplication.d.ts +38 -0
- package/lib/orchestrate/structures/IAutoViewRenderApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewRenderApplication.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewReviewApplication.d.ts +40 -0
- package/lib/orchestrate/structures/IAutoViewReviewApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewReviewApplication.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewSdkMap.d.ts +63 -0
- package/lib/orchestrate/structures/IAutoViewSdkMap.js +3 -0
- package/lib/orchestrate/structures/IAutoViewSdkMap.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.d.ts +37 -0
- package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.js.map +1 -0
- package/lib/orchestrate/utils/HistoryMessage.d.ts +10 -0
- package/lib/orchestrate/utils/HistoryMessage.js +25 -0
- package/lib/orchestrate/utils/HistoryMessage.js.map +1 -0
- package/lib/orchestrate/utils/auditFrontendRuntime.d.ts +53 -0
- package/lib/orchestrate/utils/auditFrontendRuntime.js +362 -0
- package/lib/orchestrate/utils/auditFrontendRuntime.js.map +1 -0
- package/lib/orchestrate/utils/buildDeterministicPlan.d.ts +4 -0
- package/lib/orchestrate/utils/buildDeterministicPlan.js +233 -0
- package/lib/orchestrate/utils/buildDeterministicPlan.js.map +1 -0
- package/lib/orchestrate/utils/buildDeterministicSdkMap.d.ts +22 -0
- package/lib/orchestrate/utils/buildDeterministicSdkMap.js +154 -0
- package/lib/orchestrate/utils/buildDeterministicSdkMap.js.map +1 -0
- package/lib/orchestrate/utils/cacheNodeModules.d.ts +31 -0
- package/lib/orchestrate/utils/cacheNodeModules.js +134 -0
- package/lib/orchestrate/utils/cacheNodeModules.js.map +1 -0
- package/lib/orchestrate/utils/describeEndpointPropsShape.d.ts +37 -0
- package/lib/orchestrate/utils/describeEndpointPropsShape.js +192 -0
- package/lib/orchestrate/utils/describeEndpointPropsShape.js.map +1 -0
- package/lib/orchestrate/utils/describeEndpointRequestBodyShape.d.ts +22 -0
- package/lib/orchestrate/utils/describeEndpointRequestBodyShape.js +29 -0
- package/lib/orchestrate/utils/describeEndpointRequestBodyShape.js.map +1 -0
- package/lib/orchestrate/utils/describeEndpointResponseShape.d.ts +19 -0
- package/lib/orchestrate/utils/describeEndpointResponseShape.js +30 -0
- package/lib/orchestrate/utils/describeEndpointResponseShape.js.map +1 -0
- package/lib/orchestrate/utils/executeCachedBatch.d.ts +22 -0
- package/lib/orchestrate/utils/executeCachedBatch.js +64 -0
- package/lib/orchestrate/utils/executeCachedBatch.js.map +1 -0
- package/lib/orchestrate/utils/loadShoppingFixture.d.ts +33 -0
- package/lib/orchestrate/utils/loadShoppingFixture.js +17 -0
- package/lib/orchestrate/utils/loadShoppingFixture.js.map +1 -0
- package/lib/orchestrate/utils/normalizeProductPlanPaths.d.ts +24 -0
- package/lib/orchestrate/utils/normalizeProductPlanPaths.js +77 -0
- package/lib/orchestrate/utils/normalizeProductPlanPaths.js.map +1 -0
- package/lib/orchestrate/utils/renderJsonSchema.d.ts +23 -0
- package/lib/orchestrate/utils/renderJsonSchema.js +122 -0
- package/lib/orchestrate/utils/renderJsonSchema.js.map +1 -0
- package/lib/orchestrate/utils/renderResourcePage.d.ts +36 -0
- package/lib/orchestrate/utils/renderResourcePage.js +1415 -0
- package/lib/orchestrate/utils/renderResourcePage.js.map +1 -0
- package/lib/orchestrate/utils/validateFrontendTypecheck.d.ts +109 -0
- package/lib/orchestrate/utils/validateFrontendTypecheck.js +274 -0
- package/lib/orchestrate/utils/validateFrontendTypecheck.js.map +1 -0
- package/lib/preview/renderPreview.d.ts +22 -0
- package/lib/preview/renderPreview.js +198 -0
- package/lib/preview/renderPreview.js.map +1 -0
- package/lib/typings/compiler.d.ts +39 -0
- package/lib/typings/compiler.js +3 -0
- package/lib/typings/compiler.js.map +1 -0
- package/lib/typings/events.d.ts +106 -0
- package/lib/typings/events.js +3 -0
- package/lib/typings/events.js.map +1 -0
- package/lib/typings/index.d.ts +10 -0
- package/lib/typings/index.js +27 -0
- package/lib/typings/index.js.map +1 -0
- package/lib/typings/misc.d.ts +78 -0
- package/lib/typings/misc.js +3 -0
- package/lib/typings/misc.js.map +1 -0
- package/lib/utils/ArrayUtil.d.ts +8 -0
- package/lib/utils/ArrayUtil.js +30 -0
- package/lib/utils/ArrayUtil.js.map +1 -0
- package/lib/utils/StringUtil.d.ts +11 -0
- package/lib/utils/StringUtil.js +28 -0
- package/lib/utils/StringUtil.js.map +1 -0
- package/lib/utils/classifyEndpoints.d.ts +62 -0
- package/lib/utils/classifyEndpoints.js +216 -0
- package/lib/utils/classifyEndpoints.js.map +1 -0
- package/lib/utils/endpointFilter.d.ts +26 -0
- package/lib/utils/endpointFilter.js +0 -0
- package/lib/utils/endpointFilter.js.map +1 -0
- package/lib/utils/extractFields.d.ts +85 -0
- package/lib/utils/extractFields.js +231 -0
- package/lib/utils/extractFields.js.map +1 -0
- package/lib/utils/index.d.ts +13 -0
- package/lib/utils/index.js +30 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/normalizeForNestia.d.ts +34 -0
- package/lib/utils/normalizeForNestia.js +133 -0
- package/lib/utils/normalizeForNestia.js.map +1 -0
- package/lib/utils/resourcePlan.d.ts +39 -0
- package/lib/utils/resourcePlan.js +95 -0
- package/lib/utils/resourcePlan.js.map +1 -0
- package/lib/utils/sliceDocument.d.ts +17 -0
- package/lib/utils/sliceDocument.js +114 -0
- package/lib/utils/sliceDocument.js.map +1 -0
- package/lib/utils/toEndpoints.d.ts +90 -0
- package/lib/utils/toEndpoints.js +227 -0
- package/lib/utils/toEndpoints.js.map +1 -0
- package/lib/verify/runWorkflows.d.ts +25 -0
- package/lib/verify/runWorkflows.js +366 -0
- package/lib/verify/runWorkflows.js.map +1 -0
- package/lib/verify/workflows.d.ts +53 -0
- package/lib/verify/workflows.js +107 -0
- package/lib/verify/workflows.js.map +1 -0
- package/package.json +82 -0
- package/prompts/AUTOVIEW_RENDER.md +398 -0
- package/prompts/AUTOVIEW_REVIEW.md +60 -0
- package/prompts/AUTOVIEW_SDK_STUDY.md +89 -0
- package/src/AutoViewAgent.ts +222 -0
- package/src/agent/emitMcpServer.integration.test.ts +168 -0
- package/src/agent/emitMcpServer.test.ts +51 -0
- package/src/agent/emitMcpServer.ts +178 -0
- package/src/agent/emitReport.ts +117 -0
- package/src/agent/toolSurface.test.ts +243 -0
- package/src/agent/toolSurface.ts +501 -0
- package/src/agent/verifyAgentTasks.test.ts +106 -0
- package/src/agent/verifyAgentTasks.ts +171 -0
- package/src/cli/main.ts +363 -0
- package/src/compiler/AutoViewInterfaceCompiler.ts +69 -0
- package/src/constants/AutoViewFrontendTemplate.ts +42 -0
- package/src/constants/AutoViewSystemPromptConstant.ts +6 -0
- package/src/context/IAutoViewAgentContext.ts +84 -0
- package/src/fromSwagger.test.ts +269 -0
- package/src/fromSwagger.ts +500 -0
- package/src/generateDeterministic.test.ts +39 -0
- package/src/generateDeterministic.ts +77 -0
- package/src/index.ts +30 -0
- package/src/orchestrate/orchestrateAutoView.ts +590 -0
- package/src/orchestrate/orchestrateAutoViewProductPlan.ts +121 -0
- package/src/orchestrate/orchestrateAutoViewRender.ts +1117 -0
- package/src/orchestrate/orchestrateAutoViewRenderDeterministic.ts +101 -0
- package/src/orchestrate/orchestrateAutoViewReview.ts +272 -0
- package/src/orchestrate/orchestrateAutoViewScaffold.ts +627 -0
- package/src/orchestrate/orchestrateAutoViewSdkStudy.ts +90 -0
- package/src/orchestrate/renderNavTs.test.ts +74 -0
- package/src/orchestrate/structures/IAutoViewProductPlan.ts +119 -0
- package/src/orchestrate/structures/IAutoViewProductPlanApplication.ts +41 -0
- package/src/orchestrate/structures/IAutoViewRenderApplication.ts +40 -0
- package/src/orchestrate/structures/IAutoViewReviewApplication.ts +42 -0
- package/src/orchestrate/structures/IAutoViewSdkMap.ts +72 -0
- package/src/orchestrate/structures/IAutoViewSdkStudyApplication.ts +40 -0
- package/src/orchestrate/utils/HistoryMessage.ts +41 -0
- package/src/orchestrate/utils/auditFrontendRuntime.test.ts +18 -0
- package/src/orchestrate/utils/auditFrontendRuntime.ts +454 -0
- package/src/orchestrate/utils/buildDeterministicPlan.test.ts +170 -0
- package/src/orchestrate/utils/buildDeterministicPlan.ts +289 -0
- package/src/orchestrate/utils/buildDeterministicSdkMap.test.ts +90 -0
- package/src/orchestrate/utils/buildDeterministicSdkMap.ts +169 -0
- package/src/orchestrate/utils/cacheNodeModules.ts +136 -0
- package/src/orchestrate/utils/describeEndpointPropsShape.test.ts +86 -0
- package/src/orchestrate/utils/describeEndpointPropsShape.ts +202 -0
- package/src/orchestrate/utils/describeEndpointRequestBodyShape.test.ts +87 -0
- package/src/orchestrate/utils/describeEndpointRequestBodyShape.ts +31 -0
- package/src/orchestrate/utils/describeEndpointResponseShape.test.ts +70 -0
- package/src/orchestrate/utils/describeEndpointResponseShape.ts +32 -0
- package/src/orchestrate/utils/executeCachedBatch.ts +59 -0
- package/src/orchestrate/utils/loadShoppingFixture.ts +52 -0
- package/src/orchestrate/utils/normalizeProductPlanPaths.ts +92 -0
- package/src/orchestrate/utils/renderJsonSchema.test.ts +162 -0
- package/src/orchestrate/utils/renderJsonSchema.ts +133 -0
- package/src/orchestrate/utils/renderResourcePage.test.ts +468 -0
- package/src/orchestrate/utils/renderResourcePage.ts +1624 -0
- package/src/orchestrate/utils/validateFrontendTypecheck.test.ts +32 -0
- package/src/orchestrate/utils/validateFrontendTypecheck.ts +335 -0
- package/src/preview/renderPreview.ts +273 -0
- package/src/typings/compiler.ts +47 -0
- package/src/typings/events.ts +155 -0
- package/src/typings/index.ts +10 -0
- package/src/typings/misc.ts +93 -0
- package/src/utils/ArrayUtil.ts +16 -0
- package/src/utils/StringUtil.ts +29 -0
- package/src/utils/classifyEndpoints.test.ts +86 -0
- package/src/utils/classifyEndpoints.ts +291 -0
- package/src/utils/endpointFilter.test.ts +50 -0
- package/src/utils/endpointFilter.ts +0 -0
- package/src/utils/extractFields.test.ts +82 -0
- package/src/utils/extractFields.ts +306 -0
- package/src/utils/index.ts +13 -0
- package/src/utils/normalizeForNestia.test.ts +93 -0
- package/src/utils/normalizeForNestia.ts +139 -0
- package/src/utils/resourcePlan.test.ts +104 -0
- package/src/utils/resourcePlan.ts +180 -0
- package/src/utils/sliceDocument.test.ts +85 -0
- package/src/utils/sliceDocument.ts +119 -0
- package/src/utils/toEndpoints.test.ts +251 -0
- package/src/utils/toEndpoints.ts +343 -0
- package/src/verify/runWorkflows.ts +403 -0
- package/src/verify/workflows.test.ts +117 -0
- package/src/verify/workflows.ts +154 -0
- package/template/CLAUDE.md +140 -0
- package/template/Dockerfile +31 -0
- package/template/PROMPT.md +80 -0
- package/template/SANDBOX.md +70 -0
- package/template/app/api/health/route.ts +10 -0
- package/template/app/globals.css +97 -0
- package/template/app/layout.tsx +30 -0
- package/template/app/page.tsx +19 -0
- package/template/components/AppShell.tsx +114 -0
- package/template/components/auto/CatalogGrid.tsx +159 -0
- package/template/components/auto/ConfirmButton.tsx +67 -0
- package/template/components/auto/EmbeddedCollection.tsx +144 -0
- package/template/components/auto/ResourceDashboard.tsx +104 -0
- package/template/components/auto/ResourceDetail.tsx +93 -0
- package/template/components/auto/ResourceForm.tsx +235 -0
- package/template/components/auto/ResourceIcon.tsx +88 -0
- package/template/components/auto/ResourceLanding.tsx +155 -0
- package/template/components/auto/ResourceTable.tsx +223 -0
- package/template/components/auto/formatValue.tsx +186 -0
- package/template/components/auto/types.ts +42 -0
- package/template/components/ui/badge.tsx +40 -0
- package/template/components/ui/button.tsx +57 -0
- package/template/components/ui/card.tsx +86 -0
- package/template/components/ui/dialog.tsx +119 -0
- package/template/components/ui/input.tsx +23 -0
- package/template/components/ui/label.tsx +24 -0
- package/template/components/ui/pagination.tsx +117 -0
- package/template/components/ui/select.tsx +92 -0
- package/template/components/ui/sheet.tsx +135 -0
- package/template/components/ui/skeleton.tsx +15 -0
- package/template/components/ui/table.tsx +120 -0
- package/template/components/ui/tabs.tsx +55 -0
- package/template/lib/utils.ts +35 -0
- package/template/next.config.mjs +52 -0
- package/template/package.json +46 -0
- package/template/postcss.config.js +6 -0
- package/template/scripts/start-shopping-backend.sh +56 -0
- package/template/tailwind.config.ts +96 -0
- package/template/tsconfig.json +29 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
import { OpenApi } from "@typia/interface";
|
|
2
|
+
import {
|
|
3
|
+
AutoBeAutoViewCompleteEvent,
|
|
4
|
+
AutoBeAutoViewStartEvent,
|
|
5
|
+
IAutoBeRunAutoViewOptions,
|
|
6
|
+
} from "../typings";
|
|
7
|
+
import { v7 } from "uuid";
|
|
8
|
+
|
|
9
|
+
import { IAutoViewAgentContext } from "../context/IAutoViewAgentContext";
|
|
10
|
+
import { orchestrateAutoViewProductPlan } from "./orchestrateAutoViewProductPlan";
|
|
11
|
+
import {
|
|
12
|
+
fileToScreenPath,
|
|
13
|
+
rerenderScreenForRuntime,
|
|
14
|
+
rerenderScreenForTypecheck,
|
|
15
|
+
screenPathToFile,
|
|
16
|
+
} from "./orchestrateAutoViewRender";
|
|
17
|
+
import { orchestrateAutoViewRenderDeterministic } from "./orchestrateAutoViewRenderDeterministic";
|
|
18
|
+
import { orchestrateAutoViewReview } from "./orchestrateAutoViewReview";
|
|
19
|
+
import { orchestrateAutoViewScaffold } from "./orchestrateAutoViewScaffold";
|
|
20
|
+
import { orchestrateAutoViewSdkStudy } from "./orchestrateAutoViewSdkStudy";
|
|
21
|
+
import {
|
|
22
|
+
type IAuditFrontendRuntimeResult,
|
|
23
|
+
auditFrontendRuntime,
|
|
24
|
+
} from "./utils/auditFrontendRuntime";
|
|
25
|
+
import { executeCachedBatch } from "./utils/executeCachedBatch";
|
|
26
|
+
import { loadShoppingFixture } from "./utils/loadShoppingFixture";
|
|
27
|
+
import { normalizeProductPlanPaths } from "./utils/normalizeProductPlanPaths";
|
|
28
|
+
import {
|
|
29
|
+
FrontendTypecheckSession,
|
|
30
|
+
type IValidateFrontendTypecheckResult,
|
|
31
|
+
} from "./utils/validateFrontendTypecheck";
|
|
32
|
+
import { deriveWorkflows } from "../verify/workflows";
|
|
33
|
+
import { runWorkflows } from "../verify/runWorkflows";
|
|
34
|
+
import { sliceDocument } from "../utils/sliceDocument";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Top-level AutoView orchestrator.
|
|
38
|
+
*
|
|
39
|
+
* Walks through the five phases — SDK Study, Product Plan, Scaffold, Render,
|
|
40
|
+
* Review — emitting one event per phase plus per-page progress during Render.
|
|
41
|
+
* The final `autoViewComplete` event carries the assembled frontend project as
|
|
42
|
+
* a flat `path → content` map ready for Sandbox deploy.
|
|
43
|
+
*
|
|
44
|
+
* All five phases (SDK Study → Product Plan → Scaffold → Render → UI Review)
|
|
45
|
+
* are implemented. Visual screenshot capture is intentionally out of scope for
|
|
46
|
+
* the agent itself — the operator runs Playwright against the Sandbox deploy —
|
|
47
|
+
* but the Review phase still produces the `wiki/sdk-feedback.md` audit so the
|
|
48
|
+
* SDK-quality signal lands in the archive.
|
|
49
|
+
*/
|
|
50
|
+
export async function orchestrateAutoView(
|
|
51
|
+
ctx: IAutoViewAgentContext,
|
|
52
|
+
options: IAutoBeRunAutoViewOptions = {},
|
|
53
|
+
): Promise<void> {
|
|
54
|
+
const source = options.source ?? "interface";
|
|
55
|
+
const designTheme = (options.designTheme ?? "").trim();
|
|
56
|
+
const {
|
|
57
|
+
document: fullDocument,
|
|
58
|
+
step,
|
|
59
|
+
reason,
|
|
60
|
+
backend,
|
|
61
|
+
} = resolveSource(ctx, source, {
|
|
62
|
+
backend: options.backend ?? null,
|
|
63
|
+
});
|
|
64
|
+
// Apply `--include` / `--exclude` at the DOCUMENT level, not just the screen
|
|
65
|
+
// list: slicing the paths AND pruning component schemas to their transitive
|
|
66
|
+
// closure is what lets a large swagger (Box, Stripe) actually run — otherwise
|
|
67
|
+
// SDK Study compiles all ~180 schemas and overflows the model's context.
|
|
68
|
+
const document = sliceDocument(fullDocument, {
|
|
69
|
+
include: options.include,
|
|
70
|
+
exclude: options.exclude,
|
|
71
|
+
});
|
|
72
|
+
const startedAt = Date.now();
|
|
73
|
+
|
|
74
|
+
ctx.dispatch({
|
|
75
|
+
type: "autoViewStart",
|
|
76
|
+
id: v7(),
|
|
77
|
+
created_at: new Date().toISOString(),
|
|
78
|
+
source,
|
|
79
|
+
step,
|
|
80
|
+
designTheme,
|
|
81
|
+
reason,
|
|
82
|
+
} satisfies AutoBeAutoViewStartEvent);
|
|
83
|
+
|
|
84
|
+
// Phase 1 — SDK Study.
|
|
85
|
+
const { map: sdkMap, markdown: sdkMapMarkdown } =
|
|
86
|
+
await orchestrateAutoViewSdkStudy(ctx, { document, step });
|
|
87
|
+
|
|
88
|
+
// Phase 2 — Product Plan.
|
|
89
|
+
const { plan: rawProductPlan, markdown: productPlanMarkdown } =
|
|
90
|
+
await orchestrateAutoViewProductPlan(ctx, {
|
|
91
|
+
document,
|
|
92
|
+
sdkMap,
|
|
93
|
+
designTheme,
|
|
94
|
+
step,
|
|
95
|
+
filter: { include: options.include, exclude: options.exclude },
|
|
96
|
+
});
|
|
97
|
+
// Next.js refuses to start when sibling routes under the same parent
|
|
98
|
+
// disagree on the dynamic-segment name (e.g. `/sales/[id]` vs.
|
|
99
|
+
// `/sales/[saleId]`). The planner cannot always avoid that — run the
|
|
100
|
+
// plan through a deterministic normalizer before the scaffold step
|
|
101
|
+
// bakes the paths into the file tree.
|
|
102
|
+
const productPlan = normalizeProductPlanPaths(rawProductPlan);
|
|
103
|
+
|
|
104
|
+
// Phase 3 — Scaffold (deterministic).
|
|
105
|
+
const scaffolded = await orchestrateAutoViewScaffold(ctx, {
|
|
106
|
+
document,
|
|
107
|
+
sdkMap,
|
|
108
|
+
sdkMapMarkdown,
|
|
109
|
+
productPlan,
|
|
110
|
+
productPlanMarkdown,
|
|
111
|
+
step,
|
|
112
|
+
backend,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Phase 4 — Render (deterministic). Emits one thin `page.tsx` per screen
|
|
116
|
+
// that wires the typed SDK call to a universal `Resource*` component, with
|
|
117
|
+
// column / field metadata baked from the swagger schema. No LLM, no
|
|
118
|
+
// parser-retry roulette: every screen gets a page and every property of its
|
|
119
|
+
// row / response / request type becomes a column / row / input. The rendered
|
|
120
|
+
// pages overwrite the scaffold placeholders in place.
|
|
121
|
+
const render = await orchestrateAutoViewRenderDeterministic(ctx, {
|
|
122
|
+
document,
|
|
123
|
+
productPlan,
|
|
124
|
+
step,
|
|
125
|
+
});
|
|
126
|
+
for (const [key, value] of Object.entries(render.files)) {
|
|
127
|
+
scaffolded[key] = value;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Phase 4.5 — deterministic `tsc --noEmit` against the assembled tree,
|
|
131
|
+
// plus a typecheck-driven retry pass for screens whose pages failed
|
|
132
|
+
// the gate. The per-screen parser check inside Render only catches
|
|
133
|
+
// grammar failures; type errors against the SDK (the model inventing
|
|
134
|
+
// properties on response types, wrong-casing fields, sending a second
|
|
135
|
+
// argument to a parameterless endpoint, etc.) escape every render
|
|
136
|
+
// attempt unless we actually compile the project the way the user
|
|
137
|
+
// will. Materializing into a temp dir + `npm install` + `tsc` is
|
|
138
|
+
// expensive (~30s on first run) but the typecheck session reuses the
|
|
139
|
+
// installed node_modules across retry rounds, so subsequent
|
|
140
|
+
// typecheck runs cost only the actual compile time.
|
|
141
|
+
const { typecheck, recovered } = await runTypecheckPhase(ctx, {
|
|
142
|
+
scaffolded,
|
|
143
|
+
document,
|
|
144
|
+
sdkMap,
|
|
145
|
+
productPlan,
|
|
146
|
+
designTheme,
|
|
147
|
+
});
|
|
148
|
+
scaffolded["wiki/typecheck.md"] = typecheck.markdown;
|
|
149
|
+
|
|
150
|
+
// Phase 6 — runtime audit (opt-in). After typecheck closes the static
|
|
151
|
+
// gate, boot `next dev` against the assembled tree, walk every screen
|
|
152
|
+
// with a headless Chromium, capture console / pageerror / navigation
|
|
153
|
+
// diagnostics, and re-render broken pages with the live errors in the
|
|
154
|
+
// prompt. The retry pass closes the class of bugs `tsc --noEmit`
|
|
155
|
+
// cannot see — `obj?.array.method(...)` undefined-access patterns,
|
|
156
|
+
// react render crashes against simulator data, hydration mismatches.
|
|
157
|
+
// Skipped when `options.runtimeAudit !== true` because the gate
|
|
158
|
+
// installs Playwright + Chromium (~150MB) and boots `next dev` twice
|
|
159
|
+
// per run, adding ~10–20 minutes to the agent's wall clock.
|
|
160
|
+
let runtimeAudit: IAuditFrontendRuntimeResult | null = null;
|
|
161
|
+
let runtimeRecovered = 0;
|
|
162
|
+
if (options.runtimeAudit === true) {
|
|
163
|
+
const result = await runRuntimeAuditPhase(ctx, {
|
|
164
|
+
scaffolded,
|
|
165
|
+
document,
|
|
166
|
+
sdkMap,
|
|
167
|
+
productPlan,
|
|
168
|
+
designTheme,
|
|
169
|
+
});
|
|
170
|
+
runtimeAudit = result.audit;
|
|
171
|
+
runtimeRecovered = result.recovered;
|
|
172
|
+
scaffolded["wiki/runtime-audit.md"] = runtimeAudit.markdown;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Phase 7 — workflow verification (opt-in). Derive the user workflows from
|
|
176
|
+
// the plan and drive them in a real headless browser, asserting each step's
|
|
177
|
+
// positive outcome (data rendered, navigation moved). Writes
|
|
178
|
+
// `wiki/verification.md` — the evidence that the generated app actually works
|
|
179
|
+
// for a user, not just that it compiles. Skipped unless `options.verify`
|
|
180
|
+
// because it installs Chromium and boots `next dev`.
|
|
181
|
+
if (options.verify === true) {
|
|
182
|
+
try {
|
|
183
|
+
const workflows = deriveWorkflows(productPlan);
|
|
184
|
+
const verification = await runWorkflows(scaffolded, workflows);
|
|
185
|
+
scaffolded["wiki/verification.md"] = verification.markdown;
|
|
186
|
+
} catch (err) {
|
|
187
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
188
|
+
scaffolded["wiki/verification.md"] = [
|
|
189
|
+
"# Workflow verification",
|
|
190
|
+
"",
|
|
191
|
+
"Verification could not run against the assembled project:",
|
|
192
|
+
"",
|
|
193
|
+
"```",
|
|
194
|
+
message,
|
|
195
|
+
"```",
|
|
196
|
+
].join("\n");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Phase 5 — UI Review. Code-and-spec audit; produces the
|
|
201
|
+
// operator-facing `wiki/sdk-feedback.md` document. Visual
|
|
202
|
+
// verification is left to the Sandbox deploy step.
|
|
203
|
+
const review = await orchestrateAutoViewReview(ctx, {
|
|
204
|
+
document,
|
|
205
|
+
sdkMap,
|
|
206
|
+
productPlan,
|
|
207
|
+
render,
|
|
208
|
+
typecheck,
|
|
209
|
+
recovered: recovered + runtimeRecovered,
|
|
210
|
+
step,
|
|
211
|
+
});
|
|
212
|
+
scaffolded["wiki/sdk-feedback.md"] = review.markdown;
|
|
213
|
+
|
|
214
|
+
ctx.dispatch({
|
|
215
|
+
type: "autoViewComplete",
|
|
216
|
+
id: v7(),
|
|
217
|
+
created_at: new Date().toISOString(),
|
|
218
|
+
step,
|
|
219
|
+
source,
|
|
220
|
+
elapsed: Date.now() - startedAt,
|
|
221
|
+
pages: productPlan.screens.length,
|
|
222
|
+
files: scaffolded,
|
|
223
|
+
} satisfies AutoBeAutoViewCompleteEvent);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
interface IResolvedSource {
|
|
227
|
+
document: OpenApi.IDocument;
|
|
228
|
+
step: number;
|
|
229
|
+
reason: string;
|
|
230
|
+
/**
|
|
231
|
+
* Backend hint surfaced from the source. When the swagger ships a real
|
|
232
|
+
* `servers[].url`, scaffold the generated frontend with that host + live mode
|
|
233
|
+
* so the demo renders real product data instead of typia-random gibberish.
|
|
234
|
+
* When omitted, scaffold falls back to localhost + simulate.
|
|
235
|
+
*/
|
|
236
|
+
backend: { host: string | null };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function resolveSource(
|
|
240
|
+
ctx: IAutoViewAgentContext,
|
|
241
|
+
source: "interface" | "shopping",
|
|
242
|
+
overrides: { backend: { host: string } | null },
|
|
243
|
+
): IResolvedSource {
|
|
244
|
+
if (source === "shopping") {
|
|
245
|
+
// Stable reference SDK derived from `@samchon/shopping-api`. Lets
|
|
246
|
+
// the AutoView pipeline run end-to-end without waiting for the
|
|
247
|
+
// live AutoBE interface phase to complete, which is the whole
|
|
248
|
+
// reason the bundled fixture exists.
|
|
249
|
+
//
|
|
250
|
+
// Default the backend at `http://127.0.0.1:37001` instead of the
|
|
251
|
+
// swagger's `servers[0].url` (the public host is not reachable from
|
|
252
|
+
// most networks). The frontend pack ships
|
|
253
|
+
// `scripts/start-shopping-backend.sh`, which clones
|
|
254
|
+
// `samchon/shopping` and boots its NestJS server on that port — so
|
|
255
|
+
// the demo runs end-to-end against the real backend with seeded
|
|
256
|
+
// product data instead of typia-random gibberish.
|
|
257
|
+
const fixture = loadShoppingFixture();
|
|
258
|
+
return {
|
|
259
|
+
document: fixture.document,
|
|
260
|
+
step: 0,
|
|
261
|
+
reason:
|
|
262
|
+
"User triggered AutoView against the bundled @samchon/shopping-api reference.",
|
|
263
|
+
backend: overrides.backend ?? { host: "http://127.0.0.1:37001" },
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
const interfaceHistory = ctx.state().interface;
|
|
267
|
+
if (interfaceHistory === null) {
|
|
268
|
+
throw new Error(
|
|
269
|
+
"AutoView requires the interface phase to be complete first. " +
|
|
270
|
+
'Run with source: "shopping" to use the bundled reference instead.',
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
document: interfaceHistory.document,
|
|
275
|
+
step: interfaceHistory.step,
|
|
276
|
+
reason: "User triggered AutoView against the AutoBE interface output.",
|
|
277
|
+
// Honor the caller's backend hint (CLI extracts it from swagger
|
|
278
|
+
// `servers[]`, or accepts a `--backend <url>` flag). When none was
|
|
279
|
+
// given the scaffold falls back to simulate-only mode — only useful
|
|
280
|
+
// for swaggers that genuinely have no backend (AutoBE's interface
|
|
281
|
+
// phase before the operator wires their own server).
|
|
282
|
+
backend: overrides.backend ?? { host: null },
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Maximum number of full typecheck+rerender rounds. Initial render counts as
|
|
288
|
+
* round 0, so this many additional rounds may follow it.
|
|
289
|
+
*/
|
|
290
|
+
const MAX_TYPECHECK_RETRY_ROUNDS = 2;
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Phase 4.5 in full: open a typecheck session against the assembled file map,
|
|
294
|
+
* iterate "typecheck → re-render broken screens → typecheck" up to
|
|
295
|
+
* {@link MAX_TYPECHECK_RETRY_ROUNDS} rounds, and return the final result. The
|
|
296
|
+
* scaffolded map is mutated in place — each successful re-render overwrites the
|
|
297
|
+
* broken file so the assembled output reflects the final state seen by the
|
|
298
|
+
* typecheck gate.
|
|
299
|
+
*
|
|
300
|
+
* Returns the last typecheck result + `recovered` count (screens that the loop
|
|
301
|
+
* fixed) so the Review event can report both honestly. On infra failure (npm
|
|
302
|
+
* install crash, etc.) returns a marker typecheck result and a recovered count
|
|
303
|
+
* of zero — the operator still gets the file map.
|
|
304
|
+
*/
|
|
305
|
+
async function runTypecheckPhase(
|
|
306
|
+
ctx: IAutoViewAgentContext,
|
|
307
|
+
args: {
|
|
308
|
+
scaffolded: Record<string, string>;
|
|
309
|
+
document: OpenApi.IDocument;
|
|
310
|
+
sdkMap: ReturnType<typeof loadShoppingFixture> extends { document: infer _ }
|
|
311
|
+
? Awaited<ReturnType<typeof orchestrateAutoViewSdkStudy>>["map"]
|
|
312
|
+
: never;
|
|
313
|
+
productPlan: Awaited<
|
|
314
|
+
ReturnType<typeof orchestrateAutoViewProductPlan>
|
|
315
|
+
>["plan"];
|
|
316
|
+
designTheme: string;
|
|
317
|
+
},
|
|
318
|
+
): Promise<{
|
|
319
|
+
typecheck: IValidateFrontendTypecheckResult;
|
|
320
|
+
recovered: number;
|
|
321
|
+
}> {
|
|
322
|
+
let session: FrontendTypecheckSession;
|
|
323
|
+
try {
|
|
324
|
+
session = await FrontendTypecheckSession.open(args.scaffolded);
|
|
325
|
+
} catch (err) {
|
|
326
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
327
|
+
return {
|
|
328
|
+
typecheck: {
|
|
329
|
+
diagnostics: new Map(),
|
|
330
|
+
totalErrors: 0,
|
|
331
|
+
markdown: [
|
|
332
|
+
"# Typecheck report",
|
|
333
|
+
"",
|
|
334
|
+
"`tsc --noEmit` could not be run against the assembled project:",
|
|
335
|
+
"",
|
|
336
|
+
"```",
|
|
337
|
+
message,
|
|
338
|
+
"```",
|
|
339
|
+
"",
|
|
340
|
+
"Re-run the project locally with `npm install && npm run typecheck` to validate.",
|
|
341
|
+
].join("\n"),
|
|
342
|
+
elapsedMs: 0,
|
|
343
|
+
},
|
|
344
|
+
recovered: 0,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
try {
|
|
349
|
+
let typecheck = await session.typecheck();
|
|
350
|
+
let recovered = 0;
|
|
351
|
+
const allScreenPaths = args.productPlan.screens.map((s) => s.path);
|
|
352
|
+
const semaphoreCap =
|
|
353
|
+
typeof ctx.vendor.semaphore === "number"
|
|
354
|
+
? ctx.vendor.semaphore
|
|
355
|
+
: ctx.vendor.semaphore !== undefined
|
|
356
|
+
? ctx.vendor.semaphore.max()
|
|
357
|
+
: 8;
|
|
358
|
+
|
|
359
|
+
for (
|
|
360
|
+
let round = 0;
|
|
361
|
+
round < MAX_TYPECHECK_RETRY_ROUNDS && typecheck.totalErrors > 0;
|
|
362
|
+
round++
|
|
363
|
+
) {
|
|
364
|
+
// Build the set of (screen, previousTsx, errors) tuples for every
|
|
365
|
+
// broken file that maps back to a known screen. Non-screen files
|
|
366
|
+
// (scaffold components, generated SDK, wiki) are not fixable by
|
|
367
|
+
// re-rendering a single screen — they are left to fail loudly.
|
|
368
|
+
const tasks: {
|
|
369
|
+
screen: (typeof args.productPlan.screens)[number];
|
|
370
|
+
filePath: string;
|
|
371
|
+
previousTsx: string;
|
|
372
|
+
errors: {
|
|
373
|
+
line: number;
|
|
374
|
+
column: number;
|
|
375
|
+
code: string;
|
|
376
|
+
message: string;
|
|
377
|
+
}[];
|
|
378
|
+
}[] = [];
|
|
379
|
+
for (const [filePath, diagnostics] of typecheck.diagnostics) {
|
|
380
|
+
const screenPath = fileToScreenPath(filePath);
|
|
381
|
+
if (screenPath === null) continue;
|
|
382
|
+
const screen = args.productPlan.screens.find(
|
|
383
|
+
(s) => s.path === screenPath,
|
|
384
|
+
);
|
|
385
|
+
if (screen === undefined) continue;
|
|
386
|
+
const previousTsx = args.scaffolded[filePath];
|
|
387
|
+
if (previousTsx === undefined) continue;
|
|
388
|
+
tasks.push({
|
|
389
|
+
screen,
|
|
390
|
+
filePath,
|
|
391
|
+
previousTsx,
|
|
392
|
+
errors: diagnostics.map((d) => ({
|
|
393
|
+
line: d.line,
|
|
394
|
+
column: d.column,
|
|
395
|
+
code: d.code,
|
|
396
|
+
message: d.message,
|
|
397
|
+
})),
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
if (tasks.length === 0) break;
|
|
401
|
+
|
|
402
|
+
const fixed = new Set<string>();
|
|
403
|
+
await executeCachedBatch(
|
|
404
|
+
semaphoreCap,
|
|
405
|
+
tasks.map((task) => async (promptCacheKey) => {
|
|
406
|
+
const result = await rerenderScreenForTypecheck(ctx, {
|
|
407
|
+
screen: task.screen,
|
|
408
|
+
document: args.document,
|
|
409
|
+
sdkMap: args.sdkMap,
|
|
410
|
+
designTheme: args.designTheme,
|
|
411
|
+
promptCacheKey,
|
|
412
|
+
allScreenPaths,
|
|
413
|
+
previousTsx: task.previousTsx,
|
|
414
|
+
typecheckErrors: task.errors,
|
|
415
|
+
});
|
|
416
|
+
if (result === null || !result.ok) return;
|
|
417
|
+
args.scaffolded[task.filePath] = result.tsx;
|
|
418
|
+
await session.writeFile(task.filePath, result.tsx);
|
|
419
|
+
fixed.add(task.filePath);
|
|
420
|
+
}),
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
if (fixed.size === 0) break;
|
|
424
|
+
const next = await session.typecheck();
|
|
425
|
+
const errorsBefore = new Set(typecheck.diagnostics.keys());
|
|
426
|
+
const errorsAfter = new Set(next.diagnostics.keys());
|
|
427
|
+
for (const filePath of fixed) {
|
|
428
|
+
if (errorsBefore.has(filePath) && !errorsAfter.has(filePath)) {
|
|
429
|
+
recovered++;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
typecheck = next;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return { typecheck, recovered };
|
|
436
|
+
} finally {
|
|
437
|
+
await session.dispose();
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Phase 6 in full: open a runtime audit session (npm install + playwright +
|
|
443
|
+
* chromium + `next dev`), capture per-page console / pageerror / navigation
|
|
444
|
+
* diagnostics, re-render the broken pages with the diagnostics in the prompt,
|
|
445
|
+
* and audit one more time. The orchestrator mutates `scaffolded` in place so
|
|
446
|
+
* the next phase sees the corrected output.
|
|
447
|
+
*
|
|
448
|
+
* Returns the final audit + `recovered` count (pages that the loop fixed) so
|
|
449
|
+
* the Review event can report runtime quality alongside the typecheck quality.
|
|
450
|
+
* On infra failure (Playwright install crashed, next dev never became ready,
|
|
451
|
+
* Chromium download blocked) returns a marker audit body and a recovered count
|
|
452
|
+
* of zero — the operator still gets the file map.
|
|
453
|
+
*/
|
|
454
|
+
async function runRuntimeAuditPhase(
|
|
455
|
+
ctx: IAutoViewAgentContext,
|
|
456
|
+
args: {
|
|
457
|
+
scaffolded: Record<string, string>;
|
|
458
|
+
document: OpenApi.IDocument;
|
|
459
|
+
sdkMap: Awaited<ReturnType<typeof orchestrateAutoViewSdkStudy>>["map"];
|
|
460
|
+
productPlan: Awaited<
|
|
461
|
+
ReturnType<typeof orchestrateAutoViewProductPlan>
|
|
462
|
+
>["plan"];
|
|
463
|
+
designTheme: string;
|
|
464
|
+
},
|
|
465
|
+
): Promise<{ audit: IAuditFrontendRuntimeResult; recovered: number }> {
|
|
466
|
+
const pages = args.productPlan.screens.map((s) => s.path);
|
|
467
|
+
let firstAudit: IAuditFrontendRuntimeResult;
|
|
468
|
+
try {
|
|
469
|
+
firstAudit = await auditFrontendRuntime(args.scaffolded, pages);
|
|
470
|
+
} catch (err) {
|
|
471
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
472
|
+
return {
|
|
473
|
+
audit: {
|
|
474
|
+
diagnostics: [],
|
|
475
|
+
byPage: new Map(),
|
|
476
|
+
visited: pages,
|
|
477
|
+
markdown: [
|
|
478
|
+
"# Runtime audit",
|
|
479
|
+
"",
|
|
480
|
+
"Playwright runtime audit could not be run against the assembled project:",
|
|
481
|
+
"",
|
|
482
|
+
"```",
|
|
483
|
+
message,
|
|
484
|
+
"```",
|
|
485
|
+
"",
|
|
486
|
+
"Re-run the project locally with `npm install && npm run dev` and visit pages by hand to validate.",
|
|
487
|
+
].join("\n"),
|
|
488
|
+
elapsedMs: 0,
|
|
489
|
+
},
|
|
490
|
+
recovered: 0,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
if (firstAudit.byPage.size === 0) {
|
|
494
|
+
return { audit: firstAudit, recovered: 0 };
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Identify broken pages whose screens we own — only `app/.../page.tsx`
|
|
498
|
+
// files map back to a planned screen; component / wiki / SDK files are
|
|
499
|
+
// out of this loop's scope.
|
|
500
|
+
type IRuntimeTask = {
|
|
501
|
+
screen: (typeof args.productPlan.screens)[number];
|
|
502
|
+
filePath: string;
|
|
503
|
+
previousTsx: string;
|
|
504
|
+
runtimeErrors: {
|
|
505
|
+
type: "console" | "pageerror" | "navigation";
|
|
506
|
+
message: string;
|
|
507
|
+
}[];
|
|
508
|
+
};
|
|
509
|
+
const tasks: IRuntimeTask[] = [];
|
|
510
|
+
for (const [pagePath, diagnostics] of firstAudit.byPage) {
|
|
511
|
+
const screen = args.productPlan.screens.find((s) => s.path === pagePath);
|
|
512
|
+
if (screen === undefined) continue;
|
|
513
|
+
const filePath = screenPathToFile(screen.path);
|
|
514
|
+
const previousTsx = args.scaffolded[filePath];
|
|
515
|
+
if (previousTsx === undefined) continue;
|
|
516
|
+
tasks.push({
|
|
517
|
+
screen,
|
|
518
|
+
filePath,
|
|
519
|
+
previousTsx,
|
|
520
|
+
runtimeErrors: diagnostics.map((d) => ({
|
|
521
|
+
type: d.type,
|
|
522
|
+
message: d.message,
|
|
523
|
+
})),
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
if (tasks.length === 0) return { audit: firstAudit, recovered: 0 };
|
|
527
|
+
|
|
528
|
+
const allScreenPaths = args.productPlan.screens.map((s) => s.path);
|
|
529
|
+
const semaphoreCap =
|
|
530
|
+
typeof ctx.vendor.semaphore === "number"
|
|
531
|
+
? ctx.vendor.semaphore
|
|
532
|
+
: ctx.vendor.semaphore !== undefined
|
|
533
|
+
? ctx.vendor.semaphore.max()
|
|
534
|
+
: 8;
|
|
535
|
+
|
|
536
|
+
const fixed = new Set<string>();
|
|
537
|
+
await executeCachedBatch(
|
|
538
|
+
semaphoreCap,
|
|
539
|
+
tasks.map((task) => async (promptCacheKey) => {
|
|
540
|
+
const result = await rerenderScreenForRuntime(ctx, {
|
|
541
|
+
screen: task.screen,
|
|
542
|
+
document: args.document,
|
|
543
|
+
sdkMap: args.sdkMap,
|
|
544
|
+
designTheme: args.designTheme,
|
|
545
|
+
promptCacheKey,
|
|
546
|
+
allScreenPaths,
|
|
547
|
+
previousTsx: task.previousTsx,
|
|
548
|
+
runtimeErrors: task.runtimeErrors,
|
|
549
|
+
});
|
|
550
|
+
if (result === null || !result.ok) return;
|
|
551
|
+
args.scaffolded[task.filePath] = result.tsx;
|
|
552
|
+
fixed.add(task.screen.path);
|
|
553
|
+
}),
|
|
554
|
+
);
|
|
555
|
+
if (fixed.size === 0) return { audit: firstAudit, recovered: 0 };
|
|
556
|
+
|
|
557
|
+
// Re-audit to measure recovery. Only one retry round to keep the gate
|
|
558
|
+
// bounded; further rounds rarely help once a page survived the prompt
|
|
559
|
+
// rewrite with the diagnostics in hand.
|
|
560
|
+
let secondAudit: IAuditFrontendRuntimeResult;
|
|
561
|
+
try {
|
|
562
|
+
secondAudit = await auditFrontendRuntime(args.scaffolded, pages);
|
|
563
|
+
} catch (err) {
|
|
564
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
565
|
+
secondAudit = {
|
|
566
|
+
diagnostics: [],
|
|
567
|
+
byPage: new Map(),
|
|
568
|
+
visited: pages,
|
|
569
|
+
markdown: [
|
|
570
|
+
"# Runtime audit (post-retry)",
|
|
571
|
+
"",
|
|
572
|
+
"Second-round Playwright audit could not be run:",
|
|
573
|
+
"",
|
|
574
|
+
"```",
|
|
575
|
+
message,
|
|
576
|
+
"```",
|
|
577
|
+
"",
|
|
578
|
+
"First-round results above are the last known runtime state.",
|
|
579
|
+
].join("\n"),
|
|
580
|
+
elapsedMs: 0,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
let recovered = 0;
|
|
584
|
+
for (const pagePath of fixed) {
|
|
585
|
+
if (firstAudit.byPage.has(pagePath) && !secondAudit.byPage.has(pagePath)) {
|
|
586
|
+
recovered++;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return { audit: secondAudit, recovered };
|
|
590
|
+
}
|