@kernel.chat/kbot 3.72.0 → 3.73.1
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 +69 -3
- package/dist/buddy.d.ts +21 -0
- package/dist/buddy.js +97 -1
- package/dist/cli.js +57 -1
- package/dist/tools/buddy-tools.js +55 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
<strong>kbot</strong><br>
|
|
5
|
-
Open-source terminal AI agent.
|
|
5
|
+
Open-source terminal AI agent. 764+ tools. 35 agents. 20 providers. Dreams, learns, watches your system, controls your phone. $0 local.
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
8
|
<p align="center">
|
|
@@ -30,7 +30,7 @@ Most terminal AI agents lock you into one provider, one model, one way of workin
|
|
|
30
30
|
- **Runs fully offline** — Embedded llama.cpp, Ollama, LM Studio, or Jan. $0, fully private.
|
|
31
31
|
- **Learns your patterns** — Bayesian skill ratings + pattern extraction. Gets faster over time.
|
|
32
32
|
- **35 specialist agents** — auto-routes your request to the right expert (coder, researcher, writer, guardian, quant, and 30 more).
|
|
33
|
-
- **
|
|
33
|
+
- **764+ tools** — files, bash, git, GitHub, web search, deploy, database, game dev, VFX, research, science, finance, security, music production, iPhone control, and more.
|
|
34
34
|
- **Programmatic SDK** — use kbot as a library in your own apps.
|
|
35
35
|
- **MCP server built in** — plug kbot into Claude Code, Cursor, VS Code, Zed, or Neovim as a tool provider.
|
|
36
36
|
|
|
@@ -65,6 +65,66 @@ kbot dream status # What kbot learned about you
|
|
|
65
65
|
- **Companion memory** — email agent remembers every user's preferences, goals, and conversation history
|
|
66
66
|
- **Proactive follow-ups** — checks in with users who go quiet, referencing their specific context
|
|
67
67
|
|
|
68
|
+
### Your Buddy — Terminal Companion
|
|
69
|
+
|
|
70
|
+
Every kbot user gets a unique ASCII buddy that evolves with them:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
[=====] /\ /\ {o,o} /\_/\
|
|
74
|
+
|[o o]| ( .. ) |)__) ( o.o )
|
|
75
|
+
| _ | ) ( -"-"- > ^ <
|
|
76
|
+
|_____| (______)\ -|-|- (_/|\_)
|
|
77
|
+
|| || || || _// \\_ | |
|
|
78
|
+
Robot Fox Owl Cat
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- **8 species** — deterministic based on your machine. Same user = same buddy always.
|
|
82
|
+
- **4 evolution levels** — levels up with XP from sessions, dreams, tool usage
|
|
83
|
+
- **18 achievements** — First Dream, Centurion, Tool Master, Night Owl, and more
|
|
84
|
+
- **Dream narration** — buddy tells you what it dreamed on startup
|
|
85
|
+
- **Chat mode** — `kbot buddy chat` to talk directly to your buddy via local Ollama ($0)
|
|
86
|
+
- **Leaderboard** — [kernel.chat/#/leaderboard](https://kernel.chat/#/leaderboard)
|
|
87
|
+
|
|
88
|
+
### iPhone Control
|
|
89
|
+
|
|
90
|
+
Control your iPhone from the terminal:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
kbot phone_message --to "mom" --message "on my way" # Send iMessage
|
|
94
|
+
kbot phone_notify # Read notifications
|
|
95
|
+
kbot phone_shortcut --name "Morning Routine" # Run Shortcuts
|
|
96
|
+
kbot phone_call --number "555-1234" # FaceTime call
|
|
97
|
+
kbot phone_clipboard --action write --text "hello" # Universal Clipboard
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Music Production — Ableton Live Integration
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
kbot produce_beat --genre trap --instruments roland # Full beat in Ableton
|
|
104
|
+
kbot generate_drum_pattern --genre house --bpm 124 # MIDI drum pattern
|
|
105
|
+
kbot music_idea "late night drive through Tokyo" # Creative blueprint
|
|
106
|
+
kbot ableton_load_effect --track 2 --name "Saturator" # Load any plugin
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Programmatic control of Ableton Live 12 — create tracks, load plugins (including Roland Cloud, Serum 2), write MIDI, set device parameters, fire clips. All from the terminal.
|
|
110
|
+
|
|
111
|
+
### Financial Analysis
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
kbot market_analysis --ticker AAPL # 5-perspective coordinated analysis
|
|
115
|
+
kbot portfolio_review --holdings '[...]' # MAGI impact, risk scoring
|
|
116
|
+
kbot market_briefing # Morning market summary
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Cyber Threat Intelligence
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
kbot threat_feed # Latest CVEs matched to your stack
|
|
123
|
+
kbot ioc_check --indicator "1.2.3.4" # Check IPs/domains/hashes
|
|
124
|
+
kbot attack_surface_scan --domain x.com # Passive recon + security headers
|
|
125
|
+
kbot incident_response --type ransomware # Generate IR playbook
|
|
126
|
+
```
|
|
127
|
+
|
|
68
128
|
### Audit Any Repo in One Command
|
|
69
129
|
|
|
70
130
|
```
|
|
@@ -81,12 +141,18 @@ Checks security, documentation, code quality, CI/CD, community health, and DevOp
|
|
|
81
141
|
|---|---|---|---|---|---|
|
|
82
142
|
| AI providers | 20 | 1 | 1 | 6 | 75+ |
|
|
83
143
|
| Specialist agents | 35 | 0 | 0 | 0 | 0 |
|
|
84
|
-
| Built-in tools |
|
|
144
|
+
| Built-in tools | 764+ | ~20 | ~15 | ~10 | ~15 |
|
|
85
145
|
| Science tools | 114 | 0 | 0 | 0 | 0 |
|
|
86
146
|
| Memory system | 7-tier bidirectional | File-based | No | No | No |
|
|
87
147
|
| Dream engine | Yes ($0 local) | Cloud API | No | No | No |
|
|
88
148
|
| Service watchdog | Yes | No | No | No | No |
|
|
89
149
|
| Behavior learning | Yes | No | No | No | No |
|
|
150
|
+
| Buddy companion | Yes (8 species) | No | No | No | No |
|
|
151
|
+
| iPhone control | Yes | No | No | No | No |
|
|
152
|
+
| Music production | Ableton Live | No | No | No | No |
|
|
153
|
+
| Financial analysis | Multi-agent | No | No | No | No |
|
|
154
|
+
| Threat intelligence | Yes | No | No | No | No |
|
|
155
|
+
| Buddy leaderboard | kernel.chat | No | No | No | No |
|
|
90
156
|
| Offline mode | Embedded + Ollama | No | No | Ollama | Ollama |
|
|
91
157
|
| SDK | Yes | No | Yes | No | No |
|
|
92
158
|
| MCP server | Yes | N/A | No | No | No |
|
package/dist/buddy.d.ts
CHANGED
|
@@ -74,6 +74,27 @@ export declare function addBuddyXP(amount: number): {
|
|
|
74
74
|
levelInfo: BuddyLevelInfo;
|
|
75
75
|
leveledUp: boolean;
|
|
76
76
|
};
|
|
77
|
+
/**
|
|
78
|
+
* Sync buddy stats to the cloud leaderboard.
|
|
79
|
+
* Anonymous — uses a SHA-256 hash of hostname+homedir, not user identity.
|
|
80
|
+
* Requires a kernel.chat token (cloud sync enabled).
|
|
81
|
+
*/
|
|
82
|
+
export declare function syncBuddyToCloud(): Promise<boolean>;
|
|
83
|
+
/**
|
|
84
|
+
* Fetch the buddy leaderboard from the cloud.
|
|
85
|
+
* Returns ranked entries sorted by XP descending.
|
|
86
|
+
*/
|
|
87
|
+
export declare function fetchBuddyLeaderboard(opts?: {
|
|
88
|
+
limit?: number;
|
|
89
|
+
species?: string;
|
|
90
|
+
}): Promise<Array<{
|
|
91
|
+
species: string;
|
|
92
|
+
level: number;
|
|
93
|
+
xp: number;
|
|
94
|
+
achievement_count: number;
|
|
95
|
+
sessions: number;
|
|
96
|
+
rank: number;
|
|
97
|
+
}>>;
|
|
77
98
|
/**
|
|
78
99
|
* Get the buddy's current level info without modifying state.
|
|
79
100
|
* Includes level, XP, XP to next level, and species-specific title.
|
package/dist/buddy.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// Achievements: milestones that unlock as the user uses kbot. Persisted in buddy.json.
|
|
8
8
|
//
|
|
9
9
|
// Persists buddy name + achievements to ~/.kbot/buddy.json
|
|
10
|
-
import { homedir } from 'node:os';
|
|
10
|
+
import { homedir, hostname } from 'node:os';
|
|
11
11
|
import { join } from 'node:path';
|
|
12
12
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
13
13
|
import { createHash } from 'node:crypto';
|
|
@@ -15,6 +15,7 @@ import { createInterface } from 'node:readline';
|
|
|
15
15
|
import { getDreamStatus, getDreamPrompt } from './dream.js';
|
|
16
16
|
import { getExtendedStats, getProfileSummary } from './learning.js';
|
|
17
17
|
import { getToolMetrics } from './tools/index.js';
|
|
18
|
+
import { getCloudToken } from './cloud-sync.js';
|
|
18
19
|
// ── Paths ──
|
|
19
20
|
const KBOT_DIR = join(homedir(), '.kbot');
|
|
20
21
|
const BUDDY_FILE = join(KBOT_DIR, 'buddy.json');
|
|
@@ -930,6 +931,8 @@ export function addBuddyXP(amount) {
|
|
|
930
931
|
config.evolution = evo;
|
|
931
932
|
saveBuddyConfig(config);
|
|
932
933
|
cachedEvolution = evo;
|
|
934
|
+
// Debounced cloud sync — leaderboard update
|
|
935
|
+
scheduleBuddySync();
|
|
933
936
|
const species = resolveSpecies();
|
|
934
937
|
const nextLevel = (newLevel < 3 ? (newLevel + 1) : null);
|
|
935
938
|
const xpToNext = nextLevel !== null ? LEVEL_THRESHOLDS[nextLevel] - evo.xp : null;
|
|
@@ -943,6 +946,99 @@ export function addBuddyXP(amount) {
|
|
|
943
946
|
leveledUp,
|
|
944
947
|
};
|
|
945
948
|
}
|
|
949
|
+
// ── Cloud Sync — Buddy Leaderboard ──
|
|
950
|
+
const ENGINE_URL = 'https://eoxxpyixdieprsxlpwcs.supabase.co/functions/v1/kbot-engine';
|
|
951
|
+
const BUDDY_SYNC_DEBOUNCE_MS = 5 * 60 * 1000; // max once per 5 minutes
|
|
952
|
+
let buddySyncTimer = null;
|
|
953
|
+
let lastBuddySync = 0;
|
|
954
|
+
/** Generate an anonymous device hash from hostname + homedir */
|
|
955
|
+
function getDeviceHash() {
|
|
956
|
+
return createHash('sha256')
|
|
957
|
+
.update(`${hostname()}:${homedir()}`)
|
|
958
|
+
.digest('hex');
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Sync buddy stats to the cloud leaderboard.
|
|
962
|
+
* Anonymous — uses a SHA-256 hash of hostname+homedir, not user identity.
|
|
963
|
+
* Requires a kernel.chat token (cloud sync enabled).
|
|
964
|
+
*/
|
|
965
|
+
export async function syncBuddyToCloud() {
|
|
966
|
+
const token = getCloudToken();
|
|
967
|
+
if (!token)
|
|
968
|
+
return false;
|
|
969
|
+
try {
|
|
970
|
+
const buddy = getBuddy();
|
|
971
|
+
const lvl = getBuddyLevel();
|
|
972
|
+
const achievements = getAchievements();
|
|
973
|
+
const stats = getExtendedStats();
|
|
974
|
+
const unlockedCount = achievements.filter(a => a.unlockedAt !== null).length;
|
|
975
|
+
const res = await fetch(`${ENGINE_URL}/sync`, {
|
|
976
|
+
method: 'POST',
|
|
977
|
+
headers: {
|
|
978
|
+
'Content-Type': 'application/json',
|
|
979
|
+
'Authorization': `Bearer ${token}`,
|
|
980
|
+
},
|
|
981
|
+
body: JSON.stringify({
|
|
982
|
+
action: 'buddy_sync',
|
|
983
|
+
device_hash: getDeviceHash(),
|
|
984
|
+
species: buddy.species,
|
|
985
|
+
level: lvl.level,
|
|
986
|
+
xp: lvl.xp,
|
|
987
|
+
achievement_count: unlockedCount,
|
|
988
|
+
sessions: stats.sessions,
|
|
989
|
+
}),
|
|
990
|
+
signal: AbortSignal.timeout(10_000),
|
|
991
|
+
});
|
|
992
|
+
return res.ok;
|
|
993
|
+
}
|
|
994
|
+
catch {
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
/** Debounced buddy sync — called from addBuddyXP, max once per 5 minutes */
|
|
999
|
+
function scheduleBuddySync() {
|
|
1000
|
+
const now = Date.now();
|
|
1001
|
+
if (now - lastBuddySync < BUDDY_SYNC_DEBOUNCE_MS)
|
|
1002
|
+
return;
|
|
1003
|
+
if (buddySyncTimer)
|
|
1004
|
+
return;
|
|
1005
|
+
buddySyncTimer = setTimeout(() => {
|
|
1006
|
+
buddySyncTimer = null;
|
|
1007
|
+
lastBuddySync = Date.now();
|
|
1008
|
+
syncBuddyToCloud().catch(() => { }); // fire and forget
|
|
1009
|
+
}, 1000); // short delay to batch rapid XP gains
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Fetch the buddy leaderboard from the cloud.
|
|
1013
|
+
* Returns ranked entries sorted by XP descending.
|
|
1014
|
+
*/
|
|
1015
|
+
export async function fetchBuddyLeaderboard(opts) {
|
|
1016
|
+
const token = getCloudToken();
|
|
1017
|
+
if (!token)
|
|
1018
|
+
return [];
|
|
1019
|
+
try {
|
|
1020
|
+
const res = await fetch(`${ENGINE_URL}/sync`, {
|
|
1021
|
+
method: 'POST',
|
|
1022
|
+
headers: {
|
|
1023
|
+
'Content-Type': 'application/json',
|
|
1024
|
+
'Authorization': `Bearer ${token}`,
|
|
1025
|
+
},
|
|
1026
|
+
body: JSON.stringify({
|
|
1027
|
+
action: 'buddy_leaderboard',
|
|
1028
|
+
limit: opts?.limit ?? 50,
|
|
1029
|
+
...(opts?.species ? { species: opts.species } : {}),
|
|
1030
|
+
}),
|
|
1031
|
+
signal: AbortSignal.timeout(10_000),
|
|
1032
|
+
});
|
|
1033
|
+
if (!res.ok)
|
|
1034
|
+
return [];
|
|
1035
|
+
const data = await res.json();
|
|
1036
|
+
return data.leaderboard ?? [];
|
|
1037
|
+
}
|
|
1038
|
+
catch {
|
|
1039
|
+
return [];
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
946
1042
|
/**
|
|
947
1043
|
* Get the buddy's current level info without modifying state.
|
|
948
1044
|
* Includes level, XP, XP to next level, and species-specific title.
|
package/dist/cli.js
CHANGED
|
@@ -27,7 +27,7 @@ import { banner, bannerCompact, bannerAuth, prompt as kbotPrompt, printError, pr
|
|
|
27
27
|
import { checkForUpdate, selfUpdate } from './updater.js';
|
|
28
28
|
import { runTutorial } from './tutorial.js';
|
|
29
29
|
import { syncOnStartup, schedulePush, flushCloudSync, isCloudSyncEnabled, setCloudToken, getCloudToken } from './cloud-sync.js';
|
|
30
|
-
import { getBuddy, getBuddyGreeting, formatBuddyStatus, getBuddyDreamNarration, renameBuddy, buddyChat, getAchievements, getBuddyLevel } from './buddy.js';
|
|
30
|
+
import { getBuddy, getBuddyGreeting, formatBuddyStatus, getBuddyDreamNarration, renameBuddy, buddyChat, getAchievements, getBuddyLevel, fetchBuddyLeaderboard } from './buddy.js';
|
|
31
31
|
import chalk from 'chalk';
|
|
32
32
|
import { createRequire } from 'node:module';
|
|
33
33
|
const __require = createRequire(import.meta.url);
|
|
@@ -3579,6 +3579,62 @@ async function main() {
|
|
|
3579
3579
|
console.log();
|
|
3580
3580
|
process.exit(0);
|
|
3581
3581
|
});
|
|
3582
|
+
buddyCmd
|
|
3583
|
+
.command('leaderboard')
|
|
3584
|
+
.description('Show the global buddy leaderboard — anonymous rankings across all kbot installs')
|
|
3585
|
+
.option('-l, --limit <n>', 'Number of entries to show', '20')
|
|
3586
|
+
.option('-s, --species <species>', 'Filter by species (fox, owl, cat, robot, ghost, mushroom, octopus, dragon)')
|
|
3587
|
+
.action(async (opts) => {
|
|
3588
|
+
const limit = Math.min(Math.max(parseInt(opts.limit, 10) || 20, 1), 200);
|
|
3589
|
+
const species = opts.species?.toLowerCase();
|
|
3590
|
+
const validSpecies = ['fox', 'owl', 'cat', 'robot', 'ghost', 'mushroom', 'octopus', 'dragon'];
|
|
3591
|
+
if (species && !validSpecies.includes(species)) {
|
|
3592
|
+
printError(`Unknown species "${species}". Valid: ${validSpecies.join(', ')}`);
|
|
3593
|
+
process.exit(1);
|
|
3594
|
+
}
|
|
3595
|
+
printInfo('Fetching leaderboard...');
|
|
3596
|
+
const entries = await fetchBuddyLeaderboard({ limit, species });
|
|
3597
|
+
if (entries.length === 0) {
|
|
3598
|
+
console.log();
|
|
3599
|
+
printWarn('No entries on the leaderboard yet.');
|
|
3600
|
+
printInfo('Use kbot to earn XP and enable cloud sync to appear on the leaderboard.');
|
|
3601
|
+
console.log();
|
|
3602
|
+
process.exit(0);
|
|
3603
|
+
}
|
|
3604
|
+
const SPECIES_ICONS = {
|
|
3605
|
+
fox: '[fox]', owl: '[owl]', cat: '[cat]', robot: '[bot]',
|
|
3606
|
+
ghost: '[gho]', mushroom: '[msh]', octopus: '[oct]', dragon: '[drg]',
|
|
3607
|
+
};
|
|
3608
|
+
const LEVEL_TITLES_SHORT = {
|
|
3609
|
+
0: 'Novice', 1: 'Adept', 2: 'Master', 3: 'Legend',
|
|
3610
|
+
};
|
|
3611
|
+
const header = species
|
|
3612
|
+
? `Buddy Leaderboard — ${species}`
|
|
3613
|
+
: 'Global Buddy Leaderboard';
|
|
3614
|
+
console.log();
|
|
3615
|
+
console.log(` ${chalk.bold(header)}`);
|
|
3616
|
+
console.log(` ${chalk.dim('─'.repeat(56))}`);
|
|
3617
|
+
console.log(` ${chalk.dim('#'.padStart(3))} ${chalk.dim('Species'.padEnd(7))} ${chalk.dim('Level'.padEnd(12))} ${chalk.dim('XP'.padStart(6))} ${chalk.dim('Achv'.padStart(4))} ${chalk.dim('Sessions'.padStart(8))}`);
|
|
3618
|
+
console.log(` ${chalk.dim('─'.repeat(56))}`);
|
|
3619
|
+
for (const entry of entries) {
|
|
3620
|
+
const icon = SPECIES_ICONS[entry.species] || entry.species.slice(0, 5);
|
|
3621
|
+
const title = LEVEL_TITLES_SHORT[entry.level] ?? `L${entry.level}`;
|
|
3622
|
+
const levelStr = `${entry.level} ${title}`;
|
|
3623
|
+
const rankStr = String(entry.rank).padStart(3);
|
|
3624
|
+
const xpStr = String(entry.xp).padStart(6);
|
|
3625
|
+
const achvStr = String(entry.achievement_count).padStart(4);
|
|
3626
|
+
const sessStr = String(entry.sessions).padStart(8);
|
|
3627
|
+
// Highlight top 3
|
|
3628
|
+
const rankColor = entry.rank === 1 ? chalk.hex('#FFD700') :
|
|
3629
|
+
entry.rank === 2 ? chalk.hex('#C0C0C0') :
|
|
3630
|
+
entry.rank === 3 ? chalk.hex('#CD7F32') : chalk.white;
|
|
3631
|
+
console.log(` ${rankColor(rankStr)} ${chalk.hex('#A78BFA')(icon.padEnd(7))} ${levelStr.padEnd(12)} ${chalk.hex('#4ADE80')(xpStr)} ${achvStr} ${chalk.dim(sessStr)}`);
|
|
3632
|
+
}
|
|
3633
|
+
console.log();
|
|
3634
|
+
console.log(` ${chalk.dim(`${entries.length} entries shown`)}`);
|
|
3635
|
+
console.log();
|
|
3636
|
+
process.exit(0);
|
|
3637
|
+
});
|
|
3582
3638
|
buddyCmd.action(() => {
|
|
3583
3639
|
buddyCmd.commands.find(c => c.name() === 'status')?.parse(['', '', 'status']);
|
|
3584
3640
|
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// kbot Buddy Tools — Interact with your terminal companion
|
|
2
2
|
//
|
|
3
|
-
//
|
|
3
|
+
// Five tools:
|
|
4
4
|
// buddy_status — Show buddy name, species, mood, and sprite
|
|
5
5
|
// buddy_rename — Give your buddy a custom name (persisted to ~/.kbot/buddy.json)
|
|
6
6
|
// buddy_achievements — Show all achievements with unlock status and progress
|
|
7
7
|
// buddy_personality — Show species personality traits, style, and strength
|
|
8
|
+
// buddy_leaderboard — Global anonymous leaderboard across all kbot installs
|
|
8
9
|
import { registerTool } from './index.js';
|
|
9
|
-
import { getBuddy, getBuddySprite, getBuddyGreeting, getBuddyLevel, formatBuddyStatus, renameBuddy, getAchievements, getAchievementProgress, getSpeciesPersonality, } from '../buddy.js';
|
|
10
|
+
import { getBuddy, getBuddySprite, getBuddyGreeting, getBuddyLevel, formatBuddyStatus, renameBuddy, getAchievements, getAchievementProgress, getSpeciesPersonality, fetchBuddyLeaderboard, } from '../buddy.js';
|
|
10
11
|
const VALID_MOODS = ['idle', 'thinking', 'success', 'error', 'learning', 'alert', 'dance', 'curious', 'proud'];
|
|
11
12
|
export function registerBuddyTools() {
|
|
12
13
|
registerTool({
|
|
@@ -124,5 +125,57 @@ export function registerBuddyTools() {
|
|
|
124
125
|
].join('\n');
|
|
125
126
|
},
|
|
126
127
|
});
|
|
128
|
+
registerTool({
|
|
129
|
+
name: 'buddy_leaderboard',
|
|
130
|
+
description: 'Show the global buddy leaderboard — anonymous rankings of all kbot buddies across installs, sorted by XP. Requires cloud sync (kernel.chat token).',
|
|
131
|
+
parameters: {
|
|
132
|
+
limit: {
|
|
133
|
+
type: 'number',
|
|
134
|
+
description: 'Number of entries to show (default 20, max 200)',
|
|
135
|
+
},
|
|
136
|
+
species: {
|
|
137
|
+
type: 'string',
|
|
138
|
+
description: 'Filter by species: fox, owl, cat, robot, ghost, mushroom, octopus, dragon',
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
tier: 'free',
|
|
142
|
+
async execute(args) {
|
|
143
|
+
const SPECIES_ICONS = {
|
|
144
|
+
fox: '[fox]', owl: '[owl]', cat: '[cat]', robot: '[bot]',
|
|
145
|
+
ghost: '[gho]', mushroom: '[msh]', octopus: '[oct]', dragon: '[drg]',
|
|
146
|
+
};
|
|
147
|
+
const LEVEL_TITLES_SHORT = {
|
|
148
|
+
0: 'Novice', 1: 'Adept', 2: 'Master', 3: 'Legend',
|
|
149
|
+
};
|
|
150
|
+
const limit = Math.min(Math.max(Math.floor(Number(args.limit) || 20), 1), 200);
|
|
151
|
+
const species = args.species ? String(args.species).toLowerCase() : undefined;
|
|
152
|
+
const validSpecies = ['fox', 'owl', 'cat', 'robot', 'ghost', 'mushroom', 'octopus', 'dragon'];
|
|
153
|
+
if (species && !validSpecies.includes(species)) {
|
|
154
|
+
return `Unknown species "${species}". Valid: ${validSpecies.join(', ')}`;
|
|
155
|
+
}
|
|
156
|
+
const entries = await fetchBuddyLeaderboard({ limit, species });
|
|
157
|
+
if (entries.length === 0) {
|
|
158
|
+
return 'No entries on the leaderboard yet. Use kbot to earn XP and sync to the cloud!';
|
|
159
|
+
}
|
|
160
|
+
const lines = [];
|
|
161
|
+
const header = species
|
|
162
|
+
? `=== Buddy Leaderboard — ${species} ===`
|
|
163
|
+
: '=== Global Buddy Leaderboard ===';
|
|
164
|
+
lines.push(header);
|
|
165
|
+
lines.push('');
|
|
166
|
+
// Table header
|
|
167
|
+
lines.push(` ${'#'.padStart(3)} ${'Species'.padEnd(7)} ${'Level'.padEnd(12)} ${'XP'.padStart(6)} ${'Achv'.padStart(4)} ${'Sessions'.padStart(8)}`);
|
|
168
|
+
lines.push(` ${'─'.repeat(3)} ${'─'.repeat(7)} ${'─'.repeat(12)} ${'─'.repeat(6)} ${'─'.repeat(4)} ${'─'.repeat(8)}`);
|
|
169
|
+
for (const entry of entries) {
|
|
170
|
+
const icon = SPECIES_ICONS[entry.species] || entry.species.slice(0, 5);
|
|
171
|
+
const title = LEVEL_TITLES_SHORT[entry.level] ?? `L${entry.level}`;
|
|
172
|
+
const levelStr = `${entry.level} ${title}`;
|
|
173
|
+
lines.push(` ${String(entry.rank).padStart(3)} ${icon.padEnd(7)} ${levelStr.padEnd(12)} ${String(entry.xp).padStart(6)} ${String(entry.achievement_count).padStart(4)} ${String(entry.sessions).padStart(8)}`);
|
|
174
|
+
}
|
|
175
|
+
lines.push('');
|
|
176
|
+
lines.push(`${entries.length} entries shown`);
|
|
177
|
+
return lines.join('\n');
|
|
178
|
+
},
|
|
179
|
+
});
|
|
127
180
|
}
|
|
128
181
|
//# sourceMappingURL=buddy-tools.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kernel.chat/kbot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.73.1",
|
|
4
4
|
"description": "Open-source terminal AI agent. 764+ tools, 35 agents, 20 providers. Dreams, learns, watches your system. Controls your phone. Fully local, fully sovereign. MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|