beercan 0.4.2 → 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.
- package/README.md +51 -0
- package/dist/skills/index.d.ts +3 -1
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +72 -1
- package/dist/skills/index.js.map +1 -1
- package/examples/skills/daily-report.json +9 -0
- package/examples/skills/social-post.json +12 -0
- package/examples/tools/hello_world.js +22 -0
- package/examples/tools/upload_post.js +160 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -20,6 +20,16 @@ beercan setup
|
|
|
20
20
|
|
|
21
21
|
Interactive wizard that configures your API keys, models, and optional integrations (Cloudflare, Telegram, Slack). Creates `~/.beercan/.env`.
|
|
22
22
|
|
|
23
|
+
## Config
|
|
24
|
+
|
|
25
|
+
Quick config management without the full setup wizard:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
beercan config set KEY=VALUE # Set a config value
|
|
29
|
+
beercan config get KEY # Get a value (keys masked)
|
|
30
|
+
beercan config list # Show all config
|
|
31
|
+
```
|
|
32
|
+
|
|
23
33
|
## Quick Start
|
|
24
34
|
|
|
25
35
|
```bash
|
|
@@ -197,6 +207,35 @@ Three ways to extend BeerCan with tools:
|
|
|
197
207
|
|
|
198
208
|
Custom tools are automatically available to all agent roles. No configuration needed.
|
|
199
209
|
|
|
210
|
+
## Skills
|
|
211
|
+
|
|
212
|
+
Skills are higher-level than tools — they orchestrate workflows with instructions, triggers, and config. Drop a `.json` file in `~/.beercan/skills/`.
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
beercan skill:create social-post # Scaffold a skill template
|
|
216
|
+
beercan skill:list # List installed skills
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Example skill (`~/.beercan/skills/social-post.json`):
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"name": "social-post",
|
|
223
|
+
"description": "Generate and publish social media posts via Mark Supreme",
|
|
224
|
+
"triggers": ["social media", "twitter", "linkedin", "post to"],
|
|
225
|
+
"instructions": "1. Call list_social_platforms to check connections\n2. Generate platform-appropriate content\n3. Use upload_post tool to publish",
|
|
226
|
+
"requiredTools": ["upload_post", "list_social_platforms"],
|
|
227
|
+
"config": {
|
|
228
|
+
"UPLOAD_POST_API_URL": "https://api.marksupreme.com/v1",
|
|
229
|
+
"UPLOAD_POST_API_KEY": "your-key"
|
|
230
|
+
},
|
|
231
|
+
"enabled": true
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
When a bloop goal matches a skill's triggers, the instructions are automatically injected into agent context. Skills + tools work together:
|
|
236
|
+
- **Tools** = atomic API calls (post to Twitter, fetch a URL)
|
|
237
|
+
- **Skills** = workflow recipes (research → generate → post to multiple platforms)
|
|
238
|
+
|
|
200
239
|
## Memory System
|
|
201
240
|
|
|
202
241
|
4-layer hybrid RAG — all in SQLite:
|
|
@@ -274,6 +313,13 @@ BeerCan's conversational interface is provider-agnostic:
|
|
|
274
313
|
|
|
275
314
|
All providers share the same ChatBridge — slash commands and natural language work everywhere.
|
|
276
315
|
|
|
316
|
+
### Telegram Quick Setup
|
|
317
|
+
|
|
318
|
+
1. Message `@BotFather` on Telegram → `/newbot` → get token
|
|
319
|
+
2. `beercan config set BEERCAN_TELEGRAM_TOKEN=your-token`
|
|
320
|
+
3. `beercan stop && beercan start`
|
|
321
|
+
4. Message your bot — Skippy answers!
|
|
322
|
+
|
|
277
323
|
## Production Features
|
|
278
324
|
|
|
279
325
|
- **Crash recovery** — stale "running" jobs auto-recovered on startup
|
|
@@ -304,6 +350,11 @@ beercan mcp:add <project> <name> <cmd> [args]
|
|
|
304
350
|
beercan tool:create <name> Scaffold a custom tool
|
|
305
351
|
beercan tool:list List custom tools
|
|
306
352
|
beercan tool:remove <name> Remove a custom tool
|
|
353
|
+
beercan skill:create <name> Scaffold a skill template
|
|
354
|
+
beercan skill:list List installed skills
|
|
355
|
+
beercan config set KEY=VALUE Set a config value
|
|
356
|
+
beercan config get KEY Get a config value
|
|
357
|
+
beercan config list Show all config
|
|
307
358
|
beercan daemon Run scheduler + events
|
|
308
359
|
beercan chat [project] Interactive Skippy chat
|
|
309
360
|
beercan serve [port] API server (default: 3939)
|
package/dist/skills/index.d.ts
CHANGED
|
@@ -16,8 +16,10 @@ export declare class SkillManager {
|
|
|
16
16
|
private dataDir;
|
|
17
17
|
private skills;
|
|
18
18
|
constructor(dataDir: string);
|
|
19
|
-
/** Load
|
|
19
|
+
/** Load built-in + user skills */
|
|
20
20
|
load(): void;
|
|
21
|
+
/** Register built-in skills that are always available */
|
|
22
|
+
private loadBuiltinSkills;
|
|
21
23
|
/** Get all loaded skills */
|
|
22
24
|
listSkills(): Skill[];
|
|
23
25
|
/** Get enabled skills */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,YAAY;IAGX,OAAO,CAAC,OAAO;IAF3B,OAAO,CAAC,MAAM,CAA4B;gBAEtB,OAAO,EAAE,MAAM;IAEnC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,YAAY;IAGX,OAAO,CAAC,OAAO;IAF3B,OAAO,CAAC,MAAM,CAA4B;gBAEtB,OAAO,EAAE,MAAM;IAEnC,kCAAkC;IAClC,IAAI,IAAI,IAAI;IA+BZ,yDAAyD;IACzD,OAAO,CAAC,iBAAiB;IAwEzB,4BAA4B;IAC5B,UAAU,IAAI,KAAK,EAAE;IAIrB,yBAAyB;IACzB,gBAAgB,IAAI,KAAK,EAAE;IAI3B,wDAAwD;IACxD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE;IAOlC,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIzC,4EAA4E;IAC5E,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAuB9C,mCAAmC;IACnC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAkBrC"}
|
package/dist/skills/index.js
CHANGED
|
@@ -7,8 +7,9 @@ export class SkillManager {
|
|
|
7
7
|
constructor(dataDir) {
|
|
8
8
|
this.dataDir = dataDir;
|
|
9
9
|
}
|
|
10
|
-
/** Load
|
|
10
|
+
/** Load built-in + user skills */
|
|
11
11
|
load() {
|
|
12
|
+
this.loadBuiltinSkills();
|
|
12
13
|
const skillsDir = path.join(this.dataDir, "skills");
|
|
13
14
|
if (!fs.existsSync(skillsDir))
|
|
14
15
|
return;
|
|
@@ -36,6 +37,76 @@ export class SkillManager {
|
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
}
|
|
40
|
+
/** Register built-in skills that are always available */
|
|
41
|
+
loadBuiltinSkills() {
|
|
42
|
+
const toolsDir = path.join(this.dataDir, "tools");
|
|
43
|
+
const skillsDir = path.join(this.dataDir, "skills");
|
|
44
|
+
this.skills.set("generate-tool", {
|
|
45
|
+
name: "generate-tool",
|
|
46
|
+
description: "Generate a custom tool file for BeerCan agents",
|
|
47
|
+
triggers: ["create a tool", "generate a tool", "make a tool", "new tool", "build a tool", "add a tool"],
|
|
48
|
+
instructions: [
|
|
49
|
+
`When asked to create/generate a custom tool:`,
|
|
50
|
+
``,
|
|
51
|
+
`1. Ask what the tool should do if not clear from the request`,
|
|
52
|
+
`2. Generate a JavaScript ESM file with this EXACT structure:`,
|
|
53
|
+
``,
|
|
54
|
+
` export const definition = {`,
|
|
55
|
+
` name: "tool_name", // snake_case, descriptive`,
|
|
56
|
+
` description: "What the tool does — agents read this to decide when to use it",`,
|
|
57
|
+
` inputSchema: {`,
|
|
58
|
+
` type: "object",`,
|
|
59
|
+
` properties: { /* input params */ },`,
|
|
60
|
+
` required: ["param1"],`,
|
|
61
|
+
` },`,
|
|
62
|
+
` };`,
|
|
63
|
+
``,
|
|
64
|
+
` export async function handler({ param1 }) {`,
|
|
65
|
+
` // Tool logic — can use fetch(), process.env, etc.`,
|
|
66
|
+
` return "string result that the agent sees";`,
|
|
67
|
+
` }`,
|
|
68
|
+
``,
|
|
69
|
+
`3. IMPORTANT: Write the file to: ${toolsDir}/<tool_name>.js`,
|
|
70
|
+
`4. The tool will be auto-loaded on next BeerCan restart`,
|
|
71
|
+
`5. For multi-tool files, export: export const tools = [{ definition, handler }, ...]`,
|
|
72
|
+
`6. Tools can access env vars via process.env for API keys`,
|
|
73
|
+
`7. Always return a string from the handler — that's what the agent sees`,
|
|
74
|
+
].join("\n"),
|
|
75
|
+
requiredTools: ["write_file"],
|
|
76
|
+
config: {},
|
|
77
|
+
enabled: true,
|
|
78
|
+
});
|
|
79
|
+
this.skills.set("generate-skill", {
|
|
80
|
+
name: "generate-skill",
|
|
81
|
+
description: "Generate a skill configuration file for BeerCan",
|
|
82
|
+
triggers: ["create a skill", "generate a skill", "make a skill", "new skill", "build a skill", "add a skill"],
|
|
83
|
+
instructions: [
|
|
84
|
+
`When asked to create/generate a skill:`,
|
|
85
|
+
``,
|
|
86
|
+
`1. Ask what the skill should do if not clear`,
|
|
87
|
+
`2. Generate a JSON file with this structure:`,
|
|
88
|
+
``,
|
|
89
|
+
` {`,
|
|
90
|
+
` "name": "skill-name",`,
|
|
91
|
+
` "description": "What this skill does",`,
|
|
92
|
+
` "triggers": ["keyword1", "keyword2"], // words that activate this skill`,
|
|
93
|
+
` "instructions": "Step-by-step instructions for agents...",`,
|
|
94
|
+
` "requiredTools": ["tool1", "tool2"], // tools agents need`,
|
|
95
|
+
` "config": { "API_KEY": "value" }, // env vars/config`,
|
|
96
|
+
` "enabled": true`,
|
|
97
|
+
` }`,
|
|
98
|
+
``,
|
|
99
|
+
`3. IMPORTANT: Write the file to: ${skillsDir}/<skill-name>.json`,
|
|
100
|
+
`4. The skill will be auto-loaded on next BeerCan restart`,
|
|
101
|
+
`5. Triggers should be natural language phrases users might say`,
|
|
102
|
+
`6. Instructions tell agents HOW to accomplish the workflow step by step`,
|
|
103
|
+
`7. If the skill needs a custom tool, offer to generate that too`,
|
|
104
|
+
].join("\n"),
|
|
105
|
+
requiredTools: ["write_file"],
|
|
106
|
+
config: {},
|
|
107
|
+
enabled: true,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
39
110
|
/** Get all loaded skills */
|
|
40
111
|
listSkills() {
|
|
41
112
|
return Array.from(this.skills.values());
|
package/dist/skills/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AA4B9C,MAAM,OAAO,YAAY;IAGH;IAFZ,MAAM,GAAG,IAAI,GAAG,EAAiB,CAAC;IAE1C,YAAoB,OAAe;QAAf,YAAO,GAAP,OAAO,CAAQ;IAAG,CAAC;IAEvC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "daily-report",
|
|
3
|
+
"description": "Generate daily summary reports from web sources on a given topic",
|
|
4
|
+
"triggers": ["daily report", "daily briefing", "daily summary", "news summary", "daily digest"],
|
|
5
|
+
"instructions": "When generating a daily report:\n1. Use web_fetch to search multiple news sources for the topic\n2. Try at least 3-5 sources (RSS feeds, news sites, blogs)\n3. For each article found: extract title, source, date, and summary\n4. Write a structured markdown report with:\n - Date/time header\n - Executive summary (3-5 sentences)\n - Individual article sections with links\n - Key takeaways at the end\n5. Save the report as a .md file in the project directory\n6. Store key findings in memory for future reference",
|
|
6
|
+
"requiredTools": ["web_fetch", "write_file", "memory_store"],
|
|
7
|
+
"config": {},
|
|
8
|
+
"enabled": true
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "social-post",
|
|
3
|
+
"description": "Generate and publish social media posts via Upload-Post (10 platforms supported)",
|
|
4
|
+
"triggers": ["social media", "social post", "twitter", "instagram", "tiktok", "linkedin", "reddit", "threads", "facebook", "youtube", "pinterest", "bluesky", "post to", "publish post", "social network", "tweet", "share on"],
|
|
5
|
+
"instructions": "When asked about social media posting:\n\n1. FIRST, call list_social_platforms to see connected accounts\n - If not configured: tell user to run:\n beercan config set UPLOAD_POST_API_KEY=your-key\n beercan config set UPLOAD_POST_PROFILE=your-nickname\n - To connect more networks: go to Mark Supreme dashboard → Platforms\n\n2. Supported platforms (10): Twitter/X, Instagram, TikTok, LinkedIn, Reddit, Threads, Facebook, YouTube, Pinterest, Bluesky\n\n3. When creating a post:\n a. Research the topic using web_fetch if needed\n b. Generate platform-appropriate content:\n - Twitter/X: max 280 chars, punchy, 2-3 hashtags\n - LinkedIn: professional, 1-3 paragraphs\n - Instagram: visual caption, emojis, 5-10 hashtags\n - TikTok: casual, trending hashtags\n - Reddit: needs title + subreddit name\n c. Use upload_post tool with platforms array: upload_post({ platforms: ['twitter', 'linkedin'], content: '...' })\n d. Can post to multiple platforms at once\n e. Store results in memory\n\n4. When asked 'what social networks do we support?': call list_social_platforms",
|
|
6
|
+
"requiredTools": ["upload_post", "list_social_platforms"],
|
|
7
|
+
"config": {
|
|
8
|
+
"UPLOAD_POST_API_KEY": "set-via-beercan-config",
|
|
9
|
+
"UPLOAD_POST_PROFILE": "set-via-beercan-config"
|
|
10
|
+
},
|
|
11
|
+
"enabled": false
|
|
12
|
+
}
|
|
@@ -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.
|
|
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
|
],
|