create-theokit 0.4.0-beta.0 → 0.5.0
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 +8 -4
- package/templates/default/.env.example +5 -0
- package/templates/default/README.md.tmpl +71 -57
- package/templates/default/_gitignore +2 -3
- package/templates/default/app/layout.tsx +51 -82
- package/templates/default/app/page.tsx +169 -271
- package/templates/default/app.ts +23 -0
- package/templates/default/package.json.tmpl +10 -23
- package/templates/default/server/agents/assistant.agent.ts +46 -0
- package/templates/default/server/controllers/tasks.controller.ts +70 -0
- package/templates/default/server/filters/http-error.filter.ts +20 -0
- package/templates/default/server/guards/auth.guard.ts +47 -0
- package/templates/default/server/interceptors/timing.interceptor.ts +14 -0
- package/templates/default/server/middleware/logger.middleware.ts +12 -0
- package/templates/default/server/store.ts +46 -0
- package/templates/default/server/toolboxes/task.tools.ts +58 -0
- package/templates/default/tsconfig.json +7 -7
- package/LICENSE +0 -201
- package/templates/api-only/.nvmrc +0 -1
- package/templates/api-only/README.md.tmpl +0 -78
- package/templates/api-only/_gitignore +0 -5
- package/templates/api-only/app/page.tsx +0 -3
- package/templates/api-only/index.html +0 -12
- package/templates/api-only/package.json.tmpl +0 -28
- package/templates/api-only/public/.gitkeep +0 -0
- package/templates/api-only/public/favicon.ico +0 -0
- package/templates/api-only/server/routes/health.ts +0 -5
- package/templates/api-only/server/routes/users.ts +0 -27
- package/templates/api-only/server/routes/webhooks/echo.ts +0 -34
- package/templates/api-only/theo.config.ts +0 -3
- package/templates/api-only/tsconfig.json +0 -15
- package/templates/dashboard/.nvmrc +0 -1
- package/templates/dashboard/README.md.tmpl +0 -76
- package/templates/dashboard/_gitignore +0 -5
- package/templates/dashboard/app/about/page.tsx +0 -3
- package/templates/dashboard/app/dashboard/layout.tsx +0 -10
- package/templates/dashboard/app/dashboard/page.tsx +0 -3
- package/templates/dashboard/app/layout.tsx +0 -14
- package/templates/dashboard/app/page.tsx +0 -8
- package/templates/dashboard/index.html +0 -12
- package/templates/dashboard/package.json.tmpl +0 -28
- package/templates/dashboard/public/.gitkeep +0 -0
- package/templates/dashboard/public/favicon.ico +0 -0
- package/templates/dashboard/server/crons/cleanup-conversations.ts +0 -59
- package/templates/dashboard/server/routes/health.ts +0 -5
- package/templates/dashboard/theo.config.ts +0 -3
- package/templates/dashboard/tsconfig.json +0 -15
- package/templates/default/.nvmrc +0 -1
- package/templates/default/index.html +0 -12
- package/templates/default/public/.gitkeep +0 -0
- package/templates/default/public/favicon.ico +0 -0
- package/templates/default/server/crons/cleanup-conversations.ts +0 -59
- package/templates/default/server/routes/chat.ts +0 -69
- package/templates/default/server/routes/health.ts +0 -5
- package/templates/default/theo.config.ts +0 -3
- package/templates/default/types/jobs.d.ts +0 -25
- package/templates/postgres/.env.example +0 -5
- package/templates/postgres/.nvmrc +0 -1
- package/templates/postgres/README.md.tmpl +0 -83
- package/templates/postgres/_gitignore +0 -5
- package/templates/postgres/app/layout.tsx +0 -14
- package/templates/postgres/app/page.tsx +0 -8
- package/templates/postgres/db/index.ts +0 -7
- package/templates/postgres/db/schema.ts +0 -8
- package/templates/postgres/drizzle.config.ts +0 -10
- package/templates/postgres/index.html +0 -12
- package/templates/postgres/package.json.tmpl +0 -36
- package/templates/postgres/public/.gitkeep +0 -0
- package/templates/postgres/public/favicon.ico +0 -0
- package/templates/postgres/server/context.ts +0 -5
- package/templates/postgres/server/jobs/log-message.ts +0 -26
- package/templates/postgres/server/routes/health.ts +0 -5
- package/templates/postgres/server/routes/users.ts +0 -22
- package/templates/postgres/theo.config.ts +0 -3
- package/templates/postgres/tsconfig.json +0 -15
- package/templates/saas/.env.example +0 -7
- package/templates/saas/.nvmrc +0 -1
- package/templates/saas/README.md.tmpl +0 -103
- package/templates/saas/_gitignore +0 -5
- package/templates/saas/app/layout.tsx +0 -5
- package/templates/saas/app/page.tsx +0 -104
- package/templates/saas/db/index.ts +0 -6
- package/templates/saas/db/schema.ts +0 -20
- package/templates/saas/drizzle.config.ts +0 -10
- package/templates/saas/index.html +0 -12
- package/templates/saas/package.json.tmpl +0 -38
- package/templates/saas/public/.gitkeep +0 -0
- package/templates/saas/public/favicon.ico +0 -0
- package/templates/saas/server/context.ts +0 -37
- package/templates/saas/server/routes/agent.ts +0 -49
- package/templates/saas/server/routes/billing/stripe-webhook.ts +0 -49
- package/templates/saas/server/routes/login.ts +0 -25
- package/templates/saas/server/routes/logout.ts +0 -10
- package/templates/saas/server/routes/me.ts +0 -10
- package/templates/saas/theo.config.ts +0 -5
- package/templates/saas/tsconfig.json +0 -15
- package/templates/services/agent-node/Dockerfile.tmpl +0 -20
- package/templates/services/agent-node/README.md +0 -38
- package/templates/services/agent-node/package.json.tmpl +0 -18
- package/templates/services/agent-node/src/index.ts +0 -58
- package/templates/services/agent-node/tsconfig.json +0 -13
- package/templates/services/agent-python/Dockerfile.tmpl +0 -20
- package/templates/services/agent-python/README.md +0 -37
- package/templates/services/agent-python/main.py +0 -77
- package/templates/services/agent-python/pyproject.toml.tmpl +0 -16
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# {{name}}
|
|
2
|
-
|
|
3
|
-
TheoKit dashboard project. Build the app your agent lives in — with nested layouts and a sidebar wired from day one.
|
|
4
|
-
|
|
5
|
-
> 📚 **Full docs:** https://docs.theokit.dev
|
|
6
|
-
|
|
7
|
-
## Quick start
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
# 1. Set your provider key (OpenRouter recommended — one key, any model)
|
|
11
|
-
echo 'OPENROUTER_API_KEY=sk-or-v1-...' > .env
|
|
12
|
-
|
|
13
|
-
# 2. Boot the dev server
|
|
14
|
-
npx theokit dev
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Open the printed URL. The default surface is a dashboard shell with sidebar nav + content area, ready to host your agent panels.
|
|
18
|
-
|
|
19
|
-
## Templates
|
|
20
|
-
|
|
21
|
-
- **default** — TheoUI chat composer + agent route.
|
|
22
|
-
- **dashboard** (this one) — nested layouts + sidebar nav.
|
|
23
|
-
- **api-only** — server routes without React.
|
|
24
|
-
- **postgres** — Drizzle ORM + migrations.
|
|
25
|
-
- **saas** — full app with auth, billing, sessions.
|
|
26
|
-
|
|
27
|
-
## What the framework auto-loads
|
|
28
|
-
|
|
29
|
-
- **`.env` → `process.env`**. Edit `.env`; restart the dev server.
|
|
30
|
-
- **`.theo/` build output cleanup** on every `theokit build`.
|
|
31
|
-
- **Tailwind + `@theokit/ui` styling** auto-configured for the TheoUI surface.
|
|
32
|
-
|
|
33
|
-
## Project structure
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
app/ Frontend (file-based routing with nested layouts)
|
|
37
|
-
├── layout.tsx root wrapper — TheoUI provider + theme
|
|
38
|
-
├── page.tsx / — dashboard home
|
|
39
|
-
├── dashboard/
|
|
40
|
-
│ ├── layout.tsx /dashboard/* — sidebar shell
|
|
41
|
-
│ └── page.tsx /dashboard — primary panel
|
|
42
|
-
server/ Backend (explicit routes)
|
|
43
|
-
├── routes/
|
|
44
|
-
│ └── health.ts GET /api/health
|
|
45
|
-
theo.config.ts Framework config
|
|
46
|
-
tailwind.config.ts Tailwind theme tokens
|
|
47
|
-
.env Secrets — never committed
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Common commands
|
|
51
|
-
|
|
52
|
-
| Command | What it does |
|
|
53
|
-
|---|---|
|
|
54
|
-
| `npx theokit dev` | Dev server with HMR + devtools overlay |
|
|
55
|
-
| `npx theokit build` | Production build → `.theo/` |
|
|
56
|
-
| `npx theokit start` | Serve the production build |
|
|
57
|
-
| `npx theokit check` | Lint for upgrade-readiness |
|
|
58
|
-
| `npx theokit routes` | List all routes + actions detected |
|
|
59
|
-
| `npm run typecheck` | TypeScript strict check (no emit) |
|
|
60
|
-
|
|
61
|
-
## Add a new panel
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
mkdir -p app/dashboard/billing
|
|
65
|
-
cat > app/dashboard/billing/page.tsx <<'EOF'
|
|
66
|
-
export default function BillingPage() {
|
|
67
|
-
return <h2>Billing</h2>
|
|
68
|
-
}
|
|
69
|
-
EOF
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
The route appears at `/dashboard/billing` after HMR.
|
|
73
|
-
|
|
74
|
-
## License
|
|
75
|
-
|
|
76
|
-
Apply your own. The TheoKit framework is Apache-2.0.
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Outlet } from 'react-router'
|
|
2
|
-
|
|
3
|
-
export default function RootLayout() {
|
|
4
|
-
return (
|
|
5
|
-
<div>
|
|
6
|
-
<nav>
|
|
7
|
-
<a href="/">Home</a> | <a href="/about">About</a> | <a href="/dashboard">Dashboard</a>
|
|
8
|
-
</nav>
|
|
9
|
-
<main>
|
|
10
|
-
<Outlet />
|
|
11
|
-
</main>
|
|
12
|
-
</div>
|
|
13
|
-
)
|
|
14
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Theo App</title>
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
<div id="root"></div>
|
|
10
|
-
<script type="module" src="/@theo/entry-client"></script>
|
|
11
|
-
</body>
|
|
12
|
-
</html>
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "{{name}}",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"type": "module",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"dev": "theokit dev",
|
|
8
|
-
"build": "theokit build",
|
|
9
|
-
"start": "theokit start",
|
|
10
|
-
"typecheck": "tsc --noEmit"
|
|
11
|
-
},
|
|
12
|
-
"dependencies": {
|
|
13
|
-
"theokit": "^0.4.0-beta.0",
|
|
14
|
-
"react": "^19.0.0",
|
|
15
|
-
"react-dom": "^19.0.0"
|
|
16
|
-
},
|
|
17
|
-
"devDependencies": {
|
|
18
|
-
"@types/node": "^22.10.0",
|
|
19
|
-
"typescript": "^5.7.0",
|
|
20
|
-
"@types/react": "^19.0.0",
|
|
21
|
-
"@types/react-dom": "^19.0.0"
|
|
22
|
-
},
|
|
23
|
-
"pnpm": {
|
|
24
|
-
"onlyBuiltDependencies": [
|
|
25
|
-
"esbuild"
|
|
26
|
-
]
|
|
27
|
-
}
|
|
28
|
-
}
|
|
File without changes
|
|
Binary file
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { defineCron } from 'theokit/server/cron'
|
|
2
|
-
import { readdir, stat, rm } from 'node:fs/promises'
|
|
3
|
-
import type { Dirent } from 'node:fs'
|
|
4
|
-
import { join, resolve } from 'node:path'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Daily GC of stale conversation transcripts.
|
|
8
|
-
*
|
|
9
|
-
* The `@theokit/sdk` Agent persists chat history under
|
|
10
|
-
* `.theokit/agents/<agentId>/messages.jsonl`. With no TTL the directory
|
|
11
|
-
* grows unbounded — production foot-gun. This cron removes any agent
|
|
12
|
-
* directory whose `messages.jsonl` hasn't been touched in 30 days.
|
|
13
|
-
*/
|
|
14
|
-
const MAX_AGE_DAYS = 30
|
|
15
|
-
const AGENTS_DIR = '.theokit/agents'
|
|
16
|
-
|
|
17
|
-
export default defineCron('cleanup-conversations', {
|
|
18
|
-
schedule: '0 4 * * *', // Daily 04:00 UTC
|
|
19
|
-
handler: async ({ traceId }) => {
|
|
20
|
-
const root = resolve(process.cwd(), AGENTS_DIR)
|
|
21
|
-
const cutoff = Date.now() - MAX_AGE_DAYS * 24 * 60 * 60 * 1000
|
|
22
|
-
let removed = 0
|
|
23
|
-
let kept = 0
|
|
24
|
-
let entries: Dirent[]
|
|
25
|
-
try {
|
|
26
|
-
entries = (await readdir(root, { withFileTypes: true })) as unknown as Dirent[]
|
|
27
|
-
} catch {
|
|
28
|
-
console.info(JSON.stringify({ msg: 'No agents dir yet — first run', dir: root, traceId }))
|
|
29
|
-
return
|
|
30
|
-
}
|
|
31
|
-
for (const entry of entries) {
|
|
32
|
-
if (!entry.isDirectory()) continue
|
|
33
|
-
const agentDir = join(root, String(entry.name))
|
|
34
|
-
const messagesFile = join(agentDir, 'messages.jsonl')
|
|
35
|
-
try {
|
|
36
|
-
const s = await stat(messagesFile)
|
|
37
|
-
if (s.mtimeMs < cutoff) {
|
|
38
|
-
await rm(agentDir, { recursive: true, force: true })
|
|
39
|
-
removed++
|
|
40
|
-
} else {
|
|
41
|
-
kept++
|
|
42
|
-
}
|
|
43
|
-
} catch {
|
|
44
|
-
// messages.jsonl missing → orphan dir, remove
|
|
45
|
-
await rm(agentDir, { recursive: true, force: true }).catch(() => {})
|
|
46
|
-
removed++
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
console.info(
|
|
50
|
-
JSON.stringify({
|
|
51
|
-
msg: 'cleanup-conversations complete',
|
|
52
|
-
removed,
|
|
53
|
-
kept,
|
|
54
|
-
maxAgeDays: MAX_AGE_DAYS,
|
|
55
|
-
traceId,
|
|
56
|
-
}),
|
|
57
|
-
)
|
|
58
|
-
},
|
|
59
|
-
})
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"strict": true,
|
|
7
|
-
"noEmit": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"jsx": "react-jsx",
|
|
11
|
-
"isolatedModules": true,
|
|
12
|
-
"resolveJsonModule": true
|
|
13
|
-
},
|
|
14
|
-
"include": ["app/**/*.ts", "app/**/*.tsx", "server/**/*.ts"]
|
|
15
|
-
}
|
package/templates/default/.nvmrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
22.12
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Theo App</title>
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
<div id="root"></div>
|
|
10
|
-
<script type="module" src="/@theo/entry-client"></script>
|
|
11
|
-
</body>
|
|
12
|
-
</html>
|
|
File without changes
|
|
Binary file
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { defineCron } from 'theokit/server/cron'
|
|
2
|
-
import { readdir, stat, rm } from 'node:fs/promises'
|
|
3
|
-
import type { Dirent } from 'node:fs'
|
|
4
|
-
import { join, resolve } from 'node:path'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Daily GC of stale conversation transcripts.
|
|
8
|
-
*
|
|
9
|
-
* The `@theokit/sdk` Agent persists chat history under
|
|
10
|
-
* `.theokit/agents/<agentId>/messages.jsonl`. With no TTL the directory
|
|
11
|
-
* grows unbounded — production foot-gun. This cron removes any agent
|
|
12
|
-
* directory whose `messages.jsonl` hasn't been touched in 30 days.
|
|
13
|
-
*/
|
|
14
|
-
const MAX_AGE_DAYS = 30
|
|
15
|
-
const AGENTS_DIR = '.theokit/agents'
|
|
16
|
-
|
|
17
|
-
export default defineCron('cleanup-conversations', {
|
|
18
|
-
schedule: '0 4 * * *', // Daily 04:00 UTC
|
|
19
|
-
handler: async ({ traceId }) => {
|
|
20
|
-
const root = resolve(process.cwd(), AGENTS_DIR)
|
|
21
|
-
const cutoff = Date.now() - MAX_AGE_DAYS * 24 * 60 * 60 * 1000
|
|
22
|
-
let removed = 0
|
|
23
|
-
let kept = 0
|
|
24
|
-
let entries: Dirent[]
|
|
25
|
-
try {
|
|
26
|
-
entries = (await readdir(root, { withFileTypes: true })) as unknown as Dirent[]
|
|
27
|
-
} catch {
|
|
28
|
-
console.info(JSON.stringify({ msg: 'No agents dir yet — first run', dir: root, traceId }))
|
|
29
|
-
return
|
|
30
|
-
}
|
|
31
|
-
for (const entry of entries) {
|
|
32
|
-
if (!entry.isDirectory()) continue
|
|
33
|
-
const agentDir = join(root, String(entry.name))
|
|
34
|
-
const messagesFile = join(agentDir, 'messages.jsonl')
|
|
35
|
-
try {
|
|
36
|
-
const s = await stat(messagesFile)
|
|
37
|
-
if (s.mtimeMs < cutoff) {
|
|
38
|
-
await rm(agentDir, { recursive: true, force: true })
|
|
39
|
-
removed++
|
|
40
|
-
} else {
|
|
41
|
-
kept++
|
|
42
|
-
}
|
|
43
|
-
} catch {
|
|
44
|
-
// messages.jsonl missing → orphan dir, remove
|
|
45
|
-
await rm(agentDir, { recursive: true, force: true }).catch(() => {})
|
|
46
|
-
removed++
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
console.info(
|
|
50
|
-
JSON.stringify({
|
|
51
|
-
msg: 'cleanup-conversations complete',
|
|
52
|
-
removed,
|
|
53
|
-
kept,
|
|
54
|
-
maxAgeDays: MAX_AGE_DAYS,
|
|
55
|
-
traceId,
|
|
56
|
-
}),
|
|
57
|
-
)
|
|
58
|
-
},
|
|
59
|
-
})
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod'
|
|
2
|
-
import {
|
|
3
|
-
defineAgentEndpoint,
|
|
4
|
-
defineAgentTool,
|
|
5
|
-
streamAgentRun,
|
|
6
|
-
createConversationHistory,
|
|
7
|
-
type AgentEvent,
|
|
8
|
-
} from 'theokit/server'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Chat agent endpoint — persistent conversation via createConversationHistory.
|
|
12
|
-
*
|
|
13
|
-
* Each browser tab gets a stable conversation id cookie on first visit;
|
|
14
|
-
* subsequent requests resume the same agent. Conversation turns auto-persist
|
|
15
|
-
* in `<cwd>/.theokit/agents/<conversationId>/messages.jsonl` (SDK owns
|
|
16
|
-
* storage). Tools: current_time example. Memory facts: opt-in via
|
|
17
|
-
* options.memory (off by default).
|
|
18
|
-
*
|
|
19
|
-
* Provider: OPENROUTER_API_KEY (preferred — gateway to many models) OR
|
|
20
|
-
* ANTHROPIC_API_KEY (direct Anthropic).
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
const currentTime = defineAgentTool({
|
|
24
|
-
name: 'current_time',
|
|
25
|
-
description: 'Get the current ISO timestamp on the server.',
|
|
26
|
-
inputSchema: z.object({}),
|
|
27
|
-
handler: () => new Date().toISOString(),
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
export const POST = defineAgentEndpoint({
|
|
31
|
-
async *handler({ body, request, cookieHeaders, signal }): AsyncGenerator<AgentEvent> {
|
|
32
|
-
const safeBody =
|
|
33
|
-
body !== null && typeof body === 'object' && !Array.isArray(body)
|
|
34
|
-
? (body as { message?: string })
|
|
35
|
-
: {}
|
|
36
|
-
const { message = '' } = safeBody
|
|
37
|
-
// Provider resolution centralizada (Strategy pattern) — theokit/server resolve
|
|
38
|
-
// apiKey + baseUrl + provider automático via OPENROUTER_API_KEY / OPENAI_API_KEY /
|
|
39
|
-
// ANTHROPIC_API_KEY presente no env. Wire protocol: OpenAI Chat Completions
|
|
40
|
-
// (universal — todos os providers implementam essa API). Consumer NÃO tem
|
|
41
|
-
// conditionals sobre provider — é responsabilidade do framework.
|
|
42
|
-
// Wrap full agent lifecycle in try/catch — provider errors (invalid KEY,
|
|
43
|
-
// 401, rate-limit, model-not-found, 5xx) MUST surface as AgentEvent
|
|
44
|
-
// 'error' so the client renders an actionable message instead of a
|
|
45
|
-
// silent SSE closure. Dogfood chaos Phase 12 validates this contract.
|
|
46
|
-
try {
|
|
47
|
-
const { agent } = await createConversationHistory({
|
|
48
|
-
request,
|
|
49
|
-
response: { headers: cookieHeaders },
|
|
50
|
-
options: {
|
|
51
|
-
// Model id is prefixed with the provider namespace. When using
|
|
52
|
-
// OPENROUTER_API_KEY (default), prefixes route to the correct
|
|
53
|
-
// upstream — `openai/`, `anthropic/`, `google/`, `meta-llama/`,
|
|
54
|
-
// `mistralai/`, `groq/`, etc. See https://openrouter.ai/models.
|
|
55
|
-
// Without the prefix the SDK falls back to a stub response.
|
|
56
|
-
model: { id: 'openai/gpt-4o-mini' },
|
|
57
|
-
tools: [currentTime],
|
|
58
|
-
},
|
|
59
|
-
})
|
|
60
|
-
const run = await agent.send(message, { signal })
|
|
61
|
-
yield* streamAgentRun(run)
|
|
62
|
-
// Intentionally NO agent.dispose() — the agent stays registered so the
|
|
63
|
-
// next request from the same conversation resumes it (continuity).
|
|
64
|
-
} catch (err) {
|
|
65
|
-
const msg = err instanceof Error ? err.message : String(err)
|
|
66
|
-
yield { type: 'error', message: `Agent error: ${msg}` }
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
})
|
|
@@ -1,25 +0,0 @@
|
|
|
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 {}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
22.12
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# {{name}}
|
|
2
|
-
|
|
3
|
-
TheoKit project with Postgres + Drizzle ORM wired. Schema-first, migration-aware, typed end-to-end.
|
|
4
|
-
|
|
5
|
-
> 📚 **Full docs:** https://docs.theokit.dev
|
|
6
|
-
|
|
7
|
-
## Quick start
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
# 0. Provision Postgres
|
|
11
|
-
# Option A — local docker (one-liner):
|
|
12
|
-
docker run --name pg -e POSTGRES_PASSWORD=dev -p 5432:5432 -d postgres:16
|
|
13
|
-
# Option B — hosted: neon.tech, supabase.com, fly.io
|
|
14
|
-
|
|
15
|
-
# 1. Set env
|
|
16
|
-
cat > .env <<'EOF'
|
|
17
|
-
DATABASE_URL=postgres://postgres:dev@localhost:5432/postgres
|
|
18
|
-
OPENROUTER_API_KEY=sk-or-v1-...
|
|
19
|
-
EOF
|
|
20
|
-
|
|
21
|
-
# 2. Generate + apply migrations
|
|
22
|
-
pnpm db:generate
|
|
23
|
-
pnpm db:migrate
|
|
24
|
-
|
|
25
|
-
# 3. Boot the dev server
|
|
26
|
-
npx theokit dev
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Open the printed URL. The default surface includes a sample users API backed by Postgres.
|
|
30
|
-
|
|
31
|
-
## Templates
|
|
32
|
-
|
|
33
|
-
- **default** — TheoUI chat composer + agent route.
|
|
34
|
-
- **dashboard** — nested layouts + sidebar.
|
|
35
|
-
- **api-only** — server routes without React.
|
|
36
|
-
- **postgres** (this one) — Drizzle ORM + migrations.
|
|
37
|
-
- **saas** — full app with auth, billing, sessions.
|
|
38
|
-
|
|
39
|
-
## What the framework auto-loads
|
|
40
|
-
|
|
41
|
-
- **`.env` → `process.env`**. `DATABASE_URL` must be set before `pnpm db:migrate`.
|
|
42
|
-
- **`.theo/` build output cleanup** on every `theokit build`.
|
|
43
|
-
- **Drizzle schema** under `db/schema.ts` drives migrations + typed query builder.
|
|
44
|
-
|
|
45
|
-
## Project structure
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
app/ Frontend
|
|
49
|
-
├── page.tsx / — sample UI
|
|
50
|
-
server/
|
|
51
|
-
├── routes/
|
|
52
|
-
│ ├── health.ts GET /api/health
|
|
53
|
-
│ └── users.ts CRUD /api/users — backed by db.users
|
|
54
|
-
db/
|
|
55
|
-
├── schema.ts Drizzle schema (tables + relations)
|
|
56
|
-
├── client.ts Drizzle client (used by routes)
|
|
57
|
-
└── migrations/ Generated SQL files (committed)
|
|
58
|
-
drizzle.config.ts Drizzle CLI config
|
|
59
|
-
theo.config.ts Framework config
|
|
60
|
-
.env Secrets — never committed
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Common commands
|
|
64
|
-
|
|
65
|
-
| Command | What it does |
|
|
66
|
-
|---|---|
|
|
67
|
-
| `npx theokit dev` | Dev server with HMR |
|
|
68
|
-
| `npx theokit build` | Production build |
|
|
69
|
-
| `npx theokit start` | Serve production build |
|
|
70
|
-
| `pnpm db:generate` | Generate SQL migration from `db/schema.ts` |
|
|
71
|
-
| `pnpm db:migrate` | Apply pending migrations to `DATABASE_URL` |
|
|
72
|
-
| `pnpm db:studio` | Open Drizzle Studio UI |
|
|
73
|
-
| `npm run typecheck` | TypeScript strict check |
|
|
74
|
-
|
|
75
|
-
## Troubleshooting
|
|
76
|
-
|
|
77
|
-
- **`pnpm db:migrate` fails with "ECONNREFUSED"** → check `DATABASE_URL` host:port + Postgres is running (`docker ps` or hosted dashboard).
|
|
78
|
-
- **`relation "users" does not exist`** → you forgot `pnpm db:migrate`. Run it.
|
|
79
|
-
- **Schema change not reflected** → `pnpm db:generate` first, then `pnpm db:migrate`.
|
|
80
|
-
|
|
81
|
-
## License
|
|
82
|
-
|
|
83
|
-
Apply your own. The TheoKit framework is Apache-2.0.
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core'
|
|
2
|
-
|
|
3
|
-
export const users = pgTable('users', {
|
|
4
|
-
id: uuid('id').primaryKey().defaultRandom(),
|
|
5
|
-
name: text('name').notNull(),
|
|
6
|
-
email: text('email').notNull().unique(),
|
|
7
|
-
createdAt: timestamp('created_at').defaultNow().notNull(),
|
|
8
|
-
})
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Theo App</title>
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
<div id="root"></div>
|
|
10
|
-
<script type="module" src="/@theo/entry-client"></script>
|
|
11
|
-
</body>
|
|
12
|
-
</html>
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "{{name}}",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"type": "module",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"dev": "theokit dev",
|
|
8
|
-
"build": "theokit build",
|
|
9
|
-
"start": "theokit start",
|
|
10
|
-
"typecheck": "tsc --noEmit",
|
|
11
|
-
"db:push": "drizzle-kit push",
|
|
12
|
-
"db:generate": "drizzle-kit generate",
|
|
13
|
-
"db:migrate": "drizzle-kit migrate",
|
|
14
|
-
"db:studio": "drizzle-kit studio"
|
|
15
|
-
},
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"theokit": "^0.4.0-beta.0",
|
|
18
|
-
"react": "^19.0.0",
|
|
19
|
-
"react-dom": "^19.0.0",
|
|
20
|
-
"drizzle-orm": "^0.45.0",
|
|
21
|
-
"postgres": "^3.4.0",
|
|
22
|
-
"zod": "^3.24.0"
|
|
23
|
-
},
|
|
24
|
-
"devDependencies": {
|
|
25
|
-
"@types/node": "^22.10.0",
|
|
26
|
-
"typescript": "^5.7.0",
|
|
27
|
-
"@types/react": "^19.0.0",
|
|
28
|
-
"@types/react-dom": "^19.0.0",
|
|
29
|
-
"drizzle-kit": "^0.31.0"
|
|
30
|
-
},
|
|
31
|
-
"pnpm": {
|
|
32
|
-
"onlyBuiltDependencies": [
|
|
33
|
-
"esbuild"
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
}
|
|
File without changes
|
|
Binary file
|