claude-switch-profile 1.0.2 → 1.4.0

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.
@@ -0,0 +1,155 @@
1
+ import { existsSync, readFileSync, writeFileSync, cpSync, rmSync, mkdirSync, lstatSync, copyFileSync, renameSync } from 'node:fs';
2
+ import { join, dirname, basename } from 'node:path';
3
+ import { CLAUDE_DIR, MANAGED_ITEMS, SOURCE_FILE } from './constants.js';
4
+
5
+ const SKIP_PATTERNS = ['.venv', 'node_modules', '__pycache__', '.git'];
6
+ const skipHeavyDirs = (src) => !SKIP_PATTERNS.includes(basename(src));
7
+
8
+ // Rename-based move with EXDEV fallback (filtered copy + delete)
9
+ const moveItem = (src, dest) => {
10
+ mkdirSync(dirname(dest), { recursive: true });
11
+ if (existsSync(dest)) rmSync(dest, { recursive: true, force: true });
12
+ try {
13
+ renameSync(src, dest);
14
+ } catch (err) {
15
+ if (err.code === 'EXDEV') {
16
+ cpSync(src, dest, { recursive: true, filter: skipHeavyDirs });
17
+ rmSync(src, { recursive: true, force: true });
18
+ } else throw err;
19
+ }
20
+ };
21
+
22
+ // Read current managed items from ~/.claude — returns map of {item: claudeDir/item}
23
+ export const readCurrentItems = () => {
24
+ const itemMap = {};
25
+ for (const item of MANAGED_ITEMS) {
26
+ const itemPath = join(CLAUDE_DIR, item);
27
+ try {
28
+ if (existsSync(itemPath)) {
29
+ itemMap[item] = itemPath;
30
+ }
31
+ } catch {
32
+ // Item doesn't exist or isn't readable — skip
33
+ }
34
+ }
35
+ return itemMap;
36
+ };
37
+
38
+ // Remove all managed items (dirs/files) from ~/.claude
39
+ export const removeItems = () => {
40
+ for (const item of MANAGED_ITEMS) {
41
+ const itemPath = join(CLAUDE_DIR, item);
42
+ try {
43
+ if (existsSync(itemPath)) {
44
+ rmSync(itemPath, { recursive: true, force: true });
45
+ }
46
+ } catch {
47
+ // Already gone — skip
48
+ }
49
+ }
50
+ };
51
+
52
+ // Copy managed items from ~/.claude into profileDir, write source.json manifest (non-destructive)
53
+ export const copyItems = (profileDir) => {
54
+ const sourceMap = {};
55
+ for (const item of MANAGED_ITEMS) {
56
+ const itemPath = join(CLAUDE_DIR, item);
57
+ try {
58
+ if (!existsSync(itemPath)) continue;
59
+
60
+ const dest = join(profileDir, item);
61
+ const stat = lstatSync(itemPath);
62
+
63
+ if (stat.isDirectory()) {
64
+ rmSync(dest, { recursive: true, force: true });
65
+ cpSync(itemPath, dest, { recursive: true });
66
+ } else if (stat.isFile()) {
67
+ copyFileSync(itemPath, dest);
68
+ }
69
+ sourceMap[item] = dest;
70
+ } catch {
71
+ // Not readable — skip
72
+ }
73
+ }
74
+ writeFileSync(join(profileDir, SOURCE_FILE), JSON.stringify(sourceMap, null, 2) + '\n');
75
+ return sourceMap;
76
+ };
77
+
78
+ // Backward-compatible alias for save.js
79
+ export const saveItems = copyItems;
80
+
81
+ // Read source.json from profileDir and copy items into ~/.claude (non-destructive)
82
+ export const restoreItems = (profileDir) => {
83
+ const sourcePath = join(profileDir, SOURCE_FILE);
84
+ if (!existsSync(sourcePath)) return {};
85
+
86
+ const sourceMap = JSON.parse(readFileSync(sourcePath, 'utf-8'));
87
+
88
+ for (const [item, srcPath] of Object.entries(sourceMap)) {
89
+ if (!MANAGED_ITEMS.includes(item)) continue;
90
+
91
+ const dest = join(CLAUDE_DIR, item);
92
+
93
+ try {
94
+ if (existsSync(dest)) rmSync(dest, { recursive: true, force: true });
95
+ } catch {
96
+ // fine
97
+ }
98
+
99
+ // Copy from profile (or external legacy path) into ~/.claude
100
+ if (existsSync(srcPath)) {
101
+ try {
102
+ const stat = lstatSync(srcPath);
103
+ if (stat.isDirectory()) {
104
+ cpSync(srcPath, dest, { recursive: true });
105
+ } else if (stat.isFile()) {
106
+ copyFileSync(srcPath, dest);
107
+ }
108
+ } catch {
109
+ // skip unreadable
110
+ }
111
+ }
112
+ }
113
+
114
+ return sourceMap;
115
+ };
116
+
117
+ // Move items from ~/.claude → profileDir (destructive — items leave ~/.claude)
118
+ export const moveItemsToProfile = (profileDir) => {
119
+ mkdirSync(profileDir, { recursive: true });
120
+ const sourceMap = {};
121
+ for (const item of MANAGED_ITEMS) {
122
+ const itemPath = join(CLAUDE_DIR, item);
123
+ if (!existsSync(itemPath)) continue;
124
+ try {
125
+ const dest = join(profileDir, item);
126
+ moveItem(itemPath, dest);
127
+ sourceMap[item] = dest;
128
+ } catch {
129
+ // skip
130
+ }
131
+ }
132
+ writeFileSync(join(profileDir, SOURCE_FILE), JSON.stringify(sourceMap, null, 2) + '\n');
133
+ return sourceMap;
134
+ };
135
+
136
+ // Move items from profileDir → ~/.claude (destructive — items leave profileDir)
137
+ export const moveItemsToClaude = (profileDir) => {
138
+ const sourcePath = join(profileDir, SOURCE_FILE);
139
+ if (!existsSync(sourcePath)) return {};
140
+ const sourceMap = JSON.parse(readFileSync(sourcePath, 'utf-8'));
141
+
142
+ for (const [item] of Object.entries(sourceMap)) {
143
+ if (!MANAGED_ITEMS.includes(item)) continue;
144
+ const src = join(profileDir, item);
145
+ const dest = join(CLAUDE_DIR, item);
146
+ if (!existsSync(src)) continue;
147
+ try {
148
+ if (existsSync(dest)) rmSync(dest, { recursive: true, force: true });
149
+ moveItem(src, dest);
150
+ } catch {
151
+ // skip
152
+ }
153
+ }
154
+ return sourceMap;
155
+ };
@@ -0,0 +1,192 @@
1
+ import { LAUNCH_ANTHROPIC_ENV_KEYS, LAUNCH_CONFIG_ENV } from './constants.js';
2
+
3
+ const RESERVED_PARENT_ENV_KEYS = new Set(['CLAUDECODE', LAUNCH_CONFIG_ENV]);
4
+ const ANTHROPIC_KEY_SET = new Set(LAUNCH_ANTHROPIC_ENV_KEYS);
5
+
6
+ // Claude Code internal env vars that carry session/auth state between instances.
7
+ // These MUST be stripped to prevent a running default instance from leaking
8
+ // credentials into a profile-specific launch.
9
+ const CLAUDE_SESSION_ENV_PREFIXES = ['CLAUDE_CODE_OAUTH', 'CLAUDE_CODE_SESSION'];
10
+ const CLAUDE_SESSION_ENV_EXACT = new Set([
11
+ 'CLAUDE_CODE_ENTRYPOINT',
12
+ 'CLAUDE_CODE_REMOTE',
13
+ 'CLAUDE_CODE_REMOTE_SESSION_ID',
14
+ 'CLAUDE_CODE_CONTAINER_ID',
15
+ 'CLAUDE_CODE_API_KEY_FILE_DESCRIPTOR',
16
+ ]);
17
+
18
+ const toUpperKey = (key) => String(key || '').toUpperCase();
19
+ const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
20
+
21
+ const sanitizeValue = (value) => {
22
+ if (value === undefined || value === null) return undefined;
23
+ return String(value);
24
+ };
25
+
26
+ const collectAnthropicValues = (source = {}) => {
27
+ const collected = {};
28
+
29
+ for (const [rawKey, rawValue] of Object.entries(source || {})) {
30
+ const key = toUpperKey(rawKey);
31
+ if (!ANTHROPIC_KEY_SET.has(key)) continue;
32
+
33
+ const value = sanitizeValue(rawValue);
34
+ if (value === undefined) continue;
35
+
36
+ collected[key] = value;
37
+ }
38
+
39
+ return collected;
40
+ };
41
+
42
+ export const sanitizeInheritedLaunchEnv = (env = {}) => {
43
+ const sanitized = {};
44
+
45
+ for (const [key, value] of Object.entries(env || {})) {
46
+ if (RESERVED_PARENT_ENV_KEYS.has(toUpperKey(key))) continue;
47
+ sanitized[key] = value;
48
+ }
49
+
50
+ return sanitized;
51
+ };
52
+
53
+ const stripAnthropicKeys = (env = {}) => {
54
+ const sanitized = {};
55
+
56
+ for (const [key, value] of Object.entries(env || {})) {
57
+ const upper = toUpperKey(key);
58
+ // Strip all ANTHROPIC_* keys (will be re-added from profile settings)
59
+ if (upper.startsWith('ANTHROPIC_')) continue;
60
+ // Strip Claude Code session/auth env vars to prevent cross-instance leakage
61
+ if (CLAUDE_SESSION_ENV_EXACT.has(upper)) continue;
62
+ if (CLAUDE_SESSION_ENV_PREFIXES.some((prefix) => upper.startsWith(prefix))) continue;
63
+ sanitized[key] = value;
64
+ }
65
+
66
+ return sanitized;
67
+ };
68
+
69
+ export const parseSettingsLaunchEnv = (settingsInput) => {
70
+ if (!settingsInput) return {};
71
+
72
+ let settings = settingsInput;
73
+
74
+ if (typeof settingsInput === 'string') {
75
+ settings = JSON.parse(settingsInput);
76
+ }
77
+
78
+ if (!settings || typeof settings !== 'object' || Array.isArray(settings)) {
79
+ return {};
80
+ }
81
+
82
+ const envBlock = settings.env;
83
+ if (!envBlock || typeof envBlock !== 'object' || Array.isArray(envBlock)) {
84
+ return {};
85
+ }
86
+
87
+ return collectAnthropicValues(envBlock);
88
+ };
89
+
90
+ const stripUnquotedInlineComment = (value) => {
91
+ const trimmed = value.trim();
92
+ if (!trimmed) return trimmed;
93
+
94
+ if (trimmed.startsWith("'") || trimmed.startsWith('"')) {
95
+ return trimmed;
96
+ }
97
+
98
+ const commentIndex = trimmed.indexOf('#');
99
+ if (commentIndex === -1) return trimmed;
100
+
101
+ return trimmed.slice(0, commentIndex).trimEnd();
102
+ };
103
+
104
+ const unquoteDotEnvValue = (value) => {
105
+ const withoutInlineComment = stripUnquotedInlineComment(value);
106
+ const trimmed = withoutInlineComment.trim();
107
+ if (trimmed.length < 2) return trimmed;
108
+
109
+ const startsWithSingle = trimmed.startsWith("'") && trimmed.endsWith("'");
110
+ const startsWithDouble = trimmed.startsWith('"') && trimmed.endsWith('"');
111
+
112
+ if (!startsWithSingle && !startsWithDouble) return trimmed;
113
+
114
+ return trimmed.slice(1, -1);
115
+ };
116
+
117
+ export const parseDotEnvLaunchEnv = (content = '') => {
118
+ const parsed = {};
119
+
120
+ for (const rawLine of String(content).split(/\r?\n/)) {
121
+ const line = rawLine.trim();
122
+ if (!line || line.startsWith('#')) continue;
123
+
124
+ const match = line.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
125
+ if (!match) continue;
126
+
127
+ const [, rawKey, rawValue] = match;
128
+ const key = toUpperKey(rawKey);
129
+ if (!ANTHROPIC_KEY_SET.has(key)) continue;
130
+
131
+ parsed[key] = unquoteDotEnvValue(rawValue);
132
+ }
133
+
134
+ return parsed;
135
+ };
136
+
137
+ const resolveAnthropicValuesByPrecedence = ({ parentValues, dotEnvValues, settingsValues, launchOverrides }) => {
138
+ // Highest -> lowest precedence:
139
+ // launchOverrides > profile settings.env > profile .env (allowlist) > parent env
140
+ const resolvedValues = {};
141
+ const resolvedSources = {};
142
+
143
+ const sources = [
144
+ ['parent', parentValues],
145
+ ['profile-dotenv', dotEnvValues],
146
+ ['profile-settings', settingsValues],
147
+ ['launch-override', launchOverrides],
148
+ ];
149
+
150
+ for (const [sourceName, sourceValues] of sources) {
151
+ for (const key of LAUNCH_ANTHROPIC_ENV_KEYS) {
152
+ if (!hasOwn(sourceValues, key)) continue;
153
+ resolvedValues[key] = sourceValues[key];
154
+ resolvedSources[key] = sourceName;
155
+ }
156
+ }
157
+
158
+ return { resolvedValues, resolvedSources };
159
+ };
160
+
161
+ export const buildEffectiveLaunchEnv = ({
162
+ parentEnv = process.env,
163
+ profileSettingsEnv = {},
164
+ profileDotEnvEnv = {},
165
+ launchOverrides = {},
166
+ } = {}) => {
167
+ const sanitizedParentEnv = sanitizeInheritedLaunchEnv(parentEnv);
168
+ const baseEnv = stripAnthropicKeys(sanitizedParentEnv);
169
+
170
+ const parentValues = collectAnthropicValues(parentEnv);
171
+ const dotEnvValues = collectAnthropicValues(profileDotEnvEnv);
172
+ const settingsValues = collectAnthropicValues(profileSettingsEnv);
173
+ const overrideValues = collectAnthropicValues(launchOverrides);
174
+
175
+ const { resolvedValues, resolvedSources } = resolveAnthropicValuesByPrecedence({
176
+ parentValues,
177
+ dotEnvValues,
178
+ settingsValues,
179
+ launchOverrides: overrideValues,
180
+ });
181
+
182
+ return {
183
+ launchEnv: {
184
+ ...baseEnv,
185
+ ...resolvedValues,
186
+ },
187
+ diagnostics: {
188
+ anthropicKeys: Object.keys(resolvedValues),
189
+ anthropicKeySources: resolvedSources,
190
+ },
191
+ };
192
+ };
@@ -0,0 +1,24 @@
1
+ import { execFileSync } from 'node:child_process';
2
+
3
+ export const isWindows = process.platform === 'win32';
4
+
5
+ /**
6
+ * Check if a process with the given name is running.
7
+ * Windows: uses tasklist. Unix: uses pgrep.
8
+ */
9
+ export const findProcess = (name) => {
10
+ try {
11
+ if (isWindows) {
12
+ const result = execFileSync('tasklist', ['/FI', `IMAGENAME eq ${name}.exe`, '/NH'], {
13
+ encoding: 'utf-8',
14
+ stdio: ['pipe', 'pipe', 'pipe'],
15
+ });
16
+ return result.includes(`${name}.exe`);
17
+ } else {
18
+ const result = execFileSync('pgrep', ['-x', name], { encoding: 'utf-8' });
19
+ return result.trim().length > 0;
20
+ }
21
+ } catch {
22
+ return false;
23
+ }
24
+ };
@@ -1,6 +1,14 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- import { PROFILES_DIR, ACTIVE_FILE, PROFILES_META } from './constants.js';
3
+ import {
4
+ PROFILES_DIR,
5
+ ACTIVE_FILE,
6
+ PROFILES_META,
7
+ CLAUDE_DIR,
8
+ DEFAULT_PROFILE,
9
+ PROFILES_SCHEMA_VERSION,
10
+ RUNTIMES_DIR,
11
+ } from './constants.js';
4
12
 
