@codexhost/cli-darwin-x64 0.16.1 → 0.17.0
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 +2 -2
- package/THIRD_PARTY_NOTICES.txt +6 -2
- package/app/codexhost-distribution.json +1 -1
- package/app/console-server.mjs +55 -20
- package/app/console-web.js +45 -17
- package/app/desktop-controller.mjs +76 -31
- package/app/host-runtime.mjs +2671 -1869
- package/app/plugins/antigravity/plugin.mjs +35 -2
- package/app/plugins/claude-code/plugin.mjs +12 -6
- package/app/plugins/codebuddy/plugin.mjs +10 -0
- package/app/plugins/cursor-cli/plugin.mjs +9 -5
- package/app/plugins/deepseek-harness/plugin.mjs +459 -46
- package/app/plugins/devin/assets/icon.svg +1 -0
- package/app/plugins/devin/manifest.json +30 -0
- package/app/plugins/devin/plugin.mjs +23363 -0
- package/app/plugins/enabled.json +2 -0
- package/app/plugins/grok/plugin.mjs +472 -391
- package/app/plugins/hermes/plugin.mjs +453 -196
- package/app/plugins/pi/plugin.mjs +1460 -411
- package/app/plugins/qoder/plugin.mjs +9524 -8654
- package/app/plugins/qoder-cn/plugin.mjs +9524 -8654
- package/app/plugins/qwen-code/assets/icon.svg +1 -0
- package/app/plugins/qwen-code/manifest.json +29 -0
- package/app/plugins/qwen-code/plugin.mjs +29298 -0
- package/app/plugins/workbuddy/plugin.mjs +10 -0
- package/app/renderer-extension.js +162 -54
- package/bin/codexhost +0 -0
- package/libexec/codexhost-shim +0 -0
- package/libexec/codexhost-updater +0 -0
- package/licenses/Qwen-Code-SDK-LICENSE.txt +203 -0
- package/package.json +2 -2
|
@@ -1138,10 +1138,10 @@ function mergeDefs(...defs) {
|
|
|
1138
1138
|
function cloneDef(schema) {
|
|
1139
1139
|
return mergeDefs(schema._zod.def);
|
|
1140
1140
|
}
|
|
1141
|
-
function getElementAtPath(obj,
|
|
1142
|
-
if (!
|
|
1141
|
+
function getElementAtPath(obj, path8) {
|
|
1142
|
+
if (!path8)
|
|
1143
1143
|
return obj;
|
|
1144
|
-
return
|
|
1144
|
+
return path8.reduce((acc, key) => acc?.[key], obj);
|
|
1145
1145
|
}
|
|
1146
1146
|
function promiseAllObject(promisesObj) {
|
|
1147
1147
|
const keys = Object.keys(promisesObj);
|
|
@@ -1550,11 +1550,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
1550
1550
|
}
|
|
1551
1551
|
return false;
|
|
1552
1552
|
}
|
|
1553
|
-
function prefixIssues(
|
|
1553
|
+
function prefixIssues(path8, issues) {
|
|
1554
1554
|
return issues.map((iss) => {
|
|
1555
1555
|
var _a3;
|
|
1556
1556
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
1557
|
-
iss.path.unshift(
|
|
1557
|
+
iss.path.unshift(path8);
|
|
1558
1558
|
return iss;
|
|
1559
1559
|
});
|
|
1560
1560
|
}
|
|
@@ -1701,16 +1701,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
1701
1701
|
}
|
|
1702
1702
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
1703
1703
|
const fieldErrors = { _errors: [] };
|
|
1704
|
-
const processError = (error52,
|
|
1704
|
+
const processError = (error52, path8 = []) => {
|
|
1705
1705
|
for (const issue2 of error52.issues) {
|
|
1706
1706
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
1707
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
1707
|
+
issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
|
|
1708
1708
|
} else if (issue2.code === "invalid_key") {
|
|
1709
|
-
processError({ issues: issue2.issues }, [...
|
|
1709
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
1710
1710
|
} else if (issue2.code === "invalid_element") {
|
|
1711
|
-
processError({ issues: issue2.issues }, [...
|
|
1711
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
1712
1712
|
} else {
|
|
1713
|
-
const fullpath = [...
|
|
1713
|
+
const fullpath = [...path8, ...issue2.path];
|
|
1714
1714
|
if (fullpath.length === 0) {
|
|
1715
1715
|
fieldErrors._errors.push(mapper(issue2));
|
|
1716
1716
|
} else {
|
|
@@ -1737,17 +1737,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
1737
1737
|
}
|
|
1738
1738
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
1739
1739
|
const result = { errors: [] };
|
|
1740
|
-
const processError = (error52,
|
|
1740
|
+
const processError = (error52, path8 = []) => {
|
|
1741
1741
|
var _a3, _b;
|
|
1742
1742
|
for (const issue2 of error52.issues) {
|
|
1743
1743
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
1744
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
1744
|
+
issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
|
|
1745
1745
|
} else if (issue2.code === "invalid_key") {
|
|
1746
|
-
processError({ issues: issue2.issues }, [...
|
|
1746
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
1747
1747
|
} else if (issue2.code === "invalid_element") {
|
|
1748
|
-
processError({ issues: issue2.issues }, [...
|
|
1748
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
1749
1749
|
} else {
|
|
1750
|
-
const fullpath = [...
|
|
1750
|
+
const fullpath = [...path8, ...issue2.path];
|
|
1751
1751
|
if (fullpath.length === 0) {
|
|
1752
1752
|
result.errors.push(mapper(issue2));
|
|
1753
1753
|
continue;
|
|
@@ -1779,8 +1779,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
1779
1779
|
}
|
|
1780
1780
|
function toDotPath(_path) {
|
|
1781
1781
|
const segs = [];
|
|
1782
|
-
const
|
|
1783
|
-
for (const seg of
|
|
1782
|
+
const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1783
|
+
for (const seg of path8) {
|
|
1784
1784
|
if (typeof seg === "number")
|
|
1785
1785
|
segs.push(`[${seg}]`);
|
|
1786
1786
|
else if (typeof seg === "symbol")
|
|
@@ -14472,13 +14472,13 @@ function resolveRef(ref, ctx) {
|
|
|
14472
14472
|
if (!ref.startsWith("#")) {
|
|
14473
14473
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
14474
14474
|
}
|
|
14475
|
-
const
|
|
14476
|
-
if (
|
|
14475
|
+
const path8 = ref.slice(1).split("/").filter(Boolean);
|
|
14476
|
+
if (path8.length === 0) {
|
|
14477
14477
|
return ctx.rootSchema;
|
|
14478
14478
|
}
|
|
14479
14479
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
14480
|
-
if (
|
|
14481
|
-
const key =
|
|
14480
|
+
if (path8[0] === defsKey) {
|
|
14481
|
+
const key = path8[1];
|
|
14482
14482
|
if (!key || !ctx.defs[key]) {
|
|
14483
14483
|
throw new Error(`Reference not found: ${ref}`);
|
|
14484
14484
|
}
|
|
@@ -16620,7 +16620,35 @@ import path4 from "node:path";
|
|
|
16620
16620
|
|
|
16621
16621
|
// dist/hermes-runtime.js
|
|
16622
16622
|
import { execFile as execFile2 } from "node:child_process";
|
|
16623
|
+
import { statSync } from "node:fs";
|
|
16623
16624
|
import { promisify } from "node:util";
|
|
16625
|
+
var launcherPrefixCache = /* @__PURE__ */ new Map();
|
|
16626
|
+
function launcherCacheKey(launcher, environment) {
|
|
16627
|
+
let stat;
|
|
16628
|
+
try {
|
|
16629
|
+
stat = statSync(launcher);
|
|
16630
|
+
} catch {
|
|
16631
|
+
return null;
|
|
16632
|
+
}
|
|
16633
|
+
return [
|
|
16634
|
+
launcher,
|
|
16635
|
+
stat.mtimeMs,
|
|
16636
|
+
stat.size,
|
|
16637
|
+
environment.HERMES_HOME ?? "",
|
|
16638
|
+
environment.PATH ?? ""
|
|
16639
|
+
].join("\0");
|
|
16640
|
+
}
|
|
16641
|
+
function timeitPassthrough(script) {
|
|
16642
|
+
return [
|
|
16643
|
+
"-n",
|
|
16644
|
+
"1",
|
|
16645
|
+
"-r",
|
|
16646
|
+
"1",
|
|
16647
|
+
"-s",
|
|
16648
|
+
`exec(${JSON.stringify(script)}, {}); import sys, io; sys.stdout = io.StringIO()`,
|
|
16649
|
+
"pass"
|
|
16650
|
+
];
|
|
16651
|
+
}
|
|
16624
16652
|
function legacyHermesPythonCommand(python, script) {
|
|
16625
16653
|
return {
|
|
16626
16654
|
command: python,
|
|
@@ -16636,22 +16664,12 @@ ${script}`
|
|
|
16636
16664
|
};
|
|
16637
16665
|
}
|
|
16638
16666
|
async function nativeHermesPythonCommand(launcher, script, environment, timeoutMs = 2e4, platform = process.platform) {
|
|
16639
|
-
const
|
|
16640
|
-
|
|
16641
|
-
|
|
16642
|
-
|
|
16643
|
-
|
|
16644
|
-
|
|
16645
|
-
"1",
|
|
16646
|
-
"-r",
|
|
16647
|
-
"1",
|
|
16648
|
-
"-s",
|
|
16649
|
-
// timeit is a stdlib entry point supported by the native launcher. After
|
|
16650
|
-
// the operation returns, redirect its timing footer, preserving normal
|
|
16651
|
-
// native cleanup and exit status without contaminating JSON/RPC stdout.
|
|
16652
|
-
`exec(${JSON.stringify(script)}, {}); import sys, io; sys.stdout = io.StringIO()`,
|
|
16653
|
-
"pass"
|
|
16654
|
-
], environment, platform);
|
|
16667
|
+
const passthrough = timeitPassthrough(script);
|
|
16668
|
+
const cacheKey = launcherCacheKey(launcher, environment);
|
|
16669
|
+
const cached2 = cacheKey !== null ? launcherPrefixCache.get(cacheKey) : void 0;
|
|
16670
|
+
if (cached2 !== void 0 && cached2.length > 0 && cached2[0])
|
|
16671
|
+
return { command: cached2[0], arguments: [...cached2.slice(1), ...passthrough] };
|
|
16672
|
+
const invocation = commandInvocation(launcher, ["--print-runtime-command", "--module", "timeit", "--", ...passthrough], environment, platform);
|
|
16655
16673
|
let stdout;
|
|
16656
16674
|
try {
|
|
16657
16675
|
({ stdout } = await promisify(execFile2)(invocation.command, invocation.arguments, {
|
|
@@ -16671,6 +16689,9 @@ async function nativeHermesPythonCommand(launcher, script, environment, timeoutM
|
|
|
16671
16689
|
if (!Array.isArray(value) || value.length === 0 || !value.every((arg) => typeof arg === "string") || !value[0]) {
|
|
16672
16690
|
throw new Error("Hermes launcher returned an invalid runtime command");
|
|
16673
16691
|
}
|
|
16692
|
+
const passthroughStart = value.length - passthrough.length;
|
|
16693
|
+
if (cacheKey !== null && passthroughStart >= 1 && value.slice(passthroughStart).every((arg, index) => arg === passthrough[index]))
|
|
16694
|
+
launcherPrefixCache.set(cacheKey, value.slice(0, passthroughStart));
|
|
16674
16695
|
return { command: value[0], arguments: value.slice(1) };
|
|
16675
16696
|
}
|
|
16676
16697
|
async function hermesPythonCommand(runtime, script, environment, timeoutMs = 2e4) {
|
|
@@ -16983,9 +17004,6 @@ function catalogModelsFromInventory(inventory) {
|
|
|
16983
17004
|
}
|
|
16984
17005
|
|
|
16985
17006
|
// dist/gateway-delegation.js
|
|
16986
|
-
import { mkdtemp as mkdtemp2, writeFile as writeFile2, rm as rm2 } from "node:fs/promises";
|
|
16987
|
-
import os2 from "node:os";
|
|
16988
|
-
import path5 from "node:path";
|
|
16989
17007
|
var HERMES_DELEGATION_GUIDANCE = `This Session runs inside codexhost.
|
|
16990
17008
|
When the user authorizes cross-Harness delegation, discover the executable named by CODEXHOST_CLI_PATH through your native terminal tool. Read its --help and harness list, then use delegate start and thread send/read/wait/cancel as documented. Prefer --format compact. Preserve CODEXHOST_RUNTIME_ENDPOINT, CODEXHOST_RUNTIME_TOKEN and CODEXHOST_THREAD_ID in these calls: they identify the Runtime and parent Thread. Never print their values or substitute another executable. Native Hermes delegate_task remains available for Hermes subagents.`;
|
|
16991
17009
|
var required2 = [
|
|
@@ -16996,48 +17014,40 @@ var required2 = [
|
|
|
16996
17014
|
];
|
|
16997
17015
|
async function prepareGatewayDelegation(environment) {
|
|
16998
17016
|
if (!required2.every((key) => environment[key]))
|
|
16999
|
-
return { environment, bootstrap: "", dispose: async () => {
|
|
17017
|
+
return { environment, bootstrap: "", guidance: null, dispose: async () => {
|
|
17000
17018
|
} };
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
|
|
17008
|
-
|
|
17009
|
-
|
|
17010
|
-
|
|
17011
|
-
|
|
17012
|
-
|
|
17013
|
-
|
|
17014
|
-
|
|
17015
|
-
|
|
17016
|
-
|
|
17017
|
-
// process-local; no plugin is installed and no user config is changed.
|
|
17018
|
-
//
|
|
17019
|
-
// ``hermes_bootstrap`` must run before ``tui_gateway.server`` is imported:
|
|
17020
|
-
// the gateway spawn uses ``python -I``, so PYTHONPATH and the launcher's
|
|
17021
|
-
// activation are stripped. Hermes's own entry point (``tui_gateway/entry.py``)
|
|
17022
|
-
// imports this module first to put the selected dependency environment on
|
|
17023
|
-
// ``sys.path``; skipping it makes bare third-party imports (e.g.
|
|
17024
|
-
// ``hermes_yaml`` -> ``ruamel``) fail on interpreters whose site-packages
|
|
17025
|
-
// do not already carry Hermes's dependencies. ``hermes_bootstrap`` is
|
|
17026
|
-
// import-safe here for the same reason entry.py relies on it: stdlib-only
|
|
17027
|
-
// at import time, so nothing can shadow it from the launch directory.
|
|
17028
|
-
bootstrap: `import hermes_bootstrap
|
|
17019
|
+
return {
|
|
17020
|
+
environment,
|
|
17021
|
+
// Reserve RPC stdout before native plugin imports.
|
|
17022
|
+
//
|
|
17023
|
+
// ``hermes_bootstrap`` must run before ``tui_gateway.server`` is imported:
|
|
17024
|
+
// the gateway spawn uses ``python -I``, so PYTHONPATH and the launcher's
|
|
17025
|
+
// activation are stripped. Hermes's own entry point (``tui_gateway/entry.py``)
|
|
17026
|
+
// imports this module first to put the selected dependency environment on
|
|
17027
|
+
// ``sys.path``; skipping it makes bare third-party imports (e.g.
|
|
17028
|
+
// ``hermes_yaml`` -> ``ruamel``) fail on interpreters whose site-packages
|
|
17029
|
+
// do not already carry Hermes's dependencies. ``hermes_bootstrap`` is
|
|
17030
|
+
// import-safe here for the same reason entry.py relies on it: stdlib-only
|
|
17031
|
+
// at import time, so nothing can shadow it from the launch directory.
|
|
17032
|
+
bootstrap: `import sys
|
|
17033
|
+
import hermes_bootstrap
|
|
17034
|
+
_stdout = sys.stdout # tui_gateway.server redirects sys.stdout to sys.stderr at import (stdio-entry protection); this bridge owns stdout as its RPC channel to the host
|
|
17029
17035
|
from tui_gateway import server
|
|
17030
|
-
|
|
17031
|
-
from hermes_cli.plugins import PluginContext, PluginManifest, get_plugin_manager
|
|
17032
|
-
PluginContext(PluginManifest(name="codexhost-runtime"), get_plugin_manager()).register_skill(
|
|
17033
|
-
"delegation", Path(${JSON.stringify(file2)}))
|
|
17036
|
+
sys.stdout = _stdout
|
|
17034
17037
|
`,
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
17038
|
+
guidance: `${HERMES_DELEGATION_GUIDANCE}
|
|
17039
|
+
|
|
17040
|
+
Runtime identity for this Thread:
|
|
17041
|
+
|
|
17042
|
+
- CODEXHOST_CLI_PATH: ${environment.CODEXHOST_CLI_PATH}
|
|
17043
|
+
- CODEXHOST_RUNTIME_ENDPOINT: ${environment.CODEXHOST_RUNTIME_ENDPOINT}
|
|
17044
|
+
- CODEXHOST_RUNTIME_TOKEN: ${environment.CODEXHOST_RUNTIME_TOKEN}
|
|
17045
|
+
- CODEXHOST_THREAD_ID: ${environment.CODEXHOST_THREAD_ID}
|
|
17046
|
+
|
|
17047
|
+
(end of codexhost delegation note; the user's message follows)`,
|
|
17048
|
+
dispose: async () => {
|
|
17049
|
+
}
|
|
17050
|
+
};
|
|
17041
17051
|
}
|
|
17042
17052
|
|
|
17043
17053
|
// dist/hermes-transport.js
|
|
@@ -17071,8 +17081,87 @@ function gatewayRecord(value) {
|
|
|
17071
17081
|
function gatewayString(value) {
|
|
17072
17082
|
return typeof value === "string" ? value : "";
|
|
17073
17083
|
}
|
|
17074
|
-
var GATEWAY_LAUNCH = `import
|
|
17075
|
-
|
|
17084
|
+
var GATEWAY_LAUNCH = `import asyncio
|
|
17085
|
+
import sys
|
|
17086
|
+
|
|
17087
|
+
|
|
17088
|
+
async def _bridge():
|
|
17089
|
+
from hermes_constants import get_hermes_home
|
|
17090
|
+
from hermes_cli.gateway_client import _session_ticket, gateway_ws_target
|
|
17091
|
+
from hermes_cli.gateway_runtime import (
|
|
17092
|
+
attachable,
|
|
17093
|
+
ensure_gateway_runtime,
|
|
17094
|
+
gateway_profile_home,
|
|
17095
|
+
)
|
|
17096
|
+
from gateway.session_contract import CANONICAL_GATEWAY_PROTOCOL
|
|
17097
|
+
from websockets.asyncio.client import connect
|
|
17098
|
+
|
|
17099
|
+
home = gateway_profile_home(get_hermes_home())
|
|
17100
|
+
result = await asyncio.to_thread(ensure_gateway_runtime, home, idle_exit=True)
|
|
17101
|
+
if not attachable(result):
|
|
17102
|
+
detail = f" ({result.detail})" if result.detail else ""
|
|
17103
|
+
raise SystemExit(
|
|
17104
|
+
f"[bridge-exit] gateway not attachable: {result.state} "
|
|
17105
|
+
f"{result.reason_code or 'not ready'}{detail}"
|
|
17106
|
+
)
|
|
17107
|
+
endpoint = result.endpoint
|
|
17108
|
+
ticket = await asyncio.to_thread(_session_ticket, home, endpoint)
|
|
17109
|
+
url, protocols = gateway_ws_target(endpoint, ticket)
|
|
17110
|
+
|
|
17111
|
+
async with connect(
|
|
17112
|
+
url, subprotocols=protocols, open_timeout=10, max_size=8 * 1024 * 1024, proxy=None
|
|
17113
|
+
) as ws:
|
|
17114
|
+
if protocols and ws.subprotocol != CANONICAL_GATEWAY_PROTOCOL:
|
|
17115
|
+
raise SystemExit("[bridge-exit] gateway protocol mismatch; update/restart required")
|
|
17116
|
+
|
|
17117
|
+
loop = asyncio.get_running_loop()
|
|
17118
|
+
# A full prompt rides on ONE JSON-RPC line; StreamReader's default 64 KiB
|
|
17119
|
+
# line limit aborts the bridge on large pastes (LimitOverrunError), so the
|
|
17120
|
+
# stdin side matches the WebSocket side's 8 MiB frame ceiling.
|
|
17121
|
+
reader = asyncio.StreamReader(limit=8 * 1024 * 1024)
|
|
17122
|
+
await loop.connect_read_pipe(
|
|
17123
|
+
lambda: asyncio.StreamReaderProtocol(reader), sys.stdin
|
|
17124
|
+
)
|
|
17125
|
+
|
|
17126
|
+
async def pump_in():
|
|
17127
|
+
async for raw in reader:
|
|
17128
|
+
line = raw.decode("utf-8", "replace").strip()
|
|
17129
|
+
if line:
|
|
17130
|
+
await ws.send(line)
|
|
17131
|
+
|
|
17132
|
+
async def pump_out():
|
|
17133
|
+
async for raw in ws:
|
|
17134
|
+
if isinstance(raw, bytes):
|
|
17135
|
+
raw = raw.decode("utf-8", "replace")
|
|
17136
|
+
sys.stdout.write(raw + "\\n")
|
|
17137
|
+
sys.stdout.flush()
|
|
17138
|
+
|
|
17139
|
+
pump_out_task = asyncio.create_task(pump_out())
|
|
17140
|
+
pump_in_task = asyncio.create_task(pump_in())
|
|
17141
|
+
# stdin EOF (host closed us) or socket close (gateway went away): end both.
|
|
17142
|
+
done, _pending = await asyncio.wait(
|
|
17143
|
+
{pump_in_task, pump_out_task}, return_when=asyncio.FIRST_COMPLETED
|
|
17144
|
+
)
|
|
17145
|
+
for task in (pump_in_task, pump_out_task):
|
|
17146
|
+
task.cancel()
|
|
17147
|
+
for task in done:
|
|
17148
|
+
if task.cancelled():
|
|
17149
|
+
continue
|
|
17150
|
+
exc = task.exception()
|
|
17151
|
+
if exc is not None:
|
|
17152
|
+
raise exc
|
|
17153
|
+
|
|
17154
|
+
|
|
17155
|
+
# No __main__ guard: the native launcher spawns this through exec(script, {})
|
|
17156
|
+
# whose fresh globals lack __name__; top-level code runs in both the legacy
|
|
17157
|
+
# (-c) and native (exec) spawn forms.
|
|
17158
|
+
try:
|
|
17159
|
+
asyncio.run(_bridge())
|
|
17160
|
+
except SystemExit:
|
|
17161
|
+
raise
|
|
17162
|
+
except Exception as exc:
|
|
17163
|
+
raise SystemExit(f"[bridge-exit] bridge failed: {type(exc).__name__}: {exc}")
|
|
17164
|
+
`;
|
|
17076
17165
|
var HermesGatewayTransport = class _HermesGatewayTransport {
|
|
17077
17166
|
runtime;
|
|
17078
17167
|
cwd;
|
|
@@ -17099,6 +17188,18 @@ var HermesGatewayTransport = class _HermesGatewayTransport {
|
|
|
17099
17188
|
this.environment = environment;
|
|
17100
17189
|
this.timeoutMs = timeoutMs;
|
|
17101
17190
|
}
|
|
17191
|
+
/** Model-facing delegation guidance for this Thread, or null without delegation. */
|
|
17192
|
+
get delegationGuidance() {
|
|
17193
|
+
return this.#delegation?.guidance ?? null;
|
|
17194
|
+
}
|
|
17195
|
+
/** Whether start() already ran (a warm transport skips prepare/start on reuse). */
|
|
17196
|
+
get started() {
|
|
17197
|
+
return this.#startRequested;
|
|
17198
|
+
}
|
|
17199
|
+
/** Whether the bridge child is gone; a closed transport cannot be reused. */
|
|
17200
|
+
get closed() {
|
|
17201
|
+
return this.#closed;
|
|
17202
|
+
}
|
|
17102
17203
|
static async probe(executable, cwd, environment) {
|
|
17103
17204
|
const override = environment.CODEXHOST_HERMES_GATEWAY_PYTHON;
|
|
17104
17205
|
if (override) {
|
|
@@ -17611,7 +17712,7 @@ async function resolveHermesSessionCandidate(input) {
|
|
|
17611
17712
|
}
|
|
17612
17713
|
|
|
17613
17714
|
// dist/command.js
|
|
17614
|
-
import
|
|
17715
|
+
import path5 from "node:path";
|
|
17615
17716
|
var HermesExecutableError = class extends Error {
|
|
17616
17717
|
code = "HERMES_NOT_FOUND";
|
|
17617
17718
|
};
|
|
@@ -17634,7 +17735,62 @@ function resolveHermesExecutable(input = {}) {
|
|
|
17634
17735
|
});
|
|
17635
17736
|
if (!resolution)
|
|
17636
17737
|
throw new HermesExecutableError("Hermes CLI is not installed");
|
|
17637
|
-
return targetPath(platform).isAbsolute(resolution.executable) ? resolution.executable :
|
|
17738
|
+
return targetPath(platform).isAbsolute(resolution.executable) ? resolution.executable : path5.resolve(resolution.executable);
|
|
17739
|
+
}
|
|
17740
|
+
|
|
17741
|
+
// dist/gateway-transport-pool.js
|
|
17742
|
+
function sameRuntime(a, b) {
|
|
17743
|
+
if (typeof a === "string" || typeof b === "string")
|
|
17744
|
+
return a === b;
|
|
17745
|
+
return a.launcher === b.launcher;
|
|
17746
|
+
}
|
|
17747
|
+
var ENVIRONMENT_IDENTITY_KEYS = ["HERMES_HOME", "HERMES_TUI_SKILLS"];
|
|
17748
|
+
function environmentIdentity(environment) {
|
|
17749
|
+
return ENVIRONMENT_IDENTITY_KEYS.map((key) => `${key}=${environment[key] ?? ""}`).join("\0");
|
|
17750
|
+
}
|
|
17751
|
+
function sameBridge(transport, runtime, cwd, environment) {
|
|
17752
|
+
return sameRuntime(transport.runtime, runtime) && transport.cwd === cwd && environmentIdentity(transport.environment) === environmentIdentity(environment);
|
|
17753
|
+
}
|
|
17754
|
+
var GatewayTransportPool = class {
|
|
17755
|
+
#idle = [];
|
|
17756
|
+
#capacity;
|
|
17757
|
+
#closed = false;
|
|
17758
|
+
constructor(capacity = 2) {
|
|
17759
|
+
this.#capacity = Math.max(1, capacity);
|
|
17760
|
+
}
|
|
17761
|
+
/** A healthy started bridge equivalent to a fresh spawn for these inputs, or null. */
|
|
17762
|
+
acquire(runtime, cwd, environment) {
|
|
17763
|
+
while (this.#idle.length > 0) {
|
|
17764
|
+
const index = this.#idle.findIndex((transport2) => sameBridge(transport2, runtime, cwd, environment));
|
|
17765
|
+
const transport = index >= 0 ? this.#idle.splice(index, 1)[0] : void 0;
|
|
17766
|
+
if (transport === void 0)
|
|
17767
|
+
return null;
|
|
17768
|
+
if (!transport.closed && transport.started)
|
|
17769
|
+
return transport;
|
|
17770
|
+
void transport.close().catch(() => void 0);
|
|
17771
|
+
}
|
|
17772
|
+
return null;
|
|
17773
|
+
}
|
|
17774
|
+
/** Return a bridge after its session settled; unhealthy or late ones are discarded. */
|
|
17775
|
+
release(transport) {
|
|
17776
|
+
if (transport.closed || this.#closed || this.#idle.length >= this.#capacity) {
|
|
17777
|
+
void transport.close().catch(() => void 0);
|
|
17778
|
+
return;
|
|
17779
|
+
}
|
|
17780
|
+
this.#idle.push(transport);
|
|
17781
|
+
}
|
|
17782
|
+
async close() {
|
|
17783
|
+
this.#closed = true;
|
|
17784
|
+
const transports = this.#idle;
|
|
17785
|
+
this.#idle = [];
|
|
17786
|
+
await Promise.all(transports.map((transport) => transport.close().catch(() => void 0)));
|
|
17787
|
+
}
|
|
17788
|
+
};
|
|
17789
|
+
async function startGatewayTransport(runtime, cwd, environment, timeoutMs) {
|
|
17790
|
+
const transport = new HermesGatewayTransport(runtime, cwd, environment, timeoutMs);
|
|
17791
|
+
await transport.prepareSession();
|
|
17792
|
+
await transport.start();
|
|
17793
|
+
return transport;
|
|
17638
17794
|
}
|
|
17639
17795
|
|
|
17640
17796
|
// dist/gateway-history.js
|
|
@@ -17724,21 +17880,24 @@ def capture(db):
|
|
|
17724
17880
|
boundaries[str(row['id'])] = {'count': end, 'digest': digest(active[:end])}
|
|
17725
17881
|
return exported, {'rows': rows, 'derivable': derivable, 'boundaries': boundaries, 'physicalSessionId': sid}
|
|
17726
17882
|
|
|
17883
|
+
def ensure_session_row(db):
|
|
17884
|
+
if db.get_session(sid) is None:
|
|
17885
|
+
from hermes_constants import parse_reasoning_effort
|
|
17886
|
+
initial = {}
|
|
17887
|
+
if isinstance(p.get('provider'), str) and p['provider']: initial['provider'] = p['provider']
|
|
17888
|
+
if isinstance(p.get('model'), str) and p['model']: initial['model'] = p['model']
|
|
17889
|
+
if isinstance(p.get('reasoningEffort'), str):
|
|
17890
|
+
reasoning = parse_reasoning_effort(p['reasoningEffort'])
|
|
17891
|
+
if reasoning is not None: initial['reasoning_config'] = reasoning
|
|
17892
|
+
if isinstance(p.get('yolo'), bool): initial['yolo_mode'] = p['yolo']
|
|
17893
|
+
db.create_session(session_id=sid, source='cli', cwd=p['cwd'], model=p.get('model'), model_config=initial)
|
|
17894
|
+
return {'created': True}
|
|
17895
|
+
|
|
17727
17896
|
try:
|
|
17728
17897
|
if p['operation'] == 'ensure':
|
|
17729
17898
|
db = SessionDB()
|
|
17730
17899
|
try:
|
|
17731
|
-
|
|
17732
|
-
from hermes_constants import parse_reasoning_effort
|
|
17733
|
-
initial = {}
|
|
17734
|
-
if isinstance(p.get('provider'), str) and p['provider']: initial['provider'] = p['provider']
|
|
17735
|
-
if isinstance(p.get('model'), str) and p['model']: initial['model'] = p['model']
|
|
17736
|
-
if isinstance(p.get('reasoningEffort'), str):
|
|
17737
|
-
reasoning = parse_reasoning_effort(p['reasoningEffort'])
|
|
17738
|
-
if reasoning is not None: initial['reasoning_config'] = reasoning
|
|
17739
|
-
if isinstance(p.get('yolo'), bool): initial['yolo_mode'] = p['yolo']
|
|
17740
|
-
db.create_session(session_id=sid, source='cli', cwd=p['cwd'], model=p.get('model'), model_config=initial)
|
|
17741
|
-
result = {'created': True}
|
|
17900
|
+
result = ensure_session_row(db)
|
|
17742
17901
|
finally: db.close()
|
|
17743
17902
|
elif p['operation'] == 'discard':
|
|
17744
17903
|
child = p['derivedSessionId']
|
|
@@ -18106,28 +18265,6 @@ var HermesUsage = class {
|
|
|
18106
18265
|
}
|
|
18107
18266
|
};
|
|
18108
18267
|
|
|
18109
|
-
// dist/gateway-configuration.js
|
|
18110
|
-
import { execFile as execFile4 } from "node:child_process";
|
|
18111
|
-
import { promisify as promisify3 } from "node:util";
|
|
18112
|
-
async function resolveGatewayModel(transport, modelId) {
|
|
18113
|
-
if (/\s/u.test(modelId) || modelId.startsWith("-"))
|
|
18114
|
-
throw new Error("Invalid Hermes Model identifier");
|
|
18115
|
-
const command = await hermesPythonCommand(transport.runtime, `import json
|
|
18116
|
-
from hermes_cli.models import parse_model_input
|
|
18117
|
-
p,m=parse_model_input(${JSON.stringify(modelId)}, '')
|
|
18118
|
-
print(json.dumps({'provider':p,'model':m}))`, { ...process.env, ...transport.environment });
|
|
18119
|
-
const result = await promisify3(execFile4)(command.command, command.arguments, {
|
|
18120
|
-
cwd: transport.cwd,
|
|
18121
|
-
env: { ...process.env, ...transport.environment },
|
|
18122
|
-
timeout: 2e4,
|
|
18123
|
-
maxBuffer: 1024 * 1024
|
|
18124
|
-
});
|
|
18125
|
-
const value = JSON.parse(result.stdout.trim());
|
|
18126
|
-
if (!value || typeof value !== "object" || !("provider" in value) || !("model" in value) || typeof value.provider !== "string" || typeof value.model !== "string")
|
|
18127
|
-
throw new Error("Hermes returned an invalid Model choice");
|
|
18128
|
-
return { provider: value.provider, model: value.model };
|
|
18129
|
-
}
|
|
18130
|
-
|
|
18131
18268
|
// dist/gateway-session-transport.js
|
|
18132
18269
|
var hermesGatewayThinkingOptions = [
|
|
18133
18270
|
"none",
|
|
@@ -18159,14 +18296,14 @@ function gatewayDiff(text2) {
|
|
|
18159
18296
|
if (!text2 || text2.length > 1024 * 1024)
|
|
18160
18297
|
return [];
|
|
18161
18298
|
const result = [];
|
|
18162
|
-
let
|
|
18299
|
+
let path8 = "";
|
|
18163
18300
|
let inHunk = false;
|
|
18164
18301
|
let oldLines = [], newLines = [];
|
|
18165
18302
|
const flush = () => {
|
|
18166
|
-
if (
|
|
18303
|
+
if (path8)
|
|
18167
18304
|
result.push({
|
|
18168
18305
|
type: "diff",
|
|
18169
|
-
path:
|
|
18306
|
+
path: path8,
|
|
18170
18307
|
oldText: oldLines.join("\n"),
|
|
18171
18308
|
newText: newLines.join("\n")
|
|
18172
18309
|
});
|
|
@@ -18179,24 +18316,24 @@ function gatewayDiff(text2) {
|
|
|
18179
18316
|
if (header) {
|
|
18180
18317
|
flush();
|
|
18181
18318
|
inHunk = false;
|
|
18182
|
-
|
|
18319
|
+
path8 = (header[2] === "/dev/null" ? header[1] ?? "" : header[2] ?? "").replace(/^[ab]\//u, "");
|
|
18183
18320
|
continue;
|
|
18184
18321
|
}
|
|
18185
18322
|
if (line.startsWith("--- ") && !inHunk) {
|
|
18186
18323
|
flush();
|
|
18187
|
-
|
|
18324
|
+
path8 = line.slice(4).replace(/^a\//u, "");
|
|
18188
18325
|
} else if (line.startsWith("+++ ") && !inHunk) {
|
|
18189
18326
|
const next = line.slice(4);
|
|
18190
18327
|
if (next !== "/dev/null")
|
|
18191
|
-
|
|
18328
|
+
path8 = next.replace(/^b\//u, "");
|
|
18192
18329
|
} else if (line.startsWith("@@")) {
|
|
18193
18330
|
inHunk = true;
|
|
18194
18331
|
continue;
|
|
18195
|
-
} else if (
|
|
18332
|
+
} else if (path8 && line.startsWith("-"))
|
|
18196
18333
|
oldLines.push(line.slice(1));
|
|
18197
|
-
else if (
|
|
18334
|
+
else if (path8 && line.startsWith("+"))
|
|
18198
18335
|
newLines.push(line.slice(1));
|
|
18199
|
-
else if (
|
|
18336
|
+
else if (path8 && line.startsWith(" ")) {
|
|
18200
18337
|
oldLines.push(line.slice(1));
|
|
18201
18338
|
newLines.push(line.slice(1));
|
|
18202
18339
|
}
|
|
@@ -18220,7 +18357,7 @@ var HermesGatewaySessionTransport = class {
|
|
|
18220
18357
|
return this.#commands;
|
|
18221
18358
|
}
|
|
18222
18359
|
async getCommands() {
|
|
18223
|
-
const params = { session_id: this.sessionId
|
|
18360
|
+
const params = { session_id: this.sessionId };
|
|
18224
18361
|
const [response, catalog] = await Promise.all([
|
|
18225
18362
|
this.transport.request("complete.slash", { ...params, text: "/" }, this.transport.timeoutMs, false),
|
|
18226
18363
|
this.transport.request("commands.catalog", params, this.transport.timeoutMs, false)
|
|
@@ -18245,13 +18382,29 @@ var HermesGatewaySessionTransport = class {
|
|
|
18245
18382
|
history;
|
|
18246
18383
|
#active = null;
|
|
18247
18384
|
#requests = /* @__PURE__ */ new Map();
|
|
18385
|
+
/** Open approval server requests by their payload request_id, for approval.cancelled. */
|
|
18386
|
+
#approvalRequests = /* @__PURE__ */ new Map();
|
|
18387
|
+
/** Pending approval prompts adopted from the create/resume snapshot. */
|
|
18388
|
+
#adoptedPrompts = [];
|
|
18248
18389
|
#closed = false;
|
|
18249
18390
|
#info;
|
|
18250
|
-
|
|
18391
|
+
#revision = null;
|
|
18392
|
+
#generation = null;
|
|
18393
|
+
#subscriptionId = null;
|
|
18394
|
+
/** Thread's delegation guidance, injected as api_text on the first turn only. */
|
|
18395
|
+
#delegationGuidance;
|
|
18396
|
+
constructor(transport, sessionId, nativeSessionId, info, bookkeeping = {}, delegationGuidance = null) {
|
|
18251
18397
|
this.transport = transport;
|
|
18252
18398
|
this.sessionId = sessionId;
|
|
18253
18399
|
this.nativeSessionId = nativeSessionId;
|
|
18254
18400
|
this.#info = info;
|
|
18401
|
+
this.#delegationGuidance = delegationGuidance;
|
|
18402
|
+
if (typeof bookkeeping.revision === "number")
|
|
18403
|
+
this.#revision = bookkeeping.revision;
|
|
18404
|
+
if (typeof bookkeeping.generation === "number")
|
|
18405
|
+
this.#generation = bookkeeping.generation;
|
|
18406
|
+
if (typeof bookkeeping.subscriptionId === "string")
|
|
18407
|
+
this.#subscriptionId = bookkeeping.subscriptionId;
|
|
18255
18408
|
this.history = new HermesGatewayHistory({
|
|
18256
18409
|
python: transport.runtime,
|
|
18257
18410
|
cwd: transport.cwd,
|
|
@@ -18312,17 +18465,24 @@ var HermesGatewaySessionTransport = class {
|
|
|
18312
18465
|
return optionId;
|
|
18313
18466
|
}
|
|
18314
18467
|
async setModel(modelId) {
|
|
18315
|
-
const
|
|
18316
|
-
const
|
|
18317
|
-
|
|
18318
|
-
|
|
18319
|
-
|
|
18320
|
-
session_id: this.sessionId
|
|
18468
|
+
const revision = this.#revision;
|
|
18469
|
+
const generation = this.#generation;
|
|
18470
|
+
if (revision === null || generation === null)
|
|
18471
|
+
throw new Error("Hermes gateway Session revision is not known yet");
|
|
18472
|
+
const result = await this.transport.request("session.mutate", {
|
|
18473
|
+
session_id: this.sessionId,
|
|
18474
|
+
request_id: `codexhost-model-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
18475
|
+
expected_revision: revision,
|
|
18476
|
+
expected_generation: generation,
|
|
18477
|
+
operation: "model",
|
|
18478
|
+
payload: { model: modelId }
|
|
18321
18479
|
});
|
|
18322
|
-
if (result.
|
|
18323
|
-
|
|
18324
|
-
|
|
18325
|
-
|
|
18480
|
+
if (typeof result.revision === "number")
|
|
18481
|
+
this.#revision = result.revision;
|
|
18482
|
+
if (typeof result.execution_generation === "number")
|
|
18483
|
+
this.#generation = result.execution_generation;
|
|
18484
|
+
const actualModel = gatewayString(result.model);
|
|
18485
|
+
const actualProvider = gatewayString(result.provider);
|
|
18326
18486
|
if (modelId !== actualModel && modelId !== `${actualProvider}:${actualModel}`)
|
|
18327
18487
|
throw new Error("Hermes did not confirm the requested Model");
|
|
18328
18488
|
}
|
|
@@ -18332,11 +18492,11 @@ var HermesGatewaySessionTransport = class {
|
|
|
18332
18492
|
const result = await this.transport.request("config.set", {
|
|
18333
18493
|
key: "yolo",
|
|
18334
18494
|
value: modeId === "dont_ask" ? "on" : "off",
|
|
18335
|
-
scope: "session",
|
|
18336
18495
|
session_id: this.sessionId
|
|
18337
18496
|
});
|
|
18338
|
-
if (result.value !== (modeId === "dont_ask" ? "1" : "0")
|
|
18497
|
+
if (result.value !== (modeId === "dont_ask" ? "1" : "0"))
|
|
18339
18498
|
throw new Error("Hermes effective approval policy differs from the requested mode; check native global approvals policy");
|
|
18499
|
+
this.#info = { ...this.#info, yolo: modeId === "dont_ask" };
|
|
18340
18500
|
}
|
|
18341
18501
|
nativeCommandName(text2) {
|
|
18342
18502
|
return hermesGatewayCommandName(text2, this.#commands);
|
|
@@ -18359,9 +18519,11 @@ var HermesGatewaySessionTransport = class {
|
|
|
18359
18519
|
reject: rejectResult,
|
|
18360
18520
|
streamed: "",
|
|
18361
18521
|
reasoning: "",
|
|
18362
|
-
toolIds: /* @__PURE__ */ new Set()
|
|
18522
|
+
toolIds: /* @__PURE__ */ new Set(),
|
|
18523
|
+
admissionId: null
|
|
18363
18524
|
};
|
|
18364
18525
|
this.#active = active;
|
|
18526
|
+
void this.#adoptedPrompts.splice(0).map((prompt) => void this.#respondAdoptedApproval(prompt, active).catch(() => void 0));
|
|
18365
18527
|
const commandText = text2.trim();
|
|
18366
18528
|
const nativeCommand = this.nativeCommandName(text2);
|
|
18367
18529
|
try {
|
|
@@ -18400,12 +18562,21 @@ var HermesGatewaySessionTransport = class {
|
|
|
18400
18562
|
emit({ type: "agent.text", text: response.output });
|
|
18401
18563
|
active.resolve({ stopReason: "end_turn" });
|
|
18402
18564
|
} else {
|
|
18565
|
+
const guidance = this.#delegationGuidance;
|
|
18566
|
+
this.#delegationGuidance = null;
|
|
18403
18567
|
const submitted = await this.transport.request("prompt.submit", {
|
|
18404
18568
|
session_id: this.sessionId,
|
|
18405
|
-
text: text2
|
|
18569
|
+
text: text2,
|
|
18570
|
+
submission_id: `codexhost-turn-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
18571
|
+
clarify_batch: true,
|
|
18572
|
+
...guidance ? { api_text: `${guidance}
|
|
18573
|
+
|
|
18574
|
+
${text2}` } : {}
|
|
18406
18575
|
});
|
|
18407
|
-
if (submitted.status !== "
|
|
18408
|
-
this.#fault(new Error(`Hermes did not
|
|
18576
|
+
if (submitted.status !== "queued" && submitted.status !== "started")
|
|
18577
|
+
this.#fault(new Error(`Hermes did not accept the turn (${String(submitted.status)})`));
|
|
18578
|
+
else if (active.admissionId === null && typeof submitted.admission_id === "string")
|
|
18579
|
+
active.admissionId = submitted.admission_id;
|
|
18409
18580
|
}
|
|
18410
18581
|
} catch (error51) {
|
|
18411
18582
|
active.reject(error51 instanceof Error ? error51 : new Error(String(error51)));
|
|
@@ -18421,7 +18592,12 @@ var HermesGatewaySessionTransport = class {
|
|
|
18421
18592
|
}
|
|
18422
18593
|
}
|
|
18423
18594
|
async cancel() {
|
|
18424
|
-
|
|
18595
|
+
if (this.#generation === null)
|
|
18596
|
+
return;
|
|
18597
|
+
await this.transport.request("session.interrupt", {
|
|
18598
|
+
session_id: this.sessionId,
|
|
18599
|
+
execution_generation: this.#generation
|
|
18600
|
+
});
|
|
18425
18601
|
}
|
|
18426
18602
|
async close() {
|
|
18427
18603
|
if (this.#closed)
|
|
@@ -18432,10 +18608,13 @@ var HermesGatewaySessionTransport = class {
|
|
|
18432
18608
|
this.#requests.clear();
|
|
18433
18609
|
this.#active?.reject(new Error("Hermes gateway Session closed"));
|
|
18434
18610
|
try {
|
|
18435
|
-
|
|
18611
|
+
if (this.#subscriptionId !== null)
|
|
18612
|
+
await this.transport.request("session.detach", {
|
|
18613
|
+
session_id: this.sessionId,
|
|
18614
|
+
subscription_id: this.#subscriptionId
|
|
18615
|
+
});
|
|
18436
18616
|
} catch {
|
|
18437
18617
|
}
|
|
18438
|
-
await this.transport.close();
|
|
18439
18618
|
}
|
|
18440
18619
|
#fault(error51) {
|
|
18441
18620
|
if (this.#closed)
|
|
@@ -18455,6 +18634,10 @@ var HermesGatewaySessionTransport = class {
|
|
|
18455
18634
|
const payload = gatewayRecord(event.payload);
|
|
18456
18635
|
if (event.type === "session.info") {
|
|
18457
18636
|
this.#info = payload;
|
|
18637
|
+
if (typeof payload.revision === "number")
|
|
18638
|
+
this.#revision = payload.revision;
|
|
18639
|
+
if (typeof payload.execution_generation === "number")
|
|
18640
|
+
this.#generation = payload.execution_generation;
|
|
18458
18641
|
return;
|
|
18459
18642
|
}
|
|
18460
18643
|
if (event.type === "session.usage") {
|
|
@@ -18466,12 +18649,26 @@ var HermesGatewaySessionTransport = class {
|
|
|
18466
18649
|
controller?.abort(payload.reason === "timeout" ? "expired" : "cancelled");
|
|
18467
18650
|
return;
|
|
18468
18651
|
}
|
|
18652
|
+
if (event.type === "approval.cancelled") {
|
|
18653
|
+
const ids = Array.isArray(payload.request_ids) ? payload.request_ids.filter((id) => typeof id === "string") : [];
|
|
18654
|
+
for (const id of ids) {
|
|
18655
|
+
this.#approvalRequests.get(id)?.abort("cancelled");
|
|
18656
|
+
this.#approvalRequests.delete(id);
|
|
18657
|
+
}
|
|
18658
|
+
return;
|
|
18659
|
+
}
|
|
18469
18660
|
const active = this.#active;
|
|
18470
18661
|
if (!active) {
|
|
18471
18662
|
if (event.type === "error")
|
|
18472
18663
|
this.#fault(new Error(gatewayString(payload.message)));
|
|
18473
18664
|
return;
|
|
18474
18665
|
}
|
|
18666
|
+
const eventAdmission = gatewayString(event.admission_id);
|
|
18667
|
+
const eventType = gatewayString(event.type);
|
|
18668
|
+
if (eventAdmission && active.admissionId && eventAdmission !== active.admissionId) {
|
|
18669
|
+
if (eventType.startsWith("message.") || eventType.startsWith("reasoning."))
|
|
18670
|
+
return;
|
|
18671
|
+
}
|
|
18475
18672
|
const text2 = gatewayString(payload.text);
|
|
18476
18673
|
if (event.type === "message.delta") {
|
|
18477
18674
|
active.streamed += text2;
|
|
@@ -18602,27 +18799,80 @@ var HermesGatewaySessionTransport = class {
|
|
|
18602
18799
|
label: choice === "session" ? "Allow for this session" : "Always allow"
|
|
18603
18800
|
}
|
|
18604
18801
|
] : choice === "deny" ? [{ id: "deny", effect: "deny", label: "Deny" }] : []);
|
|
18605
|
-
const
|
|
18606
|
-
|
|
18607
|
-
|
|
18608
|
-
|
|
18609
|
-
|
|
18610
|
-
|
|
18611
|
-
|
|
18612
|
-
|
|
18613
|
-
|
|
18802
|
+
const payloadRequestId = gatewayString(params.request_id);
|
|
18803
|
+
if (payloadRequestId)
|
|
18804
|
+
this.#approvalRequests.set(payloadRequestId, controller);
|
|
18805
|
+
try {
|
|
18806
|
+
const response = await active.permission({
|
|
18807
|
+
signal: controller.signal,
|
|
18808
|
+
title: gatewayString(params.description) || gatewayString(params.command),
|
|
18809
|
+
description: gatewayString(params.command) || gatewayString(params.description),
|
|
18810
|
+
options
|
|
18614
18811
|
});
|
|
18812
|
+
if (!controller.signal.aborted)
|
|
18813
|
+
this.transport.respond(id, {
|
|
18814
|
+
choice: response ?? "deny"
|
|
18815
|
+
});
|
|
18816
|
+
} finally {
|
|
18817
|
+
if (payloadRequestId)
|
|
18818
|
+
this.#approvalRequests.delete(payloadRequestId);
|
|
18819
|
+
}
|
|
18615
18820
|
} else
|
|
18616
18821
|
this.transport.rejectRequest(id);
|
|
18617
18822
|
} finally {
|
|
18618
18823
|
this.#requests.delete(id);
|
|
18619
18824
|
}
|
|
18620
18825
|
}
|
|
18826
|
+
/** Keep approval prompts from the create/resume snapshot for the next turn. */
|
|
18827
|
+
adoptPendingPrompts(prompts) {
|
|
18828
|
+
if (!Array.isArray(prompts))
|
|
18829
|
+
return;
|
|
18830
|
+
for (const entry of prompts) {
|
|
18831
|
+
const prompt = gatewayRecord(entry);
|
|
18832
|
+
if (gatewayString(prompt.kind) === "approval" && gatewayString(prompt.prompt_id))
|
|
18833
|
+
this.#adoptedPrompts.push(prompt);
|
|
18834
|
+
}
|
|
18835
|
+
}
|
|
18836
|
+
/**
|
|
18837
|
+
* Answer a snapshot-adopted approval through canonical `approval.respond`.
|
|
18838
|
+
* Clarify prompts are deliberately not answered here: a live clarify
|
|
18839
|
+
* question is served by the `clarify` server request (batch mode), and the
|
|
18840
|
+
* gateway re-issues still-open server requests to an attaching client.
|
|
18841
|
+
*/
|
|
18842
|
+
async #respondAdoptedApproval(prompt, active) {
|
|
18843
|
+
if (this.#closed)
|
|
18844
|
+
return;
|
|
18845
|
+
const promptId = gatewayString(prompt.prompt_id);
|
|
18846
|
+
const generation = prompt.execution_generation;
|
|
18847
|
+
const choices = Array.isArray(prompt.choices) ? prompt.choices.filter((choice) => typeof choice === "string") : ["once", "deny"];
|
|
18848
|
+
const options = choices.flatMap((choice) => choice === "once" ? [{ id: "once", effect: "allowOnce", label: "Allow once" }] : choice === "session" || choice === "always" ? [
|
|
18849
|
+
{
|
|
18850
|
+
id: choice,
|
|
18851
|
+
effect: choice === "session" ? "allowForSession" : "allowAlways",
|
|
18852
|
+
label: choice === "session" ? "Allow for this session" : "Always allow"
|
|
18853
|
+
}
|
|
18854
|
+
] : choice === "deny" ? [{ id: "deny", effect: "deny", label: "Deny" }] : []);
|
|
18855
|
+
const response = await active.permission({
|
|
18856
|
+
signal: new AbortController().signal,
|
|
18857
|
+
title: gatewayString(prompt.description) || gatewayString(prompt.command) || "Hermes approval requested before this Session attached",
|
|
18858
|
+
description: gatewayString(prompt.command) || gatewayString(prompt.description),
|
|
18859
|
+
options
|
|
18860
|
+
});
|
|
18861
|
+
if (this.#closed)
|
|
18862
|
+
return;
|
|
18863
|
+
if (typeof generation === "number")
|
|
18864
|
+
await this.transport.request("approval.respond", {
|
|
18865
|
+
session_id: this.sessionId,
|
|
18866
|
+
execution_generation: generation,
|
|
18867
|
+
prompt_id: promptId,
|
|
18868
|
+
choice: response ?? "deny"
|
|
18869
|
+
}, this.transport.timeoutMs, false);
|
|
18870
|
+
}
|
|
18621
18871
|
};
|
|
18622
18872
|
|
|
18623
18873
|
// dist/usage-statistics.js
|
|
18624
|
-
import
|
|
18625
|
-
import
|
|
18874
|
+
import os2 from "node:os";
|
|
18875
|
+
import path6 from "node:path";
|
|
18626
18876
|
import { lstat } from "node:fs/promises";
|
|
18627
18877
|
|
|
18628
18878
|
// ../../harness-adapter/dist/usage-statistics.js
|
|
@@ -18682,9 +18932,9 @@ function usageEntryFromRequest(request, occurredAtMs) {
|
|
|
18682
18932
|
|
|
18683
18933
|
// dist/usage-statistics.js
|
|
18684
18934
|
function hermesStateDatabasePath(environment) {
|
|
18685
|
-
const home = environment.HOME || environment.USERPROFILE ||
|
|
18935
|
+
const home = environment.HOME || environment.USERPROFILE || os2.homedir();
|
|
18686
18936
|
const configured = environment.HERMES_HOME;
|
|
18687
|
-
return
|
|
18937
|
+
return path6.resolve(configured ? path6.join(configured, "state.db") : path6.join(home, ".hermes", "state.db"));
|
|
18688
18938
|
}
|
|
18689
18939
|
async function fingerprint(file2) {
|
|
18690
18940
|
const info = await lstat(file2).catch(() => null);
|
|
@@ -18766,7 +19016,7 @@ function createHermesUsageStatistics(environment) {
|
|
|
18766
19016
|
}
|
|
18767
19017
|
|
|
18768
19018
|
// dist/gateway-open.js
|
|
18769
|
-
import
|
|
19019
|
+
import path7 from "node:path";
|
|
18770
19020
|
import { realpath } from "node:fs/promises";
|
|
18771
19021
|
|
|
18772
19022
|
// dist/hermes-session.js
|
|
@@ -18976,16 +19226,16 @@ var Diff = class {
|
|
|
18976
19226
|
}
|
|
18977
19227
|
}
|
|
18978
19228
|
}
|
|
18979
|
-
addToPath(
|
|
18980
|
-
const last =
|
|
19229
|
+
addToPath(path8, added, removed, oldPosInc, options) {
|
|
19230
|
+
const last = path8.lastComponent;
|
|
18981
19231
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
18982
19232
|
return {
|
|
18983
|
-
oldPos:
|
|
19233
|
+
oldPos: path8.oldPos + oldPosInc,
|
|
18984
19234
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
18985
19235
|
};
|
|
18986
19236
|
} else {
|
|
18987
19237
|
return {
|
|
18988
|
-
oldPos:
|
|
19238
|
+
oldPos: path8.oldPos + oldPosInc,
|
|
18989
19239
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
18990
19240
|
};
|
|
18991
19241
|
}
|
|
@@ -19300,8 +19550,8 @@ function hermesFileChanges(update) {
|
|
|
19300
19550
|
for (const block of update.content ?? []) {
|
|
19301
19551
|
if (block.type !== "diff")
|
|
19302
19552
|
continue;
|
|
19303
|
-
const { path:
|
|
19304
|
-
if (!
|
|
19553
|
+
const { path: path8, oldText, newText } = block;
|
|
19554
|
+
if (!path8.trim() || /[\0\r\n]/u.test(path8) || typeof newText !== "string")
|
|
19305
19555
|
continue;
|
|
19306
19556
|
if (oldText === newText)
|
|
19307
19557
|
continue;
|
|
@@ -19309,10 +19559,10 @@ function hermesFileChanges(update) {
|
|
|
19309
19559
|
if (bytes > MAX_DIFF_BYTES || changes.length === MAX_DIFFS)
|
|
19310
19560
|
return [];
|
|
19311
19561
|
changes.push({
|
|
19312
|
-
path:
|
|
19562
|
+
path: path8,
|
|
19313
19563
|
kind: "update",
|
|
19314
19564
|
diffScope: "fragment",
|
|
19315
|
-
unifiedDiff: createTwoFilesPatch(
|
|
19565
|
+
unifiedDiff: createTwoFilesPatch(path8, path8, oldText ?? "", newText, "", "", {
|
|
19316
19566
|
context: 3
|
|
19317
19567
|
})
|
|
19318
19568
|
});
|
|
@@ -20117,7 +20367,7 @@ ${reason}` }
|
|
|
20117
20367
|
|
|
20118
20368
|
// dist/gateway-open.js
|
|
20119
20369
|
async function sameDirectory(left, right) {
|
|
20120
|
-
return await realpath(left).catch(() =>
|
|
20370
|
+
return await realpath(left).catch(() => path7.resolve(left)) === await realpath(right).catch(() => path7.resolve(right));
|
|
20121
20371
|
}
|
|
20122
20372
|
var gatewayCapabilities = {
|
|
20123
20373
|
configuration: {
|
|
@@ -20179,8 +20429,10 @@ async function openGatewaySession(input, transport, onSettle, inheritedPermissio
|
|
|
20179
20429
|
let nativeRef = source;
|
|
20180
20430
|
let sourceHistory;
|
|
20181
20431
|
try {
|
|
20182
|
-
|
|
20183
|
-
|
|
20432
|
+
if (!transport.started) {
|
|
20433
|
+
await transport.prepareSession();
|
|
20434
|
+
await transport.start();
|
|
20435
|
+
}
|
|
20184
20436
|
if (source && (input.kind === "fork" || input.kind === "rollbackLastTurn")) {
|
|
20185
20437
|
sourceHistory = new HermesGatewayHistory({
|
|
20186
20438
|
python: transport.runtime,
|
|
@@ -20190,34 +20442,33 @@ async function openGatewaySession(input, transport, onSettle, inheritedPermissio
|
|
|
20190
20442
|
});
|
|
20191
20443
|
nativeRef = await sourceHistory.derive(input.kind === "fork" ? { checkpoint: input.checkpoint } : { rollbackLastTurn: true });
|
|
20192
20444
|
}
|
|
20193
|
-
const
|
|
20194
|
-
|
|
20195
|
-
|
|
20196
|
-
close_on_disconnect
|
|
20197
|
-
|
|
20198
|
-
|
|
20199
|
-
|
|
20445
|
+
const response = await transport.request(
|
|
20446
|
+
nativeRef ? "session.resume" : "session.create",
|
|
20447
|
+
// Canonical wire (hermes-gateway-v1, CanonicalCreateParams/CanonicalResumeParams):
|
|
20448
|
+
// no close_on_disconnect / eager_build keys, and the effort key is "reasoning".
|
|
20449
|
+
nativeRef ? { session_id: nativeRef.nativeSessionId, omit_messages: true } : {
|
|
20450
|
+
cwd: input.cwd,
|
|
20451
|
+
...model2 ? { model: model2 } : {},
|
|
20452
|
+
...input.kind === "create" && input.thinkingOptionId ? { reasoning: input.thinkingOptionId } : {}
|
|
20453
|
+
}
|
|
20454
|
+
);
|
|
20200
20455
|
const runtimeId = gatewayString(response.session_id);
|
|
20201
20456
|
const storedId = nativeRef?.nativeSessionId || gatewayString(response.stored_session_id);
|
|
20202
20457
|
if (!runtimeId || !storedId)
|
|
20203
20458
|
throw new Error("Hermes gateway did not return Session identity");
|
|
20204
|
-
|
|
20205
|
-
if (info.lazy === true)
|
|
20206
|
-
info = await transport.waitForSession(runtimeId);
|
|
20459
|
+
const info = gatewayRecord(response.info);
|
|
20207
20460
|
const nativeCwd = gatewayString(info.cwd);
|
|
20208
20461
|
if (nativeCwd && !await sameDirectory(nativeCwd, input.cwd))
|
|
20209
20462
|
throw new HermesGatewayHistoryError("unsupported", "Hermes resumed a different native working directory");
|
|
20210
|
-
const bridge = new HermesGatewaySessionTransport(transport, runtimeId, storedId, info
|
|
20211
|
-
|
|
20212
|
-
|
|
20213
|
-
|
|
20214
|
-
|
|
20215
|
-
|
|
20216
|
-
|
|
20217
|
-
|
|
20218
|
-
|
|
20219
|
-
if (gatewayString(info.stored_session_id) !== physicalId)
|
|
20220
|
-
throw new Error("Hermes live Session and persisted history identities differ");
|
|
20463
|
+
const bridge = new HermesGatewaySessionTransport(transport, runtimeId, storedId, info, {
|
|
20464
|
+
revision: response.revision,
|
|
20465
|
+
generation: response.execution_generation,
|
|
20466
|
+
subscriptionId: response.subscription_id
|
|
20467
|
+
}, transport.delegationGuidance);
|
|
20468
|
+
bridge.adoptPendingPrompts(response.prompts);
|
|
20469
|
+
if (nativeRef) {
|
|
20470
|
+
await bridge.history.resolvePhysicalSessionId();
|
|
20471
|
+
}
|
|
20221
20472
|
if (model2)
|
|
20222
20473
|
await bridge.setModel(model2);
|
|
20223
20474
|
if (input.kind !== "fork" && input.thinkingOptionId)
|
|
@@ -20269,6 +20520,7 @@ var HermesAdapter = class {
|
|
|
20269
20520
|
#importReads = /* @__PURE__ */ new Map();
|
|
20270
20521
|
#closed = false;
|
|
20271
20522
|
#gatewayTransports = /* @__PURE__ */ new Set();
|
|
20523
|
+
#gatewayPool = new GatewayTransportPool(2);
|
|
20272
20524
|
#gatewayProbes = /* @__PURE__ */ new Map();
|
|
20273
20525
|
#openingNativeIds = /* @__PURE__ */ new Set();
|
|
20274
20526
|
usageStatistics;
|
|
@@ -20384,9 +20636,10 @@ var HermesAdapter = class {
|
|
|
20384
20636
|
return failure("sessionBusy", "This Hermes Session already has an owner", true);
|
|
20385
20637
|
if (ref)
|
|
20386
20638
|
this.#openingNativeIds.add(ref.nativeSessionId);
|
|
20387
|
-
|
|
20388
|
-
this.#gatewayTransports.add(transport);
|
|
20639
|
+
let transport;
|
|
20389
20640
|
try {
|
|
20641
|
+
transport = this.#gatewayPool.acquire(runtime, input.cwd, environment) ?? await startGatewayTransport(runtime, input.cwd, environment, this.#options.commandTimeoutMs);
|
|
20642
|
+
this.#gatewayTransports.add(transport);
|
|
20390
20643
|
let inheritedMode;
|
|
20391
20644
|
if (input.kind === "fork") {
|
|
20392
20645
|
const source = [...this.#sessions].find((s) => s.initialState.nativeRef?.nativeSessionId === input.sourceRef.nativeSessionId);
|
|
@@ -20397,6 +20650,7 @@ var HermesAdapter = class {
|
|
|
20397
20650
|
const session = await openGatewaySession(input, transport, (settled) => {
|
|
20398
20651
|
this.#sessions.delete(settled);
|
|
20399
20652
|
this.#gatewayTransports.delete(transport);
|
|
20653
|
+
this.#gatewayPool.release(transport);
|
|
20400
20654
|
}, inheritedMode);
|
|
20401
20655
|
if (this.#closed) {
|
|
20402
20656
|
await session.close();
|
|
@@ -20405,8 +20659,10 @@ var HermesAdapter = class {
|
|
|
20405
20659
|
this.#sessions.add(session);
|
|
20406
20660
|
return { ok: true, value: session };
|
|
20407
20661
|
} catch (error51) {
|
|
20408
|
-
|
|
20409
|
-
|
|
20662
|
+
if (transport) {
|
|
20663
|
+
await transport.close().catch(() => void 0);
|
|
20664
|
+
this.#gatewayTransports.delete(transport);
|
|
20665
|
+
}
|
|
20410
20666
|
return failure(error51 instanceof HermesGatewayHistoryError ? error51.code : "nativeFailure", error51 instanceof Error ? error51.message : "Hermes gateway open failed");
|
|
20411
20667
|
} finally {
|
|
20412
20668
|
if (ref)
|
|
@@ -20430,6 +20686,7 @@ var HermesAdapter = class {
|
|
|
20430
20686
|
await Promise.all(sessions.map((session) => session.close().catch(() => void 0)));
|
|
20431
20687
|
await Promise.all([...this.#gatewayTransports].map((transport) => transport.close()));
|
|
20432
20688
|
this.#gatewayTransports.clear();
|
|
20689
|
+
await this.#gatewayPool.close();
|
|
20433
20690
|
}
|
|
20434
20691
|
#effectiveEnvironment(environment) {
|
|
20435
20692
|
return { ...this.#options.environment ?? process.env, ...environment ?? {} };
|