@tywalk/pcf-helper-run 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,7 @@ This package provides a single, consolidated command-line interface that brings
13
13
  - [Quick Start](#-quick-start)
14
14
  - [Command Structure](#️-command-structure)
15
15
  - [Available Subcommands](#️-available-subcommands)
16
+ - [Profiles](#-profiles)
16
17
  - [Usage Examples](#-detailed-command-reference)
17
18
  - [Workflow Examples](#-workflow-examples)
18
19
  - [Global Options](#️-global-options)
@@ -83,6 +84,104 @@ Each subcommand corresponds to a specific PCF operation, with consistent option
83
84
  | `deploy` | Deploy to environment (upgrade + build + import) | `pcf-helper-deploy` |
84
85
  | `upgrade` | Upgrade project dependencies | `pcf-helper-upgrade` |
85
86
  | `session` | Manage development sessions | `pcf-helper-session` |
87
+ | `profile` | Inspect named profiles (`list`, `show`, `current`, `paths`) | `pcf-helper-profile` |
88
+
89
+ ## 🧭 Profiles
90
+
91
+ Every command accepts `-P, --profile <name>` so you don't have to retype `--environment`, `--path`, `--publisher-name`, or `--publisher-prefix` on every run. Profiles are defined in a JSON config file that's merged from two places (project overrides global):
92
+
93
+ 1. `~/.pcf-helper/config.json` — global defaults for this machine.
94
+ 2. `./pcf-helper.config.json` — project-specific overrides.
95
+
96
+ Example config:
97
+
98
+ ```json
99
+ {
100
+ "defaultProfile": "dev",
101
+ "profiles": {
102
+ "dev": { "environment": "DevEnv", "publisherName": "Tyler W", "publisherPrefix": "tyw" },
103
+ "test": { "environment": "TestEnv" },
104
+ "prod": { "environment": "ProdEnv" }
105
+ },
106
+ "session": {
107
+ "remoteEnvironmentUrl": "https://org.crm.dynamics.com",
108
+ "localBundlePath": "out/controls/MyControl/bundle.js",
109
+ "startWatch": true
110
+ }
111
+ }
112
+ ```
113
+
114
+ ### Precedence (highest wins)
115
+
116
+ For `build`, `deploy`, `import`, `upgrade`, `init`:
117
+ 1. Explicit CLI flags
118
+ 2. Active profile (`--profile <name>` or `defaultProfile`)
119
+ 3. Defaults
120
+
121
+ For `session`:
122
+ 1. Explicit CLI flags
123
+ 2. Environment variables
124
+ 3. Active profile's `session` block
125
+ 4. Top-level `session` block in `pcf-helper.config.json`
126
+ 5. Legacy `session.config.json` (kept for backward compatibility)
127
+ 6. Defaults
128
+
129
+ ### Usage
130
+
131
+ ```bash
132
+ # Use the default profile
133
+ pcf-helper-run deploy -p ./MySolution
134
+
135
+ # Pick a specific profile
136
+ pcf-helper-run deploy -p ./MySolution --profile prod
137
+
138
+ # CLI flags always win
139
+ pcf-helper-run deploy -p ./MySolution --profile prod --environment HotfixEnv
140
+
141
+ # Inspect what is configured
142
+ pcf-helper-run profile list
143
+ pcf-helper-run profile show prod
144
+ pcf-helper-run profile current
145
+ pcf-helper-run profile paths
146
+
147
+ # Create a profile without editing JSON (see below for the full flag list)
148
+ pcf-helper-run profile init dev \
149
+ --environment MyDevOrg \
150
+ --publisher-name "Tyler W" \
151
+ --publisher-prefix tyw \
152
+ --path ./MySolution \
153
+ --set-default \
154
+ --no-interactive
155
+ ```
156
+
157
+ ### Creating a profile from the CLI
158
+
159
+ `profile init <name>` creates or updates a profile without hand-editing
160
+ `pcf-helper.config.json`. Project-level by default; pass `--global` to write to
161
+ `~/.pcf-helper/config.json` (parent directory is created on first use).
162
+
163
+ Interactive by default — each missing field prompts at the terminal, pre-filled
164
+ with whatever you passed as a flag. Pass `--no-interactive` to skip the prompts
165
+ entirely and write only what was supplied.
166
+
167
+ | Flag | Description |
168
+ |------|-------------|
169
+ | `-e, --environment <env>` | Dataverse environment name |
170
+ | `--publisher-name <name>` | Publisher display name |
171
+ | `--publisher-prefix <prefix>` | Publisher prefix (2-8 chars) |
172
+ | `-p, --path <path>` | Path to PCF solution folder |
173
+ | `--template <template>` | `field` or `dataset` |
174
+ | `--framework <framework>` | `none` or `react` |
175
+ | `--session-url <url>` | Session: remote environment URL |
176
+ | `--session-script <path>` | Session: remote script to intercept |
177
+ | `--session-bundle <path>` | Session: local bundle path |
178
+ | `-g, --global` | Write to `~/.pcf-helper/config.json` |
179
+ | `-d, --set-default` | Also set `defaultProfile: <name>` |
180
+ | `-f, --force` | Overwrite an existing profile of the same name |
181
+ | `--no-interactive` | Skip prompts; only use passed flags |
182
+
183
+ The write is atomic (temp file + rename), so an interrupted run never corrupts
184
+ your config.
86
185
 
87
186
  ## 📖 Detailed Command Reference
88
187
 
package/dist/index.js CHANGED
@@ -45,6 +45,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
45
45
  Object.defineProperty(exports, "__esModule", { value: true });
46
46
  const commander_1 = require("commander");
47
47
  const tasks = __importStar(require("@tywalk/pcf-helper"));
48
+ const pcf_helper_1 = require("@tywalk/pcf-helper");
48
49
  const color_logger_1 = require("@tywalk/color-logger");
49
50
  const package_json_1 = require("./package.json");
50
51
  const performanceUtil_1 = require("./util/performanceUtil");
@@ -61,7 +62,7 @@ const preprocessArgs = (args) => {
61
62
  }
62
63
  return { args: processed, hadDeprecatedEnv };
63
64
  };
64
- // Preprocess arguments and track if deprecated flags were used
65
+ // Preprocess arguments and track if deprecated flags were used
65
66
  const { args: processedArgs, hadDeprecatedEnv } = preprocessArgs(process.argv.slice(2));
66
67
  process.argv = [...process.argv.slice(0, 2), ...processedArgs];
67
68
  const parseWatchRetry = (value) => {
@@ -93,7 +94,8 @@ const withCommonOptions = (command) => {
93
94
  throw new Error('Timeout must be a positive number');
94
95
  }
95
96
  return value;
96
- });
97
+ })
98
+ .option('-P, --profile <name>', 'named profile from pcf-helper.config.json to use for defaults');
97
99
  };
98
100
  const withPathOptions = (command) => {
99
101
  return withCommonOptions(command)
@@ -103,18 +105,16 @@ const withPathOptions = (command) => {
103
105
  };
104
106
  // Helper function to resolve environment value with deprecation warning
105
107
  const resolveEnvironment = (options, logger) => {
106
- // Check if deprecated --env flag was used
107
108
  if (options.env && options.environment) {
108
- logger.warn('⚠️ Both --env (deprecated) and --environment flags provided. Using --environment value.');
109
+ logger.warn('WARN: Both --env (deprecated) and --environment flags provided. Using --environment value.');
109
110
  return options.environment;
110
111
  }
111
112
  else if (options.env) {
112
- // Show deprecation warning using the proper logger
113
113
  if (hadDeprecatedEnv) {
114
- logger.warn('⚠️ The -env flag is DEPRECATED. Please use -e or --environment instead.');
114
+ logger.warn('WARN: The -env flag is DEPRECATED. Please use -e or --environment instead.');
115
115
  }
116
116
  else {
117
- logger.warn('⚠️ The --env flag is DEPRECATED. Please use -e or --environment instead.');
117
+ logger.warn('WARN: The --env flag is DEPRECATED. Please use -e or --environment instead.');
118
118
  }
119
119
  return options.env;
120
120
  }
@@ -122,6 +122,15 @@ const resolveEnvironment = (options, logger) => {
122
122
  return options.environment || '';
123
123
  }
124
124
  };
125
+ // Loads a profile (if any) and logs which one is in use.
126
+ const loadProfile = (profileName, logger) => {
127
+ const { merged } = (0, pcf_helper_1.loadPcfHelperConfig)();
128
+ const { name, profile } = (0, pcf_helper_1.resolveProfile)(profileName, merged);
129
+ if (name) {
130
+ logger.log(`Using profile "${name}" from pcf-helper config.`);
131
+ }
132
+ return profile;
133
+ };
125
134
  // Helper function to setup logger and performance tracking
126
135
  const setupExecutionContext = (options) => {
127
136
  const logger = new color_logger_1.Logger('log');
@@ -151,19 +160,22 @@ const handleResults = (taskName, logger, tick, result) => {
151
160
  process.exit(result);
152
161
  }
153
162
  };
154
- // Define the upgrade command
163
+ // upgrade
155
164
  withPathOptions(commander_1.program.command('upgrade'))
156
165
  .description('upgrade PCF controls')
157
166
  .action((options) => {
167
+ var _a, _b;
158
168
  const { logger, tick } = setupExecutionContext(options);
159
- if (!options.path) {
160
- logger.error('Path argument is required. Use --path to specify the path to solution folder.');
169
+ const profile = loadProfile(options.profile, logger);
170
+ const resolvedPath = (_b = (_a = options.path) !== null && _a !== void 0 ? _a : profile === null || profile === void 0 ? void 0 : profile.path) !== null && _b !== void 0 ? _b : '';
171
+ if (!resolvedPath) {
172
+ logger.error('Path argument is required. Use --path or set `path` in the active profile.');
161
173
  process.exit(1);
162
174
  }
163
175
  let result = 0;
164
176
  try {
165
177
  logger.log('[PCF Helper Run] ' + (0, performanceUtil_1.formatTime)(new Date()) + ' upgrade started.\n');
166
- result = tasks.runUpgrade(options.path, options.verbose || false);
178
+ result = tasks.runUpgrade(resolvedPath, options.verbose || false);
167
179
  }
168
180
  catch (e) {
169
181
  logger.error('[PCF Helper Run] One or more tasks failed while upgrading: ', e instanceof Error ? e.message : 'unknown error');
@@ -171,19 +183,22 @@ withPathOptions(commander_1.program.command('upgrade'))
171
183
  }
172
184
  handleResults('upgrade', logger, tick, result);
173
185
  });
174
- // Define the build command
186
+ // build
175
187
  withPathOptions(commander_1.program.command('build'))
176
188
  .description('build PCF controls')
177
189
  .action((options) => {
190
+ var _a, _b;
178
191
  const { logger, tick } = setupExecutionContext(options);
179
- if (!options.path) {
180
- logger.error('Path argument is required. Use --path to specify the path to solution folder.');
192
+ const profile = loadProfile(options.profile, logger);
193
+ const resolvedPath = (_b = (_a = options.path) !== null && _a !== void 0 ? _a : profile === null || profile === void 0 ? void 0 : profile.path) !== null && _b !== void 0 ? _b : '';
194
+ if (!resolvedPath) {
195
+ logger.error('Path argument is required. Use --path or set `path` in the active profile.');
181
196
  process.exit(1);
182
197
  }
183
198
  let result = 0;
184
199
  try {
185
200
  logger.log('[PCF Helper Run] ' + (0, performanceUtil_1.formatTime)(new Date()) + ' build started.\n');
186
- result = tasks.runBuild(options.path, options.verbose || false, options.timeout ? Number(options.timeout) : undefined);
201
+ result = tasks.runBuild(resolvedPath, options.verbose || false, options.timeout ? Number(options.timeout) : undefined);
187
202
  }
188
203
  catch (e) {
189
204
  logger.error('[PCF Helper Run] One or more tasks failed while building: ', e instanceof Error ? e.message : 'unknown error');
@@ -191,23 +206,27 @@ withPathOptions(commander_1.program.command('build'))
191
206
  }
192
207
  handleResults('build', logger, tick, result);
193
208
  });
194
- // Define the import command
209
+ // import
195
210
  withPathOptions(commander_1.program.command('import'))
196
211
  .description('import PCF controls')
197
212
  .action((options) => {
213
+ var _a, _b, _c;
198
214
  const { logger, tick } = setupExecutionContext(options);
199
- if (!options.path) {
200
- logger.error('Path argument is required. Use --path to specify the path to solution folder.');
215
+ const profile = loadProfile(options.profile, logger);
216
+ const resolvedPath = (_b = (_a = options.path) !== null && _a !== void 0 ? _a : profile === null || profile === void 0 ? void 0 : profile.path) !== null && _b !== void 0 ? _b : '';
217
+ if (!resolvedPath) {
218
+ logger.error('Path argument is required. Use --path or set `path` in the active profile.');
201
219
  process.exit(1);
202
220
  }
203
- const env = resolveEnvironment(options, logger);
221
+ const explicitEnv = resolveEnvironment(options, logger);
222
+ const env = explicitEnv !== '' ? explicitEnv : (_c = profile === null || profile === void 0 ? void 0 : profile.environment) !== null && _c !== void 0 ? _c : '';
204
223
  if (env === '') {
205
224
  logger.warn('No environment specified. Defaulting to "local".');
206
225
  }
207
226
  let result = 0;
208
227
  try {
209
228
  logger.log('[PCF Helper Run] ' + (0, performanceUtil_1.formatTime)(new Date()) + ' import started.\n');
210
- result = tasks.runImport(options.path, env, options.verbose || false, options.timeout ? Number(options.timeout) : undefined);
229
+ result = tasks.runImport(resolvedPath, env, options.verbose || false, options.timeout ? Number(options.timeout) : undefined);
211
230
  }
212
231
  catch (e) {
213
232
  logger.error('[PCF Helper Run] One or more tasks failed while importing: ', e instanceof Error ? e.message : 'unknown error');
@@ -215,36 +234,37 @@ withPathOptions(commander_1.program.command('import'))
215
234
  }
216
235
  handleResults('import', logger, tick, result);
217
236
  });
218
- // Define the deploy command (runs upgrade, build, and import)
237
+ // deploy
219
238
  withPathOptions(commander_1.program.command('deploy'))
220
239
  .description('deploy PCF controls (runs upgrade, build, and import)')
221
240
  .action((options) => {
241
+ var _a, _b, _c;
222
242
  const { logger, tick } = setupExecutionContext(options);
223
- if (!options.path) {
224
- logger.error('Path argument is required. Use --path to specify the path to solution folder.');
243
+ const profile = loadProfile(options.profile, logger);
244
+ const resolvedPath = (_b = (_a = options.path) !== null && _a !== void 0 ? _a : profile === null || profile === void 0 ? void 0 : profile.path) !== null && _b !== void 0 ? _b : '';
245
+ if (!resolvedPath) {
246
+ logger.error('Path argument is required. Use --path or set `path` in the active profile.');
225
247
  process.exit(1);
226
248
  }
227
- const env = resolveEnvironment(options, logger);
249
+ const explicitEnv = resolveEnvironment(options, logger);
250
+ const env = explicitEnv !== '' ? explicitEnv : (_c = profile === null || profile === void 0 ? void 0 : profile.environment) !== null && _c !== void 0 ? _c : '';
228
251
  if (env === '') {
229
252
  logger.warn('No environment specified. Defaulting to "local".');
230
253
  }
231
254
  let result = 0;
232
255
  try {
233
256
  logger.log('[PCF Helper Run] ' + (0, performanceUtil_1.formatTime)(new Date()) + ' deploy started.\n');
234
- // Run upgrade
235
- const upgradeResult = tasks.runUpgrade(options.path, options.verbose || false);
257
+ const upgradeResult = tasks.runUpgrade(resolvedPath, options.verbose || false);
236
258
  if (upgradeResult === 1) {
237
259
  result = 1;
238
260
  }
239
261
  else {
240
- // Run build
241
- const buildResult = tasks.runBuild(options.path, options.verbose || false, options.timeout ? Number(options.timeout) : undefined);
262
+ const buildResult = tasks.runBuild(resolvedPath, options.verbose || false, options.timeout ? Number(options.timeout) : undefined);
242
263
  if (buildResult === 1) {
243
264
  result = 1;
244
265
  }
245
266
  else {
246
- // Run import
247
- const importResult = tasks.runImport(options.path, env, options.verbose || false, options.timeout ? Number(options.timeout) : undefined);
267
+ const importResult = tasks.runImport(resolvedPath, env, options.verbose || false, options.timeout ? Number(options.timeout) : undefined);
248
268
  if (importResult === 1) {
249
269
  result = 1;
250
270
  }
@@ -257,22 +277,25 @@ withPathOptions(commander_1.program.command('deploy'))
257
277
  }
258
278
  handleResults('deploy', logger, tick, result);
259
279
  });
260
- // Define the init command
280
+ // init
261
281
  withVerboseOption(commander_1.program.command('init'))
262
282
  .description('initialize a new PCF project')
263
- .requiredOption('-p, --path <path>', 'path to PCF folder')
264
283
  .requiredOption('-n, --name <name>', 'name of the control')
265
- .requiredOption('--publisher-name <publisherName>', 'publisher name')
266
- .requiredOption('--publisher-prefix <publisherPrefix>', 'publisher prefix')
267
- .option('-t, --template <template>', 'template for the component (field|dataset)', 'field')
268
- .option('-f, --framework <framework>', 'rendering framework for control (none|react)', 'react')
284
+ .option('-p, --path <path>', 'path to PCF folder')
285
+ .option('--publisher-name <publisherName>', 'publisher name')
286
+ .option('--publisher-prefix <publisherPrefix>', 'publisher prefix')
287
+ .option('-t, --template <template>', 'template for the component (field|dataset)')
288
+ .option('-f, --framework <framework>', 'rendering framework for control (none|react)')
269
289
  .option('--run-npm-install', 'run npm install after initialization', true)
290
+ .option('-P, --profile <name>', 'named profile from pcf-helper.config.json to use for defaults')
270
291
  .action((options) => {
292
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
271
293
  const { logger, tick } = setupExecutionContext(options);
294
+ const profile = loadProfile(options.profile, logger);
272
295
  let result = 0;
273
296
  try {
274
297
  logger.log('[PCF Helper Run] ' + (0, performanceUtil_1.formatTime)(new Date()) + ' init started.\n');
275
- result = tasks.runInit(options.path, options.name, options.publisherName, options.publisherPrefix, options.template || 'field', options.framework || 'react', options.runNpmInstall !== false, options.verbose || false);
298
+ result = tasks.runInit((_b = (_a = options.path) !== null && _a !== void 0 ? _a : profile === null || profile === void 0 ? void 0 : profile.path) !== null && _b !== void 0 ? _b : '', options.name, (_d = (_c = options.publisherName) !== null && _c !== void 0 ? _c : profile === null || profile === void 0 ? void 0 : profile.publisherName) !== null && _d !== void 0 ? _d : '', (_f = (_e = options.publisherPrefix) !== null && _e !== void 0 ? _e : profile === null || profile === void 0 ? void 0 : profile.publisherPrefix) !== null && _f !== void 0 ? _f : '', (_h = (_g = options.template) !== null && _g !== void 0 ? _g : profile === null || profile === void 0 ? void 0 : profile.template) !== null && _h !== void 0 ? _h : 'field', (_k = (_j = options.framework) !== null && _j !== void 0 ? _j : profile === null || profile === void 0 ? void 0 : profile.framework) !== null && _k !== void 0 ? _k : 'react', options.runNpmInstall !== false, options.verbose || false);
276
299
  }
277
300
  catch (e) {
278
301
  logger.error('[PCF Helper Run] One or more tasks failed while initializing: ', e instanceof Error ? e.message : 'unknown error');
@@ -280,7 +303,7 @@ withVerboseOption(commander_1.program.command('init'))
280
303
  }
281
304
  handleResults('init', logger, tick, result);
282
305
  });
283
- // Define the session command
306
+ // session
284
307
  withCommonOptions(commander_1.program.command('session'))
285
308
  .description('run development session')
286
309
  .option('-u, --url <url>', 'remote environment URL')
@@ -292,31 +315,20 @@ withCommonOptions(commander_1.program.command('session'))
292
315
  .option('-w, --watch', 'start pcf-scripts watch process')
293
316
  .option('--watch-retry <enabled>', 'automatically retry watch process on failure (true|false)', parseWatchRetry)
294
317
  .action((options, command) => __awaiter(void 0, void 0, void 0, function* () {
295
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
318
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
296
319
  const { logger, tick } = setupExecutionContext(options);
297
320
  try {
298
321
  logger.log('[PCF Helper Run] ' + (0, performanceUtil_1.formatTime)(new Date()) + ' session started.\n');
299
- if (!options.url || options.config) {
300
- const config = tasks.loadConfig(options.config || 'session.config.json');
301
- const configWithWatchRetry = config;
302
- const startWatch = (_b = (_a = options.watch) !== null && _a !== void 0 ? _a : config.startWatch) !== null && _b !== void 0 ? _b : false;
303
- const watchRetryFlagWasSet = command.getOptionValueSource('watchRetry') === 'cli';
304
- if (watchRetryFlagWasSet && !startWatch) {
305
- logger.error('❌ --watch-retry can only be used when --watch is enabled.');
306
- process.exit(1);
307
- }
308
- const watchRetry = (_d = (_c = options.watchRetry) !== null && _c !== void 0 ? _c : configWithWatchRetry.watchRetry) !== null && _d !== void 0 ? _d : true;
309
- // Use the config values from the config file, falling back to the CLI options if the config values are not set
310
- yield tasks.runSession((_e = config.remoteEnvironmentUrl) !== null && _e !== void 0 ? _e : options.url, (_f = config.remoteScriptToIntercept) !== null && _f !== void 0 ? _f : options.script, (_g = config.remoteStylesheetToIntercept) !== null && _g !== void 0 ? _g : options.stylesheet, (_h = config.localBundlePath) !== null && _h !== void 0 ? _h : options.bundle, (_j = config.localCssPath) !== null && _j !== void 0 ? _j : options.css, startWatch, watchRetry);
311
- }
312
- else {
313
- const watchRetryFlagWasSet = command.getOptionValueSource('watchRetry') === 'cli';
314
- if (watchRetryFlagWasSet && !options.watch) {
315
- logger.error('❌ --watch-retry can only be used when --watch is enabled.');
316
- process.exit(1);
317
- }
318
- yield tasks.runSession(options.url, options.script, options.stylesheet, options.bundle, options.css, options.watch, (_k = options.watchRetry) !== null && _k !== void 0 ? _k : true);
322
+ const config = tasks.loadConfig(options.config, options.profile);
323
+ const configWithWatchRetry = config;
324
+ const startWatch = (_b = (_a = options.watch) !== null && _a !== void 0 ? _a : config.startWatch) !== null && _b !== void 0 ? _b : false;
325
+ const watchRetryFlagWasSet = command.getOptionValueSource('watchRetry') === 'cli';
326
+ if (watchRetryFlagWasSet && !startWatch) {
327
+ logger.error('Error: --watch-retry can only be used when --watch is enabled.');
328
+ process.exit(1);
319
329
  }
330
+ const watchRetry = (_d = (_c = options.watchRetry) !== null && _c !== void 0 ? _c : configWithWatchRetry.watchRetry) !== null && _d !== void 0 ? _d : true;
331
+ yield tasks.runSession((_e = options.url) !== null && _e !== void 0 ? _e : config.remoteEnvironmentUrl, (_f = options.script) !== null && _f !== void 0 ? _f : config.remoteScriptToIntercept, (_g = options.stylesheet) !== null && _g !== void 0 ? _g : config.remoteStylesheetToIntercept, (_h = options.bundle) !== null && _h !== void 0 ? _h : config.localBundlePath, (_j = options.css) !== null && _j !== void 0 ? _j : config.localCssPath, startWatch, watchRetry);
320
332
  const tock = performance.now();
321
333
  logger.log((0, performanceUtil_1.formatMsToSec)('Session started successfully in %is.', tock - tick));
322
334
  }
@@ -324,5 +336,108 @@ withCommonOptions(commander_1.program.command('session'))
324
336
  logger.error('[PCF Helper Run] One or more tasks failed during session or session startup: ', e instanceof Error ? e.message : 'unknown error');
325
337
  }
326
338
  }));
327
- // Parse the command line arguments
328
- commander_1.program.parse();
339
+ // profile subcommand
340
+ const profileCmd = commander_1.program.command('profile').description('inspect pcf-helper profiles from pcf-helper.config.json');
341
+ profileCmd
342
+ .command('list')
343
+ .description('list all available profile names')
344
+ .action(() => {
345
+ var _a;
346
+ const { merged, sources } = (0, pcf_helper_1.loadPcfHelperConfig)();
347
+ const names = Object.keys((_a = merged.profiles) !== null && _a !== void 0 ? _a : {});
348
+ const isDefault = (n) => (merged.defaultProfile === n ? ' (default)' : '');
349
+ if (sources.length === 0) {
350
+ console.log('No pcf-helper config files found.');
351
+ console.log('Looked at:');
352
+ console.log(' - global: ~/.pcf-helper/config.json');
353
+ console.log(' - project: ./pcf-helper.config.json');
354
+ return;
355
+ }
356
+ console.log('Loaded config from:');
357
+ for (const s of sources)
358
+ console.log(` - ${s}`);
359
+ if (names.length === 0) {
360
+ console.log('\nNo profiles defined.');
361
+ return;
362
+ }
363
+ console.log('\nProfiles:');
364
+ for (const n of names)
365
+ console.log(` - ${n}${isDefault(n)}`);
366
+ });
367
+ profileCmd
368
+ .command('show <name>')
369
+ .description('print the resolved contents of a profile')
370
+ .action((name) => {
371
+ var _a, _b;
372
+ const { merged } = (0, pcf_helper_1.loadPcfHelperConfig)();
373
+ const profile = (_a = merged.profiles) === null || _a === void 0 ? void 0 : _a[name];
374
+ if (!profile) {
375
+ const available = Object.keys((_b = merged.profiles) !== null && _b !== void 0 ? _b : {});
376
+ console.error(`Profile "${name}" not found. Available: ${available.join(', ') || '(none)'}`);
377
+ process.exit(1);
378
+ }
379
+ console.log(JSON.stringify(profile, null, 2));
380
+ });
381
+ profileCmd
382
+ .command('current')
383
+ .description('print the profile that would be used by default')
384
+ .action(() => {
385
+ const { merged } = (0, pcf_helper_1.loadPcfHelperConfig)();
386
+ if (!merged.defaultProfile) {
387
+ console.log('No defaultProfile set.');
388
+ return;
389
+ }
390
+ console.log(merged.defaultProfile);
391
+ });
392
+ profileCmd
393
+ .command('paths')
394
+ .description('print the global and project config paths')
395
+ .action(() => {
396
+ const { projectPath, globalPath, sources } = (0, pcf_helper_1.loadPcfHelperConfig)();
397
+ console.log(`global: ${globalPath}`);
398
+ console.log(`project: ${projectPath}`);
399
+ console.log(`loaded: ${sources.length ? sources.join(', ') : '(none)'}`);
400
+ });
401
+ profileCmd
402
+ .command('init <name>')
403
+ .description('create a new profile in pcf-helper.config.json (project or global)')
404
+ .option('-e, --environment <env>', 'Dataverse environment name')
405
+ .option('--publisher-name <name>', 'publisher display name')
406
+ .option('--publisher-prefix <prefix>', 'publisher prefix (2-8 chars)')
407
+ .option('-p, --path <path>', 'path to PCF solution folder')
408
+ .option('--template <template>', 'control template (field|dataset)')
409
+ .option('--framework <framework>', 'rendering framework (none|react)')
410
+ .option('--session-url <url>', 'session: remote environment URL')
411
+ .option('--session-script <path>', 'session: remote script to intercept')
412
+ .option('--session-bundle <path>', 'session: local bundle path')
413
+ .option('-g, --global', 'write to ~/.pcf-helper/config.json instead of project-level')
414
+ .option('-d, --set-default', 'set this profile as the defaultProfile')
415
+ .option('-f, --force', 'overwrite an existing profile of the same name')
416
+ .option('--no-interactive', 'skip prompts for missing fields')
417
+ .action((name, flags) => __awaiter(void 0, void 0, void 0, function* () {
418
+ const options = {
419
+ name,
420
+ environment: flags.environment,
421
+ publisherName: flags.publisherName,
422
+ publisherPrefix: flags.publisherPrefix,
423
+ path: flags.path,
424
+ template: flags.template,
425
+ framework: flags.framework,
426
+ sessionUrl: flags.sessionUrl,
427
+ sessionScript: flags.sessionScript,
428
+ sessionBundle: flags.sessionBundle,
429
+ global: !!flags.global,
430
+ setDefault: !!flags.setDefault,
431
+ force: !!flags.force,
432
+ nonInteractive: flags.interactive === false,
433
+ };
434
+ try {
435
+ yield (0, pcf_helper_1.runProfileInit)(options);
436
+ }
437
+ catch (e) {
438
+ const message = e instanceof Error ? e.message : String(e);
439
+ console.error(`Error: ${message}`);
440
+ process.exit(1);
441
+ }
442
+ }));
443
+ commander_1.program.parseAsync();
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tywalk/pcf-helper-run",
3
- "version": "1.4.1",
3
+ "version": "1.6.0",
4
4
  "description": "Unified CLI interface for Power Platform Component Framework (PCF) development — init, build, import, deploy, and manage PCF controls in Dataverse.",
5
5
  "main": "dist/index.js",
6
6
  "types": "./types/",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@tywalk/color-logger": "^1.0.3",
55
- "@tywalk/pcf-helper": "^1.14.0"
55
+ "@tywalk/pcf-helper": "^1.16.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@semantic-release/git": "^10.0.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tywalk/pcf-helper-run",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "Unified CLI interface for Power Platform Component Framework (PCF) development — init, build, import, deploy, and manage PCF controls in Dataverse.",
5
5
  "main": "dist/index.js",
6
6
  "types": "./types/",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@tywalk/color-logger": "^1.0.3",
55
- "@tywalk/pcf-helper": "^1.14.0"
55
+ "@tywalk/pcf-helper": "^1.16.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@semantic-release/git": "^10.0.1",