@moltium/core 0.1.10 → 0.1.12
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/index.d.cts +17 -3
- package/dist/index.d.ts +17 -3
- package/dist/index.js +185 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +185 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -7,7 +7,7 @@ interface MoltbookConfig {
|
|
|
7
7
|
apiKey: string;
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
defaultSubmolt?: string;
|
|
10
|
-
postFrequency?:
|
|
10
|
+
postFrequency?: string;
|
|
11
11
|
engagementRate?: 'low' | 'medium' | 'high';
|
|
12
12
|
autoReply?: boolean;
|
|
13
13
|
replyFilter?: (post: any) => boolean;
|
|
@@ -21,7 +21,7 @@ interface TwitterConfig {
|
|
|
21
21
|
accessSecret: string;
|
|
22
22
|
bearerToken?: string;
|
|
23
23
|
};
|
|
24
|
-
postFrequency?:
|
|
24
|
+
postFrequency?: string;
|
|
25
25
|
replyToMentions?: boolean;
|
|
26
26
|
autoRetweet?: boolean;
|
|
27
27
|
maxTweetsPerDay?: number;
|
|
@@ -60,6 +60,11 @@ interface Plugin {
|
|
|
60
60
|
init?: (agent: any) => Promise<void>;
|
|
61
61
|
destroy?: () => Promise<void>;
|
|
62
62
|
}
|
|
63
|
+
interface ScheduledTask {
|
|
64
|
+
name: string;
|
|
65
|
+
intervalMs: number;
|
|
66
|
+
instructions: string;
|
|
67
|
+
}
|
|
63
68
|
interface AgentConfig {
|
|
64
69
|
name: string;
|
|
65
70
|
type?: string;
|
|
@@ -96,6 +101,7 @@ interface AgentConfig {
|
|
|
96
101
|
};
|
|
97
102
|
actions: string[];
|
|
98
103
|
customActions?: Action[];
|
|
104
|
+
scheduling?: ScheduledTask[];
|
|
99
105
|
webhooks?: {
|
|
100
106
|
onAction?: string | ((action: any, result: any) => Promise<void>);
|
|
101
107
|
onError?: string;
|
|
@@ -374,6 +380,11 @@ declare class Agent {
|
|
|
374
380
|
private initMoltbook;
|
|
375
381
|
private initTwitter;
|
|
376
382
|
private postStartupMessages;
|
|
383
|
+
private initScheduledJobs;
|
|
384
|
+
private wirePostFrequencyJobs;
|
|
385
|
+
private wireSchedulingTasks;
|
|
386
|
+
private scheduledPost;
|
|
387
|
+
private executeScheduledTask;
|
|
377
388
|
private logPlatformError;
|
|
378
389
|
private startAutonomousLoop;
|
|
379
390
|
private isSleeping;
|
|
@@ -424,6 +435,9 @@ declare class MarkdownParser {
|
|
|
424
435
|
private parseMemory;
|
|
425
436
|
private parseSleepSchedule;
|
|
426
437
|
private parseKeyValueLines;
|
|
438
|
+
private parseScheduling;
|
|
439
|
+
private parseIntervalFromTitle;
|
|
440
|
+
private toCamelCase;
|
|
427
441
|
private toSnakeCase;
|
|
428
442
|
}
|
|
429
443
|
|
|
@@ -566,4 +580,4 @@ declare function createRoutes(agent: Agent): Router;
|
|
|
566
580
|
|
|
567
581
|
declare function createLogger(label: string): winston.Logger;
|
|
568
582
|
|
|
569
|
-
export { type Action, type ActionContext, ActionHandler, ActionRegistry, type ActionResult, Agent, type AgentConfig, type AgentState, AnthropicProvider, type BehaviorTrigger, ConfigLoader, type ConfigType, type CustomAPIConfig, type CustomCLIConfig, type CustomDeploymentConfig, type CustomDockerConfig, type CustomSSHConfig, type Decision, type DeploymentConfig, type DeploymentResult, type DeploymentStatus, type Experience, type FeedOptions, type GenerateOptions, LLMProvider, type LifecycleEvent, type LifecycleHooks, LongTermMemory, MarkdownParser, Memory, type Mention, type Message, MoltbookAdapter, type MoltbookConfig, OpenAIProvider, type Plugin, type Post, type PostResult, type PostgresConfig, type Profile, type RedisConfig, type ReplyResult, type ScheduledJob, Scheduler, ShortTermMemory, SocialAdapter, type SocialConfig, type SocialPlatformConfig, type StructuredSchema, type TimelineOptions, TwitterAdapter, type TwitterConfig, buildDecisionPrompt, buildSkillPrompt, buildSystemPrompt, builtInActions, createApp, createLogger, createMarkdownAction, createRoutes, startServer, validateConfig };
|
|
583
|
+
export { type Action, type ActionContext, ActionHandler, ActionRegistry, type ActionResult, Agent, type AgentConfig, type AgentState, AnthropicProvider, type BehaviorTrigger, ConfigLoader, type ConfigType, type CustomAPIConfig, type CustomCLIConfig, type CustomDeploymentConfig, type CustomDockerConfig, type CustomSSHConfig, type Decision, type DeploymentConfig, type DeploymentResult, type DeploymentStatus, type Experience, type FeedOptions, type GenerateOptions, LLMProvider, type LifecycleEvent, type LifecycleHooks, LongTermMemory, MarkdownParser, Memory, type Mention, type Message, MoltbookAdapter, type MoltbookConfig, OpenAIProvider, type Plugin, type Post, type PostResult, type PostgresConfig, type Profile, type RedisConfig, type ReplyResult, type ScheduledJob, type ScheduledTask, Scheduler, ShortTermMemory, SocialAdapter, type SocialConfig, type SocialPlatformConfig, type StructuredSchema, type TimelineOptions, TwitterAdapter, type TwitterConfig, buildDecisionPrompt, buildSkillPrompt, buildSystemPrompt, builtInActions, createApp, createLogger, createMarkdownAction, createRoutes, startServer, validateConfig };
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ interface MoltbookConfig {
|
|
|
7
7
|
apiKey: string;
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
defaultSubmolt?: string;
|
|
10
|
-
postFrequency?:
|
|
10
|
+
postFrequency?: string;
|
|
11
11
|
engagementRate?: 'low' | 'medium' | 'high';
|
|
12
12
|
autoReply?: boolean;
|
|
13
13
|
replyFilter?: (post: any) => boolean;
|
|
@@ -21,7 +21,7 @@ interface TwitterConfig {
|
|
|
21
21
|
accessSecret: string;
|
|
22
22
|
bearerToken?: string;
|
|
23
23
|
};
|
|
24
|
-
postFrequency?:
|
|
24
|
+
postFrequency?: string;
|
|
25
25
|
replyToMentions?: boolean;
|
|
26
26
|
autoRetweet?: boolean;
|
|
27
27
|
maxTweetsPerDay?: number;
|
|
@@ -60,6 +60,11 @@ interface Plugin {
|
|
|
60
60
|
init?: (agent: any) => Promise<void>;
|
|
61
61
|
destroy?: () => Promise<void>;
|
|
62
62
|
}
|
|
63
|
+
interface ScheduledTask {
|
|
64
|
+
name: string;
|
|
65
|
+
intervalMs: number;
|
|
66
|
+
instructions: string;
|
|
67
|
+
}
|
|
63
68
|
interface AgentConfig {
|
|
64
69
|
name: string;
|
|
65
70
|
type?: string;
|
|
@@ -96,6 +101,7 @@ interface AgentConfig {
|
|
|
96
101
|
};
|
|
97
102
|
actions: string[];
|
|
98
103
|
customActions?: Action[];
|
|
104
|
+
scheduling?: ScheduledTask[];
|
|
99
105
|
webhooks?: {
|
|
100
106
|
onAction?: string | ((action: any, result: any) => Promise<void>);
|
|
101
107
|
onError?: string;
|
|
@@ -374,6 +380,11 @@ declare class Agent {
|
|
|
374
380
|
private initMoltbook;
|
|
375
381
|
private initTwitter;
|
|
376
382
|
private postStartupMessages;
|
|
383
|
+
private initScheduledJobs;
|
|
384
|
+
private wirePostFrequencyJobs;
|
|
385
|
+
private wireSchedulingTasks;
|
|
386
|
+
private scheduledPost;
|
|
387
|
+
private executeScheduledTask;
|
|
377
388
|
private logPlatformError;
|
|
378
389
|
private startAutonomousLoop;
|
|
379
390
|
private isSleeping;
|
|
@@ -424,6 +435,9 @@ declare class MarkdownParser {
|
|
|
424
435
|
private parseMemory;
|
|
425
436
|
private parseSleepSchedule;
|
|
426
437
|
private parseKeyValueLines;
|
|
438
|
+
private parseScheduling;
|
|
439
|
+
private parseIntervalFromTitle;
|
|
440
|
+
private toCamelCase;
|
|
427
441
|
private toSnakeCase;
|
|
428
442
|
}
|
|
429
443
|
|
|
@@ -566,4 +580,4 @@ declare function createRoutes(agent: Agent): Router;
|
|
|
566
580
|
|
|
567
581
|
declare function createLogger(label: string): winston.Logger;
|
|
568
582
|
|
|
569
|
-
export { type Action, type ActionContext, ActionHandler, ActionRegistry, type ActionResult, Agent, type AgentConfig, type AgentState, AnthropicProvider, type BehaviorTrigger, ConfigLoader, type ConfigType, type CustomAPIConfig, type CustomCLIConfig, type CustomDeploymentConfig, type CustomDockerConfig, type CustomSSHConfig, type Decision, type DeploymentConfig, type DeploymentResult, type DeploymentStatus, type Experience, type FeedOptions, type GenerateOptions, LLMProvider, type LifecycleEvent, type LifecycleHooks, LongTermMemory, MarkdownParser, Memory, type Mention, type Message, MoltbookAdapter, type MoltbookConfig, OpenAIProvider, type Plugin, type Post, type PostResult, type PostgresConfig, type Profile, type RedisConfig, type ReplyResult, type ScheduledJob, Scheduler, ShortTermMemory, SocialAdapter, type SocialConfig, type SocialPlatformConfig, type StructuredSchema, type TimelineOptions, TwitterAdapter, type TwitterConfig, buildDecisionPrompt, buildSkillPrompt, buildSystemPrompt, builtInActions, createApp, createLogger, createMarkdownAction, createRoutes, startServer, validateConfig };
|
|
583
|
+
export { type Action, type ActionContext, ActionHandler, ActionRegistry, type ActionResult, Agent, type AgentConfig, type AgentState, AnthropicProvider, type BehaviorTrigger, ConfigLoader, type ConfigType, type CustomAPIConfig, type CustomCLIConfig, type CustomDeploymentConfig, type CustomDockerConfig, type CustomSSHConfig, type Decision, type DeploymentConfig, type DeploymentResult, type DeploymentStatus, type Experience, type FeedOptions, type GenerateOptions, LLMProvider, type LifecycleEvent, type LifecycleHooks, LongTermMemory, MarkdownParser, Memory, type Mention, type Message, MoltbookAdapter, type MoltbookConfig, OpenAIProvider, type Plugin, type Post, type PostResult, type PostgresConfig, type Profile, type RedisConfig, type ReplyResult, type ScheduledJob, type ScheduledTask, Scheduler, ShortTermMemory, SocialAdapter, type SocialConfig, type SocialPlatformConfig, type StructuredSchema, type TimelineOptions, TwitterAdapter, type TwitterConfig, buildDecisionPrompt, buildSkillPrompt, buildSystemPrompt, builtInActions, createApp, createLogger, createMarkdownAction, createRoutes, startServer, validateConfig };
|
package/dist/index.js
CHANGED
|
@@ -799,6 +799,33 @@ var TwitterAdapter = class extends SocialAdapter {
|
|
|
799
799
|
|
|
800
800
|
// src/agent/Agent.ts
|
|
801
801
|
var logger4 = createLogger("Agent");
|
|
802
|
+
function parsePostFrequency(freq) {
|
|
803
|
+
const lower = freq.toLowerCase().trim();
|
|
804
|
+
if (lower === "realtime") return 5 * 60 * 1e3;
|
|
805
|
+
if (lower === "hourly") return 60 * 60 * 1e3;
|
|
806
|
+
if (lower === "daily") return 24 * 60 * 60 * 1e3;
|
|
807
|
+
const match = lower.match(/^(\d+)\s*(m|min|mins|minutes?|h|hr|hrs|hours?|d|days?)$/);
|
|
808
|
+
if (match) {
|
|
809
|
+
const n = parseInt(match[1], 10);
|
|
810
|
+
const unit = match[2][0];
|
|
811
|
+
if (unit === "m") return n * 60 * 1e3;
|
|
812
|
+
if (unit === "h") return n * 60 * 60 * 1e3;
|
|
813
|
+
if (unit === "d") return n * 24 * 60 * 60 * 1e3;
|
|
814
|
+
}
|
|
815
|
+
const nlMin = lower.match(/every\s+(\d+)\s+minutes?/);
|
|
816
|
+
if (nlMin) return parseInt(nlMin[1], 10) * 60 * 1e3;
|
|
817
|
+
const nlHour = lower.match(/every\s+(\d+)\s+hours?/);
|
|
818
|
+
if (nlHour) return parseInt(nlHour[1], 10) * 60 * 60 * 1e3;
|
|
819
|
+
if (/every\s+hour/.test(lower)) return 60 * 60 * 1e3;
|
|
820
|
+
if (/every\s+day/.test(lower)) return 24 * 60 * 60 * 1e3;
|
|
821
|
+
return 0;
|
|
822
|
+
}
|
|
823
|
+
function formatInterval(ms) {
|
|
824
|
+
if (ms < 60 * 1e3) return `${Math.round(ms / 1e3)}s`;
|
|
825
|
+
if (ms < 60 * 60 * 1e3) return `${Math.round(ms / 6e4)}m`;
|
|
826
|
+
if (ms < 24 * 60 * 60 * 1e3) return `${Math.round(ms / 36e5)}h`;
|
|
827
|
+
return `${Math.round(ms / 864e5)}d`;
|
|
828
|
+
}
|
|
802
829
|
var Agent = class {
|
|
803
830
|
config;
|
|
804
831
|
state = "idle";
|
|
@@ -869,6 +896,7 @@ var Agent = class {
|
|
|
869
896
|
this.initLLM();
|
|
870
897
|
this.registerActions();
|
|
871
898
|
await this.initSocialAdapters();
|
|
899
|
+
this.initScheduledJobs();
|
|
872
900
|
if (this.hooks.onInit) {
|
|
873
901
|
await this.hooks.onInit(this);
|
|
874
902
|
}
|
|
@@ -1108,7 +1136,23 @@ var Agent = class {
|
|
|
1108
1136
|
logger4.info("Startup post: No connected social adapters \u2014 skipping");
|
|
1109
1137
|
return;
|
|
1110
1138
|
}
|
|
1111
|
-
|
|
1139
|
+
let content;
|
|
1140
|
+
try {
|
|
1141
|
+
const prompt = `You are ${this.config.name}. You just came online.
|
|
1142
|
+
Your bio: ${this.config.personality.bio}
|
|
1143
|
+
Your personality traits: ${this.config.personality.traits.join(", ")}
|
|
1144
|
+
` + (this.config.type ? `Your role: ${this.config.type}
|
|
1145
|
+
` : "") + `
|
|
1146
|
+
Write a short, engaging first post announcing you're online. Stay in character \u2014 reflect your personality and bio. Do NOT use generic phrases like "is now online and ready". Write only the post content, nothing else.`;
|
|
1147
|
+
content = (await this.llm.generateText(prompt, {
|
|
1148
|
+
temperature: this.config.llm.temperature ?? 0.8,
|
|
1149
|
+
maxTokens: 280
|
|
1150
|
+
})).trim();
|
|
1151
|
+
logger4.info(`Startup post: LLM generated content (${content.length} chars)`);
|
|
1152
|
+
} catch (error) {
|
|
1153
|
+
logger4.warn(`Startup post: LLM generation failed (${error.message}), using fallback`);
|
|
1154
|
+
content = `${this.config.name} is now online and ready.`;
|
|
1155
|
+
}
|
|
1112
1156
|
for (const [platform, adapter] of adapters) {
|
|
1113
1157
|
logger4.info(`Startup post: Posting to ${platform}...`);
|
|
1114
1158
|
try {
|
|
@@ -1120,6 +1164,107 @@ var Agent = class {
|
|
|
1120
1164
|
}
|
|
1121
1165
|
}
|
|
1122
1166
|
}
|
|
1167
|
+
initScheduledJobs() {
|
|
1168
|
+
this.wirePostFrequencyJobs();
|
|
1169
|
+
this.wireSchedulingTasks();
|
|
1170
|
+
}
|
|
1171
|
+
wirePostFrequencyJobs() {
|
|
1172
|
+
const social = this.config.social;
|
|
1173
|
+
if (social.moltbook?.enabled !== false && this.socialAdapters["moltbook"]) {
|
|
1174
|
+
const freq = social.moltbook?.postFrequency;
|
|
1175
|
+
if (freq) {
|
|
1176
|
+
const intervalMs = parsePostFrequency(freq);
|
|
1177
|
+
if (intervalMs > 0) {
|
|
1178
|
+
this.scheduler.addJob({
|
|
1179
|
+
name: "moltbook_scheduled_post",
|
|
1180
|
+
intervalMs,
|
|
1181
|
+
handler: async () => {
|
|
1182
|
+
await this.scheduledPost("moltbook");
|
|
1183
|
+
}
|
|
1184
|
+
});
|
|
1185
|
+
logger4.info(`Scheduler: Moltbook posting every ${formatInterval(intervalMs)}`);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
if (social.twitter?.enabled !== false && this.socialAdapters["twitter"]) {
|
|
1190
|
+
const freq = social.twitter?.postFrequency;
|
|
1191
|
+
if (freq) {
|
|
1192
|
+
const intervalMs = parsePostFrequency(freq);
|
|
1193
|
+
if (intervalMs > 0) {
|
|
1194
|
+
this.scheduler.addJob({
|
|
1195
|
+
name: "twitter_scheduled_post",
|
|
1196
|
+
intervalMs,
|
|
1197
|
+
handler: async () => {
|
|
1198
|
+
await this.scheduledPost("twitter");
|
|
1199
|
+
}
|
|
1200
|
+
});
|
|
1201
|
+
logger4.info(`Scheduler: Twitter posting every ${formatInterval(intervalMs)}`);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
wireSchedulingTasks() {
|
|
1207
|
+
const tasks = this.config.scheduling;
|
|
1208
|
+
if (!tasks || tasks.length === 0) return;
|
|
1209
|
+
for (const task of tasks) {
|
|
1210
|
+
this.scheduler.addJob({
|
|
1211
|
+
name: task.name,
|
|
1212
|
+
intervalMs: task.intervalMs,
|
|
1213
|
+
handler: async () => {
|
|
1214
|
+
await this.executeScheduledTask(task);
|
|
1215
|
+
}
|
|
1216
|
+
});
|
|
1217
|
+
logger4.info(`Scheduler: "${task.name}" every ${formatInterval(task.intervalMs)}`);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
async scheduledPost(platform) {
|
|
1221
|
+
const adapter = this.socialAdapters[platform];
|
|
1222
|
+
if (!adapter) return;
|
|
1223
|
+
try {
|
|
1224
|
+
const prompt = `You are ${this.config.name}. Generate a short, engaging social media post for ${platform}. Your personality: ${this.config.personality.traits.join(", ")}. Bio: ${this.config.personality.bio}. Write only the post content, nothing else. Keep it concise and natural.`;
|
|
1225
|
+
const content = await this.llm.generateText(prompt, {
|
|
1226
|
+
temperature: this.config.llm.temperature ?? 0.8,
|
|
1227
|
+
maxTokens: 280
|
|
1228
|
+
});
|
|
1229
|
+
const result = await adapter.post(content.trim());
|
|
1230
|
+
logger4.info(`Scheduled post: ${platform} SUCCESS \u2014 id=${result.id}`);
|
|
1231
|
+
} catch (error) {
|
|
1232
|
+
logger4.error(`Scheduled post: ${platform} FAILED \u2014 ${error.message || error}`);
|
|
1233
|
+
this.logPlatformError(platform, error);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
async executeScheduledTask(task) {
|
|
1237
|
+
try {
|
|
1238
|
+
logger4.info(`Scheduled task: Running "${task.name}"`);
|
|
1239
|
+
const prompt = `You are ${this.config.name}, an autonomous agent. Execute the following scheduled task.
|
|
1240
|
+
|
|
1241
|
+
Task: ${task.name}
|
|
1242
|
+
Instructions:
|
|
1243
|
+
${task.instructions}
|
|
1244
|
+
|
|
1245
|
+
Available social platforms: ${Object.keys(this.socialAdapters).join(", ") || "none"}
|
|
1246
|
+
|
|
1247
|
+
Decide what action to take. Respond with JSON:
|
|
1248
|
+
{ "action": "<action_name>", "reasoning": "<why>", "parameters": { ... } }`;
|
|
1249
|
+
const decision = await this.llm.generateStructured(
|
|
1250
|
+
prompt,
|
|
1251
|
+
{
|
|
1252
|
+
type: "object",
|
|
1253
|
+
properties: {
|
|
1254
|
+
action: { type: "string" },
|
|
1255
|
+
reasoning: { type: "string" },
|
|
1256
|
+
parameters: { type: "object" }
|
|
1257
|
+
},
|
|
1258
|
+
required: ["action", "reasoning", "parameters"]
|
|
1259
|
+
},
|
|
1260
|
+
{ systemPrompt: this.systemPrompt, temperature: this.config.llm.temperature }
|
|
1261
|
+
);
|
|
1262
|
+
const result = await this.act(decision.action, decision.parameters);
|
|
1263
|
+
logger4.info(`Scheduled task: "${task.name}" completed \u2014 action=${decision.action}, success=${result.success}`);
|
|
1264
|
+
} catch (error) {
|
|
1265
|
+
logger4.error(`Scheduled task: "${task.name}" FAILED \u2014 ${error.message || error}`);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1123
1268
|
logPlatformError(platform, error) {
|
|
1124
1269
|
if (!error.response) {
|
|
1125
1270
|
if (error.code === "ENOTFOUND") {
|
|
@@ -1236,6 +1381,9 @@ var MarkdownParser = class {
|
|
|
1236
1381
|
if (skills) {
|
|
1237
1382
|
config.actions = skills.children.map((s) => this.toSnakeCase(s.title));
|
|
1238
1383
|
}
|
|
1384
|
+
if (scheduling && scheduling.children.length > 0) {
|
|
1385
|
+
config.scheduling = this.parseScheduling(scheduling);
|
|
1386
|
+
}
|
|
1239
1387
|
return config;
|
|
1240
1388
|
}
|
|
1241
1389
|
parseSkills(markdown) {
|
|
@@ -1300,9 +1448,13 @@ var MarkdownParser = class {
|
|
|
1300
1448
|
const fields = this.parseKeyValueLines(child.content);
|
|
1301
1449
|
const enabled = fields["enabled"] === "true";
|
|
1302
1450
|
delete fields["enabled"];
|
|
1451
|
+
const camelFields = {};
|
|
1452
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
1453
|
+
camelFields[this.toCamelCase(key)] = value;
|
|
1454
|
+
}
|
|
1303
1455
|
social[platform] = {
|
|
1304
1456
|
enabled,
|
|
1305
|
-
...
|
|
1457
|
+
...camelFields
|
|
1306
1458
|
};
|
|
1307
1459
|
}
|
|
1308
1460
|
return social;
|
|
@@ -1342,6 +1494,37 @@ var MarkdownParser = class {
|
|
|
1342
1494
|
}
|
|
1343
1495
|
return result;
|
|
1344
1496
|
}
|
|
1497
|
+
parseScheduling(section) {
|
|
1498
|
+
const tasks = [];
|
|
1499
|
+
for (const child of section.children) {
|
|
1500
|
+
const title = child.title.trim();
|
|
1501
|
+
if (/^on\s+startup$/i.test(title)) continue;
|
|
1502
|
+
const intervalMs = this.parseIntervalFromTitle(title);
|
|
1503
|
+
if (intervalMs <= 0) continue;
|
|
1504
|
+
const instructions = child.content.trim();
|
|
1505
|
+
if (!instructions) continue;
|
|
1506
|
+
tasks.push({
|
|
1507
|
+
name: this.toSnakeCase(title),
|
|
1508
|
+
intervalMs,
|
|
1509
|
+
instructions
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
return tasks;
|
|
1513
|
+
}
|
|
1514
|
+
parseIntervalFromTitle(title) {
|
|
1515
|
+
const lower = title.toLowerCase();
|
|
1516
|
+
const minMatch = lower.match(/every\s+(\d+)\s+minutes?/);
|
|
1517
|
+
if (minMatch) return parseInt(minMatch[1], 10) * 60 * 1e3;
|
|
1518
|
+
if (/every\s+hour$/i.test(lower)) return 60 * 60 * 1e3;
|
|
1519
|
+
const hourMatch = lower.match(/every\s+(\d+)\s+hours?/);
|
|
1520
|
+
if (hourMatch) return parseInt(hourMatch[1], 10) * 60 * 60 * 1e3;
|
|
1521
|
+
if (/every\s+day/i.test(lower)) return 24 * 60 * 60 * 1e3;
|
|
1522
|
+
if (/every\s+week/i.test(lower)) return 7 * 24 * 60 * 60 * 1e3;
|
|
1523
|
+
return 0;
|
|
1524
|
+
}
|
|
1525
|
+
toCamelCase(str) {
|
|
1526
|
+
return str.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
1527
|
+
}
|
|
1345
1528
|
toSnakeCase(str) {
|
|
1346
1529
|
return str.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
|
|
1347
1530
|
}
|