# Path Resolution API

This document describes the path resolution system used throughout the provisioning infrastructure for discovering configurations, extensions, and resolving workspace paths.

## Overview

The path resolution system provides a hierarchical and configurable mechanism for:

- Configuration file discovery and loading
- Extension discovery (providers, task services, clusters)
- Workspace and project path management
- Environment variable interpolation
- Cross-platform path handling

## Configuration Resolution Hierarchy

The system follows a specific hierarchy for loading configuration files:

```plaintext
1. System defaults      (config.defaults.toml)
2. User configuration   (config.user.toml)
3. Project configuration (config.project.toml)
4. Infrastructure config (infra/config.toml)
5. Environment config   (config.{env}.toml)
6. Runtime overrides    (CLI arguments, ENV vars)
```plaintext

### Configuration Search Paths

The system searches for configuration files in these locations:

```bash
# Default search paths (in order)
/usr/local/provisioning/config.defaults.toml
$HOME/.config/provisioning/config.user.toml
$PWD/config.project.toml
$PROVISIONING_KLOUD_PATH/config.infra.toml
$PWD/config.{PROVISIONING_ENV}.toml
```plaintext

## Path Resolution API

### Core Functions

#### `resolve-config-path(pattern: string, search_paths: list<string>) -> string`

Resolves configuration file paths using the search hierarchy.

**Parameters:**

- `pattern`: File pattern to search for (for example, "config.*.toml")
- `search_paths`: Additional paths to search (optional)

**Returns:**

- Full path to the first matching configuration file
- Empty string if no file found

**Example:**

```nushell
use path-resolution.nu *
let config_path = (resolve-config-path "config.user.toml" [])
# Returns: "/home/user/.config/provisioning/config.user.toml"
```plaintext

#### `resolve-extension-path(type: string, name: string) -> record`

Discovers extension paths (providers, taskservs, clusters).

**Parameters:**

- `type`: Extension type ("provider", "taskserv", "cluster")
- `name`: Extension name (for example, "upcloud", "kubernetes", "buildkit")

**Returns:**

```nushell
{
    base_path: "/usr/local/provisioning/providers/upcloud",
    schemas_path: "/usr/local/provisioning/providers/upcloud/schemas",
    nulib_path: "/usr/local/provisioning/providers/upcloud/nulib",
    templates_path: "/usr/local/provisioning/providers/upcloud/templates",
    exists: true
}
```plaintext

#### `resolve-workspace-paths() -> record`

Gets current workspace path configuration.

**Returns:**

```nushell
{
    base: "/usr/local/provisioning",
    current_infra: "/workspace/infra/production",
    kloud_path: "/workspace/kloud",
    providers: "/usr/local/provisioning/providers",
    taskservs: "/usr/local/provisioning/taskservs",
    clusters: "/usr/local/provisioning/cluster",
    extensions: "/workspace/extensions"
}
```plaintext

### Path Interpolation

The system supports variable interpolation in configuration paths:

#### Supported Variables

- `{{paths.base}}` - Base provisioning path
- `{{paths.kloud}}` - Current kloud path
- `{{env.HOME}}` - User home directory
- `{{env.PWD}}` - Current working directory
- `{{now.date}}` - Current date (YYYY-MM-DD)
- `{{now.time}}` - Current time (HH:MM:SS)
- `{{git.branch}}` - Current git branch
- `{{git.commit}}` - Current git commit hash

#### `interpolate-path(template: string, context: record) -> string`

Interpolates variables in path templates.

**Parameters:**

- `template`: Path template with variables
- `context`: Variable context record

**Example:**

```nushell
let template = "{{paths.base}}/infra/{{env.USER}}/{{git.branch}}"
let result = (interpolate-path $template {
    paths: { base: "/usr/local/provisioning" },
    env: { USER: "admin" },
    git: { branch: "main" }
})
# Returns: "/usr/local/provisioning/infra/admin/main"
```plaintext

## Extension Discovery API

### Provider Discovery

