sf-agent-framework
Version:
AI Agent Orchestration Framework for Salesforce Development - Two-phase architecture with 70% context reduction
303 lines (243 loc) • 8.05 kB
Markdown
# Salesforce Project Configuration Reader
## Purpose
Utility to read and parse Salesforce DX project configuration from `sfdx-project.json`
## Usage
### Reading API Version
```bash
# Get API version from sfdx-project.json
get_api_version() {
if [ -f "sfdx-project.json" ]; then
cat sfdx-project.json | grep sourceApiVersion | sed 's/.*"sourceApiVersion": "\(.*\)".*/\1/'
else
echo "63.0" # Fallback to latest stable
fi
}
API_VERSION=$(get_api_version)
echo "Using API Version: $API_VERSION"
```
### Reading Package Directories
```bash
# Get default package directory
get_package_dir() {
if [ -f "sfdx-project.json" ]; then
cat sfdx-project.json | jq -r '.packageDirectories[] | select(.default==true) | .path' 2>/dev/null || echo "force-app"
else
echo "force-app"
fi
}
PACKAGE_DIR=$(get_package_dir)
echo "Package Directory: $PACKAGE_DIR"
```
### Validating Project Structure
```bash
# Check if valid SFDX project
validate_sfdx_project() {
if [ ! -f "sfdx-project.json" ]; then
echo "❌ Error: Not a Salesforce DX project directory"
echo "Please run this command from a directory containing sfdx-project.json"
return 1
fi
# Check for package directories
if [ ! -d "$(get_package_dir)" ]; then
echo "⚠️ Warning: Package directory not found"
echo "Expected directory: $(get_package_dir)"
return 1
fi
echo "✅ Valid Salesforce DX project detected"
return 0
}
```
### JavaScript/Node.js Implementation
```javascript
const fs = require('fs');
const path = require('path');
class SfdxProjectConfig {
constructor(projectPath = process.cwd()) {
this.projectPath = projectPath;
this.configPath = path.join(projectPath, 'sfdx-project.json');
this.config = null;
this.loadConfig();
}
loadConfig() {
try {
if (fs.existsSync(this.configPath)) {
const configContent = fs.readFileSync(this.configPath, 'utf8');
this.config = JSON.parse(configContent);
} else {
console.warn('sfdx-project.json not found. Using defaults.');
this.config = this.getDefaultConfig();
}
} catch (error) {
console.error('Error reading sfdx-project.json:', error);
this.config = this.getDefaultConfig();
}
}
getDefaultConfig() {
return {
packageDirectories: [{ path: 'force-app', default: true }],
sourceApiVersion: '63.0',
namespace: '',
sfdcLoginUrl: 'https://login.salesforce.com',
};
}
getApiVersion() {
return this.config?.sourceApiVersion || '63.0';
}
getPackageDirectories() {
return this.config?.packageDirectories || [{ path: 'force-app', default: true }];
}
getDefaultPackageDirectory() {
const dirs = this.getPackageDirectories();
const defaultDir = dirs.find((d) => d.default === true);
return defaultDir?.path || dirs[0]?.path || 'force-app';
}
getNamespace() {
return this.config?.namespace || '';
}
getLoginUrl() {
return this.config?.sfdcLoginUrl || 'https://login.salesforce.com';
}
getAllPackagePaths() {
return this.getPackageDirectories().map((d) => d.path);
}
isValidProject() {
return fs.existsSync(this.configPath);
}
getFullPath(relativePath) {
const packageDir = this.getDefaultPackageDirectory();
return path.join(this.projectPath, packageDir, relativePath);
}
}
// Export for use in other modules
module.exports = SfdxProjectConfig;
// Usage example:
// const config = new SfdxProjectConfig();
// console.log('API Version:', config.getApiVersion());
// console.log('Package Directory:', config.getDefaultPackageDirectory());
```
### Python Implementation
```python
import json
import os
from pathlib import Path
from typing import Dict, List, Optional
class SfdxProjectConfig:
def __init__(self, project_path: str = None):
self.project_path = project_path or os.getcwd()
self.config_path = Path(self.project_path) / 'sfdx-project.json'
self.config = self._load_config()
def _load_config(self) -> Dict:
"""Load sfdx-project.json configuration"""
if self.config_path.exists():
try:
with open(self.config_path, 'r') as f:
return json.load(f)
except Exception as e:
print(f"Error reading sfdx-project.json: {e}")
return self._get_default_config()
else:
print("sfdx-project.json not found. Using defaults.")
return self._get_default_config()
def _get_default_config(self) -> Dict:
"""Return default configuration"""
return {
'packageDirectories': [{'path': 'force-app', 'default': True}],
'sourceApiVersion': '63.0',
'namespace': '',
'sfdcLoginUrl': 'https://login.salesforce.com'
}
def get_api_version(self) -> str:
"""Get the source API version"""
return self.config.get('sourceApiVersion', '63.0')
def get_package_directories(self) -> List[Dict]:
"""Get all package directories"""
return self.config.get('packageDirectories', [{'path': 'force-app', 'default': True}])
def get_default_package_directory(self) -> str:
"""Get the default package directory path"""
dirs = self.get_package_directories()
for d in dirs:
if d.get('default', False):
return d['path']
return dirs[0]['path'] if dirs else 'force-app'
def get_namespace(self) -> str:
"""Get the namespace"""
return self.config.get('namespace', '')
def is_valid_project(self) -> bool:
"""Check if this is a valid SFDX project"""
return self.config_path.exists()
# Usage example:
# config = SfdxProjectConfig()
# print(f"API Version: {config.get_api_version()}")
# print(f"Package Directory: {config.get_default_package_directory()}")
```
## Integration with Agents
When agents need to execute Salesforce commands, they should:
1. **Check for valid project**
```bash
if [ ! -f "sfdx-project.json" ]; then
echo "Please navigate to a Salesforce DX project directory"
exit 1
fi
```
2. **Read configuration dynamically**
```bash
API_VERSION=$(cat sfdx-project.json | grep sourceApiVersion | sed 's/.*"sourceApiVersion": "\(.*\)".*/\1/')
PACKAGE_DIR=$(cat sfdx-project.json | jq -r '.packageDirectories[0].path')
```
3. **Use configuration in commands**
```bash
sf project deploy start \
--source-dir "$PACKAGE_DIR" \
--api-version "$API_VERSION" \
--target-org myorg
```
## Error Handling
Always include proper error handling:
```bash
# Function to safely get project config
get_project_config() {
local config_file="sfdx-project.json"
if [ ! -f "$config_file" ]; then
echo "Error: $config_file not found" >&2
echo "Are you in a Salesforce DX project directory?" >&2
return 1
fi
# Validate JSON format
if ! jq empty "$config_file" 2>/dev/null; then
echo "Error: Invalid JSON in $config_file" >&2
return 1
fi
return 0
}
# Use before any SF command
if get_project_config; then
# Safe to proceed with SF commands
API_VERSION=$(jq -r '.sourceApiVersion' sfdx-project.json)
echo "Project configured with API version: $API_VERSION"
else
exit 1
fi
```
## Best Practices
1. **Never hardcode paths** - Always read from sfdx-project.json
2. **Never hardcode API versions** - Always read from sfdx-project.json
3. **Check for project validity** before executing commands
4. **Provide helpful error messages** when project config is missing
5. **Use fallback values** only when explicitly needed
6. **Log configuration values** for debugging purposes
## Sample sfdx-project.json Structure
```json
{
"packageDirectories": [
{
"path": "force-app",
"default": true
}
],
"name": "MyProject",
"namespace": "",
"sfdcLoginUrl": "https://login.salesforce.com",
"sourceApiVersion": "63.0"
}
```
This utility ensures that all Salesforce operations use the correct project-specific configuration rather than hardcoded values.