summer-engine 2.5.0 → 2.6.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.
Files changed (83) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +5 -4
  3. package/.codex-plugin/plugin.json +5 -4
  4. package/.cursor-plugin/plugin.json +4 -3
  5. package/.factory-plugin/plugin.json +3 -3
  6. package/AGENTS.md +6 -4
  7. package/CHANGELOG.md +20 -2
  8. package/GEMINI.md +3 -3
  9. package/README.md +113 -100
  10. package/dist/bin/summer.js +6 -1
  11. package/dist/commands/cloud.d.ts +2 -0
  12. package/dist/commands/cloud.js +80 -0
  13. package/dist/commands/doctor.js +19 -0
  14. package/dist/commands/login.js +4 -1
  15. package/dist/commands/logout.js +1 -1
  16. package/dist/commands/open.js +1 -1
  17. package/dist/commands/plan.d.ts +2 -0
  18. package/dist/commands/plan.js +60 -0
  19. package/dist/commands/run.js +132 -35
  20. package/dist/lib/api-client.js +4 -1
  21. package/dist/lib/auth.d.ts +2 -0
  22. package/dist/lib/auth.js +13 -0
  23. package/dist/lib/cloud/api.d.ts +79 -0
  24. package/dist/lib/cloud/api.js +107 -0
  25. package/dist/lib/cloud/apply.d.ts +32 -0
  26. package/dist/lib/cloud/apply.js +294 -0
  27. package/dist/lib/cloud/checkpoint.d.ts +26 -0
  28. package/dist/lib/cloud/checkpoint.js +142 -0
  29. package/dist/lib/cloud/conflicts.d.ts +55 -0
  30. package/dist/lib/cloud/conflicts.js +131 -0
  31. package/dist/lib/cloud/containment.d.ts +8 -0
  32. package/dist/lib/cloud/containment.js +52 -0
  33. package/dist/lib/cloud/diff.d.ts +39 -0
  34. package/dist/lib/cloud/diff.js +138 -0
  35. package/dist/lib/cloud/engine-bridge.d.ts +21 -0
  36. package/dist/lib/cloud/engine-bridge.js +105 -0
  37. package/dist/lib/cloud/hash-cache.d.ts +23 -0
  38. package/dist/lib/cloud/hash-cache.js +44 -0
  39. package/dist/lib/cloud/hash.d.ts +10 -0
  40. package/dist/lib/cloud/hash.js +111 -0
  41. package/dist/lib/cloud/http.d.ts +17 -0
  42. package/dist/lib/cloud/http.js +47 -0
  43. package/dist/lib/cloud/lock-path.d.ts +1 -0
  44. package/dist/lib/cloud/lock-path.js +5 -0
  45. package/dist/lib/cloud/lock.d.ts +14 -0
  46. package/dist/lib/cloud/lock.js +143 -0
  47. package/dist/lib/cloud/manifest.d.ts +6 -0
  48. package/dist/lib/cloud/manifest.js +41 -0
  49. package/dist/lib/cloud/paths.d.ts +20 -0
  50. package/dist/lib/cloud/paths.js +90 -0
  51. package/dist/lib/cloud/project-godot-merge.d.ts +32 -0
  52. package/dist/lib/cloud/project-godot-merge.js +185 -0
  53. package/dist/lib/cloud/rules.d.ts +39 -0
  54. package/dist/lib/cloud/rules.js +159 -0
  55. package/dist/lib/cloud/sync.d.ts +21 -0
  56. package/dist/lib/cloud/sync.js +518 -0
  57. package/dist/lib/cloud/transfer.d.ts +23 -0
  58. package/dist/lib/cloud/transfer.js +184 -0
  59. package/dist/lib/cloud/types.d.ts +62 -0
  60. package/dist/lib/cloud/types.js +1 -0
  61. package/dist/lib/cloud/validate-path.d.ts +23 -0
  62. package/dist/lib/cloud/validate-path.js +103 -0
  63. package/dist/lib/engine.d.ts +6 -0
  64. package/dist/lib/engine.js +36 -1
  65. package/dist/lib/game-task-plan.d.ts +42 -0
  66. package/dist/lib/game-task-plan.js +376 -0
  67. package/dist/mcp/server.js +2 -0
  68. package/dist/mcp/tools/asset-tools.js +265 -45
  69. package/dist/mcp/tools/cloud-tools.d.ts +2 -0
  70. package/dist/mcp/tools/cloud-tools.js +42 -0
  71. package/dist/mcp/tools/generate-tools.js +101 -13
  72. package/dist/mcp/tools/project-tools.js +59 -16
  73. package/gemini-extension.json +3 -3
  74. package/package.json +16 -5
  75. package/skills/3d-assets/character-model/SKILL.md +27 -5
  76. package/skills/3d-assets/environment-kit/SKILL.md +7 -2
  77. package/skills/3d-assets/organic-model/SKILL.md +4 -3
  78. package/skills/3d-assets/prop-model/SKILL.md +16 -8
  79. package/skills/3d-assets/vehicle-model/SKILL.md +4 -3
  80. package/skills/animation/animation-tree/SKILL.md +2 -0
  81. package/skills/animation/generate-motion/SKILL.md +25 -4
  82. package/skills/asset-pipeline/asset-strategy/SKILL.md +3 -2
  83. package/skills/workflow/mcpupdate/SKILL.md +134 -0
