orizu 0.5.26 → 0.5.28

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 (164) hide show
  1. package/README.md +19 -0
  2. package/dist/artifacts-git-runtime.d.ts +34 -0
  3. package/dist/artifacts-git-runtime.d.ts.map +1 -0
  4. package/dist/artifacts-git-runtime.js +312 -0
  5. package/dist/cloudflare-artifacts-git-remote.d.ts +5 -0
  6. package/dist/cloudflare-artifacts-git-remote.d.ts.map +1 -0
  7. package/dist/cloudflare-artifacts-git-remote.js +21 -0
  8. package/dist/dataset-transfer-download.d.ts +2 -0
  9. package/dist/dataset-transfer-download.d.ts.map +1 -0
  10. package/dist/dataset-transfer-download.js +66 -0
  11. package/dist/dataset-transfer-policy.d.ts +2 -0
  12. package/dist/dataset-transfer-policy.d.ts.map +1 -0
  13. package/dist/dataset-transfer-policy.js +8 -0
  14. package/dist/dataset-transfer-upload.d.ts +42 -0
  15. package/dist/dataset-transfer-upload.d.ts.map +1 -0
  16. package/dist/dataset-transfer-upload.js +110 -0
  17. package/dist/git-credential.d.ts.map +1 -1
  18. package/dist/git-credential.js +1 -1
  19. package/dist/git-recovery-environment.d.ts +1 -0
  20. package/dist/git-recovery-environment.d.ts.map +1 -1
  21. package/dist/git-recovery-environment.js +1 -1
  22. package/dist/help.d.ts.map +1 -1
  23. package/dist/help.js +44 -11
  24. package/dist/hosted-boot.d.ts +75 -2
  25. package/dist/hosted-boot.d.ts.map +1 -1
  26. package/dist/hosted-boot.js +585 -102
  27. package/dist/hosted-bootstrap.d.ts +2 -0
  28. package/dist/hosted-bootstrap.d.ts.map +1 -1
  29. package/dist/hosted-bootstrap.js +12 -3
  30. package/dist/hosted-harness-opencode.d.ts +8 -9
  31. package/dist/hosted-harness-opencode.d.ts.map +1 -1
  32. package/dist/hosted-harness-opencode.js +126 -24
  33. package/dist/hosted-harness.d.ts +3 -0
  34. package/dist/hosted-harness.d.ts.map +1 -1
  35. package/dist/hosted-harness.js +4 -1
  36. package/dist/hosted-harvest.d.ts +30 -9
  37. package/dist/hosted-harvest.d.ts.map +1 -1
  38. package/dist/hosted-harvest.js +222 -28
  39. package/dist/hosted-loop-lifecycle.d.ts +15 -3
  40. package/dist/hosted-loop-lifecycle.d.ts.map +1 -1
  41. package/dist/hosted-loop-lifecycle.js +6 -4
  42. package/dist/hosted-loop.d.ts +47 -7
  43. package/dist/hosted-loop.d.ts.map +1 -1
  44. package/dist/hosted-loop.js +310 -64
  45. package/dist/hosted-question-limits.d.ts +7 -0
  46. package/dist/hosted-question-limits.d.ts.map +1 -0
  47. package/dist/hosted-question-limits.js +6 -0
  48. package/dist/hosted-question.d.ts +27 -0
  49. package/dist/hosted-question.d.ts.map +1 -0
  50. package/dist/hosted-question.js +118 -0
  51. package/dist/hosted-run-event-sink.d.ts +10 -5
  52. package/dist/hosted-run-event-sink.d.ts.map +1 -1
  53. package/dist/hosted-run-event-sink.js +12 -8
  54. package/dist/hosted-runtime-assets.d.ts +16 -7
  55. package/dist/hosted-runtime-assets.d.ts.map +1 -1
  56. package/dist/hosted-runtime-assets.js +40 -12
  57. package/dist/hosted-session-cli.d.ts.map +1 -1
  58. package/dist/hosted-session-cli.js +10 -19
  59. package/dist/http.d.ts +1 -1
  60. package/dist/http.d.ts.map +1 -1
  61. package/dist/http.js +10 -4
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +113 -92
  64. package/dist/instruction-set-gepa-launch.d.ts +1 -1
  65. package/dist/instruction-set-gepa-launch.d.ts.map +1 -1
  66. package/dist/instruction-set-gepa-launch.js +5 -3
  67. package/dist/instruction-set-loader.d.ts.map +1 -1
  68. package/dist/instruction-set-loader.js +63 -2
  69. package/dist/instruction-set-lock/index.d.ts +51 -0
  70. package/dist/instruction-set-lock/index.d.ts.map +1 -0
  71. package/dist/instruction-set-lock/index.js +459 -0
  72. package/dist/instruction-set-lock/schema.v1.d.ts +136 -0
  73. package/dist/instruction-set-lock/schema.v1.d.ts.map +1 -0
  74. package/dist/instruction-set-lock/schema.v1.js +155 -0
  75. package/dist/instruction-set-provenance.d.ts +26 -0
  76. package/dist/instruction-set-provenance.d.ts.map +1 -0
  77. package/dist/instruction-set-provenance.js +68 -0
  78. package/dist/instruction-set-sync/helpers.d.ts +22 -0
  79. package/dist/instruction-set-sync/helpers.d.ts.map +1 -0
  80. package/dist/instruction-set-sync/helpers.js +677 -0
  81. package/dist/instruction-set-sync/index.d.ts +60 -0
  82. package/dist/instruction-set-sync/index.d.ts.map +1 -0
  83. package/dist/instruction-set-sync/index.js +689 -0
  84. package/dist/instruction-set-update/index.d.ts +42 -0
  85. package/dist/instruction-set-update/index.d.ts.map +1 -0
  86. package/dist/instruction-set-update/index.js +445 -0
  87. package/dist/instruction-set-verify/index.d.ts +27 -0
  88. package/dist/instruction-set-verify/index.d.ts.map +1 -0
  89. package/dist/instruction-set-verify/index.js +865 -0
  90. package/dist/instruction-sets-cli.d.ts +1 -4
  91. package/dist/instruction-sets-cli.d.ts.map +1 -1
  92. package/dist/instruction-sets-cli.js +220 -109
  93. package/dist/model-config-fields.d.ts +35 -0
  94. package/dist/model-config-fields.d.ts.map +1 -0
  95. package/dist/model-config-fields.js +28 -0
  96. package/dist/optimizations-list-cli.d.ts.map +1 -1
  97. package/dist/optimizations-list-cli.js +7 -4
  98. package/dist/score-format.d.ts +2 -0
  99. package/dist/score-format.d.ts.map +1 -0
  100. package/dist/score-format.js +18 -0
  101. package/dist/workbench-repo-contract.d.ts +65 -0
  102. package/dist/workbench-repo-contract.d.ts.map +1 -0
  103. package/dist/workbench-repo-contract.js +250 -0
  104. package/dist/workspace-bootstrap-job.d.ts +45 -0
  105. package/dist/workspace-bootstrap-job.d.ts.map +1 -0
  106. package/dist/workspace-bootstrap-job.js +431 -0
  107. package/dist/workspace-bootstrap-seed.d.ts +74 -0
  108. package/dist/workspace-bootstrap-seed.d.ts.map +1 -0
  109. package/dist/workspace-bootstrap-seed.js +209 -0
  110. package/package.json +4 -3
  111. package/src/artifacts-git-runtime.ts +360 -0
  112. package/src/cloudflare-artifacts-git-remote.ts +24 -0
  113. package/src/dataset-transfer-download.ts +61 -0
  114. package/src/dataset-transfer-policy.ts +8 -0
  115. package/src/dataset-transfer-upload.ts +145 -0
  116. package/src/git-credential.ts +1 -2
  117. package/src/git-recovery-environment.ts +1 -1
  118. package/src/help.ts +44 -11
  119. package/src/hosted-boot.ts +644 -109
  120. package/src/hosted-bootstrap.ts +14 -3
  121. package/src/hosted-harness-opencode.ts +130 -28
  122. package/src/hosted-harness.ts +4 -1
  123. package/src/hosted-harvest.ts +258 -33
  124. package/src/hosted-loop-lifecycle.ts +19 -5
  125. package/src/hosted-loop.ts +340 -68
  126. package/src/hosted-question-limits.ts +6 -0
  127. package/src/hosted-question.ts +145 -0
  128. package/src/hosted-run-event-sink.ts +24 -12
  129. package/src/hosted-runtime-assets.ts +51 -11
  130. package/src/hosted-session-cli.ts +10 -24
  131. package/src/http.ts +10 -4
  132. package/src/index.ts +108 -134
  133. package/src/instruction-set-gepa-launch.ts +4 -4
  134. package/src/instruction-set-loader.ts +53 -2
  135. package/src/instruction-set-lock/index.ts +561 -0
  136. package/src/instruction-set-lock/schema.v1.json +141 -0
  137. package/src/instruction-set-lock/schema.v1.ts +155 -0
  138. package/src/instruction-set-provenance.ts +89 -0
  139. package/src/instruction-set-sync/helpers.ts +707 -0
  140. package/src/instruction-set-sync/index.ts +791 -0
  141. package/src/instruction-set-update/index.ts +488 -0
  142. package/src/instruction-set-verify/index.ts +1067 -0
  143. package/src/instruction-sets-cli.ts +226 -114
  144. package/src/model-config-fields.ts +31 -0
  145. package/src/optimizations-list-cli.ts +7 -4
  146. package/src/score-format.ts +16 -0
  147. package/src/workbench-repo-contract.ts +314 -0
  148. package/src/workspace-bootstrap-job.ts +611 -0
  149. package/src/workspace-bootstrap-seed.ts +350 -0
  150. package/vendor/orizu-gepa/src/orizu_gepa_connector/instruction_set_loader.py +46 -2
  151. package/vendor/skills/orizu/SKILL.md +4 -2
  152. package/vendor/skills/orizu/flows/promote.md +4 -0
  153. package/vendor/skills/orizu/references/assess-and-plan.md +1 -1
  154. package/vendor/skills/orizu/references/authority-map.md +1 -1
  155. package/vendor/skills/orizu/references/cli-reference.md +151 -35
  156. package/vendor/skills/orizu/references/instructions-after-prompts.md +3 -3
  157. package/vendor/skills/orizu/references/migrate-existing-gepa-setup.md +5 -6
  158. package/vendor/skills/orizu/references/migrate-hand-rolled-instruction-layout.md +252 -0
  159. package/vendor/skills/orizu/references/optimization-reports.md +5 -4
  160. package/vendor/skills/orizu/references/optimization-with-gepa.md +1 -1
  161. package/vendor/skills/orizu/references/orizu-in-your-codebase.md +195 -0
  162. package/vendor/skills/orizu/references/primer.md +4 -2
  163. package/vendor/skills/orizu/references/prompt-control-plane.md +33 -29
  164. package/vendor/skills/orizu/references/vocabulary.md +1 -1
