@meistrari/tela-cli 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/package.json +1 -1
- package/src/commands/metadata.ts +0 -1
- package/src/config.ts +1 -1
- package/src/ink/components.tsx +20 -18
- package/src/program.ts +60 -46
- package/src/ui.ts +2 -4
package/README.md
CHANGED
|
@@ -95,7 +95,6 @@ Examples:
|
|
|
95
95
|
|
|
96
96
|
- Human output is structured for terminal use with grouped summaries and next actions.
|
|
97
97
|
- `--json` is available on read-heavy flows and on `tela run` for the final execution envelope.
|
|
98
|
-
- `--silent-bark` disables bark audio during the interactive `tela setup` intro while keeping the visual intro.
|
|
99
98
|
|
|
100
99
|
## First run
|
|
101
100
|
|
package/package.json
CHANGED
package/src/commands/metadata.ts
CHANGED
|
@@ -204,7 +204,6 @@ export function renderReadmeMarkdown(): string {
|
|
|
204
204
|
lines.push('')
|
|
205
205
|
lines.push('- Human output is structured for terminal use with grouped summaries and next actions.')
|
|
206
206
|
lines.push('- `--json` is available on read-heavy flows and on `tela run` for the final execution envelope.')
|
|
207
|
-
lines.push('- `--silent-bark` disables bark audio during the interactive `tela setup` intro while keeping the visual intro.')
|
|
208
207
|
lines.push('')
|
|
209
208
|
lines.push('## First run')
|
|
210
209
|
lines.push('')
|
package/src/config.ts
CHANGED
|
@@ -45,7 +45,7 @@ export interface SetupEnvironmentConfig {
|
|
|
45
45
|
|
|
46
46
|
export const ENVIRONMENT_PRESETS: Record<Exclude<TelaEnvironment, 'custom'>, Omit<SetupEnvironmentConfig, 'environment'>> = {
|
|
47
47
|
production: {
|
|
48
|
-
agentApiUrl: 'https://agent-api.
|
|
48
|
+
agentApiUrl: 'https://agent-api-production-81c9.up.railway.app',
|
|
49
49
|
authApiUrl: 'https://auth.tela.com',
|
|
50
50
|
authDashboardUrl: 'https://accounts.tela.com',
|
|
51
51
|
telaApiUrl: 'https://api.tela.com',
|
package/src/ink/components.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useState, type ReactNode } from 'react'
|
|
2
2
|
import { Box, Text } from 'ink'
|
|
3
|
-
import {
|
|
3
|
+
import { getTelaAsciiHeader } from '../ui.ts'
|
|
4
4
|
|
|
5
5
|
export interface AppFrameProps {
|
|
6
6
|
title: string
|
|
@@ -12,7 +12,7 @@ export interface AppFrameProps {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function AppFrame(props: AppFrameProps): React.ReactElement {
|
|
15
|
-
const mascot =
|
|
15
|
+
const mascot = props.mascotRows
|
|
16
16
|
const header = useMemo(() => getTelaAsciiHeader(), [])
|
|
17
17
|
|
|
18
18
|
return (
|
|
@@ -29,22 +29,24 @@ export function AppFrame(props: AppFrameProps): React.ReactElement {
|
|
|
29
29
|
{props.subtitle ? <Text dimColor>{props.subtitle}</Text> : null}
|
|
30
30
|
{props.status ? <Text color="yellow">{props.status}</Text> : null}
|
|
31
31
|
</Box>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
{row
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
32
|
+
{mascot ? (
|
|
33
|
+
<Box flexDirection="column" marginTop={1}>
|
|
34
|
+
{mascot.map((row, index) => (
|
|
35
|
+
<Box key={`mascot-${index}`} flexDirection="row">
|
|
36
|
+
{row.split('').map((cell, cellIndex) => {
|
|
37
|
+
const level = Number.parseInt(cell, 16)
|
|
38
|
+
const channel = Math.round((level / 15) * 255)
|
|
39
|
+
const colorValue = `#${channel.toString(16).padStart(2, '0').repeat(3)}`
|
|
40
|
+
return (
|
|
41
|
+
<Text key={`pixel-${index}-${cellIndex}`} backgroundColor={colorValue}>
|
|
42
|
+
{' '}
|
|
43
|
+
</Text>
|
|
44
|
+
)
|
|
45
|
+
})}
|
|
46
|
+
</Box>
|
|
47
|
+
))}
|
|
48
|
+
</Box>
|
|
49
|
+
) : null}
|
|
48
50
|
<Box flexDirection="column" marginTop={1}>
|
|
49
51
|
{props.children}
|
|
50
52
|
</Box>
|
package/src/program.ts
CHANGED
|
@@ -2,11 +2,6 @@ import { existsSync, mkdirSync, statSync } from 'node:fs'
|
|
|
2
2
|
import { basename, join } from 'node:path'
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import { Command } from 'commander'
|
|
5
|
-
import {
|
|
6
|
-
createInkBarkSession,
|
|
7
|
-
shouldShowBarkIntro,
|
|
8
|
-
type BarkIntroSession,
|
|
9
|
-
} from './ink/bark.tsx'
|
|
10
5
|
import {
|
|
11
6
|
FeedbackClaudeHandoffScreen,
|
|
12
7
|
FeedbackOutcomeScreen,
|
|
@@ -19,11 +14,6 @@ import { SyncScreen, type SyncProgressItem } from './ink/screens/sync-screen.tsx
|
|
|
19
14
|
import { renderCommandScreen } from './ink/runtime.tsx'
|
|
20
15
|
import { listOrganizations } from './agent-api.ts'
|
|
21
16
|
import { authenticateWithDeviceFlow, type SetupAuthEvent } from './auth.ts'
|
|
22
|
-
import {
|
|
23
|
-
checkAgentApiReachability,
|
|
24
|
-
getAgentApiOriginCheckStatus,
|
|
25
|
-
getAgentApiOriginWarning,
|
|
26
|
-
} from './diagnostics.ts'
|
|
27
17
|
import { createUserFacingError } from './errors.ts'
|
|
28
18
|
import {
|
|
29
19
|
getCommandMetadata,
|
|
@@ -144,7 +134,6 @@ interface CliDeps {
|
|
|
144
134
|
getDiffStatAgainstHead?: typeof getDiffStatAgainstHead
|
|
145
135
|
getStatusReport?: typeof getStatusReport
|
|
146
136
|
getDoctorReport?: typeof getDoctorReport
|
|
147
|
-
createInkBarkSession?: typeof createInkBarkSession
|
|
148
137
|
renderCommandScreen?: typeof renderCommandScreen
|
|
149
138
|
commandExists?: typeof commandExists
|
|
150
139
|
runInteractiveCommand?: typeof runInteractiveCommand
|
|
@@ -159,7 +148,6 @@ interface CliDeps {
|
|
|
159
148
|
interface GlobalCliOptions {
|
|
160
149
|
json?: boolean
|
|
161
150
|
verbose?: boolean
|
|
162
|
-
silentBark?: boolean
|
|
163
151
|
}
|
|
164
152
|
|
|
165
153
|
interface SyncCommandOptions extends GlobalCliOptions {
|
|
@@ -292,7 +280,6 @@ function renderRootHelp(program: Command): string {
|
|
|
292
280
|
section('Global flags', table(
|
|
293
281
|
['Flag', 'Description'],
|
|
294
282
|
[
|
|
295
|
-
['--silent-bark', 'Disable bark audio during the interactive `tela setup` intro'],
|
|
296
283
|
['--verbose', 'Include raw evidence for failures where available'],
|
|
297
284
|
['-h, --help', 'Show command help'],
|
|
298
285
|
],
|
|
@@ -343,25 +330,6 @@ function installCustomHelp(program: Command): void {
|
|
|
343
330
|
})
|
|
344
331
|
}
|
|
345
332
|
|
|
346
|
-
function createBarkSession(
|
|
347
|
-
deps: CliDeps,
|
|
348
|
-
options: GlobalCliOptions,
|
|
349
|
-
commandTitle: string,
|
|
350
|
-
): BarkIntroSession {
|
|
351
|
-
const createSession = deps.createInkBarkSession ?? createInkBarkSession
|
|
352
|
-
return createSession({
|
|
353
|
-
commandTitle,
|
|
354
|
-
enabled: shouldShowBarkIntro({
|
|
355
|
-
json: options.json,
|
|
356
|
-
stdinIsTTY: getStdinIsTTY(deps),
|
|
357
|
-
stdoutIsTTY: getStdoutIsTTY(deps),
|
|
358
|
-
}),
|
|
359
|
-
silentBark: options.silentBark,
|
|
360
|
-
env: process.env,
|
|
361
|
-
platform: process.platform,
|
|
362
|
-
})
|
|
363
|
-
}
|
|
364
|
-
|
|
365
333
|
function emitBootstrap(runtime: CommandRuntime, title: string, summary: string): void {
|
|
366
334
|
runtime.emit(bootstrapPane(title, summary, { decorate: runtime.decorate }))
|
|
367
335
|
}
|
|
@@ -480,17 +448,15 @@ async function executeSetupFlow(
|
|
|
480
448
|
mkdirSync(config.cloneRoot, { recursive: true, mode: 0o755 })
|
|
481
449
|
}
|
|
482
450
|
|
|
483
|
-
const [gitAvailable, claudeAvailable
|
|
451
|
+
const [gitAvailable, claudeAvailable] = await Promise.all([
|
|
484
452
|
commandExistsFn('git'),
|
|
485
453
|
commandExistsFn('claude'),
|
|
486
|
-
checkAgentApiReachability(config.agentApiUrl, fetchFn),
|
|
487
454
|
])
|
|
488
455
|
|
|
489
456
|
const warnings = [
|
|
490
457
|
!existsSync(config.cloneRoot) ? `Clone root does not exist yet: ${config.cloneRoot}` : undefined,
|
|
491
458
|
gitAvailable ? undefined : '`git` is not available on PATH.',
|
|
492
459
|
claudeAvailable ? undefined : '`claude` is not available on PATH.',
|
|
493
|
-
getAgentApiOriginWarning(reachability),
|
|
494
460
|
].filter((warning): warning is string => Boolean(warning))
|
|
495
461
|
const checks = [
|
|
496
462
|
{ label: 'auth', status: 'authenticated', detail: `${input.auth.user.email} @ ${input.auth.workspace.title}` },
|
|
@@ -499,7 +465,7 @@ async function executeSetupFlow(
|
|
|
499
465
|
{ label: 'clone-root', status: existsSync(config.cloneRoot) ? 'ready' : 'missing', detail: config.cloneRoot },
|
|
500
466
|
{ label: 'git', status: gitAvailable ? 'available' : 'missing', detail: gitAvailable ? 'ready' : 'install git' },
|
|
501
467
|
{ label: 'claude', status: claudeAvailable ? 'available' : 'missing', detail: claudeAvailable ? 'ready' : 'install Claude CLI' },
|
|
502
|
-
{ label: 'agent-api-origin', status:
|
|
468
|
+
{ label: 'agent-api-origin', status: 'verified', detail: config.agentApiUrl },
|
|
503
469
|
]
|
|
504
470
|
|
|
505
471
|
return {
|
|
@@ -532,8 +498,6 @@ function createMissingSetupOrganizationsError(workspaceTitle: string): ReturnTyp
|
|
|
532
498
|
|
|
533
499
|
async function runSetupInk(
|
|
534
500
|
deps: CliDeps = {},
|
|
535
|
-
options: GlobalCliOptions = {},
|
|
536
|
-
barkSession = createBarkSession(deps, options, 'Setup'),
|
|
537
501
|
): Promise<SetupScreenResult> {
|
|
538
502
|
const renderScreen = getRenderCommandScreen(deps)
|
|
539
503
|
const inspection = (deps.inspectSavedConfig ?? inspectSavedConfig)()
|
|
@@ -549,7 +513,6 @@ async function runSetupInk(
|
|
|
549
513
|
targetApplicationId: inspection.config?.targetApplicationId ?? '',
|
|
550
514
|
}
|
|
551
515
|
: resolveEnvironmentConfigForPreset(defaultEnvironment)
|
|
552
|
-
await barkSession.playOnce()
|
|
553
516
|
return await renderScreen<SetupScreenResult>((controller) => React.createElement(SetupScreen, {
|
|
554
517
|
controller,
|
|
555
518
|
currentConfigSummary: summarizeConfigInspection(inspection).split('\n'),
|
|
@@ -645,7 +608,7 @@ export async function runSetup(
|
|
|
645
608
|
options: GlobalCliOptions = {},
|
|
646
609
|
): Promise<SetupCommandResult> {
|
|
647
610
|
if (isInteractiveInkSession(deps, options)) {
|
|
648
|
-
return await runSetupInk(deps
|
|
611
|
+
return await runSetupInk(deps)
|
|
649
612
|
}
|
|
650
613
|
|
|
651
614
|
const prompts = getPromptModule(deps)
|
|
@@ -653,7 +616,6 @@ export async function runSetup(
|
|
|
653
616
|
const setup = deps.setupConfigInteractive ?? setupConfigInteractive
|
|
654
617
|
const inspect = deps.inspectSavedConfig ?? inspectSavedConfig
|
|
655
618
|
const commandExistsFn = deps.commandExists ?? commandExists
|
|
656
|
-
const fetchFn = deps.fetchFn ?? fetch
|
|
657
619
|
const authenticate = deps.authenticateWithDeviceFlow ?? authenticateWithDeviceFlow
|
|
658
620
|
const inspection = inspect()
|
|
659
621
|
|
|
@@ -711,17 +673,15 @@ export async function runSetup(
|
|
|
711
673
|
}
|
|
712
674
|
}
|
|
713
675
|
|
|
714
|
-
const [gitAvailable, claudeAvailable
|
|
676
|
+
const [gitAvailable, claudeAvailable] = await Promise.all([
|
|
715
677
|
commandExistsFn('git'),
|
|
716
678
|
commandExistsFn('claude'),
|
|
717
|
-
checkAgentApiReachability(config.agentApiUrl, fetchFn),
|
|
718
679
|
])
|
|
719
680
|
|
|
720
681
|
const warnings = [
|
|
721
682
|
cloneRootWarning,
|
|
722
683
|
gitAvailable ? undefined : '`git` is not available on PATH.',
|
|
723
684
|
claudeAvailable ? undefined : '`claude` is not available on PATH.',
|
|
724
|
-
getAgentApiOriginWarning(reachability),
|
|
725
685
|
].filter((warning): warning is string => Boolean(warning))
|
|
726
686
|
|
|
727
687
|
const nextSetupActions = [
|
|
@@ -757,7 +717,7 @@ export async function runSetup(
|
|
|
757
717
|
{ label: 'clone-root', status: cloneRootCreated ? 'created' : (existsSync(config.cloneRoot) ? 'ready' : 'missing'), detail: config.cloneRoot },
|
|
758
718
|
{ label: 'git', status: gitAvailable ? 'available' : 'missing', detail: gitAvailable ? 'ready' : 'install git' },
|
|
759
719
|
{ label: 'claude', status: claudeAvailable ? 'available' : 'missing', detail: claudeAvailable ? 'ready' : 'install Claude CLI' },
|
|
760
|
-
{ label: 'agent-api-origin', status:
|
|
720
|
+
{ label: 'agent-api-origin', status: 'verified', detail: config.agentApiUrl },
|
|
761
721
|
]),
|
|
762
722
|
{ decorate: runtime.decorate },
|
|
763
723
|
), { decorate: runtime.decorate }),
|
|
@@ -1889,6 +1849,53 @@ export async function runDoctor(
|
|
|
1889
1849
|
return report
|
|
1890
1850
|
}
|
|
1891
1851
|
|
|
1852
|
+
export interface ListRepositoriesResult {
|
|
1853
|
+
cloneRoot: string
|
|
1854
|
+
repositories: string[]
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
export async function runListRepositories(
|
|
1858
|
+
deps: CliDeps = {},
|
|
1859
|
+
options: GlobalCliOptions = {},
|
|
1860
|
+
): Promise<ListRepositoriesResult> {
|
|
1861
|
+
const runtime = createRuntime(deps, options)
|
|
1862
|
+
const inspection = (deps.inspectSavedConfig ?? inspectSavedConfig)()
|
|
1863
|
+
const cloneRoot = inspection.config?.cloneRoot ?? getDefaultCloneRoot()
|
|
1864
|
+
const listRepos = deps.listCloneRootRepositories ?? listCloneRootRepositories
|
|
1865
|
+
const repositories = listRepos(cloneRoot)
|
|
1866
|
+
const result: ListRepositoriesResult = { cloneRoot, repositories }
|
|
1867
|
+
|
|
1868
|
+
if (options.json) {
|
|
1869
|
+
runtime.emitJson(result)
|
|
1870
|
+
return result
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
emitBootstrap(runtime, 'Tela CLI', 'Workspace repositories under the configured clone root.')
|
|
1874
|
+
const decorate = runtime.decorate
|
|
1875
|
+
const body = repositories.length > 0
|
|
1876
|
+
? section('Repositories', bulletList(repositories), { decorate })
|
|
1877
|
+
: section('Repositories', [
|
|
1878
|
+
`No repositories found under ${cloneRoot}.`,
|
|
1879
|
+
'',
|
|
1880
|
+
'Next steps:',
|
|
1881
|
+
bulletList([
|
|
1882
|
+
'Run `tela setup` to configure the clone root.',
|
|
1883
|
+
'Run `tela sync <repo>` to clone a workspace repository.',
|
|
1884
|
+
]),
|
|
1885
|
+
], { decorate })
|
|
1886
|
+
|
|
1887
|
+
runtime.emit(joinBlocks([
|
|
1888
|
+
body,
|
|
1889
|
+
section('Clone root', cloneRoot, { decorate }),
|
|
1890
|
+
nextActions([
|
|
1891
|
+
'Run `tela sync <repo>` to clone or refresh a repository.',
|
|
1892
|
+
'Run `tela --help` to see all available commands.',
|
|
1893
|
+
], { decorate }),
|
|
1894
|
+
]))
|
|
1895
|
+
|
|
1896
|
+
return result
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1892
1899
|
function addStandardReadOptions(command: Command): Command {
|
|
1893
1900
|
return command
|
|
1894
1901
|
.option('--json', 'emit machine-readable JSON')
|
|
@@ -1899,11 +1906,18 @@ export function createProgram(deps: CliDeps = {}): Command {
|
|
|
1899
1906
|
.name('tela')
|
|
1900
1907
|
.description('Tela CLI workspace and auth helper')
|
|
1901
1908
|
.showHelpAfterError()
|
|
1902
|
-
.option('--silent-bark', 'disable bark audio during the interactive tela setup intro')
|
|
1903
1909
|
.option('--verbose', 'include raw evidence on failures')
|
|
1904
1910
|
|
|
1905
1911
|
installCustomHelp(program)
|
|
1906
1912
|
|
|
1913
|
+
addStandardReadOptions(program).action(async (commandOptions: GlobalCliOptions) => {
|
|
1914
|
+
const globalOptions = program.opts<GlobalCliOptions>()
|
|
1915
|
+
await runListRepositories(deps, {
|
|
1916
|
+
...globalOptions,
|
|
1917
|
+
...commandOptions,
|
|
1918
|
+
})
|
|
1919
|
+
})
|
|
1920
|
+
|
|
1907
1921
|
program
|
|
1908
1922
|
.command('setup')
|
|
1909
1923
|
.description('Configure Tela CLI settings and complete device-flow authentication')
|
package/src/ui.ts
CHANGED
|
@@ -38,8 +38,8 @@ const TELA_ASCII_HEADER = [
|
|
|
38
38
|
'██ ██║ ╚══██╔══╝██╔════╝██║ ██╔══██╗',
|
|
39
39
|
'██ ██║ ██║ █████╗ ██║ ███████║',
|
|
40
40
|
'██ ██║ ██║ ██╔══╝ ██║ ██╔══██║',
|
|
41
|
-
'
|
|
42
|
-
'
|
|
41
|
+
'███████████║ ██║ ███████╗███████╗██║ ██║',
|
|
42
|
+
'╚══════════╝ ╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝',
|
|
43
43
|
] as const
|
|
44
44
|
|
|
45
45
|
const ASCII_PIXEL_RAMP = ' .,:-=+*#%@'
|
|
@@ -155,8 +155,6 @@ export function bootstrapPane(
|
|
|
155
155
|
'',
|
|
156
156
|
...TELA_ASCII_HEADER.map(line => renderAsciiHeaderLine(line, options)),
|
|
157
157
|
'',
|
|
158
|
-
...BOOTSTRAP_PIXEL_ROWS.map(row => renderPixelArtLine(row, options)),
|
|
159
|
-
'',
|
|
160
158
|
...linesOf(content),
|
|
161
159
|
],
|
|
162
160
|
options,
|