at-builder 1.3.3 β†’ 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,7 +51,20 @@
51
51
  "Bash(ls -la \"$\\(yarn global bin\\)/atb\")",
52
52
  "Bash(ls -la \"$\\(yarn global dir \\)/node_modules/at-builder\")",
53
53
  "Bash(git commit -m 'fix: surface ESLint error detail and clean up atb deploy build-failure exit *)",
54
- "Bash(git commit -m 'fix\\(webpack\\): emit correct `variation=` attribute on at-build.html script tag *)"
54
+ "Bash(git commit -m 'fix\\(webpack\\): emit correct `variation=` attribute on at-build.html script tag *)",
55
+ "Bash(yarn install *)",
56
+ "Bash(git rm *)",
57
+ "Bash(git commit -m 'chore\\(deps\\): drop unused/deprecated deps + migrate qs to URLSearchParams *)",
58
+ "Bash(git commit -m 'fix\\(config\\): stop printing red \"Error reading .env\" on every atb invocation *)",
59
+ "Bash(yarn why *)",
60
+ "Bash(git commit -m 'fix\\(plop\\): trim whitespace on all atb new text prompts *)",
61
+ "Bash(atb install-extension *)",
62
+ "Bash(git commit -m 'feat\\(install-extension\\): first-class support for Antigravity IDE \\(agy\\) *)",
63
+ "Bash(npm whoami *)",
64
+ "Bash(npm view *)",
65
+ "Bash(git tag *)",
66
+ "Bash(git push *)",
67
+ "Bash(npm publish *)"
55
68
  ]
56
69
  }
57
70
  }
@@ -19,6 +19,11 @@ const prompts = function (inquirer) {
19
19
  console.log(kleur.cyan().bold(' πŸ§ͺ Create a new Adobe Target activity'));
20
20
  console.log(kleur.gray(' ─ scaffolds variation folders + shared/build.config.json\n'));
21
21
 
22
+ // All text inputs go through the same trim filter so downstream code never
23
+ // has to deal with stray leading/trailing whitespace (which would otherwise
24
+ // become folder names with trailing spaces, etc.).
25
+ const trim = (input) => (input || '').trim();
26
+
22
27
  return inquirer.prompt([
23
28
  {
24
29
  type: PROMPT_TYPE_LIST,
@@ -35,7 +40,8 @@ const prompts = function (inquirer) {
35
40
  name: 'testName',
36
41
  prefix: kleur.cyan('β€Ί'),
37
42
  message: ask('Activity name', 'folder name, e.g. TEST-1234 hero-banner'),
38
- validate: (input) => input && input.trim()
43
+ filter: trim,
44
+ validate: (input) => input
39
45
  ? true
40
46
  : 'Activity name cannot be empty.'
41
47
  },
@@ -46,7 +52,8 @@ const prompts = function (inquirer) {
46
52
  message: (answers) => answers.activityType === 'xt'
47
53
  ? ask('How many experiences?')
48
54
  : ask('How many variations?', 'control is added automatically'),
49
- validate: (input) => /^[1-9]\d*$/.test(String(input).trim())
55
+ filter: trim,
56
+ validate: (input) => /^[1-9]\d*$/.test(input)
50
57
  ? true
51
58
  : 'Enter a positive integer (1, 2, 3, ...).'
52
59
  },
@@ -55,7 +62,7 @@ const prompts = function (inquirer) {
55
62
  name: 'pageNames',
56
63
  prefix: kleur.cyan('β€Ί'),
57
64
  message: ask('Page names', 'comma-separated for multi-page, blank for single-page'),
58
- filter: (input) => (input || '').trim()
65
+ filter: trim
59
66
  }
60
67
  ]);
61
68
  };
@@ -28,6 +28,6 @@
28
28
  }
29
29
  }
30
30
  catch (err){
31
- console.log(err);
31
+ console.error(err);
32
32
  }
33
33
  }());
@@ -1,8 +1,28 @@
1
- const _camelCase = require('lodash/camelCase');
2
- const _startCase = require('lodash/startCase');
3
-
1
+ /**
2
+ * Convert an arbitrary string to PascalCase. Drop-in replacement for the
3
+ * previous `_startCase(_camelCase(str)).replace(/ /g, '')` lodash chain so we
4
+ * don't pull in 70KB+ of lodash for two trivial string ops.
5
+ *
6
+ * Handles the input shapes plop prompts actually receive:
7
+ * "hello world" β†’ "HelloWorld"
8
+ * "kebab-case-name" β†’ "KebabCaseName"
9
+ * "snake_case_name" β†’ "SnakeCaseName"
10
+ * "FOO_BAR" β†’ "FooBar"
11
+ * "UPSDDO-1234 my-test" β†’ "Upsddo1234MyTest"
12
+ * "alreadyCamel" β†’ "AlreadyCamel"
13
+ * "MyComponent" β†’ "MyComponent"
14
+ */
4
15
  exports.toPascalCase = str => {
5
- return _startCase(_camelCase(str)).replace(/ /g, '');
16
+ if (!str) return '';
17
+ return String(str)
18
+ // insert space at lower→Upper boundary: "fooBar" → "foo Bar"
19
+ .replace(/([a-z\d])([A-Z])/g, '$1 $2')
20
+ // insert space at UPPER→Upperlower boundary: "FOOBar" → "FOO Bar"
21
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
22
+ .split(/[^a-zA-Z0-9]+/)
23
+ .filter(Boolean)
24
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
25
+ .join('');
6
26
  };
