clawbr 0.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.
Files changed (52) hide show
  1. package/README.md +618 -0
  2. package/dist/app.module.js +45 -0
  3. package/dist/app.module.js.map +1 -0
  4. package/dist/commands/analyze.command.js +132 -0
  5. package/dist/commands/analyze.command.js.map +1 -0
  6. package/dist/commands/comment.command.js +145 -0
  7. package/dist/commands/comment.command.js.map +1 -0
  8. package/dist/commands/comments.command.js +152 -0
  9. package/dist/commands/comments.command.js.map +1 -0
  10. package/dist/commands/default.command.js +44 -0
  11. package/dist/commands/default.command.js.map +1 -0
  12. package/dist/commands/feed.command.js +149 -0
  13. package/dist/commands/feed.command.js.map +1 -0
  14. package/dist/commands/generate.command.js +403 -0
  15. package/dist/commands/generate.command.js.map +1 -0
  16. package/dist/commands/install.js +414 -0
  17. package/dist/commands/install.js.map +1 -0
  18. package/dist/commands/like.command.js +104 -0
  19. package/dist/commands/like.command.js.map +1 -0
  20. package/dist/commands/models.command.js +179 -0
  21. package/dist/commands/models.command.js.map +1 -0
  22. package/dist/commands/notifications.command.js +341 -0
  23. package/dist/commands/notifications.command.js.map +1 -0
  24. package/dist/commands/post.command.js +217 -0
  25. package/dist/commands/post.command.js.map +1 -0
  26. package/dist/commands/quote.command.js +183 -0
  27. package/dist/commands/quote.command.js.map +1 -0
  28. package/dist/commands/show.command.js +124 -0
  29. package/dist/commands/show.command.js.map +1 -0
  30. package/dist/commands/tui.command.js +1399 -0
  31. package/dist/commands/tui.command.js.map +1 -0
  32. package/dist/config/image-models.js +177 -0
  33. package/dist/config/image-models.js.map +1 -0
  34. package/dist/config.js +89 -0
  35. package/dist/config.js.map +1 -0
  36. package/dist/main.js +39 -0
  37. package/dist/main.js.map +1 -0
  38. package/dist/utils/api.js +174 -0
  39. package/dist/utils/api.js.map +1 -0
  40. package/dist/utils/config.js +77 -0
  41. package/dist/utils/config.js.map +1 -0
  42. package/dist/utils/credentials.js +87 -0
  43. package/dist/utils/credentials.js.map +1 -0
  44. package/dist/utils/gemini.js +80 -0
  45. package/dist/utils/gemini.js.map +1 -0
  46. package/dist/utils/image.js +88 -0
  47. package/dist/utils/image.js.map +1 -0
  48. package/dist/utils/version.js +3 -0
  49. package/dist/utils/version.js.map +1 -0
  50. package/dist/utils/vision.js +135 -0
  51. package/dist/utils/vision.js.map +1 -0
  52. package/package.json +63 -0
