@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.
Files changed (297) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +407 -0
  3. package/lib/AutoViewAgent.d.ts +109 -0
  4. package/lib/AutoViewAgent.js +123 -0
  5. package/lib/AutoViewAgent.js.map +1 -0
  6. package/lib/agent/emitMcpServer.d.ts +15 -0
  7. package/lib/agent/emitMcpServer.js +157 -0
  8. package/lib/agent/emitMcpServer.js.map +1 -0
  9. package/lib/agent/emitReport.d.ts +14 -0
  10. package/lib/agent/emitReport.js +85 -0
  11. package/lib/agent/emitReport.js.map +1 -0
  12. package/lib/agent/toolSurface.d.ts +130 -0
  13. package/lib/agent/toolSurface.js +342 -0
  14. package/lib/agent/toolSurface.js.map +1 -0
  15. package/lib/agent/verifyAgentTasks.d.ts +87 -0
  16. package/lib/agent/verifyAgentTasks.js +126 -0
  17. package/lib/agent/verifyAgentTasks.js.map +1 -0
  18. package/lib/cli/main.d.ts +2 -0
  19. package/lib/cli/main.js +295 -0
  20. package/lib/cli/main.js.map +1 -0
  21. package/lib/compiler/AutoViewInterfaceCompiler.d.ts +27 -0
  22. package/lib/compiler/AutoViewInterfaceCompiler.js +68 -0
  23. package/lib/compiler/AutoViewInterfaceCompiler.js.map +1 -0
  24. package/lib/constants/AutoViewFrontendTemplate.d.ts +1 -0
  25. package/lib/constants/AutoViewFrontendTemplate.js +46 -0
  26. package/lib/constants/AutoViewFrontendTemplate.js.map +1 -0
  27. package/lib/constants/AutoViewSystemPromptConstant.d.ts +5 -0
  28. package/lib/constants/AutoViewSystemPromptConstant.js +4 -0
  29. package/lib/constants/AutoViewSystemPromptConstant.js.map +1 -0
  30. package/lib/context/IAutoViewAgentContext.d.ts +60 -0
  31. package/lib/context/IAutoViewAgentContext.js +3 -0
  32. package/lib/context/IAutoViewAgentContext.js.map +1 -0
  33. package/lib/fromSwagger.d.ts +53 -0
  34. package/lib/fromSwagger.js +513 -0
  35. package/lib/fromSwagger.js.map +1 -0
  36. package/lib/generateDeterministic.d.ts +26 -0
  37. package/lib/generateDeterministic.js +75 -0
  38. package/lib/generateDeterministic.js.map +1 -0
  39. package/lib/index.d.ts +15 -0
  40. package/lib/index.js +41 -0
  41. package/lib/index.js.map +1 -0
  42. package/lib/orchestrate/orchestrateAutoView.d.ts +17 -0
  43. package/lib/orchestrate/orchestrateAutoView.js +491 -0
  44. package/lib/orchestrate/orchestrateAutoView.js.map +1 -0
  45. package/lib/orchestrate/orchestrateAutoViewProductPlan.d.ts +37 -0
  46. package/lib/orchestrate/orchestrateAutoViewProductPlan.js +109 -0
  47. package/lib/orchestrate/orchestrateAutoViewProductPlan.js.map +1 -0
  48. package/lib/orchestrate/orchestrateAutoViewRender.d.ts +133 -0
  49. package/lib/orchestrate/orchestrateAutoViewRender.js +943 -0
  50. package/lib/orchestrate/orchestrateAutoViewRender.js.map +1 -0
  51. package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.d.ts +24 -0
  52. package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.js +92 -0
  53. package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.js.map +1 -0
  54. package/lib/orchestrate/orchestrateAutoViewReview.d.ts +48 -0
  55. package/lib/orchestrate/orchestrateAutoViewReview.js +328 -0
  56. package/lib/orchestrate/orchestrateAutoViewReview.js.map +1 -0
  57. package/lib/orchestrate/orchestrateAutoViewScaffold.d.ts +45 -0
  58. package/lib/orchestrate/orchestrateAutoViewScaffold.js +586 -0
  59. package/lib/orchestrate/orchestrateAutoViewScaffold.js.map +1 -0
  60. package/lib/orchestrate/orchestrateAutoViewSdkStudy.d.ts +26 -0
  61. package/lib/orchestrate/orchestrateAutoViewSdkStudy.js +85 -0
  62. package/lib/orchestrate/orchestrateAutoViewSdkStudy.js.map +1 -0
  63. package/lib/orchestrate/structures/IAutoViewProductPlan.d.ts +96 -0
  64. package/lib/orchestrate/structures/IAutoViewProductPlan.js +3 -0
  65. package/lib/orchestrate/structures/IAutoViewProductPlan.js.map +1 -0
  66. package/lib/orchestrate/structures/IAutoViewProductPlanApplication.d.ts +38 -0
  67. package/lib/orchestrate/structures/IAutoViewProductPlanApplication.js +3 -0
  68. package/lib/orchestrate/structures/IAutoViewProductPlanApplication.js.map +1 -0
  69. package/lib/orchestrate/structures/IAutoViewRenderApplication.d.ts +38 -0
  70. package/lib/orchestrate/structures/IAutoViewRenderApplication.js +3 -0
  71. package/lib/orchestrate/structures/IAutoViewRenderApplication.js.map +1 -0
  72. package/lib/orchestrate/structures/IAutoViewReviewApplication.d.ts +40 -0
  73. package/lib/orchestrate/structures/IAutoViewReviewApplication.js +3 -0
  74. package/lib/orchestrate/structures/IAutoViewReviewApplication.js.map +1 -0
  75. package/lib/orchestrate/structures/IAutoViewSdkMap.d.ts +63 -0
  76. package/lib/orchestrate/structures/IAutoViewSdkMap.js +3 -0
  77. package/lib/orchestrate/structures/IAutoViewSdkMap.js.map +1 -0
  78. package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.d.ts +37 -0
  79. package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.js +3 -0
  80. package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.js.map +1 -0
  81. package/lib/orchestrate/utils/HistoryMessage.d.ts +10 -0
  82. package/lib/orchestrate/utils/HistoryMessage.js +25 -0
  83. package/lib/orchestrate/utils/HistoryMessage.js.map +1 -0
  84. package/lib/orchestrate/utils/auditFrontendRuntime.d.ts +53 -0
  85. package/lib/orchestrate/utils/auditFrontendRuntime.js +362 -0
  86. package/lib/orchestrate/utils/auditFrontendRuntime.js.map +1 -0
  87. package/lib/orchestrate/utils/buildDeterministicPlan.d.ts +4 -0
  88. package/lib/orchestrate/utils/buildDeterministicPlan.js +233 -0
  89. package/lib/orchestrate/utils/buildDeterministicPlan.js.map +1 -0
  90. package/lib/orchestrate/utils/buildDeterministicSdkMap.d.ts +22 -0
  91. package/lib/orchestrate/utils/buildDeterministicSdkMap.js +154 -0
  92. package/lib/orchestrate/utils/buildDeterministicSdkMap.js.map +1 -0
  93. package/lib/orchestrate/utils/cacheNodeModules.d.ts +31 -0
  94. package/lib/orchestrate/utils/cacheNodeModules.js +134 -0
  95. package/lib/orchestrate/utils/cacheNodeModules.js.map +1 -0
  96. package/lib/orchestrate/utils/describeEndpointPropsShape.d.ts +37 -0
  97. package/lib/orchestrate/utils/describeEndpointPropsShape.js +192 -0
  98. package/lib/orchestrate/utils/describeEndpointPropsShape.js.map +1 -0
  99. package/lib/orchestrate/utils/describeEndpointRequestBodyShape.d.ts +22 -0
  100. package/lib/orchestrate/utils/describeEndpointRequestBodyShape.js +29 -0
  101. package/lib/orchestrate/utils/describeEndpointRequestBodyShape.js.map +1 -0
  102. package/lib/orchestrate/utils/describeEndpointResponseShape.d.ts +19 -0
  103. package/lib/orchestrate/utils/describeEndpointResponseShape.js +30 -0
  104. package/lib/orchestrate/utils/describeEndpointResponseShape.js.map +1 -0
  105. package/lib/orchestrate/utils/executeCachedBatch.d.ts +22 -0
  106. package/lib/orchestrate/utils/executeCachedBatch.js +64 -0
  107. package/lib/orchestrate/utils/executeCachedBatch.js.map +1 -0
  108. package/lib/orchestrate/utils/loadShoppingFixture.d.ts +33 -0
  109. package/lib/orchestrate/utils/loadShoppingFixture.js +17 -0
  110. package/lib/orchestrate/utils/loadShoppingFixture.js.map +1 -0
  111. package/lib/orchestrate/utils/normalizeProductPlanPaths.d.ts +24 -0
  112. package/lib/orchestrate/utils/normalizeProductPlanPaths.js +77 -0
  113. package/lib/orchestrate/utils/normalizeProductPlanPaths.js.map +1 -0
  114. package/lib/orchestrate/utils/renderJsonSchema.d.ts +23 -0
  115. package/lib/orchestrate/utils/renderJsonSchema.js +122 -0
  116. package/lib/orchestrate/utils/renderJsonSchema.js.map +1 -0
  117. package/lib/orchestrate/utils/renderResourcePage.d.ts +36 -0
  118. package/lib/orchestrate/utils/renderResourcePage.js +1415 -0
  119. package/lib/orchestrate/utils/renderResourcePage.js.map +1 -0
  120. package/lib/orchestrate/utils/validateFrontendTypecheck.d.ts +109 -0
  121. package/lib/orchestrate/utils/validateFrontendTypecheck.js +274 -0
  122. package/lib/orchestrate/utils/validateFrontendTypecheck.js.map +1 -0
  123. package/lib/preview/renderPreview.d.ts +22 -0
  124. package/lib/preview/renderPreview.js +198 -0
  125. package/lib/preview/renderPreview.js.map +1 -0
  126. package/lib/typings/compiler.d.ts +39 -0
  127. package/lib/typings/compiler.js +3 -0
  128. package/lib/typings/compiler.js.map +1 -0
  129. package/lib/typings/events.d.ts +106 -0
  130. package/lib/typings/events.js +3 -0
  131. package/lib/typings/events.js.map +1 -0
  132. package/lib/typings/index.d.ts +10 -0
  133. package/lib/typings/index.js +27 -0
  134. package/lib/typings/index.js.map +1 -0
  135. package/lib/typings/misc.d.ts +78 -0
  136. package/lib/typings/misc.js +3 -0
  137. package/lib/typings/misc.js.map +1 -0
  138. package/lib/utils/ArrayUtil.d.ts +8 -0
  139. package/lib/utils/ArrayUtil.js +30 -0
  140. package/lib/utils/ArrayUtil.js.map +1 -0
  141. package/lib/utils/StringUtil.d.ts +11 -0
  142. package/lib/utils/StringUtil.js +28 -0
  143. package/lib/utils/StringUtil.js.map +1 -0
  144. package/lib/utils/classifyEndpoints.d.ts +62 -0
  145. package/lib/utils/classifyEndpoints.js +216 -0
  146. package/lib/utils/classifyEndpoints.js.map +1 -0
  147. package/lib/utils/endpointFilter.d.ts +26 -0
  148. package/lib/utils/endpointFilter.js +0 -0
  149. package/lib/utils/endpointFilter.js.map +1 -0
  150. package/lib/utils/extractFields.d.ts +85 -0
  151. package/lib/utils/extractFields.js +231 -0
  152. package/lib/utils/extractFields.js.map +1 -0
  153. package/lib/utils/index.d.ts +13 -0
  154. package/lib/utils/index.js +30 -0
  155. package/lib/utils/index.js.map +1 -0
  156. package/lib/utils/normalizeForNestia.d.ts +34 -0
  157. package/lib/utils/normalizeForNestia.js +133 -0
  158. package/lib/utils/normalizeForNestia.js.map +1 -0
  159. package/lib/utils/resourcePlan.d.ts +39 -0
  160. package/lib/utils/resourcePlan.js +95 -0
  161. package/lib/utils/resourcePlan.js.map +1 -0
  162. package/lib/utils/sliceDocument.d.ts +17 -0
  163. package/lib/utils/sliceDocument.js +114 -0
  164. package/lib/utils/sliceDocument.js.map +1 -0
  165. package/lib/utils/toEndpoints.d.ts +90 -0
  166. package/lib/utils/toEndpoints.js +227 -0
  167. package/lib/utils/toEndpoints.js.map +1 -0
  168. package/lib/verify/runWorkflows.d.ts +25 -0
  169. package/lib/verify/runWorkflows.js +366 -0
  170. package/lib/verify/runWorkflows.js.map +1 -0
  171. package/lib/verify/workflows.d.ts +53 -0
  172. package/lib/verify/workflows.js +107 -0
  173. package/lib/verify/workflows.js.map +1 -0
  174. package/package.json +82 -0
  175. package/prompts/AUTOVIEW_RENDER.md +398 -0
  176. package/prompts/AUTOVIEW_REVIEW.md +60 -0
  177. package/prompts/AUTOVIEW_SDK_STUDY.md +89 -0
  178. package/src/AutoViewAgent.ts +222 -0
  179. package/src/agent/emitMcpServer.integration.test.ts +168 -0
  180. package/src/agent/emitMcpServer.test.ts +51 -0
  181. package/src/agent/emitMcpServer.ts +178 -0
  182. package/src/agent/emitReport.ts +117 -0
  183. package/src/agent/toolSurface.test.ts +243 -0
  184. package/src/agent/toolSurface.ts +501 -0
  185. package/src/agent/verifyAgentTasks.test.ts +106 -0
  186. package/src/agent/verifyAgentTasks.ts +171 -0
  187. package/src/cli/main.ts +363 -0
  188. package/src/compiler/AutoViewInterfaceCompiler.ts +69 -0
  189. package/src/constants/AutoViewFrontendTemplate.ts +42 -0
  190. package/src/constants/AutoViewSystemPromptConstant.ts +6 -0
  191. package/src/context/IAutoViewAgentContext.ts +84 -0
  192. package/src/fromSwagger.test.ts +269 -0
  193. package/src/fromSwagger.ts +500 -0
  194. package/src/generateDeterministic.test.ts +39 -0
  195. package/src/generateDeterministic.ts +77 -0
  196. package/src/index.ts +30 -0
  197. package/src/orchestrate/orchestrateAutoView.ts +590 -0
  198. package/src/orchestrate/orchestrateAutoViewProductPlan.ts +121 -0
  199. package/src/orchestrate/orchestrateAutoViewRender.ts +1117 -0
  200. package/src/orchestrate/orchestrateAutoViewRenderDeterministic.ts +101 -0
  201. package/src/orchestrate/orchestrateAutoViewReview.ts +272 -0
  202. package/src/orchestrate/orchestrateAutoViewScaffold.ts +627 -0
  203. package/src/orchestrate/orchestrateAutoViewSdkStudy.ts +90 -0
  204. package/src/orchestrate/renderNavTs.test.ts +74 -0
  205. package/src/orchestrate/structures/IAutoViewProductPlan.ts +119 -0
  206. package/src/orchestrate/structures/IAutoViewProductPlanApplication.ts +41 -0
  207. package/src/orchestrate/structures/IAutoViewRenderApplication.ts +40 -0
  208. package/src/orchestrate/structures/IAutoViewReviewApplication.ts +42 -0
  209. package/src/orchestrate/structures/IAutoViewSdkMap.ts +72 -0
  210. package/src/orchestrate/structures/IAutoViewSdkStudyApplication.ts +40 -0
  211. package/src/orchestrate/utils/HistoryMessage.ts +41 -0
  212. package/src/orchestrate/utils/auditFrontendRuntime.test.ts +18 -0
  213. package/src/orchestrate/utils/auditFrontendRuntime.ts +454 -0
  214. package/src/orchestrate/utils/buildDeterministicPlan.test.ts +170 -0
  215. package/src/orchestrate/utils/buildDeterministicPlan.ts +289 -0
  216. package/src/orchestrate/utils/buildDeterministicSdkMap.test.ts +90 -0
  217. package/src/orchestrate/utils/buildDeterministicSdkMap.ts +169 -0
  218. package/src/orchestrate/utils/cacheNodeModules.ts +136 -0
  219. package/src/orchestrate/utils/describeEndpointPropsShape.test.ts +86 -0
  220. package/src/orchestrate/utils/describeEndpointPropsShape.ts +202 -0
  221. package/src/orchestrate/utils/describeEndpointRequestBodyShape.test.ts +87 -0
  222. package/src/orchestrate/utils/describeEndpointRequestBodyShape.ts +31 -0
  223. package/src/orchestrate/utils/describeEndpointResponseShape.test.ts +70 -0
  224. package/src/orchestrate/utils/describeEndpointResponseShape.ts +32 -0
  225. package/src/orchestrate/utils/executeCachedBatch.ts +59 -0
  226. package/src/orchestrate/utils/loadShoppingFixture.ts +52 -0
  227. package/src/orchestrate/utils/normalizeProductPlanPaths.ts +92 -0
  228. package/src/orchestrate/utils/renderJsonSchema.test.ts +162 -0
  229. package/src/orchestrate/utils/renderJsonSchema.ts +133 -0
  230. package/src/orchestrate/utils/renderResourcePage.test.ts +468 -0
  231. package/src/orchestrate/utils/renderResourcePage.ts +1624 -0
  232. package/src/orchestrate/utils/validateFrontendTypecheck.test.ts +32 -0
  233. package/src/orchestrate/utils/validateFrontendTypecheck.ts +335 -0
  234. package/src/preview/renderPreview.ts +273 -0
  235. package/src/typings/compiler.ts +47 -0
  236. package/src/typings/events.ts +155 -0
  237. package/src/typings/index.ts +10 -0
  238. package/src/typings/misc.ts +93 -0
  239. package/src/utils/ArrayUtil.ts +16 -0
  240. package/src/utils/StringUtil.ts +29 -0
  241. package/src/utils/classifyEndpoints.test.ts +86 -0
  242. package/src/utils/classifyEndpoints.ts +291 -0
  243. package/src/utils/endpointFilter.test.ts +50 -0
  244. package/src/utils/endpointFilter.ts +0 -0
  245. package/src/utils/extractFields.test.ts +82 -0
  246. package/src/utils/extractFields.ts +306 -0
  247. package/src/utils/index.ts +13 -0
  248. package/src/utils/normalizeForNestia.test.ts +93 -0
  249. package/src/utils/normalizeForNestia.ts +139 -0
  250. package/src/utils/resourcePlan.test.ts +104 -0
  251. package/src/utils/resourcePlan.ts +180 -0
  252. package/src/utils/sliceDocument.test.ts +85 -0
  253. package/src/utils/sliceDocument.ts +119 -0
  254. package/src/utils/toEndpoints.test.ts +251 -0
  255. package/src/utils/toEndpoints.ts +343 -0
  256. package/src/verify/runWorkflows.ts +403 -0
  257. package/src/verify/workflows.test.ts +117 -0
  258. package/src/verify/workflows.ts +154 -0
  259. package/template/CLAUDE.md +140 -0
  260. package/template/Dockerfile +31 -0
  261. package/template/PROMPT.md +80 -0
  262. package/template/SANDBOX.md +70 -0
  263. package/template/app/api/health/route.ts +10 -0
  264. package/template/app/globals.css +97 -0
  265. package/template/app/layout.tsx +30 -0
  266. package/template/app/page.tsx +19 -0
  267. package/template/components/AppShell.tsx +114 -0
  268. package/template/components/auto/CatalogGrid.tsx +159 -0
  269. package/template/components/auto/ConfirmButton.tsx +67 -0
  270. package/template/components/auto/EmbeddedCollection.tsx +144 -0
  271. package/template/components/auto/ResourceDashboard.tsx +104 -0
  272. package/template/components/auto/ResourceDetail.tsx +93 -0
  273. package/template/components/auto/ResourceForm.tsx +235 -0
  274. package/template/components/auto/ResourceIcon.tsx +88 -0
  275. package/template/components/auto/ResourceLanding.tsx +155 -0
  276. package/template/components/auto/ResourceTable.tsx +223 -0
  277. package/template/components/auto/formatValue.tsx +186 -0
  278. package/template/components/auto/types.ts +42 -0
  279. package/template/components/ui/badge.tsx +40 -0
  280. package/template/components/ui/button.tsx +57 -0
  281. package/template/components/ui/card.tsx +86 -0
  282. package/template/components/ui/dialog.tsx +119 -0
  283. package/template/components/ui/input.tsx +23 -0
  284. package/template/components/ui/label.tsx +24 -0
  285. package/template/components/ui/pagination.tsx +117 -0
  286. package/template/components/ui/select.tsx +92 -0
  287. package/template/components/ui/sheet.tsx +135 -0
  288. package/template/components/ui/skeleton.tsx +15 -0
  289. package/template/components/ui/table.tsx +120 -0
  290. package/template/components/ui/tabs.tsx +55 -0
  291. package/template/lib/utils.ts +35 -0
  292. package/template/next.config.mjs +52 -0
  293. package/template/package.json +46 -0
  294. package/template/postcss.config.js +6 -0
  295. package/template/scripts/start-shopping-backend.sh +56 -0
  296. package/template/tailwind.config.ts +96 -0
  297. 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.