claude-multi 0.8.1 → 0.9.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.
- package/CHANGELOG.md +40 -0
- package/README.md +1 -1
- package/build/cli.js +632 -178
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -7499,22 +7499,22 @@ var init_templates = __esm(() => {
|
|
|
7499
7499
|
kimi: {
|
|
7500
7500
|
name: "kimi",
|
|
7501
7501
|
displayName: "Moonshot Kimi",
|
|
7502
|
-
description: "Kimi K2.5 models via moonshot.ai — pay-per-token only, no subscription plan",
|
|
7502
|
+
description: "Kimi K2.7 Code, K2.6, K2.5 models via moonshot.ai — pay-per-token only, no subscription plan",
|
|
7503
7503
|
settings: {
|
|
7504
7504
|
env: {
|
|
7505
7505
|
ANTHROPIC_AUTH_TOKEN: "",
|
|
7506
7506
|
ANTHROPIC_BASE_URL: "https://api.moonshot.ai/anthropic",
|
|
7507
7507
|
API_TIMEOUT_MS: "3000000",
|
|
7508
|
-
ANTHROPIC_MODEL: "kimi-k2.
|
|
7509
|
-
ANTHROPIC_DEFAULT_OPUS_MODEL: "kimi-k2.
|
|
7510
|
-
ANTHROPIC_DEFAULT_SONNET_MODEL: "kimi-k2.
|
|
7508
|
+
ANTHROPIC_MODEL: "kimi-k2.6",
|
|
7509
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: "kimi-k2.7-code",
|
|
7510
|
+
ANTHROPIC_DEFAULT_SONNET_MODEL: "kimi-k2.6",
|
|
7511
7511
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: "kimi-k2.5",
|
|
7512
7512
|
ANTHROPIC_SMALL_FAST_MODEL: "kimi-k2.5",
|
|
7513
7513
|
ENABLE_THINKING: "true",
|
|
7514
7514
|
REASONING_EFFORT: "high",
|
|
7515
7515
|
MAX_THINKING_TOKENS: "16000",
|
|
7516
7516
|
MAX_OUTPUT_TOKENS: "65536",
|
|
7517
|
-
CLAUDE_CODE_AUTO_COMPACT_WINDOW: "
|
|
7517
|
+
CLAUDE_CODE_AUTO_COMPACT_WINDOW: "262144",
|
|
7518
7518
|
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: "75"
|
|
7519
7519
|
},
|
|
7520
7520
|
includeCoAuthoredBy: false,
|
|
@@ -7652,7 +7652,14 @@ var init_errors = __esm(() => {
|
|
|
7652
7652
|
});
|
|
7653
7653
|
|
|
7654
7654
|
// src/constants.ts
|
|
7655
|
-
|
|
7655
|
+
function canConvertSyncMode(from, to) {
|
|
7656
|
+
return SYNC_MODE_ORDER.indexOf(to) > SYNC_MODE_ORDER.indexOf(from);
|
|
7657
|
+
}
|
|
7658
|
+
function availableSyncModeConversions(current) {
|
|
7659
|
+
const idx = SYNC_MODE_ORDER.indexOf(current);
|
|
7660
|
+
return SYNC_MODE_ORDER.slice(idx + 1);
|
|
7661
|
+
}
|
|
7662
|
+
var MigrationStatus, PluginCategory, McpServerType, CopyOption, SyncMode, SYNC_MODE_ORDER, PluginAction, McpAction;
|
|
7656
7663
|
var init_constants = __esm(() => {
|
|
7657
7664
|
MigrationStatus = {
|
|
7658
7665
|
Completed: "completed",
|
|
@@ -7676,6 +7683,12 @@ var init_constants = __esm(() => {
|
|
|
7676
7683
|
All: "all",
|
|
7677
7684
|
Mcp: "mcp"
|
|
7678
7685
|
};
|
|
7686
|
+
SyncMode = {
|
|
7687
|
+
Auto: "auto",
|
|
7688
|
+
HalfManual: "half-manual",
|
|
7689
|
+
FullManual: "full-manual"
|
|
7690
|
+
};
|
|
7691
|
+
SYNC_MODE_ORDER = [SyncMode.Auto, SyncMode.HalfManual, SyncMode.FullManual];
|
|
7679
7692
|
PluginAction = {
|
|
7680
7693
|
List: "list",
|
|
7681
7694
|
Enable: "enable",
|
|
@@ -10080,10 +10093,12 @@ var exports_config = {};
|
|
|
10080
10093
|
__export(exports_config, {
|
|
10081
10094
|
writeClaudeSettings: () => writeClaudeSettings,
|
|
10082
10095
|
validatePluginOperation: () => validatePluginOperation,
|
|
10096
|
+
updateInstanceSyncMode: () => updateInstanceSyncMode,
|
|
10083
10097
|
updateInstanceAutoSync: () => updateInstanceAutoSync,
|
|
10084
10098
|
unsyncPluginsAndSkills: () => unsyncPluginsAndSkills,
|
|
10085
10099
|
syncProviderTemplateForInstance: () => syncProviderTemplateForInstance,
|
|
10086
10100
|
syncPluginsAndSkills: () => syncPluginsAndSkills,
|
|
10101
|
+
syncModeLabel: () => syncModeLabel,
|
|
10087
10102
|
setTestDefaultClaudeDir: () => setTestDefaultClaudeDir,
|
|
10088
10103
|
setTestConfigDir: () => setTestConfigDir,
|
|
10089
10104
|
setEnabledPlugins: () => setEnabledPlugins,
|
|
@@ -10103,10 +10118,13 @@ __export(exports_config, {
|
|
|
10103
10118
|
listDefaultPlugins: () => listDefaultPlugins,
|
|
10104
10119
|
listAvailablePlugins: () => listAvailablePlugins,
|
|
10105
10120
|
isPluginsSymlinked: () => isPluginsSymlinked,
|
|
10121
|
+
isHalfManualSync: () => isHalfManualSync,
|
|
10106
10122
|
isClaudeCodeRunning: () => isClaudeCodeRunning,
|
|
10107
10123
|
initializeInstanceState: () => initializeInstanceState,
|
|
10108
10124
|
hasDefaultMcpConfig: () => hasDefaultMcpConfig,
|
|
10109
10125
|
hasDefaultClaudeConfig: () => hasDefaultClaudeConfig,
|
|
10126
|
+
halfSyncPluginsAndSkills: () => halfSyncPluginsAndSkills,
|
|
10127
|
+
getSyncMode: () => getSyncMode,
|
|
10110
10128
|
getMcpServersFromPlugins: () => getMcpServersFromPlugins,
|
|
10111
10129
|
getInstanceMcpServers: () => getInstanceMcpServers,
|
|
10112
10130
|
getInstance: () => getInstance,
|
|
@@ -10146,6 +10164,23 @@ function getConfigDir() {
|
|
|
10146
10164
|
function getConfigFile() {
|
|
10147
10165
|
return join4(getConfigDir(), "config.json");
|
|
10148
10166
|
}
|
|
10167
|
+
function getSyncMode(instance) {
|
|
10168
|
+
if (instance.syncMode && VALID_SYNC_MODES.has(instance.syncMode))
|
|
10169
|
+
return instance.syncMode;
|
|
10170
|
+
if (instance.autoSync === false)
|
|
10171
|
+
return SyncMode.FullManual;
|
|
10172
|
+
return SyncMode.Auto;
|
|
10173
|
+
}
|
|
10174
|
+
function syncModeLabel(mode) {
|
|
10175
|
+
switch (mode) {
|
|
10176
|
+
case SyncMode.Auto:
|
|
10177
|
+
return "Auto-sync (symlink dirs)";
|
|
10178
|
+
case SyncMode.HalfManual:
|
|
10179
|
+
return "Half-manual (symlink items)";
|
|
10180
|
+
case SyncMode.FullManual:
|
|
10181
|
+
return "Full-manual (independent copy)";
|
|
10182
|
+
}
|
|
10183
|
+
}
|
|
10149
10184
|
async function copyDirRecursive(source, target) {
|
|
10150
10185
|
if (!existsSync4(target)) {
|
|
10151
10186
|
await mkdir(target, { recursive: true });
|
|
@@ -10262,6 +10297,34 @@ async function updateInstanceAutoSync(name, autoSync) {
|
|
|
10262
10297
|
}
|
|
10263
10298
|
const inst = config.instances[index];
|
|
10264
10299
|
inst.autoSync = autoSync;
|
|
10300
|
+
inst.syncMode = autoSync ? SyncMode.Auto : SyncMode.FullManual;
|
|
10301
|
+
await saveConfig(config);
|
|
10302
|
+
return inst;
|
|
10303
|
+
}
|
|
10304
|
+
async function updateInstanceSyncMode(name, newMode) {
|
|
10305
|
+
const config = await loadConfig();
|
|
10306
|
+
const index = config.instances.findIndex((i) => i.name === name);
|
|
10307
|
+
if (index === -1) {
|
|
10308
|
+
return null;
|
|
10309
|
+
}
|
|
10310
|
+
const inst = config.instances[index];
|
|
10311
|
+
const currentMode = getSyncMode(inst);
|
|
10312
|
+
if (currentMode === newMode)
|
|
10313
|
+
return inst;
|
|
10314
|
+
if (!canConvertSyncMode(currentMode, newMode)) {
|
|
10315
|
+
throw new ClaudeMultiError(ErrorCode.SYMLINK_CONFLICT, `Cannot convert from ${syncModeLabel(currentMode)} to ${syncModeLabel(newMode)}. Only downgrades are allowed.`);
|
|
10316
|
+
}
|
|
10317
|
+
if (newMode === SyncMode.Auto) {
|
|
10318
|
+
await syncPluginsAndSkills(inst.configDir);
|
|
10319
|
+
} else if (newMode === SyncMode.HalfManual) {
|
|
10320
|
+
if (currentMode === SyncMode.Auto) {
|
|
10321
|
+
await halfSyncPluginsAndSkills(inst.configDir);
|
|
10322
|
+
}
|
|
10323
|
+
} else if (newMode === SyncMode.FullManual) {
|
|
10324
|
+
await unsyncPluginsAndSkills(inst.configDir);
|
|
10325
|
+
}
|
|
10326
|
+
inst.syncMode = newMode;
|
|
10327
|
+
inst.autoSync = newMode === SyncMode.Auto ? true : false;
|
|
10265
10328
|
await saveConfig(config);
|
|
10266
10329
|
return inst;
|
|
10267
10330
|
}
|
|
@@ -10303,8 +10366,20 @@ function detectBrokenSymlinks(configDir) {
|
|
|
10303
10366
|
try {
|
|
10304
10367
|
const stats = lstatSync(targetPath);
|
|
10305
10368
|
result.all.push(dir);
|
|
10306
|
-
if (stats.isSymbolicLink()
|
|
10307
|
-
|
|
10369
|
+
if (stats.isSymbolicLink()) {
|
|
10370
|
+
if (isBrokenSymlink(targetPath)) {
|
|
10371
|
+
result.broken.push(dir);
|
|
10372
|
+
}
|
|
10373
|
+
} else if (stats.isDirectory()) {
|
|
10374
|
+
try {
|
|
10375
|
+
const entries = readdirSync2(targetPath, { withFileTypes: true });
|
|
10376
|
+
for (const entry of entries) {
|
|
10377
|
+
const entryPath = join4(targetPath, entry.name);
|
|
10378
|
+
if (isBrokenSymlink(entryPath)) {
|
|
10379
|
+
result.broken.push(`${dir}/${entry.name}`);
|
|
10380
|
+
}
|
|
10381
|
+
}
|
|
10382
|
+
} catch {}
|
|
10308
10383
|
}
|
|
10309
10384
|
} catch {}
|
|
10310
10385
|
}
|
|
@@ -10340,7 +10415,7 @@ async function copySettingsFromDefault(targetConfigDir) {
|
|
|
10340
10415
|
const targetSettings = join4(targetConfigDir, "settings.json");
|
|
10341
10416
|
await writeFile3(targetSettings, JSON.stringify(safeSettings, null, 2), "utf-8");
|
|
10342
10417
|
}
|
|
10343
|
-
async function copyAllFromDefault(targetConfigDir,
|
|
10418
|
+
async function copyAllFromDefault(targetConfigDir, syncModeOrAutoSync = false) {
|
|
10344
10419
|
const defaultDir = getDefaultClaudeDir();
|
|
10345
10420
|
if (!existsSync4(defaultDir)) {
|
|
10346
10421
|
throw new ClaudeMultiError(ErrorCode.DEFAULT_DIR_NOT_FOUND, "Default Claude directory not found");
|
|
@@ -10348,6 +10423,7 @@ async function copyAllFromDefault(targetConfigDir, autoSync = false) {
|
|
|
10348
10423
|
if (!existsSync4(targetConfigDir)) {
|
|
10349
10424
|
await mkdir(targetConfigDir, { recursive: true });
|
|
10350
10425
|
}
|
|
10426
|
+
const effectiveMode = typeof syncModeOrAutoSync === "boolean" ? syncModeOrAutoSync ? SyncMode.Auto : SyncMode.FullManual : syncModeOrAutoSync;
|
|
10351
10427
|
const excludeFiles = [
|
|
10352
10428
|
"config.json",
|
|
10353
10429
|
".config.json",
|
|
@@ -10375,23 +10451,46 @@ async function copyAllFromDefault(targetConfigDir, autoSync = false) {
|
|
|
10375
10451
|
continue;
|
|
10376
10452
|
}
|
|
10377
10453
|
if (stat.isDirectory()) {
|
|
10378
|
-
if (
|
|
10379
|
-
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
|
|
10385
|
-
|
|
10454
|
+
if (syncDirSet.has(entry)) {
|
|
10455
|
+
if (effectiveMode === SyncMode.Auto) {
|
|
10456
|
+
try {
|
|
10457
|
+
const targetStat = lstatSync(targetPath);
|
|
10458
|
+
if (targetStat.isSymbolicLink()) {
|
|
10459
|
+
const currentTarget = readlinkSync(targetPath);
|
|
10460
|
+
if (currentTarget === sourcePath) {
|
|
10461
|
+
console.log(` ✓ Already symlinked: ${entry}`);
|
|
10462
|
+
continue;
|
|
10463
|
+
}
|
|
10464
|
+
console.log(source_default.yellow(` ⚠ Replacing incorrect symlink: ${entry}`));
|
|
10465
|
+
} else {
|
|
10466
|
+
console.log(source_default.yellow(` ⚠ Removing existing directory: ${entry}`));
|
|
10386
10467
|
}
|
|
10387
|
-
|
|
10388
|
-
}
|
|
10389
|
-
|
|
10468
|
+
rmSync2(targetPath, { force: true, recursive: true });
|
|
10469
|
+
} catch {}
|
|
10470
|
+
await symlink(sourcePath, targetPath, "dir");
|
|
10471
|
+
console.log(` Symlinked: ${entry} -> ${sourcePath}`);
|
|
10472
|
+
} else if (effectiveMode === SyncMode.HalfManual) {
|
|
10473
|
+
if (!existsSync4(targetPath)) {
|
|
10474
|
+
await mkdir(targetPath, { recursive: true });
|
|
10475
|
+
}
|
|
10476
|
+
const subEntries = readdirSync2(sourcePath, { withFileTypes: true });
|
|
10477
|
+
let linked = 0;
|
|
10478
|
+
for (const sub of subEntries) {
|
|
10479
|
+
const subSource = join4(sourcePath, sub.name);
|
|
10480
|
+
const subTarget = join4(targetPath, sub.name);
|
|
10481
|
+
if (lstatSafe(subTarget))
|
|
10482
|
+
continue;
|
|
10483
|
+
const rel = relative(dirname4(subTarget), subSource);
|
|
10484
|
+
await symlink(rel, subTarget, sub.isDirectory() ? "dir" : "file");
|
|
10485
|
+
linked++;
|
|
10390
10486
|
}
|
|
10391
|
-
|
|
10392
|
-
}
|
|
10393
|
-
|
|
10394
|
-
|
|
10487
|
+
console.log(` Half-synced: ${entry} (${linked} items individually symlinked)`);
|
|
10488
|
+
} else {
|
|
10489
|
+
if (!existsSync4(targetPath)) {
|
|
10490
|
+
await mkdir(targetPath, { recursive: true });
|
|
10491
|
+
}
|
|
10492
|
+
await copyRecursive(sourcePath, targetPath);
|
|
10493
|
+
}
|
|
10395
10494
|
} else {
|
|
10396
10495
|
if (!existsSync4(targetPath)) {
|
|
10397
10496
|
await mkdir(targetPath, { recursive: true });
|
|
@@ -10653,6 +10752,58 @@ async function copyFilesRecursive(source, target) {
|
|
|
10653
10752
|
}
|
|
10654
10753
|
}));
|
|
10655
10754
|
}
|
|
10755
|
+
async function halfSyncPluginsAndSkills(configDir) {
|
|
10756
|
+
const defaultDir = getDefaultClaudeDir();
|
|
10757
|
+
if (!existsSync4(configDir)) {
|
|
10758
|
+
throw new ClaudeMultiError(ErrorCode.INSTANCE_DIR_NOT_FOUND, "Instance config directory does not exist");
|
|
10759
|
+
}
|
|
10760
|
+
await Promise.all(SYNC_DIRS.map(async (dir) => {
|
|
10761
|
+
const targetPath = join4(configDir, dir);
|
|
10762
|
+
const sourcePath = join4(defaultDir, dir);
|
|
10763
|
+
if (!existsSync4(sourcePath)) {
|
|
10764
|
+
console.log(source_default.yellow(` ⚠ Source ${dir} not found in ${defaultDir}, skipping`));
|
|
10765
|
+
return;
|
|
10766
|
+
}
|
|
10767
|
+
let wasWholeDirSymlink = false;
|
|
10768
|
+
try {
|
|
10769
|
+
const stat = lstatSync(targetPath);
|
|
10770
|
+
if (stat.isSymbolicLink()) {
|
|
10771
|
+
rmSync2(targetPath, { force: true });
|
|
10772
|
+
wasWholeDirSymlink = true;
|
|
10773
|
+
console.log(source_default.gray(` ✓ Removed directory symlink for ${dir}`));
|
|
10774
|
+
}
|
|
10775
|
+
} catch {}
|
|
10776
|
+
if (!existsSync4(targetPath)) {
|
|
10777
|
+
await mkdir(targetPath, { recursive: true });
|
|
10778
|
+
}
|
|
10779
|
+
const entries = readdirSync2(sourcePath, { withFileTypes: true });
|
|
10780
|
+
let linked = 0;
|
|
10781
|
+
for (const entry of entries) {
|
|
10782
|
+
const sourceEntry = join4(sourcePath, entry.name);
|
|
10783
|
+
const targetEntry = join4(targetPath, entry.name);
|
|
10784
|
+
const existingStat = lstatSafe(targetEntry);
|
|
10785
|
+
if (existingStat) {
|
|
10786
|
+
if (existingStat.isSymbolicLink()) {
|
|
10787
|
+
try {
|
|
10788
|
+
const currentTarget = readlinkSync(targetEntry);
|
|
10789
|
+
const resolvedTarget = isAbsolute(currentTarget) ? currentTarget : resolve2(dirname4(targetEntry), currentTarget);
|
|
10790
|
+
if (resolvedTarget === sourceEntry) {
|
|
10791
|
+
linked++;
|
|
10792
|
+
continue;
|
|
10793
|
+
}
|
|
10794
|
+
} catch {}
|
|
10795
|
+
rmSync2(targetEntry, { force: true });
|
|
10796
|
+
} else {
|
|
10797
|
+
continue;
|
|
10798
|
+
}
|
|
10799
|
+
}
|
|
10800
|
+
const relativePath = relative(dirname4(targetEntry), sourceEntry);
|
|
10801
|
+
await symlink(relativePath, targetEntry, entry.isDirectory() ? "dir" : "file");
|
|
10802
|
+
linked++;
|
|
10803
|
+
}
|
|
10804
|
+
console.log(source_default.green(` ✓ Half-synced ${dir}: ${linked} item(s) individually symlinked`));
|
|
10805
|
+
}));
|
|
10806
|
+
}
|
|
10656
10807
|
async function unsyncPluginsAndSkills(configDir) {
|
|
10657
10808
|
const defaultDir = getDefaultClaudeDir();
|
|
10658
10809
|
if (!existsSync4(configDir)) {
|
|
@@ -10665,21 +10816,63 @@ async function unsyncPluginsAndSkills(configDir) {
|
|
|
10665
10816
|
console.log(source_default.yellow(` ⚠ Source ${dir} not found in ${defaultDir}, skipping`));
|
|
10666
10817
|
return;
|
|
10667
10818
|
}
|
|
10668
|
-
let
|
|
10819
|
+
let isWholeDirSymlink = false;
|
|
10669
10820
|
try {
|
|
10670
10821
|
readlinkSync(targetPath);
|
|
10671
|
-
|
|
10822
|
+
isWholeDirSymlink = true;
|
|
10672
10823
|
} catch {}
|
|
10673
|
-
if (
|
|
10824
|
+
if (isWholeDirSymlink) {
|
|
10674
10825
|
rmSync2(targetPath, { force: true });
|
|
10675
|
-
console.log(source_default.gray(` ✓ Removed symlink for ${dir}`));
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
|
|
10826
|
+
console.log(source_default.gray(` ✓ Removed directory symlink for ${dir}`));
|
|
10827
|
+
await mkdir(targetPath, { recursive: true });
|
|
10828
|
+
await copyFilesRecursive(sourcePath, targetPath);
|
|
10829
|
+
console.log(source_default.green(` ✓ Copied files for ${dir}`));
|
|
10830
|
+
} else if (!existsSync4(targetPath)) {
|
|
10831
|
+
await mkdir(targetPath, { recursive: true });
|
|
10832
|
+
await copyFilesRecursive(sourcePath, targetPath);
|
|
10833
|
+
console.log(source_default.green(` ✓ Copied files for ${dir}`));
|
|
10834
|
+
} else {
|
|
10835
|
+
let replaced = 0;
|
|
10836
|
+
const entries = readdirSync2(targetPath, { withFileTypes: true });
|
|
10837
|
+
for (const entry of entries) {
|
|
10838
|
+
const entryPath = join4(targetPath, entry.name);
|
|
10839
|
+
const entryStat = lstatSafe(entryPath);
|
|
10840
|
+
if (entryStat?.isSymbolicLink()) {
|
|
10841
|
+
const linkTarget = readlinkSync(entryPath);
|
|
10842
|
+
const resolvedTarget = isAbsolute(linkTarget) ? linkTarget : resolve2(dirname4(entryPath), linkTarget);
|
|
10843
|
+
rmSync2(entryPath, { force: true });
|
|
10844
|
+
if (existsSync4(resolvedTarget)) {
|
|
10845
|
+
const realStat = statSync(resolvedTarget);
|
|
10846
|
+
if (realStat.isDirectory()) {
|
|
10847
|
+
await mkdir(entryPath, { recursive: true });
|
|
10848
|
+
await copyDirRecursive(resolvedTarget, entryPath);
|
|
10849
|
+
} else {
|
|
10850
|
+
await copyFile(resolvedTarget, entryPath);
|
|
10851
|
+
}
|
|
10852
|
+
replaced++;
|
|
10853
|
+
}
|
|
10854
|
+
}
|
|
10855
|
+
}
|
|
10856
|
+
const sourceEntries = readdirSync2(sourcePath, { withFileTypes: true });
|
|
10857
|
+
for (const entry of sourceEntries) {
|
|
10858
|
+
const targetEntry = join4(targetPath, entry.name);
|
|
10859
|
+
if (!existsSync4(targetEntry)) {
|
|
10860
|
+
const sourceEntry = join4(sourcePath, entry.name);
|
|
10861
|
+
if (entry.isDirectory()) {
|
|
10862
|
+
await mkdir(targetEntry, { recursive: true });
|
|
10863
|
+
await copyDirRecursive(sourceEntry, targetEntry);
|
|
10864
|
+
} else {
|
|
10865
|
+
await copyFile(sourceEntry, targetEntry);
|
|
10866
|
+
}
|
|
10867
|
+
replaced++;
|
|
10868
|
+
}
|
|
10869
|
+
}
|
|
10870
|
+
if (replaced > 0) {
|
|
10871
|
+
console.log(source_default.green(` ✓ ${dir}: replaced ${replaced} symlink(s) with copies`));
|
|
10872
|
+
} else {
|
|
10873
|
+
console.log(source_default.gray(` ✓ ${dir}: already fully independent`));
|
|
10874
|
+
}
|
|
10679
10875
|
}
|
|
10680
|
-
await mkdir(targetPath, { recursive: true });
|
|
10681
|
-
await copyFilesRecursive(sourcePath, targetPath);
|
|
10682
|
-
console.log(source_default.green(` ✓ Copied files for ${dir}`));
|
|
10683
10876
|
}));
|
|
10684
10877
|
}
|
|
10685
10878
|
async function readClaudeSettings(configDir) {
|
|
@@ -10820,6 +11013,26 @@ function isPluginsSymlinked(configDir) {
|
|
|
10820
11013
|
const st = lstatSafe(pluginsPath);
|
|
10821
11014
|
return st?.isSymbolicLink() ?? false;
|
|
10822
11015
|
}
|
|
11016
|
+
function isHalfManualSync(configDir) {
|
|
11017
|
+
for (const dir of SYNC_DIRS) {
|
|
11018
|
+
const dirPath = join4(configDir, dir);
|
|
11019
|
+
if (!existsSync4(dirPath))
|
|
11020
|
+
continue;
|
|
11021
|
+
const st = lstatSafe(dirPath);
|
|
11022
|
+
if (st?.isDirectory() && !st.isSymbolicLink()) {
|
|
11023
|
+
try {
|
|
11024
|
+
const entries = readdirSync2(dirPath, { withFileTypes: true });
|
|
11025
|
+
for (const entry of entries) {
|
|
11026
|
+
const entryPath = join4(dirPath, entry.name);
|
|
11027
|
+
const entryStat = lstatSafe(entryPath);
|
|
11028
|
+
if (entryStat?.isSymbolicLink())
|
|
11029
|
+
return true;
|
|
11030
|
+
}
|
|
11031
|
+
} catch {}
|
|
11032
|
+
}
|
|
11033
|
+
}
|
|
11034
|
+
return false;
|
|
11035
|
+
}
|
|
10823
11036
|
function isClaudeCodeRunning(configDir) {
|
|
10824
11037
|
if (false)
|
|
10825
11038
|
;
|
|
@@ -10918,6 +11131,9 @@ function validatePluginOperation(configDir, operation, pluginId) {
|
|
|
10918
11131
|
if (existsSync4(configDir) && isPluginsSymlinked(configDir)) {
|
|
10919
11132
|
errors.push("Plugins directory is symlinked (auto-sync). Disable auto-sync first.");
|
|
10920
11133
|
}
|
|
11134
|
+
if (existsSync4(configDir) && !isPluginsSymlinked(configDir) && isHalfManualSync(configDir)) {
|
|
11135
|
+
errors.push("Plugins are individually symlinked (half-manual). Switch to full-manual first to manage individual plugins.");
|
|
11136
|
+
}
|
|
10921
11137
|
if (operation === PluginAction.Install && pluginId) {
|
|
10922
11138
|
const defaults = listDefaultPlugins();
|
|
10923
11139
|
if (!defaults.find((p) => p.id === pluginId)) {
|
|
@@ -11082,7 +11298,7 @@ async function removeCustomMcpServer(configDir, name) {
|
|
|
11082
11298
|
delete settings.mcpServers[name];
|
|
11083
11299
|
await writeClaudeSettings(configDir, settings);
|
|
11084
11300
|
}
|
|
11085
|
-
var _testConfigDir, SYNC_DIRS, _testDefaultClaudeDir, MARKETPLACE_REL = "plugins/marketplaces/claude-plugins-official";
|
|
11301
|
+
var _testConfigDir, SYNC_DIRS, VALID_SYNC_MODES, _testDefaultClaudeDir, MARKETPLACE_REL = "plugins/marketplaces/claude-plugins-official";
|
|
11086
11302
|
var init_config = __esm(() => {
|
|
11087
11303
|
init_templates();
|
|
11088
11304
|
init_json_file();
|
|
@@ -11091,6 +11307,7 @@ var init_config = __esm(() => {
|
|
|
11091
11307
|
init_env();
|
|
11092
11308
|
init_source();
|
|
11093
11309
|
SYNC_DIRS = ["plugins", "skills"];
|
|
11310
|
+
VALID_SYNC_MODES = new Set(Object.values(SyncMode));
|
|
11094
11311
|
});
|
|
11095
11312
|
|
|
11096
11313
|
// node_modules/react/cjs/react.development.js
|
|
@@ -56073,15 +56290,10 @@ function useConfig() {
|
|
|
56073
56290
|
return instance;
|
|
56074
56291
|
}, [reload]);
|
|
56075
56292
|
const toggleAutoSync = import_react66.useCallback(async (name, enable) => {
|
|
56076
|
-
|
|
56077
|
-
|
|
56078
|
-
|
|
56079
|
-
await
|
|
56080
|
-
if (enable) {
|
|
56081
|
-
await syncPluginsAndSkills(instance.configDir);
|
|
56082
|
-
} else {
|
|
56083
|
-
await unsyncPluginsAndSkills(instance.configDir);
|
|
56084
|
-
}
|
|
56293
|
+
await toggleSyncMode(name, enable ? SyncMode.Auto : SyncMode.FullManual);
|
|
56294
|
+
}, [reload]);
|
|
56295
|
+
const toggleSyncMode = import_react66.useCallback(async (name, newMode) => {
|
|
56296
|
+
await updateInstanceSyncMode(name, newMode);
|
|
56085
56297
|
await reload();
|
|
56086
56298
|
}, [reload]);
|
|
56087
56299
|
const syncTemplateEnv = import_react66.useCallback(async (instance) => {
|
|
@@ -56106,11 +56318,14 @@ function useConfig() {
|
|
|
56106
56318
|
addInstance: addInstance2,
|
|
56107
56319
|
removeInstance: removeInstance2,
|
|
56108
56320
|
toggleAutoSync,
|
|
56321
|
+
toggleSyncMode,
|
|
56109
56322
|
syncTemplateEnv,
|
|
56110
56323
|
regenerateWrapper,
|
|
56111
56324
|
migrationStatus,
|
|
56112
56325
|
instanceMigrationVersion: config?.instanceMigrationVersion,
|
|
56113
56326
|
getInstance,
|
|
56327
|
+
getSyncMode,
|
|
56328
|
+
syncModeLabel,
|
|
56114
56329
|
listInstances,
|
|
56115
56330
|
hasDefaultConfig: hasDefaultClaudeConfig,
|
|
56116
56331
|
hasDefaultMcpConfig,
|
|
@@ -56137,6 +56352,7 @@ function useConfig() {
|
|
|
56137
56352
|
getApiKeyPlaceholder,
|
|
56138
56353
|
updateInstanceAutoSync,
|
|
56139
56354
|
syncPluginsAndSkills,
|
|
56355
|
+
halfSyncPluginsAndSkills,
|
|
56140
56356
|
initializeInstanceState,
|
|
56141
56357
|
mergeProviderEnv,
|
|
56142
56358
|
listDefaultPlugins,
|
|
@@ -56145,6 +56361,7 @@ function useConfig() {
|
|
|
56145
56361
|
copySinglePlugin,
|
|
56146
56362
|
removeSinglePlugin,
|
|
56147
56363
|
isPluginsSymlinked,
|
|
56364
|
+
isHalfManualSync,
|
|
56148
56365
|
getMcpServersFromPlugins,
|
|
56149
56366
|
getInstanceMcpServers,
|
|
56150
56367
|
setCustomMcpServer,
|
|
@@ -56162,6 +56379,7 @@ var init_useConfig = __esm(() => {
|
|
|
56162
56379
|
init_templates();
|
|
56163
56380
|
init_migration();
|
|
56164
56381
|
init_errors();
|
|
56382
|
+
init_constants();
|
|
56165
56383
|
import_react66 = __toESM(require_react(), 1);
|
|
56166
56384
|
});
|
|
56167
56385
|
|
|
@@ -56229,8 +56447,8 @@ function reducer5(state, action) {
|
|
|
56229
56447
|
return { ...state, selectedRegion: action.region };
|
|
56230
56448
|
case "SET_API_KEY":
|
|
56231
56449
|
return { ...state, apiKey: action.key };
|
|
56232
|
-
case "
|
|
56233
|
-
return { ...state,
|
|
56450
|
+
case "SET_SYNC_MODE":
|
|
56451
|
+
return { ...state, syncMode: action.value };
|
|
56234
56452
|
case "SET_COPY_OPTION":
|
|
56235
56453
|
return { ...state, copyOption: action.value };
|
|
56236
56454
|
case "SET_PLUGIN_IDS":
|
|
@@ -56252,7 +56470,7 @@ function initialState(initialName) {
|
|
|
56252
56470
|
selectedProvider: null,
|
|
56253
56471
|
selectedRegion: null,
|
|
56254
56472
|
apiKey: "",
|
|
56255
|
-
|
|
56473
|
+
syncMode: SyncMode.Auto,
|
|
56256
56474
|
copyOption: CopyOption.None,
|
|
56257
56475
|
selectedPluginIds: [],
|
|
56258
56476
|
result: null
|
|
@@ -56438,23 +56656,40 @@ var import_react67, jsx_dev_runtime4, AddResult = ({
|
|
|
56438
56656
|
onSubmit
|
|
56439
56657
|
}, undefined, false, undefined, this)
|
|
56440
56658
|
]
|
|
56441
|
-
}, undefined, true, undefined, this),
|
|
56442
|
-
|
|
56443
|
-
|
|
56444
|
-
|
|
56445
|
-
|
|
56446
|
-
|
|
56447
|
-
|
|
56448
|
-
|
|
56449
|
-
|
|
56450
|
-
|
|
56451
|
-
|
|
56452
|
-
|
|
56453
|
-
|
|
56454
|
-
|
|
56455
|
-
|
|
56456
|
-
|
|
56457
|
-
|
|
56659
|
+
}, undefined, true, undefined, this), SyncModeStep = ({ onSelect }) => {
|
|
56660
|
+
const syncModeOptions = [
|
|
56661
|
+
{
|
|
56662
|
+
label: "Auto-sync — symlink entire plugins/skills dirs (instant sync)",
|
|
56663
|
+
value: SyncMode.Auto
|
|
56664
|
+
},
|
|
56665
|
+
{
|
|
56666
|
+
label: "Half-manual — symlink individual items (new installs stay isolated)",
|
|
56667
|
+
value: SyncMode.HalfManual
|
|
56668
|
+
},
|
|
56669
|
+
{
|
|
56670
|
+
label: "Full-manual — copy everything (completely independent)",
|
|
56671
|
+
value: SyncMode.FullManual
|
|
56672
|
+
}
|
|
56673
|
+
];
|
|
56674
|
+
return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
|
|
56675
|
+
flexDirection: "column",
|
|
56676
|
+
gap: 1,
|
|
56677
|
+
children: [
|
|
56678
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
56679
|
+
children: "Choose how to sync plugins and skills:"
|
|
56680
|
+
}, undefined, false, undefined, this),
|
|
56681
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
56682
|
+
dimColor: true,
|
|
56683
|
+
children: "Controls how ~/.claude content is shared with this instance"
|
|
56684
|
+
}, undefined, false, undefined, this),
|
|
56685
|
+
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Select, {
|
|
56686
|
+
options: syncModeOptions,
|
|
56687
|
+
visibleOptionCount: syncModeOptions.length,
|
|
56688
|
+
onChange: (value) => onSelect(value)
|
|
56689
|
+
}, undefined, false, undefined, this)
|
|
56690
|
+
]
|
|
56691
|
+
}, undefined, true, undefined, this);
|
|
56692
|
+
}, AddInstance = ({ onBack, initialName }) => {
|
|
56458
56693
|
const { exit } = use_app_default();
|
|
56459
56694
|
const cfg = useConfig();
|
|
56460
56695
|
const [state, dispatch] = import_react67.useReducer(reducer5, initialName, initialState);
|
|
@@ -56540,7 +56775,8 @@ var import_react67, jsx_dev_runtime4, AddResult = ({
|
|
|
56540
56775
|
configDir: cDir,
|
|
56541
56776
|
binaryPath: bPath,
|
|
56542
56777
|
createdAt: new Date().toISOString(),
|
|
56543
|
-
autoSync: sync,
|
|
56778
|
+
autoSync: sync === SyncMode.Auto,
|
|
56779
|
+
syncMode: sync,
|
|
56544
56780
|
createdWithVersion: getClaudeMultiVersion(),
|
|
56545
56781
|
...state.useProvider && state.selectedProvider ? { providerTemplate: state.selectedProvider } : {},
|
|
56546
56782
|
...state.selectedRegion && state.useProvider && state.selectedProvider && providerHasRegions(state.selectedProvider) ? { providerRegion: state.selectedRegion } : {}
|
|
@@ -56559,8 +56795,13 @@ var import_react67, jsx_dev_runtime4, AddResult = ({
|
|
|
56559
56795
|
if (selections.length > 0) {
|
|
56560
56796
|
await cfg.copySelectedPlugins(cDir, selections);
|
|
56561
56797
|
}
|
|
56798
|
+
if (sync === SyncMode.Auto) {
|
|
56799
|
+
await cfg.syncPluginsAndSkills(cDir);
|
|
56800
|
+
} else if (sync === SyncMode.HalfManual) {
|
|
56801
|
+
await cfg.halfSyncPluginsAndSkills(cDir);
|
|
56802
|
+
}
|
|
56562
56803
|
} else if (copyOpt === CopyOption.All) {
|
|
56563
|
-
await cfg.copyAllFromDefault(cDir);
|
|
56804
|
+
await cfg.copyAllFromDefault(cDir, sync);
|
|
56564
56805
|
} else if (copyOpt === CopyOption.Settings) {
|
|
56565
56806
|
await cfg.copySettingsFromDefault(cDir);
|
|
56566
56807
|
}
|
|
@@ -56588,7 +56829,7 @@ var import_react67, jsx_dev_runtime4, AddResult = ({
|
|
|
56588
56829
|
} else if (value === CopyOption.All) {
|
|
56589
56830
|
dispatch({ type: "SET_STEP", step: "autosync" /* Autosync */ });
|
|
56590
56831
|
} else {
|
|
56591
|
-
doCreate(value,
|
|
56832
|
+
doCreate(value, SyncMode.FullManual);
|
|
56592
56833
|
}
|
|
56593
56834
|
}, [doCreate]);
|
|
56594
56835
|
const handlePluginSelection = import_react67.useCallback((ids) => {
|
|
@@ -56599,9 +56840,9 @@ var import_react67, jsx_dev_runtime4, AddResult = ({
|
|
|
56599
56840
|
dispatch({ type: "SET_PLUGIN_IDS", ids });
|
|
56600
56841
|
dispatch({ type: "SET_STEP", step: "autosync" /* Autosync */ });
|
|
56601
56842
|
}, []);
|
|
56602
|
-
const
|
|
56603
|
-
dispatch({ type: "
|
|
56604
|
-
doCreate(state.copyOption,
|
|
56843
|
+
const handleSyncModeSelect = import_react67.useCallback((mode) => {
|
|
56844
|
+
dispatch({ type: "SET_SYNC_MODE", value: mode });
|
|
56845
|
+
doCreate(state.copyOption, mode);
|
|
56605
56846
|
}, [state.copyOption, doCreate]);
|
|
56606
56847
|
const hasDefaultConfig = cfg.hasDefaultConfig();
|
|
56607
56848
|
const providerOptions = [
|
|
@@ -56674,7 +56915,7 @@ var import_react67, jsx_dev_runtime4, AddResult = ({
|
|
|
56674
56915
|
children: "No default Claude config found. Starting fresh."
|
|
56675
56916
|
}, undefined, false, undefined, this),
|
|
56676
56917
|
/* @__PURE__ */ jsx_dev_runtime4.jsxDEV(ConfirmInput, {
|
|
56677
|
-
onConfirm: () => doCreate(CopyOption.None,
|
|
56918
|
+
onConfirm: () => doCreate(CopyOption.None, SyncMode.FullManual),
|
|
56678
56919
|
onCancel: onBack
|
|
56679
56920
|
}, undefined, false, undefined, this)
|
|
56680
56921
|
]
|
|
@@ -56701,8 +56942,8 @@ var import_react67, jsx_dev_runtime4, AddResult = ({
|
|
|
56701
56942
|
defaultPluginsLength: defaultPlugins.length,
|
|
56702
56943
|
onSubmit: handlePluginSelection
|
|
56703
56944
|
}, undefined, false, undefined, this),
|
|
56704
|
-
state.step === "autosync" /* Autosync */ && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(
|
|
56705
|
-
|
|
56945
|
+
state.step === "autosync" /* Autosync */ && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(SyncModeStep, {
|
|
56946
|
+
onSelect: handleSyncModeSelect
|
|
56706
56947
|
}, undefined, false, undefined, this),
|
|
56707
56948
|
state.step === "creating" /* Creating */ && /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
|
|
56708
56949
|
dimColor: true,
|
|
@@ -56749,7 +56990,7 @@ var init_AddInstance = __esm(async () => {
|
|
|
56749
56990
|
["paths-confirm" /* PathsConfirm */]: "Paths",
|
|
56750
56991
|
["copy-options" /* CopyOptions */]: "Copy Options",
|
|
56751
56992
|
["select-plugins" /* SelectPlugins */]: "Select Plugins",
|
|
56752
|
-
["autosync" /* Autosync */]: "
|
|
56993
|
+
["autosync" /* Autosync */]: "Sync Mode",
|
|
56753
56994
|
["creating" /* Creating */]: "Creating...",
|
|
56754
56995
|
["done" /* Done */]: "Complete"
|
|
56755
56996
|
};
|
|
@@ -57240,13 +57481,33 @@ var init_useHealthCheck = __esm(() => {
|
|
|
57240
57481
|
});
|
|
57241
57482
|
|
|
57242
57483
|
// src/ink/components/InstanceCard.tsx
|
|
57484
|
+
function syncModeIcon(mode) {
|
|
57485
|
+
switch (mode) {
|
|
57486
|
+
case SyncMode.Auto:
|
|
57487
|
+
return "⚡";
|
|
57488
|
+
case SyncMode.HalfManual:
|
|
57489
|
+
return "\uD83D\uDD17";
|
|
57490
|
+
case SyncMode.FullManual:
|
|
57491
|
+
return "\uD83D\uDCE6";
|
|
57492
|
+
}
|
|
57493
|
+
}
|
|
57494
|
+
function syncModeColor(mode) {
|
|
57495
|
+
switch (mode) {
|
|
57496
|
+
case SyncMode.Auto:
|
|
57497
|
+
return "green";
|
|
57498
|
+
case SyncMode.HalfManual:
|
|
57499
|
+
return "cyan";
|
|
57500
|
+
case SyncMode.FullManual:
|
|
57501
|
+
return "yellow";
|
|
57502
|
+
}
|
|
57503
|
+
}
|
|
57243
57504
|
var jsx_dev_runtime7, InstanceCard = ({
|
|
57244
57505
|
instance,
|
|
57245
57506
|
index = 0
|
|
57246
57507
|
}) => {
|
|
57247
|
-
const
|
|
57508
|
+
const mode = getSyncMode(instance);
|
|
57248
57509
|
const visible = useFadeIn(index * 60 + 50);
|
|
57249
|
-
const pulse = usePulse(
|
|
57510
|
+
const pulse = usePulse(mode === SyncMode.Auto ? ["●", "◉", "●"] : mode === SyncMode.HalfManual ? ["◐", "◑", "◐"] : ["○", "◌", "○"], 800);
|
|
57250
57511
|
if (!visible)
|
|
57251
57512
|
return null;
|
|
57252
57513
|
const verLabel = instance.createdWithVersion === LEGACY_INSTANCE_VERSION ? "before version tracking" : instance.createdWithVersion;
|
|
@@ -57259,8 +57520,8 @@ var jsx_dev_runtime7, InstanceCard = ({
|
|
|
57259
57520
|
gap: 1,
|
|
57260
57521
|
children: [
|
|
57261
57522
|
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
57262
|
-
color:
|
|
57263
|
-
children:
|
|
57523
|
+
color: syncModeColor(mode),
|
|
57524
|
+
children: pulse
|
|
57264
57525
|
}, undefined, false, undefined, this),
|
|
57265
57526
|
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
57266
57527
|
bold: true,
|
|
@@ -57268,8 +57529,12 @@ var jsx_dev_runtime7, InstanceCard = ({
|
|
|
57268
57529
|
}, undefined, false, undefined, this),
|
|
57269
57530
|
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Text, {
|
|
57270
57531
|
dimColor: true,
|
|
57271
|
-
children:
|
|
57272
|
-
|
|
57532
|
+
children: [
|
|
57533
|
+
syncModeIcon(mode),
|
|
57534
|
+
" ",
|
|
57535
|
+
mode
|
|
57536
|
+
]
|
|
57537
|
+
}, undefined, true, undefined, this)
|
|
57273
57538
|
]
|
|
57274
57539
|
}, undefined, true, undefined, this),
|
|
57275
57540
|
/* @__PURE__ */ jsx_dev_runtime7.jsxDEV(Box_default, {
|
|
@@ -57337,6 +57602,8 @@ var jsx_dev_runtime7, InstanceCard = ({
|
|
|
57337
57602
|
};
|
|
57338
57603
|
var init_InstanceCard = __esm(async () => {
|
|
57339
57604
|
init_useAnimations();
|
|
57605
|
+
init_config();
|
|
57606
|
+
init_constants();
|
|
57340
57607
|
init_migration();
|
|
57341
57608
|
await init_build2();
|
|
57342
57609
|
jsx_dev_runtime7 = __toESM(require_jsx_dev_runtime(), 1);
|
|
@@ -57531,6 +57798,16 @@ var init_instance_diagnostics = __esm(() => {
|
|
|
57531
57798
|
});
|
|
57532
57799
|
|
|
57533
57800
|
// src/ink/screens/ShowInstanceInfo.tsx
|
|
57801
|
+
function syncModeColor2(mode) {
|
|
57802
|
+
switch (mode) {
|
|
57803
|
+
case SyncMode.Auto:
|
|
57804
|
+
return "green";
|
|
57805
|
+
case SyncMode.HalfManual:
|
|
57806
|
+
return "cyan";
|
|
57807
|
+
case SyncMode.FullManual:
|
|
57808
|
+
return "yellow";
|
|
57809
|
+
}
|
|
57810
|
+
}
|
|
57534
57811
|
function templateStatusLabel(status) {
|
|
57535
57812
|
switch (status) {
|
|
57536
57813
|
case "match":
|
|
@@ -57588,7 +57865,7 @@ var import_react69, jsx_dev_runtime10, DetailRow = ({
|
|
|
57588
57865
|
}, undefined, true, undefined, this);
|
|
57589
57866
|
}, EMPTY_INFO, ACTION_VALUES, ShowInstanceInfo = ({ onBack }) => {
|
|
57590
57867
|
const { exit } = use_app_default();
|
|
57591
|
-
const { instances: instances2, listInstancePlugins: listInstancePlugins2, getInstanceMcpServers: getInstanceMcpServers2, syncTemplateEnv, regenerateWrapper } = useConfig();
|
|
57868
|
+
const { instances: instances2, listInstancePlugins: listInstancePlugins2, getInstanceMcpServers: getInstanceMcpServers2, syncTemplateEnv, regenerateWrapper, toggleSyncMode } = useConfig();
|
|
57592
57869
|
const [step, setStep] = import_react69.useState("select");
|
|
57593
57870
|
const [selected, setSelected] = import_react69.useState(null);
|
|
57594
57871
|
const [infoData, setInfoData] = import_react69.useState(EMPTY_INFO);
|
|
@@ -57597,6 +57874,7 @@ var import_react69, jsx_dev_runtime10, DetailRow = ({
|
|
|
57597
57874
|
const [providerName, setProviderName] = import_react69.useState(null);
|
|
57598
57875
|
const [actionResult, setActionResult] = import_react69.useState(null);
|
|
57599
57876
|
const [executing, setExecuting] = import_react69.useState(false);
|
|
57877
|
+
const [pendingSyncConvert, setPendingSyncConvert] = import_react69.useState(null);
|
|
57600
57878
|
const liveSelected = selected ? instances2.find((i) => i.name === selected.name) ?? selected : null;
|
|
57601
57879
|
const runDiagnostics = import_react69.useCallback((inst) => {
|
|
57602
57880
|
const tmpl = detectTemplateMismatch(inst);
|
|
@@ -57687,9 +57965,31 @@ var import_react69, jsx_dev_runtime10, DetailRow = ({
|
|
|
57687
57965
|
runDiagnostics(inst);
|
|
57688
57966
|
await loadInstanceInfo(inst);
|
|
57689
57967
|
};
|
|
57968
|
+
const VALID_SYNC_MODES2 = new Set(Object.values(SyncMode));
|
|
57690
57969
|
const handleAction = async (value) => {
|
|
57691
57970
|
if (executing)
|
|
57692
57971
|
return;
|
|
57972
|
+
if (value.startsWith("convert:")) {
|
|
57973
|
+
const rawMode = value.replace("convert:", "");
|
|
57974
|
+
if (!VALID_SYNC_MODES2.has(rawMode)) {
|
|
57975
|
+
setActionResult({ message: `Invalid sync mode: ${rawMode}`, type: "error" });
|
|
57976
|
+
setStep("result");
|
|
57977
|
+
return;
|
|
57978
|
+
}
|
|
57979
|
+
const targetMode = rawMode;
|
|
57980
|
+
setPendingSyncConvert(targetMode);
|
|
57981
|
+
setStep("executing");
|
|
57982
|
+
setExecuting(true);
|
|
57983
|
+
try {
|
|
57984
|
+
await toggleSyncMode(selected.name, targetMode);
|
|
57985
|
+
setActionResult({ message: `Sync mode set to ${syncModeLabel(targetMode)} for '${selected.name}'`, type: "success" });
|
|
57986
|
+
} catch (err) {
|
|
57987
|
+
setActionResult({ message: err instanceof Error ? err.message : String(err), type: "error" });
|
|
57988
|
+
}
|
|
57989
|
+
setExecuting(false);
|
|
57990
|
+
setStep("result");
|
|
57991
|
+
return;
|
|
57992
|
+
}
|
|
57693
57993
|
if (value === ACTION_VALUES.Back || !selected) {
|
|
57694
57994
|
setStep("info");
|
|
57695
57995
|
return;
|
|
@@ -57732,6 +58032,17 @@ var import_react69, jsx_dev_runtime10, DetailRow = ({
|
|
|
57732
58032
|
value: ACTION_VALUES.OverrideWrapper
|
|
57733
58033
|
});
|
|
57734
58034
|
}
|
|
58035
|
+
const syncTarget = liveSelected ?? selected;
|
|
58036
|
+
if (syncTarget) {
|
|
58037
|
+
const currentMode = getSyncMode(syncTarget);
|
|
58038
|
+
const downgrades = availableSyncModeConversions(currentMode);
|
|
58039
|
+
for (const mode of downgrades) {
|
|
58040
|
+
options.push({
|
|
58041
|
+
label: `\uD83D\uDD04 Convert to ${syncModeLabel(mode)}`,
|
|
58042
|
+
value: `convert:${mode}`
|
|
58043
|
+
});
|
|
58044
|
+
}
|
|
58045
|
+
}
|
|
57735
58046
|
options.push({ label: "← Back", value: ACTION_VALUES.Back });
|
|
57736
58047
|
return options;
|
|
57737
58048
|
};
|
|
@@ -57791,9 +58102,9 @@ var import_react69, jsx_dev_runtime10, DetailRow = ({
|
|
|
57791
58102
|
delay: 150
|
|
57792
58103
|
}, undefined, false, undefined, this),
|
|
57793
58104
|
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
|
|
57794
|
-
label: "
|
|
57795
|
-
value: displayInstance
|
|
57796
|
-
color: displayInstance
|
|
58105
|
+
label: "Sync mode",
|
|
58106
|
+
value: syncModeLabel(getSyncMode(displayInstance)),
|
|
58107
|
+
color: syncModeColor2(getSyncMode(displayInstance)),
|
|
57797
58108
|
delay: 200
|
|
57798
58109
|
}, undefined, false, undefined, this),
|
|
57799
58110
|
/* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
|
|
@@ -57964,6 +58275,8 @@ var init_ShowInstanceInfo = __esm(async () => {
|
|
|
57964
58275
|
init_useConfig();
|
|
57965
58276
|
init_useAnimations();
|
|
57966
58277
|
init_migration();
|
|
58278
|
+
init_constants();
|
|
58279
|
+
init_config();
|
|
57967
58280
|
init_instance_diagnostics();
|
|
57968
58281
|
await __promiseAll([
|
|
57969
58282
|
init_build2(),
|
|
@@ -57985,6 +58298,7 @@ var init_ShowInstanceInfo = __esm(async () => {
|
|
|
57985
58298
|
SyncTemplate: "sync-template",
|
|
57986
58299
|
UpdateWrapper: "update-wrapper",
|
|
57987
58300
|
OverrideWrapper: "override-wrapper",
|
|
58301
|
+
ConvertSyncMode: "convert-sync-mode",
|
|
57988
58302
|
Back: "back"
|
|
57989
58303
|
};
|
|
57990
58304
|
});
|
|
@@ -58254,32 +58568,69 @@ var init_useMessage = __esm(() => {
|
|
|
58254
58568
|
});
|
|
58255
58569
|
|
|
58256
58570
|
// src/ink/screens/ToggleAutoSync.tsx
|
|
58257
|
-
|
|
58571
|
+
function syncModeColor3(mode) {
|
|
58572
|
+
switch (mode) {
|
|
58573
|
+
case SyncMode.Auto:
|
|
58574
|
+
return "green";
|
|
58575
|
+
case SyncMode.HalfManual:
|
|
58576
|
+
return "cyan";
|
|
58577
|
+
case SyncMode.FullManual:
|
|
58578
|
+
return "yellow";
|
|
58579
|
+
}
|
|
58580
|
+
}
|
|
58581
|
+
function syncModeIcon2(mode) {
|
|
58582
|
+
switch (mode) {
|
|
58583
|
+
case SyncMode.Auto:
|
|
58584
|
+
return "⚡";
|
|
58585
|
+
case SyncMode.HalfManual:
|
|
58586
|
+
return "\uD83D\uDD17";
|
|
58587
|
+
case SyncMode.FullManual:
|
|
58588
|
+
return "\uD83D\uDCE6";
|
|
58589
|
+
}
|
|
58590
|
+
}
|
|
58591
|
+
var import_react72, jsx_dev_runtime12, SyncModeAction = ({ selected, actionOptions, onAction }) => {
|
|
58258
58592
|
const showStatus = useFadeIn(50);
|
|
58259
58593
|
const showOptions = useFadeIn(150);
|
|
58594
|
+
const currentMode = getSyncMode(selected);
|
|
58260
58595
|
return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
58261
58596
|
flexDirection: "column",
|
|
58262
58597
|
gap: 1,
|
|
58263
58598
|
children: [
|
|
58264
58599
|
showStatus && /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
58265
|
-
|
|
58266
|
-
|
|
58267
|
-
|
|
58268
|
-
|
|
58269
|
-
|
|
58270
|
-
|
|
58271
|
-
|
|
58272
|
-
|
|
58273
|
-
|
|
58274
|
-
|
|
58275
|
-
|
|
58276
|
-
|
|
58277
|
-
|
|
58278
|
-
|
|
58279
|
-
|
|
58280
|
-
|
|
58281
|
-
|
|
58282
|
-
|
|
58600
|
+
flexDirection: "column",
|
|
58601
|
+
gap: 0,
|
|
58602
|
+
children: [
|
|
58603
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
58604
|
+
children: [
|
|
58605
|
+
"Sync mode for ",
|
|
58606
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
58607
|
+
bold: true,
|
|
58608
|
+
color: "cyan",
|
|
58609
|
+
children: selected.name
|
|
58610
|
+
}, undefined, false, undefined, this),
|
|
58611
|
+
" is",
|
|
58612
|
+
" ",
|
|
58613
|
+
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
58614
|
+
bold: true,
|
|
58615
|
+
color: syncModeColor3(currentMode),
|
|
58616
|
+
children: [
|
|
58617
|
+
syncModeIcon2(currentMode),
|
|
58618
|
+
" ",
|
|
58619
|
+
syncModeLabel(currentMode)
|
|
58620
|
+
]
|
|
58621
|
+
}, undefined, true, undefined, this)
|
|
58622
|
+
]
|
|
58623
|
+
}, undefined, true, undefined, this),
|
|
58624
|
+
currentMode !== SyncMode.FullManual && /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
58625
|
+
dimColor: true,
|
|
58626
|
+
children: [
|
|
58627
|
+
"Can convert to: ",
|
|
58628
|
+
availableSyncModeConversions(currentMode).map((m) => syncModeLabel(m)).join(", ")
|
|
58629
|
+
]
|
|
58630
|
+
}, undefined, true, undefined, this)
|
|
58631
|
+
]
|
|
58632
|
+
}, undefined, true, undefined, this),
|
|
58633
|
+
showOptions && actionOptions.length > 1 && /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(jsx_dev_runtime12.Fragment, {
|
|
58283
58634
|
children: [
|
|
58284
58635
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
58285
58636
|
children: "What would you like to do?"
|
|
@@ -58294,11 +58645,11 @@ var import_react72, jsx_dev_runtime12, ToggleActionValue, ToggleAction = ({ sele
|
|
|
58294
58645
|
]
|
|
58295
58646
|
}, undefined, true, undefined, this);
|
|
58296
58647
|
}, ToggleAutoSync = ({ onBack }) => {
|
|
58297
|
-
const { instances: instances2,
|
|
58648
|
+
const { instances: instances2, toggleSyncMode, syncPluginsAndSkills: syncPluginsAndSkills2, halfSyncPluginsAndSkills: halfSyncPluginsAndSkills2 } = useConfig();
|
|
58298
58649
|
const [step, setStep] = import_react72.useState("select");
|
|
58299
58650
|
const [selected, setSelected] = import_react72.useState(null);
|
|
58300
58651
|
const { error, setError } = useMessage();
|
|
58301
|
-
const [
|
|
58652
|
+
const [newMode, setNewMode] = import_react72.useState(SyncMode.Auto);
|
|
58302
58653
|
useNavigation(() => {
|
|
58303
58654
|
if (step === "action") {
|
|
58304
58655
|
setStep("select");
|
|
@@ -58317,7 +58668,7 @@ var import_react72, jsx_dev_runtime12, ToggleActionValue, ToggleAction = ({ sele
|
|
|
58317
58668
|
paddingY: 1,
|
|
58318
58669
|
children: [
|
|
58319
58670
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Header, {
|
|
58320
|
-
title: "\uD83D\uDD04
|
|
58671
|
+
title: "\uD83D\uDD04 Sync Mode"
|
|
58321
58672
|
}, undefined, false, undefined, this),
|
|
58322
58673
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
58323
58674
|
color: "yellow",
|
|
@@ -58333,10 +58684,13 @@ var import_react72, jsx_dev_runtime12, ToggleActionValue, ToggleAction = ({ sele
|
|
|
58333
58684
|
]
|
|
58334
58685
|
}, undefined, true, undefined, this);
|
|
58335
58686
|
}
|
|
58336
|
-
const instanceOptions = instances2.map((i) =>
|
|
58337
|
-
|
|
58338
|
-
|
|
58339
|
-
|
|
58687
|
+
const instanceOptions = instances2.map((i) => {
|
|
58688
|
+
const mode = getSyncMode(i);
|
|
58689
|
+
return {
|
|
58690
|
+
label: `${i.name} (${syncModeIcon2(mode)} ${syncModeLabel(mode)})`,
|
|
58691
|
+
value: i.name
|
|
58692
|
+
};
|
|
58693
|
+
});
|
|
58340
58694
|
const handleSelect = (value) => {
|
|
58341
58695
|
const inst = instances2.find((i) => i.name === value);
|
|
58342
58696
|
if (inst) {
|
|
@@ -58344,32 +58698,69 @@ var import_react72, jsx_dev_runtime12, ToggleActionValue, ToggleAction = ({ sele
|
|
|
58344
58698
|
setStep("action");
|
|
58345
58699
|
}
|
|
58346
58700
|
};
|
|
58701
|
+
const VALID_MODES = new Set(Object.values(SyncMode));
|
|
58702
|
+
const FORCE_RESYNC = "force-resync";
|
|
58347
58703
|
const handleAction = async (value) => {
|
|
58348
|
-
if (value ===
|
|
58704
|
+
if (value === "cancel" || !selected) {
|
|
58349
58705
|
setStep("select");
|
|
58350
58706
|
setSelected(null);
|
|
58351
58707
|
return;
|
|
58352
58708
|
}
|
|
58353
|
-
|
|
58354
|
-
|
|
58709
|
+
if (value === FORCE_RESYNC) {
|
|
58710
|
+
setStep("syncing");
|
|
58711
|
+
try {
|
|
58712
|
+
const mode = getSyncMode(selected);
|
|
58713
|
+
if (mode === SyncMode.Auto) {
|
|
58714
|
+
await syncPluginsAndSkills2(selected.configDir);
|
|
58715
|
+
} else if (mode === SyncMode.HalfManual) {
|
|
58716
|
+
await halfSyncPluginsAndSkills2(selected.configDir);
|
|
58717
|
+
}
|
|
58718
|
+
setNewMode(mode);
|
|
58719
|
+
setStep("done");
|
|
58720
|
+
} catch (err) {
|
|
58721
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
58722
|
+
setStep("select");
|
|
58723
|
+
}
|
|
58724
|
+
return;
|
|
58725
|
+
}
|
|
58726
|
+
if (!VALID_MODES.has(value)) {
|
|
58727
|
+
setError(`Invalid sync mode: ${value}`);
|
|
58728
|
+
setStep("select");
|
|
58729
|
+
return;
|
|
58730
|
+
}
|
|
58731
|
+
const targetMode = value;
|
|
58355
58732
|
setStep("syncing");
|
|
58356
58733
|
try {
|
|
58357
|
-
await
|
|
58358
|
-
|
|
58734
|
+
await toggleSyncMode(selected.name, targetMode);
|
|
58735
|
+
setNewMode(targetMode);
|
|
58359
58736
|
setStep("done");
|
|
58360
58737
|
} catch (err) {
|
|
58361
58738
|
setError(err instanceof Error ? err.message : String(err));
|
|
58362
58739
|
setStep("select");
|
|
58363
58740
|
}
|
|
58364
58741
|
};
|
|
58365
|
-
const
|
|
58366
|
-
|
|
58367
|
-
label:
|
|
58368
|
-
|
|
58369
|
-
|
|
58370
|
-
|
|
58371
|
-
|
|
58372
|
-
|
|
58742
|
+
const buildActionOptions = () => {
|
|
58743
|
+
if (!selected)
|
|
58744
|
+
return [{ label: "Cancel", value: "cancel" }];
|
|
58745
|
+
const currentMode = getSyncMode(selected);
|
|
58746
|
+
const options = [];
|
|
58747
|
+
if (currentMode === SyncMode.Auto || currentMode === SyncMode.HalfManual) {
|
|
58748
|
+
options.push({ label: "⚡ Force re-sync (rebuild symlinks)", value: FORCE_RESYNC });
|
|
58749
|
+
}
|
|
58750
|
+
const downgrades = availableSyncModeConversions(currentMode);
|
|
58751
|
+
for (const mode of downgrades) {
|
|
58752
|
+
options.push({
|
|
58753
|
+
label: `${syncModeIcon2(mode)} Convert to ${syncModeLabel(mode)}`,
|
|
58754
|
+
value: mode
|
|
58755
|
+
});
|
|
58756
|
+
}
|
|
58757
|
+
if (options.length === 0) {
|
|
58758
|
+
options.push({ label: "(already at most isolated mode)", value: "cancel" });
|
|
58759
|
+
}
|
|
58760
|
+
options.push({ label: "Cancel", value: "cancel" });
|
|
58761
|
+
return options;
|
|
58762
|
+
};
|
|
58763
|
+
const actionOptions = buildActionOptions();
|
|
58373
58764
|
return /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
58374
58765
|
flexDirection: "column",
|
|
58375
58766
|
width: "100",
|
|
@@ -58377,7 +58768,7 @@ var import_react72, jsx_dev_runtime12, ToggleActionValue, ToggleAction = ({ sele
|
|
|
58377
58768
|
paddingY: 1,
|
|
58378
58769
|
children: [
|
|
58379
58770
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Header, {
|
|
58380
|
-
title: "\uD83D\uDD04
|
|
58771
|
+
title: "\uD83D\uDD04 Sync Mode"
|
|
58381
58772
|
}, undefined, false, undefined, this),
|
|
58382
58773
|
error && /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(StatusBar, {
|
|
58383
58774
|
message: error,
|
|
@@ -58397,17 +58788,17 @@ var import_react72, jsx_dev_runtime12, ToggleActionValue, ToggleAction = ({ sele
|
|
|
58397
58788
|
}, undefined, false, undefined, this)
|
|
58398
58789
|
]
|
|
58399
58790
|
}, undefined, true, undefined, this),
|
|
58400
|
-
step === "action" && selected && /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(
|
|
58791
|
+
step === "action" && selected && /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(SyncModeAction, {
|
|
58401
58792
|
selected,
|
|
58402
58793
|
actionOptions,
|
|
58403
58794
|
onAction: handleAction
|
|
58404
58795
|
}, undefined, false, undefined, this),
|
|
58405
58796
|
step === "syncing" && /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Text, {
|
|
58406
58797
|
dimColor: true,
|
|
58407
|
-
children: "
|
|
58798
|
+
children: "Converting sync mode…"
|
|
58408
58799
|
}, undefined, false, undefined, this),
|
|
58409
58800
|
step === "done" && selected && /* @__PURE__ */ jsx_dev_runtime12.jsxDEV(StatusBar, {
|
|
58410
|
-
message: `
|
|
58801
|
+
message: `Sync mode set to ${syncModeIcon2(newMode)} ${syncModeLabel(newMode)} for '${selected.name}'`,
|
|
58411
58802
|
type: "success"
|
|
58412
58803
|
}, undefined, false, undefined, this),
|
|
58413
58804
|
/* @__PURE__ */ jsx_dev_runtime12.jsxDEV(Box_default, {
|
|
@@ -58424,6 +58815,8 @@ var init_ToggleAutoSync = __esm(async () => {
|
|
|
58424
58815
|
init_useConfig();
|
|
58425
58816
|
init_useMessage();
|
|
58426
58817
|
init_useAnimations();
|
|
58818
|
+
init_constants();
|
|
58819
|
+
init_config();
|
|
58427
58820
|
await __promiseAll([
|
|
58428
58821
|
init_build2(),
|
|
58429
58822
|
init_build3(),
|
|
@@ -58433,11 +58826,6 @@ var init_ToggleAutoSync = __esm(async () => {
|
|
|
58433
58826
|
]);
|
|
58434
58827
|
import_react72 = __toESM(require_react(), 1);
|
|
58435
58828
|
jsx_dev_runtime12 = __toESM(require_jsx_dev_runtime(), 1);
|
|
58436
|
-
ToggleActionValue = {
|
|
58437
|
-
Toggle: "toggle",
|
|
58438
|
-
ForceSync: "force-sync",
|
|
58439
|
-
Cancel: "cancel"
|
|
58440
|
-
};
|
|
58441
58829
|
});
|
|
58442
58830
|
|
|
58443
58831
|
// src/ink/screens/ManagePlugins.tsx
|
|
@@ -58486,7 +58874,8 @@ var import_react73, jsx_dev_runtime13, PluginSuccess = ({ message }) => {
|
|
|
58486
58874
|
removeSinglePlugin: removeSinglePlugin2,
|
|
58487
58875
|
enablePlugin: enablePlugin2,
|
|
58488
58876
|
disablePlugin: disablePlugin2,
|
|
58489
|
-
isPluginsSymlinked: isPluginsSymlinked2
|
|
58877
|
+
isPluginsSymlinked: isPluginsSymlinked2,
|
|
58878
|
+
isHalfManualSync: isHalfManualSync2
|
|
58490
58879
|
} = useConfig();
|
|
58491
58880
|
const [step, setStep] = import_react73.useState("action");
|
|
58492
58881
|
const [action, setAction] = import_react73.useState(null);
|
|
@@ -58547,7 +58936,7 @@ var import_react73, jsx_dev_runtime13, PluginSuccess = ({ message }) => {
|
|
|
58547
58936
|
return;
|
|
58548
58937
|
const modifiesPlugins = action === PluginAction.Install || action === PluginAction.Remove || action === PluginAction.Enable || action === PluginAction.Disable;
|
|
58549
58938
|
if (modifiesPlugins) {
|
|
58550
|
-
if (isPluginsSymlinked2(inst.configDir)) {
|
|
58939
|
+
if (isPluginsSymlinked2(inst.configDir) || isHalfManualSync2(inst.configDir)) {
|
|
58551
58940
|
setStep("symlink-warning");
|
|
58552
58941
|
return;
|
|
58553
58942
|
}
|
|
@@ -58667,16 +59056,16 @@ var import_react73, jsx_dev_runtime13, PluginSuccess = ({ message }) => {
|
|
|
58667
59056
|
gap: 1,
|
|
58668
59057
|
children: [
|
|
58669
59058
|
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(StatusBar, {
|
|
58670
|
-
message: `Instance '${selectedInstance}' has
|
|
59059
|
+
message: `Instance '${selectedInstance}' has symlinked plugins (sync mode).`,
|
|
58671
59060
|
type: "error"
|
|
58672
59061
|
}, undefined, false, undefined, this),
|
|
58673
59062
|
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
58674
59063
|
dimColor: true,
|
|
58675
|
-
children: "
|
|
59064
|
+
children: "Switch to full-manual mode first to manage plugins individually."
|
|
58676
59065
|
}, undefined, false, undefined, this),
|
|
58677
59066
|
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Text, {
|
|
58678
59067
|
dimColor: true,
|
|
58679
|
-
children: 'Use "\uD83D\uDD04
|
|
59068
|
+
children: 'Use "\uD83D\uDD04 Sync mode" from the main menu.'
|
|
58680
59069
|
}, undefined, false, undefined, this),
|
|
58681
59070
|
/* @__PURE__ */ jsx_dev_runtime13.jsxDEV(Box_default, {
|
|
58682
59071
|
marginTop: 1,
|
|
@@ -58812,7 +59201,7 @@ var import_react74, jsx_dev_runtime14, SymlinkResults = ({ results }) => {
|
|
|
58812
59201
|
]
|
|
58813
59202
|
}, undefined, true, undefined, this);
|
|
58814
59203
|
}, FixSymlinks = ({ onBack }) => {
|
|
58815
|
-
const { instances: instances2, detectBrokenSymlinks: detectBrokenSymlinks2, syncPluginsAndSkills: syncPluginsAndSkills2 } = useConfig();
|
|
59204
|
+
const { instances: instances2, detectBrokenSymlinks: detectBrokenSymlinks2, syncPluginsAndSkills: syncPluginsAndSkills2, halfSyncPluginsAndSkills: halfSyncPluginsAndSkills2 } = useConfig();
|
|
58816
59205
|
const [step, setStep] = import_react74.useState("select");
|
|
58817
59206
|
const [results, setResults] = import_react74.useState([]);
|
|
58818
59207
|
const { error, setError } = useMessage();
|
|
@@ -58846,10 +59235,13 @@ var import_react74, jsx_dev_runtime14, SymlinkResults = ({ results }) => {
|
|
|
58846
59235
|
]
|
|
58847
59236
|
}, undefined, true, undefined, this);
|
|
58848
59237
|
}
|
|
58849
|
-
const instanceOptions = instances2.map((i) =>
|
|
58850
|
-
|
|
58851
|
-
|
|
58852
|
-
|
|
59238
|
+
const instanceOptions = instances2.map((i) => {
|
|
59239
|
+
const mode = getSyncMode(i);
|
|
59240
|
+
return {
|
|
59241
|
+
label: `${i.name} (${mode})`,
|
|
59242
|
+
value: i.name
|
|
59243
|
+
};
|
|
59244
|
+
});
|
|
58853
59245
|
const handleSelect = async (selectedNames) => {
|
|
58854
59246
|
setStep("fixing");
|
|
58855
59247
|
setError("");
|
|
@@ -58860,15 +59252,20 @@ var import_react74, jsx_dev_runtime14, SymlinkResults = ({ results }) => {
|
|
|
58860
59252
|
return null;
|
|
58861
59253
|
const diagnosis = detectBrokenSymlinks2(instance.configDir);
|
|
58862
59254
|
const hasBroken = diagnosis.broken.length > 0;
|
|
58863
|
-
|
|
59255
|
+
const mode = getSyncMode(instance);
|
|
59256
|
+
if (hasBroken) {
|
|
58864
59257
|
try {
|
|
58865
|
-
|
|
59258
|
+
if (mode === SyncMode.Auto) {
|
|
59259
|
+
await syncPluginsAndSkills2(instance.configDir);
|
|
59260
|
+
} else if (mode === SyncMode.HalfManual) {
|
|
59261
|
+
await halfSyncPluginsAndSkills2(instance.configDir);
|
|
59262
|
+
}
|
|
58866
59263
|
return { name, broken: diagnosis.broken, all: diagnosis.all, fixed: true };
|
|
58867
59264
|
} catch {
|
|
58868
59265
|
return { name, broken: diagnosis.broken, all: diagnosis.all, fixed: false };
|
|
58869
59266
|
}
|
|
58870
59267
|
} else {
|
|
58871
|
-
return { name, broken: diagnosis.broken, all: diagnosis.all, fixed:
|
|
59268
|
+
return { name, broken: diagnosis.broken, all: diagnosis.all, fixed: true };
|
|
58872
59269
|
}
|
|
58873
59270
|
}));
|
|
58874
59271
|
setResults(fixResults.filter(Boolean));
|
|
@@ -58922,6 +59319,8 @@ var init_FixSymlinks = __esm(async () => {
|
|
|
58922
59319
|
init_useConfig();
|
|
58923
59320
|
init_useMessage();
|
|
58924
59321
|
init_useAnimations();
|
|
59322
|
+
init_constants();
|
|
59323
|
+
init_config();
|
|
58925
59324
|
await __promiseAll([
|
|
58926
59325
|
init_build2(),
|
|
58927
59326
|
init_build3(),
|
|
@@ -60167,7 +60566,7 @@ var import_react78, jsx_dev_runtime18, GoodbyeScreen = () => {
|
|
|
60167
60566
|
...instances2.length > 0 ? [
|
|
60168
60567
|
{ label: "ℹ️ Instance details", value: "info" },
|
|
60169
60568
|
{ label: "\uD83D\uDD0C Manage plugins", value: "plugins" },
|
|
60170
|
-
{ label: "\uD83D\uDD04
|
|
60569
|
+
{ label: "\uD83D\uDD04 Sync mode", value: "autosync" },
|
|
60171
60570
|
{ label: "\uD83D\uDD17 Re-sync symlinks", value: "resync" },
|
|
60172
60571
|
{ label: "\uD83D\uDDD1️ Remove instance", value: "remove" },
|
|
60173
60572
|
{ label: "⚙️ MCP servers", value: "mcp" }
|
|
@@ -60312,7 +60711,7 @@ function requireNonEmptyArgs(items, errorMsg, usage) {
|
|
|
60312
60711
|
}
|
|
60313
60712
|
var program2 = new Command;
|
|
60314
60713
|
program2.name("claude-multi").description("Manage multiple Claude Code instances with different aliases").version(getClaudeMultiVersion());
|
|
60315
|
-
program2.command("add <name>").description("Add a new Claude Code instance").option("-c, --config <dir>", "Config directory path", (name) => join9(homedir4(), `.claude-${name}`)).option("-b, --binary <path>", "Binary path (default: ~/.local/bin/claude-<name>)").option("--copy-settings", "Copy settings.json from default Claude").option("--copy-all", "Copy all files from default Claude").option("--copy-mcp", "Copy MCP server configurations from default Claude").option("--skip-prompts", "Skip interactive prompts (start fresh)").option("--provider <name>", "Use a provider template (glm, minimax, deepseek, mimo, mimo-token, kimi, qwen, qwen-coding)").option("--api-key <key>", "API key for the provider").option("--region <region>", "Region for regional providers (e.g., cn, sgp, ams for mimo-token)").option("--auto-sync", "Auto-sync plugins/skills via symlinks (default)").option("--manual", "Manually manage plugins/skills (copy
|
|
60714
|
+
program2.command("add <name>").description("Add a new Claude Code instance").option("-c, --config <dir>", "Config directory path", (name) => join9(homedir4(), `.claude-${name}`)).option("-b, --binary <path>", "Binary path (default: ~/.local/bin/claude-<name>)").option("--copy-settings", "Copy settings.json from default Claude").option("--copy-all", "Copy all files from default Claude").option("--copy-mcp", "Copy MCP server configurations from default Claude").option("--skip-prompts", "Skip interactive prompts (start fresh)").option("--provider <name>", "Use a provider template (glm, minimax, deepseek, mimo, mimo-token, kimi, qwen, qwen-coding)").option("--api-key <key>", "API key for the provider").option("--region <region>", "Region for regional providers (e.g., cn, sgp, ams for mimo-token)").option("--auto-sync", "Auto-sync plugins/skills via symlinks (default)").option("--manual", "Manually manage plugins/skills (full copy)").option("--half-manual", "Symlink individual plugins/skills, new installs stay isolated").option("--sync-mode <mode>", "Sync mode: auto, half-manual, full-manual").action(async (name, options) => {
|
|
60316
60715
|
try {
|
|
60317
60716
|
const configDir = options.config || join9(homedir4(), `.claude-${name}`);
|
|
60318
60717
|
const binaryPath = options.binary || getDefaultBinaryPath(name);
|
|
@@ -60324,7 +60723,29 @@ program2.command("add <name>").description("Add a new Claude Code instance").opt
|
|
|
60324
60723
|
let useProviderTemplate = false;
|
|
60325
60724
|
let providerTemplate = null;
|
|
60326
60725
|
let apiKey = "";
|
|
60327
|
-
let
|
|
60726
|
+
let effectiveSyncMode;
|
|
60727
|
+
const flagCount = [options.syncMode, options.autoSync, options.halfManual, options.manual].filter(Boolean).length;
|
|
60728
|
+
if (flagCount > 1) {
|
|
60729
|
+
console.error(source_default.red("✗ Conflicting sync mode flags. Use only one of: --sync-mode, --auto-sync, --half-manual, --manual"));
|
|
60730
|
+
exitWithCode(1);
|
|
60731
|
+
}
|
|
60732
|
+
if (options.syncMode) {
|
|
60733
|
+
const valid = [SyncMode.Auto, SyncMode.HalfManual, SyncMode.FullManual];
|
|
60734
|
+
if (!valid.includes(options.syncMode)) {
|
|
60735
|
+
console.error(source_default.red(`✗ Invalid sync mode '${options.syncMode}'. Use: ${valid.join(", ")}`));
|
|
60736
|
+
exitWithCode(1);
|
|
60737
|
+
}
|
|
60738
|
+
effectiveSyncMode = options.syncMode;
|
|
60739
|
+
} else if (options.autoSync) {
|
|
60740
|
+
effectiveSyncMode = SyncMode.Auto;
|
|
60741
|
+
} else if (options.halfManual) {
|
|
60742
|
+
effectiveSyncMode = SyncMode.HalfManual;
|
|
60743
|
+
} else if (options.manual) {
|
|
60744
|
+
effectiveSyncMode = SyncMode.FullManual;
|
|
60745
|
+
} else {
|
|
60746
|
+
effectiveSyncMode = SyncMode.Auto;
|
|
60747
|
+
}
|
|
60748
|
+
const autoSync = effectiveSyncMode === SyncMode.Auto;
|
|
60328
60749
|
let providerRegion;
|
|
60329
60750
|
if (options.provider) {
|
|
60330
60751
|
providerTemplate = getProviderTemplate(options.provider);
|
|
@@ -60417,6 +60838,7 @@ Found existing Claude Code configuration at ~/.claude`));
|
|
|
60417
60838
|
binaryPath,
|
|
60418
60839
|
createdAt: new Date().toISOString(),
|
|
60419
60840
|
autoSync,
|
|
60841
|
+
syncMode: effectiveSyncMode,
|
|
60420
60842
|
createdWithVersion: getClaudeMultiVersion(),
|
|
60421
60843
|
...useProviderTemplate && providerTemplate ? { providerTemplate: providerTemplate.name } : {},
|
|
60422
60844
|
...providerRegion ? { providerRegion } : {}
|
|
@@ -60438,11 +60860,13 @@ Found existing Claude Code configuration at ~/.claude`));
|
|
|
60438
60860
|
}
|
|
60439
60861
|
}
|
|
60440
60862
|
if (copyAllFiles) {
|
|
60441
|
-
await copyAllFromDefault(configDir);
|
|
60442
|
-
if (
|
|
60863
|
+
await copyAllFromDefault(configDir, effectiveSyncMode);
|
|
60864
|
+
if (effectiveSyncMode === SyncMode.Auto) {
|
|
60443
60865
|
console.log(source_default.green("✓ Copied all files with auto-sync (plugins/skills symlinked)"));
|
|
60866
|
+
} else if (effectiveSyncMode === SyncMode.HalfManual) {
|
|
60867
|
+
console.log(source_default.green("✓ Copied all files with half-manual sync (individual plugins/skills symlinked)"));
|
|
60444
60868
|
} else {
|
|
60445
|
-
console.log(source_default.green("✓ Copied all files from default Claude (manual mode)"));
|
|
60869
|
+
console.log(source_default.green("✓ Copied all files from default Claude (full-manual mode)"));
|
|
60446
60870
|
}
|
|
60447
60871
|
}
|
|
60448
60872
|
if (useProviderTemplate && providerTemplate) {
|
|
@@ -60519,8 +60943,10 @@ program2.command("list").alias("ls").description("List all Claude Code instances
|
|
|
60519
60943
|
const region = instance.providerRegion ? ` (${instance.providerRegion})` : "";
|
|
60520
60944
|
console.log(source_default.gray(` Provider: ${instance.providerTemplate}${region}`));
|
|
60521
60945
|
}
|
|
60522
|
-
const
|
|
60523
|
-
|
|
60946
|
+
const mode = getSyncMode(instance);
|
|
60947
|
+
const label = syncModeLabel(mode);
|
|
60948
|
+
const modeColor = mode === SyncMode.Auto ? source_default.green : mode === SyncMode.HalfManual ? source_default.cyan : source_default.yellow;
|
|
60949
|
+
console.log(source_default.gray(` Sync mode: ${modeColor(label)}`));
|
|
60524
60950
|
console.log(source_default.gray(` Version: ${formatVersionLabel(instance.createdWithVersion)}`));
|
|
60525
60951
|
console.log();
|
|
60526
60952
|
}
|
|
@@ -60537,8 +60963,9 @@ program2.command("info <name>").description("Show details about a specific insta
|
|
|
60537
60963
|
console.log(`${source_default.gray("Binary:")} ${instance.binaryPath}`);
|
|
60538
60964
|
console.log(`${source_default.gray("Config:")} ${instance.configDir}`);
|
|
60539
60965
|
console.log(`${source_default.gray("Created:")} ${new Date(instance.createdAt).toLocaleString()}`);
|
|
60540
|
-
const
|
|
60541
|
-
|
|
60966
|
+
const mode = getSyncMode(instance);
|
|
60967
|
+
const modeColor = mode === SyncMode.Auto ? source_default.green : mode === SyncMode.HalfManual ? source_default.cyan : source_default.yellow;
|
|
60968
|
+
console.log(`${source_default.gray("Sync mode:")} ${modeColor(syncModeLabel(mode))}`);
|
|
60542
60969
|
console.log(`${source_default.gray("Version:")} ${formatVersionLabel(instance.createdWithVersion)}`);
|
|
60543
60970
|
if (instance.providerTemplate) {
|
|
60544
60971
|
const region = instance.providerRegion ? ` (${instance.providerRegion})` : "";
|
|
@@ -60585,27 +61012,36 @@ program2.command("update").description("Update @anthropic-ai/claude-code to the
|
|
|
60585
61012
|
exitWithCode(1);
|
|
60586
61013
|
}
|
|
60587
61014
|
});
|
|
60588
|
-
program2.command("auto-sync <name> <status>").description("
|
|
61015
|
+
program2.command("auto-sync <name> <status>").description("Set sync mode for plugins/skills (auto, half-manual, full-manual, on, off)").action(async (name, status) => {
|
|
60589
61016
|
try {
|
|
60590
61017
|
const instance = await requireInstance(name);
|
|
61018
|
+
const currentMode = getSyncMode(instance);
|
|
60591
61019
|
const normalized = status.toLowerCase();
|
|
60592
|
-
|
|
60593
|
-
|
|
60594
|
-
|
|
60595
|
-
|
|
61020
|
+
let newMode;
|
|
61021
|
+
if (normalized === "on" || normalized === "true" || status === "1") {
|
|
61022
|
+
newMode = SyncMode.Auto;
|
|
61023
|
+
} else if (normalized === "off" || normalized === "false" || status === "0") {
|
|
61024
|
+
newMode = SyncMode.FullManual;
|
|
61025
|
+
} else if (normalized === SyncMode.Auto || normalized === SyncMode.HalfManual || normalized === SyncMode.FullManual) {
|
|
61026
|
+
newMode = normalized;
|
|
61027
|
+
} else {
|
|
61028
|
+
console.error(source_default.red(`✗ Unknown sync mode '${status}'. Use: auto, half-manual, full-manual, on, off`));
|
|
61029
|
+
exitWithCode(1);
|
|
61030
|
+
}
|
|
61031
|
+
if (currentMode === newMode) {
|
|
61032
|
+
console.log(source_default.yellow(`Sync mode is already '${syncModeLabel(newMode)}' for '${name}'`));
|
|
60596
61033
|
return;
|
|
60597
61034
|
}
|
|
60598
|
-
|
|
61035
|
+
if (!canConvertSyncMode(currentMode, newMode)) {
|
|
61036
|
+
console.error(source_default.red(`✗ Cannot convert from '${syncModeLabel(currentMode)}' to '${syncModeLabel(newMode)}'. Only downgrades are allowed (auto → half-manual → full-manual).`));
|
|
61037
|
+
exitWithCode(1);
|
|
61038
|
+
}
|
|
60599
61039
|
console.log(source_default.bold(`
|
|
60600
|
-
\uD83D\uDD04 ${
|
|
61040
|
+
\uD83D\uDD04 Converting '${name}' from ${syncModeLabel(currentMode)} → ${syncModeLabel(newMode)}...
|
|
60601
61041
|
`));
|
|
60602
|
-
|
|
60603
|
-
await syncPluginsAndSkills(instance.configDir);
|
|
60604
|
-
} else {
|
|
60605
|
-
await unsyncPluginsAndSkills(instance.configDir);
|
|
60606
|
-
}
|
|
61042
|
+
await updateInstanceSyncMode(name, newMode);
|
|
60607
61043
|
console.log(source_default.green(`
|
|
60608
|
-
✓
|
|
61044
|
+
✓ Sync mode set to '${syncModeLabel(newMode)}' for '${name}'`));
|
|
60609
61045
|
} catch (error) {
|
|
60610
61046
|
console.error(source_default.red(`✗ Error: ${toMessage(error)}`));
|
|
60611
61047
|
exitWithCode(1);
|
|
@@ -60855,6 +61291,10 @@ async function handlePluginsInstall(instanceName, pluginIds) {
|
|
|
60855
61291
|
console.error(source_default.red("✗ Instance has auto-sync enabled (symlinked plugins). Disable auto-sync first."));
|
|
60856
61292
|
exitWithCode(1);
|
|
60857
61293
|
}
|
|
61294
|
+
if (isHalfManualSync(instance.configDir)) {
|
|
61295
|
+
console.error(source_default.red("✗ Instance has half-manual sync (individually symlinked plugins). Switch to full-manual first."));
|
|
61296
|
+
exitWithCode(1);
|
|
61297
|
+
}
|
|
60858
61298
|
if (pluginIds.length === 0) {
|
|
60859
61299
|
console.error(source_default.red("✗ No plugins specified"));
|
|
60860
61300
|
console.log(source_default.gray("Usage: claude-multi plugins install <instance> <plugin-id>..."));
|
|
@@ -60889,6 +61329,10 @@ async function handlePluginsRemove(instanceName, pluginIds) {
|
|
|
60889
61329
|
console.error(source_default.red("✗ Instance has auto-sync enabled (symlinked plugins). Disable auto-sync first."));
|
|
60890
61330
|
exitWithCode(1);
|
|
60891
61331
|
}
|
|
61332
|
+
if (isHalfManualSync(instance.configDir)) {
|
|
61333
|
+
console.error(source_default.red("✗ Instance has half-manual sync (individually symlinked plugins). Switch to full-manual first."));
|
|
61334
|
+
exitWithCode(1);
|
|
61335
|
+
}
|
|
60892
61336
|
requireNonEmptyArgs(pluginIds, "✗ No plugins specified", "Usage: claude-multi plugins remove <instance> <plugin-id>...");
|
|
60893
61337
|
const installed = listInstancePlugins(instance.configDir);
|
|
60894
61338
|
const installedMap = new Map(installed.map((ip) => [ip.id, ip]));
|
|
@@ -61007,7 +61451,7 @@ async function handleFixSymlinks(names, fixAll) {
|
|
|
61007
61451
|
name: "selected",
|
|
61008
61452
|
message: "Select instances to fix:",
|
|
61009
61453
|
choices: instances2.map((i) => ({
|
|
61010
|
-
title: `${i.name} ${i
|
|
61454
|
+
title: `${i.name} (${getSyncMode(i)})`,
|
|
61011
61455
|
value: i.name
|
|
61012
61456
|
}))
|
|
61013
61457
|
});
|
|
@@ -61019,28 +61463,38 @@ async function handleFixSymlinks(names, fixAll) {
|
|
|
61019
61463
|
const fixResults = await Promise.all(instancesToFix.map(async (instance) => {
|
|
61020
61464
|
const diagnosis = detectBrokenSymlinks(instance.configDir);
|
|
61021
61465
|
const needsFix = diagnosis.broken.length > 0;
|
|
61466
|
+
const mode = getSyncMode(instance);
|
|
61022
61467
|
let fixed = false;
|
|
61023
|
-
if (needsFix
|
|
61024
|
-
|
|
61025
|
-
|
|
61468
|
+
if (needsFix) {
|
|
61469
|
+
try {
|
|
61470
|
+
if (mode === SyncMode.Auto) {
|
|
61471
|
+
await syncPluginsAndSkills(instance.configDir);
|
|
61472
|
+
fixed = true;
|
|
61473
|
+
} else if (mode === SyncMode.HalfManual) {
|
|
61474
|
+
await halfSyncPluginsAndSkills(instance.configDir);
|
|
61475
|
+
fixed = true;
|
|
61476
|
+
}
|
|
61477
|
+
} catch {}
|
|
61026
61478
|
}
|
|
61027
|
-
return { instance, diagnosis, needsFix, fixed };
|
|
61479
|
+
return { instance, diagnosis, needsFix, fixed, mode };
|
|
61028
61480
|
}));
|
|
61029
|
-
for (const { instance, diagnosis, needsFix } of fixResults) {
|
|
61481
|
+
for (const { instance, diagnosis, needsFix, fixed, mode } of fixResults) {
|
|
61030
61482
|
console.log(source_default.bold(`
|
|
61031
61483
|
\uD83D\uDD0D ${instance.name}`));
|
|
61032
61484
|
console.log(` Config: ${instance.configDir}`);
|
|
61033
|
-
console.log(`
|
|
61485
|
+
console.log(` Sync mode: ${syncModeLabel(mode)}`);
|
|
61034
61486
|
if (diagnosis.all.length === 0) {
|
|
61035
|
-
console.log(source_default.gray(" No symlinks found (manual mode)"));
|
|
61487
|
+
console.log(source_default.gray(" No symlinks found (full-manual mode)"));
|
|
61036
61488
|
continue;
|
|
61037
61489
|
}
|
|
61038
61490
|
if (needsFix) {
|
|
61039
61491
|
console.log(source_default.red(` ❌ Broken: ${diagnosis.broken.join(", ")}`));
|
|
61040
|
-
if (
|
|
61492
|
+
if (fixed) {
|
|
61041
61493
|
console.log(source_default.green(` ✅ Fixed: ${diagnosis.broken.join(", ")}`));
|
|
61494
|
+
} else if (mode === SyncMode.FullManual) {
|
|
61495
|
+
console.log(source_default.yellow(" ⚠ Full-manual mode — no symlinks to repair."));
|
|
61042
61496
|
} else {
|
|
61043
|
-
console.log(source_default.yellow(" ⚠
|
|
61497
|
+
console.log(source_default.yellow(" ⚠ Could not auto-repair. Try re-syncing via 'claude-multi auto-sync'."));
|
|
61044
61498
|
}
|
|
61045
61499
|
} else {
|
|
61046
61500
|
console.log(source_default.green(` ✅ All symlinks OK: ${diagnosis.all.join(", ")}`));
|