@chrisromp/copilot-bridge 0.6.0-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/bin/copilot-bridge.js +61 -0
  4. package/config.sample.json +100 -0
  5. package/dist/channels/mattermost/adapter.d.ts +55 -0
  6. package/dist/channels/mattermost/adapter.d.ts.map +1 -0
  7. package/dist/channels/mattermost/adapter.js +524 -0
  8. package/dist/channels/mattermost/adapter.js.map +1 -0
  9. package/dist/channels/mattermost/streaming.d.ts +29 -0
  10. package/dist/channels/mattermost/streaming.d.ts.map +1 -0
  11. package/dist/channels/mattermost/streaming.js +151 -0
  12. package/dist/channels/mattermost/streaming.js.map +1 -0
  13. package/dist/config.d.ts +107 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +817 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/core/bridge.d.ts +73 -0
  18. package/dist/core/bridge.d.ts.map +1 -0
  19. package/dist/core/bridge.js +166 -0
  20. package/dist/core/bridge.js.map +1 -0
  21. package/dist/core/channel-idle.d.ts +40 -0
  22. package/dist/core/channel-idle.d.ts.map +1 -0
  23. package/dist/core/channel-idle.js +120 -0
  24. package/dist/core/channel-idle.js.map +1 -0
  25. package/dist/core/command-handler.d.ts +51 -0
  26. package/dist/core/command-handler.d.ts.map +1 -0
  27. package/dist/core/command-handler.js +393 -0
  28. package/dist/core/command-handler.js.map +1 -0
  29. package/dist/core/inter-agent.d.ts +52 -0
  30. package/dist/core/inter-agent.d.ts.map +1 -0
  31. package/dist/core/inter-agent.js +179 -0
  32. package/dist/core/inter-agent.js.map +1 -0
  33. package/dist/core/onboarding.d.ts +44 -0
  34. package/dist/core/onboarding.d.ts.map +1 -0
  35. package/dist/core/onboarding.js +205 -0
  36. package/dist/core/onboarding.js.map +1 -0
  37. package/dist/core/scheduler.d.ts +38 -0
  38. package/dist/core/scheduler.d.ts.map +1 -0
  39. package/dist/core/scheduler.js +253 -0
  40. package/dist/core/scheduler.js.map +1 -0
  41. package/dist/core/session-manager.d.ts +166 -0
  42. package/dist/core/session-manager.d.ts.map +1 -0
  43. package/dist/core/session-manager.js +1732 -0
  44. package/dist/core/session-manager.js.map +1 -0
  45. package/dist/core/stream-formatter.d.ts +14 -0
  46. package/dist/core/stream-formatter.d.ts.map +1 -0
  47. package/dist/core/stream-formatter.js +198 -0
  48. package/dist/core/stream-formatter.js.map +1 -0
  49. package/dist/core/thread-utils.d.ts +22 -0
  50. package/dist/core/thread-utils.d.ts.map +1 -0
  51. package/dist/core/thread-utils.js +44 -0
  52. package/dist/core/thread-utils.js.map +1 -0
  53. package/dist/core/workspace-manager.d.ts +38 -0
  54. package/dist/core/workspace-manager.d.ts.map +1 -0
  55. package/dist/core/workspace-manager.js +230 -0
  56. package/dist/core/workspace-manager.js.map +1 -0
  57. package/dist/index.d.ts +2 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +1286 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/logger.d.ts +9 -0
  62. package/dist/logger.d.ts.map +1 -0
  63. package/dist/logger.js +34 -0
  64. package/dist/logger.js.map +1 -0
  65. package/dist/state/store.d.ts +124 -0
  66. package/dist/state/store.d.ts.map +1 -0
  67. package/dist/state/store.js +523 -0
  68. package/dist/state/store.js.map +1 -0
  69. package/dist/types.d.ts +185 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/types.js +2 -0
  72. package/dist/types.js.map +1 -0
  73. package/package.json +61 -0
  74. package/scripts/check.ts +267 -0
  75. package/scripts/com.copilot-bridge.plist +41 -0
  76. package/scripts/copilot-bridge.service +30 -0
  77. package/scripts/init.ts +250 -0
  78. package/scripts/install-service.ts +123 -0
  79. package/scripts/lib/config-gen.ts +129 -0
  80. package/scripts/lib/mattermost.ts +109 -0
  81. package/scripts/lib/output.ts +69 -0
  82. package/scripts/lib/prerequisites.ts +86 -0
  83. package/scripts/lib/prompts.ts +65 -0
  84. package/scripts/lib/service.ts +191 -0
  85. package/scripts/uninstall-service.ts +90 -0
  86. package/templates/admin/AGENTS.md +325 -0
  87. package/templates/admin/MEMORY.md +4 -0
  88. package/templates/agents/AGENTS.md +97 -0
  89. package/templates/agents/MEMORY.md +4 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inter-agent.js","sourceRoot":"","sources":["../../src/core/inter-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Project onboarding orchestration.
