@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
package/dist/client.d.ts CHANGED
@@ -21,6 +21,7 @@ export type UserMessageMeta = {
21
21
  clientMessageId: string;
22
22
  replyMessageId: string;
23
23
  attachments?: UserMessageAttachment[];
24
+ profile?: string;
24
25
  };
25
26
  export type AgentActivityKind = "tool" | "skill" | "memory" | "mcp";
26
27
  export type AgentActivityPayload = {
@@ -82,6 +83,7 @@ export type CronDeliveryMeta = {
82
83
  jobName: string;
83
84
  sourceKey: string;
84
85
  runAt?: number;
86
+ profile?: string;
85
87
  };
86
88
  export declare function cronDeliveryMessageId(sourceKey: string): string;
87
89
  export type ConnectResult = {
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -56,6 +56,7 @@ function sendCronResult(ws, agentId, messageId, content, meta) {
56
56
  jobName: meta.jobName,
57
57
  sourceKey: meta.sourceKey,
58
58
  runAt: meta.runAt,
59
+ ...(meta.profile ? { profile: meta.profile } : {}),
59
60
  },
60
61
  },
61
62
  }));
@@ -246,6 +247,9 @@ async function openAgentConnection(options) {
246
247
  rememberConversationId(conversationId);
247
248
  }
248
249
  const attachments = parseUserMessageAttachments(envelope.attachments);
250
+ const profile = typeof envelope.profile === "string" && envelope.profile.trim().length > 0
251
+ ? envelope.profile.trim()
252
+ : undefined;
249
253
  const clientMessageId = typeof envelope.clientMessageId === "string" && envelope.clientMessageId.trim().length > 0
250
254
  ? envelope.clientMessageId.trim()
251
255
  : randomUUID();
