create-zenbu-app 0.0.19 → 0.0.21

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/README.md CHANGED
@@ -8,53 +8,3 @@ cd my-app
8
8
  pnpm dev
9
9
  ```
10
10
 
11
- ## Interactive mode
12
-
13
- Run with no arguments to be prompted for a project name and config options:
14
-
15
- ```bash
16
- pnpm create zenbu-app
17
- ```
18
-
19
- You'll be asked for:
20
-
21
- - **Project name** — defaults to `my-zenbu-app` (just press enter to accept).
22
- - **Use Tailwind CSS?** — defaults to `yes`.
23
-
24
- Each prompt's default is selected when you press enter, so a default scaffold
25
- is just `enter, enter, enter`.
26
-
27
- ## Flags
28
-
29
- | Flag | Description |
30
- |---|---|
31
- | `--yes`, `-y` | Skip every prompt and take each option's default. With no project name, scaffolds into the current directory. |
32
- | `--no-install` | Skip the post-copy `<pm> install` step. |
33
-
34
- A few common invocations:
35
-
36
- ```bash
37
- pnpm create zenbu-app # interactive, then scaffolds ./my-zenbu-app
38
- pnpm create zenbu-app my-app # interactive options, scaffolds ./my-app
39
- pnpm create zenbu-app . # interactive options, scaffolds into cwd
40
- pnpm create zenbu-app --yes # all defaults, scaffolds into cwd
41
- pnpm create zenbu-app my-app --yes # all defaults, scaffolds ./my-app
42
- ```
43
-
44
- ## Templates
45
-
46
- The CLI ships full per-config copies of the project under `templates/<slug>/`
47
- — there are no in-template conditionals. Today:
48
-
49
- - `templates/tailwind/` — Tailwind CSS v4 wired up via `@tailwindcss/vite`.
50
- - `templates/vanilla/` — plain CSS, no utility framework.
51
-
52
- The selected slug is computed from the answered config options (Tailwind
53
- contributes `tailwind`; the empty set falls back to `vanilla`).
54
-
55
- ## Package manager support
56
-
57
- The detected invoking package manager is recorded in `zenbu.config.ts` and
58
- used for the post-copy install. pnpm, npm, yarn, and bun are all supported,
59
- but the bundled `.app` re-installs from the project's lockfile at first
60
- launch — so currently the lockfile must be a pnpm one.
package/dist/index.mjs CHANGED
@@ -138,6 +138,51 @@ function probeVersion(pm) {
138
138
  const match = (res.stdout ?? "").trim().match(/\d+\.\d+\.\d+(?:[-+][\w.]+)?/);
139
139
  return match ? match[0] : null;
140
140
  }
141
+ /**
142
+ * `npx`, `npm create`, and `npm exec` all set the same `npm/<version>`
143
+ * user agent, so when `detectPackageManager` reports `npm` the user may
144
+ * actually prefer a different installed pm. Probe all four candidates,
145
+ * present only the ones present on the machine, and let the user pick
146
+ * (or pick automatically when only one is installed / `--yes`).
147
+ */
148
+ async function resolveNpmAmbiguity(detected, opts) {
149
+ const candidates = [
150
+ "pnpm",
151
+ "npm",
152
+ "yarn",
153
+ "bun"
154
+ ];
155
+ const installed = [];
156
+ for (const c of candidates) {
157
+ if (c === "npm") {
158
+ installed.push({
159
+ type: "npm",
160
+ version: detected.version,
161
+ fallback: false
162
+ });
163
+ continue;
164
+ }
165
+ const v = probeVersion(c);
166
+ if (v) installed.push({
167
+ type: c,
168
+ version: v,
169
+ fallback: false
170
+ });
171
+ }
172
+ if (installed.length === 1) return installed[0];
173
+ const preferPnpm = installed.find((p) => p.type === "pnpm");
174
+ if (opts.yes) return preferPnpm ?? installed.find((p) => p.type === "npm");
175
+ const pick = await p.select({
176
+ message: "Which package manager should this app use?",
177
+ initialValue: preferPnpm?.type ?? "npm",
178
+ options: installed.map((p) => ({
179
+ value: p.type,
180
+ label: p.type === "pnpm" ? "pnpm (recommended)" : p.type
181
+ }))
182
+ });
183
+ if (p.isCancel(pick)) bail("Scaffolding cancelled.");
184
+ return installed.find((p) => p.type === pick);
185
+ }
141
186
  function renderTemplate(value, ctx) {
142
187
  return value.replace(/\{\{(\w+)\}\}/g, (full, key) => {
143
188
  return Object.prototype.hasOwnProperty.call(ctx, key) ? ctx[key] : full;
@@ -407,7 +452,8 @@ async function main() {
407
452
  templateDir = path.join(TEMPLATES_DIR, slug);
408
453
  }
409
454
  if (!fs.existsSync(templateDir)) bail(`No template found for configuration "${slug}".`);
410
- const pm = detectPackageManager();
455
+ let pm = detectPackageManager();
456
+ if (pm.type === "npm") pm = await resolveNpmAmbiguity(pm, { yes });
411
457
  p.log.step(`Scaffolding Zenbu ${pluginMode ? "plugin" : "app"} in "${displayName}" (template: ${slug})`);
412
458
  const ctx = pluginMode ? {
413
459
  projectName: displayName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-zenbu-app",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "Scaffold a new Zenbu app",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -8,7 +8,8 @@
8
8
  "build:source": "zen build:source",
9
9
  "build:electron": "zen build:electron",
10
10
  "publish:source": "zen publish:source",
11
- "link": "zen link"
11
+ "link": "zen link",
12
+ "db:generate": "zen db generate"
12
13
  },
13
14
  "dependencies": {
14
15
  "@zenbujs/core": "^0.0.20",
@@ -0,0 +1,7 @@
1
+ import { Service } from "@zenbujs/core/runtime"
2
+
3
+ export class CwdService extends Service.create({ key: "cwd" }) {
4
+ async get() {
5
+ return process.cwd()
6
+ }
7
+ }
@@ -27,7 +27,7 @@ function Home() {
27
27
  className="bg-indigo-600 hover:bg-indigo-700 transition text-white font-semibold px-4 py-2 rounded text-sm"
28
28
  onClick={async () => {
29
29
  setCopied(false)
30
- setCwd(await rpc.app.repo.getCwd())
30
+ setCwd(await rpc.app.cwd.get())
31
31
  }}
32
32
  >
33
33
  Get cwd
@@ -8,7 +8,8 @@
8
8
  "build:source": "zen build:source",
9
9
  "build:electron": "zen build:electron",
10
10
  "publish:source": "zen publish:source",
11
- "link": "zen link"
11
+ "link": "zen link",
12
+ "db:generate": "zen db generate"
12
13
  },
13
14
  "dependencies": {
14
15
  "@zenbujs/core": "^0.0.20",
@@ -0,0 +1,7 @@
1
+ import { Service } from "@zenbujs/core/runtime"
2
+
3
+ export class CwdService extends Service.create({ key: "cwd" }) {
4
+ async get() {
5
+ return process.cwd()
6
+ }
7
+ }
@@ -27,7 +27,7 @@ function Home() {
27
27
  className="primary-button"
28
28
  onClick={async () => {
29
29
  setCopied(false)
30
- setCwd(await rpc.app.repo.getCwd())
30
+ setCwd(await rpc.app.cwd.get())
31
31
  }}
32
32
  >
33
33
  Get cwd
@@ -1,11 +0,0 @@
1
- import { Service } from "@zenbujs/core/runtime"
2
-
3
- /**
4
- * Sample RPC service. Methods on the class are callable from the renderer
5
- * via `useRpc()` — see `src/renderer/App.tsx`.
6
- */
7
- export class Repo extends Service.create({ key: "repo" }) {
8
- async getCwd() {
9
- return process.cwd()
10
- }
11
- }
@@ -1,11 +0,0 @@
1
- import { Service } from "@zenbujs/core/runtime"
2
-
3
- /**
4
- * Sample RPC service. Methods on the class are callable from the renderer
5
- * via `useRpc()` — see `src/renderer/App.tsx`.
6
- */
7
- export class Repo extends Service.create({ key: "repo" }) {
8
- async getCwd() {
9
- return process.cwd()
10
- }
11
- }