@nextclaw/nextclaw-ncp-runtime-stdio-client 0.1.1 → 0.1.2
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/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/stdio-runtime-config.utils.d.ts +6 -1
- package/dist/stdio-runtime-config.utils.js +10 -1
- package/dist/stdio-runtime-probe.utils.js +2 -5
- package/dist/stdio-runtime.service.js +3 -4
- package/package.json +2 -2
- package/dist/hermes-acp-route-bridge/__pycache__/sitecustomize.cpython-312.pyc +0 -0
- package/dist/hermes-acp-route-bridge/__pycache__/sitecustomize.cpython-314.pyc +0 -0
- package/dist/hermes-acp-route-bridge/sitecustomize.py +0 -225
- package/dist/hermes-acp-route-bridge.utils.js +0 -61
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NARP_STDIO_PROMPT_META_KEY, NarpStdioPromptMeta, StdioRuntimeConfigResolver, StdioRuntimeEnv, StdioRuntimeProcessScope, StdioRuntimeResolvedConfig, StdioRuntimeWireDialect, buildRuntimeRouteBridgeEnv } from "./stdio-runtime-config.utils.js";
|
|
1
|
+
import { NARP_STDIO_PROMPT_META_KEY, NarpStdioPromptMeta, StdioRuntimeConfigResolver, StdioRuntimeEnv, StdioRuntimeProcessScope, StdioRuntimeResolvedConfig, StdioRuntimeWireDialect, buildRuntimeRouteBridgeEnv, buildStdioRuntimeLaunchEnv } from "./stdio-runtime-config.utils.js";
|
|
2
2
|
import { StdioRuntimeNcpAgentRuntime, StdioRuntimeNcpAgentRuntimeConfig } from "./stdio-runtime.service.js";
|
|
3
3
|
import { probeStdioRuntime } from "./stdio-runtime-probe.utils.js";
|
|
4
|
-
export { NARP_STDIO_PROMPT_META_KEY, type NarpStdioPromptMeta, StdioRuntimeConfigResolver, type StdioRuntimeEnv, StdioRuntimeNcpAgentRuntime, type StdioRuntimeNcpAgentRuntimeConfig, type StdioRuntimeProcessScope, type StdioRuntimeResolvedConfig, type StdioRuntimeWireDialect, buildRuntimeRouteBridgeEnv, probeStdioRuntime };
|
|
4
|
+
export { NARP_STDIO_PROMPT_META_KEY, type NarpStdioPromptMeta, StdioRuntimeConfigResolver, type StdioRuntimeEnv, StdioRuntimeNcpAgentRuntime, type StdioRuntimeNcpAgentRuntimeConfig, type StdioRuntimeProcessScope, type StdioRuntimeResolvedConfig, type StdioRuntimeWireDialect, buildRuntimeRouteBridgeEnv, buildStdioRuntimeLaunchEnv, probeStdioRuntime };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NARP_STDIO_PROMPT_META_KEY, StdioRuntimeConfigResolver, buildRuntimeRouteBridgeEnv } from "./stdio-runtime-config.utils.js";
|
|
1
|
+
import { NARP_STDIO_PROMPT_META_KEY, StdioRuntimeConfigResolver, buildRuntimeRouteBridgeEnv, buildStdioRuntimeLaunchEnv } from "./stdio-runtime-config.utils.js";
|
|
2
2
|
import { StdioRuntimeNcpAgentRuntime } from "./stdio-runtime.service.js";
|
|
3
3
|
import { probeStdioRuntime } from "./stdio-runtime-probe.utils.js";
|
|
4
|
-
export { NARP_STDIO_PROMPT_META_KEY, StdioRuntimeConfigResolver, StdioRuntimeNcpAgentRuntime, buildRuntimeRouteBridgeEnv, probeStdioRuntime };
|
|
4
|
+
export { NARP_STDIO_PROMPT_META_KEY, StdioRuntimeConfigResolver, StdioRuntimeNcpAgentRuntime, buildRuntimeRouteBridgeEnv, buildStdioRuntimeLaunchEnv, probeStdioRuntime };
|
|
@@ -32,5 +32,10 @@ declare class StdioRuntimeConfigResolver {
|
|
|
32
32
|
declare function buildRuntimeRouteBridgeEnv(params: {
|
|
33
33
|
providerRoute?: NcpProviderRuntimeRoute;
|
|
34
34
|
}): Record<string, string>;
|
|
35
|
+
declare function buildStdioRuntimeLaunchEnv(params: {
|
|
36
|
+
baseEnv?: Record<string, string | undefined>;
|
|
37
|
+
configEnv?: StdioRuntimeEnv;
|
|
38
|
+
providerRoute?: NcpProviderRuntimeRoute;
|
|
39
|
+
}): Record<string, string>;
|
|
35
40
|
//#endregion
|
|
36
|
-
export { NARP_STDIO_PROMPT_META_KEY, NarpStdioPromptMeta, StdioRuntimeConfigResolver, StdioRuntimeEnv, StdioRuntimeProcessScope, StdioRuntimeResolvedConfig, StdioRuntimeWireDialect, buildRuntimeRouteBridgeEnv };
|
|
41
|
+
export { NARP_STDIO_PROMPT_META_KEY, NarpStdioPromptMeta, StdioRuntimeConfigResolver, StdioRuntimeEnv, StdioRuntimeProcessScope, StdioRuntimeResolvedConfig, StdioRuntimeWireDialect, buildRuntimeRouteBridgeEnv, buildStdioRuntimeLaunchEnv };
|
|
@@ -82,6 +82,15 @@ function buildRuntimeRouteBridgeEnv(params) {
|
|
|
82
82
|
[DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.headers]: JSON.stringify(providerRoute.headers ?? {})
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
|
+
function buildStdioRuntimeLaunchEnv(params) {
|
|
86
|
+
const baseEnv = {};
|
|
87
|
+
for (const [key, value] of Object.entries(params.baseEnv ?? process.env)) if (typeof value === "string") baseEnv[key] = value;
|
|
88
|
+
return {
|
|
89
|
+
...baseEnv,
|
|
90
|
+
...params.configEnv ?? {},
|
|
91
|
+
...buildRuntimeRouteBridgeEnv({ providerRoute: params.providerRoute })
|
|
92
|
+
};
|
|
93
|
+
}
|
|
85
94
|
function parseJsonArray(value) {
|
|
86
95
|
if (typeof value !== "string" || !value.trim()) return;
|
|
87
96
|
try {
|
|
@@ -99,4 +108,4 @@ function parseJsonObject(value) {
|
|
|
99
108
|
}
|
|
100
109
|
}
|
|
101
110
|
//#endregion
|
|
102
|
-
export { NARP_STDIO_PROMPT_META_KEY, StdioRuntimeConfigResolver, buildRuntimeRouteBridgeEnv, readString };
|
|
111
|
+
export { NARP_STDIO_PROMPT_META_KEY, StdioRuntimeConfigResolver, buildRuntimeRouteBridgeEnv, buildStdioRuntimeLaunchEnv, readString };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildStdioRuntimeLaunchEnv } from "./stdio-runtime-config.utils.js";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { Readable, Writable } from "node:stream";
|
|
4
4
|
import * as acp from "@agentclientprotocol/sdk";
|
|
@@ -12,10 +12,7 @@ const createProbeClientBridge = () => ({
|
|
|
12
12
|
async function probeStdioRuntime(config) {
|
|
13
13
|
const child = spawn(config.command, config.args, {
|
|
14
14
|
cwd: config.cwd,
|
|
15
|
-
env:
|
|
16
|
-
config,
|
|
17
|
-
useProbeRoute: true
|
|
18
|
-
}),
|
|
15
|
+
env: buildStdioRuntimeLaunchEnv({ configEnv: config.env }),
|
|
19
16
|
stdio: [
|
|
20
17
|
"pipe",
|
|
21
18
|
"pipe",
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { NARP_STDIO_PROMPT_META_KEY, readString } from "./stdio-runtime-config.utils.js";
|
|
2
|
-
import { buildStdioLaunchEnv } from "./hermes-acp-route-bridge.utils.js";
|
|
1
|
+
import { NARP_STDIO_PROMPT_META_KEY, buildStdioRuntimeLaunchEnv, readString } from "./stdio-runtime-config.utils.js";
|
|
3
2
|
import { randomUUID } from "node:crypto";
|
|
4
3
|
import { spawn } from "node:child_process";
|
|
5
4
|
import { Readable, Writable } from "node:stream";
|
|
@@ -156,8 +155,8 @@ var StdioRuntimeSession = class {
|
|
|
156
155
|
ensureStarted = async (params) => {
|
|
157
156
|
this.pendingProviderRoute = params?.providerRoute;
|
|
158
157
|
if (this.connection && this.remoteSessionId) return;
|
|
159
|
-
const env =
|
|
160
|
-
|
|
158
|
+
const env = buildStdioRuntimeLaunchEnv({
|
|
159
|
+
configEnv: this.config.env,
|
|
161
160
|
providerRoute: this.pendingProviderRoute
|
|
162
161
|
});
|
|
163
162
|
this.child = spawn(this.config.command, this.config.args, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/nextclaw-ncp-runtime-stdio-client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Optional NCP runtime adapter backed by a protocol-aware stdio agent command.",
|
|
6
6
|
"type": "module",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"vitest": "^4.1.2"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
|
-
"build": "tsdown src/index.ts --dts --clean --target es2022 --no-fixedExtension --unbundle
|
|
28
|
+
"build": "tsdown src/index.ts --dts --clean --target es2022 --no-fixedExtension --unbundle",
|
|
29
29
|
"lint": "eslint .",
|
|
30
30
|
"tsc": "tsc -p tsconfig.json",
|
|
31
31
|
"test": "vitest run"
|
|
Binary file
|
|
Binary file
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
"""NextClaw bridge for Hermes ACP RuntimeRoute passthrough.
|
|
2
|
-
|
|
3
|
-
This module is auto-imported by Python when PYTHONPATH points at this
|
|
4
|
-
directory. It patches Hermes ACP so `hermes acp` consumes the active
|
|
5
|
-
NextClaw RuntimeRoute instead of resolving its own provider config first.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import json
|
|
11
|
-
import logging
|
|
12
|
-
import os
|
|
13
|
-
from typing import Any, Dict, Optional
|
|
14
|
-
|
|
15
|
-
LOGGER = logging.getLogger("nextclaw.hermes_acp_route_bridge")
|
|
16
|
-
ROUTE_ENABLE_ENV = "NEXTCLAW_HERMES_ACP_ROUTE_BRIDGE"
|
|
17
|
-
API_MODE_HEADER = "x-nextclaw-narp-api-mode"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _read_text_env(name: str) -> Optional[str]:
|
|
21
|
-
value = os.environ.get(name)
|
|
22
|
-
if not isinstance(value, str):
|
|
23
|
-
return None
|
|
24
|
-
trimmed = value.strip()
|
|
25
|
-
return trimmed or None
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def _read_headers_env() -> Dict[str, str]:
|
|
29
|
-
raw = _read_text_env("NEXTCLAW_HEADERS_JSON")
|
|
30
|
-
if not raw:
|
|
31
|
-
return {}
|
|
32
|
-
try:
|
|
33
|
-
parsed = json.loads(raw)
|
|
34
|
-
except Exception:
|
|
35
|
-
LOGGER.debug("Failed to parse NEXTCLAW_HEADERS_JSON", exc_info=True)
|
|
36
|
-
return {}
|
|
37
|
-
if not isinstance(parsed, dict):
|
|
38
|
-
return {}
|
|
39
|
-
normalized: Dict[str, str] = {}
|
|
40
|
-
for key, value in parsed.items():
|
|
41
|
-
if isinstance(key, str) and isinstance(value, str) and key.strip() and value.strip():
|
|
42
|
-
normalized[key] = value
|
|
43
|
-
return normalized
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def _read_nextclaw_route(explicit_model: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
|
47
|
-
model = explicit_model or _read_text_env("NEXTCLAW_MODEL")
|
|
48
|
-
api_base = _read_text_env("NEXTCLAW_API_BASE")
|
|
49
|
-
api_key = _read_text_env("NEXTCLAW_API_KEY")
|
|
50
|
-
headers = _read_headers_env()
|
|
51
|
-
api_mode = headers.pop(API_MODE_HEADER, None) or "chat_completions"
|
|
52
|
-
if not any([model, api_base, api_key, headers]):
|
|
53
|
-
return None
|
|
54
|
-
return {
|
|
55
|
-
"model": model,
|
|
56
|
-
"api_base": api_base,
|
|
57
|
-
"api_key": api_key or "",
|
|
58
|
-
"headers": headers,
|
|
59
|
-
"api_mode": api_mode,
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def _merge_openai_headers(agent: Any, headers: Dict[str, str]) -> None:
|
|
64
|
-
if not headers:
|
|
65
|
-
return
|
|
66
|
-
client_kwargs = getattr(agent, "_client_kwargs", None)
|
|
67
|
-
if not isinstance(client_kwargs, dict):
|
|
68
|
-
return
|
|
69
|
-
merged = dict(client_kwargs.get("default_headers") or {})
|
|
70
|
-
merged.update(headers)
|
|
71
|
-
client_kwargs["default_headers"] = merged
|
|
72
|
-
replace_client = getattr(agent, "_replace_primary_openai_client", None)
|
|
73
|
-
if callable(replace_client):
|
|
74
|
-
replace_client(reason="nextclaw_runtime_route_bridge")
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def _merge_anthropic_headers(agent: Any, headers: Dict[str, str]) -> None:
|
|
78
|
-
if not headers:
|
|
79
|
-
return
|
|
80
|
-
client = getattr(agent, "_anthropic_client", None)
|
|
81
|
-
if client is None:
|
|
82
|
-
return
|
|
83
|
-
merged = dict(getattr(client, "_default_headers", {}) or {})
|
|
84
|
-
merged.update(headers)
|
|
85
|
-
if hasattr(client, "_default_headers"):
|
|
86
|
-
client._default_headers = merged
|
|
87
|
-
inner_client = getattr(client, "_client", None)
|
|
88
|
-
if inner_client is not None:
|
|
89
|
-
if hasattr(inner_client, "_default_headers"):
|
|
90
|
-
inner_client._default_headers = merged
|
|
91
|
-
transport_headers = getattr(inner_client, "headers", None)
|
|
92
|
-
if hasattr(transport_headers, "update"):
|
|
93
|
-
transport_headers.update(merged)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def _patch_acp_auth() -> None:
|
|
97
|
-
try:
|
|
98
|
-
from acp_adapter import auth as auth_module
|
|
99
|
-
except Exception:
|
|
100
|
-
LOGGER.debug("Failed to import acp_adapter.auth", exc_info=True)
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
original_detect_provider = auth_module.detect_provider
|
|
104
|
-
|
|
105
|
-
def detect_provider():
|
|
106
|
-
route = _read_nextclaw_route()
|
|
107
|
-
if route is not None:
|
|
108
|
-
return "nextclaw"
|
|
109
|
-
return original_detect_provider()
|
|
110
|
-
|
|
111
|
-
def has_provider():
|
|
112
|
-
return detect_provider() is not None
|
|
113
|
-
|
|
114
|
-
auth_module.detect_provider = detect_provider
|
|
115
|
-
auth_module.has_provider = has_provider
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def _patch_session_manager() -> None:
|
|
119
|
-
try:
|
|
120
|
-
from acp_adapter import session as session_module
|
|
121
|
-
except Exception:
|
|
122
|
-
LOGGER.debug("Failed to import acp_adapter.session", exc_info=True)
|
|
123
|
-
return
|
|
124
|
-
|
|
125
|
-
original_make_agent = session_module.SessionManager._make_agent
|
|
126
|
-
|
|
127
|
-
def bridged_make_agent(
|
|
128
|
-
self,
|
|
129
|
-
*,
|
|
130
|
-
session_id: str,
|
|
131
|
-
cwd: str,
|
|
132
|
-
model: str | None = None,
|
|
133
|
-
requested_provider: str | None = None,
|
|
134
|
-
base_url: str | None = None,
|
|
135
|
-
api_mode: str | None = None,
|
|
136
|
-
):
|
|
137
|
-
route = _read_nextclaw_route(explicit_model=model)
|
|
138
|
-
if route is None:
|
|
139
|
-
return original_make_agent(
|
|
140
|
-
self,
|
|
141
|
-
session_id=session_id,
|
|
142
|
-
cwd=cwd,
|
|
143
|
-
model=model,
|
|
144
|
-
requested_provider=requested_provider,
|
|
145
|
-
base_url=base_url,
|
|
146
|
-
api_mode=api_mode,
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
if self._agent_factory is not None:
|
|
150
|
-
return self._agent_factory()
|
|
151
|
-
|
|
152
|
-
from run_agent import AIAgent
|
|
153
|
-
|
|
154
|
-
kwargs = {
|
|
155
|
-
"platform": "acp",
|
|
156
|
-
"enabled_toolsets": ["hermes-acp"],
|
|
157
|
-
"quiet_mode": True,
|
|
158
|
-
"session_id": session_id,
|
|
159
|
-
"model": route["model"] or "",
|
|
160
|
-
"provider": requested_provider or "custom",
|
|
161
|
-
"api_mode": api_mode or route["api_mode"],
|
|
162
|
-
"base_url": base_url or route["api_base"] or "",
|
|
163
|
-
"api_key": route["api_key"],
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
session_module._register_task_cwd(session_id, cwd)
|
|
167
|
-
agent = AIAgent(**kwargs)
|
|
168
|
-
agent._print_fn = session_module._acp_stderr_print
|
|
169
|
-
_merge_openai_headers(agent, route["headers"])
|
|
170
|
-
_merge_anthropic_headers(agent, route["headers"])
|
|
171
|
-
return agent
|
|
172
|
-
|
|
173
|
-
session_module.SessionManager._make_agent = bridged_make_agent
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def _patch_acp_reasoning_mapping() -> None:
|
|
177
|
-
try:
|
|
178
|
-
from run_agent import AIAgent
|
|
179
|
-
except Exception:
|
|
180
|
-
LOGGER.debug("Failed to import run_agent.AIAgent", exc_info=True)
|
|
181
|
-
return
|
|
182
|
-
|
|
183
|
-
original_run_conversation = getattr(AIAgent, "run_conversation", None)
|
|
184
|
-
if not callable(original_run_conversation):
|
|
185
|
-
return
|
|
186
|
-
if getattr(original_run_conversation, "__nextclaw_reasoning_bridge__", False):
|
|
187
|
-
return
|
|
188
|
-
|
|
189
|
-
def bridged_run_conversation(self, *args, **kwargs):
|
|
190
|
-
original_thinking = getattr(self, "thinking_callback", None)
|
|
191
|
-
original_reasoning = getattr(self, "reasoning_callback", None)
|
|
192
|
-
remapped = (
|
|
193
|
-
getattr(self, "platform", None) == "acp"
|
|
194
|
-
and callable(original_thinking)
|
|
195
|
-
and original_reasoning is None
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
if remapped:
|
|
199
|
-
# Hermes ACP currently wires its transient spinner/status callback
|
|
200
|
-
# into ACP thought events. For ACP sessions, remap that callback to
|
|
201
|
-
# the real reasoning channel so downstream clients receive model
|
|
202
|
-
# reasoning instead of strings like "(⌐■_■) computing...".
|
|
203
|
-
self.reasoning_callback = original_thinking
|
|
204
|
-
self.thinking_callback = None
|
|
205
|
-
|
|
206
|
-
try:
|
|
207
|
-
return original_run_conversation(self, *args, **kwargs)
|
|
208
|
-
finally:
|
|
209
|
-
if remapped:
|
|
210
|
-
self.thinking_callback = original_thinking
|
|
211
|
-
self.reasoning_callback = original_reasoning
|
|
212
|
-
|
|
213
|
-
bridged_run_conversation.__nextclaw_reasoning_bridge__ = True
|
|
214
|
-
AIAgent.run_conversation = bridged_run_conversation
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
def _activate() -> None:
|
|
218
|
-
if _read_text_env(ROUTE_ENABLE_ENV) != "1":
|
|
219
|
-
return
|
|
220
|
-
_patch_acp_auth()
|
|
221
|
-
_patch_session_manager()
|
|
222
|
-
_patch_acp_reasoning_mapping()
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
_activate()
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { buildRuntimeRouteBridgeEnv } from "./stdio-runtime-config.utils.js";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { basename, delimiter } from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
//#region src/hermes-acp-route-bridge.utils.ts
|
|
6
|
-
const HERMES_ACP_BRIDGE_ENABLE_ENV = "NEXTCLAW_HERMES_ACP_ROUTE_BRIDGE";
|
|
7
|
-
const HERMES_ACP_BRIDGE_DIR_ENV = "NEXTCLAW_HERMES_ACP_ROUTE_BRIDGE_DIR";
|
|
8
|
-
const HERMES_ACP_PROBE_ROUTE = {
|
|
9
|
-
model: "nextclaw-hermes-acp-probe",
|
|
10
|
-
apiBase: "http://127.0.0.1:1/v1",
|
|
11
|
-
apiKey: "nextclaw-hermes-acp-probe-key",
|
|
12
|
-
headers: { "x-nextclaw-narp-api-mode": "chat_completions" }
|
|
13
|
-
};
|
|
14
|
-
function normalizeCommandBasename(command) {
|
|
15
|
-
return basename(command).trim().toLowerCase();
|
|
16
|
-
}
|
|
17
|
-
function isPythonCommand(command) {
|
|
18
|
-
const normalized = normalizeCommandBasename(command);
|
|
19
|
-
return normalized === "python" || normalized === "python3" || normalized.startsWith("python3.");
|
|
20
|
-
}
|
|
21
|
-
function targetsHermesAcpModule(args) {
|
|
22
|
-
for (let index = 0; index < args.length - 1; index += 1) if (args[index] === "-m" && args[index + 1]?.trim().toLowerCase() === "acp_adapter.entry") return true;
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
function isHermesAcpRuntimeConfig(config) {
|
|
26
|
-
const command = normalizeCommandBasename(config.command);
|
|
27
|
-
if (command === "hermes-acp") return true;
|
|
28
|
-
if (command === "hermes") return config.args[0]?.trim().toLowerCase() === "acp";
|
|
29
|
-
if (isPythonCommand(config.command)) return targetsHermesAcpModule(config.args);
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
function resolveHermesAcpBridgeDir() {
|
|
33
|
-
const bridgeDir = fileURLToPath(new URL("./hermes-acp-route-bridge", import.meta.url));
|
|
34
|
-
return existsSync(bridgeDir) ? bridgeDir : null;
|
|
35
|
-
}
|
|
36
|
-
function mergePathList(existingValue, injectedPath) {
|
|
37
|
-
const parts = (existingValue ?? "").split(delimiter).map((entry) => entry.trim()).filter(Boolean);
|
|
38
|
-
if (!parts.includes(injectedPath)) parts.unshift(injectedPath);
|
|
39
|
-
return parts.join(delimiter);
|
|
40
|
-
}
|
|
41
|
-
function buildStdioLaunchEnv(params) {
|
|
42
|
-
const providerRoute = params.providerRoute ?? (params.useProbeRoute && isHermesAcpRuntimeConfig(params.config) ? HERMES_ACP_PROBE_ROUTE : void 0);
|
|
43
|
-
const baseEnv = {};
|
|
44
|
-
for (const [key, value] of Object.entries(params.baseEnv ?? process.env)) if (typeof value === "string") baseEnv[key] = value;
|
|
45
|
-
const env = {
|
|
46
|
-
...baseEnv,
|
|
47
|
-
...params.config.env ?? {},
|
|
48
|
-
...buildRuntimeRouteBridgeEnv({ providerRoute })
|
|
49
|
-
};
|
|
50
|
-
if (!isHermesAcpRuntimeConfig(params.config)) return env;
|
|
51
|
-
const bridgeDir = resolveHermesAcpBridgeDir();
|
|
52
|
-
if (!bridgeDir) return env;
|
|
53
|
-
return {
|
|
54
|
-
...env,
|
|
55
|
-
[HERMES_ACP_BRIDGE_ENABLE_ENV]: "1",
|
|
56
|
-
[HERMES_ACP_BRIDGE_DIR_ENV]: bridgeDir,
|
|
57
|
-
PYTHONPATH: mergePathList(env.PYTHONPATH, bridgeDir)
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
//#endregion
|
|
61
|
-
export { buildStdioLaunchEnv };
|