@libria/scaffold 0.3.5 → 0.3.7
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/.clean-publish.hash +1 -1
- package/README.md +68 -18
- package/dist/cli/cli.mjs +5 -5
- package/dist/cli/cli.mjs.map +1 -1
- package/dist/cli/index.cjs +2 -2
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +14 -4
- package/dist/cli/index.d.cts.map +1 -1
- package/dist/cli/index.d.mts +14 -4
- package/dist/cli/index.d.mts.map +1 -1
- package/dist/cli/index.mjs +2 -2
- package/dist/cli/index.mjs.map +1 -1
- package/package.json +7 -7
package/.clean-publish.hash
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
14624322df52dd5c41679e44f6151e38e2318fe584a01e6154d03738012bb764
|
package/README.md
CHANGED
|
@@ -13,7 +13,8 @@ Forge your next project with lightning-fast scaffolding. A pluggable CLI that tr
|
|
|
13
13
|
- **NPM Package Support**: Load templates from npm packages
|
|
14
14
|
- **Dry Run Mode**: Preview what will be generated before committing
|
|
15
15
|
- **Force Overwrite**: Safely regenerate existing projects
|
|
16
|
-
- **
|
|
16
|
+
- **Global + Local Config**: Global `~/.lbscaffold.json` defaults with local per-key overrides
|
|
17
|
+
- **Template Plugins**: Angular, NestJS, Next.js, TypeScript libraries, and workspaces
|
|
17
18
|
|
|
18
19
|
## Installation
|
|
19
20
|
|
|
@@ -103,7 +104,7 @@ A modern TypeScript library template with:
|
|
|
103
104
|
|
|
104
105
|
A complete Angular application template using the official Angular CLI. Supports:
|
|
105
106
|
|
|
106
|
-
- Angular versions: Latest, 20, 19, 18, 17, 16
|
|
107
|
+
- Angular versions: Latest, 21, 20, 19, 18, 17, 16
|
|
107
108
|
- Stylesheet formats: SCSS, CSS, Sass, Less
|
|
108
109
|
- Optional routing module
|
|
109
110
|
- Optional Server-Side Rendering (SSR)
|
|
@@ -144,43 +145,81 @@ lb-scaffold new nestjs my-nest-api
|
|
|
144
145
|
- Skip git initialization?
|
|
145
146
|
- Skip package installation?
|
|
146
147
|
|
|
148
|
+
### nextjs
|
|
149
|
+
|
|
150
|
+
A Next.js application template using the official `create-next-app`. Supports:
|
|
151
|
+
|
|
152
|
+
- Tailwind CSS (enabled by default)
|
|
153
|
+
- TypeScript or JavaScript
|
|
154
|
+
- App Router, API-only, or empty project types
|
|
155
|
+
- Turbopack or Webpack bundler
|
|
156
|
+
- ESLint, Biome, or no linter
|
|
157
|
+
- Package manager choice: npm, Yarn, pnpm, or Bun
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
lb-scaffold new nextjs my-next-app
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Interactive prompts:**
|
|
164
|
+
- Next.js version
|
|
165
|
+
- Language (TypeScript/JavaScript)
|
|
166
|
+
- Enable Tailwind CSS?
|
|
167
|
+
- Bundler (Turbopack/Webpack)
|
|
168
|
+
- Project type (app/api/empty)
|
|
169
|
+
|
|
147
170
|
### ts-workspace
|
|
148
171
|
|
|
149
|
-
A TypeScript workspace (monorepo) template using
|
|
172
|
+
A TypeScript workspace (monorepo) template using npm workspaces and TypeScript project references. Provides two subcommands:
|
|
173
|
+
|
|
174
|
+
- **`init`** — Create a new workspace with shared tsconfig, package.json workspaces, and git setup
|
|
175
|
+
- **`add`** — Add projects into an existing workspace using other templates (ts-lib, angular, nestjs, nextjs)
|
|
150
176
|
|
|
151
|
-
|
|
152
|
-
- Angular applications
|
|
153
|
-
- NestJS backends
|
|
154
|
-
- Shared packages
|
|
155
|
-
- pnpm workspace configuration
|
|
156
|
-
- Turbo or Nx for monorepo tooling (optional)
|
|
177
|
+
Automatically manages workspace `package.json` entries, TypeScript project references, and tsconfig inheritance.
|
|
157
178
|
|
|
158
179
|
```bash
|
|
180
|
+
# Create a new workspace
|
|
159
181
|
lb-scaffold new ts-workspace my-monorepo
|
|
182
|
+
|
|
183
|
+
# Add a project into the workspace
|
|
184
|
+
lb-scaffold new ts-workspace my-lib --workspace ./my-monorepo --template ts-lib
|
|
160
185
|
```
|
|
161
186
|
|
|
162
|
-
**Interactive prompts:**
|
|
163
|
-
-
|
|
164
|
-
-
|
|
165
|
-
|
|
166
|
-
|
|
187
|
+
**Interactive prompts (init):**
|
|
188
|
+
- Package manager (npm, Yarn, pnpm)
|
|
189
|
+
- Initialize git repository?
|
|
190
|
+
|
|
191
|
+
**Interactive prompts (add):**
|
|
192
|
+
- Workspace root path
|
|
193
|
+
- Template to use
|
|
194
|
+
- Base path for the new project
|
|
167
195
|
|
|
168
196
|
## Configuration
|
|
169
197
|
|
|
170
198
|
The scaffold CLI supports a configuration file (`.lbscaffold.json`) that allows you to register custom plugin directories and npm packages. This enables you to use your own templates alongside the built-in ones.
|
|
171
199
|
|
|
172
|
-
### Config File
|
|
200
|
+
### Config File Locations
|
|
201
|
+
|
|
202
|
+
The CLI supports two config file locations:
|
|
173
203
|
|
|
174
|
-
|
|
204
|
+
- **Global**: `~/.lbscaffold.json` — provides machine-wide defaults
|
|
205
|
+
- **Local**: `.lbscaffold.json` found by searching up from the current directory
|
|
206
|
+
|
|
207
|
+
When both exist, local keys override global keys on a per-key basis. For example, if the local config defines `plugins`, it fully replaces the global `plugins`; keys not present locally fall through to the global config.
|
|
175
208
|
|
|
176
209
|
### Config Commands
|
|
177
210
|
|
|
178
|
-
Initialize a new config file:
|
|
211
|
+
Initialize a new config file in the current directory:
|
|
179
212
|
|
|
180
213
|
```bash
|
|
181
214
|
lb-scaffold config init
|
|
182
215
|
```
|
|
183
216
|
|
|
217
|
+
Initialize the global config file:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
lb-scaffold config init -g
|
|
221
|
+
```
|
|
222
|
+
|
|
184
223
|
This creates a `.lbscaffold.json` file with a default plugin path:
|
|
185
224
|
|
|
186
225
|
```json
|
|
@@ -194,6 +233,9 @@ Add a custom plugin directory:
|
|
|
194
233
|
|
|
195
234
|
```bash
|
|
196
235
|
lb-scaffold config add ./my-templates/**
|
|
236
|
+
|
|
237
|
+
# Add to global config
|
|
238
|
+
lb-scaffold config add ./my-templates/** -g
|
|
197
239
|
```
|
|
198
240
|
|
|
199
241
|
Remove a plugin directory:
|
|
@@ -202,18 +244,26 @@ Remove a plugin directory:
|
|
|
202
244
|
lb-scaffold config remove ./my-templates/**
|
|
203
245
|
```
|
|
204
246
|
|
|
205
|
-
List all configured plugin patterns:
|
|
247
|
+
List all configured plugin patterns (shows merged config with source indicators):
|
|
206
248
|
|
|
207
249
|
```bash
|
|
208
250
|
lb-scaffold config list
|
|
251
|
+
|
|
252
|
+
# Show only global config
|
|
253
|
+
lb-scaffold config list -g
|
|
209
254
|
```
|
|
210
255
|
|
|
211
256
|
Show the full config file:
|
|
212
257
|
|
|
213
258
|
```bash
|
|
214
259
|
lb-scaffold config show
|
|
260
|
+
|
|
261
|
+
# Show only global config
|
|
262
|
+
lb-scaffold config show -g
|
|
215
263
|
```
|
|
216
264
|
|
|
265
|
+
All config subcommands accept `-g` / `--global` to target the global config (`~/.lbscaffold.json`) instead of the local one.
|
|
266
|
+
|
|
217
267
|
### Config File Format
|
|
218
268
|
|
|
219
269
|
The `.lbscaffold.json` config file is a JSON file with the following structure:
|
package/dist/cli/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{PluginManager as e}from"@libria/plugin-loader";import{InteractiveCommand as t,InteractiveOption as n,Option as r}from"interactive-commander";import i from"fs/promises";import a from"path";import{fileURLToPath as
|
|
3
|
-
`,`utf-8`)}async function
|
|
4
|
-
`);throw Error(e)}}async function
|
|
5
|
-
`);throw Error(e)}}async function
|
|
6
|
-
Packages:`);for(let e of n)console.log(` - ${e}`)}}),n.command(`show`).description(`Show the full config file contents`).action(async()
|
|
2
|
+
import{PluginManager as e}from"@libria/plugin-loader";import{InteractiveCommand as t,InteractiveOption as n,Option as r}from"interactive-commander";import i from"fs/promises";import a from"os";import o from"path";import{fileURLToPath as s}from"url";import*as c from"node:readline";import{SCAFFOLD_TEMPLATE_PLUGIN_TYPE as l}from"@libria/scaffold-core";const u=`.lbscaffold.json`,d=o.join(a.homedir(),u);async function f(e=process.cwd()){let t=e;for(;;){let e=o.join(t,u);try{return await i.access(e),e}catch{let e=o.dirname(t);if(e===t)return null;t=e}}}function p(){return o.join(process.cwd(),u)}async function m(e){try{let t=await i.readFile(e,`utf-8`);return JSON.parse(t)}catch(t){if(t.code===`ENOENT`)return{};throw Error(`Failed to load config from ${e}: ${t.message}`)}}async function h(e){if(e)return m(e);let t=await m(d),n=await f(),r=n?await m(n):{};return{...t,...r}}async function g(e,t){let n=t??p();await i.writeFile(n,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,`utf-8`)}async function _(e){let t=e??p();try{throw await i.access(t),Error(`Config file already exists at ${t}`)}catch(e){if(e.code!==`ENOENT`)throw e}return await g({plugins:[`./plugins/**`],packages:[]},t),t}async function v(e,t){let n=t??await f()??p(),r=await m(n);if(r.plugins||=[],r.plugins.includes(e))throw Error(`Plugin pattern '${e}' already exists in config`);r.plugins.push(e),await g(r,n)}async function y(e,t){let n=t??await f();if(!n)throw Error(`No config file found`);let r=await m(n);if(!r.plugins||!r.plugins.includes(e))throw Error(`Plugin pattern '${e}' not found in config`);r.plugins=r.plugins.filter(t=>t!==e),await g(r,n)}function b(e,t){return e.map(e=>o.isAbsolute(e)?e.replace(/\\/g,`/`):o.resolve(t,e).replace(/\\/g,`/`))}async function x(e){if(e){let t=await m(e),n=o.dirname(e);return b(t.plugins??[],n)}let t=await f(),n=t?await m(t):{};return n.plugins?b(n.plugins,o.dirname(t)):b((await m(d)).plugins??[],a.homedir())}async function S(e,t){let n=t??await f()??p(),r=await m(n);if(r.packages||=[],r.packages.includes(e))throw Error(`Package '${e}' already exists in config`);r.packages.push(e),await g(r,n)}async function C(e,t){let n=t??await f();if(!n)throw Error(`No config file found`);let r=await m(n);if(!r.packages||!r.packages.includes(e))throw Error(`Package '${e}' not found in config`);r.packages=r.packages.filter(t=>t!==e),await g(r,n)}async function w(e){return(await h(e)).packages??[]}async function T(e){try{let t=import.meta.resolve(e),n=o.dirname(s(t));for(;n!==o.dirname(n);)try{return await i.access(o.join(n,`package.json`)),n}catch{n=o.dirname(n)}throw Error(`package.json not found`)}catch{throw Error(`Package '${e}' not found. Install it locally (npm install ${e}) or globally (npm install -g ${e}).`)}}async function E(e,t){let n=await e.discoverPlugins(t),r=e.getAllMetadata(),i=new Set(n.map(e=>e.id)),a=r.filter(e=>!i.has(e.id)).map(e=>({plugin:e,blockedDeps:e.dependencies?.filter(e=>i.has(e.id))??[]})).filter(e=>e.blockedDeps.length>0);if(a.length>0){let e=[`Cannot remove plugins matching pattern "${t}" because other plugins depend on them:`,...a.map(e=>`- Plugin "${e.plugin.id}" depends on: ${e.blockedDeps.map(e=>e.id).join(`, `)}`)].join(`
|
|
4
|
+
`);throw Error(e)}}async function D(e,t){let n=await e.discoverPlugins(t),r=e.getAllMetadata(),i=new Map;r.forEach(e=>i.set(e.id,e)),n.forEach(e=>i.set(e.id,e));let a=[];for(let e of n){let t=(e.dependencies?.map(e=>e.id)??[]).filter(e=>!i.has(e));t.length>0&&a.push({plugin:e,missing:t})}if(a.length>0){let e=[`Cannot add plugins matching pattern "${t}" because dependencies are missing:`,...a.map(e=>`- Plugin "${e.plugin.id}" is missing dependencies: ${e.missing.join(`, `)}`)].join(`
|
|
5
|
+
`);throw Error(e)}}function O(e){return e.global?d:void 0}async function k(e,t){let n=e.command(`config`).description(`Manage lb-scaffold configuration`);return n.command(`init`).description(`Initialize a new .lbscaffold.json config file`).option(`-g, --global`,`Target the global config (~/.lbscaffold.json)`).action(async e=>{try{let t=await _(O(e));console.log(`Created config file: ${t}`)}catch(e){console.error(e.message),process.exit(1)}}),n.command(`add <glob>`).description(`Add a plugin glob pattern to the config`).option(`-g, --global`,`Target the global config (~/.lbscaffold.json)`).action(async(e,n)=>{try{await D(t,e),await v(e,O(n)),console.log(`Added plugin pattern: ${e}`)}catch(e){console.error(e.message),process.exit(1)}}),n.command(`remove <glob>`).description(`Remove a plugin glob pattern from the config`).option(`-g, --global`,`Target the global config (~/.lbscaffold.json)`).action(async(e,n)=>{try{await E(t,e),await y(e,O(n)),console.log(`Removed plugin pattern: ${e}`)}catch(e){console.error(e.message),process.exit(1)}}),n.command(`list`).description(`List all plugin patterns and packages in the config`).option(`-g, --global`,`Show only the global config (~/.lbscaffold.json)`).action(async e=>{if(e.global){console.log(`Global config: ${d}\n`);let e=await m(d),t=e.plugins??[];if(t.length===0)console.log(`No plugin patterns configured.`);else{console.log(`Plugin patterns:`);for(let e of t)console.log(` - ${e}`)}let n=e.packages??[];if(n.length>0){console.log(`
|
|
6
|
+
Packages:`);for(let e of n)console.log(` - ${e}`)}return}let t=await m(d),n=await f(),r=n?await m(n):{},i=Object.keys(t).length>0,a=n!==null;if(!i&&!a){console.log(`No config files found.`),console.log(`Run "lb-scaffold config init" to create a local config.`),console.log(`Run "lb-scaffold config init -g" to create a global config.`);return}i&&console.log(`Global config: ${d}`),a&&console.log(`Local config: ${n}`),console.log();let o=await h(),s=r.plugins?`local`:i&&t.plugins?`global`:null,c=o.plugins??[];if(c.length===0)console.log(`No plugin patterns configured.`);else{console.log(`Plugin patterns (source: ${s}):`);for(let e of c)console.log(` - ${e}`)}let l=r.packages?`local`:i&&t.packages?`global`:null,u=o.packages??[];if(u.length>0){console.log(`\nPackages (source: ${l}):`);for(let e of u)console.log(` - ${e}`)}}),n.command(`show`).description(`Show the full config file contents`).option(`-g, --global`,`Show only the global config (~/.lbscaffold.json)`).action(async e=>{if(e.global){console.log(`Global config: ${d}\n`);let e=await m(d);console.log(JSON.stringify(e,null,2));return}let t=await m(d),n=await f(),r=Object.keys(t).length>0;if(!r&&!n){console.log(`No config files found.`),console.log(`Run "lb-scaffold config init" to create a local config.`),console.log(`Run "lb-scaffold config init -g" to create a global config.`);return}r&&console.log(`Global config: ${d}`),n&&console.log(`Local config: ${n}`),console.log();let i=await h();console.log(JSON.stringify(i,null,2))}),n.command(`add-package <name>`).description(`Add an npm package as a plugin source`).option(`-g, --global`,`Target the global config (~/.lbscaffold.json)`).action(async(e,n)=>{try{await D(t,await T(e)),await S(e,O(n)),console.log(`Added package: ${e}`)}catch(e){console.error(e.message),process.exit(1)}}),n.command(`remove-package <name>`).description(`Remove an npm package from plugin sources`).option(`-g, --global`,`Target the global config (~/.lbscaffold.json)`).action(async(e,n)=>{try{await E(t,await T(e)),await C(e,O(n)),console.log(`Removed package: ${e}`)}catch(e){console.error(e.message),process.exit(1)}}),n.command(`list-packages`).description(`List all npm packages configured as plugin sources`).option(`-g, --global`,`Show only packages from the global config (~/.lbscaffold.json)`).action(async e=>{if(e.global){let e=(await m(d)).packages??[];if(e.length===0)console.log(`No packages configured in global config.`);else{console.log(`Packages (global):`);for(let t of e)console.log(` - ${t}`)}return}let t=await w();if(t.length===0)console.log(`No packages configured.`);else{console.log(`Packages:`);for(let e of t)console.log(` - ${e}`)}}),n}let A=null;function j(){return A||=c.createInterface({input:process.stdin,output:process.stdout}),A}function M(){A?.close(),A=null}function N(e){return new Promise(t=>j().question(e,t))}async function P(e,t,n){let r=t.map(String);console.log(`\n ${e}`),r.forEach((e,t)=>{let r=e===String(n)?` (default)`:``;console.log(` ${t+1}) ${e}${r}`)});let i=await N(` Choice [${n??r[0]}]: `);if(!i.trim())return String(n??r[0]);let a=parseInt(i,10);return a>=1&&a<=r.length?r[a-1]:r.includes(i.trim())?i.trim():String(n??r[0])}async function F(e,t){let n=await N(` ${e} (Y/n) [${t===!1?`N`:`Y`}]: `);return n.trim()?n.trim().toLowerCase().startsWith(`y`):t!==!1}async function I(e,t){return(await N(` ${e}${t===void 0?``:` [${t}]`}: `)).trim()||String(t??``)}function L(e){return!e.flags.includes(`<`)&&!e.choices?.length}async function R(e,t){if(t.type===`array`){let e=t.choices??[],n=e.length?` (comma-separated, choices: ${e.join(`, `)})`:` (comma-separated)`,r=Array.isArray(t.defaultValue)?t.defaultValue.join(`, `):t.defaultValue===void 0?``:String(t.defaultValue),i=(await N(` ${t.description}${n} [${r}]: `)).trim()||r;if(!i)return e.length,[];let a=i.split(`,`).map(e=>e.trim()).filter(Boolean);return e.length?a.filter(t=>e.includes(t)):a}return t.choices?.length?P(t.description,t.choices,t.defaultValue):L(t)?F(t.description,t.defaultValue):I(t.description,t.defaultValue)}async function z(e,t,n){for(;;){let r=await e.getOptions(t),i=!1;for(let[e,a]of Object.entries(r))a!==void 0&&t[e]===void 0&&(i=!0,n[e]===void 0?t[e]=await R(e,a):t[e]=n[e]);if(!i)break}}function B(e,t,n){if(e===`array`){let e=t.split(`,`).map(e=>e.trim()).filter(Boolean);return n?.length?e.filter(e=>n.includes(e)):e}return e===`number`?Number(t):e===`boolean`?t===`true`:t}function V(e){let t={},n=[...process.argv],r=[];r.push(n[0],n[1]);for(let i=2;i<n.length;i++){let a=n[i],o=!1;for(let r of e){let e=r.flags.match(/--([a-z][a-z-]*)/i);if(!e)continue;let s=e[1],c=`--${s}`,l=`--no-${s}`,u=s.replace(/-([a-z])/g,(e,t)=>t.toUpperCase());if(a===l){t[u]=!1,o=!0;break}if(a===c&&r.type===`boolean`){t[u]=!0,o=!0;break}if(a.startsWith(`${c}=`)){let e=a.split(`=`).slice(1).join(`=`).trim();r.type===`array`?t[u]=B(`array`,e,r.choices):t[u]=B(r.type,e),o=!0;break}if(a===c&&r.type!==`boolean`){if(r.type===`array`){let e=[];for(let t=i+1;t<n.length;t++){let i=n[t];if(i.startsWith(`--`)||r.choices?.length&&!r.choices.includes(i))break;e.push(i)}t[u]=r.choices?.length?e.filter(e=>r.choices.includes(e)):e,i+=e.length}else t[u]=B(r.type,n[i+1]),i++;o=!0;break}}o||r.push(a)}return t}function H(e,t){let r=new n(t.flags,t.description);if(t.defaultValue!==void 0&&(t.type===`array`&&!Array.isArray(t.defaultValue)?r.default([]):r.default(t.defaultValue)),t.choices?.length&&r.choices(t.choices.map(String)),t.required&&r.makeOptionMandatory(),e.addOption(r),t.type===`boolean`&&L(t)){let r=t.flags.match(/--([a-z][a-z-]*)/i);if(r){let i=r[1],a=`Disable ${t.description.toLowerCase()}`,o=new n(`--no-${i}`,a);t.defaultValue===!0&&o.default(!1),e.addOption(o)}}}async function U(e,t,n,r,i){let a=e.command(n).description(r).argument(`<name>`,`Project name`).option(`--no-dry-run`,`Write files`).option(`--dry-run`,`Simulate without writing files`).option(`--no-force`,`Do not overwrite existing files`).option(`--force`,`Overwrite existing files`).allowUnknownOption(!0),o={name:``,subcommand:i},s=await t.getOptions(o),c={...o},l=new Set;for(;;){let e=new Set(Object.keys(s));if([...e].filter(e=>!l.has(e)).length===0)break;let n=V(Object.values(s));c={...c,...n},l=e,s=await t.getOptions(c)}for(let[,e]of Object.entries(s))e!==void 0&&H(a,e);a.action(async(e,n)=>{let r={name:e,subcommand:i,dryRun:n.dryRun,force:n.force};await z(t,r,n),M(),await t.execute(r)})}async function W(e,t){let n=e.command(`new`).description(`Create a new project from a template`),r=t.getPluginsByType(l);for(let e of r){let r=t.getPlugin(e.id);if(r.subcommands?.length){let e=n.command(r.argument).description(`${r.argument} commands`);for(let t of r.subcommands)await U(e,r,t.name,t.description,t.name)}else await U(n,r,r.argument,`Create a new ${r.argument} project`)}return n}const G=await x(),K=await w(),q=await Promise.all(K.map(async e=>await T(e))),J=new e;await J.loadPlugins([...G,...q]),await J.unloadPlugin(`libria:scaffold:ts-lib`);const Y=new t;Y.name(`lb-scaffold`).description(`Scaffold new projects from templates`),await W(Y,J),await k(Y,J),Y.addOption(new r(`-i, --interactive`,`Run in interactive mode`).default(!0)),await Y.interactive().parseAsync();export{};
|
|
7
7
|
//# sourceMappingURL=cli.mjs.map
|
package/dist/cli/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts","../../src/commands/register-config.command.ts","../../src/commands/register-new.command.ts","../../src/cli.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold.json';\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load the config file\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n return {};\n }\n\n try {\n const content = await fs.readFile(resolvedPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${resolvedPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Get absolute plugin paths from config globs\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n const resolvedConfigPath = configPath ?? (await findConfigPath());\n\n if (!resolvedConfigPath) {\n return [];\n }\n\n const config = await loadConfig(resolvedConfigPath);\n const configDir = path.dirname(resolvedConfigPath);\n\n return (config.plugins ?? []).map(glob => {\n // If glob is absolute, use as-is; otherwise resolve relative to config file\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Uses import.meta.resolve() to find the package entry point,\n * then walks up to find the package.json — this works regardless\n * of the package's `exports` configuration.\n *\n * Correctly handles:\n * - npm workspaces (hoisted node_modules)\n * - Symlinked packages\n * - Global installs\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n try {\n const entryUrl = import.meta.resolve(packageName);\n let dir = path.dirname(fileURLToPath(entryUrl));\n\n // Walk up until we find the package.json\n while (dir !== path.dirname(dir)) {\n try {\n await fs.access(path.join(dir, 'package.json'));\n return dir;\n } catch {\n dir = path.dirname(dir);\n }\n }\n\n throw new Error('package.json not found');\n } catch {\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n }\n}\n","import { InteractiveCommand } from 'interactive-commander';\n\nimport {\n addPackage,\n addPluginGlob,\n findConfigPath,\n initConfig,\n listPackages,\n listPluginGlobs,\n loadConfig,\n removePackage,\n removePluginGlob,\n} from '../config';\nimport { resolvePackageDir } from '../utils';\nimport { PluginManager, PluginMetadata } from '@libria/plugin-loader';\nimport { glob } from 'fast-glob';\n\nasync function assertCanRemovePlugins(\n pluginManager: PluginManager,\n pattern: string\n): Promise<void> {\n const metadataToRemove = await pluginManager.discoverPlugins(pattern);\n const allMetadata = pluginManager.getAllMetadata();\n\n const toRemoveSet = new Set(metadataToRemove.map(m => m.id));\n\n // Check all loaded plugins to see if they depend on any plugin in the removal set\n const blockingPlugins = allMetadata\n .filter(p => !toRemoveSet.has(p.id)) // ignore plugins that are themselves being removed\n .map(p => {\n const blockedDeps = p.dependencies?.filter(d => toRemoveSet.has(d.id)) ?? [];\n return { plugin: p, blockedDeps };\n })\n .filter(x => x.blockedDeps.length > 0);\n\n if (blockingPlugins.length > 0) {\n // format the message\n const message = [\n `Cannot remove plugins matching pattern \"${pattern}\" because other plugins depend on them:`,\n ...blockingPlugins.map(\n bp =>\n `- Plugin \"${bp.plugin.id}\" depends on: ${bp.blockedDeps.map(d => d.id).join(', ')}`\n ),\n ].join('\\n');\n\n throw new Error(message);\n }\n}\n\nasync function assertCanAddPlugins(pluginManager: PluginManager, pattern: string) {\n // discover all plugins that would be added by this glob\n const metadataToAdd = await pluginManager.discoverPlugins(pattern);\n\n // all currently loaded plugins\n const allMetadata = pluginManager.getAllMetadata();\n const allLoadedOrToAdd = new Map<string, PluginMetadata>();\n allMetadata.forEach(p => allLoadedOrToAdd.set(p.id, p));\n metadataToAdd.forEach(p => allLoadedOrToAdd.set(p.id, p)); // include plugins that will be added\n\n // check dependencies for each plugin we're about to add\n const missingDeps: { plugin: PluginMetadata; missing: string[] }[] = [];\n\n for (const plugin of metadataToAdd) {\n const deps = plugin.dependencies?.map(d => d.id) ?? [];\n const missing = deps.filter(depId => !allLoadedOrToAdd.has(depId));\n if (missing.length > 0) {\n missingDeps.push({ plugin, missing });\n }\n }\n\n if (missingDeps.length > 0) {\n const message = [\n `Cannot add plugins matching pattern \"${pattern}\" because dependencies are missing:`,\n ...missingDeps.map(\n md => `- Plugin \"${md.plugin.id}\" is missing dependencies: ${md.missing.join(', ')}`\n ),\n ].join('\\n');\n throw new Error(message);\n }\n}\n\nexport async function registerConfigCommand(\n program: InteractiveCommand,\n pluginManager: PluginManager\n): Promise<InteractiveCommand> {\n const configCommand = program.command('config').description('Manage lb-scaffold configuration');\n\n configCommand\n .command('init')\n .description('Initialize a new .lbscaffold.json config file in the current directory')\n .action(async () => {\n try {\n const configPath = await initConfig();\n console.log(`Created config file: ${configPath}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('add <glob>')\n .description('Add a plugin glob pattern to the config')\n .action(async (glob: string) => {\n try {\n await assertCanAddPlugins(pluginManager, glob);\n await addPluginGlob(glob);\n console.log(`Added plugin pattern: ${glob}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('remove <glob>')\n .description('Remove a plugin glob pattern from the config')\n .action(async (glob: string) => {\n try {\n await assertCanRemovePlugins(pluginManager, glob);\n await removePluginGlob(glob);\n console.log(`Removed plugin pattern: ${glob}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('list')\n .description('List all plugin patterns and packages in the config')\n .action(async () => {\n const configPath = await findConfigPath();\n if (!configPath) {\n console.log('No .lbscaffold.json config file found.');\n console.log('Run \"lb-scaffold config init\" to create one.');\n return;\n }\n\n console.log(`Config file: ${configPath}\\n`);\n\n const globs = await listPluginGlobs();\n if (globs.length === 0) {\n console.log('No plugin patterns configured.');\n } else {\n console.log('Plugin patterns:');\n for (const glob of globs) {\n console.log(` - ${glob}`);\n }\n }\n\n const packages = await listPackages();\n if (packages.length > 0) {\n console.log('\\nPackages:');\n for (const pkg of packages) {\n console.log(` - ${pkg}`);\n }\n }\n });\n\n configCommand\n .command('show')\n .description('Show the full config file contents')\n .action(async () => {\n const configPath = await findConfigPath();\n if (!configPath) {\n console.log('No .lbscaffold.json config file found.');\n console.log('Run \"lb-scaffold config init\" to create one.');\n return;\n }\n\n console.log(`Config file: ${configPath}\\n`);\n const config = await loadConfig(configPath);\n console.log(JSON.stringify(config, null, 2));\n });\n\n configCommand\n .command('add-package <name>')\n .description('Add an npm package as a plugin source')\n .action(async (name: string) => {\n try {\n await assertCanAddPlugins(pluginManager, await resolvePackageDir(name));\n await addPackage(name);\n console.log(`Added package: ${name}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('remove-package <name>')\n .description('Remove an npm package from plugin sources')\n .action(async (name: string) => {\n try {\n await assertCanRemovePlugins(pluginManager, await resolvePackageDir(name));\n await removePackage(name);\n console.log(`Removed package: ${name}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('list-packages')\n .description('List all npm packages configured as plugin sources')\n .action(async () => {\n const configPath = await findConfigPath();\n if (!configPath) {\n console.log('No .lbscaffold.json config file found.');\n console.log('Run \"lb-scaffold config init\" to create one.');\n return;\n }\n\n const packages = await listPackages();\n if (packages.length === 0) {\n console.log('No packages configured.');\n } else {\n console.log('Packages:');\n for (const pkg of packages) {\n console.log(` - ${pkg}`);\n }\n }\n });\n\n return configCommand;\n}\n","import * as readline from 'node:readline';\n\nimport { PluginManager } from '@libria/plugin-loader';\nimport {\n ScaffoldTemplatePlugin,\n SCAFFOLD_TEMPLATE_PLUGIN_TYPE,\n ScaffoldTemplatePluginOption,\n ScaffoldTemplatePluginOptions,\n OptionTypeMap,\n} from '@libria/scaffold-core';\nimport { Command, InteractiveCommand, InteractiveOption } from 'interactive-commander';\n\n// ── Prompting helpers (readline-based, zero dependencies) ────────────────────\n\nlet rl: readline.Interface | null = null;\n\nfunction getRL(): readline.Interface {\n if (!rl) rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n return rl;\n}\n\nfunction closeRL(): void {\n rl?.close();\n rl = null;\n}\n\nfunction ask(question: string): Promise<string> {\n return new Promise(resolve => getRL().question(question, resolve));\n}\n\nasync function promptSelect(\n message: string,\n choices: unknown[],\n defaultValue?: unknown\n): Promise<string> {\n const items = choices.map(String);\n console.log(`\\n ${message}`);\n items.forEach((c, i) => {\n const marker = c === String(defaultValue) ? ' (default)' : '';\n console.log(` ${i + 1}) ${c}${marker}`);\n });\n const answer = await ask(` Choice [${defaultValue ?? items[0]}]: `);\n if (!answer.trim()) return String(defaultValue ?? items[0]);\n const idx = parseInt(answer, 10);\n if (idx >= 1 && idx <= items.length) return items[idx - 1];\n if (items.includes(answer.trim())) return answer.trim();\n return String(defaultValue ?? items[0]);\n}\n\nasync function promptConfirm(message: string, defaultValue?: unknown): Promise<boolean> {\n const def = defaultValue === false ? 'N' : 'Y';\n const answer = await ask(` ${message} (Y/n) [${def}]: `);\n if (!answer.trim()) return defaultValue !== false;\n return answer.trim().toLowerCase().startsWith('y');\n}\n\nasync function promptInput(message: string, defaultValue?: unknown): Promise<string> {\n const suffix = defaultValue !== undefined ? ` [${defaultValue}]` : '';\n const answer = await ask(` ${message}${suffix}: `);\n return answer.trim() || String(defaultValue ?? '');\n}\n\n// ── Option type detection ────────────────────────────────────────────────────\n\nfunction isBooleanFlag(opt: ScaffoldTemplatePluginOption<keyof OptionTypeMap>): boolean {\n return !opt.flags.includes('<') && !opt.choices?.length;\n}\n\n// ── Prompt for a single option ───────────────────────────────────────────────\n\nasync function promptForOption(\n key: string,\n def: ScaffoldTemplatePluginOption<keyof OptionTypeMap>\n): Promise<unknown> {\n const optType = def.type as string;\n if (optType === 'array') {\n const choices = (def.choices ?? []) as string[];\n const hint = choices.length\n ? ` (comma-separated, choices: ${choices.join(', ')})`\n : ' (comma-separated)';\n const defaultStr = Array.isArray(def.defaultValue)\n ? def.defaultValue.join(', ')\n : def.defaultValue !== undefined\n ? String(def.defaultValue)\n : '';\n const answer = await ask(` ${def.description}${hint} [${defaultStr}]: `);\n const raw = answer.trim() || defaultStr;\n if (!raw) return choices.length ? [] : [];\n const parts = raw\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n return choices.length ? parts.filter(p => choices.includes(p)) : parts;\n }\n if (def.choices?.length) {\n return promptSelect(def.description, def.choices, def.defaultValue);\n }\n if (isBooleanFlag(def)) {\n return promptConfirm(def.description, def.defaultValue);\n }\n return promptInput(def.description, def.defaultValue);\n}\n\n// ── Iterative option resolution ──────────────────────────────────────────────\n\n/**\n * Resolves plugin options iteratively:\n * 1. Call getOptions(collected) to get currently-relevant options\n * 2. Prompt for any unanswered options (or use CLI-provided values)\n * 3. If new options appeared, repeat — the plugin may reveal more\n * options based on the newly-collected answers\n * 4. Stop when no new unanswered options appear\n */\nasync function resolveOptions(\n plugin: ScaffoldTemplatePlugin,\n collected: Record<string, unknown>,\n cliOpts: Record<string, unknown>\n): Promise<void> {\n while (true) {\n const optionDefs = await plugin.getOptions(\n collected as ScaffoldTemplatePluginOptions & Partial<Record<string, unknown>>\n );\n\n let hasNewOptions = false;\n\n for (const [key, def] of Object.entries(optionDefs)) {\n if (def === undefined) continue;\n if (collected[key] !== undefined) continue;\n\n hasNewOptions = true;\n\n // Use CLI-provided value if available, otherwise prompt\n if (cliOpts[key] !== undefined) {\n collected[key] = cliOpts[key];\n } else {\n collected[key] = await promptForOption(key, def);\n }\n }\n\n if (!hasNewOptions) break;\n }\n}\n\n// ── Argv pre-parsing ─────────────────────────────────────────────────────────\nfunction castValue(\n type: 'string' | 'boolean' | 'number' | 'array',\n value: string,\n choices?: string[]\n): string | number | boolean | string[] {\n if (type === 'array') {\n const parts = value\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n if (choices?.length) {\n return parts.filter(p => choices.includes(p));\n }\n return parts;\n }\n if (type === 'number') return Number(value);\n if (type === 'boolean') return value === 'true';\n return value;\n}\n\n/**\n * Pre-parse process.argv to extract values for a set of option definitions.\n * This is a lightweight scan — no full Commander parse — so we can call\n * getOptions() with the values before Commander registers anything.\n */\nfunction preParseArgv(\n defs: ScaffoldTemplatePluginOption<keyof OptionTypeMap>[]\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const args = [...process.argv];\n const remaining: string[] = [];\n\n // skip first two (node + cli path)\n remaining.push(args[0], args[1]);\n\n for (let i = 2; i < args.length; i++) {\n const arg = args[i];\n\n let matched = false;\n\n for (const def of defs) {\n const flagMatch = def.flags.match(/--([a-z][a-z-]*)/i);\n if (!flagMatch) continue;\n\n const baseName = flagMatch[1];\n const positive = `--${baseName}`;\n const negative = `--no-${baseName}`;\n const key = baseName.replace(/-([a-z])/g, (_, c) => c.toUpperCase());\n\n // -----------------------\n // BOOLEAN NEGATION SUPPORT\n // -----------------------\n if (arg === negative) {\n result[key] = false;\n matched = true;\n break;\n }\n\n // -----------------------\n // BOOLEAN TRUE SUPPORT\n // -----------------------\n if (arg === positive && def.type === 'boolean') {\n result[key] = true;\n matched = true;\n break;\n }\n\n // -----------------------\n // --flag=value (or --flag=v1,v2 for array)\n // -----------------------\n if (arg.startsWith(`${positive}=`)) {\n const value = arg.split('=').slice(1).join('=').trim();\n if ((def.type as string) === 'array') {\n result[key] = castValue('array', value, def.choices as string[] | undefined);\n } else {\n result[key] = castValue(def.type as 'string' | 'boolean' | 'number', value);\n }\n matched = true;\n break;\n }\n\n // -----------------------\n // --flag value [value ...] (variadic for array)\n // -----------------------\n if (arg === positive && def.type !== 'boolean') {\n if ((def.type as string) === 'array') {\n const collected: string[] = [];\n for (let j = i + 1; j < args.length; j++) {\n const next = args[j];\n if (next.startsWith('--')) break;\n if (def.choices?.length && !(def.choices as string[]).includes(next)) break;\n collected.push(next);\n }\n result[key] = def.choices?.length\n ? collected.filter(c => (def.choices as string[]).includes(c))\n : collected;\n i += collected.length;\n } else {\n result[key] = castValue(def.type as 'string' | 'number', args[i + 1]);\n i++;\n }\n matched = true;\n break;\n }\n }\n\n if (!matched) {\n remaining.push(arg);\n }\n }\n\n return result;\n}\n\n// ── Commander option registration ────────────────────────────────────────────\n\nfunction registerOption(\n cmd: Command,\n def: ScaffoldTemplatePluginOption<keyof OptionTypeMap>\n): void {\n const cmdOption = new InteractiveOption(def.flags, def.description);\n\n if (def.defaultValue !== undefined) {\n // Commander variadic options expect array default; scalar default for non-array\n if ((def.type as string) === 'array' && !Array.isArray(def.defaultValue)) {\n cmdOption.default([]);\n } else {\n cmdOption.default(def.defaultValue);\n }\n }\n if (def.choices?.length) {\n cmdOption.choices(def.choices.map(String));\n }\n if (def.required) {\n cmdOption.makeOptionMandatory();\n }\n\n cmd.addOption(cmdOption);\n\n\n // Register --no-* negation option for boolean flags\n if (def.type === 'boolean' && isBooleanFlag(def)) {\n const flagMatch = def.flags.match(/--([a-z][a-z-]*)/i);\n if (flagMatch) {\n const negationName = flagMatch[1];\n const negationDescription = `Disable ${def.description.toLowerCase()}`;\n const negationOption = new InteractiveOption(`--no-${negationName}`, negationDescription);\n if (def.defaultValue === true) {\n negationOption.default(false);\n }\n cmd.addOption(negationOption);\n }\n }\n}\n\n// ── Plugin command registration helper ────────────────────────────────────────\n/**\n * Registers a single command for a plugin (or subcommand), wiring up\n * iterative option resolution and the execute action.\n */\nasync function registerPluginCommand(\n parentCmd: Command,\n plugin: ScaffoldTemplatePlugin,\n commandName: string,\n description: string,\n subcommand?: string\n): Promise<void> {\n const sub = parentCmd\n .command(commandName)\n .description(description)\n .argument('<name>', 'Project name')\n .option('--no-dry-run', 'Write files')\n .option('--dry-run', 'Simulate without writing files')\n .option('--no-force', 'Do not overwrite existing files')\n .option('--force', 'Overwrite existing files')\n .allowUnknownOption(true);\n\n // Iteratively resolve options from argv so --help shows the right set.\n const baseOpts: ScaffoldTemplatePluginOptions = { name: '', subcommand };\n let optionDefs = await plugin.getOptions(\n baseOpts as ScaffoldTemplatePluginOptions & Partial<Record<string, unknown>>\n );\n let preCollected: Record<string, unknown> = { ...baseOpts };\n let previousKeys = new Set<string>();\n\n while (true) {\n const currentKeys = new Set(Object.keys(optionDefs));\n const newKeys = [...currentKeys].filter(k => !previousKeys.has(k));\n if (newKeys.length === 0) break;\n\n const parsed = preParseArgv(\n Object.values(optionDefs) as ScaffoldTemplatePluginOption<keyof OptionTypeMap>[]\n );\n preCollected = { ...preCollected, ...parsed };\n previousKeys = currentKeys;\n\n optionDefs = await plugin.getOptions(\n preCollected as ScaffoldTemplatePluginOptions & Partial<Record<string, unknown>>\n );\n }\n\n for (const [, def] of Object.entries(optionDefs)) {\n if (def === undefined) continue;\n registerOption(sub, def);\n }\n\n sub.action(async (name: string, cliOpts: Record<string, unknown>) => {\n const collected: Record<string, unknown> = {\n name,\n subcommand,\n dryRun: cliOpts.dryRun,\n force: cliOpts.force,\n };\n\n await resolveOptions(plugin, collected, cliOpts);\n\n closeRL();\n await plugin.execute(collected as ScaffoldTemplatePluginOptions & Record<string, unknown>);\n });\n}\n\n// ── Main registration ─────────────────────────────────────────────────────────\n\nexport async function registerNewCommand(\n program: InteractiveCommand,\n pluginManager: PluginManager\n): Promise<Command> {\n const newCmd = program.command('new').description('Create a new project from a template');\n\n const templates = pluginManager.getPluginsByType(SCAFFOLD_TEMPLATE_PLUGIN_TYPE);\n\n for (const meta of templates) {\n const plugin = pluginManager.getPlugin<ScaffoldTemplatePlugin>(meta.id);\n\n if (plugin.subcommands?.length) {\n // Plugin has subcommands — register a command group with nested subcommands\n const group = newCmd\n .command(plugin.argument)\n .description(`${plugin.argument} commands`);\n\n for (const subDef of plugin.subcommands) {\n await registerPluginCommand(\n group,\n plugin,\n subDef.name,\n subDef.description,\n subDef.name\n );\n }\n } else {\n // No subcommands — register a single command directly\n await registerPluginCommand(\n newCmd,\n plugin,\n plugin.argument,\n `Create a new ${plugin.argument} project`\n );\n }\n }\n\n return newCmd;\n}\n","#!/usr/bin/env node\n\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { PluginManager } from '@libria/plugin-loader';\nimport { InteractiveCommand, Option } from 'interactive-commander';\n\nimport { registerConfigCommand, registerNewCommand } from './commands';\nimport { getPluginPaths, listPackages } from './config';\nimport { resolvePackageDir } from './utils';\n\n// Load user plugins from config\nconst userPluginPaths = await getPluginPaths();\n\n// Load plugins from npm packages\nconst packageNames = await listPackages();\n\nconst packagePaths = await Promise.all(\n packageNames.map(async name => {\n const dir = await resolvePackageDir(name);\n return dir;\n })\n);\n\nconst pluginManager = new PluginManager();\nawait pluginManager.loadPlugins([...userPluginPaths, ...packagePaths]);\nawait pluginManager.unloadPlugin('libria:scaffold:ts-lib');\nconst program = new InteractiveCommand();\nprogram.name('lb-scaffold').description('Scaffold new projects from templates');\n\nawait registerNewCommand(program, pluginManager);\nawait registerConfigCommand(program, pluginManager);\n\n// Enable interactive mode by default\nprogram.addOption(new Option('-i, --interactive', 'Run in interactive mode').default(true));\n\nawait program.interactive().parseAsync();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts","../../src/commands/register-config.command.ts","../../src/commands/register-new.command.ts","../../src/cli.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport os from 'os';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold.json';\n\nexport const GLOBAL_CONFIG_PATH = path.join(os.homedir(), CONFIG_FILENAME);\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load a single config file from a specific path\n */\nexport async function loadRawConfig(configPath: string): Promise<LbScaffoldConfig> {\n try {\n const content = await fs.readFile(configPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${configPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Load the merged config (global defaults + local overrides).\n * When configPath is provided explicitly, only that file is loaded (no merging).\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n if (configPath) {\n return loadRawConfig(configPath);\n }\n\n const globalConfig = await loadRawConfig(GLOBAL_CONFIG_PATH);\n const localPath = await findConfigPath();\n const localConfig = localPath ? await loadRawConfig(localPath) : {};\n\n // Per-key merge: local keys fully override global keys\n return { ...globalConfig, ...localConfig };\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath()) ?? getDefaultConfigPath();\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Resolve globs from a single config file relative to its directory\n */\nfunction resolveGlobs(globs: string[], configDir: string): string[] {\n return globs.map(glob => {\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Get absolute plugin paths from config globs.\n * When no configPath is given, merges global and local configs:\n * - If local config defines `plugins`, use local only (resolved relative to local config dir)\n * - Otherwise, fall through to global `plugins` (resolved relative to $HOME)\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n if (configPath) {\n const config = await loadRawConfig(configPath);\n const configDir = path.dirname(configPath);\n return resolveGlobs(config.plugins ?? [], configDir);\n }\n\n const localPath = await findConfigPath();\n const localConfig = localPath ? await loadRawConfig(localPath) : {};\n\n // If local defines plugins, use local only\n if (localConfig.plugins) {\n return resolveGlobs(localConfig.plugins, path.dirname(localPath!));\n }\n\n // Fall through to global\n const globalConfig = await loadRawConfig(GLOBAL_CONFIG_PATH);\n return resolveGlobs(globalConfig.plugins ?? [], os.homedir());\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath()) ?? getDefaultConfigPath();\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config.\n * When no configPath is given, uses per-key merge (local `packages` overrides global).\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Uses import.meta.resolve() to find the package entry point,\n * then walks up to find the package.json — this works regardless\n * of the package's `exports` configuration.\n *\n * Correctly handles:\n * - npm workspaces (hoisted node_modules)\n * - Symlinked packages\n * - Global installs\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n try {\n const entryUrl = import.meta.resolve(packageName);\n let dir = path.dirname(fileURLToPath(entryUrl));\n\n // Walk up until we find the package.json\n while (dir !== path.dirname(dir)) {\n try {\n await fs.access(path.join(dir, 'package.json'));\n return dir;\n } catch {\n dir = path.dirname(dir);\n }\n }\n\n throw new Error('package.json not found');\n } catch {\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n }\n}\n","import { InteractiveCommand } from 'interactive-commander';\n\nimport {\n addPackage,\n addPluginGlob,\n findConfigPath,\n GLOBAL_CONFIG_PATH,\n initConfig,\n listPackages,\n listPluginGlobs,\n loadConfig,\n loadRawConfig,\n removePackage,\n removePluginGlob,\n} from '../config';\nimport { resolvePackageDir } from '../utils';\nimport { PluginManager, PluginMetadata } from '@libria/plugin-loader';\nimport { glob } from 'fast-glob';\n\nasync function assertCanRemovePlugins(\n pluginManager: PluginManager,\n pattern: string\n): Promise<void> {\n const metadataToRemove = await pluginManager.discoverPlugins(pattern);\n const allMetadata = pluginManager.getAllMetadata();\n\n const toRemoveSet = new Set(metadataToRemove.map(m => m.id));\n\n // Check all loaded plugins to see if they depend on any plugin in the removal set\n const blockingPlugins = allMetadata\n .filter(p => !toRemoveSet.has(p.id)) // ignore plugins that are themselves being removed\n .map(p => {\n const blockedDeps = p.dependencies?.filter(d => toRemoveSet.has(d.id)) ?? [];\n return { plugin: p, blockedDeps };\n })\n .filter(x => x.blockedDeps.length > 0);\n\n if (blockingPlugins.length > 0) {\n // format the message\n const message = [\n `Cannot remove plugins matching pattern \"${pattern}\" because other plugins depend on them:`,\n ...blockingPlugins.map(\n bp =>\n `- Plugin \"${bp.plugin.id}\" depends on: ${bp.blockedDeps.map(d => d.id).join(', ')}`\n ),\n ].join('\\n');\n\n throw new Error(message);\n }\n}\n\nasync function assertCanAddPlugins(pluginManager: PluginManager, pattern: string) {\n // discover all plugins that would be added by this glob\n const metadataToAdd = await pluginManager.discoverPlugins(pattern);\n\n // all currently loaded plugins\n const allMetadata = pluginManager.getAllMetadata();\n const allLoadedOrToAdd = new Map<string, PluginMetadata>();\n allMetadata.forEach(p => allLoadedOrToAdd.set(p.id, p));\n metadataToAdd.forEach(p => allLoadedOrToAdd.set(p.id, p)); // include plugins that will be added\n\n // check dependencies for each plugin we're about to add\n const missingDeps: { plugin: PluginMetadata; missing: string[] }[] = [];\n\n for (const plugin of metadataToAdd) {\n const deps = plugin.dependencies?.map(d => d.id) ?? [];\n const missing = deps.filter(depId => !allLoadedOrToAdd.has(depId));\n if (missing.length > 0) {\n missingDeps.push({ plugin, missing });\n }\n }\n\n if (missingDeps.length > 0) {\n const message = [\n `Cannot add plugins matching pattern \"${pattern}\" because dependencies are missing:`,\n ...missingDeps.map(\n md => `- Plugin \"${md.plugin.id}\" is missing dependencies: ${md.missing.join(', ')}`\n ),\n ].join('\\n');\n throw new Error(message);\n }\n}\n\nfunction resolveConfigPath(opts: { global?: boolean }): string | undefined {\n return opts.global ? GLOBAL_CONFIG_PATH : undefined;\n}\n\nexport async function registerConfigCommand(\n program: InteractiveCommand,\n pluginManager: PluginManager\n): Promise<InteractiveCommand> {\n const configCommand = program.command('config').description('Manage lb-scaffold configuration');\n\n configCommand\n .command('init')\n .description('Initialize a new .lbscaffold.json config file')\n .option('-g, --global', 'Target the global config (~/.lbscaffold.json)')\n .action(async (opts: { global?: boolean }) => {\n try {\n const configPath = await initConfig(resolveConfigPath(opts));\n console.log(`Created config file: ${configPath}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('add <glob>')\n .description('Add a plugin glob pattern to the config')\n .option('-g, --global', 'Target the global config (~/.lbscaffold.json)')\n .action(async (glob: string, opts: { global?: boolean }) => {\n try {\n await assertCanAddPlugins(pluginManager, glob);\n await addPluginGlob(glob, resolveConfigPath(opts));\n console.log(`Added plugin pattern: ${glob}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('remove <glob>')\n .description('Remove a plugin glob pattern from the config')\n .option('-g, --global', 'Target the global config (~/.lbscaffold.json)')\n .action(async (glob: string, opts: { global?: boolean }) => {\n try {\n await assertCanRemovePlugins(pluginManager, glob);\n await removePluginGlob(glob, resolveConfigPath(opts));\n console.log(`Removed plugin pattern: ${glob}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('list')\n .description('List all plugin patterns and packages in the config')\n .option('-g, --global', 'Show only the global config (~/.lbscaffold.json)')\n .action(async (opts: { global?: boolean }) => {\n if (opts.global) {\n console.log(`Global config: ${GLOBAL_CONFIG_PATH}\\n`);\n const globalConfig = await loadRawConfig(GLOBAL_CONFIG_PATH);\n\n const globs = globalConfig.plugins ?? [];\n if (globs.length === 0) {\n console.log('No plugin patterns configured.');\n } else {\n console.log('Plugin patterns:');\n for (const g of globs) {\n console.log(` - ${g}`);\n }\n }\n\n const packages = globalConfig.packages ?? [];\n if (packages.length > 0) {\n console.log('\\nPackages:');\n for (const pkg of packages) {\n console.log(` - ${pkg}`);\n }\n }\n return;\n }\n\n // Show merged config with source indicators\n const globalConfig = await loadRawConfig(GLOBAL_CONFIG_PATH);\n const localPath = await findConfigPath();\n const localConfig = localPath ? await loadRawConfig(localPath) : {};\n const hasGlobal = Object.keys(globalConfig).length > 0;\n const hasLocal = localPath !== null;\n\n if (!hasGlobal && !hasLocal) {\n console.log('No config files found.');\n console.log('Run \"lb-scaffold config init\" to create a local config.');\n console.log('Run \"lb-scaffold config init -g\" to create a global config.');\n return;\n }\n\n if (hasGlobal) console.log(`Global config: ${GLOBAL_CONFIG_PATH}`);\n if (hasLocal) console.log(`Local config: ${localPath}`);\n console.log();\n\n const merged = await loadConfig();\n const pluginSource = localConfig.plugins ? 'local' : hasGlobal && globalConfig.plugins ? 'global' : null;\n const globs = merged.plugins ?? [];\n if (globs.length === 0) {\n console.log('No plugin patterns configured.');\n } else {\n console.log(`Plugin patterns (source: ${pluginSource}):`);\n for (const g of globs) {\n console.log(` - ${g}`);\n }\n }\n\n const packageSource = localConfig.packages ? 'local' : hasGlobal && globalConfig.packages ? 'global' : null;\n const packages = merged.packages ?? [];\n if (packages.length > 0) {\n console.log(`\\nPackages (source: ${packageSource}):`);\n for (const pkg of packages) {\n console.log(` - ${pkg}`);\n }\n }\n });\n\n configCommand\n .command('show')\n .description('Show the full config file contents')\n .option('-g, --global', 'Show only the global config (~/.lbscaffold.json)')\n .action(async (opts: { global?: boolean }) => {\n if (opts.global) {\n console.log(`Global config: ${GLOBAL_CONFIG_PATH}\\n`);\n const config = await loadRawConfig(GLOBAL_CONFIG_PATH);\n console.log(JSON.stringify(config, null, 2));\n return;\n }\n\n // Show merged config\n const globalConfig = await loadRawConfig(GLOBAL_CONFIG_PATH);\n const localPath = await findConfigPath();\n const hasGlobal = Object.keys(globalConfig).length > 0;\n\n if (!hasGlobal && !localPath) {\n console.log('No config files found.');\n console.log('Run \"lb-scaffold config init\" to create a local config.');\n console.log('Run \"lb-scaffold config init -g\" to create a global config.');\n return;\n }\n\n if (hasGlobal) console.log(`Global config: ${GLOBAL_CONFIG_PATH}`);\n if (localPath) console.log(`Local config: ${localPath}`);\n console.log();\n\n const merged = await loadConfig();\n console.log(JSON.stringify(merged, null, 2));\n });\n\n configCommand\n .command('add-package <name>')\n .description('Add an npm package as a plugin source')\n .option('-g, --global', 'Target the global config (~/.lbscaffold.json)')\n .action(async (name: string, opts: { global?: boolean }) => {\n try {\n await assertCanAddPlugins(pluginManager, await resolvePackageDir(name));\n await addPackage(name, resolveConfigPath(opts));\n console.log(`Added package: ${name}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('remove-package <name>')\n .description('Remove an npm package from plugin sources')\n .option('-g, --global', 'Target the global config (~/.lbscaffold.json)')\n .action(async (name: string, opts: { global?: boolean }) => {\n try {\n await assertCanRemovePlugins(pluginManager, await resolvePackageDir(name));\n await removePackage(name, resolveConfigPath(opts));\n console.log(`Removed package: ${name}`);\n } catch (error) {\n console.error((error as Error).message);\n process.exit(1);\n }\n });\n\n configCommand\n .command('list-packages')\n .description('List all npm packages configured as plugin sources')\n .option('-g, --global', 'Show only packages from the global config (~/.lbscaffold.json)')\n .action(async (opts: { global?: boolean }) => {\n if (opts.global) {\n const globalConfig = await loadRawConfig(GLOBAL_CONFIG_PATH);\n const packages = globalConfig.packages ?? [];\n if (packages.length === 0) {\n console.log('No packages configured in global config.');\n } else {\n console.log('Packages (global):');\n for (const pkg of packages) {\n console.log(` - ${pkg}`);\n }\n }\n return;\n }\n\n const packages = await listPackages();\n if (packages.length === 0) {\n console.log('No packages configured.');\n } else {\n console.log('Packages:');\n for (const pkg of packages) {\n console.log(` - ${pkg}`);\n }\n }\n });\n\n return configCommand;\n}\n","import * as readline from 'node:readline';\n\nimport { PluginManager } from '@libria/plugin-loader';\nimport {\n ScaffoldTemplatePlugin,\n SCAFFOLD_TEMPLATE_PLUGIN_TYPE,\n ScaffoldTemplatePluginOption,\n ScaffoldTemplatePluginOptions,\n OptionTypeMap,\n} from '@libria/scaffold-core';\nimport { Command, InteractiveCommand, InteractiveOption } from 'interactive-commander';\n\n// ── Prompting helpers (readline-based, zero dependencies) ────────────────────\n\nlet rl: readline.Interface | null = null;\n\nfunction getRL(): readline.Interface {\n if (!rl) rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n return rl;\n}\n\nfunction closeRL(): void {\n rl?.close();\n rl = null;\n}\n\nfunction ask(question: string): Promise<string> {\n return new Promise(resolve => getRL().question(question, resolve));\n}\n\nasync function promptSelect(\n message: string,\n choices: unknown[],\n defaultValue?: unknown\n): Promise<string> {\n const items = choices.map(String);\n console.log(`\\n ${message}`);\n items.forEach((c, i) => {\n const marker = c === String(defaultValue) ? ' (default)' : '';\n console.log(` ${i + 1}) ${c}${marker}`);\n });\n const answer = await ask(` Choice [${defaultValue ?? items[0]}]: `);\n if (!answer.trim()) return String(defaultValue ?? items[0]);\n const idx = parseInt(answer, 10);\n if (idx >= 1 && idx <= items.length) return items[idx - 1];\n if (items.includes(answer.trim())) return answer.trim();\n return String(defaultValue ?? items[0]);\n}\n\nasync function promptConfirm(message: string, defaultValue?: unknown): Promise<boolean> {\n const def = defaultValue === false ? 'N' : 'Y';\n const answer = await ask(` ${message} (Y/n) [${def}]: `);\n if (!answer.trim()) return defaultValue !== false;\n return answer.trim().toLowerCase().startsWith('y');\n}\n\nasync function promptInput(message: string, defaultValue?: unknown): Promise<string> {\n const suffix = defaultValue !== undefined ? ` [${defaultValue}]` : '';\n const answer = await ask(` ${message}${suffix}: `);\n return answer.trim() || String(defaultValue ?? '');\n}\n\n// ── Option type detection ────────────────────────────────────────────────────\n\nfunction isBooleanFlag(opt: ScaffoldTemplatePluginOption<keyof OptionTypeMap>): boolean {\n return !opt.flags.includes('<') && !opt.choices?.length;\n}\n\n// ── Prompt for a single option ───────────────────────────────────────────────\n\nasync function promptForOption(\n key: string,\n def: ScaffoldTemplatePluginOption<keyof OptionTypeMap>\n): Promise<unknown> {\n const optType = def.type as string;\n if (optType === 'array') {\n const choices = (def.choices ?? []) as string[];\n const hint = choices.length\n ? ` (comma-separated, choices: ${choices.join(', ')})`\n : ' (comma-separated)';\n const defaultStr = Array.isArray(def.defaultValue)\n ? def.defaultValue.join(', ')\n : def.defaultValue !== undefined\n ? String(def.defaultValue)\n : '';\n const answer = await ask(` ${def.description}${hint} [${defaultStr}]: `);\n const raw = answer.trim() || defaultStr;\n if (!raw) return choices.length ? [] : [];\n const parts = raw\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n return choices.length ? parts.filter(p => choices.includes(p)) : parts;\n }\n if (def.choices?.length) {\n return promptSelect(def.description, def.choices, def.defaultValue);\n }\n if (isBooleanFlag(def)) {\n return promptConfirm(def.description, def.defaultValue);\n }\n return promptInput(def.description, def.defaultValue);\n}\n\n// ── Iterative option resolution ──────────────────────────────────────────────\n\n/**\n * Resolves plugin options iteratively:\n * 1. Call getOptions(collected) to get currently-relevant options\n * 2. Prompt for any unanswered options (or use CLI-provided values)\n * 3. If new options appeared, repeat — the plugin may reveal more\n * options based on the newly-collected answers\n * 4. Stop when no new unanswered options appear\n */\nasync function resolveOptions(\n plugin: ScaffoldTemplatePlugin,\n collected: Record<string, unknown>,\n cliOpts: Record<string, unknown>\n): Promise<void> {\n while (true) {\n const optionDefs = await plugin.getOptions(\n collected as ScaffoldTemplatePluginOptions & Partial<Record<string, unknown>>\n );\n\n let hasNewOptions = false;\n\n for (const [key, def] of Object.entries(optionDefs)) {\n if (def === undefined) continue;\n if (collected[key] !== undefined) continue;\n\n hasNewOptions = true;\n\n // Use CLI-provided value if available, otherwise prompt\n if (cliOpts[key] !== undefined) {\n collected[key] = cliOpts[key];\n } else {\n collected[key] = await promptForOption(key, def);\n }\n }\n\n if (!hasNewOptions) break;\n }\n}\n\n// ── Argv pre-parsing ─────────────────────────────────────────────────────────\nfunction castValue(\n type: 'string' | 'boolean' | 'number' | 'array',\n value: string,\n choices?: string[]\n): string | number | boolean | string[] {\n if (type === 'array') {\n const parts = value\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n if (choices?.length) {\n return parts.filter(p => choices.includes(p));\n }\n return parts;\n }\n if (type === 'number') return Number(value);\n if (type === 'boolean') return value === 'true';\n return value;\n}\n\n/**\n * Pre-parse process.argv to extract values for a set of option definitions.\n * This is a lightweight scan — no full Commander parse — so we can call\n * getOptions() with the values before Commander registers anything.\n */\nfunction preParseArgv(\n defs: ScaffoldTemplatePluginOption<keyof OptionTypeMap>[]\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const args = [...process.argv];\n const remaining: string[] = [];\n\n // skip first two (node + cli path)\n remaining.push(args[0], args[1]);\n\n for (let i = 2; i < args.length; i++) {\n const arg = args[i];\n\n let matched = false;\n\n for (const def of defs) {\n const flagMatch = def.flags.match(/--([a-z][a-z-]*)/i);\n if (!flagMatch) continue;\n\n const baseName = flagMatch[1];\n const positive = `--${baseName}`;\n const negative = `--no-${baseName}`;\n const key = baseName.replace(/-([a-z])/g, (_, c) => c.toUpperCase());\n\n // -----------------------\n // BOOLEAN NEGATION SUPPORT\n // -----------------------\n if (arg === negative) {\n result[key] = false;\n matched = true;\n break;\n }\n\n // -----------------------\n // BOOLEAN TRUE SUPPORT\n // -----------------------\n if (arg === positive && def.type === 'boolean') {\n result[key] = true;\n matched = true;\n break;\n }\n\n // -----------------------\n // --flag=value (or --flag=v1,v2 for array)\n // -----------------------\n if (arg.startsWith(`${positive}=`)) {\n const value = arg.split('=').slice(1).join('=').trim();\n if ((def.type as string) === 'array') {\n result[key] = castValue('array', value, def.choices as string[] | undefined);\n } else {\n result[key] = castValue(def.type as 'string' | 'boolean' | 'number', value);\n }\n matched = true;\n break;\n }\n\n // -----------------------\n // --flag value [value ...] (variadic for array)\n // -----------------------\n if (arg === positive && def.type !== 'boolean') {\n if ((def.type as string) === 'array') {\n const collected: string[] = [];\n for (let j = i + 1; j < args.length; j++) {\n const next = args[j];\n if (next.startsWith('--')) break;\n if (def.choices?.length && !(def.choices as string[]).includes(next)) break;\n collected.push(next);\n }\n result[key] = def.choices?.length\n ? collected.filter(c => (def.choices as string[]).includes(c))\n : collected;\n i += collected.length;\n } else {\n result[key] = castValue(def.type as 'string' | 'number', args[i + 1]);\n i++;\n }\n matched = true;\n break;\n }\n }\n\n if (!matched) {\n remaining.push(arg);\n }\n }\n\n return result;\n}\n\n// ── Commander option registration ────────────────────────────────────────────\n\nfunction registerOption(\n cmd: Command,\n def: ScaffoldTemplatePluginOption<keyof OptionTypeMap>\n): void {\n const cmdOption = new InteractiveOption(def.flags, def.description);\n\n if (def.defaultValue !== undefined) {\n // Commander variadic options expect array default; scalar default for non-array\n if ((def.type as string) === 'array' && !Array.isArray(def.defaultValue)) {\n cmdOption.default([]);\n } else {\n cmdOption.default(def.defaultValue);\n }\n }\n if (def.choices?.length) {\n cmdOption.choices(def.choices.map(String));\n }\n if (def.required) {\n cmdOption.makeOptionMandatory();\n }\n\n cmd.addOption(cmdOption);\n\n\n // Register --no-* negation option for boolean flags\n if (def.type === 'boolean' && isBooleanFlag(def)) {\n const flagMatch = def.flags.match(/--([a-z][a-z-]*)/i);\n if (flagMatch) {\n const negationName = flagMatch[1];\n const negationDescription = `Disable ${def.description.toLowerCase()}`;\n const negationOption = new InteractiveOption(`--no-${negationName}`, negationDescription);\n if (def.defaultValue === true) {\n negationOption.default(false);\n }\n cmd.addOption(negationOption);\n }\n }\n}\n\n// ── Plugin command registration helper ────────────────────────────────────────\n/**\n * Registers a single command for a plugin (or subcommand), wiring up\n * iterative option resolution and the execute action.\n */\nasync function registerPluginCommand(\n parentCmd: Command,\n plugin: ScaffoldTemplatePlugin,\n commandName: string,\n description: string,\n subcommand?: string\n): Promise<void> {\n const sub = parentCmd\n .command(commandName)\n .description(description)\n .argument('<name>', 'Project name')\n .option('--no-dry-run', 'Write files')\n .option('--dry-run', 'Simulate without writing files')\n .option('--no-force', 'Do not overwrite existing files')\n .option('--force', 'Overwrite existing files')\n .allowUnknownOption(true);\n\n // Iteratively resolve options from argv so --help shows the right set.\n const baseOpts: ScaffoldTemplatePluginOptions = { name: '', subcommand };\n let optionDefs = await plugin.getOptions(\n baseOpts as ScaffoldTemplatePluginOptions & Partial<Record<string, unknown>>\n );\n let preCollected: Record<string, unknown> = { ...baseOpts };\n let previousKeys = new Set<string>();\n\n while (true) {\n const currentKeys = new Set(Object.keys(optionDefs));\n const newKeys = [...currentKeys].filter(k => !previousKeys.has(k));\n if (newKeys.length === 0) break;\n\n const parsed = preParseArgv(\n Object.values(optionDefs) as ScaffoldTemplatePluginOption<keyof OptionTypeMap>[]\n );\n preCollected = { ...preCollected, ...parsed };\n previousKeys = currentKeys;\n\n optionDefs = await plugin.getOptions(\n preCollected as ScaffoldTemplatePluginOptions & Partial<Record<string, unknown>>\n );\n }\n\n for (const [, def] of Object.entries(optionDefs)) {\n if (def === undefined) continue;\n registerOption(sub, def);\n }\n\n sub.action(async (name: string, cliOpts: Record<string, unknown>) => {\n const collected: Record<string, unknown> = {\n name,\n subcommand,\n dryRun: cliOpts.dryRun,\n force: cliOpts.force,\n };\n\n await resolveOptions(plugin, collected, cliOpts);\n\n closeRL();\n await plugin.execute(collected as ScaffoldTemplatePluginOptions & Record<string, unknown>);\n });\n}\n\n// ── Main registration ─────────────────────────────────────────────────────────\n\nexport async function registerNewCommand(\n program: InteractiveCommand,\n pluginManager: PluginManager\n): Promise<Command> {\n const newCmd = program.command('new').description('Create a new project from a template');\n\n const templates = pluginManager.getPluginsByType(SCAFFOLD_TEMPLATE_PLUGIN_TYPE);\n\n for (const meta of templates) {\n const plugin = pluginManager.getPlugin<ScaffoldTemplatePlugin>(meta.id);\n\n if (plugin.subcommands?.length) {\n // Plugin has subcommands — register a command group with nested subcommands\n const group = newCmd\n .command(plugin.argument)\n .description(`${plugin.argument} commands`);\n\n for (const subDef of plugin.subcommands) {\n await registerPluginCommand(\n group,\n plugin,\n subDef.name,\n subDef.description,\n subDef.name\n );\n }\n } else {\n // No subcommands — register a single command directly\n await registerPluginCommand(\n newCmd,\n plugin,\n plugin.argument,\n `Create a new ${plugin.argument} project`\n );\n }\n }\n\n return newCmd;\n}\n","#!/usr/bin/env node\n\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { PluginManager } from '@libria/plugin-loader';\nimport { InteractiveCommand, Option } from 'interactive-commander';\n\nimport { registerConfigCommand, registerNewCommand } from './commands';\nimport { getPluginPaths, listPackages } from './config';\nimport { resolvePackageDir } from './utils';\n\n// Load user plugins from config\nconst userPluginPaths = await getPluginPaths();\n\n// Load plugins from npm packages\nconst packageNames = await listPackages();\n\nconst packagePaths = await Promise.all(\n packageNames.map(async name => {\n const dir = await resolvePackageDir(name);\n return dir;\n })\n);\n\nconst pluginManager = new PluginManager();\nawait pluginManager.loadPlugins([...userPluginPaths, ...packagePaths]);\nawait pluginManager.unloadPlugin('libria:scaffold:ts-lib');\nconst program = new InteractiveCommand();\nprogram.name('lb-scaffold').description('Scaffold new projects from templates');\n\nawait registerNewCommand(program, pluginManager);\nawait registerConfigCommand(program, pluginManager);\n\n// Enable interactive mode by default\nprogram.addOption(new Option('-i, --interactive', 'Run in interactive mode').default(true));\n\nawait program.interactive().parseAsync();\n"],"mappings":";+VASA,MAAM,EAAkB,mBAEX,EAAqB,EAAK,KAAK,EAAG,SAAS,CAAE,EAAgB,CAK1E,eAAsB,EAAe,EAAmB,QAAQ,KAAK,CAA0B,CAC3F,IAAI,EAAa,EAEjB,OAAa,CACT,IAAM,EAAa,EAAK,KAAK,EAAY,EAAgB,CACzD,GAAI,CAEA,OADA,MAAM,EAAG,OAAO,EAAW,CACpB,OACH,CACJ,IAAM,EAAY,EAAK,QAAQ,EAAW,CAC1C,GAAI,IAAc,EAEd,OAAO,KAEX,EAAa,IAQzB,SAAgB,GAA+B,CAC3C,OAAO,EAAK,KAAK,QAAQ,KAAK,CAAE,EAAgB,CAMpD,eAAsB,EAAc,EAA+C,CAC/E,GAAI,CACA,IAAM,EAAU,MAAM,EAAG,SAAS,EAAY,QAAQ,CACtD,OAAO,KAAK,MAAM,EAAQ,OACrB,EAAO,CACZ,GAAK,EAAgC,OAAS,SAC1C,MAAO,EAAE,CAEb,MAAU,MAAM,8BAA8B,EAAW,IAAK,EAAgB,UAAU,EAQhG,eAAsB,EAAW,EAAgD,CAC7E,GAAI,EACA,OAAO,EAAc,EAAW,CAGpC,IAAM,EAAe,MAAM,EAAc,EAAmB,CACtD,EAAY,MAAM,GAAgB,CAClC,EAAc,EAAY,MAAM,EAAc,EAAU,CAAG,EAAE,CAGnE,MAAO,CAAE,GAAG,EAAc,GAAG,EAAa,CAM9C,eAAsB,EAAW,EAA0B,EAAoC,CAC3F,IAAM,EAAe,GAAc,GAAsB,CACzD,MAAM,EAAG,UAAU,EAAc,KAAK,UAAU,EAAQ,KAAM,EAAE,CAAG;EAAM,QAAQ,CAMrF,eAAsB,EAAW,EAAsC,CACnE,IAAM,EAAe,GAAc,GAAsB,CAEzD,GAAI,CAEA,MADA,MAAM,EAAG,OAAO,EAAa,CACnB,MAAM,iCAAiC,IAAe,OAC3D,EAAO,CACZ,GAAK,EAAgC,OAAS,SAC1C,MAAM,EAUd,OADA,MAAM,EALkC,CACpC,QAAS,CAAC,eAAe,CACzB,SAAU,EAAE,CACf,CAE+B,EAAa,CACtC,EAMX,eAAsB,EAAc,EAAc,EAAoC,CAClF,IAAM,EAAe,GAAe,MAAM,GAAgB,EAAK,GAAsB,CAC/E,EAAS,MAAM,EAAc,EAAa,CAMhD,GAJA,AACI,EAAO,UAAU,EAAE,CAGnB,EAAO,QAAQ,SAAS,EAAK,CAC7B,MAAU,MAAM,mBAAmB,EAAK,4BAA4B,CAGxE,EAAO,QAAQ,KAAK,EAAK,CACzB,MAAM,EAAW,EAAQ,EAAa,CAM1C,eAAsB,EAAiB,EAAc,EAAoC,CACrF,IAAM,EAAe,GAAe,MAAM,GAAgB,CAE1D,GAAI,CAAC,EACD,MAAU,MAAM,uBAAuB,CAG3C,IAAM,EAAS,MAAM,EAAc,EAAa,CAEhD,GAAI,CAAC,EAAO,SAAW,CAAC,EAAO,QAAQ,SAAS,EAAK,CACjD,MAAU,MAAM,mBAAmB,EAAK,uBAAuB,CAGnE,EAAO,QAAU,EAAO,QAAQ,OAAO,GAAK,IAAM,EAAK,CACvD,MAAM,EAAW,EAAQ,EAAa,CAc1C,SAAS,EAAa,EAAiB,EAA6B,CAChE,OAAO,EAAM,IAAI,GACT,EAAK,WAAW,EAAK,CACd,EAAK,QAAQ,MAAO,IAAI,CAE5B,EAAK,QAAQ,EAAW,EAAK,CAAC,QAAQ,MAAO,IAAI,CAC1D,CASN,eAAsB,EAAe,EAAwC,CACzE,GAAI,EAAY,CACZ,IAAM,EAAS,MAAM,EAAc,EAAW,CACxC,EAAY,EAAK,QAAQ,EAAW,CAC1C,OAAO,EAAa,EAAO,SAAW,EAAE,CAAE,EAAU,CAGxD,IAAM,EAAY,MAAM,GAAgB,CAClC,EAAc,EAAY,MAAM,EAAc,EAAU,CAAG,EAAE,CASnE,OANI,EAAY,QACL,EAAa,EAAY,QAAS,EAAK,QAAQ,EAAW,CAAC,CAK/D,GADc,MAAM,EAAc,EAAmB,EAC3B,SAAW,EAAE,CAAE,EAAG,SAAS,CAAC,CAMjE,eAAsB,EAAW,EAAqB,EAAoC,CACtF,IAAM,EAAe,GAAe,MAAM,GAAgB,EAAK,GAAsB,CAC/E,EAAS,MAAM,EAAc,EAAa,CAMhD,GAJA,AACI,EAAO,WAAW,EAAE,CAGpB,EAAO,SAAS,SAAS,EAAY,CACrC,MAAU,MAAM,YAAY,EAAY,4BAA4B,CAGxE,EAAO,SAAS,KAAK,EAAY,CACjC,MAAM,EAAW,EAAQ,EAAa,CAM1C,eAAsB,EAAc,EAAqB,EAAoC,CACzF,IAAM,EAAe,GAAe,MAAM,GAAgB,CAE1D,GAAI,CAAC,EACD,MAAU,MAAM,uBAAuB,CAG3C,IAAM,EAAS,MAAM,EAAc,EAAa,CAEhD,GAAI,CAAC,EAAO,UAAY,CAAC,EAAO,SAAS,SAAS,EAAY,CAC1D,MAAU,MAAM,YAAY,EAAY,uBAAuB,CAGnE,EAAO,SAAW,EAAO,SAAS,OAAO,GAAK,IAAM,EAAY,CAChE,MAAM,EAAW,EAAQ,EAAa,CAO1C,eAAsB,EAAa,EAAwC,CAEvE,OADe,MAAM,EAAW,EAAW,EAC7B,UAAY,EAAE,CC7NhC,eAAsB,EAAkB,EAAsC,CAC1E,GAAI,CACA,IAAM,EAAW,OAAO,KAAK,QAAQ,EAAY,CAC7C,EAAM,EAAK,QAAQ,EAAc,EAAS,CAAC,CAG/C,KAAO,IAAQ,EAAK,QAAQ,EAAI,EAC5B,GAAI,CAEA,OADA,MAAM,EAAG,OAAO,EAAK,KAAK,EAAK,eAAe,CAAC,CACxC,OACH,CACJ,EAAM,EAAK,QAAQ,EAAI,CAI/B,MAAU,MAAM,yBAAyB,MACrC,CACJ,MAAU,MACN,YAAY,EAAY,+CACe,EAAY,gCAAgC,EAAY,IAClG,EChBT,eAAe,EACX,EACA,EACa,CACb,IAAM,EAAmB,MAAM,EAAc,gBAAgB,EAAQ,CAC/D,EAAc,EAAc,gBAAgB,CAE5C,EAAc,IAAI,IAAI,EAAiB,IAAI,GAAK,EAAE,GAAG,CAAC,CAGtD,EAAkB,EACnB,OAAO,GAAK,CAAC,EAAY,IAAI,EAAE,GAAG,CAAC,CACnC,IAAI,IAEM,CAAE,OAAQ,EAAG,YADA,EAAE,cAAc,OAAO,GAAK,EAAY,IAAI,EAAE,GAAG,CAAC,EAAI,EAAE,CAC3C,EACnC,CACD,OAAO,GAAK,EAAE,YAAY,OAAS,EAAE,CAE1C,GAAI,EAAgB,OAAS,EAAG,CAE5B,IAAM,EAAU,CACZ,2CAA2C,EAAQ,yCACnD,GAAG,EAAgB,IACf,GACI,aAAa,EAAG,OAAO,GAAG,gBAAgB,EAAG,YAAY,IAAI,GAAK,EAAE,GAAG,CAAC,KAAK,KAAK,GACzF,CACJ,CAAC,KAAK;EAAK,CAEZ,MAAU,MAAM,EAAQ,EAIhC,eAAe,EAAoB,EAA8B,EAAiB,CAE9E,IAAM,EAAgB,MAAM,EAAc,gBAAgB,EAAQ,CAG5D,EAAc,EAAc,gBAAgB,CAC5C,EAAmB,IAAI,IAC7B,EAAY,QAAQ,GAAK,EAAiB,IAAI,EAAE,GAAI,EAAE,CAAC,CACvD,EAAc,QAAQ,GAAK,EAAiB,IAAI,EAAE,GAAI,EAAE,CAAC,CAGzD,IAAM,EAA+D,EAAE,CAEvE,IAAK,IAAM,KAAU,EAAe,CAEhC,IAAM,GADO,EAAO,cAAc,IAAI,GAAK,EAAE,GAAG,EAAI,EAAE,EACjC,OAAO,GAAS,CAAC,EAAiB,IAAI,EAAM,CAAC,CAC9D,EAAQ,OAAS,GACjB,EAAY,KAAK,CAAE,SAAQ,UAAS,CAAC,CAI7C,GAAI,EAAY,OAAS,EAAG,CACxB,IAAM,EAAU,CACZ,wCAAwC,EAAQ,qCAChD,GAAG,EAAY,IACX,GAAM,aAAa,EAAG,OAAO,GAAG,6BAA6B,EAAG,QAAQ,KAAK,KAAK,GACrF,CACJ,CAAC,KAAK;EAAK,CACZ,MAAU,MAAM,EAAQ,EAIhC,SAAS,EAAkB,EAAgD,CACvE,OAAO,EAAK,OAAS,EAAqB,IAAA,GAG9C,eAAsB,EAClB,EACA,EAC2B,CAC3B,IAAM,EAAgB,EAAQ,QAAQ,SAAS,CAAC,YAAY,mCAAmC,CA+M/F,OA7MA,EACK,QAAQ,OAAO,CACf,YAAY,gDAAgD,CAC5D,OAAO,eAAgB,gDAAgD,CACvE,OAAO,KAAO,IAA+B,CAC1C,GAAI,CACA,IAAM,EAAa,MAAM,EAAW,EAAkB,EAAK,CAAC,CAC5D,QAAQ,IAAI,wBAAwB,IAAa,OAC5C,EAAO,CACZ,QAAQ,MAAO,EAAgB,QAAQ,CACvC,QAAQ,KAAK,EAAE,GAErB,CAEN,EACK,QAAQ,aAAa,CACrB,YAAY,0CAA0C,CACtD,OAAO,eAAgB,gDAAgD,CACvE,OAAO,MAAO,EAAc,IAA+B,CACxD,GAAI,CACA,MAAM,EAAoB,EAAe,EAAK,CAC9C,MAAM,EAAc,EAAM,EAAkB,EAAK,CAAC,CAClD,QAAQ,IAAI,yBAAyB,IAAO,OACvC,EAAO,CACZ,QAAQ,MAAO,EAAgB,QAAQ,CACvC,QAAQ,KAAK,EAAE,GAErB,CAEN,EACK,QAAQ,gBAAgB,CACxB,YAAY,+CAA+C,CAC3D,OAAO,eAAgB,gDAAgD,CACvE,OAAO,MAAO,EAAc,IAA+B,CACxD,GAAI,CACA,MAAM,EAAuB,EAAe,EAAK,CACjD,MAAM,EAAiB,EAAM,EAAkB,EAAK,CAAC,CACrD,QAAQ,IAAI,2BAA2B,IAAO,OACzC,EAAO,CACZ,QAAQ,MAAO,EAAgB,QAAQ,CACvC,QAAQ,KAAK,EAAE,GAErB,CAEN,EACK,QAAQ,OAAO,CACf,YAAY,sDAAsD,CAClE,OAAO,eAAgB,mDAAmD,CAC1E,OAAO,KAAO,IAA+B,CAC1C,GAAI,EAAK,OAAQ,CACb,QAAQ,IAAI,kBAAkB,EAAmB,IAAI,CACrD,IAAM,EAAe,MAAM,EAAc,EAAmB,CAEtD,EAAQ,EAAa,SAAW,EAAE,CACxC,GAAI,EAAM,SAAW,EACjB,QAAQ,IAAI,iCAAiC,KAC1C,CACH,QAAQ,IAAI,mBAAmB,CAC/B,IAAK,IAAM,KAAK,EACZ,QAAQ,IAAI,OAAO,IAAI,CAI/B,IAAM,EAAW,EAAa,UAAY,EAAE,CAC5C,GAAI,EAAS,OAAS,EAAG,CACrB,QAAQ,IAAI;WAAc,CAC1B,IAAK,IAAM,KAAO,EACd,QAAQ,IAAI,OAAO,IAAM,CAGjC,OAIJ,IAAM,EAAe,MAAM,EAAc,EAAmB,CACtD,EAAY,MAAM,GAAgB,CAClC,EAAc,EAAY,MAAM,EAAc,EAAU,CAAG,EAAE,CAC7D,EAAY,OAAO,KAAK,EAAa,CAAC,OAAS,EAC/C,EAAW,IAAc,KAE/B,GAAI,CAAC,GAAa,CAAC,EAAU,CACzB,QAAQ,IAAI,yBAAyB,CACrC,QAAQ,IAAI,0DAA0D,CACtE,QAAQ,IAAI,8DAA8D,CAC1E,OAGA,GAAW,QAAQ,IAAI,kBAAkB,IAAqB,CAC9D,GAAU,QAAQ,IAAI,kBAAkB,IAAY,CACxD,QAAQ,KAAK,CAEb,IAAM,EAAS,MAAM,GAAY,CAC3B,EAAe,EAAY,QAAU,QAAU,GAAa,EAAa,QAAU,SAAW,KAC9F,EAAQ,EAAO,SAAW,EAAE,CAClC,GAAI,EAAM,SAAW,EACjB,QAAQ,IAAI,iCAAiC,KAC1C,CACH,QAAQ,IAAI,4BAA4B,EAAa,IAAI,CACzD,IAAK,IAAM,KAAK,EACZ,QAAQ,IAAI,OAAO,IAAI,CAI/B,IAAM,EAAgB,EAAY,SAAW,QAAU,GAAa,EAAa,SAAW,SAAW,KACjG,EAAW,EAAO,UAAY,EAAE,CACtC,GAAI,EAAS,OAAS,EAAG,CACrB,QAAQ,IAAI,uBAAuB,EAAc,IAAI,CACrD,IAAK,IAAM,KAAO,EACd,QAAQ,IAAI,OAAO,IAAM,GAGnC,CAEN,EACK,QAAQ,OAAO,CACf,YAAY,qCAAqC,CACjD,OAAO,eAAgB,mDAAmD,CAC1E,OAAO,KAAO,IAA+B,CAC1C,GAAI,EAAK,OAAQ,CACb,QAAQ,IAAI,kBAAkB,EAAmB,IAAI,CACrD,IAAM,EAAS,MAAM,EAAc,EAAmB,CACtD,QAAQ,IAAI,KAAK,UAAU,EAAQ,KAAM,EAAE,CAAC,CAC5C,OAIJ,IAAM,EAAe,MAAM,EAAc,EAAmB,CACtD,EAAY,MAAM,GAAgB,CAClC,EAAY,OAAO,KAAK,EAAa,CAAC,OAAS,EAErD,GAAI,CAAC,GAAa,CAAC,EAAW,CAC1B,QAAQ,IAAI,yBAAyB,CACrC,QAAQ,IAAI,0DAA0D,CACtE,QAAQ,IAAI,8DAA8D,CAC1E,OAGA,GAAW,QAAQ,IAAI,kBAAkB,IAAqB,CAC9D,GAAW,QAAQ,IAAI,kBAAkB,IAAY,CACzD,QAAQ,KAAK,CAEb,IAAM,EAAS,MAAM,GAAY,CACjC,QAAQ,IAAI,KAAK,UAAU,EAAQ,KAAM,EAAE,CAAC,EAC9C,CAEN,EACK,QAAQ,qBAAqB,CAC7B,YAAY,wCAAwC,CACpD,OAAO,eAAgB,gDAAgD,CACvE,OAAO,MAAO,EAAc,IAA+B,CACxD,GAAI,CACA,MAAM,EAAoB,EAAe,MAAM,EAAkB,EAAK,CAAC,CACvE,MAAM,EAAW,EAAM,EAAkB,EAAK,CAAC,CAC/C,QAAQ,IAAI,kBAAkB,IAAO,OAChC,EAAO,CACZ,QAAQ,MAAO,EAAgB,QAAQ,CACvC,QAAQ,KAAK,EAAE,GAErB,CAEN,EACK,QAAQ,wBAAwB,CAChC,YAAY,4CAA4C,CACxD,OAAO,eAAgB,gDAAgD,CACvE,OAAO,MAAO,EAAc,IAA+B,CACxD,GAAI,CACA,MAAM,EAAuB,EAAe,MAAM,EAAkB,EAAK,CAAC,CAC1E,MAAM,EAAc,EAAM,EAAkB,EAAK,CAAC,CAClD,QAAQ,IAAI,oBAAoB,IAAO,OAClC,EAAO,CACZ,QAAQ,MAAO,EAAgB,QAAQ,CACvC,QAAQ,KAAK,EAAE,GAErB,CAEN,EACK,QAAQ,gBAAgB,CACxB,YAAY,qDAAqD,CACjE,OAAO,eAAgB,iEAAiE,CACxF,OAAO,KAAO,IAA+B,CAC1C,GAAI,EAAK,OAAQ,CAEb,IAAM,GADe,MAAM,EAAc,EAAmB,EAC9B,UAAY,EAAE,CAC5C,GAAI,EAAS,SAAW,EACpB,QAAQ,IAAI,2CAA2C,KACpD,CACH,QAAQ,IAAI,qBAAqB,CACjC,IAAK,IAAM,KAAO,EACd,QAAQ,IAAI,OAAO,IAAM,CAGjC,OAGJ,IAAM,EAAW,MAAM,GAAc,CACrC,GAAI,EAAS,SAAW,EACpB,QAAQ,IAAI,0BAA0B,KACnC,CACH,QAAQ,IAAI,YAAY,CACxB,IAAK,IAAM,KAAO,EACd,QAAQ,IAAI,OAAO,IAAM,GAGnC,CAEC,EC5RX,IAAI,EAAgC,KAEpC,SAAS,GAA4B,CAEjC,MADA,CAAS,IAAK,EAAS,gBAAgB,CAAE,MAAO,QAAQ,MAAO,OAAQ,QAAQ,OAAQ,CAAC,CACjF,EAGX,SAAS,GAAgB,CACrB,GAAI,OAAO,CACX,EAAK,KAGT,SAAS,EAAI,EAAmC,CAC5C,OAAO,IAAI,QAAQ,GAAW,GAAO,CAAC,SAAS,EAAU,EAAQ,CAAC,CAGtE,eAAe,EACX,EACA,EACA,EACe,CACf,IAAM,EAAQ,EAAQ,IAAI,OAAO,CACjC,QAAQ,IAAI,OAAO,IAAU,CAC7B,EAAM,SAAS,EAAG,IAAM,CACpB,IAAM,EAAS,IAAM,OAAO,EAAa,CAAG,aAAe,GAC3D,QAAQ,IAAI,OAAO,EAAI,EAAE,IAAI,IAAI,IAAS,EAC5C,CACF,IAAM,EAAS,MAAM,EAAI,aAAa,GAAgB,EAAM,GAAG,KAAK,CACpE,GAAI,CAAC,EAAO,MAAM,CAAE,OAAO,OAAO,GAAgB,EAAM,GAAG,CAC3D,IAAM,EAAM,SAAS,EAAQ,GAAG,CAGhC,OAFI,GAAO,GAAK,GAAO,EAAM,OAAe,EAAM,EAAM,GACpD,EAAM,SAAS,EAAO,MAAM,CAAC,CAAS,EAAO,MAAM,CAChD,OAAO,GAAgB,EAAM,GAAG,CAG3C,eAAe,EAAc,EAAiB,EAA0C,CAEpF,IAAM,EAAS,MAAM,EAAI,KAAK,EAAQ,UAD1B,IAAiB,GAAQ,IAAM,IACS,KAAK,CAEzD,OADK,EAAO,MAAM,CACX,EAAO,MAAM,CAAC,aAAa,CAAC,WAAW,IAAI,CADvB,IAAiB,GAIhD,eAAe,EAAY,EAAiB,EAAyC,CAGjF,OADe,MAAM,EAAI,KAAK,IADf,IAAiB,IAAA,GAAmC,GAAvB,KAAK,EAAa,GACf,IAAI,EACrC,MAAM,EAAI,OAAO,GAAgB,GAAG,CAKtD,SAAS,EAAc,EAAiE,CACpF,MAAO,CAAC,EAAI,MAAM,SAAS,IAAI,EAAI,CAAC,EAAI,SAAS,OAKrD,eAAe,EACX,EACA,EACgB,CAEhB,GADgB,EAAI,OACJ,QAAS,CACrB,IAAM,EAAW,EAAI,SAAW,EAAE,CAC5B,EAAO,EAAQ,OACf,+BAA+B,EAAQ,KAAK,KAAK,CAAC,GAClD,qBACA,EAAa,MAAM,QAAQ,EAAI,aAAa,CAC5C,EAAI,aAAa,KAAK,KAAK,CAC3B,EAAI,eAAiB,IAAA,GAEnB,GADA,OAAO,EAAI,aAAa,CAG1B,GADS,MAAM,EAAI,KAAK,EAAI,cAAc,EAAK,IAAI,EAAW,KAAK,EACtD,MAAM,EAAI,EAC7B,GAAI,CAAC,EAAK,OAAO,EAAQ,OAAS,EAAE,CACpC,IAAM,EAAQ,EACT,MAAM,IAAI,CACV,IAAI,GAAK,EAAE,MAAM,CAAC,CAClB,OAAO,QAAQ,CACpB,OAAO,EAAQ,OAAS,EAAM,OAAO,GAAK,EAAQ,SAAS,EAAE,CAAC,CAAG,EAQrE,OANI,EAAI,SAAS,OACN,EAAa,EAAI,YAAa,EAAI,QAAS,EAAI,aAAa,CAEnE,EAAc,EAAI,CACX,EAAc,EAAI,YAAa,EAAI,aAAa,CAEpD,EAAY,EAAI,YAAa,EAAI,aAAa,CAazD,eAAe,EACX,EACA,EACA,EACa,CACb,OAAa,CACT,IAAM,EAAa,MAAM,EAAO,WAC5B,EACH,CAEG,EAAgB,GAEpB,IAAK,GAAM,CAAC,EAAK,KAAQ,OAAO,QAAQ,EAAW,CAC3C,IAAQ,IAAA,IACR,EAAU,KAAS,IAAA,KAEvB,EAAgB,GAGZ,EAAQ,KAAS,IAAA,GAGjB,EAAU,GAAO,MAAM,EAAgB,EAAK,EAAI,CAFhD,EAAU,GAAO,EAAQ,IAMjC,GAAI,CAAC,EAAe,OAK5B,SAAS,EACL,EACA,EACA,EACoC,CACpC,GAAI,IAAS,QAAS,CAClB,IAAM,EAAQ,EACT,MAAM,IAAI,CACV,IAAI,GAAK,EAAE,MAAM,CAAC,CAClB,OAAO,QAAQ,CAIpB,OAHI,GAAS,OACF,EAAM,OAAO,GAAK,EAAQ,SAAS,EAAE,CAAC,CAE1C,EAIX,OAFI,IAAS,SAAiB,OAAO,EAAM,CACvC,IAAS,UAAkB,IAAU,OAClC,EAQX,SAAS,EACL,EACuB,CACvB,IAAM,EAAkC,EAAE,CACpC,EAAO,CAAC,GAAG,QAAQ,KAAK,CACxB,EAAsB,EAAE,CAG9B,EAAU,KAAK,EAAK,GAAI,EAAK,GAAG,CAEhC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CAClC,IAAM,EAAM,EAAK,GAEb,EAAU,GAEd,IAAK,IAAM,KAAO,EAAM,CACpB,IAAM,EAAY,EAAI,MAAM,MAAM,oBAAoB,CACtD,GAAI,CAAC,EAAW,SAEhB,IAAM,EAAW,EAAU,GACrB,EAAW,KAAK,IAChB,EAAW,QAAQ,IACnB,EAAM,EAAS,QAAQ,aAAc,EAAG,IAAM,EAAE,aAAa,CAAC,CAKpE,GAAI,IAAQ,EAAU,CAClB,EAAO,GAAO,GACd,EAAU,GACV,MAMJ,GAAI,IAAQ,GAAY,EAAI,OAAS,UAAW,CAC5C,EAAO,GAAO,GACd,EAAU,GACV,MAMJ,GAAI,EAAI,WAAW,GAAG,EAAS,GAAG,CAAE,CAChC,IAAM,EAAQ,EAAI,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC,MAAM,CACjD,EAAI,OAAoB,QACzB,EAAO,GAAO,EAAU,QAAS,EAAO,EAAI,QAAgC,CAE5E,EAAO,GAAO,EAAU,EAAI,KAAyC,EAAM,CAE/E,EAAU,GACV,MAMJ,GAAI,IAAQ,GAAY,EAAI,OAAS,UAAW,CAC5C,GAAK,EAAI,OAAoB,QAAS,CAClC,IAAM,EAAsB,EAAE,CAC9B,IAAK,IAAI,EAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACtC,IAAM,EAAO,EAAK,GAElB,GADI,EAAK,WAAW,KAAK,EACrB,EAAI,SAAS,QAAU,CAAE,EAAI,QAAqB,SAAS,EAAK,CAAE,MACtE,EAAU,KAAK,EAAK,CAExB,EAAO,GAAO,EAAI,SAAS,OACrB,EAAU,OAAO,GAAM,EAAI,QAAqB,SAAS,EAAE,CAAC,CAC5D,EACN,GAAK,EAAU,YAEf,EAAO,GAAO,EAAU,EAAI,KAA6B,EAAK,EAAI,GAAG,CACrE,IAEJ,EAAU,GACV,OAIH,GACD,EAAU,KAAK,EAAI,CAI3B,OAAO,EAKX,SAAS,EACL,EACA,EACI,CACJ,IAAM,EAAY,IAAI,EAAkB,EAAI,MAAO,EAAI,YAAY,CAqBnE,GAnBI,EAAI,eAAiB,IAAA,KAEhB,EAAI,OAAoB,SAAW,CAAC,MAAM,QAAQ,EAAI,aAAa,CACpE,EAAU,QAAQ,EAAE,CAAC,CAErB,EAAU,QAAQ,EAAI,aAAa,EAGvC,EAAI,SAAS,QACb,EAAU,QAAQ,EAAI,QAAQ,IAAI,OAAO,CAAC,CAE1C,EAAI,UACJ,EAAU,qBAAqB,CAGnC,EAAI,UAAU,EAAU,CAIpB,EAAI,OAAS,WAAa,EAAc,EAAI,CAAE,CAC9C,IAAM,EAAY,EAAI,MAAM,MAAM,oBAAoB,CACtD,GAAI,EAAW,CACX,IAAM,EAAe,EAAU,GACzB,EAAsB,WAAW,EAAI,YAAY,aAAa,GAC9D,EAAiB,IAAI,EAAkB,QAAQ,IAAgB,EAAoB,CACrF,EAAI,eAAiB,IACrB,EAAe,QAAQ,GAAM,CAEjC,EAAI,UAAU,EAAe,GAUzC,eAAe,EACX,EACA,EACA,EACA,EACA,EACa,CACb,IAAM,EAAM,EACP,QAAQ,EAAY,CACpB,YAAY,EAAY,CACxB,SAAS,SAAU,eAAe,CAClC,OAAO,eAAgB,cAAc,CACrC,OAAO,YAAa,iCAAiC,CACrD,OAAO,aAAc,kCAAkC,CACvD,OAAO,UAAW,2BAA2B,CAC7C,mBAAmB,GAAK,CAGvB,EAA0C,CAAE,KAAM,GAAI,aAAY,CACpE,EAAa,MAAM,EAAO,WAC1B,EACH,CACG,EAAwC,CAAE,GAAG,EAAU,CACvD,EAAe,IAAI,IAEvB,OAAa,CACT,IAAM,EAAc,IAAI,IAAI,OAAO,KAAK,EAAW,CAAC,CAEpD,GADgB,CAAC,GAAG,EAAY,CAAC,OAAO,GAAK,CAAC,EAAa,IAAI,EAAE,CAAC,CACtD,SAAW,EAAG,MAE1B,IAAM,EAAS,EACX,OAAO,OAAO,EAAW,CAC5B,CACD,EAAe,CAAE,GAAG,EAAc,GAAG,EAAQ,CAC7C,EAAe,EAEf,EAAa,MAAM,EAAO,WACtB,EACH,CAGL,IAAK,GAAM,EAAG,KAAQ,OAAO,QAAQ,EAAW,CACxC,IAAQ,IAAA,IACZ,EAAe,EAAK,EAAI,CAG5B,EAAI,OAAO,MAAO,EAAc,IAAqC,CACjE,IAAM,EAAqC,CACvC,OACA,aACA,OAAQ,EAAQ,OAChB,MAAO,EAAQ,MAClB,CAED,MAAM,EAAe,EAAQ,EAAW,EAAQ,CAEhD,GAAS,CACT,MAAM,EAAO,QAAQ,EAAqE,EAC5F,CAKN,eAAsB,EAClB,EACA,EACgB,CAChB,IAAM,EAAS,EAAQ,QAAQ,MAAM,CAAC,YAAY,uCAAuC,CAEnF,EAAY,EAAc,iBAAiB,EAA8B,CAE/E,IAAK,IAAM,KAAQ,EAAW,CAC1B,IAAM,EAAS,EAAc,UAAkC,EAAK,GAAG,CAEvE,GAAI,EAAO,aAAa,OAAQ,CAE5B,IAAM,EAAQ,EACT,QAAQ,EAAO,SAAS,CACxB,YAAY,GAAG,EAAO,SAAS,WAAW,CAE/C,IAAK,IAAM,KAAU,EAAO,YACxB,MAAM,EACF,EACA,EACA,EAAO,KACP,EAAO,YACP,EAAO,KACV,MAIL,MAAM,EACF,EACA,EACA,EAAO,SACP,gBAAgB,EAAO,SAAS,UACnC,CAIT,OAAO,ECvYX,MAAM,EAAkB,MAAM,GAAgB,CAGxC,EAAe,MAAM,GAAc,CAEnC,EAAe,MAAM,QAAQ,IAC/B,EAAa,IAAI,KAAM,IACP,MAAM,EAAkB,EAAK,CAE3C,CACL,CAEK,EAAgB,IAAI,EAC1B,MAAM,EAAc,YAAY,CAAC,GAAG,EAAiB,GAAG,EAAa,CAAC,CACtE,MAAM,EAAc,aAAa,yBAAyB,CAC1D,MAAM,EAAU,IAAI,EACpB,EAAQ,KAAK,cAAc,CAAC,YAAY,uCAAuC,CAE/E,MAAM,EAAmB,EAAS,EAAc,CAChD,MAAM,EAAsB,EAAS,EAAc,CAGnD,EAAQ,UAAU,IAAI,EAAO,oBAAqB,0BAA0B,CAAC,QAAQ,GAAK,CAAC,CAE3F,MAAM,EAAQ,aAAa,CAAC,YAAY"}
|
package/dist/cli/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`fs/promises`);c=s(c);let l=require(`
|
|
2
|
-
`,`utf-8`)}async function
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`fs/promises`);c=s(c);let l=require(`os`);l=s(l);let u=require(`path`);u=s(u);let d=require(`url`);const f=`.lbscaffold.json`,p=u.default.join(l.default.homedir(),f);async function m(e=process.cwd()){let t=e;for(;;){let e=u.default.join(t,f);try{return await c.default.access(e),e}catch{let e=u.default.dirname(t);if(e===t)return null;t=e}}}function h(){return u.default.join(process.cwd(),f)}async function g(e){try{let t=await c.default.readFile(e,`utf-8`);return JSON.parse(t)}catch(t){if(t.code===`ENOENT`)return{};throw Error(`Failed to load config from ${e}: ${t.message}`)}}async function _(e){if(e)return g(e);let t=await g(p),n=await m(),r=n?await g(n):{};return{...t,...r}}async function v(e,t){let n=t??h();await c.default.writeFile(n,JSON.stringify(e,null,2)+`
|
|
2
|
+
`,`utf-8`)}async function y(e){let t=e??h();try{throw await c.default.access(t),Error(`Config file already exists at ${t}`)}catch(e){if(e.code!==`ENOENT`)throw e}return await v({plugins:[`./plugins/**`],packages:[]},t),t}async function b(e,t){let n=t??await m()??h(),r=await g(n);if(r.plugins||=[],r.plugins.includes(e))throw Error(`Plugin pattern '${e}' already exists in config`);r.plugins.push(e),await v(r,n)}async function x(e,t){let n=t??await m();if(!n)throw Error(`No config file found`);let r=await g(n);if(!r.plugins||!r.plugins.includes(e))throw Error(`Plugin pattern '${e}' not found in config`);r.plugins=r.plugins.filter(t=>t!==e),await v(r,n)}async function S(e){return(await _(e)).plugins??[]}function C(e,t){return e.map(e=>u.default.isAbsolute(e)?e.replace(/\\/g,`/`):u.default.resolve(t,e).replace(/\\/g,`/`))}async function w(e){if(e){let t=await g(e),n=u.default.dirname(e);return C(t.plugins??[],n)}let t=await m(),n=t?await g(t):{};return n.plugins?C(n.plugins,u.default.dirname(t)):C((await g(p)).plugins??[],l.default.homedir())}async function T(e,t){let n=t??await m()??h(),r=await g(n);if(r.packages||=[],r.packages.includes(e))throw Error(`Package '${e}' already exists in config`);r.packages.push(e),await v(r,n)}async function E(e,t){let n=t??await m();if(!n)throw Error(`No config file found`);let r=await g(n);if(!r.packages||!r.packages.includes(e))throw Error(`Package '${e}' not found in config`);r.packages=r.packages.filter(t=>t!==e),await v(r,n)}async function D(e){return(await _(e)).packages??[]}async function O(e){try{let t={}.resolve(e),n=u.default.dirname((0,d.fileURLToPath)(t));for(;n!==u.default.dirname(n);)try{return await c.default.access(u.default.join(n,`package.json`)),n}catch{n=u.default.dirname(n)}throw Error(`package.json not found`)}catch{throw Error(`Package '${e}' not found. Install it locally (npm install ${e}) or globally (npm install -g ${e}).`)}}exports.GLOBAL_CONFIG_PATH=p,exports.addPackage=T,exports.addPluginGlob=b,exports.findConfigPath=m,exports.getDefaultConfigPath=h,exports.getPluginPaths=w,exports.initConfig=y,exports.listPackages=D,exports.listPluginGlobs=S,exports.loadConfig=_,exports.loadRawConfig=g,exports.removePackage=E,exports.removePluginGlob=x,exports.resolvePackageDir=O,exports.saveConfig=v;
|
|
3
3
|
//# sourceMappingURL=index.cjs.map
|
package/dist/cli/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["fs","fs"],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold.json';\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load the config file\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n return {};\n }\n\n try {\n const content = await fs.readFile(resolvedPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${resolvedPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Get absolute plugin paths from config globs\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n const resolvedConfigPath = configPath ?? (await findConfigPath());\n\n if (!resolvedConfigPath) {\n return [];\n }\n\n const config = await loadConfig(resolvedConfigPath);\n const configDir = path.dirname(resolvedConfigPath);\n\n return (config.plugins ?? []).map(glob => {\n // If glob is absolute, use as-is; otherwise resolve relative to config file\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Uses import.meta.resolve() to find the package entry point,\n * then walks up to find the package.json — this works regardless\n * of the package's `exports` configuration.\n *\n * Correctly handles:\n * - npm workspaces (hoisted node_modules)\n * - Symlinked packages\n * - Global installs\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n try {\n const entryUrl = import.meta.resolve(packageName);\n let dir = path.dirname(fileURLToPath(entryUrl));\n\n // Walk up until we find the package.json\n while (dir !== path.dirname(dir)) {\n try {\n await fs.access(path.join(dir, 'package.json'));\n return dir;\n } catch {\n dir = path.dirname(dir);\n }\n }\n\n throw new Error('package.json not found');\n } catch {\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["fs","fs"],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport os from 'os';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold.json';\n\nexport const GLOBAL_CONFIG_PATH = path.join(os.homedir(), CONFIG_FILENAME);\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load a single config file from a specific path\n */\nexport async function loadRawConfig(configPath: string): Promise<LbScaffoldConfig> {\n try {\n const content = await fs.readFile(configPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${configPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Load the merged config (global defaults + local overrides).\n * When configPath is provided explicitly, only that file is loaded (no merging).\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n if (configPath) {\n return loadRawConfig(configPath);\n }\n\n const globalConfig = await loadRawConfig(GLOBAL_CONFIG_PATH);\n const localPath = await findConfigPath();\n const localConfig = localPath ? await loadRawConfig(localPath) : {};\n\n // Per-key merge: local keys fully override global keys\n return { ...globalConfig, ...localConfig };\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath()) ?? getDefaultConfigPath();\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Resolve globs from a single config file relative to its directory\n */\nfunction resolveGlobs(globs: string[], configDir: string): string[] {\n return globs.map(glob => {\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Get absolute plugin paths from config globs.\n * When no configPath is given, merges global and local configs:\n * - If local config defines `plugins`, use local only (resolved relative to local config dir)\n * - Otherwise, fall through to global `plugins` (resolved relative to $HOME)\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n if (configPath) {\n const config = await loadRawConfig(configPath);\n const configDir = path.dirname(configPath);\n return resolveGlobs(config.plugins ?? [], configDir);\n }\n\n const localPath = await findConfigPath();\n const localConfig = localPath ? await loadRawConfig(localPath) : {};\n\n // If local defines plugins, use local only\n if (localConfig.plugins) {\n return resolveGlobs(localConfig.plugins, path.dirname(localPath!));\n }\n\n // Fall through to global\n const globalConfig = await loadRawConfig(GLOBAL_CONFIG_PATH);\n return resolveGlobs(globalConfig.plugins ?? [], os.homedir());\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath()) ?? getDefaultConfigPath();\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config.\n * When no configPath is given, uses per-key merge (local `packages` overrides global).\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Uses import.meta.resolve() to find the package entry point,\n * then walks up to find the package.json — this works regardless\n * of the package's `exports` configuration.\n *\n * Correctly handles:\n * - npm workspaces (hoisted node_modules)\n * - Symlinked packages\n * - Global installs\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n try {\n const entryUrl = import.meta.resolve(packageName);\n let dir = path.dirname(fileURLToPath(entryUrl));\n\n // Walk up until we find the package.json\n while (dir !== path.dirname(dir)) {\n try {\n await fs.access(path.join(dir, 'package.json'));\n return dir;\n } catch {\n dir = path.dirname(dir);\n }\n }\n\n throw new Error('package.json not found');\n } catch {\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n }\n}\n"],"mappings":"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"}
|
package/dist/cli/index.d.cts
CHANGED
|
@@ -3,6 +3,7 @@ interface LbScaffoldConfig {
|
|
|
3
3
|
plugins?: string[];
|
|
4
4
|
packages?: string[];
|
|
5
5
|
}
|
|
6
|
+
declare const GLOBAL_CONFIG_PATH: string;
|
|
6
7
|
/**
|
|
7
8
|
* Find the config file by searching up the directory tree
|
|
8
9
|
*/
|
|
@@ -12,7 +13,12 @@ declare function findConfigPath(startDir?: string): Promise<string | null>;
|
|
|
12
13
|
*/
|
|
13
14
|
declare function getDefaultConfigPath(): string;
|
|
14
15
|
/**
|
|
15
|
-
* Load
|
|
16
|
+
* Load a single config file from a specific path
|
|
17
|
+
*/
|
|
18
|
+
declare function loadRawConfig(configPath: string): Promise<LbScaffoldConfig>;
|
|
19
|
+
/**
|
|
20
|
+
* Load the merged config (global defaults + local overrides).
|
|
21
|
+
* When configPath is provided explicitly, only that file is loaded (no merging).
|
|
16
22
|
*/
|
|
17
23
|
declare function loadConfig(configPath?: string): Promise<LbScaffoldConfig>;
|
|
18
24
|
/**
|
|
@@ -36,7 +42,10 @@ declare function removePluginGlob(glob: string, configPath?: string): Promise<vo
|
|
|
36
42
|
*/
|
|
37
43
|
declare function listPluginGlobs(configPath?: string): Promise<string[]>;
|
|
38
44
|
/**
|
|
39
|
-
* Get absolute plugin paths from config globs
|
|
45
|
+
* Get absolute plugin paths from config globs.
|
|
46
|
+
* When no configPath is given, merges global and local configs:
|
|
47
|
+
* - If local config defines `plugins`, use local only (resolved relative to local config dir)
|
|
48
|
+
* - Otherwise, fall through to global `plugins` (resolved relative to $HOME)
|
|
40
49
|
*/
|
|
41
50
|
declare function getPluginPaths(configPath?: string): Promise<string[]>;
|
|
42
51
|
/**
|
|
@@ -48,7 +57,8 @@ declare function addPackage(packageName: string, configPath?: string): Promise<v
|
|
|
48
57
|
*/
|
|
49
58
|
declare function removePackage(packageName: string, configPath?: string): Promise<void>;
|
|
50
59
|
/**
|
|
51
|
-
* List all npm package names in the config
|
|
60
|
+
* List all npm package names in the config.
|
|
61
|
+
* When no configPath is given, uses per-key merge (local `packages` overrides global).
|
|
52
62
|
*/
|
|
53
63
|
declare function listPackages(configPath?: string): Promise<string[]>;
|
|
54
64
|
//#endregion
|
|
@@ -66,5 +76,5 @@ declare function listPackages(configPath?: string): Promise<string[]>;
|
|
|
66
76
|
*/
|
|
67
77
|
declare function resolvePackageDir(packageName: string): Promise<string>;
|
|
68
78
|
//#endregion
|
|
69
|
-
export { LbScaffoldConfig, addPackage, addPluginGlob, findConfigPath, getDefaultConfigPath, getPluginPaths, initConfig, listPackages, listPluginGlobs, loadConfig, removePackage, removePluginGlob, resolvePackageDir, saveConfig };
|
|
79
|
+
export { GLOBAL_CONFIG_PATH, LbScaffoldConfig, addPackage, addPluginGlob, findConfigPath, getDefaultConfigPath, getPluginPaths, initConfig, listPackages, listPluginGlobs, loadConfig, loadRawConfig, removePackage, removePluginGlob, resolvePackageDir, saveConfig };
|
|
70
80
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/cli/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"mappings":";UAIiB,gBAAA;EACb,OAAA;EACA,QAAA;AAAA;AAAA,cAKS,kBAAA;;AAAb;;iBAKsB,cAAA,CAAe,QAAA,YAAmC,OAAA;;;AAAxE;iBAsBgB,oBAAA,CAAA;;;;iBAOM,aAAA,CAAc,UAAA,WAAqB,OAAA,CAAQ,gBAAA;;;;;iBAgB3C,UAAA,CAAW,UAAA,YAAsB,OAAA,CAAQ,gBAAA;;;;iBAgBzC,UAAA,CAAW,MAAA,EAAQ,gBAAA,EAAkB,UAAA,YAAsB,OAAA;;;;iBAQ3D,UAAA,CAAW,UAAA,YAAsB,OAAA;AAxBvD;;;AAAA,iBAgDsB,aAAA,CAAc,IAAA,UAAc,UAAA,YAAsB,OAAA;;;;iBAmBlD,gBAAA,CAAiB,IAAA,UAAc,UAAA,YAAsB,OAAA;;AAnD3E;;iBAuEsB,eAAA,CAAgB,UAAA,YAAsB,OAAA;;;;;;;iBAuBtC,cAAA,CAAe,UAAA,YAAsB,OAAA;AAtF3D;;;AAAA,iBA6GsB,UAAA,CAAW,WAAA,UAAqB,UAAA,YAAsB,OAAA;;AArF5E;;iBAwGsB,aAAA,CAAc,WAAA,UAAqB,UAAA,YAAsB,OAAA;;;;;iBAqBzD,YAAA,CAAa,UAAA,YAAsB,OAAA;;;;AAtOzD;;;;;AAOA;;;;;iBCIsB,iBAAA,CAAkB,WAAA,WAAsB,OAAA"}
|
package/dist/cli/index.d.mts
CHANGED
|
@@ -3,6 +3,7 @@ interface LbScaffoldConfig {
|
|
|
3
3
|
plugins?: string[];
|
|
4
4
|
packages?: string[];
|
|
5
5
|
}
|
|
6
|
+
declare const GLOBAL_CONFIG_PATH: string;
|
|
6
7
|
/**
|
|
7
8
|
* Find the config file by searching up the directory tree
|
|
8
9
|
*/
|
|
@@ -12,7 +13,12 @@ declare function findConfigPath(startDir?: string): Promise<string | null>;
|
|
|
12
13
|
*/
|
|
13
14
|
declare function getDefaultConfigPath(): string;
|
|
14
15
|
/**
|
|
15
|
-
* Load
|
|
16
|
+
* Load a single config file from a specific path
|
|
17
|
+
*/
|
|
18
|
+
declare function loadRawConfig(configPath: string): Promise<LbScaffoldConfig>;
|
|
19
|
+
/**
|
|
20
|
+
* Load the merged config (global defaults + local overrides).
|
|
21
|
+
* When configPath is provided explicitly, only that file is loaded (no merging).
|
|
16
22
|
*/
|
|
17
23
|
declare function loadConfig(configPath?: string): Promise<LbScaffoldConfig>;
|
|
18
24
|
/**
|
|
@@ -36,7 +42,10 @@ declare function removePluginGlob(glob: string, configPath?: string): Promise<vo
|
|
|
36
42
|
*/
|
|
37
43
|
declare function listPluginGlobs(configPath?: string): Promise<string[]>;
|
|
38
44
|
/**
|
|
39
|
-
* Get absolute plugin paths from config globs
|
|
45
|
+
* Get absolute plugin paths from config globs.
|
|
46
|
+
* When no configPath is given, merges global and local configs:
|
|
47
|
+
* - If local config defines `plugins`, use local only (resolved relative to local config dir)
|
|
48
|
+
* - Otherwise, fall through to global `plugins` (resolved relative to $HOME)
|
|
40
49
|
*/
|
|
41
50
|
declare function getPluginPaths(configPath?: string): Promise<string[]>;
|
|
42
51
|
/**
|
|
@@ -48,7 +57,8 @@ declare function addPackage(packageName: string, configPath?: string): Promise<v
|
|
|
48
57
|
*/
|
|
49
58
|
declare function removePackage(packageName: string, configPath?: string): Promise<void>;
|
|
50
59
|
/**
|
|
51
|
-
* List all npm package names in the config
|
|
60
|
+
* List all npm package names in the config.
|
|
61
|
+
* When no configPath is given, uses per-key merge (local `packages` overrides global).
|
|
52
62
|
*/
|
|
53
63
|
declare function listPackages(configPath?: string): Promise<string[]>;
|
|
54
64
|
//#endregion
|
|
@@ -66,5 +76,5 @@ declare function listPackages(configPath?: string): Promise<string[]>;
|
|
|
66
76
|
*/
|
|
67
77
|
declare function resolvePackageDir(packageName: string): Promise<string>;
|
|
68
78
|
//#endregion
|
|
69
|
-
export { LbScaffoldConfig, addPackage, addPluginGlob, findConfigPath, getDefaultConfigPath, getPluginPaths, initConfig, listPackages, listPluginGlobs, loadConfig, removePackage, removePluginGlob, resolvePackageDir, saveConfig };
|
|
79
|
+
export { GLOBAL_CONFIG_PATH, LbScaffoldConfig, addPackage, addPluginGlob, findConfigPath, getDefaultConfigPath, getPluginPaths, initConfig, listPackages, listPluginGlobs, loadConfig, loadRawConfig, removePackage, removePluginGlob, resolvePackageDir, saveConfig };
|
|
70
80
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/cli/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"mappings":";UAIiB,gBAAA;EACb,OAAA;EACA,QAAA;AAAA;AAAA,cAKS,kBAAA;;AAAb;;iBAKsB,cAAA,CAAe,QAAA,YAAmC,OAAA;;;AAAxE;iBAsBgB,oBAAA,CAAA;;;;iBAOM,aAAA,CAAc,UAAA,WAAqB,OAAA,CAAQ,gBAAA;;;;;iBAgB3C,UAAA,CAAW,UAAA,YAAsB,OAAA,CAAQ,gBAAA;;;;iBAgBzC,UAAA,CAAW,MAAA,EAAQ,gBAAA,EAAkB,UAAA,YAAsB,OAAA;;;;iBAQ3D,UAAA,CAAW,UAAA,YAAsB,OAAA;AAxBvD;;;AAAA,iBAgDsB,aAAA,CAAc,IAAA,UAAc,UAAA,YAAsB,OAAA;;;;iBAmBlD,gBAAA,CAAiB,IAAA,UAAc,UAAA,YAAsB,OAAA;;AAnD3E;;iBAuEsB,eAAA,CAAgB,UAAA,YAAsB,OAAA;;;;;;;iBAuBtC,cAAA,CAAe,UAAA,YAAsB,OAAA;AAtF3D;;;AAAA,iBA6GsB,UAAA,CAAW,WAAA,UAAqB,UAAA,YAAsB,OAAA;;AArF5E;;iBAwGsB,aAAA,CAAc,WAAA,UAAqB,UAAA,YAAsB,OAAA;;;;;iBAqBzD,YAAA,CAAa,UAAA,YAAsB,OAAA;;;;AAtOzD;;;;;AAOA;;;;;iBCIsB,iBAAA,CAAkB,WAAA,WAAsB,OAAA"}
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import e from"fs/promises";import t from"path";import{fileURLToPath as
|
|
2
|
-
`,`utf-8`)}async function
|
|
1
|
+
import e from"fs/promises";import t from"os";import n from"path";import{fileURLToPath as r}from"url";const i=`.lbscaffold.json`,a=n.join(t.homedir(),i);async function o(t=process.cwd()){let r=t;for(;;){let t=n.join(r,i);try{return await e.access(t),t}catch{let e=n.dirname(r);if(e===r)return null;r=e}}}function s(){return n.join(process.cwd(),i)}async function c(t){try{let n=await e.readFile(t,`utf-8`);return JSON.parse(n)}catch(e){if(e.code===`ENOENT`)return{};throw Error(`Failed to load config from ${t}: ${e.message}`)}}async function l(e){if(e)return c(e);let t=await c(a),n=await o(),r=n?await c(n):{};return{...t,...r}}async function u(t,n){let r=n??s();await e.writeFile(r,JSON.stringify(t,null,2)+`
|
|
2
|
+
`,`utf-8`)}async function d(t){let n=t??s();try{throw await e.access(n),Error(`Config file already exists at ${n}`)}catch(e){if(e.code!==`ENOENT`)throw e}return await u({plugins:[`./plugins/**`],packages:[]},n),n}async function f(e,t){let n=t??await o()??s(),r=await c(n);if(r.plugins||=[],r.plugins.includes(e))throw Error(`Plugin pattern '${e}' already exists in config`);r.plugins.push(e),await u(r,n)}async function p(e,t){let n=t??await o();if(!n)throw Error(`No config file found`);let r=await c(n);if(!r.plugins||!r.plugins.includes(e))throw Error(`Plugin pattern '${e}' not found in config`);r.plugins=r.plugins.filter(t=>t!==e),await u(r,n)}async function m(e){return(await l(e)).plugins??[]}function h(e,t){return e.map(e=>n.isAbsolute(e)?e.replace(/\\/g,`/`):n.resolve(t,e).replace(/\\/g,`/`))}async function g(e){if(e){let t=await c(e),r=n.dirname(e);return h(t.plugins??[],r)}let r=await o(),i=r?await c(r):{};return i.plugins?h(i.plugins,n.dirname(r)):h((await c(a)).plugins??[],t.homedir())}async function _(e,t){let n=t??await o()??s(),r=await c(n);if(r.packages||=[],r.packages.includes(e))throw Error(`Package '${e}' already exists in config`);r.packages.push(e),await u(r,n)}async function v(e,t){let n=t??await o();if(!n)throw Error(`No config file found`);let r=await c(n);if(!r.packages||!r.packages.includes(e))throw Error(`Package '${e}' not found in config`);r.packages=r.packages.filter(t=>t!==e),await u(r,n)}async function y(e){return(await l(e)).packages??[]}async function b(t){try{let i=import.meta.resolve(t),a=n.dirname(r(i));for(;a!==n.dirname(a);)try{return await e.access(n.join(a,`package.json`)),a}catch{a=n.dirname(a)}throw Error(`package.json not found`)}catch{throw Error(`Package '${t}' not found. Install it locally (npm install ${t}) or globally (npm install -g ${t}).`)}}export{a as GLOBAL_CONFIG_PATH,_ as addPackage,f as addPluginGlob,o as findConfigPath,s as getDefaultConfigPath,g as getPluginPaths,d as initConfig,y as listPackages,m as listPluginGlobs,l as loadConfig,c as loadRawConfig,v as removePackage,p as removePluginGlob,b as resolvePackageDir,u as saveConfig};
|
|
3
3
|
//# sourceMappingURL=index.mjs.map
|
package/dist/cli/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold.json';\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load the config file\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n return {};\n }\n\n try {\n const content = await fs.readFile(resolvedPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${resolvedPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Get absolute plugin paths from config globs\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n const resolvedConfigPath = configPath ?? (await findConfigPath());\n\n if (!resolvedConfigPath) {\n return [];\n }\n\n const config = await loadConfig(resolvedConfigPath);\n const configDir = path.dirname(resolvedConfigPath);\n\n return (config.plugins ?? []).map(glob => {\n // If glob is absolute, use as-is; otherwise resolve relative to config file\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const config = await loadConfig(configPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, configPath ?? (await findConfigPath()) ?? getDefaultConfigPath());\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Uses import.meta.resolve() to find the package entry point,\n * then walks up to find the package.json — this works regardless\n * of the package's `exports` configuration.\n *\n * Correctly handles:\n * - npm workspaces (hoisted node_modules)\n * - Symlinked packages\n * - Global installs\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n try {\n const entryUrl = import.meta.resolve(packageName);\n let dir = path.dirname(fileURLToPath(entryUrl));\n\n // Walk up until we find the package.json\n while (dir !== path.dirname(dir)) {\n try {\n await fs.access(path.join(dir, 'package.json'));\n return dir;\n } catch {\n dir = path.dirname(dir);\n }\n }\n\n throw new Error('package.json not found');\n } catch {\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n }\n}\n"],"mappings":"mFAQA,MAAM,EAAkB,mBAKxB,eAAsB,EAAe,EAAmB,QAAQ,KAAK,CAA0B,CAC3F,IAAI,EAAa,EAEjB,OAAa,CACT,IAAM,EAAa,EAAK,KAAK,EAAY,EAAgB,CACzD,GAAI,CAEA,OADA,MAAM,EAAG,OAAO,EAAW,CACpB,OACH,CACJ,IAAM,EAAY,EAAK,QAAQ,EAAW,CAC1C,GAAI,IAAc,EAEd,OAAO,KAEX,EAAa,IAQzB,SAAgB,GAA+B,CAC3C,OAAO,EAAK,KAAK,QAAQ,KAAK,CAAE,EAAgB,CAMpD,eAAsB,EAAW,EAAgD,CAC7E,IAAM,EAAe,GAAe,MAAM,GAAgB,CAE1D,GAAI,CAAC,EACD,MAAO,EAAE,CAGb,GAAI,CACA,IAAM,EAAU,MAAM,EAAG,SAAS,EAAc,QAAQ,CACxD,OAAO,KAAK,MAAM,EAAQ,OACrB,EAAO,CACZ,GAAK,EAAgC,OAAS,SAC1C,MAAO,EAAE,CAEb,MAAU,MAAM,8BAA8B,EAAa,IAAK,EAAgB,UAAU,EAOlG,eAAsB,EAAW,EAA0B,EAAoC,CAC3F,IAAM,EAAe,GAAc,GAAsB,CACzD,MAAM,EAAG,UAAU,EAAc,KAAK,UAAU,EAAQ,KAAM,EAAE,CAAG;EAAM,QAAQ,CAMrF,eAAsB,EAAW,EAAsC,CACnE,IAAM,EAAe,GAAc,GAAsB,CAEzD,GAAI,CAEA,MADA,MAAM,EAAG,OAAO,EAAa,CACnB,MAAM,iCAAiC,IAAe,OAC3D,EAAO,CACZ,GAAK,EAAgC,OAAS,SAC1C,MAAM,EAUd,OADA,MAAM,EALkC,CACpC,QAAS,CAAC,eAAe,CACzB,SAAU,EAAE,CACf,CAE+B,EAAa,CACtC,EAMX,eAAsB,EAAc,EAAc,EAAoC,CAClF,IAAM,EAAS,MAAM,EAAW,EAAW,CAM3C,GAJA,AACI,EAAO,UAAU,EAAE,CAGnB,EAAO,QAAQ,SAAS,EAAK,CAC7B,MAAU,MAAM,mBAAmB,EAAK,4BAA4B,CAGxE,EAAO,QAAQ,KAAK,EAAK,CACzB,MAAM,EAAW,EAAQ,GAAe,MAAM,GAAgB,EAAK,GAAsB,CAAC,CAM9F,eAAsB,EAAiB,EAAc,EAAoC,CACrF,IAAM,EAAe,GAAe,MAAM,GAAgB,CAE1D,GAAI,CAAC,EACD,MAAU,MAAM,uBAAuB,CAG3C,IAAM,EAAS,MAAM,EAAW,EAAa,CAE7C,GAAI,CAAC,EAAO,SAAW,CAAC,EAAO,QAAQ,SAAS,EAAK,CACjD,MAAU,MAAM,mBAAmB,EAAK,uBAAuB,CAGnE,EAAO,QAAU,EAAO,QAAQ,OAAO,GAAK,IAAM,EAAK,CACvD,MAAM,EAAW,EAAQ,EAAa,CAM1C,eAAsB,EAAgB,EAAwC,CAE1E,OADe,MAAM,EAAW,EAAW,EAC7B,SAAW,EAAE,CAM/B,eAAsB,EAAe,EAAwC,CACzE,IAAM,EAAqB,GAAe,MAAM,GAAgB,CAEhE,GAAI,CAAC,EACD,MAAO,EAAE,CAGb,IAAM,EAAS,MAAM,EAAW,EAAmB,CAC7C,EAAY,EAAK,QAAQ,EAAmB,CAElD,OAAQ,EAAO,SAAW,EAAE,EAAE,IAAI,GAE1B,EAAK,WAAW,EAAK,CACd,EAAK,QAAQ,MAAO,IAAI,CAE5B,EAAK,QAAQ,EAAW,EAAK,CAAC,QAAQ,MAAO,IAAI,CAC1D,CAMN,eAAsB,EAAW,EAAqB,EAAoC,CACtF,IAAM,EAAS,MAAM,EAAW,EAAW,CAM3C,GAJA,AACI,EAAO,WAAW,EAAE,CAGpB,EAAO,SAAS,SAAS,EAAY,CACrC,MAAU,MAAM,YAAY,EAAY,4BAA4B,CAGxE,EAAO,SAAS,KAAK,EAAY,CACjC,MAAM,EAAW,EAAQ,GAAe,MAAM,GAAgB,EAAK,GAAsB,CAAC,CAM9F,eAAsB,EAAc,EAAqB,EAAoC,CACzF,IAAM,EAAe,GAAe,MAAM,GAAgB,CAE1D,GAAI,CAAC,EACD,MAAU,MAAM,uBAAuB,CAG3C,IAAM,EAAS,MAAM,EAAW,EAAa,CAE7C,GAAI,CAAC,EAAO,UAAY,CAAC,EAAO,SAAS,SAAS,EAAY,CAC1D,MAAU,MAAM,YAAY,EAAY,uBAAuB,CAGnE,EAAO,SAAW,EAAO,SAAS,OAAO,GAAK,IAAM,EAAY,CAChE,MAAM,EAAW,EAAQ,EAAa,CAM1C,eAAsB,EAAa,EAAwC,CAEvE,OADe,MAAM,EAAW,EAAW,EAC7B,UAAY,EAAE,CC5LhC,eAAsB,EAAkB,EAAsC,CAC1E,GAAI,CACA,IAAM,EAAW,OAAO,KAAK,QAAQ,EAAY,CAC7C,EAAM,EAAK,QAAQ,EAAc,EAAS,CAAC,CAG/C,KAAO,IAAQ,EAAK,QAAQ,EAAI,EAC5B,GAAI,CAEA,OADA,MAAM,EAAG,OAAO,EAAK,KAAK,EAAK,eAAe,CAAC,CACxC,OACH,CACJ,EAAM,EAAK,QAAQ,EAAI,CAI/B,MAAU,MAAM,yBAAyB,MACrC,CACJ,MAAU,MACN,YAAY,EAAY,+CACe,EAAY,gCAAgC,EAAY,IAClG"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/config.ts","../../src/utils/resolve-package.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport os from 'os';\nimport path from 'path';\n\nexport interface LbScaffoldConfig {\n plugins?: string[];\n packages?: string[];\n}\n\nconst CONFIG_FILENAME = '.lbscaffold.json';\n\nexport const GLOBAL_CONFIG_PATH = path.join(os.homedir(), CONFIG_FILENAME);\n\n/**\n * Find the config file by searching up the directory tree\n */\nexport async function findConfigPath(startDir: string = process.cwd()): Promise<string | null> {\n let currentDir = startDir;\n\n while (true) {\n const configPath = path.join(currentDir, CONFIG_FILENAME);\n try {\n await fs.access(configPath);\n return configPath;\n } catch {\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) {\n // Reached root\n return null;\n }\n currentDir = parentDir;\n }\n }\n}\n\n/**\n * Get the default config path in the current directory\n */\nexport function getDefaultConfigPath(): string {\n return path.join(process.cwd(), CONFIG_FILENAME);\n}\n\n/**\n * Load a single config file from a specific path\n */\nexport async function loadRawConfig(configPath: string): Promise<LbScaffoldConfig> {\n try {\n const content = await fs.readFile(configPath, 'utf-8');\n return JSON.parse(content) as LbScaffoldConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {};\n }\n throw new Error(`Failed to load config from ${configPath}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Load the merged config (global defaults + local overrides).\n * When configPath is provided explicitly, only that file is loaded (no merging).\n */\nexport async function loadConfig(configPath?: string): Promise<LbScaffoldConfig> {\n if (configPath) {\n return loadRawConfig(configPath);\n }\n\n const globalConfig = await loadRawConfig(GLOBAL_CONFIG_PATH);\n const localPath = await findConfigPath();\n const localConfig = localPath ? await loadRawConfig(localPath) : {};\n\n // Per-key merge: local keys fully override global keys\n return { ...globalConfig, ...localConfig };\n}\n\n/**\n * Save the config file\n */\nexport async function saveConfig(config: LbScaffoldConfig, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n await fs.writeFile(resolvedPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Initialize a new config file\n */\nexport async function initConfig(configPath?: string): Promise<string> {\n const resolvedPath = configPath ?? getDefaultConfigPath();\n\n try {\n await fs.access(resolvedPath);\n throw new Error(`Config file already exists at ${resolvedPath}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n\n const defaultConfig: LbScaffoldConfig = {\n plugins: ['./plugins/**'],\n packages: [],\n };\n\n await saveConfig(defaultConfig, resolvedPath);\n return resolvedPath;\n}\n\n/**\n * Add a plugin glob pattern to the config\n */\nexport async function addPluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath()) ?? getDefaultConfigPath();\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.plugins) {\n config.plugins = [];\n }\n\n if (config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' already exists in config`);\n }\n\n config.plugins.push(glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * Remove a plugin glob pattern from the config\n */\nexport async function removePluginGlob(glob: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.plugins || !config.plugins.includes(glob)) {\n throw new Error(`Plugin pattern '${glob}' not found in config`);\n }\n\n config.plugins = config.plugins.filter(p => p !== glob);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all plugin glob patterns in the config\n */\nexport async function listPluginGlobs(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.plugins ?? [];\n}\n\n/**\n * Resolve globs from a single config file relative to its directory\n */\nfunction resolveGlobs(globs: string[], configDir: string): string[] {\n return globs.map(glob => {\n if (path.isAbsolute(glob)) {\n return glob.replace(/\\\\/g, '/');\n }\n return path.resolve(configDir, glob).replace(/\\\\/g, '/');\n });\n}\n\n/**\n * Get absolute plugin paths from config globs.\n * When no configPath is given, merges global and local configs:\n * - If local config defines `plugins`, use local only (resolved relative to local config dir)\n * - Otherwise, fall through to global `plugins` (resolved relative to $HOME)\n */\nexport async function getPluginPaths(configPath?: string): Promise<string[]> {\n if (configPath) {\n const config = await loadRawConfig(configPath);\n const configDir = path.dirname(configPath);\n return resolveGlobs(config.plugins ?? [], configDir);\n }\n\n const localPath = await findConfigPath();\n const localConfig = localPath ? await loadRawConfig(localPath) : {};\n\n // If local defines plugins, use local only\n if (localConfig.plugins) {\n return resolveGlobs(localConfig.plugins, path.dirname(localPath!));\n }\n\n // Fall through to global\n const globalConfig = await loadRawConfig(GLOBAL_CONFIG_PATH);\n return resolveGlobs(globalConfig.plugins ?? [], os.homedir());\n}\n\n/**\n * Add an npm package name to the config\n */\nexport async function addPackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath()) ?? getDefaultConfigPath();\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.packages) {\n config.packages = [];\n }\n\n if (config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' already exists in config`);\n }\n\n config.packages.push(packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * Remove an npm package name from the config\n */\nexport async function removePackage(packageName: string, configPath?: string): Promise<void> {\n const resolvedPath = configPath ?? (await findConfigPath());\n\n if (!resolvedPath) {\n throw new Error('No config file found');\n }\n\n const config = await loadRawConfig(resolvedPath);\n\n if (!config.packages || !config.packages.includes(packageName)) {\n throw new Error(`Package '${packageName}' not found in config`);\n }\n\n config.packages = config.packages.filter(p => p !== packageName);\n await saveConfig(config, resolvedPath);\n}\n\n/**\n * List all npm package names in the config.\n * When no configPath is given, uses per-key merge (local `packages` overrides global).\n */\nexport async function listPackages(configPath?: string): Promise<string[]> {\n const config = await loadConfig(configPath);\n return config.packages ?? [];\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\n/**\n * Resolve an npm package name to its installed root directory.\n * Uses import.meta.resolve() to find the package entry point,\n * then walks up to find the package.json — this works regardless\n * of the package's `exports` configuration.\n *\n * Correctly handles:\n * - npm workspaces (hoisted node_modules)\n * - Symlinked packages\n * - Global installs\n */\nexport async function resolvePackageDir(packageName: string): Promise<string> {\n try {\n const entryUrl = import.meta.resolve(packageName);\n let dir = path.dirname(fileURLToPath(entryUrl));\n\n // Walk up until we find the package.json\n while (dir !== path.dirname(dir)) {\n try {\n await fs.access(path.join(dir, 'package.json'));\n return dir;\n } catch {\n dir = path.dirname(dir);\n }\n }\n\n throw new Error('package.json not found');\n } catch {\n throw new Error(\n `Package '${packageName}' not found. ` +\n `Install it locally (npm install ${packageName}) or globally (npm install -g ${packageName}).`\n );\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libria/scaffold",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "A pluggable CLI that transforms blank directories into production-ready codebases in seconds",
|
|
5
5
|
"main": "dist/cli/index.cjs",
|
|
6
6
|
"module": "dist/cli/index.mjs",
|
|
@@ -36,17 +36,17 @@
|
|
|
36
36
|
"homepage": "https://github.com/LibriaForge/scaffold#readme",
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@libria/plugin-loader": "^2.1.0",
|
|
39
|
-
"@libria/scaffold-core": "^0.3.
|
|
39
|
+
"@libria/scaffold-core": "^0.3.7",
|
|
40
40
|
"commander": "^14.0.3",
|
|
41
41
|
"fast-glob": "^3.3.3",
|
|
42
42
|
"fs-extra": "^11.3.3",
|
|
43
43
|
"interactive-commander": "^0.6.0"
|
|
44
44
|
},
|
|
45
45
|
"optionalDependencies": {
|
|
46
|
-
"@libria/scaffold-plugin-angular": "^0.0.
|
|
47
|
-
"@libria/scaffold-plugin-nestjs": "^0.0.
|
|
48
|
-
"@libria/scaffold-plugin-nextjs": "^0.0.
|
|
49
|
-
"@libria/scaffold-plugin-ts-lib": "^0.0.
|
|
50
|
-
"@libria/scaffold-plugin-ts-workspace": "^0.0.
|
|
46
|
+
"@libria/scaffold-plugin-angular": "^0.0.6",
|
|
47
|
+
"@libria/scaffold-plugin-nestjs": "^0.0.5",
|
|
48
|
+
"@libria/scaffold-plugin-nextjs": "^0.0.3",
|
|
49
|
+
"@libria/scaffold-plugin-ts-lib": "^0.0.7",
|
|
50
|
+
"@libria/scaffold-plugin-ts-workspace": "^0.0.6"
|
|
51
51
|
}
|
|
52
52
|
}
|