@lambdacurry/arbor 0.24.34 → 0.24.35

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.
Files changed (2) hide show
  1. package/dist/arbor.js +141 -22
  2. package/package.json +1 -1
package/dist/arbor.js CHANGED
@@ -12025,6 +12025,46 @@ function buildOutputSchemas() {
12025
12025
  serializedByteLimit: number2().int().positive()
12026
12026
  })
12027
12027
  }),
12028
+ presence: discriminatedUnion("status", [
12029
+ object({ status: literal("absent") }).strict(),
12030
+ object({ status: literal("unavailable") }).strict(),
12031
+ looseObject({
12032
+ status: literal("present"),
12033
+ sessions: number2().int().positive(),
12034
+ pageId: string2().nullable(),
12035
+ viewport: jsonObject.nullable(),
12036
+ lastActiveAt: timestamp.nullable(),
12037
+ selection: looseObject({
12038
+ shapeIds: array(string2()),
12039
+ shapes: array(jsonObject),
12040
+ missingShapeIds: array(string2()),
12041
+ clusterIds: array(string2()),
12042
+ bounds: jsonObject.nullable()
12043
+ })
12044
+ })
12045
+ ]).optional(),
12046
+ comments: looseObject({
12047
+ items: array(looseObject({
12048
+ contributionId: id,
12049
+ url: string2(),
12050
+ author: jsonObject,
12051
+ createdAt: timestamp,
12052
+ text: string2(),
12053
+ anchor: jsonObject,
12054
+ replyCount: number2().int().nonnegative(),
12055
+ replies: array(jsonObject)
12056
+ })),
12057
+ total: number2().int().nonnegative(),
12058
+ omitted: number2().int().nonnegative()
12059
+ }).optional(),
12060
+ screenshot: looseObject({
12061
+ mimeType: literal("image/png"),
12062
+ width: number2().int().positive(),
12063
+ height: number2().int().positive(),
12064
+ bounds: jsonObject,
12065
+ shapeCount: number2().int().positive(),
12066
+ data: string2().optional()
12067
+ }).optional(),
12028
12068
  preview: tldrawLatestPreview
12029
12069
  }),
