create-theokit 0.1.0-alpha.3 → 0.1.0-alpha.6

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.
Files changed (52) hide show
  1. package/dist/cli.js +314 -72
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +1 -1
  4. package/templates/api-only/.nvmrc +1 -0
  5. package/templates/api-only/index.html +1 -1
  6. package/templates/api-only/package.json.tmpl +5 -2
  7. package/templates/api-only/public/favicon.ico +0 -0
  8. package/templates/dashboard/.nvmrc +1 -0
  9. package/templates/dashboard/index.html +1 -1
  10. package/templates/dashboard/package.json.tmpl +5 -2
  11. package/templates/dashboard/public/favicon.ico +0 -0
  12. package/templates/default/.nvmrc +1 -0
  13. package/templates/default/README.md.tmpl +73 -0
  14. package/templates/default/app/layout.tsx +84 -2
  15. package/templates/default/app/page.tsx +266 -87
  16. package/templates/default/index.html +1 -1
  17. package/templates/default/package.json.tmpl +14 -5
  18. package/templates/default/public/favicon.ico +0 -0
  19. package/templates/default/server/routes/chat.ts +53 -47
  20. package/templates/default/types/jobs.d.ts +25 -0
  21. package/templates/postgres/.nvmrc +1 -0
  22. package/templates/postgres/index.html +1 -1
  23. package/templates/postgres/package.json.tmpl +2 -1
  24. package/templates/postgres/public/favicon.ico +0 -0
  25. package/templates/saas/.env.example +7 -0
  26. package/templates/saas/.nvmrc +1 -0
  27. package/templates/saas/_gitignore +5 -0
  28. package/templates/saas/app/layout.tsx +5 -0
  29. package/templates/saas/app/page.tsx +104 -0
  30. package/templates/saas/db/index.ts +6 -0
  31. package/templates/saas/db/schema.ts +20 -0
  32. package/templates/saas/drizzle.config.ts +10 -0
  33. package/templates/saas/index.html +12 -0
  34. package/templates/saas/package.json.tmpl +32 -0
  35. package/templates/saas/public/.gitkeep +0 -0
  36. package/templates/saas/public/favicon.ico +0 -0
  37. package/templates/saas/server/context.ts +37 -0
  38. package/templates/saas/server/routes/agent.ts +21 -0
  39. package/templates/saas/server/routes/login.ts +25 -0
  40. package/templates/saas/server/routes/logout.ts +10 -0
  41. package/templates/saas/server/routes/me.ts +10 -0
  42. package/templates/saas/theo.config.ts +5 -0
  43. package/templates/saas/tsconfig.json +15 -0
  44. package/templates/services/agent-node/Dockerfile.tmpl +20 -0
  45. package/templates/services/agent-node/README.md +38 -0
  46. package/templates/services/agent-node/package.json.tmpl +18 -0
  47. package/templates/services/agent-node/src/index.ts +58 -0
  48. package/templates/services/agent-node/tsconfig.json +13 -0
  49. package/templates/services/agent-python/Dockerfile.tmpl +20 -0
  50. package/templates/services/agent-python/README.md +37 -0
  51. package/templates/services/agent-python/main.py +77 -0
  52. package/templates/services/agent-python/pyproject.toml.tmpl +16 -0
package/dist/cli.js CHANGED
@@ -1,25 +1,227 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { resolve as resolve2 } from "path";
4
+ import { resolve as resolve3 } from "path";
5
5
 
6
- // src/index.ts
6
+ // src/install.ts
7
+ import spawn from "cross-spawn";
8
+ function runInstall(cwd, pkgManager) {
9
+ const result = spawn.sync(pkgManager, ["install"], {
10
+ cwd,
11
+ stdio: "inherit",
12
+ env: { ...process.env, NODE_ENV: "development" }
13
+ });
14
+ if (result.status !== 0) {
15
+ throw new Error(`Failed to install dependencies with ${pkgManager}`);
16
+ }
17
+ }
18
+
19
+ // src/pkg-manager.ts
20
+ function detectPkgManager() {
21
+ const ua = process.env.npm_config_user_agent ?? "";
22
+ if (ua.startsWith("yarn")) return "yarn";
23
+ if (ua.startsWith("pnpm")) return "pnpm";
24
+ if (ua.startsWith("bun")) return "bun";
25
+ return "npm";
26
+ }
27
+
28
+ // src/preflight-node.ts
29
+ var MIN_NODE_VERSION = "22.12.0";
30
+ function compareSemver(a, b) {
31
+ const parse = (raw) => {
32
+ const stripped = raw.replace(/^v/, "").split("-")[0] ?? "0.0.0";
33
+ const parts = stripped.split(".").map((s) => Number.parseInt(s, 10) || 0);
34
+ return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
35
+ };
36
+ const [aMaj, aMin, aPat] = parse(a);
37
+ const [bMaj, bMin, bPat] = parse(b);
38
+ if (aMaj !== bMaj) return aMaj - bMaj;
39
+ if (aMin !== bMin) return aMin - bMin;
40
+ return aPat - bPat;
41
+ }
42
+ function assertNodeVersion(currentRaw, minimum = MIN_NODE_VERSION) {
43
+ const current = currentRaw.replace(/^v/, "");
44
+ if (compareSemver(currentRaw, minimum) < 0) {
45
+ throw new Error(
46
+ `create-theokit requires Node ${minimum} or later (the @usetheo/sdk peer engines floor).
47
+ Detected: Node ${current}
48
+ Fix: nvm install 22 && nvm use 22
49
+ (or your version manager equivalent \u2014 fnm, volta, asdf, nvs)
50
+ `
51
+ );
52
+ }
53
+ }
54
+
55
+ // src/scaffold-services.ts
7
56
  import {
8
- existsSync as existsSync2,
9
57
  cpSync,
10
- readFileSync as readFileSync2,
11
- writeFileSync as writeFileSync2,
12
- renameSync,
13
- unlinkSync as unlinkSync2,
58
+ existsSync,
59
+ readFileSync,
14
60
  readdirSync,
15
- rmSync
61
+ statSync,
62
+ writeFileSync,
63
+ unlinkSync
16
64
  } from "fs";
17
- import { resolve, join as join2, dirname } from "path";
65
+ import { dirname, join, resolve } from "path";
18
66
  import { fileURLToPath } from "url";
