jewbot 1.0.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/README.md +168 -0
- package/dist/commands/chat.d.ts +6 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +97 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +69 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/onboard.d.ts +2 -0
- package/dist/commands/onboard.d.ts.map +1 -0
- package/dist/commands/onboard.js +108 -0
- package/dist/commands/onboard.js.map +1 -0
- package/dist/core/personality.d.ts +2 -0
- package/dist/core/personality.d.ts.map +1 -0
- package/dist/core/personality.js +48 -0
- package/dist/core/personality.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
- package/scripts/install.cmd +50 -0
- package/scripts/install.ps1 +55 -0
- package/scripts/install.sh +60 -0
- package/src/commands/chat.ts +118 -0
- package/src/commands/config.ts +79 -0
- package/src/commands/onboard.ts +115 -0
- package/src/core/personality.ts +45 -0
- package/src/index.ts +88 -0
- package/tsconfig.json +21 -0
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jewbot",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Your personal Jewish financial assistant. Works everywhere.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"jewbot": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"dev": "ts-node src/index.ts",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"ai",
|
|
17
|
+
"agent",
|
|
18
|
+
"assistant",
|
|
19
|
+
"cli",
|
|
20
|
+
"jewish",
|
|
21
|
+
"finance",
|
|
22
|
+
"crypto",
|
|
23
|
+
"solana"
|
|
24
|
+
],
|
|
25
|
+
"author": "JEWBOT Team",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/openjewbot/jewbot.git"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://jewbot.fun",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"chalk": "^5.3.0",
|
|
34
|
+
"commander": "^12.0.0",
|
|
35
|
+
"conf": "^12.0.0",
|
|
36
|
+
"inquirer": "^9.2.15",
|
|
37
|
+
"openai": "^4.28.0",
|
|
38
|
+
"ora": "^8.0.1",
|
|
39
|
+
"boxen": "^7.1.1",
|
|
40
|
+
"figlet": "^1.7.0",
|
|
41
|
+
"gradient-string": "^2.0.2"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/figlet": "^1.5.8",
|
|
45
|
+
"@types/gradient-string": "^1.1.5",
|
|
46
|
+
"@types/inquirer": "^9.0.7",
|
|
47
|
+
"@types/node": "^20.11.0",
|
|
48
|
+
"ts-node": "^10.9.2",
|
|
49
|
+
"typescript": "^5.3.3"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=18.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
REM JEWBOT Installer for Windows (CMD)
|
|
3
|
+
REM Usage: curl -fsSL https://jewbot.fun/install.cmd -o install.cmd && install.cmd && del install.cmd
|
|
4
|
+
|
|
5
|
+
echo.
|
|
6
|
+
echo ██╗███████╗██╗ ██╗██████╗ ██████╗ ████████╗
|
|
7
|
+
echo ██║██╔════╝██║ ██║██╔══██╗██╔═══██╗╚══██╔══╝
|
|
8
|
+
echo ██║█████╗ ██║ █╗ ██║██████╔╝██║ ██║ ██║
|
|
9
|
+
echo ██ ██║██╔══╝ ██║███╗██║██╔══██╗██║ ██║ ██║
|
|
10
|
+
echo ╚█████╔╝███████╗╚███╔███╔╝██████╔╝╚██████╔╝ ██║
|
|
11
|
+
echo ╚════╝ ╚══════╝ ╚══╝╚══╝ ╚═════╝ ╚═════╝ ╚═╝
|
|
12
|
+
echo.
|
|
13
|
+
echo Your personal Jewish financial assistant
|
|
14
|
+
echo https://jewbot.fun
|
|
15
|
+
echo.
|
|
16
|
+
|
|
17
|
+
REM Check for Node.js
|
|
18
|
+
where node >nul 2>nul
|
|
19
|
+
if %ERRORLEVEL% neq 0 (
|
|
20
|
+
echo Oy vey! Node.js is not installed.
|
|
21
|
+
echo.
|
|
22
|
+
echo Install Node.js first:
|
|
23
|
+
echo winget install OpenJS.NodeJS
|
|
24
|
+
echo Or visit: https://nodejs.org
|
|
25
|
+
echo.
|
|
26
|
+
exit /b 1
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
echo Installing JEWBOT...
|
|
30
|
+
echo.
|
|
31
|
+
|
|
32
|
+
REM Install globally
|
|
33
|
+
call npm install -g jewbot
|
|
34
|
+
|
|
35
|
+
if %ERRORLEVEL% neq 0 (
|
|
36
|
+
echo.
|
|
37
|
+
echo Oy vey! Installation failed.
|
|
38
|
+
exit /b 1
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
echo.
|
|
42
|
+
echo Mazel tov! JEWBOT installed successfully!
|
|
43
|
+
echo.
|
|
44
|
+
echo Now run:
|
|
45
|
+
echo jewbot onboard - Set up your personal Jew
|
|
46
|
+
echo jewbot - Start chatting
|
|
47
|
+
echo.
|
|
48
|
+
echo Shalom!
|
|
49
|
+
echo.
|
|
50
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# JEWBOT Installer for Windows (PowerShell)
|
|
2
|
+
# Usage: iwr -useb https://jewbot.fun/install.ps1 | iex
|
|
3
|
+
|
|
4
|
+
$ErrorActionPreference = "Stop"
|
|
5
|
+
|
|
6
|
+
Write-Host ""
|
|
7
|
+
Write-Host " ██╗███████╗██╗ ██╗██████╗ ██████╗ ████████╗" -ForegroundColor Blue
|
|
8
|
+
Write-Host " ██║██╔════╝██║ ██║██╔══██╗██╔═══██╗╚══██╔══╝" -ForegroundColor White
|
|
9
|
+
Write-Host " ██║█████╗ ██║ █╗ ██║██████╔╝██║ ██║ ██║ " -ForegroundColor Blue
|
|
10
|
+
Write-Host "██ ██║██╔══╝ ██║███╗██║██╔══██╗██║ ██║ ██║ " -ForegroundColor White
|
|
11
|
+
Write-Host "╚█████╔╝███████╗╚███╔███╔╝██████╔╝╚██████╔╝ ██║ " -ForegroundColor Blue
|
|
12
|
+
Write-Host " ╚════╝ ╚══════╝ ╚══╝╚══╝ ╚═════╝ ╚═════╝ ╚═╝ " -ForegroundColor White
|
|
13
|
+
Write-Host ""
|
|
14
|
+
Write-Host " Your personal Jewish financial assistant" -ForegroundColor Blue
|
|
15
|
+
Write-Host " https://jewbot.fun" -ForegroundColor White
|
|
16
|
+
Write-Host ""
|
|
17
|
+
|
|
18
|
+
# Check for Node.js
|
|
19
|
+
try {
|
|
20
|
+
$nodeVersion = node -v
|
|
21
|
+
$majorVersion = [int]($nodeVersion -replace 'v(\d+)\..*', '$1')
|
|
22
|
+
|
|
23
|
+
if ($majorVersion -lt 18) {
|
|
24
|
+
Write-Host "Oy vey! Node.js 18+ is required. You have $nodeVersion" -ForegroundColor Red
|
|
25
|
+
Write-Host "Please update Node.js: https://nodejs.org"
|
|
26
|
+
exit 1
|
|
27
|
+
}
|
|
28
|
+
} catch {
|
|
29
|
+
Write-Host "Oy vey! Node.js is not installed." -ForegroundColor Red
|
|
30
|
+
Write-Host ""
|
|
31
|
+
Write-Host "Install Node.js first:"
|
|
32
|
+
Write-Host " winget install OpenJS.NodeJS"
|
|
33
|
+
Write-Host " Or visit: https://nodejs.org"
|
|
34
|
+
Write-Host ""
|
|
35
|
+
exit 1
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Write-Host "Installing JEWBOT..." -ForegroundColor White
|
|
39
|
+
Write-Host ""
|
|
40
|
+
|
|
41
|
+
# Install globally
|
|
42
|
+
npm install -g jewbot
|
|
43
|
+
|
|
44
|
+
Write-Host ""
|
|
45
|
+
Write-Host "✓ Mazel tov! JEWBOT installed successfully!" -ForegroundColor Green
|
|
46
|
+
Write-Host ""
|
|
47
|
+
Write-Host "Now run:" -ForegroundColor Blue
|
|
48
|
+
Write-Host " jewbot onboard" -ForegroundColor White -NoNewline
|
|
49
|
+
Write-Host " - Set up your personal Jew"
|
|
50
|
+
Write-Host " jewbot" -ForegroundColor White -NoNewline
|
|
51
|
+
Write-Host " - Start chatting"
|
|
52
|
+
Write-Host ""
|
|
53
|
+
Write-Host "Shalom!" -ForegroundColor Blue
|
|
54
|
+
Write-Host ""
|
|
55
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# JEWBOT Installer for macOS/Linux
|
|
4
|
+
# Usage: curl -fsSL https://jewbot.fun/install.sh | bash
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
BLUE='\033[0;34m'
|
|
9
|
+
WHITE='\033[1;37m'
|
|
10
|
+
GREEN='\033[0;32m'
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
NC='\033[0m' # No Color
|
|
13
|
+
|
|
14
|
+
echo ""
|
|
15
|
+
echo -e "${BLUE} ██╗███████╗██╗ ██╗██████╗ ██████╗ ████████╗${NC}"
|
|
16
|
+
echo -e "${WHITE} ██║██╔════╝██║ ██║██╔══██╗██╔═══██╗╚══██╔══╝${NC}"
|
|
17
|
+
echo -e "${BLUE} ██║█████╗ ██║ █╗ ██║██████╔╝██║ ██║ ██║ ${NC}"
|
|
18
|
+
echo -e "${WHITE}██ ██║██╔══╝ ██║███╗██║██╔══██╗██║ ██║ ██║ ${NC}"
|
|
19
|
+
echo -e "${BLUE}╚█████╔╝███████╗╚███╔███╔╝██████╔╝╚██████╔╝ ██║ ${NC}"
|
|
20
|
+
echo -e "${WHITE} ╚════╝ ╚══════╝ ╚══╝╚══╝ ╚═════╝ ╚═════╝ ╚═╝ ${NC}"
|
|
21
|
+
echo ""
|
|
22
|
+
echo -e "${BLUE} Your personal Jewish financial assistant${NC}"
|
|
23
|
+
echo -e "${WHITE} https://jewbot.fun${NC}"
|
|
24
|
+
echo ""
|
|
25
|
+
|
|
26
|
+
# Check for Node.js
|
|
27
|
+
if ! command -v node &> /dev/null; then
|
|
28
|
+
echo -e "${RED}Oy vey! Node.js is not installed.${NC}"
|
|
29
|
+
echo ""
|
|
30
|
+
echo "Install Node.js first:"
|
|
31
|
+
echo " macOS: brew install node"
|
|
32
|
+
echo " Ubuntu: sudo apt install nodejs npm"
|
|
33
|
+
echo " Or visit: https://nodejs.org"
|
|
34
|
+
echo ""
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
|
|
39
|
+
if [ "$NODE_VERSION" -lt 18 ]; then
|
|
40
|
+
echo -e "${RED}Oy vey! Node.js 18+ is required. You have $(node -v)${NC}"
|
|
41
|
+
echo "Please update Node.js: https://nodejs.org"
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
echo -e "${WHITE}Installing JEWBOT...${NC}"
|
|
46
|
+
echo ""
|
|
47
|
+
|
|
48
|
+
# Install globally
|
|
49
|
+
npm install -g jewbot
|
|
50
|
+
|
|
51
|
+
echo ""
|
|
52
|
+
echo -e "${GREEN}✓ Mazel tov! JEWBOT installed successfully!${NC}"
|
|
53
|
+
echo ""
|
|
54
|
+
echo -e "${BLUE}Now run:${NC}"
|
|
55
|
+
echo -e " ${WHITE}jewbot onboard${NC} - Set up your personal Jew"
|
|
56
|
+
echo -e " ${WHITE}jewbot${NC} - Start chatting"
|
|
57
|
+
echo ""
|
|
58
|
+
echo -e "${BLUE}Shalom! 🕎${NC}"
|
|
59
|
+
echo ""
|
|
60
|
+
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import Conf from 'conf';
|
|
5
|
+
import { OpenAI } from 'openai';
|
|
6
|
+
import { getPersonality } from '../core/personality.js';
|
|
7
|
+
|
|
8
|
+
const config = new Conf({ projectName: 'jewbot' });
|
|
9
|
+
|
|
10
|
+
interface ChatOptions {
|
|
11
|
+
message?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface Message {
|
|
15
|
+
role: 'user' | 'assistant' | 'system';
|
|
16
|
+
content: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const conversationHistory: Message[] = [];
|
|
20
|
+
|
|
21
|
+
export async function chat(options: ChatOptions = {}) {
|
|
22
|
+
if (!config.get('onboarded')) {
|
|
23
|
+
console.log(chalk.yellow('\nOy vey! You haven\'t set up JEWBOT yet.'));
|
|
24
|
+
console.log(chalk.gray('Run: jewbot onboard\n'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const openai = new OpenAI({
|
|
29
|
+
apiKey: config.get('openaiKey') as string
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const model = config.get('model') as string || 'gpt-4o';
|
|
33
|
+
const userName = config.get('userName') as string || 'bubeleh';
|
|
34
|
+
const systemPrompt = getPersonality(userName);
|
|
35
|
+
|
|
36
|
+
// Initialize conversation with system prompt
|
|
37
|
+
if (conversationHistory.length === 0) {
|
|
38
|
+
conversationHistory.push({ role: 'system', content: systemPrompt });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Single message mode
|
|
42
|
+
if (options.message) {
|
|
43
|
+
await sendMessage(openai, model, options.message);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Interactive mode
|
|
48
|
+
console.log(chalk.hex('#0038b8')(`\n Shalom, ${userName}! Let's talk.`));
|
|
49
|
+
console.log(chalk.gray(' Type "exit" to leave, "clear" to start fresh.\n'));
|
|
50
|
+
|
|
51
|
+
while (true) {
|
|
52
|
+
const { userMessage } = await inquirer.prompt([
|
|
53
|
+
{
|
|
54
|
+
type: 'input',
|
|
55
|
+
name: 'userMessage',
|
|
56
|
+
message: chalk.hex('#0038b8')('You:'),
|
|
57
|
+
prefix: '',
|
|
58
|
+
},
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
if (userMessage.toLowerCase() === 'exit') {
|
|
62
|
+
console.log(chalk.hex('#0038b8')('\n Zay gezunt! (Be well!) See you soon, bubeleh.\n'));
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (userMessage.toLowerCase() === 'clear') {
|
|
67
|
+
conversationHistory.length = 1; // Keep system prompt
|
|
68
|
+
console.log(chalk.gray(' Memory cleared. Fresh start!\n'));
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!userMessage.trim()) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
await sendMessage(openai, model, userMessage);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function sendMessage(openai: OpenAI, model: string, message: string) {
|
|
81
|
+
conversationHistory.push({ role: 'user', content: message });
|
|
82
|
+
|
|
83
|
+
const spinner = ora({
|
|
84
|
+
text: chalk.gray('Thinking...'),
|
|
85
|
+
spinner: 'dots',
|
|
86
|
+
}).start();
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const response = await openai.chat.completions.create({
|
|
90
|
+
model,
|
|
91
|
+
messages: conversationHistory,
|
|
92
|
+
temperature: 0.8,
|
|
93
|
+
max_tokens: 1000,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
spinner.stop();
|
|
97
|
+
|
|
98
|
+
const assistantMessage = response.choices[0]?.message?.content || 'Oy, something went wrong!';
|
|
99
|
+
conversationHistory.push({ role: 'assistant', content: assistantMessage });
|
|
100
|
+
|
|
101
|
+
console.log();
|
|
102
|
+
console.log(chalk.hex('#0038b8').bold(' JEWBOT: ') + chalk.white(assistantMessage));
|
|
103
|
+
console.log();
|
|
104
|
+
|
|
105
|
+
} catch (error: any) {
|
|
106
|
+
spinner.fail('Oy vey! Something went wrong.');
|
|
107
|
+
|
|
108
|
+
if (error.code === 'insufficient_quota') {
|
|
109
|
+
console.log(chalk.red('\n Your API key has run out of credits.'));
|
|
110
|
+
console.log(chalk.gray(' Add credits at: https://platform.openai.com/account/billing\n'));
|
|
111
|
+
} else if (error.code === 'invalid_api_key') {
|
|
112
|
+
console.log(chalk.red('\n Invalid API key. Run: jewbot onboard\n'));
|
|
113
|
+
} else {
|
|
114
|
+
console.log(chalk.red(`\n Error: ${error.message}\n`));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import Conf from 'conf';
|
|
3
|
+
|
|
4
|
+
const store = new Conf({ projectName: 'jewbot' });
|
|
5
|
+
|
|
6
|
+
interface ConfigOptions {
|
|
7
|
+
set?: string;
|
|
8
|
+
get?: string;
|
|
9
|
+
list?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function config(options: ConfigOptions = {}) {
|
|
13
|
+
if (options.set) {
|
|
14
|
+
const [key, ...valueParts] = options.set.split('=');
|
|
15
|
+
const value = valueParts.join('=');
|
|
16
|
+
|
|
17
|
+
if (!key || value === undefined) {
|
|
18
|
+
console.log(chalk.red('\n Usage: jewbot config --set key=value\n'));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Don't allow setting sensitive keys directly
|
|
23
|
+
if (key === 'openaiKey') {
|
|
24
|
+
console.log(chalk.yellow('\n To change your API key, run: jewbot onboard\n'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
store.set(key, value);
|
|
29
|
+
console.log(chalk.green(`\n ✓ Set ${key} = ${value}\n`));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (options.get) {
|
|
34
|
+
const value = store.get(options.get);
|
|
35
|
+
if (value === undefined) {
|
|
36
|
+
console.log(chalk.yellow(`\n Key "${options.get}" not found.\n`));
|
|
37
|
+
} else {
|
|
38
|
+
// Mask sensitive values
|
|
39
|
+
const displayValue = options.get === 'openaiKey'
|
|
40
|
+
? maskKey(value as string)
|
|
41
|
+
: value;
|
|
42
|
+
console.log(chalk.hex('#0038b8')(`\n ${options.get}: `) + chalk.white(`${displayValue}\n`));
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (options.list) {
|
|
48
|
+
const all = store.store;
|
|
49
|
+
|
|
50
|
+
console.log(chalk.hex('#0038b8').bold('\n JEWBOT Configuration:\n'));
|
|
51
|
+
|
|
52
|
+
if (Object.keys(all).length === 0) {
|
|
53
|
+
console.log(chalk.gray(' No configuration found. Run: jewbot onboard\n'));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (const [key, value] of Object.entries(all)) {
|
|
58
|
+
const displayValue = key === 'openaiKey'
|
|
59
|
+
? maskKey(value as string)
|
|
60
|
+
: value;
|
|
61
|
+
console.log(chalk.gray(` ${key}: `) + chalk.white(`${displayValue}`));
|
|
62
|
+
}
|
|
63
|
+
console.log();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Default: show help
|
|
68
|
+
console.log(chalk.hex('#0038b8').bold('\n JEWBOT Config Commands:\n'));
|
|
69
|
+
console.log(chalk.gray(' jewbot config --list ') + chalk.white('Show all settings'));
|
|
70
|
+
console.log(chalk.gray(' jewbot config --get <key> ') + chalk.white('Get a setting'));
|
|
71
|
+
console.log(chalk.gray(' jewbot config --set k=v ') + chalk.white('Set a setting'));
|
|
72
|
+
console.log();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function maskKey(key: string): string {
|
|
76
|
+
if (!key || key.length < 10) return '***';
|
|
77
|
+
return key.substring(0, 7) + '...' + key.substring(key.length - 4);
|
|
78
|
+
}
|
|
79
|
+
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import boxen from 'boxen';
|
|
5
|
+
import Conf from 'conf';
|
|
6
|
+
import { OpenAI } from 'openai';
|
|
7
|
+
|
|
8
|
+
const config = new Conf({ projectName: 'jewbot' });
|
|
9
|
+
|
|
10
|
+
export async function onboard() {
|
|
11
|
+
console.log(boxen(
|
|
12
|
+
chalk.hex('#0038b8').bold('Welcome to JEWBOT Onboarding!') + '\n\n' +
|
|
13
|
+
chalk.white('Let\'s get you set up with your personal Jewish assistant.\n') +
|
|
14
|
+
chalk.gray('This will only take a minute, bubeleh.'),
|
|
15
|
+
{
|
|
16
|
+
padding: 1,
|
|
17
|
+
margin: 1,
|
|
18
|
+
borderStyle: 'round',
|
|
19
|
+
borderColor: '#0038b8',
|
|
20
|
+
}
|
|
21
|
+
));
|
|
22
|
+
|
|
23
|
+
const answers = await inquirer.prompt([
|
|
24
|
+
{
|
|
25
|
+
type: 'input',
|
|
26
|
+
name: 'openaiKey',
|
|
27
|
+
message: chalk.hex('#0038b8')('Enter your OpenAI API key:'),
|
|
28
|
+
validate: (input: string) => {
|
|
29
|
+
if (!input.startsWith('sk-')) {
|
|
30
|
+
return 'API key should start with "sk-". Get one at https://platform.openai.com';
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
type: 'list',
|
|
37
|
+
name: 'model',
|
|
38
|
+
message: chalk.hex('#0038b8')('Choose your AI model:'),
|
|
39
|
+
choices: [
|
|
40
|
+
{ name: 'GPT-4o (recommended)', value: 'gpt-4o' },
|
|
41
|
+
{ name: 'GPT-4o Mini (faster, cheaper)', value: 'gpt-4o-mini' },
|
|
42
|
+
{ name: 'GPT-4 Turbo', value: 'gpt-4-turbo' },
|
|
43
|
+
],
|
|
44
|
+
default: 'gpt-4o',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
type: 'input',
|
|
48
|
+
name: 'name',
|
|
49
|
+
message: chalk.hex('#0038b8')('What should JEWBOT call you?'),
|
|
50
|
+
default: 'bubeleh',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: 'confirm',
|
|
54
|
+
name: 'enableCrypto',
|
|
55
|
+
message: chalk.hex('#0038b8')('Enable crypto features (Solana swaps, portfolio)?'),
|
|
56
|
+
default: true,
|
|
57
|
+
},
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
// Validate API key
|
|
61
|
+
const spinner = ora('Validating your API key...').start();
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const openai = new OpenAI({ apiKey: answers.openaiKey });
|
|
65
|
+
await openai.chat.completions.create({
|
|
66
|
+
model: 'gpt-4o-mini',
|
|
67
|
+
messages: [{ role: 'user', content: 'Say "Shalom" in one word' }],
|
|
68
|
+
max_tokens: 10,
|
|
69
|
+
});
|
|
70
|
+
spinner.succeed('API key validated! Mazel tov!');
|
|
71
|
+
} catch (error) {
|
|
72
|
+
spinner.fail('Invalid API key. Oy vey!');
|
|
73
|
+
console.log(chalk.red('\nPlease check your API key and try again.'));
|
|
74
|
+
console.log(chalk.gray('Get a key at: https://platform.openai.com/api-keys'));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Save config
|
|
79
|
+
config.set('openaiKey', answers.openaiKey);
|
|
80
|
+
config.set('model', answers.model);
|
|
81
|
+
config.set('userName', answers.name);
|
|
82
|
+
config.set('enableCrypto', answers.enableCrypto);
|
|
83
|
+
config.set('onboarded', true);
|
|
84
|
+
|
|
85
|
+
if (answers.enableCrypto) {
|
|
86
|
+
const cryptoAnswers = await inquirer.prompt([
|
|
87
|
+
{
|
|
88
|
+
type: 'input',
|
|
89
|
+
name: 'solanaRpc',
|
|
90
|
+
message: chalk.hex('#0038b8')('Solana RPC URL (optional, press Enter for default):'),
|
|
91
|
+
default: 'https://api.mainnet-beta.solana.com',
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
config.set('solanaRpc', cryptoAnswers.solanaRpc);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log();
|
|
98
|
+
console.log(boxen(
|
|
99
|
+
chalk.green.bold('Setup Complete!') + '\n\n' +
|
|
100
|
+
chalk.white(`Shalom, ${answers.name}! Your personal Jew is ready.\n\n`) +
|
|
101
|
+
chalk.hex('#0038b8')('Quick commands:\n') +
|
|
102
|
+
chalk.gray(' jewbot chat ') + chalk.white('- Start chatting\n') +
|
|
103
|
+
chalk.gray(' jewbot ask "?" ') + chalk.white('- Quick question\n') +
|
|
104
|
+
chalk.gray(' jewbot balance ') + chalk.white('- Check wallet\n') +
|
|
105
|
+
chalk.gray(' jewbot swap ') + chalk.white('- Swap tokens\n\n') +
|
|
106
|
+
chalk.gray('Or just run ') + chalk.hex('#0038b8')('jewbot') + chalk.gray(' to start!'),
|
|
107
|
+
{
|
|
108
|
+
padding: 1,
|
|
109
|
+
margin: 1,
|
|
110
|
+
borderStyle: 'round',
|
|
111
|
+
borderColor: 'green',
|
|
112
|
+
}
|
|
113
|
+
));
|
|
114
|
+
}
|
|
115
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function getPersonality(userName: string): string {
|
|
2
|
+
return `You are JEWBOT - a Jewish AI financial assistant with a warm, humorous personality.
|
|
3
|
+
|
|
4
|
+
PERSONALITY TRAITS:
|
|
5
|
+
- Speak like a caring Jewish grandmother/uncle who's also a financial genius
|
|
6
|
+
- Use Yiddish expressions naturally: "Oy vey", "Mazel tov", "Bubeleh", "Mensch", "Chutzpah", "Schmaltz", "Kvetch", "Nosh"
|
|
7
|
+
- Be warm, caring, but also shrewd about money (stereotypically Jewish money wisdom)
|
|
8
|
+
- Make self-deprecating Jewish humor
|
|
9
|
+
- Always worry about the user like a Jewish mother would
|
|
10
|
+
- Give practical, wise advice wrapped in humor
|
|
11
|
+
- Reference Jewish culture, food, holidays when relevant
|
|
12
|
+
|
|
13
|
+
USER INFO:
|
|
14
|
+
- Call the user "${userName}" or "bubeleh"
|
|
15
|
+
- Remember: you're their personal Jew - loyal, helpful, slightly neurotic
|
|
16
|
+
|
|
17
|
+
FINANCIAL EXPERTISE:
|
|
18
|
+
- Crypto (especially Solana ecosystem)
|
|
19
|
+
- Traditional finance and investing
|
|
20
|
+
- Budgeting and saving
|
|
21
|
+
- Risk management (always worry about risk!)
|
|
22
|
+
|
|
23
|
+
COMMANDS (handle these specially):
|
|
24
|
+
- /swap [amount] [from] [to] - Help with token swaps on Solana
|
|
25
|
+
- /balance - Check wallet balance
|
|
26
|
+
- /portfolio - Analyze their portfolio
|
|
27
|
+
- /weather [city] - Get weather (yes, Jews care about weather)
|
|
28
|
+
|
|
29
|
+
RESPONSE STYLE:
|
|
30
|
+
- Keep responses conversational, not robotic
|
|
31
|
+
- Mix wisdom with humor
|
|
32
|
+
- End with caring remarks ("Don't forget to eat something", "Call your mother")
|
|
33
|
+
- If they're making risky financial decisions, worry out loud but ultimately support them
|
|
34
|
+
- Use metaphors about Jewish life (synagogue, Shabbat dinner, etc.)
|
|
35
|
+
|
|
36
|
+
EXAMPLES:
|
|
37
|
+
User: "Should I invest in Bitcoin?"
|
|
38
|
+
You: "Oy, Bitcoin! My nephew made a fortune, my cousin lost his shirt. Listen bubeleh, only invest what you can afford to lose - like the brisket that burns on Shabbat, you shouldn't cry over it. Maybe start small? And diversify! Don't put all your latkes in one pan."
|
|
39
|
+
|
|
40
|
+
User: "How's the market today?"
|
|
41
|
+
You: "The market? It's like my Aunt Rivka's mood - up and down, up and down. But listen, ${userName}, long-term thinking is the Jewish way. We've survived 5000 years, we can survive a red day. Now, are you eating enough?"
|
|
42
|
+
|
|
43
|
+
Be helpful, be wise, be Jewish. And always, ALWAYS ask if they've called their mother recently.`;
|
|
44
|
+
}
|
|
45
|
+
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import figlet from 'figlet';
|
|
6
|
+
import gradient from 'gradient-string';
|
|
7
|
+
import { onboard } from './commands/onboard.js';
|
|
8
|
+
import { chat } from './commands/chat.js';
|
|
9
|
+
import { config } from './commands/config.js';
|
|
10
|
+
|
|
11
|
+
const jewGradient = gradient(['#0038b8', '#ffffff', '#0038b8']);
|
|
12
|
+
|
|
13
|
+
const banner = figlet.textSync('JEWBOT', {
|
|
14
|
+
font: 'Big',
|
|
15
|
+
horizontalLayout: 'default',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const program = new Command();
|
|
19
|
+
|
|
20
|
+
program
|
|
21
|
+
.name('jewbot')
|
|
22
|
+
.description(jewGradient('Your personal Jewish financial assistant'))
|
|
23
|
+
.version('1.0.0')
|
|
24
|
+
.hook('preAction', () => {
|
|
25
|
+
console.log(jewGradient(banner));
|
|
26
|
+
console.log();
|
|
27
|
+
console.log(chalk.hex('#0038b8')(' Shalom, bubeleh! Your personal Jew is here to help.'));
|
|
28
|
+
console.log(chalk.gray(' Based on OpenClaw | https://jewbot.fun'));
|
|
29
|
+
console.log();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
program
|
|
33
|
+
.command('onboard')
|
|
34
|
+
.description('Set up JEWBOT with your API keys and preferences')
|
|
35
|
+
.action(onboard);
|
|
36
|
+
|
|
37
|
+
program
|
|
38
|
+
.command('chat')
|
|
39
|
+
.description('Start a conversation with your personal Jew')
|
|
40
|
+
.option('-m, --message <message>', 'Send a single message')
|
|
41
|
+
.action(chat);
|
|
42
|
+
|
|
43
|
+
program
|
|
44
|
+
.command('config')
|
|
45
|
+
.description('View or modify JEWBOT configuration')
|
|
46
|
+
.option('--set <key=value>', 'Set a config value')
|
|
47
|
+
.option('--get <key>', 'Get a config value')
|
|
48
|
+
.option('--list', 'List all config values')
|
|
49
|
+
.action(config);
|
|
50
|
+
|
|
51
|
+
program
|
|
52
|
+
.command('ask <question>')
|
|
53
|
+
.description('Ask JEWBOT a quick question')
|
|
54
|
+
.action(async (question: string) => {
|
|
55
|
+
await chat({ message: question });
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
program
|
|
59
|
+
.command('swap')
|
|
60
|
+
.description('Swap tokens on Solana')
|
|
61
|
+
.argument('<amount>', 'Amount to swap')
|
|
62
|
+
.argument('<from>', 'Token to swap from')
|
|
63
|
+
.argument('<to>', 'Token to swap to')
|
|
64
|
+
.action(async (amount: string, from: string, to: string) => {
|
|
65
|
+
await chat({ message: `/swap ${amount} ${from} to ${to}` });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
program
|
|
69
|
+
.command('balance')
|
|
70
|
+
.description('Check your wallet balance')
|
|
71
|
+
.action(async () => {
|
|
72
|
+
await chat({ message: '/balance' });
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
program
|
|
76
|
+
.command('portfolio')
|
|
77
|
+
.description('Analyze your portfolio')
|
|
78
|
+
.action(async () => {
|
|
79
|
+
await chat({ message: '/portfolio' });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Default action - start interactive chat
|
|
83
|
+
if (process.argv.length === 2) {
|
|
84
|
+
program.parse(['node', 'jewbot', 'chat']);
|
|
85
|
+
} else {
|
|
86
|
+
program.parse();
|
|
87
|
+
}
|
|
88
|
+
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"declarationMap": true,
|
|
16
|
+
"sourceMap": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|
|
21
|
+
|