@creator-notes/cnotes 0.74.0 → 0.75.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/.claude-plugin/plugin.json +1 -1
- package/dist/commands/canvas.d.ts.map +1 -1
- package/dist/commands/canvas.js +117 -4
- package/dist/commands/canvas.js.map +1 -1
- package/dist/lib/canvas-layout.d.ts +62 -0
- package/dist/lib/canvas-layout.d.ts.map +1 -0
- package/dist/lib/canvas-layout.js +129 -0
- package/dist/lib/canvas-layout.js.map +1 -0
- package/dist/mcp-server.js +23 -2
- package/dist/mcp-server.js.map +1 -1
- package/package.json +1 -1
- package/skills/cnotes/SKILL.md +13 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas.d.ts","sourceRoot":"","sources":["../../src/commands/canvas.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"canvas.d.ts","sourceRoot":"","sources":["../../src/commands/canvas.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAwL5C,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAq9F7D"}
|
package/dist/commands/canvas.js
CHANGED
|
@@ -10,6 +10,7 @@ import { outputJson, outputTable, outputQuiet, truncate, timeAgo, formatAgo } fr
|
|
|
10
10
|
import { readCanvasMarkdown, renderCanvasMarkdown, parseSharedCanvasLink, sameServerOrigin, readCanvasSection, renderCanvasSectionMarkdown, } from "../lib/canvas-read.js";
|
|
11
11
|
import { resolveAgentSession } from "../lib/claude-session.js";
|
|
12
12
|
import { WARN, dim } from "../lib/style.js";
|
|
13
|
+
import { findOverlaps, layoutItemsFrom, parseSize, resolveAnchor, suggestFreeSpot, } from "../lib/canvas-layout.js";
|
|
13
14
|
import { canvasUrl, canvasLinkForRef } from "../lib/urls.js";
|
|
14
15
|
import { canvasActionPath, commentsListPath, parseCommentStatus, } from "../lib/canvas-paths.js";
|
|
15
16
|
import { registerCanvasMilestoneCommands } from "./canvas-milestone.js";
|
|
@@ -66,6 +67,18 @@ function warnLayoutListMisuse(node) {
|
|
|
66
67
|
* below a growing frame that shifted down with it (or didn't, and why).
|
|
67
68
|
* Straddlers the grown frame ran over go to stderr like every layout warning.
|
|
68
69
|
*/
|
|
70
|
+
/**
|
|
71
|
+
* add-node / move-node take raw x/y with no packing. Say so on every use, and
|
|
72
|
+
* pass on the server's overlap lint when the box lands on something (a card
|
|
73
|
+
* dropped on a portal or a text block can't be clicked). stderr, so --json
|
|
74
|
+
* stdout stays parseable.
|
|
75
|
+
*/
|
|
76
|
+
function warnRawPlacement(data, verb) {
|
|
77
|
+
const warning = data?.layoutWarning;
|
|
78
|
+
if (warning?.message)
|
|
79
|
+
console.error(`${WARN} ${warning.message}`);
|
|
80
|
+
console.error(dim(`${verb} is low-level: raw x/y, no collision check. Prefer \`canvas place\` (new items, packed) or \`canvas arrange\` (reflow existing), and \`canvas status\` to see the layout first.`));
|
|
81
|
+
}
|
|
69
82
|
function printRippleSummary(ripple, dryRun = false) {
|
|
70
83
|
if (!ripple || typeof ripple !== "object")
|
|
71
84
|
return;
|
|
@@ -273,6 +286,11 @@ Examples:
|
|
|
273
286
|
.description("Get canvas details with nodes and edges")
|
|
274
287
|
.argument("<canvasId>", "Canvas ID")
|
|
275
288
|
.addHelpText("after", `
|
|
289
|
+
Positions: --json splits items by kind (nodes, richtextNodes, listNodes,
|
|
290
|
+
canvasLinkNodes for portals, sectionNodes). To check where things sit, read
|
|
291
|
+
allNodes instead: every kind in ONE list with x, y, width and height. Or run
|
|
292
|
+
\`cnotes canvas status <canvasId>\` for that list plus any overlaps.
|
|
293
|
+
|
|
276
294
|
Examples:
|
|
277
295
|
$ cnotes canvas get <canvasId> --json
|
|
278
296
|
`)
|
|
@@ -328,6 +346,87 @@ Examples:
|
|
|
328
346
|
console.log(` ${ln.id}: -> ${name} (${ln.positionX}, ${ln.positionY})`);
|
|
329
347
|
}
|
|
330
348
|
}
|
|
349
|
+
console.log(dim("\nEvery item with its box, and any overlaps: cnotes canvas status " + canvasId));
|
|
350
|
+
}
|
|
351
|
+
catch (error) {
|
|
352
|
+
handleError(error, cfg.json);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
canvas
|
|
356
|
+
.command("status")
|
|
357
|
+
.description("See a canvas's whole layout before you move anything: every item (cards, text, lists, portals, " +
|
|
358
|
+
"sections) as one list of rectangles, the items that overlap, and with --near a free spot next to an anchor.")
|
|
359
|
+
.argument("<canvasId>", "Canvas ID")
|
|
360
|
+
.option("--near <ref>", "Suggest a free spot next to this item (display id or node id) or point (x,y)")
|
|
361
|
+
.option("--size <WxH>", "Box to find room for with --near (default: a note card, 280x130)", "280x130")
|
|
362
|
+
.addHelpText("after", `
|
|
363
|
+
Sections are containers: they are listed, but a card inside one is not an
|
|
364
|
+
overlap. Read-only.
|
|
365
|
+
|
|
366
|
+
Examples:
|
|
367
|
+
$ cnotes canvas status CANVAS-361
|
|
368
|
+
$ cnotes canvas status CANVAS-361 --near DECISION-6KJ # where can this card go?
|
|
369
|
+
$ cnotes canvas status CANVAS-361 --near 900,100 --size 560x240 --json
|
|
370
|
+
`)
|
|
371
|
+
.action(async (canvasId, opts) => {
|
|
372
|
+
const cfg = resolveConfig(program.opts());
|
|
373
|
+
const api = new ApiClient(cfg.serverUrl, cfg.token);
|
|
374
|
+
try {
|
|
375
|
+
const size = parseSize(opts.size);
|
|
376
|
+
if (!size)
|
|
377
|
+
throw new ValidationError(`--size must look like 280x130 (got "${opts.size}")`);
|
|
378
|
+
const data = await api.get(`/api/canvas/${encodeURIComponent(canvasId)}`, {
|
|
379
|
+
workspaceId: cfg.workspaceId,
|
|
380
|
+
});
|
|
381
|
+
const items = layoutItemsFrom(data);
|
|
382
|
+
const overlaps = findOverlaps(items);
|
|
383
|
+
let freeSpot = null;
|
|
384
|
+
if (opts.near) {
|
|
385
|
+
const anchor = resolveAnchor(items, opts.near);
|
|
386
|
+
if (!anchor) {
|
|
387
|
+
throw new ValidationError(`No item "${opts.near}" on this canvas.`, "Pass a display id or node id from the list above, or a point as x,y.");
|
|
388
|
+
}
|
|
389
|
+
const spot = suggestFreeSpot(items, anchor, size);
|
|
390
|
+
if (spot)
|
|
391
|
+
freeSpot = { ...spot, ...size, near: opts.near };
|
|
392
|
+
}
|
|
393
|
+
if (cfg.json) {
|
|
394
|
+
outputJson({
|
|
395
|
+
items,
|
|
396
|
+
overlaps: overlaps.map((o) => ({ a: o.a.ref, b: o.b.ref, area: o.area })),
|
|
397
|
+
...(opts.near ? { freeSpot } : {}),
|
|
398
|
+
});
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const canvas = data.canvas;
|
|
402
|
+
console.log(`Canvas: ${canvas?.title ?? canvasId} · ${items.length} items`);
|
|
403
|
+
outputTable(["KIND", "REF", "LABEL", "X", "Y", "W", "H"], items.map((i) => [
|
|
404
|
+
i.kind,
|
|
405
|
+
truncate(i.ref, 28),
|
|
406
|
+
truncate(i.label, 36),
|
|
407
|
+
String(Math.round(i.x)),
|
|
408
|
+
String(Math.round(i.y)),
|
|
409
|
+
String(Math.round(i.width)),
|
|
410
|
+
String(Math.round(i.height)),
|
|
411
|
+
]));
|
|
412
|
+
if (overlaps.length === 0) {
|
|
413
|
+
console.log("\nNo overlaps.");
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
console.log(`\n${WARN} ${overlaps.length} overlap${overlaps.length === 1 ? "" : "s"} (one item covers the other):`);
|
|
417
|
+
for (const o of overlaps) {
|
|
418
|
+
console.log(` ${o.a.ref} (${o.a.kind}) × ${o.b.ref} (${o.b.kind}) ${o.area}px²`);
|
|
419
|
+
}
|
|
420
|
+
console.log(" Fix with `canvas arrange`, or move one to a free spot from `--near`.");
|
|
421
|
+
}
|
|
422
|
+
if (opts.near) {
|
|
423
|
+
if (freeSpot) {
|
|
424
|
+
console.log(`\nFree ${size.width}x${size.height} spot near ${opts.near}: x=${freeSpot.x} y=${freeSpot.y}`);
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
427
|
+
console.log(`\nNo free ${size.width}x${size.height} spot near ${opts.near}; try \`canvas place --placement auto\`.`);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
331
430
|
}
|
|
332
431
|
catch (error) {
|
|
333
432
|
handleError(error, cfg.json);
|
|
@@ -699,12 +798,17 @@ Examples:
|
|
|
699
798
|
});
|
|
700
799
|
canvas
|
|
701
800
|
.command("add-node")
|
|
702
|
-
.description("
|
|
801
|
+
.description("Low-level: add one note card at raw x/y, with no collision check. To put cards on a canvas, " +
|
|
802
|
+
"use `canvas place` (packs them overlap-free, --placement auto finds the space). Warns when the card lands on something.")
|
|
703
803
|
.argument("<canvasId>", "Canvas ID")
|
|
704
804
|
.requiredOption("--note <noteId>", "Note display ID or Convex ID")
|
|
705
805
|
.option("--x <n>", "X position", "100")
|
|
706
806
|
.option("--y <n>", "Y position", "100")
|
|
707
807
|
.addHelpText("after", `
|
|
808
|
+
Prefer \`canvas place\` for new cards. If you do pick x/y yourself, check the
|
|
809
|
+
spot first: \`cnotes canvas status <canvasId> --near <ref>\` lists every item's
|
|
810
|
+
box and suggests a free one.
|
|
811
|
+
|
|
708
812
|
Examples:
|
|
709
813
|
$ cnotes canvas add-node <canvasId> --note MEETING-12 --x 200 --y 300
|
|
710
814
|
`)
|
|
@@ -733,6 +837,7 @@ Examples:
|
|
|
733
837
|
if (link)
|
|
734
838
|
console.log(`Link: ${link}`);
|
|
735
839
|
}
|
|
840
|
+
warnRawPlacement(data, "add-node");
|
|
736
841
|
}
|
|
737
842
|
catch (error) {
|
|
738
843
|
handleError(error, cfg.json);
|
|
@@ -1900,7 +2005,8 @@ Examples:
|
|
|
1900
2005
|
});
|
|
1901
2006
|
canvas
|
|
1902
2007
|
.command("move-node")
|
|
1903
|
-
.description("
|
|
2008
|
+
.description("Low-level: move one node to raw x/y, with no collision check. To tidy or reflow a canvas, use " +
|
|
2009
|
+
"`canvas arrange`; to see what's where first, `canvas status`. Warns when the node lands on something.")
|
|
1904
2010
|
.argument("<canvasId>", "Canvas ID")
|
|
1905
2011
|
.requiredOption("--node <nodeId>", "Canvas node ID")
|
|
1906
2012
|
.requiredOption("--x <n>", "X position")
|
|
@@ -1913,7 +2019,7 @@ Examples:
|
|
|
1913
2019
|
try {
|
|
1914
2020
|
const positionX = Number(opts.x);
|
|
1915
2021
|
const positionY = Number(opts.y);
|
|
1916
|
-
await api.post(canvasActionPath(canvasId, cfg.workspaceId), {
|
|
2022
|
+
const data = await api.post(canvasActionPath(canvasId, cfg.workspaceId), {
|
|
1917
2023
|
action: "moveNode",
|
|
1918
2024
|
nodeId: opts.node,
|
|
1919
2025
|
nodeType: opts.type,
|
|
@@ -1921,11 +2027,18 @@ Examples:
|
|
|
1921
2027
|
positionY,
|
|
1922
2028
|
});
|
|
1923
2029
|
if (cfg.json) {
|
|
1924
|
-
outputJson({
|
|
2030
|
+
outputJson({
|
|
2031
|
+
success: true,
|
|
2032
|
+
nodeId: opts.node,
|
|
2033
|
+
positionX,
|
|
2034
|
+
positionY,
|
|
2035
|
+
...(data?.layoutWarning ? { layoutWarning: data.layoutWarning } : {}),
|
|
2036
|
+
});
|
|
1925
2037
|
}
|
|
1926
2038
|
else {
|
|
1927
2039
|
console.log(`Moved node ${opts.node} to (${positionX}, ${positionY})`);
|
|
1928
2040
|
}
|
|
2041
|
+
warnRawPlacement(data, "move-node");
|
|
1929
2042
|
}
|
|
1930
2043
|
catch (error) {
|
|
1931
2044
|
handleError(error, cfg.json);
|