#### `discover-providers() -> list<record>`

Discovers all available providers.

**Returns:**

```nushell
[
    {
        name: "upcloud",
        path: "/usr/local/provisioning/providers/upcloud",
        type: "provider",
        version: "1.2.0",
        enabled: true,
        has_schemas: true,
        has_nulib: true,
        has_templates: true
    },
    {
        name: "aws",
        path: "/usr/local/provisioning/providers/aws",
        type: "provider",
        version: "2.1.0",
        enabled: true,
        has_schemas: true,
        has_nulib: true,
        has_templates: true
    }
]
```plaintext

#### `get-provider-config(name: string) -> record`

Gets provider-specific configuration and paths.

**Parameters:**

- `name`: Provider name

**Returns:**

```nushell
{
    name: "upcloud",
    base_path: "/usr/local/provisioning/providers/upcloud",
    config: {
        api_url: "https://api.upcloud.com/1.3",
        auth_method: "basic",
        interface: "API"
    },
    paths: {
        schemas: "/usr/local/provisioning/providers/upcloud/schemas",
        nulib: "/usr/local/provisioning/providers/upcloud/nulib",
        templates: "/usr/local/provisioning/providers/upcloud/templates"
    },
    metadata: {
        version: "1.2.0",
        description: "UpCloud provider for server provisioning"
    }
}
```plaintext

### Task Service Discovery

#### `discover-taskservs() -> list<record>`

Discovers all available task services.

**Returns:**

```nushell
[
    {
        name: "kubernetes",
        path: "/usr/local/provisioning/taskservs/kubernetes",
        type: "taskserv",
        category: "orchestration",
        version: "1.28.0",
        enabled: true
    },
    {
        name: "cilium",
        path: "/usr/local/provisioning/taskservs/cilium",
        type: "taskserv",
        category: "networking",
        version: "1.14.0",
        enabled: true
    }
]
```plaintext

#### `get-taskserv-config(name: string) -> record`

Gets task service configuration and version information.

**Parameters:**

- `name`: Task service name

**Returns:**

```nushell
{
    name: "kubernetes",
    path: "/usr/local/provisioning/taskservs/kubernetes",
    version: {
        current: "1.28.0",
        available: "1.28.2",
        update_available: true,
        source: "github",
        release_url: "https://github.com/kubernetes/kubernetes/releases"
    },
    config: {
        category: "orchestration",
        dependencies: ["containerd"],
        supports_versions: ["1.26.x", "1.27.x", "1.28.x"]
    }
}
```plaintext

### Cluster Discovery

#### `discover-clusters() -> list<record>`

Discovers all available cluster configurations.

**Returns:**

```nushell
[
    {
        name: "buildkit",
        path: "/usr/local/provisioning/cluster/buildkit",
        type: "cluster",
        category: "build",
        components: ["buildkit", "registry", "storage"],
        enabled: true
    }
]
```plaintext

## Environment Management API

### Environment Detection

#### `detect-environment() -> string`

Automatically detects the current environment based on:

1. `PROVISIONING_ENV` environment variable
2. Git branch patterns (main → prod, develop → dev, etc.)
3. Directory structure analysis
4. Configuration file presence

**Returns:**

- Environment name string (dev, test, prod, etc.)

#### `get-environment-config(env: string) -> record`

Gets environment-specific configuration.

**Parameters:**

- `env`: Environment name

**Returns:**

```nushell
{
    name: "production",
    paths: {
        base: "/opt/provisioning",
        kloud: "/data/kloud",
        logs: "/var/log/provisioning"
    },
    providers: {
        default: "upcloud",
        allowed: ["upcloud", "aws"]
    },
    features: {
        debug: false,
        telemetry: true,
        rollback: true
    }
}
```plaintext

### Environment Switching

#### `switch-environment(env: string, validate: bool = true) -> null`

Switches to a different environment and updates path resolution.

**Parameters:**

- `env`: Target environment name
- `validate`: Whether to validate environment configuration

**Effects:**

