@ref0/sdk 0.10.0 → 0.11.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
@@ -5423,12 +5423,15 @@ const name = ownerNamePattern.source.replace(/^\^|\$$/g, "");
5423
5423
  const projectPattern = new RegExp(`^(${name})/(${name})$`);
5424
5424
  const threadPattern = new RegExp(`^(${name})(?:/(${name}))?#([1-9][0-9]*)$`);
5425
5425
  const repoPattern = new RegExp(`^(${name})/(${repoNamePattern.source.replace(/^\^|\$$/g, "")})$`);
5426
+ const pullRequestPattern = new RegExp(`${repoPattern.source.replace(/\$$/, "")}#[1-9][0-9]*$`);
5426
5427
  /** A project, `owner/project`. */
5427
5428
  const WrittenProject = Schema.String.check(Schema.isPattern(projectPattern)).pipe(Schema.brand("WrittenProject"));
5428
5429
  /** A thread, `owner/project#number`, or an org thread, `owner#number`. */
5429
5430
  const WrittenThread = Schema.String.check(Schema.isPattern(threadPattern)).pipe(Schema.brand("WrittenThread"));
5430
5431
  /** A repo, `owner/repo`. */
5431
5432
  const WrittenRepo = Schema.String.check(Schema.isPattern(repoPattern)).pipe(Schema.brand("WrittenRepo"));
5433
+ /** A pull request, `owner/repo#number`. */
5434
+ const WrittenPullRequest = Schema.String.check(Schema.isPattern(pullRequestPattern)).pipe(Schema.brand("WrittenPullRequest"));
5432
5435
  /** A written project's parts, as an endpoint's path takes them. */
5433
5436
  const projectParts = (written) => {
5434
5437
  const [, owner = "", project = ""] = projectPattern.exec(written) ?? [];
@@ -5437,6 +5440,15 @@ const projectParts = (written) => {
5437
5440
  project
5438
5441
  };
5439
5442
  };
5443
+ /** A written thread's parts, as an endpoint's path takes them: no project for an org thread. */
5444
+ const threadParts = (written) => {
5445
+ const [, owner = "", project, number = ""] = threadPattern.exec(written) ?? [];
5446
+ return {
5447
+ owner,
5448
+ project,
5449
+ number
5450
+ };
5451
+ };
5440
5452
  //#endregion
5441
5453
  //#region ../contracts/src/mention-views.ts
5442
5454
  /**
@@ -6676,594 +6688,227 @@ Schema.Union([Schema.Struct({ found: Schema.Literal(false) }), Schema.Struct({
6676
6688
  attachGrant: Schema.optionalKey(EventId)
6677
6689
  })]);
6678
6690
  //#endregion
6679
- //#region ../contracts/src/approvals.ts
6691
+ //#region ../contracts/src/plan-events.ts
6680
6692
  /**
6681
- * Approvals, as their commands travel: what a terminal, a page or an agent asks its person to
6682
- * say yes to. A command is one endpoint, by its name in the surface table, and its request, as
6683
- * that endpoint encodes it. ref0 decodes each part by the endpoint's own `Schema` before it
6684
- * keeps or shows anything, so a command is exactly what the endpoint would take.
6693
+ * A plan's events, in its thread's project's log, written by the Project DO. A version's
6694
+ * state is folded from these and its thread's, never recorded on its own.
6685
6695
  */
6686
6696
  /**
6687
- * An endpoint by its name in the surface table, `group.endpoint`. Checked against the table
6688
- * where the command is made canonical, since the table is typed from the API this is part of.
6697
+ * A new version, as a draft. Its content never changes after this. Its reason, when given, says
6698
+ * why it was written; it's beside the plan, never in it, so it's no part of the content hash.
6689
6699
  */
6690
- const CommandEndpoint = Schema.String.check(Schema.isPattern(/^[a-zA-Z]+\.[a-zA-Z]+$/));
6691
- /** One command, as asked: its endpoint, and its request's path, query and payload, encoded. */
6692
- const ApprovalCommand = Schema.Struct({
6693
- endpoint: CommandEndpoint,
6694
- params: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)),
6695
- query: Schema.optionalKey(Schema.JsonObject),
6696
- payload: Schema.optionalKey(Schema.Json)
6697
- });
6698
- /** A command ref0 won't ask anyone about: not an endpoint's request, or not one an approval runs. */
6699
- var CommandRefused = class extends Schema.TaggedError()("CommandRefused", { nextStep: Schema.String }, { httpApiStatus: 400 }) {};
6700
- /** A terminal asking: its command, and the hash of the secret it collects the result with. */
6701
- const StartApproval = Schema.Struct({
6702
- command: ApprovalCommand,
6703
- secretHash: SecretHash
6704
- });
6705
- /** A terminal's approval, started: what to show its person, and until when. */
6706
- const ApprovalStarted = Schema.Struct({
6707
- approval: ApprovalId,
6708
- code: ApprovalCode,
6709
- expiresAt: Timestamp
6710
- });
6700
+ const PlanWritten = eventKind("plan.written", Schema.Struct({
6701
+ thread: ThreadId,
6702
+ version: PlanVersion,
6703
+ plan: PlanRecord,
6704
+ contentHash: PlanContentHash,
6705
+ reason: Schema.optionalKey(TextId)
6706
+ }));
6711
6707
  /**
6712
- * An answer that waits for the person: the call only the person may make, or that agents ask
6713
- * for, became an approval, which the person answers on their own page. A `202`, never a failure
6714
- * of the call: whoever asked collects the result with `GET /v1/approvals/{approval}`.
6708
+ * The version is put to approval: each repo it names is asked to answer for it, and ref0 says yes
6709
+ * once they have or their time runs out. Any earlier draft or proposed version is
6710
+ * superseded.
6715
6711
  */
6716
- var ApprovalNeeded = class extends Schema.TaggedError()("ApprovalNeeded", {
6717
- approval: ApprovalId,
6718
- says: Schema.String,
6719
- expiresAt: Timestamp
6720
- }, { httpApiStatus: 202 }) {};
6721
- const terminalAsker = Schema.Struct({ kind: Schema.Literal("terminal") });
6722
- const pageAsker = Schema.Struct({ kind: Schema.Literal("page") });
6723
- const agentAsker = Schema.Struct({
6724
- kind: Schema.Literal("agent"),
6725
- agent: AgentId,
6726
- handle: AgentHandle,
6727
- session: SessionId,
6728
- /** The attachment its credential was made under, for a person's agent in an organization. */
6729
- attachment: Schema.optionalKey(CredentialRef)
6712
+ const PlanProposed = eventKind("plan.proposed", Schema.Struct({
6713
+ thread: ThreadId,
6714
+ version: PlanVersion
6715
+ }));
6716
+ /** Who said yes: ref0's plans part, once every repo answered or its time ran out. */
6717
+ const PlanAcceptedBy = Schema.Struct({
6718
+ kind: Schema.Literal("answered"),
6719
+ part: Ref0Part
6730
6720
  });
6731
- /**
6732
- * Who asked, as a receipt keeps it: a terminal, one of ref0's pages, an agent, or a machine
6733
- * asking to connect, by its ID and its own word for itself, and from where.
6734
- */
6735
- const ApprovalAsker = Schema.Union([
6736
- terminalAsker,
6737
- pageAsker,
6738
- Schema.Struct({
6739
- kind: Schema.Literal("machine"),
6740
- machine: MachineId,
6741
- machineName: MachineName,
6742
- askedFrom: Schema.optionalKey(Schema.String)
6743
- }),
6744
- agentAsker
6745
- ]);
6746
- /**
6747
- * Who asked, as the person reads a request before they answer: a terminal, a page or an agent.
6748
- * A machine's request is read as an `AttachmentRequestView`, never as a command.
6749
- */
6750
- const ApprovalViewAsker = Schema.Union([
6751
- terminalAsker,
6752
- pageAsker,
6753
- agentAsker
6754
- ]);
6755
- /** A request, as the person reads it before they answer. */
6756
- const ApprovalView = Schema.Struct({
6757
- approval: ApprovalId,
6758
- /** The command as its CLI line. */
6759
- says: Schema.String,
6760
- /** Everything the command carries, each named, in order: nothing it would run is left out. */
6761
- fields: Schema.Array(Schema.Struct({
6762
- name: Schema.String,
6763
- value: Schema.String,
6764
- part: Schema.Literals([
6765
- "path",
6766
- "query",
6767
- "payload"
6768
- ])
6769
- })),
6770
- command: ApprovalCommand,
6771
- asker: ApprovalViewAsker,
6772
- askedFrom: Schema.optionalKey(Schema.String),
6773
- askedAt: Timestamp,
6774
- expiresAt: Timestamp,
6775
- /**
6776
- * An agent's ask: the kind of action its answer may set agents' permission for, and whether a
6777
- * yes may let agents take it without asking. A no with the passkey may always stop them asking.
6778
- */
6779
- agentPermission: Schema.optionalKey(Schema.Struct({
6780
- action: ScopeAction,
6781
- mayAllow: Schema.Boolean
6782
- })),
6783
- /**
6784
- * What the command acts on, drawn as ref0 resolves it for the person reading, where its
6785
- * endpoint names a preview. Without one the page can draw, it offers only no.
6786
- */
6787
- preview: Schema.optionalKey(ApprovalPreview)
6721
+ /** A child thread, by the plan entry that made it. */
6722
+ const PlanChildThread = Schema.Struct({
6723
+ entry: PlanEntryKey,
6724
+ thread: ThreadId
6788
6725
  });
6789
- /** A statement's hash: the SHA-256 of its words and quoted values as JSON, as lowercase hex. */
6790
- const StatementHash = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/));
6726
+ const ChildThreads = Schema.Array(PlanChildThread).check(Schema.isMaxLength(50));
6791
6727
  /**
6792
- * Who asks for a yes to a statement: a workflow's run, `passkey.run`'s, by the workflow and the
6793
- * run; or a gate's check, `passkey.check`'s, by the check, the pull request's version it gates and
6794
- * the check run its statement is over.
6728
+ * The version is accepted, and the one accepted before it superseded. Each child is named only
6729
+ * once its owner has registered it.
6795
6730
  */
6796
- const StatementAsker = Schema.Union([Schema.Struct({
6797
- kind: Schema.Literal("workflow"),
6798
- workflow: WorkflowName,
6799
- run: WorkflowRunId
6800
- }), Schema.Struct({
6801
- kind: Schema.Literal("gate"),
6802
- check: CheckKey,
6803
- pullRequest: PullRequestNumber,
6804
- version: VersionNumber,
6805
- run: CheckRunId
6806
- })]);
6731
+ const PlanAccepted = eventKind("plan.accepted", Schema.Struct({
6732
+ thread: ThreadId,
6733
+ version: PlanVersion,
6734
+ by: PlanAcceptedBy,
6735
+ /** The version accepted before this one. */
6736
+ supersedes: Schema.optionalKey(PlanVersion),
6737
+ /** Children made now, each starting in planning. */
6738
+ started: ChildThreads,
6739
+ /** Entries an earlier version dropped and this one adds back: the same child, reopened if it was closed. */
6740
+ rejoined: ChildThreads,
6741
+ /** Children no longer part of the plan, so it stops waiting on them. Closing one is its own event. */
6742
+ dropped: ChildThreads
6743
+ }));
6744
+ //#endregion
6745
+ //#region ../contracts/src/plan-calls.ts
6807
6746
  /**
6808
- * A passkey request, as the person reads it before they answer: the statement, its words as its
6809
- * asker wrote them and each value it quotes, and its hash; who asks; where, a workflow's
6810
- * `owner/repo` or a thread's `owner/project#number`, or a gate's pull request, `owner/repo#number`;
6811
- * whom it asks, the run's accountable person, or for a gate the person behind its run, a person by
6812
- * name, or a permission's holders; and until when.
6747
+ * Plans and decisions: what the Worker asks a thread's Project DO, once `Authorize` has said
6748
+ * who's acting. A plan is written with its words; the Project DO stores each as a text and
6749
+ * records the version with their IDs.
6813
6750
  */
6814
- const StatementView = Schema.Struct({
6815
- approval: ApprovalId,
6816
- statement: WorkflowText,
6817
- hash: StatementHash,
6818
- asker: StatementAsker,
6819
- home: Schema.String,
6820
- from: Schema.Union([Schema.Literals(["accountable", "person"]), Schema.Struct({ permission: RepoPermissionName })]),
6821
- askedAt: Timestamp,
6822
- expiresAt: Timestamp
6823
- });
6751
+ /** A plan's free text: one of its outcomes, or an answer's reason. */
6752
+ const PlanText = Schema.String.check(Schema.isBetweenLength(1, 2048));
6824
6753
  /**
6825
- * The person's own requests, waiting for them; the passkey requests workflows' runs and gates asked
6826
- * them; and each machine's request this browser session is the answerer of, so a reload finds it
6827
- * again without its code.
6754
+ * How a plan does its work, in system terms, for people: about a page. A revision replaces it,
6755
+ * with a reason; no one appends to it.
6828
6756
  */
6829
- const ApprovalsWaiting = Schema.Struct({
6830
- approvals: Schema.Array(ApprovalView),
6831
- statements: Schema.Array(StatementView),
6832
- requests: Schema.Array(AttachmentRequestView)
6833
- });
6834
- /** Finding a terminal's request by the code it showed. */
6835
- const FindApproval = Schema.Union([Schema.Struct({ code: TypedApprovalCode }), Schema.Struct({ link: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{22}$/)) })]);
6757
+ const Approach = Schema.String.check(Schema.isBetweenLength(1, 6e3));
6836
6758
  /**
6837
- * Asking for the passkey's options to answer a request: a terminal's request needs its code
6838
- * again, so its ID alone, which travels where its code doesn't, never answers it. A machine's
6839
- * request needs its answerer, and the agent it chooses to connect, before a yes has options.
6759
+ * A child as written. On a top-level org thread's plan, `project` names one of its owner's
6760
+ * projects to start it in, as that project's thread; left out, it's in its parent's scope.
6840
6761
  */
