amd-gaia 0.14.1__py3-none-any.whl

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 (800) hide show
  1. amd_gaia-0.14.1.dist-info/METADATA +768 -0
  2. amd_gaia-0.14.1.dist-info/RECORD +800 -0
  3. amd_gaia-0.14.1.dist-info/WHEEL +5 -0
  4. amd_gaia-0.14.1.dist-info/entry_points.txt +5 -0
  5. amd_gaia-0.14.1.dist-info/licenses/LICENSE.md +21 -0
  6. amd_gaia-0.14.1.dist-info/top_level.txt +1 -0
  7. gaia/__init__.py +2 -0
  8. gaia/agents/__init__.py +19 -0
  9. gaia/agents/base/__init__.py +9 -0
  10. gaia/agents/base/agent.py +2072 -0
  11. gaia/agents/base/api_agent.py +120 -0
  12. gaia/agents/base/console.py +1457 -0
  13. gaia/agents/base/mcp_agent.py +86 -0
  14. gaia/agents/base/tools.py +83 -0
  15. gaia/agents/blender/agent.py +556 -0
  16. gaia/agents/blender/agent_simple.py +135 -0
  17. gaia/agents/blender/app.py +211 -0
  18. gaia/agents/blender/app_simple.py +41 -0
  19. gaia/agents/blender/core/__init__.py +16 -0
  20. gaia/agents/blender/core/materials.py +506 -0
  21. gaia/agents/blender/core/objects.py +316 -0
  22. gaia/agents/blender/core/rendering.py +225 -0
  23. gaia/agents/blender/core/scene.py +220 -0
  24. gaia/agents/blender/core/view.py +146 -0
  25. gaia/agents/chat/__init__.py +9 -0
  26. gaia/agents/chat/agent.py +975 -0
  27. gaia/agents/chat/app.py +1058 -0
  28. gaia/agents/chat/session.py +508 -0
  29. gaia/agents/chat/tools/__init__.py +15 -0
  30. gaia/agents/chat/tools/file_tools.py +96 -0
  31. gaia/agents/chat/tools/rag_tools.py +1729 -0
  32. gaia/agents/chat/tools/shell_tools.py +436 -0
  33. gaia/agents/code/__init__.py +7 -0
  34. gaia/agents/code/agent.py +547 -0
  35. gaia/agents/code/app.py +266 -0
  36. gaia/agents/code/models.py +135 -0
  37. gaia/agents/code/orchestration/__init__.py +24 -0
  38. gaia/agents/code/orchestration/checklist_executor.py +1739 -0
  39. gaia/agents/code/orchestration/checklist_generator.py +709 -0
  40. gaia/agents/code/orchestration/factories/__init__.py +9 -0
  41. gaia/agents/code/orchestration/factories/base.py +63 -0
  42. gaia/agents/code/orchestration/factories/nextjs_factory.py +118 -0
  43. gaia/agents/code/orchestration/factories/python_factory.py +106 -0
  44. gaia/agents/code/orchestration/orchestrator.py +610 -0
  45. gaia/agents/code/orchestration/project_analyzer.py +391 -0
  46. gaia/agents/code/orchestration/steps/__init__.py +67 -0
  47. gaia/agents/code/orchestration/steps/base.py +188 -0
  48. gaia/agents/code/orchestration/steps/error_handler.py +314 -0
  49. gaia/agents/code/orchestration/steps/nextjs.py +828 -0
  50. gaia/agents/code/orchestration/steps/python.py +307 -0
  51. gaia/agents/code/orchestration/template_catalog.py +463 -0
  52. gaia/agents/code/orchestration/workflows/__init__.py +14 -0
  53. gaia/agents/code/orchestration/workflows/base.py +80 -0
  54. gaia/agents/code/orchestration/workflows/nextjs.py +186 -0
  55. gaia/agents/code/orchestration/workflows/python.py +94 -0
  56. gaia/agents/code/prompts/__init__.py +11 -0
  57. gaia/agents/code/prompts/base_prompt.py +77 -0
  58. gaia/agents/code/prompts/code_patterns.py +1925 -0
  59. gaia/agents/code/prompts/nextjs_prompt.py +40 -0
  60. gaia/agents/code/prompts/python_prompt.py +109 -0
  61. gaia/agents/code/schema_inference.py +365 -0
  62. gaia/agents/code/system_prompt.py +41 -0
  63. gaia/agents/code/tools/__init__.py +42 -0
  64. gaia/agents/code/tools/cli_tools.py +1138 -0
  65. gaia/agents/code/tools/code_formatting.py +319 -0
  66. gaia/agents/code/tools/code_tools.py +769 -0
  67. gaia/agents/code/tools/error_fixing.py +1347 -0
  68. gaia/agents/code/tools/external_tools.py +180 -0
  69. gaia/agents/code/tools/file_io.py +845 -0
  70. gaia/agents/code/tools/prisma_tools.py +190 -0
  71. gaia/agents/code/tools/project_management.py +1016 -0
  72. gaia/agents/code/tools/testing.py +321 -0
  73. gaia/agents/code/tools/typescript_tools.py +122 -0
  74. gaia/agents/code/tools/validation_parsing.py +461 -0
  75. gaia/agents/code/tools/validation_tools.py +803 -0
  76. gaia/agents/code/tools/web_dev_tools.py +1744 -0
  77. gaia/agents/code/validators/__init__.py +16 -0
  78. gaia/agents/code/validators/antipattern_checker.py +241 -0
  79. gaia/agents/code/validators/ast_analyzer.py +197 -0
  80. gaia/agents/code/validators/requirements_validator.py +145 -0
  81. gaia/agents/code/validators/syntax_validator.py +171 -0
  82. gaia/agents/docker/__init__.py +7 -0
  83. gaia/agents/docker/agent.py +642 -0
  84. gaia/agents/jira/__init__.py +11 -0
  85. gaia/agents/jira/agent.py +894 -0
  86. gaia/agents/jira/jql_templates.py +299 -0
  87. gaia/agents/routing/__init__.py +7 -0
  88. gaia/agents/routing/agent.py +512 -0
  89. gaia/agents/routing/system_prompt.py +75 -0
  90. gaia/api/__init__.py +23 -0
  91. gaia/api/agent_registry.py +238 -0
  92. gaia/api/app.py +305 -0
  93. gaia/api/openai_server.py +575 -0
  94. gaia/api/schemas.py +186 -0
  95. gaia/api/sse_handler.py +370 -0
  96. gaia/apps/__init__.py +4 -0
  97. gaia/apps/llm/__init__.py +6 -0
  98. gaia/apps/llm/app.py +169 -0
  99. gaia/apps/summarize/app.py +633 -0
  100. gaia/apps/summarize/html_viewer.py +133 -0
  101. gaia/apps/summarize/pdf_formatter.py +284 -0
  102. gaia/audio/__init__.py +2 -0
  103. gaia/audio/audio_client.py +439 -0
  104. gaia/audio/audio_recorder.py +269 -0
  105. gaia/audio/kokoro_tts.py +599 -0
  106. gaia/audio/whisper_asr.py +432 -0
  107. gaia/chat/__init__.py +16 -0
  108. gaia/chat/app.py +430 -0
  109. gaia/chat/prompts.py +522 -0
  110. gaia/chat/sdk.py +1200 -0
  111. gaia/cli.py +5621 -0
  112. gaia/eval/batch_experiment.py +2332 -0
  113. gaia/eval/claude.py +542 -0
  114. gaia/eval/config.py +37 -0
  115. gaia/eval/email_generator.py +512 -0
  116. gaia/eval/eval.py +3179 -0
  117. gaia/eval/groundtruth.py +1130 -0
  118. gaia/eval/transcript_generator.py +582 -0
  119. gaia/eval/webapp/README.md +168 -0
  120. gaia/eval/webapp/node_modules/.bin/mime +16 -0
  121. gaia/eval/webapp/node_modules/.bin/mime.cmd +17 -0
  122. gaia/eval/webapp/node_modules/.bin/mime.ps1 +28 -0
  123. gaia/eval/webapp/node_modules/.package-lock.json +865 -0
  124. gaia/eval/webapp/node_modules/accepts/HISTORY.md +243 -0
  125. gaia/eval/webapp/node_modules/accepts/LICENSE +23 -0
  126. gaia/eval/webapp/node_modules/accepts/README.md +140 -0
  127. gaia/eval/webapp/node_modules/accepts/index.js +238 -0
  128. gaia/eval/webapp/node_modules/accepts/package.json +47 -0
  129. gaia/eval/webapp/node_modules/array-flatten/LICENSE +21 -0
  130. gaia/eval/webapp/node_modules/array-flatten/README.md +43 -0
  131. gaia/eval/webapp/node_modules/array-flatten/array-flatten.js +64 -0
  132. gaia/eval/webapp/node_modules/array-flatten/package.json +39 -0
  133. gaia/eval/webapp/node_modules/body-parser/HISTORY.md +672 -0
  134. gaia/eval/webapp/node_modules/body-parser/LICENSE +23 -0
  135. gaia/eval/webapp/node_modules/body-parser/README.md +476 -0
  136. gaia/eval/webapp/node_modules/body-parser/SECURITY.md +25 -0
  137. gaia/eval/webapp/node_modules/body-parser/index.js +156 -0
  138. gaia/eval/webapp/node_modules/body-parser/lib/read.js +205 -0
  139. gaia/eval/webapp/node_modules/body-parser/lib/types/json.js +247 -0
  140. gaia/eval/webapp/node_modules/body-parser/lib/types/raw.js +101 -0
  141. gaia/eval/webapp/node_modules/body-parser/lib/types/text.js +121 -0
  142. gaia/eval/webapp/node_modules/body-parser/lib/types/urlencoded.js +307 -0
  143. gaia/eval/webapp/node_modules/body-parser/package.json +56 -0
  144. gaia/eval/webapp/node_modules/bytes/History.md +97 -0
  145. gaia/eval/webapp/node_modules/bytes/LICENSE +23 -0
  146. gaia/eval/webapp/node_modules/bytes/Readme.md +152 -0
  147. gaia/eval/webapp/node_modules/bytes/index.js +170 -0
  148. gaia/eval/webapp/node_modules/bytes/package.json +42 -0
  149. gaia/eval/webapp/node_modules/call-bind-apply-helpers/.eslintrc +17 -0
  150. gaia/eval/webapp/node_modules/call-bind-apply-helpers/.github/FUNDING.yml +12 -0
  151. gaia/eval/webapp/node_modules/call-bind-apply-helpers/.nycrc +9 -0
  152. gaia/eval/webapp/node_modules/call-bind-apply-helpers/CHANGELOG.md +30 -0
  153. gaia/eval/webapp/node_modules/call-bind-apply-helpers/LICENSE +21 -0
  154. gaia/eval/webapp/node_modules/call-bind-apply-helpers/README.md +62 -0
  155. gaia/eval/webapp/node_modules/call-bind-apply-helpers/actualApply.d.ts +1 -0
  156. gaia/eval/webapp/node_modules/call-bind-apply-helpers/actualApply.js +10 -0
  157. gaia/eval/webapp/node_modules/call-bind-apply-helpers/applyBind.d.ts +19 -0
  158. gaia/eval/webapp/node_modules/call-bind-apply-helpers/applyBind.js +10 -0
  159. gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionApply.d.ts +1 -0
  160. gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionApply.js +4 -0
  161. gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionCall.d.ts +1 -0
  162. gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionCall.js +4 -0
  163. gaia/eval/webapp/node_modules/call-bind-apply-helpers/index.d.ts +64 -0
  164. gaia/eval/webapp/node_modules/call-bind-apply-helpers/index.js +15 -0
  165. gaia/eval/webapp/node_modules/call-bind-apply-helpers/package.json +85 -0
  166. gaia/eval/webapp/node_modules/call-bind-apply-helpers/reflectApply.d.ts +3 -0
  167. gaia/eval/webapp/node_modules/call-bind-apply-helpers/reflectApply.js +4 -0
  168. gaia/eval/webapp/node_modules/call-bind-apply-helpers/test/index.js +63 -0
  169. gaia/eval/webapp/node_modules/call-bind-apply-helpers/tsconfig.json +9 -0
  170. gaia/eval/webapp/node_modules/call-bound/.eslintrc +13 -0
  171. gaia/eval/webapp/node_modules/call-bound/.github/FUNDING.yml +12 -0
  172. gaia/eval/webapp/node_modules/call-bound/.nycrc +9 -0
  173. gaia/eval/webapp/node_modules/call-bound/CHANGELOG.md +42 -0
  174. gaia/eval/webapp/node_modules/call-bound/LICENSE +21 -0
  175. gaia/eval/webapp/node_modules/call-bound/README.md +53 -0
  176. gaia/eval/webapp/node_modules/call-bound/index.d.ts +94 -0
  177. gaia/eval/webapp/node_modules/call-bound/index.js +19 -0
  178. gaia/eval/webapp/node_modules/call-bound/package.json +99 -0
  179. gaia/eval/webapp/node_modules/call-bound/test/index.js +61 -0
  180. gaia/eval/webapp/node_modules/call-bound/tsconfig.json +10 -0
  181. gaia/eval/webapp/node_modules/content-disposition/HISTORY.md +60 -0
  182. gaia/eval/webapp/node_modules/content-disposition/LICENSE +22 -0
  183. gaia/eval/webapp/node_modules/content-disposition/README.md +142 -0
  184. gaia/eval/webapp/node_modules/content-disposition/index.js +458 -0
  185. gaia/eval/webapp/node_modules/content-disposition/package.json +44 -0
  186. gaia/eval/webapp/node_modules/content-type/HISTORY.md +29 -0
  187. gaia/eval/webapp/node_modules/content-type/LICENSE +22 -0
  188. gaia/eval/webapp/node_modules/content-type/README.md +94 -0
  189. gaia/eval/webapp/node_modules/content-type/index.js +225 -0
  190. gaia/eval/webapp/node_modules/content-type/package.json +42 -0
  191. gaia/eval/webapp/node_modules/cookie/LICENSE +24 -0
  192. gaia/eval/webapp/node_modules/cookie/README.md +317 -0
  193. gaia/eval/webapp/node_modules/cookie/SECURITY.md +25 -0
  194. gaia/eval/webapp/node_modules/cookie/index.js +334 -0
  195. gaia/eval/webapp/node_modules/cookie/package.json +44 -0
  196. gaia/eval/webapp/node_modules/cookie-signature/.npmignore +4 -0
  197. gaia/eval/webapp/node_modules/cookie-signature/History.md +38 -0
  198. gaia/eval/webapp/node_modules/cookie-signature/Readme.md +42 -0
  199. gaia/eval/webapp/node_modules/cookie-signature/index.js +51 -0
  200. gaia/eval/webapp/node_modules/cookie-signature/package.json +18 -0
  201. gaia/eval/webapp/node_modules/debug/.coveralls.yml +1 -0
  202. gaia/eval/webapp/node_modules/debug/.eslintrc +11 -0
  203. gaia/eval/webapp/node_modules/debug/.npmignore +9 -0
  204. gaia/eval/webapp/node_modules/debug/.travis.yml +14 -0
  205. gaia/eval/webapp/node_modules/debug/CHANGELOG.md +362 -0
  206. gaia/eval/webapp/node_modules/debug/LICENSE +19 -0
  207. gaia/eval/webapp/node_modules/debug/Makefile +50 -0
  208. gaia/eval/webapp/node_modules/debug/README.md +312 -0
  209. gaia/eval/webapp/node_modules/debug/component.json +19 -0
  210. gaia/eval/webapp/node_modules/debug/karma.conf.js +70 -0
  211. gaia/eval/webapp/node_modules/debug/node.js +1 -0
  212. gaia/eval/webapp/node_modules/debug/package.json +49 -0
  213. gaia/eval/webapp/node_modules/debug/src/browser.js +185 -0
  214. gaia/eval/webapp/node_modules/debug/src/debug.js +202 -0
  215. gaia/eval/webapp/node_modules/debug/src/index.js +10 -0
  216. gaia/eval/webapp/node_modules/debug/src/inspector-log.js +15 -0
  217. gaia/eval/webapp/node_modules/debug/src/node.js +248 -0
  218. gaia/eval/webapp/node_modules/depd/History.md +103 -0
  219. gaia/eval/webapp/node_modules/depd/LICENSE +22 -0
  220. gaia/eval/webapp/node_modules/depd/Readme.md +280 -0
  221. gaia/eval/webapp/node_modules/depd/index.js +538 -0
  222. gaia/eval/webapp/node_modules/depd/lib/browser/index.js +77 -0
  223. gaia/eval/webapp/node_modules/depd/package.json +45 -0
  224. gaia/eval/webapp/node_modules/destroy/LICENSE +23 -0
  225. gaia/eval/webapp/node_modules/destroy/README.md +63 -0
  226. gaia/eval/webapp/node_modules/destroy/index.js +209 -0
  227. gaia/eval/webapp/node_modules/destroy/package.json +48 -0
  228. gaia/eval/webapp/node_modules/dunder-proto/.eslintrc +5 -0
  229. gaia/eval/webapp/node_modules/dunder-proto/.github/FUNDING.yml +12 -0
  230. gaia/eval/webapp/node_modules/dunder-proto/.nycrc +13 -0
  231. gaia/eval/webapp/node_modules/dunder-proto/CHANGELOG.md +24 -0
  232. gaia/eval/webapp/node_modules/dunder-proto/LICENSE +21 -0
  233. gaia/eval/webapp/node_modules/dunder-proto/README.md +54 -0
  234. gaia/eval/webapp/node_modules/dunder-proto/get.d.ts +5 -0
  235. gaia/eval/webapp/node_modules/dunder-proto/get.js +30 -0
  236. gaia/eval/webapp/node_modules/dunder-proto/package.json +76 -0
  237. gaia/eval/webapp/node_modules/dunder-proto/set.d.ts +5 -0
  238. gaia/eval/webapp/node_modules/dunder-proto/set.js +35 -0
  239. gaia/eval/webapp/node_modules/dunder-proto/test/get.js +34 -0
  240. gaia/eval/webapp/node_modules/dunder-proto/test/index.js +4 -0
  241. gaia/eval/webapp/node_modules/dunder-proto/test/set.js +50 -0
  242. gaia/eval/webapp/node_modules/dunder-proto/tsconfig.json +9 -0
  243. gaia/eval/webapp/node_modules/ee-first/LICENSE +22 -0
  244. gaia/eval/webapp/node_modules/ee-first/README.md +80 -0
  245. gaia/eval/webapp/node_modules/ee-first/index.js +95 -0
  246. gaia/eval/webapp/node_modules/ee-first/package.json +29 -0
  247. gaia/eval/webapp/node_modules/encodeurl/LICENSE +22 -0
  248. gaia/eval/webapp/node_modules/encodeurl/README.md +109 -0
  249. gaia/eval/webapp/node_modules/encodeurl/index.js +60 -0
  250. gaia/eval/webapp/node_modules/encodeurl/package.json +40 -0
  251. gaia/eval/webapp/node_modules/es-define-property/.eslintrc +13 -0
  252. gaia/eval/webapp/node_modules/es-define-property/.github/FUNDING.yml +12 -0
  253. gaia/eval/webapp/node_modules/es-define-property/.nycrc +9 -0
  254. gaia/eval/webapp/node_modules/es-define-property/CHANGELOG.md +29 -0
  255. gaia/eval/webapp/node_modules/es-define-property/LICENSE +21 -0
  256. gaia/eval/webapp/node_modules/es-define-property/README.md +49 -0
  257. gaia/eval/webapp/node_modules/es-define-property/index.d.ts +3 -0
  258. gaia/eval/webapp/node_modules/es-define-property/index.js +14 -0
  259. gaia/eval/webapp/node_modules/es-define-property/package.json +81 -0
  260. gaia/eval/webapp/node_modules/es-define-property/test/index.js +56 -0
  261. gaia/eval/webapp/node_modules/es-define-property/tsconfig.json +10 -0
  262. gaia/eval/webapp/node_modules/es-errors/.eslintrc +5 -0
  263. gaia/eval/webapp/node_modules/es-errors/.github/FUNDING.yml +12 -0
  264. gaia/eval/webapp/node_modules/es-errors/CHANGELOG.md +40 -0
  265. gaia/eval/webapp/node_modules/es-errors/LICENSE +21 -0
  266. gaia/eval/webapp/node_modules/es-errors/README.md +55 -0
  267. gaia/eval/webapp/node_modules/es-errors/eval.d.ts +3 -0
  268. gaia/eval/webapp/node_modules/es-errors/eval.js +4 -0
  269. gaia/eval/webapp/node_modules/es-errors/index.d.ts +3 -0
  270. gaia/eval/webapp/node_modules/es-errors/index.js +4 -0
  271. gaia/eval/webapp/node_modules/es-errors/package.json +80 -0
  272. gaia/eval/webapp/node_modules/es-errors/range.d.ts +3 -0
  273. gaia/eval/webapp/node_modules/es-errors/range.js +4 -0
  274. gaia/eval/webapp/node_modules/es-errors/ref.d.ts +3 -0
  275. gaia/eval/webapp/node_modules/es-errors/ref.js +4 -0
  276. gaia/eval/webapp/node_modules/es-errors/syntax.d.ts +3 -0
  277. gaia/eval/webapp/node_modules/es-errors/syntax.js +4 -0
  278. gaia/eval/webapp/node_modules/es-errors/test/index.js +19 -0
  279. gaia/eval/webapp/node_modules/es-errors/tsconfig.json +49 -0
  280. gaia/eval/webapp/node_modules/es-errors/type.d.ts +3 -0
  281. gaia/eval/webapp/node_modules/es-errors/type.js +4 -0
  282. gaia/eval/webapp/node_modules/es-errors/uri.d.ts +3 -0
  283. gaia/eval/webapp/node_modules/es-errors/uri.js +4 -0
  284. gaia/eval/webapp/node_modules/es-object-atoms/.eslintrc +16 -0
  285. gaia/eval/webapp/node_modules/es-object-atoms/.github/FUNDING.yml +12 -0
  286. gaia/eval/webapp/node_modules/es-object-atoms/CHANGELOG.md +37 -0
  287. gaia/eval/webapp/node_modules/es-object-atoms/LICENSE +21 -0
  288. gaia/eval/webapp/node_modules/es-object-atoms/README.md +63 -0
  289. gaia/eval/webapp/node_modules/es-object-atoms/RequireObjectCoercible.d.ts +3 -0
  290. gaia/eval/webapp/node_modules/es-object-atoms/RequireObjectCoercible.js +11 -0
  291. gaia/eval/webapp/node_modules/es-object-atoms/ToObject.d.ts +7 -0
  292. gaia/eval/webapp/node_modules/es-object-atoms/ToObject.js +10 -0
  293. gaia/eval/webapp/node_modules/es-object-atoms/index.d.ts +3 -0
  294. gaia/eval/webapp/node_modules/es-object-atoms/index.js +4 -0
  295. gaia/eval/webapp/node_modules/es-object-atoms/isObject.d.ts +3 -0
  296. gaia/eval/webapp/node_modules/es-object-atoms/isObject.js +6 -0
  297. gaia/eval/webapp/node_modules/es-object-atoms/package.json +80 -0
  298. gaia/eval/webapp/node_modules/es-object-atoms/test/index.js +38 -0
  299. gaia/eval/webapp/node_modules/es-object-atoms/tsconfig.json +6 -0
  300. gaia/eval/webapp/node_modules/escape-html/LICENSE +24 -0
  301. gaia/eval/webapp/node_modules/escape-html/Readme.md +43 -0
  302. gaia/eval/webapp/node_modules/escape-html/index.js +78 -0
  303. gaia/eval/webapp/node_modules/escape-html/package.json +24 -0
  304. gaia/eval/webapp/node_modules/etag/HISTORY.md +83 -0
  305. gaia/eval/webapp/node_modules/etag/LICENSE +22 -0
  306. gaia/eval/webapp/node_modules/etag/README.md +159 -0
  307. gaia/eval/webapp/node_modules/etag/index.js +131 -0
  308. gaia/eval/webapp/node_modules/etag/package.json +47 -0
  309. gaia/eval/webapp/node_modules/express/History.md +3656 -0
  310. gaia/eval/webapp/node_modules/express/LICENSE +24 -0
  311. gaia/eval/webapp/node_modules/express/Readme.md +260 -0
  312. gaia/eval/webapp/node_modules/express/index.js +11 -0
  313. gaia/eval/webapp/node_modules/express/lib/application.js +661 -0
  314. gaia/eval/webapp/node_modules/express/lib/express.js +116 -0
  315. gaia/eval/webapp/node_modules/express/lib/middleware/init.js +43 -0
  316. gaia/eval/webapp/node_modules/express/lib/middleware/query.js +47 -0
  317. gaia/eval/webapp/node_modules/express/lib/request.js +525 -0
  318. gaia/eval/webapp/node_modules/express/lib/response.js +1179 -0
  319. gaia/eval/webapp/node_modules/express/lib/router/index.js +673 -0
  320. gaia/eval/webapp/node_modules/express/lib/router/layer.js +181 -0
  321. gaia/eval/webapp/node_modules/express/lib/router/route.js +230 -0
  322. gaia/eval/webapp/node_modules/express/lib/utils.js +303 -0
  323. gaia/eval/webapp/node_modules/express/lib/view.js +182 -0
  324. gaia/eval/webapp/node_modules/express/package.json +102 -0
  325. gaia/eval/webapp/node_modules/finalhandler/HISTORY.md +210 -0
  326. gaia/eval/webapp/node_modules/finalhandler/LICENSE +22 -0
  327. gaia/eval/webapp/node_modules/finalhandler/README.md +147 -0
  328. gaia/eval/webapp/node_modules/finalhandler/SECURITY.md +25 -0
  329. gaia/eval/webapp/node_modules/finalhandler/index.js +341 -0
  330. gaia/eval/webapp/node_modules/finalhandler/package.json +47 -0
  331. gaia/eval/webapp/node_modules/forwarded/HISTORY.md +21 -0
  332. gaia/eval/webapp/node_modules/forwarded/LICENSE +22 -0
  333. gaia/eval/webapp/node_modules/forwarded/README.md +57 -0
  334. gaia/eval/webapp/node_modules/forwarded/index.js +90 -0
  335. gaia/eval/webapp/node_modules/forwarded/package.json +45 -0
  336. gaia/eval/webapp/node_modules/fresh/HISTORY.md +70 -0
  337. gaia/eval/webapp/node_modules/fresh/LICENSE +23 -0
  338. gaia/eval/webapp/node_modules/fresh/README.md +119 -0
  339. gaia/eval/webapp/node_modules/fresh/index.js +137 -0
  340. gaia/eval/webapp/node_modules/fresh/package.json +46 -0
  341. gaia/eval/webapp/node_modules/fs/README.md +9 -0
  342. gaia/eval/webapp/node_modules/fs/package.json +20 -0
  343. gaia/eval/webapp/node_modules/function-bind/.eslintrc +21 -0
  344. gaia/eval/webapp/node_modules/function-bind/.github/FUNDING.yml +12 -0
  345. gaia/eval/webapp/node_modules/function-bind/.github/SECURITY.md +3 -0
  346. gaia/eval/webapp/node_modules/function-bind/.nycrc +13 -0
  347. gaia/eval/webapp/node_modules/function-bind/CHANGELOG.md +136 -0
  348. gaia/eval/webapp/node_modules/function-bind/LICENSE +20 -0
  349. gaia/eval/webapp/node_modules/function-bind/README.md +46 -0
  350. gaia/eval/webapp/node_modules/function-bind/implementation.js +84 -0
  351. gaia/eval/webapp/node_modules/function-bind/index.js +5 -0
  352. gaia/eval/webapp/node_modules/function-bind/package.json +87 -0
  353. gaia/eval/webapp/node_modules/function-bind/test/.eslintrc +9 -0
  354. gaia/eval/webapp/node_modules/function-bind/test/index.js +252 -0
  355. gaia/eval/webapp/node_modules/get-intrinsic/.eslintrc +42 -0
  356. gaia/eval/webapp/node_modules/get-intrinsic/.github/FUNDING.yml +12 -0
  357. gaia/eval/webapp/node_modules/get-intrinsic/.nycrc +9 -0
  358. gaia/eval/webapp/node_modules/get-intrinsic/CHANGELOG.md +186 -0
  359. gaia/eval/webapp/node_modules/get-intrinsic/LICENSE +21 -0
  360. gaia/eval/webapp/node_modules/get-intrinsic/README.md +71 -0
  361. gaia/eval/webapp/node_modules/get-intrinsic/index.js +378 -0
  362. gaia/eval/webapp/node_modules/get-intrinsic/package.json +97 -0
  363. gaia/eval/webapp/node_modules/get-intrinsic/test/GetIntrinsic.js +274 -0
  364. gaia/eval/webapp/node_modules/get-proto/.eslintrc +10 -0
  365. gaia/eval/webapp/node_modules/get-proto/.github/FUNDING.yml +12 -0
  366. gaia/eval/webapp/node_modules/get-proto/.nycrc +9 -0
  367. gaia/eval/webapp/node_modules/get-proto/CHANGELOG.md +21 -0
  368. gaia/eval/webapp/node_modules/get-proto/LICENSE +21 -0
  369. gaia/eval/webapp/node_modules/get-proto/Object.getPrototypeOf.d.ts +5 -0
  370. gaia/eval/webapp/node_modules/get-proto/Object.getPrototypeOf.js +6 -0
  371. gaia/eval/webapp/node_modules/get-proto/README.md +50 -0
  372. gaia/eval/webapp/node_modules/get-proto/Reflect.getPrototypeOf.d.ts +3 -0
  373. gaia/eval/webapp/node_modules/get-proto/Reflect.getPrototypeOf.js +4 -0
  374. gaia/eval/webapp/node_modules/get-proto/index.d.ts +5 -0
  375. gaia/eval/webapp/node_modules/get-proto/index.js +27 -0
  376. gaia/eval/webapp/node_modules/get-proto/package.json +81 -0
  377. gaia/eval/webapp/node_modules/get-proto/test/index.js +68 -0
  378. gaia/eval/webapp/node_modules/get-proto/tsconfig.json +9 -0
  379. gaia/eval/webapp/node_modules/gopd/.eslintrc +16 -0
  380. gaia/eval/webapp/node_modules/gopd/.github/FUNDING.yml +12 -0
  381. gaia/eval/webapp/node_modules/gopd/CHANGELOG.md +45 -0
  382. gaia/eval/webapp/node_modules/gopd/LICENSE +21 -0
  383. gaia/eval/webapp/node_modules/gopd/README.md +40 -0
  384. gaia/eval/webapp/node_modules/gopd/gOPD.d.ts +1 -0
  385. gaia/eval/webapp/node_modules/gopd/gOPD.js +4 -0
  386. gaia/eval/webapp/node_modules/gopd/index.d.ts +5 -0
  387. gaia/eval/webapp/node_modules/gopd/index.js +15 -0
  388. gaia/eval/webapp/node_modules/gopd/package.json +77 -0
  389. gaia/eval/webapp/node_modules/gopd/test/index.js +36 -0
  390. gaia/eval/webapp/node_modules/gopd/tsconfig.json +9 -0
  391. gaia/eval/webapp/node_modules/has-symbols/.eslintrc +11 -0
  392. gaia/eval/webapp/node_modules/has-symbols/.github/FUNDING.yml +12 -0
  393. gaia/eval/webapp/node_modules/has-symbols/.nycrc +9 -0
  394. gaia/eval/webapp/node_modules/has-symbols/CHANGELOG.md +91 -0
  395. gaia/eval/webapp/node_modules/has-symbols/LICENSE +21 -0
  396. gaia/eval/webapp/node_modules/has-symbols/README.md +46 -0
  397. gaia/eval/webapp/node_modules/has-symbols/index.d.ts +3 -0
  398. gaia/eval/webapp/node_modules/has-symbols/index.js +14 -0
  399. gaia/eval/webapp/node_modules/has-symbols/package.json +111 -0
  400. gaia/eval/webapp/node_modules/has-symbols/shams.d.ts +3 -0
  401. gaia/eval/webapp/node_modules/has-symbols/shams.js +45 -0
  402. gaia/eval/webapp/node_modules/has-symbols/test/index.js +22 -0
  403. gaia/eval/webapp/node_modules/has-symbols/test/shams/core-js.js +29 -0
  404. gaia/eval/webapp/node_modules/has-symbols/test/shams/get-own-property-symbols.js +29 -0
  405. gaia/eval/webapp/node_modules/has-symbols/test/tests.js +58 -0
  406. gaia/eval/webapp/node_modules/has-symbols/tsconfig.json +10 -0
  407. gaia/eval/webapp/node_modules/hasown/.eslintrc +5 -0
  408. gaia/eval/webapp/node_modules/hasown/.github/FUNDING.yml +12 -0
  409. gaia/eval/webapp/node_modules/hasown/.nycrc +13 -0
  410. gaia/eval/webapp/node_modules/hasown/CHANGELOG.md +40 -0
  411. gaia/eval/webapp/node_modules/hasown/LICENSE +21 -0
  412. gaia/eval/webapp/node_modules/hasown/README.md +40 -0
  413. gaia/eval/webapp/node_modules/hasown/index.d.ts +3 -0
  414. gaia/eval/webapp/node_modules/hasown/index.js +8 -0
  415. gaia/eval/webapp/node_modules/hasown/package.json +92 -0
  416. gaia/eval/webapp/node_modules/hasown/tsconfig.json +6 -0
  417. gaia/eval/webapp/node_modules/http-errors/HISTORY.md +180 -0
  418. gaia/eval/webapp/node_modules/http-errors/LICENSE +23 -0
  419. gaia/eval/webapp/node_modules/http-errors/README.md +169 -0
  420. gaia/eval/webapp/node_modules/http-errors/index.js +289 -0
  421. gaia/eval/webapp/node_modules/http-errors/package.json +50 -0
  422. gaia/eval/webapp/node_modules/iconv-lite/Changelog.md +162 -0
  423. gaia/eval/webapp/node_modules/iconv-lite/LICENSE +21 -0
  424. gaia/eval/webapp/node_modules/iconv-lite/README.md +156 -0
  425. gaia/eval/webapp/node_modules/iconv-lite/encodings/dbcs-codec.js +555 -0
  426. gaia/eval/webapp/node_modules/iconv-lite/encodings/dbcs-data.js +176 -0
  427. gaia/eval/webapp/node_modules/iconv-lite/encodings/index.js +22 -0
  428. gaia/eval/webapp/node_modules/iconv-lite/encodings/internal.js +188 -0
  429. gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-codec.js +72 -0
  430. gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-data-generated.js +451 -0
  431. gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-data.js +174 -0
  432. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/big5-added.json +122 -0
  433. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp936.json +264 -0
  434. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp949.json +273 -0
  435. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp950.json +177 -0
  436. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/eucjp.json +182 -0
  437. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/gb18030-ranges.json +1 -0
  438. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/gbk-added.json +55 -0
  439. gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/shiftjis.json +125 -0
  440. gaia/eval/webapp/node_modules/iconv-lite/encodings/utf16.js +177 -0
  441. gaia/eval/webapp/node_modules/iconv-lite/encodings/utf7.js +290 -0
  442. gaia/eval/webapp/node_modules/iconv-lite/lib/bom-handling.js +52 -0
  443. gaia/eval/webapp/node_modules/iconv-lite/lib/extend-node.js +217 -0
  444. gaia/eval/webapp/node_modules/iconv-lite/lib/index.d.ts +24 -0
  445. gaia/eval/webapp/node_modules/iconv-lite/lib/index.js +153 -0
  446. gaia/eval/webapp/node_modules/iconv-lite/lib/streams.js +121 -0
  447. gaia/eval/webapp/node_modules/iconv-lite/package.json +46 -0
  448. gaia/eval/webapp/node_modules/inherits/LICENSE +16 -0
  449. gaia/eval/webapp/node_modules/inherits/README.md +42 -0
  450. gaia/eval/webapp/node_modules/inherits/inherits.js +9 -0
  451. gaia/eval/webapp/node_modules/inherits/inherits_browser.js +27 -0
  452. gaia/eval/webapp/node_modules/inherits/package.json +29 -0
  453. gaia/eval/webapp/node_modules/ipaddr.js/LICENSE +19 -0
  454. gaia/eval/webapp/node_modules/ipaddr.js/README.md +233 -0
  455. gaia/eval/webapp/node_modules/ipaddr.js/ipaddr.min.js +1 -0
  456. gaia/eval/webapp/node_modules/ipaddr.js/lib/ipaddr.js +673 -0
  457. gaia/eval/webapp/node_modules/ipaddr.js/lib/ipaddr.js.d.ts +68 -0
  458. gaia/eval/webapp/node_modules/ipaddr.js/package.json +35 -0
  459. gaia/eval/webapp/node_modules/math-intrinsics/.eslintrc +16 -0
  460. gaia/eval/webapp/node_modules/math-intrinsics/.github/FUNDING.yml +12 -0
  461. gaia/eval/webapp/node_modules/math-intrinsics/CHANGELOG.md +24 -0
  462. gaia/eval/webapp/node_modules/math-intrinsics/LICENSE +21 -0
  463. gaia/eval/webapp/node_modules/math-intrinsics/README.md +50 -0
  464. gaia/eval/webapp/node_modules/math-intrinsics/abs.d.ts +1 -0
  465. gaia/eval/webapp/node_modules/math-intrinsics/abs.js +4 -0
  466. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxArrayLength.d.ts +3 -0
  467. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxArrayLength.js +4 -0
  468. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxSafeInteger.d.ts +3 -0
  469. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxSafeInteger.js +5 -0
  470. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxValue.d.ts +3 -0
  471. gaia/eval/webapp/node_modules/math-intrinsics/constants/maxValue.js +5 -0
  472. gaia/eval/webapp/node_modules/math-intrinsics/floor.d.ts +1 -0
  473. gaia/eval/webapp/node_modules/math-intrinsics/floor.js +4 -0
  474. gaia/eval/webapp/node_modules/math-intrinsics/isFinite.d.ts +3 -0
  475. gaia/eval/webapp/node_modules/math-intrinsics/isFinite.js +12 -0
  476. gaia/eval/webapp/node_modules/math-intrinsics/isInteger.d.ts +3 -0
  477. gaia/eval/webapp/node_modules/math-intrinsics/isInteger.js +16 -0
  478. gaia/eval/webapp/node_modules/math-intrinsics/isNaN.d.ts +1 -0
  479. gaia/eval/webapp/node_modules/math-intrinsics/isNaN.js +6 -0
  480. gaia/eval/webapp/node_modules/math-intrinsics/isNegativeZero.d.ts +3 -0
  481. gaia/eval/webapp/node_modules/math-intrinsics/isNegativeZero.js +6 -0
  482. gaia/eval/webapp/node_modules/math-intrinsics/max.d.ts +1 -0
  483. gaia/eval/webapp/node_modules/math-intrinsics/max.js +4 -0
  484. gaia/eval/webapp/node_modules/math-intrinsics/min.d.ts +1 -0
  485. gaia/eval/webapp/node_modules/math-intrinsics/min.js +4 -0
  486. gaia/eval/webapp/node_modules/math-intrinsics/mod.d.ts +3 -0
  487. gaia/eval/webapp/node_modules/math-intrinsics/mod.js +9 -0
  488. gaia/eval/webapp/node_modules/math-intrinsics/package.json +86 -0
  489. gaia/eval/webapp/node_modules/math-intrinsics/pow.d.ts +1 -0
  490. gaia/eval/webapp/node_modules/math-intrinsics/pow.js +4 -0
  491. gaia/eval/webapp/node_modules/math-intrinsics/round.d.ts +1 -0
  492. gaia/eval/webapp/node_modules/math-intrinsics/round.js +4 -0
  493. gaia/eval/webapp/node_modules/math-intrinsics/sign.d.ts +3 -0
  494. gaia/eval/webapp/node_modules/math-intrinsics/sign.js +11 -0
  495. gaia/eval/webapp/node_modules/math-intrinsics/test/index.js +192 -0
  496. gaia/eval/webapp/node_modules/math-intrinsics/tsconfig.json +3 -0
  497. gaia/eval/webapp/node_modules/media-typer/HISTORY.md +22 -0
  498. gaia/eval/webapp/node_modules/media-typer/LICENSE +22 -0
  499. gaia/eval/webapp/node_modules/media-typer/README.md +81 -0
  500. gaia/eval/webapp/node_modules/media-typer/index.js +270 -0
  501. gaia/eval/webapp/node_modules/media-typer/package.json +26 -0
  502. gaia/eval/webapp/node_modules/merge-descriptors/HISTORY.md +21 -0
  503. gaia/eval/webapp/node_modules/merge-descriptors/LICENSE +23 -0
  504. gaia/eval/webapp/node_modules/merge-descriptors/README.md +49 -0
  505. gaia/eval/webapp/node_modules/merge-descriptors/index.js +60 -0
  506. gaia/eval/webapp/node_modules/merge-descriptors/package.json +39 -0
  507. gaia/eval/webapp/node_modules/methods/HISTORY.md +29 -0
  508. gaia/eval/webapp/node_modules/methods/LICENSE +24 -0
  509. gaia/eval/webapp/node_modules/methods/README.md +51 -0
  510. gaia/eval/webapp/node_modules/methods/index.js +69 -0
  511. gaia/eval/webapp/node_modules/methods/package.json +36 -0
  512. gaia/eval/webapp/node_modules/mime/.npmignore +0 -0
  513. gaia/eval/webapp/node_modules/mime/CHANGELOG.md +164 -0
  514. gaia/eval/webapp/node_modules/mime/LICENSE +21 -0
  515. gaia/eval/webapp/node_modules/mime/README.md +90 -0
  516. gaia/eval/webapp/node_modules/mime/cli.js +8 -0
  517. gaia/eval/webapp/node_modules/mime/mime.js +108 -0
  518. gaia/eval/webapp/node_modules/mime/package.json +44 -0
  519. gaia/eval/webapp/node_modules/mime/src/build.js +53 -0
  520. gaia/eval/webapp/node_modules/mime/src/test.js +60 -0
  521. gaia/eval/webapp/node_modules/mime/types.json +1 -0
  522. gaia/eval/webapp/node_modules/mime-db/HISTORY.md +507 -0
  523. gaia/eval/webapp/node_modules/mime-db/LICENSE +23 -0
  524. gaia/eval/webapp/node_modules/mime-db/README.md +100 -0
  525. gaia/eval/webapp/node_modules/mime-db/db.json +8519 -0
  526. gaia/eval/webapp/node_modules/mime-db/index.js +12 -0
  527. gaia/eval/webapp/node_modules/mime-db/package.json +60 -0
  528. gaia/eval/webapp/node_modules/mime-types/HISTORY.md +397 -0
  529. gaia/eval/webapp/node_modules/mime-types/LICENSE +23 -0
  530. gaia/eval/webapp/node_modules/mime-types/README.md +113 -0
  531. gaia/eval/webapp/node_modules/mime-types/index.js +188 -0
  532. gaia/eval/webapp/node_modules/mime-types/package.json +44 -0
  533. gaia/eval/webapp/node_modules/ms/index.js +152 -0
  534. gaia/eval/webapp/node_modules/ms/license.md +21 -0
  535. gaia/eval/webapp/node_modules/ms/package.json +37 -0
  536. gaia/eval/webapp/node_modules/ms/readme.md +51 -0
  537. gaia/eval/webapp/node_modules/negotiator/HISTORY.md +108 -0
  538. gaia/eval/webapp/node_modules/negotiator/LICENSE +24 -0
  539. gaia/eval/webapp/node_modules/negotiator/README.md +203 -0
  540. gaia/eval/webapp/node_modules/negotiator/index.js +82 -0
  541. gaia/eval/webapp/node_modules/negotiator/lib/charset.js +169 -0
  542. gaia/eval/webapp/node_modules/negotiator/lib/encoding.js +184 -0
  543. gaia/eval/webapp/node_modules/negotiator/lib/language.js +179 -0
  544. gaia/eval/webapp/node_modules/negotiator/lib/mediaType.js +294 -0
  545. gaia/eval/webapp/node_modules/negotiator/package.json +42 -0
  546. gaia/eval/webapp/node_modules/object-inspect/.eslintrc +53 -0
  547. gaia/eval/webapp/node_modules/object-inspect/.github/FUNDING.yml +12 -0
  548. gaia/eval/webapp/node_modules/object-inspect/.nycrc +13 -0
  549. gaia/eval/webapp/node_modules/object-inspect/CHANGELOG.md +424 -0
  550. gaia/eval/webapp/node_modules/object-inspect/LICENSE +21 -0
  551. gaia/eval/webapp/node_modules/object-inspect/example/all.js +23 -0
  552. gaia/eval/webapp/node_modules/object-inspect/example/circular.js +6 -0
  553. gaia/eval/webapp/node_modules/object-inspect/example/fn.js +5 -0
  554. gaia/eval/webapp/node_modules/object-inspect/example/inspect.js +10 -0
  555. gaia/eval/webapp/node_modules/object-inspect/index.js +544 -0
  556. gaia/eval/webapp/node_modules/object-inspect/package-support.json +20 -0
  557. gaia/eval/webapp/node_modules/object-inspect/package.json +105 -0
  558. gaia/eval/webapp/node_modules/object-inspect/readme.markdown +84 -0
  559. gaia/eval/webapp/node_modules/object-inspect/test/bigint.js +58 -0
  560. gaia/eval/webapp/node_modules/object-inspect/test/browser/dom.js +15 -0
  561. gaia/eval/webapp/node_modules/object-inspect/test/circular.js +16 -0
  562. gaia/eval/webapp/node_modules/object-inspect/test/deep.js +12 -0
  563. gaia/eval/webapp/node_modules/object-inspect/test/element.js +53 -0
  564. gaia/eval/webapp/node_modules/object-inspect/test/err.js +48 -0
  565. gaia/eval/webapp/node_modules/object-inspect/test/fakes.js +29 -0
  566. gaia/eval/webapp/node_modules/object-inspect/test/fn.js +76 -0
  567. gaia/eval/webapp/node_modules/object-inspect/test/global.js +17 -0
  568. gaia/eval/webapp/node_modules/object-inspect/test/has.js +15 -0
  569. gaia/eval/webapp/node_modules/object-inspect/test/holes.js +15 -0
  570. gaia/eval/webapp/node_modules/object-inspect/test/indent-option.js +271 -0
  571. gaia/eval/webapp/node_modules/object-inspect/test/inspect.js +139 -0
  572. gaia/eval/webapp/node_modules/object-inspect/test/lowbyte.js +12 -0
  573. gaia/eval/webapp/node_modules/object-inspect/test/number.js +58 -0
  574. gaia/eval/webapp/node_modules/object-inspect/test/quoteStyle.js +26 -0
  575. gaia/eval/webapp/node_modules/object-inspect/test/toStringTag.js +40 -0
  576. gaia/eval/webapp/node_modules/object-inspect/test/undef.js +12 -0
  577. gaia/eval/webapp/node_modules/object-inspect/test/values.js +261 -0
  578. gaia/eval/webapp/node_modules/object-inspect/test-core-js.js +26 -0
  579. gaia/eval/webapp/node_modules/object-inspect/util.inspect.js +1 -0
  580. gaia/eval/webapp/node_modules/on-finished/HISTORY.md +98 -0
  581. gaia/eval/webapp/node_modules/on-finished/LICENSE +23 -0
  582. gaia/eval/webapp/node_modules/on-finished/README.md +162 -0
  583. gaia/eval/webapp/node_modules/on-finished/index.js +234 -0
  584. gaia/eval/webapp/node_modules/on-finished/package.json +39 -0
  585. gaia/eval/webapp/node_modules/parseurl/HISTORY.md +58 -0
  586. gaia/eval/webapp/node_modules/parseurl/LICENSE +24 -0
  587. gaia/eval/webapp/node_modules/parseurl/README.md +133 -0
  588. gaia/eval/webapp/node_modules/parseurl/index.js +158 -0
  589. gaia/eval/webapp/node_modules/parseurl/package.json +40 -0
  590. gaia/eval/webapp/node_modules/path/.npmignore +1 -0
  591. gaia/eval/webapp/node_modules/path/LICENSE +18 -0
  592. gaia/eval/webapp/node_modules/path/README.md +15 -0
  593. gaia/eval/webapp/node_modules/path/package.json +24 -0
  594. gaia/eval/webapp/node_modules/path/path.js +628 -0
  595. gaia/eval/webapp/node_modules/path-to-regexp/LICENSE +21 -0
  596. gaia/eval/webapp/node_modules/path-to-regexp/Readme.md +35 -0
  597. gaia/eval/webapp/node_modules/path-to-regexp/index.js +156 -0
  598. gaia/eval/webapp/node_modules/path-to-regexp/package.json +30 -0
  599. gaia/eval/webapp/node_modules/process/.eslintrc +21 -0
  600. gaia/eval/webapp/node_modules/process/LICENSE +22 -0
  601. gaia/eval/webapp/node_modules/process/README.md +26 -0
  602. gaia/eval/webapp/node_modules/process/browser.js +184 -0
  603. gaia/eval/webapp/node_modules/process/index.js +2 -0
  604. gaia/eval/webapp/node_modules/process/package.json +27 -0
  605. gaia/eval/webapp/node_modules/process/test.js +199 -0
  606. gaia/eval/webapp/node_modules/proxy-addr/HISTORY.md +161 -0
  607. gaia/eval/webapp/node_modules/proxy-addr/LICENSE +22 -0
  608. gaia/eval/webapp/node_modules/proxy-addr/README.md +139 -0
  609. gaia/eval/webapp/node_modules/proxy-addr/index.js +327 -0
  610. gaia/eval/webapp/node_modules/proxy-addr/package.json +47 -0
  611. gaia/eval/webapp/node_modules/qs/.editorconfig +46 -0
  612. gaia/eval/webapp/node_modules/qs/.eslintrc +38 -0
  613. gaia/eval/webapp/node_modules/qs/.github/FUNDING.yml +12 -0
  614. gaia/eval/webapp/node_modules/qs/.nycrc +13 -0
  615. gaia/eval/webapp/node_modules/qs/CHANGELOG.md +600 -0
  616. gaia/eval/webapp/node_modules/qs/LICENSE.md +29 -0
  617. gaia/eval/webapp/node_modules/qs/README.md +709 -0
  618. gaia/eval/webapp/node_modules/qs/dist/qs.js +90 -0
  619. gaia/eval/webapp/node_modules/qs/lib/formats.js +23 -0
  620. gaia/eval/webapp/node_modules/qs/lib/index.js +11 -0
  621. gaia/eval/webapp/node_modules/qs/lib/parse.js +296 -0
  622. gaia/eval/webapp/node_modules/qs/lib/stringify.js +351 -0
  623. gaia/eval/webapp/node_modules/qs/lib/utils.js +265 -0
  624. gaia/eval/webapp/node_modules/qs/package.json +91 -0
  625. gaia/eval/webapp/node_modules/qs/test/empty-keys-cases.js +267 -0
  626. gaia/eval/webapp/node_modules/qs/test/parse.js +1170 -0
  627. gaia/eval/webapp/node_modules/qs/test/stringify.js +1298 -0
  628. gaia/eval/webapp/node_modules/qs/test/utils.js +136 -0
  629. gaia/eval/webapp/node_modules/range-parser/HISTORY.md +56 -0
  630. gaia/eval/webapp/node_modules/range-parser/LICENSE +23 -0
  631. gaia/eval/webapp/node_modules/range-parser/README.md +84 -0
  632. gaia/eval/webapp/node_modules/range-parser/index.js +162 -0
  633. gaia/eval/webapp/node_modules/range-parser/package.json +44 -0
  634. gaia/eval/webapp/node_modules/raw-body/HISTORY.md +308 -0
  635. gaia/eval/webapp/node_modules/raw-body/LICENSE +22 -0
  636. gaia/eval/webapp/node_modules/raw-body/README.md +223 -0
  637. gaia/eval/webapp/node_modules/raw-body/SECURITY.md +24 -0
  638. gaia/eval/webapp/node_modules/raw-body/index.d.ts +87 -0
  639. gaia/eval/webapp/node_modules/raw-body/index.js +336 -0
  640. gaia/eval/webapp/node_modules/raw-body/package.json +49 -0
  641. gaia/eval/webapp/node_modules/safe-buffer/LICENSE +21 -0
  642. gaia/eval/webapp/node_modules/safe-buffer/README.md +584 -0
  643. gaia/eval/webapp/node_modules/safe-buffer/index.d.ts +187 -0
  644. gaia/eval/webapp/node_modules/safe-buffer/index.js +65 -0
  645. gaia/eval/webapp/node_modules/safe-buffer/package.json +51 -0
  646. gaia/eval/webapp/node_modules/safer-buffer/LICENSE +21 -0
  647. gaia/eval/webapp/node_modules/safer-buffer/Porting-Buffer.md +268 -0
  648. gaia/eval/webapp/node_modules/safer-buffer/Readme.md +156 -0
  649. gaia/eval/webapp/node_modules/safer-buffer/dangerous.js +58 -0
  650. gaia/eval/webapp/node_modules/safer-buffer/package.json +34 -0
  651. gaia/eval/webapp/node_modules/safer-buffer/safer.js +77 -0
  652. gaia/eval/webapp/node_modules/safer-buffer/tests.js +406 -0
  653. gaia/eval/webapp/node_modules/send/HISTORY.md +526 -0
  654. gaia/eval/webapp/node_modules/send/LICENSE +23 -0
  655. gaia/eval/webapp/node_modules/send/README.md +327 -0
  656. gaia/eval/webapp/node_modules/send/SECURITY.md +24 -0
  657. gaia/eval/webapp/node_modules/send/index.js +1142 -0
  658. gaia/eval/webapp/node_modules/send/node_modules/encodeurl/HISTORY.md +14 -0
  659. gaia/eval/webapp/node_modules/send/node_modules/encodeurl/LICENSE +22 -0
  660. gaia/eval/webapp/node_modules/send/node_modules/encodeurl/README.md +128 -0
  661. gaia/eval/webapp/node_modules/send/node_modules/encodeurl/index.js +60 -0
  662. gaia/eval/webapp/node_modules/send/node_modules/encodeurl/package.json +40 -0
  663. gaia/eval/webapp/node_modules/send/node_modules/ms/index.js +162 -0
  664. gaia/eval/webapp/node_modules/send/node_modules/ms/license.md +21 -0
  665. gaia/eval/webapp/node_modules/send/node_modules/ms/package.json +38 -0
  666. gaia/eval/webapp/node_modules/send/node_modules/ms/readme.md +59 -0
  667. gaia/eval/webapp/node_modules/send/package.json +62 -0
  668. gaia/eval/webapp/node_modules/serve-static/HISTORY.md +487 -0
  669. gaia/eval/webapp/node_modules/serve-static/LICENSE +25 -0
  670. gaia/eval/webapp/node_modules/serve-static/README.md +257 -0
  671. gaia/eval/webapp/node_modules/serve-static/index.js +209 -0
  672. gaia/eval/webapp/node_modules/serve-static/package.json +42 -0
  673. gaia/eval/webapp/node_modules/setprototypeof/LICENSE +13 -0
  674. gaia/eval/webapp/node_modules/setprototypeof/README.md +31 -0
  675. gaia/eval/webapp/node_modules/setprototypeof/index.d.ts +2 -0
  676. gaia/eval/webapp/node_modules/setprototypeof/index.js +17 -0
  677. gaia/eval/webapp/node_modules/setprototypeof/package.json +38 -0
  678. gaia/eval/webapp/node_modules/setprototypeof/test/index.js +24 -0
  679. gaia/eval/webapp/node_modules/side-channel/.editorconfig +9 -0
  680. gaia/eval/webapp/node_modules/side-channel/.eslintrc +12 -0
  681. gaia/eval/webapp/node_modules/side-channel/.github/FUNDING.yml +12 -0
  682. gaia/eval/webapp/node_modules/side-channel/.nycrc +13 -0
  683. gaia/eval/webapp/node_modules/side-channel/CHANGELOG.md +110 -0
  684. gaia/eval/webapp/node_modules/side-channel/LICENSE +21 -0
  685. gaia/eval/webapp/node_modules/side-channel/README.md +61 -0
  686. gaia/eval/webapp/node_modules/side-channel/index.d.ts +14 -0
  687. gaia/eval/webapp/node_modules/side-channel/index.js +43 -0
  688. gaia/eval/webapp/node_modules/side-channel/package.json +85 -0
  689. gaia/eval/webapp/node_modules/side-channel/test/index.js +104 -0
  690. gaia/eval/webapp/node_modules/side-channel/tsconfig.json +9 -0
  691. gaia/eval/webapp/node_modules/side-channel-list/.editorconfig +9 -0
  692. gaia/eval/webapp/node_modules/side-channel-list/.eslintrc +11 -0
  693. gaia/eval/webapp/node_modules/side-channel-list/.github/FUNDING.yml +12 -0
  694. gaia/eval/webapp/node_modules/side-channel-list/.nycrc +13 -0
  695. gaia/eval/webapp/node_modules/side-channel-list/CHANGELOG.md +15 -0
  696. gaia/eval/webapp/node_modules/side-channel-list/LICENSE +21 -0
  697. gaia/eval/webapp/node_modules/side-channel-list/README.md +62 -0
  698. gaia/eval/webapp/node_modules/side-channel-list/index.d.ts +13 -0
  699. gaia/eval/webapp/node_modules/side-channel-list/index.js +113 -0
  700. gaia/eval/webapp/node_modules/side-channel-list/list.d.ts +14 -0
  701. gaia/eval/webapp/node_modules/side-channel-list/package.json +77 -0
  702. gaia/eval/webapp/node_modules/side-channel-list/test/index.js +104 -0
  703. gaia/eval/webapp/node_modules/side-channel-list/tsconfig.json +9 -0
  704. gaia/eval/webapp/node_modules/side-channel-map/.editorconfig +9 -0
  705. gaia/eval/webapp/node_modules/side-channel-map/.eslintrc +11 -0
  706. gaia/eval/webapp/node_modules/side-channel-map/.github/FUNDING.yml +12 -0
  707. gaia/eval/webapp/node_modules/side-channel-map/.nycrc +13 -0
  708. gaia/eval/webapp/node_modules/side-channel-map/CHANGELOG.md +22 -0
  709. gaia/eval/webapp/node_modules/side-channel-map/LICENSE +21 -0
  710. gaia/eval/webapp/node_modules/side-channel-map/README.md +62 -0
  711. gaia/eval/webapp/node_modules/side-channel-map/index.d.ts +15 -0
  712. gaia/eval/webapp/node_modules/side-channel-map/index.js +68 -0
  713. gaia/eval/webapp/node_modules/side-channel-map/package.json +80 -0
  714. gaia/eval/webapp/node_modules/side-channel-map/test/index.js +114 -0
  715. gaia/eval/webapp/node_modules/side-channel-map/tsconfig.json +9 -0
  716. gaia/eval/webapp/node_modules/side-channel-weakmap/.editorconfig +9 -0
  717. gaia/eval/webapp/node_modules/side-channel-weakmap/.eslintrc +12 -0
  718. gaia/eval/webapp/node_modules/side-channel-weakmap/.github/FUNDING.yml +12 -0
  719. gaia/eval/webapp/node_modules/side-channel-weakmap/.nycrc +13 -0
  720. gaia/eval/webapp/node_modules/side-channel-weakmap/CHANGELOG.md +28 -0
  721. gaia/eval/webapp/node_modules/side-channel-weakmap/LICENSE +21 -0
  722. gaia/eval/webapp/node_modules/side-channel-weakmap/README.md +62 -0
  723. gaia/eval/webapp/node_modules/side-channel-weakmap/index.d.ts +15 -0
  724. gaia/eval/webapp/node_modules/side-channel-weakmap/index.js +84 -0
  725. gaia/eval/webapp/node_modules/side-channel-weakmap/package.json +87 -0
  726. gaia/eval/webapp/node_modules/side-channel-weakmap/test/index.js +114 -0
  727. gaia/eval/webapp/node_modules/side-channel-weakmap/tsconfig.json +9 -0
  728. gaia/eval/webapp/node_modules/statuses/HISTORY.md +82 -0
  729. gaia/eval/webapp/node_modules/statuses/LICENSE +23 -0
  730. gaia/eval/webapp/node_modules/statuses/README.md +136 -0
  731. gaia/eval/webapp/node_modules/statuses/codes.json +65 -0
  732. gaia/eval/webapp/node_modules/statuses/index.js +146 -0
  733. gaia/eval/webapp/node_modules/statuses/package.json +49 -0
  734. gaia/eval/webapp/node_modules/toidentifier/HISTORY.md +9 -0
  735. gaia/eval/webapp/node_modules/toidentifier/LICENSE +21 -0
  736. gaia/eval/webapp/node_modules/toidentifier/README.md +61 -0
  737. gaia/eval/webapp/node_modules/toidentifier/index.js +32 -0
  738. gaia/eval/webapp/node_modules/toidentifier/package.json +38 -0
  739. gaia/eval/webapp/node_modules/type-is/HISTORY.md +259 -0
  740. gaia/eval/webapp/node_modules/type-is/LICENSE +23 -0
  741. gaia/eval/webapp/node_modules/type-is/README.md +170 -0
  742. gaia/eval/webapp/node_modules/type-is/index.js +266 -0
  743. gaia/eval/webapp/node_modules/type-is/package.json +45 -0
  744. gaia/eval/webapp/node_modules/unpipe/HISTORY.md +4 -0
  745. gaia/eval/webapp/node_modules/unpipe/LICENSE +22 -0
  746. gaia/eval/webapp/node_modules/unpipe/README.md +43 -0
  747. gaia/eval/webapp/node_modules/unpipe/index.js +69 -0
  748. gaia/eval/webapp/node_modules/unpipe/package.json +27 -0
  749. gaia/eval/webapp/node_modules/util/LICENSE +18 -0
  750. gaia/eval/webapp/node_modules/util/README.md +15 -0
  751. gaia/eval/webapp/node_modules/util/node_modules/inherits/LICENSE +16 -0
  752. gaia/eval/webapp/node_modules/util/node_modules/inherits/README.md +42 -0
  753. gaia/eval/webapp/node_modules/util/node_modules/inherits/inherits.js +7 -0
  754. gaia/eval/webapp/node_modules/util/node_modules/inherits/inherits_browser.js +23 -0
  755. gaia/eval/webapp/node_modules/util/node_modules/inherits/package.json +29 -0
  756. gaia/eval/webapp/node_modules/util/package.json +35 -0
  757. gaia/eval/webapp/node_modules/util/support/isBuffer.js +3 -0
  758. gaia/eval/webapp/node_modules/util/support/isBufferBrowser.js +6 -0
  759. gaia/eval/webapp/node_modules/util/util.js +586 -0
  760. gaia/eval/webapp/node_modules/utils-merge/.npmignore +9 -0
  761. gaia/eval/webapp/node_modules/utils-merge/LICENSE +20 -0
  762. gaia/eval/webapp/node_modules/utils-merge/README.md +34 -0
  763. gaia/eval/webapp/node_modules/utils-merge/index.js +23 -0
  764. gaia/eval/webapp/node_modules/utils-merge/package.json +40 -0
  765. gaia/eval/webapp/node_modules/vary/HISTORY.md +39 -0
  766. gaia/eval/webapp/node_modules/vary/LICENSE +22 -0
  767. gaia/eval/webapp/node_modules/vary/README.md +101 -0
  768. gaia/eval/webapp/node_modules/vary/index.js +149 -0
  769. gaia/eval/webapp/node_modules/vary/package.json +43 -0
  770. gaia/eval/webapp/package-lock.json +875 -0
  771. gaia/eval/webapp/package.json +21 -0
  772. gaia/eval/webapp/public/app.js +3403 -0
  773. gaia/eval/webapp/public/index.html +88 -0
  774. gaia/eval/webapp/public/styles.css +3661 -0
  775. gaia/eval/webapp/server.js +416 -0
  776. gaia/eval/webapp/test-setup.js +73 -0
  777. gaia/llm/__init__.py +2 -0
  778. gaia/llm/lemonade_client.py +3083 -0
  779. gaia/llm/lemonade_manager.py +269 -0
  780. gaia/llm/llm_client.py +729 -0
  781. gaia/llm/vlm_client.py +307 -0
  782. gaia/logger.py +189 -0
  783. gaia/mcp/agent_mcp_server.py +245 -0
  784. gaia/mcp/blender_mcp_client.py +138 -0
  785. gaia/mcp/blender_mcp_server.py +648 -0
  786. gaia/mcp/context7_cache.py +332 -0
  787. gaia/mcp/external_services.py +518 -0
  788. gaia/mcp/mcp_bridge.py +550 -0
  789. gaia/mcp/servers/__init__.py +6 -0
  790. gaia/mcp/servers/docker_mcp.py +83 -0
  791. gaia/rag/__init__.py +10 -0
  792. gaia/rag/app.py +293 -0
  793. gaia/rag/demo.py +304 -0
  794. gaia/rag/pdf_utils.py +235 -0
  795. gaia/rag/sdk.py +2194 -0
  796. gaia/security.py +163 -0
  797. gaia/talk/app.py +289 -0
  798. gaia/talk/sdk.py +538 -0
  799. gaia/util.py +46 -0
  800. gaia/version.py +100 -0
