@meistrari/tela-cli 0.7.0 → 0.7.4
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 +56 -106
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/context.d.ts +2 -0
- package/dist/commands/doctor-auth.d.ts +2 -0
- package/dist/commands/env.d.ts +2 -0
- package/dist/credentials.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7027 -0
- package/dist/output.d.ts +13 -0
- package/dist/program.d.ts +2 -0
- package/package.json +17 -24
- package/scripts/install-skills.cjs +127 -0
- package/skills/tela-cli/SKILL.md +20 -0
- package/skills/tela-cli/references/agent.md +111 -0
- package/cli.ts +0 -25
- package/postinstall.sh +0 -19
- package/src/agent-api.ts +0 -300
- package/src/assets.d.ts +0 -4
- package/src/auth.ts +0 -432
- package/src/claude.ts +0 -101
- package/src/commands/doctor.ts +0 -35
- package/src/commands/feedback.ts +0 -701
- package/src/commands/metadata.ts +0 -242
- package/src/commands/push.ts +0 -208
- package/src/commands/run.ts +0 -1699
- package/src/commands/status.ts +0 -109
- package/src/commands/sync.ts +0 -245
- package/src/commit-message.ts +0 -69
- package/src/config.ts +0 -799
- package/src/diagnostics.ts +0 -813
- package/src/errors.ts +0 -122
- package/src/forgejo.ts +0 -233
- package/src/git.ts +0 -457
- package/src/ink/assets/160092__jorickhoofd__dog-bark-1.mp3 +0 -0
- package/src/ink/bark.tsx +0 -241
- package/src/ink/components.tsx +0 -178
- package/src/ink/runtime.tsx +0 -90
- package/src/ink/screens/feedback-screen.tsx +0 -395
- package/src/ink/screens/push-screen.tsx +0 -232
- package/src/ink/screens/run-screen.tsx +0 -292
- package/src/ink/screens/setup/breadcrumb.tsx +0 -24
- package/src/ink/screens/setup/setup-screen.tsx +0 -612
- package/src/ink/screens/setup/step-frame.tsx +0 -31
- package/src/ink/screens/setup/steps/done-step.tsx +0 -29
- package/src/ink/screens/setup/steps/environment-step.tsx +0 -23
- package/src/ink/screens/setup/steps/organization-step.tsx +0 -35
- package/src/ink/screens/setup/steps/review-step.tsx +0 -78
- package/src/ink/screens/setup/steps/running-step.tsx +0 -37
- package/src/ink/screens/setup/steps/ssh-key-step.tsx +0 -48
- package/src/ink/screens/setup/steps/text-field-step.tsx +0 -18
- package/src/ink/screens/setup/steps.ts +0 -156
- package/src/ink/screens/setup/types.ts +0 -65
- package/src/ink/screens/sync-screen.tsx +0 -283
- package/src/process.ts +0 -251
- package/src/program.ts +0 -2105
- package/src/runtime.ts +0 -147
- package/src/types.ts +0 -165
- package/src/ui.ts +0 -295
- package/src/version.ts +0 -3
package/src/runtime.ts
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { createUserFacingError, toUserFacingError, type UserFacingError } from './errors.ts'
|
|
2
|
-
|
|
3
|
-
export interface RuntimePromptModule {
|
|
4
|
-
note?: (message: string, title?: string) => void
|
|
5
|
-
intro?: (message: string) => void
|
|
6
|
-
outro?: (message: string) => void
|
|
7
|
-
cancel?: (message: string) => void
|
|
8
|
-
log?: {
|
|
9
|
-
success?: (message: string) => void
|
|
10
|
-
error?: (message: string) => void
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface RuntimeOptions {
|
|
15
|
-
json?: boolean
|
|
16
|
-
verbose?: boolean
|
|
17
|
-
decorate?: boolean
|
|
18
|
-
prompts?: RuntimePromptModule
|
|
19
|
-
writeStdout?: (message: string) => void
|
|
20
|
-
writeStderr?: (message: string) => void
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface StepRecord {
|
|
24
|
-
label: string
|
|
25
|
-
status: 'success' | 'failed'
|
|
26
|
-
detail?: string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export class CommandRuntime {
|
|
30
|
-
public readonly json: boolean
|
|
31
|
-
public readonly verbose: boolean
|
|
32
|
-
public readonly decorate: boolean
|
|
33
|
-
public readonly prompts?: RuntimePromptModule
|
|
34
|
-
private readonly writeStdout?: (message: string) => void
|
|
35
|
-
private readonly writeStderr?: (message: string) => void
|
|
36
|
-
private readonly steps: StepRecord[] = []
|
|
37
|
-
|
|
38
|
-
constructor(options: RuntimeOptions = {}) {
|
|
39
|
-
this.json = options.json ?? false
|
|
40
|
-
this.verbose = options.verbose ?? false
|
|
41
|
-
this.decorate = options.decorate ?? (!this.json && Boolean(process.stdout.isTTY))
|
|
42
|
-
this.prompts = options.prompts
|
|
43
|
-
this.writeStdout = options.writeStdout
|
|
44
|
-
this.writeStderr = options.writeStderr
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
emit(message: string): void {
|
|
48
|
-
if (this.json) {
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (this.writeStdout) {
|
|
53
|
-
this.writeStdout(message)
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (this.prompts?.note) {
|
|
58
|
-
this.prompts.note(message)
|
|
59
|
-
return
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
console.log(message)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
emitJson(payload: unknown): void {
|
|
66
|
-
const message = `${JSON.stringify(payload, null, 2)}\n`
|
|
67
|
-
|
|
68
|
-
if (this.writeStdout) {
|
|
69
|
-
this.writeStdout(message)
|
|
70
|
-
return
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
process.stdout.write(message)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
emitError(message: string): void {
|
|
77
|
-
if (this.writeStderr) {
|
|
78
|
-
this.writeStderr(message)
|
|
79
|
-
return
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (this.prompts?.note) {
|
|
83
|
-
this.prompts.note(message)
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
console.error(message)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
emitSuccess(message: string): void {
|
|
91
|
-
if (this.json) {
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (this.prompts?.log?.success) {
|
|
96
|
-
this.prompts.log.success(message)
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
this.emit(message)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async runStep<T>(
|
|
104
|
-
label: string,
|
|
105
|
-
fn: () => Promise<T>,
|
|
106
|
-
detail?: (value: T) => string | undefined,
|
|
107
|
-
): Promise<T> {
|
|
108
|
-
try {
|
|
109
|
-
const value = await fn()
|
|
110
|
-
this.steps.push({
|
|
111
|
-
label,
|
|
112
|
-
status: 'success',
|
|
113
|
-
detail: detail?.(value),
|
|
114
|
-
})
|
|
115
|
-
return value
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
const userError = toUserFacingError(error)
|
|
119
|
-
this.steps.push({
|
|
120
|
-
label,
|
|
121
|
-
status: 'failed',
|
|
122
|
-
detail: userError.summary,
|
|
123
|
-
})
|
|
124
|
-
throw error
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
getStepRecords(): StepRecord[] {
|
|
129
|
-
return [...this.steps]
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
appendEvidence(error: UserFacingError, evidence: string[]): UserFacingError {
|
|
133
|
-
if (evidence.length === 0) {
|
|
134
|
-
return error
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return createUserFacingError({
|
|
138
|
-
code: error.code,
|
|
139
|
-
summary: error.summary,
|
|
140
|
-
details: error.details,
|
|
141
|
-
fixes: error.fixes,
|
|
142
|
-
evidence: [...error.evidence, ...evidence],
|
|
143
|
-
exitCode: error.exitCode,
|
|
144
|
-
cause: error.cause,
|
|
145
|
-
})
|
|
146
|
-
}
|
|
147
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
export type TelaEnvironment = 'production' | 'staging' | 'custom'
|
|
2
|
-
|
|
3
|
-
export interface TelaCliUser {
|
|
4
|
-
id: string
|
|
5
|
-
email: string
|
|
6
|
-
name: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface TelaCliWorkspace {
|
|
10
|
-
id: string
|
|
11
|
-
title: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface TelaCliSession {
|
|
15
|
-
accessToken: string
|
|
16
|
-
refreshToken: string
|
|
17
|
-
expiresAt: number
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface TelaCliForgejoOrganization {
|
|
21
|
-
id: string
|
|
22
|
-
name: string
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface TelaCliGitSshKey {
|
|
26
|
-
title: string
|
|
27
|
-
publicKeyPath: string
|
|
28
|
-
privateKeyPath: string
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface TelaCliAuthState {
|
|
32
|
-
user: TelaCliUser
|
|
33
|
-
workspace: TelaCliWorkspace
|
|
34
|
-
session: TelaCliSession
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface TelaCliConfig {
|
|
38
|
-
environment: TelaEnvironment
|
|
39
|
-
agentApiUrl: string
|
|
40
|
-
authApiUrl: string
|
|
41
|
-
authDashboardUrl: string
|
|
42
|
-
telaApiUrl: string
|
|
43
|
-
cloneRoot: string
|
|
44
|
-
requesterApplicationId: string
|
|
45
|
-
targetApplicationId: string
|
|
46
|
-
auth: TelaCliAuthState | null
|
|
47
|
-
forgejoOrganization: TelaCliForgejoOrganization | null
|
|
48
|
-
forgejoUserRegistered: boolean
|
|
49
|
-
gitSshKey: TelaCliGitSshKey | null
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface OrganizationSummary {
|
|
53
|
-
id: string
|
|
54
|
-
workspaceId: string
|
|
55
|
-
name: string
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface AgentRepoSummary {
|
|
59
|
-
id: string
|
|
60
|
-
workspaceId: string
|
|
61
|
-
organizationId: string
|
|
62
|
-
repository: string
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface ForgejoRepositorySummary {
|
|
66
|
-
id: number
|
|
67
|
-
name: string
|
|
68
|
-
fullName: string
|
|
69
|
-
ownerLogin: string
|
|
70
|
-
htmlUrl: string
|
|
71
|
-
cloneUrl: string
|
|
72
|
-
sshUrl: string
|
|
73
|
-
defaultBranch: string | null
|
|
74
|
-
private: boolean
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface RepositoryLookupResponse {
|
|
78
|
-
success: boolean
|
|
79
|
-
organization?: OrganizationSummary
|
|
80
|
-
agentRepo?: AgentRepoSummary
|
|
81
|
-
forgejoRepository?: ForgejoRepositorySummary
|
|
82
|
-
error?: string
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export interface RepositoryListItemResponse {
|
|
86
|
-
organization: OrganizationSummary
|
|
87
|
-
agentRepo: AgentRepoSummary
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export interface RepositoryListResponse {
|
|
91
|
-
success: boolean
|
|
92
|
-
repositories?: RepositoryListItemResponse[]
|
|
93
|
-
error?: string
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export interface AvailableRepositorySummary extends RepositoryListItemResponse {
|
|
97
|
-
syncStatus: 'available'
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export interface OrganizationListResponse {
|
|
101
|
-
success: boolean
|
|
102
|
-
organizations?: TelaCliForgejoOrganization[]
|
|
103
|
-
error?: string
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export interface ForgejoUserSshKeyInput {
|
|
107
|
-
title: string
|
|
108
|
-
key: string
|
|
109
|
-
readOnly?: boolean
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export interface ForgejoUserCreateResponse {
|
|
113
|
-
success: boolean
|
|
114
|
-
username?: string
|
|
115
|
-
email?: string
|
|
116
|
-
organizationName?: string
|
|
117
|
-
teamName?: string
|
|
118
|
-
teamId?: number
|
|
119
|
-
userCreated?: boolean
|
|
120
|
-
teamCreated?: boolean
|
|
121
|
-
sshKeyCreated?: boolean
|
|
122
|
-
error?: string
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export type AgentFeedbackStatus = 'success' | 'failed'
|
|
126
|
-
|
|
127
|
-
export interface AgentFeedbackItem {
|
|
128
|
-
status: AgentFeedbackStatus
|
|
129
|
-
reason: string
|
|
130
|
-
suggestion: string
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export interface AgentFeedbackListResponse {
|
|
134
|
-
commitHash: string
|
|
135
|
-
feedbacks: AgentFeedbackItem[]
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export interface SyncResult {
|
|
139
|
-
targetDir: string
|
|
140
|
-
branch: string
|
|
141
|
-
head: string
|
|
142
|
-
cloned: boolean
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export interface BatchSyncFailure {
|
|
146
|
-
targetDir: string
|
|
147
|
-
error: string
|
|
148
|
-
category?: string
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export interface BatchSyncResult {
|
|
152
|
-
successes: SyncResult[]
|
|
153
|
-
failures: BatchSyncFailure[]
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export interface PushResult {
|
|
157
|
-
repoRoot: string
|
|
158
|
-
branch: string
|
|
159
|
-
message: string
|
|
160
|
-
retriedCommit: boolean
|
|
161
|
-
commitSha: string
|
|
162
|
-
upstream: string | null
|
|
163
|
-
messageSource: 'manual' | 'claude' | 'fallback'
|
|
164
|
-
fallbackReason?: string
|
|
165
|
-
}
|
package/src/ui.ts
DELETED
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
export interface RenderOptions {
|
|
2
|
-
decorate?: boolean
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
const BOOTSTRAP_PIXEL_ROWS = [
|
|
6
|
-
'2222222222233443222222233222',
|
|
7
|
-
'2223332223556777743233333222',
|
|
8
|
-
'2233433335788789986434433222',
|
|
9
|
-
'2333433347888889988743433233',
|
|
10
|
-
'3333333368777778987554333234',
|
|
11
|
-
'3433332488755567887415433344',
|
|
12
|
-
'3333321476543456776512643344',
|
|
13
|
-
'3333311355433445666421553334',
|
|
14
|
-
'3334313453222554774211454333',
|
|
15
|
-
'3334213323223534664212334443',
|
|
16
|
-
'3343111125223327113202333443',
|
|
17
|
-
'3453121136444346345302333343',
|
|
18
|
-
'3453131146568422244401222354',
|
|
19
|
-
'3342142354345742244202222444',
|
|
20
|
-
'3344343554444764553213324545',
|
|
21
|
-
'3445444514535655543213555544',
|
|
22
|
-
'4444443410135566532131455554',
|
|
23
|
-
'4443343321123454312640255555',
|
|
24
|
-
'444333431111123214a910035555',
|
|
25
|
-
'34443331132111017bc401102465',
|
|
26
|
-
'3333320006742139cd9111110135',
|
|
27
|
-
'23342010169733addc5111111014',
|
|
28
|
-
'3333111017a3013cda2111111113',
|
|
29
|
-
'3333111029831217d51111111103',
|
|
30
|
-
'333200102a9a218a711111111102',
|
|
31
|
-
'2231011019c911bc411111110102',
|
|
32
|
-
'2231001105c411aa111111100101',
|
|
33
|
-
'2221001112821175111110000000',
|
|
34
|
-
] as const
|
|
35
|
-
|
|
36
|
-
const TELA_ASCII_HEADER = [
|
|
37
|
-
'███████████╗ ████████╗███████╗██╗ █████╗ ',
|
|
38
|
-
'██ ██║ ╚══██╔══╝██╔════╝██║ ██╔══██╗',
|
|
39
|
-
'██ ██║ ██║ █████╗ ██║ ███████║',
|
|
40
|
-
'██ ██║ ██║ ██╔══╝ ██║ ██╔══██║',
|
|
41
|
-
'███████████║ ██║ ███████╗███████╗██║ ██║',
|
|
42
|
-
'╚══════════╝ ╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝',
|
|
43
|
-
] as const
|
|
44
|
-
|
|
45
|
-
const ASCII_PIXEL_RAMP = ' .,:-=+*#%@'
|
|
46
|
-
|
|
47
|
-
function isDecorated(options: RenderOptions = {}): boolean {
|
|
48
|
-
return options.decorate ?? true
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function applyAnsi(text: string, code: number, options: RenderOptions = {}): string {
|
|
52
|
-
if (!isDecorated(options)) {
|
|
53
|
-
return text
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return `\u001B[${code}m${text}\u001B[0m`
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function bold(text: string, options: RenderOptions = {}): string {
|
|
60
|
-
return applyAnsi(text, 1, options)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function color(text: string, code: number, options: RenderOptions = {}): string {
|
|
64
|
-
return applyAnsi(text, code, options)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function linesOf(input: string | string[]): string[] {
|
|
68
|
-
return Array.isArray(input)
|
|
69
|
-
? input.flatMap(part => String(part).split('\n'))
|
|
70
|
-
: String(input).split('\n')
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function stripAnsi(input: string): string {
|
|
74
|
-
return input.replace(/\u001B\[[0-9;]*m/g, '')
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function visibleWidth(input: string): number {
|
|
78
|
-
return stripAnsi(input).length
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function padRight(input: string, width: number): string {
|
|
82
|
-
const padding = Math.max(0, width - visibleWidth(input))
|
|
83
|
-
return `${input}${' '.repeat(padding)}`
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function heading(text: string, options: RenderOptions = {}): string {
|
|
87
|
-
return bold(text, options)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function pane(
|
|
91
|
-
title: string,
|
|
92
|
-
content: string | string[],
|
|
93
|
-
options: RenderOptions = {},
|
|
94
|
-
): string {
|
|
95
|
-
const decorate = isDecorated(options)
|
|
96
|
-
const inner = linesOf(content)
|
|
97
|
-
const header = decorate
|
|
98
|
-
? color(`┌─ ${title}`, 36, options)
|
|
99
|
-
: `[${title}]`
|
|
100
|
-
const body = inner.map(line => decorate ? `│ ${line}` : line)
|
|
101
|
-
|
|
102
|
-
return [header, ...body].join('\n')
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function renderPixelArtLine(row: string, options: RenderOptions = {}): string {
|
|
106
|
-
if (!isDecorated(options)) {
|
|
107
|
-
return renderBootstrapAsciiLine(row)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return row
|
|
111
|
-
.split('')
|
|
112
|
-
.map((cell) => {
|
|
113
|
-
const level = Number.parseInt(cell, 16)
|
|
114
|
-
const colorIndex = 232 + Math.round((level / 15) * 23)
|
|
115
|
-
return `\u001B[48;5;${colorIndex}m \u001B[0m`
|
|
116
|
-
})
|
|
117
|
-
.join('')
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function renderBootstrapAsciiLine(row: string): string {
|
|
121
|
-
return row
|
|
122
|
-
.split('')
|
|
123
|
-
.map((cell) => {
|
|
124
|
-
const level = Number.parseInt(cell, 16)
|
|
125
|
-
const index = Math.round((level / 15) * (ASCII_PIXEL_RAMP.length - 1))
|
|
126
|
-
return ASCII_PIXEL_RAMP[index] ?? ' '
|
|
127
|
-
})
|
|
128
|
-
.join('')
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export function getBootstrapAsciiArt(): string[] {
|
|
132
|
-
return BOOTSTRAP_PIXEL_ROWS.map(renderBootstrapAsciiLine)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export function getBootstrapPixelRows(): readonly string[] {
|
|
136
|
-
return BOOTSTRAP_PIXEL_ROWS
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export function getTelaAsciiHeader(): string[] {
|
|
140
|
-
return [...TELA_ASCII_HEADER]
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function renderAsciiHeaderLine(line: string, options: RenderOptions = {}): string {
|
|
144
|
-
return isDecorated(options) ? color(line, 97, options) : line
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function bootstrapPane(
|
|
148
|
-
title: string,
|
|
149
|
-
content: string | string[],
|
|
150
|
-
options: RenderOptions = {},
|
|
151
|
-
): string {
|
|
152
|
-
return pane(
|
|
153
|
-
title,
|
|
154
|
-
[
|
|
155
|
-
'',
|
|
156
|
-
...TELA_ASCII_HEADER.map(line => renderAsciiHeaderLine(line, options)),
|
|
157
|
-
'',
|
|
158
|
-
...linesOf(content),
|
|
159
|
-
],
|
|
160
|
-
options,
|
|
161
|
-
)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export function section(
|
|
165
|
-
title: string,
|
|
166
|
-
content: string | string[],
|
|
167
|
-
options: RenderOptions = {},
|
|
168
|
-
): string {
|
|
169
|
-
const lines = linesOf(content)
|
|
170
|
-
return [
|
|
171
|
-
heading(title, options),
|
|
172
|
-
...lines.map(line => line ? ` ${line}` : ''),
|
|
173
|
-
].join('\n')
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
export function kvList(
|
|
177
|
-
entries: Array<{ label: string, value: string }>,
|
|
178
|
-
options: RenderOptions = {},
|
|
179
|
-
): string {
|
|
180
|
-
if (entries.length === 0) {
|
|
181
|
-
return ''
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const labelWidth = entries.reduce((max, entry) => Math.max(max, entry.label.length), 0)
|
|
185
|
-
return entries
|
|
186
|
-
.map(entry => `${padRight(`${entry.label}:`, labelWidth + 1)} ${entry.value}`)
|
|
187
|
-
.join('\n')
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export function stepList(steps: string[]): string {
|
|
191
|
-
return steps
|
|
192
|
-
.map((step, index) => `${index + 1}. ${step}`)
|
|
193
|
-
.join('\n')
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export function bulletList(items: string[], prefix = '- '): string {
|
|
197
|
-
return items.map(item => `${prefix}${item}`).join('\n')
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export function callout(
|
|
201
|
-
kind: 'info' | 'warn' | 'error' | 'success',
|
|
202
|
-
title: string,
|
|
203
|
-
content: string | string[],
|
|
204
|
-
options: RenderOptions = {},
|
|
205
|
-
): string {
|
|
206
|
-
const prefixMap = {
|
|
207
|
-
info: { symbol: 'i', color: 36 },
|
|
208
|
-
warn: { symbol: '!', color: 33 },
|
|
209
|
-
error: { symbol: 'x', color: 31 },
|
|
210
|
-
success: { symbol: '✓', color: 32 },
|
|
211
|
-
} as const
|
|
212
|
-
|
|
213
|
-
const prefix = prefixMap[kind]
|
|
214
|
-
const decorate = isDecorated(options)
|
|
215
|
-
const marker = decorate
|
|
216
|
-
? color(prefix.symbol, prefix.color, options)
|
|
217
|
-
: prefix.symbol
|
|
218
|
-
|
|
219
|
-
return pane(
|
|
220
|
-
`${marker} ${title}`,
|
|
221
|
-
content,
|
|
222
|
-
options,
|
|
223
|
-
)
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export function resultCard(
|
|
227
|
-
title: string,
|
|
228
|
-
sections: Array<string | undefined | null>,
|
|
229
|
-
options: RenderOptions = {},
|
|
230
|
-
): string {
|
|
231
|
-
return pane(
|
|
232
|
-
title,
|
|
233
|
-
sections.filter(Boolean).join('\n\n'),
|
|
234
|
-
options,
|
|
235
|
-
)
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export function errorCard(input: {
|
|
239
|
-
summary: string
|
|
240
|
-
details?: string
|
|
241
|
-
fixes?: string[]
|
|
242
|
-
evidence?: string[]
|
|
243
|
-
}, options: RenderOptions = {}): string {
|
|
244
|
-
const parts: string[] = []
|
|
245
|
-
|
|
246
|
-
if (input.details) {
|
|
247
|
-
parts.push(input.details)
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (input.fixes?.length) {
|
|
251
|
-
parts.push(section('How to fix it', stepList(input.fixes), options))
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (input.evidence?.length) {
|
|
255
|
-
parts.push(section('Evidence', bulletList(input.evidence), options))
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return callout('error', input.summary, parts, options)
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export function nextActions(actions: string[], options: RenderOptions = {}): string {
|
|
262
|
-
return section('Next actions', stepList(actions), options)
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
export function table(
|
|
266
|
-
headers: string[],
|
|
267
|
-
rows: string[][],
|
|
268
|
-
options: RenderOptions = {},
|
|
269
|
-
): string {
|
|
270
|
-
const allRows = [headers, ...rows]
|
|
271
|
-
const widths = headers.map((_, columnIndex) => allRows.reduce((max, row) => {
|
|
272
|
-
return Math.max(max, visibleWidth(row[columnIndex] ?? ''))
|
|
273
|
-
}, 0))
|
|
274
|
-
|
|
275
|
-
const divider = widths.map(width => '-'.repeat(width)).join(' ')
|
|
276
|
-
const renderedRows = allRows.map((row, rowIndex) => {
|
|
277
|
-
const rendered = row
|
|
278
|
-
.map((cell, columnIndex) => padRight(cell ?? '', widths[columnIndex] ?? 0))
|
|
279
|
-
.join(' ')
|
|
280
|
-
|
|
281
|
-
if (rowIndex === 0 && isDecorated(options)) {
|
|
282
|
-
return bold(rendered, options)
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return rendered
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
return [renderedRows[0] ?? '', divider, ...renderedRows.slice(1)].join('\n')
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
export function joinBlocks(blocks: Array<string | undefined | null>): string {
|
|
292
|
-
return blocks
|
|
293
|
-
.filter((block): block is string => Boolean(block && block.trim()))
|
|
294
|
-
.join('\n\n')
|
|
295
|
-
}
|
package/src/version.ts
DELETED