6841
- const ApprovalOptionsRequest = Schema.Struct({
6842
- code: Schema.optionalKey(TypedApprovalCode),
6843
- folders: Schema.optionalKey(ConnectFolderChoices)
6762
+ const PlanChildInput = Schema.Struct({
6763
+ entry: PlanEntryKey,
6764
+ title: Title,
6765
+ outcome: Outcome,
6766
+ stackedOn: Schema.optionalKey(PlanEntryKey),
6767
+ required: Schema.Boolean,
6768
+ project: Schema.optionalKey(ProjectName)
6844
6769
  });
6845
6770
  /**
6846
- * An answer: yes, with the passkey, or no. For an agent's ask, each answer can set the owner's
6847
- * permission its own way, so a pairing that can't happen can't be sent: yes, and let agents do
6848
- * it without asking; no, and stop agents asking, with the passkey too.
6771
+ * A plan as written: `PlanRecord`'s shape, with its words in place of text IDs. Its repos are up
6772
+ * to 20 of the project's, by name; a parent whose work is all in its children names none.
6849
6773
  */
6850
- const AnswerApproval = Schema.Union([
6851
- Schema.Struct({
6852
- answer: Schema.Literal("yes"),
6853
- permission: Schema.optionalKey(Schema.Literal("allow")),
6854
- assertion: PasskeyAsserted,
6855
- code: Schema.optionalKey(TypedApprovalCode),
6856
- /** The preview the page drew, where the command's endpoint names one. */
6857
- preview: Schema.optionalKey(PreviewEcho),
6858
- /** The statement the page showed, by its hash, for a workflow run's or a gate's passkey request. */
6859
- statement: Schema.optionalKey(Schema.Struct({ hash: StatementHash }))
6860
- }),
6861
- Schema.Struct({
6862
- answer: Schema.Literal("no"),
6863
- permission: Schema.Literal("deny"),
6864
- assertion: PasskeyAsserted,
6865
- code: Schema.optionalKey(TypedApprovalCode)
6866
- }),
6867
- Schema.Struct({
6868
- answer: Schema.Literal("no"),
6869
- code: Schema.optionalKey(TypedApprovalCode)
6870
- })
6871
- ]);
6774
+ const PlanInput = Schema.Struct({
6775
+ approach: Schema.optionalKey(Approach),
6776
+ repos: Schema.Array(RepoName).check(Schema.isMaxLength(20)),
6777
+ outcomes: Schema.Array(PlanText).check(Schema.isBetweenLength(1, 50)),
6778
+ children: Schema.Array(PlanChildInput).check(Schema.isMaxLength(50))
6779
+ }).check(Schema.makeFilter((plan) => planProblem(plan) ?? true));
6872
6780
  /**
6873
- * What running an approved command came to: its status, and its endpoint's answer or refusal,
6874
- * as JSON. ref0 reads it by the command's endpoint before anyone sees it, and whoever asked reads
6875
- * it the same way, with `ranOf`: this schema is part of the API the endpoints' types come from,
6876
- * so it can't be typed by them itself.
6781
+ * A project a plan's child names, as the Worker found it in the plan's owner before it asked the
6782
+ * scope: its ID, and whether the writer can see it; or, with no `project`, that the owner has
6783
+ * none by that name. The Worker refuses nothing for it, since only the scope knows which entries
6784
+ * a version keeps.
6877
6785
  */
6878
- const Ran = Schema.Struct({
6879
- status: Schema.Int,
6880
- result: Schema.Json
6786
+ const NamedProject = Schema.Struct({
6787
+ name: ProjectName,
6788
+ project: Schema.optionalKey(ProjectId),
6789
+ seen: Schema.Boolean
6881
6790
  });
6882
- /**
6883
- * A ran command whose answer its endpoint's schemas no longer read, such as one kept from
6884
- * before they changed: it ran, and what it came to can't be said.
6885
- */
6886
- var ResultUnreadable = class extends Schema.TaggedError()("ResultUnreadable", { nextStep: Schema.String }, { httpApiStatus: 500 }) {};
6887
- /**
6888
- * Where a request stands, for whoever asked: still waiting; approved, and running as soon as
6889
- * ref0 can; refused; expired; or what it ran to, with the endpoint it ran, whose schemas read it.
6890
- */
6891
- const ApprovalState = Schema.Union([
6892
- Schema.Struct({
6893
- state: Schema.Literal("waiting"),
6894
- expiresAt: Timestamp
6895
- }),
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
- }),
6901
- Schema.Struct({ state: Schema.Literal("refused") }),
6902
- Schema.Struct({ state: Schema.Literal("expired") }),
6903
- Schema.Struct({
6904
- state: Schema.Literal("ran"),
6905
- endpoint: CommandEndpoint,
6906
- ...Ran.fields
6907
- })
6908
- ]);
6909
- /** Only the answering browser receives a machine's answer code; state reads never carry it. */
6910
- const ApprovalAnswer = Schema.Union([
6911
- Schema.Struct({
6912
- ...ApprovalState.members[1].fields,
6913
- answerCode: ApprovalCode
6914
- }),
6915
- Schema.Struct({
6916
- ...ApprovalState.members[4].fields,
6917
- answerCode: ApprovalCode
6918
- }),
6919
- ApprovalState
6920
- ]);
6921
- /** A request that isn't there, or isn't the caller's to see, answers the same. */
6922
- var ApprovalNotFound = class extends Schema.TaggedError()("ApprovalNotFound", { nextStep: Schema.String }, { httpApiStatus: 404 }) {};
6923
- /** Too many asked, or too many codes typed, from here in the last hour. */
6924
- var SlowDown = class extends Schema.TaggedError()("SlowDown", { nextStep: Schema.String }, { httpApiStatus: 429 }) {};
6925
- /** A command's hash: the SHA-256 of its canonical JSON, as lowercase hex. */
6926
- const CommandHash = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/));
6927
6791
  Schema.Struct({
6928
- approval: ApprovalId,
6929
- endpoint: CommandEndpoint,
6930
- /** The command's canonical JSON. */
6931
- command: Schema.String,
6932
- commandHash: CommandHash,
6933
- asker: ApprovalAsker,
6934
- /** The browser session the person answered in, for their log. */
6935
- credential: CredentialRef,
6936
- generation: Generation,
6937
- /** When the request expires, in epoch milliseconds. */
6938
- deadline: Schema.Int,
6939
- challenge: Schema.String,
6940
- /** A machine answer retries only from its answering session, with this key. */
6941
- answerKey: Schema.optionalKey(RequestId),
6942
- /** An agent's ask: the credential it asked with, checked again before the answer counts. */
6943
- asking: Schema.optionalKey(TokenId),
6944
- /** The kind of action the person, answering, let agents take without asking from now on. */
6945
- allow: Schema.optionalKey(ScopeAction)
6792
+ ...commandFields,
6793
+ project: ProjectId,
6794
+ ownerName: OwnerName,
6795
+ number: ThreadNumber,
6796
+ plan: PlanInput,
6797
+ projects: Schema.Array(NamedProject).check(Schema.isMaxLength(50)),
6798
+ reason: Schema.optionalKey(Reason),
6799
+ propose: Schema.Boolean
6946
6800
  });
6947
6801
  Schema.Struct({
6948
- approval: ApprovalId,
6949
- action: ScopeAction,
6950
- credential: CredentialRef,
6951
- generation: Generation
6802
+ ...commandFields,
6803
+ ownerName: OwnerName,
6804
+ project: ProjectId,
6805
+ number: ThreadNumber,
6806
+ version: PlanVersion
6807
+ });
6808
+ /** A decision as it stands: what it asks, who decides, the answers so far, and how it closed. */
6809
+ const DecisionView = Schema.Struct({
6810
+ decision: DecisionId,
6811
+ kind: DecisionKind,
6812
+ subject: DecisionSubject,
6813
+ question: Schema.optionalKey(TextId),
6814
+ options: Schema.Array(AnswerOption),
6815
+ lean: Schema.optionalKey(AnswerKey),
6816
+ deciders: Schema.Array(Decider),
6817
+ deadline: Schema.optionalKey(Schema.DateTimeUtcFromMillis),
6818
+ state: Schema.Literals(["open", "closed"]),
6819
+ answers: Schema.Array(Schema.Struct({
6820
+ decider: DeciderRef,
6821
+ answer: AnswerKey,
6822
+ reason: Schema.optionalKey(TextId),
6823
+ at: Schema.DateTimeUtcFromMillis
6824
+ })),
6825
+ result: Schema.optionalKey(AnswerKey),
6826
+ closedWhy: Schema.optionalKey(DecisionClosedWhy)
6952
6827
  });
6953
- Schema.Union([Schema.Struct({ denied: Schema.Literal(true) }), Schema.Struct({
6954
- denied: Schema.Literal(false),
6955
- reason: Schema.Literals(["generation moved", "not set up"])
6956
- })]);
6957
- Schema.Union([Schema.Struct({
6958
- admitted: Schema.Literal(true),
6959
- admittedAt: Schema.Int,
6960
- answerCode: Schema.optionalKey(ApprovalCode)
6961
- }), Schema.Struct({
6962
- admitted: Schema.Literal(false),
6963
- reason: Schema.Literals([
6964
- "expired",
6965
- "generation moved",
6966
- "challenge used",
6967
- "not set up",
6968
- "asker gone"
6969
- ])
6970
- })]);
6971
- Schema.Union([Schema.Struct({ found: Schema.Literal(false) }), Schema.Struct({
6972
- found: Schema.Literal(true),
6973
- endpoint: CommandEndpoint,
6974
- command: Schema.String,
6975
- commandHash: CommandHash,
6976
- generation: Generation,
6977
- generationNow: Generation,
6978
- /** The `approval.answered` its admission recorded in the person's log. */
6979
- answeredEvent: EventId,
6980
- /** Who asked, as that `approval.answered` says. */
6981
- asker: ApprovalAsker,
6982
- /** What running it came to, once it ran, as `KeptRan` keeps it. */
6983
- result: Schema.optionalKey(Schema.String)
6984
- })]);
6985
6828
  /**
6986
- * A `Ran` as it's kept, on its receipt and on its approval: its JSON, as text. The Owner DO
6987
- * keeps it as it comes and runs no endpoint's schemas, so it's read only by its endpoint, with
6988
- * `keptRan`, which refuses one they don't take.
6829
+ * Where a decision is, as people write it: its thread, `pip/default#3`, or an org thread's,
6830
+ * `acme#7`; and a gate's pull request, `pip/notes#1`. Its Project DO writes them as it answers,
6831
+ * from its own threads and repos and the owner's name the Worker gives it, so each reads as it's
6832
+ * called now.
6989
6833
  */