- Updates `PROVISIONING_ENV` environment variable
- Reconfigures path resolution for new environment
- Validates environment configuration if requested

## Workspace Management API

### Workspace Discovery

#### `discover-workspaces() -> list<record>`

Discovers available workspaces and infrastructure directories.

**Returns:**

```nushell
[
    {
        name: "production",
        path: "/workspace/infra/production",
        type: "infrastructure",
        provider: "upcloud",
        settings: "settings.ncl",
        valid: true
    },
    {
        name: "development",
        path: "/workspace/infra/development",
        type: "infrastructure",
        provider: "local",
        settings: "dev-settings.ncl",
        valid: true
    }
]
```plaintext

#### `set-current-workspace(path: string) -> null`

Sets the current workspace for path resolution.

**Parameters:**

- `path`: Workspace directory path

**Effects:**

- Updates `CURRENT_INFRA_PATH` environment variable
- Reconfigures workspace-relative path resolution

### Project Structure Analysis

#### `analyze-project-structure(path: string = $PWD) -> record`

Analyzes project structure and identifies components.

**Parameters:**

- `path`: Project root path (defaults to current directory)

**Returns:**

```nushell
{
    root: "/workspace/project",
    type: "provisioning_workspace",
    components: {
        providers: [
            { name: "upcloud", path: "providers/upcloud" },
            { name: "aws", path: "providers/aws" }
        ],
        taskservs: [
            { name: "kubernetes", path: "taskservs/kubernetes" },
            { name: "cilium", path: "taskservs/cilium" }
        ],
        clusters: [
            { name: "buildkit", path: "cluster/buildkit" }
        ],
        infrastructure: [
            { name: "production", path: "infra/production" },
            { name: "staging", path: "infra/staging" }
        ]
    },
    config_files: [
        "config.defaults.toml",
        "config.user.toml",
        "config.prod.toml"
    ]
}
```plaintext

## Caching and Performance

### Path Caching

The path resolution system includes intelligent caching:

#### `cache-paths(duration: duration = 5 min) -> null`

Enables path caching for the specified duration.

**Parameters:**

- `duration`: Cache validity duration

#### `invalidate-path-cache() -> null`

Invalidates the path resolution cache.

#### `get-cache-stats() -> record`

Gets path resolution cache statistics.

**Returns:**

```nushell
{
    enabled: true,
    size: 150,
    hit_rate: 0.85,
    last_invalidated: "2025-09-26T10:00:00Z"
}
```plaintext

## Cross-Platform Compatibility

### Path Normalization

#### `normalize-path(path: string) -> string`

Normalizes paths for cross-platform compatibility.

**Parameters:**

- `path`: Input path (may contain mixed separators)

**Returns:**

- Normalized path using platform-appropriate separators

**Example:**

```nushell
# On Windows
normalize-path "path/to/file" # Returns: "path\to\file"

# On Unix
normalize-path "path\to\file" # Returns: "path/to/file"
```plaintext

#### `join-paths(segments: list<string>) -> string`

Safely joins path segments using platform separators.

**Parameters:**

- `segments`: List of path segments

**Returns:**

- Joined path string

## Configuration Validation API

### Path Validation

#### `validate-paths(config: record) -> record`

Validates all paths in configuration.

**Parameters:**

- `config`: Configuration record

**Returns:**

```nushell
{
    valid: true,
    errors: [],
    warnings: [
        { path: "paths.extensions", message: "Path does not exist" }
    ],
    checks_performed: 15
}
```plaintext

#### `validate-extension-structure(type: string, path: string) -> record`

Validates extension directory structure.

**Parameters:**

- `type`: Extension type (provider, taskserv, cluster)
- `path`: Extension base path

**Returns:**

```nushell
{
    valid: true,
    required_files: [
        { file: "manifest.toml", exists: true },
        { file: "schemas/main.ncl", exists: true },
        { file: "nulib/mod.nu", exists: true }
    ],
    optional_files: [
        { file: "templates/server.j2", exists: false }
    ]
}
```plaintext

