beplus-mcp 0.36.0 → 0.37.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/README.md +6 -4
- package/dist/index.js +507 -74
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24848,7 +24848,7 @@ function hangsRight(doc, node) {
|
|
|
24848
24848
|
return out.some((e) => doc.nodes[e.target] && FEEDS.has(kindOf(doc.nodes[e.target])));
|
|
24849
24849
|
}
|
|
24850
24850
|
var overlap = (a, b) => a.x < b.x + b.w && b.x < a.x + a.w && a.y < b.y + b.h && b.y < a.y + a.h;
|
|
24851
|
-
function arrangeRows(doc, rows, origin, gap = DEFAULT_GAP, widths = DEFAULT_WIDTHS) {
|
|
24851
|
+
function arrangeRows(doc, rows, origin, gap = DEFAULT_GAP, widths = DEFAULT_WIDTHS, scope) {
|
|
24852
24852
|
const placed = [];
|
|
24853
24853
|
const floorOf = (node, role) => role === "other" ? node.size.w : widths[role];
|
|
24854
24854
|
const place = (id, row, asTitle, x, y2, alignRight) => {
|
|
@@ -24890,7 +24890,7 @@ function arrangeRows(doc, rows, origin, gap = DEFAULT_GAP, widths = DEFAULT_WIDT
|
|
|
24890
24890
|
for (let j = i + 1; j < placed.length; j++) if (overlap(placed[i], placed[j])) inner.push([placed[i].id, placed[j].id]);
|
|
24891
24891
|
}
|
|
24892
24892
|
const ids = new Set(placed.map((p) => p.id));
|
|
24893
|
-
const others = Object.values(doc.nodes).filter((n) => !ids.has(n.id) && kindOf(n) !== "section").map((n) => ({ id: n.id, x: n.position.x, y: n.position.y, ...usedSize(n) }));
|
|
24893
|
+
const others = Object.values(doc.nodes).filter((n) => !ids.has(n.id) && kindOf(n) !== "section" && (scope === void 0 || scope.has(n.id))).map((n) => ({ id: n.id, x: n.position.x, y: n.position.y, ...usedSize(n) }));
|
|
24894
24894
|
const outer = [];
|
|
24895
24895
|
for (const p of placed) for (const o of others) if (overlap(p, o)) outer.push([p.id, o.id]);
|
|
24896
24896
|
const left = Math.min(origin.x, ...placed.map((p) => p.x));
|
|
@@ -24900,6 +24900,322 @@ function arrangeRows(doc, rows, origin, gap = DEFAULT_GAP, widths = DEFAULT_WIDT
|
|
|
24900
24900
|
return { placed, inner, outer, freeOrigin };
|
|
24901
24901
|
}
|
|
24902
24902
|
|
|
24903
|
+
// src/canvas/tabs.ts
|
|
24904
|
+
var TAB_FIELD = "aba";
|
|
24905
|
+
var TAB_ID_FIELD = "abaId";
|
|
24906
|
+
var TAB_ORDER_FIELD = "abaOrdem";
|
|
24907
|
+
var TAB_NEAR = 2e3;
|
|
24908
|
+
var AVULSOS_TAB = "avulsos";
|
|
24909
|
+
var SECTION = "section";
|
|
24910
|
+
var isFiniteNumber2 = (v) => typeof v === "number" && Number.isFinite(v);
|
|
24911
|
+
function isArchived(node) {
|
|
24912
|
+
const flag = node?.data["archived"];
|
|
24913
|
+
return typeof flag === "object" && flag !== null;
|
|
24914
|
+
}
|
|
24915
|
+
function isSectionNode(node) {
|
|
24916
|
+
return node !== void 0 && node.data[KIND_FIELD] === SECTION;
|
|
24917
|
+
}
|
|
24918
|
+
function isTabSection(node) {
|
|
24919
|
+
return node !== void 0 && isSectionNode(node) && node.data[TAB_FIELD] === true && !isArchived(node);
|
|
24920
|
+
}
|
|
24921
|
+
var rectHas = (r, x, y) => x >= r.left && x <= r.right && y >= r.top && y <= r.bottom;
|
|
24922
|
+
function distanceTo(r, x, y) {
|
|
24923
|
+
const dx = Math.max(r.left - x, 0, x - r.right);
|
|
24924
|
+
const dy = Math.max(r.top - y, 0, y - r.bottom);
|
|
24925
|
+
return Math.hypot(dx, dy);
|
|
24926
|
+
}
|
|
24927
|
+
function boardPosition(doc, node) {
|
|
24928
|
+
let x = node.position.x;
|
|
24929
|
+
let y = node.position.y;
|
|
24930
|
+
const seen = /* @__PURE__ */ new Set([node.id]);
|
|
24931
|
+
let parent = node.parentId === null ? void 0 : doc.nodes[node.parentId];
|
|
24932
|
+
while (parent !== void 0 && !seen.has(parent.id)) {
|
|
24933
|
+
seen.add(parent.id);
|
|
24934
|
+
x += parent.position.x;
|
|
24935
|
+
y += parent.position.y;
|
|
24936
|
+
parent = parent.parentId === null ? void 0 : doc.nodes[parent.parentId];
|
|
24937
|
+
}
|
|
24938
|
+
return { x, y };
|
|
24939
|
+
}
|
|
24940
|
+
function sectionRect(doc, node) {
|
|
24941
|
+
const at = boardPosition(doc, node);
|
|
24942
|
+
return { left: at.x, top: at.y, right: at.x + node.size.w, bottom: at.y + node.size.h };
|
|
24943
|
+
}
|
|
24944
|
+
function savedMeasure(node) {
|
|
24945
|
+
const value = node.data[MEASURED_KEY];
|
|
24946
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
24947
|
+
const record2 = value;
|
|
24948
|
+
if (!isFiniteNumber2(record2["w"]) || !isFiniteNumber2(record2["h"])) return void 0;
|
|
24949
|
+
return { w: record2["w"], h: record2["h"] };
|
|
24950
|
+
}
|
|
24951
|
+
function drawnRect(doc, node) {
|
|
24952
|
+
const at = boardPosition(doc, node);
|
|
24953
|
+
const saved = savedMeasure(node);
|
|
24954
|
+
const w = Math.max(node.size.w, saved?.w ?? 0);
|
|
24955
|
+
const h = Math.max(node.size.h, saved?.h ?? 0);
|
|
24956
|
+
return { left: at.x, top: at.y, right: at.x + w, bottom: at.y + h };
|
|
24957
|
+
}
|
|
24958
|
+
function savedCenter(doc, node) {
|
|
24959
|
+
const at = boardPosition(doc, node);
|
|
24960
|
+
const saved = savedMeasure(node);
|
|
24961
|
+
const w = Math.max(node.size.w, saved?.w ?? 0);
|
|
24962
|
+
const h = Math.max(node.size.h, saved?.h ?? 0);
|
|
24963
|
+
return { x: at.x + w / 2, y: at.y + h / 2 };
|
|
24964
|
+
}
|
|
24965
|
+
function tabOrderOf(node) {
|
|
24966
|
+
const raw = node.data[TAB_ORDER_FIELD];
|
|
24967
|
+
return typeof raw === "number" && Number.isFinite(raw) ? raw : null;
|
|
24968
|
+
}
|
|
24969
|
+
function orderedTabSections(doc) {
|
|
24970
|
+
return Object.values(doc.nodes).filter((node) => isTabSection(node)).sort((a, b) => {
|
|
24971
|
+
const oa = tabOrderOf(a);
|
|
24972
|
+
const ob = tabOrderOf(b);
|
|
24973
|
+
if (oa !== null && ob === null) return -1;
|
|
24974
|
+
if (oa === null && ob !== null) return 1;
|
|
24975
|
+
if (oa !== null && ob !== null && oa !== ob) return oa - ob;
|
|
24976
|
+
return a.position.y - b.position.y || a.position.x - b.position.x;
|
|
24977
|
+
});
|
|
24978
|
+
}
|
|
24979
|
+
var partitions = /* @__PURE__ */ new WeakMap();
|
|
24980
|
+
function build(doc) {
|
|
24981
|
+
const tabs = orderedTabSections(doc).map((node) => ({
|
|
24982
|
+
id: node.id,
|
|
24983
|
+
...sectionRect(doc, node)
|
|
24984
|
+
}));
|
|
24985
|
+
const live = new Map(tabs.map((tab) => [tab.id, tab]));
|
|
24986
|
+
const home = /* @__PURE__ */ new Map();
|
|
24987
|
+
const walking = /* @__PURE__ */ new Set();
|
|
24988
|
+
const byPlace = (node) => {
|
|
24989
|
+
const center = savedCenter(doc, node);
|
|
24990
|
+
for (const tab of tabs) if (rectHas(tab, center.x, center.y)) return tab.id;
|
|
24991
|
+
let near = null;
|
|
24992
|
+
let best = TAB_NEAR;
|
|
24993
|
+
for (const tab of tabs) {
|
|
24994
|
+
const distance = distanceTo(tab, center.x, center.y);
|
|
24995
|
+
if (distance <= best && (near === null || distance < best)) {
|
|
24996
|
+
near = tab;
|
|
24997
|
+
best = distance;
|
|
24998
|
+
}
|
|
24999
|
+
}
|
|
25000
|
+
return near === null ? AVULSOS_TAB : near.id;
|
|
25001
|
+
};
|
|
25002
|
+
const resolve3 = (node) => {
|
|
25003
|
+
const known = home.get(node.id);
|
|
25004
|
+
if (known !== void 0) return known;
|
|
25005
|
+
let tab;
|
|
25006
|
+
const mark = node.data[TAB_ID_FIELD];
|
|
25007
|
+
if (live.has(node.id)) {
|
|
25008
|
+
tab = node.id;
|
|
25009
|
+
} else if (typeof mark === "string" && mark !== "") {
|
|
25010
|
+
tab = live.has(mark) ? mark : AVULSOS_TAB;
|
|
25011
|
+
} else if (node.parentId !== null && !walking.has(node.id)) {
|
|
25012
|
+
const parent = doc.nodes[node.parentId];
|
|
25013
|
+
if (parent === void 0) {
|
|
25014
|
+
tab = byPlace(node);
|
|
25015
|
+
} else {
|
|
25016
|
+
walking.add(node.id);
|
|
25017
|
+
tab = resolve3(parent);
|
|
25018
|
+
walking.delete(node.id);
|
|
25019
|
+
}
|
|
25020
|
+
} else {
|
|
25021
|
+
tab = byPlace(node);
|
|
25022
|
+
}
|
|
25023
|
+
home.set(node.id, tab);
|
|
25024
|
+
return tab;
|
|
25025
|
+
};
|
|
25026
|
+
const members = /* @__PURE__ */ new Map();
|
|
25027
|
+
for (const node of Object.values(doc.nodes)) {
|
|
25028
|
+
if (isArchived(node)) continue;
|
|
25029
|
+
const tab = resolve3(node);
|
|
25030
|
+
const list = members.get(tab);
|
|
25031
|
+
if (list === void 0) members.set(tab, [node.id]);
|
|
25032
|
+
else list.push(node.id);
|
|
25033
|
+
}
|
|
25034
|
+
return { tabs, home, members };
|
|
25035
|
+
}
|
|
25036
|
+
function partitionOf(doc) {
|
|
25037
|
+
let part = partitions.get(doc);
|
|
25038
|
+
if (part === void 0) {
|
|
25039
|
+
part = build(doc);
|
|
25040
|
+
partitions.set(doc, part);
|
|
25041
|
+
}
|
|
25042
|
+
return part;
|
|
25043
|
+
}
|
|
25044
|
+
|
|
25045
|
+
// src/canvas/tab-scope.ts
|
|
25046
|
+
var LOCK_FIELD = "travada";
|
|
25047
|
+
var TAB_END_GAP = 120;
|
|
25048
|
+
var TAB_GROW_PAD = 48;
|
|
25049
|
+
var TAB_TOP_ROOM = 96;
|
|
25050
|
+
var TAB_CLEAR_GAP = 48;
|
|
25051
|
+
var SHORT_ID = 8;
|
|
25052
|
+
var MIN_PREFIX = 4;
|
|
25053
|
+
var LISTED = 12;
|
|
25054
|
+
var oneLine = (text, max) => {
|
|
25055
|
+
const flat = text.replace(/\s+/g, " ").trim();
|
|
25056
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
25057
|
+
};
|
|
25058
|
+
function tabTitle(node) {
|
|
25059
|
+
const title = typeof node.data.title === "string" ? node.data.title.trim() : "";
|
|
25060
|
+
const label = typeof node.data.label === "string" ? node.data.label.trim() : "";
|
|
25061
|
+
if (title !== "" && title !== "Se\xE7\xE3o") return title;
|
|
25062
|
+
return label || title || "Se\xE7\xE3o";
|
|
25063
|
+
}
|
|
25064
|
+
var isLockedTab = (node) => node !== void 0 && node.data[LOCK_FIELD] === true;
|
|
25065
|
+
function shortTabIds(ids) {
|
|
25066
|
+
const longest = Math.max(0, ...ids.map((id) => id.length));
|
|
25067
|
+
let length = SHORT_ID;
|
|
25068
|
+
while (length < longest && new Set(ids.map((id) => id.slice(0, length))).size < ids.length) length += 1;
|
|
25069
|
+
return new Map(ids.map((id) => [id, id.slice(0, length)]));
|
|
25070
|
+
}
|
|
25071
|
+
function tabIndex(doc) {
|
|
25072
|
+
const part = partitionOf(doc);
|
|
25073
|
+
const shorts = shortTabIds(part.tabs.map((tab) => tab.id));
|
|
25074
|
+
const tabs = part.tabs.map((tab) => {
|
|
25075
|
+
const node = doc.nodes[tab.id];
|
|
25076
|
+
return {
|
|
25077
|
+
id: tab.id,
|
|
25078
|
+
short: shorts.get(tab.id),
|
|
25079
|
+
title: tabTitle(node),
|
|
25080
|
+
locked: isLockedTab(node),
|
|
25081
|
+
cards: Math.max(0, (part.members.get(tab.id)?.length ?? 0) - 1)
|
|
25082
|
+
};
|
|
25083
|
+
});
|
|
25084
|
+
const byId = new Map(tabs.map((tab) => [tab.id, tab]));
|
|
25085
|
+
return {
|
|
25086
|
+
tabs,
|
|
25087
|
+
loose: part.members.get(AVULSOS_TAB)?.length ?? 0,
|
|
25088
|
+
label: (tab) => tab === AVULSOS_TAB ? AVULSOS_TAB : byId.get(tab)?.short ?? tab,
|
|
25089
|
+
info: (tab) => byId.get(tab)
|
|
25090
|
+
};
|
|
25091
|
+
}
|
|
25092
|
+
var hasTabs = (doc) => partitionOf(doc).tabs.length > 0;
|
|
25093
|
+
function homeTabOf(doc, nodeId3) {
|
|
25094
|
+
const part = partitionOf(doc);
|
|
25095
|
+
return part.tabs.length === 0 ? null : part.home.get(nodeId3) ?? null;
|
|
25096
|
+
}
|
|
25097
|
+
function membersOfTab(doc, tab) {
|
|
25098
|
+
return new Set(partitionOf(doc).members.get(tab) ?? []);
|
|
25099
|
+
}
|
|
25100
|
+
function tabList(doc) {
|
|
25101
|
+
const tabs = partitionOf(doc).tabs;
|
|
25102
|
+
if (tabs.length === 0) return "Este board n\xE3o tem abas (uma aba \xE9 uma se\xE7\xE3o com aba=true).";
|
|
25103
|
+
const shown = tabs.slice(0, LISTED).map((tab) => `"${oneLine(tabTitle(doc.nodes[tab.id]), 40)}" (${tab.id})`);
|
|
25104
|
+
const more = tabs.length > LISTED ? `, \u2026 e mais ${tabs.length - LISTED}` : "";
|
|
25105
|
+
return `Abas do board: ${shown.join(", ")}${more}.`;
|
|
25106
|
+
}
|
|
25107
|
+
function kindLabel(node) {
|
|
25108
|
+
const kind = node.data.kind;
|
|
25109
|
+
return typeof kind === "string" && kind ? kind : node.type;
|
|
25110
|
+
}
|
|
25111
|
+
function resolveTab(doc, ref, opts = {}) {
|
|
25112
|
+
const value = ref.trim();
|
|
25113
|
+
if (value === AVULSOS_TAB) {
|
|
25114
|
+
if (opts.allowAvulsos && hasTabs(doc)) return AVULSOS_TAB;
|
|
25115
|
+
throw new CanvasToolError(
|
|
25116
|
+
hasTabs(doc) ? '"avulsos" n\xE3o \xE9 uma aba: \xE9 onde ficam os cart\xF5es que n\xE3o moram em aba. Para criar sem aba, omita aba.' : `Aba "avulsos" n\xE3o existe. ${tabList(doc)}`
|
|
25117
|
+
);
|
|
25118
|
+
}
|
|
25119
|
+
if (Object.hasOwn(doc.nodes, value)) {
|
|
25120
|
+
const node = doc.nodes[value];
|
|
25121
|
+
if (isTabSection(node)) return node.id;
|
|
25122
|
+
const name = `"${oneLine(tabTitle(node), 40)}"`;
|
|
25123
|
+
if (isSectionNode(node) && node.data[TAB_FIELD] === true && isArchived(node)) {
|
|
25124
|
+
throw new CanvasToolError(
|
|
25125
|
+
`A aba ${name} (${value}) est\xE1 arquivada: os cart\xF5es que apontam para ela ficam em Avulsos. Escolha outra aba. ${tabList(doc)}`
|
|
25126
|
+
);
|
|
25127
|
+
}
|
|
25128
|
+
throw new CanvasToolError(
|
|
25129
|
+
`${value} \xE9 ${isSectionNode(node) ? "uma se\xE7\xE3o comum" : `um n\xF3 ${kindLabel(node)}`} (${name}), n\xE3o uma aba. Aba \xE9 a se\xE7\xE3o com aba=true. ${tabList(doc)}`
|
|
25130
|
+
);
|
|
25131
|
+
}
|
|
25132
|
+
if (value.length >= MIN_PREFIX) {
|
|
25133
|
+
const hits = partitionOf(doc).tabs.filter((tab) => tab.id.startsWith(value));
|
|
25134
|
+
if (hits.length === 1) return hits[0].id;
|
|
25135
|
+
if (hits.length > 1) {
|
|
25136
|
+
const names = hits.slice(0, LISTED).map((tab) => `"${oneLine(tabTitle(doc.nodes[tab.id]), 40)}" (${tab.id})`);
|
|
25137
|
+
throw new CanvasToolError(`"${value}" serve a mais de uma aba: ${names.join(", ")}. Use o id inteiro.`);
|
|
25138
|
+
}
|
|
25139
|
+
}
|
|
25140
|
+
throw new CanvasToolError(`Aba "${oneLine(value, 60)}" n\xE3o existe neste board. ${tabList(doc)}`);
|
|
25141
|
+
}
|
|
25142
|
+
function unionOf(rects) {
|
|
25143
|
+
let out = null;
|
|
25144
|
+
for (const r of rects) {
|
|
25145
|
+
out = out === null ? { ...r } : {
|
|
25146
|
+
left: Math.min(out.left, r.left),
|
|
25147
|
+
top: Math.min(out.top, r.top),
|
|
25148
|
+
right: Math.max(out.right, r.right),
|
|
25149
|
+
bottom: Math.max(out.bottom, r.bottom)
|
|
25150
|
+
};
|
|
25151
|
+
}
|
|
25152
|
+
return out;
|
|
25153
|
+
}
|
|
25154
|
+
function endOfTabContent(doc, tabId, size) {
|
|
25155
|
+
const part = partitionOf(doc);
|
|
25156
|
+
const section = doc.nodes[tabId];
|
|
25157
|
+
const boxes = (part.members.get(tabId) ?? []).flatMap((id) => {
|
|
25158
|
+
const node = doc.nodes[id];
|
|
25159
|
+
return id === tabId || node === void 0 || isArchived(node) ? [] : [drawnRect(doc, node)];
|
|
25160
|
+
});
|
|
25161
|
+
const content = unionOf(boxes);
|
|
25162
|
+
const frame = sectionRect(doc, section);
|
|
25163
|
+
const spot = content === null ? { x: frame.left + TAB_GROW_PAD, y: frame.top + TAB_TOP_ROOM } : { x: content.left, y: content.bottom + TAB_END_GAP };
|
|
25164
|
+
const others = part.tabs.filter((tab) => tab.id !== tabId);
|
|
25165
|
+
const cx = spot.x + size.w / 2;
|
|
25166
|
+
let y = spot.y;
|
|
25167
|
+
for (let guard = 0; guard <= others.length; guard += 1) {
|
|
25168
|
+
const hit = others.find((rect) => rectHas(rect, cx, y + size.h / 2));
|
|
25169
|
+
if (hit === void 0) break;
|
|
25170
|
+
y = hit.bottom + TAB_CLEAR_GAP;
|
|
25171
|
+
}
|
|
25172
|
+
return { x: Math.round(spot.x), y: Math.round(y) };
|
|
25173
|
+
}
|
|
25174
|
+
function placementNote(doc, node) {
|
|
25175
|
+
if (isTabSection(node)) return "";
|
|
25176
|
+
const after = { ...doc, nodes: { ...doc.nodes, [node.id]: node } };
|
|
25177
|
+
const index = tabIndex(after);
|
|
25178
|
+
if (index.tabs.length === 0) return "";
|
|
25179
|
+
const home = partitionOf(after).home.get(node.id);
|
|
25180
|
+
if (home === void 0) return "";
|
|
25181
|
+
const info = index.info(home);
|
|
25182
|
+
if (info === void 0) {
|
|
25183
|
+
return " Aten\xE7\xE3o: ficou em Avulsos (nenhuma aba o segura); passe aba=<id da aba> para ele morar numa aba.";
|
|
25184
|
+
}
|
|
25185
|
+
return ` Aba: "${oneLine(info.title, 40)}" (aba=${info.short}).`;
|
|
25186
|
+
}
|
|
25187
|
+
function flatten(ops) {
|
|
25188
|
+
return ops.flatMap((op) => op.type === "batch" ? flatten(op.ops) : [op]);
|
|
25189
|
+
}
|
|
25190
|
+
function badAbaId(doc, value) {
|
|
25191
|
+
if (value === null) return null;
|
|
25192
|
+
if (typeof value !== "string") return `data.${TAB_ID_FIELD} precisa ser o id (texto) de uma aba, ou null para tirar o campo.`;
|
|
25193
|
+
if (Object.hasOwn(doc.nodes, value) && isTabSection(doc.nodes[value])) return null;
|
|
25194
|
+
let hint;
|
|
25195
|
+
try {
|
|
25196
|
+
const full = resolveTab(doc, value);
|
|
25197
|
+
hint = `Use o id inteiro: ${full}.`;
|
|
25198
|
+
} catch (e) {
|
|
25199
|
+
hint = e instanceof Error ? e.message : "";
|
|
25200
|
+
}
|
|
25201
|
+
return `data.${TAB_ID_FIELD} "${oneLine(value, 60)}" n\xE3o \xE9 o id de uma aba viva. ${hint} Para tirar o campo, mande null.`;
|
|
25202
|
+
}
|
|
25203
|
+
function abaIdViolation(doc, ops) {
|
|
25204
|
+
for (const op of flatten(ops)) {
|
|
25205
|
+
if (op.type === "node.add") {
|
|
25206
|
+
const value = op.node.data[TAB_ID_FIELD];
|
|
25207
|
+
if (value !== void 0) {
|
|
25208
|
+
const bad = badAbaId(doc, value);
|
|
25209
|
+
if (bad) return bad;
|
|
25210
|
+
}
|
|
25211
|
+
} else if (op.type === "node.set" && op.path === `data.${TAB_ID_FIELD}` && op.value.kind === "value") {
|
|
25212
|
+
const bad = badAbaId(doc, op.value.value);
|
|
25213
|
+
if (bad) return bad;
|
|
25214
|
+
}
|
|
25215
|
+
}
|
|
25216
|
+
return null;
|
|
25217
|
+
}
|
|
25218
|
+
|
|
24903
25219
|
// src/canvas/summary.ts
|
|
24904
25220
|
var MAX_TEXT = 160;
|
|
24905
25221
|
var MAX_BLOCKS = 40;
|
|
@@ -24931,7 +25247,7 @@ function visibleData(data) {
|
|
|
24931
25247
|
return rest;
|
|
24932
25248
|
}
|
|
24933
25249
|
var NAME_KEYS = /* @__PURE__ */ new Set([KIND_FIELD, "label", "nodeTitle"]);
|
|
24934
|
-
function
|
|
25250
|
+
function oneLine2(text, max = MAX_TEXT) {
|
|
24935
25251
|
const flat = text.replace(/\s+/g, " ").trim();
|
|
24936
25252
|
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
24937
25253
|
}
|
|
@@ -24950,7 +25266,7 @@ function scalar(v) {
|
|
|
24950
25266
|
if (typeof v === "string") {
|
|
24951
25267
|
if (v.startsWith("data:")) return "[data-url]";
|
|
24952
25268
|
if (/^https?:\/\//.test(v)) return "[url]";
|
|
24953
|
-
return JSON.stringify(
|
|
25269
|
+
return JSON.stringify(oneLine2(v, 60));
|
|
24954
25270
|
}
|
|
24955
25271
|
if (typeof v === "number" || typeof v === "boolean" || v === null) return String(v);
|
|
24956
25272
|
return null;
|
|
@@ -24959,7 +25275,7 @@ function blocksLines(blocks) {
|
|
|
24959
25275
|
if (!Array.isArray(blocks)) return [];
|
|
24960
25276
|
const out = blocks.slice(0, MAX_BLOCKS).map((b) => {
|
|
24961
25277
|
const rec = b ?? {};
|
|
24962
|
-
return ` \xB7 ${String(rec.id ?? "?")}: ${
|
|
25278
|
+
return ` \xB7 ${String(rec.id ?? "?")}: ${oneLine2(String(rec.text ?? ""), 120)}`;
|
|
24963
25279
|
});
|
|
24964
25280
|
if (blocks.length > MAX_BLOCKS) out.push(` \xB7 \u2026 +${blocks.length - MAX_BLOCKS} blocos`);
|
|
24965
25281
|
return out;
|
|
@@ -24972,21 +25288,22 @@ function rowsLines(rows) {
|
|
|
24972
25288
|
const ideas = Array.isArray(rec.ideas) ? rec.ideas : [];
|
|
24973
25289
|
const ideaText = ideas.slice(0, 6).map((i) => {
|
|
24974
25290
|
const idea = i ?? {};
|
|
24975
|
-
return `${String(idea.id ?? "?")}="${
|
|
25291
|
+
return `${String(idea.id ?? "?")}="${oneLine2(String(idea.text ?? ""), 60)}"`;
|
|
24976
25292
|
}).join("; ");
|
|
24977
25293
|
out.push(` \xB7 linha ${String(rec.id ?? "?")} (bloco ${String(rec.narrationBlockId ?? "?")}): ${ideas.length} ideia(s) ${ideaText}`);
|
|
24978
25294
|
}
|
|
24979
25295
|
if (rows.length > MAX_BLOCKS) out.push(` \xB7 \u2026 +${rows.length - MAX_BLOCKS} linhas`);
|
|
24980
25296
|
return out;
|
|
24981
25297
|
}
|
|
24982
|
-
function nodeLines(node, run) {
|
|
25298
|
+
function nodeLines(node, run, aba) {
|
|
24983
25299
|
const kind = nodeKind(node);
|
|
24984
25300
|
const spec = kind ? KINDS[kind] : void 0;
|
|
24985
|
-
const head = `- ${node.id} \xB7 ${kind ?? node.type} \xB7 "${
|
|
25301
|
+
const head = `- ${node.id} \xB7 ${kind ?? node.type} \xB7 "${oneLine2(nodeName(node), 60)}" @(${Math.round(node.position.x)},${Math.round(node.position.y)}) ${sizeLabel(node)}` + (aba ? ` \xB7 aba=${aba}` : "");
|
|
24986
25302
|
const facts = [];
|
|
24987
25303
|
const extra = [];
|
|
24988
25304
|
const d = node.data;
|
|
24989
25305
|
if (d.archived) facts.push("ARQUIVADO");
|
|
25306
|
+
if (aba && isTabSection(node)) facts.push("\xE9 aba");
|
|
24990
25307
|
const approval = d.approval?.state;
|
|
24991
25308
|
if (typeof approval === "string") facts.push(`aprova\xE7\xE3o: ${approval}`);
|
|
24992
25309
|
if (Array.isArray(d.history)) facts.push(`${d.history.length} gera\xE7\xE3o(\xF5es)`);
|
|
@@ -25007,10 +25324,11 @@ function nodeLines(node, run) {
|
|
|
25007
25324
|
if (fact) facts.push(fact);
|
|
25008
25325
|
}
|
|
25009
25326
|
const main2 = spec?.main;
|
|
25010
|
-
if (main2 && typeof d[main2] === "string" && d[main2]) facts.push(`${main2}: "${
|
|
25327
|
+
if (main2 && typeof d[main2] === "string" && d[main2]) facts.push(`${main2}: "${oneLine2(d[main2])}"`);
|
|
25011
25328
|
for (const [key, value] of Object.entries(d)) {
|
|
25012
25329
|
if (NAME_KEYS.has(key) || HEAVY_KEYS.has(key) || key === main2) continue;
|
|
25013
25330
|
if (["blocks", "rows", "items", "archived", "approval"].includes(key)) continue;
|
|
25331
|
+
if (aba && (key === TAB_ID_FIELD || key === TAB_FIELD && isTabSection(node))) continue;
|
|
25014
25332
|
const s = scalar(value);
|
|
25015
25333
|
if (s !== null) facts.push(`${key}=${s}`);
|
|
25016
25334
|
else if (Array.isArray(value)) facts.push(`${key}=[${value.length}]`);
|
|
@@ -25032,27 +25350,63 @@ function timelineFact(d) {
|
|
|
25032
25350
|
const clips = seq.audioClips && typeof seq.audioClips === "object" && !Array.isArray(seq.audioClips) ? Object.values(seq.audioClips).reduce((t, list) => t + (Array.isArray(list) ? list.length : 0), 0) : 0;
|
|
25033
25351
|
return `sequ\xEAncia (legado, sem data.timeline): ${plans} plano(s), ${clips} clipe(s) de \xE1udio, ${JSON.stringify(seq).length} caracteres (inteira em canvas_read_node sem path; ${volume})`;
|
|
25034
25352
|
}
|
|
25035
|
-
|
|
25353
|
+
var cardsText = (n) => n === 1 ? "1 cart\xE3o" : `${n} cart\xF5es`;
|
|
25354
|
+
function boardSummary(snap, opts = {}) {
|
|
25036
25355
|
const doc = snap.doc;
|
|
25037
|
-
const
|
|
25038
|
-
const
|
|
25356
|
+
const part = partitionOf(doc);
|
|
25357
|
+
const index = tabIndex(doc);
|
|
25358
|
+
const tabbed = index.tabs.length > 0;
|
|
25359
|
+
const scope = opts.tab === void 0 ? null : new Set(part.members.get(opts.tab) ?? []);
|
|
25360
|
+
const everyNode = Object.values(doc.nodes).sort((a, b) => a.position.x - b.position.x || a.position.y - b.position.y);
|
|
25361
|
+
const everyEdge = Object.values(doc.edges);
|
|
25362
|
+
const nodes = scope ? everyNode.filter((n) => scope.has(n.id)) : everyNode;
|
|
25363
|
+
const edges = scope ? everyEdge.filter((e) => scope.has(e.source) || scope.has(e.target)) : everyEdge;
|
|
25039
25364
|
const runs = new Map(snap.runs.map((r) => [r.nodeId, r]));
|
|
25040
|
-
const
|
|
25041
|
-
|
|
25042
|
-
|
|
25365
|
+
const who2 = `Board "${snap.title}" \xB7 id ${snap.id} \xB7 seq ${snap.seq} \xB7 seu papel: ${snap.role}`;
|
|
25366
|
+
const lines = [];
|
|
25367
|
+
if (scope === null) {
|
|
25368
|
+
lines.push(`${who2} \xB7 ${nodes.length} n\xF3(s) \xB7 ${edges.length} liga\xE7\xE3o(\xF5es)`);
|
|
25369
|
+
} else {
|
|
25370
|
+
const external = edges.filter((e) => !(scope.has(e.source) && scope.has(e.target))).length;
|
|
25371
|
+
const info = index.info(opts.tab);
|
|
25372
|
+
const name = info ? `a aba "${oneLine2(info.title, 60)}" (aba=${info.short})` : "os avulsos (aba=avulsos)";
|
|
25373
|
+
lines.push(
|
|
25374
|
+
`${who2} \xB7 s\xF3 ${name}: ${nodes.length} n\xF3(s) \xB7 ${edges.length} liga\xE7\xE3o(\xF5es)${external ? `, ${external} externa(s)` : ""}`,
|
|
25375
|
+
`O board inteiro tem ${everyNode.length} n\xF3(s) e ${everyEdge.length} liga\xE7\xE3o(\xF5es); leia sem aba para ver tudo.`
|
|
25376
|
+
);
|
|
25377
|
+
}
|
|
25043
25378
|
const ialab = doc.meta?.ialab;
|
|
25044
25379
|
if (ialab === null) lines.push("IA Lab: sem v\xEDnculo (gera\xE7\xF5es saem dos diamantes de quem roda).");
|
|
25045
25380
|
else if (ialab && typeof ialab === "object") {
|
|
25046
25381
|
const label = ["code", "name", "projectCode", "projectName"].map((k) => ialab[k]).find((v) => typeof v === "string");
|
|
25047
25382
|
lines.push(`IA Lab: vinculado${label ? ` a ${String(label)}` : ""}.`);
|
|
25048
25383
|
}
|
|
25049
|
-
if (doc.meta?.guide) lines.push(`Guia: ${
|
|
25384
|
+
if (doc.meta?.guide) lines.push(`Guia: ${oneLine2(doc.meta.guide)}`);
|
|
25385
|
+
if (tabbed) {
|
|
25386
|
+
lines.push("", `Abas (${index.tabs.length}), cart\xF5es de cada uma sem contar a se\xE7\xE3o (canvas_read_board com aba=<id> l\xEA uma s\xF3):`);
|
|
25387
|
+
for (const t of index.tabs) {
|
|
25388
|
+
const id = t.id === t.short ? "" : ` \xB7 id ${t.id}`;
|
|
25389
|
+
lines.push(`- aba=${t.short} \xB7 "${oneLine2(t.title, 60)}" \xB7 ${cardsText(t.cards)}${t.locked ? " \xB7 travada" : ""}${id}`);
|
|
25390
|
+
}
|
|
25391
|
+
if (index.loose) lines.push(`- aba=${AVULSOS_TAB} \xB7 ${cardsText(index.loose)} (n\xE3o moram em aba)`);
|
|
25392
|
+
}
|
|
25050
25393
|
lines.push("", "N\xF3s (tamanho: medido = como est\xE1 na tela; gravado = piso, o cart\xE3o pode ser maior):");
|
|
25051
25394
|
if (!nodes.length) lines.push("(vazio)");
|
|
25052
|
-
for (const n of nodes)
|
|
25395
|
+
for (const n of nodes) {
|
|
25396
|
+
const home = tabbed ? part.home.get(n.id) : void 0;
|
|
25397
|
+
lines.push(...nodeLines(n, runs.get(n.id), home === void 0 ? void 0 : index.label(home)));
|
|
25398
|
+
}
|
|
25053
25399
|
lines.push("", "Liga\xE7\xF5es:");
|
|
25054
25400
|
if (!edges.length) lines.push("(nenhuma)");
|
|
25055
|
-
for (const e of edges)
|
|
25401
|
+
for (const e of edges) {
|
|
25402
|
+
let note = "";
|
|
25403
|
+
if (scope && !(scope.has(e.source) && scope.has(e.target))) {
|
|
25404
|
+
const far = part.home.get(scope.has(e.source) ? e.target : e.source);
|
|
25405
|
+
const farInfo = far === void 0 ? void 0 : index.info(far);
|
|
25406
|
+
note = far === void 0 ? " \xB7 externo (o outro lado \xE9 um n\xF3 arquivado ou ausente)" : farInfo ? ` \xB7 externo (outro lado: aba "${oneLine2(farInfo.title, 40)}" aba=${farInfo.short})` : ` \xB7 externo (outro lado: ${AVULSOS_TAB})`;
|
|
25407
|
+
}
|
|
25408
|
+
lines.push(`- ${e.id}: ${e.source}.${e.sourcePort} \u2192 ${e.target}.${e.targetPort}${note}`);
|
|
25409
|
+
}
|
|
25056
25410
|
return lines.join("\n");
|
|
25057
25411
|
}
|
|
25058
25412
|
function nodeDetail(node) {
|
|
@@ -25120,7 +25474,7 @@ function changesSince(envelopes, doc) {
|
|
|
25120
25474
|
count.set(key, (count.get(key) ?? 0) + 1);
|
|
25121
25475
|
}
|
|
25122
25476
|
const parts = [...count].map(([t, n]) => `${n}\xD7 ${t}`);
|
|
25123
|
-
const names = [...touchedNodes(envelopes)].map((id) => doc.nodes[id] ? `"${
|
|
25477
|
+
const names = [...touchedNodes(envelopes)].map((id) => doc.nodes[id] ? `"${oneLine2(nodeName(doc.nodes[id]), 40)}"` : `${id} (apagado)`).slice(0, 8);
|
|
25124
25478
|
return `${envelopes.length} opera\xE7\xE3o(\xF5es) de outras pessoas desde a sua leitura (${parts.join(", ")})` + (names.length ? `; n\xF3s tocados: ${names.join(", ")}` : "");
|
|
25125
25479
|
}
|
|
25126
25480
|
function touchedNodes(envelopes) {
|
|
@@ -25151,7 +25505,7 @@ function mmss(t) {
|
|
|
25151
25505
|
function nodeRef(doc, nodeId3) {
|
|
25152
25506
|
const node = doc.nodes[nodeId3];
|
|
25153
25507
|
const kind = nodeKind(node) ?? node.type;
|
|
25154
|
-
return `"${
|
|
25508
|
+
return `"${oneLine2(nodeName(node), 60)}" (${kind}, ${node.id})`;
|
|
25155
25509
|
}
|
|
25156
25510
|
function hashString(text) {
|
|
25157
25511
|
let h1 = 3735928559;
|
|
@@ -25208,7 +25562,7 @@ function describeAnchor(anchor, doc) {
|
|
|
25208
25562
|
const t = mmss(Number(anchor.t) || 0);
|
|
25209
25563
|
if (kind === "montage") {
|
|
25210
25564
|
const name = nodeName(node);
|
|
25211
|
-
const title = name === KINDS.montage.title ? "" : ` "${
|
|
25565
|
+
const title = name === KINDS.montage.title ? "" : ` "${oneLine2(name, 60)}"`;
|
|
25212
25566
|
return { text: `em ${t} da Montagem${title} (${node.id})`, nodeId: anchor.nodeId };
|
|
25213
25567
|
}
|
|
25214
25568
|
return { text: `em ${t} de ${ref}`, nodeId: anchor.nodeId };
|
|
@@ -25243,11 +25597,11 @@ function threadLines(t, doc) {
|
|
|
25243
25597
|
const where = describeAnchor(t.anchor, doc);
|
|
25244
25598
|
const state = t.resolvedAt ? " \xB7 RESOLVIDO" : "";
|
|
25245
25599
|
const reacts = reactionsText(t.reactions);
|
|
25246
|
-
const lines = t.deleted ? [`- ${t.id} \xB7 ${where.text}${state}`, " (coment\xE1rio raiz apagado: n\xE3o d\xE1 para responder nem resolver)"] : [`- ${t.id} \xB7 ${where.text} \xB7 ${who(t)}${state}${reacts ? ` \xB7 ${reacts}` : ""}`, ` pedido: ${
|
|
25600
|
+
const lines = t.deleted ? [`- ${t.id} \xB7 ${where.text}${state}`, " (coment\xE1rio raiz apagado: n\xE3o d\xE1 para responder nem resolver)"] : [`- ${t.id} \xB7 ${where.text} \xB7 ${who(t)}${state}${reacts ? ` \xB7 ${reacts}` : ""}`, ` pedido: ${oneLine2(t.body ?? "", 400)}`];
|
|
25247
25601
|
if (where.gone && !t.deleted) lines.push(` \u26A0 ALVO SUMIU: ${where.gone}. Responda com pergunta, n\xE3o resolva.`);
|
|
25248
25602
|
const replies = Array.isArray(t.replies) ? t.replies : [];
|
|
25249
25603
|
for (const r of replies.slice(-MAX_REPLIES)) {
|
|
25250
|
-
lines.push(r.deleted ? " \u21B3 (resposta apagada)" : ` \u21B3 ${who(r)}: ${
|
|
25604
|
+
lines.push(r.deleted ? " \u21B3 (resposta apagada)" : ` \u21B3 ${who(r)}: ${oneLine2(r.body ?? "", 140)}`);
|
|
25251
25605
|
}
|
|
25252
25606
|
if (replies.length > MAX_REPLIES) lines.splice(lines.length - MAX_REPLIES, 0, ` \u21B3 \u2026 ${replies.length - MAX_REPLIES} resposta(s) antes`);
|
|
25253
25607
|
return lines;
|
|
@@ -25327,7 +25681,7 @@ Para aplicar: leia o n\xF3 com canvas_read_board (node_ids), edite pelas canvas_
|
|
|
25327
25681
|
() => api.createComment(board_id, { body: text, parentId: comment_id, ...m?.length ? { mentions: m } : {} })
|
|
25328
25682
|
);
|
|
25329
25683
|
const open3 = thread?.resolvedAt ? "A thread est\xE1 resolvida; reabra com canvas_reopen_comment se precisar." : "A thread segue aberta.";
|
|
25330
|
-
return `\u2705 Resposta ${newReplyId(thread)} em ${comment_id}: "${
|
|
25684
|
+
return `\u2705 Resposta ${newReplyId(thread)} em ${comment_id}: "${oneLine2(text, 120)}". ${open3}`;
|
|
25331
25685
|
})
|
|
25332
25686
|
);
|
|
25333
25687
|
server.registerTool(
|
|
@@ -25350,10 +25704,10 @@ Para aplicar: leia o n\xF3 com canvas_read_board (node_ids), edite pelas canvas_
|
|
|
25350
25704
|
} catch (e) {
|
|
25351
25705
|
const why = e instanceof Error ? e.message : String(e);
|
|
25352
25706
|
throw new CanvasToolError(
|
|
25353
|
-
`A resposta "${
|
|
25707
|
+
`A resposta "${oneLine2(done, 80)}" (${replyId}) foi postada em ${comment_id}, mas resolver falhou: ${why} N\xE3o repita canvas_resolve_comment (postaria a resposta de novo): avise a pessoa para resolver no Canvas.`
|
|
25354
25708
|
);
|
|
25355
25709
|
}
|
|
25356
|
-
return `\u2705 Resolvido ${comment_id}: "${
|
|
25710
|
+
return `\u2705 Resolvido ${comment_id}: "${oneLine2(done, 120)}" (resposta ${replyId}).`;
|
|
25357
25711
|
})
|
|
25358
25712
|
);
|
|
25359
25713
|
server.registerTool(
|
|
@@ -25367,7 +25721,7 @@ Para aplicar: leia o n\xF3 com canvas_read_board (node_ids), edite pelas canvas_
|
|
|
25367
25721
|
async ({ board_id, comment_id, why }) => run(async () => {
|
|
25368
25722
|
await onComment(() => api.reopenComment(board_id, comment_id));
|
|
25369
25723
|
if (why) await onComment(() => api.createComment(board_id, { body: why, parentId: comment_id }));
|
|
25370
|
-
return `\u2705 Reaberto ${comment_id}${why ? ` com a resposta "${
|
|
25724
|
+
return `\u2705 Reaberto ${comment_id}${why ? ` com a resposta "${oneLine2(why, 120)}"` : ""}.`;
|
|
25371
25725
|
})
|
|
25372
25726
|
);
|
|
25373
25727
|
server.registerTool(
|
|
@@ -25422,6 +25776,13 @@ Para aplicar: leia o n\xF3 com canvas_read_board (node_ids), edite pelas canvas_
|
|
|
25422
25776
|
);
|
|
25423
25777
|
}
|
|
25424
25778
|
|
|
25779
|
+
// src/tools/canvas-aba-arg.ts
|
|
25780
|
+
var abaArg = (what) => external_exports.string().trim().min(1).max(128).optional().describe(what);
|
|
25781
|
+
var ABA_ADD_NODE = "Aba onde o cart\xE3o mora: o id da se\xE7\xE3o da aba ou o come\xE7o \xFAnico dele (o aba=\u2026 da leitura). Grava data.abaId e, sem position, o cart\xE3o nasce no fim do conte\xFAdo da aba (abaixo do cart\xE3o mais baixo, alinhado \xE0 esquerda do conte\xFAdo). data.abaId vale como aba; se os dois divergirem, recusa. Aba que n\xE3o existe ou que n\xE3o \xE9 aba \xE9 recusada.";
|
|
25782
|
+
var ABA_READ_BOARD = 'L\xEA s\xF3 uma aba: a se\xE7\xE3o, quem mora nela e os fios que tocam nesses n\xF3s (o fio que vai a outra aba vem marcado como externo). Aceita o id da se\xE7\xE3o, o come\xE7o \xFAnico dele (o aba=\u2026 da leitura) ou "avulsos". Sem aba, l\xEA o board inteiro.';
|
|
25783
|
+
var ABA_UPLOAD_MEDIA = "Aba do n\xF3 M\xEDdia novo (id da se\xE7\xE3o da aba ou o come\xE7o \xFAnico dele): grava data.abaId e p\xF5e o n\xF3 no fim do conte\xFAdo da aba, em vez de cair \xE0 direita de tudo, em Avulsos. S\xF3 vale com board_id e sem node_id (n\xF3 que j\xE1 existe n\xE3o muda de aba).";
|
|
25784
|
+
var ABA_ARRANGE_ROWS = 'Aba onde conferir a sobreposi\xE7\xE3o (id da se\xE7\xE3o ou o come\xE7o \xFAnico dele): s\xF3 os cart\xF5es dela contam como "de fora". Sem aba, vale a aba dos n\xF3s arrumados, quando \xE9 uma s\xF3; sen\xE3o, o board inteiro. N\xE3o muda a aba de nenhum n\xF3.';
|
|
25785
|
+
|
|
25425
25786
|
// src/tools/canvas-layout.ts
|
|
25426
25787
|
var nodeIdArg = external_exports.string().min(1).max(128);
|
|
25427
25788
|
var width = external_exports.number().finite().min(40).max(2e4);
|
|
@@ -25461,8 +25822,24 @@ function layoutOps(doc, a) {
|
|
|
25461
25822
|
}
|
|
25462
25823
|
return ops;
|
|
25463
25824
|
}
|
|
25464
|
-
function
|
|
25465
|
-
const
|
|
25825
|
+
function scopeFor(doc, rows, aba) {
|
|
25826
|
+
const tab = aba ? resolveTab(doc, aba) : void 0;
|
|
25827
|
+
if (!hasTabs(doc)) return void 0;
|
|
25828
|
+
const arranged = rows.flatMap((r) => [...r.title ? [r.title] : [], ...r.left, ...r.right]);
|
|
25829
|
+
const homes = new Set(arranged.map((id) => homeTabOf(doc, id)));
|
|
25830
|
+
const only = homes.size === 1 ? [...homes][0] : null;
|
|
25831
|
+
const chosen = tab ?? (only && only !== AVULSOS_TAB ? only : void 0);
|
|
25832
|
+
if (chosen === void 0) return void 0;
|
|
25833
|
+
const info = tabIndex(doc).info(chosen);
|
|
25834
|
+
return {
|
|
25835
|
+
ids: membersOfTab(doc, chosen),
|
|
25836
|
+
title: info.title,
|
|
25837
|
+
short: info.short,
|
|
25838
|
+
foreign: tab === void 0 ? [] : arranged.filter((id) => homeTabOf(doc, id) !== tab)
|
|
25839
|
+
};
|
|
25840
|
+
}
|
|
25841
|
+
function report(doc, a, scope) {
|
|
25842
|
+
const name = (id) => `"${oneLine2(nodeName(doc.nodes[id]), 36)}"`;
|
|
25466
25843
|
const lines = [];
|
|
25467
25844
|
const unmeasured = a.placed.filter((p) => p.source === "gravado");
|
|
25468
25845
|
const estimated = a.placed.filter((p) => p.source === "medido" && p.estimated);
|
|
@@ -25484,9 +25861,17 @@ function report(doc, a) {
|
|
|
25484
25861
|
lines.push("Todos os n\xF3s arrumados t\xEAm medida da tela.");
|
|
25485
25862
|
}
|
|
25486
25863
|
const pairs = (list) => list.map(([x, y]) => `${name(x)} \xD7 ${name(y)}`).join("; ");
|
|
25864
|
+
const where = scope ? ` (s\xF3 na aba "${oneLine2(scope.title, 40)}" aba=${scope.short})` : "";
|
|
25487
25865
|
lines.push(
|
|
25488
|
-
a.inner.length || a.outer.length ? `Sobreposi\xE7\xF5es com os tamanhos usados: ${pairs([...a.inner, ...a.outer])}.` :
|
|
25866
|
+
a.inner.length || a.outer.length ? `Sobreposi\xE7\xF5es com os tamanhos usados${where}: ${pairs([...a.inner, ...a.outer])}.` : `Sobreposi\xE7\xF5es com os tamanhos usados${where}: nenhuma.`
|
|
25489
25867
|
);
|
|
25868
|
+
if (scope?.foreign.length) {
|
|
25869
|
+
const n = scope.foreign.length;
|
|
25870
|
+
const names = scope.foreign.slice(0, 5).map(name).join(", ") + (n > 5 ? ` e mais ${n - 5}` : "");
|
|
25871
|
+
lines.push(
|
|
25872
|
+
`Aten\xE7\xE3o: ${names} ${n === 1 ? "mora" : "moram"} em outra aba que n\xE3o a pedida; o arranjo grava s\xF3 posi\xE7\xE3o e n\xE3o troca a aba de ningu\xE9m (data.abaId).`
|
|
25873
|
+
);
|
|
25874
|
+
}
|
|
25490
25875
|
lines.push('Caixas ([papel] id "nome" @(x,y) largura\xD7altura usada, origem da altura):');
|
|
25491
25876
|
const rows = /* @__PURE__ */ new Map();
|
|
25492
25877
|
for (const p of a.placed) {
|
|
@@ -25510,10 +25895,11 @@ function registerCanvasLayoutTools(server, deps) {
|
|
|
25510
25895
|
"canvas_arrange_rows",
|
|
25511
25896
|
{
|
|
25512
25897
|
title: "Canvas: arrumar em linhas",
|
|
25513
|
-
description: "Arruma n\xF3s em linhas, uma por vers\xE3o (revis\xE3o de imagem) ou por take (anima\xE7\xE3o), de cima para baixo a partir de origin: title em cima; \xE0 esquerda a coluna left (prompt; m\xEDdia/imagem que alimenta o prompt ou o gerador, como a refer\xEAncia e o frame de entrada, fica alinhada \xE0 direita embaixo dele); \xE0 direita a coluna right (gerador) com o topo no do prompt. Qualquer tipo entra em qualquer coluna. Usa o tamanho medido da tela (ou o gravado, avisando) e p\xF5e a largura pelo tipo real do n\xF3: prompt 1024, gerador de imagem 560, de v\xEDdeo 560, refer\xEAncia (m\xEDdia) 320, frame (m\xEDdia/imagem ligada na porta frame do v\xEDdeo) 320, t\xEDtulo 1024. Grava s\xF3 posi\xE7\xE3o e tamanho num passo, sem pedir releitura. Devolve as caixas, as sobreposi\xE7\xF5es com os tamanhos usados e os n\xF3s sem medida (a altura deles pode crescer quando o board abrir: rode de novo depois). Se a \xE1rea encostar em outro n\xF3
|
|
25898
|
+
description: "Arruma n\xF3s em linhas, uma por vers\xE3o (revis\xE3o de imagem) ou por take (anima\xE7\xE3o), de cima para baixo a partir de origin: title em cima; \xE0 esquerda a coluna left (prompt; m\xEDdia/imagem que alimenta o prompt ou o gerador, como a refer\xEAncia e o frame de entrada, fica alinhada \xE0 direita embaixo dele); \xE0 direita a coluna right (gerador) com o topo no do prompt. Qualquer tipo entra em qualquer coluna. Usa o tamanho medido da tela (ou o gravado, avisando) e p\xF5e a largura pelo tipo real do n\xF3: prompt 1024, gerador de imagem 560, de v\xEDdeo 560, refer\xEAncia (m\xEDdia) 320, frame (m\xEDdia/imagem ligada na porta frame do v\xEDdeo) 320, t\xEDtulo 1024. Grava s\xF3 posi\xE7\xE3o e tamanho num passo, sem pedir releitura. Devolve as caixas, as sobreposi\xE7\xF5es com os tamanhos usados e os n\xF3s sem medida (a altura deles pode crescer quando o board abrir: rode de novo depois). Se a \xE1rea encostar em outro n\xF3 da mesma aba (aba, ou a dos n\xF3s arrumados), n\xE3o grava nada e sugere uma origem livre. dry_run: true s\xF3 calcula.",
|
|
25514
25899
|
inputSchema: {
|
|
25515
25900
|
board_id: external_exports.string().uuid(),
|
|
25516
25901
|
origin: external_exports.object({ x: external_exports.number().finite(), y: external_exports.number().finite() }).describe("Canto de cima \xE0 esquerda da \xE1rea."),
|
|
25902
|
+
aba: abaArg(ABA_ARRANGE_ROWS),
|
|
25517
25903
|
rows: external_exports.array(
|
|
25518
25904
|
external_exports.object({
|
|
25519
25905
|
title: nodeIdArg.optional().describe("N\xF3 do t\xEDtulo da linha (Texto livre)."),
|
|
@@ -25542,15 +25928,16 @@ function registerCanvasLayoutTools(server, deps) {
|
|
|
25542
25928
|
const gap = args.gap ?? DEFAULT_GAP;
|
|
25543
25929
|
const plan = (doc) => {
|
|
25544
25930
|
checkRows(doc, rows);
|
|
25545
|
-
const
|
|
25546
|
-
|
|
25931
|
+
const scope = scopeFor(doc, rows, args.aba);
|
|
25932
|
+
const a = arrangeRows(doc, rows, args.origin, gap, widths, scope?.ids);
|
|
25933
|
+
return { a, scoped: scope !== void 0, ops: layoutOps(doc, a), text: report(doc, a, scope) };
|
|
25547
25934
|
};
|
|
25548
25935
|
const count = (ops) => new Set(ops.map((o) => o.type === "node.set" ? o.nodeId : "")).size;
|
|
25549
|
-
const blocked = (a) => `A \xE1rea encosta em n\xF3s que n\xE3o est\xE3o no arranjo. Nada foi gravado. Origem livre sugerida: {"x":${a.freeOrigin.x},"y":${a.freeOrigin.y}} (abaixo de tudo nessa faixa), ou tire esses n\xF3s do caminho.`;
|
|
25936
|
+
const blocked = (a, scoped) => `A \xE1rea encosta em n\xF3s que n\xE3o est\xE3o no arranjo. Nada foi gravado. Origem livre sugerida: {"x":${a.freeOrigin.x},"y":${a.freeOrigin.y}} (abaixo de tudo${scoped ? " da aba" : ""} nessa faixa), ou tire esses n\xF3s do caminho.`;
|
|
25550
25937
|
if (args.dry_run) {
|
|
25551
|
-
const { a, ops, text: text2 } = plan((await api.snapshot(args.board_id)).doc);
|
|
25938
|
+
const { a, scoped, ops, text: text2 } = plan((await api.snapshot(args.board_id)).doc);
|
|
25552
25939
|
const head = `Pr\xE9via, nada gravado: ${ops.length ? `${count(ops)} n\xF3(s) mudariam de lugar ou largura` : "tudo j\xE1 est\xE1 assim"}.`;
|
|
25553
|
-
return [head, ...a.outer.length ? [blocked(a)] : [], text2].join("\n");
|
|
25940
|
+
return [head, ...a.outer.length ? [blocked(a, scoped)] : [], text2].join("\n");
|
|
25554
25941
|
}
|
|
25555
25942
|
let text = "";
|
|
25556
25943
|
const done = await edit(
|
|
@@ -25558,7 +25945,7 @@ function registerCanvasLayoutTools(server, deps) {
|
|
|
25558
25945
|
async (doc) => {
|
|
25559
25946
|
const p = plan(doc);
|
|
25560
25947
|
text = p.text;
|
|
25561
|
-
if (p.a.outer.length) throw new CanvasToolError(`${blocked(p.a)}
|
|
25948
|
+
if (p.a.outer.length) throw new CanvasToolError(`${blocked(p.a, p.scoped)}
|
|
25562
25949
|
${p.text}`);
|
|
25563
25950
|
return {
|
|
25564
25951
|
ops: p.ops,
|
|
@@ -25654,7 +26041,7 @@ function needMediaNode(doc, nodeId3) {
|
|
|
25654
26041
|
if (!node) throw new CanvasToolError(`N\xF3 ${nodeId3} n\xE3o existe no board. Releia com canvas_read_board.`);
|
|
25655
26042
|
if (nodeKind(node) !== "media") {
|
|
25656
26043
|
throw new CanvasToolError(
|
|
25657
|
-
`O n\xF3 ${nodeId3} ("${
|
|
26044
|
+
`O n\xF3 ${nodeId3} ("${oneLine2(nodeName(node), 40)}") \xE9 ${nodeKind(node) ?? node.type}, n\xE3o M\xEDdia. Passe o id de um n\xF3 media, ou omita node_id para criar um n\xF3 M\xEDdia novo.`
|
|
25658
26045
|
);
|
|
25659
26046
|
}
|
|
25660
26047
|
return node;
|
|
@@ -25689,20 +26076,26 @@ function registerCanvasMediaTools(server, deps) {
|
|
|
25689
26076
|
"canvas_upload_media",
|
|
25690
26077
|
{
|
|
25691
26078
|
title: "Canvas: subir arquivo",
|
|
25692
|
-
description: "Sobe um arquivo (caminho local ou URL) pela rota de arquivos da BePlus e devolve o item pronto: url, mime, bytes, dura\xE7\xE3o/largura/altura quando \xE9 m\xEDdia, media_item (data.items do n\xF3 M\xEDdia), sequence_asset e libraryItemId (clipe da timeline da Montagem). Com board_id grava no n\xF3 M\xEDdia node_id, ou cria um n\xF3 M\xEDdia novo sem node_id; a\xED exige canvas_read_board nesta sess\xE3o. Teto de 95 MB. N\xE3o gera m\xEDdia nem gasta diamantes.",
|
|
26079
|
+
description: "Sobe um arquivo (caminho local ou URL) pela rota de arquivos da BePlus e devolve o item pronto: url, mime, bytes, dura\xE7\xE3o/largura/altura quando \xE9 m\xEDdia, media_item (data.items do n\xF3 M\xEDdia), sequence_asset e libraryItemId (clipe da timeline da Montagem). Com board_id grava no n\xF3 M\xEDdia node_id, ou cria um n\xF3 M\xEDdia novo sem node_id (com aba, ele nasce no fim do conte\xFAdo da aba e grava data.abaId); a\xED exige canvas_read_board nesta sess\xE3o. Teto de 95 MB. N\xE3o gera m\xEDdia nem gasta diamantes.",
|
|
25693
26080
|
inputSchema: {
|
|
25694
26081
|
source: external_exports.string().trim().min(1).max(2e3).describe("Caminho local (/\u2026, ~/\u2026, file://) ou URL http(s)."),
|
|
25695
26082
|
name: external_exports.string().trim().min(1).max(120).optional().describe("Nome do arquivo no Canvas (a extens\xE3o \xE9 mantida)."),
|
|
25696
26083
|
board_id: external_exports.string().uuid().optional().describe("Board onde gravar o item (opcional)."),
|
|
25697
26084
|
node_id: external_exports.string().min(1).max(128).optional().describe("N\xF3 M\xEDdia que recebe o item. Sem ele, cria um n\xF3 M\xEDdia novo."),
|
|
26085
|
+
aba: abaArg(ABA_UPLOAD_MEDIA),
|
|
25698
26086
|
label: external_exports.string().trim().min(1).max(120).optional().describe("Nome do n\xF3 M\xEDdia novo (padr\xE3o: nome do arquivo)."),
|
|
25699
26087
|
replace: external_exports.boolean().optional().describe("true troca a lista do n\xF3 por este arquivo; false acrescenta. Padr\xE3o: a regra do Canvas (n\xF3 de um arquivo s\xF3, ligado, troca).")
|
|
25700
26088
|
},
|
|
25701
26089
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true }
|
|
25702
26090
|
},
|
|
25703
26091
|
async (args) => run(async () => {
|
|
25704
|
-
if (!args.board_id && (args.node_id || args.label || args.replace !== void 0)) {
|
|
25705
|
-
throw new CanvasToolError("node_id, label e
|
|
26092
|
+
if (!args.board_id && (args.node_id || args.label || args.replace !== void 0 || args.aba)) {
|
|
26093
|
+
throw new CanvasToolError("node_id, label, replace e aba s\xF3 valem com board_id.");
|
|
26094
|
+
}
|
|
26095
|
+
if (args.aba && args.node_id) {
|
|
26096
|
+
throw new CanvasToolError(
|
|
26097
|
+
"aba s\xF3 vale quando o upload cria um n\xF3 M\xEDdia novo (sem node_id): o n\xF3 que j\xE1 existe n\xE3o muda de aba por aqui."
|
|
26098
|
+
);
|
|
25706
26099
|
}
|
|
25707
26100
|
if (args.board_id) {
|
|
25708
26101
|
if (!seen.has(args.board_id)) {
|
|
@@ -25710,12 +26103,13 @@ function registerCanvasMediaTools(server, deps) {
|
|
|
25710
26103
|
}
|
|
25711
26104
|
const snap = await api.snapshot(args.board_id);
|
|
25712
26105
|
if (snap.role === "viewer") throw new CanvasToolError("Voc\xEA \xE9 s\xF3 leitor neste board: pe\xE7a ao dono para te dar papel de editor.");
|
|
26106
|
+
if (args.aba) resolveTab(snap.doc, args.aba);
|
|
25713
26107
|
if (args.node_id) {
|
|
25714
26108
|
const node = needMediaNode(snap.doc, args.node_id);
|
|
25715
26109
|
const replacing = args.replace ?? holdsOne(snap.doc, node);
|
|
25716
26110
|
if (!replacing && itemsOf(node).length >= MAX_MEDIA_ITEMS) {
|
|
25717
26111
|
throw new CanvasToolError(
|
|
25718
|
-
`O n\xF3 "${
|
|
26112
|
+
`O n\xF3 "${oneLine2(nodeName(node), 40)}" j\xE1 tem ${MAX_MEDIA_ITEMS} arquivos (teto do Canvas). Omita node_id para criar outro n\xF3 M\xEDdia.`
|
|
25719
26113
|
);
|
|
25720
26114
|
}
|
|
25721
26115
|
}
|
|
@@ -25749,14 +26143,21 @@ URL: ${u.url}`;
|
|
|
25749
26143
|
return {
|
|
25750
26144
|
ops: [{ type: "node.set", nodeId: node.id, path: "data.items", value: setValue(items) }],
|
|
25751
26145
|
targets: [node.id],
|
|
25752
|
-
done: `N\xF3 M\xEDdia "${
|
|
26146
|
+
done: `N\xF3 M\xEDdia "${oneLine2(nodeName(node), 40)}" (${node.id}): ` + (replacing ? `arquivo trocado (${before} \u2192 1)` : `arquivo acrescentado, agora com ${items.length}`)
|
|
25753
26147
|
};
|
|
25754
26148
|
}
|
|
25755
26149
|
const spec = KINDS.media;
|
|
26150
|
+
const tab = args.aba ? resolveTab(doc, args.aba) : void 0;
|
|
25756
26151
|
const created = makeNode({
|
|
25757
26152
|
type: WORKFLOW_NODE_TYPE,
|
|
25758
|
-
data: {
|
|
25759
|
-
|
|
26153
|
+
data: {
|
|
26154
|
+
...spec.data,
|
|
26155
|
+
[KIND_FIELD]: "media",
|
|
26156
|
+
label: args.label ?? u.name,
|
|
26157
|
+
items: [item],
|
|
26158
|
+
...tab === void 0 ? {} : { [TAB_ID_FIELD]: tab }
|
|
26159
|
+
},
|
|
26160
|
+
position: placeFor(doc, spec.size, void 0, "right", tab),
|
|
25760
26161
|
size: spec.size,
|
|
25761
26162
|
zIndex: Object.values(doc.nodes).reduce((t, n) => Math.max(t, n.zIndex), 0) + 1,
|
|
25762
26163
|
createdBy: await api.me()
|
|
@@ -25765,7 +26166,7 @@ URL: ${u.url}`;
|
|
|
25765
26166
|
return {
|
|
25766
26167
|
ops: [{ type: "node.add", nodeId: created.id, node: created }],
|
|
25767
26168
|
targets: [],
|
|
25768
|
-
done: `N\xF3 M\xEDdia "${
|
|
26169
|
+
done: `N\xF3 M\xEDdia "${oneLine2(nodeName(created), 40)}" criado: ${created.id}.${placementNote(doc, created)}`
|
|
25769
26170
|
};
|
|
25770
26171
|
});
|
|
25771
26172
|
} catch (e) {
|
|
@@ -26145,6 +26546,7 @@ function isLockedSection(node) {
|
|
|
26145
26546
|
return node !== void 0 && nodeKind(node) === "section" && node.data[SECTION_LOCK_FIELD] === true;
|
|
26146
26547
|
}
|
|
26147
26548
|
var LAYOUT_PATH = /^(position|size)(\.|$)/;
|
|
26549
|
+
var STAMP_PATH = `data.${TAB_ID_FIELD}`;
|
|
26148
26550
|
function rectOf(node, withMeasured) {
|
|
26149
26551
|
const h = withMeasured ? Math.max(node.size.h, readMeasured(node)?.h ?? 0) : node.size.h;
|
|
26150
26552
|
return { x: node.position.x, y: node.position.y, w: node.size.w, h };
|
|
@@ -26152,14 +26554,14 @@ function rectOf(node, withMeasured) {
|
|
|
26152
26554
|
function contains(outer, inner) {
|
|
26153
26555
|
return inner.x >= outer.x && inner.y >= outer.y && inner.x + inner.w <= outer.x + outer.w && inner.y + inner.h <= outer.y + outer.h;
|
|
26154
26556
|
}
|
|
26155
|
-
function
|
|
26156
|
-
return ops.flatMap((op) => op.type === "batch" ?
|
|
26557
|
+
function flatten2(ops) {
|
|
26558
|
+
return ops.flatMap((op) => op.type === "batch" ? flatten2(op.ops) : [op]);
|
|
26157
26559
|
}
|
|
26158
26560
|
function lockViolation(doc, ops) {
|
|
26159
26561
|
const locked = Object.values(doc.nodes).filter(isLockedSection);
|
|
26160
26562
|
if (!locked.length) return null;
|
|
26161
|
-
const name = (node) => `"${
|
|
26162
|
-
const flat =
|
|
26563
|
+
const name = (node) => `"${oneLine2(tabTitle(node), 40)}"`;
|
|
26564
|
+
const flat = flatten2(ops);
|
|
26163
26565
|
for (const op of flat) {
|
|
26164
26566
|
if (op.type !== "node.set" && op.type !== "node.remove") continue;
|
|
26165
26567
|
const node = doc.nodes[op.nodeId];
|
|
@@ -26167,18 +26569,30 @@ function lockViolation(doc, ops) {
|
|
|
26167
26569
|
if (op.type === "node.remove") return `${name(node)}: ${LOCKED_TEXT}. Nada foi apagado.`;
|
|
26168
26570
|
if (LAYOUT_PATH.test(op.path)) return `${name(node)}: ${LOCKED_TEXT}. Nada foi aplicado.`;
|
|
26169
26571
|
}
|
|
26170
|
-
const
|
|
26572
|
+
const home = partitionOf(doc).home;
|
|
26573
|
+
const placed = /* @__PURE__ */ new Set();
|
|
26574
|
+
const restamped = /* @__PURE__ */ new Set();
|
|
26171
26575
|
for (const op of flat) {
|
|
26172
|
-
if (op.type !== "node.set"
|
|
26576
|
+
if (op.type !== "node.set") continue;
|
|
26173
26577
|
const node = doc.nodes[op.nodeId];
|
|
26174
|
-
if (node
|
|
26578
|
+
if (node === void 0 || nodeKind(node) === "section") continue;
|
|
26579
|
+
if (LAYOUT_PATH.test(op.path)) {
|
|
26580
|
+
placed.add(op.nodeId);
|
|
26581
|
+
} else if (op.path === STAMP_PATH) {
|
|
26582
|
+
const sameHome = op.value.kind === "value" && op.value.value === home.get(op.nodeId);
|
|
26583
|
+
if (!sameHome) restamped.add(op.nodeId);
|
|
26584
|
+
}
|
|
26175
26585
|
}
|
|
26586
|
+
const moved = /* @__PURE__ */ new Set([...placed, ...restamped]);
|
|
26176
26587
|
if (moved.size < 2) return null;
|
|
26177
26588
|
for (const section of locked) {
|
|
26178
|
-
const
|
|
26179
|
-
|
|
26589
|
+
const inside = isTabSection(section) ? [...moved].filter((id) => home.get(id) === section.id) : (() => {
|
|
26590
|
+
const outer = rectOf(section, false);
|
|
26591
|
+
return [...placed].filter((id) => contains(outer, rectOf(doc.nodes[id], true)));
|
|
26592
|
+
})();
|
|
26180
26593
|
if (inside.length >= 2) {
|
|
26181
|
-
|
|
26594
|
+
const stamp = inside.some((id) => restamped.has(id)) ? " Trocar a aba (data.abaId) tamb\xE9m conta como mexer na aba." : "";
|
|
26595
|
+
return `${name(section)}: ${LOCKED_TEXT}. Mudar ${inside.length} n\xF3s de dentro dela num pedido s\xF3 n\xE3o vale (um por vez segue valendo).${stamp} Nada foi aplicado.`;
|
|
26182
26596
|
}
|
|
26183
26597
|
}
|
|
26184
26598
|
return null;
|
|
@@ -26383,7 +26797,7 @@ function registerCanvasTools(server, client, cfg) {
|
|
|
26383
26797
|
return fail(e);
|
|
26384
26798
|
}
|
|
26385
26799
|
}
|
|
26386
|
-
async function edit(id,
|
|
26800
|
+
async function edit(id, build2, opts = {}) {
|
|
26387
26801
|
const last = seen.get(id);
|
|
26388
26802
|
if (last === void 0 && !opts.layoutOnly) {
|
|
26389
26803
|
throw new CanvasToolError("Leia o board com canvas_read_board antes de editar (a leitura vale para a sess\xE3o).");
|
|
@@ -26391,11 +26805,13 @@ function registerCanvasTools(server, client, cfg) {
|
|
|
26391
26805
|
const snap = await api.snapshot(id);
|
|
26392
26806
|
if (snap.role === "viewer") throw new CanvasToolError("Voc\xEA \xE9 s\xF3 leitor neste board: pe\xE7a ao dono para te dar papel de editor.");
|
|
26393
26807
|
const doc = snap.doc;
|
|
26394
|
-
const { ops, done, targets } = await
|
|
26808
|
+
const { ops, done, targets } = await build2(doc, snap);
|
|
26395
26809
|
if (!ops.length) return `Nada a mudar. ${done}`;
|
|
26396
26810
|
if (opts.layoutOnly && !ops.every(isLayoutOp)) throw new Error("layout_only com opera\xE7\xE3o fora de posi\xE7\xE3o/tamanho");
|
|
26397
26811
|
const locked = lockViolation(doc, ops);
|
|
26398
26812
|
if (locked) throw new CanvasToolError(locked);
|
|
26813
|
+
const badAba = abaIdViolation(doc, ops);
|
|
26814
|
+
if (badAba) throw new CanvasToolError(`${badAba} Nada foi aplicado.`);
|
|
26399
26815
|
let note = "";
|
|
26400
26816
|
if (!opts.layoutOnly && last !== void 0 && snap.seq > last) {
|
|
26401
26817
|
const since = await api.opsAfter(id, last);
|
|
@@ -26409,7 +26825,7 @@ function registerCanvasTools(server, client, cfg) {
|
|
|
26409
26825
|
const clash = [...touchedNodes(theirs)].filter((n) => targets.includes(n));
|
|
26410
26826
|
if (clash.length) {
|
|
26411
26827
|
seen.delete(id);
|
|
26412
|
-
const names = clash.map((n) => doc.nodes[n] ? `"${
|
|
26828
|
+
const names = clash.map((n) => doc.nodes[n] ? `"${oneLine2(nodeName(doc.nodes[n]), 40)}"` : n).join(", ");
|
|
26413
26829
|
throw new CanvasToolError(
|
|
26414
26830
|
`Outra pessoa mexeu em ${names} depois da sua leitura (seq ${last} \u2192 ${snap.seq}). Nada foi aplicado: releia com canvas_read_board e refa\xE7a a edi\xE7\xE3o em cima do estado atual.`
|
|
26415
26831
|
);
|
|
@@ -26506,15 +26922,17 @@ ${lines.join("\n")}${note}`;
|
|
|
26506
26922
|
}
|
|
26507
26923
|
return { ops, warn };
|
|
26508
26924
|
}
|
|
26509
|
-
function placeFor(doc, size, near, side = "right") {
|
|
26925
|
+
function placeFor(doc, size, near, side = "right", tab) {
|
|
26510
26926
|
if (near) {
|
|
26511
26927
|
const x = side === "right" ? near.position.x + near.size.w + GAP : near.position.x - size.w - GAP;
|
|
26512
26928
|
let y = near.position.y;
|
|
26513
|
-
const
|
|
26929
|
+
const scope = tab === void 0 ? null : membersOfTab(doc, tab);
|
|
26930
|
+
const nodes2 = Object.values(doc.nodes).filter((n) => scope === null || scope.has(n.id) && nodeKind(n) !== "section");
|
|
26514
26931
|
const hits = (yy) => nodes2.some((n) => x < n.position.x + n.size.w && x + size.w > n.position.x && yy < n.position.y + n.size.h && yy + size.h > n.position.y);
|
|
26515
26932
|
for (let i = 0; i < 50 && hits(y); i++) y += GAP;
|
|
26516
26933
|
return { x, y };
|
|
26517
26934
|
}
|
|
26935
|
+
if (tab !== void 0 && tab !== AVULSOS_TAB) return endOfTabContent(doc, tab, size);
|
|
26518
26936
|
const nodes = Object.values(doc.nodes).filter((n) => nodeKind(n) !== "section");
|
|
26519
26937
|
if (!nodes.length) return { x: 0, y: 0 };
|
|
26520
26938
|
return {
|
|
@@ -26570,7 +26988,7 @@ ${lines.join("\n")}${note}`;
|
|
|
26570
26988
|
for (const c of changed) after.nodes[c.node.id] = { ...c.node, data: c.data };
|
|
26571
26989
|
for (const e of newEdges) after.edges[e.id] = e;
|
|
26572
26990
|
const sync = mentionEdgeOps(after, prompts.map((c) => c.node.id), await api.me());
|
|
26573
|
-
const name = (id) => after.nodes[id] ? `"${
|
|
26991
|
+
const name = (id) => after.nodes[id] ? `"${oneLine2(nodeName(after.nodes[id]), 40)}"` : id;
|
|
26574
26992
|
return { ops: sync.ops, note: describeMentionSync(sync, name) };
|
|
26575
26993
|
}
|
|
26576
26994
|
server.registerTool(
|
|
@@ -26591,17 +27009,19 @@ ${lines.join("\n")}${note}`;
|
|
|
26591
27009
|
"canvas_read_board",
|
|
26592
27010
|
{
|
|
26593
27011
|
title: "Canvas: ler board",
|
|
26594
|
-
description: 'L\xEA um board: n\xF3s (id, tipo, nome, posi\xE7\xE3o, tamanho, campos principais), liga\xE7\xF5es e v\xEDnculo com o IA Lab, sem m\xEDdia. Tamanho "medido" \xE9 o da tela; "gravado" \xE9 o piso (o cart\xE3o cresce com o conte\xFAdo). Obrigat\xF3rio antes de editar (vale para a sess\xE3o). node_ids devolve o data desses n\xF3s, com cada corte marcado (path=\u2026); o valor inteiro (ex.: data.sequence da Montagem) sai no canvas_read_node.',
|
|
27012
|
+
description: 'L\xEA um board: n\xF3s (id, tipo, nome, posi\xE7\xE3o, tamanho, campos principais), liga\xE7\xF5es e v\xEDnculo com o IA Lab, sem m\xEDdia. Tamanho "medido" \xE9 o da tela; "gravado" \xE9 o piso (o cart\xE3o cresce com o conte\xFAdo). Obrigat\xF3rio antes de editar (vale para a sess\xE3o). node_ids devolve o data desses n\xF3s, com cada corte marcado (path=\u2026); o valor inteiro (ex.: data.sequence da Montagem) sai no canvas_read_node. Cada cart\xE3o diz a aba (aba=<id curto> ou aba=avulsos), o topo conta os cart\xF5es de cada aba e aba l\xEA uma aba s\xF3.',
|
|
26595
27013
|
inputSchema: {
|
|
26596
27014
|
board_id: boardId3,
|
|
26597
|
-
node_ids: external_exports.array(nodeIdArg2).max(20).optional().describe("N\xF3s para ver o data (sem blobs, cortes marcados).")
|
|
27015
|
+
node_ids: external_exports.array(nodeIdArg2).max(20).optional().describe("N\xF3s para ver o data (sem blobs, cortes marcados)."),
|
|
27016
|
+
aba: abaArg(ABA_READ_BOARD)
|
|
26598
27017
|
},
|
|
26599
27018
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
26600
27019
|
},
|
|
26601
|
-
async ({ board_id, node_ids }) => run(async () => {
|
|
27020
|
+
async ({ board_id, node_ids, aba }) => run(async () => {
|
|
26602
27021
|
const snap = await api.snapshot(board_id);
|
|
27022
|
+
const tab = aba ? resolveTab(snap.doc, aba, { allowAvulsos: true }) : void 0;
|
|
26603
27023
|
seen.set(board_id, snap.seq);
|
|
26604
|
-
const parts = [boardSummary(snap)];
|
|
27024
|
+
const parts = [boardSummary(snap, { tab })];
|
|
26605
27025
|
if (node_ids?.length) {
|
|
26606
27026
|
parts.push("", "Detalhe:");
|
|
26607
27027
|
for (const n of node_ids) parts.push(snap.doc.nodes[n] ? nodeDetail(snap.doc.nodes[n]) : `${n}: n\xE3o existe`);
|
|
@@ -26661,7 +27081,7 @@ ${lines.join("\n")}${note}`;
|
|
|
26661
27081
|
const hash = createHash("sha256").update(json2).digest("hex").slice(0, 12);
|
|
26662
27082
|
const where = `data${segments.length ? `.${segments.join(".")}` : ""}`;
|
|
26663
27083
|
const at = readMeasured(node)?.at;
|
|
26664
|
-
const head = `${node.id} \xB7 ${nodeKind(node) ?? node.type} \xB7 "${
|
|
27084
|
+
const head = `${node.id} \xB7 ${nodeKind(node) ?? node.type} \xB7 "${oneLine2(nodeName(node), 60)}" \xB7 board seq ${snap.seq} \xB7 tamanho ${sizeLabel(node)}${at ? ` \xB7 medido em ${at}` : ""} \xB7 ${where}${which}: ${total} caracteres (JSON compacto) \xB7 sha256 ${hash}`;
|
|
26665
27085
|
const part = from === 0 && to === total ? "Inteiro, abaixo." : `Parte: caracteres ${from} a ${to} de ${total}. ${to < total ? `Falta o resto: chame de novo com offset=${to}.` : "Esta \xE9 a \xFAltima parte."}`;
|
|
26666
27086
|
return `${head}
|
|
26667
27087
|
${part}
|
|
@@ -26722,12 +27142,13 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
26722
27142
|
"canvas_add_node",
|
|
26723
27143
|
{
|
|
26724
27144
|
title: "Canvas: adicionar n\xF3",
|
|
26725
|
-
description: `Adiciona um n\xF3 (n\xE3o executa). ${READ}kind: ${kindList()}. data completa o padr\xE3o do tipo; label d\xE1 o nome. Sem position, nasce ao lado do n\xF3 ligado ou \xE0 direita do board. inputs/outputs j\xE1 ligam o n\xF3 no mesmo passo. ` + MENTION_NOTE + MONTAGE_NOTE,
|
|
27145
|
+
description: `Adiciona um n\xF3 (n\xE3o executa). ${READ}kind: ${kindList()}. data completa o padr\xE3o do tipo; label d\xE1 o nome. Sem position, nasce ao lado do n\xF3 ligado ou \xE0 direita do board (com aba, no fim do conte\xFAdo da aba); aba grava data.abaId. inputs/outputs j\xE1 ligam o n\xF3 no mesmo passo. ` + MENTION_NOTE + MONTAGE_NOTE,
|
|
26726
27146
|
inputSchema: {
|
|
26727
27147
|
board_id: boardId3,
|
|
26728
27148
|
kind: external_exports.string().min(1).max(40),
|
|
26729
27149
|
label: external_exports.string().trim().min(1).max(120).optional().describe("Nome do cart\xE3o (data.label)."),
|
|
26730
27150
|
data: external_exports.record(external_exports.unknown()).optional().describe("Campos do data. Ex.: narration {blocks:[{id,text}]}, text {text}, prompt {template}."),
|
|
27151
|
+
aba: abaArg(ABA_ADD_NODE),
|
|
26731
27152
|
position: point.optional(),
|
|
26732
27153
|
size: sizeArg.optional(),
|
|
26733
27154
|
inputs: external_exports.array(external_exports.object({ from: nodeIdArg2, from_port: external_exports.string().min(1), to_port: external_exports.string().min(1) })).max(20).optional().describe("Liga\xE7\xF5es que CHEGAM no n\xF3 novo: from.from_port \u2192 novo.to_port."),
|
|
@@ -26748,8 +27169,19 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
26748
27169
|
const b = boxOf(args.size);
|
|
26749
27170
|
box = { w: b.w ?? spec.size.w, h: b.h ?? spec.size.h };
|
|
26750
27171
|
}
|
|
27172
|
+
const byParam = args.aba ? resolveTab(doc, args.aba) : void 0;
|
|
27173
|
+
const written = data[TAB_ID_FIELD];
|
|
27174
|
+
const byData = typeof written === "string" && written !== "" ? resolveTab(doc, written) : void 0;
|
|
27175
|
+
if (byParam !== void 0 && byData !== void 0 && byParam !== byData) {
|
|
27176
|
+
throw new CanvasToolError(
|
|
27177
|
+
`aba ("${tabTitle(doc.nodes[byParam])}") e data.abaId ("${tabTitle(doc.nodes[byData])}") apontam para abas diferentes: mande s\xF3 aba.`
|
|
27178
|
+
);
|
|
27179
|
+
}
|
|
27180
|
+
const tab = byParam ?? byData;
|
|
27181
|
+
if (tab !== void 0) data[TAB_ID_FIELD] = tab;
|
|
26751
27182
|
const near = args.inputs?.[0] ? doc.nodes[args.inputs[0].from] : args.outputs?.[0] ? doc.nodes[args.outputs[0].to] : void 0;
|
|
26752
|
-
const
|
|
27183
|
+
const nearTab = near ? homeTabOf(doc, near.id) ?? void 0 : void 0;
|
|
27184
|
+
const position = args.position ?? placeFor(doc, box, tab === void 0 ? near : void 0, args.inputs?.[0] ? "right" : "left", tab ?? nearTab);
|
|
26753
27185
|
const zIndex = args.kind === "section" ? SECTION_Z : Object.values(doc.nodes).reduce((t, n) => Math.max(t, n.zIndex), 0) + 1;
|
|
26754
27186
|
const node = makeNode({ type: WORKFLOW_NODE_TYPE, data, position, size: box, zIndex, createdBy: me });
|
|
26755
27187
|
const links = [
|
|
@@ -26770,7 +27202,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
26770
27202
|
return {
|
|
26771
27203
|
ops: [{ type: "node.add", nodeId: node.id, node }, ...edges.ops, ...mention.ops],
|
|
26772
27204
|
targets: links.map((l) => l.source === node.id ? l.target : l.source),
|
|
26773
|
-
done: `N\xF3 ${args.kind} "${nodeName(node)}" criado: ${node.id}${edges.ops.length ? ` com ${edges.ops.length} liga\xE7\xE3o(\xF5es)` : ""}.${edges.warn}${mention.note}`
|
|
27205
|
+
done: `N\xF3 ${args.kind} "${nodeName(node)}" criado: ${node.id}${edges.ops.length ? ` com ${edges.ops.length} liga\xE7\xE3o(\xF5es)` : ""}.${placementNote(doc, node)}${edges.warn}${mention.note}`
|
|
26774
27206
|
};
|
|
26775
27207
|
})
|
|
26776
27208
|
)
|
|
@@ -26844,7 +27276,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
26844
27276
|
});
|
|
26845
27277
|
const mention = args.layout_only ? { ops: [], note: "" } : await mentionOps(doc, changes.map((c) => ({ node: c.node, data: c.data, keys: c.dataKeys })));
|
|
26846
27278
|
const touched = changes.filter((c) => c.ops.length);
|
|
26847
|
-
const list = touched.slice(0, 12).map((c) => `"${
|
|
27279
|
+
const list = touched.slice(0, 12).map((c) => `"${oneLine2(nodeName(c.node), 30)}" (${c.keys.join(", ")})`).join("; ");
|
|
26848
27280
|
return {
|
|
26849
27281
|
ops: [...changes.flatMap((c) => c.ops), ...mention.ops],
|
|
26850
27282
|
targets: ids,
|
|
@@ -26947,7 +27379,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
26947
27379
|
return {
|
|
26948
27380
|
ops,
|
|
26949
27381
|
targets: [node.id],
|
|
26950
|
-
done: `N\xF3 "${
|
|
27382
|
+
done: `N\xF3 "${oneLine2(nodeName(node), 40)}" (${node.id}): ${written} caminho(s) gravado(s)` + (skipped ? ` (ignorados: ${skipped})` : "") + mention.note
|
|
26951
27383
|
};
|
|
26952
27384
|
},
|
|
26953
27385
|
{ split: true }
|
|
@@ -27017,7 +27449,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
27017
27449
|
ops.push(op);
|
|
27018
27450
|
}
|
|
27019
27451
|
}
|
|
27020
|
-
const names = nodeIds.map((n) => `"${
|
|
27452
|
+
const names = nodeIds.map((n) => `"${oneLine2(nodeName(doc.nodes[n]), 40)}"`);
|
|
27021
27453
|
return {
|
|
27022
27454
|
ops,
|
|
27023
27455
|
targets: nodeIds,
|
|
@@ -27099,7 +27531,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
27099
27531
|
import { createRequire } from "module";
|
|
27100
27532
|
var require2 = createRequire(import.meta.url);
|
|
27101
27533
|
function readVersion() {
|
|
27102
|
-
if ("0.
|
|
27534
|
+
if ("0.37.0") return "0.37.0";
|
|
27103
27535
|
try {
|
|
27104
27536
|
const pkg = require2("../package.json");
|
|
27105
27537
|
return pkg.version ?? "0.0.0-unknown";
|
|
@@ -27115,6 +27547,7 @@ var SERVER_INSTRUCTIONS = [
|
|
|
27115
27547
|
'M\xEDdia: generate_* gasta diamantes; confira com estimate_cost antes de lotes grandes. Sem project, a gera\xE7\xE3o cai no projeto ativo; billing:"personal" cobra do usu\xE1rio.',
|
|
27116
27548
|
"Calls: search_calls acha, get_call traz a transcri\xE7\xE3o.",
|
|
27117
27549
|
"Canvas online (canvas_*): leia com canvas_read_board antes de editar e siga o estado lido. Cada edi\xE7\xE3o vai num passo s\xF3; se outra pessoa mexeu nos mesmos n\xF3s, a ferramenta recusa e pede releitura. As canvas_* n\xE3o geram m\xEDdia, exceto canvas_run: roda n\xF3s pela aba do Canvas aberta do usu\xE1rio e gasta diamantes; max_diamonds \xE9 o teto que o usu\xE1rio autorizou (dry_run s\xF3 estima). D\xEA nome (label) aos n\xF3s, n\xE3o invente tipos nem portas, e confirme antes de canvas_delete.",
|
|
27550
|
+
"Cada aba \xE9 um plano: ao criar, passe aba (id da se\xE7\xE3o) em canvas_add_node e canvas_upload_media, sen\xE3o o cart\xE3o pode cair em Avulsos. canvas_read_board com aba l\xEA uma aba s\xF3.",
|
|
27118
27551
|
'Mostrar algo ao usu\xE1rio ("olha aqui"): canvas_focus leva a aba do Canvas que ele est\xE1 olhando at\xE9 os n\xF3s e os seleciona uma vez, sem prender a aba, sem gasto e sem escrita no board. follow: true prende a aba na \xE1rea at\xE9 o \xD7: s\xF3 se ele pedir.',
|
|
27119
27552
|
'Arrumar o board: o size gravado \xE9 piso (o cart\xE3o cresce com o conte\xFAdo); use o tamanho "medido" do canvas_read_board. \xC1rea de revis\xE3o: canvas_arrange_rows (uma linha por vers\xE3o); posi\xE7\xE3o/tamanho em lote: canvas_update_nodes com layout_only. N\xE3o afirme que nada se sobrep\xF5e com n\xF3 sem medida.',
|
|
27120
27553
|
'"Aplica os coment\xE1rios" do board: canvas_list_comments (abertos) \u2192 para cada um, leia o n\xF3 ancorado com canvas_read_board (node_ids), aplique a edi\xE7\xE3o pelas canvas_* e feche com canvas_resolve_comment dizendo em uma frase o que fez. Coment\xE1rio amb\xEDguo ou com alvo sumido: responda com pergunta (canvas_reply_comment) e n\xE3o resolva. D\xFAvida sua sobre um n\xF3: canvas_comment ancorado nele. As escritas j\xE1 saem espa\xE7adas (60/min); se ainda vier limite, pare e diga de onde seguir.'
|