6990
- const KeptRan = Schema.fromJsonString(Ran);
6991
- Schema.Struct({
6992
- approval: ApprovalId,
6993
- result: Schema.String
6834
+ const DecisionNames = Schema.Struct({
6835
+ thread: WrittenThread,
6836
+ pullRequest: Schema.optionalKey(WrittenPullRequest)
6994
6837
  });
6995
- Schema.Struct({ result: Schema.String });
6996
- Schema.Struct({ approval: ApprovalId });
6997
- Schema.Struct({ approval: ApprovalId });
6998
- Schema.Union([Schema.Struct({ expired: Schema.Literal(true) }), Schema.Struct({ expired: Schema.Literal(false) })]);
6999
- Schema.Struct({
7000
- person: PersonId,
7001
- approval: ApprovalId
6838
+ /** A decision as `/v1` answers it: as it stands, and where it is, in words. */
6839
+ const NamedDecision = Schema.Struct({
6840
+ ...DecisionView.fields,
6841
+ names: DecisionNames
7002
6842
  });
7003
- //#endregion
7004
- //#region ../contracts/src/browser-sessions.ts
7005
6843
  /**
7006
- * A browser session's cookie: Better Auth's, named for ref0, `Secure` and host-only on the
7007
- * app's one origin. It holds the session's token, signed; the directory and the person's Owner DO hold
7008
- * only the token's SHA-256.
6844
+ * A version as it stands: its content, its state, and, once proposed, where its approval is: its
6845
+ * repos still being checked, or who accepted it.
7009
6846
  */
7010
- const browserSessionCookie = "__Secure-ref0.session_token";
7011
- Schema.Struct({
7012
- token: TokenId,
7013
- secretHash: SecretHash,
7014
- expiresAt: Schema.DateTimeUtcFromMillis
6847
+ const PlanVersionView = Schema.Struct({
6848
+ thread: ThreadId,
6849
+ number: ThreadNumber,
6850
+ version: PlanVersion,
6851
+ state: PlanState,
6852
+ contentHash: PlanContentHash,
6853
+ plan: PlanView,
6854
+ /** Why it was written, when its writer said: never part of its content. */
6855
+ reason: Schema.optionalKey(TextId),
6856
+ writtenBy: ActorRef,
6857
+ writtenAt: Schema.DateTimeUtcFromMillis,
6858
+ /** Proposed, and its repos haven't all answered yet: it isn't accepted yet. */
6859
+ checking: Schema.Boolean,
6860
+ /**
6861
+ * What its check found when it ended, every repo answered or their time run out: the repos
6862
+ * that never answered. None for a draft, while it's being checked, or when a newer version or
6863
+ * the thread closing ended the check first.
6864
+ */
6865
+ check: Schema.optionalKey(PlanCheck),
6866
+ /**
6867
+ * Accepted, and waiting to be recorded: on its new `children` registering, or on a merge under
6868
+ * the thread's current revision `publishing`.
6869
+ */
6870
+ accepting: Schema.optionalKey(Schema.Literals(["children", "publishing"])),
6871
+ acceptedBy: Schema.optionalKey(PlanAcceptedBy)
7015
6872
  });
7016
- Schema.Struct({ registered: Schema.Boolean });
7017
- /**
7018
- * Where a signed-in person stands: naming, when the name their GitHub login gave was taken or
7019
- * kept back, with that login as a suggestion; setting up, once their owner is made and before
7020
- * it's ready with this session registered, which naming again finishes; or ready.
7021
- */
7022
- const Welcome = Schema.Union([Schema.Struct({
7023
- state: Schema.Literals(["ready", "setting up"]),
7024
- person: PersonId,
7025
- owner: OwnerId,
7026
- name: OwnerName
7027
- }), Schema.Struct({
7028
- state: Schema.Literal("naming"),
7029
- person: PersonId,
7030
- suggestion: Schema.optionalKey(Schema.String)
7031
- })]);
7032
- /**
7033
- * A browser session renewed: its expiry, in its person's Owner DO and in the directory, and on its cookie.
7034
- * Renewed at most once a day, so one asked sooner answers its expiry unchanged.
7035
- */
7036
- const SessionRenewed = Schema.Struct({ expiresAt: Schema.DateTimeUtcFromMillis });
6873
+ /** A plan's free text refused before anything was stored, saying which. */
6874
+ var PlanTextRefused = class extends Schema.TaggedError()("PlanTextRefused", {
6875
+ /** Where it is in the plan, such as `outcomes[3]`. */
6876
+ where: Schema.String,
6877
+ problem: Schema.Literals([
6878
+ "empty",
6879
+ "too long",
6880
+ "looks like a secret"
6881
+ ]),
6882
+ nextStep: Schema.String
6883
+ }, { httpApiStatus: 422 }) {};
6884
+ /** A plan names a repo this project doesn't hold. */
6885
+ var PlanRepoNotFound = class extends Schema.TaggedError()("PlanRepoNotFound", {
6886
+ repo: RepoName,
6887
+ nextStep: Schema.String
6888
+ }, { httpApiStatus: 422 }) {};
7037
6889
  /**
7038
- * What starting a GitHub sign-in at `POST /auth/sign-in/social` answers: GitHub's address to go
7039
- * to, with the sign-in's state in a cookie set alongside. Better Auth's answer, which ref0 serves.
6890
+ * A plan names its scope's own repo, made just now, before the scope holds it. Nothing was kept
6891
+ * under the request's delivery ID, so the same request is written once it does.
7040
6892
  */
7041
- const NavigationUrl = Schema.String.check(Schema.isPattern(/^https?:\/\/[^\s/]+(?:\/[^\s]*)?$/), Schema.makeFilter((url) => URL.canParse(url) || "an HTTP(S) URL the platform can parse")).pipe(Schema.brand("NavigationUrl"));
7042
- const SignInStarted = Schema.Struct({ url: NavigationUrl });
6893
+ var OwnRepoNotReady = class extends Schema.TaggedError()("OwnRepoNotReady", {
6894
+ repo: RepoName,
6895
+ nextStep: Schema.String
6896
+ }, { httpApiStatus: 503 }) {};
7043
6897
  /**
7044
- * Where signing in sends the browser back to, as `POST /auth/sign-in/social` takes it: a path on
7045
- * ref0's own origin, such as `/welcome`, or a whole URL. Never a socket's.
6898
+ * A child entry this plan can't have: a project named on a project thread's plan or a nested org
6899
+ * thread's, a project that isn't there or the writer can't see, one where its proposer may not
6900
+ * start threads, an entry moved to another project, or a stack across scopes. A project that
6901
+ * isn't there and one the writer can't see are refused alike, as `ProjectNotFound` is.
7046
6902
  */
7047
- const SignInDestination = Schema.String.pipe(Schema.brand("SignInDestination"));
6903
+ var PlanChildRefused = class extends Schema.TaggedError()("PlanChildRefused", { nextStep: Schema.String }, { httpApiStatus: 422 }) {};
6904
+ var PlanVersionNotFound = class extends Schema.TaggedError()("PlanVersionNotFound", {
6905
+ number: ThreadNumber,
6906
+ version: PlanVersion,
6907
+ nextStep: Schema.String
6908
+ }, { httpApiStatus: 404 }) {};
7048
6909
  /**
7049
- * What `POST /auth/sign-in/social` takes to start signing in with GitHub: where the browser
7050
- * lands coming back, and where it lands when signing in failed. Better Auth's body, which ref0
7051
- * serves.
7052
- */
7053
- const StartSignIn = Schema.Struct({
7054
- provider: Schema.Literal("github"),
7055
- callbackURL: SignInDestination,
7056
- errorCallbackURL: SignInDestination
7057
- });
7058
- /** The name a naming person chose for their owner. */
7059
- const NameOwner = Schema.Struct({ name: OwnerName });
7060
- //#endregion
7061
- //#region ../contracts/src/plan-events.ts
7062
- /**
7063
- * A plan's events, in its thread's project's log, written by the Project DO. A version's
7064
- * state is folded from these and its thread's, never recorded on its own.
7065
- */
7066
- /**
7067
- * A new version, as a draft. Its content never changes after this. Its reason, when given, says
7068
- * why it was written; it's beside the plan, never in it, so it's no part of the content hash.
7069
- */
7070
- const PlanWritten = eventKind("plan.written", Schema.Struct({
7071
- thread: ThreadId,
7072
- version: PlanVersion,
7073
- plan: PlanRecord,
7074
- contentHash: PlanContentHash,
7075
- reason: Schema.optionalKey(TextId)
7076
- }));
7077
- /**
7078
- * The version is put to approval: each repo it names is asked to answer for it, and ref0 says yes
7079
- * once they have or their time runs out. Any earlier draft or proposed version is
7080
- * superseded.
7081
- */
7082
- const PlanProposed = eventKind("plan.proposed", Schema.Struct({
7083
- thread: ThreadId,
7084
- version: PlanVersion
7085
- }));
7086
- /** Who said yes: ref0's plans part, once every repo answered or its time ran out. */
7087
- const PlanAcceptedBy = Schema.Struct({
7088
- kind: Schema.Literal("answered"),
7089
- part: Ref0Part
7090
- });
7091
- /** A child thread, by the plan entry that made it. */
7092
- const PlanChildThread = Schema.Struct({
7093
- entry: PlanEntryKey,
7094
- thread: ThreadId
7095
- });
7096
- const ChildThreads = Schema.Array(PlanChildThread).check(Schema.isMaxLength(50));
7097
- /**
7098
- * The version is accepted, and the one accepted before it superseded. Each child is named only
7099
- * once its owner has registered it.
7100
- */
7101
- const PlanAccepted = eventKind("plan.accepted", Schema.Struct({
7102
- thread: ThreadId,
7103
- version: PlanVersion,
7104
- by: PlanAcceptedBy,
7105
- /** The version accepted before this one. */
7106
- supersedes: Schema.optionalKey(PlanVersion),
7107
- /** Children made now, each starting in planning. */
7108
- started: ChildThreads,
7109
- /** Entries an earlier version dropped and this one adds back: the same child, reopened if it was closed. */
7110
- rejoined: ChildThreads,
7111
- /** Children no longer part of the plan, so it stops waiting on them. Closing one is its own event. */
7112
- dropped: ChildThreads
7113
- }));
7114
- //#endregion
7115
- //#region ../contracts/src/plan-calls.ts
7116
- /**
7117
- * Plans and decisions: what the Worker asks a thread's Project DO, once `Authorize` has said
7118
- * who's acting. A plan is written with its words; the Project DO stores each as a text and
7119
- * records the version with their IDs.
7120
- */
7121
- /** A plan's free text: one of its outcomes, or an answer's reason. */
7122
- const PlanText = Schema.String.check(Schema.isBetweenLength(1, 2048));
7123
- /**
7124
- * How a plan does its work, in system terms, for people: about a page. A revision replaces it,
7125
- * with a reason; no one appends to it.
7126
- */
7127
- const Approach = Schema.String.check(Schema.isBetweenLength(1, 6e3));
7128
- /**
7129
- * A child as written. On a top-level org thread's plan, `project` names one of its owner's
7130
- * projects to start it in, as that project's thread; left out, it's in its parent's scope.
7131
- */
7132
- const PlanChildInput = Schema.Struct({
7133
- entry: PlanEntryKey,
7134
- title: Title,
7135
- outcome: Outcome,
7136
- stackedOn: Schema.optionalKey(PlanEntryKey),
7137
- required: Schema.Boolean,
7138
- project: Schema.optionalKey(ProjectName)
7139
- });
7140
- /**
7141
- * A plan as written: `PlanRecord`'s shape, with its words in place of text IDs. Its repos are up
7142
- * to 20 of the project's, by name; a parent whose work is all in its children names none.
7143
- */
7144
- const PlanInput = Schema.Struct({
7145
- approach: Schema.optionalKey(Approach),
7146
- repos: Schema.Array(RepoName).check(Schema.isMaxLength(20)),
7147
- outcomes: Schema.Array(PlanText).check(Schema.isBetweenLength(1, 50)),
7148
- children: Schema.Array(PlanChildInput).check(Schema.isMaxLength(50))
7149
- }).check(Schema.makeFilter((plan) => planProblem(plan) ?? true));
7150
- /**
7151
- * A project a plan's child names, as the Worker found it in the plan's owner before it asked the
7152
- * scope: its ID, and whether the writer can see it; or, with no `project`, that the owner has
7153
- * none by that name. The Worker refuses nothing for it, since only the scope knows which entries
7154
- * a version keeps.
7155
- */
7156
- const NamedProject = Schema.Struct({
7157
- name: ProjectName,
7158
- project: Schema.optionalKey(ProjectId),
7159
- seen: Schema.Boolean
7160
- });
7161
- Schema.Struct({
7162
- ...commandFields,
7163
- project: ProjectId,
7164
- ownerName: OwnerName,
7165
- number: ThreadNumber,
7166
- plan: PlanInput,
7167
- projects: Schema.Array(NamedProject).check(Schema.isMaxLength(50)),
7168
- reason: Schema.optionalKey(Reason),
7169
- propose: Schema.Boolean
7170
- });
7171
- Schema.Struct({
7172
- ...commandFields,
7173
- ownerName: OwnerName,
7174
- project: ProjectId,
7175
- number: ThreadNumber,
7176
- version: PlanVersion
7177
- });
7178
- /** A decision as it stands: what it asks, who decides, the answers so far, and how it closed. */
7179
- const DecisionView = Schema.Struct({
7180
- decision: DecisionId,
7181
- kind: DecisionKind,
7182
- subject: DecisionSubject,
7183
- question: Schema.optionalKey(TextId),
7184
- options: Schema.Array(AnswerOption),
7185
- lean: Schema.optionalKey(AnswerKey),
7186
- deciders: Schema.Array(Decider),
7187
- deadline: Schema.optionalKey(Schema.DateTimeUtcFromMillis),
7188
- state: Schema.Literals(["open", "closed"]),
7189
- answers: Schema.Array(Schema.Struct({
7190
- decider: DeciderRef,
7191
- answer: AnswerKey,
7192
- reason: Schema.optionalKey(TextId),
7193
- at: Schema.DateTimeUtcFromMillis
7194
- })),
7195
- result: Schema.optionalKey(AnswerKey),
7196
- closedWhy: Schema.optionalKey(DecisionClosedWhy)
7197
- });
7198
- /**
7199
- * A version as it stands: its content, its state, and, once proposed, where its approval is: its
7200
- * repos still being checked, or who accepted it.
7201
- */
7202
- const PlanVersionView = Schema.Struct({
7203
- thread: ThreadId,
7204
- number: ThreadNumber,
7205
- version: PlanVersion,
7206
- state: PlanState,
7207
- contentHash: PlanContentHash,
7208
- plan: PlanView,
7209
- /** Why it was written, when its writer said: never part of its content. */
7210
- reason: Schema.optionalKey(TextId),
7211
- writtenBy: ActorRef,
7212
- writtenAt: Schema.DateTimeUtcFromMillis,
7213
- /** Proposed, and its repos haven't all answered yet: it isn't accepted yet. */
7214
- checking: Schema.Boolean,
7215
- /**
7216
- * What its check found when it ended, every repo answered or their time run out: the repos
7217
- * that never answered. None for a draft, while it's being checked, or when a newer version or
7218
- * the thread closing ended the check first.
7219
- */
7220
- check: Schema.optionalKey(PlanCheck),
7221
- /**
7222
- * Accepted, and waiting to be recorded: on its new `children` registering, or on a merge under
7223
- * the thread's current revision `publishing`.
7224
- */
7225
- accepting: Schema.optionalKey(Schema.Literals(["children", "publishing"])),
7226
- acceptedBy: Schema.optionalKey(PlanAcceptedBy)
7227
- });
7228
- /** A plan's free text refused before anything was stored, saying which. */
7229
- var PlanTextRefused = class extends Schema.TaggedError()("PlanTextRefused", {
7230
- /** Where it is in the plan, such as `outcomes[3]`. */
7231
- where: Schema.String,
7232
- problem: Schema.Literals([
7233
- "empty",
7234
- "too long",
7235
- "looks like a secret"
7236
- ]),
7237
- nextStep: Schema.String
7238
- }, { httpApiStatus: 422 }) {};
7239
- /** A plan names a repo this project doesn't hold. */
7240
- var PlanRepoNotFound = class extends Schema.TaggedError()("PlanRepoNotFound", {
7241
- repo: RepoName,
7242
- nextStep: Schema.String
7243
- }, { httpApiStatus: 422 }) {};
7244
- /**
7245
- * A plan names its scope's own repo, made just now, before the scope holds it. Nothing was kept
7246
- * under the request's delivery ID, so the same request is written once it does.
7247
- */
7248
- var OwnRepoNotReady = class extends Schema.TaggedError()("OwnRepoNotReady", {
7249
- repo: RepoName,
7250
- nextStep: Schema.String
7251
- }, { httpApiStatus: 503 }) {};
7252
- /**
7253
- * A child entry this plan can't have: a project named on a project thread's plan or a nested org
7254
- * thread's, a project that isn't there or the writer can't see, one where its proposer may not
7255
- * start threads, an entry moved to another project, or a stack across scopes. A project that
7256
- * isn't there and one the writer can't see are refused alike, as `ProjectNotFound` is.
7257
- */
7258
- var PlanChildRefused = class extends Schema.TaggedError()("PlanChildRefused", { nextStep: Schema.String }, { httpApiStatus: 422 }) {};
7259
- var PlanVersionNotFound = class extends Schema.TaggedError()("PlanVersionNotFound", {
7260
- number: ThreadNumber,
7261
- version: PlanVersion,
7262
- nextStep: Schema.String
7263
- }, { httpApiStatus: 404 }) {};
7264
- /**
7265
- * Only a thread's newest version is proposed, and never one already declined, nor one whose
7266
- * required or stacked children would close a cycle of threads waiting on each other.
6910
+ * Only a thread's newest version is proposed, and never one already declined, nor one whose
6911
+ * required or stacked children would close a cycle of threads waiting on each other.
7267
6912
  */
7268
6913
  var PlanNotProposable = class extends Schema.TaggedError()("PlanNotProposable", {
7269
6914
  version: PlanVersion,
@@ -7334,126 +6979,525 @@ var AnswerRefused = class extends Schema.TaggedError()("AnswerRefused", {
7334
6979
  nextStep: Schema.String
7335
6980
  }, { httpApiStatus: 409 }) {};
7336
6981
  /**
7337
- * Where a gate's answer goes: its Repo DO, which alone decides it, named by the gate's subject,
7338
- * with the answer's reason already stored here, where the fold reads it, and the scope it's in,
7339
- * which the Worker's `nextStep`s write. The Project DO keeps no receipt for a route, so a
7340
- * retry routes again, and the Repo DO keeps the answer's. The Worker takes it and never answers
7341
- * with it.
6982
+ * Where a gate's answer goes: its Repo DO, which alone decides it, named by the gate's subject,
6983
+ * with the answer's reason already stored here, where the fold reads it, and the scope it's in,
6984
+ * which the Worker's `nextStep`s write. The Project DO keeps no receipt for a route, so a
6985
+ * retry routes again, and the Repo DO keeps the answer's. The Worker takes it and never answers
6986
+ * with it.
6987
+ */
6988
+ const GateAnswerRoute = Schema.TaggedStruct("GateAnswerRoute", {
6989
+ scope: ThreadScope,
6990
+ decision: DecisionId,
6991
+ repo: RepoId,
6992
+ pullRequest: PullRequestNumber,
6993
+ version: VersionNumber,
6994
+ reason: Schema.optionalKey(TextId)
6995
+ });
6996
+ Schema.Union([
6997
+ NamedDecision,
6998
+ GateAnswerRoute,
6999
+ DecisionNotFound,
7000
+ AnswerRefused,
7001
+ PlanTextRefused,
7002
+ ProjectNotReady,
7003
+ ProjectNotFound,
7004
+ DeliveryOutsideWindow
7005
+ ]);
7006
+ Schema.Struct({
7007
+ ...commandFields,
7008
+ project: ProjectId,
7009
+ decision: DecisionId,
7010
+ pullRequest: PullRequestNumber,
7011
+ version: VersionNumber,
7012
+ answer: AnswerKey,
7013
+ reason: Schema.optionalKey(TextId),
7014
+ admin: Schema.Boolean
7015
+ });
7016
+ Schema.Union([
7017
+ Schema.Struct({
7018
+ outcome: Schema.Literal("answered"),
7019
+ deciders: Schema.Array(DeciderRef)
7020
+ }),
7021
+ Schema.Struct({ outcome: Schema.Literals([
7022
+ "decision closed",
7023
+ "not a decider",
7024
+ "already answered",
7025
+ "not an answer"
7026
+ ]) }),
7027
+ DeliveryOutsideWindow
7028
+ ]);
7029
+ /** Someone decisions wait on: a person, or an agent, and the roles the Worker found they hold. */
7030
+ const Waiter = Schema.Struct({
7031
+ decider: DeciderRef,
7032
+ roles: Schema.Array(Schema.Struct({
7033
+ role: Schema.Literal("admin"),
7034
+ owner: OwnerId
7035
+ }))
7036
+ });
7037
+ Schema.Struct({
7038
+ ownerName: OwnerName,
7039
+ you: Waiter,
7040
+ person: Schema.optionalKey(Waiter),
7041
+ decisions: Schema.optionalKey(Schema.Array(DecisionId).check(Schema.isMaxLength(100)))
7042
+ });
7043
+ /**
7044
+ * An open decision that waits on the caller: on them, or, for an agent, on its person, who
7045
+ * answers it. A gate never takes an agent's answer, so an agent's gate always waits on its person.
7046
+ */
7047
+ const WaitingDecision = Schema.Struct({
7048
+ ...NamedDecision.fields,
7049
+ waitsOn: Schema.Literals(["you", "your person"])
7050
+ });
7051
+ const WaitingPage = Schema.Struct({ decisions: Schema.Array(WaitingDecision) });
7052
+ Schema.Struct({
7053
+ ownerName: OwnerName,
7054
+ number: ThreadNumber
7055
+ });
7056
+ const PlanVersionPage = Schema.Struct({ versions: Schema.Array(PlanVersionView) });
7057
+ Schema.Union([PlanVersionPage, ThreadNotFound]);
7058
+ /** One decision of the project's, by its ID. */
7059
+ /** At most how long a read of a decision waits for it to close, in seconds. */
7060
+ const DecisionWait = Schema.Int.check(Schema.isBetween({
7061
+ minimum: 1,
7062
+ maximum: 60
7063
+ }));
7064
+ Schema.Struct({
7065
+ ownerName: OwnerName,
7066
+ decision: DecisionId,
7067
+ wait: Schema.optionalKey(DecisionWait)
7068
+ });
7069
+ Schema.Union([NamedDecision, DecisionNotFound]);
7070
+ /**
7071
+ * `POST …/plans`: a version, as a draft unless it's proposed at once, and why it was written.
7072
+ * A first version needs no reason, and a later one may leave it out.
7073
+ */
7074
+ const WritePlanRequest = Schema.Struct({
7075
+ plan: PlanInput,
7076
+ reason: Schema.optionalKey(Reason),
7077
+ propose: Schema.optionalKey(Schema.Boolean)
7078
+ });
7079
+ /** `POST …/decisions/{decision}/answers`: one of its answers, and why, in words. */
7080
+ const AnswerRequest = Schema.Struct({
7081
+ answer: AnswerKey,
7082
+ reason: Schema.optionalKey(PlanText)
7083
+ });
7084
+ Schema.Struct({
7085
+ thread: ThreadId,
7086
+ owner: OwnerId,
7087
+ parent: ThreadId,
7088
+ parentScope: ProjectId,
7089
+ parentNumber: ThreadNumber,
7090
+ fromPlan: Schema.Struct({
7091
+ version: PlanVersion,
7092
+ entry: PlanEntryKey
7093
+ }),
7094
+ title: Title,
7095
+ outcome: Outcome,
7096
+ required: Schema.Boolean,
7097
+ actor: ActorRef,
7098
+ cause: EventRef
7099
+ });
7100
+ /** The child as it stands, whether this call started it or an earlier one did. */
7101
+ const RemoteChildStarted = Schema.Struct({
7102
+ number: ThreadNumber,
7103
+ stage: ThreadStage,
7104
+ stageRevision: StageRevision
7105
+ });
7106
+ Schema.Union([RemoteChildStarted, ProjectNotReady]);
7107
+ Schema.Struct({
7108
+ thread: ThreadId,
7109
+ number: ThreadNumber
7110
+ });
7111
+ /** A child's stage and its revision, as one read found them. */
7112
+ const ChildStageView = Schema.Struct({
7113
+ stage: ThreadStage,
7114
+ stageRevision: StageRevision
7115
+ });
7116
+ Schema.Union([ChildStageView, ThreadNotFound]);
7117
+ //#endregion
7118
+ //#region ../contracts/src/approvals.ts
7119
+ /**
7120
+ * Approvals, as their commands travel: what a terminal, a page or an agent asks its person to
7121
+ * say yes to. A command is one endpoint, by its name in the surface table, and its request, as
7122
+ * that endpoint encodes it. ref0 decodes each part by the endpoint's own `Schema` before it
7123
+ * keeps or shows anything, so a command is exactly what the endpoint would take.
7124
+ */
7125
+ /**
7126
+ * An endpoint by its name in the surface table, `group.endpoint`. Checked against the table
7127
+ * where the command is made canonical, since the table is typed from the API this is part of.
7128
+ */
7129
+ const CommandEndpoint = Schema.String.check(Schema.isPattern(/^[a-zA-Z]+\.[a-zA-Z]+$/));
7130
+ /** One command, as asked: its endpoint, and its request's path, query and payload, encoded. */
7131
+ const ApprovalCommand = Schema.Struct({
7132
+ endpoint: CommandEndpoint,
7133
+ params: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)),
7134
+ query: Schema.optionalKey(Schema.JsonObject),
7135
+ payload: Schema.optionalKey(Schema.Json)
7136
+ });
7137
+ /** A command ref0 won't ask anyone about: not an endpoint's request, or not one an approval runs. */
7138
+ var CommandRefused = class extends Schema.TaggedError()("CommandRefused", { nextStep: Schema.String }, { httpApiStatus: 400 }) {};
7139
+ /** A terminal asking: its command, and the hash of the secret it collects the result with. */
7140
+ const StartApproval = Schema.Struct({
7141
+ command: ApprovalCommand,
7142
+ secretHash: SecretHash
7143
+ });
7144
+ /** A terminal's approval, started: what to show its person, and until when. */
7145
+ const ApprovalStarted = Schema.Struct({
7146
+ approval: ApprovalId,
7147
+ code: ApprovalCode,
7148
+ expiresAt: Timestamp
7149
+ });
7150
+ /**
7151
+ * An answer that waits for the person: the call only the person may make, or that agents ask
7152
+ * for, became an approval, which the person answers on their own page. A `202`, never a failure
7153
+ * of the call: whoever asked collects the result with `GET /v1/approvals/{approval}`.
7154
+ */
7155
+ var ApprovalNeeded = class extends Schema.TaggedError()("ApprovalNeeded", {
7156
+ approval: ApprovalId,
7157
+ says: Schema.String,
7158
+ expiresAt: Timestamp
7159
+ }, { httpApiStatus: 202 }) {};
7160
+ const terminalAsker = Schema.Struct({ kind: Schema.Literal("terminal") });
7161
+ const pageAsker = Schema.Struct({ kind: Schema.Literal("page") });
7162
+ const agentAsker = Schema.Struct({
7163
+ kind: Schema.Literal("agent"),
7164
+ agent: AgentId,
7165
+ handle: AgentHandle,
7166
+ session: SessionId,
7167
+ /** The attachment its credential was made under, for a person's agent in an organization. */
7168
+ attachment: Schema.optionalKey(CredentialRef)
7169
+ });
7170
+ /**
7171
+ * Who asked, as a receipt keeps it: a terminal, one of ref0's pages, an agent, or a machine
7172
+ * asking to connect, by its ID and its own word for itself, and from where.
7173
+ */
7174
+ const ApprovalAsker = Schema.Union([
7175
+ terminalAsker,
7176
+ pageAsker,
7177
+ Schema.Struct({
7178
+ kind: Schema.Literal("machine"),
7179
+ machine: MachineId,
7180
+ machineName: MachineName,
7181
+ askedFrom: Schema.optionalKey(Schema.String)
7182
+ }),
7183
+ agentAsker
7184
+ ]);
7185
+ /**
7186
+ * Who asked, as the person reads a request before they answer: a terminal, a page or an agent.
7187
+ * A machine's request is read as an `AttachmentRequestView`, never as a command.
7188
+ */
7189
+ const ApprovalViewAsker = Schema.Union([
7190
+ terminalAsker,
7191
+ pageAsker,
7192
+ agentAsker
7193
+ ]);
7194
+ /** A request, as the person reads it before they answer. */
7195
+ const ApprovalView = Schema.Struct({
7196
+ approval: ApprovalId,
7197
+ /** The command as its CLI line. */
7198
+ says: Schema.String,
7199
+ /** Everything the command carries, each named, in order: nothing it would run is left out. */
7200
+ fields: Schema.Array(Schema.Struct({
7201
+ name: Schema.String,
7202
+ value: Schema.String,
7203
+ part: Schema.Literals([
7204
+ "path",
7205
+ "query",
7206
+ "payload"
7207
+ ])
7208
+ })),
7209
+ command: ApprovalCommand,
7210
+ asker: ApprovalViewAsker,
7211
+ askedFrom: Schema.optionalKey(Schema.String),
7212
+ askedAt: Timestamp,
7213
+ expiresAt: Timestamp,
7214
+ /**
7215
+ * An agent's ask: the kind of action its answer may set agents' permission for, and whether a
7216
+ * yes may let agents take it without asking. A no with the passkey may always stop them asking.
7217
+ */
7218
+ agentPermission: Schema.optionalKey(Schema.Struct({
7219
+ action: ScopeAction,
7220
+ mayAllow: Schema.Boolean
7221
+ })),
7222
+ /**
7223
+ * What the command acts on, drawn as ref0 resolves it for the person reading, where its
7224
+ * endpoint names a preview. Without one the page can draw, it offers only no.
7225
+ */
7226
+ preview: Schema.optionalKey(ApprovalPreview)
7227
+ });
7228
+ /** A statement's hash: the SHA-256 of its words and quoted values as JSON, as lowercase hex. */
7229
+ const StatementHash = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/));
7230
+ /**
7231
+ * Who asks for a yes to a statement: a workflow's run, `passkey.run`'s, by the workflow and the
7232
+ * run; or a gate's check, `passkey.check`'s, by the check, the pull request's version it gates and
7233
+ * the check run its statement is over.
7234
+ */
7235
+ const StatementAsker = Schema.Union([Schema.Struct({
7236
+ kind: Schema.Literal("workflow"),
7237
+ workflow: WorkflowName,
7238
+ run: WorkflowRunId
7239
+ }), Schema.Struct({
7240
+ kind: Schema.Literal("gate"),
7241
+ check: CheckKey,
7242
+ pullRequest: PullRequestNumber,
7243
+ version: VersionNumber,
7244
+ run: CheckRunId
7245
+ })]);
7246
+ /**
7247
+ * A passkey request, as the person reads it before they answer: the statement, its words as its
7248
+ * asker wrote them and each value it quotes, and its hash; who asks; where, a workflow's
7249
+ * `owner/repo` or a thread's `owner/project#number`, or a gate's pull request, `owner/repo#number`;
7250
+ * whom it asks, the run's accountable person, or for a gate the person behind its run, a person by
7251
+ * name, or a permission's holders; and until when.
7252
+ */
7253
+ const StatementView = Schema.Struct({
7254
+ approval: ApprovalId,
7255
+ statement: WorkflowText,
7256
+ hash: StatementHash,
7257
+ asker: StatementAsker,
7258
+ home: Schema.String,
7259
+ from: Schema.Union([Schema.Literals(["accountable", "person"]), Schema.Struct({ permission: RepoPermissionName })]),
7260
+ askedAt: Timestamp,
7261
+ expiresAt: Timestamp
7262
+ });
7263
+ /**
7264
+ * The person's own requests, waiting for them; the passkey requests workflows' runs and gates asked
7265
+ * them; each machine's request this browser session is the answerer of, so a reload finds it
7266
+ * again without its code; and the gates' decisions that wait on their yes or no, in every project
7267
+ * they see, oldest first.
7268
+ */
7269
+ const ApprovalsWaiting = Schema.Struct({
7270
+ approvals: Schema.Array(ApprovalView),
7271
+ statements: Schema.Array(StatementView),
7272
+ requests: Schema.Array(AttachmentRequestView),
7273
+ decisions: Schema.Array(NamedDecision)
7274
+ });
7275
+ /** Finding a terminal's request by the code it showed. */
7276
+ const FindApproval = Schema.Union([Schema.Struct({ code: TypedApprovalCode }), Schema.Struct({ link: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{22}$/)) })]);
7277
+ /**
7278
+ * Asking for the passkey's options to answer a request: a terminal's request needs its code
7279
+ * again, so its ID alone, which travels where its code doesn't, never answers it. A machine's
7280
+ * request needs its answerer, and the agent it chooses to connect, before a yes has options.
7281
+ */
7282
+ const ApprovalOptionsRequest = Schema.Struct({
7283
+ code: Schema.optionalKey(TypedApprovalCode),
7284
+ folders: Schema.optionalKey(ConnectFolderChoices)
7285
+ });
7286
+ /**
7287
+ * An answer: yes, with the passkey, or no. For an agent's ask, each answer can set the owner's
7288
+ * permission its own way, so a pairing that can't happen can't be sent: yes, and let agents do
7289
+ * it without asking; no, and stop agents asking, with the passkey too.
7290
+ */
7291
+ const AnswerApproval = Schema.Union([
7292
+ Schema.Struct({
7293
+ answer: Schema.Literal("yes"),
7294
+ permission: Schema.optionalKey(Schema.Literal("allow")),
7295
+ assertion: PasskeyAsserted,
7296
+ code: Schema.optionalKey(TypedApprovalCode),
7297
+ /** The preview the page drew, where the command's endpoint names one. */
7298
+ preview: Schema.optionalKey(PreviewEcho),
7299
+ /** The statement the page showed, by its hash, for a workflow run's or a gate's passkey request. */
7300
+ statement: Schema.optionalKey(Schema.Struct({ hash: StatementHash }))
7301
+ }),
7302
+ Schema.Struct({
7303
+ answer: Schema.Literal("no"),
7304
+ permission: Schema.Literal("deny"),
7305
+ assertion: PasskeyAsserted,
7306
+ code: Schema.optionalKey(TypedApprovalCode)
7307
+ }),
7308
+ Schema.Struct({
7309
+ answer: Schema.Literal("no"),
7310
+ code: Schema.optionalKey(TypedApprovalCode)
7311
+ })
7312
+ ]);
7313
+ /**
7314
+ * What running an approved command came to: its status, and its endpoint's answer or refusal,
7315
+ * as JSON. ref0 reads it by the command's endpoint before anyone sees it, and whoever asked reads
7316
+ * it the same way, with `ranOf`: this schema is part of the API the endpoints' types come from,
7317
+ * so it can't be typed by them itself.
7318
+ */
7319
+ const Ran = Schema.Struct({
7320
+ status: Schema.Int,
7321
+ result: Schema.Json
7322
+ });
7323
+ /**
7324
+ * A ran command whose answer its endpoint's schemas no longer read, such as one kept from
7325
+ * before they changed: it ran, and what it came to can't be said.
7326
+ */
7327
+ var ResultUnreadable = class extends Schema.TaggedError()("ResultUnreadable", { nextStep: Schema.String }, { httpApiStatus: 500 }) {};
7328
+ /**
7329
+ * Where a request stands, for whoever asked: still waiting; approved, and running as soon as
7330
+ * ref0 can; refused; expired; or what it ran to, with the endpoint it ran, whose schemas read it.
7331
+ */
7332
+ const ApprovalState = Schema.Union([
7333
+ Schema.Struct({
7334
+ state: Schema.Literal("waiting"),
7335
+ expiresAt: Timestamp
7336
+ }),
7337
+ Schema.Struct({
7338
+ state: Schema.Literal("approved"),
7339
+ /** A machine's answering browser may forget its saved answer once the terminal kept it. */
7340
+ collected: Schema.optionalKey(Schema.Literal(true))
7341
+ }),
7342
+ Schema.Struct({ state: Schema.Literal("refused") }),
7343
+ Schema.Struct({ state: Schema.Literal("expired") }),
7344
+ Schema.Struct({
7345
+ state: Schema.Literal("ran"),
7346
+ endpoint: CommandEndpoint,
7347
+ ...Ran.fields
7348
+ })
7349
+ ]);
7350
+ /** Only the answering browser receives a machine's answer code; state reads never carry it. */
7351
+ const ApprovalAnswer = Schema.Union([
7352
+ Schema.Struct({
7353
+ ...ApprovalState.members[1].fields,
7354
+ answerCode: ApprovalCode
7355
+ }),
7356
+ Schema.Struct({
7357
+ ...ApprovalState.members[4].fields,
7358
+ answerCode: ApprovalCode
7359
+ }),
7360
+ ApprovalState
7361
+ ]);
7362
+ /** A request that isn't there, or isn't the caller's to see, answers the same. */
7363
+ var ApprovalNotFound = class extends Schema.TaggedError()("ApprovalNotFound", { nextStep: Schema.String }, { httpApiStatus: 404 }) {};
7364
+ /** Too many asked, or too many codes typed, from here in the last hour. */
7365
+ var SlowDown = class extends Schema.TaggedError()("SlowDown", { nextStep: Schema.String }, { httpApiStatus: 429 }) {};
7366
+ /** A command's hash: the SHA-256 of its canonical JSON, as lowercase hex. */
7367
+ const CommandHash = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/));
7368
+ Schema.Struct({
7369
+ approval: ApprovalId,
7370
+ endpoint: CommandEndpoint,
7371
+ /** The command's canonical JSON. */
7372
+ command: Schema.String,
7373
+ commandHash: CommandHash,
7374
+ asker: ApprovalAsker,
7375
+ /** The browser session the person answered in, for their log. */
7376
+ credential: CredentialRef,
7377
+ generation: Generation,
7378
+ /** When the request expires, in epoch milliseconds. */
7379
+ deadline: Schema.Int,
7380
+ challenge: Schema.String,
7381
+ /** A machine answer retries only from its answering session, with this key. */
7382
+ answerKey: Schema.optionalKey(RequestId),
7383
+ /** An agent's ask: the credential it asked with, checked again before the answer counts. */
7384
+ asking: Schema.optionalKey(TokenId),
7385
+ /** The kind of action the person, answering, let agents take without asking from now on. */
7386
+ allow: Schema.optionalKey(ScopeAction)
7387
+ });
7388
+ Schema.Struct({
7389
+ approval: ApprovalId,
7390
+ action: ScopeAction,
7391
+ credential: CredentialRef,
7392
+ generation: Generation
7393
+ });
7394
+ Schema.Union([Schema.Struct({ denied: Schema.Literal(true) }), Schema.Struct({
7395
+ denied: Schema.Literal(false),
7396
+ reason: Schema.Literals(["generation moved", "not set up"])
7397
+ })]);
7398
+ Schema.Union([Schema.Struct({
7399
+ admitted: Schema.Literal(true),
7400
+ admittedAt: Schema.Int,
7401
+ answerCode: Schema.optionalKey(ApprovalCode)
7402
+ }), Schema.Struct({
7403
+ admitted: Schema.Literal(false),
7404
+ reason: Schema.Literals([
7405
+ "expired",
7406
+ "generation moved",
7407
+ "challenge used",
7408
+ "not set up",
7409
+ "asker gone"
7410
+ ])
7411
+ })]);
7412
+ Schema.Union([Schema.Struct({ found: Schema.Literal(false) }), Schema.Struct({
7413
+ found: Schema.Literal(true),
7414
+ endpoint: CommandEndpoint,
7415
+ command: Schema.String,
7416
+ commandHash: CommandHash,
7417
+ generation: Generation,
7418
+ generationNow: Generation,
7419
+ /** The `approval.answered` its admission recorded in the person's log. */
7420
+ answeredEvent: EventId,
7421
+ /** Who asked, as that `approval.answered` says. */
7422
+ asker: ApprovalAsker,
7423
+ /** What running it came to, once it ran, as `KeptRan` keeps it. */
7424
+ result: Schema.optionalKey(Schema.String)
7425
+ })]);
7426
+ /**
7427
+ * A `Ran` as it's kept, on its receipt and on its approval: its JSON, as text. The Owner DO
7428
+ * keeps it as it comes and runs no endpoint's schemas, so it's read only by its endpoint, with
7429
+ * `keptRan`, which refuses one they don't take.
7342
7430
  */
