@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,1813 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Agent Anywhere -- Gateway Setup (Windows)
|
|
3
|
+
#
|
|
4
|
+
# Installs OpenClaw Gateway and builds the web UI so users can
|
|
5
|
+
# configure messaging channels (Telegram, WhatsApp, Slack, etc.)
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# .\setup-gateway.ps1 # Interactive
|
|
9
|
+
# .\setup-gateway.ps1 -Source "openclaw/openclaw#branch" # Specify source
|
|
10
|
+
# .\setup-gateway.ps1 -Source "github:org/repo" # npm git protocol
|
|
11
|
+
# .\setup-gateway.ps1 -Source "C:\dev\openclaw" # Local source
|
|
12
|
+
# .\setup-gateway.ps1 -Check # Check status only
|
|
13
|
+
# .\setup-gateway.ps1 -Uninstall # stop gateway + npm uninstall -g openclaw
|
|
14
|
+
# .\setup-gateway.ps1 -Reinstall -Source <src> # uninstall, verify, then install
|
|
15
|
+
# .\setup-gateway.ps1 -NoModifyPath # opt out: skip adding wrapper dir to PATH
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
param(
|
|
19
|
+
[string]$Source = "",
|
|
20
|
+
[switch]$Check,
|
|
21
|
+
[switch]$Uninstall,
|
|
22
|
+
[switch]$Reinstall,
|
|
23
|
+
[switch]$ModifyPath,
|
|
24
|
+
[switch]$NoModifyPath,
|
|
25
|
+
[int]$Port = 18789,
|
|
26
|
+
[string]$ConfigTemplate = ""
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
$ErrorActionPreference = "Stop"
|
|
30
|
+
|
|
31
|
+
function Read-OpenclawConfigGatewayPort {
|
|
32
|
+
$cfg = Join-Path $env:USERPROFILE ".openclaw\openclaw.json"
|
|
33
|
+
if (-not (Test-Path -LiteralPath $cfg)) { return $null }
|
|
34
|
+
if (-not (Get-Command node -ErrorAction SilentlyContinue)) { return $null }
|
|
35
|
+
$expr = 'const fs=require("fs");const p=require("path");const o=require("os");const f=p.join(o.homedir(),".openclaw","openclaw.json");if(!fs.existsSync(f))process.exit(1);let t=fs.readFileSync(f,"utf8");t=t.replace(/^\s*\/\/.*$/gm,"").replace(/,\s*([\]}])/g,"$1");try{const j=JSON.parse(t);const x=j&&j.gateway&&j.gateway.port;if(typeof x==="number"&&x>=1&&x<=65535){process.stdout.write(String(x));process.exit(0)}if(typeof x==="string"&&/^[0-9]+$/.test(x)){process.stdout.write(x);process.exit(0)}}catch(z){}process.exit(1);'
|
|
36
|
+
try {
|
|
37
|
+
$raw = & node -e $expr 2>$null
|
|
38
|
+
if ($null -ne $raw -and "$raw" -match '^[0-9]+$') { return [int]"$raw" }
|
|
39
|
+
} catch { }
|
|
40
|
+
return $null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (-not $PSBoundParameters.ContainsKey('Port')) {
|
|
44
|
+
$cfgPort = Read-OpenclawConfigGatewayPort
|
|
45
|
+
if ($null -ne $cfgPort) { $Port = $cfgPort }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# ============================================================================
|
|
49
|
+
# Logging helpers
|
|
50
|
+
# ============================================================================
|
|
51
|
+
function Log-Info { param([string]$msg) Write-Host "[INFO] $msg" -ForegroundColor Blue }
|
|
52
|
+
function Log-Success { param([string]$msg) Write-Host " [OK] $msg" -ForegroundColor Green }
|
|
53
|
+
function Log-Warn { param([string]$msg) Write-Host " [WARN] $msg" -ForegroundColor Yellow }
|
|
54
|
+
function Log-Error { param([string]$msg) Write-Host "[ERROR] $msg" -ForegroundColor Red }
|
|
55
|
+
function Log-Step { param([string]$msg) Write-Host "`n$msg" -ForegroundColor Cyan }
|
|
56
|
+
|
|
57
|
+
$script:NodeRequiredVersion = "22.14.0"
|
|
58
|
+
$script:NodeBootstrapVersion = if ($env:AGENT_ANYWHERE_NODE_VERSION) { $env:AGENT_ANYWHERE_NODE_VERSION.TrimStart('v') } else { "22.22.0" }
|
|
59
|
+
$script:NodeBootstrapRoot = Join-Path $env:USERPROFILE ".agenthippo\tools\node"
|
|
60
|
+
$script:NpmGlobalPrefix = Join-Path $env:USERPROFILE ".npm-global"
|
|
61
|
+
$script:ManagedGatewayStateDir = Join-Path $env:USERPROFILE ".agenthippo\gateway"
|
|
62
|
+
$script:ManagedGatewayManifestPath = Join-Path $script:ManagedGatewayStateDir "install.json"
|
|
63
|
+
$script:GatewayInstallStatusPath = Join-Path $script:ManagedGatewayStateDir "install-status.json"
|
|
64
|
+
$script:ManagedGatewayWrapperDir = if ($env:LOCALAPPDATA) { Join-Path $env:LOCALAPPDATA "AgentHippo\bin" } else { Join-Path (Join-Path $env:USERPROFILE "AppData\Local") "AgentHippo\bin" }
|
|
65
|
+
$script:ManagedGatewayWrapperMarker = "REM Managed by Agent Anywhere"
|
|
66
|
+
$script:GatewayInstallStatus = $null
|
|
67
|
+
$script:ModifyPath = $true
|
|
68
|
+
if ($NoModifyPath -or $env:AGENT_ANYWHERE_MODIFY_PATH -eq "0") {
|
|
69
|
+
$script:ModifyPath = $false
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function Reset-GatewayInstallStatus {
|
|
73
|
+
$script:GatewayInstallStatus = @{
|
|
74
|
+
phase = "starting"
|
|
75
|
+
message = "Starting Agent Anywhere setup..."
|
|
76
|
+
lastError = $null
|
|
77
|
+
updatedAt = $null
|
|
78
|
+
steps = @{
|
|
79
|
+
cliVersionWorks = $false
|
|
80
|
+
npmInstallComplete = $false
|
|
81
|
+
wrapperExists = $false
|
|
82
|
+
configExists = $false
|
|
83
|
+
distExists = $false
|
|
84
|
+
webUiExists = $false
|
|
85
|
+
finalCheckPassed = $false
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function Write-GatewayInstallStatus {
|
|
91
|
+
if ($null -eq $script:GatewayInstallStatus) {
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
New-Item -ItemType Directory -Path $script:ManagedGatewayStateDir -Force | Out-Null
|
|
96
|
+
$script:GatewayInstallStatus.updatedAt = [DateTimeOffset]::UtcNow.ToString("o")
|
|
97
|
+
$json = $script:GatewayInstallStatus | ConvertTo-Json -Depth 6
|
|
98
|
+
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
|
|
99
|
+
[System.IO.File]::WriteAllText($script:GatewayInstallStatusPath, $json, $utf8NoBom)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function Initialize-GatewayInstallStatus {
|
|
103
|
+
param(
|
|
104
|
+
[string]$Phase,
|
|
105
|
+
[string]$Message
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
Reset-GatewayInstallStatus
|
|
109
|
+
if ($Phase) {
|
|
110
|
+
$script:GatewayInstallStatus.phase = $Phase
|
|
111
|
+
}
|
|
112
|
+
if ($Message) {
|
|
113
|
+
$script:GatewayInstallStatus.message = $Message
|
|
114
|
+
}
|
|
115
|
+
Write-GatewayInstallStatus
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function Update-GatewayInstallStatus {
|
|
119
|
+
param(
|
|
120
|
+
[string]$Phase,
|
|
121
|
+
[string]$Message,
|
|
122
|
+
[hashtable]$StepUpdates,
|
|
123
|
+
[string]$LastError
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
if ($null -eq $script:GatewayInstallStatus) {
|
|
127
|
+
Reset-GatewayInstallStatus
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if ($Phase) {
|
|
131
|
+
$script:GatewayInstallStatus.phase = $Phase
|
|
132
|
+
}
|
|
133
|
+
if ($Message) {
|
|
134
|
+
$script:GatewayInstallStatus.message = $Message
|
|
135
|
+
}
|
|
136
|
+
if ($PSBoundParameters.ContainsKey('LastError')) {
|
|
137
|
+
$script:GatewayInstallStatus.lastError = $LastError
|
|
138
|
+
}
|
|
139
|
+
if ($StepUpdates) {
|
|
140
|
+
foreach ($key in $StepUpdates.Keys) {
|
|
141
|
+
$script:GatewayInstallStatus.steps[$key] = [bool]$StepUpdates[$key]
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
Write-GatewayInstallStatus
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function Complete-GatewayInstallStatus {
|
|
149
|
+
param(
|
|
150
|
+
[hashtable]$StepUpdates,
|
|
151
|
+
[string]$Message = "Agent Anywhere is fully installed!"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
Update-GatewayInstallStatus -Phase "complete" -Message $Message -StepUpdates $StepUpdates -LastError $null
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function Fail-GatewayInstallStatus {
|
|
158
|
+
param(
|
|
159
|
+
[string]$Message,
|
|
160
|
+
[hashtable]$StepUpdates
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
Update-GatewayInstallStatus -Phase "failed" -Message $Message -StepUpdates $StepUpdates -LastError $Message
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function Add-PathEntry {
|
|
167
|
+
param([string]$Entry)
|
|
168
|
+
if (-not $Entry) { return }
|
|
169
|
+
if (-not (Test-Path -LiteralPath $Entry)) { return }
|
|
170
|
+
$parts = @($env:PATH -split ';' | Where-Object { $_ -ne "" })
|
|
171
|
+
if ($parts -contains $Entry) { return }
|
|
172
|
+
$env:PATH = "$Entry;$($env:PATH)"
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function Test-PathContainsEntry {
|
|
176
|
+
param([string]$Entry)
|
|
177
|
+
if (-not $Entry) { return $false }
|
|
178
|
+
$parts = @($env:PATH -split ';' | Where-Object { $_ -and $_.Trim() -ne "" })
|
|
179
|
+
$needle = Normalize-PathForCompare -PathValue $Entry
|
|
180
|
+
foreach ($part in $parts) {
|
|
181
|
+
if ((Normalize-PathForCompare -PathValue $part) -eq $needle) {
|
|
182
|
+
return $true
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return $false
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function Normalize-PathForCompare {
|
|
189
|
+
param([string]$PathValue)
|
|
190
|
+
if (-not $PathValue) { return "" }
|
|
191
|
+
return $PathValue.Trim().TrimEnd('\').ToLowerInvariant()
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function Get-PreferredGitBashPath {
|
|
195
|
+
$candidates = @()
|
|
196
|
+
if ($env:ProgramFiles) {
|
|
197
|
+
$candidates += (Join-Path $env:ProgramFiles "Git\usr\bin\bash.exe")
|
|
198
|
+
$candidates += (Join-Path $env:ProgramFiles "Git\bin\bash.exe")
|
|
199
|
+
}
|
|
200
|
+
$programFilesX86 = [Environment]::GetEnvironmentVariable("ProgramFiles(x86)")
|
|
201
|
+
if ($programFilesX86) {
|
|
202
|
+
$candidates += (Join-Path $programFilesX86 "Git\usr\bin\bash.exe")
|
|
203
|
+
$candidates += (Join-Path $programFilesX86 "Git\bin\bash.exe")
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
foreach ($candidate in $candidates) {
|
|
207
|
+
if ($candidate -and (Test-Path -LiteralPath $candidate)) {
|
|
208
|
+
return $candidate
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
$commands = @(Get-Command bash -All -ErrorAction SilentlyContinue)
|
|
214
|
+
foreach ($command in $commands) {
|
|
215
|
+
if ($command.Source -and $command.Source -match '[\\/]Git[\\/]usr[\\/]bin[\\/]bash\.exe$') {
|
|
216
|
+
return $command.Source
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
foreach ($command in $commands) {
|
|
220
|
+
if ($command.Source -and $command.Source -match '[\\/]Git[\\/].*bash\.exe$') {
|
|
221
|
+
return $command.Source
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
} catch { }
|
|
225
|
+
|
|
226
|
+
return $null
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function Invoke-WithPreferredWindowsBash {
|
|
230
|
+
param([scriptblock]$ScriptBlock)
|
|
231
|
+
|
|
232
|
+
$originalPath = $env:PATH
|
|
233
|
+
$originalScriptShell = $env:npm_config_script_shell
|
|
234
|
+
$shimDir = $null
|
|
235
|
+
try {
|
|
236
|
+
$gitBashPath = Get-PreferredGitBashPath
|
|
237
|
+
if ($gitBashPath) {
|
|
238
|
+
$gitBashDir = Split-Path -Parent $gitBashPath
|
|
239
|
+
$shimDir = Join-Path ([System.IO.Path]::GetTempPath()) ("agent-anywhere-bash-" + [guid]::NewGuid().ToString("n"))
|
|
240
|
+
New-Item -ItemType Directory -Path $shimDir -Force | Out-Null
|
|
241
|
+
$shimPath = Join-Path $shimDir "bash.cmd"
|
|
242
|
+
$shimContent = @(
|
|
243
|
+
"@echo off",
|
|
244
|
+
('"{0}" %*' -f $gitBashPath)
|
|
245
|
+
) -join "`r`n"
|
|
246
|
+
Set-Content -Path $shimPath -Value $shimContent -Encoding Ascii
|
|
247
|
+
$env:PATH = "$shimDir;$gitBashDir;$env:PATH"
|
|
248
|
+
$env:npm_config_script_shell = $gitBashPath
|
|
249
|
+
Log-Info "Using Git Bash for source build scripts: $gitBashPath"
|
|
250
|
+
}
|
|
251
|
+
& $ScriptBlock
|
|
252
|
+
} finally {
|
|
253
|
+
$env:PATH = $originalPath
|
|
254
|
+
if ($null -eq $originalScriptShell) {
|
|
255
|
+
Remove-Item Env:npm_config_script_shell -ErrorAction SilentlyContinue
|
|
256
|
+
} else {
|
|
257
|
+
$env:npm_config_script_shell = $originalScriptShell
|
|
258
|
+
}
|
|
259
|
+
if ($shimDir -and (Test-Path -LiteralPath $shimDir)) {
|
|
260
|
+
Remove-Item -LiteralPath $shimDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
# Write the user-scope PATH via direct HKCU registry update plus a bounded,
|
|
266
|
+
# best-effort WM_SETTINGCHANGE broadcast.
|
|
267
|
+
#
|
|
268
|
+
# Background: [Environment]::SetEnvironmentVariable("Path", $v, "User") writes
|
|
269
|
+
# the registry AND synchronously broadcasts WM_SETTINGCHANGE to every top-level
|
|
270
|
+
# window. On Windows desktops with a wedged message pump (Explorer, an
|
|
271
|
+
# unresponsive Electron/Chrome window, an old Slack/Teams instance, etc.) this
|
|
272
|
+
# can stall the calling process for many minutes — observed during Agent
|
|
273
|
+
# Anywhere uninstall as a hang with the script alive but using <1s CPU and no
|
|
274
|
+
# child processes. We split the two steps so the registry update always
|
|
275
|
+
# completes, then fire-and-forget a bounded broadcast that explicitly skips
|
|
276
|
+
# hung windows.
|
|
277
|
+
function Set-UserPathRegistry {
|
|
278
|
+
param([AllowEmptyString()][string]$Value)
|
|
279
|
+
try {
|
|
280
|
+
$key = 'HKCU:\Environment'
|
|
281
|
+
if ([string]::IsNullOrEmpty($Value)) {
|
|
282
|
+
Remove-ItemProperty -Path $key -Name 'Path' -Force -ErrorAction SilentlyContinue
|
|
283
|
+
} else {
|
|
284
|
+
$kind = [Microsoft.Win32.RegistryValueKind]::ExpandString
|
|
285
|
+
try {
|
|
286
|
+
$existing = Get-Item -Path $key -ErrorAction Stop
|
|
287
|
+
$existingKind = $existing.GetValueKind('Path')
|
|
288
|
+
if ($existingKind -eq [Microsoft.Win32.RegistryValueKind]::String -or
|
|
289
|
+
$existingKind -eq [Microsoft.Win32.RegistryValueKind]::ExpandString) {
|
|
290
|
+
$kind = $existingKind
|
|
291
|
+
}
|
|
292
|
+
} catch { }
|
|
293
|
+
New-ItemProperty -Path $key -Name 'Path' -PropertyType $kind -Value $Value -Force | Out-Null
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
return $false
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
Send-EnvironmentChangeBroadcast
|
|
300
|
+
return $true
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
# Bounded WM_SETTINGCHANGE broadcast. Uses SMTO_ABORTIFHUNG with a short
|
|
304
|
+
# per-window timeout so wedged windows do not block the script. Never throws.
|
|
305
|
+
$script:EnvBroadcastTypeLoaded = $false
|
|
306
|
+
function Send-EnvironmentChangeBroadcast {
|
|
307
|
+
if (-not $script:EnvBroadcastTypeLoaded) {
|
|
308
|
+
try {
|
|
309
|
+
Add-Type -Namespace AgentAnywhereWin32 -Name NativeMethods -MemberDefinition @'
|
|
310
|
+
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
|
|
311
|
+
public static extern System.IntPtr SendMessageTimeout(
|
|
312
|
+
System.IntPtr hWnd,
|
|
313
|
+
uint Msg,
|
|
314
|
+
System.IntPtr wParam,
|
|
315
|
+
string lParam,
|
|
316
|
+
uint fuFlags,
|
|
317
|
+
uint uTimeout,
|
|
318
|
+
out System.UIntPtr lpdwResult);
|
|
319
|
+
'@ -ErrorAction Stop
|
|
320
|
+
$script:EnvBroadcastTypeLoaded = $true
|
|
321
|
+
} catch {
|
|
322
|
+
return
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
try {
|
|
326
|
+
$HWND_BROADCAST = [IntPtr]0xFFFF
|
|
327
|
+
$WM_SETTINGCHANGE = [uint32]0x001A
|
|
328
|
+
$SMTO_ABORTIFHUNG = [uint32]0x0002
|
|
329
|
+
$perWindowTimeoutMs = [uint32]500
|
|
330
|
+
$result = [UIntPtr]::Zero
|
|
331
|
+
[AgentAnywhereWin32.NativeMethods]::SendMessageTimeout(
|
|
332
|
+
$HWND_BROADCAST,
|
|
333
|
+
$WM_SETTINGCHANGE,
|
|
334
|
+
[IntPtr]::Zero,
|
|
335
|
+
'Environment',
|
|
336
|
+
$SMTO_ABORTIFHUNG,
|
|
337
|
+
$perWindowTimeoutMs,
|
|
338
|
+
[ref]$result) | Out-Null
|
|
339
|
+
} catch { }
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function Ensure-UserPathEntry {
|
|
343
|
+
param([string]$Entry)
|
|
344
|
+
if (-not $Entry) { return $false }
|
|
345
|
+
try {
|
|
346
|
+
New-Item -ItemType Directory -Path $Entry -Force | Out-Null
|
|
347
|
+
} catch { }
|
|
348
|
+
|
|
349
|
+
$current = [Environment]::GetEnvironmentVariable("Path", "User")
|
|
350
|
+
$parts = @()
|
|
351
|
+
if ($current) {
|
|
352
|
+
$parts = @($current -split ';' | Where-Object { $_ -and $_.Trim() -ne "" })
|
|
353
|
+
}
|
|
354
|
+
$needle = Normalize-PathForCompare -PathValue $Entry
|
|
355
|
+
foreach ($part in $parts) {
|
|
356
|
+
if ((Normalize-PathForCompare -PathValue $part) -eq $needle) {
|
|
357
|
+
return $false
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
$nextPath = if ([string]::IsNullOrWhiteSpace($current)) { $Entry } else { "$Entry;$current" }
|
|
361
|
+
if (Set-UserPathRegistry -Value $nextPath) {
|
|
362
|
+
return $true
|
|
363
|
+
}
|
|
364
|
+
Log-Warn "Could not persist PATH entry: $Entry"
|
|
365
|
+
return $false
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function Remove-UserPathEntry {
|
|
369
|
+
param([string]$Entry)
|
|
370
|
+
if (-not $Entry) { return $false }
|
|
371
|
+
$current = [Environment]::GetEnvironmentVariable("Path", "User")
|
|
372
|
+
if (-not $current) { return $false }
|
|
373
|
+
|
|
374
|
+
$needle = Normalize-PathForCompare -PathValue $Entry
|
|
375
|
+
$parts = @($current -split ';' | Where-Object { $_ -and $_.Trim() -ne "" })
|
|
376
|
+
$nextParts = @()
|
|
377
|
+
$removed = $false
|
|
378
|
+
foreach ($part in $parts) {
|
|
379
|
+
if ((Normalize-PathForCompare -PathValue $part) -eq $needle) {
|
|
380
|
+
$removed = $true
|
|
381
|
+
continue
|
|
382
|
+
}
|
|
383
|
+
$nextParts += $part
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (-not $removed) { return $false }
|
|
387
|
+
$nextPath = if ($nextParts.Count -gt 0) { ($nextParts -join ';') } else { '' }
|
|
388
|
+
if (Set-UserPathRegistry -Value $nextPath) {
|
|
389
|
+
return $true
|
|
390
|
+
}
|
|
391
|
+
Log-Warn "Could not remove PATH entry: $Entry"
|
|
392
|
+
return $false
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function Persist-UserGatewayEnvironment {
|
|
396
|
+
$changed = $false
|
|
397
|
+
|
|
398
|
+
if ($script:ModifyPath -and (Ensure-UserPathEntry -Entry $script:ManagedGatewayWrapperDir)) {
|
|
399
|
+
$changed = $true
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if ($changed) {
|
|
403
|
+
Log-Info "Persisted PATH for future terminals (open a new terminal window after setup)."
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function Set-NpmUserPrefix {
|
|
408
|
+
New-Item -ItemType Directory -Path $script:NpmGlobalPrefix -Force | Out-Null
|
|
409
|
+
$env:npm_config_prefix = $script:NpmGlobalPrefix
|
|
410
|
+
Add-PathEntry -Entry $script:NpmGlobalPrefix
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function Test-DirectoryWritable {
|
|
414
|
+
param([string]$PathValue)
|
|
415
|
+
if (-not $PathValue) { return $false }
|
|
416
|
+
if (-not (Test-Path -LiteralPath $PathValue)) { return $false }
|
|
417
|
+
$probe = Join-Path $PathValue (".agent-anywhere-write-test-" + [guid]::NewGuid().ToString("n") + ".tmp")
|
|
418
|
+
try {
|
|
419
|
+
Set-Content -LiteralPath $probe -Value "" -NoNewline
|
|
420
|
+
Remove-Item -LiteralPath $probe -Force -ErrorAction SilentlyContinue
|
|
421
|
+
return $true
|
|
422
|
+
} catch {
|
|
423
|
+
Remove-Item -LiteralPath $probe -Force -ErrorAction SilentlyContinue
|
|
424
|
+
return $false
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function Test-NpmGlobalInstallWritable {
|
|
429
|
+
if (-not (Get-Command npm -ErrorAction SilentlyContinue)) { return $false }
|
|
430
|
+
try {
|
|
431
|
+
$prefix = (& npm prefix -g 2>$null)
|
|
432
|
+
if (-not $prefix) { return $false }
|
|
433
|
+
$prefix = "$prefix".Trim()
|
|
434
|
+
if (-not (Test-DirectoryWritable -PathValue $prefix)) { return $false }
|
|
435
|
+
|
|
436
|
+
$root = (& npm root -g 2>$null)
|
|
437
|
+
if (-not $root) { return $false }
|
|
438
|
+
$root = "$root".Trim()
|
|
439
|
+
$rootParent = Split-Path -Parent $root
|
|
440
|
+
if (-not (Test-DirectoryWritable -PathValue $rootParent)) { return $false }
|
|
441
|
+
return $true
|
|
442
|
+
} catch {
|
|
443
|
+
return $false
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function Clear-ManagedNpmPrefixOverride {
|
|
448
|
+
if ((Normalize-PathForCompare -PathValue $env:npm_config_prefix) -eq (Normalize-PathForCompare -PathValue $script:NpmGlobalPrefix)) {
|
|
449
|
+
Remove-Item Env:npm_config_prefix -ErrorAction SilentlyContinue
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function Configure-NpmGlobalContext {
|
|
454
|
+
Clear-ManagedNpmPrefixOverride
|
|
455
|
+
if (Test-NpmGlobalInstallWritable) {
|
|
456
|
+
return
|
|
457
|
+
}
|
|
458
|
+
Set-NpmUserPrefix
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function Cleanup-UserGatewayEnvironment {
|
|
462
|
+
$changed = $false
|
|
463
|
+
|
|
464
|
+
if (Remove-UserPathEntry -Entry $script:ManagedGatewayWrapperDir) {
|
|
465
|
+
$changed = $true
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if ($changed) {
|
|
469
|
+
Log-Info "Removed Agent Anywhere PATH setting from user environment."
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function Test-NodeVersionCompatible {
|
|
474
|
+
param([string]$VersionText)
|
|
475
|
+
if (-not $VersionText) { return $false }
|
|
476
|
+
$trimmed = $VersionText.TrimStart('v')
|
|
477
|
+
$version = $null
|
|
478
|
+
if (-not [version]::TryParse($trimmed, [ref]$version)) {
|
|
479
|
+
return $false
|
|
480
|
+
}
|
|
481
|
+
$requiredVersion = $null
|
|
482
|
+
if (-not [version]::TryParse($script:NodeRequiredVersion, [ref]$requiredVersion)) {
|
|
483
|
+
return $false
|
|
484
|
+
}
|
|
485
|
+
return ($version -ge $requiredVersion)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function Test-NodeCompatible {
|
|
489
|
+
try {
|
|
490
|
+
$version = (& node -v 2>$null)
|
|
491
|
+
if (-not $version) { return $false }
|
|
492
|
+
return (Test-NodeVersionCompatible -VersionText $version)
|
|
493
|
+
} catch {
|
|
494
|
+
return $false
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function Use-BootstrappedNodeIfAvailable {
|
|
499
|
+
if (-not (Test-Path -LiteralPath $script:NodeBootstrapRoot)) { return $false }
|
|
500
|
+
$dirs = Get-ChildItem -LiteralPath $script:NodeBootstrapRoot -Directory -ErrorAction SilentlyContinue |
|
|
501
|
+
Sort-Object Name -Descending
|
|
502
|
+
foreach ($dir in $dirs) {
|
|
503
|
+
$nodeExe = Join-Path $dir.FullName "node.exe"
|
|
504
|
+
$npmCli = Join-Path $dir.FullName "npm.cmd"
|
|
505
|
+
if (-not (Test-Path -LiteralPath $nodeExe) -or -not (Test-Path -LiteralPath $npmCli)) {
|
|
506
|
+
continue
|
|
507
|
+
}
|
|
508
|
+
$version = & $nodeExe -v 2>$null
|
|
509
|
+
if (Test-NodeVersionCompatible -VersionText $version) {
|
|
510
|
+
Add-PathEntry -Entry $dir.FullName
|
|
511
|
+
return $true
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return $false
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function Get-ManagedGatewayWrapperPath {
|
|
518
|
+
return Join-Path $script:ManagedGatewayWrapperDir "hippoclaw.cmd"
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function Get-ManagedOpenclawWrapperPath {
|
|
522
|
+
return Join-Path $script:ManagedGatewayWrapperDir "openclaw.cmd"
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function Test-AgentAnywhereManagedWrapper {
|
|
526
|
+
param([string]$PathValue)
|
|
527
|
+
if (-not $PathValue -or -not (Test-Path -LiteralPath $PathValue)) { return $false }
|
|
528
|
+
try {
|
|
529
|
+
return (Get-Content -LiteralPath $PathValue -TotalCount 2 | Select-String -SimpleMatch $script:ManagedGatewayWrapperMarker -Quiet)
|
|
530
|
+
} catch {
|
|
531
|
+
return $false
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function Write-ManagedGatewayCmdWrapper {
|
|
536
|
+
param(
|
|
537
|
+
[string]$NodePath,
|
|
538
|
+
[string]$EntryScriptPath,
|
|
539
|
+
[string]$WrapperPath
|
|
540
|
+
)
|
|
541
|
+
New-Item -ItemType Directory -Path (Split-Path -Parent $WrapperPath) -Force | Out-Null
|
|
542
|
+
$content = @"
|
|
543
|
+
@echo off
|
|
544
|
+
$($script:ManagedGatewayWrapperMarker)
|
|
545
|
+
"$NodePath" "$EntryScriptPath" %*
|
|
546
|
+
"@
|
|
547
|
+
Set-Content -LiteralPath $WrapperPath -Value $content -Encoding ASCII
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function Resolve-ManagedGatewayInstallFromRoot {
|
|
551
|
+
param(
|
|
552
|
+
[string]$NodePath,
|
|
553
|
+
[string]$PackageRoot,
|
|
554
|
+
[string]$BinDir
|
|
555
|
+
)
|
|
556
|
+
if (-not $NodePath -or -not (Test-Path -LiteralPath $NodePath)) { return $null }
|
|
557
|
+
if (-not $PackageRoot -or -not (Test-Path -LiteralPath $PackageRoot)) { return $null }
|
|
558
|
+
try {
|
|
559
|
+
$pkgJsonPath = Join-Path $PackageRoot "package.json"
|
|
560
|
+
if (-not (Test-Path -LiteralPath $pkgJsonPath)) { return $null }
|
|
561
|
+
$pkg = Get-Content -LiteralPath $pkgJsonPath -Raw | ConvertFrom-Json
|
|
562
|
+
$binMap = @{}
|
|
563
|
+
if ($pkg.bin) {
|
|
564
|
+
if ($pkg.bin -is [string]) {
|
|
565
|
+
$binName = if ($pkg.name) { [string]$pkg.name } else { "openclaw" }
|
|
566
|
+
$binMap[$binName] = [string]$pkg.bin
|
|
567
|
+
} elseif ($pkg.bin.PSObject.Properties) {
|
|
568
|
+
foreach ($prop in $pkg.bin.PSObject.Properties) {
|
|
569
|
+
$binMap[$prop.Name] = [string]$prop.Value
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
$names = [System.Collections.Generic.List[string]]::new()
|
|
575
|
+
foreach ($name in @("hippoclaw", "openclaw")) {
|
|
576
|
+
if (-not $names.Contains($name)) { [void]$names.Add($name) }
|
|
577
|
+
}
|
|
578
|
+
foreach ($name in $binMap.Keys) {
|
|
579
|
+
if (-not $names.Contains($name)) { [void]$names.Add($name) }
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
foreach ($name in $names) {
|
|
583
|
+
$relativeEntry = if ($binMap.ContainsKey($name)) { $binMap[$name] } else { $null }
|
|
584
|
+
if (-not $relativeEntry) { continue }
|
|
585
|
+
$entryScriptPath = [System.IO.Path]::GetFullPath((Join-Path $PackageRoot $relativeEntry))
|
|
586
|
+
if (-not (Test-Path -LiteralPath $entryScriptPath)) { continue }
|
|
587
|
+
|
|
588
|
+
$cliPath = $null
|
|
589
|
+
foreach ($candidate in @(
|
|
590
|
+
(Join-Path $BinDir "$name.cmd"),
|
|
591
|
+
(Join-Path $BinDir "$name.ps1"),
|
|
592
|
+
(Join-Path $BinDir $name)
|
|
593
|
+
)) {
|
|
594
|
+
if (Test-Path -LiteralPath $candidate) {
|
|
595
|
+
$cliPath = $candidate
|
|
596
|
+
break
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return [pscustomobject]@{
|
|
601
|
+
NodePath = $NodePath
|
|
602
|
+
CliPath = $cliPath
|
|
603
|
+
EntryScriptPath = $entryScriptPath
|
|
604
|
+
PackageRoot = $PackageRoot
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
} catch { }
|
|
608
|
+
return $null
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
function Resolve-ManagedGatewayInstall {
|
|
612
|
+
$currentNode = (Get-Command node -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source -ErrorAction SilentlyContinue)
|
|
613
|
+
|
|
614
|
+
if ($currentNode) {
|
|
615
|
+
try {
|
|
616
|
+
$npmRoot = (npm root -g 2>$null).Trim()
|
|
617
|
+
$prefix = (& npm prefix -g 2>$null).Trim()
|
|
618
|
+
if ($npmRoot -and $prefix) {
|
|
619
|
+
$resolved = Resolve-ManagedGatewayInstallFromRoot -NodePath $currentNode -PackageRoot (Join-Path $npmRoot "openclaw") -BinDir $prefix
|
|
620
|
+
if ($resolved) { return $resolved }
|
|
621
|
+
}
|
|
622
|
+
} catch { }
|
|
623
|
+
|
|
624
|
+
# Windows npm uses node_modules/ directly (no lib/ prefix); Unix uses lib/node_modules/
|
|
625
|
+
$resolved = Resolve-ManagedGatewayInstallFromRoot -NodePath $currentNode -PackageRoot (Join-Path $script:NpmGlobalPrefix "node_modules\openclaw") -BinDir $script:NpmGlobalPrefix
|
|
626
|
+
if ($resolved) { return $resolved }
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (Test-Path -LiteralPath $script:NodeBootstrapRoot) {
|
|
630
|
+
$dirs = Get-ChildItem -LiteralPath $script:NodeBootstrapRoot -Directory -ErrorAction SilentlyContinue |
|
|
631
|
+
Sort-Object Name -Descending
|
|
632
|
+
foreach ($dir in $dirs) {
|
|
633
|
+
# Windows portable Node layout: node_modules/ at the dist root (no lib/ prefix)
|
|
634
|
+
$resolved = Resolve-ManagedGatewayInstallFromRoot -NodePath (Join-Path $dir.FullName "node.exe") -PackageRoot (Join-Path $dir.FullName "node_modules\openclaw") -BinDir $dir.FullName
|
|
635
|
+
if ($resolved) { return $resolved }
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
return $null
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function Write-ManagedGatewayManifest {
|
|
643
|
+
param(
|
|
644
|
+
[string]$NodePath,
|
|
645
|
+
[string]$CliPath,
|
|
646
|
+
[string]$EntryScriptPath,
|
|
647
|
+
[string]$PackageRoot,
|
|
648
|
+
[string]$WrapperPath,
|
|
649
|
+
[string]$OpenclawWrapperPath = ""
|
|
650
|
+
)
|
|
651
|
+
New-Item -ItemType Directory -Path $script:ManagedGatewayStateDir -Force | Out-Null
|
|
652
|
+
$record = [ordered]@{
|
|
653
|
+
nodePath = $NodePath
|
|
654
|
+
cliPath = $CliPath
|
|
655
|
+
entryScriptPath = $EntryScriptPath
|
|
656
|
+
packageRoot = $PackageRoot
|
|
657
|
+
wrapperPath = $WrapperPath
|
|
658
|
+
wrapperDir = $script:ManagedGatewayWrapperDir
|
|
659
|
+
updatedAt = [DateTime]::UtcNow.ToString("o")
|
|
660
|
+
}
|
|
661
|
+
if ($OpenclawWrapperPath) {
|
|
662
|
+
$record.openclawWrapperPath = $OpenclawWrapperPath
|
|
663
|
+
}
|
|
664
|
+
# Write without BOM - PowerShell 5.1's -Encoding UTF8 emits BOM, which breaks JSON.parse in Node.js
|
|
665
|
+
$json = $record | ConvertTo-Json
|
|
666
|
+
[System.IO.File]::WriteAllBytes($script:ManagedGatewayManifestPath, [System.Text.Encoding]::UTF8.GetBytes($json))
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function Resolve-ManagedGatewayCliPath {
|
|
670
|
+
if (-not (Test-Path -LiteralPath $script:ManagedGatewayManifestPath)) { return $null }
|
|
671
|
+
try {
|
|
672
|
+
$record = Get-Content -LiteralPath $script:ManagedGatewayManifestPath -Raw | ConvertFrom-Json
|
|
673
|
+
foreach ($candidate in @($record.wrapperPath, $record.cliPath)) {
|
|
674
|
+
if ($candidate -and (Test-Path -LiteralPath $candidate)) {
|
|
675
|
+
return $candidate
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
} catch { }
|
|
679
|
+
return $null
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function Resolve-ManagedGatewayPackageRoot {
|
|
683
|
+
if (-not (Test-Path -LiteralPath $script:ManagedGatewayManifestPath)) { return $null }
|
|
684
|
+
try {
|
|
685
|
+
$record = Get-Content -LiteralPath $script:ManagedGatewayManifestPath -Raw | ConvertFrom-Json
|
|
686
|
+
if ($record.packageRoot -and (Test-Path -LiteralPath $record.packageRoot)) {
|
|
687
|
+
return $record.packageRoot
|
|
688
|
+
}
|
|
689
|
+
} catch { }
|
|
690
|
+
return $null
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
function Ensure-ManagedGatewayWrappers {
|
|
694
|
+
$resolved = Resolve-ManagedGatewayInstall
|
|
695
|
+
if (-not $resolved) {
|
|
696
|
+
Log-Warn "Could not resolve managed gateway install location after setup"
|
|
697
|
+
return $false
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
$wrapperPath = Get-ManagedGatewayWrapperPath
|
|
701
|
+
Write-ManagedGatewayCmdWrapper -NodePath $resolved.NodePath -EntryScriptPath $resolved.EntryScriptPath -WrapperPath $wrapperPath
|
|
702
|
+
|
|
703
|
+
$openclawWrapperPath = ""
|
|
704
|
+
$existingOpenclawWrapper = Get-ManagedOpenclawWrapperPath
|
|
705
|
+
if (Test-AgentAnywhereManagedWrapper -PathValue $existingOpenclawWrapper) {
|
|
706
|
+
Write-ManagedGatewayCmdWrapper -NodePath $resolved.NodePath -EntryScriptPath $resolved.EntryScriptPath -WrapperPath $existingOpenclawWrapper
|
|
707
|
+
$openclawWrapperPath = $existingOpenclawWrapper
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
Write-ManagedGatewayManifest -NodePath $resolved.NodePath -CliPath $resolved.CliPath -EntryScriptPath $resolved.EntryScriptPath -PackageRoot $resolved.PackageRoot -WrapperPath $wrapperPath -OpenclawWrapperPath $openclawWrapperPath
|
|
711
|
+
|
|
712
|
+
if ($script:ModifyPath) {
|
|
713
|
+
Persist-UserGatewayEnvironment
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
Log-Info "Stable CLI wrapper ready: $wrapperPath"
|
|
717
|
+
if (-not (Test-PathContainsEntry -Entry $script:ManagedGatewayWrapperDir)) {
|
|
718
|
+
if ($script:ModifyPath) {
|
|
719
|
+
Log-Info "Open a new terminal after setup so $($script:ManagedGatewayWrapperDir) is available on PATH."
|
|
720
|
+
} else {
|
|
721
|
+
Log-Info "Add $($script:ManagedGatewayWrapperDir) to PATH if you want to run hippoclaw directly from new terminals."
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
return $true
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
function Remove-ManagedGatewayWrapperState {
|
|
729
|
+
foreach ($wrapperPath in @((Get-ManagedGatewayWrapperPath), (Get-ManagedOpenclawWrapperPath))) {
|
|
730
|
+
if (Test-AgentAnywhereManagedWrapper -PathValue $wrapperPath) {
|
|
731
|
+
Remove-Item -LiteralPath $wrapperPath -Force -ErrorAction SilentlyContinue
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
Remove-Item -LiteralPath $script:ManagedGatewayManifestPath -Force -ErrorAction SilentlyContinue
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
function Install-NodeRuntime {
|
|
738
|
+
$archRaw = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant()
|
|
739
|
+
$nodeArch = switch ($archRaw) {
|
|
740
|
+
"arm64" { "arm64" }
|
|
741
|
+
"x64" { "x64" }
|
|
742
|
+
"x86" { "x86" }
|
|
743
|
+
default { $null }
|
|
744
|
+
}
|
|
745
|
+
if (-not $nodeArch) {
|
|
746
|
+
Log-Error "Automatic Node bootstrap unsupported on architecture: $archRaw"
|
|
747
|
+
return $false
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
$version = $script:NodeBootstrapVersion
|
|
751
|
+
$distName = "node-v$version-win-$nodeArch"
|
|
752
|
+
$destDir = Join-Path $script:NodeBootstrapRoot $distName
|
|
753
|
+
$nodeExe = Join-Path $destDir "node.exe"
|
|
754
|
+
$npmCmd = Join-Path $destDir "npm.cmd"
|
|
755
|
+
if ((Test-Path -LiteralPath $nodeExe) -and (Test-Path -LiteralPath $npmCmd)) {
|
|
756
|
+
Add-PathEntry -Entry $destDir
|
|
757
|
+
return $true
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
$url = "https://nodejs.org/dist/v$version/$distName.zip"
|
|
761
|
+
Log-Info "Installing Node.js v$version (win-$nodeArch) to $script:NodeBootstrapRoot"
|
|
762
|
+
New-Item -ItemType Directory -Path $script:NodeBootstrapRoot -Force | Out-Null
|
|
763
|
+
|
|
764
|
+
$work = Join-Path ([System.IO.Path]::GetTempPath()) ("agent-anywhere-node-" + [guid]::NewGuid().ToString("n"))
|
|
765
|
+
New-Item -ItemType Directory -Path $work -Force | Out-Null
|
|
766
|
+
$zipPath = Join-Path $work "node.zip"
|
|
767
|
+
|
|
768
|
+
try {
|
|
769
|
+
Invoke-WebRequest -Uri $url -OutFile $zipPath
|
|
770
|
+
Expand-Archive -LiteralPath $zipPath -DestinationPath $work -Force
|
|
771
|
+
$extracted = Join-Path $work $distName
|
|
772
|
+
if (-not (Test-Path -LiteralPath $extracted)) {
|
|
773
|
+
Log-Error "Downloaded Node.js archive did not contain $distName"
|
|
774
|
+
return $false
|
|
775
|
+
}
|
|
776
|
+
if (Test-Path -LiteralPath $destDir) {
|
|
777
|
+
Remove-Item -Recurse -Force $destDir -ErrorAction SilentlyContinue
|
|
778
|
+
}
|
|
779
|
+
Move-Item -LiteralPath $extracted -Destination $destDir -Force
|
|
780
|
+
Add-PathEntry -Entry $destDir
|
|
781
|
+
return $true
|
|
782
|
+
} catch {
|
|
783
|
+
Log-Error "Failed to download/install Node.js runtime from $url"
|
|
784
|
+
return $false
|
|
785
|
+
} finally {
|
|
786
|
+
Remove-Item -Recurse -Force $work -ErrorAction SilentlyContinue
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function Ensure-NodeNpm {
|
|
791
|
+
if (Test-NodeCompatible) {
|
|
792
|
+
try {
|
|
793
|
+
$npmVersion = (npm -v 2>$null)
|
|
794
|
+
if ($npmVersion) {
|
|
795
|
+
Configure-NpmGlobalContext
|
|
796
|
+
return $true
|
|
797
|
+
}
|
|
798
|
+
} catch { }
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
$null = Use-BootstrappedNodeIfAvailable
|
|
802
|
+
if (Test-NodeCompatible) {
|
|
803
|
+
try {
|
|
804
|
+
$npmVersion = (npm -v 2>$null)
|
|
805
|
+
if ($npmVersion) {
|
|
806
|
+
Configure-NpmGlobalContext
|
|
807
|
+
return $true
|
|
808
|
+
}
|
|
809
|
+
} catch { }
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (-not (Install-NodeRuntime)) {
|
|
813
|
+
return $false
|
|
814
|
+
}
|
|
815
|
+
if (-not (Test-NodeCompatible)) { return $false }
|
|
816
|
+
try {
|
|
817
|
+
$npmVersion = (npm -v 2>$null)
|
|
818
|
+
if (-not $npmVersion) { return $false }
|
|
819
|
+
} catch {
|
|
820
|
+
return $false
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
Configure-NpmGlobalContext
|
|
824
|
+
return $true
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
# ============================================================================
|
|
828
|
+
# Git / GitHub-style sources need a local UI build
|
|
829
|
+
# ============================================================================
|
|
830
|
+
function Test-SourceNeedsBuild {
|
|
831
|
+
param([string]$S)
|
|
832
|
+
if (-not $S) { return $false }
|
|
833
|
+
if ($S.StartsWith("\\") -or $S.StartsWith("/") -or $S.StartsWith(".")) { return $true }
|
|
834
|
+
if ($S -match '^[A-Za-z]:') { return $true }
|
|
835
|
+
if ($S.StartsWith("github:")) { return $true }
|
|
836
|
+
if ($S.StartsWith("git+http:") -or $S.StartsWith("git+https:")) { return $true }
|
|
837
|
+
if ($S.Contains("#")) { return $true }
|
|
838
|
+
if ($S -match '^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$') { return $true }
|
|
839
|
+
return $false
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function Needs-Pnpm {
|
|
843
|
+
return Test-SourceNeedsBuild -S $Source
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function Test-InstallSourceLocal {
|
|
847
|
+
param([string]$S)
|
|
848
|
+
if (-not $S) { return $false }
|
|
849
|
+
return $S.StartsWith("\\") -or $S.StartsWith("/") -or $S.StartsWith(".") -or ($S -match '^[A-Za-z]:')
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
# Remote github:/git+: npm global git install can leave a broken symlink; clone -> npm pack -> install .tgz.
|
|
853
|
+
# Git checkouts omit dist/; run pnpm build + ui:build in clone before npm pack (dist/entry + control-ui).
|
|
854
|
+
function Install-OpenclawFromRemoteGitSpec {
|
|
855
|
+
param([string]$Spec)
|
|
856
|
+
|
|
857
|
+
$s = $Spec
|
|
858
|
+
$ref = $null
|
|
859
|
+
if ($s.Contains("#")) {
|
|
860
|
+
$ref = $s.Substring($s.LastIndexOf("#") + 1)
|
|
861
|
+
$s = $s.Substring(0, $s.LastIndexOf("#"))
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
$cloneUrl = $null
|
|
865
|
+
if ($s.StartsWith("git+https:") -or $s.StartsWith("git+http:")) {
|
|
866
|
+
$cloneUrl = $s.Substring(4)
|
|
867
|
+
} elseif ($s.StartsWith("github:")) {
|
|
868
|
+
$rest = $s.Substring("github:".Length)
|
|
869
|
+
$cloneUrl = "https://github.com/$rest.git"
|
|
870
|
+
} elseif ($s -match '^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$') {
|
|
871
|
+
$cloneUrl = "https://github.com/$s.git"
|
|
872
|
+
} else {
|
|
873
|
+
Log-Error "Unsupported git install source: $Spec"
|
|
874
|
+
throw "Unsupported git install source"
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
$work = Join-Path ([System.IO.Path]::GetTempPath()) ("openclaw-gateway-src-" + [guid]::NewGuid().ToString("n"))
|
|
878
|
+
New-Item -ItemType Directory -Path $work -Force | Out-Null
|
|
879
|
+
$srcDir = Join-Path $work "src"
|
|
880
|
+
|
|
881
|
+
try {
|
|
882
|
+
Log-Info "Cloning $(Split-Path -Leaf $cloneUrl) (shallow) for npm pack install..."
|
|
883
|
+
if ($ref) {
|
|
884
|
+
git clone --depth 1 -b $ref $cloneUrl $srcDir
|
|
885
|
+
} else {
|
|
886
|
+
git clone --depth 1 $cloneUrl $srcDir
|
|
887
|
+
}
|
|
888
|
+
if ($LASTEXITCODE -ne 0) {
|
|
889
|
+
if (Test-Path $work) { Remove-Item -Recurse -Force $work -ErrorAction SilentlyContinue }
|
|
890
|
+
Log-Error "git clone failed (check ref and network)"
|
|
891
|
+
throw "git clone failed"
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
Log-Info "Building OpenClaw in clone before npm pack (may take several minutes)..."
|
|
895
|
+
try {
|
|
896
|
+
Invoke-OpenclawRepoBuild -RepoDir $srcDir
|
|
897
|
+
} catch {
|
|
898
|
+
if (Test-Path $work) { Remove-Item -Recurse -Force $work -ErrorAction SilentlyContinue }
|
|
899
|
+
Log-Error "OpenClaw source build failed: $_"
|
|
900
|
+
throw
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
Log-Info "npm pack --ignore-scripts ..."
|
|
904
|
+
Push-Location $srcDir
|
|
905
|
+
try {
|
|
906
|
+
npm pack --ignore-scripts
|
|
907
|
+
if ($LASTEXITCODE -ne 0) {
|
|
908
|
+
if (Test-Path $work) { Remove-Item -Recurse -Force $work -ErrorAction SilentlyContinue }
|
|
909
|
+
Log-Error "npm pack failed"
|
|
910
|
+
throw "npm pack failed"
|
|
911
|
+
}
|
|
912
|
+
} finally {
|
|
913
|
+
Pop-Location
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
$tgz = Get-ChildItem -Path $srcDir -Filter "openclaw-*.tgz" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
|
917
|
+
if (-not $tgz) {
|
|
918
|
+
if (Test-Path $work) { Remove-Item -Recurse -Force $work -ErrorAction SilentlyContinue }
|
|
919
|
+
Log-Error "npm pack did not produce openclaw-*.tgz under clone"
|
|
920
|
+
throw "npm pack produced no tarball"
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
Log-Info "npm install -g $($tgz.Name) ..."
|
|
924
|
+
npm install -g $tgz.FullName
|
|
925
|
+
if ($LASTEXITCODE -ne 0) {
|
|
926
|
+
if (Test-Path $work) { Remove-Item -Recurse -Force $work -ErrorAction SilentlyContinue }
|
|
927
|
+
Log-Error "npm install -g tarball failed"
|
|
928
|
+
throw "npm install tarball failed"
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
$script:RemoteGatewayCloneSrc = $srcDir
|
|
932
|
+
$script:RemoteGatewayWorkDir = $work
|
|
933
|
+
} catch {
|
|
934
|
+
if (Test-Path $work) {
|
|
935
|
+
Remove-Item -Recurse -Force $work -ErrorAction SilentlyContinue
|
|
936
|
+
}
|
|
937
|
+
throw
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
# ============================================================================
|
|
942
|
+
# Check prerequisites
|
|
943
|
+
# ============================================================================
|
|
944
|
+
function Check-Prerequisites {
|
|
945
|
+
Log-Step "Checking prerequisites..."
|
|
946
|
+
|
|
947
|
+
$allGood = $true
|
|
948
|
+
|
|
949
|
+
if (-not (Ensure-NodeNpm)) {
|
|
950
|
+
Log-Warn "Could not automatically provision Node.js/npm"
|
|
951
|
+
$allGood = $false
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
# Node.js >= 22.14
|
|
955
|
+
try {
|
|
956
|
+
$nodeVersion = (node -v 2>$null)
|
|
957
|
+
if ($nodeVersion) {
|
|
958
|
+
if (Test-NodeVersionCompatible -VersionText $nodeVersion) {
|
|
959
|
+
Log-Success "Node.js $nodeVersion"
|
|
960
|
+
} else {
|
|
961
|
+
Log-Warn "Node.js $nodeVersion -- version 22.14+ required"
|
|
962
|
+
$allGood = $false
|
|
963
|
+
}
|
|
964
|
+
} else {
|
|
965
|
+
throw "not found"
|
|
966
|
+
}
|
|
967
|
+
} catch {
|
|
968
|
+
Log-Warn "Node.js not found (version 22.14+ required)"
|
|
969
|
+
Write-Host " Install: https://nodejs.org/" -ForegroundColor Gray
|
|
970
|
+
$allGood = $false
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
# npm
|
|
974
|
+
try {
|
|
975
|
+
$npmVersion = (npm -v 2>$null)
|
|
976
|
+
if ($npmVersion) {
|
|
977
|
+
Log-Success "npm $npmVersion"
|
|
978
|
+
} else {
|
|
979
|
+
throw "not found"
|
|
980
|
+
}
|
|
981
|
+
} catch {
|
|
982
|
+
Log-Warn "npm not found"
|
|
983
|
+
$allGood = $false
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
if (Test-SourceNeedsBuild -S $Source) {
|
|
987
|
+
$localSrc = Test-InstallSourceLocal -S $Source
|
|
988
|
+
if (-not $localSrc) {
|
|
989
|
+
try {
|
|
990
|
+
$gitVersion = (git --version 2>$null)
|
|
991
|
+
if ($gitVersion) {
|
|
992
|
+
Log-Success "git $gitVersion"
|
|
993
|
+
} else {
|
|
994
|
+
throw "not found"
|
|
995
|
+
}
|
|
996
|
+
} catch {
|
|
997
|
+
Log-Warn "git not found (required for GitHub / git URL gateway install sources)"
|
|
998
|
+
$allGood = $false
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
# pnpm
|
|
1004
|
+
if (Needs-Pnpm) {
|
|
1005
|
+
try {
|
|
1006
|
+
$pnpmVersion = (pnpm -v 2>$null)
|
|
1007
|
+
if ($pnpmVersion) {
|
|
1008
|
+
Log-Success "pnpm $pnpmVersion"
|
|
1009
|
+
} else {
|
|
1010
|
+
throw "not found"
|
|
1011
|
+
}
|
|
1012
|
+
} catch {
|
|
1013
|
+
if (Ensure-Pnpm) {
|
|
1014
|
+
$pnpmVersion = (pnpm -v 2>$null)
|
|
1015
|
+
Log-Success "pnpm $pnpmVersion"
|
|
1016
|
+
} else {
|
|
1017
|
+
Log-Warn "pnpm not found (needed to build OpenClaw from source)"
|
|
1018
|
+
$allGood = $false
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
} else {
|
|
1022
|
+
Log-Info "pnpm not required for published package install"
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
return $allGood
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
# ============================================================================
|
|
1029
|
+
# Ensure pnpm is available when we need to build the UI
|
|
1030
|
+
# ============================================================================
|
|
1031
|
+
function Ensure-Pnpm {
|
|
1032
|
+
try {
|
|
1033
|
+
$pnpmVersion = (pnpm -v 2>$null)
|
|
1034
|
+
if ($pnpmVersion) {
|
|
1035
|
+
Log-Success "pnpm $pnpmVersion"
|
|
1036
|
+
return $true
|
|
1037
|
+
}
|
|
1038
|
+
} catch { }
|
|
1039
|
+
|
|
1040
|
+
Log-Warn "pnpm not found - attempting to install"
|
|
1041
|
+
|
|
1042
|
+
try {
|
|
1043
|
+
Log-Info "Installing pnpm via npm..."
|
|
1044
|
+
npm install -g pnpm | Out-Null
|
|
1045
|
+
$pnpmVersion = (pnpm -v 2>$null)
|
|
1046
|
+
if ($pnpmVersion) {
|
|
1047
|
+
Log-Success "pnpm $pnpmVersion"
|
|
1048
|
+
return $true
|
|
1049
|
+
}
|
|
1050
|
+
} catch { }
|
|
1051
|
+
|
|
1052
|
+
try {
|
|
1053
|
+
$corepackVersion = (corepack -v 2>$null)
|
|
1054
|
+
if ($corepackVersion) {
|
|
1055
|
+
Log-Info "Installing pnpm via corepack..."
|
|
1056
|
+
$previousPromptValue = $env:COREPACK_ENABLE_DOWNLOAD_PROMPT
|
|
1057
|
+
try {
|
|
1058
|
+
$env:COREPACK_ENABLE_DOWNLOAD_PROMPT = "0"
|
|
1059
|
+
corepack prepare pnpm@latest --activate | Out-Null
|
|
1060
|
+
} finally {
|
|
1061
|
+
if ($null -eq $previousPromptValue) {
|
|
1062
|
+
Remove-Item Env:COREPACK_ENABLE_DOWNLOAD_PROMPT -ErrorAction SilentlyContinue
|
|
1063
|
+
} else {
|
|
1064
|
+
$env:COREPACK_ENABLE_DOWNLOAD_PROMPT = $previousPromptValue
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
$pnpmVersion = (pnpm -v 2>$null)
|
|
1068
|
+
if ($pnpmVersion) {
|
|
1069
|
+
Log-Success "pnpm $pnpmVersion"
|
|
1070
|
+
return $true
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
} catch { }
|
|
1074
|
+
|
|
1075
|
+
Log-Warn "pnpm install failed - cannot build OpenClaw from source"
|
|
1076
|
+
return $false
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
function Invoke-OpenclawRepoBuild {
|
|
1080
|
+
param([string]$RepoDir)
|
|
1081
|
+
if (-not (Test-Path -LiteralPath $RepoDir)) {
|
|
1082
|
+
Log-Error "Repo directory missing: $RepoDir"
|
|
1083
|
+
throw "missing repo dir"
|
|
1084
|
+
}
|
|
1085
|
+
if (-not (Ensure-Pnpm)) {
|
|
1086
|
+
Log-Error "pnpm is required to build OpenClaw from a git checkout"
|
|
1087
|
+
throw "pnpm missing"
|
|
1088
|
+
}
|
|
1089
|
+
$lock = Join-Path $RepoDir "pnpm-lock.yaml"
|
|
1090
|
+
if (-not (Test-Path $lock)) {
|
|
1091
|
+
Log-Error "pnpm-lock.yaml missing in $RepoDir"
|
|
1092
|
+
throw "missing pnpm-lock.yaml"
|
|
1093
|
+
}
|
|
1094
|
+
Push-Location $RepoDir
|
|
1095
|
+
try {
|
|
1096
|
+
$previousCi = $env:CI
|
|
1097
|
+
try {
|
|
1098
|
+
$env:CI = "true"
|
|
1099
|
+
Invoke-WithPreferredWindowsBash {
|
|
1100
|
+
Log-Info "pnpm install..."
|
|
1101
|
+
pnpm install
|
|
1102
|
+
if ($LASTEXITCODE -ne 0) { throw "pnpm install failed (exit $LASTEXITCODE)" }
|
|
1103
|
+
Log-Info "pnpm build..."
|
|
1104
|
+
pnpm build
|
|
1105
|
+
if ($LASTEXITCODE -ne 0) { throw "pnpm build failed (exit $LASTEXITCODE)" }
|
|
1106
|
+
Log-Info "pnpm ui:build..."
|
|
1107
|
+
pnpm ui:build
|
|
1108
|
+
if ($LASTEXITCODE -ne 0) { throw "pnpm ui:build failed (exit $LASTEXITCODE)" }
|
|
1109
|
+
}
|
|
1110
|
+
} finally {
|
|
1111
|
+
if ($null -eq $previousCi) {
|
|
1112
|
+
Remove-Item Env:CI -ErrorAction SilentlyContinue
|
|
1113
|
+
} else {
|
|
1114
|
+
$env:CI = $previousCi
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
} finally {
|
|
1118
|
+
Pop-Location
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
# ============================================================================
|
|
1123
|
+
# Check installed components
|
|
1124
|
+
# ============================================================================
|
|
1125
|
+
function Get-GatewayCliCommand {
|
|
1126
|
+
$managed = Resolve-ManagedGatewayCliPath
|
|
1127
|
+
if ($managed) {
|
|
1128
|
+
return [pscustomobject]@{
|
|
1129
|
+
Source = $managed
|
|
1130
|
+
Name = [System.IO.Path]::GetFileNameWithoutExtension($managed)
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
$hc = Get-Command hippoclaw -ErrorAction SilentlyContinue
|
|
1134
|
+
if ($hc) { return $hc }
|
|
1135
|
+
$oc = Get-Command openclaw -ErrorAction SilentlyContinue
|
|
1136
|
+
if ($oc) { return $oc }
|
|
1137
|
+
|
|
1138
|
+
try {
|
|
1139
|
+
$prefix = (& npm prefix -g 2>$null).Trim()
|
|
1140
|
+
if ($prefix) {
|
|
1141
|
+
foreach ($name in @("hippoclaw.cmd", "hippoclaw.ps1", "hippoclaw", "openclaw.cmd", "openclaw.ps1", "openclaw")) {
|
|
1142
|
+
$candidate = Join-Path $prefix $name
|
|
1143
|
+
if (Test-Path -LiteralPath $candidate) {
|
|
1144
|
+
return [pscustomobject]@{
|
|
1145
|
+
Source = $candidate
|
|
1146
|
+
Name = [System.IO.Path]::GetFileNameWithoutExtension($candidate)
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
} catch { }
|
|
1152
|
+
|
|
1153
|
+
if (Test-Path -LiteralPath $script:NodeBootstrapRoot) {
|
|
1154
|
+
$dirs = Get-ChildItem -LiteralPath $script:NodeBootstrapRoot -Directory -ErrorAction SilentlyContinue |
|
|
1155
|
+
Sort-Object Name -Descending
|
|
1156
|
+
foreach ($dir in $dirs) {
|
|
1157
|
+
foreach ($name in @("hippoclaw.cmd", "hippoclaw.ps1", "hippoclaw", "openclaw.cmd", "openclaw.ps1", "openclaw")) {
|
|
1158
|
+
$candidate = Join-Path $dir.FullName $name
|
|
1159
|
+
if (Test-Path -LiteralPath $candidate) {
|
|
1160
|
+
return [pscustomobject]@{
|
|
1161
|
+
Source = $candidate
|
|
1162
|
+
Name = [System.IO.Path]::GetFileNameWithoutExtension($candidate)
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
return $null
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
# A CLI shim can exist while the underlying package is broken (e.g. a half-finished
|
|
1173
|
+
# npm install that left dist/ missing). Treat the CLI as functional only when it both
|
|
1174
|
+
# reports a version AND has its dist entry on disk -- otherwise a plain (non-reinstall)
|
|
1175
|
+
# run must still repair it instead of skipping the install and "finishing" broken.
|
|
1176
|
+
function Test-GatewayCliFunctional {
|
|
1177
|
+
$cli = Get-GatewayCliCommand
|
|
1178
|
+
if (-not $cli) { return $false }
|
|
1179
|
+
|
|
1180
|
+
# --version inside a job with a hard timeout, so a broken/hanging shim can never wedge setup.
|
|
1181
|
+
$ver = $null
|
|
1182
|
+
try {
|
|
1183
|
+
$job = Start-Job -ScriptBlock { param($exe) (& $exe --version 2>$null | Select-Object -First 1) } -ArgumentList $cli.Source
|
|
1184
|
+
if (Wait-Job $job -Timeout 20) { $ver = Receive-Job $job } else { Stop-Job $job -ErrorAction SilentlyContinue }
|
|
1185
|
+
Remove-Job $job -Force -ErrorAction SilentlyContinue
|
|
1186
|
+
} catch { $ver = $null }
|
|
1187
|
+
if (-not $ver) { return $false }
|
|
1188
|
+
|
|
1189
|
+
# Verify the package dist entry exists where the CLI resolves (mirrors Check-Installed).
|
|
1190
|
+
$groot = Resolve-ManagedGatewayPackageRoot
|
|
1191
|
+
if (-not $groot -or -not (Test-Path -LiteralPath $groot)) {
|
|
1192
|
+
$groot = Join-Path $script:NpmGlobalPrefix "node_modules\openclaw"
|
|
1193
|
+
}
|
|
1194
|
+
if (-not (Test-Path -LiteralPath $groot)) {
|
|
1195
|
+
$npmRoot = $null
|
|
1196
|
+
try { $npmRoot = (npm root -g 2>$null).Trim() } catch { }
|
|
1197
|
+
if ($npmRoot) { $groot = Join-Path $npmRoot "openclaw" }
|
|
1198
|
+
}
|
|
1199
|
+
if ($groot -and (Test-Path -LiteralPath $groot)) {
|
|
1200
|
+
if ((Test-Path -LiteralPath (Join-Path $groot "dist\entry.mjs")) -or
|
|
1201
|
+
(Test-Path -LiteralPath (Join-Path $groot "dist\entry.js"))) {
|
|
1202
|
+
return $true
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
return $false
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
function Remove-ManagedGatewayShims {
|
|
1209
|
+
param([string]$PrefixDir)
|
|
1210
|
+
if (-not $PrefixDir) { return }
|
|
1211
|
+
foreach ($name in @("openclaw", "openclaw.cmd", "openclaw.ps1", "hippoclaw", "hippoclaw.cmd", "hippoclaw.ps1")) {
|
|
1212
|
+
Remove-Item -Force (Join-Path $PrefixDir $name) -ErrorAction SilentlyContinue
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
function Remove-ManagedOpenclawArtifacts {
|
|
1217
|
+
$legacyManagedOpenclaw = Join-Path $script:NpmGlobalPrefix "lib\node_modules\openclaw"
|
|
1218
|
+
if (Test-Path $legacyManagedOpenclaw) {
|
|
1219
|
+
Log-Info "Removing managed openclaw package from $legacyManagedOpenclaw"
|
|
1220
|
+
Remove-Item -Recurse -Force $legacyManagedOpenclaw -ErrorAction SilentlyContinue
|
|
1221
|
+
}
|
|
1222
|
+
Remove-ManagedGatewayShims -PrefixDir $script:NpmGlobalPrefix
|
|
1223
|
+
|
|
1224
|
+
if (-not (Test-Path -LiteralPath $script:NodeBootstrapRoot)) { return }
|
|
1225
|
+
$dirs = Get-ChildItem -LiteralPath $script:NodeBootstrapRoot -Directory -ErrorAction SilentlyContinue
|
|
1226
|
+
foreach ($dir in $dirs) {
|
|
1227
|
+
$pkgRoot = Join-Path $dir.FullName "lib\node_modules\openclaw"
|
|
1228
|
+
if (Test-Path $pkgRoot) {
|
|
1229
|
+
Log-Info "Removing managed openclaw package from $pkgRoot"
|
|
1230
|
+
Remove-Item -Recurse -Force $pkgRoot -ErrorAction SilentlyContinue
|
|
1231
|
+
}
|
|
1232
|
+
Remove-ManagedGatewayShims -PrefixDir $dir.FullName
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
function Check-Installed {
|
|
1237
|
+
param([switch]$UpdateInstallStatus)
|
|
1238
|
+
|
|
1239
|
+
if ($UpdateInstallStatus) {
|
|
1240
|
+
Update-GatewayInstallStatus -Phase "verifying" -Message "Checking installed components..."
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
Log-Step "Checking installed components..."
|
|
1244
|
+
|
|
1245
|
+
$allOk = $true
|
|
1246
|
+
$cliVersionWorks = $false
|
|
1247
|
+
$wrapperExists = $false
|
|
1248
|
+
$configExists = $false
|
|
1249
|
+
$distExists = $false
|
|
1250
|
+
$webUiExists = $false
|
|
1251
|
+
|
|
1252
|
+
$managedWrapper = Resolve-ManagedGatewayCliPath
|
|
1253
|
+
if ($managedWrapper -and (Test-Path -LiteralPath $managedWrapper)) {
|
|
1254
|
+
$wrapperExists = $true
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
# Gateway CLI binary (prefer hippoclaw from fork, fallback to openclaw)
|
|
1258
|
+
$cliPath = Get-GatewayCliCommand
|
|
1259
|
+
if ($cliPath) {
|
|
1260
|
+
try {
|
|
1261
|
+
$ocVersion = (& $cliPath.Source --version 2>$null | Select-Object -First 1)
|
|
1262
|
+
if ($ocVersion) {
|
|
1263
|
+
Log-Success "Gateway CLI installed ($($cliPath.Name)): $ocVersion"
|
|
1264
|
+
Log-Info "Gateway CLI path: $($cliPath.Source)"
|
|
1265
|
+
$cliVersionWorks = $true
|
|
1266
|
+
} else {
|
|
1267
|
+
throw "version unavailable"
|
|
1268
|
+
}
|
|
1269
|
+
} catch {
|
|
1270
|
+
Log-Warn "Gateway CLI found ($($cliPath.Source)) but command failed (stale/broken shim)"
|
|
1271
|
+
$allOk = $false
|
|
1272
|
+
}
|
|
1273
|
+
} else {
|
|
1274
|
+
Log-Warn "Gateway CLI not installed (hippoclaw/openclaw)"
|
|
1275
|
+
$allOk = $false
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
try {
|
|
1279
|
+
$groot = Resolve-ManagedGatewayPackageRoot
|
|
1280
|
+
if (-not $groot -or -not (Test-Path $groot)) {
|
|
1281
|
+
$groot = Join-Path $script:NpmGlobalPrefix "node_modules\openclaw"
|
|
1282
|
+
}
|
|
1283
|
+
if (-not (Test-Path $groot)) {
|
|
1284
|
+
$npmRoot = (npm root -g 2>$null).Trim()
|
|
1285
|
+
$groot = if ($npmRoot) { Join-Path $npmRoot "openclaw" } else { $null }
|
|
1286
|
+
}
|
|
1287
|
+
if ($groot -and (Test-Path $groot)) {
|
|
1288
|
+
$entryMjs = Join-Path $groot "dist\entry.mjs"
|
|
1289
|
+
$entryJs = Join-Path $groot "dist\entry.js"
|
|
1290
|
+
if ((Test-Path $entryMjs) -or (Test-Path $entryJs)) {
|
|
1291
|
+
Log-Success "CLI dist present ($groot\dist\entry.*)"
|
|
1292
|
+
$distExists = $true
|
|
1293
|
+
} else {
|
|
1294
|
+
Log-Warn "CLI dist missing (reinstall from npm or rerun setup with source build)"
|
|
1295
|
+
$allOk = $false
|
|
1296
|
+
}
|
|
1297
|
+
$uiDir = Join-Path $groot "dist\control-ui"
|
|
1298
|
+
if (Test-Path (Join-Path $uiDir "index.html")) {
|
|
1299
|
+
Log-Success "Web UI built ($uiDir)"
|
|
1300
|
+
$webUiExists = $true
|
|
1301
|
+
} else {
|
|
1302
|
+
Log-Warn "Web UI not built"
|
|
1303
|
+
$allOk = $false
|
|
1304
|
+
}
|
|
1305
|
+
} else {
|
|
1306
|
+
if ($cliPath) {
|
|
1307
|
+
Log-Warn "Global npm openclaw package not found (CLI appears external/non-npm)"
|
|
1308
|
+
} else {
|
|
1309
|
+
Log-Warn "Global npm openclaw package not found"
|
|
1310
|
+
}
|
|
1311
|
+
$allOk = $false
|
|
1312
|
+
}
|
|
1313
|
+
} catch {
|
|
1314
|
+
Log-Warn "Could not verify global openclaw dist (npm root?)"
|
|
1315
|
+
$allOk = $false
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
# Gateway running? Informational only; install succeeds even when stopped.
|
|
1319
|
+
try {
|
|
1320
|
+
$tcp = New-Object System.Net.Sockets.TcpClient
|
|
1321
|
+
$tcp.Connect("127.0.0.1", $Port)
|
|
1322
|
+
$tcp.Close()
|
|
1323
|
+
Log-Success "Gateway running on 127.0.0.1:$Port"
|
|
1324
|
+
} catch {
|
|
1325
|
+
Log-Info "Gateway not running on port $Port (this is OK; start it from Agent Anywhere when needed)"
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
# Config file
|
|
1329
|
+
$configPath = Join-Path $env:USERPROFILE ".openclaw\openclaw.json"
|
|
1330
|
+
if (Test-Path $configPath) {
|
|
1331
|
+
Log-Success "Config file present ($configPath)"
|
|
1332
|
+
$configExists = $true
|
|
1333
|
+
} else {
|
|
1334
|
+
Log-Warn "Config file not found ($configPath)"
|
|
1335
|
+
$allOk = $false
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
if ($UpdateInstallStatus) {
|
|
1339
|
+
$stepUpdates = @{
|
|
1340
|
+
cliVersionWorks = $cliVersionWorks
|
|
1341
|
+
wrapperExists = $wrapperExists
|
|
1342
|
+
configExists = $configExists
|
|
1343
|
+
distExists = $distExists
|
|
1344
|
+
webUiExists = $webUiExists
|
|
1345
|
+
finalCheckPassed = $allOk
|
|
1346
|
+
}
|
|
1347
|
+
if ($allOk) {
|
|
1348
|
+
Complete-GatewayInstallStatus -StepUpdates $stepUpdates -Message "Agent Anywhere is fully installed!"
|
|
1349
|
+
} else {
|
|
1350
|
+
Update-GatewayInstallStatus -Phase "verifying" -Message "Install verification incomplete." -StepUpdates $stepUpdates
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
Write-Host ""
|
|
1355
|
+
if ($allOk) {
|
|
1356
|
+
Write-Host "Agent Anywhere is fully installed!" -ForegroundColor Green
|
|
1357
|
+
} else {
|
|
1358
|
+
Write-Host "Agent Anywhere setup is incomplete." -ForegroundColor Yellow
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
return $allOk
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
function Check-Uninstalled {
|
|
1365
|
+
Log-Step "Checking uninstall state..."
|
|
1366
|
+
|
|
1367
|
+
$allOk = $true
|
|
1368
|
+
|
|
1369
|
+
$cliPath = Get-GatewayCliCommand
|
|
1370
|
+
if ($cliPath) {
|
|
1371
|
+
Log-Warn "Gateway CLI still resolves to $($cliPath.Source) (likely external/non-npm install)"
|
|
1372
|
+
} else {
|
|
1373
|
+
Log-Success "Gateway CLI not installed (hippoclaw/openclaw)"
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
try {
|
|
1377
|
+
$groot = Resolve-ManagedGatewayPackageRoot
|
|
1378
|
+
if (-not $groot -or -not (Test-Path $groot)) {
|
|
1379
|
+
$groot = Join-Path $script:NpmGlobalPrefix "node_modules\openclaw"
|
|
1380
|
+
}
|
|
1381
|
+
if ($groot -and (Test-Path $groot)) {
|
|
1382
|
+
Log-Warn "Managed npm openclaw package still present ($groot)"
|
|
1383
|
+
$allOk = $false
|
|
1384
|
+
} else {
|
|
1385
|
+
Log-Success "Managed npm openclaw package not found"
|
|
1386
|
+
}
|
|
1387
|
+
} catch {
|
|
1388
|
+
Log-Warn "Could not verify managed openclaw package path"
|
|
1389
|
+
$allOk = $false
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
try {
|
|
1393
|
+
$tcp = New-Object System.Net.Sockets.TcpClient
|
|
1394
|
+
$tcp.Connect("127.0.0.1", $Port)
|
|
1395
|
+
$tcp.Close()
|
|
1396
|
+
Log-Warn "Gateway still running on 127.0.0.1:$Port"
|
|
1397
|
+
$allOk = $false
|
|
1398
|
+
} catch {
|
|
1399
|
+
Log-Success "Gateway not running on port $Port"
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
$configPath = Join-Path $env:USERPROFILE ".openclaw\openclaw.json"
|
|
1403
|
+
if (Test-Path $configPath) {
|
|
1404
|
+
Log-Success "Config file preserved ($configPath)"
|
|
1405
|
+
} else {
|
|
1406
|
+
Log-Info "Config file already absent ($configPath)"
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
Write-Host ""
|
|
1410
|
+
if ($allOk) {
|
|
1411
|
+
Write-Host "Agent Anywhere uninstall complete." -ForegroundColor Green
|
|
1412
|
+
} else {
|
|
1413
|
+
Write-Host "Agent Anywhere uninstall needs attention." -ForegroundColor Yellow
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
return $allOk
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
# ============================================================================
|
|
1420
|
+
# Install gateway
|
|
1421
|
+
# ============================================================================
|
|
1422
|
+
|
|
1423
|
+
# Windows holds file handles on running executables/DLLs, so a live gateway node
|
|
1424
|
+
# process keeps the global openclaw tree locked. Stop those processes so the tree
|
|
1425
|
+
# (and its nested deps like @slack/@smithy) can actually be removed before reinstall.
|
|
1426
|
+
function Stop-GatewayProcessesLockingTree {
|
|
1427
|
+
param([string]$PkgRoot)
|
|
1428
|
+
|
|
1429
|
+
# 1) pid recorded by a running gateway
|
|
1430
|
+
$pidPath = Join-Path $env:USERPROFILE ".openclaw\gateway.pid"
|
|
1431
|
+
if (Test-Path $pidPath) {
|
|
1432
|
+
try {
|
|
1433
|
+
$gpid = (Get-Content -LiteralPath $pidPath -ErrorAction SilentlyContinue | Select-Object -First 1)
|
|
1434
|
+
if ($gpid) { Stop-Process -Id ([int]$gpid) -Force -ErrorAction SilentlyContinue }
|
|
1435
|
+
} catch { }
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
# 2) listeners bound to the gateway port(s)
|
|
1439
|
+
$sweepPorts = @($Port)
|
|
1440
|
+
if ($Port -ne 18789) { $sweepPorts += 18789 }
|
|
1441
|
+
foreach ($sp in ($sweepPorts | Select-Object -Unique)) {
|
|
1442
|
+
Stop-ListenersOnGatewayPort $sp
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
# 3) any node process running from inside the global openclaw tree
|
|
1446
|
+
if ($PkgRoot) {
|
|
1447
|
+
try {
|
|
1448
|
+
$procs = Get-CimInstance Win32_Process -Filter "Name='node.exe'" -ErrorAction SilentlyContinue
|
|
1449
|
+
foreach ($p in $procs) {
|
|
1450
|
+
if ($p.CommandLine -and $p.CommandLine -like "*$PkgRoot*") {
|
|
1451
|
+
Stop-Process -Id $p.ProcessId -Force -ErrorAction SilentlyContinue
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
} catch { }
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
Start-Sleep -Milliseconds 500
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
# Robustly remove the global openclaw package tree: stop lockers, then retry with
|
|
1461
|
+
# backoff so npm's own rmdir doesn't fail later with EPERM/ENOTEMPTY on Windows.
|
|
1462
|
+
function Remove-OpenclawGlobalTreeRobust {
|
|
1463
|
+
param([string]$PkgRoot)
|
|
1464
|
+
if (-not $PkgRoot -or -not (Test-Path -LiteralPath $PkgRoot)) { return $true }
|
|
1465
|
+
Stop-GatewayProcessesLockingTree -PkgRoot $PkgRoot
|
|
1466
|
+
for ($i = 0; $i -lt 5; $i++) {
|
|
1467
|
+
Remove-Item -Recurse -Force -LiteralPath $PkgRoot -ErrorAction SilentlyContinue
|
|
1468
|
+
if (-not (Test-Path -LiteralPath $PkgRoot)) { return $true }
|
|
1469
|
+
Start-Sleep -Milliseconds (400 * ($i + 1))
|
|
1470
|
+
}
|
|
1471
|
+
return (-not (Test-Path -LiteralPath $PkgRoot))
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
function Install-Gateway {
|
|
1475
|
+
if (-not $Source) {
|
|
1476
|
+
Log-Error "No install source specified. Use -Source <source>"
|
|
1477
|
+
Fail-GatewayInstallStatus -Message "No install source specified."
|
|
1478
|
+
exit 1
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
$script:RemoteGatewayCloneSrc = $null
|
|
1482
|
+
$script:RemoteGatewayWorkDir = $null
|
|
1483
|
+
|
|
1484
|
+
Log-Step "Installing OpenClaw Gateway..."
|
|
1485
|
+
Log-Info "Source: $Source"
|
|
1486
|
+
Update-GatewayInstallStatus -Phase "installing" -Message "Installing Gateway CLI..."
|
|
1487
|
+
|
|
1488
|
+
$npmRoot = $null
|
|
1489
|
+
try {
|
|
1490
|
+
$npmRoot = (npm root -g 2>$null).Trim()
|
|
1491
|
+
} catch { }
|
|
1492
|
+
|
|
1493
|
+
if ($npmRoot -and (Test-Path (Join-Path $npmRoot "openclaw"))) {
|
|
1494
|
+
$existingPkg = Join-Path $npmRoot "openclaw"
|
|
1495
|
+
Log-Info "Removing existing global openclaw tree (avoids partial install)..."
|
|
1496
|
+
if (-not (Remove-OpenclawGlobalTreeRobust -PkgRoot $existingPkg)) {
|
|
1497
|
+
Log-Warn "Could not fully remove $existingPkg (files may be locked by a running gateway)."
|
|
1498
|
+
Log-Warn "Close any running gateway/openclaw process and retry, or run with -Uninstall first."
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
$isLocal = Test-InstallSourceLocal -S $Source
|
|
1503
|
+
|
|
1504
|
+
try {
|
|
1505
|
+
if (Test-SourceNeedsBuild -S $Source) {
|
|
1506
|
+
if ($isLocal) {
|
|
1507
|
+
$absSrc = (Resolve-Path -LiteralPath $Source).Path
|
|
1508
|
+
try {
|
|
1509
|
+
Invoke-OpenclawRepoBuild -RepoDir $absSrc
|
|
1510
|
+
} catch {
|
|
1511
|
+
Log-Error "OpenClaw source build failed: $_"
|
|
1512
|
+
Fail-GatewayInstallStatus -Message "OpenClaw source build failed."
|
|
1513
|
+
exit 1
|
|
1514
|
+
}
|
|
1515
|
+
npm install -g $absSrc
|
|
1516
|
+
if ($LASTEXITCODE -ne 0) {
|
|
1517
|
+
Log-Error "npm install failed"
|
|
1518
|
+
Fail-GatewayInstallStatus -Message "npm install failed."
|
|
1519
|
+
exit 1
|
|
1520
|
+
}
|
|
1521
|
+
} else {
|
|
1522
|
+
Install-OpenclawFromRemoteGitSpec -Spec $Source
|
|
1523
|
+
}
|
|
1524
|
+
} else {
|
|
1525
|
+
npm install -g $Source
|
|
1526
|
+
if ($LASTEXITCODE -ne 0) {
|
|
1527
|
+
Log-Error "npm install failed"
|
|
1528
|
+
Fail-GatewayInstallStatus -Message "npm install failed."
|
|
1529
|
+
exit 1
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
Log-Success "npm install complete"
|
|
1533
|
+
Update-GatewayInstallStatus -Phase "installing" -Message "CLI install complete; preparing managed wrapper..." -StepUpdates @{ npmInstallComplete = $true }
|
|
1534
|
+
Ensure-ManagedGatewayWrappers | Out-Null
|
|
1535
|
+
$wrapperPath = Resolve-ManagedGatewayCliPath
|
|
1536
|
+
if ($wrapperPath -and (Test-Path -LiteralPath $wrapperPath)) {
|
|
1537
|
+
Update-GatewayInstallStatus -Phase "installing" -Message "Managed wrapper ready; preparing config..." -StepUpdates @{ wrapperExists = $true }
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
if (Test-SourceNeedsBuild -S $Source) {
|
|
1541
|
+
Log-Info "OpenClaw built from source; global install includes dist/."
|
|
1542
|
+
} else {
|
|
1543
|
+
Log-Info "Published package -- web UI should be pre-built"
|
|
1544
|
+
}
|
|
1545
|
+
} finally {
|
|
1546
|
+
if ($script:RemoteGatewayWorkDir -and (Test-Path $script:RemoteGatewayWorkDir)) {
|
|
1547
|
+
Remove-Item -Recurse -Force $script:RemoteGatewayWorkDir -ErrorAction SilentlyContinue
|
|
1548
|
+
}
|
|
1549
|
+
$script:RemoteGatewayWorkDir = $null
|
|
1550
|
+
$script:RemoteGatewayCloneSrc = $null
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
function Test-GatewayPortOpen([int]$ListenPort) {
|
|
1555
|
+
try {
|
|
1556
|
+
$tcp = New-Object System.Net.Sockets.TcpClient
|
|
1557
|
+
$tcp.Connect("127.0.0.1", $ListenPort)
|
|
1558
|
+
$tcp.Close()
|
|
1559
|
+
return $true
|
|
1560
|
+
} catch { return $false }
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
function Stop-ListenersOnGatewayPort([int]$ListenPort) {
|
|
1564
|
+
if (-not (Test-GatewayPortOpen $ListenPort)) { return }
|
|
1565
|
+
Log-Info "Port $ListenPort still in use - stopping listener process(es)..."
|
|
1566
|
+
try {
|
|
1567
|
+
$conns = Get-NetTCPConnection -LocalPort $ListenPort -State Listen -ErrorAction SilentlyContinue
|
|
1568
|
+
foreach ($c in $conns) {
|
|
1569
|
+
Stop-Process -Id $c.OwningProcess -Force -ErrorAction SilentlyContinue
|
|
1570
|
+
}
|
|
1571
|
+
} catch { }
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
# After npm removes the CLI: free loopback listener(s). Service teardown is openclaw uninstall --service.
|
|
1575
|
+
function Stop-OrphanGatewayListenersOnPorts {
|
|
1576
|
+
Log-Step "Clearing local gateway listener(s) if still bound..."
|
|
1577
|
+
$pidPath = Join-Path $env:USERPROFILE ".openclaw\gateway.pid"
|
|
1578
|
+
Remove-Item -Path $pidPath -ErrorAction SilentlyContinue
|
|
1579
|
+
$sweepPorts = @($Port)
|
|
1580
|
+
if ($Port -ne 18789) { $sweepPorts += 18789 }
|
|
1581
|
+
foreach ($sp in ($sweepPorts | Select-Object -Unique)) {
|
|
1582
|
+
Stop-ListenersOnGatewayPort $sp
|
|
1583
|
+
}
|
|
1584
|
+
Start-Sleep -Seconds 1
|
|
1585
|
+
$anyUp = $false
|
|
1586
|
+
foreach ($sp in ($sweepPorts | Select-Object -Unique)) {
|
|
1587
|
+
if (Test-GatewayPortOpen $sp) { $anyUp = $true; break }
|
|
1588
|
+
}
|
|
1589
|
+
if ($anyUp) {
|
|
1590
|
+
Log-Warn "A process may still be listening on 127.0.0.1 (ports: $($sweepPorts -join ', '))"
|
|
1591
|
+
} else {
|
|
1592
|
+
Log-Success "Gateway port(s) free on 127.0.0.1 ($($sweepPorts -join ', '))"
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
function Invoke-OpenclawUninstallService {
|
|
1597
|
+
$oc = Get-GatewayCliCommand
|
|
1598
|
+
if (-not $oc) { return }
|
|
1599
|
+
Log-Step "OpenClaw CLI: uninstall gateway service..."
|
|
1600
|
+
Log-Info "Running: $($oc.Source) uninstall --service --yes --non-interactive"
|
|
1601
|
+
$prevEap = $ErrorActionPreference
|
|
1602
|
+
$ErrorActionPreference = "Continue"
|
|
1603
|
+
try {
|
|
1604
|
+
& $oc.Source uninstall --service --yes --non-interactive
|
|
1605
|
+
} catch { }
|
|
1606
|
+
$ErrorActionPreference = $prevEap
|
|
1607
|
+
if ($LASTEXITCODE -eq 0) {
|
|
1608
|
+
Log-Success "openclaw uninstall --service completed"
|
|
1609
|
+
} else {
|
|
1610
|
+
Log-Info "openclaw uninstall --service failed or skipped (continuing)"
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
function Remove-ResolvedCliOpenclawInstall {
|
|
1615
|
+
# Remove the openclaw package wherever the CLI on PATH actually resolves to (the npm global
|
|
1616
|
+
# prefix that owns the shim), not just the active/managed prefix `npm uninstall -g` covers.
|
|
1617
|
+
# Bounded loop in case more than one install is present on PATH.
|
|
1618
|
+
for ($i = 0; $i -lt 8; $i++) {
|
|
1619
|
+
$cli = $null
|
|
1620
|
+
$hc = Get-Command hippoclaw -ErrorAction SilentlyContinue
|
|
1621
|
+
if ($hc) { $cli = $hc.Source }
|
|
1622
|
+
else {
|
|
1623
|
+
$oc = Get-Command openclaw -ErrorAction SilentlyContinue
|
|
1624
|
+
if ($oc) { $cli = $oc.Source }
|
|
1625
|
+
}
|
|
1626
|
+
if (-not $cli) { break }
|
|
1627
|
+
$prefix = Split-Path -Parent $cli
|
|
1628
|
+
if (-not $prefix) { break }
|
|
1629
|
+
# Windows npm global layout: <prefix>\node_modules\openclaw plus shims in <prefix>.
|
|
1630
|
+
$pkgRoot = Join-Path $prefix "node_modules\openclaw"
|
|
1631
|
+
if (Test-Path -LiteralPath $pkgRoot) {
|
|
1632
|
+
Log-Info "Removing openclaw package tree resolved via CLI on PATH: $pkgRoot"
|
|
1633
|
+
Remove-Item -Recurse -Force -LiteralPath $pkgRoot -ErrorAction SilentlyContinue
|
|
1634
|
+
}
|
|
1635
|
+
Remove-ManagedGatewayShims -PrefixDir $prefix
|
|
1636
|
+
$still = Get-Command hippoclaw -ErrorAction SilentlyContinue
|
|
1637
|
+
if (-not $still) { $still = Get-Command openclaw -ErrorAction SilentlyContinue }
|
|
1638
|
+
if (-not $still) { break }
|
|
1639
|
+
if ($still.Source -eq $cli) { break }
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
function Uninstall-Gateway {
|
|
1644
|
+
$null = Ensure-NodeNpm
|
|
1645
|
+
Invoke-OpenclawUninstallService
|
|
1646
|
+
Write-Host ""
|
|
1647
|
+
Log-Step "Uninstalling OpenClaw (global npm package)..."
|
|
1648
|
+
if (-not (Get-Command npm -ErrorAction SilentlyContinue)) {
|
|
1649
|
+
Log-Error "npm not found"
|
|
1650
|
+
exit 1
|
|
1651
|
+
}
|
|
1652
|
+
npm uninstall -g openclaw 2>$null
|
|
1653
|
+
if ($LASTEXITCODE -ne 0) {
|
|
1654
|
+
Log-Warn "npm uninstall returned exit code $LASTEXITCODE (package may not have been installed)"
|
|
1655
|
+
}
|
|
1656
|
+
Remove-ManagedGatewayWrapperState
|
|
1657
|
+
Cleanup-UserGatewayEnvironment
|
|
1658
|
+
# Also remove the install wherever the CLI actually resolves (other Node global prefixes),
|
|
1659
|
+
# not just the active node + managed prefix that `npm uninstall -g` above covers.
|
|
1660
|
+
Remove-ResolvedCliOpenclawInstall
|
|
1661
|
+
Log-Success "Ran: npm uninstall -g openclaw (global tree removed if present)"
|
|
1662
|
+
Log-Info "~/.openclaw was not removed (config, sessions, and credentials stay on disk)."
|
|
1663
|
+
$ocAfter = Get-Command hippoclaw -ErrorAction SilentlyContinue
|
|
1664
|
+
if (-not $ocAfter) { $ocAfter = Get-Command openclaw -ErrorAction SilentlyContinue }
|
|
1665
|
+
if ($ocAfter) {
|
|
1666
|
+
Log-Warn "CLI still resolves to $($ocAfter.Source) (could not be removed automatically; remove it manually)."
|
|
1667
|
+
}
|
|
1668
|
+
Write-Host ""
|
|
1669
|
+
Stop-OrphanGatewayListenersOnPorts
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
# ============================================================================
|
|
1673
|
+
# Write starter config
|
|
1674
|
+
# ============================================================================
|
|
1675
|
+
function Write-Config {
|
|
1676
|
+
$configPath = Join-Path $env:USERPROFILE ".openclaw\openclaw.json"
|
|
1677
|
+
|
|
1678
|
+
if (Test-Path $configPath) {
|
|
1679
|
+
Log-Info "Config already exists at $configPath -- skipping"
|
|
1680
|
+
Update-GatewayInstallStatus -Phase "installing" -Message "Config already exists; verifying install..." -StepUpdates @{ configExists = $true }
|
|
1681
|
+
return
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
Log-Step "Writing starter config..."
|
|
1685
|
+
Update-GatewayInstallStatus -Phase "installing" -Message "Writing starter config..."
|
|
1686
|
+
$configDir = Split-Path $configPath -Parent
|
|
1687
|
+
New-Item -ItemType Directory -Path $configDir -Force | Out-Null
|
|
1688
|
+
|
|
1689
|
+
# Generate a random auth token
|
|
1690
|
+
$bytes = New-Object byte[] 24
|
|
1691
|
+
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes)
|
|
1692
|
+
$randomToken = "ah-" + ([System.BitConverter]::ToString($bytes) -replace '-','').ToLower()
|
|
1693
|
+
|
|
1694
|
+
if ($ConfigTemplate -and (Test-Path $ConfigTemplate)) {
|
|
1695
|
+
# Copy template and replace placeholder token
|
|
1696
|
+
$content = Get-Content $ConfigTemplate -Raw
|
|
1697
|
+
$content = $content -replace '__GENERATED_TOKEN__', $randomToken
|
|
1698
|
+
[System.IO.File]::WriteAllBytes($configPath, [System.Text.Encoding]::UTF8.GetBytes($content))
|
|
1699
|
+
Log-Success "Config written from template: $configPath"
|
|
1700
|
+
Update-GatewayInstallStatus -Phase "installing" -Message "Config written; verifying install..." -StepUpdates @{ configExists = $true }
|
|
1701
|
+
} else {
|
|
1702
|
+
$minimalConfig = @"
|
|
1703
|
+
// OpenClaw Gateway Configuration (JSON5)
|
|
1704
|
+
// Docs: https://docs.openclaw.ai/configuration
|
|
1705
|
+
{
|
|
1706
|
+
"gateway": { "mode": "local", "auth": { "token": "$randomToken" } },
|
|
1707
|
+
"update": { "checkOnStart": false, "managedMode": true },
|
|
1708
|
+
"bindings": [],
|
|
1709
|
+
"channels": {},
|
|
1710
|
+
"plugins": { "entries": {} },
|
|
1711
|
+
"session": { "dmScope": "per-peer" },
|
|
1712
|
+
"agents": { "defaults": { "maxConcurrent": 4 } }
|
|
1713
|
+
}
|
|
1714
|
+
"@
|
|
1715
|
+
[System.IO.File]::WriteAllBytes($configPath, [System.Text.Encoding]::UTF8.GetBytes($minimalConfig))
|
|
1716
|
+
Log-Success "Starter config written: $configPath"
|
|
1717
|
+
Update-GatewayInstallStatus -Phase "installing" -Message "Config written; verifying install..." -StepUpdates @{ configExists = $true }
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
Write-Host ""
|
|
1721
|
+
Write-Host "Next: Edit $configPath to add your channels (Telegram, WhatsApp, etc.)" -ForegroundColor Cyan
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
# ============================================================================
|
|
1725
|
+
# Main
|
|
1726
|
+
# ============================================================================
|
|
1727
|
+
|
|
1728
|
+
Write-Host ""
|
|
1729
|
+
Write-Host " +---------------------------------------+" -ForegroundColor Cyan
|
|
1730
|
+
Write-Host " | Agent Anywhere Setup |" -ForegroundColor Cyan
|
|
1731
|
+
Write-Host " | Reach your agents from anywhere |" -ForegroundColor Cyan
|
|
1732
|
+
Write-Host " +---------------------------------------+" -ForegroundColor Cyan
|
|
1733
|
+
Write-Host ""
|
|
1734
|
+
|
|
1735
|
+
if ($Check) {
|
|
1736
|
+
$result = Check-Installed
|
|
1737
|
+
if ($result) { exit 0 } else { exit 1 }
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
if ($Reinstall) {
|
|
1741
|
+
if (-not $Source) {
|
|
1742
|
+
Log-Error "-Reinstall requires -Source <src>"
|
|
1743
|
+
Fail-GatewayInstallStatus -Message "Reinstall requires an install source."
|
|
1744
|
+
exit 1
|
|
1745
|
+
}
|
|
1746
|
+
Initialize-GatewayInstallStatus -Phase "checking-prerequisites" -Message "Starting reinstall..."
|
|
1747
|
+
Log-Step "Reinstall: uninstall -> verify -> install"
|
|
1748
|
+
Uninstall-Gateway
|
|
1749
|
+
Write-Host ""
|
|
1750
|
+
Log-Step "Post-uninstall verification (-Check)..."
|
|
1751
|
+
Check-Uninstalled | Out-Null
|
|
1752
|
+
Write-Host ""
|
|
1753
|
+
if (-not (Check-Prerequisites)) {
|
|
1754
|
+
Write-Host ""
|
|
1755
|
+
Log-Error "Prerequisites not met. Install the missing tools and try again."
|
|
1756
|
+
Fail-GatewayInstallStatus -Message "Prerequisites not met."
|
|
1757
|
+
exit 1
|
|
1758
|
+
}
|
|
1759
|
+
Write-Host ""
|
|
1760
|
+
Install-Gateway
|
|
1761
|
+
Write-Config
|
|
1762
|
+
Write-Host ""
|
|
1763
|
+
Check-Installed -UpdateInstallStatus | Out-Null
|
|
1764
|
+
Write-Host ""
|
|
1765
|
+
Write-Host "Reinstall complete. Next steps:" -ForegroundColor White
|
|
1766
|
+
Write-Host " 1. Edit " -NoNewline; Write-Host "~\.openclaw\openclaw.json" -ForegroundColor Cyan -NoNewline; Write-Host " to add your channels"
|
|
1767
|
+
Write-Host " 2. Click " -NoNewline; Write-Host "Agent Anywhere" -ForegroundColor Cyan -NoNewline; Write-Host " to start."
|
|
1768
|
+
Write-Host ""
|
|
1769
|
+
exit 0
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
if ($Uninstall) {
|
|
1773
|
+
Remove-Item -Path $script:GatewayInstallStatusPath -Force -ErrorAction SilentlyContinue
|
|
1774
|
+
Uninstall-Gateway
|
|
1775
|
+
Write-Host ""
|
|
1776
|
+
Check-Uninstalled | Out-Null
|
|
1777
|
+
exit 0
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
Initialize-GatewayInstallStatus -Phase "checking-prerequisites" -Message "Checking prerequisites..."
|
|
1781
|
+
|
|
1782
|
+
# Prerequisites
|
|
1783
|
+
if (-not (Check-Prerequisites)) {
|
|
1784
|
+
Write-Host ""
|
|
1785
|
+
Log-Error "Prerequisites not met. Install the missing tools and try again."
|
|
1786
|
+
Fail-GatewayInstallStatus -Message "Prerequisites not met."
|
|
1787
|
+
exit 1
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
# Install if not present OR if the resolved CLI is broken (shim exists but dist/ missing,
|
|
1791
|
+
# e.g. left behind by an earlier failed npm install). A bare presence check would skip the
|
|
1792
|
+
# install and "finish" in a broken state.
|
|
1793
|
+
if (-not (Test-GatewayCliFunctional)) {
|
|
1794
|
+
Write-Host ""
|
|
1795
|
+
Install-Gateway
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
if (-not (Resolve-ManagedGatewayCliPath) -and (Resolve-ManagedGatewayInstall)) {
|
|
1799
|
+
Ensure-ManagedGatewayWrappers | Out-Null
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
# Write config if missing
|
|
1803
|
+
Write-Config
|
|
1804
|
+
|
|
1805
|
+
# Final status
|
|
1806
|
+
Write-Host ""
|
|
1807
|
+
Check-Installed -UpdateInstallStatus | Out-Null
|
|
1808
|
+
|
|
1809
|
+
Write-Host ""
|
|
1810
|
+
Write-Host "Done! Next steps:" -ForegroundColor White
|
|
1811
|
+
Write-Host " 1. Edit " -NoNewline; Write-Host "~\.openclaw\openclaw.json" -ForegroundColor Cyan -NoNewline; Write-Host " to add your channels"
|
|
1812
|
+
Write-Host " 2. Click " -NoNewline; Write-Host "Agent Anywhere" -ForegroundColor Cyan -NoNewline; Write-Host " to start."
|
|
1813
|
+
Write-Host ""
|