@leynier/ccst 0.1.5 → 0.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leynier/ccst",
3
- "version": "0.1.5",
3
+ "version": "0.2.1",
4
4
  "description": "Claude Code Switch Tools for managing contexts",
5
5
  "keywords": [
6
6
  "claude",
@@ -4,6 +4,7 @@ import { existsSync, mkdirSync, readdirSync } from "node:fs";
4
4
  import type { ContextManager } from "../../core/context-manager.js";
5
5
  import { deepMerge } from "../../utils/deep-merge.js";
6
6
  import { readJson, readJsonIfExists } from "../../utils/json.js";
7
+ import { colors } from "../../utils/colors.js";
7
8
 
8
9
  const defaultConfigsDir = (): string => path.join(homedir(), ".ccst");
9
10
  const ccsDir = (): string => path.join(homedir(), ".ccs");
@@ -54,6 +55,7 @@ export const importFromCcs = async (manager: ContextManager, configsDir?: string
54
55
  if (!existsSync(ccsPath)) {
55
56
  throw new Error(`CCS directory not found: ${ccsPath}`);
56
57
  }
58
+ console.log(`📥 Importing profiles from CCS settings...`);
57
59
  const dir = configsDir ?? defaultConfigsDir();
58
60
  const { created } = await ensureDefaultConfig(manager, dir);
59
61
  const defaultConfig = await loadDefaultConfig(dir);
@@ -66,17 +68,21 @@ export const importFromCcs = async (manager: ContextManager, configsDir?: string
66
68
  } catch {
67
69
  entries = [];
68
70
  }
71
+ let importedCount = 0;
69
72
  for (const fileName of entries) {
70
73
  const settingsPath = path.join(ccsPath, fileName);
71
74
  const profileName = fileName.replace(/\.settings\.json$/u, "");
75
+ console.log(` 📦 Importing '${colors.cyan(profileName)}'...`);
72
76
  const settings = await readJson<Record<string, unknown>>(settingsPath);
73
77
  const merged = deepMerge(defaultConfig, settings);
74
78
  if (currentContext && currentContext === profileName) {
75
79
  await manager.unsetContext();
76
80
  }
77
81
  await importProfile(manager, profileName, merged);
82
+ importedCount++;
78
83
  }
79
84
  if (currentContext) {
80
85
  await manager.switchContext(currentContext);
81
86
  }
87
+ console.log(`✅ Imported ${colors.bold(colors.green(String(importedCount)))} profiles from CCS`);
82
88
  };
@@ -4,6 +4,7 @@ import { existsSync, mkdirSync, readdirSync } from "node:fs";
4
4
  import type { ContextManager } from "../../core/context-manager.js";
5
5
  import { deepMerge } from "../../utils/deep-merge.js";
6
6
  import { readJson, readJsonIfExists } from "../../utils/json.js";
7
+ import { colors } from "../../utils/colors.js";
7
8
 
8
9
  const defaultConfigsDir = (): string => path.join(homedir(), ".ccst");
9
10
 
@@ -39,6 +40,7 @@ const importProfile = async (manager: ContextManager, profileName: string, merge
39
40
 
40
41
  export const importFromConfigs = async (manager: ContextManager, configsDir?: string): Promise<void> => {
41
42
  const dir = configsDir ?? defaultConfigsDir();
43
+ console.log(`📥 Importing profiles from configs directory...`);
42
44
  const created = await ensureDefaultConfig(manager, dir);
43
45
  const defaultConfig = await loadDefaultConfig(dir);
44
46
  const defaultProfile = await readJsonIfExists<Record<string, unknown>>(path.join(dir, "default.json"), defaultConfig);
@@ -49,15 +51,18 @@ export const importFromConfigs = async (manager: ContextManager, configsDir?: st
49
51
  } catch {
50
52
  entries = [];
51
53
  }
54
+ let importedCount = 0;
52
55
  for (const fileName of entries) {
53
56
  const configPath = path.join(dir, fileName);
54
57
  const profileName = path.basename(fileName, ".json");
58
+ console.log(` 📦 Importing '${colors.cyan(profileName)}'...`);
55
59
  const config = await readJson<Record<string, unknown>>(configPath);
56
60
  const merged = fileName === "default.json" ? config : deepMerge(defaultConfig, config);
57
61
  if (currentContext && currentContext === profileName) {
58
62
  await manager.unsetContext();
59
63
  }
60
64
  await importProfile(manager, profileName, merged);
65
+ importedCount++;
61
66
  }
62
67
  if (created) {
63
68
  await importProfile(manager, "default", defaultProfile);
@@ -65,4 +70,5 @@ export const importFromConfigs = async (manager: ContextManager, configsDir?: st
65
70
  if (currentContext) {
66
71
  await manager.switchContext(currentContext);
67
72
  }
73
+ console.log(`✅ Imported ${colors.bold(colors.green(String(importedCount)))} profiles from configs`);
68
74
  };
@@ -202,19 +202,19 @@ export class ContextManager {
202
202
  }
203
203
  if (this.settingsLevel === "user") {
204
204
  if (hasProjectContexts()) {
205
- console.log(`Project contexts available: run 'ccst --in-project' to manage`);
205
+ console.log(`💡 Project contexts available: run 'ccst --in-project' to manage`);
206
206
  }
207
207
  if (hasLocalContexts()) {
208
- console.log(`Local contexts available: run 'ccst --local' to manage`);
208
+ console.log(`💡 Local contexts available: run 'ccst --local' to manage`);
209
209
  }
210
210
  }
211
211
  if (contexts.length === 0) {
212
- const label = this.settingsLevel === "user" ? "User" : this.settingsLevel === "project" ? "Project" : "Local";
212
+ const label = this.settingsLevel === "user" ? "👤 User" : this.settingsLevel === "project" ? "📁 Project" : "💻 Local";
213
213
  console.log(`${label} contexts: No contexts found. Create one with: ccst -n <name>`);
214
214
  return;
215
215
  }
216
- const label = this.settingsLevel === "user" ? "User" : this.settingsLevel === "project" ? "Project" : "Local";
217
- console.log(`${label} contexts:`);
216
+ const label = this.settingsLevel === "user" ? "👤 User" : this.settingsLevel === "project" ? "📁 Project" : "💻 Local";
217
+ console.log(`${colors.bold(colors.cyan(label))} contexts:`);
218
218
  for (const ctx of contexts) {
219
219
  if (ctx === current) {
220
220
  console.log(` ${colors.bold(colors.green(ctx))} ${colors.dim("(current)")}`);
@@ -291,7 +291,7 @@ export class ContextManager {
291
291
  const entry = mergePermissions(targetJson, sourceJson, source);
292
292
  await writeJson(targetPath, targetJson);
293
293
  await this.appendHistory(target, entry);
294
- console.log(`Merged ${entry.mergedItems.length} permissions from '${source}' into '${target}'`);
294
+ console.log(`✅ Merged ${entry.mergedItems.length} permissions from '${colors.green(source)}' into '${colors.bold(colors.green(target))}'`);
295
295
  }
296
296
 
297
297
  public async mergeFromFull(target: string, source: string): Promise<void> {
@@ -299,7 +299,7 @@ export class ContextManager {
299
299
  const entry = mergeFull(targetJson, sourceJson, source);
300
300
  await writeJson(targetPath, targetJson);
301
301
  await this.appendHistory(target, entry);
302
- console.log(`Full merge completed: ${entry.mergedItems.length} items from '${source}' into '${target}'`);
302
+ console.log(`✅ Full merge completed: ${entry.mergedItems.length} items from '${colors.green(source)}' into '${colors.bold(colors.green(target))}'`);
303
303
  }
304
304
 
305
305
  public async unmergeFrom(target: string, source: string, mergeFullFlag: boolean): Promise<void> {
@@ -312,7 +312,7 @@ export class ContextManager {
312
312
  const nextEntries = unmergePermissions(targetJson, entries, source);
313
313
  await writeJson(targetPath, targetJson);
314
314
  await saveHistory(this.contextsDir, contextName, nextEntries);
315
- console.log(`Removed permissions previously merged from '${source}' in '${target}'`);
315
+ console.log(`✅ Removed permissions previously merged from '${colors.red(source)}' in '${colors.bold(colors.green(target))}'`);
316
316
  }
317
317
 
318
318
  public async unmergeFromFull(target: string, source: string): Promise<void> {
@@ -321,7 +321,7 @@ export class ContextManager {
321
321
  const nextEntries = unmergeFull(targetJson, entries, source);
322
322
  await writeJson(targetPath, targetJson);
323
323
  await saveHistory(this.contextsDir, contextName, nextEntries);
324
- console.log(`Removed all settings previously merged from '${source}' in '${target}'`);
324
+ console.log(`✅ Removed all settings previously merged from '${colors.red(source)}' in '${colors.bold(colors.green(target))}'`);
325
325
  }
326
326
 
327
327
  public async showMergeHistory(name?: string): Promise<void> {
@@ -140,9 +140,13 @@ export const formatHistory = (contextName: string, history: MergeHistory): strin
140
140
  return `No merge history for ${contextName}`;
141
141
  }
142
142
  const lines: string[] = [];
143
- lines.push(`Merge history for ${contextName}:`);
144
- history.forEach((entry, index) => {
145
- lines.push(` ${index + 1}. ${entry.source} (${entry.mergedItems.length} items) at ${entry.timestamp}`);
146
- });
143
+ lines.push(`📋 Merge history for context '${contextName}':`);
144
+ lines.push("");
145
+ for (const entry of history) {
146
+ lines.push(` 📅 ${entry.timestamp}`);
147
+ lines.push(` 📁 Source: ${entry.source}`);
148
+ lines.push(` 📝 Merged ${entry.mergedItems.length} items`);
149
+ lines.push("");
150
+ }
147
151
  return lines.join("\n");
148
152
  };
package/src/index.ts CHANGED
@@ -42,7 +42,83 @@ const main = async (): Promise<void> => {
42
42
  .option("--unmerge <source>", "remove permissions merged from source")
43
43
  .option("--merge-history", "show merge history")
44
44
  .option("--merge-full", "merge full settings")
45
- .allowExcessArguments(false);
45
+ .allowExcessArguments(false)
46
+ .action(async (context: string | undefined, options: Record<string, unknown>) => {
47
+ if (options.completions) {
48
+ completionsCommand(options.completions as string);
49
+ return;
50
+ }
51
+ const level = resolveSettingsLevel(options);
52
+ const manager = new ContextManager(getPaths(level));
53
+ if (options.current) {
54
+ const current = await manager.getCurrentContext();
55
+ if (current) {
56
+ console.log(current);
57
+ }
58
+ return;
59
+ }
60
+ if (options.unset) {
61
+ await unsetCommand(manager);
62
+ return;
63
+ }
64
+ if (options.delete) {
65
+ await deleteCommand(manager, context);
66
+ return;
67
+ }
68
+ if (options.rename) {
69
+ await renameCommand(manager, context);
70
+ return;
71
+ }
72
+ if (options.new) {
73
+ if (!context) {
74
+ await manager.interactiveCreateContext();
75
+ return;
76
+ }
77
+ await createCommand(manager, context);
78
+ return;
79
+ }
80
+ if (options.edit) {
81
+ await editCommand(manager, context);
82
+ return;
83
+ }
84
+ if (options.show) {
85
+ await showCommand(manager, context);
86
+ return;
87
+ }
88
+ if (options.export) {
89
+ await exportCommand(manager, context);
90
+ return;
91
+ }
92
+ if (options.import) {
93
+ await importCommand(manager, context);
94
+ return;
95
+ }
96
+ if (options.mergeFrom) {
97
+ await mergeCommand(manager, options.mergeFrom as string, context, options.mergeFull as boolean);
98
+ return;
99
+ }
100
+ if (options.unmerge) {
101
+ await unmergeCommand(manager, options.unmerge as string, context, options.mergeFull as boolean);
102
+ return;
103
+ }
104
+ if (options.mergeHistory) {
105
+ await mergeHistoryCommand(manager, context);
106
+ return;
107
+ }
108
+ if (context === "-") {
109
+ await switchPreviousCommand(manager);
110
+ return;
111
+ }
112
+ if (context) {
113
+ await switchCommand(manager, context);
114
+ return;
115
+ }
116
+ if (process.env.CCTX_INTERACTIVE === "1") {
117
+ await manager.interactiveSelect();
118
+ return;
119
+ }
120
+ await listCommand(manager, options.quiet as boolean);
121
+ });
46
122
  const importCommandGroup = program.command("import").description("import profiles");
47
123
  importCommandGroup
48
124
  .command("ccs")
@@ -65,85 +141,6 @@ const main = async (): Promise<void> => {
65
141
  } catch {
66
142
  return;
67
143
  }
68
- const options = program.opts();
69
- const [context] = program.args as [string | undefined];
70
- if (context === "import") {
71
- return;
72
- }
73
- if (options.completions) {
74
- completionsCommand(options.completions);
75
- return;
76
- }
77
- const level = resolveSettingsLevel(options);
78
- const manager = new ContextManager(getPaths(level));
79
- if (options.current) {
80
- const current = await manager.getCurrentContext();
81
- if (current) {
82
- console.log(current);
83
- }
84
- return;
85
- }
86
- if (options.unset) {
87
- await unsetCommand(manager);
88
- return;
89
- }
90
- if (options.delete) {
91
- await deleteCommand(manager, context);
92
- return;
93
- }
94
- if (options.rename) {
95
- await renameCommand(manager, context);
96
- return;
97
- }
98
- if (options.new) {
99
- if (!context) {
100
- await manager.interactiveCreateContext();
101
- return;
102
- }
103
- await createCommand(manager, context);
104
- return;
105
- }
106
- if (options.edit) {
107
- await editCommand(manager, context);
108
- return;
109
- }
110
- if (options.show) {
111
- await showCommand(manager, context);
112
- return;
113
- }
114
- if (options.export) {
115
- await exportCommand(manager, context);
116
- return;
117
- }
118
- if (options.import) {
119
- await importCommand(manager, context);
120
- return;
121
- }
122
- if (options.mergeFrom) {
123
- await mergeCommand(manager, options.mergeFrom, context, options.mergeFull);
124
- return;
125
- }
126
- if (options.unmerge) {
127
- await unmergeCommand(manager, options.unmerge, context, options.mergeFull);
128
- return;
129
- }
130
- if (options.mergeHistory) {
131
- await mergeHistoryCommand(manager, context);
132
- return;
133
- }
134
- if (context === "-") {
135
- await switchPreviousCommand(manager);
136
- return;
137
- }
138
- if (context) {
139
- await switchCommand(manager, context);
140
- return;
141
- }
142
- if (process.env.CCTX_INTERACTIVE === "1") {
143
- await manager.interactiveSelect();
144
- return;
145
- }
146
- await listCommand(manager, options.quiet);
147
144
  };
148
145
 
149
146
  await main();