@pylonsync/create-pylon 0.4.29 → 0.5.2
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/bin/create-pylon.js +27 -5
- package/package.json +1 -1
- package/templates/_root/AGENTS.md +1 -1
- package/templates/agency/AGENTS.md +1 -1
- package/templates/agency/app/llms.ts +31 -0
- package/templates/agency/app/not-found.tsx +44 -0
- package/templates/agency/app.ts +3 -0
- package/templates/ai-chat/AGENTS.md +1 -1
- package/templates/ai-chat/app/llms.ts +30 -0
- package/templates/ai-chat/app/not-found.tsx +44 -0
- package/templates/ai-chat/app/robots.ts +14 -0
- package/templates/ai-chat/app/sitemap.ts +11 -0
- package/templates/ai-chat/app.ts +3 -0
- package/templates/ai-studio/AGENTS.md +1 -1
- package/templates/ai-studio/app/llms.ts +30 -0
- package/templates/ai-studio/app/not-found.tsx +44 -0
- package/templates/ai-studio/app/robots.ts +14 -0
- package/templates/ai-studio/app/sitemap.ts +11 -0
- package/templates/ai-studio/app.ts +3 -0
- package/templates/backend/b2b/apps/api/schema.ts +3 -0
- package/templates/backend/barebones/apps/api/schema.ts +3 -0
- package/templates/backend/chat/apps/api/schema.ts +3 -0
- package/templates/backend/consumer/apps/api/schema.ts +3 -0
- package/templates/backend/todo/apps/api/schema.ts +3 -0
- package/templates/barebones/AGENTS.md +1 -1
- package/templates/barebones/app/llms.ts +30 -0
- package/templates/barebones/app.ts +3 -0
- package/templates/chat/AGENTS.md +1 -1
- package/templates/chat/app/llms.ts +30 -0
- package/templates/chat/app.ts +3 -0
- package/templates/consumer/AGENTS.md +1 -1
- package/templates/consumer/app/llms.ts +30 -0
- package/templates/consumer/app.ts +3 -0
- package/templates/creator/AGENTS.md +1 -1
- package/templates/creator/app/llms.ts +30 -0
- package/templates/creator/app/not-found.tsx +44 -0
- package/templates/creator/app.ts +3 -0
- package/templates/crm/AGENTS.md +1 -1
- package/templates/crm/app/llms.ts +32 -0
- package/templates/crm/app.ts +3 -0
- package/templates/directory/AGENTS.md +1 -1
- package/templates/directory/app/llms.ts +31 -0
- package/templates/directory/app/not-found.tsx +44 -0
- package/templates/directory/app.ts +3 -0
- package/templates/helpdesk/AGENTS.md +1 -1
- package/templates/helpdesk/app/llms.ts +31 -0
- package/templates/helpdesk/app.ts +3 -0
- package/templates/inventory/AGENTS.md +1 -1
- package/templates/inventory/app/llms.ts +31 -0
- package/templates/inventory/app.ts +3 -0
- package/templates/invoices/AGENTS.md +1 -1
- package/templates/invoices/app/llms.ts +31 -0
- package/templates/invoices/app.ts +3 -0
- package/templates/local-service/AGENTS.md +1 -1
- package/templates/local-service/app/llms.ts +30 -0
- package/templates/local-service/app/not-found.tsx +44 -0
- package/templates/local-service/app.ts +3 -0
- package/templates/marketplace/AGENTS.md +1 -1
- package/templates/marketplace/app/llms.ts +32 -0
- package/templates/marketplace/app.ts +3 -0
- package/templates/marketplace/client/market.ts +4 -1
- package/templates/projects/AGENTS.md +1 -1
- package/templates/projects/app/llms.ts +31 -0
- package/templates/projects/app.ts +3 -0
- package/templates/restaurant/AGENTS.md +1 -1
- package/templates/restaurant/app/llms.ts +30 -0
- package/templates/restaurant/app/not-found.tsx +44 -0
- package/templates/restaurant/app.ts +3 -0
- package/templates/saas/AGENTS.md +1 -1
- package/templates/saas/app/llms.ts +30 -0
- package/templates/saas/app/not-found.tsx +44 -0
- package/templates/saas/app.ts +3 -0
- package/templates/shop/AGENTS.md +1 -1
- package/templates/shop/app/llms.ts +31 -0
- package/templates/shop/app/not-found.tsx +44 -0
- package/templates/shop/app.ts +3 -0
- package/templates/todo/AGENTS.md +1 -1
- package/templates/todo/app/llms.ts +30 -0
- package/templates/todo/app.ts +3 -0
- package/templates/waitlist/AGENTS.md +1 -1
- package/templates/waitlist/app/llms.ts +30 -0
- package/templates/waitlist/app/not-found.tsx +44 -0
- package/templates/waitlist/app.ts +3 -0
package/bin/create-pylon.js
CHANGED
|
@@ -311,6 +311,28 @@ Examples:
|
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Prompt, treating Ctrl+D / Ctrl+C as a deliberate cancel.
|
|
317
|
+
*
|
|
318
|
+
* readline rejects the pending question with an AbortError, which at top
|
|
319
|
+
* level in an ESM script surfaces as an unhandled rejection — so someone who
|
|
320
|
+
* changes their mind at the template picker gets a Node stack trace instead
|
|
321
|
+
* of "cancelled". Nothing has been written to disk at this point, so say so
|
|
322
|
+
* and leave quietly.
|
|
323
|
+
*/
|
|
324
|
+
async function ask(question) {
|
|
325
|
+
try {
|
|
326
|
+
return await rl.question(question);
|
|
327
|
+
} catch (err) {
|
|
328
|
+
if (err?.code === "ABORT_ERR") {
|
|
329
|
+
stdout.write("\nCancelled — nothing was created.\n");
|
|
330
|
+
rl.close();
|
|
331
|
+
exit(0);
|
|
332
|
+
}
|
|
333
|
+
throw err;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
314
336
|
// Non-interactive stdin (CI, piped, `| npm create …`): never block on a prompt.
|
|
315
337
|
// Fall back to the same defaults the interactive path uses. The skill-install
|
|
316
338
|
// below already gates on `stdin.isTTY`; the INPUT prompts must too — without
|
|
@@ -319,7 +341,7 @@ const rl = createInterface({ input: stdin, output: stdout });
|
|
|
319
341
|
const isInteractive = !!stdin.isTTY;
|
|
320
342
|
if (!projectName) {
|
|
321
343
|
projectName =
|
|
322
|
-
(isInteractive ? (await
|
|
344
|
+
(isInteractive ? (await ask("Project name: ")).trim() : "") ||
|
|
323
345
|
"my-pylon-app";
|
|
324
346
|
}
|
|
325
347
|
if (!flags.template) {
|
|
@@ -329,7 +351,7 @@ if (!flags.template) {
|
|
|
329
351
|
.join("\n");
|
|
330
352
|
process.stdout.write(`\n${lines}\n`);
|
|
331
353
|
const ans = (
|
|
332
|
-
await
|
|
354
|
+
await ask(
|
|
333
355
|
`Template (${TEMPLATES_AVAILABLE.join(", ")}) [${DEFAULT_TEMPLATE}]: `,
|
|
334
356
|
)
|
|
335
357
|
)
|
|
@@ -352,7 +374,7 @@ if (!isUnified && !flags.platforms) {
|
|
|
352
374
|
const supported = TEMPLATE_REGISTRY[flags.template].platforms.join(", ");
|
|
353
375
|
const ans = isInteractive
|
|
354
376
|
? (
|
|
355
|
-
await
|
|
377
|
+
await ask(
|
|
356
378
|
`Platforms for ${flags.template} (${supported}, comma-separated) [web]: `,
|
|
357
379
|
)
|
|
358
380
|
).trim()
|
|
@@ -364,7 +386,7 @@ if (!flags.pm) {
|
|
|
364
386
|
const def = detected ?? "bun";
|
|
365
387
|
if (isInteractive) {
|
|
366
388
|
const choice = (
|
|
367
|
-
await
|
|
389
|
+
await ask(`Package manager (bun, pnpm, yarn, npm) [${def}]: `)
|
|
368
390
|
)
|
|
369
391
|
.trim()
|
|
370
392
|
.toLowerCase();
|
|
@@ -376,7 +398,7 @@ if (!flags.pm) {
|
|
|
376
398
|
if (flags.skill === undefined) {
|
|
377
399
|
if (isInteractive) {
|
|
378
400
|
const ans = (
|
|
379
|
-
await
|
|
401
|
+
await ask(
|
|
380
402
|
"Add the Pylon skill to your coding agent (Claude Code / Codex / Cursor)? [Y/n]: ",
|
|
381
403
|
)
|
|
382
404
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pylonsync/create-pylon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Scaffold a new Pylon app — realtime backend + web/mobile/expo frontends in one command. Run via `npm create @pylonsync/pylon@latest`.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -5,7 +5,7 @@ Pylon serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR from o
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
7
7
|
**Unified SSR app:**
|
|
8
|
-
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))
|
|
8
|
+
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))` — that line is the manifest handoff (the CLI parses this file's stdout), not debug output. Never remove it.
|
|
9
9
|
- `app/`: file-based SSR routes. `app/page.tsx` → `/`, `app/about/page.tsx` → `/about`, `app/blog/[slug]/page.tsx` → `/blog/:slug`. A `(group)` directory is stripped from the URL — `app/(marketing)/about/page.tsx` still serves `/about` — so a group's `layout.tsx` gives one section its own chrome (nav, footer) without changing any path; routes outside the group render without it. `app/layout.tsx` is the document shell; `app/error.tsx` / `app/not-found.tsx` are boundaries.
|
|
10
10
|
- `app/globals.css`: Tailwind v4 entrypoint (auto-compiled and injected).
|
|
11
11
|
- `functions/`: server functions, one per file, `default`-exported.
|
|
@@ -5,7 +5,7 @@ Pylon serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR from o
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
7
7
|
**Unified SSR app:**
|
|
8
|
-
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))
|
|
8
|
+
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))` — that line is the manifest handoff (the CLI parses this file's stdout), not debug output. Never remove it.
|
|
9
9
|
- `app/`: file-based SSR routes. `app/page.tsx` → `/`, `app/about/page.tsx` → `/about`, `app/blog/[slug]/page.tsx` → `/blog/:slug`. A `(group)` directory is stripped from the URL — `app/(marketing)/about/page.tsx` still serves `/about` — so a group's `layout.tsx` gives one section its own chrome (nav, footer) without changing any path; routes outside the group render without it. `app/layout.tsx` is the document shell; `app/error.tsx` / `app/not-found.tsx` are boundaries.
|
|
10
10
|
- `app/globals.css`: Tailwind v4 entrypoint (auto-compiled and injected).
|
|
11
11
|
- `functions/`: server functions, one per file, `default`-exported.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { LlmsTxt } from "@pylonsync/react";
|
|
2
|
+
|
|
3
|
+
// app/llms.ts → served at /llms.txt, in llmstxt.org format.
|
|
4
|
+
//
|
|
5
|
+
// This is the file an AI agent reads FIRST to decide what this site is and
|
|
6
|
+
// whether it can help with the task in front of it. Keep the shape, rewrite the
|
|
7
|
+
// copy: name the jobs this app is right for and the exact call to make. Generic
|
|
8
|
+
// marketing copy does not read as guidance.
|
|
9
|
+
//
|
|
10
|
+
// The default export may be async, so it can enumerate pages from the database.
|
|
11
|
+
const SITE = process.env.SITE_URL ?? "http://localhost:4321";
|
|
12
|
+
|
|
13
|
+
export default function llms(): LlmsTxt {
|
|
14
|
+
return {
|
|
15
|
+
title: "__APP_NAME__",
|
|
16
|
+
summary: "An agency site: services, case studies, and an enquiry form.",
|
|
17
|
+
details: [
|
|
18
|
+
"Use this app to read case studies and to send an enquiry.",
|
|
19
|
+
"Every page here is also readable as markdown: add `.md` to any path, or send `Accept: text/markdown`.",
|
|
20
|
+
],
|
|
21
|
+
sections: [
|
|
22
|
+
{
|
|
23
|
+
title: "Pages",
|
|
24
|
+
links: [
|
|
25
|
+
{ title: "Home", url: `${SITE}` },
|
|
26
|
+
{ title: "Work", url: `${SITE}/work` },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Link, type NotFoundProps } from "@pylonsync/react";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
|
|
5
|
+
// `app/not-found.tsx` → rendered at HTTP 404 for any unmatched URL, and when a
|
|
6
|
+
// page calls `response.notFound()`.
|
|
7
|
+
//
|
|
8
|
+
// Give it real links. This boundary is also what an agent reads when it guesses
|
|
9
|
+
// a URL wrong: a markdown request for a missing page renders THIS file as
|
|
10
|
+
// markdown at 404, so the links below are how it finds its way back.
|
|
11
|
+
export default function NotFound(_props: NotFoundProps) {
|
|
12
|
+
return (
|
|
13
|
+
<div className="mx-auto flex min-h-[60vh] max-w-lg flex-col justify-center gap-6 px-4">
|
|
14
|
+
<section>
|
|
15
|
+
<h1 className="text-2xl font-semibold tracking-tight">Page not found</h1>
|
|
16
|
+
<p className="mt-2 text-muted-foreground">
|
|
17
|
+
That URL does not exist. Try one of these:
|
|
18
|
+
</p>
|
|
19
|
+
</section>
|
|
20
|
+
<ul className="space-y-2 text-sm">
|
|
21
|
+
<li>
|
|
22
|
+
<Link className="underline underline-offset-4" href="/">
|
|
23
|
+
Home
|
|
24
|
+
</Link>
|
|
25
|
+
</li>
|
|
26
|
+
<li>
|
|
27
|
+
<a className="underline underline-offset-4" href="/sitemap.xml">
|
|
28
|
+
Sitemap
|
|
29
|
+
</a>
|
|
30
|
+
</li>
|
|
31
|
+
<li>
|
|
32
|
+
<a className="underline underline-offset-4" href="/llms.txt">
|
|
33
|
+
llms.txt
|
|
34
|
+
</a>
|
|
35
|
+
</li>
|
|
36
|
+
</ul>
|
|
37
|
+
<div>
|
|
38
|
+
<Button asChild>
|
|
39
|
+
<Link href="/">Back to home</Link>
|
|
40
|
+
</Button>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
package/templates/agency/app.ts
CHANGED
|
@@ -300,6 +300,9 @@ const manifest = buildManifest({
|
|
|
300
300
|
routes: await discoverAppRoutes(),
|
|
301
301
|
});
|
|
302
302
|
|
|
303
|
+
// Not a debug leftover: the CLI runs `bun run app.ts` and parses stdout as
|
|
304
|
+
// your manifest (see crates/cli/src/bun.rs). Deleting this line breaks every
|
|
305
|
+
// pylon command that reads your schema.
|
|
303
306
|
console.log(JSON.stringify(manifest, null, 2));
|
|
304
307
|
|
|
305
308
|
export default manifest;
|
|
@@ -5,7 +5,7 @@ Pylon serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR from o
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
7
7
|
**Unified SSR app:**
|
|
8
|
-
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))
|
|
8
|
+
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))` — that line is the manifest handoff (the CLI parses this file's stdout), not debug output. Never remove it.
|
|
9
9
|
- `app/`: file-based SSR routes. `app/page.tsx` → `/`, `app/about/page.tsx` → `/about`, `app/blog/[slug]/page.tsx` → `/blog/:slug`. A `(group)` directory is stripped from the URL — `app/(marketing)/about/page.tsx` still serves `/about` — so a group's `layout.tsx` gives one section its own chrome (nav, footer) without changing any path; routes outside the group render without it. `app/layout.tsx` is the document shell; `app/error.tsx` / `app/not-found.tsx` are boundaries.
|
|
10
10
|
- `app/globals.css`: Tailwind v4 entrypoint (auto-compiled and injected).
|
|
11
11
|
- `functions/`: server functions, one per file, `default`-exported.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { LlmsTxt } from "@pylonsync/react";
|
|
2
|
+
|
|
3
|
+
// app/llms.ts → served at /llms.txt, in llmstxt.org format.
|
|
4
|
+
//
|
|
5
|
+
// This is the file an AI agent reads FIRST to decide what this site is and
|
|
6
|
+
// whether it can help with the task in front of it. Keep the shape, rewrite the
|
|
7
|
+
// copy: name the jobs this app is right for and the exact call to make. Generic
|
|
8
|
+
// marketing copy does not read as guidance.
|
|
9
|
+
//
|
|
10
|
+
// The default export may be async, so it can enumerate pages from the database.
|
|
11
|
+
const SITE = process.env.SITE_URL ?? "http://localhost:4321";
|
|
12
|
+
|
|
13
|
+
export default function llms(): LlmsTxt {
|
|
14
|
+
return {
|
|
15
|
+
title: "__APP_NAME__",
|
|
16
|
+
summary: "An AI chat app with streaming answers and stored transcripts.",
|
|
17
|
+
details: [
|
|
18
|
+
"Use this app to ask a question and read the streamed answer. Transcripts persist across reloads and devices.",
|
|
19
|
+
"Every page here is also readable as markdown: add `.md` to any path, or send `Accept: text/markdown`.",
|
|
20
|
+
],
|
|
21
|
+
sections: [
|
|
22
|
+
{
|
|
23
|
+
title: "Pages",
|
|
24
|
+
links: [
|
|
25
|
+
{ title: "Home", url: `${SITE}` },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Link, type NotFoundProps } from "@pylonsync/react";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
|
|
5
|
+
// `app/not-found.tsx` → rendered at HTTP 404 for any unmatched URL, and when a
|
|
6
|
+
// page calls `response.notFound()`.
|
|
7
|
+
//
|
|
8
|
+
// Give it real links. This boundary is also what an agent reads when it guesses
|
|
9
|
+
// a URL wrong: a markdown request for a missing page renders THIS file as
|
|
10
|
+
// markdown at 404, so the links below are how it finds its way back.
|
|
11
|
+
export default function NotFound(_props: NotFoundProps) {
|
|
12
|
+
return (
|
|
13
|
+
<div className="mx-auto flex min-h-[60vh] max-w-lg flex-col justify-center gap-6 px-4">
|
|
14
|
+
<section>
|
|
15
|
+
<h1 className="text-2xl font-semibold tracking-tight">Page not found</h1>
|
|
16
|
+
<p className="mt-2 text-muted-foreground">
|
|
17
|
+
That URL does not exist. Try one of these:
|
|
18
|
+
</p>
|
|
19
|
+
</section>
|
|
20
|
+
<ul className="space-y-2 text-sm">
|
|
21
|
+
<li>
|
|
22
|
+
<Link className="underline underline-offset-4" href="/">
|
|
23
|
+
Home
|
|
24
|
+
</Link>
|
|
25
|
+
</li>
|
|
26
|
+
<li>
|
|
27
|
+
<a className="underline underline-offset-4" href="/sitemap.xml">
|
|
28
|
+
Sitemap
|
|
29
|
+
</a>
|
|
30
|
+
</li>
|
|
31
|
+
<li>
|
|
32
|
+
<a className="underline underline-offset-4" href="/llms.txt">
|
|
33
|
+
llms.txt
|
|
34
|
+
</a>
|
|
35
|
+
</li>
|
|
36
|
+
</ul>
|
|
37
|
+
<div>
|
|
38
|
+
<Button asChild>
|
|
39
|
+
<Link href="/">Back to home</Link>
|
|
40
|
+
</Button>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Robots } from "@pylonsync/react";
|
|
2
|
+
|
|
3
|
+
// app/robots.ts → served at /robots.txt. Point SITE_URL at your domain in
|
|
4
|
+
// production. The default export may also be async.
|
|
5
|
+
const SITE = process.env.SITE_URL ?? "http://localhost:4321";
|
|
6
|
+
|
|
7
|
+
export default function robots(): Robots {
|
|
8
|
+
return {
|
|
9
|
+
// Keep the signed-in app and the API out of the index. `llms.txt` and the
|
|
10
|
+
// sitemap stay crawlable — they are what a crawler or agent reads first.
|
|
11
|
+
rules: { userAgent: "*", allow: "/", disallow: ["/api/", "/login"] },
|
|
12
|
+
sitemap: `${SITE}/sitemap.xml`,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Sitemap } from "@pylonsync/react";
|
|
2
|
+
|
|
3
|
+
// app/sitemap.ts → served at /sitemap.xml. The default export can be async, so
|
|
4
|
+
// it can enumerate pages from your database. Point SITE_URL at your domain in
|
|
5
|
+
// production.
|
|
6
|
+
const SITE = process.env.SITE_URL ?? "http://localhost:4321";
|
|
7
|
+
|
|
8
|
+
export default async function sitemap(): Promise<Sitemap> {
|
|
9
|
+
// Only public pages belong here. The signed-in app is private.
|
|
10
|
+
return [{ url: `${SITE}/`, changeFrequency: "weekly", priority: 1 }];
|
|
11
|
+
}
|
package/templates/ai-chat/app.ts
CHANGED
|
@@ -135,6 +135,9 @@ const manifest = buildManifest({
|
|
|
135
135
|
routes: await discoverAppRoutes(),
|
|
136
136
|
});
|
|
137
137
|
|
|
138
|
+
// Not a debug leftover: the CLI runs `bun run app.ts` and parses stdout as
|
|
139
|
+
// your manifest (see crates/cli/src/bun.rs). Deleting this line breaks every
|
|
140
|
+
// pylon command that reads your schema.
|
|
138
141
|
console.log(JSON.stringify(manifest, null, 2));
|
|
139
142
|
|
|
140
143
|
export default manifest;
|
|
@@ -5,7 +5,7 @@ Pylon serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR from o
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
7
7
|
**Unified SSR app:**
|
|
8
|
-
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))
|
|
8
|
+
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))` — that line is the manifest handoff (the CLI parses this file's stdout), not debug output. Never remove it.
|
|
9
9
|
- `app/`: file-based SSR routes. `app/page.tsx` → `/`, `app/about/page.tsx` → `/about`, `app/blog/[slug]/page.tsx` → `/blog/:slug`. A `(group)` directory is stripped from the URL — `app/(marketing)/about/page.tsx` still serves `/about` — so a group's `layout.tsx` gives one section its own chrome (nav, footer) without changing any path; routes outside the group render without it. `app/layout.tsx` is the document shell; `app/error.tsx` / `app/not-found.tsx` are boundaries.
|
|
10
10
|
- `app/globals.css`: Tailwind v4 entrypoint (auto-compiled and injected).
|
|
11
11
|
- `functions/`: server functions, one per file, `default`-exported.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { LlmsTxt } from "@pylonsync/react";
|
|
2
|
+
|
|
3
|
+
// app/llms.ts → served at /llms.txt, in llmstxt.org format.
|
|
4
|
+
//
|
|
5
|
+
// This is the file an AI agent reads FIRST to decide what this site is and
|
|
6
|
+
// whether it can help with the task in front of it. Keep the shape, rewrite the
|
|
7
|
+
// copy: name the jobs this app is right for and the exact call to make. Generic
|
|
8
|
+
// marketing copy does not read as guidance.
|
|
9
|
+
//
|
|
10
|
+
// The default export may be async, so it can enumerate pages from the database.
|
|
11
|
+
const SITE = process.env.SITE_URL ?? "http://localhost:4321";
|
|
12
|
+
|
|
13
|
+
export default function llms(): LlmsTxt {
|
|
14
|
+
return {
|
|
15
|
+
title: "__APP_NAME__",
|
|
16
|
+
summary: "An AI studio: prompts, runs, and tool calls with durable run state.",
|
|
17
|
+
details: [
|
|
18
|
+
"Use this app to run a prompt, read the streamed output, and review past runs.",
|
|
19
|
+
"Every page here is also readable as markdown: add `.md` to any path, or send `Accept: text/markdown`.",
|
|
20
|
+
],
|
|
21
|
+
sections: [
|
|
22
|
+
{
|
|
23
|
+
title: "Pages",
|
|
24
|
+
links: [
|
|
25
|
+
{ title: "Home", url: `${SITE}` },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Link, type NotFoundProps } from "@pylonsync/react";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
|
|
5
|
+
// `app/not-found.tsx` → rendered at HTTP 404 for any unmatched URL, and when a
|
|
6
|
+
// page calls `response.notFound()`.
|
|
7
|
+
//
|
|
8
|
+
// Give it real links. This boundary is also what an agent reads when it guesses
|
|
9
|
+
// a URL wrong: a markdown request for a missing page renders THIS file as
|
|
10
|
+
// markdown at 404, so the links below are how it finds its way back.
|
|
11
|
+
export default function NotFound(_props: NotFoundProps) {
|
|
12
|
+
return (
|
|
13
|
+
<div className="mx-auto flex min-h-[60vh] max-w-lg flex-col justify-center gap-6 px-4">
|
|
14
|
+
<section>
|
|
15
|
+
<h1 className="text-2xl font-semibold tracking-tight">Page not found</h1>
|
|
16
|
+
<p className="mt-2 text-muted-foreground">
|
|
17
|
+
That URL does not exist. Try one of these:
|
|
18
|
+
</p>
|
|
19
|
+
</section>
|
|
20
|
+
<ul className="space-y-2 text-sm">
|
|
21
|
+
<li>
|
|
22
|
+
<Link className="underline underline-offset-4" href="/">
|
|
23
|
+
Home
|
|
24
|
+
</Link>
|
|
25
|
+
</li>
|
|
26
|
+
<li>
|
|
27
|
+
<a className="underline underline-offset-4" href="/sitemap.xml">
|
|
28
|
+
Sitemap
|
|
29
|
+
</a>
|
|
30
|
+
</li>
|
|
31
|
+
<li>
|
|
32
|
+
<a className="underline underline-offset-4" href="/llms.txt">
|
|
33
|
+
llms.txt
|
|
34
|
+
</a>
|
|
35
|
+
</li>
|
|
36
|
+
</ul>
|
|
37
|
+
<div>
|
|
38
|
+
<Button asChild>
|
|
39
|
+
<Link href="/">Back to home</Link>
|
|
40
|
+
</Button>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Robots } from "@pylonsync/react";
|
|
2
|
+
|
|
3
|
+
// app/robots.ts → served at /robots.txt. Point SITE_URL at your domain in
|
|
4
|
+
// production. The default export may also be async.
|
|
5
|
+
const SITE = process.env.SITE_URL ?? "http://localhost:4321";
|
|
6
|
+
|
|
7
|
+
export default function robots(): Robots {
|
|
8
|
+
return {
|
|
9
|
+
// Keep the signed-in app and the API out of the index. `llms.txt` and the
|
|
10
|
+
// sitemap stay crawlable — they are what a crawler or agent reads first.
|
|
11
|
+
rules: { userAgent: "*", allow: "/", disallow: ["/api/", "/login"] },
|
|
12
|
+
sitemap: `${SITE}/sitemap.xml`,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Sitemap } from "@pylonsync/react";
|
|
2
|
+
|
|
3
|
+
// app/sitemap.ts → served at /sitemap.xml. The default export can be async, so
|
|
4
|
+
// it can enumerate pages from your database. Point SITE_URL at your domain in
|
|
5
|
+
// production.
|
|
6
|
+
const SITE = process.env.SITE_URL ?? "http://localhost:4321";
|
|
7
|
+
|
|
8
|
+
export default async function sitemap(): Promise<Sitemap> {
|
|
9
|
+
// Only public pages belong here. The signed-in app is private.
|
|
10
|
+
return [{ url: `${SITE}/`, changeFrequency: "weekly", priority: 1 }];
|
|
11
|
+
}
|
|
@@ -122,6 +122,9 @@ const manifest = buildManifest({
|
|
|
122
122
|
routes: await discoverAppRoutes(),
|
|
123
123
|
});
|
|
124
124
|
|
|
125
|
+
// Not a debug leftover: the CLI runs `bun run app.ts` and parses stdout as
|
|
126
|
+
// your manifest (see crates/cli/src/bun.rs). Deleting this line breaks every
|
|
127
|
+
// pylon command that reads your schema.
|
|
125
128
|
console.log(JSON.stringify(manifest, null, 2));
|
|
126
129
|
|
|
127
130
|
export default manifest;
|
|
@@ -176,4 +176,7 @@ const manifest = buildManifest({
|
|
|
176
176
|
routes: [],
|
|
177
177
|
});
|
|
178
178
|
|
|
179
|
+
// Not a debug leftover: the CLI runs `bun run` on this file and parses stdout
|
|
180
|
+
// as your manifest (see crates/cli/src/bun.rs). Deleting this line breaks every
|
|
181
|
+
// pylon command that reads your schema.
|
|
179
182
|
console.log(JSON.stringify(manifest));
|
|
@@ -58,4 +58,7 @@ const manifest = buildManifest({
|
|
|
58
58
|
routes: [],
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
+
// Not a debug leftover: the CLI runs `bun run` on this file and parses stdout
|
|
62
|
+
// as your manifest (see crates/cli/src/bun.rs). Deleting this line breaks every
|
|
63
|
+
// pylon command that reads your schema.
|
|
61
64
|
console.log(JSON.stringify(manifest));
|
|
@@ -93,4 +93,7 @@ const manifest = buildManifest({
|
|
|
93
93
|
routes: [],
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
+
// Not a debug leftover: the CLI runs `bun run` on this file and parses stdout
|
|
97
|
+
// as your manifest (see crates/cli/src/bun.rs). Deleting this line breaks every
|
|
98
|
+
// pylon command that reads your schema.
|
|
96
99
|
console.log(JSON.stringify(manifest));
|
|
@@ -137,4 +137,7 @@ const manifest = buildManifest({
|
|
|
137
137
|
routes: [],
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
+
// Not a debug leftover: the CLI runs `bun run` on this file and parses stdout
|
|
141
|
+
// as your manifest (see crates/cli/src/bun.rs). Deleting this line breaks every
|
|
142
|
+
// pylon command that reads your schema.
|
|
140
143
|
console.log(JSON.stringify(manifest));
|
|
@@ -82,4 +82,7 @@ const manifest = buildManifest({
|
|
|
82
82
|
routes: [],
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
+
// Not a debug leftover: the CLI runs `bun run` on this file and parses stdout
|
|
86
|
+
// as your manifest (see crates/cli/src/bun.rs). Deleting this line breaks every
|
|
87
|
+
// pylon command that reads your schema.
|
|
85
88
|
console.log(JSON.stringify(manifest));
|
|
@@ -5,7 +5,7 @@ Pylon serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR from o
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
7
7
|
**Unified SSR app:**
|
|
8
|
-
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))
|
|
8
|
+
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))` — that line is the manifest handoff (the CLI parses this file's stdout), not debug output. Never remove it.
|
|
9
9
|
- `app/`: file-based SSR routes. `app/page.tsx` → `/`, `app/about/page.tsx` → `/about`, `app/blog/[slug]/page.tsx` → `/blog/:slug`. A `(group)` directory is stripped from the URL — `app/(marketing)/about/page.tsx` still serves `/about` — so a group's `layout.tsx` gives one section its own chrome (nav, footer) without changing any path; routes outside the group render without it. `app/layout.tsx` is the document shell; `app/error.tsx` / `app/not-found.tsx` are boundaries.
|
|
10
10
|
- `app/globals.css`: Tailwind v4 entrypoint (auto-compiled and injected).
|
|
11
11
|
- `functions/`: server functions, one per file, `default`-exported.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { LlmsTxt } from "@pylonsync/react";
|
|
2
|
+
|
|
3
|
+
// app/llms.ts → served at /llms.txt, in llmstxt.org format.
|
|
4
|
+
//
|
|
5
|
+
// This is the file an AI agent reads FIRST to decide what this site is and
|
|
6
|
+
// whether it can help with the task in front of it. Keep the shape, rewrite the
|
|
7
|
+
// copy: name the jobs this app is right for and the exact call to make. Generic
|
|
8
|
+
// marketing copy does not read as guidance.
|
|
9
|
+
//
|
|
10
|
+
// The default export may be async, so it can enumerate pages from the database.
|
|
11
|
+
const SITE = process.env.SITE_URL ?? "http://localhost:4321";
|
|
12
|
+
|
|
13
|
+
export default function llms(): LlmsTxt {
|
|
14
|
+
return {
|
|
15
|
+
title: "__APP_NAME__",
|
|
16
|
+
summary: "A starter app with one entity and a live list.",
|
|
17
|
+
details: [
|
|
18
|
+
"Use this app to read and create items. Every change is pushed to open clients over the sync connection.",
|
|
19
|
+
"Every page here is also readable as markdown: add `.md` to any path, or send `Accept: text/markdown`.",
|
|
20
|
+
],
|
|
21
|
+
sections: [
|
|
22
|
+
{
|
|
23
|
+
title: "Pages",
|
|
24
|
+
links: [
|
|
25
|
+
{ title: "Home", url: `${SITE}` },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -55,6 +55,9 @@ const manifest = buildManifest({
|
|
|
55
55
|
routes: await discoverAppRoutes(),
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
+
// Not a debug leftover: the CLI runs `bun run app.ts` and parses stdout as
|
|
59
|
+
// your manifest (see crates/cli/src/bun.rs). Deleting this line breaks every
|
|
60
|
+
// pylon command that reads your schema.
|
|
58
61
|
console.log(JSON.stringify(manifest, null, 2));
|
|
59
62
|
|
|
60
63
|
export default manifest;
|
package/templates/chat/AGENTS.md
CHANGED
|
@@ -5,7 +5,7 @@ Pylon serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR from o
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
7
7
|
**Unified SSR app:**
|
|
8
|
-
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))
|
|
8
|
+
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))` — that line is the manifest handoff (the CLI parses this file's stdout), not debug output. Never remove it.
|
|
9
9
|
- `app/`: file-based SSR routes. `app/page.tsx` → `/`, `app/about/page.tsx` → `/about`, `app/blog/[slug]/page.tsx` → `/blog/:slug`. A `(group)` directory is stripped from the URL — `app/(marketing)/about/page.tsx` still serves `/about` — so a group's `layout.tsx` gives one section its own chrome (nav, footer) without changing any path; routes outside the group render without it. `app/layout.tsx` is the document shell; `app/error.tsx` / `app/not-found.tsx` are boundaries.
|
|
10
10
|
- `app/globals.css`: Tailwind v4 entrypoint (auto-compiled and injected).
|
|
11
11
|
- `functions/`: server functions, one per file, `default`-exported.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { LlmsTxt } from "@pylonsync/react";
|
|
2
|
+
|
|
3
|
+
// app/llms.ts → served at /llms.txt, in llmstxt.org format.
|
|
4
|
+
//
|
|
5
|
+
// This is the file an AI agent reads FIRST to decide what this site is and
|
|
6
|
+
// whether it can help with the task in front of it. Keep the shape, rewrite the
|
|
7
|
+
// copy: name the jobs this app is right for and the exact call to make. Generic
|
|
8
|
+
// marketing copy does not read as guidance.
|
|
9
|
+
//
|
|
10
|
+
// The default export may be async, so it can enumerate pages from the database.
|
|
11
|
+
const SITE = process.env.SITE_URL ?? "http://localhost:4321";
|
|
12
|
+
|
|
13
|
+
export default function llms(): LlmsTxt {
|
|
14
|
+
return {
|
|
15
|
+
title: "__APP_NAME__",
|
|
16
|
+
summary: "A realtime chat room.",
|
|
17
|
+
details: [
|
|
18
|
+
"Use this app to read and send messages in a shared room. Messages arrive on every open client without a refresh.",
|
|
19
|
+
"Every page here is also readable as markdown: add `.md` to any path, or send `Accept: text/markdown`.",
|
|
20
|
+
],
|
|
21
|
+
sections: [
|
|
22
|
+
{
|
|
23
|
+
title: "Pages",
|
|
24
|
+
links: [
|
|
25
|
+
{ title: "Home", url: `${SITE}` },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
package/templates/chat/app.ts
CHANGED
|
@@ -54,6 +54,9 @@ const manifest = buildManifest({
|
|
|
54
54
|
routes: await discoverAppRoutes(),
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
// Not a debug leftover: the CLI runs `bun run app.ts` and parses stdout as
|
|
58
|
+
// your manifest (see crates/cli/src/bun.rs). Deleting this line breaks every
|
|
59
|
+
// pylon command that reads your schema.
|
|
57
60
|
console.log(JSON.stringify(manifest, null, 2));
|
|
58
61
|
|
|
59
62
|
export default manifest;
|
|
@@ -5,7 +5,7 @@ Pylon serves the API, auth, sync, WebSocket, SSE, and native React 19 SSR from o
|
|
|
5
5
|
## Directory conventions
|
|
6
6
|
|
|
7
7
|
**Unified SSR app:**
|
|
8
|
-
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))
|
|
8
|
+
- `app.ts`: data model + manifest (`entity()` + `field.*`, queries/actions/policies, `routes: await discoverAppRoutes()`). Ends with `console.log(JSON.stringify(manifest))` — that line is the manifest handoff (the CLI parses this file's stdout), not debug output. Never remove it.
|
|
9
9
|
- `app/`: file-based SSR routes. `app/page.tsx` → `/`, `app/about/page.tsx` → `/about`, `app/blog/[slug]/page.tsx` → `/blog/:slug`. A `(group)` directory is stripped from the URL — `app/(marketing)/about/page.tsx` still serves `/about` — so a group's `layout.tsx` gives one section its own chrome (nav, footer) without changing any path; routes outside the group render without it. `app/layout.tsx` is the document shell; `app/error.tsx` / `app/not-found.tsx` are boundaries.
|
|
10
10
|
- `app/globals.css`: Tailwind v4 entrypoint (auto-compiled and injected).
|
|
11
11
|
- `functions/`: server functions, one per file, `default`-exported.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { LlmsTxt } from "@pylonsync/react";
|
|
2
|
+
|
|
3
|
+
// app/llms.ts → served at /llms.txt, in llmstxt.org format.
|
|
4
|
+
//
|
|
5
|
+
// This is the file an AI agent reads FIRST to decide what this site is and
|
|
6
|
+
// whether it can help with the task in front of it. Keep the shape, rewrite the
|
|
7
|
+
// copy: name the jobs this app is right for and the exact call to make. Generic
|
|
8
|
+
// marketing copy does not read as guidance.
|
|
9
|
+
//
|
|
10
|
+
// The default export may be async, so it can enumerate pages from the database.
|
|
11
|
+
const SITE = process.env.SITE_URL ?? "http://localhost:4321";
|
|
12
|
+
|
|
13
|
+
export default function llms(): LlmsTxt {
|
|
14
|
+
return {
|
|
15
|
+
title: "__APP_NAME__",
|
|
16
|
+
summary: "A social feed with posts and likes.",
|
|
17
|
+
details: [
|
|
18
|
+
"Use this app to read the public feed, post, and like. Reading needs no account; posting needs a session.",
|
|
19
|
+
"Every page here is also readable as markdown: add `.md` to any path, or send `Accept: text/markdown`.",
|
|
20
|
+
],
|
|
21
|
+
sections: [
|
|
22
|
+
{
|
|
23
|
+
title: "Pages",
|
|
24
|
+
links: [
|
|
25
|
+
{ title: "Home", url: `${SITE}` },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|