@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,39 @@
|
|
|
1
|
+
// 巴布(PicoClaw)运行时常量。
|
|
2
|
+
//
|
|
3
|
+
// 部署假设:matelink-cli 与 picoclaw daemon 烧录在同一开发板,
|
|
4
|
+
// cli 默认连本地回环 picoclaw WebSocket。token 烧录时固化,cli 端写死同值。
|
|
5
|
+
//
|
|
6
|
+
// 如需改 token,**两处**(开发板 picoclaw config + 此文件)必须同步,否则连接失败。
|
|
7
|
+
|
|
8
|
+
import process from "node:process";
|
|
9
|
+
|
|
10
|
+
// PicoClaw daemon 的 WebSocket 端点(Pico Protocol)。
|
|
11
|
+
// 默认 127.0.0.1:18790/pico/ws,可通过 env 覆盖(开发/调试用)。
|
|
12
|
+
export const PICOCLAW_WS_URL =
|
|
13
|
+
process.env.PICOCLAW_WS_URL?.trim() || "ws://127.0.0.1:18790/pico/ws";
|
|
14
|
+
|
|
15
|
+
// PicoClaw Bearer token —— 与开发板 picoclaw config 里 [pico].token 一致。
|
|
16
|
+
// 生产烧录时双方都写死成下面这个固定值;切换值时必须双侧同步。
|
|
17
|
+
export const PICOCLAW_TOKEN =
|
|
18
|
+
process.env.PICOCLAW_TOKEN?.trim() || "bubu-local-token";
|
|
19
|
+
|
|
20
|
+
// 巴布配对二维码 PNG 输出路径 —— 屏幕显示模块从这个路径加载图片。
|
|
21
|
+
// 默认写到 /tmp/bubu/pair-qr.png,可通过 env 覆盖。
|
|
22
|
+
export const QR_PNG_OUTPUT_PATH =
|
|
23
|
+
process.env.BUBU_QR_PNG_PATH?.trim() || "/tmp/bubu/pair-qr.png";
|
|
24
|
+
|
|
25
|
+
// 配对状态轮询间隔(秒)。服务端建议值在 create 响应里返回,这是兜底。
|
|
26
|
+
export const PAIR_STATUS_POLL_INTERVAL_SEC = 2;
|
|
27
|
+
|
|
28
|
+
// 配对状态最长等待时间(秒)。超过后 cli 重新生成 QR(配对码已过期)。
|
|
29
|
+
export const PAIR_STATUS_POLL_MAX_SEC = 300;
|
|
30
|
+
|
|
31
|
+
// 长轮询拉取请求的等待时长(秒)。
|
|
32
|
+
export const LONG_POLL_WAIT_SEC = 30;
|
|
33
|
+
|
|
34
|
+
// PicoClaw WS 重连退避(毫秒)— 指数退避,上限 30s。
|
|
35
|
+
export const WS_RECONNECT_INITIAL_MS = 1000;
|
|
36
|
+
export const WS_RECONNECT_MAX_MS = 30000;
|
|
37
|
+
|
|
38
|
+
// runtime 名 — 必须与服务端 RuntimeKindPicoclaw 字符串一致。
|
|
39
|
+
export const RUNTIME_NAME = "picoclaw";
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* handleRequest.mjs — D-C2
|
|
3
|
+
*
|
|
4
|
+
* Extracted from picoclaw/index.mjs so it can be unit-tested independently.
|
|
5
|
+
*
|
|
6
|
+
* createPicoHandleRequest({ wsHolder, log, dispatchHandlerOptions })
|
|
7
|
+
* → async (request, ctx) => void
|
|
8
|
+
*
|
|
9
|
+
* Routing:
|
|
10
|
+
* 1. If request.__kind == "agent.run.dispatch" → unifiedDispatchHandler (returns true) → done
|
|
11
|
+
* 2. Otherwise → original picoclaw ws path (extractUserText + wsHolder.send)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { createUnifiedDispatchHandler } from "../../core/unifiedDispatchHandler.mjs";
|
|
15
|
+
import { buildMessageSend } from "./wsClient.mjs";
|
|
16
|
+
import { createTurnState, translatePicoMessage, forceFinalize } from "./translator.mjs";
|
|
17
|
+
import { relayObjectToBlock } from "../_shared/relayObjectToBlock.mjs";
|
|
18
|
+
import { openclawChatAbort } from "../../core/openclawGatewayClient.mjs";
|
|
19
|
+
|
|
20
|
+
// ── multimodal helpers (exported for unit tests) ──────────────────────────────
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 从 blocks 中筛出 image blocks 和 PDF attachment blocks。
|
|
24
|
+
*
|
|
25
|
+
* Phase 5 (multimodal-attachment-llm-dispatch): この関数は後方互換のために残す。
|
|
26
|
+
* WS dispatch path では relayObjectToBlock を使う(下記 createPicoHandleRequest 内参照)。
|
|
27
|
+
*
|
|
28
|
+
* @param {any[]} blocks
|
|
29
|
+
* @returns {{ imageBlocks: any[], pdfBlocks: any[] }}
|
|
30
|
+
*/
|
|
31
|
+
export function extractPicoBlocks(blocks) {
|
|
32
|
+
if (!Array.isArray(blocks)) return { imageBlocks: [], pdfBlocks: [] };
|
|
33
|
+
const imageBlocks = blocks.filter(
|
|
34
|
+
(b) => b?.type === "image" && b?.source?.kind === "url" && b?.source?.url
|
|
35
|
+
);
|
|
36
|
+
const pdfBlocks = blocks.filter(
|
|
37
|
+
(b) =>
|
|
38
|
+
b?.type === "attachment" &&
|
|
39
|
+
b?.mime === "application/pdf" &&
|
|
40
|
+
b?.source?.kind === "url" &&
|
|
41
|
+
b?.source?.url
|
|
42
|
+
);
|
|
43
|
+
return { imageBlocks, pdfBlocks };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 构造 media.create 帧(用于发送图片到 picoclaw daemon)。
|
|
48
|
+
*
|
|
49
|
+
* @param {string} sessionId
|
|
50
|
+
* @param {{ source: { url: string, media_type?: string } }} imageBlock
|
|
51
|
+
*/
|
|
52
|
+
export function buildMediaCreate(sessionId, imageBlock) {
|
|
53
|
+
return {
|
|
54
|
+
type: "media.create",
|
|
55
|
+
id: randomPicoID(),
|
|
56
|
+
session_id: sessionId,
|
|
57
|
+
timestamp: Date.now(),
|
|
58
|
+
payload: {
|
|
59
|
+
url: imageBlock.source.url,
|
|
60
|
+
media_type: imageBlock.source?.media_type || "image/jpeg",
|
|
61
|
+
kind: "image",
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 构造 message.send 的 content 文本:原始 input + PDF inline 行。
|
|
68
|
+
*
|
|
69
|
+
* @param {string} input 用户输入文本
|
|
70
|
+
* @param {any[]} pdfBlocks PDF attachment blocks
|
|
71
|
+
* @returns {string}
|
|
72
|
+
*/
|
|
73
|
+
export function buildPicoMessageContent(input, pdfBlocks) {
|
|
74
|
+
if (!pdfBlocks || pdfBlocks.length === 0) return input;
|
|
75
|
+
const pdfLines = pdfBlocks
|
|
76
|
+
.map((b) => `[file: ${b.name}] ${b.source.url}`)
|
|
77
|
+
.join("\n");
|
|
78
|
+
if (!input) return pdfLines;
|
|
79
|
+
return `${input}\n${pdfLines}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function randomPicoID() {
|
|
83
|
+
return Math.random().toString(36).slice(2, 10) + Date.now().toString(36);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 延迟读取以允许测试环境通过 process.env 覆盖
|
|
87
|
+
function getTurnTimeoutMs() {
|
|
88
|
+
return Number(process.env.PICOCLAW_TURN_TIMEOUT_MS || 120000);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {{
|
|
93
|
+
* wsHolder: { isOpen(): boolean, connectOnce(): Promise<void>, send(msg): void, onMessage(fn): () => void },
|
|
94
|
+
* log: { info, warn, error },
|
|
95
|
+
* activeTurnRef: { current: any }, // shared mutable ref so ws messages can resolve the turn
|
|
96
|
+
* publishEventFn: (event: any) => Promise<void>,
|
|
97
|
+
* dispatchHandlerOptions: {
|
|
98
|
+
* relayUrl: string,
|
|
99
|
+
* bridgeToken: string,
|
|
100
|
+
* producerFactory?: Function,
|
|
101
|
+
* openclawInvoke?: Function,
|
|
102
|
+
* },
|
|
103
|
+
* }} opts
|
|
104
|
+
*
|
|
105
|
+
* Note: activeTurnRef and publishEventFn are only required when wsHolder is actually used
|
|
106
|
+
* (i.e. non-dispatch requests). Tests for dispatch path can omit them.
|
|
107
|
+
*/
|
|
108
|
+
export function createPicoHandleRequest({
|
|
109
|
+
wsHolder,
|
|
110
|
+
log,
|
|
111
|
+
activeTurnRef,
|
|
112
|
+
dispatchHandlerOptions,
|
|
113
|
+
}) {
|
|
114
|
+
// 允许测试注入 openclawChatAbort 实现(避免真实 WS 依赖)
|
|
115
|
+
const _chatAbortFn = dispatchHandlerOptions?._openclawChatAbortFn ?? openclawChatAbort;
|
|
116
|
+
|
|
117
|
+
const unifiedHandler = createUnifiedDispatchHandler({
|
|
118
|
+
...dispatchHandlerOptions,
|
|
119
|
+
log,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return async function handleRequest(request, ctx) {
|
|
123
|
+
// Step 0: RPC 分支 — sessions.abort / chat.abort(openclaw gateway WS 直连)
|
|
124
|
+
if (request?.request?.__relayKind === "rpc") {
|
|
125
|
+
const method = request.request.method;
|
|
126
|
+
const params = request.request.params ?? {};
|
|
127
|
+
let result;
|
|
128
|
+
try {
|
|
129
|
+
if (method === "sessions.abort" || method === "chat.abort") {
|
|
130
|
+
const sessionKey = params.key ?? params.sessionKey ?? "";
|
|
131
|
+
result = await _chatAbortFn({ sessionKey, log });
|
|
132
|
+
} else {
|
|
133
|
+
// 其余 RPC 方法(workspaces.scan 等)picoclaw 不处理,返回 unknown
|
|
134
|
+
result = { ok: false, error: `unknown rpc method: ${method}` };
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
137
|
+
result = { ok: false, error: err?.message ?? String(err) };
|
|
138
|
+
}
|
|
139
|
+
const bodyJson = JSON.stringify(result);
|
|
140
|
+
await ctx.publishEvent({
|
|
141
|
+
event: "response",
|
|
142
|
+
statusCode: 200,
|
|
143
|
+
contentType: "application/json; charset=utf-8",
|
|
144
|
+
body: bodyJson,
|
|
145
|
+
});
|
|
146
|
+
await ctx.publishEvent({ event: "end" });
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Step 1: Try unified dispatch handler first.
|
|
151
|
+
const handled = await unifiedHandler(request, ctx);
|
|
152
|
+
if (handled) return;
|
|
153
|
+
|
|
154
|
+
// Step 2: Original picoclaw ws path.
|
|
155
|
+
// Phase 5 (multimodal-attachment-llm-dispatch): relay_object blocks を
|
|
156
|
+
// relayObjectToBlock を通して処理する(runtimeHint="picoclaw", modelCaps=null)。
|
|
157
|
+
// image → url_ref → buildMediaCreate(URL をそのまま picoclaw daemon に送る)
|
|
158
|
+
// document/text/binary → input_text → メッセージに text として追加
|
|
159
|
+
const userText = extractUserText(request);
|
|
160
|
+
const blocks = request?.request?.blocks ?? [];
|
|
161
|
+
|
|
162
|
+
// relay_object blocks の処理(attachment_kind ベース)
|
|
163
|
+
const urlRefBlocks = []; // image → url_ref blocks
|
|
164
|
+
const textInlineLines = []; // non-image → input_text の text
|
|
165
|
+
|
|
166
|
+
for (const block of blocks) {
|
|
167
|
+
if (!block?.source?.kind || block.source.kind !== "url" || !block.source.url) continue;
|
|
168
|
+
// image か attachment のみ relay_object
|
|
169
|
+
if (block.type !== "image" && block.type !== "attachment") continue;
|
|
170
|
+
|
|
171
|
+
const result = await relayObjectToBlock(block, {
|
|
172
|
+
runtimeHint: "picoclaw",
|
|
173
|
+
modelCaps: null, // picoclaw: caps check をスキップ
|
|
174
|
+
fetchAndBase64Encode: async () => { throw new Error("picoclaw does not fetch bytes"); },
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
if (result.error) {
|
|
178
|
+
// エラーは text inline に追加
|
|
179
|
+
textInlineLines.push(`[attachment] (error: ${result.error.message})`);
|
|
180
|
+
} else if (result.type === "url_ref") {
|
|
181
|
+
// image → url_ref → buildMediaCreate 用に保存
|
|
182
|
+
urlRefBlocks.push({ url: result.url, media_type: result.media_type });
|
|
183
|
+
} else if (result.type === "input_text") {
|
|
184
|
+
// document / text / binary → inline text
|
|
185
|
+
textInlineLines.push(result.text);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const hasMedia = urlRefBlocks.length > 0;
|
|
190
|
+
// buildPicoMessageContent 互換:textInlineLines を userText に追加
|
|
191
|
+
let messageContent = userText;
|
|
192
|
+
if (textInlineLines.length > 0) {
|
|
193
|
+
messageContent = userText
|
|
194
|
+
? `${userText}\n${textInlineLines.join("\n")}`
|
|
195
|
+
: textInlineLines.join("\n");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 纯图片 + 无 PDF + 无文字:只发 media.create,不发 message.send
|
|
199
|
+
const shouldSendMessage = messageContent.trim().length > 0;
|
|
200
|
+
const shouldSendAnyMedia = hasMedia;
|
|
201
|
+
|
|
202
|
+
if (!shouldSendMessage && !shouldSendAnyMedia) {
|
|
203
|
+
log.warn("turn.skip", "no user text or blocks", { requestId: ctx.requestId });
|
|
204
|
+
await ctx.publishEvent({ event: "error", error: "empty user input" });
|
|
205
|
+
await ctx.publishEvent({ event: "end" });
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (!wsHolder.isOpen()) {
|
|
210
|
+
try { await wsHolder.connectOnce(); }
|
|
211
|
+
catch (err) {
|
|
212
|
+
await ctx.publishEvent({ event: "error", error: `picoclaw connect failed: ${err?.message || err}` });
|
|
213
|
+
await ctx.publishEvent({ event: "end" });
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const translatorState = createTurnState();
|
|
219
|
+
let resolveTurn;
|
|
220
|
+
const turnDone = new Promise((r) => { resolveTurn = r; });
|
|
221
|
+
|
|
222
|
+
if (activeTurnRef) {
|
|
223
|
+
activeTurnRef.current = { ctx, translatorState, resolve: resolveTurn };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const sessionId = `bubu-${ctx.requestId}`;
|
|
227
|
+
try {
|
|
228
|
+
// 先发所有 media.create(图片 url_ref),再发 message.send(如有文本或非 image)
|
|
229
|
+
for (const urlRef of urlRefBlocks) {
|
|
230
|
+
// url_ref → buildMediaCreate 互換オブジェクト
|
|
231
|
+
wsHolder.send(buildMediaCreate(sessionId, {
|
|
232
|
+
source: { url: urlRef.url, media_type: urlRef.media_type },
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
235
|
+
if (shouldSendMessage) {
|
|
236
|
+
wsHolder.send(buildMessageSend({
|
|
237
|
+
sessionId,
|
|
238
|
+
content: messageContent,
|
|
239
|
+
requestId: ctx.requestId,
|
|
240
|
+
}));
|
|
241
|
+
}
|
|
242
|
+
} catch (err) {
|
|
243
|
+
if (activeTurnRef) activeTurnRef.current = null;
|
|
244
|
+
await ctx.publishEvent({ event: "error", error: `picoclaw send failed: ${err?.message || err}` });
|
|
245
|
+
await ctx.publishEvent({ event: "end" });
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const turnTimeoutMs = getTurnTimeoutMs();
|
|
250
|
+
const timeoutP = new Promise((r) => setTimeout(() => r("__timeout__"), turnTimeoutMs));
|
|
251
|
+
const winner = await Promise.race([turnDone.then(() => "__done__"), timeoutP]);
|
|
252
|
+
if (winner === "__timeout__") {
|
|
253
|
+
log.warn("picoclaw.turn.timeout", "turn timed out", { requestId: ctx.requestId, ms: turnTimeoutMs });
|
|
254
|
+
const events = forceFinalize(translatorState);
|
|
255
|
+
for (const e of events) {
|
|
256
|
+
if (e) await ctx.publishEvent(e);
|
|
257
|
+
}
|
|
258
|
+
if (activeTurnRef) activeTurnRef.current = null;
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
264
|
+
|
|
265
|
+
function extractUserText(request) {
|
|
266
|
+
const input = request?.request?.input;
|
|
267
|
+
if (typeof input === "string") return input.trim();
|
|
268
|
+
if (Array.isArray(input)) {
|
|
269
|
+
const parts = [];
|
|
270
|
+
for (const item of input) {
|
|
271
|
+
if (typeof item === "string") parts.push(item);
|
|
272
|
+
else if (item && typeof item === "object") {
|
|
273
|
+
if (typeof item.text === "string") parts.push(item.text);
|
|
274
|
+
else if (Array.isArray(item.content)) {
|
|
275
|
+
for (const c of item.content) {
|
|
276
|
+
if (c && typeof c === "object" && typeof c.text === "string") parts.push(c.text);
|
|
277
|
+
}
|
|
278
|
+
} else if (typeof item.content === "string") parts.push(item.content);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return parts.join("\n").trim();
|
|
282
|
+
}
|
|
283
|
+
if (input && typeof input === "object") {
|
|
284
|
+
if (typeof input.text === "string") return input.text.trim();
|
|
285
|
+
if (typeof input.content === "string") return input.content.trim();
|
|
286
|
+
}
|
|
287
|
+
if (typeof request?.clientPreviewText === "string") return request.clientPreviewText.trim();
|
|
288
|
+
return "";
|
|
289
|
+
}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
// 巴布(PicoClaw)桥接入口 — daemon 主循环。
|
|
2
|
+
//
|
|
3
|
+
// 与 hermes/claude/codex 的差异:
|
|
4
|
+
// - 配对流程不是 `agentlink pair <code>` 由用户在 cli 输入,而是 daemon 启动后
|
|
5
|
+
// 自动调 server `/v1/pair-codes/picoclaw/create` 拿 QR PNG → 写到本地约定路径
|
|
6
|
+
// 由屏幕显示模块独立读取 → App 扫码 → server consume → cli 通过 fetch_token
|
|
7
|
+
// poll status 拿到 bridge_token。全程零命令行交互。
|
|
8
|
+
//
|
|
9
|
+
// - 与本地的 PicoClaw daemon (默认 ws://127.0.0.1:18790/pico/ws) 建立 WebSocket
|
|
10
|
+
// 连接,把用户消息翻译为 message.send 发出去;接收 message.create / .update
|
|
11
|
+
// 翻译成 OpenClaw 风格 native event 透传给服务端 long-poll 通道。
|
|
12
|
+
//
|
|
13
|
+
// - daemon 主循环:
|
|
14
|
+
// 1. readState() 拿 bridge_token
|
|
15
|
+
// 2. 没有 → pair flow → writeState
|
|
16
|
+
// 3. 有 → 启 worker(long-poll + WS),失败/被撤销时 clearState 回到 1
|
|
17
|
+
//
|
|
18
|
+
// 使用入口: `agentlink-agent picoclaw`
|
|
19
|
+
|
|
20
|
+
import process from "node:process";
|
|
21
|
+
|
|
22
|
+
import { createLogger } from "../../../src-shared/logger.mjs";
|
|
23
|
+
import { newCid } from "../../../src-shared/correlation.mjs";
|
|
24
|
+
import { createSessionSlot, SESSION_STATES } from "../../core/sessionSlot.mjs";
|
|
25
|
+
import { createRelayWorker } from "../../core/relayWorker.mjs";
|
|
26
|
+
import { installAutoTunnel } from "../../core/autoTunnelWiring.mjs";
|
|
27
|
+
import { createUsageReporter } from "../../core/usageReporter.mjs";
|
|
28
|
+
import { resolveRelayUrl } from "../../core/pairCodeClient.mjs";
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
PAIR_STATUS_POLL_INTERVAL_SEC,
|
|
32
|
+
PAIR_STATUS_POLL_MAX_SEC,
|
|
33
|
+
RUNTIME_NAME,
|
|
34
|
+
WS_RECONNECT_INITIAL_MS,
|
|
35
|
+
WS_RECONNECT_MAX_MS,
|
|
36
|
+
} from "./constants.mjs";
|
|
37
|
+
import { readState, writeState, clearState } from "./state.mjs";
|
|
38
|
+
import {
|
|
39
|
+
createPairCode,
|
|
40
|
+
pollPairStatus,
|
|
41
|
+
writeQRImage,
|
|
42
|
+
clearQRImage,
|
|
43
|
+
writeDevPairInfo,
|
|
44
|
+
clearDevPairInfo,
|
|
45
|
+
} from "./pairFlow.mjs";
|
|
46
|
+
import { connect as wsConnect } from "./wsClient.mjs";
|
|
47
|
+
import { translatePicoMessage } from "./translator.mjs";
|
|
48
|
+
import { createPicoHandleRequest } from "./handleRequest.mjs";
|
|
49
|
+
import { createPicoTodoTranslator } from "./todoTranslator.mjs";
|
|
50
|
+
|
|
51
|
+
export async function runPicoclawBridge({ options, positional, log }) {
|
|
52
|
+
const relayBase = resolveRelayUrl(options.relay);
|
|
53
|
+
const log0 = log || createLogger({ comp: "bridge", cid: newCid() }).child({ rt: RUNTIME_NAME });
|
|
54
|
+
log0.info("bridge.preflight.pass", "picoclaw daemon entering main loop", { relay: relayBase });
|
|
55
|
+
|
|
56
|
+
let shuttingDown = false;
|
|
57
|
+
process.once("SIGINT", () => { shuttingDown = true; });
|
|
58
|
+
process.once("SIGTERM", () => { shuttingDown = true; });
|
|
59
|
+
|
|
60
|
+
// daemon 主循环 — 每次循环代表一次"配对 + 长轮询"周期。
|
|
61
|
+
// 解绑或鉴权失效会导致内层 worker 退出并清 state,主循环回到 0 重新生成 QR。
|
|
62
|
+
while (!shuttingDown) {
|
|
63
|
+
let st = readState();
|
|
64
|
+
if (!st) {
|
|
65
|
+
// 没绑定 → 走 pair flow
|
|
66
|
+
try {
|
|
67
|
+
st = await runPairFlow({ relayBase, options, log: log0 });
|
|
68
|
+
} catch (err) {
|
|
69
|
+
log0.warn("picoclaw.pair.failed", "pair flow failed; retry in 5s", { err: String(err?.message || err) });
|
|
70
|
+
await sleep(5000);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
writeState(st);
|
|
74
|
+
log0.info("picoclaw.pair.persisted", "bridge_token saved, entering worker", { gw_id: st.gw_id });
|
|
75
|
+
}
|
|
76
|
+
// 启 worker — 内部异常或 token 撤销返回 reason
|
|
77
|
+
let exitReason;
|
|
78
|
+
try {
|
|
79
|
+
exitReason = await runWorkerWithBridge({ state: st, log: log0 });
|
|
80
|
+
} catch (err) {
|
|
81
|
+
log0.error("picoclaw.worker.fatal", "worker fatal", { err: String(err?.message || err) });
|
|
82
|
+
exitReason = "fatal";
|
|
83
|
+
}
|
|
84
|
+
log0.info("picoclaw.worker.exited", "worker exited", { reason: exitReason });
|
|
85
|
+
if (exitReason === "revoked" || exitReason === "auth-failed") {
|
|
86
|
+
clearState();
|
|
87
|
+
log0.info("picoclaw.state.cleared", "bridge_token revoked; back to pair loop");
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (shuttingDown) break;
|
|
91
|
+
// 网络抖动等 — 不清 state,直接重启 worker
|
|
92
|
+
await sleep(2000);
|
|
93
|
+
}
|
|
94
|
+
log0.info("bridge.shutdown", "picoclaw daemon exiting");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ── pair flow ────────────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
async function runPairFlow({ relayBase, options, log }) {
|
|
100
|
+
// 1. 调 server 创建 pair-code
|
|
101
|
+
const created = await createPairCode({
|
|
102
|
+
relayUrl: relayBase,
|
|
103
|
+
label: options.label,
|
|
104
|
+
deviceId: options.deviceId || process.env.PICOCLAW_DEVICE_ID || "",
|
|
105
|
+
fetchImpl: globalThis.fetch,
|
|
106
|
+
log,
|
|
107
|
+
});
|
|
108
|
+
// 2. 写 QR PNG 到约定路径(屏幕模块读)
|
|
109
|
+
const qrPath = writeQRImage(created.qr_png_base64, options.qrPath);
|
|
110
|
+
log.info("picoclaw.pair.qr.written", "qr image written", { path: qrPath, code: created.code });
|
|
111
|
+
// 2.5 dev 测试钩子:把 code + fetch_token + relay + 完整 deeplink 写到本地,
|
|
112
|
+
// 让 e2e 测试脚本 / iOS 模拟器粘贴测试扮演 App 角色用。
|
|
113
|
+
// (仅当 BUBU_DEV_DUMP_PAIR_INFO=1 时生效;生产环境严禁开启)
|
|
114
|
+
const devPath = writeDevPairInfo({
|
|
115
|
+
code: created.code,
|
|
116
|
+
fetch_token: created.fetch_token,
|
|
117
|
+
relay: relayBase,
|
|
118
|
+
label: options.label,
|
|
119
|
+
expires_at: created.expires_at,
|
|
120
|
+
qr_payload: created.qr_payload, // 完整 deeplink,粘贴到 App 输入框直接绑定
|
|
121
|
+
});
|
|
122
|
+
if (devPath) {
|
|
123
|
+
log.info("picoclaw.pair.devinfo.written", "dev pair-info written for test", { path: devPath });
|
|
124
|
+
}
|
|
125
|
+
// 3. poll status
|
|
126
|
+
try {
|
|
127
|
+
const result = await pollPairStatus({
|
|
128
|
+
relayUrl: relayBase,
|
|
129
|
+
code: created.code,
|
|
130
|
+
fetchToken: created.fetch_token,
|
|
131
|
+
intervalSec: created.poll_interval_seconds || PAIR_STATUS_POLL_INTERVAL_SEC,
|
|
132
|
+
maxSec: PAIR_STATUS_POLL_MAX_SEC,
|
|
133
|
+
log,
|
|
134
|
+
});
|
|
135
|
+
// 4. 配对成功 — 清 QR 图(屏幕切换为已绑定画面;具体显示模块自己处理)
|
|
136
|
+
clearQRImage(options.qrPath);
|
|
137
|
+
clearDevPairInfo();
|
|
138
|
+
return {
|
|
139
|
+
gw_id: result.gw_id,
|
|
140
|
+
bridge_token: result.bridge_token,
|
|
141
|
+
relay_url: relayBase,
|
|
142
|
+
client_user_id: result.client_user_id,
|
|
143
|
+
label: result.label,
|
|
144
|
+
};
|
|
145
|
+
} catch (err) {
|
|
146
|
+
clearQRImage(options.qrPath);
|
|
147
|
+
clearDevPairInfo();
|
|
148
|
+
throw err;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ── worker(long-poll + WS) ─────────────────────────────────────
|
|
153
|
+
|
|
154
|
+
async function runWorkerWithBridge({ state, log }) {
|
|
155
|
+
const sessLog = log.child({ gw: state.gw_id });
|
|
156
|
+
const worker = createRelayWorker({
|
|
157
|
+
relayUrl: state.relay_url,
|
|
158
|
+
gwId: state.gw_id,
|
|
159
|
+
bridgeToken: state.bridge_token,
|
|
160
|
+
runtime: RUNTIME_NAME,
|
|
161
|
+
log: sessLog,
|
|
162
|
+
});
|
|
163
|
+
installAutoTunnel({ relayUrl: state.relay_url, log: sessLog });
|
|
164
|
+
|
|
165
|
+
// ── PicoClaw WS — 自带重连 ──
|
|
166
|
+
const wsHolder = createReconnectingWS({ log: sessLog });
|
|
167
|
+
|
|
168
|
+
// 当前 in-flight turn 的 ctx — handleRequest 期间唯一非空
|
|
169
|
+
const activeTurnRef = { current: null };
|
|
170
|
+
const slot = createSessionSlot({ log: sessLog, name: RUNTIME_NAME });
|
|
171
|
+
slot.transition(SESSION_STATES.READY, "picoclaw-no-spawn");
|
|
172
|
+
|
|
173
|
+
const usage = createUsageReporter({
|
|
174
|
+
runtime: RUNTIME_NAME,
|
|
175
|
+
log: sessLog,
|
|
176
|
+
publishEvent: (event) => {
|
|
177
|
+
if (!activeTurnRef.current) return Promise.resolve(false);
|
|
178
|
+
return worker.publishEvent(activeTurnRef.current.ctx.requestId, event);
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// 连 WS
|
|
183
|
+
try {
|
|
184
|
+
await wsHolder.connectOnce();
|
|
185
|
+
} catch (err) {
|
|
186
|
+
sessLog.warn("picoclaw.ws.first_connect.err", "initial ws connect failed", { err: String(err?.message || err) });
|
|
187
|
+
// 不致命 — handleRequest 时会再触发重连。
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// todo translator(ws 路径):拦截 update_plan,阻止透传原始 tool_call 事件
|
|
191
|
+
// ws 路径不走 envelope 系统,所以只做拦截(不发 todo_list block)
|
|
192
|
+
const wsTodoTranslator = createPicoTodoTranslator("ws_path");
|
|
193
|
+
|
|
194
|
+
// 把 ws 收到的消息分发给当前 turn
|
|
195
|
+
wsHolder.onMessage((picoMsg) => {
|
|
196
|
+
const activeTurn = activeTurnRef.current;
|
|
197
|
+
if (!activeTurn) {
|
|
198
|
+
sessLog.warn("picoclaw.ws.msg.no_turn", "received pico message but no active turn", { type: picoMsg?.type });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
// todo translator 拦截:update_plan 消息不透传(阻止 function_call_arguments.delta chunk)
|
|
202
|
+
const intercepted = wsTodoTranslator.intercept(picoMsg);
|
|
203
|
+
if (intercepted.length > 0 && intercepted[0] !== picoMsg) {
|
|
204
|
+
// 拦截到 update_plan,静默丢弃(ws 路径无 envelope 能力)
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const events = translatePicoMessage(picoMsg, activeTurn.translatorState);
|
|
208
|
+
if (!events.length) return;
|
|
209
|
+
void publishEvents(activeTurn, events).catch((err) => {
|
|
210
|
+
sessLog.warn("picoclaw.publish.err", "publish failed", { err: String(err?.message || err) });
|
|
211
|
+
});
|
|
212
|
+
if (activeTurn.translatorState.finalized) {
|
|
213
|
+
const turn = activeTurnRef.current;
|
|
214
|
+
activeTurnRef.current = null;
|
|
215
|
+
turn.resolve(); // wake the awaiting handleRequest
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// ── handleRequest: dispatch 走 unifiedHandler,普通请求走原有 ws 路径 ──
|
|
220
|
+
const handleRequest = createPicoHandleRequest({
|
|
221
|
+
wsHolder,
|
|
222
|
+
log: sessLog,
|
|
223
|
+
activeTurnRef,
|
|
224
|
+
dispatchHandlerOptions: {
|
|
225
|
+
relayUrl: state.relay_url,
|
|
226
|
+
bridgeToken: state.bridge_token,
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Wrap to add usage tracking for non-dispatch turns.
|
|
231
|
+
const handleRequestWithUsage = async (request, ctx) => {
|
|
232
|
+
const turnStartedAt = Date.now();
|
|
233
|
+
await handleRequest(request, ctx);
|
|
234
|
+
usage.addCost({ turns: 1, duration_ms: Date.now() - turnStartedAt });
|
|
235
|
+
usage.schedulePublish("picoclaw.turn_end");
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// 启 long-poll 循环。worker.run() 在 401/410 时会抛带特征的错误。
|
|
239
|
+
let exitReason = "loop-exit";
|
|
240
|
+
try {
|
|
241
|
+
await worker.run(handleRequestWithUsage);
|
|
242
|
+
} catch (err) {
|
|
243
|
+
const msg = String(err?.message || err);
|
|
244
|
+
if (/401|403|410|revoked|unauthorized/i.test(msg)) {
|
|
245
|
+
exitReason = "revoked";
|
|
246
|
+
} else {
|
|
247
|
+
exitReason = "fatal";
|
|
248
|
+
sessLog.error("picoclaw.worker.err", "worker errored", { err: msg });
|
|
249
|
+
}
|
|
250
|
+
} finally {
|
|
251
|
+
try { wsHolder.close("worker-exit"); } catch {}
|
|
252
|
+
try { usage.dispose(); } catch {}
|
|
253
|
+
}
|
|
254
|
+
return exitReason;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ── helpers ──────────────────────────────────────────────────────
|
|
258
|
+
|
|
259
|
+
async function publishEvents({ ctx }, events) {
|
|
260
|
+
for (const e of events) {
|
|
261
|
+
if (!e) continue;
|
|
262
|
+
await ctx.publishEvent(e);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function createReconnectingWS({ log }) {
|
|
267
|
+
let conn = null;
|
|
268
|
+
const messageHandlers = new Set();
|
|
269
|
+
let backoff = WS_RECONNECT_INITIAL_MS;
|
|
270
|
+
|
|
271
|
+
async function connectOnce() {
|
|
272
|
+
if (conn && conn.readyState === 1) return conn;
|
|
273
|
+
conn = await wsConnect({ log });
|
|
274
|
+
backoff = WS_RECONNECT_INITIAL_MS;
|
|
275
|
+
conn.onMessage((m) => {
|
|
276
|
+
for (const h of messageHandlers) {
|
|
277
|
+
try { h(m); } catch (err) {
|
|
278
|
+
log.warn("picoclaw.ws.handler.err", "handler threw", { err: String(err?.message || err) });
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
conn.onClose(() => {
|
|
283
|
+
conn = null;
|
|
284
|
+
// 异步重连,不阻塞 ws.onClose 回调
|
|
285
|
+
setTimeout(() => {
|
|
286
|
+
connectOnce().catch((err) => {
|
|
287
|
+
log.warn("picoclaw.ws.reconnect.err", "reconnect failed", { err: String(err?.message || err) });
|
|
288
|
+
backoff = Math.min(backoff * 2, WS_RECONNECT_MAX_MS);
|
|
289
|
+
});
|
|
290
|
+
}, backoff);
|
|
291
|
+
});
|
|
292
|
+
return conn;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
connectOnce,
|
|
297
|
+
isOpen() { return conn && conn.readyState === 1; },
|
|
298
|
+
send(msg) {
|
|
299
|
+
if (!conn || conn.readyState !== 1) {
|
|
300
|
+
throw new Error("picoclaw ws not open");
|
|
301
|
+
}
|
|
302
|
+
conn.send(msg);
|
|
303
|
+
},
|
|
304
|
+
onMessage(fn) { messageHandlers.add(fn); return () => messageHandlers.delete(fn); },
|
|
305
|
+
close(reason) {
|
|
306
|
+
try { conn?.close(reason); } catch {}
|
|
307
|
+
conn = null;
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function sleep(ms) {
|
|
313
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
314
|
+
}
|