5
13
  export const ensureProfilesDir = () => {
6
14
  if (!existsSync(PROFILES_DIR)) {
@@ -8,15 +16,69 @@ export const ensureProfilesDir = () => {
8
16
  }
9
17
  };
10
18
 
19
+ const normalizeProfileMeta = (name, meta = {}) => {
20
+ const created = typeof meta.created === 'string' ? meta.created : new Date().toISOString();
21
+ const description = typeof meta.description === 'string' ? meta.description : '';
22
+ const mode =
23
+ meta.mode === 'legacy' || meta.mode === 'account-session'
24
+ ? meta.mode
25
+ : name === DEFAULT_PROFILE
26
+ ? 'legacy'
27
+ : 'account-session';
28
+ const runtimeDir = typeof meta.runtimeDir === 'string' && meta.runtimeDir ? meta.runtimeDir : getRuntimeDir(name);
29
+ const runtimeInitializedAt = typeof meta.runtimeInitializedAt === 'string' ? meta.runtimeInitializedAt : null;
30
+ const lastLaunchAt = typeof meta.lastLaunchAt === 'string' ? meta.lastLaunchAt : null;
31
+
32
+ return {
33
+ ...meta,
34
+ created,
35
+ description,
36
+ mode,
37
+ runtimeDir,
38
+ runtimeInitializedAt,
39
+ lastLaunchAt,
40
+ };
41
+ };
42
+
43
+ const normalizeProfiles = (raw) => {
44
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return {};
45
+ const legacyProfiles = raw.profiles && typeof raw.profiles === 'object' ? raw.profiles : raw;
46
+
47
+ const normalized = {};
48
+ for (const [name, meta] of Object.entries(legacyProfiles)) {
49
+ if (!meta || typeof meta !== 'object' || Array.isArray(meta)) continue;
50
+ normalized[name] = normalizeProfileMeta(name, meta);
51
+ }
52
+
53
+ return normalized;
54
+ };
55
+
11
56
  export const readProfiles = () => {
12
57
  const metaPath = join(PROFILES_DIR, PROFILES_META);
13
58
  if (!existsSync(metaPath)) return {};
14
- return JSON.parse(readFileSync(metaPath, 'utf-8'));
59
+
60
+ try {
61
+ const raw = JSON.parse(readFileSync(metaPath, 'utf-8'));
62
+ return normalizeProfiles(raw);
63
+ } catch {
64
+ return {};
65
+ }
15
66
  };
16
67
 
17
- export const writeProfiles = (data) => {
68
+ export const writeProfiles = (profiles) => {
18
69
  ensureProfilesDir();
19
- writeFileSync(join(PROFILES_DIR, PROFILES_META), JSON.stringify(data, null, 2) + '\n');
70
+
71
+ const normalized = {};
72
+ for (const [name, meta] of Object.entries(profiles || {})) {
73
+ normalized[name] = normalizeProfileMeta(name, meta);
74
+ }
75
+
76
+ const payload = {
77
+ version: PROFILES_SCHEMA_VERSION,
78
+ profiles: normalized,
79
+ };
80
+
81
+ writeFileSync(join(PROFILES_DIR, PROFILES_META), JSON.stringify(payload, null, 2) + '\n');
20
82
  };
21
83
 
22
84
  export const getActive = () => {
@@ -30,13 +92,35 @@ export const setActive = (name) => {
30
92
  writeFileSync(join(PROFILES_DIR, ACTIVE_FILE), name + '\n');
31
93
  };
32
94
 
95
+ export const clearActive = () => {
96
+ const activePath = join(PROFILES_DIR, ACTIVE_FILE);
97
+ try {
98
+ if (existsSync(activePath)) unlinkSync(activePath);
99
+ } catch {
100
+ // Best effort
101
+ }
102
+ };
103
+
104
+ const PREVIOUS_FILE = '.previous';
105
+
106
+ export const getPrevious = () => {
107
+ const prevPath = join(PROFILES_DIR, PREVIOUS_FILE);
108
+ if (!existsSync(prevPath)) return null;
109
+ return readFileSync(prevPath, 'utf-8').trim() || null;
110
+ };
111
+
112
+ export const setPrevious = (name) => {
113
+ ensureProfilesDir();
114
+ writeFileSync(join(PROFILES_DIR, PREVIOUS_FILE), name + '\n');
115
+ };
116
+
33
117
  export const addProfile = (name, metadata = {}) => {
34
118
  const profiles = readProfiles();
35
- profiles[name] = {
119
+ profiles[name] = normalizeProfileMeta(name, {
36
120
  created: new Date().toISOString(),
37
121
  description: '',
38
122
  ...metadata,
39
- };
123
+ });
40
124
  writeProfiles(profiles);
41
125
  };
42
126
 
@@ -47,6 +131,7 @@ export const removeProfile = (name) => {
47
131
  };
48
132
 
49
133
  export const profileExists = (name) => {
134
+ if (name === DEFAULT_PROFILE) return true;
50
135
  return existsSync(getProfileDir(name));
51
136
  };
52
137
 
@@ -63,6 +148,53 @@ export const getProfileDir = (name) => {
63
148
  return join(PROFILES_DIR, name);
64
149
  };
65
150
 
151
+ export const getRuntimeDir = (name) => {
152
+ validateName(name);
153
+ return join(RUNTIMES_DIR, name);
154
+ };
155
+
156
+ export const getProfileMeta = (name) => {
157
+ const profiles = readProfiles();
158
+ return profiles[name] || null;
159
+ };
160
+
161
+ export const updateProfileMeta = (name, patch) => {
162
+ const profiles = readProfiles();
163
+ if (!profiles[name]) return null;
164
+
165
+ const next = typeof patch === 'function' ? patch({ ...profiles[name] }) : { ...profiles[name], ...patch };
166
+ profiles[name] = normalizeProfileMeta(name, next);
167
+ writeProfiles(profiles);
168
+ return profiles[name];
169
+ };
170
+
171
+ export const markRuntimeInitialized = (name, runtimeDir) => {
172
+ const now = new Date().toISOString();
173
+ return updateProfileMeta(name, {
174
+ runtimeDir,
175
+ runtimeInitializedAt: now,
176
+ lastLaunchAt: now,
177
+ mode: 'account-session',
178
+ });
179
+ };
180
+
181
+ export const markProfileLaunched = (name) => {
182
+ return updateProfileMeta(name, {
183
+ lastLaunchAt: new Date().toISOString(),
184
+ mode: 'account-session',
185
+ });
186
+ };
187
+
66
188
  export const listProfileNames = () => {
67
189
  return Object.keys(readProfiles());
68
190
  };
191
+
192
+ // Returns the directory containing a profile's actual files.
193
+ // If profile is active, items were moved to CLAUDE_DIR during switch.
194
+ // If profile is not active, items are in profileDir.
195
+ export const getEffectiveDir = (name) => {
196
+ if (name === DEFAULT_PROFILE) return CLAUDE_DIR;
197
+ const active = getActive();
198
+ if (active === name) return CLAUDE_DIR;
199
+ return getProfileDir(name);
200
+ };
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readdirSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- import { SOURCE_FILE, SYMLINK_ITEMS } from './constants.js';
3
+ import { SOURCE_FILE, MANAGED_ITEMS } from './constants.js';
4
4
 
5
5
  // Validate a profile directory
6
6
  export const validateProfile = (profileDir) => {
@@ -12,13 +12,13 @@ export const validateProfile = (profileDir) => {
12
12
 
13
13
  const sourcePath = join(profileDir, SOURCE_FILE);
14
14
  if (!existsSync(sourcePath)) {
15
- errors.push('Missing source.json — no symlink targets defined');
15
+ errors.push('Missing source.json — no managed items defined');
16
16
  }
17
17
 
18
18
  return { valid: errors.length === 0, errors };
19
19
  };
20
20
 
21
- // Check all symlink targets in sourceMap actually exist on disk
21
+ // Check all item targets in sourceMap actually exist on disk
22
22
  export const validateSourceTargets = (sourceMap) => {
23
23
  const errors = [];
24
24
  for (const [item, target] of Object.entries(sourceMap)) {
@@ -29,17 +29,15 @@ export const validateSourceTargets = (sourceMap) => {
29
29
  return { valid: errors.length === 0, errors };
30
30
  };
31
31
 
32
- // List what files/symlinks a profile contains
32
+ // List what files a profile contains
33
33
  export const listManagedItems = (profileDir) => {
34
- if (!existsSync(profileDir)) return { symlinks: [], files: [], dirs: [] };
34
+ if (!existsSync(profileDir)) return { files: [], dirs: [] };
35
35
 
36
36
  const entries = readdirSync(profileDir, { withFileTypes: true });
37
- const items = { symlinks: [], files: [], dirs: [] };
37
+ const items = { files: [], dirs: [] };
38
38
 
39
39
  for (const entry of entries) {
40
- if (entry.name === SOURCE_FILE) {
41
- items.files.push(entry.name);
42
- } else if (entry.isDirectory()) {
40
+ if (entry.isDirectory()) {
43
41
  items.dirs.push(entry.name);
44
42
  } else {
45
43
  items.files.push(entry.name);