@mairwunnx/minecraft-mcp 3.1.1 → 4.0.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.RU.md +2 -2
- package/README.md +2 -2
- package/dist/prompts.js +8 -8
- package/dist/scopes.js +1 -0
- package/dist/server.js +3 -1
- package/dist/tools/blocks.js +88 -98
- package/dist/tools/entities.js +19 -26
- package/dist/tools/files.js +38 -46
- package/dist/tools/items.js +108 -0
- package/dist/tools/players.js +92 -120
- package/dist/tools/scripts.js +5 -12
- package/dist/tools/server.js +118 -122
- package/dist/tools/stats.js +22 -18
- package/dist/tools/worlds.js +93 -86
- package/dist/version.js +1 -1
- package/openapi/worldapi.json +248 -7
- package/package.json +1 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { unwrap } from "../client.js";
|
|
3
|
+
import { grants } from "../scopes.js";
|
|
4
|
+
import { tool } from "../tool.js";
|
|
5
|
+
import { item, OFFLINE_NOTE, SLOT_LAYOUT } from "./common.js";
|
|
6
|
+
export function itemTools(ctx) {
|
|
7
|
+
const { api, token } = ctx;
|
|
8
|
+
const players = grants(ctx.scopes, "players:write");
|
|
9
|
+
const blocks = grants(ctx.scopes, "world:write");
|
|
10
|
+
tool(ctx, {
|
|
11
|
+
name: "edit_items",
|
|
12
|
+
title: "Give, take, or clear items",
|
|
13
|
+
description: `Change what a player's inventory or ender chest holds (players:write; ${OFFLINE_NOTE}), or a chest, barrel, or other container block (world:write). Give either player (and container) or block. \`give\` adds an item where it fits: a player's overflow drops at their feet, a block's is lost and counted in \`dropped\`. \`set\` puts an item in a slot, replacing what was there. \`take\` removes amount items from a slot and says what it took. \`clear_slot\` empties one slot; \`clear\` empties everything, a player's armor and offhand included. Cleared and taken items are gone. ${SLOT_LAYOUT} A container's slots count from 0; a double chest has 54, the left half first.`,
|
|
14
|
+
scope: { any: ["players:write", "world:write"] },
|
|
15
|
+
effect: "destructive",
|
|
16
|
+
input: {
|
|
17
|
+
action: z.enum(["give", "set", "take", "clear_slot", "clear"]),
|
|
18
|
+
player: z
|
|
19
|
+
.string()
|
|
20
|
+
.min(1)
|
|
21
|
+
.optional()
|
|
22
|
+
.describe(`Player name or UUID${ctx.player ? `; ${ctx.player}, the user, when neither player nor block is given` : ""}`),
|
|
23
|
+
container: z.enum(["inventory", "enderchest"]).default("inventory").describe("For a player"),
|
|
24
|
+
block: z
|
|
25
|
+
.object({ world: z.string().default("world"), x: z.number().int(), y: z.number().int(), z: z.number().int() })
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("A container block instead of a player"),
|
|
28
|
+
slot: z.number().int().min(0).optional().describe("For set, take, and clear_slot"),
|
|
29
|
+
item: item.optional().describe("For give and set"),
|
|
30
|
+
amount: z.number().int().min(1).optional().describe("For take: how many; the whole stack when left out"),
|
|
31
|
+
},
|
|
32
|
+
run: (args) => {
|
|
33
|
+
const needSlot = () => {
|
|
34
|
+
if (args.slot === undefined)
|
|
35
|
+
throw new Error(`${args.action} needs slot`);
|
|
36
|
+
return args.slot;
|
|
37
|
+
};
|
|
38
|
+
const needItem = () => {
|
|
39
|
+
if (!args.item)
|
|
40
|
+
throw new Error(`${args.action} needs item`);
|
|
41
|
+
return args.item;
|
|
42
|
+
};
|
|
43
|
+
const take = { amount: args.amount ?? 6400 };
|
|
44
|
+
if (args.block) {
|
|
45
|
+
if (!blocks)
|
|
46
|
+
throw new Error("Changing a container block needs world:write");
|
|
47
|
+
const { world, x, y, z: bz } = args.block;
|
|
48
|
+
const at = { params: { path: { world, x, y, z: bz } } };
|
|
49
|
+
const slot = (n) => ({ params: { path: { world, x, y, z: bz, slot: n } } });
|
|
50
|
+
switch (args.action) {
|
|
51
|
+
case "clear":
|
|
52
|
+
return unwrap(api.DELETE("/worlds/{world}/blocks/{x}/{y}/{z}/container", at), token);
|
|
53
|
+
case "give":
|
|
54
|
+
return unwrap(api.POST("/worlds/{world}/blocks/{x}/{y}/{z}/container/give", { ...at, body: { item: needItem() } }), token);
|
|
55
|
+
case "clear_slot":
|
|
56
|
+
return unwrap(api.DELETE("/worlds/{world}/blocks/{x}/{y}/{z}/container/slots/{slot}", slot(needSlot())), token);
|
|
57
|
+
case "take":
|
|
58
|
+
return unwrap(api.POST("/worlds/{world}/blocks/{x}/{y}/{z}/container/slots/{slot}/take", {
|
|
59
|
+
...slot(needSlot()),
|
|
60
|
+
body: take,
|
|
61
|
+
}), token);
|
|
62
|
+
case "set":
|
|
63
|
+
return unwrap(api.PATCH("/worlds/{world}/blocks/{x}/{y}/{z}/container/slots/{slot}", {
|
|
64
|
+
...slot(needSlot()),
|
|
65
|
+
body: needItem(),
|
|
66
|
+
}), token);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const name = args.player ?? ctx.player;
|
|
70
|
+
if (!name)
|
|
71
|
+
throw new Error("Give player or block");
|
|
72
|
+
if (!players)
|
|
73
|
+
throw new Error("Changing a player's items needs players:write");
|
|
74
|
+
const ender = args.container === "enderchest";
|
|
75
|
+
const who = { params: { path: { player: name } } };
|
|
76
|
+
const slot = (n) => ({ params: { path: { player: name, slot: n } } });
|
|
77
|
+
switch (args.action) {
|
|
78
|
+
case "clear":
|
|
79
|
+
return unwrap(ender ? api.DELETE("/players/{player}/enderchest", who) : api.DELETE("/players/{player}/inventory", who), token);
|
|
80
|
+
case "give": {
|
|
81
|
+
const body = { item: needItem() };
|
|
82
|
+
return unwrap(ender
|
|
83
|
+
? api.POST("/players/{player}/enderchest/give", { ...who, body })
|
|
84
|
+
: api.POST("/players/{player}/inventory/give", { ...who, body }), token);
|
|
85
|
+
}
|
|
86
|
+
case "clear_slot": {
|
|
87
|
+
const at = slot(needSlot());
|
|
88
|
+
return unwrap(ender
|
|
89
|
+
? api.DELETE("/players/{player}/enderchest/slots/{slot}", at)
|
|
90
|
+
: api.DELETE("/players/{player}/inventory/slots/{slot}", at), token);
|
|
91
|
+
}
|
|
92
|
+
case "take": {
|
|
93
|
+
const at = { ...slot(needSlot()), body: take };
|
|
94
|
+
return unwrap(ender
|
|
95
|
+
? api.POST("/players/{player}/enderchest/slots/{slot}/take", at)
|
|
96
|
+
: api.POST("/players/{player}/inventory/slots/{slot}/take", at), token);
|
|
97
|
+
}
|
|
98
|
+
case "set": {
|
|
99
|
+
const at = { ...slot(needSlot()), body: needItem() };
|
|
100
|
+
return unwrap(ender
|
|
101
|
+
? api.PATCH("/players/{player}/enderchest/slots/{slot}", at)
|
|
102
|
+
: api.PATCH("/players/{player}/inventory/slots/{slot}", at), token);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=items.js.map
|
package/dist/tools/players.js
CHANGED
|
@@ -1,92 +1,96 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { unwrap } from "../client.js";
|
|
3
3
|
import { tool } from "../tool.js";
|
|
4
|
-
import {
|
|
5
|
-
const container = z.enum(["inventory", "enderchest"]).default("inventory");
|
|
4
|
+
import { cursor, format, ITEM_DETAIL, limit, location, OFFLINE_NOTE, playerOrMe, SLOT_LAYOUT } from "./common.js";
|
|
6
5
|
export function playerTools(ctx) {
|
|
7
6
|
const { api, token } = ctx;
|
|
8
7
|
const who = (name) => ({ params: { path: { player: name } } });
|
|
9
8
|
const player = playerOrMe(ctx.player);
|
|
10
9
|
tool(ctx, {
|
|
11
10
|
name: "list_players",
|
|
11
|
+
untrusted: true,
|
|
12
12
|
title: "Players",
|
|
13
|
-
description: "Everyone who has played here: online state, first and last seen, playtime in seconds
|
|
13
|
+
description: "Everyone who has played here: online state, first and last seen, playtime in seconds; limit 0 only counts them. online true lists who is playing now instead, with world, game mode, health, food, level, ping, idle time, and location.",
|
|
14
14
|
scope: "players:read",
|
|
15
15
|
effect: "read",
|
|
16
16
|
input: {
|
|
17
|
-
online: z.boolean().optional(),
|
|
17
|
+
online: z.boolean().optional().describe("true: who is online now, with their state"),
|
|
18
18
|
sort: z.enum(["name", "last_seen", "playtime"]).optional(),
|
|
19
19
|
limit,
|
|
20
20
|
cursor,
|
|
21
21
|
},
|
|
22
|
-
run: (args) =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
name: "list_online_players",
|
|
26
|
-
untrusted: true,
|
|
27
|
-
title: "Online players",
|
|
28
|
-
description: "Who is playing now, with world, game mode, health, food, level, ping, idle time, and location.",
|
|
29
|
-
scope: "players:read",
|
|
30
|
-
effect: "read",
|
|
31
|
-
input: {},
|
|
32
|
-
run: () => unwrap(api.GET("/players/online"), token),
|
|
22
|
+
run: (args) => args.online
|
|
23
|
+
? unwrap(api.GET("/players/online"), token)
|
|
24
|
+
: unwrap(api.GET("/players", { params: { query: args } }), token),
|
|
33
25
|
});
|
|
34
26
|
tool(ctx, {
|
|
35
27
|
name: "get_player",
|
|
36
28
|
untrusted: true,
|
|
37
29
|
title: "Player",
|
|
38
|
-
description: `A player's profile and, while online, full state: game mode, health, food, XP, location, flight, speed, ping, client. Offline players show their last location. include adds parts in the same call: \`inventory\` and \`enderchest\` (from the saved player file while offline; ${SLOT_LAYOUT}), \`effects\` (online only), \`deaths\` (the last death place and the newest 5 with causes and killers), \`sessions\` (the newest 5), \`statistics\` (the general ones
|
|
30
|
+
description: `A player's profile and, while online, full state: game mode, health, food, XP, location, flight, speed, ping, client. Offline players show their last location. players reads up to 10 at once. include adds parts in the same call: \`inventory\` and \`enderchest\` (from the saved player file while offline; ${SLOT_LAYOUT}), \`effects\` (online only), \`deaths\` (the last death place and the newest 5 with causes and killers), \`sessions\` (the newest 5), \`statistics\` (the general ones), and \`advancements\` (counts and the newest 5). statistics gives every vanilla statistic, or one category (custom, mined, broken, crafted, used, picked_up, dropped, killed, killed_by; play_time in ticks, distances in centimeters). advancements lists every advancement with title, description, frame, and parent: \`todo\` is what's left, and with the parents it shows what to go for next. permission says whether the player is an operator and, if online, has a permission node (a server permission, such as \`worldedit.wand\`). Coordinates, inventories, and death places need players:private. ${ITEM_DETAIL}`,
|
|
39
31
|
scope: "players:read",
|
|
40
32
|
effect: "read",
|
|
41
33
|
input: {
|
|
42
|
-
player,
|
|
34
|
+
player: player.optional(),
|
|
35
|
+
players: z.array(z.string().min(1)).min(1).max(10).optional().describe("Several players instead of one"),
|
|
43
36
|
include: z
|
|
44
37
|
.array(z.enum(["inventory", "enderchest", "effects", "deaths", "sessions", "statistics", "advancements"]))
|
|
45
38
|
.optional()
|
|
46
39
|
.describe('Parts to add, such as ["inventory", "deaths"]'),
|
|
40
|
+
statistics: z.string().min(1).optional().describe("`all`, or one category such as `mined`"),
|
|
41
|
+
advancements: z.enum(["all", "done", "todo"]).optional(),
|
|
42
|
+
permission: z.string().min(1).optional().describe("A permission node to check"),
|
|
43
|
+
},
|
|
44
|
+
run: async (args) => {
|
|
45
|
+
const one = async (name) => {
|
|
46
|
+
const [view, statistics, advancements, permission] = await Promise.all([
|
|
47
|
+
unwrap(api.GET("/players/{player}", {
|
|
48
|
+
params: { path: { player: name }, query: { include: args.include?.join(",") } },
|
|
49
|
+
}), token),
|
|
50
|
+
args.statistics
|
|
51
|
+
? unwrap(api.GET("/players/{player}/statistics", {
|
|
52
|
+
params: {
|
|
53
|
+
path: { player: name },
|
|
54
|
+
query: { category: args.statistics === "all" ? undefined : args.statistics },
|
|
55
|
+
},
|
|
56
|
+
}), token)
|
|
57
|
+
: undefined,
|
|
58
|
+
args.advancements
|
|
59
|
+
? unwrap(api.GET("/players/{player}/advancements", {
|
|
60
|
+
params: {
|
|
61
|
+
path: { player: name },
|
|
62
|
+
query: { done: args.advancements === "all" ? undefined : args.advancements === "done" },
|
|
63
|
+
},
|
|
64
|
+
}), token)
|
|
65
|
+
: undefined,
|
|
66
|
+
args.permission
|
|
67
|
+
? unwrap(api.GET("/players/{player}/permissions", {
|
|
68
|
+
params: { path: { player: name }, query: { node: args.permission } },
|
|
69
|
+
}), token)
|
|
70
|
+
: undefined,
|
|
71
|
+
]);
|
|
72
|
+
return {
|
|
73
|
+
...view,
|
|
74
|
+
...(statistics && { allStatistics: statistics }),
|
|
75
|
+
...(advancements && { allAdvancements: advancements }),
|
|
76
|
+
...(permission && { permission }),
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
if (args.players)
|
|
80
|
+
return Promise.all(args.players.map((name) => one(name).catch((error) => ({
|
|
81
|
+
player: name,
|
|
82
|
+
error: error.code ?? error.message,
|
|
83
|
+
}))));
|
|
84
|
+
const name = args.player ?? ctx.player;
|
|
85
|
+
if (!name)
|
|
86
|
+
throw new Error("Give player or players");
|
|
87
|
+
return one(name);
|
|
47
88
|
},
|
|
48
|
-
run: (args) => unwrap(api.GET("/players/{player}", {
|
|
49
|
-
params: { path: { player: args.player }, query: { include: args.include?.join(",") } },
|
|
50
|
-
}), token),
|
|
51
|
-
});
|
|
52
|
-
tool(ctx, {
|
|
53
|
-
name: "get_player_statistics",
|
|
54
|
-
title: "Statistics",
|
|
55
|
-
description: "Vanilla statistics by category (custom, mined, broken, crafted, used, picked_up, dropped, killed, killed_by); live while online. play_time is in ticks (20 per second); distances in centimeters.",
|
|
56
|
-
scope: "players:read",
|
|
57
|
-
effect: "read",
|
|
58
|
-
input: { player, category: z.string().optional().describe("Only one category, such as `mined`") },
|
|
59
|
-
run: (args) => unwrap(api.GET("/players/{player}/statistics", {
|
|
60
|
-
params: { path: { player: args.player }, query: { category: args.category } },
|
|
61
|
-
}), token),
|
|
62
|
-
});
|
|
63
|
-
tool(ctx, {
|
|
64
|
-
name: "get_player_advancements",
|
|
65
|
-
untrusted: true,
|
|
66
|
-
title: "Advancements",
|
|
67
|
-
description: "Every advancement on the server with its title, description, frame, and parent, done or not, and when it was finished. done false lists what's left: with the parents, it shows what to go for next.",
|
|
68
|
-
scope: "players:read",
|
|
69
|
-
effect: "read",
|
|
70
|
-
input: { player, done: z.boolean().optional().describe("Only finished (true) or unfinished (false)") },
|
|
71
|
-
run: (args) => unwrap(api.GET("/players/{player}/advancements", {
|
|
72
|
-
params: { path: { player: args.player }, query: { done: args.done } },
|
|
73
|
-
}), token),
|
|
74
|
-
});
|
|
75
|
-
tool(ctx, {
|
|
76
|
-
name: "check_permission",
|
|
77
|
-
title: "Permissions",
|
|
78
|
-
description: "Whether a player is an operator and, if online, whether they have a permission node (a server permission, not a WorldAPI one).",
|
|
79
|
-
scope: "players:read",
|
|
80
|
-
effect: "read",
|
|
81
|
-
input: { player, node: z.string().optional().describe("Such as `worldedit.wand`") },
|
|
82
|
-
run: (args) => unwrap(api.GET("/players/{player}/permissions", {
|
|
83
|
-
params: { path: { player: args.player }, query: { node: args.node } },
|
|
84
|
-
}), token),
|
|
85
89
|
});
|
|
86
90
|
tool(ctx, {
|
|
87
91
|
name: "teleport_player",
|
|
88
92
|
title: "Teleport a player",
|
|
89
|
-
description: `Teleport to coordinates, to another player, or to a world's spawn; give exactly one. Check
|
|
93
|
+
description: `Teleport to coordinates, to another player, or to a world's spawn; give exactly one. Check the surface with get_block (no y) first to land on solid ground. ${OFFLINE_NOTE}`,
|
|
90
94
|
scope: "players:write",
|
|
91
95
|
effect: "write",
|
|
92
96
|
input: {
|
|
@@ -130,71 +134,28 @@ export function playerTools(ctx) {
|
|
|
130
134
|
});
|
|
131
135
|
tool(ctx, {
|
|
132
136
|
name: "send_message",
|
|
133
|
-
title: "Message
|
|
134
|
-
description:
|
|
137
|
+
title: "Message players",
|
|
138
|
+
description: "Send a chat message, title, or action bar text to some players, or to everyone online when players is left out. A sound plays only for named players, who must be online.",
|
|
135
139
|
scope: "players:write",
|
|
136
140
|
effect: "write",
|
|
137
141
|
input: {
|
|
138
|
-
|
|
142
|
+
players: z.array(z.string().min(1)).min(1).optional().describe("Names or UUIDs; everyone online when left out"),
|
|
139
143
|
message: z.string().min(1),
|
|
140
144
|
kind: z.enum(["chat", "title", "actionbar"]).default("chat"),
|
|
141
|
-
subtitle: z.string().optional(),
|
|
145
|
+
subtitle: z.string().optional().describe("Only for titles"),
|
|
142
146
|
sound: z.string().optional().describe("Such as `minecraft:entity.experience_orb.pickup`"),
|
|
143
147
|
format,
|
|
144
148
|
},
|
|
145
|
-
run: ({
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
});
|
|
156
|
-
tool(ctx, {
|
|
157
|
-
name: "give_item",
|
|
158
|
-
title: "Give an item",
|
|
159
|
-
description: `Add an item to a player's inventory (what doesn't fit drops at their feet) or ender chest. ${OFFLINE_NOTE}`,
|
|
160
|
-
scope: "players:write",
|
|
161
|
-
effect: "write",
|
|
162
|
-
input: { player, item, container },
|
|
163
|
-
run: (args) => unwrap(args.container === "enderchest"
|
|
164
|
-
? api.POST("/players/{player}/enderchest/give", { ...who(args.player), body: { item: args.item } })
|
|
165
|
-
: api.POST("/players/{player}/inventory/give", { ...who(args.player), body: { item: args.item } }), token),
|
|
166
|
-
});
|
|
167
|
-
tool(ctx, {
|
|
168
|
-
name: "edit_inventory",
|
|
169
|
-
title: "Edit an inventory",
|
|
170
|
-
description: `Change a player's inventory or ender chest: \`set\` puts an item in a slot, replacing what was there; \`clear_slot\` empties one slot; \`clear\` empties everything, armor and offhand included. Cleared items are gone. To add items without picking a slot, use give_item. ${SLOT_LAYOUT} ${OFFLINE_NOTE}`,
|
|
171
|
-
scope: "players:write",
|
|
172
|
-
effect: "destructive",
|
|
173
|
-
input: {
|
|
174
|
-
player,
|
|
175
|
-
action: z.enum(["set", "clear_slot", "clear"]),
|
|
176
|
-
slot: z.number().int().min(0).optional().describe("For set and clear_slot"),
|
|
177
|
-
item: item.optional().describe("For set"),
|
|
178
|
-
container,
|
|
179
|
-
},
|
|
180
|
-
run: (args) => {
|
|
181
|
-
const ender = args.container === "enderchest";
|
|
182
|
-
if (args.action === "clear")
|
|
183
|
-
return unwrap(ender
|
|
184
|
-
? api.DELETE("/players/{player}/enderchest", who(args.player))
|
|
185
|
-
: api.DELETE("/players/{player}/inventory", who(args.player)), token);
|
|
186
|
-
if (args.slot === undefined)
|
|
187
|
-
throw new Error(`${args.action} needs slot`);
|
|
188
|
-
const params = { params: { path: { player: args.player, slot: args.slot } } };
|
|
189
|
-
if (args.action === "clear_slot")
|
|
190
|
-
return unwrap(ender
|
|
191
|
-
? api.DELETE("/players/{player}/enderchest/slots/{slot}", params)
|
|
192
|
-
: api.DELETE("/players/{player}/inventory/slots/{slot}", params), token);
|
|
193
|
-
if (!args.item)
|
|
194
|
-
throw new Error("set needs item");
|
|
195
|
-
return unwrap(ender
|
|
196
|
-
? api.PATCH("/players/{player}/enderchest/slots/{slot}", { ...params, body: args.item })
|
|
197
|
-
: api.PATCH("/players/{player}/inventory/slots/{slot}", { ...params, body: args.item }), token);
|
|
149
|
+
run: async ({ players, sound, ...body }) => {
|
|
150
|
+
if (!players)
|
|
151
|
+
return unwrap(api.POST("/server/broadcast", { body }), token);
|
|
152
|
+
const sent = [];
|
|
153
|
+
for (const name of players)
|
|
154
|
+
sent.push({
|
|
155
|
+
player: name,
|
|
156
|
+
...(await unwrap(api.POST("/players/{player}/message", { ...who(name), body: { ...body, sound } }), token)),
|
|
157
|
+
});
|
|
158
|
+
return sent.length === 1 ? sent[0] : sent;
|
|
198
159
|
},
|
|
199
160
|
});
|
|
200
161
|
const effect = z.object({
|
|
@@ -229,20 +190,31 @@ export function playerTools(ctx) {
|
|
|
229
190
|
});
|
|
230
191
|
tool(ctx, {
|
|
231
192
|
name: "set_advancement",
|
|
232
|
-
title: "Grant or revoke
|
|
233
|
-
description: `Complete every criterion of
|
|
193
|
+
title: "Grant or revoke advancements",
|
|
194
|
+
description: `Complete every criterion of advancements for a player (done true), or take them all back (done false). ${OFFLINE_NOTE}`,
|
|
234
195
|
scope: "players:write",
|
|
235
196
|
effect: "idempotent",
|
|
236
197
|
input: {
|
|
237
198
|
player,
|
|
238
|
-
|
|
199
|
+
keys: z
|
|
200
|
+
.array(z.string().min(1))
|
|
201
|
+
.min(1)
|
|
202
|
+
.max(50)
|
|
203
|
+
.describe('Advancement keys, such as ["minecraft:story/mine_diamond"]'),
|
|
239
204
|
done: z.boolean(),
|
|
240
205
|
},
|
|
241
|
-
run: (args) => {
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
206
|
+
run: async (args) => {
|
|
207
|
+
const results = [];
|
|
208
|
+
for (const key of args.keys) {
|
|
209
|
+
const params = { params: { path: { player: args.player, key } } };
|
|
210
|
+
results.push({
|
|
211
|
+
key,
|
|
212
|
+
...(await unwrap(args.done
|
|
213
|
+
? api.POST("/players/{player}/advancements/{key}", { ...params, body: {} })
|
|
214
|
+
: api.DELETE("/players/{player}/advancements/{key}", params), token)),
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
return results.length === 1 ? results[0] : results;
|
|
246
218
|
},
|
|
247
219
|
});
|
|
248
220
|
}
|
package/dist/tools/scripts.js
CHANGED
|
@@ -38,26 +38,19 @@ export function scriptTools(ctx) {
|
|
|
38
38
|
});
|
|
39
39
|
tool(ctx, {
|
|
40
40
|
name: "list_java_scripts",
|
|
41
|
-
title: "Loaded scripts",
|
|
42
|
-
description: "Resident scripts with their listener and task counts and error count.",
|
|
43
|
-
scope: "code",
|
|
44
|
-
effect: "read",
|
|
45
|
-
input: {},
|
|
46
|
-
run: () => unwrap(api.GET("/scripts"), token),
|
|
47
|
-
});
|
|
48
|
-
tool(ctx, {
|
|
49
|
-
name: "get_java_script",
|
|
50
41
|
untrusted: true,
|
|
51
|
-
title: "
|
|
52
|
-
description: "
|
|
42
|
+
title: "Loaded scripts",
|
|
43
|
+
description: "Resident scripts with their listener and task counts and error count. With id, that script with its source, plus the latest lines it wrote with ctx.log and errors from its handlers and tasks; logs false leaves the log out.",
|
|
53
44
|
scope: "code",
|
|
54
45
|
effect: "read",
|
|
55
46
|
input: {
|
|
56
|
-
id: z.string(),
|
|
47
|
+
id: z.string().optional().describe("One script in full"),
|
|
57
48
|
logs: z.boolean().default(true),
|
|
58
49
|
limit: z.number().int().min(1).max(10000).optional().describe("Log lines to return"),
|
|
59
50
|
},
|
|
60
51
|
run: async (args) => {
|
|
52
|
+
if (!args.id)
|
|
53
|
+
return unwrap(api.GET("/scripts"), token);
|
|
61
54
|
const path = { id: args.id };
|
|
62
55
|
const [script, logs] = await Promise.all([
|
|
63
56
|
unwrap(api.GET("/scripts/{id}", { params: { path } }), token),
|