@fern-api/fern-api-dev 3.64.4 → 3.64.5-1-g103be4aafa9

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.
Files changed (2) hide show
  1. package/cli.cjs +501 -105
  2. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -1427240,7 +1427240,7 @@ var AccessTokenPosthogManager = class {
1427240
1427240
  properties: {
1427241
1427241
  ...event,
1427242
1427242
  ...event.properties,
1427243
- version: "3.64.4",
1427243
+ version: "3.64.5-1-g103be4aafa9",
1427244
1427244
  usingAccessToken: true
1427245
1427245
  }
1427246
1427246
  });
@@ -1427339,7 +1427339,7 @@ var UserPosthogManager = class {
1427339
1427339
  distinctId: this.userId ?? await this.getPersistedDistinctId(),
1427340
1427340
  event: "CLI",
1427341
1427341
  properties: {
1427342
- version: "3.64.4",
1427342
+ version: "3.64.5-1-g103be4aafa9",
1427343
1427343
  ...event,
1427344
1427344
  ...event.properties,
1427345
1427345
  usingAccessToken: false,
@@ -1432669,7 +1432669,7 @@ var TaskContextLogger = class {
1432669
1432669
  debug(...args) {
1432670
1432670
  const message = args.join(" ");
1432671
1432671
  this.context.logFileWriter.write({ taskName: this.task.name, level: LogLevel2.Debug, message });
1432672
- if (this.enabled && this.context.logLevel === LogLevel2.Debug) {
1432672
+ if (this.shouldLogToTask(LogLevel2.Debug)) {
1432673
1432673
  if (this.task.logs == null) {
1432674
1432674
  this.task.logs = [];
1432675
1432675
  }
@@ -1432679,7 +1432679,7 @@ var TaskContextLogger = class {
1432679
1432679
  info(...args) {
1432680
1432680
  const message = args.join(" ");
1432681
1432681
  this.context.logFileWriter.write({ taskName: this.task.name, level: LogLevel2.Info, message });
1432682
- if (this.enabled && this.context.logLevel === LogLevel2.Debug) {
1432682
+ if (this.shouldLogToTask(LogLevel2.Info)) {
1432683
1432683
  if (this.task.logs == null) {
1432684
1432684
  this.task.logs = [];
1432685
1432685
  }
@@ -1432689,7 +1432689,7 @@ var TaskContextLogger = class {
1432689
1432689
  warn(...args) {
1432690
1432690
  const message = args.join(" ");
1432691
1432691
  this.context.logFileWriter.write({ taskName: this.task.name, level: LogLevel2.Warn, message });
1432692
- if (this.enabled) {
1432692
+ if (this.shouldLogToTask(LogLevel2.Warn)) {
1432693
1432693
  if (this.task.logs == null) {
1432694
1432694
  this.task.logs = [];
1432695
1432695
  }
@@ -1432699,7 +1432699,7 @@ var TaskContextLogger = class {
1432699
1432699
  error(...args) {
1432700
1432700
  const message = args.join(" ");
1432701
1432701
  this.context.logFileWriter.write({ taskName: this.task.name, level: LogLevel2.Error, message });
1432702
- if (this.enabled) {
1432702
+ if (this.shouldLogToTask(LogLevel2.Error)) {
1432703
1432703
  this.collectedErrors.push(message);
1432704
1432704
  if (this.task.logs == null) {
1432705
1432705
  this.task.logs = [];
@@ -1432708,14 +1432708,27 @@ var TaskContextLogger = class {
1432708
1432708
  }
1432709
1432709
  }
1432710
1432710
  log(level, ...args) {
1432711
- if (level === LogLevel2.Debug) {
1432712
- this.debug(...args);
1432713
- } else if (level === LogLevel2.Warn) {
1432714
- this.warn(...args);
1432715
- } else if (level === LogLevel2.Error) {
1432716
- this.error(...args);
1432711
+ switch (level) {
1432712
+ case LogLevel2.Debug:
1432713
+ this.debug(...args);
1432714
+ break;
1432715
+ case LogLevel2.Info:
1432716
+ this.info(...args);
1432717
+ break;
1432718
+ case LogLevel2.Warn:
1432719
+ this.warn(...args);
1432720
+ break;
1432721
+ case LogLevel2.Error:
1432722
+ this.error(...args);
1432723
+ break;
1432717
1432724
  }
1432718
1432725
  }
1432726
+ /**
1432727
+ * Check if a message at the given level should be logged to the task's UI.
1432728
+ */
1432729
+ shouldLogToTask(level) {
1432730
+ return this.enabled && LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(this.logLevel);
1432731
+ }
1432719
1432732
  };
1432720
1432733
 
1432721
1432734
  // ../cli-v2/lib/context/adapter/TaskContextAdapter.js
@@ -1432724,7 +1432737,7 @@ var TaskContextAdapter = class {
1432724
1432737
  logger;
1432725
1432738
  constructor({ context: context2, task, logLevel = LogLevel2.Warn }) {
1432726
1432739
  if (task != null) {
1432727
- this.logger = new TaskContextLogger({ context: context2, task });
1432740
+ this.logger = new TaskContextLogger({ context: context2, task, logLevel });
1432728
1432741
  } else {
1432729
1432742
  this.logger = createLogger2((level, ...args) => {
1432730
1432743
  if (LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(logLevel)) {
@@ -1510201,6 +1510214,7 @@ function getGeneratorMetadataFromName(generatorName, context2) {
1510201
1510214
  case "fern-fastapi-server":
1510202
1510215
  return "fastapi";
1510203
1510216
  // TypeScript
1510217
+ case "fern-typescript":
1510204
1510218
  case "fern-typescript-browser-sdk":
1510205
1510219
  case "fern-typescript-node-sdk":
1510206
1510220
  case "fern-typescript-sdk":
@@ -1510211,6 +1510225,7 @@ function getGeneratorMetadataFromName(generatorName, context2) {
1510211
1510225
  case "fern-java-sdk":
1510212
1510226
  return "java-sdk";
1510213
1510227
  case "fern-java-model":
1510228
+ case "java-model":
1510214
1510229
  return "java-model";
1510215
1510230
  case "fern-java-spring":
1510216
1510231
  return "java-spring";
@@ -1563529,7 +1563544,7 @@ var ApiDefinitionValidator = class {
1563529
1563544
  cliVersion;
1563530
1563545
  constructor(config3) {
1563531
1563546
  this.context = config3.context;
1563532
- this.taskContext = new TaskContextAdapter({ context: this.context });
1563547
+ this.taskContext = new TaskContextAdapter({ context: this.context, task: config3.task });
1563533
1563548
  this.cliVersion = config3.cliVersion;
1563534
1563549
  }
1563535
1563550
  /**
@@ -1563641,10 +1563656,12 @@ var ApiChecker = class {
1563641
1563656
  context;
1563642
1563657
  cliVersion;
1563643
1563658
  stream;
1563659
+ task;
1563644
1563660
  constructor(config3) {
1563645
1563661
  this.context = config3.context;
1563646
1563662
  this.cliVersion = config3.cliVersion;
1563647
1563663
  this.stream = config3.stream ?? process.stderr;
1563664
+ this.task = config3.task;
1563648
1563665
  }
1563649
1563666
  /**
1563650
1563667
  * Check APIs in the workspace and display results.
@@ -1563668,7 +1563685,8 @@ var ApiChecker = class {
1563668
1563685
  }
1563669
1563686
  const validator = new ApiDefinitionValidator({
1563670
1563687
  context: this.context,
1563671
- cliVersion: this.cliVersion
1563688
+ cliVersion: this.cliVersion,
1563689
+ task: this.task
1563672
1563690
  });
1563673
1563691
  const allViolations = [];
1563674
1563692
  for (const apiName of apisToCheck) {
@@ -1563710,7 +1563728,7 @@ var ApiChecker = class {
1563710
1563728
  }
1563711
1563729
  writeHeader() {
1563712
1563730
  this.stream.write("\n");
1563713
- this.stream.write(`${Icons.info} ${source_default.bold("Validating API definitions")}
1563731
+ this.stream.write(`${Icons.info} ${source_default.bold(`Validate APIs`)}
1563714
1563732
  `);
1563715
1563733
  this.stream.write("\n");
1563716
1563734
  }
@@ -1563885,6 +1563903,9 @@ var ApiChecker = class {
1563885
1563903
  }
1563886
1563904
  return `${(ms6 / 1e3).toFixed(1)}s`;
1563887
1563905
  }
1563906
+ maybePluralApis(apis) {
1563907
+ return apis.length === 1 ? "API" : "APIs";
1563908
+ }
1563888
1563909
  };
1563889
1563910
 
1563890
1563911
  // ../cli-v2/lib/commands/check/command.js
@@ -1682129,7 +1682150,12 @@ var LegacyRemoteGenerationRunner = class {
1682129
1682150
  this.invocationAdapter = new LegacyGeneratorInvocationAdapter({ context: this.context });
1682130
1682151
  }
1682131
1682152
  async run(args) {
1682132
- const taskContext = new TaskContextAdapter({ task: args.task, context: this.context });
1682153
+ const taskContext = new TaskContextAdapter({
1682154
+ context: this.context,
1682155
+ task: args.task,
1682156
+ logLevel: LogLevel2.Info
1682157
+ // Capture INFO logs to parse git output URLs
1682158
+ });
1682133
1682159
  try {
1682134
1682160
  const generatorInvocation = await this.invocationAdapter.adapt(args.target);
1682135
1682161
  const generatorGroup = {
@@ -1682165,9 +1682191,10 @@ var LegacyRemoteGenerationRunner = class {
1682165
1682191
  success: false
1682166
1682192
  };
1682167
1682193
  }
1682194
+ const gitOutput = this.extractGitOutputFromTaskLogs(args.task);
1682168
1682195
  return {
1682169
1682196
  success: true,
1682170
- output: absolutePathToPreview != null ? [absolutePathToPreview.toString()] : this.context.resolveTargetOutputs(args.target)
1682197
+ output: this.resolveOutput(args, gitOutput)
1682171
1682198
  };
1682172
1682199
  } catch (error49) {
1682173
1682200
  return {
@@ -1682208,6 +1682235,58 @@ var LegacyRemoteGenerationRunner = class {
1682208
1682235
  }
1682209
1682236
  return void 0;
1682210
1682237
  }
1682238
+ /**
1682239
+ * Extract git output URLs from task logs.
1682240
+ *
1682241
+ * The remote generation service logs messages like:
1682242
+ * - "Created pull request: https://github.com/owner/repo/pull/123"
1682243
+ * - "Created commit abc123"
1682244
+ * - "Pushed branch: https://github.com/owner/repo/tree/branch-name"
1682245
+ * - "Release tagged. View here: https://github.com/owner/repo/releases/tag/v1.0.0"
1682246
+ */
1682247
+ extractGitOutputFromTaskLogs(task) {
1682248
+ const gitOutput = {};
1682249
+ for (const log2 of task.logs ?? []) {
1682250
+ const prMatch = log2.message.match(/Created pull request: (.+)/);
1682251
+ if (prMatch != null) {
1682252
+ gitOutput.pullRequestUrl = prMatch[1];
1682253
+ }
1682254
+ const commitMatch = log2.message.match(/Created commit (\w+)/);
1682255
+ if (commitMatch != null) {
1682256
+ gitOutput.commitHash = commitMatch[1];
1682257
+ }
1682258
+ const branchMatch = log2.message.match(/Pushed branch: (.+)/);
1682259
+ if (branchMatch != null) {
1682260
+ gitOutput.branchUrl = branchMatch[1];
1682261
+ }
1682262
+ const releaseMatch = log2.message.match(/Release tagged\. View here: (.+)/);
1682263
+ if (releaseMatch != null) {
1682264
+ gitOutput.releaseUrl = releaseMatch[1];
1682265
+ }
1682266
+ }
1682267
+ return Object.keys(gitOutput).length > 0 ? gitOutput : void 0;
1682268
+ }
1682269
+ /**
1682270
+ * Resolve output URLs/paths for display.
1682271
+ */
1682272
+ resolveOutput(args, gitOutput) {
1682273
+ const absolutePathToPreview = this.getAbsolutePathToPreview(args);
1682274
+ if (absolutePathToPreview != null) {
1682275
+ return [absolutePathToPreview.toString()];
1682276
+ }
1682277
+ if (gitOutput != null) {
1682278
+ if (gitOutput.pullRequestUrl != null) {
1682279
+ return [gitOutput.pullRequestUrl];
1682280
+ }
1682281
+ if (gitOutput.releaseUrl != null) {
1682282
+ return [gitOutput.releaseUrl];
1682283
+ }
1682284
+ if (gitOutput.branchUrl != null) {
1682285
+ return [gitOutput.branchUrl];
1682286
+ }
1682287
+ }
1682288
+ return this.context.resolveTargetOutputs(args.target);
1682289
+ }
1682211
1682290
  };
1682212
1682291
 
1682213
1682292
  // ../cli-v2/lib/sdk/generator/GeneratorPipeline.js
@@ -1682242,6 +1682321,7 @@ var GeneratorPipeline = class {
1682242
1682321
  cliVersion: this.cliVersion
1682243
1682322
  });
1682244
1682323
  const result = await generationRunner.run({
1682324
+ task: args.task,
1682245
1682325
  target: args.target,
1682246
1682326
  apiDefinition: args.apiDefinition,
1682247
1682327
  organization: args.organization,
@@ -1682251,7 +1682331,6 @@ var GeneratorPipeline = class {
1682251
1682331
  keepContainer: args.keepContainer,
1682252
1682332
  preview: args.preview,
1682253
1682333
  outputPath: args.outputPath,
1682254
- task: args.task,
1682255
1682334
  containerEngine: args.containerEngine
1682256
1682335
  });
1682257
1682336
  if (!result.success) {
@@ -1682280,14 +1682359,14 @@ var GeneratorPipeline = class {
1682280
1682359
  apiDefinition: args.apiDefinition,
1682281
1682360
  organization: args.organization,
1682282
1682361
  token: args.token,
1682362
+ task: args.task,
1682283
1682363
  ai: args.ai,
1682284
1682364
  audiences: args.audiences,
1682285
1682365
  version: args.version,
1682286
1682366
  shouldLogS3Url: args.shouldLogS3Url,
1682287
1682367
  preview: args.preview,
1682288
1682368
  outputPath: args.outputPath,
1682289
- fernignorePath: args.fernignorePath,
1682290
- task: args.task
1682369
+ fernignorePath: args.fernignorePath
1682291
1682370
  });
1682292
1682371
  if (!result.success) {
1682293
1682372
  return {
@@ -1682306,6 +1682385,8 @@ var GeneratorPipeline = class {
1682306
1682385
 
1682307
1682386
  // ../cli-v2/lib/ui/TaskGroup.js
1682308
1682387
  var TaskGroup = class _TaskGroup {
1682388
+ static MAX_DISPLAYED_LOGS_TTY = 10;
1682389
+ static URL_PATTERN = /https?:\/\/[^\s]+/;
1682309
1682390
  context;
1682310
1682391
  ttyAwareLogger;
1682311
1682392
  stream;
@@ -1682385,6 +1682466,45 @@ var TaskGroup = class _TaskGroup {
1682385
1682466
  }
1682386
1682467
  return this;
1682387
1682468
  }
1682469
+ /**
1682470
+ * Define all stages upfront so users see the full journey. All stages start as "pending".
1682471
+ */
1682472
+ setStages(taskId, stages) {
1682473
+ const task = this.tasks[taskId];
1682474
+ if (task == null) {
1682475
+ return this;
1682476
+ }
1682477
+ task.stages = stages.map((stage) => ({
1682478
+ id: stage.id,
1682479
+ status: "pending",
1682480
+ labels: stage.labels
1682481
+ }));
1682482
+ return this;
1682483
+ }
1682484
+ /**
1682485
+ * Update a stage's status by ID. The displayed label automatically changes based on the status.
1682486
+ */
1682487
+ updateStage({ taskId, stageId, status, options: options2 }) {
1682488
+ const task = this.tasks[taskId];
1682489
+ if (task == null) {
1682490
+ return this;
1682491
+ }
1682492
+ if (task.stages == null) {
1682493
+ return this;
1682494
+ }
1682495
+ const stage = task.stages.find((s9) => s9.id === stageId);
1682496
+ if (stage == null) {
1682497
+ return this;
1682498
+ }
1682499
+ stage.status = status;
1682500
+ if (options2?.detail !== void 0) {
1682501
+ stage.detail = options2.detail;
1682502
+ }
1682503
+ if (options2?.error !== void 0) {
1682504
+ stage.error = options2.error;
1682505
+ }
1682506
+ return this;
1682507
+ }
1682388
1682508
  /**
1682389
1682509
  * Called by TtyAwareLogger to get the current display.
1682390
1682510
  * This is the integration point with TtyAwareLogger.
@@ -1682447,24 +1682567,43 @@ ${source_default.dim(`Logs written to: ${logFilePath}`)}
1682447
1682567
  }
1682448
1682568
  formatTaskLine(task, spinnerFrame) {
1682449
1682569
  const name3 = source_default.bold(task.name);
1682450
- const logLines = this.formatTaskLogs(task.logs);
1682570
+ const hasStages = task.stages != null && task.stages.length > 0;
1682451
1682571
  switch (task.status) {
1682452
- case "pending":
1682572
+ case "pending": {
1682573
+ if (hasStages) {
1682574
+ const stageLines = this.formatTaskStages(task.stages, spinnerFrame);
1682575
+ return `${source_default.dim("\u25CB")} ${source_default.dim(name3)}${stageLines}`;
1682576
+ }
1682453
1682577
  return void 0;
1682578
+ }
1682454
1682579
  case "running": {
1682580
+ if (hasStages) {
1682581
+ const stageLines = this.formatTaskStages(task.stages, spinnerFrame, task.logs);
1682582
+ return `${spinnerFrame} ${name3}${stageLines}`;
1682583
+ }
1682455
1682584
  const step = task.currentStep != null ? ` ${source_default.dim(task.currentStep)}` : "";
1682456
- return `${spinnerFrame} ${name3}${step}${logLines}`;
1682585
+ return `${spinnerFrame} ${name3}${step}`;
1682457
1682586
  }
1682458
1682587
  case "success": {
1682459
1682588
  const duration3 = this.formatTaskDuration(task);
1682589
+ if (hasStages) {
1682590
+ const stageLines = this.formatTaskStages(task.stages, spinnerFrame);
1682591
+ const outputLines2 = task.output != null && task.output.length > 0 ? task.output.map((output2) => `
1682592
+ ${source_default.dim("\u2192")} ${source_default.cyan(output2)}`).join("") : "";
1682593
+ return `${source_default.green("\u2713")} ${name3}${duration3}${stageLines}${outputLines2}`;
1682594
+ }
1682460
1682595
  const outputLines = task.output != null && task.output.length > 0 ? task.output.map((output2) => `
1682461
1682596
  ${source_default.dim("\u2192")} ${source_default.cyan(output2)}`).join("") : "";
1682462
- return `${source_default.green("\u2713")} ${name3}${duration3}${logLines}${outputLines}`;
1682597
+ return `${source_default.green("\u2713")} ${name3}${duration3}${outputLines}`;
1682463
1682598
  }
1682464
1682599
  case "error": {
1682465
1682600
  const duration3 = this.formatTaskDuration(task);
1682601
+ if (hasStages) {
1682602
+ const stageLines = this.formatTaskStages(task.stages, spinnerFrame, task.logs);
1682603
+ return `${source_default.red("\u2717")} ${name3}${duration3}${stageLines}`;
1682604
+ }
1682466
1682605
  const errorLines = formatMultilineText({ text: task.error, colorFn: source_default.red.bind(source_default) });
1682467
- return `${source_default.red("x")} ${name3}${duration3}${logLines}${errorLines}`;
1682606
+ return `${source_default.red("\u2717")} ${name3}${duration3}${errorLines}`;
1682468
1682607
  }
1682469
1682608
  case "skipped": {
1682470
1682609
  const reason = task.skipReason != null ? `skipped: ${task.skipReason}` : "skipped";
@@ -1682474,12 +1682613,92 @@ ${source_default.dim(`Logs written to: ${logFilePath}`)}
1682474
1682613
  assertNever2(task.status);
1682475
1682614
  }
1682476
1682615
  }
1682477
- static MAX_DISPLAYED_LOGS_TTY = 10;
1682478
- static URL_PATTERN = /https?:\/\//i;
1682479
- formatTaskLogs(logs) {
1682616
+ /**
1682617
+ * Format the stages for a task as indented lines. When a stage fails, logs are shown under it.
1682618
+ */
1682619
+ formatTaskStages(stages, spinnerFrame, logs) {
1682620
+ if (stages == null || stages.length === 0) {
1682621
+ return "";
1682622
+ }
1682623
+ const lines = [];
1682624
+ for (const stage of stages) {
1682625
+ const icon = this.getStageIcon(stage.status, spinnerFrame);
1682626
+ let line = `
1682627
+ ${icon} ${this.getStageLabel(stage)}`;
1682628
+ if (stage.detail != null) {
1682629
+ line += `
1682630
+ ${source_default.dim(stage.detail)}`;
1682631
+ }
1682632
+ if (stage.status === "error") {
1682633
+ const logLines = this.formatTaskLogs(logs, { baseIndent: 8 });
1682634
+ if (logLines.length > 0) {
1682635
+ line += logLines;
1682636
+ }
1682637
+ if (stage.error != null) {
1682638
+ line += `
1682639
+ ${source_default.red(stage.error)}`;
1682640
+ }
1682641
+ }
1682642
+ lines.push(line);
1682643
+ }
1682644
+ return lines.join("");
1682645
+ }
1682646
+ /**
1682647
+ * Get the appropriate icon for a stage status.
1682648
+ *
1682649
+ * Uses a static arrow (▸) for running stages to avoid visual noise
1682650
+ * from having multiple spinners (the parent task already has a spinner).
1682651
+ */
1682652
+ getStageIcon(status, _spinnerFrame) {
1682653
+ switch (status) {
1682654
+ case "pending":
1682655
+ return source_default.dim("\u25CB");
1682656
+ case "running":
1682657
+ return source_default.cyan("\u25B8");
1682658
+ case "success":
1682659
+ return source_default.green("\u2713");
1682660
+ case "error":
1682661
+ return source_default.red("\u2717");
1682662
+ case "skipped":
1682663
+ return source_default.dim("\u25CB");
1682664
+ default:
1682665
+ assertNever2(status);
1682666
+ }
1682667
+ }
1682668
+ /**
1682669
+ * Get the formatted label for a stage based on its status.
1682670
+ * Uses the appropriate label from the stage's labels map.
1682671
+ */
1682672
+ getStageLabel(stage) {
1682673
+ const label = stage.labels[stage.status] ?? stage.labels.pending;
1682674
+ switch (stage.status) {
1682675
+ case "pending":
1682676
+ return source_default.dim(label);
1682677
+ case "running":
1682678
+ return source_default.cyan(label);
1682679
+ case "success":
1682680
+ return label;
1682681
+ case "error":
1682682
+ return source_default.red(label);
1682683
+ case "skipped":
1682684
+ return source_default.dim(label);
1682685
+ default:
1682686
+ assertNever2(stage.status);
1682687
+ }
1682688
+ }
1682689
+ /**
1682690
+ * Format task logs for display.
1682691
+ *
1682692
+ * @param logs - The logs to format
1682693
+ * @param options - Formatting options
1682694
+ * @param options.baseIndent - Number of spaces for base indentation (default: 8 for stage nesting)
1682695
+ */
1682696
+ formatTaskLogs(logs, options2) {
1682480
1682697
  if (logs == null || logs.length === 0) {
1682481
1682698
  return "";
1682482
1682699
  }
1682700
+ const baseIndent = options2?.baseIndent ?? 8;
1682701
+ const indentStr = " ".repeat(baseIndent);
1682483
1682702
  const shouldLimit = this.context.isTTY;
1682484
1682703
  const filteredLogs = shouldLimit ? logs.filter((log2) => log2.level !== "debug" || !_TaskGroup.URL_PATTERN.test(log2.message)) : logs;
1682485
1682704
  const logsToShow = shouldLimit && filteredLogs.length > _TaskGroup.MAX_DISPLAYED_LOGS_TTY ? filteredLogs.slice(-_TaskGroup.MAX_DISPLAYED_LOGS_TTY) : filteredLogs;
@@ -1682491,19 +1682710,23 @@ ${source_default.dim(`Logs written to: ${logFilePath}`)}
1682491
1682710
  const message = shouldLimit ? this.truncateMessage(log2.message, maxMessageLength) : log2.message;
1682492
1682711
  const icon = source_default.dim("\u2022");
1682493
1682712
  return `
1682494
- ${icon} ${source_default.dim(message)}`;
1682713
+ ${indentStr}${icon} ${source_default.dim(message)}`;
1682495
1682714
  }
1682496
1682715
  case "warn":
1682497
1682716
  return formatMultilineText({
1682498
1682717
  text: log2.message,
1682499
1682718
  colorFn: source_default.yellow.bind(source_default),
1682500
- icon: source_default.yellow("\u26A0")
1682719
+ icon: source_default.yellow("\u26A0"),
1682720
+ baseIndent,
1682721
+ continuationIndent: baseIndent + 2
1682501
1682722
  });
1682502
1682723
  case "error":
1682503
1682724
  return formatMultilineText({
1682504
1682725
  text: log2.message,
1682505
1682726
  colorFn: source_default.red.bind(source_default),
1682506
- icon: source_default.red("\u2717")
1682727
+ icon: source_default.red("\u2717"),
1682728
+ baseIndent,
1682729
+ continuationIndent: baseIndent + 2
1682507
1682730
  });
1682508
1682731
  default:
1682509
1682732
  assertNever2(log2.level);
@@ -1682511,20 +1682734,16 @@ ${source_default.dim(`Logs written to: ${logFilePath}`)}
1682511
1682734
  }).join("");
1682512
1682735
  if (hiddenCount > 0) {
1682513
1682736
  return `
1682514
- ${source_default.dim(`... ${hiddenCount} earlier logs hidden ...`)}${formattedLogs}`;
1682737
+ ${indentStr}${source_default.dim(`... ${hiddenCount} earlier logs hidden ...`)}${formattedLogs}`;
1682515
1682738
  }
1682516
1682739
  return formattedLogs;
1682517
1682740
  }
1682518
1682741
  /**
1682519
1682742
  * Maximum characters for a log message line in TTY mode.
1682520
- * This prevents terminal line wrapping which breaks the paint/clear cycle.
1682521
- *
1682522
- * Account for: box prefix "│ " (2) + indent " " (4) + icon + space "• " (2) = 8 chars
1682523
- * Use 72 chars for message to stay under 80 col, or scale with terminal width.
1682524
1682743
  */
1682525
1682744
  getMaxLogMessageLength() {
1682526
1682745
  const terminalWidth = this.stream.columns ?? 80;
1682527
- return Math.max(40, terminalWidth - 12);
1682746
+ return Math.max(40, terminalWidth - 16);
1682528
1682747
  }
1682529
1682748
  truncateMessage(message, maxLength) {
1682530
1682749
  const sanitized = message.replace(/[\r\n]+/g, " ").trim();
@@ -1682563,6 +1682782,171 @@ ${source_default.dim(`Logs written to: ${logFilePath}`)}
1682563
1682782
  }
1682564
1682783
  };
1682565
1682784
 
1682785
+ // ../cli-v2/lib/ui/TaskStageController.js
1682786
+ var TaskStageController = class {
1682787
+ taskGroup;
1682788
+ taskId;
1682789
+ stageId;
1682790
+ constructor({ taskGroup, taskId, stageId }) {
1682791
+ this.taskGroup = taskGroup;
1682792
+ this.taskId = taskId;
1682793
+ this.stageId = stageId;
1682794
+ }
1682795
+ start(detail) {
1682796
+ this.taskGroup.updateStage({
1682797
+ taskId: this.taskId,
1682798
+ stageId: this.stageId,
1682799
+ status: "running",
1682800
+ options: { detail }
1682801
+ });
1682802
+ }
1682803
+ complete(detail) {
1682804
+ this.taskGroup.updateStage({
1682805
+ taskId: this.taskId,
1682806
+ stageId: this.stageId,
1682807
+ status: "success",
1682808
+ options: { detail }
1682809
+ });
1682810
+ }
1682811
+ fail(error49) {
1682812
+ this.taskGroup.updateStage({
1682813
+ taskId: this.taskId,
1682814
+ stageId: this.stageId,
1682815
+ status: "error"
1682816
+ });
1682817
+ const task = this.taskGroup.getTask(this.taskId);
1682818
+ if (task == null) {
1682819
+ return;
1682820
+ }
1682821
+ this.taskGroup.updateTask({
1682822
+ id: this.taskId,
1682823
+ update: { status: "error", error: error49 }
1682824
+ });
1682825
+ }
1682826
+ };
1682827
+
1682828
+ // ../cli-v2/lib/sdk/task/SdkTask.js
1682829
+ var SdkTask = class {
1682830
+ id;
1682831
+ taskGroup;
1682832
+ stage;
1682833
+ constructor({ id: id2, taskGroup }) {
1682834
+ this.id = id2;
1682835
+ this.taskGroup = taskGroup;
1682836
+ this.stage = {
1682837
+ validation: new TaskStageController({ taskId: id2, taskGroup, stageId: "validation" }),
1682838
+ generator: new TaskStageController({ taskId: id2, taskGroup, stageId: "generator" }),
1682839
+ output: new TaskStageController({ taskId: id2, taskGroup, stageId: "output" })
1682840
+ };
1682841
+ }
1682842
+ /**
1682843
+ * Get the underlying Task object for this SdkTask.
1682844
+ */
1682845
+ getTask() {
1682846
+ const task = this.taskGroup.getTask(this.id);
1682847
+ if (task == null) {
1682848
+ throw new Error(`Internal error; task '${this.id}' does not exist`);
1682849
+ }
1682850
+ return task;
1682851
+ }
1682852
+ /** Mark the task as running */
1682853
+ start(currentStep) {
1682854
+ this.taskGroup.updateTask({
1682855
+ id: this.id,
1682856
+ update: { status: "running", currentStep }
1682857
+ });
1682858
+ }
1682859
+ /** Mark the task as successfully completed */
1682860
+ complete(output2) {
1682861
+ this.taskGroup.updateTask({
1682862
+ id: this.id,
1682863
+ update: { status: "success", output: output2 }
1682864
+ });
1682865
+ }
1682866
+ /** Mark the task as failed */
1682867
+ fail(error49) {
1682868
+ this.taskGroup.updateTask({
1682869
+ id: this.id,
1682870
+ update: { status: "error", error: error49 }
1682871
+ });
1682872
+ }
1682873
+ };
1682874
+
1682875
+ // ../cli-v2/lib/sdk/task/SdkTaskGroup.js
1682876
+ var SdkTaskGroup = class {
1682877
+ taskGroup;
1682878
+ tasks = {};
1682879
+ defaultStages = [
1682880
+ {
1682881
+ id: "validation",
1682882
+ labels: {
1682883
+ pending: "Validate API",
1682884
+ running: "Validating API...",
1682885
+ success: "Validated API"
1682886
+ }
1682887
+ },
1682888
+ {
1682889
+ id: "generator",
1682890
+ labels: {
1682891
+ pending: "Run generator",
1682892
+ running: "Running generator...",
1682893
+ success: "Generator completed"
1682894
+ }
1682895
+ },
1682896
+ {
1682897
+ id: "output",
1682898
+ labels: {
1682899
+ pending: "Write output",
1682900
+ running: "Writing output...",
1682901
+ success: "Wrote output"
1682902
+ }
1682903
+ }
1682904
+ ];
1682905
+ constructor({ context: context2 }) {
1682906
+ this.tasks = {};
1682907
+ this.taskGroup = new TaskGroup({ context: context2 });
1682908
+ }
1682909
+ addTask({ id: id2, name: name3, stageOverrides }) {
1682910
+ const displayName = name3 ?? id2;
1682911
+ this.taskGroup.addTask({ id: id2, name: displayName });
1682912
+ const stages = this.buildStages(stageOverrides);
1682913
+ this.taskGroup.setStages(id2, stages);
1682914
+ const task = new SdkTask({ taskGroup: this.taskGroup, id: id2 });
1682915
+ this.tasks[id2] = task;
1682916
+ return task;
1682917
+ }
1682918
+ getTask(id2) {
1682919
+ return this.tasks[id2];
1682920
+ }
1682921
+ async start(header) {
1682922
+ await this.taskGroup.start(header);
1682923
+ }
1682924
+ finish({ successMessage, errorMessage }) {
1682925
+ return this.taskGroup.complete({
1682926
+ successMessage,
1682927
+ errorMessage
1682928
+ });
1682929
+ }
1682930
+ /**
1682931
+ * Build stage definitions, merging any overrides with defaults.
1682932
+ */
1682933
+ buildStages(overrides) {
1682934
+ if (overrides == null) {
1682935
+ return this.defaultStages;
1682936
+ }
1682937
+ return this.defaultStages.map((stage) => {
1682938
+ const override = overrides[stage.id];
1682939
+ if (override == null) {
1682940
+ return stage;
1682941
+ }
1682942
+ return {
1682943
+ ...stage,
1682944
+ labels: { ...stage.labels, ...override }
1682945
+ };
1682946
+ });
1682947
+ }
1682948
+ };
1682949
+
1682566
1682950
  // ../cli-v2/lib/commands/sdk/generate/command.js
1682567
1682951
  var GenerateCommand = class {
1682568
1682952
  async handle(context2, args) {
@@ -1682595,53 +1682979,46 @@ var GenerateCommand = class {
1682595
1682979
  });
1682596
1682980
  const token = args.local ? void 0 : await context2.getTokenOrPrompt();
1682597
1682981
  const runtime = args.local ? "local" : "remote";
1682598
- const taskGroup = new TaskGroup({ context: context2 });
1682599
- const skippedTargets = targets2.filter((t2) => checkResult.invalidApis.has(t2.api));
1682600
- for (const target of skippedTargets) {
1682982
+ const taskGroup = new SdkTaskGroup({ context: context2 });
1682983
+ for (const target of targets2) {
1682984
+ const stageOverrides = target.output.git != null ? {
1682985
+ output: this.getGitOutputStageLabels(target.output.git.mode ?? "pr")
1682986
+ } : void 0;
1682601
1682987
  taskGroup.addTask({
1682602
1682988
  id: target.name,
1682603
1682989
  name: target.name,
1682604
- status: "skipped",
1682605
- skipReason: `API '${target.api}' has errors`
1682606
- });
1682607
- }
1682608
- for (const target of validTargets) {
1682609
- taskGroup.addTask({
1682610
- id: target.name,
1682611
- name: target.name
1682990
+ stageOverrides
1682612
1682991
  });
1682613
1682992
  }
1682993
+ const sdkInitialism = this.maybePluralSdks(targets2);
1682614
1682994
  await taskGroup.start({
1682615
- title: "Generating SDKs",
1682995
+ title: `Generating ${sdkInitialism}`,
1682616
1682996
  subtitle: `org: ${workspace.sdks.org}`
1682617
1682997
  });
1682618
- await Promise.all(validTargets.map(async (target) => {
1682998
+ await Promise.all(targets2.map(async (target) => {
1682999
+ const task = taskGroup.getTask(target.name);
1683000
+ if (task == null) {
1683001
+ throw new Error(`Internal error; task '${target.name}' not found`);
1683002
+ }
1683003
+ task.start();
1683004
+ task.stage.validation.start();
1682619
1683005
  const apiDefinition = workspace.apis[target.api];
1682620
1683006
  if (apiDefinition == null) {
1682621
- const message = `API '${target.api}' not found in workspace`;
1682622
- taskGroup.updateTask({
1682623
- id: target.name,
1682624
- update: { status: "error", error: message }
1682625
- });
1683007
+ task.stage.validation.fail(`API not found in workspace`);
1682626
1683008
  return;
1682627
1683009
  }
1682628
- const task = taskGroup.getTask(target.name);
1682629
- if (task == null) {
1682630
- throw new Error(`Internal error; task '${target.name}' not found`);
1683010
+ if (checkResult.invalidApis.has(target.api)) {
1683011
+ task.stage.validation.fail(`API is invalid`);
1683012
+ return;
1682631
1683013
  }
1682632
- taskGroup.updateTask({
1682633
- id: target.name,
1682634
- update: {
1682635
- status: "running",
1682636
- currentStep: `${target.image}:${target.version}`
1682637
- }
1682638
- });
1683014
+ task.stage.validation.complete();
1683015
+ task.stage.generator.start();
1682639
1683016
  const pipelineResult = await pipeline5.run({
1682640
1683017
  organization: workspace.org,
1682641
1683018
  ai: workspace.ai,
1682642
- task,
1682643
1683019
  target,
1682644
1683020
  apiDefinition,
1683021
+ task: task.getTask(),
1682645
1683022
  audiences: this.parseAudiences(args.audience),
1682646
1683023
  runtime,
1682647
1683024
  containerEngine: args["container-engine"] ?? "docker",
@@ -1682652,31 +1683029,35 @@ var GenerateCommand = class {
1682652
1683029
  version: args.version
1682653
1683030
  });
1682654
1683031
  if (!pipelineResult.success) {
1682655
- taskGroup.updateTask({
1682656
- id: target.name,
1682657
- update: {
1682658
- status: "error",
1682659
- error: pipelineResult.error
1682660
- }
1682661
- });
1683032
+ task.stage.generator.fail(pipelineResult.error);
1682662
1683033
  return;
1682663
1683034
  }
1682664
- taskGroup.updateTask({
1682665
- id: target.name,
1682666
- update: {
1682667
- status: "success",
1682668
- output: pipelineResult.output
1682669
- }
1682670
- });
1683035
+ task.stage.generator.complete();
1683036
+ task.stage.output.complete();
1683037
+ task.complete(pipelineResult.output);
1682671
1683038
  }));
1682672
- const summary = taskGroup.complete({
1682673
- successMessage: `Successfully generated ${this.maybePluralSdks(validTargets)}`,
1682674
- errorMessage: `Failed to generate ${this.maybePluralSdks(validTargets)}`
1683039
+ const summary = taskGroup.finish({
1683040
+ successMessage: `Successfully generated ${sdkInitialism}`,
1683041
+ errorMessage: `Failed to generate ${sdkInitialism}`
1682675
1683042
  });
1682676
1683043
  if (summary.failedCount > 0) {
1682677
1683044
  throw CliError.exit();
1682678
1683045
  }
1682679
1683046
  }
1683047
+ validateArgs(args) {
1683048
+ if (args.output != null && !args.preview) {
1683049
+ throw new Error("The --output flag can only be used with --preview");
1683050
+ }
1683051
+ if (args["container-engine"] != null && !args.local) {
1683052
+ throw new Error("The --container-engine flag can only be used with --local");
1683053
+ }
1683054
+ if (args.group != null && args.target != null) {
1683055
+ throw new Error("The --group and --target flags cannot be used together");
1683056
+ }
1683057
+ if (args.group == null && args.target == null) {
1683058
+ throw new Error("A --target or --group must be specified");
1683059
+ }
1683060
+ }
1682680
1683061
  getTargets({ workspace, groupName, targetName }) {
1682681
1683062
  const targets2 = workspace.sdks != null ? this.filterTargetsByGroup(workspace.sdks.targets, groupName) : [];
1682682
1683063
  if (targetName != null) {
@@ -1682694,9 +1683075,6 @@ var GenerateCommand = class {
1682694
1683075
  }
1682695
1683076
  return targets2;
1682696
1683077
  }
1682697
- /**
1682698
- * Filter targets by group name. If no group is specified, returns all targets.
1682699
- */
1682700
1683078
  filterTargetsByGroup(targets2, groupName) {
1682701
1683079
  if (groupName == null) {
1682702
1683080
  return targets2;
@@ -1682712,23 +1683090,33 @@ var GenerateCommand = class {
1682712
1683090
  audiences
1682713
1683091
  };
1682714
1683092
  }
1682715
- validateArgs(args) {
1682716
- if (args.output != null && !args.preview) {
1682717
- throw new Error("The --output flag can only be used with --preview");
1682718
- }
1682719
- if (args["container-engine"] != null && !args.local) {
1682720
- throw new Error("The --container-engine flag can only be used with --local");
1682721
- }
1682722
- if (args.group != null && args.target != null) {
1682723
- throw new Error("The --group and --target flags cannot be used together");
1682724
- }
1682725
- if (args.group == null && args.target == null) {
1682726
- throw new Error("A --target or --group must be specified");
1682727
- }
1682728
- }
1682729
1683093
  maybePluralSdks(targets2) {
1682730
1683094
  return targets2.length === 1 ? "SDK" : "SDKs";
1682731
1683095
  }
1683096
+ getGitOutputStageLabels(mode) {
1683097
+ switch (mode) {
1683098
+ case "push":
1683099
+ return {
1683100
+ pending: "Push to repository",
1683101
+ running: "Pushing to repository...",
1683102
+ success: "Pushed to repository"
1683103
+ };
1683104
+ case "release":
1683105
+ return {
1683106
+ pending: "Create release",
1683107
+ running: "Creating release...",
1683108
+ success: "Created release"
1683109
+ };
1683110
+ case "pr":
1683111
+ return {
1683112
+ pending: "Create pull request",
1683113
+ running: "Creating pull request...",
1683114
+ success: "Created pull request"
1683115
+ };
1683116
+ default:
1683117
+ assertNever2(mode);
1683118
+ }
1683119
+ }
1682732
1683120
  };
1682733
1683121
  function addGenerateCommand(cli) {
1682734
1683122
  const cmd = new GenerateCommand();
@@ -1713426,7 +1713814,11 @@ async function getLatestGeneratorVersions({
1713426
1713814
  if (versions2.versions[group] == null) {
1713427
1713815
  versions2.versions[group] = {};
1713428
1713816
  }
1713429
- const normalizedGeneratorName = getGeneratorNameOrThrow(generator.name, context2);
1713817
+ const normalizedGeneratorName = normalizeGeneratorName(generator.name);
1713818
+ if (normalizedGeneratorName == null) {
1713819
+ context2.logger.debug(`Skipping unknown generator: ${generator.name}`);
1713820
+ return;
1713821
+ }
1713430
1713822
  const latestVersion2 = await getLatestGeneratorVersion({
1713431
1713823
  generatorName: normalizedGeneratorName,
1713432
1713824
  cliVersion: cliContext.environment.packageVersion,
@@ -1713461,7 +1713853,11 @@ async function getLatestGeneratorVersions({
1713461
1713853
  if (versions.versions[api][group] == null) {
1713462
1713854
  versions.versions[api][group] = {};
1713463
1713855
  }
1713464
- const normalizedGeneratorName = getGeneratorNameOrThrow(generator.name, context2);
1713856
+ const normalizedGeneratorName = normalizeGeneratorName(generator.name);
1713857
+ if (normalizedGeneratorName == null) {
1713858
+ context2.logger.debug(`Skipping unknown generator: ${generator.name}`);
1713859
+ return;
1713860
+ }
1713465
1713861
  const latestVersion2 = await getLatestGeneratorVersion({
1713466
1713862
  generatorName: normalizedGeneratorName,
1713467
1713863
  cliVersion: cliContext.environment.packageVersion,
@@ -1713615,7 +1714011,7 @@ var CliContext = class {
1713615
1714011
  if (false) {
1713616
1714012
  this.logger.error("CLI_VERSION is not defined");
1713617
1714013
  }
1713618
- return "3.64.4";
1714014
+ return "3.64.5-1-g103be4aafa9";
1713619
1714015
  }
1713620
1714016
  getCliName() {
1713621
1714017
  if (false) {
@@ -1716729,7 +1717125,7 @@ var import_path56 = __toESM(require("path"), 1);
1716729
1717125
  var LOCAL_STORAGE_FOLDER4 = ".fern-dev";
1716730
1717126
  var LOGS_FOLDER_NAME = "logs";
1716731
1717127
  function getCliSource() {
1716732
- const version7 = "3.64.4";
1717128
+ const version7 = "3.64.5-1-g103be4aafa9";
1716733
1717129
  return `cli@${version7}`;
1716734
1717130
  }
1716735
1717131
  var DebugLogger = class {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.64.4",
2
+ "version": "3.64.5-1-g103be4aafa9",
3
3
  "repository": {
4
4
  "type": "git",
5
5
  "url": "git+https://github.com/fern-api/fern.git",