@san-siva/blogkit-md-cli 0.1.20 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/cache/.previewinfo +1 -1
  4. package/.next/cache/.rscinfo +1 -1
  5. package/.next/cache/.tsbuildinfo +1 -1
  6. package/.next/diagnostics/route-bundle-stats.json +4 -4
  7. package/.next/fallback-build-manifest.json +3 -3
  8. package/.next/prerender-manifest.json +3 -3
  9. package/.next/server/app/[...slug]/page_client-reference-manifest.js +1 -1
  10. package/.next/server/app/_global-error.html +1 -1
  11. package/.next/server/app/_global-error.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  16. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  17. package/.next/server/app/_not-found.html +1 -1
  18. package/.next/server/app/_not-found.rsc +1 -1
  19. package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  20. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  21. package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  22. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  23. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  24. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  25. package/.next/server/app/page_client-reference-manifest.js +1 -1
  26. package/.next/server/chunks/ssr/_0lv77ha._.js +1 -1
  27. package/.next/server/chunks/ssr/_0lv77ha._.js.map +1 -1
  28. package/.next/server/chunks/ssr/_0z4n825._.js +1 -1
  29. package/.next/server/chunks/ssr/_0z4n825._.js.map +1 -1
  30. package/.next/server/middleware-build-manifest.js +3 -3
  31. package/.next/server/pages/404.html +1 -1
  32. package/.next/server/pages/500.html +1 -1
  33. package/.next/server/server-reference-manifest.js +1 -1
  34. package/.next/server/server-reference-manifest.json +1 -1
  35. package/.next/static/chunks/{0mr~5~notxy69.js → 0bgomtoptb4q7.js} +1 -1
  36. package/.next/static/chunks/{15yu-awv-.t~z.js → 10t4l336soqlc.js} +1 -1
  37. package/.next/trace +1 -1
  38. package/.next/trace-build +1 -1
  39. package/README.md +37 -2
  40. package/bin/blogkit-md.js +389 -46
  41. package/package.json +19 -4
  42. /package/.next/static/{k_detxuW-GmsRteYh4x8e → N6e_l60Njhp5bsxU4aIBS}/_buildManifest.js +0 -0
  43. /package/.next/static/{k_detxuW-GmsRteYh4x8e → N6e_l60Njhp5bsxU4aIBS}/_clientMiddlewareManifest.js +0 -0
  44. /package/.next/static/{k_detxuW-GmsRteYh4x8e → N6e_l60Njhp5bsxU4aIBS}/_ssgManifest.js +0 -0
package/bin/blogkit-md.js CHANGED
@@ -22,64 +22,360 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  mod
23
23
  ));
24
24
 
25
- // scripts/blogkit-md.ts
26
- var import_node_http = require("http");
25
+ // scripts/cli.ts
27
26
  var import_node_child_process = require("child_process");
28
27
  var import_node_fs = require("fs");
28
+ var import_node_http = require("http");
29
+ var import_node_os = __toESM(require("os"));
29
30
  var import_node_path = __toESM(require("path"));
