{"version":3,"file":"cli-connect-override-b4kKqgOZ.mjs","sources":["../src/utils/merge-default-drives.ts","../src/utils/connect-config-validation.ts","../src/utils/parse-default-drives.ts","../src/utils/cli-connect-override.ts"],"sourcesContent":["import type { PHConnectDefaultDrive } from \"@powerhousedao/shared/clis\";\n\nfunction isLocalDrive(\n  drive: PHConnectDefaultDrive,\n): drive is Extract<PHConnectDefaultDrive, { local: true }> {\n  return \"local\" in drive;\n}\n\n// Identity key for de-duplication: remote entries are keyed by URL; local\n// entries are keyed by `local:<id>` so a local drive id can never collide\n// with a remote URL that happens to be the same string.\nconst driveKey = (drive: PHConnectDefaultDrive): string =>\n  isLocalDrive(drive) ? `local:${drive.id}` : drive.url;\n\n/**\n * Concatenate groups of `connect.drives.defaultDrives` in the order given,\n * de-duplicating by drive identity (URL for remote entries, id for local\n * ones). The first occurrence of a drive wins, so earlier groups keep their\n * position and metadata — e.g. the Vetra drive `ph vetra` starts stays first\n * even when the project's `powerhouse.config.json` lists the same drive.\n */\nexport function mergeDefaultDrives(\n  ...groups: PHConnectDefaultDrive[][]\n): PHConnectDefaultDrive[] {\n  const seen = new Set<string>();\n  const out: PHConnectDefaultDrive[] = [];\n  for (const group of groups) {\n    for (const drive of group) {\n      const key = driveKey(drive);\n      if (seen.has(key)) continue;\n      seen.add(key);\n      out.push(drive);\n    }\n  }\n  return out;\n}\n","// Ajv-backed validation for `ph connect config` writes.\n//\n// Two entry points:\n//\n//   - validateConnectKeyValue(key, value)\n//     For the `<key> <value>` form. Sets the value at the dotted path inside a\n//     stub connect block, then validates the result against the runtime schema.\n//     Catches both invalid paths (key doesn't map to a real field) and invalid\n//     types (e.g. `connect.renown.chainId \"abc\"` — schema says number).\n//\n//   - validateConnectPatch(patch)\n//     For the `--json` form. Validates the whole patch as a partial connect.*\n//     blob. Same schema, but we only check the keys actually present in the\n//     patch (additional keys still fail per `additionalProperties: false`).\n//\n// Both return a typed `connect.*` partial on success or throw with a multi-\n// line, actionable message on failure.\n\nimport { phConnectRuntimeConfigSchema } from \"@powerhousedao/shared/connect\";\nimport type { PHConnectRuntimeConfig } from \"@powerhousedao/shared/clis\";\nimport AjvNs from \"ajv\";\nimport { isPlainObject, stringToPath } from \"remeda\";\n\ntype PlainObject = Record<string, unknown>;\ntype ConnectPartial = Partial<PHConnectRuntimeConfig>;\n\n// Ajv ships as CJS — under NodeNext ESM the default lands on `.default` while\n// types still point at the class on the namespace. Normalize the constructor.\ntype AjvCtor = new (opts?: Record<string, unknown>) => {\n  compile: (schema: unknown) => AjvValidate;\n};\ntype AjvError = {\n  instancePath?: string;\n  message?: string;\n  params?: { additionalProperty?: string };\n};\ntype AjvValidate = ((data: unknown) => boolean) & {\n  errors?: AjvError[] | null;\n};\n\nconst Ajv = ((AjvNs as unknown as { default?: AjvCtor }).default ??\n  (AjvNs as unknown as AjvCtor)) as AjvCtor;\n\nconst ajv = new Ajv({ allErrors: true, strict: false });\nconst validateConnect: AjvValidate = ajv.compile(phConnectRuntimeConfigSchema);\n\n/**\n * Parse the CLI-supplied value. Tries JSON first so `true`, `42`, `\"a\"`,\n * `null`, `[1,2]` coerce; falls back to the raw string for unquoted text.\n *\n * Examples:\n *   \"true\"  -> true (boolean)\n *   \"42\"    -> 42 (number)\n *   '\"x\"'   -> \"x\" (string, quoted)\n *   \"x\"     -> \"x\" (string, bare)\n *   \"[1,2]\" -> [1, 2] (array)\n */\nexport function parseCliValue(raw: string): unknown {\n  try {\n    return JSON.parse(raw);\n  } catch {\n    return raw;\n  }\n}\n\n/**\n * Strip the optional leading \"connect.\" prefix so callers can pass either\n * \"connect.renown.url\" or \"renown.url\" interchangeably.\n */\nexport function normalizeKey(key: string): string {\n  return key.startsWith(\"connect.\") ? key.slice(\"connect.\".length) : key;\n}\n\nfunction formatErrors(errors: AjvError[] | null | undefined): string {\n  if (!errors || errors.length === 0) return \"unknown validation error\";\n  return errors\n    .map((e) => {\n      const path = e.instancePath || \"(root)\";\n      const extra = e.params?.additionalProperty;\n      const suffix = extra === undefined ? \"\" : ` (${JSON.stringify(extra)})`;\n      return `  ${path} ${e.message ?? \"\"}${suffix}`.trim();\n    })\n    .join(\"\\n\");\n}\n\n/**\n * Validate a single `<key> <value>` pair. Returns the parsed connect-partial\n * that, when deep-merged into the existing config, applies the change.\n *\n * Throws on:\n *   - Empty key\n *   - Path that doesn't exist in the schema\n *   - Value whose type doesn't match the schema at the leaf path\n */\nexport function validateConnectKeyValue(\n  key: string,\n  rawValue: string,\n): ConnectPartial {\n  const normalized = normalizeKey(key);\n  if (!normalized) {\n    throw new Error(\n      \"ph connect config: key cannot be empty. Pass a dotted path inside connect.* (e.g. connect.renown.url).\",\n    );\n  }\n  const parsed = parseCliValue(rawValue);\n  // Build a nested-stub object from the dotted path so Ajv can validate\n  // the value's shape against the schema (e.g. \"renown.url\" + parsed →\n  // { renown: { url: parsed } }). Remeda's `setPath` requires the path\n  // to exist; this is the sparse-creation case, so we fold the parts.\n  const stub = stringToPath(normalized).reduceRight<unknown>(\n    (acc, key) => ({ [String(key)]: acc }),\n    parsed,\n  ) as PlainObject;\n  if (!validateConnect(stub)) {\n    throw new Error(\n      `ph connect config: validation failed for key=\"${normalized}\" value=${JSON.stringify(parsed)} (parsed as ${typeof parsed}):\\n${formatErrors(validateConnect.errors)}`,\n    );\n  }\n  return stub;\n}\n\n/**\n * Validate a `--json` bulk override. Returns the parsed partial.\n *\n * `packageRegistryUrl` is a top-level runtime field (not part of the\n * `connect.*` schema). If present in the payload, it is extracted before\n * validation so the connect-only blob can be checked against the schema,\n * then re-attached on the returned object so the caller can route it.\n *\n * `command` prefixes error messages (e.g. \"ph connect build\").\n */\nexport function validateConnectPatch(\n  raw: string,\n  command = \"ph connect config\",\n): ConnectPartial & {\n  packageRegistryUrl?: unknown;\n} {\n  const label = `${command} --json`;\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(raw);\n  } catch (e) {\n    const msg = e instanceof Error ? e.message : String(e);\n    throw new Error(\n      `${label}: invalid JSON (${msg}). Expected a partial connect.* blob, e.g. --json '{\"renown\":{\"url\":\"...\"}}'.`,\n      { cause: e },\n    );\n  }\n  if (!isPlainObject(parsed)) {\n    throw new Error(\n      `${label}: payload must be a JSON object, got ${typeof parsed}.`,\n    );\n  }\n  if (Object.prototype.hasOwnProperty.call(parsed, \"connect\")) {\n    const inner = JSON.stringify((parsed as PlainObject).connect);\n    throw new Error(\n      `${label}: pass the connect.* block without the \"connect\" wrapper, e.g. --json '${inner}'.`,\n    );\n  }\n  // Extract `packageRegistryUrl` (top-level field, not in the connect schema)\n  // before validating, so a payload like `{\"packageRegistryUrl\":\"…\"}` doesn't\n  // fail the `additionalProperties: false` check on the connect schema.\n  const top = parsed as PlainObject;\n  const hasPackageRegistryUrl = Object.prototype.hasOwnProperty.call(\n    top,\n    \"packageRegistryUrl\",\n  );\n  const packageRegistryUrl = top.packageRegistryUrl;\n  const connectOnly: PlainObject = { ...top };\n  delete connectOnly.packageRegistryUrl;\n  if (!validateConnect(connectOnly)) {\n    throw new Error(\n      `${label}: validation failed:\\n${formatErrors(validateConnect.errors)}\\nExpected a partial connect.* blob with nested keys, e.g. --json '{\"app\":{\"workflowsEnabled\":true}}'.`,\n    );\n  }\n  return hasPackageRegistryUrl\n    ? ({ ...connectOnly, packageRegistryUrl } as ConnectPartial & {\n        packageRegistryUrl?: unknown;\n      })\n    : (connectOnly as ConnectPartial);\n}\n","/**\n * Comma-separated URL string → array of `{url, name: null, icon: null}`\n * entries suitable for `connect.drives.defaultDrives`. Used by ph-cli's\n * CLI-override builders and by `ph vetra` when forwarding the local\n * switchboard's drive URLs into the runtime config.\n */\nexport const parseDefaultDrivesUrl = (\n  v: string,\n): Array<{ url: string; name: null; icon: null }> =>\n  v\n    .split(\",\")\n    .map((s) => s.trim())\n    .filter(Boolean)\n    .map((url) => ({ url, name: null, icon: null }));\n","// Builds a `connectOverride` partial from CLI flags. Shared by:\n//\n//   - `ph connect build` — uses `buildCliConnectOverride` to produce the\n//     `cliConnectOverride` patch the Vite plugin applies at the top of the\n//     precedence ladder:\n//\n//       DEFAULT_CONNECT_CONFIG  <  env-var seeds  <  source connect.*  <  --json  <  individual --flag\n//\n//   - `ph connect config` — uses `buildConnectFlagPatch` (the per-field\n//     partial builder) to translate flag-set values into the patch that\n//     gets dual-written to source + dist `powerhouse.config.json`.\n//\n// `--json` parses as a partial `connect.*` blob and merges in first; then any\n// individual --flag values merge on top, so a flag beats a conflicting --json\n// value.\n\nimport type {\n  PHConnectDefaultDrive,\n  PHConnectRuntimeConfig,\n} from \"@powerhousedao/shared/clis\";\nimport { deepMerge } from \"@powerhousedao/shared/connect\";\nimport { mergeDefaultDrives } from \"./merge-default-drives.js\";\nimport type { ConnectBuildArgs, ConnectStudioArgs } from \"../types.js\";\nimport {\n  normalizeKey,\n  parseCliValue,\n  validateConnectKeyValue,\n  validateConnectPatch,\n} from \"./connect-config-validation.js\";\nimport { parseDefaultDrivesUrl } from \"./parse-default-drives.js\";\n\ntype PlainObject = Record<string, unknown>;\n\n/**\n * Structural input shape consumed by `buildConnectFlagPatch`. Every property\n * is strict-optional — `undefined` means \"user did not pass this flag\" and\n * the path is excluded from the patch.\n *\n * Callers with cmd-ts-typed args where some flags have built-in defaults\n * (e.g. the 4 commonArgs flags `--base` / `--log-level` /\n * `--default-drives-url` / `--drive-preserve-strategy`) must filter through\n * `wasFlagExplicitlyPassed` BEFORE building this input — otherwise default\n * values like `\"info\"` will silently clobber source `powerhouse.config.json`\n * values.\n */\nexport type ConnectFlagInput = {\n  // Strict-optional flags from connectRuntimeOverrideArgs (excluding\n  // `packagesRegistry`, which is a top-level runtime field — see\n  // `buildCliConnectOverride`).\n  json?: string | undefined;\n  renownUrl?: string | undefined;\n  renownNetworkId?: string | undefined;\n  renownChainId?: number | undefined;\n  renownNamespace?: string | undefined;\n  renownSwitchboardUrl?: string | undefined;\n  allowAddDrive?: boolean | undefined;\n  externalPackages?: boolean | undefined;\n  workflows?: boolean | undefined;\n  remoteDrivesEnabled?: boolean | undefined;\n  remoteDrivesAllowAdd?: boolean | undefined;\n  remoteDrivesAllowDelete?: boolean | undefined;\n  localDrivesEnabled?: boolean | undefined;\n  localDrivesAllowAdd?: boolean | undefined;\n  localDrivesAllowDelete?: boolean | undefined;\n  appName?: string | undefined;\n  homeBackground?: string | undefined;\n  sentryDsn?: string | undefined;\n  sentryEnv?: string | undefined;\n  sentryTracingEnabled?: boolean | undefined;\n  // commonArgs flags. Callers must apply `wasFlagExplicitlyPassed`\n  // filtering (see above).\n  basePath?: string | undefined;\n  logLevel?: string | undefined;\n  defaultDrivesUrl?: string | undefined;\n  drivesPreserveStrategy?: string | undefined;\n};\n\n// Schema-validates `--json` so unknown keys, a `connect` wrapper or wrong\n// types fail instead of being dropped from the dist config.\nfunction parseJsonOverride(raw: string | undefined): PlainObject {\n  if (raw === undefined || raw === \"\") return {};\n  return validateConnectPatch(raw, \"ph connect build\") as PlainObject;\n}\n\nfunction setIfDefined<V>(\n  target: PlainObject,\n  key: string,\n  value: V | undefined,\n): void {\n  if (value !== undefined) target[key] = value;\n}\n\n/**\n * Detect whether the user literally typed `--<longName>` on the command\n * line. Used to gate the 4 commonArgs flags through `cliConnectOverride` —\n * those flags have cmd-ts defaults, so their parsed value is always\n * defined, and a naive merge would silently clobber source values with the\n * default on every build.\n *\n * Handles both `--flag value` and `--flag=value` forms.\n */\nexport function wasFlagExplicitlyPassed(longName: string): boolean {\n  const dashed = `--${longName}`;\n  return process.argv.some(\n    (arg) => arg === dashed || arg.startsWith(`${dashed}=`),\n  );\n}\n\n/**\n * Build a `connect.*` partial from the 20 field flags. Only includes paths\n * the user explicitly set (undefined values are excluded).\n *\n * Single source of truth for the flag → JSON-path mapping; consumed by both\n * `ph connect build` and `ph connect config`.\n */\nexport function buildConnectFlagPatch(args: ConnectFlagInput): PlainObject {\n  const out: PlainObject = {};\n\n  const app: PlainObject = {};\n  setIfDefined(app, \"basePath\", args.basePath);\n  setIfDefined(app, \"logLevel\", args.logLevel);\n  setIfDefined(app, \"workflowsEnabled\", args.workflows);\n  if (Object.keys(app).length > 0) out.app = app;\n\n  const renown: PlainObject = {};\n  setIfDefined(renown, \"url\", args.renownUrl);\n  setIfDefined(renown, \"networkId\", args.renownNetworkId);\n  setIfDefined(renown, \"chainId\", args.renownChainId);\n  setIfDefined(renown, \"namespace\", args.renownNamespace);\n  setIfDefined(renown, \"switchboardUrl\", args.renownSwitchboardUrl);\n  if (Object.keys(renown).length > 0) out.renown = renown;\n\n  const packages: PlainObject = {};\n  setIfDefined(packages, \"externalEnabled\", args.externalPackages);\n  if (Object.keys(packages).length > 0) out.packages = packages;\n\n  // --home-background: empty string is the explicit \"set null\" form\n  // (cmd-ts can't pass `null` directly through a string option).\n  const branding: PlainObject = {};\n  setIfDefined(branding, \"appName\", args.appName);\n  if (args.homeBackground !== undefined) {\n    branding.homeBackground =\n      args.homeBackground === \"\" ? null : args.homeBackground;\n  }\n  if (Object.keys(branding).length > 0) out.branding = branding;\n\n  // --sentry-dsn: empty string is the explicit \"set null\" form (disables\n  // Sentry). Same pattern as --home-background.\n  const sentry: PlainObject = {};\n  if (args.sentryDsn !== undefined) {\n    sentry.dsn = args.sentryDsn === \"\" ? null : args.sentryDsn;\n  }\n  setIfDefined(sentry, \"env\", args.sentryEnv);\n  setIfDefined(sentry, \"tracing\", args.sentryTracingEnabled);\n  if (Object.keys(sentry).length > 0) out.sentry = sentry;\n\n  const drives: PlainObject = {};\n  setIfDefined(drives, \"allowAddDrive\", args.allowAddDrive);\n  setIfDefined(drives, \"preserveStrategy\", args.drivesPreserveStrategy);\n  if (args.defaultDrivesUrl !== undefined && args.defaultDrivesUrl !== \"\") {\n    drives.defaultDrives = parseDefaultDrivesUrl(args.defaultDrivesUrl);\n  }\n\n  const remote: PlainObject = {};\n  setIfDefined(remote, \"enabled\", args.remoteDrivesEnabled);\n  setIfDefined(remote, \"allowAdd\", args.remoteDrivesAllowAdd);\n  setIfDefined(remote, \"allowDelete\", args.remoteDrivesAllowDelete);\n\n  const local: PlainObject = {};\n  setIfDefined(local, \"enabled\", args.localDrivesEnabled);\n  setIfDefined(local, \"allowAdd\", args.localDrivesAllowAdd);\n  setIfDefined(local, \"allowDelete\", args.localDrivesAllowDelete);\n\n  const sections: PlainObject = {};\n  if (Object.keys(remote).length > 0) sections.remote = remote;\n  if (Object.keys(local).length > 0) sections.local = local;\n  if (Object.keys(sections).length > 0) drives.sections = sections;\n  if (Object.keys(drives).length > 0) out.drives = drives;\n\n  return out;\n}\n\n/**\n * Combine `--json` and the individual flag values into the two override\n * inputs `ph connect build` forwards to the Vite plugin:\n *\n *   - `connectOverride`: a partial `connect.*` patch (deep-merged at the top\n *     of the runtime-config precedence ladder).\n *   - `packageRegistryUrl`: a separate top-level override; mirrors the\n *     source-config top-level field (the SPA reads it directly).\n *\n * `--packages-registry` and `--json` containing a top-level\n * `packageRegistryUrl` both flow into `packageRegistryUrl`; the flag wins on\n * collision. Returns `undefined` for whichever override was not supplied.\n *\n * The 4 commonArgs flags (`--base`, `--log-level`, `--default-drives-url`,\n * `--drive-preserve-strategy`) are gated through `wasFlagExplicitlyPassed`\n * because they carry cmd-ts defaults that would otherwise leak into the\n * override on every build.\n */\nexport function buildCliConnectOverride(args: ConnectBuildArgs): {\n  connectOverride: PHConnectRuntimeConfig | undefined;\n  packageRegistryUrl: string | undefined;\n} {\n  const fromJson = parseJsonOverride(args.json);\n\n  const input: ConnectFlagInput = {\n    renownUrl: args.renownUrl,\n    renownNetworkId: args.renownNetworkId,\n    renownChainId: args.renownChainId,\n    renownNamespace: args.renownNamespace,\n    renownSwitchboardUrl: args.renownSwitchboardUrl,\n    allowAddDrive: args.allowAddDrive,\n    externalPackages: args.externalPackages,\n    workflows: args.workflows,\n    remoteDrivesEnabled: args.remoteDrivesEnabled,\n    remoteDrivesAllowAdd: args.remoteDrivesAllowAdd,\n    remoteDrivesAllowDelete: args.remoteDrivesAllowDelete,\n    localDrivesEnabled: args.localDrivesEnabled,\n    localDrivesAllowAdd: args.localDrivesAllowAdd,\n    localDrivesAllowDelete: args.localDrivesAllowDelete,\n    appName: args.appName,\n    homeBackground: args.homeBackground,\n    sentryDsn: args.sentryDsn,\n    sentryEnv: args.sentryEnv,\n    sentryTracingEnabled: args.sentryTracingEnabled,\n    // commonArgs flags — only forward when the user explicitly passed them.\n    basePath: wasFlagExplicitlyPassed(\"base\")\n      ? args.connectBasePath\n      : undefined,\n    logLevel: wasFlagExplicitlyPassed(\"log-level\") ? args.logLevel : undefined,\n    defaultDrivesUrl: wasFlagExplicitlyPassed(\"default-drives-url\")\n      ? args.defaultDrivesUrl\n      : undefined,\n    drivesPreserveStrategy: wasFlagExplicitlyPassed(\"drive-preserve-strategy\")\n      ? args.drivesPreserveStrategy\n      : undefined,\n  };\n\n  const fromFlags = buildConnectFlagPatch(input);\n\n  // Positional `<key> <value>` override (only set when both are present;\n  // `runConnectBuild` rejects the 1-positional case up front because build\n  // has no read mode). Layered on top of --json + flags so a positional\n  // override wins on collision — matches the user's literal command line.\n  let positionalRegistry: string | undefined;\n  let fromPositional: PlainObject = {};\n  if (args.keyPositional !== undefined && args.valuePositional !== undefined) {\n    const normalized = normalizeKey(args.keyPositional);\n    if (!normalized) {\n      throw new Error(\n        \"ph connect build: positional <key> cannot be empty. Pass a dotted path inside connect.* (e.g. connect.renown.url).\",\n      );\n    }\n    if (normalized === \"packageRegistryUrl\") {\n      const parsed = parseCliValue(args.valuePositional);\n      if (typeof parsed !== \"string\") {\n        throw new Error(\n          `ph connect build: positional packageRegistryUrl must be a string (got ${typeof parsed}).`,\n        );\n      }\n      positionalRegistry = parsed;\n    } else {\n      fromPositional = validateConnectKeyValue(\n        normalized,\n        args.valuePositional,\n      );\n    }\n  }\n\n  // Top-level `packageRegistryUrl` can come from --json (top-level),\n  // --packages-registry flag, or positional `packageRegistryUrl <value>`.\n  // Precedence (highest → lowest): positional > flag > --json.\n  const jsonRegistry =\n    typeof fromJson.packageRegistryUrl === \"string\"\n      ? (fromJson.packageRegistryUrl as string)\n      : undefined;\n  const packageRegistryUrl =\n    positionalRegistry ?? args.packagesRegistry ?? jsonRegistry;\n  // Strip the top-level field from the JSON patch before deep-merging into\n  // the connect partial — it isn't a `connect.*` field.\n  const jsonConnect = { ...fromJson };\n  delete jsonConnect.packageRegistryUrl;\n\n  const hasJsonConnect = Object.keys(jsonConnect).length > 0;\n  const hasFlags = Object.keys(fromFlags).length > 0;\n  const hasPositional = Object.keys(fromPositional).length > 0;\n  const connectOverride =\n    !hasJsonConnect && !hasFlags && !hasPositional\n      ? undefined\n      : deepMerge(\n          deepMerge(\n            jsonConnect as PHConnectRuntimeConfig,\n            fromFlags as PHConnectRuntimeConfig,\n          ),\n          fromPositional as PHConnectRuntimeConfig,\n        );\n\n  return { connectOverride, packageRegistryUrl };\n}\n\n/**\n * Parallel of `buildCliConnectOverride` for `ph connect studio` / `ph vetra`.\n * Studio only exposes the 4 commonArgs flags (`--base`, `--log-level`,\n * `--default-drives-url`, `--drive-preserve-strategy`); each is gated through\n * `wasFlagExplicitlyPassed` so cmd-ts defaults don't leak into the override.\n *\n * `callerOverride` is supplied by wrappers around studio (notably `ph vetra`,\n * which sets default drives + preserveStrategy directly). The flag override\n * deep-merges on top of it: caller choices apply for every flag the user\n * didn't type, and an explicitly passed flag wins for its own field —\n * except `drives.defaultDrives`, which merges additively: a flag's drives\n * are appended to the caller's list (de-duplicated by drive identity) rather\n * than replacing it, so vetra's own drives stay in Connect's default set.\n * Without a caller override (plain `ph connect studio`) only the flag can\n * carry defaultDrives, so that command's behavior is unchanged.\n */\nexport function buildStudioConnectOverride(\n  args: ConnectStudioArgs,\n  callerOverride: PHConnectRuntimeConfig | undefined,\n): PHConnectRuntimeConfig | undefined {\n  const flagOverride = buildConnectFlagPatch({\n    basePath: wasFlagExplicitlyPassed(\"base\")\n      ? args.connectBasePath\n      : undefined,\n    logLevel: wasFlagExplicitlyPassed(\"log-level\") ? args.logLevel : undefined,\n    defaultDrivesUrl: wasFlagExplicitlyPassed(\"default-drives-url\")\n      ? args.defaultDrivesUrl\n      : undefined,\n    drivesPreserveStrategy: wasFlagExplicitlyPassed(\"drive-preserve-strategy\")\n      ? args.drivesPreserveStrategy\n      : undefined,\n    renownNamespace: args.renownNamespace,\n  }) as PHConnectRuntimeConfig;\n\n  // Studio commands (`ph connect studio`, `ph vetra`) always run in studio\n  // mode: Connect loads the vetra package and offers builder document types.\n  const studioOverride: PHConnectRuntimeConfig = { app: { studioMode: true } };\n  const layers = [callerOverride, flagOverride, studioOverride].filter(\n    (o): o is PHConnectRuntimeConfig =>\n      o !== undefined && Object.keys(o).length > 0,\n  );\n  const merged = layers.reduce(\n    (acc, o) => deepMerge(acc, o),\n    {} as PHConnectRuntimeConfig,\n  );\n\n  // `deepMerge` replaces arrays, so the flag's defaultDrives would clobber\n  // the caller's list; re-apply them as the de-duplicated union instead.\n  // Only needed when two or more layers contribute default drives (the\n  // plain-studio single-layer case is already exactly the flag's list).\n  const driveGroups = layers\n    .map((l) => l.drives?.defaultDrives)\n    .filter(\n      (d): d is PHConnectDefaultDrive[] => Array.isArray(d) && d.length > 0,\n    );\n  if (driveGroups.length > 1) {\n    merged.drives = {\n      ...merged.drives,\n      defaultDrives: mergeDefaultDrives(...driveGroups),\n    };\n  }\n  return merged;\n}\n"],"names":[],"mappings":"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","debug_id":"e9d67427-1c35-5d4b-85d5-4bf380d60b94"}