@pixpilot/scaffoldfy 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @pixpilot/scaffoldfy
2
2
 
3
- A flexible and powerful template initialization utility for automating project setup, cleanup, and configuration tasks.
3
+ A flexible and powerful task automation utility for project setup, cleanup, and configuration.
4
4
 
5
5
  ## Features
6
6
 
@@ -9,7 +9,8 @@ A flexible and powerful template initialization utility for automating project s
9
9
  - 🔍 **Dry-Run Mode with Diff** - Preview exact changes before applying
10
10
  - 🔌 **Plugin System** - Create custom task types and lifecycle hooks
11
11
  - 💬 **Interactive Prompts** - Collect user input with input, select, confirm, number, and password prompts
12
- - 📦 **JSON/TypeScript Config** - Define tasks in JSON or TypeScript files
12
+ - **Variables** - Define reusable values from static or executable sources without user interaction
13
+ - �📦 **JSON/TypeScript Config** - Define tasks in JSON or TypeScript files
13
14
  - 🔗 **Task Dependencies** - Ensure tasks run in the correct order
14
15
  - ✅ **Type-Safe** - Full TypeScript support with JSON schema validation
15
16
  - 🎯 **Template Variables** - Use `{{variable}}` syntax for dynamic configuration
@@ -346,6 +347,7 @@ Control execution order:
346
347
  - **[Getting Started](https://pixpilot.github.io/scaffoldfy/GETTING_STARTED.html)** - Installation, CLI usage, and examples
347
348
  - **[Task Types Reference](https://pixpilot.github.io/scaffoldfy/TASK_TYPES.html)** - All 9 built-in task types
348
349
  - **[Interactive Prompts](https://pixpilot.github.io/scaffoldfy/PROMPTS.html)** - Collect user input
350
+ - **[Variables](https://pixpilot.github.io/scaffoldfy/VARIABLES.html)** - Reusable values without user interaction
349
351
  - **[Advanced Features](https://pixpilot.github.io/scaffoldfy/FEATURES.html)** - Conditional execution, global prompts, Handlebars
350
352
  - **[Template Inheritance](https://pixpilot.github.io/scaffoldfy/TEMPLATE_INHERITANCE.html)** - Extend and compose templates
351
353
  - **[Plugin System](https://pixpilot.github.io/scaffoldfy/PLUGINS.html)** - Create custom task types
package/dist/cli.cjs CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- const e=require(`./src-CFP-DJ0M.cjs`);let t=require(`node:fs`);t=e.q(t);let n=require(`node:path`);n=e.q(n);let r=require(`node:process`);r=e.q(r);let i=require(`commander`);i=e.q(i);const a=1,o=new i.Command,s=n.default.join(__dirname,`..`,`package.json`);let c=`0.0.0`;try{c=JSON.parse(t.default.readFileSync(s,`utf-8`)).version??`0.0.0`}catch{}o.name(`scaffoldfy`).description(`Initialize and configure project templates with customizable tasks`).version(c),o.option(`--dry-run`,`Run in dry mode without making any changes`).option(`--force`,`Force re-initialization even if already initialized`).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`).action(async i=>{try{let a=[],o;if(i.tasksTs!=null&&i.tasksTs!==``){let s=n.default.resolve(r.default.cwd(),i.tasksTs);if(t.default.existsSync(s)){e.U(`Loading tasks from TypeScript file: ${i.tasksTs}`,`info`),o=s;try{let t=await import(s);a=t.default??t.tasks??[],(!Array.isArray(a)||a.length===0)&&(e.U(`⚠️ No tasks found in TypeScript file or invalid format`,`warn`),e.U(`Expected default export or named export "tasks" with TaskDefinition[]`,`info`))}catch(t){e.U(`Failed to load TypeScript tasks file: ${i.tasksTs}`,`error`),t instanceof Error&&e.U(` Error: ${t.message}`,`error`),r.default.exit(1)}}}if(a.length===0&&i.tasksFile!=null&&i.tasksFile!==``){let s=n.default.resolve(r.default.cwd(),i.tasksFile);if(t.default.existsSync(s)){o=s;try{a=await e.a(s),Array.isArray(a)||(e.U(`❌ Invalid tasks file format`,`error`),e.U(`Expected JSON with { "tasks": [...] } structure`,`info`),r.default.exit(1))}catch(t){e.U(`Failed to load JSON tasks file: ${i.tasksFile}`,`error`),t instanceof Error&&e.U(` Error: ${t.message}`,`error`),r.default.exit(1)}}else e.U(`Tasks file not found: ${i.tasksFile}`,`warn`)}a.length===0&&(e.U(`❌ No tasks defined`,`error`),console.log(``),e.U(`Please provide tasks using one of these methods:`,`info`),e.U(` 1. Create a template-tasks.json file in the current directory`,`info`),e.U(` 2. Create a template-tasks.ts file in the current directory`,`info`),e.U(` 3. Use --tasks-file option to specify a different JSON file`,`info`),e.U(` 4. Use --tasks-ts option to specify a different TypeScript file`,`info`),console.log(``),e.U(`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)),console.log(``),r.default.exit(1)),console.log(``),e.U(`Loaded ${a.length} task(s)`,`success`),console.log(``),await e.n(a,{dryRun:i.dryRun,force:i.force,tasksFilePath:o})}catch(t){if(e.U(`❌ CLI execution failed`,`error`),t instanceof Error){e.U(`Error: ${t.message}`,`error`);let n=r.default.env.DEBUG;n!=null&&n!==``&&console.error(t.stack)}else console.error(t);r.default.exit(1)}}),o.parse(r.default.argv);
2
+ const e=require(`./src-BcQJMu0M.cjs`);let t=require(`node:fs`);t=e.Y(t);let n=require(`node:path`);n=e.Y(n);let r=require(`node:process`);r=e.Y(r);let i=require(`commander`);i=e.Y(i);const a=1,o=new i.Command,s=n.default.join(__dirname,`..`,`package.json`);let c=`0.0.0`;try{c=JSON.parse(t.default.readFileSync(s,`utf-8`)).version??`0.0.0`}catch{}o.name(`scaffoldfy`).description(`Automate project setup and configuration with customizable tasks`).version(c),o.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`).action(async i=>{try{let a=[],o,s,c;if(i.tasksTs!=null&&i.tasksTs!==``){let o=n.default.resolve(r.default.cwd(),i.tasksTs);if(t.default.existsSync(o)){e.G(`Loading tasks from TypeScript file: ${i.tasksTs}`,`info`),c=o;try{let t=await import(o);a=t.default??t.tasks??[],(!Array.isArray(a)||a.length===0)&&(e.G(`⚠️ No tasks found in TypeScript file or invalid format`,`warn`),e.G(`Expected default export or named export "tasks" with TaskDefinition[]`,`info`))}catch(t){e.G(`Failed to load TypeScript tasks file: ${i.tasksTs}`,`error`),t instanceof Error&&e.G(` Error: ${t.message}`,`error`),r.default.exit(1)}}}if(a.length===0&&i.tasksFile!=null&&i.tasksFile!==``){let l=n.default.resolve(r.default.cwd(),i.tasksFile);if(t.default.existsSync(l)){c=l;try{let t=await e.f(l);a=t.tasks,o=t.variables,s=t.prompts,Array.isArray(a)||(e.G(`❌ Invalid tasks file format`,`error`),e.G(`Expected JSON with { "tasks": [...] } structure`,`info`),r.default.exit(1))}catch(t){e.G(`Failed to load JSON tasks file: ${i.tasksFile}`,`error`),t instanceof Error&&e.G(` Error: ${t.message}`,`error`),r.default.exit(1)}}else e.G(`Tasks file not found: ${i.tasksFile}`,`warn`)}let l=s!=null&&s.length>0||o!=null&&o.length>0;a.length===0&&!l&&(e.G(`❌ No tasks defined`,`error`),e.G(`Please provide tasks using one of these methods:`,`info`),e.G(` 1. Create a template-tasks.json file in the current directory`,`info`),e.G(` 2. Create a template-tasks.ts file in the current directory`,`info`),e.G(` 3. Use --tasks-file option to specify a different JSON file`,`info`),e.G(` 4. Use --tasks-ts option to specify a different TypeScript file`,`info`),e.G(`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)),r.default.exit(1)),a.length===0?e.G(`Loaded template with 0 tasks (template may only provide prompts/variables for extending)`,`info`):e.G(`Loaded ${a.length} task(s)`,`success`),await e.n(a,{dryRun:i.dryRun,force:i.force,tasksFilePath:c,globalVariables:o,globalPrompts:s})}catch(t){if(e.G(`❌ CLI execution failed`,`error`),t instanceof Error){e.G(`Error: ${t.message}`,`error`);let n=r.default.env.DEBUG;n!=null&&n!==``&&console.error(t.stack)}else console.error(t);r.default.exit(1)}}),o.parse(r.default.argv);
package/dist/cli.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{U as e,a as t,n}from"./src-RfAsa6ai.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";const c=()=>i(import.meta.url),l=(()=>r.dirname(c()))(),u=new s,d=r.join(l,`..`,`package.json`);let f=`0.0.0`;try{f=JSON.parse(a.readFileSync(d,`utf-8`)).version??`0.0.0`}catch{}u.name(`scaffoldfy`).description(`Initialize and configure project templates with customizable tasks`).version(f),u.option(`--dry-run`,`Run in dry mode without making any changes`).option(`--force`,`Force re-initialization even if already initialized`).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`).action(async i=>{try{let s=[],c;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`),c=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)){c=n;try{s=await t(n),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`)}s.length===0&&(e(`❌ No tasks defined`,`error`),console.log(``),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`),console.log(``),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)),console.log(``),o.exit(1)),console.log(``),e(`Loaded ${s.length} task(s)`,`success`),console.log(``),await n(s,{dryRun:i.dryRun,force:i.force,tasksFilePath:c})}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)}}),u.parse(o.argv);export{};
2
+ import{G as e,f as t,n}from"./src-gsac5lFQ.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";const c=()=>i(import.meta.url),l=(()=>r.dirname(c()))(),u=new s,d=r.join(l,`..`,`package.json`);let f=`0.0.0`;try{f=JSON.parse(a.readFileSync(d,`utf-8`)).version??`0.0.0`}catch{}u.name(`scaffoldfy`).description(`Automate project setup and configuration with customizable tasks`).version(f),u.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`).action(async i=>{try{let s=[],c,l,u;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`),u=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)){u=n;try{let r=await t(n);s=r.tasks,c=r.variables,l=r.prompts,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 d=l!=null&&l.length>0||c!=null&&c.length>0;s.length===0&&!d&&(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:u,globalVariables:c,globalPrompts:l})}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)}}),u.parse(o.argv);export{};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- const e=require(`./src-CFP-DJ0M.cjs`);exports.callHook=e._,exports.clearPlugins=e.v,exports.clearTemplateCache=e.r,exports.collectPrompts=e.g,exports.createPlugin=e.y,exports.displayTasksDiff=e.A,exports.evaluateCondition=e.B,exports.executePluginTask=e.b,exports.executeTask=e.l,exports.getDeleteDiff=e.j,exports.getExecDiff=e.M,exports.getGitInitDiff=e.N,exports.getGitRepoInfo=e.V,exports.getPlugin=e.x,exports.getPluginForTaskType=e.S,exports.getPluginTaskDiff=e.C,exports.getRegexReplaceDiff=e.P,exports.getRenameDiff=e.F,exports.getReplaceInFileDiff=e.I,exports.getTaskDiff=e.L,exports.getTemplateDiff=e.R,exports.getUpdateJsonDiff=e.z,exports.interpolateTemplate=e.H,exports.isPluginTaskType=e.w,exports.listPlugins=e.T,exports.loadAndMergeTemplate=e.i,exports.loadInitializationState=e.d,exports.loadTasksWithInheritance=e.a,exports.loadTemplate=e.o,exports.log=e.U,exports.main=e.t,exports.mergeTemplates=e.s,exports.prompt=e.W,exports.promptYesNo=e.G,exports.registerHooks=e.E,exports.registerPlugin=e.D,exports.resolveAllDefaultValues=e.m,exports.resolveDefaultValue=e.h,exports.runTask=e.u,exports.runWithTasks=e.n,exports.saveInitializationState=e.f,exports.setNestedProperty=e.K,exports.topologicalSort=e.c,exports.unregisterPlugin=e.O,exports.validatePluginTask=e.k,exports.validatePrompts=e.p;
1
+ const e=require(`./src-BcQJMu0M.cjs`);exports.callHook=e.y,exports.clearPlugins=e.b,exports.clearTemplateCache=e.u,exports.collectPrompts=e.v,exports.collectVariables=e.o,exports.createPlugin=e.x,exports.displayTasksDiff=e.M,exports.evaluateCondition=e.H,exports.executePluginTask=e.S,exports.executeTask=e.c,exports.getDeleteDiff=e.N,exports.getExecDiff=e.P,exports.getGitInitDiff=e.F,exports.getGitRepoInfo=e.U,exports.getPlugin=e.C,exports.getPluginForTaskType=e.w,exports.getPluginTaskDiff=e.T,exports.getRegexReplaceDiff=e.I,exports.getRenameDiff=e.L,exports.getReplaceInFileDiff=e.R,exports.getTaskDiff=e.z,exports.getTemplateDiff=e.B,exports.getUpdateJsonDiff=e.V,exports.interpolateTemplate=e.W,exports.isPluginTaskType=e.E,exports.listPlugins=e.D,exports.loadAndMergeTemplate=e.d,exports.loadTasksWithInheritance=e.f,exports.loadTemplate=e.p,exports.log=e.G,exports.main=e.t,exports.mergeTemplates=e.m,exports.prompt=e.K,exports.promptYesNo=e.q,exports.registerHooks=e.O,exports.registerPlugin=e.k,exports.resolveAllDefaultValues=e.g,exports.resolveAllVariableValues=e.i,exports.resolveDefaultValue=e._,exports.resolveVariableValue=e.a,exports.runTask=e.l,exports.runWithTasks=e.n,exports.setNestedProperty=e.J,exports.topologicalSort=e.s,exports.unregisterPlugin=e.A,exports.validatePluginTask=e.j,exports.validatePrompts=e.h,exports.validateVariables=e.r;
package/dist/index.d.cts CHANGED
@@ -1,7 +1,75 @@
1
+ //#region src/plugins/create/types.d.ts
2
+
3
+ interface CreateConfig {
4
+ file: string;
5
+ template?: string;
6
+ templateFile?: string;
7
+ condition?: ConditionExpression;
8
+ }
9
+ //#endregion
10
+ //#region src/plugins/delete/types.d.ts
11
+ interface DeleteConfig {
12
+ paths: string[];
13
+ condition?: ConditionExpression;
14
+ }
15
+ //#endregion
16
+ //#region src/plugins/exec/types.d.ts
17
+ interface ExecConfig {
18
+ command: string;
19
+ cwd?: string;
20
+ condition?: ConditionExpression;
21
+ }
22
+ //#endregion
23
+ //#region src/plugins/git-init/types.d.ts
24
+ interface GitInitConfig {
25
+ removeExisting: boolean;
26
+ initialCommit: boolean;
27
+ message?: string;
28
+ condition?: ConditionExpression;
29
+ }
30
+ //#endregion
31
+ //#region src/plugins/regex-replace/types.d.ts
32
+ interface RegexReplaceConfig {
33
+ file: string;
34
+ pattern: string;
35
+ flags?: string;
36
+ replacement: string;
37
+ condition?: ConditionExpression;
38
+ }
39
+ //#endregion
40
+ //#region src/plugins/rename/types.d.ts
41
+ interface RenameConfig {
42
+ from: string;
43
+ to: string;
44
+ condition?: ConditionExpression;
45
+ }
46
+ //#endregion
47
+ //#region src/plugins/replace-in-file/types.d.ts
48
+ interface ReplaceInFileConfig {
49
+ file: string;
50
+ replacements: Array<{
51
+ find: string;
52
+ replace: string;
53
+ }>;
54
+ condition?: ConditionExpression;
55
+ }
56
+ //#endregion
57
+ //#region src/plugins/template/types.d.ts
58
+ interface TemplateConfig {
59
+ file: string;
60
+ template?: string;
61
+ templateFile?: string;
62
+ condition?: ConditionExpression;
63
+ }
64
+ //#endregion
65
+ //#region src/plugins/update-json/types.d.ts
66
+ interface UpdateJsonConfig {
67
+ file: string;
68
+ updates: Record<string, unknown>;
69
+ condition?: ConditionExpression;
70
+ }
71
+ //#endregion
1
72
  //#region src/types.d.ts