30
- var args = process.argv.slice(2);
31
- var inputArg = args.find((a) => !a.startsWith("--"));
32
- var portArg = args.find((a) => a.startsWith("--port="));
33
- var requestedPort = portArg ? parseInt(portArg.split("=")[1]) : 0;
34
- if (!inputArg) {
35
- console.error("Usage: blogkit-md <path-to-markdown-file-or-directory> [--port=3001]");
36
- process.exit(1);
31
+ var import_node_readline = __toESM(require("readline"));
32
+ var useColor = process.stdout.isTTY && !process.env.NO_COLOR;
33
+ var paint = (code) => (s) => useColor ? `\x1B[${code}m${s}\x1B[0m` : s;
34
+ var c = {
35
+ bold: paint("1"),
36
+ dim: paint("2"),
37
+ red: paint("31"),
38
+ green: paint("32"),
39
+ yellow: paint("33"),
40
+ blue: paint("34"),
41
+ magenta: paint("35"),
42
+ cyan: paint("36"),
43
+ gray: paint("90")
44
+ };
45
+ var INDENT = " ".repeat(3);
46
+ var line = (s = "") => console.log(INDENT + s);
47
+ var tree = (s = "") => console.log(c.gray(INDENT + "\u2502 ") + s);
48
+ var bannerShown = false;
49
+ function banner() {
50
+ if (bannerShown) return;
51
+ bannerShown = true;
52
+ line();
53
+ line(c.bold(c.blue("blogkit-md")));
54
+ line(c.gray("preview markdown as blogkit blog posts"));
55
+ line();
37
56
  }
38
- var packageRoot = import_node_path.default.dirname(import_node_path.default.dirname(process.argv[1]));
39
- var inputPath = import_node_path.default.resolve(process.cwd(), inputArg);
40
- var nextBin = import_node_path.default.join(packageRoot, "node_modules/.bin/next");
41
- var inputStat;
42
- try {
43
- inputStat = (0, import_node_fs.statSync)(inputPath);
44
- } catch {
45
- console.error(`Path does not exist: ${inputPath}`);
46
- process.exit(1);
57
+ var tilde = (p) => {
58
+ const home = import_node_os.default.homedir();
59
+ return p.startsWith(home) ? "~" + p.slice(home.length) : p;
60
+ };
61
+ function humanAge(iso) {
62
+ const start = Date.parse(iso);
63
+ if (Number.isNaN(start)) return "\u2014";
64
+ const secs = Math.max(0, Math.floor((Date.now() - start) / 1e3));
65
+ if (secs < 60) return `${secs}s`;
66
+ if (secs < 3600) return `${Math.floor(secs / 60)}m`;
67
+ if (secs < 86400) return `${Math.floor(secs / 3600)}h`;
68
+ return `${Math.floor(secs / 86400)}d`;
69
+ }
70
+ function openBrowser(url) {
71
+ if (process.env.BLOGKIT_MD_NO_OPEN) return;
72
+ try {
73
+ (0, import_node_child_process.exec)(`open ${url}`);
74
+ } catch {
75
+ }
76
+ }
77
+ var registryDir = () => process.env.BLOGKIT_MD_DIR || import_node_path.default.join(import_node_os.default.homedir(), ".blogkit-md");
78
+ var registryFile = () => import_node_path.default.join(registryDir(), "instances.json");
79
+ var logDir = () => import_node_path.default.join(registryDir(), "logs");
80
+ var isAlive = (pid) => {
81
+ try {
82
+ process.kill(pid, 0);
83
+ return true;
84
+ } catch {
85
+ return false;
86
+ }
87
+ };
88
+ function readRegistry() {
89
+ try {
90
+ const raw = JSON.parse((0, import_node_fs.readFileSync)(registryFile(), "utf8"));
91
+ return Array.isArray(raw) ? raw : [];
92
+ } catch {
93
+ return [];
94
+ }
95
+ }
96
+ function writeRegistry(list) {
97
+ try {
98
+ (0, import_node_fs.mkdirSync)(registryDir(), { recursive: true });
99
+ (0, import_node_fs.writeFileSync)(registryFile(), JSON.stringify(list, null, 2));
100
+ } catch {
101
+ }
102
+ }
103
+ function pruneRegistry() {
104
+ const all = readRegistry();
105
+ const live = all.filter((index) => isAlive(index.pid));
106
+ if (live.length !== all.length) writeRegistry(live);
107
+ return live;
108
+ }
109
+ function addInstance(inst) {
110
+ const list = pruneRegistry().filter((index) => index.pid !== inst.pid);
111
+ list.push(inst);
112
+ writeRegistry(list);
113
+ }
114
+ function removeInstance(pid) {
115
+ writeRegistry(readRegistry().filter((index) => index.pid !== pid));
116
+ }
117
+ function findByDir(dir) {
118
+ return pruneRegistry().find((index) => index.dir === dir);
119
+ }
120
+ function killInstance(inst) {
121
+ try {
122
+ process.kill(inst.pid, "SIGTERM");
123
+ } catch {
124
+ }
125
+ removeInstance(inst.pid);
126
+ }
127
+ function instanceLabel(inst) {
128
+ const kind = inst.isDirectory ? "\u{1F4C1}" : "\u{1F4C4}";
129
+ const mode = inst.background ? c.magenta("bg") : c.gray("fg");
130
+ return `${c.green("localhost:" + inst.port)} ${kind} ${tilde(inst.dir)} ${c.gray("pid " + inst.pid)} ${c.gray("\xB7 " + humanAge(inst.startedAt))} ${mode}`;
131
+ }
132
+ function printPlainList(instances) {
133
+ banner();
134
+ line(c.bold("Running instances"));
135
+ instances.forEach((index) => tree(instanceLabel(index)));
136
+ line();
137
+ }
138
+ async function listInstancesInteractive() {
139
+ let instances = pruneRegistry();
140
+ if (instances.length === 0) {
141
+ banner();
142
+ line(c.yellow("No running blogkit-md instances."));
143
+ line();
144
+ return;
145
+ }
146
+ if (!process.stdin.isTTY) {
147
+ printPlainList(instances);
148
+ return;
149
+ }
150
+ await new Promise((resolve) => {
151
+ let index = 0;
152
+ const stdin = process.stdin;
153
+ try {
154
+ import_node_readline.default.emitKeypressEvents(stdin);
155
+ stdin.setRawMode(true);
156
+ stdin.resume();
157
+ } catch {
158
+ printPlainList(instances);
159
+ resolve();
160
+ return;
161
+ }
162
+ const render = (footer) => {
163
+ const out = [
164
+ "",
165
+ INDENT + c.bold(c.blue("blogkit-md")) + c.gray(" \xB7 running instances"),
166
+ "",
167
+ ...instances.map((inst, rowIndex) => {
168
+ const selected = rowIndex === index;
169
+ const pointer = selected ? c.blue("\u276F ") : " ";
170
+ const label = selected ? instanceLabel(inst) : c.dim(instanceLabel(inst));
171
+ return INDENT + pointer + label;
172
+ }),
173
+ "",
174
+ footer ?? c.gray(INDENT + "\u2191/\u2193 move \u23CE stop selected q quit"),
175
+ ""
176
+ ];
177
+ process.stdout.write("\x1B[2J\x1B[H" + out.join("\n") + "\n");
178
+ };
179
+ const finish = () => {
180
+ stdin.setRawMode(false);
181
+ stdin.removeAllListeners("keypress");
182
+ stdin.pause();
183
+ resolve();
184
+ };
185
+ const onKey = (_string, key) => {
186
+ if (!key) return;
187
+ switch (key.name) {
188
+ case "up":
189
+ case "k": {
190
+ index = (index - 1 + instances.length) % instances.length;
191
+ render();
192
+ break;
193
+ }
194
+ case "down":
195
+ case "j": {
196
+ index = (index + 1) % instances.length;
197
+ render();
198
+ break;
199
+ }
200
+ case "return": {
201
+ const target = instances[index];
202
+ killInstance(target);
203
+ instances = pruneRegistry();
204
+ if (instances.length === 0) {
205
+ render(c.green(INDENT + `\u2713 Stopped localhost:${target.port}. No instances left.`));
206
+ finish();
207
+ return;
208
+ }
209
+ index = Math.min(index, instances.length - 1);
210
+ render(c.green(INDENT + `\u2713 Stopped localhost:${target.port}.`));
211
+ break;
212
+ }
213
+ default: {
214
+ if (key.name === "q" || key.name === "escape" || key.ctrl && key.name === "c") {
215
+ render(c.gray(INDENT + "Bye \u{1F44B}"));
216
+ finish();
217
+ }
218
+ }
219
+ }
220
+ };
221
+ stdin.on("keypress", onKey);
222
+ render();
223
+ });
224
+ }
225
+ function parseArgs(argv) {
226
+ const isFlag = (a) => a.startsWith("-");
227
+ const flagNames = new Set(argv.filter(isFlag).map((a) => a.split("=", 1)[0]));
228
+ const inputArgument = argv.find((a) => !isFlag(a));
229
+ const portArgument = argv.find((a) => a.startsWith("--port="));
230
+ const requestedPort = portArgument ? Number.parseInt(portArgument.split("=", 2)[1], 10) || 0 : 0;
231
+ return {
232
+ inputArg: inputArgument,
233
+ requestedPort,
234
+ wantBackground: flagNames.has("--background") || flagNames.has("-b"),
235
+ wantList: flagNames.has("--list") || flagNames.has("-l") || flagNames.has("--list-instances"),
236
+ // legacy alias
237
+ wantTear: flagNames.has("--tear") || flagNames.has("-t"),
238
+ isDetachedChild: flagNames.has("--__detached"),
239
+ // internal use only
240
+ wantHelp: flagNames.has("--help") || flagNames.has("-h")
241
+ };
242
+ }
243
+ function printHelp() {
244
+ banner();
245
+ line(c.bold("Usage"));
246
+ tree("blogkit-md <file-or-directory> [options]");
247
+ line();
248
+ line(c.bold("Options"));
249
+ tree(`${c.green("--port=<port>")} run on a specific port (default: random free port)`);
250
+ tree(`${c.green("-b, --background")} run the preview server detached in the background`);
251
+ tree(`${c.green("-t, --tear")} stop the instance already serving this path, then start fresh`);
252
+ tree(`${c.green("-l, --list")} interactively list & stop running instances`);
253
+ tree(`${c.green("-h, --help")} show this help`);
254
+ line();
255
+ line(c.gray("If a path is already being served, running it again just reopens it."));
256
+ line();
257
+ }
258
+ async function run(argv) {
259
+ const parsed = parseArgs(argv);
260
+ if (parsed.wantHelp) {
261
+ printHelp();
262
+ process.exit(0);
263
+ }
264
+ if (parsed.wantList) {
265
+ await listInstancesInteractive();
266
+ process.exit(0);
267
+ }
268
+ if (!parsed.inputArg) {
269
+ printHelp();
270
+ process.exit(1);
271
+ }
272
+ const inputPath = import_node_path.default.resolve(process.cwd(), parsed.inputArg);
273
+ let inputStat;
274
+ try {
275
+ inputStat = (0, import_node_fs.statSync)(inputPath);
276
+ } catch {
277
+ banner();
278
+ line(c.red("\u2717 Path does not exist"));
279
+ tree(c.dim(inputPath));
280
+ line();
281
+ process.exit(1);
282
+ }
283
+ const isDirectory = inputStat.isDirectory();
284
+ if (!parsed.isDetachedChild) {
285
+ const existing = findByDir(inputPath);
286
+ if (existing) {
287
+ if (parsed.wantTear) {
288
+ banner();
289
+ line(c.yellow("\u25B8 Tearing down the running instance"));
290
+ tree(
291
+ `${c.green("localhost:" + existing.port)} ${c.gray("pid " + existing.pid)} ${existing.background ? c.magenta("background") : c.gray("foreground")}`
292
+ );
293
+ killInstance(existing);
294
+ line(c.green(`\u2713 Stopped localhost:${existing.port}`));
295
+ line();
296
+ await new Promise((r) => setTimeout(r, 400));
297
+ } else {
298
+ const url = `http://localhost:${existing.port}`;
299
+ banner();
300
+ line(c.green("\u25B8 Already running \u2014 opening it in the browser"));
301
+ tree(`${c.bold("URL")} ${c.blue(url)}`);
302
+ tree(`${c.bold("Path")} ${c.dim(tilde(existing.dir))}`);
303
+ line();
304
+ line(c.gray("Restart it with ") + c.blue("--tear") + c.gray(", or list with ") + c.blue("--list"));
305
+ line();
306
+ openBrowser(url);
307
+ process.exit(0);
308
+ }
309
+ }
310
+ }
311
+ const scriptPath = process.argv[1];
312
+ const packageRoot = import_node_path.default.dirname(import_node_path.default.dirname(scriptPath));
313
+ const nextBin = import_node_path.default.join(packageRoot, "node_modules/.bin/next");
314
+ if (parsed.wantBackground && !parsed.isDetachedChild) {
315
+ try {
316
+ const port = parsed.requestedPort || await getFreePort();
317
+ (0, import_node_fs.mkdirSync)(logDir(), { recursive: true });
318
+ const logFile = import_node_path.default.join(logDir(), `${port}.log`);
319
+ const out = (0, import_node_fs.openSync)(logFile, "a");
320
+ const child = (0, import_node_child_process.spawn)(
321
+ process.execPath,
322
+ [scriptPath, inputPath, `--port=${port}`, "--__detached"],
323
+ { detached: true, stdio: ["ignore", out, out] }
324
+ );
325
+ child.unref();
326
+ banner();
327
+ line(c.green("\u25B8 Started in the background"));
328
+ tree(`${c.bold("URL")} ${c.blue("http://localhost:" + port)}`);
329
+ tree(`${c.bold("Path")} ${c.dim(tilde(inputPath))}`);
330
+ tree(`${c.bold("PID")} ${c.dim(String(child.pid))}`);
331
+ tree(`${c.bold("Log")} ${c.dim(tilde(logFile))}`);
332
+ line();
333
+ line(c.gray("Stop it with: ") + c.blue("blogkit-md --list"));
334
+ line();
335
+ } catch (error) {
336
+ banner();
337
+ line(c.red("\u2717 Failed to start in the background"));
338
+ tree(c.dim(String(error)));
339
+ line();
340
+ process.exit(1);
341
+ }
342
+ process.exit(0);
343
+ }
344
+ await startServer(inputPath, isDirectory, parsed, { nextBin, packageRoot });
47
345
  }
48
- var isDirectory = inputStat.isDirectory();
49
- var clients = /* @__PURE__ */ new Set();
50
346
  function getFreePort() {
51
347
  return new Promise((resolve, reject) => {
52
348
  const s = (0, import_node_http.createServer)();
53
349
  s.listen(0, () => {
54
350
  const port = s.address().port;
55
- s.close((err) => err ? reject(err) : resolve(port));
351
+ s.close((error) => error ? reject(error) : resolve(port));
56
352
  });
57
353
  s.on("error", reject);
58
354
  });
59
355
  }
60
- var sseServer = (0, import_node_http.createServer)((req, res) => {
61
- res.writeHead(200, {
62
- "Content-Type": "text/event-stream",
63
- "Cache-Control": "no-cache",
64
- "Connection": "keep-alive",
65
- "Access-Control-Allow-Origin": "*"
356
+ async function startServer(inputPath, isDirectory, parsed, paths) {
357
+ const clients = /* @__PURE__ */ new Set();
358
+ const sseServer = (0, import_node_http.createServer)((request, res) => {
359
+ res.writeHead(200, {
360
+ "Content-Type": "text/event-stream",
361
+ "Cache-Control": "no-cache",
362
+ "Connection": "keep-alive",
363
+ "Access-Control-Allow-Origin": "*"
364
+ });
365
+ res.write("data: connected\n\n");
366
+ clients.add(res);
367
+ request.on("close", () => clients.delete(res));
66
368
  });
67
- res.write("data: connected\n\n");
68
- clients.add(res);
69
- req.on("close", () => clients.delete(res));
70
- });
71
- sseServer.listen(0, async () => {
369
+ await new Promise((resolve) => sseServer.listen(0, resolve));
72
370
  const ssePort = sseServer.address().port;
73
- const nextPort = requestedPort || await getFreePort();
74
- const nextEnv = {
371
+ const nextPort = parsed.requestedPort || await getFreePort();
372
+ const nextEnvironment = {
75
373
  ...process.env,
76
374
  ...isDirectory ? { MARKDOWN_DIR: inputPath } : { MARKDOWN_FILE: inputPath },
77
375
  SSE_PORT: String(ssePort)
78
376
  };
79
377
  const broadcastReload = () => {
80
- for (const client of clients) {
81
- client.write("data: reload\n\n");
82
- }
378
+ for (const client of clients) client.write("data: reload\n\n");
83
379
  };
84
380
  if (isDirectory) {
85
381
  (0, import_node_fs.watch)(inputPath, { recursive: true }, (_, filename) => {
@@ -91,24 +387,71 @@ sseServer.listen(0, async () => {
91
387
  if (filename === markdownFilename) broadcastReload();
92
388
  });
93
389
  }
94
- const child = (0, import_node_child_process.spawn)(nextBin, ["start", "--port", String(nextPort)], {
95
- cwd: packageRoot,
96
- env: nextEnv,
390
+ const me = {
391
+ pid: process.pid,
392
+ port: nextPort,
393
+ ssePort,
394
+ dir: inputPath,
395
+ isDirectory,
396
+ background: parsed.isDetachedChild,
397
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
398
+ };
399
+ addInstance(me);
400
+ if (!parsed.isDetachedChild) {
401
+ banner();
402
+ line(c.gray("starting preview server for ") + c.blue(tilde(inputPath)) + c.gray(" \u2026"));
403
+ }
404
+ const child = (0, import_node_child_process.spawn)(paths.nextBin, ["start", "--port", String(nextPort)], {
405
+ cwd: paths.packageRoot,
406
+ env: nextEnvironment,
97
407
  stdio: ["inherit", "pipe", "inherit"]
98
408
  });
99
- let browserOpened = false;
409
+ const shutdown = () => {
410
+ try {
411
+ child.kill("SIGTERM");
412
+ } catch {
413
+ }
414
+ try {
415
+ sseServer.close();
416
+ } catch {
417
+ }
418
+ removeInstance(process.pid);
419
+ };
420
+ process.on("exit", shutdown);
421
+ process.on("SIGINT", () => process.exit(0));
422
+ process.on("SIGTERM", () => process.exit(0));
423
+ let ready = false;
100
424
  child.stdout?.on("data", (chunk) => {
101
- process.stdout.write(chunk);
102
- if (!browserOpened) {
425
+ if (!ready) {
103
426
  const match = chunk.toString().match(/http:\/\/localhost:\d+/);
104
427
  if (match) {
105
- browserOpened = true;
106
- (0, import_node_child_process.exec)(`open ${match[0]}`);
428
+ ready = true;
429
+ const url = `http://localhost:${nextPort}`;
430
+ if (!parsed.isDetachedChild) {
431
+ line();
432
+ line(c.green("\u2713 Ready"));
433
+ tree(`${c.bold("URL")} ${c.blue(url)}`);
434
+ tree(`${c.bold("Path")} ${c.dim(tilde(inputPath))}`);
435
+ line();
436
+ line(c.gray("live reload on save \xB7 Ctrl-C to stop"));
437
+ line();
438
+ }
439
+ openBrowser(url);
107
440
  }
108
441
  }
109
442
  });
110
443
  child.on("exit", (code) => {
111
- sseServer.close();
444
+ try {
445
+ sseServer.close();
446
+ } catch {
447
+ }
448
+ removeInstance(process.pid);
112
449
  process.exit(code ?? 0);
113
450
  });
451
+ }
452
+
453
+ // scripts/blogkit-md.ts
454
+ run(process.argv.slice(2)).catch((error) => {
455
+ console.error(error);
456
+ process.exit(1);
114
457
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@san-siva/blogkit-md-cli",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "description": "CLI tool to preview markdown files as blogkit-md blog posts",
5
5
  "bin": {
6
6
  "blogkit-md": "./bin/blogkit-md"
@@ -13,7 +13,9 @@
13
13
  "build": "rm -rf .next && tsup && next build",
14
14
  "prepublishOnly": "npm ci && npm run build",
15
15
  "lint": "eslint . --config eslint.config.ts",
16
- "fix": "eslint . --config eslint.config.ts --fix"
16
+ "fix": "eslint . --config eslint.config.ts --fix",
17
+ "pretest": "tsup",
18
+ "test": "node --test scripts/cli.test.ts"
17
19
  },
18
20
  "dependencies": {
19
21
  "@san-siva/blogkit": "^1.1.38",
@@ -24,11 +26,24 @@
24
26
  "react-dom": "^19.0.0"
25
27
  },
26
28
  "devDependencies": {
29
+ "@eslint/js": "^9.39.4",
27
30
  "@types/node": "^22",
28
- "tsup": "^8.0.0",
29
31
  "@types/react": "^19",
30
32
  "@types/react-dom": "^19",
31
- "typescript": "^5.0.0"
33
+ "eslint": "^9.39.4",
34
+ "eslint-config-prettier": "^10.1.8",
35
+ "eslint-import-resolver-typescript": "^4.4.5",
36
+ "eslint-plugin-import": "^2.32.0",
37
+ "eslint-plugin-jsx-a11y": "^6.10.2",
38
+ "eslint-plugin-no-await-in-promise": "^3.0.1",
39
+ "eslint-plugin-react": "^7.37.5",
40
+ "eslint-plugin-react-hooks": "^7.1.1",
41
+ "eslint-plugin-simple-import-sort": "^13.0.0",
42
+ "eslint-plugin-unicorn": "^65.0.0",
43
+ "jiti": "^2.7.0",
44
+ "tsup": "^8.0.0",
45
+ "typescript": "^5.0.0",
46
+ "typescript-eslint": "^8.60.1"
32
47
  },
33
48
  "license": "MIT",
34
49
  "preferGlobal": true,