Skill: clulessboy/ds160-autofill (version 1.0.0)

--- name: ds160-autofill description: Automate filling of US nonimmigrant visa DS-160 forms using CDP for element location, CSV data source for user information, LLM assistance for complex cases (captcha, missing elements), and session persistence for resume capability. Use when user needs to: (1) Fill DS-160 visa application forms automatically, (2) Resume filling an interrupted DS-160 application, (3) Handle captcha and complex form elements with LLM assistance. Supports Chinese input with automatic translation to English. --- # DS-160 Auto-fill Skill This skill automates the filling of US nonimmigrant visa DS-160 forms by combining: - CDP (Chrome DevTools Protocol) for fast element location - CSV data source for user information - LLM assistance for complex cases (captcha, missing elements) - Session persistence for resume capability - Chinese to English translation for user input ## Quick Start ### Starting a New Application 1. **Provide CSV data**: User must provide a CSV file with their personal information (use `ds160-user-info.csv` as template) 2. **Open DS-160 website**: Use `browser` tool to open `https://ceac.state.gov/genniv/` with profile `openclaw` 3. **Initialize session**: Load and execute `scripts/ds160-filler.js` to parse mappings and CSV 4. **Start filling**: Begin with the home page, handle captcha with LLM, then proceed page by page ### Resuming an Application 1. **Load existing session**: Check `ds160/ds160-session.json` for saved Application ID 2. **Open application**: Use the saved Application ID to resume on DS-160 website 3. **Continue filling**: Load CSV from saved location and continue from last page ## Core Workflow ### Step 1: Prepare Data **Always check if session exists first:** ```javascript // Read ds160/ds160-session.json // If exists → Resume mode // If not → New application mode ``` **New application mode:** - Ask user for CSV file path or content - Save CSV to `ds160/ds160-user-info.csv` using `write` tool - Initialize session data in `ds160/ds160-session.json`: ```json { "applicationId": null, "securityQuestion": null, "securityAnswer": null, "currentPageIndex": 0, "completedPages": [], "startDate": "2026-02-06T21:00:00Z" } ``` **Resume mode:** - Load CSV from `ds160/ds160-user-info.csv` - Load session from `ds160/ds160-session.json` - Report current progress to user ### Step 2: Initialize Browser ```javascript // Open browser with openclaw profile browser_start: { profile: "openclaw", targetUrl: "https://ceac.state.gov/genniv/" } // For resume mode, add Application ID to URL // Example: https://ceac.state.gov/GenNIV/Common/ConfirmApplicationID.aspx ``` ### Step 3: Fill Current Page **For each page in sequence:** 1. **Snapshot page** to understand current state: ```javascript browser_snapshot: { refs: "role", profile: "openclaw" } ``` 2. **Load mappings** from `references/ds160-elements.yaml` 3. **Execute fill logic** using `browser act` with evaluate: ```javascript // Load ds160-filler.js // Call fillPage(page, currentUrl, userData, yamlData) ``` 4. **Handle results**: - **Success**: Continue to next page - **Needs LLM assistance**: Call LLM and retry - **Needs user input**: Save progress and pause ### Step 4: Handle Special Cases **Captcha:** - Take screenshot of captcha area - Use `image` tool to analyze captcha - Fill captcha code via browser evaluate **Missing element:** - Call LLM with page snapshot - Ask LLM to locate element and provide alternative selector - Retry fill operation **Translation needed:** - Call LLM with field context and Chinese value - Ask LLM to translate to appropriate English value - Update CSV and retry fill operation **Missing user data:** - Identify which field is missing - Report to user with field name and description - **Important**: Save current page using browser evaluate before pausing - Wait for user to provide data ### Step 5: Save Progress & Continue **After completing a page:** 1. **Update session data**: ```json { "applicationId": "AA00FBLCQP", "securityQuestion": "What is the given name of your mother's mother?", "securityAnswer": "LiMei", "currentPageIndex": 5, "completedPages": ["home", "security_question", "personal_1", "personal_2"], "startDate": "2026-02-06T21:00:00Z" } ``` 2. **Save to file**: `write(ds160/ds160-session.json, JSON.stringify(sessionData))` 3. **Report progress to user**: - Current page completed - Next page name - Application ID - Security question/answer (first time only) - Overall progress (X/Y pages) 4. **Click "Continue" button** to proceed to next page ## Data Structures ### CSV Format The CSV must have these columns: 1. `页面` - Page name 2. `字段名称` - Field identifier (matches YAML `name` field) 3. `英文说明` - English description 4. `中文说明` - Chinese description 5. `必填` - Required? (是/否) 6. `示例值` - Example value 7. `用户填写` - **User-provided value** (this is what gets filled) **Important**: Users can provide values in Chinese. The script includes a built-in translation dictionary for common fields (gender, marital status, countries, etc.). For fields not in the dictionary, LLM will be called for translation automatically. ### YAML Structure Each page in `ds160-elements.yaml` contains: - `page_id`: Unique page identifier - `page_name`: Human-readable page name - `url`: Page URL pattern - `elements`: Array of form elements with: - `id`: Element ID - `name`: Field identifier (matches CSV) - `type`: Element type (text, select, radio, checkbox, button) - `label`: English label - `label_cn`: Chinese label - `required`: Is required? - `options`: Available options (for select) - `group`: Radio group name ## Error Handling ### Element Not Found **Symptoms**: `fillPage` returns `needsLLM: true` **Action**: 1. Take page snapshot 2. Call LLM with: - Current URL - Element information (id, name, type) - Page HTML snippet - Ask LLM to analyze and provide alternative selector 3. Retry with LLM-suggested selector ### Translation Needed **Symptoms**: `fillPage` returns `needsTranslation: true` **Action**: 1. Call LLM with translation context: - Field name and description (EN/CN) - Field type and available options - Original Chinese value - Ask LLM to translate to appropriate English value for the field 2. Update CSV with translated value 3. Retry fill operation with translated value **Example LLM prompt for translation**: ``` I need to translate this Chinese value for a DS-160 form field: Field: ${elementName} Type: ${elementType} English label: ${label} Chinese label: ${label_cn} Chinese value: "${originalValue}" Available options (if select): ${options} Please provide the correct English value for this field. Consider: - The field type and context - Available options (if applicable) - Standard DS-160 terminology Return only the English value, no explanation. ``` ### Data Missing **Symptoms**: `fillPage` returns `needsUserInput: true` **Action**: 1. **CRITICAL**: Save current page before pausing: ```javascript // Find and click "Save" button browser_act: { request: { kind: "click", ref: "save_button" } } ``` 2. Report missing field to user: - Field name (English and Chinese) - Description - Whether it's required 3. Update CSV with new data using `write` tool 4. Resume filling ### Captcha **Symptoms**: Captcha image detected on page **Action**: 1. Take screenshot of captcha area 2. Use `image` tool: ```javascript image: { image: "/path/to/captcha.png", prompt: "What is the code shown in this captcha? Return only the code characters." } ``` 3. Fill captcha field via browser evaluate 4. Submit form ## Page Sequence The pages are filled in this order: 1. **home** - Start application, select location, handle captcha 2. **security_question** - Confirm Application ID, set security question 3. **personal_1** - Personal information (name, gender, DOB) 4. **personal_2** - Nationality, other nationalities, IDs 5. **travel** - Travel purpose, dates, who is paying 6. **travel_companions** - People traveling with you 7. **previous_us_travel** - Previous US visits 8. **address_phone** - Current address and phone 9. **passport** - Passport information 10. **us_contact** - US point of contact 11. **family_relatives** - Family information 12. **work_education** - Work and education history 13. **security_background** - Security questions ## Progress Reporting **Report to user after each page:** ``` ✓ Completed: Personal Information 1 📄 Next: Personal Information 2 🆔 Application ID: AA00FBLCQP 🔐 Security Question: What is the given name of your mother's mother? 🔑 Answer: LiMei 📊 Progress: 3/13 pages completed ``` **Include in every report:** - Application ID (once obtained) - Security question and answer (once generated) - Current progress (X/Y pages) - Next page name ## LLM Integration ### When to Call LLM 1. **Captcha detection**: Always use LLM to read captcha 2. **Element not found**: When multiple locator strategies fail 3. **Translation needed**: When user provides Chinese value not in built-in dictionary 4. **Complex elements**: For elements that require understanding context 5. **Validation errors**: When form submission fails with unclear reason ### LLM Prompts **For element location:** ``` I need to find this form element on a DS-160 page: - Element ID: {elementId} - Field name: {fieldName} - Element type: {elementType} - Current URL: {url} Please analyze the page and provide: 1. The correct way to locate this element (CSS selector or JavaScript) 2. Any visible labels or text associated with it ``` **For captcha:** ``` Please read the captcha code from this image. Return only the code characters, no explanation. ``` ## Translation Dictionary The script includes a built-in translation dictionary for common Chinese values. This covers: **Gender**: - 男/男性 → MALE - 女/女性 → FEMALE **Marital Status**: - 已婚 → MARRIED - 未婚 → SINGLE - 离异 → DIVORCED - 丧偶 → WIDOWED - 合法分居 → LEGALLY SEPARATED - 事实婚姻 → COMMON LAW MARRIAGE - 民事结合 → CIVIL UNION/DOMESTIC PARTNERSHIP **Yes/No**: - 是/有/是，有 → Yes - 否/没有/否，没有 → No **Countries**: - 中国 → CHINA - 美国 → USA - 英国 → UNITED KINGDOM - 日本 → JAPAN - 韩国 → KOREA, SOUTH **Visa Types**: - 旅游/商务/商务/旅游 → B1/B2 - 学生 → F1 - 访问学者 → J1 - 工作 → H1B **Payment**: - 自己/自费 → SELF - 公司 → OTHER COMPANY - 其他人 → OTHER PERSON **Relationship (US Point of Contact)**: - 朋友 → Friend - 亲戚 → Relative - 同事 → Colleague - 配偶 → Spouse - 同学 → Classmate - 其他 → Other **Other Values**: - 不适用/不，不适用 → Does Not Apply **For values not in this dictionary**, LLM will be automatically called for translation. ## Session Persistence **Session file location**: `ds160/ds160-session.json` **Session data structure**: ```json { "applicationId": "AA00FBLCQP", "securityQuestion": "What is the given name of your mother's mother?", "securityAnswer": "LiMei", "currentPageIndex": 5, "completedPages": ["home", "security_question", "personal_1", "personal_2", "travel", "travel_companions"], "startDate": "2026-02-06T21:00:00Z", "lastUpdated": "2026-02-06T21:30:00Z" } ``` **When to save session:** - After completing each page - Before pausing for user input - After receiving Application ID - After setting security question/answer ## Browser Automation Notes **Always use `openclaw` profile** to maintain session across pages. **Use `browser act` with `evaluate` for form filling**: - More reliable than individual click/type actions - Can execute complex JavaScript - Better error handling **Use `browser snapshot` before each page**: - Check page state - Identify dynamic elements - Verify page loaded correctly ## Testing Checklist Before using this skill with real data: - [ ] Test element location on each page type - [ ] Verify CSV parsing with sample data - [ ] Test captcha handling with LLM - [ ] Verify session save/load functionality - [ ] Test resume from middle of application - [ ] Verify "Save" button clicking works before pauses - [ ] Test with various element types (text, select, radio, checkbox) - [ ] Verify progress reporting format - [ ] Test Chinese to English translation ## Example Usage **User says**: "Help me fill DS-160 form with my data in this.csv" **Agent workflow**: 1. Load SKILL.md (this file) 2. Check for existing session 3. Save CSV to ds160/ds160-user-info.csv 4. Initialize session 5. Open browser to DS-160 6. Fill page by page 7. Report progress after each page 8. Handle errors with LLM or user input 9. Save progress and continue **User says**: "Continue filling my DS-160 form" **Agent workflow**: 1. Load SKILL.md 2. Load existing session 3. Open browser to DS-160 with Application ID 4. Load CSV from saved location 5. Continue from last page 6. Report progress 7. Complete remaining pages ## Files Reference - **scripts/ds160-filler.js** - Core automation logic (run via browser evaluate) - **references/ds160-elements.yaml** - Element mappings (read-only) - **references/ds160-user-info.csv** - User data template (copy to workspace) - **ds160/ds160-session.json** - Session persistence (auto-created) - **ds160/ds160-user-info.csv** - Active user data (auto-created) ## Important Notes - **NEVER submit the final form** - this is for automation/testing only - **Always save before pausing** - prevents data loss - **Report progress frequently** - at least every page - **Keep Application ID secure** - it's sensitive information - **Use fake data for testing** - don't use real personal info - **Chinese input is supported** - use built-in dictionary or LLM for translation

