@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.
Files changed (385) hide show
  1. package/README.md +860 -0
  2. package/bin/agentlink +8585 -0
  3. package/bin/agentlink-agent +7 -0
  4. package/bin/agentlink-mcp-stdio +173 -0
  5. package/docs/LOGGING.md +159 -0
  6. package/package.json +38 -0
  7. package/src/core.mjs +320 -0
  8. package/src/tunnel.mjs +291 -0
  9. package/src/tunnel_proxy.mjs +913 -0
  10. package/src/tunnel_service.mjs +699 -0
  11. package/src/tunnel_state.mjs +301 -0
  12. package/src/unified_producer.mjs +259 -0
  13. package/src-ext/README.md +75 -0
  14. package/src-ext/bin.mjs +128 -0
  15. package/src-ext/commands/agent.mjs +66 -0
  16. package/src-ext/commands/help.mjs +31 -0
  17. package/src-ext/commands/pair.mjs +455 -0
  18. package/src-ext/commands/reload.mjs +78 -0
  19. package/src-ext/commands/service.mjs +64 -0
  20. package/src-ext/core/accountResolver.mjs +137 -0
  21. package/src-ext/core/activeRuns.mjs +76 -0
  22. package/src-ext/core/agentlinkToolsBootstrap.mjs +75 -0
  23. package/src-ext/core/agentlinkToolsRegistry.mjs +323 -0
  24. package/src-ext/core/agentlinkToolsServer.mjs +109 -0
  25. package/src-ext/core/approvalGateway.mjs +132 -0
  26. package/src-ext/core/attachAuditLog.mjs +79 -0
  27. package/src-ext/core/attachDenylist.mjs +128 -0
  28. package/src-ext/core/autoTunnelDetector.mjs +98 -0
  29. package/src-ext/core/autoTunnelGateway.mjs +393 -0
  30. package/src-ext/core/autoTunnelWiring.mjs +184 -0
  31. package/src-ext/core/boundedMap.mjs +98 -0
  32. package/src-ext/core/bridgeAttachAutoScanner.mjs +237 -0
  33. package/src-ext/core/bridgeHooks.mjs +168 -0
  34. package/src-ext/core/bridgeSelfUninstall.mjs +133 -0
  35. package/src-ext/core/claudeTrust.mjs +74 -0
  36. package/src-ext/core/codexTrust.mjs +77 -0
  37. package/src-ext/core/cosUploadClient.mjs +326 -0
  38. package/src-ext/core/createWorkspace.mjs +170 -0
  39. package/src-ext/core/daemonRestart.mjs +49 -0
  40. package/src-ext/core/defaultWorkspace.mjs +65 -0
  41. package/src-ext/core/ensureGitRepo.mjs +57 -0
  42. package/src-ext/core/hermesProfile.mjs +75 -0
  43. package/src-ext/core/interruptGateway.mjs +119 -0
  44. package/src-ext/core/interruptRunListener.mjs +106 -0
  45. package/src-ext/core/mcpRuntimeFanout.mjs +236 -0
  46. package/src-ext/core/mcpStdioClient.mjs +316 -0
  47. package/src-ext/core/openclawGatewayClient.mjs +230 -0
  48. package/src-ext/core/pairCodeClient.mjs +331 -0
  49. package/src-ext/core/pairInventory.mjs +59 -0
  50. package/src-ext/core/pathExpand.mjs +34 -0
  51. package/src-ext/core/preprocessAttachments.mjs +113 -0
  52. package/src-ext/core/relayWorker.mjs +284 -0
  53. package/src-ext/core/relayWorkerHttp.mjs +58 -0
  54. package/src-ext/core/scanWorkspaces.mjs +842 -0
  55. package/src-ext/core/sessionSlot.mjs +70 -0
  56. package/src-ext/core/stateMachine.mjs +85 -0
  57. package/src-ext/core/toolsServerLifecycle.mjs +169 -0
  58. package/src-ext/core/unifiedDispatchHandler.mjs +439 -0
  59. package/src-ext/core/usageReporter.mjs +207 -0
  60. package/src-ext/openclaw-plugin/envelope-builder.cjs +619 -0
  61. package/src-ext/openclaw-plugin/index.cjs +1919 -0
  62. package/src-ext/openclaw-plugin/openclaw.plugin.json +20 -0
  63. package/src-ext/openclaw-plugin/package.json +12 -0
  64. package/src-ext/openclaw-plugin/relay-defaults.json +3 -0
  65. package/src-ext/openclaw-plugin/todoTranslatorUtils.cjs +101 -0
  66. package/src-ext/runtime/_shared/cliExec.mjs +138 -0
  67. package/src-ext/runtime/_shared/cosTextRefs.mjs +120 -0
  68. package/src-ext/runtime/_shared/fetchAndBase64Encode.mjs +52 -0
  69. package/src-ext/runtime/_shared/relayObjectToBlock.mjs +307 -0
  70. package/src-ext/runtime/_shared/sessionPicker.mjs +418 -0
  71. package/src-ext/runtime/_shared/slashCommandRouter.mjs +1346 -0
  72. package/src-ext/runtime/_shared/todoTranslatorUtils.mjs +94 -0
  73. package/src-ext/runtime/claude/askUserQuestionTranslator.mjs +241 -0
  74. package/src-ext/runtime/claude/customCommandsCollector.mjs +132 -0
  75. package/src-ext/runtime/claude/handleRequest.mjs +1418 -0
  76. package/src-ext/runtime/claude/index.mjs +160 -0
  77. package/src-ext/runtime/claude/internalCommandNames.mjs +58 -0
  78. package/src-ext/runtime/claude/launcher.mjs +313 -0
  79. package/src-ext/runtime/claude/mcpConfigAdapter.mjs +174 -0
  80. package/src-ext/runtime/claude/mcpConfigWriter.mjs +57 -0
  81. package/src-ext/runtime/claude/modelContextWindow.mjs +30 -0
  82. package/src-ext/runtime/claude/modelScanner.mjs +257 -0
  83. package/src-ext/runtime/claude/permissionInterruptBlock.mjs +86 -0
  84. package/src-ext/runtime/claude/permissionPromptServer.mjs +170 -0
  85. package/src-ext/runtime/claude/permissionPromptServerWorker.mjs +214 -0
  86. package/src-ext/runtime/claude/preflight.mjs +62 -0
  87. package/src-ext/runtime/claude/stdoutParser.mjs +365 -0
  88. package/src-ext/runtime/claude/todoTranslator.mjs +66 -0
  89. package/src-ext/runtime/claude/usageProbe.mjs +576 -0
  90. package/src-ext/runtime/claude/usageProbeStrip.mjs +14 -0
  91. package/src-ext/runtime/codex/codexCustomCommandsCollector.mjs +87 -0
  92. package/src-ext/runtime/codex/elicitationHandler.mjs +91 -0
  93. package/src-ext/runtime/codex/eventMapper.mjs +154 -0
  94. package/src-ext/runtime/codex/handleRequest.mjs +1152 -0
  95. package/src-ext/runtime/codex/index.mjs +142 -0
  96. package/src-ext/runtime/codex/mcpConfigAdapter.mjs +155 -0
  97. package/src-ext/runtime/codex/modelScanner.mjs +305 -0
  98. package/src-ext/runtime/codex/planNotificationHandler.mjs +61 -0
  99. package/src-ext/runtime/codex/preflight.mjs +67 -0
  100. package/src-ext/runtime/hermes/commandBackend.mjs +117 -0
  101. package/src-ext/runtime/hermes/envSetup.mjs +229 -0
  102. package/src-ext/runtime/hermes/gatewayManager.mjs +625 -0
  103. package/src-ext/runtime/hermes/handleRequest.mjs +1257 -0
  104. package/src-ext/runtime/hermes/httpBackend.mjs +219 -0
  105. package/src-ext/runtime/hermes/index.mjs +196 -0
  106. package/src-ext/runtime/hermes/mcpConfigAdapter.mjs +189 -0
  107. package/src-ext/runtime/hermes/preflight.mjs +359 -0
  108. package/src-ext/runtime/hermes/responsesBackend.mjs +276 -0
  109. package/src-ext/runtime/hermes/sessionStore.mjs +78 -0
  110. package/src-ext/runtime/hermes/todoTranslator.mjs +90 -0
  111. package/src-ext/runtime/hermes/workspaceRpc.mjs +124 -0
  112. package/src-ext/runtime/openclaw/buildOpenclawDaemonInput.mjs +143 -0
  113. package/src-ext/runtime/openclaw/mcpConfigAdapter.mjs +91 -0
  114. package/src-ext/runtime/openclaw/openclawConfig.mjs +145 -0
  115. package/src-ext/runtime/picoclaw/constants.mjs +39 -0
  116. package/src-ext/runtime/picoclaw/handleRequest.mjs +289 -0
  117. package/src-ext/runtime/picoclaw/index.mjs +314 -0
  118. package/src-ext/runtime/picoclaw/pairFlow.mjs +224 -0
  119. package/src-ext/runtime/picoclaw/state.mjs +78 -0
  120. package/src-ext/runtime/picoclaw/todoTranslator.mjs +67 -0
  121. package/src-ext/runtime/picoclaw/translator.mjs +272 -0
  122. package/src-ext/runtime/picoclaw/wsClient.mjs +129 -0
  123. package/src-ext/service/serviceManager.mjs +521 -0
  124. package/src-shared/README.md +44 -0
  125. package/src-shared/chat_push_normalizer.mjs +113 -0
  126. package/src-shared/correlation.mjs +25 -0
  127. package/src-shared/envelope_builder.mjs +612 -0
  128. package/src-shared/logger.mjs +167 -0
  129. package/src-shared/relay-defaults.json +3 -0
  130. package/src-shared/relay_revoke.mjs +46 -0
  131. package/src-shared/vendor/README.md +60 -0
  132. package/src-shared/vendor/smol-toml/LICENSE +24 -0
  133. package/src-shared/vendor/smol-toml/README.md +236 -0
  134. package/src-shared/vendor/smol-toml/VENDORED.md +37 -0
  135. package/src-shared/vendor/smol-toml/dist/date.d.ts +41 -0
  136. package/src-shared/vendor/smol-toml/dist/date.js +127 -0
  137. package/src-shared/vendor/smol-toml/dist/error.d.ts +38 -0
  138. package/src-shared/vendor/smol-toml/dist/error.js +63 -0
  139. package/src-shared/vendor/smol-toml/dist/extract.d.ts +30 -0
  140. package/src-shared/vendor/smol-toml/dist/extract.js +109 -0
  141. package/src-shared/vendor/smol-toml/dist/index.cjs +900 -0
  142. package/src-shared/vendor/smol-toml/dist/index.d.ts +43 -0
  143. package/src-shared/vendor/smol-toml/dist/index.js +33 -0
  144. package/src-shared/vendor/smol-toml/dist/parse.d.ts +37 -0
  145. package/src-shared/vendor/smol-toml/dist/parse.js +148 -0
  146. package/src-shared/vendor/smol-toml/dist/primitive.d.ts +31 -0
  147. package/src-shared/vendor/smol-toml/dist/primitive.js +178 -0
  148. package/src-shared/vendor/smol-toml/dist/stringify.d.ts +31 -0
  149. package/src-shared/vendor/smol-toml/dist/stringify.js +163 -0
  150. package/src-shared/vendor/smol-toml/dist/struct.d.ts +32 -0
  151. package/src-shared/vendor/smol-toml/dist/struct.js +194 -0
  152. package/src-shared/vendor/smol-toml/dist/util.d.ts +42 -0
  153. package/src-shared/vendor/smol-toml/dist/util.js +100 -0
  154. package/src-shared/vendor/smol-toml/package.json +54 -0
  155. package/src-shared/vendor/yaml/LICENSE +13 -0
  156. package/src-shared/vendor/yaml/README.md +155 -0
  157. package/src-shared/vendor/yaml/VENDORED.md +29 -0
  158. package/src-shared/vendor/yaml/bin.mjs +11 -0
  159. package/src-shared/vendor/yaml/browser/dist/compose/compose-collection.js +88 -0
  160. package/src-shared/vendor/yaml/browser/dist/compose/compose-doc.js +42 -0
  161. package/src-shared/vendor/yaml/browser/dist/compose/compose-node.js +92 -0
  162. package/src-shared/vendor/yaml/browser/dist/compose/compose-scalar.js +80 -0
  163. package/src-shared/vendor/yaml/browser/dist/compose/composer.js +217 -0
  164. package/src-shared/vendor/yaml/browser/dist/compose/resolve-block-map.js +113 -0
  165. package/src-shared/vendor/yaml/browser/dist/compose/resolve-block-scalar.js +198 -0
  166. package/src-shared/vendor/yaml/browser/dist/compose/resolve-block-seq.js +47 -0
  167. package/src-shared/vendor/yaml/browser/dist/compose/resolve-end.js +37 -0
  168. package/src-shared/vendor/yaml/browser/dist/compose/resolve-flow-collection.js +203 -0
  169. package/src-shared/vendor/yaml/browser/dist/compose/resolve-flow-scalar.js +223 -0
  170. package/src-shared/vendor/yaml/browser/dist/compose/resolve-props.js +148 -0
  171. package/src-shared/vendor/yaml/browser/dist/compose/util-contains-newline.js +34 -0
  172. package/src-shared/vendor/yaml/browser/dist/compose/util-empty-scalar-position.js +27 -0
  173. package/src-shared/vendor/yaml/browser/dist/compose/util-flow-indent-check.js +15 -0
  174. package/src-shared/vendor/yaml/browser/dist/compose/util-map-includes.js +17 -0
  175. package/src-shared/vendor/yaml/browser/dist/doc/Document.js +334 -0
  176. package/src-shared/vendor/yaml/browser/dist/doc/anchors.js +72 -0
  177. package/src-shared/vendor/yaml/browser/dist/doc/applyReviver.js +55 -0
  178. package/src-shared/vendor/yaml/browser/dist/doc/createNode.js +89 -0
  179. package/src-shared/vendor/yaml/browser/dist/doc/directives.js +176 -0
  180. package/src-shared/vendor/yaml/browser/dist/errors.js +57 -0
  181. package/src-shared/vendor/yaml/browser/dist/index.js +17 -0
  182. package/src-shared/vendor/yaml/browser/dist/log.js +14 -0
  183. package/src-shared/vendor/yaml/browser/dist/nodes/Alias.js +101 -0
  184. package/src-shared/vendor/yaml/browser/dist/nodes/Collection.js +147 -0
  185. package/src-shared/vendor/yaml/browser/dist/nodes/Node.js +38 -0
  186. package/src-shared/vendor/yaml/browser/dist/nodes/Pair.js +36 -0
  187. package/src-shared/vendor/yaml/browser/dist/nodes/Scalar.js +24 -0
  188. package/src-shared/vendor/yaml/browser/dist/nodes/YAMLMap.js +144 -0
  189. package/src-shared/vendor/yaml/browser/dist/nodes/YAMLSeq.js +113 -0
  190. package/src-shared/vendor/yaml/browser/dist/nodes/addPairToJSMap.js +104 -0
  191. package/src-shared/vendor/yaml/browser/dist/nodes/identity.js +36 -0
  192. package/src-shared/vendor/yaml/browser/dist/nodes/toJS.js +37 -0
  193. package/src-shared/vendor/yaml/browser/dist/parse/cst-scalar.js +214 -0
  194. package/src-shared/vendor/yaml/browser/dist/parse/cst-stringify.js +61 -0
  195. package/src-shared/vendor/yaml/browser/dist/parse/cst-visit.js +97 -0
  196. package/src-shared/vendor/yaml/browser/dist/parse/cst.js +98 -0
  197. package/src-shared/vendor/yaml/browser/dist/parse/lexer.js +717 -0
  198. package/src-shared/vendor/yaml/browser/dist/parse/line-counter.js +39 -0
  199. package/src-shared/vendor/yaml/browser/dist/parse/parser.js +954 -0
  200. package/src-shared/vendor/yaml/browser/dist/public-api.js +99 -0
  201. package/src-shared/vendor/yaml/browser/dist/schema/Schema.js +38 -0
  202. package/src-shared/vendor/yaml/browser/dist/schema/common/map.js +17 -0
  203. package/src-shared/vendor/yaml/browser/dist/schema/common/null.js +15 -0
  204. package/src-shared/vendor/yaml/browser/dist/schema/common/seq.js +17 -0
  205. package/src-shared/vendor/yaml/browser/dist/schema/common/string.js +14 -0
  206. package/src-shared/vendor/yaml/browser/dist/schema/core/bool.js +19 -0
  207. package/src-shared/vendor/yaml/browser/dist/schema/core/float.js +43 -0
  208. package/src-shared/vendor/yaml/browser/dist/schema/core/int.js +38 -0
  209. package/src-shared/vendor/yaml/browser/dist/schema/core/schema.js +23 -0
  210. package/src-shared/vendor/yaml/browser/dist/schema/json/schema.js +62 -0
  211. package/src-shared/vendor/yaml/browser/dist/schema/tags.js +83 -0
  212. package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/binary.js +66 -0
  213. package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/bool.js +26 -0
  214. package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/float.js +46 -0
  215. package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/int.js +71 -0
  216. package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/omap.js +74 -0
  217. package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/pairs.js +78 -0
  218. package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/schema.js +37 -0
  219. package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/set.js +93 -0
  220. package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/timestamp.js +101 -0
  221. package/src-shared/vendor/yaml/browser/dist/stringify/foldFlowLines.js +146 -0
  222. package/src-shared/vendor/yaml/browser/dist/stringify/stringify.js +124 -0
  223. package/src-shared/vendor/yaml/browser/dist/stringify/stringifyCollection.js +143 -0
  224. package/src-shared/vendor/yaml/browser/dist/stringify/stringifyComment.js +20 -0
  225. package/src-shared/vendor/yaml/browser/dist/stringify/stringifyDocument.js +85 -0
  226. package/src-shared/vendor/yaml/browser/dist/stringify/stringifyNumber.js +24 -0
  227. package/src-shared/vendor/yaml/browser/dist/stringify/stringifyPair.js +150 -0
  228. package/src-shared/vendor/yaml/browser/dist/stringify/stringifyString.js +328 -0
  229. package/src-shared/vendor/yaml/browser/dist/util.js +11 -0
  230. package/src-shared/vendor/yaml/browser/dist/visit.js +233 -0
  231. package/src-shared/vendor/yaml/browser/index.js +5 -0
  232. package/src-shared/vendor/yaml/browser/package.json +3 -0
  233. package/src-shared/vendor/yaml/dist/cli.d.ts +8 -0
  234. package/src-shared/vendor/yaml/dist/cli.mjs +199 -0
  235. package/src-shared/vendor/yaml/dist/compose/compose-collection.d.ts +11 -0
  236. package/src-shared/vendor/yaml/dist/compose/compose-collection.js +90 -0
  237. package/src-shared/vendor/yaml/dist/compose/compose-doc.d.ts +7 -0
  238. package/src-shared/vendor/yaml/dist/compose/compose-doc.js +44 -0
  239. package/src-shared/vendor/yaml/dist/compose/compose-node.d.ts +28 -0
  240. package/src-shared/vendor/yaml/dist/compose/compose-node.js +95 -0
  241. package/src-shared/vendor/yaml/dist/compose/compose-scalar.d.ts +5 -0
  242. package/src-shared/vendor/yaml/dist/compose/compose-scalar.js +82 -0
  243. package/src-shared/vendor/yaml/dist/compose/composer.d.ts +62 -0
  244. package/src-shared/vendor/yaml/dist/compose/composer.js +221 -0
  245. package/src-shared/vendor/yaml/dist/compose/resolve-block-map.d.ts +6 -0
  246. package/src-shared/vendor/yaml/dist/compose/resolve-block-map.js +115 -0
  247. package/src-shared/vendor/yaml/dist/compose/resolve-block-scalar.d.ts +11 -0
  248. package/src-shared/vendor/yaml/dist/compose/resolve-block-scalar.js +200 -0
  249. package/src-shared/vendor/yaml/dist/compose/resolve-block-seq.d.ts +6 -0
  250. package/src-shared/vendor/yaml/dist/compose/resolve-block-seq.js +49 -0
  251. package/src-shared/vendor/yaml/dist/compose/resolve-end.d.ts +6 -0
  252. package/src-shared/vendor/yaml/dist/compose/resolve-end.js +39 -0
  253. package/src-shared/vendor/yaml/dist/compose/resolve-flow-collection.d.ts +7 -0
  254. package/src-shared/vendor/yaml/dist/compose/resolve-flow-collection.js +205 -0
  255. package/src-shared/vendor/yaml/dist/compose/resolve-flow-scalar.d.ts +10 -0
  256. package/src-shared/vendor/yaml/dist/compose/resolve-flow-scalar.js +225 -0
  257. package/src-shared/vendor/yaml/dist/compose/resolve-props.d.ts +23 -0
  258. package/src-shared/vendor/yaml/dist/compose/resolve-props.js +150 -0
  259. package/src-shared/vendor/yaml/dist/compose/util-contains-newline.d.ts +2 -0
  260. package/src-shared/vendor/yaml/dist/compose/util-contains-newline.js +36 -0
  261. package/src-shared/vendor/yaml/dist/compose/util-empty-scalar-position.d.ts +2 -0
  262. package/src-shared/vendor/yaml/dist/compose/util-empty-scalar-position.js +29 -0
  263. package/src-shared/vendor/yaml/dist/compose/util-flow-indent-check.d.ts +3 -0
  264. package/src-shared/vendor/yaml/dist/compose/util-flow-indent-check.js +17 -0
  265. package/src-shared/vendor/yaml/dist/compose/util-map-includes.d.ts +4 -0
  266. package/src-shared/vendor/yaml/dist/compose/util-map-includes.js +19 -0
  267. package/src-shared/vendor/yaml/dist/doc/Document.d.ts +141 -0
  268. package/src-shared/vendor/yaml/dist/doc/Document.js +336 -0
  269. package/src-shared/vendor/yaml/dist/doc/anchors.d.ts +24 -0
  270. package/src-shared/vendor/yaml/dist/doc/anchors.js +77 -0
  271. package/src-shared/vendor/yaml/dist/doc/applyReviver.d.ts +9 -0
  272. package/src-shared/vendor/yaml/dist/doc/applyReviver.js +57 -0
  273. package/src-shared/vendor/yaml/dist/doc/createNode.d.ts +17 -0
  274. package/src-shared/vendor/yaml/dist/doc/createNode.js +91 -0
  275. package/src-shared/vendor/yaml/dist/doc/directives.d.ts +49 -0
  276. package/src-shared/vendor/yaml/dist/doc/directives.js +178 -0
  277. package/src-shared/vendor/yaml/dist/errors.d.ts +21 -0
  278. package/src-shared/vendor/yaml/dist/errors.js +62 -0
  279. package/src-shared/vendor/yaml/dist/index.d.ts +22 -0
  280. package/src-shared/vendor/yaml/dist/index.js +50 -0
  281. package/src-shared/vendor/yaml/dist/log.d.ts +3 -0
  282. package/src-shared/vendor/yaml/dist/log.js +17 -0
  283. package/src-shared/vendor/yaml/dist/nodes/Alias.d.ts +28 -0
  284. package/src-shared/vendor/yaml/dist/nodes/Alias.js +103 -0
  285. package/src-shared/vendor/yaml/dist/nodes/Collection.d.ts +73 -0
  286. package/src-shared/vendor/yaml/dist/nodes/Collection.js +151 -0
  287. package/src-shared/vendor/yaml/dist/nodes/Node.d.ts +47 -0
  288. package/src-shared/vendor/yaml/dist/nodes/Node.js +40 -0
  289. package/src-shared/vendor/yaml/dist/nodes/Pair.d.ts +21 -0
  290. package/src-shared/vendor/yaml/dist/nodes/Pair.js +39 -0
  291. package/src-shared/vendor/yaml/dist/nodes/Scalar.d.ts +42 -0
  292. package/src-shared/vendor/yaml/dist/nodes/Scalar.js +27 -0
  293. package/src-shared/vendor/yaml/dist/nodes/YAMLMap.d.ts +53 -0
  294. package/src-shared/vendor/yaml/dist/nodes/YAMLMap.js +147 -0
  295. package/src-shared/vendor/yaml/dist/nodes/YAMLSeq.d.ts +60 -0
  296. package/src-shared/vendor/yaml/dist/nodes/YAMLSeq.js +115 -0
  297. package/src-shared/vendor/yaml/dist/nodes/addPairToJSMap.d.ts +4 -0
  298. package/src-shared/vendor/yaml/dist/nodes/addPairToJSMap.js +106 -0
  299. package/src-shared/vendor/yaml/dist/nodes/identity.d.ts +23 -0
  300. package/src-shared/vendor/yaml/dist/nodes/identity.js +53 -0
  301. package/src-shared/vendor/yaml/dist/nodes/toJS.d.ts +27 -0
  302. package/src-shared/vendor/yaml/dist/nodes/toJS.js +39 -0
  303. package/src-shared/vendor/yaml/dist/options.d.ts +338 -0
  304. package/src-shared/vendor/yaml/dist/parse/cst-scalar.d.ts +64 -0
  305. package/src-shared/vendor/yaml/dist/parse/cst-scalar.js +218 -0
  306. package/src-shared/vendor/yaml/dist/parse/cst-stringify.d.ts +8 -0
  307. package/src-shared/vendor/yaml/dist/parse/cst-stringify.js +63 -0
  308. package/src-shared/vendor/yaml/dist/parse/cst-visit.d.ts +39 -0
  309. package/src-shared/vendor/yaml/dist/parse/cst-visit.js +99 -0
  310. package/src-shared/vendor/yaml/dist/parse/cst.d.ts +108 -0
  311. package/src-shared/vendor/yaml/dist/parse/cst.js +112 -0
  312. package/src-shared/vendor/yaml/dist/parse/lexer.d.ts +87 -0
  313. package/src-shared/vendor/yaml/dist/parse/lexer.js +719 -0
  314. package/src-shared/vendor/yaml/dist/parse/line-counter.d.ts +22 -0
  315. package/src-shared/vendor/yaml/dist/parse/line-counter.js +41 -0
  316. package/src-shared/vendor/yaml/dist/parse/parser.d.ts +84 -0
  317. package/src-shared/vendor/yaml/dist/parse/parser.js +958 -0
  318. package/src-shared/vendor/yaml/dist/public-api.d.ts +43 -0
  319. package/src-shared/vendor/yaml/dist/public-api.js +104 -0
  320. package/src-shared/vendor/yaml/dist/schema/Schema.d.ts +18 -0
  321. package/src-shared/vendor/yaml/dist/schema/Schema.js +40 -0
  322. package/src-shared/vendor/yaml/dist/schema/common/map.d.ts +2 -0
  323. package/src-shared/vendor/yaml/dist/schema/common/map.js +19 -0
  324. package/src-shared/vendor/yaml/dist/schema/common/null.d.ts +4 -0
  325. package/src-shared/vendor/yaml/dist/schema/common/null.js +17 -0
  326. package/src-shared/vendor/yaml/dist/schema/common/seq.d.ts +2 -0
  327. package/src-shared/vendor/yaml/dist/schema/common/seq.js +19 -0
  328. package/src-shared/vendor/yaml/dist/schema/common/string.d.ts +2 -0
  329. package/src-shared/vendor/yaml/dist/schema/common/string.js +16 -0
  330. package/src-shared/vendor/yaml/dist/schema/core/bool.d.ts +4 -0
  331. package/src-shared/vendor/yaml/dist/schema/core/bool.js +21 -0
  332. package/src-shared/vendor/yaml/dist/schema/core/float.d.ts +4 -0
  333. package/src-shared/vendor/yaml/dist/schema/core/float.js +47 -0
  334. package/src-shared/vendor/yaml/dist/schema/core/int.d.ts +4 -0
  335. package/src-shared/vendor/yaml/dist/schema/core/int.js +42 -0
  336. package/src-shared/vendor/yaml/dist/schema/core/schema.d.ts +1 -0
  337. package/src-shared/vendor/yaml/dist/schema/core/schema.js +25 -0
  338. package/src-shared/vendor/yaml/dist/schema/json/schema.d.ts +2 -0
  339. package/src-shared/vendor/yaml/dist/schema/json/schema.js +64 -0
  340. package/src-shared/vendor/yaml/dist/schema/json-schema.d.ts +69 -0
  341. package/src-shared/vendor/yaml/dist/schema/tags.d.ts +40 -0
  342. package/src-shared/vendor/yaml/dist/schema/tags.js +86 -0
  343. package/src-shared/vendor/yaml/dist/schema/types.d.ts +90 -0
  344. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/binary.d.ts +2 -0
  345. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/binary.js +68 -0
  346. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/bool.d.ts +7 -0
  347. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/bool.js +29 -0
  348. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/float.d.ts +4 -0
  349. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/float.js +50 -0
  350. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/int.d.ts +5 -0
  351. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/int.js +76 -0
  352. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/omap.d.ts +28 -0
  353. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/omap.js +77 -0
  354. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/pairs.d.ts +10 -0
  355. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/pairs.js +82 -0
  356. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -0
  357. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/schema.js +39 -0
  358. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/set.d.ts +28 -0
  359. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/set.js +96 -0
  360. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/timestamp.d.ts +6 -0
  361. package/src-shared/vendor/yaml/dist/schema/yaml-1.1/timestamp.js +105 -0
  362. package/src-shared/vendor/yaml/dist/stringify/foldFlowLines.d.ts +34 -0
  363. package/src-shared/vendor/yaml/dist/stringify/foldFlowLines.js +151 -0
  364. package/src-shared/vendor/yaml/dist/stringify/stringify.d.ts +21 -0
  365. package/src-shared/vendor/yaml/dist/stringify/stringify.js +127 -0
  366. package/src-shared/vendor/yaml/dist/stringify/stringifyCollection.d.ts +17 -0
  367. package/src-shared/vendor/yaml/dist/stringify/stringifyCollection.js +145 -0
  368. package/src-shared/vendor/yaml/dist/stringify/stringifyComment.d.ts +10 -0
  369. package/src-shared/vendor/yaml/dist/stringify/stringifyComment.js +24 -0
  370. package/src-shared/vendor/yaml/dist/stringify/stringifyDocument.d.ts +4 -0
  371. package/src-shared/vendor/yaml/dist/stringify/stringifyDocument.js +87 -0
  372. package/src-shared/vendor/yaml/dist/stringify/stringifyNumber.d.ts +2 -0
  373. package/src-shared/vendor/yaml/dist/stringify/stringifyNumber.js +26 -0
  374. package/src-shared/vendor/yaml/dist/stringify/stringifyPair.d.ts +3 -0
  375. package/src-shared/vendor/yaml/dist/stringify/stringifyPair.js +152 -0
  376. package/src-shared/vendor/yaml/dist/stringify/stringifyString.d.ts +9 -0
  377. package/src-shared/vendor/yaml/dist/stringify/stringifyString.js +330 -0
  378. package/src-shared/vendor/yaml/dist/test-events.d.ts +4 -0
  379. package/src-shared/vendor/yaml/dist/test-events.js +134 -0
  380. package/src-shared/vendor/yaml/dist/util.d.ts +12 -0
  381. package/src-shared/vendor/yaml/dist/util.js +28 -0
  382. package/src-shared/vendor/yaml/dist/visit.d.ts +102 -0
  383. package/src-shared/vendor/yaml/dist/visit.js +236 -0
  384. package/src-shared/vendor/yaml/package.json +96 -0
  385. 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
+ }