@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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/tela-cli",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "tela": "cli.ts"
@@ -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.tela.com',
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',
@@ -1,6 +1,6 @@
1
1
  import React, { useEffect, useMemo, useState, type ReactNode } from 'react'
2
2
  import { Box, Text } from 'ink'
3
- import { getBootstrapPixelRows, getTelaAsciiHeader } from '../ui.ts'
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 = useMemo(() => props.mascotRows ?? getBootstrapPixelRows(), [props.mascotRows])
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
- <Box flexDirection="column" marginTop={1}>
33
- {mascot.map((row, index) => (
34
- <Box key={`mascot-${index}`} flexDirection="row">
35
- {row.split('').map((cell, cellIndex) => {
36
- const level = Number.parseInt(cell, 16)
37
- const channel = Math.round((level / 15) * 255)
38
- const colorValue = `#${channel.toString(16).padStart(2, '0').repeat(3)}`
39
- return (
40
- <Text key={`pixel-${index}-${cellIndex}`} backgroundColor={colorValue}>
41
- {' '}
42
- </Text>
43
- )
44
- })}
45
- </Box>
46
- ))}
47
- </Box>
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, reachability] = await Promise.all([
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: getAgentApiOriginCheckStatus(reachability), detail: reachability.detail },
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, options)
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, reachability] = await Promise.all([
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: getAgentApiOriginCheckStatus(reachability), detail: reachability.detail },
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,