Files
ccs/bin/utils/delegation-validator.js
T
Kai (Tam Nhu) TranandGitHub 4df5a7d357 feat!: delegation system overhaul and .claude/ shipping (v4.1.0) (#8)
## 🚀 Release v4.1.0 - Major Update

**Breaking changes from v3.5.0**. This release includes the complete v4.0.0 delegation overhaul plus v4.1.0 architecture improvements.

---

## 🎯 v4.0.0: Delegation System Overhaul

**Complete rewrite of the delegation infrastructure with enhanced decision-making and streaming support.**

### New Delegation Features

**Stream-JSON Communication Protocol:**
- Real-time token streaming with `{type: "content", data: "..."}` format
- Progress indicators during delegation execution
- Clean separation: stdout for data, stderr for errors
- Handles tool calls, thinking blocks, and text content

**Enhanced Decision Framework:**
- `/ccs:glm` and `/ccs:kimi` slash commands with auto-enhancement
- `[AUTO ENHANCE]` prompts for better model understanding
- Context-aware task delegation with clear boundaries
- Continuation support: `/ccs:glm:continue` and `/ccs:kimi:continue`

**Robust Error Handling:**
- Graceful degradation when profiles unconfigured
- Clear error messages with actionable fixes
- Signal handling (SIGINT/SIGTERM) for clean child process termination
- Session state recovery on interruption

**Performance & Reliability:**
- Headless mode (`-p` flag) for background execution
- Slash command detection and auto-routing
- Validation system with `DelegationValidator`
- Profile readiness checks in `ccs --version`

### Delegation Components

**New Files:**
- `bin/delegation/delegation-handler.js` - Core delegation orchestrator
- `bin/delegation/stream-processor.js` - Real-time output handling
- `bin/utils/delegation-validator.js` - Profile validation
- `.claude/commands/ccs/*.md` - Slash command definitions
- `.claude/skills/ccs-delegation/` - AI decision framework
- `.claude/agents/ccs-delegator.md` - Proactive delegation agent

**Documentation:**
- Complete delegation workflows with mermaid diagrams
- Troubleshooting guides for common issues
- Headless execution patterns

---

##  v4.1.0: Selective Symlinking Architecture

**Single source of truth for CCS items with automatic propagation.**

### New Architecture

**Ship .claude/ Directory:**
- CCS items now ship with npm/sh/ps1 packages
- Selective item-level symlinks: `~/.ccs/.claude/` → `~/.claude/`
- Auto-propagation on `npm update` - zero manual sync
- Backward compatible with existing `~/.ccs/shared/` mechanism

**Symlink Chain:**
```
~/.ccs/.claude/ (source) 
    ↓ selective symlinks
~/.claude/ (CCS items installed here)
    ↑ symlinked by
~/.ccs/shared/
    ↑ symlinked by  
profiles (work, personal, team)
```

### New Commands

**Maintenance Tools:**
- `ccs update` - Re-install CCS symlinks to ~/.claude/
- `ccs doctor` - Added Check 9: CCS symlinks health verification

**Safe Installation:**
- Automatic conflict backup before symlinking
- Idempotent operations (safe to run multiple times)
- Health monitoring and recovery

### New Components

- `bin/utils/claude-symlink-manager.js` - Manages selective symlinks
- Updated all 3 installers (npm postinstall, install.sh, install.ps1)
- Enhanced `ccs doctor` with symlink health checks

---

## 💥 Breaking Changes

**From v3.5.0 → v4.x:**

1. **Delegation commands moved**: 
   - Old: User manually created in `~/.claude/commands/`
   - New: Auto-shipped in `~/.ccs/.claude/`, symlinked to `~/.claude/commands/ccs/`

2. **Slash command format**:
   - New: `/ccs:glm`, `/ccs:kimi`, `/ccs:glm:continue`
   - Old custom commands may need migration

3. **Profile validation**:
   - Placeholders (`YOUR_API_KEY_HERE`) now detected and marked invalid
   - Must configure real API keys for delegation to work

4. **Stream output format**:
   - Headless mode (`-p`) now uses stream-JSON protocol
   - Old text output replaced with structured `{type, data}` format
2025-11-16 06:31:55 -05:00

155 lines
4.7 KiB
JavaScript

#!/usr/bin/env node
'use strict';
const fs = require('fs');
const path = require('path');
const os = require('os');
/**
* Validates delegation profiles for CCS delegation system
* Ensures profiles exist and have valid API keys configured
*/
class DelegationValidator {
/**
* Validate a delegation profile
* @param {string} profileName - Name of profile to validate (e.g., 'glm', 'kimi')
* @returns {Object} Validation result { valid: boolean, error?: string, settingsPath?: string }
*/
static validate(profileName) {
const homeDir = os.homedir();
const settingsPath = path.join(homeDir, '.ccs', `${profileName}.settings.json`);
// Check if profile directory exists
if (!fs.existsSync(settingsPath)) {
return {
valid: false,
error: `Profile not found: ${profileName}`,
suggestion: `Profile settings missing at: ${settingsPath}\n\n` +
`To set up ${profileName} profile:\n` +
` 1. Copy base settings: cp config/base-${profileName}.settings.json ~/.ccs/${profileName}.settings.json\n` +
` 2. Edit settings: Edit ~/.ccs/${profileName}.settings.json\n` +
` 3. Set your API key in ANTHROPIC_AUTH_TOKEN field`
};
}
// Read and parse settings.json
let settings;
try {
const settingsContent = fs.readFileSync(settingsPath, 'utf8');
settings = JSON.parse(settingsContent);
} catch (error) {
return {
valid: false,
error: `Failed to parse settings.json for ${profileName}`,
suggestion: `Settings file is corrupted or invalid JSON.\n\n` +
`Location: ${settingsPath}\n` +
`Parse error: ${error.message}\n\n` +
`Fix: Restore from base config:\n` +
` cp config/base-${profileName}.settings.json ~/.ccs/${profileName}.settings.json`
};
}
// Validate API key exists and is not default
const apiKey = settings.env?.ANTHROPIC_AUTH_TOKEN;
if (!apiKey) {
return {
valid: false,
error: `API key not configured for ${profileName}`,
suggestion: `Missing ANTHROPIC_AUTH_TOKEN in settings.\n\n` +
`Edit: ${settingsPath}\n` +
`Set: env.ANTHROPIC_AUTH_TOKEN to your API key`
};
}
// Check for default placeholder values
const defaultPlaceholders = [
'YOUR_GLM_API_KEY_HERE',
'YOUR_KIMI_API_KEY_HERE',
'YOUR_API_KEY_HERE',
'your-api-key-here',
'PLACEHOLDER'
];
if (defaultPlaceholders.some(placeholder => apiKey.includes(placeholder))) {
return {
valid: false,
error: `Default API key placeholder detected for ${profileName}`,
suggestion: `API key is still set to default placeholder.\n\n` +
`To configure your profile:\n` +
` 1. Edit: ${settingsPath}\n` +
` 2. Replace ANTHROPIC_AUTH_TOKEN with your actual API key\n\n` +
`Get API key:\n` +
` GLM: https://z.ai/manage-apikey/apikey-list\n` +
` Kimi: https://platform.moonshot.cn/console/api-keys`
};
}
// Validation passed
return {
valid: true,
settingsPath,
apiKey: apiKey.substring(0, 8) + '...' // Show first 8 chars for verification
};
}
/**
* Format validation error for display
* @param {Object} result - Validation result from validate()
* @returns {string} Formatted error message
*/
static formatError(result) {
if (result.valid) {
return '';
}
let message = `\n[X] ${result.error}\n\n`;
if (result.suggestion) {
message += `${result.suggestion}\n`;
}
return message;
}
/**
* Check if profile is delegation-ready (shorthand)
* @param {string} profileName - Profile to check
* @returns {boolean} True if ready for delegation
*/
static isReady(profileName) {
const result = this.validate(profileName);
return result.valid;
}
/**
* Get all delegation-ready profiles
* @returns {Array<string>} List of profile names ready for delegation
*/
static getReadyProfiles() {
const homeDir = os.homedir();
const ccsDir = path.join(homeDir, '.ccs');
if (!fs.existsSync(ccsDir)) {
return [];
}
const profiles = [];
const entries = fs.readdirSync(ccsDir, { withFileTypes: true });
// Look for *.settings.json files
for (const entry of entries) {
if (entry.isFile() && entry.name.endsWith('.settings.json')) {
const profileName = entry.name.replace('.settings.json', '');
if (this.isReady(profileName)) {
profiles.push(profileName);
}
}
}
return profiles;
}
}
module.exports = { DelegationValidator };