@jr2/orchestrator 0.5.1 → 0.6.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.
Files changed (185) hide show
  1. package/docs/agents-block.md +2 -2
  2. package/docs/concepts/agents-and-turns.md +56 -20
  3. package/docs/concepts/architecture.md +30 -17
  4. package/docs/concepts/charts.md +6 -3
  5. package/docs/concepts/converge.md +3 -0
  6. package/docs/concepts/effects.md +86 -31
  7. package/docs/concepts/machines-and-workflows.md +9 -0
  8. package/docs/concepts/pools-and-sources.md +6 -6
  9. package/docs/concepts/secrets-and-trust.md +126 -42
  10. package/docs/concepts/the-menu.md +3 -0
  11. package/docs/concepts/workspaces.md +129 -51
  12. package/docs/get-started/an-agent-in-a-sandbox.md +21 -19
  13. package/docs/get-started/have-your-assistant-write-a-machine.md +111 -40
  14. package/docs/get-started/install.md +4 -0
  15. package/docs/guides/add-tools-to-the-sandbox.md +17 -4
  16. package/docs/guides/bind-open-parts.md +5 -4
  17. package/docs/guides/cut-a-worktree.md +560 -0
  18. package/docs/guides/fix-a-failed-converge.md +1 -1
  19. package/docs/guides/let-an-agent-write-a-chart.md +5 -1
  20. package/docs/guides/look-inside-a-sandbox.md +18 -15
  21. package/docs/guides/move-from-kind-to-a-shared-cluster.md +16 -0
  22. package/docs/guides/push-and-sign-a-branch.md +67 -21
  23. package/docs/guides/run-a-command-or-call-a-url.md +84 -41
  24. package/docs/guides/run-one-worker-per-item.md +19 -18
  25. package/docs/guides/set-an-agents-access-and-dials.md +67 -22
  26. package/docs/guides/size-a-workspace.md +19 -6
  27. package/docs/guides/use-a-hosted-provider.md +6 -0
  28. package/docs/guides/watch-a-run.md +47 -24
  29. package/docs/guides/write-a-workflow.md +1 -1
  30. package/docs/llms.txt +33 -12
  31. package/docs/reference/authoring-surface/agent.md +34 -11
  32. package/docs/reference/authoring-surface/answer.md +19 -3
  33. package/docs/reference/authoring-surface/arg.md +27 -5
  34. package/docs/reference/authoring-surface/branchname.md +15 -0
  35. package/docs/reference/authoring-surface/command.md +36 -21
  36. package/docs/reference/authoring-surface/fail.md +17 -4
  37. package/docs/reference/authoring-surface/file.md +36 -16
  38. package/docs/reference/authoring-surface/http.md +108 -8
  39. package/docs/reference/authoring-surface/isready.md +14 -0
  40. package/docs/reference/authoring-surface/jr2setup.md +1 -1
  41. package/docs/reference/authoring-surface/open.md +36 -5
  42. package/docs/reference/authoring-surface/paramsof.md +22 -4
  43. package/docs/reference/authoring-surface/pool.md +4 -4
  44. package/docs/reference/authoring-surface/push.md +30 -12
  45. package/docs/reference/authoring-surface/readyof.md +21 -0
  46. package/docs/reference/authoring-surface/secret.md +25 -4
  47. package/docs/reference/authoring-surface/source.md +3 -3
  48. package/docs/reference/authoring-surface/type-agentdefinition.md +2 -2
  49. package/docs/reference/authoring-surface/type-agentslots.md +4 -1
  50. package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
  51. package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
  52. package/docs/reference/authoring-surface/type-bindactors.md +14 -0
  53. package/docs/reference/authoring-surface/type-binding.md +5 -6
  54. package/docs/reference/authoring-surface/type-commandinput.md +4 -3
  55. package/docs/reference/authoring-surface/type-commandoptions.md +0 -22
  56. package/docs/reference/authoring-surface/type-commandoutput.md +22 -4
  57. package/docs/reference/authoring-surface/type-customize.md +4 -2
  58. package/docs/reference/authoring-surface/type-dispatchoutput.md +8 -1
  59. package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
  60. package/docs/reference/authoring-surface/type-filebody.md +4 -8
  61. package/docs/reference/authoring-surface/type-framepath.md +14 -0
  62. package/docs/reference/authoring-surface/type-hostinjectedinput.md +2 -4
  63. package/docs/reference/authoring-surface/type-httpdefinition.md +6 -3
  64. package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
  65. package/docs/reference/authoring-surface/type-httpoutput.md +7 -1
  66. package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
  67. package/docs/reference/authoring-surface/type-namestart.md +77 -0
  68. package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +1 -6
  69. package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
  70. package/docs/reference/authoring-surface/type-opencommandinput.md +7 -2
  71. package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +1 -6
  72. package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +5 -10
  73. package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
  74. package/docs/reference/authoring-surface/type-poolspec.md +2 -2
  75. package/docs/reference/authoring-surface/type-pushinput.md +22 -3
  76. package/docs/reference/authoring-surface/type-pushoutput.md +32 -7
  77. package/docs/reference/authoring-surface/type-reposlot.md +5 -5
  78. package/docs/reference/authoring-surface/type-sandboxoptions.md +11 -4
  79. package/docs/reference/authoring-surface/type-slothandles.md +5 -13
  80. package/docs/reference/authoring-surface/type-sourcespec.md +10 -10
  81. package/docs/reference/authoring-surface/type-workspaced.md +29 -8
  82. package/docs/reference/authoring-surface/type-workspacehandles.md +5 -6
  83. package/docs/reference/authoring-surface/type-workspaceoptions.md +1 -13
  84. package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
  85. package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
  86. package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
  87. package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
  88. package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
  89. package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
  90. package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
  91. package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
  92. package/docs/reference/authoring-surface/workspace.md +65 -37
  93. package/docs/reference/authoring-surface/worktree.md +71 -0
  94. package/docs/reference/authoring-surface.md +30 -10
  95. package/docs/reference/cli.md +1 -1
  96. package/docs/reference/config.md +13 -4
  97. package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +10 -9
  98. package/docs/reference/decisions/0002-duplex-streaming-actor.md +17 -10
  99. package/docs/reference/decisions/0004-worktree-provisioning-model.md +27 -21
  100. package/docs/reference/decisions/0005-sandbox-pod-composition.md +29 -19
  101. package/docs/reference/decisions/0006-agent-control-surface.md +6 -3
  102. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +30 -30
  103. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +35 -17
  104. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +8 -2
  105. package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +9 -7
  106. package/docs/reference/decisions/0017-pool-over-a-source-port.md +6 -4
  107. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +21 -9
  108. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +2 -1
  109. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +8 -9
  110. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +62 -65
  111. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +9 -1
  112. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +13 -12
  113. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +4 -1
  114. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +18 -19
  115. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +8 -8
  116. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +4 -4
  117. package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +57 -46
  118. package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +5 -0
  119. package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +20 -8
  120. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +24 -24
  121. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +5 -3
  122. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +110 -67
  123. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +101 -74
  124. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +5 -6
  125. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +2 -0
  126. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +181 -153
  127. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +74 -63
  128. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +31 -20
  129. package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +1 -1
  130. package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +295 -0
  131. package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +320 -0
  132. package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
  133. package/docs/reference/decisions.md +3 -0
  134. package/docs/reference/glossary.md +51 -12
  135. package/docs/reference/http-api.md +45 -7
  136. package/docs/reference/machines.md +0 -1
  137. package/docs/why.md +5 -4
  138. package/package.json +3 -3
  139. package/src/actor.ts +161 -35
  140. package/src/agent.ts +6 -6
  141. package/src/ambient.ts +3 -5
  142. package/src/chart.ts +186 -19
  143. package/src/charts.ts +9 -2
  144. package/src/config.ts +16 -6
  145. package/src/custodian.lua +17 -5
  146. package/src/custodian.ts +251 -77
  147. package/src/customize.ts +11 -3
  148. package/src/effect-checks.ts +50 -3
  149. package/src/effect.ts +343 -127
  150. package/src/effector-wire.ts +6 -3
  151. package/src/fail.ts +17 -4
  152. package/src/harness-client.ts +74 -31
  153. package/src/harness-env.ts +33 -0
  154. package/src/held-secrets.ts +125 -16
  155. package/src/holds.ts +3 -0
  156. package/src/http-effect.ts +88 -32
  157. package/src/http.ts +56 -17
  158. package/src/index.ts +15 -1
  159. package/src/internal.ts +1 -0
  160. package/src/kube-client.ts +6 -3
  161. package/src/machine-doc.ts +3 -4
  162. package/src/model-keys.ts +24 -0
  163. package/src/names.ts +19 -6
  164. package/src/notices.ts +443 -54
  165. package/src/open-body.ts +85 -19
  166. package/src/open.ts +36 -5
  167. package/src/parts.ts +40 -28
  168. package/src/party.ts +33 -0
  169. package/src/pick.ts +41 -7
  170. package/src/pool.ts +44 -23
  171. package/src/registration.ts +53 -11
  172. package/src/repo-identity.ts +7 -3
  173. package/src/repos.ts +20 -2
  174. package/src/run-host.ts +106 -20
  175. package/src/sandbox-effect.ts +217 -66
  176. package/src/sandbox-kube.ts +63 -16
  177. package/src/secret-placement.ts +9 -2
  178. package/src/setup.ts +86 -6
  179. package/src/tokens.ts +107 -32
  180. package/src/vocabulary.ts +23 -4
  181. package/src/wire.ts +10 -10
  182. package/src/workspace.ts +264 -253
  183. package/src/worktree.ts +249 -0
  184. package/docs/reference/authoring-surface/type-noslotspec.md +0 -26
  185. package/docs/reference/authoring-surface/type-workspacespec.md +0 -37
