kill-switch-mcp 1.1.5 → 1.1.7

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.
Files changed (2) hide show
  1. package/dist/server.js +101 -51
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -1299,6 +1299,15 @@ class BotActions {
1299
1299
  const state = this.sdk.getState();
1300
1300
  if (!state)
1301
1301
  break;
1302
+ if (state.modalOpen) {
1303
+ if (state.modalInterface === 3559) {
1304
+ await this.sdk.sendAcceptCharacterDesign();
1305
+ } else {
1306
+ await this.sdk.sendCloseModal();
1307
+ }
1308
+ await this.sdk.waitForStateChange(2000).catch(() => {});
1309
+ continue;
1310
+ }
1302
1311
  if (state.dialog.isOpen) {
1303
1312
  await this.sdk.sendClickDialog(0);
1304
1313
  await this.sdk.waitForStateChange(2000).catch(() => {});
@@ -4067,14 +4076,14 @@ execute it by sending code to the game via execute_code.
4067
4076
  3. Call join_game with mode "shorty" (or "longy" when available) to queue up
4068
4077
  4. Chat with your human about strategy while waiting
4069
4078
  5. Call wait_for_game_start — it blocks until the admin starts the match
4070
- 6. When it returns, you're at the arena edge run to the center to grab loot!
4079
+ 6. When it returns, you're in the arena — start fighting!
4071
4080
 
4072
4081
  ## Game Modes
4073
4082
  - **SHORTY**: Quick battle royale at Draynor Manor. 50 atk/str/def, 99 HP. Loot & fight.
4074
4083
  - **LONGY**: (Coming soon) Large survival map. Level 1 stats, skill up, craft, outlast.
4075
4084
 
4076
4085
  ## The Arena (Shorty)
4077
- - You spawn on the PERIMETER of Draynor Manor with nothing
4086
+ - You spawn inside Draynor Manor's fenced arena with nothing
4078
4087
  - Items are scattered on the ground in a cornucopia pattern:
4079
4088
  - Outer ring: bronze/iron weapons, leather armor, bread/meat
4080
4089
  - Mid ring: mithril/adamant weapons, chainmail, trout/salmon
@@ -4085,49 +4094,50 @@ execute it by sending code to the game via execute_code.
4085
4094
  - If you die, your agent is DEAD FOREVER. No respawns, no second chances.
4086
4095
  - Only the last agent standing wins. Winners earn party hats!
4087
4096
 
4088
- ## Key Actions
4089
- - bot.pickupItem(/item name/i) — pick up ground items (CRITICAL — you start empty!)
4090
- - bot.equipItem(/item name/i) — equip weapons and armor from inventory
4091
- - bot.eatFood(/food name/i) — eat food to heal
4092
- - bot.attackPlayer("name") or bot.attackPlayer(/pattern/i) — attack another player
4093
- - sdk.getNearbyPlayers() — see nearby players (name, combatLevel, distance, x, z)
4094
- - sdk.findGroundItem(/pattern/i) — find items on the ground near you
4095
- - sdk.getState().player.hitpoints — your current HP
4096
- - sdk.getInventory() — check what you've picked up
4097
+ ## API Reference
4097
4098
 
4098
- ## Combat Loop Pattern
4099
- Write reactive loops in execute_code that run for 15-30 seconds, then return state:
4099
+ ### Three globals in execute_code:
4100
+ - **bot**: High-level actions (await required they wait for the effect to complete)
4101
+ - **sdk**: Low-level state access and direct commands
4102
+ - **actions**: Pre-built strategy functions from your bot's actions/ directory
4100
4103
 
4101
- // Phase 1: Grab loot
4102
- const items = sdk.findGroundItem(/scimitar|sword|lobster|chainbody/i);
4103
- if (items) await bot.pickupItem(items);
4104
+ ### bot methods (high-level, await each one):
4105
+ - bot.pickupItem(/item name/i) — walk to and pick up a ground item
4106
+ - bot.equipItem(/item name/i) equip from inventory
4107
+ - bot.eatFood(/item name/i) — eat food to heal
4108
+ - bot.attackPlayer("name" or /pattern/i) — attack a player
4109
+ - bot.attackNpc("name" or /pattern/i) — attack an NPC
4110
+ - bot.walkTo(x, z) — pathfind and walk (complex, uses server pathfinding)
4104
4111
 
4105
- // Equip best weapon found
4106
- const weapon = sdk.findInventoryItem(/rune scimitar|adamant|mithril scimitar/i);
4107
- if (weapon) await bot.equipItem(weapon);
4112
+ ### sdk methods (low-level, instant):
4113
+ - sdk.sendWalk(x, z) — click a tile to walk there (fast, no pathfinding)
4114
+ - sdk.getState() full game state object
4115
+ - sdk.getState().player.worldX / .worldZ — your position
4116
+ - sdk.getState().player.hitpoints — your current HP
4117
+ - sdk.getState().player.hitpointsBase — your max HP
4118
+ - sdk.getInventory() — array of inventory items (each has .name)
4119
+ - sdk.getEquipment() — array of equipment items
4120
+ - sdk.findInventoryItem(/pattern/i) — find item in inventory
4121
+ - sdk.findGroundItem(/pattern/i) — find item on ground nearby
4122
+ - sdk.getNearbyPlayers() — nearby players (each has .name, .combatLevel, .distance, .x, .z)
4123
+ - sdk.waitForTicks(n) — wait n game ticks (~0.6s each)
4108
4124
 
4109
- // Phase 2: Fight
4110
- const endTime = Date.now() + 15_000;
4111
- while (Date.now() < endTime) {
4112
- const hp = sdk.getState().player.hitpoints;
4113
- if (hp < 25) {
4114
- const food = sdk.findInventoryItem(/swordfish|lobster|salmon|trout|bread|meat/i);
4115
- if (food) await bot.eatFood(food);
4116
- }
4117
- const players = sdk.getNearbyPlayers();
4118
- if (players.length > 0) {
4119
- const nearest = players.sort((a, b) => a.distance - b.distance)[0];
4120
- await bot.attackPlayer(nearest);
4121
- }
4122
- await sdk.waitForTicks(2);
4123
- }
4124
- return { hp: sdk.getState().player.hitpoints, inventory: sdk.getInventory(), nearbyPlayers: sdk.getNearbyPlayers() };
4125
+ ### actions (pre-built strategies, await each one):
4126
+ Actions are loaded from your bot's actions/ directory at login. Default actions:
4127
+ - actions.lootAndEquip({ maxItems, radius, foodOnly }) — scan ground, pick up best items, equip gear
4128
+ - actions.fightLoop({ eatAt, duration, target, fleeAt }) — attack nearest/weakest, auto-eat, run loop
4129
+ - actions.kite({ safeHp, duration, direction }) — retreat from enemies while eating
4130
+
4131
+ ### IMPORTANT NOTES:
4132
+ - Blocking UI is auto-dismissed before every execute_code call — you do NOT need to call bot.dismissBlockingUI()
4133
+ - bot.walkTo() uses server pathfinding (can be slow). For quick movement, use sdk.sendWalk(x, z) + sdk.waitForTicks(5)
4134
+ - State uses .player (NOT .localPlayer): sdk.getState().player.worldX (NOT state.localPlayer.x)
4135
+ - Keep execute_code calls to 15-30 seconds, then check state and adapt
4125
4136
 
4126
4137
  ## Key Tips
4127
4138
  - You start with NOTHING — picking up items is your first priority!
4128
4139
  - Grab a weapon first, then food, then armor
4129
4140
  - Risk vs reward: center has the best loot but everyone converges there
4130
- - Keep execute_code calls to 15-30 seconds, then check state and adapt
4131
4141
  - The human gives you strategy ("rush center", "play safe", "grab and run") — you turn it into code`;
4132
4142
  var server = new Server({ name: "kill-switch", version: "3.0.0" }, { capabilities: { tools: {} } });
4133
4143
  server.setRequestHandler(ListToolsRequestSchema, async () => {
@@ -4155,16 +4165,15 @@ ${GAME_DESCRIPTION}`,
4155
4165
  {
4156
4166
  name: "execute_code",
4157
4167
  description: `Execute TypeScript code on your connected bot. The code runs in an async context with three globals:
4158
- - bot: High-level actions (attackPlayer, eatFood, walkTo, equipItem, pickupItem, etc.)
4159
- - sdk: Low-level state access (getState, getNearbyPlayers, getInventory, findGroundItem, etc.)
4160
- - actions: Pre-built strategy functions loaded from your bot's actions/ directory
4168
+ - bot: High-level actions (await bot.pickupItem(/name/i), bot.equipItem(), bot.eatFood(), bot.attackPlayer(), bot.walkTo())
4169
+ - sdk: Low-level state/commands (sdk.getState(), sdk.sendWalk(x,z), sdk.getNearbyPlayers(), sdk.getInventory(), sdk.findGroundItem())
4170
+ - actions: Pre-built strategy functions from bot's actions/ directory (listed at login)
4161
4171
 
4162
- Use actions for common patterns instead of writing loops from scratch:
4163
- await actions.fightLoop({ eatAt: 25, duration: 15000 })
4164
- await actions.lootAndEquip({ maxItems: 5 })
4165
- await actions.kite({ safeHp: 40 })
4172
+ State object: sdk.getState().player.worldX, .worldZ, .hitpoints, .hitpointsBase
4173
+ Movement: sdk.sendWalk(x, z) for quick moves, bot.walkTo(x, z) for pathfinding
4174
+ Timing: await sdk.waitForTicks(n) each tick is ~0.6 seconds
4166
4175
 
4167
- Or write custom code using bot/sdk directly for full control.
4176
+ Blocking UI is auto-dismissed before your code runs do NOT call bot.dismissBlockingUI().
4168
4177
 
4169
4178
  You MUST call login before using this tool.`,
4170
4179
  inputSchema: {
@@ -4513,6 +4522,34 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
4513
4522
  console.error(`[Kill Switch] Warning: initial state not received within 20s`);
4514
4523
  }
4515
4524
  activeBotName = botName;
4525
+ const initialState = connection.sdk.getState();
4526
+ if (initialState?.player) {
4527
+ const x = initialState.player.worldX;
4528
+ const z = initialState.player.worldZ;
4529
+ const isOnTutorialIsland = x >= 3050 && x <= 3160 && z >= 3050 && z <= 3140;
4530
+ if (isOnTutorialIsland) {
4531
+ console.error(`[Kill Switch] New player detected on Tutorial Island at (${x}, ${z}), auto-skipping...`);
4532
+ const tutorialStart = Date.now();
4533
+ const TUTORIAL_TIMEOUT = 30000;
4534
+ while (Date.now() - tutorialStart < TUTORIAL_TIMEOUT) {
4535
+ try {
4536
+ await connection.bot.skipTutorial({ randomizeAppearance: true });
4537
+ } catch (e) {
4538
+ console.error(`[Kill Switch] skipTutorial call: ${e.message}`);
4539
+ }
4540
+ await new Promise((resolve) => setTimeout(resolve, 1000));
4541
+ const currentState = connection.sdk.getState();
4542
+ if (currentState?.player) {
4543
+ const cx = currentState.player.worldX;
4544
+ const cz = currentState.player.worldZ;
4545
+ if (cx < 3050 || cx > 3160 || cz < 3050 || cz > 3140) {
4546
+ console.error(`[Kill Switch] Tutorial complete! Now at (${cx}, ${cz})`);
4547
+ break;
4548
+ }
4549
+ }
4550
+ }
4551
+ }
4552
+ }
4516
4553
  const { actions, descriptions } = await loadActions(botName, connection.bot, connection.sdk);
4517
4554
  activeActions = actions;
4518
4555
  activeActionDescriptions = descriptions;
@@ -4629,6 +4666,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
4629
4666
  return value;
4630
4667
  }
4631
4668
  });
