@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,954 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* Copyright (c) AgentHippo.ai. All rights reserved. */
|
|
3
|
+
/* Data contract for fleet.json: extensions/agentide/src/analytics/dashboard/FLEET_DATA_CONTRACT.md */
|
|
4
|
+
/* eslint-disable no-console */
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
const EXPORT_FILE = 'fleet.json';
|
|
9
|
+
const LEGACY_EXPORT_FILE = 'agent-fleet.json';
|
|
10
|
+
const OUTPUT_HTML = 'agent-fleet.html';
|
|
11
|
+
const OUTPUT_CSV = 'agent-fleet.csv';
|
|
12
|
+
|
|
13
|
+
function safeNumber(value) {
|
|
14
|
+
const num = Number(value);
|
|
15
|
+
return Number.isFinite(num) ? num : 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function resolveFleetExportPath(exportDir) {
|
|
19
|
+
const primary = path.join(exportDir, EXPORT_FILE);
|
|
20
|
+
if (fs.existsSync(primary)) {
|
|
21
|
+
return primary;
|
|
22
|
+
}
|
|
23
|
+
const legacy = path.join(exportDir, LEGACY_EXPORT_FILE);
|
|
24
|
+
return fs.existsSync(legacy) ? legacy : primary;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function readFleetExport(exportDir) {
|
|
28
|
+
const exportPath = resolveFleetExportPath(exportDir);
|
|
29
|
+
try {
|
|
30
|
+
fs.mkdirSync(exportDir, { recursive: true });
|
|
31
|
+
const raw = fs.readFileSync(exportPath, 'utf8');
|
|
32
|
+
const parsed = JSON.parse(raw);
|
|
33
|
+
const sessions = Array.isArray(parsed?.sessions) ? parsed.sessions : [];
|
|
34
|
+
return {
|
|
35
|
+
ok: true,
|
|
36
|
+
exportPath,
|
|
37
|
+
payload: {
|
|
38
|
+
generatedAt: parsed?.generatedAt || '',
|
|
39
|
+
totals: parsed?.totals || {},
|
|
40
|
+
sessions,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
} catch (error) {
|
|
44
|
+
// Missing file (ENOENT) = no data yet; return empty payload so dashboard still renders
|
|
45
|
+
const isEnoent = error && (error.code === 'ENOENT' || (error.message && error.message.includes('ENOENT')));
|
|
46
|
+
return {
|
|
47
|
+
ok: isEnoent,
|
|
48
|
+
exportPath,
|
|
49
|
+
error: error instanceof Error ? error.message : String(error),
|
|
50
|
+
payload: {
|
|
51
|
+
generatedAt: new Date().toISOString(),
|
|
52
|
+
totals: { sessions: 0, activeAgents: 0, inProgress: 0, scheduled: 0, done: 0, tokens: 0, turns: 0 },
|
|
53
|
+
sessions: [],
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function statusRank(status) {
|
|
60
|
+
if (status === 'in_progress') return 0;
|
|
61
|
+
if (status === 'scheduled') return 1;
|
|
62
|
+
if (status === 'done') return 2;
|
|
63
|
+
return 3;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function inferFleetEngineId(model, engine) {
|
|
67
|
+
const engineTrim = String(engine || '').trim();
|
|
68
|
+
if (engineTrim) return engineTrim;
|
|
69
|
+
const raw = String(model || '').trim().toLowerCase();
|
|
70
|
+
if (!raw || raw === 'unknown' || raw === 'scheduled') return '';
|
|
71
|
+
if (raw.includes('cursor')) return 'cursor';
|
|
72
|
+
if (raw.includes('codex') || raw.includes('openai-codex')) return 'codex';
|
|
73
|
+
if (raw.includes('claude')) return 'claude';
|
|
74
|
+
if (raw.includes('grok')) return 'grok';
|
|
75
|
+
if (raw.includes('openclaw')) return 'openclaw';
|
|
76
|
+
if (raw.startsWith('agentide-litellm::')) return '';
|
|
77
|
+
if (raw.startsWith('agentide-')) {
|
|
78
|
+
const vendor = raw.slice('agentide-'.length).split('::')[0];
|
|
79
|
+
if (vendor && vendor !== 'litellm' && vendor !== 'unknown') return vendor;
|
|
80
|
+
}
|
|
81
|
+
return '';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function formatFleetModelLabel(model, engine) {
|
|
85
|
+
const raw = String(model || '').trim();
|
|
86
|
+
if (!raw || raw === 'unknown' || raw === 'scheduled') {
|
|
87
|
+
const engineId = inferFleetEngineId('', engine);
|
|
88
|
+
if (engineId === 'cursor') return 'Cursor Auto';
|
|
89
|
+
if (engineId) return engineId.charAt(0).toUpperCase() + engineId.slice(1);
|
|
90
|
+
return '—';
|
|
91
|
+
}
|
|
92
|
+
if (raw.startsWith('agentide-cursor::')) {
|
|
93
|
+
const tail = raw.slice('agentide-cursor::'.length).trim() || 'auto';
|
|
94
|
+
return tail === 'auto' ? 'Cursor Auto' : ('Cursor ' + tail);
|
|
95
|
+
}
|
|
96
|
+
if (raw.startsWith('agentide-')) {
|
|
97
|
+
const inner = raw.slice('agentide-'.length);
|
|
98
|
+
const sep = inner.indexOf('::');
|
|
99
|
+
if (sep >= 0) {
|
|
100
|
+
const tail = inner.slice(sep + 2);
|
|
101
|
+
if (tail) return tail;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return raw;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function formatFleetEngineLabel(model, engine) {
|
|
108
|
+
const engineId = inferFleetEngineId(model, engine);
|
|
109
|
+
if (!engineId) return '—';
|
|
110
|
+
return engineId.charAt(0).toUpperCase() + engineId.slice(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function enrichFleetSessionDisplay(session) {
|
|
114
|
+
if (!session || typeof session !== 'object') {
|
|
115
|
+
return session;
|
|
116
|
+
}
|
|
117
|
+
const model = String(session.model || '').trim();
|
|
118
|
+
const engine = String(session.engine || '').trim();
|
|
119
|
+
const title = String(session.taskTitle || session.cardTitle || '').toLowerCase();
|
|
120
|
+
if ((!model || model === 'unknown' || model === 'scheduled') && title.includes('cursor')) {
|
|
121
|
+
session.model = 'agentide-cursor::auto';
|
|
122
|
+
session.engine = engine || 'cursor';
|
|
123
|
+
} else if ((!model || model === 'unknown' || model === 'scheduled') && title.includes('codex')) {
|
|
124
|
+
session.engine = engine || 'codex';
|
|
125
|
+
} else if ((!model || model === 'unknown' || model === 'scheduled') && title.includes('claude')) {
|
|
126
|
+
session.engine = engine || 'claude';
|
|
127
|
+
}
|
|
128
|
+
if (!String(session.engine || '').trim()) {
|
|
129
|
+
if (title.includes('cursor')) {
|
|
130
|
+
session.engine = 'cursor';
|
|
131
|
+
} else if (title.includes('codex')) {
|
|
132
|
+
session.engine = 'codex';
|
|
133
|
+
} else if (title.includes('claude')) {
|
|
134
|
+
session.engine = 'claude';
|
|
135
|
+
} else {
|
|
136
|
+
session.engine = inferFleetEngineId(session.model, session.engine);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return session;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function telemetryPillsHtml(session) {
|
|
143
|
+
const tokens = Number(session.totalTokens || 0);
|
|
144
|
+
const turns = Number(session.turns || 0);
|
|
145
|
+
if (tokens > 0) {
|
|
146
|
+
const tokenClass = tokens > 500000 ? 'pill alert' : 'pill';
|
|
147
|
+
const turnClass = turns > 100 ? 'pill alert' : 'pill';
|
|
148
|
+
return '<span class="' + tokenClass + '">' + tokens.toLocaleString() + ' Tokens</span>' +
|
|
149
|
+
'<span class="' + turnClass + '">' + turns.toLocaleString() + ' Turns</span>';
|
|
150
|
+
}
|
|
151
|
+
if (turns > 0) {
|
|
152
|
+
return '<span class="pill">Ran ' + turns.toLocaleString() + ' time' + (turns === 1 ? '' : 's') + '</span>';
|
|
153
|
+
}
|
|
154
|
+
return '';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function escapeHtml(value) {
|
|
158
|
+
return String(value ?? '')
|
|
159
|
+
.replaceAll('&', '&')
|
|
160
|
+
.replaceAll('<', '<')
|
|
161
|
+
.replaceAll('>', '>')
|
|
162
|
+
.replaceAll('"', '"')
|
|
163
|
+
.replaceAll("'", ''');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function writeIfChanged(filePath, content) {
|
|
167
|
+
try {
|
|
168
|
+
const existing = fs.readFileSync(filePath, 'utf8');
|
|
169
|
+
if (existing === content) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
} catch (error) {
|
|
173
|
+
// ENOENT = first write; proceed.
|
|
174
|
+
}
|
|
175
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function writeCsv(exportDir, sessions) {
|
|
180
|
+
const rows = [
|
|
181
|
+
['session_id', 'agent_id', 'status', 'started_at', 'ended_at', 'tokens', 'turns', 'model', 'channel_type', 'channel_target', 'agent_pack', 'engine'],
|
|
182
|
+
...sessions.map((session) => [
|
|
183
|
+
session.sessionId || '',
|
|
184
|
+
session.agentId || '',
|
|
185
|
+
session.status || '',
|
|
186
|
+
session.startedAt || '',
|
|
187
|
+
session.endedAt || '',
|
|
188
|
+
String(safeNumber(session.totalTokens)),
|
|
189
|
+
String(safeNumber(session.turns)),
|
|
190
|
+
session.model || 'unknown',
|
|
191
|
+
session.channelType || 'none',
|
|
192
|
+
session.channelTarget || '',
|
|
193
|
+
session.agentPack || '',
|
|
194
|
+
session.engine || '',
|
|
195
|
+
]),
|
|
196
|
+
];
|
|
197
|
+
const content = rows
|
|
198
|
+
.map((columns) => columns
|
|
199
|
+
.map((cell) => `"${String(cell).replaceAll('"', '""')}"`)
|
|
200
|
+
.join(','))
|
|
201
|
+
.join('\n');
|
|
202
|
+
return writeIfChanged(path.join(exportDir, OUTPUT_CSV), `${content}\n`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function buildHtml(data, diagnostics) {
|
|
206
|
+
const payloadJson = JSON.stringify(data);
|
|
207
|
+
const diagnosticsJson = JSON.stringify(diagnostics);
|
|
208
|
+
return `<!doctype html>
|
|
209
|
+
<html>
|
|
210
|
+
<head>
|
|
211
|
+
<meta charset="utf-8" />
|
|
212
|
+
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
213
|
+
<title>Agent Hippo – Fleet Operations</title>
|
|
214
|
+
<style>
|
|
215
|
+
:root { color-scheme: dark; --bg: #0b1020; --surface: #11182b; --border: #1f2f4a; --muted: #94a3b8; --text: #e2e8f0; }
|
|
216
|
+
* { box-sizing: border-box; }
|
|
217
|
+
body { margin: 0; background: var(--bg); color: var(--text); font: 12px/1.5 ui-sans-serif, system-ui; }
|
|
218
|
+
#fleet-summary-bar {
|
|
219
|
+
position: sticky; top: 0; z-index: 10;
|
|
220
|
+
display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px;
|
|
221
|
+
padding: 10px 12px; background: #0f172a; border-bottom: 1px solid var(--border);
|
|
222
|
+
}
|
|
223
|
+
.fleet-kpi { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; }
|
|
224
|
+
.fleet-kpi .label { color: var(--muted); font-size: 10px; text-transform: uppercase; letter-spacing: .05em; }
|
|
225
|
+
.fleet-kpi .value { font-size: 16px; font-weight: 700; }
|
|
226
|
+
.fleet-kpi.active .value { color: #4ade80; }
|
|
227
|
+
.fleet-kpi.scheduled .value { color: #60a5fa; }
|
|
228
|
+
.fleet-kpi.done .value { color: var(--muted); }
|
|
229
|
+
#control-bar {
|
|
230
|
+
display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 8px 12px;
|
|
231
|
+
background: var(--surface); border-bottom: 1px solid var(--border);
|
|
232
|
+
}
|
|
233
|
+
#control-bar select, #control-bar input { background: #0f172a; color: var(--text); border: 1px solid #334155; border-radius: 6px; padding: 5px 8px; font-size: 12px; }
|
|
234
|
+
#control-bar .control-group { display: flex; align-items: center; gap: 6px; }
|
|
235
|
+
#control-bar .control-group label { color: var(--muted); font-size: 11px; }
|
|
236
|
+
#control-bar .last-updated { color: var(--muted); font-size: 11px; margin-left: auto; }
|
|
237
|
+
#fleet-canvas { display: flex; flex-direction: column; gap: 16px; padding: 12px; min-height: 200px; }
|
|
238
|
+
.swimlane { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
|
|
239
|
+
.swimlane.hidden-by-filter { display: none; }
|
|
240
|
+
.swimlane-header { display: flex; align-items: center; gap: 6px; cursor: pointer; padding: 4px 0; user-select: none; }
|
|
241
|
+
.swimlane-header:hover { opacity: .9; }
|
|
242
|
+
.row-toggle { width: 18px; height: 18px; display: flex; align-items: center; justify-content: center; font-size: 10px; color: var(--muted); flex-shrink: 0; }
|
|
243
|
+
.swimlane.collapsed .row-toggle::before { content: '▶'; }
|
|
244
|
+
.swimlane:not(.collapsed) .row-toggle::before { content: '▼'; }
|
|
245
|
+
.swimlane-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); margin: 0; }
|
|
246
|
+
.swimlane.active .swimlane-title { color: #4ade80; }
|
|
247
|
+
.swimlane.scheduled .swimlane-title { color: #60a5fa; }
|
|
248
|
+
.swimlane.done .swimlane-title { color: var(--muted); }
|
|
249
|
+
.swimlane-cards { display: flex; flex-direction: row; flex-wrap: wrap; gap: 8px; }
|
|
250
|
+
.swimlane.collapsed .swimlane-cards { display: none; }
|
|
251
|
+
.agent-card {
|
|
252
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 10px;
|
|
253
|
+
cursor: pointer; transition: border-color .15s, box-shadow .15s;
|
|
254
|
+
min-width: 260px; max-width: 320px; flex: 1 1 260px;
|
|
255
|
+
}
|
|
256
|
+
.agent-card:hover { border-color: #334155; box-shadow: 0 2px 8px rgba(0,0,0,.2); }
|
|
257
|
+
.agent-card .card-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
|
|
258
|
+
.agent-card .card-header-left { display: flex; align-items: center; gap: 6px; min-width: 0; }
|
|
259
|
+
.status-badge { font-size: 10px; border-radius: 999px; padding: 2px 8px; font-weight: 600; flex-shrink: 0; }
|
|
260
|
+
.status-badge.in_progress { background: rgba(74, 222, 128, .2); color: #4ade80; border: 1px solid #22c55e; }
|
|
261
|
+
.status-badge.in_progress.pulse { animation: pulse 1.5s ease-in-out infinite; }
|
|
262
|
+
.status-badge.scheduled { background: rgba(96, 165, 250, .2); color: #60a5fa; border: 1px solid #3b82f6; }
|
|
263
|
+
.status-badge.done { background: rgba(148, 163, 184, .15); color: var(--muted); border: 1px solid #475569; }
|
|
264
|
+
@keyframes pulse { 50% { opacity: .85; } }
|
|
265
|
+
.task-title { font-weight: 700; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
266
|
+
.task-title[data-edit-title] { cursor: text; }
|
|
267
|
+
.title-editor {
|
|
268
|
+
font: inherit;
|
|
269
|
+
font-weight: 700;
|
|
270
|
+
font-size: 13px;
|
|
271
|
+
width: 100%;
|
|
272
|
+
min-width: 120px;
|
|
273
|
+
max-width: 220px;
|
|
274
|
+
background: #0f172a;
|
|
275
|
+
color: var(--text);
|
|
276
|
+
border: 1px solid #334155;
|
|
277
|
+
border-radius: 6px;
|
|
278
|
+
padding: 2px 6px;
|
|
279
|
+
outline: none;
|
|
280
|
+
}
|
|
281
|
+
.title-editor:focus { border-color: var(--muted); }
|
|
282
|
+
.connection-icon { width: 24px; height: 24px; flex-shrink: 0; border-radius: 6px; display: flex; align-items: center; justify-content: center; font-size: 12px; background: #1e293b; color: var(--muted); }
|
|
283
|
+
.connection-icon.whatsapp { background: rgba(37, 211, 102, .2); color: #25d366; }
|
|
284
|
+
.connection-icon.telegram { background: rgba(0, 136, 204, .2); color: #0088cc; }
|
|
285
|
+
.agent-card .card-body { margin-bottom: 8px; }
|
|
286
|
+
.start-time { font-size: 11px; color: var(--muted); margin-bottom: 6px; }
|
|
287
|
+
.telemetry-pills { display: flex; gap: 6px; flex-wrap: wrap; }
|
|
288
|
+
.pill { font-size: 10px; border-radius: 999px; padding: 2px 8px; background: #1e293b; color: #cbd5e1; border: 1px solid #334155; }
|
|
289
|
+
.pill.alert { background: rgba(239, 68, 68, .15); color: #f87171; border-color: #dc2626; }
|
|
290
|
+
.agent-card .card-footer { border-top: 1px solid var(--border); padding-top: 8px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px; }
|
|
291
|
+
.stack-tags { font-size: 10px; color: var(--muted); }
|
|
292
|
+
.stack-tags span { margin-right: 8px; }
|
|
293
|
+
.action-area { flex-shrink: 0; }
|
|
294
|
+
.btn-disconnect { background: transparent; color: var(--muted); border: none; padding: 4px 6px; cursor: pointer; font-size: 11px; text-decoration: underline; }
|
|
295
|
+
.btn-disconnect:hover { color: #f87171; }
|
|
296
|
+
.btn-disconnect:disabled { opacity: .5; cursor: not-allowed; }
|
|
297
|
+
.empty-lane { color: var(--muted); font-size: 12px; padding: 16px; border: 1px dashed var(--border); border-radius: 8px; text-align: center; }
|
|
298
|
+
#msg { margin: 0 12px 12px; color: #93c5fd; min-height: 14px; font-size: 11px; }
|
|
299
|
+
</style>
|
|
300
|
+
</head>
|
|
301
|
+
<body data-fleet-snapshot-shell="1">
|
|
302
|
+
<div id="fleet-summary-bar">
|
|
303
|
+
<div class="fleet-kpi active"><div class="label">Active Agents</div><div class="value" id="kpi-active">0</div></div>
|
|
304
|
+
<div class="fleet-kpi scheduled"><div class="label">Scheduled</div><div class="value" id="kpi-scheduled">0</div></div>
|
|
305
|
+
<div class="fleet-kpi done"><div class="label">Done (24h)</div><div class="value" id="kpi-done">0</div></div>
|
|
306
|
+
<div class="fleet-kpi"><div class="label">Total Tokens</div><div class="value" id="kpi-tokens">0</div></div>
|
|
307
|
+
<div class="fleet-kpi"><div class="label">Total Turns</div><div class="value" id="kpi-turns">0</div></div>
|
|
308
|
+
</div>
|
|
309
|
+
<div id="control-bar">
|
|
310
|
+
<input id="search" type="search" placeholder="Search sessions..." />
|
|
311
|
+
<span class="last-updated" id="last-updated"></span>
|
|
312
|
+
</div>
|
|
313
|
+
<div id="fleet-canvas">
|
|
314
|
+
<div class="swimlane active" data-lane="in_progress">
|
|
315
|
+
<div class="swimlane-header"><span class="row-toggle" aria-hidden="true"></span><span class="swimlane-title">In Progress</span></div>
|
|
316
|
+
<div class="swimlane-cards" id="lane-in_progress"></div>
|
|
317
|
+
</div>
|
|
318
|
+
<div class="swimlane scheduled" data-lane="scheduled">
|
|
319
|
+
<div class="swimlane-header"><span class="row-toggle" aria-hidden="true"></span><span class="swimlane-title">Scheduled</span></div>
|
|
320
|
+
<div class="swimlane-cards" id="lane-scheduled"></div>
|
|
321
|
+
</div>
|
|
322
|
+
<div class="swimlane done" data-lane="done">
|
|
323
|
+
<div class="swimlane-header"><span class="row-toggle" aria-hidden="true"></span><span class="swimlane-title">Done (Last 24h)</span></div>
|
|
324
|
+
<div class="swimlane-cards" id="lane-done"></div>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
<div id="msg"></div>
|
|
328
|
+
<script>
|
|
329
|
+
const payload = ${payloadJson};
|
|
330
|
+
const diagnostics = ${diagnosticsJson};
|
|
331
|
+
const esc = (v) => String(v ?? '').replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
|
|
332
|
+
const statusRank = (s) => s === 'in_progress' ? 0 : s === 'scheduled' ? 1 : s === 'done' ? 2 : 3;
|
|
333
|
+
function inferFleetEngineId(model, engine) {
|
|
334
|
+
const e = String(engine || '').trim().toLowerCase();
|
|
335
|
+
if (e && e !== 'unknown') return e;
|
|
336
|
+
const m = String(model || '').trim().toLowerCase();
|
|
337
|
+
if (m.startsWith('agentide-cursor') || m.includes('cursor')) return 'cursor';
|
|
338
|
+
if (m.startsWith('agentide-codex') || m.includes('codex')) return 'codex';
|
|
339
|
+
if (m.includes('claude')) return 'claude';
|
|
340
|
+
if (m.includes('gemini')) return 'gemini';
|
|
341
|
+
if (m.includes('grok')) return 'grok';
|
|
342
|
+
if (m.startsWith('agentide-litellm::')) return '';
|
|
343
|
+
const raw = m || e;
|
|
344
|
+
const parts = raw.split(/[:/]/);
|
|
345
|
+
const tail = parts[0] || '';
|
|
346
|
+
if (tail) return tail;
|
|
347
|
+
return '';
|
|
348
|
+
}
|
|
349
|
+
function formatFleetModelLabel(model, engine) {
|
|
350
|
+
const m = String(model || '').trim();
|
|
351
|
+
if (!m || m === 'unknown' || m === 'scheduled') {
|
|
352
|
+
const engineId = inferFleetEngineId('', engine);
|
|
353
|
+
if (!engineId) return '—';
|
|
354
|
+
return engineId.charAt(0).toUpperCase() + engineId.slice(1) + ' (inferred)';
|
|
355
|
+
}
|
|
356
|
+
if (m.startsWith('agentide-cursor::')) return 'Cursor ' + (m.split('::')[1] || 'Auto').replace(/^\w/, c => c.toUpperCase());
|
|
357
|
+
if (m.startsWith('agentide-litellm::')) return m.slice('agentide-litellm::'.length) || m;
|
|
358
|
+
return m;
|
|
359
|
+
}
|
|
360
|
+
function formatFleetEngineLabel(model, engine) {
|
|
361
|
+
const engineId = inferFleetEngineId(model, engine);
|
|
362
|
+
if (!engineId) return '—';
|
|
363
|
+
return engineId.charAt(0).toUpperCase() + engineId.slice(1);
|
|
364
|
+
}
|
|
365
|
+
function enrichFleetSessionDisplay(session) {
|
|
366
|
+
if (!session || typeof session !== 'object') return session;
|
|
367
|
+
const model = String(session.model || '').trim();
|
|
368
|
+
const engine = String(session.engine || '').trim();
|
|
369
|
+
const title = String(session.taskTitle || session.cardTitle || '').toLowerCase();
|
|
370
|
+
if ((!model || model === 'unknown' || model === 'scheduled') && title.includes('cursor')) {
|
|
371
|
+
session.model = 'agentide-cursor::auto';
|
|
372
|
+
session.engine = engine || 'cursor';
|
|
373
|
+
} else if ((!model || model === 'unknown' || model === 'scheduled') && title.includes('codex')) {
|
|
374
|
+
session.engine = engine || 'codex';
|
|
375
|
+
} else if ((!model || model === 'unknown' || model === 'scheduled') && title.includes('claude')) {
|
|
376
|
+
session.engine = engine || 'claude';
|
|
377
|
+
}
|
|
378
|
+
if (!String(session.engine || '').trim()) {
|
|
379
|
+
if (title.includes('cursor')) {
|
|
380
|
+
session.engine = 'cursor';
|
|
381
|
+
} else if (title.includes('codex')) {
|
|
382
|
+
session.engine = 'codex';
|
|
383
|
+
} else if (title.includes('claude')) {
|
|
384
|
+
session.engine = 'claude';
|
|
385
|
+
} else {
|
|
386
|
+
session.engine = inferFleetEngineId(session.model, session.engine);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return session;
|
|
390
|
+
}
|
|
391
|
+
function telemetryPillsHtml(session) {
|
|
392
|
+
const tokens = Number(session.totalTokens || 0);
|
|
393
|
+
const turns = Number(session.turns || 0);
|
|
394
|
+
const tokenClass = tokens > 500000 ? 'pill alert' : 'pill';
|
|
395
|
+
const turnClass = turns > 100 ? 'pill alert' : 'pill';
|
|
396
|
+
if (tokens > 0) {
|
|
397
|
+
return '<span class="' + tokenClass + '">' + tokens.toLocaleString() + ' Tokens</span>' +
|
|
398
|
+
'<span class="' + turnClass + '">' + turns.toLocaleString() + ' Turns</span>';
|
|
399
|
+
}
|
|
400
|
+
if (turns > 0) {
|
|
401
|
+
return '<span class="' + turnClass + '">Ran ' + turns.toLocaleString() + ' turn' + (turns === 1 ? '' : 's') + '</span>';
|
|
402
|
+
}
|
|
403
|
+
return '';
|
|
404
|
+
}
|
|
405
|
+
let sessions = Array.isArray(payload.sessions)
|
|
406
|
+
? payload.sessions.slice().map((session) => enrichFleetSessionDisplay({ ...session }))
|
|
407
|
+
: [];
|
|
408
|
+
let pendingSessionSnapshot = null;
|
|
409
|
+
function startedMs(session) {
|
|
410
|
+
const t = Date.parse(String(session.startedAt || ''));
|
|
411
|
+
return Number.isFinite(t) ? t : 0;
|
|
412
|
+
}
|
|
413
|
+
function scheduledDistanceMs(session) {
|
|
414
|
+
const t = startedMs(session);
|
|
415
|
+
if (!t) return Number.POSITIVE_INFINITY;
|
|
416
|
+
return Math.abs(t - Date.now());
|
|
417
|
+
}
|
|
418
|
+
function compareSessionsForLane(lane, a, b) {
|
|
419
|
+
if (lane === 'scheduled') {
|
|
420
|
+
const distance = scheduledDistanceMs(a) - scheduledDistanceMs(b);
|
|
421
|
+
if (distance !== 0) return distance;
|
|
422
|
+
return startedMs(a) - startedMs(b);
|
|
423
|
+
}
|
|
424
|
+
const time = startedMs(b) - startedMs(a);
|
|
425
|
+
if (time !== 0) return time;
|
|
426
|
+
return String(a.sessionId || '').localeCompare(String(b.sessionId || ''));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
let fleetTotals = payload.totals || {};
|
|
430
|
+
let fleetGeneratedAt = payload.generatedAt || '';
|
|
431
|
+
let lastUpdatedTimer = null;
|
|
432
|
+
let autoRefreshInFlight = false;
|
|
433
|
+
|
|
434
|
+
function renderSummary() {
|
|
435
|
+
document.getElementById('kpi-active').textContent = Number(fleetTotals.activeAgents ?? fleetTotals.inProgress ?? 0).toLocaleString();
|
|
436
|
+
document.getElementById('kpi-scheduled').textContent = Number(fleetTotals.scheduled ?? 0).toLocaleString();
|
|
437
|
+
document.getElementById('kpi-done').textContent = Number(fleetTotals.done ?? 0).toLocaleString();
|
|
438
|
+
document.getElementById('kpi-tokens').textContent = Number(fleetTotals.tokens ?? 0).toLocaleString();
|
|
439
|
+
document.getElementById('kpi-turns').textContent = Number(fleetTotals.turns ?? 0).toLocaleString();
|
|
440
|
+
if (lastUpdatedTimer) {
|
|
441
|
+
clearInterval(lastUpdatedTimer);
|
|
442
|
+
lastUpdatedTimer = null;
|
|
443
|
+
}
|
|
444
|
+
if (fleetGeneratedAt) {
|
|
445
|
+
const t = new Date(fleetGeneratedAt).getTime();
|
|
446
|
+
function updateLastUpdated() {
|
|
447
|
+
const sec = Math.max(0, Math.floor((Date.now() - t) / 1000));
|
|
448
|
+
const el = document.getElementById('last-updated');
|
|
449
|
+
el.textContent = sec < 60 ? 'Last updated: just now' : sec < 3600 ? 'Last updated: ' + Math.floor(sec / 60) + 'm ago' : 'Last updated: ' + Math.floor(sec / 3600) + 'h ago';
|
|
450
|
+
}
|
|
451
|
+
updateLastUpdated();
|
|
452
|
+
lastUpdatedTimer = setInterval(updateLastUpdated, 60000);
|
|
453
|
+
} else {
|
|
454
|
+
document.getElementById('last-updated').textContent = '';
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
renderSummary();
|
|
458
|
+
|
|
459
|
+
function clearRefreshLoading() {
|
|
460
|
+
autoRefreshInFlight = false;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function assembleChunkedSnapshot(snapshotPayload, meta) {
|
|
464
|
+
if (!meta || meta.chunkedSessions !== true || !Array.isArray(snapshotPayload?.sessions)) {
|
|
465
|
+
return snapshotPayload;
|
|
466
|
+
}
|
|
467
|
+
const snapshotId = String(meta.snapshotId || '');
|
|
468
|
+
const chunkIndex = Number(meta.chunkIndex);
|
|
469
|
+
const chunkCount = Number(meta.chunkCount);
|
|
470
|
+
if (!snapshotId || !Number.isInteger(chunkIndex) || !Number.isInteger(chunkCount) || chunkIndex < 0 || chunkCount <= 0) {
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
if (!pendingSessionSnapshot || pendingSessionSnapshot.id !== snapshotId) {
|
|
474
|
+
pendingSessionSnapshot = {
|
|
475
|
+
id: snapshotId,
|
|
476
|
+
generatedAt: snapshotPayload.generatedAt || '',
|
|
477
|
+
totals: snapshotPayload.totals || {},
|
|
478
|
+
chunkCount,
|
|
479
|
+
chunks: new Array(chunkCount),
|
|
480
|
+
received: 0,
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
if (chunkIndex >= pendingSessionSnapshot.chunkCount) {
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
if (!pendingSessionSnapshot.chunks[chunkIndex]) {
|
|
487
|
+
pendingSessionSnapshot.received += 1;
|
|
488
|
+
}
|
|
489
|
+
pendingSessionSnapshot.chunks[chunkIndex] = snapshotPayload.sessions;
|
|
490
|
+
if (pendingSessionSnapshot.received < pendingSessionSnapshot.chunkCount) {
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
const assembled = {
|
|
494
|
+
generatedAt: pendingSessionSnapshot.generatedAt,
|
|
495
|
+
totals: pendingSessionSnapshot.totals,
|
|
496
|
+
sessions: pendingSessionSnapshot.chunks.flat(),
|
|
497
|
+
};
|
|
498
|
+
pendingSessionSnapshot = null;
|
|
499
|
+
return assembled;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function applySnapshot(snapshotPayload, meta) {
|
|
503
|
+
snapshotPayload = assembleChunkedSnapshot(snapshotPayload, meta);
|
|
504
|
+
if (!snapshotPayload) {
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
if (snapshotPayload && typeof snapshotPayload === 'object') {
|
|
508
|
+
if (Array.isArray(snapshotPayload.sessions)) {
|
|
509
|
+
const incoming = snapshotPayload.sessions;
|
|
510
|
+
// Host may send sessions:[] on read/postMessage failure — keep embedded cards.
|
|
511
|
+
if (incoming.length > 0 || sessions.length === 0) {
|
|
512
|
+
sessions = incoming.slice().map((session) => enrichFleetSessionDisplay({ ...session }));
|
|
513
|
+
}
|
|
514
|
+
} else if (meta && meta.omitSessions && sessions.length > 0) {
|
|
515
|
+
// Large export: host omitted sessions; keep embedded HTML payload.
|
|
516
|
+
}
|
|
517
|
+
if (snapshotPayload.totals && typeof snapshotPayload.totals === 'object') {
|
|
518
|
+
fleetTotals = snapshotPayload.totals;
|
|
519
|
+
}
|
|
520
|
+
if (typeof snapshotPayload.generatedAt === 'string') {
|
|
521
|
+
fleetGeneratedAt = snapshotPayload.generatedAt;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
renderSummary();
|
|
525
|
+
renderLanes();
|
|
526
|
+
clearRefreshLoading();
|
|
527
|
+
const msgEl = document.getElementById('msg');
|
|
528
|
+
if (meta && meta.ok === false && meta.error) {
|
|
529
|
+
msgEl.textContent = 'Fleet export read issue: ' + esc(meta.error);
|
|
530
|
+
} else if (!diagnostics.ok && diagnostics.error) {
|
|
531
|
+
msgEl.textContent = 'Fleet export read issue: ' + esc(diagnostics.error);
|
|
532
|
+
} else {
|
|
533
|
+
msgEl.textContent = '';
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
function requestSnapshot() {
|
|
538
|
+
try {
|
|
539
|
+
window.parent.postMessage({ source: 'agentide-wow-widget', type: 'requestViewExportSnapshot' }, '*');
|
|
540
|
+
} catch (err) {
|
|
541
|
+
// Ignore cross-origin postMessage failures.
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function requestFleetRefresh() {
|
|
546
|
+
if (autoRefreshInFlight) {
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
autoRefreshInFlight = true;
|
|
550
|
+
try {
|
|
551
|
+
window.parent.postMessage({ source: 'agentide-wow-widget', type: 'refreshWidget', script: 'agent-fleet-widget.js' }, '*');
|
|
552
|
+
} catch (err) {
|
|
553
|
+
// Ignore cross-origin postMessage failures.
|
|
554
|
+
}
|
|
555
|
+
requestSnapshot();
|
|
556
|
+
// If the host cannot report completion (e.g. stale extension host), avoid
|
|
557
|
+
// permanently suppressing future refreshes.
|
|
558
|
+
setTimeout(() => clearRefreshLoading(), 25000);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
function formatStartTime(session) {
|
|
563
|
+
const status = String(session.status || '');
|
|
564
|
+
const started = session.startedAt ? new Date(session.startedAt).getTime() : NaN;
|
|
565
|
+
const ended = session.endedAt ? new Date(session.endedAt).getTime() : NaN;
|
|
566
|
+
const now = Date.now();
|
|
567
|
+
if (status === 'scheduled' && Number.isFinite(started) && started > now) {
|
|
568
|
+
const d = new Date(started);
|
|
569
|
+
const today = new Date();
|
|
570
|
+
if (d.toDateString() === today.toDateString()) return 'Scheduled: Today, ' + d.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
|
|
571
|
+
return 'Scheduled: ' + d.toLocaleDateString() + ', ' + d.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
|
|
572
|
+
}
|
|
573
|
+
const lastRun = Number.isFinite(ended) ? ended : started;
|
|
574
|
+
if (Number.isFinite(lastRun)) {
|
|
575
|
+
const min = Math.max(0, Math.floor((now - lastRun) / 60000));
|
|
576
|
+
if (min < 1) return 'Last run: just now';
|
|
577
|
+
if (min < 60) return 'Last run: ' + min + 'm ago';
|
|
578
|
+
if (min < 24 * 60) return 'Last run: ' + Math.floor(min / 60) + 'h ago';
|
|
579
|
+
return 'Last run: ' + new Date(lastRun).toLocaleString();
|
|
580
|
+
}
|
|
581
|
+
return 'Last run: —';
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function connectionIcon(channelType) {
|
|
585
|
+
const ch = String(channelType || 'none').toLowerCase();
|
|
586
|
+
if (ch === 'whatsapp') return '<span class="connection-icon whatsapp" title="WhatsApp">WA</span>';
|
|
587
|
+
if (ch === 'telegram') return '<span class="connection-icon telegram" title="Telegram">TG</span>';
|
|
588
|
+
if (ch !== 'none') return '<span class="connection-icon" title="' + esc(ch) + '">Web</span>';
|
|
589
|
+
return '';
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function filteredSessions() {
|
|
593
|
+
const query = String(document.getElementById('search')?.value || '').trim().toLowerCase();
|
|
594
|
+
return sessions.filter((session) => {
|
|
595
|
+
if (!query) return true;
|
|
596
|
+
const haystack = [session.sessionId, session.agentId, session.taskTitle, session.taskSummary, session.model, session.engine].map(i => String(i || '').toLowerCase()).join(' ');
|
|
597
|
+
return haystack.includes(query);
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function postOpenSpotlight(session) {
|
|
602
|
+
enrichFleetSessionDisplay(session);
|
|
603
|
+
const msg = {
|
|
604
|
+
source: 'agentide-wow-widget',
|
|
605
|
+
type: 'openSpotlightForSession',
|
|
606
|
+
sessionId: String(session.sessionId || ''),
|
|
607
|
+
channelType: String(session.channelType || ''),
|
|
608
|
+
channelTarget: String(session.channelTarget || ''),
|
|
609
|
+
model: String(session.model || ''),
|
|
610
|
+
engine: String(session.engine || inferFleetEngineId(session.model, session.engine)),
|
|
611
|
+
agentId: String(session.agentId || session.agentPack || ''),
|
|
612
|
+
};
|
|
613
|
+
try { window.parent.postMessage(msg, '*'); } catch (e) {}
|
|
614
|
+
if (window.top !== window.parent) { try { window.top.postMessage(msg, '*'); } catch (e) {} }
|
|
615
|
+
}
|
|
616
|
+
function postDisconnect(session, e) {
|
|
617
|
+
e.preventDefault(); e.stopPropagation();
|
|
618
|
+
window.parent.postMessage({ source: 'agentide-wow-widget', type: 'disconnectFleetChannel', sessionId: String(session.sessionId || ''), channelType: String(session.channelType || ''), channelTarget: String(session.channelTarget || '') }, '*');
|
|
619
|
+
document.getElementById('msg').textContent = 'Disconnect requested for ' + esc(session.sessionId || 'session');
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function postToHost(payload) {
|
|
623
|
+
try {
|
|
624
|
+
// Prefer direct webview messaging to the extension host. This bypasses
|
|
625
|
+
// any seeded/older panel.js bridge code and makes title persistence
|
|
626
|
+
// independent from how the outer webview forwards messages.
|
|
627
|
+
const api = typeof acquireVsCodeApi === 'function' ? acquireVsCodeApi() : null;
|
|
628
|
+
if (api && typeof api.postMessage === 'function') {
|
|
629
|
+
api.postMessage(payload);
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
} catch (err) {
|
|
633
|
+
// Fall back to window.parent postMessage below.
|
|
634
|
+
}
|
|
635
|
+
try { window.parent.postMessage(payload, '*'); } catch (err) {}
|
|
636
|
+
if (window.top !== window.parent) { try { window.top.postMessage(payload, '*'); } catch (err) {} }
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Inner HTML for a card body (no outer wrapper). Outer .agent-card element is created/reused
|
|
640
|
+
// by renderCardElement/updateCardElement to enable DOM diffing in syncLaneCards.
|
|
641
|
+
function renderCardInnerHtml(session) {
|
|
642
|
+
enrichFleetSessionDisplay(session);
|
|
643
|
+
const status = String(session.status || 'done');
|
|
644
|
+
const cardTitleRaw = session.cardTitle || session.taskTitle || session.agentId || session.sessionId || 'Task';
|
|
645
|
+
const cardTitle = esc(cardTitleRaw);
|
|
646
|
+
const canDisconnect = String(session.channelType || 'none').toLowerCase() !== 'none';
|
|
647
|
+
const startTimeHtml = formatStartTime(session);
|
|
648
|
+
const model = esc(formatFleetModelLabel(session.model, session.engine));
|
|
649
|
+
const pack = esc(session.agentPack || session.agentId || '—');
|
|
650
|
+
const engine = esc(formatFleetEngineLabel(session.model, session.engine));
|
|
651
|
+
const telemetryHtml = telemetryPillsHtml(session);
|
|
652
|
+
return '<div class="card-header">' +
|
|
653
|
+
'<div class="card-header-left">' +
|
|
654
|
+
'<span class="status-badge ' + esc(status) + (status === 'in_progress' ? ' pulse' : '') + '">' + (status === 'in_progress' ? 'In Progress' : status === 'scheduled' ? 'Scheduled' : 'Done') + '</span>' +
|
|
655
|
+
'<span class="task-title" data-edit-title title="Click to edit title">' + cardTitle + '</span>' +
|
|
656
|
+
'<input class="title-editor" data-title-editor style="display:none" />' +
|
|
657
|
+
'</div>' +
|
|
658
|
+
connectionIcon(session.channelType) +
|
|
659
|
+
'</div>' +
|
|
660
|
+
'<div class="card-body">' +
|
|
661
|
+
'<div class="start-time">' + startTimeHtml + '</div>' +
|
|
662
|
+
'<div class="telemetry-pills">' + telemetryHtml + '</div>' +
|
|
663
|
+
'</div>' +
|
|
664
|
+
'<div class="card-footer">' +
|
|
665
|
+
'<div class="stack-tags"><span>Model: ' + model + '</span><span>Pack: ' + pack + '</span><span>Engine: ' + engine + '</span></div>' +
|
|
666
|
+
'<div class="action-area">' +
|
|
667
|
+
'<button type="button" class="btn-disconnect" ' + (canDisconnect ? '' : 'disabled') + ' data-disconnect>Disconnect Channel</button>' +
|
|
668
|
+
'</div>' +
|
|
669
|
+
'</div>';
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Stable signature: change in any of these fields triggers innerHTML rewrite.
|
|
673
|
+
// Skips rewrite when nothing visible changed (e.g. unrelated session refresh).
|
|
674
|
+
function cardSignature(session) {
|
|
675
|
+
return [
|
|
676
|
+
session.status || '',
|
|
677
|
+
session.cardTitle || session.taskTitle || session.agentId || session.sessionId || '',
|
|
678
|
+
session.totalTokens || 0,
|
|
679
|
+
session.turns || 0,
|
|
680
|
+
session.startedAt || '',
|
|
681
|
+
session.endedAt || '',
|
|
682
|
+
session.model || '',
|
|
683
|
+
session.engine || '',
|
|
684
|
+
session.channelType || '',
|
|
685
|
+
session.agentPack || '',
|
|
686
|
+
].join('|');
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
function renderCardElement(session) {
|
|
690
|
+
const card = document.createElement('div');
|
|
691
|
+
card.className = 'agent-card';
|
|
692
|
+
card.setAttribute('role', 'button');
|
|
693
|
+
card.setAttribute('tabindex', '0');
|
|
694
|
+
card.setAttribute('data-session-id', String(session.sessionId || ''));
|
|
695
|
+
card.setAttribute('data-source-id', String(session.source || ''));
|
|
696
|
+
card.setAttribute('data-sig', cardSignature(session));
|
|
697
|
+
card.innerHTML = renderCardInnerHtml(session);
|
|
698
|
+
return card;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function updateCardElement(card, session) {
|
|
702
|
+
// Don't disrupt an active title edit; the user is typing.
|
|
703
|
+
const editor = card.querySelector('[data-title-editor]');
|
|
704
|
+
if (editor instanceof HTMLInputElement && editor.style.display !== 'none') {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
const newSig = cardSignature(session);
|
|
708
|
+
if (card.getAttribute('data-sig') === newSig) {
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
card.setAttribute('data-sig', newSig);
|
|
712
|
+
card.setAttribute('data-source-id', String(session.source || ''));
|
|
713
|
+
card.innerHTML = renderCardInnerHtml(session);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// DOM diff: reuse card elements where possible (no flicker, preserves focus).
|
|
717
|
+
// Departed sessions are removed; new sessions are appended; surviving sessions are
|
|
718
|
+
// updated in-place; element order is rewritten to match desired sequence.
|
|
719
|
+
function syncLaneCards(container, sessionsList) {
|
|
720
|
+
const wantIds = new Set(sessionsList.map((s) => String(s.sessionId || '')));
|
|
721
|
+
const existingById = new Map();
|
|
722
|
+
container.querySelectorAll('.agent-card[data-session-id]').forEach((card) => {
|
|
723
|
+
existingById.set(card.getAttribute('data-session-id') || '', card);
|
|
724
|
+
});
|
|
725
|
+
for (const [id, card] of existingById) {
|
|
726
|
+
if (!id || !wantIds.has(id)) {
|
|
727
|
+
card.remove();
|
|
728
|
+
existingById.delete(id);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
if (!sessionsList.length) {
|
|
732
|
+
if (!container.querySelector('.empty-lane')) {
|
|
733
|
+
container.innerHTML = '<div class="empty-lane">No agents</div>';
|
|
734
|
+
}
|
|
735
|
+
container.classList.add('lane-empty');
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
container.querySelectorAll('.empty-lane').forEach((el) => el.remove());
|
|
739
|
+
container.classList.remove('lane-empty');
|
|
740
|
+
let anchor = null;
|
|
741
|
+
for (const session of sessionsList) {
|
|
742
|
+
const id = String(session.sessionId || '');
|
|
743
|
+
let card = existingById.get(id);
|
|
744
|
+
if (!card) {
|
|
745
|
+
card = renderCardElement(session);
|
|
746
|
+
} else {
|
|
747
|
+
updateCardElement(card, session);
|
|
748
|
+
}
|
|
749
|
+
const desiredPosition = anchor ? anchor.nextElementSibling : container.firstElementChild;
|
|
750
|
+
if (card !== desiredPosition) {
|
|
751
|
+
container.insertBefore(card, desiredPosition || null);
|
|
752
|
+
}
|
|
753
|
+
anchor = card;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// laneCollapsed: user's explicit collapse choice (toggled by header click only).
|
|
758
|
+
// Empty lanes are visually collapsed but never persist a flag — when items arrive
|
|
759
|
+
// (e.g. a new scheduled task), the lane auto-expands back to the user's setting.
|
|
760
|
+
const laneCollapsed = { in_progress: false, scheduled: false, done: false };
|
|
761
|
+
|
|
762
|
+
function applyRowVisibility() {
|
|
763
|
+
['in_progress', 'scheduled', 'done'].forEach(lane => {
|
|
764
|
+
const row = document.querySelector('.swimlane[data-lane="' + lane + '"]');
|
|
765
|
+
if (!row) return;
|
|
766
|
+
const container = document.getElementById('lane-' + lane);
|
|
767
|
+
const isEmpty = container && container.classList.contains('lane-empty');
|
|
768
|
+
row.classList.toggle('empty', !!isEmpty);
|
|
769
|
+
row.classList.remove('hidden-by-filter');
|
|
770
|
+
// Show collapsed when empty OR user has manually collapsed. Don't mutate
|
|
771
|
+
// laneCollapsed here — that's user state, set only by header click handler.
|
|
772
|
+
row.classList.toggle('collapsed', !!laneCollapsed[lane] || isEmpty);
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
function renderLanes() {
|
|
777
|
+
const items = filteredSessions();
|
|
778
|
+
const byStatus = { in_progress: [], scheduled: [], done: [] };
|
|
779
|
+
items.forEach(s => {
|
|
780
|
+
const st = String(s.status || 'done');
|
|
781
|
+
if (byStatus[st]) byStatus[st].push(s);
|
|
782
|
+
});
|
|
783
|
+
['in_progress', 'scheduled', 'done'].forEach(lane => {
|
|
784
|
+
const container = document.getElementById('lane-' + lane);
|
|
785
|
+
const list = (byStatus[lane] || []).slice().sort((a, b) => compareSessionsForLane(lane, a, b));
|
|
786
|
+
syncLaneCards(container, list);
|
|
787
|
+
});
|
|
788
|
+
applyRowVisibility();
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
function findSessionById(sessionId) {
|
|
792
|
+
if (!sessionId) return undefined;
|
|
793
|
+
return sessions.find((s) => String(s.sessionId || '') === sessionId);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// Single delegated click handler for the canvas: handles lane collapse, card open,
|
|
797
|
+
// disconnect, and title-edit start. Replaces per-card listeners (avoids re-attaching
|
|
798
|
+
// listeners on every sync; new cards work automatically).
|
|
799
|
+
document.getElementById('fleet-canvas').addEventListener('click', (e) => {
|
|
800
|
+
const target = e.target instanceof HTMLElement ? e.target : null;
|
|
801
|
+
if (!target) return;
|
|
802
|
+
|
|
803
|
+
// Lane header collapse toggle.
|
|
804
|
+
const header = target.closest('.swimlane-header');
|
|
805
|
+
if (header) {
|
|
806
|
+
const row = header.closest('.swimlane');
|
|
807
|
+
const lane = row && row.getAttribute('data-lane');
|
|
808
|
+
if (lane) {
|
|
809
|
+
laneCollapsed[lane] = !laneCollapsed[lane];
|
|
810
|
+
row.classList.toggle('collapsed', laneCollapsed[lane]);
|
|
811
|
+
}
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// Disconnect button.
|
|
816
|
+
const disconnectBtn = target.closest('[data-disconnect]');
|
|
817
|
+
if (disconnectBtn) {
|
|
818
|
+
const card = disconnectBtn.closest('.agent-card');
|
|
819
|
+
const session = findSessionById(card && card.getAttribute('data-session-id'));
|
|
820
|
+
if (session) postDisconnect(session, e);
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// Title edit start.
|
|
825
|
+
const titleEl = target.closest('[data-edit-title]');
|
|
826
|
+
if (titleEl) {
|
|
827
|
+
const card = titleEl.closest('.agent-card');
|
|
828
|
+
if (!card) return;
|
|
829
|
+
e.preventDefault();
|
|
830
|
+
e.stopPropagation();
|
|
831
|
+
const sessionId = String(card.getAttribute('data-session-id') || '').trim();
|
|
832
|
+
const sourceId = String(card.getAttribute('data-source-id') || '').trim() || 'local';
|
|
833
|
+
if (!sessionId) return;
|
|
834
|
+
const input = card.querySelector('[data-title-editor]');
|
|
835
|
+
if (!(input instanceof HTMLInputElement)) return;
|
|
836
|
+
const existingSession = findSessionById(sessionId);
|
|
837
|
+
const current = String((existingSession && (existingSession.cardTitle || existingSession.taskTitle)) || titleEl.textContent || '').trim();
|
|
838
|
+
function cleanup() {
|
|
839
|
+
input.style.display = 'none';
|
|
840
|
+
titleEl.style.display = '';
|
|
841
|
+
input.onblur = null;
|
|
842
|
+
input.onkeydown = null;
|
|
843
|
+
}
|
|
844
|
+
function commit(nextValue) {
|
|
845
|
+
const trimmed = String(nextValue || '').trim();
|
|
846
|
+
postToHost({ source: 'agentide-wow-widget', type: 'updateFleetCardTitle', sourceId, sessionId, cardTitle: trimmed });
|
|
847
|
+
if (existingSession) {
|
|
848
|
+
existingSession.cardTitle = trimmed;
|
|
849
|
+
}
|
|
850
|
+
titleEl.textContent = esc(trimmed || (existingSession && existingSession.taskTitle) || sessionId);
|
|
851
|
+
cleanup();
|
|
852
|
+
}
|
|
853
|
+
titleEl.style.display = 'none';
|
|
854
|
+
input.value = current;
|
|
855
|
+
input.style.display = '';
|
|
856
|
+
input.focus();
|
|
857
|
+
input.select();
|
|
858
|
+
input.onblur = () => commit(input.value);
|
|
859
|
+
input.onkeydown = (evt) => {
|
|
860
|
+
if (evt.key === 'Enter') { evt.preventDefault(); commit(input.value); }
|
|
861
|
+
else if (evt.key === 'Escape') { evt.preventDefault(); cleanup(); }
|
|
862
|
+
};
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// Open spotlight for the clicked card.
|
|
867
|
+
const card = target.closest('.agent-card');
|
|
868
|
+
if (card) {
|
|
869
|
+
const session = findSessionById(card.getAttribute('data-session-id'));
|
|
870
|
+
if (session) postOpenSpotlight(session);
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
// Keyboard: Enter/Space on a focused card opens spotlight (matches click).
|
|
875
|
+
document.getElementById('fleet-canvas').addEventListener('keydown', (e) => {
|
|
876
|
+
if (e.key !== 'Enter' && e.key !== ' ') return;
|
|
877
|
+
const target = e.target instanceof HTMLElement ? e.target : null;
|
|
878
|
+
if (!target) return;
|
|
879
|
+
if (target.closest('[data-disconnect]') || target.closest('[data-edit-title]') || target.closest('[data-title-editor]')) return;
|
|
880
|
+
const card = target.closest('.agent-card');
|
|
881
|
+
if (!card) return;
|
|
882
|
+
e.preventDefault();
|
|
883
|
+
const session = findSessionById(card.getAttribute('data-session-id'));
|
|
884
|
+
if (session) postOpenSpotlight(session);
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
document.getElementById('search').addEventListener('input', renderLanes);
|
|
888
|
+
|
|
889
|
+
renderLanes();
|
|
890
|
+
|
|
891
|
+
if (!diagnostics.ok) {
|
|
892
|
+
document.getElementById('msg').textContent = 'Fleet export read issue: ' + esc(diagnostics.error);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
window.addEventListener('message', (e) => {
|
|
896
|
+
const d = e.data;
|
|
897
|
+
if (!d || typeof d !== 'object') {
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
if (d.type === 'viewExportSnapshot' || d.type === 'liveFleetSnapshot') {
|
|
901
|
+
applySnapshot(d.payload, d.meta);
|
|
902
|
+
}
|
|
903
|
+
if (d.type === 'refreshFinished' || d.type === 'fleetRefreshComplete') {
|
|
904
|
+
clearRefreshLoading();
|
|
905
|
+
requestSnapshot();
|
|
906
|
+
}
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
requestSnapshot();
|
|
910
|
+
// Self-poll as a safety net. Host also pushes snapshots after refresh; this fills
|
|
911
|
+
// gaps if the host signal is lost (e.g. webview restart) and keeps lanes fresh.
|
|
912
|
+
setInterval(requestSnapshot, 15000);
|
|
913
|
+
// The snapshot poll above only reads the current export. This refresh poll asks
|
|
914
|
+
// the host to recompute the export/widget so new scheduled/running sessions appear.
|
|
915
|
+
setInterval(requestFleetRefresh, 30000);
|
|
916
|
+
</script>
|
|
917
|
+
</body>
|
|
918
|
+
</html>`;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
function main() {
|
|
922
|
+
const home = process.env.HOME || '';
|
|
923
|
+
const chartDir = process.env.AGENTIDE_CHART_DIR || path.join(home, '.agent-hippo', 'analytics', 'views', 'global', '__all', '__all', 'charts');
|
|
924
|
+
const exportDir = process.env.AGENTIDE_EXPORT_DIR || path.join(home, '.agent-hippo', 'analytics', 'views', 'global', '__all', '__all', 'exports');
|
|
925
|
+
|
|
926
|
+
fs.mkdirSync(chartDir, { recursive: true });
|
|
927
|
+
fs.mkdirSync(exportDir, { recursive: true });
|
|
928
|
+
|
|
929
|
+
const fleet = readFleetExport(exportDir);
|
|
930
|
+
const sessions = Array.isArray(fleet.payload.sessions) ? fleet.payload.sessions : [];
|
|
931
|
+
sessions.sort((a, b) => {
|
|
932
|
+
const rank = statusRank(String(a.status || '')) - statusRank(String(b.status || ''));
|
|
933
|
+
if (rank !== 0) return rank;
|
|
934
|
+
// Ascending so the next/oldest scheduled items appear first.
|
|
935
|
+
return Date.parse(String(a.startedAt || '')) - Date.parse(String(b.startedAt || ''));
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
writeCsv(exportDir, sessions);
|
|
939
|
+
const html = buildHtml(
|
|
940
|
+
{
|
|
941
|
+
generatedAt: fleet.payload.generatedAt,
|
|
942
|
+
totals: fleet.payload.totals,
|
|
943
|
+
sessions,
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
ok: fleet.ok,
|
|
947
|
+
error: fleet.error || '',
|
|
948
|
+
exportPath: fleet.exportPath,
|
|
949
|
+
}
|
|
950
|
+
);
|
|
951
|
+
fs.writeFileSync(path.join(chartDir, OUTPUT_HTML), html, 'utf8');
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
main();
|