7
27
 
8
28
  /**
package/README.md CHANGED
@@ -58,16 +58,16 @@ atb deploy
58
58
 
59
59
  ### **Core Commands**
60
60
 
61
- | Command | Description | Options |
62
- |---------|-------------|---------|
63
- | `atb init` | Initialize project with configuration files | |
64
- | `atb new` | Create new Adobe Target activity with variations | |
65
- | `atb build` | Build activity for development | `--prod` for production |
66
- | `atb dev` | Start development server with file watching | `--browser` to open browser |
67
- | `atb deploy` | Deploy activity to Adobe Target | `--dry-run` for testing, `--force` to override the 60s cooldown |
68
- | `atb sync` | Sync `build.config.json` with the AT activity (pages, experiences, names) | `--scaffold` to auto-create missing variation folders |
69
- | `atb doctor` | Diagnose and fix configuration issues | `--fix` to auto-fix |
70
- | `atb install-extension` | Install the bundled at-builder VSCode extension (.vsix) | `--editor cursor` (or `codium`, etc.) to use a non-VSCode editor CLI |
61
+ | Command | Description | Options |
62
+ | ----------------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------------- |
63
+ | `atb init` | Initialize project with configuration files | |
64
+ | `atb new` | Create new Adobe Target activity with variations | |
65
+ | `atb build` | Build activity for development | `--prod` for production |
66
+ | `atb dev` | Start development server with file watching | `--browser` to open browser |
67
+ | `atb deploy` | Deploy activity to Adobe Target | `--dry-run` for testing, `--force` to override the 60s cooldown |
68
+ | `atb sync` | Sync `build.config.json` with the AT activity (pages, experiences, names) | `--scaffold` to auto-create missing variation folders |
69
+ | `atb doctor` | Diagnose and fix configuration issues | `--fix` to auto-fix |
70
+ | `atb install-extension` | Install the at-builder extension from the Marketplace (defaults to the VSCode `code` CLI) | `--editor agy` for Antigravity IDE; `--editor cursor`, `--editor codium`, or any VSCode-fork CLI on `PATH` |
71
71
 
72
72
  ### **Examples**
73
73
 
@@ -156,7 +156,7 @@ VARIATION="Variation-1"
156
156
  # Adobe Target Deployment
157
157
  ADOBE_CLIENT_ID="your-client-id"
158
158
  ADOBE_CLIENT_SECRET="your-client-secret"
159
- ADOBE_TENANT="" # Optional. Your Adobe org slug (e.g. "ups"). Enables clickable AT UI links in deploy/sync output.
159
+ ADOBE_TENANT="" # Optional. Your Adobe org slug (e.g."tst123"). Enables clickable AT UI links in deploy/sync output.
160
160
  ```
161
161
 
162
162
  ### **Adobe Target Configuration (adobe.config.js)**
@@ -108,7 +108,7 @@ var getHelpInfo = function () { return __awaiter(void 0, void 0, void 0, functio
108
108
  case 0: return [4 /*yield*/, (0, exports.getVersion)()];
109
109
  case 1:
110
110
  version = _a.sent();
