@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,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createWorkspace.mjs — workspaces.create RPC 核心实现
|
|
3
|
+
*
|
|
4
|
+
* createWorkspace({ runtime, name }, deps?)
|
|
5
|
+
* → Promise<{ ok: true, workspacePath: string, created: boolean }
|
|
6
|
+
* | { ok: false, code: string, error: string }>
|
|
7
|
+
*
|
|
8
|
+
* 支持的 runtime:claude | codex | openclaw | hermes
|
|
9
|
+
*
|
|
10
|
+
* 路径计算:
|
|
11
|
+
* - claude/codex/openclaw:<workspacesRoot()>/<runtime>/<name>
|
|
12
|
+
* - hermes:~/.hermes/profiles/<name>
|
|
13
|
+
*
|
|
14
|
+
* 后置操作(按 runtime):
|
|
15
|
+
* - claude:writeCaudeTrust → ~/.claude.json
|
|
16
|
+
* - codex:writeCaudeTrust + writeCodexTrust → ~/.codex/config.toml
|
|
17
|
+
* - openclaw:openclaw --version 探测 + openclaw agents add
|
|
18
|
+
* - hermes:createHermesProfile(含 root .env 复制)
|
|
19
|
+
*
|
|
20
|
+
* deps 注入接口(测试用):
|
|
21
|
+
* _workspacesRoot: string 覆盖 workspacesRoot() 返回值
|
|
22
|
+
* _hermesRoot: string 覆盖 ~/.hermes 路径
|
|
23
|
+
* _claudeJsonPath: string 覆盖 ~/.claude.json 路径
|
|
24
|
+
* _codexConfigPath: string 覆盖 ~/.codex/config.toml 路径
|
|
25
|
+
* _execFile: Function 覆盖 execFile 调用(测试 openclaw)
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import fs from "node:fs/promises";
|
|
29
|
+
import { existsSync } from "node:fs";
|
|
30
|
+
import { execFile as nodeExecFile } from "node:child_process";
|
|
31
|
+
import { promisify } from "node:util";
|
|
32
|
+
import os from "node:os";
|
|
33
|
+
import path from "node:path";
|
|
34
|
+
|
|
35
|
+
import { workspacesRoot } from "./defaultWorkspace.mjs";
|
|
36
|
+
import { writeCaudeTrust } from "./claudeTrust.mjs";
|
|
37
|
+
import { writeCodexTrust } from "./codexTrust.mjs";
|
|
38
|
+
import { ensureGitRepo } from "./ensureGitRepo.mjs";
|
|
39
|
+
import { createHermesProfile } from "./hermesProfile.mjs";
|
|
40
|
+
|
|
41
|
+
const execFileAsync = promisify(nodeExecFile);
|
|
42
|
+
|
|
43
|
+
/** slug 通用校验正则(1-64 位,首字符字母数字,其余可含 _ -) */
|
|
44
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,62}([a-z0-9])?$/;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 使用可注入的 _execFile 运行命令,返回 { stdout, stderr }。
|
|
48
|
+
* 失败时 throw,携带 exitCode / stderr / stdout。
|
|
49
|
+
*/
|
|
50
|
+
async function runCmd(cmd, args, _execFile) {
|
|
51
|
+
const exec = _execFile ?? execFileAsync;
|
|
52
|
+
try {
|
|
53
|
+
const result = await exec(cmd, args);
|
|
54
|
+
// promisify(execFile) 返回 { stdout, stderr }
|
|
55
|
+
return { stdout: String(result?.stdout ?? ""), stderr: String(result?.stderr ?? "") };
|
|
56
|
+
} catch (err) {
|
|
57
|
+
// 注入版或 execFile 失败:携带 exitCode / stderr / stdout
|
|
58
|
+
const wrapped = new Error(err?.message ?? String(err));
|
|
59
|
+
wrapped.code = err?.code;
|
|
60
|
+
wrapped.exitCode = err?.code === "ENOENT" ? null : (err?.exitCode ?? (err?.status ?? null));
|
|
61
|
+
wrapped.stderr = String(err?.stderr ?? "");
|
|
62
|
+
wrapped.stdout = String(err?.stdout ?? "");
|
|
63
|
+
throw wrapped;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 探测 openclaw 是否安装
|
|
69
|
+
*/
|
|
70
|
+
async function probeOpenclaw(_execFile) {
|
|
71
|
+
try {
|
|
72
|
+
await runCmd("openclaw", ["--version"], _execFile);
|
|
73
|
+
return true;
|
|
74
|
+
} catch (err) {
|
|
75
|
+
if (err.code === "ENOENT" || /not found|ENOENT/i.test(err.message)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
// --version 以非零退出但能运行(极少见),视为已安装
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 创建工作区。
|
|
85
|
+
*
|
|
86
|
+
* @param {{ runtime: string, name: string }} params
|
|
87
|
+
* @param {{
|
|
88
|
+
* _workspacesRoot?: string,
|
|
89
|
+
* _hermesRoot?: string,
|
|
90
|
+
* _claudeJsonPath?: string,
|
|
91
|
+
* _codexConfigPath?: string,
|
|
92
|
+
* _execFile?: Function,
|
|
93
|
+
* }} deps 测试依赖注入
|
|
94
|
+
*/
|
|
95
|
+
export async function createWorkspace({ runtime, name }, deps = {}) {
|
|
96
|
+
const {
|
|
97
|
+
_workspacesRoot,
|
|
98
|
+
_hermesRoot,
|
|
99
|
+
_claudeJsonPath,
|
|
100
|
+
_codexConfigPath,
|
|
101
|
+
_execFile,
|
|
102
|
+
} = deps;
|
|
103
|
+
|
|
104
|
+
// hermes 走独立路径(profile 语义不同)
|
|
105
|
+
if (runtime === "hermes") {
|
|
106
|
+
return createWorkspace_hermes(name, { _hermesRoot });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ── 通用 slug 校验 ──────────────────────────────────────────────────────
|
|
110
|
+
if (!name || !SLUG_RE.test(name)) {
|
|
111
|
+
return { ok: false, code: "name_invalid", error: `invalid workspace name: "${name}"` };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// openclaw 需要先探测安装(探测失败则不建目录)
|
|
115
|
+
if (runtime === "openclaw") {
|
|
116
|
+
const installed = await probeOpenclaw(_execFile);
|
|
117
|
+
if (!installed) {
|
|
118
|
+
return { ok: false, code: "openclaw_not_installed", error: "openclaw not found in PATH" };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ── 路径计算 ────────────────────────────────────────────────────────────
|
|
123
|
+
const root = _workspacesRoot ?? workspacesRoot();
|
|
124
|
+
const workspacePath = path.join(root, runtime, name);
|
|
125
|
+
|
|
126
|
+
// ── 幂等检查 ────────────────────────────────────────────────────────────
|
|
127
|
+
const alreadyExists = existsSync(workspacePath);
|
|
128
|
+
|
|
129
|
+
// ── mkdir -p ────────────────────────────────────────────────────────────
|
|
130
|
+
await fs.mkdir(workspacePath, { recursive: true, mode: 0o700 });
|
|
131
|
+
|
|
132
|
+
// ── 后置操作 ────────────────────────────────────────────────────────────
|
|
133
|
+
if (runtime === "claude") {
|
|
134
|
+
await writeCaudeTrust(workspacePath, { _claudeJsonPath });
|
|
135
|
+
} else if (runtime === "codex") {
|
|
136
|
+
// codex 只认 ~/.codex/config.toml,绝不写 ~/.claude.json(否则 codex 工作区
|
|
137
|
+
// 会错误地出现在 claude 的扫描结果里——两者扫描源完全独立)
|
|
138
|
+
await writeCodexTrust(workspacePath, { _configPath: _codexConfigPath });
|
|
139
|
+
// codex 靠「目录是否 git 仓库」决定可写(workspace-write),trust_level 只管
|
|
140
|
+
// 加载 .codex 层、不给写权限。非 git 工作区 codex 会退回 read-only → 无法执行。
|
|
141
|
+
// best-effort:ensureGitRepo 自身吞错,git 缺失也不影响目录创建。
|
|
142
|
+
await ensureGitRepo(workspacePath, { _execFile });
|
|
143
|
+
} else if (runtime === "openclaw") {
|
|
144
|
+
// openclaw agents add <name> --workspace <absPath>
|
|
145
|
+
try {
|
|
146
|
+
await runCmd("openclaw", ["agents", "add", name, "--workspace", workspacePath], _execFile);
|
|
147
|
+
return { ok: true, workspacePath, created: true };
|
|
148
|
+
} catch (err) {
|
|
149
|
+
const combinedOutput = (err.stderr + " " + err.stdout).toLowerCase();
|
|
150
|
+
if (combinedOutput.includes("already")) {
|
|
151
|
+
// 幂等成功
|
|
152
|
+
return { ok: true, workspacePath, created: false };
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
ok: false,
|
|
156
|
+
code: "openclaw_register_failed",
|
|
157
|
+
error: err.stderr || err.message,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { ok: true, workspacePath, created: !alreadyExists };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* hermes runtime 创建 profile(独立路径)
|
|
167
|
+
*/
|
|
168
|
+
async function createWorkspace_hermes(name, { _hermesRoot } = {}) {
|
|
169
|
+
return createHermesProfile(name, { _hermesRoot });
|
|
170
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* daemonRestart.mjs — AgentLink daemon 热重启辅助
|
|
3
|
+
*
|
|
4
|
+
* kickstartDaemons() 在 macOS 上通过 launchctl kickstart -k
|
|
5
|
+
* 热重启已注册的 agentlink claude 和 codex daemon。
|
|
6
|
+
*
|
|
7
|
+
* 典型调用场景:
|
|
8
|
+
* - make cli-link / cli-link-local(新代码链接后自动生效)
|
|
9
|
+
* - npm_cli postinstall
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { execSync as _nodeExecSync } from "node:child_process";
|
|
13
|
+
|
|
14
|
+
// launchd service labels
|
|
15
|
+
const DAEMON_LABELS = [
|
|
16
|
+
"com.agentlink.agent.claude",
|
|
17
|
+
"com.agentlink.agent.codex",
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 热重启 AgentLink daemon(仅 macOS)。
|
|
22
|
+
*
|
|
23
|
+
* @param {{
|
|
24
|
+
* _platform?: string, // 测试注入,默认 process.platform
|
|
25
|
+
* _execSync?: Function, // 测试注入,默认 node:child_process execSync
|
|
26
|
+
* _log?: { warn: Function, info: Function }, // 测试注入,默认 console
|
|
27
|
+
* }} opts
|
|
28
|
+
*/
|
|
29
|
+
export async function kickstartDaemons({
|
|
30
|
+
_platform = process.platform,
|
|
31
|
+
_execSync = _nodeExecSync,
|
|
32
|
+
_log = console,
|
|
33
|
+
} = {}) {
|
|
34
|
+
if (_platform !== "darwin") return;
|
|
35
|
+
|
|
36
|
+
// 优先用 process.getuid()(Node.js 内置,不需要 spawn 子进程)
|
|
37
|
+
const uid = String(process.getuid?.() ?? "");
|
|
38
|
+
|
|
39
|
+
for (const label of DAEMON_LABELS) {
|
|
40
|
+
const target = `gui/${uid}/${label}`;
|
|
41
|
+
const cmd = `launchctl kickstart -k "${target}"`;
|
|
42
|
+
try {
|
|
43
|
+
_execSync(cmd, { encoding: "utf8", stdio: "pipe" });
|
|
44
|
+
_log.info?.(`[daemonRestart] kickstarted ${label}`);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
_log.warn(`[daemonRestart] warn: could not kickstart ${label}: ${err?.message ?? err}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* defaultWorkspace.mjs — claude/codex 默认工作区路径管理
|
|
3
|
+
*
|
|
4
|
+
* 提供三个函数:
|
|
5
|
+
* workspacesRoot() — 工作区根目录(~/agentlink),供 default + 用户新建工作区共用
|
|
6
|
+
* defaultWorkspacePath(runtime) — 纯路径计算,不建目录(供 scan 合成 entry 用)
|
|
7
|
+
* ensureDefaultWorkspace(runtime) — mkdir -p 后返回路径(pair 时 eager 创建 + dispatch 懒建)
|
|
8
|
+
*
|
|
9
|
+
* 路径结构:<workspacesRoot()>/<runtime>/default
|
|
10
|
+
* 例如 ~/agentlink/claude/default
|
|
11
|
+
* ~/agentlink/codex/default
|
|
12
|
+
*
|
|
13
|
+
* 注意:工作区根 ~/agentlink(非隐藏、用户可见的项目目录)刻意与 CLI 状态目录
|
|
14
|
+
* ~/.agentlink(隐藏,放审计日志 / 凭证 / sessions)分开——前者是 agent 实际读写
|
|
15
|
+
* 代码的项目根,后者是工具自身状态,二者不能混在一起(参 openclaw 官方同款建议:
|
|
16
|
+
* workspace 要与 ~/.openclaw 分离)。用户新建工作区走 <workspacesRoot()>/<runtime>/<name>。
|
|
17
|
+
*
|
|
18
|
+
* 改名 agentlink 时只需改 workspacesRoot() 的返回值(统一来源)。
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import fs from "node:fs/promises";
|
|
22
|
+
import os from "node:os";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
|
|
25
|
+
import { ensureGitRepo } from "./ensureGitRepo.mjs";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 返回工作区根目录的绝对路径(~/agentlink),不建目录。
|
|
29
|
+
* default 与用户新建工作区都挂在它下面:<root>/<runtime>/<name>。
|
|
30
|
+
*
|
|
31
|
+
* @returns {string} 绝对路径
|
|
32
|
+
*/
|
|
33
|
+
export function workspacesRoot() {
|
|
34
|
+
return path.join(os.homedir(), "agentlink");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 返回 <runtime> 对应默认工作区的绝对路径,不建目录。
|
|
39
|
+
*
|
|
40
|
+
* @param {string} runtime "claude" | "codex"
|
|
41
|
+
* @returns {string} 绝对路径
|
|
42
|
+
*/
|
|
43
|
+
export function defaultWorkspacePath(runtime) {
|
|
44
|
+
return path.join(workspacesRoot(), runtime, "default");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 确保 <runtime> 默认工作区目录存在(mkdir -p),返回绝对路径。
|
|
49
|
+
* 幂等:目录已存在时不报错。
|
|
50
|
+
*
|
|
51
|
+
* codex 默认工作区还会 git init(与新建工作区同口径)——codex 靠「目录是否 git
|
|
52
|
+
* 仓库」决定 workspace-write,非 git 会退回 read-only。best-effort,不阻断。
|
|
53
|
+
*
|
|
54
|
+
* @param {string} runtime "claude" | "codex"
|
|
55
|
+
* @param {{ _execFile?: Function }} [opts] 测试注入
|
|
56
|
+
* @returns {Promise<string>} 绝对路径
|
|
57
|
+
*/
|
|
58
|
+
export async function ensureDefaultWorkspace(runtime, { _execFile } = {}) {
|
|
59
|
+
const p = defaultWorkspacePath(runtime);
|
|
60
|
+
await fs.mkdir(p, { recursive: true, mode: 0o700 });
|
|
61
|
+
if (runtime === "codex") {
|
|
62
|
+
await ensureGitRepo(p, { _execFile });
|
|
63
|
+
}
|
|
64
|
+
return p;
|
|
65
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ensureGitRepo.mjs — 把工作区初始化为 git 仓库(codex 可写的前提)
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要:codex 用「目录是否受版本控制(git)」来决定 sandbox——
|
|
5
|
+
* - git 仓库 → workspace-write(agent 可在工作区内读写)
|
|
6
|
+
* - 非 git 目录 → read-only(exec 模式甚至直接拒跑:
|
|
7
|
+
* "Not inside a trusted directory and --skip-git-repo-check was not specified.")
|
|
8
|
+
* 这一点经 codex 官方文档(config-reference / agent-approvals:"Version-controlled
|
|
9
|
+
* folders: Auto (workspace write + on-request approvals)")+ 本地实测双重确认。
|
|
10
|
+
*
|
|
11
|
+
* 注意:`~/.codex/config.toml` 的 `[projects."<path>"] trust_level="trusted"` **不是**
|
|
12
|
+
* 写权限开关——官方原文:trust_level 只决定是否加载项目级 `.codex/` 层(config /
|
|
13
|
+
* hooks / rules)。所以 writeCodexTrust 解决不了「只读」,必须 git init。
|
|
14
|
+
*
|
|
15
|
+
* 幂等 + best-effort:已是仓库(自身或父级 work tree)跳过;git 缺失/失败不抛,
|
|
16
|
+
* 只返回 ok:false(工作区仍可用,codex 退回 read-only)。
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { execFile as nodeExecFile } from "node:child_process";
|
|
20
|
+
import { promisify } from "node:util";
|
|
21
|
+
import { existsSync } from "node:fs";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
|
|
24
|
+
const execFileAsync = promisify(nodeExecFile);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 确保 dir 是一个 git 仓库。
|
|
28
|
+
*
|
|
29
|
+
* @param {string} dir 工作区绝对路径
|
|
30
|
+
* @param {{ _execFile?: Function }} [opts] 测试注入
|
|
31
|
+
* @returns {Promise<{ ok: boolean, created: boolean, reason?: string }>}
|
|
32
|
+
*/
|
|
33
|
+
export async function ensureGitRepo(dir, { _execFile } = {}) {
|
|
34
|
+
const exec = _execFile ?? execFileAsync;
|
|
35
|
+
|
|
36
|
+
// 快路径:自身已是仓库根 → 跳过,不 spawn git。
|
|
37
|
+
// (ensureDefaultWorkspace 每次 dispatch 都会调,这条短路避免每轮起 git 进程。)
|
|
38
|
+
if (existsSync(path.join(dir, ".git"))) {
|
|
39
|
+
return { ok: true, created: false };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 已落在某个父级 work tree 内(如 ~/agentlink 本身被 git 管理)→ 也算受版本控制,
|
|
43
|
+
// 不再嵌套 init。
|
|
44
|
+
try {
|
|
45
|
+
await exec("git", ["-C", dir, "rev-parse", "--is-inside-work-tree"]);
|
|
46
|
+
return { ok: true, created: false };
|
|
47
|
+
} catch {
|
|
48
|
+
// 不在任何 work tree 内 → 初始化
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
await exec("git", ["init", "-q", dir]);
|
|
53
|
+
return { ok: true, created: true };
|
|
54
|
+
} catch (err) {
|
|
55
|
+
return { ok: false, created: false, reason: err?.message || String(err) };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hermesProfile.mjs — 初始化 hermes profile 目录并继承 root 凭证
|
|
3
|
+
*
|
|
4
|
+
* createHermesProfile(name, { _hermesRoot? })
|
|
5
|
+
* → Promise<{ ok: true, workspacePath: string, created: boolean }
|
|
6
|
+
* | { ok: false, code: string, error: string }>
|
|
7
|
+
*
|
|
8
|
+
* 流程:
|
|
9
|
+
* 1. name 校验(/^[a-z0-9][a-z0-9_-]{0,63}$/)
|
|
10
|
+
* 2. 校验 root ~/.hermes/.env 存在(不存在 → hermes_root_credentials_missing)
|
|
11
|
+
* 3. mkdir ~/.hermes/profiles/<name>(mode 0o700,递归)
|
|
12
|
+
* 4. 若 profile .env 不存在,复制 root .env(幂等:已存在不覆盖)
|
|
13
|
+
* 5. 返回 { ok: true, workspacePath, created }
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import fs from "node:fs/promises";
|
|
17
|
+
import { existsSync } from "node:fs";
|
|
18
|
+
import os from "node:os";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
|
|
21
|
+
/** hermes profile name 合法正则(与 hermes-profile-isolation spec 一致) */
|
|
22
|
+
const HERMES_NAME_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 返回默认 ~/.hermes 根目录
|
|
26
|
+
*/
|
|
27
|
+
function defaultHermesRoot() {
|
|
28
|
+
return path.join(os.homedir(), ".hermes");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 初始化 hermes profile 目录并继承 root 凭证。
|
|
33
|
+
*
|
|
34
|
+
* @param {string} name profile 名(slug)
|
|
35
|
+
* @param {{ _hermesRoot?: string }} opts 可注入路径(测试用)
|
|
36
|
+
* @returns {Promise<{ ok: boolean, workspacePath?: string, created?: boolean, code?: string, error?: string }>}
|
|
37
|
+
*/
|
|
38
|
+
export async function createHermesProfile(name, { _hermesRoot } = {}) {
|
|
39
|
+
const hermesRoot = _hermesRoot ?? defaultHermesRoot();
|
|
40
|
+
|
|
41
|
+
// 1. name 校验
|
|
42
|
+
if (!HERMES_NAME_RE.test(name)) {
|
|
43
|
+
return { ok: false, code: "name_invalid", error: `invalid hermes profile name: "${name}"` };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const rootEnvPath = path.join(hermesRoot, ".env");
|
|
47
|
+
const profileDir = path.join(hermesRoot, "profiles", name);
|
|
48
|
+
const profileEnvPath = path.join(profileDir, ".env");
|
|
49
|
+
|
|
50
|
+
// 2. 校验 root .env 存在
|
|
51
|
+
if (!existsSync(rootEnvPath)) {
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
code: "hermes_root_credentials_missing",
|
|
55
|
+
error: `root ~/.hermes/.env not found at ${rootEnvPath}`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 3. 检查 profile 是否已存在(幂等判断)
|
|
60
|
+
const alreadyExists = existsSync(profileDir);
|
|
61
|
+
|
|
62
|
+
// 4. mkdir(幂等,已存在不报错)
|
|
63
|
+
await fs.mkdir(profileDir, { recursive: true, mode: 0o700 });
|
|
64
|
+
|
|
65
|
+
// 5. 复制 .env(幂等:profile .env 已存在不覆盖)
|
|
66
|
+
if (!existsSync(profileEnvPath)) {
|
|
67
|
+
await fs.copyFile(rootEnvPath, profileEnvPath);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
ok: true,
|
|
72
|
+
workspacePath: profileDir,
|
|
73
|
+
created: !alreadyExists,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* interruptGateway.mjs — HITL interrupt 阻塞闸门
|
|
3
|
+
*
|
|
4
|
+
* 语义与 approvalGateway 对齐(openRequest / settle / dispose),
|
|
5
|
+
* 但接的是 unified interrupt + resume 端点,而非私有 tool_approval 协议。
|
|
6
|
+
*
|
|
7
|
+
* 工作流:
|
|
8
|
+
* 1. handleRequest 发出 interrupt block + run.paused
|
|
9
|
+
* 2. 调用 openRequest({ runId, blockId, interruptId }) 挂起等待
|
|
10
|
+
* 3. SSE 消费层收到 run.resumed → 调用 settle(interruptId, value)
|
|
11
|
+
* 4. promise resolve,handleRequest 继续发 content_block.completed + run.completed
|
|
12
|
+
* 5. dispose() 在连接关闭 / run cancel 时 reject 所有 pending
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {{ log: { info?, warn?, error?, child? } }} opts
|
|
17
|
+
* @returns {{ openRequest, settle, dispose }}
|
|
18
|
+
*/
|
|
19
|
+
// audit 修复:用户断网/进程异常导致 settle 永不到达时,interrupt 此前永久
|
|
20
|
+
// 悬挂。默认 30 分钟硬超时(/resume picker 用户可能离开较久,给宽裕窗口;
|
|
21
|
+
// relay 侧 decision key TTL 24h,超时后用户再决策由 relay 兜底为无主决策丢弃)。
|
|
22
|
+
const DEFAULT_INTERRUPT_TIMEOUT_MS = 30 * 60_000;
|
|
23
|
+
|
|
24
|
+
export function createInterruptGateway({ log, timeoutMs = DEFAULT_INTERRUPT_TIMEOUT_MS }) {
|
|
25
|
+
if (!log) throw new Error("createInterruptGateway: log required");
|
|
26
|
+
const gwLog = log.child ? log.child({ comp: "interrupt" }) : log;
|
|
27
|
+
|
|
28
|
+
// interruptId → { resolve, reject, runId, blockId, openedAt }
|
|
29
|
+
const pending = new Map();
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 开启一个 interrupt 等待。
|
|
33
|
+
* @param {{ runId: string, blockId: string, interruptId: string }} params
|
|
34
|
+
* @returns {{ promise: Promise<any> }}
|
|
35
|
+
*/
|
|
36
|
+
function openRequest({ runId, blockId, interruptId }) {
|
|
37
|
+
if (pending.has(interruptId)) {
|
|
38
|
+
throw new Error(`duplicate interruptId: ${interruptId}`);
|
|
39
|
+
}
|
|
40
|
+
let resolveFn, rejectFn;
|
|
41
|
+
const promise = new Promise((resolve, reject) => {
|
|
42
|
+
resolveFn = resolve;
|
|
43
|
+
rejectFn = reject;
|
|
44
|
+
});
|
|
45
|
+
let timeoutHandle = null;
|
|
46
|
+
if (timeoutMs > 0) {
|
|
47
|
+
timeoutHandle = setTimeout(() => {
|
|
48
|
+
const e = pending.get(interruptId);
|
|
49
|
+
if (!e) return;
|
|
50
|
+
pending.delete(interruptId);
|
|
51
|
+
gwLog.warn?.("interrupt.timeout", "interrupt wait timed out, rejecting", {
|
|
52
|
+
interrupt_id: interruptId, run_id: runId, timeout_ms: timeoutMs,
|
|
53
|
+
});
|
|
54
|
+
e.reject(new Error("interrupt timeout"));
|
|
55
|
+
}, timeoutMs);
|
|
56
|
+
timeoutHandle.unref?.();
|
|
57
|
+
}
|
|
58
|
+
pending.set(interruptId, {
|
|
59
|
+
resolve: resolveFn,
|
|
60
|
+
reject: rejectFn,
|
|
61
|
+
runId,
|
|
62
|
+
blockId,
|
|
63
|
+
openedAt: Date.now(),
|
|
64
|
+
timeoutHandle,
|
|
65
|
+
});
|
|
66
|
+
gwLog.info?.("interrupt.request.opened", "interrupt request opened", {
|
|
67
|
+
interrupt_id: interruptId,
|
|
68
|
+
run_id: runId,
|
|
69
|
+
block_id: blockId,
|
|
70
|
+
});
|
|
71
|
+
return { promise };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 以 value resolve 对应 interruptId 的 promise(来自 run.resumed 事件)。
|
|
76
|
+
* 未知 interruptId 时 warn 并静默忽略。
|
|
77
|
+
* @param {string} interruptId
|
|
78
|
+
* @param {any} value run.resumed extensions.agent.value
|
|
79
|
+
*/
|
|
80
|
+
function settle(interruptId, value) {
|
|
81
|
+
const entry = pending.get(interruptId);
|
|
82
|
+
if (!entry) {
|
|
83
|
+
gwLog.warn?.("interrupt.settle.unknown", "settle called for unknown interruptId", {
|
|
84
|
+
interrupt_id: interruptId,
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
pending.delete(interruptId);
|
|
89
|
+
if (entry.timeoutHandle) clearTimeout(entry.timeoutHandle);
|
|
90
|
+
const waitMs = Date.now() - entry.openedAt;
|
|
91
|
+
gwLog.info?.("interrupt.settled", "interrupt resolved by user decision", {
|
|
92
|
+
interrupt_id: interruptId,
|
|
93
|
+
run_id: entry.runId,
|
|
94
|
+
wait_ms: waitMs,
|
|
95
|
+
});
|
|
96
|
+
entry.resolve(value);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* reject 所有 pending promise,message = "interrupt_gateway_disposed"。
|
|
101
|
+
* 在连接关闭 / 进程销毁时调用。
|
|
102
|
+
*/
|
|
103
|
+
function dispose() {
|
|
104
|
+
const ids = [...pending.keys()];
|
|
105
|
+
for (const id of ids) {
|
|
106
|
+
const entry = pending.get(id);
|
|
107
|
+
if (!entry) continue;
|
|
108
|
+
pending.delete(id);
|
|
109
|
+
if (entry.timeoutHandle) clearTimeout(entry.timeoutHandle);
|
|
110
|
+
gwLog.warn?.("interrupt.dispose", "rejecting pending interrupt on dispose", {
|
|
111
|
+
interrupt_id: id,
|
|
112
|
+
run_id: entry.runId,
|
|
113
|
+
});
|
|
114
|
+
entry.reject(new Error("interrupt_gateway_disposed"));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return { openRequest, settle, dispose };
|
|
119
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* interruptRunListener.mjs — 等待 relay 的 run.resumed 事件
|
|
3
|
+
*
|
|
4
|
+
* 订阅 GET /v1/agents/threads/{tid}/stream(bridge token),
|
|
5
|
+
* 解析 SSE 帧,在看到 run.resumed 且 interrupt_id 匹配时 resolve。
|
|
6
|
+
*
|
|
7
|
+
* 用于 interrupt picker 分支:bridge 发出 run.paused 后用它等待用户决策。
|
|
8
|
+
*
|
|
9
|
+
* @param {{
|
|
10
|
+
* relayUrl: string,
|
|
11
|
+
* bridgeToken: string,
|
|
12
|
+
* threadId: string,
|
|
13
|
+
* runId: string,
|
|
14
|
+
* interruptId: string,
|
|
15
|
+
* timeoutMs?: number, // 默认 24h(TTL 与 relay decision key 对齐)
|
|
16
|
+
* signal?: AbortSignal,
|
|
17
|
+
* log?: any,
|
|
18
|
+
* }} opts
|
|
19
|
+
* @returns {Promise<{ value: any }>} resolves with user decision value
|
|
20
|
+
*/
|
|
21
|
+
export async function waitForRunResumed({
|
|
22
|
+
relayUrl,
|
|
23
|
+
bridgeToken,
|
|
24
|
+
threadId,
|
|
25
|
+
runId,
|
|
26
|
+
interruptId,
|
|
27
|
+
timeoutMs = 24 * 60 * 60 * 1000,
|
|
28
|
+
signal: outerSignal,
|
|
29
|
+
log,
|
|
30
|
+
}) {
|
|
31
|
+
const base = String(relayUrl || "").replace(/\/+$/, "");
|
|
32
|
+
const url = `${base}/v1/agents/threads/${encodeURIComponent(threadId)}/stream`;
|
|
33
|
+
const headers = {
|
|
34
|
+
"Authorization": `Bearer ${bridgeToken}`,
|
|
35
|
+
"Accept": "text/event-stream",
|
|
36
|
+
"Cache-Control": "no-cache",
|
|
37
|
+
// Bridge token scoped: relay will not apply caps_filter for interrupt events
|
|
38
|
+
"X-Agent-Bridge-Token": bridgeToken,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const ctrl = new AbortController();
|
|
42
|
+
// Compose outer signal
|
|
43
|
+
if (outerSignal) {
|
|
44
|
+
outerSignal.addEventListener("abort", () => ctrl.abort(), { once: true });
|
|
45
|
+
}
|
|
46
|
+
// Auto-timeout
|
|
47
|
+
const timeoutHandle = setTimeout(() => {
|
|
48
|
+
ctrl.abort();
|
|
49
|
+
log?.warn?.("interrupt.listener.timeout", "run.resumed wait timed out", {
|
|
50
|
+
run_id: runId,
|
|
51
|
+
interrupt_id: interruptId,
|
|
52
|
+
timeout_ms: timeoutMs,
|
|
53
|
+
});
|
|
54
|
+
}, timeoutMs);
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
const res = await fetch(url, { headers, signal: ctrl.signal });
|
|
58
|
+
if (!res.ok) {
|
|
59
|
+
throw new Error(`interrupt listener: stream ${res.status}`);
|
|
60
|
+
}
|
|
61
|
+
const reader = res.body.getReader();
|
|
62
|
+
const decoder = new TextDecoder();
|
|
63
|
+
let buf = "";
|
|
64
|
+
|
|
65
|
+
while (true) {
|
|
66
|
+
const { done, value } = await reader.read();
|
|
67
|
+
if (done) {
|
|
68
|
+
throw new Error("interrupt listener: stream ended without run.resumed");
|
|
69
|
+
}
|
|
70
|
+
buf += decoder.decode(value, { stream: true });
|
|
71
|
+
// Parse SSE frames
|
|
72
|
+
const frames = buf.split("\n\n");
|
|
73
|
+
buf = frames.pop() ?? "";
|
|
74
|
+
for (const frame of frames) {
|
|
75
|
+
if (!frame.trim()) continue;
|
|
76
|
+
const dataLine = frame.split("\n").find((l) => l.startsWith("data:"));
|
|
77
|
+
if (!dataLine) continue;
|
|
78
|
+
const jsonStr = dataLine.slice("data:".length).trim();
|
|
79
|
+
if (!jsonStr || jsonStr === "[DONE]") continue;
|
|
80
|
+
let event;
|
|
81
|
+
try {
|
|
82
|
+
event = JSON.parse(jsonStr);
|
|
83
|
+
} catch {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
// We only care about run.resumed for our run + interrupt
|
|
87
|
+
if (event?.type !== "run.resumed") continue;
|
|
88
|
+
if (event.run_id !== runId) continue;
|
|
89
|
+
const agentExt = event?.extensions?.agent;
|
|
90
|
+
if (!agentExt) continue;
|
|
91
|
+
const eventInterruptId = agentExt.interrupt_id;
|
|
92
|
+
if (eventInterruptId && eventInterruptId !== interruptId) continue;
|
|
93
|
+
// Match! Extract value
|
|
94
|
+
const decisionValue = agentExt.value ?? null;
|
|
95
|
+
log?.info?.("interrupt.listener.resolved", "run.resumed received", {
|
|
96
|
+
run_id: runId,
|
|
97
|
+
interrupt_id: interruptId,
|
|
98
|
+
});
|
|
99
|
+
return { value: decisionValue };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} finally {
|
|
103
|
+
clearTimeout(timeoutHandle);
|
|
104
|
+
ctrl.abort(); // ensure stream is closed
|
|
105
|
+
}
|
|
106
|
+
}
|