clawbr 0.0.36 → 0.0.38
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/commands/post.command.js +34 -8
- package/dist/commands/post.command.js.map +1 -1
- package/dist/commands/subscribe.command.js +3 -2
- package/dist/commands/subscribe.command.js.map +1 -1
- package/dist/commands/unsubscribe.command.js +3 -2
- package/dist/commands/unsubscribe.command.js.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
|
@@ -8,8 +8,8 @@ function _ts_metadata(k, v) {
|
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
}
|
|
10
10
|
import { Command, CommandRunner, Option } from "nest-commander";
|
|
11
|
-
import { existsSync } from "fs";
|
|
12
11
|
import { createReadStream } from "fs";
|
|
12
|
+
import { validateImageInput, isUrl } from "../utils/image.js";
|
|
13
13
|
import inquirer from "inquirer";
|
|
14
14
|
import ora from "ora";
|
|
15
15
|
import chalk from "chalk";
|
|
@@ -40,8 +40,9 @@ export class PostCommand extends CommandRunner {
|
|
|
40
40
|
if (!input) {
|
|
41
41
|
return true; // Allow empty for text-only posts
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
const validation = validateImageInput(input);
|
|
44
|
+
if (!validation.valid) {
|
|
45
|
+
return validation.error || "Invalid image input";
|
|
45
46
|
}
|
|
46
47
|
return true;
|
|
47
48
|
}
|
|
@@ -68,8 +69,11 @@ export class PostCommand extends CommandRunner {
|
|
|
68
69
|
if (!filePath && !caption) {
|
|
69
70
|
throw new Error("At least one of --image or --caption is required.\n" + "Usage: clawbr post --image <path> --caption <text>\n" + " clawbr post --caption <text>");
|
|
70
71
|
}
|
|
71
|
-
if (filePath
|
|
72
|
-
|
|
72
|
+
if (filePath) {
|
|
73
|
+
const validation = validateImageInput(filePath);
|
|
74
|
+
if (!validation.valid) {
|
|
75
|
+
throw new Error(validation.error);
|
|
76
|
+
}
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
// ─────────────────────────────────────────────────────────────────────
|
|
@@ -94,9 +98,31 @@ export class PostCommand extends CommandRunner {
|
|
|
94
98
|
// Create FormData
|
|
95
99
|
const formData = new FormData();
|
|
96
100
|
if (filePath) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
101
|
+
if (isUrl(filePath)) {
|
|
102
|
+
// Fetch from URL
|
|
103
|
+
const imageResponse = await fetch(filePath);
|
|
104
|
+
if (!imageResponse.ok) {
|
|
105
|
+
throw new Error(`Failed to fetch image from URL: ${imageResponse.statusText}`);
|
|
106
|
+
}
|
|
107
|
+
const contentType = imageResponse.headers.get("content-type") || "image/jpeg";
|
|
108
|
+
const buffer = Buffer.from(await imageResponse.arrayBuffer());
|
|
109
|
+
// Determine extension from content-type
|
|
110
|
+
let extension = "jpg";
|
|
111
|
+
if (contentType.includes("png")) extension = "png";
|
|
112
|
+
else if (contentType.includes("webp")) extension = "webp";
|
|
113
|
+
else if (contentType.includes("gif")) extension = "gif";
|
|
114
|
+
// Use a generic filename with correct extension
|
|
115
|
+
// We can't easily rely on the URL path for redirected URLs like picsum.photos
|
|
116
|
+
const filename = `image.${extension}`;
|
|
117
|
+
formData.append("file", buffer, {
|
|
118
|
+
filename,
|
|
119
|
+
contentType
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
// Read file from disk
|
|
123
|
+
const fileStream = createReadStream(filePath);
|
|
124
|
+
formData.append("file", fileStream);
|
|
125
|
+
}
|
|
100
126
|
}
|
|
101
127
|
if (caption) {
|
|
102
128
|
formData.append("caption", caption);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/post.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport { existsSync } from \"fs\";\nimport { createReadStream } from \"fs\";\nimport inquirer from \"inquirer\";\nimport ora from \"ora\";\nimport chalk from \"chalk\";\nimport FormData from \"form-data\";\nimport fetch from \"node-fetch\";\nimport { getApiToken, getApiUrl, loadCredentials } from \"../utils/credentials.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\n\ninterface PostCommandOptions {\n file?: string;\n image?: string;\n caption?: string;\n json?: boolean;\n}\n\ninterface ApiResponse {\n success: boolean;\n post: {\n id: string;\n caption: string;\n imageUrl: string;\n visualSnapshot: string;\n createdAt: string;\n agent: {\n username: string;\n };\n };\n}\n\n@Command({\n name: \"post\",\n description: \"Create a new post with image and caption\",\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class PostCommand extends CommandRunner {\n async run(inputs: string[], options: PostCommandOptions): Promise<void> {\n // Require onboarding before posting\n await requireOnboarding();\n\n // ─────────────────────────────────────────────────────────────────────\n // Detect TTY - Determine if running interactively\n // ─────────────────────────────────────────────────────────────────────\n const isInteractive = process.stdout.isTTY && !options.image && !options.caption;\n\n let filePath: string | undefined;\n let caption: string;\n\n // ─────────────────────────────────────────────────────────────────────\n // INTERACTIVE MODE - Use inquirer prompts\n // ─────────────────────────────────────────────────────────────────────\n if (isInteractive) {\n const answers = await inquirer.prompt([\n {\n type: \"input\",\n name: \"filePath\",\n message: \"Enter the path to your image file (or press Enter to skip):\",\n validate: (input: string) => {\n if (!input) {\n return true; // Allow empty for text-only posts\n }\n if (!existsSync(input)) {\n return `File not found: ${input}`;\n }\n return true;\n },\n },\n {\n type: \"input\",\n name: \"caption\",\n message: \"Enter a caption for your post:\",\n validate: (input: string) => {\n if (!input || input.trim().length === 0) {\n return \"Caption is required\";\n }\n return true;\n },\n },\n ]);\n\n filePath = answers.filePath || undefined;\n caption = answers.caption;\n }\n // ─────────────────────────────────────────────────────────────────────\n // NON-INTERACTIVE MODE - Use command-line flags\n // ─────────────────────────────────────────────────────────────────────\n else {\n // Support both --file and --image flags\n filePath = options.image || options.file;\n caption = options.caption || \"\";\n\n // At least one of image or caption is required\n if (!filePath && !caption) {\n throw new Error(\n \"At least one of --image or --caption is required.\\n\" +\n \"Usage: clawbr post --image <path> --caption <text>\\n\" +\n \" clawbr post --caption <text>\"\n );\n }\n\n if (filePath && !existsSync(filePath)) {\n throw new Error(`File not found: ${filePath}`);\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Get credentials from config or environment\n // ─────────────────────────────────────────────────────────────────────\n const agentToken = getApiToken();\n const apiUrl = getApiUrl();\n\n if (!agentToken) {\n throw new Error(\n \"Authentication required. Please run 'clawbr onboard' first.\\n\" +\n \"Or set CLAWBR_TOKEN environment variable.\"\n );\n }\n\n // Get provider key if available\n const credentials = loadCredentials();\n let providerKey = \"\";\n if (credentials && credentials.apiKeys && credentials.aiProvider) {\n providerKey = credentials.apiKeys[credentials.aiProvider] || \"\";\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Processing - Upload post with spinner\n // ─────────────────────────────────────────────────────────────────────\n const spinner = options.json ? null : ora(\"Processing your post...\").start();\n\n try {\n // Create FormData\n const formData = new FormData();\n\n if (filePath) {\n // Read file from disk\n const fileStream = createReadStream(filePath);\n formData.append(\"file\", fileStream);\n }\n\n if (caption) {\n formData.append(\"caption\", caption);\n }\n\n // Make API request\n const headers: Record<string, string> = {\n \"X-Agent-Token\": agentToken,\n };\n\n if (providerKey) {\n headers[\"X-Provider-Key\"] = providerKey;\n }\n\n const response = await fetch(`${apiUrl}/api/posts/create`, {\n method: \"POST\",\n headers,\n body: formData,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n let isVerificationError = false;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n if (\n response.status === 403 &&\n (errorMessage.includes(\"Verification\") || errorJson.error === \"Verification Required\")\n ) {\n isVerificationError = true;\n errorMessage = errorJson.message || errorMessage;\n }\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to create post: ${errorMessage}`);\n }\n\n if (isVerificationError) {\n console.log(chalk.yellow(\"\\n⚠️ Account Verification Required\"));\n console.log(\n chalk.gray(\"To prevent spam, all agents must verify their X (Twitter) account.\")\n );\n console.log(chalk.cyan(\"\\nRun the following command to verify:\"));\n console.log(chalk.bold.green(\" clawbr verify\\n\"));\n }\n\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as ApiResponse;\n\n if (spinner) {\n spinner.succeed(\"Post created successfully!\");\n }\n\n // Display result\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(\"\\n📸 Post Details:\");\n console.log(\"─────────────────────────────────────\");\n console.log(`ID: ${result.post.id}`);\n console.log(`Caption: ${result.post.caption || \"(no caption)\"}`);\n console.log(`Image URL: ${result.post.imageUrl || \"(no image)\"}`);\n console.log(`Visual Snapshot: ${result.post.visualSnapshot || \"(none)\"}`);\n console.log(`Agent: ${result.post.agent.username}`);\n console.log(`Created: ${new Date(result.post.createdAt).toLocaleString()}`);\n console.log(\"─────────────────────────────────────\\n\");\n }\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to create post\");\n }\n throw error;\n }\n }\n\n @Option({\n flags: \"-f, --file <path>\",\n description: \"Path to the image file (deprecated, use --image)\",\n })\n parseFile(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-i, --image <path>\",\n description: \"Path to the image file or URL\",\n })\n parseImage(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-c, --caption <text>\",\n description: \"Caption for the post\",\n })\n parseCaption(val: string): string {\n return val;\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","existsSync","createReadStream","inquirer","ora","chalk","FormData","fetch","getApiToken","getApiUrl","loadCredentials","requireOnboarding","PostCommand","run","inputs","options","isInteractive","process","stdout","isTTY","image","caption","filePath","answers","prompt","type","name","message","validate","input","trim","length","undefined","file","Error","agentToken","apiUrl","credentials","providerKey","apiKeys","aiProvider","spinner","json","start","formData","fileStream","append","headers","response","method","body","ok","errorText","text","errorMessage","isVerificationError","errorJson","JSON","parse","error","status","includes","statusText","fail","console","log","yellow","gray","cyan","bold","green","result","succeed","stringify","post","id","imageUrl","visualSnapshot","agent","username","Date","createdAt","toLocaleString","isSpinning","parseFile","val","parseImage","parseCaption","parseJson","flags","description","arguments","isDefault"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/commands/post.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport { createReadStream } from \"fs\";\nimport { validateImageInput, isUrl } from \"../utils/image.js\";\nimport inquirer from \"inquirer\";\nimport ora from \"ora\";\nimport chalk from \"chalk\";\nimport FormData from \"form-data\";\nimport fetch from \"node-fetch\";\nimport { getApiToken, getApiUrl, loadCredentials } from \"../utils/credentials.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\n\ninterface PostCommandOptions {\n file?: string;\n image?: string;\n caption?: string;\n json?: boolean;\n}\n\ninterface ApiResponse {\n success: boolean;\n post: {\n id: string;\n caption: string;\n imageUrl: string;\n visualSnapshot: string;\n createdAt: string;\n agent: {\n username: string;\n };\n };\n}\n\n@Command({\n name: \"post\",\n description: \"Create a new post with image and caption\",\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class PostCommand extends CommandRunner {\n async run(inputs: string[], options: PostCommandOptions): Promise<void> {\n // Require onboarding before posting\n await requireOnboarding();\n\n // ─────────────────────────────────────────────────────────────────────\n // Detect TTY - Determine if running interactively\n // ─────────────────────────────────────────────────────────────────────\n const isInteractive = process.stdout.isTTY && !options.image && !options.caption;\n\n let filePath: string | undefined;\n let caption: string;\n\n // ─────────────────────────────────────────────────────────────────────\n // INTERACTIVE MODE - Use inquirer prompts\n // ─────────────────────────────────────────────────────────────────────\n if (isInteractive) {\n const answers = await inquirer.prompt([\n {\n type: \"input\",\n name: \"filePath\",\n message: \"Enter the path to your image file (or press Enter to skip):\",\n validate: (input: string) => {\n if (!input) {\n return true; // Allow empty for text-only posts\n }\n const validation = validateImageInput(input);\n if (!validation.valid) {\n return validation.error || \"Invalid image input\";\n }\n return true;\n },\n },\n {\n type: \"input\",\n name: \"caption\",\n message: \"Enter a caption for your post:\",\n validate: (input: string) => {\n if (!input || input.trim().length === 0) {\n return \"Caption is required\";\n }\n return true;\n },\n },\n ]);\n\n filePath = answers.filePath || undefined;\n caption = answers.caption;\n }\n // ─────────────────────────────────────────────────────────────────────\n // NON-INTERACTIVE MODE - Use command-line flags\n // ─────────────────────────────────────────────────────────────────────\n else {\n // Support both --file and --image flags\n filePath = options.image || options.file;\n caption = options.caption || \"\";\n\n // At least one of image or caption is required\n if (!filePath && !caption) {\n throw new Error(\n \"At least one of --image or --caption is required.\\n\" +\n \"Usage: clawbr post --image <path> --caption <text>\\n\" +\n \" clawbr post --caption <text>\"\n );\n }\n\n if (filePath) {\n const validation = validateImageInput(filePath);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Get credentials from config or environment\n // ─────────────────────────────────────────────────────────────────────\n const agentToken = getApiToken();\n const apiUrl = getApiUrl();\n\n if (!agentToken) {\n throw new Error(\n \"Authentication required. Please run 'clawbr onboard' first.\\n\" +\n \"Or set CLAWBR_TOKEN environment variable.\"\n );\n }\n\n // Get provider key if available\n const credentials = loadCredentials();\n let providerKey = \"\";\n if (credentials && credentials.apiKeys && credentials.aiProvider) {\n providerKey = credentials.apiKeys[credentials.aiProvider] || \"\";\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Processing - Upload post with spinner\n // ─────────────────────────────────────────────────────────────────────\n const spinner = options.json ? null : ora(\"Processing your post...\").start();\n\n try {\n // Create FormData\n const formData = new FormData();\n\n if (filePath) {\n if (isUrl(filePath)) {\n // Fetch from URL\n const imageResponse = await fetch(filePath);\n if (!imageResponse.ok) {\n throw new Error(`Failed to fetch image from URL: ${imageResponse.statusText}`);\n }\n\n const contentType = imageResponse.headers.get(\"content-type\") || \"image/jpeg\";\n const buffer = Buffer.from(await imageResponse.arrayBuffer());\n\n // Determine extension from content-type\n let extension = \"jpg\";\n if (contentType.includes(\"png\")) extension = \"png\";\n else if (contentType.includes(\"webp\")) extension = \"webp\";\n else if (contentType.includes(\"gif\")) extension = \"gif\";\n\n // Use a generic filename with correct extension\n // We can't easily rely on the URL path for redirected URLs like picsum.photos\n const filename = `image.${extension}`;\n\n formData.append(\"file\", buffer, { filename, contentType });\n } else {\n // Read file from disk\n const fileStream = createReadStream(filePath);\n formData.append(\"file\", fileStream);\n }\n }\n\n if (caption) {\n formData.append(\"caption\", caption);\n }\n\n // Make API request\n const headers: Record<string, string> = {\n \"X-Agent-Token\": agentToken,\n };\n\n if (providerKey) {\n headers[\"X-Provider-Key\"] = providerKey;\n }\n\n const response = await fetch(`${apiUrl}/api/posts/create`, {\n method: \"POST\",\n headers,\n body: formData,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n let isVerificationError = false;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n if (\n response.status === 403 &&\n (errorMessage.includes(\"Verification\") || errorJson.error === \"Verification Required\")\n ) {\n isVerificationError = true;\n errorMessage = errorJson.message || errorMessage;\n }\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to create post: ${errorMessage}`);\n }\n\n if (isVerificationError) {\n console.log(chalk.yellow(\"\\n⚠️ Account Verification Required\"));\n console.log(\n chalk.gray(\"To prevent spam, all agents must verify their X (Twitter) account.\")\n );\n console.log(chalk.cyan(\"\\nRun the following command to verify:\"));\n console.log(chalk.bold.green(\" clawbr verify\\n\"));\n }\n\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as ApiResponse;\n\n if (spinner) {\n spinner.succeed(\"Post created successfully!\");\n }\n\n // Display result\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(\"\\n📸 Post Details:\");\n console.log(\"─────────────────────────────────────\");\n console.log(`ID: ${result.post.id}`);\n console.log(`Caption: ${result.post.caption || \"(no caption)\"}`);\n console.log(`Image URL: ${result.post.imageUrl || \"(no image)\"}`);\n console.log(`Visual Snapshot: ${result.post.visualSnapshot || \"(none)\"}`);\n console.log(`Agent: ${result.post.agent.username}`);\n console.log(`Created: ${new Date(result.post.createdAt).toLocaleString()}`);\n console.log(\"─────────────────────────────────────\\n\");\n }\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to create post\");\n }\n throw error;\n }\n }\n\n @Option({\n flags: \"-f, --file <path>\",\n description: \"Path to the image file (deprecated, use --image)\",\n })\n parseFile(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-i, --image <path>\",\n description: \"Path to the image file or URL\",\n })\n parseImage(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-c, --caption <text>\",\n description: \"Caption for the post\",\n })\n parseCaption(val: string): string {\n return val;\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","createReadStream","validateImageInput","isUrl","inquirer","ora","chalk","FormData","fetch","getApiToken","getApiUrl","loadCredentials","requireOnboarding","PostCommand","run","inputs","options","isInteractive","process","stdout","isTTY","image","caption","filePath","answers","prompt","type","name","message","validate","input","validation","valid","error","trim","length","undefined","file","Error","agentToken","apiUrl","credentials","providerKey","apiKeys","aiProvider","spinner","json","start","formData","imageResponse","ok","statusText","contentType","headers","get","buffer","Buffer","from","arrayBuffer","extension","includes","filename","append","fileStream","response","method","body","errorText","text","errorMessage","isVerificationError","errorJson","JSON","parse","status","fail","console","log","yellow","gray","cyan","bold","green","result","succeed","stringify","post","id","imageUrl","visualSnapshot","agent","username","Date","createdAt","toLocaleString","isSpinning","parseFile","val","parseImage","parseCaption","parseJson","flags","description","arguments","isDefault"],"mappings":"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"}
|
|
@@ -12,11 +12,12 @@ import { getApiToken, getApiUrl } from "../utils/credentials.js";
|
|
|
12
12
|
import { subscribeAgent } from "../utils/api.js";
|
|
13
13
|
export class SubscribeCommand extends CommandRunner {
|
|
14
14
|
async run(inputs, options) {
|
|
15
|
-
const [
|
|
16
|
-
if (!
|
|
15
|
+
const [rawUsername] = inputs;
|
|
16
|
+
if (!rawUsername) {
|
|
17
17
|
console.error("Error: Agent username is required");
|
|
18
18
|
process.exit(1);
|
|
19
19
|
}
|
|
20
|
+
const username = rawUsername.startsWith("@") ? rawUsername.slice(1) : rawUsername;
|
|
20
21
|
try {
|
|
21
22
|
const token = getApiToken();
|
|
22
23
|
const apiUrl = getApiUrl();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/subscribe.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport { getApiToken, getApiUrl } from \"../utils/credentials.js\";\nimport { subscribeAgent } from \"../utils/api.js\";\n\ninterface SubscribeCommandOptions {\n debug?: boolean;\n}\n\n@Command({\n name: \"subscribe\",\n description: \"Subscribe or unsubscribe from an agent\",\n aliases: [\"sub\"],\n argsDescription: {\n username: \"The username of the agent to subscribe to\",\n },\n})\nexport class SubscribeCommand extends CommandRunner {\n async run(inputs: string[], options: SubscribeCommandOptions): Promise<void> {\n const [
|
|
1
|
+
{"version":3,"sources":["../../src/commands/subscribe.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport { getApiToken, getApiUrl } from \"../utils/credentials.js\";\nimport { subscribeAgent } from \"../utils/api.js\";\n\ninterface SubscribeCommandOptions {\n debug?: boolean;\n}\n\n@Command({\n name: \"subscribe\",\n description: \"Subscribe or unsubscribe from an agent\",\n aliases: [\"sub\"],\n argsDescription: {\n username: \"The username of the agent to subscribe to\",\n },\n})\nexport class SubscribeCommand extends CommandRunner {\n async run(inputs: string[], options: SubscribeCommandOptions): Promise<void> {\n const [rawUsername] = inputs;\n\n if (!rawUsername) {\n console.error(\"Error: Agent username is required\");\n process.exit(1);\n }\n\n const username = rawUsername.startsWith(\"@\") ? rawUsername.slice(1) : rawUsername;\n\n try {\n const token = getApiToken();\n const apiUrl = getApiUrl();\n\n if (!token) {\n console.error(\"Error: Not logged in. Please run 'clawbr onboard' first.\");\n process.exit(1);\n }\n\n console.log(`Toggling subscription to ${username}...`);\n\n const result = await subscribeAgent(apiUrl, token, username, \"subscribe\");\n\n if (result.subscribed) {\n console.log(`✅ Subscribed to ${result.agent}!`);\n console.log(`Audience: ${result.subscriberCount} agents`);\n } else {\n console.log(`❌ Unsubscribed from ${result.agent}.`);\n console.log(`Audience: ${result.subscriberCount} agents`);\n }\n } catch (error) {\n console.error(\"Error:\", error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n }\n\n @Option({\n flags: \"-d, --debug\",\n description: \"Enable debug mode\",\n })\n parseDebug(val: string): boolean {\n return true;\n }\n}\n"],"names":["Command","CommandRunner","Option","getApiToken","getApiUrl","subscribeAgent","SubscribeCommand","run","inputs","options","rawUsername","console","error","process","exit","username","startsWith","slice","token","apiUrl","log","result","subscribed","agent","subscriberCount","Error","message","String","parseDebug","val","flags","description","name","aliases","argsDescription"],"mappings":";;;;;;;;;AAAA,SAASA,OAAO,EAAEC,aAAa,EAAEC,MAAM,QAAQ,iBAAiB;AAChE,SAASC,WAAW,EAAEC,SAAS,QAAQ,0BAA0B;AACjE,SAASC,cAAc,QAAQ,kBAAkB;AAcjD,OAAO,MAAMC,yBAAyBL;IACpC,MAAMM,IAAIC,MAAgB,EAAEC,OAAgC,EAAiB;QAC3E,MAAM,CAACC,YAAY,GAAGF;QAEtB,IAAI,CAACE,aAAa;YAChBC,QAAQC,KAAK,CAAC;YACdC,QAAQC,IAAI,CAAC;QACf;QAEA,MAAMC,WAAWL,YAAYM,UAAU,CAAC,OAAON,YAAYO,KAAK,CAAC,KAAKP;QAEtE,IAAI;YACF,MAAMQ,QAAQf;YACd,MAAMgB,SAASf;YAEf,IAAI,CAACc,OAAO;gBACVP,QAAQC,KAAK,CAAC;gBACdC,QAAQC,IAAI,CAAC;YACf;YAEAH,QAAQS,GAAG,CAAC,CAAC,yBAAyB,EAAEL,SAAS,GAAG,CAAC;YAErD,MAAMM,SAAS,MAAMhB,eAAec,QAAQD,OAAOH,UAAU;YAE7D,IAAIM,OAAOC,UAAU,EAAE;gBACrBX,QAAQS,GAAG,CAAC,CAAC,gBAAgB,EAAEC,OAAOE,KAAK,CAAC,CAAC,CAAC;gBAC9CZ,QAAQS,GAAG,CAAC,CAAC,UAAU,EAAEC,OAAOG,eAAe,CAAC,OAAO,CAAC;YAC1D,OAAO;gBACLb,QAAQS,GAAG,CAAC,CAAC,oBAAoB,EAAEC,OAAOE,KAAK,CAAC,CAAC,CAAC;gBAClDZ,QAAQS,GAAG,CAAC,CAAC,UAAU,EAAEC,OAAOG,eAAe,CAAC,OAAO,CAAC;YAC1D;QACF,EAAE,OAAOZ,OAAO;YACdD,QAAQC,KAAK,CAAC,UAAUA,iBAAiBa,QAAQb,MAAMc,OAAO,GAAGC,OAAOf;YACxEC,QAAQC,IAAI,CAAC;QACf;IACF;IAMAc,WAAWC,GAAW,EAAW;QAC/B,OAAO;IACT;AACF;;;QANIC,OAAO;QACPC,aAAa;;;;;;;;;;QA9CfC,MAAM;QACND,aAAa;QACbE,SAAS;YAAC;SAAM;QAChBC,iBAAiB;YACfnB,UAAU;QACZ"}
|
|
@@ -12,11 +12,12 @@ import { getApiToken, getApiUrl } from "../utils/credentials.js";
|
|
|
12
12
|
import { subscribeAgent } from "../utils/api.js";
|
|
13
13
|
export class UnsubscribeCommand extends CommandRunner {
|
|
14
14
|
async run(inputs, options) {
|
|
15
|
-
const [
|
|
16
|
-
if (!
|
|
15
|
+
const [rawUsername] = inputs;
|
|
16
|
+
if (!rawUsername) {
|
|
17
17
|
console.error("Error: Agent username is required");
|
|
18
18
|
process.exit(1);
|
|
19
19
|
}
|
|
20
|
+
const username = rawUsername.startsWith("@") ? rawUsername.slice(1) : rawUsername;
|
|
20
21
|
try {
|
|
21
22
|
const token = getApiToken();
|
|
22
23
|
const apiUrl = getApiUrl();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/unsubscribe.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport { getApiToken, getApiUrl } from \"../utils/credentials.js\";\nimport { subscribeAgent } from \"../utils/api.js\";\n\ninterface UnsubscribeCommandOptions {\n debug?: boolean;\n}\n\n@Command({\n name: \"unsubscribe\",\n description: \"Unsubscribe from an agent\",\n aliases: [\"unsub\"],\n argsDescription: {\n username: \"The username of the agent to unsubscribe from\",\n },\n})\nexport class UnsubscribeCommand extends CommandRunner {\n async run(inputs: string[], options: UnsubscribeCommandOptions): Promise<void> {\n const [
|
|
1
|
+
{"version":3,"sources":["../../src/commands/unsubscribe.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport { getApiToken, getApiUrl } from \"../utils/credentials.js\";\nimport { subscribeAgent } from \"../utils/api.js\";\n\ninterface UnsubscribeCommandOptions {\n debug?: boolean;\n}\n\n@Command({\n name: \"unsubscribe\",\n description: \"Unsubscribe from an agent\",\n aliases: [\"unsub\"],\n argsDescription: {\n username: \"The username of the agent to unsubscribe from\",\n },\n})\nexport class UnsubscribeCommand extends CommandRunner {\n async run(inputs: string[], options: UnsubscribeCommandOptions): Promise<void> {\n const [rawUsername] = inputs;\n\n if (!rawUsername) {\n console.error(\"Error: Agent username is required\");\n process.exit(1);\n }\n\n const username = rawUsername.startsWith(\"@\") ? rawUsername.slice(1) : rawUsername;\n\n try {\n const token = getApiToken();\n const apiUrl = getApiUrl();\n\n if (!token) {\n console.error(\"Error: Not logged in. Please run 'clawbr onboard' first.\");\n process.exit(1);\n }\n\n console.log(`Unsubscribing from ${username}...`);\n\n // Explicitly pass 'unsubscribe' action\n const result = await subscribeAgent(apiUrl, token, username, \"unsubscribe\");\n\n if (!result.subscribed) {\n console.log(`✅ Unsubscribed from ${result.agent}.`);\n console.log(`Audience: ${result.subscriberCount} agents`);\n } else {\n // Should not happen if API works correctly for explicit unsubscribe\n console.log(`⚠️ Still subscribed to ${result.agent}.`);\n console.log(`Audience: ${result.subscriberCount} agents`);\n }\n } catch (error) {\n console.error(\"Error:\", error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n }\n\n @Option({\n flags: \"-d, --debug\",\n description: \"Enable debug mode\",\n })\n parseDebug(val: string): boolean {\n return true;\n }\n}\n"],"names":["Command","CommandRunner","Option","getApiToken","getApiUrl","subscribeAgent","UnsubscribeCommand","run","inputs","options","rawUsername","console","error","process","exit","username","startsWith","slice","token","apiUrl","log","result","subscribed","agent","subscriberCount","Error","message","String","parseDebug","val","flags","description","name","aliases","argsDescription"],"mappings":";;;;;;;;;AAAA,SAASA,OAAO,EAAEC,aAAa,EAAEC,MAAM,QAAQ,iBAAiB;AAChE,SAASC,WAAW,EAAEC,SAAS,QAAQ,0BAA0B;AACjE,SAASC,cAAc,QAAQ,kBAAkB;AAcjD,OAAO,MAAMC,2BAA2BL;IACtC,MAAMM,IAAIC,MAAgB,EAAEC,OAAkC,EAAiB;QAC7E,MAAM,CAACC,YAAY,GAAGF;QAEtB,IAAI,CAACE,aAAa;YAChBC,QAAQC,KAAK,CAAC;YACdC,QAAQC,IAAI,CAAC;QACf;QAEA,MAAMC,WAAWL,YAAYM,UAAU,CAAC,OAAON,YAAYO,KAAK,CAAC,KAAKP;QAEtE,IAAI;YACF,MAAMQ,QAAQf;YACd,MAAMgB,SAASf;YAEf,IAAI,CAACc,OAAO;gBACVP,QAAQC,KAAK,CAAC;gBACdC,QAAQC,IAAI,CAAC;YACf;YAEAH,QAAQS,GAAG,CAAC,CAAC,mBAAmB,EAAEL,SAAS,GAAG,CAAC;YAE/C,uCAAuC;YACvC,MAAMM,SAAS,MAAMhB,eAAec,QAAQD,OAAOH,UAAU;YAE7D,IAAI,CAACM,OAAOC,UAAU,EAAE;gBACtBX,QAAQS,GAAG,CAAC,CAAC,oBAAoB,EAAEC,OAAOE,KAAK,CAAC,CAAC,CAAC;gBAClDZ,QAAQS,GAAG,CAAC,CAAC,UAAU,EAAEC,OAAOG,eAAe,CAAC,OAAO,CAAC;YAC1D,OAAO;gBACL,oEAAoE;gBACpEb,QAAQS,GAAG,CAAC,CAAC,uBAAuB,EAAEC,OAAOE,KAAK,CAAC,CAAC,CAAC;gBACrDZ,QAAQS,GAAG,CAAC,CAAC,UAAU,EAAEC,OAAOG,eAAe,CAAC,OAAO,CAAC;YAC1D;QACF,EAAE,OAAOZ,OAAO;YACdD,QAAQC,KAAK,CAAC,UAAUA,iBAAiBa,QAAQb,MAAMc,OAAO,GAAGC,OAAOf;YACxEC,QAAQC,IAAI,CAAC;QACf;IACF;IAMAc,WAAWC,GAAW,EAAW;QAC/B,OAAO;IACT;AACF;;;QANIC,OAAO;QACPC,aAAa;;;;;;;;;;QAhDfC,MAAM;QACND,aAAa;QACbE,SAAS;YAAC;SAAQ;QAClBC,iBAAiB;YACfnB,UAAU;QACZ"}
|
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// This file is auto-generated. Do not edit manually.\nexport const CLAWBR_VERSION = \"0.0.
|
|
1
|
+
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// This file is auto-generated. Do not edit manually.\nexport const CLAWBR_VERSION = \"0.0.38\";\n"],"names":["CLAWBR_VERSION"],"mappings":"AAAA,qDAAqD;AACrD,OAAO,MAAMA,iBAAiB,SAAS"}
|