@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,53 @@
|
|
|
1
|
+
import { IAutoViewProductPlan } from "../orchestrate/structures/IAutoViewProductPlan";
|
|
2
|
+
/**
|
|
3
|
+
* The verification layer — "정확하게 검증한다".
|
|
4
|
+
*
|
|
5
|
+
* A generated frontend that typechecks is not proven to work: a user has to be
|
|
6
|
+
* able to open it, see real data, and move through it. This module derives, from
|
|
7
|
+
* the deterministic product plan, the set of USER WORKFLOWS that a real visitor
|
|
8
|
+
* would perform — each a short journey with an explicit positive expectation at
|
|
9
|
+
* every step (the table actually rendered rows or an honest empty state; the
|
|
10
|
+
* detail actually showed fields; navigation actually moved). The execution layer
|
|
11
|
+
* ({@link ../verify/runWorkflows}) drives these in a real headless browser and
|
|
12
|
+
* reports pass/fail per step, so "it works" is demonstrated, not asserted.
|
|
13
|
+
*
|
|
14
|
+
* Pure and deterministic: same plan → same workflows, no browser needed. This is
|
|
15
|
+
* the spec of WHAT gets verified.
|
|
16
|
+
*/
|
|
17
|
+
/** What a page must be after a step — drives the runtime DOM assertion. */
|
|
18
|
+
export type WorkflowExpect = "landing" | "table" | "detail" | "form";
|
|
19
|
+
/** One user action plus the outcome it must produce. */
|
|
20
|
+
export interface IWorkflowStep {
|
|
21
|
+
action: {
|
|
22
|
+
type: "visit";
|
|
23
|
+
path: string;
|
|
24
|
+
} | {
|
|
25
|
+
type: "clickFirstRow";
|
|
26
|
+
} | {
|
|
27
|
+
type: "clickLink";
|
|
28
|
+
text: string;
|
|
29
|
+
};
|
|
30
|
+
expect: WorkflowExpect;
|
|
31
|
+
/** Human description, shown in the report. */
|
|
32
|
+
label: string;
|
|
33
|
+
}
|
|
34
|
+
/** One end-to-end user journey through a resource. */
|
|
35
|
+
export interface IWorkflow {
|
|
36
|
+
/** Stable slug (route-derived). */
|
|
37
|
+
id: string;
|
|
38
|
+
title: string;
|
|
39
|
+
/** Resource the journey covers, for grouping the report. */
|
|
40
|
+
resource: string;
|
|
41
|
+
steps: IWorkflowStep[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Derive the user workflows to verify from the product plan.
|
|
45
|
+
*
|
|
46
|
+
* - Home: the landing hub must open and present its resource links.
|
|
47
|
+
* - Per top-level resource: visit the list (it must render a table or an honest
|
|
48
|
+
* empty state, not an error), then open the first row's detail (it must render
|
|
49
|
+
* the record's fields). This is the core read journey — the one a user does
|
|
50
|
+
* first and the one that exercises data fetch + render + navigation together.
|
|
51
|
+
* - Per top-level singleton read (`/system`): visit it; the detail must render.
|
|
52
|
+
*/
|
|
53
|
+
export declare function deriveWorkflows(plan: IAutoViewProductPlan): IWorkflow[];
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deriveWorkflows = deriveWorkflows;
|
|
4
|
+
function slug(path) {
|
|
5
|
+
const cleaned = path.replace(/[^A-Za-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
6
|
+
return cleaned.length > 0 ? cleaned : "home";
|
|
7
|
+
}
|
|
8
|
+
/** A top-level resource screen earns its own browse workflow. */
|
|
9
|
+
function isTopLevelTable(screen) {
|
|
10
|
+
if (screen.depth !== undefined && screen.depth !== 1)
|
|
11
|
+
return false;
|
|
12
|
+
if (screen.path.includes("["))
|
|
13
|
+
return false;
|
|
14
|
+
return screen.uiPattern === "table" || screen.uiPattern === "catalog";
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Derive the user workflows to verify from the product plan.
|
|
18
|
+
*
|
|
19
|
+
* - Home: the landing hub must open and present its resource links.
|
|
20
|
+
* - Per top-level resource: visit the list (it must render a table or an honest
|
|
21
|
+
* empty state, not an error), then open the first row's detail (it must render
|
|
22
|
+
* the record's fields). This is the core read journey — the one a user does
|
|
23
|
+
* first and the one that exercises data fetch + render + navigation together.
|
|
24
|
+
* - Per top-level singleton read (`/system`): visit it; the detail must render.
|
|
25
|
+
*/
|
|
26
|
+
function deriveWorkflows(plan) {
|
|
27
|
+
const workflows = [];
|
|
28
|
+
const screens = plan.screens;
|
|
29
|
+
const landing = screens.find((s) => s.uiPattern === "landing");
|
|
30
|
+
if (landing !== undefined) {
|
|
31
|
+
workflows.push({
|
|
32
|
+
id: "home",
|
|
33
|
+
title: "Home hub loads and links to resources",
|
|
34
|
+
resource: "",
|
|
35
|
+
steps: [
|
|
36
|
+
{ action: { type: "visit", path: "/" }, expect: "landing", label: "Open home" },
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
for (const screen of screens) {
|
|
41
|
+
if (isTopLevelTable(screen)) {
|
|
42
|
+
const detail = screens.find((s) => s.uiPattern === "detail" && s.path.startsWith(`${screen.path}/[`));
|
|
43
|
+
const steps = [
|
|
44
|
+
{
|
|
45
|
+
action: { type: "visit", path: screen.path },
|
|
46
|
+
expect: "table",
|
|
47
|
+
label: `Open ${screen.title} list`,
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
if (detail !== undefined) {
|
|
51
|
+
steps.push({
|
|
52
|
+
action: { type: "clickFirstRow" },
|
|
53
|
+
expect: "detail",
|
|
54
|
+
label: `Open a ${screen.title} record`,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
workflows.push({
|
|
58
|
+
id: slug(screen.path),
|
|
59
|
+
title: `Browse ${screen.title}`,
|
|
60
|
+
resource: screen.title,
|
|
61
|
+
steps,
|
|
62
|
+
});
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
// Top-level create form (`/coupons/new`): verify it opens and renders its
|
|
66
|
+
// inputs. Forms do not fetch, so this is a fast, reliable structural check
|
|
67
|
+
// that the request-body schema produced a usable form.
|
|
68
|
+
if (screen.uiPattern === "form" &&
|
|
69
|
+
screen.path.endsWith("/new") &&
|
|
70
|
+
!screen.path.slice(0, -4).includes("[") &&
|
|
71
|
+
(screen.depth === undefined || screen.depth === 1)) {
|
|
72
|
+
workflows.push({
|
|
73
|
+
id: slug(screen.path),
|
|
74
|
+
title: `Open the ${screen.title} form`,
|
|
75
|
+
resource: screen.title,
|
|
76
|
+
steps: [
|
|
77
|
+
{
|
|
78
|
+
action: { type: "visit", path: screen.path },
|
|
79
|
+
expect: "form",
|
|
80
|
+
label: `Open ${screen.title}`,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
// Top-level singleton read (`/system`, `/performance`): a bracket-less
|
|
87
|
+
// detail page. Verify it opens and renders.
|
|
88
|
+
if (screen.uiPattern === "detail" &&
|
|
89
|
+
!screen.path.includes("[") &&
|
|
90
|
+
(screen.depth === undefined || screen.depth === 1)) {
|
|
91
|
+
workflows.push({
|
|
92
|
+
id: slug(screen.path),
|
|
93
|
+
title: `View ${screen.title}`,
|
|
94
|
+
resource: screen.title,
|
|
95
|
+
steps: [
|
|
96
|
+
{
|
|
97
|
+
action: { type: "visit", path: screen.path },
|
|
98
|
+
expect: "detail",
|
|
99
|
+
label: `Open ${screen.title}`,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return workflows;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=workflows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflows.js","sourceRoot":"","sources":["../../src/verify/workflows.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@autoview/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Read any OpenAPI document, prove it can be driven as a product, and emit the surfaces that drive it — a human frontend and an agent tool surface (MCP) — each verified.",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"author": "Wrtn Technologies",
|
|
7
|
+
"license": "AGPL-3.0",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/wrtnlabs/AutoView-Legacy.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/wrtnlabs/AutoView-Legacy/issues"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"lib",
|
|
17
|
+
"src",
|
|
18
|
+
"prompts",
|
|
19
|
+
"template",
|
|
20
|
+
"package.json",
|
|
21
|
+
"LICENSE",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"bin": {
|
|
25
|
+
"autoview": "lib/cli/main.js"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"prepare": "ts-patch install && npm run build:prompt && npm run build:template",
|
|
29
|
+
"build": "rimraf lib && npm run build:prompt && npm run build:template && tspc",
|
|
30
|
+
"build:prompt": "ts-node build/prompt.ts",
|
|
31
|
+
"build:template": "ts-node build/template.ts",
|
|
32
|
+
"dev": "rimraf lib && npm run build:prompt && npm run build:template && tspc --watch",
|
|
33
|
+
"prepack": "npm run build",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"verify:agent": "ts-node examples/verify-agent.ts",
|
|
36
|
+
"ab:nested": "ts-node examples/ab-nested-chain.ts"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@agentica/core": "^0.45.1",
|
|
40
|
+
"@nestia/migrate": "^11.0.1",
|
|
41
|
+
"@samchon/shopping-api": "^0.18.0",
|
|
42
|
+
"@typia/interface": "^12.0.1",
|
|
43
|
+
"@typia/utils": "^12.0.1",
|
|
44
|
+
"openai": "^6.38.0",
|
|
45
|
+
"tstl": "^3.0.0",
|
|
46
|
+
"typescript": "~5.9.3",
|
|
47
|
+
"typia": "^12.0.1",
|
|
48
|
+
"uuid": "^11.1.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
52
|
+
"@types/node": "^22.15.3",
|
|
53
|
+
"@types/uuid": "^10.0.0",
|
|
54
|
+
"rimraf": "^6.0.1",
|
|
55
|
+
"ts-node": "^10.9.2",
|
|
56
|
+
"ts-patch": "^3.3.0",
|
|
57
|
+
"vitest": "^3.1.4"
|
|
58
|
+
},
|
|
59
|
+
"keywords": [
|
|
60
|
+
"agent",
|
|
61
|
+
"ai",
|
|
62
|
+
"autoview",
|
|
63
|
+
"frontend",
|
|
64
|
+
"generator",
|
|
65
|
+
"nextjs",
|
|
66
|
+
"openapi",
|
|
67
|
+
"react",
|
|
68
|
+
"shadcn",
|
|
69
|
+
"swagger",
|
|
70
|
+
"tailwind",
|
|
71
|
+
"typescript",
|
|
72
|
+
"mcp",
|
|
73
|
+
"tool-surface",
|
|
74
|
+
"api-consumability",
|
|
75
|
+
"code-generator"
|
|
76
|
+
],
|
|
77
|
+
"publishConfig": {
|
|
78
|
+
"access": "public",
|
|
79
|
+
"main": "lib/index.js",
|
|
80
|
+
"typings": "lib/index.d.ts"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
You are the Render phase of the AutoView agent.
|
|
2
|
+
|
|
3
|
+
You receive one screen from the product plan and produce a complete,
|
|
4
|
+
runnable Next.js page (TSX) that composes the SDK endpoints listed for
|
|
5
|
+
that screen into a single coherent UI. You are not redesigning the
|
|
6
|
+
product, choosing the actor, or inventing endpoints — those decisions
|
|
7
|
+
were already made by the Product Plan phase. You translate the plan
|
|
8
|
+
into TSX.
|
|
9
|
+
|
|
10
|
+
## Stack
|
|
11
|
+
|
|
12
|
+
- Next.js 15 App Router. Output a single TSX file with `export default
|
|
13
|
+
function Page()`.
|
|
14
|
+
- React 18 client component by default. Start the file with
|
|
15
|
+
`"use client";` because every page calls the SDK from the browser.
|
|
16
|
+
- shadcn/ui primitives, already vendored under `@/components/ui/*`.
|
|
17
|
+
Common primitives available: `Button`, `Card` (with `CardHeader`,
|
|
18
|
+
`CardTitle`, `CardDescription`, `CardContent`, `CardFooter`),
|
|
19
|
+
`Input`, `Label`, `Table` (`TableHeader`, `TableBody`, `TableHead`,
|
|
20
|
+
`TableRow`, `TableCell`, `TableCaption`), `Dialog`, `Sheet`,
|
|
21
|
+
`Tabs`, `Select`, `Pagination`, `Badge`, `Skeleton`. Compose them.
|
|
22
|
+
- Tailwind utilities for layout and spacing. The CSS variables behind
|
|
23
|
+
shadcn (`--background`, `--foreground`, `--primary`, …) are
|
|
24
|
+
configured in `globals.css`. Stick to the design tokens unless the
|
|
25
|
+
design theme asks for otherwise.
|
|
26
|
+
- TypeScript strict. No `any` cast that isn't justified by the SDK
|
|
27
|
+
surface. Use the SDK's exported types directly.
|
|
28
|
+
|
|
29
|
+
## SDK access
|
|
30
|
+
|
|
31
|
+
The bundled SDK adapter exposes the AutoBE-generated API like this:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import api from "@/src/api";
|
|
35
|
+
import { connection } from "@/src/lib/connection";
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Every accessor takes **`(connection, props)`**. The shape of `props` is
|
|
39
|
+
fixed by Nestia and **must** match the operation's path parameters and
|
|
40
|
+
request body. Getting this wrong is the single most common AutoView
|
|
41
|
+
runtime defect, so read this section carefully before writing any
|
|
42
|
+
fetch.
|
|
43
|
+
|
|
44
|
+
### Nestia `props` shape — derive it from the operation, never guess
|
|
45
|
+
|
|
46
|
+
For each operation listed in the screen's `endpoints`, the operation
|
|
47
|
+
payload (passed to you in the prompt) carries `parameters` (path
|
|
48
|
+
parameters) and `requestBody` (body schema). Translate them into
|
|
49
|
+
`props` deterministically:
|
|
50
|
+
|
|
51
|
+
| Operation shape | `props` shape |
|
|
52
|
+
| ------------------------------------------------------------- | ---------------------------------------------- |
|
|
53
|
+
| Path parameters only (GET / DELETE, e.g. `at`, `erase`) | `{ paramA, paramB }` |
|
|
54
|
+
| Body only (POST / PATCH / PUT at root, e.g. `index`, `create` at `/sales`) | `{ body: { ... } }` |
|
|
55
|
+
| Path + body (PUT / PATCH / POST under `/.../:id`) | `{ id, body: { ... } }` |
|
|
56
|
+
| Multiple path params + body | `{ saleId, questionId, body: { ... } }` |
|
|
57
|
+
| No params, no body | `{}` (rare; only when `parameters` is empty AND `requestBody` is `null`) |
|
|
58
|
+
|
|
59
|
+
Concrete examples that match the real shopping SDK exactly:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
// PATCH /sales (list). `requestBody` is `IShoppingSale.IRequest`,
|
|
63
|
+
// `parameters` is empty → wrap the search fields under `body`.
|
|
64
|
+
const sales = await api.functional.shoppings.customers.sales.index(
|
|
65
|
+
connection,
|
|
66
|
+
{ body: { page: 1, limit: 24, search: { title: "macbook" } } },
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// GET /sales/:id. `parameters` has `id`, `requestBody` is null →
|
|
70
|
+
// pass the path param at the top level, no `body`.
|
|
71
|
+
const sale = await api.functional.shoppings.customers.sales.at(
|
|
72
|
+
connection,
|
|
73
|
+
{ id: saleId },
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// POST /sales/:saleId/reviews. `parameters` has `saleId`,
|
|
77
|
+
// `requestBody` is `IShoppingReview.ICreate` → both at the top.
|
|
78
|
+
const review = await api.functional.shoppings.customers.sales.reviews.create(
|
|
79
|
+
connection,
|
|
80
|
+
{ saleId, body: { score: 5, title: "great", body: "loved it" } },
|
|
81
|
+
);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Never** put body fields at the top level of `props`. Writing
|
|
85
|
+
`api.functional.sales.index(connection, { limit: 24 })` looks intuitive
|
|
86
|
+
but passes `undefined` as `props.body`; in simulate mode the SDK's
|
|
87
|
+
typia.assert rejects the call, the simulator returns a 400 error
|
|
88
|
+
masked as the success Response shape, and the UI silently renders the
|
|
89
|
+
empty state because `.data` ends up as an error object whose `.length`
|
|
90
|
+
is undefined. Always wrap.
|
|
91
|
+
|
|
92
|
+
Likewise, **never** pass `{}` (or `{ body: {} }`) to an endpoint whose
|
|
93
|
+
`requestBody` schema declares required fields. The prompt context
|
|
94
|
+
includes a "Body required-fields hint" block that lists every required
|
|
95
|
+
key per endpoint plus a sample literal — copy the sample shape as the
|
|
96
|
+
starting `body` and only override the fields you actually need:
|
|
97
|
+
|
|
98
|
+
- `cart create` requires `commodity_ids` and `pseudos` — pass
|
|
99
|
+
`{ body: { commodity_ids: [], pseudos: [] } }` when the user has not
|
|
100
|
+
added anything yet, then mutate as they click "Add to cart". Never
|
|
101
|
+
send an empty body that fails validation immediately on mount.
|
|
102
|
+
- List endpoints (`index`) with required `page` / `limit` — pass
|
|
103
|
+
`{ body: { page: 1, limit: 24 } }`. Even when you do not want a
|
|
104
|
+
filter, the body has to satisfy the schema.
|
|
105
|
+
|
|
106
|
+
If a required field is genuinely unknown at the call site (e.g. an
|
|
107
|
+
opaque id the user has not selected yet), do not issue the SDK call —
|
|
108
|
+
gate it behind the user action that produces the id, and render an
|
|
109
|
+
informative empty state until then.
|
|
110
|
+
|
|
111
|
+
Use exactly the accessor paths listed in the screen's `endpoints` array
|
|
112
|
+
— do not invent helpers or new accessors. The connection has
|
|
113
|
+
`simulate: true` wired by default, so the calls will work offline.
|
|
114
|
+
|
|
115
|
+
## Data fetching
|
|
116
|
+
|
|
117
|
+
- `useEffect` + `useState`. Each `endpoints[]` entry maps to one async
|
|
118
|
+
call. Run them in parallel with `Promise.all` unless one depends on
|
|
119
|
+
another.
|
|
120
|
+
- Always handle four states: `loading`, `error`, `empty`, and `data`.
|
|
121
|
+
Show a `Skeleton` block during loading, a destructive `Card` for
|
|
122
|
+
errors with a `Retry` button, an empty state with a one-line
|
|
123
|
+
explanation when the list comes back empty, and the real UI when
|
|
124
|
+
data is present.
|
|
125
|
+
- Surface server error messages from `instanceof HttpError`-style
|
|
126
|
+
catches. Never silently swallow.
|
|
127
|
+
|
|
128
|
+
### Use SDK types directly — infer them, never hand-write them
|
|
129
|
+
|
|
130
|
+
The SDK's returned objects are typia-validated and exactly match the
|
|
131
|
+
generated types. When `simulate: true`, `typia.random<T>()` produces
|
|
132
|
+
mocks that follow those types byte-for-byte. The trap is that AutoBE's
|
|
133
|
+
OpenAPI inverter sometimes emits the page shape as a **monomorphized**
|
|
134
|
+
type (e.g. `IPageIShoppingSale.ISummary`) instead of a generic
|
|
135
|
+
`IPage<T>`. Importing `IPage` and writing `IPage<IShoppingSale.ISummary>`
|
|
136
|
+
will compile but `IPage` resolves to an empty namespace at runtime, so
|
|
137
|
+
`useState<IPage<...> | null>(null)` produces a mock whose `.data`
|
|
138
|
+
field is `undefined` and the page crashes with
|
|
139
|
+
`.filter is not a function`.
|
|
140
|
+
|
|
141
|
+
The bulletproof pattern is to let TypeScript infer the response type
|
|
142
|
+
from the SDK function itself, not to hand-write the type name:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
type SalesResponse = Awaited<
|
|
146
|
+
ReturnType<typeof api.functional.shoppings.customers.sales.index>
|
|
147
|
+
>;
|
|
148
|
+
const [sales, setSales] = useState<SalesResponse | null>(null);
|
|
149
|
+
// ...
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
api.functional.shoppings.customers.sales
|
|
152
|
+
.index(connection, { body: { page: 1, limit: 24 } })
|
|
153
|
+
.then(setSales);
|
|
154
|
+
}, []);
|
|
155
|
+
// `sales.data` is now correctly typed as `IShoppingSale.ISummary[]`
|
|
156
|
+
// regardless of whether the SDK names the page `IPage<T>` or
|
|
157
|
+
// `IPageIShoppingSale.ISummary`.
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Use the `Awaited<ReturnType<typeof api.functional.xxx>>` pattern for
|
|
161
|
+
every SDK call — list endpoints and detail endpoints alike. It is
|
|
162
|
+
robust against the inverter's naming choices.
|
|
163
|
+
|
|
164
|
+
Other ironclad rules:
|
|
165
|
+
|
|
166
|
+
- Do not hand-type the response as `IPage<X>` unless you have
|
|
167
|
+
confirmed via the inference pattern that the SDK actually exposes
|
|
168
|
+
that generic. In most AutoBE-generated archives it does not.
|
|
169
|
+
- Never widen with `as AnyPage<T>` / `as Record<string, unknown>` /
|
|
170
|
+
`as { data?: T[] }` etc. Broad casts lose the type and push you
|
|
171
|
+
into runtime guard code that crashes when the mock shape does not
|
|
172
|
+
match your guess.
|
|
173
|
+
- Never write fallback chains like
|
|
174
|
+
`page?.data ?? page?.items ?? page?.rows ?? []`. The SDK never
|
|
175
|
+
returns `items` or `rows` — only `data`. The fallback only fires
|
|
176
|
+
when your type assumption is already wrong, and it hides the real
|
|
177
|
+
defect behind a `.filter is not a function` runtime error.
|
|
178
|
+
- Never wrap a response in a helper that returns `unknown[]`. Type
|
|
179
|
+
the state with the inferred response type and call
|
|
180
|
+
`.data.filter(...)` / `.data.map(...)` directly.
|
|
181
|
+
- Never write `as never`, `as unknown as X`, or `as any` to push a
|
|
182
|
+
value past the type checker. These casts lie about the SDK shape
|
|
183
|
+
and always break at runtime. The only allowed escape is `as const`
|
|
184
|
+
on inline literals.
|
|
185
|
+
- Never combine optional chaining with a direct method call:
|
|
186
|
+
`sale?.units.find(...)`, `cart?.items.map(...)`, `page?.data.reduce(...)`.
|
|
187
|
+
When `sale` is `undefined` the whole expression evaluates to
|
|
188
|
+
`undefined`, but TypeScript stops checking the `.units` access at
|
|
189
|
+
the `?.` and lets the `.find` slip through. At runtime the page
|
|
190
|
+
crashes with `Cannot read properties of undefined (reading 'find')`
|
|
191
|
+
even though `tsc --noEmit` was green. The two safe shapes are
|
|
192
|
+
`(sale?.units ?? []).find(...)` (when you want the empty fallback)
|
|
193
|
+
and `sale?.units?.find(...)` (when you want the whole expression
|
|
194
|
+
to short-circuit to `undefined`). Use the empty-array form for any
|
|
195
|
+
array you immediately render or count; use the `?.` form when the
|
|
196
|
+
result feeds another optional chain. The same rule covers
|
|
197
|
+
`.map / .filter / .reduce / .some / .every / .forEach / .slice /
|
|
198
|
+
.sort / .at` on arrays and `Object.keys / Object.entries /
|
|
199
|
+
Object.values` on objects: `(obj?.things ?? {})` before
|
|
200
|
+
`Object.keys`.
|
|
201
|
+
- The same rule applies to **multi-step** property chains:
|
|
202
|
+
`order?.summary.ticket_payments[0]` crashes when `summary` is
|
|
203
|
+
`undefined` because the optional chain stops at `order?.` and the
|
|
204
|
+
`.summary.ticket_payments[0]` access slips through. Apply `?.` to
|
|
205
|
+
every nullable hop, not just the first: write
|
|
206
|
+
`order?.summary?.ticket_payments?.[0]` (note the `?.[` for the
|
|
207
|
+
index), or guard the parent once with
|
|
208
|
+
`const summary = order?.summary; if (summary === undefined) return …;`
|
|
209
|
+
before the array read. The runtime audit catches dozens of these
|
|
210
|
+
per shopping run when the rule is only applied to the first hop.
|
|
211
|
+
- Never call a `setState` (`setX(...)`, `dispatch(...)`,
|
|
212
|
+
`useTransition` start, etc.) directly inside the render body. React
|
|
213
|
+
throws "Cannot update a component while rendering a different
|
|
214
|
+
component" and the page crashes after the first render. Common
|
|
215
|
+
triggers and fixes:
|
|
216
|
+
- Computing derived state? Use `useMemo`, not `setState` inside the
|
|
217
|
+
body.
|
|
218
|
+
- Reacting to a prop change? Use `useEffect(() => { setX(...); },
|
|
219
|
+
[prop])`.
|
|
220
|
+
- Bailing out early on bad data? Render a fallback `<>...</>`
|
|
221
|
+
directly — do **not** call `setError(...)` mid-render.
|
|
222
|
+
- Need to sync with an external store? Use `useSyncExternalStore`
|
|
223
|
+
or move the side effect into `useEffect`.
|
|
224
|
+
Setter calls are always either inside an event handler, inside a
|
|
225
|
+
`useEffect` (or its return), or inside a `useMemo`/`useCallback`
|
|
226
|
+
dependency-aware factory — never at the top level of the component
|
|
227
|
+
function.
|
|
228
|
+
|
|
229
|
+
If the screen's accessor returns a single object (not a page), the
|
|
230
|
+
same inference pattern works — `type SaleResponse = Awaited<ReturnType<
|
|
231
|
+
typeof api.functional.shoppings.customers.sales.at>>` and
|
|
232
|
+
`useState<SaleResponse | null>(null)`.
|
|
233
|
+
|
|
234
|
+
### Retry, refetch, and pagination handlers must produce new values
|
|
235
|
+
|
|
236
|
+
State setters in click handlers must change the state. Patterns like
|
|
237
|
+
`onClick={() => setPage((p) => p)}` or `onClick={() => setData(data)}`
|
|
238
|
+
do nothing — the user clicks "Retry" and the page does not reset.
|
|
239
|
+
Concrete rules:
|
|
240
|
+
|
|
241
|
+
- Retry buttons reset to the initial state and re-run the load
|
|
242
|
+
effect: `setError(null); setLoading(true); setPage(1); refresh();`.
|
|
243
|
+
- Pagination buttons update to the new page: `setPage(page + 1)` /
|
|
244
|
+
`setPage(page - 1)`. Never `setPage((p) => p)`.
|
|
245
|
+
- Refresh / refetch buttons should trigger the same `useEffect` that
|
|
246
|
+
the initial load uses — either via a bumped `refreshKey` state or a
|
|
247
|
+
dedicated `refresh()` callback.
|
|
248
|
+
|
|
249
|
+
## Rendering SDK objects — never dump, always pick named fields
|
|
250
|
+
|
|
251
|
+
The SDK returns typed objects. Render only the fields you can name
|
|
252
|
+
from the operation's `responseBody` and the schema (`name`, `title`,
|
|
253
|
+
`code`, `nickname`, `status`, `price`, `summary`, `created_at`, …). If
|
|
254
|
+
you do not know which field to show, choose `name ?? title ?? code ??
|
|
255
|
+
id` and stop — never reach for the whole object.
|
|
256
|
+
|
|
257
|
+
**Strict ban on object dumps in JSX**. The model has a strong tendency
|
|
258
|
+
to escape unknown shapes by writing `{JSON.stringify(item)}` (or
|
|
259
|
+
`item.toString()`, or `<pre>{JSON.stringify(item, null, 2)}</pre>`)
|
|
260
|
+
straight into a `Card` / `TableCell` / `div`. This is forbidden in
|
|
261
|
+
every form, including:
|
|
262
|
+
|
|
263
|
+
- `<div>{JSON.stringify(channel)}</div>`
|
|
264
|
+
- `<TableCell>{JSON.stringify(sale).slice(0, 60)}</TableCell>`
|
|
265
|
+
- `<pre>{JSON.stringify(channel, null, 2)}</pre>`
|
|
266
|
+
- `<span>{String(item)}</span>` for any non-primitive `item`
|
|
267
|
+
- `{`${item.id}: ${JSON.stringify(item)}`}`
|
|
268
|
+
|
|
269
|
+
The rendered page is a product surface, not a debug view. A page that
|
|
270
|
+
dumps JSON looks broken even when the data flowed correctly.
|
|
271
|
+
|
|
272
|
+
Allowed substitutes when the data is unfamiliar mock content:
|
|
273
|
+
|
|
274
|
+
- Pick the most identifying string field from the schema (`name`,
|
|
275
|
+
`title`, `nickname`, `code`) and show that.
|
|
276
|
+
- If multiple objects share the same shape, render them in a `Table`
|
|
277
|
+
with one column per known field plus a trailing "Details" link that
|
|
278
|
+
navigates to the detail page declared in the product plan.
|
|
279
|
+
- For truly opaque payloads (rare; only when the schema is `unknown`
|
|
280
|
+
or `Record<string, never>`), render a single muted line such as
|
|
281
|
+
"Imported entry · click Inspect to view raw fields" rather than the
|
|
282
|
+
JSON itself.
|
|
283
|
+
|
|
284
|
+
**Long string overflow**. Mock data from `typia.random()` regularly
|
|
285
|
+
produces 50+ character UUIDs, slugs, and base64-like values for `code`
|
|
286
|
+
/ `name` / `description` fields. Every string element you render from
|
|
287
|
+
the SDK must be wrapped with overflow controls so it cannot blow out
|
|
288
|
+
the column:
|
|
289
|
+
|
|
290
|
+
- Single-line cells / headers: add `truncate` (single line, ellipsis).
|
|
291
|
+
- Multi-line descriptions: add `line-clamp-2` or `line-clamp-3`.
|
|
292
|
+
- Free-form text inside cards: add `break-words` so long words wrap.
|
|
293
|
+
- Inside `<TableCell>`: combine `max-w-xs truncate` (or wider) so the
|
|
294
|
+
table layout stays within the container.
|
|
295
|
+
|
|
296
|
+
Skipping these classes produces the "horizontal scroll bar of doom"
|
|
297
|
+
that pushes the search bar and pagination buttons off-screen.
|
|
298
|
+
|
|
299
|
+
## Routing
|
|
300
|
+
|
|
301
|
+
- Dynamic params come from `useParams()` from `next/navigation`.
|
|
302
|
+
- Internal navigation uses `Link` from `next/link` or
|
|
303
|
+
`useRouter().push()`. No external links unless the SDK returns them
|
|
304
|
+
explicitly.
|
|
305
|
+
|
|
306
|
+
## Responsive shape
|
|
307
|
+
|
|
308
|
+
- Mobile-first. The page must be usable at 360px width.
|
|
309
|
+
- Use Tailwind responsive prefixes (`sm:`, `md:`, `lg:`) when laying
|
|
310
|
+
out grids, tables, or sidebars.
|
|
311
|
+
- Tables collapse to stacked cards on `sm` and below for shopping /
|
|
312
|
+
catalog-style flows; admin tables can stay tabular if the design
|
|
313
|
+
theme says enterprise.
|
|
314
|
+
|
|
315
|
+
## Forms
|
|
316
|
+
|
|
317
|
+
- `react-hook-form` is available — use it for any input with two or
|
|
318
|
+
more fields. Wire `Input` / `Select` / `Label` to the form state.
|
|
319
|
+
- Validate on submit, not on every keystroke (avoid flicker).
|
|
320
|
+
- Disable the submit button while the SDK call is in flight.
|
|
321
|
+
- Toast the result with a `Card` or inline `Badge` rather than
|
|
322
|
+
`alert()`.
|
|
323
|
+
|
|
324
|
+
## What the produced TSX MUST contain
|
|
325
|
+
|
|
326
|
+
- `"use client";` at the top.
|
|
327
|
+
- A single default export named `Page`.
|
|
328
|
+
- All imports resolved against `@/...` (alias for repo root) or
|
|
329
|
+
`next/*`.
|
|
330
|
+
- Real data wiring through the listed SDK endpoints, not fake static
|
|
331
|
+
arrays.
|
|
332
|
+
- All four UI states (loading / error / empty / data).
|
|
333
|
+
- Tailwind classes that satisfy the design theme. Empty design theme
|
|
334
|
+
means prototype-first, content-first defaults.
|
|
335
|
+
|
|
336
|
+
## What you must NOT produce
|
|
337
|
+
|
|
338
|
+
- Do not invent SDK accessors. Use what `endpoints[]` declares.
|
|
339
|
+
- Do not flatten request bodies into the top level of `props`. List
|
|
340
|
+
endpoints take `{ body: { page, limit, search, sort } }`, not
|
|
341
|
+
`{ page, limit, search, sort }`. Passing the flat shape causes the
|
|
342
|
+
simulator to return a masked 400 and the page renders the empty
|
|
343
|
+
state instead of data — see the "Nestia `props` shape" subsection.
|
|
344
|
+
- Do not pass an empty `{}` to a list endpoint. List endpoints have a
|
|
345
|
+
required `body`; the minimum is `{ body: { page: 1, limit: 24 } }`.
|
|
346
|
+
- Do not dump SDK objects with `JSON.stringify(item)`,
|
|
347
|
+
`String(item)`, `item.toString()`, or `<pre>{JSON.stringify(item,
|
|
348
|
+
null, 2)}</pre>` inside JSX. The page is a product surface, not a
|
|
349
|
+
debug view — see the "Rendering SDK objects" section above for the
|
|
350
|
+
allowed alternatives.
|
|
351
|
+
- Do not omit overflow controls on SDK-derived strings. Every
|
|
352
|
+
`<TableCell>` / `<div>` / `<span>` that prints a mock string needs
|
|
353
|
+
`truncate`, `line-clamp-N`, or `break-words` so a 60-character UUID
|
|
354
|
+
cannot push the layout off-screen.
|
|
355
|
+
- Do not import shadcn primitives the project does not ship. Stick to
|
|
356
|
+
the list above.
|
|
357
|
+
- Do not declare local `AnyPage<T>` / `AnyResponse` aliases or
|
|
358
|
+
`getItems()` helpers — see the "Use SDK types directly" rule above.
|
|
359
|
+
Import the SDK type and reach into `.data` straight away.
|
|
360
|
+
- Do not write `as never`, `as any`, or `as unknown as X`. These casts
|
|
361
|
+
silently break the SDK type contract and crash at runtime. The one
|
|
362
|
+
allowed escape is `as const` on inline literals.
|
|
363
|
+
- Do not write identity state updates like `setPage((p) => p)` or
|
|
364
|
+
`setData(data)` in retry / refetch / pagination handlers. Every
|
|
365
|
+
setter call must produce a new value — see the "Retry, refetch,
|
|
366
|
+
and pagination" rules under Data fetching.
|
|
367
|
+
- Do not write `a ?? b || c` or `a || b ?? c`. TC39 forbids mixing
|
|
368
|
+
`??` with `||` / `&&` without parentheses, and the parser will
|
|
369
|
+
reject the page. If you really need both, parenthesize explicitly:
|
|
370
|
+
`(a ?? b) || c`. Same rule applies inside JSX attribute values.
|
|
371
|
+
Easier: **avoid `??` in any expression that already contains `||`
|
|
372
|
+
or `&&`**. Use a ternary instead (e.g.
|
|
373
|
+
`(a !== null && a !== undefined) ? a : (b || c)`) or just chain
|
|
374
|
+
`||` everywhere. The retry loop will not save you here; pages that
|
|
375
|
+
mix `??` with `||` consistently get dropped to an error
|
|
376
|
+
placeholder.
|
|
377
|
+
- Do not link to backend / SDK accessor paths from `<Link>` or
|
|
378
|
+
`router.push()`. Those paths (e.g.
|
|
379
|
+
`/shoppings/customers/systematic/channels`, `/shoppings/customers/sales/:id`)
|
|
380
|
+
are HTTP endpoints, not Next.js routes. The product plan lists
|
|
381
|
+
every real frontend route in `screen.path`. Use only those —
|
|
382
|
+
`/catalog`, `/cart`, `/orders/[id]`, `/admin`, etc. Internal links
|
|
383
|
+
to anything else 404 the moment a user clicks them.
|
|
384
|
+
- Do not render `<Image />` from `next/image` for URLs the SDK
|
|
385
|
+
returns. The SDK mocks emit arbitrary hostnames and the optimizer
|
|
386
|
+
rejects them. Use a plain `<img />` tag for SDK-provided URLs, or
|
|
387
|
+
pass `unoptimized` on the `<Image />` element.
|
|
388
|
+
- Do not write Korean.
|
|
389
|
+
- Do not output anything except the function-call payload.
|
|
390
|
+
|
|
391
|
+
## Output
|
|
392
|
+
|
|
393
|
+
Call `renderPage` exactly once with the complete TSX source code as a
|
|
394
|
+
single string. The orchestrator runs the result through the TypeScript
|
|
395
|
+
parser; if it fails, you will be invoked again with the diagnostic and
|
|
396
|
+
a chance to repair it. Take the repair seriously — the most common LLM
|
|
397
|
+
errors are `??` mixed with `||` without parentheses, regex literals
|
|
398
|
+
with unescaped slashes, and unclosed JSX expression braces.
|