@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.
Files changed (61) hide show
  1. package/dist/client.d.ts +2 -0
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/client.js +5 -1
  4. package/dist/constants.d.ts +2 -0
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/constants.js +3 -0
  7. package/dist/cronList.d.ts +2 -0
  8. package/dist/cronList.d.ts.map +1 -1
  9. package/dist/cronList.js +11 -8
  10. package/dist/cronWatcher.d.ts +1 -1
  11. package/dist/cronWatcher.d.ts.map +1 -1
  12. package/dist/cronWatcher.js +70 -29
  13. package/dist/ensureHermesApi.d.ts +1 -1
  14. package/dist/ensureHermesApi.d.ts.map +1 -1
  15. package/dist/ensureHermesApi.js +14 -10
  16. package/dist/gatewayControl.d.ts +3 -3
  17. package/dist/gatewayControl.d.ts.map +1 -1
  18. package/dist/gatewayControl.js +58 -24
  19. package/dist/hermesCommands.d.ts +1 -1
  20. package/dist/hermesCommands.d.ts.map +1 -1
  21. package/dist/hermesCommands.js +48 -27
  22. package/dist/hermesFileCommands.d.ts +5 -5
  23. package/dist/hermesFileCommands.d.ts.map +1 -1
  24. package/dist/hermesFileCommands.js +10 -10
  25. package/dist/hermesFiles.d.ts +7 -6
  26. package/dist/hermesFiles.d.ts.map +1 -1
  27. package/dist/hermesFiles.js +11 -14
  28. package/dist/hermesForwarder.d.ts +2 -0
  29. package/dist/hermesForwarder.d.ts.map +1 -1
  30. package/dist/hermesForwarder.js +49 -24
  31. package/dist/hermesSessionDb.d.ts +10 -6
  32. package/dist/hermesSessionDb.d.ts.map +1 -1
  33. package/dist/hermesSessionDb.js +48 -24
  34. package/dist/hermesStructuredContent.d.ts +8 -0
  35. package/dist/hermesStructuredContent.d.ts.map +1 -0
  36. package/dist/hermesStructuredContent.js +197 -0
  37. package/dist/hermesStructuredContent.test.d.ts +2 -0
  38. package/dist/hermesStructuredContent.test.d.ts.map +1 -0
  39. package/dist/hermesStructuredContent.test.js +15 -0
  40. package/dist/index.d.ts +3 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +2 -1
  43. package/dist/mcpList.d.ts +3 -2
  44. package/dist/mcpList.d.ts.map +1 -1
  45. package/dist/mcpList.js +5 -5
  46. package/dist/profiles.d.ts +66 -0
  47. package/dist/profiles.d.ts.map +1 -0
  48. package/dist/profiles.js +409 -0
  49. package/dist/renameHermesSession.d.ts +1 -1
  50. package/dist/renameHermesSession.d.ts.map +1 -1
  51. package/dist/renameHermesSession.js +2 -2
  52. package/dist/skillLearnedDetector.d.ts +1 -1
  53. package/dist/skillLearnedDetector.d.ts.map +1 -1
  54. package/dist/skillLearnedDetector.js +2 -3
  55. package/dist/skillsList.d.ts +5 -2
  56. package/dist/skillsList.d.ts.map +1 -1
  57. package/dist/skillsList.js +14 -14
  58. package/dist/toolsList.d.ts +2 -2
  59. package/dist/toolsList.d.ts.map +1 -1
  60. package/dist/toolsList.js +4 -4
  61. package/package.json +2 -2
@@ -12,6 +12,7 @@ import { executeShellExec, resetShellSession } from "./shellSession.js";
12
12
  import { fetchHermesRuntimeVersion } from "./runtimeVersion.js";
13
13
  import { fetchBridgeRuntimeVersion, fetchInstalledBridgeVersion } from "./bridgeVersion.js";
14
14
  import { runBridgeUpdate } from "./update.js";
15
+ import { createHermesProfile, deleteHermesProfile, listHermesProfiles, renameHermesProfile, resolveProfileContext, setHermesProfileModel, } from "./profiles.js";
15
16
  import { spawn } from "node:child_process";
