tabtree-mcp 1.6.0 → 1.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.
- package/package.json +1 -1
- package/tabtree-mcp.mjs +31 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tabtree-mcp",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"mcpName": "app.tabtree/tabtree",
|
|
5
5
|
"description": "Let Claude read your TabTree library and build mind maps, kanban boards and whiteboards in your TabTree account — team spaces included.",
|
|
6
6
|
"repository": {
|
package/tabtree-mcp.mjs
CHANGED
|
@@ -672,6 +672,13 @@ function fitSize(text, w, h, kind, want){
|
|
|
672
672
|
return { size: 9, shrunk: true, readable: false };
|
|
673
673
|
}
|
|
674
674
|
|
|
675
|
+
// L'ordre de superposition (`z`, ≡ `zOk` de l'app) : un entier [-9, 9], 0 omis. À z égal l'app peint
|
|
676
|
+
// par nature — images < formes < flèches < tracés < post-it — donc un panneau coloré REMPLI recouvre
|
|
677
|
+
// un logo posé dedans : `z:-1` sur le panneau (ou `z:1` sur l'image) est ce qui le remet devant.
|
|
678
|
+
function zMcp(v){
|
|
679
|
+
const n = Math.round(+v);
|
|
680
|
+
return (v != null && isFinite(n) && n >= -9 && n <= 9 && n !== 0) ? n : undefined;
|
|
681
|
+
}
|
|
675
682
|
function buildBoardDoc(name, elements, connections, style){
|
|
676
683
|
if(!Array.isArray(elements) || !elements.length) throw new Error("`elements` must be a non-empty list.");
|
|
677
684
|
const imgCount = elements.filter(e=>e && e.kind === "image").length;
|
|
@@ -689,7 +696,7 @@ function buildBoardDoc(name, elements, connections, style){
|
|
|
689
696
|
if(w && !h) h = Math.max(24, Math.round(w / ar));
|
|
690
697
|
else if(h && !w) w = Math.max(24, Math.round(h * ar));
|
|
691
698
|
else if(!w && !h){ if(ar >= 1){ w = 220; h = Math.max(24, Math.round(220 / ar)); } else { h = 220; w = Math.max(24, Math.round(220 * ar)); } }
|
|
692
|
-
return { lid: String(e.id != null ? e.id : i), kind: "image", text: "", src: im.src,
|
|
699
|
+
return { lid: String(e.id != null ? e.id : i), kind: "image", text: "", src: im.src, z: zMcp(e.z),
|
|
693
700
|
x: Number.isFinite(+e.x) && e.x!=null ? Math.round(+e.x) : null,
|
|
694
701
|
y: Number.isFinite(+e.y) && e.y!=null ? Math.round(+e.y) : null, w, h };
|
|
695
702
|
}
|
|
@@ -708,7 +715,8 @@ function buildBoardDoc(name, elements, connections, style){
|
|
|
708
715
|
// L'image sans octets sur un élément de board (2026-09-03) : même frontière que
|
|
709
716
|
// pour un nœud — un id inventé retombe sur « aucune image », jamais sur du balisage.
|
|
710
717
|
// Pas sur un secteur, un gradin ou un chevron : leur silhouette n'a pas de « haut ».
|
|
711
|
-
pic: (e.pic != null && !["arc","trap","chev"].includes(kind)) ? okPic(String(e.pic)) : ""
|
|
718
|
+
pic: (e.pic != null && !["arc","trap","chev"].includes(kind)) ? okPic(String(e.pic)) : "",
|
|
719
|
+
z: zMcp(e.z) };
|
|
712
720
|
});
|
|
713
721
|
const byId = new Map();
|
|
714
722
|
for(const e of els){
|
|
@@ -775,10 +783,10 @@ function buildBoardDoc(name, elements, connections, style){
|
|
|
775
783
|
for(const e of els){
|
|
776
784
|
if(e.kind==="image"){
|
|
777
785
|
refOf.set(e.lid, "im:" + images.length);
|
|
778
|
-
images.push({ id: "im" + images.length, src: e.src, x: e.x, y: e.y, w: e.w, h: e.h });
|
|
786
|
+
images.push({ id: "im" + images.length, src: e.src, x: e.x, y: e.y, w: e.w, h: e.h, z: e.z });
|
|
779
787
|
} else if(e.kind==="sticky"){
|
|
780
788
|
refOf.set(e.lid, "st:" + stickies.length);
|
|
781
|
-
stickies.push({ text:e.text, x:e.x, y:e.y, w:e.w, h:e.h, color:e.color, size:e.size||undefined, pic:e.pic||undefined });
|
|
789
|
+
stickies.push({ text:e.text, x:e.x, y:e.y, w:e.w, h:e.h, color:e.color, size:e.size||undefined, pic:e.pic||undefined, z:e.z });
|
|
782
790
|
} else {
|
|
783
791
|
refOf.set(e.lid, "sh:" + shapes.length);
|
|
784
792
|
shapes.push({ kind:e.kind, x:e.x, y:e.y, w:e.w, h:e.h, color:e.kind==="text" ? "#ffffff" : e.color, text:e.text, size:e.size||undefined,
|
|
@@ -786,7 +794,8 @@ function buildBoardDoc(name, elements, connections, style){
|
|
|
786
794
|
tk: e.tk != null ? e.tk : undefined,
|
|
787
795
|
a0: e.a0 != null ? e.a0 : undefined,
|
|
788
796
|
a1: e.a1 != null ? e.a1 : undefined,
|
|
789
|
-
ir: e.ir != null ? e.ir : undefined
|
|
797
|
+
ir: e.ir != null ? e.ir : undefined,
|
|
798
|
+
z: e.z });
|
|
790
799
|
}
|
|
791
800
|
}
|
|
792
801
|
const arrows = conns.map(c=>{
|
|
@@ -995,15 +1004,27 @@ function boardToText(doc){
|
|
|
995
1004
|
const o = arr[i];
|
|
996
1005
|
return o ? `${tag}${i} ${JSON.stringify((o.text||"(no text)").slice(0,60))}` : tag+i+" ?";
|
|
997
1006
|
};
|
|
1007
|
+
const zs = o=>o && o.z ? ` z:${o.z}` : "";
|
|
998
1008
|
lines.push(`Shapes (${(doc.shapes||[]).length}):`);
|
|
999
|
-
(doc.shapes||[]).forEach((s,i)=>lines.push(` sh:${i} [${s.kind}] ${JSON.stringify((s.text||"").slice(0,80))} @(${s.x},${s.y}) ${s.w}×${s.h}`));
|
|
1009
|
+
(doc.shapes||[]).forEach((s,i)=>lines.push(` sh:${i} [${s.kind}] ${JSON.stringify((s.text||"").slice(0,80))} @(${s.x},${s.y}) ${s.w}×${s.h}${zs(s)}`));
|
|
1010
|
+
// Les images d'un board (2026-10-23) : le type et le poids, jamais les octets — une data URL de
|
|
1011
|
+
// 200 Ko dans la réponse noierait tout le reste, et Claude n'en lirait rien.
|
|
1012
|
+
const imgs = (doc.images||[]);
|
|
1013
|
+
if(imgs.length){
|
|
1014
|
+
lines.push(`Images (${imgs.length}):`);
|
|
1015
|
+
imgs.forEach((m,i)=>{
|
|
1016
|
+
const t = (/^data:image\/([a-z+.-]+)/i.exec(m.src||"") || [,"?"])[1].replace("svg+xml","svg");
|
|
1017
|
+
lines.push(` im:${i} [${t}, ${Math.round(String(m.src||"").length * 3 / 4 / 1024)} KB] @(${m.x},${m.y}) ${m.w}×${m.h}${zs(m)}`);
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1000
1020
|
if((doc.stickies||[]).length){
|
|
1001
1021
|
lines.push(`Sticky notes (${doc.stickies.length}):`);
|
|
1002
1022
|
doc.stickies.forEach((s,i)=>lines.push(` st:${i} ${JSON.stringify((s.text||"").slice(0,80))} @(${s.x},${s.y})`));
|
|
1003
1023
|
}
|
|
1004
1024
|
const named = ref=>{
|
|
1005
1025
|
if(typeof ref !== "string") return null;
|
|
1006
|
-
const m = /^(sh|st):(\d+)$/.exec(ref); if(!m) return null;
|
|
1026
|
+
const m = /^(sh|st|im):(\d+)$/.exec(ref); if(!m) return null;
|
|
1027
|
+
if(m[1]==="im") return (doc.images||[])[+m[2]] ? "im:" + m[2] + " (image)" : "im:" + m[2] + " ?";
|
|
1007
1028
|
return label(m[1]==="sh" ? (doc.shapes||[]) : (doc.stickies||[]), +m[2], m[1]+":");
|
|
1008
1029
|
};
|
|
1009
1030
|
if((doc.arrows||[]).length){
|
|
@@ -1731,7 +1752,8 @@ const TOOLS = [
|
|
|
1731
1752
|
a1:{ type:"number", description:"arc only — end angle in degrees (a1 > a0; a full circle is a0=0, a1=360)" },
|
|
1732
1753
|
ir:{ type:"number", description:"arc only — inner-radius fraction 0..0.9 (0 = pie slice, 0.55 = donut)" },
|
|
1733
1754
|
file:{ type:"string", description:"image only — full path of a PNG/JPEG/WebP/GIF/SVG file on this machine. Rasters are re-encoded to about 840 px; an SVG is kept as is (300 KB max)." },
|
|
1734
|
-
data:{ type:"string", description:"image only — a data:image/(png|jpeg|webp|gif|svg+xml) URL instead of a file" }
|
|
1755
|
+
data:{ type:"string", description:"image only — a data:image/(png|jpeg|webp|gif|svg+xml) URL instead of a file" },
|
|
1756
|
+
z:{ type:"number", description:"Stacking order, -9..9 (default 0). At equal z the app paints images UNDER shapes, shapes under sticky notes — so a filled background panel hides a logo placed on it. Give such a panel z:-1 (or the image z:1) to keep the picture visible." }
|
|
1735
1757
|
}, additionalProperties:false } },
|
|
1736
1758
|
connections:{ type:"array", description:"Arrows anchored between elements (by id)", items:{ type:"object", properties:{
|
|
1737
1759
|
from:{ type:"string" }, to:{ type:"string" }
|
|
@@ -2168,7 +2190,7 @@ function handle(msg){
|
|
|
2168
2190
|
// déjà dérivé (1.0.0 ici, 1.1.0 dans le manifeste) sans que rien ne le
|
|
2169
2191
|
// signale : un client affiche l'une, le registre publie l'autre. Un
|
|
2170
2192
|
// autotest les compare désormais toutes les quatre.
|
|
2171
|
-
serverInfo: { name: "tabtree", version: "1.6.
|
|
2193
|
+
serverInfo: { name: "tabtree", version: "1.6.1" }
|
|
2172
2194
|
});
|
|
2173
2195
|
} else if(method === "notifications/initialized" || (method||"").startsWith("notifications/")){
|
|
2174
2196
|
// notification : pas de réponse
|