@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
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* openclawGatewayClient.mjs — 轻量 openclaw gateway WebSocket 客户端
|
|
3
|
+
*
|
|
4
|
+
* 用途:bridge 收到 sessions.abort / chat.abort RPC 时,直连本地
|
|
5
|
+
* openclaw gateway WS 发送 chat.abort 命令真正中断 run。
|
|
6
|
+
*
|
|
7
|
+
* 函数设计均支持依赖注入(_readJsonFn / _tokenFn / _portFn / _wsFactory),
|
|
8
|
+
* 便于单元测试隔离文件系统和网络。
|
|
9
|
+
*
|
|
10
|
+
* 限定行数 ≤ 200 行。
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { readFileSync } from "node:fs";
|
|
14
|
+
import { homedir } from "node:os";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
|
|
17
|
+
// ── 内部工具 ──────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 读 JSON 文件,失败(文件不存在/JSON 语法错)返回 null,永不抛。
|
|
21
|
+
* @param {string} filePath
|
|
22
|
+
* @returns {object|null}
|
|
23
|
+
*/
|
|
24
|
+
function _readJsonFileSafe(filePath) {
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(readFileSync(filePath, "utf8"));
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const DEFAULT_GATEWAY_PORT = 18789;
|
|
33
|
+
|
|
34
|
+
// ── 公开 API ──────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 从 ~/.openclaw/devices/paired.json 读取持有 operator.write scope 的 operator token。
|
|
38
|
+
*
|
|
39
|
+
* @param {{ log?: object, _readJsonFn?: Function }} opts
|
|
40
|
+
* @returns {Promise<string|null>}
|
|
41
|
+
*/
|
|
42
|
+
export async function readOpenclawOperatorToken({ log, _readJsonFn } = {}) {
|
|
43
|
+
const readJson = _readJsonFn ?? ((path) => _readJsonFileSafe(path));
|
|
44
|
+
const pairedPath = join(homedir(), ".openclaw", "devices", "paired.json");
|
|
45
|
+
|
|
46
|
+
let paired;
|
|
47
|
+
try {
|
|
48
|
+
paired = await readJson(pairedPath);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
log?.warn?.("openclawGatewayClient.readToken.err", "paired.json read failed", { err: err?.message });
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!paired) return null;
|
|
55
|
+
|
|
56
|
+
// 支持两种 schema:{ devices: [...] } 或直接是 devices 数组
|
|
57
|
+
const devices = Array.isArray(paired.devices)
|
|
58
|
+
? paired.devices
|
|
59
|
+
: Array.isArray(paired)
|
|
60
|
+
? paired
|
|
61
|
+
: [];
|
|
62
|
+
|
|
63
|
+
for (const device of devices) {
|
|
64
|
+
const scopes = Array.isArray(device?.scopes) ? device.scopes : [];
|
|
65
|
+
if (!scopes.includes("operator.write")) continue;
|
|
66
|
+
const token = device?.tokens?.operator?.token;
|
|
67
|
+
if (token && typeof token === "string") return token;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
log?.warn?.("openclawGatewayClient.readToken.notFound", "no operator.write device with token in paired.json");
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 从 ~/.openclaw/openclaw.json 读取 gateway.port,默认 18789。
|
|
76
|
+
*
|
|
77
|
+
* @param {{ log?: object, _readJsonFn?: Function }} opts
|
|
78
|
+
* @returns {Promise<number>}
|
|
79
|
+
*/
|
|
80
|
+
export async function readOpenclawGatewayPort({ log, _readJsonFn } = {}) {
|
|
81
|
+
const readJson = _readJsonFn ?? ((path) => _readJsonFileSafe(path));
|
|
82
|
+
const cfgPath = join(homedir(), ".openclaw", "openclaw.json");
|
|
83
|
+
|
|
84
|
+
let cfg;
|
|
85
|
+
try {
|
|
86
|
+
cfg = await readJson(cfgPath);
|
|
87
|
+
} catch (err) {
|
|
88
|
+
log?.warn?.("openclawGatewayClient.readPort.err", "openclaw.json read failed", { err: err?.message });
|
|
89
|
+
return DEFAULT_GATEWAY_PORT;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const port = cfg?.gateway?.port;
|
|
93
|
+
return typeof port === "number" && port > 0 ? port : DEFAULT_GATEWAY_PORT;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 通过 openclaw gateway WebSocket 发送 chat.abort。
|
|
98
|
+
*
|
|
99
|
+
* 整体超时 5s;失败返回 { ok: false, limited, error },不抛。
|
|
100
|
+
*
|
|
101
|
+
* @param {{
|
|
102
|
+
* sessionKey: string,
|
|
103
|
+
* log?: object,
|
|
104
|
+
* _tokenFn?: () => Promise<string|null>,
|
|
105
|
+
* _portFn?: () => Promise<number>,
|
|
106
|
+
* _wsFactory?: (url: string) => WebSocket,
|
|
107
|
+
* }} opts
|
|
108
|
+
* @returns {Promise<{ ok: true, aborted: number } | { ok: false, limited: string, error: string }>}
|
|
109
|
+
*/
|
|
110
|
+
export async function openclawChatAbort({
|
|
111
|
+
sessionKey,
|
|
112
|
+
log,
|
|
113
|
+
_tokenFn,
|
|
114
|
+
_portFn,
|
|
115
|
+
_wsFactory,
|
|
116
|
+
} = {}) {
|
|
117
|
+
// 读取 token
|
|
118
|
+
const getToken = _tokenFn ?? (() => readOpenclawOperatorToken({ log }));
|
|
119
|
+
const getPort = _portFn ?? (() => readOpenclawGatewayPort({ log }));
|
|
120
|
+
|
|
121
|
+
const token = await getToken();
|
|
122
|
+
if (!token) {
|
|
123
|
+
return { ok: false, limited: "openclaw-no-token", error: "no operator token found in paired.json" };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const port = await getPort();
|
|
127
|
+
const url = `ws://127.0.0.1:${port}`;
|
|
128
|
+
|
|
129
|
+
// WS 通信(带超时)
|
|
130
|
+
return await Promise.race([
|
|
131
|
+
_performWsAbort({ url, token, sessionKey, log, _wsFactory }),
|
|
132
|
+
_timeout(5000, "openclaw-gateway-unreachable", "WS operation timed out after 5s"),
|
|
133
|
+
]);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ── 内部实现 ──────────────────────────────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
async function _performWsAbort({ url, token, sessionKey, log, _wsFactory }) {
|
|
139
|
+
let ws;
|
|
140
|
+
try {
|
|
141
|
+
ws = _wsFactory ? _wsFactory(url) : new WebSocket(url);
|
|
142
|
+
} catch (err) {
|
|
143
|
+
return {
|
|
144
|
+
ok: false,
|
|
145
|
+
limited: "openclaw-gateway-unreachable",
|
|
146
|
+
error: `WS connect failed: ${err?.message || String(err)}`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return new Promise((resolve) => {
|
|
151
|
+
let phase = "connecting"; // connecting → hello → abort → done
|
|
152
|
+
|
|
153
|
+
function cleanup() {
|
|
154
|
+
try { ws.close(); } catch {}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function fail(limited, error) {
|
|
158
|
+
cleanup();
|
|
159
|
+
resolve({ ok: false, limited, error });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
ws.addEventListener("error", (evt) => {
|
|
163
|
+
const msg = evt?.message || String(evt?.error || "ws error");
|
|
164
|
+
if (phase === "connecting" || phase === "hello") {
|
|
165
|
+
fail("openclaw-gateway-unreachable", `WS error: ${msg}`);
|
|
166
|
+
} else {
|
|
167
|
+
fail("openclaw-gateway-unreachable", `WS error during abort: ${msg}`);
|
|
168
|
+
}
|
|
169
|
+
phase = "done";
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
ws.addEventListener("open", () => {
|
|
173
|
+
phase = "hello";
|
|
174
|
+
// 发送握手 connect
|
|
175
|
+
ws.send(JSON.stringify({
|
|
176
|
+
type: "req",
|
|
177
|
+
id: "1",
|
|
178
|
+
method: "connect",
|
|
179
|
+
params: {
|
|
180
|
+
minProtocol: 4,
|
|
181
|
+
maxProtocol: 4,
|
|
182
|
+
token,
|
|
183
|
+
},
|
|
184
|
+
}));
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
ws.addEventListener("message", (evt) => {
|
|
188
|
+
let msg;
|
|
189
|
+
try {
|
|
190
|
+
msg = JSON.parse(typeof evt.data === "string" ? evt.data : evt.data.toString());
|
|
191
|
+
} catch {
|
|
192
|
+
return; // 忽略不可解析帧
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (phase === "hello") {
|
|
196
|
+
const msgType = msg?.type ?? "";
|
|
197
|
+
if (msgType === "hello-ok" || msgType === "hello_ok") {
|
|
198
|
+
// 握手成功,发 chat.abort
|
|
199
|
+
phase = "abort";
|
|
200
|
+
ws.send(JSON.stringify({
|
|
201
|
+
type: "req",
|
|
202
|
+
id: "2",
|
|
203
|
+
method: "chat.abort",
|
|
204
|
+
params: { sessionKey },
|
|
205
|
+
}));
|
|
206
|
+
} else if (msgType === "hello-err" || msgType === "hello_err") {
|
|
207
|
+
phase = "done";
|
|
208
|
+
fail("openclaw-auth-failed", `gateway hello-err: ${msg?.error || "auth failed"}`);
|
|
209
|
+
}
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (phase === "abort") {
|
|
214
|
+
// 等待 chat.abort 响应(id="2" 或任意 res)
|
|
215
|
+
const isResponse = msg?.id === "2" || msg?.type === "res";
|
|
216
|
+
if (isResponse) {
|
|
217
|
+
phase = "done";
|
|
218
|
+
cleanup();
|
|
219
|
+
resolve({ ok: true, aborted: 1 });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function _timeout(ms, limited, error) {
|
|
227
|
+
return new Promise((resolve) =>
|
|
228
|
+
setTimeout(() => resolve({ ok: false, limited, error }), ms)
|
|
229
|
+
);
|
|
230
|
+
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
// pair code consume + 本地持久化。
|
|
2
|
+
//
|
|
3
|
+
// 升级后的协议(对齐服务端 internal/handler/pair_code/handler.go):
|
|
4
|
+
//
|
|
5
|
+
// POST /v1/pair-codes/<code>/consume
|
|
6
|
+
// Body: {"client_user_id":"<...>", "runtime":"hermes|claude|codex|openclaw"}
|
|
7
|
+
// Response: {"status":"ok", "gw_id":"...", "bridge_token":"...", "runtime":"..."}
|
|
8
|
+
//
|
|
9
|
+
// session_id 现在是 gw_id —— 服务端 BridgeStore.Issue 颁发的 gateway 身份。
|
|
10
|
+
// bridge 走 long-poll worker 模式,所有通讯都用 (gw_id, bridge_token) 鉴权,
|
|
11
|
+
// 不再走 SSE 订阅 / 不再有"unified thread_id"概念,session 概念退化。
|
|
12
|
+
//
|
|
13
|
+
// 兼容路径:服务端仍保留 /api/ext/pair-codes/<code>/consume(legacy 老 cli 用),
|
|
14
|
+
// 这里默认调新端点;失败回退老端点(让用户在升级期间不会全炸)。
|
|
15
|
+
//
|
|
16
|
+
// 存储位置: ~/.agentlink/ext-<runtime>-last.json,内容兼容老格式
|
|
17
|
+
// (新增 gw_id,session_id 仍保留作 legacy 兼容,值与 gw_id 相同)。
|
|
18
|
+
|
|
19
|
+
import fs from "node:fs";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import os from "node:os";
|
|
22
|
+
import process from "node:process";
|
|
23
|
+
import relayDefaults from "../../src-shared/relay-defaults.json" with { type: "json" };
|
|
24
|
+
import { CLI_STATE_DIR_NAME } from "./attachAuditLog.mjs";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Normalize a raw hostname for reporting to the server.
|
|
28
|
+
*
|
|
29
|
+
* Rules (applied in order):
|
|
30
|
+
* 1. trim whitespace
|
|
31
|
+
* 2. strip `.local` or `.localdomain` suffix (case-sensitive — macOS produces lowercase)
|
|
32
|
+
* 3. truncate to 64 graphemes (unicode-safe)
|
|
33
|
+
* 4. if empty → return "unknown-host"
|
|
34
|
+
*
|
|
35
|
+
* The function is pure — it takes a string and never calls os.hostname().
|
|
36
|
+
* Callers pass os.hostname() themselves so this is unit-testable without monkey-patching.
|
|
37
|
+
*
|
|
38
|
+
* @param {string} raw e.g. os.hostname()
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
41
|
+
export function normalizeHostName(raw) {
|
|
42
|
+
let s = String(raw ?? "").trim();
|
|
43
|
+
if (s.endsWith(".local")) s = s.slice(0, -".local".length);
|
|
44
|
+
else if (s.endsWith(".localdomain")) s = s.slice(0, -".localdomain".length);
|
|
45
|
+
const graphemes = Array.from(s);
|
|
46
|
+
if (graphemes.length > 64) s = graphemes.slice(0, 64).join("");
|
|
47
|
+
return s || "unknown-host";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** 默认 relay URL。 */
|
|
51
|
+
export const DEFAULT_RELAY_URL = relayDefaults.defaultRelayUrl;
|
|
52
|
+
|
|
53
|
+
/** 4 种合法 runtime — 与服务端 util.IsValidRuntimeKind 对齐。 */
|
|
54
|
+
export const VALID_RUNTIMES = Object.freeze(["hermes", "claude", "codex", "openclaw"]);
|
|
55
|
+
|
|
56
|
+
/** 按优先级解析 relay url:显式 --relay > env > 默认。永远有值。 */
|
|
57
|
+
export function resolveRelayUrl(optionsRelay) {
|
|
58
|
+
const opt = typeof optionsRelay === "string" ? optionsRelay.trim() : "";
|
|
59
|
+
if (opt) return opt;
|
|
60
|
+
const env = process.env.AGENTLINK_RELAY_URL?.trim() || "";
|
|
61
|
+
if (env) return env;
|
|
62
|
+
return DEFAULT_RELAY_URL;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 唯一来源:目录名 CLI_STATE_DIR_NAME 来自 attachAuditLog.mjs
|
|
66
|
+
// 改名 agentlink 时只改那里;这里动态计算确保测试注入 HOME 时路径正确。
|
|
67
|
+
//
|
|
68
|
+
// 必须认 AGENTLINK_HOME —— native 侧(bin/agentlink 的 resolveAgentlinkHome)优先
|
|
69
|
+
// 读 AGENTLINK_HOME 来定位 ~/.agentlink;ext 侧若只用 os.homedir(),当用户/ service
|
|
70
|
+
// 设了 AGENTLINK_HOME≠$HOME/.agentlink 时两侧分叉 —— reset 的孤儿探测(bin 的
|
|
71
|
+
// runtimeHasLocalState)与 ext 的实际清理读写不同文件,导致漏检/空操作。统一优先
|
|
72
|
+
// AGENTLINK_HOME(其值即 .agentlink 目录全路径),保持四端 pair state 定位一致。
|
|
73
|
+
function stateDir() {
|
|
74
|
+
const fromEnv = process.env.AGENTLINK_HOME?.trim();
|
|
75
|
+
if (fromEnv) return fromEnv;
|
|
76
|
+
return path.join(os.homedir(), CLI_STATE_DIR_NAME);
|
|
77
|
+
}
|
|
78
|
+
function stateFile(runtime) { return path.join(stateDir(), `ext-${runtime}-last.json`); }
|
|
79
|
+
function configJsonFile() { return path.join(stateDir(), "config.json"); }
|
|
80
|
+
function ensureDir() {
|
|
81
|
+
try { fs.mkdirSync(stateDir(), { recursive: true }); return true; }
|
|
82
|
+
catch { return false; }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// openclaw / hermes 的 pair 凭证由 `agentlink pair` 命令写到
|
|
86
|
+
// ~/.agentlink/config.json (key: relayGatewayId/Token、hermesRelayGatewayId/Token),
|
|
87
|
+
// 与 claude/codex 用的 ext-<runtime>-last.json 是两套独立存储。bridge 历史只读
|
|
88
|
+
// ext 文件,导致 openclaw/hermes 新版 pair 后 bridge 启动报"尚未配对"。
|
|
89
|
+
// 这里加一层 fallback:ext 文件不存在 / 字段不全时,从 config.json 兜底。
|
|
90
|
+
function readPairStateFromConfig(runtime) {
|
|
91
|
+
if (runtime !== "hermes" && runtime !== "openclaw") return null;
|
|
92
|
+
let parsed;
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(fs.readFileSync(configJsonFile(), "utf8"));
|
|
95
|
+
} catch { return null; }
|
|
96
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
97
|
+
const idKey = runtime === "hermes" ? "hermesRelayGatewayId" : "relayGatewayId";
|
|
98
|
+
const tokKey = runtime === "hermes" ? "hermesRelayGatewayToken" : "relayGatewayToken";
|
|
99
|
+
const gwId = String(parsed[idKey] || "").trim();
|
|
100
|
+
const relayUrl = String(parsed.relayUrl || "").trim();
|
|
101
|
+
const bridgeToken = String(parsed[tokKey] || "").trim();
|
|
102
|
+
if (!gwId || !relayUrl) return null;
|
|
103
|
+
return {
|
|
104
|
+
gw_id: gwId,
|
|
105
|
+
runtime,
|
|
106
|
+
relay_url: relayUrl,
|
|
107
|
+
bridge_token: bridgeToken,
|
|
108
|
+
saved_at: null,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 读本地保存的 pair 状态。
|
|
114
|
+
* 老格式只有 session_id,新格式同时有 gw_id;读时兼容(gw_id 缺时用 session_id 兜底)。
|
|
115
|
+
*
|
|
116
|
+
* @returns {{gw_id, runtime, relay_url, bridge_token, saved_at} | null}
|
|
117
|
+
*/
|
|
118
|
+
export function readPairState(runtime) {
|
|
119
|
+
try {
|
|
120
|
+
const raw = fs.readFileSync(stateFile(runtime), "utf8");
|
|
121
|
+
const obj = JSON.parse(raw);
|
|
122
|
+
if (!obj || typeof obj !== "object") return readPairStateFromConfig(runtime);
|
|
123
|
+
if (obj.runtime !== runtime) return readPairStateFromConfig(runtime);
|
|
124
|
+
const gwId = String(obj.gw_id || obj.session_id || "").trim();
|
|
125
|
+
const relayUrl = String(obj.relay_url || "").trim();
|
|
126
|
+
if (!gwId || !relayUrl) return readPairStateFromConfig(runtime);
|
|
127
|
+
const result = {
|
|
128
|
+
gw_id: gwId,
|
|
129
|
+
runtime: obj.runtime,
|
|
130
|
+
relay_url: relayUrl,
|
|
131
|
+
bridge_token: String(obj.bridge_token || "").trim(),
|
|
132
|
+
saved_at: obj.saved_at || null,
|
|
133
|
+
};
|
|
134
|
+
// hermesProfileName: hermes-profile-isolation 新字段,旧 pair state 无此字段
|
|
135
|
+
if (obj.hermesProfileName != null) {
|
|
136
|
+
result.hermesProfileName = String(obj.hermesProfileName);
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
} catch { return readPairStateFromConfig(runtime); }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 写入 pair 状态。同时写 gw_id 与 session_id(后者为 legacy 字段,与 gw_id 同值)。
|
|
144
|
+
* hermesProfileName 可选字段,hermes runtime 配对时写入,供 bridge 启动时读取。
|
|
145
|
+
*/
|
|
146
|
+
export function writePairState(runtime, { gw_id, relay_url, bridge_token, hermesProfileName }) {
|
|
147
|
+
if (!ensureDir()) return false;
|
|
148
|
+
const id = String(gw_id || "").trim();
|
|
149
|
+
if (!id) return false;
|
|
150
|
+
const obj = {
|
|
151
|
+
gw_id: id,
|
|
152
|
+
session_id: id, // legacy 字段保留,服务管理脚本读老格式时不报错
|
|
153
|
+
runtime,
|
|
154
|
+
relay_url,
|
|
155
|
+
bridge_token: bridge_token || "",
|
|
156
|
+
saved_at: new Date().toISOString(),
|
|
157
|
+
};
|
|
158
|
+
// hermes profile name: 写入时携带,供 bridge 启动读取 profileHome
|
|
159
|
+
if (hermesProfileName != null) {
|
|
160
|
+
obj.hermesProfileName = String(hermesProfileName);
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
fs.writeFileSync(stateFile(runtime), JSON.stringify(obj, null, 2) + "\n", "utf8");
|
|
164
|
+
return true;
|
|
165
|
+
} catch { return false; }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function clearPairState(runtime) {
|
|
169
|
+
try { fs.unlinkSync(stateFile(runtime)); return true; }
|
|
170
|
+
catch { return false; }
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* 已废弃 — 旧的 SSE cursor 概念。新 worker 模式不需要;保留空函数避免外部 import 报错。
|
|
175
|
+
*/
|
|
176
|
+
export function clearCursor() { return false; }
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 向 server 消费 pair code。
|
|
180
|
+
*
|
|
181
|
+
* runtime 必填 — 服务端复合主键(code, runtime)允许同 code 复用到不同 runtime。
|
|
182
|
+
* 优先调新端点 /v1/pair-codes/<code>/consume,404/410 时回退老端点
|
|
183
|
+
* /api/ext/pair-codes/<code>/consume(让升级期同时存在新老服务端的环境工作)。
|
|
184
|
+
*
|
|
185
|
+
* 返回 server 响应:
|
|
186
|
+
* { status:"ok", gw_id, bridge_token, runtime }
|
|
187
|
+
*
|
|
188
|
+
* 老端点的响应字段 session_id 会被规范化为 gw_id。
|
|
189
|
+
*
|
|
190
|
+
* @param {{relayUrl:string, code:string, runtime:string, clientUserId?:string, fetchImpl?:Function}} args
|
|
191
|
+
*/
|
|
192
|
+
export async function consumePairCode({ relayUrl, code, runtime, clientUserId, fetchImpl }) {
|
|
193
|
+
const f = fetchImpl || globalThis.fetch;
|
|
194
|
+
if (typeof f !== "function") throw new Error("fetch unavailable");
|
|
195
|
+
const rt = String(runtime ?? "").trim().toLowerCase();
|
|
196
|
+
if (!VALID_RUNTIMES.includes(rt)) {
|
|
197
|
+
throw new Error(`consumePairCode: runtime must be one of ${VALID_RUNTIMES.join(", ")}`);
|
|
198
|
+
}
|
|
199
|
+
const cuid = String(clientUserId ?? "").trim() || `cli-${rt}`;
|
|
200
|
+
const base = relayUrl.replace(/\/+$/, "");
|
|
201
|
+
|
|
202
|
+
const hostName = normalizeHostName(os.hostname());
|
|
203
|
+
|
|
204
|
+
// 1. 优先打新端点
|
|
205
|
+
const v1 = `${base}/v1/pair-codes/${encodeURIComponent(code)}/consume`;
|
|
206
|
+
const v1Body = JSON.stringify({ client_user_id: cuid, runtime: rt, hostName });
|
|
207
|
+
const v1Res = await f(v1, {
|
|
208
|
+
method: "POST",
|
|
209
|
+
headers: { "Content-Type": "application/json" },
|
|
210
|
+
body: v1Body,
|
|
211
|
+
});
|
|
212
|
+
const v1Text = await v1Res.text();
|
|
213
|
+
if (v1Res.ok) {
|
|
214
|
+
return parseConsumeBody(v1Text, rt);
|
|
215
|
+
}
|
|
216
|
+
if (v1Res.status !== 404) {
|
|
217
|
+
// 404 = 端点不存在 → 老服务,回退;其它(400/410/500)直接抛。
|
|
218
|
+
throw makeConsumeError(v1Res.status, v1Text);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// 2. 回退老端点 /api/ext/pair-codes/<code>/consume
|
|
222
|
+
const legacy = `${base}/api/ext/pair-codes/${encodeURIComponent(code)}/consume?runtime=${rt}`;
|
|
223
|
+
const legacyRes = await f(legacy, {
|
|
224
|
+
method: "POST",
|
|
225
|
+
headers: { "Content-Type": "application/json" },
|
|
226
|
+
body: JSON.stringify({ runtime: rt, client_user_id: cuid, hostName }),
|
|
227
|
+
});
|
|
228
|
+
const legacyText = await legacyRes.text();
|
|
229
|
+
if (!legacyRes.ok) throw makeConsumeError(legacyRes.status, legacyText);
|
|
230
|
+
return parseConsumeBody(legacyText, rt);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function parseConsumeBody(text, expectedRuntime) {
|
|
234
|
+
let obj;
|
|
235
|
+
try { obj = JSON.parse(text); }
|
|
236
|
+
catch (err) { throw new Error(`consume: bad json response: ${err?.message}`); }
|
|
237
|
+
if (!obj || typeof obj !== "object") throw new Error("consume: empty response");
|
|
238
|
+
// 新端点返回 gw_id;老端点返回 session_id(也是 gw_id 值)。统一成 gw_id。
|
|
239
|
+
const gwId = String(obj.gw_id || obj.session_id || "").trim();
|
|
240
|
+
if (!gwId) throw new Error("consume: response missing gw_id/session_id");
|
|
241
|
+
const bridgeToken = String(obj.bridge_token || "").trim();
|
|
242
|
+
const rt = String(obj.runtime || expectedRuntime).toLowerCase();
|
|
243
|
+
return { status: "ok", gw_id: gwId, bridge_token: bridgeToken, runtime: rt };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function makeConsumeError(status, text) {
|
|
247
|
+
const snippet = String(text || "").slice(0, 200);
|
|
248
|
+
if (status === 404) {
|
|
249
|
+
const err = new Error(`pair code invalid or expired: ${snippet}`);
|
|
250
|
+
err.code = "PAIR_NOT_FOUND";
|
|
251
|
+
return err;
|
|
252
|
+
}
|
|
253
|
+
if (status === 410) {
|
|
254
|
+
const err = new Error(`pair code already consumed or expired: ${snippet}`);
|
|
255
|
+
err.code = "PAIR_GONE";
|
|
256
|
+
return err;
|
|
257
|
+
}
|
|
258
|
+
return new Error(`consume failed: HTTP ${status} ${snippet}`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* 一站式:根据 CLI 参数解析出最终要用的 { gwId, relayUrl, bridgeToken }。
|
|
263
|
+
*
|
|
264
|
+
* 规则:
|
|
265
|
+
* 1. options.pair 有值: 调 consume,写本地状态,返回新结果
|
|
266
|
+
* 2. options["session-id"] 有值: 直接返回(需要 options.relay 或 env 给 relay)
|
|
267
|
+
* —— bridge_token 缺失时返回空,worker 启动会失败,提示用户重新 pair
|
|
268
|
+
* 3. 否则:读本地状态(上次 pair 过的)
|
|
269
|
+
* 4. 找不到就抛错
|
|
270
|
+
*/
|
|
271
|
+
export async function resolveSession({ runtime, options, log }) {
|
|
272
|
+
const relay = resolveRelayUrl(options.relay);
|
|
273
|
+
if (options.pair) {
|
|
274
|
+
log?.info("pair.consume.start", "consuming pair code", { code: options.pair, relay });
|
|
275
|
+
const res = await consumePairCode({
|
|
276
|
+
relayUrl: relay,
|
|
277
|
+
code: String(options.pair),
|
|
278
|
+
runtime,
|
|
279
|
+
clientUserId: options["client-user-id"] ? String(options["client-user-id"]) : undefined,
|
|
280
|
+
});
|
|
281
|
+
if (res.runtime !== runtime) {
|
|
282
|
+
throw new Error(
|
|
283
|
+
`pair code is for runtime=${res.runtime}, but you ran agentlink-agent ${runtime}`,
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
writePairState(runtime, {
|
|
287
|
+
gw_id: res.gw_id,
|
|
288
|
+
relay_url: relay,
|
|
289
|
+
bridge_token: res.bridge_token,
|
|
290
|
+
});
|
|
291
|
+
log?.info("pair.consumed", "pair code accepted", {
|
|
292
|
+
gw_id: res.gw_id, runtime, has_bridge_token: !!res.bridge_token,
|
|
293
|
+
});
|
|
294
|
+
return {
|
|
295
|
+
gwId: res.gw_id,
|
|
296
|
+
relayUrl: relay,
|
|
297
|
+
source: "pair",
|
|
298
|
+
bridgeToken: res.bridge_token || "",
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
if (options["session-id"] || options["gw-id"]) {
|
|
302
|
+
return {
|
|
303
|
+
gwId: String(options["gw-id"] || options["session-id"]),
|
|
304
|
+
relayUrl: relay,
|
|
305
|
+
source: "explicit",
|
|
306
|
+
bridgeToken: "",
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
const saved = readPairState(runtime);
|
|
310
|
+
if (saved) {
|
|
311
|
+
log?.info("pair.state.reuse", "reusing saved pair state", {
|
|
312
|
+
gw_id: saved.gw_id, relay: saved.relay_url, has_bridge_token: !!saved.bridge_token,
|
|
313
|
+
});
|
|
314
|
+
const savedResult = {
|
|
315
|
+
gwId: saved.gw_id,
|
|
316
|
+
relayUrl: saved.relay_url,
|
|
317
|
+
source: "saved",
|
|
318
|
+
bridgeToken: saved.bridge_token || "",
|
|
319
|
+
};
|
|
320
|
+
// N2.3: 透传 hermesProfileName(hermes-profile-isolation)
|
|
321
|
+
if (saved.hermesProfileName != null) {
|
|
322
|
+
savedResult.profileName = saved.hermesProfileName;
|
|
323
|
+
}
|
|
324
|
+
return savedResult;
|
|
325
|
+
}
|
|
326
|
+
throw new Error(
|
|
327
|
+
"尚未配对。请在 App 上创建会话,然后运行:\n" +
|
|
328
|
+
` agentlink pair <4位码> -r ${runtime}\n` +
|
|
329
|
+
"配对成功后 CLI 会自动在后台保活运行。",
|
|
330
|
+
);
|
|
331
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pairInventory.mjs — pair-all host-inventory Phase 2 辅助
|
|
3
|
+
*
|
|
4
|
+
* 把 runPairAll 的 summary 数组与 detectInstalledRuntimes 的 detected 数组
|
|
5
|
+
* 合并成 relay /v1/pair-sessions/:code/host-inventory Phase 2 POST 所需的
|
|
6
|
+
* results 数组。
|
|
7
|
+
*
|
|
8
|
+
* outcome 映射规则(与 spec-delta cli-pair-session-result 对齐):
|
|
9
|
+
* summary ok=true && !skipped → "paired_new"
|
|
10
|
+
* summary skipped=true → "paired_existing"
|
|
11
|
+
* summary ok=false → "failed"
|
|
12
|
+
* 未出现在 summary(未安装) → "not_installed"
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** 所有被扫描的 runtime 名(固定 4 个)。 */
|
|
16
|
+
const SCANNED_RUNTIMES = ["openclaw", "hermes", "claude", "codex"];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* buildPairSessionResults 从 summary + detected 构建 per-runtime outcome 列表。
|
|
20
|
+
*
|
|
21
|
+
* @param {Array<{kind: string, ok: boolean, skipped?: boolean}>} summary
|
|
22
|
+
* runPairAll 内的 summary 数组,只包含已安装的 runtime。
|
|
23
|
+
* @param {Array<{kind: string, installed: boolean}>} detected
|
|
24
|
+
* detectInstalledRuntimes 的返回值,含全部 4 个 runtime。
|
|
25
|
+
* @returns {Array<{runtime: string, outcome: string}>}
|
|
26
|
+
* 长度为 4,覆盖全部 scanned runtimes。
|
|
27
|
+
*/
|
|
28
|
+
export function buildPairSessionResults(summary, detected) {
|
|
29
|
+
// 构建 summaryMap:kind → summary entry(方便 O(1) 查找)
|
|
30
|
+
const summaryMap = new Map(summary.map((s) => [s.kind, s]));
|
|
31
|
+
|
|
32
|
+
// 构建 installedSet:已安装的 runtime 集合
|
|
33
|
+
const installedSet = new Set(
|
|
34
|
+
(detected || []).filter((d) => d.installed).map((d) => d.kind),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return SCANNED_RUNTIMES.map((rt) => {
|
|
38
|
+
const s = summaryMap.get(rt);
|
|
39
|
+
let outcome;
|
|
40
|
+
|
|
41
|
+
if (s) {
|
|
42
|
+
// 出现在 summary → 已安装且参与过配对流程
|
|
43
|
+
if (s.skipped) {
|
|
44
|
+
outcome = "paired_existing";
|
|
45
|
+
} else if (s.ok) {
|
|
46
|
+
outcome = "paired_new";
|
|
47
|
+
} else {
|
|
48
|
+
outcome = "failed";
|
|
49
|
+
}
|
|
50
|
+
} else if (!installedSet.has(rt)) {
|
|
51
|
+
outcome = "not_installed";
|
|
52
|
+
} else {
|
|
53
|
+
// 已安装但没有出现在 summary(理论上不应发生)→ 保守标 failed
|
|
54
|
+
outcome = "failed";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { runtime: rt, outcome };
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pathExpand.mjs — ~ 展开工具
|
|
3
|
+
*
|
|
4
|
+
* expandHome(p): 展开路径中的 ~ 前缀(~ 或 ~/),再 path.resolve 为绝对路径。
|
|
5
|
+
* 四种 runtime 共用,是统一路径规范化的基础。
|
|
6
|
+
*
|
|
7
|
+
* 规则:
|
|
8
|
+
* "~" → os.homedir()
|
|
9
|
+
* "~/" → os.homedir() + "/"(join 后 resolve)
|
|
10
|
+
* "~/foo" → path.join(os.homedir(), "foo")
|
|
11
|
+
* 其他 → path.resolve(p)(绝对路径不变,相对路径基于 cwd 解析)
|
|
12
|
+
*
|
|
13
|
+
* 注意:~foo(非 ~/)不展开,视为普通路径(与 bash 行为一致,~foo 是他人 home)。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import os from "node:os";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 展开路径中的 ~ 前缀,再 path.resolve 到绝对路径。
|
|
21
|
+
*
|
|
22
|
+
* @param {string} p 输入路径(可能含 ~ 前缀)
|
|
23
|
+
* @returns {string} 绝对路径字符串
|
|
24
|
+
*/
|
|
25
|
+
export function expandHome(p) {
|
|
26
|
+
if (typeof p !== "string") p = String(p ?? "");
|
|
27
|
+
if (p === "~") {
|
|
28
|
+
return path.resolve(os.homedir());
|
|
29
|
+
}
|
|
30
|
+
if (p.startsWith("~/")) {
|
|
31
|
+
return path.resolve(path.join(os.homedir(), p.slice(2)));
|
|
32
|
+
}
|
|
33
|
+
return path.resolve(p);
|
|
34
|
+
}
|