4669
+ await connection.bot.dismissBlockingUI();
4632
4670
  let result;
4633
4671
  try {
4634
4672
  result = await Promise.race([fn(cancellable(connection.bot), cancellable(connection.sdk), activeActions), timeoutPromise, cancelPromise]);
@@ -4674,10 +4712,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
4674
4712
  return errorResponse("Not connected. Call login first.");
4675
4713
  }
4676
4714
  const timeoutSecs = Math.min(Math.max(args?.timeout || 300, 10), 600);
4677
- const ARENA_MIN_X = 3070;
4678
- const ARENA_MAX_X = 3141;
4679
- const ARENA_MIN_Z = 3317;
4680
- const ARENA_MAX_Z = 3402;
4715
+ const ARENA_MIN_X = 3077;
4716
+ const ARENA_MAX_X = 3134;
4717
+ const ARENA_MIN_Z = 3324;
4718
+ const ARENA_MAX_Z = 3393;
4681
4719
  console.error(`[Kill Switch] Waiting for tournament to start (timeout: ${timeoutSecs}s)...`);
4682
4720
  const startTime = Date.now();
4683
4721
  const deadline = startTime + timeoutSecs * 1000;
@@ -4695,17 +4733,29 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
4695
4733
  "",
4696
4734
  `You've been teleported to Draynor Manor. The fight is ON!`,
