at-builder 1.4.4 ā 1.5.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 +38 -0
- package/bin/constants/config.js +1 -1
- package/bin/index.js +153 -66
- package/bin/services/telemetry.js +320 -0
- package/package.json +12 -1
- package/.claude/settings.local.json +0 -77
- package/.plop/index.js +0 -5
- package/.vscode/settings.json +0 -6
- package/CustomWrapperPlugin.js +0 -61
- package/DEVELOPMENT.md +0 -164
- package/at-builder-0.0.2.vsix +0 -0
- package/package/package.json +0 -86
- package/src/constants/config.ts +0 -321
- package/src/index.ts +0 -387
- package/src/services/doctor.ts +0 -724
- package/src/services/logger.ts +0 -84
package/src/index.ts
DELETED
|
@@ -1,387 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from "child_process";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import fs from "fs";
|
|
5
|
-
import { Command } from 'commander';
|
|
6
|
-
import { getVersion, getHelpInfo, setupEnv } from "./constants/config";
|
|
7
|
-
import { runDiagnostics, fixIssues } from "./services/doctor";
|
|
8
|
-
import logger from "./services/logger";
|
|
9
|
-
/**
|
|
10
|
-
* Checks if the .env file exists at the current working directory
|
|
11
|
-
*
|
|
12
|
-
* @throws {Error} If the .env file is not found
|
|
13
|
-
*/
|
|
14
|
-
const checkEnvFile = () => {
|
|
15
|
-
logger.info("checkEnvFile", "Checking if .env file exists at current working directory");
|
|
16
|
-
try {
|
|
17
|
-
// Check if the file exists and is readable
|
|
18
|
-
fs.accessSync(path.join(process.cwd(), ".env"), fs.constants.R_OK);
|
|
19
|
-
logger.info("checkEnvFile", ".env file found");
|
|
20
|
-
} catch (error) {
|
|
21
|
-
// If the file does not exist, provide helpful guidance
|
|
22
|
-
console.error('\x1b[31m%s\x1b[0m', `ā Error: .env file not found at ${process.cwd()}`);
|
|
23
|
-
console.error('\x1b[33m%s\x1b[0m', 'š” Run "atb init" to create .env file or "atb doctor --fix" to diagnose and fix configuration issues.');
|
|
24
|
-
logger.error("checkEnvFile", `Error: Couldn't find .env file at location ${process.cwd()}`);
|
|
25
|
-
throw error;
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
// Prepare environment for spawning processes
|
|
30
|
-
const productionEnv = {
|
|
31
|
-
...process.env,
|
|
32
|
-
executionPath: process.cwd()
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
// Commander setup with proper subcommands
|
|
36
|
-
const setupCommander = async () => {
|
|
37
|
-
logger.info("setupCommander", "Setting up commander");
|
|
38
|
-
const version = await getVersion();
|
|
39
|
-
const program = new Command();
|
|
40
|
-
|
|
41
|
-
program
|
|
42
|
-
.name('atb')
|
|
43
|
-
.description('Adobe Target Activity Development CLI')
|
|
44
|
-
.version(version, "-V, --version")
|
|
45
|
-
.option("-v, --verbose", "Enable verbose logging");
|
|
46
|
-
|
|
47
|
-
// Add subcommands with proper actions
|
|
48
|
-
program
|
|
49
|
-
.command('init')
|
|
50
|
-
.description('Initialize project with .env configuration and templates')
|
|
51
|
-
.action(async (options, command) => {
|
|
52
|
-
const globalOpts = command.parent.opts();
|
|
53
|
-
await handleInit(globalOpts.verbose);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
program
|
|
57
|
-
.command('new')
|
|
58
|
-
.description('Create a new Adobe Target activity with variations')
|
|
59
|
-
.action(async (options, command) => {
|
|
60
|
-
const globalOpts = command.parent.opts();
|
|
61
|
-
await handleNew(globalOpts.verbose);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
program
|
|
65
|
-
.command('build')
|
|
66
|
-
.description('Build activity for development or production')
|
|
67
|
-
.option('--prod', 'Build for production deployment')
|
|
68
|
-
.action(async (options, command) => {
|
|
69
|
-
const globalOpts = command.parent.opts();
|
|
70
|
-
checkEnvFile();
|
|
71
|
-
await handleBuild(options.prod, globalOpts.verbose);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
program
|
|
75
|
-
.command('dev')
|
|
76
|
-
.description('Start development server with file watching')
|
|
77
|
-
.option('--browser', 'Open in browser automatically')
|
|
78
|
-
.action(async (options, command) => {
|
|
79
|
-
const globalOpts = command.parent.opts();
|
|
80
|
-
checkEnvFile();
|
|
81
|
-
await handleDev(options.browser, globalOpts.verbose);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
program
|
|
85
|
-
.command('deploy')
|
|
86
|
-
.description('Deploy activity to Adobe Target using at-deploy.js')
|
|
87
|
-
.option('--dry-run', 'Run deployment in dry-run mode without actual deployment')
|
|
88
|
-
.option('--force', 'Override the 60s post-deploy cooldown lock')
|
|
89
|
-
.action(async (options, command) => {
|
|
90
|
-
const globalOpts = command.parent.opts();
|
|
91
|
-
checkEnvFile();
|
|
92
|
-
await handleDeploy(options.dryRun, options.force, globalOpts.verbose);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
program
|
|
96
|
-
.command('sync')
|
|
97
|
-
.description('Sync build.config.json with the Adobe Target activity definition')
|
|
98
|
-
.option('--scaffold', 'Auto-create missing variation folders with boilerplate')
|
|
99
|
-
.action(async (options, command) => {
|
|
100
|
-
const globalOpts = command.parent.opts();
|
|
101
|
-
checkEnvFile();
|
|
102
|
-
await handleSync(options.scaffold, globalOpts.verbose);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
program
|
|
106
|
-
.command('doctor')
|
|
107
|
-
.description('Diagnose and fix project configuration issues')
|
|
108
|
-
.option('--fix', 'Automatically fix detected issues')
|
|
109
|
-
.action(async (options, command) => {
|
|
110
|
-
const globalOpts = command.parent.opts();
|
|
111
|
-
await handleDoctor(options.fix, globalOpts.verbose);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
program
|
|
115
|
-
.command('install-extension')
|
|
116
|
-
.description('Install the at-builder VSCode extension from the Marketplace')
|
|
117
|
-
.option('--editor <bin>', 'Editor CLI to use (e.g. code, agy, cursor, codium)', 'code')
|
|
118
|
-
.action(async (options, command) => {
|
|
119
|
-
const globalOpts = command.parent.opts();
|
|
120
|
-
await handleInstallExtension(options.editor, globalOpts.verbose);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
await program.parseAsync(process.argv);
|
|
124
|
-
|
|
125
|
-
logger.info("setupCommander", "Commander setup complete");
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Spawn a command using `npm` with the given command array and environment object.
|
|
132
|
-
*
|
|
133
|
-
* Any entries in `scriptArgs` are forwarded to the underlying script via npm's
|
|
134
|
-
* `--` passthrough (e.g. `npm run foo -- --dry-run`).
|
|
135
|
-
*
|
|
136
|
-
* @param commandArr - The array of command strings to pass to `npm`.
|
|
137
|
-
* @param env - The environment object to pass to the spawned process.
|
|
138
|
-
* @param scriptArgs - Optional flags/args to forward to the npm script itself.
|
|
139
|
-
*/
|
|
140
|
-
const runCommand = (commandArr: string[], env: NodeJS.ProcessEnv, scriptArgs: string[] = []): void => {
|
|
141
|
-
const fullArgs = scriptArgs.length > 0
|
|
142
|
-
? [...commandArr, "--", ...scriptArgs]
|
|
143
|
-
: commandArr;
|
|
144
|
-
|
|
145
|
-
logger.info("runCommand", `Running npm command [${fullArgs.join(", ")}]`);
|
|
146
|
-
logger.info("runCommand", `Current working directory: ${process.cwd()}`);
|
|
147
|
-
|
|
148
|
-
spawn("npm", fullArgs, {
|
|
149
|
-
cwd: path.join(__dirname, "../"),
|
|
150
|
-
env,
|
|
151
|
-
shell: true,
|
|
152
|
-
stdio: "inherit",
|
|
153
|
-
});
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Handles the init command
|
|
158
|
-
*/
|
|
159
|
-
const handleInit = async (verbose: boolean): Promise<void> => {
|
|
160
|
-
if (verbose) logger.info("verbose", "Initializing new .env file");
|
|
161
|
-
|
|
162
|
-
// Run npm init in the current working directory (where user ran atb init)
|
|
163
|
-
spawn("npm", ["init", "-y"], {
|
|
164
|
-
cwd: process.cwd(),
|
|
165
|
-
env: process.env,
|
|
166
|
-
shell: true,
|
|
167
|
-
stdio: "inherit",
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// Install @babel/runtime as dev dependency in the current directory
|
|
171
|
-
spawn("npm", ["install", "@babel/runtime", "-D"], {
|
|
172
|
-
cwd: process.cwd(),
|
|
173
|
-
env: process.env,
|
|
174
|
-
shell: true,
|
|
175
|
-
stdio: "inherit",
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
setupEnv(process.cwd());
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Handles the new command
|
|
183
|
-
*/
|
|
184
|
-
const handleNew = async (verbose: boolean): Promise<void> => {
|
|
185
|
-
if (verbose) logger.info("verbose", "Creating new activity");
|
|
186
|
-
runCommand(["run", "atb:plop:new:activity"], productionEnv);
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Handles the build command
|
|
191
|
-
*/
|
|
192
|
-
const handleBuild = async (prod: boolean, verbose: boolean): Promise<void> => {
|
|
193
|
-
if (verbose) logger.info("verbose", `Building in ${prod ? 'production' : 'development'} mode`);
|
|
194
|
-
|
|
195
|
-
if (prod) {
|
|
196
|
-
process.env['NODE_ENV'] = 'production';
|
|
197
|
-
logger.info("handleBuild", "Running build with production environment");
|
|
198
|
-
runCommand(['run', 'atb:build:prod'], productionEnv);
|
|
199
|
-
} else {
|
|
200
|
-
logger.info("handleBuild", "Running build with development environment");
|
|
201
|
-
runCommand(['run', 'atb:build:dev'], productionEnv);
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Handles the dev command
|
|
207
|
-
*/
|
|
208
|
-
const handleDev = async (browser: boolean, verbose: boolean): Promise<void> => {
|
|
209
|
-
if (verbose) logger.info("verbose", `Starting development server with browser=${browser}`);
|
|
210
|
-
|
|
211
|
-
const commandArr = ['run', browser ? 'atb:build:dev:puppeteer' : 'atb:build:dev'];
|
|
212
|
-
logger.info("handleDev", `Running command: ${commandArr.join(', ')}`);
|
|
213
|
-
|
|
214
|
-
runCommand(commandArr, productionEnv);
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Handles the deploy command
|
|
219
|
-
*/
|
|
220
|
-
const handleDeploy = async (dryRun: boolean, force: boolean, verbose: boolean): Promise<void> => {
|
|
221
|
-
if (verbose) logger.info("verbose", `Deploying to Adobe Target with dry-run=${dryRun} force=${force}`);
|
|
222
|
-
|
|
223
|
-
logger.info("handleDeploy", "Running Adobe Target deployment");
|
|
224
|
-
|
|
225
|
-
const scriptArgs: string[] = [];
|
|
226
|
-
if (dryRun) scriptArgs.push('--dry-run');
|
|
227
|
-
if (force) scriptArgs.push('--force');
|
|
228
|
-
|
|
229
|
-
runCommand(['run', 'atb:build:deploy'], productionEnv, scriptArgs);
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Handles the sync command
|
|
234
|
-
*/
|
|
235
|
-
const handleSync = async (scaffold: boolean, verbose: boolean): Promise<void> => {
|
|
236
|
-
if (verbose) logger.info("verbose", `Syncing build.config.json with scaffold=${scaffold}`);
|
|
237
|
-
|
|
238
|
-
logger.info("handleSync", "Running Adobe Target sync");
|
|
239
|
-
|
|
240
|
-
const scriptArgs: string[] = [];
|
|
241
|
-
if (scaffold) scriptArgs.push('--scaffold');
|
|
242
|
-
|
|
243
|
-
runCommand(['run', 'atb:build:sync'], productionEnv, scriptArgs);
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Handles the install-extension command.
|
|
248
|
-
*
|
|
249
|
-
* Installs the at-builder VSCode extension from the VS Code Marketplace
|
|
250
|
-
* using the editor's CLI. Defaults to `code`; users on Cursor/VSCodium
|
|
251
|
-
* can pass --editor.
|
|
252
|
-
*/
|
|
253
|
-
/**
|
|
254
|
-
* Per-editor install hints for when the CLI binary isn't on PATH. Each
|
|
255
|
-
* recognized editor gets a one-line, copy-pasteable suggestion. Anything
|
|
256
|
-
* else falls back to a generic hint.
|
|
257
|
-
*/
|
|
258
|
-
const EDITOR_INSTALL_HINTS: Record<string, string> = {
|
|
259
|
-
code: 'Open VSCode and run Command Palette ā "Shell Command: Install \'code\' command in PATH".',
|
|
260
|
-
agy: 'Open Antigravity IDE and run Command Palette ā "Shell Command: Install \'agy\' command in PATH".',
|
|
261
|
-
cursor: 'Open Cursor and run Command Palette ā "Shell Command: Install \'cursor\' command in PATH".',
|
|
262
|
-
codium: 'Open VSCodium and run Command Palette ā "Shell Command: Install \'codium\' command in PATH".',
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
const reportEditorNotFound = (editor: string): void => {
|
|
266
|
-
console.error(`ā "${editor}" CLI not found in PATH.`);
|
|
267
|
-
const hint = EDITOR_INSTALL_HINTS[editor]
|
|
268
|
-
|| `Make sure the "${editor}" CLI is installed and on your PATH, or pass a different --editor.`;
|
|
269
|
-
console.error(`š” ${hint}`);
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
const handleInstallExtension = async (editor: string, verbose: boolean): Promise<void> => {
|
|
273
|
-
const extensionId = "UpendraSengar.at-builder";
|
|
274
|
-
|
|
275
|
-
if (verbose) logger.info("verbose", `Installing ${extensionId} via ${editor}`);
|
|
276
|
-
|
|
277
|
-
console.log(`š¦ Installing ${extensionId} from the Marketplace via "${editor}"...`);
|
|
278
|
-
|
|
279
|
-
const result = spawn(editor, ["--install-extension", extensionId], {
|
|
280
|
-
stdio: "inherit",
|
|
281
|
-
shell: true
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
result.on("error", (err) => {
|
|
285
|
-
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
286
|
-
reportEditorNotFound(editor);
|
|
287
|
-
} else {
|
|
288
|
-
console.error(`ā Failed to launch "${editor}": ${err.message}`);
|
|
289
|
-
}
|
|
290
|
-
process.exit(1);
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
result.on("exit", (code) => {
|
|
294
|
-
if (code === 0) {
|
|
295
|
-
console.log("ā
Extension installed. Reload your editor window to activate.");
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
// 127 = shell's "command not found". With shell:true the spawn 'error'
|
|
299
|
-
// event never fires for missing CLIs, so we surface the same hint here.
|
|
300
|
-
if (code === 127) {
|
|
301
|
-
reportEditorNotFound(editor);
|
|
302
|
-
process.exit(1);
|
|
303
|
-
}
|
|
304
|
-
console.error(`ā "${editor} --install-extension" exited with code ${code}.`);
|
|
305
|
-
process.exit(code ?? 1);
|
|
306
|
-
});
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Handles the doctor command
|
|
311
|
-
*/
|
|
312
|
-
const handleDoctor = async (autoFix: boolean, verbose: boolean): Promise<void> => {
|
|
313
|
-
if (verbose) logger.info("verbose", `Running diagnostics with auto-fix=${autoFix}`);
|
|
314
|
-
|
|
315
|
-
logger.info("handleDoctor", "Diagnosing project configuration");
|
|
316
|
-
|
|
317
|
-
try {
|
|
318
|
-
// Run diagnostics
|
|
319
|
-
const issues = await runDiagnostics(process.cwd(), verbose);
|
|
320
|
-
|
|
321
|
-
if (issues.length === 0) {
|
|
322
|
-
console.log("ā
No issues found. Your project configuration is healthy!");
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Display issues
|
|
327
|
-
console.log(`\nš Found ${issues.length} issue(s):\n`);
|
|
328
|
-
issues.forEach((issue, index) => {
|
|
329
|
-
console.log(`${index + 1}. ${issue.severity === 'error' ? 'ā' : 'ā ļø'} ${issue.message}`);
|
|
330
|
-
if (issue.suggestion) {
|
|
331
|
-
console.log(` š” ${issue.suggestion}`);
|
|
332
|
-
}
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
if (autoFix) {
|
|
336
|
-
console.log('\nš§ Attempting to fix issues...\n');
|
|
337
|
-
const fixed = await fixIssues(issues, process.cwd(), verbose);
|
|
338
|
-
console.log(`\nā
Fixed ${fixed} issue(s).`);
|
|
339
|
-
|
|
340
|
-
if (fixed < issues.length) {
|
|
341
|
-
console.log(`ā ļø ${issues.length - fixed} issue(s) require manual attention.`);
|
|
342
|
-
}
|
|
343
|
-
} else {
|
|
344
|
-
console.log('\nš” Run `atb doctor --fix` to automatically fix resolvable issues.');
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
} catch (error) {
|
|
348
|
-
logger.error("handleDoctor", `Doctor command failed: ${error.message}`);
|
|
349
|
-
process.exit(1);
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
// Command execution logic
|
|
354
|
-
/**
|
|
355
|
-
* Main command execution entry point
|
|
356
|
-
*/
|
|
357
|
-
const executeCommand = async () => {
|
|
358
|
-
logger.info("executeCommand", "Entering executeCommand");
|
|
359
|
-
await setupCommander();
|
|
360
|
-
logger.info("executeCommand", "Exiting executeCommand");
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
// Print command help
|
|
364
|
-
const printCommandHelp = async () => {
|
|
365
|
-
const help = await getHelpInfo();
|
|
366
|
-
console.log(help);
|
|
367
|
-
process.exit(0);
|
|
368
|
-
};
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Main program flow
|
|
372
|
-
*/
|
|
373
|
-
const main = async () => {
|
|
374
|
-
try {
|
|
375
|
-
await executeCommand();
|
|
376
|
-
} catch (error) {
|
|
377
|
-
logger.error("main", error.message);
|
|
378
|
-
process.exit(1);
|
|
379
|
-
}
|
|
380
|
-
};
|
|
381
|
-
|
|
382
|
-
// Print custom help if no arguments, otherwise let Commander.js handle everything
|
|
383
|
-
if (process.argv.length <= 2) {
|
|
384
|
-
printCommandHelp();
|
|
385
|
-
} else {
|
|
386
|
-
main();
|
|
387
|
-
}
|