@xyagent/cli 0.0.1
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/README.md +860 -0
- package/bin/agentlink +8585 -0
- package/bin/agentlink-agent +7 -0
- package/bin/agentlink-mcp-stdio +173 -0
- package/docs/LOGGING.md +159 -0
- package/package.json +38 -0
- package/src/core.mjs +320 -0
- package/src/tunnel.mjs +291 -0
- package/src/tunnel_proxy.mjs +913 -0
- package/src/tunnel_service.mjs +699 -0
- package/src/tunnel_state.mjs +301 -0
- package/src/unified_producer.mjs +259 -0
- package/src-ext/README.md +75 -0
- package/src-ext/bin.mjs +128 -0
- package/src-ext/commands/agent.mjs +66 -0
- package/src-ext/commands/help.mjs +31 -0
- package/src-ext/commands/pair.mjs +455 -0
- package/src-ext/commands/reload.mjs +78 -0
- package/src-ext/commands/service.mjs +64 -0
- package/src-ext/core/accountResolver.mjs +137 -0
- package/src-ext/core/activeRuns.mjs +76 -0
- package/src-ext/core/agentlinkToolsBootstrap.mjs +75 -0
- package/src-ext/core/agentlinkToolsRegistry.mjs +323 -0
- package/src-ext/core/agentlinkToolsServer.mjs +109 -0
- package/src-ext/core/approvalGateway.mjs +132 -0
- package/src-ext/core/attachAuditLog.mjs +79 -0
- package/src-ext/core/attachDenylist.mjs +128 -0
- package/src-ext/core/autoTunnelDetector.mjs +98 -0
- package/src-ext/core/autoTunnelGateway.mjs +393 -0
- package/src-ext/core/autoTunnelWiring.mjs +184 -0
- package/src-ext/core/boundedMap.mjs +98 -0
- package/src-ext/core/bridgeAttachAutoScanner.mjs +237 -0
- package/src-ext/core/bridgeHooks.mjs +168 -0
- package/src-ext/core/bridgeSelfUninstall.mjs +133 -0
- package/src-ext/core/claudeTrust.mjs +74 -0
- package/src-ext/core/codexTrust.mjs +77 -0
- package/src-ext/core/cosUploadClient.mjs +326 -0
- package/src-ext/core/createWorkspace.mjs +170 -0
- package/src-ext/core/daemonRestart.mjs +49 -0
- package/src-ext/core/defaultWorkspace.mjs +65 -0
- package/src-ext/core/ensureGitRepo.mjs +57 -0
- package/src-ext/core/hermesProfile.mjs +75 -0
- package/src-ext/core/interruptGateway.mjs +119 -0
- package/src-ext/core/interruptRunListener.mjs +106 -0
- package/src-ext/core/mcpRuntimeFanout.mjs +236 -0
- package/src-ext/core/mcpStdioClient.mjs +316 -0
- package/src-ext/core/openclawGatewayClient.mjs +230 -0
- package/src-ext/core/pairCodeClient.mjs +331 -0
- package/src-ext/core/pairInventory.mjs +59 -0
- package/src-ext/core/pathExpand.mjs +34 -0
- package/src-ext/core/preprocessAttachments.mjs +113 -0
- package/src-ext/core/relayWorker.mjs +284 -0
- package/src-ext/core/relayWorkerHttp.mjs +58 -0
- package/src-ext/core/scanWorkspaces.mjs +842 -0
- package/src-ext/core/sessionSlot.mjs +70 -0
- package/src-ext/core/stateMachine.mjs +85 -0
- package/src-ext/core/toolsServerLifecycle.mjs +169 -0
- package/src-ext/core/unifiedDispatchHandler.mjs +439 -0
- package/src-ext/core/usageReporter.mjs +207 -0
- package/src-ext/openclaw-plugin/envelope-builder.cjs +619 -0
- package/src-ext/openclaw-plugin/index.cjs +1919 -0
- package/src-ext/openclaw-plugin/openclaw.plugin.json +20 -0
- package/src-ext/openclaw-plugin/package.json +12 -0
- package/src-ext/openclaw-plugin/relay-defaults.json +3 -0
- package/src-ext/openclaw-plugin/todoTranslatorUtils.cjs +101 -0
- package/src-ext/runtime/_shared/cliExec.mjs +138 -0
- package/src-ext/runtime/_shared/cosTextRefs.mjs +120 -0
- package/src-ext/runtime/_shared/fetchAndBase64Encode.mjs +52 -0
- package/src-ext/runtime/_shared/relayObjectToBlock.mjs +307 -0
- package/src-ext/runtime/_shared/sessionPicker.mjs +418 -0
- package/src-ext/runtime/_shared/slashCommandRouter.mjs +1346 -0
- package/src-ext/runtime/_shared/todoTranslatorUtils.mjs +94 -0
- package/src-ext/runtime/claude/askUserQuestionTranslator.mjs +241 -0
- package/src-ext/runtime/claude/customCommandsCollector.mjs +132 -0
- package/src-ext/runtime/claude/handleRequest.mjs +1418 -0
- package/src-ext/runtime/claude/index.mjs +160 -0
- package/src-ext/runtime/claude/internalCommandNames.mjs +58 -0
- package/src-ext/runtime/claude/launcher.mjs +313 -0
- package/src-ext/runtime/claude/mcpConfigAdapter.mjs +174 -0
- package/src-ext/runtime/claude/mcpConfigWriter.mjs +57 -0
- package/src-ext/runtime/claude/modelContextWindow.mjs +30 -0
- package/src-ext/runtime/claude/modelScanner.mjs +257 -0
- package/src-ext/runtime/claude/permissionInterruptBlock.mjs +86 -0
- package/src-ext/runtime/claude/permissionPromptServer.mjs +170 -0
- package/src-ext/runtime/claude/permissionPromptServerWorker.mjs +214 -0
- package/src-ext/runtime/claude/preflight.mjs +62 -0
- package/src-ext/runtime/claude/stdoutParser.mjs +365 -0
- package/src-ext/runtime/claude/todoTranslator.mjs +66 -0
- package/src-ext/runtime/claude/usageProbe.mjs +576 -0
- package/src-ext/runtime/claude/usageProbeStrip.mjs +14 -0
- package/src-ext/runtime/codex/codexCustomCommandsCollector.mjs +87 -0
- package/src-ext/runtime/codex/elicitationHandler.mjs +91 -0
- package/src-ext/runtime/codex/eventMapper.mjs +154 -0
- package/src-ext/runtime/codex/handleRequest.mjs +1152 -0
- package/src-ext/runtime/codex/index.mjs +142 -0
- package/src-ext/runtime/codex/mcpConfigAdapter.mjs +155 -0
- package/src-ext/runtime/codex/modelScanner.mjs +305 -0
- package/src-ext/runtime/codex/planNotificationHandler.mjs +61 -0
- package/src-ext/runtime/codex/preflight.mjs +67 -0
- package/src-ext/runtime/hermes/commandBackend.mjs +117 -0
- package/src-ext/runtime/hermes/envSetup.mjs +229 -0
- package/src-ext/runtime/hermes/gatewayManager.mjs +625 -0
- package/src-ext/runtime/hermes/handleRequest.mjs +1257 -0
- package/src-ext/runtime/hermes/httpBackend.mjs +219 -0
- package/src-ext/runtime/hermes/index.mjs +196 -0
- package/src-ext/runtime/hermes/mcpConfigAdapter.mjs +189 -0
- package/src-ext/runtime/hermes/preflight.mjs +359 -0
- package/src-ext/runtime/hermes/responsesBackend.mjs +276 -0
- package/src-ext/runtime/hermes/sessionStore.mjs +78 -0
- package/src-ext/runtime/hermes/todoTranslator.mjs +90 -0
- package/src-ext/runtime/hermes/workspaceRpc.mjs +124 -0
- package/src-ext/runtime/openclaw/buildOpenclawDaemonInput.mjs +143 -0
- package/src-ext/runtime/openclaw/mcpConfigAdapter.mjs +91 -0
- package/src-ext/runtime/openclaw/openclawConfig.mjs +145 -0
- package/src-ext/runtime/picoclaw/constants.mjs +39 -0
- package/src-ext/runtime/picoclaw/handleRequest.mjs +289 -0
- package/src-ext/runtime/picoclaw/index.mjs +314 -0
- package/src-ext/runtime/picoclaw/pairFlow.mjs +224 -0
- package/src-ext/runtime/picoclaw/state.mjs +78 -0
- package/src-ext/runtime/picoclaw/todoTranslator.mjs +67 -0
- package/src-ext/runtime/picoclaw/translator.mjs +272 -0
- package/src-ext/runtime/picoclaw/wsClient.mjs +129 -0
- package/src-ext/service/serviceManager.mjs +521 -0
- package/src-shared/README.md +44 -0
- package/src-shared/chat_push_normalizer.mjs +113 -0
- package/src-shared/correlation.mjs +25 -0
- package/src-shared/envelope_builder.mjs +612 -0
- package/src-shared/logger.mjs +167 -0
- package/src-shared/relay-defaults.json +3 -0
- package/src-shared/relay_revoke.mjs +46 -0
- package/src-shared/vendor/README.md +60 -0
- package/src-shared/vendor/smol-toml/LICENSE +24 -0
- package/src-shared/vendor/smol-toml/README.md +236 -0
- package/src-shared/vendor/smol-toml/VENDORED.md +37 -0
- package/src-shared/vendor/smol-toml/dist/date.d.ts +41 -0
- package/src-shared/vendor/smol-toml/dist/date.js +127 -0
- package/src-shared/vendor/smol-toml/dist/error.d.ts +38 -0
- package/src-shared/vendor/smol-toml/dist/error.js +63 -0
- package/src-shared/vendor/smol-toml/dist/extract.d.ts +30 -0
- package/src-shared/vendor/smol-toml/dist/extract.js +109 -0
- package/src-shared/vendor/smol-toml/dist/index.cjs +900 -0
- package/src-shared/vendor/smol-toml/dist/index.d.ts +43 -0
- package/src-shared/vendor/smol-toml/dist/index.js +33 -0
- package/src-shared/vendor/smol-toml/dist/parse.d.ts +37 -0
- package/src-shared/vendor/smol-toml/dist/parse.js +148 -0
- package/src-shared/vendor/smol-toml/dist/primitive.d.ts +31 -0
- package/src-shared/vendor/smol-toml/dist/primitive.js +178 -0
- package/src-shared/vendor/smol-toml/dist/stringify.d.ts +31 -0
- package/src-shared/vendor/smol-toml/dist/stringify.js +163 -0
- package/src-shared/vendor/smol-toml/dist/struct.d.ts +32 -0
- package/src-shared/vendor/smol-toml/dist/struct.js +194 -0
- package/src-shared/vendor/smol-toml/dist/util.d.ts +42 -0
- package/src-shared/vendor/smol-toml/dist/util.js +100 -0
- package/src-shared/vendor/smol-toml/package.json +54 -0
- package/src-shared/vendor/yaml/LICENSE +13 -0
- package/src-shared/vendor/yaml/README.md +155 -0
- package/src-shared/vendor/yaml/VENDORED.md +29 -0
- package/src-shared/vendor/yaml/bin.mjs +11 -0
- package/src-shared/vendor/yaml/browser/dist/compose/compose-collection.js +88 -0
- package/src-shared/vendor/yaml/browser/dist/compose/compose-doc.js +42 -0
- package/src-shared/vendor/yaml/browser/dist/compose/compose-node.js +92 -0
- package/src-shared/vendor/yaml/browser/dist/compose/compose-scalar.js +80 -0
- package/src-shared/vendor/yaml/browser/dist/compose/composer.js +217 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-block-map.js +113 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-block-scalar.js +198 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-block-seq.js +47 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-end.js +37 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-flow-collection.js +203 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-flow-scalar.js +223 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-props.js +148 -0
- package/src-shared/vendor/yaml/browser/dist/compose/util-contains-newline.js +34 -0
- package/src-shared/vendor/yaml/browser/dist/compose/util-empty-scalar-position.js +27 -0
- package/src-shared/vendor/yaml/browser/dist/compose/util-flow-indent-check.js +15 -0
- package/src-shared/vendor/yaml/browser/dist/compose/util-map-includes.js +17 -0
- package/src-shared/vendor/yaml/browser/dist/doc/Document.js +334 -0
- package/src-shared/vendor/yaml/browser/dist/doc/anchors.js +72 -0
- package/src-shared/vendor/yaml/browser/dist/doc/applyReviver.js +55 -0
- package/src-shared/vendor/yaml/browser/dist/doc/createNode.js +89 -0
- package/src-shared/vendor/yaml/browser/dist/doc/directives.js +176 -0
- package/src-shared/vendor/yaml/browser/dist/errors.js +57 -0
- package/src-shared/vendor/yaml/browser/dist/index.js +17 -0
- package/src-shared/vendor/yaml/browser/dist/log.js +14 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/Alias.js +101 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/Collection.js +147 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/Node.js +38 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/Pair.js +36 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/Scalar.js +24 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/YAMLMap.js +144 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/YAMLSeq.js +113 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/addPairToJSMap.js +104 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/identity.js +36 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/toJS.js +37 -0
- package/src-shared/vendor/yaml/browser/dist/parse/cst-scalar.js +214 -0
- package/src-shared/vendor/yaml/browser/dist/parse/cst-stringify.js +61 -0
- package/src-shared/vendor/yaml/browser/dist/parse/cst-visit.js +97 -0
- package/src-shared/vendor/yaml/browser/dist/parse/cst.js +98 -0
- package/src-shared/vendor/yaml/browser/dist/parse/lexer.js +717 -0
- package/src-shared/vendor/yaml/browser/dist/parse/line-counter.js +39 -0
- package/src-shared/vendor/yaml/browser/dist/parse/parser.js +954 -0
- package/src-shared/vendor/yaml/browser/dist/public-api.js +99 -0
- package/src-shared/vendor/yaml/browser/dist/schema/Schema.js +38 -0
- package/src-shared/vendor/yaml/browser/dist/schema/common/map.js +17 -0
- package/src-shared/vendor/yaml/browser/dist/schema/common/null.js +15 -0
- package/src-shared/vendor/yaml/browser/dist/schema/common/seq.js +17 -0
- package/src-shared/vendor/yaml/browser/dist/schema/common/string.js +14 -0
- package/src-shared/vendor/yaml/browser/dist/schema/core/bool.js +19 -0
- package/src-shared/vendor/yaml/browser/dist/schema/core/float.js +43 -0
- package/src-shared/vendor/yaml/browser/dist/schema/core/int.js +38 -0
- package/src-shared/vendor/yaml/browser/dist/schema/core/schema.js +23 -0
- package/src-shared/vendor/yaml/browser/dist/schema/json/schema.js +62 -0
- package/src-shared/vendor/yaml/browser/dist/schema/tags.js +83 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/binary.js +66 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/bool.js +26 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/float.js +46 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/int.js +71 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/omap.js +74 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/pairs.js +78 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/schema.js +37 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/set.js +93 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/timestamp.js +101 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/foldFlowLines.js +146 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringify.js +124 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyCollection.js +143 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyComment.js +20 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyDocument.js +85 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyNumber.js +24 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyPair.js +150 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyString.js +328 -0
- package/src-shared/vendor/yaml/browser/dist/util.js +11 -0
- package/src-shared/vendor/yaml/browser/dist/visit.js +233 -0
- package/src-shared/vendor/yaml/browser/index.js +5 -0
- package/src-shared/vendor/yaml/browser/package.json +3 -0
- package/src-shared/vendor/yaml/dist/cli.d.ts +8 -0
- package/src-shared/vendor/yaml/dist/cli.mjs +199 -0
- package/src-shared/vendor/yaml/dist/compose/compose-collection.d.ts +11 -0
- package/src-shared/vendor/yaml/dist/compose/compose-collection.js +90 -0
- package/src-shared/vendor/yaml/dist/compose/compose-doc.d.ts +7 -0
- package/src-shared/vendor/yaml/dist/compose/compose-doc.js +44 -0
- package/src-shared/vendor/yaml/dist/compose/compose-node.d.ts +28 -0
- package/src-shared/vendor/yaml/dist/compose/compose-node.js +95 -0
- package/src-shared/vendor/yaml/dist/compose/compose-scalar.d.ts +5 -0
- package/src-shared/vendor/yaml/dist/compose/compose-scalar.js +82 -0
- package/src-shared/vendor/yaml/dist/compose/composer.d.ts +62 -0
- package/src-shared/vendor/yaml/dist/compose/composer.js +221 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-map.d.ts +6 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-map.js +115 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-scalar.d.ts +11 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-scalar.js +200 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-seq.d.ts +6 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-seq.js +49 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-end.d.ts +6 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-end.js +39 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-flow-collection.d.ts +7 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-flow-collection.js +205 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-flow-scalar.d.ts +10 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-flow-scalar.js +225 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-props.d.ts +23 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-props.js +150 -0
- package/src-shared/vendor/yaml/dist/compose/util-contains-newline.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/compose/util-contains-newline.js +36 -0
- package/src-shared/vendor/yaml/dist/compose/util-empty-scalar-position.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/compose/util-empty-scalar-position.js +29 -0
- package/src-shared/vendor/yaml/dist/compose/util-flow-indent-check.d.ts +3 -0
- package/src-shared/vendor/yaml/dist/compose/util-flow-indent-check.js +17 -0
- package/src-shared/vendor/yaml/dist/compose/util-map-includes.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/compose/util-map-includes.js +19 -0
- package/src-shared/vendor/yaml/dist/doc/Document.d.ts +141 -0
- package/src-shared/vendor/yaml/dist/doc/Document.js +336 -0
- package/src-shared/vendor/yaml/dist/doc/anchors.d.ts +24 -0
- package/src-shared/vendor/yaml/dist/doc/anchors.js +77 -0
- package/src-shared/vendor/yaml/dist/doc/applyReviver.d.ts +9 -0
- package/src-shared/vendor/yaml/dist/doc/applyReviver.js +57 -0
- package/src-shared/vendor/yaml/dist/doc/createNode.d.ts +17 -0
- package/src-shared/vendor/yaml/dist/doc/createNode.js +91 -0
- package/src-shared/vendor/yaml/dist/doc/directives.d.ts +49 -0
- package/src-shared/vendor/yaml/dist/doc/directives.js +178 -0
- package/src-shared/vendor/yaml/dist/errors.d.ts +21 -0
- package/src-shared/vendor/yaml/dist/errors.js +62 -0
- package/src-shared/vendor/yaml/dist/index.d.ts +22 -0
- package/src-shared/vendor/yaml/dist/index.js +50 -0
- package/src-shared/vendor/yaml/dist/log.d.ts +3 -0
- package/src-shared/vendor/yaml/dist/log.js +17 -0
- package/src-shared/vendor/yaml/dist/nodes/Alias.d.ts +28 -0
- package/src-shared/vendor/yaml/dist/nodes/Alias.js +103 -0
- package/src-shared/vendor/yaml/dist/nodes/Collection.d.ts +73 -0
- package/src-shared/vendor/yaml/dist/nodes/Collection.js +151 -0
- package/src-shared/vendor/yaml/dist/nodes/Node.d.ts +47 -0
- package/src-shared/vendor/yaml/dist/nodes/Node.js +40 -0
- package/src-shared/vendor/yaml/dist/nodes/Pair.d.ts +21 -0
- package/src-shared/vendor/yaml/dist/nodes/Pair.js +39 -0
- package/src-shared/vendor/yaml/dist/nodes/Scalar.d.ts +42 -0
- package/src-shared/vendor/yaml/dist/nodes/Scalar.js +27 -0
- package/src-shared/vendor/yaml/dist/nodes/YAMLMap.d.ts +53 -0
- package/src-shared/vendor/yaml/dist/nodes/YAMLMap.js +147 -0
- package/src-shared/vendor/yaml/dist/nodes/YAMLSeq.d.ts +60 -0
- package/src-shared/vendor/yaml/dist/nodes/YAMLSeq.js +115 -0
- package/src-shared/vendor/yaml/dist/nodes/addPairToJSMap.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/nodes/addPairToJSMap.js +106 -0
- package/src-shared/vendor/yaml/dist/nodes/identity.d.ts +23 -0
- package/src-shared/vendor/yaml/dist/nodes/identity.js +53 -0
- package/src-shared/vendor/yaml/dist/nodes/toJS.d.ts +27 -0
- package/src-shared/vendor/yaml/dist/nodes/toJS.js +39 -0
- package/src-shared/vendor/yaml/dist/options.d.ts +338 -0
- package/src-shared/vendor/yaml/dist/parse/cst-scalar.d.ts +64 -0
- package/src-shared/vendor/yaml/dist/parse/cst-scalar.js +218 -0
- package/src-shared/vendor/yaml/dist/parse/cst-stringify.d.ts +8 -0
- package/src-shared/vendor/yaml/dist/parse/cst-stringify.js +63 -0
- package/src-shared/vendor/yaml/dist/parse/cst-visit.d.ts +39 -0
- package/src-shared/vendor/yaml/dist/parse/cst-visit.js +99 -0
- package/src-shared/vendor/yaml/dist/parse/cst.d.ts +108 -0
- package/src-shared/vendor/yaml/dist/parse/cst.js +112 -0
- package/src-shared/vendor/yaml/dist/parse/lexer.d.ts +87 -0
- package/src-shared/vendor/yaml/dist/parse/lexer.js +719 -0
- package/src-shared/vendor/yaml/dist/parse/line-counter.d.ts +22 -0
- package/src-shared/vendor/yaml/dist/parse/line-counter.js +41 -0
- package/src-shared/vendor/yaml/dist/parse/parser.d.ts +84 -0
- package/src-shared/vendor/yaml/dist/parse/parser.js +958 -0
- package/src-shared/vendor/yaml/dist/public-api.d.ts +43 -0
- package/src-shared/vendor/yaml/dist/public-api.js +104 -0
- package/src-shared/vendor/yaml/dist/schema/Schema.d.ts +18 -0
- package/src-shared/vendor/yaml/dist/schema/Schema.js +40 -0
- package/src-shared/vendor/yaml/dist/schema/common/map.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/schema/common/map.js +19 -0
- package/src-shared/vendor/yaml/dist/schema/common/null.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/schema/common/null.js +17 -0
- package/src-shared/vendor/yaml/dist/schema/common/seq.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/schema/common/seq.js +19 -0
- package/src-shared/vendor/yaml/dist/schema/common/string.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/schema/common/string.js +16 -0
- package/src-shared/vendor/yaml/dist/schema/core/bool.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/schema/core/bool.js +21 -0
- package/src-shared/vendor/yaml/dist/schema/core/float.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/schema/core/float.js +47 -0
- package/src-shared/vendor/yaml/dist/schema/core/int.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/schema/core/int.js +42 -0
- package/src-shared/vendor/yaml/dist/schema/core/schema.d.ts +1 -0
- package/src-shared/vendor/yaml/dist/schema/core/schema.js +25 -0
- package/src-shared/vendor/yaml/dist/schema/json/schema.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/schema/json/schema.js +64 -0
- package/src-shared/vendor/yaml/dist/schema/json-schema.d.ts +69 -0
- package/src-shared/vendor/yaml/dist/schema/tags.d.ts +40 -0
- package/src-shared/vendor/yaml/dist/schema/tags.js +86 -0
- package/src-shared/vendor/yaml/dist/schema/types.d.ts +90 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/binary.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/binary.js +68 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/bool.d.ts +7 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/bool.js +29 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/float.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/float.js +50 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/int.d.ts +5 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/int.js +76 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/omap.d.ts +28 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/omap.js +77 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/pairs.d.ts +10 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/pairs.js +82 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/schema.js +39 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/set.d.ts +28 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/set.js +96 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/timestamp.d.ts +6 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/timestamp.js +105 -0
- package/src-shared/vendor/yaml/dist/stringify/foldFlowLines.d.ts +34 -0
- package/src-shared/vendor/yaml/dist/stringify/foldFlowLines.js +151 -0
- package/src-shared/vendor/yaml/dist/stringify/stringify.d.ts +21 -0
- package/src-shared/vendor/yaml/dist/stringify/stringify.js +127 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyCollection.d.ts +17 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyCollection.js +145 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyComment.d.ts +10 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyComment.js +24 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyDocument.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyDocument.js +87 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyNumber.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyNumber.js +26 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyPair.d.ts +3 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyPair.js +152 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyString.d.ts +9 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyString.js +330 -0
- package/src-shared/vendor/yaml/dist/test-events.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/test-events.js +134 -0
- package/src-shared/vendor/yaml/dist/util.d.ts +12 -0
- package/src-shared/vendor/yaml/dist/util.js +28 -0
- package/src-shared/vendor/yaml/dist/visit.d.ts +102 -0
- package/src-shared/vendor/yaml/dist/visit.js +236 -0
- package/src-shared/vendor/yaml/package.json +96 -0
- package/src-shared/vendor/yaml/util.js +2 -0
package/src-ext/bin.mjs
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// agentlink-agent 入口。
|
|
2
|
+
//
|
|
3
|
+
// 本文件**禁止** import `../src/**`。只允许 `../src-shared/**` 以及
|
|
4
|
+
// 同目录子模块。违反即破坏"平行世界"原则。
|
|
5
|
+
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
import { createLogger } from "../src-shared/logger.mjs";
|
|
8
|
+
import { newCid } from "../src-shared/correlation.mjs";
|
|
9
|
+
import { runAgentCommand } from "./commands/agent.mjs";
|
|
10
|
+
import { runServiceCommand } from "./commands/service.mjs";
|
|
11
|
+
import { printHelp } from "./commands/help.mjs";
|
|
12
|
+
|
|
13
|
+
const PKG_NAME = "agentlink-agent";
|
|
14
|
+
|
|
15
|
+
// short flag 到长名的映射。只加必要的:-r → runtime。
|
|
16
|
+
const SHORT_FLAGS = Object.freeze({ r: "runtime" });
|
|
17
|
+
|
|
18
|
+
function parseArgs(argv) {
|
|
19
|
+
// 支持:
|
|
20
|
+
// --key=value / --key value / --bool / -r value
|
|
21
|
+
// 第一个 non-flag token 是 subcommand,其余 positional。
|
|
22
|
+
let subcommand = "";
|
|
23
|
+
const positional = [];
|
|
24
|
+
const options = {};
|
|
25
|
+
for (let i = 0; i < argv.length; i++) {
|
|
26
|
+
const raw = argv[i];
|
|
27
|
+
if (raw.startsWith("--")) {
|
|
28
|
+
const eq = raw.indexOf("=");
|
|
29
|
+
if (eq > 0) {
|
|
30
|
+
options[raw.slice(2, eq)] = raw.slice(eq + 1);
|
|
31
|
+
} else {
|
|
32
|
+
const key = raw.slice(2);
|
|
33
|
+
const nxt = argv[i + 1];
|
|
34
|
+
if (nxt === undefined || nxt.startsWith("-")) {
|
|
35
|
+
options[key] = true;
|
|
36
|
+
} else {
|
|
37
|
+
options[key] = nxt;
|
|
38
|
+
i += 1;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} else if (raw.startsWith("-") && raw.length >= 2 && !/^\-\d/.test(raw)) {
|
|
42
|
+
// single-dash short flag: `-r claude`
|
|
43
|
+
const short = raw.slice(1);
|
|
44
|
+
const mapped = SHORT_FLAGS[short] || short;
|
|
45
|
+
const nxt = argv[i + 1];
|
|
46
|
+
if (nxt === undefined || nxt.startsWith("-")) {
|
|
47
|
+
options[mapped] = true;
|
|
48
|
+
} else {
|
|
49
|
+
options[mapped] = nxt;
|
|
50
|
+
i += 1;
|
|
51
|
+
}
|
|
52
|
+
} else if (!subcommand) {
|
|
53
|
+
subcommand = raw;
|
|
54
|
+
} else {
|
|
55
|
+
positional.push(raw);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { subcommand, positional, options };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function main() {
|
|
62
|
+
// 只在启动期用一次 cid,用于冒烟日志;后续每个 session / request 自己生成。
|
|
63
|
+
const startCid = newCid();
|
|
64
|
+
const log = createLogger({ comp: "bridge", cid: startCid });
|
|
65
|
+
|
|
66
|
+
const { subcommand, positional, options } = parseArgs(process.argv.slice(2));
|
|
67
|
+
|
|
68
|
+
if (options.help || subcommand === "help" || subcommand === "") {
|
|
69
|
+
printHelp();
|
|
70
|
+
log.info("bridge.exit", "help rendered");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (options.version) {
|
|
75
|
+
// 版本信息走简单 stdout(非 JSON 行)避免脚本侧解析困难;logger 独立记一条。
|
|
76
|
+
process.stdout.write(`${PKG_NAME} p1-skeleton\n`);
|
|
77
|
+
log.info("bridge.exit", "version rendered");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
log.info("bridge.start", "agent bin start", {
|
|
82
|
+
subcommand,
|
|
83
|
+
node: process.version,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
process.on("SIGINT", () => {
|
|
87
|
+
log.info("bridge.signal.recv", "SIGINT", { signal: "SIGINT" });
|
|
88
|
+
});
|
|
89
|
+
process.on("SIGTERM", () => {
|
|
90
|
+
log.info("bridge.signal.recv", "SIGTERM", { signal: "SIGTERM" });
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
switch (subcommand) {
|
|
94
|
+
case "claude":
|
|
95
|
+
case "codex":
|
|
96
|
+
case "hermes":
|
|
97
|
+
case "picoclaw":
|
|
98
|
+
await runAgentCommand({ runtime: subcommand, options, positional, log });
|
|
99
|
+
return;
|
|
100
|
+
case "service":
|
|
101
|
+
await runServiceCommand({ options, positional, log });
|
|
102
|
+
return;
|
|
103
|
+
case "logs":
|
|
104
|
+
// P6 实现;P1 先占位
|
|
105
|
+
log.warn("bridge.not_implemented", "logs subcommand not implemented yet");
|
|
106
|
+
process.stderr.write("logs subcommand will land in P6\n");
|
|
107
|
+
process.exit(2);
|
|
108
|
+
default:
|
|
109
|
+
log.error("bridge.unknown_subcommand", "unknown subcommand", { subcommand });
|
|
110
|
+
process.stderr.write(`unknown subcommand: ${subcommand}\n`);
|
|
111
|
+
process.stderr.write("run 'agentlink-agent --help' for usage\n");
|
|
112
|
+
process.exit(2);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
main().catch((err) => {
|
|
117
|
+
// main 保护性 catch:logger 可能还没初始化完整,直接写 stderr + 尝试 log。
|
|
118
|
+
const msg = err && err.message ? err.message : String(err);
|
|
119
|
+
try {
|
|
120
|
+
const log = createLogger({ comp: "bridge" });
|
|
121
|
+
log.error("bridge.fatal", "unhandled error in main", {
|
|
122
|
+
err: msg,
|
|
123
|
+
stack: err && err.stack ? String(err.stack).split("\n").slice(0, 6).join("\n") : undefined,
|
|
124
|
+
});
|
|
125
|
+
} catch {}
|
|
126
|
+
process.stderr.write(`fatal: ${msg}\n`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { runClaudeBridge } from "../runtime/claude/index.mjs";
|
|
2
|
+
import { runCodexBridge } from "../runtime/codex/index.mjs";
|
|
3
|
+
import { runHermesBridge } from "../runtime/hermes/index.mjs";
|
|
4
|
+
import { runPicoclawBridge } from "../runtime/picoclaw/index.mjs";
|
|
5
|
+
import { runPairInstall, runUninstall } from "./pair.mjs";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `agentlink-agent <runtime> [action] [args]` 分发。
|
|
9
|
+
*
|
|
10
|
+
* 子动作:
|
|
11
|
+
* pair <code> —— 消费配对码 + 保存状态 + 自动装 service(后台保活)
|
|
12
|
+
* uninstall —— 卸载 service + 清理本地状态
|
|
13
|
+
* (无) —— 前台 bridge(从本地状态读 session,适合调试)
|
|
14
|
+
*/
|
|
15
|
+
export async function runAgentCommand({ runtime, options, positional, log }) {
|
|
16
|
+
const rtLog = log.child({ rt: runtime });
|
|
17
|
+
const action = (positional[0] || "").toLowerCase();
|
|
18
|
+
|
|
19
|
+
if (action === "pair") {
|
|
20
|
+
// picoclaw 不走传统 `pair <code>`,daemon 启动后自动配对(QR 流)。
|
|
21
|
+
if (runtime === "picoclaw") {
|
|
22
|
+
process.stderr.write(
|
|
23
|
+
"picoclaw 不需要 pair 子命令,直接启动 daemon: agentlink-agent picoclaw\n",
|
|
24
|
+
);
|
|
25
|
+
process.exit(2);
|
|
26
|
+
}
|
|
27
|
+
const code = String(positional[1] || options.pair || "").trim();
|
|
28
|
+
if (!code) {
|
|
29
|
+
process.stderr.write(`usage: agentlink pair <code> -r ${runtime}\n`);
|
|
30
|
+
process.exit(2);
|
|
31
|
+
}
|
|
32
|
+
rtLog.info("bridge.preflight.pass", "pair subcommand", { code_len: code.length });
|
|
33
|
+
await runPairInstall({ runtime, code, options, log: rtLog });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (action === "uninstall") {
|
|
38
|
+
rtLog.info("bridge.preflight.pass", "uninstall subcommand", {});
|
|
39
|
+
await runUninstall({ runtime, options, log: rtLog });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
rtLog.info("bridge.preflight.pass", "runtime dispatcher entered", {
|
|
44
|
+
runtime,
|
|
45
|
+
args_count: positional.length,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
switch (runtime) {
|
|
49
|
+
case "claude":
|
|
50
|
+
await runClaudeBridge({ options, positional, log: rtLog });
|
|
51
|
+
return;
|
|
52
|
+
case "codex":
|
|
53
|
+
await runCodexBridge({ options, positional, log: rtLog });
|
|
54
|
+
return;
|
|
55
|
+
case "hermes":
|
|
56
|
+
await runHermesBridge({ options, positional, log: rtLog });
|
|
57
|
+
return;
|
|
58
|
+
case "picoclaw":
|
|
59
|
+
await runPicoclawBridge({ options, positional, log: rtLog });
|
|
60
|
+
return;
|
|
61
|
+
default:
|
|
62
|
+
rtLog.error("bridge.unknown_runtime", "unsupported runtime", { runtime });
|
|
63
|
+
process.stderr.write(`unsupported runtime: ${runtime}\n`);
|
|
64
|
+
process.exit(2);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// 纯 stdout 帮助文本。不走 logger —— 这是给人看的,不是日志。
|
|
2
|
+
|
|
3
|
+
export function printHelp() {
|
|
4
|
+
const lines = [
|
|
5
|
+
"agentlink-agent —— 连接手机 App 与本地 Claude Code / Codex 的中继桥",
|
|
6
|
+
"",
|
|
7
|
+
"用法:",
|
|
8
|
+
" agentlink-agent <runtime> [--pair-code=<code>] [--cwd=<path>] [...]",
|
|
9
|
+
"",
|
|
10
|
+
"运行时:",
|
|
11
|
+
" claude 桥接官方 claude CLI(P2 起实现)",
|
|
12
|
+
" codex 桥接官方 codex CLI(P4 起实现)",
|
|
13
|
+
"",
|
|
14
|
+
"工具:",
|
|
15
|
+
" logs tail 实时跟踪日志(P6 实现)",
|
|
16
|
+
" logs grep 按 correlation id 查日志(P6 实现)",
|
|
17
|
+
"",
|
|
18
|
+
"环境变量:",
|
|
19
|
+
" AGENTLINK_AGENT_LOG_LEVEL debug / info (默认) / warn / error",
|
|
20
|
+
" AGENTLINK_AGENT_LOG_DIR 日志目录,默认 ~/.agentlink/logs",
|
|
21
|
+
" AGENTLINK_RELAY_URL relay 地址(P2 起使用)",
|
|
22
|
+
"",
|
|
23
|
+
"选项:",
|
|
24
|
+
" --help 本帮助",
|
|
25
|
+
" --version 版本",
|
|
26
|
+
"",
|
|
27
|
+
"本命令独立于 `agentlink bridge`,两者可并存互不干扰。",
|
|
28
|
+
"",
|
|
29
|
+
];
|
|
30
|
+
process.stdout.write(lines.join("\n"));
|
|
31
|
+
}
|
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
// `agentlink-agent <runtime> pair <code>`:一次性完成 consume + 装 service + 退出。
|
|
2
|
+
//
|
|
3
|
+
// 设计:与老 `agentlink pair` 语义对齐 —— pair 完就行,不需要用户再跑第二条命令。
|
|
4
|
+
// 用户明确不要后台时可加 `--no-service`,此时仅 consume + save state。
|
|
5
|
+
//
|
|
6
|
+
// 流程:
|
|
7
|
+
// 1. 调 /api/ext/pair-codes/<code>/consume
|
|
8
|
+
// 2. 写本地状态 ~/.agentlink/ext-<runtime>-last.json
|
|
9
|
+
// 3. 装 service(launchd / systemd-user / schtasks)
|
|
10
|
+
// 4. 打印回执
|
|
11
|
+
//
|
|
12
|
+
// 失败路径:service install 失败不回滚 pair state —— 配对凭证仍有效,
|
|
13
|
+
// 用户可以手动 `agentlink bridge -r <runtime>` 前台跑,或稍后 `agentlink service install`。
|
|
14
|
+
|
|
15
|
+
import process from "node:process";
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
consumePairCode,
|
|
19
|
+
writePairState,
|
|
20
|
+
resolveRelayUrl,
|
|
21
|
+
} from "../core/pairCodeClient.mjs";
|
|
22
|
+
import {
|
|
23
|
+
serviceInstall,
|
|
24
|
+
serviceUninstall,
|
|
25
|
+
serviceStatus,
|
|
26
|
+
} from "../service/serviceManager.mjs";
|
|
27
|
+
import { ensureHermesApiServer } from "../runtime/hermes/envSetup.mjs";
|
|
28
|
+
import { manageHermesGateway } from "../runtime/hermes/gatewayManager.mjs";
|
|
29
|
+
import { ensureDefaultWorkspace } from "../core/defaultWorkspace.mjs";
|
|
30
|
+
import os from "node:os";
|
|
31
|
+
import path from "node:path";
|
|
32
|
+
|
|
33
|
+
export async function runPairInstall({ runtime, code, options, log }) {
|
|
34
|
+
const relay = resolveRelayUrl(options.relay);
|
|
35
|
+
const pLog = log.child({ comp: "pair" });
|
|
36
|
+
pLog.info("pair.consume.start", "consuming pair code", { code, relay });
|
|
37
|
+
|
|
38
|
+
// 1. consume
|
|
39
|
+
let result;
|
|
40
|
+
try {
|
|
41
|
+
result = await consumePairCode({ relayUrl: relay, code, runtime });
|
|
42
|
+
} catch (err) {
|
|
43
|
+
pLog.error("pair.consume.failed", "consume failed", {
|
|
44
|
+
err: err?.message || String(err), code: err?.code || "",
|
|
45
|
+
});
|
|
46
|
+
process.stderr.write(`配对失败:${err?.message || err}\n`);
|
|
47
|
+
process.exit(65);
|
|
48
|
+
}
|
|
49
|
+
if (result.runtime !== runtime) {
|
|
50
|
+
process.stderr.write(
|
|
51
|
+
`配对码是 ${result.runtime} 的,但你用了 -r ${runtime}\n`,
|
|
52
|
+
);
|
|
53
|
+
process.exit(65);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 2. 保存本地状态(含 server 颁发的 bridge_token + gw_id 供 bridge SSE 鉴权)
|
|
57
|
+
// N2.1/N2.2: hermes runtime 支持 --profile <name> 指定 profile,写入 hermesProfileName
|
|
58
|
+
const pairStateData = {
|
|
59
|
+
session_id: result.session_id,
|
|
60
|
+
relay_url: relay,
|
|
61
|
+
bridge_token: result.bridge_token || "",
|
|
62
|
+
gw_id: result.gw_id || "",
|
|
63
|
+
};
|
|
64
|
+
if (runtime === "hermes" && options.profile) {
|
|
65
|
+
pairStateData.hermesProfileName = String(options.profile).trim();
|
|
66
|
+
}
|
|
67
|
+
writePairState(runtime, pairStateData);
|
|
68
|
+
pLog.info("pair.consumed", "pair code accepted", {
|
|
69
|
+
session_id: result.session_id, runtime,
|
|
70
|
+
has_bridge_token: !!result.bridge_token,
|
|
71
|
+
});
|
|
72
|
+
// result 字段是 gw_id(pairCodeClient 把老 session_id 也归一到 gw_id)。
|
|
73
|
+
// 用 session_id 会显示 undefined,对用户没意义;显示 runtime + 短 gw 后缀更清楚。
|
|
74
|
+
process.stdout.write(`✅ 配对成功(${runtime})\n`);
|
|
75
|
+
|
|
76
|
+
// 2.5 runtime-specific 本机配置体检 —— hermes 必须 API_SERVER_ENABLED=true,
|
|
77
|
+
// 默认关闭会让 :8642 没监听 → bridge 连不上 → App 消息不通。
|
|
78
|
+
if (runtime === "hermes") {
|
|
79
|
+
await ensureHermesEnvAndProbe(pLog);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 2.6 align-runtime-default-workspace: 对 claude/codex 配对时 eager 创建默认工作区。
|
|
83
|
+
// 这样新装用户配对完、打开 App 导入列表时,默认工作区已物理存在。
|
|
84
|
+
// openclaw/hermes 有原生默认工作区(openclaw.json / profileHome),跳过。
|
|
85
|
+
if (runtime === "claude" || runtime === "codex") {
|
|
86
|
+
try {
|
|
87
|
+
const wsPath = await ensureDefaultWorkspace(runtime);
|
|
88
|
+
pLog.info("pair.default_workspace.created", "default workspace ensured", {
|
|
89
|
+
runtime, path: wsPath,
|
|
90
|
+
});
|
|
91
|
+
} catch (err) {
|
|
92
|
+
// best-effort:不让默认工作区创建失败影响配对流程
|
|
93
|
+
pLog.warn("pair.default_workspace.failed", "failed to ensure default workspace (non-fatal)", {
|
|
94
|
+
runtime, err: err?.message || String(err),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 3. 装 service(可被 --no-service / --manual 跳过)
|
|
100
|
+
if (options["no-service"] || options.manual) {
|
|
101
|
+
process.stdout.write("⚠️ 已跳过后台服务安装(--no-service)\n");
|
|
102
|
+
process.stdout.write(
|
|
103
|
+
` 如需后台运行:agentlink service install -r ${runtime}\n` +
|
|
104
|
+
` 或前台调试:agentlink bridge -r ${runtime}\n`,
|
|
105
|
+
);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 先尝试 uninstall 旧的(幂等保险 —— 反复配对不会冲突)
|
|
110
|
+
try { serviceUninstall(runtime, pLog); } catch {}
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const r = await serviceInstall(runtime, pLog);
|
|
114
|
+
process.stdout.write(`✅ 已装为后台服务(${r.backend})\n`);
|
|
115
|
+
// 装完等 3s 再查状态 —— launchd / systemd 都需要短暂时间拉起子进程
|
|
116
|
+
await sleep(3000);
|
|
117
|
+
const status = serviceStatus(runtime);
|
|
118
|
+
pLog.info("pair.install.status_after_3s", "post-install status", status);
|
|
119
|
+
if (status.running) {
|
|
120
|
+
process.stdout.write(
|
|
121
|
+
`✅ 后台进程已运行${status.pid ? ` (pid=${status.pid})` : ""}\n` +
|
|
122
|
+
` 查看状态:agentlink service status -r ${runtime}\n` +
|
|
123
|
+
` 卸载:agentlink uninstall -r ${runtime}\n`,
|
|
124
|
+
);
|
|
125
|
+
} else {
|
|
126
|
+
const logDir = `${process.env.HOME || "~"}/.agentlink/logs`;
|
|
127
|
+
process.stderr.write(
|
|
128
|
+
`⚠️ service 已装,但进程 3 秒内未运行起来。\n` +
|
|
129
|
+
` 最可能原因:后台 PATH 里找不到 claude/codex,或 agent 启动崩溃。\n` +
|
|
130
|
+
` 请看日志:${logDir}/service-${runtime}.err.log\n` +
|
|
131
|
+
` 也可以直接前台跑看报错:agentlink bridge -r ${runtime}\n`,
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
} catch (err) {
|
|
135
|
+
pLog.warn("pair.install.failed", "service install failed after pair", {
|
|
136
|
+
err: err?.message || String(err),
|
|
137
|
+
});
|
|
138
|
+
process.stderr.write(
|
|
139
|
+
`⚠️ 自动装服务失败:${err?.message || err}\n` +
|
|
140
|
+
` 配对本身已完成。可以手动跑:agentlink bridge -r ${runtime}\n`,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 4. MCP fanout —— 把 agentlink MCP server 注入到当前 runtime 的 MCP 配置,
|
|
145
|
+
// 让 agent 启动时就能 spawn agentlink-mcp-stdio 看到 agentlink_*_* 工具。
|
|
146
|
+
// 失败不致命:pair 已经成功;用户可手动 `agentlink mcp register <runtime>` 重试。
|
|
147
|
+
try {
|
|
148
|
+
const { register } = await import("../core/mcpRuntimeFanout.mjs");
|
|
149
|
+
const pkgVersion = await readPkgVersion();
|
|
150
|
+
const r = await register(runtime, {
|
|
151
|
+
projectCwd: process.cwd(),
|
|
152
|
+
version: pkgVersion,
|
|
153
|
+
log: pLog,
|
|
154
|
+
});
|
|
155
|
+
if (r.ok && r.changed) {
|
|
156
|
+
process.stdout.write(`✅ 已注册 agentlink MCP server 到 ${runtime}\n`);
|
|
157
|
+
} else if (r.ok && r.mode === "plugin_managed") {
|
|
158
|
+
process.stdout.write(`ℹ️ openclaw 用 plugin 管理 agentlink 工具(无需 MCP 配置)\n`);
|
|
159
|
+
} else if (r.ok && !r.changed) {
|
|
160
|
+
// idempotent no-op,什么都不打印,免噪音
|
|
161
|
+
} else if (!r.ok && r.reason === "hermes_not_installed") {
|
|
162
|
+
process.stderr.write(`⚠️ Hermes 未安装,跳过 MCP 配置注册\n`);
|
|
163
|
+
} else if (!r.ok) {
|
|
164
|
+
process.stderr.write(`⚠️ MCP 配置注册失败 (${r.reason || "unknown"}): agentlink 工具不会出现在 ${runtime} 的工具列表里。\n` +
|
|
165
|
+
` 可手动重试:agentlink mcp register ${runtime}\n`);
|
|
166
|
+
}
|
|
167
|
+
} catch (err) {
|
|
168
|
+
pLog.warn("pair.fanout.failed", "mcp fanout failed after pair", {
|
|
169
|
+
err: err?.message || String(err),
|
|
170
|
+
});
|
|
171
|
+
process.stderr.write(`⚠️ MCP 配置注册抛错(${err?.message || err}),pair 本身已成功;agentlink 工具暂不可用。\n`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** 读 npm_cli/package.json 的 version 字段,失败兜底 "unknown"。 */
|
|
176
|
+
async function readPkgVersion() {
|
|
177
|
+
try {
|
|
178
|
+
const { readFile } = await import("node:fs/promises");
|
|
179
|
+
const path = await import("node:path");
|
|
180
|
+
const { fileURLToPath } = await import("node:url");
|
|
181
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
182
|
+
const pkg = JSON.parse(await readFile(path.join(__dirname, "../../package.json"), "utf8"));
|
|
183
|
+
return pkg.version || "unknown";
|
|
184
|
+
} catch {
|
|
185
|
+
return "unknown";
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function sleep(ms) {
|
|
190
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* hermes 专用:确保 `~/.hermes/.env` 里 `API_SERVER_ENABLED=true`,
|
|
195
|
+
* 必要时也写齐 HOST/PORT。已设的不动。
|
|
196
|
+
*
|
|
197
|
+
* 写完之后 probe `http://<host>:<port>/health`,如果不通就提示用户启动 /
|
|
198
|
+
* 重启 gateway(new env 只对**之后启动的** gateway 生效)。
|
|
199
|
+
*/
|
|
200
|
+
// 配对场景下等 hermes gateway 健康的上限。收短到 5s(默认 30s 是给 bridge
|
|
201
|
+
// preflight 用的):配对**不该**为了确认 gateway 健康而阻塞后续 runtime ——
|
|
202
|
+
// hermes 没配模型时 gateway 永远不健康,等满 30s 会把 claude/codex 的配对 +
|
|
203
|
+
// host-inventory 上报顶到 App 等待窗口之外,导致「CLI 成功但 App 不显示」。
|
|
204
|
+
// gateway 是 detached spawn,5s 没就绪也会在后台继续起来。
|
|
205
|
+
const PAIR_GATEWAY_HEALTH_TIMEOUT_MS = 5000;
|
|
206
|
+
|
|
207
|
+
export async function ensureHermesEnvAndProbe(log, opts = {}) {
|
|
208
|
+
const healthTimeoutMs = opts.healthTimeoutMs || PAIR_GATEWAY_HEALTH_TIMEOUT_MS;
|
|
209
|
+
const r = ensureHermesApiServer({ log });
|
|
210
|
+
if (r.status === "no_home") {
|
|
211
|
+
process.stdout.write(`⚠️ ${r.warning || "~/.hermes 不存在"}\n`);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (r.status === "io_error") {
|
|
215
|
+
process.stderr.write(`⚠️ hermes 配置自检失败:${r.error}\n`);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
let restartMatters = false;
|
|
219
|
+
if (r.status === "patched") {
|
|
220
|
+
const parts = [];
|
|
221
|
+
if (r.appended.length > 0) parts.push(`追加 [${r.appended.join(", ")}]`);
|
|
222
|
+
if (r.overridden.length > 0) parts.push(`改写 [${r.overridden.join(", ")}=true]`);
|
|
223
|
+
if (r.kept.length > 0) {
|
|
224
|
+
const keepStr = r.kept.map(({ key, value }) => `${key}=${value}`).join(", ");
|
|
225
|
+
parts.push(`沿用 [${keepStr}]`);
|
|
226
|
+
}
|
|
227
|
+
process.stdout.write(`🔧 已更新 ${r.envPath}:${parts.join(";")}\n`);
|
|
228
|
+
// overridden(强制把 false → true)一定需要重启;appended 中只有
|
|
229
|
+
// API_SERVER_ENABLED 真正改变行为(HOST/PORT 缺失情况下 gateway 也是用同
|
|
230
|
+
// 一套默认值 127.0.0.1:8642 在 listen,append 默认值不改行为)。
|
|
231
|
+
restartMatters =
|
|
232
|
+
r.overridden.length > 0 ||
|
|
233
|
+
r.appended.includes("API_SERVER_ENABLED");
|
|
234
|
+
} else if (r.kept.length > 0) {
|
|
235
|
+
// status === "ok",但仍然把用户已设的 host/port 列出来给用户确认
|
|
236
|
+
const keepStr = r.kept.map(({ key, value }) => `${key}=${value}`).join(", ");
|
|
237
|
+
log.info("hermes.env.ok", "hermes API_SERVER_* env already configured", {
|
|
238
|
+
env_path: r.envPath, kept: r.kept,
|
|
239
|
+
});
|
|
240
|
+
process.stdout.write(`ℹ️ hermes 配置 OK,沿用 [${keepStr}]\n`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 自动起 / 重启 hermes gateway —— 用户不用再手敲 nohup。
|
|
244
|
+
// - 配置有 behavior-affecting 变化 (restartMatters):mode=restart 强制
|
|
245
|
+
// kill listening process 再 spawn(老内存里是 stale env,不重启没用)。
|
|
246
|
+
// - 配置不变 / 只是补默认值:mode=ensure 只有探活失败才 spawn。
|
|
247
|
+
const baseUrl = _resolveHermesBaseUrl(r);
|
|
248
|
+
const logPath = path.join(os.homedir(), ".hermes", "gateway.log");
|
|
249
|
+
const mgr = await manageHermesGateway({
|
|
250
|
+
baseUrl,
|
|
251
|
+
mode: restartMatters ? "restart" : "ensure",
|
|
252
|
+
logPath,
|
|
253
|
+
log,
|
|
254
|
+
healthTimeoutMs,
|
|
255
|
+
});
|
|
256
|
+
if (mgr.ok) {
|
|
257
|
+
if (mgr.alreadyOk) {
|
|
258
|
+
process.stdout.write(`✅ hermes gateway 已在跑,健康检查通过 (${baseUrl}/health)\n`);
|
|
259
|
+
} else if (mgr.restarted) {
|
|
260
|
+
process.stdout.write(
|
|
261
|
+
`✅ hermes gateway 已重启 (新 pid=${mgr.pid}, 旧 pid=${mgr.stoppedOldPid}),` +
|
|
262
|
+
`新配置生效,健康检查通过 (${baseUrl}/health)\n` +
|
|
263
|
+
` 日志:${mgr.logPath}\n`,
|
|
264
|
+
);
|
|
265
|
+
} else {
|
|
266
|
+
process.stdout.write(
|
|
267
|
+
`✅ hermes gateway 已自动启动 (pid=${mgr.pid}),健康检查通过 (${baseUrl}/health)\n` +
|
|
268
|
+
` 日志:${mgr.logPath}\n`,
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
} else if (mgr.healthTimedOut) {
|
|
272
|
+
// gateway 进程已 spawn(detached),只是没在收短的健康窗口内通过 /health
|
|
273
|
+
// —— 典型是没配模型 / 启动慢。这**不阻塞配对**:进程在后台继续起,配模型
|
|
274
|
+
// 后即可用。打 info 级软提示,不报错、不刷一屏 troubleshooting。
|
|
275
|
+
log.info("hermes.gateway.health.pending", "gateway spawned but not healthy within pair window (non-blocking)", {
|
|
276
|
+
baseUrl, timeoutMs: healthTimeoutMs, logPath: mgr.logPath,
|
|
277
|
+
});
|
|
278
|
+
process.stdout.write(
|
|
279
|
+
`ℹ️ hermes gateway 已在后台启动 (pid=${mgr.pid}),但 ${healthTimeoutMs / 1000}s 内未通过健康检查` +
|
|
280
|
+
`(多半是未配置模型)。不阻塞配对,配好模型后即生效。\n` +
|
|
281
|
+
` 验证:curl -sf ${baseUrl}/health 日志:${mgr.logPath}\n`,
|
|
282
|
+
);
|
|
283
|
+
} else {
|
|
284
|
+
process.stderr.write(
|
|
285
|
+
`⚠️ hermes gateway 自动启动失败:${mgr.error}\n`,
|
|
286
|
+
);
|
|
287
|
+
if (mgr.logPath) {
|
|
288
|
+
process.stderr.write(` 看日志定位:tail -50 ${mgr.logPath}\n`);
|
|
289
|
+
}
|
|
290
|
+
process.stderr.write(
|
|
291
|
+
` 手动启动:nohup hermes gateway run > ${mgr.logPath || "/tmp/hermes-gateway.log"} 2>&1 &\n` +
|
|
292
|
+
` 验证:curl -sf ${baseUrl}/health\n`,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* 从 envSetup 返回值 + 默认值反推 hermes gateway 的 base URL。
|
|
299
|
+
* 已设的 HOST/PORT 用用户值;缺失的用默认 127.0.0.1:8642。
|
|
300
|
+
*/
|
|
301
|
+
function _resolveHermesBaseUrl(setupResult) {
|
|
302
|
+
const kept = new Map((setupResult.kept || []).map(({ key, value }) => [key, value]));
|
|
303
|
+
const host = kept.get("API_SERVER_HOST") || "127.0.0.1";
|
|
304
|
+
const port = kept.get("API_SERVER_PORT") || "8642";
|
|
305
|
+
return `http://${host}:${port}`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* 把"解绑"通知到 relay server。这步是双向解绑的关键 ——
|
|
310
|
+
*
|
|
311
|
+
* - 不通知:CLI 这边状态清了、launchd plist 卸了,但 server 还以为
|
|
312
|
+
* binding 在跑;App 端 GET /v1/app-users/me/binding 仍能看到这条
|
|
313
|
+
* gateway,发消息会被 dispatch 到一个永远没人 poll 的 gateway。
|
|
314
|
+
* - 通知:server 把 pair_sessions 这一行 deleted_at=now,App 下次
|
|
315
|
+
* 刷新 / SSE 推 thread.archived 时这条会议自动消失。
|
|
316
|
+
*
|
|
317
|
+
* 用 POST /v1/gateways/<gw>/reset,鉴权用本机存的 bridge_token(=
|
|
318
|
+
* relayGatewayToken)。404 = server 端已经被人 reset(典型情况:用户
|
|
319
|
+
* 在 App 上先删了 → relayWorker 收到 404 自调 uninstall)→ 视为成功,
|
|
320
|
+
* 不阻塞后续 service uninstall + 本地状态清理。
|
|
321
|
+
*
|
|
322
|
+
* @param {string} runtime
|
|
323
|
+
* @param {{ info, warn, error }} log
|
|
324
|
+
* @returns {Promise<{ ok: boolean, alreadyRevoked?: boolean, error?: string }>}
|
|
325
|
+
*/
|
|
326
|
+
async function notifyServerOfRevoke(runtime, log) {
|
|
327
|
+
const { readPairState } = await import("../core/pairCodeClient.mjs");
|
|
328
|
+
const state = readPairState(runtime);
|
|
329
|
+
if (!state) return { ok: true, alreadyRevoked: true };
|
|
330
|
+
const relayUrl = String(state.relay_url || "").replace(/\/+$/, "");
|
|
331
|
+
const gwId = String(state.gw_id || "").trim();
|
|
332
|
+
const bridgeToken = String(state.bridge_token || "").trim();
|
|
333
|
+
if (!relayUrl || !gwId || !bridgeToken) {
|
|
334
|
+
log?.info?.("uninstall.revoke.skip", "缺少 gw/token,跳过 server 通知", {
|
|
335
|
+
has_relay: !!relayUrl, has_gw: !!gwId, has_token: !!bridgeToken,
|
|
336
|
+
});
|
|
337
|
+
return { ok: true, alreadyRevoked: true };
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
const controller = new AbortController();
|
|
341
|
+
const t = setTimeout(() => controller.abort(), 5000);
|
|
342
|
+
const res = await fetch(`${relayUrl}/v1/gateways/${encodeURIComponent(gwId)}/reset`, {
|
|
343
|
+
method: "POST",
|
|
344
|
+
headers: {
|
|
345
|
+
Authorization: `Bearer ${bridgeToken}`,
|
|
346
|
+
"Content-Type": "application/json",
|
|
347
|
+
},
|
|
348
|
+
signal: controller.signal,
|
|
349
|
+
});
|
|
350
|
+
clearTimeout(t);
|
|
351
|
+
if (res.ok) {
|
|
352
|
+
log?.info?.("uninstall.revoke.ok", "server-side binding revoked", {
|
|
353
|
+
gw_id: gwId, status: res.status,
|
|
354
|
+
});
|
|
355
|
+
return { ok: true };
|
|
356
|
+
}
|
|
357
|
+
// 404 / 401 都视为 already revoked —— server 这边没这个 binding 了。
|
|
358
|
+
if (res.status === 404 || res.status === 401 || res.status === 410) {
|
|
359
|
+
log?.info?.("uninstall.revoke.gone", "server-side binding already gone", {
|
|
360
|
+
gw_id: gwId, status: res.status,
|
|
361
|
+
});
|
|
362
|
+
return { ok: true, alreadyRevoked: true };
|
|
363
|
+
}
|
|
364
|
+
log?.warn?.("uninstall.revoke.fail", "server reset failed (continuing)", {
|
|
365
|
+
gw_id: gwId, status: res.status,
|
|
366
|
+
});
|
|
367
|
+
return { ok: false, error: `HTTP ${res.status}` };
|
|
368
|
+
} catch (err) {
|
|
369
|
+
log?.warn?.("uninstall.revoke.err", "server reset errored (continuing)", {
|
|
370
|
+
err: err?.message || String(err),
|
|
371
|
+
});
|
|
372
|
+
return { ok: false, error: err?.message || String(err) };
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* `agentlink-agent <runtime> uninstall`:通知 server 解绑 + 卸 service +
|
|
378
|
+
* 清本地状态。三件事**容错执行**,任一步失败不阻断后面,最终态保证:
|
|
379
|
+
* - server: pair_sessions deleted_at 标记
|
|
380
|
+
* - 本机: launchd plist 移除 + ~/.agentlink/ext-<runtime>-last.json 删除
|
|
381
|
+
*
|
|
382
|
+
* **bridge 进程自调用场景**:relayWorker 检测到 binding 被 App 端解绑
|
|
383
|
+
* (HTTP 404 on /requests/next) → spawn 自己 \`agentlink uninstall -r
|
|
384
|
+
* <runtime> --keep-state\` 把 service plist 也卸掉,pair state 已被
|
|
385
|
+
* bridge 自行清掉。--keep-state 让 uninstall 跳过 clearPairState。
|
|
386
|
+
*/
|
|
387
|
+
export async function runUninstall({ runtime, options, log }) {
|
|
388
|
+
const pLog = log.child({ comp: "uninstall" });
|
|
389
|
+
pLog.info("uninstall.start", "uninstalling runtime", { runtime });
|
|
390
|
+
|
|
391
|
+
// 1. **先**通知 server —— 本地状态还在才能拿到 gw_id/bridge_token
|
|
392
|
+
if (options["skip-server-revoke"]) {
|
|
393
|
+
process.stdout.write("ℹ️ 跳过 server 端解绑通知(--skip-server-revoke)\n");
|
|
394
|
+
} else {
|
|
395
|
+
const r = await notifyServerOfRevoke(runtime, pLog);
|
|
396
|
+
if (r.ok && r.alreadyRevoked) {
|
|
397
|
+
process.stdout.write(`✅ server 端绑定已不存在\n`);
|
|
398
|
+
} else if (r.ok) {
|
|
399
|
+
process.stdout.write(`✅ 已通知 server 解绑 (POST /v1/gateways/<gw>/reset)\n`);
|
|
400
|
+
} else {
|
|
401
|
+
process.stderr.write(
|
|
402
|
+
`⚠️ 通知 server 解绑失败:${r.error}\n` +
|
|
403
|
+
` 本地清理仍继续。server 端 binding 残留请手动 App 端删除。\n`,
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// 1.5 撤 MCP fanout —— 把 ~/.claude.json / ~/.codex/config.toml /
|
|
409
|
+
// ~/.hermes/config.yaml 里 agentlink server entry 删掉(用户其它 MCP server
|
|
410
|
+
// 一字不动)。失败不致命,后面 service / state 清理继续。
|
|
411
|
+
try {
|
|
412
|
+
const { deregister } = await import("../core/mcpRuntimeFanout.mjs");
|
|
413
|
+
const r = await deregister(runtime, {
|
|
414
|
+
projectCwd: process.cwd(),
|
|
415
|
+
log: pLog,
|
|
416
|
+
});
|
|
417
|
+
if (r.ok && r.changed) {
|
|
418
|
+
process.stdout.write(`✅ 已从 ${runtime} 移除 agentlink MCP server\n`);
|
|
419
|
+
} else if (!r.ok) {
|
|
420
|
+
process.stderr.write(`⚠️ MCP 配置清理失败 (${r.reason || "unknown"});其它清理继续。\n`);
|
|
421
|
+
}
|
|
422
|
+
} catch (err) {
|
|
423
|
+
pLog.warn("uninstall.fanout.failed", "mcp deregister failed", {
|
|
424
|
+
err: err?.message || String(err),
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// 2. 卸 service (launchd plist / systemd-user / schtasks)
|
|
429
|
+
let serviceResult = null;
|
|
430
|
+
try {
|
|
431
|
+
serviceResult = serviceUninstall(runtime, pLog);
|
|
432
|
+
pLog.info("uninstall.service.done", "service uninstalled", serviceResult);
|
|
433
|
+
} catch (err) {
|
|
434
|
+
pLog.warn("uninstall.service.failed", "service uninstall failed", {
|
|
435
|
+
err: err?.message || String(err),
|
|
436
|
+
});
|
|
437
|
+
process.stderr.write(`⚠️ service uninstall: ${err?.message || err}\n`);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// 3. 清本地状态文件(除非用户显式保留)
|
|
441
|
+
if (options["keep-state"]) {
|
|
442
|
+
process.stdout.write("ℹ️ 保留本地配对状态(--keep-state)\n");
|
|
443
|
+
} else {
|
|
444
|
+
const { clearPairState, clearCursor } = await import("../core/pairCodeClient.mjs");
|
|
445
|
+
const cleared = clearPairState(runtime);
|
|
446
|
+
// cursor 必须一起清:留着会让下次 pair 到新 session 时做 session_id 不
|
|
447
|
+
// 匹配判断——虽然能兜住,但多一次文件 IO。主要目的是状态一致。
|
|
448
|
+
const cursorCleared = clearCursor(runtime);
|
|
449
|
+
pLog.info("uninstall.state.cleared", "pair state cleared", {
|
|
450
|
+
cleared, cursor_cleared: cursorCleared,
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
process.stdout.write(`✅ 已卸载 ${runtime}\n`);
|
|
455
|
+
}
|