@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
|
@@ -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(
|
|
205
|
+
console.log(`💡 Project contexts available: run 'ccst --in-project' to manage`);
|
|
206
206
|
}
|
|
207
207
|
if (hasLocalContexts()) {
|
|
208
|
-
console.log(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
144
|
-
|
|
145
|
-
|
|
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();
|