@abraca/mcp 1.6.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/abracadabra-mcp.cjs +1165 -190
- package/dist/abracadabra-mcp.cjs.map +1 -1
- package/dist/abracadabra-mcp.esm.js +1165 -190
- package/dist/abracadabra-mcp.esm.js.map +1 -1
- package/dist/index.d.ts +32 -1
- package/package.json +1 -1
- package/src/converters/page-types.ts +408 -0
- package/src/converters/types.ts +15 -11
- package/src/hook-bridge.ts +18 -8
- package/src/index.ts +29 -2
- package/src/mentions.ts +42 -0
- package/src/resources/agent-guide.ts +151 -29
- package/src/server.ts +139 -14
- package/src/tools/awareness.ts +3 -0
- package/src/tools/channel.ts +18 -8
- package/src/tools/content.ts +0 -5
- package/src/tools/files.ts +8 -0
- package/src/tools/meta.ts +1 -7
- package/src/tools/svg.ts +0 -3
- package/src/tools/tree.ts +28 -22
package/dist/abracadabra-mcp.cjs
CHANGED
|
@@ -3761,7 +3761,7 @@ const propertyKeyTypes = new Set([
|
|
|
3761
3761
|
"number",
|
|
3762
3762
|
"symbol"
|
|
3763
3763
|
]);
|
|
3764
|
-
function escapeRegex(str) {
|
|
3764
|
+
function escapeRegex$1(str) {
|
|
3765
3765
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3766
3766
|
}
|
|
3767
3767
|
function clone(inst, def, params) {
|
|
@@ -4472,7 +4472,7 @@ const $ZodCheckUpperCase = /* @__PURE__ */ $constructor("$ZodCheckUpperCase", (i
|
|
|
4472
4472
|
});
|
|
4473
4473
|
const $ZodCheckIncludes = /* @__PURE__ */ $constructor("$ZodCheckIncludes", (inst, def) => {
|
|
4474
4474
|
$ZodCheck.init(inst, def);
|
|
4475
|
-
const escapedRegex = escapeRegex(def.includes);
|
|
4475
|
+
const escapedRegex = escapeRegex$1(def.includes);
|
|
4476
4476
|
const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position}}${escapedRegex}` : escapedRegex);
|
|
4477
4477
|
def.pattern = pattern;
|
|
4478
4478
|
inst._zod.onattach.push((inst) => {
|
|
@@ -4495,7 +4495,7 @@ const $ZodCheckIncludes = /* @__PURE__ */ $constructor("$ZodCheckIncludes", (ins
|
|
|
4495
4495
|
});
|
|
4496
4496
|
const $ZodCheckStartsWith = /* @__PURE__ */ $constructor("$ZodCheckStartsWith", (inst, def) => {
|
|
4497
4497
|
$ZodCheck.init(inst, def);
|
|
4498
|
-
const pattern = new RegExp(`^${escapeRegex(def.prefix)}.*`);
|
|
4498
|
+
const pattern = new RegExp(`^${escapeRegex$1(def.prefix)}.*`);
|
|
4499
4499
|
def.pattern ?? (def.pattern = pattern);
|
|
4500
4500
|
inst._zod.onattach.push((inst) => {
|
|
4501
4501
|
const bag = inst._zod.bag;
|
|
@@ -4517,7 +4517,7 @@ const $ZodCheckStartsWith = /* @__PURE__ */ $constructor("$ZodCheckStartsWith",
|
|
|
4517
4517
|
});
|
|
4518
4518
|
const $ZodCheckEndsWith = /* @__PURE__ */ $constructor("$ZodCheckEndsWith", (inst, def) => {
|
|
4519
4519
|
$ZodCheck.init(inst, def);
|
|
4520
|
-
const pattern = new RegExp(`.*${escapeRegex(def.suffix)}$`);
|
|
4520
|
+
const pattern = new RegExp(`.*${escapeRegex$1(def.suffix)}$`);
|
|
4521
4521
|
def.pattern ?? (def.pattern = pattern);
|
|
4522
4522
|
inst._zod.onattach.push((inst) => {
|
|
4523
4523
|
const bag = inst._zod.bag;
|
|
@@ -5549,7 +5549,7 @@ const $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
|
|
|
5549
5549
|
const values = getEnumValues(def.entries);
|
|
5550
5550
|
const valuesSet = new Set(values);
|
|
5551
5551
|
inst._zod.values = valuesSet;
|
|
5552
|
-
inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex(o) : o.toString()).join("|")})$`);
|
|
5552
|
+
inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex$1(o) : o.toString()).join("|")})$`);
|
|
5553
5553
|
inst._zod.parse = (payload, _ctx) => {
|
|
5554
5554
|
const input = payload.value;
|
|
5555
5555
|
if (valuesSet.has(input)) return payload;
|
|
@@ -5567,7 +5567,7 @@ const $ZodLiteral = /* @__PURE__ */ $constructor("$ZodLiteral", (inst, def) => {
|
|
|
5567
5567
|
if (def.values.length === 0) throw new Error("Cannot create literal schema with no valid values");
|
|
5568
5568
|
const values = new Set(def.values);
|
|
5569
5569
|
inst._zod.values = values;
|
|
5570
|
-
inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`);
|
|
5570
|
+
inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex$1(o) : o ? escapeRegex$1(o.toString()) : String(o)).join("|")})$`);
|
|
5571
5571
|
inst._zod.parse = (payload, _ctx) => {
|
|
5572
5572
|
const input = payload.value;
|
|
5573
5573
|
if (values.has(input)) return payload;
|
|
@@ -19969,6 +19969,47 @@ function signChallenge(challengeB64, privateKey) {
|
|
|
19969
19969
|
return toBase64url(sign(challenge, privateKey));
|
|
19970
19970
|
}
|
|
19971
19971
|
|
|
19972
|
+
//#endregion
|
|
19973
|
+
//#region packages/mcp/src/mentions.ts
|
|
19974
|
+
/**
|
|
19975
|
+
* Mention parsing for chat messages.
|
|
19976
|
+
*
|
|
19977
|
+
* Recognizes `@alias` tokens (case-insensitive, word-boundary) so the agent
|
|
19978
|
+
* can decide whether a group-chat message is directed at it.
|
|
19979
|
+
*/
|
|
19980
|
+
/** Escape regex metacharacters in an alias string. */
|
|
19981
|
+
function escapeRegex(s) {
|
|
19982
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
19983
|
+
}
|
|
19984
|
+
/**
|
|
19985
|
+
* Build a regex that matches `@<alias>` for any of the given aliases.
|
|
19986
|
+
* Requires a non-word char (or start) before `@` and a word boundary after the alias
|
|
19987
|
+
* so `@Claude` matches but `email@claudesomething` does not.
|
|
19988
|
+
*/
|
|
19989
|
+
function buildMentionRegex(aliases) {
|
|
19990
|
+
const cleaned = aliases.map((a) => a.trim()).filter((a) => a.length > 0);
|
|
19991
|
+
if (cleaned.length === 0) return null;
|
|
19992
|
+
const alt = cleaned.map(escapeRegex).join("|");
|
|
19993
|
+
return new RegExp(`(?:^|[^\\w@])@(?:${alt})\\b`, "i");
|
|
19994
|
+
}
|
|
19995
|
+
/** Returns true if `text` contains `@alias` for any alias (case-insensitive). */
|
|
19996
|
+
function containsMention(text, aliases) {
|
|
19997
|
+
const re = buildMentionRegex(aliases);
|
|
19998
|
+
if (!re) return false;
|
|
19999
|
+
return re.test(text);
|
|
20000
|
+
}
|
|
20001
|
+
/**
|
|
20002
|
+
* Remove `@alias` tokens from the text. Leaves surrounding whitespace tidy so
|
|
20003
|
+
* the cleaned prompt reads naturally (e.g. `"@Claude help"` → `"help"`).
|
|
20004
|
+
*/
|
|
20005
|
+
function stripMention(text, aliases) {
|
|
20006
|
+
const cleaned = aliases.map((a) => a.trim()).filter((a) => a.length > 0);
|
|
20007
|
+
if (cleaned.length === 0) return text;
|
|
20008
|
+
const alt = cleaned.map(escapeRegex).join("|");
|
|
20009
|
+
const re = new RegExp(`(^|\\s)@(?:${alt})\\b[,:]?\\s*`, "gi");
|
|
20010
|
+
return text.replace(re, (_m, lead) => lead ? " " : "").replace(/\s{2,}/g, " ").trim();
|
|
20011
|
+
}
|
|
20012
|
+
|
|
19972
20013
|
//#endregion
|
|
19973
20014
|
//#region packages/mcp/src/server.ts
|
|
19974
20015
|
/**
|
|
@@ -19979,7 +20020,10 @@ function signChallenge(challengeB64, privateKey) {
|
|
|
19979
20020
|
* Use switchSpace(docId) to change the active space.
|
|
19980
20021
|
*/
|
|
19981
20022
|
const IDLE_TIMEOUT_MS = 300 * 1e3;
|
|
19982
|
-
var AbracadabraMCPServer = class {
|
|
20023
|
+
var AbracadabraMCPServer = class AbracadabraMCPServer {
|
|
20024
|
+
static {
|
|
20025
|
+
this.TOOL_HISTORY_MAX = 20;
|
|
20026
|
+
}
|
|
19983
20027
|
constructor(config) {
|
|
19984
20028
|
this._serverInfo = null;
|
|
19985
20029
|
this._rootDocId = null;
|
|
@@ -19996,6 +20040,7 @@ var AbracadabraMCPServer = class {
|
|
|
19996
20040
|
this._typingInterval = null;
|
|
19997
20041
|
this._lastChatChannel = null;
|
|
19998
20042
|
this._signFn = null;
|
|
20043
|
+
this._toolHistory = [];
|
|
19999
20044
|
this.config = config;
|
|
20000
20045
|
this.client = new _abraca_dabra.AbracadabraClient({
|
|
20001
20046
|
url: config.url,
|
|
@@ -20008,6 +20053,14 @@ var AbracadabraMCPServer = class {
|
|
|
20008
20053
|
get agentColor() {
|
|
20009
20054
|
return this.config.agentColor || "hsl(270, 80%, 60%)";
|
|
20010
20055
|
}
|
|
20056
|
+
get triggerMode() {
|
|
20057
|
+
return this.config.triggerMode ?? "mention+task";
|
|
20058
|
+
}
|
|
20059
|
+
get mentionAliases() {
|
|
20060
|
+
const explicit = this.config.mentionAliases?.filter((a) => a.trim().length > 0);
|
|
20061
|
+
if (explicit && explicit.length > 0) return explicit;
|
|
20062
|
+
return [this.agentName];
|
|
20063
|
+
}
|
|
20011
20064
|
get serverInfo() {
|
|
20012
20065
|
return this._serverInfo;
|
|
20013
20066
|
}
|
|
@@ -20048,7 +20101,7 @@ var AbracadabraMCPServer = class {
|
|
|
20048
20101
|
await this.client.loginWithKey(keypair.publicKeyB64, signFn);
|
|
20049
20102
|
} else throw err;
|
|
20050
20103
|
}
|
|
20051
|
-
console.error(`[abracadabra-mcp] Authenticated as ${this.agentName} (
|
|
20104
|
+
console.error(`[abracadabra-mcp] Authenticated as ${this.agentName} (pubkey=${keypair.publicKeyB64})`);
|
|
20052
20105
|
this._serverInfo = await this.client.serverInfo();
|
|
20053
20106
|
let initialDocId = this._serverInfo.index_doc_id ?? null;
|
|
20054
20107
|
try {
|
|
@@ -20115,6 +20168,8 @@ var AbracadabraMCPServer = class {
|
|
|
20115
20168
|
provider.awareness.setLocalStateField("status", null);
|
|
20116
20169
|
provider.awareness.setLocalStateField("activeToolCall", null);
|
|
20117
20170
|
provider.awareness.setLocalStateField("statusContext", null);
|
|
20171
|
+
provider.awareness.setLocalStateField("turnId", null);
|
|
20172
|
+
provider.awareness.setLocalStateField("toolHistory", []);
|
|
20118
20173
|
const conn = {
|
|
20119
20174
|
doc,
|
|
20120
20175
|
provider,
|
|
@@ -20149,6 +20204,17 @@ var AbracadabraMCPServer = class {
|
|
|
20149
20204
|
getTrashMap() {
|
|
20150
20205
|
return this._activeConnection?.doc.getMap("doc-trash") ?? null;
|
|
20151
20206
|
}
|
|
20207
|
+
/** Get plugin names enabled in the active space via space-plugins Y.Map. */
|
|
20208
|
+
getEnabledPluginNames() {
|
|
20209
|
+
const doc = this._activeConnection?.doc;
|
|
20210
|
+
if (!doc) return [];
|
|
20211
|
+
const pluginsMap = doc.getMap("space-plugins");
|
|
20212
|
+
const names = [];
|
|
20213
|
+
pluginsMap.forEach((value, key) => {
|
|
20214
|
+
if ((value?.toJSON ? value.toJSON() : value)?.enabled) names.push(key);
|
|
20215
|
+
});
|
|
20216
|
+
return names;
|
|
20217
|
+
}
|
|
20152
20218
|
/**
|
|
20153
20219
|
* Get or create a child provider for a given document ID.
|
|
20154
20220
|
* Caches providers and waits for sync before returning.
|
|
@@ -20227,6 +20293,7 @@ var AbracadabraMCPServer = class {
|
|
|
20227
20293
|
_observeRootAwareness(provider) {
|
|
20228
20294
|
const selfId = provider.awareness.clientID;
|
|
20229
20295
|
provider.awareness.on("change", () => {
|
|
20296
|
+
if (this.triggerMode === "mention") return;
|
|
20230
20297
|
const states = provider.awareness.getStates();
|
|
20231
20298
|
for (const [clientId, state] of states) {
|
|
20232
20299
|
if (clientId === selfId) continue;
|
|
@@ -20239,6 +20306,7 @@ var AbracadabraMCPServer = class {
|
|
|
20239
20306
|
const user = state["user"];
|
|
20240
20307
|
const senderName = user && typeof user === "object" && typeof user.name === "string" ? user.name : "Unknown";
|
|
20241
20308
|
console.error(`[abracadabra-mcp] Handling ai:task id=${id} from ${senderName}: ${text.slice(0, 80)}`);
|
|
20309
|
+
this._beginTurn();
|
|
20242
20310
|
this.setAutoStatus("thinking");
|
|
20243
20311
|
this._dispatchAiTask({
|
|
20244
20312
|
id,
|
|
@@ -20301,9 +20369,28 @@ var AbracadabraMCPServer = class {
|
|
|
20301
20369
|
if (data.sender_id && data.sender_id === this._userId) return;
|
|
20302
20370
|
const channel = data.channel;
|
|
20303
20371
|
const docId = channel?.startsWith("group:") ? channel.slice(6) : "";
|
|
20304
|
-
|
|
20372
|
+
const isDM = channel?.startsWith("dm:") ?? false;
|
|
20373
|
+
const isGroup = channel?.startsWith("group:") ?? false;
|
|
20374
|
+
if (isDM) {
|
|
20305
20375
|
const parts = channel.split(":");
|
|
20306
|
-
if (parts.length === 3 && parts[1] !== this._userId && parts[2] !== this._userId)
|
|
20376
|
+
if (parts.length === 3 && parts[1] !== this._userId && parts[2] !== this._userId) {
|
|
20377
|
+
console.error(`[abracadabra-mcp] Dropping DM: agent _userId=${this._userId} not in channel parts=[${parts[1]}, ${parts[2]}] — channel='${channel}'. The dashboard's awareness likely points at a stale Claude identity.`);
|
|
20378
|
+
return;
|
|
20379
|
+
}
|
|
20380
|
+
}
|
|
20381
|
+
const mode = this.triggerMode;
|
|
20382
|
+
const content = typeof data.content === "string" ? data.content : "";
|
|
20383
|
+
let dispatchContent = content;
|
|
20384
|
+
if (isGroup) {
|
|
20385
|
+
if (mode === "task") return;
|
|
20386
|
+
if (mode === "mention" || mode === "mention+task") {
|
|
20387
|
+
const aliases = this.mentionAliases;
|
|
20388
|
+
if (!containsMention(content, aliases)) {
|
|
20389
|
+
console.error(`[abracadabra-mcp] skipped message on ${channel} — no @mention for ${aliases.join("|")}`);
|
|
20390
|
+
return;
|
|
20391
|
+
}
|
|
20392
|
+
dispatchContent = stripMention(content, aliases) || content;
|
|
20393
|
+
}
|
|
20307
20394
|
}
|
|
20308
20395
|
if (channel) {
|
|
20309
20396
|
const rootProvider = this._activeConnection?.provider;
|
|
@@ -20313,14 +20400,13 @@ var AbracadabraMCPServer = class {
|
|
|
20313
20400
|
timestamp: Math.floor(Date.now() / 1e3)
|
|
20314
20401
|
}));
|
|
20315
20402
|
this._lastChatChannel = channel;
|
|
20316
|
-
this.sendTypingIndicator(channel);
|
|
20317
|
-
this._startTypingInterval(channel);
|
|
20318
20403
|
}
|
|
20404
|
+
this._beginTurn();
|
|
20319
20405
|
this.setAutoStatus("thinking");
|
|
20320
20406
|
await this._serverRef.notification({
|
|
20321
20407
|
method: "notifications/claude/channel",
|
|
20322
20408
|
params: {
|
|
20323
|
-
content:
|
|
20409
|
+
content: dispatchContent,
|
|
20324
20410
|
instructions: `You MUST use send_chat_message with channel="${channel ?? ""}" for ALL responses — both progress updates and final answers. The user CANNOT see plain text output; they only see messages sent via send_chat_message. When doing multi-step work, send brief status updates via send_chat_message (e.g. "Looking into that..." or "Found it, writing up results...") so the user knows you're working. Never output plain text as a substitute for send_chat_message.`,
|
|
20325
20411
|
meta: {
|
|
20326
20412
|
source: "abracadabra",
|
|
@@ -20351,13 +20437,35 @@ var AbracadabraMCPServer = class {
|
|
|
20351
20437
|
if (docId !== void 0) provider.awareness.setLocalStateField("docId", docId);
|
|
20352
20438
|
const context = status ? statusContext !== void 0 ? statusContext : this._lastChatChannel : null;
|
|
20353
20439
|
provider.awareness.setLocalStateField("statusContext", context ?? null);
|
|
20354
|
-
if (!status)
|
|
20440
|
+
if (!status) {
|
|
20441
|
+
this._stopTypingInterval();
|
|
20442
|
+
provider.awareness.setLocalStateField("activeToolCall", null);
|
|
20443
|
+
provider.awareness.setLocalStateField("turnId", null);
|
|
20444
|
+
this._toolHistory = [];
|
|
20445
|
+
provider.awareness.setLocalStateField("toolHistory", []);
|
|
20446
|
+
}
|
|
20355
20447
|
if (status) this._statusClearTimer = setTimeout(() => {
|
|
20356
20448
|
provider.awareness.setLocalStateField("status", null);
|
|
20357
20449
|
provider.awareness.setLocalStateField("activeToolCall", null);
|
|
20358
20450
|
provider.awareness.setLocalStateField("statusContext", null);
|
|
20451
|
+
provider.awareness.setLocalStateField("turnId", null);
|
|
20452
|
+
this._toolHistory = [];
|
|
20453
|
+
provider.awareness.setLocalStateField("toolHistory", []);
|
|
20359
20454
|
this._stopTypingInterval();
|
|
20360
|
-
},
|
|
20455
|
+
}, 1e4);
|
|
20456
|
+
}
|
|
20457
|
+
/**
|
|
20458
|
+
* Start a new agent turn. Mints a fresh UUID and writes it to awareness so
|
|
20459
|
+
* the dashboard can gate the incantation on "there is an active turn",
|
|
20460
|
+
* decoupled from the (racier) status field. Called from chat arrival and
|
|
20461
|
+
* ai:task dispatch right before `setAutoStatus('thinking')`.
|
|
20462
|
+
*/
|
|
20463
|
+
_beginTurn() {
|
|
20464
|
+
const provider = this._activeConnection?.provider;
|
|
20465
|
+
if (!provider) return;
|
|
20466
|
+
this._toolHistory = [];
|
|
20467
|
+
provider.awareness.setLocalStateField("toolHistory", []);
|
|
20468
|
+
provider.awareness.setLocalStateField("turnId", crypto.randomUUID());
|
|
20361
20469
|
}
|
|
20362
20470
|
/** Re-send typing indicator every 2s so dashboard keeps showing it (expires at 3s). */
|
|
20363
20471
|
_startTypingInterval(channel) {
|
|
@@ -20375,10 +20483,28 @@ var AbracadabraMCPServer = class {
|
|
|
20375
20483
|
}
|
|
20376
20484
|
/**
|
|
20377
20485
|
* Broadcast which tool the agent is currently executing.
|
|
20378
|
-
*
|
|
20486
|
+
*
|
|
20487
|
+
* Renders as a ChatTool pill on the dashboard. On non-null calls, the tool
|
|
20488
|
+
* is also appended to `toolHistory` (capped at TOOL_HISTORY_MAX) and written
|
|
20489
|
+
* to awareness so the dashboard's inline trace can show the turn's recent
|
|
20490
|
+
* activity. Tools do NOT clear (`setActiveToolCall(null)`) on completion —
|
|
20491
|
+
* the pill stays until the next tool replaces it or `setAutoStatus(null)`
|
|
20492
|
+
* flushes the turn. This keeps pills visible long enough to see.
|
|
20379
20493
|
*/
|
|
20380
20494
|
setActiveToolCall(toolCall) {
|
|
20381
|
-
this._activeConnection?.provider
|
|
20495
|
+
const provider = this._activeConnection?.provider;
|
|
20496
|
+
if (!provider) return;
|
|
20497
|
+
provider.awareness.setLocalStateField("activeToolCall", toolCall);
|
|
20498
|
+
if (toolCall) {
|
|
20499
|
+
this._toolHistory.push({
|
|
20500
|
+
tool: toolCall.name,
|
|
20501
|
+
target: toolCall.target,
|
|
20502
|
+
ts: Date.now(),
|
|
20503
|
+
channel: this._lastChatChannel
|
|
20504
|
+
});
|
|
20505
|
+
if (this._toolHistory.length > AbracadabraMCPServer.TOOL_HISTORY_MAX) this._toolHistory.splice(0, this._toolHistory.length - AbracadabraMCPServer.TOOL_HISTORY_MAX);
|
|
20506
|
+
provider.awareness.setLocalStateField("toolHistory", [...this._toolHistory]);
|
|
20507
|
+
}
|
|
20382
20508
|
}
|
|
20383
20509
|
/**
|
|
20384
20510
|
* Send a typing indicator to a chat channel.
|
|
@@ -20409,8 +20535,11 @@ var AbracadabraMCPServer = class {
|
|
|
20409
20535
|
conn.provider.awareness.setLocalStateField("status", null);
|
|
20410
20536
|
conn.provider.awareness.setLocalStateField("activeToolCall", null);
|
|
20411
20537
|
conn.provider.awareness.setLocalStateField("statusContext", null);
|
|
20538
|
+
conn.provider.awareness.setLocalStateField("turnId", null);
|
|
20539
|
+
conn.provider.awareness.setLocalStateField("toolHistory", []);
|
|
20412
20540
|
conn.provider.destroy();
|
|
20413
20541
|
}
|
|
20542
|
+
this._toolHistory = [];
|
|
20414
20543
|
this._spaceConnections.clear();
|
|
20415
20544
|
this._activeConnection = null;
|
|
20416
20545
|
console.error("[abracadabra-mcp] Shutdown complete");
|
|
@@ -20435,6 +20564,724 @@ function docToSpaceMeta(doc) {
|
|
|
20435
20564
|
};
|
|
20436
20565
|
}
|
|
20437
20566
|
|
|
20567
|
+
//#endregion
|
|
20568
|
+
//#region packages/mcp/src/converters/page-types.ts
|
|
20569
|
+
const PAGE_TYPES = {
|
|
20570
|
+
doc: {
|
|
20571
|
+
key: "doc",
|
|
20572
|
+
label: "Document",
|
|
20573
|
+
icon: "file-text",
|
|
20574
|
+
description: "Rich text document with real-time collaboration",
|
|
20575
|
+
core: true,
|
|
20576
|
+
supportsChildren: true
|
|
20577
|
+
},
|
|
20578
|
+
kanban: {
|
|
20579
|
+
key: "kanban",
|
|
20580
|
+
label: "Kanban",
|
|
20581
|
+
icon: "kanban",
|
|
20582
|
+
description: "Drag-and-drop task board with columns and cards",
|
|
20583
|
+
core: true,
|
|
20584
|
+
supportsChildren: true,
|
|
20585
|
+
childLabel: "Column",
|
|
20586
|
+
grandchildLabel: "Card",
|
|
20587
|
+
defaultMetaFields: [{
|
|
20588
|
+
type: "select",
|
|
20589
|
+
key: "kanbanColumnWidth",
|
|
20590
|
+
options: [
|
|
20591
|
+
"narrow",
|
|
20592
|
+
"default",
|
|
20593
|
+
"wide"
|
|
20594
|
+
],
|
|
20595
|
+
label: "Column Width"
|
|
20596
|
+
}]
|
|
20597
|
+
},
|
|
20598
|
+
gallery: {
|
|
20599
|
+
key: "gallery",
|
|
20600
|
+
label: "Gallery",
|
|
20601
|
+
icon: "images",
|
|
20602
|
+
description: "Visual grid of items with rich content",
|
|
20603
|
+
core: true,
|
|
20604
|
+
supportsChildren: true,
|
|
20605
|
+
childLabel: "Item",
|
|
20606
|
+
metaSchema: [
|
|
20607
|
+
{
|
|
20608
|
+
type: "location",
|
|
20609
|
+
latKey: "geoLat",
|
|
20610
|
+
lngKey: "geoLng",
|
|
20611
|
+
label: "Location"
|
|
20612
|
+
},
|
|
20613
|
+
{
|
|
20614
|
+
type: "datetime",
|
|
20615
|
+
key: "datetimeStart",
|
|
20616
|
+
label: "Date"
|
|
20617
|
+
},
|
|
20618
|
+
{
|
|
20619
|
+
type: "tags",
|
|
20620
|
+
key: "tags",
|
|
20621
|
+
label: "Tags"
|
|
20622
|
+
},
|
|
20623
|
+
{
|
|
20624
|
+
type: "rating",
|
|
20625
|
+
key: "rating",
|
|
20626
|
+
max: 5,
|
|
20627
|
+
label: "Rating"
|
|
20628
|
+
},
|
|
20629
|
+
{
|
|
20630
|
+
type: "icon",
|
|
20631
|
+
key: "icon",
|
|
20632
|
+
label: "Icon"
|
|
20633
|
+
},
|
|
20634
|
+
{
|
|
20635
|
+
type: "colorPreset",
|
|
20636
|
+
key: "color",
|
|
20637
|
+
presets: [
|
|
20638
|
+
"#6366f1",
|
|
20639
|
+
"#ec4899",
|
|
20640
|
+
"#f97316",
|
|
20641
|
+
"#22c55e",
|
|
20642
|
+
"#3b82f6",
|
|
20643
|
+
"#a855f7"
|
|
20644
|
+
],
|
|
20645
|
+
label: "Color"
|
|
20646
|
+
}
|
|
20647
|
+
],
|
|
20648
|
+
defaultMetaFields: [
|
|
20649
|
+
{
|
|
20650
|
+
type: "number",
|
|
20651
|
+
key: "galleryColumns",
|
|
20652
|
+
min: 1,
|
|
20653
|
+
max: 6,
|
|
20654
|
+
step: 1,
|
|
20655
|
+
label: "Columns"
|
|
20656
|
+
},
|
|
20657
|
+
{
|
|
20658
|
+
type: "select",
|
|
20659
|
+
key: "galleryAspect",
|
|
20660
|
+
options: [
|
|
20661
|
+
"square",
|
|
20662
|
+
"4:3",
|
|
20663
|
+
"3:2",
|
|
20664
|
+
"16:9",
|
|
20665
|
+
"free"
|
|
20666
|
+
],
|
|
20667
|
+
label: "Aspect Ratio"
|
|
20668
|
+
},
|
|
20669
|
+
{
|
|
20670
|
+
type: "select",
|
|
20671
|
+
key: "galleryCardStyle",
|
|
20672
|
+
options: [
|
|
20673
|
+
"default",
|
|
20674
|
+
"compact",
|
|
20675
|
+
"detailed"
|
|
20676
|
+
],
|
|
20677
|
+
label: "Card Style"
|
|
20678
|
+
},
|
|
20679
|
+
{
|
|
20680
|
+
type: "toggle",
|
|
20681
|
+
key: "galleryShowLabels",
|
|
20682
|
+
label: "Show Labels"
|
|
20683
|
+
},
|
|
20684
|
+
{
|
|
20685
|
+
type: "select",
|
|
20686
|
+
key: "gallerySortBy",
|
|
20687
|
+
options: [
|
|
20688
|
+
"manual",
|
|
20689
|
+
"date",
|
|
20690
|
+
"name",
|
|
20691
|
+
"rating"
|
|
20692
|
+
],
|
|
20693
|
+
label: "Sort"
|
|
20694
|
+
}
|
|
20695
|
+
]
|
|
20696
|
+
},
|
|
20697
|
+
table: {
|
|
20698
|
+
key: "table",
|
|
20699
|
+
label: "Table",
|
|
20700
|
+
icon: "table",
|
|
20701
|
+
description: "Collaborative spreadsheet with custom fields",
|
|
20702
|
+
core: true,
|
|
20703
|
+
supportsChildren: true,
|
|
20704
|
+
childLabel: "Column",
|
|
20705
|
+
grandchildLabel: "Row",
|
|
20706
|
+
defaultMetaFields: [{
|
|
20707
|
+
type: "select",
|
|
20708
|
+
key: "tableMode",
|
|
20709
|
+
options: ["hierarchy", "flat"],
|
|
20710
|
+
label: "Mode"
|
|
20711
|
+
}, {
|
|
20712
|
+
type: "select",
|
|
20713
|
+
key: "tableSortDir",
|
|
20714
|
+
options: ["asc", "desc"],
|
|
20715
|
+
label: "Sort Direction"
|
|
20716
|
+
}]
|
|
20717
|
+
},
|
|
20718
|
+
outline: {
|
|
20719
|
+
key: "outline",
|
|
20720
|
+
label: "Outline",
|
|
20721
|
+
icon: "list-tree",
|
|
20722
|
+
description: "Hierarchical outline with keyboard navigation",
|
|
20723
|
+
core: true,
|
|
20724
|
+
supportsChildren: true,
|
|
20725
|
+
childLabel: "Item",
|
|
20726
|
+
defaultDepth: -1
|
|
20727
|
+
},
|
|
20728
|
+
checklist: {
|
|
20729
|
+
key: "checklist",
|
|
20730
|
+
label: "Checklist",
|
|
20731
|
+
icon: "check-square",
|
|
20732
|
+
description: "Collaborative checklist with sub-tasks, drag-and-drop, and due dates",
|
|
20733
|
+
core: true,
|
|
20734
|
+
supportsChildren: true,
|
|
20735
|
+
childLabel: "Task",
|
|
20736
|
+
defaultDepth: -1,
|
|
20737
|
+
metaSchema: [
|
|
20738
|
+
{
|
|
20739
|
+
type: "toggle",
|
|
20740
|
+
key: "checked",
|
|
20741
|
+
label: "Done"
|
|
20742
|
+
},
|
|
20743
|
+
{
|
|
20744
|
+
type: "select",
|
|
20745
|
+
key: "priority",
|
|
20746
|
+
options: [
|
|
20747
|
+
"none",
|
|
20748
|
+
"low",
|
|
20749
|
+
"medium",
|
|
20750
|
+
"high"
|
|
20751
|
+
],
|
|
20752
|
+
label: "Priority"
|
|
20753
|
+
},
|
|
20754
|
+
{
|
|
20755
|
+
type: "date",
|
|
20756
|
+
key: "dateEnd",
|
|
20757
|
+
label: "Due date"
|
|
20758
|
+
}
|
|
20759
|
+
],
|
|
20760
|
+
defaultMetaFields: [{
|
|
20761
|
+
type: "select",
|
|
20762
|
+
key: "checklistFilter",
|
|
20763
|
+
options: [
|
|
20764
|
+
"all",
|
|
20765
|
+
"active",
|
|
20766
|
+
"completed"
|
|
20767
|
+
],
|
|
20768
|
+
label: "Filter"
|
|
20769
|
+
}, {
|
|
20770
|
+
type: "select",
|
|
20771
|
+
key: "checklistSort",
|
|
20772
|
+
options: [
|
|
20773
|
+
"manual",
|
|
20774
|
+
"priority",
|
|
20775
|
+
"due"
|
|
20776
|
+
],
|
|
20777
|
+
label: "Sort"
|
|
20778
|
+
}]
|
|
20779
|
+
},
|
|
20780
|
+
graph: {
|
|
20781
|
+
key: "graph",
|
|
20782
|
+
label: "Graph",
|
|
20783
|
+
icon: "git-fork",
|
|
20784
|
+
description: "Force-directed knowledge graph — full document tree as nodes & edges",
|
|
20785
|
+
core: true,
|
|
20786
|
+
supportsChildren: true,
|
|
20787
|
+
childLabel: "Node",
|
|
20788
|
+
defaultMetaFields: [{
|
|
20789
|
+
type: "toggle",
|
|
20790
|
+
key: "showRefEdges",
|
|
20791
|
+
label: "Show Ref Edges",
|
|
20792
|
+
default: true
|
|
20793
|
+
}]
|
|
20794
|
+
},
|
|
20795
|
+
timeline: {
|
|
20796
|
+
key: "timeline",
|
|
20797
|
+
label: "Timeline",
|
|
20798
|
+
icon: "gantt-chart",
|
|
20799
|
+
description: "Gantt-style project timeline with epics and tasks",
|
|
20800
|
+
core: true,
|
|
20801
|
+
supportsChildren: true,
|
|
20802
|
+
childLabel: "Epic",
|
|
20803
|
+
grandchildLabel: "Task",
|
|
20804
|
+
metaSchema: [
|
|
20805
|
+
{
|
|
20806
|
+
type: "daterange",
|
|
20807
|
+
startKey: "dateStart",
|
|
20808
|
+
endKey: "dateEnd"
|
|
20809
|
+
},
|
|
20810
|
+
{
|
|
20811
|
+
type: "slider",
|
|
20812
|
+
key: "taskProgress",
|
|
20813
|
+
min: 0,
|
|
20814
|
+
max: 100,
|
|
20815
|
+
label: "Progress"
|
|
20816
|
+
},
|
|
20817
|
+
{
|
|
20818
|
+
type: "colorPreset",
|
|
20819
|
+
key: "color",
|
|
20820
|
+
presets: [
|
|
20821
|
+
"#6366f1",
|
|
20822
|
+
"#818cf8",
|
|
20823
|
+
"#f97316",
|
|
20824
|
+
"#22c55e",
|
|
20825
|
+
"#3b82f6",
|
|
20826
|
+
"#a855f7"
|
|
20827
|
+
],
|
|
20828
|
+
label: "Color"
|
|
20829
|
+
}
|
|
20830
|
+
]
|
|
20831
|
+
},
|
|
20832
|
+
calendar: {
|
|
20833
|
+
key: "calendar",
|
|
20834
|
+
label: "Calendar",
|
|
20835
|
+
icon: "calendar",
|
|
20836
|
+
description: "Event calendar with month, week, and day views",
|
|
20837
|
+
core: true,
|
|
20838
|
+
supportsChildren: true,
|
|
20839
|
+
childLabel: "Event",
|
|
20840
|
+
metaSchema: [
|
|
20841
|
+
{
|
|
20842
|
+
type: "datetimerange",
|
|
20843
|
+
startKey: "datetimeStart",
|
|
20844
|
+
endKey: "datetimeEnd",
|
|
20845
|
+
allDayKey: "allDay"
|
|
20846
|
+
},
|
|
20847
|
+
{
|
|
20848
|
+
type: "colorPreset",
|
|
20849
|
+
key: "color",
|
|
20850
|
+
presets: [
|
|
20851
|
+
"#6366f1",
|
|
20852
|
+
"#ec4899",
|
|
20853
|
+
"#f97316",
|
|
20854
|
+
"#22c55e",
|
|
20855
|
+
"#3b82f6",
|
|
20856
|
+
"#a855f7"
|
|
20857
|
+
],
|
|
20858
|
+
label: "Color"
|
|
20859
|
+
},
|
|
20860
|
+
{
|
|
20861
|
+
type: "icon",
|
|
20862
|
+
key: "icon",
|
|
20863
|
+
label: "Icon"
|
|
20864
|
+
}
|
|
20865
|
+
],
|
|
20866
|
+
defaultMetaFields: [
|
|
20867
|
+
{
|
|
20868
|
+
type: "select",
|
|
20869
|
+
key: "calendarWeekStart",
|
|
20870
|
+
options: ["sun", "mon"],
|
|
20871
|
+
label: "Week Starts"
|
|
20872
|
+
},
|
|
20873
|
+
{
|
|
20874
|
+
type: "select",
|
|
20875
|
+
key: "calendarView",
|
|
20876
|
+
options: [
|
|
20877
|
+
"month",
|
|
20878
|
+
"week",
|
|
20879
|
+
"day"
|
|
20880
|
+
],
|
|
20881
|
+
label: "Default View"
|
|
20882
|
+
},
|
|
20883
|
+
{
|
|
20884
|
+
type: "toggle",
|
|
20885
|
+
key: "calendarShowWeekNumbers",
|
|
20886
|
+
label: "Show Week Numbers"
|
|
20887
|
+
}
|
|
20888
|
+
]
|
|
20889
|
+
},
|
|
20890
|
+
map: {
|
|
20891
|
+
key: "map",
|
|
20892
|
+
label: "Map",
|
|
20893
|
+
icon: "map",
|
|
20894
|
+
description: "Collaborative world map with shared markers",
|
|
20895
|
+
core: true,
|
|
20896
|
+
supportsChildren: true,
|
|
20897
|
+
childLabel: "Location",
|
|
20898
|
+
defaultMetaFields: [{
|
|
20899
|
+
type: "toggle",
|
|
20900
|
+
key: "mapShowLabels",
|
|
20901
|
+
label: "Show Labels",
|
|
20902
|
+
default: true
|
|
20903
|
+
}]
|
|
20904
|
+
},
|
|
20905
|
+
dashboard: {
|
|
20906
|
+
key: "dashboard",
|
|
20907
|
+
label: "Dashboard",
|
|
20908
|
+
icon: "layout-dashboard",
|
|
20909
|
+
description: "Arrange documents as draggable icons with optional widget views",
|
|
20910
|
+
core: true,
|
|
20911
|
+
supportsChildren: true,
|
|
20912
|
+
childLabel: "Item"
|
|
20913
|
+
},
|
|
20914
|
+
call: {
|
|
20915
|
+
key: "call",
|
|
20916
|
+
label: "Call",
|
|
20917
|
+
icon: "phone",
|
|
20918
|
+
description: "Video call room with live audio and screen sharing",
|
|
20919
|
+
core: true,
|
|
20920
|
+
supportsChildren: false
|
|
20921
|
+
},
|
|
20922
|
+
chart: {
|
|
20923
|
+
key: "chart",
|
|
20924
|
+
label: "Chart",
|
|
20925
|
+
icon: "bar-chart-3",
|
|
20926
|
+
description: "Charts — manual data points or aggregation over document trees",
|
|
20927
|
+
core: true,
|
|
20928
|
+
supportsChildren: true,
|
|
20929
|
+
childLabel: "Data Point",
|
|
20930
|
+
grandchildLabel: "Data Point",
|
|
20931
|
+
metaSchema: [
|
|
20932
|
+
{
|
|
20933
|
+
type: "number",
|
|
20934
|
+
key: "number",
|
|
20935
|
+
step: .01,
|
|
20936
|
+
label: "Value"
|
|
20937
|
+
},
|
|
20938
|
+
{
|
|
20939
|
+
type: "colorPreset",
|
|
20940
|
+
key: "color",
|
|
20941
|
+
presets: [
|
|
20942
|
+
"#6366f1",
|
|
20943
|
+
"#ec4899",
|
|
20944
|
+
"#f97316",
|
|
20945
|
+
"#22c55e",
|
|
20946
|
+
"#3b82f6",
|
|
20947
|
+
"#a855f7",
|
|
20948
|
+
"#14b8a6",
|
|
20949
|
+
"#eab308"
|
|
20950
|
+
],
|
|
20951
|
+
label: "Color"
|
|
20952
|
+
},
|
|
20953
|
+
{
|
|
20954
|
+
type: "tags",
|
|
20955
|
+
key: "tags",
|
|
20956
|
+
label: "Tags"
|
|
20957
|
+
}
|
|
20958
|
+
],
|
|
20959
|
+
defaultMetaFields: [
|
|
20960
|
+
{
|
|
20961
|
+
type: "select",
|
|
20962
|
+
key: "chartType",
|
|
20963
|
+
options: [
|
|
20964
|
+
"bar",
|
|
20965
|
+
"stacked bar",
|
|
20966
|
+
"line",
|
|
20967
|
+
"donut",
|
|
20968
|
+
"treemap"
|
|
20969
|
+
],
|
|
20970
|
+
label: "Chart Type"
|
|
20971
|
+
},
|
|
20972
|
+
{
|
|
20973
|
+
type: "select",
|
|
20974
|
+
key: "chartMetric",
|
|
20975
|
+
options: [
|
|
20976
|
+
"value",
|
|
20977
|
+
"type",
|
|
20978
|
+
"tag",
|
|
20979
|
+
"status",
|
|
20980
|
+
"priority",
|
|
20981
|
+
"activity",
|
|
20982
|
+
"completion"
|
|
20983
|
+
],
|
|
20984
|
+
label: "Metric"
|
|
20985
|
+
},
|
|
20986
|
+
{
|
|
20987
|
+
type: "select",
|
|
20988
|
+
key: "chartColorScheme",
|
|
20989
|
+
options: [
|
|
20990
|
+
"default",
|
|
20991
|
+
"warm",
|
|
20992
|
+
"cool",
|
|
20993
|
+
"mono"
|
|
20994
|
+
],
|
|
20995
|
+
label: "Colors"
|
|
20996
|
+
},
|
|
20997
|
+
{
|
|
20998
|
+
type: "number",
|
|
20999
|
+
key: "chartLimit",
|
|
21000
|
+
min: 3,
|
|
21001
|
+
max: 30,
|
|
21002
|
+
step: 1,
|
|
21003
|
+
label: "Max Items"
|
|
21004
|
+
},
|
|
21005
|
+
{
|
|
21006
|
+
type: "toggle",
|
|
21007
|
+
key: "chartShowLegend",
|
|
21008
|
+
label: "Show Legend",
|
|
21009
|
+
default: true
|
|
21010
|
+
},
|
|
21011
|
+
{
|
|
21012
|
+
type: "toggle",
|
|
21013
|
+
key: "chartShowValues",
|
|
21014
|
+
label: "Show Values"
|
|
21015
|
+
}
|
|
21016
|
+
]
|
|
21017
|
+
},
|
|
21018
|
+
sheets: {
|
|
21019
|
+
key: "sheets",
|
|
21020
|
+
label: "Sheets",
|
|
21021
|
+
icon: "grid-3x3",
|
|
21022
|
+
description: "Spreadsheet — cells, formulas, and formatting in a collaborative grid",
|
|
21023
|
+
core: true,
|
|
21024
|
+
supportsChildren: true,
|
|
21025
|
+
childLabel: "Column",
|
|
21026
|
+
grandchildLabel: "Cell",
|
|
21027
|
+
defaultMetaFields: [
|
|
21028
|
+
{
|
|
21029
|
+
type: "number",
|
|
21030
|
+
key: "sheetsDefaultColWidth",
|
|
21031
|
+
min: 40,
|
|
21032
|
+
max: 500,
|
|
21033
|
+
step: 10,
|
|
21034
|
+
label: "Column Width"
|
|
21035
|
+
},
|
|
21036
|
+
{
|
|
21037
|
+
type: "number",
|
|
21038
|
+
key: "sheetsDefaultRowHeight",
|
|
21039
|
+
min: 20,
|
|
21040
|
+
max: 100,
|
|
21041
|
+
step: 2,
|
|
21042
|
+
label: "Row Height"
|
|
21043
|
+
},
|
|
21044
|
+
{
|
|
21045
|
+
type: "toggle",
|
|
21046
|
+
key: "sheetsShowGridlines",
|
|
21047
|
+
label: "Gridlines"
|
|
21048
|
+
}
|
|
21049
|
+
]
|
|
21050
|
+
},
|
|
21051
|
+
slides: {
|
|
21052
|
+
key: "slides",
|
|
21053
|
+
label: "Slides",
|
|
21054
|
+
icon: "presentation",
|
|
21055
|
+
description: "Presentation slides with two-axis navigation",
|
|
21056
|
+
core: true,
|
|
21057
|
+
supportsChildren: true,
|
|
21058
|
+
childLabel: "Slide",
|
|
21059
|
+
grandchildLabel: "Sub-slide",
|
|
21060
|
+
metaSchema: [{
|
|
21061
|
+
type: "select",
|
|
21062
|
+
key: "slidesTransition",
|
|
21063
|
+
options: [
|
|
21064
|
+
"none",
|
|
21065
|
+
"fade",
|
|
21066
|
+
"slide"
|
|
21067
|
+
],
|
|
21068
|
+
label: "Transition"
|
|
21069
|
+
}, {
|
|
21070
|
+
type: "colorPreset",
|
|
21071
|
+
key: "color",
|
|
21072
|
+
presets: [
|
|
21073
|
+
"#6366f1",
|
|
21074
|
+
"#ec4899",
|
|
21075
|
+
"#f97316",
|
|
21076
|
+
"#22c55e",
|
|
21077
|
+
"#3b82f6",
|
|
21078
|
+
"#a855f7"
|
|
21079
|
+
],
|
|
21080
|
+
label: "Accent"
|
|
21081
|
+
}],
|
|
21082
|
+
defaultMetaFields: [{
|
|
21083
|
+
type: "select",
|
|
21084
|
+
key: "slidesTheme",
|
|
21085
|
+
options: ["dark", "light"],
|
|
21086
|
+
label: "Theme"
|
|
21087
|
+
}]
|
|
21088
|
+
},
|
|
21089
|
+
overview: {
|
|
21090
|
+
key: "overview",
|
|
21091
|
+
label: "Overview",
|
|
21092
|
+
icon: "radar",
|
|
21093
|
+
description: "Space home — activity, people, stats, and health at a glance",
|
|
21094
|
+
core: true,
|
|
21095
|
+
supportsChildren: true,
|
|
21096
|
+
childLabel: "Page"
|
|
21097
|
+
},
|
|
21098
|
+
spatial: {
|
|
21099
|
+
key: "spatial",
|
|
21100
|
+
label: "Spatial",
|
|
21101
|
+
icon: "box",
|
|
21102
|
+
description: "3D scene with collaborative objects and real-time presence",
|
|
21103
|
+
core: false,
|
|
21104
|
+
plugin: "spatial",
|
|
21105
|
+
supportsChildren: true,
|
|
21106
|
+
childLabel: "Object",
|
|
21107
|
+
grandchildLabel: "Part",
|
|
21108
|
+
defaultDepth: -1,
|
|
21109
|
+
metaSchema: [
|
|
21110
|
+
{
|
|
21111
|
+
type: "select",
|
|
21112
|
+
key: "spShape",
|
|
21113
|
+
options: [
|
|
21114
|
+
"box",
|
|
21115
|
+
"sphere",
|
|
21116
|
+
"cylinder",
|
|
21117
|
+
"cone",
|
|
21118
|
+
"plane",
|
|
21119
|
+
"torus",
|
|
21120
|
+
"glb"
|
|
21121
|
+
],
|
|
21122
|
+
label: "Shape"
|
|
21123
|
+
},
|
|
21124
|
+
{
|
|
21125
|
+
type: "colorPreset",
|
|
21126
|
+
key: "color",
|
|
21127
|
+
presets: [
|
|
21128
|
+
"#6366f1",
|
|
21129
|
+
"#ef4444",
|
|
21130
|
+
"#22c55e",
|
|
21131
|
+
"#3b82f6",
|
|
21132
|
+
"#f97316",
|
|
21133
|
+
"#a855f7",
|
|
21134
|
+
"#ec4899",
|
|
21135
|
+
"#14b8a6"
|
|
21136
|
+
],
|
|
21137
|
+
label: "Color"
|
|
21138
|
+
},
|
|
21139
|
+
{
|
|
21140
|
+
type: "slider",
|
|
21141
|
+
key: "spOpacity",
|
|
21142
|
+
min: 0,
|
|
21143
|
+
max: 100,
|
|
21144
|
+
label: "Opacity"
|
|
21145
|
+
},
|
|
21146
|
+
{
|
|
21147
|
+
type: "number",
|
|
21148
|
+
key: "spX",
|
|
21149
|
+
step: .1,
|
|
21150
|
+
label: "X"
|
|
21151
|
+
},
|
|
21152
|
+
{
|
|
21153
|
+
type: "number",
|
|
21154
|
+
key: "spY",
|
|
21155
|
+
step: .1,
|
|
21156
|
+
label: "Y"
|
|
21157
|
+
},
|
|
21158
|
+
{
|
|
21159
|
+
type: "number",
|
|
21160
|
+
key: "spZ",
|
|
21161
|
+
step: .1,
|
|
21162
|
+
label: "Z"
|
|
21163
|
+
},
|
|
21164
|
+
{
|
|
21165
|
+
type: "number",
|
|
21166
|
+
key: "spRX",
|
|
21167
|
+
min: -180,
|
|
21168
|
+
max: 180,
|
|
21169
|
+
step: 1,
|
|
21170
|
+
label: "Rot X"
|
|
21171
|
+
},
|
|
21172
|
+
{
|
|
21173
|
+
type: "number",
|
|
21174
|
+
key: "spRY",
|
|
21175
|
+
min: -180,
|
|
21176
|
+
max: 180,
|
|
21177
|
+
step: 1,
|
|
21178
|
+
label: "Rot Y"
|
|
21179
|
+
},
|
|
21180
|
+
{
|
|
21181
|
+
type: "number",
|
|
21182
|
+
key: "spRZ",
|
|
21183
|
+
min: -180,
|
|
21184
|
+
max: 180,
|
|
21185
|
+
step: 1,
|
|
21186
|
+
label: "Rot Z"
|
|
21187
|
+
},
|
|
21188
|
+
{
|
|
21189
|
+
type: "number",
|
|
21190
|
+
key: "spSX",
|
|
21191
|
+
min: .01,
|
|
21192
|
+
max: 100,
|
|
21193
|
+
step: .1,
|
|
21194
|
+
label: "Scale X"
|
|
21195
|
+
},
|
|
21196
|
+
{
|
|
21197
|
+
type: "number",
|
|
21198
|
+
key: "spSY",
|
|
21199
|
+
min: .01,
|
|
21200
|
+
max: 100,
|
|
21201
|
+
step: .1,
|
|
21202
|
+
label: "Scale Y"
|
|
21203
|
+
},
|
|
21204
|
+
{
|
|
21205
|
+
type: "number",
|
|
21206
|
+
key: "spSZ",
|
|
21207
|
+
min: .01,
|
|
21208
|
+
max: 100,
|
|
21209
|
+
step: .1,
|
|
21210
|
+
label: "Scale Z"
|
|
21211
|
+
}
|
|
21212
|
+
],
|
|
21213
|
+
defaultMetaFields: [{
|
|
21214
|
+
type: "toggle",
|
|
21215
|
+
key: "spatialGridVisible",
|
|
21216
|
+
label: "Show Grid",
|
|
21217
|
+
default: true
|
|
21218
|
+
}]
|
|
21219
|
+
},
|
|
21220
|
+
media: {
|
|
21221
|
+
key: "media",
|
|
21222
|
+
label: "Media",
|
|
21223
|
+
icon: "disc-3",
|
|
21224
|
+
description: "Media player with synced listening and playlists",
|
|
21225
|
+
core: false,
|
|
21226
|
+
plugin: "media",
|
|
21227
|
+
supportsChildren: true,
|
|
21228
|
+
childLabel: "Track",
|
|
21229
|
+
defaultDepth: -1,
|
|
21230
|
+
metaSchema: [{
|
|
21231
|
+
type: "tags",
|
|
21232
|
+
key: "tags",
|
|
21233
|
+
label: "Tags"
|
|
21234
|
+
}],
|
|
21235
|
+
defaultMetaFields: [{
|
|
21236
|
+
type: "select",
|
|
21237
|
+
key: "mediaRepeat",
|
|
21238
|
+
options: [
|
|
21239
|
+
"off",
|
|
21240
|
+
"all",
|
|
21241
|
+
"one"
|
|
21242
|
+
],
|
|
21243
|
+
label: "Repeat"
|
|
21244
|
+
}, {
|
|
21245
|
+
type: "toggle",
|
|
21246
|
+
key: "mediaShuffle",
|
|
21247
|
+
label: "Shuffle"
|
|
21248
|
+
}]
|
|
21249
|
+
},
|
|
21250
|
+
coder: {
|
|
21251
|
+
key: "coder",
|
|
21252
|
+
label: "Coder",
|
|
21253
|
+
icon: "code-2",
|
|
21254
|
+
description: "Collaborative multi-file coding environment",
|
|
21255
|
+
core: false,
|
|
21256
|
+
plugin: "coder",
|
|
21257
|
+
supportsChildren: true,
|
|
21258
|
+
childLabel: "File",
|
|
21259
|
+
defaultDepth: -1,
|
|
21260
|
+
metaSchema: [{
|
|
21261
|
+
type: "select",
|
|
21262
|
+
key: "fileType",
|
|
21263
|
+
options: [
|
|
21264
|
+
"vue",
|
|
21265
|
+
"ts",
|
|
21266
|
+
"js",
|
|
21267
|
+
"css",
|
|
21268
|
+
"json",
|
|
21269
|
+
"folder"
|
|
21270
|
+
],
|
|
21271
|
+
label: "Type"
|
|
21272
|
+
}, {
|
|
21273
|
+
type: "toggle",
|
|
21274
|
+
key: "entry",
|
|
21275
|
+
label: "Entry Point"
|
|
21276
|
+
}]
|
|
21277
|
+
}
|
|
21278
|
+
};
|
|
21279
|
+
const TYPE_ALIASES = { desktop: "dashboard" };
|
|
21280
|
+
function resolvePageType(key) {
|
|
21281
|
+
if (!key) return void 0;
|
|
21282
|
+
return PAGE_TYPES[TYPE_ALIASES[key] ?? key];
|
|
21283
|
+
}
|
|
21284
|
+
|
|
20438
21285
|
//#endregion
|
|
20439
21286
|
//#region packages/mcp/src/tools/tree.ts
|
|
20440
21287
|
/**
|
|
@@ -20508,16 +21355,12 @@ function registerTreeTools(mcp, server) {
|
|
|
20508
21355
|
server.setAutoStatus("reading");
|
|
20509
21356
|
server.setActiveToolCall({ name: "list_documents" });
|
|
20510
21357
|
const treeMap = server.getTreeMap();
|
|
20511
|
-
if (!treeMap) {
|
|
20512
|
-
|
|
20513
|
-
|
|
20514
|
-
|
|
20515
|
-
text: "Not connected"
|
|
20516
|
-
}] };
|
|
20517
|
-
}
|
|
21358
|
+
if (!treeMap) return { content: [{
|
|
21359
|
+
type: "text",
|
|
21360
|
+
text: "Not connected"
|
|
21361
|
+
}] };
|
|
20518
21362
|
const targetId = normalizeRootId(parentId, server);
|
|
20519
21363
|
const children = childrenOf$1(readEntries$1(treeMap), targetId);
|
|
20520
|
-
server.setActiveToolCall(null);
|
|
20521
21364
|
return { content: [{
|
|
20522
21365
|
type: "text",
|
|
20523
21366
|
text: JSON.stringify(children, null, 2)
|
|
@@ -20530,17 +21373,13 @@ function registerTreeTools(mcp, server) {
|
|
|
20530
21373
|
server.setAutoStatus("reading");
|
|
20531
21374
|
server.setActiveToolCall({ name: "get_document_tree" });
|
|
20532
21375
|
const treeMap = server.getTreeMap();
|
|
20533
|
-
if (!treeMap) {
|
|
20534
|
-
|
|
20535
|
-
|
|
20536
|
-
|
|
20537
|
-
text: "Not connected"
|
|
20538
|
-
}] };
|
|
20539
|
-
}
|
|
21376
|
+
if (!treeMap) return { content: [{
|
|
21377
|
+
type: "text",
|
|
21378
|
+
text: "Not connected"
|
|
21379
|
+
}] };
|
|
20540
21380
|
const targetId = normalizeRootId(rootId, server);
|
|
20541
21381
|
const maxDepth = depth ?? 3;
|
|
20542
21382
|
const tree = buildTree$1(readEntries$1(treeMap), targetId, maxDepth);
|
|
20543
|
-
server.setActiveToolCall(null);
|
|
20544
21383
|
return { content: [{
|
|
20545
21384
|
type: "text",
|
|
20546
21385
|
text: JSON.stringify(tree, null, 2)
|
|
@@ -20556,13 +21395,10 @@ function registerTreeTools(mcp, server) {
|
|
|
20556
21395
|
target: query
|
|
20557
21396
|
});
|
|
20558
21397
|
const treeMap = server.getTreeMap();
|
|
20559
|
-
if (!treeMap) {
|
|
20560
|
-
|
|
20561
|
-
|
|
20562
|
-
|
|
20563
|
-
text: "Not connected"
|
|
20564
|
-
}] };
|
|
20565
|
-
}
|
|
21398
|
+
if (!treeMap) return { content: [{
|
|
21399
|
+
type: "text",
|
|
21400
|
+
text: "Not connected"
|
|
21401
|
+
}] };
|
|
20566
21402
|
const entries = readEntries$1(treeMap);
|
|
20567
21403
|
const lowerQuery = query.toLowerCase();
|
|
20568
21404
|
const normalizedRoot = normalizeRootId(rootId, server);
|
|
@@ -20587,7 +21423,6 @@ function registerTreeTools(mcp, server) {
|
|
|
20587
21423
|
path
|
|
20588
21424
|
};
|
|
20589
21425
|
});
|
|
20590
|
-
server.setActiveToolCall(null);
|
|
20591
21426
|
if (results.length === 0) return { content: [{
|
|
20592
21427
|
type: "text",
|
|
20593
21428
|
text: `No documents found matching "${query}". Try get_document_tree to see the full hierarchy.`
|
|
@@ -20600,8 +21435,8 @@ function registerTreeTools(mcp, server) {
|
|
|
20600
21435
|
mcp.tool("create_document", "Create a new document in the tree. Returns the new document ID.", {
|
|
20601
21436
|
parentId: zod.z.string().optional().describe("Parent document ID. Omit for top-level pages. Use a document ID for nested/child pages."),
|
|
20602
21437
|
label: zod.z.string().describe("Display name / title for the document."),
|
|
20603
|
-
type: zod.z.string().optional().describe("Page type — sets how this document renders. \"doc\" (rich text), \"kanban\" (columns → cards), \"table\" (columns → rows
|
|
20604
|
-
meta: zod.z.record(zod.z.unknown()).optional().describe("Initial metadata (PageMeta fields: color as hex string, icon as Lucide kebab-case name like \"star\"/\"code-2\"/\"users\" — never emoji, dateStart, dateEnd, priority 0-4, tags array, etc). Omit icon entirely to use page type default.")
|
|
21438
|
+
type: zod.z.string().optional().describe("Page type — sets how this document renders. Core types (always available): \"doc\" (rich text), \"kanban\" (columns → cards), \"table\" (columns → rows, positional), \"calendar\" (events with datetimeStart/End), \"timeline\" (epics → tasks with dateStart/End + taskProgress), \"checklist\" (tasks with checked/priority, unlimited nesting), \"outline\" (nested items, unlimited depth), \"gallery\" (visual grid with covers/ratings), \"map\" (markers/lines with geoLat/geoLng), \"graph\" (force-directed knowledge graph), \"dashboard\" (positioned widgets with deskX/deskY/deskMode), \"slides\" (slides → sub-slides with transitions), \"chart\" (bar/stacked bar/line/donut/treemap from data points or aggregation), \"sheets\" (spreadsheet with formulas and formatting), \"overview\" (space home — activity and stats), \"call\" (video call room, no children). Plugin types (require plugin enabled on the server): \"spatial\" (3D scene with spShape/spX/spY/spZ + universal color, plugin: spatial), \"media\" (audio/video player with playlists, plugin: media), \"coder\" (collaborative multi-file coding env with fileType/entry, plugin: coder). Alias: \"desktop\" → \"dashboard\". Omit to inherit parent view. Only set on the parent page, NEVER on child items."),
|
|
21439
|
+
meta: zod.z.record(zod.z.string(), zod.z.unknown()).optional().describe("Initial metadata (PageMeta fields: color as hex string, icon as Lucide kebab-case name like \"star\"/\"code-2\"/\"users\" — never emoji, dateStart, dateEnd, priority 0-4, tags array, etc). Omit icon entirely to use page type default.")
|
|
20605
21440
|
}, async ({ parentId, label, type, meta }) => {
|
|
20606
21441
|
server.setAutoStatus("creating");
|
|
20607
21442
|
server.setActiveToolCall({
|
|
@@ -20610,13 +21445,10 @@ function registerTreeTools(mcp, server) {
|
|
|
20610
21445
|
});
|
|
20611
21446
|
const treeMap = server.getTreeMap();
|
|
20612
21447
|
const rootDoc = server.rootDocument;
|
|
20613
|
-
if (!treeMap || !rootDoc) {
|
|
20614
|
-
|
|
20615
|
-
|
|
20616
|
-
|
|
20617
|
-
text: "Not connected"
|
|
20618
|
-
}] };
|
|
20619
|
-
}
|
|
21448
|
+
if (!treeMap || !rootDoc) return { content: [{
|
|
21449
|
+
type: "text",
|
|
21450
|
+
text: "Not connected"
|
|
21451
|
+
}] };
|
|
20620
21452
|
const id = crypto.randomUUID();
|
|
20621
21453
|
const normalizedParent = normalizeRootId(parentId, server);
|
|
20622
21454
|
const now = Date.now();
|
|
@@ -20632,7 +21464,6 @@ function registerTreeTools(mcp, server) {
|
|
|
20632
21464
|
});
|
|
20633
21465
|
});
|
|
20634
21466
|
server.setFocusedDoc(id);
|
|
20635
|
-
server.setActiveToolCall(null);
|
|
20636
21467
|
return { content: [{
|
|
20637
21468
|
type: "text",
|
|
20638
21469
|
text: JSON.stringify({
|
|
@@ -20653,28 +21484,21 @@ function registerTreeTools(mcp, server) {
|
|
|
20653
21484
|
target: id
|
|
20654
21485
|
});
|
|
20655
21486
|
const treeMap = server.getTreeMap();
|
|
20656
|
-
if (!treeMap) {
|
|
20657
|
-
|
|
20658
|
-
|
|
20659
|
-
|
|
20660
|
-
text: "Not connected"
|
|
20661
|
-
}] };
|
|
20662
|
-
}
|
|
21487
|
+
if (!treeMap) return { content: [{
|
|
21488
|
+
type: "text",
|
|
21489
|
+
text: "Not connected"
|
|
21490
|
+
}] };
|
|
20663
21491
|
const raw = treeMap.get(id);
|
|
20664
|
-
if (!raw) {
|
|
20665
|
-
|
|
20666
|
-
|
|
20667
|
-
|
|
20668
|
-
text: `Document ${id} not found`
|
|
20669
|
-
}] };
|
|
20670
|
-
}
|
|
21492
|
+
if (!raw) return { content: [{
|
|
21493
|
+
type: "text",
|
|
21494
|
+
text: `Document ${id} not found`
|
|
21495
|
+
}] };
|
|
20671
21496
|
const entry = toPlain(raw);
|
|
20672
21497
|
treeMap.set(id, {
|
|
20673
21498
|
...entry,
|
|
20674
21499
|
label,
|
|
20675
21500
|
updatedAt: Date.now()
|
|
20676
21501
|
});
|
|
20677
|
-
server.setActiveToolCall(null);
|
|
20678
21502
|
return { content: [{
|
|
20679
21503
|
type: "text",
|
|
20680
21504
|
text: `Renamed to "${label}"`
|
|
@@ -20691,21 +21515,15 @@ function registerTreeTools(mcp, server) {
|
|
|
20691
21515
|
target: id
|
|
20692
21516
|
});
|
|
20693
21517
|
const treeMap = server.getTreeMap();
|
|
20694
|
-
if (!treeMap) {
|
|
20695
|
-
|
|
20696
|
-
|
|
20697
|
-
|
|
20698
|
-
text: "Not connected"
|
|
20699
|
-
}] };
|
|
20700
|
-
}
|
|
21518
|
+
if (!treeMap) return { content: [{
|
|
21519
|
+
type: "text",
|
|
21520
|
+
text: "Not connected"
|
|
21521
|
+
}] };
|
|
20701
21522
|
const raw = treeMap.get(id);
|
|
20702
|
-
if (!raw) {
|
|
20703
|
-
|
|
20704
|
-
|
|
20705
|
-
|
|
20706
|
-
text: `Document ${id} not found`
|
|
20707
|
-
}] };
|
|
20708
|
-
}
|
|
21523
|
+
if (!raw) return { content: [{
|
|
21524
|
+
type: "text",
|
|
21525
|
+
text: `Document ${id} not found`
|
|
21526
|
+
}] };
|
|
20709
21527
|
const entry = toPlain(raw);
|
|
20710
21528
|
treeMap.set(id, {
|
|
20711
21529
|
...entry,
|
|
@@ -20713,7 +21531,6 @@ function registerTreeTools(mcp, server) {
|
|
|
20713
21531
|
order: order ?? Date.now(),
|
|
20714
21532
|
updatedAt: Date.now()
|
|
20715
21533
|
});
|
|
20716
|
-
server.setActiveToolCall(null);
|
|
20717
21534
|
return { content: [{
|
|
20718
21535
|
type: "text",
|
|
20719
21536
|
text: `Moved ${id} to parent ${newParentId}`
|
|
@@ -20728,13 +21545,10 @@ function registerTreeTools(mcp, server) {
|
|
|
20728
21545
|
const treeMap = server.getTreeMap();
|
|
20729
21546
|
const trashMap = server.getTrashMap();
|
|
20730
21547
|
const rootDoc = server.rootDocument;
|
|
20731
|
-
if (!treeMap || !trashMap || !rootDoc) {
|
|
20732
|
-
|
|
20733
|
-
|
|
20734
|
-
|
|
20735
|
-
text: "Not connected"
|
|
20736
|
-
}] };
|
|
20737
|
-
}
|
|
21548
|
+
if (!treeMap || !trashMap || !rootDoc) return { content: [{
|
|
21549
|
+
type: "text",
|
|
21550
|
+
text: "Not connected"
|
|
21551
|
+
}] };
|
|
20738
21552
|
const toDelete = [id, ...descendantsOf(readEntries$1(treeMap), id).map((e) => e.id)];
|
|
20739
21553
|
const now = Date.now();
|
|
20740
21554
|
rootDoc.transact(() => {
|
|
@@ -20753,7 +21567,6 @@ function registerTreeTools(mcp, server) {
|
|
|
20753
21567
|
treeMap.delete(nid);
|
|
20754
21568
|
}
|
|
20755
21569
|
});
|
|
20756
|
-
server.setActiveToolCall(null);
|
|
20757
21570
|
return { content: [{
|
|
20758
21571
|
type: "text",
|
|
20759
21572
|
text: `Deleted ${toDelete.length} document(s)`
|
|
@@ -20761,7 +21574,7 @@ function registerTreeTools(mcp, server) {
|
|
|
20761
21574
|
});
|
|
20762
21575
|
mcp.tool("change_document_type", "Change the page type view of a document (data is preserved).", {
|
|
20763
21576
|
id: zod.z.string().describe("Document ID."),
|
|
20764
|
-
type: zod.z.string().describe("New page type: \"doc\", \"kanban\", \"table\", \"calendar\", \"timeline\", \"checklist\", \"outline\", \"gallery\", \"map\", \"graph\", \"dashboard\", \"
|
|
21577
|
+
type: zod.z.string().describe("New page type. Core: \"doc\", \"kanban\", \"table\", \"calendar\", \"timeline\", \"checklist\", \"outline\", \"gallery\", \"map\", \"graph\", \"dashboard\", \"slides\", \"chart\", \"sheets\", \"overview\", \"call\". Plugin (require plugin enabled): \"spatial\", \"media\", \"coder\". Switching preserves the tree — children, labels, and meta are all retained; only the view changes.")
|
|
20765
21578
|
}, async ({ id, type }) => {
|
|
20766
21579
|
server.setAutoStatus("writing");
|
|
20767
21580
|
server.setActiveToolCall({
|
|
@@ -20769,28 +21582,21 @@ function registerTreeTools(mcp, server) {
|
|
|
20769
21582
|
target: id
|
|
20770
21583
|
});
|
|
20771
21584
|
const treeMap = server.getTreeMap();
|
|
20772
|
-
if (!treeMap) {
|
|
20773
|
-
|
|
20774
|
-
|
|
20775
|
-
|
|
20776
|
-
text: "Not connected"
|
|
20777
|
-
}] };
|
|
20778
|
-
}
|
|
21585
|
+
if (!treeMap) return { content: [{
|
|
21586
|
+
type: "text",
|
|
21587
|
+
text: "Not connected"
|
|
21588
|
+
}] };
|
|
20779
21589
|
const raw = treeMap.get(id);
|
|
20780
|
-
if (!raw) {
|
|
20781
|
-
|
|
20782
|
-
|
|
20783
|
-
|
|
20784
|
-
text: `Document ${id} not found`
|
|
20785
|
-
}] };
|
|
20786
|
-
}
|
|
21590
|
+
if (!raw) return { content: [{
|
|
21591
|
+
type: "text",
|
|
21592
|
+
text: `Document ${id} not found`
|
|
21593
|
+
}] };
|
|
20787
21594
|
const entry = toPlain(raw);
|
|
20788
21595
|
treeMap.set(id, {
|
|
20789
21596
|
...entry,
|
|
20790
21597
|
type,
|
|
20791
21598
|
updatedAt: Date.now()
|
|
20792
21599
|
});
|
|
20793
|
-
server.setActiveToolCall(null);
|
|
20794
21600
|
return { content: [{
|
|
20795
21601
|
type: "text",
|
|
20796
21602
|
text: `Changed type to "${type}"`
|
|
@@ -20846,6 +21652,27 @@ function registerTreeTools(mcp, server) {
|
|
|
20846
21652
|
}, null, 2)
|
|
20847
21653
|
}] };
|
|
20848
21654
|
});
|
|
21655
|
+
mcp.tool("list_page_types", "Enumerate all known Abracadabra page types with their metadata schemas. Returns an array of { key, label, icon, description, core, plugin, supportsChildren, childLabel, grandchildLabel, defaultDepth, metaSchema, defaultMetaFields }. `metaSchema` describes fields that apply to DESCENDANTS (children, grandchildren, ...) of a page of this type. `defaultMetaFields` are view-config fields on the page doc itself. Plugin types (core: false) require the named plugin to be enabled on the server. Use this to discover what meta keys a given renderer supports instead of guessing.", { key: zod.z.string().optional().describe("Filter to a single type by key (e.g. \"kanban\", \"calendar\"). Aliases are resolved (e.g. \"desktop\" → \"dashboard\"). Omit to list all types.") }, async ({ key }) => {
|
|
21656
|
+
if (key) {
|
|
21657
|
+
const resolved = resolvePageType(key);
|
|
21658
|
+
if (!resolved) return { content: [{
|
|
21659
|
+
type: "text",
|
|
21660
|
+
text: `Unknown page type "${key}". Call list_page_types with no args to see all types.`
|
|
21661
|
+
}] };
|
|
21662
|
+
return { content: [{
|
|
21663
|
+
type: "text",
|
|
21664
|
+
text: JSON.stringify(resolved, null, 2)
|
|
21665
|
+
}] };
|
|
21666
|
+
}
|
|
21667
|
+
const all = Object.values(PAGE_TYPES);
|
|
21668
|
+
return { content: [{
|
|
21669
|
+
type: "text",
|
|
21670
|
+
text: JSON.stringify({
|
|
21671
|
+
types: all,
|
|
21672
|
+
aliases: TYPE_ALIASES
|
|
21673
|
+
}, null, 2)
|
|
21674
|
+
}] };
|
|
21675
|
+
});
|
|
20849
21676
|
}
|
|
20850
21677
|
|
|
20851
21678
|
//#endregion
|
|
@@ -22025,7 +22852,6 @@ function registerContentTools(mcp, server) {
|
|
|
22025
22852
|
});
|
|
22026
22853
|
children.sort((a, b) => (treeMap.get(a.id)?.order ?? 0) - (treeMap.get(b.id)?.order ?? 0));
|
|
22027
22854
|
}
|
|
22028
|
-
server.setActiveToolCall(null);
|
|
22029
22855
|
const result = {
|
|
22030
22856
|
label,
|
|
22031
22857
|
type,
|
|
@@ -22038,7 +22864,6 @@ function registerContentTools(mcp, server) {
|
|
|
22038
22864
|
text: JSON.stringify(result, null, 2)
|
|
22039
22865
|
}] };
|
|
22040
22866
|
} catch (error) {
|
|
22041
|
-
server.setActiveToolCall(null);
|
|
22042
22867
|
return {
|
|
22043
22868
|
content: [{
|
|
22044
22869
|
type: "text",
|
|
@@ -22088,13 +22913,11 @@ function registerContentTools(mcp, server) {
|
|
|
22088
22913
|
populateYDocFromMarkdown(fragment, body || markdown, title || "Untitled");
|
|
22089
22914
|
server.setFocusedDoc(docId);
|
|
22090
22915
|
server.setDocCursor(docId, fragment.length);
|
|
22091
|
-
server.setActiveToolCall(null);
|
|
22092
22916
|
return { content: [{
|
|
22093
22917
|
type: "text",
|
|
22094
22918
|
text: `Document ${docId} updated (${writeMode} mode)`
|
|
22095
22919
|
}] };
|
|
22096
22920
|
} catch (error) {
|
|
22097
|
-
server.setActiveToolCall(null);
|
|
22098
22921
|
return {
|
|
22099
22922
|
content: [{
|
|
22100
22923
|
type: "text",
|
|
@@ -22116,22 +22939,15 @@ function registerMetaTools(mcp, server) {
|
|
|
22116
22939
|
target: docId
|
|
22117
22940
|
});
|
|
22118
22941
|
const treeMap = server.getTreeMap();
|
|
22119
|
-
if (!treeMap) {
|
|
22120
|
-
|
|
22121
|
-
|
|
22122
|
-
|
|
22123
|
-
text: "Not connected"
|
|
22124
|
-
}] };
|
|
22125
|
-
}
|
|
22942
|
+
if (!treeMap) return { content: [{
|
|
22943
|
+
type: "text",
|
|
22944
|
+
text: "Not connected"
|
|
22945
|
+
}] };
|
|
22126
22946
|
const entry = treeMap.get(docId);
|
|
22127
|
-
if (!entry) {
|
|
22128
|
-
|
|
22129
|
-
|
|
22130
|
-
|
|
22131
|
-
text: `Document ${docId} not found`
|
|
22132
|
-
}] };
|
|
22133
|
-
}
|
|
22134
|
-
server.setActiveToolCall(null);
|
|
22947
|
+
if (!entry) return { content: [{
|
|
22948
|
+
type: "text",
|
|
22949
|
+
text: `Document ${docId} not found`
|
|
22950
|
+
}] };
|
|
22135
22951
|
return { content: [{
|
|
22136
22952
|
type: "text",
|
|
22137
22953
|
text: JSON.stringify({
|
|
@@ -22144,7 +22960,7 @@ function registerMetaTools(mcp, server) {
|
|
|
22144
22960
|
});
|
|
22145
22961
|
mcp.tool("update_metadata", "Update metadata fields on a document. Merges the provided fields into existing metadata.", {
|
|
22146
22962
|
docId: zod.z.string().describe("Document ID."),
|
|
22147
|
-
meta: zod.z.record(zod.z.unknown()).describe("Metadata fields to update (merged with existing). Universal keys: color (hex), icon (Lucide kebab-case — NEVER emoji), dateStart/dateEnd, datetimeStart/datetimeEnd, allDay, tags (string[]), checked (bool), priority (0=none,1=low,2=med,3=high,4=urgent), status, rating (0-5), url, email, phone, number, unit, subtitle, note, taskProgress (0-100), members ({id,label}[]), coverUploadId. Geo/Map: geoType (\"marker\"|\"line\"|\"measure\"), geoLat, geoLng, geoDescription. Spatial 3D: spShape (\"box\"|\"sphere\"|\"cylinder\"|\"cone\"|\"plane\"|\"torus\"|\"glb\"), spX/spY/spZ, spRX/spRY/spRZ, spSX/spSY/spSZ
|
|
22963
|
+
meta: zod.z.record(zod.z.string(), zod.z.unknown()).describe("Metadata fields to update (merged with existing). Universal keys: color (hex), icon (Lucide kebab-case — NEVER emoji), dateStart/dateEnd, datetimeStart/datetimeEnd, allDay, timeStart/timeEnd, tags (string[]), checked (bool), priority (0=none,1=low,2=med,3=high,4=urgent), status, rating (0-5), url, email, phone, number, unit, subtitle, note, taskProgress (0-100), members ({id,label}[]), coverUploadId, coverDocId, dateTaken. Geo/Map (children): geoType (\"marker\"|\"line\"|\"measure\"), geoLat, geoLng, geoDescription. Spatial 3D (children, plugin: spatial): spShape (\"box\"|\"sphere\"|\"cylinder\"|\"cone\"|\"plane\"|\"torus\"|\"glb\"), spX/spY/spZ, spRX/spRY/spRZ (deg), spSX/spSY/spSZ (scale), spOpacity (0-100), spModelUploadId, spModelDocId — spatial uses the universal `color` key, NOT spColor. Dashboard (children): deskX, deskY, deskZ, deskMode (\"icon\"|\"widget-sm\"|\"widget-lg\"). Mindmap-layout (children): mmX, mmY. Graph-layout (children): graphX, graphY, graphPinned. Slides (children): slidesTransition (\"none\"|\"fade\"|\"slide\"). Coder (children, plugin: coder): fileType (\"vue\"|\"ts\"|\"js\"|\"css\"|\"json\"|\"folder\"), entry (bool). Cell formatting (sheets cells): bold, italic, textColor, bgColor, align (\"left\"|\"center\"|\"right\"), formula. Renderer config (on the PAGE doc itself, not children): kanbanColumnWidth (\"narrow\"|\"default\"|\"wide\"), galleryColumns (1-6), galleryAspect (\"square\"|\"4:3\"|\"3:2\"|\"16:9\"|\"free\"), galleryCardStyle (\"default\"|\"compact\"|\"detailed\"), galleryShowLabels, gallerySortBy (\"manual\"|\"date\"|\"name\"|\"rating\"), calendarView (\"month\"|\"week\"|\"day\"), calendarWeekStart (\"sun\"|\"mon\"), calendarShowWeekNumbers, tableMode (\"hierarchy\"|\"flat\"), tableSortKey, tableSortDir (\"asc\"|\"desc\"), timelineZoom (\"week\"|\"month\"|\"quarter\"), timelinePixelsPerDay, timelineCenterDate (ISO date), checklistFilter (\"all\"|\"active\"|\"completed\"), checklistSort (\"manual\"|\"priority\"|\"due\"), mapShowLabels, graphSpacing (\"compact\"|\"default\"|\"spacious\"), graphShowLabels, graphEdgeThickness (\"thin\"|\"normal\"|\"thick\"), showRefEdges, mmSpacing, spatialGridVisible, slidesTheme (\"dark\"|\"light\"), chartType (\"bar\"|\"stacked bar\"|\"line\"|\"donut\"|\"treemap\"), chartMetric (\"value\"|\"type\"|\"tag\"|\"status\"|\"priority\"|\"activity\"|\"completion\"), chartColorScheme (\"default\"|\"warm\"|\"cool\"|\"mono\"), chartLimit (3-30), chartShowLegend, chartShowValues, sheetsDefaultColWidth (40-500), sheetsDefaultRowHeight (20-100), sheetsShowGridlines, sheetsFreezeRows, sheetsFreezeCols, mediaRepeat (\"off\"|\"all\"|\"one\"), mediaShuffle. Set a key to null to clear it.")
|
|
22148
22964
|
}, async ({ docId, meta }) => {
|
|
22149
22965
|
server.setAutoStatus("writing", docId);
|
|
22150
22966
|
server.setActiveToolCall({
|
|
@@ -22152,21 +22968,15 @@ function registerMetaTools(mcp, server) {
|
|
|
22152
22968
|
target: docId
|
|
22153
22969
|
});
|
|
22154
22970
|
const treeMap = server.getTreeMap();
|
|
22155
|
-
if (!treeMap) {
|
|
22156
|
-
|
|
22157
|
-
|
|
22158
|
-
|
|
22159
|
-
text: "Not connected"
|
|
22160
|
-
}] };
|
|
22161
|
-
}
|
|
22971
|
+
if (!treeMap) return { content: [{
|
|
22972
|
+
type: "text",
|
|
22973
|
+
text: "Not connected"
|
|
22974
|
+
}] };
|
|
22162
22975
|
const entry = treeMap.get(docId);
|
|
22163
|
-
if (!entry) {
|
|
22164
|
-
|
|
22165
|
-
|
|
22166
|
-
|
|
22167
|
-
text: `Document ${docId} not found`
|
|
22168
|
-
}] };
|
|
22169
|
-
}
|
|
22976
|
+
if (!entry) return { content: [{
|
|
22977
|
+
type: "text",
|
|
22978
|
+
text: `Document ${docId} not found`
|
|
22979
|
+
}] };
|
|
22170
22980
|
treeMap.set(docId, {
|
|
22171
22981
|
...entry,
|
|
22172
22982
|
meta: {
|
|
@@ -22175,7 +22985,6 @@ function registerMetaTools(mcp, server) {
|
|
|
22175
22985
|
},
|
|
22176
22986
|
updatedAt: Date.now()
|
|
22177
22987
|
});
|
|
22178
|
-
server.setActiveToolCall(null);
|
|
22179
22988
|
return { content: [{
|
|
22180
22989
|
type: "text",
|
|
22181
22990
|
text: `Metadata updated for ${docId}`
|
|
@@ -22190,6 +22999,11 @@ function registerMetaTools(mcp, server) {
|
|
|
22190
22999
|
*/
|
|
22191
23000
|
function registerFileTools(mcp, server) {
|
|
22192
23001
|
mcp.tool("list_uploads", "List file attachments for a document.", { docId: zod.z.string().describe("Document ID.") }, async ({ docId }) => {
|
|
23002
|
+
server.setAutoStatus("reading", docId);
|
|
23003
|
+
server.setActiveToolCall({
|
|
23004
|
+
name: "list_uploads",
|
|
23005
|
+
target: docId
|
|
23006
|
+
});
|
|
22193
23007
|
try {
|
|
22194
23008
|
const uploads = await server.client.listUploads(docId);
|
|
22195
23009
|
return { content: [{
|
|
@@ -22211,6 +23025,11 @@ function registerFileTools(mcp, server) {
|
|
|
22211
23025
|
filePath: zod.z.string().describe("Absolute path to the local file to upload."),
|
|
22212
23026
|
filename: zod.z.string().optional().describe("Override filename (defaults to basename of filePath).")
|
|
22213
23027
|
}, async ({ docId, filePath, filename }) => {
|
|
23028
|
+
server.setAutoStatus("uploading", docId);
|
|
23029
|
+
server.setActiveToolCall({
|
|
23030
|
+
name: "upload_file",
|
|
23031
|
+
target: node_path.basename(filePath)
|
|
23032
|
+
});
|
|
22214
23033
|
try {
|
|
22215
23034
|
const resolvedPath = node_path.resolve(filePath);
|
|
22216
23035
|
const data = node_fs.readFileSync(resolvedPath);
|
|
@@ -22236,6 +23055,11 @@ function registerFileTools(mcp, server) {
|
|
|
22236
23055
|
uploadId: zod.z.string().describe("Upload ID to download."),
|
|
22237
23056
|
saveTo: zod.z.string().describe("Absolute local file path to save the download.")
|
|
22238
23057
|
}, async ({ docId, uploadId, saveTo }) => {
|
|
23058
|
+
server.setAutoStatus("reading", docId);
|
|
23059
|
+
server.setActiveToolCall({
|
|
23060
|
+
name: "download_file",
|
|
23061
|
+
target: node_path.basename(saveTo)
|
|
23062
|
+
});
|
|
22239
23063
|
try {
|
|
22240
23064
|
const blob = await server.client.getUpload(docId, uploadId);
|
|
22241
23065
|
const buffer = Buffer.from(await blob.arrayBuffer());
|
|
@@ -22259,6 +23083,11 @@ function registerFileTools(mcp, server) {
|
|
|
22259
23083
|
docId: zod.z.string().describe("Document ID."),
|
|
22260
23084
|
uploadId: zod.z.string().describe("Upload ID to delete.")
|
|
22261
23085
|
}, async ({ docId, uploadId }) => {
|
|
23086
|
+
server.setAutoStatus("writing", docId);
|
|
23087
|
+
server.setActiveToolCall({
|
|
23088
|
+
name: "delete_file",
|
|
23089
|
+
target: uploadId
|
|
23090
|
+
});
|
|
22262
23091
|
try {
|
|
22263
23092
|
await server.client.deleteUpload(docId, uploadId);
|
|
22264
23093
|
return { content: [{
|
|
@@ -22300,6 +23129,10 @@ function registerAwarenessTools(mcp, server) {
|
|
|
22300
23129
|
docId: zod.z.string().describe("Document ID to set awareness on."),
|
|
22301
23130
|
fields: zod.z.record(zod.z.string(), zod.z.unknown()).describe("Key-value pairs to set on the child document's awareness state. Use namespaced keys like \"kanban:hovering\", \"table:editing\", \"slides:viewing\", \"outline:editing\", \"calendar:focused\", \"gallery:focused\", \"timeline:focused\", \"graph:focused\", \"map:focused\", \"doc:scroll\". Set a key to null to clear it.")
|
|
22302
23131
|
}, async ({ docId, fields }) => {
|
|
23132
|
+
server.setActiveToolCall({
|
|
23133
|
+
name: "set_doc_awareness",
|
|
23134
|
+
target: docId
|
|
23135
|
+
});
|
|
22303
23136
|
try {
|
|
22304
23137
|
const provider = await server.getChildProvider(docId);
|
|
22305
23138
|
for (const [key, value] of Object.entries(fields)) provider.awareness.setLocalStateField(key, value ?? null);
|
|
@@ -22318,6 +23151,7 @@ function registerAwarenessTools(mcp, server) {
|
|
|
22318
23151
|
}
|
|
22319
23152
|
});
|
|
22320
23153
|
mcp.tool("poll_inbox", "Check the \"AI Inbox\" document for pending instructions from humans. Returns the inbox content and any pending task sub-documents. Create the inbox as a doc called \"AI Inbox\" under the hub doc if it does not exist yet. Note: channel-based watching via watch_chat is preferred for real-time use.", {}, async () => {
|
|
23154
|
+
server.setActiveToolCall({ name: "poll_inbox" });
|
|
22321
23155
|
try {
|
|
22322
23156
|
const treeMap = server.getTreeMap();
|
|
22323
23157
|
const rootDocId = server.rootDocId;
|
|
@@ -22364,6 +23198,10 @@ function registerAwarenessTools(mcp, server) {
|
|
|
22364
23198
|
}
|
|
22365
23199
|
});
|
|
22366
23200
|
mcp.tool("list_connected_users", "List all connected users and their awareness state. Shows who is online and what they are doing.", { docId: zod.z.string().optional().describe("If provided, list users connected to this specific document. Otherwise lists users from root awareness.") }, async ({ docId }) => {
|
|
23201
|
+
server.setActiveToolCall({
|
|
23202
|
+
name: "list_connected_users",
|
|
23203
|
+
target: docId
|
|
23204
|
+
});
|
|
22367
23205
|
try {
|
|
22368
23206
|
let awareness;
|
|
22369
23207
|
if (docId) awareness = (await server.getChildProvider(docId)).awareness;
|
|
@@ -22408,16 +23246,13 @@ function registerChannelTools(mcp, server) {
|
|
|
22408
23246
|
});
|
|
22409
23247
|
const treeMap = server.getTreeMap();
|
|
22410
23248
|
const rootDoc = server.rootDocument;
|
|
22411
|
-
if (!treeMap || !rootDoc) {
|
|
22412
|
-
|
|
22413
|
-
|
|
22414
|
-
|
|
22415
|
-
|
|
22416
|
-
|
|
22417
|
-
|
|
22418
|
-
isError: true
|
|
22419
|
-
};
|
|
22420
|
-
}
|
|
23249
|
+
if (!treeMap || !rootDoc) return {
|
|
23250
|
+
content: [{
|
|
23251
|
+
type: "text",
|
|
23252
|
+
text: "Not connected"
|
|
23253
|
+
}],
|
|
23254
|
+
isError: true
|
|
23255
|
+
};
|
|
22421
23256
|
const label = `AI Reply — ${(/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)}: ${text.slice(0, 40).replace(/\n/g, " ")}`;
|
|
22422
23257
|
const replyId = crypto.randomUUID();
|
|
22423
23258
|
const now = Date.now();
|
|
@@ -22433,7 +23268,6 @@ function registerChannelTools(mcp, server) {
|
|
|
22433
23268
|
});
|
|
22434
23269
|
populateYDocFromMarkdown((await server.getChildProvider(replyId)).document, text);
|
|
22435
23270
|
if (task_id) server.clearAiTask(task_id);
|
|
22436
|
-
server.setActiveToolCall(null);
|
|
22437
23271
|
return { content: [{
|
|
22438
23272
|
type: "text",
|
|
22439
23273
|
text: JSON.stringify({
|
|
@@ -22442,7 +23276,6 @@ function registerChannelTools(mcp, server) {
|
|
|
22442
23276
|
})
|
|
22443
23277
|
}] };
|
|
22444
23278
|
} catch (error) {
|
|
22445
|
-
server.setActiveToolCall(null);
|
|
22446
23279
|
return {
|
|
22447
23280
|
content: [{
|
|
22448
23281
|
type: "text",
|
|
@@ -22465,14 +23298,15 @@ function registerChannelTools(mcp, server) {
|
|
|
22465
23298
|
}],
|
|
22466
23299
|
isError: true
|
|
22467
23300
|
};
|
|
23301
|
+
const normalized = text.replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\r/g, "\n");
|
|
23302
|
+
server.setAutoStatus(null);
|
|
23303
|
+
server.sendTypingIndicator(channel);
|
|
22468
23304
|
rootProvider.sendStateless(JSON.stringify({
|
|
22469
23305
|
type: "chat:send",
|
|
22470
23306
|
channel,
|
|
22471
|
-
content:
|
|
23307
|
+
content: normalized,
|
|
22472
23308
|
sender_name: server.agentName
|
|
22473
23309
|
}));
|
|
22474
|
-
server.setAutoStatus(null);
|
|
22475
|
-
server.setActiveToolCall(null);
|
|
22476
23310
|
return { content: [{
|
|
22477
23311
|
type: "text",
|
|
22478
23312
|
text: `Sent to ${channel}`
|
|
@@ -22627,16 +23461,13 @@ function registerSvgTools(mcp, server) {
|
|
|
22627
23461
|
target: docId
|
|
22628
23462
|
});
|
|
22629
23463
|
const cleanSvg = sanitizeSvg(svg);
|
|
22630
|
-
if (!cleanSvg) {
|
|
22631
|
-
|
|
22632
|
-
|
|
22633
|
-
|
|
22634
|
-
|
|
22635
|
-
|
|
22636
|
-
|
|
22637
|
-
isError: true
|
|
22638
|
-
};
|
|
22639
|
-
}
|
|
23464
|
+
if (!cleanSvg) return {
|
|
23465
|
+
content: [{
|
|
23466
|
+
type: "text",
|
|
23467
|
+
text: "Error: SVG markup was empty or entirely stripped by sanitizer."
|
|
23468
|
+
}],
|
|
23469
|
+
isError: true
|
|
23470
|
+
};
|
|
22640
23471
|
const doc = (await server.getChildProvider(docId)).document;
|
|
22641
23472
|
const fragment = doc.getXmlFragment("default");
|
|
22642
23473
|
doc.transact(() => {
|
|
@@ -22647,13 +23478,11 @@ function registerSvgTools(mcp, server) {
|
|
|
22647
23478
|
fragment.insert(insertPos, [el]);
|
|
22648
23479
|
});
|
|
22649
23480
|
server.setFocusedDoc(docId);
|
|
22650
|
-
server.setActiveToolCall(null);
|
|
22651
23481
|
return { content: [{
|
|
22652
23482
|
type: "text",
|
|
22653
23483
|
text: `SVG inserted into document ${docId}${title ? ` ("${title}")` : ""}`
|
|
22654
23484
|
}] };
|
|
22655
23485
|
} catch (error) {
|
|
22656
|
-
server.setActiveToolCall(null);
|
|
22657
23486
|
return {
|
|
22658
23487
|
content: [{
|
|
22659
23488
|
type: "text",
|
|
@@ -22711,24 +23540,38 @@ If you are adding content to an existing space, call \`get_document_tree(rootId:
|
|
|
22711
23540
|
|
|
22712
23541
|
## Page Types Reference
|
|
22713
23542
|
|
|
23543
|
+
### Core Types (always available)
|
|
23544
|
+
|
|
22714
23545
|
| Type | Children Are | Grandchildren Are | Depth | Key Meta on Children |
|
|
22715
23546
|
|------|-------------|-------------------|-------|---------------------|
|
|
22716
23547
|
| **doc** | Sub-documents | Sub-sub-documents | ∞ | — |
|
|
22717
23548
|
| **kanban** | Columns | Cards | 2 | color, icon on cards |
|
|
22718
23549
|
| **table** | Columns | Cells (positional rows) | 2 | — |
|
|
22719
|
-
| **calendar** | Events | — | 1 | datetimeStart, datetimeEnd, allDay, color |
|
|
23550
|
+
| **calendar** | Events | — | 1 | datetimeStart, datetimeEnd, allDay, color, icon |
|
|
22720
23551
|
| **timeline** | Epics | Tasks | 2 | dateStart, dateEnd, taskProgress, color |
|
|
22721
23552
|
| **checklist** | Tasks | Sub-tasks | ∞ | checked, priority, dateEnd |
|
|
22722
23553
|
| **outline** | Items | Sub-items | ∞ | — |
|
|
22723
|
-
| **mindmap** | Central nodes | Branches | ∞ | mmX, mmY |
|
|
22724
23554
|
| **graph** | Nodes | — | 1 | graphX, graphY, graphPinned, color |
|
|
22725
|
-
| **gallery** | Items | — | 1 | geoLat, geoLng, datetimeStart, tags |
|
|
23555
|
+
| **gallery** | Items | — | 1 | geoLat, geoLng, datetimeStart, tags, rating, icon, color |
|
|
22726
23556
|
| **map** | Markers/Lines | Points (for lines) | 2 | geoType, geoLat, geoLng, icon, color |
|
|
22727
|
-
| **
|
|
22728
|
-
| **
|
|
22729
|
-
| **
|
|
22730
|
-
| **
|
|
22731
|
-
| **
|
|
23557
|
+
| **slides** | Slides | Sub-slides | 2 | slidesTransition, color |
|
|
23558
|
+
| **dashboard** | Items | — | 1 | deskX, deskY, deskZ, deskMode |
|
|
23559
|
+
| **chart** | Data points | Data points | 2 | number (value), color, tags |
|
|
23560
|
+
| **sheets** | Columns | Cells | 2 | formula, bold, italic, textColor, bgColor, align |
|
|
23561
|
+
| **overview** | Pages | — | 1 | — |
|
|
23562
|
+
| **call** | — (no children) | — | 0 | — |
|
|
23563
|
+
|
|
23564
|
+
Alias: \`desktop\` → \`dashboard\`.
|
|
23565
|
+
|
|
23566
|
+
### Plugin Types (require plugin enabled on the server)
|
|
23567
|
+
|
|
23568
|
+
| Type | Plugin | Children Are | Grandchildren Are | Depth | Key Meta on Children |
|
|
23569
|
+
|------|--------|-------------|-------------------|-------|---------------------|
|
|
23570
|
+
| **spatial** | spatial | Objects | Sub-parts | ∞ | spShape, spX/Y/Z, spRX/RY/RZ, spSX/SY/SZ, color, spOpacity |
|
|
23571
|
+
| **media** | media | Tracks | — | ∞ | tags |
|
|
23572
|
+
| **coder** | coder | Files/Folders | — | ∞ | fileType, entry |
|
|
23573
|
+
|
|
23574
|
+
> Spatial uses the universal \`color\` key for object color — there is no \`spColor\`.
|
|
22732
23575
|
|
|
22733
23576
|
---
|
|
22734
23577
|
|
|
@@ -22801,18 +23644,65 @@ If you are adding content to an existing space, call \`get_document_tree(rootId:
|
|
|
22801
23644
|
4. Modes: \`"icon"\` (small), \`"widget-sm"\` (240×180), \`"widget-lg"\` (400×320)
|
|
22802
23645
|
5. Grid uses 80px cells
|
|
22803
23646
|
|
|
22804
|
-
**Spatial (3D scene)
|
|
23647
|
+
**Spatial (3D scene)** *(requires spatial plugin):*
|
|
22805
23648
|
1. \`create_document(parentId, "3D Scene", "spatial")\`
|
|
22806
23649
|
2. Create objects: \`create_document(sceneId, "Red Cube")\`
|
|
22807
|
-
3. Set 3D properties: \`update_metadata(objId, { spShape: "box",
|
|
22808
|
-
4. Shapes: \`"box"\`, \`"sphere"\`, \`"cylinder"\`, \`"cone"\`, \`"plane"\`, \`"torus"\`, \`"glb"\` (uploaded 3D model)
|
|
23650
|
+
3. Set 3D properties: \`update_metadata(objId, { spShape: "box", color: "#ef4444", spX: 0, spY: 1, spZ: 0, spSX: 2, spSY: 2, spSZ: 2 })\`
|
|
23651
|
+
4. Shapes: \`"box"\`, \`"sphere"\`, \`"cylinder"\`, \`"cone"\`, \`"plane"\`, \`"torus"\`, \`"glb"\` (uploaded 3D model — set \`spModelUploadId\` and \`spModelDocId\`)
|
|
22809
23652
|
5. Rotation (degrees): \`spRX\`, \`spRY\`, \`spRZ\`. Scale: \`spSX\`, \`spSY\`, \`spSZ\` (default 1). Opacity: \`spOpacity\` (0–100)
|
|
23653
|
+
6. Use the universal \`color\` key — **never \`spColor\`**
|
|
22810
23654
|
|
|
22811
23655
|
**Outline (nested items):**
|
|
22812
23656
|
1. \`create_document(parentId, "Meeting Notes", "outline")\`
|
|
22813
23657
|
2. Create items: \`create_document(outlineId, "Agenda Item 1")\`
|
|
22814
23658
|
3. Create sub-items (unlimited depth): \`create_document(itemId, "Sub-point")\`
|
|
22815
23659
|
|
|
23660
|
+
**Slides (presentation with two-axis nav):**
|
|
23661
|
+
1. \`create_document(parentId, "Q1 Review", "slides")\`
|
|
23662
|
+
2. Create slides as direct children: \`create_document(deckId, "Intro")\`
|
|
23663
|
+
3. Create sub-slides (vertical navigation) as grandchildren: \`create_document(slideId, "Deep dive")\`
|
|
23664
|
+
4. Per-slide transition: \`update_metadata(slideId, { slidesTransition: "fade", color: "#6366f1" })\`
|
|
23665
|
+
5. Deck-level theme: \`update_metadata(deckId, { slidesTheme: "dark" })\`
|
|
23666
|
+
|
|
23667
|
+
**Chart (data viz — manual or aggregation):**
|
|
23668
|
+
1. \`create_document(parentId, "Sales", "chart")\`
|
|
23669
|
+
2. Configure: \`update_metadata(chartId, { chartType: "bar", chartMetric: "value", chartShowLegend: true, chartLimit: 10 })\`
|
|
23670
|
+
3. Modes:
|
|
23671
|
+
- **Manual data points**: create children with \`number\` (value) and optional \`tags\`/\`color\`
|
|
23672
|
+
\`create_document(chartId, "Q1")\` then \`update_metadata(dpId, { number: 42500, color: "#6366f1" })\`
|
|
23673
|
+
- **Aggregation**: set \`chartMetric\` to \`"type"\`/\`"tag"\`/\`"status"\`/\`"priority"\`/\`"activity"\`/\`"completion"\` and point the chart at a subtree — it aggregates the descendants' meta automatically
|
|
23674
|
+
4. Chart types: \`"bar"\`, \`"stacked bar"\`, \`"line"\`, \`"donut"\`, \`"treemap"\`
|
|
23675
|
+
5. Color schemes: \`"default"\`, \`"warm"\`, \`"cool"\`, \`"mono"\`
|
|
23676
|
+
|
|
23677
|
+
**Sheets (spreadsheet with formulas):**
|
|
23678
|
+
1. \`create_document(parentId, "Budget", "sheets")\`
|
|
23679
|
+
2. Create columns: \`create_document(sheetId, "A")\`, \`create_document(sheetId, "B")\`
|
|
23680
|
+
3. Create cells under columns (positional rows, like \`table\`)
|
|
23681
|
+
4. Formulas on cells: \`update_metadata(cellId, { formula: "=A1+B1" })\`
|
|
23682
|
+
5. Cell formatting: \`update_metadata(cellId, { bold: true, bgColor: "#fef3c7", align: "right" })\`
|
|
23683
|
+
6. Deck config: \`update_metadata(sheetId, { sheetsDefaultColWidth: 120, sheetsDefaultRowHeight: 28, sheetsShowGridlines: true, sheetsFreezeRows: 1, sheetsFreezeCols: 1 })\`
|
|
23684
|
+
|
|
23685
|
+
**Overview (space home):**
|
|
23686
|
+
1. \`create_document(parentId, "Home", "overview")\`
|
|
23687
|
+
2. No children required — renders activity, people, stats from the surrounding space
|
|
23688
|
+
3. Children (if any) show as linked pages
|
|
23689
|
+
|
|
23690
|
+
**Call (video room):**
|
|
23691
|
+
1. \`create_document(parentId, "Daily Standup", "call")\`
|
|
23692
|
+
2. Video rooms have **no children** — do not add documents underneath
|
|
23693
|
+
|
|
23694
|
+
**Coder (multi-file collaborative editor)** *(requires coder plugin):*
|
|
23695
|
+
1. \`create_document(parentId, "My App", "coder")\`
|
|
23696
|
+
2. Create files/folders: \`create_document(projectId, "App.vue")\`, \`create_document(projectId, "src")\`
|
|
23697
|
+
3. Set file type: \`update_metadata(fileId, { fileType: "vue", entry: true })\`
|
|
23698
|
+
4. \`fileType\` options: \`"vue"\`, \`"ts"\`, \`"js"\`, \`"css"\`, \`"json"\`, \`"folder"\`
|
|
23699
|
+
5. Mark the entry file with \`entry: true\` — the renderer uses it as the preview root
|
|
23700
|
+
|
|
23701
|
+
**Media (audio/video playlist)** *(requires media plugin):*
|
|
23702
|
+
1. \`create_document(parentId, "Focus Mix", "media")\`
|
|
23703
|
+
2. Create tracks: \`create_document(playlistId, "Track 1")\` — attach audio/video file via upload tool
|
|
23704
|
+
3. Playlist config: \`update_metadata(playlistId, { mediaRepeat: "all", mediaShuffle: false })\`
|
|
23705
|
+
|
|
22816
23706
|
---
|
|
22817
23707
|
|
|
22818
23708
|
## Document References
|
|
@@ -22887,22 +23777,55 @@ In the **graph** page type, document references (embeds and links) create visibl
|
|
|
22887
23777
|
|-----|------|-----------|--------|
|
|
22888
23778
|
| \`kanbanColumnWidth\` | string | kanban | "narrow", "default", "wide" |
|
|
22889
23779
|
| \`galleryColumns\` | number | gallery | 1–6 |
|
|
22890
|
-
| \`galleryAspect\` | string | gallery | "square", "4:3", "16:9" |
|
|
23780
|
+
| \`galleryAspect\` | string | gallery | "square", "4:3", "3:2", "16:9", "free" |
|
|
23781
|
+
| \`galleryCardStyle\` | string | gallery | "default", "compact", "detailed" |
|
|
23782
|
+
| \`galleryShowLabels\` | boolean | gallery | show item labels |
|
|
23783
|
+
| \`gallerySortBy\` | string | gallery | "manual", "date", "name", "rating" |
|
|
22891
23784
|
| \`calendarView\` | string | calendar | "month", "week", "day" |
|
|
22892
23785
|
| \`calendarWeekStart\` | string | calendar | "sun", "mon" |
|
|
23786
|
+
| \`calendarShowWeekNumbers\` | boolean | calendar | — |
|
|
22893
23787
|
| \`tableMode\` | string | table | "hierarchy", "flat" |
|
|
23788
|
+
| \`tableSortKey\` | string | table | meta key to sort by |
|
|
23789
|
+
| \`tableSortDir\` | string | table | "asc", "desc" |
|
|
23790
|
+
| \`timelineZoom\` | string | timeline | "week", "month", "quarter" |
|
|
23791
|
+
| \`timelinePixelsPerDay\` | number | timeline | zoom granularity |
|
|
23792
|
+
| \`timelineCenterDate\` | string | timeline | ISO date to center view |
|
|
23793
|
+
| \`checklistFilter\` | string | checklist | "all", "active", "completed" |
|
|
23794
|
+
| \`checklistSort\` | string | checklist | "manual", "priority", "due" |
|
|
23795
|
+
| \`mapShowLabels\` | boolean | map | — |
|
|
23796
|
+
| \`graphSpacing\` | string | graph | "compact", "default", "spacious" |
|
|
23797
|
+
| \`graphShowLabels\` | boolean | graph | — |
|
|
23798
|
+
| \`graphEdgeThickness\` | string | graph | "thin", "normal", "thick" |
|
|
22894
23799
|
| \`showRefEdges\` | boolean | graph | show doc-reference edges |
|
|
22895
|
-
|
|
22896
|
-
|
|
23800
|
+
| \`mmSpacing\` | string | mindmap-layout | spacing between branches |
|
|
23801
|
+
| \`spatialGridVisible\` | boolean | spatial | show ground grid |
|
|
23802
|
+
| \`slidesTheme\` | string | slides | "dark", "light" |
|
|
23803
|
+
| \`chartType\` | string | chart | "bar", "stacked bar", "line", "donut", "treemap" |
|
|
23804
|
+
| \`chartMetric\` | string | chart | "value", "type", "tag", "status", "priority", "activity", "completion" |
|
|
23805
|
+
| \`chartColorScheme\` | string | chart | "default", "warm", "cool", "mono" |
|
|
23806
|
+
| \`chartLimit\` | number | chart | 3–30 (max items) |
|
|
23807
|
+
| \`chartShowLegend\` | boolean | chart | — |
|
|
23808
|
+
| \`chartShowValues\` | boolean | chart | — |
|
|
23809
|
+
| \`sheetsDefaultColWidth\` | number | sheets | 40–500 |
|
|
23810
|
+
| \`sheetsDefaultRowHeight\` | number | sheets | 20–100 |
|
|
23811
|
+
| \`sheetsShowGridlines\` | boolean | sheets | — |
|
|
23812
|
+
| \`sheetsFreezeRows\` | number | sheets | frozen rows count |
|
|
23813
|
+
| \`sheetsFreezeCols\` | number | sheets | frozen cols count |
|
|
23814
|
+
| \`mediaRepeat\` | string | media | "off", "all", "one" (plugin) |
|
|
23815
|
+
| \`mediaShuffle\` | boolean | media | plugin |
|
|
23816
|
+
|
|
23817
|
+
### Spatial 3D Keys (for spatial children — requires spatial plugin)
|
|
22897
23818
|
|
|
22898
23819
|
| Key | Type | Default | Meaning |
|
|
22899
23820
|
|-----|------|---------|---------|
|
|
22900
23821
|
| \`spShape\` | string | — | "box", "sphere", "cylinder", "cone", "plane", "torus", "glb" |
|
|
22901
|
-
| \`
|
|
23822
|
+
| \`color\` | string | — | CSS color — universal key, **not** \`spColor\` |
|
|
22902
23823
|
| \`spOpacity\` | number | 100 | 0–100 |
|
|
22903
23824
|
| \`spX\`, \`spY\`, \`spZ\` | number | 0 | Position |
|
|
22904
23825
|
| \`spRX\`, \`spRY\`, \`spRZ\` | number | 0 | Rotation (degrees) |
|
|
22905
23826
|
| \`spSX\`, \`spSY\`, \`spSZ\` | number | 1 | Scale |
|
|
23827
|
+
| \`spModelUploadId\` | string | — | GLB upload ID (when \`spShape: "glb"\`) |
|
|
23828
|
+
| \`spModelDocId\` | string | — | Doc ID that owns the GLB upload |
|
|
22906
23829
|
|
|
22907
23830
|
### Dashboard Keys (for dashboard children)
|
|
22908
23831
|
|
|
@@ -22912,6 +23835,28 @@ In the **graph** page type, document references (embeds and links) create visibl
|
|
|
22912
23835
|
| \`deskZ\` | number | Z-index (layering) |
|
|
22913
23836
|
| \`deskMode\` | string | "icon", "widget-sm" (240×180), "widget-lg" (400×320) |
|
|
22914
23837
|
|
|
23838
|
+
### Sheets Cell Formatting (per-cell meta)
|
|
23839
|
+
|
|
23840
|
+
| Key | Type | Meaning |
|
|
23841
|
+
|-----|------|---------|
|
|
23842
|
+
| \`formula\` | string | Cell formula (e.g. "=A1+B1") |
|
|
23843
|
+
| \`bold\` | boolean | — |
|
|
23844
|
+
| \`italic\` | boolean | — |
|
|
23845
|
+
| \`textColor\` | string | CSS color |
|
|
23846
|
+
| \`bgColor\` | string | CSS color |
|
|
23847
|
+
| \`align\` | string | "left", "center", "right" |
|
|
23848
|
+
|
|
23849
|
+
### Coder Keys (for coder children — plugin)
|
|
23850
|
+
|
|
23851
|
+
| Key | Type | Meaning |
|
|
23852
|
+
|-----|------|---------|
|
|
23853
|
+
| \`fileType\` | string | "vue", "ts", "js", "css", "json", "folder" |
|
|
23854
|
+
| \`entry\` | boolean | Mark this file as the preview entry point |
|
|
23855
|
+
|
|
23856
|
+
### Discovering What Metadata Applies
|
|
23857
|
+
|
|
23858
|
+
Use the \`list_page_types\` tool to enumerate all known page types and their declared \`metaSchema\` (fields that apply to children/descendants) and \`defaultMetaFields\` (renderer config fields on the page itself). It's the authoritative list of what meta keys make sense for any given page type.
|
|
23859
|
+
|
|
22915
23860
|
---
|
|
22916
23861
|
|
|
22917
23862
|
## Content Structure
|
|
@@ -22994,8 +23939,11 @@ Always clear fields when done by setting them to \`null\`.
|
|
|
22994
23939
|
| **Outline** | \`outline:editing\` | nodeId | Editing an outline node |
|
|
22995
23940
|
| **Gallery** | \`gallery:focused\` | itemId | Item hovered/selected |
|
|
22996
23941
|
| **Timeline** | \`timeline:focused\` | taskId | Task selected |
|
|
22997
|
-
| **Mindmap** | \`mindmap:focused\` | nodeId | Node selected/edited |
|
|
22998
23942
|
| **Graph** | \`graph:focused\` | nodeId | Node hovered/selected |
|
|
23943
|
+
| **Slides** | \`slides:current\` | slideId | Slide being presented |
|
|
23944
|
+
| **Spatial** | \`spatial:selected\`, \`spatial:camera\` | objectId / camera state | plugin |
|
|
23945
|
+
| **Media** | \`media:playing\`, \`media:position\` | trackId / 0–1 | plugin |
|
|
23946
|
+
| **Coder** | \`coder:activeFile\` | fileId | plugin |
|
|
22999
23947
|
| **Map** | \`map:focused\` | markerId | Marker hovered/selected |
|
|
23000
23948
|
| **Doc** | \`doc:scroll\` | 0–1 number | Scroll position in document |
|
|
23001
23949
|
|
|
@@ -23338,6 +24286,9 @@ var HookBridge = class {
|
|
|
23338
24286
|
}
|
|
23339
24287
|
routeEvent(payload) {
|
|
23340
24288
|
switch (payload.hook_event_name) {
|
|
24289
|
+
case "UserPromptSubmit":
|
|
24290
|
+
this.onUserPromptSubmit();
|
|
24291
|
+
break;
|
|
23341
24292
|
case "PreToolUse":
|
|
23342
24293
|
this.onPreToolUse(payload);
|
|
23343
24294
|
break;
|
|
@@ -23348,13 +24299,18 @@ var HookBridge = class {
|
|
|
23348
24299
|
this.onSubagentStart(payload);
|
|
23349
24300
|
break;
|
|
23350
24301
|
case "SubagentStop":
|
|
23351
|
-
this.onSubagentStop(
|
|
24302
|
+
this.onSubagentStop();
|
|
23352
24303
|
break;
|
|
23353
24304
|
case "Stop":
|
|
23354
24305
|
this.onStop();
|
|
23355
24306
|
break;
|
|
23356
24307
|
}
|
|
23357
24308
|
}
|
|
24309
|
+
/** New user turn — reset any lingering status/tool state from the previous turn. */
|
|
24310
|
+
onUserPromptSubmit() {
|
|
24311
|
+
this.server.setAutoStatus(null);
|
|
24312
|
+
this.server.setActiveToolCall(null);
|
|
24313
|
+
}
|
|
23358
24314
|
onPreToolUse(payload) {
|
|
23359
24315
|
const toolName = payload.tool_name ?? "";
|
|
23360
24316
|
if (toolName.startsWith("mcp__abracadabra__")) return;
|
|
@@ -23366,7 +24322,6 @@ var HookBridge = class {
|
|
|
23366
24322
|
}
|
|
23367
24323
|
onPostToolUse(payload) {
|
|
23368
24324
|
if ((payload.tool_name ?? "").startsWith("mcp__abracadabra__")) return;
|
|
23369
|
-
this.server.setAutoStatus("thinking");
|
|
23370
24325
|
}
|
|
23371
24326
|
onSubagentStart(payload) {
|
|
23372
24327
|
const agentType = payload.agent_type ?? "agent";
|
|
@@ -23376,9 +24331,7 @@ var HookBridge = class {
|
|
|
23376
24331
|
});
|
|
23377
24332
|
this.server.setAutoStatus("thinking");
|
|
23378
24333
|
}
|
|
23379
|
-
onSubagentStop(
|
|
23380
|
-
this.server.setAutoStatus("thinking");
|
|
23381
|
-
}
|
|
24334
|
+
onSubagentStop() {}
|
|
23382
24335
|
onStop() {
|
|
23383
24336
|
this.server.setAutoStatus(null);
|
|
23384
24337
|
this.server.setActiveToolCall(null);
|
|
@@ -23391,11 +24344,19 @@ var HookBridge = class {
|
|
|
23391
24344
|
* Abracadabra MCP Server — entry point.
|
|
23392
24345
|
*
|
|
23393
24346
|
* Environment variables:
|
|
23394
|
-
* ABRA_URL
|
|
24347
|
+
* ABRA_URL (required) — Server URL (e.g. http://localhost:1234)
|
|
23395
24348
|
* ABRA_AGENT_NAME — Display name (default: "AI Assistant")
|
|
23396
24349
|
* ABRA_AGENT_COLOR — HSL color for presence (default: "hsl(270, 80%, 60%)")
|
|
23397
24350
|
* ABRA_INVITE_CODE — Invite code for first-run registration (grants role)
|
|
23398
24351
|
* ABRA_KEY_FILE — Path to Ed25519 key file (default: ~/.abracadabra/agent.key)
|
|
24352
|
+
* ABRA_AGENT_TRIGGER_MODE — When to respond in group chats:
|
|
24353
|
+
* all → every message (legacy)
|
|
24354
|
+
* mention → only when @<alias> is used
|
|
24355
|
+
* task → only ai:task awareness events
|
|
24356
|
+
* mention+task → mention OR ai:task (default)
|
|
24357
|
+
* DMs always trigger regardless of mode.
|
|
24358
|
+
* ABRA_AGENT_MENTION_ALIASES — Comma-separated aliases for @mentions
|
|
24359
|
+
* (default: [ABRA_AGENT_NAME])
|
|
23399
24360
|
*/
|
|
23400
24361
|
async function main() {
|
|
23401
24362
|
const url = process.env.ABRA_URL;
|
|
@@ -23403,13 +24364,27 @@ async function main() {
|
|
|
23403
24364
|
console.error("Missing required environment variable: ABRA_URL");
|
|
23404
24365
|
process.exit(1);
|
|
23405
24366
|
}
|
|
24367
|
+
const rawMode = (process.env.ABRA_AGENT_TRIGGER_MODE ?? "mention+task").trim().toLowerCase();
|
|
24368
|
+
const validModes = [
|
|
24369
|
+
"all",
|
|
24370
|
+
"mention",
|
|
24371
|
+
"task",
|
|
24372
|
+
"mention+task"
|
|
24373
|
+
];
|
|
24374
|
+
const triggerMode = validModes.includes(rawMode) ? rawMode : "mention+task";
|
|
24375
|
+
if (rawMode && !validModes.includes(rawMode)) console.error(`[abracadabra-mcp] Invalid ABRA_AGENT_TRIGGER_MODE="${rawMode}", falling back to "mention+task"`);
|
|
24376
|
+
const aliasEnv = process.env.ABRA_AGENT_MENTION_ALIASES;
|
|
24377
|
+
const mentionAliases = aliasEnv ? aliasEnv.split(",").map((a) => a.trim()).filter((a) => a.length > 0) : void 0;
|
|
23406
24378
|
const server = new AbracadabraMCPServer({
|
|
23407
24379
|
url,
|
|
23408
24380
|
agentName: process.env.ABRA_AGENT_NAME,
|
|
23409
24381
|
agentColor: process.env.ABRA_AGENT_COLOR,
|
|
23410
24382
|
inviteCode: process.env.ABRA_INVITE_CODE,
|
|
23411
|
-
keyFile: process.env.ABRA_KEY_FILE
|
|
24383
|
+
keyFile: process.env.ABRA_KEY_FILE,
|
|
24384
|
+
triggerMode,
|
|
24385
|
+
mentionAliases
|
|
23412
24386
|
});
|
|
24387
|
+
console.error(`[abracadabra-mcp] Trigger mode: ${triggerMode}; aliases: ${server.mentionAliases.join(", ")}`);
|
|
23413
24388
|
const mcp = new McpServer({
|
|
23414
24389
|
name: "abracadabra",
|
|
23415
24390
|
version: "1.0.0"
|