@ref0/sdk 0.5.0 → 0.7.0

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/client.mjs CHANGED
@@ -1266,7 +1266,9 @@ const FindingRef = Schema.Struct({
1266
1266
  * Who a passkey request asks: the accountable person; a person, by their name; or anyone holding
1267
1267
  * one of the repo's permissions, the first of whom to answer decides. Until a permission's holders
1268
1268
  * are kept, they're its owner's admins. A workflow run's `passkey.run` asks its run's accountable
1269
- * person; a gate's `passkey.check` asks the person behind the run that meets its need.
1269
+ * person; a gate's `passkey.check` asks the person behind the run that meets its need. A person or
1270
+ * a permission is someone else, a second pair of eyes, so the person `'accountable'` would ask
1271
+ * never answers it: a request with nobody else to ask is refused.
1270
1272
  */
1271
1273
  const PasskeyFrom = Schema.Union([
1272
1274
  Schema.Literal("accountable"),
@@ -3353,14 +3355,10 @@ const durationOf = (least, most, bounds) => Schema.String.check(Schema.makeFilte
3353
3355
  /** A check run's timeout, as its file writes it: 45 minutes unless it says, and 6 hours at most. */
3354
3356
  const CheckRunTimeout = durationOf(1, 21600, "from a second to 6 hours");
3355
3357
  /**
3356
- * When ref0 starts a check itself: on each `change`, before the change joins `main`; on the
3357
- * merge queue's `tip`, before `main` moves, so it guards `main`; or on what `deployed`.
3358
+ * When ref0 starts a check itself: on each `change`, before the change joins `main`; or on the
3359
+ * merge queue's `tip`, before `main` moves, so it guards `main`.
3358
3360
  */
3359
- const CheckTrigger = Schema.Literals([
3360
- "change",
3361
- "tip",
3362
- "deployed"
3363
- ]);
3361
+ const CheckTrigger = Schema.Literals(["change", "tip"]);
3364
3362
  /**
3365
3363
  * Each time ref0 starts a check itself, each once: `['change', 'tip']` unless its file says, and
3366
3364
  * `[]` for a check other code calls or people run by hand. Whether any other start may make a new
@@ -6420,41 +6418,51 @@ const PasskeyList = Schema.Struct({
6420
6418
  var PasskeyRefused = class extends Schema.TaggedError()("PasskeyRefused", { nextStep: Schema.String }, { httpApiStatus: 400 }) {};
6421
6419
  //#endregion
6422
6420
  //#region ../contracts/src/attachments.ts
6423
- /**
6424
- * `ref0 connect`, as agent-connect builds it: a machine asks first, with no credential, to connect
6425
- * to one of an owner's agents, and its terminal shows a code; the owner's person types it under
6426
- * Waiting on you and answers, with their passkey for a yes; and the machine collects its host
6427
- * grant with a secret it made.
6428
- */
6421
+ /** A machine asks, a signed-in person claims and approves, and the answer returns to its terminal. */
6429
6422
  /** A machine's own word for itself: shown to the person as what it says, never as fact. */
6430
6423
  const MachineName = Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(64));
6431
6424
  /** The harness a machine says it connects for, never proof of what it runs. */
6432
6425
  const ConnectHarness = Schema.Literals(["claude-code", "codex"]);
6433
- /**
6434
- * An attachment request: `ref0 connect --owner <name>` asking, with no credential, to connect this
6435
- * machine to one of that owner's agents. It names the owner, the machine, and the hashes of two
6436
- * secrets it made: the host grant's, which ref0 first sees when the grant is used, and another it
6437
- * collects with, so the grant's own secret never goes to ref0 before then. Its terminal shows the
6438
- * code its answer gives, which the owner's person types under Waiting on you.
6439
- */
6426
+ /** The machine's loopback listener; no caller may choose its host. */
6427
+ const AttachmentCallback = Schema.Struct({
6428
+ port: Schema.Int.check(Schema.isBetween({
6429
+ minimum: 1024,
6430
+ maximum: 65535
6431
+ })),
6432
+ state: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{22}$/))
6433
+ });
6434
+ /** A config folder's path, as the machine shows it, never proof of its location. */
6435
+ const ConfigFolderPath = Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(200), Schema.isPattern(/^[^\p{C}\p{Zl}\p{Zp}]+$/u));
6436
+ const uniqueFolderPaths = Schema.makeFilter((folders) => new Set(folders.map((folder) => folder.path)).size === folders.length, { expected: "unique config folder paths" });
6437
+ const RequestFolder = Schema.Struct({
6438
+ path: ConfigFolderPath,
6439
+ harness: ConnectHarness,
6440
+ secretHash: SecretHash,
6441
+ replaces: Schema.optionalKey(TokenId)
6442
+ });
6443
+ /** One to eight config folders, each with its own grant secret. */
6440
6444
  const RequestAttachment = Schema.Struct({
6441
- owner: OwnerName,
6442
6445
  machine: MachineId,
6443
6446
  machineName: MachineName,
6444
- harness: Schema.optionalKey(ConnectHarness),
6445
- secretHash: SecretHash,
6446
- collectHash: SecretHash
6447
+ folders: Schema.Array(RequestFolder).check(Schema.isMinLength(1), Schema.isMaxLength(8), uniqueFolderPaths),
6448
+ collectHash: SecretHash,
6449
+ linkHash: SecretHash,
6450
+ callback: Schema.optionalKey(AttachmentCallback)
6447
6451
  });
6448
6452
  /** An attachment request, as its person reads it once they type its code. */
6449
6453
  const AttachmentRequestView = Schema.Struct({
6450
6454
  approval: ApprovalId,
6451
6455
  /** The machine's own word for itself, never fact. */
6452
6456
  machineName: MachineName,
6453
- /** The harness the machine says it uses, never fact. */
6454
- harness: Schema.optionalKey(ConnectHarness),
6457
+ folders: Schema.Array(Schema.Struct({
6458
+ path: ConfigFolderPath,
6459
+ harness: ConnectHarness,
6460
+ replaces: Schema.optionalKey(TokenId)
6461
+ })),
6455
6462
  askedFrom: Schema.optionalKey(Schema.String),
6456
6463
  askedAt: Timestamp,
6457
- expiresAt: Timestamp
6464
+ expiresAt: Timestamp,
6465
+ callback: Schema.optionalKey(AttachmentCallback)
6458
6466
  });
6459
6467
  /**
6460
6468
  * What its answerer chooses to connect a machine's request to: one of the person's own agents,
@@ -6478,6 +6486,16 @@ const ConnectOrganization = Schema.Struct({
6478
6486
  organization: OrgId,
6479
6487
  name: OwnerName
6480
6488
  });
6489
+ /** Whether admission replaced a live host grant, or skipped one that no longer belongs here. */
6490
+ const GrantReplacement = Schema.Struct({
6491
+ grant: TokenId,
6492
+ state: Schema.Literals([
6493
+ "replaces",
6494
+ "revoked",
6495
+ "skipped"
6496
+ ]),
6497
+ attachedAt: Schema.optionalKey(Timestamp)
6498
+ });
6481
6499
  /**
6482
6500
  * What a yes would connect the machine to, as options resolved the choice: the agent, or none
6483
6501
  * yet, to make with the handle; and each organization its attachment is authorized in.
@@ -6485,22 +6503,32 @@ const ConnectOrganization = Schema.Struct({
6485
6503
  const ConnectChosen = Schema.Struct({
6486
6504
  agent: Schema.optionalKey(AgentRef),
6487
6505
  handle: AgentHandle,
6488
- organizations: Schema.Array(ConnectOrganization)
6506
+ organizations: Schema.Array(ConnectOrganization),
6507
+ replacement: Schema.optionalKey(GrantReplacement)
6489
6508
  });
6490
- /**
6491
- * A machine's request, as its answerer chooses what it connects to. Without a choice: the
6492
- * request and the person's agents that are on, and nothing chosen for them. With one: the
6493
- * request, what the choice resolved to, and the passkey's options, whose challenge signs over
6494
- * the connect it would run.
6495
- */
6496
- const ConnectOptions = Schema.Union([Schema.Struct({
6497
- request: AttachmentRequestView,
6498
- agents: Schema.Array(ConnectableAgent)
6509
+ /** A complete choice: name every folder once, leaving at least one in. */
6510
+ const ConnectFolderChoice = Schema.Union([Schema.Struct({
6511
+ path: ConfigFolderPath,
6512
+ excluded: Schema.Literal(true)
6499
6513
  }), Schema.Struct({
6514
+ path: ConfigFolderPath,
6515
+ agent: ConnectAgent
6516
+ })]);
6517
+ const ConnectFolderChoices = Schema.Array(ConnectFolderChoice).check(Schema.isMinLength(1), Schema.isMaxLength(8), uniqueFolderPaths);
6518
+ const ConnectFolderOption = Schema.Union([Schema.Struct({
6519
+ path: ConfigFolderPath,
6520
+ excluded: Schema.Literal(true)
6521
+ }), Schema.Struct({
6522
+ path: ConfigFolderPath,
6523
+ connect: ConnectChosen
6524
+ })]);
6525
+ /** Defaults and explicit choices both resolve the entire request and sign one challenge. */
6526
+ const ConnectOptions = Schema.Struct({
6500
6527
  request: AttachmentRequestView,
6501
- connect: ConnectChosen,
6528
+ agents: Schema.Array(ConnectableAgent),
6529
+ folders: Schema.Array(ConnectFolderOption),
6502
6530
  passkey: PasskeyRequestOptions
6503
- })]);
6531
+ });
6504
6532
  /** Why connecting connected nothing, said for the person. */
6505
6533
  const AttachmentFailure = Schema.Struct({
6506
6534
  reason: Schema.Literals([
@@ -6528,11 +6556,9 @@ const RequestOrganization = Schema.Struct({
6528
6556
  ])
6529
6557
  });
6530
6558
  /**
6531
- * Where a machine's request stands, for the machine that asked, by its collecting secret: waiting,
6532
- * or how it ended. Every answer but waiting is final, but a connect nobody confirmed 10 minutes
6533
- * after it connected fails `not confirmed` once ref0 takes its grant to revoke it. Connected
6534
- * names the owner by its name, and the host grant, whose token the machine makes from its ID and
6535
- * the grant's secret.
6559
+ * The result collected with the machine's two proofs: each included folder's identity and grant,
6560
+ * its agent's owner name and organizations, and excluded paths. Confirmation checks each saved
6561
+ * grant's live deadline in the Owner DO.
6536
6562
  */
6537
6563
  const RequestState = Schema.Union([
6538
6564
  Schema.Struct({
@@ -6542,20 +6568,30 @@ const RequestState = Schema.Union([
6542
6568
  Schema.Struct({
6543
6569
  state: Schema.Literal("connected"),
6544
6570
  owner: OwnerName,
6545
- agent: AgentRef,
6546
- handle: AgentHandle,
6547
- credential: CredentialRef,
6548
- organizations: Schema.Array(RequestOrganization)
6571
+ folders: Schema.Array(Schema.Struct({
6572
+ path: ConfigFolderPath,
6573
+ owner: OwnerName,
6574
+ ...MachineConnected.fields,
6575
+ organizations: Schema.Array(RequestOrganization),
6576
+ replacement: Schema.optionalKey(GrantReplacement)
6577
+ })),
6578
+ excluded: Schema.Array(ConfigFolderPath)
6549
6579
  }),
6550
6580
  Schema.Struct({ state: Schema.Literal("refused") }),
6551
6581
  Schema.Struct({ state: Schema.Literal("aborted") }),
6552
6582
  Schema.Struct({ state: Schema.Literal("expired") }),
6553
6583
  Schema.Struct({
6554
6584
  state: Schema.Literal("failed"),
6555
- reason: Schema.Literals([...AttachmentFailure.fields.reason.literals, "not confirmed"]),
6585
+ reason: AttachmentFailure.fields.reason,
6556
6586
  nextStep: Schema.String
6557
6587
  })
6558
6588
  ]);
6589
+ /** The grant IDs saved by this terminal, each belonging to the same admission. */
6590
+ const SavedMachineGrants = Schema.Array(TokenId).check(Schema.isMinLength(1), Schema.isMaxLength(8), Schema.isUnique());
6591
+ Schema.Struct({
6592
+ approval: ApprovalId,
6593
+ grants: SavedMachineGrants
6594
+ });
6559
6595
  /**
6560
6596
  * The machine saying it saved the grant it collected: confirmed, the same again, or not, once ref0
6561
6597
  * has taken the grant to revoke it, and the machine deletes what it saved.
@@ -6588,21 +6624,34 @@ const AuthorizeIn = Schema.Struct({
6588
6624
  organization: OrgId,
6589
6625
  targetGeneration: TargetGeneration
6590
6626
  });
6591
- /** What every connect names: the agent, the machine and its host grant, and what it was bound to. */
6592
- const connectFields = {
6627
+ /** One folder admitted under the request's machine and approving browser. */
6628
+ const ConnectFolderCommand = Schema.Struct({
6629
+ path: ConfigFolderPath,
6593
6630
  agent: AttachmentAgent,
6594
- machine: MachineId,
6595
- machineName: MachineName,
6596
6631
  token: TokenId,
6597
6632
  secretHash: SecretHash,
6598
- browserSession: TokenId,
6599
- personGeneration: Generation,
6633
+ replaces: Schema.optionalKey(TokenId),
6600
6634
  authorizeIn: Schema.Array(AuthorizeIn)
6601
- };
6635
+ });
6602
6636
  Schema.Struct({
6603
6637
  request: ApprovalId,
6604
- ...connectFields
6638
+ machine: MachineId,
6639
+ machineName: MachineName,
6640
+ browserSession: TokenId,
6641
+ personGeneration: Generation,
6642
+ folders: Schema.Array(ConnectFolderCommand).check(Schema.isMinLength(1), Schema.isMaxLength(8), uniqueFolderPaths),
6643
+ excluded: Schema.Array(ConfigFolderPath).check(Schema.isMaxLength(7), Schema.isUnique())
6644
+ });
6645
+ const FoldersConnected = Schema.Struct({
6646
+ folders: Schema.Array(Schema.Struct({
6647
+ path: ConfigFolderPath,
6648
+ ...MachineConnected.fields,
6649
+ replacement: Schema.optionalKey(GrantReplacement)
6650
+ })),
6651
+ excluded: Schema.Array(ConfigFolderPath)
6605
6652
  });
6653
+ Schema.Array(GrantReplacement);
6654
+ Schema.Array(TokenId).check(Schema.isMaxLength(8));
6606
6655
  /** An attachment that isn't there, or isn't the caller's, answers the same. */
6607
6656
  var AttachmentNotFound = class extends Schema.TaggedError()("AttachmentNotFound", { nextStep: Schema.String }, { httpApiStatus: 404 }) {};
6608
6657
  /** Connecting connected nothing, and why: what an attachment's approval came to instead. */
@@ -6776,7 +6825,7 @@ const ApprovalsWaiting = Schema.Struct({
6776
6825
  requests: Schema.Array(AttachmentRequestView)
6777
6826
  });
6778
6827
  /** Finding a terminal's request by the code it showed. */
6779
- const FindApproval = Schema.Struct({ code: TypedApprovalCode });
6828
+ const FindApproval = Schema.Union([Schema.Struct({ code: TypedApprovalCode }), Schema.Struct({ link: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{22}$/)) })]);
6780
6829
  /**
6781
6830
  * Asking for the passkey's options to answer a request: a terminal's request needs its code
6782
6831
  * again, so its ID alone, which travels where its code doesn't, never answers it. A machine's
@@ -6784,7 +6833,7 @@ const FindApproval = Schema.Struct({ code: TypedApprovalCode });
6784
6833
  */
6785
6834
  const ApprovalOptionsRequest = Schema.Struct({
6786
6835
  code: Schema.optionalKey(TypedApprovalCode),
6787
- agent: Schema.optionalKey(ConnectAgent)
6836
+ folders: Schema.optionalKey(ConnectFolderChoices)
6788
6837
  });
6789
6838
  /**
6790
6839
  * An answer: yes, with the passkey, or no. For an agent's ask, each answer can set the owner's
@@ -6837,7 +6886,11 @@ const ApprovalState = Schema.Union([
6837
6886
  state: Schema.Literal("waiting"),
6838
6887
  expiresAt: Timestamp
6839
6888
  }),
6840
- Schema.Struct({ state: Schema.Literal("approved") }),
6889
+ Schema.Struct({
6890
+ state: Schema.Literal("approved"),
6891
+ /** A machine's answering browser may forget its saved answer once the terminal kept it. */
6892
+ collected: Schema.optionalKey(Schema.Literal(true))
6893
+ }),
6841
6894
  Schema.Struct({ state: Schema.Literal("refused") }),
6842
6895
  Schema.Struct({ state: Schema.Literal("expired") }),
6843
6896
  Schema.Struct({
@@ -6846,6 +6899,18 @@ const ApprovalState = Schema.Union([
6846
6899
  ...Ran.fields
6847
6900
  })
6848
6901
  ]);
6902
+ /** Only the answering browser receives a machine's answer code; state reads never carry it. */
6903
+ const ApprovalAnswer = Schema.Union([
6904
+ Schema.Struct({
6905
+ ...ApprovalState.members[1].fields,
6906
+ answerCode: ApprovalCode
6907
+ }),
6908
+ Schema.Struct({
6909
+ ...ApprovalState.members[4].fields,
6910
+ answerCode: ApprovalCode
6911
+ }),
6912
+ ApprovalState
6913
+ ]);
6849
6914
  /** A request that isn't there, or isn't the caller's to see, answers the same. */
6850
6915
  var ApprovalNotFound = class extends Schema.TaggedError()("ApprovalNotFound", { nextStep: Schema.String }, { httpApiStatus: 404 }) {};
6851
6916
  /** Too many asked, or too many codes typed, from here in the last hour. */
@@ -6865,6 +6930,8 @@ Schema.Struct({
6865
6930
  /** When the request expires, in epoch milliseconds. */
6866
6931
  deadline: Schema.Int,
6867
6932
  challenge: Schema.String,
6933
+ /** A machine answer retries only from its answering session, with this key. */
6934
+ answerKey: Schema.optionalKey(RequestId),
6868
6935
  /** An agent's ask: the credential it asked with, checked again before the answer counts. */
6869
6936
  asking: Schema.optionalKey(TokenId),
6870
6937
  /** The kind of action the person, answering, let agents take without asking from now on. */
@@ -6882,7 +6949,8 @@ Schema.Union([Schema.Struct({ denied: Schema.Literal(true) }), Schema.Struct({
6882
6949
  })]);
6883
6950
  Schema.Union([Schema.Struct({
6884
6951
  admitted: Schema.Literal(true),
6885
- admittedAt: Schema.Int
6952
+ admittedAt: Schema.Int,
6953
+ answerCode: Schema.optionalKey(ApprovalCode)
6886
6954
  }), Schema.Struct({
6887
6955
  admitted: Schema.Literal(false),
6888
6956
  reason: Schema.Literals([
@@ -10660,7 +10728,16 @@ const DeliveryTake = Schema.Struct({
10660
10728
  */
10661
10729
  requestKey: Schema.String.check(Schema.isBetweenLength(1, 256)),
10662
10730
  /** Its place in the session's order, so a take from a process that's been replaced is refused. */
10663
- seq: HookSeq
10731
+ seq: HookSeq,
10732
+ /**
10733
+ * The UTF-8 bytes `ref0 mcp` keeps in this hook's answer for text of its own, a notice of what
10734
+ * merged into the session's base, at most one item's. The ledger's items fit beside it, unless
10735
+ * one wouldn't: then they take the room, and the text waits whole for the next hook.
10736
+ */
10737
+ reserved: Schema.optionalKey(Schema.Int.check(Schema.isBetween({
10738
+ minimum: 1,
10739
+ maximum: 7600
10740
+ })))
10664
10741
  });
10665
10742
  /**
10666
10743
  * One item handed to a hook: its key, kind and text, rendered when it's taken, after who may
@@ -10689,6 +10766,15 @@ const DeliveriesTaken = Schema.Struct({
10689
10766
  left: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))
10690
10767
  });
10691
10768
  /**
10769
+ * What a hook's take answers: what it hands, and whether the bytes it reserved are still free
10770
+ * beside that. Not when a ledger item needed them, so the text they were kept for waits whole
10771
+ * for the next hook. Kept when none were reserved.
10772
+ */
10773
+ const HookTaken = Schema.Struct({
10774
+ ...DeliveriesTaken.fields,
10775
+ reservedKept: Schema.Boolean
10776
+ });
10777
+ /**
10692
10778
  * A take refused: the session ended, or the hook message is older than one its session already
10693
10779
  * sent, from a `ref0 mcp` that's since been replaced. Nothing is handed over.
10694
10780
  */
@@ -10708,8 +10794,8 @@ Schema.Struct({
10708
10794
  Schema.Union([DeliveriesTaken, TakeRefused]);
10709
10795
  /**
10710
10796
  * Where a take's notices may go once the Project DO has handed its own: the UTF-8 bytes left
10711
- * in the hook's answer, and the repos whose Repo DOs owe the session one. Absent when the hook
10712
- * can't carry a notice.
10797
+ * in the hook's answer, past any it kept reserved, and the repos whose Repo DOs owe the session
10798
+ * one. Absent when the hook can't carry a notice.
10713
10799
  */
10714
10800
  const NoticeRoom = Schema.Struct({
10715
10801
  room: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
@@ -10719,7 +10805,7 @@ const NoticeRoom = Schema.Struct({
10719
10805
  });
10720
10806
  /** What the Project DO's take answers the Worker: its own attempts, and where notices may go. */
10721
10807
  const ProjectDeliveriesTaken = Schema.Struct({
10722
- ...DeliveriesTaken.fields,
10808
+ ...HookTaken.fields,
10723
10809
  notices: Schema.optionalKey(NoticeRoom)
10724
10810
  });
10725
10811
  Schema.Union([ProjectDeliveriesTaken, TakeRefused]);
@@ -11658,6 +11744,70 @@ Schema.Union([
11658
11744
  NotPermitted
11659
11745
  ]);
11660
11746
  //#endregion
11747
+ //#region ../contracts/src/session-base.ts
11748
+ /**
11749
+ * A session's base in a repo: what its work there builds on now, read from its live fork. That's
11750
+ * the pin of the thread its thread is stacked on, when that thread has one in the repo, and
11751
+ * otherwise `main`. `ref0 sync` merges it, and the local check checks the agent's work against it.
11752
+ */
11753
+ /** What a base is: `main`, or the thread this one is stacked on, by its number. */
11754
+ const BaseOn = Schema.Union([Schema.Literal("main"), Schema.Struct({ thread: ThreadNumber })]);
11755
+ /** A session's base, as `GET /v1/sessions/{session}/repos/{repo}/base` answers it. */
11756
+ const SessionBase = Schema.Struct({
11757
+ on: BaseOn,
11758
+ /** `main`'s tip, or the pin's commit: what `ref` reaches once fetched. */
11759
+ commit: CommitOid,
11760
+ /**
11761
+ * Where to fetch it from, on ref0's origin: the repo's own path, as `ref0 clone` cloned it, for
11762
+ * `main`; for a stack, the path of the fork that holds the pin.
11763
+ */
11764
+ path: Schema.String.check(Schema.isPattern(/^\/[^\s]+\.git$/), Schema.isMaxLength(512)),
11765
+ /** `path` on the app's one origin. A client checks it's a fork of its own repo there. */
11766
+ url: Schema.String,
11767
+ ref: Schema.Literal("refs/heads/main")
11768
+ });
11769
+ /**
11770
+ * No base to fetch: `main` has no commit yet, or the pin of the thread below is in a workflow
11771
+ * run's fork, which has no session's path to fetch from.
11772
+ */
11773
+ var NoBase = class extends Schema.TaggedError()("NoBase", {
11774
+ why: Schema.Literals(["main empty", "held by a run"]),
11775
+ nextStep: Schema.String
11776
+ }, { httpApiStatus: 404 }) {};
11777
+ Schema.Struct({
11778
+ session: SessionId,
11779
+ /**
11780
+ * For an agent that sees only threads it holds a grant on, those threads: a session whose
11781
+ * thread is stacked, at any depth, on any other is refused, as its base holds that thread's
11782
+ * work. Unset for one that sees the project as a whole.
11783
+ */
11784
+ only: Schema.optionalKey(Schema.Array(ThreadId))
11785
+ });
11786
+ /** The base on `main`, at its tip. */
11787
+ const BaseOnMain = Schema.Struct({
11788
+ on: Schema.Literal("main"),
11789
+ commit: CommitOid
11790
+ });
11791
+ /**
11792
+ * The base on the thread below, `lower`: its pin's commit, the fork that holds it, and that
11793
+ * fork's session, or none for a workflow run's fork.
11794
+ */
11795
+ const BaseOnStack = Schema.Struct({
11796
+ on: Schema.Literal("stack"),
11797
+ lower: ThreadId,
11798
+ commit: CommitOid,
11799
+ fork: ForkId,
11800
+ session: Schema.NullOr(SessionId)
11801
+ });
11802
+ Schema.Union([
11803
+ BaseOnMain,
11804
+ BaseOnStack,
11805
+ NoFork,
11806
+ NoBase,
11807
+ RepoNotReady,
11808
+ NotPermitted
11809
+ ]);
11810
+ //#endregion
11661
11811
  //#region ../contracts/src/gate-views.ts
11662
11812
  /**
11663
11813
  * A pull request's gate, as `ref0 gate` reads it: its current version, whether its needs are
@@ -11695,10 +11845,10 @@ const GateInPlaceView = Schema.Struct({
11695
11845
  /**
11696
11846
  * One `from`'s yes over the run that counts for a part that needs one (L2), as `passkey.check`
11697
11847
  * asks: `asked`, waiting, of `asked` when it's one person; `yes`, by whom and when; `no`;
11698
- * `expired`, its day passed unanswered; `refused`, the person it names can't be asked; or
11699
- * `revoked`, a yes whose answerer a miss revoked since, until an admin restores them. A local
11700
- * run's no or day passing waits for a newer local run; a ref0 run's, or a refusal, leaves the
11701
- * part with no yes, until an admin overrides it.
11848
+ * `expired`, its day passed unanswered; `refused`, asking nobody, `why`; or `revoked`, a yes whose
11849
+ * answerer a miss revoked since, until an admin restores them. A local run's no or day passing
11850
+ * waits for a newer local run; a ref0 run's, or a refusal, leaves the part with no yes, until an
11851
+ * admin overrides it.
11702
11852
  */
11703
11853
  const GatePartYes = Schema.Struct({
11704
11854
  from: PasskeyFrom,
@@ -11710,6 +11860,12 @@ const GatePartYes = Schema.Struct({
11710
11860
  "refused",
11711
11861
  "revoked"
11712
11862
  ]),
11863
+ /**
11864
+ * Why a request was refused: `target`, nobody it names can be asked, a person who isn't there
11865
+ * or can't see the pull request's thread; or `self`, it names the person behind the run, or a
11866
+ * permission only they hold, who can't be the second pair of eyes over their own run.
11867
+ */
11868
+ why: Schema.optionalKey(Schema.Literals(["target", "self"])),
11713
11869
  asked: Schema.optionalKey(PersonId),
11714
11870
  by: Schema.optionalKey(OwnerName),
11715
11871
  at: Schema.optionalKey(Schema.DateTimeUtcFromMillis)
@@ -14870,12 +15026,17 @@ var MachineAttachmentsGroup = class extends HttpApiGroup.make("machineAttachment
14870
15026
  SlowDown,
14871
15027
  AuthorityUnavailable
14872
15028
  ]
14873
- }), HttpApiEndpoint.get("collect", "/v1/attachments/requests/:approval/result", {
15029
+ }), HttpApiEndpoint.post("collect", "/v1/attachments/requests/:approval/result", {
14874
15030
  params: { approval: ApprovalId },
15031
+ payload: Schema.Struct({ answerCode: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(64))) }),
14875
15032
  success: RequestState,
14876
15033
  error: [AttachmentNotFound, AuthorityUnavailable]
14877
15034
  }).middleware(ApprovalSecret), HttpApiEndpoint.post("confirm", "/v1/attachments/requests/:approval/collected", {
14878
15035
  params: { approval: ApprovalId },
15036
+ payload: Schema.Struct({
15037
+ grants: SavedMachineGrants,
15038
+ answerCode: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(64)))
15039
+ }),
14879
15040
  headers: idempotency,
14880
15041
  success: RequestConfirmed,
14881
15042
  error: [AttachmentNotFound, AuthorityUnavailable]
@@ -14925,7 +15086,7 @@ var ApprovalsGroup = class extends HttpApiGroup.make("approvals").add(HttpApiEnd
14925
15086
  params: { approval: ApprovalId },
14926
15087
  headers: idempotency,
14927
15088
  payload: AnswerApproval,
14928
- success: ApprovalState,
15089
+ success: ApprovalAnswer,
14929
15090
  error: [
14930
15091
  ApprovalNotFound,
14931
15092
  NotPermitted,
@@ -15154,6 +15315,19 @@ var SessionsGroup = class extends HttpApiGroup.make("sessions").add(HttpApiEndpo
15154
15315
  RepoNotReady,
15155
15316
  NotPermitted
15156
15317
  ]
15318
+ }), HttpApiEndpoint.get("base", "/:session/repos/:repo/base", {
15319
+ params: {
15320
+ session: SessionId,
15321
+ repo: RepoName
15322
+ },
15323
+ success: SessionBase,
15324
+ error: [
15325
+ RepoNotFound,
15326
+ RepoNotReady,
15327
+ NotPermitted,
15328
+ NoFork,
15329
+ NoBase
15330
+ ]
15157
15331
  }), HttpApiEndpoint.post("openPull", "/:session/repos/:repo/pulls", {
15158
15332
  params: {
15159
15333
  session: SessionId,
@@ -15272,7 +15446,7 @@ var SessionsGroup = class extends HttpApiGroup.make("sessions").add(HttpApiEndpo
15272
15446
  }), HttpApiEndpoint.post("take", "/:session/deliveries/take", {
15273
15447
  params: onSession,
15274
15448
  payload: DeliveryTake,
15275
- success: DeliveriesTaken,
15449
+ success: HookTaken,
15276
15450
  error: [TakeRefused, NotPermitted]
15277
15451
  }), HttpApiEndpoint.post("report", "/:session/deliveries/report", {
15278
15452
  params: onSession,
@@ -16863,6 +17037,15 @@ const ownSurfaces = {
16863
17037
  cli: "clone",
16864
17038
  mcp: "repo_fork"
16865
17039
  },
17040
+ "sessions.base": {
17041
+ action: "project:read",
17042
+ actors: "agent",
17043
+ target: "session",
17044
+ stepUp: "never",
17045
+ asks: "never",
17046
+ cli: "sync",
17047
+ mcp: null
17048
+ },
16866
17049
  "sessions.openPull": {
16867
17050
  action: "session:change",
16868
17051
  actors: "agent",
@@ -17862,7 +18045,7 @@ HttpApi.reflect(Api, {
17862
18045
  * leaves out only `ApprovalNeeded`, at `202`.
17863
18046
  */
17864
18047
  const schemasOf = (name) => Option.fromNullishOr(reflected.get(name));
17865
- Schema.toCodecJson(MachineConnected), Schema.toCodecJson(AttachmentFailed);
18048
+ Schema.toCodecJson(FoldersConnected), Schema.toCodecJson(AttachmentFailed);
17866
18049
  const isEndpointName = (name) => name in surfaces;
17867
18050
  const encodeJson = Schema.encodeEffect(Schema.fromJsonString(Schema.Json));
17868
18051
  const decodeJson = Schema.decodeUnknownEffect(Schema.Json);
@@ -18131,6 +18314,6 @@ const signOut = (origin) => Effect.gen(function* () {
18131
18314
  yield* client.execute(HttpClientRequest.make(method)(path, { body: HttpBody.jsonUnsafe({}) }));
18132
18315
  });
18133
18316
  //#endregion
18134
- export { AgentHandle, ApiOrigin, AttachmentFailed, ClientAccess, ClientGranted, ConnectionChanged, ConnectionKind, ConnectionName, ConsentProject, LiveTrackName, MachineConnected, OwnerName, OwnerTrackMessage, PasskeyAsserted, PasskeyCreated, PreviewUnavailable, ProjectName, ProjectTrackMessage, RepoName, RepoUrl, SecretHash, SentryOrg, SentryRegion, SentryToken, SignInDestination, ThreadId, ThreadStage, TypedApprovalCode, WorkflowPreview, WrittenProject, anonymousCredential, bearerCredential, browserCredential, commandLine, connectEndpoint, encodeSecret, fetchTransport, followApproval, hookTokenPrefix, hookUrl, isRef0Path, liveMessages, liveSocketUrl, newRequestId, projectParts, ref0Client, repoNameKey, settledOf, signOut, startGitHubSignIn, surfaceOf };
18317
+ export { AgentHandle, ApiOrigin, AttachmentFailed, AttachmentRequestView, ClientAccess, ClientGranted, ConnectionChanged, ConnectionKind, ConnectionName, ConsentProject, FoldersConnected, LiveTrackName, MachineConnected, OwnerName, OwnerTrackMessage, PasskeyAsserted, PasskeyCreated, PreviewUnavailable, ProjectName, ProjectTrackMessage, RepoName, RepoUrl, SecretHash, SentryOrg, SentryRegion, SentryToken, SignInDestination, ThreadId, ThreadStage, TypedApprovalCode, WorkflowPreview, WrittenProject, anonymousCredential, bearerCredential, browserCredential, commandLine, connectEndpoint, encodeSecret, fetchTransport, followApproval, hookTokenPrefix, hookUrl, isRef0Path, liveMessages, liveSocketUrl, newRequestId, projectParts, ref0Client, repoNameKey, settledOf, signOut, startGitHubSignIn, surfaceOf };
18135
18318
 
18136
18319
  //# sourceMappingURL=client.mjs.map