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,6 +1,6 @@
1
1
  {
2
2
  "name": "create-theokit",
3
- "version": "1.16.1",
3
+ "version": "1.17.1",
4
4
  "type": "module",
5
5
  "description": "Scaffold a new TheoKit project",
6
6
  "license": "Apache-2.0",
@@ -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
- const CWD = process.cwd()
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&apos;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
- <WelcomeBanner
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