mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-15 18:21:09 +00:00
## 🚀 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
110 lines
3.1 KiB
JavaScript
110 lines
3.1 KiB
JavaScript
#!/usr/bin/env node
|
|
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
/**
|
|
* Parses Claude Code settings for tool restrictions
|
|
*/
|
|
class SettingsParser {
|
|
/**
|
|
* Parse default permission mode from project settings
|
|
* @param {string} projectDir - Project directory (usually cwd)
|
|
* @returns {string} Default permission mode (e.g., 'acceptEdits', 'bypassPermissions', 'plan', 'default')
|
|
*/
|
|
static parseDefaultPermissionMode(projectDir) {
|
|
const settings = this._loadSettings(projectDir);
|
|
const permissions = settings.permissions || {};
|
|
|
|
// Priority: local > shared > fallback to 'acceptEdits'
|
|
const defaultMode = permissions.defaultMode || 'acceptEdits';
|
|
|
|
if (process.env.CCS_DEBUG) {
|
|
console.error(`[i] Permission mode from settings: ${defaultMode}`);
|
|
}
|
|
|
|
return defaultMode;
|
|
}
|
|
|
|
/**
|
|
* Parse project settings for tool restrictions
|
|
* @param {string} projectDir - Project directory (usually cwd)
|
|
* @returns {Object} { allowedTools: string[], disallowedTools: string[] }
|
|
*/
|
|
static parseToolRestrictions(projectDir) {
|
|
const settings = this._loadSettings(projectDir);
|
|
const permissions = settings.permissions || {};
|
|
|
|
const allowed = permissions.allow || [];
|
|
const denied = permissions.deny || [];
|
|
|
|
if (process.env.CCS_DEBUG) {
|
|
console.error(`[i] Tool restrictions: ${allowed.length} allowed, ${denied.length} denied`);
|
|
}
|
|
|
|
return {
|
|
allowedTools: allowed,
|
|
disallowedTools: denied
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Load and merge settings files (local overrides shared)
|
|
* @param {string} projectDir - Project directory
|
|
* @returns {Object} Merged settings
|
|
* @private
|
|
*/
|
|
static _loadSettings(projectDir) {
|
|
const claudeDir = path.join(projectDir, '.claude');
|
|
const sharedPath = path.join(claudeDir, 'settings.json');
|
|
const localPath = path.join(claudeDir, 'settings.local.json');
|
|
|
|
// Load shared settings
|
|
const shared = this._readJsonSafe(sharedPath) || {};
|
|
|
|
// Load local settings (overrides shared)
|
|
const local = this._readJsonSafe(localPath) || {};
|
|
|
|
// Merge permissions (local overrides shared)
|
|
return {
|
|
permissions: {
|
|
allow: [
|
|
...(shared.permissions?.allow || []),
|
|
...(local.permissions?.allow || [])
|
|
],
|
|
deny: [
|
|
...(shared.permissions?.deny || []),
|
|
...(local.permissions?.deny || [])
|
|
],
|
|
// Local defaultMode takes priority over shared
|
|
defaultMode: local.permissions?.defaultMode || shared.permissions?.defaultMode || null
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Read JSON file safely (no throw)
|
|
* @param {string} filePath - Path to JSON file
|
|
* @returns {Object|null} Parsed JSON or null
|
|
* @private
|
|
*/
|
|
static _readJsonSafe(filePath) {
|
|
try {
|
|
if (!fs.existsSync(filePath)) {
|
|
return null;
|
|
}
|
|
|
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
return JSON.parse(content);
|
|
} catch (error) {
|
|
if (process.env.CCS_DEBUG) {
|
|
console.warn(`[!] Failed to read settings: ${filePath}: ${error.message}`);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = { SettingsParser };
|