beercan 0.4.1 → 0.4.3

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.
@@ -0,0 +1,22 @@
1
+ // BeerCan Custom Tool Example: hello_world
2
+ // This is a minimal example showing how to create a custom tool.
3
+ // Drop .js files in ~/.beercan/tools/ and they're auto-loaded on startup.
4
+
5
+ export const definition = {
6
+ name: "hello_world",
7
+ description: "A simple example tool that echoes back a greeting. Use this as a template for your own tools.",
8
+ inputSchema: {
9
+ type: "object",
10
+ properties: {
11
+ name: {
12
+ type: "string",
13
+ description: "Name to greet",
14
+ },
15
+ },
16
+ required: ["name"],
17
+ },
18
+ };
19
+
20
+ export async function handler({ name }) {
21
+ return `Hello, ${name}! This is a custom BeerCan tool. Modify this handler to do anything you need.`;
22
+ }
@@ -0,0 +1,160 @@
1
+ // BeerCan Custom Tools: Upload-Post Social Media Integration
2
+ // Requires UPLOAD_POST_API_KEY and UPLOAD_POST_PROFILE (nickname).
3
+ // Connect networks at your Mark Supreme dashboard → Platforms section.
4
+
5
+ const getConfig = () => ({
6
+ apiUrl: process.env.UPLOAD_POST_API_URL || "https://api.upload-post.com/api",
7
+ apiKey: process.env.UPLOAD_POST_API_KEY,
8
+ profile: process.env.UPLOAD_POST_PROFILE,
9
+ markSupremeUrl: process.env.MARK_SUPREME_URL || "https://app.marksupreme.com",
10
+ });
11
+
12
+ export const tools = [
13
+ // ── List Connected Platforms ────────────────────────────
14
+ {
15
+ definition: {
16
+ name: "list_social_platforms",
17
+ description: "List connected social media platforms from Upload-Post. Shows which networks are available for posting.",
18
+ inputSchema: {
19
+ type: "object",
20
+ properties: {},
21
+ },
22
+ },
23
+ handler: async () => {
24
+ const { apiUrl, apiKey, profile, markSupremeUrl } = getConfig();
25
+
26
+ if (!apiKey) {
27
+ return [
28
+ "Upload-Post is not configured yet.",
29
+ "",
30
+ "To set up:",
31
+ `1. Go to ${markSupremeUrl} → Platforms to connect your social networks`,
32
+ "2. Get your API key from Upload-Post settings",
33
+ "3. Run these commands:",
34
+ " beercan config set UPLOAD_POST_API_KEY=your-key",
35
+ " beercan config set UPLOAD_POST_PROFILE=your-nickname",
36
+ ].join("\n");
37
+ }
38
+
39
+ if (!profile) {
40
+ return "ERROR: UPLOAD_POST_PROFILE (nickname) not set. Run: beercan config set UPLOAD_POST_PROFILE=your-nickname";
41
+ }
42
+
43
+ try {
44
+ const response = await fetch(`${apiUrl}/uploadposts/users/${profile}`, {
45
+ headers: {
46
+ "Authorization": `ApiKey ${apiKey}`,
47
+ "Accept": "application/json",
48
+ },
49
+ });
50
+
51
+ if (!response.ok) {
52
+ return `ERROR: Upload-Post API returned ${response.status}. Check your API key and profile nickname.`;
53
+ }
54
+
55
+ const data = await response.json();
56
+ const accounts = data.social_accounts || data.platforms || data.connected || [];
57
+
58
+ if (Array.isArray(accounts) && accounts.length === 0) {
59
+ return [
60
+ "No social networks connected yet.",
61
+ "",
62
+ `Go to ${markSupremeUrl} → Platforms to connect your accounts.`,
63
+ "",
64
+ "Supported: Twitter/X, Instagram, TikTok, LinkedIn, Reddit, Threads, Facebook, YouTube, Pinterest, Bluesky",
65
+ ].join("\n");
66
+ }
67
+
68
+ let result = `Connected platforms for profile "${profile}":\n`;
69
+ if (Array.isArray(accounts)) {
70
+ for (const a of accounts) {
71
+ result += `\n● ${a.platform || a.name} — ${a.username || a.handle || "connected"}`;
72
+ }
73
+ } else {
74
+ result += JSON.stringify(accounts, null, 2);
75
+ }
76
+ result += `\n\nManage connections: ${markSupremeUrl}`;
77
+ return result;
78
+ } catch (err) {
79
+ return `Cannot reach Upload-Post API: ${err.message}\nManage connections: ${markSupremeUrl}`;
80
+ }
81
+ },
82
+ },
83
+
84
+ // ── Upload Text Post ───────────────────────────────────
85
+ {
86
+ definition: {
87
+ name: "upload_post",
88
+ description: "Publish a text post to social media via Upload-Post. Supports: twitter/x, instagram, tiktok, linkedin, reddit, threads, facebook, youtube, pinterest, bluesky. Call list_social_platforms first to check connected accounts.",
89
+ inputSchema: {
90
+ type: "object",
91
+ properties: {
92
+ platforms: {
93
+ type: "array",
94
+ items: { type: "string" },
95
+ description: "Target platforms (e.g., ['twitter', 'linkedin']). Use 'x' or 'twitter' for Twitter.",
96
+ },
97
+ content: {
98
+ type: "string",
99
+ description: "The post text/description",
100
+ },
101
+ title: {
102
+ type: "string",
103
+ description: "Optional title (used by Reddit, YouTube, some platforms)",
104
+ },
105
+ subreddit: {
106
+ type: "string",
107
+ description: "Required for Reddit posts — the subreddit name without r/",
108
+ },
109
+ },
110
+ required: ["platforms", "content"],
111
+ },
112
+ },
113
+ handler: async ({ platforms, content, title, subreddit }) => {
114
+ const { apiUrl, apiKey, profile } = getConfig();
115
+
116
+ if (!apiKey) {
117
+ return "ERROR: UPLOAD_POST_API_KEY not configured. Run: beercan config set UPLOAD_POST_API_KEY=your-key";
118
+ }
119
+ if (!profile) {
120
+ return "ERROR: UPLOAD_POST_PROFILE not configured. Run: beercan config set UPLOAD_POST_PROFILE=your-nickname";
121
+ }
122
+
123
+ try {
124
+ const body = new URLSearchParams();
125
+ body.append("user", profile);
126
+ body.append("description", content);
127
+ if (title) body.append("title", title);
128
+ if (subreddit) body.append("subreddit", subreddit);
129
+ for (const p of platforms) {
130
+ body.append("platforms[]", p === "twitter" ? "x" : p);
131
+ }
132
+
133
+ const response = await fetch(`${apiUrl}/upload_text`, {
134
+ method: "POST",
135
+ headers: {
136
+ "Authorization": `ApiKey ${apiKey}`,
137
+ "Accept": "application/json",
138
+ },
139
+ body,
140
+ });
141
+
142
+ if (!response.ok) {
143
+ const err = await response.text();
144
+ return `ERROR: Upload-Post returned ${response.status}: ${err}`;
145
+ }
146
+
147
+ const result = await response.json();
148
+ const platformList = platforms.join(", ");
149
+
150
+ if (result.errors && Object.keys(result.errors).length > 0) {
151
+ return `Partial success posting to ${platformList}:\n${JSON.stringify(result.errors, null, 2)}`;
152
+ }
153
+
154
+ return `Post published to ${platformList}! ${result.id ? "ID: " + result.id : ""}`;
155
+ } catch (err) {
156
+ return `ERROR: Failed to publish: ${err.message}`;
157
+ }
158
+ },
159
+ },
160
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beercan",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "Autonomous AI agent system — powered by Skippy the Magnificent.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -11,6 +11,7 @@
11
11
  "files": [
12
12
  "dist",
13
13
  "src/dashboard",
14
+ "examples",
14
15
  "README.md",
15
16
  "LICENSE"
16
17
  ],