@hermespilot/link 0.7.7 → 0.7.8
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/{chunk-JQYZZDVU.js → chunk-7JPQICDK.js} +642 -275
- package/dist/cli/index.js +5 -3
- package/dist/http/app.js +1 -1
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ import Router from "@koa/router";
|
|
|
5
5
|
// src/conversations/conversation-service.ts
|
|
6
6
|
import { EventEmitter } from "events";
|
|
7
7
|
import { createHash as createHash6, randomUUID as randomUUID11 } from "crypto";
|
|
8
|
-
import
|
|
8
|
+
import path25 from "path";
|
|
9
9
|
|
|
10
10
|
// src/database/link-database.ts
|
|
11
11
|
import { mkdir } from "fs/promises";
|
|
@@ -2032,6 +2032,13 @@ function translateChineseKnownErrorToEnglish(message) {
|
|
|
2032
2032
|
if (restartFailed?.groups) {
|
|
2033
2033
|
return `Hermes Gateway restart failed.${restartFailed.groups.detail}`;
|
|
2034
2034
|
}
|
|
2035
|
+
if (message.startsWith("Hermes Link \u5DF2\u8FDE\u63A5\uFF0C\u4F46\u672C\u673A\u6267\u884C\u9762\u4E0D\u53EF\u7528\uFF1A")) {
|
|
2036
|
+
return [
|
|
2037
|
+
"Hermes Link is reachable, but the local Hermes execution backend is unavailable because the background service cannot find the `hermes` command.",
|
|
2038
|
+
"First run `hermeslink restart` on this computer to try to recover. If that fixes the App, run `hermeslink autostart on` afterwards to refresh the boot autostart environment so this does not happen again after the next reboot.",
|
|
2039
|
+
"If it still fails, run `hermeslink doctor` for diagnostics. If Hermes Agent is installed in a custom location, set HERMES_BIN to the full path of the `hermes` executable."
|
|
2040
|
+
].join("\n");
|
|
2041
|
+
}
|
|
2035
2042
|
const cliMissing = /^没有找到可用的 Hermes Agent CLI。请先安装 Hermes Agent,或设置 HERMES_BIN。(?<detail>.*)$/u.exec(message);
|
|
2036
2043
|
if (cliMissing?.groups) {
|
|
2037
2044
|
return `No usable Hermes Agent CLI was found. Install Hermes Agent or set HERMES_BIN.${cliMissing.groups.detail}`;
|
|
@@ -6547,7 +6554,7 @@ async function listCronOutputFiles(profileName, jobId) {
|
|
|
6547
6554
|
orderTimeMs: fileStat.mtimeMs
|
|
6548
6555
|
});
|
|
6549
6556
|
}
|
|
6550
|
-
return files.sort((left, right) => left.orderTimeMs - right.orderTimeMs).map(({ path:
|
|
6557
|
+
return files.sort((left, right) => left.orderTimeMs - right.orderTimeMs).map(({ path: path35, mtime }) => ({ path: path35, mtime }));
|
|
6551
6558
|
}
|
|
6552
6559
|
function readCronOutputTimestamp(fileName) {
|
|
6553
6560
|
const match = fileName.match(
|
|
@@ -6636,7 +6643,7 @@ function isConversationMissingError(error) {
|
|
|
6636
6643
|
}
|
|
6637
6644
|
|
|
6638
6645
|
// src/constants.ts
|
|
6639
|
-
var LINK_VERSION = "0.7.
|
|
6646
|
+
var LINK_VERSION = "0.7.8";
|
|
6640
6647
|
var LINK_COMMAND = "hermeslink";
|
|
6641
6648
|
var LINK_DEFAULT_PORT = 52379;
|
|
6642
6649
|
var LINK_RUNTIME_DIR_NAME = ".hermeslink";
|
|
@@ -6669,6 +6676,7 @@ function resolveRuntimePaths(homeDir = resolveRuntimeHome()) {
|
|
|
6669
6676
|
var defaultLinkConfig = {
|
|
6670
6677
|
port: LINK_DEFAULT_PORT,
|
|
6671
6678
|
lanHost: null,
|
|
6679
|
+
hermesBin: null,
|
|
6672
6680
|
serverBaseUrl: "https://hermes-server.clawpilot.me",
|
|
6673
6681
|
relayBaseUrl: "https://hermes-relay.clawpilot.me",
|
|
6674
6682
|
appConnectTokenIssuer: "https://hermes-server.clawpilot.me",
|
|
@@ -6680,6 +6688,7 @@ async function loadConfig(paths = resolveRuntimePaths()) {
|
|
|
6680
6688
|
const existing = await readJsonFile(paths.configFile);
|
|
6681
6689
|
const language = normalizeConfiguredLanguage(existing?.language);
|
|
6682
6690
|
const lanHost = normalizeLanHost(existing?.lanHost);
|
|
6691
|
+
const hermesBin = normalizeHermesBin(existing?.hermesBin);
|
|
6683
6692
|
const logLevel = normalizeLogLevel(
|
|
6684
6693
|
existing?.logLevel ?? process.env.HERMESLINK_LOG_LEVEL
|
|
6685
6694
|
);
|
|
@@ -6688,6 +6697,7 @@ async function loadConfig(paths = resolveRuntimePaths()) {
|
|
|
6688
6697
|
...existing ?? {},
|
|
6689
6698
|
language,
|
|
6690
6699
|
lanHost,
|
|
6700
|
+
hermesBin,
|
|
6691
6701
|
logLevel
|
|
6692
6702
|
};
|
|
6693
6703
|
}
|
|
@@ -6696,6 +6706,7 @@ async function saveConfig(patch, paths = resolveRuntimePaths()) {
|
|
|
6696
6706
|
const next = {
|
|
6697
6707
|
...current,
|
|
6698
6708
|
...patch,
|
|
6709
|
+
hermesBin: patch.hermesBin === void 0 ? current.hermesBin : normalizeHermesBin(patch.hermesBin),
|
|
6699
6710
|
logLevel: patch.logLevel === void 0 ? current.logLevel : normalizeLogLevel(patch.logLevel)
|
|
6700
6711
|
};
|
|
6701
6712
|
await writeJsonFile(paths.configFile, next);
|
|
@@ -6735,6 +6746,16 @@ function normalizeLanHost(value) {
|
|
|
6735
6746
|
}
|
|
6736
6747
|
return host;
|
|
6737
6748
|
}
|
|
6749
|
+
function normalizeHermesBin(value) {
|
|
6750
|
+
if (value === null || value === void 0) {
|
|
6751
|
+
return null;
|
|
6752
|
+
}
|
|
6753
|
+
if (typeof value !== "string") {
|
|
6754
|
+
return null;
|
|
6755
|
+
}
|
|
6756
|
+
const trimmed = value.trim();
|
|
6757
|
+
return trimmed || null;
|
|
6758
|
+
}
|
|
6738
6759
|
function isUsableLanIpv4(value) {
|
|
6739
6760
|
const parts = value.split(".").map((part) => Number.parseInt(part, 10));
|
|
6740
6761
|
if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) {
|
|
@@ -6904,9 +6925,8 @@ function readErrorMessage(payload) {
|
|
|
6904
6925
|
|
|
6905
6926
|
// src/hermes/gateway.ts
|
|
6906
6927
|
import { execFile as execFile2, spawn } from "child_process";
|
|
6907
|
-
import {
|
|
6908
|
-
import
|
|
6909
|
-
import path7 from "path";
|
|
6928
|
+
import { access, readFile as readFile5, stat as stat4 } from "fs/promises";
|
|
6929
|
+
import path8 from "path";
|
|
6910
6930
|
import { setTimeout as delay2 } from "timers/promises";
|
|
6911
6931
|
import { promisify as promisify2 } from "util";
|
|
6912
6932
|
|
|
@@ -7287,6 +7307,15 @@ function rotatedLogFile(filePath, index) {
|
|
|
7287
7307
|
|
|
7288
7308
|
// src/hermes/cli.ts
|
|
7289
7309
|
import { execFile } from "child_process";
|
|
7310
|
+
import {
|
|
7311
|
+
accessSync,
|
|
7312
|
+
constants as fsConstants,
|
|
7313
|
+
readFileSync,
|
|
7314
|
+
realpathSync,
|
|
7315
|
+
statSync
|
|
7316
|
+
} from "fs";
|
|
7317
|
+
import os4 from "os";
|
|
7318
|
+
import path7 from "path";
|
|
7290
7319
|
import { promisify } from "util";
|
|
7291
7320
|
var execFileAsync = promisify(execFile);
|
|
7292
7321
|
async function deleteHermesSession(sessionId, profileName = "default") {
|
|
@@ -7379,7 +7408,158 @@ async function renameHermesSession(sessionId, title, profileName = "default") {
|
|
|
7379
7408
|
}
|
|
7380
7409
|
}
|
|
7381
7410
|
function resolveHermesBin() {
|
|
7382
|
-
return
|
|
7411
|
+
return resolveHermesBinResolution().bin;
|
|
7412
|
+
}
|
|
7413
|
+
function resolveHermesBinResolution(paths = resolveRuntimePaths()) {
|
|
7414
|
+
const envHermesBin = process.env.HERMES_BIN?.trim();
|
|
7415
|
+
if (envHermesBin) {
|
|
7416
|
+
return { bin: envHermesBin, source: "env" };
|
|
7417
|
+
}
|
|
7418
|
+
const configuredHermesBin = readConfiguredHermesBin(paths);
|
|
7419
|
+
if (configuredHermesBin) {
|
|
7420
|
+
const resolved = resolveExecutablePathSync(configuredHermesBin);
|
|
7421
|
+
if (resolved) {
|
|
7422
|
+
return { bin: resolved, source: "config" };
|
|
7423
|
+
}
|
|
7424
|
+
}
|
|
7425
|
+
const pathHermesBin = resolveExecutablePathSync("hermes", { pathOnly: true });
|
|
7426
|
+
if (pathHermesBin) {
|
|
7427
|
+
return { bin: pathHermesBin, source: "path" };
|
|
7428
|
+
}
|
|
7429
|
+
const commonHermesBin = commonHermesBinCandidates().map((candidate) => resolveExecutablePathSync(candidate)).find((candidate) => Boolean(candidate));
|
|
7430
|
+
if (commonHermesBin) {
|
|
7431
|
+
return { bin: commonHermesBin, source: "common" };
|
|
7432
|
+
}
|
|
7433
|
+
return { bin: "hermes", source: "fallback" };
|
|
7434
|
+
}
|
|
7435
|
+
async function rememberResolvedHermesBin(hermesBin, paths = resolveRuntimePaths()) {
|
|
7436
|
+
const resolved = resolveExecutablePathSync(hermesBin);
|
|
7437
|
+
if (!resolved || !path7.isAbsolute(resolved)) {
|
|
7438
|
+
return null;
|
|
7439
|
+
}
|
|
7440
|
+
if (readConfiguredHermesBin(paths) === resolved) {
|
|
7441
|
+
return resolved;
|
|
7442
|
+
}
|
|
7443
|
+
await saveConfig({ hermesBin: resolved }, paths);
|
|
7444
|
+
return resolved;
|
|
7445
|
+
}
|
|
7446
|
+
function resolveExecutablePathSync(command, options = {}) {
|
|
7447
|
+
const candidates = executablePathCandidates(command, options);
|
|
7448
|
+
for (const candidate of candidates) {
|
|
7449
|
+
if (!isExecutableFile(candidate)) {
|
|
7450
|
+
continue;
|
|
7451
|
+
}
|
|
7452
|
+
try {
|
|
7453
|
+
return realpathSync(candidate);
|
|
7454
|
+
} catch {
|
|
7455
|
+
return candidate;
|
|
7456
|
+
}
|
|
7457
|
+
}
|
|
7458
|
+
return null;
|
|
7459
|
+
}
|
|
7460
|
+
function isHermesExecutableMissingError(error) {
|
|
7461
|
+
if (typeof error === "object" && error !== null && "code" in error) {
|
|
7462
|
+
const code = error.code;
|
|
7463
|
+
if (code === "ENOENT") {
|
|
7464
|
+
return true;
|
|
7465
|
+
}
|
|
7466
|
+
}
|
|
7467
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7468
|
+
return /\bspawn\b[\s\S]*\bENOENT\b/u.test(message);
|
|
7469
|
+
}
|
|
7470
|
+
function createHermesCliMissingError(error, language = "zh-CN") {
|
|
7471
|
+
return new LinkHttpError(
|
|
7472
|
+
503,
|
|
7473
|
+
"hermes_agent_cli_missing",
|
|
7474
|
+
buildHermesCliMissingMessage(resolveHermesBin(), error, language)
|
|
7475
|
+
);
|
|
7476
|
+
}
|
|
7477
|
+
function buildHermesCliMissingMessage(hermesBin, error, language = "zh-CN") {
|
|
7478
|
+
if (language === "en") {
|
|
7479
|
+
return buildEnglishHermesCliMissingMessage(hermesBin, error);
|
|
7480
|
+
}
|
|
7481
|
+
const detail = path7.isAbsolute(hermesBin) ? `\u914D\u7F6E\u7684 Hermes CLI \u8DEF\u5F84\u4E0D\u53EF\u7528\uFF1A${hermesBin}` : `\u540E\u53F0\u73AF\u5883\u627E\u4E0D\u5230 Hermes Agent \u7684 \`${hermesBin}\` \u547D\u4EE4`;
|
|
7482
|
+
const originalHint = isHermesExecutableMissingError(error) ? "" : formatHermesCliErrorHint(error);
|
|
7483
|
+
return [
|
|
7484
|
+
`Hermes Link \u5DF2\u8FDE\u63A5\uFF0C\u4F46\u672C\u673A\u6267\u884C\u9762\u4E0D\u53EF\u7528\uFF1A${detail}\uFF0C\u56E0\u6B64\u65E0\u6CD5\u542F\u52A8 Hermes Agent \u804A\u5929\u8FDB\u7A0B\u3002`,
|
|
7485
|
+
"\u8BF7\u5148\u5728\u8FD9\u53F0\u7535\u8111\u7684\u7EC8\u7AEF\u8FD0\u884C `hermeslink restart` \u5C1D\u8BD5\u6062\u590D\u3002\u82E5\u91CD\u542F\u540E\u6062\u590D\u6B63\u5E38\uFF0C\u8BF7\u518D\u8FD0\u884C `hermeslink autostart on` \u5237\u65B0\u5F00\u673A\u81EA\u542F\u73AF\u5883\uFF0C\u907F\u514D\u4E0B\u6B21\u91CD\u542F\u7535\u8111\u540E\u518D\u6B21\u53D1\u751F\u3002",
|
|
7486
|
+
"\u5982\u679C\u4ECD\u7136\u5931\u8D25\uFF0C\u8BF7\u8FD0\u884C `hermeslink doctor` \u67E5\u770B\u8BCA\u65AD\uFF1B\u82E5 Hermes Agent \u5B89\u88C5\u5728\u81EA\u5B9A\u4E49\u8DEF\u5F84\uFF0C\u8BF7\u5C06 HERMES_BIN \u8BBE\u7F6E\u4E3A `hermes` \u53EF\u6267\u884C\u6587\u4EF6\u7684\u5B8C\u6574\u8DEF\u5F84\u3002",
|
|
7487
|
+
originalHint
|
|
7488
|
+
].filter(Boolean).join("\n");
|
|
7489
|
+
}
|
|
7490
|
+
function buildEnglishHermesCliMissingMessage(hermesBin, error) {
|
|
7491
|
+
const detail = path7.isAbsolute(hermesBin) ? `the configured Hermes CLI path is not usable: ${hermesBin}` : `the background environment cannot find the \`${hermesBin}\` command`;
|
|
7492
|
+
const originalHint = isHermesExecutableMissingError(error) ? "" : formatHermesCliErrorHint(error, "en");
|
|
7493
|
+
return [
|
|
7494
|
+
`Hermes Link is reachable, but the local Hermes execution backend is unavailable because ${detail}. Hermes Link cannot start the Hermes Agent chat process.`,
|
|
7495
|
+
"First run `hermeslink restart` on this computer to try to recover. If that fixes the App, run `hermeslink autostart on` afterwards to refresh the boot autostart environment so this does not happen again after the next reboot.",
|
|
7496
|
+
"If it still fails, run `hermeslink doctor` for diagnostics. If Hermes Agent is installed in a custom location, set HERMES_BIN to the full path of the `hermes` executable.",
|
|
7497
|
+
originalHint
|
|
7498
|
+
].filter(Boolean).join("\n");
|
|
7499
|
+
}
|
|
7500
|
+
function formatHermesCliErrorHint(error, language = "zh-CN") {
|
|
7501
|
+
if (error === void 0 || error === null) {
|
|
7502
|
+
return "";
|
|
7503
|
+
}
|
|
7504
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7505
|
+
if (!message.trim()) {
|
|
7506
|
+
return "";
|
|
7507
|
+
}
|
|
7508
|
+
return language === "en" ? `Raw diagnostic: ${message}` : `\u539F\u59CB\u8BCA\u65AD\uFF1A${message}`;
|
|
7509
|
+
}
|
|
7510
|
+
function readConfiguredHermesBin(paths) {
|
|
7511
|
+
try {
|
|
7512
|
+
const raw = readFileSync(paths.configFile, "utf8");
|
|
7513
|
+
const payload = JSON.parse(raw);
|
|
7514
|
+
return normalizeHermesBin(payload.hermesBin);
|
|
7515
|
+
} catch {
|
|
7516
|
+
return null;
|
|
7517
|
+
}
|
|
7518
|
+
}
|
|
7519
|
+
function executablePathCandidates(command, options) {
|
|
7520
|
+
const normalized = command.trim();
|
|
7521
|
+
if (!normalized) {
|
|
7522
|
+
return [];
|
|
7523
|
+
}
|
|
7524
|
+
if (/[\\/]/u.test(normalized)) {
|
|
7525
|
+
return options.pathOnly ? [] : withWindowsExecutableExtensions(normalized);
|
|
7526
|
+
}
|
|
7527
|
+
const pathEntries = (process.env.PATH ?? "").split(path7.delimiter).filter(Boolean);
|
|
7528
|
+
return pathEntries.flatMap(
|
|
7529
|
+
(entry) => withWindowsExecutableExtensions(path7.join(entry, normalized))
|
|
7530
|
+
);
|
|
7531
|
+
}
|
|
7532
|
+
function commonHermesBinCandidates() {
|
|
7533
|
+
const home = os4.homedir();
|
|
7534
|
+
return [
|
|
7535
|
+
path7.join(home, ".hermes", "hermes-agent", "venv", "bin", "hermes"),
|
|
7536
|
+
path7.join(home, ".local", "bin", "hermes"),
|
|
7537
|
+
...process.platform === "win32" ? [] : [
|
|
7538
|
+
"/opt/homebrew/bin/hermes",
|
|
7539
|
+
"/usr/local/bin/hermes",
|
|
7540
|
+
"/usr/bin/hermes",
|
|
7541
|
+
"/bin/hermes"
|
|
7542
|
+
]
|
|
7543
|
+
];
|
|
7544
|
+
}
|
|
7545
|
+
function withWindowsExecutableExtensions(filePath) {
|
|
7546
|
+
if (process.platform !== "win32" || path7.extname(filePath)) {
|
|
7547
|
+
return [filePath];
|
|
7548
|
+
}
|
|
7549
|
+
const extensions = (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";").filter(Boolean);
|
|
7550
|
+
return [filePath, ...extensions.map((extension) => `${filePath}${extension}`)];
|
|
7551
|
+
}
|
|
7552
|
+
function isExecutableFile(filePath) {
|
|
7553
|
+
try {
|
|
7554
|
+
const stats = statSync(filePath);
|
|
7555
|
+
if (!stats.isFile()) {
|
|
7556
|
+
return false;
|
|
7557
|
+
}
|
|
7558
|
+
accessSync(filePath, fsConstants.X_OK);
|
|
7559
|
+
return true;
|
|
7560
|
+
} catch {
|
|
7561
|
+
return false;
|
|
7562
|
+
}
|
|
7383
7563
|
}
|
|
7384
7564
|
function readSessionDeleteStatus(stdout, stderr) {
|
|
7385
7565
|
const output = `${stdout.toString()}
|
|
@@ -7486,7 +7666,8 @@ async function ensureHermesApiServerAvailable(options = {}) {
|
|
|
7486
7666
|
const start = await startHermesGatewayOnce(
|
|
7487
7667
|
options.paths ?? resolveRuntimePaths(),
|
|
7488
7668
|
profileName,
|
|
7489
|
-
options.logger
|
|
7669
|
+
options.logger,
|
|
7670
|
+
options.language
|
|
7490
7671
|
);
|
|
7491
7672
|
health = await waitForHermesApiHealth(
|
|
7492
7673
|
configResult.apiServer,
|
|
@@ -7512,7 +7693,8 @@ async function ensureHermesApiServerAvailable(options = {}) {
|
|
|
7512
7693
|
const repairedStart = await startHermesGatewayOnce(
|
|
7513
7694
|
options.paths ?? resolveRuntimePaths(),
|
|
7514
7695
|
profileName,
|
|
7515
|
-
options.logger
|
|
7696
|
+
options.logger,
|
|
7697
|
+
options.language
|
|
7516
7698
|
);
|
|
7517
7699
|
health = await waitForHermesApiHealth(
|
|
7518
7700
|
repairedConfigResult.apiServer,
|
|
@@ -7673,7 +7855,7 @@ async function execHermesVersion(hermesBin, logger) {
|
|
|
7673
7855
|
throw new Error(summary);
|
|
7674
7856
|
}
|
|
7675
7857
|
async function readHermesPythonMetadataVersion(hermesBin, timeoutMs) {
|
|
7676
|
-
const hermesPath =
|
|
7858
|
+
const hermesPath = resolveExecutablePathSync(hermesBin);
|
|
7677
7859
|
if (!hermesPath) {
|
|
7678
7860
|
return null;
|
|
7679
7861
|
}
|
|
@@ -7865,22 +8047,25 @@ function assertHermesRunsApiSupported(version, status, endpoint = "/v1/runs", la
|
|
|
7865
8047
|
language === "en" ? `${versionText}The current Hermes Agent API Server does not support the ${endpoint} endpoint required by HermesPilot. Run \`hermes update\` to upgrade Hermes Agent.` : `${versionText}\u5F53\u524D Hermes Agent API Server \u4E0D\u652F\u6301 HermesPilot \u9700\u8981\u7684 ${endpoint} \u63A5\u53E3\uFF0C\u8BF7\u5148\u8FD0\u884C \`hermes update\` \u5347\u7EA7 Hermes Agent\u3002`
|
|
7866
8048
|
);
|
|
7867
8049
|
}
|
|
7868
|
-
async function startHermesGatewayOnce(paths, profileName, logger) {
|
|
8050
|
+
async function startHermesGatewayOnce(paths, profileName, logger, language = "zh-CN") {
|
|
7869
8051
|
if (!gatewayStartInFlightByProfile.has(profileName)) {
|
|
7870
8052
|
gatewayStartInFlightByProfile.set(
|
|
7871
8053
|
profileName,
|
|
7872
|
-
startHermesGateway(paths, profileName, logger).finally(() => {
|
|
8054
|
+
startHermesGateway(paths, profileName, logger, language).finally(() => {
|
|
7873
8055
|
gatewayStartInFlightByProfile.delete(profileName);
|
|
7874
8056
|
})
|
|
7875
8057
|
);
|
|
7876
8058
|
}
|
|
7877
8059
|
return await gatewayStartInFlightByProfile.get(profileName);
|
|
7878
8060
|
}
|
|
7879
|
-
async function startHermesGateway(paths, profileName, logger) {
|
|
8061
|
+
async function startHermesGateway(paths, profileName, logger, language = "zh-CN") {
|
|
7880
8062
|
const version = await readHermesVersion({ logger }).catch((error) => {
|
|
7881
8063
|
void logger?.error("gateway_hermes_cli_unavailable", {
|
|
7882
8064
|
error: error instanceof Error ? error.message : String(error)
|
|
7883
8065
|
});
|
|
8066
|
+
if (isHermesExecutableMissingError(error)) {
|
|
8067
|
+
throw createHermesCliMissingError(error, language);
|
|
8068
|
+
}
|
|
7884
8069
|
throw new LinkHttpError(
|
|
7885
8070
|
503,
|
|
7886
8071
|
"hermes_agent_not_available",
|
|
@@ -7899,11 +8084,12 @@ async function startHermesGateway(paths, profileName, logger) {
|
|
|
7899
8084
|
}
|
|
7900
8085
|
const gatewayLog = createRotatingTextLogWriter({
|
|
7901
8086
|
paths,
|
|
7902
|
-
fileName:
|
|
8087
|
+
fileName: path8.basename(getGatewayRuntimeLogFile(paths))
|
|
7903
8088
|
});
|
|
7904
8089
|
const logPath = gatewayLog.filePath;
|
|
7905
8090
|
try {
|
|
7906
|
-
const
|
|
8091
|
+
const hermesBin = resolveHermesBin();
|
|
8092
|
+
const child = spawn(hermesBin, gatewayRunArgs(profileName), {
|
|
7907
8093
|
detached: true,
|
|
7908
8094
|
env: buildHermesGatewayChildEnv(),
|
|
7909
8095
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -7934,7 +8120,20 @@ async function startHermesGateway(paths, profileName, logger) {
|
|
|
7934
8120
|
callback();
|
|
7935
8121
|
};
|
|
7936
8122
|
child.once("spawn", () => finish(resolve));
|
|
7937
|
-
child.once(
|
|
8123
|
+
child.once(
|
|
8124
|
+
"error",
|
|
8125
|
+
(error) => finish(() => {
|
|
8126
|
+
if (isHermesExecutableMissingError(error)) {
|
|
8127
|
+
void logger?.error("gateway_hermes_cli_spawn_missing", {
|
|
8128
|
+
hermes_bin: hermesBin,
|
|
8129
|
+
error: error.message
|
|
8130
|
+
});
|
|
8131
|
+
reject(createHermesCliMissingError(error, language));
|
|
8132
|
+
return;
|
|
8133
|
+
}
|
|
8134
|
+
reject(error);
|
|
8135
|
+
})
|
|
8136
|
+
);
|
|
7938
8137
|
});
|
|
7939
8138
|
unrefDetachedGatewayProcess(child);
|
|
7940
8139
|
void logger?.info("gateway_process_spawned", {
|
|
@@ -7969,7 +8168,7 @@ async function restartHermesGatewayServiceIfAvailable(options) {
|
|
|
7969
8168
|
if (!home) {
|
|
7970
8169
|
return null;
|
|
7971
8170
|
}
|
|
7972
|
-
const launchdPlistPath =
|
|
8171
|
+
const launchdPlistPath = path8.join(
|
|
7973
8172
|
home,
|
|
7974
8173
|
"Library",
|
|
7975
8174
|
"LaunchAgents",
|
|
@@ -7988,13 +8187,16 @@ async function restartHermesGatewayServiceIfAvailable(options) {
|
|
|
7988
8187
|
void options.logger?.error("gateway_service_restart_failed", {
|
|
7989
8188
|
error: error instanceof Error ? error.message : String(error)
|
|
7990
8189
|
});
|
|
8190
|
+
if (isHermesExecutableMissingError(error)) {
|
|
8191
|
+
throw createHermesCliMissingError(error, options.language);
|
|
8192
|
+
}
|
|
7991
8193
|
throw new LinkHttpError(
|
|
7992
8194
|
503,
|
|
7993
8195
|
"hermes_gateway_restart_failed",
|
|
7994
8196
|
`Hermes Gateway \u670D\u52A1\u91CD\u542F\u5931\u8D25\u3002${formatErrorSuffix(error)}`
|
|
7995
8197
|
);
|
|
7996
8198
|
}
|
|
7997
|
-
const logPath =
|
|
8199
|
+
const logPath = path8.join(home, ".hermes", "logs", "gateway.error.log");
|
|
7998
8200
|
const logHint = await readRecentGatewayLogHint(logPath);
|
|
7999
8201
|
return {
|
|
8000
8202
|
pid: null,
|
|
@@ -8414,6 +8616,12 @@ async function readHermesDashboardVersion(options = {}) {
|
|
|
8414
8616
|
async function probeHermesVersion(hermesBin, options) {
|
|
8415
8617
|
try {
|
|
8416
8618
|
const { stdout } = await execHermesVersion(hermesBin, options.logger);
|
|
8619
|
+
await rememberResolvedHermesBin(hermesBin).catch((error) => {
|
|
8620
|
+
void options.logger?.debug("hermes_bin_remember_failed", {
|
|
8621
|
+
hermes_bin: hermesBin,
|
|
8622
|
+
error: error instanceof Error ? error.message : String(error)
|
|
8623
|
+
});
|
|
8624
|
+
});
|
|
8417
8625
|
const raw = stdout.trim();
|
|
8418
8626
|
const version = parseHermesVersion(raw);
|
|
8419
8627
|
return buildHermesVersionInfo(raw, version);
|
|
@@ -8523,37 +8731,6 @@ function readExecErrorDetails(error, message) {
|
|
|
8523
8731
|
function truncateVersionLogOutput(value) {
|
|
8524
8732
|
return value.length > MAX_VERSION_LOG_OUTPUT_LENGTH ? `${value.slice(0, MAX_VERSION_LOG_OUTPUT_LENGTH)}...` : value;
|
|
8525
8733
|
}
|
|
8526
|
-
async function resolveExecutablePath(command) {
|
|
8527
|
-
const candidates = executablePathCandidates(command);
|
|
8528
|
-
for (const candidate of candidates) {
|
|
8529
|
-
try {
|
|
8530
|
-
await access(candidate, fsConstants.X_OK);
|
|
8531
|
-
return await realpath(candidate).catch(() => candidate);
|
|
8532
|
-
} catch {
|
|
8533
|
-
}
|
|
8534
|
-
}
|
|
8535
|
-
return null;
|
|
8536
|
-
}
|
|
8537
|
-
function executablePathCandidates(command) {
|
|
8538
|
-
const normalized = command.trim();
|
|
8539
|
-
if (!normalized) {
|
|
8540
|
-
return [];
|
|
8541
|
-
}
|
|
8542
|
-
if (/[\\/]/u.test(normalized)) {
|
|
8543
|
-
return withWindowsExecutableExtensions(normalized);
|
|
8544
|
-
}
|
|
8545
|
-
const pathEntries = (process.env.PATH ?? "").split(path7.delimiter).filter(Boolean);
|
|
8546
|
-
return pathEntries.flatMap(
|
|
8547
|
-
(entry) => withWindowsExecutableExtensions(path7.join(entry, normalized))
|
|
8548
|
-
);
|
|
8549
|
-
}
|
|
8550
|
-
function withWindowsExecutableExtensions(filePath) {
|
|
8551
|
-
if (process.platform !== "win32" || path7.extname(filePath)) {
|
|
8552
|
-
return [filePath];
|
|
8553
|
-
}
|
|
8554
|
-
const extensions = (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";").filter(Boolean);
|
|
8555
|
-
return [filePath, ...extensions.map((extension) => `${filePath}${extension}`)];
|
|
8556
|
-
}
|
|
8557
8734
|
async function readFirstLine(filePath) {
|
|
8558
8735
|
const raw = await readFile5(filePath, "utf8");
|
|
8559
8736
|
return raw.split(/\r?\n/u, 1)[0] ?? "";
|
|
@@ -8566,7 +8743,7 @@ function parsePythonShebang(line) {
|
|
|
8566
8743
|
if (parts.length === 0) {
|
|
8567
8744
|
return null;
|
|
8568
8745
|
}
|
|
8569
|
-
const commandName =
|
|
8746
|
+
const commandName = path8.basename(parts[0] ?? "").toLowerCase();
|
|
8570
8747
|
if (commandName === "env") {
|
|
8571
8748
|
const args = expandEnvShebangArgs(parts.slice(1));
|
|
8572
8749
|
const pythonIndex = args.findIndex((part) => isPythonCommandName(part));
|
|
@@ -8587,7 +8764,7 @@ function parsePythonShebang(line) {
|
|
|
8587
8764
|
};
|
|
8588
8765
|
}
|
|
8589
8766
|
function isPythonCommandName(command) {
|
|
8590
|
-
return /^python(?:\d+(?:\.\d+)?)?$/iu.test(
|
|
8767
|
+
return /^python(?:\d+(?:\.\d+)?)?$/iu.test(path8.basename(command));
|
|
8591
8768
|
}
|
|
8592
8769
|
function expandEnvShebangArgs(args) {
|
|
8593
8770
|
const expanded = [];
|
|
@@ -8631,11 +8808,12 @@ import { spawn as spawn2 } from "child_process";
|
|
|
8631
8808
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
8632
8809
|
import { readFile as readFile6, stat as stat5 } from "fs/promises";
|
|
8633
8810
|
import net2 from "net";
|
|
8634
|
-
import
|
|
8811
|
+
import path9 from "path";
|
|
8635
8812
|
import { setTimeout as delay3 } from "timers/promises";
|
|
8636
8813
|
import WebSocket from "ws";
|
|
8637
8814
|
var CONNECT_TIMEOUT_MS = 15e3;
|
|
8638
8815
|
var REQUEST_TIMEOUT_MS = 12e4;
|
|
8816
|
+
var USAGE_REQUEST_TIMEOUT_MS = 1e4;
|
|
8639
8817
|
var PROMPT_SUBMIT_TIMEOUT_MS = 0;
|
|
8640
8818
|
var READY_TIMEOUT_MS = 1e4;
|
|
8641
8819
|
var BACKEND_START_TIMEOUT_MS = 45e3;
|
|
@@ -8656,19 +8834,31 @@ async function streamTuiGatewayRun(input) {
|
|
|
8656
8834
|
profileName,
|
|
8657
8835
|
paths: input.paths,
|
|
8658
8836
|
logger: input.logger,
|
|
8659
|
-
signal: input.signal
|
|
8837
|
+
signal: input.signal,
|
|
8838
|
+
language: input.language
|
|
8660
8839
|
});
|
|
8661
8840
|
const started = await ensureRpcSession(client, {
|
|
8662
8841
|
...input,
|
|
8663
8842
|
profileName
|
|
8664
8843
|
});
|
|
8665
8844
|
await client.waitForSessionDrain(started.runtimeSessionId, input.signal);
|
|
8845
|
+
const usageBaseline = await client.readSessionUsage(started.runtimeSessionId).catch((error) => {
|
|
8846
|
+
void input.logger?.debug("tui_gateway_usage_baseline_read_failed", {
|
|
8847
|
+
profile: profileName,
|
|
8848
|
+
session_id: started.runtimeSessionId,
|
|
8849
|
+
error: error instanceof Error ? error.message : String(error)
|
|
8850
|
+
});
|
|
8851
|
+
return started.resumed ? null : {};
|
|
8852
|
+
});
|
|
8666
8853
|
const events = client.submitPrompt({
|
|
8667
8854
|
sessionId: started.runtimeSessionId,
|
|
8668
8855
|
text: buildTuiGatewayPromptText(input),
|
|
8669
8856
|
signal: input.signal
|
|
8670
8857
|
});
|
|
8671
|
-
return {
|
|
8858
|
+
return {
|
|
8859
|
+
started,
|
|
8860
|
+
events: normalizeTuiGatewayRunUsageDeltas(events, usageBaseline)
|
|
8861
|
+
};
|
|
8672
8862
|
}
|
|
8673
8863
|
function buildTuiGatewayPromptText(input) {
|
|
8674
8864
|
return input.input;
|
|
@@ -8949,9 +9139,10 @@ async function startTuiGatewayBackend(input) {
|
|
|
8949
9139
|
];
|
|
8950
9140
|
const logWriter = createRotatingTextLogWriter({
|
|
8951
9141
|
paths,
|
|
8952
|
-
fileName:
|
|
9142
|
+
fileName: path9.basename(getGatewayRuntimeLogFile(paths))
|
|
8953
9143
|
});
|
|
8954
|
-
const
|
|
9144
|
+
const hermesBin = resolveHermesBin();
|
|
9145
|
+
const child = spawn2(hermesBin, args, {
|
|
8955
9146
|
env: {
|
|
8956
9147
|
...process.env,
|
|
8957
9148
|
HERMES_DASHBOARD_SESSION_TOKEN: token
|
|
@@ -8976,7 +9167,13 @@ async function startTuiGatewayBackend(input) {
|
|
|
8976
9167
|
signal
|
|
8977
9168
|
});
|
|
8978
9169
|
});
|
|
8979
|
-
await waitForChildSpawn(
|
|
9170
|
+
await waitForChildSpawn(
|
|
9171
|
+
child,
|
|
9172
|
+
input.signal,
|
|
9173
|
+
input.logger,
|
|
9174
|
+
hermesBin,
|
|
9175
|
+
input.language
|
|
9176
|
+
);
|
|
8980
9177
|
const baseUrl = `http://127.0.0.1:${port}`;
|
|
8981
9178
|
const wsUrl = `ws://127.0.0.1:${port}/api/ws?token=${encodeURIComponent(token)}`;
|
|
8982
9179
|
try {
|
|
@@ -9180,6 +9377,13 @@ var TuiGatewayClient = class {
|
|
|
9180
9377
|
queue.closed.finally(cleanup).catch(() => void 0);
|
|
9181
9378
|
return queue;
|
|
9182
9379
|
}
|
|
9380
|
+
async readSessionUsage(sessionId) {
|
|
9381
|
+
return await this.request(
|
|
9382
|
+
"session.usage",
|
|
9383
|
+
{ session_id: sessionId },
|
|
9384
|
+
USAGE_REQUEST_TIMEOUT_MS
|
|
9385
|
+
);
|
|
9386
|
+
}
|
|
9183
9387
|
async interruptSession(sessionId) {
|
|
9184
9388
|
const queue = new GatewayEventQueue(sessionId);
|
|
9185
9389
|
this.eventQueues.add(queue);
|
|
@@ -9477,6 +9681,94 @@ var GatewayEventQueue = class {
|
|
|
9477
9681
|
});
|
|
9478
9682
|
}
|
|
9479
9683
|
};
|
|
9684
|
+
async function* normalizeTuiGatewayRunUsageDeltas(events, baseline) {
|
|
9685
|
+
for await (const event of events) {
|
|
9686
|
+
yield normalizeTuiGatewayRunUsageDelta(event, baseline);
|
|
9687
|
+
}
|
|
9688
|
+
}
|
|
9689
|
+
function normalizeTuiGatewayRunUsageDelta(event, baseline) {
|
|
9690
|
+
if (baseline === null || event.payloadType !== "run.completed" && event.payloadType !== "run.failed" && event.payloadType !== "run.cancelled") {
|
|
9691
|
+
return event;
|
|
9692
|
+
}
|
|
9693
|
+
const usage = normalizeTuiGatewayUsageDelta(event.payload.usage, baseline);
|
|
9694
|
+
if (!usage) {
|
|
9695
|
+
return event;
|
|
9696
|
+
}
|
|
9697
|
+
return {
|
|
9698
|
+
...event,
|
|
9699
|
+
payload: {
|
|
9700
|
+
...event.payload,
|
|
9701
|
+
usage
|
|
9702
|
+
}
|
|
9703
|
+
};
|
|
9704
|
+
}
|
|
9705
|
+
function normalizeTuiGatewayUsageDelta(usageValue, baseline) {
|
|
9706
|
+
const usage = toRecord3(usageValue);
|
|
9707
|
+
if (Object.keys(usage).length === 0) {
|
|
9708
|
+
return null;
|
|
9709
|
+
}
|
|
9710
|
+
const inputTokens = usageDelta(usage, baseline, [
|
|
9711
|
+
"input",
|
|
9712
|
+
"input_tokens",
|
|
9713
|
+
"prompt",
|
|
9714
|
+
"prompt_tokens"
|
|
9715
|
+
]);
|
|
9716
|
+
const outputTokens = usageDelta(usage, baseline, [
|
|
9717
|
+
"output",
|
|
9718
|
+
"output_tokens",
|
|
9719
|
+
"completion",
|
|
9720
|
+
"completion_tokens"
|
|
9721
|
+
]);
|
|
9722
|
+
const totalTokens = totalUsageDelta(
|
|
9723
|
+
usage,
|
|
9724
|
+
baseline,
|
|
9725
|
+
inputTokens,
|
|
9726
|
+
outputTokens
|
|
9727
|
+
);
|
|
9728
|
+
const contextTokens = readNumber2(usage, "context_used") ?? readNumber2(usage, "context_tokens") ?? readNumber2(usage, "current_context_tokens") ?? readNumber2(usage, "last_prompt_tokens");
|
|
9729
|
+
const contextWindow = readNumber2(usage, "context_max") ?? readNumber2(usage, "context_window") ?? readNumber2(usage, "context_length");
|
|
9730
|
+
const usagePercent = readNumber2(usage, "context_percent") ?? readNumber2(usage, "usage_percent");
|
|
9731
|
+
if (inputTokens === void 0 && outputTokens === void 0 && totalTokens === void 0 && contextTokens === void 0) {
|
|
9732
|
+
return null;
|
|
9733
|
+
}
|
|
9734
|
+
return {
|
|
9735
|
+
...usage,
|
|
9736
|
+
...inputTokens !== void 0 ? { input_tokens: inputTokens } : {},
|
|
9737
|
+
...outputTokens !== void 0 ? { output_tokens: outputTokens } : {},
|
|
9738
|
+
...totalTokens !== void 0 ? { total_tokens: totalTokens } : {},
|
|
9739
|
+
...contextTokens !== void 0 ? { context_tokens: contextTokens } : {},
|
|
9740
|
+
...contextWindow !== void 0 ? { context_window: contextWindow } : {},
|
|
9741
|
+
...usagePercent !== void 0 ? { usage_percent: usagePercent } : {}
|
|
9742
|
+
};
|
|
9743
|
+
}
|
|
9744
|
+
function usageDelta(current, baseline, keys) {
|
|
9745
|
+
const currentValue = readFirstNumber(current, keys);
|
|
9746
|
+
if (currentValue === void 0) {
|
|
9747
|
+
return void 0;
|
|
9748
|
+
}
|
|
9749
|
+
const baselineValue = readFirstNumber(baseline, keys) ?? 0;
|
|
9750
|
+
return Math.max(0, currentValue - baselineValue);
|
|
9751
|
+
}
|
|
9752
|
+
function totalUsageDelta(current, baseline, inputTokens, outputTokens) {
|
|
9753
|
+
const currentTotal = readFirstNumber(current, ["total", "total_tokens"]);
|
|
9754
|
+
const baselineTotal = readFirstNumber(baseline, ["total", "total_tokens"]);
|
|
9755
|
+
if (currentTotal !== void 0 && (baselineTotal !== void 0 || Object.keys(baseline).length === 0)) {
|
|
9756
|
+
return Math.max(0, currentTotal - (baselineTotal ?? 0));
|
|
9757
|
+
}
|
|
9758
|
+
if (inputTokens !== void 0 || outputTokens !== void 0) {
|
|
9759
|
+
return (inputTokens ?? 0) + (outputTokens ?? 0);
|
|
9760
|
+
}
|
|
9761
|
+
return void 0;
|
|
9762
|
+
}
|
|
9763
|
+
function readFirstNumber(payload, keys) {
|
|
9764
|
+
for (const key of keys) {
|
|
9765
|
+
const value = readNumber2(payload, key);
|
|
9766
|
+
if (value !== void 0) {
|
|
9767
|
+
return value;
|
|
9768
|
+
}
|
|
9769
|
+
}
|
|
9770
|
+
return void 0;
|
|
9771
|
+
}
|
|
9480
9772
|
function normalizeGatewayEvent(event) {
|
|
9481
9773
|
const payload = toRecord3(event.payload);
|
|
9482
9774
|
const base = {
|
|
@@ -9657,7 +9949,7 @@ async function readLogTailSummary(logPath) {
|
|
|
9657
9949
|
return "";
|
|
9658
9950
|
}
|
|
9659
9951
|
}
|
|
9660
|
-
async function waitForChildSpawn(child, signal) {
|
|
9952
|
+
async function waitForChildSpawn(child, signal, logger, hermesBin = resolveHermesBin(), language = "zh-CN") {
|
|
9661
9953
|
await new Promise((resolve, reject) => {
|
|
9662
9954
|
const abort = () => {
|
|
9663
9955
|
child.kill();
|
|
@@ -9680,6 +9972,14 @@ async function waitForChildSpawn(child, signal) {
|
|
|
9680
9972
|
};
|
|
9681
9973
|
const onError = (error) => {
|
|
9682
9974
|
cleanup();
|
|
9975
|
+
if (isHermesExecutableMissingError(error)) {
|
|
9976
|
+
void logger?.error("tui_gateway_hermes_cli_spawn_missing", {
|
|
9977
|
+
hermes_bin: hermesBin,
|
|
9978
|
+
error: error.message
|
|
9979
|
+
});
|
|
9980
|
+
reject(createHermesCliMissingError(error, language));
|
|
9981
|
+
return;
|
|
9982
|
+
}
|
|
9683
9983
|
reject(error);
|
|
9684
9984
|
};
|
|
9685
9985
|
signal?.addEventListener("abort", abort, { once: true });
|
|
@@ -9762,7 +10062,14 @@ function readString5(payload, key) {
|
|
|
9762
10062
|
}
|
|
9763
10063
|
function readNumber2(payload, key) {
|
|
9764
10064
|
const value = payload[key];
|
|
9765
|
-
|
|
10065
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
10066
|
+
return Math.max(0, Math.floor(value));
|
|
10067
|
+
}
|
|
10068
|
+
if (typeof value === "string" && value.trim()) {
|
|
10069
|
+
const parsed = Number.parseInt(value.replaceAll(",", ""), 10);
|
|
10070
|
+
return Number.isFinite(parsed) ? Math.max(0, parsed) : void 0;
|
|
10071
|
+
}
|
|
10072
|
+
return void 0;
|
|
9766
10073
|
}
|
|
9767
10074
|
function readText(payload, key) {
|
|
9768
10075
|
const value = payload[key];
|
|
@@ -9996,6 +10303,25 @@ function latestUsageRun(snapshot) {
|
|
|
9996
10303
|
}
|
|
9997
10304
|
return void 0;
|
|
9998
10305
|
}
|
|
10306
|
+
function latestContextUsageRun(snapshot) {
|
|
10307
|
+
let latestEstimatedRun;
|
|
10308
|
+
let latestUsageRun2;
|
|
10309
|
+
for (const run of [...snapshot.runs].reverse()) {
|
|
10310
|
+
if (!isAgentRun(run) || !run.usage) {
|
|
10311
|
+
continue;
|
|
10312
|
+
}
|
|
10313
|
+
latestUsageRun2 ??= run;
|
|
10314
|
+
if (run.usage.context_tokens === void 0) {
|
|
10315
|
+
continue;
|
|
10316
|
+
}
|
|
10317
|
+
if (run.usage.context_source === "estimated") {
|
|
10318
|
+
latestEstimatedRun ??= run;
|
|
10319
|
+
continue;
|
|
10320
|
+
}
|
|
10321
|
+
return run;
|
|
10322
|
+
}
|
|
10323
|
+
return latestEstimatedRun ?? latestUsageRun2;
|
|
10324
|
+
}
|
|
9999
10325
|
function latestRuntimeRun(snapshot) {
|
|
10000
10326
|
for (const run of [...snapshot.runs].reverse()) {
|
|
10001
10327
|
if (isAgentRun(run) && (run.model || run.profile_uid || run.profile_name_snapshot || run.profile || run.usage)) {
|
|
@@ -10319,11 +10645,11 @@ function workspaceNotFound() {
|
|
|
10319
10645
|
// src/conversations/blob-store.ts
|
|
10320
10646
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
10321
10647
|
import { mkdir as mkdir6, readFile as readFile7, readdir as readdir4, rm as rm3, stat as stat6, writeFile } from "fs/promises";
|
|
10322
|
-
import
|
|
10648
|
+
import path11 from "path";
|
|
10323
10649
|
|
|
10324
10650
|
// src/conversations/media.ts
|
|
10325
10651
|
import { createHash as createHash2 } from "crypto";
|
|
10326
|
-
import
|
|
10652
|
+
import path10 from "path";
|
|
10327
10653
|
|
|
10328
10654
|
// src/conversations/delivery-contract.ts
|
|
10329
10655
|
var HERMES_LINK_DELIVERY_TAG_PATTERN = /<hermes_link_delivery>\s*(\{[\s\S]*?\})\s*<\/hermes_link_delivery>/giu;
|
|
@@ -10413,7 +10739,7 @@ function cleanMessageTextParts(message) {
|
|
|
10413
10739
|
}
|
|
10414
10740
|
}
|
|
10415
10741
|
function inferMimeType(filePath) {
|
|
10416
|
-
const extension =
|
|
10742
|
+
const extension = path10.extname(filePath).toLowerCase();
|
|
10417
10743
|
return {
|
|
10418
10744
|
".png": "image/png",
|
|
10419
10745
|
".jpg": "image/jpeg",
|
|
@@ -10537,7 +10863,7 @@ function mediaSourceKey(sourcePath) {
|
|
|
10537
10863
|
return createHash2("sha256").update(resolveMediaSourcePath(sourcePath)).digest("hex").slice(0, 32);
|
|
10538
10864
|
}
|
|
10539
10865
|
function sanitizeFilename(value, fallback) {
|
|
10540
|
-
const base =
|
|
10866
|
+
const base = path10.basename((value ?? "").replace(/[\r\n\t]/gu, " ").trim());
|
|
10541
10867
|
const safe = base.replace(/[/:\\]/gu, "_").slice(0, 200).trim();
|
|
10542
10868
|
return safe || fallback;
|
|
10543
10869
|
}
|
|
@@ -10566,9 +10892,9 @@ function isBlobReferencedByMessages(snapshot, blobId) {
|
|
|
10566
10892
|
}
|
|
10567
10893
|
function resolveMediaSourcePath(sourcePath) {
|
|
10568
10894
|
const trimmed = sourcePath.trim();
|
|
10569
|
-
const expanded = trimmed.startsWith("~/") ?
|
|
10570
|
-
const resolved =
|
|
10571
|
-
if (!
|
|
10895
|
+
const expanded = trimmed.startsWith("~/") ? path10.join(process.env.HOME ?? "", trimmed.slice(2)) : trimmed;
|
|
10896
|
+
const resolved = path10.resolve(expanded);
|
|
10897
|
+
if (!path10.isAbsolute(expanded)) {
|
|
10572
10898
|
throw new LinkHttpError(
|
|
10573
10899
|
400,
|
|
10574
10900
|
"media_source_path_not_absolute",
|
|
@@ -10763,7 +11089,7 @@ function normalizeConversationIds(conversationIds) {
|
|
|
10763
11089
|
}
|
|
10764
11090
|
function blobPath(paths, blobId) {
|
|
10765
11091
|
assertValidBlobId(blobId);
|
|
10766
|
-
return
|
|
11092
|
+
return path11.join(paths.blobsDir, `${blobId}.bin`);
|
|
10767
11093
|
}
|
|
10768
11094
|
async function writeConversationBlob(paths, conversationId, input, options) {
|
|
10769
11095
|
assertValidConversationId(conversationId);
|
|
@@ -10772,7 +11098,7 @@ async function writeConversationBlob(paths, conversationId, input, options) {
|
|
|
10772
11098
|
}
|
|
10773
11099
|
const id = `blob_${randomUUID5().replaceAll("-", "")}`;
|
|
10774
11100
|
const filePath = blobPath(paths, id);
|
|
10775
|
-
await mkdir6(
|
|
11101
|
+
await mkdir6(path11.dirname(filePath), { recursive: true, mode: 448 });
|
|
10776
11102
|
await writeFile(filePath, input.bytes, { mode: 384 });
|
|
10777
11103
|
const blob = {
|
|
10778
11104
|
id,
|
|
@@ -10848,7 +11174,7 @@ async function materializeConversationBlob(paths, conversationId, blobId, manife
|
|
|
10848
11174
|
}
|
|
10849
11175
|
}
|
|
10850
11176
|
const targetDir = conversationAttachmentsDir(paths, conversationId);
|
|
10851
|
-
const targetPath =
|
|
11177
|
+
const targetPath = path11.join(
|
|
10852
11178
|
targetDir,
|
|
10853
11179
|
materializedAttachmentFilename(blobId, manifest.filename ?? blobId)
|
|
10854
11180
|
);
|
|
@@ -10901,7 +11227,7 @@ async function listConversationBlobIds(paths, conversationId) {
|
|
|
10901
11227
|
continue;
|
|
10902
11228
|
}
|
|
10903
11229
|
const manifest = await readJsonFile(
|
|
10904
|
-
|
|
11230
|
+
path11.join(paths.blobsDir, entry.name)
|
|
10905
11231
|
).catch(() => null);
|
|
10906
11232
|
if (manifest?.conversation_ids?.includes(conversationId)) {
|
|
10907
11233
|
blobIds.push(blobId);
|
|
@@ -10911,7 +11237,7 @@ async function listConversationBlobIds(paths, conversationId) {
|
|
|
10911
11237
|
}
|
|
10912
11238
|
function conversationAttachmentsDir(paths, conversationId) {
|
|
10913
11239
|
assertValidConversationId(conversationId);
|
|
10914
|
-
return
|
|
11240
|
+
return path11.join(paths.conversationsDir, conversationId, "attachments");
|
|
10915
11241
|
}
|
|
10916
11242
|
function isNodeError6(error, code) {
|
|
10917
11243
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
@@ -10991,7 +11317,7 @@ async function readConversationProfileSummary(paths, manifest) {
|
|
|
10991
11317
|
}
|
|
10992
11318
|
async function buildConversationRuntimeMetadata(paths, manifest, snapshot) {
|
|
10993
11319
|
const current = await readCurrentConversationRuntime(paths, manifest);
|
|
10994
|
-
const usageRun =
|
|
11320
|
+
const usageRun = latestContextUsageRun(snapshot);
|
|
10995
11321
|
const profileUid = current.profileUid;
|
|
10996
11322
|
const profileName = current.profileName;
|
|
10997
11323
|
const profilePresentation = {
|
|
@@ -11946,7 +12272,7 @@ function commandText(language, zh, en) {
|
|
|
11946
12272
|
|
|
11947
12273
|
// src/conversations/delivery-staging.ts
|
|
11948
12274
|
import { mkdir as mkdir7, rm as rm4 } from "fs/promises";
|
|
11949
|
-
import
|
|
12275
|
+
import path12 from "path";
|
|
11950
12276
|
async function prepareDeliveryStagingRunDir(paths, conversationId, runId) {
|
|
11951
12277
|
const directory = deliveryStagingRunDir(paths, conversationId, runId);
|
|
11952
12278
|
await mkdir7(directory, { recursive: true, mode: 448 });
|
|
@@ -11959,14 +12285,14 @@ async function removeConversationDeliveryStaging(paths, conversationId) {
|
|
|
11959
12285
|
});
|
|
11960
12286
|
}
|
|
11961
12287
|
function deliveryStagingRunDir(paths, conversationId, runId) {
|
|
11962
|
-
return
|
|
12288
|
+
return path12.join(
|
|
11963
12289
|
deliveryStagingConversationDir(paths, conversationId),
|
|
11964
12290
|
safePathSegment(runId, "run")
|
|
11965
12291
|
);
|
|
11966
12292
|
}
|
|
11967
12293
|
function deliveryStagingConversationDir(paths, conversationId) {
|
|
11968
12294
|
assertValidConversationId(conversationId);
|
|
11969
|
-
return
|
|
12295
|
+
return path12.join(paths.conversationsDir, conversationId, "delivery-staging");
|
|
11970
12296
|
}
|
|
11971
12297
|
function safePathSegment(value, fallback) {
|
|
11972
12298
|
const safe = value.trim().replaceAll(/[^a-zA-Z0-9._-]/gu, "_");
|
|
@@ -11976,7 +12302,7 @@ function safePathSegment(value, fallback) {
|
|
|
11976
12302
|
// src/conversations/conversation-archive-plans.ts
|
|
11977
12303
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
11978
12304
|
import { mkdir as mkdir8 } from "fs/promises";
|
|
11979
|
-
import
|
|
12305
|
+
import path13 from "path";
|
|
11980
12306
|
var PLAN_ID_PATTERN = /^archive_[a-f0-9]{32}$/u;
|
|
11981
12307
|
var ConversationArchivePlanStore = class {
|
|
11982
12308
|
constructor(paths) {
|
|
@@ -12019,10 +12345,10 @@ var ConversationArchivePlanStore = class {
|
|
|
12019
12345
|
await writeJsonFile(this.planPath(normalizedPlanId), plan);
|
|
12020
12346
|
}
|
|
12021
12347
|
plansDir() {
|
|
12022
|
-
return
|
|
12348
|
+
return path13.join(this.paths.indexesDir, "conversation-archive-plans");
|
|
12023
12349
|
}
|
|
12024
12350
|
planPath(planId) {
|
|
12025
|
-
return
|
|
12351
|
+
return path13.join(this.plansDir(), `${planId}.json`);
|
|
12026
12352
|
}
|
|
12027
12353
|
};
|
|
12028
12354
|
function normalizePlanId(planId) {
|
|
@@ -12040,7 +12366,7 @@ function normalizePlanId(planId) {
|
|
|
12040
12366
|
// src/conversations/conversation-clear-plans.ts
|
|
12041
12367
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
12042
12368
|
import { mkdir as mkdir9 } from "fs/promises";
|
|
12043
|
-
import
|
|
12369
|
+
import path14 from "path";
|
|
12044
12370
|
var PLAN_ID_PATTERN2 = /^clear_[a-f0-9]{32}$/u;
|
|
12045
12371
|
var ConversationClearPlanStore = class {
|
|
12046
12372
|
constructor(paths) {
|
|
@@ -12084,10 +12410,10 @@ var ConversationClearPlanStore = class {
|
|
|
12084
12410
|
await writeJsonFile(this.planPath(normalizedPlanId), plan);
|
|
12085
12411
|
}
|
|
12086
12412
|
plansDir() {
|
|
12087
|
-
return
|
|
12413
|
+
return path14.join(this.paths.indexesDir, "conversation-clear-plans");
|
|
12088
12414
|
}
|
|
12089
12415
|
planPath(planId) {
|
|
12090
|
-
return
|
|
12416
|
+
return path14.join(this.plansDir(), `${planId}.json`);
|
|
12091
12417
|
}
|
|
12092
12418
|
};
|
|
12093
12419
|
function normalizePlanId2(planId) {
|
|
@@ -12926,14 +13252,14 @@ function readAttachmentWaveform(attachment) {
|
|
|
12926
13252
|
|
|
12927
13253
|
// src/hermes/session-title.ts
|
|
12928
13254
|
import { stat as stat8 } from "fs/promises";
|
|
12929
|
-
import
|
|
13255
|
+
import path15 from "path";
|
|
12930
13256
|
async function readHermesSessionTitle(sessionId, paths, profileName) {
|
|
12931
13257
|
const trimmedSessionId = sessionId.trim();
|
|
12932
13258
|
if (!trimmedSessionId) {
|
|
12933
13259
|
return void 0;
|
|
12934
13260
|
}
|
|
12935
13261
|
const resolvedProfileName = isValidProfileName(profileName) ? profileName : "default";
|
|
12936
|
-
const dbPath =
|
|
13262
|
+
const dbPath = path15.join(
|
|
12937
13263
|
resolveHermesProfileDir(resolvedProfileName),
|
|
12938
13264
|
"state.db"
|
|
12939
13265
|
);
|
|
@@ -12954,7 +13280,7 @@ async function readHermesCompressionTip(sessionId, paths, profileName) {
|
|
|
12954
13280
|
return void 0;
|
|
12955
13281
|
}
|
|
12956
13282
|
const resolvedProfileName = isValidProfileName(profileName) ? profileName : "default";
|
|
12957
|
-
const dbPath =
|
|
13283
|
+
const dbPath = path15.join(
|
|
12958
13284
|
resolveHermesProfileDir(resolvedProfileName),
|
|
12959
13285
|
"state.db"
|
|
12960
13286
|
);
|
|
@@ -13730,10 +14056,15 @@ var ConversationOrchestrationCoordinator = class {
|
|
|
13730
14056
|
return;
|
|
13731
14057
|
}
|
|
13732
14058
|
try {
|
|
14059
|
+
const failureMessage = await this.formatRunWorkerFailureMessage(
|
|
14060
|
+
conversationId,
|
|
14061
|
+
runId,
|
|
14062
|
+
error
|
|
14063
|
+
);
|
|
13733
14064
|
await this.deps.runLifecycle.failRun(
|
|
13734
14065
|
conversationId,
|
|
13735
14066
|
runId,
|
|
13736
|
-
|
|
14067
|
+
failureMessage
|
|
13737
14068
|
);
|
|
13738
14069
|
} catch (failError) {
|
|
13739
14070
|
if (isConversationNotFoundError(failError)) {
|
|
@@ -13760,6 +14091,26 @@ var ConversationOrchestrationCoordinator = class {
|
|
|
13760
14091
|
});
|
|
13761
14092
|
});
|
|
13762
14093
|
}
|
|
14094
|
+
async formatRunWorkerFailureMessage(conversationId, runId, error) {
|
|
14095
|
+
if (error instanceof LinkHttpError && error.code === "hermes_agent_cli_missing") {
|
|
14096
|
+
return createHermesCliMissingError(
|
|
14097
|
+
void 0,
|
|
14098
|
+
await this.readRunLanguage(conversationId, runId)
|
|
14099
|
+
).message;
|
|
14100
|
+
}
|
|
14101
|
+
if (isHermesExecutableMissingError(error)) {
|
|
14102
|
+
return createHermesCliMissingError(
|
|
14103
|
+
error,
|
|
14104
|
+
await this.readRunLanguage(conversationId, runId)
|
|
14105
|
+
).message;
|
|
14106
|
+
}
|
|
14107
|
+
return error instanceof Error ? error.message : String(error);
|
|
14108
|
+
}
|
|
14109
|
+
async readRunLanguage(conversationId, runId) {
|
|
14110
|
+
const snapshot = await this.deps.store.readSnapshot(conversationId).catch(() => null);
|
|
14111
|
+
const run = snapshot?.runs.find((item) => item.id === runId);
|
|
14112
|
+
return normalizeLanguage(run?.language);
|
|
14113
|
+
}
|
|
13763
14114
|
async startNextQueuedRunLocked(conversationId) {
|
|
13764
14115
|
const manifest = await this.deps.store.readRunnableManifest(conversationId);
|
|
13765
14116
|
const snapshot = await this.deps.store.readSnapshot(conversationId);
|
|
@@ -15297,7 +15648,7 @@ import {
|
|
|
15297
15648
|
rm as rm5,
|
|
15298
15649
|
writeFile as writeFile2
|
|
15299
15650
|
} from "fs/promises";
|
|
15300
|
-
import
|
|
15651
|
+
import path16 from "path";
|
|
15301
15652
|
var ConversationStore = class {
|
|
15302
15653
|
constructor(paths) {
|
|
15303
15654
|
this.paths = paths;
|
|
@@ -15428,23 +15779,23 @@ var ConversationStore = class {
|
|
|
15428
15779
|
return manifest != null && manifest.status !== "deleted_soft";
|
|
15429
15780
|
}
|
|
15430
15781
|
removeConversationAttachments(conversationId) {
|
|
15431
|
-
return rm5(
|
|
15782
|
+
return rm5(path16.join(this.conversationDir(conversationId), "attachments"), {
|
|
15432
15783
|
recursive: true,
|
|
15433
15784
|
force: true
|
|
15434
15785
|
});
|
|
15435
15786
|
}
|
|
15436
15787
|
conversationDir(conversationId) {
|
|
15437
15788
|
assertValidConversationId(conversationId);
|
|
15438
|
-
return
|
|
15789
|
+
return path16.join(this.paths.conversationsDir, conversationId);
|
|
15439
15790
|
}
|
|
15440
15791
|
manifestPath(conversationId) {
|
|
15441
|
-
return
|
|
15792
|
+
return path16.join(this.conversationDir(conversationId), "manifest.json");
|
|
15442
15793
|
}
|
|
15443
15794
|
snapshotPath(conversationId) {
|
|
15444
|
-
return
|
|
15795
|
+
return path16.join(this.conversationDir(conversationId), "snapshot.json");
|
|
15445
15796
|
}
|
|
15446
15797
|
eventsPath(conversationId) {
|
|
15447
|
-
return
|
|
15798
|
+
return path16.join(this.conversationDir(conversationId), "events.ndjson");
|
|
15448
15799
|
}
|
|
15449
15800
|
};
|
|
15450
15801
|
function createEmptySnapshot2() {
|
|
@@ -15457,11 +15808,11 @@ function isNodeError9(error, code) {
|
|
|
15457
15808
|
// src/conversations/hermes-session-sync.ts
|
|
15458
15809
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
15459
15810
|
import { readdir as readdir7, readFile as readFile10, stat as stat10 } from "fs/promises";
|
|
15460
|
-
import
|
|
15811
|
+
import path18 from "path";
|
|
15461
15812
|
|
|
15462
15813
|
// src/conversations/delivery-import.ts
|
|
15463
15814
|
import { lstat as lstat2, readFile as readFile9, readdir as readdir6, stat as stat9 } from "fs/promises";
|
|
15464
|
-
import
|
|
15815
|
+
import path17 from "path";
|
|
15465
15816
|
var MAX_IMPORTED_BLOB_BYTES = 100 * 1024 * 1024;
|
|
15466
15817
|
var MAX_MEDIA_IMPORT_FAILURES = 20;
|
|
15467
15818
|
var MAX_DELIVERY_FILES = 50;
|
|
@@ -15532,16 +15883,16 @@ var SUPPORTED_DELIVERY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
15532
15883
|
".m4a"
|
|
15533
15884
|
]);
|
|
15534
15885
|
function resolveDeliveryStagingTarget(paths, stagingDir) {
|
|
15535
|
-
const resolvedDir =
|
|
15536
|
-
const relative =
|
|
15537
|
-
if (!relative || relative.startsWith("..") ||
|
|
15886
|
+
const resolvedDir = path17.resolve(stagingDir);
|
|
15887
|
+
const relative = path17.relative(path17.resolve(paths.conversationsDir), resolvedDir);
|
|
15888
|
+
if (!relative || relative.startsWith("..") || path17.isAbsolute(relative)) {
|
|
15538
15889
|
throw new LinkHttpError(
|
|
15539
15890
|
400,
|
|
15540
15891
|
"delivery_staging_invalid",
|
|
15541
15892
|
"delivery staging directory must be inside Hermes Link conversations"
|
|
15542
15893
|
);
|
|
15543
15894
|
}
|
|
15544
|
-
const segments = relative.split(
|
|
15895
|
+
const segments = relative.split(path17.sep);
|
|
15545
15896
|
if (segments.length !== 3 || segments[1] !== DELIVERY_STAGING_SEGMENT || !segments[0] || !segments[2]) {
|
|
15546
15897
|
throw new LinkHttpError(
|
|
15547
15898
|
400,
|
|
@@ -15577,7 +15928,7 @@ async function collectStagedDeliveryReferences(stagingDir) {
|
|
|
15577
15928
|
return entries.filter((entry) => entry.isFile() && !entry.name.startsWith(".")).filter((entry) => isSupportedDeliveryFilename(entry.name)).sort(
|
|
15578
15929
|
(left, right) => left.name.localeCompare(right.name, "en", { numeric: true })
|
|
15579
15930
|
).slice(0, MAX_DELIVERY_FILES).map((entry) => {
|
|
15580
|
-
const sourcePath =
|
|
15931
|
+
const sourcePath = path17.join(stagingDir, entry.name);
|
|
15581
15932
|
const mime = inferMimeType(sourcePath);
|
|
15582
15933
|
return {
|
|
15583
15934
|
path: sourcePath,
|
|
@@ -15763,7 +16114,7 @@ async function writeBlobFromFile(deps, conversationId, source) {
|
|
|
15763
16114
|
}
|
|
15764
16115
|
return deps.writeBlob(conversationId, {
|
|
15765
16116
|
bytes: await readFile9(sourcePath),
|
|
15766
|
-
filename:
|
|
16117
|
+
filename: path17.basename(sourcePath),
|
|
15767
16118
|
mime: source.mime ?? inferMimeType(sourcePath)
|
|
15768
16119
|
});
|
|
15769
16120
|
}
|
|
@@ -15776,7 +16127,7 @@ function describeMediaImportFailure(reference, sourceKey, error) {
|
|
|
15776
16127
|
};
|
|
15777
16128
|
}
|
|
15778
16129
|
function isSupportedDeliveryFilename(filename) {
|
|
15779
|
-
return SUPPORTED_DELIVERY_EXTENSIONS.has(
|
|
16130
|
+
return SUPPORTED_DELIVERY_EXTENSIONS.has(path17.extname(filename).toLowerCase());
|
|
15780
16131
|
}
|
|
15781
16132
|
function readString9(payload, key) {
|
|
15782
16133
|
const value = payload[key];
|
|
@@ -15834,7 +16185,7 @@ async function syncHermesSessionsIntoConversations(paths, logger, options = {})
|
|
|
15834
16185
|
const candidates = [];
|
|
15835
16186
|
for (const profileName of profileNames) {
|
|
15836
16187
|
const profileDir = resolveHermesProfileDir(profileName);
|
|
15837
|
-
const dbPath =
|
|
16188
|
+
const dbPath = path18.join(profileDir, "state.db");
|
|
15838
16189
|
const sessions = await listProfileSessions(dbPath).catch((error) => {
|
|
15839
16190
|
result.errors.push({
|
|
15840
16191
|
profile: profileName,
|
|
@@ -15950,7 +16301,7 @@ async function syncHermesCronSessionIntoConversations(paths, logger, input) {
|
|
|
15950
16301
|
const knownHermesSessions = await readKnownHermesSessions(store);
|
|
15951
16302
|
const profileName = input.profileName.trim() || DEFAULT_PROFILE_NAME;
|
|
15952
16303
|
const profileDir = resolveHermesProfileDir(profileName);
|
|
15953
|
-
const dbPath =
|
|
16304
|
+
const dbPath = path18.join(profileDir, "state.db");
|
|
15954
16305
|
const sessions = await listProfileSessionsByIdPrefix(
|
|
15955
16306
|
dbPath,
|
|
15956
16307
|
`cron_${jobId}_`
|
|
@@ -17261,8 +17612,8 @@ async function readJsonlMessages(profileName, sessionId) {
|
|
|
17261
17612
|
return [];
|
|
17262
17613
|
}
|
|
17263
17614
|
const profileDir = resolveHermesProfileDir(profileName);
|
|
17264
|
-
const sessionsDir = await readHermesSessionsDir(profileName).then((value) => value.sessionsDir).catch(() =>
|
|
17265
|
-
const transcriptPath =
|
|
17615
|
+
const sessionsDir = await readHermesSessionsDir(profileName).then((value) => value.sessionsDir).catch(() => path18.join(profileDir, "sessions"));
|
|
17616
|
+
const transcriptPath = path18.join(sessionsDir, `${sessionId}.jsonl`);
|
|
17266
17617
|
const raw = await readFile10(transcriptPath, "utf8").catch((error) => {
|
|
17267
17618
|
if (isNodeError11(error, "ENOENT")) {
|
|
17268
17619
|
return "";
|
|
@@ -17632,7 +17983,7 @@ function isNodeError11(error, code) {
|
|
|
17632
17983
|
|
|
17633
17984
|
// src/conversations/delivery-context.ts
|
|
17634
17985
|
import { copyFile, mkdir as mkdir11, stat as stat11 } from "fs/promises";
|
|
17635
|
-
import
|
|
17986
|
+
import path19 from "path";
|
|
17636
17987
|
var ACTIVE_CONTEXTS = /* @__PURE__ */ new Map();
|
|
17637
17988
|
var CONTEXT_TTL_MS = 2 * 60 * 60 * 1e3;
|
|
17638
17989
|
var MAX_DELIVERY_TOOL_FILES = 50;
|
|
@@ -17704,10 +18055,10 @@ function findDeliveryContext(input) {
|
|
|
17704
18055
|
);
|
|
17705
18056
|
}
|
|
17706
18057
|
async function copyFilesIntoDeliveryContext(paths, context, files) {
|
|
17707
|
-
const stagingDir =
|
|
17708
|
-
const conversationsRoot =
|
|
17709
|
-
const relative =
|
|
17710
|
-
if (!relative || relative.startsWith("..") ||
|
|
18058
|
+
const stagingDir = path19.resolve(context.stagingDir);
|
|
18059
|
+
const conversationsRoot = path19.resolve(paths.conversationsDir);
|
|
18060
|
+
const relative = path19.relative(conversationsRoot, stagingDir);
|
|
18061
|
+
if (!relative || relative.startsWith("..") || path19.isAbsolute(relative)) {
|
|
17711
18062
|
throw new LinkHttpError(
|
|
17712
18063
|
400,
|
|
17713
18064
|
"delivery_staging_invalid",
|
|
@@ -17718,13 +18069,13 @@ async function copyFilesIntoDeliveryContext(paths, context, files) {
|
|
|
17718
18069
|
const result = { staged: [], skipped: [] };
|
|
17719
18070
|
const usedNames = /* @__PURE__ */ new Set();
|
|
17720
18071
|
for (const [index, file] of files.slice(0, MAX_DELIVERY_TOOL_FILES).entries()) {
|
|
17721
|
-
const sourcePath =
|
|
18072
|
+
const sourcePath = path19.resolve(file.path);
|
|
17722
18073
|
let baseName = sanitizeFilename(
|
|
17723
|
-
file.caption ||
|
|
18074
|
+
file.caption || path19.basename(sourcePath),
|
|
17724
18075
|
`attachment-${index + 1}`
|
|
17725
18076
|
);
|
|
17726
|
-
const sourceExtension =
|
|
17727
|
-
if (!
|
|
18077
|
+
const sourceExtension = path19.extname(sourcePath);
|
|
18078
|
+
if (!path19.extname(baseName) && sourceExtension) {
|
|
17728
18079
|
baseName = `${baseName}${sourceExtension}`;
|
|
17729
18080
|
}
|
|
17730
18081
|
const filename = uniqueStagingFilename(
|
|
@@ -17751,7 +18102,7 @@ async function copyFilesIntoDeliveryContext(paths, context, files) {
|
|
|
17751
18102
|
});
|
|
17752
18103
|
continue;
|
|
17753
18104
|
}
|
|
17754
|
-
const targetPath =
|
|
18105
|
+
const targetPath = path19.join(stagingDir, filename);
|
|
17755
18106
|
await copyFile(sourcePath, targetPath);
|
|
17756
18107
|
result.staged.push({
|
|
17757
18108
|
source_path: sourcePath,
|
|
@@ -17794,7 +18145,7 @@ function normalizeDeliveryFileInputs(value) {
|
|
|
17794
18145
|
});
|
|
17795
18146
|
}
|
|
17796
18147
|
function uniqueStagingFilename(filename, usedNames) {
|
|
17797
|
-
const extension =
|
|
18148
|
+
const extension = path19.extname(filename);
|
|
17798
18149
|
const stem = filename.slice(0, filename.length - extension.length);
|
|
17799
18150
|
let candidate = filename;
|
|
17800
18151
|
let suffix = 2;
|
|
@@ -18291,10 +18642,10 @@ function parseHermesApiCapabilities(payload) {
|
|
|
18291
18642
|
sessionKeyHeader: readString12(features, "session_key_header")
|
|
18292
18643
|
};
|
|
18293
18644
|
}
|
|
18294
|
-
async function callHermesApi(
|
|
18645
|
+
async function callHermesApi(path35, init, options) {
|
|
18295
18646
|
const method = init.method ?? "GET";
|
|
18296
18647
|
const startedAt = Date.now();
|
|
18297
|
-
void options.logger?.debug("hermes_api_request_started", { method, path:
|
|
18648
|
+
void options.logger?.debug("hermes_api_request_started", { method, path: path35 });
|
|
18298
18649
|
const availability = await ensureHermesApiServerAvailable({
|
|
18299
18650
|
fetchImpl: options.fetchImpl,
|
|
18300
18651
|
logger: options.logger,
|
|
@@ -18303,7 +18654,7 @@ async function callHermesApi(path34, init, options) {
|
|
|
18303
18654
|
});
|
|
18304
18655
|
let config = availability.configResult.apiServer;
|
|
18305
18656
|
const fetcher = options.fetchImpl ?? fetch;
|
|
18306
|
-
const request = () => fetchHermesApi(fetcher, config,
|
|
18657
|
+
const request = () => fetchHermesApi(fetcher, config, path35, init, options);
|
|
18307
18658
|
let response;
|
|
18308
18659
|
try {
|
|
18309
18660
|
response = await request();
|
|
@@ -18311,7 +18662,7 @@ async function callHermesApi(path34, init, options) {
|
|
|
18311
18662
|
logHermesApiError(
|
|
18312
18663
|
options.logger,
|
|
18313
18664
|
method,
|
|
18314
|
-
|
|
18665
|
+
path35,
|
|
18315
18666
|
options.profileName,
|
|
18316
18667
|
startedAt,
|
|
18317
18668
|
error
|
|
@@ -18322,7 +18673,7 @@ async function callHermesApi(path34, init, options) {
|
|
|
18322
18673
|
logHermesApiResponse(
|
|
18323
18674
|
options.logger,
|
|
18324
18675
|
method,
|
|
18325
|
-
|
|
18676
|
+
path35,
|
|
18326
18677
|
options.profileName,
|
|
18327
18678
|
startedAt,
|
|
18328
18679
|
response
|
|
@@ -18331,7 +18682,7 @@ async function callHermesApi(path34, init, options) {
|
|
|
18331
18682
|
}
|
|
18332
18683
|
void options.logger?.warn("hermes_api_request_retrying_after_401", {
|
|
18333
18684
|
method,
|
|
18334
|
-
path:
|
|
18685
|
+
path: path35,
|
|
18335
18686
|
profile: options.profileName ?? "default",
|
|
18336
18687
|
port: config.port ?? null,
|
|
18337
18688
|
duration_ms: Date.now() - startedAt
|
|
@@ -18350,7 +18701,7 @@ async function callHermesApi(path34, init, options) {
|
|
|
18350
18701
|
logHermesApiError(
|
|
18351
18702
|
options.logger,
|
|
18352
18703
|
method,
|
|
18353
|
-
|
|
18704
|
+
path35,
|
|
18354
18705
|
options.profileName,
|
|
18355
18706
|
startedAt,
|
|
18356
18707
|
error
|
|
@@ -18360,7 +18711,7 @@ async function callHermesApi(path34, init, options) {
|
|
|
18360
18711
|
logHermesApiResponse(
|
|
18361
18712
|
options.logger,
|
|
18362
18713
|
method,
|
|
18363
|
-
|
|
18714
|
+
path35,
|
|
18364
18715
|
options.profileName,
|
|
18365
18716
|
startedAt,
|
|
18366
18717
|
response
|
|
@@ -18370,7 +18721,7 @@ async function callHermesApi(path34, init, options) {
|
|
|
18370
18721
|
}
|
|
18371
18722
|
void options.logger?.warn("hermes_api_request_repairing_after_401", {
|
|
18372
18723
|
method,
|
|
18373
|
-
path:
|
|
18724
|
+
path: path35,
|
|
18374
18725
|
profile: options.profileName ?? "default",
|
|
18375
18726
|
port: config.port ?? null,
|
|
18376
18727
|
duration_ms: Date.now() - startedAt
|
|
@@ -18391,7 +18742,7 @@ async function callHermesApi(path34, init, options) {
|
|
|
18391
18742
|
logHermesApiError(
|
|
18392
18743
|
options.logger,
|
|
18393
18744
|
method,
|
|
18394
|
-
|
|
18745
|
+
path35,
|
|
18395
18746
|
options.profileName,
|
|
18396
18747
|
startedAt,
|
|
18397
18748
|
error
|
|
@@ -18401,21 +18752,21 @@ async function callHermesApi(path34, init, options) {
|
|
|
18401
18752
|
logHermesApiResponse(
|
|
18402
18753
|
options.logger,
|
|
18403
18754
|
method,
|
|
18404
|
-
|
|
18755
|
+
path35,
|
|
18405
18756
|
options.profileName,
|
|
18406
18757
|
startedAt,
|
|
18407
18758
|
response
|
|
18408
18759
|
);
|
|
18409
18760
|
return response;
|
|
18410
18761
|
}
|
|
18411
|
-
async function fetchHermesApi(fetcher, config,
|
|
18762
|
+
async function fetchHermesApi(fetcher, config, path35, init, options) {
|
|
18412
18763
|
const headers = new Headers(init.headers);
|
|
18413
18764
|
headers.set("accept", headers.get("accept") ?? "application/json");
|
|
18414
18765
|
if (config.key) {
|
|
18415
18766
|
headers.set("x-api-key", config.key);
|
|
18416
18767
|
headers.set("authorization", `Bearer ${config.key}`);
|
|
18417
18768
|
}
|
|
18418
|
-
return await fetcher(`http://127.0.0.1:${config.port}${
|
|
18769
|
+
return await fetcher(`http://127.0.0.1:${config.port}${path35}`, {
|
|
18419
18770
|
...init,
|
|
18420
18771
|
headers
|
|
18421
18772
|
}).catch((error) => {
|
|
@@ -18424,10 +18775,10 @@ async function fetchHermesApi(fetcher, config, path34, init, options) {
|
|
|
18424
18775
|
}
|
|
18425
18776
|
void options.logger?.warn("hermes_api_server_connect_failed", {
|
|
18426
18777
|
method: String(init.method ?? "GET").toUpperCase(),
|
|
18427
|
-
path:
|
|
18778
|
+
path: path35,
|
|
18428
18779
|
profile: options.profileName ?? "default",
|
|
18429
18780
|
port: config.port ?? null,
|
|
18430
|
-
url: `http://127.0.0.1:${config.port}${
|
|
18781
|
+
url: `http://127.0.0.1:${config.port}${path35}`,
|
|
18431
18782
|
error: error instanceof Error ? error.message : String(error)
|
|
18432
18783
|
});
|
|
18433
18784
|
throw new LinkHttpError(
|
|
@@ -18437,10 +18788,10 @@ async function fetchHermesApi(fetcher, config, path34, init, options) {
|
|
|
18437
18788
|
);
|
|
18438
18789
|
});
|
|
18439
18790
|
}
|
|
18440
|
-
function logHermesApiResponse(logger, method,
|
|
18791
|
+
function logHermesApiResponse(logger, method, path35, profileName, startedAt, response) {
|
|
18441
18792
|
const fields = {
|
|
18442
18793
|
method,
|
|
18443
|
-
path:
|
|
18794
|
+
path: path35,
|
|
18444
18795
|
profile: profileName ?? "default",
|
|
18445
18796
|
status: response.status,
|
|
18446
18797
|
duration_ms: Date.now() - startedAt
|
|
@@ -18461,10 +18812,10 @@ async function logHermesApiFailureResponse(logger, fields, response) {
|
|
|
18461
18812
|
...upstreamError ? { upstream_error: upstreamError } : {}
|
|
18462
18813
|
});
|
|
18463
18814
|
}
|
|
18464
|
-
function logHermesApiError(logger, method,
|
|
18815
|
+
function logHermesApiError(logger, method, path35, profileName, startedAt, error) {
|
|
18465
18816
|
void logger?.warn("hermes_api_request_failed", {
|
|
18466
18817
|
method,
|
|
18467
|
-
path:
|
|
18818
|
+
path: path35,
|
|
18468
18819
|
profile: profileName ?? "default",
|
|
18469
18820
|
duration_ms: Date.now() - startedAt,
|
|
18470
18821
|
...error instanceof LinkHttpError ? { status: error.status, code: error.code } : {},
|
|
@@ -18532,7 +18883,7 @@ function readBoolean2(payload, key) {
|
|
|
18532
18883
|
|
|
18533
18884
|
// src/conversations/history-builder.ts
|
|
18534
18885
|
import { readFile as readFile11, stat as stat12 } from "fs/promises";
|
|
18535
|
-
import
|
|
18886
|
+
import path20 from "path";
|
|
18536
18887
|
var HISTORY_ROLES = /* @__PURE__ */ new Set(["user", "assistant"]);
|
|
18537
18888
|
var HERMES_HISTORY_COLUMNS = [
|
|
18538
18889
|
"role",
|
|
@@ -18604,13 +18955,13 @@ async function readHermesTranscriptHistory(sessionId, profileName) {
|
|
|
18604
18955
|
}
|
|
18605
18956
|
const normalizedProfileName = isValidProfileName2(profileName) ? profileName : "default";
|
|
18606
18957
|
const profileDir = resolveHermesProfileDir(normalizedProfileName);
|
|
18607
|
-
const dbPath =
|
|
18958
|
+
const dbPath = path20.join(profileDir, "state.db");
|
|
18608
18959
|
const sessionsDirConfig = await readHermesSessionsDir(normalizedProfileName).then((value) => ({
|
|
18609
18960
|
sessionsDir: value.sessionsDir,
|
|
18610
18961
|
configured: value.configured,
|
|
18611
18962
|
configError: false
|
|
18612
18963
|
})).catch(() => ({
|
|
18613
|
-
sessionsDir:
|
|
18964
|
+
sessionsDir: path20.join(profileDir, "sessions"),
|
|
18614
18965
|
configured: false,
|
|
18615
18966
|
configError: true
|
|
18616
18967
|
}));
|
|
@@ -18786,8 +19137,8 @@ async function readFirstExistingFile(paths) {
|
|
|
18786
19137
|
}
|
|
18787
19138
|
function candidateTranscriptPaths(sessionsDir, sessionId, extension) {
|
|
18788
19139
|
return [
|
|
18789
|
-
|
|
18790
|
-
|
|
19140
|
+
path20.join(sessionsDir, `session_${sessionId}.${extension}`),
|
|
19141
|
+
path20.join(sessionsDir, `${sessionId}.${extension}`)
|
|
18791
19142
|
];
|
|
18792
19143
|
}
|
|
18793
19144
|
function readHistoryRows(dbPath, sessionId) {
|
|
@@ -19006,8 +19357,8 @@ function normalizeProfileForCompare(value) {
|
|
|
19006
19357
|
// src/hermes/stt.ts
|
|
19007
19358
|
import { execFile as execFile3 } from "child_process";
|
|
19008
19359
|
import { access as access2, readFile as readFile12, stat as stat13 } from "fs/promises";
|
|
19009
|
-
import
|
|
19010
|
-
import
|
|
19360
|
+
import os5 from "os";
|
|
19361
|
+
import path21 from "path";
|
|
19011
19362
|
import { promisify as promisify3 } from "util";
|
|
19012
19363
|
var execFileAsync3 = promisify3(execFile3);
|
|
19013
19364
|
var STT_RESULT_PREFIX = "__HERMES_LINK_STT__";
|
|
@@ -19102,7 +19453,7 @@ async function buildHermesSttEnv(profileName, hermesSourceRoot) {
|
|
|
19102
19453
|
};
|
|
19103
19454
|
const sourceRoot = hermesSourceRoot ?? await findDevHermesAgentSource();
|
|
19104
19455
|
if (sourceRoot) {
|
|
19105
|
-
env.PYTHONPATH = [sourceRoot, env.PYTHONPATH].filter(Boolean).join(
|
|
19456
|
+
env.PYTHONPATH = [sourceRoot, env.PYTHONPATH].filter(Boolean).join(path21.delimiter);
|
|
19106
19457
|
}
|
|
19107
19458
|
return env;
|
|
19108
19459
|
}
|
|
@@ -19139,7 +19490,7 @@ async function resolveHermesPythonRuntime() {
|
|
|
19139
19490
|
sourceRoot: await findExplicitHermesSourceRoot() ?? await findHermesSourceRoot(explicit)
|
|
19140
19491
|
};
|
|
19141
19492
|
}
|
|
19142
|
-
const hermesBin = await
|
|
19493
|
+
const hermesBin = await resolveExecutablePath(resolveHermesBin());
|
|
19143
19494
|
let shebangRuntime = null;
|
|
19144
19495
|
if (hermesBin) {
|
|
19145
19496
|
const launcherTarget = await readHermesLauncherTarget(hermesBin);
|
|
@@ -19196,23 +19547,23 @@ async function resolveHermesPythonRuntime() {
|
|
|
19196
19547
|
sourceRoot: await findExplicitHermesSourceRoot() ?? await findDevHermesAgentSource()
|
|
19197
19548
|
};
|
|
19198
19549
|
}
|
|
19199
|
-
async function
|
|
19200
|
-
if (
|
|
19201
|
-
return await
|
|
19550
|
+
async function resolveExecutablePath(command) {
|
|
19551
|
+
if (path21.isAbsolute(command)) {
|
|
19552
|
+
return await isExecutableFile2(command) ? command : null;
|
|
19202
19553
|
}
|
|
19203
19554
|
const pathEnv = process.env.PATH ?? "";
|
|
19204
19555
|
const extensions = process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";") : [""];
|
|
19205
|
-
for (const dir of pathEnv.split(
|
|
19556
|
+
for (const dir of pathEnv.split(path21.delimiter)) {
|
|
19206
19557
|
for (const extension of extensions) {
|
|
19207
|
-
const candidate =
|
|
19208
|
-
if (await
|
|
19558
|
+
const candidate = path21.join(dir, `${command}${extension}`);
|
|
19559
|
+
if (await isExecutableFile2(candidate)) {
|
|
19209
19560
|
return candidate;
|
|
19210
19561
|
}
|
|
19211
19562
|
}
|
|
19212
19563
|
}
|
|
19213
19564
|
return null;
|
|
19214
19565
|
}
|
|
19215
|
-
async function
|
|
19566
|
+
async function isExecutableFile2(filePath) {
|
|
19216
19567
|
try {
|
|
19217
19568
|
const info = await stat13(filePath);
|
|
19218
19569
|
if (!info.isFile()) {
|
|
@@ -19226,14 +19577,14 @@ async function isExecutableFile(filePath) {
|
|
|
19226
19577
|
}
|
|
19227
19578
|
async function findHermesVenvPython(sourceRoot) {
|
|
19228
19579
|
const candidates = process.platform === "win32" ? [
|
|
19229
|
-
|
|
19230
|
-
|
|
19580
|
+
path21.join(sourceRoot, "venv", "Scripts", "python.exe"),
|
|
19581
|
+
path21.join(sourceRoot, ".venv", "Scripts", "python.exe")
|
|
19231
19582
|
] : [
|
|
19232
|
-
|
|
19233
|
-
|
|
19583
|
+
path21.join(sourceRoot, "venv", "bin", "python"),
|
|
19584
|
+
path21.join(sourceRoot, ".venv", "bin", "python")
|
|
19234
19585
|
];
|
|
19235
19586
|
for (const candidate of candidates) {
|
|
19236
|
-
if (await
|
|
19587
|
+
if (await isExecutableFile2(candidate)) {
|
|
19237
19588
|
return candidate;
|
|
19238
19589
|
}
|
|
19239
19590
|
}
|
|
@@ -19259,8 +19610,8 @@ function shebangToPythonCommand(shebang) {
|
|
|
19259
19610
|
}
|
|
19260
19611
|
async function findDevHermesAgentSource() {
|
|
19261
19612
|
const candidates = [
|
|
19262
|
-
|
|
19263
|
-
|
|
19613
|
+
path21.resolve(process.cwd(), "reference/hermes-agent"),
|
|
19614
|
+
path21.resolve(process.cwd(), "../../reference/hermes-agent")
|
|
19264
19615
|
];
|
|
19265
19616
|
for (const candidate of candidates) {
|
|
19266
19617
|
if (await isHermesAgentSourceRoot(candidate)) {
|
|
@@ -19276,10 +19627,10 @@ async function readHermesLauncherTarget(filePath) {
|
|
|
19276
19627
|
line
|
|
19277
19628
|
);
|
|
19278
19629
|
const rawTarget = quoted?.groups?.target ?? /^\s*exec\s+(?<target>\S+)\s+(?:"\$@"|'\$@')/.exec(line)?.groups?.target;
|
|
19279
|
-
if (!rawTarget || !
|
|
19630
|
+
if (!rawTarget || !path21.isAbsolute(rawTarget)) {
|
|
19280
19631
|
continue;
|
|
19281
19632
|
}
|
|
19282
|
-
if (await
|
|
19633
|
+
if (await isExecutableFile2(rawTarget)) {
|
|
19283
19634
|
return rawTarget;
|
|
19284
19635
|
}
|
|
19285
19636
|
}
|
|
@@ -19306,12 +19657,12 @@ async function resolveHermesEntrypointRuntime(entrypointPath) {
|
|
|
19306
19657
|
return null;
|
|
19307
19658
|
}
|
|
19308
19659
|
async function findHermesSourceRoot(executablePath) {
|
|
19309
|
-
let cursor =
|
|
19660
|
+
let cursor = path21.dirname(path21.resolve(executablePath));
|
|
19310
19661
|
for (let index = 0; index < 6; index += 1) {
|
|
19311
19662
|
if (await isHermesAgentSourceRoot(cursor)) {
|
|
19312
19663
|
return cursor;
|
|
19313
19664
|
}
|
|
19314
|
-
const parent =
|
|
19665
|
+
const parent = path21.dirname(cursor);
|
|
19315
19666
|
if (parent === cursor) {
|
|
19316
19667
|
break;
|
|
19317
19668
|
}
|
|
@@ -19322,14 +19673,14 @@ async function findHermesSourceRoot(executablePath) {
|
|
|
19322
19673
|
function hermesSourceRootCandidates() {
|
|
19323
19674
|
const candidates = [
|
|
19324
19675
|
process.env.HERMES_PYTHON_SRC_ROOT?.trim(),
|
|
19325
|
-
|
|
19676
|
+
path21.join(os5.homedir(), ".hermes", "hermes-agent"),
|
|
19326
19677
|
"/usr/local/lib/hermes-agent",
|
|
19327
19678
|
"/opt/hermes"
|
|
19328
19679
|
].filter((candidate) => Boolean(candidate));
|
|
19329
19680
|
if (process.platform === "win32") {
|
|
19330
19681
|
const localAppData = process.env.LOCALAPPDATA?.trim();
|
|
19331
19682
|
if (localAppData) {
|
|
19332
|
-
candidates.unshift(
|
|
19683
|
+
candidates.unshift(path21.join(localAppData, "hermes", "hermes-agent"));
|
|
19333
19684
|
}
|
|
19334
19685
|
}
|
|
19335
19686
|
return candidates;
|
|
@@ -19339,7 +19690,7 @@ async function findExplicitHermesSourceRoot() {
|
|
|
19339
19690
|
return explicit && await isHermesAgentSourceRoot(explicit) ? explicit : null;
|
|
19340
19691
|
}
|
|
19341
19692
|
async function isHermesAgentSourceRoot(candidate) {
|
|
19342
|
-
return await isDirectory(candidate) && await isDirectory(
|
|
19693
|
+
return await isDirectory(candidate) && await isDirectory(path21.join(candidate, "tools")) && await isDirectory(path21.join(candidate, "hermes_cli"));
|
|
19343
19694
|
}
|
|
19344
19695
|
async function isDirectory(candidate) {
|
|
19345
19696
|
return stat13(candidate).then((info) => info.isDirectory()).catch(() => false);
|
|
@@ -19351,13 +19702,13 @@ function compactProcessOutput(value) {
|
|
|
19351
19702
|
|
|
19352
19703
|
// src/hermes/usage-probe.ts
|
|
19353
19704
|
import { open as open3, readFile as readFile14, rm as rm6, stat as stat15 } from "fs/promises";
|
|
19354
|
-
import
|
|
19705
|
+
import path23 from "path";
|
|
19355
19706
|
import YAML3 from "yaml";
|
|
19356
19707
|
|
|
19357
19708
|
// src/hermes/profiles.ts
|
|
19358
19709
|
import { execFile as execFile4 } from "child_process";
|
|
19359
19710
|
import { readdir as readdir8, readFile as readFile13, rename as rename3, stat as stat14 } from "fs/promises";
|
|
19360
|
-
import
|
|
19711
|
+
import path22 from "path";
|
|
19361
19712
|
import { setTimeout as delay4 } from "timers/promises";
|
|
19362
19713
|
import { promisify as promisify4 } from "util";
|
|
19363
19714
|
import YAML2 from "yaml";
|
|
@@ -19500,7 +19851,7 @@ async function readHermesProfileCapabilities(name) {
|
|
|
19500
19851
|
return {
|
|
19501
19852
|
defaultModel: listedModels?.defaultModel ?? null,
|
|
19502
19853
|
modelCount: listedModels?.models.length ?? 0,
|
|
19503
|
-
skillCount: await countSkills(
|
|
19854
|
+
skillCount: await countSkills(path22.join(profileDir, "skills")).catch(
|
|
19504
19855
|
() => 0
|
|
19505
19856
|
),
|
|
19506
19857
|
toolCount: await countConfiguredTools(name).catch(() => 0)
|
|
@@ -19561,7 +19912,7 @@ async function hasDefaultProfileConfigSource() {
|
|
|
19561
19912
|
if (!profileStat?.isDirectory()) {
|
|
19562
19913
|
return false;
|
|
19563
19914
|
}
|
|
19564
|
-
return await pathExists(resolveHermesConfigPath(DEFAULT_PROFILE)) || await pathExists(
|
|
19915
|
+
return await pathExists(resolveHermesConfigPath(DEFAULT_PROFILE)) || await pathExists(path22.join(profilePath, ".env"));
|
|
19565
19916
|
}
|
|
19566
19917
|
async function deleteHermesProfileWithCli(name) {
|
|
19567
19918
|
try {
|
|
@@ -19731,7 +20082,7 @@ async function countSkills(root) {
|
|
|
19731
20082
|
);
|
|
19732
20083
|
let count = 0;
|
|
19733
20084
|
for (const entry of entries) {
|
|
19734
|
-
const entryPath =
|
|
20085
|
+
const entryPath = path22.join(root, entry.name);
|
|
19735
20086
|
if (entry.name === ".git" || entry.name === ".hub") {
|
|
19736
20087
|
continue;
|
|
19737
20088
|
}
|
|
@@ -19824,7 +20175,7 @@ async function ensureHermesUsageProbeForProfile(profileName, options = {}) {
|
|
|
19824
20175
|
const normalizedProfile = normalizeProfileName4(profileName);
|
|
19825
20176
|
const profilePath = resolveHermesProfileDir(normalizedProfile);
|
|
19826
20177
|
const configPath = resolveHermesConfigPath(normalizedProfile);
|
|
19827
|
-
const pluginPath =
|
|
20178
|
+
const pluginPath = path23.join(
|
|
19828
20179
|
profilePath,
|
|
19829
20180
|
"plugins",
|
|
19830
20181
|
HERMES_USAGE_PROBE_PLUGIN_KEY
|
|
@@ -19850,7 +20201,7 @@ async function ensureHermesUsageProbeForProfile(profileName, options = {}) {
|
|
|
19850
20201
|
return { ...base(), skipped: true };
|
|
19851
20202
|
}
|
|
19852
20203
|
try {
|
|
19853
|
-
await ensureDirectoryWithInheritedMetadata(
|
|
20204
|
+
await ensureDirectoryWithInheritedMetadata(path23.dirname(eventsPath), 448);
|
|
19854
20205
|
const state = await readUsageProbeState(paths);
|
|
19855
20206
|
const pluginState = state.profiles[normalizedProfile];
|
|
19856
20207
|
const currentConfig = await readUsageProbeConfigStatus({
|
|
@@ -19983,7 +20334,7 @@ async function findHermesUsageProbeEventForRun(input) {
|
|
|
19983
20334
|
return aggregateUsageProbeEvents(events.sort(compareUsageProbeEventsByTime));
|
|
19984
20335
|
}
|
|
19985
20336
|
function resolveUsageProbeEventsPath(paths = resolveRuntimePaths(), profileName = "default") {
|
|
19986
|
-
return
|
|
20337
|
+
return path23.join(
|
|
19987
20338
|
paths.homeDir,
|
|
19988
20339
|
USAGE_PROBE_DIR,
|
|
19989
20340
|
safeProfileSegment(profileName),
|
|
@@ -20007,8 +20358,8 @@ function summarizeUsageProbeEnsure(result) {
|
|
|
20007
20358
|
};
|
|
20008
20359
|
}
|
|
20009
20360
|
async function writeUsageProbePlugin(input) {
|
|
20010
|
-
const manifestPath =
|
|
20011
|
-
const initPath =
|
|
20361
|
+
const manifestPath = path23.join(input.pluginPath, "plugin.yaml");
|
|
20362
|
+
const initPath = path23.join(input.pluginPath, "__init__.py");
|
|
20012
20363
|
const manifest = usageProbeManifest();
|
|
20013
20364
|
const source = usageProbePythonSource(
|
|
20014
20365
|
input.profileName,
|
|
@@ -20355,9 +20706,9 @@ async function disableUsageProbeAfterActivationFailure(input) {
|
|
|
20355
20706
|
});
|
|
20356
20707
|
}
|
|
20357
20708
|
async function cleanupLegacyUsageProbePlugin(profilePath) {
|
|
20358
|
-
const legacyPath =
|
|
20709
|
+
const legacyPath = path23.join(profilePath, "plugins", LEGACY_PLUGIN_KEY);
|
|
20359
20710
|
const [manifest, init] = await Promise.all([
|
|
20360
|
-
readFile14(
|
|
20711
|
+
readFile14(path23.join(legacyPath, "plugin.yaml"), "utf8").catch(
|
|
20361
20712
|
(error) => {
|
|
20362
20713
|
if (isNodeError15(error, "ENOENT")) {
|
|
20363
20714
|
return null;
|
|
@@ -20365,7 +20716,7 @@ async function cleanupLegacyUsageProbePlugin(profilePath) {
|
|
|
20365
20716
|
throw error;
|
|
20366
20717
|
}
|
|
20367
20718
|
),
|
|
20368
|
-
readFile14(
|
|
20719
|
+
readFile14(path23.join(legacyPath, "__init__.py"), "utf8").catch(
|
|
20369
20720
|
(error) => {
|
|
20370
20721
|
if (isNodeError15(error, "ENOENT")) {
|
|
20371
20722
|
return null;
|
|
@@ -20414,7 +20765,7 @@ async function rememberUsageProbeState(paths, profileName, patch) {
|
|
|
20414
20765
|
}));
|
|
20415
20766
|
}
|
|
20416
20767
|
function usageProbeStatePath(paths) {
|
|
20417
|
-
return
|
|
20768
|
+
return path23.join(paths.homeDir, USAGE_PROBE_DIR, USAGE_PROBE_STATE_FILE);
|
|
20418
20769
|
}
|
|
20419
20770
|
async function readHermesConfigDocument2(configPath, language) {
|
|
20420
20771
|
const existingRaw = await readFile14(configPath, "utf8").catch(
|
|
@@ -21017,7 +21368,7 @@ function isRunToolResultCompensationEnabled(env = process.env) {
|
|
|
21017
21368
|
|
|
21018
21369
|
// src/conversations/run-transcript-enrichment.ts
|
|
21019
21370
|
import { readFile as readFile15, stat as stat16 } from "fs/promises";
|
|
21020
|
-
import
|
|
21371
|
+
import path24 from "path";
|
|
21021
21372
|
var MESSAGE_COLUMNS2 = [
|
|
21022
21373
|
"id",
|
|
21023
21374
|
"session_id",
|
|
@@ -21093,8 +21444,8 @@ async function readRunFinalAssistantText(input) {
|
|
|
21093
21444
|
}
|
|
21094
21445
|
async function readHermesTranscriptRows(profileName, sessionId) {
|
|
21095
21446
|
const profileDir = resolveHermesProfileDir(profileName);
|
|
21096
|
-
const dbPath =
|
|
21097
|
-
const sessionsDir = await readHermesSessionsDir(profileName).then((value) => value.sessionsDir).catch(() =>
|
|
21447
|
+
const dbPath = path24.join(profileDir, "state.db");
|
|
21448
|
+
const sessionsDir = await readHermesSessionsDir(profileName).then((value) => value.sessionsDir).catch(() => path24.join(profileDir, "sessions"));
|
|
21098
21449
|
const [dbRows, jsonlRows] = await Promise.all([
|
|
21099
21450
|
readStateDbMessages2(dbPath, sessionId),
|
|
21100
21451
|
readJsonlMessages2(sessionsDir, sessionId)
|
|
@@ -21157,7 +21508,7 @@ async function readJsonlMessages2(sessionsDir, sessionId) {
|
|
|
21157
21508
|
if (!/^[A-Za-z0-9._:-]{1,160}$/u.test(sessionId)) {
|
|
21158
21509
|
return [];
|
|
21159
21510
|
}
|
|
21160
|
-
const transcriptPath =
|
|
21511
|
+
const transcriptPath = path24.join(sessionsDir, `${sessionId}.jsonl`);
|
|
21161
21512
|
const raw = await readFile15(transcriptPath, "utf8").catch((error) => {
|
|
21162
21513
|
if (isNodeError16(error, "ENOENT")) {
|
|
21163
21514
|
return "";
|
|
@@ -22150,6 +22501,7 @@ var ConversationRunLifecycle = class {
|
|
|
22150
22501
|
profileName: run.profile,
|
|
22151
22502
|
signal: controller.signal,
|
|
22152
22503
|
logger: this.deps.logger,
|
|
22504
|
+
language: run.language === "en" ? "en" : "zh-CN",
|
|
22153
22505
|
paths: this.deps.paths
|
|
22154
22506
|
});
|
|
22155
22507
|
await this.updateRun(conversationId, runId, {
|
|
@@ -23489,7 +23841,7 @@ ${details.join("\n")}` : localizedEmptyHermesResponseMessage(language);
|
|
|
23489
23841
|
payload: { message: assistant }
|
|
23490
23842
|
});
|
|
23491
23843
|
}
|
|
23492
|
-
const contextUsage =
|
|
23844
|
+
const contextUsage = contextUsagePayloadForSnapshot(snapshot);
|
|
23493
23845
|
await this.deps.appendEvent(conversationId, {
|
|
23494
23846
|
type: "run.completed",
|
|
23495
23847
|
message_id: assistant?.id,
|
|
@@ -23557,7 +23909,7 @@ ${details.join("\n")}` : localizedEmptyHermesResponseMessage(language);
|
|
|
23557
23909
|
assistant?.id,
|
|
23558
23910
|
expiredApprovals
|
|
23559
23911
|
);
|
|
23560
|
-
const contextUsage =
|
|
23912
|
+
const contextUsage = contextUsagePayloadForSnapshot(snapshot);
|
|
23561
23913
|
await this.deps.appendEvent(conversationId, {
|
|
23562
23914
|
type: "run.failed",
|
|
23563
23915
|
message_id: assistant?.id,
|
|
@@ -23760,11 +24112,16 @@ ${details.join("\n")}` : localizedEmptyHermesResponseMessage(language);
|
|
|
23760
24112
|
payload: { message: assistant, cancelled: true }
|
|
23761
24113
|
});
|
|
23762
24114
|
}
|
|
24115
|
+
const contextUsage = contextUsagePayloadForSnapshot(snapshot);
|
|
23763
24116
|
const event = await this.deps.appendEvent(conversationId, {
|
|
23764
24117
|
type: "run.cancelled",
|
|
23765
24118
|
message_id: assistant?.id,
|
|
23766
24119
|
run_id: runId,
|
|
23767
|
-
payload: {
|
|
24120
|
+
payload: {
|
|
24121
|
+
run,
|
|
24122
|
+
reason: options.reason,
|
|
24123
|
+
...contextUsage ? { context: contextUsage } : {}
|
|
24124
|
+
}
|
|
23768
24125
|
});
|
|
23769
24126
|
await this.deps.persistConversationStats(conversationId, snapshot);
|
|
23770
24127
|
void this.deps.logger.info("conversation_run_cancelled", {
|
|
@@ -24126,6 +24483,10 @@ function appendAgentEventBlock2(message, event, updatedAt) {
|
|
|
24126
24483
|
}
|
|
24127
24484
|
message.blocks = blocks;
|
|
24128
24485
|
}
|
|
24486
|
+
function contextUsagePayloadForSnapshot(snapshot) {
|
|
24487
|
+
const run = latestContextUsageRun(snapshot);
|
|
24488
|
+
return run ? contextUsagePayload(run) : null;
|
|
24489
|
+
}
|
|
24129
24490
|
function contextUsagePayload(run) {
|
|
24130
24491
|
const usage = run.usage;
|
|
24131
24492
|
const runtimeContext = resolveRuntimeContextUsage({
|
|
@@ -25612,7 +25973,7 @@ var ConversationService = class {
|
|
|
25612
25973
|
}
|
|
25613
25974
|
}
|
|
25614
25975
|
hermesArchiveStateSyncMarkerPath() {
|
|
25615
|
-
return
|
|
25976
|
+
return path25.join(this.paths.indexesDir, "hermes-archive-state-sync.json");
|
|
25616
25977
|
}
|
|
25617
25978
|
prepareClearAllConversationPlan(targetStatus) {
|
|
25618
25979
|
return this.maintenance.prepareClearAllConversationPlan(targetStatus);
|
|
@@ -27498,11 +27859,11 @@ function isSseRequestContext(ctx) {
|
|
|
27498
27859
|
}
|
|
27499
27860
|
return isSseRequestPath(ctx.path) || isActiveSseSocket(ctx.req.socket);
|
|
27500
27861
|
}
|
|
27501
|
-
function isSseRequestPath(
|
|
27502
|
-
if (!
|
|
27862
|
+
function isSseRequestPath(path35) {
|
|
27863
|
+
if (!path35) {
|
|
27503
27864
|
return false;
|
|
27504
27865
|
}
|
|
27505
|
-
return
|
|
27866
|
+
return path35 === "/api/v1/conversations/events" || path35 === "/api/v1/profile-creation/events" || path35 === "/api/v1/hermes/update/events" || path35 === "/api/v1/link/update/events" || /^\/api\/v1\/conversations\/[^/]+\/events$/u.test(path35) || /^\/api\/v1\/runs\/[^/]+\/events$/u.test(path35);
|
|
27506
27867
|
}
|
|
27507
27868
|
function isExpectedClientDisconnectError2(error, options = {}) {
|
|
27508
27869
|
if (!(error instanceof Error)) {
|
|
@@ -28334,7 +28695,7 @@ function errorMessage3(error) {
|
|
|
28334
28695
|
|
|
28335
28696
|
// src/hermes/profile-identity.ts
|
|
28336
28697
|
import { readFile as readFile16, stat as stat17 } from "fs/promises";
|
|
28337
|
-
import
|
|
28698
|
+
import path26 from "path";
|
|
28338
28699
|
var MAX_SOUL_MD_LENGTH = 2e4;
|
|
28339
28700
|
async function readHermesProfileIdentity(profileName, paths) {
|
|
28340
28701
|
await assertProfileExists3(profileName, paths);
|
|
@@ -28391,7 +28752,7 @@ async function assertProfileExists3(profileName, paths) {
|
|
|
28391
28752
|
}
|
|
28392
28753
|
}
|
|
28393
28754
|
function resolveSoulPath(profileName) {
|
|
28394
|
-
return
|
|
28755
|
+
return path26.join(resolveHermesProfileDir(profileName), "SOUL.md");
|
|
28395
28756
|
}
|
|
28396
28757
|
function isNodeError18(error, code) {
|
|
28397
28758
|
return error instanceof Error && "code" in error && error.code === code;
|
|
@@ -28407,13 +28768,13 @@ import {
|
|
|
28407
28768
|
rm as rm7,
|
|
28408
28769
|
stat as stat19
|
|
28409
28770
|
} from "fs/promises";
|
|
28410
|
-
import
|
|
28771
|
+
import path28 from "path";
|
|
28411
28772
|
import YAML5 from "yaml";
|
|
28412
28773
|
|
|
28413
28774
|
// src/hermes/link-skill.ts
|
|
28414
28775
|
import { readFile as readFile17, stat as stat18 } from "fs/promises";
|
|
28415
|
-
import
|
|
28416
|
-
import
|
|
28776
|
+
import os6 from "os";
|
|
28777
|
+
import path27 from "path";
|
|
28417
28778
|
import YAML4 from "yaml";
|
|
28418
28779
|
var HERMES_LINK_SKILL_ROOT_DIR = "hermes-skills";
|
|
28419
28780
|
var HERMES_LINK_SKILL_DIR = "hermes-link";
|
|
@@ -28498,7 +28859,7 @@ Do not modify Hermes profiles, delete user data, edit config files, or kill proc
|
|
|
28498
28859
|
async function ensureHermesLinkSkillInstalledForProfiles(options = {}) {
|
|
28499
28860
|
const paths = options.paths ?? resolveRuntimePaths();
|
|
28500
28861
|
const externalDir = resolveHermesLinkSkillExternalDir(paths);
|
|
28501
|
-
const skillPath =
|
|
28862
|
+
const skillPath = path27.join(
|
|
28502
28863
|
externalDir,
|
|
28503
28864
|
HERMES_LINK_SKILL_DIR,
|
|
28504
28865
|
HERMES_LINK_SKILL_FILE
|
|
@@ -28580,7 +28941,7 @@ function withDefaultProfilePlaceholder2(profiles) {
|
|
|
28580
28941
|
];
|
|
28581
28942
|
}
|
|
28582
28943
|
function resolveHermesLinkSkillExternalDir(paths = resolveRuntimePaths()) {
|
|
28583
|
-
return
|
|
28944
|
+
return path27.join(paths.homeDir, HERMES_LINK_SKILL_ROOT_DIR);
|
|
28584
28945
|
}
|
|
28585
28946
|
async function writeHermesLinkSkill(skillPath) {
|
|
28586
28947
|
const existing = await readFile17(skillPath, "utf8").catch((error) => {
|
|
@@ -28675,11 +29036,11 @@ function appendExternalDir(current, externalDir, hermesHome) {
|
|
|
28675
29036
|
const seen = new Set(
|
|
28676
29037
|
entries.map((entry) => resolveExternalDirEntry(entry, hermesHome))
|
|
28677
29038
|
);
|
|
28678
|
-
const normalizedExternalDir =
|
|
29039
|
+
const normalizedExternalDir = path27.resolve(externalDir);
|
|
28679
29040
|
return seen.has(normalizedExternalDir) ? entries : [...entries, normalizedExternalDir];
|
|
28680
29041
|
}
|
|
28681
29042
|
function externalDirsInclude(current, externalDir, hermesHome) {
|
|
28682
|
-
const normalizedExternalDir =
|
|
29043
|
+
const normalizedExternalDir = path27.resolve(externalDir);
|
|
28683
29044
|
return readExternalDirEntries(current).some(
|
|
28684
29045
|
(entry) => resolveExternalDirEntry(entry, hermesHome) === normalizedExternalDir
|
|
28685
29046
|
);
|
|
@@ -28690,14 +29051,14 @@ function readExternalDirEntries(value) {
|
|
|
28690
29051
|
}
|
|
28691
29052
|
function resolveExternalDirEntry(entry, hermesHome) {
|
|
28692
29053
|
const expanded = expandHome(expandEnvVars(entry));
|
|
28693
|
-
return
|
|
29054
|
+
return path27.resolve(path27.isAbsolute(expanded) ? expanded : path27.join(hermesHome, expanded));
|
|
28694
29055
|
}
|
|
28695
29056
|
function expandHome(value) {
|
|
28696
29057
|
if (value === "~") {
|
|
28697
|
-
return
|
|
29058
|
+
return os6.homedir();
|
|
28698
29059
|
}
|
|
28699
|
-
if (value.startsWith(`~${
|
|
28700
|
-
return
|
|
29060
|
+
if (value.startsWith(`~${path27.sep}`) || value.startsWith("~/")) {
|
|
29061
|
+
return path27.join(os6.homedir(), value.slice(2));
|
|
28701
29062
|
}
|
|
28702
29063
|
return value;
|
|
28703
29064
|
}
|
|
@@ -29249,7 +29610,7 @@ function collectEnvKeys(value, keys = /* @__PURE__ */ new Set()) {
|
|
|
29249
29610
|
return keys;
|
|
29250
29611
|
}
|
|
29251
29612
|
async function writeEnvValues(profileName, values) {
|
|
29252
|
-
const envPath =
|
|
29613
|
+
const envPath = path28.join(resolveHermesProfileDir(profileName), ".env");
|
|
29253
29614
|
const existingRaw = await readFile18(envPath, "utf8").catch((error) => {
|
|
29254
29615
|
if (isNodeError20(error, "ENOENT")) {
|
|
29255
29616
|
return "";
|
|
@@ -29286,8 +29647,8 @@ async function writeEnvValues(profileName, values) {
|
|
|
29286
29647
|
await atomicWriteFilePreservingMetadata(envPath, nextRaw);
|
|
29287
29648
|
}
|
|
29288
29649
|
async function copySkills(sourceProfile, targetProfile) {
|
|
29289
|
-
const sourceSkills =
|
|
29290
|
-
const targetSkills =
|
|
29650
|
+
const sourceSkills = path28.join(resolveHermesProfileDir(sourceProfile), "skills");
|
|
29651
|
+
const targetSkills = path28.join(resolveHermesProfileDir(targetProfile), "skills");
|
|
29291
29652
|
if (!await pathExists2(sourceSkills)) {
|
|
29292
29653
|
return;
|
|
29293
29654
|
}
|
|
@@ -29382,10 +29743,10 @@ async function readProfileCreationLogLines(paths) {
|
|
|
29382
29743
|
);
|
|
29383
29744
|
}
|
|
29384
29745
|
function profileCreationStatePath(paths) {
|
|
29385
|
-
return
|
|
29746
|
+
return path28.join(paths.runDir, "profile-create-state.json");
|
|
29386
29747
|
}
|
|
29387
29748
|
function profileCreationLogPath(paths) {
|
|
29388
|
-
return
|
|
29749
|
+
return path28.join(paths.logsDir, PROFILE_CREATE_LOG_FILE);
|
|
29389
29750
|
}
|
|
29390
29751
|
async function clearProfileCreationLogFiles(paths) {
|
|
29391
29752
|
const primary = profileCreationLogPath(paths);
|
|
@@ -29674,7 +30035,7 @@ import {
|
|
|
29674
30035
|
readFile as readFile19,
|
|
29675
30036
|
stat as stat20
|
|
29676
30037
|
} from "fs/promises";
|
|
29677
|
-
import
|
|
30038
|
+
import path29 from "path";
|
|
29678
30039
|
import YAML6 from "yaml";
|
|
29679
30040
|
var ENTRY_DELIMITER = "\n\xA7\n";
|
|
29680
30041
|
var DEFAULT_MEMORY_LIMIT = 2200;
|
|
@@ -30005,7 +30366,7 @@ async function saveProviderSettings(profileName, provider, patch) {
|
|
|
30005
30366
|
});
|
|
30006
30367
|
await patchJsonProviderConfig(
|
|
30007
30368
|
profileName,
|
|
30008
|
-
|
|
30369
|
+
path29.join("hindsight", "config.json"),
|
|
30009
30370
|
{
|
|
30010
30371
|
mode: patch.mode,
|
|
30011
30372
|
api_url: patch.apiUrl,
|
|
@@ -30208,7 +30569,7 @@ async function patchHermesMemoryLimits(profileName, patch) {
|
|
|
30208
30569
|
await atomicWriteFilePreservingMetadata(configPath, document.toString());
|
|
30209
30570
|
}
|
|
30210
30571
|
function resolveMemoryDir(profileName) {
|
|
30211
|
-
return
|
|
30572
|
+
return path29.join(resolveHermesProfileDir(profileName), "memories");
|
|
30212
30573
|
}
|
|
30213
30574
|
async function readMemoryStore(profileName, target, limits) {
|
|
30214
30575
|
const filePath = memoryFilePath(profileName, target);
|
|
@@ -30269,7 +30630,7 @@ async function writeMemoryEntries(profileName, target, entries) {
|
|
|
30269
30630
|
);
|
|
30270
30631
|
}
|
|
30271
30632
|
function memoryFilePath(profileName, target) {
|
|
30272
|
-
return
|
|
30633
|
+
return path29.join(
|
|
30273
30634
|
resolveMemoryDir(profileName),
|
|
30274
30635
|
target === "user" ? "USER.md" : "MEMORY.md"
|
|
30275
30636
|
);
|
|
@@ -30329,7 +30690,7 @@ async function readCustomProviderSetupSummary(profileName) {
|
|
|
30329
30690
|
configurable: true,
|
|
30330
30691
|
configured: true,
|
|
30331
30692
|
configurationIssue: null,
|
|
30332
|
-
providerConfigPath:
|
|
30693
|
+
providerConfigPath: path29.join(
|
|
30333
30694
|
resolveHermesProfileDir(profileName),
|
|
30334
30695
|
"<provider>.json"
|
|
30335
30696
|
),
|
|
@@ -30723,7 +31084,7 @@ async function readProviderSettings(profileName, provider) {
|
|
|
30723
31084
|
stringSetting(
|
|
30724
31085
|
"dbPath",
|
|
30725
31086
|
"SQLite \u6570\u636E\u5E93\u8DEF\u5F84",
|
|
30726
|
-
config.db_path ??
|
|
31087
|
+
config.db_path ?? path29.join(resolveHermesProfileDir(profileName), "memory_store.db")
|
|
30727
31088
|
),
|
|
30728
31089
|
booleanSetting("autoExtract", "\u4F1A\u8BDD\u7ED3\u675F\u81EA\u52A8\u62BD\u53D6", config.auto_extract ?? false),
|
|
30729
31090
|
numberSetting("defaultTrust", "\u9ED8\u8BA4\u4FE1\u4EFB\u5206", config.default_trust ?? 0.5),
|
|
@@ -30759,7 +31120,7 @@ async function readProviderSettings(profileName, provider) {
|
|
|
30759
31120
|
stringSetting(
|
|
30760
31121
|
"workingDirectory",
|
|
30761
31122
|
"\u5DE5\u4F5C\u76EE\u5F55",
|
|
30762
|
-
|
|
31123
|
+
path29.join(resolveHermesProfileDir(profileName), "byterover"),
|
|
30763
31124
|
false
|
|
30764
31125
|
)
|
|
30765
31126
|
];
|
|
@@ -30768,16 +31129,16 @@ async function readProviderSettings(profileName, provider) {
|
|
|
30768
31129
|
}
|
|
30769
31130
|
function memoryProviderConfigPath(profileName, provider) {
|
|
30770
31131
|
if (provider === "honcho") {
|
|
30771
|
-
return
|
|
31132
|
+
return path29.join(resolveHermesProfileDir(profileName), "honcho.json");
|
|
30772
31133
|
}
|
|
30773
31134
|
if (provider === "mem0") {
|
|
30774
|
-
return
|
|
31135
|
+
return path29.join(resolveHermesProfileDir(profileName), "mem0.json");
|
|
30775
31136
|
}
|
|
30776
31137
|
if (provider === "supermemory") {
|
|
30777
|
-
return
|
|
31138
|
+
return path29.join(resolveHermesProfileDir(profileName), "supermemory.json");
|
|
30778
31139
|
}
|
|
30779
31140
|
if (provider === "hindsight") {
|
|
30780
|
-
return
|
|
31141
|
+
return path29.join(
|
|
30781
31142
|
resolveHermesProfileDir(profileName),
|
|
30782
31143
|
"hindsight",
|
|
30783
31144
|
"config.json"
|
|
@@ -30786,13 +31147,13 @@ function memoryProviderConfigPath(profileName, provider) {
|
|
|
30786
31147
|
return null;
|
|
30787
31148
|
}
|
|
30788
31149
|
function customProviderConfigPath(profileName, provider) {
|
|
30789
|
-
return
|
|
31150
|
+
return path29.join(
|
|
30790
31151
|
resolveHermesProfileDir(profileName),
|
|
30791
31152
|
`${normalizeCustomProviderId(provider)}.json`
|
|
30792
31153
|
);
|
|
30793
31154
|
}
|
|
30794
31155
|
function customProviderRegistryPath(profileName) {
|
|
30795
|
-
return
|
|
31156
|
+
return path29.join(
|
|
30796
31157
|
resolveHermesProfileDir(profileName),
|
|
30797
31158
|
CUSTOM_PROVIDER_REGISTRY_FILE
|
|
30798
31159
|
);
|
|
@@ -30844,7 +31205,7 @@ async function saveCustomProviderRegistryEntry(profileName, provider) {
|
|
|
30844
31205
|
);
|
|
30845
31206
|
}
|
|
30846
31207
|
async function discoverUserMemoryProviderDescriptors(profileName) {
|
|
30847
|
-
const pluginsDir =
|
|
31208
|
+
const pluginsDir = path29.join(resolveHermesProfileDir(profileName), "plugins");
|
|
30848
31209
|
const entries = await readdir10(pluginsDir, { withFileTypes: true }).catch(
|
|
30849
31210
|
(error) => {
|
|
30850
31211
|
if (isNodeError21(error, "ENOENT")) {
|
|
@@ -30864,7 +31225,7 @@ async function discoverUserMemoryProviderDescriptors(profileName) {
|
|
|
30864
31225
|
} catch {
|
|
30865
31226
|
continue;
|
|
30866
31227
|
}
|
|
30867
|
-
const providerDir =
|
|
31228
|
+
const providerDir = path29.join(pluginsDir, entry.name);
|
|
30868
31229
|
if (!await isMemoryProviderPluginDir(providerDir)) {
|
|
30869
31230
|
continue;
|
|
30870
31231
|
}
|
|
@@ -30878,7 +31239,7 @@ async function discoverUserMemoryProviderDescriptors(profileName) {
|
|
|
30878
31239
|
return descriptors;
|
|
30879
31240
|
}
|
|
30880
31241
|
async function isUserMemoryProviderInstalled(profileName, provider) {
|
|
30881
|
-
const providerDir =
|
|
31242
|
+
const providerDir = path29.join(
|
|
30882
31243
|
resolveHermesProfileDir(profileName),
|
|
30883
31244
|
"plugins",
|
|
30884
31245
|
normalizeCustomProviderId(provider)
|
|
@@ -30886,7 +31247,7 @@ async function isUserMemoryProviderInstalled(profileName, provider) {
|
|
|
30886
31247
|
return isMemoryProviderPluginDir(providerDir);
|
|
30887
31248
|
}
|
|
30888
31249
|
async function isMemoryProviderPluginDir(providerDir) {
|
|
30889
|
-
const source = await readFile19(
|
|
31250
|
+
const source = await readFile19(path29.join(providerDir, "__init__.py"), "utf8").catch(
|
|
30890
31251
|
(error) => {
|
|
30891
31252
|
if (isNodeError21(error, "ENOENT")) {
|
|
30892
31253
|
return "";
|
|
@@ -30898,7 +31259,7 @@ async function isMemoryProviderPluginDir(providerDir) {
|
|
|
30898
31259
|
return sample.includes("register_memory_provider") || sample.includes("MemoryProvider");
|
|
30899
31260
|
}
|
|
30900
31261
|
async function readPluginMetadata(providerDir) {
|
|
30901
|
-
const raw = await readFile19(
|
|
31262
|
+
const raw = await readFile19(path29.join(providerDir, "plugin.yaml"), "utf8").catch(
|
|
30902
31263
|
(error) => {
|
|
30903
31264
|
if (isNodeError21(error, "ENOENT")) {
|
|
30904
31265
|
return "";
|
|
@@ -30910,10 +31271,10 @@ async function readPluginMetadata(providerDir) {
|
|
|
30910
31271
|
}
|
|
30911
31272
|
async function resolveByteRoverCli() {
|
|
30912
31273
|
const candidates = [
|
|
30913
|
-
...(process.env.PATH ?? "").split(
|
|
30914
|
-
|
|
31274
|
+
...(process.env.PATH ?? "").split(path29.delimiter).filter(Boolean).map((dir) => path29.join(dir, "brv")),
|
|
31275
|
+
path29.join(process.env.HOME ?? "", ".brv-cli", "bin", "brv"),
|
|
30915
31276
|
"/usr/local/bin/brv",
|
|
30916
|
-
|
|
31277
|
+
path29.join(process.env.HOME ?? "", ".npm-global", "bin", "brv")
|
|
30917
31278
|
].filter(Boolean);
|
|
30918
31279
|
for (const candidate of candidates) {
|
|
30919
31280
|
const found = await access3(candidate).then(() => true).catch(() => false);
|
|
@@ -30974,7 +31335,7 @@ async function patchHermesMemoryEnv(profileName, patch) {
|
|
|
30974
31335
|
if (entries.length === 0) {
|
|
30975
31336
|
return;
|
|
30976
31337
|
}
|
|
30977
|
-
const envPath =
|
|
31338
|
+
const envPath = path29.join(resolveHermesProfileDir(profileName), ".env");
|
|
30978
31339
|
const existingRaw = await readFile19(envPath, "utf8").catch((error) => {
|
|
30979
31340
|
if (isNodeError21(error, "ENOENT")) {
|
|
30980
31341
|
return "";
|
|
@@ -31145,7 +31506,7 @@ async function readActiveMemoryProvider(profileName) {
|
|
|
31145
31506
|
return provider;
|
|
31146
31507
|
}
|
|
31147
31508
|
async function patchJsonProviderConfig(profileName, relativePath, patch) {
|
|
31148
|
-
const configPath =
|
|
31509
|
+
const configPath = path29.join(
|
|
31149
31510
|
resolveHermesProfileDir(profileName),
|
|
31150
31511
|
relativePath
|
|
31151
31512
|
);
|
|
@@ -31174,7 +31535,7 @@ async function readJsonObject(filePath) {
|
|
|
31174
31535
|
} catch {
|
|
31175
31536
|
throw new HermesMemoryError(
|
|
31176
31537
|
"memory_provider_config_invalid",
|
|
31177
|
-
`${
|
|
31538
|
+
`${path29.basename(filePath)} \u4E0D\u662F\u6709\u6548\u7684 JSON \u914D\u7F6E\u6587\u4EF6\u3002`
|
|
31178
31539
|
);
|
|
31179
31540
|
}
|
|
31180
31541
|
}
|
|
@@ -31798,7 +32159,7 @@ function toMemoryHttpError(error) {
|
|
|
31798
32159
|
|
|
31799
32160
|
// src/hermes/skills.ts
|
|
31800
32161
|
import { readFile as readFile20, readdir as readdir11 } from "fs/promises";
|
|
31801
|
-
import
|
|
32162
|
+
import path30 from "path";
|
|
31802
32163
|
import YAML7 from "yaml";
|
|
31803
32164
|
var HermesSkillNotFoundError = class extends Error {
|
|
31804
32165
|
constructor(skillName) {
|
|
@@ -31812,7 +32173,7 @@ var EXCLUDED_SKILL_DIRS = /* @__PURE__ */ new Set([".git", ".github", ".hub"]);
|
|
|
31812
32173
|
async function listHermesProfileSkills(profileName, paths = resolveRuntimePaths()) {
|
|
31813
32174
|
const profile = await readExistingProfile(profileName, paths);
|
|
31814
32175
|
const profileDir = resolveHermesProfileDir(profile.name);
|
|
31815
|
-
const skillsRoot =
|
|
32176
|
+
const skillsRoot = path30.join(profileDir, "skills");
|
|
31816
32177
|
const [skillFiles, disabled, provenance] = await Promise.all([
|
|
31817
32178
|
findSkillFiles(skillsRoot),
|
|
31818
32179
|
readDisabledSkillNames(resolveHermesConfigPath(profile.name)),
|
|
@@ -31903,7 +32264,7 @@ async function collectSkillFiles(directory, results) {
|
|
|
31903
32264
|
if (EXCLUDED_SKILL_DIRS.has(entry.name)) {
|
|
31904
32265
|
continue;
|
|
31905
32266
|
}
|
|
31906
|
-
const entryPath =
|
|
32267
|
+
const entryPath = path30.join(directory, entry.name);
|
|
31907
32268
|
if (entry.isDirectory()) {
|
|
31908
32269
|
await collectSkillFiles(entryPath, results);
|
|
31909
32270
|
continue;
|
|
@@ -31925,10 +32286,10 @@ async function readSkillMetadata(input) {
|
|
|
31925
32286
|
if (raw === null) {
|
|
31926
32287
|
return null;
|
|
31927
32288
|
}
|
|
31928
|
-
const skillDir =
|
|
32289
|
+
const skillDir = path30.dirname(input.skillFile);
|
|
31929
32290
|
const { frontmatter, body } = parseSkillDocument(raw.slice(0, 4e3));
|
|
31930
32291
|
const name = normalizeSkillName(
|
|
31931
|
-
readString21(frontmatter.name) ??
|
|
32292
|
+
readString21(frontmatter.name) ?? path30.basename(skillDir)
|
|
31932
32293
|
);
|
|
31933
32294
|
if (!name) {
|
|
31934
32295
|
return null;
|
|
@@ -31947,7 +32308,7 @@ async function readSkillMetadata(input) {
|
|
|
31947
32308
|
enabled: !input.disabled.has(name),
|
|
31948
32309
|
source: provenance.source,
|
|
31949
32310
|
trust: provenance.trust,
|
|
31950
|
-
relativePath:
|
|
32311
|
+
relativePath: path30.relative(input.skillsRoot, skillDir)
|
|
31951
32312
|
};
|
|
31952
32313
|
}
|
|
31953
32314
|
function parseSkillDocument(raw) {
|
|
@@ -31968,8 +32329,8 @@ function parseSkillDocument(raw) {
|
|
|
31968
32329
|
}
|
|
31969
32330
|
}
|
|
31970
32331
|
function categoryFromPath(skillsRoot, skillFile) {
|
|
31971
|
-
const relative =
|
|
31972
|
-
const parts = relative.split(
|
|
32332
|
+
const relative = path30.relative(skillsRoot, skillFile);
|
|
32333
|
+
const parts = relative.split(path30.sep).filter(Boolean);
|
|
31973
32334
|
return parts.length >= 3 ? parts[0] : null;
|
|
31974
32335
|
}
|
|
31975
32336
|
function firstBodyDescription(body) {
|
|
@@ -32016,7 +32377,7 @@ async function readSkillProvenance(root) {
|
|
|
32016
32377
|
return provenance;
|
|
32017
32378
|
}
|
|
32018
32379
|
async function readBundledSkillNames(root) {
|
|
32019
|
-
const raw = await readFile20(
|
|
32380
|
+
const raw = await readFile20(path30.join(root, ".bundled_manifest"), "utf8").catch(
|
|
32020
32381
|
(error) => {
|
|
32021
32382
|
if (isNodeError22(error, "ENOENT")) {
|
|
32022
32383
|
return "";
|
|
@@ -32039,7 +32400,7 @@ async function readBundledSkillNames(root) {
|
|
|
32039
32400
|
return names;
|
|
32040
32401
|
}
|
|
32041
32402
|
async function readHubInstalledSkills(root) {
|
|
32042
|
-
const raw = await readFile20(
|
|
32403
|
+
const raw = await readFile20(path30.join(root, ".hub", "lock.json"), "utf8").catch(
|
|
32043
32404
|
(error) => {
|
|
32044
32405
|
if (isNodeError22(error, "ENOENT")) {
|
|
32045
32406
|
return "";
|
|
@@ -32516,6 +32877,7 @@ function registerRunRoutes(router, options) {
|
|
|
32516
32877
|
const { paths, logger, conversations } = options;
|
|
32517
32878
|
router.post("/api/v1/runs", async (ctx) => {
|
|
32518
32879
|
await authenticateRequest(ctx, paths);
|
|
32880
|
+
const language = readPreferredLanguage(ctx);
|
|
32519
32881
|
const body = await readJsonBody(ctx.req);
|
|
32520
32882
|
const input = readString19(body, "input");
|
|
32521
32883
|
if (!input) {
|
|
@@ -32532,14 +32894,16 @@ function registerRunRoutes(router, options) {
|
|
|
32532
32894
|
session_id: readString19(body, "session_id") ?? readString19(body, "sessionId") ?? void 0,
|
|
32533
32895
|
session_key: readString19(body, "session_key") ?? readString19(body, "sessionKey") ?? void 0
|
|
32534
32896
|
},
|
|
32535
|
-
{ logger, profileName: readOptionalProfileName(body) }
|
|
32897
|
+
{ logger, profileName: readOptionalProfileName(body), language }
|
|
32536
32898
|
);
|
|
32537
32899
|
});
|
|
32538
32900
|
router.get("/api/v1/runs/:runId/events", async (ctx) => {
|
|
32539
32901
|
await authenticateRequest(ctx, paths);
|
|
32902
|
+
const language = readPreferredLanguage(ctx);
|
|
32540
32903
|
const response = await streamHermesRunEvents(ctx.params.runId, {
|
|
32541
32904
|
logger,
|
|
32542
|
-
profileName: readQueryString(ctx.query.profile)
|
|
32905
|
+
profileName: readQueryString(ctx.query.profile),
|
|
32906
|
+
language
|
|
32543
32907
|
});
|
|
32544
32908
|
ctx.status = response.status;
|
|
32545
32909
|
for (const [key, value] of response.headers.entries()) {
|
|
@@ -32561,6 +32925,7 @@ function registerRunRoutes(router, options) {
|
|
|
32561
32925
|
});
|
|
32562
32926
|
router.post("/api/v1/runs/:runId/cancel", async (ctx) => {
|
|
32563
32927
|
await authenticateRequest(ctx, paths);
|
|
32928
|
+
const language = readPreferredLanguage(ctx);
|
|
32564
32929
|
try {
|
|
32565
32930
|
ctx.body = {
|
|
32566
32931
|
ok: true,
|
|
@@ -32572,7 +32937,8 @@ function registerRunRoutes(router, options) {
|
|
|
32572
32937
|
}
|
|
32573
32938
|
await cancelHermesRun(ctx.params.runId, {
|
|
32574
32939
|
logger,
|
|
32575
|
-
profileName: readQueryString(ctx.query.profile)
|
|
32940
|
+
profileName: readQueryString(ctx.query.profile),
|
|
32941
|
+
language
|
|
32576
32942
|
});
|
|
32577
32943
|
ctx.body = { ok: true };
|
|
32578
32944
|
}
|
|
@@ -32702,7 +33068,7 @@ function readModelList(payload) {
|
|
|
32702
33068
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
32703
33069
|
import { spawn as spawn4 } from "child_process";
|
|
32704
33070
|
import { mkdir as mkdir13, readFile as readFile21, rm as rm8 } from "fs/promises";
|
|
32705
|
-
import
|
|
33071
|
+
import path31 from "path";
|
|
32706
33072
|
var SERVER_HERMES_RELEASES_LATEST_PATH = "/api/v1/hermes-agent/releases/latest";
|
|
32707
33073
|
var RELEASE_CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
32708
33074
|
var RELEASE_FETCH_TIMEOUT_MS = 5e3;
|
|
@@ -32980,13 +33346,13 @@ async function readUpdateLogLines(paths) {
|
|
|
32980
33346
|
);
|
|
32981
33347
|
}
|
|
32982
33348
|
function releaseCachePath(paths) {
|
|
32983
|
-
return
|
|
33349
|
+
return path31.join(paths.indexesDir, "hermes-release-check.json");
|
|
32984
33350
|
}
|
|
32985
33351
|
function updateStatePath(paths) {
|
|
32986
|
-
return
|
|
33352
|
+
return path31.join(paths.runDir, "hermes-update-state.json");
|
|
32987
33353
|
}
|
|
32988
33354
|
function updateLogPath(paths) {
|
|
32989
|
-
return
|
|
33355
|
+
return path31.join(paths.logsDir, UPDATE_LOG_FILE);
|
|
32990
33356
|
}
|
|
32991
33357
|
async function clearUpdateLogFiles(paths) {
|
|
32992
33358
|
const primary = updateLogPath(paths);
|
|
@@ -33087,12 +33453,12 @@ function readString22(payload, key) {
|
|
|
33087
33453
|
import { spawn as spawn6 } from "child_process";
|
|
33088
33454
|
import { EventEmitter as EventEmitter4 } from "events";
|
|
33089
33455
|
import { mkdir as mkdir16, readFile as readFile23, rm as rm11 } from "fs/promises";
|
|
33090
|
-
import
|
|
33456
|
+
import path33 from "path";
|
|
33091
33457
|
|
|
33092
33458
|
// src/daemon/process.ts
|
|
33093
33459
|
import { spawn as spawn5 } from "child_process";
|
|
33094
33460
|
import { mkdir as mkdir15, readFile as readFile22, rm as rm10, writeFile as writeFile4 } from "fs/promises";
|
|
33095
|
-
import
|
|
33461
|
+
import path32 from "path";
|
|
33096
33462
|
|
|
33097
33463
|
// src/daemon/service.ts
|
|
33098
33464
|
import { createServer } from "http";
|
|
@@ -33768,8 +34134,8 @@ function normalizeMessage(value) {
|
|
|
33768
34134
|
|
|
33769
34135
|
// src/runtime/system-info.ts
|
|
33770
34136
|
import { execFileSync } from "child_process";
|
|
33771
|
-
import { readFileSync } from "fs";
|
|
33772
|
-
import
|
|
34137
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
34138
|
+
import os7 from "os";
|
|
33773
34139
|
function readLinkSystemInfo() {
|
|
33774
34140
|
const platform = process.platform;
|
|
33775
34141
|
const hostname = readHostname(platform);
|
|
@@ -33808,7 +34174,7 @@ function readHostname(platform) {
|
|
|
33808
34174
|
return computerName;
|
|
33809
34175
|
}
|
|
33810
34176
|
}
|
|
33811
|
-
return normalizeText(
|
|
34177
|
+
return normalizeText(os7.hostname());
|
|
33812
34178
|
}
|
|
33813
34179
|
function readOsLabel(platform) {
|
|
33814
34180
|
if (platform === "darwin") {
|
|
@@ -33816,17 +34182,17 @@ function readOsLabel(platform) {
|
|
|
33816
34182
|
return version ? `macOS ${version}` : "macOS";
|
|
33817
34183
|
}
|
|
33818
34184
|
if (platform === "linux") {
|
|
33819
|
-
return readLinuxOsRelease() ?? `Linux ${
|
|
34185
|
+
return readLinuxOsRelease() ?? `Linux ${os7.release()}`;
|
|
33820
34186
|
}
|
|
33821
34187
|
if (platform === "win32") {
|
|
33822
|
-
return `Windows ${
|
|
34188
|
+
return `Windows ${os7.release()}`;
|
|
33823
34189
|
}
|
|
33824
|
-
return `${
|
|
34190
|
+
return `${os7.type()} ${os7.release()}`.trim();
|
|
33825
34191
|
}
|
|
33826
34192
|
function readLinuxOsRelease() {
|
|
33827
34193
|
for (const file of ["/etc/os-release", "/usr/lib/os-release"]) {
|
|
33828
34194
|
try {
|
|
33829
|
-
return parseLinuxOsRelease(
|
|
34195
|
+
return parseLinuxOsRelease(readFileSync2(file, "utf8"));
|
|
33830
34196
|
} catch {
|
|
33831
34197
|
}
|
|
33832
34198
|
}
|
|
@@ -33868,11 +34234,11 @@ function truncateText(value, maxLength) {
|
|
|
33868
34234
|
}
|
|
33869
34235
|
|
|
33870
34236
|
// src/topology/network.ts
|
|
33871
|
-
import
|
|
34237
|
+
import os9 from "os";
|
|
33872
34238
|
|
|
33873
34239
|
// src/topology/environment.ts
|
|
33874
|
-
import { existsSync, readFileSync as
|
|
33875
|
-
import
|
|
34240
|
+
import { existsSync, readFileSync as readFileSync3 } from "fs";
|
|
34241
|
+
import os8 from "os";
|
|
33876
34242
|
function detectRuntimeEnvironment(env = process.env) {
|
|
33877
34243
|
if (isWsl(env)) {
|
|
33878
34244
|
return {
|
|
@@ -33901,7 +34267,7 @@ function isWsl(env) {
|
|
|
33901
34267
|
if (env.WSL_DISTRO_NAME || env.WSL_INTEROP) {
|
|
33902
34268
|
return true;
|
|
33903
34269
|
}
|
|
33904
|
-
const release =
|
|
34270
|
+
const release = os8.release().toLowerCase();
|
|
33905
34271
|
return release.includes("microsoft") || release.includes("wsl");
|
|
33906
34272
|
}
|
|
33907
34273
|
function isContainer(env) {
|
|
@@ -33912,7 +34278,7 @@ function isContainer(env) {
|
|
|
33912
34278
|
return true;
|
|
33913
34279
|
}
|
|
33914
34280
|
try {
|
|
33915
|
-
const cgroup =
|
|
34281
|
+
const cgroup = readFileSync3("/proc/1/cgroup", "utf8").toLowerCase();
|
|
33916
34282
|
return /docker|containerd|kubepods|libpod|podman/u.test(cgroup);
|
|
33917
34283
|
} catch {
|
|
33918
34284
|
return false;
|
|
@@ -33946,7 +34312,7 @@ async function discoverRouteCandidates(options) {
|
|
|
33946
34312
|
};
|
|
33947
34313
|
}
|
|
33948
34314
|
function discoverLanIps() {
|
|
33949
|
-
return discoverLanIpsFromInterfaces(
|
|
34315
|
+
return discoverLanIpsFromInterfaces(os9.networkInterfaces());
|
|
33950
34316
|
}
|
|
33951
34317
|
function discoverLanIpsFromInterfaces(interfaces) {
|
|
33952
34318
|
const result = /* @__PURE__ */ new Set();
|
|
@@ -35039,7 +35405,7 @@ async function runDaemonSupervisor(paths = resolveRuntimePaths()) {
|
|
|
35039
35405
|
await mkdir15(paths.logsDir, { recursive: true, mode: 448 });
|
|
35040
35406
|
const log = createRotatingTextLogWriter({
|
|
35041
35407
|
paths,
|
|
35042
|
-
fileName:
|
|
35408
|
+
fileName: path32.basename(daemonLogFile(paths))
|
|
35043
35409
|
});
|
|
35044
35410
|
const scriptPath = currentCliScriptPath();
|
|
35045
35411
|
const write = (chunk) => {
|
|
@@ -35337,7 +35703,7 @@ function terminateChild(child, previousForceKillTimer) {
|
|
|
35337
35703
|
}
|
|
35338
35704
|
}
|
|
35339
35705
|
function supervisorStopIntentPath(paths) {
|
|
35340
|
-
return
|
|
35706
|
+
return path32.join(paths.runDir, "supervisor-stop-intent.json");
|
|
35341
35707
|
}
|
|
35342
35708
|
async function writeSupervisorStopIntent(paths, pid) {
|
|
35343
35709
|
await mkdir15(paths.runDir, { recursive: true, mode: 448 });
|
|
@@ -35900,7 +36266,7 @@ async function buildOfficialInstallCommand(options, targetVersion) {
|
|
|
35900
36266
|
};
|
|
35901
36267
|
}
|
|
35902
36268
|
function buildUnixInstallCommand(installerUrl) {
|
|
35903
|
-
const nodeBinDir =
|
|
36269
|
+
const nodeBinDir = path33.dirname(process.execPath);
|
|
35904
36270
|
const fetchScript = [
|
|
35905
36271
|
quoteShellToken(process.execPath),
|
|
35906
36272
|
"--input-type=module",
|
|
@@ -36170,10 +36536,10 @@ async function readUpdateLogLines2(paths) {
|
|
|
36170
36536
|
);
|
|
36171
36537
|
}
|
|
36172
36538
|
function updateStatePath2(paths) {
|
|
36173
|
-
return
|
|
36539
|
+
return path33.join(paths.runDir, "link-update-state.json");
|
|
36174
36540
|
}
|
|
36175
36541
|
function updateLogPath2(paths) {
|
|
36176
|
-
return
|
|
36542
|
+
return path33.join(paths.logsDir, UPDATE_LOG_FILE2);
|
|
36177
36543
|
}
|
|
36178
36544
|
async function clearUpdateLogFiles2(paths) {
|
|
36179
36545
|
const primary = updateLogPath2(paths);
|
|
@@ -36257,7 +36623,7 @@ function readString23(payload, key) {
|
|
|
36257
36623
|
}
|
|
36258
36624
|
|
|
36259
36625
|
// src/pairing/pairing.ts
|
|
36260
|
-
import
|
|
36626
|
+
import path34 from "path";
|
|
36261
36627
|
import { rm as rm12 } from "fs/promises";
|
|
36262
36628
|
|
|
36263
36629
|
// src/relay/bootstrap.ts
|
|
@@ -36597,10 +36963,10 @@ async function loadRequiredIdentity2(paths) {
|
|
|
36597
36963
|
}
|
|
36598
36964
|
return identity;
|
|
36599
36965
|
}
|
|
36600
|
-
async function postServerJson(serverBaseUrl,
|
|
36966
|
+
async function postServerJson(serverBaseUrl, path35, body, options) {
|
|
36601
36967
|
let response;
|
|
36602
36968
|
try {
|
|
36603
|
-
response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${
|
|
36969
|
+
response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path35}`, {
|
|
36604
36970
|
method: "POST",
|
|
36605
36971
|
headers: {
|
|
36606
36972
|
accept: "application/json",
|
|
@@ -36648,10 +37014,10 @@ function pairingErrorSnapshot(stage, error) {
|
|
|
36648
37014
|
occurred_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
36649
37015
|
};
|
|
36650
37016
|
}
|
|
36651
|
-
async function patchServerJson(serverBaseUrl,
|
|
37017
|
+
async function patchServerJson(serverBaseUrl, path35, token, body, options) {
|
|
36652
37018
|
let response;
|
|
36653
37019
|
try {
|
|
36654
|
-
response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${
|
|
37020
|
+
response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path35}`, {
|
|
36655
37021
|
method: "PATCH",
|
|
36656
37022
|
headers: {
|
|
36657
37023
|
accept: "application/json",
|
|
@@ -36699,10 +37065,10 @@ function createPairingNetworkError(input) {
|
|
|
36699
37065
|
);
|
|
36700
37066
|
}
|
|
36701
37067
|
function pairingClaimPath(sessionId, paths) {
|
|
36702
|
-
return
|
|
37068
|
+
return path34.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.claimed.json`);
|
|
36703
37069
|
}
|
|
36704
37070
|
function pairingSessionPath(sessionId, paths) {
|
|
36705
|
-
return
|
|
37071
|
+
return path34.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.json`);
|
|
36706
37072
|
}
|
|
36707
37073
|
function qrPreferredUrls(routes) {
|
|
36708
37074
|
return routes.preferredUrls.filter((url) => !url.includes("/api/v1/relay/links/")).slice(0, 1);
|
|
@@ -38029,6 +38395,7 @@ export {
|
|
|
38029
38395
|
getGatewayLogFiles,
|
|
38030
38396
|
readRecentGatewayLogEntries,
|
|
38031
38397
|
flushLogFiles,
|
|
38398
|
+
resolveHermesBin,
|
|
38032
38399
|
HermesApiServerUnavailableError,
|
|
38033
38400
|
ensureHermesApiServerAvailable,
|
|
38034
38401
|
readHermesVersion,
|