@luckydraw/cumulus 0.27.41 → 0.28.1
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/gateway/adapters/webchat.d.ts +5 -7
- package/dist/gateway/adapters/webchat.d.ts.map +1 -1
- package/dist/gateway/adapters/webchat.js +204 -57
- package/dist/gateway/adapters/webchat.js.map +1 -1
- package/dist/gateway/config.d.ts +48 -0
- package/dist/gateway/config.d.ts.map +1 -1
- package/dist/gateway/config.js +90 -0
- package/dist/gateway/config.js.map +1 -1
- package/dist/gateway/daemon.d.ts.map +1 -1
- package/dist/gateway/daemon.js +272 -28
- package/dist/gateway/daemon.js.map +1 -1
- package/dist/gateway/gateway-agents-mcp.js +570 -31
- package/dist/gateway/gateway-agents-mcp.js.map +1 -1
- package/dist/gateway/hooks.d.ts +101 -0
- package/dist/gateway/hooks.d.ts.map +1 -0
- package/dist/gateway/hooks.js +200 -0
- package/dist/gateway/hooks.js.map +1 -0
- package/dist/gateway/scheduler.d.ts +50 -0
- package/dist/gateway/scheduler.d.ts.map +1 -0
- package/dist/gateway/scheduler.js +263 -0
- package/dist/gateway/scheduler.js.map +1 -0
- package/dist/gateway/server.d.ts +16 -1
- package/dist/gateway/server.d.ts.map +1 -1
- package/dist/gateway/server.js +451 -22
- package/dist/gateway/server.js.map +1 -1
- package/dist/gateway/static/blex.min.js +74 -17
- package/dist/gateway/static/chat.html +1 -4
- package/dist/gateway/static/dashboard.html +151 -0
- package/dist/gateway/static/dashboard.js +229 -0
- package/dist/gateway/static/widget.js +656 -460
- package/dist/index.d.ts +13 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/agentic-loop.d.ts +124 -0
- package/dist/lib/agentic-loop.d.ts.map +1 -0
- package/dist/lib/agentic-loop.js +338 -0
- package/dist/lib/agentic-loop.js.map +1 -0
- package/dist/lib/config.d.ts +28 -15
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +47 -41
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/gateway.d.ts +34 -3
- package/dist/lib/gateway.d.ts.map +1 -1
- package/dist/lib/gateway.js +584 -37
- package/dist/lib/gateway.js.map +1 -1
- package/dist/lib/huggingface-provider.d.ts +26 -0
- package/dist/lib/huggingface-provider.d.ts.map +1 -0
- package/dist/lib/huggingface-provider.js +338 -0
- package/dist/lib/huggingface-provider.js.map +1 -0
- package/dist/lib/provider.d.ts +71 -0
- package/dist/lib/provider.d.ts.map +1 -0
- package/dist/lib/provider.js +90 -0
- package/dist/lib/provider.js.map +1 -0
- package/dist/lib/tools/ask-user-question.d.ts +14 -0
- package/dist/lib/tools/ask-user-question.d.ts.map +1 -0
- package/dist/lib/tools/ask-user-question.js +74 -0
- package/dist/lib/tools/ask-user-question.js.map +1 -0
- package/dist/lib/tools/bash.d.ts +6 -0
- package/dist/lib/tools/bash.d.ts.map +1 -0
- package/dist/lib/tools/bash.js +85 -0
- package/dist/lib/tools/bash.js.map +1 -0
- package/dist/lib/tools/edit.d.ts +6 -0
- package/dist/lib/tools/edit.d.ts.map +1 -0
- package/dist/lib/tools/edit.js +79 -0
- package/dist/lib/tools/edit.js.map +1 -0
- package/dist/lib/tools/glob.d.ts +6 -0
- package/dist/lib/tools/glob.d.ts.map +1 -0
- package/dist/lib/tools/glob.js +91 -0
- package/dist/lib/tools/glob.js.map +1 -0
- package/dist/lib/tools/grep.d.ts +6 -0
- package/dist/lib/tools/grep.d.ts.map +1 -0
- package/dist/lib/tools/grep.js +110 -0
- package/dist/lib/tools/grep.js.map +1 -0
- package/dist/lib/tools/index.d.ts +29 -0
- package/dist/lib/tools/index.d.ts.map +1 -0
- package/dist/lib/tools/index.js +52 -0
- package/dist/lib/tools/index.js.map +1 -0
- package/dist/lib/tools/read.d.ts +6 -0
- package/dist/lib/tools/read.d.ts.map +1 -0
- package/dist/lib/tools/read.js +80 -0
- package/dist/lib/tools/read.js.map +1 -0
- package/dist/lib/tools/tool-search.d.ts +30 -0
- package/dist/lib/tools/tool-search.d.ts.map +1 -0
- package/dist/lib/tools/tool-search.js +108 -0
- package/dist/lib/tools/tool-search.js.map +1 -0
- package/dist/lib/tools/web-fetch.d.ts +9 -0
- package/dist/lib/tools/web-fetch.d.ts.map +1 -0
- package/dist/lib/tools/web-fetch.js +114 -0
- package/dist/lib/tools/web-fetch.js.map +1 -0
- package/dist/lib/tools/web-search.d.ts +12 -0
- package/dist/lib/tools/web-search.d.ts.map +1 -0
- package/dist/lib/tools/web-search.js +89 -0
- package/dist/lib/tools/web-search.js.map +1 -0
- package/dist/lib/tools/write.d.ts +6 -0
- package/dist/lib/tools/write.d.ts.map +1 -0
- package/dist/lib/tools/write.js +44 -0
- package/dist/lib/tools/write.js.map +1 -0
- package/package.json +3 -2
package/dist/gateway/config.d.ts
CHANGED
|
@@ -20,6 +20,31 @@ export interface VapidConfig {
|
|
|
20
20
|
privateKey: string;
|
|
21
21
|
email: string;
|
|
22
22
|
}
|
|
23
|
+
export interface HooksConfig {
|
|
24
|
+
email?: {
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
provider: 'resend';
|
|
27
|
+
signingSecret?: string;
|
|
28
|
+
threadMapping: string;
|
|
29
|
+
defaultTemplate?: string;
|
|
30
|
+
};
|
|
31
|
+
form?: {
|
|
32
|
+
enabled: boolean;
|
|
33
|
+
threadMapping: string;
|
|
34
|
+
defaultTemplate?: string;
|
|
35
|
+
};
|
|
36
|
+
webhooks?: Record<string, {
|
|
37
|
+
thread: string;
|
|
38
|
+
template?: string;
|
|
39
|
+
}>;
|
|
40
|
+
}
|
|
41
|
+
export interface ResendConfig {
|
|
42
|
+
apiKey: string;
|
|
43
|
+
defaultFrom: string;
|
|
44
|
+
replyTo?: string;
|
|
45
|
+
/** Max emails per hour per thread (default: 10) */
|
|
46
|
+
rateLimit?: number;
|
|
47
|
+
}
|
|
23
48
|
export interface GatewayConfig {
|
|
24
49
|
apiKeys: string[];
|
|
25
50
|
port: number;
|
|
@@ -39,6 +64,29 @@ export interface GatewayConfig {
|
|
|
39
64
|
defaultMode?: 'local' | 'remote';
|
|
40
65
|
/** Optional: VAPID config for web push notifications */
|
|
41
66
|
vapid?: VapidConfig;
|
|
67
|
+
/** Optional: inbound webhook configurations */
|
|
68
|
+
hooks?: HooksConfig;
|
|
69
|
+
/** Optional: Resend email API configuration */
|
|
70
|
+
resend?: ResendConfig;
|
|
71
|
+
/** Optional: HuggingFace API key for non-Claude models */
|
|
72
|
+
hfApiKey?: string;
|
|
73
|
+
/** Optional: available models for per-thread selection */
|
|
74
|
+
models?: ModelEntry[];
|
|
75
|
+
/** Optional: default model ID for new threads (e.g., "claude" or "zai-org/GLM-5") */
|
|
76
|
+
model?: string;
|
|
77
|
+
}
|
|
78
|
+
/** Model entry for per-thread selection */
|
|
79
|
+
export interface ModelEntry {
|
|
80
|
+
/** Model ID — "claude" for CLI, or HuggingFace model ID like "zai-org/GLM-5" */
|
|
81
|
+
id: string;
|
|
82
|
+
/** Display label for the widget dropdown */
|
|
83
|
+
label: string;
|
|
84
|
+
/** Provider — "claude-cli" or "huggingface" */
|
|
85
|
+
provider: 'claude-cli' | 'huggingface';
|
|
86
|
+
/** Whether this is the default model */
|
|
87
|
+
default?: boolean;
|
|
88
|
+
/** Context window size in tokens (for HuggingFace models) */
|
|
89
|
+
contextWindow?: number;
|
|
42
90
|
}
|
|
43
91
|
/**
|
|
44
92
|
* Load gateway config from ~/.cumulus/gateway.config.json.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/gateway/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACjC,wDAAwD;IACxD,KAAK,CAAC,EAAE,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/gateway/config.ts"],"names":[],"mappings":"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"}
|
package/dist/gateway/config.js
CHANGED
|
@@ -52,8 +52,44 @@ function validateConfig(raw) {
|
|
|
52
52
|
projectRoot: typeof raw.projectRoot === 'string' && raw.projectRoot ? raw.projectRoot : undefined,
|
|
53
53
|
defaultMode: raw.defaultMode === 'local' ? 'local' : undefined,
|
|
54
54
|
vapid: validateVapid(raw.vapid),
|
|
55
|
+
hooks: validateHooks(raw.hooks),
|
|
56
|
+
resend: validateResend(raw.resend),
|
|
57
|
+
hfApiKey: typeof raw.hfApiKey === 'string' && raw.hfApiKey ? raw.hfApiKey : undefined,
|
|
58
|
+
models: validateModels(raw.models),
|
|
59
|
+
model: typeof raw.model === 'string' && raw.model ? raw.model : undefined,
|
|
55
60
|
};
|
|
56
61
|
}
|
|
62
|
+
function validateResend(raw) {
|
|
63
|
+
if (!raw || typeof raw !== 'object')
|
|
64
|
+
return undefined;
|
|
65
|
+
const r = raw;
|
|
66
|
+
if (typeof r.apiKey !== 'string' || !r.apiKey) {
|
|
67
|
+
throw new Error('gateway.config.json: resend.apiKey is required');
|
|
68
|
+
}
|
|
69
|
+
if (typeof r.defaultFrom !== 'string' || !r.defaultFrom) {
|
|
70
|
+
throw new Error('gateway.config.json: resend.defaultFrom is required');
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
apiKey: r.apiKey,
|
|
74
|
+
defaultFrom: r.defaultFrom,
|
|
75
|
+
replyTo: typeof r.replyTo === 'string' ? r.replyTo : undefined,
|
|
76
|
+
rateLimit: typeof r.rateLimit === 'number' ? r.rateLimit : undefined,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function validateModels(raw) {
|
|
80
|
+
if (!raw || !Array.isArray(raw))
|
|
81
|
+
return undefined;
|
|
82
|
+
return raw
|
|
83
|
+
.filter((m) => m && typeof m === 'object')
|
|
84
|
+
.map(m => ({
|
|
85
|
+
id: String(m.id || ''),
|
|
86
|
+
label: String(m.label || m.id || ''),
|
|
87
|
+
provider: m.provider === 'huggingface' ? 'huggingface' : 'claude-cli',
|
|
88
|
+
default: m.default === true ? true : undefined,
|
|
89
|
+
contextWindow: typeof m.contextWindow === 'number' ? m.contextWindow : undefined,
|
|
90
|
+
}))
|
|
91
|
+
.filter(m => m.id.length > 0);
|
|
92
|
+
}
|
|
57
93
|
function validateChannels(raw) {
|
|
58
94
|
if (!raw || typeof raw !== 'object')
|
|
59
95
|
return undefined;
|
|
@@ -105,6 +141,60 @@ function validateVapid(raw) {
|
|
|
105
141
|
email: typeof v.email === 'string' ? v.email : 'mailto:noreply@example.com',
|
|
106
142
|
};
|
|
107
143
|
}
|
|
144
|
+
function validateHooks(raw) {
|
|
145
|
+
if (!raw || typeof raw !== 'object')
|
|
146
|
+
return undefined;
|
|
147
|
+
const h = raw;
|
|
148
|
+
const result = {};
|
|
149
|
+
if (h.email && typeof h.email === 'object') {
|
|
150
|
+
const email = h.email;
|
|
151
|
+
if (email.enabled === true) {
|
|
152
|
+
if (typeof email.threadMapping !== 'string' || !email.threadMapping) {
|
|
153
|
+
throw new Error('gateway.config.json: hooks.email.threadMapping is required when enabled');
|
|
154
|
+
}
|
|
155
|
+
result.email = {
|
|
156
|
+
enabled: true,
|
|
157
|
+
provider: 'resend',
|
|
158
|
+
signingSecret: typeof email.signingSecret === 'string' ? email.signingSecret : undefined,
|
|
159
|
+
threadMapping: email.threadMapping,
|
|
160
|
+
defaultTemplate: typeof email.defaultTemplate === 'string' ? email.defaultTemplate : undefined,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (h.form && typeof h.form === 'object') {
|
|
165
|
+
const form = h.form;
|
|
166
|
+
if (form.enabled === true) {
|
|
167
|
+
if (typeof form.threadMapping !== 'string' || !form.threadMapping) {
|
|
168
|
+
throw new Error('gateway.config.json: hooks.form.threadMapping is required when enabled');
|
|
169
|
+
}
|
|
170
|
+
result.form = {
|
|
171
|
+
enabled: true,
|
|
172
|
+
threadMapping: form.threadMapping,
|
|
173
|
+
defaultTemplate: typeof form.defaultTemplate === 'string' ? form.defaultTemplate : undefined,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (h.webhooks && typeof h.webhooks === 'object') {
|
|
178
|
+
const webhooks = h.webhooks;
|
|
179
|
+
const validated = {};
|
|
180
|
+
for (const [name, cfg] of Object.entries(webhooks)) {
|
|
181
|
+
if (cfg && typeof cfg === 'object') {
|
|
182
|
+
const wh = cfg;
|
|
183
|
+
if (typeof wh.thread !== 'string' || !wh.thread) {
|
|
184
|
+
throw new Error(`gateway.config.json: hooks.webhooks.${name}.thread is required`);
|
|
185
|
+
}
|
|
186
|
+
validated[name] = {
|
|
187
|
+
thread: wh.thread,
|
|
188
|
+
template: typeof wh.template === 'string' ? wh.template : undefined,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (Object.keys(validated).length > 0) {
|
|
193
|
+
result.webhooks = validated;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
197
|
+
}
|
|
108
198
|
export function getConfigPath() {
|
|
109
199
|
return CONFIG_PATH;
|
|
110
200
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/gateway/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AACxD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,qBAAqB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/gateway/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/gateway/daemon.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/gateway/daemon.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AA+BH,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAoB,GAAG,IAAI,CAG5D;AAED,wBAAgB,WAAW,IAAI,MAAM,GAAG,IAAI,CAQ3C;AAED,wBAAgB,aAAa,IAAI,IAAI,CAMpC;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOrD;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAID,UAAU,UAAU;IAClB,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1D,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAoDpD"}
|
package/dist/gateway/daemon.js
CHANGED
|
@@ -12,15 +12,20 @@
|
|
|
12
12
|
import * as fs from 'fs';
|
|
13
13
|
import * as os from 'os';
|
|
14
14
|
import * as path from 'path';
|
|
15
|
+
import { drainActiveSubprocesses, getActiveSubprocessCount, getActiveThreadNames, recoverStreamingBuffers, sendMessage, } from '../lib/gateway.js';
|
|
15
16
|
import { createDiscordAdapter } from './adapters/discord.js';
|
|
16
17
|
import { createSlackAdapter } from './adapters/slack.js';
|
|
17
|
-
import { createWebChatAdapter
|
|
18
|
+
import { createWebChatAdapter } from './adapters/webchat.js';
|
|
18
19
|
import { loadGatewayConfig, getConfigPath } from './config.js';
|
|
19
20
|
import { createLogger, getDefaultLogPath } from './logger.js';
|
|
21
|
+
import { createScheduler } from './scheduler.js';
|
|
20
22
|
import { startGatewayServer } from './server.js';
|
|
21
23
|
const CUMULUS_DIR = path.join(os.homedir(), '.cumulus');
|
|
22
24
|
const PID_FILE = path.join(CUMULUS_DIR, 'gateway.pid');
|
|
23
|
-
|
|
25
|
+
// Read version from package.json at build time via import
|
|
26
|
+
import { createRequire } from 'module';
|
|
27
|
+
const _require = createRequire(import.meta.url);
|
|
28
|
+
const VERSION = _require('../../package.json').version;
|
|
24
29
|
// ─── PID file helpers ────────────────────────────────────────
|
|
25
30
|
export function writePidFile(pid = process.pid) {
|
|
26
31
|
fs.mkdirSync(CUMULUS_DIR, { recursive: true });
|
|
@@ -178,9 +183,21 @@ async function cmdStart(args) {
|
|
|
178
183
|
sharedMcpPort: config.sharedMcpPort,
|
|
179
184
|
projectRoot: config.projectRoot,
|
|
180
185
|
vapid: config.vapid,
|
|
186
|
+
hooks: config.hooks,
|
|
187
|
+
hfApiKey: config.hfApiKey,
|
|
188
|
+
models: config.models,
|
|
189
|
+
model: config.model,
|
|
181
190
|
gatewayAgentsConfig: {
|
|
182
191
|
apiUrl: `http://127.0.0.1:${port}`,
|
|
183
192
|
apiKey: config.apiKeys[0],
|
|
193
|
+
...(config.resend
|
|
194
|
+
? {
|
|
195
|
+
resendApiKey: config.resend.apiKey,
|
|
196
|
+
resendDefaultFrom: config.resend.defaultFrom,
|
|
197
|
+
resendReplyTo: config.resend.replyTo,
|
|
198
|
+
resendRateLimit: config.resend.rateLimit,
|
|
199
|
+
}
|
|
200
|
+
: {}),
|
|
184
201
|
},
|
|
185
202
|
});
|
|
186
203
|
}
|
|
@@ -250,8 +267,17 @@ async function cmdStart(args) {
|
|
|
250
267
|
gatewayAgentsConfig: {
|
|
251
268
|
apiUrl: `http://127.0.0.1:${port}`,
|
|
252
269
|
apiKey: config.apiKeys[0],
|
|
270
|
+
...(config.resend
|
|
271
|
+
? {
|
|
272
|
+
resendApiKey: config.resend.apiKey,
|
|
273
|
+
resendDefaultFrom: config.resend.defaultFrom,
|
|
274
|
+
resendReplyTo: config.resend.replyTo,
|
|
275
|
+
resendRateLimit: config.resend.rateLimit,
|
|
276
|
+
}
|
|
277
|
+
: {}),
|
|
253
278
|
},
|
|
254
279
|
executorRegistry: handle.executorRegistry,
|
|
280
|
+
hfApiKey: config.hfApiKey,
|
|
255
281
|
},
|
|
256
282
|
});
|
|
257
283
|
// Wire broadcast so agent inject messages reach connected web clients
|
|
@@ -265,6 +291,39 @@ async function cmdStart(args) {
|
|
|
265
291
|
if (foreground)
|
|
266
292
|
console.error(`[Gateway] WebChat adapter failed: ${err}`);
|
|
267
293
|
}
|
|
294
|
+
// Start scheduler engine (scans thread configs for schedules, manages timers)
|
|
295
|
+
let schedulerHandle;
|
|
296
|
+
try {
|
|
297
|
+
schedulerHandle = createScheduler({
|
|
298
|
+
pipelineOpts: {
|
|
299
|
+
claudePath: config.claudePath,
|
|
300
|
+
sharedMcpPort: config.sharedMcpPort,
|
|
301
|
+
projectRoot: config.projectRoot,
|
|
302
|
+
gatewayAgentsConfig: {
|
|
303
|
+
apiUrl: `http://127.0.0.1:${port}`,
|
|
304
|
+
apiKey: config.apiKeys[0],
|
|
305
|
+
...(config.resend
|
|
306
|
+
? {
|
|
307
|
+
resendApiKey: config.resend.apiKey,
|
|
308
|
+
resendDefaultFrom: config.resend.defaultFrom,
|
|
309
|
+
resendReplyTo: config.resend.replyTo,
|
|
310
|
+
resendRateLimit: config.resend.rateLimit,
|
|
311
|
+
}
|
|
312
|
+
: {}),
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
log: (msg, data) => logger.info(`[Scheduler] ${msg}`, data),
|
|
316
|
+
});
|
|
317
|
+
handle.setScheduler(schedulerHandle);
|
|
318
|
+
logger.info('Scheduler started');
|
|
319
|
+
if (foreground)
|
|
320
|
+
console.log('[Gateway] Scheduler started');
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
logger.error('Failed to start scheduler', { error: String(err) });
|
|
324
|
+
if (foreground)
|
|
325
|
+
console.error(`[Gateway] Scheduler failed: ${err}`);
|
|
326
|
+
}
|
|
268
327
|
const activeChannels = [slackAdapter && 'slack', discordAdapter && 'discord', webChatAdapter && 'webchat']
|
|
269
328
|
.filter(Boolean)
|
|
270
329
|
.join(', ') || 'none';
|
|
@@ -282,17 +341,23 @@ async function cmdStart(args) {
|
|
|
282
341
|
if (shuttingDown)
|
|
283
342
|
return;
|
|
284
343
|
shuttingDown = true;
|
|
285
|
-
|
|
344
|
+
const activeCount = getActiveSubprocessCount();
|
|
345
|
+
logger.info('Shutdown initiated', { signal, activeSubprocesses: activeCount });
|
|
286
346
|
if (foreground)
|
|
287
|
-
console.log(`\n[Gateway] ${signal} received,
|
|
288
|
-
// Stop
|
|
289
|
-
if (
|
|
347
|
+
console.log(`\n[Gateway] ${signal} received, draining ${activeCount} active streams...`);
|
|
348
|
+
// 0. Stop scheduler (no new triggers should fire during shutdown)
|
|
349
|
+
if (schedulerHandle) {
|
|
350
|
+
schedulerHandle.stop();
|
|
351
|
+
logger.info('Scheduler stopped');
|
|
352
|
+
}
|
|
353
|
+
// 1. Stop accepting new messages via channel adapters
|
|
354
|
+
if (slackAdapter) {
|
|
290
355
|
try {
|
|
291
|
-
await
|
|
292
|
-
logger.info('
|
|
356
|
+
await slackAdapter.stop();
|
|
357
|
+
logger.info('Slack adapter stopped');
|
|
293
358
|
}
|
|
294
359
|
catch (err) {
|
|
295
|
-
logger.error('Error stopping
|
|
360
|
+
logger.error('Error stopping Slack adapter', { error: String(err) });
|
|
296
361
|
}
|
|
297
362
|
}
|
|
298
363
|
if (discordAdapter) {
|
|
@@ -304,15 +369,58 @@ async function cmdStart(args) {
|
|
|
304
369
|
logger.error('Error stopping Discord adapter', { error: String(err) });
|
|
305
370
|
}
|
|
306
371
|
}
|
|
307
|
-
|
|
372
|
+
// 2. Wait for active Claude subprocesses to complete (up to 120s)
|
|
373
|
+
if (getActiveSubprocessCount() > 0) {
|
|
374
|
+
logger.info('Waiting for active subprocesses to complete...', {
|
|
375
|
+
count: getActiveSubprocessCount(),
|
|
376
|
+
});
|
|
377
|
+
if (foreground)
|
|
378
|
+
console.log(`[Gateway] Waiting for ${getActiveSubprocessCount()} active streams...`);
|
|
379
|
+
const drained = await drainActiveSubprocesses(120_000);
|
|
380
|
+
logger.info('Subprocess drain complete', { drained, remaining: getActiveSubprocessCount() });
|
|
381
|
+
if (foreground)
|
|
382
|
+
console.log(`[Gateway] Drained ${drained} streams, ${getActiveSubprocessCount()} remaining`);
|
|
383
|
+
}
|
|
384
|
+
// 2b. Record interrupted threads for auto-resume on next startup
|
|
385
|
+
const interruptedThreads = getActiveThreadNames();
|
|
386
|
+
const activeThreadsPath = path.join(CUMULUS_DIR, 'active-threads.json');
|
|
387
|
+
if (interruptedThreads.length > 0) {
|
|
388
|
+
const record = interruptedThreads.map(name => ({
|
|
389
|
+
threadName: name,
|
|
390
|
+
timestamp: new Date().toISOString(),
|
|
391
|
+
}));
|
|
308
392
|
try {
|
|
309
|
-
|
|
310
|
-
logger.info('
|
|
393
|
+
fs.writeFileSync(activeThreadsPath, JSON.stringify(record, null, 2));
|
|
394
|
+
logger.info('Recorded interrupted threads for auto-resume', {
|
|
395
|
+
threads: interruptedThreads,
|
|
396
|
+
});
|
|
397
|
+
if (foreground)
|
|
398
|
+
console.log(`[Gateway] Recorded ${interruptedThreads.length} interrupted thread(s) for auto-resume`);
|
|
311
399
|
}
|
|
312
400
|
catch (err) {
|
|
313
|
-
logger.error('
|
|
401
|
+
logger.error('Failed to write active-threads.json', { error: String(err) });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
// Clean up stale file if no interrupted threads
|
|
406
|
+
try {
|
|
407
|
+
fs.unlinkSync(activeThreadsPath);
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
// File didn't exist — fine
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
// 3. Stop webchat adapter (closes WebSocket connections)
|
|
414
|
+
if (webChatAdapter) {
|
|
415
|
+
try {
|
|
416
|
+
await webChatAdapter.stop();
|
|
417
|
+
logger.info('WebChat adapter stopped');
|
|
418
|
+
}
|
|
419
|
+
catch (err) {
|
|
420
|
+
logger.error('Error stopping WebChat adapter', { error: String(err) });
|
|
314
421
|
}
|
|
315
422
|
}
|
|
423
|
+
// 4. Close HTTP server
|
|
316
424
|
try {
|
|
317
425
|
await handle.close();
|
|
318
426
|
logger.info('Server closed');
|
|
@@ -320,8 +428,6 @@ async function cmdStart(args) {
|
|
|
320
428
|
catch (err) {
|
|
321
429
|
logger.error('Error during shutdown', { error: String(err) });
|
|
322
430
|
}
|
|
323
|
-
// Wait for in-flight messages to persist before exiting
|
|
324
|
-
await drainInflightMessages(30000);
|
|
325
431
|
removePidFile();
|
|
326
432
|
logger.info('Gateway stopped');
|
|
327
433
|
logger.close();
|
|
@@ -329,25 +435,163 @@ async function cmdStart(args) {
|
|
|
329
435
|
};
|
|
330
436
|
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
331
437
|
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
332
|
-
// SIGHUP =
|
|
438
|
+
// SIGHUP = graceful restart (drain active streams, then exit — systemd Restart=always brings it back with fresh code)
|
|
333
439
|
process.on('SIGHUP', async () => {
|
|
334
|
-
|
|
440
|
+
const activeCount = getActiveSubprocessCount();
|
|
441
|
+
logger.info('SIGHUP received — graceful restart', { activeSubprocesses: activeCount });
|
|
335
442
|
if (foreground)
|
|
336
|
-
console.log(
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
handle.updateApiKeys?.(newConfig.apiKeys);
|
|
341
|
-
logger.info('Config reloaded', { apiKeys: newConfig.apiKeys.length });
|
|
443
|
+
console.log(`\n[Gateway] SIGHUP received — graceful restart (${activeCount} active streams)`);
|
|
444
|
+
if (activeCount === 0) {
|
|
445
|
+
// No active streams — exit immediately, systemd restarts with fresh code
|
|
446
|
+
logger.info('No active streams, exiting for restart');
|
|
342
447
|
if (foreground)
|
|
343
|
-
console.log(
|
|
448
|
+
console.log('[Gateway] No active streams — restarting now');
|
|
449
|
+
removePidFile();
|
|
450
|
+
logger.close();
|
|
451
|
+
process.exit(0);
|
|
452
|
+
return;
|
|
344
453
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
454
|
+
// Active streams exist — drain them first
|
|
455
|
+
logger.info('Waiting for active subprocesses to drain before restart...', {
|
|
456
|
+
count: activeCount,
|
|
457
|
+
});
|
|
458
|
+
if (foreground)
|
|
459
|
+
console.log(`[Gateway] Waiting for ${activeCount} active stream(s) to complete...`);
|
|
460
|
+
const drained = await drainActiveSubprocesses(120_000);
|
|
461
|
+
const remaining = getActiveSubprocessCount();
|
|
462
|
+
logger.info('Drain complete, exiting for restart', { drained, remaining });
|
|
463
|
+
if (foreground)
|
|
464
|
+
console.log(`[Gateway] Drained ${drained} streams (${remaining} remaining) — restarting`);
|
|
465
|
+
// Record any threads that didn't complete for auto-resume
|
|
466
|
+
if (remaining > 0) {
|
|
467
|
+
const interruptedThreads = getActiveThreadNames();
|
|
468
|
+
const activeThreadsPath = path.join(CUMULUS_DIR, 'active-threads.json');
|
|
469
|
+
const record = interruptedThreads.map(name => ({
|
|
470
|
+
threadName: name,
|
|
471
|
+
timestamp: new Date().toISOString(),
|
|
472
|
+
}));
|
|
473
|
+
try {
|
|
474
|
+
fs.writeFileSync(activeThreadsPath, JSON.stringify(record, null, 2));
|
|
475
|
+
logger.info('Recorded interrupted threads for auto-resume', {
|
|
476
|
+
threads: interruptedThreads,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
catch (err) {
|
|
480
|
+
logger.error('Failed to write active-threads.json', { error: String(err) });
|
|
481
|
+
}
|
|
349
482
|
}
|
|
483
|
+
removePidFile();
|
|
484
|
+
logger.close();
|
|
485
|
+
process.exit(0);
|
|
350
486
|
});
|
|
487
|
+
// ─── Recover partial streaming responses from previous crash/restart ────────
|
|
488
|
+
try {
|
|
489
|
+
const recoveredCount = await recoverStreamingBuffers();
|
|
490
|
+
if (recoveredCount > 0) {
|
|
491
|
+
logger.info('Recovered partial streaming responses', { count: recoveredCount });
|
|
492
|
+
if (foreground)
|
|
493
|
+
console.log(`[Gateway] Recovered ${recoveredCount} partial streaming response(s) from disk`);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
catch (err) {
|
|
497
|
+
logger.error('Failed to recover streaming buffers', { error: String(err) });
|
|
498
|
+
// Non-fatal — gateway continues
|
|
499
|
+
}
|
|
500
|
+
// ─── Auto-resume interrupted threads from previous shutdown ────────
|
|
501
|
+
const resumedThreadNames = new Set(); // tracks threads that got full resume messages
|
|
502
|
+
const activeThreadsPath = path.join(CUMULUS_DIR, 'active-threads.json');
|
|
503
|
+
try {
|
|
504
|
+
if (fs.existsSync(activeThreadsPath)) {
|
|
505
|
+
const raw = JSON.parse(fs.readFileSync(activeThreadsPath, 'utf-8'));
|
|
506
|
+
const threads = Array.isArray(raw)
|
|
507
|
+
? raw
|
|
508
|
+
: [];
|
|
509
|
+
if (threads.length > 0) {
|
|
510
|
+
logger.info('Found interrupted threads from previous shutdown', {
|
|
511
|
+
count: threads.length,
|
|
512
|
+
threads: threads.map(t => t.threadName),
|
|
513
|
+
});
|
|
514
|
+
if (foreground)
|
|
515
|
+
console.log(`[Gateway] Resuming ${threads.length} interrupted thread(s): ${threads.map(t => t.threadName).join(', ')}`);
|
|
516
|
+
// Inject resume message into each interrupted thread (fire-and-forget)
|
|
517
|
+
for (const { threadName, timestamp } of threads) {
|
|
518
|
+
resumedThreadNames.add(threadName);
|
|
519
|
+
const resumeMsg = `[System] Gateway restarted at ${new Date().toISOString()}. ` +
|
|
520
|
+
`Your previous response was interrupted mid-stream (at ${timestamp}). ` +
|
|
521
|
+
`Please resume where you left off.`;
|
|
522
|
+
sendMessage({
|
|
523
|
+
threadName,
|
|
524
|
+
message: resumeMsg,
|
|
525
|
+
claudePath: config.claudePath,
|
|
526
|
+
sharedMcpPort: config.sharedMcpPort,
|
|
527
|
+
projectRoot: config.projectRoot,
|
|
528
|
+
hfApiKey: config.hfApiKey,
|
|
529
|
+
gatewayAgentsConfig: {
|
|
530
|
+
apiUrl: `http://127.0.0.1:${port}`,
|
|
531
|
+
apiKey: config.apiKeys[0],
|
|
532
|
+
},
|
|
533
|
+
})
|
|
534
|
+
.then(result => {
|
|
535
|
+
logger.info('Auto-resume completed', {
|
|
536
|
+
threadName,
|
|
537
|
+
responseChars: result?.response?.length ?? 0,
|
|
538
|
+
});
|
|
539
|
+
})
|
|
540
|
+
.catch(err => {
|
|
541
|
+
logger.error('Auto-resume failed', {
|
|
542
|
+
threadName,
|
|
543
|
+
error: String(err),
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
// Clean up the file regardless of outcome
|
|
549
|
+
fs.unlinkSync(activeThreadsPath);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
catch (err) {
|
|
553
|
+
logger.error('Failed to process active-threads.json', { error: String(err) });
|
|
554
|
+
// Non-fatal — gateway continues without resume
|
|
555
|
+
}
|
|
556
|
+
// Delayed restart notification for threads that reconnect but weren't actively streaming.
|
|
557
|
+
// Covers both cases: active-threads.json existed (some threads already got resume) or didn't.
|
|
558
|
+
setTimeout(() => {
|
|
559
|
+
if (!webChatAdapter)
|
|
560
|
+
return;
|
|
561
|
+
const connectedThreads = webChatAdapter.getConnectedThreadNames();
|
|
562
|
+
if (connectedThreads.length === 0)
|
|
563
|
+
return;
|
|
564
|
+
const restartTimestamp = new Date().toISOString();
|
|
565
|
+
let notified = 0;
|
|
566
|
+
for (const threadName of connectedThreads) {
|
|
567
|
+
// Skip threads that already got a full sendMessage resume from active-threads.json
|
|
568
|
+
if (resumedThreadNames.has(threadName))
|
|
569
|
+
continue;
|
|
570
|
+
const notifyMsg = `[System] Gateway restarted at ${restartTimestamp}. ` +
|
|
571
|
+
`If your previous response was interrupted, please let me know and I'll resume.`;
|
|
572
|
+
sendMessage({
|
|
573
|
+
threadName,
|
|
574
|
+
message: notifyMsg,
|
|
575
|
+
claudePath: config.claudePath,
|
|
576
|
+
sharedMcpPort: config.sharedMcpPort,
|
|
577
|
+
projectRoot: config.projectRoot,
|
|
578
|
+
hfApiKey: config.hfApiKey,
|
|
579
|
+
gatewayAgentsConfig: {
|
|
580
|
+
apiUrl: `http://127.0.0.1:${port}`,
|
|
581
|
+
apiKey: config.apiKeys[0],
|
|
582
|
+
},
|
|
583
|
+
}).catch(err => {
|
|
584
|
+
logger.error('Restart notification failed', { threadName, error: String(err) });
|
|
585
|
+
});
|
|
586
|
+
notified++;
|
|
587
|
+
}
|
|
588
|
+
if (notified > 0) {
|
|
589
|
+
logger.info('Sent restart notifications to reconnected threads', {
|
|
590
|
+
count: notified,
|
|
591
|
+
threads: connectedThreads.filter(t => !resumedThreadNames.has(t)),
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
}, 5000);
|
|
351
595
|
}
|
|
352
596
|
function cmdStop() {
|
|
353
597
|
const pid = readPidFile();
|