busabase-sdk 0.1.0 → 0.9.3

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.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createORPCClient } from '@orpc/client';
2
2
  import { OpenAPILink } from '@orpc/openapi-client/fetch';
3
- import { oc } from '@orpc/contract';
3
+ import { oc, eventIterator } from '@orpc/contract';
4
4
  import { z } from 'zod';
5
5
 
6
6
  // src/client.ts
@@ -44,36 +44,24 @@ var RequestUploadUrlVOSchema = z.object({
44
44
  */
45
45
  duplicate: z.boolean().optional(),
46
46
  /** Existing attachment id — present only when `duplicate` is true. */
47
- attachmentId: z.string().optional()
47
+ attachmentId: z.string().optional(),
48
+ /** Host-specific logical asset id, when the app maps uploads into an Asset library. */
49
+ assetId: z.string().optional()
48
50
  });
49
51
  var ConfirmUploadVOSchema = z.object({
50
52
  success: z.boolean(),
51
53
  attachmentId: z.string(),
54
+ /** Host-specific logical asset id, when the app maps uploads into an Asset library. */
55
+ assetId: z.string().optional(),
52
56
  storageKey: z.string(),
53
57
  publicUrl: z.string()
54
58
  });
55
-
56
- // ../../packages/open-domains/attachments/contract.ts
57
- var attachmentsContract = oc.router({
58
- createUploadUrl: oc.route({
59
- method: "POST",
60
- path: "/attachments/upload-urls",
61
- tags: ["Attachments"],
62
- summary: "Request upload URL",
63
- successDescription: "Presigned (or dev) upload URL plus the public URL the file will resolve to."
64
- }).input(RequestUploadUrlInputSchema).output(RequestUploadUrlVOSchema),
65
- confirm: oc.route({
66
- method: "POST",
67
- path: "/attachments/confirmations",
68
- tags: ["Attachments"],
69
- summary: "Confirm upload",
70
- successDescription: "Recorded attachment row and its public URL."
71
- }).input(ConfirmUploadInputSchema).output(ConfirmUploadVOSchema)
72
- });
73
59
  var AssetVOSchema = z.object({
74
60
  id: z.string(),
75
61
  attachmentId: z.string(),
76
62
  name: z.string(),
63
+ contentKind: z.enum(["text", "binary"]),
64
+ metadata: z.record(z.string(), z.unknown()).default({}),
77
65
  fileName: z.string(),
78
66
  mimeType: z.string(),
79
67
  size: z.number().int().nonnegative(),
@@ -84,15 +72,20 @@ var AssetVOSchema = z.object({
84
72
  createdAt: z.string()
85
73
  });
86
74
  var AssetUsageVOSchema = z.object({
75
+ ownerType: z.enum(["drive", "skill", "base", "doc", "file_node"]),
87
76
  nodeId: z.string(),
88
77
  nodeName: z.string(),
89
78
  nodeType: z.string(),
90
79
  /** Node slug, so the UI can link to the owning Base/Doc (`/{type}/{slug}`). */
91
80
  nodeSlug: z.string(),
81
+ /** Drive/Skill mounted path, or null when the usage is not path-based. */
82
+ path: z.string().nullable(),
92
83
  /** Base record id, or null for whole-node usages (e.g. a Doc body). */
93
84
  recordId: z.string().nullable(),
94
85
  /** Attachment field slug, or null for whole-node usages. */
95
86
  fieldSlug: z.string().nullable(),
87
+ /** Doc block id, or null when the usage is not block-based. */
88
+ blockId: z.string().nullable(),
96
89
  createdAt: z.string()
97
90
  });
98
91
  var AssetDetailVOSchema = z.object({
@@ -101,7 +94,26 @@ var AssetDetailVOSchema = z.object({
101
94
  });
102
95
 
103
96
  // ../../packages/busabase-contract/src/domains/assets/contract.ts
97
+ var UpdateAssetMetadataInputSchema = z.object({
98
+ assetId: z.string(),
99
+ metadata: z.record(z.string(), z.unknown()),
100
+ mode: z.enum(["merge", "replace"]).optional().default("merge")
101
+ });
104
102
  var assetsContract = {
103
+ createUploadUrl: oc.route({
104
+ method: "POST",
105
+ path: "/assets/upload-urls",
106
+ tags: ["Assets"],
107
+ summary: "Request asset upload URL",
108
+ successDescription: "Presigned (or dev) upload URL plus the public URL and asset id when identical bytes are already in the library."
109
+ }).input(RequestUploadUrlInputSchema).output(RequestUploadUrlVOSchema),
110
+ confirm: oc.route({
111
+ method: "POST",
112
+ path: "/assets/confirmations",
113
+ tags: ["Assets"],
114
+ summary: "Confirm asset upload",
115
+ successDescription: "Recorded the file and ensured its Busabase Asset library entry."
116
+ }).input(ConfirmUploadInputSchema).output(ConfirmUploadVOSchema),
105
117
  list: oc.route({
106
118
  method: "GET",
107
119
  path: "/assets",
@@ -116,6 +128,13 @@ var assetsContract = {
116
128
  summary: "Get asset detail",
117
129
  successDescription: "Asset metadata plus every place it is referenced (where-used)."
118
130
  }).input(z.object({ assetId: z.string() })).output(AssetDetailVOSchema),
131
+ updateMetadata: oc.route({
132
+ method: "PATCH",
133
+ path: "/assets/{assetId}/metadata",
134
+ tags: ["Assets"],
135
+ summary: "Update asset metadata",
136
+ successDescription: "Updated AI-readable metadata for a file, such as summary, extracted text, tags, source URL, or schema-specific hints."
137
+ }).input(UpdateAssetMetadataInputSchema).output(AssetDetailVOSchema),
119
138
  delete: oc.route({
120
139
  method: "DELETE",
121
140
  path: "/assets/{assetId}",
@@ -151,6 +170,7 @@ var fieldTypeSchema = z.enum([
151
170
  "select",
152
171
  "multiselect",
153
172
  "url",
173
+ "embed",
154
174
  "email",
155
175
  "phone",
156
176
  "created_time",
@@ -160,7 +180,9 @@ var fieldTypeSchema = z.enum([
160
180
  "auto_number",
161
181
  "ai_summary",
162
182
  "ai_tags",
163
- "code"
183
+ "code",
184
+ "json",
185
+ "yaml"
164
186
  ]);
165
187
  var fieldOptionsSchema = z.object({
166
188
  ai: z.object({
@@ -186,6 +208,11 @@ var fieldOptionsSchema = z.object({
186
208
  code: z.object({
187
209
  language: z.string().optional()
188
210
  }).optional(),
211
+ embed: z.object({
212
+ aspectRatio: z.enum(["16:9", "4:3", "1:1"]).optional(),
213
+ height: z.number().int().positive().max(1200).optional(),
214
+ providers: z.array(z.string()).optional()
215
+ }).optional(),
189
216
  inverseFieldId: z.string().optional(),
190
217
  multiple: z.boolean().optional(),
191
218
  // Display formatting for `number` columns (Notion-style: one number type,
@@ -195,7 +222,10 @@ var fieldOptionsSchema = z.object({
195
222
  currency: z.string().optional(),
196
223
  locale: z.string().optional()
197
224
  }).optional(),
198
- targetBaseId: z.string().optional()
225
+ targetBaseId: z.string().optional().describe("Relation target Base id (bse_\u2026). Or pass targetBaseSlug to name it by slug."),
226
+ targetBaseSlug: z.string().optional().describe(
227
+ "Relation target Base by slug \u2014 a convenience alias for targetBaseId, resolved server-side (active bases in the current space). If both are given, targetBaseId wins."
228
+ )
199
229
  }).default({});
200
230
  var baseFieldSchema = z.object({
201
231
  id: z.string(),
@@ -394,6 +424,52 @@ var docNodeType = {
394
424
  ]
395
425
  };
396
426
 
427
+ // ../../packages/busabase-contract/src/domains/filetree/definition.ts
428
+ var fileTreeOperations = (type) => [
429
+ {
430
+ kind: `${type}_file_create`,
431
+ label: "Create file",
432
+ tone: "border-emerald-200 bg-emerald-50 text-emerald-800"
433
+ },
434
+ {
435
+ kind: `${type}_file_update`,
436
+ label: "Update file",
437
+ tone: "border-blue-200 bg-blue-50 text-blue-800"
438
+ },
439
+ {
440
+ kind: `${type}_file_delete`,
441
+ label: "Delete file",
442
+ tone: "border-rose-200 bg-rose-50 text-rose-800"
443
+ },
444
+ {
445
+ kind: `${type}_metadata_update`,
446
+ label: `Update ${type}`,
447
+ tone: "border-violet-200 bg-violet-50 text-violet-800"
448
+ }
449
+ ];
450
+ var makeFileTreeNodeType = (config) => ({
451
+ type: config.type,
452
+ label: config.label,
453
+ icon: config.icon,
454
+ capabilities: { hasDetail: true, creatable: true },
455
+ operations: fileTreeOperations(config.type)
456
+ });
457
+
458
+ // ../../packages/busabase-contract/src/domains/drive/definition.ts
459
+ var driveNodeType = makeFileTreeNodeType({
460
+ type: "drive",
461
+ label: "Drive",
462
+ icon: "hard-drive"});
463
+
464
+ // ../../packages/busabase-contract/src/domains/file-node/definition.ts
465
+ var fileNodeType = {
466
+ type: "file",
467
+ label: "File",
468
+ icon: "file",
469
+ capabilities: { hasDetail: true, creatable: true },
470
+ operations: []
471
+ };
472
+
397
473
  // ../../packages/busabase-contract/src/domains/folder/definition.ts
398
474
  var folderNodeType = {
399
475
  type: "folder",
@@ -404,34 +480,10 @@ var folderNodeType = {
404
480
  };
405
481
 
406
482
  // ../../packages/busabase-contract/src/domains/skill/definition.ts
407
- var skillNodeType = {
483
+ var skillNodeType = makeFileTreeNodeType({
408
484
  type: "skill",
409
485
  label: "Skill",
410
- icon: "sparkles",
411
- capabilities: { hasDetail: true, creatable: true },
412
- operations: [
413
- {
414
- kind: "skill_file_create",
415
- label: "Create file",
416
- tone: "border-emerald-200 bg-emerald-50 text-emerald-800"
417
- },
418
- {
419
- kind: "skill_file_update",
420
- label: "Update file",
421
- tone: "border-blue-200 bg-blue-50 text-blue-800"
422
- },
423
- {
424
- kind: "skill_file_delete",
425
- label: "Delete file",
426
- tone: "border-rose-200 bg-rose-50 text-rose-800"
427
- },
428
- {
429
- kind: "skill_metadata_update",
430
- label: "Update skill",
431
- tone: "border-violet-200 bg-violet-50 text-violet-800"
432
- }
433
- ]
434
- };
486
+ icon: "sparkles"});
435
487
 
436
488
  // ../../packages/busabase-contract/src/domains/registry.ts
437
489
  var GENERIC_NODE_OPERATIONS = [
@@ -457,6 +509,8 @@ var BUILTIN_NODE_TYPES = [
457
509
  folderNodeType,
458
510
  baseNodeType,
459
511
  skillNodeType,
512
+ driveNodeType,
513
+ fileNodeType,
460
514
  docNodeType
461
515
  ];
462
516
  for (const definition of BUILTIN_NODE_TYPES) {
@@ -493,10 +547,10 @@ var nodeSchema = z.lazy(
493
547
  name: z.string(),
494
548
  description: z.string(),
495
549
  metadata: z.object({
496
- storagePrefix: z.string().optional(),
497
550
  entryFile: z.string().optional(),
498
551
  visibility: z.enum(["private", "workspace", "public"]).optional(),
499
- version: z.string().optional()
552
+ version: z.string().optional(),
553
+ assetId: z.string().optional()
500
554
  }).default({}),
501
555
  position: z.number(),
502
556
  createdAt: z.string(),
@@ -505,6 +559,13 @@ var nodeSchema = z.lazy(
505
559
  children: z.array(nodeSchema)
506
560
  })
507
561
  );
562
+ var userRefSchema = z.object({
563
+ id: z.string(),
564
+ name: z.string().nullable(),
565
+ email: z.string().nullable(),
566
+ image: z.string().nullable(),
567
+ role: z.string().nullable().optional()
568
+ });
508
569
  var commitSchema = z.object({
509
570
  id: z.string(),
510
571
  baseId: z.string().nullable(),
@@ -516,6 +577,7 @@ var commitSchema = z.object({
516
577
  operation: z.enum(OPERATION_KINDS),
517
578
  message: z.string(),
518
579
  author: z.string(),
580
+ authorUser: userRefSchema.nullable().optional().default(null),
519
581
  createdAt: z.string()
520
582
  });
521
583
  var operationSchema = z.object({
@@ -551,6 +613,7 @@ var reviewSchema = z.object({
551
613
  id: z.string(),
552
614
  changeRequestId: z.string(),
553
615
  reviewerId: z.string(),
616
+ reviewer: userRefSchema.nullable().optional().default(null),
554
617
  verdict: z.enum(["approved", "rejected"]),
555
618
  reason: z.string().nullable(),
556
619
  visibleOperationHeads: z.record(z.string(), z.string()),
@@ -566,26 +629,29 @@ var commentSchema = z.object({
566
629
  operationId: z.string().nullable(),
567
630
  commitId: z.string().nullable(),
568
631
  authorId: z.string(),
632
+ author: userRefSchema.nullable().optional().default(null),
569
633
  body: z.string(),
570
634
  mentionsAi: z.boolean(),
571
635
  createdAt: z.string(),
572
636
  updatedAt: z.string()
573
637
  });
638
+ var changeRequestStatusSchema = z.enum([
639
+ "in_review",
640
+ "changes_requested",
641
+ "approved",
642
+ "rejected",
643
+ "merged",
644
+ "abandoned",
645
+ "conflict"
646
+ ]);
574
647
  var changeRequestSchema = z.object({
575
648
  id: z.string(),
576
649
  baseId: z.string().nullable(),
577
650
  targetType: z.enum(["base", "node"]),
578
651
  nodeId: z.string().nullable(),
579
- status: z.enum([
580
- "in_review",
581
- "changes_requested",
582
- "approved",
583
- "rejected",
584
- "merged",
585
- "abandoned",
586
- "conflict"
587
- ]),
652
+ status: changeRequestStatusSchema,
588
653
  submittedBy: z.string(),
654
+ submittedByUser: userRefSchema.nullable().optional().default(null),
589
655
  sourceMeta: z.record(z.string(), z.unknown()),
590
656
  reviewPolicySnapshot: z.record(z.string(), z.unknown()),
591
657
  mergeSummary: z.record(z.string(), z.unknown()),
@@ -609,7 +675,7 @@ var agentTaskSchema = z.object({
609
675
  });
610
676
  var searchResultSchema = z.object({
611
677
  id: z.string(),
612
- kind: z.enum(["record", "change_request", "base"]),
678
+ kind: z.enum(["record", "change_request", "base", "file"]),
613
679
  title: z.string(),
614
680
  body: z.string(),
615
681
  eyebrow: z.string(),
@@ -623,6 +689,23 @@ var searchResponseSchema = z.object({
623
689
  hasMore: z.boolean(),
624
690
  results: z.array(searchResultSchema)
625
691
  });
692
+ var liveEventSchema = z.object({
693
+ kind: z.enum([
694
+ "change_request.created",
695
+ "change_request.updated",
696
+ "change_request.deleted",
697
+ "change_request.reviewed",
698
+ "change_request.merged"
699
+ ]),
700
+ spaceId: z.string(),
701
+ actorId: z.string(),
702
+ changeRequestId: z.string(),
703
+ baseId: z.string().nullable(),
704
+ nodeIds: z.array(z.string()),
705
+ recordIds: z.array(z.string()),
706
+ viewIds: z.array(z.string()),
707
+ operationCount: z.number()
708
+ });
626
709
  var auditActionSchema = z.enum([
627
710
  "record.viewed",
628
711
  "change_request.created",
@@ -637,14 +720,18 @@ var auditActionSchema = z.enum([
637
720
  "field.created",
638
721
  "doc.created",
639
722
  "doc.updated",
723
+ "file.created",
640
724
  "skill.created",
725
+ "drive.created",
641
726
  "asset.deleted",
727
+ "asset.metadata_updated",
642
728
  "node.purged"
643
729
  ]);
644
730
  var auditEventSchema = z.object({
645
731
  id: z.string(),
646
732
  action: auditActionSchema,
647
733
  actorId: z.string(),
734
+ actor: userRefSchema.nullable().optional().default(null),
648
735
  baseId: z.string().nullable(),
649
736
  recordId: z.string().nullable(),
650
737
  changeRequestId: z.string().nullable(),
@@ -666,7 +753,13 @@ var createAuditEventInputSchema = z.object({
666
753
  var nodeOperationInputSchema = z.discriminatedUnion("kind", [
667
754
  z.object({
668
755
  kind: z.literal("create"),
756
+ ref: z.string().min(1).optional().describe(
757
+ 'Optional in-change-request temp id for this node. A later operation can set parentNodeRef to this value to nest under it \u2014 e.g. create a folder with ref "growth", then create Bases with parentNodeRef "growth", all in one change request.'
758
+ ),
669
759
  parentNodeId: z.string().optional(),
760
+ parentNodeRef: z.string().min(1).optional().describe(
761
+ "Parent this node under a node an EARLIER operation in the same change request created (matched by its ref). Mutually exclusive with parentNodeId."
762
+ ),
670
763
  nodeType: z.enum(CREATABLE_NODE_TYPES),
671
764
  slug: z.string().min(1).regex(/^[a-z0-9-]+$/),
672
765
  name: z.string().min(1),
@@ -701,7 +794,9 @@ var nodeOperationInputSchema = z.discriminatedUnion("kind", [
701
794
  z.object({
702
795
  kind: z.literal("move"),
703
796
  nodeId: z.string(),
704
- parentNodeId: z.string(),
797
+ // Exactly one of parentNodeId / parentNodeRef (a ref created earlier in this CR).
798
+ parentNodeId: z.string().optional(),
799
+ parentNodeRef: z.string().min(1).optional(),
705
800
  position: z.number().int().optional()
706
801
  })
707
802
  ]);
@@ -710,6 +805,9 @@ var createNodeChangeRequestInputSchema = z.object({
710
805
  'Explanation shown to the human reviewer. Write a conventional-commit style subject \u2014 imperative verb + what + why, e.g. "Reorganize marketing docs under a Campaigns folder".'
711
806
  ),
712
807
  submittedBy: z.string().optional().default("local-producer"),
808
+ autoMerge: z.boolean().optional().default(false).describe(
809
+ "Whether to approve and merge this structural node change immediately. Defaults to false so node Change Request creation is review-first unless explicitly requested."
810
+ ),
713
811
  operations: z.array(nodeOperationInputSchema).min(1)
714
812
  });
715
813
  var createDeleteChangeRequestInputSchema = z.object({
@@ -747,6 +845,25 @@ var createCommentInputSchema = commentSubjectInputSchema.extend({
747
845
  var listInputSchema = z.object({
748
846
  limit: z.coerce.number().int().min(1).max(100).optional().default(50)
749
847
  }).optional().default({ limit: 50 });
848
+ var listChangeRequestsPagedInputSchema = z.object({
849
+ limit: z.coerce.number().int().min(1).max(100).optional().default(50),
850
+ /** Opaque base64 cursor (`createdAt|id`) for keyset pagination. */
851
+ cursor: z.string().optional(),
852
+ status: z.array(changeRequestStatusSchema).optional(),
853
+ mine: z.boolean().optional()
854
+ }).optional().default({ limit: 50 });
855
+ var listChangeRequestsResponseSchema = z.object({
856
+ changeRequests: z.array(changeRequestSchema),
857
+ nextCursor: z.string().nullable()
858
+ });
859
+ var changeRequestCountsSchema = z.object({
860
+ review: z.number().int().nonnegative(),
861
+ changes: z.number().int().nonnegative(),
862
+ created: z.number().int().nonnegative(),
863
+ approved: z.number().int().nonnegative(),
864
+ merged: z.number().int().nonnegative(),
865
+ rejected: z.number().int().nonnegative()
866
+ });
750
867
  var searchInputSchema = z.object({
751
868
  query: z.string().default(""),
752
869
  limit: z.coerce.number().int().min(1).max(100).optional().default(20),
@@ -781,64 +898,6 @@ var authInfoSchema = z.object({
781
898
  */
782
899
  spaces: z.array(authSpaceSchema)
783
900
  });
784
-
785
- // ../../packages/busabase-contract/src/domains/base/contract/record-schemas.ts
786
- var recordSchema = z.object({
787
- id: z.string(),
788
- baseId: z.string(),
789
- headCommitId: z.string(),
790
- parentRecordId: z.string().nullable(),
791
- parentCommitId: z.string().nullable(),
792
- status: z.enum(["active", "archived"]),
793
- createdBy: z.string(),
794
- archivedAt: z.string().nullable(),
795
- createdAt: z.string(),
796
- updatedAt: z.string(),
797
- base: baseSchema,
798
- headCommit: commitSchema
799
- });
800
- var listRecordsInputSchema = z.object({
801
- limit: z.coerce.number().int().min(1).max(100).optional().default(50),
802
- baseId: z.string().optional(),
803
- /** Opaque base64 cursor (`createdAt:id`) for keyset pagination. */
804
- cursor: z.string().optional()
805
- }).optional().default({ limit: 50 });
806
- var listRecordsResponseSchema = z.object({
807
- records: z.array(recordSchema),
808
- nextCursor: z.string().nullable()
809
- });
810
- var createChangeRequestInputSchema = z.object({
811
- fields: z.record(z.string(), z.unknown()).describe(
812
- "Record field values keyed by field slug. The base's PRIMARY field (its first field) becomes the record's display name and the change request title everywhere \u2014 always give it a short, human-readable value, never an id or placeholder."
813
- ),
814
- message: z.string().optional().default("Initial change request").describe(
815
- 'Explanation shown to the human reviewer. Write a conventional-commit style subject \u2014 imperative verb + what + why, e.g. "Add Acme Corp \u2014 qualified lead from the June webinar".'
816
- ),
817
- submittedBy: z.string().optional().default("local-producer")
818
- });
819
- var recordFieldFilterInputSchema = z.object({
820
- baseId: z.string().optional(),
821
- fieldSlug: z.string().min(1),
822
- valueText: z.string().min(1),
823
- limit: z.coerce.number().int().min(1).max(100).optional().default(50)
824
- });
825
- var restoreRecordInputSchema = z.object({
826
- message: z.string().optional(),
827
- submittedBy: z.string().optional().default("local-editor")
828
- });
829
- var recordLinkSchema = z.object({
830
- id: z.string(),
831
- baseId: z.string(),
832
- fieldId: z.string(),
833
- fieldSlug: z.string(),
834
- sourceRecordId: z.string(),
835
- targetBaseId: z.string(),
836
- targetRecordId: z.string(),
837
- commitId: z.string(),
838
- position: z.number(),
839
- createdAt: z.string(),
840
- updatedAt: z.string()
841
- });
842
901
  var viewFilterOperatorSchema = z.enum([
843
902
  "contains",
844
903
  "equals",
@@ -874,6 +933,7 @@ var viewSchema = z.object({
874
933
  config: viewConfigSchema,
875
934
  status: z.enum(["active", "archived"]),
876
935
  createdBy: z.string(),
936
+ createdByUser: userRefSchema.nullable().optional().default(null),
877
937
  archivedAt: z.string().nullable(),
878
938
  createdAt: z.string(),
879
939
  updatedAt: z.string()
@@ -902,7 +962,95 @@ var restoreViewInputSchema = z.object({
902
962
  submittedBy: z.string().optional().default("local-producer")
903
963
  });
904
964
 
905
- // ../../packages/busabase-contract/src/domains/base/contract/routes.ts
965
+ // ../../packages/busabase-contract/src/domains/base/contract/record-schemas.ts
966
+ var recordSchema = z.object({
967
+ id: z.string(),
968
+ baseId: z.string(),
969
+ headCommitId: z.string(),
970
+ parentRecordId: z.string().nullable(),
971
+ parentCommitId: z.string().nullable(),
972
+ status: z.enum(["active", "archived"]),
973
+ createdBy: z.string(),
974
+ createdByUser: userRefSchema.nullable().optional().default(null),
975
+ archivedAt: z.string().nullable(),
976
+ createdAt: z.string(),
977
+ updatedAt: z.string(),
978
+ base: baseSchema,
979
+ headCommit: commitSchema
980
+ });
981
+ var listRecordsFilterSchema = z.object({
982
+ fieldSlug: z.string(),
983
+ fieldType: z.string().optional(),
984
+ operator: viewFilterOperatorSchema,
985
+ value: z.unknown().optional()
986
+ });
987
+ var listRecordsSortSchema = z.object({
988
+ fieldSlug: z.string(),
989
+ fieldType: z.string().optional(),
990
+ direction: z.enum(["asc", "desc"]).optional().default("asc")
991
+ });
992
+ var listRecordsInputSchema = z.object({
993
+ limit: z.coerce.number().int().min(1).max(100).optional().default(50),
994
+ baseId: z.string().optional(),
995
+ /** Opaque base64 cursor for keyset pagination (createdAt-keyed, or sort-keyed when `sort` is set). */
996
+ cursor: z.string().optional(),
997
+ /** View filters for server-side push-down (superset; client still narrows). */
998
+ filters: z.array(listRecordsFilterSchema).optional(),
999
+ /** View sort for server-side push-down (number/date fields only). */
1000
+ sort: listRecordsSortSchema.optional()
1001
+ }).optional().default({ limit: 50 });
1002
+ var listRecordsResponseSchema = z.object({
1003
+ records: z.array(recordSchema),
1004
+ nextCursor: z.string().nullable()
1005
+ });
1006
+ var countRecordsInputSchema = z.object({
1007
+ baseId: z.string().optional()
1008
+ }).optional().default({});
1009
+ var countRecordsResponseSchema = z.object({
1010
+ /** Total active records in the space (optionally scoped to a base). */
1011
+ total: z.number().int().nonnegative()
1012
+ });
1013
+ var createChangeRequestInputSchema = z.object({
1014
+ fields: z.record(z.string(), z.unknown()).describe(
1015
+ "Record field values keyed by field slug. The base's PRIMARY field (its first field) becomes the record's display name and the change request title everywhere \u2014 always give it a short, human-readable value, never an id or placeholder."
1016
+ ),
1017
+ message: z.string().optional().default("Initial change request").describe(
1018
+ 'Explanation shown to the human reviewer. Write a conventional-commit style subject \u2014 imperative verb + what + why, e.g. "Add Acme Corp \u2014 qualified lead from the June webinar".'
1019
+ ),
1020
+ submittedBy: z.string().optional().default("local-producer")
1021
+ });
1022
+ var createBulkChangeRequestInputSchema = z.object({
1023
+ records: z.array(z.record(z.string(), z.unknown())).min(1).max(1e3).describe(
1024
+ "Field-value maps, one per record to create, each keyed by field slug. All records are proposed as a SINGLE change request (one review, one merge) \u2014 use this to import/seed many rows at once instead of one change request per record. Capped at 1000; for very large loads prefer a dedicated import job. Always give each record's PRIMARY field a short human-readable value."
1025
+ ),
1026
+ message: z.string().optional().default("Bulk create records").describe(
1027
+ 'Explanation shown to the human reviewer for the whole batch \u2014 e.g. "Import 240 June webinar leads".'
1028
+ ),
1029
+ submittedBy: z.string().optional().default("local-producer")
1030
+ });
1031
+ var recordFieldFilterInputSchema = z.object({
1032
+ baseId: z.string().optional(),
1033
+ fieldSlug: z.string().min(1),
1034
+ valueText: z.string().min(1),
1035
+ limit: z.coerce.number().int().min(1).max(100).optional().default(50)
1036
+ });
1037
+ var restoreRecordInputSchema = z.object({
1038
+ message: z.string().optional(),
1039
+ submittedBy: z.string().optional().default("local-editor")
1040
+ });
1041
+ var recordLinkSchema = z.object({
1042
+ id: z.string(),
1043
+ baseId: z.string(),
1044
+ fieldId: z.string(),
1045
+ fieldSlug: z.string(),
1046
+ sourceRecordId: z.string(),
1047
+ targetBaseId: z.string(),
1048
+ targetRecordId: z.string(),
1049
+ commitId: z.string(),
1050
+ position: z.number(),
1051
+ createdAt: z.string(),
1052
+ updatedAt: z.string()
1053
+ });
906
1054
  var baseContract = {
907
1055
  list: oc.route({
908
1056
  method: "GET",
@@ -967,6 +1115,13 @@ var baseContract = {
967
1115
  summary: "Create Change Request in Base",
968
1116
  successDescription: "Created change request for review."
969
1117
  }).input(createChangeRequestInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema),
1118
+ createBulkChangeRequest: oc.route({
1119
+ method: "POST",
1120
+ path: "/bases/{baseId}/records/bulk-change-request",
1121
+ tags: ["Bases", "Change Requests"],
1122
+ summary: "Create bulk record Change Request in Base",
1123
+ successDescription: "Created one change request proposing many record creates."
1124
+ }).input(createBulkChangeRequestInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema),
970
1125
  createField: oc.route({
971
1126
  method: "POST",
972
1127
  path: "/bases/{baseId}/fields",
@@ -1060,6 +1215,13 @@ var recordContract = {
1060
1215
  summary: "List records with keyset pagination",
1061
1216
  successDescription: "A page of canonical records plus an opaque nextCursor (null at the end)."
1062
1217
  }).input(listRecordsInputSchema).output(listRecordsResponseSchema),
1218
+ count: oc.route({
1219
+ method: "GET",
1220
+ path: "/records/count",
1221
+ tags: ["Records"],
1222
+ summary: "Count records",
1223
+ successDescription: "Total active records in the space, optionally scoped to a base."
1224
+ }).input(countRecordsInputSchema).output(countRecordsResponseSchema),
1063
1225
  get: oc.route({
1064
1226
  method: "GET",
1065
1227
  path: "/records/{recordId}",
@@ -1192,67 +1354,65 @@ var docContract = {
1192
1354
  successDescription: "Created a change request that proposes a new Doc body."
1193
1355
  }).input(createDocChangeRequestInputSchema.extend({ nodeId: z.string() })).output(changeRequestSchema)
1194
1356
  };
1195
- var folderSchema = z.object({
1196
- node: nodeSchema,
1197
- children: z.array(nodeSchema)
1198
- });
1199
- var folderContract = {
1200
- list: oc.route({
1201
- method: "GET",
1202
- path: "/folders",
1203
- tags: ["Folders"],
1204
- summary: "List Folder nodes",
1205
- successDescription: "Folder nodes with their direct children."
1206
- }).output(z.array(folderSchema)),
1207
- get: oc.route({
1208
- method: "GET",
1209
- path: "/folders/{nodeId}",
1210
- tags: ["Folders"],
1211
- summary: "Get Folder node",
1212
- successDescription: "Folder node and its direct children."
1213
- }).input(z.object({ nodeId: z.string() })).output(folderSchema)
1214
- };
1215
- var skillFileSchema = z.object({
1357
+ var fileTreeFileSchema = z.object({
1216
1358
  path: z.string(),
1217
1359
  name: z.string(),
1218
- type: z.enum(["file", "folder"]),
1219
1360
  size: z.number(),
1220
- updatedAt: z.string().nullable()
1221
- });
1222
- var skillSchema = z.object({
1361
+ updatedAt: z.string().nullable(),
1362
+ mimeType: z.string().nullable(),
1363
+ assetId: z.string(),
1364
+ displayName: z.string().nullable()
1365
+ });
1366
+ var assetFileInputSchema = z.object({
1367
+ path: z.string().min(1),
1368
+ assetId: z.string().min(1),
1369
+ displayName: z.string().optional(),
1370
+ mimeType: z.string().optional()
1371
+ }).strict();
1372
+ var textFileInputSchema = z.object({
1373
+ path: z.string().min(1),
1374
+ content: z.string().default(""),
1375
+ mimeType: z.string().optional()
1376
+ }).strict();
1377
+ var assetFileOperationInputSchema = z.object({
1378
+ kind: z.enum(["create", "update"]),
1379
+ path: z.string().min(1),
1380
+ assetId: z.string().min(1),
1381
+ displayName: z.string().optional(),
1382
+ mimeType: z.string().optional(),
1383
+ baseContentHash: z.string().optional()
1384
+ }).strict();
1385
+ var textFileOperationInputSchema = z.object({
1386
+ kind: z.enum(["create", "update"]),
1387
+ path: z.string().min(1),
1388
+ content: z.string(),
1389
+ mimeType: z.string().optional(),
1390
+ baseContentHash: z.string().optional()
1391
+ }).strict();
1392
+ var fileTreeNodeSchema = z.object({
1223
1393
  node: nodeSchema,
1224
- storagePrefix: z.string(),
1225
1394
  entryFile: z.string(),
1226
1395
  visibility: z.enum(["private", "workspace", "public"]),
1227
1396
  version: z.string(),
1228
- files: z.array(skillFileSchema)
1397
+ files: z.array(fileTreeFileSchema)
1229
1398
  });
1230
- var createSkillInputSchema = z.object({
1399
+ var createFileTreeInputSchema = z.object({
1231
1400
  parentNodeId: z.string().optional(),
1232
1401
  slug: z.string().min(1).regex(/^[a-z0-9-]+$/),
1233
1402
  name: z.string().min(1),
1234
1403
  description: z.string().optional().default(""),
1235
1404
  visibility: z.enum(["private", "workspace", "public"]).optional().default("private"),
1236
1405
  version: z.string().optional().default("0.1.0"),
1237
- files: z.array(
1238
- z.object({
1239
- path: z.string().min(1),
1240
- content: z.string().default("")
1241
- })
1242
- ).optional().default([])
1406
+ files: z.array(z.union([assetFileInputSchema, textFileInputSchema])).optional().default([])
1243
1407
  });
1244
- var skillFileOperationInputSchema = z.discriminatedUnion("kind", [
1245
- z.object({
1246
- kind: z.enum(["create", "update"]),
1247
- path: z.string().min(1),
1248
- content: z.string(),
1249
- baseContentHash: z.string().optional()
1250
- }),
1408
+ var fileTreeFileOperationInputSchema = z.union([
1409
+ assetFileOperationInputSchema,
1410
+ textFileOperationInputSchema,
1251
1411
  z.object({
1252
1412
  kind: z.literal("delete"),
1253
1413
  path: z.string().min(1),
1254
1414
  baseContentHash: z.string().optional()
1255
- }),
1415
+ }).strict(),
1256
1416
  z.object({
1257
1417
  kind: z.literal("metadata_update"),
1258
1418
  metadata: z.object({
@@ -1260,68 +1420,228 @@ var skillFileOperationInputSchema = z.discriminatedUnion("kind", [
1260
1420
  visibility: z.enum(["private", "workspace", "public"]).optional(),
1261
1421
  version: z.string().optional()
1262
1422
  }).default({})
1263
- })
1423
+ }).strict()
1264
1424
  ]);
1265
- var createSkillChangeRequestInputSchema = z.object({
1266
- message: z.string().optional().default("Update skill").describe(
1267
- 'Explanation shown to the human reviewer. Write a conventional-commit style subject \u2014 imperative verb + what + why, e.g. "Rewrite SKILL.md quickstart for the new auth flow".'
1425
+ var createFileTreeChangeRequestInputSchema = z.object({
1426
+ message: z.string().optional().default("Update file tree").describe(
1427
+ 'Explanation shown to the human reviewer. Write a conventional-commit style subject \u2014 imperative verb + what + why, e.g. "Rewrite README.md quickstart for the new auth flow".'
1268
1428
  ),
1269
1429
  submittedBy: z.string().optional().default("local-producer"),
1270
- operations: z.array(skillFileOperationInputSchema).min(1)
1430
+ operations: z.array(fileTreeFileOperationInputSchema).min(1)
1431
+ });
1432
+ var makeFileTreeContract = (routeBase, tag) => {
1433
+ const label = tag.endsWith("s") ? tag.slice(0, -1) : tag;
1434
+ const basePath = `/${routeBase}`;
1435
+ return {
1436
+ list: oc.route({
1437
+ method: "GET",
1438
+ path: basePath,
1439
+ tags: [tag],
1440
+ summary: `List ${label} nodes`,
1441
+ successDescription: `${label} nodes with their Asset-backed file trees.`
1442
+ }).output(z.array(fileTreeNodeSchema)),
1443
+ create: oc.route({
1444
+ method: "POST",
1445
+ path: basePath,
1446
+ tags: [tag],
1447
+ summary: `Create ${label} node`,
1448
+ successDescription: `Created ${label} node and initialized file tree.`
1449
+ }).input(createFileTreeInputSchema).output(fileTreeNodeSchema),
1450
+ get: oc.route({
1451
+ method: "GET",
1452
+ path: `${basePath}/{nodeId}`,
1453
+ tags: [tag],
1454
+ summary: `Get ${label} node`,
1455
+ successDescription: `${label} node detail and file tree.`
1456
+ }).input(z.object({ nodeId: z.string() })).output(fileTreeNodeSchema),
1457
+ listFiles: oc.route({
1458
+ method: "GET",
1459
+ path: `${basePath}/{nodeId}/files`,
1460
+ tags: [tag],
1461
+ summary: `List ${label} files`,
1462
+ successDescription: `Asset-backed files mounted under the ${label} node.`
1463
+ }).input(z.object({ nodeId: z.string() })).output(z.array(fileTreeFileSchema)),
1464
+ readFile: oc.route({
1465
+ method: "GET",
1466
+ path: `${basePath}/{nodeId}/files/{+filePath}`,
1467
+ tags: [tag],
1468
+ summary: `Read ${label} file`,
1469
+ successDescription: `${label} file content and content hash.`
1470
+ }).input(z.object({ nodeId: z.string(), filePath: z.string() })).output(
1471
+ z.object({
1472
+ nodeId: z.string(),
1473
+ path: z.string(),
1474
+ encoding: z.enum(["utf8", "url"]),
1475
+ content: z.string(),
1476
+ mimeType: z.string(),
1477
+ assetId: z.string(),
1478
+ displayName: z.string().nullable(),
1479
+ assetUrl: z.string().nullable(),
1480
+ contentHash: z.string()
1481
+ })
1482
+ ),
1483
+ createChangeRequest: oc.route({
1484
+ method: "POST",
1485
+ path: `${basePath}/{nodeId}/change-requests`,
1486
+ tags: [tag, "Change Requests"],
1487
+ summary: `Create ${label} change request`,
1488
+ successDescription: `Created file-tree change request for a ${label} node.`
1489
+ }).input(createFileTreeChangeRequestInputSchema.extend({ nodeId: z.string() })).output(changeRequestSchema)
1490
+ };
1491
+ };
1492
+
1493
+ // ../../packages/busabase-contract/src/domains/drive/contract.ts
1494
+ var driveContract = makeFileTreeContract("drives", "Drives");
1495
+ z.object({
1496
+ assetId: z.string()
1497
+ });
1498
+ var FileNodeVOSchema = z.object({
1499
+ node: nodeSchema,
1500
+ asset: AssetVOSchema
1501
+ });
1502
+
1503
+ // ../../packages/busabase-contract/src/domains/file-node/contract.ts
1504
+ var createFileNodeInputSchema = z.object({
1505
+ parentNodeId: z.string().optional(),
1506
+ slug: z.string().min(1).regex(/^[a-z0-9-]+$/),
1507
+ name: z.string().min(1),
1508
+ description: z.string().optional().default(""),
1509
+ assetId: z.string().min(1)
1271
1510
  });
1272
- var skillContract = {
1511
+ var fileContract = {
1273
1512
  list: oc.route({
1274
1513
  method: "GET",
1275
- path: "/skills",
1276
- tags: ["Skills"],
1277
- summary: "List Skill nodes",
1278
- successDescription: "Skill nodes with their storage-backed file trees."
1279
- }).output(z.array(skillSchema)),
1514
+ path: "/files",
1515
+ tags: ["Files"],
1516
+ summary: "List File nodes",
1517
+ successDescription: "Workspace File nodes with their backing Asset metadata."
1518
+ }).output(z.array(FileNodeVOSchema)),
1280
1519
  create: oc.route({
1281
1520
  method: "POST",
1282
- path: "/skills",
1283
- tags: ["Skills"],
1284
- summary: "Create Skill node",
1285
- successDescription: "Created Skill node and initialized file tree."
1286
- }).input(createSkillInputSchema).output(skillSchema),
1521
+ path: "/files",
1522
+ tags: ["Files"],
1523
+ summary: "Create File node",
1524
+ successDescription: "Created a first-class File node that references an Asset."
1525
+ }).input(createFileNodeInputSchema).output(FileNodeVOSchema),
1287
1526
  get: oc.route({
1288
1527
  method: "GET",
1289
- path: "/skills/{nodeId}",
1290
- tags: ["Skills"],
1291
- summary: "Get Skill node",
1292
- successDescription: "Skill node detail and file tree."
1293
- }).input(z.object({ nodeId: z.string() })).output(skillSchema),
1294
- listFiles: oc.route({
1528
+ path: "/files/{nodeId}",
1529
+ tags: ["Files"],
1530
+ summary: "Get File node",
1531
+ successDescription: "File node detail and backing Asset metadata."
1532
+ }).input(z.object({ nodeId: z.string() })).output(FileNodeVOSchema)
1533
+ };
1534
+ var folderSchema = z.object({
1535
+ node: nodeSchema,
1536
+ children: z.array(nodeSchema)
1537
+ });
1538
+ var folderContract = {
1539
+ list: oc.route({
1295
1540
  method: "GET",
1296
- path: "/skills/{nodeId}/files",
1297
- tags: ["Skills"],
1298
- summary: "List Skill files",
1299
- successDescription: "Storage-backed files under the Skill node prefix."
1300
- }).input(z.object({ nodeId: z.string() })).output(z.array(skillFileSchema)),
1301
- readFile: oc.route({
1541
+ path: "/folders",
1542
+ tags: ["Folders"],
1543
+ summary: "List Folder nodes",
1544
+ successDescription: "Folder nodes with their direct children."
1545
+ }).output(z.array(folderSchema)),
1546
+ get: oc.route({
1302
1547
  method: "GET",
1303
- path: "/skills/{nodeId}/files/{+filePath}",
1304
- tags: ["Skills"],
1305
- summary: "Read Skill file",
1306
- successDescription: "Skill file content and content hash."
1307
- }).input(z.object({ nodeId: z.string(), filePath: z.string() })).output(
1308
- z.object({
1309
- nodeId: z.string(),
1310
- path: z.string(),
1311
- content: z.string(),
1312
- contentHash: z.string()
1313
- })
1314
- ),
1315
- createChangeRequest: oc.route({
1316
- method: "POST",
1317
- path: "/skills/{nodeId}/change-requests",
1318
- tags: ["Skills", "Change Requests"],
1319
- summary: "Create Skill change request",
1320
- successDescription: "Created file-tree change request for a Skill node."
1321
- }).input(createSkillChangeRequestInputSchema.extend({ nodeId: z.string() })).output(changeRequestSchema)
1548
+ path: "/folders/{nodeId}",
1549
+ tags: ["Folders"],
1550
+ summary: "Get Folder node",
1551
+ successDescription: "Folder node and its direct children."
1552
+ }).input(z.object({ nodeId: z.string() })).output(folderSchema)
1553
+ };
1554
+
1555
+ // ../../packages/busabase-contract/src/domains/skill/contract.ts
1556
+ var skillContract = makeFileTreeContract("skills", "Skills");
1557
+ var VaultItemKeySchema = z.string().trim().min(1).max(128).regex(/^[A-Z_][A-Z0-9_]*$/, "Use uppercase letters, numbers, and underscores");
1558
+ var VaultItemValueSchema = z.string().max(8192);
1559
+ var VaultItemKindSchema = z.enum(["secret", "variable"]);
1560
+ var VaultScopeTypeSchema = z.enum([
1561
+ "personal",
1562
+ "workspace",
1563
+ "base",
1564
+ "agent",
1565
+ "tool",
1566
+ "api_key"
1567
+ ]);
1568
+ var VaultEnvironmentSchema = z.enum(["local", "development", "staging", "production"]);
1569
+ var VaultAccessPolicySchema = z.object({
1570
+ runtime: z.boolean().default(true),
1571
+ reveal: z.boolean().default(true),
1572
+ edit: z.boolean().default(true),
1573
+ share: z.boolean().default(false)
1574
+ });
1575
+ var VaultItemInputSchema = z.object({
1576
+ id: z.string().optional(),
1577
+ kind: VaultItemKindSchema,
1578
+ key: VaultItemKeySchema,
1579
+ value: VaultItemValueSchema,
1580
+ scopeType: VaultScopeTypeSchema.default("personal"),
1581
+ scopeId: z.string().trim().nullable().optional(),
1582
+ environment: VaultEnvironmentSchema.default("local"),
1583
+ description: z.string().trim().max(512).default(""),
1584
+ access: VaultAccessPolicySchema.default({
1585
+ runtime: true,
1586
+ reveal: true,
1587
+ edit: true,
1588
+ share: false
1589
+ })
1590
+ });
1591
+ var UpdateVaultSettingsInputSchema = z.object({
1592
+ items: z.array(VaultItemInputSchema).max(200)
1593
+ });
1594
+ var VaultItemVOSchema = VaultItemInputSchema.extend({
1595
+ id: z.string(),
1596
+ scopeId: z.string().nullable(),
1597
+ updatedAt: z.string(),
1598
+ createdAt: z.string(),
1599
+ lastUsedAt: z.string().nullable()
1600
+ });
1601
+ var VaultSettingsVOSchema = z.object({
1602
+ ownerId: z.string().nullable(),
1603
+ items: z.array(VaultItemVOSchema),
1604
+ updatedAt: z.string().nullable()
1605
+ });
1606
+ z.record(VaultItemKeySchema, VaultItemValueSchema).default({});
1607
+ var VaultSuccessSchema = z.object({ success: z.boolean() });
1608
+
1609
+ // ../../packages/busabase-contract/src/domains/vault/contract.ts
1610
+ var vaultContract = {
1611
+ get: oc.route({
1612
+ method: "GET",
1613
+ path: "/vault",
1614
+ tags: ["Vault"],
1615
+ summary: "Get local Vault settings",
1616
+ successDescription: "Local Vault secrets and variables for this Busabase instance."
1617
+ }).output(VaultSettingsVOSchema),
1618
+ update: oc.route({
1619
+ method: "PUT",
1620
+ path: "/vault",
1621
+ tags: ["Vault"],
1622
+ summary: "Replace local Vault settings",
1623
+ successDescription: "Updated local Vault secrets and variables."
1624
+ }).input(UpdateVaultSettingsInputSchema).output(VaultSettingsVOSchema),
1625
+ clear: oc.route({
1626
+ method: "DELETE",
1627
+ path: "/vault",
1628
+ tags: ["Vault"],
1629
+ summary: "Clear local Vault settings",
1630
+ successDescription: "Removed local Vault secrets and variables."
1631
+ }).output(VaultSuccessSchema)
1322
1632
  };
1323
1633
 
1324
1634
  // ../../packages/busabase-contract/src/contract/busabase.ts
1635
+ var changeRequestBatchResultSchema = z.object({
1636
+ results: z.array(
1637
+ z.object({
1638
+ changeRequestId: z.string(),
1639
+ ok: z.boolean(),
1640
+ status: z.string().optional(),
1641
+ error: z.string().optional()
1642
+ })
1643
+ )
1644
+ });
1325
1645
  var busabaseContractRoutes = {
1326
1646
  auth: {
1327
1647
  verify: oc.route({
@@ -1337,7 +1657,7 @@ var busabaseContractRoutes = {
1337
1657
  path: "/search",
1338
1658
  tags: ["Search"],
1339
1659
  summary: "Search Busabase",
1340
- successDescription: "Paginated search results across records, change requests, and Bases."
1660
+ successDescription: "Paginated search results across records, change requests, Bases, File nodes, and Assets."
1341
1661
  }).input(searchInputSchema).output(searchResponseSchema),
1342
1662
  nodes: {
1343
1663
  list: oc.route({
@@ -1410,12 +1730,19 @@ var busabaseContractRoutes = {
1410
1730
  successDescription: "Change requests awaiting an external agent (request-changes or @ai mentions)."
1411
1731
  }).output(z.array(agentTaskSchema))
1412
1732
  },
1733
+ live: {
1734
+ // RPC-only by design: no `.route(...)`, so OpenAPI generation and MCP tool
1735
+ // discovery skip this long-lived Event Iterator while `/api/rpc` stays typed.
1736
+ subscribe: oc.output(eventIterator(liveEventSchema))
1737
+ },
1413
1738
  bases: baseContract,
1414
1739
  skills: skillContract,
1740
+ drives: driveContract,
1741
+ files: fileContract,
1415
1742
  docs: docContract,
1416
1743
  folders: folderContract,
1417
- attachments: attachmentsContract,
1418
1744
  assets: assetsContract,
1745
+ vault: vaultContract,
1419
1746
  changeRequests: {
1420
1747
  list: oc.route({
1421
1748
  method: "GET",
@@ -1424,6 +1751,20 @@ var busabaseContractRoutes = {
1424
1751
  summary: "List change requests",
1425
1752
  successDescription: "Change requests waiting for review or ready to merge."
1426
1753
  }).input(listInputSchema).output(z.array(changeRequestSchema)),
1754
+ listPaged: oc.route({
1755
+ method: "GET",
1756
+ path: "/change-requests/paged",
1757
+ tags: ["Change Requests"],
1758
+ summary: "List change requests with keyset pagination",
1759
+ successDescription: "A page of change requests plus an opaque nextCursor (null at the end). Filter with `status` and/or `mine`."
1760
+ }).input(listChangeRequestsPagedInputSchema).output(listChangeRequestsResponseSchema),
1761
+ counts: oc.route({
1762
+ method: "GET",
1763
+ path: "/change-requests/counts",
1764
+ tags: ["Change Requests"],
1765
+ summary: "Count change requests by inbox tab",
1766
+ successDescription: "Whole-space change request counts per inbox tab (review / changes / created / approved / merged / rejected)."
1767
+ }).output(changeRequestCountsSchema),
1427
1768
  get: oc.route({
1428
1769
  method: "GET",
1429
1770
  path: "/change-requests/{changeRequestId}",
@@ -1438,6 +1779,17 @@ var busabaseContractRoutes = {
1438
1779
  summary: "Review change request",
1439
1780
  successDescription: "Reviewed change request."
1440
1781
  }).input(reviewChangeRequestInputSchema.extend({ changeRequestId: z.string() })).output(changeRequestSchema),
1782
+ reviewMany: oc.route({
1783
+ method: "POST",
1784
+ path: "/change-requests/reviews",
1785
+ tags: ["Change Requests"],
1786
+ summary: "Review many change requests",
1787
+ successDescription: "Per-change-request review results (failures isolated \u2014 one bad id does not abort the rest)."
1788
+ }).input(
1789
+ reviewChangeRequestInputSchema.extend({
1790
+ changeRequestIds: z.array(z.string()).min(1).max(100)
1791
+ })
1792
+ ).output(changeRequestBatchResultSchema),
1441
1793
  close: oc.route({
1442
1794
  method: "POST",
1443
1795
  path: "/change-requests/{changeRequestId}/close",
@@ -1457,7 +1809,14 @@ var busabaseContractRoutes = {
1457
1809
  record: recordSchema.nullable(),
1458
1810
  view: viewSchema.nullable()
1459
1811
  })
1460
- )
1812
+ ),
1813
+ mergeMany: oc.route({
1814
+ method: "POST",
1815
+ path: "/change-requests/merge",
1816
+ tags: ["Change Requests"],
1817
+ summary: "Merge many change requests",
1818
+ successDescription: "Per-change-request merge results (each merged in its own transaction; failures isolated)."
1819
+ }).input(z.object({ changeRequestIds: z.array(z.string()).min(1).max(100) })).output(changeRequestBatchResultSchema)
1461
1820
  },
1462
1821
  operations: {
1463
1822
  revise: oc.route({
@@ -1527,6 +1886,7 @@ var notFoundErrors = {
1527
1886
  data: ErrorResponseSchema
1528
1887
  }
1529
1888
  };
1889
+ var { vault: _localVault, ...cloudWorkbenchRoutes } = busabaseContractRoutes;
1530
1890
  var cloudExtraRoutes = {
1531
1891
  system: {
1532
1892
  health: oc.route({
@@ -1607,7 +1967,7 @@ var cloudExtraRoutes = {
1607
1967
  }
1608
1968
  };
1609
1969
  var cloudContract = oc.prefix("/api/v1").router({
1610
- ...busabaseContractRoutes,
1970
+ ...cloudWorkbenchRoutes,
1611
1971
  ...cloudExtraRoutes
1612
1972
  });
1613
1973
 
@@ -1688,12 +2048,18 @@ var Busabase = class {
1688
2048
  get agent() {
1689
2049
  return this.client.agent;
1690
2050
  }
1691
- get attachments() {
1692
- return this.client.attachments;
2051
+ get assets() {
2052
+ return this.client.assets;
1693
2053
  }
1694
2054
  get skills() {
1695
2055
  return this.client.skills;
1696
2056
  }
2057
+ get drives() {
2058
+ return this.client.drives;
2059
+ }
2060
+ get files() {
2061
+ return this.client.files;
2062
+ }
1697
2063
  get docs() {
1698
2064
  return this.client.docs;
1699
2065
  }