@agenthippo-ai/agenthippo 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/bin/agenthippo.js +2 -0
- package/out/agentpack/github.js +547 -0
- package/out/agentpack/index.js +66 -0
- package/out/agentpack/install.js +297 -0
- package/out/agentpack/manager.js +441 -0
- package/out/agentpack/manifest.js +135 -0
- package/out/agentpack/paths.js +475 -0
- package/out/agentpack/publish.js +248 -0
- package/out/agentpack/stores.js +554 -0
- package/out/agentpack/types.js +5 -0
- package/out/analytics/dashboard/artifactManager.js +439 -0
- package/out/analytics/dashboard/fleetDisplayUtils.js +159 -0
- package/out/analytics/dashboard/fleetOrchestrator.js +142 -0
- package/out/analytics/dashboard/fleetRegistry.js +79 -0
- package/out/analytics/dashboard/fleetRowDefaults.js +87 -0
- package/out/analytics/dashboard/fleetScriptAdapter.js +146 -0
- package/out/analytics/dashboard/fleetStatusUtils.js +30 -0
- package/out/analytics/dashboard/fleetTitleUtils.js +68 -0
- package/out/analytics/dashboard/fleetTypes.js +29 -0
- package/out/analytics/dashboard/index.js +17 -0
- package/out/analytics/dashboard/indexingService.js +422 -0
- package/out/analytics/dashboard/localFleetAdapter.js +222 -0
- package/out/analytics/dashboard/performanceMonitor.js +76 -0
- package/out/analytics/dashboard/processManager.js +209 -0
- package/out/analytics/dashboard/provider.js +3885 -0
- package/out/analytics/dashboard/queryRunner.js +994 -0
- package/out/analytics/dashboard/refreshPolicy.js +16 -0
- package/out/analytics/dashboard/scheduledFleetFingerprint.js +22 -0
- package/out/analytics/dashboard/scheduledFleetStorage.js +241 -0
- package/out/analytics/dashboard/scheduledFleetUtils.js +22 -0
- package/out/analytics/dashboard/sessionEventFleetStats.js +118 -0
- package/out/analytics/dashboard/sessionJsonlFleet.js +204 -0
- package/out/analytics/dashboard/teamViewDiscovery.js +106 -0
- package/out/analytics/dashboard/viewsConfigMerge.js +221 -0
- package/out/analytics/dashboard/webview/analytics-panel.html +155 -0
- package/out/analytics/dashboard/webview/codicon.ttf +0 -0
- package/out/analytics/dashboard/webview/index.html +78 -0
- package/out/analytics/dashboard/webview/panel.js +2295 -0
- package/out/analytics/dashboard/webview/runtime-bridge.js +82 -0
- package/out/analytics/dashboard/webview/styles.css +1009 -0
- package/out/analytics/lifecycle.js +43 -0
- package/out/analytics/service.js +1279 -0
- package/out/analytics/sessionEvents.js +231 -0
- package/out/auth/bootstrapApply.js +72 -0
- package/out/auth/brokerClient.js +126 -0
- package/out/auth/callbackUri.js +59 -0
- package/out/auth/callbackUriParse.js +59 -0
- package/out/auth/githubStoreGate.js +70 -0
- package/out/auth/loopbackAuthServer.js +165 -0
- package/out/auth/pkce.js +9 -0
- package/out/auth/provider.js +239 -0
- package/out/auth/sessionStore.js +193 -0
- package/out/auth/signInFlow.js +182 -0
- package/out/auth/types.js +12 -0
- package/out/auth-broker/config.js +62 -0
- package/out/auth-broker/jwt.js +105 -0
- package/out/auth-broker/pkce.js +57 -0
- package/out/auth-broker/server.js +539 -0
- package/out/auth-broker/store.js +273 -0
- package/out/base-prompts/gateway/openclaw-starter.json5 +144 -0
- package/out/base-prompts/gateway/slack-socket-mode-minimal.manifest.json +44 -0
- package/out/base-prompts/mcp-servers/.mcp.json +13 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/README.md +142 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/mcp.json +13 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/package-lock.json +1192 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/package.json +23 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/run-with-env.sh +12 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/sdk-test.js +102 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/simple-test.js +137 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-client.js +118 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-server.js +209 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/src/client.ts +431 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/src/index.ts +270 -0
- package/out/base-prompts/mcp-servers/langfuse-analytics/tsconfig.json +18 -0
- package/out/base-prompts/rules/AGENTS.md +204 -0
- package/out/base-prompts/skills/agent-browser/SKILL.md +102 -0
- package/out/base-prompts/skills/agent-builder/SKILL.md +73 -0
- package/out/base-prompts/skills/agent-builder/references/agent-pack.md +63 -0
- package/out/base-prompts/skills/agent-builder/references/crewai.md +66 -0
- package/out/base-prompts/skills/agent-builder/references/langchain.md +60 -0
- package/out/base-prompts/skills/agent-builder/references/raw-sdk.md +73 -0
- package/out/base-prompts/skills/agent-engine-creator/SKILL.md +586 -0
- package/out/base-prompts/skills/agent-engine-installer/SKILL.md +106 -0
- package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.mjs +259 -0
- package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.ps1 +189 -0
- package/out/base-prompts/skills/agenthippo-cli/SKILL.md +69 -0
- package/out/base-prompts/skills/agenthippo-cli/scripts/install.sh +63 -0
- package/out/base-prompts/skills/agentpack-creator/SKILL.md +375 -0
- package/out/base-prompts/skills/agentpack-creator/references/agent-templates.md +261 -0
- package/out/base-prompts/skills/agentpack-creator/references/agents-md-guide.md +195 -0
- package/out/base-prompts/skills/agentpack-creator/scripts/init_pack.py +391 -0
- package/out/base-prompts/skills/agentpack-creator/scripts/init_pack_test.py +294 -0
- package/out/base-prompts/skills/agentpack-testbench/SKILL.md +135 -0
- package/out/base-prompts/skills/algorithmic-art/LICENSE.txt +202 -0
- package/out/base-prompts/skills/algorithmic-art/SKILL.md +405 -0
- package/out/base-prompts/skills/algorithmic-art/templates/generator_template.js +223 -0
- package/out/base-prompts/skills/algorithmic-art/templates/viewer.html +599 -0
- package/out/base-prompts/skills/debug-agent/SKILL.md +83 -0
- package/out/base-prompts/skills/desktop-automation/SKILL.md +166 -0
- package/out/base-prompts/skills/desktop-automation/references/agenthippo-ui-recipes.md +441 -0
- package/out/base-prompts/skills/desktop-automation/scripts/windows-desktop-uia.psm1 +280 -0
- package/out/base-prompts/skills/docx/LICENSE.txt +30 -0
- package/out/base-prompts/skills/docx/SKILL.md +197 -0
- package/out/base-prompts/skills/docx/docx-js.md +350 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/out/base-prompts/skills/docx/ooxml/scripts/pack.py +159 -0
- package/out/base-prompts/skills/docx/ooxml/scripts/unpack.py +29 -0
- package/out/base-prompts/skills/docx/ooxml/scripts/validate.py +69 -0
- package/out/base-prompts/skills/docx/ooxml/scripts/validation/__init__.py +15 -0
- package/out/base-prompts/skills/docx/ooxml/scripts/validation/base.py +951 -0
- package/out/base-prompts/skills/docx/ooxml/scripts/validation/docx.py +274 -0
- package/out/base-prompts/skills/docx/ooxml/scripts/validation/pptx.py +315 -0
- package/out/base-prompts/skills/docx/ooxml/scripts/validation/redlining.py +279 -0
- package/out/base-prompts/skills/docx/ooxml.md +610 -0
- package/out/base-prompts/skills/docx/scripts/__init__.py +1 -0
- package/out/base-prompts/skills/docx/scripts/document.py +1276 -0
- package/out/base-prompts/skills/docx/scripts/templates/comments.xml +3 -0
- package/out/base-prompts/skills/docx/scripts/templates/commentsExtended.xml +3 -0
- package/out/base-prompts/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/out/base-prompts/skills/docx/scripts/templates/commentsIds.xml +3 -0
- package/out/base-prompts/skills/docx/scripts/templates/people.xml +3 -0
- package/out/base-prompts/skills/docx/scripts/utilities.py +374 -0
- package/out/base-prompts/skills/gateway-outbound/SKILL.md +136 -0
- package/out/base-prompts/skills/mcp-builder/LICENSE.txt +202 -0
- package/out/base-prompts/skills/mcp-builder/SKILL.md +328 -0
- package/out/base-prompts/skills/mcp-builder/reference/evaluation.md +602 -0
- package/out/base-prompts/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
- package/out/base-prompts/skills/mcp-builder/reference/node_mcp_server.md +970 -0
- package/out/base-prompts/skills/mcp-builder/reference/python_mcp_server.md +719 -0
- package/out/base-prompts/skills/mcp-builder/scripts/connections.py +151 -0
- package/out/base-prompts/skills/mcp-builder/scripts/evaluation.py +373 -0
- package/out/base-prompts/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/out/base-prompts/skills/mcp-builder/scripts/requirements.txt +2 -0
- package/out/base-prompts/skills/openclaw/SKILL.md +406 -0
- package/out/base-prompts/skills/openclaw/scripts/run-smoke.sh +61 -0
- package/out/base-prompts/skills/pdf/LICENSE.txt +30 -0
- package/out/base-prompts/skills/pdf/SKILL.md +294 -0
- package/out/base-prompts/skills/pdf/forms.md +205 -0
- package/out/base-prompts/skills/pdf/reference.md +612 -0
- package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes.py +70 -0
- package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
- package/out/base-prompts/skills/pdf/scripts/check_fillable_fields.py +12 -0
- package/out/base-prompts/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/out/base-prompts/skills/pdf/scripts/create_validation_image.py +41 -0
- package/out/base-prompts/skills/pdf/scripts/extract_form_field_info.py +152 -0
- package/out/base-prompts/skills/pdf/scripts/fill_fillable_fields.py +114 -0
- package/out/base-prompts/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/out/base-prompts/skills/pptx/LICENSE.txt +30 -0
- package/out/base-prompts/skills/pptx/SKILL.md +484 -0
- package/out/base-prompts/skills/pptx/html2pptx.md +625 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/out/base-prompts/skills/pptx/ooxml/scripts/pack.py +159 -0
- package/out/base-prompts/skills/pptx/ooxml/scripts/unpack.py +29 -0
- package/out/base-prompts/skills/pptx/ooxml/scripts/validate.py +69 -0
- package/out/base-prompts/skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
- package/out/base-prompts/skills/pptx/ooxml/scripts/validation/base.py +951 -0
- package/out/base-prompts/skills/pptx/ooxml/scripts/validation/docx.py +274 -0
- package/out/base-prompts/skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
- package/out/base-prompts/skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
- package/out/base-prompts/skills/pptx/ooxml.md +427 -0
- package/out/base-prompts/skills/pptx/scripts/html2pptx.js +984 -0
- package/out/base-prompts/skills/pptx/scripts/inventory.py +1020 -0
- package/out/base-prompts/skills/pptx/scripts/rearrange.py +231 -0
- package/out/base-prompts/skills/pptx/scripts/replace.py +385 -0
- package/out/base-prompts/skills/pptx/scripts/thumbnail.py +450 -0
- package/out/base-prompts/skills/prompt-lab/SKILL.md +149 -0
- package/out/base-prompts/skills/prompt-lab/scripts/query-analytics.sh +2551 -0
- package/out/base-prompts/skills/skill-creator/LICENSE.txt +202 -0
- package/out/base-prompts/skills/skill-creator/SKILL.md +371 -0
- package/out/base-prompts/skills/skill-creator/references/output-patterns.md +82 -0
- package/out/base-prompts/skills/skill-creator/references/workflows.md +28 -0
- package/out/base-prompts/skills/skill-creator/scripts/init_skill.py +303 -0
- package/out/base-prompts/skills/skill-creator/scripts/package_skill.py +110 -0
- package/out/base-prompts/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/out/base-prompts/skills/skill-installer/SKILL.md +251 -0
- package/out/base-prompts/skills/skill-installer/references/store-api.md +219 -0
- package/out/base-prompts/skills/spotlight-dashboard/SKILL.md +83 -0
- package/out/base-prompts/skills/spotlight-insights/SKILL.md +101 -0
- package/out/base-prompts/skills/spotlight-optimize/SKILL.md +93 -0
- package/out/base-prompts/skills/spotlight-optimize/scripts/query-analytics.sh +2551 -0
- package/out/base-prompts/skills/spotlight-query/SKILL.md +314 -0
- package/out/base-prompts/skills/spotlight-query/references/otel-schema.md +163 -0
- package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.sh +2551 -0
- package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.test.sh +744 -0
- package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/sessions/sess-test-1.jsonl +14 -0
- package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/.duckdb-index.json +7 -0
- package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/sample.jsonl +5 -0
- package/out/base-prompts/skills/spotlight-report/SKILL.md +86 -0
- package/out/base-prompts/skills/spotlight-visualize/SKILL.md +92 -0
- package/out/base-prompts/skills/spotlight-visualize/scripts/query-analytics.sh +2551 -0
- package/out/base-prompts/skills/xlsx/LICENSE.txt +30 -0
- package/out/base-prompts/skills/xlsx/SKILL.md +289 -0
- package/out/base-prompts/skills/xlsx/recalc.py +178 -0
- package/out/branding.js +23 -0
- package/out/cli/commands/anywhere.js +66 -0
- package/out/cli/commands/ask.js +243 -0
- package/out/cli/commands/auth-broker.js +24 -0
- package/out/cli/commands/auth.js +219 -0
- package/out/cli/commands/chat.js +354 -0
- package/out/cli/commands/deploy.js +223 -0
- package/out/cli/commands/gateway.js +160 -0
- package/out/cli/commands/pack.js +220 -0
- package/out/cli/commands/probe-custom-engine.js +82 -0
- package/out/cli/commands/serve.js +583 -0
- package/out/cli/commands/store.js +919 -0
- package/out/cli/credential-context.js +113 -0
- package/out/cli/deploy-init.js +2087 -0
- package/out/cli/deps.js +238 -0
- package/out/cli/index.js +390 -0
- package/out/cli/pack-loader.js +376 -0
- package/out/cli/run-custom-engine-runner.js +318 -0
- package/out/cli/runtime.js +409 -0
- package/out/cli/serve-hardening.js +325 -0
- package/out/cli/state-sync.js +135 -0
- package/out/cli/utils.js +220 -0
- package/out/cli/vscode-shim.js +86 -0
- package/out/engines/base.js +159 -0
- package/out/engines/claude.js +1215 -0
- package/out/engines/codex.js +759 -0
- package/out/engines/custom.js +632 -0
- package/out/engines/customEngineIpc.js +95 -0
- package/out/engines/customEngineRunnerEmbed.js +107 -0
- package/out/engines/customRegistry.js +274 -0
- package/out/engines/embeddedCustomEngineRunner.generated.js +9 -0
- package/out/engines/engineApiKey.js +138 -0
- package/out/engines/factory.js +45 -0
- package/out/engines/install.js +372 -0
- package/out/engines/persistentEngineWorker.js +320 -0
- package/out/engines/publish.js +341 -0
- package/out/engines/types.js +17 -0
- package/out/examples/run-headless-repl.js +291 -0
- package/out/examples/run-headless.js +187 -0
- package/out/extension.js +4472 -0
- package/out/gateway/bridge.js +805 -0
- package/out/gateway/cli-agent-id.js +36 -0
- package/out/gateway/client.js +303 -0
- package/out/gateway/client.test.js +395 -0
- package/out/gateway/gateway-scope-errors.js +14 -0
- package/out/gateway/gatewayBackup.js +76 -0
- package/out/gateway/gatewayRouteIndex.js +371 -0
- package/out/gateway/gatewaySessionStore.js +243 -0
- package/out/gateway/index.js +31 -0
- package/out/gateway/lifecycle.js +3056 -0
- package/out/gateway/openclaw-channel-routing.js +317 -0
- package/out/gateway/outboundHandles.js +373 -0
- package/out/gateway/outboundPaths.js +72 -0
- package/out/gateway/outboundSend.js +254 -0
- package/out/gateway/protocol.js +48 -0
- package/out/gateway/resetMappings.js +52 -0
- package/out/gateway/service.js +1244 -0
- package/out/gateway/sessionRouting.js +77 -0
- package/out/headless/index.js +505 -0
- package/out/headless/sync.js +473 -0
- package/out/mcp/publish.js +143 -0
- package/out/mcp.js +597 -0
- package/out/permissions.js +108 -0
- package/out/permissions.mapping.yaml +68 -0
- package/out/registry/index.js +332 -0
- package/out/remote/handleRemoteChat.js +122 -0
- package/out/remote/remotePackStatusBar.js +103 -0
- package/out/remote/serveClient.js +216 -0
- package/out/remoteSkills.js +191 -0
- package/out/runtime/index.js +32 -0
- package/out/runtime/interfaces/config-provider.js +32 -0
- package/out/runtime/interfaces/edit-tracker.js +22 -0
- package/out/runtime/interfaces/index.js +29 -0
- package/out/runtime/interfaces/logger.js +40 -0
- package/out/runtime/interfaces/permission-handler.js +66 -0
- package/out/runtime/interfaces/session-store.js +342 -0
- package/out/runtime/vscode/index.js +20 -0
- package/out/runtime/vscode/vscode-config-provider.js +77 -0
- package/out/runtime/vscode/vscode-edit-tracker.js +120 -0
- package/out/runtime/vscode/vscode-logger.js +30 -0
- package/out/runtime/vscode/vscode-permission-handler.js +72 -0
- package/out/runtime/vscode/vscode-session-store.js +22 -0
- package/out/scripts/agentide-litellm.ps1 +501 -0
- package/out/scripts/agentide-litellm.sh +700 -0
- package/out/scripts/agentide_litellm_hooks_v1.py +604 -0
- package/out/scripts/analytics/agent-fleet-widget.js +954 -0
- package/out/scripts/analytics/agentide-litellm-otel.config.yaml +160 -0
- package/out/scripts/analytics/default-seed-scripts.json +12 -0
- package/out/scripts/analytics/duckdbLocator.js +29 -0
- package/out/scripts/analytics/fleet-local-adapter.js +246 -0
- package/out/scripts/analytics/fleet-workflow.sh +263 -0
- package/out/scripts/analytics/generate-default-charts.py +685 -0
- package/out/scripts/analytics/hotspot-analysis-widget.js +909 -0
- package/out/scripts/analytics/index-traces.py +1394 -0
- package/out/scripts/analytics/install-analytics.sh +286 -0
- package/out/scripts/analytics/live-fleet-4-collector.cjs +315 -0
- package/out/scripts/analytics/live-fleet-4-daemon.mjs +134 -0
- package/out/scripts/analytics/live-fleet-4-widget.cjs +433 -0
- package/out/scripts/analytics/otel-collector.yaml +55 -0
- package/out/scripts/analytics/query-analytics.ps1 +396 -0
- package/out/scripts/analytics/query-analytics.sh +2551 -0
- package/out/scripts/analytics/session-comparison-widget.js +1468 -0
- package/out/scripts/analytics/session-timeline-widget.js +2137 -0
- package/out/scripts/analytics/setup-analytics.ps1 +432 -0
- package/out/scripts/analytics/setup-analytics.sh +854 -0
- package/out/scripts/analytics/start-analytics.ps1 +169 -0
- package/out/scripts/analytics/start-analytics.sh +323 -0
- package/out/scripts/analytics/token-cost-flamegraph-widget.js +954 -0
- package/out/scripts/analytics/token-cost-trend-widget.js +1062 -0
- package/out/scripts/analytics/workflows-collector.cjs +315 -0
- package/out/scripts/analytics/workflows-daemon.mjs +186 -0
- package/out/scripts/analytics/workflows-widget.cjs +433 -0
- package/out/scripts/analytics/wow-model-widget.js +191 -0
- package/out/scripts/gateway/Dockerfile.serve +45 -0
- package/out/scripts/gateway/docker-serve.sh +248 -0
- package/out/scripts/gateway/setup-gateway-server.ps1 +953 -0
- package/out/scripts/gateway/setup-gateway-server.sh +935 -0
- package/out/scripts/gateway/setup-gateway.ps1 +1813 -0
- package/out/scripts/gateway/setup-gateway.sh +1541 -0
- package/out/scripts/setup-cli.ps1 +86 -0
- package/out/scripts/setup-cli.sh +117 -0
- package/out/scripts/tools-manifest.json +83 -0
- package/out/scripts/vendor-tools.mjs +234 -0
- package/out/session.js +272 -0
- package/out/shared/agentEngines.js +170 -0
- package/out/shared/index.js +109 -0
- package/out/shared/models.js +235 -0
- package/out/shared/providers.js +202 -0
- package/out/skills/publish.js +178 -0
- package/out/spotlight/install.js +339 -0
- package/out/spotlight/publish.js +544 -0
- package/out/spotlight/yaml.js +31 -0
- package/out/store/github/setup.js +235 -0
- package/out/store/github/templates/build-index.ts +339 -0
- package/out/store/github/templates/build-index.yml +97 -0
- package/out/store/github/templates/package.json +11 -0
- package/out/store/index.js +755 -0
- package/out/store/oramaIndex.js +884 -0
- package/out/store/shared.js +241 -0
- package/out/sync.js +1827 -0
- package/out/terminalLogger.js +358 -0
- package/out/test/agentEnvFile.test.js +97 -0
- package/out/test/agentYaml.test.js +373 -0
- package/out/test/agentpack.test.js +639 -0
- package/out/test/analytics-lifecycle.test.js +174 -0
- package/out/test/analytics.test.js +524 -0
- package/out/test/auth-bootstrapApply.test.js +102 -0
- package/out/test/auth-broker.test.js +434 -0
- package/out/test/auth-callback.test.js +62 -0
- package/out/test/branding.test.js +229 -0
- package/out/test/cli-agent-id.test.js +55 -0
- package/out/test/credential-context.test.js +105 -0
- package/out/test/customEngineInstall.test.js +100 -0
- package/out/test/customRegistry.test.js +122 -0
- package/out/test/deploy-init.test.js +532 -0
- package/out/test/deps-auto-install.test.js +81 -0
- package/out/test/engine-integration.test.js +297 -0
- package/out/test/enginePaths.test.js +195 -0
- package/out/test/enginePublish.test.js +82 -0
- package/out/test/fleetDisplayUtils.test.js +96 -0
- package/out/test/gateway-client.test.js +381 -0
- package/out/test/gateway-lifecycle.test.js +608 -0
- package/out/test/gateway-outbound.test.js +531 -0
- package/out/test/gateway-reset-mappings.test.js +221 -0
- package/out/test/gateway-route-index.test.js +235 -0
- package/out/test/gateway-session-routing.test.js +47 -0
- package/out/test/gateway-session-store.test.js +216 -0
- package/out/test/github.test.js +232 -0
- package/out/test/headless-sync.test.js +279 -0
- package/out/test/helpers/manifest-fixtures.js +27 -0
- package/out/test/mcp-obo.test.js +82 -0
- package/out/test/mcp.test.js +307 -0
- package/out/test/openclaw-channel-routing.test.js +191 -0
- package/out/test/pathSafety.test.js +63 -0
- package/out/test/permissions.test.js +175 -0
- package/out/test/persistent-engine-worker.test.js +220 -0
- package/out/test/refreshPolicy.test.js +60 -0
- package/out/test/registry.test.js +351 -0
- package/out/test/runtime.test.js +349 -0
- package/out/test/scheduledFleetStorage.test.js +72 -0
- package/out/test/serve-hardening.test.js +192 -0
- package/out/test/serveClient.test.js +173 -0
- package/out/test/sessionJsonlFleet.test.js +78 -0
- package/out/test/shared.test.js +173 -0
- package/out/test/skills-mcp.test.js +299 -0
- package/out/test/spotlightPublish.test.js +299 -0
- package/out/test/spotlightYaml.test.js +58 -0
- package/out/test/state-sync-peer.test.js +74 -0
- package/out/test/store.test.js +331 -0
- package/out/test/stores.test.js +504 -0
- package/out/test/sync-switch.test.js +251 -0
- package/out/test/teamViewDiscovery.test.js +90 -0
- package/out/test/toolPath.test.js +120 -0
- package/out/test/utils.test.js +308 -0
- package/out/test/viewsConfigMerge.test.js +180 -0
- package/out/test/windows-command-line.test.js +75 -0
- package/out/utils/agentEnvFile.js +131 -0
- package/out/utils/binary.js +175 -0
- package/out/utils/index.js +37 -0
- package/out/utils/network.js +74 -0
- package/out/utils/pathSafety.js +60 -0
- package/out/utils/paths.js +116 -0
- package/out/utils/pid.js +180 -0
- package/out/utils/pythonRunner.js +258 -0
- package/out/utils/resolveNodeBinary.js +168 -0
- package/out/utils/toolPath.js +83 -0
- package/out/utils/windowsCommandLine.js +29 -0
- package/out/utils.js +915 -0
- package/out/workspaceFolders.js +59 -0
- package/package.json +41 -0
|
@@ -0,0 +1,1279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) AgentHippo.ai. All rights reserved.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.AnalyticsService = void 0;
|
|
40
|
+
const vscode = __importStar(require("vscode"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const fsSync = __importStar(require("fs"));
|
|
43
|
+
const fs_1 = require("fs");
|
|
44
|
+
const child_process_1 = require("child_process");
|
|
45
|
+
const branding_1 = require("../branding");
|
|
46
|
+
const indexingService_1 = require("./dashboard/indexingService");
|
|
47
|
+
const performanceMonitor_1 = require("./dashboard/performanceMonitor");
|
|
48
|
+
const lifecycle_1 = require("./lifecycle");
|
|
49
|
+
const index_1 = require("../utils/index");
|
|
50
|
+
const windowsCommandLine_1 = require("../utils/windowsCommandLine");
|
|
51
|
+
/**
|
|
52
|
+
* Resolve the preferred PowerShell host on Windows. PowerShell 7 (`pwsh.exe`)
|
|
53
|
+
* fixed native-command argument quoting bugs that affect inline `bash -c`
|
|
54
|
+
* scripts containing embedded double quotes. We prefer it when present and
|
|
55
|
+
* fall back to the always-present Windows PowerShell 5.1 (`powershell.exe`).
|
|
56
|
+
*
|
|
57
|
+
* Cached for the lifetime of the extension host — pwsh install state is not
|
|
58
|
+
* expected to change mid-session, and the lookup hits the filesystem.
|
|
59
|
+
*/
|
|
60
|
+
let cachedWindowsPwshPath;
|
|
61
|
+
function getWindowsPwshOrPowerShell() {
|
|
62
|
+
if (process.platform !== 'win32') {
|
|
63
|
+
return 'powershell.exe';
|
|
64
|
+
}
|
|
65
|
+
if (cachedWindowsPwshPath === undefined) {
|
|
66
|
+
cachedWindowsPwshPath = resolvePwshExecutable();
|
|
67
|
+
}
|
|
68
|
+
return cachedWindowsPwshPath ?? 'powershell.exe';
|
|
69
|
+
}
|
|
70
|
+
function resolvePwshExecutable() {
|
|
71
|
+
const candidates = [];
|
|
72
|
+
const pathDirs = (process.env.PATH ?? '').split(path.delimiter).filter(Boolean);
|
|
73
|
+
for (const dir of pathDirs) {
|
|
74
|
+
candidates.push(path.join(dir, 'pwsh.exe'));
|
|
75
|
+
}
|
|
76
|
+
const programFiles = process.env.ProgramFiles ?? 'C:\\Program Files';
|
|
77
|
+
const programFilesX86 = process.env['ProgramFiles(x86)'] ?? 'C:\\Program Files (x86)';
|
|
78
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
79
|
+
for (const major of ['7', '8']) {
|
|
80
|
+
candidates.push(path.join(programFiles, 'PowerShell', major, 'pwsh.exe'));
|
|
81
|
+
candidates.push(path.join(programFilesX86, 'PowerShell', major, 'pwsh.exe'));
|
|
82
|
+
}
|
|
83
|
+
if (localAppData) {
|
|
84
|
+
candidates.push(path.join(localAppData, 'Microsoft', 'PowerShell', 'pwsh.exe'));
|
|
85
|
+
}
|
|
86
|
+
for (const candidate of candidates) {
|
|
87
|
+
try {
|
|
88
|
+
if (fsSync.statSync(candidate).isFile()) {
|
|
89
|
+
return candidate;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// not present; continue
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Manages LiteLLM Spotlight (OTEL Collector + DuckDB analytics).
|
|
100
|
+
* Provides status bar indicator and commands for managing the analytics stack.
|
|
101
|
+
*/
|
|
102
|
+
class AnalyticsService {
|
|
103
|
+
statusBarItem;
|
|
104
|
+
outputChannel;
|
|
105
|
+
extensionContext;
|
|
106
|
+
_status = 'stopped';
|
|
107
|
+
_lastStackStatus = { otelRunning: false, litellmRunning: false, litellmWithOtel: false };
|
|
108
|
+
indexProgress = { status: 'idle', percent: 0 };
|
|
109
|
+
indexingService;
|
|
110
|
+
performanceMonitor;
|
|
111
|
+
disposables = [];
|
|
112
|
+
lifecycleInProgress = false;
|
|
113
|
+
/**
|
|
114
|
+
* Get the current status of the analytics stack.
|
|
115
|
+
*/
|
|
116
|
+
get status() {
|
|
117
|
+
return this._status;
|
|
118
|
+
}
|
|
119
|
+
healthCheckTimer = null;
|
|
120
|
+
static HEALTH_CHECK_INTERVAL = 30000; // 30 seconds
|
|
121
|
+
constructor(extensionContext, outputChannel) {
|
|
122
|
+
this.extensionContext = extensionContext;
|
|
123
|
+
this.outputChannel = outputChannel;
|
|
124
|
+
this.performanceMonitor = new performanceMonitor_1.PerformanceMonitor(outputChannel);
|
|
125
|
+
// Create status bar item
|
|
126
|
+
this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 99);
|
|
127
|
+
this.statusBarItem.command = 'agentide.analytics.toggle';
|
|
128
|
+
// Register commands
|
|
129
|
+
this.registerCommands();
|
|
130
|
+
// Check if analytics has ever been configured before starting heartbeat
|
|
131
|
+
void this.initializeWithLazyHeartbeat();
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Initialize with lazy heartbeat - only start periodic checks if analytics is configured.
|
|
135
|
+
* This avoids unnecessary process spawning (pgrep) when user hasn't set up analytics.
|
|
136
|
+
*/
|
|
137
|
+
async initializeWithLazyHeartbeat() {
|
|
138
|
+
const isConfigured = await this.isAnalyticsConfigured();
|
|
139
|
+
if (isConfigured) {
|
|
140
|
+
// Analytics was set up - do full check and start heartbeat
|
|
141
|
+
this.updateStatusBar('checking');
|
|
142
|
+
await this.checkStatus();
|
|
143
|
+
this.startHeartbeat();
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Not configured - show stopped, no heartbeat needed
|
|
147
|
+
this.updateStatusBar('stopped');
|
|
148
|
+
this.statusBarItem.show();
|
|
149
|
+
// Still check for standalone LiteLLM (not tied to analytics)
|
|
150
|
+
// This allows Language Models table to populate even without analytics setup
|
|
151
|
+
await this.detectStandaloneLiteLLM();
|
|
152
|
+
}
|
|
153
|
+
// Initialize background indexing service for dashboard
|
|
154
|
+
await this.initializeIndexingService();
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Initialize background indexing service.
|
|
158
|
+
*/
|
|
159
|
+
async initializeIndexingService() {
|
|
160
|
+
try {
|
|
161
|
+
const analyticsDir = this.getAnalyticsDir();
|
|
162
|
+
const tracesDir = path.join(analyticsDir, 'traces');
|
|
163
|
+
this.indexingService = new indexingService_1.IndexingService(tracesDir, this.outputChannel, this.performanceMonitor);
|
|
164
|
+
// Subscribe to indexing progress updates
|
|
165
|
+
this.disposables.push(this.indexingService.onProgressChange((progress) => {
|
|
166
|
+
this.indexProgress = progress;
|
|
167
|
+
this.updateStatusBar(this._status); // Refresh status bar with new progress
|
|
168
|
+
}));
|
|
169
|
+
// Initialize indexing service (starts file watcher, checks if re-indexing needed)
|
|
170
|
+
await this.indexingService.initialize();
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
this.outputChannel.appendLine(`[Analytics] Failed to initialize indexing service: ${error}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Get IndexingService instance (for provider integration).
|
|
178
|
+
*/
|
|
179
|
+
getIndexingService() {
|
|
180
|
+
return this.indexingService;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Detect standalone LiteLLM (running without analytics) and update base URL setting.
|
|
184
|
+
* This is a one-time check on startup to enable model discovery even when analytics
|
|
185
|
+
* is not configured.
|
|
186
|
+
*/
|
|
187
|
+
async detectStandaloneLiteLLM() {
|
|
188
|
+
try {
|
|
189
|
+
const status = await this.getLiteLLMStatus();
|
|
190
|
+
if (status.running) {
|
|
191
|
+
this.outputChannel.appendLine('[Analytics] Detected standalone LiteLLM running');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// Best-effort only - don't block startup
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Check if analytics has been configured (config files exist).
|
|
200
|
+
* This is a fast check that doesn't spawn any processes.
|
|
201
|
+
*/
|
|
202
|
+
async isAnalyticsConfigured() {
|
|
203
|
+
const analyticsDir = this.getAnalyticsDir();
|
|
204
|
+
const configPath = path.join(analyticsDir, 'config', 'otel-collector.yaml');
|
|
205
|
+
try {
|
|
206
|
+
await fs_1.promises.access(configPath);
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Start the periodic heartbeat timer.
|
|
215
|
+
*/
|
|
216
|
+
startHeartbeat() {
|
|
217
|
+
if (this.healthCheckTimer) {
|
|
218
|
+
return; // Already running
|
|
219
|
+
}
|
|
220
|
+
this.healthCheckTimer = setInterval(() => {
|
|
221
|
+
void this.checkStatus();
|
|
222
|
+
}, AnalyticsService.HEALTH_CHECK_INTERVAL);
|
|
223
|
+
}
|
|
224
|
+
registerCommands() {
|
|
225
|
+
this.disposables.push(vscode.commands.registerCommand('agentide.analytics.toggle', () => this.toggle()), vscode.commands.registerCommand('agentide.analytics.restart', () => this.restart()), vscode.commands.registerCommand('agentide.analytics.start', () => this.start()), vscode.commands.registerCommand('agentide.analytics.stop', () => this.stop()), vscode.commands.registerCommand('agentide.analytics.status', () => this.showStatus()), vscode.commands.registerCommand('agentide.analytics.query', () => this.openQueryTerminal()), vscode.commands.registerCommand('agentide.analytics.openLiteLLMConfig', () => this.openLiteLLMConfig()),
|
|
226
|
+
// Returns true if the full analytics stack is running (used by core to skip redundant setup prompts)
|
|
227
|
+
vscode.commands.registerCommand('agentide.analytics.isRunning', () => this.checkStatus()));
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Get the analytics home directory.
|
|
231
|
+
* Uses shared path utility for consistency.
|
|
232
|
+
*/
|
|
233
|
+
getAnalyticsDir() {
|
|
234
|
+
return index_1.DIRS.analytics();
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Get the PID file path for OTEL Collector.
|
|
238
|
+
* Uses shared PID_FILES constant for consistency.
|
|
239
|
+
*/
|
|
240
|
+
getOtelPidFile() {
|
|
241
|
+
return index_1.PID_FILES.otelcol();
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get the PID file path for LiteLLM.
|
|
245
|
+
* Uses shared PID_FILES constant for consistency.
|
|
246
|
+
*/
|
|
247
|
+
getLiteLLMPidFile() {
|
|
248
|
+
return index_1.PID_FILES.litellm();
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Check full analytics stack status (OTEL Collector + LiteLLM).
|
|
252
|
+
* Returns true only if both services are properly configured.
|
|
253
|
+
*/
|
|
254
|
+
async checkStatus() {
|
|
255
|
+
try {
|
|
256
|
+
const stackStatus = await this.getStackStatus();
|
|
257
|
+
this._lastStackStatus = stackStatus;
|
|
258
|
+
if (stackStatus.otelRunning && stackStatus.litellmWithOtel) {
|
|
259
|
+
// Full stack running properly
|
|
260
|
+
this.updateStatusBar('running');
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
else if (this.lifecycleInProgress) {
|
|
264
|
+
// During an explicit start/setup/restart, OTEL commonly becomes visible
|
|
265
|
+
// before LiteLLM has written its PID metadata. Keep the UI in a
|
|
266
|
+
// starting state until readiness monitoring completes.
|
|
267
|
+
this.updateStatusBar('checking');
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
else if (stackStatus.otelRunning || stackStatus.litellmRunning) {
|
|
271
|
+
// Partial - something is running but not fully configured
|
|
272
|
+
this.updateStatusBar('partial');
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
// Nothing running
|
|
277
|
+
this.updateStatusBar('stopped');
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
this.updateStatusBar('error');
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Get detailed status of each analytics component.
|
|
288
|
+
*/
|
|
289
|
+
async getStackStatus() {
|
|
290
|
+
const otelRunning = await this.isOtelRunning();
|
|
291
|
+
const litellmStatus = await this.getLiteLLMStatus();
|
|
292
|
+
return {
|
|
293
|
+
otelRunning,
|
|
294
|
+
litellmRunning: litellmStatus.running,
|
|
295
|
+
litellmWithOtel: litellmStatus.withOtel,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Check if OTEL Collector is running via PID file.
|
|
300
|
+
* Cost: ~1-2ms (file read + signal check, no process spawn)
|
|
301
|
+
* Also cleans up stale PID files per ARCHITECTURE.md pattern.
|
|
302
|
+
*/
|
|
303
|
+
async isOtelRunning() {
|
|
304
|
+
const result = await (0, index_1.checkPidFileWithCleanup)(this.getOtelPidFile());
|
|
305
|
+
return result !== null;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Check LiteLLM status via the canonical PID file written by agentide-litellm.{sh,ps1}.
|
|
309
|
+
* Cost: ~1-2ms (file read + signal check, no process spawn).
|
|
310
|
+
*
|
|
311
|
+
* PID file format: "PID\n[otel]\n[url=...]". Process detection / killing across
|
|
312
|
+
* platforms (incl. winpid) is handled inside the launcher script — this code only
|
|
313
|
+
* trusts what the launcher wrote.
|
|
314
|
+
*/
|
|
315
|
+
async getLiteLLMStatus() {
|
|
316
|
+
const pidData = await (0, index_1.checkPidFileWithCleanup)(this.getLiteLLMPidFile());
|
|
317
|
+
if (!pidData) {
|
|
318
|
+
return { running: false, withOtel: false };
|
|
319
|
+
}
|
|
320
|
+
const metadata = pidData.metadata ?? [];
|
|
321
|
+
const withOtel = metadata.some(line => line.trim().toLowerCase() === 'otel');
|
|
322
|
+
const urlLine = metadata.find(line => line.startsWith('url='));
|
|
323
|
+
if (urlLine) {
|
|
324
|
+
await this.maybeUpdateLiteLLMBaseUrlValue(urlLine.slice('url='.length).trim());
|
|
325
|
+
}
|
|
326
|
+
return { running: true, withOtel };
|
|
327
|
+
}
|
|
328
|
+
async maybeUpdateLiteLLMBaseUrlValue(baseUrl) {
|
|
329
|
+
const config = vscode.workspace.getConfiguration('agentide.providers.litellm');
|
|
330
|
+
if (config.get('baseUrl')?.trim()) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const trimmed = baseUrl.trim();
|
|
334
|
+
if (!trimmed) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
await config.update('baseUrl', trimmed, vscode.ConfigurationTarget.Global);
|
|
338
|
+
this.outputChannel.appendLine(`[Analytics] Auto-detected LiteLLM base URL: ${trimmed}`);
|
|
339
|
+
}
|
|
340
|
+
async waitForStackReady(timeoutMs = 30_000, intervalMs = 1_000) {
|
|
341
|
+
const deadline = Date.now() + timeoutMs;
|
|
342
|
+
let lastStatus = await this.getStackStatus();
|
|
343
|
+
while (Date.now() < deadline) {
|
|
344
|
+
lastStatus = await this.getStackStatus();
|
|
345
|
+
this._lastStackStatus = lastStatus;
|
|
346
|
+
if (lastStatus.otelRunning && lastStatus.litellmWithOtel) {
|
|
347
|
+
return lastStatus;
|
|
348
|
+
}
|
|
349
|
+
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
350
|
+
}
|
|
351
|
+
return lastStatus;
|
|
352
|
+
}
|
|
353
|
+
async waitForStackStopped(timeoutMs = 15_000, intervalMs = 500) {
|
|
354
|
+
const deadline = Date.now() + timeoutMs;
|
|
355
|
+
let lastStatus = await this.getStackStatus();
|
|
356
|
+
while (Date.now() < deadline) {
|
|
357
|
+
lastStatus = await this.getStackStatus();
|
|
358
|
+
this._lastStackStatus = lastStatus;
|
|
359
|
+
if (!lastStatus.otelRunning && !lastStatus.litellmRunning) {
|
|
360
|
+
return lastStatus;
|
|
361
|
+
}
|
|
362
|
+
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
363
|
+
}
|
|
364
|
+
return lastStatus;
|
|
365
|
+
}
|
|
366
|
+
async monitorStartupReadiness(reason) {
|
|
367
|
+
const stackStatus = await this.waitForStackReady();
|
|
368
|
+
this._lastStackStatus = stackStatus;
|
|
369
|
+
const status = this.deriveStatusFrom(stackStatus);
|
|
370
|
+
this.lifecycleInProgress = false;
|
|
371
|
+
this.updateStatusBar(status);
|
|
372
|
+
if (status === 'running') {
|
|
373
|
+
this.log(`Analytics stack ready after ${reason}.`);
|
|
374
|
+
vscode.window.showInformationMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Spotlight ${reason === 'restart' ? 'restarted' : 'started'}.`);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
this.log(`Analytics stack not fully ready after ${reason} ` +
|
|
378
|
+
`(otel=${stackStatus.otelRunning}, litellm=${stackStatus.litellmRunning}, litellmWithOtel=${stackStatus.litellmWithOtel})`);
|
|
379
|
+
const choice = await vscode.window.showWarningMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Spotlight ${reason === 'restart' ? 'restart' : 'start'} is not fully ready yet.`, 'Show Status');
|
|
380
|
+
if (choice === 'Show Status') {
|
|
381
|
+
await this.showStatus();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
async monitorStopReadiness() {
|
|
385
|
+
const stackStatus = await this.waitForStackStopped();
|
|
386
|
+
this._lastStackStatus = stackStatus;
|
|
387
|
+
const status = this.deriveStatusFrom(stackStatus);
|
|
388
|
+
this.lifecycleInProgress = false;
|
|
389
|
+
this.updateStatusBar(status);
|
|
390
|
+
if (status === 'stopped') {
|
|
391
|
+
this.log('Analytics stack stopped.');
|
|
392
|
+
vscode.window.showInformationMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Spotlight stopped.`);
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
this.log(`Analytics stack not fully stopped ` +
|
|
396
|
+
`(otel=${stackStatus.otelRunning}, litellm=${stackStatus.litellmRunning}, litellmWithOtel=${stackStatus.litellmWithOtel})`);
|
|
397
|
+
const choice = await vscode.window.showWarningMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Spotlight stop is not fully complete yet.`, 'Show Status');
|
|
398
|
+
if (choice === 'Show Status') {
|
|
399
|
+
await this.showStatus();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Handle status bar click.
|
|
404
|
+
* Always open a menu instantly from cached state.
|
|
405
|
+
* Heavy checks/actions run only after explicit user choice.
|
|
406
|
+
*/
|
|
407
|
+
async toggle() {
|
|
408
|
+
// Don't block the click on a foreground check; act on the cached snapshot.
|
|
409
|
+
const status = this._status === 'checking'
|
|
410
|
+
? this.deriveStatusFrom(this._lastStackStatus)
|
|
411
|
+
: this._status;
|
|
412
|
+
if (status === 'running') {
|
|
413
|
+
await this.showStatusWithRestartOption();
|
|
414
|
+
}
|
|
415
|
+
else if (status === 'partial') {
|
|
416
|
+
await this.showPartialStatusOption();
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
await this.showStoppedStatusOption(status);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
queueBackgroundStatusRefresh(reason) {
|
|
423
|
+
if (this.lifecycleInProgress) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
setTimeout(() => {
|
|
427
|
+
if (this.lifecycleInProgress) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
void this.checkStatus().catch((err) => {
|
|
431
|
+
this.log(`Background status refresh failed after ${reason}: ${err instanceof Error ? err.message : String(err)}`);
|
|
432
|
+
});
|
|
433
|
+
}, 100);
|
|
434
|
+
}
|
|
435
|
+
deriveStatusFrom(s) {
|
|
436
|
+
return (0, lifecycle_1.deriveAnalyticsStatus)(s);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Show options when in partial state (something running but not fully configured).
|
|
440
|
+
*/
|
|
441
|
+
async showPartialStatusOption() {
|
|
442
|
+
const stackStatus = this._lastStackStatus;
|
|
443
|
+
const message = (0, lifecycle_1.getPartialSpotlightMessage)(stackStatus);
|
|
444
|
+
const choicePromise = vscode.window.showWarningMessage(`${branding_1.AGENTIDE_BRAND_NAME}: ${message}`, 'Install', 'Restart All', 'Show Status');
|
|
445
|
+
this.queueBackgroundStatusRefresh('opening partial menu');
|
|
446
|
+
const choice = await choicePromise;
|
|
447
|
+
switch (choice) {
|
|
448
|
+
case 'Install':
|
|
449
|
+
await vscode.commands.executeCommand('agentide.setupAnalytics');
|
|
450
|
+
break;
|
|
451
|
+
case 'Restart All':
|
|
452
|
+
await this.restart();
|
|
453
|
+
break;
|
|
454
|
+
case 'Show Status':
|
|
455
|
+
await this.showStatus();
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Show status summary and offer to restart.
|
|
461
|
+
*/
|
|
462
|
+
async showStatusWithRestartOption() {
|
|
463
|
+
const choicePromise = vscode.window.showInformationMessage(`${branding_1.AGENTIDE_BRAND_NAME} Spotlight is running.`, 'See Spotlight', 'Restart All', 'Stop', 'Indexing', 'Show Status');
|
|
464
|
+
this.queueBackgroundStatusRefresh('opening running menu');
|
|
465
|
+
const choice = await choicePromise;
|
|
466
|
+
switch (choice) {
|
|
467
|
+
case 'See Spotlight':
|
|
468
|
+
await vscode.commands.executeCommand('agentide.analytics.openDashboard');
|
|
469
|
+
break;
|
|
470
|
+
case 'Restart All':
|
|
471
|
+
await this.restart();
|
|
472
|
+
break;
|
|
473
|
+
case 'Stop':
|
|
474
|
+
await this.stop();
|
|
475
|
+
break;
|
|
476
|
+
case 'Indexing':
|
|
477
|
+
await this.triggerIndexing();
|
|
478
|
+
break;
|
|
479
|
+
case 'Show Status':
|
|
480
|
+
await this.showStatus();
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Restart the analytics stack: stop LiteLLM, restart OTEL via terminal, start LiteLLM detached.
|
|
486
|
+
*/
|
|
487
|
+
async restart() {
|
|
488
|
+
this.log('Restarting analytics stack...');
|
|
489
|
+
this.lifecycleInProgress = true;
|
|
490
|
+
this.updateStatusBar('checking');
|
|
491
|
+
if (!(await this.isAnalyticsConfigured())) {
|
|
492
|
+
await this.start();
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
const isWindows = process.platform === 'win32';
|
|
496
|
+
const startScript = await this.findScript(isWindows ? 'start-analytics.ps1' : 'start-analytics.sh');
|
|
497
|
+
if (!startScript) {
|
|
498
|
+
this.lifecycleInProgress = false;
|
|
499
|
+
this.updateStatusBar('error');
|
|
500
|
+
vscode.window.showErrorMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Spotlight scripts not found. Run Install first.`);
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const terminal = await this.createSpotlightLifecycleTerminal('Spotlight Restart', 'restart', startScript);
|
|
504
|
+
terminal.show();
|
|
505
|
+
this.updateStatusBar('checking');
|
|
506
|
+
this.startHeartbeat();
|
|
507
|
+
void this.monitorStartupReadiness('restart');
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Run Windows setup end-to-end from the extension, then start LiteLLM via
|
|
511
|
+
* the existing launcher path. Unix setup remains script-owned for now.
|
|
512
|
+
*/
|
|
513
|
+
async setupWindowsSpotlight(options = {}) {
|
|
514
|
+
if (process.platform !== 'win32') {
|
|
515
|
+
return { success: false, error: 'Windows-only setup flow invoked on a non-Windows platform.' };
|
|
516
|
+
}
|
|
517
|
+
const setupScript = await this.findScript('setup-analytics.ps1');
|
|
518
|
+
if (!setupScript) {
|
|
519
|
+
const message = `${branding_1.AGENTIDE_BRAND_NAME}: Spotlight install script not found.`;
|
|
520
|
+
vscode.window.showErrorMessage(message);
|
|
521
|
+
return { success: false, error: message };
|
|
522
|
+
}
|
|
523
|
+
this.lifecycleInProgress = true;
|
|
524
|
+
this.updateStatusBar('checking');
|
|
525
|
+
this.outputChannel.show(true);
|
|
526
|
+
this.log(`${options.reinstall ? 'Reinstalling' : 'Installing/repairing'} Spotlight on Windows...`);
|
|
527
|
+
vscode.window.showInformationMessage(`${branding_1.AGENTIDE_BRAND_NAME}: ${options.reinstall ? 'Reinstalling' : 'Installing'} Spotlight...`);
|
|
528
|
+
try {
|
|
529
|
+
if (options.reinstall) {
|
|
530
|
+
this.log('Stopping LiteLLM before reinstall...');
|
|
531
|
+
await this.stopLiteLLMDirectly();
|
|
532
|
+
}
|
|
533
|
+
const setupOk = await this.runWindowsSetupScript(setupScript);
|
|
534
|
+
if (!setupOk) {
|
|
535
|
+
throw new Error('setup-analytics.ps1 failed');
|
|
536
|
+
}
|
|
537
|
+
const litellmStatus = await this.getLiteLLMStatus();
|
|
538
|
+
if (litellmStatus.running) {
|
|
539
|
+
this.log('Restarting LiteLLM to apply Spotlight config...');
|
|
540
|
+
await this.stopLiteLLMDirectly();
|
|
541
|
+
}
|
|
542
|
+
this.log('Starting LiteLLM proxy via IDE-managed launcher...');
|
|
543
|
+
const litellmStarted = await this.startLiteLLMDirectly();
|
|
544
|
+
if (!litellmStarted) {
|
|
545
|
+
throw new Error('LiteLLM launcher did not start');
|
|
546
|
+
}
|
|
547
|
+
const analyticsDir = this.getAnalyticsDir();
|
|
548
|
+
this.log(`LiteLLM logs: ${path.join(analyticsDir, 'litellm.log')}`);
|
|
549
|
+
this.log(`LiteLLM errors: ${path.join(analyticsDir, 'litellm.error.log')}`);
|
|
550
|
+
this.startHeartbeat();
|
|
551
|
+
void this.monitorStartupReadiness(options.reinstall ? 'restart' : 'start');
|
|
552
|
+
return { success: true };
|
|
553
|
+
}
|
|
554
|
+
catch (error) {
|
|
555
|
+
this.lifecycleInProgress = false;
|
|
556
|
+
this.updateStatusBar('error');
|
|
557
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
558
|
+
this.log(`Windows Spotlight install failed: ${message}`);
|
|
559
|
+
vscode.window.showErrorMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Spotlight install failed. ${message}`);
|
|
560
|
+
return { success: false, error: message };
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Show options when Spotlight is stopped/unknown.
|
|
565
|
+
*/
|
|
566
|
+
async showStoppedStatusOption(status) {
|
|
567
|
+
const message = status === 'error'
|
|
568
|
+
? `${branding_1.AGENTIDE_BRAND_NAME}: Spotlight status is unavailable.`
|
|
569
|
+
: `${branding_1.AGENTIDE_BRAND_NAME}: Spotlight is stopped.`;
|
|
570
|
+
const choicePromise = vscode.window.showInformationMessage(message, 'Start', 'Install', 'See Spotlight', 'Show Status');
|
|
571
|
+
this.queueBackgroundStatusRefresh('opening stopped menu');
|
|
572
|
+
const choice = await choicePromise;
|
|
573
|
+
switch (choice) {
|
|
574
|
+
case 'Start':
|
|
575
|
+
await this.start();
|
|
576
|
+
break;
|
|
577
|
+
case 'Install':
|
|
578
|
+
await vscode.commands.executeCommand('agentide.setupAnalytics');
|
|
579
|
+
break;
|
|
580
|
+
case 'See Spotlight':
|
|
581
|
+
await vscode.commands.executeCommand('agentide.analytics.openDashboard');
|
|
582
|
+
break;
|
|
583
|
+
case 'Show Status':
|
|
584
|
+
await this.showStatus();
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
async runWindowsSetupScript(scriptPath) {
|
|
589
|
+
const agentHomeDir = (0, index_1.getAgentideHome)();
|
|
590
|
+
const args = [
|
|
591
|
+
'-NoProfile',
|
|
592
|
+
'-NonInteractive',
|
|
593
|
+
'-ExecutionPolicy',
|
|
594
|
+
'Bypass',
|
|
595
|
+
'-File',
|
|
596
|
+
scriptPath,
|
|
597
|
+
'-Yes',
|
|
598
|
+
];
|
|
599
|
+
this.log(`Running ${path.basename(scriptPath)} -Yes...`);
|
|
600
|
+
return new Promise((resolve) => {
|
|
601
|
+
let settled = false;
|
|
602
|
+
const finish = (ok) => {
|
|
603
|
+
if (settled) {
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
settled = true;
|
|
607
|
+
resolve(ok);
|
|
608
|
+
};
|
|
609
|
+
const child = (0, child_process_1.spawn)(getWindowsPwshOrPowerShell(), args, {
|
|
610
|
+
cwd: path.dirname(scriptPath),
|
|
611
|
+
env: { ...process.env, AGENT_HOME_DIR: agentHomeDir },
|
|
612
|
+
windowsHide: true,
|
|
613
|
+
});
|
|
614
|
+
child.stdout?.on('data', data => {
|
|
615
|
+
this.outputChannel.append(data.toString());
|
|
616
|
+
});
|
|
617
|
+
child.stderr?.on('data', data => {
|
|
618
|
+
this.outputChannel.append(data.toString());
|
|
619
|
+
});
|
|
620
|
+
child.once('error', err => {
|
|
621
|
+
this.log(`Windows setup script failed to spawn: ${err.message}`);
|
|
622
|
+
finish(false);
|
|
623
|
+
});
|
|
624
|
+
child.once('exit', code => {
|
|
625
|
+
if (code === 0) {
|
|
626
|
+
this.log('Windows Spotlight install script completed.');
|
|
627
|
+
finish(true);
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
this.log(`Windows Spotlight install script exited with code ${code ?? 'unknown'}.`);
|
|
631
|
+
finish(false);
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Start the OTEL Collector.
|
|
638
|
+
*/
|
|
639
|
+
async start() {
|
|
640
|
+
const isRunning = await this.checkStatus();
|
|
641
|
+
if (isRunning) {
|
|
642
|
+
vscode.window.showInformationMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Spotlight is already running.`);
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
// Find the start script (platform-specific)
|
|
646
|
+
const isWindows = process.platform === 'win32';
|
|
647
|
+
const scriptPath = await this.findScript(isWindows ? 'start-analytics.ps1' : 'start-analytics.sh');
|
|
648
|
+
if (!scriptPath) {
|
|
649
|
+
this.lifecycleInProgress = false;
|
|
650
|
+
vscode.window.showErrorMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Spotlight scripts not found. Run Install first.`);
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
this.lifecycleInProgress = true;
|
|
654
|
+
this.updateStatusBar('checking');
|
|
655
|
+
const terminal = await this.createSpotlightLifecycleTerminal('Spotlight Start', 'start', scriptPath);
|
|
656
|
+
terminal.show();
|
|
657
|
+
this.log('Starting Spotlight (OTEL Collector + LiteLLM)...');
|
|
658
|
+
vscode.window.showInformationMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Starting Spotlight...`);
|
|
659
|
+
this.updateStatusBar('checking');
|
|
660
|
+
// Start heartbeat if not already running (user just set up analytics)
|
|
661
|
+
this.startHeartbeat();
|
|
662
|
+
void this.monitorStartupReadiness('start');
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Stop the OTEL Collector.
|
|
666
|
+
*/
|
|
667
|
+
async stop() {
|
|
668
|
+
this.lifecycleInProgress = true;
|
|
669
|
+
this.updateStatusBar('checking');
|
|
670
|
+
// Find the start script (which also handles stopping)
|
|
671
|
+
const isWindows = process.platform === 'win32';
|
|
672
|
+
const scriptPath = await this.findScript(isWindows ? 'start-analytics.ps1' : 'start-analytics.sh');
|
|
673
|
+
if (!scriptPath) {
|
|
674
|
+
// Try to stop directly via PID
|
|
675
|
+
await this.stopDirectly();
|
|
676
|
+
this.lifecycleInProgress = false;
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
// Run the stop command with visible output
|
|
680
|
+
const terminal = await this.createSpotlightLifecycleTerminal('Spotlight Stop', 'stop', scriptPath);
|
|
681
|
+
terminal.show();
|
|
682
|
+
this.log('Stopping Spotlight (OTEL Collector + LiteLLM)...');
|
|
683
|
+
this.updateStatusBar('checking');
|
|
684
|
+
void this.monitorStopReadiness();
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Stop OTEL Collector directly via PID file.
|
|
688
|
+
*/
|
|
689
|
+
async stopDirectly() {
|
|
690
|
+
try {
|
|
691
|
+
const pidFile = this.getOtelPidFile();
|
|
692
|
+
const pidContent = await fs_1.promises.readFile(pidFile, 'utf8');
|
|
693
|
+
const pid = parseInt(pidContent.trim(), 10);
|
|
694
|
+
if (!isNaN(pid)) {
|
|
695
|
+
process.kill(pid, 'SIGTERM');
|
|
696
|
+
await fs_1.promises.unlink(pidFile).catch(() => { });
|
|
697
|
+
this.log(`Stopped OTEL Collector (PID: ${pid})`);
|
|
698
|
+
}
|
|
699
|
+
await this.stopLiteLLMDirectly();
|
|
700
|
+
this.updateStatusBar('stopped');
|
|
701
|
+
}
|
|
702
|
+
catch (error) {
|
|
703
|
+
this.log(`Failed to stop directly: ${error}`);
|
|
704
|
+
this.updateStatusBar('error');
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
async createSpotlightLifecycleTerminal(name, action, startScript) {
|
|
708
|
+
const agentHomeDir = (0, index_1.getAgentideHome)();
|
|
709
|
+
const analyticsDir = path.join(agentHomeDir, 'analytics');
|
|
710
|
+
fsSync.mkdirSync(analyticsDir, { recursive: true });
|
|
711
|
+
const litellmScript = await this.findLiteLLMScript();
|
|
712
|
+
const configPath = path.join(agentHomeDir, 'litellm-otel.yaml');
|
|
713
|
+
const stdoutPath = path.join(analyticsDir, 'litellm.log');
|
|
714
|
+
const stderrPath = path.join(analyticsDir, 'litellm.error.log');
|
|
715
|
+
if (process.platform === 'win32') {
|
|
716
|
+
return vscode.window.createTerminal({
|
|
717
|
+
name,
|
|
718
|
+
cwd: path.dirname(startScript),
|
|
719
|
+
env: { AGENT_HOME_DIR: agentHomeDir },
|
|
720
|
+
shellPath: getWindowsPwshOrPowerShell(),
|
|
721
|
+
shellArgs: [
|
|
722
|
+
'-NoProfile',
|
|
723
|
+
'-NoExit',
|
|
724
|
+
'-ExecutionPolicy',
|
|
725
|
+
'Bypass',
|
|
726
|
+
'-Command',
|
|
727
|
+
this.buildWindowsSpotlightLifecycleCommand({
|
|
728
|
+
action,
|
|
729
|
+
startScript,
|
|
730
|
+
litellmScript,
|
|
731
|
+
agentHomeDir,
|
|
732
|
+
configPath,
|
|
733
|
+
stdoutPath,
|
|
734
|
+
stderrPath,
|
|
735
|
+
}),
|
|
736
|
+
],
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
return vscode.window.createTerminal({
|
|
740
|
+
name,
|
|
741
|
+
cwd: path.dirname(startScript),
|
|
742
|
+
env: { AGENT_HOME_DIR: agentHomeDir },
|
|
743
|
+
shellPath: '/bin/bash',
|
|
744
|
+
shellArgs: [
|
|
745
|
+
'-c',
|
|
746
|
+
this.buildUnixSpotlightLifecycleCommand({
|
|
747
|
+
action,
|
|
748
|
+
startScript,
|
|
749
|
+
litellmScript,
|
|
750
|
+
agentHomeDir,
|
|
751
|
+
configPath,
|
|
752
|
+
stdoutPath,
|
|
753
|
+
stderrPath,
|
|
754
|
+
}),
|
|
755
|
+
],
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
buildWindowsSpotlightLifecycleCommand(options) {
|
|
759
|
+
const q = (value) => `'${this.escapePowerShellSingleQuotedString(value)}'`;
|
|
760
|
+
const lines = [
|
|
761
|
+
'$ErrorActionPreference = \'Continue\'',
|
|
762
|
+
`$env:AGENT_HOME_DIR = ${q(options.agentHomeDir)}`,
|
|
763
|
+
`Write-Host ${q(this.getLifecycleTerminalIntro(options.action))}`,
|
|
764
|
+
];
|
|
765
|
+
if (options.action === 'stop' || options.action === 'restart') {
|
|
766
|
+
lines.push('Write-Host ""', 'Write-Host "Stopping LiteLLM proxy..."', ...this.buildWindowsLiteLLMStopCommands(options.litellmScript, q));
|
|
767
|
+
}
|
|
768
|
+
if (options.action === 'stop') {
|
|
769
|
+
lines.push('Write-Host ""', 'Write-Host "Stopping OTEL Collector..."', `& ${q(options.startScript)} -Stop`);
|
|
770
|
+
}
|
|
771
|
+
else if (options.action === 'restart') {
|
|
772
|
+
lines.push('Write-Host ""', 'Write-Host "Restarting OTEL Collector..."', `& ${q(options.startScript)} -Stop`, 'Start-Sleep 1', `& ${q(options.startScript)} -ForceDaemon`);
|
|
773
|
+
}
|
|
774
|
+
else {
|
|
775
|
+
lines.push('Write-Host ""', 'Write-Host "Starting OTEL Collector..."', `& ${q(options.startScript)} -ForceDaemon`);
|
|
776
|
+
}
|
|
777
|
+
if (options.action === 'start' || options.action === 'restart') {
|
|
778
|
+
lines.push('Write-Host ""', ...this.buildWindowsLiteLLMStartCommands(options, q));
|
|
779
|
+
}
|
|
780
|
+
lines.push('Write-Host ""', 'Write-Host "You can close this window."');
|
|
781
|
+
return lines.join('\r\n');
|
|
782
|
+
}
|
|
783
|
+
buildWindowsLiteLLMStopCommands(litellmScript, q) {
|
|
784
|
+
if (!litellmScript) {
|
|
785
|
+
return ['Write-Host "[WARN] LiteLLM launcher script not found. Skipping LiteLLM stop." -ForegroundColor Yellow'];
|
|
786
|
+
}
|
|
787
|
+
return [`& ${q(litellmScript)} -Stop`];
|
|
788
|
+
}
|
|
789
|
+
buildWindowsLiteLLMStartCommands(options, q) {
|
|
790
|
+
if (!options.litellmScript) {
|
|
791
|
+
return ['Write-Host "[WARN] LiteLLM launcher script not found. Skipping LiteLLM start." -ForegroundColor Yellow'];
|
|
792
|
+
}
|
|
793
|
+
const launcherArgumentLine = (0, windowsCommandLine_1.buildWindowsArgumentLine)([
|
|
794
|
+
'-NoProfile',
|
|
795
|
+
'-NoLogo',
|
|
796
|
+
'-ExecutionPolicy',
|
|
797
|
+
'Bypass',
|
|
798
|
+
'-File',
|
|
799
|
+
options.litellmScript,
|
|
800
|
+
'-ConfigPath',
|
|
801
|
+
options.configPath,
|
|
802
|
+
]);
|
|
803
|
+
return [
|
|
804
|
+
'Write-Host "Starting LiteLLM proxy..."',
|
|
805
|
+
`if (-not (Test-Path ${q(options.configPath)})) {`,
|
|
806
|
+
` Write-Host ${q(`[WARN] LiteLLM config not found: ${options.configPath}`)} -ForegroundColor Yellow`,
|
|
807
|
+
'} else {',
|
|
808
|
+
` $env:LITELLM_CONFIG_PATH = ${q(options.configPath)}`,
|
|
809
|
+
' try {',
|
|
810
|
+
` $proc = Start-Process -FilePath ${q(getWindowsPwshOrPowerShell())} -WindowStyle Hidden -WorkingDirectory ${q(path.dirname(options.litellmScript))} -ArgumentList ${q(launcherArgumentLine)} -RedirectStandardOutput ${q(options.stdoutPath)} -RedirectStandardError ${q(options.stderrPath)} -PassThru -ErrorAction Stop`,
|
|
811
|
+
' Write-Host "[OK] LiteLLM launcher started (PID: $($proc.Id))"',
|
|
812
|
+
` Write-Host ${q(` Logs: ${options.stdoutPath}`)}`,
|
|
813
|
+
` Write-Host ${q(` Errors: ${options.stderrPath}`)}`,
|
|
814
|
+
' } catch {',
|
|
815
|
+
' Write-Host "[ERROR] Failed to start LiteLLM launcher." -ForegroundColor Red',
|
|
816
|
+
' Write-Host $_.Exception.Message -ForegroundColor Red',
|
|
817
|
+
' }',
|
|
818
|
+
'}',
|
|
819
|
+
];
|
|
820
|
+
}
|
|
821
|
+
buildUnixSpotlightLifecycleCommand(options) {
|
|
822
|
+
const q = (value) => this.quoteBash(value);
|
|
823
|
+
const lines = [
|
|
824
|
+
'set +e',
|
|
825
|
+
`export AGENT_HOME_DIR=${q(options.agentHomeDir)}`,
|
|
826
|
+
`mkdir -p ${q(path.dirname(options.stdoutPath))}`,
|
|
827
|
+
`echo ${q(this.getLifecycleTerminalIntro(options.action))}`,
|
|
828
|
+
];
|
|
829
|
+
if (options.action === 'stop' || options.action === 'restart') {
|
|
830
|
+
lines.push('echo ""', 'echo "Stopping LiteLLM proxy..."', ...this.buildUnixLiteLLMStopCommands(options.litellmScript, q));
|
|
831
|
+
}
|
|
832
|
+
if (options.action === 'stop') {
|
|
833
|
+
lines.push('echo ""', 'echo "Stopping OTEL Collector..."', `${q(options.startScript)} --stop`);
|
|
834
|
+
}
|
|
835
|
+
else if (options.action === 'restart') {
|
|
836
|
+
lines.push('echo ""', 'echo "Restarting OTEL Collector..."', `${q(options.startScript)} --stop`, 'sleep 1', `${q(options.startScript)} --force-daemon`);
|
|
837
|
+
}
|
|
838
|
+
else {
|
|
839
|
+
lines.push('echo ""', 'echo "Starting OTEL Collector..."', `${q(options.startScript)} --force-daemon`);
|
|
840
|
+
}
|
|
841
|
+
if (options.action === 'start' || options.action === 'restart') {
|
|
842
|
+
lines.push('echo ""', ...this.buildUnixLiteLLMStartCommands(options, q));
|
|
843
|
+
}
|
|
844
|
+
lines.push('echo ""', 'echo "Press any key to close..."', 'read -n 1');
|
|
845
|
+
return lines.join('\n');
|
|
846
|
+
}
|
|
847
|
+
buildUnixLiteLLMStopCommands(litellmScript, q) {
|
|
848
|
+
if (!litellmScript) {
|
|
849
|
+
return ['echo "[WARN] LiteLLM launcher script not found. Skipping LiteLLM stop." >&2'];
|
|
850
|
+
}
|
|
851
|
+
return [`${q(litellmScript)} --stop`];
|
|
852
|
+
}
|
|
853
|
+
buildUnixLiteLLMStartCommands(options, q) {
|
|
854
|
+
if (!options.litellmScript) {
|
|
855
|
+
return ['echo "[WARN] LiteLLM launcher script not found. Skipping LiteLLM start." >&2'];
|
|
856
|
+
}
|
|
857
|
+
return [
|
|
858
|
+
'echo "Starting LiteLLM proxy..."',
|
|
859
|
+
`if [ ! -f ${q(options.configPath)} ]; then`,
|
|
860
|
+
` echo ${q(`[WARN] LiteLLM config not found: ${options.configPath}`)} >&2`,
|
|
861
|
+
'else',
|
|
862
|
+
` export LITELLM_CONFIG_PATH=${q(options.configPath)}`,
|
|
863
|
+
` nohup ${q(options.litellmScript)} --config ${q(options.configPath)} >> ${q(options.stdoutPath)} 2>> ${q(options.stderrPath)} &`,
|
|
864
|
+
' echo "[OK] LiteLLM launcher started (PID: $!)"',
|
|
865
|
+
` echo ${q(` Logs: ${options.stdoutPath}`)}`,
|
|
866
|
+
` echo ${q(` Errors: ${options.stderrPath}`)}`,
|
|
867
|
+
'fi',
|
|
868
|
+
];
|
|
869
|
+
}
|
|
870
|
+
getLifecycleTerminalIntro(action) {
|
|
871
|
+
switch (action) {
|
|
872
|
+
case 'start':
|
|
873
|
+
return 'Starting Spotlight (OTEL Collector + LiteLLM)...';
|
|
874
|
+
case 'stop':
|
|
875
|
+
return 'Stopping Spotlight (LiteLLM + OTEL Collector)...';
|
|
876
|
+
case 'restart':
|
|
877
|
+
return 'Restarting Spotlight (LiteLLM + OTEL Collector)...';
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
quoteBash(value) {
|
|
881
|
+
return `'${value.replace(/'/g, '\'\\\'\'')}'`;
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Stop LiteLLM by invoking the launcher script with --stop / -Stop.
|
|
885
|
+
* The script reads the canonical PID file and handles winpid/taskkill on Windows.
|
|
886
|
+
*/
|
|
887
|
+
async stopLiteLLMDirectly() {
|
|
888
|
+
const isWindows = process.platform === 'win32';
|
|
889
|
+
const args = isWindows ? ['-Stop'] : ['--stop'];
|
|
890
|
+
return this.runLauncher(args, { detached: false });
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Start LiteLLM in a detached background process. Logs go to .agent-hippo/analytics/litellm.{log,error.log}.
|
|
894
|
+
*/
|
|
895
|
+
async startLiteLLMDirectly() {
|
|
896
|
+
const configPath = path.join((0, index_1.getAgentideHome)(), 'litellm-otel.yaml');
|
|
897
|
+
try {
|
|
898
|
+
await fs_1.promises.access(configPath);
|
|
899
|
+
}
|
|
900
|
+
catch {
|
|
901
|
+
return false;
|
|
902
|
+
}
|
|
903
|
+
const isWindows = process.platform === 'win32';
|
|
904
|
+
const args = isWindows
|
|
905
|
+
? ['-ConfigPath', configPath]
|
|
906
|
+
: ['--config', configPath];
|
|
907
|
+
return this.runLauncher(args, { detached: true, configPath });
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Spawn the agentide-litellm launcher with the given args.
|
|
911
|
+
* `detached: true` returns immediately and pipes child stdout/stderr to log files.
|
|
912
|
+
* `detached: false` resolves when the process exits (used for --stop).
|
|
913
|
+
*/
|
|
914
|
+
async runLauncher(args, opts) {
|
|
915
|
+
const scriptPath = await this.findLiteLLMScript();
|
|
916
|
+
if (!scriptPath) {
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
const isWindows = process.platform === 'win32';
|
|
920
|
+
const shellPath = isWindows ? getWindowsPwshOrPowerShell() : '/bin/bash';
|
|
921
|
+
const shellArgs = isWindows
|
|
922
|
+
? ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', scriptPath, ...args]
|
|
923
|
+
: [scriptPath, ...args];
|
|
924
|
+
const env = { ...process.env, AGENT_HOME_DIR: (0, index_1.getAgentideHome)() };
|
|
925
|
+
if (opts.configPath) {
|
|
926
|
+
env.LITELLM_CONFIG_PATH = opts.configPath;
|
|
927
|
+
}
|
|
928
|
+
if (isWindows && opts.detached) {
|
|
929
|
+
return this.startLiteLLMViaHiddenWindowsProcess(scriptPath, args, env);
|
|
930
|
+
}
|
|
931
|
+
if (opts.detached) {
|
|
932
|
+
// Open log files synchronously so spawn can dup the fds before we close them.
|
|
933
|
+
const analyticsDir = path.join((0, index_1.getAgentideHome)(), 'analytics');
|
|
934
|
+
fsSync.mkdirSync(analyticsDir, { recursive: true });
|
|
935
|
+
const stdoutFd = fsSync.openSync(path.join(analyticsDir, 'litellm.log'), 'a');
|
|
936
|
+
const stderrFd = fsSync.openSync(path.join(analyticsDir, 'litellm.error.log'), 'a');
|
|
937
|
+
try {
|
|
938
|
+
const child = (0, child_process_1.spawn)(shellPath, shellArgs, {
|
|
939
|
+
detached: true,
|
|
940
|
+
stdio: ['ignore', stdoutFd, stderrFd],
|
|
941
|
+
windowsHide: true,
|
|
942
|
+
env,
|
|
943
|
+
cwd: path.dirname(scriptPath),
|
|
944
|
+
});
|
|
945
|
+
child.unref();
|
|
946
|
+
this.log(`LiteLLM launcher started (PID: ${child.pid})`);
|
|
947
|
+
return true;
|
|
948
|
+
}
|
|
949
|
+
catch (error) {
|
|
950
|
+
this.log(`Failed to start LiteLLM: ${error}`);
|
|
951
|
+
return false;
|
|
952
|
+
}
|
|
953
|
+
finally {
|
|
954
|
+
fsSync.closeSync(stdoutFd);
|
|
955
|
+
fsSync.closeSync(stderrFd);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return new Promise((resolve) => {
|
|
959
|
+
const child = (0, child_process_1.spawn)(shellPath, shellArgs, {
|
|
960
|
+
windowsHide: true,
|
|
961
|
+
env,
|
|
962
|
+
cwd: path.dirname(scriptPath),
|
|
963
|
+
});
|
|
964
|
+
child.once('error', (err) => {
|
|
965
|
+
this.log(`LiteLLM launcher failed to spawn: ${err}`);
|
|
966
|
+
resolve(false);
|
|
967
|
+
});
|
|
968
|
+
child.once('exit', (code) => resolve(code === 0));
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
async startLiteLLMViaHiddenWindowsProcess(scriptPath, args, env) {
|
|
972
|
+
const analyticsDir = path.join((0, index_1.getAgentideHome)(), 'analytics');
|
|
973
|
+
fsSync.mkdirSync(analyticsDir, { recursive: true });
|
|
974
|
+
const stdoutPath = path.join(analyticsDir, 'litellm.log');
|
|
975
|
+
const stderrPath = path.join(analyticsDir, 'litellm.error.log');
|
|
976
|
+
const launcherArgumentLine = (0, windowsCommandLine_1.buildWindowsArgumentLine)([
|
|
977
|
+
'-NoProfile',
|
|
978
|
+
'-NoLogo',
|
|
979
|
+
'-ExecutionPolicy',
|
|
980
|
+
'Bypass',
|
|
981
|
+
'-File',
|
|
982
|
+
scriptPath,
|
|
983
|
+
...args,
|
|
984
|
+
]);
|
|
985
|
+
const psCommand = [
|
|
986
|
+
`$env:AGENT_HOME_DIR = '${this.escapePowerShellSingleQuotedString(env.AGENT_HOME_DIR ?? (0, index_1.getAgentideHome)())}'`,
|
|
987
|
+
env.LITELLM_CONFIG_PATH
|
|
988
|
+
? `$env:LITELLM_CONFIG_PATH = '${this.escapePowerShellSingleQuotedString(env.LITELLM_CONFIG_PATH)}'`
|
|
989
|
+
: '',
|
|
990
|
+
`$proc = Start-Process -FilePath '${this.escapePowerShellSingleQuotedString(getWindowsPwshOrPowerShell())}' -WindowStyle Hidden -WorkingDirectory '${this.escapePowerShellSingleQuotedString(path.dirname(scriptPath))}' -ArgumentList '${this.escapePowerShellSingleQuotedString(launcherArgumentLine)}' -RedirectStandardOutput '${this.escapePowerShellSingleQuotedString(stdoutPath)}' -RedirectStandardError '${this.escapePowerShellSingleQuotedString(stderrPath)}' -PassThru`,
|
|
991
|
+
'Write-Output $proc.Id',
|
|
992
|
+
].filter(Boolean).join('; ');
|
|
993
|
+
return new Promise((resolve) => {
|
|
994
|
+
let stdout = '';
|
|
995
|
+
let stderr = '';
|
|
996
|
+
const child = (0, child_process_1.spawn)(getWindowsPwshOrPowerShell(), [
|
|
997
|
+
'-NoProfile',
|
|
998
|
+
'-ExecutionPolicy',
|
|
999
|
+
'Bypass',
|
|
1000
|
+
'-Command',
|
|
1001
|
+
psCommand,
|
|
1002
|
+
], {
|
|
1003
|
+
windowsHide: true,
|
|
1004
|
+
env,
|
|
1005
|
+
cwd: path.dirname(scriptPath),
|
|
1006
|
+
});
|
|
1007
|
+
child.stdout.on('data', data => {
|
|
1008
|
+
stdout += data.toString();
|
|
1009
|
+
});
|
|
1010
|
+
child.stderr.on('data', data => {
|
|
1011
|
+
stderr += data.toString();
|
|
1012
|
+
});
|
|
1013
|
+
child.once('error', (err) => {
|
|
1014
|
+
this.log(`LiteLLM launcher failed to spawn hidden Windows process: ${err}`);
|
|
1015
|
+
resolve(false);
|
|
1016
|
+
});
|
|
1017
|
+
child.once('exit', (code) => {
|
|
1018
|
+
if (code !== 0) {
|
|
1019
|
+
const detail = stderr.trim() || stdout.trim();
|
|
1020
|
+
this.log(`LiteLLM hidden Windows launcher exited with code ${code}${detail ? `: ${detail}` : ''}`);
|
|
1021
|
+
resolve(false);
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
const startedPid = parseInt(stdout.trim(), 10);
|
|
1025
|
+
if (!Number.isNaN(startedPid)) {
|
|
1026
|
+
this.log(`LiteLLM hidden Windows process started (PID: ${startedPid})`);
|
|
1027
|
+
}
|
|
1028
|
+
resolve(true);
|
|
1029
|
+
});
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
escapePowerShellSingleQuotedString(value) {
|
|
1033
|
+
return value.replace(/'/g, '\'\'');
|
|
1034
|
+
}
|
|
1035
|
+
async findLiteLLMScript() {
|
|
1036
|
+
const extensionPath = this.extensionContext.extensionPath;
|
|
1037
|
+
const isWindows = process.platform === 'win32';
|
|
1038
|
+
const scriptName = isWindows ? 'agentide-litellm.ps1' : 'agentide-litellm.sh';
|
|
1039
|
+
const candidates = [
|
|
1040
|
+
path.join(extensionPath, 'out', 'scripts', scriptName),
|
|
1041
|
+
path.join(extensionPath, 'scripts', scriptName),
|
|
1042
|
+
path.join(extensionPath, '..', '..', 'scripts', scriptName),
|
|
1043
|
+
];
|
|
1044
|
+
for (const candidate of candidates) {
|
|
1045
|
+
try {
|
|
1046
|
+
await fs_1.promises.access(candidate);
|
|
1047
|
+
return candidate;
|
|
1048
|
+
}
|
|
1049
|
+
catch {
|
|
1050
|
+
// ignore
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
return null;
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Run DuckDB re-indexing from trace JSONL (dashboard).
|
|
1057
|
+
*/
|
|
1058
|
+
async triggerIndexing() {
|
|
1059
|
+
if (!this.indexingService) {
|
|
1060
|
+
vscode.window.showWarningMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Indexing service is not available.`);
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
if (this.indexingService.isIndexing()) {
|
|
1064
|
+
vscode.window.showInformationMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Indexing is already in progress.`);
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
this.indexingService.scheduleIndexing(true);
|
|
1068
|
+
vscode.window.showInformationMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Triggered indexing.`);
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Show analytics status in a notification.
|
|
1072
|
+
*/
|
|
1073
|
+
async showStatus() {
|
|
1074
|
+
const stackStatus = await this.getStackStatus();
|
|
1075
|
+
const litellmBaseUrl = vscode.workspace
|
|
1076
|
+
.getConfiguration('agentide.providers.litellm')
|
|
1077
|
+
.get('baseUrl')
|
|
1078
|
+
?.trim();
|
|
1079
|
+
// Build status lines
|
|
1080
|
+
// allow-any-unicode-next-line
|
|
1081
|
+
const otelStatus = stackStatus.otelRunning ? '🟢 127.0.0.1:4318' : '⚫ Not running';
|
|
1082
|
+
let litellmStatus;
|
|
1083
|
+
if (stackStatus.litellmRunning && litellmBaseUrl) {
|
|
1084
|
+
// allow-any-unicode-next-line
|
|
1085
|
+
litellmStatus = `🟢 ${litellmBaseUrl}`;
|
|
1086
|
+
}
|
|
1087
|
+
else if (stackStatus.litellmRunning) {
|
|
1088
|
+
// allow-any-unicode-next-line
|
|
1089
|
+
litellmStatus = '🟢 Set URL in Settings or Stop External LiteLLM';
|
|
1090
|
+
}
|
|
1091
|
+
else {
|
|
1092
|
+
// allow-any-unicode-next-line
|
|
1093
|
+
litellmStatus = '⚫ Not running';
|
|
1094
|
+
}
|
|
1095
|
+
const message = [
|
|
1096
|
+
`LiteLLM: ${litellmStatus}`,
|
|
1097
|
+
`OTEL: ${otelStatus}`,
|
|
1098
|
+
].join('\n\n');
|
|
1099
|
+
const lifecycleAction = (0, lifecycle_1.getSpotlightLifecycleAction)(stackStatus);
|
|
1100
|
+
const installAction = (0, lifecycle_1.getSpotlightInstallAction)(await this.isAnalyticsConfigured());
|
|
1101
|
+
const action = await vscode.window.showInformationMessage(`${message}`, 'Config', installAction, lifecycleAction);
|
|
1102
|
+
switch (action) {
|
|
1103
|
+
case 'Start':
|
|
1104
|
+
await this.start();
|
|
1105
|
+
break;
|
|
1106
|
+
case 'Stop':
|
|
1107
|
+
await this.stop();
|
|
1108
|
+
break;
|
|
1109
|
+
case 'Config':
|
|
1110
|
+
await this.openLiteLLMConfig();
|
|
1111
|
+
break;
|
|
1112
|
+
case 'Restart All':
|
|
1113
|
+
await this.restart();
|
|
1114
|
+
break;
|
|
1115
|
+
case 'Install':
|
|
1116
|
+
if (process.platform === 'win32') {
|
|
1117
|
+
await this.setupWindowsSpotlight({ reinstall: false });
|
|
1118
|
+
}
|
|
1119
|
+
else {
|
|
1120
|
+
await vscode.commands.executeCommand('agentide.setupAnalytics');
|
|
1121
|
+
}
|
|
1122
|
+
break;
|
|
1123
|
+
case 'Reinstall':
|
|
1124
|
+
if (process.platform === 'win32') {
|
|
1125
|
+
await this.setupWindowsSpotlight({ reinstall: true });
|
|
1126
|
+
}
|
|
1127
|
+
else {
|
|
1128
|
+
await vscode.commands.executeCommand('agentide.setupAnalytics');
|
|
1129
|
+
}
|
|
1130
|
+
break;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
async openLiteLLMConfig() {
|
|
1134
|
+
const configPath = path.join((0, index_1.getAgentideHome)(), 'litellm-otel.yaml');
|
|
1135
|
+
try {
|
|
1136
|
+
await fs_1.promises.access(configPath);
|
|
1137
|
+
}
|
|
1138
|
+
catch {
|
|
1139
|
+
const choice = await vscode.window.showWarningMessage(`${branding_1.AGENTIDE_BRAND_NAME}: LiteLLM OTEL config not found.`, 'Install');
|
|
1140
|
+
if (choice === 'Install') {
|
|
1141
|
+
await vscode.commands.executeCommand('agentide.setupAnalytics');
|
|
1142
|
+
}
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
const doc = await vscode.workspace.openTextDocument(configPath);
|
|
1146
|
+
await vscode.window.showTextDocument(doc);
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Open a terminal with analytics query commands.
|
|
1150
|
+
* Shows the latest session info by default.
|
|
1151
|
+
*/
|
|
1152
|
+
async openQueryTerminal() {
|
|
1153
|
+
const scriptPath = await this.findScript('query-analytics.sh');
|
|
1154
|
+
if (!scriptPath) {
|
|
1155
|
+
vscode.window.showErrorMessage(`${branding_1.AGENTIDE_BRAND_NAME}: Query script not found. Run 'Setup Analytics' first.`);
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
// Show latest session info by default - includes chat history and costs
|
|
1159
|
+
// Keep terminal open so user can see the output
|
|
1160
|
+
const terminal = this.createScriptTerminal('Spotlight Query', scriptPath, '--latest-session', true);
|
|
1161
|
+
terminal.show();
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Find a script in the extension bundle or source directory.
|
|
1165
|
+
*/
|
|
1166
|
+
async findScript(scriptName) {
|
|
1167
|
+
const extensionPath = this.extensionContext.extensionPath;
|
|
1168
|
+
// Try bundled location first
|
|
1169
|
+
const bundledPath = path.join(extensionPath, 'out', 'scripts', 'analytics', scriptName);
|
|
1170
|
+
try {
|
|
1171
|
+
await fs_1.promises.access(bundledPath);
|
|
1172
|
+
return bundledPath;
|
|
1173
|
+
}
|
|
1174
|
+
catch {
|
|
1175
|
+
// Not in bundled location
|
|
1176
|
+
}
|
|
1177
|
+
// Try development location
|
|
1178
|
+
const devPath = path.join(extensionPath, 'scripts', 'analytics', scriptName);
|
|
1179
|
+
try {
|
|
1180
|
+
await fs_1.promises.access(devPath);
|
|
1181
|
+
return devPath;
|
|
1182
|
+
}
|
|
1183
|
+
catch {
|
|
1184
|
+
// Not in dev location
|
|
1185
|
+
}
|
|
1186
|
+
return null;
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Update the status bar item.
|
|
1190
|
+
*/
|
|
1191
|
+
updateStatusBar(status) {
|
|
1192
|
+
this._status = status;
|
|
1193
|
+
let tooltip;
|
|
1194
|
+
// Use different icons and colors based on status
|
|
1195
|
+
switch (status) {
|
|
1196
|
+
case 'running':
|
|
1197
|
+
this.statusBarItem.text = '$(pulse) Spotlight';
|
|
1198
|
+
tooltip = 'Spotlight: Running (OTEL + LiteLLM configured)';
|
|
1199
|
+
this.statusBarItem.color = new vscode.ThemeColor('testing.iconPassed'); // Green
|
|
1200
|
+
this.statusBarItem.backgroundColor = undefined;
|
|
1201
|
+
break;
|
|
1202
|
+
case 'partial':
|
|
1203
|
+
this.statusBarItem.text = '$(pulse) Spotlight';
|
|
1204
|
+
tooltip = 'Spotlight: Partial (click to configure)';
|
|
1205
|
+
this.statusBarItem.color = new vscode.ThemeColor('editorWarning.foreground'); // Yellow
|
|
1206
|
+
this.statusBarItem.backgroundColor = undefined;
|
|
1207
|
+
break;
|
|
1208
|
+
case 'stopped':
|
|
1209
|
+
this.statusBarItem.text = '$(pulse) Spotlight';
|
|
1210
|
+
tooltip = 'Spotlight: Stopped (click to start)';
|
|
1211
|
+
this.statusBarItem.color = undefined;
|
|
1212
|
+
this.statusBarItem.backgroundColor = undefined;
|
|
1213
|
+
break;
|
|
1214
|
+
case 'checking':
|
|
1215
|
+
this.statusBarItem.text = '$(sync~spin) Spotlight';
|
|
1216
|
+
tooltip = 'Spotlight: Checking...';
|
|
1217
|
+
this.statusBarItem.color = undefined;
|
|
1218
|
+
this.statusBarItem.backgroundColor = undefined;
|
|
1219
|
+
break;
|
|
1220
|
+
case 'error':
|
|
1221
|
+
this.statusBarItem.text = '$(warning) Spotlight';
|
|
1222
|
+
tooltip = 'Spotlight: Error (click to retry)';
|
|
1223
|
+
this.statusBarItem.color = new vscode.ThemeColor('errorForeground');
|
|
1224
|
+
this.statusBarItem.backgroundColor = undefined;
|
|
1225
|
+
break;
|
|
1226
|
+
}
|
|
1227
|
+
if (this.indexProgress.status === 'indexing') {
|
|
1228
|
+
tooltip += `\n\nBackground analytics indexing is running (${this.indexProgress.percent}% complete). Charts may use JSONL fallback until indexing finishes.`;
|
|
1229
|
+
}
|
|
1230
|
+
this.statusBarItem.tooltip = tooltip;
|
|
1231
|
+
this.statusBarItem.show();
|
|
1232
|
+
}
|
|
1233
|
+
log(message) {
|
|
1234
|
+
this.outputChannel.appendLine(`[Analytics] ${message}`);
|
|
1235
|
+
}
|
|
1236
|
+
/**
|
|
1237
|
+
* Create a terminal that runs a command directly via shellArgs.
|
|
1238
|
+
* This avoids the sendText character-dropping issue.
|
|
1239
|
+
*/
|
|
1240
|
+
createScriptTerminal(name, scriptPath, args, keepOpen = false) {
|
|
1241
|
+
const agentHomeDir = (0, index_1.getAgentideHome)();
|
|
1242
|
+
if (keepOpen) {
|
|
1243
|
+
// Run the script, then drop into an interactive shell
|
|
1244
|
+
// Uses the same shellPath/shellArgs approach as Setup Analytics to avoid sendText issues
|
|
1245
|
+
// Echo the command first so user can see what's running
|
|
1246
|
+
const cmd = `"${scriptPath}" ${args}`;
|
|
1247
|
+
return vscode.window.createTerminal({
|
|
1248
|
+
name,
|
|
1249
|
+
cwd: path.dirname(scriptPath),
|
|
1250
|
+
env: {
|
|
1251
|
+
AGENT_HOME_DIR: agentHomeDir,
|
|
1252
|
+
},
|
|
1253
|
+
shellPath: '/bin/bash',
|
|
1254
|
+
shellArgs: ['-c', `echo '$ ${cmd}'; echo ''; ${cmd}; echo ''; exec bash -l`],
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
// For non-keepOpen, use bash -c for a one-shot command
|
|
1258
|
+
return vscode.window.createTerminal({
|
|
1259
|
+
name,
|
|
1260
|
+
cwd: path.dirname(scriptPath),
|
|
1261
|
+
env: {
|
|
1262
|
+
AGENT_HOME_DIR: agentHomeDir,
|
|
1263
|
+
},
|
|
1264
|
+
shellPath: '/bin/bash',
|
|
1265
|
+
shellArgs: ['-c', `"${scriptPath}" ${args}`],
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
dispose() {
|
|
1269
|
+
if (this.healthCheckTimer) {
|
|
1270
|
+
clearInterval(this.healthCheckTimer);
|
|
1271
|
+
this.healthCheckTimer = null;
|
|
1272
|
+
}
|
|
1273
|
+
this.statusBarItem.dispose();
|
|
1274
|
+
for (const d of this.disposables) {
|
|
1275
|
+
d.dispose();
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
exports.AnalyticsService = AnalyticsService;
|