7343
- const GateAnswerRoute = Schema.TaggedStruct("GateAnswerRoute", {
7344
- scope: ThreadScope,
7345
- decision: DecisionId,
7346
- repo: RepoId,
7347
- pullRequest: PullRequestNumber,
7348
- version: VersionNumber,
7349
- reason: Schema.optionalKey(TextId)
7350
- });
7351
- Schema.Union([
7352
- DecisionView,
7353
- GateAnswerRoute,
7354
- DecisionNotFound,
7355
- AnswerRefused,
7356
- PlanTextRefused,
7357
- ProjectNotReady,
7358
- ProjectNotFound,
7359
- DeliveryOutsideWindow
7360
- ]);
7361
- Schema.Struct({
7362
- ...commandFields,
7363
- project: ProjectId,
7364
- decision: DecisionId,
7365
- pullRequest: PullRequestNumber,
7366
- version: VersionNumber,
7367
- answer: AnswerKey,
7368
- reason: Schema.optionalKey(TextId),
7369
- admin: Schema.Boolean
7370
- });
7371
- Schema.Union([
7372
- Schema.Struct({
7373
- outcome: Schema.Literal("answered"),
7374
- deciders: Schema.Array(DeciderRef)
7375
- }),
7376
- Schema.Struct({ outcome: Schema.Literals([
7377
- "decision closed",
7378
- "not a decider",
7379
- "already answered",
7380
- "not an answer"
7381
- ]) }),
7382
- DeliveryOutsideWindow
7383
- ]);
7431
+ const KeptRan = Schema.fromJsonString(Ran);
7384
7432
  Schema.Struct({
7385
- decider: DeciderRef,
7386
- roles: Schema.optionalKey(Schema.Array(Schema.Struct({
7387
- role: Schema.Literal("admin"),
7388
- owner: OwnerId
7389
- })))
7433
+ approval: ApprovalId,
7434
+ result: Schema.String
7390
7435
  });
