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,1138 @@
|
|
|
1
|
+
# Copyright(C) 2024-2025 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
"""
|
|
4
|
+
CLI Tools Mixin for Code Agent.
|
|
5
|
+
|
|
6
|
+
Provides universal CLI command execution with background process management,
|
|
7
|
+
error detection, and graceful shutdown capabilities.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
import os
|
|
12
|
+
import platform
|
|
13
|
+
import re
|
|
14
|
+
import signal
|
|
15
|
+
import socket
|
|
16
|
+
import subprocess
|
|
17
|
+
import tempfile
|
|
18
|
+
import time
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from threading import Thread
|
|
22
|
+
from typing import Any, Dict, List, Optional
|
|
23
|
+
|
|
24
|
+
import psutil
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
# CLI configuration constants
|
|
29
|
+
DEFAULT_PORT_RANGE_START = 3000
|
|
30
|
+
DEFAULT_PORT_RANGE_END = 9999
|
|
31
|
+
DEFAULT_COMMAND_TIMEOUT_SECS = 120
|
|
32
|
+
MAX_OUTPUT_CHARS = 10_000
|
|
33
|
+
MAX_ERROR_OUTPUT_CHARS = 2000
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class ProcessInfo:
|
|
38
|
+
"""Information about a managed background process."""
|
|
39
|
+
|
|
40
|
+
pid: int
|
|
41
|
+
command: str
|
|
42
|
+
working_dir: str
|
|
43
|
+
log_file: str
|
|
44
|
+
start_time: float
|
|
45
|
+
port: Optional[int] = None
|
|
46
|
+
errors: List[Dict[str, Any]] = None
|
|
47
|
+
warnings: List[str] = None
|
|
48
|
+
|
|
49
|
+
def __post_init__(self):
|
|
50
|
+
if self.errors is None:
|
|
51
|
+
self.errors = []
|
|
52
|
+
if self.warnings is None:
|
|
53
|
+
self.warnings = []
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# Error patterns to detect common startup issues
|
|
57
|
+
ERROR_PATTERNS = {
|
|
58
|
+
"port_conflict": [
|
|
59
|
+
r"Port (\d+) is (?:already )?in use",
|
|
60
|
+
r"EADDRINUSE.*:(\d+)",
|
|
61
|
+
r"address already in use.*:(\d+)",
|
|
62
|
+
r"bind\(\) failed.*Address already in use",
|
|
63
|
+
r"listen EADDRINUSE:.*:(\d+)",
|
|
64
|
+
],
|
|
65
|
+
"missing_deps": [
|
|
66
|
+
r"Cannot find module ['\"]([^'\"]+)['\"]",
|
|
67
|
+
r"Module not found: Error: Can't resolve ['\"]([^'\"]+)['\"]",
|
|
68
|
+
r"Error: Cannot find package ['\"]([^'\"]+)['\"]",
|
|
69
|
+
r"ModuleNotFoundError: No module named ['\"]([^'\"]+)['\"]",
|
|
70
|
+
r"ImportError: No module named ['\"]([^'\"]+)['\"]",
|
|
71
|
+
r"command not found: (npm|node|yarn|pnpm|python|pip)",
|
|
72
|
+
],
|
|
73
|
+
"compilation": [
|
|
74
|
+
r"SyntaxError:",
|
|
75
|
+
r"TypeError:",
|
|
76
|
+
r"ReferenceError:",
|
|
77
|
+
r"(\d+) error(?:s)?",
|
|
78
|
+
r"Failed to compile",
|
|
79
|
+
r"Build failed",
|
|
80
|
+
r"ERROR in \./",
|
|
81
|
+
r"TS\d+:", # TypeScript errors
|
|
82
|
+
r"Compilation failed",
|
|
83
|
+
],
|
|
84
|
+
"permissions": [
|
|
85
|
+
r"EACCES: permission denied",
|
|
86
|
+
r"Permission denied",
|
|
87
|
+
r"Access is denied",
|
|
88
|
+
r"Operation not permitted",
|
|
89
|
+
r"EPERM:",
|
|
90
|
+
],
|
|
91
|
+
"resources": [
|
|
92
|
+
r"JavaScript heap out of memory",
|
|
93
|
+
r"ENOMEM",
|
|
94
|
+
r"Cannot allocate memory",
|
|
95
|
+
r"Out of memory",
|
|
96
|
+
],
|
|
97
|
+
"network": [
|
|
98
|
+
r"ECONNREFUSED",
|
|
99
|
+
r"fetch failed",
|
|
100
|
+
r"Network error",
|
|
101
|
+
r"ETIMEDOUT",
|
|
102
|
+
r"ENOTFOUND",
|
|
103
|
+
],
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def find_process_on_port(port: int) -> Optional[int]:
|
|
108
|
+
"""
|
|
109
|
+
Find the PID of the process using a specific port.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
port: Port number to check
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
PID of the process using the port, or None if port is free
|
|
116
|
+
"""
|
|
117
|
+
try:
|
|
118
|
+
for proc in psutil.process_iter(["pid", "name"]):
|
|
119
|
+
try:
|
|
120
|
+
connections = proc.net_connections()
|
|
121
|
+
for conn in connections:
|
|
122
|
+
if conn.laddr.port == port:
|
|
123
|
+
return proc.pid
|
|
124
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
|
125
|
+
continue
|
|
126
|
+
except Exception as e:
|
|
127
|
+
logger.warning(f"Error checking port {port}: {e}")
|
|
128
|
+
return None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def kill_process_on_port(port: int) -> bool:
|
|
132
|
+
"""
|
|
133
|
+
Kill any process using the specified port.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
port: Port number to free
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
True if a process was killed, False otherwise
|
|
140
|
+
"""
|
|
141
|
+
pid = find_process_on_port(port)
|
|
142
|
+
if pid:
|
|
143
|
+
try:
|
|
144
|
+
proc = psutil.Process(pid)
|
|
145
|
+
proc.kill()
|
|
146
|
+
logger.info(f"Killed process {proc.name()} (PID: {pid}) using port {port}")
|
|
147
|
+
return True
|
|
148
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied) as e:
|
|
149
|
+
logger.warning(f"Failed to kill process on port {port}: {e}")
|
|
150
|
+
return False
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def is_port_available(port: int, host: str = "localhost") -> bool:
|
|
154
|
+
"""
|
|
155
|
+
Check if a port is available for use.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
port: Port number to check
|
|
159
|
+
host: Host address (default: localhost)
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
True if port is available, False if in use
|
|
163
|
+
"""
|
|
164
|
+
try:
|
|
165
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
166
|
+
sock.bind((host, port))
|
|
167
|
+
return True
|
|
168
|
+
except OSError:
|
|
169
|
+
return False
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def find_available_port(
|
|
173
|
+
start: int = DEFAULT_PORT_RANGE_START, end: int = DEFAULT_PORT_RANGE_END
|
|
174
|
+
) -> int:
|
|
175
|
+
"""
|
|
176
|
+
Find the next available port in a range.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
start: Starting port number
|
|
180
|
+
end: Ending port number
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Next available port number
|
|
184
|
+
|
|
185
|
+
Raises:
|
|
186
|
+
RuntimeError: If no available ports found
|
|
187
|
+
"""
|
|
188
|
+
for port in range(start, end + 1):
|
|
189
|
+
if is_port_available(port):
|
|
190
|
+
return port
|
|
191
|
+
raise RuntimeError(f"No available ports found in range {start}-{end}")
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class CLIToolsMixin:
|
|
195
|
+
"""
|
|
196
|
+
Mixin providing unrestricted CLI command execution with process management.
|
|
197
|
+
|
|
198
|
+
Designed for trusted developer tools - no security restrictions.
|
|
199
|
+
Provides background process support with error detection and graceful shutdown.
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
def __init__(self, *args, **kwargs):
|
|
203
|
+
"""Initialize CLI tools with process tracking."""
|
|
204
|
+
super().__init__(*args, **kwargs)
|
|
205
|
+
|
|
206
|
+
self._ensure_cli_tools_initialized()
|
|
207
|
+
|
|
208
|
+
def _ensure_cli_tools_initialized(self) -> None:
|
|
209
|
+
"""Ensure platform flags and process registries exist."""
|
|
210
|
+
if getattr(self, "_cli_tools_initialized", False):
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
existing_platform = getattr(self, "platform", None)
|
|
214
|
+
if isinstance(existing_platform, str):
|
|
215
|
+
normalized_platform = existing_platform.lower()
|
|
216
|
+
else:
|
|
217
|
+
normalized_platform = platform.system().lower()
|
|
218
|
+
|
|
219
|
+
self.platform = normalized_platform
|
|
220
|
+
self.is_windows = normalized_platform == "windows"
|
|
221
|
+
|
|
222
|
+
if not hasattr(self, "background_processes"):
|
|
223
|
+
self.background_processes = {} # type: Dict[int, ProcessInfo]
|
|
224
|
+
if not hasattr(self, "port_registry"):
|
|
225
|
+
self.port_registry = {} # type: Dict[int, int]
|
|
226
|
+
|
|
227
|
+
self._cli_tools_initialized = True
|
|
228
|
+
|
|
229
|
+
def register_cli_tools(self) -> None:
|
|
230
|
+
"""Register CLI command execution tools."""
|
|
231
|
+
self._ensure_cli_tools_initialized()
|
|
232
|
+
from gaia.agents.base.tools import tool
|
|
233
|
+
|
|
234
|
+
@tool(
|
|
235
|
+
name="run_cli_command",
|
|
236
|
+
description="Execute any CLI command (npm, python, docker, gh, etc.) with optional background execution for servers. "
|
|
237
|
+
"Automatically detects startup errors and manages process lifecycle.",
|
|
238
|
+
parameters={
|
|
239
|
+
"command": {
|
|
240
|
+
"type": "str",
|
|
241
|
+
"description": "The command to execute (e.g., 'npm run dev', 'python app.py', 'docker ps')",
|
|
242
|
+
"required": True,
|
|
243
|
+
},
|
|
244
|
+
"working_dir": {
|
|
245
|
+
"type": "str",
|
|
246
|
+
"description": "Directory to execute command in (default: current directory)",
|
|
247
|
+
"required": False,
|
|
248
|
+
},
|
|
249
|
+
"background": {
|
|
250
|
+
"type": "bool",
|
|
251
|
+
"description": "Run as background process (for dev servers, long-running processes)",
|
|
252
|
+
"required": False,
|
|
253
|
+
},
|
|
254
|
+
"timeout": {
|
|
255
|
+
"type": "int",
|
|
256
|
+
"description": "Timeout in seconds for foreground commands (default: 120)",
|
|
257
|
+
"required": False,
|
|
258
|
+
},
|
|
259
|
+
"startup_timeout": {
|
|
260
|
+
"type": "int",
|
|
261
|
+
"description": "Timeout for startup error detection in background mode (default: 5)",
|
|
262
|
+
"required": False,
|
|
263
|
+
},
|
|
264
|
+
"expected_port": {
|
|
265
|
+
"type": "int",
|
|
266
|
+
"description": "Port the process should bind to (for verification)",
|
|
267
|
+
"required": False,
|
|
268
|
+
},
|
|
269
|
+
"auto_respond": {
|
|
270
|
+
"type": "str",
|
|
271
|
+
"description": "String to auto-respond to interactive prompts (default: 'y\\n')",
|
|
272
|
+
"required": False,
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
)
|
|
276
|
+
def run_cli_command(
|
|
277
|
+
command: str,
|
|
278
|
+
working_dir: str = None,
|
|
279
|
+
background: bool = False,
|
|
280
|
+
timeout: Optional[int] = None,
|
|
281
|
+
startup_timeout: int = 5,
|
|
282
|
+
expected_port: Optional[int] = None,
|
|
283
|
+
auto_respond: str = "y\n",
|
|
284
|
+
) -> Dict[str, Any]:
|
|
285
|
+
"""
|
|
286
|
+
Execute any CLI command without restrictions.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
command: Command to execute
|
|
290
|
+
working_dir: Directory to run command in (default: current directory)
|
|
291
|
+
background: Run as background process
|
|
292
|
+
timeout: Timeout for foreground commands (default: 120s)
|
|
293
|
+
startup_timeout: Timeout for error detection (default: 5s)
|
|
294
|
+
expected_port: Port process should bind to
|
|
295
|
+
auto_respond: Response for interactive prompts
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
Dict with execution status, output, and errors
|
|
299
|
+
"""
|
|
300
|
+
try:
|
|
301
|
+
# Use workspace_root if available, else current directory
|
|
302
|
+
if working_dir is None:
|
|
303
|
+
if hasattr(self, "workspace_root") and self.workspace_root:
|
|
304
|
+
working_dir = self.workspace_root
|
|
305
|
+
else:
|
|
306
|
+
working_dir = "."
|
|
307
|
+
|
|
308
|
+
# Resolve working directory
|
|
309
|
+
work_path = Path(working_dir).resolve()
|
|
310
|
+
if not work_path.exists():
|
|
311
|
+
return {
|
|
312
|
+
"status": "error",
|
|
313
|
+
"success": False,
|
|
314
|
+
"error": f"Working directory not found: {working_dir}",
|
|
315
|
+
"has_errors": True,
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if not work_path.is_dir():
|
|
319
|
+
return {
|
|
320
|
+
"status": "error",
|
|
321
|
+
"success": False,
|
|
322
|
+
"error": f"Path is not a directory: {working_dir}",
|
|
323
|
+
"has_errors": True,
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
# Set default timeout for foreground commands
|
|
327
|
+
if timeout is None and not background:
|
|
328
|
+
timeout = DEFAULT_COMMAND_TIMEOUT_SECS
|
|
329
|
+
|
|
330
|
+
# Detect port from command if not specified
|
|
331
|
+
if expected_port is None:
|
|
332
|
+
expected_port = self._detect_port_from_command(command)
|
|
333
|
+
|
|
334
|
+
# Check for port conflicts before starting
|
|
335
|
+
if expected_port and not is_port_available(expected_port):
|
|
336
|
+
existing_pid = find_process_on_port(expected_port)
|
|
337
|
+
return {
|
|
338
|
+
"status": "error",
|
|
339
|
+
"success": False,
|
|
340
|
+
"error": f"Port {expected_port} is already in use",
|
|
341
|
+
"port": expected_port,
|
|
342
|
+
"blocking_pid": existing_pid,
|
|
343
|
+
"has_errors": True,
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if background:
|
|
347
|
+
return self._run_background_command(
|
|
348
|
+
command=command,
|
|
349
|
+
work_path=work_path,
|
|
350
|
+
startup_timeout=startup_timeout,
|
|
351
|
+
expected_port=expected_port,
|
|
352
|
+
auto_respond=auto_respond,
|
|
353
|
+
)
|
|
354
|
+
else:
|
|
355
|
+
return self._run_foreground_command(
|
|
356
|
+
command=command,
|
|
357
|
+
work_path=work_path,
|
|
358
|
+
timeout=timeout,
|
|
359
|
+
auto_respond=auto_respond,
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
except Exception as e:
|
|
363
|
+
logger.error(f"Error executing CLI command: {e}")
|
|
364
|
+
return {
|
|
365
|
+
"status": "error",
|
|
366
|
+
"success": False,
|
|
367
|
+
"error": str(e),
|
|
368
|
+
"has_errors": True,
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
@tool(
|
|
372
|
+
name="stop_process",
|
|
373
|
+
description="Stop a background process gracefully (SIGINT/Ctrl+C), with optional force kill",
|
|
374
|
+
parameters={
|
|
375
|
+
"pid": {
|
|
376
|
+
"type": "int",
|
|
377
|
+
"description": "Process ID to stop",
|
|
378
|
+
"required": True,
|
|
379
|
+
},
|
|
380
|
+
"force": {
|
|
381
|
+
"type": "bool",
|
|
382
|
+
"description": "Force kill immediately without graceful shutdown",
|
|
383
|
+
"required": False,
|
|
384
|
+
},
|
|
385
|
+
},
|
|
386
|
+
)
|
|
387
|
+
def stop_process(pid: int, force: bool = False) -> Dict[str, Any]:
|
|
388
|
+
"""
|
|
389
|
+
Stop a background process with graceful shutdown.
|
|
390
|
+
|
|
391
|
+
Args:
|
|
392
|
+
pid: Process ID to stop
|
|
393
|
+
force: Skip graceful shutdown and force kill
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
Dict with stop status and method used
|
|
397
|
+
"""
|
|
398
|
+
return self._stop_process(pid, force)
|
|
399
|
+
|
|
400
|
+
@tool(
|
|
401
|
+
name="list_processes",
|
|
402
|
+
description="List all managed background processes",
|
|
403
|
+
parameters={},
|
|
404
|
+
)
|
|
405
|
+
def list_processes() -> Dict[str, Any]:
|
|
406
|
+
"""
|
|
407
|
+
List all managed background processes.
|
|
408
|
+
|
|
409
|
+
Returns:
|
|
410
|
+
Dict with list of running processes and their info
|
|
411
|
+
"""
|
|
412
|
+
return self._list_processes()
|
|
413
|
+
|
|
414
|
+
@tool(
|
|
415
|
+
name="get_process_logs",
|
|
416
|
+
description="Get output logs from a background process",
|
|
417
|
+
parameters={
|
|
418
|
+
"pid": {
|
|
419
|
+
"type": "int",
|
|
420
|
+
"description": "Process ID to get logs for",
|
|
421
|
+
"required": True,
|
|
422
|
+
},
|
|
423
|
+
"lines": {
|
|
424
|
+
"type": "int",
|
|
425
|
+
"description": "Number of lines to return (default: 50)",
|
|
426
|
+
"required": False,
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
)
|
|
430
|
+
def get_process_logs(pid: int, lines: int = 50) -> Dict[str, Any]:
|
|
431
|
+
"""
|
|
432
|
+
Get output logs from a background process.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
pid: Process ID
|
|
436
|
+
lines: Number of lines to return
|
|
437
|
+
|
|
438
|
+
Returns:
|
|
439
|
+
Dict with log output
|
|
440
|
+
"""
|
|
441
|
+
return self._get_process_logs(pid, lines)
|
|
442
|
+
|
|
443
|
+
@tool(
|
|
444
|
+
name="cleanup_all_processes",
|
|
445
|
+
description="Stop all managed background processes gracefully",
|
|
446
|
+
parameters={},
|
|
447
|
+
)
|
|
448
|
+
def cleanup_all_processes() -> Dict[str, Any]:
|
|
449
|
+
"""
|
|
450
|
+
Stop all managed background processes.
|
|
451
|
+
|
|
452
|
+
Returns:
|
|
453
|
+
Dict with cleanup status
|
|
454
|
+
"""
|
|
455
|
+
return self._cleanup_all_processes()
|
|
456
|
+
|
|
457
|
+
def _detect_port_from_command(self, command: str) -> Optional[int]:
|
|
458
|
+
"""
|
|
459
|
+
Detect port number from common command patterns.
|
|
460
|
+
|
|
461
|
+
Args:
|
|
462
|
+
command: Command string
|
|
463
|
+
|
|
464
|
+
Returns:
|
|
465
|
+
Detected port number or None
|
|
466
|
+
"""
|
|
467
|
+
# Common port patterns
|
|
468
|
+
patterns = [
|
|
469
|
+
r"PORT[=\s]+(\d+)", # PORT=3000
|
|
470
|
+
r"--port[=\s]+(\d+)", # --port 3000
|
|
471
|
+
r"-p\s+(\d+)", # -p 3000
|
|
472
|
+
r":(\d+)", # localhost:3000
|
|
473
|
+
]
|
|
474
|
+
|
|
475
|
+
for pattern in patterns:
|
|
476
|
+
match = re.search(pattern, command, re.IGNORECASE)
|
|
477
|
+
if match:
|
|
478
|
+
return int(match.group(1))
|
|
479
|
+
|
|
480
|
+
# Default ports for common commands
|
|
481
|
+
if "npm run dev" in command or "next dev" in command:
|
|
482
|
+
return 3000
|
|
483
|
+
if "vite" in command.lower():
|
|
484
|
+
return 5173
|
|
485
|
+
if "flask run" in command:
|
|
486
|
+
return 5000
|
|
487
|
+
if "uvicorn" in command:
|
|
488
|
+
return 8000
|
|
489
|
+
|
|
490
|
+
return None
|
|
491
|
+
|
|
492
|
+
def _run_foreground_command(
|
|
493
|
+
self,
|
|
494
|
+
command: str,
|
|
495
|
+
work_path: Path,
|
|
496
|
+
timeout: int,
|
|
497
|
+
auto_respond: str,
|
|
498
|
+
) -> Dict[str, Any]:
|
|
499
|
+
"""
|
|
500
|
+
Execute a command in foreground mode.
|
|
501
|
+
|
|
502
|
+
Args:
|
|
503
|
+
command: Command to execute
|
|
504
|
+
work_path: Working directory
|
|
505
|
+
timeout: Command timeout
|
|
506
|
+
auto_respond: Auto-response for interactive prompts
|
|
507
|
+
|
|
508
|
+
Returns:
|
|
509
|
+
Dict with command output and status
|
|
510
|
+
"""
|
|
511
|
+
try:
|
|
512
|
+
# Log to debug instead of info
|
|
513
|
+
logger.debug(f"Executing foreground command: {command}")
|
|
514
|
+
|
|
515
|
+
# Check if console is available for preview
|
|
516
|
+
console = getattr(self, "console", None)
|
|
517
|
+
|
|
518
|
+
if console:
|
|
519
|
+
console.start_file_preview(command, max_lines=15, title_prefix="💻")
|
|
520
|
+
elif getattr(self, "console", None):
|
|
521
|
+
self.console.print_command_executing(command)
|
|
522
|
+
else:
|
|
523
|
+
print(f"\nExecuting Command: {command}")
|
|
524
|
+
|
|
525
|
+
# Run command with real-time streaming
|
|
526
|
+
# Use stdin=PIPE to prevent inheriting terminal stdin (which can cause
|
|
527
|
+
# hangs waiting for input), while still allowing auto_respond to work
|
|
528
|
+
process = subprocess.Popen(
|
|
529
|
+
command,
|
|
530
|
+
cwd=str(work_path),
|
|
531
|
+
shell=True,
|
|
532
|
+
stdin=subprocess.PIPE,
|
|
533
|
+
stdout=subprocess.PIPE,
|
|
534
|
+
stderr=subprocess.PIPE,
|
|
535
|
+
text=True,
|
|
536
|
+
encoding="utf-8",
|
|
537
|
+
bufsize=1,
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
# Send auto_respond and close stdin to prevent command from waiting
|
|
541
|
+
if process.stdin:
|
|
542
|
+
try:
|
|
543
|
+
if auto_respond:
|
|
544
|
+
process.stdin.write(auto_respond)
|
|
545
|
+
process.stdin.close()
|
|
546
|
+
except Exception as e:
|
|
547
|
+
logger.debug(f"Error writing to stdin: {e}")
|
|
548
|
+
|
|
549
|
+
stdout_lines = []
|
|
550
|
+
stderr_lines = []
|
|
551
|
+
|
|
552
|
+
# Function to read and print streams
|
|
553
|
+
def read_stream(stream, output_list, is_stderr=False):
|
|
554
|
+
for line in iter(stream.readline, ""):
|
|
555
|
+
output_list.append(line)
|
|
556
|
+
if console:
|
|
557
|
+
console.update_file_preview(line)
|
|
558
|
+
else:
|
|
559
|
+
if is_stderr:
|
|
560
|
+
# Print stderr in red if it's not just info/warning
|
|
561
|
+
print(f"{line.rstrip()}", flush=True)
|
|
562
|
+
else:
|
|
563
|
+
print(line.rstrip(), flush=True)
|
|
564
|
+
stream.close()
|
|
565
|
+
|
|
566
|
+
# Start threads to read streams
|
|
567
|
+
stdout_thread = Thread(
|
|
568
|
+
target=read_stream, args=(process.stdout, stdout_lines, False)
|
|
569
|
+
)
|
|
570
|
+
stderr_thread = Thread(
|
|
571
|
+
target=read_stream, args=(process.stderr, stderr_lines, True)
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
stdout_thread.start()
|
|
575
|
+
stderr_thread.start()
|
|
576
|
+
|
|
577
|
+
# Wait for command to finish
|
|
578
|
+
try:
|
|
579
|
+
process.wait(timeout=timeout)
|
|
580
|
+
except subprocess.TimeoutExpired:
|
|
581
|
+
process.kill()
|
|
582
|
+
stdout_thread.join()
|
|
583
|
+
stderr_thread.join()
|
|
584
|
+
raise subprocess.TimeoutExpired(
|
|
585
|
+
process.args,
|
|
586
|
+
timeout,
|
|
587
|
+
output="".join(stdout_lines),
|
|
588
|
+
stderr="".join(stderr_lines),
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
stdout_thread.join()
|
|
592
|
+
stderr_thread.join()
|
|
593
|
+
|
|
594
|
+
# Stop preview
|
|
595
|
+
if console:
|
|
596
|
+
console.stop_file_preview()
|
|
597
|
+
|
|
598
|
+
# Collect full output
|
|
599
|
+
stdout = "".join(stdout_lines)
|
|
600
|
+
stderr = "".join(stderr_lines)
|
|
601
|
+
returncode = process.returncode
|
|
602
|
+
|
|
603
|
+
# Print status
|
|
604
|
+
if not console:
|
|
605
|
+
if returncode == 0:
|
|
606
|
+
print("✓ Command successful\n")
|
|
607
|
+
else:
|
|
608
|
+
print(f"✗ Command failed (exit code {returncode})\n")
|
|
609
|
+
|
|
610
|
+
# Scan for errors
|
|
611
|
+
errors = self._scan_output_for_errors(stdout + stderr)
|
|
612
|
+
|
|
613
|
+
truncated = False
|
|
614
|
+
max_output = MAX_OUTPUT_CHARS
|
|
615
|
+
|
|
616
|
+
if len(stdout) > max_output:
|
|
617
|
+
stdout = stdout[:max_output] + "\n...output truncated (stdout)..."
|
|
618
|
+
truncated = True
|
|
619
|
+
|
|
620
|
+
if len(stderr) > max_output:
|
|
621
|
+
stderr = stderr[:max_output] + "\n...output truncated (stderr)..."
|
|
622
|
+
truncated = True
|
|
623
|
+
|
|
624
|
+
return {
|
|
625
|
+
"status": "error" if returncode != 0 else "success",
|
|
626
|
+
"success": returncode == 0,
|
|
627
|
+
"command": command,
|
|
628
|
+
"stdout": stdout,
|
|
629
|
+
"stderr": stderr,
|
|
630
|
+
"return_code": returncode,
|
|
631
|
+
"has_errors": returncode != 0 or len(errors) > 0,
|
|
632
|
+
"error": stderr if returncode != 0 else None,
|
|
633
|
+
"errors": errors,
|
|
634
|
+
"output_truncated": truncated,
|
|
635
|
+
"working_dir": str(work_path),
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
except subprocess.TimeoutExpired as e:
|
|
639
|
+
# Ensure preview is stopped on timeout
|
|
640
|
+
if getattr(self, "console", None):
|
|
641
|
+
self.console.stop_file_preview()
|
|
642
|
+
|
|
643
|
+
# Handle both string and bytes output (text=True returns strings)
|
|
644
|
+
stdout_str = ""
|
|
645
|
+
if e.stdout:
|
|
646
|
+
stdout_str = (
|
|
647
|
+
e.stdout
|
|
648
|
+
if isinstance(e.stdout, str)
|
|
649
|
+
else e.stdout.decode("utf-8", errors="replace")
|
|
650
|
+
)
|
|
651
|
+
|
|
652
|
+
stderr_str = ""
|
|
653
|
+
if e.stderr:
|
|
654
|
+
stderr_str = (
|
|
655
|
+
e.stderr
|
|
656
|
+
if isinstance(e.stderr, str)
|
|
657
|
+
else e.stderr.decode("utf-8", errors="replace")
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
return {
|
|
661
|
+
"status": "error",
|
|
662
|
+
"success": False,
|
|
663
|
+
"error": f"Command timed out after {timeout} seconds",
|
|
664
|
+
"command": command,
|
|
665
|
+
"stdout": stdout_str,
|
|
666
|
+
"stderr": stderr_str,
|
|
667
|
+
"has_errors": True,
|
|
668
|
+
"timed_out": True,
|
|
669
|
+
"timeout": timeout,
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
except Exception as e:
|
|
673
|
+
# Ensure preview is stopped on error
|
|
674
|
+
if getattr(self, "console", None):
|
|
675
|
+
self.console.stop_file_preview()
|
|
676
|
+
|
|
677
|
+
return {
|
|
678
|
+
"status": "error",
|
|
679
|
+
"success": False,
|
|
680
|
+
"error": str(e),
|
|
681
|
+
"command": command,
|
|
682
|
+
"has_errors": True,
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
def _run_background_command(
|
|
686
|
+
self,
|
|
687
|
+
command: str,
|
|
688
|
+
work_path: Path,
|
|
689
|
+
startup_timeout: int,
|
|
690
|
+
expected_port: Optional[int],
|
|
691
|
+
auto_respond: str,
|
|
692
|
+
) -> Dict[str, Any]:
|
|
693
|
+
"""
|
|
694
|
+
Execute a command in background mode with error detection.
|
|
695
|
+
|
|
696
|
+
Args:
|
|
697
|
+
command: Command to execute
|
|
698
|
+
work_path: Working directory
|
|
699
|
+
startup_timeout: Time to monitor for errors
|
|
700
|
+
expected_port: Expected port for the process
|
|
701
|
+
auto_respond: Auto-response for interactive prompts
|
|
702
|
+
|
|
703
|
+
Returns:
|
|
704
|
+
Dict with process info or error details
|
|
705
|
+
"""
|
|
706
|
+
self._ensure_cli_tools_initialized()
|
|
707
|
+
try:
|
|
708
|
+
logger.info(f"Starting background command: {command}")
|
|
709
|
+
|
|
710
|
+
# Create log file
|
|
711
|
+
log_file = tempfile.NamedTemporaryFile(
|
|
712
|
+
mode="w",
|
|
713
|
+
suffix=".log",
|
|
714
|
+
prefix="gaia_cli_",
|
|
715
|
+
delete=False,
|
|
716
|
+
encoding="utf-8",
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
# Start process
|
|
720
|
+
if self.is_windows:
|
|
721
|
+
# Windows: CREATE_NEW_PROCESS_GROUP for Ctrl+C support
|
|
722
|
+
process = subprocess.Popen(
|
|
723
|
+
command,
|
|
724
|
+
cwd=str(work_path),
|
|
725
|
+
shell=True,
|
|
726
|
+
stdout=log_file,
|
|
727
|
+
stderr=subprocess.STDOUT,
|
|
728
|
+
stdin=subprocess.PIPE if auto_respond else subprocess.DEVNULL,
|
|
729
|
+
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP,
|
|
730
|
+
)
|
|
731
|
+
else:
|
|
732
|
+
# Unix: start_new_session for signal isolation
|
|
733
|
+
process = subprocess.Popen(
|
|
734
|
+
command,
|
|
735
|
+
cwd=str(work_path),
|
|
736
|
+
shell=True,
|
|
737
|
+
stdout=log_file,
|
|
738
|
+
stderr=subprocess.STDOUT,
|
|
739
|
+
stdin=subprocess.PIPE if auto_respond else subprocess.DEVNULL,
|
|
740
|
+
start_new_session=True,
|
|
741
|
+
)
|
|
742
|
+
|
|
743
|
+
log_file.close()
|
|
744
|
+
|
|
745
|
+
# Auto-respond to prompts in background thread
|
|
746
|
+
if auto_respond:
|
|
747
|
+
|
|
748
|
+
def send_input():
|
|
749
|
+
try:
|
|
750
|
+
time.sleep(0.5) # Small delay for process to start
|
|
751
|
+
if process.stdin:
|
|
752
|
+
process.stdin.write(auto_respond.encode())
|
|
753
|
+
process.stdin.flush()
|
|
754
|
+
process.stdin.close()
|
|
755
|
+
except Exception as e:
|
|
756
|
+
logger.debug(f"Auto-respond thread error: {e}")
|
|
757
|
+
|
|
758
|
+
Thread(target=send_input, daemon=True).start()
|
|
759
|
+
|
|
760
|
+
# Monitor for startup errors
|
|
761
|
+
start_time = time.time()
|
|
762
|
+
errors_detected = []
|
|
763
|
+
output_buffer = []
|
|
764
|
+
|
|
765
|
+
logger.info(
|
|
766
|
+
f"Monitoring process {process.pid} for {startup_timeout} seconds..."
|
|
767
|
+
)
|
|
768
|
+
|
|
769
|
+
while time.time() - start_time < startup_timeout:
|
|
770
|
+
# Check if process died
|
|
771
|
+
if process.poll() is not None:
|
|
772
|
+
errors_detected.append(
|
|
773
|
+
{
|
|
774
|
+
"type": "process_died",
|
|
775
|
+
"message": f"Process exited with code {process.returncode}",
|
|
776
|
+
}
|
|
777
|
+
)
|
|
778
|
+
break
|
|
779
|
+
|
|
780
|
+
# Read recent output
|
|
781
|
+
try:
|
|
782
|
+
with open(log_file.name, "r", encoding="utf-8") as f:
|
|
783
|
+
new_output = f.read()
|
|
784
|
+
if new_output and new_output != "".join(output_buffer):
|
|
785
|
+
output_buffer.append(new_output)
|
|
786
|
+
# Scan for errors
|
|
787
|
+
errors = self._scan_output_for_errors(new_output)
|
|
788
|
+
errors_detected.extend(errors)
|
|
789
|
+
|
|
790
|
+
# Stop if critical errors found
|
|
791
|
+
if any(
|
|
792
|
+
e["type"]
|
|
793
|
+
in ["port_conflict", "missing_deps", "permissions"]
|
|
794
|
+
for e in errors
|
|
795
|
+
):
|
|
796
|
+
break
|
|
797
|
+
|
|
798
|
+
except Exception as e:
|
|
799
|
+
logger.debug(f"Error reading log file: {e}")
|
|
800
|
+
|
|
801
|
+
time.sleep(0.1)
|
|
802
|
+
|
|
803
|
+
# Check if process is still alive
|
|
804
|
+
is_alive = process.poll() is None
|
|
805
|
+
|
|
806
|
+
# If errors detected or process died, stop it
|
|
807
|
+
if errors_detected or not is_alive:
|
|
808
|
+
if is_alive:
|
|
809
|
+
self._terminate_process(process.pid)
|
|
810
|
+
|
|
811
|
+
# Read final output
|
|
812
|
+
try:
|
|
813
|
+
with open(log_file.name, "r", encoding="utf-8") as f:
|
|
814
|
+
final_output = f.read()
|
|
815
|
+
except Exception:
|
|
816
|
+
final_output = "".join(output_buffer)
|
|
817
|
+
|
|
818
|
+
return {
|
|
819
|
+
"success": False,
|
|
820
|
+
"command": command,
|
|
821
|
+
"output": final_output[-MAX_ERROR_OUTPUT_CHARS:],
|
|
822
|
+
"errors": errors_detected,
|
|
823
|
+
"has_errors": True,
|
|
824
|
+
"log_file": log_file.name,
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
# Check port is bound if expected
|
|
828
|
+
if expected_port:
|
|
829
|
+
port_ready = False
|
|
830
|
+
for _ in range(10): # Check for 1 second
|
|
831
|
+
if not is_port_available(expected_port):
|
|
832
|
+
port_ready = True
|
|
833
|
+
self.port_registry[expected_port] = process.pid
|
|
834
|
+
break
|
|
835
|
+
time.sleep(0.1)
|
|
836
|
+
|
|
837
|
+
if not port_ready:
|
|
838
|
+
self._terminate_process(process.pid)
|
|
839
|
+
return {
|
|
840
|
+
"success": False,
|
|
841
|
+
"error": f"Process started but port {expected_port} not bound",
|
|
842
|
+
"has_errors": True,
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
# Process started successfully!
|
|
846
|
+
process_info = ProcessInfo(
|
|
847
|
+
pid=process.pid,
|
|
848
|
+
command=command,
|
|
849
|
+
working_dir=str(work_path),
|
|
850
|
+
log_file=log_file.name,
|
|
851
|
+
start_time=time.time(),
|
|
852
|
+
port=expected_port,
|
|
853
|
+
)
|
|
854
|
+
|
|
855
|
+
self.background_processes[process.pid] = process_info
|
|
856
|
+
|
|
857
|
+
logger.info(f"Background process started successfully: PID {process.pid}")
|
|
858
|
+
|
|
859
|
+
return {
|
|
860
|
+
"success": True,
|
|
861
|
+
"pid": process.pid,
|
|
862
|
+
"command": command,
|
|
863
|
+
"port": expected_port,
|
|
864
|
+
"log_file": log_file.name,
|
|
865
|
+
"background": True,
|
|
866
|
+
"message": f"Process started with PID {process.pid}"
|
|
867
|
+
+ (f" on port {expected_port}" if expected_port else ""),
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
except Exception as e:
|
|
871
|
+
logger.error(f"Error starting background command: {e}")
|
|
872
|
+
return {
|
|
873
|
+
"success": False,
|
|
874
|
+
"error": str(e),
|
|
875
|
+
"has_errors": True,
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
def _scan_output_for_errors(self, output: str) -> List[Dict[str, Any]]:
|
|
879
|
+
"""
|
|
880
|
+
Scan output for known error patterns.
|
|
881
|
+
|
|
882
|
+
Args:
|
|
883
|
+
output: Command output to scan
|
|
884
|
+
|
|
885
|
+
Returns:
|
|
886
|
+
List of detected errors
|
|
887
|
+
"""
|
|
888
|
+
detected_errors = []
|
|
889
|
+
|
|
890
|
+
for error_type, patterns in ERROR_PATTERNS.items():
|
|
891
|
+
for pattern in patterns:
|
|
892
|
+
matches = re.finditer(pattern, output, re.IGNORECASE | re.MULTILINE)
|
|
893
|
+
for match in matches:
|
|
894
|
+
error_info = {
|
|
895
|
+
"type": error_type,
|
|
896
|
+
"message": match.group(0),
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
# Extract specific details
|
|
900
|
+
if error_type == "port_conflict" and len(match.groups()) > 0:
|
|
901
|
+
error_info["port"] = int(match.group(1))
|
|
902
|
+
elif error_type == "missing_deps" and len(match.groups()) > 0:
|
|
903
|
+
error_info["module"] = match.group(1)
|
|
904
|
+
|
|
905
|
+
detected_errors.append(error_info)
|
|
906
|
+
|
|
907
|
+
return detected_errors
|
|
908
|
+
|
|
909
|
+
def _stop_process(self, pid: int, force: bool = False) -> Dict[str, Any]:
|
|
910
|
+
"""
|
|
911
|
+
Stop a background process gracefully.
|
|
912
|
+
|
|
913
|
+
Args:
|
|
914
|
+
pid: Process ID
|
|
915
|
+
force: Skip graceful shutdown
|
|
916
|
+
|
|
917
|
+
Returns:
|
|
918
|
+
Dict with stop status
|
|
919
|
+
"""
|
|
920
|
+
self._ensure_cli_tools_initialized()
|
|
921
|
+
if pid not in self.background_processes:
|
|
922
|
+
return {
|
|
923
|
+
"success": False,
|
|
924
|
+
"error": f"Process {pid} not found in managed processes",
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
try:
|
|
928
|
+
# Get process info
|
|
929
|
+
proc_info = self.background_processes[pid]
|
|
930
|
+
|
|
931
|
+
# Try to terminate
|
|
932
|
+
method = "forced" if force else "graceful"
|
|
933
|
+
self._terminate_process(pid, force=force)
|
|
934
|
+
|
|
935
|
+
# Remove from tracking
|
|
936
|
+
del self.background_processes[pid]
|
|
937
|
+
|
|
938
|
+
# Remove port registry
|
|
939
|
+
if proc_info.port and proc_info.port in self.port_registry:
|
|
940
|
+
del self.port_registry[proc_info.port]
|
|
941
|
+
|
|
942
|
+
logger.info(f"Stopped process {pid} ({method})")
|
|
943
|
+
|
|
944
|
+
return {
|
|
945
|
+
"success": True,
|
|
946
|
+
"pid": pid,
|
|
947
|
+
"method": method,
|
|
948
|
+
"message": f"Process {pid} stopped successfully",
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
except Exception as e:
|
|
952
|
+
logger.error(f"Error stopping process {pid}: {e}")
|
|
953
|
+
return {
|
|
954
|
+
"success": False,
|
|
955
|
+
"error": str(e),
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
def _terminate_process(self, pid: int, force: bool = False):
|
|
959
|
+
"""
|
|
960
|
+
Terminate a process using platform-specific methods.
|
|
961
|
+
|
|
962
|
+
Args:
|
|
963
|
+
pid: Process ID to terminate
|
|
964
|
+
force: Skip graceful termination
|
|
965
|
+
"""
|
|
966
|
+
self._ensure_cli_tools_initialized()
|
|
967
|
+
try:
|
|
968
|
+
proc = psutil.Process(pid)
|
|
969
|
+
|
|
970
|
+
if self.is_windows:
|
|
971
|
+
if force:
|
|
972
|
+
# Force kill with taskkill
|
|
973
|
+
os.system(f"taskkill /F /T /PID {pid}")
|
|
974
|
+
else:
|
|
975
|
+
# Try graceful termination first
|
|
976
|
+
try:
|
|
977
|
+
# pylint: disable=no-member
|
|
978
|
+
proc.send_signal(signal.CTRL_C_EVENT)
|
|
979
|
+
proc.wait(timeout=5)
|
|
980
|
+
except (psutil.TimeoutExpired, psutil.NoSuchProcess):
|
|
981
|
+
# Fallback to taskkill
|
|
982
|
+
os.system(f"taskkill /F /T /PID {pid}")
|
|
983
|
+
else:
|
|
984
|
+
# Unix/Linux/macOS
|
|
985
|
+
if not force:
|
|
986
|
+
# Send SIGINT (Ctrl+C)
|
|
987
|
+
try:
|
|
988
|
+
os.kill(pid, signal.SIGINT)
|
|
989
|
+
proc.wait(timeout=5)
|
|
990
|
+
return # Success!
|
|
991
|
+
except (psutil.TimeoutExpired, ProcessLookupError):
|
|
992
|
+
pass # Continue to SIGTERM
|
|
993
|
+
|
|
994
|
+
# Send SIGTERM (Unix only - killpg not available on Windows)
|
|
995
|
+
if hasattr(os, "killpg"):
|
|
996
|
+
try:
|
|
997
|
+
os.killpg(os.getpgid(pid), signal.SIGTERM)
|
|
998
|
+
proc.wait(timeout=2)
|
|
999
|
+
return # Success!
|
|
1000
|
+
except (OSError, ProcessLookupError, psutil.TimeoutExpired):
|
|
1001
|
+
pass # Continue to SIGKILL
|
|
1002
|
+
|
|
1003
|
+
# Force kill with SIGKILL (Unix) or terminate (Windows)
|
|
1004
|
+
if hasattr(os, "killpg") and hasattr(signal, "SIGKILL"):
|
|
1005
|
+
try:
|
|
1006
|
+
# pylint: disable=no-member
|
|
1007
|
+
os.killpg(os.getpgid(pid), signal.SIGTERM)
|
|
1008
|
+
proc.wait(timeout=2)
|
|
1009
|
+
return # Success!
|
|
1010
|
+
except (OSError, ProcessLookupError, psutil.TimeoutExpired):
|
|
1011
|
+
pass # Continue to SIGKILL
|
|
1012
|
+
|
|
1013
|
+
# Force kill with SIGKILL
|
|
1014
|
+
try:
|
|
1015
|
+
# pylint: disable=no-member
|
|
1016
|
+
os.killpg(os.getpgid(pid), signal.SIGKILL)
|
|
1017
|
+
except (OSError, ProcessLookupError):
|
|
1018
|
+
# Fallback to individual kill
|
|
1019
|
+
try:
|
|
1020
|
+
proc.kill()
|
|
1021
|
+
except psutil.NoSuchProcess:
|
|
1022
|
+
pass # Already dead
|
|
1023
|
+
|
|
1024
|
+
except psutil.NoSuchProcess:
|
|
1025
|
+
logger.debug(f"Process {pid} already terminated")
|
|
1026
|
+
except Exception as e:
|
|
1027
|
+
logger.warning(f"Error terminating process {pid}: {e}")
|
|
1028
|
+
|
|
1029
|
+
def _list_processes(self) -> Dict[str, Any]:
|
|
1030
|
+
"""
|
|
1031
|
+
List all managed background processes.
|
|
1032
|
+
|
|
1033
|
+
Returns:
|
|
1034
|
+
Dict with process list
|
|
1035
|
+
"""
|
|
1036
|
+
self._ensure_cli_tools_initialized()
|
|
1037
|
+
processes = []
|
|
1038
|
+
|
|
1039
|
+
for pid, info in self.background_processes.items():
|
|
1040
|
+
# Check if process is still running
|
|
1041
|
+
try:
|
|
1042
|
+
proc = psutil.Process(pid)
|
|
1043
|
+
is_running = proc.is_running()
|
|
1044
|
+
except psutil.NoSuchProcess:
|
|
1045
|
+
is_running = False
|
|
1046
|
+
|
|
1047
|
+
processes.append(
|
|
1048
|
+
{
|
|
1049
|
+
"pid": pid,
|
|
1050
|
+
"command": info.command,
|
|
1051
|
+
"working_dir": info.working_dir,
|
|
1052
|
+
"port": info.port,
|
|
1053
|
+
"running": is_running,
|
|
1054
|
+
"runtime_seconds": time.time() - info.start_time,
|
|
1055
|
+
"log_file": info.log_file,
|
|
1056
|
+
}
|
|
1057
|
+
)
|
|
1058
|
+
|
|
1059
|
+
return {
|
|
1060
|
+
"success": True,
|
|
1061
|
+
"count": len(processes),
|
|
1062
|
+
"processes": processes,
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
def _get_process_logs(self, pid: int, lines: int = 50) -> Dict[str, Any]:
|
|
1066
|
+
"""
|
|
1067
|
+
Get output logs from a background process.
|
|
1068
|
+
|
|
1069
|
+
Args:
|
|
1070
|
+
pid: Process ID
|
|
1071
|
+
lines: Number of lines to return
|
|
1072
|
+
|
|
1073
|
+
Returns:
|
|
1074
|
+
Dict with log output
|
|
1075
|
+
"""
|
|
1076
|
+
self._ensure_cli_tools_initialized()
|
|
1077
|
+
if pid not in self.background_processes:
|
|
1078
|
+
return {
|
|
1079
|
+
"success": False,
|
|
1080
|
+
"error": f"Process {pid} not found",
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
proc_info = self.background_processes[pid]
|
|
1084
|
+
|
|
1085
|
+
try:
|
|
1086
|
+
with open(proc_info.log_file, "r", encoding="utf-8") as f:
|
|
1087
|
+
all_lines = f.readlines()
|
|
1088
|
+
recent_lines = (
|
|
1089
|
+
all_lines[-lines:] if len(all_lines) > lines else all_lines
|
|
1090
|
+
)
|
|
1091
|
+
|
|
1092
|
+
return {
|
|
1093
|
+
"success": True,
|
|
1094
|
+
"pid": pid,
|
|
1095
|
+
"lines": len(recent_lines),
|
|
1096
|
+
"output": "".join(recent_lines),
|
|
1097
|
+
"log_file": proc_info.log_file,
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
except Exception as e:
|
|
1101
|
+
return {
|
|
1102
|
+
"success": False,
|
|
1103
|
+
"error": str(e),
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
def _cleanup_all_processes(self) -> Dict[str, Any]:
|
|
1107
|
+
"""
|
|
1108
|
+
Stop all managed background processes.
|
|
1109
|
+
|
|
1110
|
+
Returns:
|
|
1111
|
+
Dict with cleanup status
|
|
1112
|
+
"""
|
|
1113
|
+
self._ensure_cli_tools_initialized()
|
|
1114
|
+
pids = list(self.background_processes.keys())
|
|
1115
|
+
stopped = []
|
|
1116
|
+
failed = []
|
|
1117
|
+
|
|
1118
|
+
for pid in pids:
|
|
1119
|
+
result = self._stop_process(pid, force=False)
|
|
1120
|
+
if result.get("success"):
|
|
1121
|
+
stopped.append(pid)
|
|
1122
|
+
else:
|
|
1123
|
+
failed.append(pid)
|
|
1124
|
+
|
|
1125
|
+
return {
|
|
1126
|
+
"success": len(failed) == 0,
|
|
1127
|
+
"stopped": stopped,
|
|
1128
|
+
"failed": failed,
|
|
1129
|
+
"message": f"Stopped {len(stopped)} processes, {len(failed)} failures",
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
def __del__(self):
|
|
1133
|
+
"""Cleanup all processes on deletion."""
|
|
1134
|
+
if hasattr(self, "background_processes"):
|
|
1135
|
+
try:
|
|
1136
|
+
self._cleanup_all_processes()
|
|
1137
|
+
except Exception as e:
|
|
1138
|
+
logger.debug(f"Error cleaning up processes in __del__: {e}")
|