workmatic 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,24 +1,13 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Workmatic CLI
4
- *
5
- * Commands:
6
- * stats <db> Show job statistics
7
- * export <db> [output] Export jobs to CSV
8
- * import <db> <input> Import jobs from CSV
9
- * purge <db> [--status=done] Delete jobs by status
10
- * retry <db> [--status=dead] Retry failed/dead jobs
11
- * pause <db> <queue> Pause a queue (workers stop claiming)
12
- * resume <db> <queue> Resume a paused queue
13
- */
14
- import Database from 'better-sqlite3';
15
- import { createReadStream, createWriteStream } from 'fs';
16
- import { createInterface } from 'readline';
17
- // Parse command line arguments
18
- const args = process.argv.slice(2);
19
- const command = args[0];
2
+
3
+ // src/cli.ts
4
+ import Database from "better-sqlite3";
5
+ import { createReadStream, createWriteStream } from "fs";
6
+ import { createInterface } from "readline";
7
+ var args = process.argv.slice(2);
8
+ var command = args[0];
20
9
  function printUsage() {
21
- console.log(`
10
+ console.log(`
22
11
  Workmatic CLI - Job Queue Management
23
12
 
24
13
  Usage:
@@ -52,200 +41,195 @@ Examples:
52
41
  workmatic resume ./jobs.db emails
53
42
  `);
54
43
  }
55
- function parseOptions(args) {
56
- const options = {};
57
- for (const arg of args) {
58
- if (arg.startsWith('--')) {
59
- const [key, value] = arg.slice(2).split('=');
60
- options[key] = value ?? 'true';
61
- }
44
+ function parseOptions(args2) {
45
+ const options = {};
46
+ for (const arg of args2) {
47
+ if (arg.startsWith("--")) {
48
+ const [key, value] = arg.slice(2).split("=");
49
+ options[key] = value ?? "true";
62
50
  }
63
- return options;
51
+ }
52
+ return options;
64
53
  }
65
- function getPositionalArgs(args) {
66
- return args.filter(arg => !arg.startsWith('--'));
54
+ function getPositionalArgs(args2) {
55
+ return args2.filter((arg) => !arg.startsWith("--"));
67
56
  }
68
- // CSV helpers
69
57
  function escapeCSV(value) {
70
- if (value === null)
71
- return '';
72
- const str = String(value);
73
- if (str.includes(',') || str.includes('"') || str.includes('\n')) {
74
- return `"${str.replace(/"/g, '""')}"`;
75
- }
76
- return str;
58
+ if (value === null) return "";
59
+ const str = String(value);
60
+ if (str.includes(",") || str.includes('"') || str.includes("\n")) {
61
+ return `"${str.replace(/"/g, '""')}"`;
62
+ }
63
+ return str;
77
64
  }
