@pixpilot/scaffoldfy 0.23.0 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # @pixpilot/scaffoldfy
2
2
 
3
+ [![Documentation](https://img.shields.io/badge/docs-pixpilot.github.io/scaffoldfy-blue)](https://pixpilot.github.io/scaffoldfy/)
4
+
3
5
  A flexible and powerful task automation utility for project setup, cleanup, and configuration.
4
6
 
5
7
  ## Features
6
8
 
7
- - 🔄 **9 Task Types** - update-json, write, regex-replace, replace-in-file, delete, conditional-delete, rename, git-init, exec
9
+ - 🔄 **13 Task Types** - update-json, template, create, regex-replace, replace-in-file, delete, rename, move, copy, append, mkdir, git-init, exec
8
10
  - 🧩 **Template Inheritance** - Extend base templates for code reuse
9
11
  - 🔍 **Dry-Run Mode with Diff** - Preview exact changes before applying
10
12
  - 🔌 **Plugin System** - Create custom task types and lifecycle hooks
@@ -34,14 +36,8 @@ scaffoldfy
34
36
  # With custom tasks file
35
37
  scaffoldfy --tasks-file ./my-tasks.json
36
38
 
37
- # TypeScript tasks file
38
- scaffoldfy --tasks-ts ./my-tasks.ts
39
-
40
39
  # Preview changes (dry run)
41
40
  scaffoldfy --dry-run
42
-
43
- # Force re-initialization
44
- scaffoldfy --force
45
41
  ```
46
42
 
47
43
  Or run without installing using npx:
@@ -53,14 +49,8 @@ npx @pixpilot/scaffoldfy
53
49
  # With custom tasks file
54
50
  npx @pixpilot/scaffoldfy --tasks-file ./my-tasks.json
55
51
 
56
- # TypeScript tasks file
57
- npx @pixpilot/scaffoldfy --tasks-ts ./my-tasks.ts
58
-
59
52
  # Preview changes (dry run)
60
53
  npx @pixpilot/scaffoldfy --dry-run
61
-
62
- # Force re-initialization
63
- npx @pixpilot/scaffoldfy --force
64
54
  ```
65
55
 
66
56
  ### CLI Options
@@ -70,7 +60,6 @@ npx @pixpilot/scaffoldfy --force
70
60
  | `--tasks-file <path>` | Path to JSON task file (default: `./template-tasks.json`) |
71
61
  | `--tasks-ts <path>` | Path to TypeScript task file (default: `./template-tasks.ts`) |
72
62
  | `--dry-run` | Preview changes without applying them |
73
- | `--force` | Force re-initialization |
74
63
  | `--no-validate` | Skip schema validation of task configuration (validation is enabled by default) |
75
64
  | `-h, --help` | Show help message |
76
65
  | `-v, --version` | Show version |
@@ -89,36 +78,38 @@ await runWithTasks(tasks, {
89
78
 
90
79
  ### Task Types
91
80
 
92
- 9 built-in task types for common operations:
93
-
94
- | Type | Purpose |
95
- | -------------------- | -------------------------------------------------- |
96
- | `update-json` | Update JSON files (supports nested properties) |
97
- | `template` | Create files from templates (simple or Handlebars) |
98
- | `regex-replace` | Find and replace with regex |
99
- | `replace-in-file` | Simple find and replace |
100
- | `delete` | Remove files/directories |
101
- | `conditional-delete` | Remove based on conditions |
102
- | `rename` | Rename or move files |
103
- | `git-init` | Initialize git repository |
104
- | `exec` | Execute shell commands |
81
+ 13 built-in task types for common operations:
82
+
83
+ | Type | Purpose |
84
+ | ----------------- | -------------------------------------------------- |
85
+ | `update-json` | Update JSON files (supports nested properties) |
86
+ | `template` | Create files from templates (simple or Handlebars) |
87
+ | `create` | Create new files with optional content |
88
+ | `regex-replace` | Find and replace with regex |
89
+ | `replace-in-file` | Simple find and replace |
90
+ | `delete` | Remove files/directories |
91
+ | `rename` | Rename or move files |
92
+ | `move` | Move files or directories |
93
+ | `copy` | Copy files or directories |
94
+ | `append` | Append content to existing files |
95
+ | `mkdir` | Create directories |
96
+ | `git-init` | Initialize git repository |
97
+ | `exec` | Execute shell commands |
105
98
 
106
99
  📖 **[Complete Task Types Reference →](https://pixpilot.github.io/scaffoldfy/TASK_TYPES.html)**
107
100
 
108
101
  ### Interactive Prompts
109
102
 
110
- Collect custom user input directly in your task definitions:
103
+ Collect user input at the root level - prompts are collected once before tasks run and available to all tasks:
111
104
 
112
105
  ```json
113
106
  {
114
- "id": "setup",
115
107
  "prompts": [
116
108
  {
117
109
  "id": "projectName",
118
110
  "type": "input",
119
111
  "message": "What is your project name?",
120
- "required": true,
121
- "global": true
112
+ "required": true
122
113
  },
123
114
  {
124
115
  "id": "useTypeScript",
@@ -127,38 +118,72 @@ Collect custom user input directly in your task definitions:
127
118
  "default": true
128
119
  }
129
120
  ],
130
- "config": {
131
- "file": "package.json",
132
- "updates": {
133
- "name": "{{projectName}}"
121
+ "tasks": [
122
+ {
123
+ "id": "setup",
124
+ "name": "Setup Project",
125
+ "type": "update-json",
126
+ "config": {
127
+ "file": "package.json",
128
+ "updates": {
129
+ "name": "{{projectName}}"
130
+ }
131
+ }
134
132
  }
135
- }
133
+ ]
136
134
  }
137
135
  ```
138
136
 
139
137
  **Supported prompt types:** `input`, `password`, `number`, `select`, `confirm`
140
138
 
141
- **Global prompts:** Mark prompts with `"global": true` to share values across all tasks
139
+ **Root-level only:** Prompts are defined at the root level, collected once upfront, and available to all tasks
142
140
 
143
141
  💬 **[Full Prompts Guide →](https://pixpilot.github.io/scaffoldfy/PROMPTS.html)** | 📋 **[Quick Reference →](https://pixpilot.github.io/scaffoldfy/PROMPTS_QUICK_REFERENCE.html)**
144
142
 
145
- ### Template Variables
143
+ ### Variables
146
144
 
147
- Use `{{variable}}` syntax anywhere in your task configs:
145
+ Define reusable values without user interaction - automatically resolved from static values or executable commands:
148
146
 
149
147
  ```json
150
148
  {
151
- "updates": {
152
- "name": "{{projectName}}",
153
- "author": "{{author}}",
154
- "repository": "{{repoUrl}}"
155
- }
149
+ "variables": [
150
+ {
151
+ "id": "currentYear",
152
+ "value": {
153
+ "type": "exec",
154
+ "value": "node -e \"console.log(new Date().getFullYear())\""
155
+ }
156
+ },
157
+ {
158
+ "id": "gitUserName",
159
+ "value": {
160
+ "type": "exec",
161
+ "value": "git config user.name"
162
+ }
163
+ },
164
+ {
165
+ "id": "defaultLicense",
166
+ "value": "MIT"
167
+ }
168
+ ],
169
+ "tasks": [
170
+ {
171
+ "id": "update-license",
172
+ "type": "template",
173
+ "config": {
174
+ "file": "LICENSE",
175
+ "template": "Copyright {{currentYear}} {{gitUserName}}\n\nLicense: {{defaultLicense}}"
176
+ }
177
+ }
178
+ ]
156
179
  }
157
180
  ```
158
181
 
159
- **All variables come from prompts:** Define prompts with `"global": true` to create variables available across all tasks.
182
+ **Use in tasks:** Reference variables using `{{variable}}` syntax: `{{currentYear}}`, `{{gitUserName}}`, `{{defaultLicense}}`
160
183
 
161
- **Example:** `{{projectName}}`, `{{author}}`, `{{repoUrl}}`, `{{port}}`, etc.
184
+ **Variable types:** Static values, executable commands (with auto-parsing), or conditional expressions
185
+
186
+ 📌 **[Complete Variables Guide →](https://pixpilot.github.io/scaffoldfy/VARIABLES.html)**
162
187
 
163
188
  ### Handlebars Templates
164
189
 
@@ -292,63 +317,96 @@ Control execution order:
292
317
 
293
318
  ## Example Configuration
294
319
 
295
- ### Simple Example
320
+ ### Complete Example with Prompts and Variables
296
321
 
297
322
  ```json
298
323
  {
324
+ "prompts": [
325
+ {
326
+ "id": "projectName",
327
+ "type": "input",
328
+ "message": "What is your project name?",
329
+ "required": true
330
+ },
331
+ {
332
+ "id": "author",
333
+ "type": "input",
334
+ "message": "Who is the author?",
335
+ "default": {
336
+ "type": "exec",
337
+ "value": "git config user.name"
338
+ }
339
+ },
340
+ {
341
+ "id": "useTypeScript",
342
+ "type": "confirm",
343
+ "message": "Use TypeScript?",
344
+ "default": true
345
+ }
346
+ ],
347
+ "variables": [
348
+ {
349
+ "id": "currentYear",
350
+ "value": {
351
+ "type": "exec",
352
+ "value": "node -e \"console.log(new Date().getFullYear())\""
353
+ }
354
+ },
355
+ {
356
+ "id": "license",
357
+ "value": "MIT"
358
+ }
359
+ ],
299
360
  "tasks": [
300
361
  {
301
362
  "id": "update-package",
302
363
  "name": "Update package.json",
303
- "description": "Update repository information",
304
- "required": true,
305
- "enabled": true,
364
+ "description": "Set project metadata",
306
365
  "type": "update-json",
307
366
  "config": {
308
367
  "file": "package.json",
309
368
  "updates": {
310
369
  "name": "{{projectName}}",
311
- "author": "{{author}}"
370
+ "author": "{{author}}",
371
+ "license": "{{license}}"
312
372
  }
313
373
  }
374
+ },
375
+ {
376
+ "id": "create-readme",
377
+ "name": "Create README",
378
+ "description": "Generate README file",
379
+ "type": "template",
380
+ "config": {
381
+ "file": "README.md",
382
+ "template": "# {{projectName}}\n\nAuthor: {{author}}\nCopyright {{currentYear}}"
383
+ }
314
384
  }
315
385
  ]
316
386
  }
317
387
  ```
318
388
 
319
- ### With Prompts
389
+ ### Simple Example
320
390
 
321
391
  ```json
322
392
  {
393
+ "prompts": [
394
+ {
395
+ "id": "projectName",
396
+ "type": "input",
397
+ "message": "Project name?",
398
+ "required": true
399
+ }
400
+ ],
323
401
  "tasks": [
324
402
  {
325
- "id": "setup-project",
326
- "name": "Setup Project",
327
- "description": "Configure project settings",
328
- "required": true,
329
- "enabled": true,
403
+ "id": "update-package",
404
+ "name": "Update package.json",
330
405
  "type": "update-json",
331
- "prompts": [
332
- {
333
- "id": "projectName",
334
- "type": "input",
335
- "message": "Project name?",
336
- "required": true
337
- },
338
- {
339
- "id": "includeTests",
340
- "type": "confirm",
341
- "message": "Include tests?",
342
- "default": true
343
- }
344
- ],
345
406
  "config": {
346
407
  "file": "package.json",
347
408
  "updates": {
348
- "name": "{{projectName}}",
349
- "scripts": {
350
- "test": "{{includeTests ? 'vitest' : 'echo \"No tests\"'}}"
351
- }
409
+ "name": "{{projectName}}"
352
410
  }
353
411
  }
354
412
  }
@@ -365,7 +423,7 @@ Control execution order:
365
423
  ### Quick Links
366
424
 
367
425
  - **[Getting Started](https://pixpilot.github.io/scaffoldfy/GETTING_STARTED.html)** - Installation, CLI usage, and examples
368
- - **[Task Types Reference](https://pixpilot.github.io/scaffoldfy/TASK_TYPES.html)** - All 9 built-in task types
426
+ - **[Task Types Reference](https://pixpilot.github.io/scaffoldfy/TASK_TYPES.html)** - All 13 built-in task types
369
427
  - **[Interactive Prompts](https://pixpilot.github.io/scaffoldfy/PROMPTS.html)** - Collect user input
370
428
  - **[Variables](https://pixpilot.github.io/scaffoldfy/VARIABLES.html)** - Reusable values without user interaction
371
429
  - **[Advanced Features](https://pixpilot.github.io/scaffoldfy/FEATURES.html)** - Conditional execution, global prompts, Handlebars
package/dist/cli.cjs CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- const e=require(`./utils-CdfjwUZm.cjs`),t=require(`./src-C2AFidMo.cjs`);let n=require(`node:fs`);n=e._(n);let r=require(`node:path`);r=e._(r);let i=require(`node:process`);i=e._(i);let a=require(`commander`);a=e._(a);let o=require(`node:url`);o=e._(o);let s=require(`ajv`);s=e._(s);const c=1,l=(0,o.fileURLToPath)(require(`url`).pathToFileURL(__filename).href),u=r.default.dirname(l);function d(){return new s.default({allErrors:!0,verbose:!0,strict:!1,discriminator:!0})}function f(){let e=r.default.join(u,`..`,`schema`,`tasks.schema.json`);try{let t=n.default.readFileSync(e,`utf-8`);return JSON.parse(t)}catch(t){throw Error(`Failed to load tasks schema from ${e}: ${t instanceof Error?t.message:String(t)}`)}}function p(e){return e.filter(t=>{if(t.keyword===`oneOf`){let e=t.params;if(e.passingSchemas&&e.passingSchemas.length>0)return!1}if(t.keyword===`required`){let n=e.find(e=>e.keyword===`oneOf`&&e.instancePath===t.instancePath);if(n){let e=n.params;if(e.passingSchemas&&e.passingSchemas.length>0)return!1}}return!0}).map(e=>{let t=e.instancePath||`root`,n=e.message??`Unknown error`;switch(e.keyword){case`required`:return`${t}: Missing required property "${String(e.params.missingProperty??`unknown`)}"`;case`type`:return`${t}: Expected type "${String(e.params.type??`unknown`)}", received "${typeof e.data}"`;case`enum`:{let r=e.params.allowedValues;return`${t}: ${n}. Allowed values: ${Array.isArray(r)?r.join(`, `):String(r)}`}case`pattern`:{let{pattern:r}=e.params;return`${t}: ${n}. Value must match pattern: ${String(r)}`}case`oneOf`:return`${t}: ${n}. Configuration must match exactly one of the allowed schemas`;case`additionalProperties`:return`${t}: ${n}. Unknown property: "${String(e.params.additionalProperty??`unknown`)}"`;default:return`${t}: ${n}`}})}function m(t,n={}){try{let e=d(),r=f(),i=e.compile(r);if(!i(t)&&i.errors){let e=p(i.errors);return e.length===0?{valid:!0,errors:[]}:(n.silent||h(e),{valid:!1,errors:e})}return{valid:!0,errors:[]}}catch(t){let r=t instanceof Error?t.message:`Unknown error occurred during schema validation`;return n.silent||(e.i(`❌ Schema validation error:`,`error`),e.i(` ${r}`,`error`)),{valid:!1,errors:[r]}}}function h(t){e.i(`❌ Schema validation failed:`,`error`),e.i(``,`error`),e.i(`The following validation errors were found:`,`error`),e.i(``,`error`);for(let n of t)e.i(` • ${n}`,`error`);e.i(``,`error`),e.i(`Please fix these errors in your template configuration file.`,`error`),e.i(``,`error`),e.i(`For schema documentation, see: https://github.com/pixpilot/scaffoldfy/tree/main/packages/scaffoldfy/schema`,`info`)}const g=new a.Command,_=r.default.join(__dirname,`..`,`package.json`);let v=`0.0.0`;try{v=JSON.parse(n.default.readFileSync(_,`utf-8`)).version??`0.0.0`}catch{}g.name(`scaffoldfy`).description(`Automate project setup and configuration with customizable tasks`).version(v),g.option(`--dry-run`,`Run in dry mode without making any changes`).option(`--force`,`Force execution even if checks fail`).option(`--tasks-file <path>`,`Path to JSON file containing task definitions`,`./template-tasks.json`).option(`--tasks-ts <path>`,`Path to TypeScript file exporting tasks`,`./template-tasks.ts`).option(`--no-validate`,`Skip schema validation of task configuration (validation is enabled by default)`).action(async a=>{try{let o=[],s,c,l,u;if(a.tasksTs!=null&&a.tasksTs!==``){let t=r.default.resolve(i.default.cwd(),a.tasksTs);if(n.default.existsSync(t)){e.i(`Loading tasks from TypeScript file: ${a.tasksTs}`,`info`),u=t;try{let n=await import(t);o=n.default??n.tasks??[],(!Array.isArray(o)||o.length===0)&&(e.i(`⚠️ No tasks found in TypeScript file or invalid format`,`warn`),e.i(`Expected default export or named export "tasks" with TaskDefinition[]`,`info`))}catch(t){e.i(`Failed to load TypeScript tasks file: ${a.tasksTs}`,`error`),t instanceof Error&&e.i(` Error: ${t.message}`,`error`),i.default.exit(1)}}}if(o.length===0&&a.tasksFile!=null&&a.tasksFile!==``){let d=r.default.resolve(i.default.cwd(),a.tasksFile);if(n.default.existsSync(d)){u=d;try{if(a.validate!==!1){e.i(`Validating task configuration against schema...`,`info`);let t=n.default.readFileSync(d,`utf-8`);m(JSON.parse(t),{silent:!1}).valid||(e.i(``,`error`),e.i(`💡 You can skip validation with --no-validate flag, but this is not recommended.`,`info`),i.default.exit(1)),e.i(`✓ Schema validation passed`,`success`)}let r=await t.q(d);o=r.tasks,s=r.variables,c=r.prompts,l=r.enabled,Array.isArray(o)||(e.i(`❌ Invalid tasks file format`,`error`),e.i(`Expected JSON with { "tasks": [...] } structure`,`info`),i.default.exit(1))}catch(t){e.i(`Failed to load JSON tasks file: ${a.tasksFile}`,`error`),t instanceof Error&&e.i(` Error: ${t.message}`,`error`),i.default.exit(1)}}else e.i(`Tasks file not found: ${a.tasksFile}`,`warn`)}let d=c!=null&&c.length>0||s!=null&&s.length>0;o.length===0&&!d&&(e.i(`❌ No tasks defined`,`error`),e.i(`Please provide tasks using one of these methods:`,`info`),e.i(` 1. Create a template-tasks.json file in the current directory`,`info`),e.i(` 2. Create a template-tasks.ts file in the current directory`,`info`),e.i(` 3. Use --tasks-file option to specify a different JSON file`,`info`),e.i(` 4. Use --tasks-ts option to specify a different TypeScript file`,`info`),e.i(`Example JSON structure:`,`info`),console.log(JSON.stringify({tasks:[{id:`update-package`,name:`Update package.json`,description:`Update package.json with repository information`,required:!0,enabled:!0,type:`update-json`,prompts:[{id:`projectName`,type:`input`,message:`What is your project name?`,default:`my-project`,required:!0},{id:`includeTests`,type:`confirm`,message:`Include test files?`,default:!0}],config:{file:`package.json`,updates:{name:`{{projectName}}`,author:`{{author}}`}}}]},null,2)),i.default.exit(1)),o.length===0?e.i(`Loaded template with 0 tasks (template may only provide prompts/variables for extending)`,`info`):e.i(`Loaded ${o.length} task(s)`,`success`),await t.n(o,{dryRun:a.dryRun,force:a.force,tasksFilePath:u,globalVariables:s,globalPrompts:c,templateEnabled:l})}catch(t){if(e.i(`❌ CLI execution failed`,`error`),t instanceof Error){e.i(`Error: ${t.message}`,`error`);let n=i.default.env.DEBUG;n!=null&&n!==``&&console.error(t.stack)}else console.error(t);i.default.exit(1)}}),g.parse(i.default.argv);
2
+ const e=require(`./utils-Bhsv13ij.cjs`);require(`./config-DlJs75hK.cjs`);const t=require(`./run-tasks-Bn4lboAE.cjs`),n=require(`./src-BlvCkBsJ.cjs`);let r=require(`node:fs`);r=e._(r);let i=require(`node:path`);i=e._(i);let a=require(`node:process`);a=e._(a);let o=require(`commander`);o=e._(o);let s=require(`node:url`);s=e._(s);let c=require(`ajv`);c=e._(c);const l=1,u=(0,s.fileURLToPath)(require(`url`).pathToFileURL(__filename).href),d=i.default.dirname(u);function f(){return new c.default({allErrors:!0,verbose:!0,strict:!1,discriminator:!0})}function p(){let e=i.default.join(d,`..`,`schema`,`tasks.schema.json`);try{let t=r.default.readFileSync(e,`utf-8`);return JSON.parse(t)}catch(t){throw Error(`Failed to load tasks schema from ${e}: ${t instanceof Error?t.message:String(t)}`)}}function m(e){return e.filter(t=>{if(t.keyword===`oneOf`){let e=t.params;if(e.passingSchemas&&e.passingSchemas.length>0)return!1}if(t.keyword===`required`){let n=e.find(e=>e.keyword===`oneOf`&&e.instancePath===t.instancePath);if(n){let e=n.params;if(e.passingSchemas&&e.passingSchemas.length>0)return!1}}return!0}).map(e=>{let t=e.instancePath||`root`,n=e.message??`Unknown error`;switch(e.keyword){case`required`:return`${t}: Missing required property "${String(e.params.missingProperty??`unknown`)}"`;case`type`:return`${t}: Expected type "${String(e.params.type??`unknown`)}", received "${typeof e.data}"`;case`enum`:{let r=e.params.allowedValues;return`${t}: ${n}. Allowed values: ${Array.isArray(r)?r.join(`, `):String(r)}`}case`pattern`:{let{pattern:r}=e.params;return`${t}: ${n}. Value must match pattern: ${String(r)}`}case`oneOf`:return`${t}: ${n}. Configuration must match exactly one of the allowed schemas`;case`additionalProperties`:return`${t}: ${n}. Unknown property: "${String(e.params.additionalProperty??`unknown`)}"`;default:return`${t}: ${n}`}})}function h(t,n={}){try{let e=f(),r=p(),i=e.compile(r);if(!i(t)&&i.errors){let e=m(i.errors);return e.length===0?{valid:!0,errors:[]}:(n.silent||g(e),{valid:!1,errors:e})}return{valid:!0,errors:[]}}catch(t){let r=t instanceof Error?t.message:`Unknown error occurred during schema validation`;return n.silent||(e.i(`❌ Schema validation error:`,`error`),e.i(` ${r}`,`error`)),{valid:!1,errors:[r]}}}function g(t){e.i(`❌ Schema validation failed:`,`error`),e.i(``,`error`),e.i(`The following validation errors were found:`,`error`),e.i(``,`error`);for(let n of t)e.i(` • ${n}`,`error`);e.i(``,`error`),e.i(`Please fix these errors in your template configuration file.`,`error`),e.i(``,`error`),e.i(`For schema documentation, see: https://github.com/pixpilot/scaffoldfy/tree/main/packages/scaffoldfy/schema`,`info`)}const _=new o.Command,v=i.default.join(__dirname,`..`,`package.json`);let y=`0.0.0`;try{y=JSON.parse(r.default.readFileSync(v,`utf-8`)).version??`0.0.0`}catch{}_.name(`scaffoldfy`).description(`Automate project setup and configuration with customizable tasks`).version(y),_.option(`--dry-run`,`Run in dry mode without making any changes`).option(`--force`,`Force execution even if checks fail`).option(`--tasks-file <path>`,`Path to JSON file containing task definitions`,`./template-tasks.json`).option(`--tasks-ts <path>`,`Path to TypeScript file exporting tasks`,`./template-tasks.ts`).option(`--no-validate`,`Skip schema validation of task configuration (validation is enabled by default)`).action(async o=>{try{let s=[],c,l,u,d;if(o.tasksTs!=null&&o.tasksTs!==``){let t=i.default.resolve(a.default.cwd(),o.tasksTs);if(r.default.existsSync(t)){e.i(`Loading tasks from TypeScript file: ${o.tasksTs}`,`info`),d=t;try{let n=await import(t);s=n.default??n.tasks??[],(!Array.isArray(s)||s.length===0)&&(e.i(`⚠️ No tasks found in TypeScript file or invalid format`,`warn`),e.i(`Expected default export or named export "tasks" with TaskDefinition[]`,`info`))}catch(t){e.i(`Failed to load TypeScript tasks file: ${o.tasksTs}`,`error`),t instanceof Error&&e.i(` Error: ${t.message}`,`error`),a.default.exit(1)}}}if(s.length===0&&o.tasksFile!=null&&o.tasksFile!==``){let n=i.default.resolve(a.default.cwd(),o.tasksFile);if(r.default.existsSync(n)){d=n;try{if(o.validate!==!1){e.i(`Validating task configuration against schema...`,`info`);let t=r.default.readFileSync(n,`utf-8`);h(JSON.parse(t),{silent:!1}).valid||(e.i(``,`error`),e.i(`💡 You can skip validation with --no-validate flag, but this is not recommended.`,`info`),a.default.exit(1)),e.i(`✓ Schema validation passed`,`success`)}let i=await t.q(n,{sequential:!0});if(i.templates!=null&&i.templates.length>0){e.i(`Using sequential template processing mode`,`info`);let{runTemplatesSequentially:t}=await Promise.resolve().then(()=>require(`./run-tasks-BZQH28T_.cjs`)),{createInitialConfig:r}=await Promise.resolve().then(()=>require(`./config-DmK0Erv2.cjs`));await t(i.templates,{dryRun:o.dryRun??!1,force:o.force??!1,tasksFilePath:n},r()),a.default.exit(0)}s=i.tasks,c=i.variables,l=i.prompts,u=i.enabled,Array.isArray(s)||(e.i(`❌ Invalid tasks file format`,`error`),e.i(`Expected JSON with { "tasks": [...] } structure`,`info`),a.default.exit(1))}catch(t){e.i(`Failed to load JSON tasks file: ${o.tasksFile}`,`error`),t instanceof Error&&e.i(` Error: ${t.message}`,`error`),a.default.exit(1)}}else e.i(`Tasks file not found: ${o.tasksFile}`,`warn`)}let f=l!=null&&l.length>0||c!=null&&c.length>0;s.length===0&&!f&&(e.i(`❌ No tasks defined`,`error`),e.i(`Please provide tasks using one of these methods:`,`info`),e.i(` 1. Create a template-tasks.json file in the current directory`,`info`),e.i(` 2. Create a template-tasks.ts file in the current directory`,`info`),e.i(` 3. Use --tasks-file option to specify a different JSON file`,`info`),e.i(` 4. Use --tasks-ts option to specify a different TypeScript file`,`info`),e.i(`Example JSON structure:`,`info`),console.log(JSON.stringify({tasks:[{id:`update-package`,name:`Update package.json`,description:`Update package.json with repository information`,required:!0,enabled:!0,type:`update-json`,prompts:[{id:`projectName`,type:`input`,message:`What is your project name?`,default:`my-project`,required:!0},{id:`includeTests`,type:`confirm`,message:`Include test files?`,default:!0}],config:{file:`package.json`,updates:{name:`{{projectName}}`,author:`{{author}}`}}}]},null,2)),a.default.exit(1)),s.length===0?e.i(`Loaded template with 0 tasks (template may only provide prompts/variables for extending)`,`info`):e.i(`Loaded ${s.length} task(s)`,`success`),await n.n(s,{dryRun:o.dryRun,force:o.force,tasksFilePath:d,globalVariables:c,globalPrompts:l,templateEnabled:u})}catch(t){if(e.i(`❌ CLI execution failed`,`error`),t instanceof Error){e.i(`Error: ${t.message}`,`error`);let n=a.default.env.DEBUG;n!=null&&n!==``&&console.error(t.stack)}else console.error(t);a.default.exit(1)}}),_.parse(a.default.argv);
package/dist/cli.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{n as e,q as t}from"./src-DNp4KfEG.js";import{i as n}from"./utils-DfD7I1u2.js";import r from"node:path";import{fileURLToPath as i}from"node:url";import a from"node:fs";import o from"node:process";import{Command as s}from"commander";import c from"ajv";const l=()=>i(import.meta.url),u=(()=>r.dirname(l()))(),d=i(import.meta.url),f=r.dirname(d);function p(){return new c({allErrors:!0,verbose:!0,strict:!1,discriminator:!0})}function m(){let e=r.join(f,`..`,`schema`,`tasks.schema.json`);try{let t=a.readFileSync(e,`utf-8`);return JSON.parse(t)}catch(t){throw Error(`Failed to load tasks schema from ${e}: ${t instanceof Error?t.message:String(t)}`)}}function h(e){return e.filter(t=>{if(t.keyword===`oneOf`){let e=t.params;if(e.passingSchemas&&e.passingSchemas.length>0)return!1}if(t.keyword===`required`){let n=e.find(e=>e.keyword===`oneOf`&&e.instancePath===t.instancePath);if(n){let e=n.params;if(e.passingSchemas&&e.passingSchemas.length>0)return!1}}return!0}).map(e=>{let t=e.instancePath||`root`,n=e.message??`Unknown error`;switch(e.keyword){case`required`:return`${t}: Missing required property "${String(e.params.missingProperty??`unknown`)}"`;case`type`:return`${t}: Expected type "${String(e.params.type??`unknown`)}", received "${typeof e.data}"`;case`enum`:{let r=e.params.allowedValues;return`${t}: ${n}. Allowed values: ${Array.isArray(r)?r.join(`, `):String(r)}`}case`pattern`:{let{pattern:r}=e.params;return`${t}: ${n}. Value must match pattern: ${String(r)}`}case`oneOf`:return`${t}: ${n}. Configuration must match exactly one of the allowed schemas`;case`additionalProperties`:return`${t}: ${n}. Unknown property: "${String(e.params.additionalProperty??`unknown`)}"`;default:return`${t}: ${n}`}})}function g(e,t={}){try{let n=p(),r=m(),i=n.compile(r);if(!i(e)&&i.errors){let e=h(i.errors);return e.length===0?{valid:!0,errors:[]}:(t.silent||_(e),{valid:!1,errors:e})}return{valid:!0,errors:[]}}catch(e){let r=e instanceof Error?e.message:`Unknown error occurred during schema validation`;return t.silent||(n(`❌ Schema validation error:`,`error`),n(` ${r}`,`error`)),{valid:!1,errors:[r]}}}function _(e){n(`❌ Schema validation failed:`,`error`),n(``,`error`),n(`The following validation errors were found:`,`error`),n(``,`error`);for(let t of e)n(` • ${t}`,`error`);n(``,`error`),n(`Please fix these errors in your template configuration file.`,`error`),n(``,`error`),n(`For schema documentation, see: https://github.com/pixpilot/scaffoldfy/tree/main/packages/scaffoldfy/schema`,`info`)}const v=new s,y=r.join(u,`..`,`package.json`);let b=`0.0.0`;try{b=JSON.parse(a.readFileSync(y,`utf-8`)).version??`0.0.0`}catch{}v.name(`scaffoldfy`).description(`Automate project setup and configuration with customizable tasks`).version(b),v.option(`--dry-run`,`Run in dry mode without making any changes`).option(`--force`,`Force execution even if checks fail`).option(`--tasks-file <path>`,`Path to JSON file containing task definitions`,`./template-tasks.json`).option(`--tasks-ts <path>`,`Path to TypeScript file exporting tasks`,`./template-tasks.ts`).option(`--no-validate`,`Skip schema validation of task configuration (validation is enabled by default)`).action(async i=>{try{let s=[],c,l,u,d;if(i.tasksTs!=null&&i.tasksTs!==``){let e=r.resolve(o.cwd(),i.tasksTs);if(a.existsSync(e)){n(`Loading tasks from TypeScript file: ${i.tasksTs}`,`info`),d=e;try{let t=await import(e);s=t.default??t.tasks??[],(!Array.isArray(s)||s.length===0)&&(n(`⚠️ No tasks found in TypeScript file or invalid format`,`warn`),n(`Expected default export or named export "tasks" with TaskDefinition[]`,`info`))}catch(e){n(`Failed to load TypeScript tasks file: ${i.tasksTs}`,`error`),e instanceof Error&&n(` Error: ${e.message}`,`error`),o.exit(1)}}}if(s.length===0&&i.tasksFile!=null&&i.tasksFile!==``){let e=r.resolve(o.cwd(),i.tasksFile);if(a.existsSync(e)){d=e;try{if(i.validate!==!1){n(`Validating task configuration against schema...`,`info`);let t=a.readFileSync(e,`utf-8`);g(JSON.parse(t),{silent:!1}).valid||(n(``,`error`),n(`💡 You can skip validation with --no-validate flag, but this is not recommended.`,`info`),o.exit(1)),n(`✓ Schema validation passed`,`success`)}let r=await t(e);s=r.tasks,c=r.variables,l=r.prompts,u=r.enabled,Array.isArray(s)||(n(`❌ Invalid tasks file format`,`error`),n(`Expected JSON with { "tasks": [...] } structure`,`info`),o.exit(1))}catch(e){n(`Failed to load JSON tasks file: ${i.tasksFile}`,`error`),e instanceof Error&&n(` Error: ${e.message}`,`error`),o.exit(1)}}else n(`Tasks file not found: ${i.tasksFile}`,`warn`)}let f=l!=null&&l.length>0||c!=null&&c.length>0;s.length===0&&!f&&(n(`❌ No tasks defined`,`error`),n(`Please provide tasks using one of these methods:`,`info`),n(` 1. Create a template-tasks.json file in the current directory`,`info`),n(` 2. Create a template-tasks.ts file in the current directory`,`info`),n(` 3. Use --tasks-file option to specify a different JSON file`,`info`),n(` 4. Use --tasks-ts option to specify a different TypeScript file`,`info`),n(`Example JSON structure:`,`info`),console.log(JSON.stringify({tasks:[{id:`update-package`,name:`Update package.json`,description:`Update package.json with repository information`,required:!0,enabled:!0,type:`update-json`,prompts:[{id:`projectName`,type:`input`,message:`What is your project name?`,default:`my-project`,required:!0},{id:`includeTests`,type:`confirm`,message:`Include test files?`,default:!0}],config:{file:`package.json`,updates:{name:`{{projectName}}`,author:`{{author}}`}}}]},null,2)),o.exit(1)),s.length===0?n(`Loaded template with 0 tasks (template may only provide prompts/variables for extending)`,`info`):n(`Loaded ${s.length} task(s)`,`success`),await e(s,{dryRun:i.dryRun,force:i.force,tasksFilePath:d,globalVariables:c,globalPrompts:l,templateEnabled:u})}catch(e){if(n(`❌ CLI execution failed`,`error`),e instanceof Error){n(`Error: ${e.message}`,`error`);let t=o.env.DEBUG;t!=null&&t!==``&&console.error(e.stack)}else console.error(e);o.exit(1)}}),v.parse(o.argv);export{};
2
+ import"./config-DfRbCqsT.js";import{i as e}from"./utils-D61aLjOR.js";import{q as t}from"./run-tasks-C859oQ3R.js";import{n}from"./src-DfhwwM_Y.js";import r from"node:path";import{fileURLToPath as i}from"node:url";import a from"node:fs";import o from"node:process";import{Command as s}from"commander";import c from"ajv";const l=()=>i(import.meta.url),u=(()=>r.dirname(l()))(),d=i(import.meta.url),f=r.dirname(d);function p(){return new c({allErrors:!0,verbose:!0,strict:!1,discriminator:!0})}function m(){let e=r.join(f,`..`,`schema`,`tasks.schema.json`);try{let t=a.readFileSync(e,`utf-8`);return JSON.parse(t)}catch(t){throw Error(`Failed to load tasks schema from ${e}: ${t instanceof Error?t.message:String(t)}`)}}function h(e){return e.filter(t=>{if(t.keyword===`oneOf`){let e=t.params;if(e.passingSchemas&&e.passingSchemas.length>0)return!1}if(t.keyword===`required`){let n=e.find(e=>e.keyword===`oneOf`&&e.instancePath===t.instancePath);if(n){let e=n.params;if(e.passingSchemas&&e.passingSchemas.length>0)return!1}}return!0}).map(e=>{let t=e.instancePath||`root`,n=e.message??`Unknown error`;switch(e.keyword){case`required`:return`${t}: Missing required property "${String(e.params.missingProperty??`unknown`)}"`;case`type`:return`${t}: Expected type "${String(e.params.type??`unknown`)}", received "${typeof e.data}"`;case`enum`:{let r=e.params.allowedValues;return`${t}: ${n}. Allowed values: ${Array.isArray(r)?r.join(`, `):String(r)}`}case`pattern`:{let{pattern:r}=e.params;return`${t}: ${n}. Value must match pattern: ${String(r)}`}case`oneOf`:return`${t}: ${n}. Configuration must match exactly one of the allowed schemas`;case`additionalProperties`:return`${t}: ${n}. Unknown property: "${String(e.params.additionalProperty??`unknown`)}"`;default:return`${t}: ${n}`}})}function g(t,n={}){try{let e=p(),r=m(),i=e.compile(r);if(!i(t)&&i.errors){let e=h(i.errors);return e.length===0?{valid:!0,errors:[]}:(n.silent||_(e),{valid:!1,errors:e})}return{valid:!0,errors:[]}}catch(t){let r=t instanceof Error?t.message:`Unknown error occurred during schema validation`;return n.silent||(e(`❌ Schema validation error:`,`error`),e(` ${r}`,`error`)),{valid:!1,errors:[r]}}}function _(t){e(`❌ Schema validation failed:`,`error`),e(``,`error`),e(`The following validation errors were found:`,`error`),e(``,`error`);for(let n of t)e(` • ${n}`,`error`);e(``,`error`),e(`Please fix these errors in your template configuration file.`,`error`),e(``,`error`),e(`For schema documentation, see: https://github.com/pixpilot/scaffoldfy/tree/main/packages/scaffoldfy/schema`,`info`)}const v=new s,y=r.join(u,`..`,`package.json`);let b=`0.0.0`;try{b=JSON.parse(a.readFileSync(y,`utf-8`)).version??`0.0.0`}catch{}v.name(`scaffoldfy`).description(`Automate project setup and configuration with customizable tasks`).version(b),v.option(`--dry-run`,`Run in dry mode without making any changes`).option(`--force`,`Force execution even if checks fail`).option(`--tasks-file <path>`,`Path to JSON file containing task definitions`,`./template-tasks.json`).option(`--tasks-ts <path>`,`Path to TypeScript file exporting tasks`,`./template-tasks.ts`).option(`--no-validate`,`Skip schema validation of task configuration (validation is enabled by default)`).action(async i=>{try{let s=[],c,l,u,d;if(i.tasksTs!=null&&i.tasksTs!==``){let t=r.resolve(o.cwd(),i.tasksTs);if(a.existsSync(t)){e(`Loading tasks from TypeScript file: ${i.tasksTs}`,`info`),d=t;try{let n=await import(t);s=n.default??n.tasks??[],(!Array.isArray(s)||s.length===0)&&(e(`⚠️ No tasks found in TypeScript file or invalid format`,`warn`),e(`Expected default export or named export "tasks" with TaskDefinition[]`,`info`))}catch(t){e(`Failed to load TypeScript tasks file: ${i.tasksTs}`,`error`),t instanceof Error&&e(` Error: ${t.message}`,`error`),o.exit(1)}}}if(s.length===0&&i.tasksFile!=null&&i.tasksFile!==``){let n=r.resolve(o.cwd(),i.tasksFile);if(a.existsSync(n)){d=n;try{if(i.validate!==!1){e(`Validating task configuration against schema...`,`info`);let t=a.readFileSync(n,`utf-8`);g(JSON.parse(t),{silent:!1}).valid||(e(``,`error`),e(`💡 You can skip validation with --no-validate flag, but this is not recommended.`,`info`),o.exit(1)),e(`✓ Schema validation passed`,`success`)}let r=await t(n,{sequential:!0});if(r.templates!=null&&r.templates.length>0){e(`Using sequential template processing mode`,`info`);let{runTemplatesSequentially:t}=await import(`./run-tasks-D-CbjBoy.js`),{createInitialConfig:a}=await import(`./config-C8hh88Lc.js`);await t(r.templates,{dryRun:i.dryRun??!1,force:i.force??!1,tasksFilePath:n},a()),o.exit(0)}s=r.tasks,c=r.variables,l=r.prompts,u=r.enabled,Array.isArray(s)||(e(`❌ Invalid tasks file format`,`error`),e(`Expected JSON with { "tasks": [...] } structure`,`info`),o.exit(1))}catch(t){e(`Failed to load JSON tasks file: ${i.tasksFile}`,`error`),t instanceof Error&&e(` Error: ${t.message}`,`error`),o.exit(1)}}else e(`Tasks file not found: ${i.tasksFile}`,`warn`)}let f=l!=null&&l.length>0||c!=null&&c.length>0;s.length===0&&!f&&(e(`❌ No tasks defined`,`error`),e(`Please provide tasks using one of these methods:`,`info`),e(` 1. Create a template-tasks.json file in the current directory`,`info`),e(` 2. Create a template-tasks.ts file in the current directory`,`info`),e(` 3. Use --tasks-file option to specify a different JSON file`,`info`),e(` 4. Use --tasks-ts option to specify a different TypeScript file`,`info`),e(`Example JSON structure:`,`info`),console.log(JSON.stringify({tasks:[{id:`update-package`,name:`Update package.json`,description:`Update package.json with repository information`,required:!0,enabled:!0,type:`update-json`,prompts:[{id:`projectName`,type:`input`,message:`What is your project name?`,default:`my-project`,required:!0},{id:`includeTests`,type:`confirm`,message:`Include test files?`,default:!0}],config:{file:`package.json`,updates:{name:`{{projectName}}`,author:`{{author}}`}}}]},null,2)),o.exit(1)),s.length===0?e(`Loaded template with 0 tasks (template may only provide prompts/variables for extending)`,`info`):e(`Loaded ${s.length} task(s)`,`success`),await n(s,{dryRun:i.dryRun,force:i.force,tasksFilePath:d,globalVariables:c,globalPrompts:l,templateEnabled:u})}catch(t){if(e(`❌ CLI execution failed`,`error`),t instanceof Error){e(`Error: ${t.message}`,`error`);let n=o.env.DEBUG;n!=null&&n!==``&&console.error(t.stack)}else console.error(t);o.exit(1)}}),v.parse(o.argv);export{};
@@ -0,0 +1 @@
1
+ import{t as e}from"./config-DfRbCqsT.js";export{e as createInitialConfig};
@@ -0,0 +1 @@
1
+ function e(){return{}}export{e as t};
@@ -0,0 +1 @@
1
+ function e(){return{}}Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return e}});
@@ -0,0 +1 @@
1
+ const e=require(`./config-DlJs75hK.cjs`);exports.createInitialConfig=e.t;
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- const e=require(`./utils-CdfjwUZm.cjs`),t=require(`./src-C2AFidMo.cjs`);exports.callHook=t.h,exports.clearPlugins=t.g,exports.clearTemplateCache=t.G,exports.collectPrompts=t.p,exports.collectVariables=t.o,exports.createPlugin=t._,exports.displayTasksDiff=t.O,exports.evaluateCondition=e.t,exports.executePluginTask=t.v,exports.executeTask=t.c,exports.getCreateDiff=t.k,exports.getDeleteDiff=t.A,exports.getExecDiff=t.j,exports.getGitInitDiff=t.M,exports.getGitRepoInfo=e.n,exports.getPlugin=t.y,exports.getPluginForTaskType=t.b,exports.getPluginTaskDiff=t.x,exports.getRegexReplaceDiff=t.N,exports.getRenameDiff=t.P,exports.getReplaceInFileDiff=t.F,exports.getTaskDiff=t.I,exports.getTemplateSourceDescription=t.z,exports.getUpdateJsonDiff=t.L,exports.getWriteDiff=t.R,exports.hasInlineTemplate=t.B,exports.hasTemplateFile=t.V,exports.interpolateTemplate=e.r,exports.isPluginTaskType=t.S,exports.listPlugins=t.C,exports.loadAndMergeTemplate=t.K,exports.loadTasksWithInheritance=t.q,exports.loadTemplate=t.J,exports.log=e.i,exports.main=t.t,exports.mergeTemplates=t.Y,exports.processTemplate=t.H,exports.prompt=e.a,exports.promptYesNo=e.o,exports.registerBuiltInPlugins=t.l,exports.registerHooks=t.w,exports.registerPlugin=t.T,exports.resolveAllDefaultValues=t.f,exports.resolveAllVariableValues=t.i,exports.resolveDefaultValue=t.m,exports.resolveVariableValue=t.a,exports.runTask=t.u,exports.runWithTasks=t.n,exports.setNestedProperty=e.s,exports.shouldUseHandlebars=t.U,exports.topologicalSort=t.s,exports.unregisterPlugin=t.E,exports.validatePluginTask=t.D,exports.validatePrompts=t.d,exports.validateTemplateConfig=t.W,exports.validateVariables=t.r;
1
+ const e=require(`./utils-Bhsv13ij.cjs`);require(`./config-DlJs75hK.cjs`);const t=require(`./run-tasks-Bn4lboAE.cjs`),n=require(`./src-BlvCkBsJ.cjs`);exports.callHook=t.h,exports.clearPlugins=t.g,exports.clearTemplateCache=t.G,exports.collectPrompts=t.p,exports.collectVariables=t.o,exports.createPlugin=t._,exports.displayTasksDiff=t.O,exports.evaluateCondition=e.t,exports.executePluginTask=t.v,exports.executeTask=t.c,exports.getCreateDiff=t.k,exports.getDeleteDiff=t.A,exports.getExecDiff=t.j,exports.getGitInitDiff=t.M,exports.getGitRepoInfo=e.n,exports.getPlugin=t.y,exports.getPluginForTaskType=t.b,exports.getPluginTaskDiff=t.x,exports.getRegexReplaceDiff=t.N,exports.getRenameDiff=t.P,exports.getReplaceInFileDiff=t.F,exports.getTaskDiff=t.I,exports.getTemplateSourceDescription=t.z,exports.getUpdateJsonDiff=t.L,exports.getWriteDiff=t.R,exports.hasInlineTemplate=t.B,exports.hasTemplateFile=t.V,exports.interpolateTemplate=e.r,exports.isPluginTaskType=t.S,exports.listPlugins=t.C,exports.loadAndMergeTemplate=t.K,exports.loadTasksWithInheritance=t.q,exports.loadTemplate=t.J,exports.loadTemplatesInOrder=t.Y,exports.log=e.i,exports.main=n.t,exports.mergeTemplates=t.X,exports.processTemplate=t.H,exports.prompt=e.a,exports.promptYesNo=e.o,exports.registerBuiltInPlugins=t.l,exports.registerHooks=t.w,exports.registerPlugin=t.T,exports.resolveAllDefaultValues=t.f,exports.resolveAllVariableValues=t.i,exports.resolveDefaultValue=t.m,exports.resolveVariableValue=t.a,exports.runTask=t.u,exports.runTasks=t.t,exports.runTemplatesSequentially=t.n,exports.runWithTasks=n.n,exports.setNestedProperty=e.s,exports.shouldUseHandlebars=t.U,exports.topologicalSort=t.s,exports.unregisterPlugin=t.E,exports.validatePluginTask=t.D,exports.validatePrompts=t.d,exports.validateTemplateConfig=t.W,exports.validateVariables=t.r;
package/dist/index.d.cts CHANGED
@@ -241,8 +241,6 @@ interface TaskDefinition {
241
241
  config: UpdateJsonConfig | WriteConfig | CreateConfig | RegexReplaceConfig | ReplaceInFileConfig | DeleteConfig | RenameConfig | GitInitConfig | ExecConfig | MoveConfig | CopyConfig | AppendConfig | MkdirConfig | Record<string, unknown>;
242
242
  dependencies?: string[];
243
243
  rollback?: RollbackConfig;
244
- prompts?: PromptDefinition[];
245
- variables?: VariableDefinition[];
246
244
  override?: MergeStrategy;
247
245
  $sourceUrl?: string;
248
246
  $templateEnabled?: EnabledValue;
@@ -473,6 +471,32 @@ declare function resolveDefaultValue<T = string | number | boolean>(defaultValue
473
471
  */
474
472
  declare function validatePrompts(prompts: PromptDefinition[]): string[];
475
473
  //#endregion
474
+ //#region src/run-tasks.d.ts
475
+ /**
476
+ * Core task execution logic shared by both main() and runWithTasks()
477
+ */
478
+ declare function runTasks(tasks: TaskDefinition[], options: {
479
+ dryRun: boolean;
480
+ force: boolean;
481
+ tasksFilePath: string | undefined;
482
+ globalVariables?: VariableDefinition[];
483
+ globalPrompts?: PromptDefinition[];
484
+ templateEnabled?: EnabledValue;
485
+ }): Promise<void>;
486
+ /**
487
+ * Run templates sequentially for variables/prompts, then all tasks together
488
+ * Phase 1: Process variables and prompts sequentially from each template
489
+ * Phase 2: Collect all tasks from all enabled templates
490
+ * Phase 3: Execute all tasks together at the end
491
+ * This allows later templates to use values from earlier templates in their conditions,
492
+ * while still executing all tasks together after all variables/prompts are resolved
493
+ */
494
+ declare function runTemplatesSequentially(templates: TasksConfiguration[], options: {
495
+ dryRun: boolean;
496
+ force: boolean;
497
+ tasksFilePath: string | undefined;
498
+ }, config?: InitConfig): Promise<void>;
499
+ //#endregion
476
500
  //#region src/task-executors.d.ts
477
501
  declare function registerBuiltInPlugins(): void;
478
502
  /**
@@ -498,6 +522,14 @@ declare function topologicalSort(tasks: TaskDefinition[]): TaskDefinition[];
498
522
  * @returns The loaded template configuration
499
523
  */
500
524
  declare function loadTemplate(templatePath: string, visitedPaths?: Set<string>): Promise<TasksConfiguration>;
525
+ /**
526
+ * Load all templates in dependency order without merging
527
+ * @param templatePath - Path or URL to the template file
528
+ * @param baseDir - Base directory or URL for resolving relative paths in extends
529
+ * @param visitedPaths - Set of already visited paths
530
+ * @returns Array of sorted templates (in dependency order, ready for sequential processing)
531
+ */
532
+ declare function loadTemplatesInOrder(templatePath: string, baseDir?: string, visitedPaths?: Set<string>): Promise<TasksConfiguration[]>;
501
533
  /**
502
534
  * Recursively load and merge templates
503
535
  * @param templatePath - Path or URL to the template file
@@ -520,13 +552,18 @@ declare function clearTemplateCache(): void;
520
552
  /**
521
553
  * Load tasks from a configuration file with template inheritance support
522
554
  * @param tasksFilePath - Path to the tasks configuration file
555
+ * @param options - Optional configuration
556
+ * @param options.sequential - If true, return templates as separate items for sequential processing
523
557
  * @returns Task configuration with tasks, optional variables, and optional prompts
524
558
  */
525
- declare function loadTasksWithInheritance(tasksFilePath: string): Promise<{
559
+ declare function loadTasksWithInheritance(tasksFilePath: string, options?: {
560
+ sequential?: boolean;
561
+ }): Promise<{
526
562
  tasks: TaskDefinition[];
527
563
  variables?: VariableDefinition[];
528
564
  prompts?: PromptDefinition[];
529
565
  enabled?: EnabledValue;
566
+ templates?: TasksConfiguration[];
530
567
  }>;
531
568
  //#endregion
532
569
  //#region src/template-utils.d.ts
@@ -656,9 +693,13 @@ declare function collectVariables(variables: VariableDefinition[], resolvedValue
656
693
  * Each variable can access values from previous variables and prompts
657
694
  * @param variables - Array of variable definitions
658
695
  * @param context - Optional context for evaluating conditional variables
696
+ * @param options - Optional resolution options
697
+ * @param options.skipConditional - If true, skip conditional variables (they will be resolved later)
659
698
  * @returns Map of variable IDs to their resolved values
660
699
  */
661
- declare function resolveAllVariableValues(variables: VariableDefinition[], context?: InitConfig): Promise<Map<string, unknown>>;
700
+ declare function resolveAllVariableValues(variables: VariableDefinition[], context?: InitConfig, options?: {
701
+ skipConditional?: boolean;
702
+ }): Promise<Map<string, unknown>>;
662
703
  //#endregion
663
704
  //#region src/variables/resolve-variable-value.d.ts
664
705
  /**
@@ -704,4 +745,4 @@ declare function runWithTasks(customTasks: TaskDefinition[], options?: {
704
745
  templateEnabled?: EnabledValue | undefined;
705
746
  }): Promise<void>;
706
747
  //#endregion
707
- export { type AppendConfig, BasePrompt, ConditionExpression, ConditionalDefaultConfig, ConditionalEnabled, ConfirmPrompt, type CopyConfig, type CreateConfig, DefaultValue, DefaultValueConfig, DefaultValueType, type DeleteConfig, EnabledValue, type ExecConfig, ExecutableEnabled, type GitInitConfig, InitConfig, InputPrompt, MergeStrategy, type MkdirConfig, type MoveConfig, NumberPrompt, PluginHooks, PromptDefinition, PromptType, type RegexReplaceConfig, type RenameConfig, type ReplaceInFileConfig, RollbackConfig, SelectPrompt, TaskDefinition, TaskPlugin, TaskType, TasksConfiguration, type UpdateJsonConfig, VariableDefinition, type WriteConfig, callHook, clearPlugins, clearTemplateCache, collectPrompts, collectVariables, createPlugin, displayTasksDiff, evaluateCondition, executePluginTask, executeTask, getCreateDiff, getDeleteDiff, getExecDiff, getGitInitDiff, getGitRepoInfo, getPlugin, getPluginForTaskType, getPluginTaskDiff, getRegexReplaceDiff, getRenameDiff, getReplaceInFileDiff, getTaskDiff, getTemplateSourceDescription, getUpdateJsonDiff, getWriteDiff, hasInlineTemplate, hasTemplateFile, interpolateTemplate, isPluginTaskType, listPlugins, loadAndMergeTemplate, loadTasksWithInheritance, loadTemplate, log, main, mergeTemplates, processTemplate, prompt, promptYesNo, registerBuiltInPlugins, registerHooks, registerPlugin, resolveAllDefaultValues, resolveAllVariableValues, resolveDefaultValue, resolveVariableValue, runTask, runWithTasks, setNestedProperty, shouldUseHandlebars, topologicalSort, unregisterPlugin, validatePluginTask, validatePrompts, validateTemplateConfig, validateVariables };
748
+ export { type AppendConfig, BasePrompt, ConditionExpression, ConditionalDefaultConfig, ConditionalEnabled, ConfirmPrompt, type CopyConfig, type CreateConfig, DefaultValue, DefaultValueConfig, DefaultValueType, type DeleteConfig, EnabledValue, type ExecConfig, ExecutableEnabled, type GitInitConfig, InitConfig, InputPrompt, MergeStrategy, type MkdirConfig, type MoveConfig, NumberPrompt, PluginHooks, PromptDefinition, PromptType, type RegexReplaceConfig, type RenameConfig, type ReplaceInFileConfig, RollbackConfig, SelectPrompt, TaskDefinition, TaskPlugin, TaskType, TasksConfiguration, type UpdateJsonConfig, VariableDefinition, type WriteConfig, callHook, clearPlugins, clearTemplateCache, collectPrompts, collectVariables, createPlugin, displayTasksDiff, evaluateCondition, executePluginTask, executeTask, getCreateDiff, getDeleteDiff, getExecDiff, getGitInitDiff, getGitRepoInfo, getPlugin, getPluginForTaskType, getPluginTaskDiff, getRegexReplaceDiff, getRenameDiff, getReplaceInFileDiff, getTaskDiff, getTemplateSourceDescription, getUpdateJsonDiff, getWriteDiff, hasInlineTemplate, hasTemplateFile, interpolateTemplate, isPluginTaskType, listPlugins, loadAndMergeTemplate, loadTasksWithInheritance, loadTemplate, loadTemplatesInOrder, log, main, mergeTemplates, processTemplate, prompt, promptYesNo, registerBuiltInPlugins, registerHooks, registerPlugin, resolveAllDefaultValues, resolveAllVariableValues, resolveDefaultValue, resolveVariableValue, runTask, runTasks, runTemplatesSequentially, runWithTasks, setNestedProperty, shouldUseHandlebars, topologicalSort, unregisterPlugin, validatePluginTask, validatePrompts, validateTemplateConfig, validateVariables };
package/dist/index.d.ts CHANGED
@@ -241,8 +241,6 @@ interface TaskDefinition {
241
241
  config: UpdateJsonConfig | WriteConfig | CreateConfig | RegexReplaceConfig | ReplaceInFileConfig | DeleteConfig | RenameConfig | GitInitConfig | ExecConfig | MoveConfig | CopyConfig | AppendConfig | MkdirConfig | Record<string, unknown>;
242
242
  dependencies?: string[];
243
243
  rollback?: RollbackConfig;
244
- prompts?: PromptDefinition[];
245
- variables?: VariableDefinition[];
246
244
  override?: MergeStrategy;
247
245
  $sourceUrl?: string;
248
246
  $templateEnabled?: EnabledValue;
@@ -473,6 +471,32 @@ declare function resolveDefaultValue<T = string | number | boolean>(defaultValue
473
471
  */
474
472
  declare function validatePrompts(prompts: PromptDefinition[]): string[];
475
473
  //#endregion
474
+ //#region src/run-tasks.d.ts
475
+ /**
476
+ * Core task execution logic shared by both main() and runWithTasks()
477
+ */
478
+ declare function runTasks(tasks: TaskDefinition[], options: {
479
+ dryRun: boolean;
480
+ force: boolean;
481
+ tasksFilePath: string | undefined;
482
+ globalVariables?: VariableDefinition[];
483
+ globalPrompts?: PromptDefinition[];
484
+ templateEnabled?: EnabledValue;
485
+ }): Promise<void>;
486
+ /**
487
+ * Run templates sequentially for variables/prompts, then all tasks together
488
+ * Phase 1: Process variables and prompts sequentially from each template
489
+ * Phase 2: Collect all tasks from all enabled templates
490
+ * Phase 3: Execute all tasks together at the end
491
+ * This allows later templates to use values from earlier templates in their conditions,
492
+ * while still executing all tasks together after all variables/prompts are resolved
493
+ */
494
+ declare function runTemplatesSequentially(templates: TasksConfiguration[], options: {
495
+ dryRun: boolean;
496
+ force: boolean;
497
+ tasksFilePath: string | undefined;
498
+ }, config?: InitConfig): Promise<void>;
499
+ //#endregion
476
500
  //#region src/task-executors.d.ts
477
501
  declare function registerBuiltInPlugins(): void;
478
502
  /**
@@ -498,6 +522,14 @@ declare function topologicalSort(tasks: TaskDefinition[]): TaskDefinition[];
498
522
  * @returns The loaded template configuration
499
523
  */
500
524
  declare function loadTemplate(templatePath: string, visitedPaths?: Set<string>): Promise<TasksConfiguration>;
525
+ /**
526
+ * Load all templates in dependency order without merging
527
+ * @param templatePath - Path or URL to the template file
528
+ * @param baseDir - Base directory or URL for resolving relative paths in extends
529
+ * @param visitedPaths - Set of already visited paths
530
+ * @returns Array of sorted templates (in dependency order, ready for sequential processing)
531
+ */
532
+ declare function loadTemplatesInOrder(templatePath: string, baseDir?: string, visitedPaths?: Set<string>): Promise<TasksConfiguration[]>;
501
533
  /**
502
534
  * Recursively load and merge templates
503
535
  * @param templatePath - Path or URL to the template file
@@ -520,13 +552,18 @@ declare function clearTemplateCache(): void;
520
552
  /**
521
553
  * Load tasks from a configuration file with template inheritance support
522
554
  * @param tasksFilePath - Path to the tasks configuration file
555
+ * @param options - Optional configuration
556
+ * @param options.sequential - If true, return templates as separate items for sequential processing
523
557
  * @returns Task configuration with tasks, optional variables, and optional prompts
524
558
  */
525
- declare function loadTasksWithInheritance(tasksFilePath: string): Promise<{
559
+ declare function loadTasksWithInheritance(tasksFilePath: string, options?: {
560
+ sequential?: boolean;
561
+ }): Promise<{
526
562
  tasks: TaskDefinition[];
527
563
  variables?: VariableDefinition[];
528
564
  prompts?: PromptDefinition[];
529
565
  enabled?: EnabledValue;
566
+ templates?: TasksConfiguration[];
530
567
  }>;
531
568
  //#endregion
532
569
  //#region src/template-utils.d.ts
@@ -656,9 +693,13 @@ declare function collectVariables(variables: VariableDefinition[], resolvedValue
656
693
  * Each variable can access values from previous variables and prompts
657
694
  * @param variables - Array of variable definitions
658
695
  * @param context - Optional context for evaluating conditional variables
696
+ * @param options - Optional resolution options
697
+ * @param options.skipConditional - If true, skip conditional variables (they will be resolved later)
659
698
  * @returns Map of variable IDs to their resolved values
660
699
  */
661
- declare function resolveAllVariableValues(variables: VariableDefinition[], context?: InitConfig): Promise<Map<string, unknown>>;
700
+ declare function resolveAllVariableValues(variables: VariableDefinition[], context?: InitConfig, options?: {
701
+ skipConditional?: boolean;
702
+ }): Promise<Map<string, unknown>>;
662
703
  //#endregion
663
704
  //#region src/variables/resolve-variable-value.d.ts
664
705
  /**
@@ -704,4 +745,4 @@ declare function runWithTasks(customTasks: TaskDefinition[], options?: {
704
745
  templateEnabled?: EnabledValue | undefined;
705
746
  }): Promise<void>;
706
747
  //#endregion
707
- export { type AppendConfig, BasePrompt, ConditionExpression, ConditionalDefaultConfig, ConditionalEnabled, ConfirmPrompt, type CopyConfig, type CreateConfig, DefaultValue, DefaultValueConfig, DefaultValueType, type DeleteConfig, EnabledValue, type ExecConfig, ExecutableEnabled, type GitInitConfig, InitConfig, InputPrompt, MergeStrategy, type MkdirConfig, type MoveConfig, NumberPrompt, PluginHooks, PromptDefinition, PromptType, type RegexReplaceConfig, type RenameConfig, type ReplaceInFileConfig, RollbackConfig, SelectPrompt, TaskDefinition, TaskPlugin, TaskType, TasksConfiguration, type UpdateJsonConfig, VariableDefinition, type WriteConfig, callHook, clearPlugins, clearTemplateCache, collectPrompts, collectVariables, createPlugin, displayTasksDiff, evaluateCondition, executePluginTask, executeTask, getCreateDiff, getDeleteDiff, getExecDiff, getGitInitDiff, getGitRepoInfo, getPlugin, getPluginForTaskType, getPluginTaskDiff, getRegexReplaceDiff, getRenameDiff, getReplaceInFileDiff, getTaskDiff, getTemplateSourceDescription, getUpdateJsonDiff, getWriteDiff, hasInlineTemplate, hasTemplateFile, interpolateTemplate, isPluginTaskType, listPlugins, loadAndMergeTemplate, loadTasksWithInheritance, loadTemplate, log, main, mergeTemplates, processTemplate, prompt, promptYesNo, registerBuiltInPlugins, registerHooks, registerPlugin, resolveAllDefaultValues, resolveAllVariableValues, resolveDefaultValue, resolveVariableValue, runTask, runWithTasks, setNestedProperty, shouldUseHandlebars, topologicalSort, unregisterPlugin, validatePluginTask, validatePrompts, validateTemplateConfig, validateVariables };
748
+ export { type AppendConfig, BasePrompt, ConditionExpression, ConditionalDefaultConfig, ConditionalEnabled, ConfirmPrompt, type CopyConfig, type CreateConfig, DefaultValue, DefaultValueConfig, DefaultValueType, type DeleteConfig, EnabledValue, type ExecConfig, ExecutableEnabled, type GitInitConfig, InitConfig, InputPrompt, MergeStrategy, type MkdirConfig, type MoveConfig, NumberPrompt, PluginHooks, PromptDefinition, PromptType, type RegexReplaceConfig, type RenameConfig, type ReplaceInFileConfig, RollbackConfig, SelectPrompt, TaskDefinition, TaskPlugin, TaskType, TasksConfiguration, type UpdateJsonConfig, VariableDefinition, type WriteConfig, callHook, clearPlugins, clearTemplateCache, collectPrompts, collectVariables, createPlugin, displayTasksDiff, evaluateCondition, executePluginTask, executeTask, getCreateDiff, getDeleteDiff, getExecDiff, getGitInitDiff, getGitRepoInfo, getPlugin, getPluginForTaskType, getPluginTaskDiff, getRegexReplaceDiff, getRenameDiff, getReplaceInFileDiff, getTaskDiff, getTemplateSourceDescription, getUpdateJsonDiff, getWriteDiff, hasInlineTemplate, hasTemplateFile, interpolateTemplate, isPluginTaskType, listPlugins, loadAndMergeTemplate, loadTasksWithInheritance, loadTemplate, loadTemplatesInOrder, log, main, mergeTemplates, processTemplate, prompt, promptYesNo, registerBuiltInPlugins, registerHooks, registerPlugin, resolveAllDefaultValues, resolveAllVariableValues, resolveDefaultValue, resolveVariableValue, runTask, runTasks, runTemplatesSequentially, runWithTasks, setNestedProperty, shouldUseHandlebars, topologicalSort, unregisterPlugin, validatePluginTask, validatePrompts, validateTemplateConfig, validateVariables };