skills/fabioc-aloha/lithium/VS Code Configuration Validation

VS Code Configuration Validation

SKILL.md

VS Code Extension Configuration Validation

Domain: VS Code extension development, configuration management, quality assurance
Complexity: Intermediate
Prerequisites: Understanding of VS Code extension manifest (package.json), TypeScript

Problem

VS Code extensions fail at runtime when:

  • Configuration keys are updated without being registered in package.json
  • Commands are invoked but not declared in manifest
  • Views/webviews reference unregistered IDs
  • Context keys are set but not documented

These misconfigurations don't cause compile-time errors and only surface when users interact with specific features.

Solution

Systematic validation of VS Code extension manifest against runtime code usage.

1. Configuration Registration Validation

Check: All workspace.getConfiguration().update() calls reference registered properties.

// ❌ WRONG - config key not registered
await vscode.workspace.getConfiguration('alex.skillRecommendations')
  .update('code-review.accepted', count + 1, ConfigurationTarget.Global);

// ✅ RIGHT - key registered in package.json or wrapped in try-catch
try {
  await vscode.workspace.getConfiguration('alex.skillRecommendations')
    .update('code-review.accepted', count + 1, ConfigurationTarget.Global);
} catch (error) {
  console.log(`Skip tracking: ${error}`);
}

Audit Pattern:

# Find all config.update() calls
grep -r "getConfiguration.*\.update\(" src/

# Cross-reference with package.json properties section
# Each update() key must exist in "configuration.properties"

2. Command Registration Validation

Check: All commands.registerCommand() calls match declared commands in manifest.

// Code registration
vscode.commands.registerCommand('alex.validateHeir', async () => {...});

// Must have package.json declaration
{
  "contributes": {
    "commands": [{
      "command": "alex.validateHeir",
      "title": "Validate as Heir Project"
    }]
  }
}

Audit Pattern:

# Find all command registrations
grep -r "registerCommand\(['\"]alex\." src/

# Extract command names and verify each exists in package.json

3. Configuration Read Validation

Check: All getConfiguration().get() calls match registered properties.

// This config read should have a registered property
const enabled = vscode.workspace.getConfiguration('alex.voice').get('enabled', false);

// Check package.json has "alex.voice.enabled"

Warning Pattern: Configuration reads with no defaults are risky:

// ⚠️ No fallback - will be undefined if not registered
const value = config.get('someKey');

// ✅ Better - always provide default
const value = config.get('someKey', defaultValue);

4. Error Handling Patterns

For Dynamic Configuration Keys (skill recommendations, user preferences):

Option A: Register schema with dynamic pattern (complex) Option B: Graceful try-catch (simple, recommended)

// Pattern: Non-critical dynamic config
async function trackUserPreference(key: string, value: any) {
  try {
    await vscode.workspace.getConfiguration('alex.dynamic')
      .update(key, value, ConfigurationTarget.Global);
  } catch (error) {
    // Log but don't fail - tracking is optional
    console.log(`[Alex] Skipping preference tracking: ${error}`);
  }
}

For Critical Configuration:

// Pattern: Essential config must be registered
await vscode.workspace.getConfiguration('alex.globalKnowledge')
  .update('remoteRepo', repo, ConfigurationTarget.Global);
// No try-catch - failure should bubble up

Validation Checklist

Pre-Publish Review

  • Search code for getConfiguration().update() calls
  • Verify each updated key exists in package.json properties OR has try-catch
  • Search for registerCommand() calls
  • Verify each command exists in contributes.commands
  • Check for dynamic config patterns (user tracking, etc.)
  • Apply graceful degradation pattern for non-critical features

Automated Audit Script

Create scripts/validate-manifest.ps1:

# Find all config updates
$updates = Select-String -Path "src/**/*.ts" -Pattern "getConfiguration\(['\"]([^'\"]+)['\"].*\.update\(['\"]([^'\"]+)"

# Load package.json properties
$manifest = Get-Content "package.json" | ConvertFrom-Json
$registered = $manifest.contributes.configuration.properties.PSObject.Properties.Name

# Check each update
$issues = @()
foreach ($match in $updates) {
  $context = $match.Matches.Groups[1].Value
  $key = $match.Matches.Groups[2].Value
  $fullKey = "$context.$key"
  
  if ($registered -notcontains $fullKey) {
    # Check if wrapped in try-catch (manual review needed)
    $issues += "⚠️  $fullKey - not registered (verify try-catch exists)"
  }
}

if ($issues.Count -gt 0) {
  Write-Host "Configuration validation issues:" -ForegroundColor Yellow
  $issues | ForEach-Object { Write-Host $_ }
  exit 1
}

Common Pitfalls

  1. Dynamic Configuration Keys: User preferences, tracking counters

    • Solution: Either register dynamic schema or use try-catch pattern
  2. Namespaced Configuration: alex.skill.subkey.value

    • Solution: Register full dotted path: "alex.skill.subkey.value": {...}
  3. Multi-Target Updates: Workspace vs Global vs WorkspaceFolder

    • Solution: Test configuration across all scopes
  4. Configuration Migration: Deprecated settings

    • Solution: Use deprecationMessage in property definition

Real-World Example: Skill Recommendations

Problem: Tracking skill usage without bloating package.json with hundreds of dynamic keys.

Solution: Graceful degradation pattern

async function trackRecommendation(skillId: string, accepted: boolean) {
  try {
    const context = 'alex.skillRecommendations';
    const key = `${skillId}.${accepted ? 'accepted' : 'dismissed'}`;
    const current = vscode.workspace.getConfiguration(context).get<number>(key, 0);
    await vscode.workspace.getConfiguration(context).update(
      key, 
      current + 1, 
      vscode.ConfigurationTarget.Global
    );
  } catch (error) {
    // Feature degrades gracefully - recommendations still work
    console.log(`[Alex] Skipping recommendation tracking: ${error}`);
  }
}

Why This Works:

  • Feature works with or without tracking
  • No user-facing error for unregistered config
  • Logging helps debug if tracking is important
  • Simple implementation vs complex dynamic schema

Integration with Existing QA

Add to .github/instructions/extension-audit-methodology.instructions.md:

### Configuration Validation

Before each release:
1. Run `scripts/validate-manifest.ps1`
2. Review any warnings for try-catch coverage
3. Test configuration updates in clean VS Code instance
4. Verify error messages are user-friendly

Resources


Sources of Truth:

  • Incident: Skill recommendations broken due to unregistered config (2026-02-15)
  • Root Cause: alex.skillRecommendations.* keys not in package.json
  • Fix: Try-catch wrapper in src/chat/skillRecommendations.ts
Weekly Installs
0
First Seen
Jan 1, 1970