78
65
  function parseCSVLine(line) {
79
- const result = [];
80
- let current = '';
81
- let inQuotes = false;
82
- for (let i = 0; i < line.length; i++) {
83
- const char = line[i];
84
- if (inQuotes) {
85
- if (char === '"') {
86
- if (line[i + 1] === '"') {
87
- current += '"';
88
- i++;
89
- }
90
- else {
91
- inQuotes = false;
92
- }
93
- }
94
- else {
95
- current += char;
96
- }
97
- }
98
- else {
99
- if (char === '"') {
100
- inQuotes = true;
101
- }
102
- else if (char === ',') {
103
- result.push(current);
104
- current = '';
105
- }
106
- else {
107
- current += char;
108
- }
66
+ const result = [];
67
+ let current = "";
68
+ let inQuotes = false;
69
+ for (let i = 0; i < line.length; i++) {
70
+ const char = line[i];
71
+ if (inQuotes) {
72
+ if (char === '"') {
73
+ if (line[i + 1] === '"') {
74
+ current += '"';
75
+ i++;
76
+ } else {
77
+ inQuotes = false;
109
78
  }
79
+ } else {
80
+ current += char;
81
+ }
82
+ } else {
83
+ if (char === '"') {
84
+ inQuotes = true;
85
+ } else if (char === ",") {
86
+ result.push(current);
87
+ current = "";
88
+ } else {
89
+ current += char;
90
+ }
110
91
  }
111
- result.push(current);
112
- return result;
92
+ }
93
+ result.push(current);
94
+ return result;
113
95
  }
114
- // Commands
115
96
  async function cmdStats(dbPath) {
116
- const db = new Database(dbPath, { readonly: true });
117
- try {
118
- const stats = db.prepare(`
97
+ const db = new Database(dbPath, { readonly: true });
98
+ try {
99
+ const stats = db.prepare(`
119
100
  SELECT status, COUNT(*) as count
120
101
  FROM workmatic_jobs
121
102
  GROUP BY status
122
103
  `).all();
123
- const queues = db.prepare(`
104
+ const queues = db.prepare(`
124
105
  SELECT queue, COUNT(*) as count
125
106
  FROM workmatic_jobs
126
107
  GROUP BY queue
127
108
  `).all();
128
- const total = stats.reduce((sum, s) => sum + s.count, 0);
129
- console.log('\n📊 Job Statistics\n');
130
- console.log('By Status:');
131
- console.log('─'.repeat(30));
132
- const statusOrder = ['ready', 'running', 'done', 'failed', 'dead'];
133
- const statusEmoji = {
134
- ready: '⏳',
135
- running: '▶️ ',
136
- done: '✅',
137
- failed: '⚠️ ',
138
- dead: '💀',
139
- };
140
- for (const status of statusOrder) {
141
- const stat = stats.find(s => s.status === status);
142
- const count = stat?.count ?? 0;
143
- const emoji = statusEmoji[status] || ' ';
144
- console.log(` ${emoji} ${status.padEnd(10)} ${count.toLocaleString().padStart(8)}`);
145
- }
146
- console.log('─'.repeat(30));
147
- console.log(` Total: ${total.toLocaleString().padStart(8)}`);
148
- if (queues.length > 0) {
149
- console.log('\nBy Queue:');
150
- console.log('─'.repeat(30));
151
- for (const q of queues) {
152
- console.log(` ${q.queue.padEnd(15)} ${q.count.toLocaleString().padStart(8)}`);
153
- }
154
- }
155
- console.log();
109
+ const total = stats.reduce((sum, s) => sum + s.count, 0);
110
+ console.log("\n\u{1F4CA} Job Statistics\n");
111
+ console.log("By Status:");
112
+ console.log("\u2500".repeat(30));
113
+ const statusOrder = ["ready", "running", "done", "failed", "dead"];
114
+ const statusEmoji = {
115
+ ready: "\u23F3",
116
+ running: "\u25B6\uFE0F ",
117
+ done: "\u2705",
118
+ failed: "\u26A0\uFE0F ",
119
+ dead: "\u{1F480}"
120
+ };
121
+ for (const status of statusOrder) {
122
+ const stat = stats.find((s) => s.status === status);
123
+ const count = stat?.count ?? 0;
124
+ const emoji = statusEmoji[status] || " ";
125
+ console.log(` ${emoji} ${status.padEnd(10)} ${count.toLocaleString().padStart(8)}`);
156
126
  }
157
- finally {
158
- db.close();
127
+ console.log("\u2500".repeat(30));
128
+ console.log(` Total: ${total.toLocaleString().padStart(8)}`);
129
+ if (queues.length > 0) {
130
+ console.log("\nBy Queue:");
131
+ console.log("\u2500".repeat(30));
132
+ for (const q of queues) {
133
+ console.log(` ${q.queue.padEnd(15)} ${q.count.toLocaleString().padStart(8)}`);
134
+ }
159
135
  }
136
+ console.log();
137
+ } finally {
138
+ db.close();
139
+ }
160
140
  }
161
141
  async function cmdList(dbPath, options) {
162
- const db = new Database(dbPath, { readonly: true });
163
- try {
164
- let query = 'SELECT public_id, queue, status, priority, attempts, max_attempts, created_at, last_error FROM workmatic_jobs WHERE 1=1';
165
- const params = [];
166
- if (options.status) {
167
- query += ' AND status = ?';
168
- params.push(options.status);
169
- }
170
- if (options.queue) {
171
- query += ' AND queue = ?';
172
- params.push(options.queue);
173
- }
174
- query += ' ORDER BY created_at DESC LIMIT ?';
175
- params.push(parseInt(options.limit || '100', 10));
176
- const jobs = db.prepare(query).all(...params);
177
- if (jobs.length === 0) {
178
- console.log('No jobs found.');
179
- return;
180
- }
181
- console.log('\nID Queue Status Pri Attempts Created');
182
- console.log('─'.repeat(85));
183
- for (const job of jobs) {
184
- const id = job.public_id.slice(0, 21);
185
- const queue = job.queue.slice(0, 15).padEnd(15);
186
- const status = job.status.padEnd(9);
187
- const pri = String(job.priority).padStart(3);
188
- const attempts = `${job.attempts}/${job.max_attempts}`.padStart(8);
189
- const created = new Date(job.created_at).toISOString().slice(0, 19);
190
- console.log(`${id} ${queue} ${status} ${pri} ${attempts} ${created}`);
191
- }
192
- console.log(`\nShowing ${jobs.length} jobs\n`);
142
+ const db = new Database(dbPath, { readonly: true });
143
+ try {
144
+ let query = "SELECT public_id, queue, status, priority, attempts, max_attempts, created_at, last_error FROM workmatic_jobs WHERE 1=1";
145
+ const params = [];
146
+ if (options.status) {
147
+ query += " AND status = ?";
148
+ params.push(options.status);
149
+ }
150
+ if (options.queue) {
151
+ query += " AND queue = ?";
152
+ params.push(options.queue);
153
+ }
154
+ query += " ORDER BY created_at DESC LIMIT ?";
155
+ params.push(parseInt(options.limit || "100", 10));
156
+ const jobs = db.prepare(query).all(...params);
157
+ if (jobs.length === 0) {
158
+ console.log("No jobs found.");
159
+ return;
193
160
  }
194
- finally {
195
- db.close();
161
+ console.log("\nID Queue Status Pri Attempts Created");
162
+ console.log("\u2500".repeat(85));
163
+ for (const job of jobs) {
164
+ const id = job.public_id.slice(0, 21);
165
+ const queue = job.queue.slice(0, 15).padEnd(15);
166
+ const status = job.status.padEnd(9);
167
+ const pri = String(job.priority).padStart(3);
168
+ const attempts = `${job.attempts}/${job.max_attempts}`.padStart(8);
169
+ const created = new Date(job.created_at).toISOString().slice(0, 19);
170
+ console.log(`${id} ${queue} ${status} ${pri} ${attempts} ${created}`);
196
171
  }
172
+ console.log(`
173
+ Showing ${jobs.length} jobs
174
+ `);
175
+ } finally {
176
+ db.close();
177
+ }
197
178
  }
198
179
  async function cmdExport(dbPath, outputPath, options) {
199
- const db = new Database(dbPath, { readonly: true });
200
- try {
201
- let query = 'SELECT * FROM workmatic_jobs WHERE 1=1';
202
- const params = [];
203
- if (options.status) {
204
- query += ' AND status = ?';
205
- params.push(options.status);
206
- }
207
- if (options.queue) {
208
- query += ' AND queue = ?';
209
- params.push(options.queue);
210
- }
211
- query += ' ORDER BY id';
212
- const jobs = db.prepare(query).all(...params);
213
- const output = outputPath ? createWriteStream(outputPath) : process.stdout;
214
- // Header
215
- const columns = [
216
- 'public_id', 'queue', 'payload', 'status', 'priority',
217
- 'run_at', 'attempts', 'max_attempts', 'lease_until',
218
- 'created_at', 'updated_at', 'last_error'
219
- ];
220
- if (outputPath) {
221
- output.write(columns.join(',') + '\n');
222
- }
223
- else {
224
- console.log(columns.join(','));
225
- }
226
- // Rows
227
- for (const job of jobs) {
228
- const row = columns.map(col => escapeCSV(job[col]));
229
- if (outputPath) {
230
- output.write(row.join(',') + '\n');
231
- }
232
- else {
233
- console.log(row.join(','));
234
- }
235
- }
236
- if (outputPath) {
237
- output.end();
238
- console.error(`✅ Exported ${jobs.length} jobs to ${outputPath}`);
239
- }
180
+ const db = new Database(dbPath, { readonly: true });
181
+ try {
182
+ let query = "SELECT * FROM workmatic_jobs WHERE 1=1";
183
+ const params = [];
184
+ if (options.status) {
185
+ query += " AND status = ?";
186
+ params.push(options.status);
187
+ }
188
+ if (options.queue) {
189
+ query += " AND queue = ?";
190
+ params.push(options.queue);
191
+ }
192
+ query += " ORDER BY id";
193
+ const jobs = db.prepare(query).all(...params);
194
+ const output = outputPath ? createWriteStream(outputPath) : process.stdout;
195
+ const columns = [
196
+ "public_id",
197
+ "queue",
198
+ "payload",
199
+ "status",
200
+ "priority",
201
+ "run_at",
202
+ "attempts",
203
+ "max_attempts",
204
+ "lease_until",
205
+ "created_at",
206
+ "updated_at",
207
+ "last_error"
208
+ ];
209
+ if (outputPath) {
210
+ output.write(columns.join(",") + "\n");
211
+ } else {
212
+ console.log(columns.join(","));
240
213
  }
241
- finally {
242
- db.close();
214
+ for (const job of jobs) {
215
+ const row = columns.map((col) => escapeCSV(job[col]));
216
+ if (outputPath) {
217
+ output.write(row.join(",") + "\n");
218
+ } else {
219
+ console.log(row.join(","));
220
+ }
243
221
  }
222
+ if (outputPath) {
223
+ output.end();
224
+ console.error(`\u2705 Exported ${jobs.length} jobs to ${outputPath}`);
225
+ }
226
+ } finally {
227
+ db.close();
228
+ }
244
229
  }
245
230
  async function cmdImport(dbPath, inputPath) {
246
- const db = new Database(dbPath);
247
- // Ensure schema exists
248
- db.exec(`
231
+ const db = new Database(dbPath);
232
+ db.exec(`
249
233
  CREATE TABLE IF NOT EXISTS workmatic_jobs (
250
234
  id INTEGER PRIMARY KEY AUTOINCREMENT,
251
235
  public_id TEXT UNIQUE NOT NULL,
@@ -262,79 +246,87 @@ async function cmdImport(dbPath, inputPath) {
262
246
  last_error TEXT
263
247
  )
264
248
  `);
265
- const insert = db.prepare(`
249
+ const insert = db.prepare(`
266
250
  INSERT OR REPLACE INTO workmatic_jobs
267
251
  (public_id, queue, payload, status, priority, run_at, attempts, max_attempts, lease_until, created_at, updated_at, last_error)
268
252
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
269
253
  `);
270
- const rl = createInterface({
271
- input: createReadStream(inputPath),
272
- crlfDelay: Infinity,
254
+ const rl = createInterface({
255
+ input: createReadStream(inputPath),
256
+ crlfDelay: Infinity
257
+ });
258
+ let lineNum = 0;
259
+ let imported = 0;
260
+ let columns = [];
261
+ try {
262
+ const insertMany = db.transaction((rows) => {
263
+ for (const row of rows) {
264
+ insert.run(
265
+ row.public_id,
266
+ row.queue,
267
+ row.payload,
268
+ row.status,
269
+ parseInt(row.priority, 10) || 0,
270
+ parseInt(row.run_at, 10) || Date.now(),
271
+ parseInt(row.attempts, 10) || 0,
272
+ parseInt(row.max_attempts, 10) || 3,
273
+ parseInt(row.lease_until, 10) || 0,
274
+ parseInt(row.created_at, 10) || Date.now(),
275
+ parseInt(row.updated_at, 10) || Date.now(),
276
+ row.last_error || null
277
+ );
278
+ imported++;
279
+ }
273
280
  });
274
- let lineNum = 0;
275
- let imported = 0;
276
- let columns = [];
277
- try {
278
- const insertMany = db.transaction((rows) => {
279
- for (const row of rows) {
280
- insert.run(row.public_id, row.queue, row.payload, row.status, parseInt(row.priority, 10) || 0, parseInt(row.run_at, 10) || Date.now(), parseInt(row.attempts, 10) || 0, parseInt(row.max_attempts, 10) || 3, parseInt(row.lease_until, 10) || 0, parseInt(row.created_at, 10) || Date.now(), parseInt(row.updated_at, 10) || Date.now(), row.last_error || null);
281
- imported++;
282
- }
283
- });
284
- const batch = [];
285
- for await (const line of rl) {
286
- lineNum++;
287
- if (lineNum === 1) {
288
- // Header row
289
- columns = parseCSVLine(line);
290
- continue;
291
- }
292
- if (!line.trim())
293
- continue;
294
- const values = parseCSVLine(line);
295
- const row = {};
296
- for (let i = 0; i < columns.length; i++) {
297
- row[columns[i]] = values[i] ?? '';
298
- }
299
- batch.push(row);
300
- // Batch insert every 1000 rows
301
- if (batch.length >= 1000) {
302
- insertMany(batch);
303
- batch.length = 0;
304
- process.stderr.write(`\rImported ${imported} jobs...`);
305
- }
306
- }
307
- // Insert remaining
308
- if (batch.length > 0) {
309
- insertMany(batch);
310
- }
311
- console.log(`\n✅ Imported ${imported} jobs from ${inputPath}`);
281
+ const batch = [];
282
+ for await (const line of rl) {
283
+ lineNum++;
284
+ if (lineNum === 1) {
285
+ columns = parseCSVLine(line);
286
+ continue;
287
+ }
288
+ if (!line.trim()) continue;
289
+ const values = parseCSVLine(line);
290
+ const row = {};
291
+ for (let i = 0; i < columns.length; i++) {
292
+ row[columns[i]] = values[i] ?? "";
293
+ }
294
+ batch.push(row);
295
+ if (batch.length >= 1e3) {
296
+ insertMany(batch);
297
+ batch.length = 0;
298
+ process.stderr.write(`\rImported ${imported} jobs...`);
299
+ }
312
300
  }
313
- finally {
314
- db.close();
301
+ if (batch.length > 0) {
302
+ insertMany(batch);
315
303
  }
304
+ console.log(`
305
+ \u2705 Imported ${imported} jobs from ${inputPath}`);
306
+ } finally {
307
+ db.close();
308
+ }
316
309
  }
317
310
  async function cmdPurge(dbPath, options) {
318
- if (!options.status) {
319
- console.error('Error: --status is required for purge command');
320
- console.error('Example: workmatic purge ./jobs.db --status=done');
321
- process.exit(1);
322
- }
323
- const db = new Database(dbPath);
324
- try {
325
- const result = db.prepare('DELETE FROM workmatic_jobs WHERE status = ?').run(options.status);
326
- console.log(`🗑️ Deleted ${result.changes} jobs with status '${options.status}'`);
327
- }
328
- finally {
329
- db.close();
330
- }
311
+ if (!options.status) {
312
+ console.error("Error: --status is required for purge command");
313
+ console.error("Example: workmatic purge ./jobs.db --status=done");
314
+ process.exit(1);
315
+ }
316
+ const db = new Database(dbPath);
317
+ try {
318
+ const result = db.prepare("DELETE FROM workmatic_jobs WHERE status = ?").run(options.status);
319
+ console.log(`\u{1F5D1}\uFE0F Deleted ${result.changes} jobs with status '${options.status}'`);
320
+ } finally {
321
+ db.close();
322
+ }
331
323
  }
332
324
  async function cmdRetry(dbPath, options) {
333
- const status = options.status || 'dead';
334
- const db = new Database(dbPath);
335
- try {
336
- const now = Date.now();
337
- const result = db.prepare(`
325
+ const status = options.status || "dead";
326
+ const db = new Database(dbPath);
327
+ try {
328
+ const now = Date.now();
329
+ const result = db.prepare(`
338
330
  UPDATE workmatic_jobs
339
331
  SET status = 'ready',
340
332
  attempts = 0,
@@ -343,65 +335,59 @@ async function cmdRetry(dbPath, options) {
343
335
  updated_at = ?
344
336
  WHERE status = ?
345
337
  `).run(now, now, status);
346
- console.log(`🔄 Reset ${result.changes} jobs from '${status}' to 'ready'`);
347
- }
348
- finally {
349
- db.close();
350
- }
338
+ console.log(`\u{1F504} Reset ${result.changes} jobs from '${status}' to 'ready'`);
339
+ } finally {
340
+ db.close();
341
+ }
351
342
  }
352
343
  async function cmdPause(dbPath, queueName) {
353
- const db = new Database(dbPath);
354
- try {
355
- // Ensure settings table exists
356
- db.exec(`
344
+ const db = new Database(dbPath);
345
+ try {
346
+ db.exec(`
357
347
  CREATE TABLE IF NOT EXISTS workmatic_settings (
358
348
  queue TEXT PRIMARY KEY,
359
349
  paused INTEGER NOT NULL DEFAULT 0,
360
350
  updated_at INTEGER NOT NULL
361
351
  )
362
352
  `);
363
- const now = Date.now();
364
- db.prepare(`
353
+ const now = Date.now();
354
+ db.prepare(`
365
355
  INSERT INTO workmatic_settings (queue, paused, updated_at)
366
356
  VALUES (?, 1, ?)
367
357
  ON CONFLICT(queue) DO UPDATE SET paused = 1, updated_at = ?
368
358
  `).run(queueName, now, now);
369
- console.log(`⏸️ Paused queue '${queueName}'`);
370
- console.log(` Running workers will stop claiming new jobs.`);
371
- }
372
- finally {
373
- db.close();
374
- }
359
+ console.log(`\u23F8\uFE0F Paused queue '${queueName}'`);
360
+ console.log(` Running workers will stop claiming new jobs.`);
361
+ } finally {
362
+ db.close();
363
+ }
375
364
  }
376
365
  async function cmdResume(dbPath, queueName) {
377
- const db = new Database(dbPath);
378
- try {
379
- // Ensure settings table exists
380
- db.exec(`
366
+ const db = new Database(dbPath);
367
+ try {
368
+ db.exec(`
381
369
  CREATE TABLE IF NOT EXISTS workmatic_settings (
382
370
  queue TEXT PRIMARY KEY,
383
371
  paused INTEGER NOT NULL DEFAULT 0,
384
372
  updated_at INTEGER NOT NULL
385
373
  )
386
374
  `);
387
- const now = Date.now();
388
- db.prepare(`
375
+ const now = Date.now();
376
+ db.prepare(`
389
377
  INSERT INTO workmatic_settings (queue, paused, updated_at)
390
378
  VALUES (?, 0, ?)
391
379
  ON CONFLICT(queue) DO UPDATE SET paused = 0, updated_at = ?
392
380
  `).run(queueName, now, now);
393
- console.log(`▶️ Resumed queue '${queueName}'`);
394
- console.log(` Workers will start claiming jobs again.`);
395
- }
396
- finally {
397
- db.close();
398
- }
381
+ console.log(`\u25B6\uFE0F Resumed queue '${queueName}'`);
382
+ console.log(` Workers will start claiming jobs again.`);
383
+ } finally {
384
+ db.close();
385
+ }
399
386
  }
400
387
  async function cmdQueues(dbPath) {
401
- const db = new Database(dbPath, { readonly: true });
402
- try {
403
- // Get all queues with their job counts and pause state
404
- const queues = db.prepare(`
388
+ const db = new Database(dbPath, { readonly: true });
389
+ try {
390
+ const queues = db.prepare(`
405
391
  SELECT
406
392
  j.queue,
407
393
  COUNT(*) as total,
@@ -412,94 +398,91 @@ async function cmdQueues(dbPath) {
412
398
  LEFT JOIN workmatic_settings s ON j.queue = s.queue
413
399
  GROUP BY j.queue
414
400
  `).all();
415
- if (queues.length === 0) {
416
- console.log('No queues found.');
417
- return;
418
- }
419
- console.log('\n📋 Queues\n');
420
- console.log('Queue Status Ready Running Total');
421
- console.log('─'.repeat(55));
422
- for (const q of queues) {
423
- const name = q.queue.padEnd(16);
424
- const status = q.paused ? '⏸️ PAUSED' : '▶️ ACTIVE';
425
- const ready = String(q.ready).padStart(5);
426
- const running = String(q.running).padStart(8);
427
- const total = String(q.total).padStart(6);
428
- console.log(`${name} ${status} ${ready} ${running} ${total}`);
429
- }
430
- console.log();
401
+ if (queues.length === 0) {
402
+ console.log("No queues found.");
403
+ return;
431
404
  }
432
- finally {
433
- db.close();
405
+ console.log("\n\u{1F4CB} Queues\n");
406
+ console.log("Queue Status Ready Running Total");
407
+ console.log("\u2500".repeat(55));
408
+ for (const q of queues) {
409
+ const name = q.queue.padEnd(16);
410
+ const status = q.paused ? "\u23F8\uFE0F PAUSED" : "\u25B6\uFE0F ACTIVE";
411
+ const ready = String(q.ready).padStart(5);
412
+ const running = String(q.running).padStart(8);
413
+ const total = String(q.total).padStart(6);
414
+ console.log(`${name} ${status} ${ready} ${running} ${total}`);
434
415
  }
416
+ console.log();
417
+ } finally {
418
+ db.close();
419
+ }
435
420
  }
436
- // Main
437
421
  async function main() {
438
- if (!command || command === '--help' || command === '-h') {
439
- printUsage();
440
- process.exit(0);
441
- }
442
- const positionalArgs = getPositionalArgs(args.slice(1));
443
- const options = parseOptions(args);
444
- const dbPath = positionalArgs[0];
445
- if (!dbPath) {
446
- console.error('Error: Database path is required');
447
- printUsage();
448
- process.exit(1);
449
- }
450
- try {
451
- switch (command) {
452
- case 'stats':
453
- await cmdStats(dbPath);
454
- break;
455
- case 'list':
456
- await cmdList(dbPath, options);
457
- break;
458
- case 'export':
459
- await cmdExport(dbPath, positionalArgs[1], options);
460
- break;
461
- case 'import':
462
- if (!positionalArgs[1]) {
463
- console.error('Error: Input CSV file is required');
464
- process.exit(1);
465
- }
466
- await cmdImport(dbPath, positionalArgs[1]);
467
- break;
468
- case 'purge':
469
- await cmdPurge(dbPath, options);
470
- break;
471
- case 'retry':
472
- await cmdRetry(dbPath, options);
473
- break;
474
- case 'pause':
475
- if (!positionalArgs[1]) {
476
- console.error('Error: Queue name is required');
477
- console.error('Example: workmatic pause ./jobs.db emails');
478
- process.exit(1);
479
- }
480
- await cmdPause(dbPath, positionalArgs[1]);
481
- break;
482
- case 'resume':
483
- if (!positionalArgs[1]) {
484
- console.error('Error: Queue name is required');
485
- console.error('Example: workmatic resume ./jobs.db emails');
486
- process.exit(1);
487
- }
488
- await cmdResume(dbPath, positionalArgs[1]);
489
- break;
490
- case 'queues':
491
- await cmdQueues(dbPath);
492
- break;
493
- default:
494
- console.error(`Unknown command: ${command}`);
495
- printUsage();
496
- process.exit(1);
422
+ if (!command || command === "--help" || command === "-h") {
423
+ printUsage();
424
+ process.exit(0);
425
+ }
426
+ const positionalArgs = getPositionalArgs(args.slice(1));
427
+ const options = parseOptions(args);
428
+ const dbPath = positionalArgs[0];
429
+ if (!dbPath) {
430
+ console.error("Error: Database path is required");
431
+ printUsage();
432
+ process.exit(1);
433
+ }
434
+ try {
435
+ switch (command) {
436
+ case "stats":
437
+ await cmdStats(dbPath);
438
+ break;
439
+ case "list":
440
+ await cmdList(dbPath, options);
441
+ break;
442
+ case "export":
443
+ await cmdExport(dbPath, positionalArgs[1], options);
444
+ break;
445
+ case "import":
446
+ if (!positionalArgs[1]) {
447
+ console.error("Error: Input CSV file is required");
448
+ process.exit(1);
497
449
  }
498
- }
499
- catch (error) {
500
- console.error('Error:', error instanceof Error ? error.message : error);
450
+ await cmdImport(dbPath, positionalArgs[1]);
451
+ break;
452
+ case "purge":
453
+ await cmdPurge(dbPath, options);
454
+ break;
455
+ case "retry":
456
+ await cmdRetry(dbPath, options);
457
+ break;
458
+ case "pause":
459
+ if (!positionalArgs[1]) {
460
+ console.error("Error: Queue name is required");
461
+ console.error("Example: workmatic pause ./jobs.db emails");
462
+ process.exit(1);
463
+ }
464
+ await cmdPause(dbPath, positionalArgs[1]);
465
+ break;
466
+ case "resume":
467
+ if (!positionalArgs[1]) {
468
+ console.error("Error: Queue name is required");
469
+ console.error("Example: workmatic resume ./jobs.db emails");
470
+ process.exit(1);
471
+ }
472
+ await cmdResume(dbPath, positionalArgs[1]);
473
+ break;
474
+ case "queues":
475
+ await cmdQueues(dbPath);
476
+ break;
477
+ default:
478
+ console.error(`Unknown command: ${command}`);
479
+ printUsage();
501
480
  process.exit(1);
502
481
  }
482
+ } catch (error) {
483
+ console.error("Error:", error instanceof Error ? error.message : error);
484
+ process.exit(1);
485
+ }
503
486
  }
504
487
  main();
505
488
  //# sourceMappingURL=cli.js.map