@lambdacurry/arbor 0.21.22 → 0.21.24

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 +62 -23
  2. package/package.json +1 -1
package/dist/arbor.js CHANGED
@@ -1720,7 +1720,8 @@ var orgs = sqliteTable("orgs", {
1720
1720
  status: text("status").$type().notNull().default("active"),
1721
1721
  lockedAt: ts("locked_at"),
1722
1722
  lockedReason: text("locked_reason"),
1723
- systemKind: text("system_kind").unique()
1723
+ systemKind: text("system_kind").unique(),
1724
+ memberSpaceCreation: text("member_space_creation").$type().notNull().default("admins")
1724
1725
  });
1725
1726
  var profiles = sqliteTable("profiles", {
1726
1727
  id: text("id").primaryKey(),
@@ -2010,6 +2011,11 @@ var threadComputers = sqliteTable("thread_computers", {
2010
2011
  successorComputerId: text("successor_computer_id"),
2011
2012
  restoredFromSnapshotId: text("restored_from_snapshot_id"),
2012
2013
  currentSnapshotId: text("current_snapshot_id"),
2014
+ workspaceMutationStarted: integer("workspace_mutation_started").notNull().default(0),
2015
+ workspaceMutationAcknowledged: integer("workspace_mutation_acknowledged").notNull().default(0),
2016
+ workspaceDurableMutationVersion: integer("workspace_durable_mutation_version"),
2017
+ workspaceRecoveryLeaseId: text("workspace_recovery_lease_id"),
2018
+ workspaceRecoveryLeaseExpiresAt: ts("workspace_recovery_lease_expires_at"),
2013
2019
  createdByProfileId: text("created_by_profile_id").notNull().references(() => profiles.id),
2014
2020
  createdExecutionContextId: text("created_execution_context_id").notNull().references(() => executionContexts.id),
2015
2021
  createdAt: ts("created_at").notNull()
@@ -2056,10 +2062,13 @@ var computerSessions = sqliteTable("computer_sessions", {
2056
2062
  executionContextId: text("execution_context_id").notNull().references(() => executionContexts.id),
2057
2063
  configKey: text("config_key").notNull(),
2058
2064
  startingSnapshotId: text("starting_snapshot_id"),
2065
+ openIdempotencyKey: text("open_idempotency_key"),
2066
+ openIdempotencyFingerprint: text("open_idempotency_fingerprint"),
2059
2067
  attachedAt: ts("attached_at").notNull()
2060
2068
  }, (t) => ({
2061
2069
  computerIdx: index("computer_sessions_computer_idx").on(t.computerId, t.attachedAt),
2062
- threadIdx: index("computer_sessions_thread_idx").on(t.threadId, t.attachedAt)
2070
+ threadIdx: index("computer_sessions_thread_idx").on(t.threadId, t.attachedAt),
2071
+ openIdempotencyIdx: uniqueIndex("computer_sessions_open_idempotency_idx").on(t.profileId, t.threadId, t.openIdempotencyKey)
2063
2072
  }));
2064
2073
  var computerRuns = sqliteTable("computer_runs", {
2065
2074
  id: text("id").primaryKey(),
@@ -2322,7 +2331,8 @@ var artifacts = sqliteTable("artifacts", {
2322
2331
  }, (t) => ({
2323
2332
  statusIdx: index("artifacts_status_idx").on(t.status),
2324
2333
  tierIdx: index("artifacts_tier_idx").on(t.retrievalTier),
2325
- ownerIdx: index("artifacts_owner_idx").on(t.ownerProfileId)
2334
+ ownerIdx: index("artifacts_owner_idx").on(t.ownerProfileId),
2335
+ sourceThreadIdx: index("artifacts_source_thread_idx").on(t.sourceThreadId)
2326
2336
  }));
2327
2337
  var artifactLivePreviewSurfaces = sqliteTable("artifact_live_preview_surfaces", {
2328
2338
  artifactId: text("artifact_id").primaryKey().references(() => artifacts.id),
@@ -2796,6 +2806,25 @@ var watches = sqliteTable("watches", {
2796
2806
  watchUq: uniqueIndex("watches_watcher_target_uniq").on(t.watcherProfileId, t.targetType, t.targetId),
2797
2807
  watchTargetIdx: index("watches_target_idx").on(t.targetType, t.targetId)
2798
2808
  }));
2809
+ // ../core/src/ops/secret.ts
2810
+ var SECRET_PERMISSIONS = [
2811
+ "create",
2812
+ "metadata:read",
2813
+ "value:write",
2814
+ "rotate",
2815
+ "bind",
2816
+ "unbind",
2817
+ "revoke",
2818
+ "delete",
2819
+ "plaintext:read"
2820
+ ];
2821
+ var SECRET_ADMIN_PERMISSIONS = SECRET_PERMISSIONS.filter((permission) => permission !== "create" && permission !== "plaintext:read");
2822
+ var ORG_ADMIN_CONTAINMENT_PERMISSIONS = new Set([
2823
+ "metadata:read",
2824
+ "unbind",
2825
+ "revoke"
2826
+ ]);
2827
+
2799
2828
  // ../core/src/ops/computer-run.ts
2800
2829
  var COMPUTER_RUN_START_CHECKPOINT_RESERVATION_STALE_MS = 12 * 60 * 1000;
2801
2830
  var TERMINAL = new Set(["finished", "failed", "cancelled"]);
@@ -2820,6 +2849,11 @@ var RUN_PROVIDER_LIFECYCLE_PHASE_SET = new Set(RUN_PROVIDER_LIFECYCLE_PHASES);
2820
2849
 
2821
2850
  // ../core/src/ops/computer.ts
2822
2851
  var MAX_COMPUTER_REPOSITORIES = 10;
2852
+ var COMPUTER_WORKSPACE_RECOVERY_CHECKPOINT_DEADLINE_MS = 10 * 60 * 1000;
2853
+ var COMPUTER_WORKSPACE_RECOVERY_ATTACH_DEADLINE_MS = 31 * 60 * 1000;
2854
+ var COMPUTER_WORKSPACE_RECOVERY_HEALTH_DEADLINE_MS = 2 * 60 * 1000;
2855
+ var COMPUTER_WORKSPACE_RECOVERY_HEADROOM_MS = 2 * 60 * 1000;
2856
+ 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;
2823
2857
 
2824
2858
  // ../core/src/ops/request.ts
2825
2859
  var REQUEST_TTL_MS = 14 * 24 * 60 * 60 * 1000;
@@ -2832,24 +2866,6 @@ var EMOJI_RE = new RegExp("^\\p{RGI_Emoji}$", "v");
2832
2866
  var BASE_MS = Date.parse("2026-07-20T15:00:00.000Z");
2833
2867
  // ../core/src/ops/agent-pairing.ts
2834
2868
  var PAIRING_TTL_MS = 15 * 60 * 1000;
2835
- // ../core/src/ops/secret.ts
2836
- var SECRET_PERMISSIONS = [
2837
- "create",
2838
- "metadata:read",
2839
- "value:write",
2840
- "rotate",
2841
- "bind",
2842
- "unbind",
2843
- "revoke",
2844
- "delete",
2845
- "plaintext:read"
2846
- ];
2847
- var SECRET_ADMIN_PERMISSIONS = SECRET_PERMISSIONS.filter((permission) => permission !== "create" && permission !== "plaintext:read");
2848
- var ORG_ADMIN_CONTAINMENT_PERMISSIONS = new Set([
2849
- "metadata:read",
2850
- "unbind",
2851
- "revoke"
2852
- ]);
2853
2869
  // ../core/src/ops/preview.ts
2854
2870
  var PREVIEW_ENTRY_MIME = "text/html; charset=utf-8";
2855
2871
  var PREVIEW_MAX_BYTES = 2 * 1024 * 1024;
@@ -18330,6 +18346,11 @@ var MCP_OUTPUT_SCHEMAS = {
18330
18346
  defaultCwd: exports_external.string(),
18331
18347
  capabilities: computerOpenCapabilities,
18332
18348
  agentBrief: computerOpenAgentBrief,
18349
+ startupReceipt: exports_external.object({
18350
+ computerSessionId: id,
18351
+ replayed: exports_external.boolean(),
18352
+ mutationRetrySafety: exports_external.literal("safe")
18353
+ }),
18333
18354
  reconciliation: exports_external.union([
18334
18355
  exports_external.object({
18335
18356
  action: exports_external.literal("automatic_reprovision"),
@@ -18709,6 +18730,11 @@ var OUTPUT_SHAPERS = {
18709
18730
  "restorationOutcome",
18710
18731
  "addedRepositories"
18711
18732
  ]);
18733
+ const startupReceipt = selected(result.startupReceipt, [
18734
+ "computerSessionId",
18735
+ "replayed",
18736
+ "mutationRetrySafety"
18737
+ ]);
18712
18738
  return defined([
18713
18739
  ["computerSessionId", result.computerSessionId],
18714
18740
  [
@@ -18740,6 +18766,7 @@ var OUTPUT_SHAPERS = {
18740
18766
  ["activeRuns", activeRuns]
18741
18767
  ]) : undefined
18742
18768
  ],
18769
+ ["startupReceipt", startupReceipt],
18743
18770
  ["reconciliation", reconciliation]
18744
18771
  ]);
18745
18772
  },
@@ -19678,6 +19705,7 @@ var ACTION_DEFINITIONS = [
19678
19705
  description: "Open a Thread project environment and return its session/workspace, verified root repository instruction pointers, Agent Brief, capabilities, Runs, and reconciliation receipt. Forward profile-revision or additive authorized repository drift auto-reconciles through a successor; removal, setup, backend/provider/profile changes, or ambiguous drift refuse with computer_reprovision guidance.",
19679
19706
  inputSchema: {
19680
19707
  threadId: exports_external.string().describe("the Arbor Thread whose stable computer to open, thr_…"),
19708
+ idempotencyKey: exports_external.string().min(1).max(200).describe("stable key for this ONE logical open; retry the same call unchanged—even after a lost response—to reuse the same ComputerSession; never mint a new key for an unresolved attempt"),
19681
19709
  vcpus: exports_external.number().int().min(1).max(4).optional().describe("optional container vCPU request"),
19682
19710
  label: exports_external.string().optional().describe("short runtime label for operator diagnostics")
19683
19711
  },
@@ -20612,7 +20640,7 @@ var ACTION_DEFINITIONS = [
20612
20640
  {
20613
20641
  name: "space_create",
20614
20642
  title: "Create a space",
20615
- description: "Create a top-level Space for a new collaboration area; org owner/admin only, with open/private visibility and optional seeded members (agents join directly, humans receive invites). After creation set Space guidance, contribution lanes, and Goals so the room has an operating model.",
20643
+ description: "Create a top-level Space for a new collaboration area — open/private visibility plus optional seeded members (agents join directly, humans get invites); you become its first admin. Org owner/admins always can; other members only when their org enables member space creation.",
20616
20644
  inputSchema: {
20617
20645
  title: exports_external.string().min(1).describe("the space title"),
20618
20646
  purpose: exports_external.string().optional().describe("optional one-line purpose"),
@@ -20673,6 +20701,17 @@ var ACTION_DEFINITIONS = [
20673
20701
  toolset: "admin",
20674
20702
  run: forward("human.invite")
20675
20703
  },
20704
+ {
20705
+ name: "set_member_space_creation",
20706
+ title: "Set who may create spaces",
20707
+ description: "Set your org's space-creation policy (AD-052 rev): 'admins' (default — org owner/admin only) or 'members' (every active org member may create spaces they administer). Owner/admin only. Spaces remain visible/membership-governed exactly as before; this only moves who may stand one up.",
20708
+ inputSchema: {
20709
+ value: exports_external.enum(["admins", "members"]).describe("the new creation policy for the org")
20710
+ },
20711
+ surfaces: ["cli"],
20712
+ toolset: "admin",
20713
+ run: forward("org.setMemberSpaceCreation")
20714
+ },
20676
20715
  {
20677
20716
  name: "space_get",
20678
20717
  title: "Read a space",
@@ -22621,7 +22660,7 @@ async function renderMe(ctx, action) {
22621
22660
  ` : "") + spaceLines;
22622
22661
  emitDual(me, human, action, ctx);
22623
22662
  }
22624
- var CLI_NOTE = `On this CLI, before your first write: commands are NOUN-VERB (\`thread get\`, \`space get\`, not \`get thread\`). The underscore tool-names you see in MCP, recall, and docs (\`set_space_charter\`, \`transition_thread\`) work as CLI commands VERBATIM too — \`set_space_charter …\` and \`set space charter …\` are the same command, either form. Computer work is one parallel family: start project work with \`arbor computer open --thread-id thr_…\`, keep its cms_… receipt, then pass it as \`--computer-session-id\` to later tools. Checkpoint intermediate complete units; \`computer stop\` performs the final checkpoint before teardown. Internal Currybox grants are exchanged per call and never printed. A public screenshot is lighter: \`arbor computer verify --thread-id thr_… --target-url https://…\` runs directly, with no open/checkpoint/stop ceremony, and returns a gated download URL plus ready-to-place Markdown; put that Markdown where the image belongs in the contribution body and pass the matching attachment id. A single-argument command also takes a bare positional — \`recall "your question"\`, \`thread get thr_…\` — so you don't have to name the obvious flag. Flag names are kebab-derived from the inputs (\`--thread-id\`, \`--request-id\`, \`--contribution-id\` — not \`--thread\`/\`--request\`), so check \`arbor help\` or \`arbor <command> --help\` (now focused on that command's flags) instead of guessing. Pass long/markdown bodies via \`--body-file -\` (stdin), never shell-quoted; a one-line \`--summary\` (1-2 short sentences, hard limit 500 chars) on a long contribution becomes its recall snippet. List inputs always accept a REPEATED flag, one item each (\`--guidance "…" --guidance "…"\`) — the form that works everywhere. A single value additionally comma-splits for TOKEN lists (\`--capabilities a,b,c\`), but stays one literal item for PROSE lists (\`--guidance\`, \`--ways-to-help\`, \`--contribution-lanes\`) so a comma inside a sentence can't shred it; \`arbor <command> --help\` names which form each list flag takes. \`tree\` is the lifecycle map (default depth \`topics\`): choose a Topic, then \`recall --topic top_… "your question"\` before targeted \`thread get\`/\`artifact get\`; use \`topic get\` or deeper tree only when you intentionally need Topic-wide context or enumeration. If \`inbox\` is empty, that's "nothing needs you" — but if you're unsure your auth resolved, \`whoami\` confirms it.`;
22663
+ var CLI_NOTE = `On this CLI, before your first write: commands are NOUN-VERB (\`thread get\`, \`space get\`, not \`get thread\`). The underscore tool-names you see in MCP, recall, and docs (\`set_space_charter\`, \`transition_thread\`) work as CLI commands VERBATIM too — \`set_space_charter …\` and \`set space charter …\` are the same command, either form. Computer work is one parallel family: start project work with \`arbor computer open --thread-id thr_… --idempotency-key scope-open-1\`, reuse that key only for the same logical open, keep its cms_… receipt, then pass it as \`--computer-session-id\` to later tools. Checkpoint intermediate complete units; \`computer stop\` performs the final checkpoint before teardown. Internal Currybox grants are exchanged per call and never printed. A public screenshot is lighter: \`arbor computer verify --thread-id thr_… --target-url https://…\` runs directly, with no open/checkpoint/stop ceremony, and returns a gated download URL plus ready-to-place Markdown; put that Markdown where the image belongs in the contribution body and pass the matching attachment id. A single-argument command also takes a bare positional — \`recall "your question"\`, \`thread get thr_…\` — so you don't have to name the obvious flag. Flag names are kebab-derived from the inputs (\`--thread-id\`, \`--request-id\`, \`--contribution-id\` — not \`--thread\`/\`--request\`), so check \`arbor help\` or \`arbor <command> --help\` (now focused on that command's flags) instead of guessing. Pass long/markdown bodies via \`--body-file -\` (stdin), never shell-quoted; a one-line \`--summary\` (1-2 short sentences, hard limit 500 chars) on a long contribution becomes its recall snippet. List inputs always accept a REPEATED flag, one item each (\`--guidance "…" --guidance "…"\`) — the form that works everywhere. A single value additionally comma-splits for TOKEN lists (\`--capabilities a,b,c\`), but stays one literal item for PROSE lists (\`--guidance\`, \`--ways-to-help\`, \`--contribution-lanes\`) so a comma inside a sentence can't shred it; \`arbor <command> --help\` names which form each list flag takes. \`tree\` is the lifecycle map (default depth \`topics\`): choose a Topic, then \`recall --topic top_… "your question"\` before targeted \`thread get\`/\`artifact get\`; use \`topic get\` or deeper tree only when you intentionally need Topic-wide context or enumeration. If \`inbox\` is empty, that's "nothing needs you" — but if you're unsure your auth resolved, \`whoami\` confirms it.`;
22625
22664
  function renderOrient(ctx) {
22626
22665
  emitDual({ orientation: ORIENTATION, cliNote: CLI_NOTE }, `${ORIENTATION}
22627
22666
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdacurry/arbor",
3
- "version": "0.21.22",
3
+ "version": "0.21.24",
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",