omnikey-cli 1.0.35 → 1.0.36
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.
|
@@ -171,9 +171,6 @@ async function runToolLoop(initialResult, session, sessionId, send, log, tools,
|
|
|
171
171
|
return result;
|
|
172
172
|
}
|
|
173
173
|
const aiModel = (0, ai_client_1.getDefaultModel)(config_1.config.aiProvider, 'smart');
|
|
174
|
-
// In-memory cache: sessionId -> live SessionState. Hydrated from DB on first
|
|
175
|
-
// access and written back after each turn so restarts resume correctly.
|
|
176
|
-
const sessionMessages = new Map();
|
|
177
174
|
const MAX_TURNS = 20;
|
|
178
175
|
// ─── DB helpers ───────────────────────────────────────────────────────────────
|
|
179
176
|
async function persistSessionToDB(sessionId, state) {
|
|
@@ -216,22 +213,7 @@ async function enforceSessionCap(subscriptionId, logger) {
|
|
|
216
213
|
}
|
|
217
214
|
}
|
|
218
215
|
async function getOrCreateSession(sessionId, subscription, platform, log, isCronJob = false) {
|
|
219
|
-
// 1.
|
|
220
|
-
const existing = sessionMessages.get(sessionId);
|
|
221
|
-
if (existing) {
|
|
222
|
-
log.debug('Reusing existing agent session (in-memory)', {
|
|
223
|
-
sessionId,
|
|
224
|
-
subscriptionId: existing.subscription.id,
|
|
225
|
-
turns: existing.turns,
|
|
226
|
-
});
|
|
227
|
-
return {
|
|
228
|
-
sessionState: existing,
|
|
229
|
-
hasStoredPrompt: existing.history
|
|
230
|
-
.filter((h) => h.role === 'user')
|
|
231
|
-
.some((h) => typeof h.content === 'string' && h.content.includes('<stored_instructions>')),
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
// 2. Try to resume from a persisted DB record.
|
|
216
|
+
// 1. Try to resume from a persisted DB record.
|
|
235
217
|
try {
|
|
236
218
|
const dbSession = await agentSession_1.AgentSession.findOne({
|
|
237
219
|
where: { id: sessionId, subscriptionId: subscription.id },
|
|
@@ -243,7 +225,6 @@ async function getOrCreateSession(sessionId, subscription, platform, log, isCron
|
|
|
243
225
|
history,
|
|
244
226
|
turns: dbSession.turns,
|
|
245
227
|
};
|
|
246
|
-
sessionMessages.set(sessionId, entry);
|
|
247
228
|
log.info('Resumed agent session from DB', {
|
|
248
229
|
sessionId,
|
|
249
230
|
subscriptionId: subscription.id,
|
|
@@ -263,7 +244,7 @@ async function getOrCreateSession(sessionId, subscription, platform, log, isCron
|
|
|
263
244
|
error: err,
|
|
264
245
|
});
|
|
265
246
|
}
|
|
266
|
-
//
|
|
247
|
+
// 2. Create a brand-new session and persist it to the DB.
|
|
267
248
|
const prompt = await (0, featureRoutes_1.getPromptForCommand)(log, 'task', subscription).catch((err) => {
|
|
268
249
|
log.error('Failed to get system prompt for new agent session', { error: err });
|
|
269
250
|
return '';
|
|
@@ -293,17 +274,19 @@ ${prompt}
|
|
|
293
274
|
],
|
|
294
275
|
turns: 0,
|
|
295
276
|
};
|
|
296
|
-
sessionMessages.set(sessionId, entry);
|
|
297
277
|
// Persist immediately so that GET /sessions picks it up right away.
|
|
298
278
|
try {
|
|
299
|
-
await agentSession_1.AgentSession.
|
|
300
|
-
id: sessionId,
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
279
|
+
await agentSession_1.AgentSession.findOrCreate({
|
|
280
|
+
where: { id: sessionId, subscriptionId: subscription.id },
|
|
281
|
+
defaults: {
|
|
282
|
+
id: sessionId,
|
|
283
|
+
subscriptionId: subscription.id,
|
|
284
|
+
title: 'New Session',
|
|
285
|
+
platform: platform ?? null,
|
|
286
|
+
historyJson: JSON.stringify(entry.history),
|
|
287
|
+
turns: 0,
|
|
288
|
+
lastActiveAt: new Date(),
|
|
289
|
+
},
|
|
307
290
|
});
|
|
308
291
|
// Prune oldest sessions after each creation so the cap is always respected.
|
|
309
292
|
void enforceSessionCap(subscription.id, log);
|
|
@@ -321,7 +304,7 @@ ${prompt}
|
|
|
321
304
|
hasStoredPrompt: !!prompt,
|
|
322
305
|
};
|
|
323
306
|
}
|
|
324
|
-
async function
|
|
307
|
+
async function runAgentTurnInternal(sessionId, subscription, clientMessage, send, log, options) {
|
|
325
308
|
const { sessionState: session, hasStoredPrompt } = await getOrCreateSession(sessionId, subscription, clientMessage.platform, log, options?.isCronJob);
|
|
326
309
|
// Count this call as one agent iteration.
|
|
327
310
|
session.turns += 1;
|
|
@@ -445,7 +428,6 @@ async function runAgentTurn(sessionId, subscription, clientMessage, send, log, o
|
|
|
445
428
|
log.warn('Agent LLM returned empty content; sending generic error to client.');
|
|
446
429
|
const errorMessage = 'The agent returned an empty response. Please try again.';
|
|
447
430
|
await persistSessionToDB(sessionId, session);
|
|
448
|
-
sessionMessages.delete(sessionId);
|
|
449
431
|
(0, utils_1.sendFinalAnswer)(send, sessionId, errorMessage, true);
|
|
450
432
|
return;
|
|
451
433
|
}
|
|
@@ -506,7 +488,7 @@ async function runAgentTurn(sessionId, subscription, clientMessage, send, log, o
|
|
|
506
488
|
'No plain text. No other format.',
|
|
507
489
|
].join('\n'),
|
|
508
490
|
});
|
|
509
|
-
await
|
|
491
|
+
await runAgentTurnInternal(sessionId, subscription, {
|
|
510
492
|
sender: 'agent',
|
|
511
493
|
session_id: sessionId,
|
|
512
494
|
content: '',
|
|
@@ -552,7 +534,6 @@ async function runAgentTurn(sessionId, subscription, clientMessage, send, log, o
|
|
|
552
534
|
});
|
|
553
535
|
(0, utils_1.pushToSessionHistory)(logger_1.logger, session, { role: 'assistant', content });
|
|
554
536
|
await persistSessionToDB(sessionId, session);
|
|
555
|
-
sessionMessages.delete(sessionId);
|
|
556
537
|
send({
|
|
557
538
|
session_id: sessionId,
|
|
558
539
|
sender: 'agent',
|
|
@@ -571,7 +552,6 @@ async function runAgentTurn(sessionId, subscription, clientMessage, send, log, o
|
|
|
571
552
|
});
|
|
572
553
|
(0, utils_1.pushToSessionHistory)(log, session, { role: 'assistant', content });
|
|
573
554
|
await persistSessionToDB(sessionId, session);
|
|
574
|
-
sessionMessages.delete(sessionId);
|
|
575
555
|
send({
|
|
576
556
|
session_id: sessionId,
|
|
577
557
|
sender: 'agent',
|
|
@@ -583,7 +563,6 @@ async function runAgentTurn(sessionId, subscription, clientMessage, send, log, o
|
|
|
583
563
|
sessionId,
|
|
584
564
|
});
|
|
585
565
|
await persistSessionToDB(sessionId, session);
|
|
586
|
-
sessionMessages.delete(sessionId);
|
|
587
566
|
(0, utils_1.sendFinalAnswer)(send, sessionId, 'The agent returned an empty response. Please try again.', true);
|
|
588
567
|
}
|
|
589
568
|
}
|
|
@@ -591,10 +570,12 @@ async function runAgentTurn(sessionId, subscription, clientMessage, send, log, o
|
|
|
591
570
|
log.error('Agent LLM call failed', { error: err });
|
|
592
571
|
const errorMessage = 'Agent failed to call language model. Please try again later.';
|
|
593
572
|
await persistSessionToDB(sessionId, session);
|
|
594
|
-
sessionMessages.delete(sessionId);
|
|
595
573
|
(0, utils_1.sendFinalAnswer)(send, sessionId, errorMessage, true);
|
|
596
574
|
}
|
|
597
575
|
}
|
|
576
|
+
async function runAgentTurn(sessionId, subscription, clientMessage, send, log, options) {
|
|
577
|
+
await runAgentTurnInternal(sessionId, subscription, clientMessage, send, log, options);
|
|
578
|
+
}
|
|
598
579
|
function attachAgentWebSocketServer(server) {
|
|
599
580
|
const wss = new ws_1.WebSocketServer({ server, path: '/ws/omni-agent' });
|
|
600
581
|
wss.on('connection', (ws, req) => {
|
|
@@ -731,8 +712,6 @@ function createAgentRouter() {
|
|
|
731
712
|
res.status(404).json({ error: 'Session not found' });
|
|
732
713
|
return;
|
|
733
714
|
}
|
|
734
|
-
// Also remove from the in-memory cache if it was loaded.
|
|
735
|
-
sessionMessages.delete(sessionId);
|
|
736
715
|
res.status(200).json({ deleted: true });
|
|
737
716
|
}
|
|
738
717
|
catch (err) {
|
|
@@ -10,18 +10,33 @@ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
|
10
10
|
const logger_1 = require("./logger");
|
|
11
11
|
const config_1 = require("./config");
|
|
12
12
|
const subscription_1 = require("./models/subscription");
|
|
13
|
+
const SELF_HOSTED_SUBSCRIPTION_ID = 'self-hosted-local-subscription';
|
|
13
14
|
async function selfHostedSubscription() {
|
|
14
15
|
try {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
// Reuse any existing self-hosted record (including legacy IDs) first.
|
|
17
|
+
const existing = await subscription_1.Subscription.findOne({ where: { isSelfHosted: true } });
|
|
18
|
+
if (existing)
|
|
19
|
+
return existing;
|
|
20
|
+
// Use a deterministic primary key so concurrent first-time requests do not
|
|
21
|
+
// create duplicate rows.
|
|
22
|
+
const [subscription, created] = await subscription_1.Subscription.findOrCreate({
|
|
23
|
+
where: { id: SELF_HOSTED_SUBSCRIPTION_ID },
|
|
24
|
+
defaults: {
|
|
25
|
+
id: SELF_HOSTED_SUBSCRIPTION_ID,
|
|
18
26
|
email: 'local-user@omnikey.ai',
|
|
19
27
|
licenseKey: 'self-hosted',
|
|
20
28
|
subscriptionStatus: 'active',
|
|
21
29
|
isSelfHosted: true,
|
|
22
|
-
}
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
if (created) {
|
|
23
33
|
logger_1.logger.info('Created self-hosted subscription record in database.');
|
|
24
34
|
}
|
|
35
|
+
// Ensure deterministic row remains flagged for self-hosted mode.
|
|
36
|
+
if (!subscription.isSelfHosted) {
|
|
37
|
+
subscription.isSelfHosted = true;
|
|
38
|
+
await subscription.save();
|
|
39
|
+
}
|
|
25
40
|
return subscription;
|
|
26
41
|
}
|
|
27
42
|
catch (err) {
|
|
@@ -31,37 +46,37 @@ async function selfHostedSubscription() {
|
|
|
31
46
|
}
|
|
32
47
|
async function authMiddleware(req, res, next) {
|
|
33
48
|
const authHeader = req.headers.authorization;
|
|
34
|
-
logger_1.logger.
|
|
49
|
+
const requestLogger = logger_1.logger.child({ traceId: (0, crypto_1.randomUUID)() });
|
|
50
|
+
res.locals.logger = requestLogger;
|
|
35
51
|
if (config_1.config.blockSaas) {
|
|
36
|
-
|
|
52
|
+
requestLogger.warn('Blocking SaaS access: rejecting request due to BLOCK_SAAS=true');
|
|
37
53
|
return res.status(403).json({ error: 'SaaS access is blocked.' });
|
|
38
54
|
}
|
|
39
55
|
if (config_1.config.isSelfHosted || !config_1.config.jwtSecret) {
|
|
40
|
-
|
|
56
|
+
requestLogger.info('Self-hosted mode: skipping auth middleware.');
|
|
41
57
|
if (config_1.config.isSelfHosted) {
|
|
42
58
|
res.locals.subscription = await selfHostedSubscription();
|
|
43
|
-
res.locals.logger = logger_1.logger;
|
|
44
59
|
}
|
|
45
60
|
return next();
|
|
46
61
|
}
|
|
47
62
|
if (!authHeader) {
|
|
48
|
-
|
|
63
|
+
requestLogger.warn('Missing Authorization header on feature route.');
|
|
49
64
|
return res.status(401).json({ error: 'Missing bearer token.' });
|
|
50
65
|
}
|
|
51
66
|
const [scheme, token] = authHeader.split(' ');
|
|
52
67
|
if (scheme !== 'Bearer' || !token) {
|
|
53
|
-
|
|
68
|
+
requestLogger.warn('Malformed Authorization header on feature route.');
|
|
54
69
|
return res.status(401).json({ error: 'Invalid authorization header.' });
|
|
55
70
|
}
|
|
56
71
|
try {
|
|
57
72
|
const decoded = jsonwebtoken_1.default.verify(token, config_1.config.jwtSecret);
|
|
58
73
|
const subscription = await subscription_1.Subscription.findByPk(decoded.sid);
|
|
59
74
|
if (!subscription) {
|
|
60
|
-
|
|
75
|
+
requestLogger.warn('Subscription not found for JWT.', { sid: decoded.sid });
|
|
61
76
|
return res.status(403).json({ error: 'Invalid or expired token.' });
|
|
62
77
|
}
|
|
63
78
|
if (subscription.subscriptionStatus == 'expired') {
|
|
64
|
-
|
|
79
|
+
requestLogger.warn('Inactive subscription for JWT.', {
|
|
65
80
|
sid: decoded.sid,
|
|
66
81
|
status: subscription.subscriptionStatus,
|
|
67
82
|
});
|
|
@@ -71,19 +86,18 @@ async function authMiddleware(req, res, next) {
|
|
|
71
86
|
if (subscription.licenseKeyExpiresAt && subscription.licenseKeyExpiresAt <= now) {
|
|
72
87
|
subscription.subscriptionStatus = 'expired';
|
|
73
88
|
await subscription.save();
|
|
74
|
-
|
|
89
|
+
requestLogger.info('Subscription key has expired during activation.', {
|
|
75
90
|
subscriptionId: subscription.id,
|
|
76
91
|
});
|
|
77
92
|
return res
|
|
78
93
|
.status(403)
|
|
79
94
|
.json({ error: 'Subscription has expired.', subscriptionStatus: 'expired' });
|
|
80
95
|
}
|
|
81
|
-
res.locals.logger = logger_1.logger;
|
|
82
96
|
res.locals.subscription = subscription;
|
|
83
97
|
next();
|
|
84
98
|
}
|
|
85
99
|
catch (err) {
|
|
86
|
-
|
|
100
|
+
requestLogger.warn('Invalid or expired JWT on feature route.', { error: err });
|
|
87
101
|
return res.status(403).json({ error: 'Invalid or expired token.' });
|
|
88
102
|
}
|
|
89
103
|
}
|
|
@@ -3,9 +3,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getDownloadCounts = getDownloadCounts;
|
|
4
4
|
exports.incrementDownloadCount = incrementDownloadCount;
|
|
5
5
|
const storage_1 = require("@google-cloud/storage");
|
|
6
|
+
const zod_1 = require("zod");
|
|
6
7
|
const logger_1 = require("../logger");
|
|
7
8
|
const config_1 = require("../config");
|
|
8
9
|
const DEFAULT_COUNTS = { macos: 0, windows: 0 };
|
|
10
|
+
const downloadCountsSchema = zod_1.z.object({
|
|
11
|
+
macos: zod_1.z.number().nonnegative().optional(),
|
|
12
|
+
windows: zod_1.z.number().nonnegative().optional(),
|
|
13
|
+
});
|
|
14
|
+
function parseDownloadCounts(raw) {
|
|
15
|
+
const json = JSON.parse(raw);
|
|
16
|
+
const parsed = downloadCountsSchema.safeParse(json);
|
|
17
|
+
if (!parsed.success) {
|
|
18
|
+
return { ...DEFAULT_COUNTS };
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
macos: parsed.data.macos ?? 0,
|
|
22
|
+
windows: parsed.data.windows ?? 0,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
9
25
|
// Initialised once at module load — uses Application Default Credentials when
|
|
10
26
|
// running on Cloud Run (or any GCP environment), and falls back to ADC from
|
|
11
27
|
// the local environment during development.
|
|
@@ -30,28 +46,57 @@ async function readCounts(bucketName, objectPath) {
|
|
|
30
46
|
return { ...DEFAULT_COUNTS };
|
|
31
47
|
}
|
|
32
48
|
const [contents] = await file.download();
|
|
33
|
-
|
|
49
|
+
return parseDownloadCounts(contents.toString('utf8'));
|
|
50
|
+
}
|
|
51
|
+
async function readCountsWithGeneration(bucketName, objectPath) {
|
|
52
|
+
const file = storage.bucket(bucketName).file(objectPath);
|
|
53
|
+
const [exists] = await file.exists();
|
|
54
|
+
if (!exists) {
|
|
55
|
+
return { counts: { ...DEFAULT_COUNTS }, generation: null, exists: false };
|
|
56
|
+
}
|
|
57
|
+
const [[metadata], [contents]] = await Promise.all([file.getMetadata(), file.download()]);
|
|
58
|
+
const counts = parseDownloadCounts(contents.toString('utf8'));
|
|
34
59
|
return {
|
|
35
|
-
|
|
36
|
-
|
|
60
|
+
counts,
|
|
61
|
+
generation: metadata.generation ?? null,
|
|
62
|
+
exists: true,
|
|
37
63
|
};
|
|
38
64
|
}
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
65
|
+
function isGcsPreconditionError(err) {
|
|
66
|
+
const maybe = err;
|
|
67
|
+
return (maybe?.code === 412 ||
|
|
68
|
+
maybe?.message?.includes('conditionNotMet') === true ||
|
|
69
|
+
maybe?.message?.includes('Precondition Failed') === true);
|
|
45
70
|
}
|
|
46
71
|
async function incrementDownloadCount(platform) {
|
|
47
72
|
const gcs = getGcsConfig();
|
|
48
73
|
if (!gcs)
|
|
49
74
|
return;
|
|
75
|
+
const file = storage.bucket(gcs.bucketName).file(gcs.objectPath);
|
|
76
|
+
const MAX_RETRIES = 6;
|
|
50
77
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
78
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
79
|
+
const { counts, generation, exists } = await readCountsWithGeneration(gcs.bucketName, gcs.objectPath);
|
|
80
|
+
counts[platform] += 1;
|
|
81
|
+
try {
|
|
82
|
+
await file.save(JSON.stringify(counts), {
|
|
83
|
+
contentType: 'application/json',
|
|
84
|
+
resumable: false,
|
|
85
|
+
preconditionOpts: exists
|
|
86
|
+
? { ifGenerationMatch: Number(generation) }
|
|
87
|
+
: { ifGenerationMatch: 0 },
|
|
88
|
+
});
|
|
89
|
+
logger_1.logger.info(`Download count incremented for ${platform}.`, { counts, attempt });
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
if (isGcsPreconditionError(err) && attempt < MAX_RETRIES) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
throw err;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
logger_1.logger.warn(`Download count increment exhausted retries for ${platform}.`);
|
|
55
100
|
}
|
|
56
101
|
catch (err) {
|
|
57
102
|
logger_1.logger.error(`Failed to increment download count for ${platform}.`, { error: err });
|
package/backend-dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const cors_1 = __importDefault(require("cors"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
10
|
const zlib_1 = __importDefault(require("zlib"));
|
|
11
|
+
const child_process_1 = require("child_process");
|
|
11
12
|
const subscriptionRoutes_1 = require("./subscriptionRoutes");
|
|
12
13
|
const featureRoutes_1 = require("./featureRoutes");
|
|
13
14
|
const db_1 = require("./db");
|
|
@@ -23,6 +24,7 @@ require("./models/scheduledJob");
|
|
|
23
24
|
const bucket_adapter_1 = require("./bucket-adapter");
|
|
24
25
|
const app = (0, express_1.default)();
|
|
25
26
|
const PORT = Number(config_1.config.port);
|
|
27
|
+
const IS_CRON_CHILD = process.env.OMNIKEY_CRON_CHILD === '1';
|
|
26
28
|
app.set('trust proxy', 1);
|
|
27
29
|
app.use((0, cors_1.default)());
|
|
28
30
|
app.use(express_1.default.json());
|
|
@@ -165,9 +167,38 @@ app.get('*', (_req, res) => {
|
|
|
165
167
|
res.sendFile(path_1.default.join(process.cwd(), 'public', 'index.html'));
|
|
166
168
|
});
|
|
167
169
|
let server = null;
|
|
170
|
+
let cronChildProcess = null;
|
|
171
|
+
function startCronChildProcess() {
|
|
172
|
+
if (IS_CRON_CHILD || cronChildProcess)
|
|
173
|
+
return;
|
|
174
|
+
const childPort = PORT + 1;
|
|
175
|
+
const entry = process.argv[1] || __filename;
|
|
176
|
+
cronChildProcess = (0, child_process_1.fork)(entry, [], {
|
|
177
|
+
env: {
|
|
178
|
+
...process.env,
|
|
179
|
+
OMNIKEY_CRON_CHILD: '1',
|
|
180
|
+
OMNIKEY_PORT: String(childPort),
|
|
181
|
+
},
|
|
182
|
+
execArgv: process.execArgv,
|
|
183
|
+
stdio: 'inherit',
|
|
184
|
+
});
|
|
185
|
+
logger_1.logger.info('Spawned cron child process.', {
|
|
186
|
+
pid: cronChildProcess.pid,
|
|
187
|
+
port: childPort,
|
|
188
|
+
});
|
|
189
|
+
cronChildProcess.on('exit', (code, signal) => {
|
|
190
|
+
logger_1.logger.warn('Cron child process exited.', { code, signal });
|
|
191
|
+
cronChildProcess = null;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
168
194
|
async function start() {
|
|
169
195
|
try {
|
|
170
196
|
await (0, db_1.initDatabase)(logger_1.logger);
|
|
197
|
+
if (IS_CRON_CHILD) {
|
|
198
|
+
logger_1.logger.info('Starting cron child process mode.', { port: PORT });
|
|
199
|
+
(0, scheduledJobExecutor_1.startScheduledJobExecutor)();
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
171
202
|
server = app.listen(PORT, () => {
|
|
172
203
|
logger_1.logger.info(`Enhancer API listening on http://localhost:${PORT}`, {
|
|
173
204
|
isSelfHosted: config_1.config.isSelfHosted,
|
|
@@ -181,7 +212,7 @@ async function start() {
|
|
|
181
212
|
(0, agentServer_1.attachAgentWebSocketServer)(server);
|
|
182
213
|
}
|
|
183
214
|
if (config_1.config.isSelfHosted) {
|
|
184
|
-
(
|
|
215
|
+
startCronChildProcess();
|
|
185
216
|
}
|
|
186
217
|
}
|
|
187
218
|
catch (err) {
|
|
@@ -192,6 +223,15 @@ async function start() {
|
|
|
192
223
|
start();
|
|
193
224
|
function gracefulShutdown(signal) {
|
|
194
225
|
logger_1.logger.info(`Received ${signal}. Starting graceful shutdown...`);
|
|
226
|
+
if (cronChildProcess) {
|
|
227
|
+
cronChildProcess.kill('SIGTERM');
|
|
228
|
+
cronChildProcess = null;
|
|
229
|
+
}
|
|
230
|
+
if (IS_CRON_CHILD) {
|
|
231
|
+
logger_1.logger.info('Cron child process exiting.');
|
|
232
|
+
process.exit(0);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
195
235
|
if (!server) {
|
|
196
236
|
logger_1.logger.info('Server was not started or already closed. Exiting process.');
|
|
197
237
|
process.exit(0);
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public",
|
|
5
5
|
"registry": "https://registry.npmjs.org/"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.0.
|
|
7
|
+
"version": "1.0.36",
|
|
8
8
|
"description": "CLI for onboarding users to Omnikey AI and configuring OPENAI_API_KEY. Use Yarn for install/build.",
|
|
9
9
|
"engines": {
|
|
10
10
|
"node": ">=14.0.0",
|