beplus-mcp 0.35.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 +545 -64
- 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) {
|
|
@@ -26138,6 +26539,65 @@ function registerCanvasFocusTools(server, api, run) {
|
|
|
26138
26539
|
);
|
|
26139
26540
|
}
|
|
26140
26541
|
|
|
26542
|
+
// src/canvas/lock.ts
|
|
26543
|
+
var SECTION_LOCK_FIELD = "travada";
|
|
26544
|
+
var LOCKED_TEXT = "\xE1rea travada pelo dono (cadeado); pe\xE7a pra destravar";
|
|
26545
|
+
function isLockedSection(node) {
|
|
26546
|
+
return node !== void 0 && nodeKind(node) === "section" && node.data[SECTION_LOCK_FIELD] === true;
|
|
26547
|
+
}
|
|
26548
|
+
var LAYOUT_PATH = /^(position|size)(\.|$)/;
|
|
26549
|
+
var STAMP_PATH = `data.${TAB_ID_FIELD}`;
|
|
26550
|
+
function rectOf(node, withMeasured) {
|
|
26551
|
+
const h = withMeasured ? Math.max(node.size.h, readMeasured(node)?.h ?? 0) : node.size.h;
|
|
26552
|
+
return { x: node.position.x, y: node.position.y, w: node.size.w, h };
|
|
26553
|
+
}
|
|
26554
|
+
function contains(outer, inner) {
|
|
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;
|
|
26556
|
+
}
|
|
26557
|
+
function flatten2(ops) {
|
|
26558
|
+
return ops.flatMap((op) => op.type === "batch" ? flatten2(op.ops) : [op]);
|
|
26559
|
+
}
|
|
26560
|
+
function lockViolation(doc, ops) {
|
|
26561
|
+
const locked = Object.values(doc.nodes).filter(isLockedSection);
|
|
26562
|
+
if (!locked.length) return null;
|
|
26563
|
+
const name = (node) => `"${oneLine2(tabTitle(node), 40)}"`;
|
|
26564
|
+
const flat = flatten2(ops);
|
|
26565
|
+
for (const op of flat) {
|
|
26566
|
+
if (op.type !== "node.set" && op.type !== "node.remove") continue;
|
|
26567
|
+
const node = doc.nodes[op.nodeId];
|
|
26568
|
+
if (!isLockedSection(node)) continue;
|
|
26569
|
+
if (op.type === "node.remove") return `${name(node)}: ${LOCKED_TEXT}. Nada foi apagado.`;
|
|
26570
|
+
if (LAYOUT_PATH.test(op.path)) return `${name(node)}: ${LOCKED_TEXT}. Nada foi aplicado.`;
|
|
26571
|
+
}
|
|
26572
|
+
const home = partitionOf(doc).home;
|
|
26573
|
+
const placed = /* @__PURE__ */ new Set();
|
|
26574
|
+
const restamped = /* @__PURE__ */ new Set();
|
|
26575
|
+
for (const op of flat) {
|
|
26576
|
+
if (op.type !== "node.set") continue;
|
|
26577
|
+
const node = doc.nodes[op.nodeId];
|
|
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
|
+
}
|
|
26585
|
+
}
|
|
26586
|
+
const moved = /* @__PURE__ */ new Set([...placed, ...restamped]);
|
|
26587
|
+
if (moved.size < 2) return null;
|
|
26588
|
+
for (const section of locked) {
|
|
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
|
+
})();
|
|
26593
|
+
if (inside.length >= 2) {
|
|
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.`;
|
|
26596
|
+
}
|
|
26597
|
+
}
|
|
26598
|
+
return null;
|
|
26599
|
+
}
|
|
26600
|
+
|
|
26141
26601
|
// src/canvas/mentions.ts
|
|
26142
26602
|
var VIA_MENTION = "viaMention";
|
|
26143
26603
|
var PROMPT_REFS_INPUT = "refs";
|
|
@@ -26337,7 +26797,7 @@ function registerCanvasTools(server, client, cfg) {
|
|
|
26337
26797
|
return fail(e);
|
|
26338
26798
|
}
|
|
26339
26799
|
}
|
|
26340
|
-
async function edit(id,
|
|
26800
|
+
async function edit(id, build2, opts = {}) {
|
|
26341
26801
|
const last = seen.get(id);
|
|
26342
26802
|
if (last === void 0 && !opts.layoutOnly) {
|
|
26343
26803
|
throw new CanvasToolError("Leia o board com canvas_read_board antes de editar (a leitura vale para a sess\xE3o).");
|
|
@@ -26345,9 +26805,13 @@ function registerCanvasTools(server, client, cfg) {
|
|
|
26345
26805
|
const snap = await api.snapshot(id);
|
|
26346
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.");
|
|
26347
26807
|
const doc = snap.doc;
|
|
26348
|
-
const { ops, done, targets } = await
|
|
26808
|
+
const { ops, done, targets } = await build2(doc, snap);
|
|
26349
26809
|
if (!ops.length) return `Nada a mudar. ${done}`;
|
|
26350
26810
|
if (opts.layoutOnly && !ops.every(isLayoutOp)) throw new Error("layout_only com opera\xE7\xE3o fora de posi\xE7\xE3o/tamanho");
|
|
26811
|
+
const locked = lockViolation(doc, ops);
|
|
26812
|
+
if (locked) throw new CanvasToolError(locked);
|
|
26813
|
+
const badAba = abaIdViolation(doc, ops);
|
|
26814
|
+
if (badAba) throw new CanvasToolError(`${badAba} Nada foi aplicado.`);
|
|
26351
26815
|
let note = "";
|
|
26352
26816
|
if (!opts.layoutOnly && last !== void 0 && snap.seq > last) {
|
|
26353
26817
|
const since = await api.opsAfter(id, last);
|
|
@@ -26361,7 +26825,7 @@ function registerCanvasTools(server, client, cfg) {
|
|
|
26361
26825
|
const clash = [...touchedNodes(theirs)].filter((n) => targets.includes(n));
|
|
26362
26826
|
if (clash.length) {
|
|
26363
26827
|
seen.delete(id);
|
|
26364
|
-
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(", ");
|
|
26365
26829
|
throw new CanvasToolError(
|
|
26366
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.`
|
|
26367
26831
|
);
|
|
@@ -26458,15 +26922,17 @@ ${lines.join("\n")}${note}`;
|
|
|
26458
26922
|
}
|
|
26459
26923
|
return { ops, warn };
|
|
26460
26924
|
}
|
|
26461
|
-
function placeFor(doc, size, near, side = "right") {
|
|
26925
|
+
function placeFor(doc, size, near, side = "right", tab) {
|
|
26462
26926
|
if (near) {
|
|
26463
26927
|
const x = side === "right" ? near.position.x + near.size.w + GAP : near.position.x - size.w - GAP;
|
|
26464
26928
|
let y = near.position.y;
|
|
26465
|
-
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");
|
|
26466
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);
|
|
26467
26932
|
for (let i = 0; i < 50 && hits(y); i++) y += GAP;
|
|
26468
26933
|
return { x, y };
|
|
26469
26934
|
}
|
|
26935
|
+
if (tab !== void 0 && tab !== AVULSOS_TAB) return endOfTabContent(doc, tab, size);
|
|
26470
26936
|
const nodes = Object.values(doc.nodes).filter((n) => nodeKind(n) !== "section");
|
|
26471
26937
|
if (!nodes.length) return { x: 0, y: 0 };
|
|
26472
26938
|
return {
|
|
@@ -26522,7 +26988,7 @@ ${lines.join("\n")}${note}`;
|
|
|
26522
26988
|
for (const c of changed) after.nodes[c.node.id] = { ...c.node, data: c.data };
|
|
26523
26989
|
for (const e of newEdges) after.edges[e.id] = e;
|
|
26524
26990
|
const sync = mentionEdgeOps(after, prompts.map((c) => c.node.id), await api.me());
|
|
26525
|
-
const name = (id) => after.nodes[id] ? `"${
|
|
26991
|
+
const name = (id) => after.nodes[id] ? `"${oneLine2(nodeName(after.nodes[id]), 40)}"` : id;
|
|
26526
26992
|
return { ops: sync.ops, note: describeMentionSync(sync, name) };
|
|
26527
26993
|
}
|
|
26528
26994
|
server.registerTool(
|
|
@@ -26543,17 +27009,19 @@ ${lines.join("\n")}${note}`;
|
|
|
26543
27009
|
"canvas_read_board",
|
|
26544
27010
|
{
|
|
26545
27011
|
title: "Canvas: ler board",
|
|
26546
|
-
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.',
|
|
26547
27013
|
inputSchema: {
|
|
26548
27014
|
board_id: boardId3,
|
|
26549
|
-
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)
|
|
26550
27017
|
},
|
|
26551
27018
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
26552
27019
|
},
|
|
26553
|
-
async ({ board_id, node_ids }) => run(async () => {
|
|
27020
|
+
async ({ board_id, node_ids, aba }) => run(async () => {
|
|
26554
27021
|
const snap = await api.snapshot(board_id);
|
|
27022
|
+
const tab = aba ? resolveTab(snap.doc, aba, { allowAvulsos: true }) : void 0;
|
|
26555
27023
|
seen.set(board_id, snap.seq);
|
|
26556
|
-
const parts = [boardSummary(snap)];
|
|
27024
|
+
const parts = [boardSummary(snap, { tab })];
|
|
26557
27025
|
if (node_ids?.length) {
|
|
26558
27026
|
parts.push("", "Detalhe:");
|
|
26559
27027
|
for (const n of node_ids) parts.push(snap.doc.nodes[n] ? nodeDetail(snap.doc.nodes[n]) : `${n}: n\xE3o existe`);
|
|
@@ -26613,7 +27081,7 @@ ${lines.join("\n")}${note}`;
|
|
|
26613
27081
|
const hash = createHash("sha256").update(json2).digest("hex").slice(0, 12);
|
|
26614
27082
|
const where = `data${segments.length ? `.${segments.join(".")}` : ""}`;
|
|
26615
27083
|
const at = readMeasured(node)?.at;
|
|
26616
|
-
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}`;
|
|
26617
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."}`;
|
|
26618
27086
|
return `${head}
|
|
26619
27087
|
${part}
|
|
@@ -26674,12 +27142,13 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
26674
27142
|
"canvas_add_node",
|
|
26675
27143
|
{
|
|
26676
27144
|
title: "Canvas: adicionar n\xF3",
|
|
26677
|
-
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,
|
|
26678
27146
|
inputSchema: {
|
|
26679
27147
|
board_id: boardId3,
|
|
26680
27148
|
kind: external_exports.string().min(1).max(40),
|
|
26681
27149
|
label: external_exports.string().trim().min(1).max(120).optional().describe("Nome do cart\xE3o (data.label)."),
|
|
26682
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),
|
|
26683
27152
|
position: point.optional(),
|
|
26684
27153
|
size: sizeArg.optional(),
|
|
26685
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."),
|
|
@@ -26700,8 +27169,19 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
26700
27169
|
const b = boxOf(args.size);
|
|
26701
27170
|
box = { w: b.w ?? spec.size.w, h: b.h ?? spec.size.h };
|
|
26702
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;
|
|
26703
27182
|
const near = args.inputs?.[0] ? doc.nodes[args.inputs[0].from] : args.outputs?.[0] ? doc.nodes[args.outputs[0].to] : void 0;
|
|
26704
|
-
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);
|
|
26705
27185
|
const zIndex = args.kind === "section" ? SECTION_Z : Object.values(doc.nodes).reduce((t, n) => Math.max(t, n.zIndex), 0) + 1;
|
|
26706
27186
|
const node = makeNode({ type: WORKFLOW_NODE_TYPE, data, position, size: box, zIndex, createdBy: me });
|
|
26707
27187
|
const links = [
|
|
@@ -26722,7 +27202,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
26722
27202
|
return {
|
|
26723
27203
|
ops: [{ type: "node.add", nodeId: node.id, node }, ...edges.ops, ...mention.ops],
|
|
26724
27204
|
targets: links.map((l) => l.source === node.id ? l.target : l.source),
|
|
26725
|
-
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}`
|
|
26726
27206
|
};
|
|
26727
27207
|
})
|
|
26728
27208
|
)
|
|
@@ -26796,7 +27276,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
26796
27276
|
});
|
|
26797
27277
|
const mention = args.layout_only ? { ops: [], note: "" } : await mentionOps(doc, changes.map((c) => ({ node: c.node, data: c.data, keys: c.dataKeys })));
|
|
26798
27278
|
const touched = changes.filter((c) => c.ops.length);
|
|
26799
|
-
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("; ");
|
|
26800
27280
|
return {
|
|
26801
27281
|
ops: [...changes.flatMap((c) => c.ops), ...mention.ops],
|
|
26802
27282
|
targets: ids,
|
|
@@ -26899,7 +27379,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
26899
27379
|
return {
|
|
26900
27380
|
ops,
|
|
26901
27381
|
targets: [node.id],
|
|
26902
|
-
done: `N\xF3 "${
|
|
27382
|
+
done: `N\xF3 "${oneLine2(nodeName(node), 40)}" (${node.id}): ${written} caminho(s) gravado(s)` + (skipped ? ` (ignorados: ${skipped})` : "") + mention.note
|
|
26903
27383
|
};
|
|
26904
27384
|
},
|
|
26905
27385
|
{ split: true }
|
|
@@ -26969,7 +27449,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
26969
27449
|
ops.push(op);
|
|
26970
27450
|
}
|
|
26971
27451
|
}
|
|
26972
|
-
const names = nodeIds.map((n) => `"${
|
|
27452
|
+
const names = nodeIds.map((n) => `"${oneLine2(nodeName(doc.nodes[n]), 40)}"`);
|
|
26973
27453
|
return {
|
|
26974
27454
|
ops,
|
|
26975
27455
|
targets: nodeIds,
|
|
@@ -27051,7 +27531,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
27051
27531
|
import { createRequire } from "module";
|
|
27052
27532
|
var require2 = createRequire(import.meta.url);
|
|
27053
27533
|
function readVersion() {
|
|
27054
|
-
if ("0.
|
|
27534
|
+
if ("0.37.0") return "0.37.0";
|
|
27055
27535
|
try {
|
|
27056
27536
|
const pkg = require2("../package.json");
|
|
27057
27537
|
return pkg.version ?? "0.0.0-unknown";
|
|
@@ -27067,6 +27547,7 @@ var SERVER_INSTRUCTIONS = [
|
|
|
27067
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.',
|
|
27068
27548
|
"Calls: search_calls acha, get_call traz a transcri\xE7\xE3o.",
|
|
27069
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.",
|
|
27070
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.',
|
|
27071
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.',
|
|
27072
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.'
|