@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,174 @@
|
|
|
1
|
+
// mcpConfigAdapter.mjs — Claude Code 的 MCP server 配置注入器。
|
|
2
|
+
//
|
|
3
|
+
// Claude 读 ~/.claude.json (项目 scope, 在 projectCwd) 或 ~/.claude.json (全
|
|
4
|
+
// 局 fallback)。具体 schema:
|
|
5
|
+
// {
|
|
6
|
+
// "mcpServers": {
|
|
7
|
+
// "<name>": {
|
|
8
|
+
// "type": "stdio",
|
|
9
|
+
// "command": "node",
|
|
10
|
+
// "args": [...]
|
|
11
|
+
// }
|
|
12
|
+
// },
|
|
13
|
+
// ...其它用户 keys
|
|
14
|
+
// }
|
|
15
|
+
//
|
|
16
|
+
// 操作要求(spec.md Claude Code MCP server registration):
|
|
17
|
+
// - idempotent (deep-equal check before write)
|
|
18
|
+
// - non-destructive (其它 mcpServers entry 不动)
|
|
19
|
+
// - versioned (新 args 含 --agentlink-version,version drift 时覆盖)
|
|
20
|
+
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
import os from "node:os";
|
|
23
|
+
import fs from "node:fs/promises";
|
|
24
|
+
import { existsSync } from "node:fs";
|
|
25
|
+
|
|
26
|
+
export const fileExtension = "json";
|
|
27
|
+
|
|
28
|
+
const CONFIG_BASENAME = ".claude.json";
|
|
29
|
+
const SERVER_NAME = "agentlink";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 始终用 user-global `~/.claude.json`。
|
|
33
|
+
*
|
|
34
|
+
* 为什么不用 project-scoped:
|
|
35
|
+
* - Claude Code 默认读 user-global,所有 Claude 项目都能看到 agentlink MCP server
|
|
36
|
+
* - project-scoped 只覆盖该项目目录,用户切到别的项目就看不到 agentlink 工具
|
|
37
|
+
* - 配对一次 = 让 agentlink 在该用户的所有 Claude 项目里都可用,这是正确语义
|
|
38
|
+
* - projectCwd 参数保留向后兼容(忽略不报错),但实际不使用
|
|
39
|
+
*/
|
|
40
|
+
function resolveConfigPath(_projectCwd) {
|
|
41
|
+
return path.join(os.homedir(), CONFIG_BASENAME);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 读原始文件文本。ENOENT 抛 err.code = "ENOENT" 给 caller 决定怎么处理。
|
|
46
|
+
*/
|
|
47
|
+
export async function read({ projectCwd } = {}) {
|
|
48
|
+
const cfgPath = resolveConfigPath(projectCwd);
|
|
49
|
+
return await fs.readFile(cfgPath, "utf8");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* idempotent 注册。args 由 fanout core 提供(含 --discovery + --agentlink-version)。
|
|
54
|
+
*/
|
|
55
|
+
export async function register({ projectCwd, args, log } = {}) {
|
|
56
|
+
const cfgPath = resolveConfigPath(projectCwd);
|
|
57
|
+
const desired = {
|
|
58
|
+
type: "stdio",
|
|
59
|
+
command: "node",
|
|
60
|
+
args: args.slice(),
|
|
61
|
+
};
|
|
62
|
+
const next = await mergeServerEntry(cfgPath, SERVER_NAME, desired);
|
|
63
|
+
if (!next.changed) {
|
|
64
|
+
return { changed: false, configPath: cfgPath, mode: "noop_idempotent" };
|
|
65
|
+
}
|
|
66
|
+
await fs.writeFile(cfgPath, JSON.stringify(next.config, null, 2) + "\n", { mode: 0o600 });
|
|
67
|
+
log?.info?.("mcp.fanout.claude.write", "wrote agentlink mcp entry", {
|
|
68
|
+
configPath: cfgPath,
|
|
69
|
+
});
|
|
70
|
+
return { changed: true, configPath: cfgPath };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function deregister({ projectCwd, log } = {}) {
|
|
74
|
+
const cfgPath = resolveConfigPath(projectCwd);
|
|
75
|
+
let raw;
|
|
76
|
+
try {
|
|
77
|
+
raw = await fs.readFile(cfgPath, "utf8");
|
|
78
|
+
} catch (err) {
|
|
79
|
+
if (err.code === "ENOENT") {
|
|
80
|
+
return { changed: false, configPath: cfgPath, mode: "noop_no_config" };
|
|
81
|
+
}
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
const cfg = safeParse(raw);
|
|
85
|
+
if (!cfg || !cfg.mcpServers || !(SERVER_NAME in cfg.mcpServers)) {
|
|
86
|
+
return { changed: false, configPath: cfgPath, mode: "noop_not_registered" };
|
|
87
|
+
}
|
|
88
|
+
delete cfg.mcpServers[SERVER_NAME];
|
|
89
|
+
await fs.writeFile(cfgPath, JSON.stringify(cfg, null, 2) + "\n", { mode: 0o600 });
|
|
90
|
+
log?.info?.("mcp.fanout.claude.delete", "removed agentlink mcp entry", {
|
|
91
|
+
configPath: cfgPath,
|
|
92
|
+
});
|
|
93
|
+
return { changed: true, configPath: cfgPath };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function status({ projectCwd } = {}) {
|
|
97
|
+
const cfgPath = resolveConfigPath(projectCwd);
|
|
98
|
+
let raw;
|
|
99
|
+
try {
|
|
100
|
+
raw = await fs.readFile(cfgPath, "utf8");
|
|
101
|
+
} catch (err) {
|
|
102
|
+
if (err.code === "ENOENT") {
|
|
103
|
+
return { installed: true, registered: false, configPath: cfgPath, reason: "no_config_file" };
|
|
104
|
+
}
|
|
105
|
+
return { installed: false, registered: false, error: err?.message };
|
|
106
|
+
}
|
|
107
|
+
const cfg = safeParse(raw);
|
|
108
|
+
const entry = cfg?.mcpServers?.[SERVER_NAME];
|
|
109
|
+
if (!entry) {
|
|
110
|
+
return { installed: true, registered: false, configPath: cfgPath };
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
installed: true,
|
|
114
|
+
registered: true,
|
|
115
|
+
configPath: cfgPath,
|
|
116
|
+
version: extractAgentlinkVersion(entry?.args),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 合并:读 cfg, 检查 mcpServers.agentlink 跟 desired 是否相等;不等就替换。
|
|
122
|
+
* 返回 { config, changed }。caller 决定写不写。
|
|
123
|
+
*/
|
|
124
|
+
async function mergeServerEntry(cfgPath, name, desired) {
|
|
125
|
+
let raw = "{}";
|
|
126
|
+
try {
|
|
127
|
+
raw = await fs.readFile(cfgPath, "utf8");
|
|
128
|
+
} catch (err) {
|
|
129
|
+
if (err.code !== "ENOENT") throw err;
|
|
130
|
+
}
|
|
131
|
+
const cfg = safeParse(raw) || {};
|
|
132
|
+
if (!cfg.mcpServers || typeof cfg.mcpServers !== "object") {
|
|
133
|
+
cfg.mcpServers = {};
|
|
134
|
+
}
|
|
135
|
+
const current = cfg.mcpServers[name];
|
|
136
|
+
if (deepEqual(current, desired)) {
|
|
137
|
+
return { config: cfg, changed: false };
|
|
138
|
+
}
|
|
139
|
+
cfg.mcpServers[name] = desired;
|
|
140
|
+
return { config: cfg, changed: true };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function safeParse(raw) {
|
|
144
|
+
try { return JSON.parse(raw); }
|
|
145
|
+
catch { return null; }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function deepEqual(a, b) {
|
|
149
|
+
if (a === b) return true;
|
|
150
|
+
if (typeof a !== typeof b) return false;
|
|
151
|
+
if (a === null || b === null) return false;
|
|
152
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
153
|
+
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
154
|
+
}
|
|
155
|
+
if (typeof a === "object" && typeof b === "object") {
|
|
156
|
+
const ak = Object.keys(a).sort();
|
|
157
|
+
const bk = Object.keys(b).sort();
|
|
158
|
+
if (ak.length !== bk.length) return false;
|
|
159
|
+
for (let i = 0; i < ak.length; i++) {
|
|
160
|
+
if (ak[i] !== bk[i]) return false;
|
|
161
|
+
if (!deepEqual(a[ak[i]], b[ak[i]])) return false;
|
|
162
|
+
}
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** 从 args 数组里挖 --agentlink-version 之后那个值,用于 fanout 漂移检测。 */
|
|
169
|
+
function extractAgentlinkVersion(args) {
|
|
170
|
+
if (!Array.isArray(args)) return null;
|
|
171
|
+
const idx = args.indexOf("--agentlink-version");
|
|
172
|
+
if (idx >= 0 && idx + 1 < args.length) return args[idx + 1];
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpConfigWriter.mjs — 任务 2.1 / 2.2
|
|
3
|
+
*
|
|
4
|
+
* 向 os.tmpdir() 写入临时 MCP config 文件,供 claude --mcp-config 使用。
|
|
5
|
+
*
|
|
6
|
+
* 文件名:agentlink-mcp-<runId>.json
|
|
7
|
+
* 内容:{ "mcpServers": { "agentlink-permission": { "type": "stdio", "command": "node", "args": [scriptPath] } } }
|
|
8
|
+
*
|
|
9
|
+
* 设计:写入 tmpdir(跨平台),不写项目目录,避免 claude 扫描项目结构。
|
|
10
|
+
* run 结束(finally 块)调用 deleteMcpConfig 清理。
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import fs from "node:fs/promises";
|
|
14
|
+
import { existsSync } from "node:fs";
|
|
15
|
+
import os from "node:os";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 写入临时 MCP config 文件。
|
|
20
|
+
*
|
|
21
|
+
* @param {{ runId: string, serverScriptPath: string }} opts
|
|
22
|
+
* @returns {Promise<string>} 写入的文件绝对路径
|
|
23
|
+
*/
|
|
24
|
+
export async function writeMcpConfig({ runId, serverScriptPath }) {
|
|
25
|
+
const fileName = `agentlink-mcp-${runId}.json`;
|
|
26
|
+
const filePath = path.join(os.tmpdir(), fileName);
|
|
27
|
+
|
|
28
|
+
const config = {
|
|
29
|
+
mcpServers: {
|
|
30
|
+
"agentlink-permission": {
|
|
31
|
+
type: "stdio",
|
|
32
|
+
command: "node",
|
|
33
|
+
args: [serverScriptPath],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
await fs.writeFile(filePath, JSON.stringify(config, null, 2), { encoding: "utf8" });
|
|
39
|
+
return filePath;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 删除临时 MCP config 文件。
|
|
44
|
+
* 文件不存在时静默忽略(ENOENT)。
|
|
45
|
+
*
|
|
46
|
+
* @param {string} filePath writeMcpConfig 返回的路径
|
|
47
|
+
* @returns {Promise<void>}
|
|
48
|
+
*/
|
|
49
|
+
export async function deleteMcpConfig(filePath) {
|
|
50
|
+
if (!filePath) return;
|
|
51
|
+
try {
|
|
52
|
+
await fs.unlink(filePath);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
if (err?.code !== "ENOENT") throw err;
|
|
55
|
+
// ENOENT: 文件已不存在,静默忽略
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// 按 claude 模型 ID 查对应上下文窗口大小(tokens)。
|
|
2
|
+
//
|
|
3
|
+
// 数据来源:Anthropic 官方文档 + claude-code /model 输出。
|
|
4
|
+
// 策略:
|
|
5
|
+
// - 精确前缀匹配优先(opus / sonnet / haiku 各家族)
|
|
6
|
+
// - 不认识的模型回退到 200k(Claude 家族当前统一默认)
|
|
7
|
+
// - 特殊:`-1m` / `-1m-beta` 后缀标识 1M 扩展上下文
|
|
8
|
+
//
|
|
9
|
+
// 注意这里不包含 Claude 2.x / 3.x 早期模型 —— claude-code v2.1+ 只用 Claude 4.x 起。
|
|
10
|
+
|
|
11
|
+
const FAMILY_WINDOWS = [
|
|
12
|
+
// 1M 扩展上下文(Sonnet 4.5 某些入口支持)
|
|
13
|
+
{ pattern: /-1m(?:-beta)?$/i, window: 1_000_000 },
|
|
14
|
+
// 标准 200k 上下文(所有 4.x 家族)
|
|
15
|
+
{ pattern: /^claude-(opus|sonnet|haiku)-/i, window: 200_000 },
|
|
16
|
+
// 用户友好别名(claude-code /model 切换时的短名)
|
|
17
|
+
{ pattern: /^(opus|sonnet|haiku|default|opusplan)$/i, window: 200_000 },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {string|null|undefined} model
|
|
22
|
+
* @returns {number} tokens;未知模型回退 200000(Claude 系列通用)
|
|
23
|
+
*/
|
|
24
|
+
export function pickContextWindow(model) {
|
|
25
|
+
if (typeof model !== "string" || !model) return 200_000;
|
|
26
|
+
for (const { pattern, window } of FAMILY_WINDOWS) {
|
|
27
|
+
if (pattern.test(model)) return window;
|
|
28
|
+
}
|
|
29
|
+
return 200_000;
|
|
30
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// Claude 模型列表扫描器。
|
|
2
|
+
//
|
|
3
|
+
// 背景:claude-code CLI 不提供 "list models" 子命令;`/model` 是交互式 REPL
|
|
4
|
+
// 的斜杠命令(在 --print + stream-json 模式下会被当成 unknown skill)。PTY
|
|
5
|
+
// 抓 picker 代价大(~3s 冷启动 + node-pty 原生依赖 + ANSI 解析),而且 picker
|
|
6
|
+
// 展示的就是家族别名(Default/Opus/Haiku 三项),数据量和扫二进制拿到的
|
|
7
|
+
// 家族信息完全重叠。
|
|
8
|
+
//
|
|
9
|
+
// 所以策略:扫二进制提取所有 `claude-<family>-<version>` 模型 id,按家族
|
|
10
|
+
// 分组 → 每个家族输出一个 alias 项(id = 家族名)。alias id 直接对应 CLI
|
|
11
|
+
// 里 `--model sonnet` / `--model opus` 等稳定形式。hint 附上扫到的最新
|
|
12
|
+
// 版本号,跟着二进制升级自动更新。
|
|
13
|
+
//
|
|
14
|
+
// 完全动态:家族名、版本号都从二进制扫出;未来 claude-code 加新家族(如
|
|
15
|
+
// "ultra"),扫描器无需改代码就会发现并展示。
|
|
16
|
+
//
|
|
17
|
+
// 跨平台:PE32 (Windows) / ELF (Linux) / Mach-O (macOS) 二进制里 ASCII 字符
|
|
18
|
+
// 串常量都是明文存放的,latin1 逐字节扫描正则匹配与格式无关。PATH 分隔符
|
|
19
|
+
// 与可执行文件扩展名按 process.platform 分流。
|
|
20
|
+
//
|
|
21
|
+
// 实现要点:
|
|
22
|
+
// - 流式扫描(chunk + overlap),避免几百 MB 二进制一次性读爆内存
|
|
23
|
+
// - 结果进程内缓存,key = realpath(bin) + mtime,二进制升级自动失效
|
|
24
|
+
|
|
25
|
+
import { promises as fs } from "node:fs";
|
|
26
|
+
import os from "node:os";
|
|
27
|
+
import path from "node:path";
|
|
28
|
+
import process from "node:process";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 扫描目标正则:claude-<family>-<version-segments>。
|
|
32
|
+
* family 用 `[a-z]+` 宽松匹配(不写死 opus/sonnet/haiku),未来新家族自动纳入。
|
|
33
|
+
* 版本段用 `[\d-]+` 宽松匹配,解析时再识别末段的 8 位日期。
|
|
34
|
+
*/
|
|
35
|
+
const MODEL_ID_RE = /\bclaude-([a-z]+)-([\d-]+)(?=\D|$)/g;
|
|
36
|
+
|
|
37
|
+
const cache = new Map(); // key -> { at, result }
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 返回 { models: [ ... ], default: "<alias>" | null }。扫不到 models 返回空列表。
|
|
41
|
+
* default 取自 `~/.claude/settings.json` 的 model 字段(已归一化为家族 alias)。
|
|
42
|
+
*/
|
|
43
|
+
export async function listClaudeModels() {
|
|
44
|
+
const bin = await resolveClaudeBinary();
|
|
45
|
+
const settingsPath = path.join(os.homedir(), ".claude", "settings.json");
|
|
46
|
+
const binStat = bin ? await safeStat(bin) : null;
|
|
47
|
+
const settingsStat = await safeStat(settingsPath);
|
|
48
|
+
const cacheKey = `${bin || ""}:${binStat?.mtimeMs ?? 0}:${settingsStat?.mtimeMs ?? 0}`;
|
|
49
|
+
const hit = cache.get(cacheKey);
|
|
50
|
+
if (hit) return hit.result;
|
|
51
|
+
|
|
52
|
+
let versions;
|
|
53
|
+
if (!bin) {
|
|
54
|
+
versions = new Set();
|
|
55
|
+
} else {
|
|
56
|
+
try {
|
|
57
|
+
versions = await scanBinaryForModelIds(bin);
|
|
58
|
+
} catch {
|
|
59
|
+
versions = new Set();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const models = composeModels(versions);
|
|
64
|
+
const defaultAlias = await readClaudeDefault(settingsPath);
|
|
65
|
+
const result = { models, default: defaultAlias };
|
|
66
|
+
cache.set(cacheKey, { at: Date.now(), result });
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 从 ~/.claude/settings.json 读 model 字段并归一化为家族 alias。
|
|
71
|
+
// - "sonnet" / "opus" / "haiku" / "default" / "opusplan" → 原样返回
|
|
72
|
+
// - "claude-sonnet-4-6" → 提取家族 "sonnet"
|
|
73
|
+
// - 没有 / 解析失败 → null
|
|
74
|
+
async function readClaudeDefault(settingsPath) {
|
|
75
|
+
try {
|
|
76
|
+
const raw = await fs.readFile(settingsPath, "utf8");
|
|
77
|
+
const obj = JSON.parse(raw);
|
|
78
|
+
const m = typeof obj?.model === "string" ? obj.model.trim() : "";
|
|
79
|
+
if (!m) return null;
|
|
80
|
+
// full id: claude-<family>-... → 取 family
|
|
81
|
+
const full = m.match(/^claude-([a-z]+)-/);
|
|
82
|
+
if (full) return full[1];
|
|
83
|
+
return m;
|
|
84
|
+
} catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ── Pipeline ──────────────────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
function composeModels(versionStrings) {
|
|
92
|
+
const byFamily = new Map(); // family -> [parsed]
|
|
93
|
+
for (const id of versionStrings) {
|
|
94
|
+
const v = parseId(id);
|
|
95
|
+
if (!v) continue;
|
|
96
|
+
if (!byFamily.has(v.family)) byFamily.set(v.family, []);
|
|
97
|
+
byFamily.get(v.family).push(v);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const families = [];
|
|
101
|
+
for (const [family, list] of byFamily) {
|
|
102
|
+
// 过滤:家族里至少要存在一个"当代"版本(3 <= major < 1000)才保留。
|
|
103
|
+
// 这会干掉两类噪音:
|
|
104
|
+
// - claude-instant-1 (Claude 1 遗留,CLI 已不支持)
|
|
105
|
+
// - claude-code-20250219 (产品 slug 被误匹配,major=20250219)
|
|
106
|
+
const hasCurrentVersion = list.some((v) => v.major >= 3 && v.major < 1000);
|
|
107
|
+
if (!hasCurrentVersion) continue;
|
|
108
|
+
|
|
109
|
+
list.sort(compareVersionDesc);
|
|
110
|
+
const latest = list[0];
|
|
111
|
+
families.push({ family, latest });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 家族展示顺序:按 latest 版本号降序(越新的家族越靠前)
|
|
115
|
+
families.sort((a, b) => compareVersionDesc(a.latest, b.latest));
|
|
116
|
+
|
|
117
|
+
return families.map(({ family, latest }) => ({
|
|
118
|
+
// alias id 发给 CLI:claude 的 `--model sonnet` / `--model opus` 等家族形式
|
|
119
|
+
id: family,
|
|
120
|
+
// label 是"具体版本"(如 `Opus 4.6` / `Haiku 4.5 · 2025-10-01`),扫出的
|
|
121
|
+
// latest 带日期时一并展示。菜单外的"模型"按钮也会拿到这个 label。
|
|
122
|
+
label: buildVersionLabel(latest),
|
|
123
|
+
// hint 是家族定位描述。claude-code 二进制里没有这份元信息 —— 对已知家族
|
|
124
|
+
// 给一份稳定的本地化描述;未知家族(未来 Anthropic 新家族)返回空。
|
|
125
|
+
hint: familyDescription(family),
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function familyDescription(family) {
|
|
130
|
+
switch (family) {
|
|
131
|
+
case "opus": return "最强 · 复杂推理 / 架构";
|
|
132
|
+
case "sonnet": return "均衡 · 日常编码";
|
|
133
|
+
case "haiku": return "最快 · 轻量任务";
|
|
134
|
+
default: return "";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function parseId(id) {
|
|
139
|
+
const m = id.match(/^claude-([a-z]+)-([\d-]+)$/);
|
|
140
|
+
if (!m) return null;
|
|
141
|
+
const parts = m[2].split("-").filter(Boolean);
|
|
142
|
+
if (parts.length === 0) return null;
|
|
143
|
+
|
|
144
|
+
let date = null;
|
|
145
|
+
if (parts.length > 1 && /^\d{8}$/.test(parts[parts.length - 1])) {
|
|
146
|
+
date = parts.pop();
|
|
147
|
+
}
|
|
148
|
+
const major = Number(parts[0]);
|
|
149
|
+
if (!Number.isFinite(major)) return null;
|
|
150
|
+
const minor = parts.length > 1 ? Number(parts[1]) : null;
|
|
151
|
+
if (minor != null && !Number.isFinite(minor)) return null;
|
|
152
|
+
|
|
153
|
+
return { id, family: m[1], major, minor, date };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function compareVersionDesc(a, b) {
|
|
157
|
+
if (a.major !== b.major) return b.major - a.major;
|
|
158
|
+
const am = a.minor ?? -1;
|
|
159
|
+
const bm = b.minor ?? -1;
|
|
160
|
+
if (am !== bm) return bm - am;
|
|
161
|
+
const ad = a.date || "00000000";
|
|
162
|
+
const bd = b.date || "00000000";
|
|
163
|
+
return bd.localeCompare(ad);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function buildVersionLabel(v) {
|
|
167
|
+
const ver = v.minor != null ? `${v.major}.${v.minor}` : `${v.major}`;
|
|
168
|
+
const famName = capitalize(v.family);
|
|
169
|
+
if (v.date) {
|
|
170
|
+
return `${famName} ${ver} · ${formatDate(v.date)}`;
|
|
171
|
+
}
|
|
172
|
+
return `${famName} ${ver}`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function capitalize(s) {
|
|
176
|
+
return s ? s[0].toUpperCase() + s.slice(1) : s;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function formatDate(yyyymmdd) {
|
|
180
|
+
return `${yyyymmdd.slice(0, 4)}-${yyyymmdd.slice(4, 6)}-${yyyymmdd.slice(6, 8)}`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ── Binary scanning ───────────────────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
async function scanBinaryForModelIds(binPath) {
|
|
186
|
+
const CHUNK = 1 << 20; // 1MB
|
|
187
|
+
const OVERLAP = 64; // 模型 id 最长 ~30 字节,64 字节 overlap 足够
|
|
188
|
+
const fd = await fs.open(binPath, "r");
|
|
189
|
+
try {
|
|
190
|
+
const buf = Buffer.alloc(CHUNK);
|
|
191
|
+
const found = new Set();
|
|
192
|
+
let position = 0;
|
|
193
|
+
let carry = "";
|
|
194
|
+
while (true) {
|
|
195
|
+
const { bytesRead } = await fd.read(buf, 0, CHUNK, position);
|
|
196
|
+
if (bytesRead === 0) break;
|
|
197
|
+
const hay = carry + buf.slice(0, bytesRead).toString("latin1");
|
|
198
|
+
MODEL_ID_RE.lastIndex = 0;
|
|
199
|
+
for (const m of hay.matchAll(MODEL_ID_RE)) {
|
|
200
|
+
// 完整 id:claude-<family>-<version>
|
|
201
|
+
found.add(m[0]);
|
|
202
|
+
}
|
|
203
|
+
carry = hay.slice(-OVERLAP);
|
|
204
|
+
position += bytesRead;
|
|
205
|
+
}
|
|
206
|
+
return found;
|
|
207
|
+
} finally {
|
|
208
|
+
await fd.close();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ── Binary resolution ─────────────────────────────────────────────────────
|
|
213
|
+
//
|
|
214
|
+
// 跨平台:
|
|
215
|
+
// - macOS / Linux:PATH 里找 `claude`(symlink 跟随 realpath)
|
|
216
|
+
// - Windows:PATH 里找 `claude.exe`(也可能是 `.cmd`/`.bat` wrapper —— 我们
|
|
217
|
+
// 需要真正的二进制,所以也尝试 `.exe`/`.cmd`/`.bat` 的 realpath 并过滤文件
|
|
218
|
+
|
|
219
|
+
async function resolveClaudeBinary() {
|
|
220
|
+
const pathDirs = splitPath(process.env.PATH || "");
|
|
221
|
+
const candidates = binaryCandidateNames();
|
|
222
|
+
for (const dir of pathDirs) {
|
|
223
|
+
for (const name of candidates) {
|
|
224
|
+
const candidate = path.join(dir, name);
|
|
225
|
+
const real = await safeRealpath(candidate);
|
|
226
|
+
if (!real) continue;
|
|
227
|
+
const st = await safeStat(real);
|
|
228
|
+
if (!st || !st.isFile()) continue;
|
|
229
|
+
// 过滤 wrapper 脚本(太小,比如 <100KB 的 shell/batch wrapper)
|
|
230
|
+
// 真实 claude 二进制 ~190MB,阈值留 1MB 即可区分
|
|
231
|
+
if (st.size < 1024 * 1024) continue;
|
|
232
|
+
return real;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function splitPath(raw) {
|
|
239
|
+
const sep = process.platform === "win32" ? ";" : ":";
|
|
240
|
+
return raw.split(sep).filter(Boolean);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function binaryCandidateNames() {
|
|
244
|
+
if (process.platform === "win32") {
|
|
245
|
+
// Windows:优先 .exe;.cmd/.bat 是 wrapper,走它们的 realpath 也可能指到真正 .exe
|
|
246
|
+
return ["claude.exe", "claude.cmd", "claude.bat", "claude"];
|
|
247
|
+
}
|
|
248
|
+
return ["claude"];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function safeStat(p) {
|
|
252
|
+
try { return await fs.stat(p); } catch { return null; }
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async function safeRealpath(p) {
|
|
256
|
+
try { return await fs.realpath(p); } catch { return null; }
|
|
257
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* permissionInterruptBlock.mjs — 任务 3.1
|
|
3
|
+
*
|
|
4
|
+
* 构造符合协议的 interrupt block(approval subtype)。
|
|
5
|
+
* CLI 端直接构造,bypass relay mapApprovalRequest,与 Codex elicitation 同构。
|
|
6
|
+
*
|
|
7
|
+
* Wire Format 见 design.md § Wire Format。
|
|
8
|
+
* v1:不含 scope_options。
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const DANGER_RE = /bash|shell|exec|delete|remove|rm|write|create|overwrite|truncate|drop/i;
|
|
12
|
+
const SUMMARY_MAX = 120;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 判断工具是否"危险"(需 severity=warning,approve is_destructive=true)。
|
|
16
|
+
* 与 relay mapper 保持一致规则。
|
|
17
|
+
* @param {string} toolName
|
|
18
|
+
*/
|
|
19
|
+
function isDangerous(toolName) {
|
|
20
|
+
return DANGER_RE.test(toolName);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 生成命令摘要(最多 120 字符,超出加 …)。
|
|
25
|
+
* @param {string} toolName
|
|
26
|
+
* @param {object} toolInput
|
|
27
|
+
*/
|
|
28
|
+
function commandSummary(toolName, toolInput) {
|
|
29
|
+
let raw;
|
|
30
|
+
if (/^bash$/i.test(toolName)) {
|
|
31
|
+
raw = typeof toolInput?.command === "string" ? toolInput.command : JSON.stringify(toolInput);
|
|
32
|
+
} else {
|
|
33
|
+
raw = typeof toolInput?.description === "string"
|
|
34
|
+
? toolInput.description
|
|
35
|
+
: JSON.stringify(toolInput);
|
|
36
|
+
}
|
|
37
|
+
if (raw.length > SUMMARY_MAX) {
|
|
38
|
+
return raw.slice(0, SUMMARY_MAX) + "…";
|
|
39
|
+
}
|
|
40
|
+
return raw;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 构造 interrupt approval block。
|
|
45
|
+
*
|
|
46
|
+
* @param {{
|
|
47
|
+
* toolName: string,
|
|
48
|
+
* toolInput: object,
|
|
49
|
+
* blockId: string,
|
|
50
|
+
* runId: string,
|
|
51
|
+
* expiresAt?: string, // ISO8601(测试注入用);默认 now + 10min
|
|
52
|
+
* }} opts
|
|
53
|
+
* @returns {object} interrupt block(符合协议)
|
|
54
|
+
*/
|
|
55
|
+
export function buildPermissionInterruptBlock({ toolName, toolInput, blockId, runId, expiresAt }) {
|
|
56
|
+
const dangerous = isDangerous(toolName);
|
|
57
|
+
const summary = commandSummary(toolName, toolInput || {});
|
|
58
|
+
const resolvedExpiresAt = expiresAt || new Date(Date.now() + 10 * 60_000).toISOString();
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
type: "interrupt",
|
|
62
|
+
subtype: "approval",
|
|
63
|
+
status: "awaiting",
|
|
64
|
+
id: blockId,
|
|
65
|
+
title: toolName,
|
|
66
|
+
prompt: `${toolName}: ${summary}`,
|
|
67
|
+
severity: dangerous ? "warning" : "info",
|
|
68
|
+
on_timeout: "reject",
|
|
69
|
+
options: [
|
|
70
|
+
{
|
|
71
|
+
id: "approve",
|
|
72
|
+
label: "同意",
|
|
73
|
+
is_default: true,
|
|
74
|
+
is_destructive: dangerous,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "reject",
|
|
78
|
+
label: "拒绝",
|
|
79
|
+
is_default: false,
|
|
80
|
+
is_destructive: false,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
expires_at: resolvedExpiresAt,
|
|
84
|
+
// v1:不含 scope_options
|
|
85
|
+
};
|
|
86
|
+
}
|