3
+ *
4
+ * Provides the logic for creating a project: Mattermost channel creation,
5
+ * bot assignment, workspace setup, optional repo clone, and dynamic channel registration.
6
+ */
7
+ import type { ChannelAdapter } from '../types.js';
8
+ export interface OnboardProjectOpts {
9
+ /** Project name (used for channel name slug and display) */
10
+ projectName: string;
11
+ /** Bot name to assign (key into platform.bots) */
12
+ botName: string;
13
+ /** Platform name */
14
+ platform: string;
15
+ /** Mattermost team ID */
16
+ teamId: string;
17
+ /** Private channel (default true) */
18
+ private?: boolean;
19
+ /** Custom workspace path (default: ~/.copilot-bridge/workspaces/<projectName>/) */
20
+ workspacePath?: string;
21
+ /** Git repo URL to clone into workspace */
22
+ repoUrl?: string;
23
+ /** User ID to add to the channel */
24
+ userId?: string;
25
+ /** Trigger mode (default: from config defaults) */
26
+ triggerMode?: 'mention' | 'all';
27
+ /** Threaded replies (default: from config defaults) */
28
+ threadedReplies?: boolean;
29
+ }
30
+ export interface OnboardResult {
31
+ channelId: string;
32
+ channelName: string;
33
+ workspacePath: string;
34
+ cloned: boolean;
35
+ steps: string[];
36
+ }
37
+ /** Slugify a project name for use as a Mattermost channel name. */
38
+ export declare function slugify(name: string): string;
39
+ /**
40
+ * Run the full project onboarding flow.
41
+ * Returns a result describing what was created.
42
+ */
43
+ export declare function onboardProject(adapter: ChannelAdapter, opts: OnboardProjectOpts): Promise<OnboardResult>;
44
+ //# sourceMappingURL=onboarding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/core/onboarding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,cAAc,EAA2D,MAAM,aAAa,CAAC;AAI3G,MAAM,WAAW,kBAAkB;IACjC,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,WAAW,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IAChC,uDAAuD;IACvD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,mEAAmE;AACnE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO5C;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,aAAa,CAAC,CAmKxB"}
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Project onboarding orchestration.
3
+ *
4
+ * Provides the logic for creating a project: Mattermost channel creation,
5
+ * bot assignment, workspace setup, optional repo clone, and dynamic channel registration.
6
+ */
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import { execFileSync } from 'node:child_process';
10
+ import { createLogger } from '../logger.js';
11
+ import { initWorkspace } from './workspace-manager.js';
12
+ import { addDynamicChannel } from '../state/store.js';
13
+ import { getConfig, registerDynamicChannel } from '../config.js';
14
+ const log = createLogger('onboarding');
15
+ /** Slugify a project name for use as a Mattermost channel name. */
16
+ export function slugify(name) {
17
+ return name
18
+ .toLowerCase()
19
+ .replace(/[^a-z0-9-]/g, '-')
20
+ .replace(/-+/g, '-')
21
+ .replace(/^-|-$/g, '')
22
+ .slice(0, 64);
23
+ }
24
+ /**
25
+ * Run the full project onboarding flow.
26
+ * Returns a result describing what was created.
27
+ */
28
+ export async function onboardProject(adapter, opts) {
29
+ const steps = [];
30
+ const slug = slugify(opts.projectName);
31
+ if (!slug)
32
+ throw new Error('Project name must contain at least one alphanumeric character');
33
+ const isPrivate = opts.private !== false;
34
+ const config = getConfig();
35
+ // Validate platform and bot exist
36
+ const platform = config.platforms[opts.platform];
37
+ if (!platform)
38
+ throw new Error(`Unknown platform "${opts.platform}"`);
39
+ if (opts.botName && platform.bots && !platform.bots[opts.botName]) {
40
+ throw new Error(`Unknown bot "${opts.botName}" on platform "${opts.platform}"`);
41
+ }
42
+ // 1. Check if channel exists, create if not
43
+ let channelId;
44
+ let channelName = slug;
45
+ if (!adapter.getChannelByName || !adapter.createChannel || !adapter.addUserToChannel) {
46
+ throw new Error('Platform adapter does not support channel management');
47
+ }
48
+ const existing = await adapter.getChannelByName(opts.teamId, slug);
49
+ if (existing) {
50
+ channelId = existing.id;
51
+ channelName = existing.name;
52
+ steps.push(`Joined existing channel #${channelName}`);
53
+ log.info(`Channel #${channelName} already exists (${channelId}), joining`);
54
+ }
55
+ else {
56
+ channelId = await adapter.createChannel({
57
+ name: slug,
58
+ displayName: opts.projectName,
59
+ private: isPrivate,
60
+ teamId: opts.teamId,
61
+ });
62
+ steps.push(`Created ${isPrivate ? 'private' : 'public'} channel #${slug}`);
63
+ log.info(`Created channel #${slug} (${channelId})`);
64
+ }
65
+ // 2. Add bot to channel
66
+ const botConfig = opts.botName && platform.bots?.[opts.botName];
67
+ if (botConfig) {
68
+ // We need the bot's user ID — create a temporary connection to get it
69
+ // For now, we pass it through the adapter since admin bot is making the calls
70
+ // The adapter.addUserToChannel handles team membership automatically
71
+ try {
72
+ // Get bot user ID by looking up the username via MM API
73
+ const botUserId = await lookupBotUserId(adapter, opts.botName);
74
+ if (botUserId) {
75
+ await adapter.addUserToChannel(channelId, botUserId);
76
+ steps.push(`Added @${opts.botName} to channel`);
77
+ }
78
+ else {
79
+ steps.push(`⚠️ Could not find bot user @${opts.botName} — add manually`);
80
+ }
81
+ }
82
+ catch (err) {
83
+ steps.push(`⚠️ Could not add bot: ${err?.message ?? 'unknown error'}`);
84
+ log.warn(`Failed to add bot ${opts.botName} to channel:`, err);
85
+ }
86
+ }
87
+ // 3. Add requesting user to channel
88
+ if (opts.userId) {
89
+ try {
90
+ await adapter.addUserToChannel(channelId, opts.userId);
91
+ steps.push(`Added you to channel`);
92
+ }
93
+ catch (err) {
94
+ // User might already be in the channel
95
+ log.debug(`Could not add user ${opts.userId}: ${err?.message}`);
96
+ }
97
+ }
98
+ // 4. Set up workspace
99
+ const defaultWorkspace = path.join(process.env.HOME ?? '/tmp', '.copilot-bridge', 'workspaces', slug);
100
+ let workspacePath = opts.workspacePath ?? defaultWorkspace;
101
+ // Expand ~ to home directory (Node fs APIs don't expand tilde)
102
+ if (workspacePath.startsWith('~/')) {
103
+ workspacePath = path.join(process.env.HOME ?? '/tmp', workspacePath.slice(2));
104
+ }
105
+ // 5. Clone repo if provided (before template overlay)
106
+ let cloned = false;
107
+ if (opts.repoUrl) {
108
+ if (!fs.existsSync(workspacePath)) {
109
+ fs.mkdirSync(workspacePath, { recursive: true });
110
+ }
111
+ try {
112
+ // Check if directory is empty or doesn't have .git
113
+ const hasGit = fs.existsSync(path.join(workspacePath, '.git'));
114
+ if (hasGit) {
115
+ steps.push(`Workspace already has a git repo — skipping clone`);
116
+ }
117
+ else {
118
+ const isEmpty = fs.readdirSync(workspacePath).length === 0;
119
+ if (isEmpty) {
120
+ execFileSync('git', ['clone', opts.repoUrl, '.'], { cwd: workspacePath, stdio: 'pipe' });
121
+ }
122
+ else {
123
+ // Non-empty, non-git dir: init, add remote, fetch, and checkout default branch
124
+ execFileSync('git', ['init'], { cwd: workspacePath, stdio: 'pipe' });
125
+ execFileSync('git', ['remote', 'add', 'origin', opts.repoUrl], { cwd: workspacePath, stdio: 'pipe' });
126
+ execFileSync('git', ['fetch', 'origin'], { cwd: workspacePath, stdio: 'pipe' });
127
+ try {
128
+ execFileSync('git', ['checkout', '-t', 'origin/main'], { cwd: workspacePath, stdio: 'pipe' });
129
+ }
130
+ catch {
131
+ execFileSync('git', ['checkout', '-t', 'origin/master'], { cwd: workspacePath, stdio: 'pipe' });
132
+ }
133
+ }
134
+ cloned = true;
135
+ steps.push(`Cloned ${opts.repoUrl}`);
136
+ log.info(`Cloned ${opts.repoUrl} into ${workspacePath}`);
137
+ }
138
+ }
139
+ catch (err) {
140
+ steps.push(`⚠️ Clone failed: ${err?.message ?? 'unknown error'}`);
141
+ log.error(`Failed to clone ${opts.repoUrl}:`, err);
142
+ }
143
+ }
144
+ // 6. Initialize workspace with templates (conflict-aware)
145
+ if (!fs.existsSync(workspacePath)) {
146
+ fs.mkdirSync(workspacePath, { recursive: true });
147
+ }
148
+ // initWorkspace handles AGENTS.md and MEMORY.md creation (skips if exists)
149
+ try {
150
+ initWorkspace(opts.botName ?? 'copilot', workspacePath, false);
151
+ steps.push(`Workspace initialized at ${workspacePath}`);
152
+ }
153
+ catch (err) {
154
+ steps.push(`⚠️ Workspace init warning: ${err?.message}`);
155
+ log.warn(`Workspace init issue:`, err);
156
+ }
157
+ // 7. Register dynamic channel
158
+ const triggerMode = opts.triggerMode ?? config.defaults.triggerMode;
159
+ const threadedReplies = opts.threadedReplies ?? config.defaults.threadedReplies;
160
+ addDynamicChannel({
161
+ channelId,
162
+ platform: opts.platform,
163
+ name: channelName,
164
+ bot: opts.botName,
165
+ workingDirectory: workspacePath,
166
+ isDM: false,
167
+ triggerMode,
168
+ threadedReplies,
169
+ });
170
+ // Also register in-memory so it's immediately available
171
+ registerDynamicChannel({
172
+ id: channelId,
173
+ platform: opts.platform,
174
+ name: channelName,
175
+ bot: opts.botName,
176
+ workingDirectory: workspacePath,
177
+ triggerMode,
178
+ threadedReplies,
179
+ verbose: config.defaults.verbose,
180
+ });
181
+ steps.push(`Channel registered — bot is live`);
182
+ log.info(`Onboarding complete: #${channelName} → ${opts.botName} → ${workspacePath}`);
183
+ return { channelId, channelName, workspacePath, cloned, steps };
184
+ }
185
+ /** Look up a bot's Mattermost user ID by username. */
186
+ async function lookupBotUserId(adapter, botName) {
187
+ try {
188
+ // Use the adapter's underlying client to search for the user
189
+ const baseUrl = adapter.client?.getBaseRoute?.();
190
+ const token = adapter.token;
191
+ if (!baseUrl || !token)
192
+ return null;
193
+ const resp = await fetch(`${baseUrl}/users/username/${botName}`, {
194
+ headers: { 'Authorization': `Bearer ${token}` },
195
+ });
196
+ if (!resp.ok)
197
+ return null;
198
+ const user = await resp.json();
199
+ return user.id;
200
+ }
201
+ catch {
202
+ return null;
203
+ }
204
+ }
205
+ //# sourceMappingURL=onboarding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.js","sourceRoot":"","sources":["../../src/core/onboarding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAGjE,MAAM,GAAG,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;AAiCvC,mEAAmE;AACnE,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,IAAI;SACR,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAuB,EACvB,IAAwB;IAExB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACvC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;IAC5F,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC;IACzC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,kCAAkC;IAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;IACtE,IAAI,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,OAAO,kBAAkB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;IAClF,CAAC;IAED,4CAA4C;IAC5C,IAAI,SAAiB,CAAC;IACtB,IAAI,WAAW,GAAG,IAAI,CAAC;IAEvB,IAAI,CAAC,OAAO,CAAC,gBAAgB,IAAI,CAAC,OAAO,CAAC,aAAa,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;QACrF,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnE,IAAI,QAAQ,EAAE,CAAC;QACb,SAAS,GAAG,QAAQ,CAAC,EAAE,CAAC;QACxB,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,4BAA4B,WAAW,EAAE,CAAC,CAAC;QACtD,GAAG,CAAC,IAAI,CAAC,YAAY,WAAW,oBAAoB,SAAS,YAAY,CAAC,CAAC;IAC7E,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC;YACtC,IAAI,EAAE,IAAI;YACV,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,WAAW,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,aAAa,IAAI,EAAE,CAAC,CAAC;QAC3E,GAAG,CAAC,IAAI,CAAC,oBAAoB,IAAI,KAAK,SAAS,GAAG,CAAC,CAAC;IACtD,CAAC;IAED,wBAAwB;IACxB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAChE,IAAI,SAAS,EAAE,CAAC;QACd,sEAAsE;QACtE,8EAA8E;QAC9E,qEAAqE;QACrE,IAAI,CAAC;YACH,wDAAwD;YACxD,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAC/D,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;gBACrD,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,aAAa,CAAC,CAAC;YAClD,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC,+BAA+B,IAAI,CAAC,OAAO,iBAAiB,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,KAAK,CAAC,IAAI,CAAC,yBAAyB,GAAG,EAAE,OAAO,IAAI,eAAe,EAAE,CAAC,CAAC;YACvE,GAAG,CAAC,IAAI,CAAC,qBAAqB,IAAI,CAAC,OAAO,cAAc,EAAE,GAAG,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAED,oCAAoC;IACpC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACvD,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,uCAAuC;YACvC,GAAG,CAAC,KAAK,CAAC,sBAAsB,IAAI,CAAC,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAED,sBAAsB;IACtB,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAChC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAC1B,iBAAiB,EAAE,YAAY,EAAE,IAAI,CACtC,CAAC;IACF,IAAI,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,gBAAgB,CAAC;IAC3D,+DAA+D;IAC/D,IAAI,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,sDAAsD;IACtD,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAClC,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,CAAC;QACD,IAAI,CAAC;YACH,mDAAmD;YACnD,MAAM,MAAM,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;YAC/D,IAAI,MAAM,EAAE,CAAC;gBACX,KAAK,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;YAClE,CAAC;iBAAM,CAAC;gBACN,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;gBAC3D,IAAI,OAAO,EAAE,CAAC;oBACZ,YAAY,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC3F,CAAC;qBAAM,CAAC;oBACN,+EAA+E;oBAC/E,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;oBACrE,YAAY,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;oBACtG,YAAY,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;oBAChF,IAAI,CAAC;wBACH,YAAY,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,IAAI,EAAE,aAAa,CAAC,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;oBAChG,CAAC;oBAAC,MAAM,CAAC;wBACP,YAAY,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,IAAI,EAAE,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;oBAClG,CAAC;gBACH,CAAC;gBACD,MAAM,GAAG,IAAI,CAAC;gBACd,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;gBACrC,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,SAAS,aAAa,EAAE,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,KAAK,CAAC,IAAI,CAAC,oBAAoB,GAAG,EAAE,OAAO,IAAI,eAAe,EAAE,CAAC,CAAC;YAClE,GAAG,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,0DAA0D;IAC1D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAClC,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,2EAA2E;IAC3E,IAAI,CAAC;QACH,aAAa,CAAC,IAAI,CAAC,OAAO,IAAI,SAAS,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,4BAA4B,aAAa,EAAE,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,8BAA8B,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;QACzD,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,8BAA8B;IAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;IACpE,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC;IAEhF,iBAAiB,CAAC;QAChB,SAAS;QACT,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,IAAI,EAAE,WAAW;QACjB,GAAG,EAAE,IAAI,CAAC,OAAO;QACjB,gBAAgB,EAAE,aAAa;QAC/B,IAAI,EAAE,KAAK;QACX,WAAW;QACX,eAAe;KAChB,CAAC,CAAC;IAEH,wDAAwD;IACxD,sBAAsB,CAAC;QACrB,EAAE,EAAE,SAAS;QACb,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,IAAI,EAAE,WAAW;QACjB,GAAG,EAAE,IAAI,CAAC,OAAO;QACjB,gBAAgB,EAAE,aAAa;QAC/B,WAAW;QACX,eAAe;QACf,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO;KAChB,CAAC,CAAC;IAEpB,KAAK,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAC/C,GAAG,CAAC,IAAI,CAAC,yBAAyB,WAAW,MAAM,IAAI,CAAC,OAAO,MAAM,aAAa,EAAE,CAAC,CAAC;IAEtF,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAClE,CAAC;AAED,sDAAsD;AACtD,KAAK,UAAU,eAAe,CAAC,OAAuB,EAAE,OAAe;IACrE,IAAI,CAAC;QACH,6DAA6D;QAC7D,MAAM,OAAO,GAAI,OAAe,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC;QAC1D,MAAM,KAAK,GAAI,OAAe,CAAC,KAAK,CAAC;QACrC,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAEpC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,mBAAmB,OAAO,EAAE,EAAE;YAC/D,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,KAAK,EAAE,EAAE;SAChD,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAC1B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAoB,CAAC;QACjD,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { type ScheduledTask } from '../state/store.js';
2
+ interface SchedulerDeps {
3
+ /** Send a prompt to a channel's session (creates/resumes as needed). */
4
+ sendMessage: (channelId: string, prompt: string) => Promise<string>;
5
+ /** Post a notification to a channel (no LLM, just a message). */
6
+ postMessage: (channelId: string, text: string) => Promise<void>;
7
+ }
8
+ /** Format a timestamp (ISO or SQLite datetime) in the given IANA timezone for display. */
9
+ export declare function formatInTimezone(timestamp: string, timezone: string): string;
10
+ /** Convert a cron expression to a human-readable description. */
11
+ export declare function describeCron(cronExpr: string): string;
12
+ /** Initialize the scheduler — load persisted jobs and start them. */
13
+ export declare function initScheduler(schedulerDeps: SchedulerDeps): void;
14
+ /** Create and persist a new scheduled task. */
15
+ export declare function addJob(opts: {
16
+ channelId: string;
17
+ botName: string;
18
+ prompt: string;
19
+ cronExpr?: string;
20
+ runAt?: string;
21
+ timezone?: string;
22
+ createdBy?: string;
23
+ description?: string;
24
+ }): ScheduledTask;
25
+ /** Remove a job (stops and deletes from DB). Optionally scoped to a channel. */
26
+ export declare function removeJob(id: string, channelId?: string): boolean;
27
+ /** Pause a job (stops timer, keeps in DB). Optionally scoped to a channel. */
28
+ export declare function pauseJob(id: string, channelId?: string): boolean;
29
+ /** Resume a paused job. Optionally scoped to a channel. */
30
+ export declare function resumeJob(id: string, channelId?: string): boolean;
31
+ /** List jobs for a channel (or all if no channelId). */
32
+ export declare function listJobs(channelId?: string): ScheduledTask[];
33
+ /** Get a job by ID. */
34
+ export declare function getJob(id: string): ScheduledTask | null;
35
+ /** Stop all active jobs (for shutdown). */
36
+ export declare function stopAll(): void;
37
+ export {};
38
+ //# sourceMappingURL=scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/core/scheduler.ts"],"names":[],"mappings":"AAKA,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAI3B,UAAU,aAAa;IACrB,wEAAwE;IACxE,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,iEAAiE;IACjE,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACjE;AAKD,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK5E;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMrD;AAID,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,aAAa,EAAE,aAAa,GAAG,IAAI,CA6ChE;AAED,+CAA+C;AAC/C,wBAAgB,MAAM,CAAC,IAAI,EAAE;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,aAAa,CA6ChB;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAYjE;AAED,8EAA8E;AAC9E,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAYhE;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAcjE;AAED,wDAAwD;AACxD,wBAAgB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CAG5D;AAED,uBAAuB;AACvB,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAEvD;AAED,2CAA2C;AAC3C,wBAAgB,OAAO,IAAI,IAAI,CAM9B"}
@@ -0,0 +1,253 @@
1
+ import { CronJob } from 'cron';
2
+ import cronstrue from 'cronstrue';
3
+ import crypto from 'node:crypto';
4
+ import { DateTime } from 'luxon';
5
+ import { createLogger } from '../logger.js';
6
+ import { getEnabledScheduledTasks, insertScheduledTask, deleteScheduledTask, updateScheduledTaskEnabled, updateScheduledTaskLastRun, getScheduledTasksForChannel, getScheduledTask, insertTaskHistory, } from '../state/store.js';
7
+ const log = createLogger('scheduler');
8
+ // Active CronJob instances keyed by task ID
9
+ const activeJobs = new Map();
10
+ /** Format a timestamp (ISO or SQLite datetime) in the given IANA timezone for display. */
11
+ export function formatInTimezone(timestamp, timezone) {
12
+ // SQLite datetime('now') produces "2026-03-08 22:57:06" — normalize to ISO
13
+ const normalized = timestamp.includes('T') ? timestamp : timestamp.replace(' ', 'T') + 'Z';
14
+ const dt = DateTime.fromISO(normalized, { zone: 'utc' }).setZone(timezone);
15
+ return dt.toLocaleString(DateTime.DATETIME_FULL);
16
+ }
17
+ /** Convert a cron expression to a human-readable description. */
18
+ export function describeCron(cronExpr) {
19
+ try {
20
+ return cronstrue.toString(cronExpr, { use24HourTimeFormat: false });
21
+ }
22
+ catch {
23
+ return cronExpr;
24
+ }
25
+ }
26
+ let deps = null;
27
+ /** Initialize the scheduler — load persisted jobs and start them. */
28
+ export function initScheduler(schedulerDeps) {
29
+ deps = schedulerDeps;
30
+ const tasks = getEnabledScheduledTasks();
31
+ let started = 0;
32
+ let missed = 0;
33
+ const missedByChannel = new Map();
34
+ for (const task of tasks) {
35
+ // One-off jobs with run_at in the past — notify instead of executing
36
+ if (task.runAt && new Date(task.runAt) <= new Date()) {
37
+ missed++;
38
+ const list = missedByChannel.get(task.channelId) ?? [];
39
+ list.push(task.description ?? task.prompt.slice(0, 60));
40
+ missedByChannel.set(task.channelId, list);
41
+ // Delete the one-off (it won't run again)
42
+ deleteScheduledTask(task.id);
43
+ continue;
44
+ }
45
+ try {
46
+ startJob(task);
47
+ started++;
48
+ }
49
+ catch (err) {
50
+ log.error(`Failed to start job ${task.id}: ${err?.message}`);
51
+ }
52
+ }
53
+ // Notify channels and log one consolidated history entry per channel
54
+ for (const [channelId, descriptions] of missedByChannel) {
55
+ const summary = descriptions.length === 1
56
+ ? descriptions[0]
57
+ : `${descriptions.length} tasks: ${descriptions.join(', ')}`;
58
+ insertTaskHistory({
59
+ taskId: 'system', channelId,
60
+ prompt: summary, description: `Missed while offline`,
61
+ timezone: 'UTC',
62
+ status: 'error', error: `Bridge was offline — ${summary}`,
63
+ });
64
+ const msg = `⏰ **Missed ${descriptions.length} scheduled task(s)** while offline:\n${descriptions.map(d => `- ${d}`).join('\n')}`;
65
+ deps.postMessage(channelId, msg).catch(err => log.error(`Failed to notify channel about missed jobs:`, err));
66
+ }
67
+ log.info(`Scheduler initialized: ${started} job(s) started, ${missed} missed`);
68
+ }
69
+ /** Create and persist a new scheduled task. */
70
+ export function addJob(opts) {
71
+ if (!opts.cronExpr && !opts.runAt) {
72
+ throw new Error('Either cronExpr or runAt must be provided');
73
+ }
74
+ if (opts.cronExpr && opts.runAt) {
75
+ throw new Error('Provide either cronExpr or runAt, not both');
76
+ }
77
+ // Short, human-friendly ID (6 alphanumeric chars)
78
+ const id = crypto.randomBytes(4).toString('base64url').slice(0, 6);
79
+ const timezone = opts.timezone ?? 'UTC';
80
+ // Compute next run time (also validates cron expression / timezone)
81
+ let nextRun;
82
+ if (opts.runAt) {
83
+ const parsed = new Date(opts.runAt);
84
+ if (isNaN(parsed.getTime()))
85
+ throw new Error(`Invalid run_at datetime: ${opts.runAt}`);
86
+ if (parsed <= new Date())
87
+ throw new Error(`run_at must be in the future (got ${opts.runAt})`);
88
+ nextRun = parsed.toISOString();
89
+ }
90
+ else if (opts.cronExpr) {
91
+ // Throws if cron expression or timezone is invalid — before we persist anything
92
+ const probe = CronJob.from({ cronTime: opts.cronExpr, onTick: () => { }, timeZone: timezone });
93
+ nextRun = probe.nextDate().toISO() ?? undefined;
94
+ probe.stop();
95
+ }
96
+ const task = {
97
+ id,
98
+ channelId: opts.channelId,
99
+ botName: opts.botName,
100
+ prompt: opts.prompt,
101
+ cronExpr: opts.cronExpr,
102
+ runAt: opts.runAt,
103
+ timezone,
104
+ createdBy: opts.createdBy,
105
+ description: opts.description,
106
+ enabled: true,
107
+ nextRun,
108
+ createdAt: new Date().toISOString(),
109
+ };
110
+ insertScheduledTask(task);
111
+ startJob(task);
112
+ log.info(`Job ${id} created: ${opts.description ?? opts.cronExpr ?? opts.runAt}`);
113
+ return task;
114
+ }
115
+ /** Remove a job (stops and deletes from DB). Optionally scoped to a channel. */
116
+ export function removeJob(id, channelId) {
117
+ const task = getScheduledTask(id);
118
+ if (!task)
119
+ return false;
120
+ if (channelId && task.channelId !== channelId)
121
+ return false;
122
+ const existing = activeJobs.get(id);
123
+ if (existing) {
124
+ existing.stop();
125
+ activeJobs.delete(id);
126
+ }
127
+ deleteScheduledTask(id);
128
+ log.info(`Job ${id} removed`);
129
+ return true;
130
+ }
131
+ /** Pause a job (stops timer, keeps in DB). Optionally scoped to a channel. */
132
+ export function pauseJob(id, channelId) {
133
+ const task = getScheduledTask(id);
134
+ if (!task)
135
+ return false;
136
+ if (channelId && task.channelId !== channelId)
137
+ return false;
138
+ const job = activeJobs.get(id);
139
+ if (job) {
140
+ job.stop();
141
+ activeJobs.delete(id);
142
+ }
143
+ updateScheduledTaskEnabled(id, false);
144
+ log.info(`Job ${id} paused`);
145
+ return true;
146
+ }
147
+ /** Resume a paused job. Optionally scoped to a channel. */
148
+ export function resumeJob(id, channelId) {
149
+ const task = getScheduledTask(id);
150
+ if (!task)
151
+ return false;
152
+ if (channelId && task.channelId !== channelId)
153
+ return false;
154
+ updateScheduledTaskEnabled(id, true);
155
+ try {
156
+ startJob({ ...task, enabled: true });
157
+ log.info(`Job ${id} resumed`);
158
+ return true;
159
+ }
160
+ catch (err) {
161
+ updateScheduledTaskEnabled(id, false);
162
+ log.error(`Failed to resume job ${id}: ${err?.message}`);
163
+ return false;
164
+ }
165
+ }
166
+ /** List jobs for a channel (or all if no channelId). */
167
+ export function listJobs(channelId) {
168
+ if (channelId)
169
+ return getScheduledTasksForChannel(channelId);
170
+ return getEnabledScheduledTasks();
171
+ }
172
+ /** Get a job by ID. */
173
+ export function getJob(id) {
174
+ return getScheduledTask(id);
175
+ }
176
+ /** Stop all active jobs (for shutdown). */
177
+ export function stopAll() {
178
+ for (const [id, job] of activeJobs) {
179
+ job.stop();
180
+ log.debug(`Stopped job ${id}`);
181
+ }
182
+ activeJobs.clear();
183
+ }
184
+ /** Start a CronJob for a task. */
185
+ function startJob(task) {
186
+ if (activeJobs.has(task.id)) {
187
+ activeJobs.get(task.id).stop();
188
+ activeJobs.delete(task.id);
189
+ }
190
+ const cronTime = task.cronExpr ?? new Date(task.runAt);
191
+ const isOneOff = !!task.runAt;
192
+ const job = CronJob.from({
193
+ cronTime,
194
+ onTick: () => { executeJob(task.id, isOneOff).catch(e => log.error(`Job ${task.id} unhandled error:`, e)); },
195
+ timeZone: task.cronExpr ? task.timezone : undefined,
196
+ start: true,
197
+ });
198
+ activeJobs.set(task.id, job);
199
+ }
200
+ /** Execute a scheduled job — send the prompt to the channel. */
201
+ async function executeJob(taskId, isOneOff) {
202
+ if (!deps) {
203
+ log.error(`Scheduler deps not initialized, skipping job ${taskId}`);
204
+ return;
205
+ }
206
+ const task = getScheduledTask(taskId);
207
+ if (!task || !task.enabled)
208
+ return;
209
+ const now = new Date().toISOString();
210
+ log.info(`Executing job ${taskId}: "${task.prompt.slice(0, 80)}"`);
211
+ try {
212
+ await deps.sendMessage(task.channelId, task.prompt);
213
+ insertTaskHistory({
214
+ taskId: task.id, channelId: task.channelId,
215
+ prompt: task.prompt, description: task.description,
216
+ timezone: task.timezone,
217
+ status: 'success',
218
+ });
219
+ // Update last_run and next_run
220
+ let nextRun;
221
+ if (task.cronExpr) {
222
+ const job = activeJobs.get(taskId);
223
+ if (job) {
224
+ nextRun = job.nextDate().toISO() ?? undefined;
225
+ }
226
+ }
227
+ updateScheduledTaskLastRun(taskId, now, nextRun);
228
+ }
229
+ catch (err) {
230
+ log.error(`Job ${taskId} execution failed: ${err?.message}`);
231
+ try {
232
+ insertTaskHistory({
233
+ taskId: task.id, channelId: task.channelId,
234
+ prompt: task.prompt, description: task.description,
235
+ timezone: task.timezone,
236
+ status: 'error', error: err?.message,
237
+ });
238
+ }
239
+ catch (histErr) {
240
+ log.error(`Failed to record task history for ${taskId}: ${histErr?.message}`);
241
+ }
242
+ }
243
+ // One-off jobs: delete after execution (they won't run again)
244
+ if (isOneOff) {
245
+ const job = activeJobs.get(taskId);
246
+ if (job)
247
+ job.stop();
248
+ activeJobs.delete(taskId);
249
+ deleteScheduledTask(taskId);
250
+ log.info(`One-off job ${taskId} completed and removed`);
251
+ }
252
+ }
253
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/core/scheduler.ts"],"names":[],"mappings":"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"}