gt 2.14.66 → 2.15.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/api/saveLocalEdits.js +1 -3
  3. package/dist/api/saveLocalEdits.js.map +1 -1
  4. package/dist/cli/base.js +4 -0
  5. package/dist/cli/base.js.map +1 -1
  6. package/dist/cli/inline.js +1 -3
  7. package/dist/cli/inline.js.map +1 -1
  8. package/dist/console/logger.d.ts +13 -0
  9. package/dist/console/logger.js +35 -8
  10. package/dist/console/logger.js.map +1 -1
  11. package/dist/console/logging.js +4 -2
  12. package/dist/console/logging.js.map +1 -1
  13. package/dist/generated/version.d.ts +1 -1
  14. package/dist/generated/version.js +1 -1
  15. package/dist/generated/version.js.map +1 -1
  16. package/dist/workflows/download.js +3 -9
  17. package/dist/workflows/download.js.map +1 -1
  18. package/dist/workflows/enqueue.js +0 -2
  19. package/dist/workflows/enqueue.js.map +1 -1
  20. package/dist/workflows/publish.js +1 -3
  21. package/dist/workflows/publish.js.map +1 -1
  22. package/dist/workflows/setupProject.js +0 -3
  23. package/dist/workflows/setupProject.js.map +1 -1
  24. package/dist/workflows/stage.js +3 -13
  25. package/dist/workflows/stage.js.map +1 -1
  26. package/dist/workflows/steps/BranchStep.d.ts +1 -3
  27. package/dist/workflows/steps/BranchStep.js +1 -4
  28. package/dist/workflows/steps/BranchStep.js.map +1 -1
  29. package/dist/workflows/steps/DownloadStep.d.ts +1 -3
  30. package/dist/workflows/steps/DownloadStep.js +1 -4
  31. package/dist/workflows/steps/DownloadStep.js.map +1 -1
  32. package/dist/workflows/steps/EnqueueStep.d.ts +1 -5
  33. package/dist/workflows/steps/EnqueueStep.js +9 -19
  34. package/dist/workflows/steps/EnqueueStep.js.map +1 -1
  35. package/dist/workflows/steps/PollJobsStep.d.ts +1 -3
  36. package/dist/workflows/steps/PollJobsStep.js +1 -4
  37. package/dist/workflows/steps/PollJobsStep.js.map +1 -1
  38. package/dist/workflows/steps/PublishStep.d.ts +1 -3
  39. package/dist/workflows/steps/PublishStep.js +1 -4
  40. package/dist/workflows/steps/PublishStep.js.map +1 -1
  41. package/dist/workflows/steps/SetupStep.d.ts +1 -6
  42. package/dist/workflows/steps/SetupStep.js +14 -41
  43. package/dist/workflows/steps/SetupStep.js.map +1 -1
  44. package/dist/workflows/steps/TagStep.d.ts +1 -4
  45. package/dist/workflows/steps/TagStep.js +4 -9
  46. package/dist/workflows/steps/TagStep.js.map +1 -1
  47. package/dist/workflows/steps/UploadSourcesStep.d.ts +1 -7
  48. package/dist/workflows/steps/UploadSourcesStep.js +4 -8
  49. package/dist/workflows/steps/UploadSourcesStep.js.map +1 -1
  50. package/dist/workflows/steps/UploadTranslationsStep.d.ts +1 -4
  51. package/dist/workflows/steps/UploadTranslationsStep.js +6 -11
  52. package/dist/workflows/steps/UploadTranslationsStep.js.map +1 -1
  53. package/dist/workflows/steps/UserEditDiffsStep.d.ts +1 -5
  54. package/dist/workflows/steps/UserEditDiffsStep.js +3 -11
  55. package/dist/workflows/steps/UserEditDiffsStep.js.map +1 -1
  56. package/dist/workflows/upload.js +1 -6
  57. package/dist/workflows/upload.js.map +1 -1
  58. package/package.json +6 -6
  59. package/dist/workflows/steps/WorkflowStep.d.ts +0 -4
  60. package/dist/workflows/steps/WorkflowStep.js +0 -6
  61. package/dist/workflows/steps/WorkflowStep.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.15.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1920](https://github.com/generaltranslation/gt/pull/1920) [`f2c196b`](https://github.com/generaltranslation/gt/commit/f2c196b6d37c4abb646961826f2a2154f8cabbc8) Thanks [@JoshKappler](https://github.com/JoshKappler)! - Add a global `--quiet` / `-q` flag to the CLI that suppresses informational output. Under `--quiet` the CLI drops the info/step/success/spinner chatter and the ASCII banner in both the default and `GT_LOG_FORMAT=json` paths, while warnings, errors, exit codes, and command results stay the same. In JSON mode the remaining output keeps its shape: only info/debug/trace lines are dropped, and warn/error and above still print. The flag takes precedence over `GT_LOG_LEVEL` without lowering an already-more-restrictive level, and interactive prompts still run when a command genuinely needs input.
8
+
9
+ ### Patch Changes
10
+
11
+ - [#1889](https://github.com/generaltranslation/gt/pull/1889) [`29cd6b8`](https://github.com/generaltranslation/gt/commit/29cd6b89f3587d3253cfadde6bec925d8697324b) Thanks [@bgub](https://github.com/bgub)! - Allow `awaitJobs()` to poll job IDs directly and reuse that shared polling implementation for CLI and Sanity project setup.
12
+
13
+ - [#1886](https://github.com/generaltranslation/gt/pull/1886) [`7cb2dfe`](https://github.com/generaltranslation/gt/commit/7cb2dfef077ee642f211996b0d729844a18258a8) Thanks [@bgub](https://github.com/bgub)! - Flatten the CLI workflow step lifecycle by folding completion behavior into each step's `run()` method and removing the unused shared step protocol.
14
+
15
+ - Updated dependencies [[`29cd6b8`](https://github.com/generaltranslation/gt/commit/29cd6b89f3587d3253cfadde6bec925d8697324b), [`e55aaa9`](https://github.com/generaltranslation/gt/commit/e55aaa9cfdf6dfe3ab96d0eea927f255b66cd20d)]:
16
+ - generaltranslation@9.0.5
17
+ - @generaltranslation/icu@0.1.1
18
+ - @generaltranslation/python-extractor@0.2.32
19
+ - @generaltranslation/supported-locales@2.1.12
20
+ - @generaltranslation/format@0.1.4
21
+
3
22
  ## 2.14.66
4
23
 
5
24
  ### Patch Changes
@@ -16,9 +16,7 @@ async function saveLocalEdits(settings) {
16
16
  if (!settings.files) return;
17
17
  const { files, publishMap } = await aggregateFiles(settings);
18
18
  if (!files.length) return;
19
- const branchStep = new BranchStep(gt, settings);
20
- const branchResult = await branchStep.run();
21
- await branchStep.wait();
19
+ const branchResult = await new BranchStep(gt, settings).run();
22
20
  if (!branchResult) return logErrorAndExit(branchResolutionError);
23
21
  const uploads = files.map((file) => ({
24
22
  fileName: file.fileName,
@@ -1 +1 @@
1
- {"version":3,"file":"saveLocalEdits.js","names":[],"sources":["../../src/api/saveLocalEdits.ts"],"sourcesContent":["import { Settings } from '../types/index.js';\nimport { aggregateFiles } from '../formats/files/aggregateFiles.js';\nimport { collectAndSendUserEditDiffs } from './collectUserEditDiffs.js';\nimport { gt } from '../utils/gt.js';\nimport { BranchStep } from '../workflows/steps/BranchStep.js';\nimport { logErrorAndExit } from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { branchResolutionError } from '../console/index.js';\nimport type { FileReference } from 'generaltranslation/types';\nimport chalk from 'chalk';\nimport { runPublishWorkflow } from '../workflows/publish.js';\n\n/**\n * Uploads current source files to obtain file references, then collects and sends\n * diffs for all locales based on last downloaded versions. Does not enqueue translations.\n */\nexport async function saveLocalEdits(settings: Settings): Promise<void> {\n if (!settings.files) return;\n\n // Collect current files from config\n const { files, publishMap } = await aggregateFiles(settings);\n if (!files.length) return;\n\n // run branch query to get branch id\n // Run the branch step\n const branchStep = new BranchStep(gt, settings);\n const branchResult = await branchStep.run();\n await branchStep.wait();\n if (!branchResult) {\n return logErrorAndExit(branchResolutionError);\n }\n\n const uploads = files.map((file) => ({\n fileName: file.fileName,\n fileFormat: file.fileFormat,\n branchId: branchResult.currentBranch.id,\n fileId: file.fileId,\n versionId: file.versionId,\n })) satisfies FileReference[];\n\n const spinner = logger.createSpinner('dots');\n spinner.start('Saving local edits...');\n\n const hadDiffs = await collectAndSendUserEditDiffs(uploads, settings);\n spinner.stop(chalk.green('Local edits saved successfully'));\n\n // Publish files to CDN if diffs were detected and publish config exists\n if (hadDiffs) {\n await runPublishWorkflow(\n files,\n publishMap,\n branchResult.currentBranch.id,\n settings\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAgBA,eAAsB,eAAe,UAAmC;AACtE,KAAI,CAAC,SAAS,MAAO;CAGrB,MAAM,EAAE,OAAO,eAAe,MAAM,eAAe,SAAS;AAC5D,KAAI,CAAC,MAAM,OAAQ;CAInB,MAAM,aAAa,IAAI,WAAW,IAAI,SAAS;CAC/C,MAAM,eAAe,MAAM,WAAW,KAAK;AAC3C,OAAM,WAAW,MAAM;AACvB,KAAI,CAAC,aACH,QAAO,gBAAgB,sBAAsB;CAG/C,MAAM,UAAU,MAAM,KAAK,UAAU;EACnC,UAAU,KAAK;EACf,YAAY,KAAK;EACjB,UAAU,aAAa,cAAc;EACrC,QAAQ,KAAK;EACb,WAAW,KAAK;EACjB,EAAE;CAEH,MAAM,UAAU,OAAO,cAAc,OAAO;AAC5C,SAAQ,MAAM,wBAAwB;CAEtC,MAAM,WAAW,MAAM,4BAA4B,SAAS,SAAS;AACrE,SAAQ,KAAK,MAAM,MAAM,iCAAiC,CAAC;AAG3D,KAAI,SACF,OAAM,mBACJ,OACA,YACA,aAAa,cAAc,IAC3B,SACD"}
1
+ {"version":3,"file":"saveLocalEdits.js","names":[],"sources":["../../src/api/saveLocalEdits.ts"],"sourcesContent":["import { Settings } from '../types/index.js';\nimport { aggregateFiles } from '../formats/files/aggregateFiles.js';\nimport { collectAndSendUserEditDiffs } from './collectUserEditDiffs.js';\nimport { gt } from '../utils/gt.js';\nimport { BranchStep } from '../workflows/steps/BranchStep.js';\nimport { logErrorAndExit } from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { branchResolutionError } from '../console/index.js';\nimport type { FileReference } from 'generaltranslation/types';\nimport chalk from 'chalk';\nimport { runPublishWorkflow } from '../workflows/publish.js';\n\n/**\n * Uploads current source files to obtain file references, then collects and sends\n * diffs for all locales based on last downloaded versions. Does not enqueue translations.\n */\nexport async function saveLocalEdits(settings: Settings): Promise<void> {\n if (!settings.files) return;\n\n // Collect current files from config\n const { files, publishMap } = await aggregateFiles(settings);\n if (!files.length) return;\n\n // run branch query to get branch id\n // Run the branch step\n const branchStep = new BranchStep(gt, settings);\n const branchResult = await branchStep.run();\n if (!branchResult) {\n return logErrorAndExit(branchResolutionError);\n }\n\n const uploads = files.map((file) => ({\n fileName: file.fileName,\n fileFormat: file.fileFormat,\n branchId: branchResult.currentBranch.id,\n fileId: file.fileId,\n versionId: file.versionId,\n })) satisfies FileReference[];\n\n const spinner = logger.createSpinner('dots');\n spinner.start('Saving local edits...');\n\n const hadDiffs = await collectAndSendUserEditDiffs(uploads, settings);\n spinner.stop(chalk.green('Local edits saved successfully'));\n\n // Publish files to CDN if diffs were detected and publish config exists\n if (hadDiffs) {\n await runPublishWorkflow(\n files,\n publishMap,\n branchResult.currentBranch.id,\n settings\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAgBA,eAAsB,eAAe,UAAmC;AACtE,KAAI,CAAC,SAAS,MAAO;CAGrB,MAAM,EAAE,OAAO,eAAe,MAAM,eAAe,SAAS;AAC5D,KAAI,CAAC,MAAM,OAAQ;CAKnB,MAAM,eAAe,MAAM,IADJ,WAAW,IAAI,SACD,CAAC,KAAK;AAC3C,KAAI,CAAC,aACH,QAAO,gBAAgB,sBAAsB;CAG/C,MAAM,UAAU,MAAM,KAAK,UAAU;EACnC,UAAU,KAAK;EACf,YAAY,KAAK;EACjB,UAAU,aAAa,cAAc;EACrC,QAAQ,KAAK;EACb,WAAW,KAAK;EACjB,EAAE;CAEH,MAAM,UAAU,OAAO,cAAc,OAAO;AAC5C,SAAQ,MAAM,wBAAwB;CAEtC,MAAM,WAAW,MAAM,4BAA4B,SAAS,SAAS;AACrE,SAAQ,KAAK,MAAM,MAAM,iCAAiC,CAAC;AAG3D,KAAI,SACF,OAAM,mBACJ,OACA,YACA,aAAa,cAAc,IAC3B,SACD"}
package/dist/cli/base.js CHANGED
@@ -57,6 +57,10 @@ var BaseCLI = class {
57
57
  this.additionalModules = additionalModules || [];
58
58
  this.program.option("--skip-version-check", "Skip the monorepo GT package version consistency check");
59
59
  this.program.option("--suppress-id-compatibility-warning", "Suppress the React package ID compatibility warning");
60
+ this.program.option("-q, --quiet", "Suppress informational output; only warnings and errors are shown");
61
+ this.program.hook("preAction", () => {
62
+ logger.setQuiet(Boolean(this.program.opts().quiet));
63
+ });
60
64
  this.program.hook("preAction", async (thisCommand, actionCommand) => {
61
65
  if (actionCommand.parent !== thisCommand) return;
62
66
  if (!ID_COMPATIBILITY_WARNING_COMMANDS.has(actionCommand.name())) return;
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","names":[],"sources":["../../src/cli/base.ts"],"sourcesContent":["import { Command } from 'commander';\nimport {\n DEFAULT_TRANSLATIONS_DIR,\n DEFAULT_VITE_TRANSLATIONS_DIR,\n} from '../utils/constants.js';\nimport { createOrUpdateConfig } from '../fs/config/setupConfig.js';\nimport findFilepath from '../fs/findFilepath.js';\nimport {\n displayHeader,\n promptText,\n logErrorAndExit,\n exitSync,\n promptConfirm,\n promptMultiSelect,\n promptSelect,\n promptGlobPatterns,\n} from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { parseGlobPatterns } from '../console/promptParsing.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport {\n FilesOptions,\n Settings,\n SupportedLibraries,\n SetupOptions,\n TranslateFlags,\n SharedFlags,\n} from '../types/index.js';\nimport { generateSettings } from '../config/generateSettings.js';\nimport chalk from 'chalk';\nimport { FILE_EXT_TO_EXT_LABEL } from '../formats/files/supportedFiles.js';\nimport { handleSetupReactCommand } from '../setup/wizard.js';\nimport {\n isPackageInstalled,\n searchForPackageJson,\n} from '../utils/packageJson.js';\nimport { getDesiredLocales } from '../setup/userInput.js';\nimport { installPackage } from '../utils/installPackage.js';\nimport { getPackageManager } from '../utils/packageManager.js';\nimport { retrieveCredentials, setCredentials } from '../utils/credentials.js';\nimport { areCredentialsSet } from '../utils/credentials.js';\nimport { upload } from './commands/upload.js';\nimport { attachSharedFlags, attachTranslateFlags } from './flags.js';\nimport { handleStage } from './commands/stage.js';\nimport { handleSetupProject } from './commands/setupProject.js';\nimport { handleDownload } from './commands/download.js';\nimport {\n handleTranslate,\n postProcessTranslations,\n} from './commands/translate.js';\nimport {\n getNeedsPostprocessing,\n clearDownloaded,\n} from '../state/recentDownloads.js';\nimport { clearWarnings } from '../state/translateWarnings.js';\nimport { displayTranslateSummary } from '../console/displayTranslateSummary.js';\nimport updateConfig from '../fs/config/updateConfig.js';\nimport { createLoadTranslationsFile } from '../fs/createLoadTranslationsFile.js';\nimport { saveLocalEdits } from '../api/saveLocalEdits.js';\nimport processSharedStaticAssets, {\n mirrorAssetsToLocales,\n} from '../utils/sharedStaticAssets.js';\nimport { setupLocadex } from '../locadex/setupFlow.js';\nimport { detectFramework } from '../setup/detectFramework.js';\nimport {\n getFrameworkDisplayName,\n getReactFrameworkLibrary,\n} from '../setup/frameworkUtils.js';\nimport { INLINE_LIBRARIES } from '../types/libraries.js';\nimport { handleEnqueue } from './commands/enqueue.js';\nimport { splitMintlifyLanguageRefs } from '../utils/splitMintlifyLanguageRefs.js';\nimport { runMergeDriver, type MergeDriverName } from '../git/mergeDrivers.js';\nimport { setupGitMergeDrivers } from '../git/setupMergeDrivers.js';\nimport { warnReactPackageCompatibility } from '../utils/reactPackageCompatibility.js';\n\nconst ID_COMPATIBILITY_WARNING_COMMANDS = new Set([\n 'download',\n 'enqueue',\n 'generate',\n 'setup',\n 'stage',\n 'translate',\n 'validate',\n]);\n\nexport type UploadOptions = {\n config?: string;\n apiKey?: string;\n projectId?: string;\n defaultLocale?: string;\n};\n\nexport type LoginOptions = {\n config?: string;\n keyType?: 'development' | 'production' | 'all';\n};\n\nexport type GitSetupOptions = {\n config?: string;\n dryRun?: boolean;\n omitConfigIds?: boolean;\n driverCommand?: string;\n};\n\nexport class BaseCLI {\n protected library: SupportedLibraries;\n protected additionalModules: SupportedLibraries[];\n protected program: Command;\n // Constructor is shared amongst all CLI class types\n public constructor(\n program: Command,\n library: SupportedLibraries,\n additionalModules?: SupportedLibraries[]\n ) {\n this.program = program;\n this.library = library;\n this.additionalModules = additionalModules || [];\n\n this.program.option(\n '--skip-version-check',\n 'Skip the monorepo GT package version consistency check'\n );\n this.program.option(\n '--suppress-id-compatibility-warning',\n 'Suppress the React package ID compatibility warning'\n );\n this.program.hook('preAction', async (thisCommand, actionCommand) => {\n // Nested commands (e.g. `gt git setup`) can share leaf names with\n // translation commands; only direct children of the root qualify\n if (actionCommand.parent !== thisCommand) return;\n if (!ID_COMPATIBILITY_WARNING_COMMANDS.has(actionCommand.name())) return;\n await warnReactPackageCompatibility(\n Boolean(this.program.opts().suppressIdCompatibilityWarning)\n );\n });\n\n this.setupInitCommand();\n this.setupConfigureCommand();\n this.setupUploadCommand();\n this.setupLoginCommand();\n this.setupSendDiffsCommand();\n this.setupGitCommand();\n }\n // Init is never called in a child class\n public init() {\n this.setupSetupProjectCommand();\n this.setupStageCommand();\n this.setupTranslateCommand();\n this.setupDownloadCommand();\n this.setupEnqueueCommand();\n }\n // Execute is called by the main program\n public execute() {\n // If no command is specified, run 'init'\n if (process.argv.length <= 2) {\n process.argv.push('init');\n }\n }\n\n protected setupSetupProjectCommand(): void {\n attachTranslateFlags(\n this.program\n .command('setup')\n .description(\n 'Upload source files and setup the project for translation'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Uploading source files and setting up project...');\n await this.handleSetupProject(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupStageCommand(): void {\n attachTranslateFlags(\n this.program\n .command('stage')\n .description(\n 'Submits the project to the General Translation API for translation. Translations created using this command will require human approval.'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader(\n 'Staging project for translation with approval required...'\n );\n await this.handleStage(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupEnqueueCommand(): void {\n attachTranslateFlags(\n this.program\n .command('enqueue')\n .description('Enqueues translations for a given set of files')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Enqueuing translations...');\n await this.handleEnqueue(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupDownloadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('download')\n .description('Download translations that were originally staged')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Downloading translations...');\n await this.handleDownload(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupTranslateCommand(): void {\n attachTranslateFlags(\n this.program\n .command('translate')\n .description('Translate your project using General Translation')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Starting translation...');\n await this.handleTranslate(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupSendDiffsCommand(): void {\n attachSharedFlags(\n this.program\n .command('save-local')\n .description(\n 'Save local edits for all configured files by sending diffs (no translation enqueued)'\n )\n )\n .option('--publish', 'Publish translations to the CDN', false)\n .action(async (initOptions: SharedFlags) => {\n displayHeader('Saving local edits...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await saveLocalEdits(settings);\n logger.endCommand('Saved local edits');\n });\n }\n\n protected setupGitCommand(): void {\n const gitCommand = this.program\n .command('git')\n .description('Configure Git integrations for General Translation');\n\n gitCommand\n .command('setup')\n .description('Set up GT merge drivers for generated translation files')\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .option('--dry-run', 'Print changes without writing files', false)\n .option(\n '--omit-config-ids',\n 'Persist omitConfigIds and remove generated config IDs'\n )\n .option(\n '--driver-command <command>',\n 'Command Git should use to invoke gt, e.g. \"pnpm exec gt\"'\n )\n .action(async (options: GitSetupOptions) => {\n displayHeader('Setting up GT Git merge drivers...');\n const settings = await generateSettings(options, undefined, {\n requireConfig: true,\n });\n const omitConfigIds = await this.resolveGitSetupOmitConfigIds(\n options,\n settings\n );\n const result = await setupGitMergeDrivers(settings, {\n dryRun: options.dryRun,\n omitConfigIds,\n driverCommand: options.driverCommand,\n });\n\n for (const line of result.addedAttributes) {\n logger.step(\n `${options.dryRun ? 'Would add' : 'Added'} ${chalk.cyan(\n line\n )} to ${chalk.cyan(result.gitattributesPath)}`\n );\n }\n if (result.addedAttributes.length === 0) {\n logger.info(`${chalk.cyan('.gitattributes')} is already configured.`);\n }\n\n for (const args of result.gitConfigCommands) {\n logger.step(\n `${options.dryRun ? 'Would run' : 'Configured'} ${chalk.cyan(\n `git config --local ${args.join(' ')}`\n )}`\n );\n }\n\n if (result.updatedConfig) {\n logger.step(\n `${options.dryRun ? 'Would persist' : 'Persisted'} ${chalk.cyan(\n 'omitConfigIds: true'\n )} in ${chalk.cyan(settings.config)}`\n );\n } else if (options.dryRun && !settings.omitConfigIds) {\n logger.info(\n `Run without ${chalk.cyan('--dry-run')} to be prompted to persist ${chalk.cyan(\n 'omitConfigIds: true'\n )}, or pass ${chalk.cyan('--omit-config-ids')}.`\n );\n }\n\n for (const warning of result.warnings) {\n logger.warn(chalk.yellow(warning));\n }\n\n logger.endCommand(\n options.dryRun\n ? 'Dry run complete.'\n : 'GT Git merge drivers configured.'\n );\n });\n\n gitCommand\n .command('merge-driver', { hidden: true })\n .argument('<driver>', 'Merge driver name')\n .argument('<base>', 'Common ancestor file')\n .argument('<ours>', 'Current branch file')\n .argument('<theirs>', 'Incoming branch file')\n .argument('[path]', 'Merged path')\n .action((driver: string, base: string, ours: string, theirs: string) => {\n if (driver !== 'gt-lock' && driver !== 'gtjson') {\n logger.error(`Unknown GT merge driver: ${driver}`);\n exitSync(1);\n }\n const result = runMergeDriver(\n driver as MergeDriverName,\n base,\n ours,\n theirs\n );\n if (!result.ok) {\n logger.error(result.reason);\n exitSync(1);\n }\n });\n }\n\n protected async resolveGitSetupOmitConfigIds(\n options: GitSetupOptions,\n settings: Settings\n ): Promise<boolean> {\n if (options.omitConfigIds) return true;\n // Already opted in: persist again so stale config IDs still get removed\n if (settings.omitConfigIds) return true;\n if (options.dryRun || !process.stdin.isTTY || !process.stdout.isTTY) {\n return false;\n }\n return promptConfirm({\n message:\n 'Also set omitConfigIds: true to reduce gt.config.json merge conflicts?',\n defaultValue: true,\n });\n }\n\n protected async handleSetupProject(\n initOptions: TranslateFlags\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n await handleSetupProject(initOptions, settings, this.library);\n }\n\n protected async handleStage(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n // Update settings.stageTranslations to true\n settings.stageTranslations = true;\n await updateConfig(settings.config, {\n stageTranslations: true,\n });\n }\n await handleStage(initOptions, settings, this.library, true);\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleEnqueue(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleEnqueue(initOptions, settings, this.library);\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleDownload(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleDownload(initOptions, settings, this.library);\n }\n\n protected async handleTranslate(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n const results = await handleStage(\n initOptions,\n settings,\n this.library,\n false\n );\n if (results) {\n await handleTranslate(\n initOptions,\n settings,\n results.fileVersionData,\n results.jobData,\n results.branchData,\n results.publishMap\n );\n }\n } else {\n await handleDownload(initOptions, settings, this.library);\n }\n // Only postprocess files downloaded in this run\n const include = getNeedsPostprocessing();\n if (include.size > 0) {\n await postProcessTranslations(settings, include);\n }\n // Split Mintlify language entries into $ref files to keep docs.json small\n await splitMintlifyLanguageRefs(settings);\n // Mirror assets after translations are downloaded and locale dirs are populated\n await mirrorAssetsToLocales(settings);\n clearDownloaded();\n displayTranslateSummary();\n clearWarnings();\n }\n\n protected setupUploadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('upload')\n .description(\n 'Upload source files and translations to the General Translation platform'\n )\n ).action(async (initOptions: UploadOptions) => {\n displayHeader('Starting upload...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n const options = { ...initOptions, ...settings };\n\n await this.handleUploadCommand(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupLoginCommand(): void {\n this.program\n .command('auth')\n .description('Generate General Translation API keys and project ID')\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .option(\n '-t, --key-type <type>',\n 'Type of key to generate, production | development | all'\n )\n .action(async (options: LoginOptions) => {\n displayHeader('Authenticating with General Translation...');\n if (!options.keyType) {\n options.keyType = await promptSelect<\n 'development' | 'production' | 'all'\n >({\n message: 'What type of API key would you like to generate?',\n options: [\n { value: 'development', label: 'Development' },\n { value: 'production', label: 'Production' },\n { value: 'all', label: 'Both' },\n ],\n defaultValue: 'all',\n });\n } else {\n if (\n options.keyType !== 'development' &&\n options.keyType !== 'production' &&\n options.keyType !== 'all'\n ) {\n logErrorAndExit(\n 'Invalid key type, must be development, production, or all'\n );\n }\n }\n await this.handleLoginCommand(options);\n logger.endCommand(\n `Done! ${options.keyType} keys have been generated and saved to your .env.local file.`\n );\n });\n }\n\n protected setupInitCommand(): void {\n this.program\n .command('init')\n .description(\n 'Run the setup wizard to configure your project for General Translation'\n )\n .option(\n '--src <paths...>',\n \"Space-separated list of glob patterns containing the app's source code, by default 'src/**/*.{js,jsx,ts,tsx}' 'app/**/*.{js,jsx,ts,tsx}' 'pages/**/*.{js,jsx,ts,tsx}' 'components/**/*.{js,jsx,ts,tsx}'\"\n )\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .action(async (options: SetupOptions) => {\n const settings = await generateSettings(options);\n displayHeader('Running setup wizard...');\n\n const framework = await detectFramework();\n\n const useAgent = await (async () => {\n let useAgentMessage;\n if (framework.name === 'mintlify') {\n useAgentMessage = `Mintlify project detected. Would you like to connect to GitHub so that the Locadex AI Agent can translate your project automatically?`;\n }\n if (framework.name === 'next-app') {\n useAgentMessage = `Next.js App Router detected. Would you like to connect to GitHub so that the Locadex AI Agent can set up your project automatically?`;\n }\n if (useAgentMessage) {\n return await promptConfirm({\n message: useAgentMessage,\n defaultValue: false,\n });\n }\n return false;\n })();\n\n if (useAgent) {\n await setupLocadex(settings);\n logger.endCommand(\n 'Once installed, Locadex will open a PR to your repository. See the docs for more information: https://generaltranslation.com/docs/locadex'\n );\n } else {\n // Get framework display info for the defaults message\n const frameworkDisplayName =\n framework.type === 'react'\n ? getFrameworkDisplayName(framework)\n : null;\n const library =\n framework.type === 'react'\n ? getReactFrameworkLibrary(framework)\n : null;\n\n // Build defaults description based on detected framework\n const defaultTranslationsDir =\n framework.name === 'vite'\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n const defaultsDescription =\n framework.type === 'react'\n ? `${library} & GTProvider, ${frameworkDisplayName}, Files saved locally in ${defaultTranslationsDir}`\n : `Files saved locally in ${defaultTranslationsDir}`;\n\n // Ask if user wants to use defaults\n const useDefaults = await promptConfirm({\n message: `Would you like to use the recommended General Translation defaults? ${chalk.dim(`(${defaultsDescription})`)}`,\n defaultValue: true,\n });\n\n let ranReactSetup = false;\n\n // so that people can run init in non-js projects\n if (framework.type === 'react') {\n const wrap = useDefaults\n ? true\n : await promptConfirm({\n message: `Would you like to install ${library} and add the GTProvider? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`,\n defaultValue: true,\n });\n\n if (wrap) {\n logger.info(\n `${chalk.yellow('[EXPERIMENTAL]')} Configuring project...`\n );\n await handleSetupReactCommand(options, framework, useDefaults);\n logger.endCommand(\n `Done! Since this wizard is experimental, please review the changes and make modifications as needed.\n\\nNext step: start internationalizing! See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`\n );\n ranReactSetup = true;\n }\n }\n\n if (ranReactSetup) {\n logger.startCommand('Setting up project config...');\n }\n // Configure gt.config.json\n await this.handleInitCommand(\n ranReactSetup,\n useDefaults,\n framework.name === 'vite'\n );\n\n logger.endCommand(\n 'Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs'\n );\n }\n });\n }\n\n protected setupConfigureCommand(): void {\n this.program\n .command('configure')\n .description(\n 'Configure your project for General Translation. This will create a gt.config.json file in your codebase.'\n )\n .action(async () => {\n displayHeader('Configuring project...');\n\n logger.info(\n 'Welcome! This tool will help you configure your gt.config.json file. See the docs: https://generaltranslation.com/docs/cli/reference/config for more information.'\n );\n\n // Configure gt.config.json\n const framework = await detectFramework();\n await this.handleInitCommand(false, false, framework.name === 'vite');\n\n logger.endCommand(\n 'Done! Make sure you have an API key and project ID to use General Translation. Get them on the dashboard: https://generaltranslation.com/dashboard'\n );\n });\n }\n\n protected async handleUploadCommand(\n settings: Settings & UploadOptions\n ): Promise<void> {\n if (!settings.files) {\n return;\n }\n\n // Process all file types at once with a single call\n await upload(settings);\n }\n\n // Wizard for configuring gt.config.json\n protected async handleInitCommand(\n ranReactSetup: boolean,\n useDefaults: boolean = false,\n isVite: boolean = false\n ): Promise<void> {\n const { defaultLocale, locales } = await getDesiredLocales(); // Locales should still be asked for even if using defaults\n\n const packageJson = await searchForPackageJson();\n\n // Ask if using another i18n library\n const gtInstalled =\n !!packageJson &&\n INLINE_LIBRARIES.some((lib) => isPackageInstalled(lib, packageJson));\n const isUsingGT = ranReactSetup || gtInstalled;\n\n // Ask where the translations are stored\n const usingCDN = await (async () => {\n if (!isUsingGT) return false;\n if (useDefaults) return false; // Default to local\n const selectedValue = await promptSelect({\n message: `Would you like to save translation files locally or use the General Translation CDN to store them?`,\n options: [\n { value: 'local', label: 'Save locally' },\n { value: 'cdn', label: 'Use CDN' },\n ],\n defaultValue: 'local',\n });\n return selectedValue === 'cdn';\n })();\n\n const defaultTranslationsDir = isVite\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n // Ask where the translations are stored\n const translationsDir =\n isUsingGT && !usingCDN\n ? useDefaults\n ? defaultTranslationsDir\n : await promptText({\n message:\n 'What is the path to the directory where you would like to store your translation files?',\n defaultValue: defaultTranslationsDir,\n })\n : null;\n\n // Determine final translations directory with fallback\n const finalTranslationsDir =\n translationsDir?.trim() || defaultTranslationsDir;\n\n if (isUsingGT && !usingCDN) {\n // Create loadTranslations.js file for local translations\n await createLoadTranslationsFile(\n process.cwd(),\n finalTranslationsDir,\n locales\n );\n logger.message(\n `Created ${chalk.cyan('loadTranslations.js')} file for local translations.\nMake sure to add this function to your app configuration.\nSee https://generaltranslation.com/en/docs/next/guides/local-tx`\n );\n }\n\n const message = !isUsingGT\n ? 'What is the format of your language resource files? Select as many as applicable.\\nAdditionally, you can translate any other files you have in your project.'\n : `Do you have any additional files in this project to translate? For example, Markdown files for docs. ${chalk.dim(\n '(To continue without selecting press Enter)'\n )}`;\n const fileExtensions =\n useDefaults && isUsingGT\n ? [] // Skip for GT projects when using defaults\n : await promptMultiSelect({\n message,\n options: [\n { value: 'json', label: FILE_EXT_TO_EXT_LABEL.json },\n { value: 'md', label: FILE_EXT_TO_EXT_LABEL.md },\n { value: 'mdx', label: FILE_EXT_TO_EXT_LABEL.mdx },\n { value: 'ts', label: FILE_EXT_TO_EXT_LABEL.ts },\n { value: 'js', label: FILE_EXT_TO_EXT_LABEL.js },\n { value: 'yaml', label: FILE_EXT_TO_EXT_LABEL.yaml },\n // TWILIO_CONTENT_JSON not supported in CLI init as its too niche\n ],\n required: !isUsingGT,\n });\n\n const files: FilesOptions = {};\n for (const fileExtension of fileExtensions) {\n const label = FILE_EXT_TO_EXT_LABEL[fileExtension];\n const paths = await promptGlobPatterns({\n label,\n message: `${chalk.cyan(FILE_EXT_TO_EXT_LABEL[fileExtension])}: Enter a space-separated list of glob patterns matching the location of the ${FILE_EXT_TO_EXT_LABEL[fileExtension]} files you would like to translate.\\nMake sure to include [locale] in the patterns.\\nSee https://generaltranslation.com/docs/cli/reference/config#include for more information.`,\n defaultValue: `./**/[locale]/*.${fileExtension}`,\n });\n\n files[fileExtension] = {\n include: parseGlobPatterns(paths),\n };\n }\n\n // Add GT translations if using GT and storing locally\n if (isUsingGT && !usingCDN) {\n files.gt = {\n output: path.join(finalTranslationsDir, `[locale].json`),\n };\n }\n\n let configFilepath = 'gt.config.json';\n if (fs.existsSync('src/gt.config.json')) {\n configFilepath = 'src/gt.config.json';\n }\n\n // Create gt.config.json\n await createOrUpdateConfig(configFilepath, {\n defaultLocale,\n locales,\n files: Object.keys(files).length > 0 ? files : undefined,\n publish: isUsingGT && usingCDN,\n });\n\n logger.success(\n `Edit ${chalk.cyan(\n configFilepath\n )} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`\n );\n\n // Install gt if not installed\n const isCLIInstalled = packageJson\n ? isPackageInstalled('gt', packageJson, true, true)\n : true; // if no package.json, we can't install it\n\n if (!isCLIInstalled) {\n const packageManager = await getPackageManager();\n const spinner = logger.createSpinner();\n spinner.start(\n `Installing gt as a dev dependency with ${packageManager.name}...`\n );\n await installPackage('gt', packageManager, true);\n spinner.stop(chalk.green('Installed gt.'));\n }\n\n // Set credentials\n if (!areCredentialsSet()) {\n const loginQuestion = useDefaults\n ? true\n : await promptConfirm({\n message:\n 'Would you like the wizard to automatically generate API keys and a project ID for you?',\n defaultValue: true,\n });\n if (loginQuestion) {\n const settings = await generateSettings({});\n const keyType = useDefaults\n ? 'all'\n : await promptSelect<'development' | 'production' | 'all'>({\n message: 'What type of API key would you like to generate?',\n options: [\n { value: 'development', label: 'Development' },\n { value: 'production', label: 'Production' },\n { value: 'all', label: 'Both' },\n ],\n defaultValue: 'all',\n });\n const credentials = await retrieveCredentials(settings, keyType);\n await setCredentials(credentials, settings.framework);\n }\n }\n }\n protected async handleLoginCommand(options: LoginOptions): Promise<void> {\n const settings = await generateSettings({ config: options.config });\n const keyType = options.keyType || 'all';\n const credentials = await retrieveCredentials(settings, keyType);\n await setCredentials(credentials, settings.framework);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../src/cli/base.ts"],"sourcesContent":["import { Command } from 'commander';\nimport {\n DEFAULT_TRANSLATIONS_DIR,\n DEFAULT_VITE_TRANSLATIONS_DIR,\n} from '../utils/constants.js';\nimport { createOrUpdateConfig } from '../fs/config/setupConfig.js';\nimport findFilepath from '../fs/findFilepath.js';\nimport {\n displayHeader,\n promptText,\n logErrorAndExit,\n exitSync,\n promptConfirm,\n promptMultiSelect,\n promptSelect,\n promptGlobPatterns,\n} from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { parseGlobPatterns } from '../console/promptParsing.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport {\n FilesOptions,\n Settings,\n SupportedLibraries,\n SetupOptions,\n TranslateFlags,\n SharedFlags,\n} from '../types/index.js';\nimport { generateSettings } from '../config/generateSettings.js';\nimport chalk from 'chalk';\nimport { FILE_EXT_TO_EXT_LABEL } from '../formats/files/supportedFiles.js';\nimport { handleSetupReactCommand } from '../setup/wizard.js';\nimport {\n isPackageInstalled,\n searchForPackageJson,\n} from '../utils/packageJson.js';\nimport { getDesiredLocales } from '../setup/userInput.js';\nimport { installPackage } from '../utils/installPackage.js';\nimport { getPackageManager } from '../utils/packageManager.js';\nimport { retrieveCredentials, setCredentials } from '../utils/credentials.js';\nimport { areCredentialsSet } from '../utils/credentials.js';\nimport { upload } from './commands/upload.js';\nimport { attachSharedFlags, attachTranslateFlags } from './flags.js';\nimport { handleStage } from './commands/stage.js';\nimport { handleSetupProject } from './commands/setupProject.js';\nimport { handleDownload } from './commands/download.js';\nimport {\n handleTranslate,\n postProcessTranslations,\n} from './commands/translate.js';\nimport {\n getNeedsPostprocessing,\n clearDownloaded,\n} from '../state/recentDownloads.js';\nimport { clearWarnings } from '../state/translateWarnings.js';\nimport { displayTranslateSummary } from '../console/displayTranslateSummary.js';\nimport updateConfig from '../fs/config/updateConfig.js';\nimport { createLoadTranslationsFile } from '../fs/createLoadTranslationsFile.js';\nimport { saveLocalEdits } from '../api/saveLocalEdits.js';\nimport processSharedStaticAssets, {\n mirrorAssetsToLocales,\n} from '../utils/sharedStaticAssets.js';\nimport { setupLocadex } from '../locadex/setupFlow.js';\nimport { detectFramework } from '../setup/detectFramework.js';\nimport {\n getFrameworkDisplayName,\n getReactFrameworkLibrary,\n} from '../setup/frameworkUtils.js';\nimport { INLINE_LIBRARIES } from '../types/libraries.js';\nimport { handleEnqueue } from './commands/enqueue.js';\nimport { splitMintlifyLanguageRefs } from '../utils/splitMintlifyLanguageRefs.js';\nimport { runMergeDriver, type MergeDriverName } from '../git/mergeDrivers.js';\nimport { setupGitMergeDrivers } from '../git/setupMergeDrivers.js';\nimport { warnReactPackageCompatibility } from '../utils/reactPackageCompatibility.js';\n\nconst ID_COMPATIBILITY_WARNING_COMMANDS = new Set([\n 'download',\n 'enqueue',\n 'generate',\n 'setup',\n 'stage',\n 'translate',\n 'validate',\n]);\n\nexport type UploadOptions = {\n config?: string;\n apiKey?: string;\n projectId?: string;\n defaultLocale?: string;\n};\n\nexport type LoginOptions = {\n config?: string;\n keyType?: 'development' | 'production' | 'all';\n};\n\nexport type GitSetupOptions = {\n config?: string;\n dryRun?: boolean;\n omitConfigIds?: boolean;\n driverCommand?: string;\n};\n\nexport class BaseCLI {\n protected library: SupportedLibraries;\n protected additionalModules: SupportedLibraries[];\n protected program: Command;\n // Constructor is shared amongst all CLI class types\n public constructor(\n program: Command,\n library: SupportedLibraries,\n additionalModules?: SupportedLibraries[]\n ) {\n this.program = program;\n this.library = library;\n this.additionalModules = additionalModules || [];\n\n this.program.option(\n '--skip-version-check',\n 'Skip the monorepo GT package version consistency check'\n );\n this.program.option(\n '--suppress-id-compatibility-warning',\n 'Suppress the React package ID compatibility warning'\n );\n this.program.option(\n '-q, --quiet',\n 'Suppress informational output; only warnings and errors are shown'\n );\n // Apply --quiet before any other hook or command action runs so the\n // singleton logger is muted for the rest of the invocation. The flag is a\n // global root option, so commander resolves it in any position and for\n // nested commands (e.g. `gt git setup --quiet`).\n this.program.hook('preAction', () => {\n logger.setQuiet(Boolean(this.program.opts().quiet));\n });\n this.program.hook('preAction', async (thisCommand, actionCommand) => {\n // Nested commands (e.g. `gt git setup`) can share leaf names with\n // translation commands; only direct children of the root qualify\n if (actionCommand.parent !== thisCommand) return;\n if (!ID_COMPATIBILITY_WARNING_COMMANDS.has(actionCommand.name())) return;\n await warnReactPackageCompatibility(\n Boolean(this.program.opts().suppressIdCompatibilityWarning)\n );\n });\n\n this.setupInitCommand();\n this.setupConfigureCommand();\n this.setupUploadCommand();\n this.setupLoginCommand();\n this.setupSendDiffsCommand();\n this.setupGitCommand();\n }\n // Init is never called in a child class\n public init() {\n this.setupSetupProjectCommand();\n this.setupStageCommand();\n this.setupTranslateCommand();\n this.setupDownloadCommand();\n this.setupEnqueueCommand();\n }\n // Execute is called by the main program\n public execute() {\n // If no command is specified, run 'init'\n if (process.argv.length <= 2) {\n process.argv.push('init');\n }\n }\n\n protected setupSetupProjectCommand(): void {\n attachTranslateFlags(\n this.program\n .command('setup')\n .description(\n 'Upload source files and setup the project for translation'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Uploading source files and setting up project...');\n await this.handleSetupProject(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupStageCommand(): void {\n attachTranslateFlags(\n this.program\n .command('stage')\n .description(\n 'Submits the project to the General Translation API for translation. Translations created using this command will require human approval.'\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader(\n 'Staging project for translation with approval required...'\n );\n await this.handleStage(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupEnqueueCommand(): void {\n attachTranslateFlags(\n this.program\n .command('enqueue')\n .description('Enqueues translations for a given set of files')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Enqueuing translations...');\n await this.handleEnqueue(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected setupDownloadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('download')\n .description('Download translations that were originally staged')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Downloading translations...');\n await this.handleDownload(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupTranslateCommand(): void {\n attachTranslateFlags(\n this.program\n .command('translate')\n .description('Translate your project using General Translation')\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Starting translation...');\n await this.handleTranslate(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected setupSendDiffsCommand(): void {\n attachSharedFlags(\n this.program\n .command('save-local')\n .description(\n 'Save local edits for all configured files by sending diffs (no translation enqueued)'\n )\n )\n .option('--publish', 'Publish translations to the CDN', false)\n .action(async (initOptions: SharedFlags) => {\n displayHeader('Saving local edits...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await saveLocalEdits(settings);\n logger.endCommand('Saved local edits');\n });\n }\n\n protected setupGitCommand(): void {\n const gitCommand = this.program\n .command('git')\n .description('Configure Git integrations for General Translation');\n\n gitCommand\n .command('setup')\n .description('Set up GT merge drivers for generated translation files')\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .option('--dry-run', 'Print changes without writing files', false)\n .option(\n '--omit-config-ids',\n 'Persist omitConfigIds and remove generated config IDs'\n )\n .option(\n '--driver-command <command>',\n 'Command Git should use to invoke gt, e.g. \"pnpm exec gt\"'\n )\n .action(async (options: GitSetupOptions) => {\n displayHeader('Setting up GT Git merge drivers...');\n const settings = await generateSettings(options, undefined, {\n requireConfig: true,\n });\n const omitConfigIds = await this.resolveGitSetupOmitConfigIds(\n options,\n settings\n );\n const result = await setupGitMergeDrivers(settings, {\n dryRun: options.dryRun,\n omitConfigIds,\n driverCommand: options.driverCommand,\n });\n\n for (const line of result.addedAttributes) {\n logger.step(\n `${options.dryRun ? 'Would add' : 'Added'} ${chalk.cyan(\n line\n )} to ${chalk.cyan(result.gitattributesPath)}`\n );\n }\n if (result.addedAttributes.length === 0) {\n logger.info(`${chalk.cyan('.gitattributes')} is already configured.`);\n }\n\n for (const args of result.gitConfigCommands) {\n logger.step(\n `${options.dryRun ? 'Would run' : 'Configured'} ${chalk.cyan(\n `git config --local ${args.join(' ')}`\n )}`\n );\n }\n\n if (result.updatedConfig) {\n logger.step(\n `${options.dryRun ? 'Would persist' : 'Persisted'} ${chalk.cyan(\n 'omitConfigIds: true'\n )} in ${chalk.cyan(settings.config)}`\n );\n } else if (options.dryRun && !settings.omitConfigIds) {\n logger.info(\n `Run without ${chalk.cyan('--dry-run')} to be prompted to persist ${chalk.cyan(\n 'omitConfigIds: true'\n )}, or pass ${chalk.cyan('--omit-config-ids')}.`\n );\n }\n\n for (const warning of result.warnings) {\n logger.warn(chalk.yellow(warning));\n }\n\n logger.endCommand(\n options.dryRun\n ? 'Dry run complete.'\n : 'GT Git merge drivers configured.'\n );\n });\n\n gitCommand\n .command('merge-driver', { hidden: true })\n .argument('<driver>', 'Merge driver name')\n .argument('<base>', 'Common ancestor file')\n .argument('<ours>', 'Current branch file')\n .argument('<theirs>', 'Incoming branch file')\n .argument('[path]', 'Merged path')\n .action((driver: string, base: string, ours: string, theirs: string) => {\n if (driver !== 'gt-lock' && driver !== 'gtjson') {\n logger.error(`Unknown GT merge driver: ${driver}`);\n exitSync(1);\n }\n const result = runMergeDriver(\n driver as MergeDriverName,\n base,\n ours,\n theirs\n );\n if (!result.ok) {\n logger.error(result.reason);\n exitSync(1);\n }\n });\n }\n\n protected async resolveGitSetupOmitConfigIds(\n options: GitSetupOptions,\n settings: Settings\n ): Promise<boolean> {\n if (options.omitConfigIds) return true;\n // Already opted in: persist again so stale config IDs still get removed\n if (settings.omitConfigIds) return true;\n if (options.dryRun || !process.stdin.isTTY || !process.stdout.isTTY) {\n return false;\n }\n return promptConfirm({\n message:\n 'Also set omitConfigIds: true to reduce gt.config.json merge conflicts?',\n defaultValue: true,\n });\n }\n\n protected async handleSetupProject(\n initOptions: TranslateFlags\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n await handleSetupProject(initOptions, settings, this.library);\n }\n\n protected async handleStage(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n // Update settings.stageTranslations to true\n settings.stageTranslations = true;\n await updateConfig(settings.config, {\n stageTranslations: true,\n });\n }\n await handleStage(initOptions, settings, this.library, true);\n }\n\n /**\n * Enqueues translations for a given set of files\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleEnqueue(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleEnqueue(initOptions, settings, this.library);\n }\n\n /**\n * Downloads translations that were originally staged\n * @param initOptions - The options for the command\n * @returns The results of the command\n */\n protected async handleDownload(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n await handleDownload(initOptions, settings, this.library);\n }\n\n protected async handleTranslate(initOptions: TranslateFlags): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // Preprocess shared static assets if configured (move + rewrite sources)\n await processSharedStaticAssets(settings);\n\n if (!settings.stageTranslations) {\n const results = await handleStage(\n initOptions,\n settings,\n this.library,\n false\n );\n if (results) {\n await handleTranslate(\n initOptions,\n settings,\n results.fileVersionData,\n results.jobData,\n results.branchData,\n results.publishMap\n );\n }\n } else {\n await handleDownload(initOptions, settings, this.library);\n }\n // Only postprocess files downloaded in this run\n const include = getNeedsPostprocessing();\n if (include.size > 0) {\n await postProcessTranslations(settings, include);\n }\n // Split Mintlify language entries into $ref files to keep docs.json small\n await splitMintlifyLanguageRefs(settings);\n // Mirror assets after translations are downloaded and locale dirs are populated\n await mirrorAssetsToLocales(settings);\n clearDownloaded();\n displayTranslateSummary();\n clearWarnings();\n }\n\n protected setupUploadCommand(): void {\n attachTranslateFlags(\n this.program\n .command('upload')\n .description(\n 'Upload source files and translations to the General Translation platform'\n )\n ).action(async (initOptions: UploadOptions) => {\n displayHeader('Starting upload...');\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n const options = { ...initOptions, ...settings };\n\n await this.handleUploadCommand(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupLoginCommand(): void {\n this.program\n .command('auth')\n .description('Generate General Translation API keys and project ID')\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .option(\n '-t, --key-type <type>',\n 'Type of key to generate, production | development | all'\n )\n .action(async (options: LoginOptions) => {\n displayHeader('Authenticating with General Translation...');\n if (!options.keyType) {\n options.keyType = await promptSelect<\n 'development' | 'production' | 'all'\n >({\n message: 'What type of API key would you like to generate?',\n options: [\n { value: 'development', label: 'Development' },\n { value: 'production', label: 'Production' },\n { value: 'all', label: 'Both' },\n ],\n defaultValue: 'all',\n });\n } else {\n if (\n options.keyType !== 'development' &&\n options.keyType !== 'production' &&\n options.keyType !== 'all'\n ) {\n logErrorAndExit(\n 'Invalid key type, must be development, production, or all'\n );\n }\n }\n await this.handleLoginCommand(options);\n logger.endCommand(\n `Done! ${options.keyType} keys have been generated and saved to your .env.local file.`\n );\n });\n }\n\n protected setupInitCommand(): void {\n this.program\n .command('init')\n .description(\n 'Run the setup wizard to configure your project for General Translation'\n )\n .option(\n '--src <paths...>',\n \"Space-separated list of glob patterns containing the app's source code, by default 'src/**/*.{js,jsx,ts,tsx}' 'app/**/*.{js,jsx,ts,tsx}' 'pages/**/*.{js,jsx,ts,tsx}' 'components/**/*.{js,jsx,ts,tsx}'\"\n )\n .option(\n '-c, --config <path>',\n 'Filepath to config file, by default gt.config.json',\n findFilepath(['gt.config.json'])\n )\n .action(async (options: SetupOptions) => {\n const settings = await generateSettings(options);\n displayHeader('Running setup wizard...');\n\n const framework = await detectFramework();\n\n const useAgent = await (async () => {\n let useAgentMessage;\n if (framework.name === 'mintlify') {\n useAgentMessage = `Mintlify project detected. Would you like to connect to GitHub so that the Locadex AI Agent can translate your project automatically?`;\n }\n if (framework.name === 'next-app') {\n useAgentMessage = `Next.js App Router detected. Would you like to connect to GitHub so that the Locadex AI Agent can set up your project automatically?`;\n }\n if (useAgentMessage) {\n return await promptConfirm({\n message: useAgentMessage,\n defaultValue: false,\n });\n }\n return false;\n })();\n\n if (useAgent) {\n await setupLocadex(settings);\n logger.endCommand(\n 'Once installed, Locadex will open a PR to your repository. See the docs for more information: https://generaltranslation.com/docs/locadex'\n );\n } else {\n // Get framework display info for the defaults message\n const frameworkDisplayName =\n framework.type === 'react'\n ? getFrameworkDisplayName(framework)\n : null;\n const library =\n framework.type === 'react'\n ? getReactFrameworkLibrary(framework)\n : null;\n\n // Build defaults description based on detected framework\n const defaultTranslationsDir =\n framework.name === 'vite'\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n const defaultsDescription =\n framework.type === 'react'\n ? `${library} & GTProvider, ${frameworkDisplayName}, Files saved locally in ${defaultTranslationsDir}`\n : `Files saved locally in ${defaultTranslationsDir}`;\n\n // Ask if user wants to use defaults\n const useDefaults = await promptConfirm({\n message: `Would you like to use the recommended General Translation defaults? ${chalk.dim(`(${defaultsDescription})`)}`,\n defaultValue: true,\n });\n\n let ranReactSetup = false;\n\n // so that people can run init in non-js projects\n if (framework.type === 'react') {\n const wrap = useDefaults\n ? true\n : await promptConfirm({\n message: `Would you like to install ${library} and add the GTProvider? See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`,\n defaultValue: true,\n });\n\n if (wrap) {\n logger.info(\n `${chalk.yellow('[EXPERIMENTAL]')} Configuring project...`\n );\n await handleSetupReactCommand(options, framework, useDefaults);\n logger.endCommand(\n `Done! Since this wizard is experimental, please review the changes and make modifications as needed.\n\\nNext step: start internationalizing! See the docs for more information: https://generaltranslation.com/docs/react/tutorials/quickstart`\n );\n ranReactSetup = true;\n }\n }\n\n if (ranReactSetup) {\n logger.startCommand('Setting up project config...');\n }\n // Configure gt.config.json\n await this.handleInitCommand(\n ranReactSetup,\n useDefaults,\n framework.name === 'vite'\n );\n\n logger.endCommand(\n 'Done! Check out our docs for more information on how to use General Translation: https://generaltranslation.com/docs'\n );\n }\n });\n }\n\n protected setupConfigureCommand(): void {\n this.program\n .command('configure')\n .description(\n 'Configure your project for General Translation. This will create a gt.config.json file in your codebase.'\n )\n .action(async () => {\n displayHeader('Configuring project...');\n\n logger.info(\n 'Welcome! This tool will help you configure your gt.config.json file. See the docs: https://generaltranslation.com/docs/cli/reference/config for more information.'\n );\n\n // Configure gt.config.json\n const framework = await detectFramework();\n await this.handleInitCommand(false, false, framework.name === 'vite');\n\n logger.endCommand(\n 'Done! Make sure you have an API key and project ID to use General Translation. Get them on the dashboard: https://generaltranslation.com/dashboard'\n );\n });\n }\n\n protected async handleUploadCommand(\n settings: Settings & UploadOptions\n ): Promise<void> {\n if (!settings.files) {\n return;\n }\n\n // Process all file types at once with a single call\n await upload(settings);\n }\n\n // Wizard for configuring gt.config.json\n protected async handleInitCommand(\n ranReactSetup: boolean,\n useDefaults: boolean = false,\n isVite: boolean = false\n ): Promise<void> {\n const { defaultLocale, locales } = await getDesiredLocales(); // Locales should still be asked for even if using defaults\n\n const packageJson = await searchForPackageJson();\n\n // Ask if using another i18n library\n const gtInstalled =\n !!packageJson &&\n INLINE_LIBRARIES.some((lib) => isPackageInstalled(lib, packageJson));\n const isUsingGT = ranReactSetup || gtInstalled;\n\n // Ask where the translations are stored\n const usingCDN = await (async () => {\n if (!isUsingGT) return false;\n if (useDefaults) return false; // Default to local\n const selectedValue = await promptSelect({\n message: `Would you like to save translation files locally or use the General Translation CDN to store them?`,\n options: [\n { value: 'local', label: 'Save locally' },\n { value: 'cdn', label: 'Use CDN' },\n ],\n defaultValue: 'local',\n });\n return selectedValue === 'cdn';\n })();\n\n const defaultTranslationsDir = isVite\n ? DEFAULT_VITE_TRANSLATIONS_DIR\n : DEFAULT_TRANSLATIONS_DIR;\n\n // Ask where the translations are stored\n const translationsDir =\n isUsingGT && !usingCDN\n ? useDefaults\n ? defaultTranslationsDir\n : await promptText({\n message:\n 'What is the path to the directory where you would like to store your translation files?',\n defaultValue: defaultTranslationsDir,\n })\n : null;\n\n // Determine final translations directory with fallback\n const finalTranslationsDir =\n translationsDir?.trim() || defaultTranslationsDir;\n\n if (isUsingGT && !usingCDN) {\n // Create loadTranslations.js file for local translations\n await createLoadTranslationsFile(\n process.cwd(),\n finalTranslationsDir,\n locales\n );\n logger.message(\n `Created ${chalk.cyan('loadTranslations.js')} file for local translations.\nMake sure to add this function to your app configuration.\nSee https://generaltranslation.com/en/docs/next/guides/local-tx`\n );\n }\n\n const message = !isUsingGT\n ? 'What is the format of your language resource files? Select as many as applicable.\\nAdditionally, you can translate any other files you have in your project.'\n : `Do you have any additional files in this project to translate? For example, Markdown files for docs. ${chalk.dim(\n '(To continue without selecting press Enter)'\n )}`;\n const fileExtensions =\n useDefaults && isUsingGT\n ? [] // Skip for GT projects when using defaults\n : await promptMultiSelect({\n message,\n options: [\n { value: 'json', label: FILE_EXT_TO_EXT_LABEL.json },\n { value: 'md', label: FILE_EXT_TO_EXT_LABEL.md },\n { value: 'mdx', label: FILE_EXT_TO_EXT_LABEL.mdx },\n { value: 'ts', label: FILE_EXT_TO_EXT_LABEL.ts },\n { value: 'js', label: FILE_EXT_TO_EXT_LABEL.js },\n { value: 'yaml', label: FILE_EXT_TO_EXT_LABEL.yaml },\n // TWILIO_CONTENT_JSON not supported in CLI init as its too niche\n ],\n required: !isUsingGT,\n });\n\n const files: FilesOptions = {};\n for (const fileExtension of fileExtensions) {\n const label = FILE_EXT_TO_EXT_LABEL[fileExtension];\n const paths = await promptGlobPatterns({\n label,\n message: `${chalk.cyan(FILE_EXT_TO_EXT_LABEL[fileExtension])}: Enter a space-separated list of glob patterns matching the location of the ${FILE_EXT_TO_EXT_LABEL[fileExtension]} files you would like to translate.\\nMake sure to include [locale] in the patterns.\\nSee https://generaltranslation.com/docs/cli/reference/config#include for more information.`,\n defaultValue: `./**/[locale]/*.${fileExtension}`,\n });\n\n files[fileExtension] = {\n include: parseGlobPatterns(paths),\n };\n }\n\n // Add GT translations if using GT and storing locally\n if (isUsingGT && !usingCDN) {\n files.gt = {\n output: path.join(finalTranslationsDir, `[locale].json`),\n };\n }\n\n let configFilepath = 'gt.config.json';\n if (fs.existsSync('src/gt.config.json')) {\n configFilepath = 'src/gt.config.json';\n }\n\n // Create gt.config.json\n await createOrUpdateConfig(configFilepath, {\n defaultLocale,\n locales,\n files: Object.keys(files).length > 0 ? files : undefined,\n publish: isUsingGT && usingCDN,\n });\n\n logger.success(\n `Edit ${chalk.cyan(\n configFilepath\n )} to customize your translation setup. Docs: https://generaltranslation.com/docs/cli/reference/config`\n );\n\n // Install gt if not installed\n const isCLIInstalled = packageJson\n ? isPackageInstalled('gt', packageJson, true, true)\n : true; // if no package.json, we can't install it\n\n if (!isCLIInstalled) {\n const packageManager = await getPackageManager();\n const spinner = logger.createSpinner();\n spinner.start(\n `Installing gt as a dev dependency with ${packageManager.name}...`\n );\n await installPackage('gt', packageManager, true);\n spinner.stop(chalk.green('Installed gt.'));\n }\n\n // Set credentials\n if (!areCredentialsSet()) {\n const loginQuestion = useDefaults\n ? true\n : await promptConfirm({\n message:\n 'Would you like the wizard to automatically generate API keys and a project ID for you?',\n defaultValue: true,\n });\n if (loginQuestion) {\n const settings = await generateSettings({});\n const keyType = useDefaults\n ? 'all'\n : await promptSelect<'development' | 'production' | 'all'>({\n message: 'What type of API key would you like to generate?',\n options: [\n { value: 'development', label: 'Development' },\n { value: 'production', label: 'Production' },\n { value: 'all', label: 'Both' },\n ],\n defaultValue: 'all',\n });\n const credentials = await retrieveCredentials(settings, keyType);\n await setCredentials(credentials, settings.framework);\n }\n }\n }\n protected async handleLoginCommand(options: LoginOptions): Promise<void> {\n const settings = await generateSettings({ config: options.config });\n const keyType = options.keyType || 'all';\n const credentials = await retrieveCredentials(settings, keyType);\n await setCredentials(credentials, settings.framework);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4EA,MAAM,oCAAoC,IAAI,IAAI;CAChD;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAqBF,IAAa,UAAb,MAAqB;CACnB;CACA;CACA;CAEA,YACE,SACA,SACA,mBACA;AACA,OAAK,UAAU;AACf,OAAK,UAAU;AACf,OAAK,oBAAoB,qBAAqB,EAAE;AAEhD,OAAK,QAAQ,OACX,wBACA,yDACD;AACD,OAAK,QAAQ,OACX,uCACA,sDACD;AACD,OAAK,QAAQ,OACX,eACA,oEACD;AAKD,OAAK,QAAQ,KAAK,mBAAmB;AACnC,UAAO,SAAS,QAAQ,KAAK,QAAQ,MAAM,CAAC,MAAM,CAAC;IACnD;AACF,OAAK,QAAQ,KAAK,aAAa,OAAO,aAAa,kBAAkB;AAGnE,OAAI,cAAc,WAAW,YAAa;AAC1C,OAAI,CAAC,kCAAkC,IAAI,cAAc,MAAM,CAAC,CAAE;AAClE,SAAM,8BACJ,QAAQ,KAAK,QAAQ,MAAM,CAAC,+BAA+B,CAC5D;IACD;AAEF,OAAK,kBAAkB;AACvB,OAAK,uBAAuB;AAC5B,OAAK,oBAAoB;AACzB,OAAK,mBAAmB;AACxB,OAAK,uBAAuB;AAC5B,OAAK,iBAAiB;;CAGxB,OAAc;AACZ,OAAK,0BAA0B;AAC/B,OAAK,mBAAmB;AACxB,OAAK,uBAAuB;AAC5B,OAAK,sBAAsB;AAC3B,OAAK,qBAAqB;;CAG5B,UAAiB;AAEf,MAAI,QAAQ,KAAK,UAAU,EACzB,SAAQ,KAAK,KAAK,OAAO;;CAI7B,2BAA2C;AACzC,uBACE,KAAK,QACF,QAAQ,QAAQ,CAChB,YACC,4DACD,CACJ,CAAC,OAAO,OAAO,gBAAgC;AAC9C,iBAAc,mDAAmD;AACjE,SAAM,KAAK,mBAAmB,YAAY;AAC1C,UAAO,WAAW,QAAQ;IAC1B;;CAGJ,oBAAoC;AAClC,uBACE,KAAK,QACF,QAAQ,QAAQ,CAChB,YACC,2IACD,CACJ,CAAC,OAAO,OAAO,gBAAgC;AAC9C,iBACE,4DACD;AACD,SAAM,KAAK,YAAY,YAAY;AACnC,UAAO,WAAW,QAAQ;IAC1B;;;;;;;CAQJ,sBAAsC;AACpC,uBACE,KAAK,QACF,QAAQ,UAAU,CAClB,YAAY,iDAAiD,CACjE,CAAC,OAAO,OAAO,gBAAgC;AAC9C,iBAAc,4BAA4B;AAC1C,SAAM,KAAK,cAAc,YAAY;AACrC,UAAO,WAAW,QAAQ;IAC1B;;;;;;;CAQJ,uBAAuC;AACrC,uBACE,KAAK,QACF,QAAQ,WAAW,CACnB,YAAY,oDAAoD,CACpE,CAAC,OAAO,OAAO,gBAAgC;AAC9C,iBAAc,8BAA8B;AAC5C,SAAM,KAAK,eAAe,YAAY;AACtC,UAAO,WAAW,QAAQ;IAC1B;;CAGJ,wBAAwC;AACtC,uBACE,KAAK,QACF,QAAQ,YAAY,CACpB,YAAY,mDAAmD,CACnE,CAAC,OAAO,OAAO,gBAAgC;AAC9C,iBAAc,0BAA0B;AACxC,SAAM,KAAK,gBAAgB,YAAY;AACvC,UAAO,WAAW,QAAQ;IAC1B;;CAGJ,wBAAwC;AACtC,oBACE,KAAK,QACF,QAAQ,aAAa,CACrB,YACC,uFACD,CACJ,CACE,OAAO,aAAa,mCAAmC,MAAM,CAC7D,OAAO,OAAO,gBAA6B;AAC1C,iBAAc,wBAAwB;AAItC,SAAM,eAAe,MAHE,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC,CAC4B;AAC9B,UAAO,WAAW,oBAAoB;IACtC;;CAGN,kBAAkC;EAChC,MAAM,aAAa,KAAK,QACrB,QAAQ,MAAM,CACd,YAAY,qDAAqD;AAEpE,aACG,QAAQ,QAAQ,CAChB,YAAY,0DAA0D,CACtE,OACC,uBACA,sDACA,aAAa,CAAC,iBAAiB,CAAC,CACjC,CACA,OAAO,aAAa,uCAAuC,MAAM,CACjE,OACC,qBACA,wDACD,CACA,OACC,8BACA,6DACD,CACA,OAAO,OAAO,YAA6B;AAC1C,iBAAc,qCAAqC;GACnD,MAAM,WAAW,MAAM,iBAAiB,SAAS,KAAA,GAAW,EAC1D,eAAe,MAChB,CAAC;GACF,MAAM,gBAAgB,MAAM,KAAK,6BAC/B,SACA,SACD;GACD,MAAM,SAAS,MAAM,qBAAqB,UAAU;IAClD,QAAQ,QAAQ;IAChB;IACA,eAAe,QAAQ;IACxB,CAAC;AAEF,QAAK,MAAM,QAAQ,OAAO,gBACxB,QAAO,KACL,GAAG,QAAQ,SAAS,cAAc,QAAQ,GAAG,MAAM,KACjD,KACD,CAAC,MAAM,MAAM,KAAK,OAAO,kBAAkB,GAC7C;AAEH,OAAI,OAAO,gBAAgB,WAAW,EACpC,QAAO,KAAK,GAAG,MAAM,KAAK,iBAAiB,CAAC,yBAAyB;AAGvE,QAAK,MAAM,QAAQ,OAAO,kBACxB,QAAO,KACL,GAAG,QAAQ,SAAS,cAAc,aAAa,GAAG,MAAM,KACtD,sBAAsB,KAAK,KAAK,IAAI,GACrC,GACF;AAGH,OAAI,OAAO,cACT,QAAO,KACL,GAAG,QAAQ,SAAS,kBAAkB,YAAY,GAAG,MAAM,KACzD,sBACD,CAAC,MAAM,MAAM,KAAK,SAAS,OAAO,GACpC;YACQ,QAAQ,UAAU,CAAC,SAAS,cACrC,QAAO,KACL,eAAe,MAAM,KAAK,YAAY,CAAC,6BAA6B,MAAM,KACxE,sBACD,CAAC,YAAY,MAAM,KAAK,oBAAoB,CAAC,GAC/C;AAGH,QAAK,MAAM,WAAW,OAAO,SAC3B,QAAO,KAAK,MAAM,OAAO,QAAQ,CAAC;AAGpC,UAAO,WACL,QAAQ,SACJ,sBACA,mCACL;IACD;AAEJ,aACG,QAAQ,gBAAgB,EAAE,QAAQ,MAAM,CAAC,CACzC,SAAS,YAAY,oBAAoB,CACzC,SAAS,UAAU,uBAAuB,CAC1C,SAAS,UAAU,sBAAsB,CACzC,SAAS,YAAY,uBAAuB,CAC5C,SAAS,UAAU,cAAc,CACjC,QAAQ,QAAgB,MAAc,MAAc,WAAmB;AACtE,OAAI,WAAW,aAAa,WAAW,UAAU;AAC/C,WAAO,MAAM,4BAA4B,SAAS;AAClD,aAAS,EAAE;;GAEb,MAAM,SAAS,eACb,QACA,MACA,MACA,OACD;AACD,OAAI,CAAC,OAAO,IAAI;AACd,WAAO,MAAM,OAAO,OAAO;AAC3B,aAAS,EAAE;;IAEb;;CAGN,MAAgB,6BACd,SACA,UACkB;AAClB,MAAI,QAAQ,cAAe,QAAO;AAElC,MAAI,SAAS,cAAe,QAAO;AACnC,MAAI,QAAQ,UAAU,CAAC,QAAQ,MAAM,SAAS,CAAC,QAAQ,OAAO,MAC5D,QAAO;AAET,SAAO,cAAc;GACnB,SACE;GACF,cAAc;GACf,CAAC;;CAGJ,MAAgB,mBACd,aACe;EACf,MAAM,WAAW,MAAM,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC;AAGF,QAAM,0BAA0B,SAAS;AAEzC,QAAM,mBAAmB,aAAa,UAAU,KAAK,QAAQ;;CAG/D,MAAgB,YAAY,aAA4C;EACtE,MAAM,WAAW,MAAM,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC;AAGF,QAAM,0BAA0B,SAAS;AAEzC,MAAI,CAAC,SAAS,mBAAmB;AAE/B,YAAS,oBAAoB;AAC7B,SAAM,aAAa,SAAS,QAAQ,EAClC,mBAAmB,MACpB,CAAC;;AAEJ,QAAM,YAAY,aAAa,UAAU,KAAK,SAAS,KAAK;;;;;;;CAQ9D,MAAgB,cAAc,aAA4C;AAIxE,QAAM,cAAc,aAAa,MAHV,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC,EACyC,KAAK,QAAQ;;;;;;;CAQ1D,MAAgB,eAAe,aAA4C;AAIzE,QAAM,eAAe,aAAa,MAHX,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC,EAC0C,KAAK,QAAQ;;CAG3D,MAAgB,gBAAgB,aAA4C;EAC1E,MAAM,WAAW,MAAM,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC;AAGF,QAAM,0BAA0B,SAAS;AAEzC,MAAI,CAAC,SAAS,mBAAmB;GAC/B,MAAM,UAAU,MAAM,YACpB,aACA,UACA,KAAK,SACL,MACD;AACD,OAAI,QACF,OAAM,gBACJ,aACA,UACA,QAAQ,iBACR,QAAQ,SACR,QAAQ,YACR,QAAQ,WACT;QAGH,OAAM,eAAe,aAAa,UAAU,KAAK,QAAQ;EAG3D,MAAM,UAAU,wBAAwB;AACxC,MAAI,QAAQ,OAAO,EACjB,OAAM,wBAAwB,UAAU,QAAQ;AAGlD,QAAM,0BAA0B,SAAS;AAEzC,QAAM,sBAAsB,SAAS;AACrC,mBAAiB;AACjB,2BAAyB;AACzB,iBAAe;;CAGjB,qBAAqC;AACnC,uBACE,KAAK,QACF,QAAQ,SAAS,CACjB,YACC,2EACD,CACJ,CAAC,OAAO,OAAO,gBAA+B;AAC7C,iBAAc,qBAAqB;GACnC,MAAM,WAAW,MAAM,iBAAiB,aAAa,KAAA,GAAW,EAC9D,eAAe,MAChB,CAAC;GAEF,MAAM,UAAU;IAAE,GAAG;IAAa,GAAG;IAAU;AAE/C,SAAM,KAAK,oBAAoB,QAAQ;AACvC,UAAO,WAAW,QAAQ;IAC1B;;CAGJ,oBAAoC;AAClC,OAAK,QACF,QAAQ,OAAO,CACf,YAAY,uDAAuD,CACnE,OACC,uBACA,sDACA,aAAa,CAAC,iBAAiB,CAAC,CACjC,CACA,OACC,yBACA,0DACD,CACA,OAAO,OAAO,YAA0B;AACvC,iBAAc,6CAA6C;AAC3D,OAAI,CAAC,QAAQ,QACX,SAAQ,UAAU,MAAM,aAEtB;IACA,SAAS;IACT,SAAS;KACP;MAAE,OAAO;MAAe,OAAO;MAAe;KAC9C;MAAE,OAAO;MAAc,OAAO;MAAc;KAC5C;MAAE,OAAO;MAAO,OAAO;MAAQ;KAChC;IACD,cAAc;IACf,CAAC;YAGA,QAAQ,YAAY,iBACpB,QAAQ,YAAY,gBACpB,QAAQ,YAAY,MAEpB,iBACE,4DACD;AAGL,SAAM,KAAK,mBAAmB,QAAQ;AACtC,UAAO,WACL,SAAS,QAAQ,QAAQ,8DAC1B;IACD;;CAGN,mBAAmC;AACjC,OAAK,QACF,QAAQ,OAAO,CACf,YACC,yEACD,CACA,OACC,oBACA,0MACD,CACA,OACC,uBACA,sDACA,aAAa,CAAC,iBAAiB,CAAC,CACjC,CACA,OAAO,OAAO,YAA0B;GACvC,MAAM,WAAW,MAAM,iBAAiB,QAAQ;AAChD,iBAAc,0BAA0B;GAExC,MAAM,YAAY,MAAM,iBAAiB;AAmBzC,OAAI,OAjBoB,YAAY;IAClC,IAAI;AACJ,QAAI,UAAU,SAAS,WACrB,mBAAkB;AAEpB,QAAI,UAAU,SAAS,WACrB,mBAAkB;AAEpB,QAAI,gBACF,QAAO,MAAM,cAAc;KACzB,SAAS;KACT,cAAc;KACf,CAAC;AAEJ,WAAO;OACL,EAEU;AACZ,UAAM,aAAa,SAAS;AAC5B,WAAO,WACL,4IACD;UACI;IAEL,MAAM,uBACJ,UAAU,SAAS,UACf,wBAAwB,UAAU,GAClC;IACN,MAAM,UACJ,UAAU,SAAS,UACf,yBAAyB,UAAU,GACnC;IAGN,MAAM,yBACJ,UAAU,SAAS,SACf,gCACA;IAEN,MAAM,sBACJ,UAAU,SAAS,UACf,GAAG,QAAQ,iBAAiB,qBAAqB,2BAA2B,2BAC5E,0BAA0B;IAGhC,MAAM,cAAc,MAAM,cAAc;KACtC,SAAS,uEAAuE,MAAM,IAAI,IAAI,oBAAoB,GAAG;KACrH,cAAc;KACf,CAAC;IAEF,IAAI,gBAAgB;AAGpB,QAAI,UAAU,SAAS;SACR,cACT,OACA,MAAM,cAAc;MAClB,SAAS,6BAA6B,QAAQ;MAC9C,cAAc;MACf,CAAC,EAEI;AACR,aAAO,KACL,GAAG,MAAM,OAAO,iBAAiB,CAAC,yBACnC;AACD,YAAM,wBAAwB,SAAS,WAAW,YAAY;AAC9D,aAAO,WACL;0IAED;AACD,sBAAgB;;;AAIpB,QAAI,cACF,QAAO,aAAa,+BAA+B;AAGrD,UAAM,KAAK,kBACT,eACA,aACA,UAAU,SAAS,OACpB;AAED,WAAO,WACL,uHACD;;IAEH;;CAGN,wBAAwC;AACtC,OAAK,QACF,QAAQ,YAAY,CACpB,YACC,2GACD,CACA,OAAO,YAAY;AAClB,iBAAc,yBAAyB;AAEvC,UAAO,KACL,oKACD;GAGD,MAAM,YAAY,MAAM,iBAAiB;AACzC,SAAM,KAAK,kBAAkB,OAAO,OAAO,UAAU,SAAS,OAAO;AAErE,UAAO,WACL,qJACD;IACD;;CAGN,MAAgB,oBACd,UACe;AACf,MAAI,CAAC,SAAS,MACZ;AAIF,QAAM,OAAO,SAAS;;CAIxB,MAAgB,kBACd,eACA,cAAuB,OACvB,SAAkB,OACH;EACf,MAAM,EAAE,eAAe,YAAY,MAAM,mBAAmB;EAE5D,MAAM,cAAc,MAAM,sBAAsB;EAGhD,MAAM,cACJ,CAAC,CAAC,eACF,iBAAiB,MAAM,QAAQ,mBAAmB,KAAK,YAAY,CAAC;EACtE,MAAM,YAAY,iBAAiB;EAGnC,MAAM,WAAW,OAAO,YAAY;AAClC,OAAI,CAAC,UAAW,QAAO;AACvB,OAAI,YAAa,QAAO;AASxB,UAAO,MARqB,aAAa;IACvC,SAAS;IACT,SAAS,CACP;KAAE,OAAO;KAAS,OAAO;KAAgB,EACzC;KAAE,OAAO;KAAO,OAAO;KAAW,CACnC;IACD,cAAc;IACf,CAAC,KACuB;MACvB;EAEJ,MAAM,yBAAyB,SAC3B,gCACA;EAeJ,MAAM,wBAXJ,aAAa,CAAC,WACV,cACE,yBACA,MAAM,WAAW;GACf,SACE;GACF,cAAc;GACf,CAAC,GACJ,OAIa,MAAM,IAAI;AAE7B,MAAI,aAAa,CAAC,UAAU;AAE1B,SAAM,2BACJ,QAAQ,KAAK,EACb,sBACA,QACD;AACD,UAAO,QACL,WAAW,MAAM,KAAK,sBAAsB,CAAC;;iEAG9C;;EAGH,MAAM,UAAU,CAAC,YACb,iKACA,wGAAwG,MAAM,IAC5G,8CACD;EACL,MAAM,iBACJ,eAAe,YACX,EAAE,GACF,MAAM,kBAAkB;GACtB;GACA,SAAS;IACP;KAAE,OAAO;KAAQ,OAAO,sBAAsB;KAAM;IACpD;KAAE,OAAO;KAAM,OAAO,sBAAsB;KAAI;IAChD;KAAE,OAAO;KAAO,OAAO,sBAAsB;KAAK;IAClD;KAAE,OAAO;KAAM,OAAO,sBAAsB;KAAI;IAChD;KAAE,OAAO;KAAM,OAAO,sBAAsB;KAAI;IAChD;KAAE,OAAO;KAAQ,OAAO,sBAAsB;KAAM;IAErD;GACD,UAAU,CAAC;GACZ,CAAC;EAER,MAAM,QAAsB,EAAE;AAC9B,OAAK,MAAM,iBAAiB,gBAAgB;GAC1C,MAAM,QAAQ,sBAAsB;AAOpC,SAAM,iBAAiB,EACrB,SAAS,kBAAkB,MAPT,mBAAmB;IACrC;IACA,SAAS,GAAG,MAAM,KAAK,sBAAsB,eAAe,CAAC,+EAA+E,sBAAsB,eAAe;IACjL,cAAc,mBAAmB;IAClC,CAAC,CAGiC,EAClC;;AAIH,MAAI,aAAa,CAAC,SAChB,OAAM,KAAK,EACT,QAAQ,KAAK,KAAK,sBAAsB,gBAAgB,EACzD;EAGH,IAAI,iBAAiB;AACrB,MAAI,GAAG,WAAW,qBAAqB,CACrC,kBAAiB;AAInB,QAAM,qBAAqB,gBAAgB;GACzC;GACA;GACA,OAAO,OAAO,KAAK,MAAM,CAAC,SAAS,IAAI,QAAQ,KAAA;GAC/C,SAAS,aAAa;GACvB,CAAC;AAEF,SAAO,QACL,QAAQ,MAAM,KACZ,eACD,CAAC,sGACH;AAOD,MAAI,EAJmB,cACnB,mBAAmB,MAAM,aAAa,MAAM,KAAK,GACjD,OAEiB;GACnB,MAAM,iBAAiB,MAAM,mBAAmB;GAChD,MAAM,UAAU,OAAO,eAAe;AACtC,WAAQ,MACN,0CAA0C,eAAe,KAAK,KAC/D;AACD,SAAM,eAAe,MAAM,gBAAgB,KAAK;AAChD,WAAQ,KAAK,MAAM,MAAM,gBAAgB,CAAC;;AAI5C,MAAI,CAAC,mBAAmB;OACA,cAClB,OACA,MAAM,cAAc;IAClB,SACE;IACF,cAAc;IACf,CAAC,EACa;IACjB,MAAM,WAAW,MAAM,iBAAiB,EAAE,CAAC;AAa3C,UAAM,eAAe,MADK,oBAAoB,UAX9B,cACZ,QACA,MAAM,aAAmD;KACvD,SAAS;KACT,SAAS;MACP;OAAE,OAAO;OAAe,OAAO;OAAe;MAC9C;OAAE,OAAO;OAAc,OAAO;OAAc;MAC5C;OAAE,OAAO;OAAO,OAAO;OAAQ;MAChC;KACD,cAAc;KACf,CAAC,CAC0D,EAC9B,SAAS,UAAU;;;;CAI3D,MAAgB,mBAAmB,SAAsC;EACvE,MAAM,WAAW,MAAM,iBAAiB,EAAE,QAAQ,QAAQ,QAAQ,CAAC;AAGnE,QAAM,eAAe,MADK,oBAAoB,UAD9B,QAAQ,WAAW,MAC6B,EAC9B,SAAS,UAAU"}
@@ -10,8 +10,6 @@ import { attachInlineTranslateFlags, attachTranslateFlags, attachValidateFlags }
10
10
  import { aggregateInlineTranslations } from "../translation/stage.js";
11
11
  import { BaseCLI } from "./base.js";
12
12
  import { saveJSON } from "../fs/saveJSON.js";
13
- import { intro } from "@clack/prompts";
14
- import chalk from "chalk";
15
13
  //#region src/cli/inline.ts
16
14
  /**
17
15
  * Stand in for a CLI tool that does any sort of inline content translations
@@ -44,7 +42,7 @@ var InlineCLI = class extends BaseCLI {
44
42
  }
45
43
  setupValidateCommand() {
46
44
  attachValidateFlags(this.program.command("validate [files...]").description("Scans the project for a dictionary and/or inline content and validates the project for errors.")).action(async (files, options) => {
47
- intro(chalk.cyan("Validating project..."));
45
+ logger.startCommand("Validating project...");
48
46
  await this.handleValidate(options, files);
49
47
  logger.endCommand("Done!");
50
48
  });
@@ -1 +1 @@
1
- {"version":3,"file":"inline.js","names":[],"sources":["../../src/cli/inline.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { BaseCLI } from './base.js';\nimport { SupportedLibraries, TranslateFlags, Options } from '../types/index.js';\nimport {\n attachInlineTranslateFlags,\n attachTranslateFlags,\n attachValidateFlags,\n} from './flags.js';\nimport { displayHeader, exitSync } from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { intro } from '@clack/prompts';\nimport chalk from 'chalk';\nimport { resolveLocaleFiles } from '../fs/config/parseFilesConfig.js';\nimport { noFilesError } from '../console/index.js';\nimport { saveJSON } from '../fs/saveJSON.js';\nimport loadJSON from '../fs/loadJSON.js';\nimport { generateSettings } from '../config/generateSettings.js';\nimport { aggregateInlineTranslations } from '../translation/stage.js';\nimport { validateProject } from '../translation/validate.js';\nimport { Libraries, InlineLibrary } from '../types/libraries.js';\n\n/**\n * Stand in for a CLI tool that does any sort of inline content translations\n */\nexport class InlineCLI extends BaseCLI {\n constructor(\n command: Command,\n library: InlineLibrary,\n additionalModules?: SupportedLibraries[]\n ) {\n super(command, library, additionalModules);\n }\n public init() {\n this.setupStageCommand();\n this.setupTranslateCommand();\n this.setupGenerateSourceCommand();\n this.setupValidateCommand();\n this.setupDownloadCommand();\n this.setupEnqueueCommand();\n }\n\n protected setupStageCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('stage')\n .description(\n 'Submits the project to the General Translation API for translation. Translations created using this command will require human approval.'\n )\n )\n ).action(async (options: TranslateFlags) => {\n displayHeader(\n 'Staging project for translation with approval required...'\n );\n await this.handleStage(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupTranslateCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('translate')\n .description(\n 'Scans the project for a dictionary and inline translations and sends the updates to the General Translation API for translation.'\n )\n )\n ).action(async (options: TranslateFlags) => {\n displayHeader('Translating project...');\n await this.handleTranslate(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupValidateCommand(): void {\n attachValidateFlags(\n this.program\n .command('validate [files...]')\n .description(\n 'Scans the project for a dictionary and/or inline content and validates the project for errors.'\n )\n ).action(async (files: string[], options: Options) => {\n // intro here since we don't want to show the ascii title\n intro(chalk.cyan('Validating project...'));\n await this.handleValidate(options, files);\n logger.endCommand('Done!');\n });\n }\n\n protected setupGenerateSourceCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('generate')\n .description(\n 'Generate a translation file for the source locale. This command should be used if you are handling your own translations.'\n )\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Generating source templates...');\n await this.handleGenerateSourceCommand(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected async handleGenerateSourceCommand(\n initOptions: TranslateFlags\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n const updates = await aggregateInlineTranslations(\n initOptions,\n settings,\n fallbackToGtReact(this.library)\n );\n\n // Convert updates to the proper data format\n const newData: Record<string, unknown> = {};\n for (const update of updates) {\n const { source, metadata } = update;\n const { hash } = metadata;\n if (hash) {\n newData[hash] = source;\n }\n }\n\n // Save source file if files.json is provided\n if (settings.files && settings.files.placeholderPaths.gt) {\n const translationFiles = resolveLocaleFiles(\n settings.files.placeholderPaths,\n settings.defaultLocale\n );\n if (!translationFiles.gt) {\n logger.error(noFilesError);\n exitSync(1);\n }\n await saveJSON(translationFiles.gt, newData);\n logger.step('Source file saved successfully!');\n // Also save translations (after merging with existing translations)\n for (const locale of settings.locales) {\n const translationsFile = resolveLocaleFiles(\n settings.files.placeholderPaths,\n locale\n );\n\n if (!translationsFile.gt) {\n continue;\n }\n const existingTranslations = loadJSON(translationsFile.gt);\n const mergedTranslations = {\n ...newData,\n ...existingTranslations,\n };\n // Filter out keys that don't exist in newData\n const filteredTranslations = Object.fromEntries(\n Object.entries(mergedTranslations).filter(([key]) => newData[key])\n );\n await saveJSON(translationsFile.gt, filteredTranslations);\n }\n logger.step('Merged translations successfully!');\n }\n }\n\n protected async handleValidate(\n initOptions: Options,\n files?: string[]\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // First run the base class's handleTranslate method\n const options = { ...initOptions, ...settings };\n\n // Fallback to gt-react\n const pkg = fallbackToGtReact(this.library);\n\n if (files && files.length > 0) {\n // Validate specific files using createInlineUpdates\n await validateProject(options, pkg, files);\n } else {\n // Validate whole project as before\n await validateProject(options, pkg);\n }\n }\n}\n\nfunction fallbackToGtReact(library: SupportedLibraries): InlineLibrary {\n return [\n Libraries.GT_NEXT,\n Libraries.GT_NODE,\n Libraries.GT_REACT_NATIVE,\n Libraries.GT_TANSTACK_START,\n Libraries.GT_FLASK,\n Libraries.GT_FASTAPI,\n ].includes(library as Libraries)\n ? (library as\n | typeof Libraries.GT_NEXT\n | typeof Libraries.GT_NODE\n | typeof Libraries.GT_REACT_NATIVE\n | typeof Libraries.GT_TANSTACK_START\n | typeof Libraries.GT_FLASK\n | typeof Libraries.GT_FASTAPI)\n : Libraries.GT_REACT;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inline.js","names":[],"sources":["../../src/cli/inline.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { BaseCLI } from './base.js';\nimport { SupportedLibraries, TranslateFlags, Options } from '../types/index.js';\nimport {\n attachInlineTranslateFlags,\n attachTranslateFlags,\n attachValidateFlags,\n} from './flags.js';\nimport { displayHeader, exitSync } from '../console/logging.js';\nimport { logger } from '../console/logger.js';\nimport { resolveLocaleFiles } from '../fs/config/parseFilesConfig.js';\nimport { noFilesError } from '../console/index.js';\nimport { saveJSON } from '../fs/saveJSON.js';\nimport loadJSON from '../fs/loadJSON.js';\nimport { generateSettings } from '../config/generateSettings.js';\nimport { aggregateInlineTranslations } from '../translation/stage.js';\nimport { validateProject } from '../translation/validate.js';\nimport { Libraries, InlineLibrary } from '../types/libraries.js';\n\n/**\n * Stand in for a CLI tool that does any sort of inline content translations\n */\nexport class InlineCLI extends BaseCLI {\n constructor(\n command: Command,\n library: InlineLibrary,\n additionalModules?: SupportedLibraries[]\n ) {\n super(command, library, additionalModules);\n }\n public init() {\n this.setupStageCommand();\n this.setupTranslateCommand();\n this.setupGenerateSourceCommand();\n this.setupValidateCommand();\n this.setupDownloadCommand();\n this.setupEnqueueCommand();\n }\n\n protected setupStageCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('stage')\n .description(\n 'Submits the project to the General Translation API for translation. Translations created using this command will require human approval.'\n )\n )\n ).action(async (options: TranslateFlags) => {\n displayHeader(\n 'Staging project for translation with approval required...'\n );\n await this.handleStage(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupTranslateCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('translate')\n .description(\n 'Scans the project for a dictionary and inline translations and sends the updates to the General Translation API for translation.'\n )\n )\n ).action(async (options: TranslateFlags) => {\n displayHeader('Translating project...');\n await this.handleTranslate(options);\n logger.endCommand('Done!');\n });\n }\n\n protected setupValidateCommand(): void {\n attachValidateFlags(\n this.program\n .command('validate [files...]')\n .description(\n 'Scans the project for a dictionary and/or inline content and validates the project for errors.'\n )\n ).action(async (files: string[], options: Options) => {\n // startCommand here since we don't want to show the ascii title; it\n // renders the same intro while honoring --quiet.\n logger.startCommand('Validating project...');\n await this.handleValidate(options, files);\n logger.endCommand('Done!');\n });\n }\n\n protected setupGenerateSourceCommand(): void {\n attachInlineTranslateFlags(\n attachTranslateFlags(\n this.program\n .command('generate')\n .description(\n 'Generate a translation file for the source locale. This command should be used if you are handling your own translations.'\n )\n )\n ).action(async (initOptions: TranslateFlags) => {\n displayHeader('Generating source templates...');\n await this.handleGenerateSourceCommand(initOptions);\n logger.endCommand('Done!');\n });\n }\n\n protected async handleGenerateSourceCommand(\n initOptions: TranslateFlags\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n const updates = await aggregateInlineTranslations(\n initOptions,\n settings,\n fallbackToGtReact(this.library)\n );\n\n // Convert updates to the proper data format\n const newData: Record<string, unknown> = {};\n for (const update of updates) {\n const { source, metadata } = update;\n const { hash } = metadata;\n if (hash) {\n newData[hash] = source;\n }\n }\n\n // Save source file if files.json is provided\n if (settings.files && settings.files.placeholderPaths.gt) {\n const translationFiles = resolveLocaleFiles(\n settings.files.placeholderPaths,\n settings.defaultLocale\n );\n if (!translationFiles.gt) {\n logger.error(noFilesError);\n exitSync(1);\n }\n await saveJSON(translationFiles.gt, newData);\n logger.step('Source file saved successfully!');\n // Also save translations (after merging with existing translations)\n for (const locale of settings.locales) {\n const translationsFile = resolveLocaleFiles(\n settings.files.placeholderPaths,\n locale\n );\n\n if (!translationsFile.gt) {\n continue;\n }\n const existingTranslations = loadJSON(translationsFile.gt);\n const mergedTranslations = {\n ...newData,\n ...existingTranslations,\n };\n // Filter out keys that don't exist in newData\n const filteredTranslations = Object.fromEntries(\n Object.entries(mergedTranslations).filter(([key]) => newData[key])\n );\n await saveJSON(translationsFile.gt, filteredTranslations);\n }\n logger.step('Merged translations successfully!');\n }\n }\n\n protected async handleValidate(\n initOptions: Options,\n files?: string[]\n ): Promise<void> {\n const settings = await generateSettings(initOptions, undefined, {\n requireConfig: true,\n });\n\n // First run the base class's handleTranslate method\n const options = { ...initOptions, ...settings };\n\n // Fallback to gt-react\n const pkg = fallbackToGtReact(this.library);\n\n if (files && files.length > 0) {\n // Validate specific files using createInlineUpdates\n await validateProject(options, pkg, files);\n } else {\n // Validate whole project as before\n await validateProject(options, pkg);\n }\n }\n}\n\nfunction fallbackToGtReact(library: SupportedLibraries): InlineLibrary {\n return [\n Libraries.GT_NEXT,\n Libraries.GT_NODE,\n Libraries.GT_REACT_NATIVE,\n Libraries.GT_TANSTACK_START,\n Libraries.GT_FLASK,\n Libraries.GT_FASTAPI,\n ].includes(library as Libraries)\n ? (library as\n | typeof Libraries.GT_NEXT\n | typeof Libraries.GT_NODE\n | typeof Libraries.GT_REACT_NATIVE\n | typeof Libraries.GT_TANSTACK_START\n | typeof Libraries.GT_FLASK\n | typeof Libraries.GT_FASTAPI)\n : Libraries.GT_REACT;\n}\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type { SpinnerResult, ProgressResult } from '@clack/prompts';
2
2
  export type LogFormat = 'default' | 'json';
3
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
3
4
  /**
4
5
  * GT_LOG_FORMAT: default | json.
5
6
  * - If default, logs will be pretty-printed using @clack/prompts.
@@ -13,8 +14,20 @@ declare class Logger {
13
14
  private pinoLogger;
14
15
  private fileLogger;
15
16
  private logFormat;
17
+ private logLevel;
18
+ private quiet;
16
19
  private constructor();
17
20
  static getInstance(): Logger;
21
+ /**
22
+ * Enable or disable quiet mode. When quiet, informational chatter
23
+ * (info/step/success/message/debug/trace, spinners, progress bars, and
24
+ * command intro/outro markers) is suppressed on the console, while warnings
25
+ * and errors still print. Quiet wins over GT_LOG_LEVEL but never lowers an
26
+ * already-more-restrictive level. File logging is unaffected so an explicit
27
+ * GT_LOG_FILE still captures everything.
28
+ */
29
+ setQuiet(quiet: boolean): void;
30
+ isQuiet(): boolean;
18
31
  trace(message: string): void;
19
32
  debug(message: string): void;
20
33
  info(message: string): void;
@@ -29,6 +29,13 @@ function wrapTerminalSessionAware(target) {
29
29
  }
30
30
  return target;
31
31
  }
32
+ const LOG_LEVEL_RANK = {
33
+ debug: 10,
34
+ info: 20,
35
+ warn: 30,
36
+ error: 40
37
+ };
38
+ const QUIET_FLOOR_LEVEL = "warn";
32
39
  var MockSpinner = class {
33
40
  currentMessage = "";
34
41
  logger;
@@ -85,6 +92,8 @@ const logger = class Logger {
85
92
  pinoLogger = null;
86
93
  fileLogger = null;
87
94
  logFormat;
95
+ logLevel;
96
+ quiet = false;
88
97
  constructor() {
89
98
  const format = (process.env.GT_LOG_FORMAT || "default").toLowerCase();
90
99
  const logFile = process.env.GT_LOG_FILE;
@@ -98,6 +107,7 @@ const logger = class Logger {
98
107
  process.exit(1);
99
108
  }
100
109
  this.logFormat = format;
110
+ this.logLevel = logLevel;
101
111
  if (format === "json") this.pinoLogger = pino({
102
112
  level: logLevel,
103
113
  mixin: () => ({ logId: randomUUID() })
@@ -111,22 +121,37 @@ const logger = class Logger {
111
121
  if (!Logger.instance) Logger.instance = new Logger();
112
122
  return Logger.instance;
113
123
  }
124
+ /**
125
+ * Enable or disable quiet mode. When quiet, informational chatter
126
+ * (info/step/success/message/debug/trace, spinners, progress bars, and
127
+ * command intro/outro markers) is suppressed on the console, while warnings
128
+ * and errors still print. Quiet wins over GT_LOG_LEVEL but never lowers an
129
+ * already-more-restrictive level. File logging is unaffected so an explicit
130
+ * GT_LOG_FILE still captures everything.
131
+ */
132
+ setQuiet(quiet) {
133
+ this.quiet = quiet;
134
+ if (this.pinoLogger) this.pinoLogger.level = quiet ? LOG_LEVEL_RANK[this.logLevel] > LOG_LEVEL_RANK[QUIET_FLOOR_LEVEL] ? this.logLevel : QUIET_FLOOR_LEVEL : this.logLevel;
135
+ }
136
+ isQuiet() {
137
+ return this.quiet;
138
+ }
114
139
  trace(message) {
115
- if (this.logFormat === "default") {
140
+ if (!this.quiet) if (this.logFormat === "default") {
116
141
  endTerminalSession();
117
142
  log.message(message, { symbol: chalk.dim("•") });
118
143
  } else this.pinoLogger?.trace(message);
119
144
  this.fileLogger?.trace(message);
120
145
  }
121
146
  debug(message) {
122
- if (this.logFormat === "default") {
147
+ if (!this.quiet) if (this.logFormat === "default") {
123
148
  endTerminalSession();
124
149
  log.message(message, { symbol: chalk.dim("◆") });
125
150
  } else this.pinoLogger?.debug(message);
126
151
  this.fileLogger?.debug(message);
127
152
  }
128
153
  info(message) {
129
- if (this.logFormat === "default") {
154
+ if (!this.quiet) if (this.logFormat === "default") {
130
155
  endTerminalSession();
131
156
  log.info(message);
132
157
  } else this.pinoLogger?.info(message);
@@ -157,43 +182,45 @@ const logger = class Logger {
157
182
  this.fileLogger?.silent(message);
158
183
  }
159
184
  success(message) {
160
- if (this.logFormat === "default") {
185
+ if (!this.quiet) if (this.logFormat === "default") {
161
186
  endTerminalSession();
162
187
  log.success(message);
163
188
  } else this.pinoLogger?.info(message);
164
189
  this.fileLogger?.info(message);
165
190
  }
166
191
  step(message) {
167
- if (this.logFormat === "default") {
192
+ if (!this.quiet) if (this.logFormat === "default") {
168
193
  endTerminalSession();
169
194
  log.step(message);
170
195
  } else this.pinoLogger?.info(message);
171
196
  this.fileLogger?.info(message);
172
197
  }
173
198
  message(message, symbol) {
174
- if (this.logFormat === "default") {
199
+ if (!this.quiet) if (this.logFormat === "default") {
175
200
  endTerminalSession();
176
201
  log.message(message, symbol ? { symbol } : void 0);
177
202
  } else this.pinoLogger?.info(message);
178
203
  this.fileLogger?.info(message);
179
204
  }
180
205
  createSpinner(indicator = "timer") {
206
+ if (this.quiet) return new MockSpinner(this);
181
207
  if (this.logFormat === "default") return wrapTerminalSessionAware(spinner({ indicator }));
182
208
  else return new MockSpinner(this);
183
209
  }
184
210
  createProgressBar(total) {
211
+ if (this.quiet) return new MockProgress(total, this);
185
212
  if (this.logFormat === "default") return wrapTerminalSessionAware(progress({ max: total }));
186
213
  else return new MockProgress(total, this);
187
214
  }
188
215
  startCommand(message) {
189
- if (this.logFormat === "default") {
216
+ if (!this.quiet) if (this.logFormat === "default") {
190
217
  endTerminalSession();
191
218
  intro(chalk.cyan(message));
192
219
  } else this.info(`╭─ ${message}`);
193
220
  this.fileLogger?.info(`[START] ${message}`);
194
221
  }
195
222
  endCommand(message) {
196
- if (this.logFormat === "default") {
223
+ if (!this.quiet) if (this.logFormat === "default") {
197
224
  endTerminalSession();
198
225
  outro(chalk.cyan(message));
199
226
  } else this.info(`╰─ ${message}`);
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","names":[],"sources":["../../src/console/logger.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { randomUUID } from 'node:crypto';\nimport { pino, destination } from 'pino';\nimport {\n log as clackLog,\n spinner,\n progress,\n intro,\n outro,\n} from '@clack/prompts';\nimport { endTerminalSession } from './terminalSession.js';\n\nimport type { Logger as PinoLogger } from 'pino';\nimport type { SpinnerResult, ProgressResult } from '@clack/prompts';\n\nfunction wrapTerminalSessionAware<T extends SpinnerResult | ProgressResult>(\n target: T\n): T {\n const start = target.start.bind(target);\n const stop = target.stop.bind(target);\n const message = target.message.bind(target);\n target.start = (msg?: string) => {\n endTerminalSession();\n return start(msg);\n };\n target.stop = (msg?: string, code?: number) => {\n endTerminalSession();\n return (stop as (m?: string, c?: number) => void)(msg, code);\n };\n target.message = (msg?: string) => {\n endTerminalSession();\n return message(msg);\n };\n if ('advance' in target) {\n const advance = target.advance.bind(target);\n target.advance = (amount: number, msg?: string) => {\n endTerminalSession();\n return advance(amount, msg);\n };\n }\n return target;\n}\n\nexport type LogFormat = 'default' | 'json';\n\n// Mock spinner that logs to console instead of updating terminal UI\nclass MockSpinner implements SpinnerResult {\n private currentMessage: string = '';\n private logger: Logger;\n isCancelled: boolean = false;\n\n constructor(logger: Logger) {\n this.logger = logger;\n }\n\n start(message?: string): void {\n if (message) {\n this.currentMessage = message;\n this.logger.info(`[Spinner] ${message}`);\n }\n }\n\n stop(message?: string): void {\n const msg = message || this.currentMessage;\n if (msg) {\n this.logger.info(`[Spinner] ${msg}`);\n }\n this.currentMessage = '';\n }\n\n message(message?: string): void {\n if (message) {\n this.currentMessage = message;\n this.logger.info(`[Spinner] ${message}`);\n }\n }\n}\n\n// Mock progress bar that logs to console instead of updating terminal UI\nclass MockProgress implements ProgressResult {\n private max: number;\n private current: number = 0;\n private logger: Logger;\n isCancelled: boolean = false;\n\n constructor(max: number, logger: Logger) {\n this.max = max;\n this.logger = logger;\n }\n\n start(message?: string): void {\n const msg = message || 'Starting progress';\n this.logger.info(`[Progress] ${msg} (0/${this.max})`);\n }\n\n stop(message?: string): void {\n const msg = message || 'Complete';\n this.logger.info(`[Progress] ${msg} (${this.current}/${this.max})`);\n }\n\n message(message?: string): void {\n if (message) {\n this.logger.info(`[Progress] ${message} (${this.current}/${this.max})`);\n }\n }\n\n advance(amount: number, message?: string): void {\n this.current += amount;\n const msg = message || 'Progress';\n this.logger.info(`[Progress] ${msg} (${this.current}/${this.max})`);\n }\n}\n\n/**\n * GT_LOG_FORMAT: default | json.\n * - If default, logs will be pretty-printed using @clack/prompts.\n * - If json, logs will be written in JSON format to the console.\n * GT_LOG_FILE: If specified, logs will be written to the file.\n * GT_LOG_LEVEL: The level of logs to write. If not specified, defaults to 'info'.\n * - Valid levels: debug, info, warn, error.\n */\nclass Logger {\n private static instance: Logger;\n private pinoLogger: PinoLogger | null = null;\n private fileLogger: PinoLogger | null = null;\n private logFormat: LogFormat;\n\n private constructor() {\n // Read configuration from environment variables\n const format = (\n process.env.GT_LOG_FORMAT || 'default'\n ).toLowerCase() as LogFormat;\n const logFile = process.env.GT_LOG_FILE;\n const logLevel = process.env.GT_LOG_LEVEL || 'info';\n\n if (format !== 'default' && format !== 'json') {\n console.error('Invalid log format');\n process.exit(1);\n }\n if (\n logLevel !== 'debug' &&\n logLevel !== 'info' &&\n logLevel !== 'warn' &&\n logLevel !== 'error'\n ) {\n console.error('Invalid log level');\n process.exit(1);\n }\n\n this.logFormat = format;\n\n // Console output (stdout) - only for JSON format\n // For 'default' format, we use @clack/prompts directly\n if (format === 'json') {\n this.pinoLogger = pino(\n {\n level: logLevel,\n mixin: () => ({\n logId: randomUUID(),\n }),\n },\n destination(1)\n );\n }\n\n // File output (if specified) - always JSON format\n if (logFile) {\n this.fileLogger = pino(\n {\n level: logLevel,\n mixin: () => ({\n logId: randomUUID(),\n }),\n },\n destination(logFile)\n );\n }\n }\n\n static getInstance(): Logger {\n if (!Logger.instance) {\n Logger.instance = new Logger();\n }\n return Logger.instance;\n }\n\n // Standard logging methods\n trace(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n // @clack/prompts doesn't have trace, use message\n clackLog.message(message, { symbol: chalk.dim('•') });\n } else {\n this.pinoLogger?.trace(message);\n }\n this.fileLogger?.trace(message);\n }\n\n debug(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n // @clack/prompts doesn't have debug, use message\n clackLog.message(message, { symbol: chalk.dim('◆') });\n } else {\n this.pinoLogger?.debug(message);\n }\n this.fileLogger?.debug(message);\n }\n\n info(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.info(message);\n } else {\n this.pinoLogger?.info(message);\n }\n this.fileLogger?.info(message);\n }\n\n warn(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.warn(message);\n } else {\n this.pinoLogger?.warn(message);\n }\n this.fileLogger?.warn(message);\n }\n\n error(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.error(message);\n } else {\n this.pinoLogger?.error(message);\n }\n this.fileLogger?.error(message);\n }\n\n fatal(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.error(message); // @clack/prompts doesn't have fatal, use error\n } else {\n this.pinoLogger?.fatal(message);\n }\n this.fileLogger?.fatal(message);\n }\n\n silent(message: string): void {\n // Silent doesn't log to console, only to file\n this.fileLogger?.silent(message);\n }\n\n // @clack/prompts specific methods (for 'default' format)\n success(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.success(message);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n this.fileLogger?.info(message);\n }\n\n step(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.step(message);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n this.fileLogger?.info(message);\n }\n\n message(message: string, symbol?: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.message(message, symbol ? { symbol } : undefined);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n this.fileLogger?.info(message);\n }\n\n // Spinner functionality\n createSpinner(indicator: 'dots' | 'timer' = 'timer'): SpinnerResult {\n if (this.logFormat === 'default') {\n return wrapTerminalSessionAware(spinner({ indicator }));\n } else {\n return new MockSpinner(this);\n }\n }\n\n // Progress bar functionality\n createProgressBar(total: number): ProgressResult {\n if (this.logFormat === 'default') {\n return wrapTerminalSessionAware(progress({ max: total }));\n } else {\n return new MockProgress(total, this);\n }\n }\n\n // Command start/end markers\n startCommand(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n intro(chalk.cyan(message));\n } else {\n this.info(`╭─ ${message}`);\n }\n this.fileLogger?.info(`[START] ${message}`);\n }\n\n endCommand(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n outro(chalk.cyan(message));\n } else {\n this.info(`╰─ ${message}`);\n }\n this.fileLogger?.info(`[END] ${message}`);\n }\n\n // Flush logs to ensure they're written before process exit\n flush(): void {\n this.pinoLogger?.flush();\n this.fileLogger?.flush();\n }\n}\n\nexport const logger = Logger.getInstance();\n"],"mappings":"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"}
1
+ {"version":3,"file":"logger.js","names":[],"sources":["../../src/console/logger.ts"],"sourcesContent":["import chalk from 'chalk';\nimport { randomUUID } from 'node:crypto';\nimport { pino, destination } from 'pino';\nimport {\n log as clackLog,\n spinner,\n progress,\n intro,\n outro,\n} from '@clack/prompts';\nimport { endTerminalSession } from './terminalSession.js';\n\nimport type { Logger as PinoLogger } from 'pino';\nimport type { SpinnerResult, ProgressResult } from '@clack/prompts';\n\nfunction wrapTerminalSessionAware<T extends SpinnerResult | ProgressResult>(\n target: T\n): T {\n const start = target.start.bind(target);\n const stop = target.stop.bind(target);\n const message = target.message.bind(target);\n target.start = (msg?: string) => {\n endTerminalSession();\n return start(msg);\n };\n target.stop = (msg?: string, code?: number) => {\n endTerminalSession();\n return (stop as (m?: string, c?: number) => void)(msg, code);\n };\n target.message = (msg?: string) => {\n endTerminalSession();\n return message(msg);\n };\n if ('advance' in target) {\n const advance = target.advance.bind(target);\n target.advance = (amount: number, msg?: string) => {\n endTerminalSession();\n return advance(amount, msg);\n };\n }\n return target;\n}\n\nexport type LogFormat = 'default' | 'json';\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n// Numeric ordering used to decide the quiet floor without lowering an\n// already-more-restrictive level chosen via GT_LOG_LEVEL.\nconst LOG_LEVEL_RANK: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n};\n\n// Under --quiet, informational output is suppressed but warnings and errors\n// still print, so the console never drops below this level.\nconst QUIET_FLOOR_LEVEL: LogLevel = 'warn';\n\n// Mock spinner that logs to console instead of updating terminal UI\nclass MockSpinner implements SpinnerResult {\n private currentMessage: string = '';\n private logger: Logger;\n isCancelled: boolean = false;\n\n constructor(logger: Logger) {\n this.logger = logger;\n }\n\n start(message?: string): void {\n if (message) {\n this.currentMessage = message;\n this.logger.info(`[Spinner] ${message}`);\n }\n }\n\n stop(message?: string): void {\n const msg = message || this.currentMessage;\n if (msg) {\n this.logger.info(`[Spinner] ${msg}`);\n }\n this.currentMessage = '';\n }\n\n message(message?: string): void {\n if (message) {\n this.currentMessage = message;\n this.logger.info(`[Spinner] ${message}`);\n }\n }\n}\n\n// Mock progress bar that logs to console instead of updating terminal UI\nclass MockProgress implements ProgressResult {\n private max: number;\n private current: number = 0;\n private logger: Logger;\n isCancelled: boolean = false;\n\n constructor(max: number, logger: Logger) {\n this.max = max;\n this.logger = logger;\n }\n\n start(message?: string): void {\n const msg = message || 'Starting progress';\n this.logger.info(`[Progress] ${msg} (0/${this.max})`);\n }\n\n stop(message?: string): void {\n const msg = message || 'Complete';\n this.logger.info(`[Progress] ${msg} (${this.current}/${this.max})`);\n }\n\n message(message?: string): void {\n if (message) {\n this.logger.info(`[Progress] ${message} (${this.current}/${this.max})`);\n }\n }\n\n advance(amount: number, message?: string): void {\n this.current += amount;\n const msg = message || 'Progress';\n this.logger.info(`[Progress] ${msg} (${this.current}/${this.max})`);\n }\n}\n\n/**\n * GT_LOG_FORMAT: default | json.\n * - If default, logs will be pretty-printed using @clack/prompts.\n * - If json, logs will be written in JSON format to the console.\n * GT_LOG_FILE: If specified, logs will be written to the file.\n * GT_LOG_LEVEL: The level of logs to write. If not specified, defaults to 'info'.\n * - Valid levels: debug, info, warn, error.\n */\nclass Logger {\n private static instance: Logger;\n private pinoLogger: PinoLogger | null = null;\n private fileLogger: PinoLogger | null = null;\n private logFormat: LogFormat;\n private logLevel: LogLevel;\n private quiet = false;\n\n private constructor() {\n // Read configuration from environment variables\n const format = (\n process.env.GT_LOG_FORMAT || 'default'\n ).toLowerCase() as LogFormat;\n const logFile = process.env.GT_LOG_FILE;\n const logLevel = process.env.GT_LOG_LEVEL || 'info';\n\n if (format !== 'default' && format !== 'json') {\n console.error('Invalid log format');\n process.exit(1);\n }\n if (\n logLevel !== 'debug' &&\n logLevel !== 'info' &&\n logLevel !== 'warn' &&\n logLevel !== 'error'\n ) {\n console.error('Invalid log level');\n process.exit(1);\n }\n\n this.logFormat = format;\n this.logLevel = logLevel as LogLevel;\n\n // Console output (stdout) - only for JSON format\n // For 'default' format, we use @clack/prompts directly\n if (format === 'json') {\n this.pinoLogger = pino(\n {\n level: logLevel,\n mixin: () => ({\n logId: randomUUID(),\n }),\n },\n destination(1)\n );\n }\n\n // File output (if specified) - always JSON format\n if (logFile) {\n this.fileLogger = pino(\n {\n level: logLevel,\n mixin: () => ({\n logId: randomUUID(),\n }),\n },\n destination(logFile)\n );\n }\n }\n\n static getInstance(): Logger {\n if (!Logger.instance) {\n Logger.instance = new Logger();\n }\n return Logger.instance;\n }\n\n /**\n * Enable or disable quiet mode. When quiet, informational chatter\n * (info/step/success/message/debug/trace, spinners, progress bars, and\n * command intro/outro markers) is suppressed on the console, while warnings\n * and errors still print. Quiet wins over GT_LOG_LEVEL but never lowers an\n * already-more-restrictive level. File logging is unaffected so an explicit\n * GT_LOG_FILE still captures everything.\n */\n setQuiet(quiet: boolean): void {\n this.quiet = quiet;\n if (this.pinoLogger) {\n this.pinoLogger.level = quiet\n ? LOG_LEVEL_RANK[this.logLevel] > LOG_LEVEL_RANK[QUIET_FLOOR_LEVEL]\n ? this.logLevel\n : QUIET_FLOOR_LEVEL\n : this.logLevel;\n }\n }\n\n isQuiet(): boolean {\n return this.quiet;\n }\n\n // Standard logging methods\n trace(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n // @clack/prompts doesn't have trace, use message\n clackLog.message(message, { symbol: chalk.dim('•') });\n } else {\n this.pinoLogger?.trace(message);\n }\n }\n this.fileLogger?.trace(message);\n }\n\n debug(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n // @clack/prompts doesn't have debug, use message\n clackLog.message(message, { symbol: chalk.dim('◆') });\n } else {\n this.pinoLogger?.debug(message);\n }\n }\n this.fileLogger?.debug(message);\n }\n\n info(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.info(message);\n } else {\n this.pinoLogger?.info(message);\n }\n }\n this.fileLogger?.info(message);\n }\n\n warn(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.warn(message);\n } else {\n this.pinoLogger?.warn(message);\n }\n this.fileLogger?.warn(message);\n }\n\n error(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.error(message);\n } else {\n this.pinoLogger?.error(message);\n }\n this.fileLogger?.error(message);\n }\n\n fatal(message: string): void {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.error(message); // @clack/prompts doesn't have fatal, use error\n } else {\n this.pinoLogger?.fatal(message);\n }\n this.fileLogger?.fatal(message);\n }\n\n silent(message: string): void {\n // Silent doesn't log to console, only to file\n this.fileLogger?.silent(message);\n }\n\n // @clack/prompts specific methods (for 'default' format)\n success(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.success(message);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n }\n this.fileLogger?.info(message);\n }\n\n step(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.step(message);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n }\n this.fileLogger?.info(message);\n }\n\n message(message: string, symbol?: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n clackLog.message(message, symbol ? { symbol } : undefined);\n } else {\n this.pinoLogger?.info(message); // Map to info for non-default formats\n }\n }\n this.fileLogger?.info(message);\n }\n\n // Spinner functionality\n createSpinner(indicator: 'dots' | 'timer' = 'timer'): SpinnerResult {\n // Quiet mode suppresses spinner UI; the mock routes through the gated\n // info() so nothing reaches the console while file logging is preserved.\n if (this.quiet) {\n return new MockSpinner(this);\n }\n if (this.logFormat === 'default') {\n return wrapTerminalSessionAware(spinner({ indicator }));\n } else {\n return new MockSpinner(this);\n }\n }\n\n // Progress bar functionality\n createProgressBar(total: number): ProgressResult {\n if (this.quiet) {\n return new MockProgress(total, this);\n }\n if (this.logFormat === 'default') {\n return wrapTerminalSessionAware(progress({ max: total }));\n } else {\n return new MockProgress(total, this);\n }\n }\n\n // Command start/end markers\n startCommand(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n intro(chalk.cyan(message));\n } else {\n this.info(`╭─ ${message}`);\n }\n }\n this.fileLogger?.info(`[START] ${message}`);\n }\n\n endCommand(message: string): void {\n if (!this.quiet) {\n if (this.logFormat === 'default') {\n endTerminalSession();\n outro(chalk.cyan(message));\n } else {\n this.info(`╰─ ${message}`);\n }\n }\n this.fileLogger?.info(`[END] ${message}`);\n }\n\n // Flush logs to ensure they're written before process exit\n flush(): void {\n this.pinoLogger?.flush();\n this.fileLogger?.flush();\n }\n}\n\nexport const logger = Logger.getInstance();\n"],"mappings":"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"}
@@ -34,8 +34,10 @@ function exitSync(code) {
34
34
  process.exit(code);
35
35
  }
36
36
  function displayHeader(introString) {
37
- displayAsciiTitle();
38
- displayInitializingText();
37
+ if (!logger.isQuiet()) {
38
+ displayAsciiTitle();
39
+ displayInitializingText();
40
+ }
39
41
  if (introString) logger.startCommand(introString);
40
42
  }
41
43
  function displayAsciiTitle() {