111
- return [2 /*return*/, "\n".concat(formatText("\uD83C\uDFAF at-builder", 'cyan', true), " ").concat(formatText("v".concat(version), 'gray'), "\n\n").concat(formatText("Adobe Target Activity Development CLI", 'white', true), "\n\nA streamlined command-line tool for creating, building, and deploying Adobe Target \nA/B testing activities with modern web technologies.\n\n").concat(formatText("USAGE", 'yellow', true), "\n ").concat(formatText("atb", 'cyan'), " ").concat(formatText("<command> [options]", 'gray'), "\n\n").concat(formatText("COMMANDS", 'yellow', true), "\n ").concat(formatText("init", 'cyan', true), " Initialize project with .env configuration and templates\n ").concat(formatText("new", 'cyan', true), " Create a new Adobe Target activity with variations\n ").concat(formatText("build", 'cyan', true), " Build activity for development\n ").concat(formatText("build --prod", 'cyan', true), " Build for production deployment\n ").concat(formatText("dev", 'cyan', true), " Start development server with file watching\n ").concat(formatText("dev --browser", 'cyan', true), " Start development server and open in browser\n ").concat(formatText("deploy", 'cyan', true), " Deploy activity to Adobe Target\n ").concat(formatText("deploy --dry-run", 'cyan', true), " Deploy in dry-run mode without actual deployment\n ").concat(formatText("deploy --force", 'cyan', true), " Override the 60s post-deploy cooldown lock\n ").concat(formatText("sync", 'cyan', true), " Sync build.config.json with the AT activity (pages, experiences, names)\n ").concat(formatText("sync --scaffold", 'cyan', true), " Sync and auto-create any missing variation folders with boilerplate\n ").concat(formatText("doctor", 'cyan', true), " Diagnose and fix project configuration issues\n ").concat(formatText("doctor --fix", 'cyan', true), " Automatically fix detected configuration issues\n ").concat(formatText("install-extension", 'cyan', true), " Install the bundled at-builder VSCode extension (.vsix)\n \n").concat(formatText("GLOBAL OPTIONS", 'yellow', true), "\n ").concat(formatText("-v, --verbose", 'green'), " Enable detailed logging\n ").concat(formatText("-V, --version", 'green'), " Display version information\n ").concat(formatText("-h, --help", 'green'), " Show help information\n\n").concat(formatText("EXAMPLES", 'yellow', true), "\n ").concat(formatText("# Initialize new project", 'gray'), "\n ").concat(formatText("atb init", 'white'), "\n \n ").concat(formatText("# Create new activity", 'gray'), "\n ").concat(formatText("atb new", 'white'), "\n \n ").concat(formatText("# Development build with hot reload", 'gray'), "\n ").concat(formatText("atb build", 'white'), "\n \n ").concat(formatText("# Production build for Adobe Target deployment", 'gray'), "\n ").concat(formatText("atb build --prod", 'white'), "\n \n ").concat(formatText("# Development server with browser", 'gray'), "\n ").concat(formatText("atb dev --browser", 'white'), "\n \n ").concat(formatText("# Deploy to Adobe Target", 'gray'), "\n ").concat(formatText("atb deploy", 'white'), "\n \n ").concat(formatText("# Deploy in dry-run mode", 'gray'), "\n ").concat(formatText("atb deploy --dry-run", 'white'), "\n\n ").concat(formatText("# Sync build.config.json from Adobe Target", 'gray'), "\n ").concat(formatText("atb sync", 'white'), "\n\n ").concat(formatText("# Sync and scaffold missing variation folders", 'gray'), "\n ").concat(formatText("atb sync --scaffold", 'white'), "\n\n ").concat(formatText("# Check project configuration", 'gray'), "\n ").concat(formatText("atb doctor", 'white'), "\n \n ").concat(formatText("# Auto-fix configuration issues", 'gray'), "\n ").concat(formatText("atb doctor --fix", 'white'), "\n\n").concat(formatText("WORKFLOW", 'yellow', true), "\n ").concat(formatText("1.", 'cyan'), " Run ").concat(formatText("atb init", 'white'), " to set up project configuration\n ").concat(formatText("2.", 'cyan'), " Run ").concat(formatText("atb new", 'white'), " to create activity templates \n ").concat(formatText("3.", 'cyan'), " Develop variations in ").concat(formatText("/Activities/{name}/Variation-*/", 'gray'), "\n ").concat(formatText("4.", 'cyan'), " Run ").concat(formatText("atb build", 'white'), " for development testing\n ").concat(formatText("5.", 'cyan'), " Run ").concat(formatText("atb build --prod", 'white'), " for Adobe Target deployment\n ").concat(formatText("6.", 'cyan'), " Run ").concat(formatText("atb deploy", 'white'), " to deploy to Adobe Target\n\n").concat(formatText("SUPPORT", 'yellow', true), "\n Repository: ").concat(formatText("https://github.com/upesenga/at-builder", 'blue'), "\n Issues: ").concat(formatText("https://github.com/upesenga/at-builder/issues", 'blue'), "\n License: ").concat(formatText("MIT", 'green'), "\n")];
111
+ return [2 /*return*/, "\n".concat(formatText("\uD83C\uDFAF at-builder", 'cyan', true), " ").concat(formatText("v".concat(version), 'gray'), "\n\n").concat(formatText("Adobe Target Activity Development CLI", 'white', true), "\n\nA streamlined command-line tool for creating, building, and deploying Adobe Target \nA/B testing activities with modern web technologies.\n\n").concat(formatText("USAGE", 'yellow', true), "\n ").concat(formatText("atb", 'cyan'), " ").concat(formatText("<command> [options]", 'gray'), "\n\n").concat(formatText("COMMANDS", 'yellow', true), "\n ").concat(formatText("init", 'cyan', true), " Initialize project with .env configuration and templates\n ").concat(formatText("new", 'cyan', true), " Create a new Adobe Target activity with variations\n ").concat(formatText("build", 'cyan', true), " Build activity for development\n ").concat(formatText("build --prod", 'cyan', true), " Build for production deployment\n ").concat(formatText("dev", 'cyan', true), " Start development server with file watching\n ").concat(formatText("dev --browser", 'cyan', true), " Start development server and open in browser\n ").concat(formatText("deploy", 'cyan', true), " Deploy activity to Adobe Target\n ").concat(formatText("deploy --dry-run", 'cyan', true), " Deploy in dry-run mode without actual deployment\n ").concat(formatText("deploy --force", 'cyan', true), " Override the 60s post-deploy cooldown lock\n ").concat(formatText("sync", 'cyan', true), " Sync build.config.json with the AT activity (pages, experiences, names)\n ").concat(formatText("sync --scaffold", 'cyan', true), " Sync and auto-create any missing variation folders with boilerplate\n ").concat(formatText("doctor", 'cyan', true), " Diagnose and fix project configuration issues\n ").concat(formatText("doctor --fix", 'cyan', true), " Automatically fix detected configuration issues\n ").concat(formatText("install-extension", 'cyan', true), " Install the at-builder extension from the Marketplace (default: VSCode)\n ").concat(formatText("install-extension --editor agy", 'cyan', true), " Install into Antigravity IDE (also: cursor, codium, etc.)\n \n").concat(formatText("GLOBAL OPTIONS", 'yellow', true), "\n ").concat(formatText("-v, --verbose", 'green'), " Enable detailed logging\n ").concat(formatText("-V, --version", 'green'), " Display version information\n ").concat(formatText("-h, --help", 'green'), " Show help information\n\n").concat(formatText("EXAMPLES", 'yellow', true), "\n ").concat(formatText("# Initialize new project", 'gray'), "\n ").concat(formatText("atb init", 'white'), "\n \n ").concat(formatText("# Create new activity", 'gray'), "\n ").concat(formatText("atb new", 'white'), "\n \n ").concat(formatText("# Development build with hot reload", 'gray'), "\n ").concat(formatText("atb build", 'white'), "\n \n ").concat(formatText("# Production build for Adobe Target deployment", 'gray'), "\n ").concat(formatText("atb build --prod", 'white'), "\n \n ").concat(formatText("# Development server with browser", 'gray'), "\n ").concat(formatText("atb dev --browser", 'white'), "\n \n ").concat(formatText("# Deploy to Adobe Target", 'gray'), "\n ").concat(formatText("atb deploy", 'white'), "\n \n ").concat(formatText("# Deploy in dry-run mode", 'gray'), "\n ").concat(formatText("atb deploy --dry-run", 'white'), "\n\n ").concat(formatText("# Sync build.config.json from Adobe Target", 'gray'), "\n ").concat(formatText("atb sync", 'white'), "\n\n ").concat(formatText("# Sync and scaffold missing variation folders", 'gray'), "\n ").concat(formatText("atb sync --scaffold", 'white'), "\n\n ").concat(formatText("# Check project configuration", 'gray'), "\n ").concat(formatText("atb doctor", 'white'), "\n \n ").concat(formatText("# Auto-fix configuration issues", 'gray'), "\n ").concat(formatText("atb doctor --fix", 'white'), "\n\n").concat(formatText("WORKFLOW", 'yellow', true), "\n ").concat(formatText("1.", 'cyan'), " Run ").concat(formatText("atb init", 'white'), " to set up project configuration\n ").concat(formatText("2.", 'cyan'), " Run ").concat(formatText("atb new", 'white'), " to create activity templates \n ").concat(formatText("3.", 'cyan'), " Develop variations in ").concat(formatText("/Activities/{name}/Variation-*/", 'gray'), "\n ").concat(formatText("4.", 'cyan'), " Run ").concat(formatText("atb build", 'white'), " for development testing\n ").concat(formatText("5.", 'cyan'), " Run ").concat(formatText("atb build --prod", 'white'), " for Adobe Target deployment\n ").concat(formatText("6.", 'cyan'), " Run ").concat(formatText("atb deploy", 'white'), " to deploy to Adobe Target\n\n").concat(formatText("SUPPORT", 'yellow', true), "\n Repository: ").concat(formatText("https://github.com/upesenga/at-builder", 'blue'), "\n Issues: ").concat(formatText("https://github.com/upesenga/at-builder/issues", 'blue'), "\n License: ").concat(formatText("MIT", 'green'), "\n")];
112
112
  }
