@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 +4 -2
- package/dist/cli.cjs +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +157 -78
- package/dist/index.d.ts +157 -78
- package/dist/index.js +1 -1
- package/dist/src-BcQJMu0M.cjs +17 -0
- package/dist/src-gsac5lFQ.js +17 -0
- package/package.json +4 -4
- package/schema/tasks.schema.json +264 -10
- package/dist/src-CFP-DJ0M.cjs +0 -13
- package/dist/src-RfAsa6ai.js +0 -13
package/dist/index.d.ts
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
443
|
+
* @returns Task configuration with tasks, optional variables, and optional prompts
|
|
410
444
|
*/
|
|
411
|
-
declare function loadTasksWithInheritance(tasksFilePath: string): Promise<
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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,
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{A as e,B as t,C as n,D as r,E as i,F as a,G as o,H as s,I as c,
|
|
1
|
+
import{A as e,B as t,C as n,D as r,E as i,F as a,G as o,H as s,I as c,J as l,K as u,L as d,M as f,N as p,O as m,P as h,R as g,S as _,T as v,U as y,V as b,W as x,_ as S,a as C,b as w,c as T,d as E,f as D,g as O,h as k,i as A,j,k as M,l as N,m as P,n as F,o as I,p as L,q as R,r as z,s as B,t as V,u as H,v as U,w as W,x as G,y as K,z as q}from"./src-gsac5lFQ.js";export{K as callHook,w as clearPlugins,H as clearTemplateCache,U as collectPrompts,I as collectVariables,G as createPlugin,f as displayTasksDiff,s as evaluateCondition,_ as executePluginTask,T as executeTask,p as getDeleteDiff,h as getExecDiff,a as getGitInitDiff,y as getGitRepoInfo,n as getPlugin,W as getPluginForTaskType,v as getPluginTaskDiff,c as getRegexReplaceDiff,d as getRenameDiff,g as getReplaceInFileDiff,q as getTaskDiff,t as getTemplateDiff,b as getUpdateJsonDiff,x as interpolateTemplate,i as isPluginTaskType,r as listPlugins,E as loadAndMergeTemplate,D as loadTasksWithInheritance,L as loadTemplate,o as log,V as main,P as mergeTemplates,u as prompt,R as promptYesNo,m as registerHooks,M as registerPlugin,O as resolveAllDefaultValues,A as resolveAllVariableValues,S as resolveDefaultValue,C as resolveVariableValue,N as runTask,F as runWithTasks,l as setNestedProperty,B as topologicalSort,e as unregisterPlugin,j as validatePluginTask,k as validatePrompts,z as validateVariables};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
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(`node:fs`);c=s(c);let l=require(`node:path`);l=s(l);let u=require(`node:process`);u=s(u);let d=require(`node:child_process`);d=s(d);let f=require(`node:util`);f=s(f);let p=require(`node:readline`);p=s(p);let m=require(`handlebars`);m=s(m);let h=require(`@inquirer/prompts`);h=s(h);function g(){return{}}function _(e,t){return e===void 0?!0:typeof e==`boolean`?e:typeof e==`object`&&`condition`in e?w(e.condition,t):!1}function v(){try{let e=(0,d.execSync)(`git remote get-url origin`,{encoding:`utf-8`}).trim(),t=e.match(/github\.com[:/](?<owner>[^/]+)\/(?<name>[^/]+)$/u);if(t?.groups){let{owner:n,name:r}=t.groups,i=r;return i.endsWith(`.git`)&&(i=i.slice(0,-4)),{owner:n,name:i,url:e}}return null}catch{return null}}async function y(e,t){let n=p.default.createInterface({input:u.default.stdin,output:u.default.stdout});return new Promise(r=>{let i;i=t==null?`${e}: `:`${e} (${t}): `,n.question(i,e=>{n.close(),r(e.trim()||(t??``))})})}async function b(e,t=!1){return y(`${e} (${t?`Y/n`:`y/N`})`,t?`y`:`n`).then(e=>e.toLowerCase()===`y`||e.toLowerCase()===`yes`)}function x(e,t=`info`){console.log(`${{info:`\x1B[36m`,success:`\x1B[32m`,error:`\x1B[31m`,warn:`\x1B[33m`}[t]}${{info:`ℹ`,success:`✓`,error:`✗`,warn:`⚠`}[t]} ${e}[0m`)}function S(e,t){return e.replace(/\{\{(?<key>\w+)\}\}/gu,(e,n)=>t[n]?.toString()??``)}function C(e,t,n){let r=t.split(`.`),i=e;for(let e=0;e<r.length-1;e++){let t=r[e];t!=null&&t!==``&&((!(t in i)||typeof i[t]!=`object`||i[t]===null)&&(i[t]={}),i=i[t])}let a=r[r.length-1];a!=null&&a!==``&&(i[a]=n)}function w(e,t){try{let n={...t};return Function(...Object.keys(n),`'use strict'; return (${e})`)(...Object.values(n))}catch(t){return x(`Failed to evaluate condition: ${e}`,`warn`),t instanceof Error&&x(` Error: ${t.message}`,`warn`),!1}}function ee(e,t){try{let n=l.default.isAbsolute(e)?e:l.default.join(u.default.cwd(),e);if(!c.default.existsSync(n))throw Error(`Template file not found: ${e}`);return te(c.default.readFileSync(n,`utf-8`),t)}catch(t){throw x(`Failed to read template file: ${e}`,`error`),t instanceof Error&&x(` Error: ${t.message}`,`error`),t}}function te(e,t){try{return m.default.compile(e)(t)}catch(e){throw x(`Failed to compile Handlebars template`,`error`),e instanceof Error&&x(` Error: ${e.message}`,`error`),e}}const T=(0,f.promisify)(c.default.readFile),ne=2,re=10,ie=55,E={reset:`\x1B[0m`,red:`\x1B[31m`,green:`\x1B[32m`,yellow:`\x1B[33m`,blue:`\x1B[34m`,cyan:`\x1B[36m`,gray:`\x1B[90m`};function D(e,t){switch(t){case`add`:return`${E.green}+ ${e}${E.reset}`;case`remove`:return`${E.red}- ${e}${E.reset}`;case`context`:return`${E.gray} ${e}${E.reset}`;default:return e}}function O(e,t){let n=e.split(`
|
|
2
|
+
`),r=t.split(`
|
|
3
|
+
`),i=[],a=Math.max(n.length,r.length);for(let e=0;e<a;e++){let t=n[e],a=r[e];t===a?t!==void 0&&i.push(D(t,`context`)):(t!==void 0&&i.push(D(t,`remove`)),a!==void 0&&i.push(D(a,`add`)))}return i}async function k(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t))return`${E.yellow}⊘ Condition not met - task would be skipped${E.reset}`;let n=l.default.join(u.default.cwd(),e.file);if(!c.default.existsSync(n))return`${E.red}✗ File not found: ${e.file}${E.reset}`;try{let r=await T(n,`utf-8`),i=JSON.parse(r),a={...i};function o(e){if(typeof e==`string`)return S(e,t);if(Array.isArray(e))return e.map(e=>o(e));if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[n]=o(r);return t}return e}for(let[t,n]of Object.entries(e.updates)){let e=o(n);t.includes(`.`)?C(i,t,e):i[t]=e}let s=JSON.stringify(a,null,2),c=JSON.stringify(i,null,2);if(s===c)return`${E.cyan}→ No changes${E.reset}`;let l=O(s,c);return`${E.blue}File: ${e.file}${E.reset}\n${l.join(`
|
|
4
|
+
`)}`}catch(e){return`${E.red}✗ Error: ${e instanceof Error?e.message:String(e)}${E.reset}`}}async function ae(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t))return`${E.yellow}⊘ Condition not met - task would be skipped${E.reset}`;if(e.template==null||e.template===``)return`${E.red}✗ No template content provided for file: ${e.file}${E.reset}`;let n=l.default.join(u.default.cwd(),e.file),r=S(e.template,t);if(!c.default.existsSync(n)){let t=r.split(`
|
|
5
|
+
`).slice(0,10).join(`
|
|
6
|
+
`),n=r.split(`
|
|
7
|
+
`).length>10;return`${E.blue}File: ${e.file}${E.reset}\n${E.green}+ New file would be created${E.reset}\n${E.gray}Content preview:${E.reset}\n${t}${n?`
|
|
8
|
+
...`:``}`}try{let t=await T(n,`utf-8`);if(t===r)return`${E.cyan}→ No changes${E.reset}`;let i=O(t,r);return`${E.blue}File: ${e.file}${E.reset}\n${i.join(`
|
|
9
|
+
`)}`}catch(e){return`${E.red}✗ Error: ${e instanceof Error?e.message:String(e)}${E.reset}`}}async function oe(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t))return`${E.yellow}⊘ Condition not met - task would be skipped${E.reset}`;let n=l.default.join(u.default.cwd(),e.file);if(c.default.existsSync(n))return`${E.cyan}→ File already exists, would be skipped: ${e.file}${E.reset}`;let r=e.template!=null&&e.template!==``,i=e.templateFile!=null&&e.templateFile!==``;if(!r&&!i)return`${E.red}✗ No template content provided for file: ${e.file}${E.reset}`;try{let n;if(r)n=S(e.template,t);else return`${E.blue}File: ${e.file}${E.reset}\n${E.green}+ New file would be created from template: ${e.templateFile}${E.reset}`;let i=n.split(`
|
|
10
|
+
`).slice(0,10).join(`
|
|
11
|
+
`),a=n.split(`
|
|
12
|
+
`).length>10;return`${E.blue}File: ${e.file}${E.reset}\n${E.green}+ New file would be created${E.reset}\n${E.gray}Content preview:${E.reset}\n${i}${a?`
|
|
13
|
+
...`:``}`}catch(e){return`${E.red}✗ Error: ${e instanceof Error?e.message:String(e)}${E.reset}`}}async function se(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t))return`${E.yellow}⊘ Condition not met - task would be skipped${E.reset}`;let n=l.default.join(u.default.cwd(),e.file);if(!c.default.existsSync(n))return`${E.red}✗ File not found: ${e.file}${E.reset}`;try{let r=await T(n,`utf-8`),i=new RegExp(e.pattern,e.flags??`g`),a=S(e.replacement,t),o=r.replace(i,a);if(r===o)return`${E.cyan}→ No matches found${E.reset}`;let s=O(r,o);return`${E.blue}File: ${e.file}${E.reset}\n${s.join(`
|
|
14
|
+
`)}`}catch(e){return`${E.red}✗ Error: ${e instanceof Error?e.message:String(e)}${E.reset}`}}async function A(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t))return`${E.yellow}⊘ Condition not met - task would be skipped${E.reset}`;let n=l.default.join(u.default.cwd(),e.file);if(!c.default.existsSync(n))return`${E.red}✗ File not found: ${e.file}${E.reset}`;try{let r=await T(n,`utf-8`),i=r;for(let{find:n,replace:i}of e.replacements){let e=S(n,t),a=S(i,t);r=r.replace(e,a)}if(i===r)return`${E.cyan}→ No changes${E.reset}`;let a=O(i,r);return`${E.blue}File: ${e.file}${E.reset}\n${a.join(`
|
|
15
|
+
`)}`}catch(e){return`${E.red}✗ Error: ${e instanceof Error?e.message:String(e)}${E.reset}`}}function j(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t))return`${E.yellow}⊘ Condition not met - task would be skipped${E.reset}`;let n=e.paths.map(e=>S(e,t)).filter(e=>c.default.existsSync(l.default.join(u.default.cwd(),e)));return n.length===0?`${E.cyan}→ No files/directories to delete${E.reset}`:`${E.red}Would delete:${E.reset}\n${n.map(e=>`${E.red} - ${e}${E.reset}`).join(`
|
|
16
|
+
`)}`}function M(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t))return`${E.yellow}⊘ Condition not met - task would be skipped${E.reset}`;let n=S(e.from,t),r=S(e.to,t),i=l.default.join(u.default.cwd(),n),a=l.default.join(u.default.cwd(),r);return c.default.existsSync(i)?c.default.existsSync(a)?`${E.yellow}⚠ Destination already exists: ${r}${E.reset}\n${E.cyan}Would rename: ${n} → ${r}${E.reset}`:`${E.cyan}Would rename: ${n} → ${r}${E.reset}`:`${E.red}✗ Source not found: ${n}${E.reset}`}function N(e){if(e.condition!=null&&e.condition!==``)return`${E.yellow}⊘ Condition check skipped in dry-run${E.reset}`;let t=l.default.join(u.default.cwd(),`.git`),n=c.default.existsSync(t),r=[];if(e.removeExisting&&n&&r.push(`${E.red}Would remove existing .git directory${E.reset}`),r.push(`${E.green}Would initialize git repository${E.reset}`),e.initialCommit){let t=e.message??`Initial commit`;r.push(`${E.green}Would create initial commit: "${t}"${E.reset}`)}return r.join(`
|
|
17
|
+
`)}function ce(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t))return`${E.yellow}⊘ Condition not met - task would be skipped${E.reset}`;let n=S(e.command,t),r=e.cwd==null?u.default.cwd():S(e.cwd,t);return`${E.yellow}Would execute:${E.reset}\n${E.cyan} Command: ${n}${E.reset}\n${E.cyan} Working directory: ${r}${E.reset}`}async function P(e,t){try{switch(e.type){case`update-json`:return await k(e.config,t);case`template`:return await ae(e.config,t);case`create`:return await oe(e.config,t);case`regex-replace`:return await se(e.config,t);case`replace-in-file`:return await A(e.config,t);case`delete`:return j(e.config,t);case`rename`:return M(e.config,t);case`git-init`:return N(e.config);case`exec`:return ce(e.config,t);default:{let t=e.type;return`${E.yellow}⚠ Diff not available for task type: ${t}${E.reset}`}}}catch(e){return`${E.red}✗ Error generating diff: ${e instanceof Error?e.message:String(e)}${E.reset}`}}async function F(e,t){console.log(`${E.blue}═══════════════════════════════════════════════════════${E.reset}`),console.log(`${E.blue} DRY RUN - Preview of changes${E.reset}`),console.log(`${E.blue}═══════════════════════════════════════════════════════${E.reset}`);for(let n of e){console.log(`${E.cyan}▶ Task: ${n.name}${E.reset}`),console.log(`${E.gray} ${n.description}${E.reset}`);let e=await P(n,t);console.log(e),console.log(`${E.gray}${`─`.repeat(55)}${E.reset}`)}console.log(`${E.blue}═══════════════════════════════════════════════════════${E.reset}`),console.log(`${E.yellow} No changes were applied (dry-run mode)${E.reset}`),console.log(`${E.blue}═══════════════════════════════════════════════════════${E.reset}`)}const I=new Map,L={},R=new Map;function z(e){if(e.name==null||e.name===``)throw TypeError(`Plugin name is required`);if(!Array.isArray(e.taskTypes)||e.taskTypes.length===0)throw TypeError(`Plugin ${e.name} must define at least one task type`);if(typeof e.execute!=`function`)throw TypeError(`Plugin ${e.name} must provide an execute function`);if(I.has(e.name))throw TypeError(`Plugin ${e.name} is already registered`);for(let t of e.taskTypes)if(R.has(t)){let e=R.get(t);throw TypeError(`Task type "${t}" is already registered by plugin "${e}"`)}I.set(e.name,e);for(let t of e.taskTypes)R.set(t,e.name);x(`✓ Registered plugin: ${e.name}${e.version==null?``:` v${e.version}`}`,`info`)}function le(e){let t=I.get(e);if(t!=null){for(let e of t.taskTypes)R.delete(e);I.delete(e)}}function ue(e){return I.get(e)}function B(e){let t=R.get(e);if(t!=null)return I.get(t)}function V(e){return R.has(e)}function de(){return Array.from(I.keys())}function fe(){I.clear(),R.clear()}function pe(e){e.beforeAll!=null&&(L.beforeAll=e.beforeAll),e.afterAll!=null&&(L.afterAll=e.afterAll),e.beforeTask!=null&&(L.beforeTask=e.beforeTask),e.afterTask!=null&&(L.afterTask=e.afterTask),e.onError!=null&&(L.onError=e.onError)}async function H(e,...t){let n=L[e];if(n!=null)try{e===`beforeAll`||e===`afterAll`?await n(t[0]):(e===`beforeTask`||e===`afterTask`||e===`onError`)&&await n(t[0],t[1])}catch(t){x(`Error in ${e} hook: ${t instanceof Error?t.message:String(t)}`,`error`)}}async function U(e,t,n){let r=B(e.type);if(r==null)throw TypeError(`No plugin found for task type: ${e.type}`);await r.execute(e,t,n)}async function me(e,t){let n=B(e.type);if(!(n==null||n.getDiff==null))return n.getDiff(e,t)}function he(e){let t=B(e.type);return t==null?[`No plugin found for task type: ${e.type}`]:t.validate==null?[]:t.validate(e)}function ge(e,t,n,r){return{name:e,...r?.version!=null&&{version:r.version},taskTypes:[t],execute:n,...r?.getDiff!=null&&{getDiff:r.getDiff},...r?.validate!=null&&{validate:r.validate}}}async function W(e,t=new Map,n={}){let r={};if(e.length===0)return r;for(let i of e){let e={...n,...r};if(_(i.enabled,e))try{let e,n=t.get(i.id);switch(i.type){case`input`:{let t={message:i.message};if(n!==void 0&&(t.default=String(n)),i.required!==void 0&&(t.required=i.required),e=await(0,h.input)(t),i.required&&(e==null||typeof e==`string`&&e.trim()===``))throw x(`${i.message} is required`,`error`),Error(`Prompt "${i.id}" is required`);break}case`password`:if(e=await(0,h.password)({message:i.message,mask:`*`}),i.required&&(e==null||typeof e==`string`&&e.trim()===``))throw x(`${i.message} is required`,`error`),Error(`Prompt "${i.id}" is required`);break;case`number`:{let t={message:i.message};if(n!==void 0&&(t.default=Number(n)),i.required!==void 0&&(t.required=i.required),i.min!==void 0&&(t.min=i.min),i.max!==void 0&&(t.max=i.max),e=await(0,h.number)(t),i.required&&e==null)throw x(`${i.message} is required`,`error`),Error(`Prompt "${i.id}" is required`);break}case`select`:{let t={message:i.message,choices:i.choices.map(e=>({name:e.name,value:e.value}))};n!==void 0&&(t.default=n),e=await(0,h.select)(t);break}case`confirm`:{let t=n===void 0?!1:!!n;e=await(0,h.confirm)({message:i.message,default:t});break}default:throw x(`Unknown prompt type: ${i.type}`,`error`),Error(`Unknown prompt type: ${i.type}`)}r[i.id]=e}catch(e){throw e instanceof Error&&x(`Failed to collect prompt "${i.id}": ${e.message}`,`error`),e}}return r}async function G(e,t){if(e===void 0)return;if(typeof e!=`object`||!e||Array.isArray(e))return e;let n=e;if(n.type===`exec`){let e=n.value;if(typeof e!=`string`){x(`Prompt "${t}": exec default value must have a string command`,`error`);return}try{let t=(0,d.execSync)(e,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:1e4}).trim();if(t.startsWith(`{`)||t.startsWith(`[`))try{return JSON.parse(t)}catch{return t}if(/^-?\d+(?:\.\d+)?$/u.test(t)){let e=Number.parseFloat(t);if(!Number.isNaN(e))return e}return t===`true`||t===`false`?t===`true`:t}catch(e){x(`Prompt "${t}": failed to execute default value command: ${e instanceof Error?e.message:`Unknown error`}`,`warn`);return}}else if(n.type===`static`)return n.value;return e}async function K(e){let t=new Map,n=e.map(async e=>{if(e.default!==void 0){let n=await G(e.default,e.id);n!==void 0&&t.set(e.id,n)}});return await Promise.all(n),t}function q(e){let t=[],n=new Set;for(let r of e){if(n.has(r.id)&&t.push(`Duplicate prompt ID: ${r.id}`),n.add(r.id),/^[\w-]+$/u.test(r.id)||t.push(`Invalid prompt ID "${r.id}": must contain only alphanumeric characters, underscores, and hyphens`),(!r.message||r.message.trim()===``)&&t.push(`Prompt "${r.id}" must have a non-empty message`),r.type===`select`){r.choices.length===0&&t.push(`Select prompt "${r.id}" must have at least one choice`);for(let e of r.choices)(!e.name||e.name.trim()===``)&&t.push(`Select prompt "${r.id}" has a choice with empty name`),e.value===void 0&&t.push(`Select prompt "${r.id}" has a choice with undefined value`)}r.type===`number`&&r.min!==void 0&&r.max!==void 0&&r.min>r.max&&t.push(`Number prompt "${r.id}" has min greater than max`)}return t}const _e=(0,f.promisify)(c.default.writeFile);async function ve(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t)){x(`Condition not met, skipping create task`,`info`);return}let n=l.default.join(u.default.cwd(),e.file);if(c.default.existsSync(n)){x(`File already exists, skipping: ${e.file}`,`info`);return}let r=e.template!=null&&e.template!==``,i=e.templateFile!=null&&e.templateFile!==``;if(!r&&!i)throw Error(`Create task requires either "template" (inline) or "templateFile" (file path) to be specified`);if(r&&i)throw Error(`Create task cannot have both "template" and "templateFile" specified. Use one or the other.`);let a;if(i&&e.templateFile.endsWith(`.hbs`))a=ee(e.templateFile,t);else if(i){let n=e.templateFile,r=l.default.isAbsolute(n)?n:l.default.join(u.default.cwd(),n);if(!c.default.existsSync(r))throw Error(`Template file not found: ${n}`);a=S(c.default.readFileSync(r,`utf-8`),t)}else a=S(e.template,t);let o=l.default.dirname(n);c.default.existsSync(o)||c.default.mkdirSync(o,{recursive:!0}),await _e(n,a),x(`Created file: ${e.file}`,`success`)}const ye={name:`create`,version:`1.0.0`,taskTypes:[`create`],execute:async(e,t,n)=>{n.dryRun||await ve(e.config,t)}};async function be(e,t){let{paths:n,condition:r}=e;if(r!=null&&r!==``){if(!t){x(`Condition specified but no config provided, skipping deletion`,`warn`);return}if(!w(r,t)){x(`Condition not met, skipping deletion`,`info`);return}}for(let e of n){let t=l.default.join(u.default.cwd(),e);c.default.existsSync(t)&&c.default.rmSync(t,{recursive:!0,force:!0})}}const xe={name:`delete`,version:`1.0.0`,taskTypes:[`delete`],execute:async(e,t,n)=>{n.dryRun||await be(e.config,t)}};async function Se(e,t){if(e.condition!=null&&e.condition!==``){if(!t){x(`Condition specified but no config provided, skipping exec`,`warn`);return}if(!w(e.condition,t)){x(`Condition not met, skipping exec task`,`info`);return}}let n=e.cwd==null?u.default.cwd():l.default.join(u.default.cwd(),e.cwd);(0,d.execSync)(e.command,{cwd:n,stdio:`inherit`})}const Ce={name:`exec`,version:`1.0.0`,taskTypes:[`exec`],execute:async(e,t,n)=>{n.dryRun||await Se(e.config,t)}};async function we(e,t){if(e.condition!=null&&e.condition!==``){if(!t){x(`Condition specified but no config provided, skipping git-init`,`warn`);return}if(!w(e.condition,t)){x(`Condition not met, skipping git-init task`,`info`);return}}if(e.removeExisting){let e=l.default.join(u.default.cwd(),`.git`);c.default.existsSync(e)&&c.default.rmSync(e,{recursive:!0,force:!0})}if((0,d.execSync)(`git init`,{stdio:`inherit`}),e.initialCommit){let t=e.message??`Initial commit`;(0,d.execSync)(`git add .`,{stdio:`inherit`}),(0,d.execSync)(`git commit -m "${t}"`,{stdio:`inherit`})}}const Te={name:`git-init`,version:`1.0.0`,taskTypes:[`git-init`],execute:async(e,t,n)=>{n.dryRun||await we(e.config,t)}},Ee=(0,f.promisify)(c.default.readFile),De=(0,f.promisify)(c.default.writeFile);async function Oe(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t)){x(`Condition not met, skipping regex-replace task`,`info`);return}let n=l.default.join(u.default.cwd(),e.file),{pattern:r}=e,i=e.flags??``,a=e.replacement||``,o=await Ee(n,`utf-8`),s=new RegExp(r,i);o=o.replace(s,S(a,t)),await De(n,o)}const ke={name:`regex-replace`,version:`1.0.0`,taskTypes:[`regex-replace`],execute:async(e,t,n)=>{n.dryRun||await Oe(e.config,t)}},Ae=(0,f.promisify)(c.default.rename);async function je(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t)){x(`Condition not met, skipping rename task`,`info`);return}let n=l.default.join(u.default.cwd(),S(e.from,t)),r=l.default.join(u.default.cwd(),S(e.to,t));if(!c.default.existsSync(n)){x(`Source path does not exist: ${n}`,`warn`);return}await Ae(n,r)}const Me={name:`rename`,version:`1.0.0`,taskTypes:[`rename`],execute:async(e,t,n)=>{n.dryRun||await je(e.config,t)}},Ne=(0,f.promisify)(c.default.readFile),Pe=(0,f.promisify)(c.default.writeFile);async function Fe(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t)){x(`Condition not met, skipping replace-in-file task`,`info`);return}let n=l.default.join(u.default.cwd(),e.file),{replacements:r}=e;if(!c.default.existsSync(n)){x(`File not found: ${n}, skipping`,`warn`);return}let i=await Ne(n,`utf-8`);for(let{find:e,replace:n}of r){let r=S(n,t);i=i.replace(new RegExp(e,`gu`),r)}await Pe(n,i)}const Ie={name:`replace-in-file`,version:`1.0.0`,taskTypes:[`replace-in-file`],execute:async(e,t,n)=>{n.dryRun||await Fe(e.config,t)}},J=(0,f.promisify)(c.default.readFile);function Y(e){try{let t=new URL(e);return t.protocol===`http:`||t.protocol===`https:`}catch{return!1}}function X(e,t){if(Y(e))return e;if(t==null||t===``)return l.default.isAbsolute(e)?e:l.default.resolve(u.default.cwd(),e);if(Y(t))try{let n=new URL(`.`,t);return new URL(e,n).href}catch{throw Error(`Failed to resolve templateFile "${e}" relative to remote template "${t}"`)}let n=l.default.dirname(t);return l.default.isAbsolute(e)?e:l.default.resolve(n,e)}async function Le(e){if(Y(e))return Re(e);if(!c.default.existsSync(e))throw Error(`Template file not found: ${e}`);return J(e,`utf-8`)}async function Re(e){try{let t=await fetch(e);if(!t.ok)throw Error(`Failed to fetch template from ${e}: ${t.status} ${t.statusText}`);return await t.text()}catch(t){throw t instanceof Error&&t.message.includes(`Failed to fetch`)?t:Error(`Failed to fetch template from ${e}: ${t instanceof Error?t.message:String(t)}`)}}const Z=new Map;async function ze(e,t=new Set){let n=Y(e),r;if(r=n||l.default.isAbsolute(e)?e:l.default.resolve(u.default.cwd(),e),Z.has(r))return Z.get(r);if(t.has(r))throw Error(`Circular dependency detected: ${Array.from(t).join(` -> `)} -> ${r}`);t.add(r);let i;if(n)i=await Re(r);else{if(!c.default.existsSync(r))throw Error(`Template file not found: ${r}`);i=await J(r,`utf-8`)}let a;try{a=JSON.parse(i)}catch(e){throw Error(`Failed to parse template file ${r}: ${e instanceof Error?e.message:String(e)}`)}if(a.tasks!==void 0&&!Array.isArray(a.tasks))throw TypeError(`Invalid template file ${r}: 'tasks' must be an array if provided`);a.tasks===void 0&&(a.tasks=[]);for(let e of a.tasks)e.$sourceUrl=r;return Z.set(r,a),a}async function Q(e,t,n=new Set){let r=Y(e),i;if(i=r||l.default.isAbsolute(e)?e:t==null?l.default.resolve(u.default.cwd(),e):Y(t)?new URL(e,t).href:l.default.resolve(t,e),n.has(i))throw Error(`Circular dependency detected: ${Array.from(n).join(` -> `)} -> ${i}`);n.add(i);let a=await ze(i);if(a.extends==null||a.extends===``)return a;let o=Y(i)?new URL(`.`,i).href:l.default.dirname(i),s=Array.isArray(a.extends)?a.extends:[a.extends],c=[];for(let e of s){let t=await Q(e,o,n);c.push(t)}return Be([...c,a])}function Be(e){if(e.length===0)return{tasks:[]};if(e.length===1)return e[0];let t=new Map,n=new Map,r=new Map;for(let i of e){if(i.prompts!=null)for(let e of i.prompts)r.set(e.id,{...e});if(i.variables!=null)for(let e of i.variables)n.set(e.id,{...e});for(let e of i.tasks??[])if(t.has(e.id)){let n=t.get(e.id);t.set(e.id,Ve(n,e))}else t.set(e.id,{...e})}let i={tasks:Array.from(t.values())};return r.size>0&&(i.prompts=Array.from(r.values())),n.size>0&&(i.variables=Array.from(n.values())),i}function Ve(e,t){let n=typeof e.config==`object`&&e.config!==null&&typeof t.config==`object`&&t.config!==null?{...e.config,...t.config}:t.config,r=e.prompts?[...e.prompts]:void 0;if(t.prompts&&t.prompts.length>0)if(!r)r=[...t.prompts];else{let e=new Map(r.map(e=>[e.id,e]));for(let n of t.prompts)e.set(n.id,n);r=Array.from(e.values())}let i=e.variables?[...e.variables]:void 0;if(t.variables&&t.variables.length>0)if(!i)i=[...t.variables];else{let e=new Map(i.map(e=>[e.id,e]));for(let n of t.variables)e.set(n.id,n);i=Array.from(e.values())}let a=[...e.dependencies??[],...t.dependencies??[]],o=a.length>0?[...new Set(a)]:void 0,s=t.$sourceUrl??e.$sourceUrl;return{...e,...t,config:n,...r!=null&&{prompts:r},...i!=null&&{variables:i},...o!=null&&{dependencies:o},...s!=null&&{$sourceUrl:s}}}function He(){Z.clear()}async function Ue(e){x(`Loading tasks from ${e}...`,`info`);let t=await Q(e);x(`Loaded ${t.tasks?.length??0} task(s)`,`info`),t.extends!=null&&t.extends!==``&&x(`Extended from: ${(Array.isArray(t.extends)?t.extends:[t.extends]).join(`, `)}`,`info`),t.prompts!=null&&t.prompts.length>0&&x(`Found ${t.prompts.length} top-level prompt(s)`,`info`),t.variables!=null&&t.variables.length>0&&x(`Found ${t.variables.length} top-level variable(s)`,`info`);let n={tasks:t.tasks??[]};return t.prompts!=null&&(n.prompts=t.prompts),t.variables!=null&&(n.variables=t.variables),n}const We=(0,f.promisify)(c.default.writeFile);async function Ge(e,t,n){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t)){x(`Condition not met, skipping template task`,`info`);return}let r=l.default.join(u.default.cwd(),e.file),i=e.template!=null&&e.template!==``,a=e.templateFile!=null&&e.templateFile!==``;if(!i&&!a)throw Error(`Template task requires either "template" (inline) or "templateFile" (file path) to be specified`);if(i&&a)throw Error(`Template task cannot have both "template" and "templateFile" specified. Use one or the other.`);let o;if(a&&e.templateFile.endsWith(`.hbs`)){let r=await Le(X(e.templateFile,n?.$sourceUrl));o=(await import(`handlebars`)).default.compile(r)(t)}else o=S(a?await Le(X(e.templateFile,n?.$sourceUrl)):e.template,t);await We(r,o)}const Ke={name:`template`,version:`1.0.0`,taskTypes:[`template`],execute:async(e,t,n)=>{n.dryRun||await Ge(e.config,t,e)}},qe=(0,f.promisify)(c.default.readFile),Je=(0,f.promisify)(c.default.writeFile),Ye=2;async function Xe(e,t){if(e.condition!=null&&e.condition!==``&&!w(e.condition,t)){x(`Condition not met, skipping update-json task`,`info`);return}let n=l.default.join(u.default.cwd(),e.file),{updates:r}=e,i=await qe(n,`utf-8`),a=JSON.parse(i);function o(e){if(typeof e==`string`)return S(e,t);if(Array.isArray(e))return e.map(e=>o(e));if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[n]=o(r);return t}return e}for(let[e,t]of Object.entries(r)){let n=o(t);e.includes(`.`)?C(a,e,n):a[e]=n}await Je(n,`${JSON.stringify(a,null,2)}\n`)}const Ze={name:`update-json`,version:`1.0.0`,taskTypes:[`update-json`],execute:async(e,t,n)=>{n.dryRun||await Xe(e.config,t)}};let Qe=!1;function $e(){Qe||=(z(Ze),z(Ke),z(ye),z(ke),z(Ie),z(xe),z(Me),z(Te),z(Ce),!0)}async function et(e,t,n=!1){if($e(),n){x(`[DRY RUN] Would execute: ${e.name}`,`info`);return}if(V(e.type)){await U(e,t,{dryRun:n});return}throw TypeError(`Unknown task type: ${e.type}`)}async function tt(e,t,n,r,i=!1){try{return x(`[${n}/${r}] Running: ${e.name}...`,`info`),await et(e,t,i),x(`✓ ${e.name}`,`success`),!0}catch(t){return x(`✗ Failed: ${e.name}`,`error`),t instanceof Error&&(x(` Reason: ${t.message}`,`error`),t.stack!=null&&u.default.env.DEBUG!=null&&console.error(t.stack)),e.required&&x(` This is a required task. Initialization cannot continue.`,`error`),!1}}function $(e){let t=[],n=new Set,r=new Set,i=new Map(e.map(e=>[e.id,e]));function a(e){if(n.has(e))return;if(r.has(e))throw Error(`Circular dependency detected involving task: ${e}`);r.add(e);let o=i.get(e);if(!o)throw Error(`Task not found: ${e}`);if(o.dependencies)for(let e of o.dependencies)a(e);r.delete(e),n.add(e),t.push(o)}for(let t of e)n.has(t.id)||a(t.id);return t}function nt(e,t=new Map){let n={};for(let r of e){let e=t.get(r.id);e!==void 0&&(n[r.id]=e)}return n}async function rt(e,t){if(e==null)return;if(typeof e!=`object`||!e||Array.isArray(e))return e;let n=e;if(n.type===`exec`){let e=n.value;if(typeof e!=`string`){x(`Variable "${t}": exec value must have a string command`,`error`);return}try{let t=(0,d.execSync)(e,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:1e4}).trim();if(t.startsWith(`{`)||t.startsWith(`[`))try{return JSON.parse(t)}catch{return t}if(/^-?\d+(?:\.\d+)?$/u.test(t)){let e=Number.parseFloat(t);if(!Number.isNaN(e))return e}return t===`true`||t===`false`?t===`true`:t}catch(e){x(`Variable "${t}": failed to execute command: ${e instanceof Error?e.message:`Unknown error`}`,`warn`);return}}else if(n.type===`static`)return n.value;return e}async function it(e){let t=new Map,n=e.map(async e=>{let t=await rt(e.value,e.id);return{id:e.id,value:t}}),r=await Promise.all(n);for(let e of r)e.value!==void 0&&t.set(e.id,e.value);return t}function at(e){let t=[],n=new Set;for(let r of e)if(n.has(r.id)&&t.push(`Duplicate variable ID: "${r.id}"`),n.add(r.id),/^[\w$]+$/u.test(r.id)||t.push(`Variable ID "${r.id}" is invalid. Must contain only letters, numbers, underscore, or dollar sign.`),r.value===void 0||r.value===null)t.push(`Variable "${r.id}" must have a value`);else if(typeof r.value==`object`&&!Array.isArray(r.value)&&r.value!==null){let e=r.value;e.type==null||e.type===``?t.push(`Variable "${r.id}": value object must have a "type" field ("static" or "exec")`):e.type!==`static`&&e.type!==`exec`&&t.push(`Variable "${r.id}": type must be "static" or "exec", got "${e.type}"`),(e.value===void 0||e.value===null)&&t.push(`Variable "${r.id}": value config must have a "value" field`),e.type===`exec`&&typeof e.value!=`string`&&t.push(`Variable "${r.id}": exec type must have a string command as value`)}return t}const ot=(0,f.promisify)(c.default.readFile);async function st(e,t){let n=e.filter(e=>_(e.enabled,g()));x(`Resolving task dependencies...`,`info`);let r=$(n);x(`Welcome! Let's execute your tasks.`,`info`),t.dryRun&&x(`🔍 DRY RUN MODE - No changes will be made`,`warn`),x(`This will execute your project tasks based on the defined configuration.`,`info`);let i=g(),a=t.globalVariables??[],o=[],s=[...a];for(let e of r)if(e.variables&&e.variables.length>0)for(let t of e.variables)o.push(t),s.push(t);if(s.length>0){let e=at(s);e.length>0&&(x(`❌ Variable validation errors:`,`error`),e.forEach(e=>x(` - ${e}`,`error`)),u.default.exit(1)),x(`Resolving variable values...`,`info`);let t=nt(s,await it(s));Object.assign(i,t),Object.keys(t).length>0&&x(`✓ Resolved ${Object.keys(t).length} variable(s)`,`success`)}let f=t.globalPrompts??[],p=[],m=[...f];for(let e of r)if(e.prompts&&e.prompts.length>0)for(let t of e.prompts)p.push(t),m.push(t);if(m.length>0){let e=q(m);e.length>0&&(x(`❌ Prompt validation errors:`,`error`),e.forEach(e=>x(` - ${e}`,`error`)),u.default.exit(1)),x(`Resolving prompt default values...`,`info`);let t=await K(m),n={};if(f.length>0&&(x(`📋 Top-level prompts (available to all tasks):`,`info`),n=await W(f,t,i),Object.assign(i,n)),p.length>0){f.length>0&&x(`📋 Task-specific prompts:`,`info`);let e=await W(p,t,i);Object.assign(i,e)}}let h=r.filter(e=>_(e.enabled,i));if(x(`${h.length} of ${r.length} task(s) enabled for execution`,`info`),t.dryRun){await F(h,i),x(`🔍 Dry run completed - no changes were made`,`info`),x(`Run without --dry-run to apply changes`,`info`);return}x(`Starting task execution...`,`info`),await H(`beforeAll`,i);let v=h.length,y=0,S=0,C=[];for(let e=0;e<h.length;e++){let n=h[e];if(n!=null)if(await H(`beforeTask`,n,i),await tt(n,i,e+1,v,t.dryRun))y++,C.push(n.id),await H(`afterTask`,n,i);else if(n.required){S++,await H(`onError`,Error(`Task ${n.name} failed`),n);break}else x(`⚠️ Non-critical task failed, continuing...`,`warn`),await H(`onError`,Error(`Task ${n.name} failed`),n)}if(S>0&&(x(`❌ Task execution failed with ${S} critical error(s)`,`error`),x(`✓ Completed: ${y}/${v} tasks`,`info`),u.default.exit(1)),await H(`afterAll`,i),x(`✅ All tasks completed successfully!`,`success`),x(`✓ Completed: ${y}/${v} tasks`,`success`),!t.dryRun){x(`Next steps:`,`info`),x(`1. Review the changes made to your project`,`info`),x(`2. Commit the changes to git`,`info`);let e=l.default.join(u.default.cwd(),`package.json`);c.default.existsSync(e)&&JSON.parse(await ot(e,`utf-8`)).scripts?.[`turbo:gen:init`]!=null&&(x(`3. Run "pnpm run turbo:gen:init" to create your first package`,`info`),await b(`Would you like to run turbo:gen:init now?`,!0)&&(x(`Running turbo:gen:init...`,`info`),(0,d.execSync)(`pnpm run turbo:gen:init`,{stdio:`inherit`})))}}const ct=u.default.argv.includes(`--dry-run`),lt=u.default.argv.includes(`--force`);async function ut(e){try{let t=e||[];t.length===0&&(x(`⚠️ No tasks defined. Use --tasks-file to specify tasks or call runWithTasks() programmatically.`,`warn`),x(`Example: scaffoldfy --tasks-file ./tasks.json`,`info`),u.default.exit(1)),await st(t,{dryRun:ct,force:lt,tasksFilePath:void 0})}catch(e){x(`❌ Task execution failed`,`error`),e instanceof Error?(x(`Error: ${e.message}`,`error`),u.default.env.DEBUG!=null&&console.error(e.stack)):console.error(e),u.default.exit(1)}}async function dt(e,t){try{await st(e,{dryRun:t?.dryRun??ct,force:t?.force??lt,tasksFilePath:t?.tasksFilePath??void 0,...t?.globalVariables!=null&&{globalVariables:t.globalVariables},...t?.globalPrompts!=null&&{globalPrompts:t.globalPrompts}})}catch(e){x(`❌ Task execution failed`,`error`),e instanceof Error?(x(`Error: ${e.message}`,`error`),u.default.env.DEBUG!=null&&console.error(e.stack)):console.error(e),u.default.exit(1)}}Object.defineProperty(exports,`A`,{enumerable:!0,get:function(){return le}}),Object.defineProperty(exports,`B`,{enumerable:!0,get:function(){return ae}}),Object.defineProperty(exports,`C`,{enumerable:!0,get:function(){return ue}}),Object.defineProperty(exports,`D`,{enumerable:!0,get:function(){return de}}),Object.defineProperty(exports,`E`,{enumerable:!0,get:function(){return V}}),Object.defineProperty(exports,`F`,{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,`G`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`H`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`I`,{enumerable:!0,get:function(){return se}}),Object.defineProperty(exports,`J`,{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,`K`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`L`,{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,`M`,{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,`N`,{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,`O`,{enumerable:!0,get:function(){return pe}}),Object.defineProperty(exports,`P`,{enumerable:!0,get:function(){return ce}}),Object.defineProperty(exports,`R`,{enumerable:!0,get:function(){return A}}),Object.defineProperty(exports,`S`,{enumerable:!0,get:function(){return U}}),Object.defineProperty(exports,`T`,{enumerable:!0,get:function(){return me}}),Object.defineProperty(exports,`U`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`V`,{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,`W`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`Y`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return G}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return rt}}),Object.defineProperty(exports,`b`,{enumerable:!0,get:function(){return fe}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return et}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return Q}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return Ue}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return K}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return q}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return it}}),Object.defineProperty(exports,`j`,{enumerable:!0,get:function(){return he}}),Object.defineProperty(exports,`k`,{enumerable:!0,get:function(){return z}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return tt}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return Be}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return dt}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return nt}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return ze}}),Object.defineProperty(exports,`q`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return at}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return $}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return ut}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return He}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return W}}),Object.defineProperty(exports,`w`,{enumerable:!0,get:function(){return B}}),Object.defineProperty(exports,`x`,{enumerable:!0,get:function(){return ge}}),Object.defineProperty(exports,`y`,{enumerable:!0,get:function(){return H}}),Object.defineProperty(exports,`z`,{enumerable:!0,get:function(){return P}});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import e from"node:path";import t from"node:fs";import n from"node:process";import{execSync as r}from"node:child_process";import{promisify as i}from"node:util";import a from"node:readline";import o from"handlebars";import{confirm as s,input as c,number as l,password as u,select as d}from"@inquirer/prompts";function f(){return{}}function p(e,t){return e===void 0?!0:typeof e==`boolean`?e:typeof e==`object`&&`condition`in e?b(e.condition,t):!1}function m(){try{let e=r(`git remote get-url origin`,{encoding:`utf-8`}).trim(),t=e.match(/github\.com[:/](?<owner>[^/]+)\/(?<name>[^/]+)$/u);if(t?.groups){let{owner:n,name:r}=t.groups,i=r;return i.endsWith(`.git`)&&(i=i.slice(0,-4)),{owner:n,name:i,url:e}}return null}catch{return null}}async function h(e,t){let r=a.createInterface({input:n.stdin,output:n.stdout});return new Promise(n=>{let i;i=t==null?`${e}: `:`${e} (${t}): `,r.question(i,e=>{r.close(),n(e.trim()||(t??``))})})}async function g(e,t=!1){return h(`${e} (${t?`Y/n`:`y/N`})`,t?`y`:`n`).then(e=>e.toLowerCase()===`y`||e.toLowerCase()===`yes`)}function _(e,t=`info`){console.log(`${{info:`\x1B[36m`,success:`\x1B[32m`,error:`\x1B[31m`,warn:`\x1B[33m`}[t]}${{info:`ℹ`,success:`✓`,error:`✗`,warn:`⚠`}[t]} ${e}[0m`)}function v(e,t){return e.replace(/\{\{(?<key>\w+)\}\}/gu,(e,n)=>t[n]?.toString()??``)}function y(e,t,n){let r=t.split(`.`),i=e;for(let e=0;e<r.length-1;e++){let t=r[e];t!=null&&t!==``&&((!(t in i)||typeof i[t]!=`object`||i[t]===null)&&(i[t]={}),i=i[t])}let a=r[r.length-1];a!=null&&a!==``&&(i[a]=n)}function b(e,t){try{let n={...t};return Function(...Object.keys(n),`'use strict'; return (${e})`)(...Object.values(n))}catch(t){return _(`Failed to evaluate condition: ${e}`,`warn`),t instanceof Error&&_(` Error: ${t.message}`,`warn`),!1}}function x(r,i){try{let a=e.isAbsolute(r)?r:e.join(n.cwd(),r);if(!t.existsSync(a))throw Error(`Template file not found: ${r}`);return S(t.readFileSync(a,`utf-8`),i)}catch(e){throw _(`Failed to read template file: ${r}`,`error`),e instanceof Error&&_(` Error: ${e.message}`,`error`),e}}function S(e,t){try{return o.compile(e)(t)}catch(e){throw _(`Failed to compile Handlebars template`,`error`),e instanceof Error&&_(` Error: ${e.message}`,`error`),e}}const C=i(t.readFile),w={reset:`\x1B[0m`,red:`\x1B[31m`,green:`\x1B[32m`,yellow:`\x1B[33m`,blue:`\x1B[34m`,cyan:`\x1B[36m`,gray:`\x1B[90m`};function T(e,t){switch(t){case`add`:return`${w.green}+ ${e}${w.reset}`;case`remove`:return`${w.red}- ${e}${w.reset}`;case`context`:return`${w.gray} ${e}${w.reset}`;default:return e}}function E(e,t){let n=e.split(`
|
|
2
|
+
`),r=t.split(`
|
|
3
|
+
`),i=[],a=Math.max(n.length,r.length);for(let e=0;e<a;e++){let t=n[e],a=r[e];t===a?t!==void 0&&i.push(T(t,`context`)):(t!==void 0&&i.push(T(t,`remove`)),a!==void 0&&i.push(T(a,`add`)))}return i}async function D(r,i){if(r.condition!=null&&r.condition!==``&&!b(r.condition,i))return`${w.yellow}⊘ Condition not met - task would be skipped${w.reset}`;let a=e.join(n.cwd(),r.file);if(!t.existsSync(a))return`${w.red}✗ File not found: ${r.file}${w.reset}`;try{let e=await C(a,`utf-8`),t=JSON.parse(e),n={...t};function o(e){if(typeof e==`string`)return v(e,i);if(Array.isArray(e))return e.map(e=>o(e));if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[n]=o(r);return t}return e}for(let[e,n]of Object.entries(r.updates)){let r=o(n);e.includes(`.`)?y(t,e,r):t[e]=r}let s=JSON.stringify(n,null,2),c=JSON.stringify(t,null,2);if(s===c)return`${w.cyan}→ No changes${w.reset}`;let l=E(s,c);return`${w.blue}File: ${r.file}${w.reset}\n${l.join(`
|
|
4
|
+
`)}`}catch(e){return`${w.red}✗ Error: ${e instanceof Error?e.message:String(e)}${w.reset}`}}async function O(r,i){if(r.condition!=null&&r.condition!==``&&!b(r.condition,i))return`${w.yellow}⊘ Condition not met - task would be skipped${w.reset}`;if(r.template==null||r.template===``)return`${w.red}✗ No template content provided for file: ${r.file}${w.reset}`;let a=e.join(n.cwd(),r.file),o=v(r.template,i);if(!t.existsSync(a)){let e=o.split(`
|
|
5
|
+
`).slice(0,10).join(`
|
|
6
|
+
`),t=o.split(`
|
|
7
|
+
`).length>10;return`${w.blue}File: ${r.file}${w.reset}\n${w.green}+ New file would be created${w.reset}\n${w.gray}Content preview:${w.reset}\n${e}${t?`
|
|
8
|
+
...`:``}`}try{let e=await C(a,`utf-8`);if(e===o)return`${w.cyan}→ No changes${w.reset}`;let t=E(e,o);return`${w.blue}File: ${r.file}${w.reset}\n${t.join(`
|
|
9
|
+
`)}`}catch(e){return`${w.red}✗ Error: ${e instanceof Error?e.message:String(e)}${w.reset}`}}async function ee(r,i){if(r.condition!=null&&r.condition!==``&&!b(r.condition,i))return`${w.yellow}⊘ Condition not met - task would be skipped${w.reset}`;let a=e.join(n.cwd(),r.file);if(t.existsSync(a))return`${w.cyan}→ File already exists, would be skipped: ${r.file}${w.reset}`;let o=r.template!=null&&r.template!==``,s=r.templateFile!=null&&r.templateFile!==``;if(!o&&!s)return`${w.red}✗ No template content provided for file: ${r.file}${w.reset}`;try{let e;if(o)e=v(r.template,i);else return`${w.blue}File: ${r.file}${w.reset}\n${w.green}+ New file would be created from template: ${r.templateFile}${w.reset}`;let t=e.split(`
|
|
10
|
+
`).slice(0,10).join(`
|
|
11
|
+
`),n=e.split(`
|
|
12
|
+
`).length>10;return`${w.blue}File: ${r.file}${w.reset}\n${w.green}+ New file would be created${w.reset}\n${w.gray}Content preview:${w.reset}\n${t}${n?`
|
|
13
|
+
...`:``}`}catch(e){return`${w.red}✗ Error: ${e instanceof Error?e.message:String(e)}${w.reset}`}}async function k(r,i){if(r.condition!=null&&r.condition!==``&&!b(r.condition,i))return`${w.yellow}⊘ Condition not met - task would be skipped${w.reset}`;let a=e.join(n.cwd(),r.file);if(!t.existsSync(a))return`${w.red}✗ File not found: ${r.file}${w.reset}`;try{let e=await C(a,`utf-8`),t=new RegExp(r.pattern,r.flags??`g`),n=v(r.replacement,i),o=e.replace(t,n);if(e===o)return`${w.cyan}→ No matches found${w.reset}`;let s=E(e,o);return`${w.blue}File: ${r.file}${w.reset}\n${s.join(`
|
|
14
|
+
`)}`}catch(e){return`${w.red}✗ Error: ${e instanceof Error?e.message:String(e)}${w.reset}`}}async function A(r,i){if(r.condition!=null&&r.condition!==``&&!b(r.condition,i))return`${w.yellow}⊘ Condition not met - task would be skipped${w.reset}`;let a=e.join(n.cwd(),r.file);if(!t.existsSync(a))return`${w.red}✗ File not found: ${r.file}${w.reset}`;try{let e=await C(a,`utf-8`),t=e;for(let{find:t,replace:n}of r.replacements){let r=v(t,i),a=v(n,i);e=e.replace(r,a)}if(t===e)return`${w.cyan}→ No changes${w.reset}`;let n=E(t,e);return`${w.blue}File: ${r.file}${w.reset}\n${n.join(`
|
|
15
|
+
`)}`}catch(e){return`${w.red}✗ Error: ${e instanceof Error?e.message:String(e)}${w.reset}`}}function j(r,i){if(r.condition!=null&&r.condition!==``&&!b(r.condition,i))return`${w.yellow}⊘ Condition not met - task would be skipped${w.reset}`;let a=r.paths.map(e=>v(e,i)).filter(r=>t.existsSync(e.join(n.cwd(),r)));return a.length===0?`${w.cyan}→ No files/directories to delete${w.reset}`:`${w.red}Would delete:${w.reset}\n${a.map(e=>`${w.red} - ${e}${w.reset}`).join(`
|
|
16
|
+
`)}`}function M(r,i){if(r.condition!=null&&r.condition!==``&&!b(r.condition,i))return`${w.yellow}⊘ Condition not met - task would be skipped${w.reset}`;let a=v(r.from,i),o=v(r.to,i),s=e.join(n.cwd(),a),c=e.join(n.cwd(),o);return t.existsSync(s)?t.existsSync(c)?`${w.yellow}⚠ Destination already exists: ${o}${w.reset}\n${w.cyan}Would rename: ${a} → ${o}${w.reset}`:`${w.cyan}Would rename: ${a} → ${o}${w.reset}`:`${w.red}✗ Source not found: ${a}${w.reset}`}function te(r){if(r.condition!=null&&r.condition!==``)return`${w.yellow}⊘ Condition check skipped in dry-run${w.reset}`;let i=e.join(n.cwd(),`.git`),a=t.existsSync(i),o=[];if(r.removeExisting&&a&&o.push(`${w.red}Would remove existing .git directory${w.reset}`),o.push(`${w.green}Would initialize git repository${w.reset}`),r.initialCommit){let e=r.message??`Initial commit`;o.push(`${w.green}Would create initial commit: "${e}"${w.reset}`)}return o.join(`
|
|
17
|
+
`)}function ne(e,t){if(e.condition!=null&&e.condition!==``&&!b(e.condition,t))return`${w.yellow}⊘ Condition not met - task would be skipped${w.reset}`;let r=v(e.command,t),i=e.cwd==null?n.cwd():v(e.cwd,t);return`${w.yellow}Would execute:${w.reset}\n${w.cyan} Command: ${r}${w.reset}\n${w.cyan} Working directory: ${i}${w.reset}`}async function re(e,t){try{switch(e.type){case`update-json`:return await D(e.config,t);case`template`:return await O(e.config,t);case`create`:return await ee(e.config,t);case`regex-replace`:return await k(e.config,t);case`replace-in-file`:return await A(e.config,t);case`delete`:return j(e.config,t);case`rename`:return M(e.config,t);case`git-init`:return te(e.config);case`exec`:return ne(e.config,t);default:{let t=e.type;return`${w.yellow}⚠ Diff not available for task type: ${t}${w.reset}`}}}catch(e){return`${w.red}✗ Error generating diff: ${e instanceof Error?e.message:String(e)}${w.reset}`}}async function N(e,t){console.log(`${w.blue}═══════════════════════════════════════════════════════${w.reset}`),console.log(`${w.blue} DRY RUN - Preview of changes${w.reset}`),console.log(`${w.blue}═══════════════════════════════════════════════════════${w.reset}`);for(let n of e){console.log(`${w.cyan}▶ Task: ${n.name}${w.reset}`),console.log(`${w.gray} ${n.description}${w.reset}`);let e=await re(n,t);console.log(e),console.log(`${w.gray}${`─`.repeat(55)}${w.reset}`)}console.log(`${w.blue}═══════════════════════════════════════════════════════${w.reset}`),console.log(`${w.yellow} No changes were applied (dry-run mode)${w.reset}`),console.log(`${w.blue}═══════════════════════════════════════════════════════${w.reset}`)}const P=new Map,F={},I=new Map;function L(e){if(e.name==null||e.name===``)throw TypeError(`Plugin name is required`);if(!Array.isArray(e.taskTypes)||e.taskTypes.length===0)throw TypeError(`Plugin ${e.name} must define at least one task type`);if(typeof e.execute!=`function`)throw TypeError(`Plugin ${e.name} must provide an execute function`);if(P.has(e.name))throw TypeError(`Plugin ${e.name} is already registered`);for(let t of e.taskTypes)if(I.has(t)){let e=I.get(t);throw TypeError(`Task type "${t}" is already registered by plugin "${e}"`)}P.set(e.name,e);for(let t of e.taskTypes)I.set(t,e.name);_(`✓ Registered plugin: ${e.name}${e.version==null?``:` v${e.version}`}`,`info`)}function ie(e){let t=P.get(e);if(t!=null){for(let e of t.taskTypes)I.delete(e);P.delete(e)}}function ae(e){return P.get(e)}function R(e){let t=I.get(e);if(t!=null)return P.get(t)}function z(e){return I.has(e)}function oe(){return Array.from(P.keys())}function se(){P.clear(),I.clear()}function ce(e){e.beforeAll!=null&&(F.beforeAll=e.beforeAll),e.afterAll!=null&&(F.afterAll=e.afterAll),e.beforeTask!=null&&(F.beforeTask=e.beforeTask),e.afterTask!=null&&(F.afterTask=e.afterTask),e.onError!=null&&(F.onError=e.onError)}async function B(e,...t){let n=F[e];if(n!=null)try{e===`beforeAll`||e===`afterAll`?await n(t[0]):(e===`beforeTask`||e===`afterTask`||e===`onError`)&&await n(t[0],t[1])}catch(t){_(`Error in ${e} hook: ${t instanceof Error?t.message:String(t)}`,`error`)}}async function V(e,t,n){let r=R(e.type);if(r==null)throw TypeError(`No plugin found for task type: ${e.type}`);await r.execute(e,t,n)}async function le(e,t){let n=R(e.type);if(!(n==null||n.getDiff==null))return n.getDiff(e,t)}function ue(e){let t=R(e.type);return t==null?[`No plugin found for task type: ${e.type}`]:t.validate==null?[]:t.validate(e)}function de(e,t,n,r){return{name:e,...r?.version!=null&&{version:r.version},taskTypes:[t],execute:n,...r?.getDiff!=null&&{getDiff:r.getDiff},...r?.validate!=null&&{validate:r.validate}}}async function H(e,t=new Map,n={}){let r={};if(e.length===0)return r;for(let i of e){let e={...n,...r};if(p(i.enabled,e))try{let e,n=t.get(i.id);switch(i.type){case`input`:{let t={message:i.message};if(n!==void 0&&(t.default=String(n)),i.required!==void 0&&(t.required=i.required),e=await c(t),i.required&&(e==null||typeof e==`string`&&e.trim()===``))throw _(`${i.message} is required`,`error`),Error(`Prompt "${i.id}" is required`);break}case`password`:if(e=await u({message:i.message,mask:`*`}),i.required&&(e==null||typeof e==`string`&&e.trim()===``))throw _(`${i.message} is required`,`error`),Error(`Prompt "${i.id}" is required`);break;case`number`:{let t={message:i.message};if(n!==void 0&&(t.default=Number(n)),i.required!==void 0&&(t.required=i.required),i.min!==void 0&&(t.min=i.min),i.max!==void 0&&(t.max=i.max),e=await l(t),i.required&&e==null)throw _(`${i.message} is required`,`error`),Error(`Prompt "${i.id}" is required`);break}case`select`:{let t={message:i.message,choices:i.choices.map(e=>({name:e.name,value:e.value}))};n!==void 0&&(t.default=n),e=await d(t);break}case`confirm`:{let t=n===void 0?!1:!!n;e=await s({message:i.message,default:t});break}default:throw _(`Unknown prompt type: ${i.type}`,`error`),Error(`Unknown prompt type: ${i.type}`)}r[i.id]=e}catch(e){throw e instanceof Error&&_(`Failed to collect prompt "${i.id}": ${e.message}`,`error`),e}}return r}async function U(e,t){if(e===void 0)return;if(typeof e!=`object`||!e||Array.isArray(e))return e;let n=e;if(n.type===`exec`){let e=n.value;if(typeof e!=`string`){_(`Prompt "${t}": exec default value must have a string command`,`error`);return}try{let t=r(e,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:1e4}).trim();if(t.startsWith(`{`)||t.startsWith(`[`))try{return JSON.parse(t)}catch{return t}if(/^-?\d+(?:\.\d+)?$/u.test(t)){let e=Number.parseFloat(t);if(!Number.isNaN(e))return e}return t===`true`||t===`false`?t===`true`:t}catch(e){_(`Prompt "${t}": failed to execute default value command: ${e instanceof Error?e.message:`Unknown error`}`,`warn`);return}}else if(n.type===`static`)return n.value;return e}async function W(e){let t=new Map,n=e.map(async e=>{if(e.default!==void 0){let n=await U(e.default,e.id);n!==void 0&&t.set(e.id,n)}});return await Promise.all(n),t}function G(e){let t=[],n=new Set;for(let r of e){if(n.has(r.id)&&t.push(`Duplicate prompt ID: ${r.id}`),n.add(r.id),/^[\w-]+$/u.test(r.id)||t.push(`Invalid prompt ID "${r.id}": must contain only alphanumeric characters, underscores, and hyphens`),(!r.message||r.message.trim()===``)&&t.push(`Prompt "${r.id}" must have a non-empty message`),r.type===`select`){r.choices.length===0&&t.push(`Select prompt "${r.id}" must have at least one choice`);for(let e of r.choices)(!e.name||e.name.trim()===``)&&t.push(`Select prompt "${r.id}" has a choice with empty name`),e.value===void 0&&t.push(`Select prompt "${r.id}" has a choice with undefined value`)}r.type===`number`&&r.min!==void 0&&r.max!==void 0&&r.min>r.max&&t.push(`Number prompt "${r.id}" has min greater than max`)}return t}const fe=i(t.writeFile);async function pe(r,i){if(r.condition!=null&&r.condition!==``&&!b(r.condition,i)){_(`Condition not met, skipping create task`,`info`);return}let a=e.join(n.cwd(),r.file);if(t.existsSync(a)){_(`File already exists, skipping: ${r.file}`,`info`);return}let o=r.template!=null&&r.template!==``,s=r.templateFile!=null&&r.templateFile!==``;if(!o&&!s)throw Error(`Create task requires either "template" (inline) or "templateFile" (file path) to be specified`);if(o&&s)throw Error(`Create task cannot have both "template" and "templateFile" specified. Use one or the other.`);let c;if(s&&r.templateFile.endsWith(`.hbs`))c=x(r.templateFile,i);else if(s){let a=r.templateFile,o=e.isAbsolute(a)?a:e.join(n.cwd(),a);if(!t.existsSync(o))throw Error(`Template file not found: ${a}`);c=v(t.readFileSync(o,`utf-8`),i)}else c=v(r.template,i);let l=e.dirname(a);t.existsSync(l)||t.mkdirSync(l,{recursive:!0}),await fe(a,c),_(`Created file: ${r.file}`,`success`)}const me={name:`create`,version:`1.0.0`,taskTypes:[`create`],execute:async(e,t,n)=>{n.dryRun||await pe(e.config,t)}};async function he(r,i){let{paths:a,condition:o}=r;if(o!=null&&o!==``){if(!i){_(`Condition specified but no config provided, skipping deletion`,`warn`);return}if(!b(o,i)){_(`Condition not met, skipping deletion`,`info`);return}}for(let r of a){let i=e.join(n.cwd(),r);t.existsSync(i)&&t.rmSync(i,{recursive:!0,force:!0})}}const ge={name:`delete`,version:`1.0.0`,taskTypes:[`delete`],execute:async(e,t,n)=>{n.dryRun||await he(e.config,t)}};async function _e(t,i){if(t.condition!=null&&t.condition!==``){if(!i){_(`Condition specified but no config provided, skipping exec`,`warn`);return}if(!b(t.condition,i)){_(`Condition not met, skipping exec task`,`info`);return}}let a=t.cwd==null?n.cwd():e.join(n.cwd(),t.cwd);r(t.command,{cwd:a,stdio:`inherit`})}const ve={name:`exec`,version:`1.0.0`,taskTypes:[`exec`],execute:async(e,t,n)=>{n.dryRun||await _e(e.config,t)}};async function ye(i,a){if(i.condition!=null&&i.condition!==``){if(!a){_(`Condition specified but no config provided, skipping git-init`,`warn`);return}if(!b(i.condition,a)){_(`Condition not met, skipping git-init task`,`info`);return}}if(i.removeExisting){let r=e.join(n.cwd(),`.git`);t.existsSync(r)&&t.rmSync(r,{recursive:!0,force:!0})}if(r(`git init`,{stdio:`inherit`}),i.initialCommit){let e=i.message??`Initial commit`;r(`git add .`,{stdio:`inherit`}),r(`git commit -m "${e}"`,{stdio:`inherit`})}}const be={name:`git-init`,version:`1.0.0`,taskTypes:[`git-init`],execute:async(e,t,n)=>{n.dryRun||await ye(e.config,t)}},xe=i(t.readFile),Se=i(t.writeFile);async function Ce(t,r){if(t.condition!=null&&t.condition!==``&&!b(t.condition,r)){_(`Condition not met, skipping regex-replace task`,`info`);return}let i=e.join(n.cwd(),t.file),{pattern:a}=t,o=t.flags??``,s=t.replacement||``,c=await xe(i,`utf-8`),l=new RegExp(a,o);c=c.replace(l,v(s,r)),await Se(i,c)}const we={name:`regex-replace`,version:`1.0.0`,taskTypes:[`regex-replace`],execute:async(e,t,n)=>{n.dryRun||await Ce(e.config,t)}},Te=i(t.rename);async function Ee(r,i){if(r.condition!=null&&r.condition!==``&&!b(r.condition,i)){_(`Condition not met, skipping rename task`,`info`);return}let a=e.join(n.cwd(),v(r.from,i)),o=e.join(n.cwd(),v(r.to,i));if(!t.existsSync(a)){_(`Source path does not exist: ${a}`,`warn`);return}await Te(a,o)}const De={name:`rename`,version:`1.0.0`,taskTypes:[`rename`],execute:async(e,t,n)=>{n.dryRun||await Ee(e.config,t)}},Oe=i(t.readFile),ke=i(t.writeFile);async function Ae(r,i){if(r.condition!=null&&r.condition!==``&&!b(r.condition,i)){_(`Condition not met, skipping replace-in-file task`,`info`);return}let a=e.join(n.cwd(),r.file),{replacements:o}=r;if(!t.existsSync(a)){_(`File not found: ${a}, skipping`,`warn`);return}let s=await Oe(a,`utf-8`);for(let{find:e,replace:t}of o){let n=v(t,i);s=s.replace(new RegExp(e,`gu`),n)}await ke(a,s)}const je={name:`replace-in-file`,version:`1.0.0`,taskTypes:[`replace-in-file`],execute:async(e,t,n)=>{n.dryRun||await Ae(e.config,t)}},K=i(t.readFile);function q(e){try{let t=new URL(e);return t.protocol===`http:`||t.protocol===`https:`}catch{return!1}}function J(t,r){if(q(t))return t;if(r==null||r===``)return e.isAbsolute(t)?t:e.resolve(n.cwd(),t);if(q(r))try{let e=new URL(`.`,r);return new URL(t,e).href}catch{throw Error(`Failed to resolve templateFile "${t}" relative to remote template "${r}"`)}let i=e.dirname(r);return e.isAbsolute(t)?t:e.resolve(i,t)}async function Y(e){if(q(e))return X(e);if(!t.existsSync(e))throw Error(`Template file not found: ${e}`);return K(e,`utf-8`)}async function X(e){try{let t=await fetch(e);if(!t.ok)throw Error(`Failed to fetch template from ${e}: ${t.status} ${t.statusText}`);return await t.text()}catch(t){throw t instanceof Error&&t.message.includes(`Failed to fetch`)?t:Error(`Failed to fetch template from ${e}: ${t instanceof Error?t.message:String(t)}`)}}const Z=new Map;async function Me(r,i=new Set){let a=q(r),o;if(o=a||e.isAbsolute(r)?r:e.resolve(n.cwd(),r),Z.has(o))return Z.get(o);if(i.has(o))throw Error(`Circular dependency detected: ${Array.from(i).join(` -> `)} -> ${o}`);i.add(o);let s;if(a)s=await X(o);else{if(!t.existsSync(o))throw Error(`Template file not found: ${o}`);s=await K(o,`utf-8`)}let c;try{c=JSON.parse(s)}catch(e){throw Error(`Failed to parse template file ${o}: ${e instanceof Error?e.message:String(e)}`)}if(c.tasks!==void 0&&!Array.isArray(c.tasks))throw TypeError(`Invalid template file ${o}: 'tasks' must be an array if provided`);c.tasks===void 0&&(c.tasks=[]);for(let e of c.tasks)e.$sourceUrl=o;return Z.set(o,c),c}async function Q(t,r,i=new Set){let a=q(t),o;if(o=a||e.isAbsolute(t)?t:r==null?e.resolve(n.cwd(),t):q(r)?new URL(t,r).href:e.resolve(r,t),i.has(o))throw Error(`Circular dependency detected: ${Array.from(i).join(` -> `)} -> ${o}`);i.add(o);let s=await Me(o);if(s.extends==null||s.extends===``)return s;let c=q(o)?new URL(`.`,o).href:e.dirname(o),l=Array.isArray(s.extends)?s.extends:[s.extends],u=[];for(let e of l){let t=await Q(e,c,i);u.push(t)}return Ne([...u,s])}function Ne(e){if(e.length===0)return{tasks:[]};if(e.length===1)return e[0];let t=new Map,n=new Map,r=new Map;for(let i of e){if(i.prompts!=null)for(let e of i.prompts)r.set(e.id,{...e});if(i.variables!=null)for(let e of i.variables)n.set(e.id,{...e});for(let e of i.tasks??[])if(t.has(e.id)){let n=t.get(e.id);t.set(e.id,Pe(n,e))}else t.set(e.id,{...e})}let i={tasks:Array.from(t.values())};return r.size>0&&(i.prompts=Array.from(r.values())),n.size>0&&(i.variables=Array.from(n.values())),i}function Pe(e,t){let n=typeof e.config==`object`&&e.config!==null&&typeof t.config==`object`&&t.config!==null?{...e.config,...t.config}:t.config,r=e.prompts?[...e.prompts]:void 0;if(t.prompts&&t.prompts.length>0)if(!r)r=[...t.prompts];else{let e=new Map(r.map(e=>[e.id,e]));for(let n of t.prompts)e.set(n.id,n);r=Array.from(e.values())}let i=e.variables?[...e.variables]:void 0;if(t.variables&&t.variables.length>0)if(!i)i=[...t.variables];else{let e=new Map(i.map(e=>[e.id,e]));for(let n of t.variables)e.set(n.id,n);i=Array.from(e.values())}let a=[...e.dependencies??[],...t.dependencies??[]],o=a.length>0?[...new Set(a)]:void 0,s=t.$sourceUrl??e.$sourceUrl;return{...e,...t,config:n,...r!=null&&{prompts:r},...i!=null&&{variables:i},...o!=null&&{dependencies:o},...s!=null&&{$sourceUrl:s}}}function Fe(){Z.clear()}async function Ie(e){_(`Loading tasks from ${e}...`,`info`);let t=await Q(e);_(`Loaded ${t.tasks?.length??0} task(s)`,`info`),t.extends!=null&&t.extends!==``&&_(`Extended from: ${(Array.isArray(t.extends)?t.extends:[t.extends]).join(`, `)}`,`info`),t.prompts!=null&&t.prompts.length>0&&_(`Found ${t.prompts.length} top-level prompt(s)`,`info`),t.variables!=null&&t.variables.length>0&&_(`Found ${t.variables.length} top-level variable(s)`,`info`);let n={tasks:t.tasks??[]};return t.prompts!=null&&(n.prompts=t.prompts),t.variables!=null&&(n.variables=t.variables),n}const Le=i(t.writeFile);async function Re(t,r,i){if(t.condition!=null&&t.condition!==``&&!b(t.condition,r)){_(`Condition not met, skipping template task`,`info`);return}let a=e.join(n.cwd(),t.file),o=t.template!=null&&t.template!==``,s=t.templateFile!=null&&t.templateFile!==``;if(!o&&!s)throw Error(`Template task requires either "template" (inline) or "templateFile" (file path) to be specified`);if(o&&s)throw Error(`Template task cannot have both "template" and "templateFile" specified. Use one or the other.`);let c;if(s&&t.templateFile.endsWith(`.hbs`)){let e=await Y(J(t.templateFile,i?.$sourceUrl));c=(await import(`handlebars`)).default.compile(e)(r)}else c=v(s?await Y(J(t.templateFile,i?.$sourceUrl)):t.template,r);await Le(a,c)}const ze={name:`template`,version:`1.0.0`,taskTypes:[`template`],execute:async(e,t,n)=>{n.dryRun||await Re(e.config,t,e)}},Be=i(t.readFile),Ve=i(t.writeFile);async function He(t,r){if(t.condition!=null&&t.condition!==``&&!b(t.condition,r)){_(`Condition not met, skipping update-json task`,`info`);return}let i=e.join(n.cwd(),t.file),{updates:a}=t,o=await Be(i,`utf-8`),s=JSON.parse(o);function c(e){if(typeof e==`string`)return v(e,r);if(Array.isArray(e))return e.map(e=>c(e));if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[n]=c(r);return t}return e}for(let[e,t]of Object.entries(a)){let n=c(t);e.includes(`.`)?y(s,e,n):s[e]=n}await Ve(i,`${JSON.stringify(s,null,2)}\n`)}const Ue={name:`update-json`,version:`1.0.0`,taskTypes:[`update-json`],execute:async(e,t,n)=>{n.dryRun||await He(e.config,t)}};let We=!1;function Ge(){We||=(L(Ue),L(ze),L(me),L(we),L(je),L(ge),L(De),L(be),L(ve),!0)}async function Ke(e,t,n=!1){if(Ge(),n){_(`[DRY RUN] Would execute: ${e.name}`,`info`);return}if(z(e.type)){await V(e,t,{dryRun:n});return}throw TypeError(`Unknown task type: ${e.type}`)}async function qe(e,t,r,i,a=!1){try{return _(`[${r}/${i}] Running: ${e.name}...`,`info`),await Ke(e,t,a),_(`✓ ${e.name}`,`success`),!0}catch(t){return _(`✗ Failed: ${e.name}`,`error`),t instanceof Error&&(_(` Reason: ${t.message}`,`error`),t.stack!=null&&n.env.DEBUG!=null&&console.error(t.stack)),e.required&&_(` This is a required task. Initialization cannot continue.`,`error`),!1}}function Je(e){let t=[],n=new Set,r=new Set,i=new Map(e.map(e=>[e.id,e]));function a(e){if(n.has(e))return;if(r.has(e))throw Error(`Circular dependency detected involving task: ${e}`);r.add(e);let o=i.get(e);if(!o)throw Error(`Task not found: ${e}`);if(o.dependencies)for(let e of o.dependencies)a(e);r.delete(e),n.add(e),t.push(o)}for(let t of e)n.has(t.id)||a(t.id);return t}function $(e,t=new Map){let n={};for(let r of e){let e=t.get(r.id);e!==void 0&&(n[r.id]=e)}return n}async function Ye(e,t){if(e==null)return;if(typeof e!=`object`||!e||Array.isArray(e))return e;let n=e;if(n.type===`exec`){let e=n.value;if(typeof e!=`string`){_(`Variable "${t}": exec value must have a string command`,`error`);return}try{let t=r(e,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:1e4}).trim();if(t.startsWith(`{`)||t.startsWith(`[`))try{return JSON.parse(t)}catch{return t}if(/^-?\d+(?:\.\d+)?$/u.test(t)){let e=Number.parseFloat(t);if(!Number.isNaN(e))return e}return t===`true`||t===`false`?t===`true`:t}catch(e){_(`Variable "${t}": failed to execute command: ${e instanceof Error?e.message:`Unknown error`}`,`warn`);return}}else if(n.type===`static`)return n.value;return e}async function Xe(e){let t=new Map,n=e.map(async e=>{let t=await Ye(e.value,e.id);return{id:e.id,value:t}}),r=await Promise.all(n);for(let e of r)e.value!==void 0&&t.set(e.id,e.value);return t}function Ze(e){let t=[],n=new Set;for(let r of e)if(n.has(r.id)&&t.push(`Duplicate variable ID: "${r.id}"`),n.add(r.id),/^[\w$]+$/u.test(r.id)||t.push(`Variable ID "${r.id}" is invalid. Must contain only letters, numbers, underscore, or dollar sign.`),r.value===void 0||r.value===null)t.push(`Variable "${r.id}" must have a value`);else if(typeof r.value==`object`&&!Array.isArray(r.value)&&r.value!==null){let e=r.value;e.type==null||e.type===``?t.push(`Variable "${r.id}": value object must have a "type" field ("static" or "exec")`):e.type!==`static`&&e.type!==`exec`&&t.push(`Variable "${r.id}": type must be "static" or "exec", got "${e.type}"`),(e.value===void 0||e.value===null)&&t.push(`Variable "${r.id}": value config must have a "value" field`),e.type===`exec`&&typeof e.value!=`string`&&t.push(`Variable "${r.id}": exec type must have a string command as value`)}return t}const Qe=i(t.readFile);async function $e(i,a){let o=i.filter(e=>p(e.enabled,f()));_(`Resolving task dependencies...`,`info`);let s=Je(o);_(`Welcome! Let's execute your tasks.`,`info`),a.dryRun&&_(`🔍 DRY RUN MODE - No changes will be made`,`warn`),_(`This will execute your project tasks based on the defined configuration.`,`info`);let c=f(),l=a.globalVariables??[],u=[],d=[...l];for(let e of s)if(e.variables&&e.variables.length>0)for(let t of e.variables)u.push(t),d.push(t);if(d.length>0){let e=Ze(d);e.length>0&&(_(`❌ Variable validation errors:`,`error`),e.forEach(e=>_(` - ${e}`,`error`)),n.exit(1)),_(`Resolving variable values...`,`info`);let t=$(d,await Xe(d));Object.assign(c,t),Object.keys(t).length>0&&_(`✓ Resolved ${Object.keys(t).length} variable(s)`,`success`)}let m=a.globalPrompts??[],h=[],v=[...m];for(let e of s)if(e.prompts&&e.prompts.length>0)for(let t of e.prompts)h.push(t),v.push(t);if(v.length>0){let e=G(v);e.length>0&&(_(`❌ Prompt validation errors:`,`error`),e.forEach(e=>_(` - ${e}`,`error`)),n.exit(1)),_(`Resolving prompt default values...`,`info`);let t=await W(v),r={};if(m.length>0&&(_(`📋 Top-level prompts (available to all tasks):`,`info`),r=await H(m,t,c),Object.assign(c,r)),h.length>0){m.length>0&&_(`📋 Task-specific prompts:`,`info`);let e=await H(h,t,c);Object.assign(c,e)}}let y=s.filter(e=>p(e.enabled,c));if(_(`${y.length} of ${s.length} task(s) enabled for execution`,`info`),a.dryRun){await N(y,c),_(`🔍 Dry run completed - no changes were made`,`info`),_(`Run without --dry-run to apply changes`,`info`);return}_(`Starting task execution...`,`info`),await B(`beforeAll`,c);let b=y.length,x=0,S=0,C=[];for(let e=0;e<y.length;e++){let t=y[e];if(t!=null)if(await B(`beforeTask`,t,c),await qe(t,c,e+1,b,a.dryRun))x++,C.push(t.id),await B(`afterTask`,t,c);else if(t.required){S++,await B(`onError`,Error(`Task ${t.name} failed`),t);break}else _(`⚠️ Non-critical task failed, continuing...`,`warn`),await B(`onError`,Error(`Task ${t.name} failed`),t)}if(S>0&&(_(`❌ Task execution failed with ${S} critical error(s)`,`error`),_(`✓ Completed: ${x}/${b} tasks`,`info`),n.exit(1)),await B(`afterAll`,c),_(`✅ All tasks completed successfully!`,`success`),_(`✓ Completed: ${x}/${b} tasks`,`success`),!a.dryRun){_(`Next steps:`,`info`),_(`1. Review the changes made to your project`,`info`),_(`2. Commit the changes to git`,`info`);let i=e.join(n.cwd(),`package.json`);t.existsSync(i)&&JSON.parse(await Qe(i,`utf-8`)).scripts?.[`turbo:gen:init`]!=null&&(_(`3. Run "pnpm run turbo:gen:init" to create your first package`,`info`),await g(`Would you like to run turbo:gen:init now?`,!0)&&(_(`Running turbo:gen:init...`,`info`),r(`pnpm run turbo:gen:init`,{stdio:`inherit`})))}}const et=n.argv.includes(`--dry-run`),tt=n.argv.includes(`--force`);async function nt(e){try{let t=e||[];t.length===0&&(_(`⚠️ No tasks defined. Use --tasks-file to specify tasks or call runWithTasks() programmatically.`,`warn`),_(`Example: scaffoldfy --tasks-file ./tasks.json`,`info`),n.exit(1)),await $e(t,{dryRun:et,force:tt,tasksFilePath:void 0})}catch(e){_(`❌ Task execution failed`,`error`),e instanceof Error?(_(`Error: ${e.message}`,`error`),n.env.DEBUG!=null&&console.error(e.stack)):console.error(e),n.exit(1)}}async function rt(e,t){try{await $e(e,{dryRun:t?.dryRun??et,force:t?.force??tt,tasksFilePath:t?.tasksFilePath??void 0,...t?.globalVariables!=null&&{globalVariables:t.globalVariables},...t?.globalPrompts!=null&&{globalPrompts:t.globalPrompts}})}catch(e){_(`❌ Task execution failed`,`error`),e instanceof Error?(_(`Error: ${e.message}`,`error`),n.env.DEBUG!=null&&console.error(e.stack)):console.error(e),n.exit(1)}}export{ie as A,O as B,ae as C,oe as D,z as E,te as F,_ as G,b as H,k as I,y as J,h as K,M as L,N as M,j as N,ce as O,ne as P,A as R,V as S,le as T,m as U,D as V,v as W,U as _,Ye as a,se as b,Ke as c,Q as d,Ie as f,W as g,G as h,Xe as i,ue as j,L as k,qe as l,Ne as m,rt as n,$ as o,Me as p,g as q,Ze as r,Je as s,nt as t,Fe as u,H as v,R as w,de as x,B as y,re as z};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixpilot/scaffoldfy",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.10.0",
|
|
5
5
|
"author": "PixPilot <m.doaie@hotmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
"tsdown": "^0.15.8",
|
|
48
48
|
"typescript": "^5.9.3",
|
|
49
49
|
"@internal/eslint-config": "0.3.0",
|
|
50
|
-
"@internal/
|
|
51
|
-
"@internal/vitest-config": "0.1.0",
|
|
50
|
+
"@internal/prettier-config": "0.0.1",
|
|
52
51
|
"@internal/tsdown-config": "0.1.0",
|
|
53
|
-
"@internal/
|
|
52
|
+
"@internal/tsconfig": "0.1.0",
|
|
53
|
+
"@internal/vitest-config": "0.1.0"
|
|
54
54
|
},
|
|
55
55
|
"prettier": "@internal/prettier-config",
|
|
56
56
|
"scripts": {
|