path: scripts/ds160-filler.js
content: /**
 * DS-160 Auto-fill Script
 *
 * This script uses Chrome DevTools Protocol (CDP) to automate filling DS-160 visa forms.
 * It reads element mappings from YAML and user data from CSV.
 *
 * Note: Users may provide data in Chinese. This script includes a built-in translation
 * dictionary for common fields. For fields not in the dictionary, the script will
 * request LLM assistance for translation.
 */

const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');

// Configuration
const CONFIG = {
  workspaceDir: process.env.OPENCLAW_WORKSPACE || '/home/jasonzhao/.openclaw/workspace',
  dataDir: path.join(process.env.OPENCLAW_WORKSPACE || '/home/jasonzhao/.openclaw/workspace', 'ds160'),
  yamlFile: path.join(__dirname, '../references/ds160-elements.yaml'),
  csvFile: path.join(process.env.OPENCLAW_WORKSPACE || '/home/jasonzhao/.openclaw/workspace', 'ds160/ds160-user-info.csv'),
  sessionFile: path.join(process.env.OPENCLAW_WORKSPACE || '/home/jasonzhao/.openclaw/workspace', 'ds160/ds160-session.json')
};

// Global session data
let sessionData = {
  applicationId: null,
  securityQuestion: null,
  securityAnswer: null,
  currentPageIndex: 0,
  completedPages: [],
  startDate: null
};

/**
 * Chinese to English translation dictionary for common DS-160 fields
 */
const TRANSLATION_DICT = {
  // Gender
  '男': 'MALE',
  '女': 'FEMALE',
  '男性': 'MALE',
  '女性': 'FEMALE',

  // Marital Status
  '已婚': 'MARRIED',
  '未婚': 'SINGLE',
  '离异': 'DIVORCED',
  '丧偶': 'WIDOWED',
  '合法分居': 'LEGALLY SEPARATED',
  '事实婚姻': 'COMMON LAW MARRIAGE',
  '民事结合': 'CIVIL UNION/DOMESTIC PARTNERSHIP',

  // Yes/No
  '是': 'Yes',
  '否': 'No',
  '有': 'Yes',
  '没有': 'No',
  '是，有': 'Yes',
  '否，没有': 'No',

  // Common Countries
  '中国': 'CHINA',
  '美国': 'USA',
  '英国': 'UNITED KINGDOM',
  '日本': 'JAPAN',
  '韩国': 'KOREA, SOUTH',

  // Common Visa Types
  '旅游': 'B1/B2',
  '商务': 'B1/B2',
  '商务/旅游': 'B1/B2',
  '学生': 'F1',
  '访问学者': 'J1',
  '工作': 'H1B',

  // Payment
  '自己': 'SELF',
  '自费': 'SELF',
  '公司': 'OTHER COMPANY',
  '其他人': 'OTHER PERSON',

  // U.S. Point of Contact - Relationship
  '朋友': 'Friend',
  '亲戚': 'Relative',
  '同事': 'Colleague',
  '配偶': 'Spouse',
  '同学': 'Classmate',
  '其他': 'Other',

  // Other Names, Telecode, etc.
  '不适用': 'Does Not Apply',
  '不，不适用': 'Does Not Apply'
};

/**
 * Check if a string contains Chinese characters
 */
function hasChinese(str) {
  return /[\u4e00-\u9fa5]/.test(str);
}

/**
 * Translate Chinese value to English using dictionary or request LLM assistance
 */
function translateValue(value, elementName, elementInfo) {
  if (!value || !hasChinese(value)) {
    return { translated: false, value };
  }

  const trimmedValue = value.trim();

  // Check dictionary first
  if (TRANSLATION_DICT[trimmedValue]) {
    console.log(`✓ Translated "${trimmedValue}" → "${TRANSLATION_DICT[trimmedValue]}" (dict)`);
    return { translated: true, value: TRANSLATION_DICT[trimmedValue] };
  }

  // Not in dictionary - request LLM assistance
  return {
    translated: false,
    value: trimmedValue,
    needsTranslation: true,
    translationContext: {
      elementName,
      elementInfo: {
        label: elementInfo.label,
        label_cn: elementInfo.label_cn,
        type: elementInfo.type,
        options: elementInfo.options
      }
    }
  };
}

/**
 * Load session data from file
 */
function loadSession() {
  try {
    if (fs.existsSync(CONFIG.sessionFile)) {
      const data = fs.readFileSync(CONFIG.sessionFile, 'utf8');
      sessionData = JSON.parse(data);
      console.log('✓ Loaded session data:', JSON.stringify(sessionData, null, 2));
      return sessionData;
    }
  } catch (error) {
    console.log('No existing session found, starting fresh');
  }
  return null;
}

/**
 * Save session data to file
 */
function saveSession() {
  try {
    if (!fs.existsSync(CONFIG.dataDir)) {
      fs.mkdirSync(CONFIG.dataDir, { recursive: true });
    }
    fs.writeFileSync(CONFIG.sessionFile, JSON.stringify(sessionData, null, 2));
    console.log('✓ Session data saved');
  } catch (error) {
    console.error('✗ Failed to save session:', error.message);
  }
}

/**
 * Parse YAML element mapping file
 */
function parseYaml(yamlPath) {
  try {
    const fileContents = fs.readFileSync(yamlPath, 'utf8');
    const data = yaml.load(fileContents);
    console.log(`✓ Loaded ${data.pages.length} pages from YAML`);
    return data;
  } catch (error) {
    throw new Error(`Failed to parse YAML: ${error.message}`);
  }
}

/**
 * Parse CSV user data file
 */
function parseCSV(csvPath) {
  try {
    const fileContents = fs.readFileSync(csvPath, 'utf8');
    const lines = fileContents.trim().split('\n');
    const headers = lines[0].split(',').map(h => h.trim());

    const data = {};
    for (let i = 1; i < lines.length; i++) {
      const values = parseCSVLine(lines[i]);
      const page = values[0];
      const fieldName = values[1];
      const userValue = values[6] || ''; // User填写 column (index 6)

      if (fieldName && !data[fieldName]) {
        data[fieldName] = {
          page,
          value: userValue.trim(),
          description: values[2] || '',
          descriptionCn: values[3] || '',
          required: values[4] === '是',
          example: values[5] || ''
        };
      }
    }

    console.log(`✓ Loaded ${Object.keys(data).length} fields from CSV`);
    return data;
  } catch (error) {
    throw new Error(`Failed to parse CSV: ${error.message}`);
  }
}

/**
 * Parse a CSV line handling quoted values
 */
function parseCSVLine(line) {
  const result = [];
  let current = '';
  let inQuotes = false;

  for (let i = 0; i < line.length; i++) {
    const char = line[i];

    if (char === '"') {
      inQuotes = !inQuotes;
    } else if (char === ',' && !inQuotes) {
      result.push(current);
      current = '';
    } else {
      current += char;
    }
  }
  result.push(current);

  return result;
}

/**
 * Find current page from URL
 */
function findCurrentPage(pages, currentUrl) {
  for (const page of pages) {
    if (currentUrl.includes(page.url) || currentUrl.includes(page.page_id)) {
      return page;
    }
  }
  return null;
}

/**
 * Locate element using CDP
 */
async function locateElement(page, elementInfo) {
  const elementId = elementInfo.id;
  const elementType = elementInfo.type;
  const elementName = elementInfo.name;

  // Try multiple locator strategies
  const locators = [
    // Strategy 1: By ID
    `document.getElementById('${elementId}')`,
    // Strategy 2: By name
    `document.querySelector('[name="${elementName}"]')`,
    // Strategy 3: By selector
    `document.querySelector('#${elementId}')`
  ];

  for (const locator of locators) {
    try {
      const result = await page.evaluate(`!!(${locator})`);
      if (result) {
        console.log(`✓ Found element ${elementName} using: ${locator}`);
        return { found: true, locator, elementId };
      }
    } catch (error) {
      // Continue to next strategy
    }
  }

  console.log(`✗ Element ${elementName} (${elementId}) not found`);
  return { found: false, elementId, elementType, elementName, elementInfo };
}

