@lambdacurry/arbor 0.12.2 → 0.12.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 +65 -11
  2. package/package.json +1 -1
package/dist/arbor.js CHANGED
@@ -1572,6 +1572,8 @@ var previewVersions = sqliteTable("preview_versions", {
1572
1572
  computerSessionId: text("computer_session_id").notNull().references(() => computerSessions.id),
1573
1573
  snapshotId: text("snapshot_id").notNull().references(() => computerSnapshots.id),
1574
1574
  publishedByProfileId: text("published_by_profile_id").notNull().references(() => profiles.id),
1575
+ idempotencyKey: text("idempotency_key"),
1576
+ idempotencyFingerprint: text("idempotency_fingerprint"),
1575
1577
  publishedExecutionContextId: text("published_execution_context_id").notNull().references(() => executionContexts.id),
1576
1578
  failureCode: text("failure_code"),
1577
1579
  createdAt: ts("created_at").notNull(),
@@ -1580,8 +1582,18 @@ var previewVersions = sqliteTable("preview_versions", {
1580
1582
  previewVersionIdx: uniqueIndex("preview_versions_preview_version_idx").on(t.previewId, t.version),
1581
1583
  hostIdx: uniqueIndex("preview_versions_host_idx").on(t.hostLabel),
1582
1584
  sessionIdx: index("preview_versions_session_idx").on(t.computerSessionId, t.createdAt),
1585
+ idempotencyIdx: uniqueIndex("preview_versions_idempotency_idx").on(t.computerSessionId, t.publishedByProfileId, t.idempotencyKey),
1583
1586
  snapshotIdx: index("preview_versions_snapshot_idx").on(t.snapshotId)
1584
1587
  }));
1588
+ var previewVersionFiles = sqliteTable("preview_version_files", {
1589
+ versionId: text("version_id").notNull().references(() => previewVersions.id),
1590
+ path: text("path").notNull(),
1591
+ size: integer("size").notNull(),
1592
+ mimeType: text("mime_type").notNull(),
1593
+ sha256: text("sha256").notNull()
1594
+ }, (t) => ({
1595
+ pk: primaryKey({ columns: [t.versionId, t.path] })
1596
+ }));
1585
1597
  var previewVersionFinalizations = sqliteTable("preview_version_finalizations", {
1586
1598
  versionId: text("version_id").primaryKey().references(() => previewVersions.id),
1587
1599
  finalizedAt: ts("finalized_at").notNull()
@@ -1646,15 +1658,21 @@ var reviews = sqliteTable("reviews", {
1646
1658
  var attachments = sqliteTable("attachments", {
1647
1659
  id: text("id").primaryKey(),
1648
1660
  filename: text("filename").notNull(),
1661
+ description: text("description").notNull().default(""),
1649
1662
  mimeType: text("mime_type").notNull(),
1650
1663
  size: integer("size").notNull(),
1651
1664
  r2Key: text("r2_key").notNull(),
1652
1665
  uploadedByProfileId: text("uploaded_by_profile_id").notNull().references(() => profiles.id),
1666
+ computerSessionId: text("computer_session_id").references(() => computerSessions.id),
1667
+ idempotencyKey: text("idempotency_key"),
1668
+ idempotencyFingerprint: text("idempotency_fingerprint"),
1669
+ sha256: text("sha256"),
1653
1670
  threadId: text("thread_id").notNull().references(() => threads.id),
1654
1671
  createdAt: ts("created_at").notNull()
1655
1672
  }, (t) => ({
1656
1673
  threadIdx: index("attachments_thread_idx").on(t.threadId),
1657
1674
  uploaderIdx: index("attachments_uploader_idx").on(t.uploadedByProfileId),
1675
+ computerExportIdempotencyIdx: uniqueIndex("attachments_computer_export_idempotency_idx").on(t.computerSessionId, t.uploadedByProfileId, t.idempotencyKey),
1658
1676
  r2KeyIdx: uniqueIndex("attachments_r2_key_uniq").on(t.r2Key)
1659
1677
  }));
1660
1678
  var reactions = sqliteTable("reactions", {
@@ -1781,6 +1799,11 @@ var notificationCursors = sqliteTable("notification_cursors", {
1781
1799
  profileId: text("profile_id").primaryKey().references(() => profiles.id),
1782
1800
  lastSeenAt: ts("last_seen_at").notNull()
1783
1801
  });
1802
+ var recallIndex = sqliteTable("recall_index", {
1803
+ objectId: text("object_id").primaryKey(),
1804
+ indexedAt: ts("indexed_at").notNull(),
1805
+ chunks: integer("chunks")
1806
+ });
1784
1807
  var watches = sqliteTable("watches", {
1785
1808
  id: text("id").primaryKey(),
1786
1809
  watcherProfileId: text("watcher_profile_id").notNull().references(() => profiles.id),
@@ -1832,6 +1855,28 @@ class InMemoryBlobStore {
1832
1855
  async put(key, bytes, mimeType) {
1833
1856
  this.store.set(key, { bytes: new Uint8Array(bytes), mimeType });
1834
1857
  }
1858
+ async putStream(key, stream, size, mimeType) {
1859
+ const reader = stream.getReader();
1860
+ const bytes = new Uint8Array(size);
1861
+ let offset = 0;
1862
+ try {
1863
+ while (true) {
1864
+ const { done, value } = await reader.read();
1865
+ if (done)
1866
+ break;
1867
+ if (offset + value.byteLength > size) {
1868
+ throw new Error(`Blob stream exceeded its declared ${size} bytes`);
1869
+ }
1870
+ bytes.set(value, offset);
1871
+ offset += value.byteLength;
1872
+ }
1873
+ } finally {
1874
+ reader.releaseLock();
1875
+ }
1876
+ if (offset !== size)
1877
+ throw new Error(`Blob stream ended at ${offset} of ${size} bytes`);
1878
+ this.store.set(key, { bytes, mimeType });
1879
+ }
1835
1880
  async get(key, range) {
1836
1881
  const blob2 = this.store.get(key);
1837
1882
  if (!blob2)
@@ -1884,6 +1929,8 @@ class InMemoryVectorStore {
1884
1929
  async query(vector, q) {
1885
1930
  const scored = [];
1886
1931
  for (const r of this.records.values()) {
1932
+ if ((r.namespace ?? null) !== (q.namespace ?? null))
1933
+ continue;
1887
1934
  if (!matchesFilter(r.metadata, q.filter))
1888
1935
  continue;
1889
1936
  scored.push({ id: r.id, score: cosine(vector, r.vector), metadata: r.metadata });
@@ -1906,6 +1953,7 @@ class InMemoryVectorStore {
1906
1953
  var recallFts = sqliteTable("recall_fts", {
1907
1954
  id: text("id"),
1908
1955
  body: text("body"),
1956
+ org: text("org"),
1909
1957
  space: text("space"),
1910
1958
  topic: text("topic"),
1911
1959
  thread: text("thread")
@@ -1920,8 +1968,10 @@ var INDEX_ON = new Set([
1920
1968
  "review.added",
1921
1969
  "thread.created",
1922
1970
  "topic.created",
1923
- "topic.edited"
1971
+ "topic.edited",
1972
+ "contribution.restored"
1924
1973
  ]);
1974
+ var PURGE_ON = new Set(["contribution.deleted"]);
1925
1975
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
1926
1976
  var exports_external = {};
1927
1977
  __export(exports_external, {
@@ -16555,10 +16605,12 @@ var ACTIONS = [
16555
16605
  {
16556
16606
  name: "computer_export",
16557
16607
  title: "Export a Thread file",
16558
- description: "Move one bounded image, MP4/WebM video, or supported file from an opened computer into a durable Thread Attachment. Returns attachmentIds and ready-to-place attachments[].markdown; put the Markdown where the media belongs and bind those ids when contributing or responding.",
16608
+ description: "Move one bounded image, MP4/WebM video, or supported file from an opened computer into a durable Thread Attachment. Describe what it shows so the returned attachments[].markdown has meaningful image alt text or a video/file label; put that Markdown where the media belongs and bind those ids when contributing or responding. Supply one stable idempotencyKey per logical export: safe retries return the original Attachment, while reusing the key for another path or description conflicts.",
16559
16609
  inputSchema: {
16560
16610
  computerSessionId: exports_external.string().describe("the computerSessionId returned by computer_open, cms_…"),
16561
- path: exports_external.string().describe("absolute path to one supported file under /workspace")
16611
+ path: exports_external.string().describe("absolute path to one supported file under /workspace"),
16612
+ description: exports_external.string().min(1).max(500).describe("concise description of what the file shows or contains; becomes image alt text, a video caption, and the Artifact summary"),
16613
+ idempotencyKey: exports_external.string().min(1).max(200).describe("stable key for this ONE logical export (≤200 chars); reuse it only to retry the same path")
16562
16614
  },
16563
16615
  surfaces: ["computer-mcp", "computer-cli"],
16564
16616
  toolset: "loop",
@@ -16567,11 +16619,12 @@ var ACTIONS = [
16567
16619
  {
16568
16620
  name: "computer_write",
16569
16621
  title: "Write a project file",
16570
- description: "Write one file under /workspace. Prefer normal editing tools for code changes; reach for this when the MCP/CLI computer surface is the only filesystem path.",
16622
+ description: "Write one file under /workspace. Content is UTF-8 by default; pass encoding=base64 only for binary bytes. Prefer normal editing tools for code changes; reach for this when the MCP/CLI computer surface is the only filesystem path.",
16571
16623
  inputSchema: {
16572
16624
  computerSessionId: exports_external.string().describe("the computerSessionId returned by computer_open, cms_…"),
16573
16625
  path: exports_external.string().describe("absolute path under /workspace"),
16574
- content: exports_external.string().describe("complete UTF-8 file content")
16626
+ content: exports_external.string().describe("complete UTF-8 content, or base64 bytes when encoding=base64"),
16627
+ encoding: exports_external.enum(["utf8", "base64"]).optional().describe("content encoding; defaults to utf8, use base64 for binary files")
16575
16628
  },
16576
16629
  surfaces: ["computer-mcp", "computer-cli"],
16577
16630
  toolset: "loop",
@@ -16605,11 +16658,12 @@ var ACTIONS = [
16605
16658
  {
16606
16659
  name: "computer_publish_preview",
16607
16660
  title: "Publish an immutable static Preview",
16608
- description: "Publish one checked HTML file or bounded static build directory as a private immutable Preview after checkpointing its source. The returned arborthreads.dev URL survives computer teardown; put it on its own line to show the interactive Preview card. A directory must contain index.html, use relative local asset URLs, and cannot include dotfiles, source maps, secrets, symlinks, or server code.",
16661
+ description: "Publish one checked HTML file or bounded static build directory as a private immutable Preview after checkpointing its source. The returned arborthreads.dev URL survives computer teardown; put it on its own line to show the interactive Preview card. A directory must contain index.html, use relative local asset URLs, and cannot include dotfiles, source maps, secrets, symlinks, or server code. Supply one stable idempotencyKey per logical publication: safe retries return the original immutable URL, while reusing the key for another path/title conflicts.",
16609
16662
  inputSchema: {
16610
16663
  computerSessionId: exports_external.string().describe("the computerSessionId returned by computer_open, cms_…"),
16611
16664
  path: exports_external.string().describe("absolute path to one HTML file or static build directory under /workspace"),
16612
- title: exports_external.string().min(1).max(160).describe("short factual Preview title")
16665
+ title: exports_external.string().min(1).max(160).describe("short factual Preview title"),
16666
+ idempotencyKey: exports_external.string().min(1).max(200).describe("stable key for this ONE logical publication (≤200 chars); reuse it only to retry the same path and title")
16613
16667
  },
16614
16668
  surfaces: ["computer-mcp", "computer-cli"],
16615
16669
  toolset: "loop",
@@ -16693,7 +16747,7 @@ var ACTIONS = [
16693
16747
  {
16694
16748
  name: "create_artifact",
16695
16749
  title: "Create an artifact",
16696
- description: "Promote durable output — a decision, summary, plan, or research brief — into a first-class artifact you own. Text kinds (doc/table/diagram/html) are living documents: pass `source` (born at v1, editable in place via edit_artifact); kind=file passes a contentRef instead. The artifact is AUTOMATICALLY listed on its source thread (no link post needed). When it came from an attached Thread computer, pass that attach_computer receipt as computerSessionId so the artifact cites the reproducible session. Reach for this when a thread has produced something worth retaining and citing beyond the conversation — especially a table or doc the team will UPDATE, which beats pasting it into a prose contribution.",
16750
+ description: "Promote durable output — a decision, summary, plan, or research brief — into a first-class artifact you own. Give it a concise summary of what the Artifact is or accomplishes; this is the skim and retrieval description, not a repeat of its title. Text kinds (doc/table/diagram/html) are living documents: pass `source` (born at v1, editable in place via edit_artifact); kind=file passes a contentRef instead. The artifact is AUTOMATICALLY listed on its source thread (no link post needed). When it came from an attached Thread computer, pass that attach_computer receipt as computerSessionId so the artifact cites the reproducible session. Reach for this when a thread has produced something worth retaining and citing beyond the conversation — especially a table or doc the team will UPDATE, which beats pasting it into a prose contribution.",
16697
16751
  inputSchema: {
16698
16752
  type: exports_external.string().describe("semantic type, e.g. decision|summary|plan|markdown|table|research-brief"),
16699
16753
  kind: exports_external.enum(["doc", "table", "diagram", "html", "file"]).optional().describe("structural kind (default file). doc/table/diagram/html are editable, versioned text"),
@@ -16701,7 +16755,7 @@ var ACTIONS = [
16701
16755
  source: exports_external.string().optional().describe("text kinds: the initial content (v1)"),
16702
16756
  contentRef: exports_external.string().optional().describe("kind=file: where the content lives, e.g. inline://… or a URL"),
16703
16757
  editPolicy: exports_external.enum(["owner", "members", "anyone"]).optional().describe("who may edit (default members)"),
16704
- summary: exports_external.string().optional(),
16758
+ summary: exports_external.string().min(1).max(500).describe("required one-line description of what this durable Artifact is or accomplishes"),
16705
16759
  sourceThreadId: exports_external.string().optional(),
16706
16760
  sourceContributionIds: exports_external.array(exports_external.string()).optional(),
16707
16761
  computerSessionId: exports_external.string().optional().describe("the attached computer session that produced this artifact, cms_…")
@@ -17499,7 +17553,7 @@ var ACTIONS = [
17499
17553
  {
17500
17554
  name: "artifact",
17501
17555
  title: "Durable artifacts",
17502
- description: "Durable, versioned artifacts — the team's living documents (AD-201). Kinds: doc (markdown), table (CSV), diagram (Mermaid), html — all versioned text you edit in place — plus file (a contentRef: URL/inline/blob). " + "verb=create (kind+type+title, source for text kinds / contentRef for file; a text artifact is born at v1 and is AUTOMATICALLY listed on its sourceThreadId thread — no link post needed). " + "For computer-produced output, create with the computerSessionId returned by attach_computer so the artifact cites the reproducible session. " + "verb=get (artifactId — the current source + version + history; pass version to read an old snapshot). " + "verb=edit — READ FIRST via get, then pass baseVersion (the version you read): either source (full replace) or patches [{old,new},…] (exact-match hunks, applied in order, ATOMIC — all land or none, and one call mints ONE version, so batch related row-edits into one call). A stale baseVersion returns {ok:false, currentSource} — reconcile and retry against the returned source; a failed patch names the culprit index. " + "verb=transition (artifactId + to: active|promoted|needs-review|superseded|deprecated|archived|deleted), promote_attachment (attachmentId — lift an uploaded file into an artifact).",
17556
+ description: "Durable, versioned artifacts — the team's living documents (AD-201). Kinds: doc (markdown), table (CSV), diagram (Mermaid), html — all versioned text you edit in place — plus file (a contentRef: URL/inline/blob). " + "verb=create (kind+type+title+summary, source for text kinds / contentRef for file; summary is the required one-line skim/retrieval description; a text artifact is born at v1 and is AUTOMATICALLY listed on its sourceThreadId thread — no link post needed). " + "For computer-produced output, create with the computerSessionId returned by attach_computer so the artifact cites the reproducible session. " + "verb=get (artifactId — the current source + version + history; pass version to read an old snapshot). " + "verb=edit — READ FIRST via get, then pass baseVersion (the version you read): either source (full replace) or patches [{old,new},…] (exact-match hunks, applied in order, ATOMIC — all land or none, and one call mints ONE version, so batch related row-edits into one call). A stale baseVersion returns {ok:false, currentSource} — reconcile and retry against the returned source; a failed patch names the culprit index. " + "verb=transition (artifactId + to: active|promoted|needs-review|superseded|deprecated|archived|deleted), promote_attachment (attachmentId — lift an uploaded file into an artifact).",
17503
17557
  inputSchema: {
17504
17558
  verb: exports_external.enum(["create", "get", "edit", "transition", "promote_attachment"]).describe("which artifact move"),
17505
17559
  title: exports_external.string().optional().describe("create: the artifact's title"),
@@ -17508,7 +17562,7 @@ var ACTIONS = [
17508
17562
  source: exports_external.string().optional().describe("create (text kinds): the initial content · edit verb=replace: the full new content"),
17509
17563
  contentRef: exports_external.string().optional().describe("create (kind=file): where the content lives, e.g. inline://… or a URL"),
17510
17564
  editPolicy: exports_external.enum(["owner", "members", "anyone"]).optional().describe("create: who may edit (default members)"),
17511
- summary: exports_external.string().optional().describe("create: a short summary"),
17565
+ summary: exports_external.string().min(1).max(500).optional().describe("create: REQUIRED one-line description of what this Artifact is or accomplishes"),
17512
17566
  sourceThreadId: exports_external.string().optional().describe("create: the thread it came from"),
17513
17567
  computerSessionId: exports_external.string().optional().describe("create: the attached computer session that produced it, cms_…"),
17514
17568
  sourceContributionIds: exports_external.array(exports_external.string()).optional().describe("create: contributions it distills"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdacurry/arbor",
3
- "version": "0.12.2",
3
+ "version": "0.12.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",