create-theokit 1.2.2 → 1.2.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/package.json
CHANGED
|
@@ -1,21 +1,35 @@
|
|
|
1
1
|
import { Box, Text, useApp, useInput } from 'ink'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { type ReactElement } from 'react'
|
|
3
|
+
import {
|
|
4
|
+
AgentStreaming,
|
|
5
|
+
AppStatusBar,
|
|
6
|
+
ChatComposer,
|
|
7
|
+
ChatThread,
|
|
8
|
+
TheoTUIProvider,
|
|
9
|
+
useTurnElapsed,
|
|
10
|
+
WelcomeBanner,
|
|
11
|
+
} from '@theokit/tui'
|
|
4
12
|
import { uiMessagesToChatThread } from '@theokit/tui/ai-sdk'
|
|
5
13
|
import { InProcessTransport, useAgent } from 'theokit/client'
|
|
6
|
-
import { streamAgentTurnInProcess } from 'theokit/server'
|
|
14
|
+
import { streamAgentTurnInProcess } from 'theokit/server/agent'
|
|
7
15
|
|
|
8
16
|
import * as chatAgent from '../agents/chat.js'
|
|
9
17
|
|
|
10
|
-
/**
|
|
11
|
-
const
|
|
18
|
+
/** Shown in the status bar — keep in sync with the model in `agents/chat.ts`. */
|
|
19
|
+
const MODEL = 'openai/gpt-4o-mini'
|
|
20
|
+
const CWD = process.cwd()
|
|
21
|
+
|
|
22
|
+
/** Resolve the provider key from the environment (OpenRouter / Anthropic / OpenAI). */
|
|
23
|
+
const apiKey = (): string =>
|
|
24
|
+
process.env.OPENROUTER_API_KEY ?? process.env.ANTHROPIC_API_KEY ?? process.env.OPENAI_API_KEY ?? ''
|
|
12
25
|
|
|
13
26
|
/**
|
|
14
|
-
* M46 — the terminal surface
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* (
|
|
18
|
-
*
|
|
27
|
+
* M46 — the terminal surface, composed from `@theokit/tui` the way a Claude Code / OpenCode / Codex CLI is:
|
|
28
|
+
* a `WelcomeBanner` header, a scrolling `<ChatThread>`, a live `<AgentStreaming>` indicator, the Claude-Code
|
|
29
|
+
* bordered `<ChatComposer>` (slash-commands, `@` file mentions, Alt+Enter newline — all shipped), and a
|
|
30
|
+
* persistent `<AppStatusBar>` footer (model · cwd · state). The agent is driven by the UNIFIED `useAgent`
|
|
31
|
+
* hook (M41) over the in-process seam — its `UIMessage[]` projected onto `<ChatThread>` by the
|
|
32
|
+
* `@theokit/tui/ai-sdk` adapter. We compose shipped primitives: no hand-rolled input, no bespoke reader.
|
|
19
33
|
*/
|
|
20
34
|
const transport = new InProcessTransport({
|
|
21
35
|
run: (input) => streamAgentTurnInProcess(chatAgent, apiKey(), input),
|
|
@@ -23,39 +37,53 @@ const transport = new InProcessTransport({
|
|
|
23
37
|
|
|
24
38
|
export function App(): ReactElement {
|
|
25
39
|
const agent = useAgent<{ message: string }>(transport)
|
|
26
|
-
const
|
|
40
|
+
const streaming = agent.status === 'streaming'
|
|
41
|
+
const elapsed = useTurnElapsed(streaming)
|
|
27
42
|
const { exit } = useApp()
|
|
28
43
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
setInput('')
|
|
35
|
-
} else if (key.backspace || key.delete) {
|
|
36
|
-
setInput((s) => s.slice(0, -1))
|
|
37
|
-
} else if (char && !key.ctrl && !key.meta) {
|
|
38
|
-
setInput((s) => s + char)
|
|
39
|
-
}
|
|
44
|
+
// Esc cancels a running turn, or quits when idle (the Claude Code affordance).
|
|
45
|
+
useInput((_input, key) => {
|
|
46
|
+
if (!key.escape) return
|
|
47
|
+
if (streaming) agent.abort()
|
|
48
|
+
else exit()
|
|
40
49
|
})
|
|
41
50
|
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
const handleSubmit = (text: string): void => {
|
|
52
|
+
const trimmed = text.trim()
|
|
53
|
+
if (trimmed.length === 0) return
|
|
54
|
+
if (trimmed === '/clear') {
|
|
55
|
+
agent.reset()
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
agent.send({ message: trimmed })
|
|
59
|
+
}
|
|
44
60
|
|
|
45
61
|
return (
|
|
46
|
-
<
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
<
|
|
57
|
-
|
|
62
|
+
<TheoTUIProvider theme={{ base: 'dark', override: { accent: 'cyan' } }}>
|
|
63
|
+
<Box flexDirection="column">
|
|
64
|
+
<WelcomeBanner
|
|
65
|
+
name="{{name}}"
|
|
66
|
+
tagline="Your agent, in the terminal — built with TheoKit."
|
|
67
|
+
hints={['Enter sends · Alt+Enter for a newline', '/clear resets · esc cancels a turn or quits']}
|
|
68
|
+
>
|
|
69
|
+
<Text dimColor>cwd: {CWD}</Text>
|
|
70
|
+
</WelcomeBanner>
|
|
71
|
+
|
|
72
|
+
<ChatThread messages={uiMessagesToChatThread(agent.messages)} />
|
|
73
|
+
|
|
74
|
+
{streaming ? <AgentStreaming thought="Thinking…" elapsedSeconds={elapsed} showCancelHint /> : null}
|
|
75
|
+
{agent.error ? <Text color="red">⚠ {agent.error.message}</Text> : null}
|
|
76
|
+
|
|
77
|
+
<ChatComposer
|
|
78
|
+
placeholder="Ask your agent… (Enter sends · / commands · @ files)"
|
|
79
|
+
bordered
|
|
80
|
+
hint="Enter sends · Alt+Enter newline · /clear resets · esc cancels"
|
|
81
|
+
commands={[{ name: 'clear', description: 'clear the conversation' }]}
|
|
82
|
+
onSubmit={handleSubmit}
|
|
83
|
+
/>
|
|
84
|
+
|
|
85
|
+
<AppStatusBar model={MODEL} cwd={CWD} state={streaming ? 'streaming' : 'idle'} />
|
|
58
86
|
</Box>
|
|
59
|
-
</
|
|
87
|
+
</TheoTUIProvider>
|
|
60
88
|
)
|
|
61
89
|
}
|