@meistrari/tela-cli 0.7.0 → 0.7.5

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 (59) hide show
  1. package/README.md +56 -106
  2. package/dist/commands/auth.d.ts +2 -0
  3. package/dist/commands/context.d.ts +2 -0
  4. package/dist/commands/doctor-auth.d.ts +2 -0
  5. package/dist/commands/env.d.ts +2 -0
  6. package/dist/credentials.d.ts +2 -0
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.js +7027 -0
  9. package/dist/output.d.ts +13 -0
  10. package/dist/program.d.ts +2 -0
  11. package/package.json +17 -24
  12. package/scripts/install-skills.cjs +127 -0
  13. package/skills/tela-cli/SKILL.md +20 -0
  14. package/skills/tela-cli/references/agent.md +111 -0
  15. package/cli.ts +0 -25
  16. package/postinstall.sh +0 -19
  17. package/src/agent-api.ts +0 -300
  18. package/src/assets.d.ts +0 -4
  19. package/src/auth.ts +0 -432
  20. package/src/claude.ts +0 -101
  21. package/src/commands/doctor.ts +0 -35
  22. package/src/commands/feedback.ts +0 -701
  23. package/src/commands/metadata.ts +0 -242
  24. package/src/commands/push.ts +0 -208
  25. package/src/commands/run.ts +0 -1699
  26. package/src/commands/status.ts +0 -109
  27. package/src/commands/sync.ts +0 -245
  28. package/src/commit-message.ts +0 -69
  29. package/src/config.ts +0 -799
  30. package/src/diagnostics.ts +0 -813
  31. package/src/errors.ts +0 -122
  32. package/src/forgejo.ts +0 -233
  33. package/src/git.ts +0 -457
  34. package/src/ink/assets/160092__jorickhoofd__dog-bark-1.mp3 +0 -0
  35. package/src/ink/bark.tsx +0 -241
  36. package/src/ink/components.tsx +0 -178
  37. package/src/ink/runtime.tsx +0 -90
  38. package/src/ink/screens/feedback-screen.tsx +0 -395
  39. package/src/ink/screens/push-screen.tsx +0 -232
  40. package/src/ink/screens/run-screen.tsx +0 -292
  41. package/src/ink/screens/setup/breadcrumb.tsx +0 -24
  42. package/src/ink/screens/setup/setup-screen.tsx +0 -612
  43. package/src/ink/screens/setup/step-frame.tsx +0 -31
  44. package/src/ink/screens/setup/steps/done-step.tsx +0 -29
  45. package/src/ink/screens/setup/steps/environment-step.tsx +0 -23
  46. package/src/ink/screens/setup/steps/organization-step.tsx +0 -35
  47. package/src/ink/screens/setup/steps/review-step.tsx +0 -78
  48. package/src/ink/screens/setup/steps/running-step.tsx +0 -37
  49. package/src/ink/screens/setup/steps/ssh-key-step.tsx +0 -48
  50. package/src/ink/screens/setup/steps/text-field-step.tsx +0 -18
  51. package/src/ink/screens/setup/steps.ts +0 -156
  52. package/src/ink/screens/setup/types.ts +0 -65
  53. package/src/ink/screens/sync-screen.tsx +0 -283
  54. package/src/process.ts +0 -251
  55. package/src/program.ts +0 -2105
  56. package/src/runtime.ts +0 -147
  57. package/src/types.ts +0 -165
  58. package/src/ui.ts +0 -295
  59. package/src/version.ts +0 -3