@@ -0,0 +1,376 @@
1
+ import { SKILL_REGISTRY } from "./skills-registry.js";
2
+ export const GAME_TASK_MODES = [
3
+ "auto",
4
+ "new-game",
5
+ "feature",
6
+ "asset",
7
+ "debug",
8
+ "playtest",
9
+ "polish",
10
+ "ship",
11
+ ];
12
+ export const GAME_TASK_TARGETS = [
13
+ "auto",
14
+ "2d",
15
+ "3d",
16
+ "ui",
17
+ "audio",
18
+ "animation",
19
+ "level",
20
+ "npc",
21
+ "multiplayer",
22
+ ];
23
+ export const ASSET_POLICIES = [
24
+ "reuse-first",
25
+ "ask-before-paid-generation",
26
+ "no-paid-generation",
27
+ "generate-when-clearly-needed",
28
+ ];
29
+ export const VERIFICATION_LEVELS = ["none", "fast", "full"];
30
+ const SKILL_BY_NAME = new Map(SKILL_REGISTRY.map((skill) => [skill.name, skill]));
31
+ function includesAny(text, words) {
32
+ return words.some((word) => text.includes(word));
33
+ }
34
+ function inferMode(goal, requested) {
35
+ if (requested !== "auto")
36
+ return requested;
37
+ const text = goal.toLowerCase();
38
+ const gameGenre = includesAny(text, [
39
+ "shooter",
40
+ "platformer",
41
+ "roguelike",
42
+ "rpg",
43
+ "racing",
44
+ "puzzle game",
45
+ "survival",
46
+ "tower defense",
47
+ "metroidvania",
48
+ "arena",
49
+ ]);
50
+ const buildVerb = /(^|\s)(make|build|create|start)\s/.test(text);
51
+ if (includesAny(text, ["crash", "bug", "error", "broken", "fix", "debug", "not working"]))
52
+ return "debug";
53
+ if (includesAny(text, ["export", "ship", "release", "build for", "deploy"]))
54
+ return "ship";
55
+ if (includesAny(text, ["playtest", "test the game", "feel", "tune"]))
56
+ return "playtest";
57
+ if (includesAny(text, ["asset", "model", "sprite", "texture", "sound", "music", "voice", "animation"]))
58
+ return "asset";
59
+ if (includesAny(text, ["new game", "start a game", "make a game", "prototype", "from scratch"]) || (buildVerb && gameGenre))
60
+ return "new-game";
61
+ if (includesAny(text, ["polish", "lighting", "performance", "juice", "ui pass"]))
62
+ return "polish";
63
+ return "feature";
64
+ }
65
+ function inferTarget(goal, requested) {
66
+ if (requested !== "auto")
67
+ return requested;
68
+ const text = goal.toLowerCase();
69
+ if (includesAny(text, ["3d", "model", "mesh", "glb", "character", "prop", "vehicle", "tree", "rock"]))
70
+ return "3d";
71
+ if (includesAny(text, ["2d", "sprite", "pixel", "portrait", "icon", "texture", "tileset", "skybox"]))
72
+ return "2d";
73
+ if (includesAny(text, ["sound", "sfx", "music", "audio", "voice", "dialogue", "ambient"]))
74
+ return "audio";
75
+ if (includesAny(text, ["animation", "animate", "idle", "walk", "run", "attack", "motion", "retarget"]))
76
+ return "animation";
77
+ if (includesAny(text, ["ui", "hud", "menu", "button", "inventory"]))
78
+ return "ui";
79
+ if (includesAny(text, ["level", "map", "dungeon", "arena", "room", "world"]))
80
+ return "level";
81
+ if (includesAny(text, ["npc", "enemy", "boss", "dialogue", "behavior"]))
82
+ return "npc";
83
+ if (includesAny(text, ["multiplayer", "network", "server", "host", "peer"]))
84
+ return "multiplayer";
85
+ return "general";
86
+ }
87
+ function addSkill(routes, name, why, weight) {
88
+ if (!SKILL_BY_NAME.has(name))
89
+ return;
90
+ const existing = routes.find((route) => route.name === name);
91
+ if (existing) {
92
+ if (weight > existing.weight) {
93
+ existing.weight = weight;
94
+ existing.why = why;
95
+ }
96
+ return;
97
+ }
98
+ routes.push({ name, why, weight });
99
+ }
100
+ function inferSkills(mode, target, goal) {
101
+ const text = goal.toLowerCase();
102
+ const routes = [];
103
+ const animationIntent = includesAny(text, [
104
+ "animated",
105
+ "animation",
106
+ "animate",
107
+ "idle",
108
+ "walk",
109
+ "run",
110
+ "jump",
111
+ "attack",
112
+ "motion",
113
+ "mocap",
114
+ "locomotion",
115
+ "animationtree",
116
+ "state machine",
117
+ ]);
118
+ const assetIntent = mode === "asset" ||
119
+ includesAny(text, [
120
+ "asset",
121
+ "model",
122
+ "mesh",
123
+ "glb",
124
+ "sprite",
125
+ "texture",
126
+ "sound",
127
+ "sfx",
128
+ "music",
129
+ "voice",
130
+ "animation clip",
131
+ ]);
132
+ addSkill(routes, "using-summer", "Baseline workflow for building through Summer CLI/MCP.", 100);
133
+ if (mode === "debug") {
134
+ addSkill(routes, "debug", "Primary runtime/script/diagnostics loop.", 300);
135
+ addSkill(routes, "investigating-bugs", "Systematic bug investigation workflow.", 220);
136
+ }
137
+ if (mode === "playtest") {
138
+ addSkill(routes, "play", "Run, observe, and report runtime state.", 260);
139
+ addSkill(routes, "playtesting-a-feature", "Feature-level playtest loop.", 220);
140
+ addSkill(routes, "debugging-game-feel", "Tune feel problems after runtime verification.", 160);
141
+ }
142
+ if (mode === "new-game") {
143
+ addSkill(routes, "new-project", "Create/open the project if needed.", 260);
144
+ addSkill(routes, "brainstorm-game", "Lock a small playable brief before building.", 240);
145
+ addSkill(routes, "make-game", "Build one narrow playable prototype end-to-end.", 300);
146
+ }
147
+ if (mode === "ship") {
148
+ addSkill(routes, "export-and-ship", "Export and release readiness workflow.", 280);
149
+ addSkill(routes, "tune-performance", "Performance pass before shipping.", 180);
150
+ }
151
+ if (mode === "polish") {
152
+ addSkill(routes, "art-direction", "Visual consistency and taste pass.", 200);
153
+ addSkill(routes, "3d-lighting", "Lighting/world environment pass for 3D scenes.", 190);
154
+ addSkill(routes, "game-feel", "Screen shake, hit-stop, juice, and responsiveness.", 180);
155
+ addSkill(routes, "tune-performance", "Frame budget and bottleneck pass.", 170);
156
+ }
157
+ if (assetIntent) {
158
+ addSkill(routes, "asset-strategy", "Choose reuse/import/generate before spending credits.", 260);
159
+ }
160
+ if (target === "3d" && assetIntent) {
161
+ if (includesAny(text, ["character", "player", "npc", "enemy", "boss", "humanoid", "rig"])) {
162
+ addSkill(routes, "character-model", "Humanoid T-pose, mesh, rig, and handoff to animation.", 300);
163
+ }
164
+ else if (includesAny(text, ["vehicle", "car", "ship", "spaceship", "mech", "tank", "bike"])) {
165
+ addSkill(routes, "vehicle-model", "Hard-surface vehicle generation and scene wiring.", 280);
166
+ }
167
+ else if (includesAny(text, ["tree", "rock", "mushroom", "foliage", "plant", "crystal"])) {
168
+ addSkill(routes, "organic-model", "Fast organic 3D asset generation and scatter guidance.", 270);
169
+ }
170
+ else if (includesAny(text, ["kit", "modular", "wall", "floor", "door", "pillar", "dungeon"])) {
171
+ addSkill(routes, "environment-kit", "Style-locked modular kit workflow.", 270);
172
+ }
173
+ else {
174
+ addSkill(routes, "prop-model", "Single static 3D prop workflow.", 270);
175
+ }
176
+ addSkill(routes, "scene-composition", "Instantiate/import models into robust scene structure.", 150);
177
+ if (animationIntent && includesAny(text, ["character", "player", "npc", "enemy", "boss", "humanoid", "rig"])) {
178
+ addSkill(routes, "generate-motion", "Generate idle/walk/run/jump/attack clips for the rigged character.", 275);
179
+ addSkill(routes, "animation-tree", "Wire generated clips into playback/state-machine behavior.", 210);
180
+ }
181
+ }
182
+ if (target === "3d" && !assetIntent) {
183
+ addSkill(routes, "scene-composition", "Build robust 3D scene structure.", 220);
184
+ addSkill(routes, "3d-lighting", "Give the scene readable camera, light, and environment defaults.", 180);
185
+ }
186
+ if (target === "2d" && assetIntent) {
187
+ if (includesAny(text, ["sprite sheet", "spritesheet", "run cycle", "frame grid"])) {
188
+ addSkill(routes, "sprite-sheet", "Frame grid/sprite animation workflow.", 280);
189
+ }
190
+ else if (includesAny(text, ["texture", "tile", "seamless", "wall", "floor"])) {
191
+ addSkill(routes, "tileable-texture", "Seamless texture generation and material use.", 260);
192
+ }
193
+ else if (includesAny(text, ["portrait", "dialogue", "bust"])) {
194
+ addSkill(routes, "character-portrait", "Polished dialogue portrait workflow.", 260);
195
+ }
196
+ else if (includesAny(text, ["ui", "hud", "button", "icon"])) {
197
+ addSkill(routes, "ui-graphics", "HUD/icon/UI image asset workflow.", 260);
198
+ }
199
+ else {
200
+ addSkill(routes, "concept-art", "Explore visual direction before final assets.", 220);
201
+ }
202
+ }
203
+ if (target === "audio" && assetIntent) {
204
+ if (includesAny(text, ["music", "theme", "track", "boss"])) {
205
+ addSkill(routes, "music-track", "Music generation workflow.", 280);
206
+ }
207
+ else if (includesAny(text, ["ambient", "ambience", "atmosphere"])) {
208
+ addSkill(routes, "ambient-bed", "Looping ambience workflow.", 260);
209
+ }
210
+ else if (includesAny(text, ["voice", "dialogue", "vo", "line"])) {
211
+ addSkill(routes, "voice-line", "Voice/dialogue generation workflow.", 260);
212
+ }
213
+ else {
214
+ addSkill(routes, "sound-effect", "One-shot SFX workflow.", 260);
215
+ }
216
+ addSkill(routes, "audio-direction", "Keep audio style coherent across the game.", 150);
217
+ }
218
+ if (target === "animation") {
219
+ addSkill(routes, "generate-motion", "Generate curated humanoid motion on a rigged character.", 280);
220
+ if (includesAny(text, ["blend", "state machine", "animationtree", "tree"])) {
221
+ addSkill(routes, "animation-tree", "Wire clips into an AnimationTree/state machine.", 260);
222
+ }
223
+ if (includesAny(text, ["retarget", "reuse", "another character"])) {
224
+ addSkill(routes, "retarget", "Reuse motion across compatible rigs.", 260);
225
+ }
226
+ }
227
+ if (target === "level") {
228
+ addSkill(routes, "design-level", "Build level structure, pacing, landmarks, and routes.", 270);
229
+ addSkill(routes, "scene-to-level", "Convert scene goals into playable level layout.", 210);
230
+ addSkill(routes, "scene-composition", "Use robust node/scene composition patterns.", 180);
231
+ }
232
+ if (target === "npc") {
233
+ addSkill(routes, "design-npc", "NPC behavior/dialogue integration workflow.", 270);
234
+ addSkill(routes, "gdscript-patterns", "Typed scripts/signals for NPC behavior.", 150);
235
+ }
236
+ if (target === "ui") {
237
+ addSkill(routes, "ui-basics", "HUD/menu/control composition workflow.", 270);
238
+ addSkill(routes, "gdscript-patterns", "Typed signal and state patterns for UI code.", 150);
239
+ }
240
+ if (target === "multiplayer") {
241
+ addSkill(routes, "setup-multiplayer", "Choose networking model before implementation.", 270);
242
+ addSkill(routes, "host-authoritative-state", "Server-authoritative state model.", 220);
243
+ }
244
+ if (includesAny(text, ["player controller", "fps", "first person", "wasd", "camera"])) {
245
+ addSkill(routes, "fps-controller", "Player controller, camera, collision, and input bindings.", 240);
246
+ }
247
+ if (includesAny(text, ["shooter", "arena shooter", "fps"])) {
248
+ addSkill(routes, "fps-controller", "Shooter input/camera/controller foundation.", 245);
249
+ addSkill(routes, "design-mechanic", "Implement the core shooting/combat loop.", 230);
250
+ addSkill(routes, "design-level", "Shape the arena, spawn space, cover, and pacing.", 210);
251
+ }
252
+ addSkill(routes, "gdscript-patterns", "Use direct host file edits for scripts, then verify through MCP.", 90);
253
+ addSkill(routes, "verification-before-completion", "Do not finish without a clean verification story.", 80);
254
+ return routes
255
+ .sort((a, b) => b.weight - a.weight)
256
+ .slice(0, 7)
257
+ .map((route) => {
258
+ const skill = SKILL_BY_NAME.get(route.name);
259
+ return {
260
+ id: `summer:${skill.category}/${skill.name}`,
261
+ name: skill.name,
262
+ category: skill.category,
263
+ why: route.why,
264
+ requiresMcpTools: skill.requiresMcpTools,
265
+ };
266
+ });
267
+ }
268
+ function buildMcpToolPlan(mode, target, assetPolicy, verification, goal = "") {
269
+ const text = goal.toLowerCase();
270
+ const animationIntent = includesAny(text, [
271
+ "animated",
272
+ "animation",
273
+ "animate",
274
+ "idle",
275
+ "walk",
276
+ "run",
277
+ "jump",
278
+ "attack",
279
+ "motion",
280
+ "mocap",
281
+ "locomotion",
282
+ ]);
283
+ const start = ["summer_start_game_task", "summer_get_project_context", "summer_get_agent_playbook"];
284
+ const mutate = ["summer_open_main_scene", "summer_get_scene_tree", "summer_add_node", "summer_set_prop", "summer_save_scene"];
285
+ const assets = [];
286
+ const verify = [];
287
+ if (mode === "debug") {
288
+ start.push("summer_get_diagnostics", "summer_get_script_errors", "summer_get_debugger_errors");
289
+ }
290
+ if (target === "animation") {
291
+ assets.push("summer_search_assets", "summer_get_asset", "summer_generate_motion");
292
+ }
293
+ else if (target === "3d" || target === "2d" || target === "audio") {
294
+ assets.push("summer_search_assets", "summer_list_my_assets", "summer_get_asset", "summer_import_asset_by_id");
295
+ if (assetPolicy !== "no-paid-generation") {
296
+ if (target === "3d")
297
+ assets.push("summer_generate_3d");
298
+ if (target === "2d")
299
+ assets.push("summer_generate_image");
300
+ if (target === "audio")
301
+ assets.push("summer_generate_audio");
302
+ if (target === "3d" && animationIntent)
303
+ assets.push("summer_generate_motion");
304
+ assets.push("summer_check_job");
305
+ }
306
+ }
307
+ else if (assetPolicy !== "no-paid-generation") {
308
+ assets.push("summer_search_assets", "summer_import_asset");
309
+ }
310
+ if (verification !== "none") {
311
+ verify.push("summer_get_script_errors", "summer_get_diagnostics");
312
+ }
313
+ if (verification === "full") {
314
+ verify.push("summer_clear_console", "summer_play", "summer_get_debugger_errors", "summer_stop");
315
+ }
316
+ return { start, mutate, assets, verify };
317
+ }
318
+ function buildUserGates(mode, assetPolicy) {
319
+ const gates = [
320
+ "Ask before destructive scene changes, deleting assets, or changing locked .summer memory.",
321
+ ];
322
+ if (assetPolicy !== "generate-when-clearly-needed") {
323
+ gates.push("Ask before paid generation, rigging, video, or large batch asset creation.");
324
+ }
325
+ if (mode === "new-game") {
326
+ gates.push("Lock one narrow playable loop before expanding scope.");
327
+ }
328
+ if (mode === "asset") {
329
+ gates.push("For generated 3D characters, show the unrigged preview before paid rigging.");
330
+ }
331
+ return gates;
332
+ }
333
+ export function buildGameTaskPlan(options) {
334
+ const goal = options.goal.trim();
335
+ if (!goal)
336
+ throw new Error("goal is required");
337
+ const assetPolicy = options.assetPolicy ?? "ask-before-paid-generation";
338
+ const verification = options.verification ?? "full";
339
+ const mode = inferMode(goal, options.mode ?? "auto");
340
+ const target = inferTarget(goal, options.target ?? "auto");
341
+ return {
342
+ goal,
343
+ mode,
344
+ target,
345
+ assetPolicy,
346
+ verification,
347
+ principles: [
348
+ "The agent should build a playable game slice, not a static demo.",
349
+ "Use host file edits for code/data/docs; use MCP for live scene state, imports, inspector values, play, and diagnostics.",
350
+ "Reuse/import assets before paid generation unless the user explicitly wants custom output.",
351
+ "Prefer exact IDs and structured tool results over search guesses after asset creation.",
352
+ "Verify through the engine before claiming completion.",
353
+ ],
354
+ recommendedSkills: inferSkills(mode, target, goal),
355
+ mcpToolPlan: buildMcpToolPlan(mode, target, assetPolicy, verification, goal),
356
+ hostFileWork: [
357
+ "Write and edit .gd/.cs scripts directly with host file tools.",
358
+ "Use direct file edits for JSON, markdown, project notes, and simple resources.",
359
+ "Read relevant .summer memory files when project context reports them.",
360
+ ],
361
+ userGates: buildUserGates(mode, assetPolicy),
362
+ nextAgentSteps: [
363
+ "Call summer_get_project_context and read relevant .summer memory.",
364
+ "Open the main scene if no scene is active.",
365
+ "Load the top recommended skill before mutating the project.",
366
+ "Make the smallest coherent change that advances the playable loop.",
367
+ "Save, run diagnostics, and playtest according to the verification level.",
368
+ ],
369
+ antiPatterns: [
370
+ "Do not hand-edit .tscn scene structure when Summer MCP can mutate the live scene.",
371
+ "Do not generate assets before checking library/user assets.",
372
+ "Do not search by name for an asset immediately after generation; use the returned asset ID.",
373
+ "Do not finish with only code changes when the request affects gameplay; run engine verification.",
374
+ ],
375
+ };
376
+ }
@@ -7,6 +7,7 @@ import { registerDebugTools } from "./tools/debug-tools.js";
7
7
  import { registerProjectTools } from "./tools/project-tools.js";
8
8
  import { registerAssetTools } from "./tools/asset-tools.js";
9
9
  import { registerGenerateTools } from "./tools/generate-tools.js";
10
+ import { registerCloudTools } from "./tools/cloud-tools.js";
10
11
  import { buildBootDriftNotice, fetchLatestRegistryVersion, } from "../lib/version-check.js";
11
12
  const require = createRequire(import.meta.url);
12
13
  const { version } = require("../../package.json");
@@ -115,6 +116,7 @@ export async function startMcpServer() {
115
116
  registerProjectTools(server);
116
117
  registerAssetTools(server);
117
118
  registerGenerateTools(server);
119
+ registerCloudTools(server);
118
120
  // Fire-and-forget — never block tool registration on the npm registry.
119
121
  void probeBootDrift();
120
122
  const transport = new StdioServerTransport();