@tailor-platform/sdk 2.38.0 → 2.39.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 (55) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dist/{application-Bz80INH4.mjs → application-OeNMQzOC.mjs} +1 -1
  3. package/dist/{application-CeqD1OK-.mjs → application-mNOJx9Y2.mjs} +4 -4
  4. package/dist/{application-CeqD1OK-.mjs.map → application-mNOJx9Y2.mjs.map} +1 -1
  5. package/dist/cli/commands/executor/trigger.d.mts +1 -0
  6. package/dist/cli/commands/generate/seed/bundler.d.mts +7 -5
  7. package/dist/cli/commands/workspace/transform.d.mts +1 -2
  8. package/dist/cli/lib.d.mts +4 -2
  9. package/dist/cli/lib.mjs +1 -1
  10. package/dist/cli/lib.mjs.map +1 -1
  11. package/dist/cli/main.mjs +30 -30
  12. package/dist/cli/main.mjs.map +1 -1
  13. package/dist/cli/shared/build-options.d.mts +13 -0
  14. package/dist/cli/shared/client.d.mts +1 -0
  15. package/dist/cli/shared/script-workflow.d.mts +65 -0
  16. package/dist/cli/shared/seed-chunker.d.mts +3 -3
  17. package/dist/{client-DOQv-BP8.mjs → client-CqiPQgMG.mjs} +2 -2
  18. package/dist/client-CqiPQgMG.mjs.map +1 -0
  19. package/dist/client-DO2_Xz_z.mjs +1 -0
  20. package/dist/completion/zsh-worker.zsh +61 -6
  21. package/dist/configure/index.mjs +1 -1
  22. package/dist/configure/index.mjs.map +1 -1
  23. package/dist/configure/services/auth/types.d.mts +20 -3
  24. package/dist/configure/services/executor/trigger/webhook.d.mts +8 -1
  25. package/dist/{context-OOASEQLA.mjs → context-CYBcQZyO.mjs} +1 -1
  26. package/dist/{context-DSi5kfqr.mjs → context-aAgFGDBD.mjs} +4 -4
  27. package/dist/{context-DSi5kfqr.mjs.map → context-aAgFGDBD.mjs.map} +1 -1
  28. package/dist/{register-ts-hook-CXYYYgCl.mjs → register-ts-hook-CORbtrSN.mjs} +82 -71
  29. package/dist/register-ts-hook-CORbtrSN.mjs.map +1 -0
  30. package/dist/{service-DB-RHn25.mjs → service-Bkz_TB5v.mjs} +2 -2
  31. package/dist/{service-DB-RHn25.mjs.map → service-Bkz_TB5v.mjs.map} +1 -1
  32. package/dist/service-Dffd4how.mjs +1 -0
  33. package/dist/syntax-diagnostic-BQgOV8Fz.mjs +2 -0
  34. package/dist/syntax-diagnostic-BQgOV8Fz.mjs.map +1 -0
  35. package/dist/validation-errors-ChvCG6wT.mjs +3 -0
  36. package/dist/validation-errors-ChvCG6wT.mjs.map +1 -0
  37. package/dist/vitest/index.mjs +1 -1
  38. package/dist/vitest/index.mjs.map +1 -1
  39. package/docs/cli/application.md +3 -3
  40. package/docs/cli/executor.md +13 -17
  41. package/docs/cli/function.md +1 -1
  42. package/docs/cli/workspace.md +2 -3
  43. package/docs/configuration.md +28 -0
  44. package/docs/github-actions.md +82 -15
  45. package/docs/migration/v2.md +5 -3
  46. package/docs/services/auth.md +5 -0
  47. package/docs/services/executor.md +2 -0
  48. package/docs/services/tailordb/migration.md +3 -3
  49. package/package.json +12 -12
  50. package/dist/client-CHXix4LD.mjs +0 -1
  51. package/dist/client-DOQv-BP8.mjs.map +0 -1
  52. package/dist/register-ts-hook-CXYYYgCl.mjs.map +0 -1
  53. package/dist/service-DsAWXbVX.mjs +0 -1
  54. package/dist/validation-errors-DqCeUW4L.mjs +0 -3
  55. package/dist/validation-errors-DqCeUW4L.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"context-DSi5kfqr.mjs","names":["semverLt","PageDirection","withErrorDiagnostics","parseBoolean","isCLIError","jsonDefaultAgent","logger","formatCommandHint","CLIError","multiline","getPlatformBaseUrl","rememberPlatformConfigForToken","initOAuth2Client","fetchUserInfo","registerAccessTokenSource","normalizeBaseUrl","defaultPlatformBaseUrl","getConsoleBaseUrl","readPackageJson","tightenSecretFilePermissions","writeSecretFile","ensureSecretDir","path","fs","crypto","os","unitToMs","durationPattern","durationArg","z","val","match","digits","assertDefined","duration","value","unit","positiveIntArg","nonNegativeIntArg","orderArg","order","separator","argv","token","machineUser","options","originalEnvKeys","file","files","envPath","required","content","parsed","parseEnv","key","envFiles","envFilesIfExists","JSON_ARG_NAME","VERBOSE_ARG_NAME","GLOBAL_FLAG_PARSER_OPTIONS","globalArgsWereApplied","parseArgv","tokens","name","alias","flag","env","JSON_OUTPUT_ENV_VAR","envEnabled","verbose","source","error","\"TAILOR_JSON_OUTPUT\"","arg","args","commonArgs","option","toCamelCase","envFileArgKeys","envFileArgKeyByToken","extractFields","field","chars","index","booleanAliases","char","result","inlineValue","workspaceArgs","DEFAULT_CONFIG_PATH","configPath","relativeConfigPath","context","profile","configArg","multiConfigArg","deprecatedConfigPath","deploymentArgs","confirmationArgs","SKIP_CONFIRMATION_SUGGESTION","organizationArgs","defaultOrder","pagedLogArgs","folderArgs","LOCK_TIMEOUT_CODE","INSTANCE_ID","lockOwnerSchema","heldLocks","AsyncLocalStorage","localQueues","held","lockPath","fn","previous","turn","resolve","queue","nonce","startedAt","noticeShown","delay","waitedMs","timeoutMs","fd","owner","stat","lock","now","pid","observed","guardPath","current","SERVICE_NAME","entryClass","Entry","raw","account","pfProfileSchema","pfUserSchemaV1","pfUserKeyringSchema","pfUserFileSchema","pfUserSchemaV2","pfUserIdentitySchemaV3","pfUserMetadataV3","pfUserKeyringSchemaV3","pfUserFileSchemaV3","pfUserSchemaV3","pfConfigSchemaV1","V3_MIN_SDK_VERSION","semverSchema","pfConfigSchemaV2","pfConfigSchemaV3","xdgConfig","config","platformUrl","user","platformPrefix","userKey","platformConfig","defaultPlatform","users","entry","email","userEntry","emailMatch","opts","legacyEntry","currentUser","schemas","schema","v2ConfigKeys","v2UserKeys","userTokenKeys","profileKeys","v2OnlyConfigKeys","v3OnlyConfigKeys","v3OnlyUserKeys","keys","v1User","v1Config","v2Config","warnedAboutNewerConfig","sdkVersion","lt","rawConfig","parseYAML","version","minSdk","updateHint","v3Result","v2Result","v1Result","knownKeys","hasKeyringUser","u","diskConfig","stringifyYAML","_accessToken","_refreshToken","keyringEntry","workspaceId","wsId","profileNotFoundError","envMachineUser","explicitMachineUser","explicit","details","pfConfig","profileEntry","stored","envToken","fromProfile","identity","identitySource","tokenStatus","label","aliasKey","canonicalKey","canonicalEntry","existing","extraFields","expiresAt","fromUser","toUser","legacyUser","canonicalUser","TOKEN_REFRESH_MARGIN_MS","MIN_USABLE_TOKEN_LIFETIME_MS","remainingMs","marginMs","rejectedToken","loginFailure","target","latest","loginArgs","request","expired","storedUser","storedConfigUser","client","resp","refreshedTokens","newExpiresAt","previousEmail","resolvedUser","userInfo","RENEWAL_RETRY_INTERVAL_MS","init","renewal","renewalError","retryAt","renewedAt","forcedAt","lastRejected","replacesRejected","accessToken","rejected","findUpSync"],"sources":["../src/cli/shared/args.ts","../src/cli/shared/config-lock.ts","../src/cli/shared/token-store.ts","../src/cli/shared/context.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport { parseEnv } from \"node:util\";\nimport { arg, extractFields, parseArgv, toCamelCase, type ArgSource } from \"@politty/zod\";\nimport { PageDirection } from \"@tailor-platform/tailor-proto/resource_pb\";\nimport * as path from \"pathe\";\nimport { z } from \"zod\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { withErrorDiagnostics } from \"./error-diagnostics\";\nimport { JSON_OUTPUT_ENV_VAR, jsonDefaultAgent, logger, type JsonModeSource } from \"./logger\";\nimport { parseBoolean } from \"./parse-boolean\";\n\ntype ArgsShape = Record<string, z.ZodType>;\nexport type MachineUserInputSource = \"option\" | \"env\";\ntype ResolveMachineUserInputSourceOptions = {\n valueIsExplicit?: boolean;\n};\n\n// ============================================================================\n// Validators\n// ============================================================================\n\nconst durationUnits = [\"ms\", \"s\", \"m\"] as const;\ntype DurationUnit = (typeof durationUnits)[number];\n\nconst unitToMs: Record<DurationUnit, number> = {\n ms: 1,\n s: 1000,\n m: 60 * 1000,\n};\n\nconst durationPattern = /^(\\d+)(ms|s|m)$/;\n\n/**\n * Schema for duration string validation (e.g., \"3s\", \"500ms\", \"1m\")\n * Only validates format; use parseDuration() to convert to milliseconds\n */\nexport const durationArg = z\n .string()\n .refine((val) => durationPattern.test(val), {\n message: \"Invalid duration format. Expected format: '3s', '500ms', '1m'\",\n })\n .refine(\n (val) => {\n const match = val.match(durationPattern);\n if (!match) return false;\n const digits = match[1];\n return digits !== undefined && parseInt(digits, 10) > 0;\n },\n { message: \"Duration must be greater than 0\" },\n );\n\n/**\n * Parse a validated duration string into milliseconds\n * @param duration - Duration string (e.g., \"3s\", \"500ms\", \"1m\")\n * @returns Duration in milliseconds\n */\nexport function parseDuration(duration: string): number {\n const match = assertDefined(\n duration.match(durationPattern),\n `invalid duration format: ${duration}`,\n );\n const value = parseInt(assertDefined(match[1], \"duration digits group missing\"), 10);\n const unit = assertDefined(match[2], \"duration unit group missing\") as DurationUnit;\n return value * unitToMs[unit];\n}\n\n/**\n * Schema for positive integer validation (from string input)\n * Transforms the string to a number\n */\nexport const positiveIntArg = z.coerce.number().int().positive();\n\n/**\n * Schema for non-negative integer validation (from string input).\n * Accepts 0 (used for `--limit 0` to disable the limit).\n */\nexport const nonNegativeIntArg = z.coerce.number().int().nonnegative();\n\n/**\n * Schema for sort order (`asc` or `desc`).\n */\nexport const orderArg = z.enum([\"asc\", \"desc\"]);\n\nexport type Order = z.infer<typeof orderArg>;\n\n/**\n * Translate a CLI `--order` value into the proto `PageDirection` enum.\n * Returns `undefined` when the user did not specify an order so that\n * callers can omit the field and fall back to the server default.\n * @param order - Order string from CLI args (`\"asc\"` | `\"desc\"` | undefined)\n * @returns PageDirection, or undefined when `order` is undefined\n */\nexport function toPageDirection(order: Order | undefined): PageDirection | undefined {\n if (order === undefined) return undefined;\n return order === \"asc\" ? PageDirection.ASC : PageDirection.DESC;\n}\n\n/**\n * Drop the arguments after `--`, which belong to the invoked program.\n * @param argv - Raw CLI argv, excluding the executable and script path\n * @returns The tokens the CLI itself parses as options\n */\nfunction optionTokens(argv: readonly string[]): readonly string[] {\n const separator = argv.indexOf(\"--\");\n return separator === -1 ? argv : argv.slice(0, separator);\n}\n\nfunction hasMachineUserFlag(argv: readonly string[]): boolean {\n return optionTokens(argv).some(\n (token) =>\n token === \"-m\" ||\n token.startsWith(\"-m=\") ||\n token === \"--machine-user\" ||\n token.startsWith(\"--machine-user=\") ||\n token === \"--machineUser\" ||\n token.startsWith(\"--machineUser=\") ||\n token === \"--machineuser\" ||\n token.startsWith(\"--machineuser=\"),\n );\n}\n\n/**\n * Resolve whether a parsed machine user value came from an explicit CLI option or env fallback.\n * @param machineUser - Parsed machine user value\n * @param argv - Raw CLI argv, excluding the executable and script path\n * @param options - Source resolution options\n * @returns Machine user input source, or undefined when no value was parsed\n */\nexport function resolveMachineUserInputSource(\n machineUser: string | undefined,\n argv: readonly string[] = process.argv.slice(2),\n options: ResolveMachineUserInputSourceOptions = {},\n): MachineUserInputSource | undefined {\n if (machineUser === undefined) return undefined;\n if (options.valueIsExplicit) return \"option\";\n if (hasMachineUserFlag(argv)) return \"option\";\n return process.env.TAILOR_PLATFORM_MACHINE_USER_NAME === machineUser ? \"env\" : \"option\";\n}\n\n// ============================================================================\n// Env File Helpers\n// ============================================================================\n\ntype EnvFileArg = string | string[] | undefined;\n\n/**\n * Load env files from parsed arguments.\n * Processes --env-file first, then --env-file-if-exists.\n *\n * Follows Node.js --env-file behavior:\n * - Variables already set in the environment are NOT overwritten\n * - Variables from later files override those from earlier files\n * @param envFiles - Required env file path(s) that must exist\n * @param envFilesIfExists - Optional env file path(s) that are loaded if they exist\n */\nexport function loadEnvFiles(envFiles: EnvFileArg, envFilesIfExists: EnvFileArg): void {\n // Snapshot of originally set environment variables (before loading any files)\n const originalEnvKeys = new Set(Object.keys(process.env));\n\n const load = (files: EnvFileArg, required: boolean) => {\n for (const file of [files ?? []].flat()) {\n const envPath = path.resolve(process.cwd(), file);\n if (!fs.existsSync(envPath)) {\n if (required) {\n throw new Error(`Environment file not found: ${envPath}`);\n }\n continue;\n }\n const content = fs.readFileSync(envPath, \"utf-8\");\n const parsed = parseEnv(content);\n for (const [key, value] of Object.entries(parsed)) {\n // Skip if the variable was originally set in the environment\n if (originalEnvKeys.has(key)) {\n continue;\n }\n // Allow overwriting between env files\n process.env[key] = value;\n }\n }\n };\n\n load(envFiles, true);\n load(envFilesIfExists, false);\n}\n\n// ============================================================================\n// Argument Definitions\n// ============================================================================\n\n/** Name and short alias of the `--json` flag. */\nconst JSON_ARG_NAME = \"json\";\nconst JSON_ARG_ALIAS = \"j\";\nconst VERBOSE_ARG_NAME = \"verbose\";\n\nconst GLOBAL_FLAG_PARSER_OPTIONS = {\n aliasMap: new Map([[JSON_ARG_ALIAS, JSON_ARG_NAME]]),\n booleanFlags: new Set([JSON_ARG_NAME, VERBOSE_ARG_NAME]),\n defaultNegationDisabledFields: new Set<string>(),\n};\n\nlet globalArgsWereApplied = false;\n\n/**\n * Report whether the global arguments have been applied, which happens only\n * after every argument of the command parsed and validated.\n * @returns True once the `--json` effect has run\n */\nexport function globalArgsApplied(): boolean {\n return globalArgsWereApplied;\n}\n\n/**\n * Read the value tokens set for a global boolean flag, coerced the way the CLI\n * coerces the flag and its environment variable.\n * @param tokens - Tokens of the flag, each optionally carrying `=value`\n * @param name - Flag name\n * @returns `true`, `false`, a rejected value unchanged, or undefined when no token sets it\n */\nfunction parseGlobalFlag(tokens: string[], name: string): unknown {\n return parseArgv(tokens, GLOBAL_FLAG_PARSER_OPTIONS).options[name];\n}\n\n/**\n * Read the value the command line gives a global boolean flag. Tokens after\n * `--` are positional values, never flags.\n * @param argv - Command-line arguments after the executable and script path\n * @param name - Flag name\n * @param alias - Short alias of the flag, if it has one\n * @returns `true`, `false`, a rejected value unchanged, or undefined when argv does not set it\n */\nfunction globalFlagValue(argv: readonly string[], name: string, alias?: string): unknown {\n const separator = argv.indexOf(\"--\");\n const options = separator === -1 ? argv : argv.slice(0, separator);\n return parseGlobalFlag(\n options.filter((value) => {\n const [token] = value.split(\"=\", 1);\n return (\n token === `--${name}` ||\n value === `--no-${name}` ||\n (alias !== undefined && token === `-${alias}`)\n );\n }),\n name,\n );\n}\n\n/**\n * Report whether the command line turns `--json` on.\n *\n * A failure during argument parsing or validation ends the command before the\n * `--json` effect sets the logger's mode, so the flag is read from argv instead.\n * @param argv - Command-line arguments after the executable and script path\n * @returns True when argv sets `--json` or `-j` to true\n */\nexport function jsonFlagRequested(argv: readonly string[]): boolean {\n return globalFlagValue(argv, JSON_ARG_NAME, JSON_ARG_ALIAS) === true;\n}\n\n/**\n * Report what requested JSON output, reading the command line, the environment,\n * and the recorded AI coding agent the same way the `--json` argument would.\n * @param argv - Command-line arguments after the executable and script path\n * @returns What requested JSON output, or undefined when it is off\n */\nexport function requestedJsonModeSource(argv: readonly string[]): JsonModeSource | undefined {\n const flag = globalFlagValue(argv, JSON_ARG_NAME, JSON_ARG_ALIAS);\n const env = process.env[JSON_OUTPUT_ENV_VAR];\n const envEnabled =\n env !== undefined && parseGlobalFlag([`--${JSON_ARG_NAME}=${env}`], JSON_ARG_NAME) === true;\n if (flag === true) return envEnabled ? \"both\" : \"flag\";\n if (flag !== undefined) return undefined;\n if (envEnabled) return \"env\";\n if (env === undefined && jsonDefaultAgent() !== undefined) return \"agent\";\n return undefined;\n}\n\n/**\n * Prepare a failure that ended the command before the global arguments were\n * applied (see {@link globalArgsApplied}): apply `--verbose`, and when the\n * command line, the environment, or the recorded AI coding agent asked for JSON\n * output, turn it on and name a plain argument-parsing error `INVALID_ARGUMENTS`.\n * @param error - Failure about to be rendered\n * @param argv - Command-line arguments after the executable and script path\n */\nexport function resolveEarlyFailure(error: unknown, argv: readonly string[]): void {\n const verbose = globalFlagValue(argv, VERBOSE_ARG_NAME);\n if (typeof verbose === \"boolean\") logger.verbose = verbose;\n const source = requestedJsonModeSource(argv);\n if (!source) return;\n logger.setJsonMode(true, source);\n if (\n error instanceof Error &&\n Object.getPrototypeOf(error) === Error.prototype &&\n !Object.hasOwn(error, \"code\")\n ) {\n withErrorDiagnostics(error, { code: \"INVALID_ARGUMENTS\" });\n }\n}\n\n/**\n * Name what set the `--json` value, the way the logger records it.\n * @param source - Where the value was read from\n * @returns What selected JSON output when the value is true\n */\nfunction jsonArgSource(source: ArgSource | undefined): JsonModeSource {\n if (source === \"env\") return \"env\";\n // Only a recorded AI coding agent makes the default true.\n if (source === \"default\") return \"agent\";\n return source === \"cli\" && parseBoolean(process.env[JSON_OUTPUT_ENV_VAR]) === true\n ? \"both\"\n : \"flag\";\n}\n\nexport interface CommonArgsOptions {\n /** Extra short alias for `--verbose` (e.g. `\"v\"`), for plugins that need one */\n verboseAlias?: string;\n}\n\n/**\n * Build the common arguments for all CLI commands. CLI plugins call this so\n * their forwarded global flags parse identically to the host Tailor CLI and\n * feed the same logger state. Only the host CLI records a detected AI coding\n * agent, so under an agent `--json` defaults to true there but not in plugins.\n *\n * NOTE: --env-file and --env-file-if-exists collide with Node.js flags due to a bug\n * (https://github.com/nodejs/node/issues/54232). Node.js parses these even after the\n * script path, causing warnings (twice due to tsx loader).\n * @param options - Per-plugin adjustments to the shared arguments\n * @returns Argument shape suitable for spreading into a command schema\n */\nexport function createCommonArgs(options: CommonArgsOptions = {}) {\n return {\n \"env-file\": arg(z.array(z.string()).optional(), {\n alias: \"e\",\n description: \"Path to an environment file, repeatable (error if not found)\",\n completion: { type: \"file\", matcher: [\".env.*\", \".env\"] },\n }),\n \"env-file-if-exists\": arg(z.array(z.string()).optional(), {\n description: \"Path to an environment file, repeatable (ignored if not found)\",\n completion: { type: \"file\", matcher: [\".env.*\", \".env\"] },\n // Sets nothing new after loadEnvFilesFromArgv; loads the files for runs that skip it.\n effect: (_value, { args }) => {\n loadEnvFiles(\n args[\"env-file\"] as string[] | undefined,\n args[\"env-file-if-exists\"] as string[] | undefined,\n );\n },\n }),\n [VERBOSE_ARG_NAME]: arg(z.boolean().default(false), {\n ...(options.verboseAlias === undefined ? {} : { alias: options.verboseAlias }),\n description: \"Enable verbose logging\",\n negation: true,\n effect: (value, { args }) => {\n logger.verbose = args.$source?.(VERBOSE_ARG_NAME) === \"cli\" ? value : undefined;\n },\n }),\n [JSON_ARG_NAME]: arg(\n z.boolean().default(() => jsonDefaultAgent() !== undefined),\n {\n alias: JSON_ARG_ALIAS,\n description: \"Output as JSON\",\n negation: true,\n env: JSON_OUTPUT_ENV_VAR,\n effect: (value, { args }) => {\n globalArgsWereApplied = true;\n logger.setJsonMode(value, jsonArgSource(args.$source?.(JSON_ARG_NAME)));\n },\n },\n ),\n } satisfies ArgsShape;\n}\n\n/**\n * Common arguments for all CLI commands\n */\nexport const commonArgs = createCommonArgs();\n\ninterface NamedOption {\n cliName: string;\n alias?: readonly string[] | undefined;\n}\n\n/**\n * Spell an option every way the CLI accepts it on the command line.\n * @param option - Option field as `extractFields` describes it\n * @returns `-x` for each one-letter name, and the kebab-case and camelCase forms of each longer one\n */\nexport function flagTokensOf(option: NamedOption): string[] {\n return [option.cliName, ...(option.alias ?? [])].flatMap((name) =>\n name.length === 1 ? [`-${name}`] : [`--${name}`, `--${toCamelCase(name)}`],\n );\n}\n\n/** Env file paths given on the command line, in the order given. */\nexport interface EnvFileArgs {\n envFiles: string[];\n envFilesIfExists: string[];\n}\n\nconst envFileArgKeys = new Map<string, keyof EnvFileArgs>([\n [\"env-file\", \"envFiles\"],\n [\"env-file-if-exists\", \"envFilesIfExists\"],\n]);\n\nconst envFileArgKeyByToken: ReadonlyMap<string, keyof EnvFileArgs> = new Map(\n extractFields(z.strictObject(commonArgs)).fields.flatMap((field) => {\n const key = envFileArgKeys.get(field.name);\n if (key === undefined) return [];\n return flagTokensOf(field).map((token) => [token, key] as const);\n }),\n);\n\n/**\n * List the short aliases of the global boolean flags.\n * @param options - Per-plugin adjustments the common arguments were built with\n * @returns Every alias of a boolean flag in the common arguments\n */\nfunction globalBooleanAliases(options: CommonArgsOptions): ReadonlySet<string> {\n return new Set(\n extractFields(z.strictObject(createCommonArgs(options)))\n .fields.filter((field) => field.type === \"boolean\")\n .flatMap((field) => field.alias ?? []),\n );\n}\n\ninterface OptionToken {\n flag: string;\n value: string | undefined;\n}\n\n/**\n * Split an option token into its flag and the value it carries. A short-option\n * bundle such as `-je.env` yields its first option that is not a global\n * boolean, with the rest of the bundle as the value.\n * @param token - Command-line token\n * @param booleanAliases - Short aliases of the global boolean flags\n * @returns The flag, and its value when the token carries one\n */\nfunction splitOptionToken(token: string, booleanAliases: ReadonlySet<string>): OptionToken {\n if (\n token.startsWith(\"-\") &&\n !token.startsWith(\"--\") &&\n token.length > 2 &&\n !token.includes(\"=\")\n ) {\n const chars = Array.from(token.slice(1));\n const index = chars.findIndex((char) => !booleanAliases.has(char));\n if (index === -1) return { flag: token, value: undefined };\n const value = chars.slice(index + 1).join(\"\");\n return { flag: `-${chars[index]}`, value: value === \"\" ? undefined : value };\n }\n const separator = token.indexOf(\"=\");\n return separator === -1\n ? { flag: token, value: undefined }\n : { flag: token.slice(0, separator), value: token.slice(separator + 1) };\n}\n\n/**\n * Read the env file paths given on the command line. A short-option bundle\n * counts only when every option before `-e` in it is a global boolean, as in\n * `-je .env`.\n * @param argv - Command-line arguments after the executable and script path\n * @param options - Options passed to {@link createCommonArgs} for the global arguments\n * @returns Every `--env-file` and `--env-file-if-exists` value before `--`\n */\nexport function readEnvFileArgs(\n argv: readonly string[],\n options: CommonArgsOptions = {},\n): EnvFileArgs {\n const result: EnvFileArgs = { envFiles: [], envFilesIfExists: [] };\n const booleanAliases = globalBooleanAliases(options);\n const tokens = optionTokens(argv);\n for (let index = 0; index < tokens.length; index++) {\n const { flag, value: inlineValue } = splitOptionToken(tokens[index] ?? \"\", booleanAliases);\n const key = envFileArgKeyByToken.get(flag);\n if (key === undefined) continue;\n if (inlineValue !== undefined) {\n result[key].push(inlineValue);\n continue;\n }\n const value = tokens[index + 1];\n if (value !== undefined && !value.startsWith(\"-\")) {\n result[key].push(value);\n index++;\n }\n }\n return result;\n}\n\n/**\n * Load the env files given on the command line, so that options backed by an\n * environment variable read the values these files set. Call it before the\n * CLI parses its arguments, such as from the `setup` hook of `runMain`.\n * @param argv - Command-line arguments after the executable and script path\n * @param options - Options passed to {@link createCommonArgs} for the global arguments\n */\nexport function loadEnvFilesFromArgv(\n argv: readonly string[],\n options: CommonArgsOptions = {},\n): void {\n const { envFiles, envFilesIfExists } = readEnvFileArgs(argv, options);\n loadEnvFiles(envFiles, envFilesIfExists);\n}\n\n/**\n * Arguments for commands that require workspace context\n */\nexport const workspaceArgs = {\n \"workspace-id\": arg(z.string().optional(), {\n alias: \"w\",\n description: \"Workspace ID\",\n env: \"TAILOR_PLATFORM_WORKSPACE_ID\",\n completion: { type: \"none\" },\n }),\n profile: arg(z.string().optional(), {\n alias: \"p\",\n description: \"Workspace profile\",\n env: \"TAILOR_PLATFORM_PROFILE\",\n completion: { type: \"none\" },\n }),\n} satisfies ArgsShape;\n\n/**\n * Default config file path used when --config is not passed\n */\nexport const DEFAULT_CONFIG_PATH = \"tailor.config.ts\";\n\n/**\n * Format the --config argument for remediation command hints so they target\n * the same config the current run used. The `--config=<value>` form keeps a\n * leading-hyphen path bound as the option value.\n * @param {string} [configPath] - Config path the current run used, if any\n * @returns {string | undefined} `--config=<path>` argument, or undefined when the default config is in use\n */\nexport function formatConfigArg(configPath?: string): string | undefined {\n if (!configPath) return undefined;\n const relativeConfigPath = path.relative(process.cwd(), configPath);\n if (relativeConfigPath === DEFAULT_CONFIG_PATH) return undefined;\n return `--config=${relativeConfigPath}`;\n}\n\n/** Profile and workspace selection the current run used. */\nexport interface RecoveryContext {\n profile?: string | undefined;\n workspaceId?: string | undefined;\n}\n\n/**\n * Arguments that make a hinted follow-up command select the same profile and\n * workspace as the current run. The `--option=<value>` form keeps a\n * leading-hyphen value bound as the option value.\n * @param {RecoveryContext} context - Profile and workspace id the current run used\n * @returns {readonly string[]} Arguments to append to the hinted command\n */\nexport function recoveryContextArgs(context: RecoveryContext): readonly string[] {\n return [\n ...(context.workspaceId ? [`--workspace-id=${context.workspaceId}`] : []),\n ...(context.profile ? [`--profile=${context.profile}`] : []),\n ];\n}\n\n/**\n * Arguments for a hinted `tailor profile update` command. The profile name\n * comes first unless it starts with a hyphen, which only parses after `--`.\n * @param {string} profile - Profile to update\n * @param {readonly string[]} options - Options to set on the profile\n * @returns {readonly string[]} Arguments following the `tailor` executable\n */\nexport function profileUpdateArgs(profile: string, options: readonly string[]): readonly string[] {\n return profile.startsWith(\"-\")\n ? [\"profile\", \"update\", ...options, \"--\", profile]\n : [\"profile\", \"update\", profile, ...options];\n}\n\n/**\n * Shared config arg for commands that accept a config file path\n */\nexport const configArg = {\n config: arg(z.string().default(DEFAULT_CONFIG_PATH), {\n alias: \"c\",\n description: \"Path to Tailor config file\",\n env: \"TAILOR_CONFIG_PATH\",\n completion: { type: \"file\", extensions: [\"ts\"] },\n }),\n} satisfies ArgsShape;\n\n/**\n * Shared config arg for commands that accept one or more comma-separated config file paths\n */\nexport const multiConfigArg = {\n config: arg(z.string().default(DEFAULT_CONFIG_PATH), {\n alias: \"c\",\n description:\n \"Path to SDK config file. Use comma-separated paths to deploy multiple apps together.\",\n env: \"TAILOR_CONFIG_PATH\",\n completion: { type: \"file\", extensions: [\"ts\"] },\n }),\n} satisfies ArgsShape;\n\n/**\n * Read the deploy config paths set through the environment, warning when the deprecated TAILOR_PLATFORM_SDK_CONFIG_PATH supplies them.\n * @returns TAILOR_CONFIG_PATH, or the deprecated TAILOR_PLATFORM_SDK_CONFIG_PATH; empty values count as not set\n */\nexport function readDeployConfigPathEnv(): string | undefined {\n const configPath = process.env.TAILOR_CONFIG_PATH;\n if (configPath) return configPath;\n const deprecatedConfigPath = process.env.TAILOR_PLATFORM_SDK_CONFIG_PATH;\n if (!deprecatedConfigPath) return undefined;\n logger.warn(\n \"TAILOR_PLATFORM_SDK_CONFIG_PATH is deprecated. Please use TAILOR_CONFIG_PATH instead.\",\n );\n return deprecatedConfigPath;\n}\n\n/**\n * Arguments for commands that interact with deployed resources (includes config)\n */\nexport const deploymentArgs = {\n ...workspaceArgs,\n ...configArg,\n} satisfies ArgsShape;\n\n/**\n * Arguments for commands that require confirmation\n */\nexport const confirmationArgs = {\n yes: arg(z.boolean().default(false), {\n alias: \"y\",\n description: \"Skip confirmation prompts\",\n }),\n} satisfies ArgsShape;\n\n/** Suggestion for a confirmation prompt that {@link confirmationArgs} skips but cannot be shown. */\nexport const SKIP_CONFIRMATION_SUGGESTION = \"Pass --yes to skip the confirmation.\";\n\n/**\n * Arguments for commands that require organization context\n */\nexport const organizationArgs = {\n \"organization-id\": arg(z.string(), {\n alias: \"o\",\n description: \"Organization ID\",\n env: \"TAILOR_PLATFORM_ORGANIZATION_ID\",\n completion: { type: \"none\" },\n }),\n} satisfies ArgsShape;\n\n/**\n * Arguments for list commands that accept `--order` / `--limit`. Sort\n * order defaults to `desc` (newest first) because most callers want the\n * latest items; pass `--order asc` to opt in to ascending order. The\n * limit is unbounded by default so existing invocations keep returning\n * every item; pass `--limit N` to cap the result size.\n * @param defaultOrder - Default value for `--order` (defaults to `\"desc\"`)\n * @returns Argument shape suitable for spreading into a command schema\n */\nexport const paginationArgs = (defaultOrder: Order = \"desc\") =>\n ({\n order: arg(orderArg.default(defaultOrder), {\n description: \"Sort order (asc or desc)\",\n }),\n limit: arg(nonNegativeIntArg.optional(), {\n alias: \"l\",\n description: \"Maximum number of items to return (0 or omit: unlimited)\",\n }),\n }) satisfies ArgsShape;\n\n/**\n * Arguments for time-series log list commands. Defaults to newest-first\n * (`desc`) and a 50-item cap so that listing stays responsive on busy\n * workspaces. Pass `--limit 0` to disable the cap and fetch all entries.\n */\nexport const pagedLogArgs = {\n order: arg(orderArg.default(\"desc\"), {\n description: \"Sort order (asc or desc)\",\n }),\n limit: arg(nonNegativeIntArg.default(50), {\n alias: \"l\",\n description: \"Maximum number of items to return (0: unlimited)\",\n }),\n} satisfies ArgsShape;\n\n/**\n * Arguments for commands that require folder context\n */\nexport const folderArgs = {\n \"folder-id\": arg(z.string(), {\n alias: \"f\",\n description: \"Folder ID\",\n env: \"TAILOR_PLATFORM_FOLDER_ID\",\n completion: { type: \"none\" },\n }),\n} satisfies ArgsShape;\n\ntype LocationIdName = \"organization-id\" | \"folder-id\";\n\ntype LocationIdArgs = {\n [name in LocationIdName]?: string | undefined;\n} & {\n $source?: ((name: LocationIdName) => ArgSource) | undefined;\n};\n\n/**\n * Read the organization and folder ID options.\n * @param args - Parsed command arguments\n * @returns Organization and folder IDs; empty values from the environment count as not given\n */\nexport function locationIds(args: LocationIdArgs): {\n organizationId?: string;\n folderId?: string;\n} {\n const read = (name: LocationIdName) => {\n const value = args[name];\n return value === \"\" && args.$source?.(name) === \"env\" ? undefined : value;\n };\n return { organizationId: read(\"organization-id\"), folderId: read(\"folder-id\") };\n}\n\nexport type CommonArgsType = z.infer<z.ZodObject<typeof commonArgs>>;\n","import { AsyncLocalStorage } from \"node:async_hooks\";\nimport * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"pathe\";\nimport { z } from \"zod\";\nimport { CLIError, isCLIError } from \"./errors\";\nimport { logger } from \"./logger\";\nimport { ensureSecretDir } from \"./secret-file\";\n\nconst MAX_LOCK_AGE_MS = 2 * 60 * 1000;\nconst DEFAULT_TIMEOUT_MS = MAX_LOCK_AGE_MS + 30_000;\nconst UNWRITTEN_LOCK_AGE_MS = 10_000;\nconst RECLAIM_GUARD_AGE_MS = 10_000;\nconst WAIT_NOTICE_DELAY_MS = 3_000;\nconst MAX_RETRY_DELAY_MS = 250;\nconst LOCK_TIMEOUT_CODE = \"CONFIG_LOCK_TIMEOUT\";\n\nconst INSTANCE_ID = crypto.randomUUID();\n\n// A lock written by a newer SDK may carry more fields.\nconst lockOwnerSchema = z.looseObject({\n pid: z.number().int(),\n hostname: z.string(),\n instanceId: z.string(),\n nonce: z.string(),\n createdAt: z.number(),\n});\n\ntype LockOwner = z.output<typeof lockOwnerSchema>;\n\ntype ObservedLock = {\n content: string;\n ino: number;\n mtimeMs: number;\n owner: LockOwner | undefined;\n};\n\nexport type ConfigLockOptions = {\n /** How long to wait for another process to release the lock, in milliseconds. */\n timeoutMs?: number;\n};\n\nconst heldLocks = new AsyncLocalStorage<ReadonlySet<string>>();\nconst localQueues = new Map<string, Promise<void>>();\n\n/**\n * Run a callback while holding an exclusive lock that every process on this host respects.\n * Callers in the same process wait their turn, and a callback that is already holding the\n * lock can take it again.\n * @param lockPath - Lock file path\n * @param fn - Callback to run while holding the lock\n * @param options - Lock options\n * @returns The callback's result\n */\nexport async function withConfigLock<T>(\n lockPath: string,\n fn: () => Promise<T>,\n options: ConfigLockOptions = {},\n): Promise<T> {\n const held = heldLocks.getStore();\n if (held?.has(lockPath)) return await fn();\n\n const previous = localQueues.get(lockPath) ?? Promise.resolve();\n let releaseLocal = () => {};\n const turn = new Promise<void>((resolve) => {\n releaseLocal = resolve;\n });\n const queue = previous.then(() => turn);\n localQueues.set(lockPath, queue);\n await previous;\n try {\n const nonce = await acquireFileLock(lockPath, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n try {\n return await heldLocks.run(new Set([...(held ?? []), lockPath]), fn);\n } finally {\n releaseFileLock(lockPath, nonce);\n }\n } finally {\n releaseLocal();\n if (localQueues.get(lockPath) === queue) localQueues.delete(lockPath);\n }\n}\n\n/**\n * Whether an error is the timeout {@link withConfigLock} throws when the lock stays held.\n * @param error - Error to check\n * @returns True for a lock timeout\n */\nexport function isConfigLockTimeout(error: unknown): boolean {\n return isCLIError(error) && error.code === LOCK_TIMEOUT_CODE;\n}\n\nasync function acquireFileLock(lockPath: string, timeoutMs: number): Promise<string> {\n ensureSecretDir(path.dirname(lockPath));\n const nonce = crypto.randomUUID();\n const startedAt = Date.now();\n let noticeShown = false;\n let delay = 10;\n for (;;) {\n if (tryCreateLock(lockPath, nonce)) return nonce;\n if (reclaimIfStale(lockPath)) continue;\n const waitedMs = Date.now() - startedAt;\n if (waitedMs >= timeoutMs) throw lockTimeoutError(lockPath);\n if (!noticeShown && waitedMs >= WAIT_NOTICE_DELAY_MS) {\n noticeShown = true;\n logger.info(`Waiting for another tailor command to release ${lockPath}...`);\n }\n await new Promise((resolve) => setTimeout(resolve, delay * (0.5 + Math.random())));\n delay = Math.min(delay * 2, MAX_RETRY_DELAY_MS);\n }\n}\n\nfunction tryCreateLock(lockPath: string, nonce: string): boolean {\n let fd: number;\n try {\n fd = fs.openSync(lockPath, \"wx\", 0o600);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\") return false;\n throw error;\n }\n const owner: LockOwner = {\n pid: process.pid,\n hostname: os.hostname(),\n instanceId: INSTANCE_ID,\n nonce,\n createdAt: Date.now(),\n };\n try {\n fs.writeSync(fd, JSON.stringify(owner));\n } catch (error) {\n fs.closeSync(fd);\n fs.rmSync(lockPath, { force: true });\n throw error;\n }\n fs.closeSync(fd);\n return true;\n}\n\nfunction readLock(lockPath: string): ObservedLock | undefined {\n let stat: fs.Stats;\n let content: string;\n try {\n stat = fs.statSync(lockPath);\n content = fs.readFileSync(lockPath, \"utf-8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw error;\n }\n return { content, ino: stat.ino, mtimeMs: stat.mtimeMs, owner: parseOwner(content) };\n}\n\nfunction parseOwner(content: string): LockOwner | undefined {\n try {\n const result = lockOwnerSchema.safeParse(JSON.parse(content));\n return result.success ? result.data : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isStale(lock: ObservedLock): boolean {\n const { owner } = lock;\n const now = Date.now();\n if (!owner) return now - lock.mtimeMs > UNWRITTEN_LOCK_AGE_MS;\n if (now - owner.createdAt > MAX_LOCK_AGE_MS) return true;\n if (owner.hostname !== os.hostname()) return false;\n // Another thread may hold a lock with this pid; this module never acquires while holding one.\n if (owner.pid === process.pid) return owner.instanceId === INSTANCE_ID;\n return !isProcessAlive(owner.pid);\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n\n/**\n * Remove a stale lock. Only the process holding the reclaim guard removes it, and only if\n * the lock is still the one judged stale.\n * @param lockPath - Lock file path\n * @returns Whether creating the lock can be retried right away\n */\nfunction reclaimIfStale(lockPath: string): boolean {\n const observed = readLock(lockPath);\n if (!observed) return true;\n if (!isStale(observed)) return false;\n\n const guardPath = `${lockPath}.reclaim`;\n if (!tryCreateGuard(guardPath)) return false;\n try {\n const current = readLock(lockPath);\n if (\n current?.ino === observed.ino &&\n current.mtimeMs === observed.mtimeMs &&\n current.content === observed.content\n ) {\n fs.rmSync(lockPath, { force: true });\n }\n return true;\n } finally {\n fs.rmSync(guardPath, { force: true });\n }\n}\n\nfunction tryCreateGuard(guardPath: string): boolean {\n try {\n fs.closeSync(fs.openSync(guardPath, \"wx\", 0o600));\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n }\n try {\n if (Date.now() - fs.statSync(guardPath).mtimeMs > RECLAIM_GUARD_AGE_MS) {\n fs.rmSync(guardPath, { force: true });\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n return false;\n}\n\nfunction releaseFileLock(lockPath: string, nonce: string): void {\n if (readLock(lockPath)?.owner?.nonce === nonce) {\n fs.rmSync(lockPath, { force: true });\n }\n}\n\nfunction lockTimeoutError(lockPath: string): Error {\n return CLIError({\n code: LOCK_TIMEOUT_CODE,\n message: `Timed out waiting for another tailor command to release ${lockPath}.`,\n suggestion:\n \"Wait for the other tailor commands to finish, then retry. If none is running, delete the lock file.\",\n context: { lockPath },\n });\n}\n","import { logger } from \"./logger\";\n\nconst SERVICE_NAME = \"tailor-platform-cli\";\n\ntype TokenData = {\n accessToken: string;\n refreshToken?: string;\n};\n\ntype EntryLike = {\n setPassword(password: string): void;\n getPassword(): string | null;\n deletePassword(): void;\n};\n\ntype EntryConstructor = new (service: string, account: string) => EntryLike;\n\nlet entryClass: EntryConstructor | false | undefined;\n\nasync function getEntryClass(): Promise<EntryConstructor | false> {\n if (entryClass !== undefined) return entryClass;\n\n try {\n const mod = await import(\"@napi-rs/keyring\");\n entryClass = mod.Entry;\n } catch {\n logger.warn(\n \"System keyring is not available. Tokens will be stored in the config file. Set TAILOR_PLATFORM_TOKEN environment variable for CI environments.\",\n );\n entryClass = false;\n }\n\n return entryClass;\n}\n\n/**\n * Check whether the native keyring library can be loaded.\n * @returns true if the library is available; individual operations may still fail\n */\nexport async function isKeyringAvailable(): Promise<boolean> {\n return (await getEntryClass()) !== false;\n}\n\n/**\n * Load tokens from the OS keyring for a given account.\n * @param account - User identifier (e.g. email or client ID)\n * @returns Token data or undefined if not found or the stored JSON is invalid\n * @throws If the keyring library is unavailable or the keyring cannot be read\n */\nexport async function loadKeyringTokens(account: string): Promise<TokenData | undefined> {\n const Entry = await getEntryClass();\n if (!Entry) throw new Error(\"System keyring is not available.\");\n\n const entry = new Entry(SERVICE_NAME, account);\n const raw = entry.getPassword();\n if (raw === null) return undefined;\n try {\n return JSON.parse(raw) as TokenData;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Save tokens to the OS keyring for a given account.\n * @param account - User identifier (e.g. email or client ID)\n * @param tokens - Token data to store\n */\nexport async function saveKeyringTokens(account: string, tokens: TokenData): Promise<void> {\n const Entry = await getEntryClass();\n if (!Entry) throw new Error(\"System keyring is not available.\");\n\n const entry = new Entry(SERVICE_NAME, account);\n entry.setPassword(JSON.stringify(tokens));\n}\n\n/**\n * Delete tokens from the OS keyring for a given account.\n * @param account - User identifier (e.g. email or client ID)\n */\nexport async function deleteKeyringTokens(account: string): Promise<void> {\n const Entry = await getEntryClass();\n if (!Entry) return;\n\n try {\n const entry = new Entry(SERVICE_NAME, account);\n entry.deletePassword();\n } catch {\n // Ignore \"not found\" errors\n }\n}\n\n/**\n * Reset the cached keyring state. Used for testing.\n */\nexport function resetKeyringState(): void {\n entryClass = undefined;\n}\n\nexport type { TokenData };\n","import * as fs from \"node:fs\";\nimport { parseYAML, stringifyYAML } from \"confbox\";\nimport { findUpSync } from \"find-up-simple\";\nimport * as path from \"pathe\";\nimport { lt as semverLt } from \"semver\";\nimport { xdgConfig } from \"xdg-basedir\";\nimport { z } from \"zod\";\nimport { assertDefined } from \"#/utils/assert\";\nimport ml from \"#/utils/multiline\";\nimport { type MachineUserInputSource, profileUpdateArgs, recoveryContextArgs } from \"./args\";\nimport {\n defaultPlatformBaseUrl,\n fetchUserInfo,\n getConsoleBaseUrl,\n getPlatformBaseUrl,\n initOAuth2Client,\n normalizeBaseUrl,\n registerAccessTokenSource,\n rememberPlatformConfigForToken,\n type AccessTokenSource,\n type PlatformClientConfig,\n} from \"./client\";\nimport { type ConfigLockOptions, isConfigLockTimeout, withConfigLock } from \"./config-lock\";\nimport { CLIError, formatCommandHint, profileNotFoundError } from \"./errors\";\nimport { logger } from \"./logger\";\nimport { readPackageJson } from \"./package-json\";\nimport { tightenSecretFilePermissions, writeSecretFile } from \"./secret-file\";\nimport {\n isKeyringAvailable,\n loadKeyringTokens,\n saveKeyringTokens,\n deleteKeyringTokens,\n} from \"./token-store\";\n\n// Config schemas keep unknown keys so that rewriting a file written by a newer SDK does not drop them.\nconst pfProfileSchema = z.looseObject({\n user: z.string(),\n workspace_id: z.string(),\n readonly: z.boolean().optional(),\n machine_user: z.string().optional(),\n machine_user_override: z.enum([\"allow\", \"deny\"]).optional(),\n platform_url: z.url().optional(),\n oauth2_client_id: z.string().optional(),\n console_url: z.url().optional(),\n});\n\nconst pfUserSchemaV1 = z.looseObject({\n access_token: z.string(),\n refresh_token: z.string().optional(),\n token_expires_at: z.string(),\n});\n\nconst pfUserKeyringSchema = z.looseObject({\n storage: z.literal(\"keyring\"),\n token_expires_at: z.string(),\n});\n\nconst pfUserFileSchema = z.looseObject({\n storage: z.literal(\"file\"),\n token_expires_at: z.string(),\n access_token: z.string(),\n refresh_token: z.string().optional(),\n});\n\nconst pfUserSchemaV2 = z.discriminatedUnion(\"storage\", [pfUserKeyringSchema, pfUserFileSchema]);\n\nconst pfUserIdentitySchemaV3 = z.strictObject({\n email: z.string().optional(),\n});\n\nconst pfUserMetadataV3 = {\n ...pfUserIdentitySchemaV3.shape,\n default_organization_id: z.string().optional(),\n default_folder_id: z.string().optional(),\n};\n\nconst pfUserKeyringSchemaV3 = pfUserKeyringSchema.extend(pfUserMetadataV3);\n\nconst pfUserFileSchemaV3 = pfUserFileSchema.extend(pfUserMetadataV3);\n\nconst pfUserSchemaV3 = z.discriminatedUnion(\"storage\", [pfUserKeyringSchemaV3, pfUserFileSchemaV3]);\n\nconst pfConfigSchemaV1 = z.looseObject({\n version: z.literal(1),\n users: z.partialRecord(z.string(), pfUserSchemaV1),\n profiles: z.partialRecord(z.string(), pfProfileSchema),\n current_user: z.string().nullable(),\n});\n\nconst V2_CONFIG_VERSION = 2;\nconst LATEST_CONFIG_VERSION = 3;\nconst V2_MIN_SDK_VERSION = \"1.29.0\";\nconst V3_MIN_SDK_VERSION = \"2.0.0\";\n\nconst semverSchema = z.templateLiteral([\n z.number().int(),\n \".\",\n z.number().int(),\n \".\",\n z.number().int(),\n]);\n\nconst pfConfigSchemaV2 = z.looseObject({\n version: z.literal(V2_CONFIG_VERSION),\n min_sdk_version: semverSchema,\n latest_version: z.number().int().optional(),\n latest_min_sdk_version: semverSchema.optional(),\n users: z.partialRecord(z.string(), pfUserSchemaV2),\n profiles: z.partialRecord(z.string(), pfProfileSchema),\n current_user: z.string().nullable(),\n});\n\nconst pfConfigSchemaV3 = z.looseObject({\n version: z.literal(LATEST_CONFIG_VERSION),\n min_sdk_version: semverSchema,\n latest_version: z.number().int().optional(),\n latest_min_sdk_version: semverSchema.optional(),\n users: z.partialRecord(z.string(), pfUserSchemaV3),\n profiles: z.partialRecord(z.string(), pfProfileSchema),\n current_user: z.string().nullable(),\n});\n\ntype PfConfigV1 = z.output<typeof pfConfigSchemaV1>;\ntype PfConfigV2 = z.output<typeof pfConfigSchemaV2>;\ntype PfConfig = z.output<typeof pfConfigSchemaV3>;\ntype PfUser = z.output<typeof pfUserSchemaV3>;\ntype UserTokens = { accessToken: string; refreshToken?: string };\ntype PfConfigV3 = PfConfig;\ntype LoadWorkspaceIdOptions = {\n workspaceId?: string;\n profile?: string;\n};\ntype LoadAccessTokenOptions = {\n profile?: string;\n};\ntype LoadPlatformClientConfigOptions = {\n profile?: string;\n allowMissingProfile?: boolean;\n};\ntype LoadConsoleBaseUrlOptions = {\n profile?: string;\n allowMissingProfile?: boolean;\n};\ntype LoadMachineUserNameOptions = {\n machineUser?: string;\n machineUserSource?: MachineUserInputSource;\n profile?: string;\n};\ntype ExplicitMachineUser = {\n source: MachineUserInputSource;\n value: string;\n};\n\nexport type AuthStatus = {\n authenticated: boolean;\n identity: string | null;\n identitySource: \"environment\" | \"profile\" | \"default\" | \"none\";\n profile: string | null;\n workspaceId: string | null;\n permission: \"read\" | \"write\";\n platformUrl: string;\n tokenStatus: \"environment\" | \"valid\" | \"refreshable\" | \"expired\" | \"missing\";\n};\n\nfunction platformConfigPath() {\n if (!xdgConfig) {\n throw new Error(\"User home directory not found\");\n }\n return path.join(xdgConfig, \"tailor-platform\", \"config.yaml\");\n}\n\n/**\n * Whether the platform config file exists. Unlike `readPlatformConfig`, this never creates it,\n * so a background check can run on a machine that has never logged in without side effects.\n * @returns true when the config file is present\n */\nexport function platformConfigExists(): boolean {\n if (!xdgConfig) return false;\n return fs.existsSync(platformConfigPath());\n}\n\ntype ProfilePlatformSettings = {\n platform_url?: string;\n oauth2_client_id?: string;\n console_url?: string;\n};\n\n/**\n * Convert stored profile platform fields to platform client settings.\n * @param profile - Profile platform settings\n * @returns Platform client settings\n */\nexport function platformConfigFromProfile(\n profile: ProfilePlatformSettings | undefined,\n): PlatformClientConfig | undefined {\n const config = {\n ...(profile?.platform_url ? { platformUrl: profile.platform_url } : {}),\n ...(profile?.oauth2_client_id ? { oauth2ClientId: profile.oauth2_client_id } : {}),\n ...(profile?.console_url ? { consoleUrl: profile.console_url } : {}),\n };\n return Object.keys(config).length > 0 ? config : undefined;\n}\n\nfunction platformUserKey(user: string, config?: PlatformClientConfig): string {\n const platformUrl = getPlatformBaseUrl(config);\n if (platformUrl === normalizeBaseUrl(defaultPlatformBaseUrl)) {\n return user;\n }\n return `${platformUrl}|${user}`;\n}\n\nfunction userFromPlatformUserKey(userKey: string, config?: PlatformClientConfig): string {\n const platformPrefix = `${getPlatformBaseUrl(config)}|`;\n return userKey.startsWith(platformPrefix) ? userKey.slice(platformPrefix.length) : userKey;\n}\n\nfunction canUseLegacyUserKey(platformUrl: string): boolean {\n try {\n return getPlatformBaseUrl() === platformUrl;\n } catch {\n return false;\n }\n}\n\ntype UserEntryLookupOptions = {\n allowLegacyUserKey?: boolean;\n};\n\nfunction findUserByEmail(\n users: PfConfig[\"users\"],\n email: string,\n platformConfig?: PlatformClientConfig,\n) {\n const platformUrl = getPlatformBaseUrl(platformConfig);\n const platformPrefix = `${platformUrl}|`;\n const defaultPlatform = platformUrl === normalizeBaseUrl(defaultPlatformBaseUrl);\n return Object.entries(users).find(([key, entry]) => {\n if (entry?.email !== email) return false;\n return defaultPlatform ? !key.includes(\"|\") : key.startsWith(platformPrefix);\n });\n}\n\nfunction findUserEntry(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts: UserEntryLookupOptions = {},\n) {\n const userKey = platformUserKey(user, platformConfig);\n const userEntry = config.users[userKey];\n if (userEntry) {\n return { userKey, userEntry };\n }\n const emailMatch = findUserByEmail(config.users, user, platformConfig);\n if (emailMatch?.[1]) {\n return { userKey: emailMatch[0], userEntry: emailMatch[1] };\n }\n const platformUrl = getPlatformBaseUrl(platformConfig);\n if (\n userKey !== user &&\n (opts.allowLegacyUserKey === false || !canUseLegacyUserKey(platformUrl))\n ) {\n return { userKey, userEntry };\n }\n const legacyEntry = config.users[user];\n return legacyEntry ? { userKey: user, userEntry: legacyEntry } : { userKey, userEntry };\n}\n\n/**\n * Resolve the config user key that would be used for a user on the selected platform.\n * @param config - Platform config\n * @param user - User name\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n * @returns Resolved config user key\n */\nexport function resolveUserTokenKey(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts?: UserEntryLookupOptions,\n): string {\n return findUserEntry(config, user, platformConfig, opts).userKey;\n}\n\nexport function resolveConfigUser(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts?: UserEntryLookupOptions,\n): string | undefined {\n const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);\n return userEntry ? userFromPlatformUserKey(userKey, platformConfig) : undefined;\n}\n\n/**\n * Check whether tokens are registered for a user on the selected platform.\n * @param config - Platform config\n * @param user - User name\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n * @returns True when the user has a registered token entry\n */\nexport function hasUserTokenEntry(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts?: UserEntryLookupOptions,\n): boolean {\n return findUserEntry(config, user, platformConfig, opts).userEntry !== undefined;\n}\n\nfunction hasUserKeyForName(users: Record<string, unknown>, user: string): boolean {\n return users[user] !== undefined || Object.keys(users).some((key) => key.endsWith(`|${user}`));\n}\n\nfunction hasUserEmailEntry(users: PfConfig[\"users\"], user: string): boolean {\n return Object.values(users).some((entry) => entry?.email === user);\n}\n\n/**\n * Check whether any platform has tokens registered for a user.\n * @param config - Platform config\n * @param user - User name\n * @returns True when the user has a token entry for any platform\n */\nexport function hasAnyUserTokenEntry(config: Pick<PfConfig, \"users\">, user: string): boolean {\n return hasUserKeyForName(config.users, user) || hasUserEmailEntry(config.users, user);\n}\n\nfunction hasCurrentUserEntry(users: PfConfigV1[\"users\"], currentUser: string): boolean {\n return hasUserKeyForName(users, currentUser);\n}\n\ntype ObjectSchema = { shape: object };\n\nfunction declaredKeys(...schemas: ObjectSchema[]): Set<string> {\n return new Set(schemas.flatMap((schema) => Object.keys(schema.shape)));\n}\n\nconst v2ConfigKeys = declaredKeys(pfConfigSchemaV2);\nconst v2UserKeys = declaredKeys(pfUserKeyringSchema, pfUserFileSchema);\nconst userTokenKeys = v2UserKeys.union(declaredKeys(pfUserIdentitySchemaV3));\nconst profileKeys = declaredKeys(pfProfileSchema);\n// An older format does not validate keys a later format declares, so migration drops them.\nconst v2OnlyConfigKeys = v2ConfigKeys.difference(declaredKeys(pfConfigSchemaV1));\nconst v3OnlyConfigKeys = declaredKeys(pfConfigSchemaV3).difference(v2ConfigKeys);\nconst v3OnlyUserKeys = declaredKeys(pfUserKeyringSchemaV3, pfUserFileSchemaV3).difference(\n v2UserKeys,\n);\n\nfunction withoutKeys<T extends object>(entry: T, keys: ReadonlySet<string>): T {\n return Object.fromEntries(Object.entries(entry).filter(([key]) => !keys.has(key))) as T;\n}\n\n/**\n * Migrate a v1 config to v2.\n * Tokens are kept in the config file (storage: \"file\") during migration.\n * They will be moved to the OS keyring on next login or token refresh.\n * @param v1Config - v1 configuration to migrate\n * @returns Migrated v2 configuration\n */\nfunction migrateV1ToV2(v1Config: PfConfigV1): PfConfigV2 {\n const users: PfConfigV2[\"users\"] = {};\n\n for (const [name, v1User] of Object.entries(v1Config.users)) {\n if (!v1User) continue;\n\n users[name] = { ...withoutKeys(v1User, v3OnlyUserKeys), storage: \"file\" };\n }\n\n return {\n ...withoutKeys(v1Config, v2OnlyConfigKeys),\n version: V2_CONFIG_VERSION,\n min_sdk_version: V2_MIN_SDK_VERSION,\n users,\n };\n}\n\nfunction inferEmailFromUserId(user: string): string | undefined {\n return z.email().safeParse(user).success ? user : undefined;\n}\n\nfunction migrateV2ToV3(v2Config: PfConfigV2): PfConfig {\n const users: PfConfig[\"users\"] = {};\n\n for (const [user, entry] of Object.entries(v2Config.users)) {\n if (!entry) continue;\n const email = inferEmailFromUserId(user);\n users[user] = {\n ...withoutKeys(entry, v3OnlyUserKeys),\n ...(email ? { email } : {}),\n };\n }\n\n return {\n ...withoutKeys(v2Config, v3OnlyConfigKeys),\n version: LATEST_CONFIG_VERSION,\n min_sdk_version: V3_MIN_SDK_VERSION,\n users,\n };\n}\n\nfunction migrateV1ToV3(v1Config: PfConfigV1): PfConfig {\n return migrateV2ToV3(migrateV1ToV2(v1Config));\n}\n\nfunction formatUnknownError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nasync function trySaveTokensInKeyring(user: string, tokens: UserTokens): Promise<boolean> {\n if (!(await isKeyringAvailable())) return false;\n try {\n await saveKeyringTokens(user, tokens);\n return true;\n } catch (error) {\n logger.warn(\n `System keyring failed to store credentials. Tokens will be stored in the config file. ${formatUnknownError(error)}`,\n );\n return false;\n }\n}\n\nlet warnedAboutNewerConfig = false;\n\nasync function warnIfNewerConfigAvailable(config: {\n latest_version?: number;\n latest_min_sdk_version?: string;\n}) {\n if (!config.latest_min_sdk_version || warnedAboutNewerConfig) return;\n const packageJson = await readPackageJson();\n const sdkVersion = packageJson.version ?? \"0.0.0\";\n if (semverLt(sdkVersion, config.latest_min_sdk_version)) {\n warnedAboutNewerConfig = true;\n logger.warn(ml`\n A newer config version (${String(config.latest_version)}) is available.\n Please update your SDK to >= ${config.latest_min_sdk_version}: pnpm update @tailor-platform/sdk\n `);\n }\n}\n\n/**\n * Read Tailor Platform CLI configuration, migrating from v1 if necessary.\n * @returns Parsed platform configuration\n */\nexport async function readPlatformConfig(): Promise<PfConfig> {\n const configPath = platformConfigPath();\n\n if (!fs.existsSync(configPath)) {\n const config: PfConfig = {\n version: LATEST_CONFIG_VERSION,\n min_sdk_version: V3_MIN_SDK_VERSION,\n users: {},\n profiles: {},\n current_user: null,\n };\n writePlatformConfig(config);\n return config;\n }\n\n const rawConfig = parseYAML(fs.readFileSync(configPath, \"utf-8\"));\n\n // Legacy installs may have left the config world-readable (umask default\n // 0o644). Tighten it here so users who only run read-only commands still\n // get the secret-file permissions applied without waiting for a write.\n tightenSecretFilePermissions(configPath);\n\n // Check for unsupported future versions\n const version =\n rawConfig != null && typeof rawConfig === \"object\" && \"version\" in rawConfig\n ? rawConfig.version\n : undefined;\n if (typeof version === \"number\" && version > LATEST_CONFIG_VERSION) {\n const minSdk =\n \"min_sdk_version\" in (rawConfig as object)\n ? String((rawConfig as { min_sdk_version: unknown }).min_sdk_version)\n : undefined;\n const updateHint = minSdk\n ? `Please update your SDK to >= ${minSdk}: pnpm update @tailor-platform/sdk`\n : \"Please update your SDK: pnpm update @tailor-platform/sdk\";\n throw new Error(ml`\n Config file uses version ${String(version)}, but this SDK only supports up to version ${String(LATEST_CONFIG_VERSION)}.\n ${updateHint}\n `);\n }\n\n // Try v3 first\n const v3Result = pfConfigSchemaV3.safeParse(rawConfig);\n if (v3Result.success) {\n await warnIfNewerConfigAvailable(v3Result.data);\n return v3Result.data;\n }\n\n // Try v2 next\n const v2Result = pfConfigSchemaV2.safeParse(rawConfig);\n if (v2Result.success) {\n await warnIfNewerConfigAvailable(v2Result.data);\n return migrateV2ToV3(v2Result.data);\n }\n\n // Fall back to v1 (convert to v3 in memory, but don't rewrite disk)\n const v1Result = pfConfigSchemaV1.safeParse(rawConfig);\n if (v1Result.success) {\n return migrateV1ToV3(v1Result.data);\n }\n\n // Neither v1, v2, nor v3\n throw new Error(ml`\n Failed to parse config file at ${configPath}.\n The file may be corrupted or created by an incompatible SDK version.\n `);\n}\n\nfunction toV1ForDisk(config: PfConfigV2): PfConfigV1 {\n const users: PfConfigV1[\"users\"] = {};\n for (const [name, entry] of Object.entries(config.users)) {\n if (!entry || entry.storage === \"keyring\") continue;\n users[name] = {\n access_token: entry.access_token,\n refresh_token: entry.refresh_token,\n token_expires_at: entry.token_expires_at,\n };\n }\n const currentUser =\n config.current_user && hasCurrentUserEntry(users, config.current_user)\n ? config.current_user\n : null;\n return {\n version: 1,\n users,\n profiles: config.profiles,\n current_user: currentUser,\n };\n}\n\nfunction hasProfilePlatformSettings(config: Pick<PfConfig | PfConfigV1, \"profiles\">): boolean {\n return Object.values(config.profiles).some(\n (profile) =>\n profile?.platform_url !== undefined ||\n profile?.oauth2_client_id !== undefined ||\n profile?.console_url !== undefined,\n );\n}\n\nfunction hasScopedUserKeys(config: Pick<PfConfig | PfConfigV1, \"users\">): boolean {\n return Object.keys(config.users).some((userKey) => userKey.includes(\"|\"));\n}\n\nfunction hasKeysOutside(entry: object | undefined, knownKeys: ReadonlySet<string>): boolean {\n return (\n entry !== undefined &&\n Object.entries(entry).some(([key, value]) => value !== undefined && !knownKeys.has(key))\n );\n}\n\nfunction hasFieldsUnknownToV2(config: PfConfig | PfConfigV2 | PfConfigV1): boolean {\n return (\n hasKeysOutside(config, v2ConfigKeys) ||\n Object.values(config.users).some((user) => hasKeysOutside(user, v2UserKeys)) ||\n Object.values(config.profiles).some((profile) => hasKeysOutside(profile, profileKeys))\n );\n}\n\nfunction toLatestForDisk(config: PfConfig | PfConfigV2 | PfConfigV1): PfConfigV3 {\n const latestInput = config.version === 1 ? migrateV1ToV2(config) : config;\n return {\n ...latestInput,\n version: LATEST_CONFIG_VERSION,\n min_sdk_version: V3_MIN_SDK_VERSION,\n };\n}\n\n/**\n * Write Tailor Platform CLI configuration to disk.\n * By default, file-backed configs without newer fields are converted to V1 for\n * backward compatibility, so an older SDK can still read the file. Configs\n * containing a keyring user are kept in V2 or later because the keyring storage\n * variant is not representable in V1. Configs containing profile-level Platform\n * settings, platform-scoped user tokens, canonical user IDs, email metadata, or\n * any other field the V2 format does not define are written in the latest\n * min-SDK-gated format because older SDKs would silently drop or misread those\n * settings.\n *\n * The config file may contain access/refresh tokens when the OS keyring is\n * unavailable, so it is written via {@link writeSecretFile} so other users\n * on the host cannot read it.\n * @param config - Platform configuration to write\n */\nexport function writePlatformConfig(config: PfConfig | PfConfigV2 | PfConfigV1) {\n const configPath = platformConfigPath();\n const hasKeyringUser =\n config.version !== 1 && Object.values(config.users).some((u) => u?.storage === \"keyring\");\n const diskConfig =\n config.version === LATEST_CONFIG_VERSION ||\n hasProfilePlatformSettings(config) ||\n hasScopedUserKeys(config) ||\n hasFieldsUnknownToV2(config)\n ? toLatestForDisk(config)\n : config.version === V2_CONFIG_VERSION && !hasKeyringUser\n ? toV1ForDisk(config)\n : config;\n writeSecretFile(\n configPath,\n stringifyYAML(\n diskConfig.version === 1\n ? diskConfig\n : { ...diskConfig, users: withoutKeyringFileTokens(diskConfig.users) },\n ),\n );\n}\n\nfunction withoutKeyringFileTokens(users: PfConfig[\"users\"] | PfConfigV2[\"users\"]) {\n return Object.fromEntries(\n Object.entries(users).map(([userKey, entry]) => {\n if (entry?.storage !== \"keyring\") return [userKey, entry];\n const { access_token: _accessToken, refresh_token: _refreshToken, ...keyringEntry } = entry;\n return [userKey, keyringEntry];\n }),\n );\n}\n\nfunction validateUUID(value: string, source: string): string {\n const result = z.uuid().safeParse(value);\n if (!result.success) {\n throw new Error(`Invalid value from ${source}: must be a valid UUID`);\n }\n return result.data;\n}\n\n/**\n * Load workspace ID from command options, environment variables, or platform config.\n * In CLI context, env fallback is also handled by politty's arg env option.\n * Priority: opts/workspaceId > env/workspaceId > opts/profile > error\n * @param opts - Workspace and profile options\n * @returns Resolved workspace ID\n */\nexport async function loadWorkspaceId(opts?: LoadWorkspaceIdOptions): Promise<string> {\n const workspaceId = await tryLoadWorkspaceId(opts);\n if (workspaceId) return workspaceId;\n\n throw new Error(ml`\n Workspace ID not found.\n Please specify workspace ID via --workspace-id option or TAILOR_PLATFORM_WORKSPACE_ID environment variable.\n `);\n}\n\n/**\n * Load a workspace ID when one is explicitly configured.\n * @param opts - Workspace and profile options\n * @returns Resolved workspace ID, or undefined when no source is configured\n */\nexport async function tryLoadWorkspaceId(\n opts?: LoadWorkspaceIdOptions,\n): Promise<string | undefined> {\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n\n if (opts?.workspaceId !== undefined) {\n return validateUUID(opts.workspaceId, \"--workspace-id option\");\n }\n\n if (process.env.TAILOR_PLATFORM_WORKSPACE_ID) {\n return validateUUID(\n process.env.TAILOR_PLATFORM_WORKSPACE_ID,\n \"TAILOR_PLATFORM_WORKSPACE_ID environment variable\",\n );\n }\n\n if (profile) {\n const pfConfig = await readPlatformConfig();\n const profileEntry = pfConfig.profiles[profile];\n const wsId = profileEntry?.workspace_id;\n if (!wsId) {\n throw profileNotFoundError(profile);\n }\n return validateUUID(wsId, `profile \"${profile}\"`);\n }\n\n return undefined;\n}\n\n/**\n * Load machine user name from command options, environment variables, or platform config.\n * In CLI context, env fallback is also handled by politty's arg env option.\n * Priority: opts/machineUser > env/TAILOR_PLATFORM_MACHINE_USER_NAME > opts/profile (profile default) > undefined.\n * An explicitly empty `opts.machineUser` is rejected with a CLIError (`MACHINE_USER_NAME_EMPTY`) rather than falling back to the env var or profile default.\n * When the active profile has `machine_user_override: \"deny\"`, an explicit value that differs from the profile's machine user throws a CLIError with code `PROFILE_MACHINE_USER_OVERRIDE_DENIED`.\n * @param opts - Machine user and profile options\n * @returns Resolved machine user name, or undefined if not set\n */\nexport async function loadMachineUserName(\n opts?: LoadMachineUserNameOptions,\n): Promise<string | undefined> {\n if (opts?.machineUser === \"\") {\n throw CLIError({\n code: \"MACHINE_USER_NAME_EMPTY\",\n message: \"Machine user name cannot be empty.\",\n suggestion:\n \"Pass a non-empty machine user name, or omit the option to use the environment variable or profile default.\",\n });\n }\n\n const envMachineUser = process.env.TAILOR_PLATFORM_MACHINE_USER_NAME || undefined;\n const explicitMachineUser: ExplicitMachineUser | undefined = opts?.machineUser\n ? {\n source: opts.machineUserSource ?? \"option\",\n value: opts.machineUser,\n }\n : envMachineUser\n ? { source: \"env\", value: envMachineUser }\n : undefined;\n const explicit = explicitMachineUser?.value;\n\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n if (!profile) return explicit;\n\n const pfConfig = await readPlatformConfig();\n const entry = pfConfig.profiles[profile];\n if (!entry) {\n if (explicit) return explicit;\n throw profileNotFoundError(profile);\n }\n\n if (entry.machine_user && entry.machine_user_override === \"deny\") {\n if (explicit && explicit !== entry.machine_user) {\n const details =\n explicitMachineUser.source === \"env\"\n ? `The machine user is being set to \"${explicit}\" via the TAILOR_PLATFORM_MACHINE_USER_NAME environment variable, which conflicts with this profile's pinned machine user \"${entry.machine_user}\".`\n : `This profile fixes the machine user to \"${entry.machine_user}\" for application-data commands.`;\n throw CLIError({\n code: \"PROFILE_MACHINE_USER_OVERRIDE_DENIED\",\n message: `Profile \"${profile}\" denies overriding the machine user.`,\n details,\n suggestion: `Omit the machine user option, unset TAILOR_PLATFORM_MACHINE_USER_NAME, or run ${formatCommandHint(\n {\n command: \"tailor\",\n args: profileUpdateArgs(profile, [\"--machine-user-override\", \"allow\"]),\n },\n )}.`,\n });\n }\n return entry.machine_user;\n }\n\n return explicit || entry.machine_user;\n}\n\n/**\n * Read the access token set through the environment, which takes precedence over any logged-in user.\n * @returns TAILOR_PLATFORM_TOKEN, or the deprecated TAILOR_TOKEN, when set\n */\nexport function readEnvironmentToken(): string | undefined {\n return process.env.TAILOR_PLATFORM_TOKEN ?? process.env.TAILOR_TOKEN;\n}\n\n/**\n * Read the stored browser login for a profile without ever renewing it: no refresh request, no\n * config write, no lock. For best-effort background calls that may be abandoned mid-flight,\n * where a refresh could rotate the refresh token and lose the replacement. Pair it with\n * `initOperatorClient(token, config, { renewToken: false })`.\n * @param opts - Profile options\n * @param opts.profile - Profile name; falls back to TAILOR_PLATFORM_PROFILE, then the current user\n * @returns The stored access token and the profile's platform settings, or undefined when there\n * is no login or the token is due for renewal\n */\nexport async function loadStoredAccessTokenWithoutRefresh(opts: {\n profile?: string | undefined;\n}): Promise<{ accessToken: string; platformConfig: PlatformClientConfig | undefined } | undefined> {\n const profile = opts.profile || process.env.TAILOR_PLATFORM_PROFILE;\n const pfConfig = await readPlatformConfig();\n const profileEntry = profile ? pfConfig.profiles[profile] : undefined;\n if (profile && !profileEntry) return undefined;\n const user = profileEntry?.user ?? pfConfig.current_user;\n if (!user) return undefined;\n const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n const stored = await readStoredToken(pfConfig, user, platformConfig, loginFailureFor(profile));\n if (isDueForRefresh(stored)) return undefined;\n return { accessToken: stored.tokens.accessToken, platformConfig };\n}\n\n/**\n * Load access token from environment variables, command options, or platform config.\n * In CLI context, profile env fallback is also handled by politty's arg env option.\n * Priority: env/TAILOR_PLATFORM_TOKEN > env/TAILOR_TOKEN (deprecated) > opts/profile > env/profile > config/currentUser > error\n * @param opts - Profile options\n * @returns Resolved access token\n */\nexport async function loadAccessToken(opts?: LoadAccessTokenOptions) {\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n const envToken = readEnvironmentToken();\n if (envToken && !process.env.TAILOR_PLATFORM_TOKEN) {\n logger.warn(\"TAILOR_TOKEN is deprecated. Please use TAILOR_PLATFORM_TOKEN instead.\");\n }\n\n if (envToken) {\n logger.registerSecret(envToken);\n const platformConfig = await loadPlatformClientConfig({ profile, allowMissingProfile: true });\n rememberPlatformConfigForToken(envToken, platformConfig);\n return envToken;\n }\n\n const pfConfig = await readPlatformConfig();\n const profileEntry = profile ? pfConfig.profiles[profile] : undefined;\n if (profile && !profileEntry) {\n throw profileNotFoundError(profile);\n }\n const user = profileEntry?.user ?? pfConfig.current_user;\n if (!user) {\n throw CLIError({\n code: \"AUTH_TOKEN_NOT_FOUND\",\n message: \"Tailor Platform token not found.\",\n suggestion: \"Set TAILOR_PLATFORM_TOKEN or log in using the selected profile.\",\n next: { command: \"tailor\", args: [\"login\", ...recoveryContextArgs({ profile })] },\n context: { profile: profile ?? null },\n });\n }\n const fromProfile = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n const token = await resolveLatestToken({\n config: pfConfig,\n user,\n platformConfig: fromProfile,\n profile,\n });\n if (token.refreshable) {\n registerAccessTokenSource(\n token.accessToken,\n createStoredTokenSource({ token, platformConfig: fromProfile, profile }),\n );\n }\n return token.accessToken;\n}\n\n/**\n * Resolve authentication metadata without returning token values.\n * @param opts - Profile options\n * @returns Authentication status for the active environment and profile\n */\nexport async function loadAuthStatus(opts?: LoadAccessTokenOptions): Promise<AuthStatus> {\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n const envToken = readEnvironmentToken();\n if (envToken && !process.env.TAILOR_PLATFORM_TOKEN) {\n logger.warn(\"TAILOR_TOKEN is deprecated. Please use TAILOR_PLATFORM_TOKEN instead.\");\n }\n\n if (envToken) {\n logger.registerSecret(envToken);\n const config = await readPlatformConfig().catch(() => undefined);\n const profileEntry = profile ? config?.profiles[profile] : undefined;\n const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n return {\n authenticated: true,\n identity: null,\n identitySource: \"environment\",\n profile: profile ?? null,\n workspaceId: process.env.TAILOR_PLATFORM_WORKSPACE_ID ?? profileEntry?.workspace_id ?? null,\n permission: profileEntry?.readonly === true ? \"read\" : \"write\",\n platformUrl: getPlatformBaseUrl(platformConfig),\n tokenStatus: \"environment\",\n };\n }\n\n const config = await readPlatformConfig();\n const profileEntry = profile ? config.profiles[profile] : undefined;\n if (profile && !profileEntry) {\n throw profileNotFoundError(profile);\n }\n\n const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n const platformUrl = getPlatformBaseUrl(platformConfig);\n const workspaceId =\n process.env.TAILOR_PLATFORM_WORKSPACE_ID ?? profileEntry?.workspace_id ?? null;\n\n const identity = profileEntry?.user ?? config.current_user;\n const identitySource = profileEntry?.user ? \"profile\" : identity ? \"default\" : \"none\";\n let tokenStatus: AuthStatus[\"tokenStatus\"] = \"missing\";\n if (identity) {\n const { userKey, userEntry } = findUserEntry(config, identity, platformConfig);\n if (userEntry) {\n const tokens = await resolveTokens(userEntry, userKey, identity).catch(() => undefined);\n if (tokens) {\n const expired = new Date(userEntry.token_expires_at) <= new Date();\n if (!expired) {\n tokenStatus = \"valid\";\n } else {\n tokenStatus = tokens.refreshToken ? \"refreshable\" : \"expired\";\n }\n }\n }\n }\n\n return {\n authenticated: tokenStatus === \"valid\" || tokenStatus === \"refreshable\",\n identity: identity ?? null,\n identitySource,\n profile: profile ?? null,\n workspaceId,\n permission: profileEntry?.readonly === true ? \"read\" : \"write\",\n platformUrl,\n tokenStatus,\n };\n}\n\n/** Where `workspace create` places a workspace when no location is given. */\nexport type UserWorkspaceDefaults = {\n organizationId: string;\n folderId?: string;\n};\n\n/**\n * Resolve the selected user's entry on the selected platform without a legacy-key fallback.\n * @param config - Platform config\n * @param opts - Profile options\n * @returns The selected user and entry, or undefined when the profile does not exist\n */\nexport function resolveSelectedUserEntry(config: PfConfig, opts?: LoadAccessTokenOptions) {\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n const profileEntry = profile ? config.profiles[profile] : undefined;\n if (profile && !profileEntry) return undefined;\n const user = profileEntry?.user ?? config.current_user;\n const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n const userEntry = user\n ? findUserEntry(config, user, platformConfig, { allowLegacyUserKey: false }).userEntry\n : undefined;\n return { profile, user, userEntry };\n}\n\n/**\n * Load the default organization and folder stored on the user that config-based authentication\n * selects. An environment token's identity is not a config user, so none apply while one is set.\n * @param opts - Profile options\n * @returns The user's defaults, or undefined when none apply\n */\nexport async function loadUserWorkspaceDefaults(\n opts?: LoadAccessTokenOptions,\n): Promise<UserWorkspaceDefaults | undefined> {\n if (readEnvironmentToken()) return undefined;\n const config = await readPlatformConfig();\n const userEntry = resolveSelectedUserEntry(config, opts)?.userEntry;\n if (!userEntry?.default_organization_id) return undefined;\n return {\n organizationId: userEntry.default_organization_id,\n ...(userEntry.default_folder_id ? { folderId: userEntry.default_folder_id } : {}),\n };\n}\n\n/**\n * Load platform connection settings from the active profile.\n * @param opts - Profile options\n * @returns Resolved platform connection settings, or undefined for the default environment\n */\nexport async function loadPlatformClientConfig(\n opts?: LoadPlatformClientConfigOptions,\n): Promise<PlatformClientConfig | undefined> {\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n if (!profile) {\n return undefined;\n }\n\n let pfConfig: PfConfig;\n try {\n pfConfig = await readPlatformConfig();\n } catch (error) {\n if (opts?.allowMissingProfile) {\n return undefined;\n }\n throw error;\n }\n const profileEntry = pfConfig.profiles[profile];\n if (!profileEntry) {\n if (opts?.allowMissingProfile) {\n return undefined;\n }\n throw profileNotFoundError(profile);\n }\n return platformConfigFromProfile(profileEntry);\n}\n\n/**\n * Load the Tailor Platform Console base URL from environment variables or the active profile.\n * @param opts - Profile options\n * @returns Resolved Console base URL\n */\nexport async function loadConsoleBaseUrl(opts?: LoadConsoleBaseUrlOptions): Promise<string> {\n const platformConfig = await loadPlatformClientConfig(opts);\n return getConsoleBaseUrl(platformConfig);\n}\n\n/**\n * Registers a token pair's values with the logger so they are redacted from diagnostic\n * log output, wherever they later flow (retries, error messages, etc.). Call this as soon\n * as a token is obtained, not just before it is persisted — code between the two points\n * (e.g. an intervening API call) can still fail or log diagnostically.\n * @param tokens - Access token and optional refresh token\n */\nexport function registerTokenSecrets(tokens: UserTokens): void {\n logger.registerSecret(tokens.accessToken);\n if (tokens.refreshToken) logger.registerSecret(tokens.refreshToken);\n}\n\n/**\n * Resolve the actual token values for a user, reading from keyring or config as appropriate.\n * @param userEntry - User entry from the config\n * @param user - User identifier\n * @param label - User-facing identifier used in error messages\n * @returns Access token and optional refresh token\n */\nexport async function resolveTokens(\n userEntry: PfUser,\n user: string,\n label = user,\n): Promise<{ accessToken: string; refreshToken?: string }> {\n if (userEntry.storage === \"keyring\") {\n let tokens: UserTokens | undefined;\n try {\n tokens = await loadKeyringTokens(user);\n } catch (error) {\n throw new Error(\n ml`\n Failed to read credentials from OS keyring for \"${label}\". ${formatUnknownError(error)}\n Restore access to the OS keyring and try again, or run 'tailor login' in this environment to authenticate again.\n For non-interactive environments, set TAILOR_PLATFORM_TOKEN.\n `,\n { cause: error },\n );\n }\n if (!tokens) {\n throw new Error(ml`\n Credentials not found in OS keyring for \"${label}\".\n Credentials may be missing or inaccessible from this environment (for example, due to sandbox restrictions).\n Restore access to the OS keyring and try again, or run 'tailor login' in this environment to authenticate again.\n For non-interactive environments, set TAILOR_PLATFORM_TOKEN.\n `);\n }\n registerTokenSecrets(tokens);\n return tokens;\n }\n\n const tokens = {\n accessToken: userEntry.access_token,\n refreshToken: userEntry.refresh_token,\n };\n registerTokenSecrets(tokens);\n return tokens;\n}\n\nfunction userExtraFields(entry: PfUser | undefined) {\n if (!entry) return {};\n return withoutKeys(entry, userTokenKeys);\n}\n\ntype RemoveUserAliasOptions = {\n carryExtraFields: boolean;\n};\n\nasync function removeUserAlias(\n config: PfConfig,\n aliasKey: string,\n canonicalKey: string,\n opts: RemoveUserAliasOptions,\n) {\n const entry = config.users[aliasKey];\n if (aliasKey === canonicalKey || !entry) return;\n const canonicalEntry = config.users[canonicalKey];\n if (opts.carryExtraFields && canonicalEntry) {\n config.users[canonicalKey] = { ...userExtraFields(entry), ...canonicalEntry };\n }\n if (entry.storage === \"keyring\") {\n await deleteKeyringTokens(aliasKey);\n }\n delete config.users[aliasKey];\n}\n\n/**\n * Save tokens for a user, writing to keyring by default when available.\n * @param config - Platform config\n * @param user - User identifier\n * @param tokens - Token data to save\n * @param tokens.accessToken - Access token to save\n * @param tokens.refreshToken - Optional refresh token to save\n * @param expiresAt - Token expiration date\n * @param opts - Optional platform and user metadata\n */\nexport async function saveUserTokens(\n config: PfConfig,\n user: string,\n tokens: UserTokens,\n expiresAt: string,\n opts: { platformConfig?: PlatformClientConfig; email?: string } = {},\n): Promise<void> {\n registerTokenSecrets(tokens);\n const userKey = platformUserKey(user, opts.platformConfig);\n const existing = config.users[userKey];\n const extraFields = userExtraFields(existing);\n const email = opts.email ?? existing?.email;\n if (await trySaveTokensInKeyring(userKey, tokens)) {\n config.users[userKey] = {\n ...extraFields,\n token_expires_at: expiresAt,\n storage: \"keyring\",\n ...(email ? { email } : {}),\n };\n } else {\n if (existing?.storage === \"keyring\") {\n await deleteKeyringTokens(userKey);\n }\n config.users[userKey] = {\n ...extraFields,\n access_token: tokens.accessToken,\n refresh_token: tokens.refreshToken,\n token_expires_at: expiresAt,\n storage: \"file\",\n ...(email ? { email } : {}),\n };\n }\n}\n\n/**\n * Delete tokens for a user from keyring if applicable.\n * @param config - Platform config\n * @param user - User identifier\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n */\nexport async function deleteUserTokens(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts?: UserEntryLookupOptions,\n): Promise<void> {\n const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);\n if (userEntry?.storage === \"keyring\") {\n await deleteKeyringTokens(userKey);\n }\n delete config.users[userKey];\n}\n\n/**\n * Resolve stored tokens for a user on the selected platform.\n * @param config - Platform config\n * @param user - User name\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n * @returns Stored user entry and token values, or undefined when the user is not logged in\n */\nexport async function loadStoredUserTokens(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts?: UserEntryLookupOptions,\n): Promise<\n | {\n userEntry: PfUser;\n accessToken: string;\n refreshToken?: string;\n }\n | undefined\n> {\n const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);\n if (!userEntry) return undefined;\n const tokens = await resolveTokens(userEntry, userKey, user);\n return { userEntry, ...tokens };\n}\n\nfunction updateUserReferences(config: PfConfig, fromUser: string, toUser: string) {\n if (fromUser === toUser) return;\n if (config.current_user === fromUser) {\n config.current_user = toUser;\n }\n for (const profile of Object.values(config.profiles)) {\n if (profile?.user === fromUser) {\n profile.user = toUser;\n }\n }\n}\n\n/**\n * Remove a legacy alias after a canonical user ID has been written.\n * @param config - Platform config\n * @param legacyUser - Previous user key\n * @param canonicalUser - Canonical user key\n * @param platformConfig - Platform settings for scoped token storage\n */\nexport async function removeLegacyUserAlias(\n config: PfConfig,\n legacyUser: string,\n canonicalUser: string,\n platformConfig?: PlatformClientConfig,\n): Promise<void> {\n if (legacyUser === canonicalUser) return;\n updateUserReferences(config, legacyUser, canonicalUser);\n const canonicalKey = platformUserKey(canonicalUser, platformConfig);\n const scopedLegacyKey = platformUserKey(legacyUser, platformConfig);\n await removeUserAlias(config, scopedLegacyKey, canonicalKey, { carryExtraFields: true });\n const legacyKeyServesThisPlatform = canUseLegacyUserKey(getPlatformBaseUrl(platformConfig));\n await removeUserAlias(config, legacyUser, canonicalKey, {\n carryExtraFields: legacyKeyServesThisPlatform,\n });\n}\n\nfunction shouldResolveSubjectOnRefresh(user: string, userEntry: PfUser): boolean {\n return Boolean(userEntry.email || inferEmailFromUserId(user));\n}\n\n/**\n * Run a callback while holding the lock on the platform config file, which token refresh\n * and logout take while they read and write stored tokens.\n * @param fn - Callback to run while holding the lock\n * @param options - Lock options\n * @returns The callback's result\n */\nexport async function withPlatformConfigLock<T>(\n fn: () => Promise<T>,\n options?: ConfigLockOptions,\n): Promise<T> {\n return await withConfigLock(`${platformConfigPath()}.lock`, fn, options);\n}\n\nconst TOKEN_REFRESH_MARGIN_MS = 5 * 60 * 1000;\nconst EARLY_REFRESH_LOCK_TIMEOUT_MS = 2_000;\nconst MIN_USABLE_TOKEN_LIFETIME_MS = 10_000;\n\ntype LatestToken = { accessToken: string; user: string };\ntype ResolvedToken = LatestToken & { expiresAt: number; refreshable: boolean };\ntype LoginFailure = (code: string, message: string, suggestion: string) => Error;\ntype StoredToken = {\n userKey: string;\n configUser: string;\n entry: PfUser;\n tokens: UserTokens;\n};\ntype TokenRequest = {\n config: PfConfig;\n user: string;\n platformConfig?: PlatformClientConfig;\n profile?: string;\n /** A token the Platform rejected; a stored token equal to it counts as expired. */\n rejectedToken?: string;\n};\n\nfunction expiresWithin(expiresAt: number, marginMs: number): boolean {\n const remainingMs = expiresAt - Date.now();\n return Number.isNaN(remainingMs) || remainingMs <= marginMs;\n}\n\nfunction isExpired(stored: StoredToken, rejectedToken?: string): boolean {\n return (\n stored.tokens.accessToken === rejectedToken ||\n expiresWithin(Date.parse(stored.entry.token_expires_at), MIN_USABLE_TOKEN_LIFETIME_MS)\n );\n}\n\nfunction isDueForRefresh(stored: StoredToken, rejectedToken?: string): boolean {\n return (\n isExpired(stored, rejectedToken) ||\n (Boolean(stored.tokens.refreshToken) &&\n expiresWithin(Date.parse(stored.entry.token_expires_at), TOKEN_REFRESH_MARGIN_MS))\n );\n}\n\nasync function readStoredToken(\n config: PfConfig,\n user: string,\n platformConfig: PlatformClientConfig | undefined,\n loginFailure: LoginFailure,\n): Promise<StoredToken> {\n const { userKey, userEntry } = findUserEntry(config, user, platformConfig);\n if (!userEntry) {\n throw loginFailure(\n \"AUTH_USER_NOT_FOUND\",\n `User \"${user}\" not found.`,\n \"Verify the selected user and use the original login method (browser or --machine-user) on the same platform.\",\n );\n }\n return {\n userKey,\n configUser: userFromPlatformUserKey(userKey, platformConfig),\n entry: userEntry,\n tokens: await resolveTokens(userEntry, userKey, user),\n };\n}\n\nfunction useStoredToken(\n stored: StoredToken,\n platformConfig: PlatformClientConfig | undefined,\n): ResolvedToken {\n rememberPlatformConfigForToken(stored.tokens.accessToken, platformConfig);\n return {\n accessToken: stored.tokens.accessToken,\n user: stored.configUser,\n expiresAt: Date.parse(stored.entry.token_expires_at),\n refreshable: Boolean(stored.tokens.refreshToken),\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction replaceContents(target: Record<string, unknown>, source: Record<string, unknown>) {\n for (const key of Object.keys(target)) {\n if (!Object.hasOwn(source, key)) delete target[key];\n }\n for (const [key, value] of Object.entries(source)) {\n const current = target[key];\n if (isRecord(current) && isRecord(value)) {\n replaceContents(current, value);\n } else {\n target[key] = value;\n }\n }\n}\n\n/**\n * Fetch the latest access token, refreshing it when it expires within five minutes.\n * A refresh rereads the stored config under {@link withPlatformConfigLock} and uses a token\n * another process stored in the meantime instead of refreshing again. Until the current token\n * expires, a refresh that fails or would wait for another process falls back to it.\n * @param config - Platform config; replaced in place with the stored config when a refresh was needed\n * @param user - User identifier\n * @param platformConfig - Optional platform connection settings\n * @param profile - Selected profile for login recovery\n * @returns Latest access token and the canonical user ID it is stored under\n * (the resolved subject when a legacy email key was migrated during refresh,\n * otherwise the matching config user)\n */\nexport async function fetchLatestToken(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n profile?: string,\n): Promise<LatestToken> {\n const latest = await resolveLatestToken({ config, user, platformConfig, profile });\n return { accessToken: latest.accessToken, user: latest.user };\n}\n\nfunction loginFailureFor(profile: string | undefined): LoginFailure {\n const loginArgs = profile ? [\"--profile\", profile] : [];\n return (code, message, suggestion) =>\n CLIError({\n code,\n message,\n suggestion,\n next: { command: \"tailor\", args: [\"login\", ...loginArgs, \"--help\"] },\n context: { profile: profile ?? null },\n });\n}\n\nfunction tokenExpiredError(loginFailure: LoginFailure): Error {\n return loginFailure(\n \"AUTH_TOKEN_EXPIRED\",\n \"Token expired.\",\n \"Use the original login method (browser or --machine-user) to authenticate again on the same platform.\",\n );\n}\n\nasync function resolveLatestToken(request: TokenRequest): Promise<ResolvedToken> {\n const { config, user, platformConfig, profile, rejectedToken } = request;\n const loginFailure = loginFailureFor(profile);\n const stored = await readStoredToken(config, user, platformConfig, loginFailure);\n if (!isDueForRefresh(stored, rejectedToken)) return useStoredToken(stored, platformConfig);\n\n const expired = isExpired(stored, rejectedToken);\n try {\n return await withPlatformConfigLock(\n async () => {\n const latest = await readPlatformConfig();\n try {\n return await refreshStoredToken({ ...request, config: latest }, loginFailure);\n } finally {\n replaceContents(config, latest);\n }\n },\n expired ? undefined : { timeoutMs: EARLY_REFRESH_LOCK_TIMEOUT_MS },\n );\n } catch (error) {\n if (expired || !isConfigLockTimeout(error)) throw error;\n if (isExpired(stored, rejectedToken)) return await resolveLatestToken(request);\n logger.debug(\"Another tailor command is refreshing the token; using the current token.\");\n return useStoredToken(stored, platformConfig);\n }\n}\n\nasync function refreshStoredToken(\n request: TokenRequest,\n loginFailure: LoginFailure,\n): Promise<ResolvedToken> {\n const { config, user, platformConfig, rejectedToken } = request;\n const stored = await readStoredToken(config, user, platformConfig, loginFailure);\n if (!isDueForRefresh(stored, rejectedToken)) return useStoredToken(stored, platformConfig);\n\n const { userKey: storedUser, configUser: storedConfigUser, entry: userEntry, tokens } = stored;\n if (!tokens.refreshToken) throw tokenExpiredError(loginFailure);\n\n const client = initOAuth2Client(platformConfig);\n let resp;\n try {\n resp = await client.refreshToken({\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n expiresAt: Date.parse(userEntry.token_expires_at),\n });\n } catch (error) {\n if (!isExpired(stored, rejectedToken)) {\n logger.debug(`Failed to refresh a token that has not expired yet: ${String(error)}`);\n return useStoredToken(stored, platformConfig);\n }\n throw loginFailure(\n \"AUTH_TOKEN_REFRESH_FAILED\",\n \"Failed to refresh token. Your session may have expired.\",\n \"Check network connectivity and platform availability, then use the original login method (browser or --machine-user) on the same platform if needed.\",\n );\n }\n registerTokenSecrets({\n accessToken: resp.accessToken,\n refreshToken: resp.refreshToken ?? undefined,\n });\n\n const refreshedTokens = {\n accessToken: resp.accessToken,\n refreshToken: resp.refreshToken ?? tokens.refreshToken,\n };\n const newExpiresAt = new Date(\n assertDefined(resp.expiresAt, \"token refresh response missing expiresAt\"),\n ).toISOString();\n const previousEmail =\n userEntry.email ?? inferEmailFromUserId(user) ?? inferEmailFromUserId(storedConfigUser);\n\n // Store before any other request: the refresh token just sent is already invalid.\n await saveUserTokens(config, storedConfigUser, refreshedTokens, newExpiresAt, {\n platformConfig,\n email: previousEmail,\n });\n writePlatformConfig(config);\n\n let resolvedUser = storedConfigUser;\n let email = previousEmail;\n if (\n shouldResolveSubjectOnRefresh(user, userEntry) ||\n shouldResolveSubjectOnRefresh(storedConfigUser, userEntry)\n ) {\n try {\n const userInfo = await fetchUserInfo(resp.accessToken, platformConfig);\n resolvedUser = userInfo.sub;\n email = userInfo.email;\n } catch (error) {\n logger.debug(`Failed to resolve refreshed token user info: ${String(error)}`);\n }\n }\n\n if (resolvedUser !== storedConfigUser || email !== previousEmail) {\n await saveUserTokens(config, resolvedUser, refreshedTokens, newExpiresAt, {\n platformConfig,\n email,\n });\n }\n await removeLegacyUserAlias(config, user, resolvedUser, platformConfig);\n await removeUserAlias(config, storedUser, platformUserKey(resolvedUser, platformConfig), {\n carryExtraFields: true,\n });\n if (previousEmail && email && previousEmail !== email) {\n logger.info(`Updated local user email from \"${previousEmail}\" to \"${email}\".`);\n }\n writePlatformConfig(config);\n rememberPlatformConfigForToken(resp.accessToken, platformConfig);\n return {\n accessToken: resp.accessToken,\n user: resolvedUser,\n expiresAt: Date.parse(newExpiresAt),\n refreshable: true,\n };\n}\n\nconst RENEWAL_RETRY_INTERVAL_MS = 30_000;\nconst FORCED_RENEWAL_INTERVAL_MS = 60_000;\n\ntype StoredTokenSourceInit = {\n token: ResolvedToken;\n platformConfig?: PlatformClientConfig;\n profile?: string;\n};\n\n/**\n * Keep the token of a browser login usable for a long-running command. It renews only inside\n * a request, never on a timer, so the process cannot exit before a new token is stored.\n * @param init - Token to start from and the login it belongs to\n * @returns Source for the Operator client\n */\nfunction createStoredTokenSource(init: StoredTokenSourceInit): AccessTokenSource {\n let { accessToken, expiresAt, user } = init.token;\n let renewal: Promise<void> | undefined;\n let renewalError: Error | undefined;\n let retryAt = 0;\n let renewedAt = -Infinity;\n let forcedAt = -Infinity;\n let lastRejected: string | undefined;\n\n const isUsable = () => !expiresWithin(expiresAt, MIN_USABLE_TOKEN_LIFETIME_MS);\n const isDue = () =>\n expiresWithin(expiresAt, TOKEN_REFRESH_MARGIN_MS) && (!isUsable() || Date.now() >= retryAt);\n\n const renew = (rejectedToken?: string) =>\n (renewal ??= (async () => {\n try {\n const latest = await resolveLatestToken({\n config: await readPlatformConfig(),\n user,\n platformConfig: init.platformConfig,\n profile: init.profile,\n rejectedToken,\n });\n renewalError = undefined;\n const replacesRejected =\n rejectedToken !== undefined && latest.accessToken !== rejectedToken;\n if (latest.expiresAt > expiresAt || replacesRejected) {\n ({ accessToken, expiresAt, user } = latest);\n renewedAt = Date.now();\n registerAccessTokenSource(accessToken, source);\n } else {\n retryAt = Date.now() + RENEWAL_RETRY_INTERVAL_MS;\n }\n } catch (error) {\n renewalError = error instanceof Error ? error : new Error(String(error));\n retryAt = Date.now() + RENEWAL_RETRY_INTERVAL_MS;\n logger.debug(`Failed to renew the access token: ${String(error)}`);\n } finally {\n renewal = undefined;\n }\n })());\n\n const source: AccessTokenSource = {\n async current() {\n if (renewal && accessToken === lastRejected) await renewal;\n if (!isDue() || (renewal && isUsable())) return accessToken;\n await renew();\n if (!isUsable()) throw renewalError ?? tokenExpiredError(loginFailureFor(init.profile));\n return accessToken;\n },\n async replaceRejected(rejected) {\n if (accessToken !== rejected) return accessToken;\n lastRejected = rejected;\n while (renewal) await renewal;\n if (accessToken !== rejected) return accessToken;\n if (Date.now() - Math.max(renewedAt, forcedAt) < FORCED_RENEWAL_INTERVAL_MS) return undefined;\n forcedAt = Date.now();\n await renew(rejected);\n return accessToken === rejected ? undefined : accessToken;\n },\n };\n return source;\n}\n\nconst DEFAULT_CONFIG_FILENAME = \"tailor.config.ts\";\n\n/**\n * Load config path from command options, environment variables, or search parent directories.\n * In CLI context, env fallback is also handled by politty's arg env option.\n * Priority: opts/config > env/config > search parent directories\n * @param configPath - Optional explicit config path\n * @returns Resolved config path or undefined\n */\nexport function loadConfigPath(configPath?: string): string | undefined {\n if (configPath) {\n return configPath;\n }\n if (process.env.TAILOR_CONFIG_PATH) {\n return process.env.TAILOR_CONFIG_PATH;\n }\n\n // Search for config file in current directory and parent directories\n return findUpSync(DEFAULT_CONFIG_FILENAME);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"context-aAgFGDBD.mjs","names":["semverLt","PageDirection","withErrorDiagnostics","parseBoolean","isCLIError","jsonDefaultAgent","logger","formatCommandHint","CLIError","multiline","normalizeBaseUrl","getPlatformBaseUrl","registerAccessTokenSource","rememberPlatformConfigForToken","initOAuth2Client","fetchUserInfo","defaultPlatformBaseUrl","getConsoleBaseUrl","readPackageJson","tightenSecretFilePermissions","writeSecretFile","ensureSecretDir","path","fs","crypto","os","unitToMs","durationPattern","durationArg","z","val","match","digits","assertDefined","duration","value","unit","positiveIntArg","nonNegativeIntArg","orderArg","order","separator","argv","token","machineUser","options","originalEnvKeys","file","files","envPath","required","content","parsed","parseEnv","key","envFiles","envFilesIfExists","JSON_ARG_NAME","VERBOSE_ARG_NAME","GLOBAL_FLAG_PARSER_OPTIONS","globalArgsWereApplied","parseArgv","tokens","name","alias","flag","env","JSON_OUTPUT_ENV_VAR","envEnabled","verbose","source","error","\"TAILOR_JSON_OUTPUT\"","arg","args","commonArgs","option","toCamelCase","envFileArgKeys","envFileArgKeyByToken","extractFields","field","chars","index","booleanAliases","char","result","inlineValue","workspaceArgs","DEFAULT_CONFIG_PATH","configPath","relativeConfigPath","context","profile","configArg","multiConfigArg","deprecatedConfigPath","deploymentArgs","confirmationArgs","SKIP_CONFIRMATION_SUGGESTION","organizationArgs","defaultOrder","pagedLogArgs","folderArgs","LOCK_TIMEOUT_CODE","INSTANCE_ID","lockOwnerSchema","heldLocks","AsyncLocalStorage","localQueues","held","lockPath","fn","previous","turn","resolve","queue","nonce","startedAt","noticeShown","delay","waitedMs","timeoutMs","fd","owner","stat","lock","now","pid","observed","guardPath","current","SERVICE_NAME","entryClass","Entry","raw","account","pfProfileSchema","pfUserSchemaV1","pfUserKeyringSchema","pfUserFileSchema","pfUserSchemaV2","pfUserIdentitySchemaV3","pfUserMetadataV3","pfUserKeyringSchemaV3","pfUserFileSchemaV3","pfUserSchemaV3","pfConfigSchemaV1","V3_MIN_SDK_VERSION","semverSchema","pfConfigSchemaV2","pfConfigSchemaV3","xdgConfig","config","platformUrl","user","platformPrefix","userKey","platformConfig","defaultPlatform","users","entry","email","userEntry","emailMatch","opts","legacyEntry","currentUser","schemas","schema","v2ConfigKeys","v2UserKeys","userTokenKeys","profileKeys","v2OnlyConfigKeys","v3OnlyConfigKeys","v3OnlyUserKeys","keys","v1User","v1Config","v2Config","warnedAboutNewerConfig","sdkVersion","lt","rawConfig","parseYAML","version","minSdk","updateHint","v3Result","v2Result","v1Result","knownKeys","hasKeyringUser","u","diskConfig","stringifyYAML","_accessToken","_refreshToken","keyringEntry","workspaceId","wsId","profileNotFoundError","envMachineUser","explicitMachineUser","explicit","details","pfConfig","profileEntry","stored","envToken","fromProfile","identity","identitySource","tokenStatus","label","aliasKey","canonicalKey","canonicalEntry","existing","extraFields","expiresAt","fromUser","toUser","legacyUser","canonicalUser","TOKEN_REFRESH_MARGIN_MS","MIN_USABLE_TOKEN_LIFETIME_MS","remainingMs","marginMs","rejectedToken","loginFailure","target","latest","loginArgs","request","expired","storedUser","storedConfigUser","client","resp","refreshedTokens","newExpiresAt","previousEmail","resolvedUser","userInfo","RENEWAL_RETRY_INTERVAL_MS","init","renewal","renewalError","retryAt","renewedAt","forcedAt","lastRejected","replacesRejected","accessToken","rejected","findUpSync"],"sources":["../src/cli/shared/args.ts","../src/cli/shared/config-lock.ts","../src/cli/shared/token-store.ts","../src/cli/shared/context.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport { parseEnv } from \"node:util\";\nimport { arg, extractFields, parseArgv, toCamelCase, type ArgSource } from \"@politty/zod\";\nimport { PageDirection } from \"@tailor-platform/tailor-proto/resource_pb\";\nimport * as path from \"pathe\";\nimport { z } from \"zod\";\nimport { assertDefined } from \"#/utils/assert\";\nimport { withErrorDiagnostics } from \"./error-diagnostics\";\nimport { JSON_OUTPUT_ENV_VAR, jsonDefaultAgent, logger, type JsonModeSource } from \"./logger\";\nimport { parseBoolean } from \"./parse-boolean\";\n\ntype ArgsShape = Record<string, z.ZodType>;\nexport type MachineUserInputSource = \"option\" | \"env\";\ntype ResolveMachineUserInputSourceOptions = {\n valueIsExplicit?: boolean;\n};\n\n// ============================================================================\n// Validators\n// ============================================================================\n\nconst durationUnits = [\"ms\", \"s\", \"m\"] as const;\ntype DurationUnit = (typeof durationUnits)[number];\n\nconst unitToMs: Record<DurationUnit, number> = {\n ms: 1,\n s: 1000,\n m: 60 * 1000,\n};\n\nconst durationPattern = /^(\\d+)(ms|s|m)$/;\n\n/**\n * Schema for duration string validation (e.g., \"3s\", \"500ms\", \"1m\")\n * Only validates format; use parseDuration() to convert to milliseconds\n */\nexport const durationArg = z\n .string()\n .refine((val) => durationPattern.test(val), {\n message: \"Invalid duration format. Expected format: '3s', '500ms', '1m'\",\n })\n .refine(\n (val) => {\n const match = val.match(durationPattern);\n if (!match) return false;\n const digits = match[1];\n return digits !== undefined && parseInt(digits, 10) > 0;\n },\n { message: \"Duration must be greater than 0\" },\n );\n\n/**\n * Parse a validated duration string into milliseconds\n * @param duration - Duration string (e.g., \"3s\", \"500ms\", \"1m\")\n * @returns Duration in milliseconds\n */\nexport function parseDuration(duration: string): number {\n const match = assertDefined(\n duration.match(durationPattern),\n `invalid duration format: ${duration}`,\n );\n const value = parseInt(assertDefined(match[1], \"duration digits group missing\"), 10);\n const unit = assertDefined(match[2], \"duration unit group missing\") as DurationUnit;\n return value * unitToMs[unit];\n}\n\n/**\n * Schema for positive integer validation (from string input)\n * Transforms the string to a number\n */\nexport const positiveIntArg = z.coerce.number().int().positive();\n\n/**\n * Schema for non-negative integer validation (from string input).\n * Accepts 0 (used for `--limit 0` to disable the limit).\n */\nexport const nonNegativeIntArg = z.coerce.number().int().nonnegative();\n\n/**\n * Schema for sort order (`asc` or `desc`).\n */\nexport const orderArg = z.enum([\"asc\", \"desc\"]);\n\nexport type Order = z.infer<typeof orderArg>;\n\n/**\n * Translate a CLI `--order` value into the proto `PageDirection` enum.\n * Returns `undefined` when the user did not specify an order so that\n * callers can omit the field and fall back to the server default.\n * @param order - Order string from CLI args (`\"asc\"` | `\"desc\"` | undefined)\n * @returns PageDirection, or undefined when `order` is undefined\n */\nexport function toPageDirection(order: Order | undefined): PageDirection | undefined {\n if (order === undefined) return undefined;\n return order === \"asc\" ? PageDirection.ASC : PageDirection.DESC;\n}\n\n/**\n * Drop the arguments after `--`, which belong to the invoked program.\n * @param argv - Raw CLI argv, excluding the executable and script path\n * @returns The tokens the CLI itself parses as options\n */\nfunction optionTokens(argv: readonly string[]): readonly string[] {\n const separator = argv.indexOf(\"--\");\n return separator === -1 ? argv : argv.slice(0, separator);\n}\n\nfunction hasMachineUserFlag(argv: readonly string[]): boolean {\n return optionTokens(argv).some(\n (token) =>\n token === \"-m\" ||\n token.startsWith(\"-m=\") ||\n token === \"--machine-user\" ||\n token.startsWith(\"--machine-user=\") ||\n token === \"--machineUser\" ||\n token.startsWith(\"--machineUser=\") ||\n token === \"--machineuser\" ||\n token.startsWith(\"--machineuser=\"),\n );\n}\n\n/**\n * Resolve whether a parsed machine user value came from an explicit CLI option or env fallback.\n * @param machineUser - Parsed machine user value\n * @param argv - Raw CLI argv, excluding the executable and script path\n * @param options - Source resolution options\n * @returns Machine user input source, or undefined when no value was parsed\n */\nexport function resolveMachineUserInputSource(\n machineUser: string | undefined,\n argv: readonly string[] = process.argv.slice(2),\n options: ResolveMachineUserInputSourceOptions = {},\n): MachineUserInputSource | undefined {\n if (machineUser === undefined) return undefined;\n if (options.valueIsExplicit) return \"option\";\n if (hasMachineUserFlag(argv)) return \"option\";\n return process.env.TAILOR_PLATFORM_MACHINE_USER_NAME === machineUser ? \"env\" : \"option\";\n}\n\n// ============================================================================\n// Env File Helpers\n// ============================================================================\n\ntype EnvFileArg = string | string[] | undefined;\n\n/**\n * Load env files from parsed arguments.\n * Processes --env-file first, then --env-file-if-exists.\n *\n * Follows Node.js --env-file behavior:\n * - Variables already set in the environment are NOT overwritten\n * - Variables from later files override those from earlier files\n * @param envFiles - Required env file path(s) that must exist\n * @param envFilesIfExists - Optional env file path(s) that are loaded if they exist\n */\nexport function loadEnvFiles(envFiles: EnvFileArg, envFilesIfExists: EnvFileArg): void {\n // Snapshot of originally set environment variables (before loading any files)\n const originalEnvKeys = new Set(Object.keys(process.env));\n\n const load = (files: EnvFileArg, required: boolean) => {\n for (const file of [files ?? []].flat()) {\n const envPath = path.resolve(process.cwd(), file);\n if (!fs.existsSync(envPath)) {\n if (required) {\n throw new Error(`Environment file not found: ${envPath}`);\n }\n continue;\n }\n const content = fs.readFileSync(envPath, \"utf-8\");\n const parsed = parseEnv(content);\n for (const [key, value] of Object.entries(parsed)) {\n // Skip if the variable was originally set in the environment\n if (originalEnvKeys.has(key)) {\n continue;\n }\n // Allow overwriting between env files\n process.env[key] = value;\n }\n }\n };\n\n load(envFiles, true);\n load(envFilesIfExists, false);\n}\n\n// ============================================================================\n// Argument Definitions\n// ============================================================================\n\n/** Name and short alias of the `--json` flag. */\nconst JSON_ARG_NAME = \"json\";\nconst JSON_ARG_ALIAS = \"j\";\nconst VERBOSE_ARG_NAME = \"verbose\";\n\nconst GLOBAL_FLAG_PARSER_OPTIONS = {\n aliasMap: new Map([[JSON_ARG_ALIAS, JSON_ARG_NAME]]),\n booleanFlags: new Set([JSON_ARG_NAME, VERBOSE_ARG_NAME]),\n defaultNegationDisabledFields: new Set<string>(),\n};\n\nlet globalArgsWereApplied = false;\n\n/**\n * Report whether the global arguments have been applied, which happens only\n * after every argument of the command parsed and validated.\n * @returns True once the `--json` effect has run\n */\nexport function globalArgsApplied(): boolean {\n return globalArgsWereApplied;\n}\n\n/**\n * Read the value tokens set for a global boolean flag, coerced the way the CLI\n * coerces the flag and its environment variable.\n * @param tokens - Tokens of the flag, each optionally carrying `=value`\n * @param name - Flag name\n * @returns `true`, `false`, a rejected value unchanged, or undefined when no token sets it\n */\nfunction parseGlobalFlag(tokens: string[], name: string): unknown {\n return parseArgv(tokens, GLOBAL_FLAG_PARSER_OPTIONS).options[name];\n}\n\n/**\n * Read the value the command line gives a global boolean flag. Tokens after\n * `--` are positional values, never flags.\n * @param argv - Command-line arguments after the executable and script path\n * @param name - Flag name\n * @param alias - Short alias of the flag, if it has one\n * @returns `true`, `false`, a rejected value unchanged, or undefined when argv does not set it\n */\nfunction globalFlagValue(argv: readonly string[], name: string, alias?: string): unknown {\n const separator = argv.indexOf(\"--\");\n const options = separator === -1 ? argv : argv.slice(0, separator);\n return parseGlobalFlag(\n options.filter((value) => {\n const [token] = value.split(\"=\", 1);\n return (\n token === `--${name}` ||\n value === `--no-${name}` ||\n (alias !== undefined && token === `-${alias}`)\n );\n }),\n name,\n );\n}\n\n/**\n * Report whether the command line turns `--json` on.\n *\n * A failure during argument parsing or validation ends the command before the\n * `--json` effect sets the logger's mode, so the flag is read from argv instead.\n * @param argv - Command-line arguments after the executable and script path\n * @returns True when argv sets `--json` or `-j` to true\n */\nexport function jsonFlagRequested(argv: readonly string[]): boolean {\n return globalFlagValue(argv, JSON_ARG_NAME, JSON_ARG_ALIAS) === true;\n}\n\n/**\n * Report what requested JSON output, reading the command line, the environment,\n * and the recorded AI coding agent the same way the `--json` argument would.\n * @param argv - Command-line arguments after the executable and script path\n * @returns What requested JSON output, or undefined when it is off\n */\nexport function requestedJsonModeSource(argv: readonly string[]): JsonModeSource | undefined {\n const flag = globalFlagValue(argv, JSON_ARG_NAME, JSON_ARG_ALIAS);\n const env = process.env[JSON_OUTPUT_ENV_VAR];\n const envEnabled =\n env !== undefined && parseGlobalFlag([`--${JSON_ARG_NAME}=${env}`], JSON_ARG_NAME) === true;\n if (flag === true) return envEnabled ? \"both\" : \"flag\";\n if (flag !== undefined) return undefined;\n if (envEnabled) return \"env\";\n if (env === undefined && jsonDefaultAgent() !== undefined) return \"agent\";\n return undefined;\n}\n\n/**\n * Prepare a failure that ended the command before the global arguments were\n * applied (see {@link globalArgsApplied}): apply `--verbose`, and when the\n * command line, the environment, or the recorded AI coding agent asked for JSON\n * output, turn it on and name a plain argument-parsing error `INVALID_ARGUMENTS`.\n * @param error - Failure about to be rendered\n * @param argv - Command-line arguments after the executable and script path\n */\nexport function resolveEarlyFailure(error: unknown, argv: readonly string[]): void {\n const verbose = globalFlagValue(argv, VERBOSE_ARG_NAME);\n if (typeof verbose === \"boolean\") logger.verbose = verbose;\n const source = requestedJsonModeSource(argv);\n if (!source) return;\n logger.setJsonMode(true, source);\n if (\n error instanceof Error &&\n Object.getPrototypeOf(error) === Error.prototype &&\n !Object.hasOwn(error, \"code\")\n ) {\n withErrorDiagnostics(error, { code: \"INVALID_ARGUMENTS\" });\n }\n}\n\n/**\n * Name what set the `--json` value, the way the logger records it.\n * @param source - Where the value was read from\n * @returns What selected JSON output when the value is true\n */\nfunction jsonArgSource(source: ArgSource | undefined): JsonModeSource {\n if (source === \"env\") return \"env\";\n // Only a recorded AI coding agent makes the default true.\n if (source === \"default\") return \"agent\";\n return source === \"cli\" && parseBoolean(process.env[JSON_OUTPUT_ENV_VAR]) === true\n ? \"both\"\n : \"flag\";\n}\n\nexport interface CommonArgsOptions {\n /** Extra short alias for `--verbose` (e.g. `\"v\"`), for plugins that need one */\n verboseAlias?: string;\n}\n\n/**\n * Build the common arguments for all CLI commands. CLI plugins call this so\n * their forwarded global flags parse identically to the host Tailor CLI and\n * feed the same logger state. Only the host CLI records a detected AI coding\n * agent, so under an agent `--json` defaults to true there but not in plugins.\n *\n * NOTE: --env-file and --env-file-if-exists collide with Node.js flags due to a bug\n * (https://github.com/nodejs/node/issues/54232). Node.js parses these even after the\n * script path, causing warnings (twice due to tsx loader).\n * @param options - Per-plugin adjustments to the shared arguments\n * @returns Argument shape suitable for spreading into a command schema\n */\nexport function createCommonArgs(options: CommonArgsOptions = {}) {\n return {\n \"env-file\": arg(z.array(z.string()).optional(), {\n alias: \"e\",\n description: \"Path to an environment file, repeatable (error if not found)\",\n completion: { type: \"file\", matcher: [\".env.*\", \".env\"] },\n }),\n \"env-file-if-exists\": arg(z.array(z.string()).optional(), {\n description: \"Path to an environment file, repeatable (ignored if not found)\",\n completion: { type: \"file\", matcher: [\".env.*\", \".env\"] },\n // Sets nothing new after loadEnvFilesFromArgv; loads the files for runs that skip it.\n effect: (_value, { args }) => {\n loadEnvFiles(\n args[\"env-file\"] as string[] | undefined,\n args[\"env-file-if-exists\"] as string[] | undefined,\n );\n },\n }),\n [VERBOSE_ARG_NAME]: arg(z.boolean().default(false), {\n ...(options.verboseAlias === undefined ? {} : { alias: options.verboseAlias }),\n description: \"Enable verbose logging\",\n negation: true,\n effect: (value, { args }) => {\n logger.verbose = args.$source?.(VERBOSE_ARG_NAME) === \"cli\" ? value : undefined;\n },\n }),\n [JSON_ARG_NAME]: arg(\n z.boolean().default(() => jsonDefaultAgent() !== undefined),\n {\n alias: JSON_ARG_ALIAS,\n description: \"Output as JSON\",\n negation: true,\n env: JSON_OUTPUT_ENV_VAR,\n effect: (value, { args }) => {\n globalArgsWereApplied = true;\n logger.setJsonMode(value, jsonArgSource(args.$source?.(JSON_ARG_NAME)));\n },\n },\n ),\n } satisfies ArgsShape;\n}\n\n/**\n * Common arguments for all CLI commands\n */\nexport const commonArgs = createCommonArgs();\n\ninterface NamedOption {\n cliName: string;\n alias?: readonly string[] | undefined;\n}\n\n/**\n * Spell an option every way the CLI accepts it on the command line.\n * @param option - Option field as `extractFields` describes it\n * @returns `-x` for each one-letter name, and the kebab-case and camelCase forms of each longer one\n */\nexport function flagTokensOf(option: NamedOption): string[] {\n return [option.cliName, ...(option.alias ?? [])].flatMap((name) =>\n name.length === 1 ? [`-${name}`] : [`--${name}`, `--${toCamelCase(name)}`],\n );\n}\n\n/** Env file paths given on the command line, in the order given. */\nexport interface EnvFileArgs {\n envFiles: string[];\n envFilesIfExists: string[];\n}\n\nconst envFileArgKeys = new Map<string, keyof EnvFileArgs>([\n [\"env-file\", \"envFiles\"],\n [\"env-file-if-exists\", \"envFilesIfExists\"],\n]);\n\nconst envFileArgKeyByToken: ReadonlyMap<string, keyof EnvFileArgs> = new Map(\n extractFields(z.strictObject(commonArgs)).fields.flatMap((field) => {\n const key = envFileArgKeys.get(field.name);\n if (key === undefined) return [];\n return flagTokensOf(field).map((token) => [token, key] as const);\n }),\n);\n\n/**\n * List the short aliases of the global boolean flags.\n * @param options - Per-plugin adjustments the common arguments were built with\n * @returns Every alias of a boolean flag in the common arguments\n */\nfunction globalBooleanAliases(options: CommonArgsOptions): ReadonlySet<string> {\n return new Set(\n extractFields(z.strictObject(createCommonArgs(options)))\n .fields.filter((field) => field.type === \"boolean\")\n .flatMap((field) => field.alias ?? []),\n );\n}\n\ninterface OptionToken {\n flag: string;\n value: string | undefined;\n}\n\n/**\n * Split an option token into its flag and the value it carries. A short-option\n * bundle such as `-je.env` yields its first option that is not a global\n * boolean, with the rest of the bundle as the value.\n * @param token - Command-line token\n * @param booleanAliases - Short aliases of the global boolean flags\n * @returns The flag, and its value when the token carries one\n */\nfunction splitOptionToken(token: string, booleanAliases: ReadonlySet<string>): OptionToken {\n if (\n token.startsWith(\"-\") &&\n !token.startsWith(\"--\") &&\n token.length > 2 &&\n !token.includes(\"=\")\n ) {\n const chars = Array.from(token.slice(1));\n const index = chars.findIndex((char) => !booleanAliases.has(char));\n if (index === -1) return { flag: token, value: undefined };\n const value = chars.slice(index + 1).join(\"\");\n return { flag: `-${chars[index]}`, value: value === \"\" ? undefined : value };\n }\n const separator = token.indexOf(\"=\");\n return separator === -1\n ? { flag: token, value: undefined }\n : { flag: token.slice(0, separator), value: token.slice(separator + 1) };\n}\n\n/**\n * Read the env file paths given on the command line. A short-option bundle\n * counts only when every option before `-e` in it is a global boolean, as in\n * `-je .env`.\n * @param argv - Command-line arguments after the executable and script path\n * @param options - Options passed to {@link createCommonArgs} for the global arguments\n * @returns Every `--env-file` and `--env-file-if-exists` value before `--`\n */\nexport function readEnvFileArgs(\n argv: readonly string[],\n options: CommonArgsOptions = {},\n): EnvFileArgs {\n const result: EnvFileArgs = { envFiles: [], envFilesIfExists: [] };\n const booleanAliases = globalBooleanAliases(options);\n const tokens = optionTokens(argv);\n for (let index = 0; index < tokens.length; index++) {\n const { flag, value: inlineValue } = splitOptionToken(tokens[index] ?? \"\", booleanAliases);\n const key = envFileArgKeyByToken.get(flag);\n if (key === undefined) continue;\n if (inlineValue !== undefined) {\n result[key].push(inlineValue);\n continue;\n }\n const value = tokens[index + 1];\n if (value !== undefined && !value.startsWith(\"-\")) {\n result[key].push(value);\n index++;\n }\n }\n return result;\n}\n\n/**\n * Load the env files given on the command line, so that options backed by an\n * environment variable read the values these files set. Call it before the\n * CLI parses its arguments, such as from the `setup` hook of `runMain`.\n * @param argv - Command-line arguments after the executable and script path\n * @param options - Options passed to {@link createCommonArgs} for the global arguments\n */\nexport function loadEnvFilesFromArgv(\n argv: readonly string[],\n options: CommonArgsOptions = {},\n): void {\n const { envFiles, envFilesIfExists } = readEnvFileArgs(argv, options);\n loadEnvFiles(envFiles, envFilesIfExists);\n}\n\n/**\n * Arguments for commands that require workspace context\n */\nexport const workspaceArgs = {\n \"workspace-id\": arg(z.string().optional(), {\n alias: \"w\",\n description: \"Workspace ID\",\n env: \"TAILOR_PLATFORM_WORKSPACE_ID\",\n completion: { type: \"none\" },\n }),\n profile: arg(z.string().optional(), {\n alias: \"p\",\n description: \"Workspace profile\",\n env: \"TAILOR_PLATFORM_PROFILE\",\n completion: { type: \"none\" },\n }),\n} satisfies ArgsShape;\n\n/**\n * Default config file path used when --config is not passed\n */\nexport const DEFAULT_CONFIG_PATH = \"tailor.config.ts\";\n\n/**\n * Format the --config argument for remediation command hints so they target\n * the same config the current run used. The `--config=<value>` form keeps a\n * leading-hyphen path bound as the option value.\n * @param {string} [configPath] - Config path the current run used, if any\n * @returns {string | undefined} `--config=<path>` argument, or undefined when the default config is in use\n */\nexport function formatConfigArg(configPath?: string): string | undefined {\n if (!configPath) return undefined;\n const relativeConfigPath = path.relative(process.cwd(), configPath);\n if (relativeConfigPath === DEFAULT_CONFIG_PATH) return undefined;\n return `--config=${relativeConfigPath}`;\n}\n\n/** Profile and workspace selection the current run used. */\nexport interface RecoveryContext {\n profile?: string | undefined;\n workspaceId?: string | undefined;\n}\n\n/**\n * Arguments that make a hinted follow-up command select the same profile and\n * workspace as the current run. The `--option=<value>` form keeps a\n * leading-hyphen value bound as the option value.\n * @param {RecoveryContext} context - Profile and workspace id the current run used\n * @returns {readonly string[]} Arguments to append to the hinted command\n */\nexport function recoveryContextArgs(context: RecoveryContext): readonly string[] {\n return [\n ...(context.workspaceId ? [`--workspace-id=${context.workspaceId}`] : []),\n ...(context.profile ? [`--profile=${context.profile}`] : []),\n ];\n}\n\n/**\n * Arguments for a hinted `tailor profile update` command. The profile name\n * comes first unless it starts with a hyphen, which only parses after `--`.\n * @param {string} profile - Profile to update\n * @param {readonly string[]} options - Options to set on the profile\n * @returns {readonly string[]} Arguments following the `tailor` executable\n */\nexport function profileUpdateArgs(profile: string, options: readonly string[]): readonly string[] {\n return profile.startsWith(\"-\")\n ? [\"profile\", \"update\", ...options, \"--\", profile]\n : [\"profile\", \"update\", profile, ...options];\n}\n\n/**\n * Shared config arg for commands that accept a config file path\n */\nexport const configArg = {\n config: arg(z.string().default(DEFAULT_CONFIG_PATH), {\n alias: \"c\",\n description: \"Path to Tailor config file\",\n env: \"TAILOR_CONFIG_PATH\",\n completion: { type: \"file\", extensions: [\"ts\"] },\n }),\n} satisfies ArgsShape;\n\n/**\n * Shared config arg for commands that accept one or more comma-separated config file paths\n */\nexport const multiConfigArg = {\n config: arg(z.string().default(DEFAULT_CONFIG_PATH), {\n alias: \"c\",\n description:\n \"Path to SDK config file. Use comma-separated paths to deploy multiple apps together.\",\n env: \"TAILOR_CONFIG_PATH\",\n completion: { type: \"file\", extensions: [\"ts\"] },\n }),\n} satisfies ArgsShape;\n\n/**\n * Read the deploy config paths set through the environment, warning when the deprecated TAILOR_PLATFORM_SDK_CONFIG_PATH supplies them.\n * @returns TAILOR_CONFIG_PATH, or the deprecated TAILOR_PLATFORM_SDK_CONFIG_PATH; empty values count as not set\n */\nexport function readDeployConfigPathEnv(): string | undefined {\n const configPath = process.env.TAILOR_CONFIG_PATH;\n if (configPath) return configPath;\n const deprecatedConfigPath = process.env.TAILOR_PLATFORM_SDK_CONFIG_PATH;\n if (!deprecatedConfigPath) return undefined;\n logger.warn(\n \"TAILOR_PLATFORM_SDK_CONFIG_PATH is deprecated. Please use TAILOR_CONFIG_PATH instead.\",\n );\n return deprecatedConfigPath;\n}\n\n/**\n * Arguments for commands that interact with deployed resources (includes config)\n */\nexport const deploymentArgs = {\n ...workspaceArgs,\n ...configArg,\n} satisfies ArgsShape;\n\n/**\n * Arguments for commands that require confirmation\n */\nexport const confirmationArgs = {\n yes: arg(z.boolean().default(false), {\n alias: \"y\",\n description: \"Skip confirmation prompts\",\n }),\n} satisfies ArgsShape;\n\n/** Suggestion for a confirmation prompt that {@link confirmationArgs} skips but cannot be shown. */\nexport const SKIP_CONFIRMATION_SUGGESTION = \"Pass --yes to skip the confirmation.\";\n\n/**\n * Arguments for commands that require organization context\n */\nexport const organizationArgs = {\n \"organization-id\": arg(z.string(), {\n alias: \"o\",\n description: \"Organization ID\",\n env: \"TAILOR_PLATFORM_ORGANIZATION_ID\",\n completion: { type: \"none\" },\n }),\n} satisfies ArgsShape;\n\n/**\n * Arguments for list commands that accept `--order` / `--limit`. Sort\n * order defaults to `desc` (newest first) because most callers want the\n * latest items; pass `--order asc` to opt in to ascending order. The\n * limit is unbounded by default so existing invocations keep returning\n * every item; pass `--limit N` to cap the result size.\n * @param defaultOrder - Default value for `--order` (defaults to `\"desc\"`)\n * @returns Argument shape suitable for spreading into a command schema\n */\nexport const paginationArgs = (defaultOrder: Order = \"desc\") =>\n ({\n order: arg(orderArg.default(defaultOrder), {\n description: \"Sort order (asc or desc)\",\n }),\n limit: arg(nonNegativeIntArg.optional(), {\n alias: \"l\",\n description: \"Maximum number of items to return (0 or omit: unlimited)\",\n }),\n }) satisfies ArgsShape;\n\n/**\n * Arguments for time-series log list commands. Defaults to newest-first\n * (`desc`) and a 50-item cap so that listing stays responsive on busy\n * workspaces. Pass `--limit 0` to disable the cap and fetch all entries.\n */\nexport const pagedLogArgs = {\n order: arg(orderArg.default(\"desc\"), {\n description: \"Sort order (asc or desc)\",\n }),\n limit: arg(nonNegativeIntArg.default(50), {\n alias: \"l\",\n description: \"Maximum number of items to return (0: unlimited)\",\n }),\n} satisfies ArgsShape;\n\n/**\n * Arguments for commands that require folder context\n */\nexport const folderArgs = {\n \"folder-id\": arg(z.string(), {\n alias: \"f\",\n description: \"Folder ID\",\n env: \"TAILOR_PLATFORM_FOLDER_ID\",\n completion: { type: \"none\" },\n }),\n} satisfies ArgsShape;\n\ntype LocationIdName = \"organization-id\" | \"folder-id\";\n\ntype LocationIdArgs = {\n [name in LocationIdName]?: string | undefined;\n} & {\n $source?: ((name: LocationIdName) => ArgSource) | undefined;\n};\n\n/**\n * Read the organization and folder ID options.\n * @param args - Parsed command arguments\n * @returns Organization and folder IDs; empty values from the environment count as not given\n */\nexport function locationIds(args: LocationIdArgs): {\n organizationId?: string;\n folderId?: string;\n} {\n const read = (name: LocationIdName) => {\n const value = args[name];\n return value === \"\" && args.$source?.(name) === \"env\" ? undefined : value;\n };\n return { organizationId: read(\"organization-id\"), folderId: read(\"folder-id\") };\n}\n\nexport type CommonArgsType = z.infer<z.ZodObject<typeof commonArgs>>;\n","import { AsyncLocalStorage } from \"node:async_hooks\";\nimport * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"pathe\";\nimport { z } from \"zod\";\nimport { CLIError, isCLIError } from \"./errors\";\nimport { logger } from \"./logger\";\nimport { ensureSecretDir } from \"./secret-file\";\n\nconst MAX_LOCK_AGE_MS = 2 * 60 * 1000;\nconst DEFAULT_TIMEOUT_MS = MAX_LOCK_AGE_MS + 30_000;\nconst UNWRITTEN_LOCK_AGE_MS = 10_000;\nconst RECLAIM_GUARD_AGE_MS = 10_000;\nconst WAIT_NOTICE_DELAY_MS = 3_000;\nconst MAX_RETRY_DELAY_MS = 250;\nconst LOCK_TIMEOUT_CODE = \"CONFIG_LOCK_TIMEOUT\";\n\nconst INSTANCE_ID = crypto.randomUUID();\n\n// A lock written by a newer SDK may carry more fields.\nconst lockOwnerSchema = z.looseObject({\n pid: z.number().int(),\n hostname: z.string(),\n instanceId: z.string(),\n nonce: z.string(),\n createdAt: z.number(),\n});\n\ntype LockOwner = z.output<typeof lockOwnerSchema>;\n\ntype ObservedLock = {\n content: string;\n ino: number;\n mtimeMs: number;\n owner: LockOwner | undefined;\n};\n\nexport type ConfigLockOptions = {\n /** How long to wait for another process to release the lock, in milliseconds. */\n timeoutMs?: number;\n};\n\nconst heldLocks = new AsyncLocalStorage<ReadonlySet<string>>();\nconst localQueues = new Map<string, Promise<void>>();\n\n/**\n * Run a callback while holding an exclusive lock that every process on this host respects.\n * Callers in the same process wait their turn, and a callback that is already holding the\n * lock can take it again.\n * @param lockPath - Lock file path\n * @param fn - Callback to run while holding the lock\n * @param options - Lock options\n * @returns The callback's result\n */\nexport async function withConfigLock<T>(\n lockPath: string,\n fn: () => Promise<T>,\n options: ConfigLockOptions = {},\n): Promise<T> {\n const held = heldLocks.getStore();\n if (held?.has(lockPath)) return await fn();\n\n const previous = localQueues.get(lockPath) ?? Promise.resolve();\n let releaseLocal = () => {};\n const turn = new Promise<void>((resolve) => {\n releaseLocal = resolve;\n });\n const queue = previous.then(() => turn);\n localQueues.set(lockPath, queue);\n await previous;\n try {\n const nonce = await acquireFileLock(lockPath, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n try {\n return await heldLocks.run(new Set([...(held ?? []), lockPath]), fn);\n } finally {\n releaseFileLock(lockPath, nonce);\n }\n } finally {\n releaseLocal();\n if (localQueues.get(lockPath) === queue) localQueues.delete(lockPath);\n }\n}\n\n/**\n * Whether an error is the timeout {@link withConfigLock} throws when the lock stays held.\n * @param error - Error to check\n * @returns True for a lock timeout\n */\nexport function isConfigLockTimeout(error: unknown): boolean {\n return isCLIError(error) && error.code === LOCK_TIMEOUT_CODE;\n}\n\nasync function acquireFileLock(lockPath: string, timeoutMs: number): Promise<string> {\n ensureSecretDir(path.dirname(lockPath));\n const nonce = crypto.randomUUID();\n const startedAt = Date.now();\n let noticeShown = false;\n let delay = 10;\n for (;;) {\n if (tryCreateLock(lockPath, nonce)) return nonce;\n if (reclaimIfStale(lockPath)) continue;\n const waitedMs = Date.now() - startedAt;\n if (waitedMs >= timeoutMs) throw lockTimeoutError(lockPath);\n if (!noticeShown && waitedMs >= WAIT_NOTICE_DELAY_MS) {\n noticeShown = true;\n logger.info(`Waiting for another tailor command to release ${lockPath}...`);\n }\n await new Promise((resolve) => setTimeout(resolve, delay * (0.5 + Math.random())));\n delay = Math.min(delay * 2, MAX_RETRY_DELAY_MS);\n }\n}\n\nfunction tryCreateLock(lockPath: string, nonce: string): boolean {\n let fd: number;\n try {\n fd = fs.openSync(lockPath, \"wx\", 0o600);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\") return false;\n throw error;\n }\n const owner: LockOwner = {\n pid: process.pid,\n hostname: os.hostname(),\n instanceId: INSTANCE_ID,\n nonce,\n createdAt: Date.now(),\n };\n try {\n fs.writeSync(fd, JSON.stringify(owner));\n } catch (error) {\n fs.closeSync(fd);\n fs.rmSync(lockPath, { force: true });\n throw error;\n }\n fs.closeSync(fd);\n return true;\n}\n\nfunction readLock(lockPath: string): ObservedLock | undefined {\n let stat: fs.Stats;\n let content: string;\n try {\n stat = fs.statSync(lockPath);\n content = fs.readFileSync(lockPath, \"utf-8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw error;\n }\n return { content, ino: stat.ino, mtimeMs: stat.mtimeMs, owner: parseOwner(content) };\n}\n\nfunction parseOwner(content: string): LockOwner | undefined {\n try {\n const result = lockOwnerSchema.safeParse(JSON.parse(content));\n return result.success ? result.data : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isStale(lock: ObservedLock): boolean {\n const { owner } = lock;\n const now = Date.now();\n if (!owner) return now - lock.mtimeMs > UNWRITTEN_LOCK_AGE_MS;\n if (now - owner.createdAt > MAX_LOCK_AGE_MS) return true;\n if (owner.hostname !== os.hostname()) return false;\n // Another thread may hold a lock with this pid; this module never acquires while holding one.\n if (owner.pid === process.pid) return owner.instanceId === INSTANCE_ID;\n return !isProcessAlive(owner.pid);\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n\n/**\n * Remove a stale lock. Only the process holding the reclaim guard removes it, and only if\n * the lock is still the one judged stale.\n * @param lockPath - Lock file path\n * @returns Whether creating the lock can be retried right away\n */\nfunction reclaimIfStale(lockPath: string): boolean {\n const observed = readLock(lockPath);\n if (!observed) return true;\n if (!isStale(observed)) return false;\n\n const guardPath = `${lockPath}.reclaim`;\n if (!tryCreateGuard(guardPath)) return false;\n try {\n const current = readLock(lockPath);\n if (\n current?.ino === observed.ino &&\n current.mtimeMs === observed.mtimeMs &&\n current.content === observed.content\n ) {\n fs.rmSync(lockPath, { force: true });\n }\n return true;\n } finally {\n fs.rmSync(guardPath, { force: true });\n }\n}\n\nfunction tryCreateGuard(guardPath: string): boolean {\n try {\n fs.closeSync(fs.openSync(guardPath, \"wx\", 0o600));\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n }\n try {\n if (Date.now() - fs.statSync(guardPath).mtimeMs > RECLAIM_GUARD_AGE_MS) {\n fs.rmSync(guardPath, { force: true });\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n return false;\n}\n\nfunction releaseFileLock(lockPath: string, nonce: string): void {\n if (readLock(lockPath)?.owner?.nonce === nonce) {\n fs.rmSync(lockPath, { force: true });\n }\n}\n\nfunction lockTimeoutError(lockPath: string): Error {\n return CLIError({\n code: LOCK_TIMEOUT_CODE,\n message: `Timed out waiting for another tailor command to release ${lockPath}.`,\n suggestion:\n \"Wait for the other tailor commands to finish, then retry. If none is running, delete the lock file.\",\n context: { lockPath },\n });\n}\n","import { logger } from \"./logger\";\n\nconst SERVICE_NAME = \"tailor-platform-cli\";\n\ntype TokenData = {\n accessToken: string;\n refreshToken?: string;\n};\n\ntype EntryLike = {\n setPassword(password: string): void;\n getPassword(): string | null;\n deletePassword(): void;\n};\n\ntype EntryConstructor = new (service: string, account: string) => EntryLike;\n\nlet entryClass: EntryConstructor | false | undefined;\n\nasync function getEntryClass(): Promise<EntryConstructor | false> {\n if (entryClass !== undefined) return entryClass;\n\n try {\n const mod = await import(\"@napi-rs/keyring\");\n entryClass = mod.Entry;\n } catch {\n logger.warn(\n \"System keyring is not available. Tokens will be stored in the config file. Set TAILOR_PLATFORM_TOKEN environment variable for CI environments.\",\n );\n entryClass = false;\n }\n\n return entryClass;\n}\n\n/**\n * Check whether the native keyring library can be loaded.\n * @returns true if the library is available; individual operations may still fail\n */\nexport async function isKeyringAvailable(): Promise<boolean> {\n return (await getEntryClass()) !== false;\n}\n\n/**\n * Load tokens from the OS keyring for a given account.\n * @param account - User identifier (e.g. email or client ID)\n * @returns Token data or undefined if not found or the stored JSON is invalid\n * @throws If the keyring library is unavailable or the keyring cannot be read\n */\nexport async function loadKeyringTokens(account: string): Promise<TokenData | undefined> {\n const Entry = await getEntryClass();\n if (!Entry) throw new Error(\"System keyring is not available.\");\n\n const entry = new Entry(SERVICE_NAME, account);\n const raw = entry.getPassword();\n if (raw === null) return undefined;\n try {\n return JSON.parse(raw) as TokenData;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Save tokens to the OS keyring for a given account.\n * @param account - User identifier (e.g. email or client ID)\n * @param tokens - Token data to store\n */\nexport async function saveKeyringTokens(account: string, tokens: TokenData): Promise<void> {\n const Entry = await getEntryClass();\n if (!Entry) throw new Error(\"System keyring is not available.\");\n\n const entry = new Entry(SERVICE_NAME, account);\n entry.setPassword(JSON.stringify(tokens));\n}\n\n/**\n * Delete tokens from the OS keyring for a given account.\n * @param account - User identifier (e.g. email or client ID)\n */\nexport async function deleteKeyringTokens(account: string): Promise<void> {\n const Entry = await getEntryClass();\n if (!Entry) return;\n\n try {\n const entry = new Entry(SERVICE_NAME, account);\n entry.deletePassword();\n } catch {\n // Ignore \"not found\" errors\n }\n}\n\n/**\n * Reset the cached keyring state. Used for testing.\n */\nexport function resetKeyringState(): void {\n entryClass = undefined;\n}\n\nexport type { TokenData };\n","import * as fs from \"node:fs\";\nimport { parseYAML, stringifyYAML } from \"confbox\";\nimport { findUpSync } from \"find-up-simple\";\nimport * as path from \"pathe\";\nimport { lt as semverLt } from \"semver\";\nimport { xdgConfig } from \"xdg-basedir\";\nimport { z } from \"zod\";\nimport { assertDefined } from \"#/utils/assert\";\nimport ml from \"#/utils/multiline\";\nimport { type MachineUserInputSource, profileUpdateArgs, recoveryContextArgs } from \"./args\";\nimport {\n defaultPlatformBaseUrl,\n fetchUserInfo,\n getConsoleBaseUrl,\n getPlatformBaseUrl,\n initOAuth2Client,\n normalizeBaseUrl,\n registerAccessTokenSource,\n rememberPlatformConfigForToken,\n type AccessTokenSource,\n type PlatformClientConfig,\n} from \"./client\";\nimport { type ConfigLockOptions, isConfigLockTimeout, withConfigLock } from \"./config-lock\";\nimport { CLIError, formatCommandHint, profileNotFoundError } from \"./errors\";\nimport { logger } from \"./logger\";\nimport { readPackageJson } from \"./package-json\";\nimport { tightenSecretFilePermissions, writeSecretFile } from \"./secret-file\";\nimport {\n isKeyringAvailable,\n loadKeyringTokens,\n saveKeyringTokens,\n deleteKeyringTokens,\n} from \"./token-store\";\n\n// Config schemas keep unknown keys so that rewriting a file written by a newer SDK does not drop them.\nconst pfProfileSchema = z.looseObject({\n user: z.string(),\n workspace_id: z.string(),\n readonly: z.boolean().optional(),\n machine_user: z.string().optional(),\n machine_user_override: z.enum([\"allow\", \"deny\"]).optional(),\n platform_url: z.url().optional(),\n oauth2_client_id: z.string().optional(),\n console_url: z.url().optional(),\n});\n\nconst pfUserSchemaV1 = z.looseObject({\n access_token: z.string(),\n refresh_token: z.string().optional(),\n token_expires_at: z.string(),\n});\n\nconst pfUserKeyringSchema = z.looseObject({\n storage: z.literal(\"keyring\"),\n token_expires_at: z.string(),\n});\n\nconst pfUserFileSchema = z.looseObject({\n storage: z.literal(\"file\"),\n token_expires_at: z.string(),\n access_token: z.string(),\n refresh_token: z.string().optional(),\n});\n\nconst pfUserSchemaV2 = z.discriminatedUnion(\"storage\", [pfUserKeyringSchema, pfUserFileSchema]);\n\nconst pfUserIdentitySchemaV3 = z.strictObject({\n email: z.string().optional(),\n});\n\nconst pfUserMetadataV3 = {\n ...pfUserIdentitySchemaV3.shape,\n default_organization_id: z.string().optional(),\n default_folder_id: z.string().optional(),\n};\n\nconst pfUserKeyringSchemaV3 = pfUserKeyringSchema.extend(pfUserMetadataV3);\n\nconst pfUserFileSchemaV3 = pfUserFileSchema.extend(pfUserMetadataV3);\n\nconst pfUserSchemaV3 = z.discriminatedUnion(\"storage\", [pfUserKeyringSchemaV3, pfUserFileSchemaV3]);\n\nconst pfConfigSchemaV1 = z.looseObject({\n version: z.literal(1),\n users: z.partialRecord(z.string(), pfUserSchemaV1),\n profiles: z.partialRecord(z.string(), pfProfileSchema),\n current_user: z.string().nullable(),\n});\n\nconst V2_CONFIG_VERSION = 2;\nconst LATEST_CONFIG_VERSION = 3;\nconst V2_MIN_SDK_VERSION = \"1.29.0\";\nconst V3_MIN_SDK_VERSION = \"2.0.0\";\n\nconst semverSchema = z.templateLiteral([\n z.number().int(),\n \".\",\n z.number().int(),\n \".\",\n z.number().int(),\n]);\n\nconst pfConfigSchemaV2 = z.looseObject({\n version: z.literal(V2_CONFIG_VERSION),\n min_sdk_version: semverSchema,\n latest_version: z.number().int().optional(),\n latest_min_sdk_version: semverSchema.optional(),\n users: z.partialRecord(z.string(), pfUserSchemaV2),\n profiles: z.partialRecord(z.string(), pfProfileSchema),\n current_user: z.string().nullable(),\n});\n\nconst pfConfigSchemaV3 = z.looseObject({\n version: z.literal(LATEST_CONFIG_VERSION),\n min_sdk_version: semverSchema,\n latest_version: z.number().int().optional(),\n latest_min_sdk_version: semverSchema.optional(),\n users: z.partialRecord(z.string(), pfUserSchemaV3),\n profiles: z.partialRecord(z.string(), pfProfileSchema),\n current_user: z.string().nullable(),\n});\n\ntype PfConfigV1 = z.output<typeof pfConfigSchemaV1>;\ntype PfConfigV2 = z.output<typeof pfConfigSchemaV2>;\ntype PfConfig = z.output<typeof pfConfigSchemaV3>;\ntype PfUser = z.output<typeof pfUserSchemaV3>;\ntype UserTokens = { accessToken: string; refreshToken?: string };\ntype PfConfigV3 = PfConfig;\ntype LoadWorkspaceIdOptions = {\n workspaceId?: string;\n profile?: string;\n};\ntype LoadAccessTokenOptions = {\n profile?: string;\n};\ntype LoadPlatformClientConfigOptions = {\n profile?: string;\n allowMissingProfile?: boolean;\n};\ntype LoadConsoleBaseUrlOptions = {\n profile?: string;\n allowMissingProfile?: boolean;\n};\ntype LoadMachineUserNameOptions = {\n machineUser?: string;\n machineUserSource?: MachineUserInputSource;\n profile?: string;\n};\ntype ExplicitMachineUser = {\n source: MachineUserInputSource;\n value: string;\n};\n\nexport type AuthStatus = {\n authenticated: boolean;\n identity: string | null;\n identitySource: \"environment\" | \"profile\" | \"default\" | \"none\";\n profile: string | null;\n workspaceId: string | null;\n permission: \"read\" | \"write\";\n platformUrl: string;\n tokenStatus: \"environment\" | \"valid\" | \"refreshable\" | \"expired\" | \"missing\";\n};\n\nfunction platformConfigPath() {\n if (!xdgConfig) {\n throw new Error(\"User home directory not found\");\n }\n return path.join(xdgConfig, \"tailor-platform\", \"config.yaml\");\n}\n\n/**\n * Whether the platform config file exists. Unlike `readPlatformConfig`, this never creates it,\n * so a background check can run on a machine that has never logged in without side effects.\n * @returns true when the config file is present\n */\nexport function platformConfigExists(): boolean {\n if (!xdgConfig) return false;\n return fs.existsSync(platformConfigPath());\n}\n\ntype ProfilePlatformSettings = {\n platform_url?: string;\n oauth2_client_id?: string;\n console_url?: string;\n};\n\n/**\n * Convert stored profile platform fields to platform client settings.\n * @param profile - Profile platform settings\n * @returns Platform client settings\n */\nexport function platformConfigFromProfile(\n profile: ProfilePlatformSettings | undefined,\n): PlatformClientConfig | undefined {\n const config = {\n ...(profile?.platform_url ? { platformUrl: profile.platform_url } : {}),\n ...(profile?.oauth2_client_id ? { oauth2ClientId: profile.oauth2_client_id } : {}),\n ...(profile?.console_url ? { consoleUrl: profile.console_url } : {}),\n };\n return Object.keys(config).length > 0 ? config : undefined;\n}\n\nfunction platformUserKey(user: string, config?: PlatformClientConfig): string {\n const platformUrl = getPlatformBaseUrl(config);\n if (platformUrl === normalizeBaseUrl(defaultPlatformBaseUrl)) {\n return user;\n }\n return `${platformUrl}|${user}`;\n}\n\nfunction userFromPlatformUserKey(userKey: string, config?: PlatformClientConfig): string {\n const platformPrefix = `${getPlatformBaseUrl(config)}|`;\n return userKey.startsWith(platformPrefix) ? userKey.slice(platformPrefix.length) : userKey;\n}\n\nfunction canUseLegacyUserKey(platformUrl: string): boolean {\n try {\n return getPlatformBaseUrl() === platformUrl;\n } catch {\n return false;\n }\n}\n\ntype UserEntryLookupOptions = {\n allowLegacyUserKey?: boolean;\n};\n\nfunction findUserByEmail(\n users: PfConfig[\"users\"],\n email: string,\n platformConfig?: PlatformClientConfig,\n) {\n const platformUrl = getPlatformBaseUrl(platformConfig);\n const platformPrefix = `${platformUrl}|`;\n const defaultPlatform = platformUrl === normalizeBaseUrl(defaultPlatformBaseUrl);\n return Object.entries(users).find(([key, entry]) => {\n if (entry?.email !== email) return false;\n return defaultPlatform ? !key.includes(\"|\") : key.startsWith(platformPrefix);\n });\n}\n\nfunction findUserEntry(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts: UserEntryLookupOptions = {},\n) {\n const userKey = platformUserKey(user, platformConfig);\n const userEntry = config.users[userKey];\n if (userEntry) {\n return { userKey, userEntry };\n }\n const emailMatch = findUserByEmail(config.users, user, platformConfig);\n if (emailMatch?.[1]) {\n return { userKey: emailMatch[0], userEntry: emailMatch[1] };\n }\n const platformUrl = getPlatformBaseUrl(platformConfig);\n if (\n userKey !== user &&\n (opts.allowLegacyUserKey === false || !canUseLegacyUserKey(platformUrl))\n ) {\n return { userKey, userEntry };\n }\n const legacyEntry = config.users[user];\n return legacyEntry ? { userKey: user, userEntry: legacyEntry } : { userKey, userEntry };\n}\n\n/**\n * Resolve the config user key that would be used for a user on the selected platform.\n * @param config - Platform config\n * @param user - User name\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n * @returns Resolved config user key\n */\nexport function resolveUserTokenKey(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts?: UserEntryLookupOptions,\n): string {\n return findUserEntry(config, user, platformConfig, opts).userKey;\n}\n\nexport function resolveConfigUser(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts?: UserEntryLookupOptions,\n): string | undefined {\n const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);\n return userEntry ? userFromPlatformUserKey(userKey, platformConfig) : undefined;\n}\n\n/**\n * Check whether tokens are registered for a user on the selected platform.\n * @param config - Platform config\n * @param user - User name\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n * @returns True when the user has a registered token entry\n */\nexport function hasUserTokenEntry(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts?: UserEntryLookupOptions,\n): boolean {\n return findUserEntry(config, user, platformConfig, opts).userEntry !== undefined;\n}\n\nfunction hasUserKeyForName(users: Record<string, unknown>, user: string): boolean {\n return users[user] !== undefined || Object.keys(users).some((key) => key.endsWith(`|${user}`));\n}\n\nfunction hasUserEmailEntry(users: PfConfig[\"users\"], user: string): boolean {\n return Object.values(users).some((entry) => entry?.email === user);\n}\n\n/**\n * Check whether any platform has tokens registered for a user.\n * @param config - Platform config\n * @param user - User name\n * @returns True when the user has a token entry for any platform\n */\nexport function hasAnyUserTokenEntry(config: Pick<PfConfig, \"users\">, user: string): boolean {\n return hasUserKeyForName(config.users, user) || hasUserEmailEntry(config.users, user);\n}\n\nfunction hasCurrentUserEntry(users: PfConfigV1[\"users\"], currentUser: string): boolean {\n return hasUserKeyForName(users, currentUser);\n}\n\ntype ObjectSchema = { shape: object };\n\nfunction declaredKeys(...schemas: ObjectSchema[]): Set<string> {\n return new Set(schemas.flatMap((schema) => Object.keys(schema.shape)));\n}\n\nconst v2ConfigKeys = declaredKeys(pfConfigSchemaV2);\nconst v2UserKeys = declaredKeys(pfUserKeyringSchema, pfUserFileSchema);\nconst userTokenKeys = v2UserKeys.union(declaredKeys(pfUserIdentitySchemaV3));\nconst profileKeys = declaredKeys(pfProfileSchema);\n// An older format does not validate keys a later format declares, so migration drops them.\nconst v2OnlyConfigKeys = v2ConfigKeys.difference(declaredKeys(pfConfigSchemaV1));\nconst v3OnlyConfigKeys = declaredKeys(pfConfigSchemaV3).difference(v2ConfigKeys);\nconst v3OnlyUserKeys = declaredKeys(pfUserKeyringSchemaV3, pfUserFileSchemaV3).difference(\n v2UserKeys,\n);\n\nfunction withoutKeys<T extends object>(entry: T, keys: ReadonlySet<string>): T {\n return Object.fromEntries(Object.entries(entry).filter(([key]) => !keys.has(key))) as T;\n}\n\n/**\n * Migrate a v1 config to v2.\n * Tokens are kept in the config file (storage: \"file\") during migration.\n * They will be moved to the OS keyring on next login or token refresh.\n * @param v1Config - v1 configuration to migrate\n * @returns Migrated v2 configuration\n */\nfunction migrateV1ToV2(v1Config: PfConfigV1): PfConfigV2 {\n const users: PfConfigV2[\"users\"] = {};\n\n for (const [name, v1User] of Object.entries(v1Config.users)) {\n if (!v1User) continue;\n\n users[name] = { ...withoutKeys(v1User, v3OnlyUserKeys), storage: \"file\" };\n }\n\n return {\n ...withoutKeys(v1Config, v2OnlyConfigKeys),\n version: V2_CONFIG_VERSION,\n min_sdk_version: V2_MIN_SDK_VERSION,\n users,\n };\n}\n\nfunction inferEmailFromUserId(user: string): string | undefined {\n return z.email().safeParse(user).success ? user : undefined;\n}\n\nfunction migrateV2ToV3(v2Config: PfConfigV2): PfConfig {\n const users: PfConfig[\"users\"] = {};\n\n for (const [user, entry] of Object.entries(v2Config.users)) {\n if (!entry) continue;\n const email = inferEmailFromUserId(user);\n users[user] = {\n ...withoutKeys(entry, v3OnlyUserKeys),\n ...(email ? { email } : {}),\n };\n }\n\n return {\n ...withoutKeys(v2Config, v3OnlyConfigKeys),\n version: LATEST_CONFIG_VERSION,\n min_sdk_version: V3_MIN_SDK_VERSION,\n users,\n };\n}\n\nfunction migrateV1ToV3(v1Config: PfConfigV1): PfConfig {\n return migrateV2ToV3(migrateV1ToV2(v1Config));\n}\n\nfunction formatUnknownError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nasync function trySaveTokensInKeyring(user: string, tokens: UserTokens): Promise<boolean> {\n if (!(await isKeyringAvailable())) return false;\n try {\n await saveKeyringTokens(user, tokens);\n return true;\n } catch (error) {\n logger.warn(\n `System keyring failed to store credentials. Tokens will be stored in the config file. ${formatUnknownError(error)}`,\n );\n return false;\n }\n}\n\nlet warnedAboutNewerConfig = false;\n\nasync function warnIfNewerConfigAvailable(config: {\n latest_version?: number;\n latest_min_sdk_version?: string;\n}) {\n if (!config.latest_min_sdk_version || warnedAboutNewerConfig) return;\n const packageJson = await readPackageJson();\n const sdkVersion = packageJson.version ?? \"0.0.0\";\n if (semverLt(sdkVersion, config.latest_min_sdk_version)) {\n warnedAboutNewerConfig = true;\n logger.warn(ml`\n A newer config version (${String(config.latest_version)}) is available.\n Please update your SDK to >= ${config.latest_min_sdk_version}: pnpm update @tailor-platform/sdk\n `);\n }\n}\n\n/**\n * Read Tailor Platform CLI configuration, migrating from v1 if necessary.\n * @returns Parsed platform configuration\n */\nexport async function readPlatformConfig(): Promise<PfConfig> {\n const configPath = platformConfigPath();\n\n if (!fs.existsSync(configPath)) {\n const config: PfConfig = {\n version: LATEST_CONFIG_VERSION,\n min_sdk_version: V3_MIN_SDK_VERSION,\n users: {},\n profiles: {},\n current_user: null,\n };\n writePlatformConfig(config);\n return config;\n }\n\n const rawConfig = parseYAML(fs.readFileSync(configPath, \"utf-8\"));\n\n // Legacy installs may have left the config world-readable (umask default\n // 0o644). Tighten it here so users who only run read-only commands still\n // get the secret-file permissions applied without waiting for a write.\n tightenSecretFilePermissions(configPath);\n\n // Check for unsupported future versions\n const version =\n rawConfig != null && typeof rawConfig === \"object\" && \"version\" in rawConfig\n ? rawConfig.version\n : undefined;\n if (typeof version === \"number\" && version > LATEST_CONFIG_VERSION) {\n const minSdk =\n \"min_sdk_version\" in (rawConfig as object)\n ? String((rawConfig as { min_sdk_version: unknown }).min_sdk_version)\n : undefined;\n const updateHint = minSdk\n ? `Please update your SDK to >= ${minSdk}: pnpm update @tailor-platform/sdk`\n : \"Please update your SDK: pnpm update @tailor-platform/sdk\";\n throw new Error(ml`\n Config file uses version ${String(version)}, but this SDK only supports up to version ${String(LATEST_CONFIG_VERSION)}.\n ${updateHint}\n `);\n }\n\n // Try v3 first\n const v3Result = pfConfigSchemaV3.safeParse(rawConfig);\n if (v3Result.success) {\n await warnIfNewerConfigAvailable(v3Result.data);\n return v3Result.data;\n }\n\n // Try v2 next\n const v2Result = pfConfigSchemaV2.safeParse(rawConfig);\n if (v2Result.success) {\n await warnIfNewerConfigAvailable(v2Result.data);\n return migrateV2ToV3(v2Result.data);\n }\n\n // Fall back to v1 (convert to v3 in memory, but don't rewrite disk)\n const v1Result = pfConfigSchemaV1.safeParse(rawConfig);\n if (v1Result.success) {\n return migrateV1ToV3(v1Result.data);\n }\n\n // Neither v1, v2, nor v3\n throw new Error(ml`\n Failed to parse config file at ${configPath}.\n The file may be corrupted or created by an incompatible SDK version.\n `);\n}\n\nfunction toV1ForDisk(config: PfConfigV2): PfConfigV1 {\n const users: PfConfigV1[\"users\"] = {};\n for (const [name, entry] of Object.entries(config.users)) {\n if (!entry || entry.storage === \"keyring\") continue;\n users[name] = {\n access_token: entry.access_token,\n refresh_token: entry.refresh_token,\n token_expires_at: entry.token_expires_at,\n };\n }\n const currentUser =\n config.current_user && hasCurrentUserEntry(users, config.current_user)\n ? config.current_user\n : null;\n return {\n version: 1,\n users,\n profiles: config.profiles,\n current_user: currentUser,\n };\n}\n\nfunction hasProfilePlatformSettings(config: Pick<PfConfig | PfConfigV1, \"profiles\">): boolean {\n return Object.values(config.profiles).some(\n (profile) =>\n profile?.platform_url !== undefined ||\n profile?.oauth2_client_id !== undefined ||\n profile?.console_url !== undefined,\n );\n}\n\nfunction hasScopedUserKeys(config: Pick<PfConfig | PfConfigV1, \"users\">): boolean {\n return Object.keys(config.users).some((userKey) => userKey.includes(\"|\"));\n}\n\nfunction hasKeysOutside(entry: object | undefined, knownKeys: ReadonlySet<string>): boolean {\n return (\n entry !== undefined &&\n Object.entries(entry).some(([key, value]) => value !== undefined && !knownKeys.has(key))\n );\n}\n\nfunction hasFieldsUnknownToV2(config: PfConfig | PfConfigV2 | PfConfigV1): boolean {\n return (\n hasKeysOutside(config, v2ConfigKeys) ||\n Object.values(config.users).some((user) => hasKeysOutside(user, v2UserKeys)) ||\n Object.values(config.profiles).some((profile) => hasKeysOutside(profile, profileKeys))\n );\n}\n\nfunction toLatestForDisk(config: PfConfig | PfConfigV2 | PfConfigV1): PfConfigV3 {\n const latestInput = config.version === 1 ? migrateV1ToV2(config) : config;\n return {\n ...latestInput,\n version: LATEST_CONFIG_VERSION,\n min_sdk_version: V3_MIN_SDK_VERSION,\n };\n}\n\n/**\n * Write Tailor Platform CLI configuration to disk.\n * By default, file-backed configs without newer fields are converted to V1 for\n * backward compatibility, so an older SDK can still read the file. Configs\n * containing a keyring user are kept in V2 or later because the keyring storage\n * variant is not representable in V1. Configs containing profile-level Platform\n * settings, platform-scoped user tokens, canonical user IDs, email metadata, or\n * any other field the V2 format does not define are written in the latest\n * min-SDK-gated format because older SDKs would silently drop or misread those\n * settings.\n *\n * The config file may contain access/refresh tokens when the OS keyring is\n * unavailable, so it is written via {@link writeSecretFile} so other users\n * on the host cannot read it.\n * @param config - Platform configuration to write\n */\nexport function writePlatformConfig(config: PfConfig | PfConfigV2 | PfConfigV1) {\n const configPath = platformConfigPath();\n const hasKeyringUser =\n config.version !== 1 && Object.values(config.users).some((u) => u?.storage === \"keyring\");\n const diskConfig =\n config.version === LATEST_CONFIG_VERSION ||\n hasProfilePlatformSettings(config) ||\n hasScopedUserKeys(config) ||\n hasFieldsUnknownToV2(config)\n ? toLatestForDisk(config)\n : config.version === V2_CONFIG_VERSION && !hasKeyringUser\n ? toV1ForDisk(config)\n : config;\n writeSecretFile(\n configPath,\n stringifyYAML(\n diskConfig.version === 1\n ? diskConfig\n : { ...diskConfig, users: withoutKeyringFileTokens(diskConfig.users) },\n ),\n );\n}\n\nfunction withoutKeyringFileTokens(users: PfConfig[\"users\"] | PfConfigV2[\"users\"]) {\n return Object.fromEntries(\n Object.entries(users).map(([userKey, entry]) => {\n if (entry?.storage !== \"keyring\") return [userKey, entry];\n const { access_token: _accessToken, refresh_token: _refreshToken, ...keyringEntry } = entry;\n return [userKey, keyringEntry];\n }),\n );\n}\n\nfunction validateUUID(value: string, source: string): string {\n const result = z.uuid().safeParse(value);\n if (!result.success) {\n throw new Error(`Invalid value from ${source}: must be a valid UUID`);\n }\n return result.data;\n}\n\n/**\n * Load workspace ID from command options, environment variables, or platform config.\n * In CLI context, env fallback is also handled by politty's arg env option.\n * Priority: opts/workspaceId > env/workspaceId > opts/profile > error\n * @param opts - Workspace and profile options\n * @returns Resolved workspace ID\n */\nexport async function loadWorkspaceId(opts?: LoadWorkspaceIdOptions): Promise<string> {\n const workspaceId = await tryLoadWorkspaceId(opts);\n if (workspaceId) return workspaceId;\n\n throw new Error(ml`\n Workspace ID not found.\n Please specify workspace ID via --workspace-id option or TAILOR_PLATFORM_WORKSPACE_ID environment variable.\n `);\n}\n\n/**\n * Load a workspace ID when one is explicitly configured.\n * @param opts - Workspace and profile options\n * @returns Resolved workspace ID, or undefined when no source is configured\n */\nexport async function tryLoadWorkspaceId(\n opts?: LoadWorkspaceIdOptions,\n): Promise<string | undefined> {\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n\n if (opts?.workspaceId !== undefined) {\n return validateUUID(opts.workspaceId, \"--workspace-id option\");\n }\n\n if (process.env.TAILOR_PLATFORM_WORKSPACE_ID) {\n return validateUUID(\n process.env.TAILOR_PLATFORM_WORKSPACE_ID,\n \"TAILOR_PLATFORM_WORKSPACE_ID environment variable\",\n );\n }\n\n if (profile) {\n const pfConfig = await readPlatformConfig();\n const profileEntry = pfConfig.profiles[profile];\n const wsId = profileEntry?.workspace_id;\n if (!wsId) {\n throw profileNotFoundError(profile);\n }\n return validateUUID(wsId, `profile \"${profile}\"`);\n }\n\n return undefined;\n}\n\n/**\n * Load machine user name from command options, environment variables, or platform config.\n * In CLI context, env fallback is also handled by politty's arg env option.\n * Priority: opts/machineUser > env/TAILOR_PLATFORM_MACHINE_USER_NAME > opts/profile (profile default) > undefined.\n * An explicitly empty `opts.machineUser` is rejected with a CLIError (`MACHINE_USER_NAME_EMPTY`) rather than falling back to the env var or profile default.\n * When the active profile has `machine_user_override: \"deny\"`, an explicit value that differs from the profile's machine user throws a CLIError with code `PROFILE_MACHINE_USER_OVERRIDE_DENIED`.\n * @param opts - Machine user and profile options\n * @returns Resolved machine user name, or undefined if not set\n */\nexport async function loadMachineUserName(\n opts?: LoadMachineUserNameOptions,\n): Promise<string | undefined> {\n if (opts?.machineUser === \"\") {\n throw CLIError({\n code: \"MACHINE_USER_NAME_EMPTY\",\n message: \"Machine user name cannot be empty.\",\n suggestion:\n \"Pass a non-empty machine user name, or omit the option to use the environment variable or profile default.\",\n });\n }\n\n const envMachineUser = process.env.TAILOR_PLATFORM_MACHINE_USER_NAME || undefined;\n const explicitMachineUser: ExplicitMachineUser | undefined = opts?.machineUser\n ? {\n source: opts.machineUserSource ?? \"option\",\n value: opts.machineUser,\n }\n : envMachineUser\n ? { source: \"env\", value: envMachineUser }\n : undefined;\n const explicit = explicitMachineUser?.value;\n\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n if (!profile) return explicit;\n\n const pfConfig = await readPlatformConfig();\n const entry = pfConfig.profiles[profile];\n if (!entry) {\n if (explicit) return explicit;\n throw profileNotFoundError(profile);\n }\n\n if (entry.machine_user && entry.machine_user_override === \"deny\") {\n if (explicit && explicit !== entry.machine_user) {\n const details =\n explicitMachineUser.source === \"env\"\n ? `The machine user is being set to \"${explicit}\" via the TAILOR_PLATFORM_MACHINE_USER_NAME environment variable, which conflicts with this profile's pinned machine user \"${entry.machine_user}\".`\n : `This profile fixes the machine user to \"${entry.machine_user}\" for application-data commands.`;\n throw CLIError({\n code: \"PROFILE_MACHINE_USER_OVERRIDE_DENIED\",\n message: `Profile \"${profile}\" denies overriding the machine user.`,\n details,\n suggestion: `Omit the machine user option, unset TAILOR_PLATFORM_MACHINE_USER_NAME, or run ${formatCommandHint(\n {\n command: \"tailor\",\n args: profileUpdateArgs(profile, [\"--machine-user-override\", \"allow\"]),\n },\n )}.`,\n });\n }\n return entry.machine_user;\n }\n\n return explicit || entry.machine_user;\n}\n\n/**\n * Read the access token set through the environment, which takes precedence over any logged-in user.\n * @returns TAILOR_PLATFORM_TOKEN, or the deprecated TAILOR_TOKEN, when set\n */\nexport function readEnvironmentToken(): string | undefined {\n return process.env.TAILOR_PLATFORM_TOKEN ?? process.env.TAILOR_TOKEN;\n}\n\n/**\n * Read the stored browser login for a profile without ever renewing it: no refresh request, no\n * config write, no lock. For best-effort background calls that may be abandoned mid-flight,\n * where a refresh could rotate the refresh token and lose the replacement. Pair it with\n * `initOperatorClient(token, config, { renewToken: false })`.\n * @param opts - Profile options\n * @param opts.profile - Profile name; falls back to TAILOR_PLATFORM_PROFILE, then the current user\n * @returns The stored access token and the profile's platform settings, or undefined when there\n * is no login or the token is due for renewal\n */\nexport async function loadStoredAccessTokenWithoutRefresh(opts: {\n profile?: string | undefined;\n}): Promise<{ accessToken: string; platformConfig: PlatformClientConfig | undefined } | undefined> {\n const profile = opts.profile || process.env.TAILOR_PLATFORM_PROFILE;\n const pfConfig = await readPlatformConfig();\n const profileEntry = profile ? pfConfig.profiles[profile] : undefined;\n if (profile && !profileEntry) return undefined;\n const user = profileEntry?.user ?? pfConfig.current_user;\n if (!user) return undefined;\n const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n const stored = await readStoredToken(pfConfig, user, platformConfig, loginFailureFor(profile));\n if (isDueForRefresh(stored)) return undefined;\n return { accessToken: stored.tokens.accessToken, platformConfig };\n}\n\n/**\n * Load access token from environment variables, command options, or platform config.\n * In CLI context, profile env fallback is also handled by politty's arg env option.\n * Priority: env/TAILOR_PLATFORM_TOKEN > env/TAILOR_TOKEN (deprecated) > opts/profile > env/profile > config/currentUser > error\n * @param opts - Profile options\n * @returns Resolved access token\n */\nexport async function loadAccessToken(opts?: LoadAccessTokenOptions) {\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n const envToken = readEnvironmentToken();\n if (envToken && !process.env.TAILOR_PLATFORM_TOKEN) {\n logger.warn(\"TAILOR_TOKEN is deprecated. Please use TAILOR_PLATFORM_TOKEN instead.\");\n }\n\n if (envToken) {\n logger.registerSecret(envToken);\n const platformConfig = await loadPlatformClientConfig({ profile, allowMissingProfile: true });\n rememberPlatformConfigForToken(envToken, platformConfig);\n return envToken;\n }\n\n const pfConfig = await readPlatformConfig();\n const profileEntry = profile ? pfConfig.profiles[profile] : undefined;\n if (profile && !profileEntry) {\n throw profileNotFoundError(profile);\n }\n const user = profileEntry?.user ?? pfConfig.current_user;\n if (!user) {\n throw CLIError({\n code: \"AUTH_TOKEN_NOT_FOUND\",\n message: \"Tailor Platform token not found.\",\n suggestion: \"Set TAILOR_PLATFORM_TOKEN or log in using the selected profile.\",\n next: { command: \"tailor\", args: [\"login\", ...recoveryContextArgs({ profile })] },\n context: { profile: profile ?? null },\n });\n }\n const fromProfile = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n const token = await resolveLatestToken({\n config: pfConfig,\n user,\n platformConfig: fromProfile,\n profile,\n });\n if (token.refreshable) {\n registerAccessTokenSource(\n token.accessToken,\n createStoredTokenSource({ token, platformConfig: fromProfile, profile }),\n );\n }\n return token.accessToken;\n}\n\n/**\n * Resolve authentication metadata without returning token values.\n * @param opts - Profile options\n * @returns Authentication status for the active environment and profile\n */\nexport async function loadAuthStatus(opts?: LoadAccessTokenOptions): Promise<AuthStatus> {\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n const envToken = readEnvironmentToken();\n if (envToken && !process.env.TAILOR_PLATFORM_TOKEN) {\n logger.warn(\"TAILOR_TOKEN is deprecated. Please use TAILOR_PLATFORM_TOKEN instead.\");\n }\n\n if (envToken) {\n logger.registerSecret(envToken);\n const config = await readPlatformConfig().catch(() => undefined);\n const profileEntry = profile ? config?.profiles[profile] : undefined;\n const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n return {\n authenticated: true,\n identity: null,\n identitySource: \"environment\",\n profile: profile ?? null,\n workspaceId: process.env.TAILOR_PLATFORM_WORKSPACE_ID ?? profileEntry?.workspace_id ?? null,\n permission: profileEntry?.readonly === true ? \"read\" : \"write\",\n platformUrl: getPlatformBaseUrl(platformConfig),\n tokenStatus: \"environment\",\n };\n }\n\n const config = await readPlatformConfig();\n const profileEntry = profile ? config.profiles[profile] : undefined;\n if (profile && !profileEntry) {\n throw profileNotFoundError(profile);\n }\n\n const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n const platformUrl = getPlatformBaseUrl(platformConfig);\n const workspaceId =\n process.env.TAILOR_PLATFORM_WORKSPACE_ID ?? profileEntry?.workspace_id ?? null;\n\n const identity = profileEntry?.user ?? config.current_user;\n const identitySource = profileEntry?.user ? \"profile\" : identity ? \"default\" : \"none\";\n let tokenStatus: AuthStatus[\"tokenStatus\"] = \"missing\";\n if (identity) {\n const { userKey, userEntry } = findUserEntry(config, identity, platformConfig);\n if (userEntry) {\n const tokens = await resolveTokens(userEntry, userKey, identity).catch(() => undefined);\n if (tokens) {\n const expired = new Date(userEntry.token_expires_at) <= new Date();\n if (!expired) {\n tokenStatus = \"valid\";\n } else {\n tokenStatus = tokens.refreshToken ? \"refreshable\" : \"expired\";\n }\n }\n }\n }\n\n return {\n authenticated: tokenStatus === \"valid\" || tokenStatus === \"refreshable\",\n identity: identity ?? null,\n identitySource,\n profile: profile ?? null,\n workspaceId,\n permission: profileEntry?.readonly === true ? \"read\" : \"write\",\n platformUrl,\n tokenStatus,\n };\n}\n\n/** Where `workspace create` places a workspace when no location is given. */\nexport type UserWorkspaceDefaults = {\n organizationId: string;\n folderId?: string;\n};\n\n/**\n * Resolve the selected user's entry on the selected platform without a legacy-key fallback.\n * @param config - Platform config\n * @param opts - Profile options\n * @returns The selected user and entry, or undefined when the profile does not exist\n */\nexport function resolveSelectedUserEntry(config: PfConfig, opts?: LoadAccessTokenOptions) {\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n const profileEntry = profile ? config.profiles[profile] : undefined;\n if (profile && !profileEntry) return undefined;\n const user = profileEntry?.user ?? config.current_user;\n const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : undefined;\n const userEntry = user\n ? findUserEntry(config, user, platformConfig, { allowLegacyUserKey: false }).userEntry\n : undefined;\n return { profile, user, userEntry };\n}\n\n/**\n * Load the default organization and folder stored on the user that config-based authentication\n * selects. An environment token's identity is not a config user, so none apply while one is set.\n * @param opts - Profile options\n * @returns The user's defaults, or undefined when none apply\n */\nexport async function loadUserWorkspaceDefaults(\n opts?: LoadAccessTokenOptions,\n): Promise<UserWorkspaceDefaults | undefined> {\n if (readEnvironmentToken()) return undefined;\n const config = await readPlatformConfig();\n const userEntry = resolveSelectedUserEntry(config, opts)?.userEntry;\n if (!userEntry?.default_organization_id) return undefined;\n return {\n organizationId: userEntry.default_organization_id,\n ...(userEntry.default_folder_id ? { folderId: userEntry.default_folder_id } : {}),\n };\n}\n\n/**\n * Load platform connection settings from the active profile.\n * @param opts - Profile options\n * @returns Resolved platform connection settings, or undefined for the default environment\n */\nexport async function loadPlatformClientConfig(\n opts?: LoadPlatformClientConfigOptions,\n): Promise<PlatformClientConfig | undefined> {\n const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;\n if (!profile) {\n return undefined;\n }\n\n let pfConfig: PfConfig;\n try {\n pfConfig = await readPlatformConfig();\n } catch (error) {\n if (opts?.allowMissingProfile) {\n return undefined;\n }\n throw error;\n }\n const profileEntry = pfConfig.profiles[profile];\n if (!profileEntry) {\n if (opts?.allowMissingProfile) {\n return undefined;\n }\n throw profileNotFoundError(profile);\n }\n return platformConfigFromProfile(profileEntry);\n}\n\n/**\n * Load the Tailor Platform Console base URL from environment variables or the active profile.\n * @param opts - Profile options\n * @returns Resolved Console base URL\n */\nexport async function loadConsoleBaseUrl(opts?: LoadConsoleBaseUrlOptions): Promise<string> {\n const platformConfig = await loadPlatformClientConfig(opts);\n return getConsoleBaseUrl(platformConfig);\n}\n\n/**\n * Registers a token pair's values with the logger so they are redacted from diagnostic\n * log output, wherever they later flow (retries, error messages, etc.). Call this as soon\n * as a token is obtained, not just before it is persisted — code between the two points\n * (e.g. an intervening API call) can still fail or log diagnostically.\n * @param tokens - Access token and optional refresh token\n */\nexport function registerTokenSecrets(tokens: UserTokens): void {\n logger.registerSecret(tokens.accessToken);\n if (tokens.refreshToken) logger.registerSecret(tokens.refreshToken);\n}\n\n/**\n * Resolve the actual token values for a user, reading from keyring or config as appropriate.\n * @param userEntry - User entry from the config\n * @param user - User identifier\n * @param label - User-facing identifier used in error messages\n * @returns Access token and optional refresh token\n */\nexport async function resolveTokens(\n userEntry: PfUser,\n user: string,\n label = user,\n): Promise<{ accessToken: string; refreshToken?: string }> {\n if (userEntry.storage === \"keyring\") {\n let tokens: UserTokens | undefined;\n try {\n tokens = await loadKeyringTokens(user);\n } catch (error) {\n throw new Error(\n ml`\n Failed to read credentials from OS keyring for \"${label}\". ${formatUnknownError(error)}\n Restore access to the OS keyring and try again, or run 'tailor login' in this environment to authenticate again.\n For non-interactive environments, set TAILOR_PLATFORM_TOKEN.\n `,\n { cause: error },\n );\n }\n if (!tokens) {\n throw new Error(ml`\n Credentials not found in OS keyring for \"${label}\".\n Credentials may be missing or inaccessible from this environment (for example, due to sandbox restrictions).\n Restore access to the OS keyring and try again, or run 'tailor login' in this environment to authenticate again.\n For non-interactive environments, set TAILOR_PLATFORM_TOKEN.\n `);\n }\n registerTokenSecrets(tokens);\n return tokens;\n }\n\n const tokens = {\n accessToken: userEntry.access_token,\n refreshToken: userEntry.refresh_token,\n };\n registerTokenSecrets(tokens);\n return tokens;\n}\n\nfunction userExtraFields(entry: PfUser | undefined) {\n if (!entry) return {};\n return withoutKeys(entry, userTokenKeys);\n}\n\ntype RemoveUserAliasOptions = {\n carryExtraFields: boolean;\n};\n\nasync function removeUserAlias(\n config: PfConfig,\n aliasKey: string,\n canonicalKey: string,\n opts: RemoveUserAliasOptions,\n) {\n const entry = config.users[aliasKey];\n if (aliasKey === canonicalKey || !entry) return;\n const canonicalEntry = config.users[canonicalKey];\n if (opts.carryExtraFields && canonicalEntry) {\n config.users[canonicalKey] = { ...userExtraFields(entry), ...canonicalEntry };\n }\n if (entry.storage === \"keyring\") {\n await deleteKeyringTokens(aliasKey);\n }\n delete config.users[aliasKey];\n}\n\n/**\n * Save tokens for a user, writing to keyring by default when available.\n * @param config - Platform config\n * @param user - User identifier\n * @param tokens - Token data to save\n * @param tokens.accessToken - Access token to save\n * @param tokens.refreshToken - Optional refresh token to save\n * @param expiresAt - Token expiration date\n * @param opts - Optional platform and user metadata\n */\nexport async function saveUserTokens(\n config: PfConfig,\n user: string,\n tokens: UserTokens,\n expiresAt: string,\n opts: { platformConfig?: PlatformClientConfig; email?: string } = {},\n): Promise<void> {\n registerTokenSecrets(tokens);\n const userKey = platformUserKey(user, opts.platformConfig);\n const existing = config.users[userKey];\n const extraFields = userExtraFields(existing);\n const email = opts.email ?? existing?.email;\n if (await trySaveTokensInKeyring(userKey, tokens)) {\n config.users[userKey] = {\n ...extraFields,\n token_expires_at: expiresAt,\n storage: \"keyring\",\n ...(email ? { email } : {}),\n };\n } else {\n if (existing?.storage === \"keyring\") {\n await deleteKeyringTokens(userKey);\n }\n config.users[userKey] = {\n ...extraFields,\n access_token: tokens.accessToken,\n refresh_token: tokens.refreshToken,\n token_expires_at: expiresAt,\n storage: \"file\",\n ...(email ? { email } : {}),\n };\n }\n}\n\n/**\n * Delete tokens for a user from keyring if applicable.\n * @param config - Platform config\n * @param user - User identifier\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n */\nexport async function deleteUserTokens(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts?: UserEntryLookupOptions,\n): Promise<void> {\n const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);\n if (userEntry?.storage === \"keyring\") {\n await deleteKeyringTokens(userKey);\n }\n delete config.users[userKey];\n}\n\n/**\n * Resolve stored tokens for a user on the selected platform.\n * @param config - Platform config\n * @param user - User name\n * @param platformConfig - Optional platform connection settings\n * @param opts - Token lookup options\n * @returns Stored user entry and token values, or undefined when the user is not logged in\n */\nexport async function loadStoredUserTokens(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n opts?: UserEntryLookupOptions,\n): Promise<\n | {\n userEntry: PfUser;\n accessToken: string;\n refreshToken?: string;\n }\n | undefined\n> {\n const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);\n if (!userEntry) return undefined;\n const tokens = await resolveTokens(userEntry, userKey, user);\n return { userEntry, ...tokens };\n}\n\nfunction updateUserReferences(config: PfConfig, fromUser: string, toUser: string) {\n if (fromUser === toUser) return;\n if (config.current_user === fromUser) {\n config.current_user = toUser;\n }\n for (const profile of Object.values(config.profiles)) {\n if (profile?.user === fromUser) {\n profile.user = toUser;\n }\n }\n}\n\n/**\n * Remove a legacy alias after a canonical user ID has been written.\n * @param config - Platform config\n * @param legacyUser - Previous user key\n * @param canonicalUser - Canonical user key\n * @param platformConfig - Platform settings for scoped token storage\n */\nexport async function removeLegacyUserAlias(\n config: PfConfig,\n legacyUser: string,\n canonicalUser: string,\n platformConfig?: PlatformClientConfig,\n): Promise<void> {\n if (legacyUser === canonicalUser) return;\n updateUserReferences(config, legacyUser, canonicalUser);\n const canonicalKey = platformUserKey(canonicalUser, platformConfig);\n const scopedLegacyKey = platformUserKey(legacyUser, platformConfig);\n await removeUserAlias(config, scopedLegacyKey, canonicalKey, { carryExtraFields: true });\n const legacyKeyServesThisPlatform = canUseLegacyUserKey(getPlatformBaseUrl(platformConfig));\n await removeUserAlias(config, legacyUser, canonicalKey, {\n carryExtraFields: legacyKeyServesThisPlatform,\n });\n}\n\nfunction shouldResolveSubjectOnRefresh(user: string, userEntry: PfUser): boolean {\n return Boolean(userEntry.email || inferEmailFromUserId(user));\n}\n\n/**\n * Run a callback while holding the lock on the platform config file, which token refresh\n * and logout take while they read and write stored tokens.\n * @param fn - Callback to run while holding the lock\n * @param options - Lock options\n * @returns The callback's result\n */\nexport async function withPlatformConfigLock<T>(\n fn: () => Promise<T>,\n options?: ConfigLockOptions,\n): Promise<T> {\n return await withConfigLock(`${platformConfigPath()}.lock`, fn, options);\n}\n\nconst TOKEN_REFRESH_MARGIN_MS = 5 * 60 * 1000;\nconst EARLY_REFRESH_LOCK_TIMEOUT_MS = 2_000;\nconst MIN_USABLE_TOKEN_LIFETIME_MS = 10_000;\n\ntype LatestToken = { accessToken: string; user: string };\ntype ResolvedToken = LatestToken & { expiresAt: number; refreshable: boolean };\ntype LoginFailure = (code: string, message: string, suggestion: string) => Error;\ntype StoredToken = {\n userKey: string;\n configUser: string;\n entry: PfUser;\n tokens: UserTokens;\n};\ntype TokenRequest = {\n config: PfConfig;\n user: string;\n platformConfig?: PlatformClientConfig;\n profile?: string;\n /** A token the Platform rejected; a stored token equal to it counts as expired. */\n rejectedToken?: string;\n};\n\nfunction expiresWithin(expiresAt: number, marginMs: number): boolean {\n const remainingMs = expiresAt - Date.now();\n return Number.isNaN(remainingMs) || remainingMs <= marginMs;\n}\n\nfunction isExpired(stored: StoredToken, rejectedToken?: string): boolean {\n return (\n stored.tokens.accessToken === rejectedToken ||\n expiresWithin(Date.parse(stored.entry.token_expires_at), MIN_USABLE_TOKEN_LIFETIME_MS)\n );\n}\n\nfunction isDueForRefresh(stored: StoredToken, rejectedToken?: string): boolean {\n return (\n isExpired(stored, rejectedToken) ||\n (Boolean(stored.tokens.refreshToken) &&\n expiresWithin(Date.parse(stored.entry.token_expires_at), TOKEN_REFRESH_MARGIN_MS))\n );\n}\n\nasync function readStoredToken(\n config: PfConfig,\n user: string,\n platformConfig: PlatformClientConfig | undefined,\n loginFailure: LoginFailure,\n): Promise<StoredToken> {\n const { userKey, userEntry } = findUserEntry(config, user, platformConfig);\n if (!userEntry) {\n throw loginFailure(\n \"AUTH_USER_NOT_FOUND\",\n `User \"${user}\" not found.`,\n \"Verify the selected user and use the original login method (browser or --machine-user) on the same platform.\",\n );\n }\n return {\n userKey,\n configUser: userFromPlatformUserKey(userKey, platformConfig),\n entry: userEntry,\n tokens: await resolveTokens(userEntry, userKey, user),\n };\n}\n\nfunction useStoredToken(\n stored: StoredToken,\n platformConfig: PlatformClientConfig | undefined,\n): ResolvedToken {\n rememberPlatformConfigForToken(stored.tokens.accessToken, platformConfig);\n return {\n accessToken: stored.tokens.accessToken,\n user: stored.configUser,\n expiresAt: Date.parse(stored.entry.token_expires_at),\n refreshable: Boolean(stored.tokens.refreshToken),\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction replaceContents(target: Record<string, unknown>, source: Record<string, unknown>) {\n for (const key of Object.keys(target)) {\n if (!Object.hasOwn(source, key)) delete target[key];\n }\n for (const [key, value] of Object.entries(source)) {\n const current = target[key];\n if (isRecord(current) && isRecord(value)) {\n replaceContents(current, value);\n } else {\n target[key] = value;\n }\n }\n}\n\n/**\n * Fetch the latest access token, refreshing it when it expires within five minutes.\n * A refresh rereads the stored config under {@link withPlatformConfigLock} and uses a token\n * another process stored in the meantime instead of refreshing again. Until the current token\n * expires, a refresh that fails or would wait for another process falls back to it.\n * @param config - Platform config; replaced in place with the stored config when a refresh was needed\n * @param user - User identifier\n * @param platformConfig - Optional platform connection settings\n * @param profile - Selected profile for login recovery\n * @returns Latest access token and the canonical user ID it is stored under\n * (the resolved subject when a legacy email key was migrated during refresh,\n * otherwise the matching config user)\n */\nexport async function fetchLatestToken(\n config: PfConfig,\n user: string,\n platformConfig?: PlatformClientConfig,\n profile?: string,\n): Promise<LatestToken> {\n const latest = await resolveLatestToken({ config, user, platformConfig, profile });\n return { accessToken: latest.accessToken, user: latest.user };\n}\n\nfunction loginFailureFor(profile: string | undefined): LoginFailure {\n const loginArgs = profile ? [\"--profile\", profile] : [];\n return (code, message, suggestion) =>\n CLIError({\n code,\n message,\n suggestion,\n next: { command: \"tailor\", args: [\"login\", ...loginArgs, \"--help\"] },\n context: { profile: profile ?? null },\n });\n}\n\nfunction tokenExpiredError(loginFailure: LoginFailure): Error {\n return loginFailure(\n \"AUTH_TOKEN_EXPIRED\",\n \"Token expired.\",\n \"Use the original login method (browser or --machine-user) to authenticate again on the same platform.\",\n );\n}\n\nasync function resolveLatestToken(request: TokenRequest): Promise<ResolvedToken> {\n const { config, user, platformConfig, profile, rejectedToken } = request;\n const loginFailure = loginFailureFor(profile);\n const stored = await readStoredToken(config, user, platformConfig, loginFailure);\n if (!isDueForRefresh(stored, rejectedToken)) return useStoredToken(stored, platformConfig);\n\n const expired = isExpired(stored, rejectedToken);\n try {\n return await withPlatformConfigLock(\n async () => {\n const latest = await readPlatformConfig();\n try {\n return await refreshStoredToken({ ...request, config: latest }, loginFailure);\n } finally {\n replaceContents(config, latest);\n }\n },\n expired ? undefined : { timeoutMs: EARLY_REFRESH_LOCK_TIMEOUT_MS },\n );\n } catch (error) {\n if (expired || !isConfigLockTimeout(error)) throw error;\n if (isExpired(stored, rejectedToken)) return await resolveLatestToken(request);\n logger.debug(\"Another tailor command is refreshing the token; using the current token.\");\n return useStoredToken(stored, platformConfig);\n }\n}\n\nasync function refreshStoredToken(\n request: TokenRequest,\n loginFailure: LoginFailure,\n): Promise<ResolvedToken> {\n const { config, user, platformConfig, rejectedToken } = request;\n const stored = await readStoredToken(config, user, platformConfig, loginFailure);\n if (!isDueForRefresh(stored, rejectedToken)) return useStoredToken(stored, platformConfig);\n\n const { userKey: storedUser, configUser: storedConfigUser, entry: userEntry, tokens } = stored;\n if (!tokens.refreshToken) throw tokenExpiredError(loginFailure);\n\n const client = initOAuth2Client(platformConfig);\n let resp;\n try {\n resp = await client.refreshToken({\n accessToken: tokens.accessToken,\n refreshToken: tokens.refreshToken,\n expiresAt: Date.parse(userEntry.token_expires_at),\n });\n } catch (error) {\n if (!isExpired(stored, rejectedToken)) {\n logger.debug(`Failed to refresh a token that has not expired yet: ${String(error)}`);\n return useStoredToken(stored, platformConfig);\n }\n throw loginFailure(\n \"AUTH_TOKEN_REFRESH_FAILED\",\n \"Failed to refresh token. Your session may have expired.\",\n \"Check network connectivity and platform availability, then use the original login method (browser or --machine-user) on the same platform if needed.\",\n );\n }\n registerTokenSecrets({\n accessToken: resp.accessToken,\n refreshToken: resp.refreshToken ?? undefined,\n });\n\n const refreshedTokens = {\n accessToken: resp.accessToken,\n refreshToken: resp.refreshToken ?? tokens.refreshToken,\n };\n const newExpiresAt = new Date(\n assertDefined(resp.expiresAt, \"token refresh response missing expiresAt\"),\n ).toISOString();\n const previousEmail =\n userEntry.email ?? inferEmailFromUserId(user) ?? inferEmailFromUserId(storedConfigUser);\n\n // Store before any other request: the refresh token just sent is already invalid.\n await saveUserTokens(config, storedConfigUser, refreshedTokens, newExpiresAt, {\n platformConfig,\n email: previousEmail,\n });\n writePlatformConfig(config);\n\n let resolvedUser = storedConfigUser;\n let email = previousEmail;\n if (\n shouldResolveSubjectOnRefresh(user, userEntry) ||\n shouldResolveSubjectOnRefresh(storedConfigUser, userEntry)\n ) {\n try {\n const userInfo = await fetchUserInfo(resp.accessToken, platformConfig);\n resolvedUser = userInfo.sub;\n email = userInfo.email;\n } catch (error) {\n logger.debug(`Failed to resolve refreshed token user info: ${String(error)}`);\n }\n }\n\n if (resolvedUser !== storedConfigUser || email !== previousEmail) {\n await saveUserTokens(config, resolvedUser, refreshedTokens, newExpiresAt, {\n platformConfig,\n email,\n });\n }\n await removeLegacyUserAlias(config, user, resolvedUser, platformConfig);\n await removeUserAlias(config, storedUser, platformUserKey(resolvedUser, platformConfig), {\n carryExtraFields: true,\n });\n if (previousEmail && email && previousEmail !== email) {\n logger.info(`Updated local user email from \"${previousEmail}\" to \"${email}\".`);\n }\n writePlatformConfig(config);\n rememberPlatformConfigForToken(resp.accessToken, platformConfig);\n return {\n accessToken: resp.accessToken,\n user: resolvedUser,\n expiresAt: Date.parse(newExpiresAt),\n refreshable: true,\n };\n}\n\nconst RENEWAL_RETRY_INTERVAL_MS = 30_000;\nconst FORCED_RENEWAL_INTERVAL_MS = 60_000;\n\ntype StoredTokenSourceInit = {\n token: ResolvedToken;\n platformConfig?: PlatformClientConfig;\n profile?: string;\n};\n\n/**\n * Keep the token of a browser login usable for a long-running command. It renews only inside\n * a request, never on a timer, so the process cannot exit before a new token is stored.\n * @param init - Token to start from and the login it belongs to\n * @returns Source for the Operator client\n */\nfunction createStoredTokenSource(init: StoredTokenSourceInit): AccessTokenSource {\n let { accessToken, expiresAt, user } = init.token;\n let renewal: Promise<void> | undefined;\n let renewalError: Error | undefined;\n let retryAt = 0;\n let renewedAt = -Infinity;\n let forcedAt = -Infinity;\n let lastRejected: string | undefined;\n\n const isUsable = () => !expiresWithin(expiresAt, MIN_USABLE_TOKEN_LIFETIME_MS);\n const isDue = () =>\n expiresWithin(expiresAt, TOKEN_REFRESH_MARGIN_MS) && (!isUsable() || Date.now() >= retryAt);\n\n const renew = (rejectedToken?: string) =>\n (renewal ??= (async () => {\n try {\n const latest = await resolveLatestToken({\n config: await readPlatformConfig(),\n user,\n platformConfig: init.platformConfig,\n profile: init.profile,\n rejectedToken,\n });\n renewalError = undefined;\n const replacesRejected =\n rejectedToken !== undefined && latest.accessToken !== rejectedToken;\n if (latest.expiresAt > expiresAt || replacesRejected) {\n ({ accessToken, expiresAt, user } = latest);\n renewedAt = Date.now();\n registerAccessTokenSource(accessToken, source);\n } else {\n retryAt = Date.now() + RENEWAL_RETRY_INTERVAL_MS;\n }\n } catch (error) {\n renewalError = error instanceof Error ? error : new Error(String(error));\n retryAt = Date.now() + RENEWAL_RETRY_INTERVAL_MS;\n logger.debug(`Failed to renew the access token: ${String(error)}`);\n } finally {\n renewal = undefined;\n }\n })());\n\n const source: AccessTokenSource = {\n async current() {\n if (renewal && accessToken === lastRejected) await renewal;\n if (!isDue() || (renewal && isUsable())) return accessToken;\n await renew();\n if (!isUsable()) throw renewalError ?? tokenExpiredError(loginFailureFor(init.profile));\n return accessToken;\n },\n async replaceRejected(rejected) {\n if (accessToken !== rejected) return accessToken;\n lastRejected = rejected;\n while (renewal) await renewal;\n if (accessToken !== rejected) return accessToken;\n if (Date.now() - Math.max(renewedAt, forcedAt) < FORCED_RENEWAL_INTERVAL_MS) return undefined;\n forcedAt = Date.now();\n await renew(rejected);\n return accessToken === rejected ? undefined : accessToken;\n },\n };\n return source;\n}\n\nconst DEFAULT_CONFIG_FILENAME = \"tailor.config.ts\";\n\n/**\n * Load config path from command options, environment variables, or search parent directories.\n * In CLI context, env fallback is also handled by politty's arg env option.\n * Priority: opts/config > env/config > search parent directories\n * @param configPath - Optional explicit config path\n * @returns Resolved config path or undefined\n */\nexport function loadConfigPath(configPath?: string): string | undefined {\n if (configPath) {\n return configPath;\n }\n if (process.env.TAILOR_CONFIG_PATH) {\n return process.env.TAILOR_CONFIG_PATH;\n }\n\n // Search for config file in current directory and parent directories\n return findUpSync(DEFAULT_CONFIG_FILENAME);\n}\n"],"mappings":"A,s7BAwBA,MAAM0B,GAAyC,CAC7C,GAAI,EACJ,EAAG,IACH,EAAG,GACL,EAEMC,EAAkB,kBAMXC,GAAcC,EACxB,OAAO,CAAC,CACR,OAAQ,GAAQF,EAAgB,KAAKG,CAAG,EAAG,CAC1C,QAAS,+DACX,CAAC,CAAC,CACD,OACE,GAAQ,CACP,IAAMC,EAAQD,EAAI,MAAMH,CAAe,EACvC,GAAI,CAACI,EAAO,MAAO,GACnB,IAAMC,EAASD,EAAM,GACrB,OAAOC,IAAW,IAAA,IAAa,SAASA,EAAQ,EAAE,EAAI,CACxD,EACA,CAAE,QAAS,iCAAkC,CAC/C,EAOF,SAAgB,cAAc,EAA0B,CACtD,IAAMD,EAAQE,EACZC,EAAS,MAAMP,CAAe,EAC9B,4BAA4BO,GAC9B,EACMC,EAAQ,SAASF,EAAcF,EAAM,GAAI,+BAA+B,EAAG,EAAE,EAC7EK,EAAOH,EAAcF,EAAM,GAAI,6BAA6B,EAClE,OAAOI,EAAQT,GAASU,EAC1B,CAMA,MAAaC,GAAiBR,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAMlDS,EAAoBT,EAAE,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAKxDU,EAAWV,EAAE,KAAK,CAAC,MAAO,MAAM,CAAC,EAW9C,SAAgB,gBAAgB,EAAqD,CACnF,GAAIW,IAAU,IAAA,GACd,OAAOA,IAAU,MAAQvC,EAAc,IAAMA,EAAc,IAC7D,CAOA,SAAS,aAAa,EAA4C,CAChE,IAAMwC,EAAYC,EAAK,QAAQ,IAAI,EACnC,OAAOD,IAAc,GAAKC,EAAOA,EAAK,MAAM,EAAGD,CAAS,CAC1D,CAEA,SAAS,mBAAmB,EAAkC,CAC5D,OAAO,aAAaC,CAAI,CAAC,CAAC,KACvB,GACCC,IAAU,MACVA,EAAM,WAAW,KAAK,GACtBA,IAAU,kBACVA,EAAM,WAAW,iBAAiB,GAClCA,IAAU,iBACVA,EAAM,WAAW,gBAAgB,GACjCA,IAAU,iBACVA,EAAM,WAAW,gBAAgB,CACrC,CACF,CASA,SAAgB,8BACd,EACA,EAA0B,QAAQ,KAAK,MAAM,CAAC,EAC9C,EAAgD,CAAC,EACb,CACpC,GAAIC,IAAgB,IAAA,GAGpB,OAFIC,EAAQ,iBACR,mBAAmBH,CAAI,EAAU,SAC9B,QAAQ,IAAI,oCAAsCE,EAAc,MAAQ,QACjF,CAkBA,SAAgB,aAAa,EAAsB,EAAoC,CAErF,IAAME,EAAkB,IAAI,IAAI,OAAO,KAAK,QAAQ,GAAG,CAAC,EAElD,MAAQ,EAAmB,IAAsB,CACrD,IAAK,IAAMC,IAAQ,CAACC,GAAS,CAAC,CAAC,CAAC,CAAC,KAAK,EAAG,CACvC,IAAMC,EAAU3B,EAAK,QAAQ,QAAQ,IAAI,EAAGyB,CAAI,EAChD,GAAI,CAACxB,EAAG,WAAW0B,CAAO,EAAG,CAC3B,GAAIC,EACF,MAAU,MAAM,+BAA+BD,GAAS,EAE1D,QACF,CACA,IAAME,EAAU5B,EAAG,aAAa0B,EAAS,OAAO,EAC1CG,EAASC,GAASF,CAAO,EAC/B,IAAK,GAAM,CAACG,EAAKnB,KAAU,OAAO,QAAQiB,CAAM,EAE1CN,EAAgB,IAAIQ,CAAG,IAI3B,QAAQ,IAAIA,GAAOnB,EAEvB,CACF,EAEA,KAAKoB,EAAU,EAAI,EACnB,KAAKC,EAAkB,EAAK,CAC9B,CAOA,MAAMC,EAAgB,OAEhBC,EAAmB,UAEnBC,GAA6B,CACjC,yBAAU,IAAI,IAAI,CAAC,CAAC,IAAgBF,CAAa,CAAC,CAAC,EACnD,6BAAc,IAAI,IAAI,CAACA,EAAeC,CAAgB,CAAC,EACvD,8CAA+B,IAAI,GACrC,EAEA,IAAIE,EAAwB,GAO5B,SAAgB,mBAA6B,CAC3C,OAAOA,CACT,CASA,SAAS,gBAAgB,EAAkB,EAAuB,CAChE,OAAOC,GAAUC,EAAQH,EAA0B,CAAC,CAAC,QAAQI,EAC/D,CAUA,SAAS,gBAAgB,EAAyB,EAAc,EAAyB,CACvF,IAAMtB,EAAYC,EAAK,QAAQ,IAAI,EAEnC,OAAO,iBADSD,IAAc,GAAKC,EAAOA,EAAK,MAAM,EAAGD,CAAS,EAAA,CAEvD,OAAQ,GAAU,CACxB,GAAM,CAACE,GAASR,EAAM,MAAM,IAAK,CAAC,EAClC,OACEQ,IAAU,KAAKoB,KACf5B,IAAU,QAAQ4B,KACjBC,IAAU,IAAA,IAAarB,IAAU,IAAIqB,GAE1C,CAAC,EACDD,CACF,CACF,CAUA,SAAgB,kBAAkB,EAAkC,CAClE,OAAO,gBAAgBrB,EAAMe,EAAe,GAAc,IAAM,EAClE,CAQA,SAAgB,wBAAwB,EAAqD,CAC3F,IAAMQ,EAAO,gBAAgBvB,EAAMe,EAAe,GAAc,EAC1DS,EAAM,QAAQ,IAAIC,GAClBC,EACJF,IAAQ,IAAA,IAAa,gBAAgB,CAAC,KAAKT,EAAc,GAAGS,GAAK,EAAGT,CAAa,IAAM,GACzF,GAAIQ,IAAS,GAAM,OAAOG,EAAa,OAAS,OAChD,GAAIH,IAAS,IAAA,GACb,IAAIG,EAAY,MAAO,MACvB,GAAIF,IAAQ,IAAA,IAAa7D,EAAiB,IAAM,IAAA,GAAW,MAAO,OAD3C,CAGzB,CAUA,SAAgB,oBAAoB,EAAgB,EAA+B,CACjF,IAAMgE,EAAU,gBAAgB3B,EAAMgB,CAAgB,EAClD,OAAOW,GAAY,YAAW,EAAO,QAAUA,GACnD,IAAMC,EAAS,wBAAwB5B,CAAI,EACtC4B,IACLhE,EAAO,YAAY,GAAMgE,CAAM,EAE7BC,aAAiB,OACjB,OAAO,eAAeA,CAAK,IAAM,MAAM,WACvC,CAAC,OAAO,OAAOA,EAAO,MAAM,GAE5BrE,EAAqBqE,EAAO,CAAE,KAAM,mBAAoB,CAAC,EAE7D,CAOA,SAAS,cAAc,EAA+C,CAIpE,OAHID,IAAW,MAAc,MAEzBA,IAAW,UAAkB,QAC1BA,IAAW,OAASnE,EAAa,QAAQ,IAAAqE,kBAAwB,IAAM,GAC1E,OACA,MACN,CAmBA,SAAgB,iBAAiB,EAA6B,CAAC,EAAG,CAChE,MAAO,CACL,WAAYC,EAAI5C,EAAE,MAAMA,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,EAAG,CAC9C,MAAO,IACP,YAAa,+DACb,WAAY,CAAE,KAAM,OAAQ,QAAS,CAAC,SAAU,MAAM,CAAE,CAC1D,CAAC,EACD,qBAAsB4C,EAAI5C,EAAE,MAAMA,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,EAAG,CACxD,YAAa,iEACb,WAAY,CAAE,KAAM,OAAQ,QAAS,CAAC,SAAU,MAAM,CAAE,EAExD,QAAS,EAAQ,CAAE,UAAW,CAC5B,aACE6C,EAAK,YACLA,EAAK,qBACP,CACF,CACF,CAAC,GACAhB,GAAmBe,EAAI5C,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CAClD,GAAIgB,EAAQ,eAAiB,IAAA,GAAY,CAAC,EAAI,CAAE,MAAOA,EAAQ,YAAa,EAC5E,YAAa,yBACb,SAAU,GACV,QAAS,EAAO,CAAE,UAAW,CAC3B,EAAO,QAAU6B,EAAK,UAAUhB,CAAgB,IAAM,MAAQvB,EAAQ,IAAA,EACxE,CACF,CAAC,GACAsB,GAAgBgB,EACf5C,EAAE,QAAQ,CAAC,CAAC,YAAcxB,EAAiB,IAAM,IAAA,EAAS,EAC1D,CACE,MAAO,IACP,YAAa,iBACb,SAAU,GACV,IAAK8D,EACL,QAAS,EAAO,CAAE,UAAW,CAC3B,EAAwB,GACxB7D,EAAO,YAAY6B,EAAO,cAAcuC,EAAK,UAAUjB,CAAa,CAAC,CAAC,CACxE,CACF,CACF,CACF,CACF,CAKA,MAAakB,EAAa,iBAAiB,EAY3C,SAAgB,aAAa,EAA+B,CAC1D,MAAO,CAACC,EAAO,QAAS,GAAIA,EAAO,OAAS,CAAC,CAAE,CAAC,CAAC,QAAS,GACxDb,EAAK,SAAW,EAAI,CAAC,IAAIA,GAAM,EAAI,CAAC,KAAKA,IAAQ,KAAKc,GAAYd,CAAI,GAAG,CAC3E,CACF,CAQA,MAAMe,mBAAiB,IAAI,IAA+B,CACxD,CAAC,WAAY,UAAU,EACvB,CAAC,qBAAsB,kBAAkB,CAC3C,CAAC,EAEKC,GAA+D,IAAI,IACvEC,GAAcnD,EAAE,aAAa8C,CAAU,CAAC,CAAC,CAAC,OAAO,QAAS,GAAU,CAClE,IAAMrB,EAAMwB,GAAe,IAAIG,EAAM,IAAI,EAEzC,OADI3B,IAAQ,IAAA,GAAkB,CAAC,EACxB,aAAa2B,CAAK,CAAC,CAAC,IAAK,GAAU,CAACtC,EAAOW,CAAG,CAAU,CACjE,CAAC,CACH,EAOA,SAAS,qBAAqB,EAAiD,CAC7E,OAAO,IAAI,IACT0B,GAAcnD,EAAE,aAAa,iBAAiBgB,CAAO,CAAC,CAAC,CAAC,CACrD,OAAO,OAAQ,GAAUoC,EAAM,OAAS,SAAS,CAAC,CAClD,QAAS,GAAUA,EAAM,OAAS,CAAC,CAAC,CACzC,CACF,CAeA,SAAS,iBAAiB,EAAe,EAAkD,CACzF,GACEtC,EAAM,WAAW,GAAG,GACpB,CAACA,EAAM,WAAW,IAAI,GACtBA,EAAM,OAAS,GACf,CAACA,EAAM,SAAS,GAAG,EACnB,CACA,IAAMuC,EAAQ,MAAM,KAAKvC,EAAM,MAAM,CAAC,CAAC,EACjCwC,EAAQD,EAAM,UAAW,GAAS,CAACE,EAAe,IAAIC,CAAI,CAAC,EACjE,GAAIF,IAAU,GAAI,MAAO,CAAE,KAAMxC,EAAO,MAAO,IAAA,EAAU,EACzD,IAAMR,EAAQ+C,EAAM,MAAMC,EAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,EAC5C,MAAO,CAAE,KAAM,IAAID,EAAMC,KAAU,MAAOhD,IAAU,GAAK,IAAA,GAAYA,CAAM,CAC7E,CACA,IAAMM,EAAYE,EAAM,QAAQ,GAAG,EACnC,OAAOF,IAAc,GACjB,CAAE,KAAME,EAAO,MAAO,IAAA,EAAU,EAChC,CAAE,KAAMA,EAAM,MAAM,EAAGF,CAAS,EAAG,MAAOE,EAAM,MAAMF,EAAY,CAAC,CAAE,CAC3E,CAUA,SAAgB,gBACd,EACA,EAA6B,CAAC,EACjB,CACb,IAAM6C,EAAsB,CAAE,SAAU,CAAC,EAAG,iBAAkB,CAAC,CAAE,EAC3DF,EAAiB,qBAAqBvC,CAAO,EAC7CiB,EAAS,aAAapB,CAAI,EAChC,IAAK,IAAIyC,EAAQ,EAAGA,EAAQrB,EAAO,OAAQ,IAAS,CAClD,GAAM,CAAE,OAAM,MAAOyB,GAAgB,iBAAiBzB,EAAOqB,IAAU,GAAIC,CAAc,EACnF9B,EAAMyB,GAAqB,IAAId,CAAI,EACzC,GAAIX,IAAQ,IAAA,GAAW,SACvB,GAAIiC,IAAgB,IAAA,GAAW,CAC7BD,EAAOhC,EAAI,CAAC,KAAKiC,CAAW,EAC5B,QACF,CACA,IAAMpD,EAAQ2B,EAAOqB,EAAQ,GACzBhD,IAAU,IAAA,IAAa,CAACA,EAAM,WAAW,GAAG,IAC9CmD,EAAOhC,EAAI,CAAC,KAAKnB,CAAK,EACtB,IAEJ,CACA,OAAOmD,CACT,CASA,SAAgB,qBACd,EACA,EAA6B,CAAC,EACxB,CACN,GAAM,CAAE,WAAU,oBAAqB,gBAAgB5C,EAAMG,CAAO,EACpE,aAAaU,EAAUC,CAAgB,CACzC,CAKA,MAAagC,EAAgB,CAC3B,eAAgBf,EAAI5C,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CACzC,MAAO,IACP,YAAa,eACb,IAAK,+BACL,WAAY,CAAE,KAAM,MAAO,CAC7B,CAAC,EACD,QAAS4C,EAAI5C,EAAE,OAAO,CAAC,CAAC,SAAS,EAAG,CAClC,MAAO,IACP,YAAa,oBACb,IAAK,0BACL,WAAY,CAAE,KAAM,MAAO,CAC7B,CAAC,CACH,EAKa4D,EAAsB,mBASnC,SAAgB,gBAAgB,EAAyC,CACvE,GAAI,CAACC,EAAY,OACjB,IAAMC,EAAqBrE,EAAK,SAAS,QAAQ,IAAI,EAAGoE,CAAU,EAClE,GAAIC,IAAA,mBACJ,MAAO,YAAYA,GACrB,CAeA,SAAgB,oBAAoB,EAA6C,CAC/E,MAAO,CACL,GAAIC,EAAQ,YAAc,CAAC,kBAAkBA,EAAQ,aAAa,EAAI,CAAC,EACvE,GAAIA,EAAQ,QAAU,CAAC,aAAaA,EAAQ,SAAS,EAAI,CAAC,CAC5D,CACF,CASA,SAAgB,kBAAkB,EAAiB,EAA+C,CAChG,OAAOC,EAAQ,WAAW,GAAG,EACzB,CAAC,UAAW,SAAU,GAAGhD,EAAS,KAAMgD,CAAO,EAC/C,CAAC,UAAW,SAAUA,EAAS,GAAGhD,CAAO,CAC/C,CAKA,MAAaiD,EAAY,CACvB,OAAQrB,EAAI5C,EAAE,OAAO,CAAC,CAAC,QAAQ4D,CAAmB,EAAG,CACnD,MAAO,IACP,YAAa,6BACb,IAAK,qBACL,WAAY,CAAE,KAAM,OAAQ,WAAY,CAAC,IAAI,CAAE,CACjD,CAAC,CACH,EAKaM,GAAiB,CAC5B,OAAQtB,EAAI5C,EAAE,OAAO,CAAC,CAAC,QAAQ4D,CAAmB,EAAG,CACnD,MAAO,IACP,YACE,uFACF,IAAK,qBACL,WAAY,CAAE,KAAM,OAAQ,WAAY,CAAC,IAAI,CAAE,CACjD,CAAC,CACH,EAMA,SAAgB,yBAA8C,CAC5D,IAAMC,EAAa,QAAQ,IAAI,mBAC/B,GAAIA,EAAY,OAAOA,EACvB,IAAMM,EAAuB,QAAQ,IAAI,gCACzC,GAAKA,EAIL,OAHA1F,EAAO,KACL,uFACF,EACO0F,CACT,CAKA,MAAaC,GAAiB,CAC5B,GAAGT,EACH,GAAGM,CACL,EAKaI,GAAmB,CAC9B,IAAKzB,EAAI5C,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAK,EAAG,CACnC,MAAO,IACP,YAAa,2BACf,CAAC,CACH,EAGasE,GAA+B,uCAK/BC,GAAmB,CAC9B,kBAAmB3B,EAAI5C,EAAE,OAAO,EAAG,CACjC,MAAO,IACP,YAAa,kBACb,IAAK,kCACL,WAAY,CAAE,KAAM,MAAO,CAC7B,CAAC,CACH,EAWa,gBAAkB,EAAsB,UAClD,CACC,MAAO4C,EAAIlC,EAAS,QAAQ8D,CAAY,EAAG,CACzC,YAAa,0BACf,CAAC,EACD,MAAO5B,EAAInC,EAAkB,SAAS,EAAG,CACvC,MAAO,IACP,YAAa,0DACf,CAAC,CACH,GAOWgE,GAAe,CAC1B,MAAO7B,EAAIlC,EAAS,QAAQ,MAAM,EAAG,CACnC,YAAa,0BACf,CAAC,EACD,MAAOkC,EAAInC,EAAkB,QAAQ,EAAE,EAAG,CACxC,MAAO,IACP,YAAa,kDACf,CAAC,CACH,EAKaiE,GAAa,CACxB,YAAa9B,EAAI5C,EAAE,OAAO,EAAG,CAC3B,MAAO,IACP,YAAa,YACb,IAAK,4BACL,WAAY,CAAE,KAAM,MAAO,CAC7B,CAAC,CACH,EAeA,SAAgB,YAAY,EAG1B,CACA,IAAM,KAAQ,GAAyB,CACrC,IAAMM,EAAQuC,EAAKX,GACnB,OAAO5B,IAAU,IAAMuC,EAAK,UAAUX,CAAI,IAAM,MAAQ,IAAA,GAAY5B,CACtE,EACA,MAAO,CAAE,eAAgB,KAAK,iBAAiB,EAAG,SAAU,KAAK,WAAW,CAAE,CAChF,CClsBA,MAMMqE,EAAoB,sBAEpBC,EAAcjF,GAAO,WAAW,EAGhCkF,GAAkB7E,EAAE,YAAY,CACpC,IAAKA,EAAE,OAAO,CAAC,CAAC,IAAI,EACpB,SAAUA,EAAE,OAAO,EACnB,WAAYA,EAAE,OAAO,EACrB,MAAOA,EAAE,OAAO,EAChB,UAAWA,EAAE,OAAO,CACtB,CAAC,EAgBK8E,EAAY,IAAIC,GAChBC,kBAAc,IAAI,IAWxB,eAAsB,eACpB,EACA,EACA,EAA6B,CAAC,EAClB,CACZ,IAAMC,EAAOH,EAAU,SAAS,EAChC,GAAIG,GAAM,IAAIC,CAAQ,EAAG,OAAO,MAAMC,EAAG,EAEzC,IAAMC,EAAWJ,EAAY,IAAIE,CAAQ,GAAK,QAAQ,QAAQ,EAC1D,iBAAqB,CAAC,EACpBG,EAAO,IAAI,QAAe,GAAY,CAC1C,aAAeC,CACjB,CAAC,EACKC,EAAQH,EAAS,SAAWC,CAAI,EACtCL,EAAY,IAAIE,EAAUK,CAAK,EAC/B,MAAMH,EACN,GAAI,CACF,IAAMI,EAAQ,MAAM,gBAAgBN,EAAUlE,EAAQ,WAAa,IAAkB,EACrF,GAAI,CACF,OAAO,MAAM8D,EAAU,oBAAI,IAAI,IAAI,CAAC,GAAIG,GAAQ,CAAC,EAAIC,CAAQ,CAAC,EAAGC,CAAE,CACrE,QAAU,CACR,gBAAgBD,EAAUM,CAAK,CACjC,CACF,QAAU,CACR,aAAa,EACTR,EAAY,IAAIE,CAAQ,IAAMK,GAAOP,EAAY,OAAOE,CAAQ,CACtE,CACF,CAOA,SAAgB,oBAAoB,EAAyB,CAC3D,OAAO3G,EAAWmE,CAAK,GAAKA,EAAM,OAASiC,CAC7C,CAEA,eAAe,gBAAgB,EAAkB,EAAoC,CACnFnF,GAAgBC,EAAK,QAAQyF,CAAQ,CAAC,EACtC,IAAMM,EAAQ7F,GAAO,WAAW,EAC1B8F,EAAY,KAAK,IAAI,EACvBC,EAAc,GACdC,EAAQ,GACZ,OAAS,CACP,GAAI,cAAcT,EAAUM,CAAK,EAAG,OAAOA,EAC3C,GAAI,eAAeN,CAAQ,EAAG,SAC9B,IAAMU,EAAW,KAAK,IAAI,EAAIH,EAC9B,GAAIG,GAAYC,EAAW,MAAM,iBAAiBX,CAAQ,EACtD,CAACQ,GAAeE,GAAY,MAC9B,EAAc,GACdnH,EAAO,KAAK,iDAAiDyG,EAAS,IAAI,GAE5E,MAAM,IAAI,QAAS,GAAY,WAAWI,EAASK,GAAS,GAAM,KAAK,OAAO,EAAE,CAAC,EACjF,EAAQ,KAAK,IAAIA,EAAQ,EAAG,GAAkB,CAChD,CACF,CAEA,SAAS,cAAc,EAAkB,EAAwB,CAC/D,IAAIG,EACJ,GAAI,CACF,EAAKpG,EAAG,SAASwF,EAAU,KAAM,GAAK,CACxC,OAASxC,EAAO,CACd,GAAKA,EAAgC,OAAS,SAAU,MAAO,GAC/D,MAAMA,CACR,CACA,IAAMqD,EAAmB,CACvB,IAAK,QAAQ,IACb,SAAUnG,GAAG,SAAS,EACtB,WAAYgF,EACZ,QACA,UAAW,KAAK,IAAI,CACtB,EACA,GAAI,CACFlF,EAAG,UAAUoG,EAAI,KAAK,UAAUC,CAAK,CAAC,CACxC,OAASrD,EAAO,CAGd,MAFAhD,EAAG,UAAUoG,CAAE,EACfpG,EAAG,OAAOwF,EAAU,CAAE,MAAO,EAAK,CAAC,EAC7BxC,CACR,CAEA,OADAhD,EAAG,UAAUoG,CAAE,EACR,EACT,CAEA,SAAS,SAAS,EAA4C,CAC5D,IAAIE,EACA1E,EACJ,GAAI,CACF,EAAO5B,EAAG,SAASwF,CAAQ,EAC3B,EAAUxF,EAAG,aAAawF,EAAU,OAAO,CAC7C,OAASxC,EAAO,CACd,GAAKA,EAAgC,OAAS,SAAU,OACxD,MAAMA,CACR,CACA,MAAO,CAAE,UAAS,IAAKsD,EAAK,IAAK,QAASA,EAAK,QAAS,MAAO,WAAW1E,CAAO,CAAE,CACrF,CAEA,SAAS,WAAW,EAAwC,CAC1D,GAAI,CACF,IAAMmC,EAASoB,GAAgB,UAAU,KAAK,MAAMvD,CAAO,CAAC,EAC5D,OAAOmC,EAAO,QAAUA,EAAO,KAAO,IAAA,EACxC,MAAQ,CACN,MACF,CACF,CAEA,SAAS,QAAQ,EAA6B,CAC5C,GAAM,CAAE,SAAUwC,EACZC,EAAM,KAAK,IAAI,EAMrB,OALKH,EACDG,EAAMH,EAAM,UAAY,KAAwB,GAChDA,EAAM,WAAanG,GAAG,SAAS,EAE/BmG,EAAM,MAAQ,QAAQ,IAAYA,EAAM,aAAenB,EACpD,CAAC,eAAemB,EAAM,GAAG,EAHa,GAF1BG,EAAMD,EAAK,QAAU,GAM1C,CAEA,SAAS,eAAe,EAAsB,CAC5C,GAAI,CAEF,OADA,QAAQ,KAAKE,EAAK,CAAC,EACZ,EACT,OAASzD,EAAO,CACd,OAAQA,EAAgC,OAAS,OACnD,CACF,CAQA,SAAS,eAAe,EAA2B,CACjD,IAAM0D,EAAW,SAASlB,CAAQ,EAClC,GAAI,CAACkB,EAAU,MAAO,GACtB,GAAI,CAAC,QAAQA,CAAQ,EAAG,MAAO,GAE/B,IAAMC,EAAY,GAAGnB,EAAS,UAC9B,GAAI,CAAC,eAAemB,CAAS,EAAG,MAAO,GACvC,GAAI,CACF,IAAMC,EAAU,SAASpB,CAAQ,EAQjC,OANEoB,GAAS,MAAQF,EAAS,KAC1BE,EAAQ,UAAYF,EAAS,SAC7BE,EAAQ,UAAYF,EAAS,SAE7B1G,EAAG,OAAOwF,EAAU,CAAE,MAAO,EAAK,CAAC,EAE9B,EACT,QAAU,CACRxF,EAAG,OAAO2G,EAAW,CAAE,MAAO,EAAK,CAAC,CACtC,CACF,CAEA,SAAS,eAAe,EAA4B,CAClD,GAAI,CAEF,OADA3G,EAAG,UAAUA,EAAG,SAAS2G,EAAW,KAAM,GAAK,CAAC,EACzC,EACT,OAAS3D,EAAO,CACd,GAAKA,EAAgC,OAAS,SAAU,MAAMA,CAChE,CACA,GAAI,CACE,KAAK,IAAI,EAAIhD,EAAG,SAAS2G,CAAS,CAAC,CAAC,QAAU,KAChD3G,EAAG,OAAO2G,EAAW,CAAE,MAAO,EAAK,CAAC,CAExC,OAAS3D,EAAO,CACd,GAAKA,EAAgC,OAAS,SAAU,MAAMA,CAChE,CACA,MAAO,EACT,CAEA,SAAS,gBAAgB,EAAkB,EAAqB,CAC1D,SAASwC,CAAQ,CAAC,EAAE,OAAO,QAAUM,GACvC9F,EAAG,OAAOwF,EAAU,CAAE,MAAO,EAAK,CAAC,CAEvC,CAEA,SAAS,iBAAiB,EAAyB,CACjD,OAAOvG,EAAS,CACd,KAAMgG,EACN,QAAS,2DAA2DO,EAAS,GAC7E,WACE,sGACF,QAAS,CAAE,UAAS,CACtB,CAAC,CACH,CC9OA,MAAMqB,EAAe,sBAerB,IAAIC,EAEJ,eAAe,eAAmD,CAChE,GAAIA,IAAe,IAAA,GAAW,OAAOA,EAErC,GAAI,CAEF,GAAa,MADK,OAAO,oBAAA,CACR,KACnB,MAAQ,CACN/H,EAAO,KACL,gJACF,EACA,EAAa,EACf,CAEA,OAAO+H,CACT,CAMA,eAAsB,oBAAuC,CAC3D,OAAQ,MAAM,cAAc,IAAO,EACrC,CAQA,eAAsB,kBAAkB,EAAiD,CACvF,IAAMC,EAAQ,MAAM,cAAc,EAClC,GAAI,CAACA,EAAO,MAAU,MAAM,kCAAkC,EAG9D,IAAMC,EAAM,IADMD,EAAMF,EAAcI,CACtB,CAAC,CAAC,YAAY,EAC9B,GAAID,IAAQ,KACZ,GAAI,CACF,OAAO,KAAK,MAAMA,CAAG,CACvB,MAAQ,CACN,MACF,CACF,CAOA,eAAsB,kBAAkB,EAAiB,EAAkC,CACzF,IAAMD,EAAQ,MAAM,cAAc,EAClC,GAAI,CAACA,EAAO,MAAU,MAAM,kCAAkC,EAG9D,IADkBA,EAAMF,EAAcI,CAClC,CAAC,CAAC,YAAY,KAAK,UAAU1E,CAAM,CAAC,CAC1C,CAMA,eAAsB,oBAAoB,EAAgC,CACxE,IAAMwE,EAAQ,MAAM,cAAc,EAClC,GAAKA,EAEL,GAAI,CAEF,IADkBA,EAAMF,EAAcI,CAClC,CAAC,CAAC,eAAe,CACvB,MAAQ,CAER,CACF,CCvDA,MAAMC,EAAkB5G,EAAE,YAAY,CACpC,KAAMA,EAAE,OAAO,EACf,aAAcA,EAAE,OAAO,EACvB,SAAUA,EAAE,QAAQ,CAAC,CAAC,SAAS,EAC/B,aAAcA,EAAE,OAAO,CAAC,CAAC,SAAS,EAClC,sBAAuBA,EAAE,KAAK,CAAC,QAAS,MAAM,CAAC,CAAC,CAAC,SAAS,EAC1D,aAAcA,EAAE,IAAI,CAAC,CAAC,SAAS,EAC/B,iBAAkBA,EAAE,OAAO,CAAC,CAAC,SAAS,EACtC,YAAaA,EAAE,IAAI,CAAC,CAAC,SAAS,CAChC,CAAC,EAEK6G,GAAiB7G,EAAE,YAAY,CACnC,aAAcA,EAAE,OAAO,EACvB,cAAeA,EAAE,OAAO,CAAC,CAAC,SAAS,EACnC,iBAAkBA,EAAE,OAAO,CAC7B,CAAC,EAEK8G,EAAsB9G,EAAE,YAAY,CACxC,QAASA,EAAE,QAAQ,SAAS,EAC5B,iBAAkBA,EAAE,OAAO,CAC7B,CAAC,EAEK+G,EAAmB/G,EAAE,YAAY,CACrC,QAASA,EAAE,QAAQ,MAAM,EACzB,iBAAkBA,EAAE,OAAO,EAC3B,aAAcA,EAAE,OAAO,EACvB,cAAeA,EAAE,OAAO,CAAC,CAAC,SAAS,CACrC,CAAC,EAEKgH,GAAiBhH,EAAE,mBAAmB,UAAW,CAAC8G,EAAqBC,CAAgB,CAAC,EAExFE,EAAyBjH,EAAE,aAAa,CAC5C,MAAOA,EAAE,OAAO,CAAC,CAAC,SAAS,CAC7B,CAAC,EAEKkH,EAAmB,CACvB,GAAGD,EAAuB,MAC1B,wBAAyBjH,EAAE,OAAO,CAAC,CAAC,SAAS,EAC7C,kBAAmBA,EAAE,OAAO,CAAC,CAAC,SAAS,CACzC,EAEMmH,EAAwBL,EAAoB,OAAOI,CAAgB,EAEnEE,GAAqBL,EAAiB,OAAOG,CAAgB,EAE7DG,GAAiBrH,EAAE,mBAAmB,UAAW,CAACmH,EAAuBC,EAAkB,CAAC,EAE5FE,GAAmBtH,EAAE,YAAY,CACrC,QAASA,EAAE,QAAQ,CAAC,EACpB,MAAOA,EAAE,cAAcA,EAAE,OAAO,EAAG6G,EAAc,EACjD,SAAU7G,EAAE,cAAcA,EAAE,OAAO,EAAG4G,CAAe,EACrD,aAAc5G,EAAE,OAAO,CAAC,CAAC,SAAS,CACpC,CAAC,EAKKuH,EAAqB,QAErBC,EAAexH,EAAE,gBAAgB,CACrCA,EAAE,OAAO,CAAC,CAAC,IAAI,EACf,IACAA,EAAE,OAAO,CAAC,CAAC,IAAI,EACf,IACAA,EAAE,OAAO,CAAC,CAAC,IAAI,CACjB,CAAC,EAEKyH,GAAmBzH,EAAE,YAAY,CACrC,QAASA,EAAE,QAAQ,CAAiB,EACpC,gBAAiBwH,EACjB,eAAgBxH,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAC1C,uBAAwBwH,EAAa,SAAS,EAC9C,MAAOxH,EAAE,cAAcA,EAAE,OAAO,EAAGgH,EAAc,EACjD,SAAUhH,EAAE,cAAcA,EAAE,OAAO,EAAG4G,CAAe,EACrD,aAAc5G,EAAE,OAAO,CAAC,CAAC,SAAS,CACpC,CAAC,EAEK0H,EAAmB1H,EAAE,YAAY,CACrC,QAASA,EAAE,QAAQ,CAAqB,EACxC,gBAAiBwH,EACjB,eAAgBxH,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAC1C,uBAAwBwH,EAAa,SAAS,EAC9C,MAAOxH,EAAE,cAAcA,EAAE,OAAO,EAAGqH,EAAc,EACjD,SAAUrH,EAAE,cAAcA,EAAE,OAAO,EAAG4G,CAAe,EACrD,aAAc5G,EAAE,OAAO,CAAC,CAAC,SAAS,CACpC,CAAC,EA4CD,SAAS,oBAAqB,CAC5B,GAAI,CAAC2H,EACH,MAAU,MAAM,+BAA+B,EAEjD,OAAOlI,EAAK,KAAKkI,EAAW,kBAAmB,aAAa,CAC9D,CAOA,SAAgB,sBAAgC,CAE9C,OADKA,EACEjI,EAAG,WAAW,mBAAmB,CAAC,EADlB,EAEzB,CAaA,SAAgB,0BACd,EACkC,CAClC,IAAMkI,EAAS,CACb,GAAI5D,GAAS,aAAe,CAAE,YAAaA,EAAQ,YAAa,EAAI,CAAC,EACrE,GAAIA,GAAS,iBAAmB,CAAE,eAAgBA,EAAQ,gBAAiB,EAAI,CAAC,EAChF,GAAIA,GAAS,YAAc,CAAE,WAAYA,EAAQ,WAAY,EAAI,CAAC,CACpE,EACA,OAAO,OAAO,KAAK4D,CAAM,CAAC,CAAC,OAAS,EAAIA,EAAS,IAAA,EACnD,CAEA,SAAS,gBAAgB,EAAc,EAAuC,CAC5E,IAAMC,EAAc/I,EAAmB8I,CAAM,EAI7C,OAHIC,IAAgBhJ,EAAA,yBAAuC,EAClDiJ,EAEF,GAAGD,EAAY,GAAGC,GAC3B,CAEA,SAAS,wBAAwB,EAAiB,EAAuC,CACvF,IAAMC,EAAiB,GAAGjJ,EAAmB8I,CAAM,EAAE,GACrD,OAAOI,EAAQ,WAAWD,CAAc,EAAIC,EAAQ,MAAMD,EAAe,MAAM,EAAIC,CACrF,CAEA,SAAS,oBAAoB,EAA8B,CACzD,GAAI,CACF,OAAOlJ,EAAmB,IAAM+I,CAClC,MAAQ,CACN,MAAO,EACT,CACF,CAMA,SAAS,gBACP,EACA,EACA,EACA,CACA,IAAMA,EAAc/I,EAAmBmJ,CAAc,EAC/CF,EAAiB,GAAGF,EAAY,GAChCK,EAAkBL,IAAgBhJ,EAAiBM,CAAsB,EAC/E,OAAO,OAAO,QAAQgJ,CAAK,CAAC,CAAC,MAAM,CAAC1G,EAAK2G,KACnCA,GAAO,QAAUC,EACdH,EAAkB,CAACzG,EAAI,SAAS,GAAG,EAAIA,EAAI,WAAWsG,CAAc,EADxC,EAEpC,CACH,CAEA,SAAS,cACP,EACA,EACA,EACA,EAA+B,CAAC,EAChC,CACA,IAAMC,EAAU,gBAAgBF,EAAMG,CAAc,EAC9CK,EAAYV,EAAO,MAAMI,GAC/B,GAAIM,EACF,MAAO,CAAE,UAAS,WAAU,EAE9B,IAAMC,EAAa,gBAAgBX,EAAO,MAAOE,EAAMG,CAAc,EACrE,GAAIM,IAAa,GACf,MAAO,CAAE,QAASA,EAAW,GAAI,UAAWA,EAAW,EAAG,EAE5D,IAAMV,EAAc/I,EAAmBmJ,CAAc,EACrD,GACED,IAAYF,IACXU,EAAK,qBAAuB,IAAS,CAAC,oBAAoBX,CAAW,GAEtE,MAAO,CAAE,UAAS,WAAU,EAE9B,IAAMY,EAAcb,EAAO,MAAME,GACjC,OAAOW,EAAc,CAAE,QAASX,EAAM,UAAWW,CAAY,EAAI,CAAE,UAAS,WAAU,CACxF,CAUA,SAAgB,oBACd,EACA,EACA,EACA,EACQ,CACR,OAAO,cAAcb,EAAQE,EAAMG,EAAgBO,CAAI,CAAC,CAAC,OAC3D,CAEA,SAAgB,kBACd,EACA,EACA,EACA,EACoB,CACpB,GAAM,CAAE,UAAS,aAAc,cAAcZ,EAAQE,EAAMG,EAAgBO,CAAI,EAC/E,OAAOF,EAAY,wBAAwBN,EAASC,CAAc,EAAI,IAAA,EACxE,CAUA,SAAgB,kBACd,EACA,EACA,EACA,EACS,CACT,OAAO,cAAcL,EAAQE,EAAMG,EAAgBO,CAAI,CAAC,CAAC,YAAc,IAAA,EACzE,CAEA,SAAS,kBAAkB,EAAgC,EAAuB,CAChF,OAAOL,EAAML,KAAU,IAAA,IAAa,OAAO,KAAKK,CAAK,CAAC,CAAC,KAAM,GAAQ1G,EAAI,SAAS,IAAIqG,GAAM,CAAC,CAC/F,CAEA,SAAS,kBAAkB,EAA0B,EAAuB,CAC1E,OAAO,OAAO,OAAOK,CAAK,CAAC,CAAC,KAAM,GAAUC,GAAO,QAAUN,CAAI,CACnE,CAQA,SAAgB,qBAAqB,EAAiC,EAAuB,CAC3F,OAAO,kBAAkBF,EAAO,MAAOE,CAAI,GAAK,kBAAkBF,EAAO,MAAOE,CAAI,CACtF,CAEA,SAAS,oBAAoB,EAA4B,EAA8B,CACrF,OAAO,kBAAkBK,EAAOO,CAAW,CAC7C,CAIA,SAAS,aAAa,GAAGC,EAAsC,CAC7D,OAAO,IAAI,IAAIA,EAAQ,QAAS,GAAW,OAAO,KAAKC,EAAO,KAAK,CAAC,CAAC,CACvE,CAEA,MAAMC,EAAe,aAAapB,EAAgB,EAC5CqB,EAAa,aAAahC,EAAqBC,CAAgB,EAC/DgC,GAAgBD,EAAW,MAAM,aAAa7B,CAAsB,CAAC,EACrE+B,GAAc,aAAapC,CAAe,EAE1CqC,GAAmBJ,EAAa,WAAW,aAAavB,EAAgB,CAAC,EACzE4B,GAAmB,aAAaxB,CAAgB,CAAC,CAAC,WAAWmB,CAAY,EACzEM,GAAiB,aAAahC,EAAuBC,EAAkB,CAAC,CAAC,WAC7E0B,CACF,EAEA,SAAS,YAA8B,EAAU,EAA8B,CAC7E,OAAO,OAAO,YAAY,OAAO,QAAQV,CAAK,CAAC,CAAC,QAAQ,CAAC3G,KAAS,CAAC2H,EAAK,IAAI3H,CAAG,CAAC,CAAC,CACnF,CASA,SAAS,cAAc,EAAkC,CACvD,IAAM0G,EAA6B,CAAC,EAEpC,IAAK,GAAM,CAACjG,EAAMmH,KAAW,OAAO,QAAQC,EAAS,KAAK,EACnDD,IAEL,EAAMnH,GAAQ,CAAE,GAAG,YAAYmH,EAAQF,EAAc,EAAG,QAAS,MAAO,GAG1E,MAAO,CACL,GAAG,YAAYG,EAAUL,EAAgB,EACzC,QAAS,EACT,gBAAiB,SACjB,OACF,CACF,CAEA,SAAS,qBAAqB,EAAkC,CAC9D,OAAOjJ,EAAE,MAAM,CAAC,CAAC,UAAU8H,CAAI,CAAC,CAAC,QAAUA,EAAO,IAAA,EACpD,CAEA,SAAS,cAAc,EAAgC,CACrD,IAAMK,EAA2B,CAAC,EAElC,IAAK,GAAM,CAACL,EAAMM,KAAU,OAAO,QAAQmB,EAAS,KAAK,EAAG,CAC1D,GAAI,CAACnB,EAAO,SACZ,IAAMC,EAAQ,qBAAqBP,CAAI,EACvC,EAAMA,GAAQ,CACZ,GAAG,YAAYM,EAAOe,EAAc,EACpC,GAAId,EAAQ,CAAE,OAAM,EAAI,CAAC,CAC3B,CACF,CAEA,MAAO,CACL,GAAG,YAAYkB,EAAUL,EAAgB,EACzC,QAAS,EACT,gBAAiB3B,EACjB,OACF,CACF,CAEA,SAAS,cAAc,EAAgC,CACrD,OAAO,cAAc,cAAc+B,CAAQ,CAAC,CAC9C,CAEA,SAAS,mBAAmB,EAAwB,CAClD,OAAO5G,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAC9D,CAEA,eAAe,uBAAuB,EAAc,EAAsC,CACxF,GAAI,CAAE,MAAM,mBAAmB,EAAI,MAAO,GAC1C,GAAI,CAEF,OADA,MAAM,kBAAkBoF,EAAM7F,CAAM,EAC7B,EACT,OAASS,EAAO,CAId,OAHAjE,EAAO,KACL,yFAAyF,mBAAmBiE,CAAK,GACnH,EACO,EACT,CACF,CAEA,IAAI8G,GAAyB,GAE7B,eAAe,2BAA2B,EAGvC,CACD,GAAI,CAAC5B,EAAO,wBAA0B4B,GAAwB,OAE9D,IAAMC,GAAa,MADOpK,EAAgB,EAAA,CACX,SAAW,QACtClB,GAASsL,EAAY7B,EAAO,sBAAsB,IACpD,GAAyB,GACzBnJ,EAAO,KAAK,CAAE;gCACc,OAAOmJ,EAAO,cAAc,EAAE;qCACzBA,EAAO,uBAAuB;KAC9D,EAEL,CAMA,eAAsB,oBAAwC,CAC5D,IAAM/D,EAAa,mBAAmB,EAEtC,GAAI,CAACnE,EAAG,WAAWmE,CAAU,EAAG,CAC9B,IAAM+D,EAAmB,CACvB,QAAS,EACT,gBAAiBL,EACjB,MAAO,CAAC,EACR,SAAU,CAAC,EACX,aAAc,IAChB,EAEA,OADA,oBAAoBK,CAAM,EACnBA,CACT,CAEA,IAAM+B,EAAYC,GAAUlK,EAAG,aAAamE,EAAY,OAAO,CAAC,EAKhEvE,EAA6BuE,CAAU,EAGvC,IAAMgG,EACiB,OAAOF,GAAc,UAA1CA,GAAsD,YAAaA,EAC/DA,EAAU,QACV,IAAA,GACN,GAAI,OAAOE,GAAY,UAAYA,EAAU,EAAuB,CAClE,IAAMC,EACJ,oBAAsBH,EAClB,OAAQA,EAA2C,eAAe,EAClE,IAAA,GACAI,EAAaD,EACf,gCAAgCA,EAAO,oCACvC,2DACJ,MAAU,MAAM,CAAE;iCACW,OAAOD,CAAO,EAAE,6CAA6C,IAA8B;QACpHE,EAAW;KACd,CACH,CAGA,IAAMC,EAAWtC,EAAiB,UAAUiC,CAAS,EACrD,GAAIK,EAAS,QAEX,OADA,MAAM,2BAA2BA,EAAS,IAAI,EACvCA,EAAS,KAIlB,IAAMC,EAAWxC,GAAiB,UAAUkC,CAAS,EACrD,GAAIM,EAAS,QAEX,OADA,MAAM,2BAA2BA,EAAS,IAAI,EACvC,cAAcA,EAAS,IAAI,EAIpC,IAAMC,EAAW5C,GAAiB,UAAUqC,CAAS,EACrD,GAAIO,EAAS,QACX,OAAO,cAAcA,EAAS,IAAI,EAIpC,MAAU,MAAM,CAAE;qCACiBrG,EAAW;;GAE7C,CACH,CAEA,SAAS,YAAY,EAAgC,CACnD,IAAMsE,EAA6B,CAAC,EACpC,IAAK,GAAM,CAACjG,EAAMkG,KAAU,OAAO,QAAQR,EAAO,KAAK,EAChDQ,GAASA,EAAM,UAAY,YAChC,EAAMlG,GAAQ,CACZ,aAAckG,EAAM,aACpB,cAAeA,EAAM,cACrB,iBAAkBA,EAAM,gBAC1B,GAEF,IAAMM,EACJd,EAAO,cAAgB,oBAAoBO,EAAOP,EAAO,YAAY,EACjEA,EAAO,aACP,KACN,MAAO,CACL,QAAS,EACT,QACA,SAAUA,EAAO,SACjB,aAAcc,CAChB,CACF,CAEA,SAAS,2BAA2B,EAA0D,CAC5F,OAAO,OAAO,OAAOd,EAAO,QAAQ,CAAC,CAAC,KACnC,GACC5D,GAAS,eAAiB,IAAA,IAC1BA,GAAS,mBAAqB,IAAA,IAC9BA,GAAS,cAAgB,IAAA,EAC7B,CACF,CAEA,SAAS,kBAAkB,EAAuD,CAChF,OAAO,OAAO,KAAK4D,EAAO,KAAK,CAAC,CAAC,KAAM,GAAYI,EAAQ,SAAS,GAAG,CAAC,CAC1E,CAEA,SAAS,eAAe,EAA2B,EAAyC,CAC1F,OACEI,IAAU,IAAA,IACV,OAAO,QAAQA,CAAK,CAAC,CAAC,MAAM,CAAC3G,EAAKnB,KAAWA,IAAU,IAAA,IAAa,CAAC6J,EAAU,IAAI1I,CAAG,CAAC,CAE3F,CAEA,SAAS,qBAAqB,EAAqD,CACjF,OACE,eAAemG,EAAQiB,CAAY,GACnC,OAAO,OAAOjB,EAAO,KAAK,CAAC,CAAC,KAAM,GAAS,eAAeE,EAAMgB,CAAU,CAAC,GAC3E,OAAO,OAAOlB,EAAO,QAAQ,CAAC,CAAC,KAAM,GAAY,eAAe5D,EAASgF,EAAW,CAAC,CAEzF,CAEA,SAAS,gBAAgB,EAAwD,CAE/E,MAAO,CACL,GAFkBpB,EAAO,UAAY,EAAI,cAAcA,CAAM,EAAIA,EAGjE,QAAS,EACT,gBAAiBL,CACnB,CACF,CAkBA,SAAgB,oBAAoB,EAA4C,CAC9E,IAAM1D,EAAa,mBAAmB,EAChCuG,EACJxC,EAAO,UAAY,GAAK,OAAO,OAAOA,EAAO,KAAK,CAAC,CAAC,KAAM,GAAMyC,GAAG,UAAY,SAAS,EACpFC,EACJ1C,EAAO,UAAY,GACnB,2BAA2BA,CAAM,GACjC,kBAAkBA,CAAM,GACxB,qBAAqBA,CAAM,EACvB,gBAAgBA,CAAM,EACtBA,EAAO,UAAY,GAAqB,CAACwC,EACvC,YAAYxC,CAAM,EAClBA,EACRrI,EACEsE,EACA0G,GACED,EAAW,UAAY,EACnBA,EACA,CAAE,GAAGA,EAAY,MAAO,yBAAyBA,EAAW,KAAK,CAAE,CACzE,CACF,CACF,CAEA,SAAS,yBAAyB,EAAgD,CAChF,OAAO,OAAO,YACZ,OAAO,QAAQnC,CAAK,CAAC,CAAC,KAAK,CAACH,EAASI,KAAW,CAC9C,GAAIA,GAAO,UAAY,UAAW,MAAO,CAACJ,EAASI,CAAK,EACxD,GAAM,CAAE,aAAcoC,EAAc,cAAeC,EAAe,GAAGC,GAAiBtC,EACtF,MAAO,CAACJ,EAAS0C,CAAY,CAC/B,CAAC,CACH,CACF,CAEA,SAAS,aAAa,EAAe,EAAwB,CAC3D,IAAMjH,EAASzD,EAAE,KAAK,CAAC,CAAC,UAAUM,CAAK,EACvC,GAAI,CAACmD,EAAO,QACV,MAAU,MAAM,sBAAsBhB,EAAO,uBAAuB,EAEtE,OAAOgB,EAAO,IAChB,CASA,eAAsB,gBAAgB,EAAgD,CACpF,IAAMkH,EAAc,MAAM,mBAAmBnC,CAAI,EACjD,GAAImC,EAAa,OAAOA,EAExB,MAAU,MAAM,CAAE;;;GAGjB,CACH,CAOA,eAAsB,mBACpB,EAC6B,CAC7B,IAAM3G,EAAUwE,GAAM,SAAW,QAAQ,IAAI,wBAE7C,GAAIA,GAAM,cAAgB,IAAA,GACxB,OAAO,aAAaA,EAAK,YAAa,uBAAuB,EAG/D,GAAI,QAAQ,IAAI,6BACd,OAAO,aACL,QAAQ,IAAI,6BACZ,mDACF,EAGF,GAAIxE,EAAS,CAGX,IAAM4G,GADe,MADE,mBAAmB,EAAA,CACZ,SAAS5G,EACd,EAAE,aAC3B,GAAI,CAAC4G,EACH,MAAMC,EAAqB7G,CAAO,EAEpC,OAAO,aAAa4G,EAAM,YAAY5G,EAAQ,EAAE,CAClD,CAGF,CAWA,eAAsB,oBACpB,EAC6B,CAC7B,GAAIwE,GAAM,cAAgB,GACxB,MAAM7J,EAAS,CACb,KAAM,0BACN,QAAS,qCACT,WACE,4GACJ,CAAC,EAGH,IAAMmM,EAAiB,QAAQ,IAAI,mCAAqC,IAAA,GAClEC,EAAuDvC,GAAM,YAC/D,CACE,OAAQA,EAAK,mBAAqB,SAClC,MAAOA,EAAK,WACd,EACAsC,EACE,CAAE,OAAQ,MAAO,MAAOA,CAAe,EACvC,IAAA,GACAE,EAAWD,GAAqB,MAEhC/G,EAAUwE,GAAM,SAAW,QAAQ,IAAI,wBAC7C,GAAI,CAACxE,EAAS,OAAOgH,EAGrB,IAAM5C,GAAQ,MADS,mBAAmB,EAAA,CACnB,SAASpE,GAChC,GAAI,CAACoE,EAAO,CACV,GAAI4C,EAAU,OAAOA,EACrB,MAAMH,EAAqB7G,CAAO,CACpC,CAEA,GAAIoE,EAAM,cAAgBA,EAAM,wBAA0B,OAAQ,CAChE,GAAI4C,GAAYA,IAAa5C,EAAM,aAAc,CAC/C,IAAM6C,EACJF,EAAoB,SAAW,MAC3B,qCAAqCC,EAAS,6HAA6H5C,EAAM,aAAa,IAC9L,2CAA2CA,EAAM,aAAa,kCACpE,MAAMzJ,EAAS,CACb,KAAM,uCACN,QAAS,YAAYqF,EAAQ,uCAC7B,UACA,WAAY,iFAAiFtF,EAC3F,CACE,QAAS,SACT,KAAM,kBAAkBsF,EAAS,CAAC,0BAA2B,OAAO,CAAC,CACvE,CACF,EAAE,EACJ,CAAC,CACH,CACA,OAAOoE,EAAM,YACf,CAEA,OAAO4C,GAAY5C,EAAM,YAC3B,CAMA,SAAgB,sBAA2C,CACzD,OAAO,QAAQ,IAAI,uBAAyB,QAAQ,IAAI,YAC1D,CAYA,eAAsB,oCAAoC,EAEyC,CACjG,IAAMpE,EAAUwE,EAAK,SAAW,QAAQ,IAAI,wBACtC0C,EAAW,MAAM,mBAAmB,EACpCC,EAAenH,EAAUkH,EAAS,SAASlH,GAAW,IAAA,GAC5D,GAAIA,GAAW,CAACmH,EAAc,OAC9B,IAAMrD,EAAOqD,GAAc,MAAQD,EAAS,aAC5C,GAAI,CAACpD,EAAM,OACX,IAAMG,EAAiBkD,EAAe,0BAA0BA,CAAY,EAAI,IAAA,GAC1EC,EAAS,MAAM,gBAAgBF,EAAUpD,EAAMG,EAAgB,gBAAgBjE,CAAO,CAAC,EAC7F,GAAI,iBAAgBoH,CAAM,EAC1B,MAAO,CAAE,YAAaA,EAAO,OAAO,YAAa,gBAAe,CAClE,CASA,eAAsB,gBAAgB,EAA+B,CACnE,IAAMpH,EAAUwE,GAAM,SAAW,QAAQ,IAAI,wBACvC6C,EAAW,qBAAqB,EAKtC,GAJIA,GAAY,CAAC,QAAQ,IAAI,uBAC3B5M,EAAO,KAAK,uEAAuE,EAGjF4M,EAAU,CACZ5M,EAAO,eAAe4M,CAAQ,EAC9B,IAAMpD,EAAiB,MAAM,yBAAyB,CAAE,UAAS,oBAAqB,EAAK,CAAC,EAE5F,OADAjJ,EAA+BqM,EAAUpD,CAAc,EAChDoD,CACT,CAEA,IAAMH,EAAW,MAAM,mBAAmB,EACpCC,EAAenH,EAAUkH,EAAS,SAASlH,GAAW,IAAA,GAC5D,GAAIA,GAAW,CAACmH,EACd,MAAMN,EAAqB7G,CAAO,EAEpC,IAAM8D,EAAOqD,GAAc,MAAQD,EAAS,aAC5C,GAAI,CAACpD,EACH,MAAMnJ,EAAS,CACb,KAAM,uBACN,QAAS,mCACT,WAAY,kEACZ,KAAM,CAAE,QAAS,SAAU,KAAM,CAAC,QAAS,GAAG,oBAAoB,CAAE,SAAQ,CAAC,CAAC,CAAE,EAChF,QAAS,CAAE,QAASqF,GAAW,IAAK,CACtC,CAAC,EAEH,IAAMsH,EAAcH,EAAe,0BAA0BA,CAAY,EAAI,IAAA,GACvErK,EAAQ,MAAM,mBAAmB,CACrC,OAAQoK,EACR,OACA,eAAgBI,EAChB,SACF,CAAC,EAOD,OANIxK,EAAM,aACR/B,EACE+B,EAAM,YACN,wBAAwB,CAAE,QAAO,eAAgBwK,EAAa,SAAQ,CAAC,CACzE,EAEKxK,EAAM,WACf,CAOA,eAAsB,eAAe,EAAoD,CACvF,IAAMkD,EAAUwE,GAAM,SAAW,QAAQ,IAAI,wBACvC6C,EAAW,qBAAqB,EAKtC,GAJIA,GAAY,CAAC,QAAQ,IAAI,uBAC3B5M,EAAO,KAAK,uEAAuE,EAGjF4M,EAAU,CACZ5M,EAAO,eAAe4M,CAAQ,EAC9B,IAAMzD,EAAS,MAAM,mBAAmB,CAAC,CAAC,UAAY,IAAA,EAAS,EACzDuD,EAAenH,EAAU4D,GAAQ,SAAS5D,GAAW,IAAA,GACrDiE,EAAiBkD,EAAe,0BAA0BA,CAAY,EAAI,IAAA,GAChF,MAAO,CACL,cAAe,GACf,SAAU,KACV,eAAgB,cAChB,QAASnH,GAAW,KACpB,YAAa,QAAQ,IAAI,8BAAgCmH,GAAc,cAAgB,KACvF,WAAYA,GAAc,WAAa,GAAO,OAAS,QACvD,YAAarM,EAAmBmJ,CAAc,EAC9C,YAAa,aACf,CACF,CAEA,IAAML,EAAS,MAAM,mBAAmB,EAClCuD,EAAenH,EAAU4D,EAAO,SAAS5D,GAAW,IAAA,GAC1D,GAAIA,GAAW,CAACmH,EACd,MAAMN,EAAqB7G,CAAO,EAGpC,IAAMiE,EAAiBkD,EAAe,0BAA0BA,CAAY,EAAI,IAAA,GAC1EtD,EAAc/I,EAAmBmJ,CAAc,EAC/C0C,EACJ,QAAQ,IAAI,8BAAgCQ,GAAc,cAAgB,KAEtEI,EAAWJ,GAAc,MAAQvD,EAAO,aACxC4D,EAAiBL,GAAc,KAAO,UAAYI,EAAW,UAAY,OAC3EE,EAAyC,UAC7C,GAAIF,EAAU,CACZ,GAAM,CAAE,UAAS,aAAc,cAAc3D,EAAQ2D,EAAUtD,CAAc,EAC7E,GAAIK,EAAW,CACb,IAAMrG,EAAS,MAAM,cAAcqG,EAAWN,EAASuD,CAAQ,CAAC,CAAC,UAAY,IAAA,EAAS,EAClFtJ,IAEF,AACEwJ,EAFc,IAAI,KAAKnD,EAAU,gBAAgB,mBAAK,IAAI,KAI5CrG,EAAO,aAAe,cAAgB,UAFtC,QAKpB,CACF,CAEA,MAAO,CACL,cAAewJ,IAAgB,SAAWA,IAAgB,cAC1D,SAAUF,GAAY,KACtB,iBACA,QAASvH,GAAW,KACpB,cACA,WAAYmH,GAAc,WAAa,GAAO,OAAS,QACvD,cACA,aACF,CACF,CAcA,SAAgB,yBAAyB,EAAkB,EAA+B,CACxF,IAAMnH,EAAUwE,GAAM,SAAW,QAAQ,IAAI,wBACvC2C,EAAenH,EAAU4D,EAAO,SAAS5D,GAAW,IAAA,GAC1D,GAAIA,GAAW,CAACmH,EAAc,OAC9B,IAAMrD,EAAOqD,GAAc,MAAQvD,EAAO,aACpCK,EAAiBkD,EAAe,0BAA0BA,CAAY,EAAI,IAAA,GAIhF,MAAO,CAAE,UAAS,OAAM,UAHNrD,EACd,cAAcF,EAAQE,EAAMG,EAAgB,CAAE,mBAAoB,EAAM,CAAC,CAAC,CAAC,UAC3E,IAAA,EAC8B,CACpC,CAQA,eAAsB,0BACpB,EAC4C,CAC5C,GAAI,qBAAqB,EAAG,OAE5B,IAAMK,EAAY,yBAAyB,MADtB,mBAAmB,EACWE,CAAI,CAAC,EAAE,UAC1D,GAAKF,GAAW,wBAChB,MAAO,CACL,eAAgBA,EAAU,wBAC1B,GAAIA,EAAU,kBAAoB,CAAE,SAAUA,EAAU,iBAAkB,EAAI,CAAC,CACjF,CACF,CAOA,eAAsB,yBACpB,EAC2C,CAC3C,IAAMtE,EAAUwE,GAAM,SAAW,QAAQ,IAAI,wBAC7C,GAAI,CAACxE,EACH,OAGF,IAAIkH,EACJ,GAAI,CACF,EAAW,MAAM,mBAAmB,CACtC,OAASxI,EAAO,CACd,GAAI8F,GAAM,oBACR,OAEF,MAAM9F,CACR,CACA,IAAMyI,EAAeD,EAAS,SAASlH,GACvC,GAAI,CAACmH,EAAc,CACjB,GAAI3C,GAAM,oBACR,OAEF,MAAMqC,EAAqB7G,CAAO,CACpC,CACA,OAAO,0BAA0BmH,CAAY,CAC/C,CAOA,eAAsB,mBAAmB,EAAmD,CAC1F,IAAMlD,EAAiB,MAAM,yBAAyBO,CAAI,EAC1D,OAAOpJ,EAAkB6I,CAAc,CACzC,CASA,SAAgB,qBAAqB,EAA0B,CAC7DxJ,EAAO,eAAewD,EAAO,WAAW,EACpCA,EAAO,cAAcxD,EAAO,eAAewD,EAAO,YAAY,CACpE,CASA,eAAsB,cACpB,EACA,EACA,EAAQ6F,EACiD,CACzD,GAAIQ,EAAU,UAAY,UAAW,CACnC,IAAIrG,EACJ,GAAI,CACF,EAAS,MAAM,kBAAkB6F,CAAI,CACvC,OAASpF,EAAO,CACd,MAAU,MACR,CAAE;4DACkDgJ,EAAM,KAAK,mBAAmBhJ,CAAK,EAAE;;;UAIzF,CAAE,MAAOA,CAAM,CACjB,CACF,CACA,GAAI,CAACT,EACH,MAAU,MAAM,CAAE;mDAC2ByJ,EAAM;;;;OAIlD,EAGH,OADA,qBAAqBzJ,CAAM,EACpBA,CACT,CAEA,IAAMA,EAAS,CACb,YAAaqG,EAAU,aACvB,aAAcA,EAAU,aAC1B,EAEA,OADA,qBAAqBrG,CAAM,EACpBA,CACT,CAEA,SAAS,gBAAgB,EAA2B,CAElD,OADKmG,EACE,YAAYA,EAAOW,EAAa,EADpB,CAAC,CAEtB,CAMA,eAAe,gBACb,EACA,EACA,EACA,EACA,CACA,IAAMX,EAAQR,EAAO,MAAM+D,GAC3B,GAAIA,IAAaC,GAAgB,CAACxD,EAAO,OACzC,IAAMyD,EAAiBjE,EAAO,MAAMgE,GAChCpD,EAAK,kBAAoBqD,IAC3B,EAAO,MAAMD,GAAgB,CAAE,GAAG,gBAAgBxD,CAAK,EAAG,GAAGyD,CAAe,GAE1EzD,EAAM,UAAY,WACpB,MAAM,oBAAoBuD,CAAQ,EAEpC,OAAO/D,EAAO,MAAM+D,EACtB,CAYA,eAAsB,eACpB,EACA,EACA,EACA,EACA,EAAkE,CAAC,EACpD,CACf,qBAAqB1J,CAAM,EAC3B,IAAM+F,EAAU,gBAAgBF,EAAMU,EAAK,cAAc,EACnDsD,EAAWlE,EAAO,MAAMI,GACxB+D,EAAc,gBAAgBD,CAAQ,EACtCzD,EAAQG,EAAK,OAASsD,GAAU,MAClC,MAAM,uBAAuB9D,EAAS/F,CAAM,EAC9C,EAAO,MAAM+F,GAAW,CACtB,GAAG+D,EACH,iBAAkBC,EAClB,QAAS,UACT,GAAI3D,EAAQ,CAAE,OAAM,EAAI,CAAC,CAC3B,GAEIyD,GAAU,UAAY,WACxB,MAAM,oBAAoB9D,CAAO,EAEnC,EAAO,MAAMA,GAAW,CACtB,GAAG+D,EACH,aAAc9J,EAAO,YACrB,cAAeA,EAAO,aACtB,iBAAkB+J,EAClB,QAAS,OACT,GAAI3D,EAAQ,CAAE,OAAM,EAAI,CAAC,CAC3B,EAEJ,CASA,eAAsB,iBACpB,EACA,EACA,EACA,EACe,CACf,GAAM,CAAE,UAAS,aAAc,cAAcT,EAAQE,EAAMG,EAAgBO,CAAI,EAC3EF,GAAW,UAAY,WACzB,MAAM,oBAAoBN,CAAO,EAEnC,OAAOJ,EAAO,MAAMI,EACtB,CAUA,eAAsB,qBACpB,EACA,EACA,EACA,EAQA,CACA,GAAM,CAAE,UAAS,aAAc,cAAcJ,EAAQE,EAAMG,EAAgBO,CAAI,EAC/E,GAAKF,EAEL,MAAO,CAAE,YAAW,GAAG,MADF,cAAcA,EAAWN,EAASF,CAAI,CAC7B,CAChC,CAEA,SAAS,qBAAqB,EAAkB,EAAkB,EAAgB,CAChF,GAAImE,IAAaC,EACjB,CAAItE,EAAO,eAAiBqE,IAC1B,EAAO,aAAeC,GAExB,IAAK,IAAMlI,KAAW,OAAO,OAAO4D,EAAO,QAAQ,EAC7C5D,GAAS,OAASiI,IACpB,EAAQ,KAAOC,EAJK,CAO1B,CASA,eAAsB,sBACpB,EACA,EACA,EACA,EACe,CACf,GAAIC,IAAeC,EAAe,OAClC,qBAAqBxE,EAAQuE,EAAYC,CAAa,EACtD,IAAMR,EAAe,gBAAgBQ,EAAenE,CAAc,EAElE,MAAM,gBAAgBL,EADE,gBAAgBuE,EAAYlE,CACR,EAAG2D,EAAc,CAAE,iBAAkB,EAAK,CAAC,EAEvF,MAAM,gBAAgBhE,EAAQuE,EAAYP,EAAc,CACtD,iBAFkC,oBAAoB9M,EAAmBmJ,CAAc,CAE3C,CAC9C,CAAC,CACH,CAEA,SAAS,8BAA8B,EAAc,EAA4B,CAC/E,MAAO,GAAQK,EAAU,OAAS,qBAAqBR,CAAI,EAC7D,CASA,eAAsB,uBACpB,EACA,EACY,CACZ,OAAO,MAAM,eAAe,GAAG,mBAAmB,EAAE,OAAQ3C,EAAInE,CAAO,CACzE,CAEA,MAAMqL,GAA0B,IAE1BC,GAA+B,IAoBrC,SAAS,cAAc,EAAmB,EAA2B,CACnE,IAAMC,EAAcP,EAAY,KAAK,IAAI,EACzC,OAAO,OAAO,MAAMO,CAAW,GAAKA,GAAeC,CACrD,CAEA,SAAS,UAAU,EAAqB,EAAiC,CACvE,OACEpB,EAAO,OAAO,cAAgBqB,GAC9B,cAAc,KAAK,MAAMrB,EAAO,MAAM,gBAAgB,EAAGkB,EAA4B,CAEzF,CAEA,SAAS,gBAAgB,EAAqB,EAAiC,CAC7E,OACE,UAAUlB,EAAQqB,CAAa,GAC9B,EAAQrB,EAAO,OAAO,cACrB,cAAc,KAAK,MAAMA,EAAO,MAAM,gBAAgB,EAAGiB,EAAuB,CAEtF,CAEA,eAAe,gBACb,EACA,EACA,EACA,EACsB,CACtB,GAAM,CAAE,UAAS,aAAc,cAAczE,EAAQE,EAAMG,CAAc,EACzE,GAAI,CAACK,EACH,MAAMoE,EACJ,sBACA,SAAS5E,EAAK,cACd,8GACF,EAEF,MAAO,CACL,UACA,WAAY,wBAAwBE,EAASC,CAAc,EAC3D,MAAOK,EACP,OAAQ,MAAM,cAAcA,EAAWN,EAASF,CAAI,CACtD,CACF,CAEA,SAAS,eACP,EACA,EACe,CAEf,OADA9I,EAA+BoM,EAAO,OAAO,YAAanD,CAAc,EACjE,CACL,YAAamD,EAAO,OAAO,YAC3B,KAAMA,EAAO,WACb,UAAW,KAAK,MAAMA,EAAO,MAAM,gBAAgB,EACnD,YAAa,EAAQA,EAAO,OAAO,YACrC,CACF,CAEA,SAAS,SAAS,EAAkD,CAClE,OAAO,OAAO9K,GAAU,YAAYA,GAAkB,CAAC,MAAM,QAAQA,CAAK,CAC5E,CAEA,SAAS,gBAAgB,EAAiC,EAAiC,CACzF,IAAK,IAAMmB,KAAO,OAAO,KAAKkL,CAAM,EAC7B,OAAO,OAAOlK,EAAQhB,CAAG,GAAG,OAAOkL,EAAOlL,GAEjD,IAAK,GAAM,CAACA,EAAKnB,KAAU,OAAO,QAAQmC,CAAM,EAAG,CACjD,IAAM6D,EAAUqG,EAAOlL,GACnB,SAAS6E,CAAO,GAAK,SAAShG,CAAK,EACrC,gBAAgBgG,EAAShG,CAAK,EAE9B,EAAOmB,GAAOnB,CAElB,CACF,CAeA,eAAsB,iBACpB,EACA,EACA,EACA,EACsB,CACtB,IAAMsM,EAAS,MAAM,mBAAmB,CAAE,SAAQ,OAAM,iBAAgB,SAAQ,CAAC,EACjF,MAAO,CAAE,YAAaA,EAAO,YAAa,KAAMA,EAAO,IAAK,CAC9D,CAEA,SAAS,gBAAgB,EAA2C,CAClE,IAAMC,EAAY7I,EAAU,CAAC,YAAaA,CAAO,EAAI,CAAC,EACtD,OAAQ,EAAM,EAAS,IACrBrF,EAAS,CACP,OACA,UACA,aACA,KAAM,CAAE,QAAS,SAAU,KAAM,CAAC,QAAS,GAAGkO,EAAW,QAAQ,CAAE,EACnE,QAAS,CAAE,QAAS7I,GAAW,IAAK,CACtC,CAAC,CACL,CAEA,SAAS,kBAAkB,EAAmC,CAC5D,OAAO0I,EACL,qBACA,iBACA,uGACF,CACF,CAEA,eAAe,mBAAmB,EAA+C,CAC/E,GAAM,CAAE,SAAQ,OAAM,iBAAgB,UAAS,iBAAkBI,EAC3DJ,EAAe,gBAAgB1I,CAAO,EACtCoH,EAAS,MAAM,gBAAgBxD,EAAQE,EAAMG,EAAgByE,CAAY,EAC/E,GAAI,CAAC,gBAAgBtB,EAAQqB,CAAa,EAAG,OAAO,eAAerB,EAAQnD,CAAc,EAEzF,IAAM8E,EAAU,UAAU3B,EAAQqB,CAAa,EAC/C,GAAI,CACF,OAAO,MAAM,uBACX,SAAY,CACV,IAAMG,EAAS,MAAM,mBAAmB,EACxC,GAAI,CACF,OAAO,MAAM,mBAAmB,CAAE,GAAGE,EAAS,OAAQF,CAAO,EAAGF,CAAY,CAC9E,QAAU,CACR,gBAAgB9E,EAAQgF,CAAM,CAChC,CACF,EACAG,EAAU,IAAA,GAAY,CAAE,UAAW,GAA8B,CACnE,CACF,OAASrK,EAAO,CACd,GAAIqK,GAAW,CAAC,oBAAoBrK,CAAK,EAAG,MAAMA,EAGlD,OAFI,UAAU0I,EAAQqB,CAAa,EAAU,MAAM,mBAAmBK,CAAO,GAC7ErO,EAAO,MAAM,0EAA0E,EAChF,eAAe2M,EAAQnD,CAAc,EAC9C,CACF,CAEA,eAAe,mBACb,EACA,EACwB,CACxB,GAAM,CAAE,SAAQ,OAAM,iBAAgB,iBAAkB6E,EAClD1B,EAAS,MAAM,gBAAgBxD,EAAQE,EAAMG,EAAgByE,CAAY,EAC/E,GAAI,CAAC,gBAAgBtB,EAAQqB,CAAa,EAAG,OAAO,eAAerB,EAAQnD,CAAc,EAEzF,GAAM,CAAE,QAAS+E,EAAY,WAAYC,EAAkB,MAAO3E,EAAW,UAAW8C,EACxF,GAAI,CAACnJ,EAAO,aAAc,MAAM,kBAAkByK,CAAY,EAE9D,IAAMQ,EAASjO,GAAiBgJ,CAAc,EAC1CkF,EACJ,GAAI,CACF,EAAO,MAAMD,EAAO,aAAa,CAC/B,YAAajL,EAAO,YACpB,aAAcA,EAAO,aACrB,UAAW,KAAK,MAAMqG,EAAU,gBAAgB,CAClD,CAAC,CACH,OAAS5F,EAAO,CACd,GAAI,CAAC,UAAU0I,EAAQqB,CAAa,EAElC,OADAhO,EAAO,MAAM,uDAAuD,OAAOiE,CAAK,GAAG,EAC5E,eAAe0I,EAAQnD,CAAc,EAE9C,MAAMyE,EACJ,4BACA,0DACA,sJACF,CACF,CACA,qBAAqB,CACnB,YAAaS,EAAK,YAClB,aAAcA,EAAK,cAAgB,IAAA,EACrC,CAAC,EAED,IAAMC,EAAkB,CACtB,YAAaD,EAAK,YAClB,aAAcA,EAAK,cAAgBlL,EAAO,YAC5C,EACMoL,EAAe,IAAI,KACvBjN,EAAc+M,EAAK,UAAW,0CAA0C,CAC1E,CAAC,CAAC,YAAY,EACRG,EACJhF,EAAU,OAAS,qBAAqBR,CAAI,GAAK,qBAAqBmF,CAAgB,EAGxF,MAAM,eAAerF,EAAQqF,EAAkBG,EAAiBC,EAAc,CAC5E,iBACA,MAAOC,CACT,CAAC,EACD,oBAAoB1F,CAAM,EAE1B,IAAI2F,EAAeN,EACf5E,EAAQiF,EACZ,GACE,8BAA8BxF,EAAMQ,CAAS,GAC7C,8BAA8B2E,EAAkB3E,CAAS,EAEzD,GAAI,CACF,IAAMkF,EAAW,MAAMtO,GAAciO,EAAK,YAAalF,CAAc,EACrE,EAAeuF,EAAS,IACxB,EAAQA,EAAS,KACnB,OAAS9K,EAAO,CACdjE,EAAO,MAAM,gDAAgD,OAAOiE,CAAK,GAAG,CAC9E,CAkBF,OAfI6K,IAAiBN,GAAoB5E,IAAUiF,IACjD,MAAM,eAAe1F,EAAQ2F,EAAcH,EAAiBC,EAAc,CACxE,iBACA,OACF,CAAC,EAEH,MAAM,sBAAsBzF,EAAQE,EAAMyF,EAActF,CAAc,EACtE,MAAM,gBAAgBL,EAAQoF,EAAY,gBAAgBO,EAActF,CAAc,EAAG,CACvF,iBAAkB,EACpB,CAAC,EACGqF,GAAiBjF,GAASiF,IAAkBjF,GAC9C5J,EAAO,KAAK,kCAAkC6O,EAAc,QAAQjF,EAAM,GAAG,EAE/E,oBAAoBT,CAAM,EAC1B5I,EAA+BmO,EAAK,YAAalF,CAAc,EACxD,CACL,YAAakF,EAAK,YAClB,KAAMI,EACN,UAAW,KAAK,MAAMF,CAAY,EAClC,YAAa,EACf,CACF,CAEA,MAAMI,EAA4B,IAelC,SAAS,wBAAwB,EAAgD,CAC/E,GAAI,CAAE,cAAa,YAAW,QAASC,EAAK,MACxCC,EACAC,EACAC,EAAU,EACVC,EAAY,KACZC,EAAW,KACXC,EAEE,aAAiB,CAAC,cAAchC,EAAWM,EAA4B,EACvE,UACJ,cAAcN,EAAWK,EAAuB,IAAM,CAAC,SAAS,GAAK,KAAK,IAAI,GAAKwB,GAE/E,MAAS,GACZ,KAAa,SAAY,CACxB,GAAI,CACF,IAAMjB,EAAS,MAAM,mBAAmB,CACtC,OAAQ,MAAM,mBAAmB,EACjC,OACA,eAAgBc,EAAK,eACrB,QAASA,EAAK,QACd,eACF,CAAC,EACD,EAAe,IAAA,GACf,IAAMO,EACJxB,IAAkB,IAAA,IAAaG,EAAO,cAAgBH,EACpDG,EAAO,UAAYZ,GAAaiC,GACjC,mCAAmCrB,EACpC,EAAY,KAAK,IAAI,EACrB7N,EAA0BmP,EAAazL,CAAM,GAE7C,EAAU,KAAK,IAAI,EAAIgL,CAE3B,OAAS/K,EAAO,CACd,EAAeA,aAAiB,MAAQA,EAAY,MAAM,OAAOA,CAAK,CAAC,EACvE,EAAU,KAAK,IAAI,EAAI+K,EACvBhP,EAAO,MAAM,qCAAqC,OAAOiE,CAAK,GAAG,CACnE,QAAU,CACR,EAAU,IAAA,EACZ,CACF,EAAA,CAAG,EAECD,EAA4B,CAChC,MAAM,SAAU,CAEd,GADIkL,GAAWO,IAAgBF,GAAc,MAAML,EAC/C,CAAC,MAAM,GAAMA,GAAW,SAAS,EAAI,OAAOO,EAEhD,GADA,MAAM,MAAM,EACR,CAAC,SAAS,EAAG,MAAMN,GAAgB,kBAAkB,gBAAgBF,EAAK,OAAO,CAAC,EACtF,OAAOQ,CACT,EACA,MAAM,gBAAgB,EAAU,CAC9B,GAAIA,IAAgBC,EAAU,OAAOD,EAErC,IADA,EAAeC,EACRR,GAAS,MAAMA,EACtB,GAAIO,IAAgBC,EAAU,OAAOD,EACrC,GAAI,OAAK,IAAI,EAAI,KAAK,IAAIJ,EAAWC,CAAQ,EAAI,KAGjD,MAFA,GAAW,KAAK,IAAI,EACpB,MAAM,MAAMI,CAAQ,EACbD,IAAgBC,EAAW,IAAA,GAAYD,CAChD,CACF,EACA,OAAOzL,CACT,CAWA,SAAgB,eAAe,EAAyC,CAStE,OARIoB,IAGA,QAAQ,IAAI,mBACP,QAAQ,IAAI,mBAIduK,GAAW,kBAAuB,EAC3C,C"}