67
+ var __dirname = dirname(fileURLToPath(import.meta.url));
68
+ var VALID_BACKENDS = ["python", "node"];
69
+ function parseBackendFlags(args) {
70
+ const out = [];
71
+ for (let i = 0; i < args.length; i++) {
72
+ const a = args[i] ?? "";
73
+ let value;
74
+ if (a === "--backend") {
75
+ value = args[i + 1];
76
+ i++;
77
+ } else if (a.startsWith("--backend=")) {
78
+ value = a.slice("--backend=".length);
79
+ }
80
+ if (value === void 0) continue;
81
+ if (!VALID_BACKENDS.includes(value)) {
82
+ throw new Error(
83
+ `unknown --backend value: '${value}'. Valid options: ${VALID_BACKENDS.join(", ")}.`
84
+ );
85
+ }
86
+ out.push(value);
87
+ }
88
+ return out;
89
+ }
90
+ var BACKEND_CONFIG = {
91
+ python: {
92
+ templateDir: "agent-python",
93
+ serviceName: "agent",
94
+ port: 8001,
95
+ proxy: "/api/agent",
96
+ dev: "uvicorn main:app --reload --port 8001",
97
+ start: "uvicorn main:app --port 8001 --workers 4"
98
+ },
99
+ node: {
100
+ templateDir: "agent-node",
101
+ serviceName: "worker",
102
+ port: 8002,
103
+ proxy: "/api/worker",
104
+ dev: "pnpm dev",
105
+ start: "pnpm start"
106
+ }
107
+ };
108
+ function getServiceTemplateDir(kind) {
109
+ return resolve(__dirname, "../templates/services", BACKEND_CONFIG[kind].templateDir);
110
+ }
111
+ function substituteTmpls(dir, projectName) {
112
+ for (const entry of readdirSync(dir)) {
113
+ const full = join(dir, entry);
114
+ const stat = statSync(full);
115
+ if (stat.isDirectory()) {
116
+ substituteTmpls(full, projectName);
117
+ continue;
118
+ }
119
+ if (entry.endsWith(".tmpl")) {
120
+ const content = readFileSync(full, "utf-8").replace(/\{\{name\}\}/g, projectName);
121
+ const dest = full.replace(/\.tmpl$/, "");
122
+ writeFileSync(dest, content);
123
+ unlinkSync(full);
124
+ }
125
+ }
126
+ }
127
+ function buildServicesSnippet(selections) {
128
+ if (selections.length === 0) return "";
129
+ const blocks = selections.map(({ name, entry }) => {
130
+ return ` ${name}: {
131
+ runtime: '${entry.runtime}',
132
+ port: ${String(entry.port)},
133
+ proxy: '${entry.proxy}',
134
+ dev: ${JSON.stringify(entry.dev)},
135
+ start: ${JSON.stringify(entry.start)},
136
+ },`;
137
+ });
138
+ return ` services: {
139
+ ${blocks.join("\n")}
140
+ },
141
+ `;
142
+ }
143
+ function injectServicesIntoConfig(configSource, snippet) {
144
+ if (snippet.length === 0) return configSource;
145
+ if (configSource.includes("services:")) return configSource;
146
+ const re = /defineConfig\(\{([\s\S]*?)\}\)/m;
147
+ const match = re.exec(configSource);
148
+ if (!match) return configSource;
149
+ const inner = match[1];
150
+ let trimEnd = inner.length;
151
+ while (trimEnd > 0 && /\s/.test(inner.charAt(trimEnd - 1))) {
152
+ trimEnd--;
153
+ }
154
+ const trimmed = inner.slice(0, trimEnd);
155
+ const sep = trimmed.length > 0 && !trimmed.endsWith(",") ? ",\n" : "\n";
156
+ const newInner = `${trimmed}${sep}${snippet}`;
157
+ return configSource.replace(re, `defineConfig({${newInner}})`);
158
+ }
159
+ function injectHeyApiDep(packageJsonSource) {
160
+ const pkg = JSON.parse(packageJsonSource);
161
+ pkg.dependencies = pkg.dependencies ?? {};
162
+ if (!("@hey-api/client-fetch" in pkg.dependencies)) {
163
+ pkg.dependencies["@hey-api/client-fetch"] = "^0.6.0";
164
+ }
165
+ return JSON.stringify(pkg, null, 2) + "\n";
166
+ }
167
+ function scaffoldServices(options) {
168
+ if (options.backends.length === 0) return;
169
+ const selections = [];
170
+ for (const kind of options.backends) {
171
+ const cfg = BACKEND_CONFIG[kind];
172
+ const src = getServiceTemplateDir(kind);
173
+ const dest = join(options.targetDir, "services", cfg.serviceName);
174
+ if (!existsSync(src)) {
175
+ throw new Error(`service template not found: ${src}`);
176
+ }
177
+ cpSync(src, dest, { recursive: true });
178
+ substituteTmpls(dest, options.projectName);
179
+ selections.push({
180
+ name: cfg.serviceName,
181
+ entry: {
182
+ runtime: kind,
183
+ port: cfg.port,
184
+ proxy: cfg.proxy,
185
+ dev: cfg.dev,
186
+ start: cfg.start
187
+ }
188
+ });
189
+ }
190
+ const configPath = join(options.targetDir, "theo.config.ts");
191
+ if (existsSync(configPath)) {
192
+ const cfgSrc = readFileSync(configPath, "utf-8");
193
+ const snippet = buildServicesSnippet(selections);
194
+ const updated = injectServicesIntoConfig(cfgSrc, snippet);
195
+ if (updated !== cfgSrc) {
196
+ writeFileSync(configPath, updated);
197
+ }
198
+ }
199
+ const pkgPath = join(options.targetDir, "package.json");
200
+ if (existsSync(pkgPath)) {
201
+ const pkgSrc = readFileSync(pkgPath, "utf-8");
202
+ const updated = injectHeyApiDep(pkgSrc);
203
+ writeFileSync(pkgPath, updated);
204
+ }
205
+ }
206
+
207
+ // src/index.ts
208
+ import {
209
+ existsSync as existsSync3,
210
+ cpSync as cpSync2,
211
+ readFileSync as readFileSync3,
212
+ writeFileSync as writeFileSync3,
213
+ renameSync,
214
+ unlinkSync as unlinkSync3,
215
+ readdirSync as readdirSync2,
216
+ rmSync,
217
+ statSync as statSync2
218
+ } from "fs";
219
+ import { resolve as resolve2, join as join3, dirname as dirname2 } from "path";
220
+ import { fileURLToPath as fileURLToPath2 } from "url";
19
221
 
20
222
  // src/bare-transform.ts
21
- import { existsSync, readFileSync, writeFileSync, unlinkSync } from "fs";
22
- import { join } from "path";
223
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
224
+ import { join as join2 } from "path";
23
225
  var HELLO_PAGE = `export default function Page() {
24
226
  return <h1>Hello Theo</h1>
25
227
  }
@@ -28,28 +230,45 @@ function applyBareTransform(targetDir, options = {}) {
28
230
  if (options._testForceError) {
29
231
  throw new Error(`Forced transform failure: ${options._testForceError}`);
30
232
  }
31
- const pkgPath = join(targetDir, "package.json");
32
- if (existsSync(pkgPath)) {
33
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
34
- if (pkg.dependencies && "@usetheo/ui" in pkg.dependencies) {
233
+ const pkgPath = join2(targetDir, "package.json");
234
+ if (existsSync2(pkgPath)) {
235
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
236
+ if (pkg.dependencies) {
35
237
  delete pkg.dependencies["@usetheo/ui"];
238
+ delete pkg.dependencies["@usetheo/sdk"];
239
+ delete pkg.dependencies["lucide-react"];
36
240
  }
37
- writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
241
+ if (pkg.devDependencies) {
242
+ delete pkg.devDependencies.tailwindcss;
243
+ delete pkg.devDependencies["tailwindcss-animate"];
244
+ delete pkg.devDependencies.postcss;
245
+ delete pkg.devDependencies.autoprefixer;
246
+ }
247
+ writeFileSync2(pkgPath, `${JSON.stringify(pkg, null, 2)}
248
+ `);
38
249
  }
39
- const pagePath = join(targetDir, "app/page.tsx");
40
- if (existsSync(pagePath)) {
41
- writeFileSync(pagePath, HELLO_PAGE);
250
+ const pagePath = join2(targetDir, "app/page.tsx");
251
+ if (existsSync2(pagePath)) {
252
+ writeFileSync2(pagePath, HELLO_PAGE);
42
253
  }
43
- const chatPath = join(targetDir, "server/routes/chat.ts");
44
- if (existsSync(chatPath)) {
45
- unlinkSync(chatPath);
254
+ const chatPath = join2(targetDir, "server/routes/chat.ts");
255
+ if (existsSync2(chatPath)) {
256
+ unlinkSync2(chatPath);
257
+ }
258
+ const tailwindCfg = join2(targetDir, "tailwind.config.ts");
259
+ if (existsSync2(tailwindCfg)) {
260
+ unlinkSync2(tailwindCfg);
261
+ }
262
+ const postcssCfg = join2(targetDir, "postcss.config.js");
263
+ if (existsSync2(postcssCfg)) {
264
+ unlinkSync2(postcssCfg);
46
265
  }
47
266
  }
48
267
 
49
268
  // src/index.ts
50
- var __dirname = dirname(fileURLToPath(import.meta.url));
269
+ var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
51
270
  function getTemplateDir(templateName = "default") {
52
- return resolve(__dirname, "../templates", templateName);
271
+ return resolve2(__dirname2, "../templates", templateName);
53
272
  }
54
273
  function isValidProjectName(name) {
55
274
  return /^[a-z0-9][a-z0-9._-]*$/.test(name);
@@ -61,9 +280,9 @@ function scaffold(targetDir, projectName, templateName = "default", options = {}
61
280
  );
62
281
  }
63
282
  const templateDir = getTemplateDir(templateName);
64
- if (!existsSync2(templateDir)) {
283
+ if (!existsSync3(templateDir)) {
65
284
  throw new Error(
66
- `Template "${templateName}" not found. Available templates: default, dashboard, api-only, postgres`
285
+ `Template "${templateName}" not found. Available templates: default, dashboard, api-only, postgres, saas`
67
286
  );
68
287
  }
69
288
  if (!isValidProjectName(projectName)) {
@@ -71,26 +290,28 @@ function scaffold(targetDir, projectName, templateName = "default", options = {}
71
290
  `Invalid project name "${projectName}". Use lowercase letters, numbers, hyphens, and dots. Must start with a letter or number.`
72
291
  );
73
292
  }
74
- if (existsSync2(targetDir)) {
75
- const contents = readdirSync(targetDir);
293
+ if (existsSync3(targetDir)) {
294
+ const contents = readdirSync2(targetDir);
76
295
  if (contents.length > 0) {
77
- throw new Error(
78
- `Directory "${targetDir}" is not empty. Please use an empty directory.`
79
- );
296
+ throw new Error(`Directory "${targetDir}" is not empty. Please use an empty directory.`);
80
297
  }
81
298
  }
82
- cpSync(templateDir, targetDir, { recursive: true });
83
- const gitignoreSrc = join2(targetDir, "_gitignore");
84
- const gitignoreDest = join2(targetDir, ".gitignore");
85
- if (existsSync2(gitignoreSrc)) {
299
+ cpSync2(templateDir, targetDir, { recursive: true });
300
+ const gitignoreSrc = join3(targetDir, "_gitignore");
301
+ const gitignoreDest = join3(targetDir, ".gitignore");
302
+ if (existsSync3(gitignoreSrc)) {
86
303
  renameSync(gitignoreSrc, gitignoreDest);
87
304
  }
88
- const tmplPath = join2(targetDir, "package.json.tmpl");
89
- if (existsSync2(tmplPath)) {
90
- const content = readFileSync2(tmplPath, "utf-8");
305
+ for (const entry of readdirSync2(targetDir)) {
306
+ if (!entry.endsWith(".tmpl")) continue;
307
+ const src = join3(targetDir, entry);
308
+ const stat = statSync2(src);
309
+ if (!stat.isFile()) continue;
310
+ const dst = join3(targetDir, entry.slice(0, -".tmpl".length));
311
+ const content = readFileSync3(src, "utf-8");
91
312
  const replaced = content.replace(/\{\{name\}\}/g, projectName);
92
- writeFileSync2(join2(targetDir, "package.json"), replaced);
93
- unlinkSync2(tmplPath);
313
+ writeFileSync3(dst, replaced);
314
+ unlinkSync3(src);
94
315
  }
95
316
  if (options.bare) {
96
317
  try {
@@ -108,62 +329,83 @@ Original error: ${original}`
108
329
  }
