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.
- amd_gaia-0.14.1.dist-info/METADATA +768 -0
- amd_gaia-0.14.1.dist-info/RECORD +800 -0
- amd_gaia-0.14.1.dist-info/WHEEL +5 -0
- amd_gaia-0.14.1.dist-info/entry_points.txt +5 -0
- amd_gaia-0.14.1.dist-info/licenses/LICENSE.md +21 -0
- amd_gaia-0.14.1.dist-info/top_level.txt +1 -0
- gaia/__init__.py +2 -0
- gaia/agents/__init__.py +19 -0
- gaia/agents/base/__init__.py +9 -0
- gaia/agents/base/agent.py +2072 -0
- gaia/agents/base/api_agent.py +120 -0
- gaia/agents/base/console.py +1457 -0
- gaia/agents/base/mcp_agent.py +86 -0
- gaia/agents/base/tools.py +83 -0
- gaia/agents/blender/agent.py +556 -0
- gaia/agents/blender/agent_simple.py +135 -0
- gaia/agents/blender/app.py +211 -0
- gaia/agents/blender/app_simple.py +41 -0
- gaia/agents/blender/core/__init__.py +16 -0
- gaia/agents/blender/core/materials.py +506 -0
- gaia/agents/blender/core/objects.py +316 -0
- gaia/agents/blender/core/rendering.py +225 -0
- gaia/agents/blender/core/scene.py +220 -0
- gaia/agents/blender/core/view.py +146 -0
- gaia/agents/chat/__init__.py +9 -0
- gaia/agents/chat/agent.py +975 -0
- gaia/agents/chat/app.py +1058 -0
- gaia/agents/chat/session.py +508 -0
- gaia/agents/chat/tools/__init__.py +15 -0
- gaia/agents/chat/tools/file_tools.py +96 -0
- gaia/agents/chat/tools/rag_tools.py +1729 -0
- gaia/agents/chat/tools/shell_tools.py +436 -0
- gaia/agents/code/__init__.py +7 -0
- gaia/agents/code/agent.py +547 -0
- gaia/agents/code/app.py +266 -0
- gaia/agents/code/models.py +135 -0
- gaia/agents/code/orchestration/__init__.py +24 -0
- gaia/agents/code/orchestration/checklist_executor.py +1739 -0
- gaia/agents/code/orchestration/checklist_generator.py +709 -0
- gaia/agents/code/orchestration/factories/__init__.py +9 -0
- gaia/agents/code/orchestration/factories/base.py +63 -0
- gaia/agents/code/orchestration/factories/nextjs_factory.py +118 -0
- gaia/agents/code/orchestration/factories/python_factory.py +106 -0
- gaia/agents/code/orchestration/orchestrator.py +610 -0
- gaia/agents/code/orchestration/project_analyzer.py +391 -0
- gaia/agents/code/orchestration/steps/__init__.py +67 -0
- gaia/agents/code/orchestration/steps/base.py +188 -0
- gaia/agents/code/orchestration/steps/error_handler.py +314 -0
- gaia/agents/code/orchestration/steps/nextjs.py +828 -0
- gaia/agents/code/orchestration/steps/python.py +307 -0
- gaia/agents/code/orchestration/template_catalog.py +463 -0
- gaia/agents/code/orchestration/workflows/__init__.py +14 -0
- gaia/agents/code/orchestration/workflows/base.py +80 -0
- gaia/agents/code/orchestration/workflows/nextjs.py +186 -0
- gaia/agents/code/orchestration/workflows/python.py +94 -0
- gaia/agents/code/prompts/__init__.py +11 -0
- gaia/agents/code/prompts/base_prompt.py +77 -0
- gaia/agents/code/prompts/code_patterns.py +1925 -0
- gaia/agents/code/prompts/nextjs_prompt.py +40 -0
- gaia/agents/code/prompts/python_prompt.py +109 -0
- gaia/agents/code/schema_inference.py +365 -0
- gaia/agents/code/system_prompt.py +41 -0
- gaia/agents/code/tools/__init__.py +42 -0
- gaia/agents/code/tools/cli_tools.py +1138 -0
- gaia/agents/code/tools/code_formatting.py +319 -0
- gaia/agents/code/tools/code_tools.py +769 -0
- gaia/agents/code/tools/error_fixing.py +1347 -0
- gaia/agents/code/tools/external_tools.py +180 -0
- gaia/agents/code/tools/file_io.py +845 -0
- gaia/agents/code/tools/prisma_tools.py +190 -0
- gaia/agents/code/tools/project_management.py +1016 -0
- gaia/agents/code/tools/testing.py +321 -0
- gaia/agents/code/tools/typescript_tools.py +122 -0
- gaia/agents/code/tools/validation_parsing.py +461 -0
- gaia/agents/code/tools/validation_tools.py +803 -0
- gaia/agents/code/tools/web_dev_tools.py +1744 -0
- gaia/agents/code/validators/__init__.py +16 -0
- gaia/agents/code/validators/antipattern_checker.py +241 -0
- gaia/agents/code/validators/ast_analyzer.py +197 -0
- gaia/agents/code/validators/requirements_validator.py +145 -0
- gaia/agents/code/validators/syntax_validator.py +171 -0
- gaia/agents/docker/__init__.py +7 -0
- gaia/agents/docker/agent.py +642 -0
- gaia/agents/jira/__init__.py +11 -0
- gaia/agents/jira/agent.py +894 -0
- gaia/agents/jira/jql_templates.py +299 -0
- gaia/agents/routing/__init__.py +7 -0
- gaia/agents/routing/agent.py +512 -0
- gaia/agents/routing/system_prompt.py +75 -0
- gaia/api/__init__.py +23 -0
- gaia/api/agent_registry.py +238 -0
- gaia/api/app.py +305 -0
- gaia/api/openai_server.py +575 -0
- gaia/api/schemas.py +186 -0
- gaia/api/sse_handler.py +370 -0
- gaia/apps/__init__.py +4 -0
- gaia/apps/llm/__init__.py +6 -0
- gaia/apps/llm/app.py +169 -0
- gaia/apps/summarize/app.py +633 -0
- gaia/apps/summarize/html_viewer.py +133 -0
- gaia/apps/summarize/pdf_formatter.py +284 -0
- gaia/audio/__init__.py +2 -0
- gaia/audio/audio_client.py +439 -0
- gaia/audio/audio_recorder.py +269 -0
- gaia/audio/kokoro_tts.py +599 -0
- gaia/audio/whisper_asr.py +432 -0
- gaia/chat/__init__.py +16 -0
- gaia/chat/app.py +430 -0
- gaia/chat/prompts.py +522 -0
- gaia/chat/sdk.py +1200 -0
- gaia/cli.py +5621 -0
- gaia/eval/batch_experiment.py +2332 -0
- gaia/eval/claude.py +542 -0
- gaia/eval/config.py +37 -0
- gaia/eval/email_generator.py +512 -0
- gaia/eval/eval.py +3179 -0
- gaia/eval/groundtruth.py +1130 -0
- gaia/eval/transcript_generator.py +582 -0
- gaia/eval/webapp/README.md +168 -0
- gaia/eval/webapp/node_modules/.bin/mime +16 -0
- gaia/eval/webapp/node_modules/.bin/mime.cmd +17 -0
- gaia/eval/webapp/node_modules/.bin/mime.ps1 +28 -0
- gaia/eval/webapp/node_modules/.package-lock.json +865 -0
- gaia/eval/webapp/node_modules/accepts/HISTORY.md +243 -0
- gaia/eval/webapp/node_modules/accepts/LICENSE +23 -0
- gaia/eval/webapp/node_modules/accepts/README.md +140 -0
- gaia/eval/webapp/node_modules/accepts/index.js +238 -0
- gaia/eval/webapp/node_modules/accepts/package.json +47 -0
- gaia/eval/webapp/node_modules/array-flatten/LICENSE +21 -0
- gaia/eval/webapp/node_modules/array-flatten/README.md +43 -0
- gaia/eval/webapp/node_modules/array-flatten/array-flatten.js +64 -0
- gaia/eval/webapp/node_modules/array-flatten/package.json +39 -0
- gaia/eval/webapp/node_modules/body-parser/HISTORY.md +672 -0
- gaia/eval/webapp/node_modules/body-parser/LICENSE +23 -0
- gaia/eval/webapp/node_modules/body-parser/README.md +476 -0
- gaia/eval/webapp/node_modules/body-parser/SECURITY.md +25 -0
- gaia/eval/webapp/node_modules/body-parser/index.js +156 -0
- gaia/eval/webapp/node_modules/body-parser/lib/read.js +205 -0
- gaia/eval/webapp/node_modules/body-parser/lib/types/json.js +247 -0
- gaia/eval/webapp/node_modules/body-parser/lib/types/raw.js +101 -0
- gaia/eval/webapp/node_modules/body-parser/lib/types/text.js +121 -0
- gaia/eval/webapp/node_modules/body-parser/lib/types/urlencoded.js +307 -0
- gaia/eval/webapp/node_modules/body-parser/package.json +56 -0
- gaia/eval/webapp/node_modules/bytes/History.md +97 -0
- gaia/eval/webapp/node_modules/bytes/LICENSE +23 -0
- gaia/eval/webapp/node_modules/bytes/Readme.md +152 -0
- gaia/eval/webapp/node_modules/bytes/index.js +170 -0
- gaia/eval/webapp/node_modules/bytes/package.json +42 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/.eslintrc +17 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/.nycrc +9 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/CHANGELOG.md +30 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/LICENSE +21 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/README.md +62 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/actualApply.d.ts +1 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/actualApply.js +10 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/applyBind.d.ts +19 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/applyBind.js +10 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionApply.d.ts +1 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionApply.js +4 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionCall.d.ts +1 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/functionCall.js +4 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/index.d.ts +64 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/index.js +15 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/package.json +85 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/reflectApply.d.ts +3 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/reflectApply.js +4 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/test/index.js +63 -0
- gaia/eval/webapp/node_modules/call-bind-apply-helpers/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/call-bound/.eslintrc +13 -0
- gaia/eval/webapp/node_modules/call-bound/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/call-bound/.nycrc +9 -0
- gaia/eval/webapp/node_modules/call-bound/CHANGELOG.md +42 -0
- gaia/eval/webapp/node_modules/call-bound/LICENSE +21 -0
- gaia/eval/webapp/node_modules/call-bound/README.md +53 -0
- gaia/eval/webapp/node_modules/call-bound/index.d.ts +94 -0
- gaia/eval/webapp/node_modules/call-bound/index.js +19 -0
- gaia/eval/webapp/node_modules/call-bound/package.json +99 -0
- gaia/eval/webapp/node_modules/call-bound/test/index.js +61 -0
- gaia/eval/webapp/node_modules/call-bound/tsconfig.json +10 -0
- gaia/eval/webapp/node_modules/content-disposition/HISTORY.md +60 -0
- gaia/eval/webapp/node_modules/content-disposition/LICENSE +22 -0
- gaia/eval/webapp/node_modules/content-disposition/README.md +142 -0
- gaia/eval/webapp/node_modules/content-disposition/index.js +458 -0
- gaia/eval/webapp/node_modules/content-disposition/package.json +44 -0
- gaia/eval/webapp/node_modules/content-type/HISTORY.md +29 -0
- gaia/eval/webapp/node_modules/content-type/LICENSE +22 -0
- gaia/eval/webapp/node_modules/content-type/README.md +94 -0
- gaia/eval/webapp/node_modules/content-type/index.js +225 -0
- gaia/eval/webapp/node_modules/content-type/package.json +42 -0
- gaia/eval/webapp/node_modules/cookie/LICENSE +24 -0
- gaia/eval/webapp/node_modules/cookie/README.md +317 -0
- gaia/eval/webapp/node_modules/cookie/SECURITY.md +25 -0
- gaia/eval/webapp/node_modules/cookie/index.js +334 -0
- gaia/eval/webapp/node_modules/cookie/package.json +44 -0
- gaia/eval/webapp/node_modules/cookie-signature/.npmignore +4 -0
- gaia/eval/webapp/node_modules/cookie-signature/History.md +38 -0
- gaia/eval/webapp/node_modules/cookie-signature/Readme.md +42 -0
- gaia/eval/webapp/node_modules/cookie-signature/index.js +51 -0
- gaia/eval/webapp/node_modules/cookie-signature/package.json +18 -0
- gaia/eval/webapp/node_modules/debug/.coveralls.yml +1 -0
- gaia/eval/webapp/node_modules/debug/.eslintrc +11 -0
- gaia/eval/webapp/node_modules/debug/.npmignore +9 -0
- gaia/eval/webapp/node_modules/debug/.travis.yml +14 -0
- gaia/eval/webapp/node_modules/debug/CHANGELOG.md +362 -0
- gaia/eval/webapp/node_modules/debug/LICENSE +19 -0
- gaia/eval/webapp/node_modules/debug/Makefile +50 -0
- gaia/eval/webapp/node_modules/debug/README.md +312 -0
- gaia/eval/webapp/node_modules/debug/component.json +19 -0
- gaia/eval/webapp/node_modules/debug/karma.conf.js +70 -0
- gaia/eval/webapp/node_modules/debug/node.js +1 -0
- gaia/eval/webapp/node_modules/debug/package.json +49 -0
- gaia/eval/webapp/node_modules/debug/src/browser.js +185 -0
- gaia/eval/webapp/node_modules/debug/src/debug.js +202 -0
- gaia/eval/webapp/node_modules/debug/src/index.js +10 -0
- gaia/eval/webapp/node_modules/debug/src/inspector-log.js +15 -0
- gaia/eval/webapp/node_modules/debug/src/node.js +248 -0
- gaia/eval/webapp/node_modules/depd/History.md +103 -0
- gaia/eval/webapp/node_modules/depd/LICENSE +22 -0
- gaia/eval/webapp/node_modules/depd/Readme.md +280 -0
- gaia/eval/webapp/node_modules/depd/index.js +538 -0
- gaia/eval/webapp/node_modules/depd/lib/browser/index.js +77 -0
- gaia/eval/webapp/node_modules/depd/package.json +45 -0
- gaia/eval/webapp/node_modules/destroy/LICENSE +23 -0
- gaia/eval/webapp/node_modules/destroy/README.md +63 -0
- gaia/eval/webapp/node_modules/destroy/index.js +209 -0
- gaia/eval/webapp/node_modules/destroy/package.json +48 -0
- gaia/eval/webapp/node_modules/dunder-proto/.eslintrc +5 -0
- gaia/eval/webapp/node_modules/dunder-proto/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/dunder-proto/.nycrc +13 -0
- gaia/eval/webapp/node_modules/dunder-proto/CHANGELOG.md +24 -0
- gaia/eval/webapp/node_modules/dunder-proto/LICENSE +21 -0
- gaia/eval/webapp/node_modules/dunder-proto/README.md +54 -0
- gaia/eval/webapp/node_modules/dunder-proto/get.d.ts +5 -0
- gaia/eval/webapp/node_modules/dunder-proto/get.js +30 -0
- gaia/eval/webapp/node_modules/dunder-proto/package.json +76 -0
- gaia/eval/webapp/node_modules/dunder-proto/set.d.ts +5 -0
- gaia/eval/webapp/node_modules/dunder-proto/set.js +35 -0
- gaia/eval/webapp/node_modules/dunder-proto/test/get.js +34 -0
- gaia/eval/webapp/node_modules/dunder-proto/test/index.js +4 -0
- gaia/eval/webapp/node_modules/dunder-proto/test/set.js +50 -0
- gaia/eval/webapp/node_modules/dunder-proto/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/ee-first/LICENSE +22 -0
- gaia/eval/webapp/node_modules/ee-first/README.md +80 -0
- gaia/eval/webapp/node_modules/ee-first/index.js +95 -0
- gaia/eval/webapp/node_modules/ee-first/package.json +29 -0
- gaia/eval/webapp/node_modules/encodeurl/LICENSE +22 -0
- gaia/eval/webapp/node_modules/encodeurl/README.md +109 -0
- gaia/eval/webapp/node_modules/encodeurl/index.js +60 -0
- gaia/eval/webapp/node_modules/encodeurl/package.json +40 -0
- gaia/eval/webapp/node_modules/es-define-property/.eslintrc +13 -0
- gaia/eval/webapp/node_modules/es-define-property/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/es-define-property/.nycrc +9 -0
- gaia/eval/webapp/node_modules/es-define-property/CHANGELOG.md +29 -0
- gaia/eval/webapp/node_modules/es-define-property/LICENSE +21 -0
- gaia/eval/webapp/node_modules/es-define-property/README.md +49 -0
- gaia/eval/webapp/node_modules/es-define-property/index.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-define-property/index.js +14 -0
- gaia/eval/webapp/node_modules/es-define-property/package.json +81 -0
- gaia/eval/webapp/node_modules/es-define-property/test/index.js +56 -0
- gaia/eval/webapp/node_modules/es-define-property/tsconfig.json +10 -0
- gaia/eval/webapp/node_modules/es-errors/.eslintrc +5 -0
- gaia/eval/webapp/node_modules/es-errors/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/es-errors/CHANGELOG.md +40 -0
- gaia/eval/webapp/node_modules/es-errors/LICENSE +21 -0
- gaia/eval/webapp/node_modules/es-errors/README.md +55 -0
- gaia/eval/webapp/node_modules/es-errors/eval.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/eval.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/index.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/index.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/package.json +80 -0
- gaia/eval/webapp/node_modules/es-errors/range.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/range.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/ref.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/ref.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/syntax.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/syntax.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/test/index.js +19 -0
- gaia/eval/webapp/node_modules/es-errors/tsconfig.json +49 -0
- gaia/eval/webapp/node_modules/es-errors/type.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/type.js +4 -0
- gaia/eval/webapp/node_modules/es-errors/uri.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-errors/uri.js +4 -0
- gaia/eval/webapp/node_modules/es-object-atoms/.eslintrc +16 -0
- gaia/eval/webapp/node_modules/es-object-atoms/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/es-object-atoms/CHANGELOG.md +37 -0
- gaia/eval/webapp/node_modules/es-object-atoms/LICENSE +21 -0
- gaia/eval/webapp/node_modules/es-object-atoms/README.md +63 -0
- gaia/eval/webapp/node_modules/es-object-atoms/RequireObjectCoercible.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-object-atoms/RequireObjectCoercible.js +11 -0
- gaia/eval/webapp/node_modules/es-object-atoms/ToObject.d.ts +7 -0
- gaia/eval/webapp/node_modules/es-object-atoms/ToObject.js +10 -0
- gaia/eval/webapp/node_modules/es-object-atoms/index.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-object-atoms/index.js +4 -0
- gaia/eval/webapp/node_modules/es-object-atoms/isObject.d.ts +3 -0
- gaia/eval/webapp/node_modules/es-object-atoms/isObject.js +6 -0
- gaia/eval/webapp/node_modules/es-object-atoms/package.json +80 -0
- gaia/eval/webapp/node_modules/es-object-atoms/test/index.js +38 -0
- gaia/eval/webapp/node_modules/es-object-atoms/tsconfig.json +6 -0
- gaia/eval/webapp/node_modules/escape-html/LICENSE +24 -0
- gaia/eval/webapp/node_modules/escape-html/Readme.md +43 -0
- gaia/eval/webapp/node_modules/escape-html/index.js +78 -0
- gaia/eval/webapp/node_modules/escape-html/package.json +24 -0
- gaia/eval/webapp/node_modules/etag/HISTORY.md +83 -0
- gaia/eval/webapp/node_modules/etag/LICENSE +22 -0
- gaia/eval/webapp/node_modules/etag/README.md +159 -0
- gaia/eval/webapp/node_modules/etag/index.js +131 -0
- gaia/eval/webapp/node_modules/etag/package.json +47 -0
- gaia/eval/webapp/node_modules/express/History.md +3656 -0
- gaia/eval/webapp/node_modules/express/LICENSE +24 -0
- gaia/eval/webapp/node_modules/express/Readme.md +260 -0
- gaia/eval/webapp/node_modules/express/index.js +11 -0
- gaia/eval/webapp/node_modules/express/lib/application.js +661 -0
- gaia/eval/webapp/node_modules/express/lib/express.js +116 -0
- gaia/eval/webapp/node_modules/express/lib/middleware/init.js +43 -0
- gaia/eval/webapp/node_modules/express/lib/middleware/query.js +47 -0
- gaia/eval/webapp/node_modules/express/lib/request.js +525 -0
- gaia/eval/webapp/node_modules/express/lib/response.js +1179 -0
- gaia/eval/webapp/node_modules/express/lib/router/index.js +673 -0
- gaia/eval/webapp/node_modules/express/lib/router/layer.js +181 -0
- gaia/eval/webapp/node_modules/express/lib/router/route.js +230 -0
- gaia/eval/webapp/node_modules/express/lib/utils.js +303 -0
- gaia/eval/webapp/node_modules/express/lib/view.js +182 -0
- gaia/eval/webapp/node_modules/express/package.json +102 -0
- gaia/eval/webapp/node_modules/finalhandler/HISTORY.md +210 -0
- gaia/eval/webapp/node_modules/finalhandler/LICENSE +22 -0
- gaia/eval/webapp/node_modules/finalhandler/README.md +147 -0
- gaia/eval/webapp/node_modules/finalhandler/SECURITY.md +25 -0
- gaia/eval/webapp/node_modules/finalhandler/index.js +341 -0
- gaia/eval/webapp/node_modules/finalhandler/package.json +47 -0
- gaia/eval/webapp/node_modules/forwarded/HISTORY.md +21 -0
- gaia/eval/webapp/node_modules/forwarded/LICENSE +22 -0
- gaia/eval/webapp/node_modules/forwarded/README.md +57 -0
- gaia/eval/webapp/node_modules/forwarded/index.js +90 -0
- gaia/eval/webapp/node_modules/forwarded/package.json +45 -0
- gaia/eval/webapp/node_modules/fresh/HISTORY.md +70 -0
- gaia/eval/webapp/node_modules/fresh/LICENSE +23 -0
- gaia/eval/webapp/node_modules/fresh/README.md +119 -0
- gaia/eval/webapp/node_modules/fresh/index.js +137 -0
- gaia/eval/webapp/node_modules/fresh/package.json +46 -0
- gaia/eval/webapp/node_modules/fs/README.md +9 -0
- gaia/eval/webapp/node_modules/fs/package.json +20 -0
- gaia/eval/webapp/node_modules/function-bind/.eslintrc +21 -0
- gaia/eval/webapp/node_modules/function-bind/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/function-bind/.github/SECURITY.md +3 -0
- gaia/eval/webapp/node_modules/function-bind/.nycrc +13 -0
- gaia/eval/webapp/node_modules/function-bind/CHANGELOG.md +136 -0
- gaia/eval/webapp/node_modules/function-bind/LICENSE +20 -0
- gaia/eval/webapp/node_modules/function-bind/README.md +46 -0
- gaia/eval/webapp/node_modules/function-bind/implementation.js +84 -0
- gaia/eval/webapp/node_modules/function-bind/index.js +5 -0
- gaia/eval/webapp/node_modules/function-bind/package.json +87 -0
- gaia/eval/webapp/node_modules/function-bind/test/.eslintrc +9 -0
- gaia/eval/webapp/node_modules/function-bind/test/index.js +252 -0
- gaia/eval/webapp/node_modules/get-intrinsic/.eslintrc +42 -0
- gaia/eval/webapp/node_modules/get-intrinsic/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/get-intrinsic/.nycrc +9 -0
- gaia/eval/webapp/node_modules/get-intrinsic/CHANGELOG.md +186 -0
- gaia/eval/webapp/node_modules/get-intrinsic/LICENSE +21 -0
- gaia/eval/webapp/node_modules/get-intrinsic/README.md +71 -0
- gaia/eval/webapp/node_modules/get-intrinsic/index.js +378 -0
- gaia/eval/webapp/node_modules/get-intrinsic/package.json +97 -0
- gaia/eval/webapp/node_modules/get-intrinsic/test/GetIntrinsic.js +274 -0
- gaia/eval/webapp/node_modules/get-proto/.eslintrc +10 -0
- gaia/eval/webapp/node_modules/get-proto/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/get-proto/.nycrc +9 -0
- gaia/eval/webapp/node_modules/get-proto/CHANGELOG.md +21 -0
- gaia/eval/webapp/node_modules/get-proto/LICENSE +21 -0
- gaia/eval/webapp/node_modules/get-proto/Object.getPrototypeOf.d.ts +5 -0
- gaia/eval/webapp/node_modules/get-proto/Object.getPrototypeOf.js +6 -0
- gaia/eval/webapp/node_modules/get-proto/README.md +50 -0
- gaia/eval/webapp/node_modules/get-proto/Reflect.getPrototypeOf.d.ts +3 -0
- gaia/eval/webapp/node_modules/get-proto/Reflect.getPrototypeOf.js +4 -0
- gaia/eval/webapp/node_modules/get-proto/index.d.ts +5 -0
- gaia/eval/webapp/node_modules/get-proto/index.js +27 -0
- gaia/eval/webapp/node_modules/get-proto/package.json +81 -0
- gaia/eval/webapp/node_modules/get-proto/test/index.js +68 -0
- gaia/eval/webapp/node_modules/get-proto/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/gopd/.eslintrc +16 -0
- gaia/eval/webapp/node_modules/gopd/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/gopd/CHANGELOG.md +45 -0
- gaia/eval/webapp/node_modules/gopd/LICENSE +21 -0
- gaia/eval/webapp/node_modules/gopd/README.md +40 -0
- gaia/eval/webapp/node_modules/gopd/gOPD.d.ts +1 -0
- gaia/eval/webapp/node_modules/gopd/gOPD.js +4 -0
- gaia/eval/webapp/node_modules/gopd/index.d.ts +5 -0
- gaia/eval/webapp/node_modules/gopd/index.js +15 -0
- gaia/eval/webapp/node_modules/gopd/package.json +77 -0
- gaia/eval/webapp/node_modules/gopd/test/index.js +36 -0
- gaia/eval/webapp/node_modules/gopd/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/has-symbols/.eslintrc +11 -0
- gaia/eval/webapp/node_modules/has-symbols/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/has-symbols/.nycrc +9 -0
- gaia/eval/webapp/node_modules/has-symbols/CHANGELOG.md +91 -0
- gaia/eval/webapp/node_modules/has-symbols/LICENSE +21 -0
- gaia/eval/webapp/node_modules/has-symbols/README.md +46 -0
- gaia/eval/webapp/node_modules/has-symbols/index.d.ts +3 -0
- gaia/eval/webapp/node_modules/has-symbols/index.js +14 -0
- gaia/eval/webapp/node_modules/has-symbols/package.json +111 -0
- gaia/eval/webapp/node_modules/has-symbols/shams.d.ts +3 -0
- gaia/eval/webapp/node_modules/has-symbols/shams.js +45 -0
- gaia/eval/webapp/node_modules/has-symbols/test/index.js +22 -0
- gaia/eval/webapp/node_modules/has-symbols/test/shams/core-js.js +29 -0
- gaia/eval/webapp/node_modules/has-symbols/test/shams/get-own-property-symbols.js +29 -0
- gaia/eval/webapp/node_modules/has-symbols/test/tests.js +58 -0
- gaia/eval/webapp/node_modules/has-symbols/tsconfig.json +10 -0
- gaia/eval/webapp/node_modules/hasown/.eslintrc +5 -0
- gaia/eval/webapp/node_modules/hasown/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/hasown/.nycrc +13 -0
- gaia/eval/webapp/node_modules/hasown/CHANGELOG.md +40 -0
- gaia/eval/webapp/node_modules/hasown/LICENSE +21 -0
- gaia/eval/webapp/node_modules/hasown/README.md +40 -0
- gaia/eval/webapp/node_modules/hasown/index.d.ts +3 -0
- gaia/eval/webapp/node_modules/hasown/index.js +8 -0
- gaia/eval/webapp/node_modules/hasown/package.json +92 -0
- gaia/eval/webapp/node_modules/hasown/tsconfig.json +6 -0
- gaia/eval/webapp/node_modules/http-errors/HISTORY.md +180 -0
- gaia/eval/webapp/node_modules/http-errors/LICENSE +23 -0
- gaia/eval/webapp/node_modules/http-errors/README.md +169 -0
- gaia/eval/webapp/node_modules/http-errors/index.js +289 -0
- gaia/eval/webapp/node_modules/http-errors/package.json +50 -0
- gaia/eval/webapp/node_modules/iconv-lite/Changelog.md +162 -0
- gaia/eval/webapp/node_modules/iconv-lite/LICENSE +21 -0
- gaia/eval/webapp/node_modules/iconv-lite/README.md +156 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/dbcs-codec.js +555 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/dbcs-data.js +176 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/index.js +22 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/internal.js +188 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-codec.js +72 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-data-generated.js +451 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/sbcs-data.js +174 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/big5-added.json +122 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp936.json +264 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp949.json +273 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/cp950.json +177 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/eucjp.json +182 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/gb18030-ranges.json +1 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/gbk-added.json +55 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/tables/shiftjis.json +125 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/utf16.js +177 -0
- gaia/eval/webapp/node_modules/iconv-lite/encodings/utf7.js +290 -0
- gaia/eval/webapp/node_modules/iconv-lite/lib/bom-handling.js +52 -0
- gaia/eval/webapp/node_modules/iconv-lite/lib/extend-node.js +217 -0
- gaia/eval/webapp/node_modules/iconv-lite/lib/index.d.ts +24 -0
- gaia/eval/webapp/node_modules/iconv-lite/lib/index.js +153 -0
- gaia/eval/webapp/node_modules/iconv-lite/lib/streams.js +121 -0
- gaia/eval/webapp/node_modules/iconv-lite/package.json +46 -0
- gaia/eval/webapp/node_modules/inherits/LICENSE +16 -0
- gaia/eval/webapp/node_modules/inherits/README.md +42 -0
- gaia/eval/webapp/node_modules/inherits/inherits.js +9 -0
- gaia/eval/webapp/node_modules/inherits/inherits_browser.js +27 -0
- gaia/eval/webapp/node_modules/inherits/package.json +29 -0
- gaia/eval/webapp/node_modules/ipaddr.js/LICENSE +19 -0
- gaia/eval/webapp/node_modules/ipaddr.js/README.md +233 -0
- gaia/eval/webapp/node_modules/ipaddr.js/ipaddr.min.js +1 -0
- gaia/eval/webapp/node_modules/ipaddr.js/lib/ipaddr.js +673 -0
- gaia/eval/webapp/node_modules/ipaddr.js/lib/ipaddr.js.d.ts +68 -0
- gaia/eval/webapp/node_modules/ipaddr.js/package.json +35 -0
- gaia/eval/webapp/node_modules/math-intrinsics/.eslintrc +16 -0
- gaia/eval/webapp/node_modules/math-intrinsics/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/math-intrinsics/CHANGELOG.md +24 -0
- gaia/eval/webapp/node_modules/math-intrinsics/LICENSE +21 -0
- gaia/eval/webapp/node_modules/math-intrinsics/README.md +50 -0
- gaia/eval/webapp/node_modules/math-intrinsics/abs.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/abs.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxArrayLength.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxArrayLength.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxSafeInteger.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxSafeInteger.js +5 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxValue.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/constants/maxValue.js +5 -0
- gaia/eval/webapp/node_modules/math-intrinsics/floor.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/floor.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isFinite.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isFinite.js +12 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isInteger.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isInteger.js +16 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isNaN.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isNaN.js +6 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isNegativeZero.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/isNegativeZero.js +6 -0
- gaia/eval/webapp/node_modules/math-intrinsics/max.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/max.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/min.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/min.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/mod.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/mod.js +9 -0
- gaia/eval/webapp/node_modules/math-intrinsics/package.json +86 -0
- gaia/eval/webapp/node_modules/math-intrinsics/pow.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/pow.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/round.d.ts +1 -0
- gaia/eval/webapp/node_modules/math-intrinsics/round.js +4 -0
- gaia/eval/webapp/node_modules/math-intrinsics/sign.d.ts +3 -0
- gaia/eval/webapp/node_modules/math-intrinsics/sign.js +11 -0
- gaia/eval/webapp/node_modules/math-intrinsics/test/index.js +192 -0
- gaia/eval/webapp/node_modules/math-intrinsics/tsconfig.json +3 -0
- gaia/eval/webapp/node_modules/media-typer/HISTORY.md +22 -0
- gaia/eval/webapp/node_modules/media-typer/LICENSE +22 -0
- gaia/eval/webapp/node_modules/media-typer/README.md +81 -0
- gaia/eval/webapp/node_modules/media-typer/index.js +270 -0
- gaia/eval/webapp/node_modules/media-typer/package.json +26 -0
- gaia/eval/webapp/node_modules/merge-descriptors/HISTORY.md +21 -0
- gaia/eval/webapp/node_modules/merge-descriptors/LICENSE +23 -0
- gaia/eval/webapp/node_modules/merge-descriptors/README.md +49 -0
- gaia/eval/webapp/node_modules/merge-descriptors/index.js +60 -0
- gaia/eval/webapp/node_modules/merge-descriptors/package.json +39 -0
- gaia/eval/webapp/node_modules/methods/HISTORY.md +29 -0
- gaia/eval/webapp/node_modules/methods/LICENSE +24 -0
- gaia/eval/webapp/node_modules/methods/README.md +51 -0
- gaia/eval/webapp/node_modules/methods/index.js +69 -0
- gaia/eval/webapp/node_modules/methods/package.json +36 -0
- gaia/eval/webapp/node_modules/mime/.npmignore +0 -0
- gaia/eval/webapp/node_modules/mime/CHANGELOG.md +164 -0
- gaia/eval/webapp/node_modules/mime/LICENSE +21 -0
- gaia/eval/webapp/node_modules/mime/README.md +90 -0
- gaia/eval/webapp/node_modules/mime/cli.js +8 -0
- gaia/eval/webapp/node_modules/mime/mime.js +108 -0
- gaia/eval/webapp/node_modules/mime/package.json +44 -0
- gaia/eval/webapp/node_modules/mime/src/build.js +53 -0
- gaia/eval/webapp/node_modules/mime/src/test.js +60 -0
- gaia/eval/webapp/node_modules/mime/types.json +1 -0
- gaia/eval/webapp/node_modules/mime-db/HISTORY.md +507 -0
- gaia/eval/webapp/node_modules/mime-db/LICENSE +23 -0
- gaia/eval/webapp/node_modules/mime-db/README.md +100 -0
- gaia/eval/webapp/node_modules/mime-db/db.json +8519 -0
- gaia/eval/webapp/node_modules/mime-db/index.js +12 -0
- gaia/eval/webapp/node_modules/mime-db/package.json +60 -0
- gaia/eval/webapp/node_modules/mime-types/HISTORY.md +397 -0
- gaia/eval/webapp/node_modules/mime-types/LICENSE +23 -0
- gaia/eval/webapp/node_modules/mime-types/README.md +113 -0
- gaia/eval/webapp/node_modules/mime-types/index.js +188 -0
- gaia/eval/webapp/node_modules/mime-types/package.json +44 -0
- gaia/eval/webapp/node_modules/ms/index.js +152 -0
- gaia/eval/webapp/node_modules/ms/license.md +21 -0
- gaia/eval/webapp/node_modules/ms/package.json +37 -0
- gaia/eval/webapp/node_modules/ms/readme.md +51 -0
- gaia/eval/webapp/node_modules/negotiator/HISTORY.md +108 -0
- gaia/eval/webapp/node_modules/negotiator/LICENSE +24 -0
- gaia/eval/webapp/node_modules/negotiator/README.md +203 -0
- gaia/eval/webapp/node_modules/negotiator/index.js +82 -0
- gaia/eval/webapp/node_modules/negotiator/lib/charset.js +169 -0
- gaia/eval/webapp/node_modules/negotiator/lib/encoding.js +184 -0
- gaia/eval/webapp/node_modules/negotiator/lib/language.js +179 -0
- gaia/eval/webapp/node_modules/negotiator/lib/mediaType.js +294 -0
- gaia/eval/webapp/node_modules/negotiator/package.json +42 -0
- gaia/eval/webapp/node_modules/object-inspect/.eslintrc +53 -0
- gaia/eval/webapp/node_modules/object-inspect/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/object-inspect/.nycrc +13 -0
- gaia/eval/webapp/node_modules/object-inspect/CHANGELOG.md +424 -0
- gaia/eval/webapp/node_modules/object-inspect/LICENSE +21 -0
- gaia/eval/webapp/node_modules/object-inspect/example/all.js +23 -0
- gaia/eval/webapp/node_modules/object-inspect/example/circular.js +6 -0
- gaia/eval/webapp/node_modules/object-inspect/example/fn.js +5 -0
- gaia/eval/webapp/node_modules/object-inspect/example/inspect.js +10 -0
- gaia/eval/webapp/node_modules/object-inspect/index.js +544 -0
- gaia/eval/webapp/node_modules/object-inspect/package-support.json +20 -0
- gaia/eval/webapp/node_modules/object-inspect/package.json +105 -0
- gaia/eval/webapp/node_modules/object-inspect/readme.markdown +84 -0
- gaia/eval/webapp/node_modules/object-inspect/test/bigint.js +58 -0
- gaia/eval/webapp/node_modules/object-inspect/test/browser/dom.js +15 -0
- gaia/eval/webapp/node_modules/object-inspect/test/circular.js +16 -0
- gaia/eval/webapp/node_modules/object-inspect/test/deep.js +12 -0
- gaia/eval/webapp/node_modules/object-inspect/test/element.js +53 -0
- gaia/eval/webapp/node_modules/object-inspect/test/err.js +48 -0
- gaia/eval/webapp/node_modules/object-inspect/test/fakes.js +29 -0
- gaia/eval/webapp/node_modules/object-inspect/test/fn.js +76 -0
- gaia/eval/webapp/node_modules/object-inspect/test/global.js +17 -0
- gaia/eval/webapp/node_modules/object-inspect/test/has.js +15 -0
- gaia/eval/webapp/node_modules/object-inspect/test/holes.js +15 -0
- gaia/eval/webapp/node_modules/object-inspect/test/indent-option.js +271 -0
- gaia/eval/webapp/node_modules/object-inspect/test/inspect.js +139 -0
- gaia/eval/webapp/node_modules/object-inspect/test/lowbyte.js +12 -0
- gaia/eval/webapp/node_modules/object-inspect/test/number.js +58 -0
- gaia/eval/webapp/node_modules/object-inspect/test/quoteStyle.js +26 -0
- gaia/eval/webapp/node_modules/object-inspect/test/toStringTag.js +40 -0
- gaia/eval/webapp/node_modules/object-inspect/test/undef.js +12 -0
- gaia/eval/webapp/node_modules/object-inspect/test/values.js +261 -0
- gaia/eval/webapp/node_modules/object-inspect/test-core-js.js +26 -0
- gaia/eval/webapp/node_modules/object-inspect/util.inspect.js +1 -0
- gaia/eval/webapp/node_modules/on-finished/HISTORY.md +98 -0
- gaia/eval/webapp/node_modules/on-finished/LICENSE +23 -0
- gaia/eval/webapp/node_modules/on-finished/README.md +162 -0
- gaia/eval/webapp/node_modules/on-finished/index.js +234 -0
- gaia/eval/webapp/node_modules/on-finished/package.json +39 -0
- gaia/eval/webapp/node_modules/parseurl/HISTORY.md +58 -0
- gaia/eval/webapp/node_modules/parseurl/LICENSE +24 -0
- gaia/eval/webapp/node_modules/parseurl/README.md +133 -0
- gaia/eval/webapp/node_modules/parseurl/index.js +158 -0
- gaia/eval/webapp/node_modules/parseurl/package.json +40 -0
- gaia/eval/webapp/node_modules/path/.npmignore +1 -0
- gaia/eval/webapp/node_modules/path/LICENSE +18 -0
- gaia/eval/webapp/node_modules/path/README.md +15 -0
- gaia/eval/webapp/node_modules/path/package.json +24 -0
- gaia/eval/webapp/node_modules/path/path.js +628 -0
- gaia/eval/webapp/node_modules/path-to-regexp/LICENSE +21 -0
- gaia/eval/webapp/node_modules/path-to-regexp/Readme.md +35 -0
- gaia/eval/webapp/node_modules/path-to-regexp/index.js +156 -0
- gaia/eval/webapp/node_modules/path-to-regexp/package.json +30 -0
- gaia/eval/webapp/node_modules/process/.eslintrc +21 -0
- gaia/eval/webapp/node_modules/process/LICENSE +22 -0
- gaia/eval/webapp/node_modules/process/README.md +26 -0
- gaia/eval/webapp/node_modules/process/browser.js +184 -0
- gaia/eval/webapp/node_modules/process/index.js +2 -0
- gaia/eval/webapp/node_modules/process/package.json +27 -0
- gaia/eval/webapp/node_modules/process/test.js +199 -0
- gaia/eval/webapp/node_modules/proxy-addr/HISTORY.md +161 -0
- gaia/eval/webapp/node_modules/proxy-addr/LICENSE +22 -0
- gaia/eval/webapp/node_modules/proxy-addr/README.md +139 -0
- gaia/eval/webapp/node_modules/proxy-addr/index.js +327 -0
- gaia/eval/webapp/node_modules/proxy-addr/package.json +47 -0
- gaia/eval/webapp/node_modules/qs/.editorconfig +46 -0
- gaia/eval/webapp/node_modules/qs/.eslintrc +38 -0
- gaia/eval/webapp/node_modules/qs/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/qs/.nycrc +13 -0
- gaia/eval/webapp/node_modules/qs/CHANGELOG.md +600 -0
- gaia/eval/webapp/node_modules/qs/LICENSE.md +29 -0
- gaia/eval/webapp/node_modules/qs/README.md +709 -0
- gaia/eval/webapp/node_modules/qs/dist/qs.js +90 -0
- gaia/eval/webapp/node_modules/qs/lib/formats.js +23 -0
- gaia/eval/webapp/node_modules/qs/lib/index.js +11 -0
- gaia/eval/webapp/node_modules/qs/lib/parse.js +296 -0
- gaia/eval/webapp/node_modules/qs/lib/stringify.js +351 -0
- gaia/eval/webapp/node_modules/qs/lib/utils.js +265 -0
- gaia/eval/webapp/node_modules/qs/package.json +91 -0
- gaia/eval/webapp/node_modules/qs/test/empty-keys-cases.js +267 -0
- gaia/eval/webapp/node_modules/qs/test/parse.js +1170 -0
- gaia/eval/webapp/node_modules/qs/test/stringify.js +1298 -0
- gaia/eval/webapp/node_modules/qs/test/utils.js +136 -0
- gaia/eval/webapp/node_modules/range-parser/HISTORY.md +56 -0
- gaia/eval/webapp/node_modules/range-parser/LICENSE +23 -0
- gaia/eval/webapp/node_modules/range-parser/README.md +84 -0
- gaia/eval/webapp/node_modules/range-parser/index.js +162 -0
- gaia/eval/webapp/node_modules/range-parser/package.json +44 -0
- gaia/eval/webapp/node_modules/raw-body/HISTORY.md +308 -0
- gaia/eval/webapp/node_modules/raw-body/LICENSE +22 -0
- gaia/eval/webapp/node_modules/raw-body/README.md +223 -0
- gaia/eval/webapp/node_modules/raw-body/SECURITY.md +24 -0
- gaia/eval/webapp/node_modules/raw-body/index.d.ts +87 -0
- gaia/eval/webapp/node_modules/raw-body/index.js +336 -0
- gaia/eval/webapp/node_modules/raw-body/package.json +49 -0
- gaia/eval/webapp/node_modules/safe-buffer/LICENSE +21 -0
- gaia/eval/webapp/node_modules/safe-buffer/README.md +584 -0
- gaia/eval/webapp/node_modules/safe-buffer/index.d.ts +187 -0
- gaia/eval/webapp/node_modules/safe-buffer/index.js +65 -0
- gaia/eval/webapp/node_modules/safe-buffer/package.json +51 -0
- gaia/eval/webapp/node_modules/safer-buffer/LICENSE +21 -0
- gaia/eval/webapp/node_modules/safer-buffer/Porting-Buffer.md +268 -0
- gaia/eval/webapp/node_modules/safer-buffer/Readme.md +156 -0
- gaia/eval/webapp/node_modules/safer-buffer/dangerous.js +58 -0
- gaia/eval/webapp/node_modules/safer-buffer/package.json +34 -0
- gaia/eval/webapp/node_modules/safer-buffer/safer.js +77 -0
- gaia/eval/webapp/node_modules/safer-buffer/tests.js +406 -0
- gaia/eval/webapp/node_modules/send/HISTORY.md +526 -0
- gaia/eval/webapp/node_modules/send/LICENSE +23 -0
- gaia/eval/webapp/node_modules/send/README.md +327 -0
- gaia/eval/webapp/node_modules/send/SECURITY.md +24 -0
- gaia/eval/webapp/node_modules/send/index.js +1142 -0
- gaia/eval/webapp/node_modules/send/node_modules/encodeurl/HISTORY.md +14 -0
- gaia/eval/webapp/node_modules/send/node_modules/encodeurl/LICENSE +22 -0
- gaia/eval/webapp/node_modules/send/node_modules/encodeurl/README.md +128 -0
- gaia/eval/webapp/node_modules/send/node_modules/encodeurl/index.js +60 -0
- gaia/eval/webapp/node_modules/send/node_modules/encodeurl/package.json +40 -0
- gaia/eval/webapp/node_modules/send/node_modules/ms/index.js +162 -0
- gaia/eval/webapp/node_modules/send/node_modules/ms/license.md +21 -0
- gaia/eval/webapp/node_modules/send/node_modules/ms/package.json +38 -0
- gaia/eval/webapp/node_modules/send/node_modules/ms/readme.md +59 -0
- gaia/eval/webapp/node_modules/send/package.json +62 -0
- gaia/eval/webapp/node_modules/serve-static/HISTORY.md +487 -0
- gaia/eval/webapp/node_modules/serve-static/LICENSE +25 -0
- gaia/eval/webapp/node_modules/serve-static/README.md +257 -0
- gaia/eval/webapp/node_modules/serve-static/index.js +209 -0
- gaia/eval/webapp/node_modules/serve-static/package.json +42 -0
- gaia/eval/webapp/node_modules/setprototypeof/LICENSE +13 -0
- gaia/eval/webapp/node_modules/setprototypeof/README.md +31 -0
- gaia/eval/webapp/node_modules/setprototypeof/index.d.ts +2 -0
- gaia/eval/webapp/node_modules/setprototypeof/index.js +17 -0
- gaia/eval/webapp/node_modules/setprototypeof/package.json +38 -0
- gaia/eval/webapp/node_modules/setprototypeof/test/index.js +24 -0
- gaia/eval/webapp/node_modules/side-channel/.editorconfig +9 -0
- gaia/eval/webapp/node_modules/side-channel/.eslintrc +12 -0
- gaia/eval/webapp/node_modules/side-channel/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/side-channel/.nycrc +13 -0
- gaia/eval/webapp/node_modules/side-channel/CHANGELOG.md +110 -0
- gaia/eval/webapp/node_modules/side-channel/LICENSE +21 -0
- gaia/eval/webapp/node_modules/side-channel/README.md +61 -0
- gaia/eval/webapp/node_modules/side-channel/index.d.ts +14 -0
- gaia/eval/webapp/node_modules/side-channel/index.js +43 -0
- gaia/eval/webapp/node_modules/side-channel/package.json +85 -0
- gaia/eval/webapp/node_modules/side-channel/test/index.js +104 -0
- gaia/eval/webapp/node_modules/side-channel/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/side-channel-list/.editorconfig +9 -0
- gaia/eval/webapp/node_modules/side-channel-list/.eslintrc +11 -0
- gaia/eval/webapp/node_modules/side-channel-list/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/side-channel-list/.nycrc +13 -0
- gaia/eval/webapp/node_modules/side-channel-list/CHANGELOG.md +15 -0
- gaia/eval/webapp/node_modules/side-channel-list/LICENSE +21 -0
- gaia/eval/webapp/node_modules/side-channel-list/README.md +62 -0
- gaia/eval/webapp/node_modules/side-channel-list/index.d.ts +13 -0
- gaia/eval/webapp/node_modules/side-channel-list/index.js +113 -0
- gaia/eval/webapp/node_modules/side-channel-list/list.d.ts +14 -0
- gaia/eval/webapp/node_modules/side-channel-list/package.json +77 -0
- gaia/eval/webapp/node_modules/side-channel-list/test/index.js +104 -0
- gaia/eval/webapp/node_modules/side-channel-list/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/side-channel-map/.editorconfig +9 -0
- gaia/eval/webapp/node_modules/side-channel-map/.eslintrc +11 -0
- gaia/eval/webapp/node_modules/side-channel-map/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/side-channel-map/.nycrc +13 -0
- gaia/eval/webapp/node_modules/side-channel-map/CHANGELOG.md +22 -0
- gaia/eval/webapp/node_modules/side-channel-map/LICENSE +21 -0
- gaia/eval/webapp/node_modules/side-channel-map/README.md +62 -0
- gaia/eval/webapp/node_modules/side-channel-map/index.d.ts +15 -0
- gaia/eval/webapp/node_modules/side-channel-map/index.js +68 -0
- gaia/eval/webapp/node_modules/side-channel-map/package.json +80 -0
- gaia/eval/webapp/node_modules/side-channel-map/test/index.js +114 -0
- gaia/eval/webapp/node_modules/side-channel-map/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/.editorconfig +9 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/.eslintrc +12 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/.github/FUNDING.yml +12 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/.nycrc +13 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/CHANGELOG.md +28 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/LICENSE +21 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/README.md +62 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/index.d.ts +15 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/index.js +84 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/package.json +87 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/test/index.js +114 -0
- gaia/eval/webapp/node_modules/side-channel-weakmap/tsconfig.json +9 -0
- gaia/eval/webapp/node_modules/statuses/HISTORY.md +82 -0
- gaia/eval/webapp/node_modules/statuses/LICENSE +23 -0
- gaia/eval/webapp/node_modules/statuses/README.md +136 -0
- gaia/eval/webapp/node_modules/statuses/codes.json +65 -0
- gaia/eval/webapp/node_modules/statuses/index.js +146 -0
- gaia/eval/webapp/node_modules/statuses/package.json +49 -0
- gaia/eval/webapp/node_modules/toidentifier/HISTORY.md +9 -0
- gaia/eval/webapp/node_modules/toidentifier/LICENSE +21 -0
- gaia/eval/webapp/node_modules/toidentifier/README.md +61 -0
- gaia/eval/webapp/node_modules/toidentifier/index.js +32 -0
- gaia/eval/webapp/node_modules/toidentifier/package.json +38 -0
- gaia/eval/webapp/node_modules/type-is/HISTORY.md +259 -0
- gaia/eval/webapp/node_modules/type-is/LICENSE +23 -0
- gaia/eval/webapp/node_modules/type-is/README.md +170 -0
- gaia/eval/webapp/node_modules/type-is/index.js +266 -0
- gaia/eval/webapp/node_modules/type-is/package.json +45 -0
- gaia/eval/webapp/node_modules/unpipe/HISTORY.md +4 -0
- gaia/eval/webapp/node_modules/unpipe/LICENSE +22 -0
- gaia/eval/webapp/node_modules/unpipe/README.md +43 -0
- gaia/eval/webapp/node_modules/unpipe/index.js +69 -0
- gaia/eval/webapp/node_modules/unpipe/package.json +27 -0
- gaia/eval/webapp/node_modules/util/LICENSE +18 -0
- gaia/eval/webapp/node_modules/util/README.md +15 -0
- gaia/eval/webapp/node_modules/util/node_modules/inherits/LICENSE +16 -0
- gaia/eval/webapp/node_modules/util/node_modules/inherits/README.md +42 -0
- gaia/eval/webapp/node_modules/util/node_modules/inherits/inherits.js +7 -0
- gaia/eval/webapp/node_modules/util/node_modules/inherits/inherits_browser.js +23 -0
- gaia/eval/webapp/node_modules/util/node_modules/inherits/package.json +29 -0
- gaia/eval/webapp/node_modules/util/package.json +35 -0
- gaia/eval/webapp/node_modules/util/support/isBuffer.js +3 -0
- gaia/eval/webapp/node_modules/util/support/isBufferBrowser.js +6 -0
- gaia/eval/webapp/node_modules/util/util.js +586 -0
- gaia/eval/webapp/node_modules/utils-merge/.npmignore +9 -0
- gaia/eval/webapp/node_modules/utils-merge/LICENSE +20 -0
- gaia/eval/webapp/node_modules/utils-merge/README.md +34 -0
- gaia/eval/webapp/node_modules/utils-merge/index.js +23 -0
- gaia/eval/webapp/node_modules/utils-merge/package.json +40 -0
- gaia/eval/webapp/node_modules/vary/HISTORY.md +39 -0
- gaia/eval/webapp/node_modules/vary/LICENSE +22 -0
- gaia/eval/webapp/node_modules/vary/README.md +101 -0
- gaia/eval/webapp/node_modules/vary/index.js +149 -0
- gaia/eval/webapp/node_modules/vary/package.json +43 -0
- gaia/eval/webapp/package-lock.json +875 -0
- gaia/eval/webapp/package.json +21 -0
- gaia/eval/webapp/public/app.js +3403 -0
- gaia/eval/webapp/public/index.html +88 -0
- gaia/eval/webapp/public/styles.css +3661 -0
- gaia/eval/webapp/server.js +416 -0
- gaia/eval/webapp/test-setup.js +73 -0
- gaia/llm/__init__.py +2 -0
- gaia/llm/lemonade_client.py +3083 -0
- gaia/llm/lemonade_manager.py +269 -0
- gaia/llm/llm_client.py +729 -0
- gaia/llm/vlm_client.py +307 -0
- gaia/logger.py +189 -0
- gaia/mcp/agent_mcp_server.py +245 -0
- gaia/mcp/blender_mcp_client.py +138 -0
- gaia/mcp/blender_mcp_server.py +648 -0
- gaia/mcp/context7_cache.py +332 -0
- gaia/mcp/external_services.py +518 -0
- gaia/mcp/mcp_bridge.py +550 -0
- gaia/mcp/servers/__init__.py +6 -0
- gaia/mcp/servers/docker_mcp.py +83 -0
- gaia/rag/__init__.py +10 -0
- gaia/rag/app.py +293 -0
- gaia/rag/demo.py +304 -0
- gaia/rag/pdf_utils.py +235 -0
- gaia/rag/sdk.py +2194 -0
- gaia/security.py +163 -0
- gaia/talk/app.py +289 -0
- gaia/talk/sdk.py +538 -0
- gaia/util.py +46 -0
- 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
|