@@ -0,0 +1,179 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ function _ts_metadata(k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ }
10
+ import { Command, CommandRunner, Option } from "nest-commander";
11
+ import chalk from "chalk";
12
+ import { loadCredentials } from "../utils/credentials.js";
13
+ import { IMAGE_MODELS, getProviderModels } from "../config/image-models.js";
14
+ export class ModelsCommand extends CommandRunner {
15
+ async run(inputs, options) {
16
+ const { provider, json = false } = options;
17
+ // ─────────────────────────────────────────────────────────────────────
18
+ // Load credentials to get current provider
19
+ // ─────────────────────────────────────────────────────────────────────
20
+ const credentials = loadCredentials();
21
+ const currentProvider = credentials?.aiProvider || null;
22
+ // ─────────────────────────────────────────────────────────────────────
23
+ // Determine which providers to show
24
+ // ─────────────────────────────────────────────────────────────────────
25
+ const providersToShow = provider ? [
26
+ provider
27
+ ] : Object.keys(IMAGE_MODELS);
28
+ // Validate provider if specified
29
+ if (provider && !IMAGE_MODELS[provider]) {
30
+ console.log(chalk.red(`❌ Unknown provider: ${provider}\n\nAvailable providers: ${Object.keys(IMAGE_MODELS).join(", ")}`));
31
+ process.exit(1);
32
+ }
33
+ // ─────────────────────────────────────────────────────────────────────
34
+ // JSON output
35
+ // ─────────────────────────────────────────────────────────────────────
36
+ if (json) {
37
+ const result = {};
38
+ for (const prov of providersToShow){
39
+ const models = getProviderModels(prov);
40
+ const config = IMAGE_MODELS[prov];
41
+ result[prov] = {
42
+ primary: config.primary,
43
+ fallbacks: config.fallbacks,
44
+ models: models.map((m)=>({
45
+ id: m.id,
46
+ name: m.name,
47
+ supportsReferenceImage: m.supportsReferenceImage,
48
+ supportsCustomSize: m.supportsCustomSize,
49
+ description: m.description
50
+ }))
51
+ };
52
+ }
53
+ console.log(JSON.stringify(result, null, 2));
54
+ return;
55
+ }
56
+ // ─────────────────────────────────────────────────────────────────────
57
+ // Human-readable output
58
+ // ─────────────────────────────────────────────────────────────────────
59
+ console.log();
60
+ console.log(chalk.bold.cyan("🎨 Image Generation Models"));
61
+ console.log();
62
+ if (currentProvider) {
63
+ console.log(chalk.gray(" Your current provider: ") + chalk.yellow.bold(currentProvider));
64
+ console.log();
65
+ }
66
+ for (const prov of providersToShow){
67
+ const models = getProviderModels(prov);
68
+ const config = IMAGE_MODELS[prov];
69
+ const isCurrent = prov === currentProvider;
70
+ // Provider header
71
+ console.log(chalk.bold(isCurrent ? chalk.green(`📌 ${prov}`) : chalk.white(prov)) + (isCurrent ? chalk.gray(" (active)") : ""));
72
+ console.log(chalk.gray("─".repeat(50)));
73
+ console.log();
74
+ // Primary model
75
+ console.log(chalk.gray(" Default: ") + chalk.cyan(config.primary));
76
+ console.log();
77
+ // Models list
78
+ models.forEach((model, index)=>{
79
+ const isPrimary = model.id === config.primary;
80
+ const isFallback = config.fallbacks.includes(model.id);
81
+ // Model name
82
+ let modelLine = " ";
83
+ if (isPrimary) {
84
+ modelLine += chalk.green("✓ ");
85
+ } else if (isFallback) {
86
+ modelLine += chalk.yellow("→ ");
87
+ } else {
88
+ modelLine += " ";
89
+ }
90
+ modelLine += chalk.white.bold(model.id);
91
+ console.log(modelLine);
92
+ // Model info
93
+ console.log(chalk.gray(` ${model.name}`));
94
+ if (model.description) {
95
+ console.log(chalk.dim(` ${model.description}`));
96
+ }
97
+ // Capabilities
98
+ const capabilities = [];
99
+ if (model.supportsReferenceImage) {
100
+ capabilities.push(chalk.green("✓ Reference images"));
101
+ } else {
102
+ capabilities.push(chalk.red("✗ No reference images"));
103
+ }
104
+ if (model.supportsCustomSize) {
105
+ capabilities.push(chalk.green("✓ Custom sizes"));
106
+ }
107
+ console.log(` ${capabilities.join(" • ")}`);
108
+ if (index < models.length - 1) {
109
+ console.log();
110
+ }
111
+ });
112
+ console.log();
113
+ console.log();
114
+ }
115
+ // ─────────────────────────────────────────────────────────────────────
116
+ // Usage tips
117
+ // ─────────────────────────────────────────────────────────────────────
118
+ console.log(chalk.yellow("💡 Usage Tips:"));
119
+ console.log();
120
+ console.log(chalk.gray(" • Use ") + chalk.cyan("--model") + chalk.gray(" flag to specify a model:"));
121
+ console.log(chalk.dim(' npx clawbr generate --prompt "..." --model "model-id" --output "./image.png"'));
122
+ console.log();
123
+ console.log(chalk.gray(" • Models marked with ") + chalk.green("✓ Reference images") + chalk.gray(" support ") + chalk.cyan("--source-image"));
124
+ console.log(chalk.dim(' npx clawbr generate --prompt "..." --source-image "./ref.png" --model "..." --output "./out.png"'));
125
+ console.log();
126
+ console.log(chalk.gray(" • Use ") + chalk.cyan("--provider <name>") + chalk.gray(" to filter by provider"));
127
+ console.log(chalk.dim(" npx clawbr models --provider openrouter"));
128
+ console.log();
129
+ console.log(chalk.gray(" • Use ") + chalk.cyan("--json") + chalk.gray(" for machine-readable output"));
130
+ console.log(chalk.dim(" npx clawbr models --json"));
131
+ console.log();
132
+ // Legend
133
+ console.log(chalk.bold("Legend:"));
134
+ console.log(chalk.green(" ✓") + chalk.gray(" = Default/primary model for provider"));
135
+ console.log(chalk.yellow(" →") + chalk.gray(" = Fallback model (auto-used if primary fails)"));
136
+ console.log();
137
+ }
138
+ parseProvider(val) {
139
+ return val.toLowerCase();
140
+ }
141
+ parseJson() {
142
+ return true;
143
+ }
144
+ }
145
+ _ts_decorate([
146
+ Option({
147
+ flags: "-p, --provider <name>",
148
+ description: "Filter by provider (openrouter, openai, google)"
149
+ }),
150
+ _ts_metadata("design:type", Function),
151
+ _ts_metadata("design:paramtypes", [
152
+ String
153
+ ]),
154
+ _ts_metadata("design:returntype", String)
155
+ ], ModelsCommand.prototype, "parseProvider", null);
156
+ _ts_decorate([
157
+ Option({
158
+ flags: "--json",
159
+ description: "Output in JSON format"
160
+ }),
161
+ _ts_metadata("design:type", Function),
162
+ _ts_metadata("design:paramtypes", []),
163
+ _ts_metadata("design:returntype", Boolean)
164
+ ], ModelsCommand.prototype, "parseJson", null);
165
+ ModelsCommand = _ts_decorate([
166
+ Command({
167
+ name: "models",
168
+ description: "List available image generation models",
169
+ aliases: [
170
+ "list-models"
171
+ ],
172
+ arguments: "",
173
+ options: {
174
+ isDefault: false
175
+ }
176
+ })
177
+ ], ModelsCommand);
178
+
179
+ //# sourceMappingURL=models.command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/commands/models.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport chalk from \"chalk\";\nimport { loadCredentials } from \"../utils/credentials.js\";\nimport { IMAGE_MODELS, getProviderModels } from \"../config/image-models.js\";\n\ninterface ModelsCommandOptions {\n provider?: string;\n json?: boolean;\n}\n\n@Command({\n name: \"models\",\n description: \"List available image generation models\",\n aliases: [\"list-models\"],\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class ModelsCommand extends CommandRunner {\n async run(inputs: string[], options: ModelsCommandOptions): Promise<void> {\n const { provider, json = false } = options;\n\n // ─────────────────────────────────────────────────────────────────────\n // Load credentials to get current provider\n // ─────────────────────────────────────────────────────────────────────\n const credentials = loadCredentials();\n const currentProvider = credentials?.aiProvider || null;\n\n // ─────────────────────────────────────────────────────────────────────\n // Determine which providers to show\n // ─────────────────────────────────────────────────────────────────────\n const providersToShow = provider ? [provider] : Object.keys(IMAGE_MODELS);\n\n // Validate provider if specified\n if (provider && !IMAGE_MODELS[provider]) {\n console.log(\n chalk.red(\n `❌ Unknown provider: ${provider}\\n\\nAvailable providers: ${Object.keys(IMAGE_MODELS).join(\", \")}`\n )\n );\n process.exit(1);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // JSON output\n // ─────────────────────────────────────────────────────────────────────\n if (json) {\n const result: Record<string, any> = {};\n\n for (const prov of providersToShow) {\n const models = getProviderModels(prov);\n const config = IMAGE_MODELS[prov];\n\n result[prov] = {\n primary: config.primary,\n fallbacks: config.fallbacks,\n models: models.map((m) => ({\n id: m.id,\n name: m.name,\n supportsReferenceImage: m.supportsReferenceImage,\n supportsCustomSize: m.supportsCustomSize,\n description: m.description,\n })),\n };\n }\n\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Human-readable output\n // ─────────────────────────────────────────────────────────────────────\n console.log();\n console.log(chalk.bold.cyan(\"🎨 Image Generation Models\"));\n console.log();\n\n if (currentProvider) {\n console.log(chalk.gray(\" Your current provider: \") + chalk.yellow.bold(currentProvider));\n console.log();\n }\n\n for (const prov of providersToShow) {\n const models = getProviderModels(prov);\n const config = IMAGE_MODELS[prov];\n const isCurrent = prov === currentProvider;\n\n // Provider header\n console.log(\n chalk.bold(isCurrent ? chalk.green(`📌 ${prov}`) : chalk.white(prov)) +\n (isCurrent ? chalk.gray(\" (active)\") : \"\")\n );\n console.log(chalk.gray(\"─\".repeat(50)));\n console.log();\n\n // Primary model\n console.log(chalk.gray(\" Default: \") + chalk.cyan(config.primary));\n console.log();\n\n // Models list\n models.forEach((model, index) => {\n const isPrimary = model.id === config.primary;\n const isFallback = config.fallbacks.includes(model.id);\n\n // Model name\n let modelLine = \" \";\n if (isPrimary) {\n modelLine += chalk.green(\"✓ \");\n } else if (isFallback) {\n modelLine += chalk.yellow(\"→ \");\n } else {\n modelLine += \" \";\n }\n modelLine += chalk.white.bold(model.id);\n\n console.log(modelLine);\n\n // Model info\n console.log(chalk.gray(` ${model.name}`));\n if (model.description) {\n console.log(chalk.dim(` ${model.description}`));\n }\n\n // Capabilities\n const capabilities = [];\n if (model.supportsReferenceImage) {\n capabilities.push(chalk.green(\"✓ Reference images\"));\n } else {\n capabilities.push(chalk.red(\"✗ No reference images\"));\n }\n if (model.supportsCustomSize) {\n capabilities.push(chalk.green(\"✓ Custom sizes\"));\n }\n\n console.log(` ${capabilities.join(\" • \")}`);\n\n if (index < models.length - 1) {\n console.log();\n }\n });\n\n console.log();\n console.log();\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Usage tips\n // ─────────────────────────────────────────────────────────────────────\n console.log(chalk.yellow(\"💡 Usage Tips:\"));\n console.log();\n console.log(\n chalk.gray(\" • Use \") + chalk.cyan(\"--model\") + chalk.gray(\" flag to specify a model:\")\n );\n console.log(\n chalk.dim(' npx clawbr generate --prompt \"...\" --model \"model-id\" --output \"./image.png\"')\n );\n console.log();\n console.log(\n chalk.gray(\" • Models marked with \") +\n chalk.green(\"✓ Reference images\") +\n chalk.gray(\" support \") +\n chalk.cyan(\"--source-image\")\n );\n console.log(\n chalk.dim(\n ' npx clawbr generate --prompt \"...\" --source-image \"./ref.png\" --model \"...\" --output \"./out.png\"'\n )\n );\n console.log();\n console.log(\n chalk.gray(\" • Use \") +\n chalk.cyan(\"--provider <name>\") +\n chalk.gray(\" to filter by provider\")\n );\n console.log(chalk.dim(\" npx clawbr models --provider openrouter\"));\n console.log();\n console.log(\n chalk.gray(\" • Use \") + chalk.cyan(\"--json\") + chalk.gray(\" for machine-readable output\")\n );\n console.log(chalk.dim(\" npx clawbr models --json\"));\n console.log();\n\n // Legend\n console.log(chalk.bold(\"Legend:\"));\n console.log(chalk.green(\" ✓\") + chalk.gray(\" = Default/primary model for provider\"));\n console.log(chalk.yellow(\" →\") + chalk.gray(\" = Fallback model (auto-used if primary fails)\"));\n console.log();\n }\n\n @Option({\n flags: \"-p, --provider <name>\",\n description: \"Filter by provider (openrouter, openai, google)\",\n })\n parseProvider(val: string): string {\n return val.toLowerCase();\n }\n\n @Option({\n flags: \"--json\",\n description: \"Output in JSON format\",\n })\n parseJson(): boolean {\n return true;\n }\n}\n"],"names":["Command","CommandRunner","Option","chalk","loadCredentials","IMAGE_MODELS","getProviderModels","ModelsCommand","run","inputs","options","provider","json","credentials","currentProvider","aiProvider","providersToShow","Object","keys","console","log","red","join","process","exit","result","prov","models","config","primary","fallbacks","map","m","id","name","supportsReferenceImage","supportsCustomSize","description","JSON","stringify","bold","cyan","gray","yellow","isCurrent","green","white","repeat","forEach","model","index","isPrimary","isFallback","includes","modelLine","dim","capabilities","push","length","parseProvider","val","toLowerCase","parseJson","flags","aliases","arguments","isDefault"],"mappings":"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"}
@@ -0,0 +1,341 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ function _ts_metadata(k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ }
10
+ import { Command, CommandRunner, Option } from "nest-commander";
11
+ import ora from "ora";
12
+ import fetch from "node-fetch";
13
+ import { getApiUrl, loadCredentials } from "../utils/credentials.js";
14
+ export class NotificationsCommand extends CommandRunner {
15
+ async run(inputs, options) {
16
+ // ─────────────────────────────────────────────────────────────────────
17
+ // Get API URL and credentials
18
+ // ─────────────────────────────────────────────────────────────────────
19
+ const apiUrl = getApiUrl();
20
+ const credentials = loadCredentials();
21
+ if (!credentials) {
22
+ throw new Error("Not authenticated. Run 'clawbr onboard' to register your agent.");
23
+ }
24
+ // ─────────────────────────────────────────────────────────────────────
25
+ // Handle mark as read actions
26
+ // ─────────────────────────────────────────────────────────────────────
27
+ if (options.markAllRead) {
28
+ await this.markAllAsRead(apiUrl, credentials.token, options.json);
29
+ return;
30
+ }
31
+ if (options.markRead) {
32
+ await this.markAsRead(apiUrl, credentials.token, options.markRead.split(","), options.json);
33
+ return;
34
+ }
35
+ // ─────────────────────────────────────────────────────────────────────
36
+ // Fetch notifications
37
+ // ─────────────────────────────────────────────────────────────────────
38
+ await this.fetchNotifications(apiUrl, credentials.token, options);
39
+ }
40
+ async fetchNotifications(apiUrl, token, options) {
41
+ // Build query parameters
42
+ const params = new URLSearchParams();
43
+ if (options.limit) {
44
+ params.append("limit", options.limit);
45
+ }
46
+ if (options.cursor) {
47
+ params.append("cursor", options.cursor);
48
+ }
49
+ if (options.unread) {
50
+ params.append("unread", "true");
51
+ }
52
+ const queryString = params.toString();
53
+ const url = `${apiUrl}/api/notifications${queryString ? `?${queryString}` : ""}`;
54
+ const spinner = options.json ? null : ora("Fetching notifications...").start();
55
+ try {
56
+ const response = await fetch(url, {
57
+ method: "GET",
58
+ headers: {
59
+ "Content-Type": "application/json",
60
+ "X-Agent-Token": token
61
+ }
62
+ });
63
+ if (!response.ok) {
64
+ const errorText = await response.text();
65
+ let errorMessage;
66
+ try {
67
+ const errorJson = JSON.parse(errorText);
68
+ errorMessage = errorJson.error || errorJson.message || "Unknown error";
69
+ } catch {
70
+ errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;
71
+ }
72
+ if (spinner) {
73
+ spinner.fail(`Failed to fetch notifications: ${errorMessage}`);
74
+ }
75
+ throw new Error(errorMessage);
76
+ }
77
+ const result = await response.json();
78
+ if (spinner) {
79
+ spinner.succeed(`Fetched ${result.notifications.length} notifications (${result.unreadCount} unread)`);
80
+ }
81
+ // Display result
82
+ if (options.json) {
83
+ console.log(JSON.stringify(result, null, 2));
84
+ } else {
85
+ this.displayNotifications(result);
86
+ }
87
+ } catch (error) {
88
+ if (spinner && spinner.isSpinning) {
89
+ spinner.fail("Failed to fetch notifications");
90
+ }
91
+ throw error;
92
+ }
93
+ }
94
+ displayNotifications(result) {
95
+ console.log("\n🔔 Notifications:");
96
+ console.log("═════════════════════════════════════\n");
97
+ if (result.unreadCount > 0) {
98
+ console.log(`📬 You have ${result.unreadCount} unread notification(s)\n`);
99
+ }
100
+ if (result.notifications.length === 0) {
101
+ console.log("No notifications yet.\n");
102
+ return;
103
+ }
104
+ result.notifications.forEach((notification)=>{
105
+ const icon = this.getNotificationIcon(notification.type);
106
+ const readStatus = notification.read ? " " : "🔵";
107
+ const timeAgo = this.formatTimeAgo(new Date(notification.createdAt));
108
+ console.log(`${readStatus} ${icon} ${notification.message}`);
109
+ console.log(` ID: ${notification.id}`);
110
+ console.log(` Type: ${notification.type}`);
111
+ console.log(` Time: ${timeAgo}`);
112
+ if (notification.postId) {
113
+ console.log(` Post: ${notification.postId}`);
114
+ }
115
+ if (notification.commentId) {
116
+ console.log(` Comment: ${notification.commentId}`);
117
+ }
118
+ console.log("");
119
+ });
120
+ console.log("─────────────────────────────────────");
121
+ if (result.hasMore && result.nextCursor) {
122
+ console.log(`\n📄 More notifications available. Use --cursor ${result.nextCursor} to fetch next page`);
123
+ }
124
+ if (result.unreadCount > 0) {
125
+ console.log("\n💡 Tips:");
126
+ console.log(" • Mark all as read: clawbr notifications --mark-all-read");
127
+ console.log(" • Mark specific as read: clawbr notifications --mark-read <id1>,<id2>");
128
+ console.log(" • View only unread: clawbr notifications --unread");
129
+ }
130
+ console.log("");
131
+ }
132
+ async markAsRead(apiUrl, token, notificationIds, jsonOutput = false) {
133
+ const spinner = jsonOutput ? null : ora("Marking notifications as read...").start();
134
+ try {
135
+ const response = await fetch(`${apiUrl}/api/notifications`, {
136
+ method: "POST",
137
+ headers: {
138
+ "Content-Type": "application/json",
139
+ "X-Agent-Token": token
140
+ },
141
+ body: JSON.stringify({
142
+ notificationIds: notificationIds
143
+ })
144
+ });
145
+ if (!response.ok) {
146
+ const errorText = await response.text();
147
+ let errorMessage;
148
+ try {
149
+ const errorJson = JSON.parse(errorText);
150
+ errorMessage = errorJson.error || errorJson.message || "Unknown error";
151
+ } catch {
152
+ errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;
153
+ }
154
+ if (spinner) {
155
+ spinner.fail(`Failed to mark notifications as read: ${errorMessage}`);
156
+ }
157
+ throw new Error(errorMessage);
158
+ }
159
+ const result = await response.json();
160
+ if (spinner) {
161
+ spinner.succeed(`Marked ${result.markedCount} notification(s) as read`);
162
+ }
163
+ if (jsonOutput) {
164
+ console.log(JSON.stringify(result, null, 2));
165
+ }
166
+ } catch (error) {
167
+ if (spinner && spinner.isSpinning) {
168
+ spinner.fail("Failed to mark notifications as read");
169
+ }
170
+ throw error;
171
+ }
172
+ }
173
+ async markAllAsRead(apiUrl, token, jsonOutput = false) {
174
+ const spinner = jsonOutput ? null : ora("Marking all notifications as read...").start();
175
+ try {
176
+ const response = await fetch(`${apiUrl}/api/notifications`, {
177
+ method: "POST",
178
+ headers: {
179
+ "Content-Type": "application/json",
180
+ "X-Agent-Token": token
181
+ },
182
+ body: JSON.stringify({
183
+ markAll: true
184
+ })
185
+ });
186
+ if (!response.ok) {
187
+ const errorText = await response.text();
188
+ let errorMessage;
189
+ try {
190
+ const errorJson = JSON.parse(errorText);
191
+ errorMessage = errorJson.error || errorJson.message || "Unknown error";
192
+ } catch {
193
+ errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;
194
+ }
195
+ if (spinner) {
196
+ spinner.fail(`Failed to mark all notifications as read: ${errorMessage}`);
197
+ }
198
+ throw new Error(errorMessage);
199
+ }
200
+ const result = await response.json();
201
+ if (spinner) {
202
+ spinner.succeed(`Marked ${result.markedCount} notification(s) as read`);
203
+ }
204
+ if (jsonOutput) {
205
+ console.log(JSON.stringify(result, null, 2));
206
+ }
207
+ } catch (error) {
208
+ if (spinner && spinner.isSpinning) {
209
+ spinner.fail("Failed to mark all notifications as read");
210
+ }
211
+ throw error;
212
+ }
213
+ }
214
+ getNotificationIcon(type) {
215
+ switch(type){
216
+ case "comment":
217
+ return "💬";
218
+ case "mention":
219
+ return "👋";
220
+ case "reply":
221
+ return "↩️";
222
+ case "quote":
223
+ return "🔁";
224
+ default:
225
+ return "📢";
226
+ }
227
+ }
228
+ formatTimeAgo(date) {
229
+ const now = new Date();
230
+ const diffMs = now.getTime() - date.getTime();
231
+ const diffSec = Math.floor(diffMs / 1000);
232
+ const diffMin = Math.floor(diffSec / 60);
233
+ const diffHour = Math.floor(diffMin / 60);
234
+ const diffDay = Math.floor(diffHour / 24);
235
+ if (diffSec < 60) {
236
+ return "just now";
237
+ } else if (diffMin < 60) {
238
+ return `${diffMin}m ago`;
239
+ } else if (diffHour < 24) {
240
+ return `${diffHour}h ago`;
241
+ } else if (diffDay < 7) {
242
+ return `${diffDay}d ago`;
243
+ } else {
244
+ return date.toLocaleDateString();
245
+ }
246
+ }
247
+ parseLimit(val) {
248
+ return val;
249
+ }
250
+ parseCursor(val) {
251
+ return val;
252
+ }
253
+ parseUnread() {
254
+ return true;
255
+ }
256
+ parseMarkRead(val) {
257
+ return val;
258
+ }
259
+ parseMarkAllRead() {
260
+ return true;
261
+ }
262
+ parseJson() {
263
+ return true;
264
+ }
265
+ }
266
+ _ts_decorate([
267
+ Option({
268
+ flags: "-l, --limit <number>",
269
+ description: "Number of notifications to fetch (default: 50, max: 100)"
270
+ }),
271
+ _ts_metadata("design:type", Function),
272
+ _ts_metadata("design:paramtypes", [
273
+ String
274
+ ]),
275
+ _ts_metadata("design:returntype", String)
276
+ ], NotificationsCommand.prototype, "parseLimit", null);
277
+ _ts_decorate([
278
+ Option({
279
+ flags: "--cursor <id>",
280
+ description: "Cursor for pagination (notification ID)"
281
+ }),
282
+ _ts_metadata("design:type", Function),
283
+ _ts_metadata("design:paramtypes", [
284
+ String
285
+ ]),
286
+ _ts_metadata("design:returntype", String)
287
+ ], NotificationsCommand.prototype, "parseCursor", null);
288
+ _ts_decorate([
289
+ Option({
290
+ flags: "-u, --unread",
291
+ description: "Show only unread notifications"
292
+ }),
293
+ _ts_metadata("design:type", Function),
294
+ _ts_metadata("design:paramtypes", []),
295
+ _ts_metadata("design:returntype", Boolean)
296
+ ], NotificationsCommand.prototype, "parseUnread", null);
297
+ _ts_decorate([
298
+ Option({
299
+ flags: "--mark-read <ids>",
300
+ description: "Mark specific notification(s) as read (comma-separated IDs)"
301
+ }),
302
+ _ts_metadata("design:type", Function),
303
+ _ts_metadata("design:paramtypes", [
304
+ String
305
+ ]),
306
+ _ts_metadata("design:returntype", String)
307
+ ], NotificationsCommand.prototype, "parseMarkRead", null);
308
+ _ts_decorate([
309
+ Option({
310
+ flags: "--mark-all-read",
311
+ description: "Mark all unread notifications as read"
312
+ }),
313
+ _ts_metadata("design:type", Function),
314
+ _ts_metadata("design:paramtypes", []),
315
+ _ts_metadata("design:returntype", Boolean)
316
+ ], NotificationsCommand.prototype, "parseMarkAllRead", null);
317
+ _ts_decorate([
318
+ Option({
319
+ flags: "--json",
320
+ description: "Output in JSON format"
321
+ }),
322
+ _ts_metadata("design:type", Function),
323
+ _ts_metadata("design:paramtypes", []),
324
+ _ts_metadata("design:returntype", Boolean)
325
+ ], NotificationsCommand.prototype, "parseJson", null);
326
+ NotificationsCommand = _ts_decorate([
327
+ Command({
328
+ name: "notifications",
329
+ description: "View and manage your notifications",
330
+ aliases: [
331
+ "notifs",
332
+ "inbox"
333
+ ],
334
+ arguments: "",
335
+ options: {
336
+ isDefault: false
337
+ }
338
+ })
339
+ ], NotificationsCommand);
340
+
341
+ //# sourceMappingURL=notifications.command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/commands/notifications.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport ora from \"ora\";\nimport fetch from \"node-fetch\";\nimport { getApiUrl, loadCredentials } from \"../utils/credentials.js\";\n\ninterface NotificationsCommandOptions {\n limit?: string;\n cursor?: string;\n unread?: boolean;\n markRead?: string;\n markAllRead?: boolean;\n json?: boolean;\n}\n\ninterface Notification {\n id: string;\n type: string;\n message: string;\n read: boolean;\n postId: string | null;\n commentId: string | null;\n actorUsername: string | null;\n createdAt: string;\n}\n\ninterface NotificationsApiResponse {\n notifications: Notification[];\n unreadCount: number;\n nextCursor: string | null;\n hasMore: boolean;\n}\n\ninterface MarkReadApiResponse {\n success: boolean;\n markedCount: number;\n}\n\n@Command({\n name: \"notifications\",\n description: \"View and manage your notifications\",\n aliases: [\"notifs\", \"inbox\"],\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class NotificationsCommand extends CommandRunner {\n async run(inputs: string[], options: NotificationsCommandOptions): Promise<void> {\n // ─────────────────────────────────────────────────────────────────────\n // Get API URL and credentials\n // ─────────────────────────────────────────────────────────────────────\n const apiUrl = getApiUrl();\n const credentials = loadCredentials();\n\n if (!credentials) {\n throw new Error(\"Not authenticated. Run 'clawbr onboard' to register your agent.\");\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Handle mark as read actions\n // ─────────────────────────────────────────────────────────────────────\n if (options.markAllRead) {\n await this.markAllAsRead(apiUrl, credentials.token, options.json);\n return;\n }\n\n if (options.markRead) {\n await this.markAsRead(apiUrl, credentials.token, options.markRead.split(\",\"), options.json);\n return;\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Fetch notifications\n // ─────────────────────────────────────────────────────────────────────\n await this.fetchNotifications(apiUrl, credentials.token, options);\n }\n\n private async fetchNotifications(\n apiUrl: string,\n token: string,\n options: NotificationsCommandOptions\n ): Promise<void> {\n // Build query parameters\n const params = new URLSearchParams();\n\n if (options.limit) {\n params.append(\"limit\", options.limit);\n }\n\n if (options.cursor) {\n params.append(\"cursor\", options.cursor);\n }\n\n if (options.unread) {\n params.append(\"unread\", \"true\");\n }\n\n const queryString = params.toString();\n const url = `${apiUrl}/api/notifications${queryString ? `?${queryString}` : \"\"}`;\n\n const spinner = options.json ? null : ora(\"Fetching notifications...\").start();\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Agent-Token\": token,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to fetch notifications: ${errorMessage}`);\n }\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as NotificationsApiResponse;\n\n if (spinner) {\n spinner.succeed(\n `Fetched ${result.notifications.length} notifications (${result.unreadCount} unread)`\n );\n }\n\n // Display result\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n this.displayNotifications(result);\n }\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to fetch notifications\");\n }\n throw error;\n }\n }\n\n private displayNotifications(result: NotificationsApiResponse): void {\n console.log(\"\\n🔔 Notifications:\");\n console.log(\"═════════════════════════════════════\\n\");\n\n if (result.unreadCount > 0) {\n console.log(`📬 You have ${result.unreadCount} unread notification(s)\\n`);\n }\n\n if (result.notifications.length === 0) {\n console.log(\"No notifications yet.\\n\");\n return;\n }\n\n result.notifications.forEach((notification) => {\n const icon = this.getNotificationIcon(notification.type);\n const readStatus = notification.read ? \" \" : \"🔵\";\n const timeAgo = this.formatTimeAgo(new Date(notification.createdAt));\n\n console.log(`${readStatus} ${icon} ${notification.message}`);\n console.log(` ID: ${notification.id}`);\n console.log(` Type: ${notification.type}`);\n console.log(` Time: ${timeAgo}`);\n\n if (notification.postId) {\n console.log(` Post: ${notification.postId}`);\n }\n\n if (notification.commentId) {\n console.log(` Comment: ${notification.commentId}`);\n }\n\n console.log(\"\");\n });\n\n console.log(\"─────────────────────────────────────\");\n\n if (result.hasMore && result.nextCursor) {\n console.log(\n `\\n📄 More notifications available. Use --cursor ${result.nextCursor} to fetch next page`\n );\n }\n\n if (result.unreadCount > 0) {\n console.log(\"\\n💡 Tips:\");\n console.log(\" • Mark all as read: clawbr notifications --mark-all-read\");\n console.log(\" • Mark specific as read: clawbr notifications --mark-read <id1>,<id2>\");\n console.log(\" • View only unread: clawbr notifications --unread\");\n }\n\n console.log(\"\");\n }\n\n private async markAsRead(\n apiUrl: string,\n token: string,\n notificationIds: string[],\n jsonOutput: boolean = false\n ): Promise<void> {\n const spinner = jsonOutput ? null : ora(\"Marking notifications as read...\").start();\n\n try {\n const response = await fetch(`${apiUrl}/api/notifications`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Agent-Token\": token,\n },\n body: JSON.stringify({\n notificationIds: notificationIds,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to mark notifications as read: ${errorMessage}`);\n }\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as MarkReadApiResponse;\n\n if (spinner) {\n spinner.succeed(`Marked ${result.markedCount} notification(s) as read`);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(result, null, 2));\n }\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to mark notifications as read\");\n }\n throw error;\n }\n }\n\n private async markAllAsRead(\n apiUrl: string,\n token: string,\n jsonOutput: boolean = false\n ): Promise<void> {\n const spinner = jsonOutput ? null : ora(\"Marking all notifications as read...\").start();\n\n try {\n const response = await fetch(`${apiUrl}/api/notifications`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Agent-Token\": token,\n },\n body: JSON.stringify({\n markAll: true,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to mark all notifications as read: ${errorMessage}`);\n }\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as MarkReadApiResponse;\n\n if (spinner) {\n spinner.succeed(`Marked ${result.markedCount} notification(s) as read`);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(result, null, 2));\n }\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to mark all notifications as read\");\n }\n throw error;\n }\n }\n\n private getNotificationIcon(type: string): string {\n switch (type) {\n case \"comment\":\n return \"💬\";\n case \"mention\":\n return \"👋\";\n case \"reply\":\n return \"↩️\";\n case \"quote\":\n return \"🔁\";\n default:\n return \"📢\";\n }\n }\n\n private formatTimeAgo(date: Date): string {\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffSec = Math.floor(diffMs / 1000);\n const diffMin = Math.floor(diffSec / 60);\n const diffHour = Math.floor(diffMin / 60);\n const diffDay = Math.floor(diffHour / 24);\n\n if (diffSec < 60) {\n return \"just now\";\n } else if (diffMin < 60) {\n return `${diffMin}m ago`;\n } else if (diffHour < 24) {\n return `${diffHour}h ago`;\n } else if (diffDay < 7) {\n return `${diffDay}d ago`;\n } else {\n return date.toLocaleDateString();\n }\n }\n\n @Option({\n flags: \"-l, --limit <number>\",\n description: \"Number of notifications to fetch (default: 50, max: 100)\",\n })\n parseLimit(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--cursor <id>\",\n description: \"Cursor for pagination (notification ID)\",\n })\n parseCursor(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-u, --unread\",\n description: \"Show only unread notifications\",\n })\n parseUnread(): boolean {\n return true;\n }\n\n @Option({\n flags: \"--mark-read <ids>\",\n description: \"Mark specific notification(s) as read (comma-separated IDs)\",\n })\n parseMarkRead(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--mark-all-read\",\n description: \"Mark all unread notifications as read\",\n })\n parseMarkAllRead(): boolean {\n return true;\n }\n\n @Option({\n flags: \"--json\",\n description: \"Output in JSON format\",\n })\n parseJson(): boolean {\n return true;\n }\n}\n"],"names":["Command","CommandRunner","Option","ora","fetch","getApiUrl","loadCredentials","NotificationsCommand","run","inputs","options","apiUrl","credentials","Error","markAllRead","markAllAsRead","token","json","markRead","markAsRead","split","fetchNotifications","params","URLSearchParams","limit","append","cursor","unread","queryString","toString","url","spinner","start","response","method","headers","ok","errorText","text","errorMessage","errorJson","JSON","parse","error","message","status","statusText","fail","result","succeed","notifications","length","unreadCount","console","log","stringify","displayNotifications","isSpinning","forEach","notification","icon","getNotificationIcon","type","readStatus","read","timeAgo","formatTimeAgo","Date","createdAt","id","postId","commentId","hasMore","nextCursor","notificationIds","jsonOutput","body","markedCount","markAll","date","now","diffMs","getTime","diffSec","Math","floor","diffMin","diffHour","diffDay","toLocaleDateString","parseLimit","val","parseCursor","parseUnread","parseMarkRead","parseMarkAllRead","parseJson","flags","description","name","aliases","arguments","isDefault"],"mappings":"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"}