create-patties 0.0.6 → 0.0.8
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/CHANGELOG.md +52 -0
- package/README.md +53 -0
- package/bin/create-patties.ts +7 -1
- package/package.json +7 -3
- package/src/index.ts +143 -25
- package/src/probes.ts +28 -0
- package/src/prompts.ts +98 -0
- package/src/readme.ts +67 -0
- package/templates/_claude/.claude/hooks/biome-check.sh +17 -0
- package/templates/_claude/.claude/rules/build-time-discovery.md +17 -0
- package/templates/_claude/.claude/rules/bun-native.md +28 -0
- package/templates/_claude/.claude/rules/filesystem-routing.md +31 -0
- package/templates/_claude/.claude/rules/islands.md +32 -0
- package/templates/_claude/.claude/rules/optional-ai.md +15 -0
- package/templates/_claude/.claude/rules/web-standards-boundary.md +25 -0
- package/templates/_claude/.claude/settings.json +18 -1
- package/templates/_claude/.claude/skills/patties-cli/SKILL.md +113 -0
- package/templates/_claude/CLAUDE.md +16 -51
- package/templates/_codex/.codex/README.md +10 -0
- package/templates/_codex/.codex/rules/build-time-discovery.md +17 -0
- package/templates/_codex/.codex/rules/bun-native.md +28 -0
- package/templates/_codex/.codex/rules/filesystem-routing.md +31 -0
- package/templates/_codex/.codex/rules/islands.md +32 -0
- package/templates/_codex/.codex/rules/optional-ai.md +15 -0
- package/templates/_codex/.codex/rules/patties-cli.md +113 -0
- package/templates/_codex/.codex/rules/web-standards-boundary.md +25 -0
- package/templates/_codex/AGENTS.md +21 -41
- package/templates/default/README-template.md +160 -6
- package/templates/default/app/islands/TodoApp.tsx +83 -0
- package/templates/default/app/routes/index.tsx +14 -3
- package/templates/default/app/server.ts +25 -0
- package/templates/default/app/islands/Counter.tsx +0 -12
|
@@ -1,48 +1,28 @@
|
|
|
1
|
-
# {{
|
|
1
|
+
# {{name}}
|
|
2
2
|
|
|
3
|
-
Built with Patties — Bun-native full-stack meta-framework.
|
|
3
|
+
Built with Patties — a Bun-native full-stack meta-framework.
|
|
4
4
|
|
|
5
|
-
>
|
|
6
|
-
>
|
|
7
|
-
>
|
|
8
|
-
> and conventions.
|
|
5
|
+
> Codex reads this file. The conventions below are split into focused
|
|
6
|
+
> files under `.codex/rules/`; treat the links here as authoritative —
|
|
7
|
+
> open each one when its topic is in scope for the task at hand.
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## Conventions
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
- [Bun-native](.codex/rules/bun-native.md) — reach for Bun primitives, not Node-era replacements.
|
|
12
|
+
- [Web-standards boundary](.codex/rules/web-standards-boundary.md) — handlers use standard Request / Response; `PattiesContext` stays thin.
|
|
13
|
+
- [Filesystem routing](.codex/rules/filesystem-routing.md) — how `app/routes/` becomes URLs.
|
|
14
|
+
- [Islands](.codex/rules/islands.md) — when and how to use `app/islands/*.tsx`.
|
|
15
|
+
- [Build-time discovery](.codex/rules/build-time-discovery.md) — discovery happens at build time, not at request time.
|
|
16
|
+
- [Optional AI dependency](.codex/rules/optional-ai.md) — keep `@anthropic-ai/sdk` import-disjoint from non-AI code paths.
|
|
17
|
+
- [Patties CLI](.codex/rules/patties-cli.md) — `patties dev / build / start / deploy / secret`.
|
|
13
18
|
|
|
14
|
-
##
|
|
19
|
+
## Live inventory
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
| `app/routes/hotels/[city].tsx` | `/hotels/:city` |
|
|
21
|
-
| `app/routes/api/revenue.ts` | `/api/revenue` |
|
|
22
|
-
| `app/islands/counter.tsx` | interactive island `Counter` |
|
|
23
|
-
| `app/agents/booking.ts` | agent `booking` |
|
|
24
|
-
| `app/tools/search.ts` | MCP tool `search` |
|
|
25
|
-
| `app/middleware.ts` | global middleware |
|
|
26
|
-
| `patties.config.ts` | framework config |
|
|
21
|
+
The block below is regenerated by `patties build` from the actual
|
|
22
|
+
contents of `app/`. Hand-edited content above the
|
|
23
|
+
`<!-- patties:generated -->` marker is preserved across regenerations;
|
|
24
|
+
everything below it is owned by the generator.
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
1. Never import from `"next"`.
|
|
33
|
-
2. Never use Node.js `http`, `fs.watch`, or `chokidar`. Use `Bun.serve` and `bun --watch`.
|
|
34
|
-
3. Never use webpack or vite. Use `Bun.build`.
|
|
35
|
-
4. Use React for rendering. Server: `react-dom/server.renderToReadableStream`. Client: `react-dom/client.hydrateRoot`. Never `renderToPipeableStream` or `renderToString`. Never `hono/jsx` or `hono/jsx/dom`.
|
|
36
|
-
5. `tsconfig.json` sets `"jsx": "react-jsx"` and `"jsxImportSource": "react"` — no manual `import React` in user code.
|
|
37
|
-
6. All routes are plain `(req: Request, ctx: PattiesContext) => Response | Promise<Response>`. Never import from `"hono"`.
|
|
38
|
-
7. Islands live in `app/islands/` — no exceptions.
|
|
39
|
-
8. API routes export named `GET`, `POST`, `PUT`, `DELETE` functions. Default exports are reserved for page components.
|
|
40
|
-
9. Middleware default-exports a `Middleware = (req, ctx, next) => Promise<Response>`. Never `MiddlewareHandler` from Hono.
|
|
41
|
-
10. Use Bun primitives for I/O: `Bun.file`, `Bun.write`, `Bun.spawn`, `Bun.CryptoHasher`, `Bun.env`, `Bun.password`, `bun:sqlite`, `Bun.sql`, `Bun.RedisClient`, `Bun.S3Client`. `node:fs` only when no Bun built-in exists.
|
|
42
|
-
|
|
43
|
-
## How to run
|
|
44
|
-
|
|
45
|
-
- `bun install`
|
|
46
|
-
- `bun dev` — start the dev server
|
|
47
|
-
- `bun build` — build for production
|
|
48
|
-
- `bun test`
|
|
26
|
+
<!-- patties:generated -->
|
|
27
|
+
<!-- The block below is rewritten by `patties build`. Do not edit by hand. -->
|
|
28
|
+
<!-- /patties:generated -->
|
|
@@ -1,16 +1,170 @@
|
|
|
1
|
-
#
|
|
1
|
+
# {{name}}
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Built with [Patties](https://github.com/bihaviour-ai/bun-patties-framework) — a
|
|
4
|
+
Bun-native full-stack meta-framework.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
<!-- if:scaffold=demo -->
|
|
7
|
+
## What you got
|
|
6
8
|
|
|
9
|
+
An interactive todo demo:
|
|
10
|
+
|
|
11
|
+
- `app/routes/index.tsx` — server-rendered page that mounts the island.
|
|
12
|
+
- `app/islands/TodoApp.tsx` — `useState`-based todo list, hydrated in the
|
|
13
|
+
browser.
|
|
14
|
+
- `app/server.ts` — dev entry that wires the router into `Bun.serve`.
|
|
15
|
+
|
|
16
|
+
## Run it
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
bun install # if you used --no-install
|
|
20
|
+
bun dev # → http://localhost:3000
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
> **Heads up — dev mode currently only does SSR.** The todo list will render
|
|
24
|
+
> but the buttons won't react to clicks under `bun dev`. To see the island
|
|
25
|
+
> hydrate and the demo actually work, build and serve:
|
|
26
|
+
>
|
|
27
|
+
> ```sh
|
|
28
|
+
> bun run build
|
|
29
|
+
> bun start
|
|
30
|
+
> ```
|
|
31
|
+
>
|
|
32
|
+
> Full dev-mode hydration is tracked under framework spec 18 and will land
|
|
33
|
+
> in a future Patties release — at that point `bun dev` will be enough.
|
|
34
|
+
|
|
35
|
+
## Try editing
|
|
36
|
+
|
|
37
|
+
1. Open `app/routes/index.tsx`, change the heading text, save. The browser
|
|
38
|
+
reloads (HMR).
|
|
39
|
+
2. Open `app/islands/TodoApp.tsx`, change the initial todo list or input
|
|
40
|
+
placeholder, save, rebuild with `bun run build && bun start`, and try it.
|
|
41
|
+
|
|
42
|
+
## Remove the demo when you're ready
|
|
43
|
+
|
|
44
|
+
The todo demo exists to show you state hydration. When you start your real
|
|
45
|
+
app, delete it:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
rm app/islands/TodoApp.tsx
|
|
7
49
|
```
|
|
8
|
-
|
|
9
|
-
|
|
50
|
+
|
|
51
|
+
Then replace `app/routes/index.tsx` with whatever your landing page should
|
|
52
|
+
be — a minimal version:
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
export default function Index(): JSX.Element {
|
|
56
|
+
return <main><h1>Hello from {{name}}</h1></main>;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If you don't need any islands at all, you can also delete the empty
|
|
61
|
+
`app/islands/` directory. You can re-scaffold without the demo at any time
|
|
62
|
+
using `bunx create-patties@latest <new-name> --blank`.
|
|
63
|
+
<!-- /if -->
|
|
64
|
+
<!-- if:scaffold=blank -->
|
|
65
|
+
## What you got
|
|
66
|
+
|
|
67
|
+
A minimal hello-world Patties app:
|
|
68
|
+
|
|
69
|
+
- `app/routes/index.tsx` — server-rendered landing page.
|
|
70
|
+
- `app/server.ts` — dev entry that wires the router into `Bun.serve`.
|
|
71
|
+
|
|
72
|
+
## Run it
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
bun install # if you used --no-install
|
|
76
|
+
bun dev # → http://localhost:3000
|
|
10
77
|
```
|
|
11
78
|
|
|
12
|
-
##
|
|
79
|
+
## Add your first interactive feature
|
|
80
|
+
|
|
81
|
+
Create `app/islands/` and drop in a component that uses `useState` or
|
|
82
|
+
`useEffect`. Import it from a route file under `app/routes/`. Islands hydrate
|
|
83
|
+
on the client; everything else runs server-only.
|
|
84
|
+
|
|
85
|
+
> Note: full dev-mode island hydration is tracked under framework spec 18
|
|
86
|
+
> and lands in a future Patties release. Until then, build + start to see
|
|
87
|
+
> islands react: `bun run build && bun start`.
|
|
88
|
+
<!-- /if -->
|
|
13
89
|
|
|
90
|
+
## Project layout
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
app/
|
|
94
|
+
routes/ # filesystem-routed pages and API handlers
|
|
95
|
+
islands/ # interactive client components
|
|
96
|
+
server.ts # dev entry — wires the router into Bun.serve
|
|
97
|
+
patties.config.ts
|
|
98
|
+
package.json
|
|
99
|
+
tsconfig.json
|
|
14
100
|
```
|
|
101
|
+
|
|
102
|
+
## Build for production
|
|
103
|
+
|
|
104
|
+
```sh
|
|
15
105
|
bun run build
|
|
16
106
|
```
|
|
107
|
+
|
|
108
|
+
Build artifacts land in `.patties/`. Run the server bundle with:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
bun .patties/server/server-entry.js
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
<!-- if:deploy=cloudflare -->
|
|
115
|
+
## Deploy
|
|
116
|
+
|
|
117
|
+
This project is configured for **Cloudflare** deployment. See the
|
|
118
|
+
`@patties/deploy-cloudflare` plugin docs for the next steps.
|
|
119
|
+
<!-- /if -->
|
|
120
|
+
<!-- if:deploy=vercel -->
|
|
121
|
+
## Deploy
|
|
122
|
+
|
|
123
|
+
This project is configured for **Vercel** deployment. See the
|
|
124
|
+
`@patties/deploy-vercel` plugin docs for the next steps.
|
|
125
|
+
<!-- /if -->
|
|
126
|
+
<!-- if:deploy=deno -->
|
|
127
|
+
## Deploy
|
|
128
|
+
|
|
129
|
+
This project is configured for **Deno Deploy**. See the
|
|
130
|
+
`@patties/deploy-deno` plugin docs for the next steps.
|
|
131
|
+
<!-- /if -->
|
|
132
|
+
<!-- if:deploy=netlify -->
|
|
133
|
+
## Deploy
|
|
134
|
+
|
|
135
|
+
This project is configured for **Netlify Edge**. See the
|
|
136
|
+
`@patties/deploy-netlify` plugin docs for the next steps.
|
|
137
|
+
<!-- /if -->
|
|
138
|
+
<!-- if:deploy=bun -->
|
|
139
|
+
## Deploy
|
|
140
|
+
|
|
141
|
+
This project ships as a standalone Bun bundle. Run `bun run build` then
|
|
142
|
+
deploy the contents of `.patties/` to any host that runs Bun.
|
|
143
|
+
<!-- /if -->
|
|
144
|
+
|
|
145
|
+
<!-- if:agent=claude -->
|
|
146
|
+
## Claude Code is set up
|
|
147
|
+
|
|
148
|
+
`CLAUDE.md` at the project root describes the framework conventions for Claude
|
|
149
|
+
Code. `.claude/settings.json` allow-lists the commands you'll typically need
|
|
150
|
+
(`bun`, `bunx`, `patties`). `.claude/hooks/biome-check.sh` runs Biome after
|
|
151
|
+
every edit if you install it (`bun add -d @biomejs/biome`).
|
|
152
|
+
|
|
153
|
+
Launch a session with `claude` in this directory.
|
|
154
|
+
<!-- /if -->
|
|
155
|
+
<!-- if:agent=codex -->
|
|
156
|
+
## Codex is set up
|
|
157
|
+
|
|
158
|
+
`AGENTS.md` at the project root describes the framework conventions for
|
|
159
|
+
Codex CLI and other AGENTS.md-aware tools. Patties regenerates this file on
|
|
160
|
+
`patties build` while preserving sections you mark with
|
|
161
|
+
`<!-- patties:user --> ... <!-- /patties:user -->`.
|
|
162
|
+
|
|
163
|
+
Launch a session with `codex` in this directory.
|
|
164
|
+
<!-- /if -->
|
|
165
|
+
|
|
166
|
+
## Learn more
|
|
167
|
+
|
|
168
|
+
- Patties docs: https://bun-patties.com
|
|
169
|
+
- Bun: https://bun.sh
|
|
170
|
+
- React 19: https://react.dev
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
|
|
5
|
+
interface Todo {
|
|
6
|
+
id: number;
|
|
7
|
+
text: string;
|
|
8
|
+
done: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function TodoApp(): JSX.Element {
|
|
12
|
+
const [todos, setTodos] = useState<Todo[]>([
|
|
13
|
+
{ id: 1, text: "edit app/routes/index.tsx", done: false },
|
|
14
|
+
{ id: 2, text: "edit app/islands/TodoApp.tsx", done: false },
|
|
15
|
+
{ id: 3, text: "delete this demo when you're ready", done: false },
|
|
16
|
+
]);
|
|
17
|
+
const [draft, setDraft] = useState("");
|
|
18
|
+
|
|
19
|
+
function add(): void {
|
|
20
|
+
const text = draft.trim();
|
|
21
|
+
if (!text) return;
|
|
22
|
+
setTodos([...todos, { id: Date.now(), text, done: false }]);
|
|
23
|
+
setDraft("");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function toggle(id: number): void {
|
|
27
|
+
setTodos(todos.map((t) => (t.id === id ? { ...t, done: !t.done } : t)));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function remove(id: number): void {
|
|
31
|
+
setTodos(todos.filter((t) => t.id !== id));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<section aria-label="Todo demo">
|
|
36
|
+
<form
|
|
37
|
+
onSubmit={(e) => {
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
add();
|
|
40
|
+
}}
|
|
41
|
+
>
|
|
42
|
+
<input
|
|
43
|
+
type="text"
|
|
44
|
+
value={draft}
|
|
45
|
+
onChange={(e) => setDraft(e.target.value)}
|
|
46
|
+
placeholder="What needs doing?"
|
|
47
|
+
aria-label="New todo"
|
|
48
|
+
/>
|
|
49
|
+
<button type="submit">Add</button>
|
|
50
|
+
</form>
|
|
51
|
+
<ul>
|
|
52
|
+
{todos.map((t) => (
|
|
53
|
+
<li key={t.id}>
|
|
54
|
+
<label>
|
|
55
|
+
<input
|
|
56
|
+
type="checkbox"
|
|
57
|
+
checked={t.done}
|
|
58
|
+
onChange={() => toggle(t.id)}
|
|
59
|
+
/>
|
|
60
|
+
<span
|
|
61
|
+
style={{ textDecoration: t.done ? "line-through" : "none" }}
|
|
62
|
+
>
|
|
63
|
+
{t.text}
|
|
64
|
+
</span>
|
|
65
|
+
</label>
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
onClick={() => remove(t.id)}
|
|
69
|
+
aria-label="Remove"
|
|
70
|
+
>
|
|
71
|
+
×
|
|
72
|
+
</button>
|
|
73
|
+
</li>
|
|
74
|
+
))}
|
|
75
|
+
</ul>
|
|
76
|
+
<p>
|
|
77
|
+
<small>
|
|
78
|
+
{todos.filter((t) => !t.done).length} of {todos.length} remaining
|
|
79
|
+
</small>
|
|
80
|
+
</p>
|
|
81
|
+
</section>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import TodoApp from "../islands/TodoApp.tsx";
|
|
2
2
|
|
|
3
3
|
export default function Index(): JSX.Element {
|
|
4
4
|
return (
|
|
5
5
|
<main>
|
|
6
|
-
<h1>
|
|
7
|
-
<
|
|
6
|
+
<h1>Welcome to Patties</h1>
|
|
7
|
+
<p>
|
|
8
|
+
This page is server-rendered. The list below is a client island —{" "}
|
|
9
|
+
<code>app/islands/TodoApp.tsx</code> — hydrated in the browser.
|
|
10
|
+
</p>
|
|
11
|
+
<TodoApp />
|
|
12
|
+
<hr />
|
|
13
|
+
<p>
|
|
14
|
+
<small>
|
|
15
|
+
When you're ready to start your real app, see the "Remove the demo"
|
|
16
|
+
section of <code>README.md</code>.
|
|
17
|
+
</small>
|
|
18
|
+
</p>
|
|
8
19
|
</main>
|
|
9
20
|
);
|
|
10
21
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DevServer } from "patties/dev";
|
|
2
|
+
import { createRenderer } from "patties/render";
|
|
3
|
+
import { createRouter } from "patties/router";
|
|
4
|
+
import { startServer } from "patties/server";
|
|
5
|
+
|
|
6
|
+
interface StartOpts {
|
|
7
|
+
devServer: DevServer;
|
|
8
|
+
port: number;
|
|
9
|
+
host: string;
|
|
10
|
+
appDir: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default async function start(opts: StartOpts): Promise<void> {
|
|
14
|
+
const renderer = createRenderer({ dev: true });
|
|
15
|
+
const router = await createRouter({ appDir: opts.appDir, renderer });
|
|
16
|
+
|
|
17
|
+
startServer({
|
|
18
|
+
port: opts.port,
|
|
19
|
+
hostname: opts.host,
|
|
20
|
+
dev: true,
|
|
21
|
+
devServer: opts.devServer,
|
|
22
|
+
routes: router.routes,
|
|
23
|
+
fallback: router.fallback,
|
|
24
|
+
});
|
|
25
|
+
}
|