109
330
  }
110
331
 
111
- // src/pkg-manager.ts
112
- function detectPkgManager() {
113
- const ua = process.env.npm_config_user_agent ?? "";
114
- if (ua.startsWith("yarn")) return "yarn";
115
- if (ua.startsWith("pnpm")) return "pnpm";
116
- if (ua.startsWith("bun")) return "bun";
117
- return "npm";
118
- }
119
-
120
- // src/install.ts
121
- import spawn from "cross-spawn";
122
- function runInstall(cwd, pkgManager) {
123
- const result = spawn.sync(pkgManager, ["install"], {
124
- cwd,
125
- stdio: "inherit",
126
- env: { ...process.env, NODE_ENV: "development" }
127
- });
128
- if (result.status !== 0) {
129
- throw new Error(`Failed to install dependencies with ${pkgManager}`);
130
- }
131
- }
132
-
133
332
  // src/cli.ts
134
333
  function main() {
334
+ try {
335
+ assertNodeVersion(process.version);
336
+ } catch (err) {
337
+ console.error("");
338
+ console.error(err instanceof Error ? err.message : String(err));
339
+ process.exit(1);
340
+ }
135
341
  const args = process.argv.slice(2);
136
342
  const positionalArgs = args.filter((a) => !a.startsWith("--"));
137
343
  const projectName = positionalArgs[0];
138
344
  if (!projectName) {
139
- console.error("Usage: create-theokit <project-name> [--template=name] [--bare]");
345
+ console.error(
346
+ "Usage: create-theokit <project-name> [--template=name] [--bare] [--skip-install]"
347
+ );
140
348
  console.error("");
141
- console.error("Example:");
142
- console.error(" npx create-theokit my-app");
349
+ console.error("Templates: default, dashboard, api-only, postgres, saas");
350
+ console.error("");
351
+ console.error("Recipes:");
352
+ console.error(
353
+ " npx create-theokit my-app Full TheoUI + agent surface (requires @usetheo/sdk on npm)"
354
+ );
355
+ console.error(
356
+ " npx create-theokit my-app --bare Minimal Hello Theo (no @usetheo/* deps \u2014 always works)"
357
+ );
143
358
  console.error(" npx create-theokit my-app --template=dashboard");
144
- console.error(" npx create-theokit my-app --bare (skip @usetheo/ui defaults)");
359
+ console.error(
360
+ " npx create-theokit my-app --skip-install Scaffold files only, run install manually"
361
+ );
145
362
  process.exit(1);
146
363
  }
147
364
  const templateFlag = args.find((a) => a.startsWith("--template="));
148
365
  const templateName = templateFlag ? templateFlag.split("=")[1] : "default";
149
366
  const bare = args.includes("--bare");
150
- const targetDir = resolve2(process.cwd(), projectName);
367
+ const skipInstall = args.includes("--skip-install");
368
+ let backends = [];
369
+ try {
370
+ backends = parseBackendFlags(args);
371
+ } catch (err) {
372
+ console.error("");
373
+ console.error(err instanceof Error ? err.message : String(err));
374
+ process.exit(1);
375
+ }
376
+ const targetDir = resolve3(process.cwd(), projectName);
151
377
  try {
152
378
  const suffix = bare ? " [--bare: skipping TheoUI defaults]" : "";
153
- console.log(`
154
- Creating TheoKit project "${projectName}" (template: ${templateName})${suffix}...
155
- `);
379
+ const backendsSuffix = backends.length > 0 ? ` [+services: ${backends.join(", ")}]` : "";
380
+ console.log(
381
+ `
382
+ Creating TheoKit project "${projectName}" (template: ${templateName})${suffix}${backendsSuffix}...
383
+ `
384
+ );
156
385
  scaffold(targetDir, projectName, templateName, { bare });
386
+ if (backends.length > 0) {
387
+ scaffoldServices({ targetDir, projectName, backends });
388
+ console.log(` \u2713 Scaffolded ${String(backends.length)} service(s): ${backends.join(", ")}
389
+ `);
390
+ }
157
391
  const pkgManager = detectPkgManager();
158
- console.log(`Installing dependencies with ${pkgManager}...
392
+ if (skipInstall) {
393
+ console.log(`Skipping install (--skip-install). Run \`${pkgManager} install\` manually.
159
394
  `);
160
- runInstall(targetDir, pkgManager);
395
+ } else {
396
+ console.log(`Installing dependencies with ${pkgManager}...
397
+ `);
398
+ runInstall(targetDir, pkgManager);
399
+ }
161
400
  console.log(`
162
401
  \u2713 Project created at ${targetDir}
163
402
  `);
164
403
  console.log(` Next steps:
165
404
  `);
166
405
  console.log(` cd ${projectName}`);
406
+ if (skipInstall) {
407
+ console.log(` ${pkgManager} install`);
408
+ }
167
409
  console.log(` ${pkgManager === "npm" ? "npx" : pkgManager} theokit dev
168
410
  `);
169
411
  } catch (err) {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/index.ts","../src/bare-transform.ts","../src/pkg-manager.ts","../src/install.ts"],"sourcesContent":["import { resolve } from 'node:path'\nimport { scaffold } from './index.js'\nimport { detectPkgManager } from './pkg-manager.js'\nimport { runInstall } from './install.js'\n\nexport function main(): void {\n const args = process.argv.slice(2)\n const positionalArgs = args.filter((a) => !a.startsWith('--'))\n const projectName = positionalArgs[0]\n\n if (!projectName) {\n console.error('Usage: create-theokit <project-name> [--template=name] [--bare]')\n console.error('')\n console.error('Example:')\n console.error(' npx create-theokit my-app')\n console.error(' npx create-theokit my-app --template=dashboard')\n console.error(' npx create-theokit my-app --bare (skip @usetheo/ui defaults)')\n process.exit(1)\n }\n\n // Parse --template flag\n const templateFlag = args.find((a) => a.startsWith('--template='))\n const templateName = templateFlag ? templateFlag.split('=')[1] : 'default'\n\n // Parse --bare flag (only applies to default template)\n const bare = args.includes('--bare')\n\n const targetDir = resolve(process.cwd(), projectName)\n\n try {\n const suffix = bare ? ' [--bare: skipping TheoUI defaults]' : ''\n console.log(`\\nCreating TheoKit project \"${projectName}\" (template: ${templateName})${suffix}...\\n`)\n\n scaffold(targetDir, projectName, templateName, { bare })\n\n const pkgManager = detectPkgManager()\n console.log(`Installing dependencies with ${pkgManager}...\\n`)\n runInstall(targetDir, pkgManager)\n\n console.log(`\\n ✓ Project created at ${targetDir}\\n`)\n console.log(` Next steps:\\n`)\n console.log(` cd ${projectName}`)\n console.log(` ${pkgManager === 'npm' ? 'npx' : pkgManager} theokit dev\\n`)\n } catch (err) {\n console.error(`\\n ✗ ${(err as Error).message}\\n`)\n process.exit(1)\n }\n}\n\n// Auto-execute when run as script\nmain()\n","import {\n existsSync,\n cpSync,\n readFileSync,\n writeFileSync,\n renameSync,\n unlinkSync,\n readdirSync,\n rmSync,\n} from 'node:fs'\nimport { resolve, join, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { applyBareTransform } from './bare-transform.js'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nfunction getTemplateDir(templateName = 'default'): string {\n return resolve(__dirname, '../templates', templateName)\n}\n\nfunction isValidProjectName(name: string): boolean {\n return /^[a-z0-9][a-z0-9._-]*$/.test(name)\n}\n\nexport interface ScaffoldOptions {\n bare?: boolean\n /** Test-only — force the bare transform to throw to validate EC-4 rollback. */\n _testForceTransformError?: string\n}\n\nexport function scaffold(\n targetDir: string,\n projectName: string,\n templateName = 'default',\n options: ScaffoldOptions = {},\n): void {\n // EC-4 + ADR D5: --bare only applies to default template\n if (options.bare && templateName !== 'default') {\n throw new Error(\n `--bare flag only applies to the default template; got \"${templateName}\". ` +\n `Use \\`npx create-theokit <name> --template=default --bare\\` or pick a different template.`,\n )\n }\n\n const templateDir = getTemplateDir(templateName)\n\n if (!existsSync(templateDir)) {\n throw new Error(\n `Template \"${templateName}\" not found. Available templates: default, dashboard, api-only, postgres`,\n )\n }\n\n if (!isValidProjectName(projectName)) {\n throw new Error(\n `Invalid project name \"${projectName}\". ` +\n `Use lowercase letters, numbers, hyphens, and dots. Must start with a letter or number.`,\n )\n }\n\n if (existsSync(targetDir)) {\n const contents = readdirSync(targetDir)\n if (contents.length > 0) {\n throw new Error(\n `Directory \"${targetDir}\" is not empty. Please use an empty directory.`,\n )\n }\n }\n\n cpSync(templateDir, targetDir, { recursive: true })\n\n const gitignoreSrc = join(targetDir, '_gitignore')\n const gitignoreDest = join(targetDir, '.gitignore')\n if (existsSync(gitignoreSrc)) {\n renameSync(gitignoreSrc, gitignoreDest)\n }\n\n const tmplPath = join(targetDir, 'package.json.tmpl')\n if (existsSync(tmplPath)) {\n const content = readFileSync(tmplPath, 'utf-8')\n const replaced = content.replace(/\\{\\{name\\}\\}/g, projectName)\n writeFileSync(join(targetDir, 'package.json'), replaced)\n unlinkSync(tmplPath)\n }\n\n // T4.1 — Apply --bare transform with EC-4 atomic rollback\n if (options.bare) {\n try {\n applyBareTransform(targetDir, {\n _testForceError: options._testForceTransformError,\n })\n } catch (err) {\n // EC-4: roll back partial state\n rmSync(targetDir, { recursive: true, force: true })\n const original = err instanceof Error ? err.message : String(err)\n throw new Error(\n `Scaffold rolled back: bare transform failed. Check filesystem perms.\\nOriginal error: ${original}`,\n )\n }\n }\n}\n","/**\n * T4.1 — `--bare` transformation.\n *\n * Applied AFTER the default template is copied. Removes:\n * - `@usetheo/ui` from `package.json` dependencies\n * - `app/page.tsx` agent-surface content (replaces with Hello Theo)\n * - `server/routes/chat.ts` (mock chat — depends on TheoUI events)\n *\n * EC-4: callers MUST wrap this in try/catch + `rmSync` rollback so a partial\n * transform never leaves the target dir in a broken state.\n */\n\nimport { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\n\nconst HELLO_PAGE = `export default function Page() {\n return <h1>Hello Theo</h1>\n}\n`\n\nexport interface BareTransformOptions {\n /** Test-only — force a synthetic write failure to validate rollback path. */\n _testForceError?: string\n}\n\nexport function applyBareTransform(\n targetDir: string,\n options: BareTransformOptions = {},\n): void {\n if (options._testForceError) {\n throw new Error(`Forced transform failure: ${options._testForceError}`)\n }\n\n // 1. Remove @usetheo/ui from package.json deps\n const pkgPath = join(targetDir, 'package.json')\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))\n if (pkg.dependencies && '@usetheo/ui' in pkg.dependencies) {\n delete pkg.dependencies['@usetheo/ui']\n }\n writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\\n')\n }\n\n // 2. Replace app/page.tsx with Hello Theo\n const pagePath = join(targetDir, 'app/page.tsx')\n if (existsSync(pagePath)) {\n writeFileSync(pagePath, HELLO_PAGE)\n }\n\n // 3. Remove mock chat route (depends on AgentEvent type and TheoUI deps)\n const chatPath = join(targetDir, 'server/routes/chat.ts')\n if (existsSync(chatPath)) {\n unlinkSync(chatPath)\n }\n}\n","export type PkgManager = 'npm' | 'pnpm' | 'yarn' | 'bun'\n\nexport function detectPkgManager(): PkgManager {\n const ua = process.env.npm_config_user_agent ?? ''\n if (ua.startsWith('yarn')) return 'yarn'\n if (ua.startsWith('pnpm')) return 'pnpm'\n if (ua.startsWith('bun')) return 'bun'\n return 'npm'\n}\n","import spawn from 'cross-spawn'\nimport type { PkgManager } from './pkg-manager.js'\n\nexport function runInstall(cwd: string, pkgManager: PkgManager): void {\n const result = spawn.sync(pkgManager, ['install'], {\n cwd,\n stdio: 'inherit',\n env: { ...process.env, NODE_ENV: 'development' },\n })\n\n if (result.status !== 0) {\n throw new Error(`Failed to install dependencies with ${pkgManager}`)\n }\n}\n"],"mappings":";;;AAAA,SAAS,WAAAA,gBAAe;;;ACAxB;AAAA,EACE,cAAAC;AAAA,EACA;AAAA,EACA,gBAAAC;AAAA,EACA,iBAAAC;AAAA,EACA;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,SAAS,QAAAC,OAAM,eAAe;AACvC,SAAS,qBAAqB;;;ACC9B,SAAS,YAAY,cAAc,eAAe,kBAAkB;AACpE,SAAS,YAAY;AAErB,IAAM,aAAa;AAAA;AAAA;AAAA;AAUZ,SAAS,mBACd,WACA,UAAgC,CAAC,GAC3B;AACN,MAAI,QAAQ,iBAAiB;AAC3B,UAAM,IAAI,MAAM,6BAA6B,QAAQ,eAAe,EAAE;AAAA,EACxE;AAGA,QAAM,UAAU,KAAK,WAAW,cAAc;AAC9C,MAAI,WAAW,OAAO,GAAG;AACvB,UAAM,MAAM,KAAK,MAAM,aAAa,SAAS,OAAO,CAAC;AACrD,QAAI,IAAI,gBAAgB,iBAAiB,IAAI,cAAc;AACzD,aAAO,IAAI,aAAa,aAAa;AAAA,IACvC;AACA,kBAAc,SAAS,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,IAAI;AAAA,EAC5D;AAGA,QAAM,WAAW,KAAK,WAAW,cAAc;AAC/C,MAAI,WAAW,QAAQ,GAAG;AACxB,kBAAc,UAAU,UAAU;AAAA,EACpC;AAGA,QAAM,WAAW,KAAK,WAAW,uBAAuB;AACxD,MAAI,WAAW,QAAQ,GAAG;AACxB,eAAW,QAAQ;AAAA,EACrB;AACF;;;ADxCA,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAExD,SAAS,eAAe,eAAe,WAAmB;AACxD,SAAO,QAAQ,WAAW,gBAAgB,YAAY;AACxD;AAEA,SAAS,mBAAmB,MAAuB;AACjD,SAAO,yBAAyB,KAAK,IAAI;AAC3C;AAQO,SAAS,SACd,WACA,aACA,eAAe,WACf,UAA2B,CAAC,GACtB;AAEN,MAAI,QAAQ,QAAQ,iBAAiB,WAAW;AAC9C,UAAM,IAAI;AAAA,MACR,0DAA0D,YAAY;AAAA,IAExE;AAAA,EACF;AAEA,QAAM,cAAc,eAAe,YAAY;AAE/C,MAAI,CAACC,YAAW,WAAW,GAAG;AAC5B,UAAM,IAAI;AAAA,MACR,aAAa,YAAY;AAAA,IAC3B;AAAA,EACF;AAEA,MAAI,CAAC,mBAAmB,WAAW,GAAG;AACpC,UAAM,IAAI;AAAA,MACR,yBAAyB,WAAW;AAAA,IAEtC;AAAA,EACF;AAEA,MAAIA,YAAW,SAAS,GAAG;AACzB,UAAM,WAAW,YAAY,SAAS;AACtC,QAAI,SAAS,SAAS,GAAG;AACvB,YAAM,IAAI;AAAA,QACR,cAAc,SAAS;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,aAAa,WAAW,EAAE,WAAW,KAAK,CAAC;AAElD,QAAM,eAAeC,MAAK,WAAW,YAAY;AACjD,QAAM,gBAAgBA,MAAK,WAAW,YAAY;AAClD,MAAID,YAAW,YAAY,GAAG;AAC5B,eAAW,cAAc,aAAa;AAAA,EACxC;AAEA,QAAM,WAAWC,MAAK,WAAW,mBAAmB;AACpD,MAAID,YAAW,QAAQ,GAAG;AACxB,UAAM,UAAUE,cAAa,UAAU,OAAO;AAC9C,UAAM,WAAW,QAAQ,QAAQ,iBAAiB,WAAW;AAC7D,IAAAC,eAAcF,MAAK,WAAW,cAAc,GAAG,QAAQ;AACvD,IAAAG,YAAW,QAAQ;AAAA,EACrB;AAGA,MAAI,QAAQ,MAAM;AAChB,QAAI;AACF,yBAAmB,WAAW;AAAA,QAC5B,iBAAiB,QAAQ;AAAA,MAC3B,CAAC;AAAA,IACH,SAAS,KAAK;AAEZ,aAAO,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAClD,YAAM,WAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAChE,YAAM,IAAI;AAAA,QACR;AAAA,kBAAyF,QAAQ;AAAA,MACnG;AAAA,IACF;AAAA,EACF;AACF;;;AEjGO,SAAS,mBAA+B;AAC7C,QAAM,KAAK,QAAQ,IAAI,yBAAyB;AAChD,MAAI,GAAG,WAAW,MAAM,EAAG,QAAO;AAClC,MAAI,GAAG,WAAW,MAAM,EAAG,QAAO;AAClC,MAAI,GAAG,WAAW,KAAK,EAAG,QAAO;AACjC,SAAO;AACT;;;ACRA,OAAO,WAAW;AAGX,SAAS,WAAW,KAAa,YAA8B;AACpE,QAAM,SAAS,MAAM,KAAK,YAAY,CAAC,SAAS,GAAG;AAAA,IACjD;AAAA,IACA,OAAO;AAAA,IACP,KAAK,EAAE,GAAG,QAAQ,KAAK,UAAU,cAAc;AAAA,EACjD,CAAC;AAED,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,uCAAuC,UAAU,EAAE;AAAA,EACrE;AACF;;;AJRO,SAAS,OAAa;AAC3B,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,QAAM,iBAAiB,KAAK,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,IAAI,CAAC;AAC7D,QAAM,cAAc,eAAe,CAAC;AAEpC,MAAI,CAAC,aAAa;AAChB,YAAQ,MAAM,iEAAiE;AAC/E,YAAQ,MAAM,EAAE;AAChB,YAAQ,MAAM,UAAU;AACxB,YAAQ,MAAM,6BAA6B;AAC3C,YAAQ,MAAM,kDAAkD;AAChE,YAAQ,MAAM,mEAAmE;AACjF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,eAAe,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,aAAa,CAAC;AACjE,QAAM,eAAe,eAAe,aAAa,MAAM,GAAG,EAAE,CAAC,IAAI;AAGjE,QAAM,OAAO,KAAK,SAAS,QAAQ;AAEnC,QAAM,YAAYC,SAAQ,QAAQ,IAAI,GAAG,WAAW;AAEpD,MAAI;AACF,UAAM,SAAS,OAAO,wCAAwC;AAC9D,YAAQ,IAAI;AAAA,4BAA+B,WAAW,gBAAgB,YAAY,IAAI,MAAM;AAAA,CAAO;AAEnG,aAAS,WAAW,aAAa,cAAc,EAAE,KAAK,CAAC;AAEvD,UAAM,aAAa,iBAAiB;AACpC,YAAQ,IAAI,gCAAgC,UAAU;AAAA,CAAO;AAC7D,eAAW,WAAW,UAAU;AAEhC,YAAQ,IAAI;AAAA,8BAA4B,SAAS;AAAA,CAAI;AACrD,YAAQ,IAAI;AAAA,CAAiB;AAC7B,YAAQ,IAAI,UAAU,WAAW,EAAE;AACnC,YAAQ,IAAI,OAAO,eAAe,QAAQ,QAAQ,UAAU;AAAA,CAAgB;AAAA,EAC9E,SAAS,KAAK;AACZ,YAAQ,MAAM;AAAA,WAAU,IAAc,OAAO;AAAA,CAAI;AACjD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAGA,KAAK;","names":["resolve","existsSync","readFileSync","writeFileSync","unlinkSync","join","existsSync","join","readFileSync","writeFileSync","unlinkSync","resolve"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/install.ts","../src/pkg-manager.ts","../src/preflight-node.ts","../src/scaffold-services.ts","../src/index.ts","../src/bare-transform.ts"],"sourcesContent":["import { resolve } from 'node:path'\n\nimport { runInstall } from './install.js'\nimport { detectPkgManager } from './pkg-manager.js'\nimport { assertNodeVersion } from './preflight-node.js'\nimport { parseBackendFlags, scaffoldServices, type BackendKind } from './scaffold-services.js'\n\nimport { scaffold } from './index.js'\n\nexport function main(): void {\n // Preflight FIRST — refuses to write any files if Node is below the SDK floor.\n // SDK requires Node ≥ 22.12; cryptic node:sqlite ABI errors otherwise.\n try {\n assertNodeVersion(process.version)\n } catch (err) {\n console.error('')\n console.error(err instanceof Error ? err.message : String(err))\n process.exit(1)\n }\n\n const args = process.argv.slice(2)\n const positionalArgs = args.filter((a) => !a.startsWith('--'))\n const projectName = positionalArgs[0]\n\n if (!projectName) {\n console.error(\n 'Usage: create-theokit <project-name> [--template=name] [--bare] [--skip-install]',\n )\n console.error('')\n console.error('Templates: default, dashboard, api-only, postgres, saas')\n console.error('')\n console.error('Recipes:')\n console.error(\n ' npx create-theokit my-app Full TheoUI + agent surface (requires @usetheo/sdk on npm)',\n )\n console.error(\n ' npx create-theokit my-app --bare Minimal Hello Theo (no @usetheo/* deps — always works)',\n )\n console.error(' npx create-theokit my-app --template=dashboard')\n console.error(\n ' npx create-theokit my-app --skip-install Scaffold files only, run install manually',\n )\n process.exit(1)\n }\n\n // Parse --template flag\n const templateFlag = args.find((a) => a.startsWith('--template='))\n const templateName = templateFlag ? templateFlag.split('=')[1] : 'default'\n\n // Parse --bare flag (only applies to default template)\n const bare = args.includes('--bare')\n\n // Parse --skip-install — useful for smoke testing, monorepo dogfood, air-gapped envs.\n const skipInstall = args.includes('--skip-install')\n\n // Parse --backend python | --backend node (Wave 2; multi-value supported)\n let backends: BackendKind[] = []\n try {\n backends = parseBackendFlags(args)\n } catch (err) {\n console.error('')\n console.error(err instanceof Error ? err.message : String(err))\n process.exit(1)\n }\n\n const targetDir = resolve(process.cwd(), projectName)\n\n try {\n const suffix = bare ? ' [--bare: skipping TheoUI defaults]' : ''\n const backendsSuffix = backends.length > 0 ? ` [+services: ${backends.join(', ')}]` : ''\n console.log(\n `\\nCreating TheoKit project \"${projectName}\" (template: ${templateName})${suffix}${backendsSuffix}...\\n`,\n )\n\n scaffold(targetDir, projectName, templateName, { bare })\n\n // Wave 2 — scaffold polyglot services AFTER main scaffold\n if (backends.length > 0) {\n scaffoldServices({ targetDir, projectName, backends })\n console.log(` ✓ Scaffolded ${String(backends.length)} service(s): ${backends.join(', ')}\\n`)\n }\n\n const pkgManager = detectPkgManager()\n if (skipInstall) {\n console.log(`Skipping install (--skip-install). Run \\`${pkgManager} install\\` manually.\\n`)\n } else {\n console.log(`Installing dependencies with ${pkgManager}...\\n`)\n runInstall(targetDir, pkgManager)\n }\n\n console.log(`\\n ✓ Project created at ${targetDir}\\n`)\n console.log(` Next steps:\\n`)\n console.log(` cd ${projectName}`)\n if (skipInstall) {\n console.log(` ${pkgManager} install`)\n }\n console.log(` ${pkgManager === 'npm' ? 'npx' : pkgManager} theokit dev\\n`)\n } catch (err) {\n console.error(`\\n ✗ ${(err as Error).message}\\n`)\n process.exit(1)\n }\n}\n\n// Auto-execute when run as script\nmain()\n","import spawn from 'cross-spawn'\n\nimport type { PkgManager } from './pkg-manager.js'\n\nexport function runInstall(cwd: string, pkgManager: PkgManager): void {\n const result = spawn.sync(pkgManager, ['install'], {\n cwd,\n stdio: 'inherit',\n env: { ...process.env, NODE_ENV: 'development' },\n })\n\n if (result.status !== 0) {\n throw new Error(`Failed to install dependencies with ${pkgManager}`)\n }\n}\n","export type PkgManager = 'npm' | 'pnpm' | 'yarn' | 'bun'\n\nexport function detectPkgManager(): PkgManager {\n const ua = process.env.npm_config_user_agent ?? ''\n if (ua.startsWith('yarn')) return 'yarn'\n if (ua.startsWith('pnpm')) return 'pnpm'\n if (ua.startsWith('bun')) return 'bun'\n return 'npm'\n}\n","/**\n * Node version preflight for `create-theokit`.\n *\n * `@usetheo/sdk` declares `engines.node: \">=22.12.0\"`. Users on older Node\n * hit cryptic `node:sqlite` / `better-sqlite3` ABI errors mid-chat without\n * any actionable diagnostic. This preflight runs at scaffold start, prints\n * a clear error, and exits before any FS write (ADR D4 of the plan).\n *\n * Zero-dep semver comparator — no `semver` package needed.\n */\n\n/** Minimum Node version required by `@usetheo/sdk`. */\nexport const MIN_NODE_VERSION = '22.12.0'\n\n/**\n * Compare two semver strings (major.minor.patch). Strips leading `v` from\n * either side. Pre-release suffixes (e.g., `-rc.1`, `-nightly...`) are\n * parsed as the base patch — acceptable for a preflight (we're not gating\n * on exact pre-release ordering).\n *\n * Returns:\n * <0 when a < b\n * 0 when a == b\n * >0 when a > b\n */\nexport function compareSemver(a: string, b: string): number {\n const parse = (raw: string): [number, number, number] => {\n const stripped = raw.replace(/^v/, '').split('-')[0] ?? '0.0.0'\n const parts = stripped.split('.').map((s) => Number.parseInt(s, 10) || 0)\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0]\n }\n const [aMaj, aMin, aPat] = parse(a)\n const [bMaj, bMin, bPat] = parse(b)\n if (aMaj !== bMaj) return aMaj - bMaj\n if (aMin !== bMin) return aMin - bMin\n return aPat - bPat\n}\n\n/**\n * Throw with an actionable message if `currentRaw` is below `minimum`.\n * Default minimum is `MIN_NODE_VERSION` (22.12.0).\n *\n * Called as the first line of `create-theokit`'s `main` so the preflight\n * fires before any directory is written.\n */\nexport function assertNodeVersion(currentRaw: string, minimum: string = MIN_NODE_VERSION): void {\n const current = currentRaw.replace(/^v/, '')\n if (compareSemver(currentRaw, minimum) < 0) {\n throw new Error(\n `create-theokit requires Node ${minimum} or later (the @usetheo/sdk peer engines floor).\\n` +\n ` Detected: Node ${current}\\n` +\n ` Fix: nvm install 22 && nvm use 22\\n` +\n ` (or your version manager equivalent — fnm, volta, asdf, nvs)\\n`,\n )\n }\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Build-time scaffold helper. All write paths derived from the trusted\n * targetDir (CLI argument, resolved absolute). Read paths are the\n * bundled service templates shipped with this package.\n */\n/**\n * Phase 4 — `--backend python|node` scaffolding (T4.1, T4.2).\n *\n * After the main TheoKit scaffold runs, this helper:\n * - Copies the requested service template(s) under `<target>/services/<name>/`\n * - Substitutes `{{name}}` in `.tmpl` files\n * - Renames `.tmpl` files to drop the suffix\n * - Injects services config into the user's `theo.config.ts`\n * - Injects `@hey-api/client-fetch` into the user's package.json (EC-10)\n */\nimport {\n cpSync,\n existsSync,\n readFileSync,\n readdirSync,\n statSync,\n writeFileSync,\n unlinkSync,\n} from 'node:fs'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nexport type BackendKind = 'python' | 'node'\n\nconst VALID_BACKENDS = ['python', 'node'] as const\n\n/**\n * Parse `--backend python` / `--backend node` (multi-value) from argv.\n *\n * Accepts:\n * --backend python\n * --backend=python\n * --backend python --backend node\n *\n * Throws on unknown backend name.\n */\nexport function parseBackendFlags(args: string[]): BackendKind[] {\n const out: BackendKind[] = []\n for (let i = 0; i < args.length; i++) {\n const a = args[i] ?? ''\n let value: string | undefined\n if (a === '--backend') {\n value = args[i + 1]\n i++\n } else if (a.startsWith('--backend=')) {\n value = a.slice('--backend='.length)\n }\n if (value === undefined) continue\n if (!(VALID_BACKENDS as readonly string[]).includes(value)) {\n throw new Error(\n `unknown --backend value: '${value}'. Valid options: ${VALID_BACKENDS.join(', ')}.`,\n )\n }\n out.push(value as BackendKind)\n }\n return out\n}\n\nconst BACKEND_CONFIG: Record<\n BackendKind,\n {\n templateDir: string\n serviceName: string\n port: number\n proxy: string\n dev: string\n start: string\n }\n> = {\n python: {\n templateDir: 'agent-python',\n serviceName: 'agent',\n port: 8001,\n proxy: '/api/agent',\n dev: 'uvicorn main:app --reload --port 8001',\n start: 'uvicorn main:app --port 8001 --workers 4',\n },\n node: {\n templateDir: 'agent-node',\n serviceName: 'worker',\n port: 8002,\n proxy: '/api/worker',\n dev: 'pnpm dev',\n start: 'pnpm start',\n },\n}\n\nfunction getServiceTemplateDir(kind: BackendKind): string {\n return resolve(__dirname, '../templates/services', BACKEND_CONFIG[kind].templateDir)\n}\n\nfunction substituteTmpls(dir: string, projectName: string): void {\n for (const entry of readdirSync(dir)) {\n const full = join(dir, entry)\n const stat = statSync(full)\n if (stat.isDirectory()) {\n substituteTmpls(full, projectName)\n continue\n }\n if (entry.endsWith('.tmpl')) {\n const content = readFileSync(full, 'utf-8').replace(/\\{\\{name\\}\\}/g, projectName)\n const dest = full.replace(/\\.tmpl$/, '')\n writeFileSync(dest, content)\n unlinkSync(full)\n }\n }\n}\n\ninterface ServiceEntry {\n runtime: BackendKind\n port: number\n proxy: string\n dev: string\n start: string\n}\n\n/**\n * Build the `services: {}` snippet to inject into `theo.config.ts`.\n * Returns the inner record literal — caller wraps in `services: { ... }`.\n */\nexport function buildServicesSnippet(selections: { name: string; entry: ServiceEntry }[]): string {\n if (selections.length === 0) return ''\n const blocks = selections.map(({ name, entry }) => {\n return ` ${name}: {\n runtime: '${entry.runtime}',\n port: ${String(entry.port)},\n proxy: '${entry.proxy}',\n dev: ${JSON.stringify(entry.dev)},\n start: ${JSON.stringify(entry.start)},\n },`\n })\n return ` services: {\\n${blocks.join('\\n')}\\n },\\n`\n}\n\n/**\n * Insert the services block into an existing `theo.config.ts`.\n * Strategy: find `defineConfig({` and append the services block before the closing brace.\n */\nexport function injectServicesIntoConfig(configSource: string, snippet: string): string {\n if (snippet.length === 0) return configSource\n if (configSource.includes('services:')) return configSource // already present\n\n // Match the LAST `}` before the closing of defineConfig({...})\n const re = /defineConfig\\(\\{([\\s\\S]*?)\\}\\)/m\n const match = re.exec(configSource)\n if (!match) return configSource\n\n const inner = match[1]\n // Strip trailing whitespace without backtracking-prone \\s+$ regex.\n let trimEnd = inner.length\n while (trimEnd > 0 && /\\s/.test(inner.charAt(trimEnd - 1))) {\n trimEnd--\n }\n const trimmed = inner.slice(0, trimEnd)\n const sep = trimmed.length > 0 && !trimmed.endsWith(',') ? ',\\n' : '\\n'\n const newInner = `${trimmed}${sep}${snippet}`\n return configSource.replace(re, `defineConfig({${newInner}})`)\n}\n\nexport function injectHeyApiDep(packageJsonSource: string): string {\n const pkg = JSON.parse(packageJsonSource) as {\n dependencies?: Record<string, string>\n }\n pkg.dependencies = pkg.dependencies ?? {}\n if (!('@hey-api/client-fetch' in pkg.dependencies)) {\n pkg.dependencies['@hey-api/client-fetch'] = '^0.6.0'\n }\n return JSON.stringify(pkg, null, 2) + '\\n'\n}\n\nexport interface ScaffoldServicesOptions {\n /** Target project directory (already scaffolded with the TS template). */\n targetDir: string\n /** Project name (substituted into .tmpl files). */\n projectName: string\n /** Which backends to scaffold. */\n backends: BackendKind[]\n}\n\nexport function scaffoldServices(options: ScaffoldServicesOptions): void {\n if (options.backends.length === 0) return\n\n const selections: { name: string; entry: ServiceEntry }[] = []\n\n for (const kind of options.backends) {\n const cfg = BACKEND_CONFIG[kind]\n const src = getServiceTemplateDir(kind)\n // Schema contract: dev/start commands run from `services/<serviceName>/` cwd\n // (services/schema/schema.ts line 35). The destination MUST equal serviceName\n // so the orchestrator's cwd resolution matches the on-disk directory.\n const dest = join(options.targetDir, 'services', cfg.serviceName)\n if (!existsSync(src)) {\n throw new Error(`service template not found: ${src}`)\n }\n cpSync(src, dest, { recursive: true })\n substituteTmpls(dest, options.projectName)\n\n selections.push({\n name: cfg.serviceName,\n entry: {\n runtime: kind,\n port: cfg.port,\n proxy: cfg.proxy,\n dev: cfg.dev,\n start: cfg.start,\n },\n })\n }\n\n // Inject services into theo.config.ts\n const configPath = join(options.targetDir, 'theo.config.ts')\n if (existsSync(configPath)) {\n const cfgSrc = readFileSync(configPath, 'utf-8')\n const snippet = buildServicesSnippet(selections)\n const updated = injectServicesIntoConfig(cfgSrc, snippet)\n if (updated !== cfgSrc) {\n writeFileSync(configPath, updated)\n }\n }\n\n // EC-10: inject @hey-api/client-fetch into user's package.json\n const pkgPath = join(options.targetDir, 'package.json')\n if (existsSync(pkgPath)) {\n const pkgSrc = readFileSync(pkgPath, 'utf-8')\n const updated = injectHeyApiDep(pkgSrc)\n writeFileSync(pkgPath, updated)\n }\n\n // Rename .gitignore for services if needed (none currently shipped, but reserved hook)\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * `create-theokit` scaffold tool. All write paths are derived from the\n * user-supplied target directory (CLI argument, resolved to absolute).\n * Read paths are the bundled `templates/` shipped with this package.\n * Build-time tool — no HTTP input.\n */\nimport {\n existsSync,\n cpSync,\n readFileSync,\n writeFileSync,\n renameSync,\n unlinkSync,\n readdirSync,\n rmSync,\n statSync,\n} from 'node:fs'\nimport { resolve, join, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport { applyBareTransform } from './bare-transform.js'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nfunction getTemplateDir(templateName = 'default'): string {\n return resolve(__dirname, '../templates', templateName)\n}\n\nfunction isValidProjectName(name: string): boolean {\n return /^[a-z0-9][a-z0-9._-]*$/.test(name)\n}\n\nexport interface ScaffoldOptions {\n bare?: boolean\n /** Test-only — force the bare transform to throw to validate EC-4 rollback. */\n _testForceTransformError?: string\n}\n\n// eslint-disable-next-line complexity -- scaffold orchestrator: validate → copy → rename _gitignore → template-substitute all *.tmpl → optional --bare transform with rollback. Branches are linear, not nested.\nexport function scaffold(\n targetDir: string,\n projectName: string,\n templateName = 'default',\n options: ScaffoldOptions = {},\n): void {\n // EC-4 + ADR D5: --bare only applies to default template\n if (options.bare && templateName !== 'default') {\n throw new Error(\n `--bare flag only applies to the default template; got \"${templateName}\". ` +\n `Use \\`npx create-theokit <name> --template=default --bare\\` or pick a different template.`,\n )\n }\n\n const templateDir = getTemplateDir(templateName)\n\n if (!existsSync(templateDir)) {\n throw new Error(\n `Template \"${templateName}\" not found. Available templates: default, dashboard, api-only, postgres, saas`,\n )\n }\n\n if (!isValidProjectName(projectName)) {\n throw new Error(\n `Invalid project name \"${projectName}\". ` +\n `Use lowercase letters, numbers, hyphens, and dots. Must start with a letter or number.`,\n )\n }\n\n if (existsSync(targetDir)) {\n const contents = readdirSync(targetDir)\n if (contents.length > 0) {\n throw new Error(`Directory \"${targetDir}\" is not empty. Please use an empty directory.`)\n }\n }\n\n cpSync(templateDir, targetDir, { recursive: true })\n\n const gitignoreSrc = join(targetDir, '_gitignore')\n const gitignoreDest = join(targetDir, '.gitignore')\n if (existsSync(gitignoreSrc)) {\n renameSync(gitignoreSrc, gitignoreDest)\n }\n\n // Apply {{name}} substitution to every `*.tmpl` file in the target dir.\n // Each `foo.tmpl` becomes `foo` with placeholders replaced. Walks only\n // the project root (deeper subfolders don't currently need templating).\n for (const entry of readdirSync(targetDir)) {\n if (!entry.endsWith('.tmpl')) continue\n const src = join(targetDir, entry)\n const stat = statSync(src)\n if (!stat.isFile()) continue\n const dst = join(targetDir, entry.slice(0, -'.tmpl'.length))\n const content = readFileSync(src, 'utf-8')\n const replaced = content.replace(/\\{\\{name\\}\\}/g, projectName)\n writeFileSync(dst, replaced)\n unlinkSync(src)\n }\n\n // T4.1 — Apply --bare transform with EC-4 atomic rollback\n if (options.bare) {\n try {\n applyBareTransform(targetDir, {\n _testForceError: options._testForceTransformError,\n })\n } catch (err) {\n // EC-4: roll back partial state\n rmSync(targetDir, { recursive: true, force: true })\n const original = err instanceof Error ? err.message : String(err)\n throw new Error(\n `Scaffold rolled back: bare transform failed. Check filesystem perms.\\nOriginal error: ${original}`,\n )\n }\n }\n}\n","/* eslint-disable security/detect-non-literal-fs-filename --\n * Scaffold transform. Mutates files inside the freshly-created target\n * directory whose absolute path is the function input. No HTTP input.\n */\n/**\n * T4.1 — `--bare` transformation.\n *\n * Applied AFTER the default template is copied. Removes:\n * - `@usetheo/ui` from `package.json` dependencies (TheoUI bundled components)\n * - `@usetheo/sdk` from `package.json` dependencies (agent SDK — see below)\n * - `app/page.tsx` agent-surface content (replaces with Hello Theo)\n * - `server/routes/chat.ts` (mock chat — depends on SDK + TheoUI events)\n * - `tailwind.config.ts` + `postcss.config.js` (Tailwind toolchain — only\n * needed by the @usetheo/ui-driven default surface)\n * - tailwind* + postcss* from devDependencies (toolchain cleanup)\n *\n * Why SDK removal is in --bare:\n * `@usetheo/sdk` is not yet on the public npm registry (operator-deferred\n * publish per macro roadmap item #3). A user running `npx create-theokit`\n * without `--bare` hits `npm install` → 404. The `--bare` path produces a\n * scaffold that ALWAYS works without registry dependencies — Hello Theo\n * with a clean structure to grow into.\n *\n * EC-4: callers MUST wrap this in try/catch + `rmSync` rollback so a partial\n * transform never leaves the target dir in a broken state.\n */\n\nimport { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\n\nconst HELLO_PAGE = `export default function Page() {\n return <h1>Hello Theo</h1>\n}\n`\n\nexport interface BareTransformOptions {\n /** Test-only — force a synthetic write failure to validate rollback path. */\n _testForceError?: string\n}\n\nexport function applyBareTransform(targetDir: string, options: BareTransformOptions = {}): void {\n if (options._testForceError) {\n throw new Error(`Forced transform failure: ${options._testForceError}`)\n }\n\n // 1. Remove @usetheo/ui + @usetheo/sdk + tailwind toolchain from deps\n const pkgPath = join(targetDir, 'package.json')\n if (existsSync(pkgPath)) {\n interface PartialPackageJson {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n [key: string]: unknown\n }\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as PartialPackageJson\n if (pkg.dependencies) {\n delete pkg.dependencies['@usetheo/ui']\n // Drop SDK — operator-deferred npm publish (macro roadmap item #3).\n // Without removal, `npm install` hits 404 for any consumer outside\n // the workspace.\n delete pkg.dependencies['@usetheo/sdk']\n // lucide-react ships with the TheoUI surface; --bare doesn't render\n // any icons so it's safe to drop.\n delete pkg.dependencies['lucide-react']\n }\n if (pkg.devDependencies) {\n // Tailwind toolchain is only needed by the @usetheo/ui-driven default\n // surface. --bare ships unstyled Hello Theo; no Tailwind required.\n delete pkg.devDependencies.tailwindcss\n delete pkg.devDependencies['tailwindcss-animate']\n delete pkg.devDependencies.postcss\n delete pkg.devDependencies.autoprefixer\n }\n writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\\n`)\n }\n\n // 2. Replace app/page.tsx with Hello Theo\n const pagePath = join(targetDir, 'app/page.tsx')\n if (existsSync(pagePath)) {\n writeFileSync(pagePath, HELLO_PAGE)\n }\n\n // 3. Remove mock chat route (depends on AgentEvent type and TheoUI deps)\n const chatPath = join(targetDir, 'server/routes/chat.ts')\n if (existsSync(chatPath)) {\n unlinkSync(chatPath)\n }\n\n // 4. Remove tailwind + postcss config files (toolchain dropped from devDeps)\n const tailwindCfg = join(targetDir, 'tailwind.config.ts')\n if (existsSync(tailwindCfg)) {\n unlinkSync(tailwindCfg)\n }\n const postcssCfg = join(targetDir, 'postcss.config.js')\n if (existsSync(postcssCfg)) {\n unlinkSync(postcssCfg)\n }\n}\n"],"mappings":"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","names":["resolve","existsSync","cpSync","readFileSync","writeFileSync","unlinkSync","readdirSync","statSync","resolve","join","dirname","fileURLToPath","existsSync","readFileSync","writeFileSync","unlinkSync","join","__dirname","dirname","fileURLToPath","resolve","existsSync","readdirSync","cpSync","join","statSync","readFileSync","writeFileSync","unlinkSync","resolve"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-theokit",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.6",
4
4
  "type": "module",
5
5
  "description": "Scaffold a new TheoKit project",
6
6
  "license": "Apache-2.0",
@@ -0,0 +1 @@
1
+ 22.12
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
@@ -4,10 +4,13 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "dev": "theokit dev"
7
+ "dev": "theokit dev",
8
+ "build": "theokit build",
9
+ "start": "theokit start",
10
+ "typecheck": "tsc --noEmit"
8
11
  },
9
12
  "dependencies": {
10
- "theokit": "^0.1.0-alpha.1",
13
+ "theokit": "^0.1.0-alpha.6",
11
14
  "react": "^19.0.0",
12
15
  "react-dom": "^19.0.0"
13
16
  },
@@ -0,0 +1 @@
1
+ 22.12
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
@@ -4,10 +4,13 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "dev": "theokit dev"
7
+ "dev": "theokit dev",
8
+ "build": "theokit build",
9
+ "start": "theokit start",
10
+ "typecheck": "tsc --noEmit"
8
11
  },
9
12
  "dependencies": {
10
- "theokit": "^0.1.0-alpha.1",
13
+ "theokit": "^0.1.0-alpha.6",
11
14
  "react": "^19.0.0",
12
15
  "react-dom": "^19.0.0"
13
16
  },
@@ -0,0 +1 @@
1
+ 22.12