breakpoint-mcp 1.83.0 โ 1.84.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/capabilities.js +101 -0
- package/dist/capabilities.js.map +1 -1
- package/dist/client-caps.js +75 -0
- package/dist/client-caps.js.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/peers.js +10 -1
- package/dist/peers.js.map +1 -1
- package/dist/schemas.js +36 -4
- package/dist/schemas.js.map +1 -1
- package/dist/tool-census.js +47 -0
- package/dist/tool-census.js.map +1 -0
- package/dist/tools/cli.js +11 -1
- package/dist/tools/cli.js.map +1 -1
- package/dist/tools/dap.js +2 -3
- package/dist/tools/dap.js.map +1 -1
- package/dist/tools/lsp.js +1 -1
- package/dist/tools/lsp.js.map +1 -1
- package/dist/tools/processes.js +23 -4
- package/dist/tools/processes.js.map +1 -1
- package/dist/tools/runtime.js +15 -4
- package/dist/tools/runtime.js.map +1 -1
- package/dist/tools/tabletop.js +120 -10
- package/dist/tools/tabletop.js.map +1 -1
- package/dist/tools/vcs.js +168 -24
- package/dist/tools/vcs.js.map +1 -1
- package/package.json +1 -1
package/dist/tools/tabletop.js
CHANGED
|
@@ -1411,6 +1411,96 @@ export function registerTabletopTools(server, bridge, config) {
|
|
|
1411
1411
|
function replacedField(existed) {
|
|
1412
1412
|
return existed ? { replaced: true } : {};
|
|
1413
1413
|
}
|
|
1414
|
+
/**
|
|
1415
|
+
* Which scene the editor is editing AFTER this call โ 298.
|
|
1416
|
+
*
|
|
1417
|
+
* ๐ด FOUR TOOLS MOVED THE EDITOR AND NONE OF THEM SAID SO, AND THE FACT WAS
|
|
1418
|
+
* ALREADY WRITTEN DOWN TWICE IN THIS REPOSITORY. `guardWriteTarget`'s own
|
|
1419
|
+
* comment forty lines up says the addon's `scene.new` "calls
|
|
1420
|
+
* `EditorInterface.open_scene_from_path(path)`"; `tabletop-plane.integration.mjs`
|
|
1421
|
+
* opens its live family with *every `*_create` decomposes onto scene.new โ โฆ
|
|
1422
|
+
* โ scene.save, which SWITCHES the edited scene, so the four disk writers run
|
|
1423
|
+
* first and the in-scene work follows one scene_open*. Both are correct. Both
|
|
1424
|
+
* are in files a CALLER never opens, and the tool surface said nothing โ no
|
|
1425
|
+
* description, no field, nothing in `TOOL_CATALOG.md`.
|
|
1426
|
+
*
|
|
1427
|
+
* ๐ด MEASURED AT 298 ON A LIVE GODOT 4.7, ON THE DEFAULT SURFACE. Compose a
|
|
1428
|
+
* table, call `card_template_create`, then `card_instance` with `parent: "."`
|
|
1429
|
+
* exactly as its own description invites: the card is created, `bound` lists
|
|
1430
|
+
* the slot, `isError` is false โ and the card is in the CARD TEMPLATE. The
|
|
1431
|
+
* user's table is untouched. Every call in that sequence answers success.
|
|
1432
|
+
*
|
|
1433
|
+
* ๐ต IT IS READ, NOT ASSUMED. `spec.path` is what the compose ASKED for; this
|
|
1434
|
+
* is what the editor ANSWERS, which is the difference between an echo and a
|
|
1435
|
+
* measurement (155 ยง2) โ and the two can differ, because `clearStaleTab` may
|
|
1436
|
+
* have moved the editor before the write and a failed open would leave it
|
|
1437
|
+
* somewhere else again.
|
|
1438
|
+
*
|
|
1439
|
+
* ๐ต AND IT IS SPREAD, NOT RESTATED, FOR `wroteDestination`'s REASON (284): a
|
|
1440
|
+
* fifth composite that decomposes onto `scene.new` cannot be added with the
|
|
1441
|
+
* reporting half missing. `contract_check` check 36 holds that population.
|
|
1442
|
+
*
|
|
1443
|
+
* ๐ 299 โ AND THE ANSWER TO 298's FINDING IS NOW THE ONE 298 DECLINED TO
|
|
1444
|
+
* TAKE IN-SESSION. 298 filed `tabletop-creators-leave-the-caller-elsewhere`
|
|
1445
|
+
* as a `user` row rather than deciding it: whether the four should RESTORE
|
|
1446
|
+
* the caller's scene is a change to what a shipped tool does to the editor,
|
|
1447
|
+
* and this project steers those before it builds them. Steered at 299 โ
|
|
1448
|
+
* restore โ with the argument that decided it recorded here, because the
|
|
1449
|
+
* next person to read this block will want to know why the behaviour flipped
|
|
1450
|
+
* one session after it was documented: **298's description never reached a
|
|
1451
|
+
* user.** The merge sat untagged behind a release backlog, so both the
|
|
1452
|
+
* warning label and its removal ship in the same cut and no caller ever saw
|
|
1453
|
+
* the surface promise a move it no longer makes.
|
|
1454
|
+
*/
|
|
1455
|
+
/** Which scene the editor is editing right now, or `null` for none open. */
|
|
1456
|
+
async function currentEditedScene() {
|
|
1457
|
+
const open = await emit("scene.list_open", {});
|
|
1458
|
+
return typeof open?.current === "string" ? open.current : null;
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Put the caller back on the scene they were editing when the call arrived.
|
|
1462
|
+
*
|
|
1463
|
+
* ๐ด BEST EFFORT, AND DELIBERATELY NOT A FAILURE PATH. The file is written
|
|
1464
|
+
* and saved by the time this runs. Throwing here would report a create that
|
|
1465
|
+
* SUCCEEDED as an error, and the caller's correct response to an error โ
|
|
1466
|
+
* retry โ would write it a second time. So a reopen that cannot happen
|
|
1467
|
+
* leaves the editor where the decomposition left it, and the caller learns
|
|
1468
|
+
* that from `edited_scene`, which is READ afterwards and therefore cannot
|
|
1469
|
+
* agree with a restore that did not occur. The honest report replaces the
|
|
1470
|
+
* exception; it does not merely soften it.
|
|
1471
|
+
*
|
|
1472
|
+
* ๐ต THREE NO-OPS, EACH FOR ITS OWN REASON. `null` means the editor held no
|
|
1473
|
+
* scene, so there is nothing to go back TO and the created scene stays open
|
|
1474
|
+
* โ inventing a close would be a second unasked-for movement. Already
|
|
1475
|
+
* current means the decomposition did not move us, or `clearStaleTab`
|
|
1476
|
+
* already put us back. And a `before` whose file is gone cannot be reopened:
|
|
1477
|
+
* `scene.open` would answer *Scene not found* and turn a successful create
|
|
1478
|
+
* into a refusal, which is the failure path this function exists to avoid.
|
|
1479
|
+
*/
|
|
1480
|
+
async function restoreEditedScene(before) {
|
|
1481
|
+
if (before === null)
|
|
1482
|
+
return;
|
|
1483
|
+
if (await currentEditedScene() === before)
|
|
1484
|
+
return;
|
|
1485
|
+
if (!fs.existsSync(resolveInsideProject(before, config.projectPath, "path")))
|
|
1486
|
+
return;
|
|
1487
|
+
try {
|
|
1488
|
+
await emit("scene.open", { path: before });
|
|
1489
|
+
}
|
|
1490
|
+
catch {
|
|
1491
|
+
// Swallowed on purpose โ see the comment above. `edited_scene` reports
|
|
1492
|
+
// where the editor actually is, so a failed restore is visible, not lost.
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Restore, then REPORT โ in that order, and the order is the claim. Reading
|
|
1497
|
+
* first and restoring after would answer with a path the editor had already
|
|
1498
|
+
* left, which is 155 ยง2's echo wearing a measurement's clothes one more time.
|
|
1499
|
+
*/
|
|
1500
|
+
async function editedSceneField(before) {
|
|
1501
|
+
await restoreEditedScene(before);
|
|
1502
|
+
return { edited_scene: await currentEditedScene() };
|
|
1503
|
+
}
|
|
1414
1504
|
/**
|
|
1415
1505
|
* The second half, run only AFTER the confirmation gate has been cleared โ
|
|
1416
1506
|
* closing a scene tab is a visible side effect and must not happen on a call
|
|
@@ -1477,7 +1567,7 @@ export function registerTabletopTools(server, bridge, config) {
|
|
|
1477
1567
|
title: "Create card template",
|
|
1478
1568
|
description: "Build a reusable card scene (a PackedScene) from a slot spec, with a generated script-backed set_data() / set_face(). " +
|
|
1479
1569
|
"Named slots (label / rich_text / texture / panel / badge) become the card's regions; card_instance and card_deck_from_table " +
|
|
1480
|
-
"bind data to them by slot name. Optional inline theme and a two-sided card back. DESTRUCTIVE (writes a scene + script) โ gated by confirmation.",
|
|
1570
|
+
"bind data to them by slot name. Optional inline theme and a two-sided card back. DESTRUCTIVE (writes a scene + script) โ gated by confirmation. Puts the editor back on the scene you had open; `edited_scene` names where it landed.",
|
|
1481
1571
|
inputSchema: {
|
|
1482
1572
|
path: z.string().describe("Where to save the template scene, e.g. res://ui/cards/Card.tscn"),
|
|
1483
1573
|
size: z.object({ width: z.number().int().positive(), height: z.number().int().positive() }).describe("Card dimensions in px"),
|
|
@@ -1535,8 +1625,13 @@ export function registerTabletopTools(server, bridge, config) {
|
|
|
1535
1625
|
if (blocked)
|
|
1536
1626
|
return blocked;
|
|
1537
1627
|
try {
|
|
1628
|
+
// ๐ 299 โ READ BEFORE THE FIRST THING THAT CAN MOVE THE EDITOR, which is
|
|
1629
|
+
// `clearStaleTab` and not `scene.new`: on an overwrite the stale-tab close
|
|
1630
|
+
// has already changed `current` by the time the decomposition runs, so a
|
|
1631
|
+
// capture taken any later restores the caller to the wrong scene.
|
|
1632
|
+
const before = await currentEditedScene();
|
|
1538
1633
|
await clearStaleTab(a.path);
|
|
1539
|
-
return ok({ ...await emitCardTemplate(emit, a), ...replacedField(existed) });
|
|
1634
|
+
return ok({ ...await emitCardTemplate(emit, a), ...replacedField(existed), ...(await editedSceneField(before)) });
|
|
1540
1635
|
}
|
|
1541
1636
|
catch (err) {
|
|
1542
1637
|
return fail(err);
|
|
@@ -1575,7 +1670,7 @@ export function registerTabletopTools(server, bridge, config) {
|
|
|
1575
1670
|
server.registerTool("card_hand_layout", {
|
|
1576
1671
|
title: "Lay out a hand of cards",
|
|
1577
1672
|
description: "Instance N cards under a container and arrange them as a row, fan, stack, or grid. Undoable node authoring. Each card carries its own " +
|
|
1578
|
-
"data (bound via the template's set_data) and face state
|
|
1673
|
+
"data (bound via the template's set_data) and face state.",
|
|
1579
1674
|
inputSchema: {
|
|
1580
1675
|
template_path: z.string().describe("Card template scene, e.g. res://ui/cards/Card.tscn"),
|
|
1581
1676
|
parent: z.string().describe("Container node path the cards are instanced under; \".\" for the root"),
|
|
@@ -1700,7 +1795,7 @@ export function registerTabletopTools(server, bridge, config) {
|
|
|
1700
1795
|
title: "Create board scene",
|
|
1701
1796
|
description: "Build a board scene whose children are addressable cells (each a cell_<id> node in the board_cells group) from a ring, grid, or explicit-cells layout. " +
|
|
1702
1797
|
"Cells are Marker2D (or Control) anchors positioned by pure layout math; an optional background (color or res:// art) sits behind them. " +
|
|
1703
|
-
"General-purpose โ cells carry only caller-supplied ids. DESTRUCTIVE (writes a scene) โ gated by confirmation.
|
|
1798
|
+
"General-purpose โ cells carry only caller-supplied ids. DESTRUCTIVE (writes a scene) โ gated by confirmation. Puts the editor back on the scene you had open; `edited_scene` names where it landed.",
|
|
1704
1799
|
inputSchema: {
|
|
1705
1800
|
path: z.string().describe("Where to save the board scene, e.g. res://ui/board/Board.tscn"),
|
|
1706
1801
|
layout: boardLayout.describe("ring{cells[]} | grid{rows,cols} | cells{cells[{id,x,y}]}"),
|
|
@@ -1733,8 +1828,13 @@ export function registerTabletopTools(server, bridge, config) {
|
|
|
1733
1828
|
if (blocked)
|
|
1734
1829
|
return blocked;
|
|
1735
1830
|
try {
|
|
1831
|
+
// ๐ 299 โ READ BEFORE THE FIRST THING THAT CAN MOVE THE EDITOR, which is
|
|
1832
|
+
// `clearStaleTab` and not `scene.new`: on an overwrite the stale-tab close
|
|
1833
|
+
// has already changed `current` by the time the decomposition runs, so a
|
|
1834
|
+
// capture taken any later restores the caller to the wrong scene.
|
|
1835
|
+
const before = await currentEditedScene();
|
|
1736
1836
|
await clearStaleTab(a.path);
|
|
1737
|
-
return ok({ ...await emitBoardCreate(emit, a), ...replacedField(existed) });
|
|
1837
|
+
return ok({ ...await emitBoardCreate(emit, a), ...replacedField(existed), ...(await editedSceneField(before)) });
|
|
1738
1838
|
}
|
|
1739
1839
|
catch (err) {
|
|
1740
1840
|
return fail(err);
|
|
@@ -1765,7 +1865,7 @@ export function registerTabletopTools(server, bridge, config) {
|
|
|
1765
1865
|
title: "Create tile-backed board",
|
|
1766
1866
|
description: "Build a tile-backed board scene: a TileMapLayer grid whose cells are addressable by integer [x, y] tile coordinates (cols wide ร rows tall). " +
|
|
1767
1867
|
"The layer binds a TileSet โ a supplied `tileset` .tres, or a fresh empty one created at <scene>_tiles.tres โ so it has a real tile_size (the coordinate frame placement uses); `paint` optionally fills the whole grid with one tile from the bound tileset. " +
|
|
1768
|
-
"General-purpose โ cells carry only coordinates.
|
|
1868
|
+
"General-purpose โ cells carry only coordinates. DESTRUCTIVE (writes a scene, and a TileSet .tres unless `tileset` is supplied) โ gated by confirmation. Puts the editor back on the scene you had open; `edited_scene` names where it landed.",
|
|
1769
1869
|
inputSchema: {
|
|
1770
1870
|
path: z.string().describe("Where to save the board scene, e.g. res://ui/board/TileBoard.tscn"),
|
|
1771
1871
|
rows: z.number().int().positive().describe("Grid row count (cell y ranges 0..rows-1)"),
|
|
@@ -1801,8 +1901,13 @@ export function registerTabletopTools(server, bridge, config) {
|
|
|
1801
1901
|
if (blocked)
|
|
1802
1902
|
return blocked;
|
|
1803
1903
|
try {
|
|
1904
|
+
// ๐ 299 โ READ BEFORE THE FIRST THING THAT CAN MOVE THE EDITOR, which is
|
|
1905
|
+
// `clearStaleTab` and not `scene.new`: on an overwrite the stale-tab close
|
|
1906
|
+
// has already changed `current` by the time the decomposition runs, so a
|
|
1907
|
+
// capture taken any later restores the caller to the wrong scene.
|
|
1908
|
+
const before = await currentEditedScene();
|
|
1804
1909
|
await clearStaleTab(a.path);
|
|
1805
|
-
return ok({ ...await emitBoardTileCreate(emit, a), ...replacedField(existed) });
|
|
1910
|
+
return ok({ ...await emitBoardTileCreate(emit, a), ...replacedField(existed), ...(await editedSceneField(before)) });
|
|
1806
1911
|
}
|
|
1807
1912
|
catch (err) {
|
|
1808
1913
|
return fail(err);
|
|
@@ -1812,7 +1917,7 @@ export function registerTabletopTools(server, bridge, config) {
|
|
|
1812
1917
|
server.registerTool("board_tile_place", {
|
|
1813
1918
|
title: "Place a node on a tile coordinate",
|
|
1814
1919
|
description: "Snap an existing node (a card or piece instance) onto a TileMapLayer cell by integer [x, y] tile coordinate. Undoable node authoring. " +
|
|
1815
|
-
"The cell's local position is computed from `tile_size` โ centre `(coord + 0.5) ร tile_size` (default) or corner `coord ร tile_size` โ matching Godot's TileMapLayer.map_to_local, plus an optional `align` offset.
|
|
1920
|
+
"The cell's local position is computed from `tile_size` โ centre `(coord + 0.5) ร tile_size` (default) or corner `coord ร tile_size` โ matching Godot's TileMapLayer.map_to_local, plus an optional `align` offset. Decomposes onto node.reparent + node.set_property. Returns the node's new path and local position.",
|
|
1816
1921
|
inputSchema: {
|
|
1817
1922
|
layer: z.string().describe("TileMapLayer node path in the open scene"),
|
|
1818
1923
|
node: z.string().describe("Node path of the node to place (a card / piece already in the scene)"),
|
|
@@ -1835,7 +1940,7 @@ export function registerTabletopTools(server, bridge, config) {
|
|
|
1835
1940
|
server.registerTool("piece_template_create", {
|
|
1836
1941
|
title: "Create piece template",
|
|
1837
1942
|
description: "Build a reusable piece (token) scene from a spec: an Art node (Sprite2D under a Node2D root, TextureRect under a Control root), an optional Label, an optional hit area (Area2D + CollisionShape2D), and an optional two-sided Back, plus a generated script-backed set_data() / set_face(). set_data binds art / color / label; set_face flips face/back visibility. " +
|
|
1838
|
-
"
|
|
1943
|
+
"DESTRUCTIVE (writes a scene + script) โ gated by confirmation. Puts the editor back on the scene you had open; `edited_scene` names where it landed.",
|
|
1839
1944
|
inputSchema: {
|
|
1840
1945
|
path: z.string().describe("Where to save the template scene, e.g. res://ui/pieces/Piece.tscn"),
|
|
1841
1946
|
size: z.object({ width: z.number().int().positive(), height: z.number().int().positive() }).describe("Token size in px (drives the hit-area extents and, for a Control root, the Art size)"),
|
|
@@ -1881,8 +1986,13 @@ export function registerTabletopTools(server, bridge, config) {
|
|
|
1881
1986
|
if (blocked)
|
|
1882
1987
|
return blocked;
|
|
1883
1988
|
try {
|
|
1989
|
+
// ๐ 299 โ READ BEFORE THE FIRST THING THAT CAN MOVE THE EDITOR, which is
|
|
1990
|
+
// `clearStaleTab` and not `scene.new`: on an overwrite the stale-tab close
|
|
1991
|
+
// has already changed `current` by the time the decomposition runs, so a
|
|
1992
|
+
// capture taken any later restores the caller to the wrong scene.
|
|
1993
|
+
const before = await currentEditedScene();
|
|
1884
1994
|
await clearStaleTab(a.path);
|
|
1885
|
-
return ok({ ...await emitPieceTemplate(emit, a), ...replacedField(existed) });
|
|
1995
|
+
return ok({ ...await emitPieceTemplate(emit, a), ...replacedField(existed), ...(await editedSceneField(before)) });
|
|
1886
1996
|
}
|
|
1887
1997
|
catch (err) {
|
|
1888
1998
|
return fail(err);
|