## Command-Line Interface

### Path Resolution Commands

The path resolution API is exposed via Nushell commands:

```bash
# Show current path configuration
provisioning show paths

# Discover available extensions
provisioning discover providers
provisioning discover taskservs
provisioning discover clusters

# Validate path configuration
provisioning validate paths

# Switch environments
provisioning env switch prod

# Set workspace
provisioning workspace set /path/to/infra
```plaintext

## Integration Examples

### Python Integration

```python
import subprocess
import json

class PathResolver:
    def __init__(self, provisioning_path="/usr/local/bin/provisioning"):
        self.cmd = provisioning_path

    def get_paths(self):
        result = subprocess.run([
            "nu", "-c", f"use {self.cmd} *; show-config --section=paths --format=json"
        ], capture_output=True, text=True)
        return json.loads(result.stdout)

    def discover_providers(self):
        result = subprocess.run([
            "nu", "-c", f"use {self.cmd} *; discover providers --format=json"
        ], capture_output=True, text=True)
        return json.loads(result.stdout)

# Usage
resolver = PathResolver()
paths = resolver.get_paths()
providers = resolver.discover_providers()
```plaintext

### JavaScript/Node.js Integration

```javascript
const { exec } = require('child_process');
const util = require('util');
const execAsync = util.promisify(exec);

class PathResolver {
  constructor(provisioningPath = '/usr/local/bin/provisioning') {
    this.cmd = provisioningPath;
  }

  async getPaths() {
    const { stdout } = await execAsync(
      `nu -c "use ${this.cmd} *; show-config --section=paths --format=json"`
    );
    return JSON.parse(stdout);
  }

  async discoverExtensions(type) {
    const { stdout } = await execAsync(
      `nu -c "use ${this.cmd} *; discover ${type} --format=json"`
    );
    return JSON.parse(stdout);
  }
}

// Usage
const resolver = new PathResolver();
const paths = await resolver.getPaths();
const providers = await resolver.discoverExtensions('providers');
```plaintext

## Error Handling

### Common Error Scenarios

1. **Configuration File Not Found**

   ```nushell
   Error: Configuration file not found in search paths
   Searched: ["/usr/local/provisioning/config.defaults.toml", ...]
   ```

1. **Extension Not Found**

   ```nushell
   Error: Provider 'missing-provider' not found
   Available providers: ["upcloud", "aws", "local"]
   ```

2. **Invalid Path Template**

   ```nushell
   Error: Invalid template variable: {{invalid.var}}
   Valid variables: ["paths.*", "env.*", "now.*", "git.*"]
   ```

3. **Environment Not Found**

   ```nushell
   Error: Environment 'staging' not configured
   Available environments: ["dev", "test", "prod"]
   ```

### Error Recovery

The system provides graceful fallbacks:

- Missing configuration files use system defaults
- Invalid paths fall back to safe defaults
- Extension discovery continues if some paths are inaccessible
- Environment detection falls back to 'local' if detection fails

## Performance Considerations

### Best Practices

1. **Use Path Caching**: Enable caching for frequently accessed paths
2. **Batch Discovery**: Discover all extensions at once rather than individually
3. **Lazy Loading**: Load extension configurations only when needed
4. **Environment Detection**: Cache environment detection results

### Monitoring

Monitor path resolution performance:

```nushell
# Get resolution statistics
provisioning debug path-stats

# Monitor cache performance
provisioning debug cache-stats

# Profile path resolution
provisioning debug profile-paths
```plaintext

## Security Considerations

### Path Traversal Protection

The system includes protections against path traversal attacks:

- All paths are normalized and validated
- Relative paths are resolved within safe boundaries
- Symlinks are validated before following

### Access Control

Path resolution respects file system permissions:

- Configuration files require read access
- Extension directories require read/execute access
- Workspace directories may require write access for operations

This path resolution API provides a comprehensive and flexible system for managing the complex path requirements of multi-provider, multi-environment infrastructure provisioning.