@@ -1,612 +0,0 @@
1
- /** @jsxImportSource react */
2
- import React, { useEffect, useMemo, useRef, useState } from 'react'
3
- import { useInput } from 'ink'
4
- import { ENVIRONMENT_PRESET_OPTIONS, resolveEnvironmentConfigForPreset } from '../../../config.ts'
5
- import {
6
- inferSshPrivateKeyPath,
7
- loadSshPublicKey,
8
- validateSshPrivateKeyPath,
9
- validateSshPublicKeyPath,
10
- } from '../../../forgejo.ts'
11
- import type { TelaCliAuthState, TelaCliForgejoOrganization } from '../../../types.ts'
12
- import { StepFrame } from './step-frame.tsx'
13
- import type { BreadcrumbEntry } from './breadcrumb.tsx'
14
- import {
15
- getVisibleEditSteps,
16
- summarizeStep,
17
- type SetupStepDescriptor,
18
- type SetupStepId,
19
- } from './steps.ts'
20
- import { DoneStep } from './steps/done-step.tsx'
21
- import { EnvironmentStep } from './steps/environment-step.tsx'
22
- import { OrganizationStep } from './steps/organization-step.tsx'
23
- import { ReviewStep } from './steps/review-step.tsx'
24
- import { RunningStep } from './steps/running-step.tsx'
25
- import { SshKeyStep, buildSshKeyOptions } from './steps/ssh-key-step.tsx'
26
- import { TextFieldStep } from './steps/text-field-step.tsx'
27
- import {
28
- CUSTOM_SSH_KEY_OPTION,
29
- type SetupFormValues,
30
- type SetupScreenProps,
31
- type SetupScreenResult,
32
- } from './types.ts'
33
-
34
- export type { SetupScreenProps, SetupScreenResult } from './types.ts'
35
-
36
- type SetupPhase =
37
- | 'editing'
38
- | 'review'
39
- | 'authenticating'
40
- | 'selectingOrganization'
41
- | 'provisioning'
42
- | 'done'
43
-
44
- type TextStepId = Exclude<SetupStepId, 'environment' | 'sshKey'>
45
-
46
- function pushProgressLines(lines: string[], message: string): string[] {
47
- const nextLines = message
48
- .split('\n')
49
- .map(line => line.trim())
50
- .filter(Boolean)
51
-
52
- if (nextLines.length === 0) {
53
- return lines
54
- }
55
-
56
- return [...lines, ...nextLines].slice(-12)
57
- }
58
-
59
- export function SetupScreen(props: SetupScreenProps): React.ReactElement {
60
- const [phase, setPhase] = useState<SetupPhase>('editing')
61
- const [stepIndex, setStepIndex] = useState(0)
62
- const [values, setValues] = useState<SetupFormValues>({
63
- environment: props.defaults.environment,
64
- agentApiUrl: props.defaults.agentApiUrl,
65
- authApiUrl: props.defaults.authApiUrl,
66
- authDashboardUrl: props.defaults.authDashboardUrl,
67
- telaApiUrl: props.defaults.telaApiUrl,
68
- requesterApplicationId: props.defaults.requesterApplicationId,
69
- targetApplicationId: props.defaults.targetApplicationId,
70
- cloneRoot: props.defaults.cloneRoot,
71
- sshKeySelection: props.sshPublicKeys[0]?.path ?? CUSTOM_SSH_KEY_OPTION,
72
- sshKeyPath: '',
73
- sshPrivateKeyPath: props.sshPublicKeys[0]
74
- ? inferSshPrivateKeyPath(props.sshPublicKeys[0].path)
75
- : '',
76
- })
77
- const [errors, setErrors] = useState<Partial<Record<SetupStepId, string>>>({})
78
- const [createCloneRoot, setCreateCloneRoot] = useState(true)
79
- const [progressLines, setProgressLines] = useState<string[]>([])
80
- const [verificationUrl, setVerificationUrl] = useState<string | null>(null)
81
- const [userCode, setUserCode] = useState<string | null>(null)
82
- const [runningStage, setRunningStage] = useState<'auth' | 'provision'>('auth')
83
- const [authenticated, setAuthenticated] = useState<TelaCliAuthState | null>(null)
84
- const [organizationOptions, setOrganizationOptions] = useState<TelaCliForgejoOrganization[]>([])
85
- const [organizationIndex, setOrganizationIndex] = useState(0)
86
- const [preferredOrganizationId, setPreferredOrganizationId] = useState<string | undefined>(undefined)
87
- const [selectedOrganization, setSelectedOrganization] = useState<TelaCliForgejoOrganization | null>(null)
88
- const [result, setResult] = useState<SetupScreenResult | null>(null)
89
- const authStartedRef = useRef(false)
90
- const provisionStartedRef = useRef(false)
91
- const previousSuggestedPrivateKeyPathRef = useRef(values.sshPrivateKeyPath)
92
-
93
- const visibleSteps = useMemo(() => getVisibleEditSteps(values), [values])
94
- const safeStepIndex = Math.min(stepIndex, Math.max(visibleSteps.length - 1, 0))
95
- const currentStep: SetupStepDescriptor | undefined = visibleSteps[safeStepIndex]
96
-
97
- const resolvedConfig = useMemo(() => {
98
- try {
99
- return resolveEnvironmentConfigForPreset(values.environment, values)
100
- }
101
- catch {
102
- return {
103
- environment: values.environment,
104
- agentApiUrl: values.agentApiUrl,
105
- authApiUrl: values.authApiUrl,
106
- authDashboardUrl: values.authDashboardUrl,
107
- telaApiUrl: values.telaApiUrl,
108
- requesterApplicationId: values.requesterApplicationId,
109
- targetApplicationId: values.targetApplicationId,
110
- }
111
- }
112
- }, [values])
113
-
114
- const sshKeyOptions = useMemo(() => buildSshKeyOptions(props.sshPublicKeys), [props.sshPublicKeys])
115
- const selectedSshKey = useMemo(() => {
116
- if (values.sshKeySelection === CUSTOM_SSH_KEY_OPTION) {
117
- try {
118
- return values.sshKeyPath.trim() ? loadSshPublicKey(values.sshKeyPath) : undefined
119
- }
120
- catch {
121
- return undefined
122
- }
123
- }
124
-
125
- return props.sshPublicKeys.find(key => key.path === values.sshKeySelection)
126
- }, [props.sshPublicKeys, values.sshKeyPath, values.sshKeySelection])
127
- const suggestedPrivateKeyPath = useMemo(
128
- () => selectedSshKey ? inferSshPrivateKeyPath(selectedSshKey.path) : '',
129
- [selectedSshKey],
130
- )
131
- const cloneRootState = useMemo(() => props.inspectCloneRoot(values.cloneRoot), [props, values.cloneRoot])
132
-
133
- const breadcrumb = useMemo<BreadcrumbEntry[]>(() => {
134
- const entries: BreadcrumbEntry[] = []
135
- const answered = visibleSteps.slice(0, safeStepIndex)
136
- for (const step of answered) {
137
- entries.push({
138
- label: step.label,
139
- value: summarizeStep(step, values, selectedSshKey?.title),
140
- })
141
- }
142
-
143
- return entries
144
- }, [safeStepIndex, selectedSshKey, values, visibleSteps])
145
-
146
- const reviewResolved = Boolean(authenticated && selectedOrganization)
147
-
148
- function resetResolvedSetup(): void {
149
- setAuthenticated(null)
150
- setOrganizationOptions([])
151
- setOrganizationIndex(0)
152
- setPreferredOrganizationId(undefined)
153
- setSelectedOrganization(null)
154
- setProgressLines([])
155
- setVerificationUrl(null)
156
- setUserCode(null)
157
- setRunningStage('auth')
158
- }
159
-
160
- useEffect(() => {
161
- if (phase !== 'authenticating') {
162
- authStartedRef.current = false
163
- }
164
-
165
- if (phase !== 'provisioning') {
166
- provisionStartedRef.current = false
167
- }
168
- }, [phase])
169
-
170
- useEffect(() => {
171
- if (phase !== 'authenticating' || authStartedRef.current) {
172
- return
173
- }
174
-
175
- authStartedRef.current = true
176
- resetResolvedSetup()
177
- setRunningStage('auth')
178
- setProgressLines(['Starting Tela sign-in...'])
179
-
180
- void props.authenticate({
181
- ...resolvedConfig,
182
- cloneRoot: values.cloneRoot,
183
- }, (event) => {
184
- if (event.type === 'user_code') {
185
- setVerificationUrl(event.verificationUrl ?? null)
186
- setUserCode(event.userCode ?? null)
187
- }
188
- setProgressLines(current => pushProgressLines(current, event.message))
189
- })
190
- .then(async (auth) => {
191
- setAuthenticated(auth)
192
- setVerificationUrl(null)
193
- setUserCode(null)
194
- setProgressLines(current => pushProgressLines(
195
- current,
196
- `Signed in as ${auth.user.email} in ${auth.workspace.title}.`,
197
- ))
198
- setProgressLines(current => pushProgressLines(current, 'Loading workspace organizations...'))
199
-
200
- const organizationResolution = await props.resolveOrganizations({
201
- ...resolvedConfig,
202
- cloneRoot: values.cloneRoot,
203
- auth,
204
- })
205
-
206
- setOrganizationOptions(organizationResolution.organizations)
207
- setPreferredOrganizationId(organizationResolution.preferredOrganization?.id)
208
-
209
- if (organizationResolution.organizations.length === 1) {
210
- const organization = organizationResolution.organizations[0]!
211
- setSelectedOrganization(organization)
212
- setProgressLines(current => pushProgressLines(
213
- current,
214
- `Using workspace organization ${organization.name}.`,
215
- ))
216
- setPhase('review')
217
- return
218
- }
219
-
220
- const preferredIndex = organizationResolution.organizations.findIndex(
221
- organization => organization.id === organizationResolution.preferredOrganization?.id,
222
- )
223
- setOrganizationIndex(Math.max(preferredIndex, 0))
224
- setPhase('selectingOrganization')
225
- })
226
- .catch((error) => {
227
- props.controller.reject(error)
228
- })
229
- }, [phase, props, resolvedConfig, values.cloneRoot])
230
-
231
- useEffect(() => {
232
- if (phase !== 'provisioning' || provisionStartedRef.current) {
233
- return
234
- }
235
-
236
- provisionStartedRef.current = true
237
- setRunningStage('provision')
238
- setVerificationUrl(null)
239
- setUserCode(null)
240
-
241
- if (!selectedSshKey) {
242
- props.controller.reject(new Error('SSH public key is required.'))
243
- return
244
- }
245
-
246
- if (!authenticated || !selectedOrganization) {
247
- props.controller.reject(new Error('Authenticated organization selection is required.'))
248
- return
249
- }
250
-
251
- setProgressLines(current => pushProgressLines(
252
- current,
253
- `Provisioning Forgejo access for ${selectedOrganization.name}.`,
254
- ))
255
-
256
- void props.execute({
257
- ...resolvedConfig,
258
- cloneRoot: values.cloneRoot,
259
- createCloneRoot,
260
- sshKey: selectedSshKey,
261
- sshPrivateKeyPath: values.sshPrivateKeyPath,
262
- auth: authenticated,
263
- organization: selectedOrganization,
264
- }, (event) => {
265
- setProgressLines(current => pushProgressLines(current, event.message))
266
- })
267
- .then((nextResult) => {
268
- setResult(nextResult)
269
- setPhase('done')
270
- })
271
- .catch((error) => {
272
- props.controller.reject(error)
273
- })
274
- }, [
275
- authenticated,
276
- createCloneRoot,
277
- phase,
278
- props,
279
- resolvedConfig,
280
- selectedOrganization,
281
- selectedSshKey,
282
- values.sshPrivateKeyPath,
283
- values.cloneRoot,
284
- ])
285
-
286
- useEffect(() => {
287
- if (phase === 'done' && result) {
288
- props.controller.resolve(result, 80)
289
- }
290
- }, [phase, props, result])
291
-
292
- useEffect(() => {
293
- setValues((current) => {
294
- const previousSuggested = previousSuggestedPrivateKeyPathRef.current
295
- previousSuggestedPrivateKeyPathRef.current = suggestedPrivateKeyPath
296
-
297
- if (
298
- current.sshPrivateKeyPath
299
- && current.sshPrivateKeyPath !== previousSuggested
300
- ) {
301
- return current
302
- }
303
-
304
- if (current.sshPrivateKeyPath === suggestedPrivateKeyPath) {
305
- return current
306
- }
307
-
308
- return {
309
- ...current,
310
- sshPrivateKeyPath: suggestedPrivateKeyPath,
311
- }
312
- })
313
- }, [suggestedPrivateKeyPath])
314
-
315
- useInput((input, key) => {
316
- if (phase === 'authenticating' || phase === 'provisioning' || phase === 'done') {
317
- return
318
- }
319
-
320
- if (phase === 'selectingOrganization') {
321
- if (key.escape || key.leftArrow) {
322
- resetResolvedSetup()
323
- setPhase('review')
324
- return
325
- }
326
-
327
- if (key.upArrow || key.downArrow) {
328
- const direction = key.upArrow ? -1 : 1
329
- setOrganizationIndex(current => {
330
- if (organizationOptions.length === 0) {
331
- return current
332
- }
333
-
334
- return (organizationOptions.length + current + direction) % organizationOptions.length
335
- })
336
- return
337
- }
338
-
339
- if (key.return) {
340
- const organization = organizationOptions[organizationIndex]
341
- if (!organization) {
342
- props.controller.reject(new Error('Organization selection is required.'))
343
- return
344
- }
345
-
346
- setSelectedOrganization(organization)
347
- setProgressLines(current => pushProgressLines(
348
- current,
349
- `Selected workspace organization ${organization.name}.`,
350
- ))
351
- setPhase('review')
352
- }
353
-
354
- return
355
- }
356
-
357
- if (phase === 'review') {
358
- if (key.escape || key.leftArrow) {
359
- if (reviewResolved) {
360
- if (organizationOptions.length > 1) {
361
- setSelectedOrganization(null)
362
- setPhase('selectingOrganization')
363
- return
364
- }
365
-
366
- resetResolvedSetup()
367
- return
368
- }
369
-
370
- setPhase('editing')
371
- setStepIndex(Math.max(visibleSteps.length - 1, 0))
372
- return
373
- }
374
-
375
- if (!cloneRootState.exists && (input === ' ' || key.rightArrow)) {
376
- setCreateCloneRoot(current => !current)
377
- return
378
- }
379
-
380
- if (key.return) {
381
- setPhase(reviewResolved ? 'provisioning' : 'authenticating')
382
- }
383
-
384
- return
385
- }
386
-
387
- if (!currentStep) {
388
- return
389
- }
390
-
391
- if (key.escape || key.leftArrow) {
392
- if (safeStepIndex === 0) {
393
- props.controller.reject(new Error('Setup cancelled.'))
394
- return
395
- }
396
-
397
- setErrors(current => ({ ...current, [currentStep.id]: undefined }))
398
- setStepIndex(current => Math.max(current - 1, 0))
399
- return
400
- }
401
-
402
- if (currentStep.kind === 'select-environment' && (key.upArrow || key.downArrow)) {
403
- const direction = key.upArrow ? -1 : 1
404
- setValues((current) => {
405
- const currentIdx = ENVIRONMENT_PRESET_OPTIONS.findIndex(option => option.value === current.environment)
406
- const nextIdx = (ENVIRONMENT_PRESET_OPTIONS.length + currentIdx + direction) % ENVIRONMENT_PRESET_OPTIONS.length
407
- return {
408
- ...current,
409
- environment: ENVIRONMENT_PRESET_OPTIONS[nextIdx]?.value ?? current.environment,
410
- }
411
- })
412
- return
413
- }
414
-
415
- if (currentStep.kind === 'select-ssh-key' && (key.upArrow || key.downArrow)) {
416
- const direction = key.upArrow ? -1 : 1
417
- setValues((current) => {
418
- const currentIdx = sshKeyOptions.findIndex(option => option.key === current.sshKeySelection)
419
- const nextIdx = (sshKeyOptions.length + currentIdx + direction) % sshKeyOptions.length
420
- return {
421
- ...current,
422
- sshKeySelection: sshKeyOptions[nextIdx]?.key ?? current.sshKeySelection,
423
- }
424
- })
425
- return
426
- }
427
-
428
- if (currentStep.kind === 'text' && (key.backspace || key.delete)) {
429
- const fieldKey = currentStep.id as TextStepId
430
- setValues(current => ({
431
- ...current,
432
- [fieldKey]: current[fieldKey].slice(0, -1),
433
- }))
434
- setErrors(current => ({ ...current, [currentStep.id]: undefined }))
435
- return
436
- }
437
-
438
- if (key.return) {
439
- const validationError = validateStep(currentStep, values, props, selectedSshKey)
440
- if (validationError) {
441
- setErrors(current => ({ ...current, [currentStep.id]: validationError }))
442
- return
443
- }
444
-
445
- const nextIndex = safeStepIndex + 1
446
- const nextVisible = getVisibleEditSteps(values)
447
- if (nextIndex >= nextVisible.length) {
448
- setPhase('review')
449
- return
450
- }
451
-
452
- setStepIndex(nextIndex)
453
- return
454
- }
455
-
456
- if (currentStep.kind === 'text' && input) {
457
- const fieldKey = currentStep.id as TextStepId
458
- setValues(current => ({
459
- ...current,
460
- [fieldKey]: `${current[fieldKey]}${input}`,
461
- }))
462
- setErrors(current => ({ ...current, [currentStep.id]: undefined }))
463
- }
464
- })
465
-
466
- if (phase === 'authenticating' || phase === 'provisioning') {
467
- return (
468
- <RunningStep
469
- stage={runningStage}
470
- organizationName={selectedOrganization?.name}
471
- verificationUrl={verificationUrl}
472
- userCode={userCode}
473
- progressLines={progressLines}
474
- />
475
- )
476
- }
477
-
478
- if (phase === 'done' && result) {
479
- return <DoneStep result={result} />
480
- }
481
-
482
- if (phase === 'selectingOrganization' && authenticated) {
483
- return (
484
- <OrganizationStep
485
- auth={authenticated}
486
- organizations={organizationOptions}
487
- currentIndex={organizationIndex}
488
- preferredOrganizationId={preferredOrganizationId}
489
- />
490
- )
491
- }
492
-
493
- if (phase === 'review') {
494
- return (
495
- <ReviewStep
496
- values={values}
497
- resolvedConfig={resolvedConfig}
498
- auth={authenticated}
499
- selectedOrganization={selectedOrganization}
500
- selectedSshKey={selectedSshKey}
501
- cloneRootState={cloneRootState}
502
- createCloneRoot={createCloneRoot}
503
- />
504
- )
505
- }
506
-
507
- if (!currentStep) {
508
- return (
509
- <StepFrame
510
- stepNumber={1}
511
- totalSteps={1}
512
- stepLabel="Setup"
513
- question="Preparing setup…"
514
- breadcrumb={[]}
515
- footer="Esc cancel"
516
- >
517
- <></>
518
- </StepFrame>
519
- )
520
- }
521
-
522
- const footer = buildFooter(currentStep, safeStepIndex === 0)
523
- const error = errors[currentStep.id]
524
-
525
- return (
526
- <StepFrame
527
- stepNumber={safeStepIndex + 1}
528
- totalSteps={visibleSteps.length}
529
- stepLabel={currentStep.label}
530
- question={currentStep.question}
531
- breadcrumb={breadcrumb}
532
- footer={footer}
533
- >
534
- {renderStepBody(currentStep, values, error, sshKeyOptions, props.sshPublicKeys.length > 0)}
535
- </StepFrame>
536
- )
537
- }
538
-
539
- function renderStepBody(
540
- step: SetupStepDescriptor,
541
- values: SetupFormValues,
542
- error: string | undefined,
543
- sshKeyOptions: ReturnType<typeof buildSshKeyOptions>,
544
- hasDiscoveredKeys: boolean,
545
- ): React.ReactElement {
546
- if (step.kind === 'select-environment') {
547
- return <EnvironmentStep values={values} />
548
- }
549
-
550
- if (step.kind === 'select-ssh-key') {
551
- return (
552
- <SshKeyStep
553
- options={sshKeyOptions}
554
- selection={values.sshKeySelection}
555
- hasDiscoveredKeys={hasDiscoveredKeys}
556
- />
557
- )
558
- }
559
-
560
- const fieldKey = step.id as TextStepId
561
- return (
562
- <TextFieldStep
563
- value={values[fieldKey]}
564
- placeholder={step.placeholder}
565
- error={error}
566
- />
567
- )
568
- }
569
-
570
- function buildFooter(step: SetupStepDescriptor, isFirstStep: boolean): string {
571
- const back = isFirstStep ? 'Esc cancel' : 'Esc back'
572
- switch (step.kind) {
573
- case 'select-environment':
574
- return `↑/↓ choose · Enter continue · ${back}`
575
- case 'select-ssh-key':
576
- return `↑/↓ choose · Enter continue · ${back}`
577
- case 'text':
578
- return `Type to edit · Enter continue · ${back}`
579
- }
580
- }
581
-
582
- function validateStep(
583
- step: SetupStepDescriptor,
584
- values: SetupFormValues,
585
- props: SetupScreenProps,
586
- selectedSshKey: ReturnType<typeof loadSshPublicKey> | undefined,
587
- ): string | undefined {
588
- switch (step.id) {
589
- case 'environment':
590
- return undefined
591
- case 'agentApiUrl':
592
- return props.validateAgentApiUrl(values.agentApiUrl)
593
- case 'authApiUrl':
594
- return props.validateAuthApiUrl(values.authApiUrl)
595
- case 'authDashboardUrl':
596
- return props.validateAuthDashboardUrl(values.authDashboardUrl)
597
- case 'telaApiUrl':
598
- return props.validateTelaApiUrl(values.telaApiUrl)
599
- case 'requesterApplicationId':
600
- return props.validateApplicationId(values.requesterApplicationId, 'Requester application ID')
601
- case 'targetApplicationId':
602
- return props.validateApplicationId(values.targetApplicationId, 'Target application ID')
603
- case 'cloneRoot':
604
- return props.validateCloneRoot(values.cloneRoot)
605
- case 'sshKey':
606
- return selectedSshKey ? undefined : 'SSH public key is required'
607
- case 'sshKeyPath':
608
- return validateSshPublicKeyPath(values.sshKeyPath)
609
- case 'sshPrivateKeyPath':
610
- return validateSshPrivateKeyPath(values.sshPrivateKeyPath)
611
- }
612
- }
@@ -1,31 +0,0 @@
1
- /** @jsxImportSource react */
2
- import React, { type ReactNode } from 'react'
3
- import { AppFrame, Section } from '../../components.tsx'
4
- import { Breadcrumb, type BreadcrumbEntry } from './breadcrumb.tsx'
5
-
6
- export interface StepFrameProps {
7
- stepNumber: number
8
- totalSteps: number
9
- stepLabel: string
10
- question: string
11
- breadcrumb: BreadcrumbEntry[]
12
- footer?: string
13
- status?: string
14
- children: ReactNode
15
- }
16
-
17
- export function StepFrame(props: StepFrameProps): React.ReactElement {
18
- return (
19
- <AppFrame
20
- title="Setup"
21
- subtitle={`Step ${props.stepNumber} of ${props.totalSteps} — ${props.stepLabel}`}
22
- footer={props.footer}
23
- status={props.status}
24
- >
25
- <Breadcrumb entries={props.breadcrumb} />
26
- <Section title={props.question}>
27
- {props.children}
28
- </Section>
29
- </AppFrame>
30
- )
31
- }
@@ -1,29 +0,0 @@
1
- /** @jsxImportSource react */
2
- import React from 'react'
3
- import { Text } from 'ink'
4
- import { AppFrame, Section } from '../../../components.tsx'
5
- import type { SetupScreenResult } from '../types.ts'
6
-
7
- export function DoneStep(props: { result: SetupScreenResult }): React.ReactElement {
8
- return (
9
- <AppFrame
10
- title="Setup"
11
- subtitle="Setup complete."
12
- >
13
- <Section title="Authenticated">
14
- <Text>User: {props.result.config.auth?.user.email ?? '<missing>'}</Text>
15
- <Text>Workspace: {props.result.config.auth?.workspace.title ?? '<missing>'}</Text>
16
- <Text>Organization: {props.result.config.forgejoOrganization?.name ?? '<missing>'}</Text>
17
- <Text>Clone root: {props.result.config.cloneRoot}</Text>
18
- <Text>Forgejo user: {props.result.config.forgejoUserRegistered ? 'registered' : 'pending'}</Text>
19
- </Section>
20
- <Section title="Checks">
21
- {props.result.checks.map(check => (
22
- <Text key={check.label}>
23
- {check.label}: {check.status} — {check.detail}
24
- </Text>
25
- ))}
26
- </Section>
27
- </AppFrame>
28
- )
29
- }
@@ -1,23 +0,0 @@
1
- /** @jsxImportSource react */
2
- import React from 'react'
3
- import { ENVIRONMENT_PRESET_OPTIONS } from '../../../../config.ts'
4
- import { SelectList } from '../../../components.tsx'
5
- import type { SetupFormValues } from '../types.ts'
6
-
7
- export function EnvironmentStep(props: { values: SetupFormValues }): React.ReactElement {
8
- const currentIndex = Math.max(
9
- ENVIRONMENT_PRESET_OPTIONS.findIndex(option => option.value === props.values.environment),
10
- 0,
11
- )
12
-
13
- return (
14
- <SelectList
15
- items={ENVIRONMENT_PRESET_OPTIONS.map(option => ({
16
- key: option.value,
17
- label: option.label,
18
- hint: option.hint,
19
- }))}
20
- currentIndex={currentIndex}
21
- />
22
- )
23
- }