@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/README.md
ADDED
|
@@ -0,0 +1,860 @@
|
|
|
1
|
+
# @xyagent/cli
|
|
2
|
+
|
|
3
|
+
把本地 AI runtime(OpenClaw 或 Hermes)接入 Agentlink relay 服务的独立 CLI。
|
|
4
|
+
|
|
5
|
+
手机端 App 通过 relay 跟本地 runtime 对话,CLI 负责:
|
|
6
|
+
|
|
7
|
+
- 配对:把手机 App 账号和本地 runtime 绑定到同一个 relay gateway
|
|
8
|
+
- 桥接:长时间运行一个中继 worker,把 relay 队列里的请求拉下来、喂给本地 runtime、再把事件发回 relay
|
|
9
|
+
- 守护:用系统服务(launchd / systemd / Task Scheduler)让桥接在后台常驻
|
|
10
|
+
|
|
11
|
+
**深入文档**:
|
|
12
|
+
|
|
13
|
+
- [docs/PAIR_FLOW.md](docs/PAIR_FLOW.md) — `agentlink pair` 完整流程:每一步做了什么、改了哪些文件、`--runtime all` 模式遇到 runtime 缺失怎么处理、对 OpenClaw 配置改动的安全性分析、故障排查 checklist
|
|
14
|
+
- [docs/EXTERNAL_AGENTS.md](docs/EXTERNAL_AGENTS.md) — claude / codex 等外部 agent 接入指南
|
|
15
|
+
- [docs/LOGGING.md](docs/LOGGING.md) — 日志格式与排查
|
|
16
|
+
- [docs/PLATFORM.md](docs/PLATFORM.md) — 跨平台细节(launchd / systemd / Windows)
|
|
17
|
+
- [agentlink-server/TOOL_EVENTS.md](../agentlink-server/TOOL_EVENTS.md) — 工具调用链事件 schema(OpenClaw plugin / Hermes / Codex / Claude → server `session.tool` 字段映射 + 真实样例)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. 整体架构
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
┌────────────────┐ HTTPS / SSE ┌───────────────────────┐
|
|
25
|
+
│ Mobile App │◀─────────────────▶│ Relay Server (Go) │
|
|
26
|
+
│ (nexus_flutter)│ │ go-relay-test.xyagent.com │
|
|
27
|
+
└────────────────┘ │ │
|
|
28
|
+
│ MySQL + Redis │
|
|
29
|
+
└───────────┬───────────┘
|
|
30
|
+
│
|
|
31
|
+
long-poll + POST events
|
|
32
|
+
│
|
|
33
|
+
┌───────────▼───────────┐
|
|
34
|
+
│ agentlink CLI (Node) │
|
|
35
|
+
│ bin/agentlink │
|
|
36
|
+
│ │
|
|
37
|
+
│ ┌─────────────────┐ │
|
|
38
|
+
│ │ Bridge worker │ │
|
|
39
|
+
│ └────────┬────────┘ │
|
|
40
|
+
└───────────┼───────────┘
|
|
41
|
+
│
|
|
42
|
+
┌───────────────┬────────────────┼────────────────┬──────────────┐
|
|
43
|
+
│ │ │ │ │
|
|
44
|
+
(runtime=openclaw) (runtime=hermes) (runtime=claude) (runtime=codex) │
|
|
45
|
+
│ │ │ │ │
|
|
46
|
+
HTTP /v1/responses agentlink- agentlink- agentlink- (其他 runtime
|
|
47
|
+
│ agent hermes agent claude agent codex 走相同 shim)
|
|
48
|
+
▼ ▼ ▼ ▼ ▼
|
|
49
|
+
┌────────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
|
|
50
|
+
│ OpenClaw GW │ │ Hermes JS │ │ Claude CLI │ │ Codex MCP │
|
|
51
|
+
│ (外部进程) │ │ HTTP/cmd │ │ stream-json│ │ stdio │
|
|
52
|
+
│ 127.0.0.1:<p> │ │ backend │ │ │ │ │
|
|
53
|
+
└────────────────┘ └────────────┘ └────────────┘ └────────────┘
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**核心架构(重构后)**:4 种 runtime 走**完全统一的 long-poll 模式**,CLI 端不做协议翻译。
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
启动 (任意 runtime bridge)
|
|
60
|
+
│
|
|
61
|
+
1. POST /v1/pair-codes/<code>/consume
|
|
62
|
+
body { client_user_id, runtime }
|
|
63
|
+
resp { gw_id, bridge_token, runtime }
|
|
64
|
+
│
|
|
65
|
+
2. 持久化 ~/.agentlink/ext-<runtime>-last.json
|
|
66
|
+
│
|
|
67
|
+
3. long-poll loop(永不退出):
|
|
68
|
+
┌─ GET /v1/gateways/<gw>/requests/next?waitSeconds=25
|
|
69
|
+
│ Bearer <bridge_token>
|
|
70
|
+
│ ↓ 拿到 user request
|
|
71
|
+
│
|
|
72
|
+
├─ 调本地 runtime(LLM HTTP / Claude CLI / Codex MCP / OpenClaw HTTP)
|
|
73
|
+
│
|
|
74
|
+
├─ 流式 POST /v1/gateways/<gw>/requests/<rid>/events
|
|
75
|
+
│ body 是该 runtime 的 native 事件(stream-json / OpenAI SSE chunk / codex/event 等)
|
|
76
|
+
│ ↑↑↑ 服务端 internal/adapter/<runtime>/ 翻译为统一信封
|
|
77
|
+
│
|
|
78
|
+
└─ 心跳 POST /v1/gateways/<gw>/meta(每 10s)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**关键特征(重构后)**:
|
|
82
|
+
|
|
83
|
+
- CLI bridge **不知道**统一 Agent SSE 协议(`/v1/agents/threads/*` 端点)的存在
|
|
84
|
+
- CLI bridge **直接发** runtime 自己的原生事件,服务端 `adapter/<runtime>/` 做 native → unified envelope 翻译
|
|
85
|
+
- 之前 CLI 端的 `src-ext/core/unified_relay_shim.mjs` 翻译层 + `src-shared/agent-client/` HTTP 封装**已整体删除**
|
|
86
|
+
- 4 个 bridge(OpenClaw / Hermes / Claude / Codex)共用同一套 `relayWorker` long-poll 主循环
|
|
87
|
+
|
|
88
|
+
三个关键角色:
|
|
89
|
+
|
|
90
|
+
| 角色 | 位置 | 职责 |
|
|
91
|
+
| ---------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
92
|
+
| **Relay Server** | `agentlink-server/`(Go) | 握住 App ↔ runtime 之间的所有流量;`internal/adapter/<runtime>/` 把 native 事件翻成统一信封 |
|
|
93
|
+
| **CLI** | `bin/agentlink` + `bin/agentlink-agent`(Node ≥22)| 配对 + 桥接;4 种 runtime 共用 `relayWorker` long-poll 主循环;不做协议翻译 |
|
|
94
|
+
| **Runtime** | OpenClaw gateway / Hermes(JS) / Claude CLI / Codex CLI | 实际执行 AI turn 的进程或本地 LLM 调用 |
|
|
95
|
+
|
|
96
|
+
### 4 种 runtime bridge 对比
|
|
97
|
+
|
|
98
|
+
| Runtime | 启动命令 | 入口文件 | native 协议(POST 给服务端的事件格式) | 服务端 adapter |
|
|
99
|
+
| -------- | ------------------------- | --------------------------------------------------------------------- | --------------------------------------------- | --------------------------------------- |
|
|
100
|
+
| OpenClaw | `agentlink bridge` | `src/tunnel.mjs` + `src/tunnel_proxy.mjs` + `src/tunnel_state.mjs` | OpenClaw `/v1/responses` SSE chunk | `internal/adapter/openclaw` |
|
|
101
|
+
| Hermes | `agentlink-agent hermes` | `src-ext/runtime/hermes/index.mjs` | OpenAI-compatible SSE / NDJSON | `internal/adapter/hermes`(共享 openclaw 逻辑) |
|
|
102
|
+
| Claude | `agentlink-agent claude` | `src-ext/runtime/claude/index.mjs` | Claude CLI stream-json | `internal/adapter/claude` |
|
|
103
|
+
| Codex | `agentlink-agent codex` | `src-ext/runtime/codex/index.mjs` | Codex MCP `codex/event` notification | `internal/adapter/codex` |
|
|
104
|
+
|
|
105
|
+
4 个 bridge 入口文件大小都 ≤ 800 行硬限,最大约 700 行。
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 2. 代码结构
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
agentlink-cli/
|
|
113
|
+
├── bin/
|
|
114
|
+
│ ├── agentlink # 用户入口(setup / pair / bridge / service / tunnel)
|
|
115
|
+
│ ├── agentlink-agent # bridge 子进程入口(claude / codex / hermes)
|
|
116
|
+
│ └── agentlink-mcp-stdio # codex 反向 MCP stdio bridge
|
|
117
|
+
├── src/ # OpenClaw bridge + tunnel + 共享工具
|
|
118
|
+
│ ├── core.mjs # URL / code 归一化 / 路径解析等
|
|
119
|
+
│ ├── tunnel.mjs # OpenClaw bridge 主循环(277 行)
|
|
120
|
+
│ ├── tunnel_proxy.mjs # OpenClaw HTTP / SSE 转发(476 行)
|
|
121
|
+
│ ├── tunnel_state.mjs # 文件锁 / 状态机(301 行)
|
|
122
|
+
│ └── tunnel_service.mjs # OpenClaw 桥接的 service install/uninstall
|
|
123
|
+
├── src-shared/ # 纯基础设施(无业务依赖)
|
|
124
|
+
│ ├── logger.mjs # 结构化 JSON 日志
|
|
125
|
+
│ ├── correlation.mjs # cid 生成 / 解析
|
|
126
|
+
│ └── relay-defaults.json # 默认 relay URL
|
|
127
|
+
├── src-ext/ # External Agents(Claude / Codex / Hermes)
|
|
128
|
+
│ ├── bin.mjs # agentlink-agent 入口分发
|
|
129
|
+
│ ├── commands/ # pair / service / agent / reload / help 子命令
|
|
130
|
+
│ ├── core/
|
|
131
|
+
│ │ ├── pairCodeClient.mjs # POST /v1/pair-codes/<code>/consume + 状态持久化
|
|
132
|
+
│ │ ├── relayWorker.mjs # 4 个 bridge 共用的 long-poll 主循环
|
|
133
|
+
│ │ ├── relayWorkerHttp.mjs # bridge_token Bearer header / fetchJson 工具
|
|
134
|
+
│ │ ├── sessionSlot.mjs # 单 session 槽状态机
|
|
135
|
+
│ │ ├── stateMachine.mjs # 通用 FSM
|
|
136
|
+
│ │ ├── approvalGateway.mjs # HITL 工具审批
|
|
137
|
+
│ │ ├── mcpStdioClient.mjs # MCP stdio 客户端(codex 用)
|
|
138
|
+
│ │ ├── agentlinkToolsRegistry.mjs / agentlinkToolsServer.mjs # 反向工具注入
|
|
139
|
+
│ │ ├── accountResolver.mjs # accountId/clientUserId 解析
|
|
140
|
+
│ │ └── usageReporter.mjs # token 用量上报
|
|
141
|
+
│ ├── runtime/
|
|
142
|
+
│ │ ├── claude/index.mjs # Claude bridge(spawn `claude` CLI + stream-json,223 行)
|
|
143
|
+
│ │ ├── codex/index.mjs # Codex bridge(spawn `codex` MCP stdio,240 行)
|
|
144
|
+
│ │ └── hermes/index.mjs # Hermes bridge(OpenAI-compatible HTTP / subprocess,256 行)
|
|
145
|
+
│ ├── service/
|
|
146
|
+
│ │ └── serviceManager.mjs # launchd / systemd / Task Scheduler 统一接入
|
|
147
|
+
│ └── openclaw-plugin/ # agentlink-hooks OpenClaw 插件源码(详见 docs/PLUGIN_ACTIVE_RUNS.md)
|
|
148
|
+
└── test/ # node --test 测试套件(72 个 test)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Hermes 已 100% JS 化** —— 旧 `runtime/hermes_bridge/` Python 目录已删除。`bin/agentlink` 中所有 Python 探测 / spawn 逻辑也已清除。
|
|
152
|
+
|
|
153
|
+
**已删除的代码(重构清理)**:
|
|
154
|
+
|
|
155
|
+
- `src-ext/core/unified_relay_shim.mjs` —— 整个文件删除。之前 CLI 在这里把 legacy `{kind: ...}` 事件翻译成统一信封 + POST 到 `/v1/agents/threads/<tid>/events`,现在改由服务端 adapter 翻译
|
|
156
|
+
- `src-shared/agent-client/` —— 整个目录删除。CLI bridge 不再调统一协议端点,因此不需要 `/v1/agents/*` HTTP + SSE 客户端
|
|
157
|
+
- 各 runtime 子目录里的 unified 翻译辅助文件(如 `usageReporter` 的 envelope 包装等)
|
|
158
|
+
|
|
159
|
+
`bin/agentlink` 本身只 spawn `agentlink-agent` 子进程;`openclaw` CLI 是外部可执行文件,通过 `PATH` / `OPENCLAW_HOME` 定位。
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 3. 4 种 runtime 模式
|
|
164
|
+
|
|
165
|
+
CLI 通过 `runtimeKind` 分流。**所有 runtime 在线协议层完全一致** —— 4 个 bridge 共用 `src-ext/core/relayWorker.mjs` long-poll 主循环,通过相同的 3 个端点跟 relay 通讯:
|
|
166
|
+
|
|
167
|
+
- `POST /v1/pair-codes/<code>/consume`(启动配对)
|
|
168
|
+
- `GET /v1/gateways/<gw>/requests/next?waitSeconds=25`(长轮询拉用户消息)
|
|
169
|
+
- `POST /v1/gateways/<gw>/requests/<rid>/events`(流式回 native 事件)
|
|
170
|
+
- `POST /v1/gateways/<gw>/meta`(10s 心跳)
|
|
171
|
+
|
|
172
|
+
唯一的差异是 bridge 内部对接的本地 runtime 进程,以及推回 relay 的 native 事件格式。**CLI 不做协议翻译**,服务端 `internal/adapter/<runtime>/` 把 native 事件统一翻译为 unified envelope 落库 `agent_events` 表。
|
|
173
|
+
|
|
174
|
+
### 3.1 OpenClaw 模式(默认)
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
App ──► Relay ──► CLI bridge (Node) ──► HTTP POST /v1/responses ──► OpenClaw Gateway
|
|
178
|
+
│
|
|
179
|
+
events ◄──────────────── SSE / JSON ┘
|
|
180
|
+
(publish back to relay)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- 入口:`agentlink bridge`(`src/tunnel.mjs` 主循环 + `tunnel_proxy.mjs` HTTP / SSE 转发 + `tunnel_state.mjs` 状态机)
|
|
184
|
+
- OpenClaw 是独立的外部进程(`openclaw gateway run`),监听 `127.0.0.1:<port>`
|
|
185
|
+
- CLI 把 relay long-poll 拉下来的请求转成 `POST /v1/responses`,再把流式响应原样切片发回 relay
|
|
186
|
+
- 网关鉴权:CLI 从 `~/.openclaw/config.json` 读 `gateway.auth.token`
|
|
187
|
+
- 服务端 `internal/adapter/openclaw` 把 OpenClaw 的 SSE chunk 翻译为统一信封事件
|
|
188
|
+
|
|
189
|
+
### 3.2 Hermes 模式(pure JS,已替代旧 Python bridge)
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
App ──► Relay ──► agentlink-agent hermes ──► OpenAI-compatible HTTP
|
|
193
|
+
long-poll (Node 22+ stdlib fetch) (or external command)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
- 入口:`agentlink-agent hermes`(`src-ext/runtime/hermes/index.mjs`,256 行)
|
|
197
|
+
- 走 `relayWorker` long-poll:拿到 user request → 调本地 LLM → 流式回 OpenAI-compatible SSE chunk 给 relay
|
|
198
|
+
- 后端 2 选 1:
|
|
199
|
+
- **HTTP**:`HERMES_BRIDGE_API_BASE_URL` + `HERMES_BRIDGE_API_KEY`(OpenAI / DeepSeek / 自建 vLLM 等)
|
|
200
|
+
- **subprocess**:`HERMES_BRIDGE_COMMAND="<path-to-binary>"`(newline-delimited JSON 协议)
|
|
201
|
+
- 本地 transcript 存在 `~/.agentlink/hermes/sessions/<sessionId>.json`
|
|
202
|
+
- 零 Python 依赖
|
|
203
|
+
|
|
204
|
+
### 3.3 Claude 模式
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
App ──► Relay ──► agentlink-agent claude ──► spawn `claude` CLI (stream-json)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
- 入口:`agentlink-agent claude`(`src-ext/runtime/claude/index.mjs`,223 行)
|
|
211
|
+
- spawn 外部 `claude` CLI(Anthropic 官方),从 stdout 读 stream-json,**直接**作为事件 POST 到 `/v1/gateways/<gw>/requests/<rid>/events`
|
|
212
|
+
- 服务端 `internal/adapter/claude` 解析 stream-json,把 `assistant_message_delta` / `tool_use_block` / `parent_tool_use_id` 等翻译成统一信封事件(`content_block.delta` / `tool_use` / subagent run_id 等)
|
|
213
|
+
- 工具审批走 `approvalGateway`:PreToolUse hook → 推 interrupt block → 等 App 端 resume
|
|
214
|
+
|
|
215
|
+
### 3.4 Codex 模式
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
App ──► Relay ──► agentlink-agent codex ──► spawn `codex` MCP stdio server
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
- 入口:`agentlink-agent codex`(`src-ext/runtime/codex/index.mjs`,240 行)
|
|
222
|
+
- 通过 MCP stdio 协议跟 `codex` CLI 通信,反向注入 `agentlink-mcp-stdio` 作为工具服务器
|
|
223
|
+
- `codex/event` notification 直接序列化为事件 POST 给 relay
|
|
224
|
+
- 服务端 `internal/adapter/codex` 把 `codex/event` 翻译为统一信封
|
|
225
|
+
|
|
226
|
+
4 种 runtime 使用**独立**的 relay 凭证和独立的 session 模型(见 `AppRuntimeKind` 枚举),配对流程里由 App 端决定写哪一组。
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## 4. Relay 协议
|
|
231
|
+
|
|
232
|
+
CLI 跟 relay 之间只走 HTTP(长轮询 + POST),没有 WebSocket。关键端点:
|
|
233
|
+
|
|
234
|
+
### 4.1 配对阶段
|
|
235
|
+
|
|
236
|
+
| 端点 | 方向 | 用途 |
|
|
237
|
+
| ------------------------------------------ | ----------- | -------------------------------------------------------------------- |
|
|
238
|
+
| `POST /v1/pair-sessions` | App → Relay | App 创建 4 位 pair code(含 `accountId` / `runtimeKind`) |
|
|
239
|
+
| `GET /v1/pair-sessions/{code}` | CLI → Relay | (openclaw 模式)查配对 session 是否存在、读出 App 设定的 runtimeKind |
|
|
240
|
+
| **`POST /v1/pair-codes/{code}/consume`** | CLI → Relay | **统一入口**:消费 4 位码,body `{client_user_id, runtime}` → 颁发 `{gw_id, bridge_token, runtime}` |
|
|
241
|
+
|
|
242
|
+
兼容性:服务端仍保留 `POST /api/ext/pair-codes/<code>/consume?runtime=<rt>`(legacy 老 CLI 用),新 CLI 默认调 `/v1/pair-codes/...`,404 / 410 时回退老端点(升级期间双端兼容)。
|
|
243
|
+
|
|
244
|
+
### 4.2 桥接阶段
|
|
245
|
+
|
|
246
|
+
| 端点 | 方向 | 用途 |
|
|
247
|
+
| ----------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------- |
|
|
248
|
+
| `GET /v1/gateways/{gwId}/requests/next?waitSeconds=N` | CLI/bridge → Relay | long-poll 下一个 request(204 表示超时) |
|
|
249
|
+
| `POST /v1/gateways/{gwId}/requests/{reqId}/events` | CLI/bridge → Relay | 推 native 事件(`start` / `chunk` / `end` / `error` / `response`),服务端 adapter 翻译为 unified envelope |
|
|
250
|
+
| `POST /v1/gateways/{gwId}/chat-events` | CLI → Relay | OpenClaw 模式下发送结构化聊天事件(供 App 做 structured history) |
|
|
251
|
+
| `POST /v1/gateways/{gwId}/meta` | CLI/bridge → Relay | presence 心跳(`online` / `connected` / `state`),默认 10s 一次 |
|
|
252
|
+
| `GET/DELETE /v1/gateways/{gwId}/binding` | CLI → Relay | 查询 / 解绑当前 gateway |
|
|
253
|
+
| `POST /v1/gateways/{gwId}/reset` | CLI → Relay | 硬重置(`agentlink reset`) |
|
|
254
|
+
|
|
255
|
+
**鉴权**:桥接阶段所有端点用 `Authorization: Bearer <bridge_token>`(pair-codes consume 颁发,单向 producer-only)。
|
|
256
|
+
|
|
257
|
+
> **bridge_token vs client_token**
|
|
258
|
+
>
|
|
259
|
+
> CLI 持有的是 `bridge_token`(producer 凭证):能 long-poll 拉 user request、能 POST events 推回。
|
|
260
|
+
> App 侧持有的是 `client_token`(consumer 凭证):能 GET `/v1/agents/threads/<tid>/stream` 订阅、能查询 thread 状态。
|
|
261
|
+
> **两个 token 互不可换用**,混用返回 403。
|
|
262
|
+
|
|
263
|
+
### 4.3 事件形状
|
|
264
|
+
|
|
265
|
+
桥接 worker 发回 relay 的事件统一是:
|
|
266
|
+
|
|
267
|
+
```json
|
|
268
|
+
{
|
|
269
|
+
"event": "start|chunk|end|error|response",
|
|
270
|
+
"sessionKey": "agent:<id>:relay-gw:<gwId>::<sessionKey>",
|
|
271
|
+
"runId": "...",
|
|
272
|
+
"statusCode": 200,
|
|
273
|
+
"contentType": "text/event-stream; charset=utf-8",
|
|
274
|
+
"data": "...",
|
|
275
|
+
"createdAtMs": 1713312000000
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
`sessionKey` 格式前后端不一致:App 侧带装饰前缀(`agent:` / `relay-gw:`),relay 事件来的是裸 key。两边比较必须归一化(Go 端 `normalizeSessionKeyForMatch`,Flutter 端 `_sessionKeyMatchesForPreview`)。
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## 5. 典型流程
|
|
284
|
+
|
|
285
|
+
### 5.1 配对(`agentlink pair <code>`,统一 long-poll 模式)
|
|
286
|
+
|
|
287
|
+
4 种 runtime 走完全一致的配对流程(OpenClaw 多一步本地 daemon 重启,详见 [docs/PAIR_FLOW.md](docs/PAIR_FLOW.md)):
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
App Relay CLI
|
|
291
|
+
│ │ │
|
|
292
|
+
│ 1. POST /v1/pair-sessions │ │
|
|
293
|
+
│ {runtime, accountId, │ │
|
|
294
|
+
│ clientUserId} │ │
|
|
295
|
+
├────────────────────────────▶│ │
|
|
296
|
+
│ │ │
|
|
297
|
+
│ 2. App 屏幕显示 4 位 code │ │
|
|
298
|
+
│ │ │
|
|
299
|
+
│ │ 3. 用户在 CLI 输入 code │
|
|
300
|
+
│ │ │
|
|
301
|
+
│ │ 4. POST /v1/pair-codes/ │
|
|
302
|
+
│ │ <code>/consume │
|
|
303
|
+
│ │ {client_user_id, │
|
|
304
|
+
│ │ runtime} │
|
|
305
|
+
│ │◀────────────────────────────┤
|
|
306
|
+
│ │ │
|
|
307
|
+
│ │ 5. {gw_id, bridge_token, │
|
|
308
|
+
│ │ runtime} │
|
|
309
|
+
│ ├────────────────────────────▶│
|
|
310
|
+
│ │ │
|
|
311
|
+
│ │ 6. 持久化到 │
|
|
312
|
+
│ │ ~/.agentlink/ │
|
|
313
|
+
│ │ ext-<runtime>-last.json│
|
|
314
|
+
│ │ │
|
|
315
|
+
│ │ 7. 进入 long-poll loop: │
|
|
316
|
+
│ │ GET .../requests/next │
|
|
317
|
+
│ │◀────────────────────────────┤
|
|
318
|
+
│ │ │
|
|
319
|
+
│ 8. App 端订阅 thread │ │
|
|
320
|
+
│ GET /v1/agents/threads/ │ │
|
|
321
|
+
│ <tid>/stream │ │
|
|
322
|
+
├────────────────────────────▶│ │
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
配对完成判定 = `/pair-codes/<code>/consume` 返回 `gw_id` + `bridge_token`。CLI 立刻进入 long-poll 主循环,不需要再等 App 端"确认"。
|
|
326
|
+
|
|
327
|
+
持久化位置(按 runtime 分文件,互不干扰):
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
~/.agentlink/ext-openclaw-last.json
|
|
331
|
+
~/.agentlink/ext-hermes-last.json
|
|
332
|
+
~/.agentlink/ext-claude-last.json
|
|
333
|
+
~/.agentlink/ext-codex-last.json
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
文件内容:`{ gw_id, runtime, relay_url, bridge_token, saved_at }`。`session_id` 字段保留作老 CLI 兼容(值与 `gw_id` 相同)。
|
|
337
|
+
|
|
338
|
+
### 5.2 桥接(`agentlink bridge`,OpenClaw 模式)
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
┌──────────┐ ┌──────────┐ ┌────────────┐
|
|
342
|
+
│ CLI │ long-poll 90s │ Relay │ │ OpenClaw │
|
|
343
|
+
│ bridge │───────────────────▶│ │ │ Gateway │
|
|
344
|
+
│ │◀───────────────────│ │ │ /v1/resp.. │
|
|
345
|
+
│ │ request │ │ │ │
|
|
346
|
+
│ │ │ │ │ │
|
|
347
|
+
│ │─── POST /v1/resp ─────────────────────────▶ │ │
|
|
348
|
+
│ │◀── SSE stream ────────────────────────────── │ │
|
|
349
|
+
│ │ │ │ │ │
|
|
350
|
+
│ │── POST events ────▶│ │ │ │
|
|
351
|
+
│ │ (start/chunk/ │ │ │ │
|
|
352
|
+
│ │ end) │ │ │ │
|
|
353
|
+
│ │ │ │ │ │
|
|
354
|
+
│ │── POST meta ──────▶│ │ │ │
|
|
355
|
+
│ │ (heartbeat 10s) │ │ │ │
|
|
356
|
+
└──────────┘ └──────────┘ └────────────┘
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
- Bridge 使用 `acquireBridgeLock` 做文件锁,防止一台机器上两个 bridge 抢同一个 gateway
|
|
360
|
+
- SIGINT/SIGTERM 时发一次 `state: "stopped"` presence,让 App 立刻看到离线(而不是等 25s TTL)
|
|
361
|
+
|
|
362
|
+
### 5.3 桥接(Hermes / Claude / Codex 模式 — 统一 long-poll)
|
|
363
|
+
|
|
364
|
+
3 个 External Agent runtime 共用同一套主循环,只是本地 backend 不同:
|
|
365
|
+
|
|
366
|
+
```
|
|
367
|
+
agentlink-agent <hermes|claude|codex>
|
|
368
|
+
│
|
|
369
|
+
├── relayWorker.run(handler):
|
|
370
|
+
│ loop:
|
|
371
|
+
│ req = GET /v1/gateways/<gw>/requests/next?waitSeconds=25
|
|
372
|
+
│ if 204 → continue // long-poll 超时
|
|
373
|
+
│ handler(req, ctx) →
|
|
374
|
+
│
|
|
375
|
+
├── handler 实现(按 runtime 分流):
|
|
376
|
+
│ hermes: fetch(POST OpenAI /chat/completions, stream:true)
|
|
377
|
+
│ ↓ 每个 SSE chunk: ctx.publishEvent({kind:"chunk", data:...})
|
|
378
|
+
│ claude: spawn `claude` CLI(stream-json mode)
|
|
379
|
+
│ ↓ 每个 stream-json 事件: ctx.publishEvent({kind:"chunk", data:...})
|
|
380
|
+
│ codex: MCP stdio 双向通讯 + 反向工具注入
|
|
381
|
+
│ ↓ 每个 codex/event: ctx.publishEvent({kind:"chunk", data:...})
|
|
382
|
+
│
|
|
383
|
+
├── ctx.publishEvent → POST /v1/gateways/<gw>/requests/<rid>/events
|
|
384
|
+
│ body 是 native 事件,**不在 CLI 翻译**
|
|
385
|
+
│
|
|
386
|
+
└── 心跳 POST /v1/gateways/<gw>/meta(每 10s)
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
服务端 `internal/adapter/<runtime>/` 接到 native 事件后翻译为统一信封写入 `agent_events` 表。
|
|
390
|
+
|
|
391
|
+
Hermes 会话历史持久化在 `~/.agentlink/hermes/sessions/<sessionId>.json`。无 Python,无 venv,无 pip install。
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## 6. 安装 & 快速开始
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
npm i -g @xyagent/cli
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
OpenClaw 模式(默认):
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
# 1) 准备 OpenClaw 配置 + relay 凭证
|
|
405
|
+
agentlink setup \
|
|
406
|
+
--relay http://<relay-host>:8090 \
|
|
407
|
+
--public-base http://<gateway-public-host>:<port>
|
|
408
|
+
|
|
409
|
+
# 2) 启动本地 OpenClaw gateway
|
|
410
|
+
openclaw gateway run --bind loopback --port <port> --force
|
|
411
|
+
|
|
412
|
+
# 3) 用 App 里生成的 code 完成配对
|
|
413
|
+
agentlink pair 123456
|
|
414
|
+
|
|
415
|
+
# 4) 把桥接装成后台服务
|
|
416
|
+
agentlink service install
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Hermes 模式(pure JS,无 Python 依赖):
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
# 配置后端:HTTP(OpenAI-compatible)
|
|
423
|
+
export HERMES_BRIDGE_API_BASE_URL=https://api.openai.com/v1
|
|
424
|
+
export HERMES_BRIDGE_API_KEY=sk-xxx
|
|
425
|
+
export HERMES_BRIDGE_MODEL=gpt-4o-mini
|
|
426
|
+
|
|
427
|
+
# 或者用 subprocess 后端(外部 binary,NDJSON 协议)
|
|
428
|
+
# export HERMES_BRIDGE_COMMAND=/path/to/my-llm-script
|
|
429
|
+
|
|
430
|
+
# 配对(CLI 自动检测后端 env,未配置会报错)
|
|
431
|
+
agentlink pair 123456 --runtime hermes
|
|
432
|
+
|
|
433
|
+
# 前台跑(调试)
|
|
434
|
+
agentlink bridge --runtime hermes
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Claude / Codex External Agents:
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
# Claude Code / Codex CLI 需要先在本机安装并登录
|
|
441
|
+
|
|
442
|
+
# 配对后会自动安装后台服务
|
|
443
|
+
agentlink pair 1234 -r claude
|
|
444
|
+
agentlink pair 1234 -r codex
|
|
445
|
+
|
|
446
|
+
# 前台调试运行(当前终端内运行,Ctrl+C 可停止)
|
|
447
|
+
agentlink bridge -r claude
|
|
448
|
+
agentlink bridge -r codex
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
重装 App 后重新配对(典型场景):
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
# 如果之前是 hermes 模式,配对报 "这台主机已经绑定过设备"
|
|
455
|
+
agentlink reset --runtime hermes # 只清 hermes 凭证,不动 openclaw
|
|
456
|
+
agentlink pair <new-code> --runtime hermes
|
|
457
|
+
|
|
458
|
+
# openclaw 模式不传 --runtime 即可
|
|
459
|
+
agentlink reset
|
|
460
|
+
agentlink pair <new-code>
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## 7. 命令参考
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
agentlink setup [--relay URL] [--public-base URL] # 写配置 + 装权限
|
|
469
|
+
agentlink pair <code> [--runtime openclaw|hermes|claude|codex] # 配对;claude/codex 默认会自动装后台服务
|
|
470
|
+
agentlink bridge [--runtime openclaw|hermes|claude|codex] # 前台运行桥接;claude/codex 用 Ctrl+C 停止
|
|
471
|
+
agentlink service install|stop|uninstall|restart|status [--runtime ...] # 后台服务;claude/codex 中 stop 是 uninstall 别名
|
|
472
|
+
agentlink uninstall --runtime claude|codex # claude/codex 完整卸载:停服务 + 清本地配对状态
|
|
473
|
+
agentlink reset [--runtime openclaw|hermes] [--gateway GWID] # 硬重置绑定
|
|
474
|
+
agentlink pair-url [--account ID] [--code CODE] # 生成手动配对 URL
|
|
475
|
+
agentlink tunnel on <port> [--relay URL] # 暴露本地 HTTP 端口
|
|
476
|
+
agentlink tunnel off <port> [--relay URL] # 关闭端口转发
|
|
477
|
+
agentlink tunnel ls # 查看 tunnel 状态
|
|
478
|
+
agentlink status [--runtime openclaw|hermes] # 查当前 runtime / 服务 / 绑定
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Tunnel 快速测试
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
# 启一个本地测试服务(任何 HTTP 服务器都行;这里用 Node 内置)
|
|
485
|
+
mkdir -p /tmp/agentlink-tunnel-demo
|
|
486
|
+
printf 'hello tunnel\n' >/tmp/agentlink-tunnel-demo/index.html
|
|
487
|
+
node -e 'import("node:http").then(({createServer})=>{import("node:fs").then(({readFileSync})=>{createServer((_,res)=>res.end(readFileSync("/tmp/agentlink-tunnel-demo/index.html"))).listen(8080,"127.0.0.1");console.log("listening on 127.0.0.1:8080");})})'
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
另一个终端:
|
|
491
|
+
|
|
492
|
+
```bash
|
|
493
|
+
agentlink tunnel on 8080
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
示例输出:
|
|
497
|
+
|
|
498
|
+
```text
|
|
499
|
+
Tunnel started
|
|
500
|
+
Local: http://127.0.0.1:8080
|
|
501
|
+
Public: https://go-relay-test.xyagent.com/t/p8080-03ce6ff5
|
|
502
|
+
Logs: ~/.agentlink/logs/tunnel-8080.log
|
|
503
|
+
Mode: systemd-user
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
说明:
|
|
507
|
+
|
|
508
|
+
- tunnel agent 会每 10 秒向 relay 发 heartbeat
|
|
509
|
+
- relay 超过约 35 秒没收到 heartbeat,会把 tunnel 视为 offline,并对公网请求直接返回 `503 tunnel offline`
|
|
510
|
+
- `agentlink tunnel on <port>` 会直接打印公网访问地址,示例里的 `Public: https://...` 就是可分享的访问 URL
|
|
511
|
+
- 如果不传 `--relay`,默认使用 CLI 当前内置或环境变量指定的 relay 地址
|
|
512
|
+
- 后台守护优先走当前平台的服务管理:
|
|
513
|
+
- Linux: `systemd --user`
|
|
514
|
+
- macOS: `launchd`
|
|
515
|
+
- Windows: `Task Scheduler`
|
|
516
|
+
- 如果当前环境没有可用的服务管理器,会自动回退到 detached 进程,并在 `agentlink tunnel on` 输出里提示
|
|
517
|
+
|
|
518
|
+
### Tunnel 技术实现
|
|
519
|
+
|
|
520
|
+
这套 tunnel 是标准的反向内网穿透,不要求目标机器有公网 IP,也不要求目标机器开放入站端口。
|
|
521
|
+
|
|
522
|
+
核心思路:
|
|
523
|
+
|
|
524
|
+
- 外部用户访问的是 relay server 暴露出来的公网 URL,例如 `https://go-relay-test.xyagent.com/t/<slug>`
|
|
525
|
+
- 内网机器上的 `agentlink tunnel agent` 主动连接 relay,通过长轮询拉取待处理请求
|
|
526
|
+
- agent 在本机访问 `127.0.0.1:<port>`,再把响应回传给 relay
|
|
527
|
+
- relay 把响应返回给浏览器或调用方
|
|
528
|
+
|
|
529
|
+
涉及的 3 个角色:
|
|
530
|
+
|
|
531
|
+
- `Client / Browser`
|
|
532
|
+
- 访问公网 tunnel 地址
|
|
533
|
+
- `Relay Server`
|
|
534
|
+
- 负责创建 tunnel、分配 `slug`、接收公网请求、转发给 agent、返回响应
|
|
535
|
+
- `Tunnel Agent`
|
|
536
|
+
- 运行在用户机器上,负责 heartbeat、拉取请求、访问本地服务、发布响应
|
|
537
|
+
|
|
538
|
+
关键接口:
|
|
539
|
+
|
|
540
|
+
- `POST /v1/tunnels`
|
|
541
|
+
- 创建 tunnel,返回 `id`、`agentToken`、`publicUrl`
|
|
542
|
+
- `GET /v1/tunnels/:id/requests/next`
|
|
543
|
+
- agent 长轮询拉取待处理请求
|
|
544
|
+
- `POST /v1/tunnels/:id/heartbeat`
|
|
545
|
+
- agent 上报存活状态
|
|
546
|
+
- `POST /v1/tunnels/:id/responses/:reqId/publish`
|
|
547
|
+
- agent 发布本地服务响应
|
|
548
|
+
- `GET /t/:slug/*path`
|
|
549
|
+
- 公网入口,外部流量从这里进入 tunnel
|
|
550
|
+
|
|
551
|
+
工作流程:
|
|
552
|
+
|
|
553
|
+
```mermaid
|
|
554
|
+
sequenceDiagram
|
|
555
|
+
participant U as "User / Browser"
|
|
556
|
+
participant R as "Agentlink Relay Server"
|
|
557
|
+
participant A as "Agentlink Tunnel Agent"
|
|
558
|
+
participant L as "Local Service (127.0.0.1:8080)"
|
|
559
|
+
|
|
560
|
+
A->>R: "POST /v1/tunnels"
|
|
561
|
+
R-->>A: "id + agentToken + publicUrl"
|
|
562
|
+
A->>R: "POST /v1/tunnels/:id/heartbeat"
|
|
563
|
+
A->>R: "GET /v1/tunnels/:id/requests/next"
|
|
564
|
+
|
|
565
|
+
U->>R: "GET /t/:slug/api/echo?x=1"
|
|
566
|
+
R-->>A: "返回待处理 request"
|
|
567
|
+
A->>L: "GET http://127.0.0.1:8080/api/echo?x=1"
|
|
568
|
+
L-->>A: "200 + headers + body"
|
|
569
|
+
A->>R: "POST /v1/tunnels/:id/responses/:reqId/publish"
|
|
570
|
+
R-->>U: "200 + headers + body"
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
在线状态与恢复机制:
|
|
574
|
+
|
|
575
|
+
- agent 每 `10s` 发送一次 heartbeat
|
|
576
|
+
- server 超过约 `35s` 没收到 heartbeat,会把 tunnel 判定为 `offline`
|
|
577
|
+
- `offline` 状态下,公网请求会直接返回 `503 tunnel offline`
|
|
578
|
+
- 后台运行优先使用系统服务托管:
|
|
579
|
+
- Linux: `systemd --user`,root 环境额外支持 `systemd system service`
|
|
580
|
+
- macOS: `launchd`
|
|
581
|
+
- Windows: `Task Scheduler`
|
|
582
|
+
- 如果 agent 进程异常退出,服务管理器会自动重启;如果没有服务管理器,则退回 detached 进程模式
|
|
583
|
+
|
|
584
|
+
实现边界:
|
|
585
|
+
|
|
586
|
+
- 当前 tunnel 第一版只支持 HTTP 请求/响应转发
|
|
587
|
+
- 支持 path、query、JSON/body、常见响应头透传
|
|
588
|
+
- 暂不包含 WebSocket、任意 TCP、UDP 转发
|
|
589
|
+
- 公网入口当前使用路径路由 `/t/<slug>`,没有使用独立子域名
|
|
590
|
+
|
|
591
|
+
复杂路由跳转的适配说明:
|
|
592
|
+
|
|
593
|
+
- 大多数复杂 Web 系统都可以正常工作,包括:
|
|
594
|
+
- SPA 前端路由,例如 `react-router`、`vue-router`
|
|
595
|
+
- 后端页面路由,例如 `/admin/users/list`
|
|
596
|
+
- 带 query 的跳转,例如 `/orders?page=2&status=paid`
|
|
597
|
+
- 常见的 `301/302/307/308` 重定向
|
|
598
|
+
- 这类场景通常没问题,因为 tunnel 会保留:
|
|
599
|
+
- 请求 path
|
|
600
|
+
- 原始 query string
|
|
601
|
+
- 常规请求头与响应头
|
|
602
|
+
- HTTP 状态码
|
|
603
|
+
- `x-forwarded-host`
|
|
604
|
+
- 真正容易出问题的通常不是“路由复杂”,而是“应用把绝对地址写死”:
|
|
605
|
+
- 例如后端返回 `Location: http://127.0.0.1:8080/login`
|
|
606
|
+
- 或前端代码里写死 `http://内网IP:端口/...`
|
|
607
|
+
- 或登录回调地址、Cookie domain、绝对资源地址强依赖固定 host
|
|
608
|
+
- 推荐应用侧尽量使用相对路径,或者正确读取反向代理后的 host/proto 信息生成跳转地址
|
|
609
|
+
- 如果系统强依赖 WebSocket、HMR dev server、长连接 upgrade,当前版本需要单独验证,不能默认保证完全可用
|
|
610
|
+
|
|
611
|
+
固定的 `curl` 用例:
|
|
612
|
+
|
|
613
|
+
```bash
|
|
614
|
+
# 1) GET 根路径
|
|
615
|
+
curl -i https://go-relay-test.xyagent.com/t/p8080-03ce6ff5
|
|
616
|
+
|
|
617
|
+
# 2) GET 带 path + query
|
|
618
|
+
curl -i 'https://go-relay-test.xyagent.com/t/p8080-03ce6ff5/api/echo?name=agentlink&mode=query'
|
|
619
|
+
|
|
620
|
+
# 3) POST JSON 到带 path + query 的入口
|
|
621
|
+
curl -i \
|
|
622
|
+
-X POST \
|
|
623
|
+
'https://go-relay-test.xyagent.com/t/p8080-03ce6ff5/api/echo?source=curl&lang=zh' \
|
|
624
|
+
-H 'content-type: application/json' \
|
|
625
|
+
-d '{"hello":"world","from":"agentlink"}'
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
看 agent 日志:
|
|
629
|
+
|
|
630
|
+
```bash
|
|
631
|
+
tail -f ~/.agentlink/logs/tunnel-8080.log
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
关闭:
|
|
635
|
+
|
|
636
|
+
```bash
|
|
637
|
+
agentlink tunnel off 8080
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
`agentlink reset` 的行为:
|
|
641
|
+
|
|
642
|
+
| 命令 | 作用对象 |
|
|
643
|
+
| -------------------------------- | --------------------------------------------------- |
|
|
644
|
+
| `agentlink reset` | 重置 openclaw 凭证(并额外清空 hermes 凭证,兜底) |
|
|
645
|
+
| `agentlink reset --runtime hermes`| **只**清 hermes 凭证,openclaw 绑定不动 |
|
|
646
|
+
|
|
647
|
+
reset 做的事:
|
|
648
|
+
|
|
649
|
+
- 调 relay `DELETE /v1/gateways/{id}/binding` 清服务端绑定(配对码 / 会话 / 联系人)
|
|
650
|
+
- 卸载目标 runtime 的后台服务(launchd / systemd / Task Scheduler)
|
|
651
|
+
- 停掉目标 runtime 正在跑的桥接进程
|
|
652
|
+
- 清 `~/.agentlink/config.json` 本地凭证:
|
|
653
|
+
- openclaw → 重新生成 `relayGatewayId` + 轮换 token,并连带清空 hermes 凭证
|
|
654
|
+
- hermes → 只删 `hermesRelayGatewayId` / `hermesRelayClientToken` / `hermesRelayGatewayToken`
|
|
655
|
+
|
|
656
|
+
reset 完成后即可对同一 runtime 发起新的 `agentlink pair`。
|
|
657
|
+
|
|
658
|
+
code 接受 `1234`、`123456` 或 `XXXX-XXXX`(参考 `normalizeProvidedCode`)。
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
## 8. 服务管理
|
|
663
|
+
|
|
664
|
+
| 平台 | 机制 | 单元文件 |
|
|
665
|
+
| ------------------ | ----------------- | ----------------------------------------------------------- |
|
|
666
|
+
| macOS | launchd | `~/Library/LaunchAgents/com.agentlink.bridge[-hermes].plist` |
|
|
667
|
+
| Linux (systemd) | systemd user unit | `~/.config/systemd/user/agentlink-bridge[-hermes].service` |
|
|
668
|
+
| Linux (无 systemd) | — | 只能手动 `agentlink bridge`,service install 会报友好错误 |
|
|
669
|
+
| Windows | Task Scheduler | task name `Agentlink Bridge` |
|
|
670
|
+
|
|
671
|
+
OpenClaw 和 Hermes 两种 runtime 的服务名**不同**(参考 `serviceNames(runtimeKind)`),可以同时装一台机上跑两种:
|
|
672
|
+
|
|
673
|
+
```bash
|
|
674
|
+
agentlink service status # 默认看 openclaw
|
|
675
|
+
agentlink service status --runtime hermes # 看 hermes 服务
|
|
676
|
+
agentlink service install # 装 openclaw bridge(默认)
|
|
677
|
+
agentlink service install --runtime hermes # 装 hermes bridge
|
|
678
|
+
agentlink service uninstall [--runtime hermes] # 停 + 删
|
|
679
|
+
agentlink service restart [--runtime hermes] # 重启
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
日志:
|
|
683
|
+
|
|
684
|
+
```bash
|
|
685
|
+
# OpenClaw 桥接日志
|
|
686
|
+
tail -f ~/.agentlink/logs/bridge.stdout.log
|
|
687
|
+
tail -f ~/.agentlink/logs/bridge.stderr.log
|
|
688
|
+
|
|
689
|
+
# Hermes 桥接日志
|
|
690
|
+
tail -f ~/.agentlink/logs/bridge-hermes.stdout.log
|
|
691
|
+
tail -f ~/.agentlink/logs/bridge-hermes.stderr.log
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
### Claude / Codex(External Agents)
|
|
695
|
+
|
|
696
|
+
Claude / Codex 走的是独立的 `agentlink-agent` service 管理实现,命令入口仍然是顶层 `agentlink`:
|
|
697
|
+
|
|
698
|
+
| 平台 | 机制 | 单元文件 |
|
|
699
|
+
| ------------------ | ----------------- | ----------------------------------------------------------- |
|
|
700
|
+
| macOS | launchd | `~/Library/LaunchAgents/com.agentlink.agent.<runtime>.plist` |
|
|
701
|
+
| Linux (systemd) | systemd user unit | `~/.config/systemd/user/agentlink-agent-<runtime>.service` |
|
|
702
|
+
| Linux (无 systemd) | — | 只能手动 `agentlink bridge -r <runtime>` |
|
|
703
|
+
| Windows | Task Scheduler | `Agentlink\\Agent-<runtime>` |
|
|
704
|
+
|
|
705
|
+
常用命令:
|
|
706
|
+
|
|
707
|
+
```bash
|
|
708
|
+
# 配对后自动装后台服务
|
|
709
|
+
agentlink pair 1234 -r claude
|
|
710
|
+
agentlink pair 1234 -r codex
|
|
711
|
+
|
|
712
|
+
# 查看后台状态
|
|
713
|
+
agentlink service status -r claude
|
|
714
|
+
agentlink service status -r codex
|
|
715
|
+
|
|
716
|
+
# 重装后台服务
|
|
717
|
+
agentlink service restart -r claude
|
|
718
|
+
agentlink service restart -r codex
|
|
719
|
+
|
|
720
|
+
# 只停掉后台服务,但保留本地配对状态
|
|
721
|
+
agentlink service stop -r claude
|
|
722
|
+
agentlink service stop -r codex
|
|
723
|
+
|
|
724
|
+
# `service uninstall` 对 claude/codex 与 `service stop` 等价
|
|
725
|
+
agentlink service uninstall -r claude
|
|
726
|
+
agentlink service uninstall -r codex
|
|
727
|
+
|
|
728
|
+
# 完整卸载:停服务并清掉本地配对状态(~/.agentlink/ext-<runtime>-last.json)
|
|
729
|
+
agentlink uninstall -r claude
|
|
730
|
+
agentlink uninstall -r codex
|
|
731
|
+
|
|
732
|
+
# 前台调试运行;停止方式就是 Ctrl+C
|
|
733
|
+
agentlink bridge -r claude
|
|
734
|
+
agentlink bridge -r codex
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
说明:
|
|
738
|
+
|
|
739
|
+
- `agentlink pair <code> -r claude|codex` 成功后,会自动执行后台服务安装。
|
|
740
|
+
- 对 `claude/codex` 来说,`agentlink service stop -r <runtime>` 和 `agentlink service uninstall -r <runtime>` 在当前实现里效果相同,都会卸载对应 service,但不会删除本地配对状态。
|
|
741
|
+
- 如果你想彻底解绑本机上的 Claude / Codex,请使用 `agentlink uninstall -r <runtime>`,它会在停服务之外再清掉本地状态文件。
|
|
742
|
+
|
|
743
|
+
---
|
|
744
|
+
|
|
745
|
+
## 9. 状态与持久化
|
|
746
|
+
|
|
747
|
+
| 路径 | 内容 |
|
|
748
|
+
| -------------------------------------------- | ------------------------------------------------------------- |
|
|
749
|
+
| `~/.openclaw/openclaw.json` | OpenClaw gateway 配置(模型、端口、profile、relay 配置片段) |
|
|
750
|
+
| `~/.agentlink/config.json` | CLI 级别状态(`runtimeKind`、4 套 relay 凭证) |
|
|
751
|
+
| `~/.agentlink/hermes/sessions/<sid>.json` | Hermes JS bridge 的会话历史持久化 |
|
|
752
|
+
| `~/.agentlink/bridge-launch.sh` | OpenClaw 桥接的 launchd/systemd 启动脚本 |
|
|
753
|
+
| `~/.agentlink/bridge-launch-hermes.sh` | Hermes 桥接的 launchd/systemd 启动脚本 |
|
|
754
|
+
| `~/.agentlink/logs/` | 桥接 stdout / stderr 日志 |
|
|
755
|
+
| `~/.openclaw/agentlink/runtime/bridge-*.lock` | 桥接文件锁(按 `relayUrl + gatewayId + gatewayBase` 取 hash) |
|
|
756
|
+
|
|
757
|
+
`~/.agentlink/config.json` 里两套凭证并存:
|
|
758
|
+
|
|
759
|
+
- **OpenClaw**:`relayGatewayId` / `relayClientToken` / `relayGatewayToken`
|
|
760
|
+
- **Hermes**:`hermesRelayGatewayId` / `hermesRelayClientToken` / `hermesRelayGatewayToken`
|
|
761
|
+
|
|
762
|
+
`runtimeKind` 字段记录最近一次配对的 runtime。敏感字段(`gateway.auth.token` / `channels.*.appSecret`)在 debug 输出里会被脱敏成 `***`。
|
|
763
|
+
|
|
764
|
+
---
|
|
765
|
+
|
|
766
|
+
## 10. 环境变量
|
|
767
|
+
|
|
768
|
+
| 变量 | 作用 |
|
|
769
|
+
| ----------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
770
|
+
| `OPENCLAW_HOME` | 覆盖 OpenClaw 主目录(默认 `~/.openclaw`) |
|
|
771
|
+
| `AGENTLINK_RELAY_URL` | 覆盖 relay 基址(默认 `https://go-relay-test.xyagent.com`) |
|
|
772
|
+
| `AGENTLINK_RELAY_TOKEN` | Bearer token(配对/绑定端点用) |
|
|
773
|
+
| `OPENCLAW_AGENTLINK_GATEWAY_BASE_URL` | 覆盖本地 gateway 基址 |
|
|
774
|
+
| `OPENCLAW_GATEWAY_PORT` / `OPENCLAW_GATEWAY_HOST` | 显式指定 host/port |
|
|
775
|
+
| `AGENTLINK_RELAY_GATEWAY_ID` / `_CLIENT_TOKEN` / `_GATEWAY_TOKEN` | 覆盖 openclaw 的 relay 凭证 |
|
|
776
|
+
| `AGENTLINK_HERMES_RELAY_GATEWAY_ID` / `_CLIENT_TOKEN` / `_GATEWAY_TOKEN` | 覆盖 hermes 的 relay 凭证 |
|
|
777
|
+
| **`HERMES_BRIDGE_API_BASE_URL`** | **Hermes JS bridge HTTP 后端:OpenAI-compatible base URL** |
|
|
778
|
+
| **`HERMES_BRIDGE_API_KEY`** | **Hermes HTTP 后端 Bearer token** |
|
|
779
|
+
| **`HERMES_BRIDGE_MODEL`** | **Hermes 默认模型名(`gpt-4o-mini` 等)** |
|
|
780
|
+
| **`HERMES_BRIDGE_COMMAND`** | **Hermes 子进程后端:外部 binary 路径(NDJSON 协议)** |
|
|
781
|
+
|
|
782
|
+
---
|
|
783
|
+
|
|
784
|
+
## 11. Hermes JS bridge 多 provider 与流式
|
|
785
|
+
|
|
786
|
+
Hermes JS bridge 通过 OpenAI-compatible HTTP 协议跑,任何兼容
|
|
787
|
+
`POST /v1/chat/completions { stream: true }` 的服务都能直接接:OpenAI、Azure
|
|
788
|
+
OpenAI、DeepSeek、自建 vLLM、LiteLLM、Ollama 兼容层。要切 provider 就改
|
|
789
|
+
`HERMES_BRIDGE_API_BASE_URL`。
|
|
790
|
+
|
|
791
|
+
流式默认按 OpenAI SSE 帧解析(`data:` 前缀 + `[DONE]` 终止符),逐 chunk 透传
|
|
792
|
+
为 unified `content_block.delta`,最终一帧合并为 `content_block.completed`。
|
|
793
|
+
|
|
794
|
+
不需要外部多 provider 配置文件 — 后端切换通过 env 完成:
|
|
795
|
+
|
|
796
|
+
```bash
|
|
797
|
+
# OpenAI 官方
|
|
798
|
+
export HERMES_BRIDGE_API_BASE_URL=https://api.openai.com/v1
|
|
799
|
+
export HERMES_BRIDGE_MODEL=gpt-4o-mini
|
|
800
|
+
|
|
801
|
+
# DeepSeek
|
|
802
|
+
export HERMES_BRIDGE_API_BASE_URL=https://api.deepseek.com/v1
|
|
803
|
+
export HERMES_BRIDGE_MODEL=deepseek-chat
|
|
804
|
+
|
|
805
|
+
# 本地 vLLM / Ollama 兼容层
|
|
806
|
+
export HERMES_BRIDGE_API_BASE_URL=http://127.0.0.1:8000/v1
|
|
807
|
+
export HERMES_BRIDGE_MODEL=qwen2.5
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
需要走非 OpenAI 协议(如 Anthropic 原生 `/messages`)?用 subprocess 后端:写
|
|
811
|
+
一个外部 binary 实现 `stdin JSON → stdout NDJSON`,然后
|
|
812
|
+
`export HERMES_BRIDGE_COMMAND=/path/to/my-binary`。bridge 会 spawn 它跑每个
|
|
813
|
+
turn。
|
|
814
|
+
|
|
815
|
+
模型选择用 `<provider>/<model-id>`(例 `minimax/MiniMax-M2.7`)。桥接先匹配配置的 provider,没匹配到才回退到默认 Hermes API server。
|
|
816
|
+
|
|
817
|
+
---
|
|
818
|
+
|
|
819
|
+
## 12. 已知陷阱
|
|
820
|
+
|
|
821
|
+
1. **relay_client_token 可能在多设备共享** — 删除绑定前必须走 `canUseClientTokenDeleteFallback` 检查,避免误删别人的 binding
|
|
822
|
+
2. **Session key 格式前后不一致** — App 侧装饰(`agent:xxx:relay-gw:GW-A::...`),relay 事件是裸 key。Flutter 用 `_sessionKeyMatchesForPreview` 宽松匹配
|
|
823
|
+
3. **Windows 的 PowerShell 编码** — 服务注册时通过 Base64 传命令行,避免 CJK 路径在 cmd.exe 下被 mojibake
|
|
824
|
+
4. **Hermes / OpenClaw 凭证是两套** — `AppRuntimeKind` 决定写哪一组,不能互相借用;`agentlink reset` 不传 `--runtime` 默认只重置 openclaw
|
|
825
|
+
5. **Hermes cron 任务与配对无关** — `~/.hermes/cron/jobs.json` 是本地文件。一次性任务(`30m` / `2h` / 具体时间戳)执行后会**自动删除**,重新配对看不到是正常现象
|
|
826
|
+
|
|
827
|
+
---
|
|
828
|
+
|
|
829
|
+
## 13. 测试
|
|
830
|
+
|
|
831
|
+
需要 Node.js ≥ 22。
|
|
832
|
+
|
|
833
|
+
```bash
|
|
834
|
+
npm test
|
|
835
|
+
node --test test/cli.test.mjs
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
73 个测试(13 个测试文件),覆盖:
|
|
839
|
+
|
|
840
|
+
- CLI basics / 平台路径 / OpenClaw home 解析 / XML & systemd 转义 / PID 检测 / 文件锁 / PowerShell Base64 / 服务状态 / Node 版本保护
|
|
841
|
+
- `pairCodeClient` —— `/v1/pair-codes/<code>/consume` 协议契约 + legacy 端点回退
|
|
842
|
+
- `relayWorker` —— long-poll 拉取 + publishEvent + 心跳 + 退避重试
|
|
843
|
+
- `claudeParser` / `codexEventMapper` —— native 事件解析(CLI 端只解析不翻译)
|
|
844
|
+
- `approvalGateway` / `elicitationHandler` —— HITL 工具审批
|
|
845
|
+
- `mcpStdioClient` / `mcpStdioBridge` / `agentlinkTools` —— Codex 反向 MCP 工具注入
|
|
846
|
+
- `usageReporter` —— token 用量上报
|
|
847
|
+
|
|
848
|
+
> 之前 161 测试中有近一半是 `unified_relay_shim` 的 native → unified envelope 翻译契约测试。重构把翻译层挪到服务端 adapter 后,CLI 端只剩 73 测试覆盖 long-poll + pair-code consume + native 事件解析这些核心路径。
|
|
849
|
+
|
|
850
|
+
CI:
|
|
851
|
+
|
|
852
|
+
- GitLab CI (`.gitlab-ci.yml`):Node 22 on Alpine
|
|
853
|
+
- GitHub Actions (`.github/workflows/test.yml`):Ubuntu / macOS / Windows × Node 22
|
|
854
|
+
|
|
855
|
+
| 平台 | 状态 |
|
|
856
|
+
| ----------------------------------- | ---------------------------- |
|
|
857
|
+
| macOS (launchd) | 完全支持 |
|
|
858
|
+
| Linux + systemd | 完全支持 |
|
|
859
|
+
| Linux 无 systemd(Alpine / OpenRC) | 只支持手动 `agentlink bridge` |
|
|
860
|
+
| Windows (Task Scheduler) | 支持,CI 覆盖 |
|