@qodalis/cli-cron 2.0.0-beta.8 → 2.0.0-rc.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qodalis/cli-cron",
3
- "version": "2.0.0-beta.8",
3
+ "version": "2.0.0-rc.1",
4
4
  "description": "Schedule commands to run on a repeating interval",
5
5
  "author": "Qodalis Solutions",
6
6
  "license": "MIT",
@@ -18,7 +18,7 @@
18
18
  "umd": "./umd/index.global.js",
19
19
  "unpkg": "./umd/index.global.js",
20
20
  "dependencies": {
21
- "@qodalis/cli-core": "2.0.0-beta.8"
21
+ "@qodalis/cli-core": "2.0.0-rc.1"
22
22
  },
23
23
  "sideEffects": false,
24
24
  "main": "./public-api.js",
package/public-api.d.mts CHANGED
@@ -9,6 +9,7 @@ declare class CliCronCommandProcessor implements ICliCommandProcessor {
9
9
  private timers;
10
10
  processors: ICliCommandChildProcessor[];
11
11
  initialize(context: ICliExecutionContext): Promise<void>;
12
+ writeDescription(context: ICliExecutionContext): void;
12
13
  processCommand(_: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
13
14
  private startJob;
14
15
  private stopJob;
@@ -18,7 +19,7 @@ declare class CliCronCommandProcessor implements ICliCommandProcessor {
18
19
  declare function parseInterval(input: string): number | null;
19
20
  declare function formatInterval(ms: number): string;
20
21
 
21
- declare const LIBRARY_VERSION = "2.0.0-beta.8";
22
+ declare const LIBRARY_VERSION = "2.0.0-rc.1";
22
23
  declare const API_VERSION = 2;
23
24
 
24
25
  declare const cronModule: ICliModule;
package/public-api.d.ts CHANGED
@@ -9,6 +9,7 @@ declare class CliCronCommandProcessor implements ICliCommandProcessor {
9
9
  private timers;
10
10
  processors: ICliCommandChildProcessor[];
11
11
  initialize(context: ICliExecutionContext): Promise<void>;
12
+ writeDescription(context: ICliExecutionContext): void;
12
13
  processCommand(_: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
13
14
  private startJob;
14
15
  private stopJob;
@@ -18,7 +19,7 @@ declare class CliCronCommandProcessor implements ICliCommandProcessor {
18
19
  declare function parseInterval(input: string): number | null;
19
20
  declare function formatInterval(ms: number): string;
20
21
 
21
- declare const LIBRARY_VERSION = "2.0.0-beta.8";
22
+ declare const LIBRARY_VERSION = "2.0.0-rc.1";
22
23
  declare const API_VERSION = 2;
23
24
 
24
25
  declare const cronModule: ICliModule;
package/public-api.js CHANGED
@@ -33,6 +33,13 @@ function formatInterval(ms) {
33
33
  }
34
34
 
35
35
  // src/lib/processors/cli-cron-command-processor.ts
36
+ function textAfterWords(text, count) {
37
+ const word = /\s*(?:\\.|"(?:[^"\\]|\\.)*"|'[^']*'|[^\s"'\\]|["'\\])+/y;
38
+ for (let i = 0; i < count; i++) {
39
+ if (!word.exec(text)) return "";
40
+ }
41
+ return text.slice(word.lastIndex).trim();
42
+ }
36
43
  var CliCronCommandProcessor = class {
37
44
  constructor() {
38
45
  this.command = "cron";
@@ -51,14 +58,14 @@ var CliCronCommandProcessor = class {
51
58
  acceptsRawInput: true,
52
59
  valueRequired: true,
53
60
  processCommand: async (cmd, context) => {
54
- const parts = (cmd.value ?? "").trim().split(/\s+/);
61
+ const parts = cmd.positionals ?? [];
55
62
  if (parts.length < 3) {
56
63
  context.writer.writeError("Usage: cron add <name> <interval> <command>");
57
64
  context.writer.writeln(" Example: cron add ping 5m echo heartbeat");
58
65
  return;
59
66
  }
60
67
  const [name, intervalStr, ...cmdParts] = parts;
61
- const command = cmdParts.join(" ");
68
+ const command = cmdParts.length === 1 ? cmdParts[0] : textAfterWords(cmd.value ?? "", 2) || cmdParts.join(" ");
62
69
  const intervalMs = parseInterval(intervalStr);
63
70
  if (!intervalMs) {
64
71
  context.writer.writeError(`Invalid interval "${intervalStr}". Min 10s. Examples: 10s, 5m, 1h`);
@@ -77,9 +84,9 @@ var CliCronCommandProcessor = class {
77
84
  enabled: true,
78
85
  runCount: 0
79
86
  };
80
- const updated = [...state.jobs, job];
81
- context.state.updateState({ jobs: updated });
82
- await context.state.persist();
87
+ await context.state.update((saved) => ({
88
+ jobs: [...saved["jobs"] ?? [], job]
89
+ }));
83
90
  this.startJob(job, context);
84
91
  context.writer.writeSuccess(
85
92
  `Job "${name}" added \u2014 runs every ${formatInterval(intervalMs)}: ${command}`
@@ -112,7 +119,7 @@ var CliCronCommandProcessor = class {
112
119
  acceptsRawInput: true,
113
120
  valueRequired: true,
114
121
  processCommand: async (cmd, context) => {
115
- const name = (cmd.value ?? "").trim();
122
+ const name = cliCore.joinShellWords(cmd.value ?? "");
116
123
  const state = context.state.getState();
117
124
  const idx = state.jobs.findIndex((j) => j.name === name);
118
125
  if (idx === -1) {
@@ -121,9 +128,9 @@ var CliCronCommandProcessor = class {
121
128
  }
122
129
  const job = state.jobs[idx];
123
130
  this.stopJob(job.id);
124
- const updated = state.jobs.filter((j) => j.name !== name);
125
- context.state.updateState({ jobs: updated });
126
- await context.state.persist();
131
+ await context.state.update((saved) => ({
132
+ jobs: (saved["jobs"] ?? []).filter((j) => j.name !== name)
133
+ }));
127
134
  context.writer.writeSuccess(`Job "${name}" removed`);
128
135
  }
129
136
  },
@@ -133,7 +140,7 @@ var CliCronCommandProcessor = class {
133
140
  acceptsRawInput: true,
134
141
  valueRequired: true,
135
142
  processCommand: async (cmd, context) => {
136
- await this.setEnabled((cmd.value ?? "").trim(), true, context);
143
+ await this.setEnabled(cliCore.joinShellWords(cmd.value ?? ""), true, context);
137
144
  }
138
145
  },
139
146
  {
@@ -142,7 +149,7 @@ var CliCronCommandProcessor = class {
142
149
  acceptsRawInput: true,
143
150
  valueRequired: true,
144
151
  processCommand: async (cmd, context) => {
145
- await this.setEnabled((cmd.value ?? "").trim(), false, context);
152
+ await this.setEnabled(cliCore.joinShellWords(cmd.value ?? ""), false, context);
146
153
  }
147
154
  }
148
155
  ];
@@ -153,6 +160,32 @@ var CliCronCommandProcessor = class {
153
160
  this.startJob(job, context);
154
161
  }
155
162
  }
163
+ writeDescription(context) {
164
+ const t = context.translator;
165
+ cliCore.writeWrapped(
166
+ context,
167
+ t.t("cli.cron.help.run_command_again_again", "Run a command again and again at a fixed interval while the terminal is open. Jobs are saved: they start again when the terminal starts, and can be paused without removing them.")
168
+ );
169
+ context.writer.writeln();
170
+ cliCore.writeUsage(context, [
171
+ ["cron add <name> <interval> <command>", t.t("cli.cron.help.add_job", "Add a job")],
172
+ ["cron list", t.t("cli.cron.help.jobs_interval_status_run", "Jobs with interval, status and run count (ls)")],
173
+ ["cron disable <name>", t.t("cli.cron.help.pause_job", "Pause a job")],
174
+ ["cron enable <name>", t.t("cli.cron.help.resume_paused_job", "Resume a paused job")],
175
+ ["cron remove <name>", t.t("cli.cron.help.remove_job_rm_delete", "Remove a job (rm, delete)")]
176
+ ]);
177
+ context.writer.writeln();
178
+ cliCore.writeWrapped(
179
+ context,
180
+ t.t("cli.cron.help.intervals_seconds_30_hours", "Intervals: seconds (30), or hours, minutes and seconds (1h, 5m, 1h30m, 90s); at least 10 seconds.")
181
+ );
182
+ context.writer.writeln();
183
+ cliCore.writeExamples(context, [
184
+ ["cron add ping 5m echo heartbeat", t.t("cli.cron.help.every_5_minutes", "Every 5 minutes")],
185
+ ["cron add backup 1h30m server jobs trigger backup", t.t("cli.cron.help.every_hour_half", "Every hour and a half")],
186
+ ["cron disable ping", t.t("cli.cron.help.pause", "Pause it")]
187
+ ]);
188
+ }
156
189
  async processCommand(_, context) {
157
190
  const { jobs } = context.state.getState();
158
191
  context.writer.writeln(`${jobs.length} job(s). Sub-commands: add, list, remove, enable, disable`);
@@ -171,7 +204,7 @@ var CliCronCommandProcessor = class {
171
204
  );
172
205
  context.state.updateState({ jobs: updated });
173
206
  } catch (e) {
174
- console.error(`Cron job "${job.name}" failed:`, e);
207
+ context.logger.error(`Cron job "${job.name}" failed:`, e);
175
208
  }
176
209
  }, job.intervalMs);
177
210
  this.timers.set(job.id, timer);
@@ -197,15 +230,17 @@ var CliCronCommandProcessor = class {
197
230
  } else {
198
231
  this.stopJob(job.id);
199
232
  }
200
- const updated = state.jobs.map((j) => j.name === name ? { ...j, enabled } : j);
201
- context.state.updateState({ jobs: updated });
202
- await context.state.persist();
233
+ await context.state.update((saved) => ({
234
+ jobs: (saved["jobs"] ?? []).map(
235
+ (j) => j.name === name ? { ...j, enabled } : j
236
+ )
237
+ }));
203
238
  context.writer.writeSuccess(`Job "${name}" ${enabled ? "enabled" : "disabled"}`);
204
239
  }
205
240
  };
206
241
 
207
242
  // src/lib/version.ts
208
- var LIBRARY_VERSION = "2.0.0-beta.8";
243
+ var LIBRARY_VERSION = "2.0.0-rc.1";
209
244
  var API_VERSION = 2;
210
245
 
211
246
  // src/public-api.ts
package/public-api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../packages/plugins/cron/src/lib/cron-utils.ts","../../packages/plugins/cron/src/lib/processors/cli-cron-command-processor.ts","../../packages/plugins/cron/src/lib/version.ts","../../packages/plugins/cron/src/public-api.ts"],"names":["DefaultLibraryAuthor","CliIcon","CliForegroundColor"],"mappings":"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","file":"public-api.js","sourcesContent":["const MIN_INTERVAL_MS = 10_000; // 10 seconds minimum\n\nexport function parseInterval(input: string): number | null {\n if (!input.trim()) return null;\n if (/^\\d+$/.test(input.trim())) {\n const ms = parseInt(input.trim(), 10) * 1000;\n return ms >= MIN_INTERVAL_MS ? ms : null;\n }\n const pattern = /^(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/;\n const match = input.trim().match(pattern);\n if (!match || match[0] === '') return null;\n const h = parseInt(match[1] ?? '0', 10);\n const m = parseInt(match[2] ?? '0', 10);\n const s = parseInt(match[3] ?? '0', 10);\n const total = h * 3_600_000 + m * 60_000 + s * 1_000;\n return total >= MIN_INTERVAL_MS ? total : null;\n}\n\nexport function formatInterval(ms: number): string {\n const h = Math.floor(ms / 3_600_000);\n const m = Math.floor((ms % 3_600_000) / 60_000);\n const s = Math.floor((ms % 60_000) / 1_000);\n const parts: string[] = [];\n if (h > 0) parts.push(`${h}h`);\n if (m > 0) parts.push(`${m}m`);\n if (s > 0) parts.push(`${s}s`);\n return parts.join(' ') || '0s';\n}\n","import {\n ICliCommandProcessor,\n ICliExecutionContext,\n CliProcessCommand,\n ICliCommandAuthor,\n CliProcessorMetadata,\n CliIcon,\n CliStateConfiguration,\n DefaultLibraryAuthor,\n CliForegroundColor,\n ICliCommandChildProcessor,\n} from '@qodalis/cli-core';\nimport { parseInterval, formatInterval } from '../cron-utils';\n\ninterface CronJob {\n id: string;\n name: string;\n command: string;\n intervalMs: number;\n enabled: boolean;\n runCount: number;\n lastRun?: number;\n}\n\ninterface CronState {\n jobs: CronJob[];\n}\n\nexport class CliCronCommandProcessor implements ICliCommandProcessor {\n command = 'cron';\n description = 'Schedule commands to run on a repeating interval';\n author: ICliCommandAuthor = DefaultLibraryAuthor;\n metadata: CliProcessorMetadata = { icon: CliIcon.Clock };\n\n stateConfiguration: CliStateConfiguration = {\n storeName: 'cron',\n initialState: { jobs: [] } as CronState,\n };\n\n private timers = new Map<string, ReturnType<typeof setInterval>>();\n\n processors: ICliCommandChildProcessor[] = [\n {\n command: 'add',\n description: 'Add a cron job: cron add <name> <interval> <command>',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n const parts = (cmd.value ?? '').trim().split(/\\s+/);\n if (parts.length < 3) {\n context.writer.writeError('Usage: cron add <name> <interval> <command>');\n context.writer.writeln(' Example: cron add ping 5m echo heartbeat');\n return;\n }\n const [name, intervalStr, ...cmdParts] = parts;\n const command = cmdParts.join(' ');\n const intervalMs = parseInterval(intervalStr);\n if (!intervalMs) {\n context.writer.writeError(`Invalid interval \"${intervalStr}\". Min 10s. Examples: 10s, 5m, 1h`);\n return;\n }\n const state = context.state.getState<CronState>();\n if (state.jobs.find((j) => j.name === name)) {\n context.writer.writeError(`Job \"${name}\" already exists. Remove it first: cron remove ${name}`);\n return;\n }\n const job: CronJob = {\n id: `cron_${Date.now()}`,\n name,\n command,\n intervalMs,\n enabled: true,\n runCount: 0,\n };\n const updated = [...state.jobs, job];\n context.state.updateState({ jobs: updated });\n await context.state.persist();\n this.startJob(job, context);\n context.writer.writeSuccess(\n `Job \"${name}\" added — runs every ${formatInterval(intervalMs)}: ${command}`,\n );\n },\n },\n {\n command: 'list',\n description: 'List all cron jobs',\n aliases: ['ls'],\n processCommand: async (_: CliProcessCommand, context: ICliExecutionContext) => {\n const { jobs } = context.state.getState<CronState>();\n if (!jobs.length) {\n context.writer.writeInfo('No cron jobs. Use: cron add <name> <interval> <command>');\n return;\n }\n context.writer.writeln(context.writer.wrapInColor('Cron Jobs:', CliForegroundColor.Yellow));\n for (const job of jobs) {\n const status = job.enabled\n ? context.writer.wrapInColor('enabled ', CliForegroundColor.Green)\n : context.writer.wrapInColor('disabled', CliForegroundColor.Red);\n context.writer.writeln(\n ` ${context.writer.wrapInColor(job.name.padEnd(12), CliForegroundColor.Cyan)}` +\n `[${status}] every ${formatInterval(job.intervalMs)} \\u2192 ${job.command} (ran ${job.runCount}x)`,\n );\n }\n },\n },\n {\n command: 'remove',\n description: 'Remove a cron job: cron remove <name>',\n aliases: ['rm', 'delete'],\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n const name = (cmd.value ?? '').trim();\n const state = context.state.getState<CronState>();\n const idx = state.jobs.findIndex((j) => j.name === name);\n if (idx === -1) {\n context.writer.writeError(`Job \"${name}\" not found`);\n return;\n }\n const job = state.jobs[idx];\n this.stopJob(job.id);\n const updated = state.jobs.filter((j) => j.name !== name);\n context.state.updateState({ jobs: updated });\n await context.state.persist();\n context.writer.writeSuccess(`Job \"${name}\" removed`);\n },\n },\n {\n command: 'enable',\n description: 'Enable a paused cron job',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n await this.setEnabled((cmd.value ?? '').trim(), true, context);\n },\n },\n {\n command: 'disable',\n description: 'Pause a cron job without removing it',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n await this.setEnabled((cmd.value ?? '').trim(), false, context);\n },\n },\n ];\n\n async initialize(context: ICliExecutionContext): Promise<void> {\n const { jobs } = context.state.getState<CronState>();\n for (const job of jobs.filter((j) => j.enabled)) {\n this.startJob(job, context);\n }\n }\n\n async processCommand(_: CliProcessCommand, context: ICliExecutionContext): Promise<void> {\n const { jobs } = context.state.getState<CronState>();\n context.writer.writeln(`${jobs.length} job(s). Sub-commands: add, list, remove, enable, disable`);\n }\n\n private startJob(job: CronJob, context: ICliExecutionContext): void {\n if (this.timers.has(job.id)) return; // already running\n const timer = setInterval(async () => {\n if (!job.enabled) return;\n try {\n await context.executor.executeCommand(job.command, context);\n job.runCount++;\n job.lastRun = Date.now();\n const state = context.state.getState<CronState>();\n const updated = state.jobs.map((j) =>\n j.id === job.id ? { ...j, runCount: job.runCount, lastRun: job.lastRun } : j,\n );\n context.state.updateState({ jobs: updated });\n } catch (e) {\n console.error(`Cron job \"${job.name}\" failed:`, e);\n }\n }, job.intervalMs);\n this.timers.set(job.id, timer);\n }\n\n private stopJob(id: string): void {\n const timer = this.timers.get(id);\n if (timer) {\n clearInterval(timer);\n this.timers.delete(id);\n }\n }\n\n private async setEnabled(name: string, enabled: boolean, context: ICliExecutionContext): Promise<void> {\n const state = context.state.getState<CronState>();\n const jobIdx = state.jobs.findIndex((j) => j.name === name);\n if (jobIdx === -1) {\n context.writer.writeError(`Job \"${name}\" not found`);\n return;\n }\n const job = state.jobs[jobIdx];\n job.enabled = enabled;\n if (enabled) {\n this.startJob(job, context);\n } else {\n this.stopJob(job.id);\n }\n const updated = state.jobs.map((j) => j.name === name ? { ...j, enabled } : j);\n context.state.updateState({ jobs: updated });\n await context.state.persist();\n context.writer.writeSuccess(`Job \"${name}\" ${enabled ? 'enabled' : 'disabled'}`);\n }\n}\n","\n// Automatically generated during build\nexport const LIBRARY_VERSION = '2.0.0-beta.8';\nexport const API_VERSION = 2;\n ","/*\n * Public API Surface of cron\n */\n\nexport * from './lib/processors/cli-cron-command-processor';\nexport * from './lib/cron-utils';\nexport * from './lib/version';\n\nimport { ICliModule } from '@qodalis/cli-core';\nimport { CliCronCommandProcessor } from './lib/processors/cli-cron-command-processor';\nimport { API_VERSION } from './lib/version';\n\nexport const cronModule: ICliModule = {\n apiVersion: API_VERSION,\n name: '@qodalis/cli-cron',\n processors: [new CliCronCommandProcessor()],\n translations: {\n es: { 'cli.cron.description': 'Programar comandos para ejecución periódica' },\n fr: { 'cli.cron.description': 'Planifier des commandes à exécution périodique' },\n de: { 'cli.cron.description': 'Befehle für regelmäßige Ausführung planen' },\n pt: { 'cli.cron.description': 'Agendar comandos para execução periódica' },\n it: { 'cli.cron.description': 'Pianificare comandi a esecuzione periodica' },\n ja: { 'cli.cron.description': 'コマンドの定期実行をスケジュール' },\n ko: { 'cli.cron.description': '명령어를 주기적으로 실행하도록 예약' },\n zh: { 'cli.cron.description': '定时重复执行命令' },\n ru: { 'cli.cron.description': 'Планирование периодического выполнения команд' },\n ro: { 'cli.cron.description': 'Programează comenzi pentru execuție periodică' },\n },\n};\n"]}
1
+ {"version":3,"sources":["../../packages/plugins/cron/src/lib/cron-utils.ts","../../packages/plugins/cron/src/lib/processors/cli-cron-command-processor.ts","../../packages/plugins/cron/src/lib/version.ts","../../packages/plugins/cron/src/public-api.ts"],"names":["DefaultLibraryAuthor","CliIcon","CliForegroundColor","joinShellWords","writeWrapped","writeUsage","writeExamples"],"mappings":"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","file":"public-api.js","sourcesContent":["const MIN_INTERVAL_MS = 10_000; // 10 seconds minimum\n\nexport function parseInterval(input: string): number | null {\n if (!input.trim()) return null;\n if (/^\\d+$/.test(input.trim())) {\n const ms = parseInt(input.trim(), 10) * 1000;\n return ms >= MIN_INTERVAL_MS ? ms : null;\n }\n const pattern = /^(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/;\n const match = input.trim().match(pattern);\n if (!match || match[0] === '') return null;\n const h = parseInt(match[1] ?? '0', 10);\n const m = parseInt(match[2] ?? '0', 10);\n const s = parseInt(match[3] ?? '0', 10);\n const total = h * 3_600_000 + m * 60_000 + s * 1_000;\n return total >= MIN_INTERVAL_MS ? total : null;\n}\n\nexport function formatInterval(ms: number): string {\n const h = Math.floor(ms / 3_600_000);\n const m = Math.floor((ms % 3_600_000) / 60_000);\n const s = Math.floor((ms % 60_000) / 1_000);\n const parts: string[] = [];\n if (h > 0) parts.push(`${h}h`);\n if (m > 0) parts.push(`${m}m`);\n if (s > 0) parts.push(`${s}s`);\n return parts.join(' ') || '0s';\n}\n","import {\n ICliCommandProcessor,\n ICliExecutionContext,\n CliProcessCommand,\n ICliCommandAuthor,\n CliProcessorMetadata,\n CliIcon,\n CliStateConfiguration,\n DefaultLibraryAuthor,\n CliForegroundColor,\n ICliCommandChildProcessor,\n writeExamples,\n writeUsage,\n writeWrapped,\n joinShellWords,\n} from '@qodalis/cli-core';\nimport { parseInterval, formatInterval } from '../cron-utils';\n\ninterface CronJob {\n id: string;\n name: string;\n command: string;\n intervalMs: number;\n enabled: boolean;\n runCount: number;\n lastRun?: number;\n}\n\ninterface CronState {\n jobs: CronJob[];\n}\n\n/** The text after the first `count` shell words, as typed (quotes kept). */\nfunction textAfterWords(text: string, count: number): string {\n const word = /\\s*(?:\\\\.|\"(?:[^\"\\\\]|\\\\.)*\"|'[^']*'|[^\\s\"'\\\\]|[\"'\\\\])+/y;\n for (let i = 0; i < count; i++) {\n if (!word.exec(text)) return '';\n }\n return text.slice(word.lastIndex).trim();\n}\n\nexport class CliCronCommandProcessor implements ICliCommandProcessor {\n command = 'cron';\n description = 'Schedule commands to run on a repeating interval';\n author: ICliCommandAuthor = DefaultLibraryAuthor;\n metadata: CliProcessorMetadata = { icon: CliIcon.Clock };\n\n stateConfiguration: CliStateConfiguration = {\n storeName: 'cron',\n initialState: { jobs: [] } as CronState,\n };\n\n private timers = new Map<string, ReturnType<typeof setInterval>>();\n\n processors: ICliCommandChildProcessor[] = [\n {\n command: 'add',\n description: 'Add a cron job: cron add <name> <interval> <command>',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n const parts = cmd.positionals ?? [];\n if (parts.length < 3) {\n context.writer.writeError('Usage: cron add <name> <interval> <command>');\n context.writer.writeln(' Example: cron add ping 5m echo heartbeat');\n return;\n }\n // The command: one quoted argument, or else the rest as typed\n const [name, intervalStr, ...cmdParts] = parts;\n const command =\n cmdParts.length === 1\n ? cmdParts[0]\n : textAfterWords(cmd.value ?? '', 2) || cmdParts.join(' ');\n const intervalMs = parseInterval(intervalStr);\n if (!intervalMs) {\n context.writer.writeError(`Invalid interval \"${intervalStr}\". Min 10s. Examples: 10s, 5m, 1h`);\n return;\n }\n const state = context.state.getState<CronState>();\n if (state.jobs.find((j) => j.name === name)) {\n context.writer.writeError(`Job \"${name}\" already exists. Remove it first: cron remove ${name}`);\n return;\n }\n const job: CronJob = {\n id: `cron_${Date.now()}`,\n name,\n command,\n intervalMs,\n enabled: true,\n runCount: 0,\n };\n await context.state.update((saved) => ({\n jobs: [...((saved['jobs'] as CronJob[]) ?? []), job],\n }));\n this.startJob(job, context);\n context.writer.writeSuccess(\n `Job \"${name}\" added — runs every ${formatInterval(intervalMs)}: ${command}`,\n );\n },\n },\n {\n command: 'list',\n description: 'List all cron jobs',\n aliases: ['ls'],\n processCommand: async (_: CliProcessCommand, context: ICliExecutionContext) => {\n const { jobs } = context.state.getState<CronState>();\n if (!jobs.length) {\n context.writer.writeInfo('No cron jobs. Use: cron add <name> <interval> <command>');\n return;\n }\n context.writer.writeln(context.writer.wrapInColor('Cron Jobs:', CliForegroundColor.Yellow));\n for (const job of jobs) {\n const status = job.enabled\n ? context.writer.wrapInColor('enabled ', CliForegroundColor.Green)\n : context.writer.wrapInColor('disabled', CliForegroundColor.Red);\n context.writer.writeln(\n ` ${context.writer.wrapInColor(job.name.padEnd(12), CliForegroundColor.Cyan)}` +\n `[${status}] every ${formatInterval(job.intervalMs)} \\u2192 ${job.command} (ran ${job.runCount}x)`,\n );\n }\n },\n },\n {\n command: 'remove',\n description: 'Remove a cron job: cron remove <name>',\n aliases: ['rm', 'delete'],\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n const name = joinShellWords(cmd.value ?? '');\n const state = context.state.getState<CronState>();\n const idx = state.jobs.findIndex((j) => j.name === name);\n if (idx === -1) {\n context.writer.writeError(`Job \"${name}\" not found`);\n return;\n }\n const job = state.jobs[idx];\n this.stopJob(job.id);\n await context.state.update((saved) => ({\n jobs: ((saved['jobs'] as CronJob[]) ?? []).filter((j) => j.name !== name),\n }));\n context.writer.writeSuccess(`Job \"${name}\" removed`);\n },\n },\n {\n command: 'enable',\n description: 'Enable a paused cron job',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n await this.setEnabled(joinShellWords(cmd.value ?? ''), true, context);\n },\n },\n {\n command: 'disable',\n description: 'Pause a cron job without removing it',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n await this.setEnabled(joinShellWords(cmd.value ?? ''), false, context);\n },\n },\n ];\n\n async initialize(context: ICliExecutionContext): Promise<void> {\n const { jobs } = context.state.getState<CronState>();\n for (const job of jobs.filter((j) => j.enabled)) {\n this.startJob(job, context);\n }\n }\n\n writeDescription(context: ICliExecutionContext): void {\n const t = context.translator;\n writeWrapped(\n context,\n t.t('cli.cron.help.run_command_again_again', 'Run a command again and again at a fixed interval while the terminal is open. Jobs are saved: they start again when the terminal starts, and can be paused without removing them.'),\n );\n context.writer.writeln();\n writeUsage(context, [\n ['cron add <name> <interval> <command>', t.t('cli.cron.help.add_job', 'Add a job')],\n ['cron list', t.t('cli.cron.help.jobs_interval_status_run', 'Jobs with interval, status and run count (ls)')],\n ['cron disable <name>', t.t('cli.cron.help.pause_job', 'Pause a job')],\n ['cron enable <name>', t.t('cli.cron.help.resume_paused_job', 'Resume a paused job')],\n ['cron remove <name>', t.t('cli.cron.help.remove_job_rm_delete', 'Remove a job (rm, delete)')],\n ]);\n context.writer.writeln();\n writeWrapped(\n context,\n t.t('cli.cron.help.intervals_seconds_30_hours', 'Intervals: seconds (30), or hours, minutes and seconds (1h, 5m, 1h30m, 90s); at least 10 seconds.'),\n );\n context.writer.writeln();\n writeExamples(context, [\n ['cron add ping 5m echo heartbeat', t.t('cli.cron.help.every_5_minutes', 'Every 5 minutes')],\n ['cron add backup 1h30m server jobs trigger backup', t.t('cli.cron.help.every_hour_half', 'Every hour and a half')],\n ['cron disable ping', t.t('cli.cron.help.pause', 'Pause it')],\n ]);\n }\n\n async processCommand(_: CliProcessCommand, context: ICliExecutionContext): Promise<void> {\n const { jobs } = context.state.getState<CronState>();\n context.writer.writeln(`${jobs.length} job(s). Sub-commands: add, list, remove, enable, disable`);\n }\n\n private startJob(job: CronJob, context: ICliExecutionContext): void {\n if (this.timers.has(job.id)) return; // already running\n const timer = setInterval(async () => {\n if (!job.enabled) return;\n try {\n await context.executor.executeCommand(job.command, context);\n job.runCount++;\n job.lastRun = Date.now();\n const state = context.state.getState<CronState>();\n const updated = state.jobs.map((j) =>\n j.id === job.id ? { ...j, runCount: job.runCount, lastRun: job.lastRun } : j,\n );\n context.state.updateState({ jobs: updated });\n } catch (e) {\n context.logger.error(`Cron job \"${job.name}\" failed:`, e);\n }\n }, job.intervalMs);\n this.timers.set(job.id, timer);\n }\n\n private stopJob(id: string): void {\n const timer = this.timers.get(id);\n if (timer) {\n clearInterval(timer);\n this.timers.delete(id);\n }\n }\n\n private async setEnabled(name: string, enabled: boolean, context: ICliExecutionContext): Promise<void> {\n const state = context.state.getState<CronState>();\n const jobIdx = state.jobs.findIndex((j) => j.name === name);\n if (jobIdx === -1) {\n context.writer.writeError(`Job \"${name}\" not found`);\n return;\n }\n const job = state.jobs[jobIdx];\n job.enabled = enabled;\n if (enabled) {\n this.startJob(job, context);\n } else {\n this.stopJob(job.id);\n }\n await context.state.update((saved) => ({\n jobs: ((saved['jobs'] as CronJob[]) ?? []).map((j) =>\n j.name === name ? { ...j, enabled } : j,\n ),\n }));\n context.writer.writeSuccess(`Job \"${name}\" ${enabled ? 'enabled' : 'disabled'}`);\n }\n}\n","\n// Automatically generated during build\nexport const LIBRARY_VERSION = '2.0.0-rc.1';\nexport const API_VERSION = 2;\n ","/*\n * Public API Surface of cron\n */\n\nexport * from './lib/processors/cli-cron-command-processor';\nexport * from './lib/cron-utils';\nexport * from './lib/version';\n\nimport { ICliModule } from '@qodalis/cli-core';\nimport { CliCronCommandProcessor } from './lib/processors/cli-cron-command-processor';\nimport { API_VERSION } from './lib/version';\n\nexport const cronModule: ICliModule = {\n apiVersion: API_VERSION,\n name: '@qodalis/cli-cron',\n processors: [new CliCronCommandProcessor()],\n translations: {\n es: { 'cli.cron.description': 'Programar comandos para ejecución periódica' },\n fr: { 'cli.cron.description': 'Planifier des commandes à exécution périodique' },\n de: { 'cli.cron.description': 'Befehle für regelmäßige Ausführung planen' },\n pt: { 'cli.cron.description': 'Agendar comandos para execução periódica' },\n it: { 'cli.cron.description': 'Pianificare comandi a esecuzione periodica' },\n ja: { 'cli.cron.description': 'コマンドの定期実行をスケジュール' },\n ko: { 'cli.cron.description': '명령어를 주기적으로 실행하도록 예약' },\n zh: { 'cli.cron.description': '定时重复执行命令' },\n ru: { 'cli.cron.description': 'Планирование периодического выполнения команд' },\n ro: { 'cli.cron.description': 'Programează comenzi pentru execuție periodică' },\n },\n};\n"]}
package/public-api.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { DefaultLibraryAuthor, CliIcon, CliForegroundColor } from '@qodalis/cli-core';
1
+ import { DefaultLibraryAuthor, CliIcon, CliForegroundColor, joinShellWords, writeWrapped, writeUsage, writeExamples } from '@qodalis/cli-core';
2
2
 
3
3
  // src/lib/processors/cli-cron-command-processor.ts
4
4
 
@@ -31,6 +31,13 @@ function formatInterval(ms) {
31
31
  }
32
32
 
33
33
  // src/lib/processors/cli-cron-command-processor.ts
34
+ function textAfterWords(text, count) {
35
+ const word = /\s*(?:\\.|"(?:[^"\\]|\\.)*"|'[^']*'|[^\s"'\\]|["'\\])+/y;
36
+ for (let i = 0; i < count; i++) {
37
+ if (!word.exec(text)) return "";
38
+ }
39
+ return text.slice(word.lastIndex).trim();
40
+ }
34
41
  var CliCronCommandProcessor = class {
35
42
  constructor() {
36
43
  this.command = "cron";
@@ -49,14 +56,14 @@ var CliCronCommandProcessor = class {
49
56
  acceptsRawInput: true,
50
57
  valueRequired: true,
51
58
  processCommand: async (cmd, context) => {
52
- const parts = (cmd.value ?? "").trim().split(/\s+/);
59
+ const parts = cmd.positionals ?? [];
53
60
  if (parts.length < 3) {
54
61
  context.writer.writeError("Usage: cron add <name> <interval> <command>");
55
62
  context.writer.writeln(" Example: cron add ping 5m echo heartbeat");
56
63
  return;
57
64
  }
58
65
  const [name, intervalStr, ...cmdParts] = parts;
59
- const command = cmdParts.join(" ");
66
+ const command = cmdParts.length === 1 ? cmdParts[0] : textAfterWords(cmd.value ?? "", 2) || cmdParts.join(" ");
60
67
  const intervalMs = parseInterval(intervalStr);
61
68
  if (!intervalMs) {
62
69
  context.writer.writeError(`Invalid interval "${intervalStr}". Min 10s. Examples: 10s, 5m, 1h`);
@@ -75,9 +82,9 @@ var CliCronCommandProcessor = class {
75
82
  enabled: true,
76
83
  runCount: 0
77
84
  };
78
- const updated = [...state.jobs, job];
79
- context.state.updateState({ jobs: updated });
80
- await context.state.persist();
85
+ await context.state.update((saved) => ({
86
+ jobs: [...saved["jobs"] ?? [], job]
87
+ }));
81
88
  this.startJob(job, context);
82
89
  context.writer.writeSuccess(
83
90
  `Job "${name}" added \u2014 runs every ${formatInterval(intervalMs)}: ${command}`
@@ -110,7 +117,7 @@ var CliCronCommandProcessor = class {
110
117
  acceptsRawInput: true,
111
118
  valueRequired: true,
112
119
  processCommand: async (cmd, context) => {
113
- const name = (cmd.value ?? "").trim();
120
+ const name = joinShellWords(cmd.value ?? "");
114
121
  const state = context.state.getState();
115
122
  const idx = state.jobs.findIndex((j) => j.name === name);
116
123
  if (idx === -1) {
@@ -119,9 +126,9 @@ var CliCronCommandProcessor = class {
119
126
  }
120
127
  const job = state.jobs[idx];
121
128
  this.stopJob(job.id);
122
- const updated = state.jobs.filter((j) => j.name !== name);
123
- context.state.updateState({ jobs: updated });
124
- await context.state.persist();
129
+ await context.state.update((saved) => ({
130
+ jobs: (saved["jobs"] ?? []).filter((j) => j.name !== name)
131
+ }));
125
132
  context.writer.writeSuccess(`Job "${name}" removed`);
126
133
  }
127
134
  },
@@ -131,7 +138,7 @@ var CliCronCommandProcessor = class {
131
138
  acceptsRawInput: true,
132
139
  valueRequired: true,
133
140
  processCommand: async (cmd, context) => {
134
- await this.setEnabled((cmd.value ?? "").trim(), true, context);
141
+ await this.setEnabled(joinShellWords(cmd.value ?? ""), true, context);
135
142
  }
136
143
  },
137
144
  {
@@ -140,7 +147,7 @@ var CliCronCommandProcessor = class {
140
147
  acceptsRawInput: true,
141
148
  valueRequired: true,
142
149
  processCommand: async (cmd, context) => {
143
- await this.setEnabled((cmd.value ?? "").trim(), false, context);
150
+ await this.setEnabled(joinShellWords(cmd.value ?? ""), false, context);
144
151
  }
145
152
  }
146
153
  ];
@@ -151,6 +158,32 @@ var CliCronCommandProcessor = class {
151
158
  this.startJob(job, context);
152
159
  }
153
160
  }
161
+ writeDescription(context) {
162
+ const t = context.translator;
163
+ writeWrapped(
164
+ context,
165
+ t.t("cli.cron.help.run_command_again_again", "Run a command again and again at a fixed interval while the terminal is open. Jobs are saved: they start again when the terminal starts, and can be paused without removing them.")
166
+ );
167
+ context.writer.writeln();
168
+ writeUsage(context, [
169
+ ["cron add <name> <interval> <command>", t.t("cli.cron.help.add_job", "Add a job")],
170
+ ["cron list", t.t("cli.cron.help.jobs_interval_status_run", "Jobs with interval, status and run count (ls)")],
171
+ ["cron disable <name>", t.t("cli.cron.help.pause_job", "Pause a job")],
172
+ ["cron enable <name>", t.t("cli.cron.help.resume_paused_job", "Resume a paused job")],
173
+ ["cron remove <name>", t.t("cli.cron.help.remove_job_rm_delete", "Remove a job (rm, delete)")]
174
+ ]);
175
+ context.writer.writeln();
176
+ writeWrapped(
177
+ context,
178
+ t.t("cli.cron.help.intervals_seconds_30_hours", "Intervals: seconds (30), or hours, minutes and seconds (1h, 5m, 1h30m, 90s); at least 10 seconds.")
179
+ );
180
+ context.writer.writeln();
181
+ writeExamples(context, [
182
+ ["cron add ping 5m echo heartbeat", t.t("cli.cron.help.every_5_minutes", "Every 5 minutes")],
183
+ ["cron add backup 1h30m server jobs trigger backup", t.t("cli.cron.help.every_hour_half", "Every hour and a half")],
184
+ ["cron disable ping", t.t("cli.cron.help.pause", "Pause it")]
185
+ ]);
186
+ }
154
187
  async processCommand(_, context) {
155
188
  const { jobs } = context.state.getState();
156
189
  context.writer.writeln(`${jobs.length} job(s). Sub-commands: add, list, remove, enable, disable`);
@@ -169,7 +202,7 @@ var CliCronCommandProcessor = class {
169
202
  );
170
203
  context.state.updateState({ jobs: updated });
171
204
  } catch (e) {
172
- console.error(`Cron job "${job.name}" failed:`, e);
205
+ context.logger.error(`Cron job "${job.name}" failed:`, e);
173
206
  }
174
207
  }, job.intervalMs);
175
208
  this.timers.set(job.id, timer);
@@ -195,15 +228,17 @@ var CliCronCommandProcessor = class {
195
228
  } else {
196
229
  this.stopJob(job.id);
197
230
  }
198
- const updated = state.jobs.map((j) => j.name === name ? { ...j, enabled } : j);
199
- context.state.updateState({ jobs: updated });
200
- await context.state.persist();
231
+ await context.state.update((saved) => ({
232
+ jobs: (saved["jobs"] ?? []).map(
233
+ (j) => j.name === name ? { ...j, enabled } : j
234
+ )
235
+ }));
201
236
  context.writer.writeSuccess(`Job "${name}" ${enabled ? "enabled" : "disabled"}`);
202
237
  }
203
238
  };
204
239
 
205
240
  // src/lib/version.ts
206
- var LIBRARY_VERSION = "2.0.0-beta.8";
241
+ var LIBRARY_VERSION = "2.0.0-rc.1";
207
242
  var API_VERSION = 2;
208
243
 
209
244
  // src/public-api.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../../packages/plugins/cron/src/lib/cron-utils.ts","../../packages/plugins/cron/src/lib/processors/cli-cron-command-processor.ts","../../packages/plugins/cron/src/lib/version.ts","../../packages/plugins/cron/src/public-api.ts"],"names":[],"mappings":"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","file":"public-api.mjs","sourcesContent":["const MIN_INTERVAL_MS = 10_000; // 10 seconds minimum\n\nexport function parseInterval(input: string): number | null {\n if (!input.trim()) return null;\n if (/^\\d+$/.test(input.trim())) {\n const ms = parseInt(input.trim(), 10) * 1000;\n return ms >= MIN_INTERVAL_MS ? ms : null;\n }\n const pattern = /^(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/;\n const match = input.trim().match(pattern);\n if (!match || match[0] === '') return null;\n const h = parseInt(match[1] ?? '0', 10);\n const m = parseInt(match[2] ?? '0', 10);\n const s = parseInt(match[3] ?? '0', 10);\n const total = h * 3_600_000 + m * 60_000 + s * 1_000;\n return total >= MIN_INTERVAL_MS ? total : null;\n}\n\nexport function formatInterval(ms: number): string {\n const h = Math.floor(ms / 3_600_000);\n const m = Math.floor((ms % 3_600_000) / 60_000);\n const s = Math.floor((ms % 60_000) / 1_000);\n const parts: string[] = [];\n if (h > 0) parts.push(`${h}h`);\n if (m > 0) parts.push(`${m}m`);\n if (s > 0) parts.push(`${s}s`);\n return parts.join(' ') || '0s';\n}\n","import {\n ICliCommandProcessor,\n ICliExecutionContext,\n CliProcessCommand,\n ICliCommandAuthor,\n CliProcessorMetadata,\n CliIcon,\n CliStateConfiguration,\n DefaultLibraryAuthor,\n CliForegroundColor,\n ICliCommandChildProcessor,\n} from '@qodalis/cli-core';\nimport { parseInterval, formatInterval } from '../cron-utils';\n\ninterface CronJob {\n id: string;\n name: string;\n command: string;\n intervalMs: number;\n enabled: boolean;\n runCount: number;\n lastRun?: number;\n}\n\ninterface CronState {\n jobs: CronJob[];\n}\n\nexport class CliCronCommandProcessor implements ICliCommandProcessor {\n command = 'cron';\n description = 'Schedule commands to run on a repeating interval';\n author: ICliCommandAuthor = DefaultLibraryAuthor;\n metadata: CliProcessorMetadata = { icon: CliIcon.Clock };\n\n stateConfiguration: CliStateConfiguration = {\n storeName: 'cron',\n initialState: { jobs: [] } as CronState,\n };\n\n private timers = new Map<string, ReturnType<typeof setInterval>>();\n\n processors: ICliCommandChildProcessor[] = [\n {\n command: 'add',\n description: 'Add a cron job: cron add <name> <interval> <command>',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n const parts = (cmd.value ?? '').trim().split(/\\s+/);\n if (parts.length < 3) {\n context.writer.writeError('Usage: cron add <name> <interval> <command>');\n context.writer.writeln(' Example: cron add ping 5m echo heartbeat');\n return;\n }\n const [name, intervalStr, ...cmdParts] = parts;\n const command = cmdParts.join(' ');\n const intervalMs = parseInterval(intervalStr);\n if (!intervalMs) {\n context.writer.writeError(`Invalid interval \"${intervalStr}\". Min 10s. Examples: 10s, 5m, 1h`);\n return;\n }\n const state = context.state.getState<CronState>();\n if (state.jobs.find((j) => j.name === name)) {\n context.writer.writeError(`Job \"${name}\" already exists. Remove it first: cron remove ${name}`);\n return;\n }\n const job: CronJob = {\n id: `cron_${Date.now()}`,\n name,\n command,\n intervalMs,\n enabled: true,\n runCount: 0,\n };\n const updated = [...state.jobs, job];\n context.state.updateState({ jobs: updated });\n await context.state.persist();\n this.startJob(job, context);\n context.writer.writeSuccess(\n `Job \"${name}\" added — runs every ${formatInterval(intervalMs)}: ${command}`,\n );\n },\n },\n {\n command: 'list',\n description: 'List all cron jobs',\n aliases: ['ls'],\n processCommand: async (_: CliProcessCommand, context: ICliExecutionContext) => {\n const { jobs } = context.state.getState<CronState>();\n if (!jobs.length) {\n context.writer.writeInfo('No cron jobs. Use: cron add <name> <interval> <command>');\n return;\n }\n context.writer.writeln(context.writer.wrapInColor('Cron Jobs:', CliForegroundColor.Yellow));\n for (const job of jobs) {\n const status = job.enabled\n ? context.writer.wrapInColor('enabled ', CliForegroundColor.Green)\n : context.writer.wrapInColor('disabled', CliForegroundColor.Red);\n context.writer.writeln(\n ` ${context.writer.wrapInColor(job.name.padEnd(12), CliForegroundColor.Cyan)}` +\n `[${status}] every ${formatInterval(job.intervalMs)} \\u2192 ${job.command} (ran ${job.runCount}x)`,\n );\n }\n },\n },\n {\n command: 'remove',\n description: 'Remove a cron job: cron remove <name>',\n aliases: ['rm', 'delete'],\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n const name = (cmd.value ?? '').trim();\n const state = context.state.getState<CronState>();\n const idx = state.jobs.findIndex((j) => j.name === name);\n if (idx === -1) {\n context.writer.writeError(`Job \"${name}\" not found`);\n return;\n }\n const job = state.jobs[idx];\n this.stopJob(job.id);\n const updated = state.jobs.filter((j) => j.name !== name);\n context.state.updateState({ jobs: updated });\n await context.state.persist();\n context.writer.writeSuccess(`Job \"${name}\" removed`);\n },\n },\n {\n command: 'enable',\n description: 'Enable a paused cron job',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n await this.setEnabled((cmd.value ?? '').trim(), true, context);\n },\n },\n {\n command: 'disable',\n description: 'Pause a cron job without removing it',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n await this.setEnabled((cmd.value ?? '').trim(), false, context);\n },\n },\n ];\n\n async initialize(context: ICliExecutionContext): Promise<void> {\n const { jobs } = context.state.getState<CronState>();\n for (const job of jobs.filter((j) => j.enabled)) {\n this.startJob(job, context);\n }\n }\n\n async processCommand(_: CliProcessCommand, context: ICliExecutionContext): Promise<void> {\n const { jobs } = context.state.getState<CronState>();\n context.writer.writeln(`${jobs.length} job(s). Sub-commands: add, list, remove, enable, disable`);\n }\n\n private startJob(job: CronJob, context: ICliExecutionContext): void {\n if (this.timers.has(job.id)) return; // already running\n const timer = setInterval(async () => {\n if (!job.enabled) return;\n try {\n await context.executor.executeCommand(job.command, context);\n job.runCount++;\n job.lastRun = Date.now();\n const state = context.state.getState<CronState>();\n const updated = state.jobs.map((j) =>\n j.id === job.id ? { ...j, runCount: job.runCount, lastRun: job.lastRun } : j,\n );\n context.state.updateState({ jobs: updated });\n } catch (e) {\n console.error(`Cron job \"${job.name}\" failed:`, e);\n }\n }, job.intervalMs);\n this.timers.set(job.id, timer);\n }\n\n private stopJob(id: string): void {\n const timer = this.timers.get(id);\n if (timer) {\n clearInterval(timer);\n this.timers.delete(id);\n }\n }\n\n private async setEnabled(name: string, enabled: boolean, context: ICliExecutionContext): Promise<void> {\n const state = context.state.getState<CronState>();\n const jobIdx = state.jobs.findIndex((j) => j.name === name);\n if (jobIdx === -1) {\n context.writer.writeError(`Job \"${name}\" not found`);\n return;\n }\n const job = state.jobs[jobIdx];\n job.enabled = enabled;\n if (enabled) {\n this.startJob(job, context);\n } else {\n this.stopJob(job.id);\n }\n const updated = state.jobs.map((j) => j.name === name ? { ...j, enabled } : j);\n context.state.updateState({ jobs: updated });\n await context.state.persist();\n context.writer.writeSuccess(`Job \"${name}\" ${enabled ? 'enabled' : 'disabled'}`);\n }\n}\n","\n// Automatically generated during build\nexport const LIBRARY_VERSION = '2.0.0-beta.8';\nexport const API_VERSION = 2;\n ","/*\n * Public API Surface of cron\n */\n\nexport * from './lib/processors/cli-cron-command-processor';\nexport * from './lib/cron-utils';\nexport * from './lib/version';\n\nimport { ICliModule } from '@qodalis/cli-core';\nimport { CliCronCommandProcessor } from './lib/processors/cli-cron-command-processor';\nimport { API_VERSION } from './lib/version';\n\nexport const cronModule: ICliModule = {\n apiVersion: API_VERSION,\n name: '@qodalis/cli-cron',\n processors: [new CliCronCommandProcessor()],\n translations: {\n es: { 'cli.cron.description': 'Programar comandos para ejecución periódica' },\n fr: { 'cli.cron.description': 'Planifier des commandes à exécution périodique' },\n de: { 'cli.cron.description': 'Befehle für regelmäßige Ausführung planen' },\n pt: { 'cli.cron.description': 'Agendar comandos para execução periódica' },\n it: { 'cli.cron.description': 'Pianificare comandi a esecuzione periodica' },\n ja: { 'cli.cron.description': 'コマンドの定期実行をスケジュール' },\n ko: { 'cli.cron.description': '명령어를 주기적으로 실행하도록 예약' },\n zh: { 'cli.cron.description': '定时重复执行命令' },\n ru: { 'cli.cron.description': 'Планирование периодического выполнения команд' },\n ro: { 'cli.cron.description': 'Programează comenzi pentru execuție periodică' },\n },\n};\n"]}
1
+ {"version":3,"sources":["../../packages/plugins/cron/src/lib/cron-utils.ts","../../packages/plugins/cron/src/lib/processors/cli-cron-command-processor.ts","../../packages/plugins/cron/src/lib/version.ts","../../packages/plugins/cron/src/public-api.ts"],"names":[],"mappings":"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","file":"public-api.mjs","sourcesContent":["const MIN_INTERVAL_MS = 10_000; // 10 seconds minimum\n\nexport function parseInterval(input: string): number | null {\n if (!input.trim()) return null;\n if (/^\\d+$/.test(input.trim())) {\n const ms = parseInt(input.trim(), 10) * 1000;\n return ms >= MIN_INTERVAL_MS ? ms : null;\n }\n const pattern = /^(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/;\n const match = input.trim().match(pattern);\n if (!match || match[0] === '') return null;\n const h = parseInt(match[1] ?? '0', 10);\n const m = parseInt(match[2] ?? '0', 10);\n const s = parseInt(match[3] ?? '0', 10);\n const total = h * 3_600_000 + m * 60_000 + s * 1_000;\n return total >= MIN_INTERVAL_MS ? total : null;\n}\n\nexport function formatInterval(ms: number): string {\n const h = Math.floor(ms / 3_600_000);\n const m = Math.floor((ms % 3_600_000) / 60_000);\n const s = Math.floor((ms % 60_000) / 1_000);\n const parts: string[] = [];\n if (h > 0) parts.push(`${h}h`);\n if (m > 0) parts.push(`${m}m`);\n if (s > 0) parts.push(`${s}s`);\n return parts.join(' ') || '0s';\n}\n","import {\n ICliCommandProcessor,\n ICliExecutionContext,\n CliProcessCommand,\n ICliCommandAuthor,\n CliProcessorMetadata,\n CliIcon,\n CliStateConfiguration,\n DefaultLibraryAuthor,\n CliForegroundColor,\n ICliCommandChildProcessor,\n writeExamples,\n writeUsage,\n writeWrapped,\n joinShellWords,\n} from '@qodalis/cli-core';\nimport { parseInterval, formatInterval } from '../cron-utils';\n\ninterface CronJob {\n id: string;\n name: string;\n command: string;\n intervalMs: number;\n enabled: boolean;\n runCount: number;\n lastRun?: number;\n}\n\ninterface CronState {\n jobs: CronJob[];\n}\n\n/** The text after the first `count` shell words, as typed (quotes kept). */\nfunction textAfterWords(text: string, count: number): string {\n const word = /\\s*(?:\\\\.|\"(?:[^\"\\\\]|\\\\.)*\"|'[^']*'|[^\\s\"'\\\\]|[\"'\\\\])+/y;\n for (let i = 0; i < count; i++) {\n if (!word.exec(text)) return '';\n }\n return text.slice(word.lastIndex).trim();\n}\n\nexport class CliCronCommandProcessor implements ICliCommandProcessor {\n command = 'cron';\n description = 'Schedule commands to run on a repeating interval';\n author: ICliCommandAuthor = DefaultLibraryAuthor;\n metadata: CliProcessorMetadata = { icon: CliIcon.Clock };\n\n stateConfiguration: CliStateConfiguration = {\n storeName: 'cron',\n initialState: { jobs: [] } as CronState,\n };\n\n private timers = new Map<string, ReturnType<typeof setInterval>>();\n\n processors: ICliCommandChildProcessor[] = [\n {\n command: 'add',\n description: 'Add a cron job: cron add <name> <interval> <command>',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n const parts = cmd.positionals ?? [];\n if (parts.length < 3) {\n context.writer.writeError('Usage: cron add <name> <interval> <command>');\n context.writer.writeln(' Example: cron add ping 5m echo heartbeat');\n return;\n }\n // The command: one quoted argument, or else the rest as typed\n const [name, intervalStr, ...cmdParts] = parts;\n const command =\n cmdParts.length === 1\n ? cmdParts[0]\n : textAfterWords(cmd.value ?? '', 2) || cmdParts.join(' ');\n const intervalMs = parseInterval(intervalStr);\n if (!intervalMs) {\n context.writer.writeError(`Invalid interval \"${intervalStr}\". Min 10s. Examples: 10s, 5m, 1h`);\n return;\n }\n const state = context.state.getState<CronState>();\n if (state.jobs.find((j) => j.name === name)) {\n context.writer.writeError(`Job \"${name}\" already exists. Remove it first: cron remove ${name}`);\n return;\n }\n const job: CronJob = {\n id: `cron_${Date.now()}`,\n name,\n command,\n intervalMs,\n enabled: true,\n runCount: 0,\n };\n await context.state.update((saved) => ({\n jobs: [...((saved['jobs'] as CronJob[]) ?? []), job],\n }));\n this.startJob(job, context);\n context.writer.writeSuccess(\n `Job \"${name}\" added — runs every ${formatInterval(intervalMs)}: ${command}`,\n );\n },\n },\n {\n command: 'list',\n description: 'List all cron jobs',\n aliases: ['ls'],\n processCommand: async (_: CliProcessCommand, context: ICliExecutionContext) => {\n const { jobs } = context.state.getState<CronState>();\n if (!jobs.length) {\n context.writer.writeInfo('No cron jobs. Use: cron add <name> <interval> <command>');\n return;\n }\n context.writer.writeln(context.writer.wrapInColor('Cron Jobs:', CliForegroundColor.Yellow));\n for (const job of jobs) {\n const status = job.enabled\n ? context.writer.wrapInColor('enabled ', CliForegroundColor.Green)\n : context.writer.wrapInColor('disabled', CliForegroundColor.Red);\n context.writer.writeln(\n ` ${context.writer.wrapInColor(job.name.padEnd(12), CliForegroundColor.Cyan)}` +\n `[${status}] every ${formatInterval(job.intervalMs)} \\u2192 ${job.command} (ran ${job.runCount}x)`,\n );\n }\n },\n },\n {\n command: 'remove',\n description: 'Remove a cron job: cron remove <name>',\n aliases: ['rm', 'delete'],\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n const name = joinShellWords(cmd.value ?? '');\n const state = context.state.getState<CronState>();\n const idx = state.jobs.findIndex((j) => j.name === name);\n if (idx === -1) {\n context.writer.writeError(`Job \"${name}\" not found`);\n return;\n }\n const job = state.jobs[idx];\n this.stopJob(job.id);\n await context.state.update((saved) => ({\n jobs: ((saved['jobs'] as CronJob[]) ?? []).filter((j) => j.name !== name),\n }));\n context.writer.writeSuccess(`Job \"${name}\" removed`);\n },\n },\n {\n command: 'enable',\n description: 'Enable a paused cron job',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n await this.setEnabled(joinShellWords(cmd.value ?? ''), true, context);\n },\n },\n {\n command: 'disable',\n description: 'Pause a cron job without removing it',\n acceptsRawInput: true,\n valueRequired: true,\n processCommand: async (cmd: CliProcessCommand, context: ICliExecutionContext) => {\n await this.setEnabled(joinShellWords(cmd.value ?? ''), false, context);\n },\n },\n ];\n\n async initialize(context: ICliExecutionContext): Promise<void> {\n const { jobs } = context.state.getState<CronState>();\n for (const job of jobs.filter((j) => j.enabled)) {\n this.startJob(job, context);\n }\n }\n\n writeDescription(context: ICliExecutionContext): void {\n const t = context.translator;\n writeWrapped(\n context,\n t.t('cli.cron.help.run_command_again_again', 'Run a command again and again at a fixed interval while the terminal is open. Jobs are saved: they start again when the terminal starts, and can be paused without removing them.'),\n );\n context.writer.writeln();\n writeUsage(context, [\n ['cron add <name> <interval> <command>', t.t('cli.cron.help.add_job', 'Add a job')],\n ['cron list', t.t('cli.cron.help.jobs_interval_status_run', 'Jobs with interval, status and run count (ls)')],\n ['cron disable <name>', t.t('cli.cron.help.pause_job', 'Pause a job')],\n ['cron enable <name>', t.t('cli.cron.help.resume_paused_job', 'Resume a paused job')],\n ['cron remove <name>', t.t('cli.cron.help.remove_job_rm_delete', 'Remove a job (rm, delete)')],\n ]);\n context.writer.writeln();\n writeWrapped(\n context,\n t.t('cli.cron.help.intervals_seconds_30_hours', 'Intervals: seconds (30), or hours, minutes and seconds (1h, 5m, 1h30m, 90s); at least 10 seconds.'),\n );\n context.writer.writeln();\n writeExamples(context, [\n ['cron add ping 5m echo heartbeat', t.t('cli.cron.help.every_5_minutes', 'Every 5 minutes')],\n ['cron add backup 1h30m server jobs trigger backup', t.t('cli.cron.help.every_hour_half', 'Every hour and a half')],\n ['cron disable ping', t.t('cli.cron.help.pause', 'Pause it')],\n ]);\n }\n\n async processCommand(_: CliProcessCommand, context: ICliExecutionContext): Promise<void> {\n const { jobs } = context.state.getState<CronState>();\n context.writer.writeln(`${jobs.length} job(s). Sub-commands: add, list, remove, enable, disable`);\n }\n\n private startJob(job: CronJob, context: ICliExecutionContext): void {\n if (this.timers.has(job.id)) return; // already running\n const timer = setInterval(async () => {\n if (!job.enabled) return;\n try {\n await context.executor.executeCommand(job.command, context);\n job.runCount++;\n job.lastRun = Date.now();\n const state = context.state.getState<CronState>();\n const updated = state.jobs.map((j) =>\n j.id === job.id ? { ...j, runCount: job.runCount, lastRun: job.lastRun } : j,\n );\n context.state.updateState({ jobs: updated });\n } catch (e) {\n context.logger.error(`Cron job \"${job.name}\" failed:`, e);\n }\n }, job.intervalMs);\n this.timers.set(job.id, timer);\n }\n\n private stopJob(id: string): void {\n const timer = this.timers.get(id);\n if (timer) {\n clearInterval(timer);\n this.timers.delete(id);\n }\n }\n\n private async setEnabled(name: string, enabled: boolean, context: ICliExecutionContext): Promise<void> {\n const state = context.state.getState<CronState>();\n const jobIdx = state.jobs.findIndex((j) => j.name === name);\n if (jobIdx === -1) {\n context.writer.writeError(`Job \"${name}\" not found`);\n return;\n }\n const job = state.jobs[jobIdx];\n job.enabled = enabled;\n if (enabled) {\n this.startJob(job, context);\n } else {\n this.stopJob(job.id);\n }\n await context.state.update((saved) => ({\n jobs: ((saved['jobs'] as CronJob[]) ?? []).map((j) =>\n j.name === name ? { ...j, enabled } : j,\n ),\n }));\n context.writer.writeSuccess(`Job \"${name}\" ${enabled ? 'enabled' : 'disabled'}`);\n }\n}\n","\n// Automatically generated during build\nexport const LIBRARY_VERSION = '2.0.0-rc.1';\nexport const API_VERSION = 2;\n ","/*\n * Public API Surface of cron\n */\n\nexport * from './lib/processors/cli-cron-command-processor';\nexport * from './lib/cron-utils';\nexport * from './lib/version';\n\nimport { ICliModule } from '@qodalis/cli-core';\nimport { CliCronCommandProcessor } from './lib/processors/cli-cron-command-processor';\nimport { API_VERSION } from './lib/version';\n\nexport const cronModule: ICliModule = {\n apiVersion: API_VERSION,\n name: '@qodalis/cli-cron',\n processors: [new CliCronCommandProcessor()],\n translations: {\n es: { 'cli.cron.description': 'Programar comandos para ejecución periódica' },\n fr: { 'cli.cron.description': 'Planifier des commandes à exécution périodique' },\n de: { 'cli.cron.description': 'Befehle für regelmäßige Ausführung planen' },\n pt: { 'cli.cron.description': 'Agendar comandos para execução periódica' },\n it: { 'cli.cron.description': 'Pianificare comandi a esecuzione periodica' },\n ja: { 'cli.cron.description': 'コマンドの定期実行をスケジュール' },\n ko: { 'cli.cron.description': '명령어를 주기적으로 실행하도록 예약' },\n zh: { 'cli.cron.description': '定时重复执行命令' },\n ru: { 'cli.cron.description': 'Планирование периодического выполнения команд' },\n ro: { 'cli.cron.description': 'Programează comenzi pentru execuție periodică' },\n },\n};\n"]}