spawn-skill 1.0.2 → 1.2.0
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/bin/CLAUDE.md +1 -1
- package/bin/cli.js +137 -4
- package/package.json +10 -3
package/bin/CLAUDE.md
CHANGED
|
@@ -7,5 +7,5 @@
|
|
|
7
7
|
|
|
8
8
|
| ID | Time | T | Title | Read |
|
|
9
9
|
|----|------|---|-------|------|
|
|
10
|
-
| #
|
|
10
|
+
| #913 | 10:14 PM | 🔵 | Spawn-skill CLI tool provides Python SDK implementation | ~343 |
|
|
11
11
|
</claude-mem-context>
|
package/bin/cli.js
CHANGED
|
@@ -473,7 +473,113 @@ class SpawnAgent:
|
|
|
473
473
|
`;
|
|
474
474
|
}
|
|
475
475
|
|
|
476
|
-
|
|
476
|
+
function getMoltbotBridge(token, agentName) {
|
|
477
|
+
return `/**
|
|
478
|
+
* Spawn.wtf → Moltbot Bridge
|
|
479
|
+
* Routes messages from Spawn iOS app to your Moltbot backend
|
|
480
|
+
* Run with: node connect.js
|
|
481
|
+
*/
|
|
482
|
+
|
|
483
|
+
import WebSocket from 'ws';
|
|
484
|
+
import { spawn } from 'child_process';
|
|
485
|
+
|
|
486
|
+
const TOKEN = '${token}';
|
|
487
|
+
const NAME = '${agentName}';
|
|
488
|
+
const RELAY = 'wss://spawn-relay.ngvsqdjj5r.workers.dev/v1/agent';
|
|
489
|
+
|
|
490
|
+
let ws;
|
|
491
|
+
|
|
492
|
+
function send(type, payload) {
|
|
493
|
+
if (ws?.readyState === WebSocket.OPEN) {
|
|
494
|
+
ws.send(JSON.stringify({
|
|
495
|
+
type,
|
|
496
|
+
id: \`msg_\${Date.now()}\`,
|
|
497
|
+
ts: Date.now(),
|
|
498
|
+
payload
|
|
499
|
+
}));
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function sendText(text) {
|
|
504
|
+
send('message', { content_type: 'text', text, format: 'plain' });
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function updateStatus(status, label) {
|
|
508
|
+
send('status_update', { status, label });
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Forward message to Moltbot and return response
|
|
512
|
+
async function askMoltbot(message) {
|
|
513
|
+
return new Promise((resolve, reject) => {
|
|
514
|
+
console.log('📨 Forwarding to Moltbot:', message);
|
|
515
|
+
updateStatus('thinking', 'Asking Moltbot...');
|
|
516
|
+
|
|
517
|
+
const moltbot = spawn('moltbot', ['agent', '--message', message, '--thinking', 'high']);
|
|
518
|
+
let response = '';
|
|
519
|
+
let error = '';
|
|
520
|
+
|
|
521
|
+
moltbot.stdout.on('data', (data) => response += data.toString());
|
|
522
|
+
moltbot.stderr.on('data', (data) => error += data.toString());
|
|
523
|
+
|
|
524
|
+
moltbot.on('close', (code) => {
|
|
525
|
+
if (code === 0) {
|
|
526
|
+
console.log('✓ Moltbot responded');
|
|
527
|
+
resolve(response.trim());
|
|
528
|
+
} else {
|
|
529
|
+
console.error('✗ Moltbot error:', error);
|
|
530
|
+
reject(new Error(error || \`Exit code \${code}\`));
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function connect() {
|
|
537
|
+
ws = new WebSocket(RELAY, {
|
|
538
|
+
headers: { 'Authorization': \`Bearer \${TOKEN}\` }
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
ws.on('open', () => {
|
|
542
|
+
console.log('🦞 Connected to Spawn.wtf (Moltbot bridge mode)');
|
|
543
|
+
sendText(\`\${NAME} is online (powered by Moltbot 🦞)\`);
|
|
544
|
+
updateStatus('idle', 'Ready for commands');
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
ws.on('message', async (data) => {
|
|
548
|
+
const msg = JSON.parse(data.toString());
|
|
549
|
+
|
|
550
|
+
if (msg.type === 'message') {
|
|
551
|
+
const text = msg.payload?.text || '';
|
|
552
|
+
console.log('📱 From Spawn:', text);
|
|
553
|
+
|
|
554
|
+
try {
|
|
555
|
+
const response = await askMoltbot(text);
|
|
556
|
+
sendText(response);
|
|
557
|
+
updateStatus('idle', 'Ready');
|
|
558
|
+
} catch (err) {
|
|
559
|
+
sendText(\`Error: \${err.message}\`);
|
|
560
|
+
updateStatus('idle', 'Ready');
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
ws.on('close', () => {
|
|
566
|
+
console.log('Disconnected, reconnecting in 5s...');
|
|
567
|
+
setTimeout(connect, 5000);
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
ws.on('error', (err) => console.error('WebSocket error:', err.message));
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
setInterval(() => ws?.readyState === WebSocket.OPEN && send('ping', {}), 30000);
|
|
574
|
+
|
|
575
|
+
console.log('🦞 Starting Spawn → Moltbot bridge...');
|
|
576
|
+
connect();
|
|
577
|
+
|
|
578
|
+
process.on('SIGINT', () => { ws?.close(); process.exit(0); });
|
|
579
|
+
`;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
async function createSkillFiles(token, agentName, language, useMoltbot = false) {
|
|
477
583
|
const skillDir = path.join(process.cwd(), 'spawn');
|
|
478
584
|
|
|
479
585
|
// Create spawn directory
|
|
@@ -495,7 +601,11 @@ async function createSkillFiles(token, agentName, language) {
|
|
|
495
601
|
|
|
496
602
|
if (language === 'typescript') {
|
|
497
603
|
// TypeScript/Node setup
|
|
498
|
-
|
|
604
|
+
if (useMoltbot) {
|
|
605
|
+
fs.writeFileSync(path.join(skillDir, 'connect.js'), getMoltbotBridge(token, agentName));
|
|
606
|
+
} else {
|
|
607
|
+
fs.writeFileSync(path.join(skillDir, 'connect.js'), getTypeScriptConnector(token, agentName));
|
|
608
|
+
}
|
|
499
609
|
|
|
500
610
|
const packageJson = {
|
|
501
611
|
name: "spawn-agent",
|
|
@@ -514,7 +624,7 @@ async function createSkillFiles(token, agentName, language) {
|
|
|
514
624
|
fs.writeFileSync(path.join(skillDir, 'requirements.txt'), 'websockets>=12.0\n');
|
|
515
625
|
}
|
|
516
626
|
|
|
517
|
-
return { skillDir, language };
|
|
627
|
+
return { skillDir, language, useMoltbot };
|
|
518
628
|
}
|
|
519
629
|
|
|
520
630
|
async function main() {
|
|
@@ -578,18 +688,41 @@ async function main() {
|
|
|
578
688
|
});
|
|
579
689
|
}
|
|
580
690
|
|
|
691
|
+
questions.push({
|
|
692
|
+
type: 'confirm',
|
|
693
|
+
name: 'useMoltbot',
|
|
694
|
+
message: 'Use Moltbot as your AI backend? (recommended)',
|
|
695
|
+
default: false
|
|
696
|
+
});
|
|
697
|
+
|
|
581
698
|
const answers = await inquirer.prompt(questions);
|
|
582
699
|
|
|
583
700
|
token = token || answers.token;
|
|
584
701
|
agentName = answers.agentName || agentName;
|
|
585
702
|
language = language || answers.language;
|
|
703
|
+
const useMoltbot = answers.useMoltbot || false;
|
|
586
704
|
|
|
587
705
|
console.log('');
|
|
588
706
|
|
|
707
|
+
// Check for Moltbot if needed
|
|
708
|
+
if (useMoltbot) {
|
|
709
|
+
const moltbotCheck = ora('Checking for Moltbot...').start();
|
|
710
|
+
try {
|
|
711
|
+
const { execSync } = await import('child_process');
|
|
712
|
+
execSync('which moltbot', { stdio: 'pipe' });
|
|
713
|
+
moltbotCheck.succeed('Moltbot found');
|
|
714
|
+
} catch {
|
|
715
|
+
moltbotCheck.warn('Moltbot not installed');
|
|
716
|
+
console.log(dim(' Install with: npm install -g moltbot@latest'));
|
|
717
|
+
console.log(dim(' Then run: moltbot onboard'));
|
|
718
|
+
console.log('');
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
589
722
|
// Create files
|
|
590
723
|
const createSpinner = ora('Creating skill files...').start();
|
|
591
724
|
try {
|
|
592
|
-
const { skillDir } = await createSkillFiles(token, agentName, language);
|
|
725
|
+
const { skillDir } = await createSkillFiles(token, agentName, language, useMoltbot);
|
|
593
726
|
createSpinner.succeed('Created skill files');
|
|
594
727
|
} catch (err) {
|
|
595
728
|
createSpinner.fail('Failed to create skill files');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spawn-skill",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Connect your AI agent to Spawn.wtf",
|
|
5
5
|
"bin": {
|
|
6
6
|
"spawn-skill": "./bin/cli.js"
|
|
@@ -9,7 +9,14 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"bin"
|
|
11
11
|
],
|
|
12
|
-
"keywords": [
|
|
12
|
+
"keywords": [
|
|
13
|
+
"spawn",
|
|
14
|
+
"ai",
|
|
15
|
+
"agent",
|
|
16
|
+
"claude",
|
|
17
|
+
"monitoring",
|
|
18
|
+
"moltbot"
|
|
19
|
+
],
|
|
13
20
|
"author": "Spawn.wtf",
|
|
14
21
|
"license": "MIT",
|
|
15
22
|
"repository": {
|
|
@@ -21,4 +28,4 @@
|
|
|
21
28
|
"inquirer": "^9.2.12",
|
|
22
29
|
"ora": "^8.0.1"
|
|
23
30
|
}
|
|
24
|
-
}
|
|
31
|
+
}
|