7391
- const WaitingPage = Schema.Struct({ decisions: Schema.Array(DecisionView) });
7436
+ Schema.Struct({ result: Schema.String });
7437
+ Schema.Struct({ approval: ApprovalId });
7438
+ Schema.Struct({ approval: ApprovalId });
7439
+ Schema.Union([Schema.Struct({ expired: Schema.Literal(true) }), Schema.Struct({ expired: Schema.Literal(false) })]);
7392
7440
  Schema.Struct({
7393
- ownerName: OwnerName,
7394
- number: ThreadNumber
7441
+ person: PersonId,
7442
+ approval: ApprovalId
7395
7443
  });
7396
- const PlanVersionPage = Schema.Struct({ versions: Schema.Array(PlanVersionView) });
7397
- Schema.Union([PlanVersionPage, ThreadNotFound]);
7398
- /** One decision of the project's, by its ID. */
7399
- /** At most how long a read of a decision waits for it to close, in seconds. */
7400
- const DecisionWait = Schema.Int.check(Schema.isBetween({
7401
- minimum: 1,
7402
- maximum: 60
7403
- }));
7444
+ //#endregion
7445
+ //#region ../contracts/src/browser-sessions.ts
7446
+ /**
7447
+ * A browser session's cookie: Better Auth's, named for ref0, `Secure` and host-only on the
7448
+ * app's one origin. It holds the session's token, signed; the directory and the person's Owner DO hold
7449
+ * only the token's SHA-256.
7450
+ */
7451
+ const browserSessionCookie = "__Secure-ref0.session_token";
7404
7452
  Schema.Struct({
7405
- ownerName: OwnerName,
7406
- decision: DecisionId,
7407
- wait: Schema.optionalKey(DecisionWait)
7453
+ token: TokenId,
7454
+ secretHash: SecretHash,
7455
+ expiresAt: Schema.DateTimeUtcFromMillis
7408
7456
  });
