@ref0/sdk 0.6.0 → 0.8.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/README.md CHANGED
@@ -181,7 +181,7 @@ export default workflow({
181
181
 
182
182
  `ask.run` is a step of its own. It waits for `{ key, by, via, at }`. At its deadline it returns the lean with `via: 'deadline'` and no `by`. It offers two to five answers, and a run uses each ask key once. A refused or withdrawn ask throws `AskRefused`.
183
183
 
184
- `passkey.run` is also a step of its own. Only the person in their approving browser can answer yes with their passkey. The result has `approved`, `at` and, when someone answered, `by`. A deadline answers no. `from` can also name `{ person: 'mo' }` or `{ permission: 'deploy' }`, with `person` or `permission` in `permissions.ask`. Agents have no passkey.
184
+ `passkey.run` is also a step of its own. Only the person in their approving browser can answer yes with their passkey. The result has `approved`, `at` and, when someone answered, `by`. A deadline answers no. `from` can also name someone else, `{ person: 'pip' }` or `{ permission: 'deploy' }`, with `person` or `permission` in `permissions.ask`. Someone else is never the run's accountable person: naming Mo here, or a permission only Mo holds, throws `PasskeyRequestRefused` with `self`. Agents have no passkey.
185
185
 
186
186
  Call both leaves outside `step.do` callbacks. Each request spends from the workflow's `asks` budget. Deadlines range from a minute to a day, bounded by the run's remaining day. A called workflow parses its input with one `z.object` and returns JSON to its caller.
187
187
 
@@ -248,7 +248,7 @@ The gate in story 1 takes local results with `local(unit())` and `passkey.check(
248
248
 
249
249
  The newest finished local run counts unless a ref0 failure stands. A newer local run replaces an earlier one, and a newer ref0 pass counts instead. A ref0 failure stands until an admin overrides it, even if a later run passes.
250
250
 
251
- `passkey.check` waits for the person behind the counted run to say yes over its result with their passkey. For a local run, that's the signer's person. For ref0's run, it's the version's accountable person. `{ from }` asks someone else, as in `passkey.check(local(e2e()), { from: { person: 'mo' } })`. The statement names the check-run identity, conclusion and outputs' hash. A newer counted run needs a new yes.
251
+ `passkey.check` waits for the person behind the counted run to say yes over its result with their passkey. For a local run, that's the signer's person. For ref0's run, it's the version's accountable person. `{ from }` asks someone else, as in `passkey.check(local(e2e()), { from: { person: 'mo' } })`. Someone else is never the person behind the run: if Mo ran it, or only Mo holds the permission named, ref0 refuses the request at once, and the check needs an admin's override. The statement names the check-run identity, conclusion and outputs' hash. A newer counted run needs a new yes.
252
252
 
253
253
  When ref0 runs the same check-run identity as a signed success and it fails twice, the signer stops answering that check. For `local`, ref0 revokes the attachment. For `passkey.check`, it revokes the person whose yes stood over the result. An admin restores the signer with `ref0 checks signers restore`, using `--person` for a person. The floor's needs and the queue's tip take only ref0's runs.
254
254
 
@@ -1,4 +1,4 @@
1
- import { $t as WorkflowCallRefusal, An as WorkflowStartState, Cn as WorkflowPasskeyState, Ct as SandboxPushAnswer, D as ConnectionCallAnswer, Dn as WorkflowPullRequestOpen, E as ConnectionCall, En as WorkflowPullRequestAnswer, Gt as WorkflowActionAnswer, Jt as WorkflowAskClosed, L as EventRunInput, Lt as ThreadStage, Mn as WorkflowThreadStart, Nn as WorkflowTrigger, Nt as StartActor$1, Pt as StartRun$1, Qt as WorkflowCallInput, R as ForkAnswer$1, Sn as WorkflowPasskeyRead, St as SandboxPush, V as GetIssueInput, Wt as WorkflowAction, Xt as WorkflowCallAnswer, Yt as WorkflowCall, Zt as WorkflowCallEnded, _ as CheckOwn, _n as WorkflowFilters, an as WorkflowCheckResults, b as CheckTreeEntry, bn as WorkflowPasskeyAsked, bt as SandboxOpen, cn as WorkflowCheckRunEnded, dn as WorkflowCheckStates, en as WorkflowCallRefused, fn as WorkflowCheckStatesAnswer, g as CheckOn, gn as WorkflowEvent, hn as WorkflowConnections, in as WorkflowCheckRefused, jn as WorkflowText, kn as WorkflowStartEnded, ln as WorkflowCheckStart, mn as WorkflowComment, mt as Ref0Owned, nn as WorkflowCalledStateAnswer, on as WorkflowCheckResultsAnswer, pn as WorkflowCheckWhere, rn as WorkflowCheckRefusal, sn as WorkflowCheckRun, tn as WorkflowCalledState, un as WorkflowCheckStartAnswer, v as CheckRunError, vn as WorkflowOwn, vt as SandboxExec, wn as WorkflowPermissions, xn as WorkflowPasskeyEnded, xt as SandboxOpenAnswer, y as CheckRunParams, yn as WorkflowPasskeyAsk, yt as SandboxExecAnswer, z as ForkCreate } from "./index-CJGX88qF.mjs";
1
+ import { $t as WorkflowAskClosed, A as ConnectionCallAnswer, B as EventRunInput, Cn as WorkflowOwn, Ct as SandboxExec, Dn as WorkflowPasskeyRead, Dt as SandboxPush, En as WorkflowPasskeyEnded, Et as SandboxOpenAnswer, Fn as WorkflowStartState, G as GetIssueInput, H as ForkAnswer$1, Ht as ThreadStage, In as WorkflowText, Ln as WorkflowThreadStart, Mn as WorkflowPullRequestOpen, On as WorkflowPasskeyState, Ot as SandboxPushAnswer, Pn as WorkflowStartEnded, Rn as WorkflowTrigger, Rt as StartActor$1, Sn as WorkflowFilters, Tn as WorkflowPasskeyAsked, Tt as SandboxOpen, U as ForkCreate, Xt as WorkflowActionAnswer, Yt as WorkflowAction, _ as CheckOwn, _n as WorkflowCheckStatesAnswer, an as WorkflowCallRefused, b as CheckTreeEntry, bn as WorkflowConnections, cn as WorkflowCheckRefusal, dn as WorkflowCheckResultsAnswer, en as WorkflowCall, fn as WorkflowCheckRun, g as CheckOn, gn as WorkflowCheckStates, hn as WorkflowCheckStartAnswer, in as WorkflowCallRefusal, jn as WorkflowPullRequestAnswer, k as ConnectionCall, kn as WorkflowPermissions, ln as WorkflowCheckRefused, mn as WorkflowCheckStart, nn as WorkflowCallEnded, on as WorkflowCalledState, pn as WorkflowCheckRunEnded, rn as WorkflowCallInput, sn as WorkflowCalledStateAnswer, tn as WorkflowCallAnswer, un as WorkflowCheckResults, v as CheckRunError, vn as WorkflowCheckWhere, vt as Ref0Owned, wn as WorkflowPasskeyAsk, wt as SandboxExecAnswer, xn as WorkflowEvent, y as CheckRunParams, yn as WorkflowComment, zt as StartRun$1 } from "./index-Bm4HWooV.mjs";
2
2
  import { z } from "zod";
3
3
  //#region src/needs.d.ts
4
4
  /**
@@ -671,4 +671,4 @@ interface Browser {
671
671
  }
672
672
  //#endregion
673
673
  export { StartActor as $, ForkOptions as A, WorkflowContext as B, Comment as C, EventWorkflow as D, EventOf as E, StepConfig as F, CalledWorkflow as G, text as H, StepContext as I, TreeEntry as J, JsonValue as K, ThreadStart as L, PullRequestAnswer as M, PullRequestOptions as N, EventWorkflowSpec as O, Ref0Actions as P, Refusal as Q, WaitType as R, CheckRunEnded as S, Duration as T, workflow as U, WorkflowStep as V, CalledRunFailed as W, Allow as X, TreeRead as Y, CalledRun as Z, ActionAnswer as _, CheckRunOptions as a, allow as at, CalledContext as b, CheckRunResult as c, Need as ct, OneOfValues as d, StartContext as et, OutputResult as f, oneOf as g, check as h, CheckResult as i, StartRun as it, NeedAddOptions as j, ForkAnswer as k, CheckSpec as l, Step as m, Check as n, StartOutput as nt, CheckRunReference as o, refuse as ot, OutputSchema as p, Tree as q, CheckContext as r, StartRule as rt, CheckRunRefused as s, CheckNeed as st, Browser as t, StartItem as tt, DurationText as u, CallAnswer as v, ConnectionsOf as w, CalledWorkflowSpec as x, CallEnded as y, WaitedEvent as z };
674
- //# sourceMappingURL=browse-DHgV6DTF.d.mts.map
674
+ //# sourceMappingURL=browse-DZcR8vTe.d.mts.map
@@ -1,4 +1,4 @@
1
- import { t as Browser } from "./browse-DHgV6DTF.mjs";
1
+ import { t as Browser } from "./browse-DZcR8vTe.mjs";
2
2
  import { BrowserContext, BrowserContext as BrowserContext$1, BrowserContextOptions, Locator, Page, Page as Page$1, Request, Response } from "@cloudflare/playwright";
3
3
  import { expect as expect$1 } from "@cloudflare/playwright/test";
4
4
  //#region src/browser-stub.d.ts
package/dist/client.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as OwnerThreadPage, A as ConnectionName, At as SignInDestination, Bn as isRef0Path, Bt as TrackThread, C as ConnectAgent, Dt as SentryOrg, Et as SecretHash, F as CredentialView, Fn as commandLine, Ft as StatementView, G as LiveTicketRequest, H as Harness, Hn as projectParts, I as EndpointName, In as connectEndpoint, It as ThreadId, J as MirrorChoice, K as LiveTrackName, Ln as encodeSecret, Lt as ThreadStage, M as ConsentAsked, Mt as SocketUrl, N as ConsentClient, O as ConnectionChanged, Ot as SentryRegion, P as ConsentProject, Pn as WrittenProject, Q as OwnerName, Rn as hookTokenPrefix, Rt as TrackClosed, S as ClientGranted, T as ConnectableAgent, Tn as WorkflowPreview, Tt as ScopeAction, U as ImportFailure, Un as repoNameKey, Ut as Welcome, Vn as liveSocketUrl, Vt as TypedApprovalCode, W as LiveTicket, Wn as surfaceOf, X as MirrorView, Y as MirrorEntry, Z as OwnerId, _t as RepoView, a as Api, c as ApprovalId, ct as PreviewEcho, d as ApprovalView, dt as ProjectTrackMessage, et as OwnerThreadView, f as AttachmentFailed, ft as RanOf, gt as RepoUrl, ht as RepoName, i as AgentView, it as PasskeyCreationOptions, j as ConnectionView, jt as SignedIn, k as ConnectionKind, kt as SentryToken, l as ApprovalPreview, lt as PreviewUnavailable, m as Authorization, n as AgentPermissionChoice, nt as PasskeyAsserted, o as ApiOrigin, p as AttachmentRequestView, pt as ReadEvent, q as MachineConnected, r as AgentPermissionSetting, rt as PasskeyCreated, s as ApprovalAnswer, st as PasskeyRequestOptions, t as AgentHandle, tt as OwnerTrackMessage, u as ApprovalState, ut as ProjectName, w as ConnectChosen, x as ClientAccess, zn as hookUrl, zt as TrackSession } from "./index-CJGX88qF.mjs";
1
+ import { $ as MirrorEntry, An as WorkflowPreview, At as ScopeAction, Bn as commandLine, Bt as StatementView, C as ConnectAgent, D as ConnectOptions, E as ConnectFolderOption, F as ConsentAsked, Ft as SignInDestination, Gn as isRef0Path, Gt as TrackThread, Hn as encodeSecret, Ht as ThreadStage, I as ConsentClient, It as SignedIn, J as LiveTicket, Jn as repoNameKey, Jt as Welcome, K as Harness, Kn as liveSocketUrl, Kt as TypedApprovalCode, L as ConsentProject, Lt as SocketUrl, M as ConnectionKind, Mt as SentryOrg, N as ConnectionName, Nt as SentryRegion, O as ConnectableAgent, P as ConnectionView, Pt as SentryToken, Q as MirrorChoice, R as CredentialView, S as ClientGranted, St as RequestFolder, T as ConnectFolderChoices, Un as hookTokenPrefix, Ut as TrackClosed, V as FoldersConnected, Vn as connectEndpoint, Vt as ThreadId, Wn as hookUrl, Wt as TrackSession, X as LiveTrackName, Y as LiveTicketRequest, Yn as surfaceOf, Z as MachineConnected, _t as ReadEvent, a as Api, at as OwnerTrackMessage, bt as RepoUrl, c as ApprovalId, ct as PasskeyCreationOptions, d as ApprovalView, dt as PasskeyRequestOptions, et as MirrorView, f as AttachmentFailed, ft as PreviewEcho, gt as RanOf, ht as ProjectTrackMessage, i as AgentView, it as OwnerThreadView, j as ConnectionChanged, jt as SecretHash, l as ApprovalPreview, m as Authorization, mt as ProjectName, n as AgentPermissionChoice, nt as OwnerName, o as ApiOrigin, ot as PasskeyAsserted, p as AttachmentRequestView, pt as PreviewUnavailable, q as ImportFailure, qn as projectParts, r as AgentPermissionSetting, rt as OwnerThreadPage, s as ApprovalAnswer, st as PasskeyCreated, t as AgentHandle, tt as OwnerId, u as ApprovalState, w as ConnectChosen, x as ClientAccess, xt as RepoView, yt as RepoName, z as EndpointName, zn as WrittenProject } from "./index-Bm4HWooV.mjs";
2
2
  import { Effect, Layer, Option, Redacted, Schema, Stream } from "effect";
3
3
  import { HttpApi, HttpApiClient, HttpApiGroup, HttpApiMiddleware } from "effect/http-api";
4
4
  import { HttpBody, HttpClient } from "effect/http";
@@ -90,5 +90,5 @@ export declare const startGitHubSignIn: (landing: {
90
90
  */
91
91
  export declare const signOut: (origin?: ApiOrigin) => Effect.Effect<void, import("effect/http/HttpClientError").HttpClientError, HttpClient.HttpClient>;
92
92
  //#endregion
93
- export { AgentHandle, type AgentPermissionChoice, type AgentPermissionSetting, type AgentView, ApiOrigin, type ApprovalAnswer, type ApprovalId, type ApprovalPreview, type ApprovalState, type ApprovalView, AttachmentFailed, type AttachmentRequestView, ClientAccess, ClientGranted, type ConnectAgent, type ConnectChosen, type ConnectableAgent, ConnectionChanged, ConnectionKind, ConnectionName, type ConnectionView, type ConsentAsked, type ConsentClient, ConsentProject, type CredentialView, type Harness, type ImportFailure, type LiveTicket, type LiveTicketRequest, LiveTrackName, MachineConnected, type MirrorChoice, type MirrorEntry, type MirrorView, type OwnerId, OwnerName, type OwnerThreadPage, type OwnerThreadView, OwnerTrackMessage, PasskeyAsserted, PasskeyCreated, type PasskeyCreationOptions, type PasskeyRequestOptions, type PreviewEcho, PreviewUnavailable, ProjectName, ProjectTrackMessage, type ReadEvent, type Ref0Client, RepoName, RepoUrl, type RepoView, type ScopeAction, SecretHash, SentryOrg, SentryRegion, SentryToken, type SettledApproval, SignInDestination, type StatementView, ThreadId, ThreadStage, type TrackClosed, type TrackSession, type TrackThread, TypedApprovalCode, type Welcome, WorkflowPreview, WrittenProject, commandLine, connectEndpoint, encodeSecret, hookTokenPrefix, hookUrl, isRef0Path, liveSocketUrl, projectParts, repoNameKey, surfaceOf };
93
+ export { AgentHandle, type AgentPermissionChoice, type AgentPermissionSetting, type AgentView, ApiOrigin, type ApprovalAnswer, type ApprovalId, type ApprovalPreview, type ApprovalState, type ApprovalView, AttachmentFailed, AttachmentRequestView, ClientAccess, ClientGranted, type ConnectAgent, type ConnectChosen, type ConnectFolderChoices, type ConnectFolderOption, type ConnectOptions, type ConnectableAgent, ConnectionChanged, ConnectionKind, ConnectionName, type ConnectionView, type ConsentAsked, type ConsentClient, ConsentProject, type CredentialView, FoldersConnected, type Harness, type ImportFailure, type LiveTicket, type LiveTicketRequest, LiveTrackName, MachineConnected, type MirrorChoice, type MirrorEntry, type MirrorView, type OwnerId, OwnerName, type OwnerThreadPage, type OwnerThreadView, OwnerTrackMessage, PasskeyAsserted, PasskeyCreated, type PasskeyCreationOptions, type PasskeyRequestOptions, type PreviewEcho, PreviewUnavailable, ProjectName, ProjectTrackMessage, type ReadEvent, type Ref0Client, RepoName, RepoUrl, type RepoView, type RequestFolder, type ScopeAction, SecretHash, SentryOrg, SentryRegion, SentryToken, type SettledApproval, SignInDestination, type StatementView, ThreadId, ThreadStage, type TrackClosed, type TrackSession, type TrackThread, TypedApprovalCode, type Welcome, WorkflowPreview, WrittenProject, commandLine, connectEndpoint, encodeSecret, hookTokenPrefix, hookUrl, isRef0Path, liveSocketUrl, projectParts, repoNameKey, surfaceOf };
94
94
  //# sourceMappingURL=client.d.mts.map
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"),
@@ -6417,39 +6419,57 @@ var PasskeyRefused = class extends Schema.TaggedError()("PasskeyRefused", { next
6417
6419
  //#endregion
6418
6420
  //#region ../contracts/src/attachments.ts
6419
6421
  /** A machine asks, a signed-in person claims and approves, and the answer returns to its terminal. */
6422
+ /**
6423
+ * What could reorder or hide the text around it, such as U+202E: a control, format, surrogate,
6424
+ * private-use or unassigned character, or a line or paragraph separator.
6425
+ */
6426
+ const hiddenCharacters = String.raw`\p{C}\p{Zl}\p{Zp}`;
6427
+ /** Text with none of them, which reads as it's written wherever it's shown. */
6428
+ const shownAsWritten = Schema.isPattern(new RegExp(`^[^${hiddenCharacters}]+$`, "u"));
6420
6429
  /** A machine's own word for itself: shown to the person as what it says, never as fact. */
6421
- const MachineName = Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(64));
6430
+ const MachineName = Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(64), shownAsWritten);
6422
6431
  /** The harness a machine says it connects for, never proof of what it runs. */
6423
6432
  const ConnectHarness = Schema.Literals(["claude-code", "codex"]);
6424
- /**
6425
- * A machine asks with no owner and sends hashes of its grant, collecting and link secrets.
6426
- * The optional callback names only a loopback port and a random state segment, never a host.
6427
- */
6433
+ /** The machine's loopback listener; no caller may choose its host. */
6434
+ const AttachmentCallback = Schema.Struct({
6435
+ port: Schema.Int.check(Schema.isBetween({
6436
+ minimum: 1024,
6437
+ maximum: 65535
6438
+ })),
6439
+ state: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{22}$/))
6440
+ });
6441
+ /** A config folder's path, as the machine shows it, never proof of its location. */
6442
+ const ConfigFolderPath = Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(200), shownAsWritten);
6443
+ const uniqueFolderPaths = Schema.makeFilter((folders) => new Set(folders.map((folder) => folder.path)).size === folders.length, { expected: "unique config folder paths" });
6444
+ const RequestFolder = Schema.Struct({
6445
+ path: ConfigFolderPath,
6446
+ harness: ConnectHarness,
6447
+ secretHash: SecretHash,
6448
+ replaces: Schema.optionalKey(TokenId)
6449
+ });
6450
+ /** One to eight config folders, each with its own grant secret. */
6428
6451
  const RequestAttachment = Schema.Struct({
6429
6452
  machine: MachineId,
6430
6453
  machineName: MachineName,
6431
- harness: Schema.optionalKey(ConnectHarness),
6432
- secretHash: SecretHash,
6454
+ folders: Schema.Array(RequestFolder).check(Schema.isMinLength(1), Schema.isMaxLength(8), uniqueFolderPaths),
6433
6455
  collectHash: SecretHash,
6434
6456
  linkHash: SecretHash,
6435
- callback: Schema.optionalKey(Schema.Struct({
6436
- port: Schema.Int.check(Schema.isBetween({
6437
- minimum: 1024,
6438
- maximum: 65535
6439
- })),
6440
- state: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{22}$/))
6441
- }))
6457
+ callback: Schema.optionalKey(AttachmentCallback)
6442
6458
  });
6443
6459
  /** An attachment request, as its person reads it once they type its code. */
6444
6460
  const AttachmentRequestView = Schema.Struct({
6445
6461
  approval: ApprovalId,
6446
6462
  /** The machine's own word for itself, never fact. */
6447
6463
  machineName: MachineName,
6448
- /** The harness the machine says it uses, never fact. */
6449
- harness: Schema.optionalKey(ConnectHarness),
6464
+ folders: Schema.Array(Schema.Struct({
6465
+ path: ConfigFolderPath,
6466
+ harness: ConnectHarness,
6467
+ replaces: Schema.optionalKey(TokenId)
6468
+ })),
6450
6469
  askedFrom: Schema.optionalKey(Schema.String),
6451
6470
  askedAt: Timestamp,
6452
- expiresAt: Timestamp
6471
+ expiresAt: Timestamp,
6472
+ callback: Schema.optionalKey(AttachmentCallback)
6453
6473
  });
6454
6474
  /**
6455
6475
  * What its answerer chooses to connect a machine's request to: one of the person's own agents,
@@ -6473,6 +6493,16 @@ const ConnectOrganization = Schema.Struct({
6473
6493
  organization: OrgId,
6474
6494
  name: OwnerName
6475
6495
  });
6496
+ /** Whether admission replaced a live host grant, or skipped one that no longer belongs here. */
6497
+ const GrantReplacement = Schema.Struct({
6498
+ grant: TokenId,
6499
+ state: Schema.Literals([
6500
+ "replaces",
6501
+ "revoked",
6502
+ "skipped"
6503
+ ]),
6504
+ attachedAt: Schema.optionalKey(Timestamp)
6505
+ });
6476
6506
  /**
6477
6507
  * What a yes would connect the machine to, as options resolved the choice: the agent, or none
6478
6508
  * yet, to make with the handle; and each organization its attachment is authorized in.
@@ -6480,22 +6510,32 @@ const ConnectOrganization = Schema.Struct({
6480
6510
  const ConnectChosen = Schema.Struct({
6481
6511
  agent: Schema.optionalKey(AgentRef),
6482
6512
  handle: AgentHandle,
6483
- organizations: Schema.Array(ConnectOrganization)
6513
+ organizations: Schema.Array(ConnectOrganization),
6514
+ replacement: Schema.optionalKey(GrantReplacement)
6484
6515
  });
6485
- /**
6486
- * A machine's request, as its answerer chooses what it connects to. Without a choice: the
6487
- * request and the person's agents that are on, and nothing chosen for them. With one: the
6488
- * request, what the choice resolved to, and the passkey's options, whose challenge signs over
6489
- * the connect it would run.
6490
- */
6491
- const ConnectOptions = Schema.Union([Schema.Struct({
6492
- request: AttachmentRequestView,
6493
- agents: Schema.Array(ConnectableAgent)
6516
+ /** A complete choice: name every folder once, leaving at least one in. */
6517
+ const ConnectFolderChoice = Schema.Union([Schema.Struct({
6518
+ path: ConfigFolderPath,
6519
+ excluded: Schema.Literal(true)
6520
+ }), Schema.Struct({
6521
+ path: ConfigFolderPath,
6522
+ agent: ConnectAgent
6523
+ })]);
6524
+ const ConnectFolderChoices = Schema.Array(ConnectFolderChoice).check(Schema.isMinLength(1), Schema.isMaxLength(8), uniqueFolderPaths);
6525
+ const ConnectFolderOption = Schema.Union([Schema.Struct({
6526
+ path: ConfigFolderPath,
6527
+ excluded: Schema.Literal(true)
6494
6528
  }), Schema.Struct({
6529
+ path: ConfigFolderPath,
6530
+ connect: ConnectChosen
6531
+ })]);
6532
+ /** Defaults and explicit choices both resolve the entire request and sign one challenge. */
6533
+ const ConnectOptions = Schema.Struct({
6495
6534
  request: AttachmentRequestView,
6496
- connect: ConnectChosen,
6535
+ agents: Schema.Array(ConnectableAgent),
6536
+ folders: Schema.Array(ConnectFolderOption),
6497
6537
  passkey: PasskeyRequestOptions
6498
- })]);
6538
+ });
6499
6539
  /** Why connecting connected nothing, said for the person. */
6500
6540
  const AttachmentFailure = Schema.Struct({
6501
6541
  reason: Schema.Literals([
@@ -6523,11 +6563,9 @@ const RequestOrganization = Schema.Struct({
6523
6563
  ])
6524
6564
  });
6525
6565
  /**
6526
- * Where a machine's request stands, for the machine that asked, by its collecting secret: waiting,
6527
- * or how it ended. Every answer but waiting is final, but a connect nobody confirmed 10 minutes
6528
- * after it connected fails `not confirmed` once ref0 takes its grant to revoke it. Connected
6529
- * names the owner by its name, and the host grant, whose token the machine makes from its ID and
6530
- * the grant's secret.
6566
+ * The result collected with the machine's two proofs: each included folder's identity and grant,
6567
+ * its agent's owner name and organizations, and excluded paths. Confirmation checks each saved
6568
+ * grant's live deadline in the Owner DO.
6531
6569
  */
6532
6570
  const RequestState = Schema.Union([
6533
6571
  Schema.Struct({
@@ -6537,20 +6575,30 @@ const RequestState = Schema.Union([
6537
6575
  Schema.Struct({
6538
6576
  state: Schema.Literal("connected"),
6539
6577
  owner: OwnerName,
6540
- agent: AgentRef,
6541
- handle: AgentHandle,
6542
- credential: CredentialRef,
6543
- organizations: Schema.Array(RequestOrganization)
6578
+ folders: Schema.Array(Schema.Struct({
6579
+ path: ConfigFolderPath,
6580
+ owner: OwnerName,
6581
+ ...MachineConnected.fields,
6582
+ organizations: Schema.Array(RequestOrganization),
6583
+ replacement: Schema.optionalKey(GrantReplacement)
6584
+ })),
6585
+ excluded: Schema.Array(ConfigFolderPath)
6544
6586
  }),
6545
6587
  Schema.Struct({ state: Schema.Literal("refused") }),
6546
6588
  Schema.Struct({ state: Schema.Literal("aborted") }),
6547
6589
  Schema.Struct({ state: Schema.Literal("expired") }),
6548
6590
  Schema.Struct({
6549
6591
  state: Schema.Literal("failed"),
6550
- reason: Schema.Literals([...AttachmentFailure.fields.reason.literals, "not confirmed"]),
6592
+ reason: AttachmentFailure.fields.reason,
6551
6593
  nextStep: Schema.String
6552
6594
  })
6553
6595
  ]);
6596
+ /** The grant IDs saved by this terminal, each belonging to the same admission. */
6597
+ const SavedMachineGrants = Schema.Array(TokenId).check(Schema.isMinLength(1), Schema.isMaxLength(8), Schema.isUnique());
6598
+ Schema.Struct({
6599
+ approval: ApprovalId,
6600
+ grants: SavedMachineGrants
6601
+ });
6554
6602
  /**
6555
6603
  * The machine saying it saved the grant it collected: confirmed, the same again, or not, once ref0
6556
6604
  * has taken the grant to revoke it, and the machine deletes what it saved.
@@ -6583,21 +6631,34 @@ const AuthorizeIn = Schema.Struct({
6583
6631
  organization: OrgId,
6584
6632
  targetGeneration: TargetGeneration
6585
6633
  });
6586
- /** What every connect names: the agent, the machine and its host grant, and what it was bound to. */
6587
- const connectFields = {
6634
+ /** One folder admitted under the request's machine and approving browser. */
6635
+ const ConnectFolderCommand = Schema.Struct({
6636
+ path: ConfigFolderPath,
6588
6637
  agent: AttachmentAgent,
6589
- machine: MachineId,
6590
- machineName: MachineName,
6591
6638
  token: TokenId,
6592
6639
  secretHash: SecretHash,
6593
- browserSession: TokenId,
6594
- personGeneration: Generation,
6640
+ replaces: Schema.optionalKey(TokenId),
6595
6641
  authorizeIn: Schema.Array(AuthorizeIn)
6596
- };
6642
+ });
6597
6643
  Schema.Struct({
6598
6644
  request: ApprovalId,
6599
- ...connectFields
6645
+ machine: MachineId,
6646
+ machineName: MachineName,
6647
+ browserSession: TokenId,
6648
+ personGeneration: Generation,
6649
+ folders: Schema.Array(ConnectFolderCommand).check(Schema.isMinLength(1), Schema.isMaxLength(8), uniqueFolderPaths),
6650
+ excluded: Schema.Array(ConfigFolderPath).check(Schema.isMaxLength(7), Schema.isUnique())
6651
+ });
6652
+ const FoldersConnected = Schema.Struct({
6653
+ folders: Schema.Array(Schema.Struct({
6654
+ path: ConfigFolderPath,
6655
+ ...MachineConnected.fields,
6656
+ replacement: Schema.optionalKey(GrantReplacement)
6657
+ })),
6658
+ excluded: Schema.Array(ConfigFolderPath)
6600
6659
  });
6660
+ Schema.Array(GrantReplacement);
6661
+ Schema.Array(TokenId).check(Schema.isMaxLength(8));
6601
6662
  /** An attachment that isn't there, or isn't the caller's, answers the same. */
6602
6663
  var AttachmentNotFound = class extends Schema.TaggedError()("AttachmentNotFound", { nextStep: Schema.String }, { httpApiStatus: 404 }) {};
6603
6664
  /** Connecting connected nothing, and why: what an attachment's approval came to instead. */
@@ -6779,7 +6840,7 @@ const FindApproval = Schema.Union([Schema.Struct({ code: TypedApprovalCode }), S
6779
6840
  */
6780
6841
  const ApprovalOptionsRequest = Schema.Struct({
6781
6842
  code: Schema.optionalKey(TypedApprovalCode),
6782
- agent: Schema.optionalKey(ConnectAgent)
6843
+ folders: Schema.optionalKey(ConnectFolderChoices)
6783
6844
  });
6784
6845
  /**
6785
6846
  * An answer: yes, with the passkey, or no. For an agent's ask, each answer can set the owner's
@@ -6832,7 +6893,11 @@ const ApprovalState = Schema.Union([
6832
6893
  state: Schema.Literal("waiting"),
6833
6894
  expiresAt: Timestamp
6834
6895
  }),
6835
- Schema.Struct({ state: Schema.Literal("approved") }),
6896
+ Schema.Struct({
6897
+ state: Schema.Literal("approved"),
6898
+ /** A machine's answering browser may forget its saved answer once the terminal kept it. */
6899
+ collected: Schema.optionalKey(Schema.Literal(true))
6900
+ }),
6836
6901
  Schema.Struct({ state: Schema.Literal("refused") }),
6837
6902
  Schema.Struct({ state: Schema.Literal("expired") }),
6838
6903
  Schema.Struct({
@@ -11635,10 +11700,12 @@ Schema.Union([
11635
11700
  NotPermitted
11636
11701
  ]);
11637
11702
  /**
11638
- * A session's fork's path on ref0's host. Its thread's, `/{owner}/{project}/threads/{n}/{repo}.git`
11639
- * on a project's thread and `/{owner}/threads/{n}/{repo}.git` on an org thread, reaches the fork
11640
- * of the session whose token asks, and takes its pushes. A session's,
11641
- * `…/threads/{n}/sessions/{m}/{repo}.git`, reads that session's fork, and takes no push.
11703
+ * A fork's path on ref0's host. Its thread's, `/{owner}/{project}/threads/{n}/{repo}.git` on a
11704
+ * project's thread and `/{owner}/threads/{n}/{repo}.git` on an org thread, reaches the fork of the
11705
+ * session whose token asks, and takes its pushes. A session's,
11706
+ * `…/threads/{n}/sessions/{m}/{repo}.git`, reads that session's current fork, and a fork's,
11707
+ * `…/threads/{n}/forks/{fork}/{repo}.git`, reads that fork when it holds thread `n`'s work, a
11708
+ * session's on it or a run's whose pull request is on it. Neither takes a push.
11642
11709
  */
11643
11710
  const ForkPath = Schema.String.check(Schema.isPattern(/^\/[^\s]+\.git$/), Schema.isMaxLength(512)).pipe(Schema.brand("ForkPath"));
11644
11711
  /** A session's fork's URL on the app's one origin: the one a notice names, and a clone pushes to. */
@@ -11660,17 +11727,21 @@ const ForkView = Schema.Struct({
11660
11727
  /** On the app's one origin, whichever host was asked. */
11661
11728
  url: ForkUrl
11662
11729
  });
11663
- Schema.Struct({
11730
+ /**
11731
+ * For a reader that sees only threads it holds a grant on, those threads: a fork of a thread
11732
+ * stacked, at any depth, on any other is refused, since it holds that thread's work. Unset for one
11733
+ * that reads the project as a whole.
11734
+ */
11735
+ const readerSees = { only: Schema.optionalKey(Schema.Array(ThreadId)) };
11736
+ Schema.Union([Schema.Struct({
11664
11737
  session: SessionId,
11665
- fork: Schema.optionalKey(ForkId),
11666
- /**
11667
- * For a reader that sees only threads it holds a grant on, those threads: a fork of a thread
11668
- * stacked, at any depth, on any other is refused, since it holds that thread's work. Unset for
11669
- * one that reads the project as a whole.
11670
- */
11671
- only: Schema.optionalKey(Schema.Array(ThreadId))
11672
- });
11673
- /** A session's fork in Artifacts, as Git reaches it: where it is, and which Git repository. */
11738
+ ...readerSees
11739
+ }), Schema.Struct({
11740
+ fork: ForkId,
11741
+ thread: ThreadId,
11742
+ ...readerSees
11743
+ })]);
11744
+ /** A fork in Artifacts, as Git reaches it: where it is, and which Git repository. */
11674
11745
  const ForkPlace = Schema.Struct({
11675
11746
  ...CurrentBaseline.fields,
11676
11747
  gitRepository: GitRepositoryId
@@ -11701,19 +11772,16 @@ const SessionBase = Schema.Struct({
11701
11772
  commit: CommitOid,
11702
11773
  /**
11703
11774
  * Where to fetch it from, on ref0's origin: the repo's own path, as `ref0 clone` cloned it, for
11704
- * `main`; for a stack, the path of the fork that holds the pin.
11775
+ * `main`; for a stack, the path of the fork that holds the pin, by its ID under the thread below.
11705
11776
  */
11706
11777
  path: Schema.String.check(Schema.isPattern(/^\/[^\s]+\.git$/), Schema.isMaxLength(512)),
11707
11778
  /** `path` on the app's one origin. A client checks it's a fork of its own repo there. */
11708
11779
  url: Schema.String,
11709
11780
  ref: Schema.Literal("refs/heads/main")
11710
11781
  });
11711
- /**
11712
- * No base to fetch: `main` has no commit yet, or the pin of the thread below is in a workflow
11713
- * run's fork, which has no session's path to fetch from.
11714
- */
11782
+ /** No base to fetch: `main` has no commit yet. */
11715
11783
  var NoBase = class extends Schema.TaggedError()("NoBase", {
11716
- why: Schema.Literals(["main empty", "held by a run"]),
11784
+ why: Schema.Literal("main empty"),
11717
11785
  nextStep: Schema.String
11718
11786
  }, { httpApiStatus: 404 }) {};
11719
11787
  Schema.Struct({
@@ -11731,15 +11799,14 @@ const BaseOnMain = Schema.Struct({
11731
11799
  commit: CommitOid
11732
11800
  });
11733
11801
  /**
11734
- * The base on the thread below, `lower`: its pin's commit, the fork that holds it, and that
11735
- * fork's session, or none for a workflow run's fork.
11802
+ * The base on the thread below, `lower`: its pin's commit, and the fork that holds it, a session's
11803
+ * on that thread or a run's whose pull request is on it.
11736
11804
  */
11737
11805
  const BaseOnStack = Schema.Struct({
11738
11806
  on: Schema.Literal("stack"),
11739
11807
  lower: ThreadId,
11740
11808
  commit: CommitOid,
11741
- fork: ForkId,
11742
- session: Schema.NullOr(SessionId)
11809
+ fork: ForkId
11743
11810
  });
11744
11811
  Schema.Union([
11745
11812
  BaseOnMain,
@@ -11787,10 +11854,10 @@ const GateInPlaceView = Schema.Struct({
11787
11854
  /**
11788
11855
  * One `from`'s yes over the run that counts for a part that needs one (L2), as `passkey.check`
11789
11856
  * asks: `asked`, waiting, of `asked` when it's one person; `yes`, by whom and when; `no`;
11790
- * `expired`, its day passed unanswered; `refused`, the person it names can't be asked; or
11791
- * `revoked`, a yes whose answerer a miss revoked since, until an admin restores them. A local
11792
- * run's no or day passing waits for a newer local run; a ref0 run's, or a refusal, leaves the
11793
- * part with no yes, until an admin overrides it.
11857
+ * `expired`, its day passed unanswered; `refused`, asking nobody, `why`; or `revoked`, a yes whose
11858
+ * answerer a miss revoked since, until an admin restores them. A local run's no or day passing
11859
+ * waits for a newer local run; a ref0 run's, or a refusal, leaves the part with no yes, until an
11860
+ * admin overrides it.
11794
11861
  */
11795
11862
  const GatePartYes = Schema.Struct({
11796
11863
  from: PasskeyFrom,
@@ -11802,6 +11869,12 @@ const GatePartYes = Schema.Struct({
11802
11869
  "refused",
11803
11870
  "revoked"
11804
11871
  ]),
11872
+ /**
11873
+ * Why a request was refused: `target`, nobody it names can be asked, a person who isn't there
11874
+ * or can't see the pull request's thread; or `self`, it names the person behind the run, or a
11875
+ * permission only they hold, who can't be the second pair of eyes over their own run.
11876
+ */
11877
+ why: Schema.optionalKey(Schema.Literals(["target", "self"])),
11805
11878
  asked: Schema.optionalKey(PersonId),
11806
11879
  by: Schema.optionalKey(OwnerName),
11807
11880
  at: Schema.optionalKey(Schema.DateTimeUtcFromMillis)
@@ -14839,6 +14912,11 @@ var ApprovalSecret = class extends HttpApiMiddleware.Service()("ref0/contracts/A
14839
14912
  security: { bearer: HttpApiSecurity.bearer },
14840
14913
  error: [Unauthenticated]
14841
14914
  }) {};
14915
+ /**
14916
+ * A machine's request whose name its contract refuses, answered as `CommandRefused`, which says
14917
+ * what to change. Any other part that fails its contract is answered with Effect's empty 400.
14918
+ */
14919
+ var MachineNameRefusal = class extends HttpApiMiddleware.Service()("ref0/contracts/MachineNameRefusal", { error: CommandRefused }) {};
14842
14920
  const idempotency = { "idempotency-key": RequestId };
14843
14921
  const inProject = {
14844
14922
  owner: OwnerRef,
@@ -14962,14 +15040,17 @@ var MachineAttachmentsGroup = class extends HttpApiGroup.make("machineAttachment
14962
15040
  SlowDown,
14963
15041
  AuthorityUnavailable
14964
15042
  ]
14965
- }), HttpApiEndpoint.post("collect", "/v1/attachments/requests/:approval/result", {
15043
+ }).middleware(MachineNameRefusal), HttpApiEndpoint.post("collect", "/v1/attachments/requests/:approval/result", {
14966
15044
  params: { approval: ApprovalId },
14967
15045
  payload: Schema.Struct({ answerCode: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(64))) }),
14968
15046
  success: RequestState,
14969
15047
  error: [AttachmentNotFound, AuthorityUnavailable]
14970
15048
  }).middleware(ApprovalSecret), HttpApiEndpoint.post("confirm", "/v1/attachments/requests/:approval/collected", {
14971
15049
  params: { approval: ApprovalId },
14972
- payload: Schema.Struct({ answerCode: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(64))) }),
15050
+ payload: Schema.Struct({
15051
+ grants: SavedMachineGrants,
15052
+ answerCode: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(64)))
15053
+ }),
14973
15054
  headers: idempotency,
14974
15055
  success: RequestConfirmed,
14975
15056
  error: [AttachmentNotFound, AuthorityUnavailable]
@@ -17978,7 +18059,7 @@ HttpApi.reflect(Api, {
17978
18059
  * leaves out only `ApprovalNeeded`, at `202`.
17979
18060
  */
17980
18061
  const schemasOf = (name) => Option.fromNullishOr(reflected.get(name));
17981
- Schema.toCodecJson(MachineConnected), Schema.toCodecJson(AttachmentFailed);
18062
+ Schema.toCodecJson(FoldersConnected), Schema.toCodecJson(AttachmentFailed);
17982
18063
  const isEndpointName = (name) => name in surfaces;
17983
18064
  const encodeJson = Schema.encodeEffect(Schema.fromJsonString(Schema.Json));
17984
18065
  const decodeJson = Schema.decodeUnknownEffect(Schema.Json);
@@ -18247,6 +18328,6 @@ const signOut = (origin) => Effect.gen(function* () {
18247
18328
  yield* client.execute(HttpClientRequest.make(method)(path, { body: HttpBody.jsonUnsafe({}) }));
18248
18329
  });
18249
18330
  //#endregion
18250
- 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 };
18331
+ 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 };
18251
18332
 
18252
18333
  //# sourceMappingURL=client.mjs.map