workmatic 1.0.0 β†’ 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs ADDED
@@ -0,0 +1,559 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/cli.ts
27
+ var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
28
+ var import_fs = require("fs");
29
+ var import_readline = require("readline");
30
+ var import_cli_table3 = __toESM(require("cli-table3"), 1);
31
+ var args = process.argv.slice(2);
32
+ var command = args[0];
33
+ function printUsage() {
34
+ console.log(`
35
+ Workmatic CLI - Job Queue Management
36
+
37
+ Usage:
38
+ workmatic <command> [options]
39
+
40
+ Commands:
41
+ stats <db> Show job statistics
42
+ queues <db> List all queues with status
43
+ list <db> [--status=<status>] List jobs (optionally filter by status)
44
+ export <db> [output.csv] Export jobs to CSV (default: stdout)
45
+ import <db> <input.csv> Import jobs from CSV
46
+ purge <db> --status=<status> Delete jobs by status
47
+ retry <db> [--status=dead] Retry dead/failed jobs (reset to ready)
48
+ pause <db> <queue> Pause a queue (running workers stop claiming)
49
+ resume <db> <queue> Resume a paused queue
50
+
51
+ Options:
52
+ --status=<status> Filter by status (ready|running|done|failed|dead)
53
+ --queue=<queue> Filter by queue name
54
+ --limit=<n> Limit number of results (default: 100)
55
+
56
+ Examples:
57
+ workmatic stats ./jobs.db
58
+ workmatic list ./jobs.db --status=dead --limit=10
59
+ workmatic export ./jobs.db backup.csv
60
+ workmatic export ./jobs.db --status=failed > failed-jobs.csv
61
+ workmatic import ./jobs.db backup.csv
62
+ workmatic purge ./jobs.db --status=done
63
+ workmatic retry ./jobs.db --status=dead
64
+ workmatic pause ./jobs.db emails
65
+ workmatic resume ./jobs.db emails
66
+ `);
67
+ }
68
+ function parseOptions(args2) {
69
+ const options = {};
70
+ for (const arg of args2) {
71
+ if (arg.startsWith("--")) {
72
+ const [key, value] = arg.slice(2).split("=");
73
+ options[key] = value ?? "true";
74
+ }
75
+ }
76
+ return options;
77
+ }
78
+ function getPositionalArgs(args2) {
79
+ return args2.filter((arg) => !arg.startsWith("--"));
80
+ }
81
+ function escapeCSV(value) {
82
+ if (value === null) return "";
83
+ const str = String(value);
84
+ if (str.includes(",") || str.includes('"') || str.includes("\n")) {
85
+ return `"${str.replace(/"/g, '""')}"`;
86
+ }
87
+ return str;
88
+ }
89
+ function parseCSVLine(line) {
90
+ const result = [];
91
+ let current = "";
92
+ let inQuotes = false;
93
+ for (let i = 0; i < line.length; i++) {
94
+ const char = line[i];
95
+ if (inQuotes) {
96
+ if (char === '"') {
97
+ if (line[i + 1] === '"') {
98
+ current += '"';
99
+ i++;
100
+ } else {
101
+ inQuotes = false;
102
+ }
103
+ } else {
104
+ current += char;
105
+ }
106
+ } else {
107
+ if (char === '"') {
108
+ inQuotes = true;
109
+ } else if (char === ",") {
110
+ result.push(current);
111
+ current = "";
112
+ } else {
113
+ current += char;
114
+ }
115
+ }
116
+ }
117
+ result.push(current);
118
+ return result;
119
+ }
120
+ async function cmdStats(dbPath) {
121
+ const db = new import_better_sqlite3.default(dbPath, { readonly: true });
122
+ try {
123
+ const stats = db.prepare(`
124
+ SELECT status, COUNT(*) as count
125
+ FROM workmatic_jobs
126
+ GROUP BY status
127
+ `).all();
128
+ const queues = db.prepare(`
129
+ SELECT queue, COUNT(*) as count
130
+ FROM workmatic_jobs
131
+ GROUP BY queue
132
+ `).all();
133
+ const total = stats.reduce((sum, s) => sum + s.count, 0);
134
+ console.log("\n\u{1F4CA} Job Statistics\n");
135
+ const statusOrder = ["ready", "running", "done", "failed", "dead"];
136
+ const statusEmoji = {
137
+ ready: "\u23F3",
138
+ running: "\u25B6\uFE0F",
139
+ done: "\u2705",
140
+ failed: "\u26A0\uFE0F",
141
+ dead: "\u{1F480}"
142
+ };
143
+ const statusTable = new import_cli_table3.default({
144
+ head: ["", "Status", "Count"],
145
+ style: { head: ["cyan"], border: ["gray"] },
146
+ colAligns: ["left", "left", "right"]
147
+ });
148
+ for (const status of statusOrder) {
149
+ const stat = stats.find((s) => s.status === status);
150
+ const count = stat?.count ?? 0;
151
+ const emoji = statusEmoji[status] || "";
152
+ statusTable.push([emoji, status, count.toLocaleString()]);
153
+ }
154
+ statusTable.push([{ colSpan: 2, content: "Total", hAlign: "right" }, total.toLocaleString()]);
155
+ console.log(statusTable.toString());
156
+ if (queues.length > 0) {
157
+ console.log("\n\u{1F4CB} By Queue\n");
158
+ const queueTable = new import_cli_table3.default({
159
+ head: ["Queue", "Jobs"],
160
+ style: { head: ["cyan"], border: ["gray"] },
161
+ colAligns: ["left", "right"]
162
+ });
163
+ for (const q of queues) {
164
+ queueTable.push([q.queue, q.count.toLocaleString()]);
165
+ }
166
+ console.log(queueTable.toString());
167
+ }
168
+ console.log();
169
+ } finally {
170
+ db.close();
171
+ }
172
+ }
173
+ async function cmdList(dbPath, options) {
174
+ const db = new import_better_sqlite3.default(dbPath, { readonly: true });
175
+ try {
176
+ let query = "SELECT public_id, queue, status, priority, attempts, max_attempts, created_at, last_error FROM workmatic_jobs WHERE 1=1";
177
+ const params = [];
178
+ if (options.status) {
179
+ query += " AND status = ?";
180
+ params.push(options.status);
181
+ }
182
+ if (options.queue) {
183
+ query += " AND queue = ?";
184
+ params.push(options.queue);
185
+ }
186
+ query += " ORDER BY created_at DESC LIMIT ?";
187
+ params.push(parseInt(options.limit || "100", 10));
188
+ const jobs = db.prepare(query).all(...params);
189
+ if (jobs.length === 0) {
190
+ console.log("No jobs found.");
191
+ return;
192
+ }
193
+ const statusEmoji = {
194
+ ready: "\u23F3",
195
+ running: "\u25B6\uFE0F",
196
+ done: "\u2705",
197
+ failed: "\u26A0\uFE0F",
198
+ dead: "\u{1F480}"
199
+ };
200
+ const table = new import_cli_table3.default({
201
+ head: ["ID", "Queue", "Status", "Pri", "Attempts", "Created"],
202
+ style: { head: ["cyan"], border: ["gray"] },
203
+ colAligns: ["left", "left", "left", "right", "center", "left"],
204
+ colWidths: [24, 16, 12, 5, 10, 21],
205
+ wordWrap: true
206
+ });
207
+ for (const job of jobs) {
208
+ const emoji = statusEmoji[job.status] || "";
209
+ table.push([
210
+ job.public_id.slice(0, 21),
211
+ job.queue.slice(0, 14),
212
+ `${emoji} ${job.status}`,
213
+ job.priority,
214
+ `${job.attempts}/${job.max_attempts}`,
215
+ new Date(job.created_at).toISOString().slice(0, 19)
216
+ ]);
217
+ }
218
+ console.log();
219
+ console.log(table.toString());
220
+ console.log(`
221
+ Showing ${jobs.length} jobs
222
+ `);
223
+ } finally {
224
+ db.close();
225
+ }
226
+ }
227
+ async function cmdExport(dbPath, outputPath, options) {
228
+ const db = new import_better_sqlite3.default(dbPath, { readonly: true });
229
+ try {
230
+ let query = "SELECT * FROM workmatic_jobs WHERE 1=1";
231
+ const params = [];
232
+ if (options.status) {
233
+ query += " AND status = ?";
234
+ params.push(options.status);
235
+ }
236
+ if (options.queue) {
237
+ query += " AND queue = ?";
238
+ params.push(options.queue);
239
+ }
240
+ query += " ORDER BY id";
241
+ const jobs = db.prepare(query).all(...params);
242
+ const output = outputPath ? (0, import_fs.createWriteStream)(outputPath) : process.stdout;
243
+ const columns = [
244
+ "public_id",
245
+ "queue",
246
+ "payload",
247
+ "status",
248
+ "priority",
249
+ "run_at",
250
+ "attempts",
251
+ "max_attempts",
252
+ "lease_until",
253
+ "created_at",
254
+ "updated_at",
255
+ "last_error"
256
+ ];
257
+ if (outputPath) {
258
+ output.write(columns.join(",") + "\n");
259
+ } else {
260
+ console.log(columns.join(","));
261
+ }
262
+ for (const job of jobs) {
263
+ const row = columns.map((col) => escapeCSV(job[col]));
264
+ if (outputPath) {
265
+ output.write(row.join(",") + "\n");
266
+ } else {
267
+ console.log(row.join(","));
268
+ }
269
+ }
270
+ if (outputPath) {
271
+ output.end();
272
+ console.error(`\u2705 Exported ${jobs.length} jobs to ${outputPath}`);
273
+ }
274
+ } finally {
275
+ db.close();
276
+ }
277
+ }
278
+ async function cmdImport(dbPath, inputPath) {
279
+ const db = new import_better_sqlite3.default(dbPath);
280
+ db.exec(`
281
+ CREATE TABLE IF NOT EXISTS workmatic_jobs (
282
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
283
+ public_id TEXT UNIQUE NOT NULL,
284
+ queue TEXT NOT NULL,
285
+ payload TEXT NOT NULL,
286
+ status TEXT NOT NULL DEFAULT 'ready',
287
+ priority INTEGER NOT NULL DEFAULT 0,
288
+ run_at INTEGER NOT NULL,
289
+ attempts INTEGER NOT NULL DEFAULT 0,
290
+ max_attempts INTEGER NOT NULL DEFAULT 3,
291
+ lease_until INTEGER NOT NULL DEFAULT 0,
292
+ created_at INTEGER NOT NULL,
293
+ updated_at INTEGER NOT NULL,
294
+ last_error TEXT
295
+ )
296
+ `);
297
+ const insert = db.prepare(`
298
+ INSERT OR REPLACE INTO workmatic_jobs
299
+ (public_id, queue, payload, status, priority, run_at, attempts, max_attempts, lease_until, created_at, updated_at, last_error)
300
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
301
+ `);
302
+ const rl = (0, import_readline.createInterface)({
303
+ input: (0, import_fs.createReadStream)(inputPath),
304
+ crlfDelay: Infinity
305
+ });
306
+ let lineNum = 0;
307
+ let imported = 0;
308
+ let columns = [];
309
+ try {
310
+ const insertMany = db.transaction((rows) => {
311
+ for (const row of rows) {
312
+ insert.run(
313
+ row.public_id,
314
+ row.queue,
315
+ row.payload,
316
+ row.status,
317
+ parseInt(row.priority, 10) || 0,
318
+ parseInt(row.run_at, 10) || Date.now(),
319
+ parseInt(row.attempts, 10) || 0,
320
+ parseInt(row.max_attempts, 10) || 3,
321
+ parseInt(row.lease_until, 10) || 0,
322
+ parseInt(row.created_at, 10) || Date.now(),
323
+ parseInt(row.updated_at, 10) || Date.now(),
324
+ row.last_error || null
325
+ );
326
+ imported++;
327
+ }
328
+ });
329
+ const batch = [];
330
+ for await (const line of rl) {
331
+ lineNum++;
332
+ if (lineNum === 1) {
333
+ columns = parseCSVLine(line);
334
+ continue;
335
+ }
336
+ if (!line.trim()) continue;
337
+ const values = parseCSVLine(line);
338
+ const row = {};
339
+ for (let i = 0; i < columns.length; i++) {
340
+ row[columns[i]] = values[i] ?? "";
341
+ }
342
+ batch.push(row);
343
+ if (batch.length >= 1e3) {
344
+ insertMany(batch);
345
+ batch.length = 0;
346
+ process.stderr.write(`\rImported ${imported} jobs...`);
347
+ }
348
+ }
349
+ if (batch.length > 0) {
350
+ insertMany(batch);
351
+ }
352
+ console.log(`
353
+ \u2705 Imported ${imported} jobs from ${inputPath}`);
354
+ } finally {
355
+ db.close();
356
+ }
357
+ }
358
+ async function cmdPurge(dbPath, options) {
359
+ if (!options.status) {
360
+ console.error("Error: --status is required for purge command");
361
+ console.error("Example: workmatic purge ./jobs.db --status=done");
362
+ process.exit(1);
363
+ }
364
+ const db = new import_better_sqlite3.default(dbPath);
365
+ try {
366
+ const result = db.prepare("DELETE FROM workmatic_jobs WHERE status = ?").run(options.status);
367
+ console.log(`\u{1F5D1}\uFE0F Deleted ${result.changes} jobs with status '${options.status}'`);
368
+ } finally {
369
+ db.close();
370
+ }
371
+ }
372
+ async function cmdRetry(dbPath, options) {
373
+ const status = options.status || "dead";
374
+ const db = new import_better_sqlite3.default(dbPath);
375
+ try {
376
+ const now = Date.now();
377
+ const result = db.prepare(`
378
+ UPDATE workmatic_jobs
379
+ SET status = 'ready',
380
+ attempts = 0,
381
+ run_at = ?,
382
+ lease_until = 0,
383
+ updated_at = ?
384
+ WHERE status = ?
385
+ `).run(now, now, status);
386
+ console.log(`\u{1F504} Reset ${result.changes} jobs from '${status}' to 'ready'`);
387
+ } finally {
388
+ db.close();
389
+ }
390
+ }
391
+ async function cmdPause(dbPath, queueName) {
392
+ const db = new import_better_sqlite3.default(dbPath);
393
+ try {
394
+ db.exec(`
395
+ CREATE TABLE IF NOT EXISTS workmatic_settings (
396
+ queue TEXT PRIMARY KEY,
397
+ paused INTEGER NOT NULL DEFAULT 0,
398
+ updated_at INTEGER NOT NULL
399
+ )
400
+ `);
401
+ const now = Date.now();
402
+ db.prepare(`
403
+ INSERT INTO workmatic_settings (queue, paused, updated_at)
404
+ VALUES (?, 1, ?)
405
+ ON CONFLICT(queue) DO UPDATE SET paused = 1, updated_at = ?
406
+ `).run(queueName, now, now);
407
+ console.log(`\u23F8\uFE0F Paused queue '${queueName}'`);
408
+ console.log(` Running workers will stop claiming new jobs.`);
409
+ } finally {
410
+ db.close();
411
+ }
412
+ }
413
+ async function cmdResume(dbPath, queueName) {
414
+ const db = new import_better_sqlite3.default(dbPath);
415
+ try {
416
+ db.exec(`
417
+ CREATE TABLE IF NOT EXISTS workmatic_settings (
418
+ queue TEXT PRIMARY KEY,
419
+ paused INTEGER NOT NULL DEFAULT 0,
420
+ updated_at INTEGER NOT NULL
421
+ )
422
+ `);
423
+ const now = Date.now();
424
+ db.prepare(`
425
+ INSERT INTO workmatic_settings (queue, paused, updated_at)
426
+ VALUES (?, 0, ?)
427
+ ON CONFLICT(queue) DO UPDATE SET paused = 0, updated_at = ?
428
+ `).run(queueName, now, now);
429
+ console.log(`\u25B6\uFE0F Resumed queue '${queueName}'`);
430
+ console.log(` Workers will start claiming jobs again.`);
431
+ } finally {
432
+ db.close();
433
+ }
434
+ }
435
+ async function cmdQueues(dbPath) {
436
+ const db = new import_better_sqlite3.default(dbPath, { readonly: true });
437
+ try {
438
+ const settingsExists = db.prepare(`
439
+ SELECT name FROM sqlite_master WHERE type='table' AND name='workmatic_settings'
440
+ `).get();
441
+ let queues;
442
+ if (settingsExists) {
443
+ queues = db.prepare(`
444
+ SELECT
445
+ j.queue,
446
+ COUNT(*) as total,
447
+ SUM(CASE WHEN j.status = 'ready' THEN 1 ELSE 0 END) as ready,
448
+ SUM(CASE WHEN j.status = 'running' THEN 1 ELSE 0 END) as running,
449
+ COALESCE(s.paused, 0) as paused
450
+ FROM workmatic_jobs j
451
+ LEFT JOIN workmatic_settings s ON j.queue = s.queue
452
+ GROUP BY j.queue
453
+ `).all();
454
+ } else {
455
+ queues = db.prepare(`
456
+ SELECT
457
+ queue,
458
+ COUNT(*) as total,
459
+ SUM(CASE WHEN status = 'ready' THEN 1 ELSE 0 END) as ready,
460
+ SUM(CASE WHEN status = 'running' THEN 1 ELSE 0 END) as running,
461
+ 0 as paused
462
+ FROM workmatic_jobs
463
+ GROUP BY queue
464
+ `).all();
465
+ }
466
+ if (queues.length === 0) {
467
+ console.log("No queues found.");
468
+ return;
469
+ }
470
+ console.log("\n\u{1F4CB} Queues\n");
471
+ const table = new import_cli_table3.default({
472
+ head: ["Queue", "Status", "Ready", "Running", "Total"],
473
+ style: { head: ["cyan"], border: ["gray"] },
474
+ colAligns: ["left", "left", "right", "right", "right"]
475
+ });
476
+ for (const q of queues) {
477
+ const status = q.paused ? "\u23F8\uFE0F PAUSED" : "\u25B6\uFE0F ACTIVE";
478
+ table.push([
479
+ q.queue,
480
+ status,
481
+ q.ready.toLocaleString(),
482
+ q.running.toLocaleString(),
483
+ q.total.toLocaleString()
484
+ ]);
485
+ }
486
+ console.log(table.toString());
487
+ console.log();
488
+ } finally {
489
+ db.close();
490
+ }
491
+ }
492
+ async function main() {
493
+ if (!command || command === "--help" || command === "-h") {
494
+ printUsage();
495
+ process.exit(0);
496
+ }
497
+ const positionalArgs = getPositionalArgs(args.slice(1));
498
+ const options = parseOptions(args);
499
+ const dbPath = positionalArgs[0];
500
+ if (!dbPath) {
501
+ console.error("Error: Database path is required");
502
+ printUsage();
503
+ process.exit(1);
504
+ }
505
+ try {
506
+ switch (command) {
507
+ case "stats":
508
+ await cmdStats(dbPath);
509
+ break;
510
+ case "list":
511
+ await cmdList(dbPath, options);
512
+ break;
513
+ case "export":
514
+ await cmdExport(dbPath, positionalArgs[1], options);
515
+ break;
516
+ case "import":
517
+ if (!positionalArgs[1]) {
518
+ console.error("Error: Input CSV file is required");
519
+ process.exit(1);
520
+ }
521
+ await cmdImport(dbPath, positionalArgs[1]);
522
+ break;
523
+ case "purge":
524
+ await cmdPurge(dbPath, options);
525
+ break;
526
+ case "retry":
527
+ await cmdRetry(dbPath, options);
528
+ break;
529
+ case "pause":
530
+ if (!positionalArgs[1]) {
531
+ console.error("Error: Queue name is required");
532
+ console.error("Example: workmatic pause ./jobs.db emails");
533
+ process.exit(1);
534
+ }
535
+ await cmdPause(dbPath, positionalArgs[1]);
536
+ break;
537
+ case "resume":
538
+ if (!positionalArgs[1]) {
539
+ console.error("Error: Queue name is required");
540
+ console.error("Example: workmatic resume ./jobs.db emails");
541
+ process.exit(1);
542
+ }
543
+ await cmdResume(dbPath, positionalArgs[1]);
544
+ break;
545
+ case "queues":
546
+ await cmdQueues(dbPath);
547
+ break;
548
+ default:
549
+ console.error(`Unknown command: ${command}`);
550
+ printUsage();
551
+ process.exit(1);
552
+ }
553
+ } catch (error) {
554
+ console.error("Error:", error instanceof Error ? error.message : error);
555
+ process.exit(1);
556
+ }
557
+ }
558
+ main();
559
+ //# sourceMappingURL=cli.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Workmatic CLI\n * \n * Commands:\n * stats <db> Show job statistics\n * export <db> [output] Export jobs to CSV\n * import <db> <input> Import jobs from CSV\n * purge <db> [--status=done] Delete jobs by status\n * retry <db> [--status=dead] Retry failed/dead jobs\n * pause <db> <queue> Pause a queue (workers stop claiming)\n * resume <db> <queue> Resume a paused queue\n */\n\nimport Database from 'better-sqlite3';\nimport { createReadStream, createWriteStream } from 'fs';\nimport { createInterface } from 'readline';\nimport Table from 'cli-table3';\n\n// Parse command line arguments\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nfunction printUsage(): void {\n console.log(`\nWorkmatic CLI - Job Queue Management\n\nUsage:\n workmatic <command> [options]\n\nCommands:\n stats <db> Show job statistics\n queues <db> List all queues with status\n list <db> [--status=<status>] List jobs (optionally filter by status)\n export <db> [output.csv] Export jobs to CSV (default: stdout)\n import <db> <input.csv> Import jobs from CSV\n purge <db> --status=<status> Delete jobs by status\n retry <db> [--status=dead] Retry dead/failed jobs (reset to ready)\n pause <db> <queue> Pause a queue (running workers stop claiming)\n resume <db> <queue> Resume a paused queue\n\nOptions:\n --status=<status> Filter by status (ready|running|done|failed|dead)\n --queue=<queue> Filter by queue name\n --limit=<n> Limit number of results (default: 100)\n\nExamples:\n workmatic stats ./jobs.db\n workmatic list ./jobs.db --status=dead --limit=10\n workmatic export ./jobs.db backup.csv\n workmatic export ./jobs.db --status=failed > failed-jobs.csv\n workmatic import ./jobs.db backup.csv\n workmatic purge ./jobs.db --status=done\n workmatic retry ./jobs.db --status=dead\n workmatic pause ./jobs.db emails\n workmatic resume ./jobs.db emails\n`);\n}\n\nfunction parseOptions(args: string[]): Record<string, string> {\n const options: Record<string, string> = {};\n for (const arg of args) {\n if (arg.startsWith('--')) {\n const [key, value] = arg.slice(2).split('=');\n options[key] = value ?? 'true';\n }\n }\n return options;\n}\n\nfunction getPositionalArgs(args: string[]): string[] {\n return args.filter(arg => !arg.startsWith('--'));\n}\n\n// CSV helpers\nfunction escapeCSV(value: string | null): string {\n if (value === null) return '';\n const str = String(value);\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n}\n\nfunction parseCSVLine(line: string): string[] {\n const result: string[] = [];\n let current = '';\n let inQuotes = false;\n \n for (let i = 0; i < line.length; i++) {\n const char = line[i];\n \n if (inQuotes) {\n if (char === '\"') {\n if (line[i + 1] === '\"') {\n current += '\"';\n i++;\n } else {\n inQuotes = false;\n }\n } else {\n current += char;\n }\n } else {\n if (char === '\"') {\n inQuotes = true;\n } else if (char === ',') {\n result.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n }\n \n result.push(current);\n return result;\n}\n\n// Commands\nasync function cmdStats(dbPath: string): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n \n try {\n const stats = db.prepare(`\n SELECT status, COUNT(*) as count \n FROM workmatic_jobs \n GROUP BY status\n `).all() as { status: string; count: number }[];\n \n const queues = db.prepare(`\n SELECT queue, COUNT(*) as count \n FROM workmatic_jobs \n GROUP BY queue\n `).all() as { queue: string; count: number }[];\n \n const total = stats.reduce((sum, s) => sum + s.count, 0);\n \n console.log('\\nπŸ“Š Job Statistics\\n');\n \n const statusOrder = ['ready', 'running', 'done', 'failed', 'dead'];\n const statusEmoji: Record<string, string> = {\n ready: '⏳',\n running: '▢️',\n done: 'βœ…',\n failed: '⚠️',\n dead: 'πŸ’€',\n };\n \n const statusTable = new Table({\n head: ['', 'Status', 'Count'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'left', 'right'],\n });\n \n for (const status of statusOrder) {\n const stat = stats.find(s => s.status === status);\n const count = stat?.count ?? 0;\n const emoji = statusEmoji[status] || '';\n statusTable.push([emoji, status, count.toLocaleString()]);\n }\n statusTable.push([{ colSpan: 2, content: 'Total', hAlign: 'right' }, total.toLocaleString()]);\n \n console.log(statusTable.toString());\n \n if (queues.length > 0) {\n console.log('\\nπŸ“‹ By Queue\\n');\n \n const queueTable = new Table({\n head: ['Queue', 'Jobs'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'right'],\n });\n \n for (const q of queues) {\n queueTable.push([q.queue, q.count.toLocaleString()]);\n }\n \n console.log(queueTable.toString());\n }\n \n console.log();\n } finally {\n db.close();\n }\n}\n\nasync function cmdList(dbPath: string, options: Record<string, string>): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n \n try {\n let query = 'SELECT public_id, queue, status, priority, attempts, max_attempts, created_at, last_error FROM workmatic_jobs WHERE 1=1';\n const params: any[] = [];\n \n if (options.status) {\n query += ' AND status = ?';\n params.push(options.status);\n }\n if (options.queue) {\n query += ' AND queue = ?';\n params.push(options.queue);\n }\n \n query += ' ORDER BY created_at DESC LIMIT ?';\n params.push(parseInt(options.limit || '100', 10));\n \n const jobs = db.prepare(query).all(...params) as any[];\n \n if (jobs.length === 0) {\n console.log('No jobs found.');\n return;\n }\n \n const statusEmoji: Record<string, string> = {\n ready: '⏳',\n running: '▢️',\n done: 'βœ…',\n failed: '⚠️',\n dead: 'πŸ’€',\n };\n \n const table = new Table({\n head: ['ID', 'Queue', 'Status', 'Pri', 'Attempts', 'Created'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'left', 'left', 'right', 'center', 'left'],\n colWidths: [24, 16, 12, 5, 10, 21],\n wordWrap: true,\n });\n \n for (const job of jobs) {\n const emoji = statusEmoji[job.status] || '';\n table.push([\n job.public_id.slice(0, 21),\n job.queue.slice(0, 14),\n `${emoji} ${job.status}`,\n job.priority,\n `${job.attempts}/${job.max_attempts}`,\n new Date(job.created_at).toISOString().slice(0, 19),\n ]);\n }\n \n console.log();\n console.log(table.toString());\n console.log(`\\n Showing ${jobs.length} jobs\\n`);\n } finally {\n db.close();\n }\n}\n\nasync function cmdExport(dbPath: string, outputPath: string | undefined, options: Record<string, string>): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n \n try {\n let query = 'SELECT * FROM workmatic_jobs WHERE 1=1';\n const params: any[] = [];\n \n if (options.status) {\n query += ' AND status = ?';\n params.push(options.status);\n }\n if (options.queue) {\n query += ' AND queue = ?';\n params.push(options.queue);\n }\n \n query += ' ORDER BY id';\n \n const jobs = db.prepare(query).all(...params) as any[];\n \n const output = outputPath ? createWriteStream(outputPath) : process.stdout;\n \n // Header\n const columns = [\n 'public_id', 'queue', 'payload', 'status', 'priority',\n 'run_at', 'attempts', 'max_attempts', 'lease_until',\n 'created_at', 'updated_at', 'last_error'\n ];\n \n if (outputPath) {\n output.write(columns.join(',') + '\\n');\n } else {\n console.log(columns.join(','));\n }\n \n // Rows\n for (const job of jobs) {\n const row = columns.map(col => escapeCSV(job[col]));\n if (outputPath) {\n output.write(row.join(',') + '\\n');\n } else {\n console.log(row.join(','));\n }\n }\n \n if (outputPath) {\n (output as any).end();\n console.error(`βœ… Exported ${jobs.length} jobs to ${outputPath}`);\n }\n } finally {\n db.close();\n }\n}\n\nasync function cmdImport(dbPath: string, inputPath: string): Promise<void> {\n const db = new Database(dbPath);\n \n // Ensure schema exists\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_jobs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n public_id TEXT UNIQUE NOT NULL,\n queue TEXT NOT NULL,\n payload TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'ready',\n priority INTEGER NOT NULL DEFAULT 0,\n run_at INTEGER NOT NULL,\n attempts INTEGER NOT NULL DEFAULT 0,\n max_attempts INTEGER NOT NULL DEFAULT 3,\n lease_until INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n last_error TEXT\n )\n `);\n \n const insert = db.prepare(`\n INSERT OR REPLACE INTO workmatic_jobs \n (public_id, queue, payload, status, priority, run_at, attempts, max_attempts, lease_until, created_at, updated_at, last_error)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n const rl = createInterface({\n input: createReadStream(inputPath),\n crlfDelay: Infinity,\n });\n \n let lineNum = 0;\n let imported = 0;\n let columns: string[] = [];\n \n try {\n const insertMany = db.transaction((rows: any[]) => {\n for (const row of rows) {\n insert.run(\n row.public_id,\n row.queue,\n row.payload,\n row.status,\n parseInt(row.priority, 10) || 0,\n parseInt(row.run_at, 10) || Date.now(),\n parseInt(row.attempts, 10) || 0,\n parseInt(row.max_attempts, 10) || 3,\n parseInt(row.lease_until, 10) || 0,\n parseInt(row.created_at, 10) || Date.now(),\n parseInt(row.updated_at, 10) || Date.now(),\n row.last_error || null\n );\n imported++;\n }\n });\n \n const batch: any[] = [];\n \n for await (const line of rl) {\n lineNum++;\n \n if (lineNum === 1) {\n // Header row\n columns = parseCSVLine(line);\n continue;\n }\n \n if (!line.trim()) continue;\n \n const values = parseCSVLine(line);\n const row: Record<string, string> = {};\n \n for (let i = 0; i < columns.length; i++) {\n row[columns[i]] = values[i] ?? '';\n }\n \n batch.push(row);\n \n // Batch insert every 1000 rows\n if (batch.length >= 1000) {\n insertMany(batch);\n batch.length = 0;\n process.stderr.write(`\\rImported ${imported} jobs...`);\n }\n }\n \n // Insert remaining\n if (batch.length > 0) {\n insertMany(batch);\n }\n \n console.log(`\\nβœ… Imported ${imported} jobs from ${inputPath}`);\n } finally {\n db.close();\n }\n}\n\nasync function cmdPurge(dbPath: string, options: Record<string, string>): Promise<void> {\n if (!options.status) {\n console.error('Error: --status is required for purge command');\n console.error('Example: workmatic purge ./jobs.db --status=done');\n process.exit(1);\n }\n \n const db = new Database(dbPath);\n \n try {\n const result = db.prepare('DELETE FROM workmatic_jobs WHERE status = ?').run(options.status);\n console.log(`πŸ—‘οΈ Deleted ${result.changes} jobs with status '${options.status}'`);\n } finally {\n db.close();\n }\n}\n\nasync function cmdRetry(dbPath: string, options: Record<string, string>): Promise<void> {\n const status = options.status || 'dead';\n const db = new Database(dbPath);\n \n try {\n const now = Date.now();\n const result = db.prepare(`\n UPDATE workmatic_jobs \n SET status = 'ready', \n attempts = 0, \n run_at = ?, \n lease_until = 0,\n updated_at = ?\n WHERE status = ?\n `).run(now, now, status);\n \n console.log(`πŸ”„ Reset ${result.changes} jobs from '${status}' to 'ready'`);\n } finally {\n db.close();\n }\n}\n\nasync function cmdPause(dbPath: string, queueName: string): Promise<void> {\n const db = new Database(dbPath);\n \n try {\n // Ensure settings table exists\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_settings (\n queue TEXT PRIMARY KEY,\n paused INTEGER NOT NULL DEFAULT 0,\n updated_at INTEGER NOT NULL\n )\n `);\n \n const now = Date.now();\n db.prepare(`\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (?, 1, ?)\n ON CONFLICT(queue) DO UPDATE SET paused = 1, updated_at = ?\n `).run(queueName, now, now);\n \n console.log(`⏸️ Paused queue '${queueName}'`);\n console.log(` Running workers will stop claiming new jobs.`);\n } finally {\n db.close();\n }\n}\n\nasync function cmdResume(dbPath: string, queueName: string): Promise<void> {\n const db = new Database(dbPath);\n \n try {\n // Ensure settings table exists\n db.exec(`\n CREATE TABLE IF NOT EXISTS workmatic_settings (\n queue TEXT PRIMARY KEY,\n paused INTEGER NOT NULL DEFAULT 0,\n updated_at INTEGER NOT NULL\n )\n `);\n \n const now = Date.now();\n db.prepare(`\n INSERT INTO workmatic_settings (queue, paused, updated_at)\n VALUES (?, 0, ?)\n ON CONFLICT(queue) DO UPDATE SET paused = 0, updated_at = ?\n `).run(queueName, now, now);\n \n console.log(`▢️ Resumed queue '${queueName}'`);\n console.log(` Workers will start claiming jobs again.`);\n } finally {\n db.close();\n }\n}\n\nasync function cmdQueues(dbPath: string): Promise<void> {\n const db = new Database(dbPath, { readonly: true });\n \n try {\n // Check if settings table exists\n const settingsExists = db.prepare(`\n SELECT name FROM sqlite_master WHERE type='table' AND name='workmatic_settings'\n `).get();\n \n // Get all queues with their job counts and pause state\n let queues: { queue: string; total: number; ready: number; running: number; paused: number }[];\n \n if (settingsExists) {\n queues = db.prepare(`\n SELECT \n j.queue,\n COUNT(*) as total,\n SUM(CASE WHEN j.status = 'ready' THEN 1 ELSE 0 END) as ready,\n SUM(CASE WHEN j.status = 'running' THEN 1 ELSE 0 END) as running,\n COALESCE(s.paused, 0) as paused\n FROM workmatic_jobs j\n LEFT JOIN workmatic_settings s ON j.queue = s.queue\n GROUP BY j.queue\n `).all() as typeof queues;\n } else {\n queues = db.prepare(`\n SELECT \n queue,\n COUNT(*) as total,\n SUM(CASE WHEN status = 'ready' THEN 1 ELSE 0 END) as ready,\n SUM(CASE WHEN status = 'running' THEN 1 ELSE 0 END) as running,\n 0 as paused\n FROM workmatic_jobs\n GROUP BY queue\n `).all() as typeof queues;\n }\n \n if (queues.length === 0) {\n console.log('No queues found.');\n return;\n }\n \n console.log('\\nπŸ“‹ Queues\\n');\n \n const table = new Table({\n head: ['Queue', 'Status', 'Ready', 'Running', 'Total'],\n style: { head: ['cyan'], border: ['gray'] },\n colAligns: ['left', 'left', 'right', 'right', 'right'],\n });\n \n for (const q of queues) {\n const status = q.paused ? '⏸️ PAUSED' : '▢️ ACTIVE';\n table.push([\n q.queue,\n status,\n q.ready.toLocaleString(),\n q.running.toLocaleString(),\n q.total.toLocaleString(),\n ]);\n }\n \n console.log(table.toString());\n console.log();\n } finally {\n db.close();\n }\n}\n\n// Main\nasync function main(): Promise<void> {\n if (!command || command === '--help' || command === '-h') {\n printUsage();\n process.exit(0);\n }\n \n const positionalArgs = getPositionalArgs(args.slice(1));\n const options = parseOptions(args);\n \n const dbPath = positionalArgs[0];\n \n if (!dbPath) {\n console.error('Error: Database path is required');\n printUsage();\n process.exit(1);\n }\n \n try {\n switch (command) {\n case 'stats':\n await cmdStats(dbPath);\n break;\n \n case 'list':\n await cmdList(dbPath, options);\n break;\n \n case 'export':\n await cmdExport(dbPath, positionalArgs[1], options);\n break;\n \n case 'import':\n if (!positionalArgs[1]) {\n console.error('Error: Input CSV file is required');\n process.exit(1);\n }\n await cmdImport(dbPath, positionalArgs[1]);\n break;\n \n case 'purge':\n await cmdPurge(dbPath, options);\n break;\n \n case 'retry':\n await cmdRetry(dbPath, options);\n break;\n \n case 'pause':\n if (!positionalArgs[1]) {\n console.error('Error: Queue name is required');\n console.error('Example: workmatic pause ./jobs.db emails');\n process.exit(1);\n }\n await cmdPause(dbPath, positionalArgs[1]);\n break;\n \n case 'resume':\n if (!positionalArgs[1]) {\n console.error('Error: Queue name is required');\n console.error('Example: workmatic resume ./jobs.db emails');\n process.exit(1);\n }\n await cmdResume(dbPath, positionalArgs[1]);\n break;\n \n case 'queues':\n await cmdQueues(dbPath);\n break;\n \n default:\n console.error(`Unknown command: ${command}`);\n printUsage();\n process.exit(1);\n }\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":"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","names":["args","Database","Table"]}
package/dist/cli.d.cts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.d.ts CHANGED
@@ -1,15 +1 @@
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
- export {};
15
- //# sourceMappingURL=cli.d.ts.map