7409
- Schema.Union([DecisionView, DecisionNotFound]);
7457
+ Schema.Struct({ registered: Schema.Boolean });
7410
7458
  /**
7411
- * `POST …/plans`: a version, as a draft unless it's proposed at once, and why it was written.
7412
- * A first version needs no reason, and a later one may leave it out.
7459
+ * Where a signed-in person stands: naming, when the name their GitHub login gave was taken or
7460
+ * kept back, with that login as a suggestion; setting up, once their owner is made and before
7461
+ * it's ready with this session registered, which naming again finishes; or ready.
7413
7462
  */
7414
- const WritePlanRequest = Schema.Struct({
7415
- plan: PlanInput,
7416
- reason: Schema.optionalKey(Reason),
7417
- propose: Schema.optionalKey(Schema.Boolean)
7418
- });
7419
- /** `POST …/decisions/{decision}/answers`: one of its answers, and why, in words. */
7420
- const AnswerRequest = Schema.Struct({
7421
- answer: AnswerKey,
7422
- reason: Schema.optionalKey(PlanText)
7423
- });
7424
- Schema.Struct({
7425
- thread: ThreadId,
7463
+ const Welcome = Schema.Union([Schema.Struct({
7464
+ state: Schema.Literals(["ready", "setting up"]),
7465
+ person: PersonId,
7426
7466
  owner: OwnerId,
7427
- parent: ThreadId,
7428
- parentScope: ProjectId,
7429
- parentNumber: ThreadNumber,
7430
- fromPlan: Schema.Struct({
7431
- version: PlanVersion,
7432
- entry: PlanEntryKey
7433
- }),
7434
- title: Title,
7435
- outcome: Outcome,
7436
- required: Schema.Boolean,
7437
- actor: ActorRef,
7438
- cause: EventRef
7439
- });
7440
- /** The child as it stands, whether this call started it or an earlier one did. */
7441
- const RemoteChildStarted = Schema.Struct({
7442
- number: ThreadNumber,
7443
- stage: ThreadStage,
7444
- stageRevision: StageRevision
7445
- });
7446
- Schema.Union([RemoteChildStarted, ProjectNotReady]);
7447
- Schema.Struct({
7448
- thread: ThreadId,
7449
- number: ThreadNumber
7450
- });
7451
- /** A child's stage and its revision, as one read found them. */
7452
- const ChildStageView = Schema.Struct({
7453
- stage: ThreadStage,
7454
- stageRevision: StageRevision
7467
+ name: OwnerName
7468
+ }), Schema.Struct({
7469
+ state: Schema.Literal("naming"),
7470
+ person: PersonId,
7471
+ suggestion: Schema.optionalKey(Schema.String)
7472
+ })]);
7473
+ /**
7474
+ * A browser session renewed: its expiry, in its person's Owner DO and in the directory, and on its cookie.
7475
+ * Renewed at most once a day, so one asked sooner answers its expiry unchanged.
7476
+ */
7477
+ const SessionRenewed = Schema.Struct({ expiresAt: Schema.DateTimeUtcFromMillis });
7478
+ /**
7479
+ * What starting a GitHub sign-in at `POST /auth/sign-in/social` answers: GitHub's address to go
7480
+ * to, with the sign-in's state in a cookie set alongside. Better Auth's answer, which ref0 serves.
7481
+ */
7482
+ const NavigationUrl = Schema.String.check(Schema.isPattern(/^https?:\/\/[^\s/]+(?:\/[^\s]*)?$/), Schema.makeFilter((url) => URL.canParse(url) || "an HTTP(S) URL the platform can parse")).pipe(Schema.brand("NavigationUrl"));
7483
+ const SignInStarted = Schema.Struct({ url: NavigationUrl });
7484
+ /**
7485
+ * Where signing in sends the browser back to, as `POST /auth/sign-in/social` takes it: a path on
7486
+ * ref0's own origin, such as `/welcome`, or a whole URL. Never a socket's.
7487
+ */
7488
+ const SignInDestination = Schema.String.pipe(Schema.brand("SignInDestination"));
7489
+ /**
7490
+ * What `POST /auth/sign-in/social` takes to start signing in with GitHub: where the browser
7491
+ * lands coming back, and where it lands when signing in failed. Better Auth's body, which ref0
7492
+ * serves.
7493
+ */
7494
+ const StartSignIn = Schema.Struct({
7495
+ provider: Schema.Literal("github"),
7496
+ callbackURL: SignInDestination,
7497
+ errorCallbackURL: SignInDestination
7455
7498
  });
7456
- Schema.Union([ChildStageView, ThreadNotFound]);
7499
+ /** The name a naming person chose for their owner. */
7500
+ const NameOwner = Schema.Struct({ name: OwnerName });
7457
7501
  //#endregion
7458
7502
  //#region ../contracts/src/ask-calls.ts
7459
7503
  /**
@@ -10268,10 +10312,21 @@ signInRoute("POST", "/oauth2/consent");
10268
10312
  */
10269
10313
  const oauthDiscoveryPaths = ["/.well-known/oauth-protected-resource/mcp", `${oauthRoutes.metadata.pathUnderBase}${signInBase}`];
10270
10314
  /**
10315
+ * Where an outside service finds identity tokens' issuer and its public keys, each at the
10316
+ * origin's root: the issuer's discovery document, and its JWKS. Only these two: every other path
10317
+ * under `/.well-known/` is a page's.
10318
+ */
10319
+ const identityDiscoveryRoutes = {
10320
+ configuration: "/.well-known/openid-configuration",
10321
+ keys: "/.well-known/jwks.json"
10322
+ };
10323
+ /** Whether a path is one of identity tokens' two published documents. */
10324
+ const isIdentityDiscoveryPath = (pathname) => pathname === identityDiscoveryRoutes.configuration || pathname === identityDiscoveryRoutes.keys;
10325
+ /**
10271
10326
  * Whether a path is Worker "server"'s to answer, not a page's: the API's, signing in's, a
10272
- * connection's webhook, or OAuth's metadata.
10327
+ * connection's webhook, OAuth's metadata, or identity tokens' published documents.
10273
10328
  */
10274
- const isRef0Path = (pathname) => isSignInPath(pathname) || isHooksPath(pathname) || pathname === "/v1" || pathname.startsWith(`/v1/`) || oauthDiscoveryPaths.includes(pathname);
10329
+ const isRef0Path = (pathname) => isSignInPath(pathname) || isHooksPath(pathname) || pathname === "/v1" || pathname.startsWith(`/v1/`) || oauthDiscoveryPaths.includes(pathname) || isIdentityDiscoveryPath(pathname);
10275
10330
  //#endregion
10276
10331
  //#region ../contracts/src/live-calls.ts
10277
10332
  /**
@@ -11584,6 +11639,151 @@ Schema.Struct({
11584
11639
  name: RepoName
11585
11640
  }))
11586
11641
  });
11642
+ /** Where an agent's session asks for an identity token. */
11643
+ const identityTokenPath = "/v1/me/identity-token";
11644
+ /** One DNS label, or one part of an IPv4 address: letters, digits and inner hyphens. */
11645
+ const label = "[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?";
11646
+ /** `https://`, a host name, then maybe `:` and a port with no leading zero. */
11647
+ const audiencePattern = new RegExp(`^https://(${label}(?:\\.${label})*)(?::([1-9][0-9]{0,4}))?$`);
11648
+ /**
11649
+ * Whether the platform's URL parser reads the audience as written: an `https` URL whose host is
11650
+ * the audience's own, lowercased, and whose port is its own, or none for 443. That refuses a host
11651
+ * the parser rewrites, such as `https://1.2.3` read as `1.2.0.3`, and a port past 65535.
11652
+ */
11653
+ const parsesAsWritten = (audience) => {
11654
+ const parts = audiencePattern.exec(audience);
11655
+ if (parts === null || !URL.canParse(audience)) return false;
11656
+ const url = new URL(audience);
11657
+ const port = parts[2] ?? "";
11658
+ return url.protocol === "https:" && url.hostname === (parts[1] ?? "").toLowerCase() && url.port === (port === "443" ? "" : port);
11659
+ };
11660
+ /**
11661
+ * Who an identity token is for: an outside service's HTTPS origin, in ASCII, at most 255 bytes,
11662
+ * with no credentials, path, query, fragment, wildcard or space. It's kept exactly as asked, its
11663
+ * case and any port too, so `https://verifier.example:443` is another audience than
11664
+ * `https://verifier.example`. ref0 never fetches or resolves it.
11665
+ */
11666
+ const IdentityAudience = Schema.String.check(Schema.isMaxLength(255), Schema.isPattern(audiencePattern), Schema.makeFilter((audience) => parsesAsWritten(audience) || "an origin the platform reads as written")).pipe(Schema.brand("IdentityAudience"));
11667
+ /** `POST /v1/me/identity-token`'s body: the one audience, and nothing else. */
11668
+ const IdentityTokenRequest = Schema.Struct({ audience: IdentityAudience });
11669
+ /** A compact JWT: its header, payload and signature, each in base64url, at most 4 KiB. */
11670
+ const IdentityToken = Schema.String.check(Schema.isMaxLength(4096), Schema.isPattern(/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/)).pipe(Schema.brand("IdentityToken"));
11671
+ /** What asking for an identity token answers: the token, and when it expires, its `exp`. */
11672
+ const IssuedIdentityToken = Schema.Struct({
11673
+ token: IdentityToken,
11674
+ expiresAt: Schema.DateTimeUtcFromMillis
11675
+ });
11676
+ /**
11677
+ * An identity token's `jti`: a fresh UUIDv4 from the platform's cryptographic source for each
11678
+ * token, naming its issuance in ref0's log without naming any row or secret.
11679
+ */
11680
+ const IdentityTokenId = Schema.String.check(Schema.isPattern(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/)).pipe(Schema.brand("IdentityTokenId"));
11681
+ /**
11682
+ * A person, as one audience knows them: `pperson_`, then the first 128 bits of an HMAC of the
11683
+ * person's ref0 ID for the token's issuer and audience, as a TypeID suffix. Stable at one
11684
+ * audience, different at every other, and carrying no time.
11685
+ */
11686
+ const PairwisePersonId = TypeId("pperson").pipe(Schema.brand("PairwisePersonId"));
11687
+ /** A session, as one audience knows it, made as a person's is. */
11688
+ const PairwiseSessionId = TypeId("psession").pipe(Schema.brand("PairwiseSessionId"));
11689
+ /** The accountable person, last in a token's chain: only their pairwise ID. */
11690
+ const PersonActor = Schema.Struct({ sub: PairwisePersonId });
11691
+ /** A session in a token's chain, then whoever it acts for: its parent session, or the person. */
11692
+ const sessionActing = (act) => Schema.Struct({
11693
+ sub: PairwiseSessionId,
11694
+ act
11695
+ });
11696
+ const oneSession = sessionActing(PersonActor);
11697
+ const twoSessions = sessionActing(oneSession);
11698
+ const threeSessions = sessionActing(twoSessions);
11699
+ /**
11700
+ * A token's `act`, as RFC 8693 nests it: the current session, then up to three parent sessions,
11701
+ * then the accountable person, each by its pairwise ID. It's history, not authority: a verifier
11702
+ * allows the agent in `sub`, never an actor.
11703
+ */
11704
+ const IdentityActor = Schema.Union([
11705
+ oneSession,
11706
+ twoSessions,
11707
+ threeSessions,
11708
+ sessionActing(threeSessions)
11709
+ ]);
11710
+ /** A time in a token, in whole UTC epoch seconds. */
11711
+ const EpochSeconds = Schema.Int.check(Schema.isGreaterThan(0));
11712
+ Schema.Struct({
11713
+ iss: ApiOrigin,
11714
+ sub: AgentId,
11715
+ aud: IdentityAudience,
11716
+ iat: EpochSeconds,
11717
+ exp: EpochSeconds,
11718
+ jti: IdentityTokenId,
11719
+ act: IdentityActor
11720
+ }).check(Schema.makeFilter(({ iat, exp }) => exp > iat && exp - iat <= 600 || `an expiry after its issue, at most 600 seconds later`));
11721
+ /**
11722
+ * A signing key's ID, its `kid`: the key's RFC 7638 thumbprint, SHA-256 in base64url, so one ID
11723
+ * never names two keys.
11724
+ */
11725
+ const SigningKeyId = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{43}$/)).pipe(Schema.brand("SigningKeyId"));
11726
+ Schema.Struct({
11727
+ alg: Schema.Literal("ES256"),
11728
+ kid: SigningKeyId,
11729
+ typ: Schema.Literal("JWT")
11730
+ });
11731
+ /** A P-256 coordinate: 32 bytes in base64url, unpadded, in its one canonical spelling. */
11732
+ const Coordinate = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$/));
11733
+ /** One public key in the JWKS: exactly these fields, and never a private one. */
11734
+ const PublicSigningKey = Schema.Struct({
11735
+ kty: Schema.Literal("EC"),
11736
+ crv: Schema.Literal("P-256"),
11737
+ x: Coordinate,
11738
+ y: Coordinate,
11739
+ use: Schema.Literal("sig"),
11740
+ alg: Schema.Literal("ES256"),
11741
+ kid: SigningKeyId
11742
+ });
11743
+ Schema.Struct({ keys: Schema.Array(PublicSigningKey).check(Schema.isMaxLength(3)) });
11744
+ Schema.Struct({
11745
+ issuer: ApiOrigin,
11746
+ jwks_uri: Schema.String,
11747
+ subject_types_supported: Schema.Tuple([Schema.Literal("public")]),
11748
+ id_token_signing_alg_values_supported: Schema.Tuple([Schema.Literal("ES256")]),
11749
+ claims_supported: Schema.Tuple([
11750
+ Schema.Literal("iss"),
11751
+ Schema.Literal("sub"),
11752
+ Schema.Literal("aud"),
11753
+ Schema.Literal("exp"),
11754
+ Schema.Literal("iat"),
11755
+ Schema.Literal("jti"),
11756
+ Schema.Literal("act")
11757
+ ])
11758
+ });
11759
+ /**
11760
+ * The audience isn't one ref0 signs for: missing, given twice, or not an HTTPS origin as
11761
+ * `IdentityAudience` says. The refused text is never echoed.
11762
+ */
11763
+ var IdentityAudienceRefused = class extends Schema.TaggedError()("IdentityAudienceRefused", { nextStep: Schema.String }, { httpApiStatus: 400 }) {};
11764
+ /**
11765
+ * Less than a whole second is left before the session, a parent or the credential expires, or
11766
+ * the token would expire before it's recorded: the next prompt renews or replaces the session.
11767
+ */
11768
+ var IdentityTokenNotReady = class extends Schema.TaggedError()("IdentityTokenNotReady", { nextStep: Schema.String }, { httpApiStatus: 409 }) {};
11769
+ /**
11770
+ * ref0 signed an identity token for one of a project's sessions: in that project's log, on the
11771
+ * session's thread, with ref0's own IDs for the session, its agent and its accountable person,
11772
+ * and the token's `jti`, never the token. It proves ref0 made the token, not that any service
11773
+ * received or used it. A failed append discards the token, so every token has its event.
11774
+ */
11775
+ const IdentityTokenIssued = eventKind("identity_token.issued", Schema.Struct({
11776
+ session: SessionId,
11777
+ agent: AgentRef,
11778
+ /** The person whose attachment authorized the session's chain, last in the token's `act`. */
11779
+ accountable: PersonId,
11780
+ jti: IdentityTokenId,
11781
+ audience: IdentityAudience,
11782
+ issuer: ApiOrigin,
11783
+ keyId: SigningKeyId,
11784
+ issuedAt: Schema.DateTimeUtcFromMillis,
11785
+ expiresAt: Schema.DateTimeUtcFromMillis
11786
+ }));
11587
11787
  Schema.Literals([
11588
11788
  "info/refs",
11589
11789
  "git-upload-pack",
@@ -11834,6 +12034,71 @@ const GateAddition = Schema.Struct({
11834
12034
  from: NeedFrom
11835
12035
  });
11836
12036
  /**
12037
+ * A yes that met a need: its decider's, given by the person `by` when one gave it, such as an
12038
+ * admin answering as the owner's admins; or, `overridden`, a check ref0 said no to, met by the
12039
+ * yes of each of its overrides.
12040
+ */
12041
+ const NeedYes = Schema.Struct({
12042
+ decider: DeciderRef,
12043
+ by: Schema.optionalKey(PersonId),
12044
+ overridden: Schema.optionalKey(Schema.Literal(true))
12045
+ });
12046
+ /**
12047
+ * An override left of a check ref0 said no to: of a part's failed run, or of the check not running,
12048
+ * and who answers it.
12049
+ */
12050
+ const OverrideLeft = Schema.Struct({
12051
+ of: Schema.Literals(["failed run", "not run"]),
12052
+ by: OverrideAnswerer
12053
+ });
12054
+ /**
12055
+ * A decider a need waits on. For a check ref0 said no to, `overrides` lists each of its overrides
12056
+ * left, every one of whose yeses meets it in a pass's place, none when it has none: one yes to a
12057
+ * gate answers every decider its person may answer as, each override among them.
12058
+ */
12059
+ const NeedWait = Schema.Struct({
12060
+ decider: DeciderRef,
12061
+ overrides: Schema.optionalKey(Schema.Array(OverrideLeft).check(Schema.isMaxLength(maxGateDeciders)))
12062
+ });
12063
+ /**
12064
+ * How one of a version's needs stands under its gate's answers now, as the gate is decided from
12065
+ * them: `met` by each yes in `by`; `met` with nothing to wait for, `as` `no checks`, for `checks`
12066
+ * when none of the repo's checks runs on the change, or `on the tip`, for a check only the merge
12067
+ * queue's tip runs, which judges it before `main` moves; `waiting` on each decider in `on`, when
12068
+ * `all`, or else on a yes from any one of them; `waiting` for ref0 to read which of `main`'s
12069
+ * checks run on the change; or `refused` by a person's no to one of its deciders, or to an
12070
+ * override of one, which decides the whole gate no.
12071
+ */
12072
+ const NeedStanding = Schema.Union([
12073
+ Schema.Struct({
12074
+ state: Schema.Literal("met"),
12075
+ by: Schema.Array(NeedYes).check(Schema.isMaxLength(maxGateDeciders))
12076
+ }),
12077
+ Schema.Struct({
12078
+ state: Schema.Literal("met"),
12079
+ as: Schema.Literals(["no checks", "on the tip"])
12080
+ }),
12081
+ Schema.Struct({
12082
+ state: Schema.Literal("waiting"),
12083
+ on: Schema.Array(NeedWait).check(Schema.isMaxLength(maxGateDeciders)),
12084
+ all: Schema.Boolean
12085
+ }),
12086
+ Schema.Struct({
12087
+ state: Schema.Literal("waiting"),
12088
+ for: Schema.Literal("checks read")
12089
+ }),
12090
+ Schema.Struct({
12091
+ state: Schema.Literal("refused"),
12092
+ decider: DeciderRef,
12093
+ by: PersonId
12094
+ })
12095
+ ]);
12096
+ /** A version's need, with every place it came from, and how it stands once its gate is open. */
12097
+ const GateNeedView = Schema.Struct({
12098
+ ...GateNeed.fields,
12099
+ standing: Schema.optionalKey(NeedStanding)
12100
+ });
12101
+ /**
11837
12102
  * The version's gate decided again in place under `main`'s `.ref0/` now (Q7c): on which `main`
11838
12103
  * and under its tree, `pending` until `main`'s gate answers, then `held` or `grew`; the needs
11839
12104
  * it answered, joined to ref0's floor, absent while pending; what `main`'s gate read of the
@@ -11935,8 +12200,21 @@ const GateView = Schema.Struct({
11935
12200
  state: GateState,
11936
12201
  /** Why the gate failed; null otherwise. */
11937
12202
  why: Schema.NullOr(Schema.String),
11938
- /** None while pending; once answered, the floor's too, sorted as they're spelled. */
11939
- needs: Schema.Array(GateNeed),
12203
+ /**
12204
+ * None while pending; once answered, the floor's too, sorted as they're spelled, each with how
12205
+ * it stands once the version's gate is open.
12206
+ */
12207
+ needs: Schema.Array(GateNeedView),
12208
+ /** The repo's owner, whose admins answer its admins' needs: at home, its person alone. */
12209
+ owner: OwnerId,
12210
+ /**
12211
+ * The names of the owner and of the people its needs' standings name, where the directory has
12212
+ * them.
12213
+ */
12214
+ names: Schema.optionalKey(Schema.Array(Schema.Struct({
12215
+ owner: OwnerId,
12216
+ name: OwnerName
12217
+ })).check(Schema.isMaxLength(maxGateDeciders + 1))),
11940
12218
  /** What the gate read of the change's trees, each read once, in order; none while pending. */
11941
12219
  reads: GateReads,
11942
12220
  /** The project gate revision the version was decided under; none for 0. */
@@ -14074,6 +14352,7 @@ const KnownEvent = Schema.Union([
14074
14352
  ThreadListingChanged,
14075
14353
  SessionStarted,
14076
14354
  SessionEnded,
14355
+ IdentityTokenIssued,
14077
14356
  MemberRoleChanged,
14078
14357
  MemberRemoved,
14079
14358
  InvitationSent,
@@ -14917,6 +15196,11 @@ var ApprovalSecret = class extends HttpApiMiddleware.Service()("ref0/contracts/A
14917
15196
  * what to change. Any other part that fails its contract is answered with Effect's empty 400.
14918
15197
  */
14919
15198
  var MachineNameRefusal = class extends HttpApiMiddleware.Service()("ref0/contracts/MachineNameRefusal", { error: CommandRefused }) {};
15199
+ /**
15200
+ * An identity token's request whose audience its contract refuses, missing or not an HTTPS
15201
+ * origin, answered as `IdentityAudienceRefused`, which never echoes what was sent.
15202
+ */
15203
+ var IdentityAudienceRefusal = class extends HttpApiMiddleware.Service()("ref0/contracts/IdentityAudienceRefusal", { error: IdentityAudienceRefused }) {};
14920
15204
  const idempotency = { "idempotency-key": RequestId };
14921
15205
  const inProject = {
14922
15206
  owner: OwnerRef,
@@ -15139,7 +15423,18 @@ var MeGroup = class extends HttpApiGroup.make("me").add(HttpApiEndpoint.get("get
15139
15423
  UsageRangeRefused,
15140
15424
  AuthorityUnavailable
15141
15425
  ]
15142
- })).middleware(Authorization) {};
15426
+ }), HttpApiEndpoint.post("identityToken", identityTokenPath, {
15427
+ payload: IdentityTokenRequest,
15428
+ success: IssuedIdentityToken,
15429
+ error: [
15430
+ IdentityAudienceRefused,
15431
+ IdentityTokenNotReady,
15432
+ NotPermitted,
15433
+ SessionHasEnded,
15434
+ SlowDown,
15435
+ AuthorityUnavailable
15436
+ ]
15437
+ }).middleware(IdentityAudienceRefusal)).middleware(Authorization) {};
15143
15438
  /**
15144
15439
  * A thread's endpoints, as one of a project's threads and an org thread take them alike, by
15145
15440
  * where they are: `at` is a project's path parameters, or the owner's alone for its own scope.
@@ -16075,15 +16370,18 @@ const decisionEndpoints = (at) => {
16075
16370
  HttpApiEndpoint.get("get", "/:decision", {
16076
16371
  params: onDecision,
16077
16372
  query: { wait: Schema.optionalKey(DecisionWait) },
16078
- success: DecisionView,
16373
+ success: NamedDecision,
16079
16374
  error: [...projectErrors, DecisionNotFound]
16080
16375
  }),
16081
16376
  HttpApiEndpoint.post("answer", "/:decision/answers", {
16082
16377
  params: onDecision,
16083
16378
  headers: idempotency,
16084
16379
  payload: AnswerRequest,
16085
- success: DecisionView,
16380
+ success: NamedDecision,
16086
16381
  error: [
16382
+ ApprovalNeeded,
16383
+ CommandRefused,
16384
+ SlowDown,
16087
16385
  ...projectErrors,
16088
16386
  DecisionNotFound,
16089
16387
  AnswerRefused,
@@ -16898,6 +17196,15 @@ const ownSurfaces = {
16898
17196
  cli: "meters",
16899
17197
  mcp: null
16900
17198
  },
17199
+ "me.identityToken": {
17200
+ action: "session:change",
17201
+ actors: "agent",
17202
+ target: "session",
17203
+ stepUp: "never",
17204
+ asks: "never",
17205
+ cli: "identity-token",
17206
+ mcp: null
17207
+ },
16901
17208
  "threads.list": {
16902
17209
  action: "project:read",
16903
17210
  actors: "both",
@@ -18328,6 +18635,6 @@ const signOut = (origin) => Effect.gen(function* () {
18328
18635
  yield* client.execute(HttpClientRequest.make(method)(path, { body: HttpBody.jsonUnsafe({}) }));
18329
18636
  });
18330
18637
  //#endregion
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 };
18638
+ export { AgentHandle, AnswerKey, 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, threadParts };
18332
18639
 
18333
18640
  //# sourceMappingURL=client.mjs.map