@hermespilot/link 0.6.5 → 0.6.7
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-IJOWAEQ4.js → chunk-FWX7ZUP4.js} +311 -16
- package/dist/cli/index.js +47 -2
- package/dist/http/app.d.ts +20 -0
- package/dist/http/app.js +1 -1
- package/package.json +1 -1
|
@@ -1465,6 +1465,9 @@ var messages = {
|
|
|
1465
1465
|
"config.notice.autoFilled": "Hermes API Server was auto-filled with {fields}; existing port/host/key were not overwritten.",
|
|
1466
1466
|
"config.notice.repairDefault": "Hermes API Server kept the default port and rotated the key to repair an old Gateway or a key mismatch that caused 401.",
|
|
1467
1467
|
"config.notice.repairProfile": "Hermes API Server was reassigned a local port and had its key rotated to repair an old Gateway or a key mismatch that caused 401.",
|
|
1468
|
+
"config.yaml.invalid": "Hermes Profile config is not valid YAML, so Link cannot write settings yet. Fix {path}, then try again.{details}{more}",
|
|
1469
|
+
"config.yaml.details": " YAML error: {errors}",
|
|
1470
|
+
"config.yaml.more": " and {count} more error(s).",
|
|
1468
1471
|
"daemon.description": "Run Hermes Link in the foreground",
|
|
1469
1472
|
"daemon.foreground": "Hermes Link foreground daemon is running. Press Ctrl+C to stop.",
|
|
1470
1473
|
"logs.description": "Show or follow Hermes Link logs",
|
|
@@ -1520,6 +1523,7 @@ var messages = {
|
|
|
1520
1523
|
"pair.autostartFailed": "Pairing succeeded, but boot autostart could not be enabled: {message}",
|
|
1521
1524
|
"doctor.description": "Run local diagnostics",
|
|
1522
1525
|
"doctor.installOnly": "only check npm global command and PATH setup",
|
|
1526
|
+
"doctor.noProfiles": "skip Hermes Profile diagnostics",
|
|
1523
1527
|
"doctor.installHeader": "Install/PATH diagnostics:",
|
|
1524
1528
|
"doctor.installNpmPrefix": "npm global prefix: {value}",
|
|
1525
1529
|
"doctor.installGlobalBin": "npm global bin directory: {value}",
|
|
@@ -1549,6 +1553,13 @@ var messages = {
|
|
|
1549
1553
|
"doctor.apiReady": "Hermes API Server: ready",
|
|
1550
1554
|
"doctor.apiStarted": "Hermes API Server: started and ready",
|
|
1551
1555
|
"doctor.apiUnavailable": "Hermes API Server: unavailable. {message}",
|
|
1556
|
+
"doctor.profilesHeader": "Hermes Profiles:",
|
|
1557
|
+
"doctor.profilesNone": "- no profiles found",
|
|
1558
|
+
"doctor.profileLine": "- {profile}: {endpoint}; {state}",
|
|
1559
|
+
"doctor.profileReady": "ready",
|
|
1560
|
+
"doctor.profileNotRunning": "not running ({message})",
|
|
1561
|
+
"doctor.profilePreparedState": "prepared config; {state}",
|
|
1562
|
+
"doctor.profilePrepareFailed": "prepare failed ({message})",
|
|
1552
1563
|
"doctor.apiUnavailable.summary": "Hermes API Server: unavailable",
|
|
1553
1564
|
"doctor.apiUnavailable.profile": "Profile: {profile}; port: {port}",
|
|
1554
1565
|
"doctor.apiUnavailable.diagnosisDivider": "----- API Server diagnosis -----",
|
|
@@ -1668,6 +1679,9 @@ var messages = {
|
|
|
1668
1679
|
"config.notice.autoFilled": "\u5DF2\u4E3A Hermes API Server \u81EA\u52A8\u8865\u5145 {fields}\uFF1B\u672A\u8986\u76D6\u5DF2\u6709 port/host/key\u3002",
|
|
1669
1680
|
"config.notice.repairDefault": "\u5DF2\u4E3A Hermes API Server \u4FDD\u6301\u9ED8\u8BA4\u7AEF\u53E3\u5E76\u8F6E\u6362 key\uFF0C\u7528\u4E8E\u4FEE\u590D\u65E7 Gateway \u6216 key \u4E0D\u4E00\u81F4\u5BFC\u81F4\u7684 401\u3002",
|
|
1670
1681
|
"config.notice.repairProfile": "\u5DF2\u4E3A Hermes API Server \u91CD\u65B0\u5206\u914D\u672C\u673A\u7AEF\u53E3\u5E76\u8F6E\u6362 key\uFF0C\u7528\u4E8E\u4FEE\u590D\u65E7 Gateway \u6216 key \u4E0D\u4E00\u81F4\u5BFC\u81F4\u7684 401\u3002",
|
|
1682
|
+
"config.yaml.invalid": "Hermes Profile \u914D\u7F6E\u6587\u4EF6\u4E0D\u662F\u6709\u6548\u7684 YAML\uFF0C\u6682\u65F6\u65E0\u6CD5\u5199\u5165\u914D\u7F6E\u3002\u8BF7\u5148\u4FEE\u590D {path} \u540E\u91CD\u8BD5\u3002{details}{more}",
|
|
1683
|
+
"config.yaml.details": " YAML \u9519\u8BEF\uFF1A{errors}",
|
|
1684
|
+
"config.yaml.more": " \u7B49 {count} \u5904\u9519\u8BEF\u3002",
|
|
1671
1685
|
"daemon.description": "\u4EE5\u524D\u53F0\u65B9\u5F0F\u8FD0\u884C Hermes Link",
|
|
1672
1686
|
"daemon.foreground": "Hermes Link \u524D\u53F0\u670D\u52A1\u6B63\u5728\u8FD0\u884C\u3002\u6309 Ctrl+C \u505C\u6B62\u3002",
|
|
1673
1687
|
"logs.description": "\u663E\u793A\u6216\u8DDF\u8E2A Hermes Link \u65E5\u5FD7",
|
|
@@ -1723,6 +1737,7 @@ var messages = {
|
|
|
1723
1737
|
"pair.autostartFailed": "\u914D\u5BF9\u5DF2\u6210\u529F\uFF0C\u4F46\u542F\u7528\u5F00\u673A\u81EA\u542F\u5931\u8D25\uFF1A{message}",
|
|
1724
1738
|
"doctor.description": "\u8FD0\u884C\u672C\u673A\u8BCA\u65AD",
|
|
1725
1739
|
"doctor.installOnly": "\u53EA\u68C0\u67E5 npm \u5168\u5C40\u547D\u4EE4\u548C PATH \u8BBE\u7F6E",
|
|
1740
|
+
"doctor.noProfiles": "\u8DF3\u8FC7 Hermes Profile \u8BCA\u65AD",
|
|
1726
1741
|
"doctor.installHeader": "\u5B89\u88C5 / PATH \u8BCA\u65AD\uFF1A",
|
|
1727
1742
|
"doctor.installNpmPrefix": "npm \u5168\u5C40 prefix\uFF1A{value}",
|
|
1728
1743
|
"doctor.installGlobalBin": "npm \u5168\u5C40 bin \u76EE\u5F55\uFF1A{value}",
|
|
@@ -1752,6 +1767,13 @@ var messages = {
|
|
|
1752
1767
|
"doctor.apiReady": "Hermes API Server\uFF1A\u5DF2\u5C31\u7EEA",
|
|
1753
1768
|
"doctor.apiStarted": "Hermes API Server\uFF1A\u5DF2\u81EA\u52A8\u542F\u52A8\u5E76\u5C31\u7EEA",
|
|
1754
1769
|
"doctor.apiUnavailable": "Hermes API Server\uFF1A\u4E0D\u53EF\u7528\u3002{message}",
|
|
1770
|
+
"doctor.profilesHeader": "Hermes Profiles\uFF1A",
|
|
1771
|
+
"doctor.profilesNone": "- \u6CA1\u6709\u627E\u5230 Profile",
|
|
1772
|
+
"doctor.profileLine": "- {profile}\uFF1A{endpoint}\uFF1B{state}",
|
|
1773
|
+
"doctor.profileReady": "\u5DF2\u5C31\u7EEA",
|
|
1774
|
+
"doctor.profileNotRunning": "\u5C1A\u672A\u8FD0\u884C\uFF08{message}\uFF09",
|
|
1775
|
+
"doctor.profilePreparedState": "\u5DF2\u81EA\u52A8\u51C6\u5907\u914D\u7F6E\uFF1B{state}",
|
|
1776
|
+
"doctor.profilePrepareFailed": "\u51C6\u5907\u5931\u8D25\uFF08{message}\uFF09",
|
|
1755
1777
|
"doctor.apiUnavailable.summary": "Hermes API Server\uFF1A\u4E0D\u53EF\u7528",
|
|
1756
1778
|
"doctor.apiUnavailable.profile": "Profile\uFF1A{profile}\uFF1B\u7AEF\u53E3\uFF1A{port}",
|
|
1757
1779
|
"doctor.apiUnavailable.diagnosisDivider": "----- API Server \u8BCA\u65AD -----",
|
|
@@ -1894,6 +1916,17 @@ var MODEL_CONFIG_RESTART_HINT = "\u6A21\u578B\u914D\u7F6E\u5DF2\u4FDD\u5B58\u300
|
|
|
1894
1916
|
var MODEL_DEFAULTS_APPLIED_HINT = "\u9ED8\u8BA4\u6A21\u578B\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002\u65B0\u7684 Run \u4F1A\u76F4\u63A5\u8BFB\u53D6\u6700\u65B0\u914D\u7F6E\uFF0C\u65E0\u9700\u91CD\u8F7D Hermes Gateway\u3002";
|
|
1895
1917
|
var PROFILE_PERMISSIONS_RESTART_HINT = "\u6743\u9650\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002\u540E\u7EED\u4EE5\u8BE5 Profile \u53D1\u8D77\u7684\u65B0 Run \u4F1A\u8BFB\u53D6\u6700\u65B0\u914D\u7F6E\uFF1B\u5982\u679C\u8BE5 Profile \u7684 Gateway \u5DF2\u7ECF\u5728\u8FD0\u884C\uFF0C\u9700\u8981\u91CD\u8F7D\u5BF9\u5E94 Gateway\u3002";
|
|
1896
1918
|
var PROFILE_TOOL_CONFIG_RESTART_HINT = "\u5DE5\u5177\u540E\u7AEF\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002\u540E\u7EED\u4EE5\u8BE5 Profile \u53D1\u8D77\u7684\u65B0 Run \u4F1A\u8BFB\u53D6\u6700\u65B0\u914D\u7F6E\uFF1B\u5982\u679C\u8BE5 Profile \u7684 Gateway \u5DF2\u7ECF\u5728\u8FD0\u884C\uFF0C\u9700\u8981\u91CD\u8F7D\u5BF9\u5E94 Gateway\u3002";
|
|
1919
|
+
var HermesConfigYamlError = class extends Error {
|
|
1920
|
+
constructor(configPath, errors, language) {
|
|
1921
|
+
super(buildHermesConfigYamlErrorMessage(configPath, errors, language));
|
|
1922
|
+
this.configPath = configPath;
|
|
1923
|
+
this.errors = errors;
|
|
1924
|
+
this.name = "HermesConfigYamlError";
|
|
1925
|
+
}
|
|
1926
|
+
configPath;
|
|
1927
|
+
errors;
|
|
1928
|
+
code = "hermes_config_yaml_invalid";
|
|
1929
|
+
};
|
|
1897
1930
|
var REASONING_EFFORTS = [
|
|
1898
1931
|
"none",
|
|
1899
1932
|
"minimal",
|
|
@@ -2805,12 +2838,12 @@ async function saveHermesProfilePermissions(profileName, input, configPath = res
|
|
|
2805
2838
|
restartHint: PROFILE_PERMISSIONS_RESTART_HINT
|
|
2806
2839
|
};
|
|
2807
2840
|
}
|
|
2808
|
-
async function addHermesCommandAllowlistEntry(profileName, entry, configPath = resolveHermesConfigPath(profileName)) {
|
|
2841
|
+
async function addHermesCommandAllowlistEntry(profileName, entry, configPath = resolveHermesConfigPath(profileName), language) {
|
|
2809
2842
|
const normalizedEntry = entry.trim();
|
|
2810
2843
|
if (!normalizedEntry) {
|
|
2811
2844
|
throw new Error("command_allowlist entry must be non-empty");
|
|
2812
2845
|
}
|
|
2813
|
-
const { document, config, existingRaw } = await readHermesConfigDocument(configPath);
|
|
2846
|
+
const { document, config, existingRaw } = await readHermesConfigDocument(configPath, language);
|
|
2814
2847
|
const current = readStringList(config.command_allowlist);
|
|
2815
2848
|
if (current.includes(normalizedEntry)) {
|
|
2816
2849
|
return {
|
|
@@ -3132,7 +3165,7 @@ async function repairHermesApiServerConfigUnlocked(profileName = "default", conf
|
|
|
3132
3165
|
notice: buildRepairNotice(language, profileName)
|
|
3133
3166
|
};
|
|
3134
3167
|
}
|
|
3135
|
-
async function readHermesConfigDocument(configPath) {
|
|
3168
|
+
async function readHermesConfigDocument(configPath, language) {
|
|
3136
3169
|
const existingRaw = await readFile2(configPath, "utf8").catch(
|
|
3137
3170
|
(error) => {
|
|
3138
3171
|
if (isNodeError3(error, "ENOENT")) {
|
|
@@ -3142,12 +3175,34 @@ async function readHermesConfigDocument(configPath) {
|
|
|
3142
3175
|
}
|
|
3143
3176
|
);
|
|
3144
3177
|
const document = existingRaw ? YAML.parseDocument(existingRaw) : new YAML.Document({});
|
|
3178
|
+
assertValidHermesConfigDocument(configPath, document, language);
|
|
3145
3179
|
return {
|
|
3146
3180
|
document,
|
|
3147
3181
|
config: toRecord(document.toJSON()),
|
|
3148
3182
|
existingRaw
|
|
3149
3183
|
};
|
|
3150
3184
|
}
|
|
3185
|
+
function assertValidHermesConfigDocument(configPath, document, language) {
|
|
3186
|
+
const errors = document.errors.map((error) => error.message.trim()).filter((message) => message.length > 0);
|
|
3187
|
+
if (errors.length > 0) {
|
|
3188
|
+
throw new HermesConfigYamlError(configPath, errors, language);
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
function buildHermesConfigYamlErrorMessage(configPath, errors, language) {
|
|
3192
|
+
const firstErrors = errors.slice(0, 3);
|
|
3193
|
+
const resolvedLanguage = language ?? "zh-CN";
|
|
3194
|
+
const details = firstErrors.length > 0 ? translate(resolvedLanguage, "config.yaml.details", {
|
|
3195
|
+
errors: firstErrors.join("; ")
|
|
3196
|
+
}) : "";
|
|
3197
|
+
const more = errors.length > firstErrors.length ? translate(resolvedLanguage, "config.yaml.more", {
|
|
3198
|
+
count: errors.length - firstErrors.length
|
|
3199
|
+
}) : "";
|
|
3200
|
+
return translate(resolvedLanguage, "config.yaml.invalid", {
|
|
3201
|
+
path: configPath,
|
|
3202
|
+
details,
|
|
3203
|
+
more
|
|
3204
|
+
});
|
|
3205
|
+
}
|
|
3151
3206
|
async function writeHermesConfigDocument(input) {
|
|
3152
3207
|
const backupPath = input.existingRaw ? `${input.configPath}.bak.${Date.now()}` : null;
|
|
3153
3208
|
if (backupPath) {
|
|
@@ -4894,12 +4949,24 @@ async function addConfiguredApiServerPort(ports, profileName, excludedProfileNam
|
|
|
4894
4949
|
throw error;
|
|
4895
4950
|
});
|
|
4896
4951
|
if (!raw.trim()) {
|
|
4952
|
+
const envPort2 = readApiServerPort(
|
|
4953
|
+
(await readHermesApiServerEnvOverrides(profileName)).port
|
|
4954
|
+
);
|
|
4955
|
+
if (envPort2 !== null) {
|
|
4956
|
+
ports.add(envPort2);
|
|
4957
|
+
}
|
|
4897
4958
|
return;
|
|
4898
4959
|
}
|
|
4899
4960
|
const config = toRecord(YAML.parse(raw));
|
|
4900
4961
|
const apiServer = toRecord(toRecord(config.platforms).api_server);
|
|
4901
|
-
const
|
|
4902
|
-
|
|
4962
|
+
const envPort = readApiServerPort(
|
|
4963
|
+
(await readHermesApiServerEnvOverrides(profileName)).port
|
|
4964
|
+
);
|
|
4965
|
+
const configPort = readApiServerPort(readApiServerConfig(apiServer).port);
|
|
4966
|
+
for (const port of [envPort, configPort]) {
|
|
4967
|
+
if (port === null) {
|
|
4968
|
+
continue;
|
|
4969
|
+
}
|
|
4903
4970
|
ports.add(port);
|
|
4904
4971
|
}
|
|
4905
4972
|
}
|
|
@@ -5418,7 +5485,7 @@ import os2 from "os";
|
|
|
5418
5485
|
import path5 from "path";
|
|
5419
5486
|
|
|
5420
5487
|
// src/constants.ts
|
|
5421
|
-
var LINK_VERSION = "0.6.
|
|
5488
|
+
var LINK_VERSION = "0.6.7";
|
|
5422
5489
|
var LINK_COMMAND = "hermeslink";
|
|
5423
5490
|
var LINK_DEFAULT_PORT = 52379;
|
|
5424
5491
|
var LINK_RUNTIME_DIR_NAME = ".hermeslink";
|
|
@@ -8273,6 +8340,37 @@ function hasRunningRuns(snapshot) {
|
|
|
8273
8340
|
function hasQueuedRuns(snapshot) {
|
|
8274
8341
|
return snapshot.runs.some((run) => run.status === "queued");
|
|
8275
8342
|
}
|
|
8343
|
+
function buildConversationEventStreamState(snapshot) {
|
|
8344
|
+
const pendingApprovalRunIds = /* @__PURE__ */ new Set();
|
|
8345
|
+
let hasPendingApproval = false;
|
|
8346
|
+
for (const message of snapshot.messages) {
|
|
8347
|
+
if (!message.approvals?.some((approval) => approval.status === "pending")) {
|
|
8348
|
+
continue;
|
|
8349
|
+
}
|
|
8350
|
+
hasPendingApproval = true;
|
|
8351
|
+
if (message.run_id) {
|
|
8352
|
+
pendingApprovalRunIds.add(message.run_id);
|
|
8353
|
+
}
|
|
8354
|
+
}
|
|
8355
|
+
const summaries = snapshot.runs.map(
|
|
8356
|
+
(run) => toEventStreamRunSummary(run, pendingApprovalRunIds.has(run.id))
|
|
8357
|
+
);
|
|
8358
|
+
const activeRuns = summaries.filter((run) => isRealtimeRunStatus(run.status));
|
|
8359
|
+
const unknownRuns = summaries.filter((run) => run.status === "unknown");
|
|
8360
|
+
const requiresUserAction = hasPendingApproval || summaries.some((run) => run.requires_user_action);
|
|
8361
|
+
const hasQueuedRun = activeRuns.some((run) => run.status === "queued");
|
|
8362
|
+
const hasRunningRun = activeRuns.some((run) => run.status === "running");
|
|
8363
|
+
const hasUnknownRun = unknownRuns.length > 0;
|
|
8364
|
+
const reason = requiresUserAction ? "requires_user_action" : hasQueuedRun ? "queued_run" : hasRunningRun ? "active_run" : hasUnknownRun ? "unknown" : "terminal";
|
|
8365
|
+
return {
|
|
8366
|
+
should_subscribe: !requiresUserAction && activeRuns.length > 0,
|
|
8367
|
+
reason,
|
|
8368
|
+
has_active_runs: activeRuns.length > 0 || hasUnknownRun,
|
|
8369
|
+
requires_user_action: requiresUserAction,
|
|
8370
|
+
active_runs: activeRuns,
|
|
8371
|
+
latest_runs: summaries.slice().sort((left, right) => right.updated_at.localeCompare(left.updated_at)).slice(0, 5)
|
|
8372
|
+
};
|
|
8373
|
+
}
|
|
8276
8374
|
function isRetryableUserMessage(message) {
|
|
8277
8375
|
return message.role === "user" && message.raw?.format !== "hermes-link-slash-command" && (messageText(message).length > 0 || message.parts.some((part) => Boolean(part.blob)));
|
|
8278
8376
|
}
|
|
@@ -8325,6 +8423,18 @@ function previewText(message) {
|
|
|
8325
8423
|
function messageText(message) {
|
|
8326
8424
|
return message.parts.filter((part) => part.type === "text" && part.text).map((part) => part.text).join("").trim();
|
|
8327
8425
|
}
|
|
8426
|
+
function toEventStreamRunSummary(run, requiresUserAction) {
|
|
8427
|
+
return {
|
|
8428
|
+
id: run.id,
|
|
8429
|
+
status: run.status,
|
|
8430
|
+
assistant_message_id: run.assistant_message_id,
|
|
8431
|
+
requires_user_action: requiresUserAction,
|
|
8432
|
+
updated_at: run.completed_at ?? run.started_at
|
|
8433
|
+
};
|
|
8434
|
+
}
|
|
8435
|
+
function isRealtimeRunStatus(status) {
|
|
8436
|
+
return status === "queued" || status === "running";
|
|
8437
|
+
}
|
|
8328
8438
|
|
|
8329
8439
|
// src/conversations/slash-commands.ts
|
|
8330
8440
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
@@ -11538,7 +11648,8 @@ var ConversationQueryCoordinator = class {
|
|
|
11538
11648
|
has_more_after: endIndex < total,
|
|
11539
11649
|
oldest_message_id: messages2[0]?.id ?? null,
|
|
11540
11650
|
newest_message_id: messages2.at(-1)?.id ?? null
|
|
11541
|
-
}
|
|
11651
|
+
},
|
|
11652
|
+
event_stream: buildConversationEventStreamState(snapshot)
|
|
11542
11653
|
};
|
|
11543
11654
|
}
|
|
11544
11655
|
async listEvents(conversationId, after = 0) {
|
|
@@ -18772,8 +18883,15 @@ var ConversationService = class {
|
|
|
18772
18883
|
);
|
|
18773
18884
|
const result = await addHermesCommandAllowlistEntry(
|
|
18774
18885
|
profileName,
|
|
18775
|
-
patternKey
|
|
18776
|
-
|
|
18886
|
+
patternKey,
|
|
18887
|
+
void 0,
|
|
18888
|
+
input.language
|
|
18889
|
+
).catch((error) => {
|
|
18890
|
+
if (error instanceof HermesConfigYamlError) {
|
|
18891
|
+
throw new LinkHttpError(409, error.code, error.message);
|
|
18892
|
+
}
|
|
18893
|
+
throw error;
|
|
18894
|
+
});
|
|
18777
18895
|
commandAllowlistUpdated = result.changed;
|
|
18778
18896
|
configPath = result.configPath;
|
|
18779
18897
|
requiresGatewayReload = result.requiresGatewayReload;
|
|
@@ -19485,6 +19603,36 @@ function readString16(body, key) {
|
|
|
19485
19603
|
const value = body[key];
|
|
19486
19604
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
19487
19605
|
}
|
|
19606
|
+
function readPreferredLanguage(ctx) {
|
|
19607
|
+
const candidates = [
|
|
19608
|
+
ctx.get("x-hermespilot-language"),
|
|
19609
|
+
ctx.get("x-app-language"),
|
|
19610
|
+
ctx.get("accept-language")
|
|
19611
|
+
];
|
|
19612
|
+
for (const candidate of candidates) {
|
|
19613
|
+
for (const part of candidate.split(",")) {
|
|
19614
|
+
const normalized = part.split(";")[0]?.trim();
|
|
19615
|
+
if (!normalized) {
|
|
19616
|
+
continue;
|
|
19617
|
+
}
|
|
19618
|
+
const language = readSupportedLanguage(normalized);
|
|
19619
|
+
if (language) {
|
|
19620
|
+
return language;
|
|
19621
|
+
}
|
|
19622
|
+
}
|
|
19623
|
+
}
|
|
19624
|
+
return resolveLanguage();
|
|
19625
|
+
}
|
|
19626
|
+
function readSupportedLanguage(value) {
|
|
19627
|
+
const normalized = value.trim().replace("_", "-").toLowerCase();
|
|
19628
|
+
if (normalized.startsWith("zh")) {
|
|
19629
|
+
return "zh-CN";
|
|
19630
|
+
}
|
|
19631
|
+
if (normalized.startsWith("en")) {
|
|
19632
|
+
return "en";
|
|
19633
|
+
}
|
|
19634
|
+
return null;
|
|
19635
|
+
}
|
|
19488
19636
|
function readOptionalProfileName(body) {
|
|
19489
19637
|
return readString16(body, "profile") ?? readString16(body, "profile_name") ?? readString16(body, "profileName") ?? void 0;
|
|
19490
19638
|
}
|
|
@@ -20165,7 +20313,8 @@ function registerConversationRoutes(router, options) {
|
|
|
20165
20313
|
...await conversations.resolveApproval({
|
|
20166
20314
|
conversationId: ctx.params.conversationId,
|
|
20167
20315
|
approvalId: ctx.params.approvalId,
|
|
20168
|
-
decision: scope
|
|
20316
|
+
decision: scope,
|
|
20317
|
+
language: readPreferredLanguage(ctx)
|
|
20169
20318
|
})
|
|
20170
20319
|
};
|
|
20171
20320
|
}
|
|
@@ -20179,7 +20328,8 @@ function registerConversationRoutes(router, options) {
|
|
|
20179
20328
|
...await conversations.resolveApproval({
|
|
20180
20329
|
conversationId: ctx.params.conversationId,
|
|
20181
20330
|
approvalId: ctx.params.approvalId,
|
|
20182
|
-
decision: "deny"
|
|
20331
|
+
decision: "deny",
|
|
20332
|
+
language: readPreferredLanguage(ctx)
|
|
20183
20333
|
})
|
|
20184
20334
|
};
|
|
20185
20335
|
}
|
|
@@ -20404,7 +20554,9 @@ var PROFILE_DELETE_VERIFY_INTERVAL_MS = 150;
|
|
|
20404
20554
|
var execFileAsync4 = promisify4(execFile4);
|
|
20405
20555
|
async function listHermesProfiles(paths = resolveRuntimePaths()) {
|
|
20406
20556
|
const profiles = /* @__PURE__ */ new Map();
|
|
20407
|
-
|
|
20557
|
+
if (await hasDefaultProfileConfigSource()) {
|
|
20558
|
+
profiles.set(DEFAULT_PROFILE, await profileInfo(DEFAULT_PROFILE, paths));
|
|
20559
|
+
}
|
|
20408
20560
|
const profilesDir = resolveHermesProfilesDir();
|
|
20409
20561
|
const entries = await readdir9(profilesDir, { withFileTypes: true }).catch(
|
|
20410
20562
|
(error) => {
|
|
@@ -20429,6 +20581,36 @@ async function listHermesProfiles(paths = resolveRuntimePaths()) {
|
|
|
20429
20581
|
return left.name.localeCompare(right.name);
|
|
20430
20582
|
});
|
|
20431
20583
|
}
|
|
20584
|
+
async function prepareHermesProfilesForUse(paths = resolveRuntimePaths()) {
|
|
20585
|
+
const profiles = await listHermesProfiles(paths);
|
|
20586
|
+
const prepared = [];
|
|
20587
|
+
for (const profile of profiles) {
|
|
20588
|
+
try {
|
|
20589
|
+
const result = await ensureHermesApiServerKey(
|
|
20590
|
+
profile.name,
|
|
20591
|
+
profile.configPath
|
|
20592
|
+
);
|
|
20593
|
+
prepared.push({
|
|
20594
|
+
profile,
|
|
20595
|
+
apiServer: result.apiServer,
|
|
20596
|
+
changed: result.changed,
|
|
20597
|
+
backupPath: result.backupPath,
|
|
20598
|
+
notice: result.notice,
|
|
20599
|
+
error: null
|
|
20600
|
+
});
|
|
20601
|
+
} catch (error) {
|
|
20602
|
+
prepared.push({
|
|
20603
|
+
profile,
|
|
20604
|
+
apiServer: null,
|
|
20605
|
+
changed: false,
|
|
20606
|
+
backupPath: null,
|
|
20607
|
+
notice: null,
|
|
20608
|
+
error: errorMessage(error)
|
|
20609
|
+
});
|
|
20610
|
+
}
|
|
20611
|
+
}
|
|
20612
|
+
return prepared;
|
|
20613
|
+
}
|
|
20432
20614
|
async function getHermesProfileStatus(name, paths = resolveRuntimePaths()) {
|
|
20433
20615
|
assertProfileName(name);
|
|
20434
20616
|
const profile = await profileInfo(name, paths);
|
|
@@ -20552,6 +20734,19 @@ async function pathExists(targetPath) {
|
|
|
20552
20734
|
throw error;
|
|
20553
20735
|
});
|
|
20554
20736
|
}
|
|
20737
|
+
async function hasDefaultProfileConfigSource() {
|
|
20738
|
+
const profilePath = resolveHermesProfileDir(DEFAULT_PROFILE);
|
|
20739
|
+
const profileStat = await stat13(profilePath).catch((error) => {
|
|
20740
|
+
if (isNodeError15(error, "ENOENT")) {
|
|
20741
|
+
return null;
|
|
20742
|
+
}
|
|
20743
|
+
throw error;
|
|
20744
|
+
});
|
|
20745
|
+
if (!profileStat?.isDirectory()) {
|
|
20746
|
+
return false;
|
|
20747
|
+
}
|
|
20748
|
+
return await pathExists(resolveHermesConfigPath(DEFAULT_PROFILE)) || await pathExists(path20.join(profilePath, ".env"));
|
|
20749
|
+
}
|
|
20555
20750
|
async function deleteHermesProfileWithCli(name) {
|
|
20556
20751
|
try {
|
|
20557
20752
|
await execFileAsync4(resolveHermesBin(), ["profile", "delete", name, "--yes"], {
|
|
@@ -20703,6 +20898,9 @@ function readExecErrorOutput2(error) {
|
|
|
20703
20898
|
function isNodeError15(error, code) {
|
|
20704
20899
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
20705
20900
|
}
|
|
20901
|
+
function errorMessage(error) {
|
|
20902
|
+
return error instanceof Error ? error.message : String(error);
|
|
20903
|
+
}
|
|
20706
20904
|
function escapeRegExp2(value) {
|
|
20707
20905
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20708
20906
|
}
|
|
@@ -21429,7 +21627,11 @@ function registerProfileCatalogRoutes(router, options) {
|
|
|
21429
21627
|
});
|
|
21430
21628
|
}
|
|
21431
21629
|
async function readProfileCatalogItem(profile) {
|
|
21432
|
-
const [capabilities, permissions, modelConfigs] = await Promise.all([
|
|
21630
|
+
const [apiServer, capabilities, permissions, modelConfigs] = await Promise.all([
|
|
21631
|
+
readCatalogField(
|
|
21632
|
+
"apiServer",
|
|
21633
|
+
() => readHermesApiServerConfig(profile.name, profile.configPath)
|
|
21634
|
+
),
|
|
21433
21635
|
readCatalogField(
|
|
21434
21636
|
"capabilities",
|
|
21435
21637
|
() => readHermesProfileCapabilities(profile.name)
|
|
@@ -21442,10 +21644,17 @@ async function readProfileCatalogItem(profile) {
|
|
|
21442
21644
|
]);
|
|
21443
21645
|
return {
|
|
21444
21646
|
profile,
|
|
21647
|
+
apiServer: apiServer.value ? {
|
|
21648
|
+
host: apiServer.value.host ?? null,
|
|
21649
|
+
port: apiServer.value.port ?? null,
|
|
21650
|
+
configured: Boolean(apiServer.value.key),
|
|
21651
|
+
changed: false
|
|
21652
|
+
} : null,
|
|
21445
21653
|
capabilities: capabilities.value,
|
|
21446
21654
|
permissions: permissions.value,
|
|
21447
21655
|
modelConfigs: modelConfigs.value,
|
|
21448
21656
|
errors: [
|
|
21657
|
+
...apiServer.errors,
|
|
21449
21658
|
...capabilities.errors,
|
|
21450
21659
|
...permissions.errors,
|
|
21451
21660
|
...modelConfigs.errors
|
|
@@ -21458,11 +21667,11 @@ async function readCatalogField(field, load) {
|
|
|
21458
21667
|
} catch (error) {
|
|
21459
21668
|
return {
|
|
21460
21669
|
value: null,
|
|
21461
|
-
errors: [{ field, message:
|
|
21670
|
+
errors: [{ field, message: errorMessage2(error) }]
|
|
21462
21671
|
};
|
|
21463
21672
|
}
|
|
21464
21673
|
}
|
|
21465
|
-
function
|
|
21674
|
+
function errorMessage2(error) {
|
|
21466
21675
|
return error instanceof Error ? error.message : String(error);
|
|
21467
21676
|
}
|
|
21468
21677
|
|
|
@@ -21575,7 +21784,7 @@ async function ensureHermesLinkSkillInstalledForProfiles(options = {}) {
|
|
|
21575
21784
|
const skillChanged = await writeHermesLinkSkill(skillPath);
|
|
21576
21785
|
const profiles = await listHermesProfiles(paths);
|
|
21577
21786
|
const results = [];
|
|
21578
|
-
for (const profile of profiles) {
|
|
21787
|
+
for (const profile of withDefaultProfilePlaceholder(profiles)) {
|
|
21579
21788
|
try {
|
|
21580
21789
|
results.push(await ensureProfileUsesExternalSkillDir(profile, externalDir));
|
|
21581
21790
|
} catch (error) {
|
|
@@ -21629,6 +21838,25 @@ async function ensureHermesLinkSkillInstalledBestEffort(options = {}) {
|
|
|
21629
21838
|
});
|
|
21630
21839
|
}
|
|
21631
21840
|
}
|
|
21841
|
+
function withDefaultProfilePlaceholder(profiles) {
|
|
21842
|
+
if (profiles.some((profile) => profile.name === "default")) {
|
|
21843
|
+
return profiles;
|
|
21844
|
+
}
|
|
21845
|
+
return [
|
|
21846
|
+
{
|
|
21847
|
+
uid: "default",
|
|
21848
|
+
name: "default",
|
|
21849
|
+
active: false,
|
|
21850
|
+
path: resolveHermesProfileDir("default"),
|
|
21851
|
+
configPath: resolveHermesConfigPath("default"),
|
|
21852
|
+
displayName: null,
|
|
21853
|
+
description: null,
|
|
21854
|
+
avatarType: "default",
|
|
21855
|
+
avatarUrl: null
|
|
21856
|
+
},
|
|
21857
|
+
...profiles
|
|
21858
|
+
];
|
|
21859
|
+
}
|
|
21632
21860
|
function resolveHermesLinkSkillExternalDir(paths = resolveRuntimePaths()) {
|
|
21633
21861
|
return path21.join(paths.homeDir, HERMES_LINK_SKILL_ROOT_DIR);
|
|
21634
21862
|
}
|
|
@@ -25109,6 +25337,16 @@ function registerProfileRoutes(router, options) {
|
|
|
25109
25337
|
profiles: await listHermesProfiles(paths)
|
|
25110
25338
|
};
|
|
25111
25339
|
});
|
|
25340
|
+
router.post("/api/v1/profiles/prepare", async (ctx) => {
|
|
25341
|
+
await authenticateRequest(ctx, paths);
|
|
25342
|
+
ctx.set("cache-control", "no-store");
|
|
25343
|
+
ctx.body = {
|
|
25344
|
+
ok: true,
|
|
25345
|
+
profiles: (await prepareHermesProfilesForUse(paths)).map(
|
|
25346
|
+
formatProfilePreparation
|
|
25347
|
+
)
|
|
25348
|
+
};
|
|
25349
|
+
});
|
|
25112
25350
|
router.get("/api/v1/profile-creation/status", async (ctx) => {
|
|
25113
25351
|
await authenticateRequest(ctx, paths);
|
|
25114
25352
|
ctx.set("cache-control", "no-store");
|
|
@@ -25208,6 +25446,20 @@ function registerProfileRoutes(router, options) {
|
|
|
25208
25446
|
ctx.status = 204;
|
|
25209
25447
|
});
|
|
25210
25448
|
}
|
|
25449
|
+
function formatProfilePreparation(item) {
|
|
25450
|
+
return {
|
|
25451
|
+
profile: item.profile,
|
|
25452
|
+
apiServer: item.apiServer ? {
|
|
25453
|
+
host: item.apiServer.host ?? null,
|
|
25454
|
+
port: item.apiServer.port ?? null,
|
|
25455
|
+
configured: Boolean(item.apiServer.key),
|
|
25456
|
+
changed: item.changed
|
|
25457
|
+
} : null,
|
|
25458
|
+
changed: item.changed,
|
|
25459
|
+
notice: item.notice,
|
|
25460
|
+
error: item.error
|
|
25461
|
+
};
|
|
25462
|
+
}
|
|
25211
25463
|
function readProfileName(body) {
|
|
25212
25464
|
if (typeof body.name !== "string") {
|
|
25213
25465
|
throw new Error("invalid profile name");
|
|
@@ -27369,6 +27621,15 @@ async function startLinkService(options = {}) {
|
|
|
27369
27621
|
});
|
|
27370
27622
|
return streamBatchPolicy;
|
|
27371
27623
|
};
|
|
27624
|
+
let profilePreparation = Promise.resolve();
|
|
27625
|
+
const triggerProfilePreparation = (source) => {
|
|
27626
|
+
profilePreparation = profilePreparation.catch(() => void 0).then(() => prepareHermesProfilesForUse(paths)).then((profiles) => logProfilePreparationResult(logger, source, profiles)).catch((error) => {
|
|
27627
|
+
void logger.warn("profile_preparation_failed", {
|
|
27628
|
+
source,
|
|
27629
|
+
error: error instanceof Error ? error.message : String(error)
|
|
27630
|
+
});
|
|
27631
|
+
});
|
|
27632
|
+
};
|
|
27372
27633
|
let hermesSessionSync = Promise.resolve();
|
|
27373
27634
|
const triggerHermesSessionSync = () => {
|
|
27374
27635
|
hermesSessionSync = Promise.resolve().then(() => conversations.syncHermesSessions()).then(() => void 0).catch((error) => {
|
|
@@ -27388,6 +27649,7 @@ async function startLinkService(options = {}) {
|
|
|
27388
27649
|
logger,
|
|
27389
27650
|
source: "pairing_claimed"
|
|
27390
27651
|
});
|
|
27652
|
+
triggerProfilePreparation("pairing_claimed");
|
|
27391
27653
|
triggerHermesSessionSync();
|
|
27392
27654
|
void loadRelayStreamBatchPolicy("pairing_claimed");
|
|
27393
27655
|
await options.onPairingClaimed?.();
|
|
@@ -27448,6 +27710,9 @@ async function startLinkService(options = {}) {
|
|
|
27448
27710
|
port: config.port,
|
|
27449
27711
|
link_id: identity?.link_id ?? null
|
|
27450
27712
|
});
|
|
27713
|
+
if (identity?.link_id) {
|
|
27714
|
+
triggerProfilePreparation("service_startup");
|
|
27715
|
+
}
|
|
27451
27716
|
triggerHermesSessionSync();
|
|
27452
27717
|
const scheduler = startCronDeliveryScheduler({
|
|
27453
27718
|
paths,
|
|
@@ -27532,6 +27797,7 @@ async function startLinkService(options = {}) {
|
|
|
27532
27797
|
scheduler.close(),
|
|
27533
27798
|
hermesSessionSyncScheduler.close(),
|
|
27534
27799
|
lanIpMonitor?.close(),
|
|
27800
|
+
profilePreparation.catch(() => void 0),
|
|
27535
27801
|
hermesSessionSync.catch(() => void 0)
|
|
27536
27802
|
]);
|
|
27537
27803
|
await logger.info("service_stopped");
|
|
@@ -27557,6 +27823,32 @@ function waitForRelayReadyTimeout(timeoutMs) {
|
|
|
27557
27823
|
timer.unref?.();
|
|
27558
27824
|
});
|
|
27559
27825
|
}
|
|
27826
|
+
async function logProfilePreparationResult(logger, source, profiles) {
|
|
27827
|
+
const changed = profiles.filter((profile) => profile.changed);
|
|
27828
|
+
const failed = profiles.filter((profile) => profile.error);
|
|
27829
|
+
const summary = {
|
|
27830
|
+
source,
|
|
27831
|
+
total: profiles.length,
|
|
27832
|
+
prepared: profiles.length - failed.length,
|
|
27833
|
+
changed: changed.length,
|
|
27834
|
+
failed: failed.length,
|
|
27835
|
+
changed_profiles: changed.map((profile) => profile.profile.name)
|
|
27836
|
+
};
|
|
27837
|
+
if (changed.length > 0 || failed.length > 0) {
|
|
27838
|
+
await logger.warn("profiles_prepared", summary);
|
|
27839
|
+
} else {
|
|
27840
|
+
await logger.info("profiles_prepared", summary);
|
|
27841
|
+
}
|
|
27842
|
+
if (failed.length > 0) {
|
|
27843
|
+
await logger.warn("profile_preparation_partial_failure", {
|
|
27844
|
+
source,
|
|
27845
|
+
failed_profiles: failed.map((profile) => ({
|
|
27846
|
+
profile: profile.profile.name,
|
|
27847
|
+
error: profile.error
|
|
27848
|
+
}))
|
|
27849
|
+
});
|
|
27850
|
+
}
|
|
27851
|
+
}
|
|
27560
27852
|
function pidFilePath(paths = resolveRuntimePaths()) {
|
|
27561
27853
|
return `${paths.runDir}/hermeslink.pid`;
|
|
27562
27854
|
}
|
|
@@ -30541,6 +30833,7 @@ export {
|
|
|
30541
30833
|
resolveLanguage,
|
|
30542
30834
|
translate,
|
|
30543
30835
|
localizeErrorMessage,
|
|
30836
|
+
DEFAULT_HERMES_API_SERVER_PORT,
|
|
30544
30837
|
resolveHermesProfileDir,
|
|
30545
30838
|
resolveHermesConfigPath,
|
|
30546
30839
|
ensureHermesApiServerConfig,
|
|
@@ -30555,6 +30848,7 @@ export {
|
|
|
30555
30848
|
HermesApiServerUnavailableError,
|
|
30556
30849
|
ensureHermesApiServerAvailable,
|
|
30557
30850
|
readHermesVersion,
|
|
30851
|
+
readHermesApiServerHealth,
|
|
30558
30852
|
defaultLinkConfig,
|
|
30559
30853
|
loadConfig,
|
|
30560
30854
|
saveConfig,
|
|
@@ -30565,6 +30859,7 @@ export {
|
|
|
30565
30859
|
getIdentityStatus,
|
|
30566
30860
|
ConversationService,
|
|
30567
30861
|
hasActiveDevices,
|
|
30862
|
+
prepareHermesProfilesForUse,
|
|
30568
30863
|
ensureHermesLinkSkillInstalledBestEffort,
|
|
30569
30864
|
detectRuntimeEnvironment,
|
|
30570
30865
|
preparePairing,
|
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConversationService,
|
|
4
|
+
DEFAULT_HERMES_API_SERVER_PORT,
|
|
4
5
|
HermesApiServerUnavailableError,
|
|
5
6
|
LINK_COMMAND,
|
|
6
7
|
LINK_VERSION,
|
|
@@ -29,8 +30,10 @@ import {
|
|
|
29
30
|
localizeErrorMessage,
|
|
30
31
|
normalizeLanHost,
|
|
31
32
|
parseLogLevel,
|
|
33
|
+
prepareHermesProfilesForUse,
|
|
32
34
|
preparePairing,
|
|
33
35
|
probeLocalLinkService,
|
|
36
|
+
readHermesApiServerHealth,
|
|
34
37
|
readHermesVersion,
|
|
35
38
|
readPairingClaim,
|
|
36
39
|
readRecentGatewayLogEntries,
|
|
@@ -48,7 +51,7 @@ import {
|
|
|
48
51
|
startLinkService,
|
|
49
52
|
stopDaemonProcess,
|
|
50
53
|
translate
|
|
51
|
-
} from "../chunk-
|
|
54
|
+
} from "../chunk-FWX7ZUP4.js";
|
|
52
55
|
|
|
53
56
|
// src/cli/index.ts
|
|
54
57
|
import { Command } from "commander";
|
|
@@ -1158,7 +1161,7 @@ logsCommand.command("flush").description(helpText("logs.flush.description")).opt
|
|
|
1158
1161
|
})
|
|
1159
1162
|
);
|
|
1160
1163
|
});
|
|
1161
|
-
program.command("doctor").option("--install", helpText("doctor.installOnly")).description(helpText("doctor.description")).action(async (options) => {
|
|
1164
|
+
program.command("doctor").option("--install", helpText("doctor.installOnly")).option("--no-profiles", helpText("doctor.noProfiles")).description(helpText("doctor.description")).action(async (options) => {
|
|
1162
1165
|
const installInfo = readInstallPathInfo();
|
|
1163
1166
|
const installLanguage = await loadCliLanguage().catch(() => detectSystemLanguage());
|
|
1164
1167
|
const installT = translate.bind(null, installLanguage);
|
|
@@ -1200,6 +1203,9 @@ program.command("doctor").option("--install", helpText("doctor.installOnly")).de
|
|
|
1200
1203
|
} catch (error) {
|
|
1201
1204
|
console.log(formatHermesApiServerUnavailable(error, language));
|
|
1202
1205
|
}
|
|
1206
|
+
if (options.profiles !== false) {
|
|
1207
|
+
await printProfileDiagnostics(t);
|
|
1208
|
+
}
|
|
1203
1209
|
});
|
|
1204
1210
|
if (isCliEntrypoint()) {
|
|
1205
1211
|
program.parseAsync(process.argv).catch(async (error) => {
|
|
@@ -1212,6 +1218,45 @@ async function loadCliLanguage() {
|
|
|
1212
1218
|
const config = await loadConfig();
|
|
1213
1219
|
return resolveLanguage(config.language);
|
|
1214
1220
|
}
|
|
1221
|
+
async function printProfileDiagnostics(t) {
|
|
1222
|
+
console.log(t("doctor.profilesHeader"));
|
|
1223
|
+
const profiles = await prepareHermesProfilesForUse();
|
|
1224
|
+
if (profiles.length === 0) {
|
|
1225
|
+
console.log(t("doctor.profilesNone"));
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
for (const profile of profiles) {
|
|
1229
|
+
console.log(await formatProfileDiagnosticLine(profile, t));
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
async function formatProfileDiagnosticLine(profile, t) {
|
|
1233
|
+
if (profile.error || !profile.apiServer) {
|
|
1234
|
+
return t("doctor.profileLine", {
|
|
1235
|
+
profile: profile.profile.name,
|
|
1236
|
+
endpoint: t("status.unknown"),
|
|
1237
|
+
state: t("doctor.profilePrepareFailed", {
|
|
1238
|
+
message: profile.error ?? t("status.unknown")
|
|
1239
|
+
})
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
const host = profile.apiServer.host ?? "127.0.0.1";
|
|
1243
|
+
const port = profile.apiServer.port ?? DEFAULT_HERMES_API_SERVER_PORT;
|
|
1244
|
+
const health = await readHermesApiServerHealth(profile.apiServer).catch(
|
|
1245
|
+
(error) => ({
|
|
1246
|
+
healthy: false,
|
|
1247
|
+
issue: error instanceof Error ? error.message : String(error)
|
|
1248
|
+
})
|
|
1249
|
+
);
|
|
1250
|
+
const baseState = health.healthy ? t("doctor.profileReady") : t("doctor.profileNotRunning", {
|
|
1251
|
+
message: health.issue ?? t("status.unknown")
|
|
1252
|
+
});
|
|
1253
|
+
const state = profile.changed ? t("doctor.profilePreparedState", { state: baseState }) : baseState;
|
|
1254
|
+
return t("doctor.profileLine", {
|
|
1255
|
+
profile: profile.profile.name,
|
|
1256
|
+
endpoint: `${host}:${port}`,
|
|
1257
|
+
state
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1215
1260
|
function buildRelayStatusPayload(input) {
|
|
1216
1261
|
if (!input.paired) {
|
|
1217
1262
|
return emptyRelayStatus(input.relayConfigured, "not_paired");
|
package/dist/http/app.d.ts
CHANGED
|
@@ -62,6 +62,22 @@ interface ConversationMessagesPageInfo {
|
|
|
62
62
|
oldest_message_id: string | null;
|
|
63
63
|
newest_message_id: string | null;
|
|
64
64
|
}
|
|
65
|
+
type ConversationEventStreamReason = 'terminal' | 'active_run' | 'queued_run' | 'recovering' | 'requires_user_action' | 'unknown';
|
|
66
|
+
interface ConversationEventStreamRunSummary {
|
|
67
|
+
id: string;
|
|
68
|
+
status: LinkRun['status'];
|
|
69
|
+
assistant_message_id: string;
|
|
70
|
+
requires_user_action: boolean;
|
|
71
|
+
updated_at: string;
|
|
72
|
+
}
|
|
73
|
+
interface ConversationEventStreamState {
|
|
74
|
+
should_subscribe: boolean;
|
|
75
|
+
reason: ConversationEventStreamReason;
|
|
76
|
+
has_active_runs: boolean;
|
|
77
|
+
requires_user_action: boolean;
|
|
78
|
+
active_runs: ConversationEventStreamRunSummary[];
|
|
79
|
+
latest_runs: ConversationEventStreamRunSummary[];
|
|
80
|
+
}
|
|
65
81
|
interface LinkMessagePart {
|
|
66
82
|
type: 'text' | 'image' | 'file' | 'audio' | 'video' | 'unsupported';
|
|
67
83
|
text?: string;
|
|
@@ -365,6 +381,8 @@ declare class FileLogger {
|
|
|
365
381
|
private rotateIfNeeded;
|
|
366
382
|
}
|
|
367
383
|
|
|
384
|
+
type SupportedLanguage = 'zh-CN' | 'en';
|
|
385
|
+
|
|
368
386
|
interface HermesSessionSyncResult {
|
|
369
387
|
scanned_profiles: number;
|
|
370
388
|
scanned_sessions: number;
|
|
@@ -455,6 +473,7 @@ declare class ConversationService {
|
|
|
455
473
|
last_event_seq: number;
|
|
456
474
|
runtime: ConversationRuntimeMetadata;
|
|
457
475
|
page: ConversationMessagesPageInfo;
|
|
476
|
+
event_stream: ConversationEventStreamState;
|
|
458
477
|
}>;
|
|
459
478
|
setConversationModel(conversationId: string, modelId: string): Promise<{
|
|
460
479
|
conversation_id: string;
|
|
@@ -493,6 +512,7 @@ declare class ConversationService {
|
|
|
493
512
|
conversationId: string;
|
|
494
513
|
approvalId: string;
|
|
495
514
|
decision: LinkApprovalDecision;
|
|
515
|
+
language?: SupportedLanguage;
|
|
496
516
|
}): Promise<{
|
|
497
517
|
conversation_id: string;
|
|
498
518
|
message_id: string;
|
package/dist/http/app.js
CHANGED