create-theokit 1.0.14 → 1.0.16
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/LICENSE +201 -0
- package/dist/cli.js +4 -13
- package/dist/cli.js.map +1 -1
- package/package.json +10 -8
- package/templates/default/CLAUDE.md +2 -2
- package/templates/default/README.md.tmpl +38 -50
- package/templates/default/agents/chat.ts +22 -0
- package/templates/default/app/layout.tsx +71 -3
- package/templates/default/app/page.tsx +296 -61
- package/templates/default/dot-claude/skills/theokit-agents/SKILL.md +78 -44
- package/templates/default/dot-claude/skills/theokit-frontend/SKILL.md +24 -26
- package/templates/default/dot-claude/skills/theokit-ui/SKILL.md +32 -28
- package/templates/default/eslint.config.mjs +1 -5
- package/templates/default/package.json.tmpl +16 -9
- package/templates/default/theo.config.ts +1 -3
- package/templates/default/tsconfig.json +7 -14
- package/templates/default/types/jobs.d.ts +25 -0
- package/templates/services/agent-node/Dockerfile.tmpl +20 -0
- package/templates/services/agent-node/README.md +38 -0
- package/templates/services/agent-node/package.json.tmpl +18 -0
- package/templates/services/agent-node/src/index.ts +58 -0
- package/templates/services/agent-node/tsconfig.json +13 -0
- package/templates/default/AGENTS.md +0 -106
- package/templates/default/app/globals.css +0 -377
- package/templates/default/app.ts +0 -15
- package/templates/default/drizzle.config.ts +0 -10
- package/templates/default/server/db/index.ts +0 -10
- package/templates/default/server/db/schema.ts +0 -13
- package/templates/default/server/index.ts +0 -2
- package/templates/default/tests/tasks.test.ts +0 -18
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: theokit-agents
|
|
3
|
-
description: TheoKit agent/LLM integration —
|
|
3
|
+
description: TheoKit agent/LLM integration — agents/*.ts convention (defineAgent), @Agent decorator (advanced/DI), defineAgentTool, useAgent client hook
|
|
4
4
|
user-invocable: false
|
|
5
5
|
paths:
|
|
6
6
|
- "**/*agent*"
|
|
@@ -13,37 +13,38 @@ paths:
|
|
|
13
13
|
|
|
14
14
|
# TheoKit Agents & Tools
|
|
15
15
|
|
|
16
|
-
##
|
|
16
|
+
## Server Surface — agents/*.ts (zero-config convention)
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
| Surface | Server | Events | Client | When to use |
|
|
21
|
-
|---------|--------|--------|--------|-------------|
|
|
22
|
-
| **Manual** (recommended for most apps) | `defineAgentEndpoint({ handler: async function* })` | `AgentEvent` (Message, ToolCall, Result, Error) | `useAgentStream()` / `consumeAgentStream()` | Full control over the LLM loop — you write the generator |
|
|
23
|
-
| **Decorator** (`@theokit/agents`) | `@Agent` class → auto-generated route | `AgentStreamEvent` (TextDelta, ToolCall, Done...) | (same client hooks work) | Declarative — framework manages LLM loop via `@MainLoop` |
|
|
24
|
-
|
|
25
|
-
### Surface 1: Manual (defineAgentEndpoint)
|
|
18
|
+
Create an `agents/<name>.ts` file at the project root. It is automatically served at
|
|
19
|
+
`POST /api/agents/<name>` (dev + build) with no manual route wiring.
|
|
26
20
|
|
|
27
21
|
```typescript
|
|
28
|
-
//
|
|
29
|
-
import {
|
|
30
|
-
import
|
|
31
|
-
|
|
32
|
-
export
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const result = await callLLM(body.message)
|
|
37
|
-
yield { type: 'message', content: result }
|
|
38
|
-
},
|
|
22
|
+
// agents/chat.ts
|
|
23
|
+
import { defineAgent } from '@theokit/agents'
|
|
24
|
+
import { z } from 'zod'
|
|
25
|
+
|
|
26
|
+
export default defineAgent({
|
|
27
|
+
input: z.object({ message: z.string() }),
|
|
28
|
+
model: 'openai/gpt-4o-mini',
|
|
29
|
+
system: 'You are a helpful assistant.',
|
|
39
30
|
})
|
|
40
31
|
```
|
|
41
32
|
|
|
42
|
-
|
|
33
|
+
The endpoint streams the ai-sdk `UIMessageStream` that `useAgent` (client hook) consumes.
|
|
34
|
+
`@theokit/sdk` runs the agent; conversation turns auto-persist per session — the SDK owns storage.
|
|
35
|
+
|
|
36
|
+
**Provider resolution:** `OPENROUTER_API_KEY` (preferred — routes to many models) OR
|
|
37
|
+
`ANTHROPIC_API_KEY` / `OPENAI_API_KEY`. Set one in `.env`.
|
|
38
|
+
|
|
39
|
+
## Advanced Surface — @Agent Decorator (DI / class-based)
|
|
40
|
+
|
|
41
|
+
When you need dependency injection or class-based composition, use the `@Agent` class
|
|
42
|
+
decorator from `@theokit/agents`. The class name determines the route:
|
|
43
|
+
`AssistantAgent` → `POST /api/agents/assistant`.
|
|
43
44
|
|
|
44
45
|
```typescript
|
|
45
46
|
// server/agents/assistant.agent.ts
|
|
46
|
-
import { Agent, MainLoop
|
|
47
|
+
import { Agent, MainLoop } from '@theokit/agents'
|
|
47
48
|
|
|
48
49
|
@Agent({
|
|
49
50
|
model: 'openai/gpt-4o-mini',
|
|
@@ -57,9 +58,33 @@ export class AssistantAgent {
|
|
|
57
58
|
}
|
|
58
59
|
```
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
## Tools — defineAgentTool
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
Declare typed tools with `defineAgentTool` (from `theokit/server`) and pass them to
|
|
64
|
+
`defineAgent`'s `tools` array.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// agents/chat.ts
|
|
68
|
+
import { defineAgent } from '@theokit/agents'
|
|
69
|
+
import { defineAgentTool } from 'theokit/server'
|
|
70
|
+
import { z } from 'zod'
|
|
71
|
+
|
|
72
|
+
const currentTimeTool = defineAgentTool({
|
|
73
|
+
name: 'current_time',
|
|
74
|
+
description: 'Return the current ISO timestamp',
|
|
75
|
+
input: z.object({}),
|
|
76
|
+
execute: async () => ({ time: new Date().toISOString() }),
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
export default defineAgent({
|
|
80
|
+
input: z.object({ message: z.string() }),
|
|
81
|
+
model: 'openai/gpt-4o-mini',
|
|
82
|
+
system: 'You are a helpful assistant.',
|
|
83
|
+
tools: [currentTimeTool],
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### @Tool Decorator (advanced / class-based)
|
|
63
88
|
|
|
64
89
|
```typescript
|
|
65
90
|
import { Toolbox, Tool } from '@theokit/agents'
|
|
@@ -78,23 +103,26 @@ export class TaskTools {
|
|
|
78
103
|
}
|
|
79
104
|
```
|
|
80
105
|
|
|
81
|
-
## Client —
|
|
82
|
-
|
|
83
|
-
Works with BOTH surfaces. Transport: `fetch` POST + `ReadableStream` (SSE).
|
|
106
|
+
## Client — useAgent (React hook)
|
|
84
107
|
|
|
85
108
|
```typescript
|
|
86
|
-
import {
|
|
109
|
+
import { useAgent } from 'theokit/client'
|
|
87
110
|
|
|
88
111
|
function ChatUI() {
|
|
89
|
-
const {
|
|
112
|
+
const { messages, status, send, reset } = useAgent<{ message: string }>('/api/agents/chat')
|
|
90
113
|
|
|
91
114
|
return (
|
|
92
115
|
<div>
|
|
93
116
|
{status === 'streaming' && <p>Thinking...</p>}
|
|
94
|
-
{
|
|
95
|
-
<div key={
|
|
96
|
-
{
|
|
97
|
-
|
|
117
|
+
{messages.map(message => (
|
|
118
|
+
<div key={message.id}>
|
|
119
|
+
{message.parts.map((part, i) => (
|
|
120
|
+
part.type === 'text'
|
|
121
|
+
? <p key={i}>{part.text}</p>
|
|
122
|
+
: part.type === 'dynamic-tool'
|
|
123
|
+
? <p key={i}>Using tool: {part.toolName}</p>
|
|
124
|
+
: null
|
|
125
|
+
))}
|
|
98
126
|
</div>
|
|
99
127
|
))}
|
|
100
128
|
<button onClick={() => send({ message: 'Hello' })}>Send</button>
|
|
@@ -103,15 +131,23 @@ function ChatUI() {
|
|
|
103
131
|
}
|
|
104
132
|
```
|
|
105
133
|
|
|
106
|
-
|
|
134
|
+
`messages` is `UIMessage[]` (ai-sdk). Render `message.parts` — text parts
|
|
135
|
+
(`part.type === 'text'`, `part.text`) and tool parts (`part.type === 'dynamic-tool'`,
|
|
136
|
+
`part.toolName`, `part.state`, `part.output`). Do NOT switch on an `events`/`event.type`
|
|
137
|
+
pattern — the wire is `UIMessageStream`, not SSE events.
|
|
138
|
+
|
|
139
|
+
### Non-React: consumeUIMessageStream
|
|
107
140
|
|
|
108
141
|
```typescript
|
|
109
|
-
import {
|
|
142
|
+
import { consumeUIMessageStream } from 'theokit/client'
|
|
110
143
|
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
144
|
+
const response = await fetch('/api/agents/chat', {
|
|
145
|
+
method: 'POST',
|
|
146
|
+
body: JSON.stringify({ message: 'Hello' }),
|
|
147
|
+
})
|
|
148
|
+
consumeUIMessageStream(response, (message) => {
|
|
149
|
+
console.log(message.parts)
|
|
150
|
+
})
|
|
115
151
|
```
|
|
116
152
|
|
|
117
153
|
## SDK Ecosystem — "you are here" map
|
|
@@ -134,14 +170,12 @@ Before writing custom tools, check if they already exist:
|
|
|
134
170
|
- `@UseGuards()` works on agents (shared with HTTP pipeline)
|
|
135
171
|
- `@UseInterceptors()` and `@UseFilters()` on agents are metadata-only (emit warnings)
|
|
136
172
|
- Agent runtime is `@theokit/sdk` — NEVER call LLM APIs directly via fetch
|
|
137
|
-
- Pick ONE surface per endpoint — don't mix defineAgentEndpoint with @Agent for the same route
|
|
138
173
|
- Check `@theokit/sdk-tools` BEFORE writing custom tools — it may already exist
|
|
139
174
|
|
|
140
175
|
## Anti-patterns
|
|
141
176
|
|
|
142
|
-
- NEVER call OpenAI/Anthropic/OpenRouter APIs directly — use
|
|
177
|
+
- NEVER call OpenAI/Anthropic/OpenRouter APIs directly — use `defineAgent` or `@Agent`
|
|
143
178
|
- NEVER reimplement tool calling loop — the SDK handles it
|
|
144
179
|
- NEVER reimplement file/search/shell tools — use `@theokit/sdk-tools` (readFile, writeFile, search, etc.)
|
|
145
|
-
- NEVER store conversations manually —
|
|
180
|
+
- NEVER store conversations manually — SDK persistence is automatic (the SDK owns storage)
|
|
146
181
|
- NEVER infer tool capability from method name — always provide explicit `name` + `description`
|
|
147
|
-
- NEVER mix both surfaces for the same endpoint — pick manual OR decorator
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: theokit-frontend
|
|
3
|
-
description: TheoKit frontend — file-based routing, layouts, theoFetch typed client,
|
|
3
|
+
description: TheoKit frontend — file-based routing, layouts, theoFetch typed client, useAgent, React patterns
|
|
4
4
|
user-invocable: false
|
|
5
5
|
paths:
|
|
6
6
|
- "app/**"
|
|
@@ -50,23 +50,24 @@ const created = await client.tasks.POST({ body: { title: 'New' } })
|
|
|
50
50
|
|
|
51
51
|
## Agent Streaming
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Two client APIs from `theokit/client`:
|
|
54
54
|
|
|
55
|
-
###
|
|
55
|
+
### useAgent (React hook — most common)
|
|
56
56
|
|
|
57
57
|
```typescript
|
|
58
|
-
import {
|
|
58
|
+
import { useAgent } from 'theokit/client'
|
|
59
59
|
|
|
60
60
|
function ChatUI() {
|
|
61
|
-
const {
|
|
61
|
+
const { messages, status, send, reset } = useAgent<{ message: string }>('/api/agents/chat')
|
|
62
62
|
|
|
63
63
|
return (
|
|
64
64
|
<div>
|
|
65
65
|
{status === 'streaming' && <p>Thinking...</p>}
|
|
66
|
-
{
|
|
67
|
-
<div key={
|
|
68
|
-
{
|
|
69
|
-
|
|
66
|
+
{messages.map(message => (
|
|
67
|
+
<div key={message.id}>
|
|
68
|
+
{message.parts.map((part, i) =>
|
|
69
|
+
part.type === 'text' ? <p key={i}>{part.text}</p> : null
|
|
70
|
+
)}
|
|
70
71
|
</div>
|
|
71
72
|
))}
|
|
72
73
|
<button onClick={() => send({ message: 'Hello' })}>Send</button>
|
|
@@ -75,26 +76,23 @@ function ChatUI() {
|
|
|
75
76
|
}
|
|
76
77
|
```
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
`messages` is `UIMessage[]` (ai-sdk). Render `message.parts`: text parts
|
|
80
|
+
(`part.type === 'text'`, `part.text`) and tool parts (`part.type === 'dynamic-tool'`,
|
|
81
|
+
`part.toolName`, `part.state`, `part.output`). Do NOT switch on an `events`/`event.type`
|
|
82
|
+
pattern — the wire is `UIMessageStream`, not SSE events.
|
|
79
83
|
|
|
80
|
-
|
|
81
|
-
import { consumeAgentStream } from 'theokit/client'
|
|
82
|
-
|
|
83
|
-
const stream = consumeAgentStream('/api/agents/assistant', {
|
|
84
|
-
body: { message: 'Hello' },
|
|
85
|
-
})
|
|
86
|
-
for await (const event of stream) {
|
|
87
|
-
console.log(event.type, event.content)
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### parseSSEChunk (low-level SSE parser)
|
|
84
|
+
### consumeUIMessageStream (non-React)
|
|
92
85
|
|
|
93
86
|
```typescript
|
|
94
|
-
import {
|
|
87
|
+
import { consumeUIMessageStream } from 'theokit/client'
|
|
95
88
|
|
|
96
|
-
|
|
97
|
-
|
|
89
|
+
const response = await fetch('/api/agents/chat', {
|
|
90
|
+
method: 'POST',
|
|
91
|
+
body: JSON.stringify({ message: 'Hello' }),
|
|
92
|
+
})
|
|
93
|
+
consumeUIMessageStream(response, (message) => {
|
|
94
|
+
console.log(message.parts)
|
|
95
|
+
})
|
|
98
96
|
```
|
|
99
97
|
|
|
100
98
|
## Path Aliases
|
|
@@ -111,4 +109,4 @@ Configured in `tsconfig.json` — works in both server and app code.
|
|
|
111
109
|
- NEVER use raw `fetch('/api/...')` — use `theoFetch` for type safety
|
|
112
110
|
- NEVER create pages outside `app/` — they won't be discovered by the router
|
|
113
111
|
- NEVER import server code directly in `app/` — use theoFetch or server actions
|
|
114
|
-
- NEVER use `useEffect` + `fetch` for data loading — use theoFetch or
|
|
112
|
+
- NEVER use `useEffect` + `fetch` for data loading — use theoFetch or `useAgent`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: theokit-ui
|
|
3
|
-
description: "@theokit/ui component library —
|
|
3
|
+
description: "@theokit/ui AI-native component library — AI-agent surfaces (ChatThread, ChatMessage, ChatComposer, ToolCallCard, AgentStream), theming, providers; generic primitives (CodeBlock, Sidebar, Button) come from @usetheo/ui"
|
|
4
4
|
user-invocable: false
|
|
5
5
|
paths:
|
|
6
6
|
- "app/**"
|
|
@@ -12,13 +12,13 @@ paths:
|
|
|
12
12
|
- "**/*Theme*"
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
# @theokit/ui — AI
|
|
15
|
+
# @theokit/ui — AI-native Component Library (AI-agent surfaces)
|
|
16
16
|
|
|
17
|
-
`@theokit/ui` is an optional peer dependency. If installed, it provides ready-made components for chat
|
|
17
|
+
`@theokit/ui` is an optional peer dependency. If installed, it provides ready-made AI components for chat + coding-agent surfaces (chat thread, agent events, tool calls, diff viewer, build logs), plus theming. **Never build custom equivalents** of components it provides. Generic primitives (Button, Input, Card, CodeBlock, PageShell, Sidebar, Avatar, Alert, etc.) live in `@usetheo/ui`, which `@theokit/ui` depends on — import those from `@usetheo/ui`.
|
|
18
18
|
|
|
19
19
|
## Package Identity
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
`@theokit/ui` (AI-native, currently `1.0.0`) provides the AI-agent-surface components. Its generic foundation was split into `@usetheo/ui` in the 2026-07-03 AI-exclusive pivot; `@theokit/ui` depends on `@usetheo/ui`, so installing `@theokit/ui` pulls the foundation transitively.
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
# Install from npm (preferred)
|
|
@@ -54,19 +54,19 @@ export default function Layout({ children }) {
|
|
|
54
54
|
### Full Chat Page (typical assembly)
|
|
55
55
|
|
|
56
56
|
```typescript
|
|
57
|
+
// AI-agent-surface components live in @theokit/ui
|
|
57
58
|
import {
|
|
58
|
-
PageShell,
|
|
59
|
-
Sidebar,
|
|
60
|
-
SessionListItem,
|
|
61
59
|
ChatThread,
|
|
62
60
|
ChatMessage,
|
|
63
61
|
ChatMessageContent,
|
|
64
62
|
ChatComposer,
|
|
65
63
|
} from '@theokit/ui'
|
|
66
|
-
|
|
64
|
+
// Generic layout primitives moved to @usetheo/ui (2026-07-03 pivot)
|
|
65
|
+
import { PageShell, Sidebar, SessionListItem } from '@usetheo/ui'
|
|
66
|
+
import { useAgent } from 'theokit/client'
|
|
67
67
|
|
|
68
68
|
function ChatPage() {
|
|
69
|
-
const {
|
|
69
|
+
const { messages, status, send } = useAgent('/api/agents/assistant')
|
|
70
70
|
|
|
71
71
|
return (
|
|
72
72
|
<PageShell sidebar={
|
|
@@ -77,9 +77,13 @@ function ChatPage() {
|
|
|
77
77
|
</Sidebar>
|
|
78
78
|
}>
|
|
79
79
|
<ChatThread>
|
|
80
|
-
{messages.map(
|
|
81
|
-
<ChatMessage key={
|
|
82
|
-
|
|
80
|
+
{messages.map(message => (
|
|
81
|
+
<ChatMessage key={message.id} role={message.role}>
|
|
82
|
+
{message.parts.map((part, i) =>
|
|
83
|
+
part.type === 'text'
|
|
84
|
+
? <ChatMessageContent key={i} markdown={part.text} />
|
|
85
|
+
: null
|
|
86
|
+
)}
|
|
83
87
|
</ChatMessage>
|
|
84
88
|
))}
|
|
85
89
|
</ChatThread>
|
|
@@ -93,29 +97,29 @@ function ChatPage() {
|
|
|
93
97
|
}
|
|
94
98
|
```
|
|
95
99
|
|
|
96
|
-
###
|
|
100
|
+
### AI-agent-surface components (from `@theokit/ui`)
|
|
97
101
|
|
|
98
102
|
| Component | Purpose | Key Props |
|
|
99
103
|
|-----------|---------|-----------|
|
|
100
104
|
| `ChatThread` | Scrollable message container | `children` (ChatMessage elements) |
|
|
101
105
|
| `ChatMessage` | Single message bubble | `role: 'user' \| 'assistant'`, `children` |
|
|
102
106
|
| `ChatMessageContent` | Markdown + code rendering | `markdown: string` (handles streaming partial) |
|
|
103
|
-
| `CodeBlock` | Syntax-highlighted code | `code: string`, `language?: string` (uses shiki, lazy-loaded) |
|
|
104
107
|
| `ChatComposer` | Message input + submit | `onSubmit: (text) => void`, `disabled?: boolean` |
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `SessionListItem` | Session entry in sidebar | `title: string`, `onClick`, `active?: boolean` |
|
|
108
|
+
| `ToolCallCard` | Display agent tool invocations | — |
|
|
109
|
+
| `AgentStream` | Lower-level stream renderer | — |
|
|
108
110
|
|
|
109
|
-
###
|
|
111
|
+
### Generic primitives (from `@usetheo/ui`)
|
|
110
112
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
|
114
|
-
|
|
115
|
-
| `
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
118
|
-
| `
|
|
113
|
+
Moved out of `@theokit/ui` in the 2026-07-03 AI-exclusive pivot. Import these from `@usetheo/ui`.
|
|
114
|
+
|
|
115
|
+
| Component | Purpose | Key Props |
|
|
116
|
+
|-----------|---------|-----------|
|
|
117
|
+
| `CodeBlock` | Syntax-highlighted code | `code: string`, `language?: string` (uses shiki, lazy-loaded) |
|
|
118
|
+
| `PageShell` | App layout with sidebar slot | `sidebar?: ReactNode`, `children` |
|
|
119
|
+
| `Sidebar` | Collapsible side panel | `children` |
|
|
120
|
+
| `Button`, `Input`, `Textarea` | Form primitives (themed) | — |
|
|
121
|
+
| `Avatar` | User/agent avatar | — |
|
|
122
|
+
| `Alert` | Status messages | — |
|
|
119
123
|
|
|
120
124
|
## Peer Dependencies (install only what you use)
|
|
121
125
|
|
|
@@ -154,8 +158,8 @@ const myTheme = defineTheme({
|
|
|
154
158
|
|
|
155
159
|
- NEVER build a custom chat message component — use `ChatMessage` + `ChatMessageContent`
|
|
156
160
|
- NEVER build a custom markdown renderer — `ChatMessageContent` handles it (including streaming partial fences)
|
|
157
|
-
- NEVER build a custom code highlighter — `CodeBlock` uses shiki (lazy-loaded)
|
|
158
|
-
-
|
|
161
|
+
- NEVER build a custom code highlighter — `CodeBlock` (from `@usetheo/ui`) uses shiki (lazy-loaded)
|
|
162
|
+
- Import AI-agent-surface components (ChatThread, ChatMessage, ToolCallCard, etc.) from `@theokit/ui`; import generic primitives (Button, Input, CodeBlock, PageShell, Sidebar, Avatar, Alert) from `@usetheo/ui` — both are live packages since the 2026-07-03 pivot (`@theokit/ui` depends on `@usetheo/ui`)
|
|
159
163
|
- NEVER use `npm link` or `file:../theo-ui` to install — causes dual-React (use tarball or npm registry)
|
|
160
164
|
- NEVER install ALL peer deps — only install the peers for components you actually use
|
|
161
165
|
- NEVER use components without wrapping in `TheoUIProvider` + `ThemeProvider` first
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import tseslint from 'typescript-eslint'
|
|
2
2
|
import prettierConfig from 'eslint-config-prettier'
|
|
3
|
-
import drizzle from 'eslint-plugin-drizzle'
|
|
4
3
|
|
|
5
4
|
export default tseslint.config(
|
|
6
|
-
{ ignores: ['dist/', 'node_modules/'
|
|
5
|
+
{ ignores: ['dist/', 'node_modules/'] },
|
|
7
6
|
...tseslint.configs.recommended,
|
|
8
7
|
prettierConfig,
|
|
9
8
|
{
|
|
10
|
-
plugins: { drizzle },
|
|
11
9
|
rules: {
|
|
12
10
|
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
|
13
11
|
'@typescript-eslint/no-explicit-any': 'warn',
|
|
14
|
-
'drizzle/enforce-delete-with-where': 'error',
|
|
15
|
-
'drizzle/enforce-update-with-where': 'error',
|
|
16
12
|
},
|
|
17
13
|
},
|
|
18
14
|
)
|
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
"build": "theokit build",
|
|
9
9
|
"start": "theokit start",
|
|
10
10
|
"test": "vitest run",
|
|
11
|
-
"db:migrate": "theokit db migrate",
|
|
12
|
-
"db:generate": "theokit db generate",
|
|
13
11
|
"lint": "eslint .",
|
|
14
12
|
"lint:fix": "eslint . --fix",
|
|
15
13
|
"format": "prettier --write .",
|
|
@@ -17,25 +15,34 @@
|
|
|
17
15
|
"typecheck": "tsc --noEmit"
|
|
18
16
|
},
|
|
19
17
|
"dependencies": {
|
|
20
|
-
"theokit": "^0.
|
|
18
|
+
"theokit": "^0.15.1",
|
|
19
|
+
"@theokit/agents": "^0.30.1",
|
|
20
|
+
"@theokit/sdk": "^2.13.0",
|
|
21
|
+
"@theokit/ui": "^1.0.0",
|
|
22
|
+
"@usetheo/ui": "^0.14.0",
|
|
23
|
+
"lucide-react": "^0.469.0",
|
|
21
24
|
"react": "^19.0.0",
|
|
22
25
|
"react-dom": "^19.0.0",
|
|
23
26
|
"react-router": "^7.0.0",
|
|
24
|
-
"zod": "^4.0.0"
|
|
25
|
-
"drizzle-orm": "^0.44.0",
|
|
26
|
-
"better-sqlite3": "^12.0.0"
|
|
27
|
+
"zod": "^4.0.0"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
|
-
"@types/better-sqlite3": "^7.6.0",
|
|
30
30
|
"@types/react": "^19.0.0",
|
|
31
31
|
"@types/react-dom": "^19.0.0",
|
|
32
|
-
"
|
|
32
|
+
"tailwindcss": "^4.0.0",
|
|
33
|
+
"@tailwindcss/vite": "^4.0.0",
|
|
33
34
|
"eslint": "^9.0.0",
|
|
34
35
|
"eslint-config-prettier": "^10.0.0",
|
|
35
|
-
"eslint-plugin-drizzle": "^0.2.0",
|
|
36
36
|
"prettier": "^3.0.0",
|
|
37
37
|
"typescript": "^5.5.0",
|
|
38
38
|
"typescript-eslint": "^8.0.0",
|
|
39
39
|
"vitest": "^3.0.0"
|
|
40
|
+
},
|
|
41
|
+
"pnpm": {
|
|
42
|
+
"onlyBuiltDependencies": [
|
|
43
|
+
"esbuild",
|
|
44
|
+
"better-sqlite3",
|
|
45
|
+
"workerd"
|
|
46
|
+
]
|
|
40
47
|
}
|
|
41
48
|
}
|
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ES2022",
|
|
4
|
-
"module": "
|
|
5
|
-
"moduleResolution": "
|
|
6
|
-
"experimentalDecorators": true,
|
|
7
|
-
"emitDecoratorMetadata": true,
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
8
6
|
"strict": true,
|
|
9
|
-
"
|
|
7
|
+
"noEmit": true,
|
|
10
8
|
"esModuleInterop": true,
|
|
11
9
|
"skipLibCheck": true,
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"@/*": ["./*"],
|
|
16
|
-
"@/server/*": ["./server/*"],
|
|
17
|
-
"@/app/*": ["./app/*"]
|
|
18
|
-
}
|
|
10
|
+
"jsx": "react-jsx",
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"resolveJsonModule": true
|
|
19
13
|
},
|
|
20
|
-
"include": ["
|
|
21
|
-
"exclude": ["node_modules", "dist"]
|
|
14
|
+
"include": ["app/**/*.ts", "app/**/*.tsx", "server/**/*.ts", "agents/**/*.ts"]
|
|
22
15
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JobRegistry augmentation — REQUIRED for typed `ctx.queue.enqueue` calls.
|
|
3
|
+
*
|
|
4
|
+
* Without this augmentation, `ctx.queue.enqueue('foo', ...)` errors with:
|
|
5
|
+
* "Type 'foo' is not assignable to type 'never'"
|
|
6
|
+
*
|
|
7
|
+
* This is the canonical TheoKit jobs onboarding bug (EC-110). To add a
|
|
8
|
+
* job:
|
|
9
|
+
*
|
|
10
|
+
* 1. Create `server/jobs/<name>.ts` exporting `defineJob('<name>', ...)`
|
|
11
|
+
* 2. Add `'<name>': { ...inputShape }` below
|
|
12
|
+
* 3. Use `ctx.queue.enqueue('<name>', { ...input })` from any route handler
|
|
13
|
+
*
|
|
14
|
+
* See: docs/concepts/jobs.md
|
|
15
|
+
*/
|
|
16
|
+
declare module 'theokit/server' {
|
|
17
|
+
interface JobRegistry {
|
|
18
|
+
// Add your jobs here. Examples (uncomment and customize):
|
|
19
|
+
//
|
|
20
|
+
// 'process-document': { documentId: string }
|
|
21
|
+
// 'send-email': { to: string; subject: string; body: string }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
FROM node:22-alpine
|
|
2
|
+
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
|
|
5
|
+
# Install pnpm (or use npm if pnpm not available in image)
|
|
6
|
+
RUN corepack enable && corepack prepare pnpm@latest --activate || true
|
|
7
|
+
|
|
8
|
+
# Copy manifest and install
|
|
9
|
+
COPY package.json ./
|
|
10
|
+
RUN pnpm install --frozen-lockfile || npm install
|
|
11
|
+
|
|
12
|
+
# Copy source
|
|
13
|
+
COPY . .
|
|
14
|
+
|
|
15
|
+
EXPOSE 8002
|
|
16
|
+
|
|
17
|
+
HEALTHCHECK --interval=10s --timeout=5s --retries=3 \
|
|
18
|
+
CMD wget --spider -q http://localhost:8002/health || exit 1
|
|
19
|
+
|
|
20
|
+
CMD ["pnpm", "start"]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Agent service (Node / Hono)
|
|
2
|
+
|
|
3
|
+
This is a TheoKit polyglot sidecar generated by `create-theokit --backend node`.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- **Node.js 22+** (matches TheoKit's floor)
|
|
8
|
+
- **pnpm** or **npm** (TheoKit's CLI prefers pnpm)
|
|
9
|
+
|
|
10
|
+
## Run it
|
|
11
|
+
|
|
12
|
+
The TheoKit app boots this service automatically via `pnpm dev` (per `theo.config.ts > services`).
|
|
13
|
+
|
|
14
|
+
To run standalone:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
cd services/agent-node
|
|
18
|
+
pnpm install
|
|
19
|
+
pnpm dev
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Endpoints
|
|
23
|
+
|
|
24
|
+
- `GET /health` — healthcheck (returns `{"status":"ok"}`)
|
|
25
|
+
- `POST /echo` — example: `{ "message": "..." }` → `{ "echo": "..." }`
|
|
26
|
+
|
|
27
|
+
## What is wired
|
|
28
|
+
|
|
29
|
+
- Native fetch handler via Hono (works on TheoCloud and local)
|
|
30
|
+
- JSON-line stdout logs
|
|
31
|
+
- W3C `traceparent` propagation from incoming headers
|
|
32
|
+
- TheoKit injects `THEOKIT_SERVICE_NAME` + `THEOKIT_SERVICE_PORT` env vars
|
|
33
|
+
|
|
34
|
+
## Add a tool the TheoKit agent can call
|
|
35
|
+
|
|
36
|
+
Add another `app.post('/tool/<name>', ...)` handler. From the TheoKit TS side,
|
|
37
|
+
`services.worker.<name>({...})` is auto-typed when an OpenAPI URL is reachable
|
|
38
|
+
(Hey API integration — Phase 5).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}-agent-node",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "tsx watch src/index.ts",
|
|
7
|
+
"start": "tsx src/index.ts",
|
|
8
|
+
"build": "echo 'no build step; tsx runs TS directly'"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"hono": "^4.6.0",
|
|
12
|
+
"@hono/node-server": "^1.13.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"tsx": "^4.19.0",
|
|
16
|
+
"typescript": "^5.7.0"
|
|
17
|
+
}
|
|
18
|
+
}
|