{"version":3,"file":"interactive.mjs","names":[],"sources":["../../src/feature/interactive.ts"],"sourcesContent":["import { getJsonSchema } from '../core/args.ts';\nimport type { InteractivePromptConfig, ResolvedPadroneRuntime } from '../core/runtime.ts';\nimport type { AnyPadroneCommand } from '../types/index.ts';\n\n/**\n * Auto-detect the prompt type for a field based on its JSON schema property definition.\n */\nexport function detectPromptConfig(\n  name: string,\n  propSchema: Record<string, any> | undefined,\n  description?: string,\n): InteractivePromptConfig {\n  const message = description || propSchema?.description || name;\n\n  if (!propSchema) return { name, message, type: 'input' };\n\n  if (propSchema.type === 'boolean') {\n    return { name, message, type: 'confirm', default: propSchema.default };\n  }\n\n  if (propSchema.enum) {\n    return {\n      name,\n      message,\n      type: 'select',\n      choices: propSchema.enum.map((v: unknown) => ({ label: String(v), value: v })),\n      default: propSchema.default,\n    };\n  }\n\n  if (propSchema.type === 'array' && propSchema.items?.enum) {\n    return {\n      name,\n      message,\n      type: 'multiselect',\n      choices: propSchema.items.enum.map((v: unknown) => ({ label: String(v), value: v })),\n      default: propSchema.default,\n    };\n  }\n\n  if (propSchema.format === 'password') {\n    return { name, message, type: 'password', default: propSchema.default };\n  }\n\n  return { name, message, type: 'input', default: propSchema.default };\n}\n\n/**\n * Prompt a single field and validate it against the command's schema.\n * Re-prompts with a warning until the user provides a valid value.\n */\nasync function promptWithValidation(\n  field: string,\n  config: InteractivePromptConfig,\n  currentData: Record<string, unknown>,\n  command: AnyPadroneCommand,\n  runtime: ResolvedPadroneRuntime,\n): Promise<unknown> {\n  let promptConfig = config;\n\n  // eslint-disable-next-line no-constant-condition\n  while (true) {\n    const value = await runtime.prompt!(promptConfig);\n\n    if (!command.argsSchema) return value;\n\n    // Validate the full object with the new value to catch field-level issues\n    const testData = { ...currentData, [field]: value };\n    const validated = await command.argsSchema['~standard'].validate(testData);\n\n    if (!validated.issues) return value;\n\n    // Only keep issues whose path starts with this field\n    const fieldIssues = validated.issues.filter((issue: { path?: ReadonlyArray<PropertyKey> }) => {\n      const rootKey = issue.path?.[0];\n      return rootKey !== undefined && String(rootKey) === field;\n    });\n\n    if (fieldIssues.length === 0) return value;\n\n    // Warn the user and re-prompt with the invalid value as default\n    const messages = fieldIssues.map((i: { message: string }) => i.message).join('; ');\n    runtime.error(`Invalid value for \"${field}\": ${messages}`);\n    promptConfig = { ...config, default: value };\n  }\n}\n\n/**\n * Prompt for missing interactive fields.\n * Runs after env/config preprocessing and before schema validation.\n *\n * When `force` is true, all configured interactive fields are prompted even if they already\n * have values. The current values are used as defaults in the prompts.\n */\nexport async function promptInteractiveFields(\n  data: Record<string, unknown>,\n  command: AnyPadroneCommand,\n  runtime: ResolvedPadroneRuntime,\n  force?: boolean,\n): Promise<Record<string, unknown>> {\n  if (!runtime.prompt) return data;\n\n  const meta = command.meta;\n  const interactiveConfig = meta?.interactive;\n  const optionalInteractiveConfig = meta?.optionalInteractive;\n  if (!interactiveConfig && !optionalInteractiveConfig) return data;\n\n  // Extract JSON schema properties for prompt type detection\n  let jsonProperties: Record<string, any> = {};\n  let requiredFields: Set<string> = new Set();\n  if (command.argsSchema) {\n    try {\n      const jsonSchema = getJsonSchema(command.argsSchema) as Record<string, any>;\n      if (jsonSchema.type === 'object' && jsonSchema.properties) {\n        jsonProperties = jsonSchema.properties;\n      }\n      if (Array.isArray(jsonSchema.required)) {\n        requiredFields = new Set(jsonSchema.required);\n      }\n    } catch {\n      // Ignore schema parsing errors\n    }\n  }\n\n  const fieldDescriptions: Record<string, string | undefined> = {};\n  if (meta?.fields) {\n    for (const [key, value] of Object.entries(meta.fields)) {\n      if (value?.description) fieldDescriptions[key] = value.description;\n    }\n  }\n\n  const result = { ...data };\n\n  // Determine which required interactive fields to prompt\n  let fieldsToPrompt: string[] = [];\n  if (interactiveConfig === true) {\n    if (force) {\n      // When forced, prompt all required fields regardless of current value\n      fieldsToPrompt = [...requiredFields];\n    } else {\n      // All required fields that are missing\n      fieldsToPrompt = [...requiredFields].filter((name) => result[name] === undefined);\n    }\n  } else if (Array.isArray(interactiveConfig)) {\n    if (force) {\n      fieldsToPrompt = [...interactiveConfig];\n    } else {\n      fieldsToPrompt = interactiveConfig.filter((name) => result[name] === undefined);\n    }\n  }\n\n  // Prompt each required interactive field with per-field validation\n  for (const field of fieldsToPrompt) {\n    const config = detectPromptConfig(field, jsonProperties[field], fieldDescriptions[field]);\n    // When forced, use the current value as the default\n    if (force && result[field] !== undefined) {\n      config.default = result[field];\n    }\n    result[field] = await promptWithValidation(field, config, result, command, runtime);\n  }\n\n  // Determine optional interactive fields\n  let optionalFields: string[] = [];\n  if (optionalInteractiveConfig === true) {\n    if (force) {\n      // When forced, include all non-required fields (even those with values)\n      const allKeys = Object.keys(jsonProperties);\n      optionalFields = allKeys.filter((name) => !requiredFields.has(name));\n    } else {\n      // All non-required fields that are still missing\n      const allKeys = Object.keys(jsonProperties);\n      optionalFields = allKeys.filter((name) => !requiredFields.has(name) && result[name] === undefined);\n    }\n  } else if (Array.isArray(optionalInteractiveConfig)) {\n    if (force) {\n      optionalFields = [...optionalInteractiveConfig];\n    } else {\n      optionalFields = optionalInteractiveConfig.filter((name) => result[name] === undefined);\n    }\n  }\n\n  // Show multiselect for optional fields, then prompt selected ones\n  if (optionalFields.length > 0) {\n    const selected = (await runtime.prompt({\n      name: '_optionalFields',\n      message: 'Would you also like to configure:',\n      type: 'multiselect',\n      choices: optionalFields.map((f) => {\n        const label = fieldDescriptions[f] || jsonProperties[f]?.description || f;\n        const currentValue = result[f];\n        // When forced, show current value next to the label for fields that already have values\n        const displayLabel = force && currentValue !== undefined ? `${label} (current: ${currentValue})` : label;\n        return { label: displayLabel, value: f };\n      }),\n    })) as string[];\n\n    if (Array.isArray(selected)) {\n      for (const field of selected) {\n        const config = detectPromptConfig(field, jsonProperties[field], fieldDescriptions[field]);\n        // When forced, use the current value as the default\n        if (force && result[field] !== undefined) {\n          config.default = result[field];\n        }\n        result[field] = await promptWithValidation(field, config, result, command, runtime);\n      }\n    }\n  }\n\n  return result;\n}\n"],"mappings":"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"}