2
- /**
3
- * Task Types and Interfaces for Template Initialization
4
- */
5
73
  interface InitConfig {
6
74
  [key: string]: unknown;
7
75
  }
@@ -29,12 +97,23 @@ interface DefaultValueConfig<T = string | number | boolean> {
29
97
  * - For explicit static values, use { type: 'static', value: yourValue }
30
98
  */
31
99
  type DefaultValue<T = string | number | boolean> = T | DefaultValueConfig<T>;
100
+ /**
101
+ * Conditional enabled configuration for prompts and tasks
102
+ * Allows dynamic enabling/disabling based on runtime conditions
103
+ */
104
+ interface ConditionalEnabled {
105
+ condition: ConditionExpression;
106
+ }
107
+ /**
108
+ * Type for enabled field that can be boolean or conditional
109
+ */
110
+ type EnabledValue = boolean | ConditionalEnabled;
32
111
  interface BasePrompt {
33
112
  id: string;
34
113
  type: PromptType;
35
114
  message: string;
36
115
  required?: boolean;
37
- global?: boolean;
116
+ enabled?: EnabledValue;
38
117
  }
39
118
  interface InputPrompt extends BasePrompt {
40
119
  type: 'input' | 'password';
@@ -60,15 +139,26 @@ interface ConfirmPrompt extends BasePrompt {
60
139
  default?: DefaultValue<boolean>;
61
140
  }
62
141
  type PromptDefinition = InputPrompt | NumberPrompt | SelectPrompt | ConfirmPrompt;
142
+ /**
143
+ * Variable value configuration for defining optional global or task-scoped variables
144
+ * Variables are similar to prompts but don't require user input - they can have static
145
+ * values or values resolved from executable commands
146
+ *
147
+ * Note: Top-level variables are always global. Task-level variables are task-scoped.
148
+ */
149
+ interface VariableDefinition {
150
+ id: string;
151
+ value: DefaultValue;
152
+ }
63
153
  /**
64
154
  * JavaScript expression evaluated at runtime to determine if a task or operation should execute.
65
- * Has access to all prompt values and config variables.
155
+ * Has access to all prompt values, variables, and config variables.
66
156
  * @example "useTypeScript === true"
67
157
  * @example "nodeVersion >= 16 && includeTests === true"
68
158
  * @example "packageManager === 'pnpm'"
69
159
  */
70
160
  type ConditionExpression = string;
71
- type TaskType = 'update-json' | 'template' | 'regex-replace' | 'replace-in-file' | 'delete' | 'rename' | 'git-init' | 'exec';
161
+ type TaskType = 'update-json' | 'template' | 'create' | 'regex-replace' | 'replace-in-file' | 'delete' | 'rename' | 'git-init' | 'exec';
72
162
  interface RollbackConfig {
73
163
  type: TaskType;
74
164
  config: unknown;
@@ -78,71 +168,23 @@ interface TaskDefinition {
78
168
  name: string;
79
169
  description: string;
80
170
  required: boolean;
81
- enabled: boolean;
171
+ enabled: EnabledValue;
82
172
  type: TaskType;
83
- config: UpdateJsonConfig | TemplateConfig | RegexReplaceConfig | ReplaceInFileConfig | DeleteConfig | RenameConfig | GitInitConfig | ExecConfig | Record<string, unknown>;
173
+ config: UpdateJsonConfig | TemplateConfig | CreateConfig | RegexReplaceConfig | ReplaceInFileConfig | DeleteConfig | RenameConfig | GitInitConfig | ExecConfig | Record<string, unknown>;
84
174
  dependencies?: string[];
85
175
  rollback?: RollbackConfig;
86
176
  prompts?: PromptDefinition[];
87
- }
88
- interface UpdateJsonConfig {
89
- file: string;
90
- updates: Record<string, unknown>;
91
- condition?: ConditionExpression;
92
- }
93
- interface TemplateConfig {
94
- file: string;
95
- template?: string;
96
- templateFile?: string;
97
- condition?: ConditionExpression;
98
- }
99
- interface RegexReplaceConfig {
100
- file: string;
101
- pattern: string;
102
- flags?: string;
103
- replacement: string;
104
- condition?: ConditionExpression;
105
- }
106
- interface ReplaceInFileConfig {
107
- file: string;
108
- replacements: Array<{
109
- find: string;
110
- replace: string;
111
- }>;
112
- condition?: ConditionExpression;
113
- }
114
- interface DeleteConfig {
115
- paths: string[];
116
- condition?: ConditionExpression;
117
- }
118
- interface RenameConfig {
119
- from: string;
120
- to: string;
121
- condition?: ConditionExpression;
122
- }
123
- interface GitInitConfig {
124
- removeExisting: boolean;
125
- initialCommit: boolean;
126
- message?: string;
127
- condition?: ConditionExpression;
128
- }
129
- interface ExecConfig {
130
- command: string;
131
- cwd?: string;
132
- condition?: ConditionExpression;
133
- }
134
- interface InitializationMetadata {
135
- initializedAt: string;
136
- config: InitConfig;
137
- completedTasks: string[];
138
- version: string;
177
+ variables?: VariableDefinition[];
178
+ $sourceUrl?: string;
139
179
  }
140
180
  /**
141
181
  * Configuration file structure for template tasks
142
182
  */
143
183
  interface TasksConfiguration {
144
184
  extends?: string | string[];
145
- tasks: TaskDefinition[];
185
+ variables?: VariableDefinition[];
186
+ prompts?: PromptDefinition[];
187
+ tasks?: TaskDefinition[];
146
188
  }
147
189
  /**
148
190
  * Plugin interface for custom task types
@@ -319,11 +361,13 @@ declare function createPlugin(name: string, taskType: string, execute: (task: Ta
319
361
  //#region src/prompts/collect-prompts.d.ts
320
362
  /**
321
363
  * Collect prompt answers from task-defined prompts
364
+ * Only prompts with enabled=true (or enabled condition that evaluates to true) will be shown
322
365
  * @param prompts - Array of prompt definitions from tasks
323
366
  * @param resolvedDefaults - Map of pre-resolved default values
367
+ * @param config - Current configuration context (for evaluating enabled conditions)
324
368
  * @returns Object mapping prompt IDs to their values
325
369
  */
326
- declare function collectPrompts(prompts: PromptDefinition[], resolvedDefaults?: Map<string, unknown>): Promise<Record<string, unknown>>;
370
+ declare function collectPrompts(prompts: PromptDefinition[], resolvedDefaults?: Map<string, unknown>, config?: InitConfig): Promise<Record<string, unknown>>;
327
371
  //#endregion
328
372
  //#region src/prompts/resolve-all-default-values.d.ts
329
373
  /**
@@ -350,16 +394,6 @@ declare function resolveDefaultValue<T = string | number | boolean>(defaultValue
350
394
  */
351
395
  declare function validatePrompts(prompts: PromptDefinition[]): string[];
352
396
  //#endregion
353
- //#region src/state.d.ts
354
- /**
355
- * Load initialization state from file
356
- */
357
- declare function loadInitializationState(): InitializationMetadata | null;
358
- /**
359
- * Save initialization state to file
360
- */
361
- declare function saveInitializationState(config: InitConfig, completedTasks: string[], dryRun?: boolean): void;
362
- //#endregion
363
397
  //#region src/task-executors.d.ts
364
398
  /**
365
399
  * Execute a task based on its type
@@ -406,9 +440,13 @@ declare function clearTemplateCache(): void;
406
440
  /**
407
441
  * Load tasks from a configuration file with template inheritance support
408
442
  * @param tasksFilePath - Path to the tasks configuration file
409
- * @returns Array of task definitions
443
+ * @returns Task configuration with tasks, optional variables, and optional prompts
410
444
  */
411
- declare function loadTasksWithInheritance(tasksFilePath: string): Promise<TaskDefinition[]>;
445
+ declare function loadTasksWithInheritance(tasksFilePath: string): Promise<{
446
+ tasks: TaskDefinition[];
447
+ variables?: VariableDefinition[];
448
+ prompts?: PromptDefinition[];
449
+ }>;
412
450
  //#endregion
413
451
  //#region src/utils.d.ts
414
452
  /**
@@ -444,24 +482,65 @@ declare function setNestedProperty(obj: Record<string, unknown>, propertyPath: s
444
482
  */
445
483
  declare function evaluateCondition(condition: string, config: InitConfig): boolean;
446
484
  //#endregion
485
+ //#region src/variables/collect-variables.d.ts
486
+ /**
487
+ * Collect variable values from resolved variables
488
+ * Variables don't require user interaction - they're just resolved from static
489
+ * values or executable commands
490
+ *
491
+ * @param variables - Array of variable definitions
492
+ * @param resolvedValues - Map of pre-resolved variable values
493
+ * @returns Object mapping variable IDs to their values
494
+ */
495
+ declare function collectVariables(variables: VariableDefinition[], resolvedValues?: Map<string, unknown>): Record<string, unknown>;
496
+ //#endregion
497
+ //#region src/variables/resolve-all-variable-values.d.ts
498
+ /**
499
+ * Pre-resolve all variable values (execute commands in parallel for efficiency)
500
+ * @param variables - Array of variable definitions
501
+ * @returns Map of variable IDs to their resolved values
502
+ */
503
+ declare function resolveAllVariableValues(variables: VariableDefinition[]): Promise<Map<string, unknown>>;
504
+ //#endregion
505
+ //#region src/variables/resolve-variable-value.d.ts
506
+ /**
507
+ * Resolve a variable value that may be static or executable
508
+ * @param value - The variable value configuration
509
+ * @param variableId - The variable ID for error reporting
510
+ * @returns The resolved variable value
511
+ */
512
+ declare function resolveVariableValue<T = string | number | boolean>(value: DefaultValue<T>, variableId: string): Promise<T | undefined>;
513
+ //#endregion
514
+ //#region src/variables/validate-variables.d.ts
515
+ /**
516
+ * Validate variable definitions for common errors
517
+ * @param variables - Array of variable definitions to validate
518
+ * @returns Array of error messages (empty if no errors)
519
+ */
520
+ declare function validateVariables(variables: VariableDefinition[]): string[];
521
+ //#endregion
447
522
  //#region src/index.d.ts
448
523
  /**
449
- * Main function for running initialization with default/empty tasks
524
+ * Main function for executing tasks with default/empty tasks array
450
525
  * For most use cases, you should use runWithTasks() with your custom tasks
451
526
  */
452
527
  declare function main(customTasks?: TaskDefinition[]): Promise<void>;
453
528
  /**
454
- * Run initialization with custom tasks
529
+ * Execute tasks with custom task definitions
455
530
  * @param customTasks - Array of task definitions to execute
456
531
  * @param options - Optional configuration
457
532
  * @param options.dryRun - Preview changes without applying them
458
- * @param options.force - Force re-initialization even if already initialized
533
+ * @param options.force - Force execution even if checks fail
459
534
  * @param options.tasksFilePath - Path to the tasks file
535
+ * @param options.globalVariables - Optional top-level global variables
536
+ * @param options.globalPrompts - Optional top-level global prompts
460
537
  */
461
538
  declare function runWithTasks(customTasks: TaskDefinition[], options?: {
462
539
  dryRun?: boolean | undefined;
463
540
  force?: boolean | undefined;
464
541
  tasksFilePath?: string | undefined;
542
+ globalVariables?: VariableDefinition[] | undefined;
543
+ globalPrompts?: PromptDefinition[] | undefined;
465
544
  }): Promise<void>;
466
545
  //#endregion
467
- export { BasePrompt, ConditionExpression, ConfirmPrompt, DefaultValue, DefaultValueConfig, DefaultValueType, DeleteConfig, ExecConfig, GitInitConfig, InitConfig, InitializationMetadata, InputPrompt, NumberPrompt, PluginHooks, PromptDefinition, PromptType, RegexReplaceConfig, RenameConfig, ReplaceInFileConfig, RollbackConfig, SelectPrompt, TaskDefinition, TaskPlugin, TaskType, TasksConfiguration, TemplateConfig, UpdateJsonConfig, callHook, clearPlugins, clearTemplateCache, collectPrompts, createPlugin, displayTasksDiff, evaluateCondition, executePluginTask, executeTask, getDeleteDiff, getExecDiff, getGitInitDiff, getGitRepoInfo, getPlugin, getPluginForTaskType, getPluginTaskDiff, getRegexReplaceDiff, getRenameDiff, getReplaceInFileDiff, getTaskDiff, getTemplateDiff, getUpdateJsonDiff, interpolateTemplate, isPluginTaskType, listPlugins, loadAndMergeTemplate, loadInitializationState, loadTasksWithInheritance, loadTemplate, log, main, mergeTemplates, prompt, promptYesNo, registerHooks, registerPlugin, resolveAllDefaultValues, resolveDefaultValue, runTask, runWithTasks, saveInitializationState, setNestedProperty, topologicalSort, unregisterPlugin, validatePluginTask, validatePrompts };
546
+ export { BasePrompt, ConditionExpression, ConditionalEnabled, ConfirmPrompt, type CreateConfig, DefaultValue, DefaultValueConfig, DefaultValueType, type DeleteConfig, EnabledValue, type ExecConfig, type GitInitConfig, InitConfig, InputPrompt, NumberPrompt, PluginHooks, PromptDefinition, PromptType, type RegexReplaceConfig, type RenameConfig, type ReplaceInFileConfig, RollbackConfig, SelectPrompt, TaskDefinition, TaskPlugin, TaskType, TasksConfiguration, type TemplateConfig, type UpdateJsonConfig, VariableDefinition, callHook, clearPlugins, clearTemplateCache, collectPrompts, collectVariables, createPlugin, displayTasksDiff, evaluateCondition, executePluginTask, executeTask, getDeleteDiff, getExecDiff, getGitInitDiff, getGitRepoInfo, getPlugin, getPluginForTaskType, getPluginTaskDiff, getRegexReplaceDiff, getRenameDiff, getReplaceInFileDiff, getTaskDiff, getTemplateDiff, getUpdateJsonDiff, interpolateTemplate, isPluginTaskType, listPlugins, loadAndMergeTemplate, loadTasksWithInheritance, loadTemplate, log, main, mergeTemplates, prompt, promptYesNo, registerHooks, registerPlugin, resolveAllDefaultValues, resolveAllVariableValues, resolveDefaultValue, resolveVariableValue, runTask, runWithTasks, setNestedProperty, topologicalSort, unregisterPlugin, validatePluginTask, validatePrompts, validateVariables };