@creator-notes/cnotes 0.74.0 → 0.76.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "creator-notes-cli",
3
- "version": "0.74.0",
3
+ "version": "0.76.0",
4
4
  "description": "CreatorNotes CLI: create notes, build canvases, search knowledge from the terminal",
5
5
  "author": {
6
6
  "name": "CreatorNotes",
@@ -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;AAiK5C,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAo2F7D"}
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"}
@@ -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("Add a note to a canvas")
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("Move a node to a new position on a canvas")
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({ success: true, nodeId: opts.node, positionX, positionY });
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);