create-theokit 1.0.5 → 1.0.7
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
|
@@ -220,6 +220,7 @@ code, pre { font-family: var(--font-mono); }
|
|
|
220
220
|
border: 1px solid var(--border);
|
|
221
221
|
border-radius: 12px;
|
|
222
222
|
padding: 24px;
|
|
223
|
+
width: 100%;
|
|
223
224
|
}
|
|
224
225
|
|
|
225
226
|
.card h2 {
|
|
@@ -314,6 +315,41 @@ tr.done td { opacity: 0.4; text-decoration: line-through; }
|
|
|
314
315
|
}
|
|
315
316
|
.chat-bar input:focus { border-color: var(--accent); }
|
|
316
317
|
|
|
318
|
+
/* ─── Features grid ─────────────────────────────────── */
|
|
319
|
+
|
|
320
|
+
.features {
|
|
321
|
+
margin-top: 32px;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.feature {
|
|
325
|
+
padding: 20px;
|
|
326
|
+
border: 1px solid var(--border);
|
|
327
|
+
border-radius: 12px;
|
|
328
|
+
background: var(--card);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.feature h3 {
|
|
332
|
+
font-size: 14px;
|
|
333
|
+
font-weight: 600;
|
|
334
|
+
margin-bottom: 6px;
|
|
335
|
+
font-family: var(--font-mono);
|
|
336
|
+
color: var(--accent);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.feature p {
|
|
340
|
+
font-size: 13px;
|
|
341
|
+
line-height: 1.5;
|
|
342
|
+
color: var(--text-secondary);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.feature code {
|
|
346
|
+
background: var(--bg);
|
|
347
|
+
border: 1px solid var(--border);
|
|
348
|
+
padding: 1px 5px;
|
|
349
|
+
border-radius: 4px;
|
|
350
|
+
font-size: 12px;
|
|
351
|
+
}
|
|
352
|
+
|
|
317
353
|
/* ─── Footer ────────────────────────────────────────── */
|
|
318
354
|
|
|
319
355
|
.footer {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { useState, useEffect, useCallback,
|
|
3
|
+
import { useState, useEffect, useCallback, type FormEvent } from 'react'
|
|
4
4
|
|
|
5
5
|
interface Task { id: number; title: string; priority: 'high' | 'medium' | 'low'; done: boolean }
|
|
6
6
|
type Role = '' | 'user' | 'admin'
|
|
7
|
-
interface ChatMsg { role: 'user' | 'agent' | 'tool' | 'system' | 'error'; text: string }
|
|
8
7
|
|
|
9
8
|
export default function Page() {
|
|
10
9
|
const [tasks, setTasks] = useState<Task[]>([])
|
|
@@ -12,10 +11,6 @@ export default function Page() {
|
|
|
12
11
|
const [title, setTitle] = useState('')
|
|
13
12
|
const [priority, setPriority] = useState<Task['priority']>('medium')
|
|
14
13
|
const [formError, setFormError] = useState('')
|
|
15
|
-
const [chat, setChat] = useState<ChatMsg[]>([{ role: 'system', text: 'Ask me to list, create, or complete tasks...' }])
|
|
16
|
-
const [chatInput, setChatInput] = useState('')
|
|
17
|
-
const [chatBusy, setChatBusy] = useState(false)
|
|
18
|
-
const chatRef = useRef<HTMLDivElement>(null)
|
|
19
14
|
|
|
20
15
|
const hdrs = useCallback((): Record<string, string> => {
|
|
21
16
|
const h: Record<string, string> = { 'Content-Type': 'application/json' }
|
|
@@ -41,47 +36,6 @@ export default function Page() {
|
|
|
41
36
|
loadTasks()
|
|
42
37
|
}
|
|
43
38
|
|
|
44
|
-
const sendChat = async () => {
|
|
45
|
-
const msg = chatInput.trim()
|
|
46
|
-
if (!msg || chatBusy) return
|
|
47
|
-
setChatInput('')
|
|
48
|
-
setChat(c => [...c, { role: 'user', text: msg }])
|
|
49
|
-
setChatBusy(true)
|
|
50
|
-
try {
|
|
51
|
-
const res = await fetch('/api/agents/assistant/chat', {
|
|
52
|
-
method: 'POST', headers: hdrs(),
|
|
53
|
-
body: JSON.stringify({ message: msg, sessionId: 'session-' + Date.now() }),
|
|
54
|
-
})
|
|
55
|
-
if (res.status === 403) { setChat(c => [...c, { role: 'error', text: '403 — Need User role' }]); return }
|
|
56
|
-
const reader = res.body?.getReader()
|
|
57
|
-
if (!reader) return
|
|
58
|
-
const decoder = new TextDecoder()
|
|
59
|
-
let buf = '', agentText = ''
|
|
60
|
-
while (true) {
|
|
61
|
-
const { done, value } = await reader.read()
|
|
62
|
-
if (done) break
|
|
63
|
-
buf += decoder.decode(value, { stream: true })
|
|
64
|
-
const lines = buf.split('\n'); buf = lines.pop() ?? ''
|
|
65
|
-
for (const line of lines) {
|
|
66
|
-
if (!line.startsWith('data: ')) continue
|
|
67
|
-
try {
|
|
68
|
-
const ev = JSON.parse(line.slice(6))
|
|
69
|
-
if (ev.type === 'text_delta') agentText += ev.content
|
|
70
|
-
else if (ev.type === 'tool_call') setChat(c => [...c, { role: 'tool', text: `🔧 ${ev.toolName}` }])
|
|
71
|
-
else if (ev.type === 'tool_result') setChat(c => [...c, { role: 'tool', text: `✅ ${(ev.output ?? '').slice(0, 80)}` }])
|
|
72
|
-
else if (ev.type === 'error') setChat(c => [...c, { role: 'error', text: ev.message }])
|
|
73
|
-
} catch { /* partial */ }
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
if (agentText) setChat(c => [...c, { role: 'agent', text: agentText }])
|
|
77
|
-
loadTasks()
|
|
78
|
-
} catch (err) {
|
|
79
|
-
setChat(c => [...c, { role: 'error', text: `Error: ${err instanceof Error ? err.message : String(err)}` }])
|
|
80
|
-
} finally { setChatBusy(false) }
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
useEffect(() => { chatRef.current?.scrollTo(0, chatRef.current.scrollHeight) }, [chat])
|
|
84
|
-
|
|
85
39
|
return (
|
|
86
40
|
<div className="page">
|
|
87
41
|
<div className="main">
|
|
@@ -99,7 +53,7 @@ export default function Page() {
|
|
|
99
53
|
</a>
|
|
100
54
|
</nav>
|
|
101
55
|
<p className="hint">
|
|
102
|
-
Edit <code>app/page.tsx</code> to get started.
|
|
56
|
+
Edit <code>app/page.tsx</code> to get started. Changes hot-reload instantly.
|
|
103
57
|
</p>
|
|
104
58
|
</header>
|
|
105
59
|
|
|
@@ -113,46 +67,51 @@ export default function Page() {
|
|
|
113
67
|
</select>
|
|
114
68
|
</div>
|
|
115
69
|
|
|
116
|
-
{/*
|
|
117
|
-
<
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
{
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
</tr>
|
|
129
|
-
))}
|
|
130
|
-
</tbody>
|
|
131
|
-
</table>
|
|
132
|
-
<form onSubmit={createTask} className="create-bar">
|
|
133
|
-
<input value={title} onChange={e => setTitle(e.target.value)} placeholder="New task..." required minLength={3} />
|
|
134
|
-
<select value={priority} onChange={e => setPriority(e.target.value as Task['priority'])}>
|
|
135
|
-
<option value="medium">Medium</option>
|
|
136
|
-
<option value="high">High</option>
|
|
137
|
-
<option value="low">Low</option>
|
|
138
|
-
</select>
|
|
139
|
-
<button type="submit">Add</button>
|
|
140
|
-
</form>
|
|
141
|
-
{formError && <p className="error">{formError}</p>}
|
|
142
|
-
</section>
|
|
143
|
-
|
|
144
|
-
<section className="card">
|
|
145
|
-
<h2>AI Assistant <span className="badge badge-ai">@Agent + SSE</span></h2>
|
|
146
|
-
<div ref={chatRef} className="chat-box">
|
|
147
|
-
{chat.map((m, i) => (
|
|
148
|
-
<div key={i} className={`msg ${m.role}`}>{m.role === 'user' ? `You: ${m.text}` : m.text}</div>
|
|
70
|
+
{/* Tasks */}
|
|
71
|
+
<section className="card">
|
|
72
|
+
<h2>Tasks <span className="badge">@Controller</span></h2>
|
|
73
|
+
<table>
|
|
74
|
+
<thead><tr><th>Task</th><th>Priority</th><th>Status</th></tr></thead>
|
|
75
|
+
<tbody>
|
|
76
|
+
{tasks.map(t => (
|
|
77
|
+
<tr key={t.id} className={t.done ? 'done' : ''}>
|
|
78
|
+
<td>{t.done ? '✅ ' : '○ '}{t.title}</td>
|
|
79
|
+
<td><span className={`prio prio-${t.priority}`}>{t.priority}</span></td>
|
|
80
|
+
<td>{t.done ? 'Done' : 'To do'}</td>
|
|
81
|
+
</tr>
|
|
149
82
|
))}
|
|
150
|
-
</
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
83
|
+
</tbody>
|
|
84
|
+
</table>
|
|
85
|
+
<form onSubmit={createTask} className="create-bar">
|
|
86
|
+
<input value={title} onChange={e => setTitle(e.target.value)} placeholder="New task..." required minLength={3} />
|
|
87
|
+
<select value={priority} onChange={e => setPriority(e.target.value as Task['priority'])}>
|
|
88
|
+
<option value="medium">Medium</option>
|
|
89
|
+
<option value="high">High</option>
|
|
90
|
+
<option value="low">Low</option>
|
|
91
|
+
</select>
|
|
92
|
+
<button type="submit">Add</button>
|
|
93
|
+
</form>
|
|
94
|
+
{formError && <p className="error">{formError}</p>}
|
|
95
|
+
</section>
|
|
96
|
+
|
|
97
|
+
{/* Features */}
|
|
98
|
+
<div className="grid features">
|
|
99
|
+
<div className="feature">
|
|
100
|
+
<h3>@Controller</h3>
|
|
101
|
+
<p>NestJS-style decorators with convention naming. <code>TasksController</code> → <code>/api/tasks</code></p>
|
|
102
|
+
</div>
|
|
103
|
+
<div className="feature">
|
|
104
|
+
<h3>defineRoute</h3>
|
|
105
|
+
<p>Typed API routes with Zod validation. See <code>server/routes/health.ts</code></p>
|
|
106
|
+
</div>
|
|
107
|
+
<div className="feature">
|
|
108
|
+
<h3>@Agent + @Tool</h3>
|
|
109
|
+
<p>AI agents with SSE streaming, budget control, and human-in-the-loop approval.</p>
|
|
110
|
+
</div>
|
|
111
|
+
<div className="feature">
|
|
112
|
+
<h3>React + Vite</h3>
|
|
113
|
+
<p>File-based routing, HMR, SSR streaming. Edit and see changes instantly.</p>
|
|
114
|
+
</div>
|
|
156
115
|
</div>
|
|
157
116
|
|
|
158
117
|
{/* Footer */}
|