@@ -253,7 +257,7 @@ async function openAgentConnection(options) {
253
257
  const reply = createReplySender(ws, agentId, conversationId, replyMessageId);
254
258
  if (options.onUserMessage) {
255
259
  try {
256
- await options.onUserMessage(content, { agentId, conversationId, clientMessageId, replyMessageId, attachments }, reply);
260
+ await options.onUserMessage(content, { agentId, conversationId, clientMessageId, replyMessageId, attachments, profile }, reply);
257
261
  }
258
262
  catch (error) {
259
263
  const { message, code } = userSafeHermesError(error);
@@ -10,6 +10,8 @@ export declare const HERMES_SESSION_TITLES_CAPABILITY = "hermes.commands.session
10
10
  export declare const HERMES_SESSIONS_LIST_CAPABILITY = "hermes.commands.sessions.list.v1";
11
11
  /** Remote shell command execution over relay. */
12
12
  export declare const TERMINAL_SHELL_CAPABILITY = "terminal.shell.v1";
13
+ /** Bridge can list/create/rename/delete Hermes profiles and route per-profile. */
14
+ export declare const HERMES_PROFILES_CAPABILITY = "hermes.commands.profiles.v1";
13
15
  export declare const DEFAULT_BRIDGE_CAPABILITIES: string[];
14
16
  /** VPS one-line installer (served from public Convex HTTP). */
15
17
  export declare const DEFAULT_BRIDGE_INSTALL_URL = "https://amicable-elephant-407.convex.site/install-bridge.sh";
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,eAAO,MAAM,6BAA6B,8CAA8C,CAAC;AAEzF,6FAA6F;AAC7F,eAAO,MAAM,sBAAsB,8CAA8C,CAAC;AAElF,4DAA4D;AAC5D,eAAO,MAAM,0BAA0B,uBAAuB,CAAC;AAE/D,gFAAgF;AAChF,eAAO,MAAM,gCAAgC,uCAAuC,CAAC;AAErF,iGAAiG;AACjG,eAAO,MAAM,+BAA+B,qCAAqC,CAAC;AAElF,iDAAiD;AACjD,eAAO,MAAM,yBAAyB,sBAAsB,CAAC;AAE7D,eAAO,MAAM,2BAA2B,UAMvC,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,0BAA0B,gEACwB,CAAC;AAEhE,6DAA6D;AAC7D,eAAO,MAAM,yBAAyB,+DACwB,CAAC;AAE/D,uGAAuG;AACvG,eAAO,MAAM,mBAAmB,gCAAgC,CAAC;AAEjE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,eAAO,MAAM,6BAA6B,8CAA8C,CAAC;AAEzF,6FAA6F;AAC7F,eAAO,MAAM,sBAAsB,8CAA8C,CAAC;AAElF,4DAA4D;AAC5D,eAAO,MAAM,0BAA0B,uBAAuB,CAAC;AAE/D,gFAAgF;AAChF,eAAO,MAAM,gCAAgC,uCAAuC,CAAC;AAErF,iGAAiG;AACjG,eAAO,MAAM,+BAA+B,qCAAqC,CAAC;AAElF,iDAAiD;AACjD,eAAO,MAAM,yBAAyB,sBAAsB,CAAC;AAE7D,kFAAkF;AAClF,eAAO,MAAM,0BAA0B,gCAAgC,CAAC;AAExE,eAAO,MAAM,2BAA2B,UAOvC,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,0BAA0B,gEACwB,CAAC;AAEhE,6DAA6D;AAC7D,eAAO,MAAM,yBAAyB,+DACwB,CAAC;AAE/D,uGAAuG;AACvG,eAAO,MAAM,mBAAmB,gCAAgC,CAAC;AAEjE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
package/dist/constants.js CHANGED
@@ -10,12 +10,15 @@ export const HERMES_SESSION_TITLES_CAPABILITY = "hermes.commands.sessions.titles
10
10
  export const HERMES_SESSIONS_LIST_CAPABILITY = "hermes.commands.sessions.list.v1";
11
11
  /** Remote shell command execution over relay. */
12
12
  export const TERMINAL_SHELL_CAPABILITY = "terminal.shell.v1";
13
+ /** Bridge can list/create/rename/delete Hermes profiles and route per-profile. */
14
+ export const HERMES_PROFILES_CAPABILITY = "hermes.commands.profiles.v1";
13
15
  export const DEFAULT_BRIDGE_CAPABILITIES = [
14
16
  "chat",
15
17
  HERMES_COMMANDS_CAPABILITY,
16
18
  HERMES_SESSION_TITLES_CAPABILITY,
17
19
  HERMES_SESSIONS_LIST_CAPABILITY,
18
20
  TERMINAL_SHELL_CAPABILITY,
21
+ HERMES_PROFILES_CAPABILITY,
19
22
  ];
20
23
  /** VPS one-line installer (served from public Convex HTTP). */
21
24
  export const DEFAULT_BRIDGE_INSTALL_URL = "https://amicable-elephant-407.convex.site/install-bridge.sh";
@@ -1,5 +1,7 @@
1
1
  export type ListHermesCronJobsOptions = {
2
2
  all?: boolean;
3
+ home?: string;
4
+ env?: NodeJS.ProcessEnv;
3
5
  };
4
6
  export declare function listHermesCronJobs(options?: ListHermesCronJobsOptions): Promise<unknown>;
5
7
  //# sourceMappingURL=cronList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cronList.d.ts","sourceRoot":"","sources":["../src/cronList.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,yBAAyB,GAAG;IACtC,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AA6CF,wBAAsB,kBAAkB,CACtC,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,OAAO,CAAC,CAelB"}
1
+ {"version":3,"file":"cronList.d.ts","sourceRoot":"","sources":["../src/cronList.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,yBAAyB,GAAG;IACtC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,CAAC;AA8CF,wBAAsB,kBAAkB,CACtC,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,OAAO,CAAC,CAelB"}
package/dist/cronList.js CHANGED
@@ -4,9 +4,11 @@ import { homedir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { promisify } from "node:util";
6
6
  const execFileAsync = promisify(execFile);
7
- const HERMES_CRON_JOBS_FILE = join(homedir(), ".hermes", "cron", "jobs.json");
8
7
  const LIST_TIMEOUT_MS = 30_000;
9
8
  const MAX_OUTPUT_BYTES = 10 * 1024 * 1024;
9
+ function hermesCronJobsFile(home) {
10
+ return join(home?.trim() || join(homedir(), ".hermes"), "cron", "jobs.json");
11
+ }
10
12
  function normalizeJobsPayload(value) {
11
13
  if (Array.isArray(value)) {
12
14
  return { jobs: value };
@@ -22,14 +24,15 @@ function normalizeJobsPayload(value) {
22
24
  }
23
25
  return { jobs: [] };
24
26
  }
25
- function readJobsFromFile() {
26
- if (!existsSync(HERMES_CRON_JOBS_FILE)) {
27
+ function readJobsFromFile(home) {
28
+ const jobsFile = hermesCronJobsFile(home);
29
+ if (!existsSync(jobsFile)) {
27
30
  return { jobs: [] };
28
31
  }
29
- const raw = readFileSync(HERMES_CRON_JOBS_FILE, "utf8");
32
+ const raw = readFileSync(jobsFile, "utf8");
30
33
  return normalizeJobsPayload(JSON.parse(raw));
31
34
  }
32
- async function runHermesCronListJson(all) {
35
+ async function runHermesCronListJson(all, env) {
33
36
  const args = ["cron", "list"];
34
37
  if (all)
35
38
  args.push("--all");
@@ -38,7 +41,7 @@ async function runHermesCronListJson(all) {
38
41
  const { stdout } = await execFileAsync("hermes", args, {
39
42
  timeout: LIST_TIMEOUT_MS,
40
43
  maxBuffer: MAX_OUTPUT_BYTES,
41
- env: process.env,
44
+ env,
42
45
  });
43
46
  const trimmed = stdout.trim();
44
47
  if (!trimmed)
@@ -51,12 +54,12 @@ async function runHermesCronListJson(all) {
51
54
  }
52
55
  export async function listHermesCronJobs(options = {}) {
53
56
  const includeAll = options.all === true;
54
- const jsonResult = await runHermesCronListJson(includeAll);
57
+ const jsonResult = await runHermesCronListJson(includeAll, options.env ?? process.env);
55
58
  if (jsonResult != null) {
56
59
  return jsonResult;
57
60
  }
58
61
  if (includeAll) {
59
- return readJobsFromFile();
62
+ return readJobsFromFile(options.home);
60
63
  }
61
64
  throw new Error("Could not list Hermes cron jobs. Ensure `hermes` is installed and supports `hermes cron list --json`.");
62
65
  }
@@ -13,7 +13,7 @@ type CronWatcherOptions = {
13
13
  export declare function readDeliveredIndex(): Set<string>;
14
14
  export declare function writeDeliveredIndex(delivered: Set<string>): void;
15
15
  export declare function clearDeliveredIndex(): number;
16
- export declare function listCronOutputFiles(rootDir?: string): string[];
16
+ export declare function listCronOutputFiles(): string[];
17
17
  export declare function relativeOutputKey(filePath: string): string;
18
18
  export declare function listPendingCronFiles(delivered?: Set<string>): string[];
19
19
  export declare function startCronWatcher(options: CronWatcherOptions): () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"cronWatcher.d.ts","sourceRoot":"","sources":["../src/cronWatcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,eAAO,MAAM,sBAAsB,QAA+C,CAAC;AAEnF,eAAO,MAAM,oBAAoB,QAAmD,CAAC;AA6BrF,KAAK,kBAAkB,GAAG;IACxB,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACnF,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,wBAAgB,kBAAkB,IAAI,GAAG,CAAC,MAAM,CAAC,CAQhD;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAGhE;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAI5C;AAED,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,MAA+B,GAAG,MAAM,EAAE,CAoBtF;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,oBAAoB,CAAC,SAAS,GAAE,GAAG,CAAC,MAAM,CAAwB,GAAG,MAAM,EAAE,CAE5F;AA8KD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,IAAI,CA4BxE;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC;IAC1F,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC,CAmBD"}
1
+ {"version":3,"file":"cronWatcher.d.ts","sourceRoot":"","sources":["../src/cronWatcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKjD,eAAO,MAAM,sBAAsB,QAA+C,CAAC;AACnF,eAAO,MAAM,oBAAoB,QAAmD,CAAC;AAkDrF,KAAK,kBAAkB,GAAG;IACxB,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACnF,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,wBAAgB,kBAAkB,IAAI,GAAG,CAAC,MAAM,CAAC,CAQhD;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAGhE;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAI5C;AAmCD,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAS1D;AAED,wBAAgB,oBAAoB,CAAC,SAAS,GAAE,GAAG,CAAC,MAAM,CAAwB,GAAG,MAAM,EAAE,CAI5F;AAqLD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,IAAI,CA4BxE;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC;IAC1F,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC,CAmBD"}
@@ -3,9 +3,19 @@ import { homedir } from "node:os";
3
3
  import { dirname, join, relative } from "node:path";
4
4
  import { resolveActiveConversationId } from "./activeConversation.js";
5
5
  import { loadCredentials } from "./credentials.js";
6
+ import { DEFAULT_PROFILE, listProfileHomes } from "./profiles.js";
6
7
  export const HERMES_CRON_OUTPUT_DIR = join(homedir(), ".hermes", "cron", "output");
7
- const HERMES_CRON_JOBS_FILE = join(homedir(), ".hermes", "cron", "jobs.json");
8
8
  export const DELIVERED_INDEX_PATH = join(homedir(), ".cleos", "cron-delivered.json");
9
+ function cronOutputDir(home) {
10
+ return join(home, "cron", "output");
11
+ }
12
+ function cronJobsFile(home) {
13
+ return join(home, "cron", "jobs.json");
14
+ }
15
+ /** Delivered-index key, namespaced by profile (default profile keeps legacy unprefixed keys). */
16
+ function deliveredKeyFor(profile, relativePath) {
17
+ return profile === DEFAULT_PROFILE ? relativePath : `@${profile}/${relativePath}`;
18
+ }
9
19
  const POLL_INTERVAL_MS = 5_000;
10
20
  const FILE_SETTLE_MS = 750;
11
21
  // Keep in sync with isSilentHermesCronOutput in @repo/backend-types.
@@ -44,41 +54,64 @@ export function clearDeliveredIndex() {
44
54
  writeDeliveredIndex(new Set());
45
55
  return previous;
46
56
  }
47
- export function listCronOutputFiles(rootDir = HERMES_CRON_OUTPUT_DIR) {
48
- if (!existsSync(rootDir))
49
- return [];
50
- const files = [];
51
- for (const jobId of readdirSync(rootDir)) {
52
- const jobDir = join(rootDir, jobId);
53
- let stat;
54
- try {
55
- stat = statSync(jobDir);
56
- }
57
- catch {
58
- continue;
59
- }
60
- if (!stat.isDirectory())
57
+ /** Enumerate cron output files across every profile (default + on-disk profiles). */
58
+ function listCronOutputEntries() {
59
+ const entries = [];
60
+ for (const { profile, home } of listProfileHomes()) {
61
+ const rootDir = cronOutputDir(home);
62
+ if (!existsSync(rootDir))
61
63
  continue;
62
- for (const fileName of readdirSync(jobDir)) {
63
- if (!fileName.endsWith(".md"))
64
+ for (const jobId of readdirSync(rootDir)) {
65
+ const jobDir = join(rootDir, jobId);
66
+ let stat;
67
+ try {
68
+ stat = statSync(jobDir);
69
+ }
70
+ catch {
71
+ continue;
72
+ }
73
+ if (!stat.isDirectory())
64
74
  continue;
65
- files.push(join(jobDir, fileName));
75
+ for (const fileName of readdirSync(jobDir)) {
76
+ if (!fileName.endsWith(".md"))
77
+ continue;
78
+ const filePath = join(jobDir, fileName);
79
+ entries.push({
80
+ filePath,
81
+ profile,
82
+ jobId,
83
+ key: deliveredKeyFor(profile, `${jobId}/${fileName}`),
84
+ jobsFile: cronJobsFile(home),
85
+ });
86
+ }
66
87
  }
67
88
  }
68
- return files.sort();
89
+ return entries.sort((left, right) => left.key.localeCompare(right.key));
90
+ }
91
+ export function listCronOutputFiles() {
92
+ return listCronOutputEntries().map((entry) => entry.filePath);
69
93
  }
70
94
  export function relativeOutputKey(filePath) {
95
+ const normalized = filePath.replace(/\\/g, "/");
96
+ for (const { profile, home } of listProfileHomes()) {
97
+ const dir = cronOutputDir(home).replace(/\\/g, "/");
98
+ if (normalized.startsWith(`${dir}/`)) {
99
+ return deliveredKeyFor(profile, normalized.slice(dir.length + 1));
100
+ }
101
+ }
71
102
  return relative(HERMES_CRON_OUTPUT_DIR, filePath).replace(/\\/g, "/");
72
103
  }
73
104
  export function listPendingCronFiles(delivered = readDeliveredIndex()) {
74
- return listCronOutputFiles().filter((filePath) => !delivered.has(relativeOutputKey(filePath)));
105
+ return listCronOutputEntries()
106
+ .filter((entry) => !delivered.has(entry.key))
107
+ .map((entry) => entry.filePath);
75
108
  }
76
- function loadHermesCronJobs() {
109
+ function loadHermesCronJobs(jobsFile) {
77
110
  const names = new Map();
78
- if (!existsSync(HERMES_CRON_JOBS_FILE))
111
+ if (!existsSync(jobsFile))
79
112
  return names;
80
113
  try {
81
- const parsed = JSON.parse(readFileSync(HERMES_CRON_JOBS_FILE, "utf8"));
114
+ const parsed = JSON.parse(readFileSync(jobsFile, "utf8"));
82
115
  const jobs = Array.isArray(parsed)
83
116
  ? parsed
84
117
  : parsed && typeof parsed === "object" && Array.isArray(parsed.jobs)
@@ -138,14 +171,20 @@ function isRelayNotOpenError(error) {
138
171
  return error instanceof Error && error.message === "Cleos relay connection is not open";
139
172
  }
140
173
  async function deliverPendingFiles(session, delivered, conversationRef, options) {
141
- const jobNames = loadHermesCronJobs();
142
- for (const filePath of listCronOutputFiles()) {
143
- const key = relativeOutputKey(filePath);
174
+ const jobNamesByFile = new Map();
175
+ const jobNamesFor = (jobsFile) => {
176
+ const cached = jobNamesByFile.get(jobsFile);
177
+ if (cached)
178
+ return cached;
179
+ const names = loadHermesCronJobs(jobsFile);
180
+ jobNamesByFile.set(jobsFile, names);
181
+ return names;
182
+ };
183
+ for (const entry of listCronOutputEntries()) {
184
+ const { filePath, key, jobId, profile } = entry;
144
185
  if (delivered.has(key))
145
186
  continue;
146
- const parts = key.split("/");
147
- const jobId = parts[0] ?? "unknown";
148
- const jobName = jobNames.get(jobId) ?? jobId;
187
+ const jobName = jobNamesFor(entry.jobsFile).get(jobId) ?? jobId;
149
188
  const content = await readFileWhenStable(filePath);
150
189
  if (!content) {
151
190
  delivered.add(key);
@@ -159,6 +198,7 @@ async function deliverPendingFiles(session, delivered, conversationRef, options)
159
198
  event: "cleos-bridge.cron-skipped-silent",
160
199
  jobId,
161
200
  jobName,
201
+ profile,
162
202
  file: key,
163
203
  }));
164
204
  continue;
@@ -173,6 +213,7 @@ async function deliverPendingFiles(session, delivered, conversationRef, options)
173
213
  jobName,
174
214
  sourceKey: key,
175
215
  runAt: parseRunAtFromFileName(filePath),
216
+ profile,
176
217
  });
177
218
  deliveredSuccessfully = true;
178
219
  break;
@@ -1,4 +1,4 @@
1
- export declare function ensureHermesApiConfigured(): Promise<{
1
+ export declare function ensureHermesApiConfigured(profile?: string): Promise<{
2
2
  envPath: string;
3
3
  changed: boolean;
4
4
  apiKey: string;
@@ -1 +1 @@
1
- {"version":3,"file":"ensureHermesApi.d.ts","sourceRoot":"","sources":["../src/ensureHermesApi.ts"],"names":[],"mappings":"AAsEA,wBAAsB,yBAAyB,IAAI,OAAO,CAAC;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CA0BD;AAED,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAsB5D"}
1
+ {"version":3,"file":"ensureHermesApi.d.ts","sourceRoot":"","sources":["../src/ensureHermesApi.ts"],"names":[],"mappings":"AAwEA,wBAAsB,yBAAyB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CA4BD;AAED,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAsB5D"}
@@ -1,8 +1,10 @@
1
1
  import { randomBytes } from "node:crypto";
2
2
  import { access, mkdir, readFile, writeFile } from "node:fs/promises";
3
- import { homedir } from "node:os";
4
3
  import { join } from "node:path";
5
- const HERMES_ENV_PATH = join(homedir(), ".hermes", ".env");
4
+ import { resolveProfileHome } from "./profiles.js";
5
+ function hermesEnvPath(home) {
6
+ return join(home, ".env");
7
+ }
6
8
  function parseEnvLine(line) {
7
9
  const trimmed = line.trim();
8
10
  if (!trimmed)
@@ -26,10 +28,10 @@ function serializeEnvLine(line) {
26
28
  function generateApiKey() {
27
29
  return randomBytes(24).toString("base64url");
28
30
  }
29
- async function readHermesEnvLines() {
31
+ async function readHermesEnvLines(envPath) {
30
32
  try {
31
- await access(HERMES_ENV_PATH);
32
- const contents = await readFile(HERMES_ENV_PATH, "utf8");
33
+ await access(envPath);
34
+ const contents = await readFile(envPath, "utf8");
33
35
  return contents.split("\n").map(parseEnvLine);
34
36
  }
35
37
  catch {
@@ -60,9 +62,11 @@ function upsertAssignment(lines, key, value) {
60
62
  }
61
63
  return next;
62
64
  }
63
- export async function ensureHermesApiConfigured() {
64
- await mkdir(join(homedir(), ".hermes"), { recursive: true });
65
- const before = await readHermesEnvLines();
65
+ export async function ensureHermesApiConfigured(profile) {
66
+ const home = resolveProfileHome(profile);
67
+ const envPath = hermesEnvPath(home);
68
+ await mkdir(home, { recursive: true });
69
+ const before = await readHermesEnvLines(envPath);
66
70
  const enabled = getAssignment(before, "API_SERVER_ENABLED");
67
71
  const existingKey = getAssignment(before, "API_SERVER_KEY");
68
72
  const apiKey = existingKey && existingKey.length >= 8 ? existingKey : generateApiKey();
@@ -78,9 +82,9 @@ export async function ensureHermesApiConfigured() {
78
82
  }
79
83
  if (changed || before.length === 0) {
80
84
  const body = lines.map(serializeEnvLine).join("\n");
81
- await writeFile(HERMES_ENV_PATH, body.endsWith("\n") ? body : `${body}\n`, "utf8");
85
+ await writeFile(envPath, body.endsWith("\n") ? body : `${body}\n`, "utf8");
82
86
  }
83
- return { envPath: HERMES_ENV_PATH, changed, apiKey };
87
+ return { envPath, changed, apiKey };
84
88
  }
85
89
  export async function prepareHermesForBridge() {
86
90
  const { envPath, changed } = await ensureHermesApiConfigured();
@@ -1,12 +1,12 @@
1
- export declare function startHermesGateway(): Promise<{
1
+ export declare function startHermesGateway(profile?: string): Promise<{
2
2
  ok: true;
3
3
  alreadyRunning: boolean;
4
4
  }>;
5
- export declare function stopHermesGateway(): Promise<{
5
+ export declare function stopHermesGateway(profile?: string): Promise<{
6
6
  ok: true;
7
7
  wasRunning: boolean;
8
8
  }>;
9
- export declare function restartHermesGateway(): Promise<{
9
+ export declare function restartHermesGateway(profile?: string): Promise<{
10
10
  ok: true;
11
11
  }>;
12
12
  //# sourceMappingURL=gatewayControl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gatewayControl.d.ts","sourceRoot":"","sources":["../src/gatewayControl.ts"],"names":[],"mappings":"AA8EA,wBAAsB,kBAAkB,IAAI,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,OAAO,CAAA;CAAE,CAAC,CAezF;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAiBpF;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,CAyBlE"}
1
+ {"version":3,"file":"gatewayControl.d.ts","sourceRoot":"","sources":["../src/gatewayControl.ts"],"names":[],"mappings":"AA6GA,wBAAsB,kBAAkB,CACtC,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,OAAO,CAAA;CAAE,CAAC,CAehD;AAED,wBAAsB,iBAAiB,CACrC,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAoB5C;AAED,wBAAsB,oBAAoB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,CA2BlF"}
@@ -1,28 +1,33 @@
1
1
  import { execFile, spawn } from "node:child_process";
2
2
  import { promisify } from "node:util";
3
- import { DEFAULT_HERMES_API_URL } from "./constants.js";
4
3
  import { ensureHermesApiConfigured } from "./ensureHermesApi.js";
4
+ import { profileEnv, resolveProfileGatewayPort, resolveProfileGatewayUrl, } from "./profiles.js";
5
5
  const execFileAsync = promisify(execFile);
6
- const HEALTH_URL = DEFAULT_HERMES_API_URL.replace(/\/v1\/chat\/completions\/?$/, "/health");
7
6
  const HEALTH_POLL_MS = 1_000;
8
7
  const HEALTH_TIMEOUT_MS = 30_000;
9
8
  const GATEWAY_UNITS = ["hermes-gateway.service", "hermes.service", "hermes-gateway", "hermes"];
10
- async function fetchHermesHealth(apiKey) {
9
+ function healthUrlForProfile(profile) {
10
+ return resolveProfileGatewayUrl(profile).replace(/\/v1\/chat\/completions\/?$/, "/health");
11
+ }
12
+ async function fetchHermesHealth(profile, apiKey) {
11
13
  const headers = {};
12
14
  if (apiKey)
13
15
  headers.authorization = `Bearer ${apiKey}`;
14
16
  try {
15
- const response = await fetch(HEALTH_URL, { headers, signal: AbortSignal.timeout(2_000) });
17
+ const response = await fetch(healthUrlForProfile(profile), {
18
+ headers,
19
+ signal: AbortSignal.timeout(2_000),
20
+ });
16
21
  return response.ok;
17
22
  }
18
23
  catch {
19
24
  return false;
20
25
  }
21
26
  }
22
- async function waitForHermesHealth(apiKey) {
27
+ async function waitForHermesHealth(profile, apiKey) {
23
28
  const deadline = Date.now() + HEALTH_TIMEOUT_MS;
24
29
  while (Date.now() < deadline) {
25
- if (await fetchHermesHealth(apiKey))
30
+ if (await fetchHermesHealth(profile, apiKey))
26
31
  return true;
27
32
  await new Promise((resolve) => setTimeout(resolve, HEALTH_POLL_MS));
28
33
  }
@@ -48,6 +53,28 @@ async function tryStopHermesGatewayUnits() {
48
53
  }
49
54
  }
50
55
  }
56
+ /** Kill whichever process is bound to the profile's gateway port (precise, per-profile). */
57
+ async function killProcessOnPort(port) {
58
+ if (!port)
59
+ return;
60
+ try {
61
+ const { stdout } = await execFileAsync("lsof", ["-ti", `tcp:${port}`], { timeout: 5_000 });
62
+ for (const pid of stdout.split(/\s+/).filter(Boolean)) {
63
+ const numeric = Number(pid);
64
+ if (Number.isFinite(numeric)) {
65
+ try {
66
+ process.kill(numeric, "SIGTERM");
67
+ }
68
+ catch {
69
+ // Process already gone.
70
+ }
71
+ }
72
+ }
73
+ }
74
+ catch {
75
+ // lsof unavailable or nothing listening.
76
+ }
77
+ }
51
78
  async function tryKillHermesGatewayProcess() {
52
79
  try {
53
80
  await execFileAsync("pkill", ["-f", "hermes gateway"], { timeout: 5_000 });
@@ -56,12 +83,13 @@ async function tryKillHermesGatewayProcess() {
56
83
  // No matching process — that's fine.
57
84
  }
58
85
  }
59
- async function spawnHermesGateway() {
86
+ async function spawnHermesGateway(profile) {
60
87
  await new Promise((resolve) => {
61
88
  try {
62
89
  const child = spawn("hermes", ["gateway"], {
63
90
  detached: true,
64
91
  stdio: "ignore",
92
+ env: profileEnv(profile),
65
93
  });
66
94
  child.on("error", () => resolve());
67
95
  child.unref();
@@ -72,47 +100,53 @@ async function spawnHermesGateway() {
72
100
  }
73
101
  });
74
102
  }
75
- export async function startHermesGateway() {
76
- const { apiKey } = await ensureHermesApiConfigured();
77
- if (await fetchHermesHealth(apiKey)) {
103
+ export async function startHermesGateway(profile) {
104
+ const { apiKey } = await ensureHermesApiConfigured(profile);
105
+ if (await fetchHermesHealth(profile, apiKey)) {
78
106
  return { ok: true, alreadyRunning: true };
79
107
  }
80
- await spawnHermesGateway();
81
- if (await waitForHermesHealth(apiKey)) {
108
+ await spawnHermesGateway(profile);
109
+ if (await waitForHermesHealth(profile, apiKey)) {
82
110
  return { ok: true, alreadyRunning: false };
83
111
  }
84
112
  throw new Error("Hermes gateway did not become healthy. Install Hermes, then run `hermes gateway` on this machine and retry.");
85
113
  }
86
- export async function stopHermesGateway() {
87
- const { apiKey } = await ensureHermesApiConfigured();
88
- const wasRunning = await fetchHermesHealth(apiKey);
114
+ export async function stopHermesGateway(profile) {
115
+ const { apiKey } = await ensureHermesApiConfigured(profile);
116
+ const wasRunning = await fetchHermesHealth(profile, apiKey);
117
+ const port = resolveProfileGatewayPort(profile);
118
+ // Prefer port-precise termination; fall back to systemd/pkill for the default profile.
119
+ await killProcessOnPort(port);
89
120
  await tryStopHermesGatewayUnits();
90
- await tryKillHermesGatewayProcess();
121
+ if (!port)
122
+ await tryKillHermesGatewayProcess();
91
123
  if (wasRunning) {
92
124
  await new Promise((resolve) => setTimeout(resolve, HEALTH_POLL_MS));
93
125
  }
94
- const stillRunning = await fetchHermesHealth(apiKey);
126
+ const stillRunning = await fetchHermesHealth(profile, apiKey);
95
127
  if (stillRunning) {
96
128
  throw new Error("Hermes gateway is still running. Stop it manually on the agent machine.");
97
129
  }
98
130
  return { ok: true, wasRunning };
99
131
  }
100
- export async function restartHermesGateway() {
101
- const { changed, apiKey } = await ensureHermesApiConfigured();
132
+ export async function restartHermesGateway(profile) {
133
+ const { changed, apiKey } = await ensureHermesApiConfigured(profile);
102
134
  if (changed) {
103
135
  await tryRestartHermesGatewayUnits();
104
- if (await waitForHermesHealth(apiKey)) {
136
+ if (await waitForHermesHealth(profile, apiKey)) {
105
137
  return { ok: true };
106
138
  }
107
139
  }
108
- if (await fetchHermesHealth(apiKey)) {
140
+ if (await fetchHermesHealth(profile, apiKey)) {
141
+ await killProcessOnPort(resolveProfileGatewayPort(profile));
109
142
  await tryRestartHermesGatewayUnits();
110
- if (await waitForHermesHealth(apiKey)) {
143
+ await spawnHermesGateway(profile);
144
+ if (await waitForHermesHealth(profile, apiKey)) {
111
145
  return { ok: true };
112
146
  }
113
147
  }
114
- await spawnHermesGateway();
115
- if (await waitForHermesHealth(apiKey)) {
148
+ await spawnHermesGateway(profile);
149
+ if (await waitForHermesHealth(profile, apiKey)) {
116
150
  return { ok: true };
117
151
  }
118
152
  throw new Error("Hermes gateway did not restart successfully. Run `hermes gateway` on this machine and retry.");
@@ -1,5 +1,5 @@
1
1
  import { type ShellDeltaEmitter } from "./shellSession.js";
2
- export declare const HERMES_COMMAND_NAMES: readonly ["runtime.health", "runtime.detailedHealth", "runtime.version", "runtime.capabilities", "models.list", "model.set", "responses.create", "runs.create", "runs.status", "runs.stop", "jobs.list", "jobs.get", "jobs.create", "jobs.update", "jobs.pause", "jobs.resume", "jobs.runNow", "jobs.delete", "profiles.list", "profiles.create", "gateway.start", "gateway.stop", "gateway.restart", "hermes.update", "bridge.version", "bridge.update", "sessions.messages.list", "sessions.messages.countSent", "sessions.titles.resolve", "sessions.rename", "sessions.usage.get", "sessions.list", "skills.list", "tools.list", "tools.set", "mcp.list", "mcp.add", "mcp.remove", "files.list", "files.read", "files.write", "files.delete", "memories.list", "shell.exec", "shell.session.reset"];
2
+ export declare const HERMES_COMMAND_NAMES: readonly ["runtime.health", "runtime.detailedHealth", "runtime.version", "runtime.capabilities", "models.list", "model.set", "responses.create", "runs.create", "runs.status", "runs.stop", "jobs.list", "jobs.get", "jobs.create", "jobs.update", "jobs.pause", "jobs.resume", "jobs.runNow", "jobs.delete", "profiles.list", "profiles.create", "profiles.rename", "profiles.delete", "gateway.start", "gateway.stop", "gateway.restart", "hermes.update", "bridge.version", "bridge.update", "sessions.messages.list", "sessions.messages.countSent", "sessions.titles.resolve", "sessions.rename", "sessions.usage.get", "sessions.list", "skills.list", "tools.list", "tools.set", "mcp.list", "mcp.add", "mcp.remove", "files.list", "files.read", "files.write", "files.delete", "memories.list", "shell.exec", "shell.session.reset"];
3
3
  export type HermesCommandName = (typeof HERMES_COMMAND_NAMES)[number];
4
4
  export declare function isHermesCommandName(value: string): value is HermesCommandName;
5
5
  export type HermesCommandErrorCode = "command_unsupported" | "hermes_unreachable" | "hermes_request_failed" | "invalid_command_args" | "unsupported_by_http";
@@ -1 +1 @@
1
- {"version":3,"file":"hermesCommands.d.ts","sourceRoot":"","sources":["../src/hermesCommands.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAuC,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAMhG,eAAO,MAAM,oBAAoB,ywBA8CvB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,iBAAiB,CAE7E;AAED,MAAM,MAAM,sBAAsB,GAC9B,qBAAqB,GACrB,oBAAoB,GACpB,uBAAuB,GACvB,sBAAsB,GACtB,qBAAqB,CAAC;AAE1B,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;gBAE1B,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM;CAI1D;AAkID,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,iBAAiB,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,iBAAiB,CAAA;CAAO,GAC9F,OAAO,CAAC,OAAO,CAAC,CAuQlB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAetG"}
1
+ {"version":3,"file":"hermesCommands.d.ts","sourceRoot":"","sources":["../src/hermesCommands.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAuC,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAchG,eAAO,MAAM,oBAAoB,+yBAgDvB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,iBAAiB,CAE7E;AAED,MAAM,MAAM,sBAAsB,GAC9B,qBAAqB,GACrB,oBAAoB,GACpB,uBAAuB,GACvB,sBAAsB,GACtB,qBAAqB,CAAC;AAE1B,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;gBAE1B,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM;CAI1D;AAkID,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,iBAAiB,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,iBAAiB,CAAA;CAAO,GAC9F,OAAO,CAAC,OAAO,CAAC,CAgRlB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAetG"}