create-theokit 1.17.0 → 1.17.2

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.17.0",
3
+ "version": "1.17.2",
4
4
  "type": "module",
5
5
  "description": "Scaffold a new TheoKit project",
6
6
  "license": "Apache-2.0",
@@ -31,8 +31,15 @@ const MODEL = AGENT.model
31
31
  const CWD = process.cwd().replace(homedir(), '~')
32
32
  /** Claude Code's warm accent (truecolor; degrades gracefully on 256-color terminals). */
33
33
  const ACCENT = '#d97757'
34
- /** A little pixel mascot for the welcome box (single-width block glyphs — renders everywhere). */
35
- const MASCOT = ['▛▀▜', '▌••▐', '▙▄▟'].join('\n')
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')
36
43
  /** Below this column count the welcome box collapses to a single column (the two-column aside needs room). */
37
44
  const WIDE_COLS = 90
38
45
  /** Whimsical status words cycled while the agent thinks (Claude Code idiom — the ✻ spinner rotates these). */
@@ -78,43 +85,59 @@ const transport = new InProcessTransport({
78
85
  const APP_NAME = '{{name}}'
79
86
 
80
87
  /**
81
- * The Claude-Code welcome box: a rounded accent border. On a wide terminal it lays out two columns —
82
- * left is the `✻` header + a little pixel mascot + the model + cwd; right is the getting-started tips +
83
- * what's new. Below `WIDE_COLS` it collapses to a single column so nothing truncates.
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.
84
91
  */
85
92
  function Banner(): ReactElement {
86
93
  const cols = process.stdout.columns ?? 80
87
94
  const wide = cols >= WIDE_COLS
88
95
  return (
89
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}
90
103
  borderStyle="round"
91
104
  borderColor={ACCENT}
92
- paddingX={1}
93
105
  flexDirection="row"
94
- width={wide ? Math.min(cols - 2, 96) : undefined}
95
106
  >
96
- <Box flexDirection="column" flexGrow={1}>
97
- <Text color={ACCENT} bold>
98
- Welcome to {APP_NAME}
99
- </Text>
100
- <Text color={ACCENT}>{MASCOT}</Text>
101
- <Text dimColor>{MODEL}</Text>
102
- <Text dimColor wrap="truncate-start">
103
- cwd: {CWD}
104
- </Text>
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>
105
122
  </Box>
106
123
  {wide ? (
107
- <Box flexDirection="column" flexShrink={0} marginLeft={2}>
124
+ <Box flexDirection="column" flexShrink={0} marginLeft={4}>
108
125
  <Text color={ACCENT} bold>
109
126
  Tips for getting started
110
127
  </Text>
111
- <Text dimColor>Ask me anything — I stream a reply</Text>
112
- <Text dimColor>/help · @ mention a file · esc interrupts</Text>
113
- <Text> </Text>
114
- <Text color={ACCENT} bold>
115
- What&apos;s new
116
- </Text>
117
- <Text dimColor>Human-in-the-loop approvals · live token usage</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>
118
141
  </Box>
119
142
  ) : null}
120
143
  </Box>
@@ -216,30 +239,33 @@ export function App(): ReactElement {
216
239
 
217
240
  {showHelp ? <KeyboardHelp shortcuts={DEFAULT_COMPOSER_SHORTCUTS} /> : null}
218
241
 
219
- {pendingApproval ? (
220
- <ApprovalPrompt
221
- title={`Allow ${pendingApproval.toolName}?`}
222
- onDecision={(decision) => {
223
- // The prompt's choices are `once`/`always`/`reject`; only `reject` denies. Map to the client's
224
- // decision object and settle (remembering the id so the standalone gate part stops re-showing).
225
- settleApproval(pendingApproval.approvalId, decision !== 'reject')
226
- }}
227
- >
228
- <Text dimColor>{JSON.stringify(pendingApproval.input)}</Text>
229
- </ApprovalPrompt>
230
- ) : (
231
- <ChatComposer
232
- placeholder="Ask {{name}} anything…"
233
- bordered
234
- hint={exitArmed ? 'Press Ctrl+C again to quit' : '? for shortcuts'}
235
- commands={[
236
- { name: 'clear', description: 'clear the conversation' },
237
- { name: 'help', description: 'toggle the keyboard shortcuts panel' },
238
- ]}
239
- onHelpToggle={() => setShowHelp((h) => !h)}
240
- onSubmit={handleSubmit}
241
- />
242
- )}
242
+ {/* A one-line top margin separates the input (or the approval prompt) from the conversation above. */}
243
+ <Box marginTop={1} flexDirection="column">
244
+ {pendingApproval ? (
245
+ <ApprovalPrompt
246
+ title={`Allow ${pendingApproval.toolName}?`}
247
+ onDecision={(decision) => {
248
+ // The prompt's choices are `once`/`always`/`reject`; only `reject` denies. Map to the client's
249
+ // decision object and settle (remembering the id so the standalone gate part stops re-showing).
250
+ settleApproval(pendingApproval.approvalId, decision !== 'reject')
251
+ }}
252
+ >
253
+ <Text dimColor>{JSON.stringify(pendingApproval.input)}</Text>
254
+ </ApprovalPrompt>
255
+ ) : (
256
+ <ChatComposer
257
+ placeholder="Ask {{name}} anything…"
258
+ bordered
259
+ hint={exitArmed ? 'Press Ctrl+C again to quit' : '? for shortcuts'}
260
+ commands={[
261
+ { name: 'clear', description: 'clear the conversation' },
262
+ { name: 'help', description: 'toggle the keyboard shortcuts panel' },
263
+ ]}
264
+ onHelpToggle={() => setShowHelp((h) => !h)}
265
+ onSubmit={handleSubmit}
266
+ />
267
+ )}
268
+ </Box>
243
269
 
244
270
  <AppStatusBar
245
271
  model={MODEL}