/**
 * Fill form element
 */
async function fillElement(page, elementData, userData, currentUrl) {
  const { found, locator, elementId, elementType, elementName, elementInfo } = elementData;

  if (!found) {
    // Element not found - need LLM assistance
    return {
      success: false,
      needsLLM: true,
      message: `Element ${elementName} (${elementId}) not found on page`,
      elementId,
      elementType,
      elementInfo,
      currentUrl
    };
  }

  // Get user value
  const fieldValue = userData[elementName]?.value;

  if (!fieldValue && elementInfo.required) {
    // Data missing - need user input
    return {
      success: false,
      needsUserInput: true,
      message: `Missing data for required field: ${elementName} (${elementInfo.label_cn || elementInfo.label})`,
      elementId,
      elementType,
      elementName,
      elementInfo
    };
  }

  // Check if translation is needed
  const translationResult = translateValue(fieldValue, elementName, elementInfo);

  if (translationResult.needsTranslation) {
    // Need LLM assistance for translation
    return {
      success: false,
      needsTranslation: true,
      message: `Translation needed for field ${elementName}: "${translationResult.value}"`,
      elementId,
      elementType,
      elementName,
      elementInfo,
      originalValue: translationResult.value,
      translationContext: translationResult.translationContext
    };
  }

  const valueToFill = translationResult.value;

  try {
    let fillScript = '';

    switch (elementType) {
      case 'text':
      case 'textarea':
        fillScript = `
          const el = ${locator};
          if (el) {
            el.value = '${valueToFill}';
            el.dispatchEvent(new Event('input', { bubbles: true }));
            el.dispatchEvent(new Event('change', { bubbles: true }));
            true;
          } else {
            false;
          }
        `;
        break;

      case 'select':
        // Find option by text or value
        fillScript = `
          const el = ${locator};
          if (el) {
            const options = Array.from(el.options);
            let option = options.find(o => o.text === '${valueToFill}' || o.value === '${valueToFill}');
            if (!option) {
              option = options.find(o => o.text.includes('${valueToFill}') || o.value.includes('${valueToFill}'));
            }
            if (option) {
              el.value = option.value;
              el.dispatchEvent(new Event('change', { bubbles: true }));
              true;
            } else {
              false;
            }
          } else {
            false;
          }
        `;
        break;

      case 'checkbox':
        fillScript = `
          const el = ${locator};
          if (el) {
            const shouldBeChecked = '${valueToFill}'.toLowerCase() === 'true' || '${valueToFill}'.toLowerCase() === 'yes';
            if (el.checked !== shouldBeChecked) {
              el.click();
            }
            true;
          } else {
            false;
          }
        `;
        break;

      case 'radio':
        fillScript = `
          const el = ${locator};
          if (el) {
            const radios = document.querySelectorAll('[name="${elementName}"]');
            const radio = Array.from(radios).find(r => r.id === '${elementId}');
            if (radio) {
              radio.click();
              true;
            } else {
              false;
            }
          } else {
            false;
          }
        `;
        break;

      default:
        return {
          success: false,
          needsLLM: true,
          message: `Unsupported element type: ${elementType}`,
          elementId,
          elementType
        };
    }

    const result = await page.evaluate(fillScript);

    if (result) {
      const displayValue = translationResult.translated
        ? `${translationResult.value} (translated from: "${fieldValue}")`
        : valueToFill;
      console.log(`✓ Filled ${elementName}: ${displayValue}`);
      return { success: true, elementName, value: valueToFill, originalValue: fieldValue };
    } else {
      return {
        success: false,
        needsLLM: true,
        message: `Failed to fill ${elementName}`,
        elementId,
        elementType
      };
    }

  } catch (error) {
    return {
      success: false,
      needsLLM: true,
      message: `Error filling ${elementName}: ${error.message}`,
      elementId,
      elementType
    };
  }
}

/**
 * Handle captcha using LLM
 */
async function handleCaptcha(page, currentUrl) {
  console.log('🤖 Captcha detected - calling LLM for assistance');

  // This function should be called from the main skill
  // The skill will use the image tool to analyze the captcha
  return {
    needsCaptcha: true,
    message: 'Captcha detected. Please analyze the captcha image and provide the code.',
    currentUrl
  };
}

/**
 * Extract Application ID from page
 */
async function extractApplicationId(page) {
  try {
    // Try to find Application ID in various locations
    const selectors = [
      '//td[contains(text(), "Application ID")]/following-sibling::td',
      '//div[contains(text(), "Application ID")]',
      '//span[contains(text(), "Application ID")]'
    ];

    for (const selector of selectors) {
      try {
        const result = await page.evaluate(`
          (function() {
            const xpath = '${selector}';
            const result = document.evaluate(
              xpath,
              document,
              null,
              XPathResult.FIRST_ORDERED_NODE_TYPE,
              null
            );
            const node = result.singleNodeValue;
            return node ? node.textContent.trim() : null;
          })()
        `);

        if (result && result.match(/[A-Z0-9]{10}/)) {
          const match = result.match(/[A-Z0-9]{10}/);
          if (match) {
            console.log(`✓ Found Application ID: ${match[0]}`);
            return match[0];
          }
        }
      } catch (error) {
        // Continue to next selector
      }
    }

    return null;
  } catch (error) {
    console.log('Could not extract Application ID');
    return null;
  }
}

/**
 * Generate random security question and answer
 */
function generateSecurityQA() {
  const questions = [
    {
      value: '1',
      text: 'What is the given name of your mother\'s mother?',
      answer: 'LiMei'
    },
    {
      value: '2',
      text: 'What is the given name of your father\'s father?',
      answer: 'WangGang'
    },
    {
      value: '3',
      text: 'What is your maternal grandmother\'s maiden name?',
      answer: 'Chen'
    },
    {
      value: '4',
      text: 'What name did your family used to call you when you were a child?',
      answer: 'XiaoMing'
    },
    {
      value: '5',
      text: 'In what city did you meet your spouse/significant other?',
      answer: 'Beijing'
    }
  ];

  const selected = questions[Math.floor(Math.random() * questions.length)];
  return {
    question: selected.text,
    questionValue: selected.value,
    answer: selected.answer
  };
}

/**
 * Save CSV file to workspace
 */
function saveCSVFile(csvContent) {
  try {
    if (!fs.existsSync(CONFIG.dataDir)) {
      fs.mkdirSync(CONFIG.dataDir, { recursive: true });
    }
    fs.writeFileSync(CONFIG.csvFile, csvContent);
    console.log(`✓ CSV saved to ${CONFIG.csvFile}`);
    return CONFIG.csvFile;
  } catch (error) {
    throw new Error(`Failed to save CSV: ${error.message}`);
  }
}

/**
 * Main fill function
 */
async function fillPage(page, currentUrl, userData, yamlData) {
  console.log(`\n📄 Processing page: ${currentUrl}`);

  // Find current page in YAML
  const currentPage = findCurrentPage(yamlData.pages, currentUrl);

  if (!currentPage) {
    console.log(`⚠️  Page not found in mapping: ${currentUrl}`);
    return {
      success: false,
      message: `Page not found in mapping`,
      currentUrl
    };
  }

  console.log(`✓ Found page mapping: ${currentPage.page_name}`);

  // Check for captcha
  if (currentPage.page_id === 'home') {
    const captchaResult = await handleCaptcha(page, currentUrl);
    if (captchaResult.needsCaptcha) {
      return captchaResult;
    }
  }

  const results = [];
  let needsSave = false;

  // Process each element
  for (const element of currentPage.elements) {
    // Skip buttons (will be handled at the end)
    if (element.type === 'button') {
      continue;
    }

    // Skip captcha text field (will be handled by LLM)
    if (element.name === 'captcha') {
      continue;
    }

    // Locate element
    const elementData = await locateElement(page, element);

    // Fill element
    const fillResult = await fillElement(page, elementData, userData, currentUrl);
    results.push(fillResult);

    // Check if we need to pause
    if (fillResult.needsUserInput) {
      console.log(`\n⚠️  PAUSE NEEDED: ${fillResult.message}`);
      needsSave = true;
      break;
    }

    if (fillResult.needsLLM) {
      console.log(`\n⤵️  LLM ASSISTANCE NEEDED: ${fillResult.message}`);
      return {
        needsLLM: true,
        message: fillResult.message,
        elementInfo: fillResult,
        results,
        needsSave
      };
    }
  }

  // Check if we need to save current progress
  if (needsSave) {
    return {
      needsUserInput: true,
      message: results.find(r => r.needsUserInput)?.message,
      results,
      needsSave: true,
      currentPage: currentPage.page_name
    };
  }

  return {
    success: true,
    currentPage: currentPage.page_name,
    completedElements: results.filter(r => r.success).length,
    totalElements: results.length
  };
}

/**
 * Get progress report
 */
function getProgressReport(yamlData) {
  const totalPages = yamlData.pages.length;
  const completedPages = sessionData.completedPages.length;

  return {
    applicationId: sessionData.applicationId,
    securityQuestion: sessionData.securityQuestion,
    securityAnswer: sessionData.securityAnswer,
    progress: `${completedPages}/${totalPages} pages completed`,
    completedPages: sessionData.completedPages,
    startDate: sessionData.startDate
  };
}

// Export functions for use in OpenClaw skill
module.exports = {
  parseYaml,
  parseCSV,
  fillPage,
  loadSession,
  saveSession,
  extractApplicationId,
  generateSecurityQA,
  saveCSVFile,
  getProgressReport,
  CONFIG
};


path: references/ds160-elements.yaml
content: # DS-160 表单元素映射文件
# 用于自动化填写美国非移民签证申请表
# 生成日期: 2026-02-06
# 领事馆: CHINA, BEIJING

