@pyreon/create-zero 0.2.0 → 0.4.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/lib/index.js
CHANGED
|
@@ -65,6 +65,26 @@ const FEATURES = {
|
|
|
65
65
|
hooks: {
|
|
66
66
|
label: "Hooks (@pyreon/hooks — 25+ signal-based utilities)",
|
|
67
67
|
deps: ["@pyreon/hooks"]
|
|
68
|
+
},
|
|
69
|
+
charts: {
|
|
70
|
+
label: "Charts (@pyreon/charts — reactive ECharts)",
|
|
71
|
+
deps: ["@pyreon/charts"]
|
|
72
|
+
},
|
|
73
|
+
hotkeys: {
|
|
74
|
+
label: "Hotkeys (@pyreon/hotkeys — keyboard shortcuts)",
|
|
75
|
+
deps: ["@pyreon/hotkeys"]
|
|
76
|
+
},
|
|
77
|
+
storage: {
|
|
78
|
+
label: "Storage (@pyreon/storage — localStorage, cookies, IndexedDB)",
|
|
79
|
+
deps: ["@pyreon/storage"]
|
|
80
|
+
},
|
|
81
|
+
flow: {
|
|
82
|
+
label: "Flow Diagrams (@pyreon/flow — reactive node graphs)",
|
|
83
|
+
deps: ["@pyreon/flow"]
|
|
84
|
+
},
|
|
85
|
+
code: {
|
|
86
|
+
label: "Code Editor (@pyreon/code — CodeMirror 6)",
|
|
87
|
+
deps: ["@pyreon/code"]
|
|
68
88
|
}
|
|
69
89
|
};
|
|
70
90
|
const TEMPLATE_DIR = resolve(import.meta.dirname, "../templates/default");
|
|
@@ -138,6 +158,22 @@ async function main() {
|
|
|
138
158
|
p.cancel("Cancelled.");
|
|
139
159
|
process.exit(0);
|
|
140
160
|
}
|
|
161
|
+
const packageStrategy = await p.select({
|
|
162
|
+
message: "Package imports",
|
|
163
|
+
options: [{
|
|
164
|
+
value: "meta",
|
|
165
|
+
label: "@pyreon/meta (single barrel)",
|
|
166
|
+
hint: "one import for everything — simpler, tree-shaken at build"
|
|
167
|
+
}, {
|
|
168
|
+
value: "individual",
|
|
169
|
+
label: "Individual packages",
|
|
170
|
+
hint: "only install what you selected — smaller node_modules"
|
|
171
|
+
}]
|
|
172
|
+
});
|
|
173
|
+
if (p.isCancel(packageStrategy)) {
|
|
174
|
+
p.cancel("Cancelled.");
|
|
175
|
+
process.exit(0);
|
|
176
|
+
}
|
|
141
177
|
const aiToolchain = await p.confirm({
|
|
142
178
|
message: "Include AI toolchain? (MCP server, CLAUDE.md, doctor)",
|
|
143
179
|
initialValue: true
|
|
@@ -151,6 +187,7 @@ async function main() {
|
|
|
151
187
|
targetDir,
|
|
152
188
|
renderMode,
|
|
153
189
|
features,
|
|
190
|
+
packageStrategy,
|
|
154
191
|
aiToolchain
|
|
155
192
|
};
|
|
156
193
|
const s = p.spinner();
|
|
@@ -196,32 +233,76 @@ async function scaffold(config) {
|
|
|
196
233
|
}
|
|
197
234
|
}
|
|
198
235
|
}
|
|
236
|
+
function pyreonVersion(pkg) {
|
|
237
|
+
if ([
|
|
238
|
+
"core",
|
|
239
|
+
"reactivity",
|
|
240
|
+
"runtime-dom",
|
|
241
|
+
"runtime-server",
|
|
242
|
+
"server",
|
|
243
|
+
"head",
|
|
244
|
+
"router",
|
|
245
|
+
"vite-plugin",
|
|
246
|
+
"compiler",
|
|
247
|
+
"cli",
|
|
248
|
+
"mcp"
|
|
249
|
+
].some((c) => pkg === `@pyreon/${c}`)) return "^0.7.5";
|
|
250
|
+
if (pkg === "@pyreon/zero" || pkg === "@pyreon/meta" || pkg === "@pyreon/zero-cli" || pkg === "@pyreon/create-zero") return "^0.3.0";
|
|
251
|
+
if ([
|
|
252
|
+
"store",
|
|
253
|
+
"form",
|
|
254
|
+
"validation",
|
|
255
|
+
"query",
|
|
256
|
+
"table",
|
|
257
|
+
"virtual",
|
|
258
|
+
"i18n",
|
|
259
|
+
"feature",
|
|
260
|
+
"machine",
|
|
261
|
+
"permissions",
|
|
262
|
+
"flow",
|
|
263
|
+
"code"
|
|
264
|
+
].some((f) => pkg === `@pyreon/${f}`)) return "^0.9.0";
|
|
265
|
+
return "^0.3.0";
|
|
266
|
+
}
|
|
199
267
|
function generatePackageJson(config) {
|
|
200
268
|
const deps = {
|
|
201
|
-
"@pyreon/core": "
|
|
202
|
-
"@pyreon/head": "
|
|
203
|
-
"@pyreon/reactivity": "
|
|
204
|
-
"@pyreon/router": "
|
|
205
|
-
"@pyreon/runtime-dom": "
|
|
206
|
-
"@pyreon/runtime-server": "
|
|
207
|
-
"@pyreon/server": "
|
|
208
|
-
"@pyreon/zero": "
|
|
269
|
+
"@pyreon/core": pyreonVersion("@pyreon/core"),
|
|
270
|
+
"@pyreon/head": pyreonVersion("@pyreon/head"),
|
|
271
|
+
"@pyreon/reactivity": pyreonVersion("@pyreon/reactivity"),
|
|
272
|
+
"@pyreon/router": pyreonVersion("@pyreon/router"),
|
|
273
|
+
"@pyreon/runtime-dom": pyreonVersion("@pyreon/runtime-dom"),
|
|
274
|
+
"@pyreon/runtime-server": pyreonVersion("@pyreon/runtime-server"),
|
|
275
|
+
"@pyreon/server": pyreonVersion("@pyreon/server"),
|
|
276
|
+
"@pyreon/zero": pyreonVersion("@pyreon/zero")
|
|
209
277
|
};
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const
|
|
213
|
-
|
|
278
|
+
if (config.packageStrategy === "meta") {
|
|
279
|
+
deps["@pyreon/meta"] = pyreonVersion("@pyreon/meta");
|
|
280
|
+
for (const key of config.features) {
|
|
281
|
+
const feature = FEATURES[key];
|
|
282
|
+
if (feature) {
|
|
283
|
+
for (const dep of feature.deps) if (!dep.startsWith("@pyreon/")) {
|
|
284
|
+
if (dep.startsWith("@tanstack/")) deps[dep] = dep.includes("query") ? "^5.90.0" : dep.includes("table") ? "^8.21.0" : "^3.13.0";
|
|
285
|
+
else if (dep === "zod") deps[dep] = "^4.0.0";
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
} else {
|
|
290
|
+
const allDeps = /* @__PURE__ */ new Set();
|
|
291
|
+
for (const key of config.features) {
|
|
292
|
+
const feature = FEATURES[key];
|
|
293
|
+
if (feature) for (const dep of feature.deps) allDeps.add(dep);
|
|
294
|
+
}
|
|
295
|
+
for (const dep of allDeps) if (dep.startsWith("@pyreon/")) deps[dep] = pyreonVersion(dep);
|
|
296
|
+
else if (dep.startsWith("@tanstack/")) deps[dep] = dep.includes("query") ? "^5.90.0" : dep.includes("table") ? "^8.21.0" : "^3.13.0";
|
|
297
|
+
else if (dep === "zod") deps[dep] = "^4.0.0";
|
|
214
298
|
}
|
|
215
|
-
for (const dep of allDeps) if (dep.startsWith("@pyreon/")) deps[dep] = "latest";
|
|
216
|
-
else if (dep.startsWith("@tanstack/")) deps[dep] = dep.includes("query") ? "^5.90.0" : dep.includes("table") ? "^8.21.0" : "^3.13.0";
|
|
217
|
-
else if (dep === "zod") deps[dep] = "^4.0.0";
|
|
218
299
|
const devDeps = {
|
|
219
|
-
"@pyreon/vite-plugin": "
|
|
220
|
-
"@pyreon/zero-cli": "
|
|
300
|
+
"@pyreon/vite-plugin": pyreonVersion("@pyreon/vite-plugin"),
|
|
301
|
+
"@pyreon/zero-cli": pyreonVersion("@pyreon/zero-cli"),
|
|
221
302
|
"typescript": "^5.9.3",
|
|
222
303
|
"vite": "^7.0.0"
|
|
223
304
|
};
|
|
224
|
-
if (config.aiToolchain) devDeps["@pyreon/mcp"] = "
|
|
305
|
+
if (config.aiToolchain) devDeps["@pyreon/mcp"] = pyreonVersion("@pyreon/mcp");
|
|
225
306
|
const pkg = {
|
|
226
307
|
name: basename(config.name),
|
|
227
308
|
version: "0.0.1",
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { cp, readFile, writeFile } from 'node:fs/promises'\nimport { basename, join, resolve } from 'node:path'\nimport * as p from '@clack/prompts'\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\ninterface ProjectConfig {\n name: string\n targetDir: string\n renderMode: 'ssr-stream' | 'ssr-string' | 'ssg' | 'spa'\n features: string[]\n aiToolchain: boolean\n}\n\n// ─── Feature definitions ────────────────────────────────────────────────────\n\nconst FEATURES = {\n store: {\n label: 'State Management (@pyreon/store)',\n deps: ['@pyreon/store'],\n },\n query: {\n label: 'Data Fetching (@pyreon/query)',\n deps: ['@pyreon/query', '@tanstack/query-core'],\n },\n forms: {\n label: 'Forms + Validation (@pyreon/form, @pyreon/validation)',\n deps: ['@pyreon/form', '@pyreon/validation', 'zod'],\n },\n feature: {\n label: 'Feature CRUD (@pyreon/feature) — includes store, query, forms',\n deps: [\n '@pyreon/feature',\n '@pyreon/store',\n '@pyreon/query',\n '@pyreon/form',\n '@pyreon/validation',\n '@tanstack/query-core',\n 'zod',\n ],\n },\n i18n: {\n label: 'Internationalization (@pyreon/i18n)',\n deps: ['@pyreon/i18n'],\n },\n table: {\n label: 'Tables (@pyreon/table)',\n deps: ['@pyreon/table', '@tanstack/table-core'],\n },\n virtual: {\n label: 'Virtual Lists (@pyreon/virtual)',\n deps: ['@pyreon/virtual', '@tanstack/virtual-core'],\n },\n styler: {\n label: 'CSS-in-JS (@pyreon/styler)',\n deps: ['@pyreon/styler', '@pyreon/ui-core'],\n },\n elements: {\n label: 'UI Elements (@pyreon/elements, @pyreon/coolgrid)',\n deps: ['@pyreon/elements', '@pyreon/coolgrid', '@pyreon/unistyle', '@pyreon/ui-core'],\n },\n animations: {\n label: 'Animations (@pyreon/kinetic + 120 presets)',\n deps: ['@pyreon/kinetic', '@pyreon/kinetic-presets'],\n },\n hooks: {\n label: 'Hooks (@pyreon/hooks — 25+ signal-based utilities)',\n deps: ['@pyreon/hooks'],\n },\n} as const\n\ntype FeatureKey = keyof typeof FEATURES\n\n// ─── Template directory ─────────────────────────────────────────────────────\n\nconst TEMPLATE_DIR = resolve(import.meta.dirname, '../templates/default')\n\n// ─── Main ───────────────────────────────────────────────────────────────────\n\nasync function main() {\n const args = process.argv.slice(2)\n const argName = args[0]\n\n if (argName === '--help' || argName === '-h') {\n console.log('Usage: create-zero [project-name]')\n process.exit(0)\n }\n\n p.intro('Create a new Pyreon Zero project')\n\n // Project name\n const name = argName ?? (await p.text({\n message: 'Project name',\n placeholder: 'my-zero-app',\n validate: (v) => {\n if (!v?.trim()) return 'Project name is required'\n if (existsSync(resolve(process.cwd(), v))) return `Directory \"${v}\" already exists`\n },\n }))\n\n if (p.isCancel(name)) {\n p.cancel('Cancelled.')\n process.exit(0)\n }\n\n const targetDir = resolve(process.cwd(), name as string)\n if (existsSync(targetDir)) {\n p.cancel(`Directory \"${name}\" already exists.`)\n process.exit(1)\n }\n\n // Rendering mode\n const renderMode = await p.select({\n message: 'Rendering mode',\n options: [\n { value: 'ssr-stream', label: 'SSR Streaming', hint: 'recommended — progressive HTML with Suspense' },\n { value: 'ssr-string', label: 'SSR String', hint: 'buffered HTML, simpler but slower TTFB' },\n { value: 'ssg', label: 'Static (SSG)', hint: 'pre-rendered at build time' },\n { value: 'spa', label: 'SPA', hint: 'client-only, no server rendering' },\n ],\n })\n\n if (p.isCancel(renderMode)) {\n p.cancel('Cancelled.')\n process.exit(0)\n }\n\n // Features\n const features = await p.multiselect({\n message: 'Select features (space to toggle, enter to confirm)',\n options: Object.entries(FEATURES).map(([key, { label }]) => ({\n value: key,\n label,\n })),\n initialValues: ['store', 'query', 'forms'],\n required: false,\n })\n\n if (p.isCancel(features)) {\n p.cancel('Cancelled.')\n process.exit(0)\n }\n\n // AI toolchain\n const aiToolchain = await p.confirm({\n message: 'Include AI toolchain? (MCP server, CLAUDE.md, doctor)',\n initialValue: true,\n })\n\n if (p.isCancel(aiToolchain)) {\n p.cancel('Cancelled.')\n process.exit(0)\n }\n\n const config: ProjectConfig = {\n name: name as string,\n targetDir,\n renderMode: renderMode as ProjectConfig['renderMode'],\n features: features as string[],\n aiToolchain: aiToolchain as boolean,\n }\n\n const s = p.spinner()\n s.start('Scaffolding project...')\n\n await scaffold(config)\n\n s.stop('Project created!')\n\n // Next steps\n p.note(\n [\n `cd ${config.name}`,\n 'bun install',\n 'bun run dev',\n ].join('\\n'),\n 'Next steps',\n )\n\n p.outro('Happy building!')\n}\n\n// ─── Scaffolding ────────────────────────────────────────────────────────────\n\nasync function scaffold(config: ProjectConfig) {\n // Copy full template as base\n await cp(TEMPLATE_DIR, config.targetDir, { recursive: true })\n\n // Generate customized files\n await writeFile(\n join(config.targetDir, 'package.json'),\n generatePackageJson(config),\n )\n\n await writeFile(\n join(config.targetDir, 'vite.config.ts'),\n generateViteConfig(config),\n )\n\n await writeFile(\n join(config.targetDir, 'src/entry-server.ts'),\n generateEntryServer(config),\n )\n\n await writeFile(\n join(config.targetDir, 'env.d.ts'),\n generateEnvDts(config),\n )\n\n // Create .gitignore (npm strips it from packages)\n await writeFile(\n join(config.targetDir, '.gitignore'),\n 'node_modules\\ndist\\n.DS_Store\\n*.local\\n.pyreon\\n',\n )\n\n // AI toolchain files\n if (config.aiToolchain) {\n await writeFile(\n join(config.targetDir, '.mcp.json'),\n JSON.stringify(\n {\n mcpServers: {\n pyreon: { command: 'bunx', args: ['@pyreon/mcp'] },\n },\n },\n null,\n 2,\n ),\n )\n } else {\n // Remove AI files from copied template\n const aiFiles = ['.mcp.json', 'CLAUDE.md']\n for (const f of aiFiles) {\n const path = join(config.targetDir, f)\n if (existsSync(path)) {\n const { unlink } = await import('node:fs/promises')\n await unlink(path)\n }\n }\n }\n\n // Remove feature-specific files if features not selected\n if (!config.features.includes('feature') && !config.features.includes('forms')) {\n await removeIfExists(join(config.targetDir, 'src/routes/posts/new.tsx'))\n await removeIfExists(join(config.targetDir, 'src/features'))\n }\n\n if (!config.features.includes('store')) {\n await removeIfExists(join(config.targetDir, 'src/stores'))\n }\n\n // Remove store import from layout if store not selected\n if (!config.features.includes('store')) {\n const layoutPath = join(config.targetDir, 'src/routes/_layout.tsx')\n if (existsSync(layoutPath)) {\n let layout = await readFile(layoutPath, 'utf-8')\n layout = layout\n .replace(/import .* from '\\.\\.\\/stores\\/app'\\n/g, '')\n .replace(/.*useAppStore.*\\n/g, '')\n .replace(/\\s*<button[\\s\\S]*?sidebar-toggle[\\s\\S]*?<\\/button>\\n/g, '')\n await writeFile(layoutPath, layout)\n }\n }\n}\n\n// ─── File generators ────────────────────────────────────────────────────────\n\nfunction generatePackageJson(config: ProjectConfig): string {\n const deps: Record<string, string> = {\n '@pyreon/core': 'latest',\n '@pyreon/head': 'latest',\n '@pyreon/reactivity': 'latest',\n '@pyreon/router': 'latest',\n '@pyreon/runtime-dom': 'latest',\n '@pyreon/runtime-server': 'latest',\n '@pyreon/server': 'latest',\n '@pyreon/zero': 'latest',\n }\n\n // Add feature-specific deps\n const allDeps = new Set<string>()\n for (const key of config.features) {\n const feature = FEATURES[key as FeatureKey]\n if (feature) {\n for (const dep of feature.deps) allDeps.add(dep)\n }\n }\n for (const dep of allDeps) {\n if (dep.startsWith('@pyreon/')) {\n deps[dep] = 'latest'\n } else if (dep.startsWith('@tanstack/')) {\n deps[dep] = dep.includes('query') ? '^5.90.0' : dep.includes('table') ? '^8.21.0' : '^3.13.0'\n } else if (dep === 'zod') {\n deps[dep] = '^4.0.0'\n }\n }\n\n const devDeps: Record<string, string> = {\n '@pyreon/vite-plugin': 'latest',\n '@pyreon/zero-cli': 'latest',\n 'typescript': '^5.9.3',\n 'vite': '^7.0.0',\n }\n\n if (config.aiToolchain) {\n devDeps['@pyreon/mcp'] = 'latest'\n }\n\n const scripts: Record<string, string> = {\n dev: 'zero dev',\n build: 'zero build',\n preview: 'zero preview',\n doctor: 'zero doctor',\n 'doctor:fix': 'zero doctor --fix',\n 'doctor:ci': 'zero doctor --ci',\n }\n\n const pkg = {\n name: basename(config.name),\n version: '0.0.1',\n private: true,\n type: 'module',\n scripts,\n dependencies: Object.fromEntries(Object.entries(deps).sort(([a], [b]) => a.localeCompare(b))),\n devDependencies: Object.fromEntries(Object.entries(devDeps).sort(([a], [b]) => a.localeCompare(b))),\n }\n\n return `${JSON.stringify(pkg, null, 2)}\\n`\n}\n\nfunction generateViteConfig(config: ProjectConfig): string {\n const modeMap = {\n 'ssr-stream': `mode: 'ssr', ssr: { mode: 'stream' }`,\n 'ssr-string': `mode: 'ssr'`,\n ssg: `mode: 'ssg'`,\n spa: `mode: 'spa'`,\n }\n\n return `import pyreon from '@pyreon/vite-plugin'\nimport zero from '@pyreon/zero'\nimport { fontPlugin } from '@pyreon/zero/font'\nimport { seoPlugin } from '@pyreon/zero/seo'\n\nexport default {\n plugins: [\n pyreon(),\n zero({ ${modeMap[config.renderMode]} }),\n\n // Google Fonts — self-hosted at build time, CDN in dev\n fontPlugin({\n google: ['Inter:wght@400;500;600;700;800', 'JetBrains Mono:wght@400'],\n fallbacks: {\n Inter: { fallback: 'Arial', sizeAdjust: 1.07, ascentOverride: 90 },\n },\n }),\n\n // Generate sitemap.xml and robots.txt at build time\n seoPlugin({\n sitemap: { origin: 'https://example.com' },\n robots: {\n rules: [{ userAgent: '*', allow: ['/'] }],\n sitemap: 'https://example.com/sitemap.xml',\n },\n }),\n ],\n}\n`\n}\n\nfunction generateEntryServer(config: ProjectConfig): string {\n const imports = [\n `import { routes } from 'virtual:zero/routes'`,\n `import { routeMiddleware } from 'virtual:zero/route-middleware'`,\n `import { createServer } from '@pyreon/zero'`,\n `import {\\n cacheMiddleware,\\n securityHeaders,\\n varyEncoding,\\n} from '@pyreon/zero/cache'`,\n ]\n\n const modeMap = {\n 'ssr-stream': `stream`,\n 'ssr-string': `string`,\n ssg: `string`,\n spa: `string`,\n }\n\n return `${imports.join('\\n')}\n\nexport default createServer({\n routes,\n routeMiddleware,\n config: {\n ssr: { mode: '${modeMap[config.renderMode]}' },\n },\n middleware: [\n securityHeaders(),\n cacheMiddleware({ staleWhileRevalidate: 120 }),\n varyEncoding(),\n ],\n})\n`\n}\n\nfunction generateEnvDts(config: ProjectConfig): string {\n let content = `/// <reference types=\"vite/client\" />\n\ndeclare module 'virtual:zero/routes' {\n import type { RouteRecord } from '@pyreon/router'\n export const routes: RouteRecord[]\n}\n\ndeclare module 'virtual:zero/route-middleware' {\n import type { RouteMiddlewareEntry } from '@pyreon/zero'\n export const routeMiddleware: RouteMiddlewareEntry[]\n}\n`\n\n if (config.features.includes('query')) {\n content += `\ndeclare module 'virtual:zero/actions' {\n export {}\n}\n`\n }\n\n return content\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\nasync function removeIfExists(path: string) {\n if (!existsSync(path)) return\n const { rm } = await import('node:fs/promises')\n await rm(path, { recursive: true })\n}\n\nmain().catch((err) => {\n console.error(err)\n process.exit(1)\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { cp, readFile, writeFile } from 'node:fs/promises'\nimport { basename, join, resolve } from 'node:path'\nimport * as p from '@clack/prompts'\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\ninterface ProjectConfig {\n name: string\n targetDir: string\n renderMode: 'ssr-stream' | 'ssr-string' | 'ssg' | 'spa'\n features: string[]\n packageStrategy: 'meta' | 'individual'\n aiToolchain: boolean\n}\n\n// ─── Feature definitions ────────────────────────────────────────────────────\n\nconst FEATURES = {\n store: {\n label: 'State Management (@pyreon/store)',\n deps: ['@pyreon/store'],\n },\n query: {\n label: 'Data Fetching (@pyreon/query)',\n deps: ['@pyreon/query', '@tanstack/query-core'],\n },\n forms: {\n label: 'Forms + Validation (@pyreon/form, @pyreon/validation)',\n deps: ['@pyreon/form', '@pyreon/validation', 'zod'],\n },\n feature: {\n label: 'Feature CRUD (@pyreon/feature) — includes store, query, forms',\n deps: [\n '@pyreon/feature',\n '@pyreon/store',\n '@pyreon/query',\n '@pyreon/form',\n '@pyreon/validation',\n '@tanstack/query-core',\n 'zod',\n ],\n },\n i18n: {\n label: 'Internationalization (@pyreon/i18n)',\n deps: ['@pyreon/i18n'],\n },\n table: {\n label: 'Tables (@pyreon/table)',\n deps: ['@pyreon/table', '@tanstack/table-core'],\n },\n virtual: {\n label: 'Virtual Lists (@pyreon/virtual)',\n deps: ['@pyreon/virtual', '@tanstack/virtual-core'],\n },\n styler: {\n label: 'CSS-in-JS (@pyreon/styler)',\n deps: ['@pyreon/styler', '@pyreon/ui-core'],\n },\n elements: {\n label: 'UI Elements (@pyreon/elements, @pyreon/coolgrid)',\n deps: ['@pyreon/elements', '@pyreon/coolgrid', '@pyreon/unistyle', '@pyreon/ui-core'],\n },\n animations: {\n label: 'Animations (@pyreon/kinetic + 120 presets)',\n deps: ['@pyreon/kinetic', '@pyreon/kinetic-presets'],\n },\n hooks: {\n label: 'Hooks (@pyreon/hooks — 25+ signal-based utilities)',\n deps: ['@pyreon/hooks'],\n },\n charts: {\n label: 'Charts (@pyreon/charts — reactive ECharts)',\n deps: ['@pyreon/charts'],\n },\n hotkeys: {\n label: 'Hotkeys (@pyreon/hotkeys — keyboard shortcuts)',\n deps: ['@pyreon/hotkeys'],\n },\n storage: {\n label: 'Storage (@pyreon/storage — localStorage, cookies, IndexedDB)',\n deps: ['@pyreon/storage'],\n },\n flow: {\n label: 'Flow Diagrams (@pyreon/flow — reactive node graphs)',\n deps: ['@pyreon/flow'],\n },\n code: {\n label: 'Code Editor (@pyreon/code — CodeMirror 6)',\n deps: ['@pyreon/code'],\n },\n} as const\n\ntype FeatureKey = keyof typeof FEATURES\n\n// ─── Template directory ─────────────────────────────────────────────────────\n\nconst TEMPLATE_DIR = resolve(import.meta.dirname, '../templates/default')\n\n// ─── Main ───────────────────────────────────────────────────────────────────\n\nasync function main() {\n const args = process.argv.slice(2)\n const argName = args[0]\n\n if (argName === '--help' || argName === '-h') {\n console.log('Usage: create-zero [project-name]')\n process.exit(0)\n }\n\n p.intro('Create a new Pyreon Zero project')\n\n // Project name\n const name = argName ?? (await p.text({\n message: 'Project name',\n placeholder: 'my-zero-app',\n validate: (v) => {\n if (!v?.trim()) return 'Project name is required'\n if (existsSync(resolve(process.cwd(), v))) return `Directory \"${v}\" already exists`\n },\n }))\n\n if (p.isCancel(name)) {\n p.cancel('Cancelled.')\n process.exit(0)\n }\n\n const targetDir = resolve(process.cwd(), name as string)\n if (existsSync(targetDir)) {\n p.cancel(`Directory \"${name}\" already exists.`)\n process.exit(1)\n }\n\n // Rendering mode\n const renderMode = await p.select({\n message: 'Rendering mode',\n options: [\n { value: 'ssr-stream', label: 'SSR Streaming', hint: 'recommended — progressive HTML with Suspense' },\n { value: 'ssr-string', label: 'SSR String', hint: 'buffered HTML, simpler but slower TTFB' },\n { value: 'ssg', label: 'Static (SSG)', hint: 'pre-rendered at build time' },\n { value: 'spa', label: 'SPA', hint: 'client-only, no server rendering' },\n ],\n })\n\n if (p.isCancel(renderMode)) {\n p.cancel('Cancelled.')\n process.exit(0)\n }\n\n // Features\n const features = await p.multiselect({\n message: 'Select features (space to toggle, enter to confirm)',\n options: Object.entries(FEATURES).map(([key, { label }]) => ({\n value: key,\n label,\n })),\n initialValues: ['store', 'query', 'forms'],\n required: false,\n })\n\n if (p.isCancel(features)) {\n p.cancel('Cancelled.')\n process.exit(0)\n }\n\n // Package strategy\n const packageStrategy = await p.select({\n message: 'Package imports',\n options: [\n { value: 'meta', label: '@pyreon/meta (single barrel)', hint: 'one import for everything — simpler, tree-shaken at build' },\n { value: 'individual', label: 'Individual packages', hint: 'only install what you selected — smaller node_modules' },\n ],\n })\n\n if (p.isCancel(packageStrategy)) {\n p.cancel('Cancelled.')\n process.exit(0)\n }\n\n // AI toolchain\n const aiToolchain = await p.confirm({\n message: 'Include AI toolchain? (MCP server, CLAUDE.md, doctor)',\n initialValue: true,\n })\n\n if (p.isCancel(aiToolchain)) {\n p.cancel('Cancelled.')\n process.exit(0)\n }\n\n const config: ProjectConfig = {\n name: name as string,\n targetDir,\n renderMode: renderMode as ProjectConfig['renderMode'],\n features: features as string[],\n packageStrategy: packageStrategy as ProjectConfig['packageStrategy'],\n aiToolchain: aiToolchain as boolean,\n }\n\n const s = p.spinner()\n s.start('Scaffolding project...')\n\n await scaffold(config)\n\n s.stop('Project created!')\n\n // Next steps\n p.note(\n [\n `cd ${config.name}`,\n 'bun install',\n 'bun run dev',\n ].join('\\n'),\n 'Next steps',\n )\n\n p.outro('Happy building!')\n}\n\n// ─── Scaffolding ────────────────────────────────────────────────────────────\n\nasync function scaffold(config: ProjectConfig) {\n // Copy full template as base\n await cp(TEMPLATE_DIR, config.targetDir, { recursive: true })\n\n // Generate customized files\n await writeFile(\n join(config.targetDir, 'package.json'),\n generatePackageJson(config),\n )\n\n await writeFile(\n join(config.targetDir, 'vite.config.ts'),\n generateViteConfig(config),\n )\n\n await writeFile(\n join(config.targetDir, 'src/entry-server.ts'),\n generateEntryServer(config),\n )\n\n await writeFile(\n join(config.targetDir, 'env.d.ts'),\n generateEnvDts(config),\n )\n\n // Create .gitignore (npm strips it from packages)\n await writeFile(\n join(config.targetDir, '.gitignore'),\n 'node_modules\\ndist\\n.DS_Store\\n*.local\\n.pyreon\\n',\n )\n\n // AI toolchain files\n if (config.aiToolchain) {\n await writeFile(\n join(config.targetDir, '.mcp.json'),\n JSON.stringify(\n {\n mcpServers: {\n pyreon: { command: 'bunx', args: ['@pyreon/mcp'] },\n },\n },\n null,\n 2,\n ),\n )\n } else {\n // Remove AI files from copied template\n const aiFiles = ['.mcp.json', 'CLAUDE.md']\n for (const f of aiFiles) {\n const path = join(config.targetDir, f)\n if (existsSync(path)) {\n const { unlink } = await import('node:fs/promises')\n await unlink(path)\n }\n }\n }\n\n // Remove feature-specific files if features not selected\n if (!config.features.includes('feature') && !config.features.includes('forms')) {\n await removeIfExists(join(config.targetDir, 'src/routes/posts/new.tsx'))\n await removeIfExists(join(config.targetDir, 'src/features'))\n }\n\n if (!config.features.includes('store')) {\n await removeIfExists(join(config.targetDir, 'src/stores'))\n }\n\n // Remove store import from layout if store not selected\n if (!config.features.includes('store')) {\n const layoutPath = join(config.targetDir, 'src/routes/_layout.tsx')\n if (existsSync(layoutPath)) {\n let layout = await readFile(layoutPath, 'utf-8')\n layout = layout\n .replace(/import .* from '\\.\\.\\/stores\\/app'\\n/g, '')\n .replace(/.*useAppStore.*\\n/g, '')\n .replace(/\\s*<button[\\s\\S]*?sidebar-toggle[\\s\\S]*?<\\/button>\\n/g, '')\n await writeFile(layoutPath, layout)\n }\n }\n}\n\n// ─── File generators ────────────────────────────────────────────────────────\n\n// Resolve the correct version range for a @pyreon/* package\nfunction pyreonVersion(pkg: string): string {\n // Core packages\n const core = ['core', 'reactivity', 'runtime-dom', 'runtime-server', 'server', 'head', 'router', 'vite-plugin', 'compiler', 'cli', 'mcp']\n if (core.some((c) => pkg === `@pyreon/${c}`)) return '^0.7.5'\n // Zero framework packages\n if (pkg === '@pyreon/zero' || pkg === '@pyreon/meta' || pkg === '@pyreon/zero-cli' || pkg === '@pyreon/create-zero') return '^0.3.0'\n // Fundamentals\n const fundamentals = ['store', 'form', 'validation', 'query', 'table', 'virtual', 'i18n', 'feature', 'machine', 'permissions', 'flow', 'code']\n if (fundamentals.some((f) => pkg === `@pyreon/${f}`)) return '^0.9.0'\n // UI system\n return '^0.3.0'\n}\n\nfunction generatePackageJson(config: ProjectConfig): string {\n const deps: Record<string, string> = {\n '@pyreon/core': pyreonVersion('@pyreon/core'),\n '@pyreon/head': pyreonVersion('@pyreon/head'),\n '@pyreon/reactivity': pyreonVersion('@pyreon/reactivity'),\n '@pyreon/router': pyreonVersion('@pyreon/router'),\n '@pyreon/runtime-dom': pyreonVersion('@pyreon/runtime-dom'),\n '@pyreon/runtime-server': pyreonVersion('@pyreon/runtime-server'),\n '@pyreon/server': pyreonVersion('@pyreon/server'),\n '@pyreon/zero': pyreonVersion('@pyreon/zero'),\n }\n\n if (config.packageStrategy === 'meta') {\n // Single barrel — includes all fundamentals + UI system\n deps['@pyreon/meta'] = pyreonVersion('@pyreon/meta')\n // Still need non-pyreon deps for selected features\n for (const key of config.features) {\n const feature = FEATURES[key as FeatureKey]\n if (feature) {\n for (const dep of feature.deps) {\n if (!dep.startsWith('@pyreon/')) {\n if (dep.startsWith('@tanstack/')) {\n deps[dep] = dep.includes('query') ? '^5.90.0' : dep.includes('table') ? '^8.21.0' : '^3.13.0'\n } else if (dep === 'zod') {\n deps[dep] = '^4.0.0'\n }\n }\n }\n }\n }\n } else {\n // Individual packages — only install what's selected\n const allDeps = new Set<string>()\n for (const key of config.features) {\n const feature = FEATURES[key as FeatureKey]\n if (feature) {\n for (const dep of feature.deps) allDeps.add(dep)\n }\n }\n for (const dep of allDeps) {\n if (dep.startsWith('@pyreon/')) {\n deps[dep] = pyreonVersion(dep)\n } else if (dep.startsWith('@tanstack/')) {\n deps[dep] = dep.includes('query') ? '^5.90.0' : dep.includes('table') ? '^8.21.0' : '^3.13.0'\n } else if (dep === 'zod') {\n deps[dep] = '^4.0.0'\n }\n }\n }\n\n const devDeps: Record<string, string> = {\n '@pyreon/vite-plugin': pyreonVersion('@pyreon/vite-plugin'),\n '@pyreon/zero-cli': pyreonVersion('@pyreon/zero-cli'),\n 'typescript': '^5.9.3',\n 'vite': '^7.0.0',\n }\n\n if (config.aiToolchain) {\n devDeps['@pyreon/mcp'] = pyreonVersion('@pyreon/mcp')\n }\n\n const scripts: Record<string, string> = {\n dev: 'zero dev',\n build: 'zero build',\n preview: 'zero preview',\n doctor: 'zero doctor',\n 'doctor:fix': 'zero doctor --fix',\n 'doctor:ci': 'zero doctor --ci',\n }\n\n const pkg = {\n name: basename(config.name),\n version: '0.0.1',\n private: true,\n type: 'module',\n scripts,\n dependencies: Object.fromEntries(Object.entries(deps).sort(([a], [b]) => a.localeCompare(b))),\n devDependencies: Object.fromEntries(Object.entries(devDeps).sort(([a], [b]) => a.localeCompare(b))),\n }\n\n return `${JSON.stringify(pkg, null, 2)}\\n`\n}\n\nfunction generateViteConfig(config: ProjectConfig): string {\n const modeMap = {\n 'ssr-stream': `mode: 'ssr', ssr: { mode: 'stream' }`,\n 'ssr-string': `mode: 'ssr'`,\n ssg: `mode: 'ssg'`,\n spa: `mode: 'spa'`,\n }\n\n return `import pyreon from '@pyreon/vite-plugin'\nimport zero from '@pyreon/zero'\nimport { fontPlugin } from '@pyreon/zero/font'\nimport { seoPlugin } from '@pyreon/zero/seo'\n\nexport default {\n plugins: [\n pyreon(),\n zero({ ${modeMap[config.renderMode]} }),\n\n // Google Fonts — self-hosted at build time, CDN in dev\n fontPlugin({\n google: ['Inter:wght@400;500;600;700;800', 'JetBrains Mono:wght@400'],\n fallbacks: {\n Inter: { fallback: 'Arial', sizeAdjust: 1.07, ascentOverride: 90 },\n },\n }),\n\n // Generate sitemap.xml and robots.txt at build time\n seoPlugin({\n sitemap: { origin: 'https://example.com' },\n robots: {\n rules: [{ userAgent: '*', allow: ['/'] }],\n sitemap: 'https://example.com/sitemap.xml',\n },\n }),\n ],\n}\n`\n}\n\nfunction generateEntryServer(config: ProjectConfig): string {\n const imports = [\n `import { routes } from 'virtual:zero/routes'`,\n `import { routeMiddleware } from 'virtual:zero/route-middleware'`,\n `import { createServer } from '@pyreon/zero'`,\n `import {\\n cacheMiddleware,\\n securityHeaders,\\n varyEncoding,\\n} from '@pyreon/zero/cache'`,\n ]\n\n const modeMap = {\n 'ssr-stream': `stream`,\n 'ssr-string': `string`,\n ssg: `string`,\n spa: `string`,\n }\n\n return `${imports.join('\\n')}\n\nexport default createServer({\n routes,\n routeMiddleware,\n config: {\n ssr: { mode: '${modeMap[config.renderMode]}' },\n },\n middleware: [\n securityHeaders(),\n cacheMiddleware({ staleWhileRevalidate: 120 }),\n varyEncoding(),\n ],\n})\n`\n}\n\nfunction generateEnvDts(config: ProjectConfig): string {\n let content = `/// <reference types=\"vite/client\" />\n\ndeclare module 'virtual:zero/routes' {\n import type { RouteRecord } from '@pyreon/router'\n export const routes: RouteRecord[]\n}\n\ndeclare module 'virtual:zero/route-middleware' {\n import type { RouteMiddlewareEntry } from '@pyreon/zero'\n export const routeMiddleware: RouteMiddlewareEntry[]\n}\n`\n\n if (config.features.includes('query')) {\n content += `\ndeclare module 'virtual:zero/actions' {\n export {}\n}\n`\n }\n\n return content\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\nasync function removeIfExists(path: string) {\n if (!existsSync(path)) return\n const { rm } = await import('node:fs/promises')\n await rm(path, { recursive: true })\n}\n\nmain().catch((err) => {\n console.error(err)\n process.exit(1)\n})\n"],"mappings":";;;;;;AAkBA,MAAM,WAAW;CACf,OAAO;EACL,OAAO;EACP,MAAM,CAAC,gBAAgB;EACxB;CACD,OAAO;EACL,OAAO;EACP,MAAM,CAAC,iBAAiB,uBAAuB;EAChD;CACD,OAAO;EACL,OAAO;EACP,MAAM;GAAC;GAAgB;GAAsB;GAAM;EACpD;CACD,SAAS;EACP,OAAO;EACP,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;GACA;GACD;EACF;CACD,MAAM;EACJ,OAAO;EACP,MAAM,CAAC,eAAe;EACvB;CACD,OAAO;EACL,OAAO;EACP,MAAM,CAAC,iBAAiB,uBAAuB;EAChD;CACD,SAAS;EACP,OAAO;EACP,MAAM,CAAC,mBAAmB,yBAAyB;EACpD;CACD,QAAQ;EACN,OAAO;EACP,MAAM,CAAC,kBAAkB,kBAAkB;EAC5C;CACD,UAAU;EACR,OAAO;EACP,MAAM;GAAC;GAAoB;GAAoB;GAAoB;GAAkB;EACtF;CACD,YAAY;EACV,OAAO;EACP,MAAM,CAAC,mBAAmB,0BAA0B;EACrD;CACD,OAAO;EACL,OAAO;EACP,MAAM,CAAC,gBAAgB;EACxB;CACD,QAAQ;EACN,OAAO;EACP,MAAM,CAAC,iBAAiB;EACzB;CACD,SAAS;EACP,OAAO;EACP,MAAM,CAAC,kBAAkB;EAC1B;CACD,SAAS;EACP,OAAO;EACP,MAAM,CAAC,kBAAkB;EAC1B;CACD,MAAM;EACJ,OAAO;EACP,MAAM,CAAC,eAAe;EACvB;CACD,MAAM;EACJ,OAAO;EACP,MAAM,CAAC,eAAe;EACvB;CACF;AAMD,MAAM,eAAe,QAAQ,OAAO,KAAK,SAAS,uBAAuB;AAIzE,eAAe,OAAO;CAEpB,MAAM,UADO,QAAQ,KAAK,MAAM,EAAE,CACb;AAErB,KAAI,YAAY,YAAY,YAAY,MAAM;AAC5C,UAAQ,IAAI,oCAAoC;AAChD,UAAQ,KAAK,EAAE;;AAGjB,GAAE,MAAM,mCAAmC;CAG3C,MAAM,OAAO,WAAY,MAAM,EAAE,KAAK;EACpC,SAAS;EACT,aAAa;EACb,WAAW,MAAM;AACf,OAAI,CAAC,GAAG,MAAM,CAAE,QAAO;AACvB,OAAI,WAAW,QAAQ,QAAQ,KAAK,EAAE,EAAE,CAAC,CAAE,QAAO,cAAc,EAAE;;EAErE,CAAC;AAEF,KAAI,EAAE,SAAS,KAAK,EAAE;AACpB,IAAE,OAAO,aAAa;AACtB,UAAQ,KAAK,EAAE;;CAGjB,MAAM,YAAY,QAAQ,QAAQ,KAAK,EAAE,KAAe;AACxD,KAAI,WAAW,UAAU,EAAE;AACzB,IAAE,OAAO,cAAc,KAAK,mBAAmB;AAC/C,UAAQ,KAAK,EAAE;;CAIjB,MAAM,aAAa,MAAM,EAAE,OAAO;EAChC,SAAS;EACT,SAAS;GACP;IAAE,OAAO;IAAc,OAAO;IAAiB,MAAM;IAAgD;GACrG;IAAE,OAAO;IAAc,OAAO;IAAc,MAAM;IAA0C;GAC5F;IAAE,OAAO;IAAO,OAAO;IAAgB,MAAM;IAA8B;GAC3E;IAAE,OAAO;IAAO,OAAO;IAAO,MAAM;IAAoC;GACzE;EACF,CAAC;AAEF,KAAI,EAAE,SAAS,WAAW,EAAE;AAC1B,IAAE,OAAO,aAAa;AACtB,UAAQ,KAAK,EAAE;;CAIjB,MAAM,WAAW,MAAM,EAAE,YAAY;EACnC,SAAS;EACT,SAAS,OAAO,QAAQ,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,cAAc;GAC3D,OAAO;GACP;GACD,EAAE;EACH,eAAe;GAAC;GAAS;GAAS;GAAQ;EAC1C,UAAU;EACX,CAAC;AAEF,KAAI,EAAE,SAAS,SAAS,EAAE;AACxB,IAAE,OAAO,aAAa;AACtB,UAAQ,KAAK,EAAE;;CAIjB,MAAM,kBAAkB,MAAM,EAAE,OAAO;EACrC,SAAS;EACT,SAAS,CACP;GAAE,OAAO;GAAQ,OAAO;GAAgC,MAAM;GAA6D,EAC3H;GAAE,OAAO;GAAc,OAAO;GAAuB,MAAM;GAAyD,CACrH;EACF,CAAC;AAEF,KAAI,EAAE,SAAS,gBAAgB,EAAE;AAC/B,IAAE,OAAO,aAAa;AACtB,UAAQ,KAAK,EAAE;;CAIjB,MAAM,cAAc,MAAM,EAAE,QAAQ;EAClC,SAAS;EACT,cAAc;EACf,CAAC;AAEF,KAAI,EAAE,SAAS,YAAY,EAAE;AAC3B,IAAE,OAAO,aAAa;AACtB,UAAQ,KAAK,EAAE;;CAGjB,MAAM,SAAwB;EACtB;EACN;EACY;EACF;EACO;EACJ;EACd;CAED,MAAM,IAAI,EAAE,SAAS;AACrB,GAAE,MAAM,yBAAyB;AAEjC,OAAM,SAAS,OAAO;AAEtB,GAAE,KAAK,mBAAmB;AAG1B,GAAE,KACA;EACE,MAAM,OAAO;EACb;EACA;EACD,CAAC,KAAK,KAAK,EACZ,aACD;AAED,GAAE,MAAM,kBAAkB;;AAK5B,eAAe,SAAS,QAAuB;AAE7C,OAAM,GAAG,cAAc,OAAO,WAAW,EAAE,WAAW,MAAM,CAAC;AAG7D,OAAM,UACJ,KAAK,OAAO,WAAW,eAAe,EACtC,oBAAoB,OAAO,CAC5B;AAED,OAAM,UACJ,KAAK,OAAO,WAAW,iBAAiB,EACxC,mBAAmB,OAAO,CAC3B;AAED,OAAM,UACJ,KAAK,OAAO,WAAW,sBAAsB,EAC7C,oBAAoB,OAAO,CAC5B;AAED,OAAM,UACJ,KAAK,OAAO,WAAW,WAAW,EAClC,eAAe,OAAO,CACvB;AAGD,OAAM,UACJ,KAAK,OAAO,WAAW,aAAa,EACpC,oDACD;AAGD,KAAI,OAAO,YACT,OAAM,UACJ,KAAK,OAAO,WAAW,YAAY,EACnC,KAAK,UACH,EACE,YAAY,EACV,QAAQ;EAAE,SAAS;EAAQ,MAAM,CAAC,cAAc;EAAE,EACnD,EACF,EACD,MACA,EACD,CACF;KAID,MAAK,MAAM,KADK,CAAC,aAAa,YAAY,EACjB;EACvB,MAAM,OAAO,KAAK,OAAO,WAAW,EAAE;AACtC,MAAI,WAAW,KAAK,EAAE;GACpB,MAAM,EAAE,WAAW,MAAM,OAAO;AAChC,SAAM,OAAO,KAAK;;;AAMxB,KAAI,CAAC,OAAO,SAAS,SAAS,UAAU,IAAI,CAAC,OAAO,SAAS,SAAS,QAAQ,EAAE;AAC9E,QAAM,eAAe,KAAK,OAAO,WAAW,2BAA2B,CAAC;AACxE,QAAM,eAAe,KAAK,OAAO,WAAW,eAAe,CAAC;;AAG9D,KAAI,CAAC,OAAO,SAAS,SAAS,QAAQ,CACpC,OAAM,eAAe,KAAK,OAAO,WAAW,aAAa,CAAC;AAI5D,KAAI,CAAC,OAAO,SAAS,SAAS,QAAQ,EAAE;EACtC,MAAM,aAAa,KAAK,OAAO,WAAW,yBAAyB;AACnE,MAAI,WAAW,WAAW,EAAE;GAC1B,IAAI,SAAS,MAAM,SAAS,YAAY,QAAQ;AAChD,YAAS,OACN,QAAQ,yCAAyC,GAAG,CACpD,QAAQ,sBAAsB,GAAG,CACjC,QAAQ,yDAAyD,GAAG;AACvE,SAAM,UAAU,YAAY,OAAO;;;;AAQzC,SAAS,cAAc,KAAqB;AAG1C,KADa;EAAC;EAAQ;EAAc;EAAe;EAAkB;EAAU;EAAQ;EAAU;EAAe;EAAY;EAAO;EAAM,CAChI,MAAM,MAAM,QAAQ,WAAW,IAAI,CAAE,QAAO;AAErD,KAAI,QAAQ,kBAAkB,QAAQ,kBAAkB,QAAQ,sBAAsB,QAAQ,sBAAuB,QAAO;AAG5H,KADqB;EAAC;EAAS;EAAQ;EAAc;EAAS;EAAS;EAAW;EAAQ;EAAW;EAAW;EAAe;EAAQ;EAAO,CAC7H,MAAM,MAAM,QAAQ,WAAW,IAAI,CAAE,QAAO;AAE7D,QAAO;;AAGT,SAAS,oBAAoB,QAA+B;CAC1D,MAAM,OAA+B;EACnC,gBAAgB,cAAc,eAAe;EAC7C,gBAAgB,cAAc,eAAe;EAC7C,sBAAsB,cAAc,qBAAqB;EACzD,kBAAkB,cAAc,iBAAiB;EACjD,uBAAuB,cAAc,sBAAsB;EAC3D,0BAA0B,cAAc,yBAAyB;EACjE,kBAAkB,cAAc,iBAAiB;EACjD,gBAAgB,cAAc,eAAe;EAC9C;AAED,KAAI,OAAO,oBAAoB,QAAQ;AAErC,OAAK,kBAAkB,cAAc,eAAe;AAEpD,OAAK,MAAM,OAAO,OAAO,UAAU;GACjC,MAAM,UAAU,SAAS;AACzB,OAAI,SACF;SAAK,MAAM,OAAO,QAAQ,KACxB,KAAI,CAAC,IAAI,WAAW,WAAW,EAC7B;SAAI,IAAI,WAAW,aAAa,CAC9B,MAAK,OAAO,IAAI,SAAS,QAAQ,GAAG,YAAY,IAAI,SAAS,QAAQ,GAAG,YAAY;cAC3E,QAAQ,MACjB,MAAK,OAAO;;;;QAMjB;EAEL,MAAM,0BAAU,IAAI,KAAa;AACjC,OAAK,MAAM,OAAO,OAAO,UAAU;GACjC,MAAM,UAAU,SAAS;AACzB,OAAI,QACF,MAAK,MAAM,OAAO,QAAQ,KAAM,SAAQ,IAAI,IAAI;;AAGpD,OAAK,MAAM,OAAO,QAChB,KAAI,IAAI,WAAW,WAAW,CAC5B,MAAK,OAAO,cAAc,IAAI;WACrB,IAAI,WAAW,aAAa,CACrC,MAAK,OAAO,IAAI,SAAS,QAAQ,GAAG,YAAY,IAAI,SAAS,QAAQ,GAAG,YAAY;WAC3E,QAAQ,MACjB,MAAK,OAAO;;CAKlB,MAAM,UAAkC;EACtC,uBAAuB,cAAc,sBAAsB;EAC3D,oBAAoB,cAAc,mBAAmB;EACrD,cAAc;EACd,QAAQ;EACT;AAED,KAAI,OAAO,YACT,SAAQ,iBAAiB,cAAc,cAAc;CAYvD,MAAM,MAAM;EACV,MAAM,SAAS,OAAO,KAAK;EAC3B,SAAS;EACT,SAAS;EACT,MAAM;EACN,SAdsC;GACtC,KAAK;GACL,OAAO;GACP,SAAS;GACT,QAAQ;GACR,cAAc;GACd,aAAa;GACd;EAQC,cAAc,OAAO,YAAY,OAAO,QAAQ,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;EAC7F,iBAAiB,OAAO,YAAY,OAAO,QAAQ,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;EACpG;AAED,QAAO,GAAG,KAAK,UAAU,KAAK,MAAM,EAAE,CAAC;;AAGzC,SAAS,mBAAmB,QAA+B;AAQzD,QAAO;;;;;;;;aAPS;EACd,cAAc;EACd,cAAc;EACd,KAAK;EACL,KAAK;EACN,CAUkB,OAAO,YAAY;;;;;;;;;;;;;;;;;;;;;;AAuBxC,SAAS,oBAAoB,QAA+B;AAe1D,QAAO,GAdS;EACd;EACA;EACA;EACA;EACD,CASiB,KAAK,KAAK,CAAC;;;;;;oBAPb;EACd,cAAc;EACd,cAAc;EACd,KAAK;EACL,KAAK;EACN,CAQyB,OAAO,YAAY;;;;;;;;;;AAW/C,SAAS,eAAe,QAA+B;CACrD,IAAI,UAAU;;;;;;;;;;;;AAad,KAAI,OAAO,SAAS,SAAS,QAAQ,CACnC,YAAW;;;;;AAOb,QAAO;;AAKT,eAAe,eAAe,MAAc;AAC1C,KAAI,CAAC,WAAW,KAAK,CAAE;CACvB,MAAM,EAAE,OAAO,MAAM,OAAO;AAC5B,OAAM,GAAG,MAAM,EAAE,WAAW,MAAM,CAAC;;AAGrC,MAAM,CAAC,OAAO,QAAQ;AACpB,SAAQ,MAAM,IAAI;AAClB,SAAQ,KAAK,EAAE;EACf"}
|
package/package.json
CHANGED
|
@@ -12,42 +12,18 @@
|
|
|
12
12
|
"doctor:ci": "zero doctor --ci"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@pyreon/
|
|
16
|
-
"@pyreon/
|
|
17
|
-
"@pyreon/core": "latest",
|
|
18
|
-
"@pyreon/elements": "latest",
|
|
19
|
-
"@pyreon/feature": "latest",
|
|
20
|
-
"@pyreon/form": "latest",
|
|
21
|
-
"@pyreon/head": "latest",
|
|
22
|
-
"@pyreon/hooks": "latest",
|
|
23
|
-
"@pyreon/i18n": "latest",
|
|
24
|
-
"@pyreon/kinetic": "latest",
|
|
25
|
-
"@pyreon/kinetic-presets": "latest",
|
|
26
|
-
"@pyreon/query": "latest",
|
|
27
|
-
"@pyreon/reactivity": "latest",
|
|
28
|
-
"@pyreon/rocketstyle": "latest",
|
|
29
|
-
"@pyreon/router": "latest",
|
|
30
|
-
"@pyreon/runtime-dom": "latest",
|
|
31
|
-
"@pyreon/runtime-server": "latest",
|
|
32
|
-
"@pyreon/server": "latest",
|
|
33
|
-
"@pyreon/store": "latest",
|
|
34
|
-
"@pyreon/styler": "latest",
|
|
35
|
-
"@pyreon/table": "latest",
|
|
36
|
-
"@pyreon/ui-core": "latest",
|
|
37
|
-
"@pyreon/unistyle": "latest",
|
|
38
|
-
"@pyreon/validation": "latest",
|
|
39
|
-
"@pyreon/virtual": "latest",
|
|
40
|
-
"@pyreon/zero": "latest",
|
|
15
|
+
"@pyreon/meta": "^0.3.0",
|
|
16
|
+
"@pyreon/zero": "^0.3.0",
|
|
41
17
|
"@tanstack/query-core": "^5.90.0",
|
|
42
18
|
"@tanstack/table-core": "^8.21.0",
|
|
43
19
|
"@tanstack/virtual-core": "^3.13.0",
|
|
44
20
|
"zod": "^4.0.0"
|
|
45
21
|
},
|
|
46
22
|
"devDependencies": {
|
|
47
|
-
"@pyreon/mcp": "
|
|
48
|
-
"@pyreon/vite-plugin": "
|
|
49
|
-
"@pyreon/zero-cli": "
|
|
50
|
-
"typescript": "^
|
|
51
|
-
"vite": "^
|
|
23
|
+
"@pyreon/mcp": "^0.7.5",
|
|
24
|
+
"@pyreon/vite-plugin": "^0.7.5",
|
|
25
|
+
"@pyreon/zero-cli": "^0.3.0",
|
|
26
|
+
"typescript": "^6.0.2",
|
|
27
|
+
"vite": "^8.0.0"
|
|
52
28
|
}
|
|
53
29
|
}
|
|
@@ -31,21 +31,21 @@ export default function Counter() {
|
|
|
31
31
|
<button
|
|
32
32
|
type="button"
|
|
33
33
|
class="btn btn-secondary"
|
|
34
|
-
onclick={() => count(
|
|
34
|
+
onclick={() => count.update((n) => n - 1)}
|
|
35
35
|
>
|
|
36
36
|
-
|
|
37
37
|
</button>
|
|
38
38
|
<button
|
|
39
39
|
type="button"
|
|
40
40
|
class="btn btn-primary"
|
|
41
|
-
onclick={() => count(0)}
|
|
41
|
+
onclick={() => count.set(0)}
|
|
42
42
|
>
|
|
43
43
|
Reset
|
|
44
44
|
</button>
|
|
45
45
|
<button
|
|
46
46
|
type="button"
|
|
47
47
|
class="btn btn-secondary"
|
|
48
|
-
onclick={() => count(
|
|
48
|
+
onclick={() => count.update((n) => n + 1)}
|
|
49
49
|
>
|
|
50
50
|
+
|
|
51
51
|
</button>
|
|
@@ -33,11 +33,11 @@ export default function NewPostPage() {
|
|
|
33
33
|
<form onSubmit={(e: Event) => form.handleSubmit(e)}>
|
|
34
34
|
<div class="form-field">
|
|
35
35
|
<label for="title">Title</label>
|
|
36
|
-
<input id="title" {...form.register('title')} />
|
|
36
|
+
<input id="title" {...form.register('title', {})} />
|
|
37
37
|
</div>
|
|
38
38
|
<div class="form-field">
|
|
39
39
|
<label for="body">Body</label>
|
|
40
|
-
<textarea id="body" rows={6} {...form.register('body')} />
|
|
40
|
+
<textarea id="body" rows={6} {...form.register('body', {})} />
|
|
41
41
|
</div>
|
|
42
42
|
<div class="form-field">
|
|
43
43
|
<label class="checkbox-label">
|