@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,323 @@
1
+ // Agentlink 自定义工具的声明 + 执行器。
2
+ //
3
+ // 这些工具是暴露给 Claude / Codex / Hermes / OpenClaw 用的(通过 MCP 桥
4
+ // + plugin tool injection)。不是给用户的。
5
+ //
6
+ // 设计原则:
7
+ // - 每个工具的 schema 明确、最小
8
+ // - 副作用只影响当前 session(change_title / notify_user / attach_file)
9
+ // - 未来要做"跨设备"动作(推送、日历等)在这里注册
10
+ //
11
+ // 每个工具的 handler 返回:
12
+ // { content: [{ type: "text", text: "..." }], isError?: boolean }
13
+ // 符合 MCP tools/call 的标准 result 结构。
14
+ //
15
+ // ctx 注入:
16
+ // publishEvent(event) bridge 的 worker.publishEvent 偏函数(已绑定当前
17
+ // in-flight requestId)。无 in-flight 时是 no-op。
18
+ // runtime "claude" / "codex" / "hermes" / "openclaw"
19
+ // log bridge logger
20
+ // relayConfig { baseUrl, gatewayId, token } 给 cosUploadClient 用,
21
+ // agentlink_attach_file 需要。caller 没传就 attach 工具
22
+ // 不可用(仅 list 不报)。
23
+
24
+ import os from "node:os";
25
+ import path from "node:path";
26
+ import crypto from "node:crypto";
27
+ import fs from "node:fs/promises";
28
+ import { uploadFileToCos, inferMime } from "./cosUploadClient.mjs";
29
+ import { checkDenylist } from "./attachDenylist.mjs";
30
+ import { appendAuditEntry } from "./attachAuditLog.mjs";
31
+
32
+ // attach 工具的大小上限,与 spec D2 / relay 端一致(50 MiB)。
33
+ const ATTACH_MAX_BYTES = 50 * 1024 * 1024;
34
+
35
+ /**
36
+ * @param {{ publishEvent: (event:object)=>Promise<any>, runtime: string, log: any, relayConfig?: object, _uploadFn?: Function }} ctx
37
+ * _uploadFn: 可选注入,用于单元测试覆盖 uploadFileToCos(避免真 COS 网络请求)
38
+ * @returns {{ list: Array<{name,description,inputSchema}>, dispatch: (name,args)=>Promise<any> }}
39
+ */
40
+ export function createAgentlinkToolsRegistry(ctx) {
41
+ if (typeof ctx?.publishEvent !== "function") {
42
+ throw new Error("agentlinkTools: publishEvent function required");
43
+ }
44
+ if (!ctx?.log) throw new Error("agentlinkTools: log required");
45
+
46
+ const log = ctx.log.child({ comp: "mcp", side: "agentlink-tools" });
47
+
48
+ const tools = [
49
+ {
50
+ name: "agentlink_change_title",
51
+ description:
52
+ "Change the title of the current agentlink session. Visible to the user in the app's " +
53
+ "session list. Use sparingly.",
54
+ inputSchema: {
55
+ type: "object",
56
+ properties: {
57
+ title: { type: "string", description: "New title text (<= 120 chars)." },
58
+ },
59
+ required: ["title"],
60
+ },
61
+ },
62
+ {
63
+ name: "agentlink_notify_user",
64
+ description:
65
+ "Send a one-shot notification message to the user's mobile app. Shows as a system " +
66
+ "bubble in the chat. Use for important status changes only.",
67
+ inputSchema: {
68
+ type: "object",
69
+ properties: {
70
+ message: { type: "string" },
71
+ level: { type: "string", enum: ["info", "warn", "error"] },
72
+ },
73
+ required: ["message"],
74
+ },
75
+ },
76
+ {
77
+ name: "agentlink_attach_file",
78
+ description:
79
+ "Share a local file on this host with the user's mobile app. The mobile app cannot " +
80
+ "access host filesystem paths directly. Call this whenever the user might want to view " +
81
+ "a file you are referring to. The file is uploaded to cloud storage and an attachment " +
82
+ "event is sent to the app; the user sees a preview card and can tap to view contents. " +
83
+ "Files matching the privacy denylist (SSH keys, .env, credentials, .git, etc.) are " +
84
+ "rejected. Maximum file size is 50 MiB.",
85
+ inputSchema: {
86
+ type: "object",
87
+ properties: {
88
+ path: {
89
+ type: "string",
90
+ description:
91
+ "Absolute path or '~/'-prefixed path on this host. Symlinks are resolved before processing.",
92
+ },
93
+ reason: {
94
+ type: "string",
95
+ description: "Optional short reason for sharing, recorded in the host's audit log.",
96
+ },
97
+ },
98
+ required: ["path"],
99
+ },
100
+ },
101
+ ];
102
+
103
+ async function dispatch(name, args) {
104
+ const input = args && typeof args === "object" ? args : {};
105
+ // attach_file 的 path/reason 对线下调试很关键(audit log 也会记一份,但是个
106
+ // dispatcher 入口 log 让我们看到"哪个 caller 触发"了 attach: agent 主动 vs
107
+ // bridgeAttachAutoScanner 自动)。reason="auto-scan" → 自动触发,其它 reason
108
+ // 是 agent 显式调用。
109
+ if (name === "agentlink_attach_file") {
110
+ log.info("mcp_bridge.forward", "agentlink tool called", {
111
+ name,
112
+ path: typeof input.path === "string" ? input.path : null,
113
+ reason: typeof input.reason === "string" ? input.reason : null,
114
+ });
115
+ } else {
116
+ log.info("mcp_bridge.forward", "agentlink tool called", { name });
117
+ }
118
+ switch (name) {
119
+ case "agentlink_change_title": {
120
+ const title = String(input.title || "").slice(0, 120);
121
+ if (!title) return errResult("title required");
122
+ await ctx.publishEvent({ event: "title_change", payload: { title } });
123
+ return okResult(`title changed to: ${title}`);
124
+ }
125
+ case "agentlink_notify_user": {
126
+ const message = String(input.message || "");
127
+ const level = input.level === "warn" || input.level === "error" ? input.level : "info";
128
+ if (!message) return errResult("message required");
129
+ await ctx.publishEvent({ event: "notification", payload: { message, level } });
130
+ return okResult(`notified user (level=${level})`);
131
+ }
132
+ case "agentlink_attach_file": {
133
+ // 完整流程见 spec host-file-attach-cos / Requirement: CLI exposes
134
+ // agentlink_attach_file MCP tool。注意点:
135
+ // 1. try/finally 保证每个 exit path 都写一行 audit
136
+ // 2. 失败时 throw 一个带 .reason 的对象,统一映射到 tool result
137
+ // `ok: false, reason: <code>`(agent 拿到的)
138
+ // 3. publishEvent 失败不视为 attach 失败(对象已在 COS),只是 App
139
+ // 没收到事件;audit 记 publish_failed
140
+ const rawPath = String(input.path || "").trim();
141
+ const reason = String(input.reason || "").slice(0, 256);
142
+ const agentId = ctx.relayConfig?.gatewayId || null;
143
+ const auditBase = { agentId, reason: reason || undefined };
144
+ if (!rawPath) {
145
+ await appendAuditEntry({ ...auditBase, result: "denied", denylist_pattern: "<empty-path>" });
146
+ return errResult(JSON.stringify({ ok: false, reason: "denied" }));
147
+ }
148
+
149
+ // 1) 路径展开 + realpath。让 denylist 看到的就是用户文件系统上的实
150
+ // 际路径(symlink 解析后),防 ../ 之类的绕过。
151
+ let absPath = rawPath;
152
+ if (absPath.startsWith("~/")) {
153
+ absPath = path.join(os.homedir(), absPath.slice(2));
154
+ } else if (absPath === "~") {
155
+ absPath = os.homedir();
156
+ }
157
+ absPath = path.resolve(absPath);
158
+ try {
159
+ absPath = await fs.realpath(absPath);
160
+ } catch {
161
+ // realpath 失败往往因为文件不存在;留到 stat 阶段统一处理 not_found
162
+ }
163
+
164
+ // 2) denylist
165
+ const dl = checkDenylist(absPath);
166
+ if (dl.denied) {
167
+ await appendAuditEntry({
168
+ ...auditBase,
169
+ path: absPath,
170
+ result: "denied",
171
+ denylist_pattern: dl.pattern,
172
+ });
173
+ return errResult(JSON.stringify({ ok: false, reason: "denied" }));
174
+ }
175
+
176
+ // 3) stat + size check
177
+ let st;
178
+ try {
179
+ st = await fs.stat(absPath);
180
+ } catch (err) {
181
+ await appendAuditEntry({
182
+ ...auditBase,
183
+ path: absPath,
184
+ result: "not_found",
185
+ error: err?.code || err?.message?.slice(0, 80),
186
+ });
187
+ return errResult(JSON.stringify({ ok: false, reason: "not_found" }));
188
+ }
189
+ if (!st.isFile()) {
190
+ await appendAuditEntry({ ...auditBase, path: absPath, result: "not_found", error: "not a regular file" });
191
+ return errResult(JSON.stringify({ ok: false, reason: "not_found" }));
192
+ }
193
+ if (st.size > ATTACH_MAX_BYTES) {
194
+ await appendAuditEntry({
195
+ ...auditBase,
196
+ path: absPath,
197
+ size: st.size,
198
+ result: "too_large",
199
+ });
200
+ return errResult(JSON.stringify({ ok: false, reason: "too_large" }));
201
+ }
202
+
203
+ // 4) read + sha256 + mime
204
+ let content;
205
+ try {
206
+ content = await fs.readFile(absPath);
207
+ } catch (err) {
208
+ await appendAuditEntry({
209
+ ...auditBase,
210
+ path: absPath,
211
+ size: st.size,
212
+ result: "not_found",
213
+ error: err?.code || err?.message?.slice(0, 80),
214
+ });
215
+ return errResult(JSON.stringify({ ok: false, reason: "not_found" }));
216
+ }
217
+ const sha256 = crypto.createHash("sha256").update(content).digest("hex");
218
+ const basename = path.basename(absPath);
219
+ const mime = inferMime(basename);
220
+
221
+ // 5–7) sign → PUT → commit (cosUploadClient 内部分类)
222
+ if (!ctx.relayConfig?.baseUrl || !ctx.relayConfig?.gatewayId || !ctx.relayConfig?.token) {
223
+ await appendAuditEntry({
224
+ ...auditBase,
225
+ path: absPath,
226
+ sha256,
227
+ size: st.size,
228
+ mime,
229
+ result: "sign_failed",
230
+ error: "relayConfig missing on registry ctx",
231
+ });
232
+ return errResult(JSON.stringify({ ok: false, reason: "sign_failed" }));
233
+ }
234
+ // _uploadFn 可由单元测试注入以避免真 COS 网络请求;生产走 uploadFileToCos
235
+ const doUpload = ctx._uploadFn ?? uploadFileToCos;
236
+ let uploadResult;
237
+ try {
238
+ uploadResult = await doUpload({
239
+ name: basename,
240
+ content,
241
+ mime,
242
+ size: st.size,
243
+ sha256,
244
+ relayConfig: ctx.relayConfig,
245
+ log,
246
+ });
247
+ } catch (err) {
248
+ const kind = err?.kind || "sign_failed";
249
+ await appendAuditEntry({
250
+ ...auditBase,
251
+ path: absPath,
252
+ sha256,
253
+ size: st.size,
254
+ mime,
255
+ result: kind,
256
+ error: err?.message?.slice(0, 200),
257
+ });
258
+ return errResult(JSON.stringify({ ok: false, reason: kind }));
259
+ }
260
+
261
+ // 8) publishEvent — 失败不致命,但要 audit
262
+ // spec D6: payload 含 cosObjectKey,不含 publicUrl
263
+ const eventPayload = {
264
+ name: basename,
265
+ cosObjectKey: uploadResult.cosObjectKey,
266
+ mime,
267
+ size: st.size,
268
+ sha256,
269
+ // 故意不带 absPath: 不让本机文件系统布局泄到 App / 云端日志
270
+ };
271
+ let publishOk = true;
272
+ try {
273
+ await ctx.publishEvent({ event: "attachment", payload: eventPayload });
274
+ } catch (err) {
275
+ publishOk = false;
276
+ await appendAuditEntry({
277
+ ...auditBase,
278
+ path: absPath,
279
+ sha256,
280
+ size: st.size,
281
+ mime,
282
+ result: "publish_failed",
283
+ error: err?.message?.slice(0, 200),
284
+ });
285
+ // 此处仍然继续:对象已在 COS,返回 ok 给 agent,只是 App 端不感知本轮事件
286
+ }
287
+ if (publishOk) {
288
+ await appendAuditEntry({
289
+ ...auditBase,
290
+ path: absPath,
291
+ sha256,
292
+ size: st.size,
293
+ mime,
294
+ result: "ok",
295
+ cosObjectKey: uploadResult.cosObjectKey,
296
+ deduped: uploadResult.deduped || false,
297
+ });
298
+ }
299
+ // spec D6: tool result = { ok, cosObjectKey, sha256, deduped },无 url 字段
300
+ return okResult(
301
+ JSON.stringify({
302
+ ok: true,
303
+ cosObjectKey: uploadResult.cosObjectKey,
304
+ sha256,
305
+ deduped: uploadResult.deduped || false,
306
+ }),
307
+ );
308
+ }
309
+ default:
310
+ return errResult(`unknown tool: ${name}`);
311
+ }
312
+ }
313
+
314
+ return { list: tools, dispatch };
315
+ }
316
+
317
+ function okResult(text) {
318
+ return { content: [{ type: "text", text }] };
319
+ }
320
+
321
+ function errResult(text) {
322
+ return { content: [{ type: "text", text }], isError: true };
323
+ }
@@ -0,0 +1,109 @@
1
+ // 本地 HTTP server:暴露 agentlink tools 给 agentlink-mcp-stdio.mjs 桥脚本。
2
+ //
3
+ // 协议是简化的 "MCP-ish" JSON over HTTP:
4
+ // POST /tools/list → { tools: [...] }
5
+ // POST /tools/call { name, arguments } → { content: [...], isError? }
6
+ //
7
+ // 和 Unix 标准 MCP 差别:这里不做 initialize,因为只给自家 stdio bridge 用,
8
+ // 不对外通用。跨平台统一选 TCP 而非 UDS(见 docs/PLATFORM.md)。
9
+ //
10
+ // 鉴权:启动时生成 auth token,桥脚本用 header `X-Agentlink-Auth` 带过来。
11
+
12
+ import http from "node:http";
13
+ import { randomBytes } from "node:crypto";
14
+
15
+ export async function startAgentlinkToolsServer({ registry, log }) {
16
+ if (!registry) throw new Error("startAgentlinkToolsServer: registry required");
17
+ if (!log) throw new Error("startAgentlinkToolsServer: log required");
18
+ const sLog = log.child({ comp: "mcp", side: "agentlink-tools-server" });
19
+
20
+ const authToken = randomBytes(16).toString("hex");
21
+
22
+ const server = http.createServer(async (req, res) => {
23
+ try {
24
+ if (req.method !== "POST") {
25
+ res.statusCode = 405;
26
+ res.end();
27
+ return;
28
+ }
29
+ // 接受 Authorization: Bearer <token>(标准 MCP / 与 agentlink-mcp-stdio
30
+ // 的 --discovery 流程一致)或 x-agentlink-auth: <token>(兼容老路径)。
31
+ const authz = req.headers["authorization"];
32
+ const bearerOk =
33
+ typeof authz === "string" &&
34
+ authz.toLowerCase().startsWith("bearer ") &&
35
+ authz.slice(7).trim() === authToken;
36
+ const legacyOk = req.headers["x-agentlink-auth"] === authToken;
37
+ if (!bearerOk && !legacyOk) {
38
+ sLog.warn("mcp_bridge.auth.invalid", "unauthenticated request", {
39
+ remote: req.socket?.remoteAddress,
40
+ });
41
+ res.statusCode = 401; res.end();
42
+ return;
43
+ }
44
+ const body = await readBody(req, 1 << 20);
45
+ let input = {};
46
+ if (body) {
47
+ try { input = JSON.parse(body.toString("utf8")); }
48
+ catch { res.statusCode = 400; res.end(); return; }
49
+ }
50
+ res.setHeader("Content-Type", "application/json");
51
+ if (req.url === "/tools/list") {
52
+ res.end(JSON.stringify({ tools: registry.list }));
53
+ return;
54
+ }
55
+ if (req.url === "/tools/call") {
56
+ const name = String(input.name || "");
57
+ const args = input.arguments || {};
58
+ const out = await registry.dispatch(name, args);
59
+ res.end(JSON.stringify(out || { content: [], isError: true }));
60
+ return;
61
+ }
62
+ res.statusCode = 404; res.end();
63
+ } catch (err) {
64
+ sLog.error("error.caught", "agentlink-tools-server handler threw", {
65
+ where: "agentlinkToolsServer.handler",
66
+ err: err?.message || String(err),
67
+ });
68
+ if (!res.headersSent) {
69
+ res.statusCode = 500;
70
+ res.end();
71
+ }
72
+ }
73
+ });
74
+
75
+ await new Promise((resolve, reject) => {
76
+ server.once("error", reject);
77
+ server.listen(0, "127.0.0.1", () => {
78
+ server.removeListener("error", reject);
79
+ resolve();
80
+ });
81
+ });
82
+ const port = server.address().port;
83
+ const baseUrl = `http://127.0.0.1:${port}`;
84
+ sLog.info("mcp_bridge.server.listen", "tools server ready", { port });
85
+
86
+ return {
87
+ port,
88
+ baseUrl,
89
+ authToken,
90
+ close: () => new Promise((resolve) => {
91
+ sLog.info("mcp_bridge.server.close", "closing tools server");
92
+ server.close(() => resolve());
93
+ }),
94
+ };
95
+ }
96
+
97
+ function readBody(req, limit) {
98
+ return new Promise((resolve, reject) => {
99
+ const chunks = [];
100
+ let size = 0;
101
+ req.on("data", (c) => {
102
+ size += c.length;
103
+ if (size > limit) { req.destroy(); reject(new Error("body too large")); return; }
104
+ chunks.push(c);
105
+ });
106
+ req.on("end", () => resolve(Buffer.concat(chunks)));
107
+ req.on("error", reject);
108
+ });
109
+ }
@@ -0,0 +1,132 @@
1
+ // 审批闸门:Claude hook / Codex elicitation 都在这里收敛。
2
+ //
3
+ // 工作流:
4
+ // 1. Hook/Elicit 触发 → openRequest({tool, input}) 返回 { requestId, promise }
5
+ // 2. 调用方把 requestId + 工具信息通过 relay 发到 App(kind=tool_approval_request)
6
+ // 3. 调用方 await promise —— 阻塞直到 settle()
7
+ // 4. App 通过 SSE 回传 kind=tool_approval_response → CLI 的 SSE handler 调
8
+ // approvalGateway.settle(requestId, decision)
9
+ // 5. promise resolve,Hook/Elicit 返回"允许/拒绝"到 agent
10
+ //
11
+ // 关键:
12
+ // - 每 60s 打 `approval.pending wait_s=N` 日志;手机一直不响应也不超时,
13
+ // 但日志能看到等了多久。
14
+ // - dispose() 时强制 reject 所有 pending(CLI 关闭 → 告诉 Hook "被取消")。
15
+
16
+ import { randomBytes } from "node:crypto";
17
+
18
+ const PENDING_LOG_INTERVAL_MS = 60_000;
19
+ // audit 修复:settle 丢失(网络抖动 / App 离线)的请求此前永久挂在 pending。
20
+ // 默认 10 分钟硬超时后按 reject 收尾(codex elicitation 自身也有秒级超时,
21
+ // 10min 已远超任何正常交互窗口)。可经 opts.timeoutMs 覆盖。
22
+ const DEFAULT_APPROVAL_TIMEOUT_MS = 10 * 60_000;
23
+
24
+ export function createApprovalGateway({ log, timeoutMs = DEFAULT_APPROVAL_TIMEOUT_MS }) {
25
+ if (!log) throw new Error("createApprovalGateway: log required");
26
+ const agLog = log.child({ comp: "approval" });
27
+ const pending = new Map(); // requestId → { resolve, reject, openedAt, meta, tickerHandle }
28
+
29
+ function newRequestId() {
30
+ return "req_" + randomBytes(4).toString("hex");
31
+ }
32
+
33
+ function openRequest(meta = {}) {
34
+ const requestId = newRequestId();
35
+ let resolveFn, rejectFn;
36
+ const promise = new Promise((resolve, reject) => {
37
+ resolveFn = resolve;
38
+ rejectFn = reject;
39
+ });
40
+ const openedAt = Date.now();
41
+ const tickerHandle = setInterval(() => {
42
+ if (!pending.has(requestId)) return;
43
+ const waitMs = Date.now() - openedAt;
44
+ agLog.info("approval.pending", "still waiting for user", {
45
+ request_id: requestId,
46
+ tool: meta.tool_name || "",
47
+ wait_s: Math.round(waitMs / 1000),
48
+ });
49
+ }, PENDING_LOG_INTERVAL_MS);
50
+ tickerHandle.unref?.();
51
+
52
+ // 硬超时:超窗自动按 reject 收尾(与用户点「拒绝」同构,调用方无需特判)
53
+ let timeoutHandle = null;
54
+ if (timeoutMs > 0) {
55
+ timeoutHandle = setTimeout(() => {
56
+ if (!pending.has(requestId)) return;
57
+ agLog.warn("approval.timeout", "approval request timed out, auto-reject", {
58
+ request_id: requestId, tool: meta.tool_name || "", timeout_ms: timeoutMs,
59
+ });
60
+ settle(requestId, "reject", "approval-timeout");
61
+ }, timeoutMs);
62
+ timeoutHandle.unref?.();
63
+ }
64
+
65
+ pending.set(requestId, {
66
+ resolve: resolveFn,
67
+ reject: rejectFn,
68
+ openedAt,
69
+ meta,
70
+ tickerHandle,
71
+ timeoutHandle,
72
+ });
73
+
74
+ agLog.info("approval.request.sent", "approval request opened", {
75
+ request_id: requestId,
76
+ tool: meta.tool_name || "",
77
+ has_input: !!meta.tool_input,
78
+ });
79
+
80
+ return { requestId, promise };
81
+ }
82
+
83
+ function settle(requestId, decision, reason) {
84
+ const entry = pending.get(requestId);
85
+ if (!entry) {
86
+ agLog.warn("approval.settle.missing", "no pending request for id", {
87
+ request_id: requestId,
88
+ decision,
89
+ });
90
+ return false;
91
+ }
92
+ pending.delete(requestId);
93
+ clearInterval(entry.tickerHandle);
94
+ if (entry.timeoutHandle) clearTimeout(entry.timeoutHandle);
95
+ const waitMs = Date.now() - entry.openedAt;
96
+ agLog.info("approval.response.recv", "approval resolved", {
97
+ request_id: requestId,
98
+ tool: entry.meta.tool_name || "",
99
+ decision,
100
+ wait_ms: waitMs,
101
+ });
102
+ entry.resolve({ decision, reason: reason || "", wait_ms: waitMs });
103
+ return true;
104
+ }
105
+
106
+ // dispose:把所有 pending 以 "cancelled" reject 掉(例如 CLI 关闭)。
107
+ function dispose(reason = "gateway-disposed") {
108
+ const ids = [...pending.keys()];
109
+ for (const id of ids) {
110
+ const entry = pending.get(id);
111
+ if (!entry) continue;
112
+ pending.delete(id);
113
+ clearInterval(entry.tickerHandle);
114
+ if (entry.timeoutHandle) clearTimeout(entry.timeoutHandle);
115
+ agLog.warn("approval.dispose", "cancelling pending request", {
116
+ request_id: id, reason,
117
+ });
118
+ // Hook 那边收到 reject → 会走 deny 语义 (看 hookServer 怎么编码)
119
+ entry.reject(new Error(`approval cancelled: ${reason}`));
120
+ }
121
+ }
122
+
123
+ function pendingCount() {
124
+ return pending.size;
125
+ }
126
+
127
+ function hasPending(requestId) {
128
+ return pending.has(requestId);
129
+ }
130
+
131
+ return { openRequest, settle, dispose, pendingCount, hasPending };
132
+ }
@@ -0,0 +1,79 @@
1
+ // attachAuditLog.mjs — agentlink_attach_file 工具的本地审计日志
2
+ //
3
+ // 每次 attach 调用(成功 / 拒绝 / 失败)都追加一行 NDJSON 到
4
+ // `~/.agentlink/attach-log.ndjson`,让用户事后能追责(哪个 agent 在什么时候
5
+ // attach 了哪个文件 / 为什么被拒)。
6
+ //
7
+ // 设计原则:
8
+ // - best-effort:FS 错误 swallow + console.error,绝不让 audit 写失败把
9
+ // 工具 dispatch 拖崩
10
+ // - 同步串行:用 promise chain 保证多 attach 并发时也按顺序写盘
11
+ // - 不轮转:第一版不实现 size cap / rotation;用户 ndjson 文件不大,
12
+ // 后续 change 再加(与其它 ~/.agentlink/ 下日志策略统一)
13
+ //
14
+ // spec ref: openspec/changes/host-file-cos-attachment/specs/host-file-attach-cos/spec.md
15
+ // Requirement: audit log
16
+
17
+ import fs from "node:fs/promises";
18
+ import os from "node:os";
19
+ import path from "node:path";
20
+
21
+ const HOME = os.homedir();
22
+ const AGENTLINK_DIR = path.join(HOME, ".agentlink");
23
+ const AUDIT_PATH = path.join(AGENTLINK_DIR, "attach-log.ndjson");
24
+
25
+ // 串行化 write,避免并发 attach 时两次 appendFile 交错出乱行
26
+ let writeChain = Promise.resolve();
27
+
28
+ /**
29
+ * 追加一条审计记录。non-throwing:FS 错误时 console.error 但不 reject。
30
+ *
31
+ * entry 字段建议(spec 列了,工具 dispatcher 负责填):
32
+ * ts, agentId, path, sha256?, size?, mime?, result, denylist_pattern?, error?
33
+ *
34
+ * 调用方不需要 await,但如果想等写完(测试场景)可以 await 返回的 Promise。
35
+ *
36
+ * @param {Record<string, any>} entry
37
+ * @returns {Promise<void>}
38
+ */
39
+ export function appendAuditEntry(entry) {
40
+ writeChain = writeChain.then(async () => {
41
+ try {
42
+ // ensure ~/.agentlink 存在(mode 0o700 = 仅 owner 读写执行)
43
+ await fs.mkdir(AGENTLINK_DIR, { recursive: true, mode: 0o700 });
44
+ // ts 字段未填的话兜底现在时刻
45
+ const record = {
46
+ ts: new Date().toISOString(),
47
+ ...entry,
48
+ };
49
+ const line = JSON.stringify(record) + "\n";
50
+ await fs.appendFile(AUDIT_PATH, line, { mode: 0o600 });
51
+ } catch (err) {
52
+ // 用 console.error 而不是 throw —— audit 不能让工具 dispatch 失败
53
+ console.error(`[attachAuditLog] append failed: ${err?.message || err}`);
54
+ }
55
+ });
56
+ return writeChain;
57
+ }
58
+
59
+ /**
60
+ * 暴露 audit 文件路径(测试 / 文档用)。
61
+ */
62
+ export function getAuditLogPath() {
63
+ return AUDIT_PATH;
64
+ }
65
+
66
+ /**
67
+ * CLI 状态目录名常量(唯一来源)。
68
+ * 改名 agentlink 时只改这一处。
69
+ */
70
+ export const CLI_STATE_DIR_NAME = ".agentlink";
71
+
72
+ /**
73
+ * 暴露 ~/.agentlink/ 目录路径(其它模块如 toolsServerLifecycle 也用得到)。
74
+ * 注意:路径在模块加载时基于当时的 os.homedir() 固化。
75
+ * 若需动态跟随 HOME 变化(如测试),请自行用 CLI_STATE_DIR_NAME + os.homedir()。
76
+ */
77
+ export function getAgentlinkDir() {
78
+ return AGENTLINK_DIR;
79
+ }