16
17
  export const HERMES_COMMAND_NAMES = [
17
18
  "runtime.health",
@@ -34,6 +35,8 @@ export const HERMES_COMMAND_NAMES = [
34
35
  "jobs.delete",
35
36
  "profiles.list",
36
37
  "profiles.create",
38
+ "profiles.rename",
39
+ "profiles.delete",
37
40
  "gateway.start",
38
41
  "gateway.stop",
39
42
  "gateway.restart",
@@ -175,7 +178,11 @@ function scheduleDetachedBridgeRestart() {
175
178
  }
176
179
  }
177
180
  export async function executeHermesCommand(command, args, options = {}) {
178
- const config = resolveHermesApiConfig(options);
181
+ const profileName = optionalString(args, "profile");
182
+ const profileCtx = resolveProfileContext(profileName);
183
+ const config = resolveHermesApiConfig({ ...options, profile: profileCtx.profile });
184
+ const home = profileCtx.home;
185
+ const env = profileCtx.env;
179
186
  const { onDelta } = options;
180
187
  switch (command) {
181
188
  case "runtime.health":
@@ -188,8 +195,10 @@ export async function executeHermesCommand(command, args, options = {}) {
188
195
  return await hermesFetchJson(config, "/v1/capabilities");
189
196
  case "models.list":
190
197
  return await hermesFetchJson(config, "/v1/models");
191
- case "model.set":
192
- throw new HermesCommandError("unsupported_by_http", "Changing the active Hermes model is not exposed over the HTTP API. Update Hermes config on the agent machine.");
198
+ case "model.set": {
199
+ const model = requireString(args, "model");
200
+ return await setHermesProfileModel(profileCtx.profile, model);
201
+ }
193
202
  case "responses.create": {
194
203
  const input = args.input ?? args.prompt;
195
204
  if (typeof input !== "string" || input.trim().length === 0) {
@@ -256,7 +265,7 @@ export async function executeHermesCommand(command, args, options = {}) {
256
265
  case "jobs.list": {
257
266
  const includeAll = args.all === true || args.includeInactive === true;
258
267
  if (includeAll) {
259
- return await listHermesCronJobs({ all: true });
268
+ return await listHermesCronJobs({ all: true, home, env });
260
269
  }
261
270
  return await hermesFetchJson(config, "/api/jobs");
262
271
  }
@@ -318,15 +327,27 @@ export async function executeHermesCommand(command, args, options = {}) {
318
327
  });
319
328
  }
320
329
  case "profiles.list":
321
- throw new HermesCommandError("unsupported_by_http", "Listing Hermes profiles is not exposed over the HTTP API.");
322
- case "profiles.create":
323
- throw new HermesCommandError("unsupported_by_http", "Creating Hermes profiles is not exposed over the HTTP API. Run `hermes profile create` on the agent machine.");
330
+ return await listHermesProfiles();
331
+ case "profiles.create": {
332
+ const name = requireString(args, "name");
333
+ const clone = args.clone === true;
334
+ return await createHermesProfile(name, { clone });
335
+ }
336
+ case "profiles.rename": {
337
+ const oldName = requireString(args, "oldName");
338
+ const newName = requireString(args, "newName");
339
+ return await renameHermesProfile(oldName, newName);
340
+ }
341
+ case "profiles.delete": {
342
+ const name = requireString(args, "name");
343
+ return await deleteHermesProfile(name);
344
+ }
324
345
  case "gateway.start":
325
- return await startHermesGateway();
346
+ return await startHermesGateway(profileCtx.profile);
326
347
  case "gateway.stop":
327
- return await stopHermesGateway();
348
+ return await stopHermesGateway(profileCtx.profile);
328
349
  case "gateway.restart":
329
- return await restartHermesGateway();
350
+ return await restartHermesGateway(profileCtx.profile);
330
351
  case "hermes.update": {
331
352
  const restartGateway = args.restartGateway === true || args.restart_gateway === true;
332
353
  return await runHermesUpdate({ restartGateway });
@@ -349,57 +370,57 @@ export async function executeHermesCommand(command, args, options = {}) {
349
370
  const limit = optionalNumber(args, "limit");
350
371
  const offset = optionalNumber(args, "offset");
351
372
  const offsetFromEnd = optionalNumber(args, "offsetFromEnd");
352
- return listSessionMessages(sessionId, { limit, offset, offsetFromEnd });
373
+ return listSessionMessages(sessionId, { limit, offset, offsetFromEnd, home });
353
374
  }
354
375
  case "sessions.messages.countSent":
355
- return countUserMessagesSent();
376
+ return countUserMessagesSent(home);
356
377
  case "sessions.titles.resolve": {
357
378
  const sessionIds = optionalStringArray(args, "sessionIds") ?? [];
358
- return { titles: resolveSessionTitles(sessionIds) };
379
+ return { titles: resolveSessionTitles(sessionIds, home) };
359
380
  }
360
381
  case "sessions.rename": {
361
382
  const sessionId = requireString(args, "sessionId");
362
383
  const title = requireString(args, "title");
363
- return await renameHermesSession(sessionId, title);
384
+ return await renameHermesSession(sessionId, title, env);
364
385
  }
365
386
  case "sessions.usage.get": {
366
387
  const sessionId = requireString(args, "sessionId");
367
- return getSessionUsage(sessionId);
388
+ return getSessionUsage(sessionId, home);
368
389
  }
369
390
  case "sessions.list": {
370
391
  const limit = optionalNumber(args, "limit");
371
- return { sessions: listHermesSessions({ limit: limit ?? 200 }) };
392
+ return { sessions: listHermesSessions({ limit: limit ?? 200, home }) };
372
393
  }
373
394
  case "skills.list":
374
- return await listHermesSkills();
395
+ return await listHermesSkills({ home, env });
375
396
  case "tools.list": {
376
397
  const platform = optionalString(args, "platform");
377
- return await listHermesTools(platform);
398
+ return await listHermesTools(platform, env);
378
399
  }
379
400
  case "tools.set": {
380
401
  const name = requireString(args, "name");
381
402
  const enabled = args.enabled === true;
382
- return await setHermesToolEnabled(name, enabled);
403
+ return await setHermesToolEnabled(name, enabled, env);
383
404
  }
384
405
  case "mcp.list":
385
- return await listHermesMcpServers();
406
+ return await listHermesMcpServers(env);
386
407
  case "mcp.add": {
387
408
  const name = optionalString(args, "name");
388
409
  const json = requireString(args, "json");
389
- return await addHermesMcpServer({ name, json });
410
+ return await addHermesMcpServer({ name, json, env });
390
411
  }
391
412
  case "mcp.remove": {
392
413
  const name = requireString(args, "name");
393
- return await removeHermesMcpServer(name);
414
+ return await removeHermesMcpServer(name, env);
394
415
  }
395
416
  case "files.list":
396
- return await executeFilesList(args);
417
+ return await executeFilesList(args, home);
397
418
  case "files.read": {
398
419
  const path = optionalString(args, "path");
399
420
  if (!path) {
400
421
  throw new HermesCommandError("invalid_command_args", 'Missing "path"');
401
422
  }
402
- return await executeFilesRead({ ...args, path });
423
+ return await executeFilesRead({ ...args, path }, home);
403
424
  }
404
425
  case "files.write": {
405
426
  const path = optionalString(args, "path");
@@ -410,17 +431,17 @@ export async function executeHermesCommand(command, args, options = {}) {
410
431
  if (typeof content !== "string") {
411
432
  throw new HermesCommandError("invalid_command_args", 'Missing "content"');
412
433
  }
413
- return await executeFilesWrite({ path, content });
434
+ return await executeFilesWrite({ path, content }, home);
414
435
  }
415
436
  case "files.delete": {
416
437
  const path = optionalString(args, "path");
417
438
  if (!path) {
418
439
  throw new HermesCommandError("invalid_command_args", 'Missing "path"');
419
440
  }
420
- return await executeFilesDelete({ path });
441
+ return await executeFilesDelete({ path }, home);
421
442
  }
422
443
  case "memories.list":
423
- return await executeMemoriesList();
444
+ return await executeMemoriesList(home);
424
445
  case "shell.exec": {
425
446
  if (!onDelta) {
426
447
  throw new HermesCommandError("invalid_command_args", "shell.exec requires streaming support");
@@ -1,19 +1,19 @@
1
- export declare function executeFilesList(args: Record<string, unknown>): Promise<{
1
+ export declare function executeFilesList(args: Record<string, unknown>, home?: string): Promise<{
2
2
  files: import("./hermesFiles.js").HermesFileEntry[];
3
3
  }>;
4
- export declare function executeFilesWrite(args: Record<string, unknown>): Promise<{
4
+ export declare function executeFilesWrite(args: Record<string, unknown>, home?: string): Promise<{
5
5
  ok: true;
6
6
  relativePath: string;
7
7
  size: number;
8
8
  }>;
9
- export declare function executeFilesDelete(args: Record<string, unknown>): Promise<{
9
+ export declare function executeFilesDelete(args: Record<string, unknown>, home?: string): Promise<{
10
10
  ok: true;
11
11
  deletedPath: string;
12
12
  }>;
13
- export declare function executeMemoriesList(): Promise<{
13
+ export declare function executeMemoriesList(home?: string): Promise<{
14
14
  files: import("./hermesFiles.js").HermesFileEntry[];
15
15
  }>;
16
- export declare function executeFilesRead(args: Record<string, unknown>): Promise<{
16
+ export declare function executeFilesRead(args: Record<string, unknown>, home?: string): Promise<{
17
17
  fileName: string;
18
18
  mimeType: string;
19
19
  size: number;
@@ -1 +1 @@
1
- {"version":3,"file":"hermesFileCommands.d.ts","sourceRoot":"","sources":["../src/hermesFileCommands.ts"],"names":[],"mappings":"AAgCA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;GAKnE;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;GAUpE;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;GAMrE;AAED,wBAAsB,mBAAmB;;GAExC;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;;;GAkCnE"}
1
+ {"version":3,"file":"hermesFileCommands.d.ts","sourceRoot":"","sources":["../src/hermesFileCommands.ts"],"names":[],"mappings":"AAgCA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM;;GAKlF;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM;;;;GAUnF;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM;;;GAMpF;AAED,wBAAsB,mBAAmB,CAAC,IAAI,CAAC,EAAE,MAAM;;GAEtD;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM;;;;;;;;;;;;;;GAkClF"}
@@ -22,13 +22,13 @@ function optionalCategory(args) {
22
22
  }
23
23
  return "all";
24
24
  }
25
- export async function executeFilesList(args) {
25
+ export async function executeFilesList(args, home) {
26
26
  const limit = optionalNumber(args, "limit");
27
27
  const offset = optionalNumber(args, "offset");
28
28
  const category = optionalCategory(args);
29
- return listHermesFiles({ limit, offset, category });
29
+ return listHermesFiles({ limit, offset, category, home });
30
30
  }
31
- export async function executeFilesWrite(args) {
31
+ export async function executeFilesWrite(args, home) {
32
32
  const path = typeof args.path === "string" ? args.path.trim() : "";
33
33
  if (!path) {
34
34
  throw new Error('Missing "path"');
@@ -37,22 +37,22 @@ export async function executeFilesWrite(args) {
37
37
  if (content === undefined) {
38
38
  throw new Error('Missing "content"');
39
39
  }
40
- return writeHermesFile(path, content);
40
+ return writeHermesFile(path, content, home);
41
41
  }
42
- export async function executeFilesDelete(args) {
42
+ export async function executeFilesDelete(args, home) {
43
43
  const path = typeof args.path === "string" ? args.path.trim() : "";
44
44
  if (!path) {
45
45
  throw new Error('Missing "path"');
46
46
  }
47
- return deleteHermesFile(path);
47
+ return deleteHermesFile(path, home);
48
48
  }
49
- export async function executeMemoriesList() {
50
- return listHermesMemoryFiles();
49
+ export async function executeMemoriesList(home) {
50
+ return listHermesMemoryFiles(home);
51
51
  }
52
- export async function executeFilesRead(args) {
52
+ export async function executeFilesRead(args, home) {
53
53
  const path = typeof args.path === "string" ? args.path.trim() : "";
54
54
  const maxBytes = optionalNumber(args, "maxBytes") ?? DEFAULT_FILES_READ_MAX_BYTES;
55
- const { bytes, mimeType, fileName, size } = readHermesFileBytes(path);
55
+ const { bytes, mimeType, fileName, size } = readHermesFileBytes(path, home);
56
56
  if (size <= maxBytes) {
57
57
  return {
58
58
  fileName,
@@ -43,30 +43,31 @@ export type MediaReference = {
43
43
  export declare function resolveHermesHome(): string;
44
44
  export declare function inferMimeType(fileName: string): string;
45
45
  export declare function inferCategory(fileName: string): HermesFileCategory;
46
- export declare function resolveSandboxedPath(inputPath: string): string;
46
+ export declare function resolveSandboxedPath(inputPath: string, home?: string): string;
47
47
  export declare function listHermesFiles(options?: {
48
48
  limit?: number;
49
49
  offset?: number;
50
50
  category?: HermesFileCategory | "all";
51
+ home?: string;
51
52
  }): {
52
53
  files: HermesFileEntry[];
53
54
  };
54
55
  export declare function normalizeHermesRelativePath(inputPath: string): string;
55
56
  export declare function isWritableSkillPath(relativePath: string): boolean;
56
57
  export declare function assertWritableHermesPath(inputPath: string): string;
57
- export declare function writeHermesFile(inputPath: string, content: string): {
58
+ export declare function writeHermesFile(inputPath: string, content: string, home?: string): {
58
59
  ok: true;
59
60
  relativePath: string;
60
61
  size: number;
61
62
  };
62
- export declare function deleteHermesFile(inputPath: string): {
63
+ export declare function deleteHermesFile(inputPath: string, home?: string): {
63
64
  ok: true;
64
65
  deletedPath: string;
65
66
  };
66
- export declare function listHermesMemoryFiles(): {
67
+ export declare function listHermesMemoryFiles(home?: string): {
67
68
  files: HermesFileEntry[];
68
69
  };
69
- export declare function readHermesFileBytes(inputPath: string): {
70
+ export declare function readHermesFileBytes(inputPath: string, home?: string): {
70
71
  bytes: Buffer;
71
72
  mimeType: string;
72
73
  fileName: string;
@@ -80,7 +81,7 @@ export declare function downloadUrlToBytes(url: string, timeoutMs?: number): Pro
80
81
  fileName: string;
81
82
  size: number;
82
83
  }>;
83
- export declare function resolveMediaReferenceBytes(ref: MediaReference): Promise<{
84
+ export declare function resolveMediaReferenceBytes(ref: MediaReference, home?: string): Promise<{
84
85
  bytes: Buffer;
85
86
  mimeType: string;
86
87
  fileName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"hermesFiles.d.ts","sourceRoot":"","sources":["../src/hermesFiles.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hermesFiles.d.ts","sourceRoot":"","sources":["../src/hermesFiles.ts"],"names":[],"mappings":"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"}
@@ -131,8 +131,7 @@ function isPathInsideRoot(root, candidate) {
131
131
  const { root: normalizedRoot, candidate: normalizedCandidate } = normalizePathForSandbox(root, candidate);
132
132
  return normalizedCandidate === normalizedRoot || normalizedCandidate.startsWith(`${normalizedRoot}${sep}`);
133
133
  }
134
- export function resolveSandboxedPath(inputPath) {
135
- const home = resolveHermesHome();
134
+ export function resolveSandboxedPath(inputPath, home = resolveHermesHome()) {
136
135
  const candidate = inputPath.startsWith("/") ? resolve(inputPath) : resolve(home, inputPath);
137
136
  if (!isPathInsideRoot(home, candidate)) {
138
137
  throw new Error(`Path is outside Hermes home: ${inputPath}`);
@@ -227,7 +226,7 @@ function walkFiles(rootDir, home, files, jobNames) {
227
226
  }
228
227
  }
229
228
  export function listHermesFiles(options = {}) {
230
- const home = resolveHermesHome();
229
+ const home = options.home ?? resolveHermesHome();
231
230
  const limit = options.limit ?? 200;
232
231
  const offset = options.offset ?? 0;
233
232
  const category = options.category ?? "all";
@@ -283,14 +282,13 @@ function memoryCharLimitForPath(relativePath) {
283
282
  return USER_MD_CHAR_LIMIT;
284
283
  return undefined;
285
284
  }
286
- export function writeHermesFile(inputPath, content) {
285
+ export function writeHermesFile(inputPath, content, home = resolveHermesHome()) {
287
286
  const relativePath = assertWritableHermesPath(inputPath);
288
287
  const charLimit = memoryCharLimitForPath(relativePath);
289
288
  if (charLimit !== undefined && content.length > charLimit) {
290
289
  throw new Error(`Content exceeds ${charLimit} character limit for ${relativePath} (${content.length} chars)`);
291
290
  }
292
- const home = resolveHermesHome();
293
- const resolved = resolveSandboxedPath(relativePath);
291
+ const resolved = resolveSandboxedPath(relativePath, home);
294
292
  if (relativePath.startsWith(`${SKILLS_DIR}/`)) {
295
293
  mkdirSync(dirname(resolved), { recursive: true });
296
294
  }
@@ -301,12 +299,12 @@ export function writeHermesFile(inputPath, content) {
301
299
  writeFileSync(resolved, bytes);
302
300
  return { ok: true, relativePath, size: bytes.length };
303
301
  }
304
- export function deleteHermesFile(inputPath) {
302
+ export function deleteHermesFile(inputPath, home = resolveHermesHome()) {
305
303
  const relativePath = normalizeHermesRelativePath(inputPath);
306
304
  if (!isWritableSkillPath(relativePath)) {
307
305
  throw new Error(`Path is not deletable: ${inputPath}`);
308
306
  }
309
- const resolved = resolveSandboxedPath(relativePath);
307
+ const resolved = resolveSandboxedPath(relativePath, home);
310
308
  if (!existsSync(resolved)) {
311
309
  throw new Error(`File not found: ${inputPath}`);
312
310
  }
@@ -342,8 +340,7 @@ function memoryFileEntry(home, fileName) {
342
340
  source: "artifact",
343
341
  };
344
342
  }
345
- export function listHermesMemoryFiles() {
346
- const home = resolveHermesHome();
343
+ export function listHermesMemoryFiles(home = resolveHermesHome()) {
347
344
  const memoriesRoot = join(home, MEMORIES_DIR);
348
345
  const discovered = new Set(KNOWN_MEMORY_FILES);
349
346
  if (existsSync(memoriesRoot)) {
@@ -363,8 +360,8 @@ export function listHermesMemoryFiles() {
363
360
  .map((fileName) => memoryFileEntry(home, fileName));
364
361
  return { files };
365
362
  }
366
- export function readHermesFileBytes(inputPath) {
367
- const resolved = resolveSandboxedPath(inputPath);
363
+ export function readHermesFileBytes(inputPath, home = resolveHermesHome()) {
364
+ const resolved = resolveSandboxedPath(inputPath, home);
368
365
  if (!existsSync(resolved)) {
369
366
  throw new Error(`File not found: ${inputPath}`);
370
367
  }
@@ -441,10 +438,10 @@ export async function downloadUrlToBytes(url, timeoutMs = 30_000) {
441
438
  clearTimeout(timer);
442
439
  }
443
440
  }
444
- export async function resolveMediaReferenceBytes(ref) {
441
+ export async function resolveMediaReferenceBytes(ref, home = resolveHermesHome()) {
445
442
  try {
446
443
  if (ref.kind === "local") {
447
- return readHermesFileBytes(ref.absolutePath);
444
+ return readHermesFileBytes(ref.absolutePath, home);
448
445
  }
449
446
  return await downloadUrlToBytes(ref.url);
450
447
  }
@@ -4,6 +4,7 @@ export type HermesForwarderOptions = {
4
4
  apiKey?: string;
5
5
  model?: string;
6
6
  conversationId?: string;
7
+ profile?: string;
7
8
  };
8
9
  export type HermesForwardResult = {
9
10
  sessionId: string;
@@ -12,6 +13,7 @@ export declare function resolveHermesApiConfig(options?: HermesForwarderOptions)
12
13
  apiUrl: string;
13
14
  apiKey: string | undefined;
14
15
  model: string;
16
+ home: string;
15
17
  };
16
18
  export declare function forwardToHermes(content: string, meta: UserMessageMeta, reply: AgentReply, options?: HermesForwarderOptions): Promise<HermesForwardResult>;
17
19
  export declare function createHermesMessageHandler(options?: HermesForwarderOptions): (content: string, meta: UserMessageMeta, reply: AgentReply) => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"hermesForwarder.d.ts","sourceRoot":"","sources":["../src/hermesForwarder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAyB,eAAe,EAAE,MAAM,aAAa,CAAC;AAmBtF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAkBF,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,sBAA2B,GAAG;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;CACf,CAUA;AAgID,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,CAyF9B;AA2BD,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,sBAA2B,IAC/D,SAAS,MAAM,EAAE,MAAM,eAAe,EAAE,OAAO,UAAU,KAAG,OAAO,CAAC,IAAI,CAAC,CAMxF"}
1
+ {"version":3,"file":"hermesForwarder.d.ts","sourceRoot":"","sources":["../src/hermesForwarder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAyB,eAAe,EAAE,MAAM,aAAa,CAAC;AAuBtF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAkBF,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,sBAA2B,GAAG;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAaA;AAiID,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,CA6G9B;AA4BD,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,sBAA2B,IAC/D,SAAS,MAAM,EAAE,MAAM,eAAe,EAAE,OAAO,UAAU,KAAG,OAAO,CAAC,IAAI,CAAC,CAOxF"}
@@ -2,13 +2,14 @@ import { readFileSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { linkHermesMessageIds, uploadFileToConvex } from "./convexRelay.js";
5
- import { DEFAULT_HERMES_API_URL } from "./constants.js";
6
5
  import { getLatestTurnMessageIds, getSessionUsage, hermesStateDbExists } from "./hermesSessionDb.js";
7
6
  import { diffSkillsLearned, snapshotSkills } from "./skillLearnedDetector.js";
8
7
  import { buildTurnActivity, createTurnActivityAccumulator, parseSseDataLines, processSseEventBlock, } from "./turnActivity.js";
9
8
  import { parseMediaReferences, resolveMediaReferenceBytes, stripMediaReferences, } from "./hermesFiles.js";
10
- function readHermesApiKeyFromEnvFile() {
11
- const envPath = join(homedir(), ".hermes", ".env");
9
+ import { looksLikeHermesStructuredStream, unwrapHermesStructuredContent, } from "./hermesStructuredContent.js";
10
+ import { resolveProfileContext } from "./profiles.js";
11
+ function readHermesApiKeyFromEnvFile(home) {
12
+ const envPath = join(home?.trim() || join(homedir(), ".hermes"), ".env");
12
13
  try {
13
14
  const contents = readFileSync(envPath, "utf8");
14
15
  for (const line of contents.split("\n")) {
@@ -26,13 +27,16 @@ function readHermesApiKeyFromEnvFile() {
26
27
  return undefined;
27
28
  }
28
29
  export function resolveHermesApiConfig(options = {}) {
30
+ const ctx = resolveProfileContext(options.profile);
29
31
  return {
30
- apiUrl: options.apiUrl?.trim() || process.env.HERMES_API_URL?.trim() || DEFAULT_HERMES_API_URL,
32
+ apiUrl: options.apiUrl?.trim() || ctx.apiUrl,
31
33
  apiKey: options.apiKey?.trim() ||
34
+ ctx.apiKey ||
32
35
  process.env.HERMES_API_KEY?.trim() ||
33
36
  process.env.API_SERVER_KEY?.trim() ||
34
- readHermesApiKeyFromEnvFile(),
37
+ readHermesApiKeyFromEnvFile(ctx.home),
35
38
  model: options.model?.trim() || process.env.HERMES_MODEL?.trim() || "hermes-agent",
39
+ home: ctx.home,
36
40
  };
37
41
  }
38
42
  async function ensureHermesReachable(apiUrl, apiKey) {
@@ -77,10 +81,10 @@ function buildHermesUserContent(text, attachments) {
77
81
  parts.push(...imageParts);
78
82
  return parts;
79
83
  }
80
- async function uploadMediaAttachments(agentId, refs) {
84
+ async function uploadMediaAttachments(agentId, refs, home) {
81
85
  const attachments = [];
82
86
  for (const ref of refs) {
83
- const resolved = await resolveMediaReferenceBytes(ref);
87
+ const resolved = await resolveMediaReferenceBytes(ref, home);
84
88
  if (!resolved)
85
89
  continue;
86
90
  try {
@@ -105,10 +109,10 @@ async function uploadMediaAttachments(agentId, refs) {
105
109
  }
106
110
  return attachments;
107
111
  }
108
- async function linkTurnToConvex(meta, sessionId) {
109
- if (!hermesStateDbExists())
112
+ async function linkTurnToConvex(meta, sessionId, home) {
113
+ if (!hermesStateDbExists(home))
110
114
  return;
111
- const { userMessageId, assistantMessageId } = getLatestTurnMessageIds(sessionId);
115
+ const { userMessageId, assistantMessageId } = getLatestTurnMessageIds(sessionId, home);
112
116
  const links = [];
113
117
  if (userMessageId !== undefined) {
114
118
  links.push({
@@ -144,7 +148,10 @@ async function linkTurnToConvex(meta, sessionId) {
144
148
  }
145
149
  }
146
150
  export async function forwardToHermes(content, meta, reply, options = {}) {
147
- const { apiUrl, apiKey, model } = resolveHermesApiConfig(options);
151
+ const { apiUrl, apiKey, model, home } = resolveHermesApiConfig({
152
+ ...options,
153
+ profile: options.profile ?? meta.profile,
154
+ });
148
155
  await ensureHermesReachable(apiUrl, apiKey);
149
156
  const sessionId = options.conversationId ?? meta.conversationId;
150
157
  const headers = {
@@ -162,7 +169,7 @@ export async function forwardToHermes(content, meta, reply, options = {}) {
162
169
  user: sessionId,
163
170
  };
164
171
  const turnStartedAt = Date.now();
165
- const skillsBefore = snapshotSkills();
172
+ const skillsBefore = snapshotSkills(home);
166
173
  const response = await fetch(apiUrl, {
167
174
  method: "POST",
168
175
  headers,
@@ -183,6 +190,17 @@ export async function forwardToHermes(content, meta, reply, options = {}) {
183
190
  const counters = { textSequence: 0, activitySequence: 0 };
184
191
  const accumulator = createTurnActivityAccumulator();
185
192
  let fullText = "";
193
+ let suppressStreamDeltas = false;
194
+ const streamingReply = {
195
+ delta(text, sequence) {
196
+ if (!suppressStreamDeltas) {
197
+ reply.delta(text, sequence);
198
+ }
199
+ },
200
+ activity: (activity) => reply.activity(activity),
201
+ complete: (...args) => reply.complete(...args),
202
+ failed: (failure) => reply.failed(failure),
203
+ };
186
204
  while (true) {
187
205
  const { done, value } = await reader.read();
188
206
  if (done)
@@ -191,28 +209,34 @@ export async function forwardToHermes(content, meta, reply, options = {}) {
191
209
  const { events, rest } = parseSseDataLines(buffer);
192
210
  buffer = rest;
193
211
  for (const eventBlock of events) {
194
- processSseEventBlock(eventBlock, reply, counters, accumulator, (delta) => {
212
+ processSseEventBlock(eventBlock, streamingReply, counters, accumulator, (delta) => {
195
213
  fullText += delta;
214
+ if (!suppressStreamDeltas && looksLikeHermesStructuredStream(fullText)) {
215
+ suppressStreamDeltas = true;
216
+ }
196
217
  });
197
218
  }
198
219
  }
199
220
  if (!fullText.trim()) {
200
221
  fullText = "(Hermes returned an empty response)";
201
- reply.delta(fullText, counters.textSequence);
202
- counters.textSequence += 1;
222
+ if (!suppressStreamDeltas) {
223
+ reply.delta(fullText, counters.textSequence);
224
+ counters.textSequence += 1;
225
+ }
203
226
  }
204
227
  const mediaRefs = parseMediaReferences(fullText);
205
- const attachments = mediaRefs.length > 0 ? await uploadMediaAttachments(meta.agentId, mediaRefs) : [];
206
- const displayText = attachments.length > 0 ? stripMediaReferences(fullText, mediaRefs) : fullText.trim() || fullText;
207
- const { assistantMessageId } = getLatestTurnMessageIds(resolvedSessionId);
208
- const replyModel = resolveReplyModel(modelFromHeader, resolvedSessionId, model);
228
+ const attachments = mediaRefs.length > 0 ? await uploadMediaAttachments(meta.agentId, mediaRefs, home) : [];
229
+ const rawDisplayText = attachments.length > 0 ? stripMediaReferences(fullText, mediaRefs) : fullText.trim() || fullText;
230
+ const displayText = unwrapHermesStructuredContent(rawDisplayText);
231
+ const { assistantMessageId } = getLatestTurnMessageIds(resolvedSessionId, home);
232
+ const replyModel = resolveReplyModel(modelFromHeader, resolvedSessionId, model, home);
209
233
  const turnActivity = buildTurnActivity(accumulator, replyModel);
210
- const skillsLearned = diffSkillsLearned(skillsBefore, snapshotSkills(), { turnStartedAt });
234
+ const skillsLearned = diffSkillsLearned(skillsBefore, snapshotSkills(home), { turnStartedAt });
211
235
  if (skillsLearned.length > 0) {
212
236
  turnActivity.skillsLearned = skillsLearned;
213
237
  }
214
238
  reply.complete(displayText, counters.textSequence, attachments.length > 0 ? attachments : undefined, assistantMessageId !== undefined ? String(assistantMessageId) : undefined, turnActivity);
215
- await linkTurnToConvex(meta, resolvedSessionId);
239
+ await linkTurnToConvex(meta, resolvedSessionId, home);
216
240
  return { sessionId: resolvedSessionId };
217
241
  }
218
242
  /**
@@ -221,12 +245,12 @@ export async function forwardToHermes(content, meta, reply, options = {}) {
221
245
  * 2. The session's recorded model in Hermes `state.db`.
222
246
  * 3. The model from the outbound request (skipping the generic placeholder alias).
223
247
  */
224
- function resolveReplyModel(modelFromHeader, resolvedSessionId, requestModel) {
248
+ function resolveReplyModel(modelFromHeader, resolvedSessionId, requestModel, home) {
225
249
  if (modelFromHeader)
226
250
  return modelFromHeader;
227
- if (hermesStateDbExists()) {
251
+ if (hermesStateDbExists(home)) {
228
252
  try {
229
- const usage = getSessionUsage(resolvedSessionId);
253
+ const usage = getSessionUsage(resolvedSessionId, home);
230
254
  if (usage.model)
231
255
  return usage.model;
232
256
  }
@@ -241,6 +265,7 @@ export function createHermesMessageHandler(options = {}) {
241
265
  await forwardToHermes(content, meta, reply, {
242
266
  ...options,
243
267
  conversationId: meta.conversationId,
268
+ profile: options.profile ?? meta.profile,
244
269
  });
245
270
  };
246
271
  }
@@ -5,14 +5,15 @@ export type HermesSessionMessage = {
5
5
  content: string;
6
6
  timestamp: number;
7
7
  };
8
- export declare function resolveSessionTitle(sessionId: string): string | null;
9
- export declare function resolveSessionTitles(sessionIds: string[]): Record<string, string | null>;
8
+ export declare function resolveSessionTitle(sessionId: string, home?: string): string | null;
9
+ export declare function resolveSessionTitles(sessionIds: string[], home?: string): Record<string, string | null>;
10
10
  export declare function listSessionMessages(sessionId: string, options?: {
11
11
  limit?: number;
12
12
  offset?: number;
13
13
  offsetFromEnd?: number;
14
+ home?: string;
14
15
  }): HermesSessionMessage[];
15
- export declare function getLatestTurnMessageIds(sessionId: string): {
16
+ export declare function getLatestTurnMessageIds(sessionId: string, home?: string): {
16
17
  userMessageId?: number;
17
18
  assistantMessageId?: number;
18
19
  };
@@ -28,6 +29,7 @@ export type HermesSessionListEntry = {
28
29
  export declare function isAutomatedHermesSessionPrompt(content: string): boolean;
29
30
  export declare function listHermesSessions(options?: {
30
31
  limit?: number;
32
+ home?: string;
31
33
  }): HermesSessionListEntry[];
32
34
  export type HermesSessionUsage = {
33
35
  sessionId: string;
@@ -41,9 +43,11 @@ export type HermesSessionUsage = {
41
43
  estimatedCostUsd: number | null;
42
44
  messageCount: number;
43
45
  };
44
- export declare function getSessionUsage(sessionId: string): HermesSessionUsage;
45
- export declare function hermesStateDbExists(): boolean;
46
- export declare function countUserMessagesSent(): {
46
+ export declare function getSessionUsage(sessionId: string, home?: string): HermesSessionUsage;
47
+ export declare function hermesStateDbExists(home?: string): boolean;
48
+ export declare function countUserMessagesSent(home?: string): {
47
49
  count: number;
48
50
  };
51
+ /** Total number of sessions in a profile's state.db (best-effort). */
52
+ export declare function countSessions(home?: string): number;
49
53
  //# sourceMappingURL=hermesSessionDb.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hermesSessionDb.d.ts","sourceRoot":"","sources":["../src/hermesSessionDb.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAyIF,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAapE;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAuBxF;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACxE,oBAAoB,EAAE,CAwCxB;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAChB;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,CAmCzD;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAMF,mFAAmF;AACnF,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAqBvE;AAcD,wBAAgB,kBAAkB,CAAC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,sBAAsB,EAAE,CAsE7F;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAiBF,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,CAkErE;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAO7C;AAED,wBAAgB,qBAAqB,IAAI;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAgBzD"}
1
+ {"version":3,"file":"hermesSessionDb.d.ts","sourceRoot":"","sources":["../src/hermesSessionDb.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAgJF,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAanF;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAuBvG;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GACvF,oBAAoB,EAAE,CAwCxB;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,GACZ;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,CAmCzD;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAMF,mFAAmF;AACnF,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAqBvE;AAcD,wBAAgB,kBAAkB,CAAC,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,sBAAsB,EAAE,CAsE5G;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAiBF,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAkEpF;AAED,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAO1D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAgBtE;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAgBnD"}