@@ -0,0 +1,1739 @@
1
+ # Copyright(C) 2024-2025 Advanced Micro Devices, Inc. All rights reserved.
2
+ # SPDX-License-Identifier: MIT
3
+ """Checklist Executor for LLM-Driven Code Generation.
4
+
5
+ This module executes checklist items generated by ChecklistGenerator.
6
+ For code-generating templates, the LLM is invoked per item to produce
7
+ contextual, high-quality code. CLI commands remain deterministic.
8
+
9
+ The executor:
10
+ 1. Receives a GeneratedChecklist from ChecklistGenerator
11
+ 2. For each item, routes to LLM generation or deterministic execution
12
+ 3. Tracks results and handles errors with recovery
13
+ 4. Returns a complete ExecutionResult
14
+
15
+ Error handling follows the three-tier strategy:
16
+ 1. RETRY: Simple retries for transient errors
17
+ 2. FIX_AND_RETRY: Auto-fix and retry for known issues
18
+ 3. ABORT: Stop execution for unrecoverable errors
19
+ """
20
+
21
+ import inspect
22
+ import json
23
+ import logging
24
+ import os
25
+ import sys
26
+ from dataclasses import dataclass, field
27
+ from typing import Any, Callable, Dict, List, Optional, Protocol
28
+
29
+ from gaia.agents.base.console import AgentConsole
30
+ from gaia.agents.base.tools import _TOOL_REGISTRY
31
+
32
+ from .checklist_generator import ChecklistItem, GeneratedChecklist
33
+ from .steps.base import StepResult, ToolExecutor, UserContext
34
+ from .steps.error_handler import ErrorHandler, RecoveryAction
35
+ from .template_catalog import get_template
36
+
37
+ logger = logging.getLogger(__name__)
38
+
39
+
40
+ class ChatSDK(Protocol):
41
+ """Protocol for chat SDK interface used by LLM code generation."""
42
+
43
+ def send(self, message: str, timeout: int = 600, no_history: bool = False) -> Any:
44
+ """Send a message and get response."""
45
+ ...
46
+
47
+ def send_stream(self, message: str, **kwargs) -> Any:
48
+ """Send a message and get streaming response."""
49
+ ...
50
+
51
+
52
+ # ============================================================================
53
+ # Template Classification
54
+ # ============================================================================
55
+
56
+ # Templates that execute CLI commands - remain deterministic (no LLM)
57
+ DETERMINISTIC_TEMPLATES = {
58
+ "create_next_app",
59
+ "setup_prisma",
60
+ "prisma_db_sync",
61
+ "setup_testing",
62
+ "run_typescript_check",
63
+ "validate_styles",
64
+ "generate_style_tests",
65
+ "run_tests",
66
+ "fix_code",
67
+ }
68
+
69
+ # Templates that generate code files - use LLM for contextual generation
70
+ # NOTE: generate_prisma_model is NOT here because it must APPEND to schema.prisma,
71
+ # not overwrite it. The manage_data_model tool handles this correctly.
72
+ LLM_GENERATED_TEMPLATES = {
73
+ "generate_react_component",
74
+ "generate_api_route",
75
+ "setup_app_styling",
76
+ "update_landing_page",
77
+ }
78
+
79
+ # Template metadata for validation of LLM-generated code
80
+ TEMPLATE_METADATA: Dict[str, Dict[str, Any]] = {
81
+ "generate_react_component": {
82
+ "list": {
83
+ "requires_client": False,
84
+ "expected_classes": ["page-title", "btn-primary"],
85
+ "file_pattern": "src/app/{resource}s/page.tsx",
86
+ },
87
+ "form": {
88
+ "requires_client": True,
89
+ "expected_classes": [
90
+ "input-field",
91
+ "btn-primary",
92
+ "btn-secondary",
93
+ ],
94
+ "file_pattern": "src/components/{Resource}Form.tsx",
95
+ },
96
+ "new": {
97
+ "requires_client": True,
98
+ "expected_classes": ["page-title", "link-back"],
99
+ "file_pattern": "src/app/{resource}s/new/page.tsx",
100
+ },
101
+ "detail": {
102
+ "requires_client": True,
103
+ "expected_classes": [
104
+ "page-title",
105
+ "btn-primary",
106
+ "btn-danger",
107
+ ],
108
+ "file_pattern": "src/app/{resource}s/[id]/page.tsx",
109
+ },
110
+ },
111
+ "generate_api_route": {
112
+ "collection": {
113
+ "requires_client": False,
114
+ "expected_classes": [],
115
+ "file_pattern": "src/app/api/{resource}s/route.ts",
116
+ },
117
+ "item": {
118
+ "requires_client": False,
119
+ "expected_classes": [],
120
+ "file_pattern": "src/app/api/{resource}s/[id]/route.ts",
121
+ },
122
+ },
123
+ # NOTE: generate_prisma_model removed - uses tool-based execution, not LLM
124
+ "setup_app_styling": {
125
+ "default": {
126
+ "requires_client": False,
127
+ "expected_classes": ["page-title", "btn-primary"],
128
+ "file_pattern": "src/app/globals.css",
129
+ },
130
+ },
131
+ "update_landing_page": {
132
+ "default": {
133
+ "requires_client": False,
134
+ "expected_classes": ["page-title"],
135
+ "file_pattern": "src/app/page.tsx",
136
+ },
137
+ },
138
+ }
139
+
140
+ # Templates whose results should be logged for downstream validation/QA prompts
141
+ VALIDATION_TEMPLATES = {
142
+ "run_typescript_check",
143
+ "validate_styles",
144
+ "run_tests",
145
+ }
146
+
147
+
148
+ @dataclass
149
+ class ItemExecutionResult:
150
+ """Result of executing a single checklist item."""
151
+
152
+ template: str
153
+ params: Dict[str, Any]
154
+ description: str
155
+ success: bool
156
+ files: List[str] = field(default_factory=list)
157
+ warnings: List[str] = field(default_factory=list)
158
+ error: Optional[str] = None
159
+ error_recoverable: bool = True
160
+ output: Dict[str, Any] = field(default_factory=dict)
161
+
162
+ def to_dict(self) -> Dict[str, Any]:
163
+ """Convert to dictionary representation."""
164
+ return {
165
+ "template": self.template,
166
+ "params": self.params,
167
+ "description": self.description,
168
+ "success": self.success,
169
+ "files": self.files,
170
+ "warnings": self.warnings,
171
+ "error": self.error,
172
+ }
173
+
174
+
175
+ @dataclass
176
+ class ValidationLogEntry:
177
+ """Structured log entry for validation/test steps."""
178
+
179
+ template: str
180
+ description: str
181
+ success: bool
182
+ error: Optional[str]
183
+ output: Dict[str, Any] = field(default_factory=dict)
184
+ files: List[str] = field(default_factory=list)
185
+
186
+ def to_dict(self) -> Dict[str, Any]:
187
+ """Convert to plain dictionary for serialization."""
188
+ return {
189
+ "template": self.template,
190
+ "description": self.description,
191
+ "success": self.success,
192
+ "error": self.error,
193
+ "files": self.files,
194
+ "output": self.output,
195
+ }
196
+
197
+
198
+ @dataclass
199
+ class ChecklistExecutionResult:
200
+ """Result of executing a complete checklist."""
201
+
202
+ checklist: GeneratedChecklist
203
+ item_results: List[ItemExecutionResult] = field(default_factory=list)
204
+ success: bool = True
205
+ total_files: List[str] = field(default_factory=list)
206
+ errors: List[str] = field(default_factory=list)
207
+ warnings: List[str] = field(default_factory=list)
208
+ validation_logs: List[ValidationLogEntry] = field(default_factory=list)
209
+
210
+ @property
211
+ def items_succeeded(self) -> int:
212
+ """Count of successfully executed items."""
213
+ return sum(1 for r in self.item_results if r.success)
214
+
215
+ @property
216
+ def items_failed(self) -> int:
217
+ """Count of failed items."""
218
+ return sum(1 for r in self.item_results if not r.success)
219
+
220
+ @property
221
+ def summary(self) -> str:
222
+ """Human-readable summary of execution."""
223
+ status = "SUCCESS" if self.success else "FAILED"
224
+ return (
225
+ f"{status}: {self.items_succeeded}/{len(self.item_results)} items completed, "
226
+ f"{len(self.total_files)} files created"
227
+ )
228
+
229
+ def to_dict(self) -> Dict[str, Any]:
230
+ """Convert to dictionary representation."""
231
+ return {
232
+ "success": self.success,
233
+ "summary": self.summary,
234
+ "reasoning": self.checklist.reasoning,
235
+ "items": [r.to_dict() for r in self.item_results],
236
+ "files": self.total_files,
237
+ "errors": self.errors,
238
+ "warnings": self.warnings,
239
+ "validation_logs": [log.to_dict() for log in self.validation_logs],
240
+ }
241
+
242
+
243
+ # Template to tool mapping
244
+ TEMPLATE_TO_TOOL: Dict[str, str] = {
245
+ "create_next_app": "run_cli_command", # Uses npx create-next-app
246
+ "setup_app_styling": "setup_app_styling",
247
+ "setup_prisma": "run_cli_command", # Uses npx prisma init + creates singleton
248
+ "prisma_db_sync": "run_cli_command", # Uses npx prisma generate && npx prisma db push
249
+ "setup_testing": "setup_nextjs_testing",
250
+ "generate_prisma_model": "manage_data_model",
251
+ "generate_api_route": "manage_api_endpoint",
252
+ "generate_react_component": "manage_react_component",
253
+ "update_landing_page": "update_landing_page",
254
+ "run_typescript_check": "validate_typescript",
255
+ "validate_styles": "validate_styles", # CSS/design system validation (Issue #1002)
256
+ "generate_style_tests": "generate_style_tests", # Generate CSS tests
257
+ "run_tests": "run_cli_command", # Uses npm test
258
+ "fix_code": "fix_code",
259
+ }
260
+
261
+ # Next.js version for create-next-app
262
+ NEXTJS_VERSION = "14.2.33"
263
+
264
+
265
+ class ChecklistExecutor:
266
+ """Execute checklist items with LLM-driven code generation.
267
+
268
+ For code-generating templates, the LLM is invoked per item to produce
269
+ contextual, high-quality code. CLI commands remain deterministic.
270
+
271
+ Template routing:
272
+ - DETERMINISTIC_TEMPLATES: Execute CLI commands directly (no LLM)
273
+ - LLM_GENERATED_TEMPLATES: Use LLM to generate code with template as guidance
274
+ - Fallback: Use tool executor for unknown templates
275
+
276
+ Error recovery uses the three-tier strategy via ErrorHandler:
277
+ 1. RETRY: Simple retry for transient errors
278
+ 2. FIX_AND_RETRY: LLM fixes code then retry
279
+ 3. ESCALATE: LLM rewrites from scratch
280
+ 4. ABORT: Give up after max attempts
281
+ """
282
+
283
+ def __init__(
284
+ self,
285
+ tool_executor: ToolExecutor,
286
+ llm_client: Optional[ChatSDK] = None,
287
+ error_handler: Optional[ErrorHandler] = None,
288
+ progress_callback: Optional[Callable[[str, int, int], None]] = None,
289
+ console: Optional[AgentConsole] = None,
290
+ ):
291
+ """Initialize the checklist executor.
292
+
293
+ Args:
294
+ tool_executor: Function to execute tools (name, args) -> result
295
+ llm_client: Optional LLM client for code generation (enables per-item LLM)
296
+ error_handler: Optional error handler for recovery (enables retries)
297
+ progress_callback: Optional callback(item_desc, current, total)
298
+ console: Optional console for displaying output
299
+ """
300
+ self.tool_executor = tool_executor
301
+ self.llm_client = llm_client
302
+ self.error_handler = error_handler
303
+ self.progress_callback = progress_callback
304
+ self.console = console or AgentConsole()
305
+ self._tool_signature_cache: Dict[str, inspect.Signature] = {}
306
+
307
+ def _tool_accepts_parameter(self, tool_name: str, parameter: str) -> bool:
308
+ """Return True if the tool accepts the provided parameter."""
309
+ tool_entry = _TOOL_REGISTRY.get(tool_name)
310
+ if not tool_entry:
311
+ return False
312
+
313
+ if tool_name in self._tool_signature_cache:
314
+ signature = self._tool_signature_cache[tool_name]
315
+ else:
316
+ tool_func = tool_entry.get("function")
317
+ if not tool_func:
318
+ return False
319
+ try:
320
+ signature = inspect.signature(tool_func)
321
+ except (TypeError, ValueError):
322
+ return False
323
+ self._tool_signature_cache[tool_name] = signature
324
+
325
+ if parameter in signature.parameters:
326
+ return True
327
+
328
+ return any(
329
+ param.kind == inspect.Parameter.VAR_KEYWORD
330
+ for param in signature.parameters.values()
331
+ )
332
+
333
+ def execute(
334
+ self,
335
+ checklist: GeneratedChecklist,
336
+ context: UserContext,
337
+ stop_on_error: bool = True,
338
+ step_through: bool = False,
339
+ ) -> ChecklistExecutionResult:
340
+ """Execute all checklist items in order.
341
+
342
+ Args:
343
+ checklist: Checklist to execute
344
+ context: User context with project info
345
+ stop_on_error: Whether to stop on first critical error
346
+ step_through: Enable step-through debugging
347
+
348
+ Returns:
349
+ ChecklistExecutionResult with all item results
350
+ """
351
+ logger.debug(
352
+ f"Executing checklist with {len(checklist.items)} items: "
353
+ f"{checklist.reasoning}"
354
+ )
355
+
356
+ self.console.print_checklist_reasoning(checklist.reasoning)
357
+
358
+ result = ChecklistExecutionResult(checklist=checklist)
359
+
360
+ # Check for validation errors first
361
+ if not checklist.is_valid:
362
+ logger.error(
363
+ f"Checklist has validation errors: {checklist.validation_errors}"
364
+ )
365
+ result.success = False
366
+ result.errors.extend(checklist.validation_errors)
367
+ return result
368
+
369
+ # Use items in the order generated by LLM
370
+ ordered_items = checklist.items
371
+ total = len(ordered_items)
372
+
373
+ # Execute each item with error recovery
374
+ for idx, item in enumerate(ordered_items, 1):
375
+ self.console.print_checklist(ordered_items, idx - 1)
376
+ self._report_progress(item.description, idx, total)
377
+
378
+ # Use recovery wrapper if error_handler is available
379
+ item_result = self._execute_item_with_recovery(item, context)
380
+ result.item_results.append(item_result)
381
+
382
+ # Capture validation/test output for downstream prompts
383
+ if item.template in VALIDATION_TEMPLATES:
384
+ result.validation_logs.append(
385
+ ValidationLogEntry(
386
+ template=item.template,
387
+ description=item.description,
388
+ success=item_result.success,
389
+ error=item_result.error,
390
+ output=item_result.output,
391
+ files=item_result.files,
392
+ )
393
+ )
394
+
395
+ # Collect files
396
+ result.total_files.extend(item_result.files)
397
+
398
+ # Handle errors
399
+ if not item_result.success:
400
+ result.errors.append(item_result.error or "Unknown error")
401
+
402
+ if stop_on_error and not item_result.error_recoverable:
403
+ logger.error(
404
+ f"Stopping execution due to critical error in "
405
+ f"{item.template}: {item_result.error}"
406
+ )
407
+ result.success = False
408
+ break
409
+
410
+ # Collect warnings
411
+ result.warnings.extend(item_result.warnings)
412
+
413
+ # Handle step-through
414
+ if step_through:
415
+ if not self._handle_step_through(item.description):
416
+ logger.info("Execution stopped by user during step-through")
417
+ break
418
+
419
+ # Update overall success
420
+ if result.items_failed > 0:
421
+ result.success = False
422
+
423
+ logger.info(result.summary)
424
+ return result
425
+
426
+ def _execute_item(
427
+ self,
428
+ item: ChecklistItem,
429
+ context: UserContext,
430
+ ) -> ItemExecutionResult:
431
+ """Execute a single checklist item with routing.
432
+
433
+ Routes execution based on template type:
434
+ - DETERMINISTIC_TEMPLATES: Execute CLI commands directly (no LLM)
435
+ - LLM_GENERATED_TEMPLATES: Use LLM to generate code (if llm_client available)
436
+ - Fallback: Use tool executor for unknown templates
437
+
438
+ Args:
439
+ item: Checklist item to execute
440
+ context: User context
441
+
442
+ Returns:
443
+ ItemExecutionResult
444
+ """
445
+ logger.debug(f"Executing: {item.template} - {item.description}")
446
+
447
+ try:
448
+ # Route 1: Deterministic templates (CLI commands) - no LLM needed
449
+ if item.template in DETERMINISTIC_TEMPLATES:
450
+ logger.debug(f"Deterministic execution for {item.template}")
451
+ return self._execute_deterministic(item, context)
452
+
453
+ # Route 2: LLM-generated templates - use LLM for code generation
454
+ if item.template in LLM_GENERATED_TEMPLATES and self.llm_client:
455
+ logger.info(f"LLM code generation for {item.template}")
456
+ return self._execute_with_llm(item, context)
457
+
458
+ # Route 3: Fallback to tool execution (no LLM or unknown template)
459
+ logger.debug(f"Fallback tool execution for {item.template}")
460
+ return self._execute_via_tool(item, context)
461
+
462
+ except Exception as e:
463
+ logger.exception(f"Exception executing {item.template}")
464
+ return ItemExecutionResult(
465
+ template=item.template,
466
+ params=item.params,
467
+ description=item.description,
468
+ success=False,
469
+ error=str(e),
470
+ error_recoverable=False,
471
+ )
472
+
473
+ def _execute_deterministic(
474
+ self,
475
+ item: ChecklistItem,
476
+ context: UserContext,
477
+ ) -> ItemExecutionResult:
478
+ """Execute a deterministic template (CLI command).
479
+
480
+ These templates don't need LLM - they run predefined commands.
481
+
482
+ Args:
483
+ item: Checklist item to execute
484
+ context: User context
485
+
486
+ Returns:
487
+ ItemExecutionResult
488
+ """
489
+ # Map template to tool name
490
+ tool_name = TEMPLATE_TO_TOOL.get(item.template, item.template)
491
+
492
+ # Build params for CLI execution
493
+ params = self._build_params(item, context)
494
+
495
+ logger.debug(f"Calling tool '{tool_name}' with params: {params}")
496
+
497
+ # Execute the tool
498
+ raw_result = self.tool_executor(tool_name, params)
499
+
500
+ # Parse result
501
+ result = self._parse_tool_result(item, raw_result)
502
+
503
+ # Post-command file operations (cross-platform, avoids shell file writing)
504
+ if result.success and item.template == "setup_prisma":
505
+ self._write_prisma_singleton(context.project_dir)
506
+
507
+ return result
508
+
509
+ def _execute_via_tool(
510
+ self,
511
+ item: ChecklistItem,
512
+ context: UserContext,
513
+ ) -> ItemExecutionResult:
514
+ """Execute via tool executor (fallback when no LLM).
515
+
516
+ Args:
517
+ item: Checklist item to execute
518
+ context: User context
519
+
520
+ Returns:
521
+ ItemExecutionResult
522
+ """
523
+ # Map template to tool name
524
+ tool_name = TEMPLATE_TO_TOOL.get(item.template, item.template)
525
+
526
+ # Build params with project_dir
527
+ params = self._build_params(item, context)
528
+
529
+ logger.debug(f"Calling tool '{tool_name}' with params: {params}")
530
+
531
+ # Execute the tool
532
+ raw_result = self.tool_executor(tool_name, params)
533
+
534
+ # Parse result
535
+ return self._parse_tool_result(item, raw_result)
536
+
537
+ def _execute_with_llm(
538
+ self,
539
+ item: ChecklistItem,
540
+ context: UserContext,
541
+ ) -> ItemExecutionResult:
542
+ """Execute a checklist item using LLM code generation.
543
+
544
+ This is the core of Phase 9 - LLM generates contextual code using
545
+ templates as structural guidance.
546
+
547
+ Args:
548
+ item: Checklist item to execute
549
+ context: User context
550
+
551
+ Returns:
552
+ ItemExecutionResult
553
+ """
554
+ logger.info(f"Generating code with LLM for {item.template}")
555
+
556
+ try:
557
+ # 1. Get template as guidance
558
+ template_guidance = self._get_template_guidance(item)
559
+ if not template_guidance:
560
+ logger.warning(
561
+ f"No template guidance for {item.template}, falling back to tool"
562
+ )
563
+ return self._execute_via_tool(item, context)
564
+
565
+ # 1b. Resolve field definitions for prompt + post-processing
566
+ resolved_fields = self._resolve_fields(item, context)
567
+
568
+ # 2. Build prompt
569
+ prompt = self._build_code_generation_prompt(
570
+ item, context, template_guidance, resolved_fields
571
+ )
572
+
573
+ # 3. Call LLM
574
+ logger.debug(f"Sending prompt to LLM ({len(prompt)} chars)")
575
+
576
+ file_path = self._determine_file_path(item, context)
577
+
578
+ # Start file preview
579
+ self.console.start_file_preview(file_path, max_lines=15)
580
+
581
+ # Stream the response
582
+ full_response = ""
583
+ try:
584
+ # Try streaming first if available
585
+ if hasattr(self.llm_client, "send_stream"):
586
+ for chunk in self.llm_client.send_stream(prompt, timeout=1200):
587
+ if hasattr(chunk, "text"):
588
+ text = chunk.text
589
+ self.console.update_file_preview(text)
590
+ full_response += text
591
+
592
+ if full_response.strip():
593
+ generated_code = full_response
594
+ else:
595
+ raise ValueError("Empty streaming response")
596
+ else:
597
+ # Fallback to non-streaming
598
+ response = self.llm_client.send(prompt, timeout=1200)
599
+ if hasattr(response, "text"):
600
+ generated_code = response.text
601
+ elif hasattr(response, "content"):
602
+ generated_code = response.content
603
+ else:
604
+ generated_code = str(response)
605
+
606
+ self.console.update_file_preview(generated_code)
607
+
608
+ except Exception as e:
609
+ # Fallback if streaming fails
610
+ logger.warning(f"Streaming failed, falling back to standard send: {e}")
611
+ response = self.llm_client.send(prompt, timeout=1200)
612
+ if hasattr(response, "text"):
613
+ generated_code = response.text
614
+ elif hasattr(response, "content"):
615
+ generated_code = response.content
616
+ else:
617
+ generated_code = str(response)
618
+
619
+ self.console.update_file_preview(generated_code)
620
+
621
+ # Stop file preview
622
+ self.console.stop_file_preview()
623
+
624
+ # 4. Clean response (strip markdown if present)
625
+ clean_code = self._clean_llm_response(generated_code)
626
+
627
+ # 5. Validate generated code
628
+ is_valid, issues, is_blocking = self._validate_generated_code(
629
+ clean_code, item
630
+ )
631
+ if not is_valid:
632
+ logger.warning(f"Validation issues for {item.template}: {issues}")
633
+
634
+ # CRITICAL: Block file write for blocking errors (Issue #1002)
635
+ # This prevents TypeScript code from being written to CSS files
636
+ if is_blocking:
637
+ logger.error(
638
+ f"BLOCKING validation error for {item.template}: {issues}"
639
+ )
640
+ return ItemExecutionResult(
641
+ template=item.template,
642
+ params=item.params,
643
+ description=item.description,
644
+ success=False,
645
+ error=f"Content validation failed: {'; '.join(issues)}",
646
+ error_recoverable=True, # Allow LLM retry with recovery
647
+ )
648
+ # Non-blocking issues: log warning and continue (best effort)
649
+
650
+ # 6. Write to file
651
+ full_path = os.path.join(context.project_dir, file_path)
652
+
653
+ # Create directory if needed
654
+ os.makedirs(os.path.dirname(full_path), exist_ok=True)
655
+
656
+ # Write the generated code
657
+ with open(full_path, "w", encoding="utf-8") as f:
658
+ f.write(clean_code)
659
+
660
+ logger.info(f"Wrote LLM-generated code to {file_path}")
661
+
662
+ generated_files = [file_path]
663
+
664
+ return ItemExecutionResult(
665
+ template=item.template,
666
+ params=item.params,
667
+ description=item.description,
668
+ success=True,
669
+ files=generated_files,
670
+ warnings=issues if not is_valid else [],
671
+ )
672
+
673
+ except Exception as e:
674
+ logger.exception(f"LLM generation failed for {item.template}")
675
+ return ItemExecutionResult(
676
+ template=item.template,
677
+ params=item.params,
678
+ description=item.description,
679
+ success=False,
680
+ error=str(e),
681
+ error_recoverable=True,
682
+ )
683
+
684
+ def _build_code_generation_prompt(
685
+ self,
686
+ item: ChecklistItem,
687
+ context: UserContext,
688
+ template_guidance: str,
689
+ fields_override: Optional[Dict[str, str]] = None,
690
+ ) -> str:
691
+ """Build prompt for LLM code generation.
692
+
693
+ Args:
694
+ item: Checklist item describing what to generate
695
+ context: User context with project info
696
+ template_guidance: Template structure as guidance
697
+
698
+ Returns:
699
+ Prompt string for LLM
700
+ """
701
+ # CSS templates need a different prompt - they should NOT generate TypeScript
702
+ css_templates = {"setup_app_styling"}
703
+ if item.template in css_templates:
704
+ return self._build_css_generation_prompt(item, template_guidance)
705
+
706
+ resource = item.params.get("resource", "item")
707
+ variant = item.params.get("variant", "default")
708
+ fields = (
709
+ fields_override
710
+ if fields_override is not None
711
+ else item.params.get("fields", context.schema_fields or {})
712
+ )
713
+
714
+ # Determine file type and output format
715
+ is_css_file = item.template == "setup_app_styling"
716
+ file_type = "CSS" if is_css_file else "TypeScript/TSX"
717
+ code_language = "css" if is_css_file else "typescript"
718
+ start_instruction = (
719
+ "Start immediately with @tailwind directives or CSS rules"
720
+ if is_css_file
721
+ else 'Start immediately with imports or "use client"'
722
+ )
723
+
724
+ # Get required classes for this variant
725
+ required_classes = self._get_required_classes(item)
726
+ required_classes_str = (
727
+ ", ".join(f"`{cls}`" for cls in required_classes)
728
+ if required_classes
729
+ else "None specified"
730
+ )
731
+
732
+ # Build architecture rules - skip TypeScript-specific rules for CSS
733
+ architecture_rules = ""
734
+ if not is_css_file:
735
+ architecture_rules = """## Architecture Rules
736
+ - Use Server Components by default for data fetching
737
+ - Add "use client" directive ONLY when using hooks, event handlers, or browser APIs
738
+ - Define explicit TypeScript types for all props and return values
739
+ - Use Prisma-generated types where applicable
740
+ - Never use `any` type
741
+
742
+ ---"""
743
+
744
+ # Add CSS-specific warning for CSS files
745
+ css_warning = ""
746
+ if is_css_file:
747
+ css_warning = """## CRITICAL: CSS File Requirements
748
+
749
+ This is a CSS file (globals.css). You MUST generate ONLY CSS code:
750
+ - NO TypeScript/JavaScript code
751
+ - NO import statements
752
+ - NO export statements
753
+ - NO const/let/function declarations
754
+ - NO JSX/React components
755
+ - NO TypeScript interfaces or types
756
+ - ONLY CSS rules, @tailwind directives, @layer directives, and CSS selectors
757
+
758
+ ---
759
+
760
+ """
761
+
762
+ return f"""You are an expert Next.js 14+ developer specializing in full-stack TypeScript applications.
763
+
764
+ {css_warning}## CRITICAL: Required CSS Classes
765
+
766
+ Your generated code MUST include these CSS classes:
767
+ {required_classes_str}
768
+
769
+ These classes are MANDATORY and will be validated. Code without them will fail validation.
770
+
771
+ ---
772
+
773
+ ## Task
774
+ Generate a {item.template} ({variant}) for the {resource} resource.
775
+
776
+ ### Purpose
777
+ {item.description}
778
+
779
+ ### User Request Context
780
+ {context.user_request}
781
+
782
+ ### Parameters
783
+ {json.dumps(item.params, indent=2)}
784
+
785
+ ### Data Model Fields
786
+ {json.dumps(fields, indent=2) if fields else "Not specified - use reasonable defaults based on resource name"}
787
+
788
+ ---
789
+
790
+ {architecture_rules}## Design System Classes (Dark Theme)
791
+
792
+ **Containers**: `glass-card` (ALWAYS use for main content container - glassmorphism effect)
793
+ **Typography**: `page-title` (ALWAYS use for h1 headers - gradient text)
794
+ **Buttons**: `btn-primary` (blue gradient), `btn-secondary` (outline), `btn-danger` (red)
795
+ **Forms**: `input-field`, `select-field`, `textarea-field`, `label-text`, `form-group`
796
+ **Navigation**: `link-back` (for ← back links)
797
+ **Checkboxes**: `checkbox-modern` (for boolean fields)
798
+
799
+ Theme: Dark backgrounds (slate-900), white text, blue-500 accents, white/10 borders.
800
+
801
+ ---
802
+
803
+ ## Reference Pattern
804
+
805
+ Adapt this structural pattern. Replace placeholders with actual values for {resource}:
806
+
807
+ ```{code_language}
808
+ {template_guidance}
809
+ ```
810
+
811
+ ---
812
+
813
+ ## Output Format
814
+
815
+ Return ONLY raw {file_type} code:
816
+ - NO markdown code blocks (no ```)
817
+ - NO explanatory text before or after
818
+ - {start_instruction}
819
+ - MUST include all required CSS classes listed above"""
820
+
821
+ def _build_css_generation_prompt(
822
+ self,
823
+ item: ChecklistItem,
824
+ template_guidance: str,
825
+ ) -> str:
826
+ """Build prompt for CSS code generation.
827
+
828
+ This is a specialized prompt for CSS files that ensures the LLM
829
+ generates Tailwind CSS instead of TypeScript/JSX.
830
+
831
+ Args:
832
+ item: Checklist item describing what to generate
833
+ template_guidance: CSS template as guidance
834
+
835
+ Returns:
836
+ Prompt string for LLM
837
+ """
838
+ return f"""You are an expert CSS developer specializing in Tailwind CSS.
839
+
840
+ ## Task
841
+ Generate a Tailwind CSS stylesheet for: {item.description}
842
+
843
+ ## Rules
844
+ - Return ONLY CSS code (Tailwind CSS with @apply directives is valid CSS)
845
+ - NO TypeScript, JavaScript, imports, or exports
846
+ - NO React components or JSX
847
+ - NO markdown code blocks
848
+ - Start with @tailwind directives
849
+
850
+ ## Required Structure
851
+ The CSS must include:
852
+ 1. @tailwind base, components, utilities directives
853
+ 2. :root CSS variables for theming
854
+ 3. @layer components with these classes using @apply:
855
+ - .glass-card (glassmorphism container)
856
+ - .page-title (gradient text heading)
857
+ - .btn-primary, .btn-secondary, .btn-danger (buttons)
858
+ - .input-field (form inputs)
859
+ - .checkbox-modern (styled checkboxes)
860
+ - .link-back (navigation links)
861
+
862
+ ## Reference Pattern
863
+
864
+ Follow this Tailwind CSS template exactly:
865
+
866
+ {template_guidance}
867
+
868
+ ## Output
869
+ Return raw CSS starting with @tailwind base;"""
870
+
871
+ def _get_template_guidance(self, item: ChecklistItem) -> Optional[str]:
872
+ """Get template content as guidance for LLM.
873
+
874
+ The templates from code_patterns.py serve as structural guidance,
875
+ not verbatim content to copy.
876
+
877
+ Args:
878
+ item: Checklist item with template and params
879
+
880
+ Returns:
881
+ Template string if found, None otherwise
882
+ """
883
+ # Import templates lazily to avoid circular imports
884
+ try:
885
+ from ..prompts.code_patterns import (
886
+ API_ROUTE_DYNAMIC_DELETE,
887
+ API_ROUTE_DYNAMIC_GET,
888
+ API_ROUTE_DYNAMIC_PATCH,
889
+ API_ROUTE_GET,
890
+ API_ROUTE_POST,
891
+ APP_GLOBALS_CSS,
892
+ CLIENT_COMPONENT_FORM,
893
+ CLIENT_COMPONENT_NEW_PAGE,
894
+ SERVER_COMPONENT_DETAIL,
895
+ SERVER_COMPONENT_LIST,
896
+ )
897
+ except ImportError:
898
+ logger.warning("Could not import code_patterns templates")
899
+ return None
900
+
901
+ # Compose API route templates
902
+ api_route_collection = f"""import {{ NextResponse }} from "next/server";
903
+ import {{ prisma }} from "@/lib/prisma";
904
+ import {{ z }} from "zod";
905
+
906
+ // Schema for validation
907
+ // IMPORTANT: Use z.coerce.date() for any date/datetime/timestamp fields
908
+ const {{Resource}}Schema = z.object({{
909
+ // Example: publishedOn: z.coerce.date(),
910
+ // Define fields based on your data model
911
+ }});
912
+
913
+ {API_ROUTE_GET}
914
+
915
+ {API_ROUTE_POST}
916
+ """
917
+
918
+ api_route_item = f"""import {{ NextResponse }} from "next/server";
919
+ import {{ prisma }} from "@/lib/prisma";
920
+ import {{ z }} from "zod";
921
+
922
+ // Schema for update validation
923
+ // IMPORTANT: Use z.coerce.date() for any date/datetime/timestamp fields
924
+ const {{Resource}}UpdateSchema = z.object({{
925
+ // Example: publishedOn: z.coerce.date().optional(),
926
+ // Define update fields (all optional for PATCH)
927
+ }}).partial();
928
+
929
+ {API_ROUTE_DYNAMIC_GET}
930
+
931
+ {API_ROUTE_DYNAMIC_PATCH}
932
+
933
+ {API_ROUTE_DYNAMIC_DELETE}
934
+ """
935
+
936
+ # NOTE: Prisma model guidance removed - uses manage_data_model tool, not LLM
937
+
938
+ # Landing page template guidance
939
+ landing_page_guidance = """import Link from "next/link";
940
+
941
+ export default function Home() {
942
+ return (
943
+ <main className="min-h-screen">
944
+ <div className="container mx-auto px-4 py-12 max-w-4xl">
945
+ <h1 className="page-title mb-8">Welcome</h1>
946
+
947
+ <div className="grid gap-6">
948
+ <Link
949
+ href="/{resource}s"
950
+ className="glass-card p-6 block hover:border-indigo-500/50 transition-all duration-300 group"
951
+ >
952
+ <div className="flex items-center justify-between">
953
+ <div>
954
+ <h2 className="text-2xl font-semibold text-slate-100 mb-2 group-hover:text-indigo-400 transition-colors">
955
+ {Resource}s
956
+ </h2>
957
+ <p className="text-slate-400">Manage your {resource}s</p>
958
+ </div>
959
+ <svg className="w-6 h-6 text-slate-500 group-hover:text-indigo-400 group-hover:translate-x-1 transition-all" fill="none" stroke="currentColor" viewBox="0 0 24 24">
960
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
961
+ </svg>
962
+ </div>
963
+ </Link>
964
+ </div>
965
+ </div>
966
+ </main>
967
+ );
968
+ }
969
+ """
970
+
971
+ # Mapping of template names to their guidance
972
+ TEMPLATE_GUIDANCE = {
973
+ "generate_react_component": {
974
+ "list": SERVER_COMPONENT_LIST,
975
+ "form": CLIENT_COMPONENT_FORM,
976
+ "new": CLIENT_COMPONENT_NEW_PAGE,
977
+ "detail": SERVER_COMPONENT_DETAIL,
978
+ },
979
+ "generate_api_route": {
980
+ "collection": api_route_collection,
981
+ "item": api_route_item,
982
+ },
983
+ # NOTE: generate_prisma_model removed - uses manage_data_model tool
984
+ "setup_app_styling": {
985
+ "default": APP_GLOBALS_CSS,
986
+ },
987
+ "update_landing_page": {
988
+ "default": landing_page_guidance,
989
+ },
990
+ }
991
+
992
+ template_name = item.template
993
+ guidance_map = TEMPLATE_GUIDANCE.get(template_name)
994
+
995
+ if guidance_map is None:
996
+ return None
997
+
998
+ if isinstance(guidance_map, str):
999
+ return guidance_map
1000
+
1001
+ # Get variant-specific guidance
1002
+ variant = item.params.get("variant", "default")
1003
+ route_type = item.params.get("type", "default") # For API routes
1004
+
1005
+ # Try variant first, then route_type, then default
1006
+ return (
1007
+ guidance_map.get(variant)
1008
+ or guidance_map.get(route_type)
1009
+ or guidance_map.get("default")
1010
+ )
1011
+
1012
+ def _determine_file_path(
1013
+ self,
1014
+ item: ChecklistItem,
1015
+ context: UserContext, # pylint: disable=unused-argument
1016
+ ) -> str:
1017
+ """Determine the output file path for generated code.
1018
+
1019
+ Args:
1020
+ item: Checklist item with template and params
1021
+ context: User context (unused but kept for consistency)
1022
+
1023
+ Returns:
1024
+ Relative file path from project root
1025
+ """
1026
+ template = item.template
1027
+ params = item.params
1028
+ resource = params.get("resource", "item")
1029
+ resource_cap = resource.capitalize()
1030
+
1031
+ if template == "generate_react_component":
1032
+ variant = params.get("variant", "list")
1033
+
1034
+ if variant == "list":
1035
+ return f"src/app/{resource}s/page.tsx"
1036
+ elif variant == "form":
1037
+ return f"src/components/{resource_cap}Form.tsx"
1038
+ elif variant == "new":
1039
+ return f"src/app/{resource}s/new/page.tsx"
1040
+ elif variant == "detail":
1041
+ return f"src/app/{resource}s/[id]/page.tsx"
1042
+ else:
1043
+ return f"src/components/{resource_cap}{variant.capitalize()}.tsx"
1044
+
1045
+ elif template == "generate_api_route":
1046
+ route_type = params.get("type", "collection")
1047
+ if route_type == "item":
1048
+ return f"src/app/api/{resource}s/[id]/route.ts"
1049
+ else:
1050
+ return f"src/app/api/{resource}s/route.ts"
1051
+
1052
+ # NOTE: generate_prisma_model removed - uses manage_data_model tool, not LLM
1053
+
1054
+ elif template == "setup_app_styling":
1055
+ return "src/app/globals.css"
1056
+
1057
+ elif template == "update_landing_page":
1058
+ return "src/app/page.tsx"
1059
+
1060
+ # Default fallback
1061
+ return f"src/generated/{template}.tsx"
1062
+
1063
+ def _resolve_fields(
1064
+ self, item: ChecklistItem, context: UserContext
1065
+ ) -> Dict[str, str]:
1066
+ """Resolve resource fields for code generation prompts."""
1067
+ params = item.params or {}
1068
+
1069
+ def _normalize(fields: Dict[str, str]) -> Dict[str, str]:
1070
+ type_map = {
1071
+ "string": "string",
1072
+ "text": "string",
1073
+ "int": "number",
1074
+ "float": "float",
1075
+ "double": "float",
1076
+ "number": "number",
1077
+ "boolean": "boolean",
1078
+ "datetime": "datetime",
1079
+ "date": "date",
1080
+ "timestamp": "datetime",
1081
+ "email": "email",
1082
+ "url": "url",
1083
+ }
1084
+ normalized = {}
1085
+ for name, field_type in (fields or {}).items():
1086
+ mapped = type_map.get(field_type.lower(), "string")
1087
+ normalized[name] = mapped
1088
+ return normalized
1089
+
1090
+ if "fields" in params and isinstance(params["fields"], dict):
1091
+ return _normalize(params["fields"])
1092
+
1093
+ if context.schema_fields:
1094
+ return _normalize(context.schema_fields)
1095
+
1096
+ resource = params.get("resource")
1097
+ if not resource:
1098
+ return {}
1099
+
1100
+ try:
1101
+ from ..tools.web_dev_tools import read_prisma_model
1102
+ except ImportError:
1103
+ logger.debug("read_prisma_model unavailable for field resolution")
1104
+ return {}
1105
+
1106
+ try:
1107
+ model_info = read_prisma_model(context.project_dir, resource.capitalize())
1108
+ except Exception as exc: # noqa: BLE001
1109
+ logger.warning(f"Failed to read Prisma model for {resource}: {exc}")
1110
+ return {}
1111
+
1112
+ if not model_info.get("success"):
1113
+ logger.debug(
1114
+ "Could not resolve Prisma fields for %s: %s",
1115
+ resource,
1116
+ model_info.get("error"),
1117
+ )
1118
+ return {}
1119
+
1120
+ prisma_fields = model_info.get("fields", {})
1121
+ return _normalize(prisma_fields)
1122
+
1123
+ def _clean_llm_response(self, response: str) -> str:
1124
+ """Clean LLM response by removing markdown artifacts.
1125
+
1126
+ Args:
1127
+ response: Raw LLM response
1128
+
1129
+ Returns:
1130
+ Cleaned code string
1131
+ """
1132
+ code = response.strip()
1133
+
1134
+ # Remove markdown code blocks
1135
+ if code.startswith("```"):
1136
+ lines = code.split("\n")
1137
+ # Remove first line (```typescript or ```)
1138
+ lines = lines[1:]
1139
+ # Remove last line if it's closing ```
1140
+ if lines and lines[-1].strip() == "```":
1141
+ lines = lines[:-1]
1142
+ code = "\n".join(lines)
1143
+
1144
+ # Also handle case where there might be text before code block
1145
+ if "```typescript" in code or "```tsx" in code:
1146
+ # Find start of code block
1147
+ for marker in ["```typescript", "```tsx", "```"]:
1148
+ if marker in code:
1149
+ start = code.find(marker)
1150
+ end = code.find("```", start + len(marker))
1151
+ if end > start:
1152
+ code = code[start + len(marker) : end]
1153
+ break
1154
+
1155
+ return code.strip()
1156
+
1157
+ def _get_required_classes(self, item: ChecklistItem) -> List[str]:
1158
+ """Get list of required CSS classes for a checklist item.
1159
+
1160
+ Args:
1161
+ item: Checklist item with template and variant info
1162
+
1163
+ Returns:
1164
+ List of required CSS class names
1165
+ """
1166
+ metadata = TEMPLATE_METADATA.get(item.template, {})
1167
+ variant = item.params.get("variant", "default")
1168
+ route_type = item.params.get("type", "default")
1169
+
1170
+ # Try variant, then route_type, then default
1171
+ variant_meta = (
1172
+ metadata.get(variant)
1173
+ or metadata.get(route_type)
1174
+ or metadata.get("default")
1175
+ or {}
1176
+ )
1177
+
1178
+ return variant_meta.get("expected_classes", [])
1179
+
1180
+ def _validate_generated_code(
1181
+ self,
1182
+ code: str,
1183
+ item: ChecklistItem,
1184
+ ) -> tuple[bool, List[str], bool]:
1185
+ """Validate generated code meets requirements.
1186
+
1187
+ Args:
1188
+ code: Generated code to validate
1189
+ item: Checklist item with template info
1190
+
1191
+ Returns:
1192
+ Tuple of (is_valid, list_of_issues, is_blocking)
1193
+ - is_valid: True if no issues found
1194
+ - list_of_issues: List of validation issue messages
1195
+ - is_blocking: True if issues should prevent file write (CRITICAL errors)
1196
+ """
1197
+ issues = []
1198
+ is_blocking = False
1199
+
1200
+ # Check for markdown artifacts that slipped through
1201
+ if code.strip().startswith("```"):
1202
+ issues.append("Code still contains markdown block markers")
1203
+
1204
+ # CRITICAL: For CSS files (setup_app_styling), check for TypeScript content
1205
+ # This catches Issue #1002 where CSS files contain TypeScript code
1206
+ if item.template == "setup_app_styling":
1207
+ css_validation = self._validate_css_content_inline(code)
1208
+ if css_validation["errors"]:
1209
+ issues.extend(css_validation["errors"])
1210
+ is_blocking = True # TypeScript in CSS is a BLOCKING error
1211
+
1212
+ # Get metadata for this template
1213
+ metadata = TEMPLATE_METADATA.get(item.template, {})
1214
+ variant = item.params.get("variant", "default")
1215
+ route_type = item.params.get("type", "default")
1216
+
1217
+ # Try variant, then route_type, then default
1218
+ variant_meta = (
1219
+ metadata.get(variant)
1220
+ or metadata.get(route_type)
1221
+ or metadata.get("default")
1222
+ or {}
1223
+ )
1224
+
1225
+ # Check for expected CSS classes (for UI components)
1226
+ expected_classes = variant_meta.get("expected_classes", [])
1227
+ for cls in expected_classes:
1228
+ if cls not in code:
1229
+ issues.append(f"Missing expected class: {cls}")
1230
+
1231
+ # Check for 'use client' when needed
1232
+ if variant_meta.get("requires_client"):
1233
+ if '"use client"' not in code and "'use client'" not in code:
1234
+ issues.append("Missing 'use client' directive for client component")
1235
+
1236
+ # Check for basic TypeScript syntax
1237
+ if item.template == "generate_react_component":
1238
+ if "export default" not in code and "export function" not in code:
1239
+ issues.append("Missing export statement")
1240
+
1241
+ return len(issues) == 0, issues, is_blocking
1242
+
1243
+ def _validate_css_content_inline(self, content: str) -> Dict[str, Any]:
1244
+ """Validate CSS content for TypeScript/JavaScript code (Issue #1002).
1245
+
1246
+ This is an inline version of the CSS validation for use during LLM
1247
+ code generation. It detects when the LLM accidentally generates
1248
+ TypeScript/JSX code instead of CSS.
1249
+
1250
+ Args:
1251
+ content: File content to validate
1252
+
1253
+ Returns:
1254
+ Dictionary with errors (blocking) and warnings
1255
+ """
1256
+ import re
1257
+
1258
+ errors = []
1259
+ warnings = []
1260
+
1261
+ # CRITICAL: Detect TypeScript/JavaScript code in CSS files
1262
+ # These patterns indicate wrong file content - always invalid
1263
+ typescript_indicators = [
1264
+ (r"^\s*import\s+.*from", "import statement"),
1265
+ (r"^\s*export\s+(default|const|function|class|async)", "export statement"),
1266
+ (r'"use client"|\'use client\'', "React client directive"),
1267
+ (r"^\s*interface\s+\w+", "TypeScript interface"),
1268
+ (r"^\s*type\s+\w+\s*=", "TypeScript type alias"),
1269
+ (r"^\s*const\s+\w+\s*[=:]", "const declaration"),
1270
+ (r"^\s*let\s+\w+\s*[=:]", "let declaration"),
1271
+ (r"^\s*function\s+\w+", "function declaration"),
1272
+ (r"^\s*async\s+function", "async function"),
1273
+ (r"<[A-Z][a-zA-Z]*[\s/>]", "JSX component tag"),
1274
+ (r"useState|useEffect|useRouter|usePathname", "React hook"),
1275
+ ]
1276
+
1277
+ for pattern, description in typescript_indicators:
1278
+ if re.search(pattern, content, re.MULTILINE):
1279
+ errors.append(
1280
+ f"CRITICAL - CSS file contains {description}. "
1281
+ f"This is TypeScript/JSX code, not CSS."
1282
+ )
1283
+
1284
+ # Check for balanced braces
1285
+ if content.count("{") != content.count("}"):
1286
+ errors.append("Mismatched braces in CSS")
1287
+
1288
+ # Check for Tailwind directives
1289
+ has_tailwind = "@tailwind" in content or '@import "tailwindcss' in content
1290
+ if not has_tailwind and len(content.strip()) > 50:
1291
+ warnings.append(
1292
+ "Missing Tailwind directives (@tailwind base/components/utilities)"
1293
+ )
1294
+
1295
+ return {
1296
+ "errors": errors,
1297
+ "warnings": warnings,
1298
+ "is_valid": len(errors) == 0,
1299
+ }
1300
+
1301
+ def _execute_item_with_recovery(
1302
+ self,
1303
+ item: ChecklistItem,
1304
+ context: UserContext,
1305
+ max_attempts: int = 3,
1306
+ ) -> ItemExecutionResult:
1307
+ """Execute a checklist item with error recovery.
1308
+
1309
+ Uses the three-tier recovery strategy via ErrorHandler:
1310
+ 1. RETRY: Simple retry (transient errors)
1311
+ 2. FIX_AND_RETRY: LLM fixes code then retry
1312
+ 3. ESCALATE: LLM rewrites from scratch
1313
+ 4. ABORT: Give up after max attempts
1314
+
1315
+ Args:
1316
+ item: Checklist item to execute
1317
+ context: User context
1318
+ max_attempts: Maximum recovery attempts (default 3)
1319
+
1320
+ Returns:
1321
+ ItemExecutionResult from execution (or recovery attempts)
1322
+ """
1323
+ last_result = None
1324
+
1325
+ for attempt in range(max_attempts):
1326
+ try:
1327
+ # Execute the item
1328
+ result = self._execute_item(item, context)
1329
+ last_result = result
1330
+
1331
+ if result.success:
1332
+ # Reset retry count on success
1333
+ if self.error_handler:
1334
+ self.error_handler.reset_retry_count(item.template)
1335
+ return result
1336
+
1337
+ # No error handler - return failure immediately
1338
+ if not self.error_handler:
1339
+ logger.warning(
1340
+ f"No error handler available for {item.template}, "
1341
+ f"cannot retry: {result.error}"
1342
+ )
1343
+ return result
1344
+
1345
+ # Last attempt - return failure
1346
+ if attempt >= max_attempts - 1:
1347
+ logger.error(
1348
+ f"Max attempts ({max_attempts}) exceeded for {item.template}"
1349
+ )
1350
+ return result
1351
+
1352
+ # Handle failure with error handler
1353
+ logger.info(
1354
+ f"Attempting recovery for {item.template} "
1355
+ f"(attempt {attempt + 1}/{max_attempts}): {result.error}"
1356
+ )
1357
+
1358
+ action, fix_info = self.error_handler.handle_error(
1359
+ item.template,
1360
+ result.error or "Unknown error",
1361
+ {
1362
+ "code": "", # Tool output doesn't include code
1363
+ "project_dir": context.project_dir,
1364
+ },
1365
+ )
1366
+
1367
+ if action == RecoveryAction.ABORT:
1368
+ logger.error(f"Recovery aborted for {item.template}")
1369
+ return result
1370
+
1371
+ if action == RecoveryAction.RETRY:
1372
+ logger.info(
1373
+ f"Retrying {item.template} "
1374
+ f"(attempt {attempt + 2}/{max_attempts})"
1375
+ )
1376
+ continue
1377
+
1378
+ if action in (RecoveryAction.FIX_AND_RETRY, RecoveryAction.ESCALATE):
1379
+ if fix_info:
1380
+ logger.info(
1381
+ f"Fix applied for {item.template}: {fix_info[:100]}..."
1382
+ )
1383
+ logger.info(
1384
+ f"Retrying {item.template} after fix "
1385
+ f"(attempt {attempt + 2}/{max_attempts})"
1386
+ )
1387
+ continue
1388
+
1389
+ except Exception as e:
1390
+ logger.exception(
1391
+ f"Exception in {item.template} (attempt {attempt + 1})"
1392
+ )
1393
+ last_result = ItemExecutionResult(
1394
+ template=item.template,
1395
+ params=item.params,
1396
+ description=item.description,
1397
+ success=False,
1398
+ error=str(e),
1399
+ error_recoverable=True,
1400
+ )
1401
+
1402
+ # Last attempt - return exception result
1403
+ if attempt >= max_attempts - 1:
1404
+ last_result.error_recoverable = False
1405
+ return last_result
1406
+
1407
+ # Should not reach here, but return last result just in case
1408
+ if last_result:
1409
+ return last_result
1410
+
1411
+ return ItemExecutionResult(
1412
+ template=item.template,
1413
+ params=item.params,
1414
+ description=item.description,
1415
+ success=False,
1416
+ error=f"Max attempts ({max_attempts}) exceeded",
1417
+ error_recoverable=False,
1418
+ )
1419
+
1420
+ def _build_params(
1421
+ self,
1422
+ item: ChecklistItem,
1423
+ context: UserContext,
1424
+ ) -> Dict[str, Any]:
1425
+ """Build tool parameters from checklist item and context.
1426
+
1427
+ Args:
1428
+ item: Checklist item
1429
+ context: User context
1430
+
1431
+ Returns:
1432
+ Dictionary of tool parameters
1433
+ """
1434
+ params = dict(item.params)
1435
+ tool_name = TEMPLATE_TO_TOOL.get(item.template, item.template)
1436
+
1437
+ # Handle CLI command templates specially
1438
+ if item.template == "create_next_app":
1439
+ # Convert to run_cli_command format
1440
+ return {
1441
+ "command": (
1442
+ f"npx -y create-next-app@{NEXTJS_VERSION} . "
1443
+ "--typescript --tailwind --eslint --app --src-dir --import-alias '@/*' --yes"
1444
+ ),
1445
+ "working_dir": context.project_dir,
1446
+ "timeout": 1200,
1447
+ }
1448
+
1449
+ if item.template == "run_tests":
1450
+ # Convert to run_cli_command format
1451
+ return {
1452
+ "command": "npm test",
1453
+ "working_dir": context.project_dir,
1454
+ "timeout": 1200,
1455
+ }
1456
+
1457
+ if item.template == "prisma_db_sync":
1458
+ # Generate Prisma client and push schema to database
1459
+ # This MUST run after generate_prisma_model and before API routes
1460
+ return {
1461
+ "command": "npx -y prisma generate && npx -y prisma db push",
1462
+ "working_dir": context.project_dir,
1463
+ "timeout": 1200,
1464
+ }
1465
+
1466
+ # Handle setup_prisma specially - needs to initialize Prisma first
1467
+ if item.template == "setup_prisma":
1468
+ return self._build_setup_prisma_params(item, context)
1469
+
1470
+ # Handle generate_react_component specially - needs component_name derivation
1471
+ if item.template == "generate_react_component":
1472
+ return self._build_react_component_params(item, context)
1473
+
1474
+ # Add project_dir only if tool expects it
1475
+ if "project_dir" not in params and self._tool_accepts_parameter(
1476
+ tool_name, "project_dir"
1477
+ ):
1478
+ params["project_dir"] = context.project_dir
1479
+
1480
+ # Map checklist param names to tool param names
1481
+ param_mapping = {
1482
+ "resource": "resource_name", # generate_api_route -> manage_api_endpoint
1483
+ "model_name": "model_name", # stays the same
1484
+ "variant": "variant", # stays the same
1485
+ }
1486
+
1487
+ # Apply mappings
1488
+ for checklist_name, tool_name in param_mapping.items():
1489
+ if checklist_name in params and checklist_name != tool_name:
1490
+ params[tool_name] = params.pop(checklist_name)
1491
+
1492
+ # Handle specific template parameters
1493
+ template_def = get_template(item.template)
1494
+ if template_def:
1495
+ # Add entity name for data models
1496
+ if item.template == "generate_prisma_model" and "model_name" in params:
1497
+ context.entity_name = params["model_name"]
1498
+
1499
+ # Handle API route type
1500
+ if item.template == "generate_api_route":
1501
+ route_type = params.pop("type", "collection")
1502
+ if route_type == "item":
1503
+ # For item routes, set operations appropriately
1504
+ if "operations" not in params:
1505
+ params["operations"] = ["GET", "PATCH", "DELETE"]
1506
+
1507
+ return params
1508
+
1509
+ def _build_setup_prisma_params(
1510
+ self,
1511
+ item: ChecklistItem, # pylint: disable=unused-argument
1512
+ context: UserContext,
1513
+ ) -> Dict[str, Any]:
1514
+ """Build parameters for Prisma initialization.
1515
+
1516
+ The setup_prisma template needs to:
1517
+ 1. Initialize Prisma with SQLite (npx prisma init)
1518
+ 2. Create the singleton file (src/lib/prisma.ts)
1519
+
1520
+ The CLI commands run via shell, but the singleton file is written
1521
+ via Python's pathlib in _execute_deterministic() for cross-platform
1522
+ compatibility (Windows doesn't support Unix shell file operations).
1523
+
1524
+ Args:
1525
+ item: Checklist item (unused, kept for consistency)
1526
+ context: User context
1527
+
1528
+ Returns:
1529
+ Dictionary of tool parameters for run_cli_command
1530
+ """
1531
+ # Only run CLI commands - file writing is handled separately in
1532
+ # _execute_deterministic() via _write_prisma_singleton() for
1533
+ # cross-platform compatibility (mkdir -p and echo don't work on Windows)
1534
+ command = (
1535
+ "npm install prisma@5 @prisma/client@5 zod && "
1536
+ "npx -y prisma init --datasource-provider sqlite"
1537
+ )
1538
+
1539
+ return {
1540
+ "command": command,
1541
+ "working_dir": context.project_dir,
1542
+ "timeout": 1200,
1543
+ }
1544
+
1545
+ def _write_prisma_singleton(self, project_dir: str) -> None:
1546
+ """Write Prisma singleton file using cross-platform Python.
1547
+
1548
+ This method is called after setup_prisma CLI commands succeed.
1549
+ We use Python's pathlib instead of shell commands (mkdir -p, echo)
1550
+ because those Unix commands don't work on Windows.
1551
+
1552
+ Args:
1553
+ project_dir: Project root directory
1554
+ """
1555
+ from pathlib import Path
1556
+
1557
+ singleton_content = """import { PrismaClient } from "@prisma/client";
1558
+
1559
+ const globalForPrisma = globalThis as unknown as {
1560
+ prisma: PrismaClient | undefined;
1561
+ };
1562
+
1563
+ export const prisma = globalForPrisma.prisma ?? new PrismaClient();
1564
+
1565
+ if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
1566
+ """
1567
+ lib_dir = Path(project_dir) / "src" / "lib"
1568
+ lib_dir.mkdir(parents=True, exist_ok=True)
1569
+ singleton_file = lib_dir / "prisma.ts"
1570
+ singleton_file.write_text(singleton_content)
1571
+ logger.debug(f"Created Prisma singleton at {singleton_file}")
1572
+
1573
+ def _build_react_component_params(
1574
+ self,
1575
+ item: ChecklistItem,
1576
+ context: UserContext,
1577
+ ) -> Dict[str, Any]:
1578
+ """Build parameters for manage_react_component tool.
1579
+
1580
+ The template catalog defines:
1581
+ - resource: Resource name (lowercase, singular)
1582
+ - variant: Component variant (list|form|new|detail|actions)
1583
+ - with_checkboxes: Boolean (optional, not supported by tool)
1584
+
1585
+ The tool expects:
1586
+ - project_dir: Path to project
1587
+ - component_name: Component name (e.g., "TodoList", "UserForm")
1588
+ - component_type: "server" or "client"
1589
+ - resource_name: Associated resource
1590
+ - fields: Resource fields (optional)
1591
+ - variant: Component variant
1592
+
1593
+ Args:
1594
+ item: Checklist item with template params
1595
+ context: User context
1596
+
1597
+ Returns:
1598
+ Dictionary of tool parameters
1599
+ """
1600
+ template_params = dict(item.params)
1601
+
1602
+ # Extract resource and variant
1603
+ resource = template_params.get("resource", "")
1604
+ variant = template_params.get("variant", "list")
1605
+
1606
+ # Generate component_name from resource + variant
1607
+ # e.g., "todo" + "list" -> "TodoList"
1608
+ resource_capitalized = resource.capitalize() if resource else "Item"
1609
+ variant_capitalized = variant.capitalize() if variant else "List"
1610
+
1611
+ # Build component name based on variant
1612
+ if variant == "list":
1613
+ component_name = f"{resource_capitalized}List"
1614
+ elif variant == "form":
1615
+ component_name = f"{resource_capitalized}Form"
1616
+ elif variant == "new":
1617
+ component_name = f"New{resource_capitalized}"
1618
+ elif variant == "detail":
1619
+ component_name = f"{resource_capitalized}Detail"
1620
+ elif variant == "actions":
1621
+ component_name = f"{resource_capitalized}Actions"
1622
+ else:
1623
+ component_name = f"{resource_capitalized}{variant_capitalized}"
1624
+
1625
+ # Determine component_type based on variant
1626
+ # list pages are server components, forms and interactive pages are client
1627
+ if variant in ("list",):
1628
+ component_type = "server"
1629
+ else:
1630
+ component_type = "client"
1631
+
1632
+ # Build the actual tool params
1633
+ tool_params = {
1634
+ "project_dir": context.project_dir,
1635
+ "component_name": component_name,
1636
+ "component_type": component_type,
1637
+ "resource_name": resource,
1638
+ "variant": variant,
1639
+ }
1640
+
1641
+ # Add fields from context if available
1642
+ if context.schema_fields:
1643
+ tool_params["fields"] = context.schema_fields
1644
+
1645
+ # Note: with_checkboxes is NOT passed - tool doesn't support it
1646
+ # The variant and resource determine the component behavior
1647
+
1648
+ return tool_params
1649
+
1650
+ def _parse_tool_result(
1651
+ self,
1652
+ item: ChecklistItem,
1653
+ raw_result: Any,
1654
+ ) -> ItemExecutionResult:
1655
+ """Parse raw tool result into ItemExecutionResult.
1656
+
1657
+ Args:
1658
+ item: Original checklist item
1659
+ raw_result: Raw result from tool execution
1660
+
1661
+ Returns:
1662
+ ItemExecutionResult
1663
+ """
1664
+ # Handle different result types
1665
+ if isinstance(raw_result, StepResult):
1666
+ return ItemExecutionResult(
1667
+ template=item.template,
1668
+ params=item.params,
1669
+ description=item.description,
1670
+ success=raw_result.success,
1671
+ files=raw_result.output.get("files", []),
1672
+ warnings=raw_result.output.get("warnings", []),
1673
+ error=raw_result.error_message,
1674
+ error_recoverable=raw_result.retryable,
1675
+ output=raw_result.output,
1676
+ )
1677
+
1678
+ if isinstance(raw_result, dict):
1679
+ success = raw_result.get("success", True)
1680
+ return ItemExecutionResult(
1681
+ template=item.template,
1682
+ params=item.params,
1683
+ description=item.description,
1684
+ success=success,
1685
+ files=raw_result.get("files", []),
1686
+ warnings=raw_result.get("warnings", []),
1687
+ error=raw_result.get("error"),
1688
+ error_recoverable=raw_result.get("retryable", True),
1689
+ output=raw_result,
1690
+ )
1691
+
1692
+ # Unknown result type - treat as success if truthy
1693
+ return ItemExecutionResult(
1694
+ template=item.template,
1695
+ params=item.params,
1696
+ description=item.description,
1697
+ success=bool(raw_result),
1698
+ output={"raw": raw_result},
1699
+ )
1700
+
1701
+ def _report_progress(self, description: str, current: int, total: int) -> None:
1702
+ """Report progress via callback if available.
1703
+
1704
+ Args:
1705
+ description: Current item description
1706
+ current: Current item number
1707
+ total: Total items
1708
+ """
1709
+ # Log at debug level to avoid duplicate console output (checklist state is already printed)
1710
+ logger.debug(f"[{current}/{total}] {description}")
1711
+ if self.progress_callback:
1712
+ self.progress_callback(description, current, total)
1713
+
1714
+ def _handle_step_through(self, description: str) -> bool:
1715
+ """Handle step-through pause.
1716
+
1717
+ Args:
1718
+ description: Description of the completed step
1719
+
1720
+ Returns:
1721
+ True to continue, False to stop
1722
+ """
1723
+ # Check for TTY to avoid hanging in non-interactive modes
1724
+ if not sys.stdin or not sys.stdin.isatty():
1725
+ # In non-interactive mode, log and continue
1726
+ logger.debug(
1727
+ f"Step-through enabled but no TTY. Continuing after: {description}"
1728
+ )
1729
+ return True
1730
+
1731
+ self.console.print_step_paused(description)
1732
+
1733
+ try:
1734
+ response = input("> ").strip().lower()
1735
+ if response in ["n", "no", "q", "quit", "exit"]:
1736
+ return False
1737
+ return True
1738
+ except (EOFError, KeyboardInterrupt):
1739
+ return False