jinn-cli 0.1.1 → 0.2.0
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/bin/jimmy.js +1 -1
- package/dist/src/connectors/cron/index.d.ts +21 -0
- package/dist/src/connectors/cron/index.d.ts.map +1 -0
- package/dist/src/connectors/cron/index.js +75 -0
- package/dist/src/connectors/cron/index.js.map +1 -0
- package/dist/src/connectors/slack/index.d.ts +13 -5
- package/dist/src/connectors/slack/index.d.ts.map +1 -1
- package/dist/src/connectors/slack/index.js +80 -3
- package/dist/src/connectors/slack/index.js.map +1 -1
- package/dist/src/connectors/slack/threads.d.ts +14 -1
- package/dist/src/connectors/slack/threads.d.ts.map +1 -1
- package/dist/src/connectors/slack/threads.js +23 -2
- package/dist/src/connectors/slack/threads.js.map +1 -1
- package/dist/src/connectors/slack/threads.test.d.ts +2 -0
- package/dist/src/connectors/slack/threads.test.d.ts.map +1 -0
- package/dist/src/connectors/slack/threads.test.js +45 -0
- package/dist/src/connectors/slack/threads.test.js.map +1 -0
- package/dist/src/cron/runner.d.ts +3 -2
- package/dist/src/cron/runner.d.ts.map +1 -1
- package/dist/src/cron/runner.js +48 -89
- package/dist/src/cron/runner.js.map +1 -1
- package/dist/src/cron/scheduler.d.ts +5 -2
- package/dist/src/cron/scheduler.d.ts.map +1 -1
- package/dist/src/cron/scheduler.js +29 -4
- package/dist/src/cron/scheduler.js.map +1 -1
- package/dist/src/engines/claude.js +1 -1
- package/dist/src/engines/claude.js.map +1 -1
- package/dist/src/gateway/api.d.ts.map +1 -1
- package/dist/src/gateway/api.js +58 -26
- package/dist/src/gateway/api.js.map +1 -1
- package/dist/src/gateway/server.d.ts.map +1 -1
- package/dist/src/gateway/server.js +5 -3
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/sessions/manager.d.ts +12 -25
- package/dist/src/sessions/manager.d.ts.map +1 -1
- package/dist/src/sessions/manager.js +171 -96
- package/dist/src/sessions/manager.js.map +1 -1
- package/dist/src/sessions/queue.d.ts +5 -0
- package/dist/src/sessions/queue.d.ts.map +1 -1
- package/dist/src/sessions/queue.js +26 -0
- package/dist/src/sessions/queue.js.map +1 -1
- package/dist/src/sessions/queue.test.d.ts +2 -0
- package/dist/src/sessions/queue.test.d.ts.map +1 -0
- package/dist/src/sessions/queue.test.js +28 -0
- package/dist/src/sessions/queue.test.js.map +1 -0
- package/dist/src/sessions/registry.d.ts +12 -1
- package/dist/src/sessions/registry.d.ts.map +1 -1
- package/dist/src/sessions/registry.js +89 -11
- package/dist/src/sessions/registry.js.map +1 -1
- package/dist/src/sessions/registry.test.d.ts +2 -0
- package/dist/src/sessions/registry.test.d.ts.map +1 -0
- package/dist/src/sessions/registry.test.js +41 -0
- package/dist/src/sessions/registry.test.js.map +1 -0
- package/dist/src/shared/types.d.ts +43 -1
- package/dist/src/shared/types.d.ts.map +1 -1
- package/dist/web/404.html +1 -1
- package/dist/web/_next/static/chunks/app/sessions/page-c83c890177c18258.js +1 -0
- package/dist/web/_next/static/chunks/app/settings/page-2583d55551abdf72.js +1 -0
- package/dist/web/chat.html +1 -1
- package/dist/web/chat.txt +1 -1
- package/dist/web/costs.html +2 -2
- package/dist/web/costs.txt +1 -1
- package/dist/web/cron.html +1 -1
- package/dist/web/cron.txt +1 -1
- package/dist/web/index.html +1 -1
- package/dist/web/index.txt +1 -1
- package/dist/web/kanban.html +1 -1
- package/dist/web/kanban.txt +1 -1
- package/dist/web/logs.html +2 -2
- package/dist/web/logs.txt +1 -1
- package/dist/web/org.html +1 -1
- package/dist/web/org.txt +1 -1
- package/dist/web/sessions.html +1 -1
- package/dist/web/sessions.txt +2 -2
- package/dist/web/settings.html +1 -1
- package/dist/web/settings.txt +2 -2
- package/dist/web/skills.html +1 -1
- package/dist/web/skills.txt +1 -1
- package/package.json +9 -8
- package/template/config.default.yaml +5 -2
- package/template/migrations/0.2.0/MIGRATION.md +41 -0
- package/template/migrations/0.2.0/files/config.default.yaml +30 -0
- package/LICENSE +0 -21
- package/dist/web/_next/static/chunks/app/sessions/page-2eef6ac7882a28ba.js +0 -1
- package/dist/web/_next/static/chunks/app/settings/page-4fb01b9b09500170.js +0 -1
- /package/dist/web/_next/static/{vLvOwhC8JocJzSHTHKKOv → jt8R5JvUgfB9CMfFwWFr0}/_buildManifest.js +0 -0
- /package/dist/web/_next/static/{vLvOwhC8JocJzSHTHKKOv → jt8R5JvUgfB9CMfFwWFr0}/_ssgManifest.js +0 -0
package/dist/bin/jimmy.js
CHANGED
|
@@ -6,7 +6,7 @@ const program = new Command();
|
|
|
6
6
|
program
|
|
7
7
|
.name("jinn")
|
|
8
8
|
.description("Lightweight AI gateway daemon")
|
|
9
|
-
.version("0.
|
|
9
|
+
.version("0.2.0")
|
|
10
10
|
.option("-i, --instance <name>", "Target a specific instance (default: jinn)");
|
|
11
11
|
// Pre-parse to set JINN_HOME before any module imports resolve paths
|
|
12
12
|
program.hook("preAction", (thisCommand) => {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Connector, ConnectorCapabilities, ConnectorHealth, CronDelivery, IncomingMessage, ReplyContext, Target } from "../../shared/types.js";
|
|
2
|
+
export declare class CronConnector implements Connector {
|
|
3
|
+
private readonly connectors;
|
|
4
|
+
private readonly delivery?;
|
|
5
|
+
name: string;
|
|
6
|
+
private handler;
|
|
7
|
+
constructor(connectors: Map<string, Connector>, delivery?: CronDelivery | undefined);
|
|
8
|
+
start(): Promise<void>;
|
|
9
|
+
stop(): Promise<void>;
|
|
10
|
+
getCapabilities(): ConnectorCapabilities;
|
|
11
|
+
getHealth(): ConnectorHealth;
|
|
12
|
+
reconstructTarget(replyContext: ReplyContext): Target;
|
|
13
|
+
sendMessage(target: Target, text: string): Promise<string | void>;
|
|
14
|
+
replyMessage(target: Target, text: string): Promise<string | void>;
|
|
15
|
+
addReaction(): Promise<void>;
|
|
16
|
+
removeReaction(): Promise<void>;
|
|
17
|
+
editMessage(target: Target, text: string): Promise<void>;
|
|
18
|
+
onMessage(handler: (msg: IncomingMessage) => void): void;
|
|
19
|
+
private forward;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/connectors/cron/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,MAAM,EACP,MAAM,uBAAuB,CAAC;AAU/B,qBAAa,aAAc,YAAW,SAAS;IAK3C,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAL5B,IAAI,SAAU;IACd,OAAO,CAAC,OAAO,CAAiD;gBAG7C,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAClC,QAAQ,CAAC,EAAE,YAAY,YAAA;IAGpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAEtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAE3B,eAAe,IAAI,qBAAqB;IAIxC,SAAS,IAAI,eAAe;IAO5B,iBAAiB,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM;IAS/C,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIjE,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIlE,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAE5B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAE/B,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9D,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI;YAI1C,OAAO;CAqBtB"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { logger } from "../../shared/logger.js";
|
|
2
|
+
const capabilities = {
|
|
3
|
+
threading: false,
|
|
4
|
+
messageEdits: false,
|
|
5
|
+
reactions: false,
|
|
6
|
+
attachments: false,
|
|
7
|
+
};
|
|
8
|
+
export class CronConnector {
|
|
9
|
+
connectors;
|
|
10
|
+
delivery;
|
|
11
|
+
name = "cron";
|
|
12
|
+
handler = null;
|
|
13
|
+
constructor(connectors, delivery) {
|
|
14
|
+
this.connectors = connectors;
|
|
15
|
+
this.delivery = delivery;
|
|
16
|
+
}
|
|
17
|
+
async start() { }
|
|
18
|
+
async stop() { }
|
|
19
|
+
getCapabilities() {
|
|
20
|
+
return capabilities;
|
|
21
|
+
}
|
|
22
|
+
getHealth() {
|
|
23
|
+
return {
|
|
24
|
+
status: "running",
|
|
25
|
+
capabilities,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
reconstructTarget(replyContext) {
|
|
29
|
+
return {
|
|
30
|
+
channel: typeof replyContext.channel === "string" ? replyContext.channel : "",
|
|
31
|
+
thread: typeof replyContext.thread === "string" ? replyContext.thread : undefined,
|
|
32
|
+
messageTs: typeof replyContext.messageTs === "string" ? replyContext.messageTs : undefined,
|
|
33
|
+
replyContext,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async sendMessage(target, text) {
|
|
37
|
+
return this.forward(target, text, false);
|
|
38
|
+
}
|
|
39
|
+
async replyMessage(target, text) {
|
|
40
|
+
return this.forward(target, text, true);
|
|
41
|
+
}
|
|
42
|
+
async addReaction() { }
|
|
43
|
+
async removeReaction() { }
|
|
44
|
+
async editMessage(target, text) {
|
|
45
|
+
if (!this.delivery)
|
|
46
|
+
return;
|
|
47
|
+
const connector = this.connectors.get(this.delivery.connector);
|
|
48
|
+
if (!connector || !connector.getCapabilities().messageEdits)
|
|
49
|
+
return;
|
|
50
|
+
await connector.editMessage(target, text);
|
|
51
|
+
}
|
|
52
|
+
onMessage(handler) {
|
|
53
|
+
this.handler = handler;
|
|
54
|
+
}
|
|
55
|
+
async forward(target, text, asReply) {
|
|
56
|
+
if (!this.delivery)
|
|
57
|
+
return undefined;
|
|
58
|
+
const connector = this.connectors.get(this.delivery.connector);
|
|
59
|
+
if (!connector) {
|
|
60
|
+
logger.warn(`Cron delivery connector "${this.delivery.connector}" not found`);
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
const resolvedTarget = {
|
|
64
|
+
channel: target.channel || this.delivery.channel,
|
|
65
|
+
thread: target.thread,
|
|
66
|
+
messageTs: target.messageTs,
|
|
67
|
+
replyContext: target.replyContext,
|
|
68
|
+
};
|
|
69
|
+
if (asReply) {
|
|
70
|
+
return connector.replyMessage(resolvedTarget, text);
|
|
71
|
+
}
|
|
72
|
+
return connector.sendMessage(resolvedTarget, text);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/connectors/cron/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import type { Connector, IncomingMessage, Target } from "../../shared/types.js";
|
|
1
|
+
import type { Connector, ConnectorCapabilities, ConnectorHealth, IncomingMessage, ReplyContext, SlackConnectorConfig, Target } from "../../shared/types.js";
|
|
2
2
|
export declare class SlackConnector implements Connector {
|
|
3
3
|
name: string;
|
|
4
4
|
private app;
|
|
5
5
|
private handler;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
private readonly shareSessionInChannel;
|
|
7
|
+
private readonly allowedUsers;
|
|
8
|
+
private readonly ignoreOldMessagesOnBoot;
|
|
9
|
+
private readonly bootTimeMs;
|
|
10
|
+
private started;
|
|
11
|
+
private lastError;
|
|
12
|
+
private readonly capabilities;
|
|
13
|
+
constructor(config: SlackConnectorConfig);
|
|
10
14
|
start(): Promise<void>;
|
|
11
15
|
stop(): Promise<void>;
|
|
16
|
+
getCapabilities(): ConnectorCapabilities;
|
|
17
|
+
getHealth(): ConnectorHealth;
|
|
18
|
+
reconstructTarget(replyContext: ReplyContext): Target;
|
|
12
19
|
sendMessage(target: Target, text: string): Promise<string | undefined>;
|
|
20
|
+
replyMessage(target: Target, text: string): Promise<string | undefined>;
|
|
13
21
|
addReaction(target: Target, emoji: string): Promise<void>;
|
|
14
22
|
removeReaction(target: Target, emoji: string): Promise<void>;
|
|
15
23
|
editMessage(target: Target, text: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/connectors/slack/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/connectors/slack/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EACT,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,MAAM,EACP,MAAM,uBAAuB,CAAC;AAM/B,qBAAa,cAAe,YAAW,SAAS;IAC9C,IAAI,SAAW;IACf,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,OAAO,CAAiD;IAChE,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAU;IAChD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAU;IAClD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAc;IACzC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAuB;IAExC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAK3B;gBAEU,MAAM,EAAE,oBAAoB;IAgBlC,KAAK;IAqEL,IAAI;IAMV,eAAe,IAAI,qBAAqB;IAIxC,SAAS,IAAI,eAAe;IAQ5B,iBAAiB,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM;IAS/C,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAetE,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAiBvE,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAazC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAa5C,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAU9C,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI;CAGlD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { App } from "@slack/bolt";
|
|
2
|
-
import {
|
|
2
|
+
import { buildReplyContext, deriveSessionKey, isOldSlackMessage } from "./threads.js";
|
|
3
3
|
import { formatResponse, downloadAttachment } from "./format.js";
|
|
4
4
|
import { TMP_DIR } from "../../shared/paths.js";
|
|
5
5
|
import { logger } from "../../shared/logger.js";
|
|
@@ -7,12 +7,32 @@ export class SlackConnector {
|
|
|
7
7
|
name = "slack";
|
|
8
8
|
app;
|
|
9
9
|
handler = null;
|
|
10
|
+
shareSessionInChannel;
|
|
11
|
+
allowedUsers;
|
|
12
|
+
ignoreOldMessagesOnBoot;
|
|
13
|
+
bootTimeMs = Date.now();
|
|
14
|
+
started = false;
|
|
15
|
+
lastError = null;
|
|
16
|
+
capabilities = {
|
|
17
|
+
threading: true,
|
|
18
|
+
messageEdits: true,
|
|
19
|
+
reactions: true,
|
|
20
|
+
attachments: true,
|
|
21
|
+
};
|
|
10
22
|
constructor(config) {
|
|
11
23
|
this.app = new App({
|
|
12
24
|
token: config.botToken,
|
|
13
25
|
appToken: config.appToken,
|
|
14
26
|
socketMode: true,
|
|
15
27
|
});
|
|
28
|
+
this.shareSessionInChannel = !!config.shareSessionInChannel;
|
|
29
|
+
this.ignoreOldMessagesOnBoot = config.ignoreOldMessagesOnBoot !== false;
|
|
30
|
+
const allowFrom = Array.isArray(config.allowFrom)
|
|
31
|
+
? config.allowFrom
|
|
32
|
+
: typeof config.allowFrom === "string"
|
|
33
|
+
? config.allowFrom.split(",").map((value) => value.trim()).filter(Boolean)
|
|
34
|
+
: [];
|
|
35
|
+
this.allowedUsers = allowFrom.length > 0 ? new Set(allowFrom) : null;
|
|
16
36
|
}
|
|
17
37
|
async start() {
|
|
18
38
|
this.app.message(async ({ event }) => {
|
|
@@ -21,7 +41,18 @@ export class SlackConnector {
|
|
|
21
41
|
return;
|
|
22
42
|
if (!this.handler)
|
|
23
43
|
return;
|
|
24
|
-
|
|
44
|
+
if (this.ignoreOldMessagesOnBoot && isOldSlackMessage(event.ts, this.bootTimeMs)) {
|
|
45
|
+
logger.debug(`Ignoring old Slack message ${event.ts}`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (this.allowedUsers && !this.allowedUsers.has(event.user)) {
|
|
49
|
+
logger.debug(`Ignoring Slack message from unauthorized user ${event.user}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const sessionKey = deriveSessionKey(event, {
|
|
53
|
+
shareSessionInChannel: this.shareSessionInChannel,
|
|
54
|
+
});
|
|
55
|
+
const replyContext = buildReplyContext(event);
|
|
25
56
|
// Download attachments if present
|
|
26
57
|
const attachments = [];
|
|
27
58
|
if (event.files) {
|
|
@@ -41,7 +72,11 @@ export class SlackConnector {
|
|
|
41
72
|
}
|
|
42
73
|
}
|
|
43
74
|
const msg = {
|
|
75
|
+
connector: this.name,
|
|
44
76
|
source: "slack",
|
|
77
|
+
sessionKey,
|
|
78
|
+
replyContext,
|
|
79
|
+
messageId: event.ts,
|
|
45
80
|
channel: event.channel,
|
|
46
81
|
thread: event.thread_ts,
|
|
47
82
|
user: event.user,
|
|
@@ -49,16 +84,41 @@ export class SlackConnector {
|
|
|
49
84
|
text: event.text || "",
|
|
50
85
|
attachments,
|
|
51
86
|
raw: event,
|
|
87
|
+
transportMeta: {
|
|
88
|
+
channelType: event.channel_type || "channel",
|
|
89
|
+
team: event.team || null,
|
|
90
|
+
},
|
|
52
91
|
};
|
|
53
92
|
this.handler(msg);
|
|
54
93
|
});
|
|
55
94
|
await this.app.start();
|
|
95
|
+
this.started = true;
|
|
96
|
+
this.lastError = null;
|
|
56
97
|
logger.info("Slack connector started (socket mode)");
|
|
57
98
|
}
|
|
58
99
|
async stop() {
|
|
59
100
|
await this.app.stop();
|
|
101
|
+
this.started = false;
|
|
60
102
|
logger.info("Slack connector stopped");
|
|
61
103
|
}
|
|
104
|
+
getCapabilities() {
|
|
105
|
+
return this.capabilities;
|
|
106
|
+
}
|
|
107
|
+
getHealth() {
|
|
108
|
+
return {
|
|
109
|
+
status: this.lastError ? "error" : this.started ? "running" : "stopped",
|
|
110
|
+
detail: this.lastError ?? undefined,
|
|
111
|
+
capabilities: this.capabilities,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
reconstructTarget(replyContext) {
|
|
115
|
+
return {
|
|
116
|
+
channel: typeof replyContext.channel === "string" ? replyContext.channel : "",
|
|
117
|
+
thread: typeof replyContext.thread === "string" ? replyContext.thread : undefined,
|
|
118
|
+
messageTs: typeof replyContext.messageTs === "string" ? replyContext.messageTs : undefined,
|
|
119
|
+
replyContext,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
62
122
|
async sendMessage(target, text) {
|
|
63
123
|
if (!text || !text.trim())
|
|
64
124
|
return undefined;
|
|
@@ -69,7 +129,24 @@ export class SlackConnector {
|
|
|
69
129
|
continue;
|
|
70
130
|
const res = await this.app.client.chat.postMessage({
|
|
71
131
|
channel: target.channel,
|
|
72
|
-
|
|
132
|
+
text: chunk,
|
|
133
|
+
});
|
|
134
|
+
lastTs = res.ts;
|
|
135
|
+
}
|
|
136
|
+
return lastTs;
|
|
137
|
+
}
|
|
138
|
+
async replyMessage(target, text) {
|
|
139
|
+
if (!text || !text.trim())
|
|
140
|
+
return undefined;
|
|
141
|
+
const threadTs = target.thread || target.messageTs;
|
|
142
|
+
const chunks = formatResponse(text);
|
|
143
|
+
let lastTs;
|
|
144
|
+
for (const chunk of chunks) {
|
|
145
|
+
if (!chunk.trim())
|
|
146
|
+
continue;
|
|
147
|
+
const res = await this.app.client.chat.postMessage({
|
|
148
|
+
channel: target.channel,
|
|
149
|
+
thread_ts: threadTs,
|
|
73
150
|
text: chunk,
|
|
74
151
|
});
|
|
75
152
|
lastTs = res.ts;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/connectors/slack/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/connectors/slack/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ReplyContext } from "../../shared/types.js";
|
|
2
|
+
export interface SlackMessageEventLike {
|
|
3
|
+
channel: string;
|
|
4
|
+
user?: string;
|
|
5
|
+
ts?: string;
|
|
6
|
+
thread_ts?: string;
|
|
7
|
+
channel_type?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SlackThreadOptions {
|
|
10
|
+
shareSessionInChannel?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function deriveSessionKey(event: SlackMessageEventLike, opts?: SlackThreadOptions): string;
|
|
13
|
+
export declare function buildReplyContext(event: SlackMessageEventLike): ReplyContext;
|
|
14
|
+
export declare function isOldSlackMessage(ts: string | undefined, bootTimeMs: number): boolean;
|
|
2
15
|
//# sourceMappingURL=threads.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../../../../src/connectors/slack/threads.ts"],"names":[],"mappings":"AAAA,wBAAgB,
|
|
1
|
+
{"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../../../../src/connectors/slack/threads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,qBAAqB,EAC5B,IAAI,GAAE,kBAAuB,GAC5B,MAAM,CAcR;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,qBAAqB,GAAG,YAAY,CAU5E;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAKrF"}
|
|
@@ -1,10 +1,31 @@
|
|
|
1
|
-
export function
|
|
1
|
+
export function deriveSessionKey(event, opts = {}) {
|
|
2
2
|
if (event.channel_type === "im") {
|
|
3
|
-
return `slack:dm:${event.user}`;
|
|
3
|
+
return `slack:dm:${event.user || "unknown"}`;
|
|
4
|
+
}
|
|
5
|
+
if (opts.shareSessionInChannel) {
|
|
6
|
+
return `slack:${event.channel}`;
|
|
4
7
|
}
|
|
5
8
|
if (event.thread_ts && event.thread_ts !== event.ts) {
|
|
6
9
|
return `slack:${event.channel}:${event.thread_ts}`;
|
|
7
10
|
}
|
|
8
11
|
return `slack:${event.channel}`;
|
|
9
12
|
}
|
|
13
|
+
export function buildReplyContext(event) {
|
|
14
|
+
const thread = event.thread_ts && event.thread_ts !== event.ts
|
|
15
|
+
? event.thread_ts
|
|
16
|
+
: undefined;
|
|
17
|
+
return {
|
|
18
|
+
channel: event.channel,
|
|
19
|
+
thread: thread ?? null,
|
|
20
|
+
messageTs: event.ts ?? null,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function isOldSlackMessage(ts, bootTimeMs) {
|
|
24
|
+
if (!ts)
|
|
25
|
+
return false;
|
|
26
|
+
const secs = Number(ts.split(".")[0]);
|
|
27
|
+
if (!Number.isFinite(secs))
|
|
28
|
+
return false;
|
|
29
|
+
return secs * 1000 < bootTimeMs;
|
|
30
|
+
}
|
|
10
31
|
//# sourceMappingURL=threads.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"threads.js","sourceRoot":"","sources":["../../../../src/connectors/slack/threads.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"threads.js","sourceRoot":"","sources":["../../../../src/connectors/slack/threads.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,gBAAgB,CAC9B,KAA4B,EAC5B,OAA2B,EAAE;IAE7B,IAAI,KAAK,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;QAChC,OAAO,YAAY,KAAK,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC;IAC/C,CAAC;IAED,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC/B,OAAO,SAAS,KAAK,CAAC,OAAO,EAAE,CAAC;IAClC,CAAC;IAED,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,EAAE,EAAE,CAAC;QACpD,OAAO,SAAS,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;IACrD,CAAC;IAED,OAAO,SAAS,KAAK,CAAC,OAAO,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAA4B;IAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,EAAE;QAC5D,CAAC,CAAC,KAAK,CAAC,SAAS;QACjB,CAAC,CAAC,SAAS,CAAC;IAEd,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,MAAM,IAAI,IAAI;QACtB,SAAS,EAAE,KAAK,CAAC,EAAE,IAAI,IAAI;KAC5B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAsB,EAAE,UAAkB;IAC1E,IAAI,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC;IACtB,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,OAAO,IAAI,GAAG,IAAI,GAAG,UAAU,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threads.test.d.ts","sourceRoot":"","sources":["../../../../src/connectors/slack/threads.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { buildReplyContext, deriveSessionKey, isOldSlackMessage } from "./threads.js";
|
|
4
|
+
test("deriveSessionKey keeps DM sessions per user", () => {
|
|
5
|
+
const key = deriveSessionKey({
|
|
6
|
+
channel: "D123",
|
|
7
|
+
user: "U123",
|
|
8
|
+
channel_type: "im",
|
|
9
|
+
ts: "1700000000.000100",
|
|
10
|
+
});
|
|
11
|
+
assert.equal(key, "slack:dm:U123");
|
|
12
|
+
});
|
|
13
|
+
test("deriveSessionKey isolates thread replies unless channel sharing is enabled", () => {
|
|
14
|
+
const threaded = deriveSessionKey({
|
|
15
|
+
channel: "C123",
|
|
16
|
+
user: "U123",
|
|
17
|
+
ts: "1700000100.000200",
|
|
18
|
+
thread_ts: "1700000000.000100",
|
|
19
|
+
});
|
|
20
|
+
const shared = deriveSessionKey({
|
|
21
|
+
channel: "C123",
|
|
22
|
+
user: "U123",
|
|
23
|
+
ts: "1700000100.000200",
|
|
24
|
+
thread_ts: "1700000000.000100",
|
|
25
|
+
}, { shareSessionInChannel: true });
|
|
26
|
+
assert.equal(threaded, "slack:C123:1700000000.000100");
|
|
27
|
+
assert.equal(shared, "slack:C123");
|
|
28
|
+
});
|
|
29
|
+
test("buildReplyContext keeps the original message id for replies", () => {
|
|
30
|
+
const context = buildReplyContext({
|
|
31
|
+
channel: "C123",
|
|
32
|
+
ts: "1700000100.000200",
|
|
33
|
+
thread_ts: "1700000000.000100",
|
|
34
|
+
});
|
|
35
|
+
assert.deepEqual(context, {
|
|
36
|
+
channel: "C123",
|
|
37
|
+
thread: "1700000000.000100",
|
|
38
|
+
messageTs: "1700000100.000200",
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
test("isOldSlackMessage compares against boot time", () => {
|
|
42
|
+
assert.equal(isOldSlackMessage("1700000000.000100", 1700000001000), true);
|
|
43
|
+
assert.equal(isOldSlackMessage("1700000002.000100", 1700000001000), false);
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=threads.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threads.test.js","sourceRoot":"","sources":["../../../../src/connectors/slack/threads.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtF,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;IACvD,MAAM,GAAG,GAAG,gBAAgB,CAAC;QAC3B,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,MAAM;QACZ,YAAY,EAAE,IAAI;QAClB,EAAE,EAAE,mBAAmB;KACxB,CAAC,CAAC;IAEH,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4EAA4E,EAAE,GAAG,EAAE;IACtF,MAAM,QAAQ,GAAG,gBAAgB,CAAC;QAChC,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,MAAM;QACZ,EAAE,EAAE,mBAAmB;QACvB,SAAS,EAAE,mBAAmB;KAC/B,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,gBAAgB,CAC7B;QACE,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,MAAM;QACZ,EAAE,EAAE,mBAAmB;QACvB,SAAS,EAAE,mBAAmB;KAC/B,EACD,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAChC,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,8BAA8B,CAAC,CAAC;IACvD,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6DAA6D,EAAE,GAAG,EAAE;IACvE,MAAM,OAAO,GAAG,iBAAiB,CAAC;QAChC,OAAO,EAAE,MAAM;QACf,EAAE,EAAE,mBAAmB;QACvB,SAAS,EAAE,mBAAmB;KAC/B,CAAC,CAAC;IAEH,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE;QACxB,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,mBAAmB;QAC3B,SAAS,EAAE,mBAAmB;KAC/B,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;IACxD,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,mBAAmB,EAAE,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC;IAC1E,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,mBAAmB,EAAE,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC;AAC7E,CAAC,CAAC,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type { CronJob,
|
|
2
|
-
|
|
1
|
+
import type { CronJob, Connector, JinnConfig } from "../shared/types.js";
|
|
2
|
+
import type { SessionManager } from "../sessions/manager.js";
|
|
3
|
+
export declare function runCronJob(job: CronJob, sessionManager: SessionManager, config: JinnConfig, connectors: Map<string, Connector>): Promise<void>;
|
|
3
4
|
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/cron/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/cron/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,cAAc,EAAE,cAAc,EAC9B,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC,CAiFf"}
|
package/dist/src/cron/runner.js
CHANGED
|
@@ -1,118 +1,77 @@
|
|
|
1
|
-
import { buildContext } from "../sessions/context.js";
|
|
2
|
-
import { createSession, updateSession, insertMessage } from "../sessions/registry.js";
|
|
3
|
-
import { JINN_HOME } from "../shared/paths.js";
|
|
4
1
|
import { logger } from "../shared/logger.js";
|
|
5
2
|
import { appendRunLog } from "./jobs.js";
|
|
6
3
|
import { scanOrg, findEmployee } from "../gateway/org.js";
|
|
7
|
-
|
|
4
|
+
import { CronConnector } from "../connectors/cron/index.js";
|
|
5
|
+
export async function runCronJob(job, sessionManager, config, connectors) {
|
|
8
6
|
const startTime = Date.now();
|
|
9
7
|
logger.info(`Cron job "${job.name}" (${job.id}) starting`);
|
|
10
|
-
// 1. Determine engine + model
|
|
11
|
-
const engineName = job.engine || config.engines.default;
|
|
12
|
-
const engine = engines.get(engineName);
|
|
13
|
-
if (!engine) {
|
|
14
|
-
logger.error(`Engine "${engineName}" not found for cron job "${job.name}"`);
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
const model = job.model || config.engines[engineName]?.model;
|
|
18
|
-
// 2. Warn if a non-COO employee has delivery configured (anti-pattern)
|
|
19
8
|
const delivery = job.delivery || config.cron?.defaultDelivery;
|
|
20
9
|
const cooSlug = config.portal?.portalName?.toLowerCase() || "jinn";
|
|
21
10
|
if (delivery && job.employee && job.employee !== cooSlug) {
|
|
22
11
|
logger.warn(`Cron job "${job.name}" targets employee "${job.employee}" with delivery to ${delivery.connector}:${delivery.channel}. ` +
|
|
23
12
|
`Recommended pattern: target "${cooSlug}" and let the COO delegate to "${job.employee}" via a child session for output review/filtering.`);
|
|
24
13
|
}
|
|
25
|
-
// 3. Resolve employee
|
|
26
14
|
let employee;
|
|
27
15
|
if (job.employee) {
|
|
28
16
|
const orgRegistry = scanOrg();
|
|
29
17
|
employee = findEmployee(job.employee, orgRegistry);
|
|
30
18
|
}
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
engine: engineName,
|
|
35
|
-
source: "cron",
|
|
36
|
-
sourceRef,
|
|
37
|
-
employee: employee?.name,
|
|
38
|
-
model,
|
|
39
|
-
title: job.name,
|
|
40
|
-
prompt: job.prompt,
|
|
41
|
-
portalName: config.portal?.portalName,
|
|
42
|
-
});
|
|
43
|
-
insertMessage(session.id, "user", job.prompt);
|
|
44
|
-
// 5. Build context
|
|
45
|
-
const ctx = buildContext({
|
|
46
|
-
source: "cron",
|
|
47
|
-
channel: job.id,
|
|
48
|
-
user: "system",
|
|
49
|
-
employee,
|
|
50
|
-
config,
|
|
51
|
-
connectors: Array.from(connectors.keys()),
|
|
52
|
-
sessionId: session.id,
|
|
53
|
-
});
|
|
54
|
-
updateSession(session.id, {
|
|
55
|
-
status: "running",
|
|
56
|
-
lastActivity: new Date().toISOString(),
|
|
57
|
-
});
|
|
58
|
-
// 6. Run engine (fresh session, no resume)
|
|
19
|
+
const connector = new CronConnector(connectors, delivery);
|
|
20
|
+
const startedAt = new Date().toISOString();
|
|
21
|
+
const sessionKey = `cron:${job.id}:${Date.now()}`;
|
|
59
22
|
try {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
23
|
+
await sessionManager.route({
|
|
24
|
+
connector: connector.name,
|
|
25
|
+
source: "cron",
|
|
26
|
+
sessionKey,
|
|
27
|
+
replyContext: {
|
|
28
|
+
channel: delivery?.channel || job.id,
|
|
29
|
+
messageTs: null,
|
|
30
|
+
cronJobId: job.id,
|
|
31
|
+
cronJobName: job.name,
|
|
32
|
+
deliveryConnector: delivery?.connector ?? null,
|
|
33
|
+
},
|
|
34
|
+
messageId: undefined,
|
|
35
|
+
channel: delivery?.channel || job.id,
|
|
36
|
+
thread: undefined,
|
|
37
|
+
user: "system",
|
|
38
|
+
userId: "system",
|
|
39
|
+
text: job.prompt,
|
|
40
|
+
attachments: [],
|
|
41
|
+
raw: { jobId: job.id, trigger: "cron" },
|
|
42
|
+
transportMeta: {
|
|
43
|
+
cronJobId: job.id,
|
|
44
|
+
cronJobName: job.name,
|
|
45
|
+
deliveryConnector: delivery?.connector ?? null,
|
|
46
|
+
deliveryChannel: delivery?.channel ?? null,
|
|
47
|
+
},
|
|
48
|
+
}, connector, {
|
|
49
|
+
employee,
|
|
50
|
+
engine: job.engine || config.engines.default,
|
|
51
|
+
model: job.model || config.engines[(job.engine || config.engines.default)]?.model,
|
|
52
|
+
title: job.name,
|
|
78
53
|
});
|
|
79
|
-
// 7. If delivery configured (job-level or default), send result to connector
|
|
80
|
-
if (delivery && result.result) {
|
|
81
|
-
const connector = connectors.get(delivery.connector);
|
|
82
|
-
if (connector) {
|
|
83
|
-
await connector.sendMessage({ channel: delivery.channel }, result.result);
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
logger.warn(`Delivery connector "${delivery.connector}" not found`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
// 8. Log run
|
|
90
54
|
appendRunLog(job.id, {
|
|
91
|
-
timestamp:
|
|
92
|
-
|
|
93
|
-
status:
|
|
94
|
-
durationMs,
|
|
95
|
-
error:
|
|
96
|
-
resultPreview:
|
|
55
|
+
timestamp: startedAt,
|
|
56
|
+
sessionKey,
|
|
57
|
+
status: "success",
|
|
58
|
+
durationMs: Date.now() - startTime,
|
|
59
|
+
error: null,
|
|
60
|
+
resultPreview: null,
|
|
97
61
|
});
|
|
98
|
-
logger.info(`Cron job "${job.name}" completed in ${
|
|
62
|
+
logger.info(`Cron job "${job.name}" completed in ${Date.now() - startTime}ms`);
|
|
99
63
|
}
|
|
100
64
|
catch (err) {
|
|
101
|
-
const
|
|
102
|
-
updateSession(session.id, {
|
|
103
|
-
status: "error",
|
|
104
|
-
lastActivity: new Date().toISOString(),
|
|
105
|
-
lastError: err.message,
|
|
106
|
-
});
|
|
65
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
107
66
|
appendRunLog(job.id, {
|
|
108
|
-
timestamp:
|
|
109
|
-
|
|
67
|
+
timestamp: startedAt,
|
|
68
|
+
sessionKey,
|
|
110
69
|
status: "error",
|
|
111
|
-
durationMs,
|
|
112
|
-
error:
|
|
70
|
+
durationMs: Date.now() - startTime,
|
|
71
|
+
error: message,
|
|
113
72
|
resultPreview: null,
|
|
114
73
|
});
|
|
115
|
-
logger.error(`Cron job "${job.name}" failed: ${
|
|
74
|
+
logger.error(`Cron job "${job.name}" failed: ${message}`);
|
|
116
75
|
}
|
|
117
76
|
}
|
|
118
77
|
//# sourceMappingURL=runner.js.map
|