@kaitranntt/ccs 4.3.4 → 4.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -323,8 +323,7 @@ graph LR
323
323
  ~/.ccs/
324
324
  ├── .claude/ # CCS items (ships with package, v4.1)
325
325
  │ ├── commands/ccs/ # Delegation commands (/ccs, /ccs:continue)
326
- ├── skills/ccs-delegation/ # AI decision framework
327
- │ └── agents/ccs-delegator.md # Proactive delegation agent
326
+ └── skills/ccs-delegation/ # AI decision framework (replaces deprecated agents)
328
327
  ├── shared/ # Symlinks to ~/.claude/ (for profiles)
329
328
  │ ├── agents@ → ~/.claude/agents/
330
329
  │ ├── commands@ → ~/.claude/commands/
@@ -341,7 +340,7 @@ graph LR
341
340
  ~/.claude/ # User's Claude directory
342
341
  ├── commands/ccs@ → ~/.ccs/.claude/commands/ccs/ # Selective symlink
343
342
  ├── skills/ccs-delegation@ → ~/.ccs/.claude/skills/ccs-delegation/
344
- └── agents/ccs-delegator.md@ → ~/.ccs/.claude/agents/ccs-delegator.md
343
+ # agents/ccs-delegator.md@ → ~/.ccs/.claude/agents/ccs-delegator.md # Deprecated in v4.3.2
345
344
  ```
346
345
 
347
346
  **Symlink Chain**: `work profile → ~/.ccs/shared/ → ~/.claude/ → ~/.ccs/.claude/` (CCS items)
@@ -507,8 +506,8 @@ Savings: $0.0275 (86% reduction)
507
506
  ### Documentation
508
507
 
509
508
  - **Workflow Diagrams**: See [docs/ccs-delegation-diagrams.md](docs/ccs-delegation-diagrams.md) for visual architecture
510
- - **Skill Reference**: `.claude/skills/ccs-delegation/` for AI decision framework
511
- - **Agent Docs**: `.claude/agents/ccs-delegator.md` for orchestration patterns
509
+ - **Skill Reference**: `.claude/skills/ccs-delegation/` for AI decision framework (replaces deprecated agents)
510
+ - **Agent Docs**: `.claude/agents/ccs-delegator.md` was deprecated in v4.3.2, functionality moved to ccs-delegation skill
512
511
 
513
512
  <br>
514
513
 
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.3.4
1
+ 4.3.5
package/bin/ccs.js CHANGED
@@ -286,6 +286,11 @@ async function handleSyncCommand() {
286
286
 
287
287
  console.log('');
288
288
 
289
+ const cleanupResult = installer.cleanupDeprecated();
290
+ if (cleanupResult.success && cleanupResult.cleanedFiles.length > 0) {
291
+ console.log('');
292
+ }
293
+
289
294
  // Then, create symlinks from ~/.ccs/.claude/ to ~/.claude/
290
295
  const ClaudeSymlinkManager = require('./utils/claude-symlink-manager');
291
296
  const manager = new ClaudeSymlinkManager();
@@ -148,6 +148,108 @@ class ClaudeDirInstaller {
148
148
  return { files, dirs };
149
149
  }
150
150
 
151
+ /**
152
+ * Clean up deprecated files from previous installations
153
+ * Removes ccs-delegator.md that was deprecated in v4.3.2
154
+ * @param {boolean} silent - Suppress console output
155
+ */
156
+ cleanupDeprecated(silent = false) {
157
+ const deprecatedFile = path.join(this.ccsClaudeDir, 'agents', 'ccs-delegator.md');
158
+ const userSymlinkFile = path.join(this.homeDir, '.claude', 'agents', 'ccs-delegator.md');
159
+ const migrationMarker = path.join(this.homeDir, '.ccs', '.migrations', 'v435-delegator-cleanup');
160
+
161
+ let cleanedFiles = [];
162
+
163
+ try {
164
+ // Check if cleanup already done
165
+ if (fs.existsSync(migrationMarker)) {
166
+ return { success: true, cleanedFiles: [] }; // Already cleaned
167
+ }
168
+
169
+ // Clean up user symlink in ~/.claude/agents/ccs-delegator.md FIRST
170
+ // This ensures we can detect broken symlinks before deleting the target
171
+ try {
172
+ const userStats = fs.lstatSync(userSymlinkFile);
173
+ if (userStats.isSymbolicLink()) {
174
+ fs.unlinkSync(userSymlinkFile);
175
+ cleanedFiles.push('user symlink');
176
+ } else {
177
+ // It's not a symlink (user created their own file), backup it
178
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
179
+ const backupPath = `${userSymlinkFile}.backup-${timestamp}`;
180
+ fs.renameSync(userSymlinkFile, backupPath);
181
+ if (!silent) console.log(`[i] Backed up user file to ${path.basename(backupPath)}`);
182
+ cleanedFiles.push('user file (backed up)');
183
+ }
184
+ } catch (err) {
185
+ // File doesn't exist or other error - that's okay
186
+ if (err.code !== 'ENOENT' && !silent) {
187
+ console.log(`[!] Failed to remove user symlink: ${err.message}`);
188
+ }
189
+ }
190
+
191
+ // Clean up package copy in ~/.ccs/.claude/agents/ccs-delegator.md
192
+ if (fs.existsSync(deprecatedFile)) {
193
+ try {
194
+ // Check if file was modified by user (compare with expected content)
195
+ const shouldBackup = this._shouldBackupDeprecatedFile(deprecatedFile);
196
+
197
+ if (shouldBackup) {
198
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
199
+ const backupPath = `${deprecatedFile}.backup-${timestamp}`;
200
+ fs.renameSync(deprecatedFile, backupPath);
201
+ if (!silent) console.log(`[i] Backed up modified deprecated file to ${path.basename(backupPath)}`);
202
+ } else {
203
+ fs.rmSync(deprecatedFile, { force: true });
204
+ }
205
+ cleanedFiles.push('package copy');
206
+ } catch (err) {
207
+ if (!silent) console.log(`[!] Failed to remove package copy: ${err.message}`);
208
+ }
209
+ }
210
+
211
+ // Create migration marker
212
+ if (cleanedFiles.length > 0) {
213
+ const migrationsDir = path.dirname(migrationMarker);
214
+ if (!fs.existsSync(migrationsDir)) {
215
+ fs.mkdirSync(migrationsDir, { recursive: true, mode: 0o700 });
216
+ }
217
+ fs.writeFileSync(migrationMarker, new Date().toISOString());
218
+
219
+ if (!silent) {
220
+ console.log(`[OK] Cleaned up deprecated agent files: ${cleanedFiles.join(', ')}`);
221
+ }
222
+ }
223
+
224
+ return { success: true, cleanedFiles };
225
+ } catch (err) {
226
+ if (!silent) console.log(`[!] Cleanup failed: ${err.message}`);
227
+ return { success: false, error: err.message, cleanedFiles };
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Check if deprecated file should be backed up (user modified)
233
+ * @param {string} filePath - Path to check
234
+ * @returns {boolean} True if file should be backed up
235
+ * @private
236
+ */
237
+ _shouldBackupDeprecatedFile(filePath) {
238
+ try {
239
+ // Simple heuristic: if file size differs significantly from expected, assume user modified
240
+ // Expected size for ccs-delegator.md was around 2-3KB
241
+ const stats = fs.statSync(filePath);
242
+ const expectedMinSize = 1000; // 1KB minimum
243
+ const expectedMaxSize = 10000; // 10KB maximum
244
+
245
+ // If size is outside expected range, likely user modified
246
+ return stats.size < expectedMinSize || stats.size > expectedMaxSize;
247
+ } catch (err) {
248
+ // If we can't determine, err on side of caution and backup
249
+ return true;
250
+ }
251
+ }
252
+
151
253
  /**
152
254
  * Check if ~/.ccs/.claude/ exists and is valid
153
255
  * @returns {boolean} True if directory exists
@@ -28,8 +28,7 @@ class ClaudeSymlinkManager {
28
28
  // CCS items to symlink (selective, item-level)
29
29
  this.ccsItems = [
30
30
  { source: 'commands/ccs', target: 'commands/ccs', type: 'directory' },
31
- { source: 'skills/ccs-delegation', target: 'skills/ccs-delegation', type: 'directory' },
32
- { source: 'agents/ccs-delegator.md', target: 'agents/ccs-delegator.md', type: 'file' }
31
+ { source: 'skills/ccs-delegation', target: 'skills/ccs-delegation', type: 'directory' }
33
32
  ];
34
33
  }
35
34
 
package/lib/ccs CHANGED
@@ -2,7 +2,7 @@
2
2
  set -euo pipefail
3
3
 
4
4
  # Version (updated by scripts/bump-version.sh)
5
- CCS_VERSION="4.3.4"
5
+ CCS_VERSION="4.3.5"
6
6
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
7
  readonly CONFIG_FILE="${CCS_CONFIG:-$HOME/.ccs/config.json}"
8
8
  readonly PROFILES_JSON="$HOME/.ccs/profiles.json"
package/lib/ccs.ps1 CHANGED
@@ -12,7 +12,7 @@ param(
12
12
  $ErrorActionPreference = "Stop"
13
13
 
14
14
  # Version (updated by scripts/bump-version.sh)
15
- $CcsVersion = "4.3.4"
15
+ $CcsVersion = "4.3.5"
16
16
  $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
17
17
  $ConfigFile = if ($env:CCS_CONFIG) { $env:CCS_CONFIG } else { "$env:USERPROFILE\.ccs\config.json" }
18
18
  $ProfilesJson = "$env:USERPROFILE\.ccs\profiles.json"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaitranntt/ccs",
3
- "version": "4.3.4",
3
+ "version": "4.3.5",
4
4
  "description": "Claude Code Switch - Instant profile switching between Claude Sonnet 4.5 and GLM 4.6",
5
5
  "keywords": [
6
6
  "cli",
@@ -59,7 +59,7 @@
59
59
  },
60
60
  "dependencies": {
61
61
  "cli-table3": "^0.6.5",
62
- "ora": "^5.4.1"
62
+ "ora": "^9.0.0"
63
63
  },
64
64
  "devDependencies": {
65
65
  "mocha": "^11.7.5"
@@ -109,6 +109,9 @@ function createConfigFiles() {
109
109
  const installer = new ClaudeDirInstaller();
110
110
  const packageDir = path.join(__dirname, '..');
111
111
  installer.install(packageDir);
112
+
113
+ // Clean up deprecated files (v4.3.2)
114
+ installer.cleanupDeprecated();
112
115
  } catch (err) {
113
116
  console.warn('[!] Failed to install .claude/ directory:', err.message);
114
117
  console.warn(' CCS items may not be available');