social-light 0.0.1 → 0.1.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/README.md CHANGED
@@ -80,13 +80,14 @@ This will guide you through creating a new post with:
80
80
  ### Manage Posts
81
81
 
82
82
  ```bash
83
- # List unpublished posts
84
- social-light unpublished
85
-
86
- # List published posts
87
- social-light published
83
+ # List all unpublished post
84
+ social-light list
85
+ # List all post (including published)
86
+ social-light list --published
87
+ ```
88
88
 
89
- # Edit a post by index
89
+ ```bash
90
+ # Edit a post by unpublished index
90
91
  social-light edit 1
91
92
  ```
92
93
 
@@ -100,6 +101,16 @@ social-light publish
100
101
  social-light publish --continuous
101
102
  ```
102
103
 
104
+ ### Clean Posts
105
+
106
+ ```bash
107
+ # Clean all published posts
108
+ social-light clean
109
+
110
+ # Clean all posts (including unpublished)
111
+ social-light clean --unpublished
112
+ ```
113
+
103
114
  ### Web Interface
104
115
 
105
116
  Open the web interface to manage post visually
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "social-light",
3
- "version": "0.0.1",
3
+ "version": "0.1.1",
4
4
  "description": "AI-powered social media scheduling tool",
5
5
  "main": "src/index.mjs",
6
6
  "type": "module",
@@ -0,0 +1,88 @@
1
+ import chalk from "chalk";
2
+ import ora from "ora";
3
+ import inquirer from "inquirer";
4
+
5
+ import { deletePosts } from "../utils/db.mjs";
6
+
7
+ /**
8
+ * Clean up posts
9
+ * @param {Object} argv - Command arguments
10
+ * @example
11
+ * await cleanPosts({ force: true }); // Clean only published posts with force flag
12
+ * await cleanPosts({ unpublished: true }); // Clean published and unpublished posts
13
+ * await cleanPosts({ unpublished: true, published:false }); // Clean only unpublished posts
14
+ */
15
+ export const cleanPosts = async (argv) => {
16
+ try {
17
+ // Determine which posts to delete
18
+ const deletePublished = argv.published;
19
+ const deleteUnpublished = argv.unpublished;
20
+
21
+ // Generate appropriate confirmation message
22
+ let confirmMessage = "";
23
+ if (deletePublished && deleteUnpublished) {
24
+ confirmMessage =
25
+ "Are you sure you want to remove ALL posts (published and unpublished)? This action cannot be undone.";
26
+ } else if (deletePublished) {
27
+ confirmMessage =
28
+ "Are you sure you want to remove all published posts? This action cannot be undone.";
29
+ } else if (deleteUnpublished) {
30
+ confirmMessage =
31
+ "Are you sure you want to remove all unpublished posts? This action cannot be undone.";
32
+ }
33
+
34
+ // Skip confirmation if --force flag is used
35
+ if (!argv.force) {
36
+ const { confirm } = await inquirer.prompt([
37
+ {
38
+ type: "confirm",
39
+ name: "confirm",
40
+ message: confirmMessage,
41
+ default: false,
42
+ },
43
+ ]);
44
+
45
+ if (!confirm) {
46
+ console.log(chalk.yellow("Operation cancelled."));
47
+ return;
48
+ }
49
+ }
50
+
51
+ // Show a spinner while deleting
52
+ let spinnerText = "Cleaning up";
53
+ if (deletePublished && deleteUnpublished) {
54
+ spinnerText += " all posts...";
55
+ } else if (deletePublished) {
56
+ spinnerText += " published posts...";
57
+ } else if (deleteUnpublished) {
58
+ spinnerText += " unpublished posts...";
59
+ }
60
+
61
+ const spinner = ora(spinnerText).start();
62
+
63
+ // Delete posts
64
+ const result = deletePosts({
65
+ published: deletePublished,
66
+ unpublished: deleteUnpublished,
67
+ });
68
+
69
+ // Generate success message
70
+ let successMessage = `Cleaned up ${result.total} post${
71
+ result.total !== 1 ? "s" : ""
72
+ }.`;
73
+ if (deletePublished && deleteUnpublished) {
74
+ successMessage += ` (${result.published} published, ${result.unpublished} unpublished)`;
75
+ }
76
+
77
+ spinner.succeed(successMessage);
78
+
79
+ if (result.total > 0) {
80
+ console.log(chalk.green("\n✓ Cleanup complete."));
81
+ } else {
82
+ console.log(chalk.blue("\nℹ No posts found to clean up."));
83
+ }
84
+ } catch (error) {
85
+ console.error(chalk.red("Error cleaning posts:"), error.message);
86
+ process.exit(1);
87
+ }
88
+ };
@@ -78,7 +78,7 @@ export const createPost = async (argv) => {
78
78
  emptyLineCount++;
79
79
 
80
80
  // If we have 3 consecutive empty lines, we're done
81
- if (emptyLineCount >= 3) {
81
+ if (emptyLineCount >= 2) {
82
82
  // Remove the last empty lines (if any) from the result
83
83
  while (
84
84
  lines.length > 0 &&
@@ -263,7 +263,7 @@ export const createPost = async (argv) => {
263
263
  console.log("\n", chalk.green("✓"), "Post created successfully!");
264
264
  console.log(
265
265
  chalk.gray(" Run"),
266
- chalk.cyan("social-light unpublished"),
266
+ chalk.cyan("social-light list"),
267
267
  chalk.gray("to see your scheduled posts")
268
268
  );
269
269
  } catch (error) {
@@ -179,7 +179,7 @@ export const editPost = async (argv) => {
179
179
  console.log(chalk.green("\n✓ Post updated successfully!"));
180
180
  console.log(
181
181
  chalk.gray("Run"),
182
- chalk.cyan("social-light unpublished"),
182
+ chalk.cyan("social-light list"),
183
183
  chalk.gray("to see your updated post.")
184
184
  );
185
185
  console.log(
@@ -0,0 +1,31 @@
1
+ import { listPublished } from "./published.mjs";
2
+ import { listUnpublished } from "./unpublished.mjs";
3
+
4
+ export const list = async (argv) => {
5
+ try {
6
+ const { published, unpublished } = argv;
7
+
8
+ if (!published && !unpublished) {
9
+ console.log(chalk.yellow("No filter specified. Listing all posts."));
10
+ console.log(
11
+ chalk.gray("Run"),
12
+ chalk.cyan("social-light list --published --unpublished"),
13
+ chalk.gray("to see all posts.")
14
+ );
15
+ }
16
+
17
+ if (published) {
18
+ await listPublished(argv);
19
+ }
20
+
21
+ if (unpublished) {
22
+ await listUnpublished(argv);
23
+ }
24
+
25
+ if (!published && !unpublished) {
26
+ console.log(chalk.yellow("No posts found."));
27
+ }
28
+ } catch (error) {
29
+ console.error(chalk.red("Error listing posts:"), error.message);
30
+ }
31
+ };
package/src/index.mjs CHANGED
@@ -1,8 +1,9 @@
1
- #!/usr/bin/env node --no-deprecation
1
+ #!/usr/bin/env node --no-warnings
2
2
 
3
3
  // Load environment variables from .env file
4
4
  import { config } from "dotenv";
5
5
  config();
6
+ import NPMPackage from "../package.json" with { type: "json" };
6
7
 
7
8
  import yargs from "yargs";
8
9
  import { hideBin } from "yargs/helpers";
@@ -10,33 +11,35 @@ import chalk from "chalk";
10
11
 
11
12
  import { initialize } from "./commands/init.mjs";
12
13
  import { createPost } from "./commands/create.mjs";
13
- import { listUnpublished } from "./commands/unpublished.mjs";
14
- import { listPublished } from "./commands/published.mjs";
14
+
15
+ import { list } from "./commands/list.mjs";
15
16
  import { editPost } from "./commands/edit.mjs";
16
17
  import { publishPosts } from "./commands/publish.mjs";
18
+ import { cleanPosts } from "./commands/clean.mjs";
17
19
  import { startServer } from "./server/index.mjs";
18
20
 
19
21
  // Application title banner
20
22
  const displayBanner = () => {
21
23
  console.log(
22
- chalk.cyan(`
24
+ chalk.cyan(`
23
25
  _____ ____ _____ _____ _ _ _____ _____ _ _ _______
24
- / ____|/ __ \ / ____|_ _| /\ | | | | |_ _/ ____| | | |__ __|
25
- | (___ | | | | | | | / \ | | | | | || | __| |__| | | |
26
- \___ \| | | | | | | / /\ \ | | | | | || | |_ | __ | | |
27
- ____) | |__| | |____ _| |_ / ____ \| |____ | |____ _| || |__| | | | | | |
28
- |_____/ \____/ \_____|_____/_/ \_\______| |______|_____\_____|_| |_| |_|
29
-
30
-
31
- `)
26
+ / ____|/ __ \\ / ____|_ _| /\\ | | | | |_ _/ ____| | | |__ __|
27
+ | (___ | | | || | | | / \\ | | __ | | | || | __| |__| | | |
28
+ \\___ \\| | | || | | | / /\\ \\ | | | | | || | |_ | __ | | |
29
+ ____) | |__| || |____ _| |_/ ____ \\| |_____ | |____ _| || |__| | | | | | |
30
+ |_____/ \\____/ \\_____|_____/_/ \\__\\\\______||______|_____\\_____|_| |_| |_|
31
+ `)
32
32
  );
33
33
  console.log(chalk.gray("AI-powered social media scheduler\n"));
34
34
  };
35
-
36
35
  const main = async () => {
37
- displayBanner();
38
-
39
36
  yargs(hideBin(process.argv))
37
+ .parserConfiguration({
38
+ 'boolean-negation': true
39
+ })
40
+ .command("version", "Social Light version", {}, () => {
41
+ console.log(NPMPackage.version);
42
+ })
40
43
  .command("init", "Initialize Social Light configuration", {}, initialize)
41
44
  .command(
42
45
  "create",
@@ -50,11 +53,28 @@ const main = async () => {
50
53
  },
51
54
  createPost
52
55
  )
53
- .command("unpublished", "List all unpublished posts", {}, listUnpublished)
54
- .command("published", "List all published posts", {}, listPublished)
56
+ .command(
57
+ "list",
58
+ "List posts",
59
+ {
60
+ published: {
61
+ alias: "p",
62
+ describe: "List published posts",
63
+ type: "boolean",
64
+ default: false,
65
+ },
66
+ unpublished: {
67
+ alias: "u",
68
+ describe: "List unpublished posts",
69
+ type: "boolean",
70
+ default: true,
71
+ },
72
+ },
73
+ list
74
+ )
55
75
  .command(
56
76
  "edit [index]",
57
- "Edit a draft post by index",
77
+ "Edit an unpublished post by index",
58
78
  {
59
79
  index: {
60
80
  describe: "Index of the post to edit",
@@ -65,7 +85,7 @@ const main = async () => {
65
85
  )
66
86
  .command(
67
87
  "publish",
68
- "Publish eligible posts",
88
+ "Publish unpublished posts",
69
89
  {
70
90
  continuous: {
71
91
  alias: "c",
@@ -94,8 +114,38 @@ const main = async () => {
94
114
  },
95
115
  startServer
96
116
  )
117
+ .command(
118
+ "clean",
119
+ "Remove posts from the database",
120
+ {
121
+ published: {
122
+ alias: "p",
123
+ describe: "Remove published posts",
124
+ type: "boolean",
125
+ default: true,
126
+ },
127
+ unpublished: {
128
+ alias: "u",
129
+ describe: "Remove unpublished posts",
130
+ type: "boolean",
131
+ default: false,
132
+ },
133
+ },
134
+ cleanPosts
135
+ )
97
136
  .demandCommand(1, "Please specify a command")
98
- .help().argv;
137
+ .fail((msg, err, yargs) => {
138
+ displayBanner();
139
+ if(msg) {
140
+ console.error(msg);
141
+ }
142
+ console.log(yargs.help());
143
+ process.exit(1);
144
+ })
145
+ .showHelpOnFail(false)
146
+ .help()
147
+ .epilogue('For more information, check the documentation.')
148
+ .parse();
99
149
  };
100
150
 
101
151
  // Handle top-level await
@@ -381,7 +381,7 @@ const renderPostEditor = () => {
381
381
  state.config.aiEnabled && platformOptions.length > 0
382
382
  ? `