@@ -0,0 +1,611 @@
1
+ /** Agent-free synthetic workspace bootstrap. Account-level provider authority
2
+ * stays in the isolated broker; this process receives one scoped credential
3
+ * at a time and revokes it before continuing. */
4
+ import { mkdir, mkdtemp, rm } from 'node:fs/promises'
5
+ import { tmpdir } from 'node:os'
6
+ import { join } from 'node:path'
7
+
8
+ import { CLOUDFLARE_ARTIFACTS_HOST_PATTERN } from './cloudflare-artifacts-git-remote.js'
9
+ import {
10
+ buildSyntheticWorkspaceSeed,
11
+ buildSeedWorktree,
12
+ verifySeedClone,
13
+ } from './workspace-bootstrap-seed.js'
14
+ import {
15
+ createEphemeralAskPass,
16
+ defaultGitRunner,
17
+ type GitAuth,
18
+ type GitRunner,
19
+ } from './artifacts-git-runtime.js'
20
+ import { assertSecureTokenTransport } from './http.js'
21
+
22
+ export const WORKSPACE_BOOTSTRAP_JOB_CAPABILITY = 'workspace-bootstrap-job:v1'
23
+ export const WORKSPACE_BOOTSTRAP_NAMESPACE = 'orizu-workbench-dev'
24
+
25
+ const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
26
+ const CALLBACK_ATTEMPTS = 3
27
+ // The coordinator's eight-minute wall must still leave time for bounded seed
28
+ // preparation, revocation, failure reporting, and an independent readback.
29
+ // These are intentionally local to the hosted one-shot, never the legacy
30
+ // script's longer migration/repository budgets.
31
+ export const WORKSPACE_BOOTSTRAP_PUSH_TIMEOUT_MS = 120_000
32
+ export const WORKSPACE_BOOTSTRAP_VERIFICATION_CLONE_TIMEOUT_MS = 120_000
33
+
34
+ export const WORKSPACE_BOOTSTRAP_FAILURE_CODES = [
35
+ 'scope_refused',
36
+ 'provider_unavailable',
37
+ 'create_uncertain',
38
+ 'readback_failed',
39
+ 'credentials_pending',
40
+ 'bootstrap_interrupted',
41
+ ] as const
42
+
43
+ export type WorkspaceBootstrapFailureCode = (typeof WORKSPACE_BOOTSTRAP_FAILURE_CODES)[number]
44
+ export type WorkspaceBootstrapJobFetch = (url: string, init?: RequestInit) => Promise<Response>
45
+
46
+ export interface WorkspaceBootstrapJobEnv {
47
+ bootSecret: string
48
+ intentId: string
49
+ attemptId: string
50
+ coordinatorUrl: string
51
+ baseUrl: string
52
+ /** Derived by the coordinator from its pinned operator account id. */
53
+ expectedGitHost: string
54
+ }
55
+
56
+ export interface WorkspaceBootstrapJobCommandIo {
57
+ print: (line: string) => void
58
+ printErr?: (line: string) => void
59
+ json?: boolean
60
+ }
61
+
62
+ interface WorkspaceBootstrapSpec {
63
+ intentId: string
64
+ attemptId: string
65
+ team: { id: string; slug: string }
66
+ project: { id: string; slug: string; name: string | null }
67
+ repository: {
68
+ provider: 'cloudflare_artifacts'
69
+ repositoryId: string
70
+ remote: string
71
+ }
72
+ expectedSeedSha?: string
73
+ }
74
+
75
+ interface WorkspaceBootstrapCredential {
76
+ remote: string
77
+ username: 'x'
78
+ password: string
79
+ tokenId: string
80
+ expiresAt: string
81
+ }
82
+
83
+ interface VerifiedResult {
84
+ state: 'verified'
85
+ seedCommitSha: string
86
+ contentBytes: number
87
+ fileCount: number
88
+ }
89
+
90
+ interface FailedResult {
91
+ state: 'failed'
92
+ diagnostic: WorkspaceBootstrapFailureCode
93
+ }
94
+
95
+ type WorkspaceBootstrapControlResult = VerifiedResult | FailedResult
96
+
97
+ export interface WorkspaceBootstrapJobRunResult {
98
+ reported: boolean
99
+ state: 'verified' | 'failed'
100
+ diagnostic: WorkspaceBootstrapFailureCode | null
101
+ }
102
+
103
+ class WorkspaceBootstrapFailure extends Error {
104
+ readonly diagnostic: WorkspaceBootstrapFailureCode
105
+
106
+ constructor(diagnostic: WorkspaceBootstrapFailureCode) {
107
+ super(diagnostic)
108
+ this.name = 'WorkspaceBootstrapFailure'
109
+ this.diagnostic = diagnostic
110
+ }
111
+ }
112
+
113
+ function isObject(value: unknown): value is Record<string, unknown> {
114
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
115
+ }
116
+
117
+ function isLoopbackOrigin(value: string): boolean {
118
+ try {
119
+ const host = new URL(value).hostname
120
+ return host === 'localhost' || host === '127.0.0.1' || host === '::1'
121
+ } catch {
122
+ return false
123
+ }
124
+ }
125
+
126
+ export function resolveWorkspaceBootstrapJobEnv(
127
+ env: Record<string, string | undefined>
128
+ ):
129
+ | { ok: true; value: WorkspaceBootstrapJobEnv }
130
+ | { ok: false; missing: string[]; invalid: string[] } {
131
+ const names = [
132
+ 'ORIZU_BOOT_SECRET',
133
+ 'ORIZU_WORKSPACE_BOOTSTRAP_INTENT_ID',
134
+ 'ORIZU_WORKSPACE_BOOTSTRAP_ATTEMPT_ID',
135
+ 'ORIZU_COORDINATOR_URL',
136
+ 'ORIZU_BASE_URL',
137
+ 'ORIZU_WORKSPACE_BOOTSTRAP_GIT_HOST',
138
+ ] as const
139
+ const values = Object.fromEntries(names.map((name) => [name, env[name]?.trim() ?? ''])) as Record<
140
+ (typeof names)[number],
141
+ string
142
+ >
143
+ const missing = names.filter((name) => values[name].length === 0)
144
+ if (missing.length > 0) return { ok: false, missing: [...missing], invalid: [] }
145
+
146
+ const invalid: string[] = []
147
+ for (const name of ['ORIZU_COORDINATOR_URL', 'ORIZU_BASE_URL'] as const) {
148
+ try {
149
+ const parsed = new URL(values[name])
150
+ if (parsed.username || parsed.password) throw new Error('userinfo')
151
+ assertSecureTokenTransport(values[name])
152
+ } catch {
153
+ invalid.push(name)
154
+ }
155
+ }
156
+ if (!UUID_PATTERN.test(values.ORIZU_WORKSPACE_BOOTSTRAP_INTENT_ID))
157
+ invalid.push('ORIZU_WORKSPACE_BOOTSTRAP_INTENT_ID')
158
+ if (!UUID_PATTERN.test(values.ORIZU_WORKSPACE_BOOTSTRAP_ATTEMPT_ID))
159
+ invalid.push('ORIZU_WORKSPACE_BOOTSTRAP_ATTEMPT_ID')
160
+ const host = values.ORIZU_WORKSPACE_BOOTSTRAP_GIT_HOST.toLowerCase()
161
+ const localHostAllowed =
162
+ isLoopbackOrigin(values.ORIZU_COORDINATOR_URL) &&
163
+ isLoopbackOrigin(values.ORIZU_BASE_URL) &&
164
+ (host === 'localhost' || host === '127.0.0.1')
165
+ if (!CLOUDFLARE_ARTIFACTS_HOST_PATTERN.test(host) && !localHostAllowed) {
166
+ invalid.push('ORIZU_WORKSPACE_BOOTSTRAP_GIT_HOST')
167
+ }
168
+ if (invalid.length > 0) return { ok: false, missing: [], invalid }
169
+ return {
170
+ ok: true,
171
+ value: {
172
+ bootSecret: values.ORIZU_BOOT_SECRET,
173
+ intentId: values.ORIZU_WORKSPACE_BOOTSTRAP_INTENT_ID,
174
+ attemptId: values.ORIZU_WORKSPACE_BOOTSTRAP_ATTEMPT_ID,
175
+ coordinatorUrl: values.ORIZU_COORDINATOR_URL.replace(/\/+$/, ''),
176
+ baseUrl: values.ORIZU_BASE_URL.replace(/\/+$/, ''),
177
+ expectedGitHost: host,
178
+ },
179
+ }
180
+ }
181
+
182
+ export function assertWorkspaceBootstrapRemote(remote: string, expectedGitHost: string): void {
183
+ let parsed: URL
184
+ try {
185
+ parsed = new URL(remote)
186
+ } catch {
187
+ throw new WorkspaceBootstrapFailure('scope_refused')
188
+ }
189
+ const local =
190
+ (expectedGitHost === 'localhost' || expectedGitHost === '127.0.0.1') &&
191
+ parsed.hostname === expectedGitHost
192
+ if (
193
+ parsed.protocol !== 'https:' ||
194
+ parsed.hostname !== expectedGitHost ||
195
+ parsed.username.length > 0 ||
196
+ parsed.password.length > 0 ||
197
+ parsed.search.length > 0 ||
198
+ parsed.hash.length > 0 ||
199
+ (!local && parsed.port.length > 0) ||
200
+ !new RegExp(`^/git/${WORKSPACE_BOOTSTRAP_NAMESPACE}/[A-Za-z0-9][A-Za-z0-9._-]*\\.git$`).test(
201
+ parsed.pathname
202
+ )
203
+ ) {
204
+ throw new WorkspaceBootstrapFailure('scope_refused')
205
+ }
206
+ }
207
+
208
+ async function postJson(
209
+ url: string,
210
+ token: string,
211
+ body: object,
212
+ fetchImpl: WorkspaceBootstrapJobFetch
213
+ ): Promise<Response> {
214
+ return fetchImpl(url, {
215
+ method: 'POST',
216
+ redirect: 'error',
217
+ headers: {
218
+ Authorization: `Bearer ${token}`,
219
+ 'Content-Type': 'application/json',
220
+ },
221
+ body: JSON.stringify(body),
222
+ })
223
+ }
224
+
225
+ async function exchangeJobToken(
226
+ env: WorkspaceBootstrapJobEnv,
227
+ fetchImpl: WorkspaceBootstrapJobFetch,
228
+ sleep: (ms: number) => Promise<void>
229
+ ): Promise<string> {
230
+ const url = `${env.coordinatorUrl}/workspace-bootstrap-jobs/${encodeURIComponent(env.intentId)}/claim`
231
+ for (let attempt = 0; attempt < CALLBACK_ATTEMPTS; attempt += 1) {
232
+ try {
233
+ const response = await postJson(url, env.bootSecret, { attemptId: env.attemptId }, fetchImpl)
234
+ if (response.status === 401 || response.status === 403 || response.status === 409) {
235
+ throw new WorkspaceBootstrapFailure('scope_refused')
236
+ }
237
+ if (response.ok) {
238
+ const value: unknown = await response.json().catch(() => null)
239
+ if (
240
+ isObject(value) &&
241
+ typeof value.jobToken === 'string' &&
242
+ value.jobToken.length > 0 &&
243
+ value.attemptId === env.attemptId &&
244
+ typeof value.expiresAt === 'string'
245
+ ) {
246
+ return value.jobToken
247
+ }
248
+ throw new WorkspaceBootstrapFailure('scope_refused')
249
+ }
250
+ } catch (error) {
251
+ if (error instanceof WorkspaceBootstrapFailure) throw error
252
+ }
253
+ if (attempt < CALLBACK_ATTEMPTS - 1) await sleep(250 * 2 ** attempt)
254
+ }
255
+ throw new WorkspaceBootstrapFailure('provider_unavailable')
256
+ }
257
+
258
+ function parseSpec(value: unknown, env: WorkspaceBootstrapJobEnv): WorkspaceBootstrapSpec {
259
+ if (
260
+ !isObject(value) ||
261
+ value.intentId !== env.intentId ||
262
+ value.attemptId !== env.attemptId ||
263
+ !isObject(value.team) ||
264
+ !isObject(value.project) ||
265
+ !isObject(value.repository) ||
266
+ typeof value.team.id !== 'string' ||
267
+ typeof value.team.slug !== 'string' ||
268
+ typeof value.project.id !== 'string' ||
269
+ typeof value.project.slug !== 'string' ||
270
+ (value.project.name !== null && typeof value.project.name !== 'string') ||
271
+ value.repository.provider !== 'cloudflare_artifacts' ||
272
+ typeof value.repository.repositoryId !== 'string' ||
273
+ value.repository.repositoryId.length === 0 ||
274
+ typeof value.repository.remote !== 'string' ||
275
+ (value.expectedSeedSha !== undefined &&
276
+ (typeof value.expectedSeedSha !== 'string' || !/^[0-9a-f]{40}$/.test(value.expectedSeedSha)))
277
+ ) {
278
+ throw new WorkspaceBootstrapFailure('scope_refused')
279
+ }
280
+ assertWorkspaceBootstrapRemote(value.repository.remote, env.expectedGitHost)
281
+ return value as unknown as WorkspaceBootstrapSpec
282
+ }
283
+
284
+ async function fetchSpec(
285
+ env: WorkspaceBootstrapJobEnv,
286
+ token: string,
287
+ fetchImpl: WorkspaceBootstrapJobFetch
288
+ ): Promise<WorkspaceBootstrapSpec> {
289
+ let response: Response
290
+ try {
291
+ response = await postJson(
292
+ `${env.baseUrl}/api/internal/hosted-workspace-bootstrap/${encodeURIComponent(env.intentId)}/spec`,
293
+ token,
294
+ { attemptId: env.attemptId },
295
+ fetchImpl
296
+ )
297
+ } catch {
298
+ throw new WorkspaceBootstrapFailure('provider_unavailable')
299
+ }
300
+ if (response.status === 401 || response.status === 403 || response.status === 409)
301
+ throw new WorkspaceBootstrapFailure('scope_refused')
302
+ if (!response.ok) throw new WorkspaceBootstrapFailure('provider_unavailable')
303
+ return parseSpec(await response.json().catch(() => null), env)
304
+ }
305
+
306
+ function parseCredential(
307
+ value: unknown,
308
+ expectedRemote: string,
309
+ expectedGitHost: string
310
+ ): WorkspaceBootstrapCredential {
311
+ if (
312
+ !isObject(value) ||
313
+ value.remote !== expectedRemote ||
314
+ value.username !== 'x' ||
315
+ typeof value.password !== 'string' ||
316
+ value.password.length < 16 ||
317
+ typeof value.tokenId !== 'string' ||
318
+ value.tokenId.length === 0 ||
319
+ typeof value.expiresAt !== 'string' ||
320
+ !Number.isFinite(Date.parse(value.expiresAt))
321
+ ) {
322
+ throw new WorkspaceBootstrapFailure('scope_refused')
323
+ }
324
+ assertWorkspaceBootstrapRemote(value.remote, expectedGitHost)
325
+ return value as unknown as WorkspaceBootstrapCredential
326
+ }
327
+
328
+ async function fetchCredential(
329
+ env: WorkspaceBootstrapJobEnv,
330
+ token: string,
331
+ remote: string,
332
+ scope: 'write' | 'read',
333
+ fetchImpl: WorkspaceBootstrapJobFetch
334
+ ): Promise<WorkspaceBootstrapCredential> {
335
+ let response: Response
336
+ try {
337
+ response = await postJson(
338
+ `${env.baseUrl}/api/internal/hosted-workspace-bootstrap/${encodeURIComponent(env.intentId)}/credential`,
339
+ token,
340
+ { scope },
341
+ fetchImpl
342
+ )
343
+ } catch {
344
+ throw new WorkspaceBootstrapFailure('provider_unavailable')
345
+ }
346
+ if (response.status === 401 || response.status === 403 || response.status === 409)
347
+ throw new WorkspaceBootstrapFailure('scope_refused')
348
+ if (!response.ok) throw new WorkspaceBootstrapFailure('provider_unavailable')
349
+ return parseCredential(await response.json().catch(() => null), remote, env.expectedGitHost)
350
+ }
351
+
352
+ async function revokeCredential(
353
+ env: WorkspaceBootstrapJobEnv,
354
+ token: string,
355
+ tokenId: string,
356
+ fetchImpl: WorkspaceBootstrapJobFetch
357
+ ): Promise<void> {
358
+ let response: Response
359
+ try {
360
+ response = await postJson(
361
+ `${env.baseUrl}/api/internal/hosted-workspace-bootstrap/${encodeURIComponent(env.intentId)}/revoke`,
362
+ token,
363
+ { tokenId },
364
+ fetchImpl
365
+ )
366
+ } catch {
367
+ throw new WorkspaceBootstrapFailure('credentials_pending')
368
+ }
369
+ const value: unknown = response.ok ? await response.json().catch(() => null) : null
370
+ if (!response.ok || !isObject(value) || value.revoked !== true) {
371
+ throw new WorkspaceBootstrapFailure('credentials_pending')
372
+ }
373
+ }
374
+
375
+ async function withScopedCredential<T>(input: {
376
+ env: WorkspaceBootstrapJobEnv
377
+ token: string
378
+ remote: string
379
+ scope: 'write' | 'read'
380
+ root: string
381
+ fetchImpl: WorkspaceBootstrapJobFetch
382
+ operation: (auth: GitAuth) => Promise<T>
383
+ }): Promise<T> {
384
+ const credential = await fetchCredential(
385
+ input.env,
386
+ input.token,
387
+ input.remote,
388
+ input.scope,
389
+ input.fetchImpl
390
+ )
391
+ let result: T | undefined
392
+ let operationError: unknown
393
+ try {
394
+ const askPass = await createEphemeralAskPass(join(input.root, `${input.scope}-credential`))
395
+ try {
396
+ result = await input.operation({
397
+ askPassPath: askPass.path,
398
+ token: credential.password,
399
+ })
400
+ } catch (error) {
401
+ operationError = error
402
+ } finally {
403
+ await askPass.dispose()
404
+ }
405
+ } catch (error) {
406
+ operationError = error
407
+ }
408
+ // Revocation wins over the Git error: uncertain authority is the most
409
+ // safety-relevant recoverable state.
410
+ await revokeCredential(input.env, input.token, credential.tokenId, input.fetchImpl)
411
+ if (operationError) throw operationError
412
+ return result as T
413
+ }
414
+
415
+ function requireGitOk(
416
+ result: { exitCode: number },
417
+ diagnostic: WorkspaceBootstrapFailureCode
418
+ ): void {
419
+ if (result.exitCode !== 0) throw new WorkspaceBootstrapFailure(diagnostic)
420
+ }
421
+
422
+ async function reportControlResult(
423
+ env: WorkspaceBootstrapJobEnv,
424
+ token: string,
425
+ result: WorkspaceBootstrapControlResult,
426
+ fetchImpl: WorkspaceBootstrapJobFetch,
427
+ sleep: (ms: number) => Promise<void>
428
+ ): Promise<boolean> {
429
+ const url = `${env.baseUrl}/api/internal/hosted-workspace-bootstrap/${encodeURIComponent(env.intentId)}/result`
430
+ for (let attempt = 0; attempt < CALLBACK_ATTEMPTS; attempt += 1) {
431
+ try {
432
+ const response = await postJson(url, token, result, fetchImpl)
433
+ // Only an authoritative 2xx receipt proves this exact attempt/result was
434
+ // recorded. A generic 409 can describe stale or conflicting state.
435
+ if (response.ok) return true
436
+ } catch {
437
+ /* retry */
438
+ }
439
+ if (attempt < CALLBACK_ATTEMPTS - 1) await sleep(250 * 2 ** attempt)
440
+ }
441
+ return false
442
+ }
443
+
444
+ async function reportCoordinatorResult(
445
+ env: WorkspaceBootstrapJobEnv,
446
+ result: WorkspaceBootstrapControlResult,
447
+ fetchImpl: WorkspaceBootstrapJobFetch,
448
+ sleep: (ms: number) => Promise<void>
449
+ ): Promise<boolean> {
450
+ const url = `${env.coordinatorUrl}/workspace-bootstrap-jobs/${encodeURIComponent(env.intentId)}/result`
451
+ const body =
452
+ result.state === 'verified'
453
+ ? { state: 'verified', seedCommitSha: result.seedCommitSha }
454
+ : result
455
+ for (let attempt = 0; attempt < CALLBACK_ATTEMPTS; attempt += 1) {
456
+ try {
457
+ const response = await postJson(url, env.bootSecret, body, fetchImpl)
458
+ if (response.ok) return true
459
+ } catch {
460
+ /* retry */
461
+ }
462
+ if (attempt < CALLBACK_ATTEMPTS - 1) await sleep(250 * 2 ** attempt)
463
+ }
464
+ return false
465
+ }
466
+
467
+ export interface RunWorkspaceBootstrapJobOptions {
468
+ env: WorkspaceBootstrapJobEnv
469
+ fetchImpl?: WorkspaceBootstrapJobFetch
470
+ runGit?: GitRunner
471
+ sleep?: (ms: number) => Promise<void>
472
+ }
473
+
474
+ export async function runWorkspaceBootstrapJob(
475
+ options: RunWorkspaceBootstrapJobOptions
476
+ ): Promise<WorkspaceBootstrapJobRunResult> {
477
+ const { env } = options
478
+ const fetchImpl = options.fetchImpl ?? (globalThis.fetch as WorkspaceBootstrapJobFetch)
479
+ const runGit = options.runGit ?? defaultGitRunner
480
+ const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)))
481
+ let jobToken: string | null = null
482
+ let controlResult: WorkspaceBootstrapControlResult = {
483
+ state: 'failed',
484
+ diagnostic: 'bootstrap_interrupted',
485
+ }
486
+ let root: string | null = null
487
+
488
+ try {
489
+ jobToken = await exchangeJobToken(env, fetchImpl, sleep)
490
+ const spec = await fetchSpec(env, jobToken, fetchImpl)
491
+ const files = buildSyntheticWorkspaceSeed({
492
+ team: spec.team,
493
+ project: spec.project,
494
+ })
495
+ root = await mkdtemp(join(tmpdir(), 'orizu-workspace-bootstrap-'))
496
+ const worktree = join(root, 'seed')
497
+ const seedCommitSha = await buildSeedWorktree({
498
+ runGit,
499
+ worktree,
500
+ files,
501
+ commitMessage: 'chore: seed synthetic hosted workspace',
502
+ })
503
+ if (spec.expectedSeedSha && spec.expectedSeedSha !== seedCommitSha) {
504
+ throw new WorkspaceBootstrapFailure('bootstrap_interrupted')
505
+ }
506
+
507
+ await withScopedCredential({
508
+ env,
509
+ token: jobToken,
510
+ remote: spec.repository.remote,
511
+ scope: 'write',
512
+ root,
513
+ fetchImpl,
514
+ operation: async (auth) => {
515
+ const pushed = await runGit(['push', spec.repository.remote, 'HEAD:refs/heads/main'], {
516
+ cwd: worktree,
517
+ auth,
518
+ timeoutMs: WORKSPACE_BOOTSTRAP_PUSH_TIMEOUT_MS,
519
+ })
520
+ requireGitOk(pushed, 'create_uncertain')
521
+ },
522
+ })
523
+
524
+ const cloneDir = join(root, 'verification-clone')
525
+ await withScopedCredential({
526
+ env,
527
+ token: jobToken,
528
+ remote: spec.repository.remote,
529
+ scope: 'read',
530
+ root,
531
+ fetchImpl,
532
+ operation: async (auth) => {
533
+ await mkdir(root as string, { recursive: true })
534
+ const cloned = await runGit(
535
+ ['clone', '--branch', 'main', '--single-branch', spec.repository.remote, cloneDir],
536
+ {
537
+ cwd: root as string,
538
+ auth,
539
+ timeoutMs: WORKSPACE_BOOTSTRAP_VERIFICATION_CLONE_TIMEOUT_MS,
540
+ }
541
+ )
542
+ requireGitOk(cloned, 'readback_failed')
543
+ try {
544
+ await verifySeedClone({
545
+ runGit,
546
+ cloneDir,
547
+ files,
548
+ expectedSha: seedCommitSha,
549
+ })
550
+ } catch {
551
+ throw new WorkspaceBootstrapFailure('readback_failed')
552
+ }
553
+ },
554
+ })
555
+
556
+ controlResult = {
557
+ state: 'verified',
558
+ seedCommitSha,
559
+ contentBytes: files.reduce((sum, file) => sum + file.bytes.byteLength, 0),
560
+ fileCount: files.length,
561
+ }
562
+ } catch (error) {
563
+ controlResult = {
564
+ state: 'failed',
565
+ diagnostic:
566
+ error instanceof WorkspaceBootstrapFailure ? error.diagnostic : 'bootstrap_interrupted',
567
+ }
568
+ } finally {
569
+ if (root) await rm(root, { recursive: true, force: true })
570
+ }
571
+
572
+ const controlReported = jobToken
573
+ ? await reportControlResult(env, jobToken, controlResult, fetchImpl, sleep)
574
+ : false
575
+ const effectiveResult: WorkspaceBootstrapControlResult =
576
+ controlResult.state === 'verified' && !controlReported
577
+ ? { state: 'failed', diagnostic: 'bootstrap_interrupted' }
578
+ : controlResult
579
+ const coordinatorReported = await reportCoordinatorResult(env, effectiveResult, fetchImpl, sleep)
580
+ return {
581
+ reported: controlReported && coordinatorReported,
582
+ state: effectiveResult.state,
583
+ diagnostic: effectiveResult.state === 'failed' ? effectiveResult.diagnostic : null,
584
+ }
585
+ }
586
+
587
+ export async function workspaceBootstrapJobCommand(
588
+ args: readonly string[],
589
+ io: WorkspaceBootstrapJobCommandIo
590
+ ): Promise<number> {
591
+ if (args.includes('--capability-check')) {
592
+ io.print(WORKSPACE_BOOTSTRAP_JOB_CAPABILITY)
593
+ return 0
594
+ }
595
+ const resolved = resolveWorkspaceBootstrapJobEnv(process.env)
596
+ if (!resolved.ok) {
597
+ const detail =
598
+ resolved.missing.length > 0
599
+ ? `missing required env: ${resolved.missing.join(', ')}`
600
+ : `invalid or insecure env: ${resolved.invalid.join(', ')}`
601
+ io.printErr?.(`workspace-bootstrap-job: ${detail}`)
602
+ return 1
603
+ }
604
+ const result = await runWorkspaceBootstrapJob({ env: resolved.value })
605
+ io.print(
606
+ io.json
607
+ ? JSON.stringify(result)
608
+ : `workspace-bootstrap-job finished: ${result.state}${result.diagnostic ? ` (${result.diagnostic})` : ''}`
609
+ )
610
+ return result.reported ? 0 : 1
611
+ }