@xyagent/cli 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +860 -0
- package/bin/agentlink +8585 -0
- package/bin/agentlink-agent +7 -0
- package/bin/agentlink-mcp-stdio +173 -0
- package/docs/LOGGING.md +159 -0
- package/package.json +38 -0
- package/src/core.mjs +320 -0
- package/src/tunnel.mjs +291 -0
- package/src/tunnel_proxy.mjs +913 -0
- package/src/tunnel_service.mjs +699 -0
- package/src/tunnel_state.mjs +301 -0
- package/src/unified_producer.mjs +259 -0
- package/src-ext/README.md +75 -0
- package/src-ext/bin.mjs +128 -0
- package/src-ext/commands/agent.mjs +66 -0
- package/src-ext/commands/help.mjs +31 -0
- package/src-ext/commands/pair.mjs +455 -0
- package/src-ext/commands/reload.mjs +78 -0
- package/src-ext/commands/service.mjs +64 -0
- package/src-ext/core/accountResolver.mjs +137 -0
- package/src-ext/core/activeRuns.mjs +76 -0
- package/src-ext/core/agentlinkToolsBootstrap.mjs +75 -0
- package/src-ext/core/agentlinkToolsRegistry.mjs +323 -0
- package/src-ext/core/agentlinkToolsServer.mjs +109 -0
- package/src-ext/core/approvalGateway.mjs +132 -0
- package/src-ext/core/attachAuditLog.mjs +79 -0
- package/src-ext/core/attachDenylist.mjs +128 -0
- package/src-ext/core/autoTunnelDetector.mjs +98 -0
- package/src-ext/core/autoTunnelGateway.mjs +393 -0
- package/src-ext/core/autoTunnelWiring.mjs +184 -0
- package/src-ext/core/boundedMap.mjs +98 -0
- package/src-ext/core/bridgeAttachAutoScanner.mjs +237 -0
- package/src-ext/core/bridgeHooks.mjs +168 -0
- package/src-ext/core/bridgeSelfUninstall.mjs +133 -0
- package/src-ext/core/claudeTrust.mjs +74 -0
- package/src-ext/core/codexTrust.mjs +77 -0
- package/src-ext/core/cosUploadClient.mjs +326 -0
- package/src-ext/core/createWorkspace.mjs +170 -0
- package/src-ext/core/daemonRestart.mjs +49 -0
- package/src-ext/core/defaultWorkspace.mjs +65 -0
- package/src-ext/core/ensureGitRepo.mjs +57 -0
- package/src-ext/core/hermesProfile.mjs +75 -0
- package/src-ext/core/interruptGateway.mjs +119 -0
- package/src-ext/core/interruptRunListener.mjs +106 -0
- package/src-ext/core/mcpRuntimeFanout.mjs +236 -0
- package/src-ext/core/mcpStdioClient.mjs +316 -0
- package/src-ext/core/openclawGatewayClient.mjs +230 -0
- package/src-ext/core/pairCodeClient.mjs +331 -0
- package/src-ext/core/pairInventory.mjs +59 -0
- package/src-ext/core/pathExpand.mjs +34 -0
- package/src-ext/core/preprocessAttachments.mjs +113 -0
- package/src-ext/core/relayWorker.mjs +284 -0
- package/src-ext/core/relayWorkerHttp.mjs +58 -0
- package/src-ext/core/scanWorkspaces.mjs +842 -0
- package/src-ext/core/sessionSlot.mjs +70 -0
- package/src-ext/core/stateMachine.mjs +85 -0
- package/src-ext/core/toolsServerLifecycle.mjs +169 -0
- package/src-ext/core/unifiedDispatchHandler.mjs +439 -0
- package/src-ext/core/usageReporter.mjs +207 -0
- package/src-ext/openclaw-plugin/envelope-builder.cjs +619 -0
- package/src-ext/openclaw-plugin/index.cjs +1919 -0
- package/src-ext/openclaw-plugin/openclaw.plugin.json +20 -0
- package/src-ext/openclaw-plugin/package.json +12 -0
- package/src-ext/openclaw-plugin/relay-defaults.json +3 -0
- package/src-ext/openclaw-plugin/todoTranslatorUtils.cjs +101 -0
- package/src-ext/runtime/_shared/cliExec.mjs +138 -0
- package/src-ext/runtime/_shared/cosTextRefs.mjs +120 -0
- package/src-ext/runtime/_shared/fetchAndBase64Encode.mjs +52 -0
- package/src-ext/runtime/_shared/relayObjectToBlock.mjs +307 -0
- package/src-ext/runtime/_shared/sessionPicker.mjs +418 -0
- package/src-ext/runtime/_shared/slashCommandRouter.mjs +1346 -0
- package/src-ext/runtime/_shared/todoTranslatorUtils.mjs +94 -0
- package/src-ext/runtime/claude/askUserQuestionTranslator.mjs +241 -0
- package/src-ext/runtime/claude/customCommandsCollector.mjs +132 -0
- package/src-ext/runtime/claude/handleRequest.mjs +1418 -0
- package/src-ext/runtime/claude/index.mjs +160 -0
- package/src-ext/runtime/claude/internalCommandNames.mjs +58 -0
- package/src-ext/runtime/claude/launcher.mjs +313 -0
- package/src-ext/runtime/claude/mcpConfigAdapter.mjs +174 -0
- package/src-ext/runtime/claude/mcpConfigWriter.mjs +57 -0
- package/src-ext/runtime/claude/modelContextWindow.mjs +30 -0
- package/src-ext/runtime/claude/modelScanner.mjs +257 -0
- package/src-ext/runtime/claude/permissionInterruptBlock.mjs +86 -0
- package/src-ext/runtime/claude/permissionPromptServer.mjs +170 -0
- package/src-ext/runtime/claude/permissionPromptServerWorker.mjs +214 -0
- package/src-ext/runtime/claude/preflight.mjs +62 -0
- package/src-ext/runtime/claude/stdoutParser.mjs +365 -0
- package/src-ext/runtime/claude/todoTranslator.mjs +66 -0
- package/src-ext/runtime/claude/usageProbe.mjs +576 -0
- package/src-ext/runtime/claude/usageProbeStrip.mjs +14 -0
- package/src-ext/runtime/codex/codexCustomCommandsCollector.mjs +87 -0
- package/src-ext/runtime/codex/elicitationHandler.mjs +91 -0
- package/src-ext/runtime/codex/eventMapper.mjs +154 -0
- package/src-ext/runtime/codex/handleRequest.mjs +1152 -0
- package/src-ext/runtime/codex/index.mjs +142 -0
- package/src-ext/runtime/codex/mcpConfigAdapter.mjs +155 -0
- package/src-ext/runtime/codex/modelScanner.mjs +305 -0
- package/src-ext/runtime/codex/planNotificationHandler.mjs +61 -0
- package/src-ext/runtime/codex/preflight.mjs +67 -0
- package/src-ext/runtime/hermes/commandBackend.mjs +117 -0
- package/src-ext/runtime/hermes/envSetup.mjs +229 -0
- package/src-ext/runtime/hermes/gatewayManager.mjs +625 -0
- package/src-ext/runtime/hermes/handleRequest.mjs +1257 -0
- package/src-ext/runtime/hermes/httpBackend.mjs +219 -0
- package/src-ext/runtime/hermes/index.mjs +196 -0
- package/src-ext/runtime/hermes/mcpConfigAdapter.mjs +189 -0
- package/src-ext/runtime/hermes/preflight.mjs +359 -0
- package/src-ext/runtime/hermes/responsesBackend.mjs +276 -0
- package/src-ext/runtime/hermes/sessionStore.mjs +78 -0
- package/src-ext/runtime/hermes/todoTranslator.mjs +90 -0
- package/src-ext/runtime/hermes/workspaceRpc.mjs +124 -0
- package/src-ext/runtime/openclaw/buildOpenclawDaemonInput.mjs +143 -0
- package/src-ext/runtime/openclaw/mcpConfigAdapter.mjs +91 -0
- package/src-ext/runtime/openclaw/openclawConfig.mjs +145 -0
- package/src-ext/runtime/picoclaw/constants.mjs +39 -0
- package/src-ext/runtime/picoclaw/handleRequest.mjs +289 -0
- package/src-ext/runtime/picoclaw/index.mjs +314 -0
- package/src-ext/runtime/picoclaw/pairFlow.mjs +224 -0
- package/src-ext/runtime/picoclaw/state.mjs +78 -0
- package/src-ext/runtime/picoclaw/todoTranslator.mjs +67 -0
- package/src-ext/runtime/picoclaw/translator.mjs +272 -0
- package/src-ext/runtime/picoclaw/wsClient.mjs +129 -0
- package/src-ext/service/serviceManager.mjs +521 -0
- package/src-shared/README.md +44 -0
- package/src-shared/chat_push_normalizer.mjs +113 -0
- package/src-shared/correlation.mjs +25 -0
- package/src-shared/envelope_builder.mjs +612 -0
- package/src-shared/logger.mjs +167 -0
- package/src-shared/relay-defaults.json +3 -0
- package/src-shared/relay_revoke.mjs +46 -0
- package/src-shared/vendor/README.md +60 -0
- package/src-shared/vendor/smol-toml/LICENSE +24 -0
- package/src-shared/vendor/smol-toml/README.md +236 -0
- package/src-shared/vendor/smol-toml/VENDORED.md +37 -0
- package/src-shared/vendor/smol-toml/dist/date.d.ts +41 -0
- package/src-shared/vendor/smol-toml/dist/date.js +127 -0
- package/src-shared/vendor/smol-toml/dist/error.d.ts +38 -0
- package/src-shared/vendor/smol-toml/dist/error.js +63 -0
- package/src-shared/vendor/smol-toml/dist/extract.d.ts +30 -0
- package/src-shared/vendor/smol-toml/dist/extract.js +109 -0
- package/src-shared/vendor/smol-toml/dist/index.cjs +900 -0
- package/src-shared/vendor/smol-toml/dist/index.d.ts +43 -0
- package/src-shared/vendor/smol-toml/dist/index.js +33 -0
- package/src-shared/vendor/smol-toml/dist/parse.d.ts +37 -0
- package/src-shared/vendor/smol-toml/dist/parse.js +148 -0
- package/src-shared/vendor/smol-toml/dist/primitive.d.ts +31 -0
- package/src-shared/vendor/smol-toml/dist/primitive.js +178 -0
- package/src-shared/vendor/smol-toml/dist/stringify.d.ts +31 -0
- package/src-shared/vendor/smol-toml/dist/stringify.js +163 -0
- package/src-shared/vendor/smol-toml/dist/struct.d.ts +32 -0
- package/src-shared/vendor/smol-toml/dist/struct.js +194 -0
- package/src-shared/vendor/smol-toml/dist/util.d.ts +42 -0
- package/src-shared/vendor/smol-toml/dist/util.js +100 -0
- package/src-shared/vendor/smol-toml/package.json +54 -0
- package/src-shared/vendor/yaml/LICENSE +13 -0
- package/src-shared/vendor/yaml/README.md +155 -0
- package/src-shared/vendor/yaml/VENDORED.md +29 -0
- package/src-shared/vendor/yaml/bin.mjs +11 -0
- package/src-shared/vendor/yaml/browser/dist/compose/compose-collection.js +88 -0
- package/src-shared/vendor/yaml/browser/dist/compose/compose-doc.js +42 -0
- package/src-shared/vendor/yaml/browser/dist/compose/compose-node.js +92 -0
- package/src-shared/vendor/yaml/browser/dist/compose/compose-scalar.js +80 -0
- package/src-shared/vendor/yaml/browser/dist/compose/composer.js +217 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-block-map.js +113 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-block-scalar.js +198 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-block-seq.js +47 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-end.js +37 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-flow-collection.js +203 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-flow-scalar.js +223 -0
- package/src-shared/vendor/yaml/browser/dist/compose/resolve-props.js +148 -0
- package/src-shared/vendor/yaml/browser/dist/compose/util-contains-newline.js +34 -0
- package/src-shared/vendor/yaml/browser/dist/compose/util-empty-scalar-position.js +27 -0
- package/src-shared/vendor/yaml/browser/dist/compose/util-flow-indent-check.js +15 -0
- package/src-shared/vendor/yaml/browser/dist/compose/util-map-includes.js +17 -0
- package/src-shared/vendor/yaml/browser/dist/doc/Document.js +334 -0
- package/src-shared/vendor/yaml/browser/dist/doc/anchors.js +72 -0
- package/src-shared/vendor/yaml/browser/dist/doc/applyReviver.js +55 -0
- package/src-shared/vendor/yaml/browser/dist/doc/createNode.js +89 -0
- package/src-shared/vendor/yaml/browser/dist/doc/directives.js +176 -0
- package/src-shared/vendor/yaml/browser/dist/errors.js +57 -0
- package/src-shared/vendor/yaml/browser/dist/index.js +17 -0
- package/src-shared/vendor/yaml/browser/dist/log.js +14 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/Alias.js +101 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/Collection.js +147 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/Node.js +38 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/Pair.js +36 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/Scalar.js +24 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/YAMLMap.js +144 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/YAMLSeq.js +113 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/addPairToJSMap.js +104 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/identity.js +36 -0
- package/src-shared/vendor/yaml/browser/dist/nodes/toJS.js +37 -0
- package/src-shared/vendor/yaml/browser/dist/parse/cst-scalar.js +214 -0
- package/src-shared/vendor/yaml/browser/dist/parse/cst-stringify.js +61 -0
- package/src-shared/vendor/yaml/browser/dist/parse/cst-visit.js +97 -0
- package/src-shared/vendor/yaml/browser/dist/parse/cst.js +98 -0
- package/src-shared/vendor/yaml/browser/dist/parse/lexer.js +717 -0
- package/src-shared/vendor/yaml/browser/dist/parse/line-counter.js +39 -0
- package/src-shared/vendor/yaml/browser/dist/parse/parser.js +954 -0
- package/src-shared/vendor/yaml/browser/dist/public-api.js +99 -0
- package/src-shared/vendor/yaml/browser/dist/schema/Schema.js +38 -0
- package/src-shared/vendor/yaml/browser/dist/schema/common/map.js +17 -0
- package/src-shared/vendor/yaml/browser/dist/schema/common/null.js +15 -0
- package/src-shared/vendor/yaml/browser/dist/schema/common/seq.js +17 -0
- package/src-shared/vendor/yaml/browser/dist/schema/common/string.js +14 -0
- package/src-shared/vendor/yaml/browser/dist/schema/core/bool.js +19 -0
- package/src-shared/vendor/yaml/browser/dist/schema/core/float.js +43 -0
- package/src-shared/vendor/yaml/browser/dist/schema/core/int.js +38 -0
- package/src-shared/vendor/yaml/browser/dist/schema/core/schema.js +23 -0
- package/src-shared/vendor/yaml/browser/dist/schema/json/schema.js +62 -0
- package/src-shared/vendor/yaml/browser/dist/schema/tags.js +83 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/binary.js +66 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/bool.js +26 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/float.js +46 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/int.js +71 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/omap.js +74 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/pairs.js +78 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/schema.js +37 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/set.js +93 -0
- package/src-shared/vendor/yaml/browser/dist/schema/yaml-1.1/timestamp.js +101 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/foldFlowLines.js +146 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringify.js +124 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyCollection.js +143 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyComment.js +20 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyDocument.js +85 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyNumber.js +24 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyPair.js +150 -0
- package/src-shared/vendor/yaml/browser/dist/stringify/stringifyString.js +328 -0
- package/src-shared/vendor/yaml/browser/dist/util.js +11 -0
- package/src-shared/vendor/yaml/browser/dist/visit.js +233 -0
- package/src-shared/vendor/yaml/browser/index.js +5 -0
- package/src-shared/vendor/yaml/browser/package.json +3 -0
- package/src-shared/vendor/yaml/dist/cli.d.ts +8 -0
- package/src-shared/vendor/yaml/dist/cli.mjs +199 -0
- package/src-shared/vendor/yaml/dist/compose/compose-collection.d.ts +11 -0
- package/src-shared/vendor/yaml/dist/compose/compose-collection.js +90 -0
- package/src-shared/vendor/yaml/dist/compose/compose-doc.d.ts +7 -0
- package/src-shared/vendor/yaml/dist/compose/compose-doc.js +44 -0
- package/src-shared/vendor/yaml/dist/compose/compose-node.d.ts +28 -0
- package/src-shared/vendor/yaml/dist/compose/compose-node.js +95 -0
- package/src-shared/vendor/yaml/dist/compose/compose-scalar.d.ts +5 -0
- package/src-shared/vendor/yaml/dist/compose/compose-scalar.js +82 -0
- package/src-shared/vendor/yaml/dist/compose/composer.d.ts +62 -0
- package/src-shared/vendor/yaml/dist/compose/composer.js +221 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-map.d.ts +6 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-map.js +115 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-scalar.d.ts +11 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-scalar.js +200 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-seq.d.ts +6 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-block-seq.js +49 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-end.d.ts +6 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-end.js +39 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-flow-collection.d.ts +7 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-flow-collection.js +205 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-flow-scalar.d.ts +10 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-flow-scalar.js +225 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-props.d.ts +23 -0
- package/src-shared/vendor/yaml/dist/compose/resolve-props.js +150 -0
- package/src-shared/vendor/yaml/dist/compose/util-contains-newline.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/compose/util-contains-newline.js +36 -0
- package/src-shared/vendor/yaml/dist/compose/util-empty-scalar-position.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/compose/util-empty-scalar-position.js +29 -0
- package/src-shared/vendor/yaml/dist/compose/util-flow-indent-check.d.ts +3 -0
- package/src-shared/vendor/yaml/dist/compose/util-flow-indent-check.js +17 -0
- package/src-shared/vendor/yaml/dist/compose/util-map-includes.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/compose/util-map-includes.js +19 -0
- package/src-shared/vendor/yaml/dist/doc/Document.d.ts +141 -0
- package/src-shared/vendor/yaml/dist/doc/Document.js +336 -0
- package/src-shared/vendor/yaml/dist/doc/anchors.d.ts +24 -0
- package/src-shared/vendor/yaml/dist/doc/anchors.js +77 -0
- package/src-shared/vendor/yaml/dist/doc/applyReviver.d.ts +9 -0
- package/src-shared/vendor/yaml/dist/doc/applyReviver.js +57 -0
- package/src-shared/vendor/yaml/dist/doc/createNode.d.ts +17 -0
- package/src-shared/vendor/yaml/dist/doc/createNode.js +91 -0
- package/src-shared/vendor/yaml/dist/doc/directives.d.ts +49 -0
- package/src-shared/vendor/yaml/dist/doc/directives.js +178 -0
- package/src-shared/vendor/yaml/dist/errors.d.ts +21 -0
- package/src-shared/vendor/yaml/dist/errors.js +62 -0
- package/src-shared/vendor/yaml/dist/index.d.ts +22 -0
- package/src-shared/vendor/yaml/dist/index.js +50 -0
- package/src-shared/vendor/yaml/dist/log.d.ts +3 -0
- package/src-shared/vendor/yaml/dist/log.js +17 -0
- package/src-shared/vendor/yaml/dist/nodes/Alias.d.ts +28 -0
- package/src-shared/vendor/yaml/dist/nodes/Alias.js +103 -0
- package/src-shared/vendor/yaml/dist/nodes/Collection.d.ts +73 -0
- package/src-shared/vendor/yaml/dist/nodes/Collection.js +151 -0
- package/src-shared/vendor/yaml/dist/nodes/Node.d.ts +47 -0
- package/src-shared/vendor/yaml/dist/nodes/Node.js +40 -0
- package/src-shared/vendor/yaml/dist/nodes/Pair.d.ts +21 -0
- package/src-shared/vendor/yaml/dist/nodes/Pair.js +39 -0
- package/src-shared/vendor/yaml/dist/nodes/Scalar.d.ts +42 -0
- package/src-shared/vendor/yaml/dist/nodes/Scalar.js +27 -0
- package/src-shared/vendor/yaml/dist/nodes/YAMLMap.d.ts +53 -0
- package/src-shared/vendor/yaml/dist/nodes/YAMLMap.js +147 -0
- package/src-shared/vendor/yaml/dist/nodes/YAMLSeq.d.ts +60 -0
- package/src-shared/vendor/yaml/dist/nodes/YAMLSeq.js +115 -0
- package/src-shared/vendor/yaml/dist/nodes/addPairToJSMap.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/nodes/addPairToJSMap.js +106 -0
- package/src-shared/vendor/yaml/dist/nodes/identity.d.ts +23 -0
- package/src-shared/vendor/yaml/dist/nodes/identity.js +53 -0
- package/src-shared/vendor/yaml/dist/nodes/toJS.d.ts +27 -0
- package/src-shared/vendor/yaml/dist/nodes/toJS.js +39 -0
- package/src-shared/vendor/yaml/dist/options.d.ts +338 -0
- package/src-shared/vendor/yaml/dist/parse/cst-scalar.d.ts +64 -0
- package/src-shared/vendor/yaml/dist/parse/cst-scalar.js +218 -0
- package/src-shared/vendor/yaml/dist/parse/cst-stringify.d.ts +8 -0
- package/src-shared/vendor/yaml/dist/parse/cst-stringify.js +63 -0
- package/src-shared/vendor/yaml/dist/parse/cst-visit.d.ts +39 -0
- package/src-shared/vendor/yaml/dist/parse/cst-visit.js +99 -0
- package/src-shared/vendor/yaml/dist/parse/cst.d.ts +108 -0
- package/src-shared/vendor/yaml/dist/parse/cst.js +112 -0
- package/src-shared/vendor/yaml/dist/parse/lexer.d.ts +87 -0
- package/src-shared/vendor/yaml/dist/parse/lexer.js +719 -0
- package/src-shared/vendor/yaml/dist/parse/line-counter.d.ts +22 -0
- package/src-shared/vendor/yaml/dist/parse/line-counter.js +41 -0
- package/src-shared/vendor/yaml/dist/parse/parser.d.ts +84 -0
- package/src-shared/vendor/yaml/dist/parse/parser.js +958 -0
- package/src-shared/vendor/yaml/dist/public-api.d.ts +43 -0
- package/src-shared/vendor/yaml/dist/public-api.js +104 -0
- package/src-shared/vendor/yaml/dist/schema/Schema.d.ts +18 -0
- package/src-shared/vendor/yaml/dist/schema/Schema.js +40 -0
- package/src-shared/vendor/yaml/dist/schema/common/map.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/schema/common/map.js +19 -0
- package/src-shared/vendor/yaml/dist/schema/common/null.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/schema/common/null.js +17 -0
- package/src-shared/vendor/yaml/dist/schema/common/seq.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/schema/common/seq.js +19 -0
- package/src-shared/vendor/yaml/dist/schema/common/string.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/schema/common/string.js +16 -0
- package/src-shared/vendor/yaml/dist/schema/core/bool.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/schema/core/bool.js +21 -0
- package/src-shared/vendor/yaml/dist/schema/core/float.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/schema/core/float.js +47 -0
- package/src-shared/vendor/yaml/dist/schema/core/int.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/schema/core/int.js +42 -0
- package/src-shared/vendor/yaml/dist/schema/core/schema.d.ts +1 -0
- package/src-shared/vendor/yaml/dist/schema/core/schema.js +25 -0
- package/src-shared/vendor/yaml/dist/schema/json/schema.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/schema/json/schema.js +64 -0
- package/src-shared/vendor/yaml/dist/schema/json-schema.d.ts +69 -0
- package/src-shared/vendor/yaml/dist/schema/tags.d.ts +40 -0
- package/src-shared/vendor/yaml/dist/schema/tags.js +86 -0
- package/src-shared/vendor/yaml/dist/schema/types.d.ts +90 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/binary.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/binary.js +68 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/bool.d.ts +7 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/bool.js +29 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/float.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/float.js +50 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/int.d.ts +5 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/int.js +76 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/omap.d.ts +28 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/omap.js +77 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/pairs.d.ts +10 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/pairs.js +82 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/schema.js +39 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/set.d.ts +28 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/set.js +96 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/timestamp.d.ts +6 -0
- package/src-shared/vendor/yaml/dist/schema/yaml-1.1/timestamp.js +105 -0
- package/src-shared/vendor/yaml/dist/stringify/foldFlowLines.d.ts +34 -0
- package/src-shared/vendor/yaml/dist/stringify/foldFlowLines.js +151 -0
- package/src-shared/vendor/yaml/dist/stringify/stringify.d.ts +21 -0
- package/src-shared/vendor/yaml/dist/stringify/stringify.js +127 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyCollection.d.ts +17 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyCollection.js +145 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyComment.d.ts +10 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyComment.js +24 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyDocument.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyDocument.js +87 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyNumber.d.ts +2 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyNumber.js +26 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyPair.d.ts +3 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyPair.js +152 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyString.d.ts +9 -0
- package/src-shared/vendor/yaml/dist/stringify/stringifyString.js +330 -0
- package/src-shared/vendor/yaml/dist/test-events.d.ts +4 -0
- package/src-shared/vendor/yaml/dist/test-events.js +134 -0
- package/src-shared/vendor/yaml/dist/util.d.ts +12 -0
- package/src-shared/vendor/yaml/dist/util.js +28 -0
- package/src-shared/vendor/yaml/dist/visit.d.ts +102 -0
- package/src-shared/vendor/yaml/dist/visit.js +236 -0
- package/src-shared/vendor/yaml/package.json +96 -0
- package/src-shared/vendor/yaml/util.js +2 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// bridge 自卸载工具 —— bridge 主循环检测到对端解绑(HTTP 404/410 on
|
|
2
|
+
// /requests/next)时调用:清本地 pair state + spawn `agentlink uninstall`
|
|
3
|
+
// 把 launchd / systemd-user / schtasks 服务也卸了,然后 bridge 进程 exit(0)。
|
|
4
|
+
//
|
|
5
|
+
// 为什么 spawn 子进程而不是直接调 serviceUninstall:
|
|
6
|
+
// - launchd 自己管理 plist 注销时机;当前进程是 plist 拉起来的,直接调
|
|
7
|
+
// launchctl unload 会让 launchd 立刻 kill 自己进程,cleanup 可能没跑完
|
|
8
|
+
// 就被 SIGTERM。
|
|
9
|
+
// - 子进程拿到 plist 路径独立跑 unload,对父进程无影响;父进程 exit(0) 之后
|
|
10
|
+
// KeepAlive 仍可能拉起一次,那一次会 preflight-fail(pair state 已清,
|
|
11
|
+
// bridge_token 没了)直接退出,10s ThrottleInterval 之后子进程 unload
|
|
12
|
+
// 完成 → 不会再拉起。
|
|
13
|
+
// - --keep-state / --skip-server-revoke 让 uninstall 跳过两个已完成的步骤
|
|
14
|
+
// (state 已清 + 对端已经主动解绑给我们了),只跑 serviceUninstall。
|
|
15
|
+
//
|
|
16
|
+
// findCliBinary:bridge 自身是被 \`agentlink-agent\` 拉起来的,但 process.argv[0]
|
|
17
|
+
// 是 node 路径,argv[1] 是 src/agentlink-agent.js。要找 \`agentlink\` CLI 入口
|
|
18
|
+
// (npm bin 链接),先看 \`which agentlink\`,再 fallback PATH 常见位置。
|
|
19
|
+
|
|
20
|
+
import { execFile, spawn, spawnSync } from "node:child_process";
|
|
21
|
+
import fs from "node:fs";
|
|
22
|
+
import os from "node:os";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
|
|
25
|
+
function findCliBinary() {
|
|
26
|
+
try {
|
|
27
|
+
const r = spawnSync("which", ["agentlink"], { encoding: "utf8", timeout: 2000 });
|
|
28
|
+
if (r.status === 0) {
|
|
29
|
+
const p = String(r.stdout || "").trim().split("\n")[0];
|
|
30
|
+
if (p && fs.existsSync(p)) return p;
|
|
31
|
+
}
|
|
32
|
+
} catch { /* fall through */ }
|
|
33
|
+
// 常见 npm bin
|
|
34
|
+
for (const candidate of [
|
|
35
|
+
path.join(os.homedir(), ".local", "node-22", "bin", "agentlink"),
|
|
36
|
+
"/usr/local/bin/agentlink",
|
|
37
|
+
"/opt/homebrew/bin/agentlink",
|
|
38
|
+
]) {
|
|
39
|
+
try { if (fs.existsSync(candidate)) return candidate; } catch { /* skip */ }
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {{ runtime: string, log: any }} opts
|
|
46
|
+
* runtime: hermes / claude / codex / openclaw / picoclaw
|
|
47
|
+
* log: bridge 自己的 logger(已经带 cid / gw context)
|
|
48
|
+
*
|
|
49
|
+
* 返回 Promise,不抛错 —— 任一步失败都 best-effort,最差也就是用户手动
|
|
50
|
+
* \`agentlink uninstall -r <runtime>\`。
|
|
51
|
+
*/
|
|
52
|
+
export async function bridgeSelfUninstall({ runtime, log } = {}) {
|
|
53
|
+
const slog = log?.child ? log.child({ comp: "self-uninstall" }) : log;
|
|
54
|
+
slog?.info?.("bridge.self_uninstall.start",
|
|
55
|
+
"binding revoked by remote, self-uninstalling", { runtime });
|
|
56
|
+
|
|
57
|
+
// 1. 清本地 pair state(best-effort,import 失败也无所谓)
|
|
58
|
+
try {
|
|
59
|
+
const { clearPairState, clearCursor } = await import("./pairCodeClient.mjs");
|
|
60
|
+
clearPairState(runtime);
|
|
61
|
+
clearCursor(runtime);
|
|
62
|
+
slog?.info?.("bridge.self_uninstall.state_cleared",
|
|
63
|
+
"local pair state cleared", { runtime });
|
|
64
|
+
} catch (err) {
|
|
65
|
+
slog?.warn?.("bridge.self_uninstall.state_err",
|
|
66
|
+
"clear pair state failed (continuing)",
|
|
67
|
+
{ err: err?.message || String(err) });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 2. spawn `agentlink uninstall` 卸 service plist(detached + unref,
|
|
71
|
+
// 我们 exit 之后子进程继续干活)
|
|
72
|
+
const bin = findCliBinary();
|
|
73
|
+
if (!bin) {
|
|
74
|
+
slog?.warn?.("bridge.self_uninstall.no_cli",
|
|
75
|
+
"找不到 agentlink CLI;service plist 需用户手动清理", {});
|
|
76
|
+
return { ok: false, reason: "no-cli" };
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const child = spawn(bin, [
|
|
80
|
+
"uninstall",
|
|
81
|
+
"-r", runtime,
|
|
82
|
+
"--keep-state", // state 我们刚清了,不要重复
|
|
83
|
+
"--skip-server-revoke", // server 那边已经解绑(404 触发的就是它)
|
|
84
|
+
], {
|
|
85
|
+
detached: true,
|
|
86
|
+
stdio: "ignore",
|
|
87
|
+
env: process.env,
|
|
88
|
+
});
|
|
89
|
+
child.unref();
|
|
90
|
+
slog?.info?.("bridge.self_uninstall.spawned",
|
|
91
|
+
"agentlink uninstall spawned (detached)",
|
|
92
|
+
{ runtime, cli: bin, child_pid: child.pid });
|
|
93
|
+
return { ok: true, pid: child.pid };
|
|
94
|
+
} catch (err) {
|
|
95
|
+
slog?.warn?.("bridge.self_uninstall.spawn_err",
|
|
96
|
+
"spawn agentlink uninstall failed (continuing to exit)",
|
|
97
|
+
{ err: err?.message || String(err) });
|
|
98
|
+
return { ok: false, reason: "spawn-fail" };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 包一层 worker.run() —— catch revoked 错误,调 self-uninstall 后 exit(0);
|
|
104
|
+
* 其它错误按原逻辑 exit(1)。
|
|
105
|
+
*
|
|
106
|
+
* 各 runtime 的 bridge entry 现在只需把:
|
|
107
|
+
* try { await worker.run(handleRequest); } catch (err) {
|
|
108
|
+
* log.error("bridge.fatal", ...); process.exit(1);
|
|
109
|
+
* }
|
|
110
|
+
* 替换为:
|
|
111
|
+
* await runWorkerWithRevokeHandling({ worker, handler, runtime, log });
|
|
112
|
+
*/
|
|
113
|
+
export async function runWorkerWithRevokeHandling({
|
|
114
|
+
worker, handler, runtime, log,
|
|
115
|
+
} = {}) {
|
|
116
|
+
try {
|
|
117
|
+
await worker.run(handler);
|
|
118
|
+
// 正常退出 —— worker 主动 stop() 才走这里
|
|
119
|
+
process.exit(0);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
if (err?.revoked === true) {
|
|
122
|
+
await bridgeSelfUninstall({ runtime, log });
|
|
123
|
+
// exit 0 让 launchd KeepAlive 看到 SuccessfulExit;即使再被拉起,
|
|
124
|
+
// 下一轮 bridge 没 bridge_token 会 preflight-fail 退出,unload 完成
|
|
125
|
+
// 之后就不再拉起了。
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
log?.error?.("bridge.fatal", "worker run errored", {
|
|
129
|
+
err: err?.message || String(err),
|
|
130
|
+
});
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* claudeTrust.mjs — 向 ~/.claude.json 写入工作区信任记录
|
|
3
|
+
*
|
|
4
|
+
* writeCaudeTrust(absPath, { _claudeJsonPath? })
|
|
5
|
+
* → Promise<void>
|
|
6
|
+
*
|
|
7
|
+
* 写入 projects[absPath] = { hasTrustDialogAccepted: true }
|
|
8
|
+
* 注意:key 必须是 hasTrustDialogAccepted(scanWorkspaces.mjs:263 检查此 key)
|
|
9
|
+
*
|
|
10
|
+
* 幂等:若已存在则不覆盖。
|
|
11
|
+
* 原子写回:write tmp → rename,避免并发写损坏。
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from "node:fs/promises";
|
|
15
|
+
import os from "node:os";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import { randomBytes } from "node:crypto";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 返回默认 ~/.claude.json 路径
|
|
21
|
+
*/
|
|
22
|
+
function defaultClaudeJsonPath() {
|
|
23
|
+
return path.join(os.homedir(), ".claude.json");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 向 ~/.claude.json 写入信任记录(原子写回)。
|
|
28
|
+
*
|
|
29
|
+
* @param {string} absPath 工作区绝对路径(作为 projects key)
|
|
30
|
+
* @param {{ _claudeJsonPath?: string }} opts 可注入路径(测试用)
|
|
31
|
+
*/
|
|
32
|
+
export async function writeCaudeTrust(absPath, { _claudeJsonPath } = {}) {
|
|
33
|
+
const claudeJsonPath = _claudeJsonPath ?? defaultClaudeJsonPath();
|
|
34
|
+
|
|
35
|
+
// 读取(不存在时用 {})
|
|
36
|
+
let data = {};
|
|
37
|
+
let raw = "";
|
|
38
|
+
try {
|
|
39
|
+
raw = await fs.readFile(claudeJsonPath, "utf8");
|
|
40
|
+
} catch (err) {
|
|
41
|
+
if (err.code !== "ENOENT") throw err;
|
|
42
|
+
// 文件不存在:从空对象开始
|
|
43
|
+
}
|
|
44
|
+
if (raw.trim().length > 0) {
|
|
45
|
+
try {
|
|
46
|
+
data = JSON.parse(raw);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
// JSON 损坏:绝不静默重写整个文件(~/.claude.json 内含 auth/history 等关键数据,
|
|
49
|
+
// 从 {} 重来会把它全抹掉)。抛错让上层感知,由用户/调用方处置。
|
|
50
|
+
const e = new Error(`~/.claude.json parse failed, refusing to overwrite: ${err.message}`);
|
|
51
|
+
e.kind = "parse_failed";
|
|
52
|
+
throw e;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 确保 projects 字段存在
|
|
57
|
+
if (!data.projects || typeof data.projects !== "object") {
|
|
58
|
+
data.projects = {};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 幂等:已存在则不覆盖
|
|
62
|
+
if (data.projects[absPath] !== undefined) return;
|
|
63
|
+
|
|
64
|
+
// 写入信任记录
|
|
65
|
+
data.projects[absPath] = { hasTrustDialogAccepted: true };
|
|
66
|
+
|
|
67
|
+
// 原子写回(write tmp → rename)
|
|
68
|
+
const dir = path.dirname(claudeJsonPath);
|
|
69
|
+
await fs.mkdir(dir, { recursive: true });
|
|
70
|
+
|
|
71
|
+
const tmpPath = claudeJsonPath + ".tmp." + randomBytes(6).toString("hex");
|
|
72
|
+
await fs.writeFile(tmpPath, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
73
|
+
await fs.rename(tmpPath, claudeJsonPath);
|
|
74
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* codexTrust.mjs — 向 ~/.codex/config.toml 写入工作区信任记录
|
|
3
|
+
*
|
|
4
|
+
* writeCodexTrust(absPath, { _configPath? })
|
|
5
|
+
* → Promise<void>
|
|
6
|
+
*
|
|
7
|
+
* 写入 [projects."<absPath>"] trust_level = "trusted"
|
|
8
|
+
* 复用 vendored smol-toml round-trip,与 mcpConfigAdapter.mjs 模式一致。
|
|
9
|
+
*
|
|
10
|
+
* 幂等:trust_level 已存在时不重写。
|
|
11
|
+
* mode 0o600,不销毁其它 section。
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from "node:fs/promises";
|
|
15
|
+
import os from "node:os";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
|
|
19
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const TOML = await import(
|
|
21
|
+
path.join(__dirname, "../../src-shared/vendor/smol-toml/dist/index.js")
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 返回默认 ~/.codex/config.toml 路径
|
|
26
|
+
*/
|
|
27
|
+
function defaultConfigPath() {
|
|
28
|
+
return path.join(os.homedir(), ".codex", "config.toml");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 向 ~/.codex/config.toml 写入工作区信任记录。
|
|
33
|
+
*
|
|
34
|
+
* @param {string} absPath 工作区绝对路径(作为 projects key)
|
|
35
|
+
* @param {{ _configPath?: string }} opts 可注入路径(测试用)
|
|
36
|
+
*/
|
|
37
|
+
export async function writeCodexTrust(absPath, { _configPath } = {}) {
|
|
38
|
+
const configPath = _configPath ?? defaultConfigPath();
|
|
39
|
+
|
|
40
|
+
// 读取(不存在时用空文档)
|
|
41
|
+
let raw = "";
|
|
42
|
+
try {
|
|
43
|
+
raw = await fs.readFile(configPath, "utf8");
|
|
44
|
+
} catch (err) {
|
|
45
|
+
if (err.code !== "ENOENT") throw err;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// TOML parse(空文档 → {})
|
|
49
|
+
let cfg = {};
|
|
50
|
+
if (raw.trim().length > 0) {
|
|
51
|
+
try {
|
|
52
|
+
cfg = TOML.parse(raw);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
const e = new Error(`codex config.toml parse failed: ${err.message}`);
|
|
55
|
+
e.kind = "parse_failed";
|
|
56
|
+
throw e;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 确保 projects 字段存在
|
|
61
|
+
if (!cfg.projects || typeof cfg.projects !== "object") {
|
|
62
|
+
cfg.projects = {};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 幂等:trust_level 已存在且为 "trusted" 则不重写
|
|
66
|
+
if (cfg.projects[absPath]?.trust_level === "trusted") return;
|
|
67
|
+
|
|
68
|
+
// 写入信任记录(merge,不覆盖已有其它字段)
|
|
69
|
+
cfg.projects[absPath] = {
|
|
70
|
+
...(cfg.projects[absPath] ?? {}),
|
|
71
|
+
trust_level: "trusted",
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// 确保 ~/.codex/ 目录存在
|
|
75
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true, mode: 0o700 });
|
|
76
|
+
await fs.writeFile(configPath, TOML.stringify(cfg), { mode: 0o600 });
|
|
77
|
+
}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
// cosUploadClient.mjs — agentlink_attach_file 工具的 COS 直传客户端
|
|
2
|
+
//
|
|
3
|
+
// 三步走,与 relay 的 gateway-scoped /v1/gateways/{gw}/uploads/{sign,commit}
|
|
4
|
+
// 完全对应:
|
|
5
|
+
// 1. POST .../uploads/sign { name, mime, size, sha256 }
|
|
6
|
+
// → { alreadyUploaded: true, cosObjectKey } // dedup
|
|
7
|
+
// → { alreadyUploaded: false, upload: { uploadUrl, headers, ... } }
|
|
8
|
+
// 2. 若 alreadyUploaded=false: PUT uploadUrl with file bytes (用 headers)
|
|
9
|
+
// 3. POST .../uploads/commit { cosObjectKey }
|
|
10
|
+
// → { attachment: { cosObjectKey, ... } }
|
|
11
|
+
//
|
|
12
|
+
// 错误分类(throw 时挂 .kind):
|
|
13
|
+
// kind=sign_failed — sign 端点失败 (4xx/5xx/network)
|
|
14
|
+
// kind=put_failed — PUT COS 失败
|
|
15
|
+
// kind=commit_failed — commit 端点失败
|
|
16
|
+
//
|
|
17
|
+
// caller (tool dispatcher) 根据 .kind 映射到 tool result 的 reason 字段。
|
|
18
|
+
//
|
|
19
|
+
// spec ref: openspec/changes/cos-private-read-refactor/specs/host-file-attach-cos/spec.md
|
|
20
|
+
// openspec/changes/cos-private-read-refactor/specs/relay-gateway-uploads/spec.md
|
|
21
|
+
|
|
22
|
+
const SIGN_PATH = (gw) => `/v1/gateways/${encodeURIComponent(gw)}/uploads/sign`;
|
|
23
|
+
const COMMIT_PATH = (gw) => `/v1/gateways/${encodeURIComponent(gw)}/uploads/commit`;
|
|
24
|
+
const SIGN_GET_PATH = (gw) => `/v1/gateways/${encodeURIComponent(gw)}/uploads/sign-get`;
|
|
25
|
+
|
|
26
|
+
// 扩展名 → mime 映射。与 App 端 _AttachmentPreviewHelper.typeOf 的 ext 集合对齐,
|
|
27
|
+
// 这样 CLI 上传的 mime 跟 App 渲染识别的扩展类型一致,避免渲染歧义。
|
|
28
|
+
// 未知扩展走 application/octet-stream(COS 接受,只是 App 端会渲成 "binary")。
|
|
29
|
+
const EXT_TO_MIME = Object.freeze({
|
|
30
|
+
// text-like
|
|
31
|
+
txt: "text/plain",
|
|
32
|
+
md: "text/markdown",
|
|
33
|
+
markdown: "text/markdown",
|
|
34
|
+
log: "text/plain",
|
|
35
|
+
json: "application/json",
|
|
36
|
+
csv: "text/csv",
|
|
37
|
+
tsv: "text/tab-separated-values",
|
|
38
|
+
yaml: "application/yaml",
|
|
39
|
+
yml: "application/yaml",
|
|
40
|
+
xml: "text/xml",
|
|
41
|
+
html: "text/html",
|
|
42
|
+
htm: "text/html",
|
|
43
|
+
svg: "image/svg+xml",
|
|
44
|
+
// code
|
|
45
|
+
dart: "text/x-dart",
|
|
46
|
+
js: "text/javascript",
|
|
47
|
+
mjs: "text/javascript",
|
|
48
|
+
cjs: "text/javascript",
|
|
49
|
+
ts: "text/typescript",
|
|
50
|
+
tsx: "text/typescript",
|
|
51
|
+
jsx: "text/javascript",
|
|
52
|
+
py: "text/x-python",
|
|
53
|
+
java: "text/x-java",
|
|
54
|
+
kt: "text/x-kotlin",
|
|
55
|
+
swift: "text/x-swift",
|
|
56
|
+
go: "text/x-go",
|
|
57
|
+
rs: "text/x-rust",
|
|
58
|
+
c: "text/x-c",
|
|
59
|
+
h: "text/x-c",
|
|
60
|
+
cpp: "text/x-c++",
|
|
61
|
+
hpp: "text/x-c++",
|
|
62
|
+
// images
|
|
63
|
+
png: "image/png",
|
|
64
|
+
jpg: "image/jpeg",
|
|
65
|
+
jpeg: "image/jpeg",
|
|
66
|
+
gif: "image/gif",
|
|
67
|
+
webp: "image/webp",
|
|
68
|
+
bmp: "image/bmp",
|
|
69
|
+
// documents / archives
|
|
70
|
+
pdf: "application/pdf",
|
|
71
|
+
doc: "application/msword",
|
|
72
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
73
|
+
xls: "application/vnd.ms-excel",
|
|
74
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
75
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
76
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
77
|
+
zip: "application/zip",
|
|
78
|
+
rar: "application/vnd.rar",
|
|
79
|
+
"7z": "application/x-7z-compressed",
|
|
80
|
+
// config
|
|
81
|
+
ini: "text/plain",
|
|
82
|
+
toml: "application/toml",
|
|
83
|
+
// shell
|
|
84
|
+
sh: "text/x-sh",
|
|
85
|
+
bash: "text/x-sh",
|
|
86
|
+
zsh: "text/x-sh",
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 根据文件名推断 mime。caller 可以覆盖(比如 readFileSync 后用 file 命令猜
|
|
91
|
+
* binary 类型)。
|
|
92
|
+
*
|
|
93
|
+
* @param {string} name 文件名(含扩展名)
|
|
94
|
+
* @returns {string} mime;未知扩展返回 "application/octet-stream"
|
|
95
|
+
*/
|
|
96
|
+
export function inferMime(name) {
|
|
97
|
+
const trimmed = (name || "").trim();
|
|
98
|
+
const dotIdx = trimmed.lastIndexOf(".");
|
|
99
|
+
if (dotIdx < 0 || dotIdx === trimmed.length - 1) {
|
|
100
|
+
return "application/octet-stream";
|
|
101
|
+
}
|
|
102
|
+
const ext = trimmed.substring(dotIdx + 1).toLowerCase();
|
|
103
|
+
return EXT_TO_MIME[ext] || "application/octet-stream";
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 抛出带 kind 标记的 Error,方便 caller 用 err.kind 分类。
|
|
108
|
+
*/
|
|
109
|
+
function throwKindedError(kind, message, cause) {
|
|
110
|
+
const err = new Error(message);
|
|
111
|
+
err.kind = kind;
|
|
112
|
+
if (cause !== undefined) err.cause = cause;
|
|
113
|
+
return err;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 三步 sign → conditional PUT → commit,返回最终结果。
|
|
118
|
+
*
|
|
119
|
+
* @param {object} opts
|
|
120
|
+
* @param {string} opts.name 文件名(不含目录)
|
|
121
|
+
* @param {Buffer|Uint8Array} opts.content 文件 bytes
|
|
122
|
+
* @param {string} opts.mime MIME 类型
|
|
123
|
+
* @param {number} opts.size 字节数(应等于 content.length)
|
|
124
|
+
* @param {string} opts.sha256 64-char 小写 hex(caller 已算好)
|
|
125
|
+
* @param {object} opts.relayConfig
|
|
126
|
+
* @param {string} opts.relayConfig.baseUrl relay base URL (e.g. http://localhost:8090)
|
|
127
|
+
* @param {string} opts.relayConfig.gatewayId
|
|
128
|
+
* @param {string} opts.relayConfig.token gateway / client bearer token
|
|
129
|
+
* @param {object} [opts.log] bridge logger,可选;用于 debug 上传细节
|
|
130
|
+
* @returns {Promise<{ cosObjectKey: string, deduped: boolean }>}
|
|
131
|
+
* @throws {Error & { kind: "sign_failed"|"put_failed"|"commit_failed" }}
|
|
132
|
+
*/
|
|
133
|
+
export async function uploadFileToCos(opts) {
|
|
134
|
+
const { name, content, mime, size, sha256, relayConfig, log } = opts;
|
|
135
|
+
const childLog = log?.child?.({ comp: "cos-upload" }) || log || console;
|
|
136
|
+
childLog.info?.("cos-upload.start", "begin upload", {
|
|
137
|
+
name, mime, size, sha256: sha256?.slice(0, 12),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// ── 1. sign ──────────────────────────────────────────────────────
|
|
141
|
+
let signRes;
|
|
142
|
+
try {
|
|
143
|
+
signRes = await postJSON(
|
|
144
|
+
`${relayConfig.baseUrl}${SIGN_PATH(relayConfig.gatewayId)}`,
|
|
145
|
+
{ name, mime, size, sha256 },
|
|
146
|
+
relayConfig.token,
|
|
147
|
+
);
|
|
148
|
+
} catch (err) {
|
|
149
|
+
throw throwKindedError("sign_failed", `sign request failed: ${err.message}`, err);
|
|
150
|
+
}
|
|
151
|
+
if (!signRes.ok) {
|
|
152
|
+
throw throwKindedError(
|
|
153
|
+
"sign_failed",
|
|
154
|
+
`sign HTTP ${signRes.status}: ${signRes.bodyText?.slice(0, 200)}`,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (signRes.json?.alreadyUploaded === true) {
|
|
159
|
+
// dedup 命中:跳过 PUT,直接走 commit 路径(走 commit 是为了拿规范的 attachment
|
|
160
|
+
// shape;relay 端 commit 在 ledger 行不存在时会返回 deduped:true 但仍 200)
|
|
161
|
+
const dedupObjectKey = signRes.json.cosObjectKey || signRes.json.objectKey;
|
|
162
|
+
childLog.info?.("cos-upload.dedup", "sha256 already in COS, skipping PUT", {
|
|
163
|
+
cosObjectKey: dedupObjectKey,
|
|
164
|
+
});
|
|
165
|
+
const commitRes = await commitCall(dedupObjectKey, relayConfig);
|
|
166
|
+
const dedupResult = { cosObjectKey: commitRes.cosObjectKey, deduped: true };
|
|
167
|
+
if (commitRes.originalName !== undefined) dedupResult.originalName = commitRes.originalName;
|
|
168
|
+
return dedupResult;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ── 2. PUT ──────────────────────────────────────────────────────
|
|
172
|
+
const upload = signRes.json?.upload;
|
|
173
|
+
if (!upload?.uploadUrl) {
|
|
174
|
+
throw throwKindedError("sign_failed", "sign response missing upload.uploadUrl");
|
|
175
|
+
}
|
|
176
|
+
let cosHost = "";
|
|
177
|
+
try { cosHost = new URL(upload.uploadUrl).host; } catch { /* swallow */ }
|
|
178
|
+
childLog.info?.("cos-upload.put.start", "PUT to COS", {
|
|
179
|
+
objectKey: upload.objectKey, cosHost, size,
|
|
180
|
+
});
|
|
181
|
+
const t0 = Date.now();
|
|
182
|
+
try {
|
|
183
|
+
const putHeaders = { ...(upload.headers || {}), "Content-Length": String(size) };
|
|
184
|
+
const putRes = await fetch(upload.uploadUrl, {
|
|
185
|
+
method: upload.method || "PUT",
|
|
186
|
+
headers: putHeaders,
|
|
187
|
+
body: content,
|
|
188
|
+
});
|
|
189
|
+
if (!putRes.ok) {
|
|
190
|
+
const body = await safeReadText(putRes);
|
|
191
|
+
throw throwKindedError(
|
|
192
|
+
"put_failed",
|
|
193
|
+
`COS PUT HTTP ${putRes.status}: ${body.slice(0, 200)}`,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
childLog.info?.("cos-upload.put.ok", "PUT succeeded", {
|
|
197
|
+
objectKey: upload.objectKey, status: putRes.status, elapsedMs: Date.now() - t0,
|
|
198
|
+
});
|
|
199
|
+
} catch (err) {
|
|
200
|
+
if (err.kind) throw err;
|
|
201
|
+
throw throwKindedError("put_failed", `COS PUT failed: ${err.message}`, err);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ── 3. commit ───────────────────────────────────────────────────
|
|
205
|
+
const commitObjectKey = upload.cosObjectKey || upload.objectKey;
|
|
206
|
+
const commitRes = await commitCall(commitObjectKey, relayConfig);
|
|
207
|
+
childLog.info?.("cos-upload.done", "commit ok", {
|
|
208
|
+
cosObjectKey: commitRes.cosObjectKey,
|
|
209
|
+
});
|
|
210
|
+
const commitResult = { cosObjectKey: commitRes.cosObjectKey, deduped: false };
|
|
211
|
+
if (commitRes.originalName !== undefined) commitResult.originalName = commitRes.originalName;
|
|
212
|
+
return commitResult;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ── cos-prefix-cache(publicUrl 预测器)已随 publicUrl 字段移除而废弃 ──────────
|
|
216
|
+
// cos-private-read-refactor (D5/D6): 服务端不再返回 publicUrl,改用 sign-get
|
|
217
|
+
// 按需签发临时 GET URL。readCosPrefixCache 保留导出以保持现有调用方不报错,
|
|
218
|
+
// 但始终返回 null;writeCosPrefixCache 已删除。
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* @deprecated publicUrl 已废弃(cos-private-read-refactor)。此函数始终返回 null。
|
|
222
|
+
*/
|
|
223
|
+
export function readCosPrefixCache() {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* 按 cosObjectKey 换取临时 GET URL(presigned)。
|
|
229
|
+
*
|
|
230
|
+
* P0「读取笔记内图片失败」: 消息正文里 agentlink-cos://<cosObjectKey> 引用
|
|
231
|
+
* 需要先换签名 URL 才能下载。失败时 throw kind=sign_get_failed。
|
|
232
|
+
*
|
|
233
|
+
* @param {{ baseUrl: string, gatewayId: string, token: string }} relayConfig
|
|
234
|
+
* @param {string} cosObjectKey
|
|
235
|
+
* @returns {Promise<{ getUrl: string, expiresAt: string|null, cosObjectKey: string }>}
|
|
236
|
+
*/
|
|
237
|
+
export async function signGetCosObject(relayConfig, cosObjectKey) {
|
|
238
|
+
let res;
|
|
239
|
+
try {
|
|
240
|
+
res = await postJSON(
|
|
241
|
+
`${relayConfig.baseUrl}${SIGN_GET_PATH(relayConfig.gatewayId)}`,
|
|
242
|
+
{ cosObjectKey },
|
|
243
|
+
relayConfig.token,
|
|
244
|
+
);
|
|
245
|
+
} catch (err) {
|
|
246
|
+
throw throwKindedError("sign_get_failed", `sign-get request failed: ${err.message}`, err);
|
|
247
|
+
}
|
|
248
|
+
if (!res.ok) {
|
|
249
|
+
throw throwKindedError(
|
|
250
|
+
"sign_get_failed",
|
|
251
|
+
`sign-get HTTP ${res.status}: ${res.bodyText?.slice(0, 200)}`,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
const getUrl = res.json?.getUrl;
|
|
255
|
+
if (!getUrl) {
|
|
256
|
+
throw throwKindedError("sign_get_failed", "sign-get response missing getUrl");
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
getUrl,
|
|
260
|
+
expiresAt: res.json?.expiresAt ?? null,
|
|
261
|
+
cosObjectKey: res.json?.cosObjectKey ?? cosObjectKey,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** commit 调用封装;失败时 throw kind=commit_failed */
|
|
266
|
+
async function commitCall(cosObjectKey, relayConfig) {
|
|
267
|
+
let res;
|
|
268
|
+
try {
|
|
269
|
+
res = await postJSON(
|
|
270
|
+
`${relayConfig.baseUrl}${COMMIT_PATH(relayConfig.gatewayId)}`,
|
|
271
|
+
{ cosObjectKey },
|
|
272
|
+
relayConfig.token,
|
|
273
|
+
);
|
|
274
|
+
} catch (err) {
|
|
275
|
+
throw throwKindedError("commit_failed", `commit request failed: ${err.message}`, err);
|
|
276
|
+
}
|
|
277
|
+
if (!res.ok) {
|
|
278
|
+
throw throwKindedError(
|
|
279
|
+
"commit_failed",
|
|
280
|
+
`commit HTTP ${res.status}: ${res.bodyText?.slice(0, 200)}`,
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
const attachment = res.json?.attachment;
|
|
284
|
+
if (!attachment?.cosObjectKey) {
|
|
285
|
+
throw throwKindedError("commit_failed", "commit response missing attachment.cosObjectKey");
|
|
286
|
+
}
|
|
287
|
+
// originalName:relay 从 app_user_attachments.file_name 读回的原始文件名(未编码),
|
|
288
|
+
// 供调用方传给 relay_object 构造时的 block.name,进而写入 source.name。
|
|
289
|
+
// 旧版 relay 不返回此字段;缺失时不写入返回对象(不写 undefined)。
|
|
290
|
+
const result = { cosObjectKey: attachment.cosObjectKey };
|
|
291
|
+
const originalName = attachment.originalName;
|
|
292
|
+
if (typeof originalName === "string" && originalName.length > 0) {
|
|
293
|
+
result.originalName = originalName;
|
|
294
|
+
}
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** JSON POST 助手。返回 { ok, status, json, bodyText }。 */
|
|
299
|
+
async function postJSON(url, body, bearerToken) {
|
|
300
|
+
const res = await fetch(url, {
|
|
301
|
+
method: "POST",
|
|
302
|
+
headers: {
|
|
303
|
+
"Content-Type": "application/json",
|
|
304
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
305
|
+
},
|
|
306
|
+
body: JSON.stringify(body),
|
|
307
|
+
});
|
|
308
|
+
const bodyText = await safeReadText(res);
|
|
309
|
+
let json = null;
|
|
310
|
+
if (bodyText) {
|
|
311
|
+
try {
|
|
312
|
+
json = JSON.parse(bodyText);
|
|
313
|
+
} catch {
|
|
314
|
+
/* not JSON */
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return { ok: res.ok, status: res.status, json, bodyText };
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async function safeReadText(res) {
|
|
321
|
+
try {
|
|
322
|
+
return await res.text();
|
|
323
|
+
} catch {
|
|
324
|
+
return "";
|
|
325
|
+
}
|
|
326
|
+
}
|