383
383
  <div class="d-flex justify-end mt-sm">
384
- <button type="button" class="btn" id="enhance-content-btn">Enhance with AI</button>
384
+ <button type="button" class="btn" id="enhance-content-btn">Enhance with for Provider AI</button>
385
385
  </div>
386
386
  `
387
387
  : ""
package/src/utils/db.mjs CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  import fs from 'fs-extra';
2
3
  import path from 'path';
3
4
  import os from 'os';
@@ -258,3 +259,60 @@ export const logAction = (action, details = {}) => {
258
259
  VALUES (?, ?)
259
260
  `).run(action, JSON.stringify(details));
260
261
  };
262
+
263
+ /**
264
+ * Delete posts by published status
265
+ * @param {Object} options - Options for deletion
266
+ * @param {boolean} options.published - Whether to delete published posts
267
+ * @param {boolean} options.unpublished - Whether to delete unpublished posts
268
+ * @returns {Object} Counts of deleted posts by type
269
+ * @example
270
+ * const result = deletePosts({ published: true }); // Delete only published posts
271
+ * const result = deletePosts({ unpublished: true }); // Delete only unpublished posts
272
+ * const result = deletePosts({ published: true, unpublished: true }); // Delete all posts
273
+ */
274
+ export const deletePosts = (options = { published: true }) => {
275
+ const db = getDb();
276
+ const result = { published: 0, unpublished: 0, total: 0 };
277
+
278
+ try {
279
+ // Delete published posts if requested
280
+ if (options.published) {
281
+ // Get count of published posts
282
+ const publishedCountQuery = db.prepare("SELECT COUNT(*) as count FROM posts WHERE published = 1");
283
+ const publishedCountResult = publishedCountQuery.get();
284
+ result.published = publishedCountResult ? publishedCountResult.count : 0;
285
+
286
+ // Delete published posts
287
+ const deletePublishedQuery = db.prepare("DELETE FROM posts WHERE published = 1");
288
+ deletePublishedQuery.run();
289
+ }
290
+
291
+ // Delete unpublished posts if requested
292
+ if (options.unpublished) {
293
+ // Get count of unpublished posts
294
+ const unpublishedCountQuery = db.prepare("SELECT COUNT(*) as count FROM posts WHERE published = 0");
295
+ const unpublishedCountResult = unpublishedCountQuery.get();
296
+ result.unpublished = unpublishedCountResult ? unpublishedCountResult.count : 0;
297
+
298
+ // Delete unpublished posts
299
+ const deleteUnpublishedQuery = db.prepare("DELETE FROM posts WHERE published = 0");
300
+ deleteUnpublishedQuery.run();
301
+ }
302
+
303
+ // Calculate total
304
+ result.total = result.published + result.unpublished;
305
+
306
+ // Log the action
307
+ logAction('posts_cleaned', {
308
+ published: result.published,
309
+ unpublished: result.unpublished,
310
+ total: result.total
311
+ });
312
+
313
+ return result;
314
+ } catch (error) {
315
+ console.error('Error deleting posts:', error.message);
316
+ throw error;
317
+ }
318
+ };