pages:
  # ==================== 第0页: 首页/开始申请 ====================
  - page_id: "home"
    page_name: "首页 - 开始申请"
    url: "https://ceac.state.gov/genniv/"
    elements:
      - id: [REDACTED_SECRET]
        name: "location"
        type: "select"
        label: "Select a location where you will be applying for this visa"
        label_cn: "选择签证申请地点"
        required: true
        options_note: "选择领事馆，如 CHINA, BEIJING"
      
      - id: [REDACTED_SECRET]
        name: "captcha"
        type: "text"
        label: "Enter the code as shown"
        label_cn: "验证码"
        required: true
        note: "需要图像识别"
      
      - id: [REDACTED_SECRET]
        name: "start_application"
        type: "button"
        label: "START AN APPLICATION"
        label_cn: "开始新申请"

  # ==================== 第1页: 确认申请ID/安全问题 ====================
  - page_id: "security_question"
    page_name: "确认申请ID - 安全问题"
    url: "https://ceac.state.gov/GenNIV/Common/ConfirmApplicationID.aspx"
    elements:
      - id: [REDACTED_SECRET]
        name: "agree_privacy"
        type: "checkbox"
        label: "I AGREE"
        label_cn: "同意隐私条款"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "security_question"
        type: "select"
        label: "Security Question"
        label_cn: "安全问题"
        required: true
        options:
          - value: "1"
            text: "What is the given name of your mother's mother?"
            text_cn: "你外婆的名字是什么？"
          - value: "2"
            text: "What is the given name of your father's father?"
            text_cn: "你爷爷的名字是什么？"
          - value: "3"
            text: "What is your maternal grandmother's maiden name?"
            text_cn: "你外婆的娘家姓是什么？"
          - value: "4"
            text: "What name did your family used to call you when you were a child?"
            text_cn: "小时候家人怎么叫你？"
          - value: "5"
            text: "In what city did you meet your spouse/significant other?"
            text_cn: "你在哪个城市认识你的配偶/伴侣？"
      
      - id: [REDACTED_SECRET]
        name: "security_answer"
        type: "text"
        label: "Answer"
        label_cn: "安全问题答案"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "continue"
        type: "button"
        label: "Continue"

  # ==================== 第2页: Personal Information 1 ====================
  - page_id: "personal_1"
    page_name: "个人信息 1"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_personal.aspx?node=Personal1"
    elements:
      - id: [REDACTED_SECRET]
        name: "surname"
        type: "text"
        label: "Surnames"
        label_cn: "姓氏"
        required: true
        note: "与护照一致，全大写"
        example: "ZHANG"
      
      - id: [REDACTED_SECRET]
        name: "given_name"
        type: "text"
        label: "Given Names"
        label_cn: "名字"
        required: true
        note: "与护照一致，全大写"
        example: "XIAOMING"
      
      - id: [REDACTED_SECRET]
        name: "full_name_native"
        type: "text"
        label: "Full Name in Native Alphabet"
        label_cn: "母语全名（中文名）"
        required: false
        example: "张小明"
      
      - id: [REDACTED_SECRET]
        name: "full_name_native_na"
        type: "checkbox"
        label: "Does Not Apply/Technology Not Available"
        label_cn: "不适用"
      
      - id: [REDACTED_SECRET]
        name: "other_names_yes"
        type: "radio"
        label: "Have you ever used other names - Yes"
        label_cn: "是否曾用其他名字 - 是"
        group: "other_names"
      
      - id: [REDACTED_SECRET]
        name: "other_names_no"
        type: "radio"
        label: "Have you ever used other names - No"
        label_cn: "是否曾用其他名字 - 否"
        group: "other_names"
      
      - id: [REDACTED_SECRET]
        name: "telecode_yes"
        type: "radio"
        label: "Do you have a telecode - Yes"
        label_cn: "是否有电码 - 是"
        group: "telecode"
      
      - id: [REDACTED_SECRET]
        name: "telecode_no"
        type: "radio"
        label: "Do you have a telecode - No"
        label_cn: "是否有电码 - 否"
        group: "telecode"
      
      - id: [REDACTED_SECRET]
        name: "sex"
        type: "select"
        label: "Sex"
        label_cn: "性别"
        required: true
        options:
          - value: "M"
            text: "MALE"
            text_cn: "男"
          - value: "F"
            text: "FEMALE"
            text_cn: "女"
      
      - id: [REDACTED_SECRET]
        name: "marital_status"
        type: "select"
        label: "Marital Status"
        label_cn: "婚姻状况"
        required: true
        options:
          - value: "M"
            text: "MARRIED"
            text_cn: "已婚"
          - value: "C"
            text: "COMMON LAW MARRIAGE"
            text_cn: "事实婚姻"
          - value: "P"
            text: "CIVIL UNION/DOMESTIC PARTNERSHIP"
            text_cn: "民事结合/同居伴侣"
          - value: "S"
            text: "SINGLE"
            text_cn: "未婚"
          - value: "W"
            text: "WIDOWED"
            text_cn: "丧偶"
          - value: "D"
            text: "DIVORCED"
            text_cn: "离异"
          - value: "L"
            text: "LEGALLY SEPARATED"
            text_cn: "合法分居"
          - value: "O"
            text: "OTHER"
            text_cn: "其他"
      
      - id: [REDACTED_SECRET]
        name: "dob_day"
        type: "select"
        label: "Date of Birth - Day"
        label_cn: "出生日期 - 日"
        required: true
        options_note: "01-31"
      
      - id: [REDACTED_SECRET]
        name: "dob_month"
        type: "select"
        label: "Date of Birth - Month"
        label_cn: "出生日期 - 月"
        required: true
        options_note: "JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC"
      
      - id: [REDACTED_SECRET]
        name: "dob_year"
        type: "text"
        label: "Date of Birth - Year"
        label_cn: "出生日期 - 年"
        required: true
        example: "1990"
      
      - id: [REDACTED_SECRET]
        name: "pob_city"
        type: "text"
        label: "City of Birth"
        label_cn: "出生城市"
        required: true
        example: "Beijing"
      
      - id: [REDACTED_SECRET]
        name: "pob_state"
        type: "text"
        label: "State/Province of Birth"
        label_cn: "出生省份/州"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "pob_state_na"
        type: "checkbox"
        label: "State/Province - Does Not Apply"
        label_cn: "省份 - 不适用"
      
      - id: [REDACTED_SECRET]
        name: "pob_country"
        type: "select"
        label: "Country/Region of Birth"
        label_cn: "出生国家/地区"
        required: true
        options_note: "选择国家代码，中国为 CHIN"
    
    navigation:
      - id: [REDACTED_SECRET]
        name: "back"
        label: "Back: Getting Started"
      - id: [REDACTED_SECRET]
        name: "save"
        label: "Save"
      - id: [REDACTED_SECRET]
        name: "next"
        label: "Next: Personal 2"

  # ==================== 第3页: Personal Information 2 ====================
  - page_id: "personal_2"
    page_name: "个人信息 2"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_personalcont.aspx?node=Personal2"
    elements:
      - id: [REDACTED_SECRET]
        name: "nationality"
        type: "select"
        label: "Country/Region of Origin (Nationality)"
        label_cn: "国籍"
        required: true
        options_note: "选择国家代码，中国为 CHIN"
      
      - id: [REDACTED_SECRET]
        name: "other_nationality_yes"
        type: "radio"
        label: "Do you hold any other nationality - Yes"
        label_cn: "是否持有其他国籍 - 是"
        group: "other_nationality"
      
      - id: [REDACTED_SECRET]
        name: "other_nationality_no"
        type: "radio"
        label: "Do you hold any other nationality - No"
        label_cn: "是否持有其他国籍 - 否"
        group: "other_nationality"
      
      - id: [REDACTED_SECRET]
        name: "perm_resident_other_yes"
        type: "radio"
        label: "Are you a permanent resident of another country - Yes"
        label_cn: "是否为其他国家永久居民 - 是"
        group: "perm_resident"
      
      - id: [REDACTED_SECRET]
        name: "perm_resident_other_no"
        type: "radio"
        label: "Are you a permanent resident of another country - No"
        label_cn: "是否为其他国家永久居民 - 否"
        group: "perm_resident"
      
      - id: [REDACTED_SECRET]
        name: "national_id"
        type: "text"
        label: "National Identification Number"
        label_cn: "身份证号码"
        required: false
        example: "110101199001150123"
      
      - id: [REDACTED_SECRET]
        name: "national_id_na"
        type: "checkbox"
        label: "National ID - Does Not Apply"
        label_cn: "身份证号 - 不适用"
      
      - id: [REDACTED_SECRET]
        name: "ssn_part1"
        type: "text"
        label: "U.S. Social Security Number - Part 1 (3 digits)"
        label_cn: "美国社保号 - 第1部分"
        maxlength: 3
      
      - id: [REDACTED_SECRET]
        name: "ssn_part2"
        type: "text"
        label: "U.S. Social Security Number - Part 2 (2 digits)"
        label_cn: "美国社保号 - 第2部分"
        maxlength: 2
      
      - id: [REDACTED_SECRET]
        name: "ssn_part3"
        type: "text"
        label: "U.S. Social Security Number - Part 3 (4 digits)"
        label_cn: "美国社保号 - 第3部分"
        maxlength: 4
      
      - id: [REDACTED_SECRET]
        name: "ssn_na"
        type: "checkbox"
        label: "SSN - Does Not Apply"
        label_cn: "美国社保号 - 不适用"
      
      - id: [REDACTED_SECRET]
        name: "tax_id"
        type: "text"
        label: "U.S. Taxpayer ID Number"
        label_cn: "美国纳税人识别号"
      
      - id: [REDACTED_SECRET]
        name: "tax_id_na"
        type: "checkbox"
        label: "Tax ID - Does Not Apply"
        label_cn: "纳税人号 - 不适用"
    
    navigation:
      - id: [REDACTED_SECRET]
        name: "back"
        label: "Back: Personal 1"
      - id: [REDACTED_SECRET]
        name: "save"
        label: "Save"
      - id: [REDACTED_SECRET]
        name: "next"
        label: "Next: Travel"

  # ==================== 第4页: Travel Information ====================
  - page_id: "travel"
    page_name: "旅行信息"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_travel.aspx?node=Travel"
    elements:
      - id: [REDACTED_SECRET]
        name: "purpose_of_trip"
        type: "select"
        label: "Purpose of Trip to the U.S."
        label_cn: "赴美目的（签证类型）"
        required: true
        options_note: "选择签证类型，如 B - TEMP. BUSINESS OR PLEASURE VISITOR"
      
      - id: [REDACTED_SECRET]
        name: "specify_purpose"
        type: "select"
        label: "Specify"
        label_cn: "具体签证类别"
        required: true
        options:
          - value: "B1-B2"
            text: "BUSINESS OR TOURISM (TEMPORARY VISITOR) (B1/B2)"
            text_cn: "商务或旅游（临时访客）(B1/B2)"
          - value: "B1-CF"
            text: "BUSINESS/CONFERENCE (B1)"
            text_cn: "商务/会议 (B1)"
          - value: "B2-TM"
            text: "TOURISM/MEDICAL TREATMENT (B2)"
            text_cn: "旅游/医疗 (B2)"
      
      - id: [REDACTED_SECRET]
        name: "specific_travel_yes"
        type: "radio"
        label: "Have you made specific travel plans - Yes"
        label_cn: "是否有具体行程 - 是"
        group: "specific_travel"
      
      - id: [REDACTED_SECRET]
        name: "specific_travel_no"
        type: "radio"
        label: "Have you made specific travel plans - No"
        label_cn: "是否有具体行程 - 否"
        group: "specific_travel"
      
      - id: [REDACTED_SECRET]
        name: "arrival_day"
        type: "select"
        label: "Intended Date of Arrival - Day"
        label_cn: "预计到达日期 - 日"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "arrival_month"
        type: "select"
        label: "Intended Date of Arrival - Month"
        label_cn: "预计到达日期 - 月"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "arrival_year"
        type: "text"
        label: "Intended Date of Arrival - Year"
        label_cn: "预计到达日期 - 年"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "length_of_stay"
        type: "text"
        label: "Intended Length of Stay"
        label_cn: "预计停留时间"
        required: true
        example: "14"
      
      - id: [REDACTED_SECRET]
        name: "length_of_stay_unit"
        type: "select"
        label: "Length of Stay Unit"
        label_cn: "停留时间单位"
        required: true
        options_note: "DAY(S), WEEK(S), MONTH(S), YEAR(S)"
      
      - id: [REDACTED_SECRET]
        name: "us_address_line1"
        type: "text"
        label: "U.S. Street Address (Line 1)"
        label_cn: "美国住址第1行"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "us_address_line2"
        type: "text"
        label: "U.S. Street Address (Line 2)"
        label_cn: "美国住址第2行"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "us_city"
        type: "text"
        label: "City"
        label_cn: "美国城市"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "us_state"
        type: "select"
        label: "State"
        label_cn: "美国州"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "us_zip"
        type: "text"
        label: "ZIP Code"
        label_cn: "美国邮编"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "who_is_paying"
        type: "select"
        label: "Person/Entity Paying for Your Trip"
        label_cn: "行程费用支付方"
        required: true
        options:
          - value: "S"
            text: "SELF"
            text_cn: "本人"
          - value: "O"
            text: "OTHER PERSON"
            text_cn: "其他个人"
          - value: "P"
            text: "PRESENT EMPLOYER (US)"
            text_cn: "现雇主（美国）"
          - value: "U"
            text: "U.S. PETITIONER"
            text_cn: "美国申请人"
          - value: "C"
            text: "OTHER COMPANY/ORGANIZATION"
            text_cn: "其他公司/组织"
    
    navigation:
      - id: [REDACTED_SECRET]
        name: "next"
        label: "Next: Travel Companions"

  # ==================== 第5页: Travel Companions ====================
  - page_id: "travel_companions"
    page_name: "同行人信息"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_travelcompanions.aspx?node=TravelCompanions"
    elements:
      - id: [REDACTED_SECRET]
        name: "traveling_with_others_yes"
        type: "radio"
        label: "Are there other persons traveling with you - Yes"
        label_cn: "是否有同行人 - 是"
        group: "traveling_with_others"
      
      - id: [REDACTED_SECRET]
        name: "traveling_with_others_no"
        type: "radio"
        label: "Are there other persons traveling with you - No"
        label_cn: "是否有同行人 - 否"
        group: "traveling_with_others"
    
    conditional_elements:
      - condition: "traveling_with_others = yes"
        elements:
          - id: [REDACTED_SECRET]
            name: "group_travel_yes"
            type: "radio"
            label: "Are you traveling as part of a group or organization - Yes"
            label_cn: "是否随团旅行 - 是"
          - id: [REDACTED_SECRET]
            name: "group_travel_no"
            type: "radio"
            label: "Are you traveling as part of a group or organization - No"
            label_cn: "是否随团旅行 - 否"
    
    navigation:
      - id: [REDACTED_SECRET]
        name: "next"
        label: "Next: Previous U.S. Travel"

  # ==================== 第6页: Previous U.S. Travel ====================
  - page_id: "previous_us_travel"
    page_name: "以往美国旅行"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_previousustravel.aspx?node=PreviousUSTravel"
    elements:
      - id: [REDACTED_SECRET]
        name: "been_in_us_yes"
        type: "radio"
        label: "Have you ever been in the U.S. - Yes"
        label_cn: "是否曾去过美国 - 是"
        group: "been_in_us"
      
      - id: [REDACTED_SECRET]
        name: "been_in_us_no"
        type: "radio"
        label: "Have you ever been in the U.S. - No"
        label_cn: "是否曾去过美国 - 否"
        group: "been_in_us"
      
      - id: [REDACTED_SECRET]
        name: "had_us_visa_yes"
        type: "radio"
        label: "Have you ever been issued a U.S. Visa - Yes"
        label_cn: "是否曾获得美国签证 - 是"
        group: "had_us_visa"
      
      - id: [REDACTED_SECRET]
        name: "had_us_visa_no"
        type: "radio"
        label: "Have you ever been issued a U.S. Visa - No"
        label_cn: "是否曾获得美国签证 - 否"
        group: "had_us_visa"
      
      - id: [REDACTED_SECRET]
        name: "visa_refused_yes"
        type: "radio"
        label: "Have you ever been refused a U.S. Visa or admission - Yes"
        label_cn: "是否曾被拒签或拒绝入境 - 是"
        group: "visa_refused"
      
      - id: [REDACTED_SECRET]
        name: "visa_refused_no"
        type: "radio"
        label: "Have you ever been refused a U.S. Visa or admission - No"
        label_cn: "是否曾被拒签或拒绝入境 - 否"
        group: "visa_refused"
      
      - id: [REDACTED_SECRET]
        name: "immigrant_petition_yes"
        type: "radio"
        label: "Has anyone ever filed an immigrant petition on your behalf - Yes"
        label_cn: "是否有人为您提交过移民申请 - 是"
        group: "immigrant_petition"
      
      - id: [REDACTED_SECRET]
        name: "immigrant_petition_no"
        type: "radio"
        label: "Has anyone ever filed an immigrant petition on your behalf - No"
        label_cn: "是否有人为您提交过移民申请 - 否"
        group: "immigrant_petition"
    
    navigation:
      - id: [REDACTED_SECRET]
        name: "next"
        label: "Next: Address and Phone"

  # ==================== 第7页: Address and Phone ====================
  - page_id: "address_phone"
    page_name: "地址和电话"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_contact.aspx?node=AddressPhone"
    elements:
      # 家庭地址
      - id: [REDACTED_SECRET]
        name: "home_address_line1"
        type: "text"
        label: "Home Street Address (Line 1)"
        label_cn: "家庭地址第1行"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "home_address_line2"
        type: "text"
        label: "Home Street Address (Line 2)"
        label_cn: "家庭地址第2行"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "home_city"
        type: "text"
        label: "City"
        label_cn: "城市"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "home_state"
        type: "text"
        label: "State/Province"
        label_cn: "省份/州"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "home_state_na"
        type: "checkbox"
        label: "State/Province - Does Not Apply"
        label_cn: "省份 - 不适用"
      
      - id: [REDACTED_SECRET]
        name: "home_postal_code"
        type: "text"
        label: "Postal Zone/ZIP Code"
        label_cn: "邮编"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "home_postal_na"
        type: "checkbox"
        label: "Postal Code - Does Not Apply"
        label_cn: "邮编 - 不适用"
      
      - id: [REDACTED_SECRET]
        name: "home_country"
        type: "select"
        label: "Country/Region"
        label_cn: "国家/地区"
        required: true
      
      # 邮寄地址
      - id: [REDACTED_SECRET]
        name: "mailing_same_yes"
        type: "radio"
        label: "Is your Mailing Address the same as your Home Address - Yes"
        label_cn: "邮寄地址与家庭地址相同 - 是"
        group: "mailing_same"
      
      - id: [REDACTED_SECRET]
        name: "mailing_same_no"
        type: "radio"
        label: "Is your Mailing Address the same as your Home Address - No"
        label_cn: "邮寄地址与家庭地址相同 - 否"
        group: "mailing_same"
      
      # 电话
      - id: [REDACTED_SECRET]
        name: "primary_phone"
        type: "text"
        label: "Primary Phone Number"
        label_cn: "主要电话"
        required: true
        example: "13800138000"
      
      - id: [REDACTED_SECRET]
        name: "secondary_phone"
        type: "text"
        label: "Secondary Phone Number"
        label_cn: "备用电话"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "secondary_phone_na"
        type: "checkbox"
        label: "Secondary Phone - Does Not Apply"
        label_cn: "备用电话 - 不适用"
      
      - id: [REDACTED_SECRET]
        name: "work_phone"
        type: "text"
        label: "Work Phone Number"
        label_cn: "工作电话"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "work_phone_na"
        type: "checkbox"
        label: "Work Phone - Does Not Apply"
        label_cn: "工作电话 - 不适用"
      
      - id: [REDACTED_SECRET]
        name: "additional_phones_yes"
        type: "radio"
        label: "Have you used other phone numbers in the last 5 years - Yes"
        label_cn: "过去5年是否用过其他电话 - 是"
        group: "additional_phones"
      
      - id: [REDACTED_SECRET]
        name: "additional_phones_no"
        type: "radio"
        label: "Have you used other phone numbers in the last 5 years - No"
        label_cn: "过去5年是否用过其他电话 - 否"
        group: "additional_phones"
      
      # 邮箱
      - id: [REDACTED_SECRET]
        name: "email"
        type: "text"
        label: "Email Address"
        label_cn: "电子邮箱"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "additional_emails_yes"
        type: "radio"
        label: "Have you used other email addresses in the last 5 years - Yes"
        label_cn: "过去5年是否用过其他邮箱 - 是"
        group: "additional_emails"
      
      - id: [REDACTED_SECRET]
        name: "additional_emails_no"
        type: "radio"
        label: "Have you used other email addresses in the last 5 years - No"
        label_cn: "过去5年是否用过其他邮箱 - 否"
        group: "additional_emails"
      
      # 社交媒体
      - id: [REDACTED_SECRET]
        name: "social_media_platform"
        type: "select"
        label: "Social Media Provider/Platform"
        label_cn: "社交媒体平台"
        required: true
        options_note: "NONE, FACEBOOK, FLICKR, INSTAGRAM, LINKEDIN, REDDIT, TIKTOK, TUMBLR, TWITTER, WEIBO, YOUTUBE, 等"
      
      - id: [REDACTED_SECRET]
        name: "social_media_id"
        type: "text"
        label: "Social Media Identifier"
        label_cn: "社交媒体用户名"
        required: false
        note: "如选择 NONE 则不需要填写"
      
      - id: [REDACTED_SECRET]
        name: "additional_social_yes"
        type: "radio"
        label: "Do you wish to provide information about other websites - Yes"
        label_cn: "是否提供其他网站信息 - 是"
        group: "additional_social"
      
      - id: [REDACTED_SECRET]
        name: "additional_social_no"
        type: "radio"
        label: "Do you wish to provide information about other websites - No"
        label_cn: "是否提供其他网站信息 - 否"
        group: "additional_social"
    
    navigation:
      - id: [REDACTED_SECRET]
        name: "next"
        label: "Next: Passport"

  # ==================== 第8页: Passport ====================
  - page_id: "passport"
    page_name: "护照信息"
    url: "https://ceac.state.gov/GenNIV/General/complete/Passport_Visa_Info.aspx?node=PptVisa"
    elements:
      - id: [REDACTED_SECRET]
        name: "passport_type"
        type: "select"
        label: "Passport/Travel Document Type"
        label_cn: "护照/旅行证件类型"
        required: true
        options:
          - value: "R"
            text: "REGULAR"
            text_cn: "普通护照"
          - value: "O"
            text: "OFFICIAL"
            text_cn: "公务护照"
          - value: "D"
            text: "DIPLOMATIC"
            text_cn: "外交护照"
          - value: "L"
            text: "LAISSEZ-PASSER"
            text_cn: "通行证"
          - value: "T"
            text: "OTHER"
            text_cn: "其他"
      
      - id: [REDACTED_SECRET]
        name: "passport_number"
        type: "text"
        label: "Passport/Travel Document Number"
        label_cn: "护照号码"
        required: true
        example: "E12345678"
      
      - id: [REDACTED_SECRET]
        name: "passport_book_number"
        type: "text"
        label: "Passport Book Number"
        label_cn: "护照本编号"
        required: false
        note: "中国护照通常没有"
      
      - id: [REDACTED_SECRET]
        name: "passport_book_na"
        type: "checkbox"
        label: "Passport Book Number - Does Not Apply"
        label_cn: "护照本编号 - 不适用"
      
      - id: [REDACTED_SECRET]
        name: "passport_issued_country"
        type: "select"
        label: "Country/Authority that Issued Passport"
        label_cn: "护照签发国家/机构"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "passport_issued_city"
        type: "text"
        label: "City Where Passport was Issued"
        label_cn: "护照签发城市"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "passport_issued_state"
        type: "text"
        label: "State/Province Where Passport was Issued"
        label_cn: "护照签发省份"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "passport_issued_in_country"
        type: "select"
        label: "Country/Region Where Passport was Issued"
        label_cn: "护照签发国家"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "passport_issue_day"
        type: "select"
        label: "Issuance Date - Day"
        label_cn: "签发日期 - 日"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "passport_issue_month"
        type: "select"
        label: "Issuance Date - Month"
        label_cn: "签发日期 - 月"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "passport_issue_year"
        type: "text"
        label: "Issuance Date - Year"
        label_cn: "签发日期 - 年"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "passport_expire_day"
        type: "select"
        label: "Expiration Date - Day"
        label_cn: "到期日期 - 日"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "passport_expire_month"
        type: "select"
        label: "Expiration Date - Month"
        label_cn: "到期日期 - 月"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "passport_expire_year"
        type: "text"
        label: "Expiration Date - Year"
        label_cn: "到期日期 - 年"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "passport_no_expiration"
        type: "checkbox"
        label: "No Expiration"
        label_cn: "无到期日"
      
      - id: [REDACTED_SECRET]
        name: "lost_passport_yes"
        type: "radio"
        label: "Have you ever lost a passport or had one stolen - Yes"
        label_cn: "是否曾丢失或被盗护照 - 是"
        group: "lost_passport"
      
      - id: [REDACTED_SECRET]
        name: "lost_passport_no"
        type: "radio"
        label: "Have you ever lost a passport or had one stolen - No"
        label_cn: "是否曾丢失或被盗护照 - 否"
        group: "lost_passport"
    
    navigation:
      - id: [REDACTED_SECRET]
        name: "next"
        label: "Next: U.S. Contact"

  # ==================== 第9页: U.S. Contact ====================
  - page_id: "us_contact"
    page_name: "美国联系人"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_uscontact.aspx?node=USContact"
    elements:
      - id: [REDACTED_SECRET]
        name: "contact_surname"
        type: "text"
        label: "Contact Person Surnames"
        label_cn: "联系人姓氏"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "contact_given_name"
        type: "text"
        label: "Contact Person Given Names"
        label_cn: "联系人名字"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "contact_name_na"
        type: "checkbox"
        label: "Do Not Know"
        label_cn: "不知道"
        note: "如果不认识具体的人，可以填酒店名"
      
      - id: [REDACTED_SECRET]
        name: "contact_organization"
        type: "text"
        label: "Organization Name"
        label_cn: "组织/公司名称"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "contact_org_na"
        type: "checkbox"
        label: "Organization - Do Not Know"
        label_cn: "组织 - 不知道"
      
      - id: [REDACTED_SECRET]
        name: "contact_relationship"
        type: "select"
        label: "Relationship to You"
        label_cn: "与您的关系"
        required: true
        options:
          - value: "R"
            text: "RELATIVE"
            text_cn: "亲属"
          - value: "S"
            text: "SPOUSE"
            text_cn: "配偶"
          - value: "F"
            text: "FRIEND"
            text_cn: "朋友"
          - value: "B"
            text: "BUSINESS ASSOCIATE"
            text_cn: "商业伙伴"
          - value: "E"
            text: "EMPLOYER"
            text_cn: "雇主"
          - value: "H"
            text: "SCHOOL OFFICIAL"
            text_cn: "学校官员"
          - value: "O"
            text: "OTHER"
            text_cn: "其他"
      
      - id: [REDACTED_SECRET]
        name: "contact_address_line1"
        type: "text"
        label: "U.S. Street Address (Line 1)"
        label_cn: "美国地址第1行"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "contact_address_line2"
        type: "text"
        label: "U.S. Street Address (Line 2)"
        label_cn: "美国地址第2行"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "contact_city"
        type: "text"
        label: "City"
        label_cn: "城市"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "contact_state"
        type: "select"
        label: "State"
        label_cn: "州"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "contact_zip"
        type: "text"
        label: "ZIP Code"
        label_cn: "邮编"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "contact_phone"
        type: "text"
        label: "Phone Number"
        label_cn: "电话号码"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "contact_email"
        type: "text"
        label: "Email Address"
        label_cn: "电子邮箱"
        required: false
      
      - id: [REDACTED_SECRET]
        name: "contact_email_na"
        type: "checkbox"
        label: "Email - Does Not Apply"
        label_cn: "邮箱 - 不适用"
    
    navigation:
      - id: [REDACTED_SECRET]
        name: "next"
        label: "Next: Family"

  # ==================== 第10页: Family - Relatives ====================
  - page_id: "family_relatives"
    page_name: "家庭信息 - 亲属"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_family1.aspx?node=Relatives"
    elements:
      # 父亲信息
      - id: [REDACTED_SECRET]
        name: "father_surname"
        type: "text"
        label: "Father's Surnames"
        label_cn: "父亲姓氏"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "father_surname_unknown"
        type: "checkbox"
        label: "Do Not Know"
        label_cn: "不知道"
      
      - id: [REDACTED_SECRET]
        name: "father_given_name"
        type: "text"
        label: "Father's Given Names"
        label_cn: "父亲名字"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "father_given_name_unknown"
        type: "checkbox"
        label: "Do Not Know"
        label_cn: "不知道"
      
      - id: [REDACTED_SECRET]
        name: "father_dob_day"
        type: "select"
        label: "Father's Date of Birth - Day"
        label_cn: "父亲出生日期 - 日"
      
      - id: [REDACTED_SECRET]
        name: "father_dob_month"
        type: "select"
        label: "Father's Date of Birth - Month"
        label_cn: "父亲出生日期 - 月"
      
      - id: [REDACTED_SECRET]
        name: "father_dob_year"
        type: "text"
        label: "Father's Date of Birth - Year"
        label_cn: "父亲出生日期 - 年"
      
      - id: [REDACTED_SECRET]
        name: "father_dob_unknown"
        type: "checkbox"
        label: "Do Not Know"
        label_cn: "不知道"
      
      - id: [REDACTED_SECRET]
        name: "father_in_us_yes"
        type: "radio"
        label: "Is your father in the U.S. - Yes"
        label_cn: "父亲是否在美国 - 是"
        group: "father_in_us"
      
      - id: [REDACTED_SECRET]
        name: "father_in_us_no"
        type: "radio"
        label: "Is your father in the U.S. - No"
        label_cn: "父亲是否在美国 - 否"
        group: "father_in_us"
      
      # 母亲信息
      - id: [REDACTED_SECRET]
        name: "mother_surname"
        type: "text"
        label: "Mother's Surnames"
        label_cn: "母亲姓氏"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "mother_surname_unknown"
        type: "checkbox"
        label: "Do Not Know"
        label_cn: "不知道"
      
      - id: [REDACTED_SECRET]
        name: "mother_given_name"
        type: "text"
        label: "Mother's Given Names"
        label_cn: "母亲名字"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "mother_given_name_unknown"
        type: "checkbox"
        label: "Do Not Know"
        label_cn: "不知道"
      
      - id: [REDACTED_SECRET]
        name: "mother_dob_day"
        type: "select"
        label: "Mother's Date of Birth - Day"
        label_cn: "母亲出生日期 - 日"
      
      - id: [REDACTED_SECRET]
        name: "mother_dob_month"
        type: "select"
        label: "Mother's Date of Birth - Month"
        label_cn: "母亲出生日期 - 月"
      
      - id: [REDACTED_SECRET]
        name: "mother_dob_year"
        type: "text"
        label: "Mother's Date of Birth - Year"
        label_cn: "母亲出生日期 - 年"
      
      - id: [REDACTED_SECRET]
        name: "mother_dob_unknown"
        type: "checkbox"
        label: "Do Not Know"
        label_cn: "不知道"
      
      - id: [REDACTED_SECRET]
        name: "mother_in_us_yes"
        type: "radio"
        label: "Is your mother in the U.S. - Yes"
        label_cn: "母亲是否在美国 - 是"
        group: "mother_in_us"
      
      - id: [REDACTED_SECRET]
        name: "mother_in_us_no"
        type: "radio"
        label: "Is your mother in the U.S. - No"
        label_cn: "母亲是否在美国 - 否"
        group: "mother_in_us"
      
      # 其他亲属
      - id: [REDACTED_SECRET]
        name: "immediate_relatives_yes"
        type: "radio"
        label: "Do you have immediate relatives in the U.S. - Yes"
        label_cn: "是否有直系亲属在美国（不含父母） - 是"
        group: "immediate_relatives"
      
      - id: [REDACTED_SECRET]
        name: "immediate_relatives_no"
        type: "radio"
        label: "Do you have immediate relatives in the U.S. - No"
        label_cn: "是否有直系亲属在美国（不含父母） - 否"
        group: "immediate_relatives"
      
      - id: [REDACTED_SECRET]
        name: "other_relatives_yes"
        type: "radio"
        label: "Do you have other relatives in the U.S. - Yes"
        label_cn: "是否有其他亲属在美国 - 是"
        group: "other_relatives"
      
      - id: [REDACTED_SECRET]
        name: "other_relatives_no"
        type: "radio"
        label: "Do you have other relatives in the U.S. - No"
        label_cn: "是否有其他亲属在美国 - 否"
        group: "other_relatives"

  # ==================== 第11页: Work/Education - Present ====================
  - page_id: "work_education_present"
    page_name: "工作/教育 - 当前"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_workeducation1.aspx?node=WorkEducation1"
    elements:
      - id: [REDACTED_SECRET]
        name: "primary_occupation"
        type: "select"
        label: "Primary Occupation"
        label_cn: "主要职业"
        required: true
        options_note: "AGRICULTURE, ARTIST/PERFORMER, BUSINESS, COMMUNICATIONS, COMPUTER SCIENCE, EDUCATION, ENGINEERING, GOVERNMENT, HOMEMAKER, LEGAL, MEDICAL/HEALTH, MILITARY, NOT EMPLOYED, RETIRED, STUDENT, etc."
      
      - id: [REDACTED_SECRET]
        name: "employer_name"
        type: "text"
        label: "Employer/School Name"
        label_cn: "雇主/学校名称"
        required: true
        condition: "if employed or student"
      
      - id: [REDACTED_SECRET]
        name: "employer_address1"
        type: "text"
        label: "Employer/School Address Line 1"
        label_cn: "雇主/学校地址第1行"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "employer_address2"
        type: "text"
        label: "Employer/School Address Line 2"
        label_cn: "雇主/学校地址第2行"
      
      - id: [REDACTED_SECRET]
        name: "employer_city"
        type: "text"
        label: "City"
        label_cn: "城市"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "employer_state"
        type: "text"
        label: "State/Province"
        label_cn: "省份/州"
      
      - id: [REDACTED_SECRET]
        name: "employer_state_na"
        type: "checkbox"
        label: "Does Not Apply"
        label_cn: "不适用"
      
      - id: [REDACTED_SECRET]
        name: "employer_postal"
        type: "text"
        label: "Postal Code"
        label_cn: "邮编"
      
      - id: [REDACTED_SECRET]
        name: "employer_postal_na"
        type: "checkbox"
        label: "Does Not Apply"
        label_cn: "不适用"
      
      - id: [REDACTED_SECRET]
        name: "employer_phone"
        type: "text"
        label: "Phone Number"
        label_cn: "电话"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "employer_country"
        type: "select"
        label: "Country/Region"
        label_cn: "国家/地区"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "employment_start_day"
        type: "select"
        label: "Start Date - Day"
        label_cn: "开始日期 - 日"
      
      - id: [REDACTED_SECRET]
        name: "employment_start_month"
        type: "select"
        label: "Start Date - Month"
        label_cn: "开始日期 - 月"
      
      - id: [REDACTED_SECRET]
        name: "employment_start_year"
        type: "text"
        label: "Start Date - Year"
        label_cn: "开始日期 - 年"
      
      - id: [REDACTED_SECRET]
        name: "monthly_salary"
        type: "text"
        label: "Monthly Salary (local currency)"
        label_cn: "月薪（当地货币）"
      
      - id: [REDACTED_SECRET]
        name: "monthly_salary_na"
        type: "checkbox"
        label: "Does Not Apply"
        label_cn: "不适用"
      
      - id: [REDACTED_SECRET]
        name: "job_duties"
        type: "textarea"
        label: "Briefly describe your duties"
        label_cn: "简述工作职责"
        required: true

  # ==================== 第12页: Work/Education - Previous ====================
  - page_id: "work_education_previous"
    page_name: "工作/教育 - 以往"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_workeducation2.aspx?node=WorkEducation2"
    elements:
      - id: [REDACTED_SECRET]
        name: "previously_employed_yes"
        type: "radio"
        label: "Were you previously employed - Yes"
        label_cn: "是否曾就业 - 是"
        group: "previously_employed"
      
      - id: [REDACTED_SECRET]
        name: "previously_employed_no"
        type: "radio"
        label: "Were you previously employed - No"
        label_cn: "是否曾就业 - 否"
        group: "previously_employed"
      
      - id: [REDACTED_SECRET]
        name: "attended_school_yes"
        type: "radio"
        label: "Did you attend educational institutions - Yes"
        label_cn: "是否上过中学及以上学校 - 是"
        group: "attended_school"
      
      - id: [REDACTED_SECRET]
        name: "attended_school_no"
        type: "radio"
        label: "Did you attend educational institutions - No"
        label_cn: "是否上过中学及以上学校 - 否"
        group: "attended_school"

  # ==================== 第13页: Work/Education - Additional ====================
  - page_id: "work_education_additional"
    page_name: "工作/教育 - 附加信息"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_workeducation3.aspx?node=WorkEducation3"
    elements:
      - id: [REDACTED_SECRET]
        name: "clan_tribe_yes"
        type: "radio"
        label: "Do you belong to a clan or tribe - Yes"
        label_cn: "是否属于某个部落 - 是"
        group: "clan_tribe"
      
      - id: [REDACTED_SECRET]
        name: "clan_tribe_no"
        type: "radio"
        label: "Do you belong to a clan or tribe - No"
        label_cn: "是否属于某个部落 - 否"
        group: "clan_tribe"
      
      - id: [REDACTED_SECRET]
        name: "language"
        type: "text"
        label: "Languages you speak"
        label_cn: "会说的语言"
        required: true
      
      - id: [REDACTED_SECRET]
        name: "countries_visited_yes"
        type: "radio"
        label: "Have you traveled to other countries in the past 5 years - Yes"
        label_cn: "过去5年是否去过其他国家 - 是"
        group: "countries_visited"
      
      - id: [REDACTED_SECRET]
        name: "countries_visited_no"
        type: "radio"
        label: "Have you traveled to other countries in the past 5 years - No"
        label_cn: "过去5年是否去过其他国家 - 否"
        group: "countries_visited"
      
      - id: [REDACTED_SECRET]
        name: "organization_yes"
        type: "radio"
        label: "Do you belong to any professional organizations - Yes"
        label_cn: "是否属于专业组织 - 是"
        group: "organization"
      
      - id: [REDACTED_SECRET]
        name: "organization_no"
        type: "radio"
        label: "Do you belong to any professional organizations - No"
        label_cn: "是否属于专业组织 - 否"
        group: "organization"
      
      - id: [REDACTED_SECRET]
        name: "specialized_skills_yes"
        type: "radio"
        label: "Do you have specialized skills - Yes"
        label_cn: "是否有专业技能 - 是"
        group: "specialized_skills"
      
      - id: [REDACTED_SECRET]
        name: "specialized_skills_no"
        type: "radio"
        label: "Do you have specialized skills - No"
        label_cn: "是否有专业技能 - 否"
        group: "specialized_skills"
      
      - id: [REDACTED_SECRET]
        name: "military_service_yes"
        type: "radio"
        label: "Have you served in the military - Yes"
        label_cn: "是否曾服兵役 - 是"
        group: "military_service"
      
      - id: [REDACTED_SECRET]
        name: "military_service_no"
        type: "radio"
        label: "Have you served in the military - No"
        label_cn: "是否曾服兵役 - 否"
        group: "military_service"
      
      - id: [REDACTED_SECRET]
        name: "insurgent_org_yes"
        type: "radio"
        label: "Have you served in a paramilitary unit - Yes"
        label_cn: "是否曾在准军事组织服役 - 是"
        group: "insurgent_org"
      
      - id: [REDACTED_SECRET]
        name: "insurgent_org_no"
        type: "radio"
        label: "Have you served in a paramilitary unit - No"
        label_cn: "是否曾在准军事组织服役 - 否"
        group: "insurgent_org"

  # ==================== 第14-18页: Security and Background ====================
  - page_id: "security_background_1"
    page_name: "安全背景 - 第1部分（健康）"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_securityandbackground1.aspx"
    elements:
      - id: [REDACTED_SECRET]
        name: "disease_yes"
        type: "radio"
        label: "Do you have a communicable disease - Yes"
        label_cn: "是否有传染病 - 是"
      - id: [REDACTED_SECRET]
        name: "disease_no"
        type: "radio"
        label: "Do you have a communicable disease - No"
        label_cn: "是否有传染病 - 否"
      - id: [REDACTED_SECRET]
        name: "disorder_yes"
        type: "radio"
        label: "Do you have a mental/physical disorder - Yes"
        label_cn: "是否有精神/身体障碍 - 是"
      - id: [REDACTED_SECRET]
        name: "disorder_no"
        type: "radio"
        label: "Do you have a mental/physical disorder - No"
        label_cn: "是否有精神/身体障碍 - 否"
      - id: [REDACTED_SECRET]
        name: "druguser_yes"
        type: "radio"
        label: "Are you a drug abuser - Yes"
        label_cn: "是否吸毒 - 是"
      - id: [REDACTED_SECRET]
        name: "druguser_no"
        type: "radio"
        label: "Are you a drug abuser - No"
        label_cn: "是否吸毒 - 否"

  - page_id: "security_background_2"
    page_name: "安全背景 - 第2部分（犯罪）"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_securityandbackground2.aspx"
    elements:
      - id: [REDACTED_SECRET]
        name: "arrested_yes"
        type: "radio"
        label: "Have you been arrested - Yes"
        label_cn: "是否曾被逮捕 - 是"
      - id: [REDACTED_SECRET]
        name: "arrested_no"
        type: "radio"
        label: "Have you been arrested - No"
        label_cn: "是否曾被逮捕 - 否"
      - id: [REDACTED_SECRET]
        name: "controlled_substances_yes"
        type: "radio"
        label: "Have you violated controlled substance laws - Yes"
        label_cn: "是否违反受控物质法 - 是"
      - id: [REDACTED_SECRET]
        name: "controlled_substances_no"
        type: "radio"
        label: "Have you violated controlled substance laws - No"
        label_cn: "是否违反受控物质法 - 否"
      - id: [REDACTED_SECRET]
        name: "prostitution_yes"
        type: "radio"
        label: "Have you engaged in prostitution - Yes"
        label_cn: "是否从事卖淫 - 是"
      - id: [REDACTED_SECRET]
        name: "prostitution_no"
        type: "radio"
        label: "Have you engaged in prostitution - No"
        label_cn: "是否从事卖淫 - 否"
      - id: [REDACTED_SECRET]
        name: "money_laundering_yes"
        type: "radio"
        label: "Have you laundered money - Yes"
        label_cn: "是否洗钱 - 是"
      - id: [REDACTED_SECRET]
        name: "money_laundering_no"
        type: "radio"
        label: "Have you laundered money - No"
        label_cn: "是否洗钱 - 否"
      - id: [REDACTED_SECRET]
        name: "human_trafficking_yes"
        type: "radio"
        label: "Have you trafficked persons - Yes"
        label_cn: "是否贩卖人口 - 是"
      - id: [REDACTED_SECRET]
        name: "human_trafficking_no"
        type: "radio"
        label: "Have you trafficked persons - No"
        label_cn: "是否贩卖人口 - 否"

  - page_id: "security_background_3"
    page_name: "安全背景 - 第3部分（恐怖主义）"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_securityandbackground3.aspx"
    elements:
      - id: [REDACTED_SECRET]
        name: "illegal_activity_yes"
        type: "radio"
        label: "Do you seek to engage in illegal activity - Yes"
        label_cn: "是否打算从事非法活动 - 是"
      - id: [REDACTED_SECRET]
        name: "illegal_activity_no"
        type: "radio"
        label: "Do you seek to engage in illegal activity - No"
        label_cn: "是否打算从事非法活动 - 否"
      - id: [REDACTED_SECRET]
        name: "terrorist_activity_yes"
        type: "radio"
        label: "Have you engaged in terrorist activities - Yes"
        label_cn: "是否曾从事恐怖活动 - 是"
      - id: [REDACTED_SECRET]
        name: "terrorist_activity_no"
        type: "radio"
        label: "Have you engaged in terrorist activities - No"
        label_cn: "是否曾从事恐怖活动 - 否"
      - id: [REDACTED_SECRET]
        name: "terrorist_org_yes"
        type: "radio"
        label: "Are you a member of a terrorist organization - Yes"
        label_cn: "是否为恐怖组织成员 - 是"
      - id: [REDACTED_SECRET]
        name: "terrorist_org_no"
        type: "radio"
        label: "Are you a member of a terrorist organization - No"
        label_cn: "是否为恐怖组织成员 - 否"
      - id: [REDACTED_SECRET]
        name: "genocide_yes"
        type: "radio"
        label: "Have you committed genocide - Yes"
        label_cn: "是否犯有种族灭绝罪 - 是"
      - id: [REDACTED_SECRET]
        name: "genocide_no"
        type: "radio"
        label: "Have you committed genocide - No"
        label_cn: "是否犯有种族灭绝罪 - 否"
      - id: [REDACTED_SECRET]
        name: "torture_yes"
        type: "radio"
        label: "Have you committed torture - Yes"
        label_cn: "是否犯有酷刑罪 - 是"
      - id: [REDACTED_SECRET]
        name: "torture_no"
        type: "radio"
        label: "Have you committed torture - No"
        label_cn: "是否犯有酷刑罪 - 否"

  - page_id: "security_background_4"
    page_name: "安全背景 - 第4部分（移民欺诈）"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_securityandbackground4.aspx"
    elements:
      - id: [REDACTED_SECRET]
        name: "immigration_fraud_yes"
        type: "radio"
        label: "Have you committed immigration fraud - Yes"
        label_cn: "是否犯有移民欺诈 - 是"
      - id: [REDACTED_SECRET]
        name: "immigration_fraud_no"
        type: "radio"
        label: "Have you committed immigration fraud - No"
        label_cn: "是否犯有移民欺诈 - 否"
      - id: [REDACTED_SECRET]
        name: "deported_yes"
        type: "radio"
        label: "Have you been deported - Yes"
        label_cn: "是否曾被驱逐出境 - 是"
      - id: [REDACTED_SECRET]
        name: "deported_no"
        type: "radio"
        label: "Have you been deported - No"
        label_cn: "是否曾被驱逐出境 - 否"

  - page_id: "security_background_5"
    page_name: "安全背景 - 第5部分（其他）"
    url: "https://ceac.state.gov/GenNIV/General/complete/complete_securityandbackground5.aspx"
    elements:
      - id: [REDACTED_SECRET]
        name: "child_custody_yes"
        type: "radio"
        label: "Have you withheld custody of a child - Yes"
        label_cn: "是否曾拒绝交出孩子监护权 - 是"
      - id: [REDACTED_SECRET]
        name: "child_custody_no"
        type: "radio"
        label: "Have you withheld custody of a child - No"
        label_cn: "是否曾拒绝交出孩子监护权 - 否"
      - id: [REDACTED_SECRET]
        name: "voting_violation_yes"
        type: "radio"
        label: "Have you voted in violation of any law - Yes"
        label_cn: "是否非法投票 - 是"
      - id: [REDACTED_SECRET]
        name: "voting_violation_no"
        type: "radio"
        label: "Have you voted in violation of any law - No"
        label_cn: "是否非法投票 - 否"
      - id: [REDACTED_SECRET]
        name: "renounce_citizenship_yes"
        type: "radio"
        label: "Have you renounced U.S. citizenship - Yes"
        label_cn: "是否曾放弃美国公民身份 - 是"
      - id: [REDACTED_SECRET]
        name: "renounce_citizenship_no"
        type: "radio"
        label: "Have you renounced U.S. citizenship - No"
        label_cn: "是否曾放弃美国公民身份 - 否"