12030
12070
  tldraw_exec: looseObject({
@@ -13016,6 +13056,9 @@ var OUTPUT_SHAPERS = {
13016
13056
  ["documentClock", result.documentClock],
13017
13057
  ["documentDigest", result.documentDigest],
13018
13058
  ["scene", result.scene],
13059
+ ["presence", result.presence],
13060
+ ["comments", result.comments],
13061
+ ["screenshot", result.screenshot],
13019
13062
  ["preview", compactTldrawPreview(result.preview)]
13020
13063
  ]),
13021
13064
  computer_write: (result) => defined([
@@ -13294,12 +13337,37 @@ var shapeId = TLDRAW_SHAPE_ID_SCHEMA.describe("stable tldraw shape id, shape:…
13294
13337
  var shapeType = _enum(["geo", "text", "note", "frame", "arrow", "line", "draw", "group"]).describe("built-in tldraw shape type; use code mode for custom or asset-backed shapes");
13295
13338
  var finite = number2().finite();
13296
13339
  var jsonRecord = record(string2(), unknown());
13340
+ var diagramKey = string2().min(1).max(80).describe("caller-meaningful node key; returned as the alias for its generated tldraw shape id");
13341
+ var pageIdFilter = string2().min(1).max(200).describe("optional page id to search");
13342
+ var textRef = object({
13343
+ text: string2().min(1).max(500),
13344
+ match: _enum(["exact", "contains"]).optional().describe("exact (default, case/whitespace-insensitive) or contains"),
13345
+ type: string2().min(1).max(64).optional().describe("optional shape type filter"),
13346
+ pageId: pageIdFilter.optional()
13347
+ }).strict().describe("the one existing shape whose text matches");
13348
+ var descriptionRef = object({ description: string2().min(1).max(200), pageId: pageIdFilter.optional() }).strict().describe(`the one existing shape a description like 'the blue box labelled "API" in the top right' names (quoted label, kind, colour, region are strict filters)`);
13349
+ var selectedRef = object({ selected: literal(true) }).strict().describe("your one currently selected shape in an open board tab");
13350
+ var createdRef = object({
13351
+ created: union([literal("last"), number2().int().min(0).max(TLDRAW_EXEC_MAX_OPERATIONS)])
13352
+ }).strict().describe('a shape created earlier in this batch: "last" or its 0-based create index');
13353
+ var keyRef = object({ key: diagramKey }).strict().describe("a diagram node created earlier in this batch, by its key");
13354
+ var TLDRAW_SHAPE_REF_SCHEMA = union([shapeId, textRef, descriptionRef, selectedRef, createdRef, keyRef]).describe("shape id, or { text } | { description } | { selected: true } | { created } | { key }; resolved before any edit, ambiguity refuses");
13355
+ var shapeRef = TLDRAW_SHAPE_REF_SCHEMA;
13356
+ var selectedAllRef = object({ selected: literal("all") }).strict().describe("every currently selected shape in your open board tab");
13357
+ var shapeRefs = array(union([shapeId, textRef, descriptionRef, selectedRef, createdRef, keyRef, selectedAllRef])).min(1).max(TLDRAW_EXEC_MAX_OPERATIONS);
13358
+ var place = object({
13359
+ relativeTo: shapeRef.describe("the existing or earlier-created shape to place beside"),
13360
+ side: _enum(["right", "left", "above", "below"]),
13361
+ gap: finite.min(0).max(1e4).optional().describe("edge-to-edge gap; defaults to 40"),
13362
+ align: _enum(["start", "center", "end"]).optional().describe("cross-axis alignment with the target; defaults to center")
13363
+ }).strict().describe("place the new shape beside another instead of giving x/y");
13297
13364
  var create = object({
13298
13365
  op: literal("create"),
13299
13366
  id: shapeId,
13300
13367
  type: shapeType,
13301
- x: finite,
13302
- y: finite,
13368
+ x: finite.optional().describe("page x; omit only when place is given"),
13369
+ y: finite.optional().describe("page y; omit only when place is given"),
13370
+ place: place.optional(),
13303
13371
  parentId: string2().min(1).max(200).optional(),
13304
13372
  rotation: finite.optional(),
13305
13373
  opacity: finite.min(0).max(1).optional(),
@@ -13309,8 +13377,8 @@ var create = object({
13309
13377
  }).strict();
13310
13378
  var update = object({
13311
13379
  op: literal("update"),
13312
- id: shapeId,
13313
- type: shapeType,
13380
+ id: shapeRef,
13381
+ type: shapeType.optional().describe("optional; read from the resolved shape when omitted"),
13314
13382
  x: finite.optional(),
13315
13383
  y: finite.optional(),
13316
13384
  parentId: string2().min(1).max(200).optional(),
@@ -13320,20 +13388,18 @@ var update = object({
13320
13388
  props: jsonRecord.optional().describe("partial shape properties"),
13321
13389
  meta: jsonRecord.optional()
13322
13390
  }).strict();
13323
- var shapeIds = array(shapeId).min(1).max(TLDRAW_EXEC_MAX_OPERATIONS);
13324
- var diagramKey = string2().min(1).max(80).describe("caller-meaningful node key; returned as the alias for its generated tldraw shape id");
13325
13391
  var diagramLabel = string2().min(1).max(160);
13326
13392
  var stack = object({
13327
13393
  op: literal("stack"),
13328
- ids: shapeIds.min(2).describe("native shapes in the exact stack order; first id is the anchor"),
13394
+ ids: shapeRefs.describe("shapes in the exact stack order; the first is the anchor (at least 2)"),
13329
13395
  axis: _enum(["horizontal", "vertical"]),
13330
13396
  gap: finite.min(0).describe("required edge-to-edge gap between adjacent shapes"),
13331
13397
  alignment: _enum(["start", "center", "end"]).optional().describe("optional cross-axis alignment relative to the first shape")
13332
13398
  }).strict();
13333
13399
  var connect = object({
13334
13400
  op: literal("connect"),
13335
- sourceId: shapeId.describe("existing native shape to bind the arrow start to"),
13336
- targetId: shapeId.describe("existing native shape to bind the arrow end to")
13401
+ sourceId: shapeRef.describe("existing native shape to bind the arrow start to"),
13402
+ targetId: shapeRef.describe("existing native shape to bind the arrow end to")
13337
13403
  }).strict();
13338
13404
  var diagram = object({
13339
13405
  op: literal("diagram"),
@@ -13351,26 +13417,32 @@ var diagram = object({
13351
13417
  var TLDRAW_EXEC_OPERATION_SCHEMA = discriminatedUnion("op", [
13352
13418
  create,
13353
13419
  update,
13354
- object({ op: literal("delete"), ids: shapeIds }).strict(),
13420
+ object({ op: literal("delete"), ids: shapeRefs }).strict(),
13355
13421
  object({
13356
13422
  op: literal("align"),
13357
- ids: shapeIds.min(2),
13423
+ ids: shapeRefs.describe("at least 2 shapes"),
13358
13424
  alignment: _enum(["bottom", "center-horizontal", "center-vertical", "left", "right", "top"])
13359
13425
  }).strict(),
13360
13426
  object({
13361
13427
  op: literal("distribute"),
13362
- ids: shapeIds.min(3),
13428
+ ids: shapeRefs.describe("at least 3 shapes"),
13363
13429
  axis: _enum(["horizontal", "vertical"])
13364
13430
  }).strict(),
13365
13431
  object({
13366
13432
  op: literal("group"),
13367
- ids: shapeIds.min(2),
13433
+ ids: shapeRefs.describe("at least 2 shapes"),
13368
13434
  groupId: shapeId.optional()
13369
13435
  }).strict(),
13370
13436
  stack,
13371
13437
  connect,
13372
13438
  diagram
13373
13439
  ]);
13440
+ var MIN_REFERENCE_COUNT = {
13441
+ align: 2,
13442
+ distribute: 3,
13443
+ group: 2,
13444
+ stack: 2
13445
+ };
13374
13446
  var TLDRAW_EXEC_OPERATIONS_SCHEMA = array(TLDRAW_EXEC_OPERATION_SCHEMA).min(1).max(TLDRAW_EXEC_MAX_OPERATIONS).superRefine((operations, ctx) => {
13375
13447
  const createdIds = new Set;
13376
13448
  const diagramKeys = new Set;
@@ -13387,20 +13459,43 @@ var TLDRAW_EXEC_OPERATIONS_SCHEMA = array(TLDRAW_EXEC_OPERATION_SCHEMA).min(1).m
13387
13459
  }
13388
13460
  createdIds.add(operation.id);
13389
13461
  }
13462
+ if (operation.op === "create") {
13463
+ const hasPoint = operation.x !== undefined || operation.y !== undefined;
13464
+ if (operation.place ? hasPoint : operation.x === undefined || operation.y === undefined) {
13465
+ ctx.addIssue({
13466
+ code: "custom",
13467
+ message: "create needs both x and y, or place instead of x/y",
13468
+ path: [index, operation.place ? "place" : "x"]
13469
+ });
13470
+ }
13471
+ }
13390
13472
  if ("ids" in operation) {
13391
13473
  const seen = new Set;
13392
13474
  operation.ids.forEach((id, idIndex) => {
13393
- if (seen.has(id)) {
13475
+ const key = typeof id === "string" ? id : JSON.stringify(id);
13476
+ if (seen.has(key)) {
13394
13477
  ctx.addIssue({
13395
13478
  code: "custom",
13396
- message: `duplicate shape id: ${id}`,
13479
+ message: `duplicate shape reference: ${key}`,
13397
13480
  path: [index, "ids", idIndex]
13398
13481
  });
13399
13482
  }
13400
- seen.add(id);
13483
+ seen.add(key);
13401
13484
  });
13485
+ const minimum = MIN_REFERENCE_COUNT[operation.op] ?? 1;
13486
+ const expands = operation.ids.some((id) => typeof id === "object" && ("selected" in id) && id.selected === "all");
13487
+ if (!expands && operation.ids.length < minimum) {
13488
+ ctx.addIssue({
13489
+ code: "too_small",
13490
+ origin: "array",
13491
+ minimum,
13492
+ inclusive: true,
13493
+ message: `${operation.op} needs at least ${minimum} shapes`,
13494
+ path: [index, "ids"]
13495
+ });
13496
+ }
13402
13497
  }
13403
- if (operation.op === "connect" && operation.sourceId === operation.targetId) {
13498
+ if (operation.op === "connect" && canonicalJson(operation.sourceId) === canonicalJson(operation.targetId)) {
13404
13499
  ctx.addIssue({
13405
13500
  code: "custom",
13406
13501
  message: "connect self-loops are not supported",
@@ -13464,6 +13559,16 @@ var TLDRAW_EXEC_OPERATIONS_SCHEMA = array(TLDRAW_EXEC_OPERATION_SCHEMA).min(1).m
13464
13559
  }
13465
13560
  });
13466
13561
  }).describe("preferred declarative edits, applied in order; mutually exclusive with code");
13562
+ function canonicalJson(value) {
13563
+ if (Array.isArray(value)) {
13564
+ return `[${value.map((item) => item === undefined ? "null" : canonicalJson(item)).join(",")}]`;
13565
+ }
13566
+ if (value && typeof value === "object") {
13567
+ const entries = Object.entries(value).filter(([, item]) => item !== undefined).sort(([a], [b]) => a.localeCompare(b));
13568
+ return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${canonicalJson(item)}`).join(",")}}`;
13569
+ }
13570
+ return JSON.stringify(value) ?? "null";
13571
+ }
13467
13572
  // ../actions/src/index.ts
13468
13573
  var ARTIFACT_TYPE_DESCRIPTION = `semantic type (one of: ${ARTIFACT_TYPES.join(", ")})`;
13469
13574
  var ARBOR_FEEDBACK_INPUT_TYPES = [...ARBOR_FEEDBACK_TYPES, "friction"];
@@ -14106,7 +14211,14 @@ var ACTION_DEFINITIONS = [
14106
14211
  id: string2(),
14107
14212
  label: string2()
14108
14213
  })).optional().describe("inline @-mentions in the body; person mentions notify"),
14109
- links: array(object({ rel: _enum(CONTRIBUTION_ADD_LINK_RELS), targetId: string2() })).optional().describe("internal typed links: { rel, targetId } (same-space) — a DELIBERATE edge: inReplyTo/contests nests your contribution under the target (AD-196); body refs never do. External refs go IN THE BODY as URLs.")
14214
+ links: array(object({ rel: _enum(CONTRIBUTION_ADD_LINK_RELS), targetId: string2() })).optional().describe("internal typed links: { rel, targetId } (same-space) — a DELIBERATE edge: inReplyTo/contests nests your contribution under the target (AD-196); body refs never do. External refs go IN THE BODY as URLs."),
14215
+ anchor: object({
14216
+ artifactId: string2().describe("a tldraw board whose source Thread is this Thread"),
14217
+ shapeId: TLDRAW_SHAPE_ID_SCHEMA.optional(),
14218
+ pageId: string2().min(1).max(200).optional(),
14219
+ x: number2().finite().optional(),
14220
+ y: number2().finite().optional()
14221
+ }).strict().optional().describe("pin this contribution to a board as a comment: shapeId, or pageId + x/y page point; reply to one with links inReplyTo")
14110
14222
  },
14111
14223
  surfaces: ["mcp", "cli"],
14112
14224
  toolset: "loop",
@@ -16292,7 +16404,7 @@ var ACTION_DEFINITIONS = [
16292
16404
  {
16293
16405
  name: "tldraw_observe",
16294
16406
  title: "Observe a tldraw board",
16295
- description: `Read bounded scene/clock/digest/lint, scoped by shape ids or region; preview defaults to metadata, ensure reuses/renders latest PNG (renderInProgress: retry shortly); lint is advisory. MCP is links-only for viewing/downloading (model pixels vary by client); signedRead is 5-min/single-Attachment, never for posts; use permanent markdown; guide: ${AGENT_GUIDE_URLS.tldraw}.`,
16407
+ description: `Read bounded scene/clock/digest/lint with labelled clusters, your own open tab's presence, and anchored comments, scoped by ids, region, or clusterIds; screenshot renders just the scope inline; preview ensure reuses/renders the board PNG (renderInProgress: retry shortly). Preview is links-only; signedRead is 5-min, never for posts; guide: ${AGENT_GUIDE_URLS.tldraw}.`,
16296
16408
  inputSchema: {
16297
16409
  artifactId: string2().describe("the tldraw Artifact, art_…"),
16298
16410
  pageId: string2().min(1).max(200).optional().describe("optional page to observe"),
@@ -16303,6 +16415,13 @@ var ACTION_DEFINITIONS = [
16303
16415
  width: number2().finite().positive(),
16304
16416
  height: number2().finite().positive()
16305
16417
  }).optional().describe("optional page-coordinate rectangle; returns shapes whose page bounds intersect it, and combines with ids by intersection"),
16418
+ clusterIds: array(string2().regex(/^cluster:[0-9a-z]{1,13}(?:-\d{1,4})?$/)).min(1).max(50).refine((values) => new Set(values).size === values.length, "cluster ids must be unique").optional().describe("drill into these clusters from a prior observe (ids change when their shapes do); intersects with ids/region"),
16419
+ clusterCursor: string2().max(32).optional().describe("continue the cluster listing from a prior observe's scene.nextClusterCursor"),
16420
+ view: _enum(["full", "clusters"]).optional().describe("full (default) returns shapes; clusters returns only the cluster overview"),
16421
+ screenshot: object({
16422
+ maxWidth: number2().int().min(64).max(1536).optional(),
16423
+ maxHeight: number2().int().min(64).max(1536).optional()
16424
+ }).strict().optional().describe("render only the observed scope (clusterIds/ids/region, else the page) as a PNG fitting maxWidth×maxHeight (default 768); returned as image content"),
16306
16425
  viewportWidth: number2().int().min(320).max(1920).optional(),
16307
16426
  viewportHeight: number2().int().min(240).max(1080).optional(),
16308
16427
  preview: _enum(["metadata", "ensure"]).optional().describe("preview behavior; defaults to metadata, while ensure explicitly refreshes only when stale/missing")
@@ -16314,7 +16433,7 @@ var ACTION_DEFINITIONS = [
16314
16433
  {
16315
16434
  name: "tldraw_exec",
16316
16435
  title: "Run a one-shot tldraw program",
16317
- description: `Modify the current live tldraw board with preferred declarative operations or bounded JavaScript, including graph-scoped diagram layout, ordered exact-gap stack composition, and safe native bound connect without caller-supplied connector geometry, then return a durable execution receipt; use IDs from a fresh observe, reacquire this current schema after compaction, and never replay an unknown result. First use: read the tldraw guide at ${AGENT_GUIDE_URLS.tldraw}.`,
16436
+ description: `Modify the live tldraw board with preferred declarative operations or bounded JavaScript (diagram layout, exact-gap stack, native bound connect, create place); operations take shape ids or { text | description | selected | created | key } references resolved before any edit, and ambiguity refuses the batch. Returns a durable receipt; reacquire this schema after compaction and never replay an unknown result; first use: read the tldraw guide at ${AGENT_GUIDE_URLS.tldraw}.`,
16318
16437
  inputSchema: {
16319
16438
  artifactId: string2().describe("the tldraw Artifact, art_…"),
16320
16439
  code: string2().min(1).max(1e5).optional().describe("advanced script source; mutually exclusive with operations"),
@@ -16841,7 +16960,7 @@ var ACTIONS = ACTION_DEFINITIONS.map((action) => {
16841
16960
  });
16842
16961
 
16843
16962
  // ../actions/src/retention-entry.ts
16844
- var ARBOR_VERSION = "0.24.34";
16963
+ var ARBOR_VERSION = "0.24.35";
16845
16964
  var historyPolicySchema = _enum(["full", "checkpoint"]).optional().describe("text Artifacts: future history retention policy; full retains every source snapshot, checkpoint keeps metadata for every revision and source only when explicitly retained");
16846
16965
  var retainSourceSchema = boolean2().optional().describe("edit: in checkpoint mode, retain this newly minted content revision's source");
16847
16966
  var checkpointSchema = boolean2().optional().describe("edit: retain the exact current version source without incrementing content version");
@@ -17249,7 +17368,7 @@ function dispositionFilename(value) {
17249
17368
  // package.json
17250
17369
  var package_default = {
17251
17370
  name: "@lambdacurry/arbor",
17252
- version: "0.24.34",
17371
+ version: "0.24.35",
17253
17372
  description: "The Arbor CLI — a shared workspace for people and agents. The human + headless-agent write path over Arbor's guarded operation surface.",
17254
17373
  keywords: [
17255
17374
  "agents",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdacurry/arbor",
3
- "version": "0.24.34",
3
+ "version": "0.24.35",
4
4
  "description": "The Arbor CLI — a shared workspace for people and agents. The human + headless-agent write path over Arbor's guarded operation surface.",
5
5
  "keywords": [
6
6
  "agents",