@@ -0,0 +1,249 @@
1
+ // `worktree()`, the kit Effect that cuts a Worktree, and the
2
+ // path types that carry a body's Repo Slots to every Worktree input.
3
+ //
4
+ // A Worktree is a folder, `/work/<slot>/<name>`. The Workspace clones only; the Machine cuts. The cut
5
+ // runs on the `command` machinery: a kit program (`packages/harness/src/cut.ts`) on the runtime
6
+ // volume, no new wire kind, marked idempotent, so a restore that finds no exec sends it again with
7
+ // the same id. What an Agent's param can cause settles as `refused`, never `onError` (ADR-0067). A
8
+ // settled `ready` row keeps the slot, the path and the branch as fields: a push reads its branch
9
+ // there, because the row's output drops its tail and a name in an input is a Chart's word.
10
+
11
+ import { z } from "zod";
12
+ import type { Duration, EffectLogic, ExecPortFactory, LaterOutcome, Unknown } from "./effect.ts";
13
+ import { commandWith } from "./effect.ts";
14
+ import { createExecPort } from "./harness-client.ts";
15
+
16
+ /** What a Worktree's name may start with: neither `.` nor `-`, and not the end of the path. */
17
+ type NameStart =
18
+ | "a"
19
+ | "b"
20
+ | "c"
21
+ | "d"
22
+ | "e"
23
+ | "f"
24
+ | "g"
25
+ | "h"
26
+ | "i"
27
+ | "j"
28
+ | "k"
29
+ | "l"
30
+ | "m"
31
+ | "n"
32
+ | "o"
33
+ | "p"
34
+ | "q"
35
+ | "r"
36
+ | "s"
37
+ | "t"
38
+ | "u"
39
+ | "v"
40
+ | "w"
41
+ | "x"
42
+ | "y"
43
+ | "z"
44
+ | "A"
45
+ | "B"
46
+ | "C"
47
+ | "D"
48
+ | "E"
49
+ | "F"
50
+ | "G"
51
+ | "H"
52
+ | "I"
53
+ | "J"
54
+ | "K"
55
+ | "L"
56
+ | "M"
57
+ | "N"
58
+ | "O"
59
+ | "P"
60
+ | "Q"
61
+ | "R"
62
+ | "S"
63
+ | "T"
64
+ | "U"
65
+ | "V"
66
+ | "W"
67
+ | "X"
68
+ | "Y"
69
+ | "Z"
70
+ | "0"
71
+ | "1"
72
+ | "2"
73
+ | "3"
74
+ | "4"
75
+ | "5"
76
+ | "6"
77
+ | "7"
78
+ | "8"
79
+ | "9"
80
+ | "_";
81
+
82
+ /** A Worktree of any Repo Slot: what a kit factory states, before `jr2Setup` narrows it to the
83
+ * slots of the body. */
84
+ export type AnyWorktreePath = `/work/${string}/${string}`;
85
+ /** A Worktree of the Repo Slots `S`. One segment below the slot, that starts with a letter, a
86
+ * digit or `_`: `${context.workspace.repos.app}/run`. The compiler sees the start of the name; a
87
+ * `/` further on is the Effect's own refusal. */
88
+ export type WorktreePath<S extends string> = `/work/${S}/${NameStart}${string}`;
89
+ /** A Turn's Frame: a Worktree, or `/work`, stated. `jr2Setup` narrows it to the body's slots. */
90
+ export type AnyFramePath = "/work" | `/work/${string}`;
91
+ /** A Turn's Frame in a Workspace with the Repo Slots `S`. */
92
+ export type FramePath<S extends string> = WorktreePath<S> | "/work";
93
+
94
+ /** A pick param that names a branch: the rule the cut and the push share, as one JSON-schema
95
+ * pattern, so that a bad name is refused at the Menu, and the Agent can correct it. */
96
+ export const BRANCH_NAME =
97
+ /^(?!\/)(?!HEAD$)(?!refs\/)(?!origin\/)(?![0-9a-f]{7,40}$)(?!.*\.\.)(?!.*\/\/)(?!(?:.*\/)?[.-])(?!.*\.lock(?:\/|$))(?!.*[./]$)[A-Za-z0-9._/-]+$/;
98
+
99
+ /** A kit schema for a pick param that names a branch. For example:
100
+ * `input: z.object({ branch: branchName })`. */
101
+ export const branchName = z.string().regex(BRANCH_NAME, "a branch name git and jr2's push both take");
102
+
103
+ /** The input of a `worktree()`: a branch Worktree, or a detached one. */
104
+ export type WorktreeInput =
105
+ | {
106
+ /** The root of the Worktree: `${context.workspace.repos.app}/<name>`, a constant word. */
107
+ path: AnyWorktreePath;
108
+ /** The branch. It resolves as a local branch, then `origin/<branch>` (tracked), then a new
109
+ * branch. */
110
+ branch: string;
111
+ /** Where a new branch starts. Default: the Binding's base. On a branch that exists, it must
112
+ * be that branch's tip, or the cut is `refused`. */
113
+ from?: string;
114
+ detach?: never;
115
+ expect?: never;
116
+ }
117
+ | {
118
+ path: AnyWorktreePath;
119
+ /** The commit to check out, with no branch. The Worktree is forced to it and cleaned on each
120
+ * cut. Ignored files stay, so that a reviewer can run the tests. */
121
+ detach: string;
122
+ branch?: never;
123
+ from?: never;
124
+ expect?: never;
125
+ };
126
+
127
+ /** What a cut found: `held`, a cut made this Worktree earlier, so what is in it is earlier work;
128
+ * `local`, a local branch; `remote`, `origin/<branch>`, now tracked; `none`, a new branch with no
129
+ * upstream; `commit`, a detached cut. Open: a later value does not break an author's code. */
130
+ export type WorktreeFound = "held" | "local" | "remote" | "none" | "commit" | (string & {});
131
+
132
+ export type WorktreeReady<S extends string = string> = {
133
+ outcome: "ready";
134
+ slot: S;
135
+ path: WorktreePath<S>;
136
+ /** The branch of the cut, from git and the cut's record, never from the folder or HEAD. `null`
137
+ * when the Worktree is detached. */
138
+ branch: string | null;
139
+ /** The tip of `branch` (of the commit, when detached). Never HEAD. */
140
+ head: string;
141
+ found: WorktreeFound;
142
+ /** ADR-0053's words when the remote did not answer. The cut used what the clone holds. */
143
+ stale?: string;
144
+ };
145
+
146
+ /** No Worktree, and nothing changed: a bad path, a name git or the push refuses, a re-cut that does
147
+ * not agree with the first, a branch that another Worktree holds, an `expect` that does not hold, or a
148
+ * name that the remote cannot confirm. */
149
+ export type WorktreeRefused = { outcome: "refused"; reason: string };
150
+
151
+ /** The output of a `worktree()`. `unknown`: its state exited while it ran, or the cut did not end. */
152
+ export type WorktreeOutput<S extends string = string> = WorktreeReady<S> | WorktreeRefused | Unknown | LaterOutcome;
153
+
154
+ /** Is it `ready`? For a guard. A Chart's form is the guard `jr2.ready`. */
155
+ export const isReady = <O extends { outcome: string }>(output: O): output is Extract<O, { outcome: "ready" }> =>
156
+ output.outcome === "ready";
157
+
158
+ /** The `ready` output of an `onDone` arm that `isReady` guards. xstate carries no guard's narrowing
159
+ * to its actions, so an `assign` reads the output through this. */
160
+ export function readyOf<O extends { outcome: string }>(output: O): Extract<O, { outcome: "ready" }> {
161
+ if (output.outcome !== "ready") throw new Error("readyOf: the output is not ready: guard the arm with isReady");
162
+ return output as Extract<O, { outcome: "ready" }>;
163
+ }
164
+
165
+ /** The options of `worktree()`. */
166
+ export type WorktreeOptions = {
167
+ /** `"new"`: refuse a branch that exists, local or on the remote. For a name that a planner or a
168
+ * door chose for new work: a collision is a refusal, not someone else's branch. `"existing"`:
169
+ * refuse a branch that does not exist, and make nothing. For a run that must continue a branch.
170
+ * A Chart cannot change it, and a cut lent to a Chart must state it. */
171
+ expect?: "new" | "existing";
172
+ /** How long the fetch and the cut can take. Default `"10m"`. */
173
+ timeout?: Duration;
174
+ };
175
+
176
+ /** Over an injected port: the seam of the tests. */
177
+ export function worktreeWith(
178
+ portFactory: ExecPortFactory,
179
+ options: WorktreeOptions = {},
180
+ ): EffectLogic<WorktreeInput, WorktreeOutput> {
181
+ return commandWith(
182
+ portFactory,
183
+ ["/opt/jr2/bin/node", "/opt/jr2/src/cut.ts"],
184
+ { timeout: options.timeout ?? "10m" },
185
+ undefined,
186
+ { ...(options.expect !== undefined ? { expect: options.expect } : {}) },
187
+ ) as unknown as EffectLogic<WorktreeInput, WorktreeOutput>;
188
+ }
189
+
190
+ /**
191
+ * Make a `worktree` Effect: it cuts a Worktree of a Repo Slot, or reads the one that is there. Put it
192
+ * in `actors`, and invoke it from a `workspace()` body.
193
+ *
194
+ * With `{ path, branch, from? }`, the branch resolves in this order, after a fetch: a local branch;
195
+ * `origin/<branch>`, tracked; a new branch from `from` or the Binding's base, with no upstream. With
196
+ * `{ path, detach }`, the Worktree is forced to that commit and cleaned, each time. `path` is exactly
197
+ * `/work/<slot>/<name>`. Each outcome is output: `ready`, `refused`, `unknown`.
198
+ *
199
+ * `expect` says if the branch can exist: `worktree({ expect: "new" })` refuses a branch that exists,
200
+ * and `worktree({ expect: "existing" })` refuses a branch that does not exist. A run cannot change it.
201
+ *
202
+ * A cut needs a Repo Slot. Under a Workspace with no Repo Slot, `jr2 up` refuses it, and the invoke
203
+ * fails with `worktree "<slot>" runs under a Workspace with no Repo Slot: a cut makes a Worktree of a
204
+ * Repo Slot, and there is none — declare one: repos: { app: "<url>" } (ADR-0075)`.
205
+ *
206
+ * @param options - Optional. `expect`, and `timeout`, how long the fetch and the cut can take.
207
+ * Default: `"10m"`.
208
+ * @returns The actor logic of the Effect's slot. Its output is a {@link WorktreeOutput}.
209
+ *
210
+ * @example
211
+ * ```ts
212
+ * import { fail, isReady, jr2Setup, worktree, type Workspaced } from "@jr2/orchestrator";
213
+ *
214
+ * type BodyInput = Workspaced<{ branch: string }, "app">;
215
+ * const tree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
216
+ *
217
+ * export const body = jr2Setup({
218
+ * types: {} as { input: BodyInput; context: BodyInput },
219
+ * actors: { cut: worktree({ expect: "new" }), fail: fail() },
220
+ * }).createMachine({
221
+ * context: ({ input }) => input,
222
+ * on: { "workspace.lost": ".notCut" },
223
+ * initial: "cutting",
224
+ * states: {
225
+ * cutting: {
226
+ * invoke: {
227
+ * src: "cut",
228
+ * input: ({ context }) => ({ path: tree(context), branch: context.branch }),
229
+ * // The last arm has no guard: it takes `refused`, `unknown` and each later outcome.
230
+ * onDone: [{ guard: ({ event }) => isReady(event.output), target: "done" }, { target: "notCut" }],
231
+ * },
232
+ * },
233
+ * done: { type: "final" },
234
+ * notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
235
+ * },
236
+ * });
237
+ * ```
238
+ *
239
+ * @see docs/guides/cut-a-worktree.md
240
+ * @see docs/concepts/workspaces.md
241
+ * @see docs/concepts/effects.md
242
+ * @see docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md
243
+ */
244
+ export function worktree(options: WorktreeOptions = {}): EffectLogic<WorktreeInput, WorktreeOutput> {
245
+ return worktreeWith(
246
+ (endpoint, bearer) => createExecPort({ baseUrl: endpoint, ...(bearer ? { token: bearer } : {}) }),
247
+ options,
248
+ );
249
+ }
@@ -1,26 +0,0 @@
1
- ---
2
- title: NoSlotSpec
3
- description: "What the `spec` of a `workspace()` with no Repo Slot returns: only `workGroup`."
4
- ---
5
-
6
- # `NoSlotSpec`
7
-
8
- Type, in `@jr2/orchestrator/src/workspace.ts`. The signature of an export, or a type that it names, names this type. The [Authoring surface](../authoring-surface.md) page lists each export. This type is not an export of `@jr2/orchestrator`, so a workflow module does not import it by name.
9
-
10
- ```ts
11
- type NoSlotSpec = Pick<WorkspaceSpec, "workGroup"> & { branch?: never; reviewSha?: never };
12
- ```
13
-
14
- What the `spec` of a `workspace()` with no Repo Slot returns: only `workGroup`. There is no
15
- branch and no review Worktree, because the Workspace has no Repo Slot.
16
-
17
- **Fields**
18
-
19
- - `workGroup` (optional): `number`
20
-
21
- The group id that owns the files in `/work`. With it, the Sandbox Image and the User
22
- Container can both write those files when they run as different users. Default: 2000. Set it
23
- to a group id that the User Container's sessions already have, for example when a root sshd
24
- builds their groups from `/etc/group`. A non-negative integer.
25
- - `branch` (optional): `never`
26
- - `reviewSha` (optional): `never`
@@ -1,37 +0,0 @@
1
- ---
2
- title: WorkspaceSpec
3
- description: "What the `spec` of a `workspace()` returns: the branch that the Workspace works on, and two optional fields."
4
- ---
5
-
6
- # `WorkspaceSpec`
7
-
8
- Type, in `@jr2/orchestrator/src/workspace.ts`. The signature of an export, or a type that it names, names this type. The [Authoring surface](../authoring-surface.md) page lists each export. This type is not an export of `@jr2/orchestrator`, so a workflow module does not import it by name.
9
-
10
- ```ts
11
- type WorkspaceSpec = {
12
- branch: string;
13
- workGroup?: number;
14
- reviewSha?: string;
15
- };
16
- ```
17
-
18
- What the `spec` of a `workspace()` returns: the branch that the Workspace works on, and two
19
- optional fields. jr2 calls `spec` with the run input when the run enters the Workspace.
20
-
21
- **Fields**
22
-
23
- - `branch`: `string`
24
-
25
- The branch that the Workspace works on: each Repo Slot gets a Worktree for it, at
26
- `/work/<slot>/<branch>`, with each `/` in the branch written as `-`. Required, and not
27
- `default`, which is the directory of the clone. Your Machine decides its name.
28
- - `workGroup` (optional): `number`
29
-
30
- The group id that owns the files in `/work`. With it, the Sandbox Image and the User
31
- Container can both write those files when they run as different users. Default: 2000. Set it
32
- to a group id that the User Container's sessions already have, for example when a root sshd
33
- builds their groups from `/etc/group`. A non-negative integer.
34
- - `reviewSha` (optional): `string`
35
-
36
- A commit to check out in a second, detached Worktree beside each branch Worktree, for a
37
- reviewer: `/work/<slot>/<branch>-review`. The body gets its paths as `workspace.review`.