kill-switch-mcp 1.1.9 → 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/dist/server.js +241 -242
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { existsSync as existsSync3 } from "fs";
|
|
15
15
|
import { readFile as readFile2 } from "fs/promises";
|
|
16
16
|
import { join as join3 } from "path";
|
|
17
|
+
import { homedir as homedir3 } from "os";
|
|
17
18
|
|
|
18
19
|
// src/sdk/types.ts
|
|
19
20
|
var PRAYER_NAMES = [
|
|
@@ -3452,6 +3453,7 @@ class BotActions {
|
|
|
3452
3453
|
import { readFile } from "fs/promises";
|
|
3453
3454
|
import { join } from "path";
|
|
3454
3455
|
import { existsSync } from "fs";
|
|
3456
|
+
import { homedir } from "os";
|
|
3455
3457
|
|
|
3456
3458
|
class BotManager {
|
|
3457
3459
|
connections = new Map;
|
|
@@ -3471,9 +3473,9 @@ class BotManager {
|
|
|
3471
3473
|
let gateway = gatewayUrl || this.defaultGatewayUrl;
|
|
3472
3474
|
let showChat = false;
|
|
3473
3475
|
if (!password) {
|
|
3474
|
-
const envPath = join(
|
|
3476
|
+
const envPath = join(homedir(), ".killswitch", "bots", name, "bot.env");
|
|
3475
3477
|
if (!existsSync(envPath)) {
|
|
3476
|
-
throw new Error(`Bot "${name}" not found. No bots/${name}/bot.env file exists. Call login with an agent_name to create one.`);
|
|
3478
|
+
throw new Error(`Bot "${name}" not found. No ~/.killswitch/bots/${name}/bot.env file exists. Call login with an agent_name to create one.`);
|
|
3477
3479
|
}
|
|
3478
3480
|
const envContent = await readFile(envPath, "utf-8");
|
|
3479
3481
|
const env = this.parseEnv(envContent);
|
|
@@ -3801,7 +3803,7 @@ function formatWorldState(state, stateAgeMs) {
|
|
|
3801
3803
|
// src/wallet/index.ts
|
|
3802
3804
|
import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
3803
3805
|
import { join as join2 } from "path";
|
|
3804
|
-
import { homedir } from "os";
|
|
3806
|
+
import { homedir as homedir2 } from "os";
|
|
3805
3807
|
import {
|
|
3806
3808
|
createPublicClient,
|
|
3807
3809
|
createWalletClient,
|
|
@@ -3812,7 +3814,7 @@ import {
|
|
|
3812
3814
|
pad
|
|
3813
3815
|
} from "viem";
|
|
3814
3816
|
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";
|
|
3815
|
-
var WALLET_DIR = join2(
|
|
3817
|
+
var WALLET_DIR = join2(homedir2(), ".killswitch");
|
|
3816
3818
|
var WALLET_FILE = join2(WALLET_DIR, "access-key.json");
|
|
3817
3819
|
var TEMPO_RPC = process.env.TEMPO_RPC_URL || "https://rpc.moderato.tempo.xyz";
|
|
3818
3820
|
var TEMPO_CHAIN_ID = parseInt(process.env.TEMPO_CHAIN_ID || "42431");
|
|
@@ -4067,84 +4069,144 @@ var SERVER_URL2 = (() => {
|
|
|
4067
4069
|
return process.env.KILL_SWITCH_SERVER || "localhost";
|
|
4068
4070
|
})();
|
|
4069
4071
|
console.error(`[Kill Switch MCP] Server: ${SERVER_URL2}`);
|
|
4070
|
-
var
|
|
4072
|
+
var KILLSWITCH_HOME = join3(homedir3(), ".killswitch");
|
|
4073
|
+
var BOTS_DIR = join3(KILLSWITCH_HOME, "bots");
|
|
4074
|
+
var GUIDE = `# Kill Switch — Player Guide
|
|
4075
|
+
|
|
4076
|
+
You are playing Kill Switch — a Hunger Games-style battle royale where AI agents fight to the death.
|
|
4077
|
+
|
|
4078
|
+
YOU are the brain of your bot. Your human talks strategy, you execute it in the game.
|
|
4079
|
+
|
|
4080
|
+
**PERMADEATH**: If your agent dies, it's dead forever. No respawns. Only the last one standing wins.
|
|
4081
|
+
|
|
4082
|
+
---
|
|
4071
4083
|
|
|
4072
|
-
|
|
4073
|
-
execute it by sending code to the game via execute_code.
|
|
4084
|
+
## Quick Start
|
|
4074
4085
|
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4086
|
+
1. \`login\` — connects to the game (creates account if needed)
|
|
4087
|
+
2. \`join_game\` with mode \`"shorty"\` — queues you up
|
|
4088
|
+
3. \`wait_for_game_start\` — blocks until teleported to the arena
|
|
4089
|
+
4. \`execute_code\` — fight! Use \`bot\`, \`sdk\`, and \`actions\` globals.
|
|
4090
|
+
|
|
4091
|
+
Before writing any execute_code, read \`killswitch://sdk-reference\` for the complete API.
|
|
4092
|
+
|
|
4093
|
+
---
|
|
4082
4094
|
|
|
4083
4095
|
## Game Modes
|
|
4084
|
-
|
|
4085
|
-
|
|
4096
|
+
|
|
4097
|
+
### Shorty (Quick Battle Royale)
|
|
4098
|
+
- **Arena**: Draynor Manor fenced grounds
|
|
4099
|
+
- **Stats**: 50 Attack, 50 Strength, 50 Defence, 99 Hitpoints
|
|
4100
|
+
- **Start**: Empty inventory — everything comes from ground loot
|
|
4101
|
+
- **Win condition**: Last agent alive
|
|
4102
|
+
|
|
4103
|
+
### Longy (Coming Soon)
|
|
4104
|
+
- Large map: Falador to Port Sarim
|
|
4105
|
+
- Level 1 everything — skill up, craft gear, fish food, outlast everyone
|
|
4106
|
+
|
|
4107
|
+
---
|
|
4086
4108
|
|
|
4087
4109
|
## The Arena (Shorty)
|
|
4088
|
-
- You spawn inside Draynor Manor's fenced arena with nothing
|
|
4089
|
-
- Items are scattered on the ground in a cornucopia pattern:
|
|
4090
|
-
- Outer ring: bronze/iron weapons, leather armor, bread/meat
|
|
4091
|
-
- Mid ring: mithril/adamant weapons, chainmail, trout/salmon
|
|
4092
|
-
- Center: rune weapons, rune/adamant armor, lobster/swordfish
|
|
4093
|
-
- Better items are closer to the center — but so is everyone else!
|
|
4094
4110
|
|
|
4095
|
-
|
|
4096
|
-
- If you die, your agent is DEAD FOREVER. No respawns, no second chances.
|
|
4097
|
-
- Only the last agent standing wins. Winners earn party hats!
|
|
4111
|
+
You spawn on the perimeter of Draynor Manor with **nothing**. Items are scattered in a cornucopia pattern:
|
|
4098
4112
|
|
|
4099
|
-
|
|
4113
|
+
- **Outer ring** (safe, near spawn): Bronze/iron weapons, leather armor, bread/meat
|
|
4114
|
+
- **Mid ring**: Mithril/adamant weapons, chainmail, trout/salmon
|
|
4115
|
+
- **Center** (dangerous, high traffic): Rune weapons, rune/adamant armor, lobster/swordfish
|
|
4100
4116
|
|
|
4101
|
-
|
|
4102
|
-
- **bot**: High-level actions (await required — they wait for the effect to complete)
|
|
4103
|
-
- **sdk**: Low-level state access and direct commands
|
|
4104
|
-
- **actions**: Pre-built strategy functions from your bot's actions/ directory
|
|
4117
|
+
**Better loot = more risk.** Everyone converges on the center.
|
|
4105
4118
|
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
- bot.eatFood(/item name/i) — eat food to heal
|
|
4110
|
-
- bot.attackPlayer("name" or /pattern/i) — attack a player
|
|
4111
|
-
- bot.attackNpc("name" or /pattern/i) — attack an NPC
|
|
4112
|
-
- bot.walkTo(x, z) — pathfind and walk (complex, uses server pathfinding)
|
|
4119
|
+
---
|
|
4120
|
+
|
|
4121
|
+
## How to Play
|
|
4113
4122
|
|
|
4114
|
-
###
|
|
4115
|
-
|
|
4116
|
-
-
|
|
4117
|
-
-
|
|
4118
|
-
-
|
|
4119
|
-
- sdk.getState().player.maxHp — your max HP
|
|
4120
|
-
- sdk.getInventory() — array of inventory items (each has .name)
|
|
4121
|
-
- sdk.getEquipment() — array of equipment items
|
|
4122
|
-
- sdk.findInventoryItem(/pattern/i) — find item in inventory
|
|
4123
|
-
- sdk.findGroundItem(/pattern/i) — find item on ground (returns { name, x, z, distance } — NOT .worldX!)
|
|
4124
|
-
- sdk.getGroundItems() — all nearby ground items (each has .name, .x, .z, .distance, .id, .count)
|
|
4125
|
-
- sdk.getNearbyPlayers() — nearby players (each has .name, .combatLevel, .distance, .x, .z)
|
|
4126
|
-
- sdk.waitForTicks(n) — wait n game ticks (~0.6s each)
|
|
4123
|
+
### Interactive Mode (default)
|
|
4124
|
+
Your human gives you strategy between rounds:
|
|
4125
|
+
- "Rush the center, grab the best gear"
|
|
4126
|
+
- "Play safe, loot the outer ring and wait"
|
|
4127
|
+
- "Focus the weakest player"
|
|
4127
4128
|
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4129
|
+
You turn their words into execute_code calls. Keep each call to **15-30 seconds**, then report back what happened so they can adjust.
|
|
4130
|
+
|
|
4131
|
+
### Autonomous Mode (\`claude -p\`)
|
|
4132
|
+
Run a full game with no human input:
|
|
4133
|
+
\`\`\`
|
|
4134
|
+
claude -p 'Play Kill Switch. Create agent named Fury. Join shorty, play aggressively. Exit when done.'
|
|
4135
|
+
\`\`\`
|
|
4136
|
+
Claude makes all decisions. Same tools, same flow — just no human between rounds.
|
|
4137
|
+
|
|
4138
|
+
---
|
|
4133
4139
|
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4140
|
+
## Pre-Built Actions
|
|
4141
|
+
|
|
4142
|
+
Your bot ships with action functions in the \`actions\` object. **Use these first** — they handle the common patterns:
|
|
4143
|
+
|
|
4144
|
+
\`\`\`typescript
|
|
4145
|
+
// Grab nearby items and equip best gear
|
|
4146
|
+
await actions.lootAndEquip({ maxItems: 5 });
|
|
4147
|
+
|
|
4148
|
+
// Fight nearest player with auto-eat (15 seconds)
|
|
4149
|
+
await actions.fightLoop({ eatAt: 25, duration: 15000 });
|
|
4150
|
+
|
|
4151
|
+
// Fight a specific player
|
|
4152
|
+
await actions.fightLoop({ target: /vex/i, eatAt: 20 });
|
|
4153
|
+
|
|
4154
|
+
// Retreat while eating to recover HP
|
|
4155
|
+
await actions.kite({ safeHp: 40 });
|
|
4156
|
+
\`\`\`
|
|
4142
4157
|
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4158
|
+
Combine them for a full turn:
|
|
4159
|
+
\`\`\`typescript
|
|
4160
|
+
const loot = await actions.lootAndEquip({ maxItems: 3 });
|
|
4161
|
+
const result = await actions.fightLoop({ eatAt: 25, duration: 15000 });
|
|
4162
|
+
if (result.hp < 15 && result.foodLeft > 0) {
|
|
4163
|
+
await actions.kite({ safeHp: 35 });
|
|
4164
|
+
}
|
|
4165
|
+
return result;
|
|
4166
|
+
\`\`\`
|
|
4167
|
+
|
|
4168
|
+
### Custom Actions
|
|
4169
|
+
Create custom actions in \`~/.killswitch/bots/<name>/actions/\`. Each \`.ts\` file exports a default function that becomes \`actions.functionName()\`. Re-login to pick up new actions.
|
|
4170
|
+
|
|
4171
|
+
---
|
|
4172
|
+
|
|
4173
|
+
## Key Rules
|
|
4174
|
+
|
|
4175
|
+
1. **Use MCP tools only** — never bash commands or scripts for gameplay
|
|
4176
|
+
2. **Read killswitch://sdk-reference** before writing execute_code
|
|
4177
|
+
3. **Pick up items first** — you start empty, looting is survival
|
|
4178
|
+
4. **Equip before fighting** — weapon first, then armor
|
|
4179
|
+
5. **Eat when HP < 25** — any food is better than no food
|
|
4180
|
+
6. **Keep execute_code calls short** (15-30s) — return state, evaluate, adapt
|
|
4181
|
+
7. **You cannot see other players' HP or inventory** — only name, combat level, position, distance
|
|
4182
|
+
8. **bot methods throw on failure** — use try/catch if you want to handle errors
|
|
4183
|
+
9. **sdk.sendWalk(x, z) for movement** — bot.walkTo() uses server pathfinding (slower, can fail)
|
|
4184
|
+
10. **PERMADEATH** — play smart!
|
|
4185
|
+
|
|
4186
|
+
---
|
|
4187
|
+
|
|
4188
|
+
## Bot Data
|
|
4189
|
+
|
|
4190
|
+
Bot credentials and custom actions are stored in \`~/.killswitch/bots/<name>/\`:
|
|
4191
|
+
\`\`\`
|
|
4192
|
+
~/.killswitch/
|
|
4193
|
+
bots/
|
|
4194
|
+
<name>/
|
|
4195
|
+
bot.env # BOT_USERNAME, PASSWORD, SERVER
|
|
4196
|
+
actions/ # Custom action files (.ts)
|
|
4197
|
+
\`\`\`
|
|
4198
|
+
|
|
4199
|
+
The \`login\` tool creates this automatically. You don't need to set up files manually.
|
|
4200
|
+
|
|
4201
|
+
---
|
|
4202
|
+
|
|
4203
|
+
## Troubleshooting
|
|
4204
|
+
|
|
4205
|
+
- **"Not connected"** — Call \`login\` again. It reconnects automatically.
|
|
4206
|
+
- **"No game state"** — The browser client needs a moment to load. Wait a few seconds.
|
|
4207
|
+
- **Agent is dead** — That agent is gone forever (permadeath). Create a new one with a different name.
|
|
4208
|
+
- **Items not picking up** — Check the SDK reference for correct method signatures and property names.
|
|
4209
|
+
`;
|
|
4148
4210
|
var server = new Server({ name: "kill-switch", version: "3.0.0" }, { capabilities: { tools: {}, resources: {} } });
|
|
4149
4211
|
var SDK_REFERENCE = `# Kill Switch SDK Reference
|
|
4150
4212
|
|
|
@@ -4181,7 +4243,7 @@ Wrap in try/catch if you want to handle failures gracefully.
|
|
|
4181
4243
|
- \`await bot.talkTo(nameOrPattern)\` — Talk to an NPC.
|
|
4182
4244
|
- \`await bot.interactLoc(nameOrPattern, option)\` — Interact with a game object.
|
|
4183
4245
|
- \`await bot.interactNpc(nameOrPattern, option)\` — Interact with an NPC.
|
|
4184
|
-
- \`await bot.openDoor(
|
|
4246
|
+
- \`await bot.openDoor(target)\` — Open a door. Pass a NearbyLoc object, string name, or RegExp. With no args, opens nearest door.
|
|
4185
4247
|
|
|
4186
4248
|
### Dialog
|
|
4187
4249
|
- \`await bot.navigateDialog(choices)\` — Navigate through NPC dialog.
|
|
@@ -4199,10 +4261,10 @@ Wrap in try/catch if you want to handle failures gracefully.
|
|
|
4199
4261
|
- \`sdk.getState()\` — Returns the full game state object. See "State Object Shape" below.
|
|
4200
4262
|
- \`sdk.getInventory()\` — Array of inventory items. Each has: \`.name\`, \`.id\`, \`.count\`, \`.slot\`
|
|
4201
4263
|
- \`sdk.getEquipment()\` — Array of equipped items. Each has: \`.name\`, \`.id\`, \`.slot\`
|
|
4202
|
-
- \`sdk.getNearbyPlayers()\` — Array of nearby players. Each has: \`.name\`, \`.combatLevel\`, \`.distance\`, \`.x\`, \`.z\`
|
|
4264
|
+
- \`sdk.getNearbyPlayers()\` — Array of nearby players. Each has: \`.index\`, \`.name\`, \`.combatLevel\`, \`.distance\`, \`.x\`, \`.z\`
|
|
4203
4265
|
- \`sdk.getGroundItems()\` — Array of ground items. Each has: \`.name\`, \`.id\`, \`.count\`, \`.x\`, \`.z\`, \`.distance\`
|
|
4204
|
-
- \`sdk.getNearbyLocs()\` — Array of nearby game objects.
|
|
4205
|
-
- \`sdk.getNearbyNpcs()\` — Array of nearby NPCs.
|
|
4266
|
+
- \`sdk.getNearbyLocs()\` — Array of nearby game objects. Each has: \`.id\`, \`.name\`, \`.x\`, \`.z\`, \`.distance\`, \`.options\`
|
|
4267
|
+
- \`sdk.getNearbyNpcs()\` — Array of nearby NPCs. Each has: \`.index\`, \`.name\`, \`.combatLevel\`, \`.x\`, \`.z\`, \`.distance\`, \`.hp\`, \`.maxHp\`, \`.inCombat\`
|
|
4206
4268
|
|
|
4207
4269
|
### Search (instant, not async)
|
|
4208
4270
|
- \`sdk.findInventoryItem(pattern)\` — Find first matching inventory item. Returns item or null.
|
|
@@ -4211,15 +4273,16 @@ Wrap in try/catch if you want to handle failures gracefully.
|
|
|
4211
4273
|
- \`sdk.findNearbyNpc(pattern)\` — Find a nearby NPC. Returns NPC or null.
|
|
4212
4274
|
- \`sdk.findNearbyLoc(pattern)\` — Find a nearby game object. Returns loc or null.
|
|
4213
4275
|
|
|
4214
|
-
### Direct Commands (
|
|
4215
|
-
|
|
4216
|
-
- \`sdk.
|
|
4217
|
-
- \`sdk.
|
|
4218
|
-
- \`sdk.
|
|
4219
|
-
- \`sdk.
|
|
4220
|
-
- \`sdk.
|
|
4276
|
+
### Direct Commands (async, send action to server)
|
|
4277
|
+
All send* methods are async and return Promise<ActionResult>. Use await or fire-and-forget.
|
|
4278
|
+
- \`sdk.sendWalk(x, z)\` — Click a tile to walk there. Fast, no pathfinding. Use for quick movement.
|
|
4279
|
+
- \`sdk.sendPickup(x, z, itemId)\` — Pick up a ground item. Args are (x, z, itemId) — NOT (itemId, x, z).
|
|
4280
|
+
- \`sdk.sendInteractPlayer(playerIndex, option)\` — Interact with a player. Use player.index from getNearbyPlayers().
|
|
4281
|
+
- \`sdk.sendInteractNpc(npcIndex, option)\` — Interact with an NPC. Use npc.index from getNearbyNpcs(). NOT npcId.
|
|
4282
|
+
- \`sdk.sendInteractLoc(x, z, locId, option)\` — Interact with a game object. Args are (x, z, locId, option) — NOT (locId, x, z).
|
|
4283
|
+
- \`sdk.sendUseItem(slot, option)\` — Use an inventory item. option defaults to 1 (first option, e.g. eat/wear).
|
|
4221
4284
|
- \`sdk.sendSetCombatStyle(style)\` — Change combat style (0-3).
|
|
4222
|
-
- \`sdk.sendTogglePrayer(
|
|
4285
|
+
- \`sdk.sendTogglePrayer(prayer)\` — Toggle a prayer. Accepts prayer name string (e.g. 'protect_from_melee') or prayer ID number.
|
|
4223
4286
|
|
|
4224
4287
|
### Timing (async)
|
|
4225
4288
|
- \`await sdk.waitForTicks(n)\` — Wait n game ticks. Each tick ≈ 0.6 seconds.
|
|
@@ -4242,16 +4305,23 @@ sdk.getState() returns:
|
|
|
4242
4305
|
hp: number, // Current hitpoints
|
|
4243
4306
|
maxHp: number, // Max hitpoints
|
|
4244
4307
|
combatLevel: number,
|
|
4245
|
-
|
|
4308
|
+
animId: number, // Current animation ID (-1 = idle)
|
|
4309
|
+
combat: { // Combat sub-state
|
|
4310
|
+
inCombat: boolean,
|
|
4311
|
+
targetIndex: number,
|
|
4312
|
+
},
|
|
4246
4313
|
},
|
|
4314
|
+
inGame: boolean, // Whether connected to game
|
|
4247
4315
|
skills: [...], // Array of skill objects
|
|
4248
4316
|
inventory: [...], // Array of inventory slots
|
|
4249
4317
|
equipment: [...], // Array of equipment slots
|
|
4250
|
-
groundItems: [...], // Nearby ground items (each has .name, .x, .z, .id, .count)
|
|
4251
|
-
nearbyPlayers: [...], // Nearby players
|
|
4252
|
-
nearbyNpcs: [...], // Nearby NPCs
|
|
4318
|
+
groundItems: [...], // Nearby ground items (each has .name, .x, .z, .id, .count, .distance)
|
|
4319
|
+
nearbyPlayers: [...], // Nearby players (each has .index, .name, .x, .z, .distance, .combatLevel)
|
|
4320
|
+
nearbyNpcs: [...], // Nearby NPCs (each has .index, .name, .x, .z, .distance, .hp, .maxHp)
|
|
4321
|
+
nearbyLocs: [...], // Nearby game objects (each has .id, .name, .x, .z, .distance, .options)
|
|
4253
4322
|
dialog: { isOpen, ... }, // Dialog state
|
|
4254
4323
|
modalOpen: boolean, // Whether a modal is open
|
|
4324
|
+
gameMessages: [...], // Recent game messages
|
|
4255
4325
|
}
|
|
4256
4326
|
\`\`\`
|
|
4257
4327
|
|
|
@@ -4267,10 +4337,20 @@ IMPORTANT PROPERTY NAMES:
|
|
|
4267
4337
|
|
|
4268
4338
|
### Quick loot (walk + pick up):
|
|
4269
4339
|
\`\`\`
|
|
4270
|
-
|
|
4271
|
-
await
|
|
4272
|
-
|
|
4273
|
-
|
|
4340
|
+
// Option A: Use bot.pickupItem (walks to item automatically, throws on failure)
|
|
4341
|
+
try { await bot.pickupItem(/lobster/i); } catch(e) { console.log("Missed lobster"); }
|
|
4342
|
+
|
|
4343
|
+
// Option B: Manual walk + raw pickup (more control)
|
|
4344
|
+
const item = sdk.findGroundItem(/lobster/i);
|
|
4345
|
+
if (item) {
|
|
4346
|
+
sdk.sendWalk(item.x, item.z); // Walk to item
|
|
4347
|
+
await sdk.waitForTicks(5); // Wait to arrive
|
|
4348
|
+
sdk.sendPickup(item.x, item.z, item.id); // Pick up (args: x, z, itemId)
|
|
4349
|
+
await sdk.waitForTicks(2); // Wait for server
|
|
4350
|
+
}
|
|
4351
|
+
|
|
4352
|
+
// Equip from inventory
|
|
4353
|
+
await bot.equipItem(/scimitar/i);
|
|
4274
4354
|
\`\`\`
|
|
4275
4355
|
|
|
4276
4356
|
### Combat loop:
|
|
@@ -4298,10 +4378,16 @@ For combat/arena play, use \`sdk.sendWalk(x, z)\` + \`await sdk.waitForTicks(n)\
|
|
|
4298
4378
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
4299
4379
|
return {
|
|
4300
4380
|
resources: [
|
|
4381
|
+
{
|
|
4382
|
+
uri: "killswitch://guide",
|
|
4383
|
+
name: "Kill Switch Player Guide",
|
|
4384
|
+
description: "START HERE. Game overview, how to play, common patterns, and key rules. Read this before doing anything.",
|
|
4385
|
+
mimeType: "text/markdown"
|
|
4386
|
+
},
|
|
4301
4387
|
{
|
|
4302
4388
|
uri: "killswitch://sdk-reference",
|
|
4303
4389
|
name: "Kill Switch SDK Reference",
|
|
4304
|
-
description: "Complete API reference for bot, sdk, and actions objects used in execute_code.
|
|
4390
|
+
description: "Complete API reference for bot, sdk, and actions objects used in execute_code. Read before writing game code.",
|
|
4305
4391
|
mimeType: "text/markdown"
|
|
4306
4392
|
}
|
|
4307
4393
|
]
|
|
@@ -4309,6 +4395,17 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
|
4309
4395
|
});
|
|
4310
4396
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
4311
4397
|
const { uri } = request.params;
|
|
4398
|
+
if (uri === "killswitch://guide") {
|
|
4399
|
+
return {
|
|
4400
|
+
contents: [
|
|
4401
|
+
{
|
|
4402
|
+
uri: "killswitch://guide",
|
|
4403
|
+
mimeType: "text/markdown",
|
|
4404
|
+
text: GUIDE
|
|
4405
|
+
}
|
|
4406
|
+
]
|
|
4407
|
+
};
|
|
4408
|
+
}
|
|
4312
4409
|
if (uri === "killswitch://sdk-reference") {
|
|
4313
4410
|
return {
|
|
4314
4411
|
contents: [
|
|
@@ -4327,44 +4424,26 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
4327
4424
|
tools: [
|
|
4328
4425
|
{
|
|
4329
4426
|
name: "login",
|
|
4330
|
-
description:
|
|
4331
|
-
|
|
4332
|
-
Call this when the user says anything like "let's play", "join the game", "log in", "connect", etc.
|
|
4333
|
-
|
|
4334
|
-
If the user already has a bot, this will reconnect. If not, it creates a new one. Idempotent — safe to call multiple times.
|
|
4335
|
-
|
|
4336
|
-
${GAME_DESCRIPTION}`,
|
|
4427
|
+
description: "Log in to Kill Switch. Creates account if needed, connects to game server, opens browser client. Idempotent — safe to call again. Read killswitch://guide first for game overview.",
|
|
4337
4428
|
inputSchema: {
|
|
4338
4429
|
type: "object",
|
|
4339
4430
|
properties: {
|
|
4340
4431
|
agent_name: {
|
|
4341
4432
|
type: "string",
|
|
4342
|
-
description: "Name for the bot (max 12 chars, alphanumeric). If not provided,
|
|
4433
|
+
description: "Name for the bot (max 12 chars, alphanumeric). If not provided, reuses existing bot or generates random name."
|
|
4343
4434
|
}
|
|
4344
4435
|
}
|
|
4345
4436
|
}
|
|
4346
4437
|
},
|
|
4347
4438
|
{
|
|
4348
4439
|
name: "execute_code",
|
|
4349
|
-
description:
|
|
4350
|
-
|
|
4351
|
-
IMPORTANT: Read the "Kill Switch SDK Reference" resource (killswitch://sdk-reference) for the complete API.
|
|
4352
|
-
Do NOT guess method names or property paths — only use what is documented in the SDK reference.
|
|
4353
|
-
|
|
4354
|
-
Quick reminders:
|
|
4355
|
-
- bot methods are async and THROW on failure
|
|
4356
|
-
- sdk.getState().player.worldX / .worldZ / .hp / .maxHp
|
|
4357
|
-
- Ground items use .x / .z (NOT .worldX)
|
|
4358
|
-
- sdk.sendWalk(x, z) for fast movement, bot.walkTo(x, z) for pathfinding
|
|
4359
|
-
- Blocking UI is auto-dismissed — do NOT call bot.dismissBlockingUI()
|
|
4360
|
-
|
|
4361
|
-
You MUST call login before using this tool.`,
|
|
4440
|
+
description: "Execute TypeScript code on your bot. Globals: bot, sdk, actions. Read killswitch://sdk-reference for API. Bot methods throw on failure. Blocking UI is auto-dismissed.",
|
|
4362
4441
|
inputSchema: {
|
|
4363
4442
|
type: "object",
|
|
4364
4443
|
properties: {
|
|
4365
4444
|
code: {
|
|
4366
4445
|
type: "string",
|
|
4367
|
-
description: "TypeScript code to execute. Has access to bot (BotActions)
|
|
4446
|
+
description: "TypeScript code to execute. Has access to bot (BotActions), sdk (BotSDK), and actions."
|
|
4368
4447
|
},
|
|
4369
4448
|
timeout: {
|
|
4370
4449
|
type: "number",
|
|
@@ -4376,7 +4455,7 @@ You MUST call login before using this tool.`,
|
|
|
4376
4455
|
},
|
|
4377
4456
|
{
|
|
4378
4457
|
name: "get_status",
|
|
4379
|
-
description: "Check
|
|
4458
|
+
description: "Check bot state (position, HP, inventory, nearby players) without executing code.",
|
|
4380
4459
|
inputSchema: {
|
|
4381
4460
|
type: "object",
|
|
4382
4461
|
properties: {}
|
|
@@ -4384,16 +4463,7 @@ You MUST call login before using this tool.`,
|
|
|
4384
4463
|
},
|
|
4385
4464
|
{
|
|
4386
4465
|
name: "wait_for_game_start",
|
|
4387
|
-
description:
|
|
4388
|
-
|
|
4389
|
-
This tool blocks until the game starts and your bot is teleported to the arena. When it returns, the fight is ON — immediately start your combat loop!
|
|
4390
|
-
|
|
4391
|
-
Typical flow:
|
|
4392
|
-
1. login → connect to game
|
|
4393
|
-
2. join_game → pick a mode
|
|
4394
|
-
3. Chat strategy with human
|
|
4395
|
-
4. wait_for_game_start → blocks until game starts
|
|
4396
|
-
5. execute_code → start fighting!`,
|
|
4466
|
+
description: "Block until the match starts and you are teleported to the arena. Call after join_game.",
|
|
4397
4467
|
inputSchema: {
|
|
4398
4468
|
type: "object",
|
|
4399
4469
|
properties: {
|
|
@@ -4406,20 +4476,14 @@ Typical flow:
|
|
|
4406
4476
|
},
|
|
4407
4477
|
{
|
|
4408
4478
|
name: "join_game",
|
|
4409
|
-
description:
|
|
4410
|
-
|
|
4411
|
-
Available modes:
|
|
4412
|
-
- "shorty": Quick battle royale at Draynor Manor. 50 atk/str/def, 99 HP. Grab loot, fight, last one standing wins.
|
|
4413
|
-
- "longy": (Coming soon) Large survival map with skill progression.
|
|
4414
|
-
|
|
4415
|
-
After joining, call wait_for_game_start to wait for the game to begin.`,
|
|
4479
|
+
description: "Join a game mode queue. Call after login. After joining, call wait_for_game_start.",
|
|
4416
4480
|
inputSchema: {
|
|
4417
4481
|
type: "object",
|
|
4418
4482
|
properties: {
|
|
4419
4483
|
mode: {
|
|
4420
4484
|
type: "string",
|
|
4421
4485
|
enum: ["shorty", "longy"],
|
|
4422
|
-
description:
|
|
4486
|
+
description: 'Game mode: "shorty" (quick battle royale) or "longy" (coming soon)'
|
|
4423
4487
|
}
|
|
4424
4488
|
},
|
|
4425
4489
|
required: ["mode"]
|
|
@@ -4427,7 +4491,7 @@ After joining, call wait_for_game_start to wait for the game to begin.`,
|
|
|
4427
4491
|
},
|
|
4428
4492
|
{
|
|
4429
4493
|
name: "disconnect_bot",
|
|
4430
|
-
description: "Disconnect from the game.
|
|
4494
|
+
description: "Disconnect from the game.",
|
|
4431
4495
|
inputSchema: {
|
|
4432
4496
|
type: "object",
|
|
4433
4497
|
properties: {}
|
|
@@ -4435,23 +4499,13 @@ After joining, call wait_for_game_start to wait for the game to begin.`,
|
|
|
4435
4499
|
},
|
|
4436
4500
|
{
|
|
4437
4501
|
name: "setup_game_wallet",
|
|
4438
|
-
description:
|
|
4439
|
-
|
|
4440
|
-
IMPORTANT: This tool handles real (or testnet) money. Explain to the user what's happening at each step.
|
|
4441
|
-
|
|
4442
|
-
Prerequisites:
|
|
4443
|
-
- The user must have the Tempo CLI installed (curl -fsSL https://tempo.xyz/install | bash)
|
|
4444
|
-
- The user must have run "tempo wallet login" to create their Tempo account
|
|
4445
|
-
|
|
4446
|
-
This tool generates a local access key. The user then needs to authorize it on their Tempo account (requires biometric/passkey confirmation). After that, the key is stored locally in ~/.killswitch/ and used for all tournament deposits.
|
|
4447
|
-
|
|
4448
|
-
Learn more about Tempo access keys: https://docs.tempo.xyz/protocol/tips/tip-1011`,
|
|
4502
|
+
description: 'Set up a Tempo wallet access key for paid tournaments. Requires Tempo CLI installed and "tempo wallet login" completed. Handles real money — explain each step to user.',
|
|
4449
4503
|
inputSchema: {
|
|
4450
4504
|
type: "object",
|
|
4451
4505
|
properties: {
|
|
4452
4506
|
tempo_account_address: {
|
|
4453
4507
|
type: "string",
|
|
4454
|
-
description: `The user's Tempo account address (0x...). Get
|
|
4508
|
+
description: `The user's Tempo account address (0x...). Get via "tempo wallet whoami".`
|
|
4455
4509
|
}
|
|
4456
4510
|
},
|
|
4457
4511
|
required: ["tempo_account_address"]
|
|
@@ -4459,9 +4513,7 @@ Learn more about Tempo access keys: https://docs.tempo.xyz/protocol/tips/tip-101
|
|
|
4459
4513
|
},
|
|
4460
4514
|
{
|
|
4461
4515
|
name: "check_wallet",
|
|
4462
|
-
description:
|
|
4463
|
-
|
|
4464
|
-
If no game wallet is set up, this will tell you to run setup_game_wallet first.`,
|
|
4516
|
+
description: "Check game wallet address and USDC balance for tournament buy-ins.",
|
|
4465
4517
|
inputSchema: {
|
|
4466
4518
|
type: "object",
|
|
4467
4519
|
properties: {}
|
|
@@ -4469,9 +4521,7 @@ If no game wallet is set up, this will tell you to run setup_game_wallet first.`
|
|
|
4469
4521
|
},
|
|
4470
4522
|
{
|
|
4471
4523
|
name: "tournament_schedule",
|
|
4472
|
-
description:
|
|
4473
|
-
|
|
4474
|
-
This is a read-only tool — it doesn't cost anything to check the schedule.`,
|
|
4524
|
+
description: "View upcoming paid tournaments — start times, buy-ins, player counts. Read-only.",
|
|
4475
4525
|
inputSchema: {
|
|
4476
4526
|
type: "object",
|
|
4477
4527
|
properties: {}
|
|
@@ -4479,26 +4529,13 @@ This is a read-only tool — it doesn't cost anything to check the schedule.`,
|
|
|
4479
4529
|
},
|
|
4480
4530
|
{
|
|
4481
4531
|
name: "join_tournament",
|
|
4482
|
-
description:
|
|
4483
|
-
|
|
4484
|
-
THIS TOOL SPENDS REAL MONEY (or testnet money). Before calling this tool:
|
|
4485
|
-
1. Tell the user exactly which tournament they're joining (time, buy-in amount)
|
|
4486
|
-
2. Show their current wallet balance
|
|
4487
|
-
3. Ask them to confirm they want to proceed
|
|
4488
|
-
4. Only then call this tool
|
|
4489
|
-
|
|
4490
|
-
The deposit is sent on-chain to the tournament's escrow contract. The user's buy-in is held in escrow until:
|
|
4491
|
-
- They win → they receive 90% of the pot
|
|
4492
|
-
- The match is cancelled → they get a full refund
|
|
4493
|
-
- The server goes down → they can claim a refund after 1 hour
|
|
4494
|
-
|
|
4495
|
-
The user must be logged in (call login first) so we know their in-game username.`,
|
|
4532
|
+
description: "Join a paid tournament by depositing buy-in from game wallet. SPENDS REAL MONEY. Confirm with user before calling. Must be logged in.",
|
|
4496
4533
|
inputSchema: {
|
|
4497
4534
|
type: "object",
|
|
4498
4535
|
properties: {
|
|
4499
4536
|
tournament_address: {
|
|
4500
4537
|
type: "string",
|
|
4501
|
-
description: "
|
|
4538
|
+
description: "Tournament contract address (from tournament_schedule)"
|
|
4502
4539
|
}
|
|
4503
4540
|
},
|
|
4504
4541
|
required: ["tournament_address"]
|
|
@@ -4514,8 +4551,7 @@ async function loadActions(botName, bot, sdk) {
|
|
|
4514
4551
|
const { existsSync: existsSync4, readdirSync, cpSync, readFileSync: readFileSync2 } = await import("fs");
|
|
4515
4552
|
const { join: join4, basename } = await import("path");
|
|
4516
4553
|
const { pathToFileURL } = await import("url");
|
|
4517
|
-
const
|
|
4518
|
-
const actionsDir = join4(botsDir, botName, "actions");
|
|
4554
|
+
const actionsDir = join4(BOTS_DIR, botName, "actions");
|
|
4519
4555
|
const defaultsDir = join4(new URL(".", import.meta.url).pathname, "..", "defaults", "actions");
|
|
4520
4556
|
console.error(`[Kill Switch] Loading actions from ${actionsDir}`);
|
|
4521
4557
|
if (!existsSync4(actionsDir) && existsSync4(defaultsDir)) {
|
|
@@ -4604,20 +4640,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
|
4604
4640
|
const parts = [`Already connected as "${activeBotName}".`];
|
|
4605
4641
|
if (state) {
|
|
4606
4642
|
parts.push("");
|
|
4607
|
-
parts.push("── Current State ──");
|
|
4608
4643
|
parts.push(formatWorldState(state, existing.sdk.getStateAge()));
|
|
4609
4644
|
}
|
|
4610
|
-
parts.push("");
|
|
4611
|
-
parts.push("Your bot is in the game. Talk strategy with your human while waiting for the tournament to start!");
|
|
4612
4645
|
return { content: [{ type: "text", text: parts.join(`
|
|
4613
4646
|
`) }] };
|
|
4614
4647
|
}
|
|
4615
4648
|
}
|
|
4616
|
-
const botsDir = join3(process.cwd(), "bots");
|
|
4617
4649
|
let username;
|
|
4618
4650
|
let password;
|
|
4651
|
+
const legacyBotsDir = join3(process.cwd(), "bots");
|
|
4652
|
+
if (botName && !existsSync3(join3(BOTS_DIR, botName, "bot.env")) && existsSync3(join3(legacyBotsDir, botName, "bot.env"))) {
|
|
4653
|
+
const { mkdirSync: mkdirSync2, cpSync } = await import("fs");
|
|
4654
|
+
mkdirSync2(join3(BOTS_DIR, botName), { recursive: true });
|
|
4655
|
+
cpSync(join3(legacyBotsDir, botName), join3(BOTS_DIR, botName), { recursive: true });
|
|
4656
|
+
console.error(`[Kill Switch] Migrated bot "${botName}" from ./bots/ to ~/.killswitch/bots/`);
|
|
4657
|
+
}
|
|
4619
4658
|
if (botName) {
|
|
4620
|
-
const envPath = join3(
|
|
4659
|
+
const envPath = join3(BOTS_DIR, botName, "bot.env");
|
|
4621
4660
|
if (existsSync3(envPath)) {
|
|
4622
4661
|
console.error(`[Kill Switch] Found existing bot "${botName}"`);
|
|
4623
4662
|
const env = parseEnv(await readFile2(envPath, "utf-8"));
|
|
@@ -4628,7 +4667,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
|
4628
4667
|
username = botName;
|
|
4629
4668
|
password = generateRandomPassword();
|
|
4630
4669
|
const { mkdirSync: mkdirSync2, writeFileSync: writeFileSync2 } = await import("fs");
|
|
4631
|
-
const botDir = join3(
|
|
4670
|
+
const botDir = join3(BOTS_DIR, botName);
|
|
4632
4671
|
mkdirSync2(botDir, { recursive: true });
|
|
4633
4672
|
writeFileSync2(join3(botDir, "bot.env"), [
|
|
4634
4673
|
`BOT_USERNAME=${username}`,
|
|
@@ -4639,21 +4678,30 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
|
4639
4678
|
`));
|
|
4640
4679
|
}
|
|
4641
4680
|
} else {
|
|
4642
|
-
const { readdirSync } = await import("fs");
|
|
4643
|
-
if (existsSync3(
|
|
4644
|
-
const
|
|
4681
|
+
const { readdirSync, mkdirSync: mkdirSync2, writeFileSync: writeFileSync2, cpSync } = await import("fs");
|
|
4682
|
+
if (existsSync3(legacyBotsDir)) {
|
|
4683
|
+
const legacyDirs = readdirSync(legacyBotsDir).filter((d) => d !== "_template" && existsSync3(join3(legacyBotsDir, d, "bot.env")));
|
|
4684
|
+
for (const legacyName of legacyDirs) {
|
|
4685
|
+
if (!existsSync3(join3(BOTS_DIR, legacyName, "bot.env"))) {
|
|
4686
|
+
mkdirSync2(join3(BOTS_DIR, legacyName), { recursive: true });
|
|
4687
|
+
cpSync(join3(legacyBotsDir, legacyName), join3(BOTS_DIR, legacyName), { recursive: true });
|
|
4688
|
+
console.error(`[Kill Switch] Migrated bot "${legacyName}" from ./bots/ to ~/.killswitch/bots/`);
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
}
|
|
4692
|
+
if (existsSync3(BOTS_DIR)) {
|
|
4693
|
+
const dirs = readdirSync(BOTS_DIR).filter((d) => d !== "_template" && existsSync3(join3(BOTS_DIR, d, "bot.env")));
|
|
4645
4694
|
if (dirs.length > 0) {
|
|
4646
4695
|
botName = dirs[0];
|
|
4647
4696
|
console.error(`[Kill Switch] Reusing existing bot "${botName}"`);
|
|
4648
|
-
const env = parseEnv(await readFile2(join3(
|
|
4697
|
+
const env = parseEnv(await readFile2(join3(BOTS_DIR, botName, "bot.env"), "utf-8"));
|
|
4649
4698
|
username = env.BOT_USERNAME || botName;
|
|
4650
4699
|
password = env.PASSWORD || "";
|
|
4651
4700
|
} else {
|
|
4652
4701
|
botName = generateRandomName();
|
|
4653
4702
|
username = botName;
|
|
4654
4703
|
password = generateRandomPassword();
|
|
4655
|
-
const
|
|
4656
|
-
const botDir = join3(botsDir, botName);
|
|
4704
|
+
const botDir = join3(BOTS_DIR, botName);
|
|
4657
4705
|
mkdirSync2(botDir, { recursive: true });
|
|
4658
4706
|
writeFileSync2(join3(botDir, "bot.env"), [
|
|
4659
4707
|
`BOT_USERNAME=${username}`,
|
|
@@ -4668,10 +4716,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
|
4668
4716
|
botName = generateRandomName();
|
|
4669
4717
|
username = botName;
|
|
4670
4718
|
password = generateRandomPassword();
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
mkdirSync2(botDir, { recursive: true });
|
|
4674
|
-
writeFileSync2(join3(botDir, "bot.env"), [
|
|
4719
|
+
mkdirSync2(join3(BOTS_DIR, botName), { recursive: true });
|
|
4720
|
+
writeFileSync2(join3(BOTS_DIR, botName, "bot.env"), [
|
|
4675
4721
|
`BOT_USERNAME=${username}`,
|
|
4676
4722
|
`PASSWORD=${password}`,
|
|
4677
4723
|
`SERVER=${SERVER_URL2}`,
|
|
@@ -4738,37 +4784,20 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
|
4738
4784
|
activeActionDescriptions = descriptions;
|
|
4739
4785
|
const state = connection.sdk.getState();
|
|
4740
4786
|
const parts = [
|
|
4741
|
-
`Connected as "${username}"
|
|
4742
|
-
|
|
4743
|
-
"Your bot is in the game. A browser window should have opened showing the game view.",
|
|
4744
|
-
"",
|
|
4745
|
-
"You're in the tournament lobby (Barbarian Village) with:",
|
|
4746
|
-
" - EMPTY inventory and no equipment",
|
|
4747
|
-
" - Combat stats: 50 Attack, 50 Strength, 50 Defence, 99 Hitpoints",
|
|
4748
|
-
"",
|
|
4749
|
-
'NEXT STEP: Call join_game with mode "shorty" (or "longy" when available) to queue up.',
|
|
4750
|
-
"",
|
|
4751
|
-
"Game modes:",
|
|
4752
|
-
" - SHORTY: Quick battle royale at Draynor Manor. Loot, fight, last one standing.",
|
|
4753
|
-
" - LONGY: (Coming soon) Large survival map with skill progression.",
|
|
4754
|
-
"",
|
|
4755
|
-
"After joining a game, call wait_for_game_start to wait for the game to begin."
|
|
4787
|
+
`Connected as "${username}".`,
|
|
4788
|
+
`Bot data: ~/.killswitch/bots/${botName}/`
|
|
4756
4789
|
];
|
|
4757
|
-
parts.push("");
|
|
4758
|
-
parts.push("── IMPORTANT: Read the SDK Reference ──");
|
|
4759
|
-
parts.push('Before writing any execute_code, read the "Kill Switch SDK Reference" resource (killswitch://sdk-reference).');
|
|
4760
|
-
parts.push("It contains the complete API for bot, sdk, and actions. Do NOT guess method names — use only what is documented.");
|
|
4761
4790
|
if (activeActionDescriptions.length > 0) {
|
|
4762
4791
|
parts.push("");
|
|
4763
|
-
parts.push("
|
|
4764
|
-
parts.push("Use these in execute_code via the `actions` object:");
|
|
4792
|
+
parts.push("Loaded actions:");
|
|
4765
4793
|
parts.push(...activeActionDescriptions);
|
|
4766
4794
|
}
|
|
4767
4795
|
if (state) {
|
|
4768
4796
|
parts.push("");
|
|
4769
|
-
parts.push("── Current State ──");
|
|
4770
4797
|
parts.push(formatWorldState(state, connection.sdk.getStateAge()));
|
|
4771
4798
|
}
|
|
4799
|
+
parts.push("");
|
|
4800
|
+
parts.push('Next: call join_game with mode "shorty" to queue up.');
|
|
4772
4801
|
return { content: [{ type: "text", text: parts.join(`
|
|
4773
4802
|
`) }] };
|
|
4774
4803
|
} finally {
|
|
@@ -4892,7 +4921,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
|
4892
4921
|
if (isLongCode) {
|
|
4893
4922
|
parts.push("");
|
|
4894
4923
|
parts.push("── Tip ──");
|
|
4895
|
-
parts.push(`Long script detected. Consider writing to a .ts file
|
|
4924
|
+
parts.push(`Long script detected. Consider writing to a .ts file in ~/.killswitch/bots/${botName}/`);
|
|
4896
4925
|
}
|
|
4897
4926
|
const output = parts.length > 0 ? parts.join(`
|
|
4898
4927
|
`) : "(no output)";
|
|
@@ -4925,33 +4954,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
|
4925
4954
|
console.error(`[Kill Switch] Tournament started! (detected after ${waitTime}s)`);
|
|
4926
4955
|
const players = connection.sdk.getNearbyPlayers?.() || [];
|
|
4927
4956
|
const parts = [
|
|
4928
|
-
"
|
|
4957
|
+
"GAME STARTED! You are in the arena.",
|
|
4929
4958
|
"",
|
|
4930
|
-
`
|
|
4931
|
-
`Position: ${state.player.worldX}, ${state.player.worldZ}`,
|
|
4959
|
+
`Position: (${state.player.worldX}, ${state.player.worldZ})`,
|
|
4932
4960
|
`HP: ${state.player.hp}/${state.player.maxHp}`,
|
|
4961
|
+
`Nearby players: ${players.length > 0 ? players.map((p) => `${p.name} (dist ${p.distance})`).join(", ") : "scanning..."}`,
|
|
4933
4962
|
"",
|
|
4934
|
-
|
|
4935
|
-
"",
|
|
4936
|
-
"REMEMBER: You die = your agent dies FOREVER. No second chances.",
|
|
4937
|
-
"",
|
|
4938
|
-
"IMMEDIATELY use execute_code to start your strategy:",
|
|
4939
|
-
"1. Pick up weapons and food from the ground",
|
|
4940
|
-
"2. Equip best weapon found, then start fighting",
|
|
4941
|
-
"3. Eat when HP gets low — you have 99 HP but no food yet!",
|
|
4942
|
-
"",
|
|
4943
|
-
"QUICK START: await actions.lootAndEquip({ maxItems: 5 }); await actions.fightLoop({ eatAt: 25, duration: 30000 });",
|
|
4944
|
-
"",
|
|
4945
|
-
"API REMINDERS:",
|
|
4946
|
-
"- sdk.sendWalk(x, z) for quick movement (NOT bot.walkTo for combat)",
|
|
4947
|
-
"- sdk.getState().player.worldX / .worldZ / .hp",
|
|
4948
|
-
"- Blocking UI is auto-dismissed — do NOT call bot.dismissBlockingUI()"
|
|
4963
|
+
"Act now — use execute_code to loot and fight."
|
|
4949
4964
|
];
|
|
4950
|
-
if (activeActionDescriptions.length > 0) {
|
|
4951
|
-
parts.push("");
|
|
4952
|
-
parts.push("AVAILABLE ACTIONS:");
|
|
4953
|
-
parts.push(...activeActionDescriptions);
|
|
4954
|
-
}
|
|
4955
4965
|
return { content: [{ type: "text", text: parts.join(`
|
|
4956
4966
|
`) }] };
|
|
4957
4967
|
}
|
|
@@ -4979,22 +4989,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
|
4979
4989
|
return errorResponse(data.error);
|
|
4980
4990
|
}
|
|
4981
4991
|
const parts = [
|
|
4982
|
-
`Joined ${mode.toUpperCase()} queue
|
|
4983
|
-
"",
|
|
4984
|
-
`Queue position: ${data.queuePosition}`,
|
|
4992
|
+
`Joined ${mode.toUpperCase()} queue.`,
|
|
4985
4993
|
`Players in queue: ${data.queuePlayers?.join(", ") || "just you"}`,
|
|
4986
|
-
""
|
|
4994
|
+
"",
|
|
4995
|
+
"Next: call wait_for_game_start to wait for the match."
|
|
4987
4996
|
];
|
|
4988
|
-
if (mode === "shorty") {
|
|
4989
|
-
parts.push("SHORTY: Quick battle royale at Draynor Manor.");
|
|
4990
|
-
parts.push("Stats: 50 Attack, 50 Strength, 50 Defence, 99 Hitpoints");
|
|
4991
|
-
parts.push("You start with NOTHING — grab weapons and food from the ground!");
|
|
4992
|
-
} else {
|
|
4993
|
-
parts.push("LONGY: Large survival map (coming soon).");
|
|
4994
|
-
}
|
|
4995
|
-
parts.push("");
|
|
4996
|
-
parts.push("Now call wait_for_game_start to wait for the game to begin.");
|
|
4997
|
-
parts.push("Chat strategy with your human while you wait!");
|
|
4998
4997
|
return { content: [{ type: "text", text: parts.join(`
|
|
4999
4998
|
`) }] };
|
|
5000
4999
|
} catch (e) {
|