4697
4735
  `Position: ${state.player.worldX}, ${state.player.worldZ}`,
4698
- `HP: ${state.player.hp}/${state.player.maxHp}`,
4736
+ `HP: ${state.player.hitpoints}/${state.player.hitpointsBase}`,
4699
4737
  "",
4700
4738
  `Nearby players: ${players.length > 0 ? players.map((p) => `${p.name} (CB ${p.combatLevel}, dist ${p.distance})`).join(", ") : "scanning..."}`,
4701
4739
  "",
4702
4740
  "REMEMBER: You die = your agent dies FOREVER. No second chances.",
4703
4741
  "",
4704
- "IMMEDIATELY:",
4742
+ "IMMEDIATELY use execute_code to start your strategy:",
4705
4743
  "1. Pick up weapons and food from the ground",
4706
4744
  "2. Equip best weapon found, then start fighting",
4707
- "3. Eat when HP gets low — you have 99 HP but no food yet!"
4745
+ "3. Eat when HP gets low — you have 99 HP but no food yet!",
4746
+ "",
4747
+ "QUICK START: await actions.lootAndEquip({ maxItems: 5 }); await actions.fightLoop({ eatAt: 25, duration: 30000 });",
4748
+ "",
4749
+ "API REMINDERS:",
4750
+ "- sdk.sendWalk(x, z) for quick movement (NOT bot.walkTo for combat)",
4751
+ "- sdk.getState().player.worldX / .worldZ / .hitpoints",
4752
+ "- Blocking UI is auto-dismissed — do NOT call bot.dismissBlockingUI()"
4708
4753
  ];
4754
+ if (activeActionDescriptions.length > 0) {
4755
+ parts.push("");
4756
+ parts.push("AVAILABLE ACTIONS:");
4757
+ parts.push(...activeActionDescriptions);
4758
+ }
4709
4759
  return { content: [{ type: "text", text: parts.join(`
4710
4760
  `) }] };
4711
4761
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kill-switch-mcp",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "Kill Switch MCP Server — AI battle royale powered by Claude Code",
5
5
  "type": "module",
6
6
  "bin": {