create-theokit 1.16.1 → 1.17.1
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/package.json
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { homedir } from 'node:os'
|
|
2
|
+
|
|
1
3
|
import { Box, Text, useApp, useInput } from 'ink'
|
|
2
4
|
import { type ReactElement, useState } from 'react'
|
|
3
5
|
import {
|
|
@@ -15,7 +17,6 @@ import {
|
|
|
15
17
|
readTurnUsage,
|
|
16
18
|
TheoTUIProvider,
|
|
17
19
|
useTurnElapsed,
|
|
18
|
-
WelcomeBanner,
|
|
19
20
|
type UIMessageLike,
|
|
20
21
|
} from '@theokit/tui'
|
|
21
22
|
import { InProcessTransport, useAgent } from 'theokit/client'
|
|
@@ -26,9 +27,21 @@ import { AGENT } from '../shared/agent.js'
|
|
|
26
27
|
|
|
27
28
|
/** Shown in the status bar (from `shared/agent.ts`). */
|
|
28
29
|
const MODEL = AGENT.model
|
|
29
|
-
|
|
30
|
+
/** cwd with the home dir tildeified (`~/…`), so the banner line stays short. */
|
|
31
|
+
const CWD = process.cwd().replace(homedir(), '~')
|
|
30
32
|
/** Claude Code's warm accent (truecolor; degrades gracefully on 256-color terminals). */
|
|
31
33
|
const ACCENT = '#d97757'
|
|
34
|
+
/** The "Theo" wordmark (figlet ANSI-Shadow, block glyphs — single-width, renders everywhere). */
|
|
35
|
+
const THEO_LOGO = [
|
|
36
|
+
'████████╗██╗ ██╗███████╗ ██████╗',
|
|
37
|
+
'╚══██╔══╝██║ ██║██╔════╝██╔═══██╗',
|
|
38
|
+
' ██║ ███████║█████╗ ██║ ██║',
|
|
39
|
+
' ██║ ██╔══██║██╔══╝ ██║ ██║',
|
|
40
|
+
' ██║ ██║ ██║███████╗╚██████╔╝',
|
|
41
|
+
' ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ',
|
|
42
|
+
].join('\n')
|
|
43
|
+
/** Below this column count the welcome box collapses to a single column (the two-column aside needs room). */
|
|
44
|
+
const WIDE_COLS = 90
|
|
32
45
|
/** Whimsical status words cycled while the agent thinks (Claude Code idiom — the ✻ spinner rotates these). */
|
|
33
46
|
const THINKING_PHRASES = [
|
|
34
47
|
'Thinking',
|
|
@@ -68,6 +81,69 @@ const transport = new InProcessTransport({
|
|
|
68
81
|
run: (input) => streamAgentTurnInProcess(chatAgent, apiKey(), input),
|
|
69
82
|
})
|
|
70
83
|
|
|
84
|
+
/** The app name — `{{name}}` is substituted at scaffold time. */
|
|
85
|
+
const APP_NAME = '{{name}}'
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The Claude-Code welcome box: a full-width rounded accent border with margins on every side. On a wide
|
|
89
|
+
* terminal it lays out two columns — left is the `Theo` wordmark + a `✻` welcome line + model + cwd; right
|
|
90
|
+
* is the getting-started tips + what's new. Below `WIDE_COLS` it collapses to a single column.
|
|
91
|
+
*/
|
|
92
|
+
function Banner(): ReactElement {
|
|
93
|
+
const cols = process.stdout.columns ?? 80
|
|
94
|
+
const wide = cols >= WIDE_COLS
|
|
95
|
+
return (
|
|
96
|
+
<Box
|
|
97
|
+
// Full width, with a one-cell margin on every side.
|
|
98
|
+
width={cols - 2}
|
|
99
|
+
marginX={1}
|
|
100
|
+
marginY={1}
|
|
101
|
+
paddingX={2}
|
|
102
|
+
paddingY={1}
|
|
103
|
+
borderStyle="round"
|
|
104
|
+
borderColor={ACCENT}
|
|
105
|
+
flexDirection="row"
|
|
106
|
+
>
|
|
107
|
+
{/* Fixed-width left column (fits the 34-wide wordmark) so a long cwd truncates instead of pushing
|
|
108
|
+
the right column off-screen — the box stays full width, the content stays grouped on the left. */}
|
|
109
|
+
<Box flexDirection="column" width={38} flexShrink={0}>
|
|
110
|
+
<Text color={ACCENT}>{THEO_LOGO}</Text>
|
|
111
|
+
<Box marginTop={1} flexDirection="column">
|
|
112
|
+
<Text color={ACCENT} bold wrap="truncate-end">
|
|
113
|
+
✻ Welcome to {APP_NAME}
|
|
114
|
+
</Text>
|
|
115
|
+
<Text dimColor wrap="truncate-end">
|
|
116
|
+
{MODEL}
|
|
117
|
+
</Text>
|
|
118
|
+
<Text dimColor wrap="truncate-start">
|
|
119
|
+
cwd: {CWD}
|
|
120
|
+
</Text>
|
|
121
|
+
</Box>
|
|
122
|
+
</Box>
|
|
123
|
+
{wide ? (
|
|
124
|
+
<Box flexDirection="column" flexShrink={0} marginLeft={4}>
|
|
125
|
+
<Text color={ACCENT} bold>
|
|
126
|
+
Tips for getting started
|
|
127
|
+
</Text>
|
|
128
|
+
<Box marginTop={1} flexDirection="column">
|
|
129
|
+
<Text dimColor>Ask me anything — I stream a reply</Text>
|
|
130
|
+
<Text dimColor>/help · @ mention a file · esc interrupts</Text>
|
|
131
|
+
</Box>
|
|
132
|
+
<Box marginTop={1} flexDirection="column">
|
|
133
|
+
<Text color={ACCENT} bold>
|
|
134
|
+
What's new
|
|
135
|
+
</Text>
|
|
136
|
+
<Box marginTop={1} flexDirection="column">
|
|
137
|
+
<Text dimColor>Human-in-the-loop approvals</Text>
|
|
138
|
+
<Text dimColor>Live token usage in the footer</Text>
|
|
139
|
+
</Box>
|
|
140
|
+
</Box>
|
|
141
|
+
</Box>
|
|
142
|
+
) : null}
|
|
143
|
+
</Box>
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
71
147
|
export function App(): ReactElement {
|
|
72
148
|
const agent = useAgent<{ message: string }>(transport)
|
|
73
149
|
const streaming = agent.status === 'streaming'
|
|
@@ -146,12 +222,7 @@ export function App(): ReactElement {
|
|
|
146
222
|
choice bar) so they receive keys under plain Ink — the ChatComposer keeps using Ink's own hooks. */}
|
|
147
223
|
<InkInputProvider>
|
|
148
224
|
<Box flexDirection="column">
|
|
149
|
-
<
|
|
150
|
-
name="✻ Welcome to {{name}}"
|
|
151
|
-
hints={['/help for help · /clear to reset', 'Enter sends · @ mentions a file · esc interrupts']}
|
|
152
|
-
>
|
|
153
|
-
<Text dimColor>cwd: {CWD}</Text>
|
|
154
|
-
</WelcomeBanner>
|
|
225
|
+
<Banner />
|
|
155
226
|
|
|
156
227
|
<AgentTimeline events={events} />
|
|
157
228
|
|