@saleso.innovations/bridge 0.1.41 → 0.1.43
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/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +5 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -0
- package/dist/cronList.d.ts +2 -0
- package/dist/cronList.d.ts.map +1 -1
- package/dist/cronList.js +11 -8
- package/dist/cronWatcher.d.ts +1 -1
- package/dist/cronWatcher.d.ts.map +1 -1
- package/dist/cronWatcher.js +70 -29
- package/dist/ensureHermesApi.d.ts +1 -1
- package/dist/ensureHermesApi.d.ts.map +1 -1
- package/dist/ensureHermesApi.js +14 -10
- package/dist/gatewayControl.d.ts +3 -3
- package/dist/gatewayControl.d.ts.map +1 -1
- package/dist/gatewayControl.js +58 -24
- package/dist/hermesCommands.d.ts +1 -1
- package/dist/hermesCommands.d.ts.map +1 -1
- package/dist/hermesCommands.js +48 -27
- package/dist/hermesFileCommands.d.ts +5 -5
- package/dist/hermesFileCommands.d.ts.map +1 -1
- package/dist/hermesFileCommands.js +10 -10
- package/dist/hermesFiles.d.ts +7 -6
- package/dist/hermesFiles.d.ts.map +1 -1
- package/dist/hermesFiles.js +11 -14
- package/dist/hermesForwarder.d.ts +2 -0
- package/dist/hermesForwarder.d.ts.map +1 -1
- package/dist/hermesForwarder.js +49 -24
- package/dist/hermesSessionDb.d.ts +10 -6
- package/dist/hermesSessionDb.d.ts.map +1 -1
- package/dist/hermesSessionDb.js +48 -24
- package/dist/hermesStructuredContent.d.ts +8 -0
- package/dist/hermesStructuredContent.d.ts.map +1 -0
- package/dist/hermesStructuredContent.js +197 -0
- package/dist/hermesStructuredContent.test.d.ts +2 -0
- package/dist/hermesStructuredContent.test.d.ts.map +1 -0
- package/dist/hermesStructuredContent.test.js +15 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/mcpList.d.ts +3 -2
- package/dist/mcpList.d.ts.map +1 -1
- package/dist/mcpList.js +5 -5
- package/dist/profiles.d.ts +66 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +409 -0
- package/dist/renameHermesSession.d.ts +1 -1
- package/dist/renameHermesSession.d.ts.map +1 -1
- package/dist/renameHermesSession.js +2 -2
- package/dist/skillLearnedDetector.d.ts +1 -1
- package/dist/skillLearnedDetector.d.ts.map +1 -1
- package/dist/skillLearnedDetector.js +2 -3
- package/dist/skillsList.d.ts +5 -2
- package/dist/skillsList.d.ts.map +1 -1
- package/dist/skillsList.js +14 -14
- package/dist/toolsList.d.ts +2 -2
- package/dist/toolsList.d.ts.map +1 -1
- package/dist/toolsList.js +4 -4
- package/package.json +2 -2
package/dist/hermesSessionDb.js
CHANGED
|
@@ -2,12 +2,16 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import Database from "better-sqlite3";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { unwrapHermesStructuredContent } from "./hermesStructuredContent.js";
|
|
6
|
+
/** Default state-db home (the default profile). Kept local to avoid a cycle with profiles.ts. */
|
|
7
|
+
function resolveStateHome(home) {
|
|
8
|
+
return home?.trim() || process.env.HERMES_HOME?.trim() || join(homedir(), ".hermes");
|
|
8
9
|
}
|
|
9
|
-
function
|
|
10
|
-
|
|
10
|
+
function hermesStateDbPath(home) {
|
|
11
|
+
return join(resolveStateHome(home), "state.db");
|
|
12
|
+
}
|
|
13
|
+
function openReadOnlyDb(home) {
|
|
14
|
+
const dbPath = hermesStateDbPath(home);
|
|
11
15
|
return new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
12
16
|
}
|
|
13
17
|
function decodeMessageContent(raw) {
|
|
@@ -24,6 +28,9 @@ function decodeMessageContent(raw) {
|
|
|
24
28
|
.map((part) => part.text)
|
|
25
29
|
.join("\n");
|
|
26
30
|
}
|
|
31
|
+
if (parsed && typeof parsed === "object") {
|
|
32
|
+
return unwrapHermesStructuredContent(raw);
|
|
33
|
+
}
|
|
27
34
|
}
|
|
28
35
|
catch {
|
|
29
36
|
// Plain text content.
|
|
@@ -109,11 +116,11 @@ function sessionTitleFromFirstUserMessage(db, sessionId) {
|
|
|
109
116
|
function sessionTitleForLookupId(db, sessionId) {
|
|
110
117
|
return sessionTitleFromChain(db, sessionId) ?? sessionTitleFromFirstUserMessage(db, sessionId);
|
|
111
118
|
}
|
|
112
|
-
export function resolveSessionTitle(sessionId) {
|
|
113
|
-
if (!sessionId.trim() || !hermesStateDbExists()) {
|
|
119
|
+
export function resolveSessionTitle(sessionId, home) {
|
|
120
|
+
if (!sessionId.trim() || !hermesStateDbExists(home)) {
|
|
114
121
|
return null;
|
|
115
122
|
}
|
|
116
|
-
const db = openReadOnlyDb();
|
|
123
|
+
const db = openReadOnlyDb(home);
|
|
117
124
|
try {
|
|
118
125
|
return sessionTitleForLookupId(db, sessionId);
|
|
119
126
|
}
|
|
@@ -124,16 +131,16 @@ export function resolveSessionTitle(sessionId) {
|
|
|
124
131
|
db.close();
|
|
125
132
|
}
|
|
126
133
|
}
|
|
127
|
-
export function resolveSessionTitles(sessionIds) {
|
|
134
|
+
export function resolveSessionTitles(sessionIds, home) {
|
|
128
135
|
const uniqueIds = [...new Set(sessionIds.map((id) => id.trim()).filter(Boolean))];
|
|
129
136
|
const titles = {};
|
|
130
137
|
for (const sessionId of uniqueIds) {
|
|
131
138
|
titles[sessionId] = null;
|
|
132
139
|
}
|
|
133
|
-
if (uniqueIds.length === 0 || !hermesStateDbExists()) {
|
|
140
|
+
if (uniqueIds.length === 0 || !hermesStateDbExists(home)) {
|
|
134
141
|
return titles;
|
|
135
142
|
}
|
|
136
|
-
const db = openReadOnlyDb();
|
|
143
|
+
const db = openReadOnlyDb(home);
|
|
137
144
|
try {
|
|
138
145
|
for (const sessionId of uniqueIds) {
|
|
139
146
|
titles[sessionId] = sessionTitleForLookupId(db, sessionId);
|
|
@@ -148,7 +155,7 @@ export function resolveSessionTitles(sessionIds) {
|
|
|
148
155
|
return titles;
|
|
149
156
|
}
|
|
150
157
|
export function listSessionMessages(sessionId, options = {}) {
|
|
151
|
-
const db = openReadOnlyDb();
|
|
158
|
+
const db = openReadOnlyDb(options.home);
|
|
152
159
|
try {
|
|
153
160
|
const resolved = resolveResumeSessionId(db, sessionId);
|
|
154
161
|
const chain = sessionAncestorChain(db, resolved);
|
|
@@ -181,8 +188,8 @@ export function listSessionMessages(sessionId, options = {}) {
|
|
|
181
188
|
db.close();
|
|
182
189
|
}
|
|
183
190
|
}
|
|
184
|
-
export function getLatestTurnMessageIds(sessionId) {
|
|
185
|
-
const db = openReadOnlyDb();
|
|
191
|
+
export function getLatestTurnMessageIds(sessionId, home) {
|
|
192
|
+
const db = openReadOnlyDb(home);
|
|
186
193
|
try {
|
|
187
194
|
const resolved = resolveResumeSessionId(db, sessionId);
|
|
188
195
|
const chain = sessionAncestorChain(db, resolved);
|
|
@@ -245,12 +252,12 @@ function firstUserMessageContent(db, sessionId) {
|
|
|
245
252
|
return decodeMessageContent(row?.content ?? null);
|
|
246
253
|
}
|
|
247
254
|
export function listHermesSessions(options = {}) {
|
|
248
|
-
if (!hermesStateDbExists()) {
|
|
255
|
+
if (!hermesStateDbExists(options.home)) {
|
|
249
256
|
return [];
|
|
250
257
|
}
|
|
251
258
|
const limit = Math.min(Math.max(options.limit ?? 200, 1), 500);
|
|
252
259
|
const fetchLimit = Math.min(limit * 4, 500);
|
|
253
|
-
const db = openReadOnlyDb();
|
|
260
|
+
const db = openReadOnlyDb(options.home);
|
|
254
261
|
try {
|
|
255
262
|
const rows = db
|
|
256
263
|
.prepare(`SELECT
|
|
@@ -313,15 +320,15 @@ function emptySessionUsage(sessionId, resolvedSessionId) {
|
|
|
313
320
|
messageCount: 0,
|
|
314
321
|
};
|
|
315
322
|
}
|
|
316
|
-
export function getSessionUsage(sessionId) {
|
|
323
|
+
export function getSessionUsage(sessionId, home) {
|
|
317
324
|
const trimmed = sessionId.trim();
|
|
318
325
|
if (!trimmed) {
|
|
319
326
|
return emptySessionUsage(sessionId, sessionId);
|
|
320
327
|
}
|
|
321
|
-
if (!hermesStateDbExists()) {
|
|
328
|
+
if (!hermesStateDbExists(home)) {
|
|
322
329
|
return emptySessionUsage(trimmed, trimmed);
|
|
323
330
|
}
|
|
324
|
-
const db = openReadOnlyDb();
|
|
331
|
+
const db = openReadOnlyDb(home);
|
|
325
332
|
try {
|
|
326
333
|
const resolved = resolveResumeSessionId(db, trimmed);
|
|
327
334
|
const chain = sessionAncestorChain(db, resolved);
|
|
@@ -366,20 +373,20 @@ export function getSessionUsage(sessionId) {
|
|
|
366
373
|
db.close();
|
|
367
374
|
}
|
|
368
375
|
}
|
|
369
|
-
export function hermesStateDbExists() {
|
|
376
|
+
export function hermesStateDbExists(home) {
|
|
370
377
|
try {
|
|
371
|
-
readFileSync(hermesStateDbPath());
|
|
378
|
+
readFileSync(hermesStateDbPath(home));
|
|
372
379
|
return true;
|
|
373
380
|
}
|
|
374
381
|
catch {
|
|
375
382
|
return false;
|
|
376
383
|
}
|
|
377
384
|
}
|
|
378
|
-
export function countUserMessagesSent() {
|
|
379
|
-
if (!hermesStateDbExists()) {
|
|
385
|
+
export function countUserMessagesSent(home) {
|
|
386
|
+
if (!hermesStateDbExists(home)) {
|
|
380
387
|
return { count: 0 };
|
|
381
388
|
}
|
|
382
|
-
const db = openReadOnlyDb();
|
|
389
|
+
const db = openReadOnlyDb(home);
|
|
383
390
|
try {
|
|
384
391
|
const row = db
|
|
385
392
|
.prepare("SELECT COUNT(*) AS count FROM messages WHERE role = 'user'")
|
|
@@ -393,3 +400,20 @@ export function countUserMessagesSent() {
|
|
|
393
400
|
db.close();
|
|
394
401
|
}
|
|
395
402
|
}
|
|
403
|
+
/** Total number of sessions in a profile's state.db (best-effort). */
|
|
404
|
+
export function countSessions(home) {
|
|
405
|
+
if (!hermesStateDbExists(home)) {
|
|
406
|
+
return 0;
|
|
407
|
+
}
|
|
408
|
+
const db = openReadOnlyDb(home);
|
|
409
|
+
try {
|
|
410
|
+
const row = db.prepare("SELECT COUNT(*) AS count FROM sessions").get();
|
|
411
|
+
return row?.count ?? 0;
|
|
412
|
+
}
|
|
413
|
+
catch {
|
|
414
|
+
return 0;
|
|
415
|
+
}
|
|
416
|
+
finally {
|
|
417
|
+
db.close();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keep in sync with @repo/backend-types/src/hermesStructuredContent.ts
|
|
3
|
+
* (duplicated here so the published bridge package stays self-contained).
|
|
4
|
+
*/
|
|
5
|
+
export declare function isHermesStructuredContent(content: string): boolean;
|
|
6
|
+
export declare function unwrapHermesStructuredContent(content: string): string;
|
|
7
|
+
export declare function looksLikeHermesStructuredStream(text: string): boolean;
|
|
8
|
+
//# sourceMappingURL=hermesStructuredContent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermesStructuredContent.d.ts","sourceRoot":"","sources":["../src/hermesStructuredContent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA0CH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAElE;AA6JD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMrE;AAED,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAIrE"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keep in sync with @repo/backend-types/src/hermesStructuredContent.ts
|
|
3
|
+
* (duplicated here so the published bridge package stays self-contained).
|
|
4
|
+
*/
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
function asString(value) {
|
|
9
|
+
return typeof value === "string" ? value : undefined;
|
|
10
|
+
}
|
|
11
|
+
function stringArray(value) {
|
|
12
|
+
if (!Array.isArray(value))
|
|
13
|
+
return [];
|
|
14
|
+
return value.filter((entry) => typeof entry === "string");
|
|
15
|
+
}
|
|
16
|
+
function stringMatrix(value) {
|
|
17
|
+
if (!Array.isArray(value))
|
|
18
|
+
return [];
|
|
19
|
+
return value
|
|
20
|
+
.filter((row) => Array.isArray(row))
|
|
21
|
+
.map((row) => row.filter((cell) => typeof cell === "string"));
|
|
22
|
+
}
|
|
23
|
+
function parseHermesStructuredRoot(text) {
|
|
24
|
+
const trimmed = text.trim();
|
|
25
|
+
if (!trimmed.startsWith("{"))
|
|
26
|
+
return null;
|
|
27
|
+
let parsed;
|
|
28
|
+
try {
|
|
29
|
+
parsed = JSON.parse(trimmed);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (!isRecord(parsed) || typeof parsed.component !== "string") {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return parsed;
|
|
38
|
+
}
|
|
39
|
+
export function isHermesStructuredContent(content) {
|
|
40
|
+
return parseHermesStructuredRoot(content) !== null;
|
|
41
|
+
}
|
|
42
|
+
function hermesChildren(node) {
|
|
43
|
+
const children = node.children;
|
|
44
|
+
if (!Array.isArray(children))
|
|
45
|
+
return [];
|
|
46
|
+
return children.filter(isRecord);
|
|
47
|
+
}
|
|
48
|
+
function joinBlocks(blocks) {
|
|
49
|
+
return blocks
|
|
50
|
+
.map((block) => block.trim())
|
|
51
|
+
.filter((block) => block.length > 0)
|
|
52
|
+
.join("\n\n");
|
|
53
|
+
}
|
|
54
|
+
function markdownTable(headers, rows) {
|
|
55
|
+
if (headers.length === 0)
|
|
56
|
+
return "";
|
|
57
|
+
const separator = headers.map(() => "---");
|
|
58
|
+
const body = rows.map((row) => {
|
|
59
|
+
const cells = headers.map((_, index) => row[index] ?? "");
|
|
60
|
+
return `| ${cells.join(" | ")} |`;
|
|
61
|
+
});
|
|
62
|
+
return joinBlocks([
|
|
63
|
+
`| ${headers.join(" | ")} |`,
|
|
64
|
+
`| ${separator.join(" | ")} |`,
|
|
65
|
+
...body,
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
function nodeToPlainText(node) {
|
|
69
|
+
const component = node.component;
|
|
70
|
+
if (typeof component !== "string")
|
|
71
|
+
return "";
|
|
72
|
+
switch (component) {
|
|
73
|
+
case "root":
|
|
74
|
+
return joinBlocks(hermesChildren(node).map(nodeToPlainText));
|
|
75
|
+
case "text":
|
|
76
|
+
return asString(node.text) ?? "";
|
|
77
|
+
case "heading": {
|
|
78
|
+
const text = asString(node.text);
|
|
79
|
+
if (!text)
|
|
80
|
+
return "";
|
|
81
|
+
const level = node.level === 3 ? 3 : 2;
|
|
82
|
+
return `${"#".repeat(level)} ${text}`;
|
|
83
|
+
}
|
|
84
|
+
case "table": {
|
|
85
|
+
const headers = stringArray(node.headers).length > 0
|
|
86
|
+
? stringArray(node.headers)
|
|
87
|
+
: stringArray(node.columns);
|
|
88
|
+
const rows = stringMatrix(node.rows);
|
|
89
|
+
if (headers.length === 0)
|
|
90
|
+
return "";
|
|
91
|
+
const caption = asString(node.caption);
|
|
92
|
+
const table = markdownTable(headers, rows);
|
|
93
|
+
return caption ? joinBlocks([caption, table]) : table;
|
|
94
|
+
}
|
|
95
|
+
case "list": {
|
|
96
|
+
const items = stringArray(node.items);
|
|
97
|
+
if (items.length === 0)
|
|
98
|
+
return "";
|
|
99
|
+
const style = node.style === "numbered" ? "numbered" : "bullet";
|
|
100
|
+
return items
|
|
101
|
+
.map((item, index) => (style === "numbered" ? `${index + 1}. ${item}` : `- ${item}`))
|
|
102
|
+
.join("\n");
|
|
103
|
+
}
|
|
104
|
+
case "code": {
|
|
105
|
+
const content = asString(node.content) ?? "";
|
|
106
|
+
const language = asString(node.language) ?? "";
|
|
107
|
+
return `\`\`\`${language}\n${content}\n\`\`\``;
|
|
108
|
+
}
|
|
109
|
+
case "link": {
|
|
110
|
+
const label = asString(node.label);
|
|
111
|
+
const url = asString(node.url);
|
|
112
|
+
if (label && url)
|
|
113
|
+
return `${label}: ${url}`;
|
|
114
|
+
return label ?? url ?? "";
|
|
115
|
+
}
|
|
116
|
+
case "key_value":
|
|
117
|
+
case "stat_cards": {
|
|
118
|
+
const items = Array.isArray(node.items) ? node.items.filter(isRecord) : [];
|
|
119
|
+
return joinBlocks(items.map((item) => {
|
|
120
|
+
const label = asString(item.label);
|
|
121
|
+
const value = asString(item.value);
|
|
122
|
+
if (!label || !value)
|
|
123
|
+
return "";
|
|
124
|
+
const hint = asString(item.hint);
|
|
125
|
+
return hint ? `${label}: ${value} (${hint})` : `${label}: ${value}`;
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
case "callout": {
|
|
129
|
+
const title = asString(node.title);
|
|
130
|
+
const body = asString(node.body) ?? "";
|
|
131
|
+
return joinBlocks([title, body].filter((part) => Boolean(part)));
|
|
132
|
+
}
|
|
133
|
+
case "choice": {
|
|
134
|
+
const prompt = asString(node.prompt) ?? "";
|
|
135
|
+
const options = Array.isArray(node.options) ? node.options.filter(isRecord) : [];
|
|
136
|
+
const optionLines = options
|
|
137
|
+
.map((option) => asString(option.label) ?? asString(option.id))
|
|
138
|
+
.filter((label) => Boolean(label))
|
|
139
|
+
.map((label) => `- ${label}`);
|
|
140
|
+
return joinBlocks([prompt, optionLines.join("\n")]);
|
|
141
|
+
}
|
|
142
|
+
case "yes_no":
|
|
143
|
+
return asString(node.prompt) ?? "";
|
|
144
|
+
case "suggestions": {
|
|
145
|
+
const items = Array.isArray(node.items) ? node.items.filter(isRecord) : [];
|
|
146
|
+
return items
|
|
147
|
+
.map((item) => asString(item.label) ?? asString(item.id))
|
|
148
|
+
.filter((label) => Boolean(label))
|
|
149
|
+
.map((label) => `- ${label}`)
|
|
150
|
+
.join("\n");
|
|
151
|
+
}
|
|
152
|
+
case "button_row": {
|
|
153
|
+
const buttons = Array.isArray(node.buttons) ? node.buttons.filter(isRecord) : [];
|
|
154
|
+
return buttons
|
|
155
|
+
.map((button) => asString(button.label) ?? asString(button.id))
|
|
156
|
+
.filter((label) => Boolean(label))
|
|
157
|
+
.join(" · ");
|
|
158
|
+
}
|
|
159
|
+
case "chart": {
|
|
160
|
+
const title = asString(node.title);
|
|
161
|
+
const labels = stringArray(node.labels);
|
|
162
|
+
const values = Array.isArray(node.values)
|
|
163
|
+
? node.values.map((value) => (typeof value === "number" ? String(value) : String(value ?? "")))
|
|
164
|
+
: [];
|
|
165
|
+
const series = labels
|
|
166
|
+
.map((label, index) => {
|
|
167
|
+
const value = values[index];
|
|
168
|
+
return value ? `${label}: ${value}` : label;
|
|
169
|
+
})
|
|
170
|
+
.join("\n");
|
|
171
|
+
return joinBlocks([title, series].filter((part) => Boolean(part)));
|
|
172
|
+
}
|
|
173
|
+
default: {
|
|
174
|
+
const text = asString(node.text) ?? asString(node.body) ?? asString(node.content);
|
|
175
|
+
if (text)
|
|
176
|
+
return text;
|
|
177
|
+
const children = hermesChildren(node);
|
|
178
|
+
if (children.length > 0) {
|
|
179
|
+
return joinBlocks(children.map(nodeToPlainText));
|
|
180
|
+
}
|
|
181
|
+
return "";
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
export function unwrapHermesStructuredContent(content) {
|
|
186
|
+
const root = parseHermesStructuredRoot(content);
|
|
187
|
+
if (!root)
|
|
188
|
+
return content;
|
|
189
|
+
const plain = nodeToPlainText(root).trim();
|
|
190
|
+
return plain.length > 0 ? plain : content;
|
|
191
|
+
}
|
|
192
|
+
export function looksLikeHermesStructuredStream(text) {
|
|
193
|
+
const trimmed = text.trimStart();
|
|
194
|
+
if (!trimmed.startsWith("{"))
|
|
195
|
+
return false;
|
|
196
|
+
return /^\{\s*"component"\s*:/.test(trimmed);
|
|
197
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermesStructuredContent.test.d.ts","sourceRoot":"","sources":["../src/hermesStructuredContent.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { isHermesStructuredContent, looksLikeHermesStructuredStream, unwrapHermesStructuredContent, } from "./hermesStructuredContent.js";
|
|
4
|
+
test("unwrapHermesStructuredContent extracts simple text block", () => {
|
|
5
|
+
const input = JSON.stringify({
|
|
6
|
+
component: "root",
|
|
7
|
+
children: [{ component: "text", text: "Det går fint! Hvordan står det til med deg?" }],
|
|
8
|
+
});
|
|
9
|
+
assert.equal(isHermesStructuredContent(input), true);
|
|
10
|
+
assert.equal(unwrapHermesStructuredContent(input), "Det går fint! Hvordan står det til med deg?");
|
|
11
|
+
});
|
|
12
|
+
test("looksLikeHermesStructuredStream detects early JSON envelope", () => {
|
|
13
|
+
assert.equal(looksLikeHermesStructuredStream('{"component":"root"'), true);
|
|
14
|
+
assert.equal(looksLikeHermesStructuredStream("Hello"), false);
|
|
15
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -19,5 +19,7 @@ export { backfillCronDeliveries, describeCronDeliveryState } from "./cronBackfil
|
|
|
19
19
|
export { resolveActiveConversationId, rememberConversationId } from "./activeConversation.js";
|
|
20
20
|
export { runBridgeDaemon } from "./daemon.js";
|
|
21
21
|
export type { RunBridgeOptions } from "./daemon.js";
|
|
22
|
-
export { DEFAULT_BRIDGE_INSTALL_URL, DEFAULT_BRIDGE_UPDATE_URL, DEFAULT_CLEOS_CONVEX_SITE_URL, DEFAULT_HERMES_API_URL, DEFAULT_BRIDGE_CAPABILITIES, HERMES_COMMANDS_CAPABILITY, HERMES_SESSION_TITLES_CAPABILITY, HERMES_SESSIONS_LIST_CAPABILITY, bridgeInstallCommand, bridgeUpdateCommand, } from "./constants.js";
|
|
22
|
+
export { DEFAULT_BRIDGE_INSTALL_URL, DEFAULT_BRIDGE_UPDATE_URL, DEFAULT_CLEOS_CONVEX_SITE_URL, DEFAULT_HERMES_API_URL, DEFAULT_BRIDGE_CAPABILITIES, HERMES_COMMANDS_CAPABILITY, HERMES_SESSION_TITLES_CAPABILITY, HERMES_SESSIONS_LIST_CAPABILITY, HERMES_PROFILES_CAPABILITY, bridgeInstallCommand, bridgeUpdateCommand, } from "./constants.js";
|
|
23
|
+
export { DEFAULT_PROFILE, isValidProfileName, listHermesProfiles, normalizeProfileName, resolveProfileContext, resolveProfileHome, } from "./profiles.js";
|
|
24
|
+
export type { HermesProfileContext, HermesProfileEntry } from "./profiles.js";
|
|
23
25
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACvF,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC/F,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACxE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC3G,YAAY,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACvF,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,+BAA+B,GAChC,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AACtF,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAC9F,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,6BAA6B,EAC7B,sBAAsB,EACtB,2BAA2B,EAC3B,0BAA0B,EAC1B,gCAAgC,EAChC,+BAA+B,EAC/B,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACvF,YAAY,EACV,oBAAoB,EACpB,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC/F,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACxE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC3G,YAAY,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACvF,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,+BAA+B,GAChC,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AACtF,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAC9F,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,6BAA6B,EAC7B,sBAAsB,EACtB,2BAA2B,EAC3B,0BAA0B,EAC1B,gCAAgC,EAChC,+BAA+B,EAC/B,0BAA0B,EAC1B,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -10,4 +10,5 @@ export { startCronWatcher, listPendingCronFiles, clearDeliveredIndex } from "./c
|
|
|
10
10
|
export { backfillCronDeliveries, describeCronDeliveryState } from "./cronBackfill.js";
|
|
11
11
|
export { resolveActiveConversationId, rememberConversationId } from "./activeConversation.js";
|
|
12
12
|
export { runBridgeDaemon } from "./daemon.js";
|
|
13
|
-
export { DEFAULT_BRIDGE_INSTALL_URL, DEFAULT_BRIDGE_UPDATE_URL, DEFAULT_CLEOS_CONVEX_SITE_URL, DEFAULT_HERMES_API_URL, DEFAULT_BRIDGE_CAPABILITIES, HERMES_COMMANDS_CAPABILITY, HERMES_SESSION_TITLES_CAPABILITY, HERMES_SESSIONS_LIST_CAPABILITY, bridgeInstallCommand, bridgeUpdateCommand, } from "./constants.js";
|
|
13
|
+
export { DEFAULT_BRIDGE_INSTALL_URL, DEFAULT_BRIDGE_UPDATE_URL, DEFAULT_CLEOS_CONVEX_SITE_URL, DEFAULT_HERMES_API_URL, DEFAULT_BRIDGE_CAPABILITIES, HERMES_COMMANDS_CAPABILITY, HERMES_SESSION_TITLES_CAPABILITY, HERMES_SESSIONS_LIST_CAPABILITY, HERMES_PROFILES_CAPABILITY, bridgeInstallCommand, bridgeUpdateCommand, } from "./constants.js";
|
|
14
|
+
export { DEFAULT_PROFILE, isValidProfileName, listHermesProfiles, normalizeProfileName, resolveProfileContext, resolveProfileHome, } from "./profiles.js";
|
package/dist/mcpList.d.ts
CHANGED
|
@@ -6,17 +6,18 @@ export type HermesMcpServerEntry = {
|
|
|
6
6
|
enabled: boolean;
|
|
7
7
|
};
|
|
8
8
|
export declare function parseMcpListOutput(stdout: string): HermesMcpServerEntry[];
|
|
9
|
-
export declare function listHermesMcpServers(): Promise<{
|
|
9
|
+
export declare function listHermesMcpServers(env?: NodeJS.ProcessEnv): Promise<{
|
|
10
10
|
servers: HermesMcpServerEntry[];
|
|
11
11
|
}>;
|
|
12
12
|
export declare function addHermesMcpServer(input: {
|
|
13
13
|
name?: string;
|
|
14
14
|
json: string;
|
|
15
|
+
env?: NodeJS.ProcessEnv;
|
|
15
16
|
}): Promise<{
|
|
16
17
|
ok: true;
|
|
17
18
|
name: string;
|
|
18
19
|
}>;
|
|
19
|
-
export declare function removeHermesMcpServer(name: string): Promise<{
|
|
20
|
+
export declare function removeHermesMcpServer(name: string, env?: NodeJS.ProcessEnv): Promise<{
|
|
20
21
|
ok: true;
|
|
21
22
|
name: string;
|
|
22
23
|
}>;
|
package/dist/mcpList.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcpList.d.ts","sourceRoot":"","sources":["../src/mcpList.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAqBF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAwEzE;AAED,wBAAsB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"mcpList.d.ts","sourceRoot":"","sources":["../src/mcpList.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAqBF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAwEzE;AAED,wBAAsB,oBAAoB,CACxC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC;IAAE,OAAO,EAAE,oBAAoB,EAAE,CAAA;CAAE,CAAC,CAgB9C;AAuLD,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAYtC;AAED,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAOrC"}
|
package/dist/mcpList.js
CHANGED
|
@@ -85,12 +85,12 @@ export function parseMcpListOutput(stdout) {
|
|
|
85
85
|
}
|
|
86
86
|
return servers;
|
|
87
87
|
}
|
|
88
|
-
export async function listHermesMcpServers() {
|
|
88
|
+
export async function listHermesMcpServers(env = process.env) {
|
|
89
89
|
try {
|
|
90
90
|
const { stdout } = await execFileAsync("hermes", ["mcp", "list"], {
|
|
91
91
|
timeout: LIST_TIMEOUT_MS,
|
|
92
92
|
maxBuffer: MAX_OUTPUT_BYTES,
|
|
93
|
-
env
|
|
93
|
+
env,
|
|
94
94
|
});
|
|
95
95
|
return { servers: parseMcpListOutput(stdout) };
|
|
96
96
|
}
|
|
@@ -261,15 +261,15 @@ export async function addHermesMcpServer(input) {
|
|
|
261
261
|
await execFileAsync("hermes", argv, {
|
|
262
262
|
timeout: ADD_TIMEOUT_MS,
|
|
263
263
|
maxBuffer: MAX_OUTPUT_BYTES,
|
|
264
|
-
env: process.env,
|
|
264
|
+
env: input.env ?? process.env,
|
|
265
265
|
});
|
|
266
266
|
return { ok: true, name: normalized.name };
|
|
267
267
|
}
|
|
268
|
-
export async function removeHermesMcpServer(name) {
|
|
268
|
+
export async function removeHermesMcpServer(name, env = process.env) {
|
|
269
269
|
await execFileAsync("hermes", ["mcp", "remove", name], {
|
|
270
270
|
timeout: REMOVE_TIMEOUT_MS,
|
|
271
271
|
maxBuffer: MAX_OUTPUT_BYTES,
|
|
272
|
-
env
|
|
272
|
+
env,
|
|
273
273
|
});
|
|
274
274
|
return { ok: true, name };
|
|
275
275
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** Hermes default profile is the base home (`~/.hermes`) itself. */
|
|
2
|
+
export declare const DEFAULT_PROFILE = "default";
|
|
3
|
+
export declare class HermesProfileError extends Error {
|
|
4
|
+
}
|
|
5
|
+
export declare function isValidProfileName(name: string): boolean;
|
|
6
|
+
export declare function normalizeProfileName(profile?: string | null): string;
|
|
7
|
+
export declare function isDefaultProfile(profile?: string | null): boolean;
|
|
8
|
+
/** Base Hermes home — the default profile's directory. */
|
|
9
|
+
export declare function resolveBaseHermesHome(): string;
|
|
10
|
+
export declare function profilesRootDir(): string;
|
|
11
|
+
/** Resolve the Hermes home directory for a given profile (default → base home). */
|
|
12
|
+
export declare function resolveProfileHome(profile?: string | null): string;
|
|
13
|
+
/** Build an env that scopes child `hermes` processes to the given profile. */
|
|
14
|
+
export declare function profileEnv(profile?: string | null): NodeJS.ProcessEnv;
|
|
15
|
+
/** Best-effort parse of `model.default` from a profile's config.yaml. */
|
|
16
|
+
export declare function readProfileModel(home: string): string | undefined;
|
|
17
|
+
export declare function resolveProfileGatewayPort(profile?: string | null): number | undefined;
|
|
18
|
+
export declare function resolveProfileGatewayUrl(profile?: string | null): string;
|
|
19
|
+
export type HermesProfileContext = {
|
|
20
|
+
profile: string;
|
|
21
|
+
home: string;
|
|
22
|
+
apiUrl: string;
|
|
23
|
+
apiKey: string | undefined;
|
|
24
|
+
env: NodeJS.ProcessEnv;
|
|
25
|
+
};
|
|
26
|
+
export declare function resolveProfileContext(profile?: string | null): HermesProfileContext;
|
|
27
|
+
export type HermesProfileEntry = {
|
|
28
|
+
name: string;
|
|
29
|
+
isDefault: boolean;
|
|
30
|
+
isActive: boolean;
|
|
31
|
+
model?: string;
|
|
32
|
+
gatewayRunning: boolean;
|
|
33
|
+
gatewayPort?: number;
|
|
34
|
+
skillsCount: number;
|
|
35
|
+
sessionsCount: number;
|
|
36
|
+
home: string;
|
|
37
|
+
};
|
|
38
|
+
/** Cheap, sync enumeration of profile homes (default + on-disk profiles). */
|
|
39
|
+
export declare function listProfileHomes(): {
|
|
40
|
+
profile: string;
|
|
41
|
+
home: string;
|
|
42
|
+
}[];
|
|
43
|
+
export declare function listHermesProfiles(): Promise<{
|
|
44
|
+
profiles: HermesProfileEntry[];
|
|
45
|
+
}>;
|
|
46
|
+
export declare function createHermesProfile(name: string, options?: {
|
|
47
|
+
clone?: boolean;
|
|
48
|
+
}): Promise<{
|
|
49
|
+
ok: true;
|
|
50
|
+
name: string;
|
|
51
|
+
}>;
|
|
52
|
+
export declare function renameHermesProfile(oldName: string, newName: string): Promise<{
|
|
53
|
+
ok: true;
|
|
54
|
+
oldName: string;
|
|
55
|
+
newName: string;
|
|
56
|
+
}>;
|
|
57
|
+
export declare function deleteHermesProfile(name: string): Promise<{
|
|
58
|
+
ok: true;
|
|
59
|
+
name: string;
|
|
60
|
+
}>;
|
|
61
|
+
export declare function setHermesProfileModel(profile: string | undefined, model: string): Promise<{
|
|
62
|
+
ok: true;
|
|
63
|
+
profile: string;
|
|
64
|
+
model: string;
|
|
65
|
+
}>;
|
|
66
|
+
//# sourceMappingURL=profiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../src/profiles.ts"],"names":[],"mappings":"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"}
|