@saleso.innovations/bridge 0.1.42 → 0.1.44
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 +64 -29
- 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 +27 -20
- package/dist/hermesSessionDb.d.ts +10 -6
- package/dist/hermesSessionDb.d.ts.map +1 -1
- package/dist/hermesSessionDb.js +44 -24
- 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/models.d.ts +19 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +37 -0
- package/dist/profiles.d.ts +70 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +442 -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 +1 -1
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 = {
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoC,KAAK,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAYhG,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACrG,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,qBAAqB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoC,KAAK,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAYhG,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACrG,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEpE,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,cAAc,GAAG,gBAAgB,CAAC;IAChD,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,iGAAiG;AACjG,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjG,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9E,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,QAAQ,EAAE,CAAC,QAAQ,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACnD,QAAQ,EAAE,CACR,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,qBAAqB,EAAE,EACrC,wBAAwB,CAAC,EAAE,MAAM,EACjC,YAAY,CAAC,EAAE,iBAAiB,KAC7B,IAAI,CAAC;IACV,MAAM,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE/D;AAaD,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/E,CAAC;AAiYF,wBAAsB,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,eAAe,CAAC,GAAG,OAAO,CAAC;IAC5F,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC,CA2BD;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAcxF;AAED,wBAAsB,oBAAoB,CAAC,OAAO,GAAE;IAClD,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,CAAC;CAC5C,GAAG,OAAO,CAAC,aAAa,CAAC,CAc9B"}
|
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);
|
package/dist/constants.d.ts
CHANGED
|
@@ -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";
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -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,
|
|
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";
|
package/dist/cronList.d.ts
CHANGED
package/dist/cronList.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cronList.d.ts","sourceRoot":"","sources":["../src/cronList.ts"],"names":[],"mappings":"
|
|
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
|
-
|
|
27
|
+
function readJobsFromFile(home) {
|
|
28
|
+
const jobsFile = hermesCronJobsFile(home);
|
|
29
|
+
if (!existsSync(jobsFile)) {
|
|
27
30
|
return { jobs: [] };
|
|
28
31
|
}
|
|
29
|
-
const raw = readFileSync(
|
|
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
|
|
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
|
}
|
package/dist/cronWatcher.d.ts
CHANGED
|
@@ -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(
|
|
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;
|
|
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"}
|
package/dist/cronWatcher.js
CHANGED
|
@@ -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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
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
|
|
63
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
111
|
+
if (!existsSync(jobsFile))
|
|
79
112
|
return names;
|
|
80
113
|
try {
|
|
81
|
-
const parsed = JSON.parse(readFileSync(
|
|
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
|
|
142
|
-
|
|
143
|
-
const
|
|
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
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ensureHermesApi.d.ts","sourceRoot":"","sources":["../src/ensureHermesApi.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/ensureHermesApi.js
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
32
|
-
const contents = await readFile(
|
|
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
|
-
|
|
65
|
-
const
|
|
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(
|
|
85
|
+
await writeFile(envPath, body.endsWith("\n") ? body : `${body}\n`, "utf8");
|
|
82
86
|
}
|
|
83
|
-
return { envPath
|
|
87
|
+
return { envPath, changed, apiKey };
|
|
84
88
|
}
|
|
85
89
|
export async function prepareHermesForBridge() {
|
|
86
90
|
const { envPath, changed } = await ensureHermesApiConfigured();
|
package/dist/gatewayControl.d.ts
CHANGED
|
@@ -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":"
|
|
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"}
|
package/dist/gatewayControl.js
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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.");
|
package/dist/hermesCommands.d.ts
CHANGED
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"hermesCommands.d.ts","sourceRoot":"","sources":["../src/hermesCommands.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAuC,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAehG,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,CA4RlB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAetG"}
|