@lambdacurry/arbor 0.24.3 → 0.24.5

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 +78 -60
  2. package/package.json +2 -3
package/dist/arbor.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // package.json
3
3
  var package_default = {
4
4
  name: "@lambdacurry/arbor",
5
- version: "0.24.3",
5
+ version: "0.24.5",
6
6
  description: "The Arbor CLI — a shared workspace for people and agents. The human + headless-agent write path over Arbor's guarded operation surface.",
7
7
  keywords: [
8
8
  "agents",
@@ -29,7 +29,7 @@ var package_default = {
29
29
  access: "public"
30
30
  },
31
31
  scripts: {
32
- arbor: "tsx src/bin.ts",
32
+ arbor: "vpx src/bin.ts",
33
33
  build: "bun build ./src/bin.ts --target=node --outfile=dist/arbor.js",
34
34
  test: "vp test run --passWithNoTests",
35
35
  typecheck: "tsc -b",
@@ -40,7 +40,6 @@ var package_default = {
40
40
  "@arbor/core": "workspace:*",
41
41
  "@types/node": "^26.2.0",
42
42
  "just-bash": "3.4.2",
43
- tsx: "^4.20.6",
44
43
  typescript: "^5.8.0",
45
44
  "vite-plus": "catalog:",
46
45
  zod: "^4.4.3"
@@ -6580,10 +6579,20 @@ var spaces = sqliteTable("spaces", {
6580
6579
  defaultReviewDimensions: text("default_review_dimensions", { mode: "json" }).$type().notNull().default([]),
6581
6580
  stage: text("stage").$type().notNull().default("exploration"),
6582
6581
  systemKind: text("system_kind"),
6582
+ key: text("key"),
6583
6583
  createdAt: ts("created_at").notNull()
6584
6584
  }, (t) => ({
6585
6585
  orgIdx: index("spaces_org_idx").on(t.orgId),
6586
- systemKindUq: uniqueIndex("spaces_system_kind_uq").on(t.systemKind)
6586
+ systemKindUq: uniqueIndex("spaces_system_kind_uq").on(t.systemKind),
6587
+ orgKeyUq: uniqueIndex("spaces_org_key_uq").on(t.orgId, t.key)
6588
+ }));
6589
+ var spaceRetiredKeys = sqliteTable("space_retired_keys", {
6590
+ orgId: text("org_id").notNull().references(() => orgs.id),
6591
+ key: text("key").notNull(),
6592
+ spaceId: text("space_id").notNull().references(() => spaces.id),
6593
+ retiredAt: ts("retired_at").notNull()
6594
+ }, (t) => ({
6595
+ orgKeyUq: uniqueIndex("space_retired_keys_org_key_uq").on(t.orgId, t.key)
6587
6596
  }));
6588
6597
  var spaceMemberships = sqliteTable("space_memberships", {
6589
6598
  id: text("id").primaryKey(),
@@ -6713,8 +6722,10 @@ var threads = sqliteTable("threads", {
6713
6722
  waysToHelp: text("ways_to_help", { mode: "json" }).$type().notNull().default([]),
6714
6723
  openQuestions: text("open_questions", { mode: "json" }).$type().notNull().default([]),
6715
6724
  expectedOutput: text("expected_output").notNull().default(""),
6725
+ number: integer2("number"),
6716
6726
  createdAt: ts("created_at").notNull()
6717
6727
  }, (t) => ({
6728
+ spaceNumberUq: uniqueIndex("threads_space_number_uq").on(t.spaceId, t.number),
6718
6729
  topicIdx: index("threads_topic_idx").on(t.topicId),
6719
6730
  spaceIdx: index("threads_space_idx").on(t.spaceId),
6720
6731
  lifecycleTypeIdx: index("threads_lifecycle_type_idx").on(t.lifecycleType),
@@ -8218,6 +8229,36 @@ var ORG_ADMIN_CONTAINMENT_PERMISSIONS = new Set([
8218
8229
  "revoke"
8219
8230
  ]);
8220
8231
 
8232
+ // ../core/src/queries/artifact-base.ts
8233
+ var eventChronology = sql`_rowid_`;
8234
+ var SPACE_ARTIFACT_STATUSES = [
8235
+ "draft",
8236
+ "proposed",
8237
+ "active",
8238
+ "promoted",
8239
+ "needs-review",
8240
+ "superseded",
8241
+ "deprecated",
8242
+ "archived"
8243
+ ];
8244
+ var artifactUpdatedAt = sql`coalesce((select max(${events.createdAt}) from ${events} where ${events.objectType} = 'artifact' and ${events.objectId} = ${artifacts.id}), ${artifacts.createdAt})`;
8245
+ // ../core/src/queries/thread-assignment.ts
8246
+ var assigneeColumns = {
8247
+ threadId: threadAssignments.threadId,
8248
+ assignedAt: threadAssignments.createdAt,
8249
+ assignedByProfileId: threadAssignments.assignedByProfileId,
8250
+ id: profiles.id,
8251
+ kind: profiles.kind,
8252
+ displayName: profiles.displayName,
8253
+ color: profiles.color,
8254
+ emoji: profiles.emoji
8255
+ };
8256
+ var lastActivityExpr = sql`coalesce(
8257
+ (select max(${contributions.createdAt}) from ${contributions}
8258
+ where ${contributions.threadId} = ${threads.id}),
8259
+ ${threads.createdAt}
8260
+ )`;
8261
+
8221
8262
  // ../core/src/ops/space.ts
8222
8263
  var GUIDANCE_LIMITS = {
8223
8264
  maxItems: 12,
@@ -8244,6 +8285,7 @@ var OPERATION_LOSS_REASONS = new Set([
8244
8285
 
8245
8286
  // ../core/src/ops/computer-run-retention.ts
8246
8287
  var COMPUTER_RUN_RETENTION_WARNING_MS = 24 * 60 * 60 * 1000;
8288
+ var COMPUTER_RUN_SUSPENDED_EXPIRY_MS = 24 * 60 * 60 * 1000;
8247
8289
 
8248
8290
  // ../core/src/ops/computer-run.ts
8249
8291
  var COMPUTER_RUN_START_CHECKPOINT_RESERVATION_STALE_MS = 12 * 60 * 1000;
@@ -8290,20 +8332,6 @@ var COMPUTER_WORKSPACE_RECOVERY_ATTACH_DEADLINE_MS = 31 * 60 * 1000;
8290
8332
  var COMPUTER_WORKSPACE_RECOVERY_HEALTH_DEADLINE_MS = 2 * 60 * 1000;
8291
8333
  var COMPUTER_WORKSPACE_RECOVERY_HEADROOM_MS = 2 * 60 * 1000;
8292
8334
  var COMPUTER_WORKSPACE_RECOVERY_LEASE_MS = COMPUTER_WORKSPACE_RECOVERY_CHECKPOINT_DEADLINE_MS + COMPUTER_WORKSPACE_RECOVERY_ATTACH_DEADLINE_MS + COMPUTER_WORKSPACE_RECOVERY_HEALTH_DEADLINE_MS + COMPUTER_WORKSPACE_RECOVERY_HEADROOM_MS;
8293
-
8294
- // ../core/src/queries/artifact-base.ts
8295
- var eventChronology = sql`_rowid_`;
8296
- var SPACE_ARTIFACT_STATUSES = [
8297
- "draft",
8298
- "proposed",
8299
- "active",
8300
- "promoted",
8301
- "needs-review",
8302
- "superseded",
8303
- "deprecated",
8304
- "archived"
8305
- ];
8306
- var artifactUpdatedAt = sql`coalesce((select max(${events.createdAt}) from ${events} where ${events.objectType} = 'artifact' and ${events.objectId} = ${artifacts.id}), ${artifacts.createdAt})`;
8307
8335
  // ../core/src/ops/artifact-git-intent.ts
8308
8336
  var RETRYABLE_REPAIR = new Set([
8309
8337
  "pending_push_unconfirmed",
@@ -8321,22 +8349,6 @@ var EMOJI_RE = new RegExp("^\\p{RGI_Emoji}$", "v");
8321
8349
  var BASE_MS = Date.parse("2026-07-20T15:00:00.000Z");
8322
8350
  // ../core/src/ops/agent-pairing.ts
8323
8351
  var PAIRING_TTL_MS = 15 * 60 * 1000;
8324
- // ../core/src/queries/thread-assignment.ts
8325
- var assigneeColumns = {
8326
- threadId: threadAssignments.threadId,
8327
- assignedAt: threadAssignments.createdAt,
8328
- assignedByProfileId: threadAssignments.assignedByProfileId,
8329
- id: profiles.id,
8330
- kind: profiles.kind,
8331
- displayName: profiles.displayName,
8332
- color: profiles.color,
8333
- emoji: profiles.emoji
8334
- };
8335
- var lastActivityExpr = sql`coalesce(
8336
- (select max(${contributions.createdAt}) from ${contributions}
8337
- where ${contributions.threadId} = ${threads.id}),
8338
- ${threads.createdAt}
8339
- )`;
8340
8352
  // ../core/src/ops/package-cache.ts
8341
8353
  var PACKAGE_CACHE_PENDING_TTL_MS = 15 * 60 * 1000;
8342
8354
  var PACKAGE_CACHE_FINAL_TTL_MS = 30 * 24 * 60 * 60 * 1000;
@@ -8510,6 +8522,7 @@ var recallHit = looseObject({
8510
8522
  excerpt: string2(),
8511
8523
  space: spaceRef.nullable(),
8512
8524
  threadId: nullableString,
8525
+ shortId: nullableString.optional(),
8513
8526
  url: nullableString,
8514
8527
  createdAt: timestamp
8515
8528
  });
@@ -8995,6 +9008,7 @@ var orgMember = looseObject({
8995
9008
  });
8996
9009
  var thread3 = looseObject({
8997
9010
  id,
9011
+ shortId: nullableString.optional(),
8998
9012
  title: string2(),
8999
9013
  objective: string2(),
9000
9014
  status: string2().optional(),
@@ -9033,6 +9047,7 @@ var topic2 = looseObject({
9033
9047
  var space3 = looseObject({
9034
9048
  id,
9035
9049
  title: string2(),
9050
+ key: nullableString.optional(),
9036
9051
  purpose: nullableString.optional(),
9037
9052
  stage: string2().optional(),
9038
9053
  url: string2().optional()
@@ -11161,6 +11176,7 @@ var TLDRAW_EXEC_OPERATIONS_SCHEMA = array(TLDRAW_EXEC_OPERATION_SCHEMA).min(1).m
11161
11176
  // ../actions/src/index.ts
11162
11177
  var ARTIFACT_TYPE_DESCRIPTION = `semantic type (one of: ${ARTIFACT_TYPES.join(", ")})`;
11163
11178
  var ARBOR_FEEDBACK_INPUT_TYPES = [...ARBOR_FEEDBACK_TYPES, "friction"];
11179
+ var SPACE_KEY_INPUT = string2().min(1).refine((key) => key.trim().length > 0, "space key cannot be blank");
11164
11180
  var CONTRIBUTION_ADD_LINK_RELS = [
11165
11181
  "cites",
11166
11182
  "contests",
@@ -11747,7 +11763,7 @@ var ACTION_DEFINITIONS = [
11747
11763
  title: "Contribute to a thread",
11748
11764
  description: "Add one additive point to a Thread; use stamp for agreement, respond/mark_as_response for requests, and links for deliberate reply/contest edges. Pass idempotencyKey (CLI: --idempotency-key) for safe retries.",
11749
11765
  inputSchema: {
11750
- threadId: string2().describe("the thread id, e.g. thr_…"),
11766
+ threadId: string2().describe("the thread id, e.g. thr_…, or its short id, e.g. BUD-34"),
11751
11767
  type: _enum(CONTRIBUTION_TYPES).describe("the contribution type (AD-066 taxonomy)"),
11752
11768
  body: string2().min(1).describe(`the contribution markdown. ${CONTRIBUTION_BODY_GUIDANCE}`),
11753
11769
  idempotencyKey: string2().min(1).max(200).optional().describe("stable key for this ONE logical contribution (≤200 chars), e.g. cron-run/work-item + output slot; safe retries return the original contribution. Reusing it with different content is a conflict."),
@@ -11906,7 +11922,7 @@ var ACTION_DEFINITIONS = [
11906
11922
  title: "Edit a thread's title, objective, or topic",
11907
11923
  description: "Correct a Thread's title or objective, or move it under another Topic of the same Space, patching only supplied fields; use it to make done clear or refile misfiled work instead of archiving and reopening. Status moves stay with `transition_thread`, column order with `--rank`, and the temporary help list with `charter` ways_to_help.",
11908
11924
  inputSchema: {
11909
- threadId: string2().describe("the thread to edit, thr_…"),
11925
+ threadId: string2().describe("the thread to edit, thr_… or a short id like BUD-34"),
11910
11926
  title: string2().min(1).optional().describe("a new title — the question, outcome, investigation, instance, or standing concern"),
11911
11927
  objective: string2().min(1).optional().describe("a new objective — what this Thread should accomplish; for finite work, what done means"),
11912
11928
  topicId: string2().optional().describe("move the thread under this topic of the same space, top_…"),
@@ -11922,7 +11938,7 @@ var ACTION_DEFINITIONS = [
11922
11938
  description: "Make a Space member (yourself when profileId is omitted) responsible for moving a Thread, or remove that responsibility; assignment is immediate, idempotent, grants no permissions, and creates no Inbox item — a specific owed action is still a `request`. Assignees stay attached through every lifecycle move, so transfer responsibility by assigning the new owner and unassigning the old.",
11923
11939
  inputSchema: {
11924
11940
  verb: _enum(["assign", "unassign"]).describe("add or remove responsibility"),
11925
- threadId: string2().describe("the thread, thr_…"),
11941
+ threadId: string2().describe("the thread, thr_… or a short id like BUD-34"),
11926
11942
  profileId: string2().optional().describe("the member to (un)assign, prof_…; omit for yourself")
11927
11943
  },
11928
11944
  surfaces: ["mcp", "cli"],
@@ -12023,7 +12039,7 @@ var ACTION_DEFINITIONS = [
12023
12039
  title: "Replace a Thread computer override",
12024
12040
  description: "DESTRUCTIVE REPLACE: Replace this Thread's entire sparse Computer override; omitted fields are cleared from the Thread layer and inherit Topic/Space/organization policy. This is config only and allocates no runtime; an existing Computer cannot switch provider, and repeating the same full layer is idempotent.",
12025
12041
  inputSchema: {
12026
- threadId: string2().describe("the Thread, thr_…"),
12042
+ threadId: string2().describe("the Thread, thr_… or a short id like BUD-34"),
12027
12043
  backend: _enum(["worker-shell", "container"]).nullable().optional().describe("override execution tier, or null to inherit"),
12028
12044
  containerProfile: string2().nullable().optional().describe("logical container profile; bun-typescript-v1 guarantees Bash, Git, GitHub CLI (gh), Bun 1.4.2, bunx, Node 26.5.1, pnpm 10.33.0, Python 3.13.15 (python/python3), jq, and ripgrep (rg), or null to clear inherited profile"),
12029
12045
  setupScript: string2().nullable().optional().describe("optional strict Bash setup for a fresh base after repositories materialize; install scoped tools in /workspace/.local/bin so exec finds them and snapshots retain them"),
@@ -12039,7 +12055,7 @@ var ACTION_DEFINITIONS = [
12039
12055
  title: "Attach a Thread computer",
12040
12056
  description: "Deprecated by AD-306: computer_run_start(threadId) attaches durable identity itself, so use this only to mint protocol identity with no Run at all. Creates or reuses the Thread's stable Computer identity and an immutable collaborator receipt without starting provider runtime.",
12041
12057
  inputSchema: {
12042
- threadId: string2().describe("the Thread whose computer you are attaching, thr_…")
12058
+ threadId: string2().describe("the Thread whose computer you are attaching, thr_… or a short id like BUD-34")
12043
12059
  },
12044
12060
  surfaces: ["cli"],
12045
12061
  toolset: "loop",
@@ -12050,7 +12066,7 @@ var ACTION_DEFINITIONS = [
12050
12066
  title: "Open a Thread computer",
12051
12067
  description: "Deprecated by AD-306: start work with computer_run_start(threadId, mode) instead; this alias remains one release and boots the parent Thread Computer, returning a computerSessionId. An optional owned active runId records a successful session attach as Run retention activity. Use it only for a legacy client that still addresses the parent by cms_ id; unsafe recovery is refused and unresolved newer workspace state stays fail-closed.",
12052
12068
  inputSchema: {
12053
- threadId: string2().describe("the Arbor Thread whose stable computer to open, thr_…"),
12069
+ threadId: string2().describe("the Arbor Thread whose stable computer to open, thr_… or a short id like BUD-34"),
12054
12070
  runId: string2().optional().describe("optional owned active Run; successful open renews its retention deadline"),
12055
12071
  idempotencyKey: string2().trim().min(1).max(200).optional().describe("optional explicit key for ONE distinct logical open; omission reuses the durable profile/Thread/recipe identity; changed options require a distinct intent; retry unchanged after response loss and never mint a new key to bypass unresolved work"),
12056
12072
  vcpus: number2().int().min(1).max(4).optional().describe("optional container vCPU request"),
@@ -12065,7 +12081,7 @@ var ACTION_DEFINITIONS = [
12065
12081
  title: "Replace a Thread computer",
12066
12082
  description: "DESTRUCTIVE RECOVERY: Replace an incompatible active Computer generation from the Thread's effective recipe when Arbor reports structural recipe incompatibility. Preserves the old generation unless the successor restores supported state and passes health.",
12067
12083
  inputSchema: {
12068
- threadId: string2().describe("the Thread whose active Computer generation is replaced, thr_…"),
12084
+ threadId: string2().describe("the Thread whose active Computer generation is replaced, thr_… or a short id like BUD-34"),
12069
12085
  idempotencyKey: string2().min(1).max(200).describe("stable key for this ONE replacement request; reuse it unchanged for retries"),
12070
12086
  reason: string2().min(1).max(500).describe("concise auditable reason for replacing the active generation")
12071
12087
  },
@@ -12078,7 +12094,7 @@ var ACTION_DEFINITIONS = [
12078
12094
  title: "Start a run",
12079
12095
  description: `Start an isolated write Run or shared/read Run with one idempotencyKey; pending admission returns runStartId for receipt observation while the lifecycle owner continues independently. Save work outside the temporary Computer and finish the Run when done; first use: read the Computer guide at ${AGENT_GUIDE_URLS.computer}.`,
12080
12096
  inputSchema: {
12081
- threadId: string2().optional().describe("the Thread whose Computer this Run works in, thr_…; the canonical Run-first front door"),
12097
+ threadId: string2().optional().describe("the Thread whose Computer this Run works in, thr_… or a short id like BUD-34; the canonical Run-first front door"),
12082
12098
  computerSessionId: string2().optional().describe("legacy compatibility alternative to threadId: an existing parent computerSessionId, cms_…"),
12083
12099
  mode: _enum(["read", "write"]).describe("write for mutable work; read for shared inspection"),
12084
12100
  execution: _enum(["shared", "isolated"]).optional().describe("write Run placement; defaults to isolated. Use shared only for intentional live collaboration on the Thread Computer"),
@@ -12096,7 +12112,7 @@ var ACTION_DEFINITIONS = [
12096
12112
  {
12097
12113
  name: "computer_run_suspend",
12098
12114
  title: "Suspend a run",
12099
- description: "Checkpoint an active WRITE Run for an external wait: save or publish needed work outside the Computer first; shared Runs checkpoint the parent without releasing it, while isolated Runs publish their exact workspace and release the Sandbox; resume with the same runId. Unread terminal output is retained for 30 days; no drain required; active/unknown work or failed preservation blocks release.",
12115
+ description: "Checkpoint an active WRITE Run for an external wait after saving needed work outside the Computer; shared Runs checkpoint the parent, isolated Runs publish their exact workspace and release the Sandbox; resume with the same runId within 24h or an unkept isolated Run ends. Unread terminal output is retained for 30 days; no drain required; active/unknown work or failed preservation blocks release.",
12100
12116
  inputSchema: {
12101
12117
  runId: string2().describe("the active WRITE Run to suspend, run_…")
12102
12118
  },
@@ -12144,7 +12160,7 @@ var ACTION_DEFINITIONS = [
12144
12160
  {
12145
12161
  name: "computer_run_retention",
12146
12162
  title: "Inspect Run retention",
12147
- description: "Report the deadline, last meaningful use, Keep flag, and advisory warning for one isolated Run. Expiry is disabled; this read sends no warning and releases nothing.",
12163
+ description: "Report the deadline, last meaningful use, Keep flag, and advisory warning for one isolated Run; a suspended Run is due 24 hours after it suspended. This read sends no warning and releases nothing.",
12148
12164
  inputSchema: {
12149
12165
  runId: string2().describe("the Run to inspect, run_…")
12150
12166
  },
@@ -12155,7 +12171,7 @@ var ACTION_DEFINITIONS = [
12155
12171
  {
12156
12172
  name: "computer_run_keep",
12157
12173
  title: "Keep Run data",
12158
- description: "The Run owner or an organization admin can set or clear Keep for a newly created isolated Run, using expectedRevision to guard races. It protects restorable Run data without keeping provider compute alive; expiry remains disabled.",
12174
+ description: "The Run owner or an organization admin can set or clear Keep for a newly created isolated Run, using expectedRevision to guard races. It protects restorable Run data without keeping provider compute alive; Keep stops a suspended Run from ending on its own after 24 hours.",
12159
12175
  inputSchema: {
12160
12176
  runId: string2().describe("the Run to protect, run_…"),
12161
12177
  keep: boolean2().describe("true to retain the Run's restorable data; false to resume the policy"),
@@ -12260,7 +12276,7 @@ var ACTION_DEFINITIONS = [
12260
12276
  title: "Capture public visual evidence",
12261
12277
  description: "Capture a 1280×720 screenshot of one public HTTPS URL as Thread evidence without opening the project runtime. Returns capture metadata plus ready-to-place attachments[].markdown; put that Markdown exactly where the image belongs and bind the matching attachmentIds, while localhost and authenticated pages remain unavailable and the capture does not judge correctness.",
12262
12278
  inputSchema: {
12263
- threadId: string2().describe("the Arbor Thread that will own the evidence, thr_…"),
12279
+ threadId: string2().describe("the Arbor Thread that will own the evidence, thr_… or a short id like BUD-34"),
12264
12280
  targetUrl: url().refine((value) => value.startsWith("https://"), "targetUrl must use HTTPS").describe("one public HTTPS URL to capture")
12265
12281
  },
12266
12282
  surfaces: ["computer-mcp", "computer-cli"],
@@ -12544,7 +12560,7 @@ var ACTION_DEFINITIONS = [
12544
12560
  title: "Read a Thread computer",
12545
12561
  description: "Inspect a Thread's provider-free durable Computer recipe/materialization state, compatibility, recoverySafety, lineage, recent receipts, Runs, and reprovision outcomes; setup content and credentials stay redacted. This read never contacts execution; use computer_status for live readiness.",
12546
12562
  inputSchema: {
12547
- threadId: string2().describe("the Thread, thr_…"),
12563
+ threadId: string2().describe("the Thread, thr_… or a short id like BUD-34"),
12548
12564
  lineageLimit: number2().int().min(1).max(100).optional().describe("recent receipts/lineage rows (default 20)")
12549
12565
  },
12550
12566
  surfaces: ["computer-mcp", "cli"],
@@ -12581,7 +12597,7 @@ var ACTION_DEFINITIONS = [
12581
12597
  title: "Set a thread's ways to help",
12582
12598
  description: "Set a thread's READ-ONLY 'ways to help' (AD-038) — a short, curated list of perspectives, skills, or concrete tasks orienting someone on how they could pitch in with THIS thread as it stands (e.g. 'a benchmark on cold-start latency'). It is thread-local and temporary: it is read inside `thread_get`, and it never rolls up into a space/topic orientation surface — a standing statement about what a room wants is the room's standing ways to help (`contributionLanes`, via `set_space_lanes`/`set_topic_lanes`, AD-222). Guidance you READ, NOT an obligation — that's `request`. Replaces the whole list; pass [] to clear.",
12583
12599
  inputSchema: {
12584
- threadId: string2().describe("the thread, thr_…"),
12600
+ threadId: string2().describe("the thread, thr_… or a short id like BUD-34"),
12585
12601
  waysToHelp: proseList("the full ways-to-help list — replaces the existing one; [] clears it")
12586
12602
  },
12587
12603
  surfaces: ["cli"],
@@ -12593,7 +12609,7 @@ var ACTION_DEFINITIONS = [
12593
12609
  title: "Move a thread's lifecycle",
12594
12610
  description: transitionThreadActionDescription(),
12595
12611
  inputSchema: {
12596
- threadId: string2().describe("the thread to move, thr_…"),
12612
+ threadId: string2().describe("the thread to move, thr_… or a short id like BUD-34"),
12597
12613
  to: string2().min(1).describe("label key, case-insensitive label name, or bare type (`resolved` still works as a type name)"),
12598
12614
  reason: string2().optional().describe("optional one-line why, recorded on the event"),
12599
12615
  rank: string2().max(THREAD_RANK_MAX).regex(THREAD_RANK_PATTERN).nullable().optional().describe("LexoRank in the destination column; omit to leave unchanged, null to restore recency. Combined with `--to` this is one atomic write — a bad rank moves nothing")
@@ -12679,7 +12695,7 @@ var ACTION_DEFINITIONS = [
12679
12695
  description: "Bind one Artifact to an existing same-Space Thread Live Preview, making the Artifact the durable entry point for that executable surface. Omit --thread-id to clear the binding; this changes no Artifact source/version and does not create or reconfigure a Computer.",
12680
12696
  inputSchema: {
12681
12697
  artifactId: string2().describe("the Artifact, art_…"),
12682
- threadId: string2().optional().describe("the configured Thread Live Preview to bind, thr_…; omit to clear")
12698
+ threadId: string2().optional().describe("the configured Thread Live Preview to bind, thr_… or a short id like BUD-34; omit to clear")
12683
12699
  },
12684
12700
  surfaces: ["cli"],
12685
12701
  toolset: "artifacts",
@@ -12759,7 +12775,7 @@ var ACTION_DEFINITIONS = [
12759
12775
  title: "Request a contribution or review",
12760
12776
  description: "Request a contribution or review on a Thread: omit aboutContributionId for a contribution answered via respond, or pass it for a review answered only by stamp; explicitly target yourself for a normal Inbox obligation, target other people, or leave it open. Choose completion/deadline and optionally opensAt/opensIn to keep it dormant until scheduled delivery; fulfill a self-target through respond or use cancel_request to retire it.",
12761
12777
  inputSchema: {
12762
- threadId: string2().describe("the thread the request is in, thr_…"),
12778
+ threadId: string2().describe("the thread the request is in, thr_… or a short id like BUD-34"),
12763
12779
  requestedAction: string2().optional().describe("a one-line 'what you're requesting'"),
12764
12780
  requestedType: _enum(CONTRIBUTION_TYPES).optional().describe("the contribution type you're HOPING for (e.g. evidence, decision) — a soft default on the responder's picker, never a constraint; omit for 'any contribution welcome'. Contribution asks only"),
12765
12781
  aboutContributionId: string2().optional().describe("PASS to request a REVIEW of this contribution (con_…, in the thread; met by a stamp, badges that card). OMIT to request a CONTRIBUTION on the thread (met by a respond)."),
@@ -12920,7 +12936,7 @@ var ACTION_DEFINITIONS = [
12920
12936
  title: "Read a thread",
12921
12937
  description: "Read one Thread as compact current context (distillate, requests, artifacts, recent tail, cursored unchanged checks) — not the durable transcript; pass view=full to read contribution bodies and attachments (including Markdown and authenticated URLs) and page history (contribLimit default 50) or all=true for the complete transcript. Read it before contributing so you can answer open requests correctly.",
12922
12938
  inputSchema: {
12923
- threadId: string2().describe("the thread id, e.g. thr_…"),
12939
+ threadId: string2().describe("the thread id, e.g. thr_…, or its short id, e.g. BUD-34"),
12924
12940
  view: _enum(["full", "compact"]).optional().describe("MCP/CLI/API default compact = bounded decision-ready context; full = transcript page"),
12925
12941
  cursor: string2().optional().describe("compact reads only: cursor from the previous compact response; if context is unchanged the response collapses to a tiny unchanged envelope"),
12926
12942
  recentLimit: number2().int().min(1).max(20).optional().describe("compact reads only: latest contributions to include (default 6, max 20)"),
@@ -13091,7 +13107,7 @@ var ACTION_DEFINITIONS = [
13091
13107
  title: "Link a thread to a goal",
13092
13108
  description: "Record that a thread contributes to a goal — the many-to-many link that surfaces the goal on the thread's space and lists the thread under the goal. Idempotent. Reach for this once a thread's work clearly serves a goal; use `list_goals` to find the goal id.",
13093
13109
  inputSchema: {
13094
- threadId: string2().describe("the contributing thread, thr_…"),
13110
+ threadId: string2().describe("the contributing thread, thr_… or a short id like BUD-34"),
13095
13111
  initiativeId: string2().describe("the goal it serves, ini_…")
13096
13112
  },
13097
13113
  surfaces: ["cli"],
@@ -13103,7 +13119,7 @@ var ACTION_DEFINITIONS = [
13103
13119
  title: "Unlink a thread from a goal",
13104
13120
  description: "Remove the link between a thread and a goal (the deliberate inverse of `link_thread_to_goal`). Idempotent. Reach for this when a thread no longer serves the goal it was attached to — the thread and the goal both stay; only the link is dropped.",
13105
13121
  inputSchema: {
13106
- threadId: string2().describe("the thread to unlink, thr_…"),
13122
+ threadId: string2().describe("the thread to unlink, thr_… or a short id like BUD-34"),
13107
13123
  initiativeId: string2().describe("the goal to unlink it from, ini_…")
13108
13124
  },
13109
13125
  surfaces: ["cli"],
@@ -13128,7 +13144,7 @@ var ACTION_DEFINITIONS = [
13128
13144
  description: "List compact goals attached to one Space, or a Thread's linked goals plus its available pick list. Space lists are compact cards; Thread lists page only the available `all` list and keep `linked` complete; view=summary returns 3 active goals; status pages named lifecycles before the page.",
13129
13145
  inputSchema: {
13130
13146
  spaceId: string2().optional().describe("a Space whose attached goals to list, spc_…"),
13131
- threadId: string2().optional().describe("a Thread whose linked and available goals to list, thr_…"),
13147
+ threadId: string2().optional().describe("a Thread whose linked and available goals to list, thr_… or a short id like BUD-34"),
13132
13148
  view: literal("summary").optional().describe("summary: Topics home — 3 most recently active goals (title + in-space linked Thread count). Ignores status. Omit for the attached list."),
13133
13149
  status: union([
13134
13150
  _enum(["active", "paused", "completed", "archived"]),
@@ -13182,6 +13198,7 @@ var ACTION_DEFINITIONS = [
13182
13198
  description: "Create a Space when work needs its own durable collaboration/governance boundary — its own membership, visibility, shared norms, and multiple durable areas; you become its first admin (org owner/admins always can, other members only when enabled), with open/private visibility and optional seeded members. If the work can live under an existing Space with the same people and governance, use a Topic instead.",
13183
13199
  inputSchema: {
13184
13200
  title: string2().min(1).describe("the space title"),
13201
+ key: SPACE_KEY_INPUT.optional().describe("thread short-id prefix (BUD in BUD-34): 1-10 letters/digits, starting with a letter, unique in the org; default: the title's first three letters"),
13185
13202
  purpose: string2().optional().describe("why this boundary exists and what it is around — commonly a Product/System, Program/Function, Portfolio/Network, or Practice/Community — plus its dominant work modes (Build, Operate, Coordinate, Discuss, Share) when that helps; plain prose, not metadata syntax"),
13186
13203
  visibility: _enum(["open", "private"]).optional().describe("open (default) or private (invite-only)"),
13187
13204
  memberProfileIds: array(string2()).optional().describe("org profile ids to seed as members — agents added directly, humans get a pending invite")
@@ -13198,6 +13215,7 @@ var ACTION_DEFINITIONS = [
13198
13215
  spaceId: string2().describe("the space, spc_…"),
13199
13216
  purpose: string2().optional().describe("why this boundary exists and what it is around — commonly a Product/System, Program/Function, Portfolio/Network, or Practice/Community — plus its dominant work modes (Build, Operate, Coordinate, Discuss, Share) when that helps; plain prose, not metadata syntax"),
13200
13217
  title: string2().optional().describe("a new title for the space"),
13218
+ key: SPACE_KEY_INPUT.optional().describe("a new thread short-id prefix (BUD in BUD-34), unique in the org; every thread's short id changes, the old ones stop resolving, and the old key stays reserved to this Space"),
13201
13219
  visibility: _enum(["open", "private"]).optional().describe("open or private (invite-only)"),
13202
13220
  stage: _enum(["exploration", "design", "implementation", "maintenance", "retired"]).optional().describe("set the lifecycle stage; retired archives the Space reversibly and restores with an active stage, but only when no Run is active/suspended and no App is serving"),
13203
13221
  attachWorkflow: string2().optional().describe("add a workflow to this Space's list: a built-in id (`standard`, `queue`, `content`, `experiment`, `funnel`) or a catalog `wfl_…` from `workflow_list`"),
@@ -13408,7 +13426,7 @@ var ACTION_DEFINITIONS = [
13408
13426
  title: "Inspect a thread (superadmin)",
13409
13427
  description: "Platform-operator only: read any thread by id across orgs (its contributions + authors), bypassing the per-org membership boundary for oversight.",
13410
13428
  inputSchema: {
13411
- threadId: string2().min(1).describe("the thread id, e.g. thr_…")
13429
+ threadId: string2().min(1).describe("the canonical thread id, e.g. thr_… (admin reads are cross-org)")
13412
13430
  },
13413
13431
  surfaces: ["cli"],
13414
13432
  toolset: "admin",
@@ -13429,7 +13447,7 @@ var ACTION_DEFINITIONS = [
13429
13447
  description: "List compact goals attached to one Space, or the linked and available goals for one Thread. Space pages omit relatedThreads; Thread pages keep linked complete and page only the available `all` list; view=summary returns 3 active goals; status pages named lifecycles before the page; it cannot mutate a goal.",
13430
13448
  inputSchema: {
13431
13449
  spaceId: string2().optional().describe("a Space whose attached goals to list, spc_…"),
13432
- threadId: string2().optional().describe("a Thread whose linked and available goals to list, thr_…"),
13450
+ threadId: string2().optional().describe("a Thread whose linked and available goals to list, thr_… or a short id like BUD-34"),
13433
13451
  view: literal("summary").optional().describe("summary: Topics home — 3 most recently active goals (title + in-space linked Thread count). Ignores status. Omit for the attached list."),
13434
13452
  status: union([
13435
13453
  _enum(["active", "paused", "completed", "archived"]),
@@ -13461,7 +13479,7 @@ var ACTION_DEFINITIONS = [
13461
13479
  threadIds: array(string2()).optional().describe("create: threads to link at birth"),
13462
13480
  id: string2().optional().describe("update/set_status: the goal, ini_…"),
13463
13481
  status: _enum(["active", "paused", "completed", "archived"]).optional().describe("set_status: the new lifecycle state"),
13464
- threadId: string2().optional().describe("link_thread/unlink_thread: the thread, thr_…"),
13482
+ threadId: string2().optional().describe("link_thread/unlink_thread: the thread, thr_… or a short id like BUD-34"),
13465
13483
  initiativeId: string2().optional().describe("link/unlink/attach/detach: the goal, ini_…")
13466
13484
  },
13467
13485
  surfaces: ["mcp"],
@@ -13645,7 +13663,7 @@ var ACTION_DEFINITIONS = [
13645
13663
  computerSessionId: string2().optional().describe("create: the attached computer session that produced it, cms_…"),
13646
13664
  sourceContributionIds: array(string2()).optional().describe("create: contributions it distills"),
13647
13665
  artifactId: string2().optional().describe("edit/set_live_preview/set_snapshot: the Artifact, art_…"),
13648
- threadId: string2().optional().describe("set_live_preview: the configured Thread Live Preview, thr_…; omit to clear the binding"),
13666
+ threadId: string2().optional().describe("set_live_preview: the configured Thread Live Preview, thr_… or a short id like BUD-34; omit to clear the binding"),
13649
13667
  baseVersion: number2().optional().describe("edit: the version you READ (from get/create) — stale base is rejected with the current source"),
13650
13668
  patches: array(object({ old: string2(), new: string2() })).optional().describe("edit: exact-match hunks applied in order, atomically; each old must match exactly once"),
13651
13669
  note: string2().optional().describe("edit: one-line summary of what changed"),
@@ -14320,7 +14338,7 @@ var ACTION_DEFINITIONS = [
14320
14338
  topicId: string2().optional().describe("topic_guidance/topic_lanes: the topic, top_…"),
14321
14339
  guidance: proseList("space_guidance/topic_guidance: full list, replaces; [] clears").optional(),
14322
14340
  contributionLanes: proseList("space_lanes/topic_lanes: full list of ways to help, replaces; [] clears").optional(),
14323
- threadId: string2().optional().describe("ways_to_help: the thread, thr_…"),
14341
+ threadId: string2().optional().describe("ways_to_help: the thread, thr_… or a short id like BUD-34"),
14324
14342
  waysToHelp: proseList("ways_to_help: full list, replaces; [] clears").optional()
14325
14343
  },
14326
14344
  surfaces: ["mcp"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdacurry/arbor",
3
- "version": "0.24.3",
3
+ "version": "0.24.5",
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",
@@ -27,7 +27,7 @@
27
27
  "access": "public"
28
28
  },
29
29
  "scripts": {
30
- "arbor": "tsx src/bin.ts",
30
+ "arbor": "vpx src/bin.ts",
31
31
  "build": "bun build ./src/bin.ts --target=node --outfile=dist/arbor.js",
32
32
  "test": "vp test run --passWithNoTests",
33
33
  "typecheck": "tsc -b",
@@ -38,7 +38,6 @@
38
38
  "@arbor/core": "workspace:*",
39
39
  "@types/node": "^26.2.0",
40
40
  "just-bash": "3.4.2",
41
- "tsx": "^4.20.6",
42
41
  "typescript": "^5.8.0",
43
42
  "vite-plus": "catalog:",
44
43
  "zod": "^4.4.3"