113
113
  });
114
114
  }); };
@@ -192,27 +192,28 @@ var createAdobeConfig = function (basePath) {
192
192
  }
193
193
  };
194
194
  /**
195
- * Reads and returns environment variables from the specified .env file
196
- * @param {string} basePath - The base path where the .env file is located
197
- * @returns {Promise<Object>} Object containing environment variables
195
+ * Reads and returns environment variables from the specified .env file.
196
+ *
197
+ * Throws if the file is missing or unreadable. Callers decide whether
198
+ * to surface the failure β€” printing here would spam every `atb` run from
199
+ * a directory that doesn't have a `.env` (e.g. `atb --version` from /tmp).
200
+ *
201
+ * @param basePath - The base path where the .env file is located
202
+ * @returns Object containing environment variables
198
203
  */
199
204
  var getENV = function (basePath) { return __awaiter(void 0, void 0, void 0, function () {
200
- var envPath, envContent, envVars_1, error_2;
205
+ var envPath, envContent, envVars;
201
206
  return __generator(this, function (_a) {
202
207
  switch (_a.label) {
203
208
  case 0:
204
209
  envPath = path_1.default.join(basePath, '.env');
205
- _a.label = 1;
206
- case 1:
207
- _a.trys.push([1, 3, , 4]);
208
- // Check if .env file exists
209
210
  if (!fs_1.default.existsSync(envPath)) {
210
211
  throw new Error('.env file not found');
211
212
  }
212
213
  return [4 /*yield*/, fs_1.default.promises.readFile(envPath, { encoding: 'utf8' })];
213
- case 2:
214
+ case 1:
214
215
  envContent = _a.sent();
215
- envVars_1 = {};
216
+ envVars = {};
216
217
  envContent.split('\n').forEach(function (line) {
217
218
  line = line.trim();
218
219
  // Skip empty lines and comments
@@ -221,16 +222,11 @@ var getENV = function (basePath) { return __awaiter(void 0, void 0, void 0, func
221
222
  if (key) {
222
223
  var value = valueParts.join('=').trim();
223
224
  // Remove quotes if present
224
- envVars_1[key.trim()] = value.replace(/^["'](.*)["']$/, '$1');
225
+ envVars[key.trim()] = value.replace(/^["'](.*)["']$/, '$1');
225
226
  }
226
227
  }
227
228
  });
228
- return [2 /*return*/, envVars_1];
229
- case 3:
230
- error_2 = _a.sent();
231
- console.error(cli_color_1.default.red("Error reading .env file: ".concat(error_2.message)));
232
- throw error_2;
233
- case 4: return [2 /*return*/];
229
+ return [2 /*return*/, envVars];
234
230
  }
235
231
  });
236
232
  }); };
package/bin/index.js CHANGED
@@ -230,8 +230,8 @@ var setupCommander = function () { return __awaiter(void 0, void 0, void 0, func
230
230
  }); });
231
231
  program
232
232
  .command('install-extension')
233
- .description('Install the bundled at-builder VSCode extension (.vsix)')
234
- .option('--editor <bin>', 'Editor CLI to use (e.g. code, cursor, codium)', 'code')
233
+ .description('Install the at-builder VSCode extension from the Marketplace')
234
+ .option('--editor <bin>', 'Editor CLI to use (e.g. code, agy, cursor, codium)', 'code')
235
235
  .action(function (options, command) { return __awaiter(void 0, void 0, void 0, function () {
236
236
  var globalOpts;
237
237
  return __generator(this, function (_a) {
@@ -382,50 +382,41 @@ var handleSync = function (scaffold, verbose) { return __awaiter(void 0, void 0,
382
382
  /**
383
383
  * Handles the install-extension command.
384
384
  *
385
- * Locates the bundled at-builder-*.vsix in at-builder's install directory
386
- * (one level up from this compiled file) and installs it via the editor's
387
- * CLI. Defaults to `code`; users on Cursor/VSCodium can pass --editor.
388
- *
389
- * The .vsix lives inside the at-builder package itself, NOT the consumer's
390
- * project β€” so it resolves via __dirname, not PWD.
385
+ * Installs the at-builder VSCode extension from the VS Code Marketplace
386
+ * using the editor's CLI. Defaults to `code`; users on Cursor/VSCodium
387
+ * can pass --editor.
388
+ */
389
+ /**
390
+ * Per-editor install hints for when the CLI binary isn't on PATH. Each
391
+ * recognized editor gets a one-line, copy-pasteable suggestion. Anything
392
+ * else falls back to a generic hint.
391
393
  */
394
+ var EDITOR_INSTALL_HINTS = {
395
+ code: 'Open VSCode and run Command Palette β†’ "Shell Command: Install \'code\' command in PATH".',
396
+ agy: 'Open Antigravity IDE and run Command Palette β†’ "Shell Command: Install \'agy\' command in PATH".',
397
+ cursor: 'Open Cursor and run Command Palette β†’ "Shell Command: Install \'cursor\' command in PATH".',
398
+ codium: 'Open VSCodium and run Command Palette β†’ "Shell Command: Install \'codium\' command in PATH".',
399
+ };
400
+ var reportEditorNotFound = function (editor) {
401
+ console.error("\u274C \"".concat(editor, "\" CLI not found in PATH."));
402
+ var hint = EDITOR_INSTALL_HINTS[editor]
403
+ || "Make sure the \"".concat(editor, "\" CLI is installed and on your PATH, or pass a different --editor.");
404
+ console.error("\uD83D\uDCA1 ".concat(hint));
405
+ };
392
406
  var handleInstallExtension = function (editor, verbose) { return __awaiter(void 0, void 0, void 0, function () {
393
- var installRoot, candidates, vsixPath, result;
407
+ var extensionId, result;
394
408
  return __generator(this, function (_a) {
409
+ extensionId = "UpendraSengar.at-builder";
395
410
  if (verbose)
396
- logger_1.default.info("verbose", "Installing VSCode extension via ".concat(editor));
397
- installRoot = path_1.default.join(__dirname, "..");
398
- try {
399
- candidates = fs_1.default.readdirSync(installRoot)
400
- .filter(function (f) { return /^at-builder-.+\.vsix$/.test(f); })
401
- .sort()
402
- .reverse(); // latest version first by lexicographic sort
403
- }
404
- catch (error) {
405
- console.error("\u274C Failed to scan at-builder directory: ".concat(error.message));
406
- process.exit(1);
407
- }
408
- if (candidates.length === 0) {
409
- console.error("❌ No at-builder VSCode extension (.vsix) found bundled with this install.");
410
- console.error("\uD83D\uDCA1 Expected at: ".concat(installRoot, "/at-builder-*.vsix"));
411
- process.exit(1);
412
- }
413
- vsixPath = path_1.default.join(installRoot, candidates[0]);
414
- console.log("\uD83D\uDCE6 Installing ".concat(candidates[0], " via \"").concat(editor, "\"..."));
415
- result = (0, child_process_1.spawn)(editor, ["--install-extension", vsixPath], {
411
+ logger_1.default.info("verbose", "Installing ".concat(extensionId, " via ").concat(editor));
412
+ console.log("\uD83D\uDCE6 Installing ".concat(extensionId, " from the Marketplace via \"").concat(editor, "\"..."));
413
+ result = (0, child_process_1.spawn)(editor, ["--install-extension", extensionId], {
416
414
  stdio: "inherit",
417
415
  shell: true
418
416
  });
419
417
  result.on("error", function (err) {
420
- // ENOENT here means the editor binary isn't on PATH.
421
418
  if (err.code === "ENOENT") {
422
- console.error("\u274C \"".concat(editor, "\" CLI not found in PATH."));
423
- if (editor === "code") {
424
- console.error("πŸ’‘ Open VSCode and run Command Palette β†’ \"Shell Command: Install 'code' command in PATH\".");
425
- }
426
- else {
427
- console.error("\uD83D\uDCA1 Make sure the \"".concat(editor, "\" CLI is installed and on your PATH, or pass a different --editor."));
428
- }
419
+ reportEditorNotFound(editor);
429
420
  }
430
421
  else {
431
422
  console.error("\u274C Failed to launch \"".concat(editor, "\": ").concat(err.message));
@@ -440,13 +431,7 @@ var handleInstallExtension = function (editor, verbose) { return __awaiter(void
440
431
  // 127 = shell's "command not found". With shell:true the spawn 'error'
441
432
  // event never fires for missing CLIs, so we surface the same hint here.
442
433
  if (code === 127) {
443
- console.error("\u274C \"".concat(editor, "\" CLI not found in PATH."));
444
- if (editor === "code") {
445
- console.error("πŸ’‘ Open VSCode and run Command Palette β†’ \"Shell Command: Install 'code' command in PATH\".");
446
- }
447
- else {
448
- console.error("\uD83D\uDCA1 Make sure the \"".concat(editor, "\" CLI is installed and on your PATH, or pass a different --editor."));
449
- }
434
+ reportEditorNotFound(editor);
450
435
  process.exit(1);
451
436
  }
452
437
  console.error("\u274C \"".concat(editor, " --install-extension\" exited with code ").concat(code, "."));
package/lib/at-deploy.js CHANGED
@@ -47,7 +47,6 @@ dotenv.config({ path: path.join(PWD, '.env'), quiet: true });
47
47
 
48
48
  const { execFileSync } = require('child_process');
49
49
  const axios = require('axios');
50
- const qs = require('querystring');
51
50
  const fs = require('fs');
52
51
 
53
52
  const { BASE_URL, IMS_TOKEN_URL, IMS_SCOPE } = require(path.join(PWD, 'adobe.config'));
@@ -207,12 +206,12 @@ function getBuildAssets(isMultiPage, allowedVariations) {
207
206
  }
208
207
 
209
208
  async function fetchAdobeToken() {
210
- const data = qs.stringify({
209
+ const data = new URLSearchParams({
211
210
  grant_type: 'client_credentials',
212
211
  client_id: process.env.ADOBE_CLIENT_ID,
213
212
  client_secret: process.env.ADOBE_CLIENT_SECRET,
214
213
  scope: IMS_SCOPE
215
- });
214
+ }).toString();
216
215
  try {
217
216
  const res = await axios.post(IMS_TOKEN_URL, data, {
218
217
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
package/lib/at-sync.js CHANGED
@@ -36,7 +36,6 @@
36
36
  const path = require('path');
37
37
  const fs = require('fs');
38
38
  const axios = require('axios');
39
- const qs = require('querystring');
40
39
  const dotenv = require('dotenv');
41
40
 
42
41
  const PWD = process.env.executionPath || process.cwd();
@@ -81,12 +80,12 @@ const CONFIG_PATHS = [
81
80
 
82
81
  // ─── Auth ───
83
82
  async function fetchToken() {
84
- const data = qs.stringify({
83
+ const data = new URLSearchParams({
85
84
  grant_type: 'client_credentials',
86
85
  client_id: process.env.ADOBE_CLIENT_ID,
87
86
  client_secret: process.env.ADOBE_CLIENT_SECRET,
88
87
  scope: IMS_SCOPE
89
- });
88
+ }).toString();
90
89
  const res = await axios.post(IMS_TOKEN_URL, data, {
91
90
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
92
91
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "at-builder",
3
- "version": "1.3.3",
3
+ "version": "1.4.1",
4
4
  "main": "bin/index.js",
5
5
  "bin": {
6
6
  "atb": "bin/index.js"
@@ -22,18 +22,13 @@
22
22
  "dependencies": {
23
23
  "@babel/core": "^7.26.9",
24
24
  "@babel/eslint-parser": "^7.26.8",
25
- "@babel/plugin-proposal-class-properties": "^7.18.6",
26
- "@babel/plugin-syntax-dynamic-import": "^7.8.3",
27
25
  "@babel/plugin-transform-runtime": "^7.18.9",
28
26
  "@babel/preset-env": "^7.18.9",
29
- "@babel/preset-react": "^7.18.6",
30
27
  "@eslint/js": "^9.20.0",
31
28
  "@types/node": "^22.13.2",
32
29
  "async": "^3.2.3",
33
30
  "axios": "^1.12.2",
34
31
  "babel-loader": "^9.2.1",
35
- "babel-plugin-transform-async-to-generator": "^6.24.1",
36
- "build": "^0.1.4",
37
32
  "chokidar": "^4.0.3",
38
33
  "cli-color": "^2.0.3",
39
34
  "commander": "^13.1.0",
@@ -50,7 +45,6 @@
50
45
  "postcss-loader": "^8.1.1",
51
46
  "postcss-preset-env": "^10.1.4",
52
47
  "puppeteer": "^24.2.0",
53
- "querystring": "^0.2.1",
54
48
  "readline": "^1.3.0",
55
49
  "sass": "^1.53.0",
56
50
  "sass-loader": "^16.0.4",
@@ -76,7 +76,8 @@ ${formatText("COMMANDS", 'yellow', true)}
76
76
  ${formatText("sync --scaffold", 'cyan', true)} Sync and auto-create any missing variation folders with boilerplate
77
77
  ${formatText("doctor", 'cyan', true)} Diagnose and fix project configuration issues
78
78
  ${formatText("doctor --fix", 'cyan', true)} Automatically fix detected configuration issues
79
- ${formatText("install-extension", 'cyan', true)} Install the bundled at-builder VSCode extension (.vsix)
79
+ ${formatText("install-extension", 'cyan', true)} Install the at-builder extension from the Marketplace (default: VSCode)
80
+ ${formatText("install-extension --editor agy", 'cyan', true)} Install into Antigravity IDE (also: cursor, codium, etc.)
80
81
 
81
82
  ${formatText("GLOBAL OPTIONS", 'yellow', true)}
82
83
  ${formatText("-v, --verbose", 'green')} Enable detailed logging
@@ -278,39 +279,36 @@ module.exports = {
278
279
  }
279
280
 
280
281
  /**
281
- * Reads and returns environment variables from the specified .env file
282
- * @param {string} basePath - The base path where the .env file is located
283
- * @returns {Promise<Object>} Object containing environment variables
282
+ * Reads and returns environment variables from the specified .env file.
283
+ *
284
+ * Throws if the file is missing or unreadable. Callers decide whether
285
+ * to surface the failure β€” printing here would spam every `atb` run from
286
+ * a directory that doesn't have a `.env` (e.g. `atb --version` from /tmp).
287
+ *
288
+ * @param basePath - The base path where the .env file is located
289
+ * @returns Object containing environment variables
284
290
  */
285
291
  export const getENV = async (basePath: string) => {
286
292
  const envPath = path.join(basePath, '.env');
287
- try {
288
- // Check if .env file exists
289
- if (!fs.existsSync(envPath)) {
290
- throw new Error('.env file not found');
291
- }
293
+ if (!fs.existsSync(envPath)) {
294
+ throw new Error('.env file not found');
295
+ }
292
296
 
293
- // Read the .env file
294
- const envContent = await fs.promises.readFile(envPath, { encoding: 'utf8' });
295
-
296
- // Parse the .env file content
297
- const envVars: { [key: string]: string } = {};
298
- envContent.split('\n').forEach(line => {
299
- line = line.trim();
300
- // Skip empty lines and comments
301
- if (line && !line.startsWith('#')) {
302
- const [key, ...valueParts] = line.split('=');
303
- if (key) {
304
- const value = valueParts.join('=').trim();
305
- // Remove quotes if present
306
- envVars[key.trim()] = value.replace(/^["'](.*)["']$/, '$1');
307
- }
297
+ const envContent = await fs.promises.readFile(envPath, { encoding: 'utf8' });
298
+
299
+ const envVars: { [key: string]: string } = {};
300
+ envContent.split('\n').forEach(line => {
301
+ line = line.trim();
302
+ // Skip empty lines and comments
303
+ if (line && !line.startsWith('#')) {
304
+ const [key, ...valueParts] = line.split('=');
305
+ if (key) {
306
+ const value = valueParts.join('=').trim();
307
+ // Remove quotes if present
308
+ envVars[key.trim()] = value.replace(/^["'](.*)["']$/, '$1');
308
309
  }
309
- });
310
+ }
311
+ });
310
312
 
311
- return envVars;
312
- } catch (error) {
313
- console.error(clc.red(`Error reading .env file: ${error.message}`));
314
- throw error;
315
- }
313
+ return envVars;
316
314
  };
package/src/index.ts CHANGED
@@ -113,8 +113,8 @@ const setupCommander = async () => {
113
113
 
114
114
  program
115
115
  .command('install-extension')
116
- .description('Install the bundled at-builder VSCode extension (.vsix)')
117
- .option('--editor <bin>', 'Editor CLI to use (e.g. code, cursor, codium)', 'code')
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
118
  .action(async (options, command) => {
119
119
  const globalOpts = command.parent.opts();
120
120
  await handleInstallExtension(options.editor, globalOpts.verbose);
@@ -246,52 +246,44 @@ const handleSync = async (scaffold: boolean, verbose: boolean): Promise<void> =>
246
246
  /**
247
247
  * Handles the install-extension command.
248
248
  *
249
- * Locates the bundled at-builder-*.vsix in at-builder's install directory
250
- * (one level up from this compiled file) and installs it via the editor's
251
- * CLI. Defaults to `code`; users on Cursor/VSCodium can pass --editor.
252
- *
253
- * The .vsix lives inside the at-builder package itself, NOT the consumer's
254
- * project β€” so it resolves via __dirname, not PWD.
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.
255
252
  */
256
- const handleInstallExtension = async (editor: string, verbose: boolean): Promise<void> => {
257
- if (verbose) logger.info("verbose", `Installing VSCode extension via ${editor}`);
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
+ };
258
264
 
259
- const installRoot = path.join(__dirname, "..");
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
+ };
260
271
 
261
- let candidates: string[];
262
- try {
263
- candidates = fs.readdirSync(installRoot)
264
- .filter(f => /^at-builder-.+\.vsix$/.test(f))
265
- .sort()
266
- .reverse(); // latest version first by lexicographic sort
267
- } catch (error) {
268
- console.error(`❌ Failed to scan at-builder directory: ${error.message}`);
269
- process.exit(1);
270
- }
272
+ const handleInstallExtension = async (editor: string, verbose: boolean): Promise<void> => {
273
+ const extensionId = "UpendraSengar.at-builder";
271
274
 
272
- if (candidates.length === 0) {
273
- console.error("❌ No at-builder VSCode extension (.vsix) found bundled with this install.");
274
- console.error(`πŸ’‘ Expected at: ${installRoot}/at-builder-*.vsix`);
275
- process.exit(1);
276
- }
275
+ if (verbose) logger.info("verbose", `Installing ${extensionId} via ${editor}`);
277
276
 
278
- const vsixPath = path.join(installRoot, candidates[0]);
279
- console.log(`πŸ“¦ Installing ${candidates[0]} via "${editor}"...`);
277
+ console.log(`πŸ“¦ Installing ${extensionId} from the Marketplace via "${editor}"...`);
280
278
 
281
- const result = spawn(editor, ["--install-extension", vsixPath], {
279
+ const result = spawn(editor, ["--install-extension", extensionId], {
282
280
  stdio: "inherit",
283
281
  shell: true
284
282
  });
285
283
 
286
284
  result.on("error", (err) => {
287
- // ENOENT here means the editor binary isn't on PATH.
288
285
  if ((err as NodeJS.ErrnoException).code === "ENOENT") {
289
- console.error(`❌ "${editor}" CLI not found in PATH.`);
290
- if (editor === "code") {
291
- console.error("πŸ’‘ Open VSCode and run Command Palette β†’ \"Shell Command: Install 'code' command in PATH\".");
292
- } else {
293
- console.error(`πŸ’‘ Make sure the "${editor}" CLI is installed and on your PATH, or pass a different --editor.`);
294
- }
286
+ reportEditorNotFound(editor);
295
287
  } else {
296
288
  console.error(`❌ Failed to launch "${editor}": ${err.message}`);
297
289
  }
@@ -306,12 +298,7 @@ const handleInstallExtension = async (editor: string, verbose: boolean): Promise
306
298
  // 127 = shell's "command not found". With shell:true the spawn 'error'
307
299
  // event never fires for missing CLIs, so we surface the same hint here.
308
300
  if (code === 127) {
309
- console.error(`❌ "${editor}" CLI not found in PATH.`);
310
- if (editor === "code") {
311
- console.error("πŸ’‘ Open VSCode and run Command Palette β†’ \"Shell Command: Install 'code' command in PATH\".");
312
- } else {
313
- console.error(`πŸ’‘ Make sure the "${editor}" CLI is installed and on your PATH, or pass a different --editor.`);
314
- }
301
+ reportEditorNotFound(editor);
315
302
  process.exit(1);
316
303
  }
317
304
  console.error(`❌ "${editor} --install-extension" exited with code ${code}.`);