# 使用说明
# 1. 使用 JavaScript 通过 document.getElementById(id) 获取元素
# 2. 文本框使用 element.value = 'xxx' 填写
# 3. 下拉菜单使用 element.value = 'xxx' 并触发 change 事件
# 4. 单选按钮使用 element.click()
# 5. 复选框使用 element.click() 切换状态
# 6. 提交使用 button.click()
# 7. 日期下拉菜单的值通常是数字(1-31)或月份缩写(JAN, FEB等)


path: references/ds160-user-info.csv
content: 页面,字段名称,英文说明,中文说明,必填,示例值,用户填写
Personal 1,surname,Surnames (as in passport),姓氏（与护照一致，大写）,是,ZHANG,
Personal 1,given_name,Given Names (as in passport),名字（与护照一致，大写）,是,XIAOMING,
Personal 1,full_name_native,Full Name in Native Alphabet,中文全名,否,张小明,
Personal 1,other_names,Have you ever used other names?,是否曾用其他名字（曾用名、宗教名、艺名等）,是,No,
Personal 1,telecode,Do you have a telecode?,是否有电码,是,No,
Personal 1,sex,Sex,性别,是,MALE / FEMALE,
Personal 1,marital_status,Marital Status,婚姻状况,是,SINGLE / MARRIED / DIVORCED 等,
Personal 1,dob_day,Date of Birth - Day,出生日期 - 日,是,15,
Personal 1,dob_month,Date of Birth - Month,出生日期 - 月,是,MAY,
Personal 1,dob_year,Date of Birth - Year,出生日期 - 年,是,1990,
Personal 1,pob_city,City of Birth,出生城市,是,Beijing,
Personal 1,pob_state,State/Province of Birth,出生省份,否,留空勾选不适用,
Personal 1,pob_country,Country/Region of Birth,出生国家,是,CHINA,
Personal 2,nationality,Country/Region of Origin (Nationality),国籍,是,CHINA,
Personal 2,other_nationality,Do you hold any other nationality?,是否持有其他国籍,是,No,
Personal 2,perm_resident_other,Permanent resident of another country?,是否为其他国家永久居民,是,No,
Personal 2,national_id,National Identification Number,身份证号码（18位）,否,110101199001150123,
Personal 2,us_ssn,U.S. Social Security Number,美国社保号（如有）,否,留空勾选不适用,
Personal 2,us_tax_id,U.S. Taxpayer ID Number,美国纳税人号（如有）,否,留空勾选不适用,
Travel,purpose_of_trip,Purpose of Trip to the U.S.,赴美目的/签证类型,是,B1/B2 旅游商务,
Travel,specific_travel_plans,Have you made specific travel plans?,是否有具体行程安排,是,Yes / No,
Travel,who_is_paying,Person/Entity Paying for Your Trip,谁支付此次行程费用,是,SELF / OTHER PERSON / OTHER COMPANY,


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)