cc-mirror 1.0.4 → 1.1.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/README.md +168 -98
- package/dist/cc-mirror.mjs +788 -249
- package/dist/skills/multi-agent-orchestrator/SKILL.md +391 -0
- package/dist/skills/multi-agent-orchestrator/references/code-review.md +266 -0
- package/dist/skills/multi-agent-orchestrator/references/data-analysis.md +315 -0
- package/dist/skills/multi-agent-orchestrator/references/devops.md +309 -0
- package/dist/skills/multi-agent-orchestrator/references/documentation.md +310 -0
- package/dist/skills/multi-agent-orchestrator/references/domains/code-review.md +301 -0
- package/dist/skills/multi-agent-orchestrator/references/domains/data-analysis.md +347 -0
- package/dist/skills/multi-agent-orchestrator/references/domains/devops.md +340 -0
- package/dist/skills/multi-agent-orchestrator/references/domains/documentation.md +343 -0
- package/dist/skills/multi-agent-orchestrator/references/domains/project-management.md +370 -0
- package/dist/skills/multi-agent-orchestrator/references/domains/research.md +322 -0
- package/dist/skills/multi-agent-orchestrator/references/domains/software-development.md +269 -0
- package/dist/skills/multi-agent-orchestrator/references/domains/testing.md +313 -0
- package/dist/skills/multi-agent-orchestrator/references/examples.md +377 -0
- package/dist/skills/multi-agent-orchestrator/references/guide.md +327 -0
- package/dist/skills/multi-agent-orchestrator/references/patterns.md +441 -0
- package/dist/skills/multi-agent-orchestrator/references/project-management.md +345 -0
- package/dist/skills/multi-agent-orchestrator/references/research.md +285 -0
- package/dist/skills/multi-agent-orchestrator/references/software-development.md +242 -0
- package/dist/skills/multi-agent-orchestrator/references/testing.md +282 -0
- package/dist/skills/multi-agent-orchestrator/references/tools.md +454 -0
- package/dist/tui.mjs +1045 -360
- package/package.json +2 -2
package/dist/tui.mjs
CHANGED
|
@@ -8,10 +8,10 @@ var __export = (target, all) => {
|
|
|
8
8
|
import { render } from "ink";
|
|
9
9
|
|
|
10
10
|
// src/tui/app.tsx
|
|
11
|
-
import { useCallback, useEffect as
|
|
11
|
+
import { useCallback, useEffect as useEffect8, useMemo as useMemo3, useState as useState13 } from "react";
|
|
12
12
|
import { Box as Box25, Text as Text23, useApp, useInput as useInput13 } from "ink";
|
|
13
13
|
import SelectInput from "ink-select-input";
|
|
14
|
-
import
|
|
14
|
+
import path24 from "node:path";
|
|
15
15
|
|
|
16
16
|
// src/brands/index.ts
|
|
17
17
|
var brands_exports = {};
|
|
@@ -1276,6 +1276,203 @@ var buildCCRouterTweakccConfig = () => ({
|
|
|
1276
1276
|
}
|
|
1277
1277
|
});
|
|
1278
1278
|
|
|
1279
|
+
// src/brands/mirror.ts
|
|
1280
|
+
var clamp5 = (value) => Math.max(0, Math.min(255, Math.round(value)));
|
|
1281
|
+
var hexToRgb5 = (hex) => {
|
|
1282
|
+
const normalized = hex.replace("#", "").trim();
|
|
1283
|
+
if (normalized.length === 3) {
|
|
1284
|
+
const [r, g, b] = normalized.split("");
|
|
1285
|
+
return {
|
|
1286
|
+
r: clamp5(parseInt(r + r, 16)),
|
|
1287
|
+
g: clamp5(parseInt(g + g, 16)),
|
|
1288
|
+
b: clamp5(parseInt(b + b, 16))
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
if (normalized.length !== 6) {
|
|
1292
|
+
throw new Error(`Unsupported hex color: ${hex}`);
|
|
1293
|
+
}
|
|
1294
|
+
return {
|
|
1295
|
+
r: clamp5(parseInt(normalized.slice(0, 2), 16)),
|
|
1296
|
+
g: clamp5(parseInt(normalized.slice(2, 4), 16)),
|
|
1297
|
+
b: clamp5(parseInt(normalized.slice(4, 6), 16))
|
|
1298
|
+
};
|
|
1299
|
+
};
|
|
1300
|
+
var rgb5 = (hex) => {
|
|
1301
|
+
const { r, g, b } = hexToRgb5(hex);
|
|
1302
|
+
return `rgb(${r},${g},${b})`;
|
|
1303
|
+
};
|
|
1304
|
+
var mix5 = (hexA, hexB, weight) => {
|
|
1305
|
+
const a = hexToRgb5(hexA);
|
|
1306
|
+
const b = hexToRgb5(hexB);
|
|
1307
|
+
const w = Math.max(0, Math.min(1, weight));
|
|
1308
|
+
return `rgb(${clamp5(a.r + (b.r - a.r) * w)},${clamp5(a.g + (b.g - a.g) * w)},${clamp5(a.b + (b.b - a.b) * w)})`;
|
|
1309
|
+
};
|
|
1310
|
+
var lighten5 = (hex, weight) => mix5(hex, "#ffffff", weight);
|
|
1311
|
+
var palette5 = {
|
|
1312
|
+
// Base surfaces - near-black with metallic sheen
|
|
1313
|
+
base: "#0d0f12",
|
|
1314
|
+
surface: "#14161a",
|
|
1315
|
+
panel: "#1a1d22",
|
|
1316
|
+
elevated: "#22262d",
|
|
1317
|
+
// Borders - subtle silver
|
|
1318
|
+
border: "#3a3f48",
|
|
1319
|
+
borderStrong: "#4a5058",
|
|
1320
|
+
borderGlow: "#6a7078",
|
|
1321
|
+
// Text
|
|
1322
|
+
text: "#e8eaed",
|
|
1323
|
+
textMuted: "#b0b5bc",
|
|
1324
|
+
textDim: "#7a8088",
|
|
1325
|
+
// Primary: Silver/Chrome
|
|
1326
|
+
silver: "#c0c0c0",
|
|
1327
|
+
chrome: "#a0a0a0",
|
|
1328
|
+
platinum: "#e5e4e2",
|
|
1329
|
+
// Accent: Electric blue
|
|
1330
|
+
electric: "#00d4ff",
|
|
1331
|
+
electricSoft: "#4de1ff",
|
|
1332
|
+
electricDeep: "#00a3cc",
|
|
1333
|
+
// Secondary: Deep purple
|
|
1334
|
+
purple: "#6b5b95",
|
|
1335
|
+
purpleSoft: "#8a7ab4",
|
|
1336
|
+
// Semantic
|
|
1337
|
+
green: "#4ade80",
|
|
1338
|
+
red: "#f87171",
|
|
1339
|
+
orange: "#fb923c",
|
|
1340
|
+
cyan: "#22d3ee"
|
|
1341
|
+
};
|
|
1342
|
+
var theme4 = {
|
|
1343
|
+
name: "Mirror Claude",
|
|
1344
|
+
id: "mirror-claude",
|
|
1345
|
+
colors: {
|
|
1346
|
+
autoAccept: rgb5(palette5.green),
|
|
1347
|
+
bashBorder: rgb5(palette5.electric),
|
|
1348
|
+
claude: rgb5(palette5.silver),
|
|
1349
|
+
claudeShimmer: rgb5(palette5.platinum),
|
|
1350
|
+
claudeBlue_FOR_SYSTEM_SPINNER: rgb5(palette5.electric),
|
|
1351
|
+
claudeBlueShimmer_FOR_SYSTEM_SPINNER: lighten5(palette5.electric, 0.2),
|
|
1352
|
+
permission: rgb5(palette5.electricSoft),
|
|
1353
|
+
permissionShimmer: lighten5(palette5.electricSoft, 0.25),
|
|
1354
|
+
planMode: rgb5(palette5.purple),
|
|
1355
|
+
ide: rgb5(palette5.cyan),
|
|
1356
|
+
promptBorder: rgb5(palette5.border),
|
|
1357
|
+
promptBorderShimmer: rgb5(palette5.borderGlow),
|
|
1358
|
+
text: rgb5(palette5.text),
|
|
1359
|
+
inverseText: rgb5(palette5.base),
|
|
1360
|
+
inactive: rgb5(palette5.textDim),
|
|
1361
|
+
subtle: mix5(palette5.base, palette5.chrome, 0.08),
|
|
1362
|
+
suggestion: rgb5(palette5.electricSoft),
|
|
1363
|
+
remember: rgb5(palette5.purple),
|
|
1364
|
+
background: rgb5(palette5.base),
|
|
1365
|
+
success: rgb5(palette5.green),
|
|
1366
|
+
error: rgb5(palette5.red),
|
|
1367
|
+
warning: rgb5(palette5.orange),
|
|
1368
|
+
warningShimmer: lighten5(palette5.orange, 0.28),
|
|
1369
|
+
diffAdded: mix5(palette5.base, palette5.green, 0.15),
|
|
1370
|
+
diffRemoved: mix5(palette5.base, palette5.red, 0.15),
|
|
1371
|
+
diffAddedDimmed: mix5(palette5.base, palette5.green, 0.08),
|
|
1372
|
+
diffRemovedDimmed: mix5(palette5.base, palette5.red, 0.08),
|
|
1373
|
+
diffAddedWord: mix5(palette5.base, palette5.green, 0.32),
|
|
1374
|
+
diffRemovedWord: mix5(palette5.base, palette5.red, 0.32),
|
|
1375
|
+
diffAddedWordDimmed: mix5(palette5.base, palette5.green, 0.18),
|
|
1376
|
+
diffRemovedWordDimmed: mix5(palette5.base, palette5.red, 0.18),
|
|
1377
|
+
red_FOR_SUBAGENTS_ONLY: rgb5(palette5.red),
|
|
1378
|
+
blue_FOR_SUBAGENTS_ONLY: rgb5(palette5.electric),
|
|
1379
|
+
green_FOR_SUBAGENTS_ONLY: rgb5(palette5.green),
|
|
1380
|
+
yellow_FOR_SUBAGENTS_ONLY: rgb5(palette5.orange),
|
|
1381
|
+
purple_FOR_SUBAGENTS_ONLY: rgb5(palette5.purple),
|
|
1382
|
+
orange_FOR_SUBAGENTS_ONLY: rgb5(palette5.orange),
|
|
1383
|
+
pink_FOR_SUBAGENTS_ONLY: lighten5(palette5.purple, 0.32),
|
|
1384
|
+
cyan_FOR_SUBAGENTS_ONLY: rgb5(palette5.cyan),
|
|
1385
|
+
professionalBlue: rgb5(palette5.electric),
|
|
1386
|
+
rainbow_red: rgb5(palette5.red),
|
|
1387
|
+
rainbow_orange: rgb5(palette5.orange),
|
|
1388
|
+
rainbow_yellow: lighten5(palette5.orange, 0.18),
|
|
1389
|
+
rainbow_green: rgb5(palette5.green),
|
|
1390
|
+
rainbow_blue: rgb5(palette5.electricSoft),
|
|
1391
|
+
rainbow_indigo: rgb5(palette5.electricDeep),
|
|
1392
|
+
rainbow_violet: rgb5(palette5.purple),
|
|
1393
|
+
rainbow_red_shimmer: lighten5(palette5.red, 0.35),
|
|
1394
|
+
rainbow_orange_shimmer: lighten5(palette5.orange, 0.35),
|
|
1395
|
+
rainbow_yellow_shimmer: lighten5(palette5.orange, 0.3),
|
|
1396
|
+
rainbow_green_shimmer: lighten5(palette5.green, 0.35),
|
|
1397
|
+
rainbow_blue_shimmer: lighten5(palette5.electricSoft, 0.35),
|
|
1398
|
+
rainbow_indigo_shimmer: lighten5(palette5.electricDeep, 0.35),
|
|
1399
|
+
rainbow_violet_shimmer: lighten5(palette5.purple, 0.35),
|
|
1400
|
+
clawd_body: rgb5(palette5.silver),
|
|
1401
|
+
clawd_background: rgb5(palette5.base),
|
|
1402
|
+
userMessageBackground: rgb5(palette5.panel),
|
|
1403
|
+
bashMessageBackgroundColor: rgb5(palette5.surface),
|
|
1404
|
+
memoryBackgroundColor: mix5(palette5.panel, palette5.purple, 0.08),
|
|
1405
|
+
rate_limit_fill: rgb5(palette5.electric),
|
|
1406
|
+
rate_limit_empty: rgb5(palette5.borderStrong)
|
|
1407
|
+
}
|
|
1408
|
+
};
|
|
1409
|
+
var buildMirrorTweakccConfig = () => ({
|
|
1410
|
+
ccVersion: "",
|
|
1411
|
+
ccInstallationPath: null,
|
|
1412
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1413
|
+
changesApplied: false,
|
|
1414
|
+
hidePiebaldAnnouncement: true,
|
|
1415
|
+
settings: {
|
|
1416
|
+
themes: [theme4, ...DEFAULT_THEMES],
|
|
1417
|
+
thinkingVerbs: {
|
|
1418
|
+
format: "{}... ",
|
|
1419
|
+
verbs: [
|
|
1420
|
+
"Reflecting",
|
|
1421
|
+
"Refracting",
|
|
1422
|
+
"Projecting",
|
|
1423
|
+
"Mirroring",
|
|
1424
|
+
"Amplifying",
|
|
1425
|
+
"Focusing",
|
|
1426
|
+
"Polishing",
|
|
1427
|
+
"Crystallizing",
|
|
1428
|
+
"Calibrating",
|
|
1429
|
+
"Synthesizing",
|
|
1430
|
+
"Resolving",
|
|
1431
|
+
"Composing",
|
|
1432
|
+
"Rendering",
|
|
1433
|
+
"Finalizing"
|
|
1434
|
+
]
|
|
1435
|
+
},
|
|
1436
|
+
thinkingStyle: {
|
|
1437
|
+
updateInterval: 100,
|
|
1438
|
+
phases: ["\u25C7", "\u25C6", "\u25C7", "\u25C8"],
|
|
1439
|
+
reverseMirror: true
|
|
1440
|
+
},
|
|
1441
|
+
userMessageDisplay: {
|
|
1442
|
+
format: formatUserMessage(getUserLabel()),
|
|
1443
|
+
styling: ["bold"],
|
|
1444
|
+
foregroundColor: rgb5(palette5.platinum),
|
|
1445
|
+
backgroundColor: rgb5(palette5.panel),
|
|
1446
|
+
borderStyle: "topBottomDouble",
|
|
1447
|
+
borderColor: rgb5(palette5.silver),
|
|
1448
|
+
paddingX: 1,
|
|
1449
|
+
paddingY: 0,
|
|
1450
|
+
fitBoxToContent: true
|
|
1451
|
+
},
|
|
1452
|
+
inputBox: {
|
|
1453
|
+
removeBorder: true
|
|
1454
|
+
},
|
|
1455
|
+
misc: {
|
|
1456
|
+
showTweakccVersion: false,
|
|
1457
|
+
showPatchesApplied: false,
|
|
1458
|
+
expandThinkingBlocks: true,
|
|
1459
|
+
enableConversationTitle: true,
|
|
1460
|
+
hideStartupBanner: true,
|
|
1461
|
+
hideCtrlGToEditPrompt: true,
|
|
1462
|
+
hideStartupClawd: true,
|
|
1463
|
+
increaseFileReadLimit: true
|
|
1464
|
+
},
|
|
1465
|
+
toolsets: [
|
|
1466
|
+
{
|
|
1467
|
+
name: "mirror",
|
|
1468
|
+
allowedTools: "*"
|
|
1469
|
+
}
|
|
1470
|
+
],
|
|
1471
|
+
defaultToolset: "mirror",
|
|
1472
|
+
planModeToolset: "mirror"
|
|
1473
|
+
}
|
|
1474
|
+
});
|
|
1475
|
+
|
|
1279
1476
|
// src/brands/index.ts
|
|
1280
1477
|
var BRAND_PRESETS = {
|
|
1281
1478
|
zai: {
|
|
@@ -1301,6 +1498,12 @@ var BRAND_PRESETS = {
|
|
|
1301
1498
|
label: "CCRouter Sky",
|
|
1302
1499
|
description: "Airy sky-blue accents for Claude Code Router.",
|
|
1303
1500
|
buildTweakccConfig: buildCCRouterTweakccConfig
|
|
1501
|
+
},
|
|
1502
|
+
mirror: {
|
|
1503
|
+
key: "mirror",
|
|
1504
|
+
label: "Mirror Claude",
|
|
1505
|
+
description: "Reflective silver/chrome theme for pure Claude Code experience.",
|
|
1506
|
+
buildTweakccConfig: buildMirrorTweakccConfig
|
|
1304
1507
|
}
|
|
1305
1508
|
};
|
|
1306
1509
|
var listBrandPresets = () => Object.values(BRAND_PRESETS);
|
|
@@ -1328,8 +1531,8 @@ var buildBrandConfig = (brandKey) => {
|
|
|
1328
1531
|
var getBrandThemeId = (brandKey) => {
|
|
1329
1532
|
if (!brandKey) return null;
|
|
1330
1533
|
const config = buildBrandConfig(brandKey);
|
|
1331
|
-
const
|
|
1332
|
-
return
|
|
1534
|
+
const theme5 = config.settings?.themes?.[0];
|
|
1535
|
+
return theme5?.id ?? null;
|
|
1333
1536
|
};
|
|
1334
1537
|
|
|
1335
1538
|
// src/core/index.ts
|
|
@@ -1349,8 +1552,8 @@ __export(core_exports, {
|
|
|
1349
1552
|
updateVariant: () => updateVariant,
|
|
1350
1553
|
updateVariantAsync: () => updateVariantAsync
|
|
1351
1554
|
});
|
|
1352
|
-
import
|
|
1353
|
-
import
|
|
1555
|
+
import fs12 from "node:fs";
|
|
1556
|
+
import path21 from "node:path";
|
|
1354
1557
|
|
|
1355
1558
|
// src/core/constants.ts
|
|
1356
1559
|
import os2 from "node:os";
|
|
@@ -1418,7 +1621,7 @@ var ensureTweakccConfig = (tweakDir, brandKey) => {
|
|
|
1418
1621
|
let didUpdate = false;
|
|
1419
1622
|
if (brandKey === "minimax" && existingThemes.length > 0) {
|
|
1420
1623
|
const filtered = existingThemes.filter(
|
|
1421
|
-
(
|
|
1624
|
+
(theme5) => theme5?.id !== "minimax-ember" && theme5?.id !== "minimax-glass" && theme5?.id !== "minimax-blade" && theme5?.name !== "MiniMax Ember" && theme5?.name !== "MiniMax Glass" && theme5?.name !== "MiniMax Blade"
|
|
1422
1625
|
);
|
|
1423
1626
|
if (filtered.length !== existingThemes.length) {
|
|
1424
1627
|
existingThemes = filtered;
|
|
@@ -1462,10 +1665,10 @@ var ensureTweakccConfig = (tweakDir, brandKey) => {
|
|
|
1462
1665
|
if (brandThemes.length > 0) {
|
|
1463
1666
|
const mergedThemes = [
|
|
1464
1667
|
...brandThemes,
|
|
1465
|
-
...existingThemes.filter((existingTheme) => !brandThemes.some((
|
|
1668
|
+
...existingThemes.filter((existingTheme) => !brandThemes.some((theme5) => themeMatches(existingTheme, theme5)))
|
|
1466
1669
|
];
|
|
1467
1670
|
const sameLength = mergedThemes.length === existingThemes.length;
|
|
1468
|
-
const sameOrder = sameLength && mergedThemes.every((
|
|
1671
|
+
const sameOrder = sameLength && mergedThemes.every((theme5, idx) => themeMatches(theme5, existingThemes[idx]));
|
|
1469
1672
|
if (!sameOrder) {
|
|
1470
1673
|
existing.settings = { ...existing.settings, themes: mergedThemes };
|
|
1471
1674
|
didUpdate = true;
|
|
@@ -1617,7 +1820,7 @@ var listVariants = (rootDir) => {
|
|
|
1617
1820
|
};
|
|
1618
1821
|
|
|
1619
1822
|
// src/core/variant-builder/VariantBuilder.ts
|
|
1620
|
-
import
|
|
1823
|
+
import path15 from "node:path";
|
|
1621
1824
|
|
|
1622
1825
|
// src/providers/index.ts
|
|
1623
1826
|
var providers_exports = {};
|
|
@@ -1699,6 +1902,29 @@ var PROVIDERS = {
|
|
|
1699
1902
|
credentialOptional: true
|
|
1700
1903
|
// No API key needed - CCRouter handles auth
|
|
1701
1904
|
},
|
|
1905
|
+
mirror: {
|
|
1906
|
+
key: "mirror",
|
|
1907
|
+
label: "Mirror Claude",
|
|
1908
|
+
description: "Pure Claude Code with advanced features (team mode, custom theme)",
|
|
1909
|
+
baseUrl: "",
|
|
1910
|
+
// Empty = use Claude Code defaults (no ANTHROPIC_BASE_URL override)
|
|
1911
|
+
env: {
|
|
1912
|
+
// Only cosmetic settings - no auth or model overrides
|
|
1913
|
+
CC_MIRROR_SPLASH: 1,
|
|
1914
|
+
CC_MIRROR_PROVIDER_LABEL: "Mirror Claude",
|
|
1915
|
+
CC_MIRROR_SPLASH_STYLE: "mirror"
|
|
1916
|
+
},
|
|
1917
|
+
apiKeyLabel: "",
|
|
1918
|
+
// Empty = skip API key prompt
|
|
1919
|
+
authMode: "none",
|
|
1920
|
+
// No auth handling - user authenticates via normal Claude flow
|
|
1921
|
+
credentialOptional: true,
|
|
1922
|
+
// No credentials required at create time
|
|
1923
|
+
enablesTeamMode: true,
|
|
1924
|
+
// Auto-enable team mode patch
|
|
1925
|
+
noPromptPack: true
|
|
1926
|
+
// Skip prompt pack (pure Claude experience)
|
|
1927
|
+
},
|
|
1702
1928
|
custom: {
|
|
1703
1929
|
key: "custom",
|
|
1704
1930
|
label: "Custom",
|
|
@@ -1744,6 +1970,19 @@ var buildEnv = ({ providerKey, baseUrl, apiKey, extraEnv, modelOverrides }) => {
|
|
|
1744
1970
|
}
|
|
1745
1971
|
const env = { ...provider.env };
|
|
1746
1972
|
const authMode = provider.authMode ?? "apiKey";
|
|
1973
|
+
if (authMode === "none") {
|
|
1974
|
+
if (Array.isArray(extraEnv)) {
|
|
1975
|
+
for (const entry of extraEnv) {
|
|
1976
|
+
const idx = entry.indexOf("=");
|
|
1977
|
+
if (idx === -1) continue;
|
|
1978
|
+
const key = entry.slice(0, idx).trim();
|
|
1979
|
+
const value = entry.slice(idx + 1).trim();
|
|
1980
|
+
if (!key) continue;
|
|
1981
|
+
env[key] = value;
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
return env;
|
|
1985
|
+
}
|
|
1747
1986
|
if (!Object.hasOwn(env, "DISABLE_AUTOUPDATER")) {
|
|
1748
1987
|
env.DISABLE_AUTOUPDATER = "1";
|
|
1749
1988
|
}
|
|
@@ -1919,12 +2158,309 @@ var InstallNpmStep = class {
|
|
|
1919
2158
|
}
|
|
1920
2159
|
};
|
|
1921
2160
|
|
|
1922
|
-
// src/core/variant-builder/steps/
|
|
2161
|
+
// src/core/variant-builder/steps/TeamModeStep.ts
|
|
2162
|
+
import fs6 from "node:fs";
|
|
1923
2163
|
import path7 from "node:path";
|
|
1924
2164
|
|
|
1925
|
-
// src/core/
|
|
2165
|
+
// src/core/skills.ts
|
|
1926
2166
|
import fs5 from "node:fs";
|
|
2167
|
+
import os4 from "node:os";
|
|
1927
2168
|
import path6 from "node:path";
|
|
2169
|
+
import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
|
|
2170
|
+
import { fileURLToPath } from "node:url";
|
|
2171
|
+
var DEV_BROWSER_REPO = "https://github.com/SawyerHood/dev-browser.git";
|
|
2172
|
+
var DEV_BROWSER_ARCHIVE = "https://github.com/SawyerHood/dev-browser/archive/refs/heads/main.tar.gz";
|
|
2173
|
+
var SKILL_SUBDIR = path6.join("skills", "dev-browser");
|
|
2174
|
+
var MANAGED_MARKER = ".cc-mirror-managed";
|
|
2175
|
+
var ensureDir2 = (dir) => {
|
|
2176
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
2177
|
+
};
|
|
2178
|
+
var copyDir = (source, target) => {
|
|
2179
|
+
fs5.cpSync(source, target, { recursive: true });
|
|
2180
|
+
};
|
|
2181
|
+
var resolveSkillSourceDir = (repoDir) => {
|
|
2182
|
+
const direct = path6.join(repoDir, SKILL_SUBDIR);
|
|
2183
|
+
if (fs5.existsSync(direct)) return direct;
|
|
2184
|
+
const nested = fs5.readdirSync(repoDir).find((entry) => entry.startsWith("dev-browser-"));
|
|
2185
|
+
if (nested) {
|
|
2186
|
+
const candidate = path6.join(repoDir, nested, SKILL_SUBDIR);
|
|
2187
|
+
if (fs5.existsSync(candidate)) return candidate;
|
|
2188
|
+
}
|
|
2189
|
+
return null;
|
|
2190
|
+
};
|
|
2191
|
+
var cloneRepo = (targetDir) => {
|
|
2192
|
+
if (!commandExists("git")) return { ok: false, message: "git not found" };
|
|
2193
|
+
const result = spawnSync4("git", ["clone", "--depth", "1", DEV_BROWSER_REPO, targetDir], {
|
|
2194
|
+
encoding: "utf8"
|
|
2195
|
+
});
|
|
2196
|
+
if (result.status === 0) return { ok: true };
|
|
2197
|
+
return { ok: false, message: result.stderr?.trim() || result.stdout?.trim() || "git clone failed" };
|
|
2198
|
+
};
|
|
2199
|
+
var downloadArchive = (targetDir) => {
|
|
2200
|
+
if (!commandExists("curl") || !commandExists("tar")) {
|
|
2201
|
+
return { ok: false, message: "curl or tar not found" };
|
|
2202
|
+
}
|
|
2203
|
+
const archivePath = path6.join(targetDir, "dev-browser.tar.gz");
|
|
2204
|
+
const curlResult = spawnSync4("curl", ["-L", "-o", archivePath, DEV_BROWSER_ARCHIVE], { encoding: "utf8" });
|
|
2205
|
+
if (curlResult.status !== 0) {
|
|
2206
|
+
return { ok: false, message: curlResult.stderr?.trim() || "curl failed" };
|
|
2207
|
+
}
|
|
2208
|
+
const tarResult = spawnSync4("tar", ["-xzf", archivePath, "-C", targetDir], { encoding: "utf8" });
|
|
2209
|
+
if (tarResult.status !== 0) {
|
|
2210
|
+
return { ok: false, message: tarResult.stderr?.trim() || "tar extract failed" };
|
|
2211
|
+
}
|
|
2212
|
+
return { ok: true };
|
|
2213
|
+
};
|
|
2214
|
+
var ensureDevBrowserSkill = (opts) => {
|
|
2215
|
+
if (!opts.install) {
|
|
2216
|
+
return { status: "skipped", message: "skill install disabled" };
|
|
2217
|
+
}
|
|
2218
|
+
const skillRoot = opts.targetDir || path6.join(os4.homedir(), ".claude", "skills");
|
|
2219
|
+
const targetDir = path6.join(skillRoot, "dev-browser");
|
|
2220
|
+
const markerPath = path6.join(targetDir, MANAGED_MARKER);
|
|
2221
|
+
const exists = fs5.existsSync(targetDir);
|
|
2222
|
+
const managed = exists && fs5.existsSync(markerPath);
|
|
2223
|
+
if (exists && !managed && !opts.update) {
|
|
2224
|
+
return { status: "skipped", message: "existing skill is user-managed", path: targetDir };
|
|
2225
|
+
}
|
|
2226
|
+
ensureDir2(skillRoot);
|
|
2227
|
+
const tmpDir = fs5.mkdtempSync(path6.join(os4.tmpdir(), "cc-mirror-skill-"));
|
|
2228
|
+
try {
|
|
2229
|
+
let fetchResult = cloneRepo(tmpDir);
|
|
2230
|
+
if (!fetchResult.ok) {
|
|
2231
|
+
fetchResult = downloadArchive(tmpDir);
|
|
2232
|
+
}
|
|
2233
|
+
if (!fetchResult.ok) {
|
|
2234
|
+
return { status: "failed", message: fetchResult.message || "skill fetch failed" };
|
|
2235
|
+
}
|
|
2236
|
+
const sourceDir = resolveSkillSourceDir(tmpDir);
|
|
2237
|
+
if (!sourceDir) {
|
|
2238
|
+
return { status: "failed", message: "skill source not found after download" };
|
|
2239
|
+
}
|
|
2240
|
+
if (exists) {
|
|
2241
|
+
fs5.rmSync(targetDir, { recursive: true, force: true });
|
|
2242
|
+
}
|
|
2243
|
+
copyDir(sourceDir, targetDir);
|
|
2244
|
+
fs5.writeFileSync(
|
|
2245
|
+
markerPath,
|
|
2246
|
+
JSON.stringify({ managedBy: "cc-mirror", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
2247
|
+
);
|
|
2248
|
+
return { status: exists ? "updated" : "installed", path: targetDir };
|
|
2249
|
+
} catch (error) {
|
|
2250
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2251
|
+
return { status: "failed", message };
|
|
2252
|
+
} finally {
|
|
2253
|
+
fs5.rmSync(tmpDir, { recursive: true, force: true });
|
|
2254
|
+
}
|
|
2255
|
+
};
|
|
2256
|
+
var ORCHESTRATOR_SKILL_NAME = "multi-agent-orchestrator";
|
|
2257
|
+
var findBundledSkillDir = () => {
|
|
2258
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
2259
|
+
const thisDir = path6.dirname(thisFile);
|
|
2260
|
+
const devPath = path6.join(thisDir, "..", "skills", ORCHESTRATOR_SKILL_NAME);
|
|
2261
|
+
if (fs5.existsSync(devPath)) return devPath;
|
|
2262
|
+
const distPath = path6.join(thisDir, "skills", ORCHESTRATOR_SKILL_NAME);
|
|
2263
|
+
if (fs5.existsSync(distPath)) return distPath;
|
|
2264
|
+
const distPath2 = path6.join(thisDir, "..", "skills", ORCHESTRATOR_SKILL_NAME);
|
|
2265
|
+
if (fs5.existsSync(distPath2)) return distPath2;
|
|
2266
|
+
return null;
|
|
2267
|
+
};
|
|
2268
|
+
var installOrchestratorSkill = (configDir) => {
|
|
2269
|
+
const sourceDir = findBundledSkillDir();
|
|
2270
|
+
if (!sourceDir) {
|
|
2271
|
+
return { status: "failed", message: "bundled orchestrator skill not found" };
|
|
2272
|
+
}
|
|
2273
|
+
const skillsDir = path6.join(configDir, "skills");
|
|
2274
|
+
const targetDir = path6.join(skillsDir, ORCHESTRATOR_SKILL_NAME);
|
|
2275
|
+
const markerPath = path6.join(targetDir, MANAGED_MARKER);
|
|
2276
|
+
try {
|
|
2277
|
+
ensureDir2(skillsDir);
|
|
2278
|
+
if (fs5.existsSync(targetDir) && !fs5.existsSync(markerPath)) {
|
|
2279
|
+
return { status: "skipped", message: "existing skill is user-managed", path: targetDir };
|
|
2280
|
+
}
|
|
2281
|
+
if (fs5.existsSync(targetDir)) {
|
|
2282
|
+
fs5.rmSync(targetDir, { recursive: true, force: true });
|
|
2283
|
+
}
|
|
2284
|
+
copyDir(sourceDir, targetDir);
|
|
2285
|
+
fs5.writeFileSync(
|
|
2286
|
+
markerPath,
|
|
2287
|
+
JSON.stringify({ managedBy: "cc-mirror", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
2288
|
+
);
|
|
2289
|
+
return { status: "installed", path: targetDir };
|
|
2290
|
+
} catch (error) {
|
|
2291
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2292
|
+
return { status: "failed", message };
|
|
2293
|
+
}
|
|
2294
|
+
};
|
|
2295
|
+
var removeOrchestratorSkill = (configDir) => {
|
|
2296
|
+
const skillsDir = path6.join(configDir, "skills");
|
|
2297
|
+
const targetDir = path6.join(skillsDir, ORCHESTRATOR_SKILL_NAME);
|
|
2298
|
+
const markerPath = path6.join(targetDir, MANAGED_MARKER);
|
|
2299
|
+
if (!fs5.existsSync(targetDir)) {
|
|
2300
|
+
return { status: "skipped", message: "skill not installed" };
|
|
2301
|
+
}
|
|
2302
|
+
if (!fs5.existsSync(markerPath)) {
|
|
2303
|
+
return { status: "skipped", message: "skill is user-managed, not removing" };
|
|
2304
|
+
}
|
|
2305
|
+
try {
|
|
2306
|
+
fs5.rmSync(targetDir, { recursive: true, force: true });
|
|
2307
|
+
return { status: "removed", path: targetDir };
|
|
2308
|
+
} catch (error) {
|
|
2309
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2310
|
+
return { status: "failed", message };
|
|
2311
|
+
}
|
|
2312
|
+
};
|
|
2313
|
+
var spawnAsync = (cmd, args) => {
|
|
2314
|
+
return new Promise((resolve) => {
|
|
2315
|
+
const child = spawn3(cmd, args, { stdio: "pipe" });
|
|
2316
|
+
let stderr = "";
|
|
2317
|
+
let stdout = "";
|
|
2318
|
+
child.stdout?.on("data", (d) => {
|
|
2319
|
+
stdout += d.toString();
|
|
2320
|
+
});
|
|
2321
|
+
child.stderr?.on("data", (d) => {
|
|
2322
|
+
stderr += d.toString();
|
|
2323
|
+
});
|
|
2324
|
+
child.on("close", (code) => {
|
|
2325
|
+
if (code === 0) resolve({ ok: true });
|
|
2326
|
+
else resolve({ ok: false, message: stderr.trim() || stdout.trim() || `${cmd} failed` });
|
|
2327
|
+
});
|
|
2328
|
+
child.on("error", (err) => resolve({ ok: false, message: err.message }));
|
|
2329
|
+
});
|
|
2330
|
+
};
|
|
2331
|
+
var cloneRepoAsync = async (targetDir) => {
|
|
2332
|
+
if (!commandExists("git")) return { ok: false, message: "git not found" };
|
|
2333
|
+
return spawnAsync("git", ["clone", "--depth", "1", DEV_BROWSER_REPO, targetDir]);
|
|
2334
|
+
};
|
|
2335
|
+
var downloadArchiveAsync = async (targetDir) => {
|
|
2336
|
+
if (!commandExists("curl") || !commandExists("tar")) {
|
|
2337
|
+
return { ok: false, message: "curl or tar not found" };
|
|
2338
|
+
}
|
|
2339
|
+
const archivePath = path6.join(targetDir, "dev-browser.tar.gz");
|
|
2340
|
+
const curlResult = await spawnAsync("curl", ["-L", "-o", archivePath, DEV_BROWSER_ARCHIVE]);
|
|
2341
|
+
if (!curlResult.ok) return curlResult;
|
|
2342
|
+
return spawnAsync("tar", ["-xzf", archivePath, "-C", targetDir]);
|
|
2343
|
+
};
|
|
2344
|
+
var ensureDevBrowserSkillAsync = async (opts) => {
|
|
2345
|
+
if (!opts.install) {
|
|
2346
|
+
return { status: "skipped", message: "skill install disabled" };
|
|
2347
|
+
}
|
|
2348
|
+
const skillRoot = opts.targetDir || path6.join(os4.homedir(), ".claude", "skills");
|
|
2349
|
+
const targetDir = path6.join(skillRoot, "dev-browser");
|
|
2350
|
+
const markerPath = path6.join(targetDir, MANAGED_MARKER);
|
|
2351
|
+
const exists = fs5.existsSync(targetDir);
|
|
2352
|
+
const managed = exists && fs5.existsSync(markerPath);
|
|
2353
|
+
if (exists && !managed && !opts.update) {
|
|
2354
|
+
return { status: "skipped", message: "existing skill is user-managed", path: targetDir };
|
|
2355
|
+
}
|
|
2356
|
+
ensureDir2(skillRoot);
|
|
2357
|
+
const tmpDir = fs5.mkdtempSync(path6.join(os4.tmpdir(), "cc-mirror-skill-"));
|
|
2358
|
+
try {
|
|
2359
|
+
let fetchResult = await cloneRepoAsync(tmpDir);
|
|
2360
|
+
if (!fetchResult.ok) {
|
|
2361
|
+
fetchResult = await downloadArchiveAsync(tmpDir);
|
|
2362
|
+
}
|
|
2363
|
+
if (!fetchResult.ok) {
|
|
2364
|
+
return { status: "failed", message: fetchResult.message || "skill fetch failed" };
|
|
2365
|
+
}
|
|
2366
|
+
const sourceDir = resolveSkillSourceDir(tmpDir);
|
|
2367
|
+
if (!sourceDir) {
|
|
2368
|
+
return { status: "failed", message: "skill source not found after download" };
|
|
2369
|
+
}
|
|
2370
|
+
if (exists) {
|
|
2371
|
+
fs5.rmSync(targetDir, { recursive: true, force: true });
|
|
2372
|
+
}
|
|
2373
|
+
copyDir(sourceDir, targetDir);
|
|
2374
|
+
fs5.writeFileSync(
|
|
2375
|
+
markerPath,
|
|
2376
|
+
JSON.stringify({ managedBy: "cc-mirror", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
2377
|
+
);
|
|
2378
|
+
return { status: exists ? "updated" : "installed", path: targetDir };
|
|
2379
|
+
} catch (error) {
|
|
2380
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2381
|
+
return { status: "failed", message };
|
|
2382
|
+
} finally {
|
|
2383
|
+
fs5.rmSync(tmpDir, { recursive: true, force: true });
|
|
2384
|
+
}
|
|
2385
|
+
};
|
|
2386
|
+
|
|
2387
|
+
// src/core/variant-builder/steps/TeamModeStep.ts
|
|
2388
|
+
var TEAM_MODE_DISABLED = "function sU(){return!1}";
|
|
2389
|
+
var TEAM_MODE_ENABLED = "function sU(){return!0}";
|
|
2390
|
+
var TeamModeStep = class {
|
|
2391
|
+
name = "TeamMode";
|
|
2392
|
+
shouldEnableTeamMode(ctx) {
|
|
2393
|
+
return Boolean(ctx.params.enableTeamMode) || Boolean(ctx.provider.enablesTeamMode);
|
|
2394
|
+
}
|
|
2395
|
+
execute(ctx) {
|
|
2396
|
+
if (!this.shouldEnableTeamMode(ctx)) return;
|
|
2397
|
+
ctx.report("Enabling team mode...");
|
|
2398
|
+
this.patchCli(ctx);
|
|
2399
|
+
}
|
|
2400
|
+
async executeAsync(ctx) {
|
|
2401
|
+
if (!this.shouldEnableTeamMode(ctx)) return;
|
|
2402
|
+
await ctx.report("Enabling team mode...");
|
|
2403
|
+
this.patchCli(ctx);
|
|
2404
|
+
}
|
|
2405
|
+
patchCli(ctx) {
|
|
2406
|
+
const { state, params, paths } = ctx;
|
|
2407
|
+
const cliPath = path7.join(paths.npmDir, "node_modules", "@anthropic-ai", "claude-code", "cli.js");
|
|
2408
|
+
const backupPath = `${cliPath}.backup`;
|
|
2409
|
+
if (!fs6.existsSync(cliPath)) {
|
|
2410
|
+
state.notes.push("Warning: cli.js not found, skipping team mode patch");
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
2413
|
+
if (!fs6.existsSync(backupPath)) {
|
|
2414
|
+
fs6.copyFileSync(cliPath, backupPath);
|
|
2415
|
+
}
|
|
2416
|
+
let content = fs6.readFileSync(cliPath, "utf8");
|
|
2417
|
+
if (content.includes(TEAM_MODE_ENABLED)) {
|
|
2418
|
+
state.notes.push("Team mode already enabled");
|
|
2419
|
+
return;
|
|
2420
|
+
}
|
|
2421
|
+
if (!content.includes(TEAM_MODE_DISABLED)) {
|
|
2422
|
+
state.notes.push("Warning: Team mode function not found in cli.js, patch may not work");
|
|
2423
|
+
return;
|
|
2424
|
+
}
|
|
2425
|
+
content = content.replace(TEAM_MODE_DISABLED, TEAM_MODE_ENABLED);
|
|
2426
|
+
fs6.writeFileSync(cliPath, content);
|
|
2427
|
+
const verifyContent = fs6.readFileSync(cliPath, "utf8");
|
|
2428
|
+
if (!verifyContent.includes(TEAM_MODE_ENABLED)) {
|
|
2429
|
+
state.notes.push("Warning: Team mode patch verification failed");
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
const settingsPath = path7.join(paths.configDir, "settings.json");
|
|
2433
|
+
if (fs6.existsSync(settingsPath)) {
|
|
2434
|
+
try {
|
|
2435
|
+
const settings = JSON.parse(fs6.readFileSync(settingsPath, "utf8"));
|
|
2436
|
+
settings.env = settings.env || {};
|
|
2437
|
+
if (!settings.env.CLAUDE_CODE_TEAM_NAME) {
|
|
2438
|
+
settings.env.CLAUDE_CODE_TEAM_NAME = params.name;
|
|
2439
|
+
}
|
|
2440
|
+
if (!settings.env.CLAUDE_CODE_AGENT_TYPE) {
|
|
2441
|
+
settings.env.CLAUDE_CODE_AGENT_TYPE = "team-lead";
|
|
2442
|
+
}
|
|
2443
|
+
fs6.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
2444
|
+
} catch {
|
|
2445
|
+
state.notes.push("Warning: Could not update settings.json with team env vars");
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
state.notes.push("Team mode enabled successfully");
|
|
2449
|
+
const skillResult = installOrchestratorSkill(paths.configDir);
|
|
2450
|
+
if (skillResult.status === "installed") {
|
|
2451
|
+
state.notes.push("Multi-agent orchestrator skill installed");
|
|
2452
|
+
} else if (skillResult.status === "failed") {
|
|
2453
|
+
state.notes.push(`Warning: orchestrator skill install failed: ${skillResult.message}`);
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
};
|
|
2457
|
+
|
|
2458
|
+
// src/core/variant-builder/steps/WriteConfigStep.ts
|
|
2459
|
+
import path9 from "node:path";
|
|
2460
|
+
|
|
2461
|
+
// src/core/claude-config.ts
|
|
2462
|
+
import fs7 from "node:fs";
|
|
2463
|
+
import path8 from "node:path";
|
|
1928
2464
|
var SETTINGS_FILE = "settings.json";
|
|
1929
2465
|
var CLAUDE_CONFIG_FILE = ".claude.json";
|
|
1930
2466
|
var PLACEHOLDER_KEY = "<API_KEY>";
|
|
@@ -1935,7 +2471,7 @@ var toStringOrNull = (value) => {
|
|
|
1935
2471
|
return trimmed;
|
|
1936
2472
|
};
|
|
1937
2473
|
var readSettingsApiKey = (configDir) => {
|
|
1938
|
-
const settingsPath =
|
|
2474
|
+
const settingsPath = path8.join(configDir, SETTINGS_FILE);
|
|
1939
2475
|
const settings = readJson(settingsPath);
|
|
1940
2476
|
if (!settings?.env) return null;
|
|
1941
2477
|
const env = settings.env;
|
|
@@ -1947,7 +2483,7 @@ var ZAI_DENY_TOOLS = [
|
|
|
1947
2483
|
"mcp__web_reader__webReader"
|
|
1948
2484
|
];
|
|
1949
2485
|
var ensureZaiMcpDeny = (configDir) => {
|
|
1950
|
-
const settingsPath =
|
|
2486
|
+
const settingsPath = path8.join(configDir, SETTINGS_FILE);
|
|
1951
2487
|
const existing = readJson(settingsPath) || {};
|
|
1952
2488
|
const permissions = existing.permissions || {};
|
|
1953
2489
|
const deny = Array.isArray(permissions.deny) ? [...permissions.deny] : [];
|
|
@@ -1970,7 +2506,7 @@ var ensureZaiMcpDeny = (configDir) => {
|
|
|
1970
2506
|
return true;
|
|
1971
2507
|
};
|
|
1972
2508
|
var ensureSettingsEnvDefaults = (configDir, defaults) => {
|
|
1973
|
-
const settingsPath =
|
|
2509
|
+
const settingsPath = path8.join(configDir, SETTINGS_FILE);
|
|
1974
2510
|
const existing = readJson(settingsPath) || {};
|
|
1975
2511
|
const env = { ...existing.env ?? {} };
|
|
1976
2512
|
let changed = false;
|
|
@@ -1985,7 +2521,7 @@ var ensureSettingsEnvDefaults = (configDir, defaults) => {
|
|
|
1985
2521
|
return true;
|
|
1986
2522
|
};
|
|
1987
2523
|
var ensureSettingsEnvOverrides = (configDir, overrides) => {
|
|
1988
|
-
const settingsPath =
|
|
2524
|
+
const settingsPath = path8.join(configDir, SETTINGS_FILE);
|
|
1989
2525
|
const existing = readJson(settingsPath) || {};
|
|
1990
2526
|
const env = { ...existing.env ?? {} };
|
|
1991
2527
|
let changed = false;
|
|
@@ -2004,8 +2540,8 @@ var ensureApiKeyApproval = (configDir, apiKey) => {
|
|
|
2004
2540
|
const resolvedKey = toStringOrNull(apiKey) || readSettingsApiKey(configDir);
|
|
2005
2541
|
if (!resolvedKey) return false;
|
|
2006
2542
|
const approvedToken = resolvedKey.slice(-20);
|
|
2007
|
-
const configPath =
|
|
2008
|
-
const exists =
|
|
2543
|
+
const configPath = path8.join(configDir, CLAUDE_CONFIG_FILE);
|
|
2544
|
+
const exists = fs7.existsSync(configPath);
|
|
2009
2545
|
let config = null;
|
|
2010
2546
|
if (exists) {
|
|
2011
2547
|
config = readJson(configPath);
|
|
@@ -2029,8 +2565,8 @@ var ensureApiKeyApproval = (configDir, apiKey) => {
|
|
|
2029
2565
|
return true;
|
|
2030
2566
|
};
|
|
2031
2567
|
var ensureOnboardingState = (configDir, opts = {}) => {
|
|
2032
|
-
const configPath =
|
|
2033
|
-
const exists =
|
|
2568
|
+
const configPath = path8.join(configDir, CLAUDE_CONFIG_FILE);
|
|
2569
|
+
const exists = fs7.existsSync(configPath);
|
|
2034
2570
|
let config = null;
|
|
2035
2571
|
if (exists) {
|
|
2036
2572
|
config = readJson(configPath);
|
|
@@ -2051,7 +2587,7 @@ var ensureOnboardingState = (configDir, opts = {}) => {
|
|
|
2051
2587
|
themeChanged = true;
|
|
2052
2588
|
}
|
|
2053
2589
|
}
|
|
2054
|
-
if (config.hasCompletedOnboarding !== true) {
|
|
2590
|
+
if (!opts.skipOnboardingFlag && config.hasCompletedOnboarding !== true) {
|
|
2055
2591
|
config.hasCompletedOnboarding = true;
|
|
2056
2592
|
changed = true;
|
|
2057
2593
|
onboardingChanged = true;
|
|
@@ -2064,8 +2600,8 @@ var ensureOnboardingState = (configDir, opts = {}) => {
|
|
|
2064
2600
|
};
|
|
2065
2601
|
var ensureMinimaxMcpServer = (configDir, apiKey) => {
|
|
2066
2602
|
const resolvedKey = toStringOrNull(apiKey) || readSettingsApiKey(configDir);
|
|
2067
|
-
const configPath =
|
|
2068
|
-
const exists =
|
|
2603
|
+
const configPath = path8.join(configDir, CLAUDE_CONFIG_FILE);
|
|
2604
|
+
const exists = fs7.existsSync(configPath);
|
|
2069
2605
|
let config = null;
|
|
2070
2606
|
if (exists) {
|
|
2071
2607
|
config = readJson(configPath);
|
|
@@ -2122,7 +2658,7 @@ var WriteConfigStep = class {
|
|
|
2122
2658
|
env.ANTHROPIC_API_KEY = "<API_KEY>";
|
|
2123
2659
|
}
|
|
2124
2660
|
const config = { env };
|
|
2125
|
-
writeJson(
|
|
2661
|
+
writeJson(path9.join(paths.configDir, "settings.json"), config);
|
|
2126
2662
|
state.env = env;
|
|
2127
2663
|
state.resolvedApiKey = typeof env.ANTHROPIC_API_KEY === "string" ? env.ANTHROPIC_API_KEY : void 0;
|
|
2128
2664
|
ensureApiKeyApproval(paths.configDir, state.resolvedApiKey);
|
|
@@ -2162,9 +2698,11 @@ var BrandThemeStep = class {
|
|
|
2162
2698
|
prefs.brandKey = brandKey;
|
|
2163
2699
|
ensureTweakccConfig(paths.tweakDir, brandKey);
|
|
2164
2700
|
const brandThemeId = !params.noTweak && brandKey ? getBrandThemeId(brandKey) : null;
|
|
2701
|
+
const skipOnboardingFlag = params.providerKey === "mirror";
|
|
2165
2702
|
const onboarding = ensureOnboardingState(paths.configDir, {
|
|
2166
2703
|
themeId: brandThemeId ?? "dark",
|
|
2167
|
-
forceTheme: Boolean(brandThemeId)
|
|
2704
|
+
forceTheme: Boolean(brandThemeId),
|
|
2705
|
+
skipOnboardingFlag
|
|
2168
2706
|
});
|
|
2169
2707
|
if (onboarding.themeChanged) {
|
|
2170
2708
|
state.notes.push(`Default theme set to ${brandThemeId ?? "dark"}.`);
|
|
@@ -2172,6 +2710,9 @@ var BrandThemeStep = class {
|
|
|
2172
2710
|
if (onboarding.onboardingChanged) {
|
|
2173
2711
|
state.notes.push("Onboarding marked complete.");
|
|
2174
2712
|
}
|
|
2713
|
+
if (skipOnboardingFlag) {
|
|
2714
|
+
state.notes.push("Login screen enabled (authenticate when you run the variant).");
|
|
2715
|
+
}
|
|
2175
2716
|
if (params.providerKey === "minimax") {
|
|
2176
2717
|
ctx.report("Configuring MiniMax MCP server...");
|
|
2177
2718
|
ensureMinimaxMcpServer(paths.configDir, state.resolvedApiKey);
|
|
@@ -2189,8 +2730,8 @@ var BrandThemeStep = class {
|
|
|
2189
2730
|
};
|
|
2190
2731
|
|
|
2191
2732
|
// src/core/prompt-pack.ts
|
|
2192
|
-
import
|
|
2193
|
-
import
|
|
2733
|
+
import fs8 from "node:fs";
|
|
2734
|
+
import path10 from "node:path";
|
|
2194
2735
|
|
|
2195
2736
|
// src/core/prompt-pack/sanitize.ts
|
|
2196
2737
|
var BACKTICK_REGEX = /`/g;
|
|
@@ -2605,17 +3146,17 @@ ${block}
|
|
|
2605
3146
|
};
|
|
2606
3147
|
var updatePromptFile = (filePath, overlay) => {
|
|
2607
3148
|
if (!overlay) return false;
|
|
2608
|
-
if (!
|
|
2609
|
-
const content =
|
|
3149
|
+
if (!fs8.existsSync(filePath)) return false;
|
|
3150
|
+
const content = fs8.readFileSync(filePath, "utf8");
|
|
2610
3151
|
const updated = insertOverlay(content, overlay);
|
|
2611
3152
|
if (updated === content) return false;
|
|
2612
|
-
|
|
3153
|
+
fs8.writeFileSync(filePath, updated);
|
|
2613
3154
|
return true;
|
|
2614
3155
|
};
|
|
2615
3156
|
var applyOverlays = (systemPromptsDir, overlays) => {
|
|
2616
3157
|
const updated = [];
|
|
2617
3158
|
for (const target of PROMPT_PACK_TARGETS) {
|
|
2618
|
-
const filePath =
|
|
3159
|
+
const filePath = path10.join(systemPromptsDir, target.filename);
|
|
2619
3160
|
const overlay = overlays[target.key];
|
|
2620
3161
|
if (updatePromptFile(filePath, overlay)) {
|
|
2621
3162
|
updated.push(target.filename);
|
|
@@ -2628,7 +3169,7 @@ var applyPromptPack = (tweakDir, providerKey, mode = "minimal") => {
|
|
|
2628
3169
|
return { changed: false, updated: [], mode };
|
|
2629
3170
|
}
|
|
2630
3171
|
const overlays = resolveOverlays(providerKey, mode);
|
|
2631
|
-
const systemPromptsDir =
|
|
3172
|
+
const systemPromptsDir = path10.join(tweakDir, "system-prompts");
|
|
2632
3173
|
const updated = applyOverlays(systemPromptsDir, overlays);
|
|
2633
3174
|
return { changed: updated.length > 0, updated, mode };
|
|
2634
3175
|
};
|
|
@@ -2695,10 +3236,10 @@ ${reapply.stdout ?? ""}`.trim();
|
|
|
2695
3236
|
};
|
|
2696
3237
|
|
|
2697
3238
|
// src/core/wrapper.ts
|
|
2698
|
-
import
|
|
2699
|
-
import
|
|
3239
|
+
import fs9 from "node:fs";
|
|
3240
|
+
import path11 from "node:path";
|
|
2700
3241
|
var writeWrapper = (wrapperPath, configDir, binaryPath, runtime = "node") => {
|
|
2701
|
-
const tweakDir =
|
|
3242
|
+
const tweakDir = path11.join(path11.dirname(configDir), "tweakcc");
|
|
2702
3243
|
const execLine = runtime === "node" ? `exec node "${binaryPath}" "$@"` : `exec "${binaryPath}" "$@"`;
|
|
2703
3244
|
const envLoader = [
|
|
2704
3245
|
"if command -v node >/dev/null 2>&1; then",
|
|
@@ -2770,6 +3311,15 @@ var writeWrapper = (wrapperPath, configDir, binaryPath, runtime = "node") => {
|
|
|
2770
3311
|
// Deep blue
|
|
2771
3312
|
ccrDim: "\x1B[38;5;31m",
|
|
2772
3313
|
// Muted blue
|
|
3314
|
+
// Mirror: Silver/Chrome with electric blue
|
|
3315
|
+
mirPrimary: "\x1B[38;5;252m",
|
|
3316
|
+
// Silver/light gray
|
|
3317
|
+
mirSecondary: "\x1B[38;5;250m",
|
|
3318
|
+
// Platinum
|
|
3319
|
+
mirAccent: "\x1B[38;5;45m",
|
|
3320
|
+
// Electric cyan
|
|
3321
|
+
mirDim: "\x1B[38;5;243m",
|
|
3322
|
+
// Muted silver
|
|
2773
3323
|
// Default: White/Gray
|
|
2774
3324
|
defPrimary: "\x1B[38;5;255m",
|
|
2775
3325
|
// White
|
|
@@ -2854,6 +3404,22 @@ var writeWrapper = (wrapperPath, configDir, binaryPath, runtime = "node") => {
|
|
|
2854
3404
|
"CCMCCR",
|
|
2855
3405
|
' __cc_show_label="0"',
|
|
2856
3406
|
" ;;",
|
|
3407
|
+
" mirror)",
|
|
3408
|
+
" cat <<'CCMMIR'",
|
|
3409
|
+
"",
|
|
3410
|
+
`${C.mirPrimary} \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557${C.reset}`,
|
|
3411
|
+
`${C.mirPrimary} \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557${C.reset}`,
|
|
3412
|
+
`${C.mirSecondary} \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D${C.reset}`,
|
|
3413
|
+
`${C.mirSecondary} \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557${C.reset}`,
|
|
3414
|
+
`${C.mirAccent} \u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551${C.reset}`,
|
|
3415
|
+
`${C.mirAccent} \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D${C.reset}`,
|
|
3416
|
+
"",
|
|
3417
|
+
`${C.mirDim} \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${C.mirAccent}\u25C7${C.mirDim}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${C.reset}`,
|
|
3418
|
+
`${C.mirSecondary} Claude ${C.mirDim}\u2501${C.mirSecondary} Pure Reflection${C.reset}`,
|
|
3419
|
+
"",
|
|
3420
|
+
"CCMMIR",
|
|
3421
|
+
' __cc_show_label="0"',
|
|
3422
|
+
" ;;",
|
|
2857
3423
|
" *)",
|
|
2858
3424
|
" cat <<'CCMGEN'",
|
|
2859
3425
|
"",
|
|
@@ -2888,7 +3454,7 @@ var writeWrapper = (wrapperPath, configDir, binaryPath, runtime = "node") => {
|
|
|
2888
3454
|
execLine,
|
|
2889
3455
|
""
|
|
2890
3456
|
].join("\n");
|
|
2891
|
-
|
|
3457
|
+
fs9.writeFileSync(wrapperPath, content, { mode: 493 });
|
|
2892
3458
|
};
|
|
2893
3459
|
|
|
2894
3460
|
// src/core/variant-builder/steps/WrapperStep.ts
|
|
@@ -2905,9 +3471,9 @@ var WrapperStep = class {
|
|
|
2905
3471
|
};
|
|
2906
3472
|
|
|
2907
3473
|
// src/core/shell-env.ts
|
|
2908
|
-
import
|
|
2909
|
-
import
|
|
2910
|
-
import
|
|
3474
|
+
import fs10 from "node:fs";
|
|
3475
|
+
import os5 from "node:os";
|
|
3476
|
+
import path12 from "node:path";
|
|
2911
3477
|
var SETTINGS_FILE2 = "settings.json";
|
|
2912
3478
|
var BLOCK_START = "# cc-mirror: Z.ai env start";
|
|
2913
3479
|
var BLOCK_END = "# cc-mirror: Z.ai env end";
|
|
@@ -2919,22 +3485,22 @@ var normalizeApiKey = (value) => {
|
|
|
2919
3485
|
return trimmed;
|
|
2920
3486
|
};
|
|
2921
3487
|
var resolveShellProfile = () => {
|
|
2922
|
-
const home =
|
|
3488
|
+
const home = os5.homedir();
|
|
2923
3489
|
const shell = process.env.SHELL || "";
|
|
2924
|
-
const name =
|
|
3490
|
+
const name = path12.basename(shell);
|
|
2925
3491
|
if (name === "zsh") {
|
|
2926
|
-
return
|
|
3492
|
+
return path12.join(home, ".zshrc");
|
|
2927
3493
|
}
|
|
2928
3494
|
if (name === "bash") {
|
|
2929
|
-
const bashrc =
|
|
2930
|
-
if (
|
|
2931
|
-
return
|
|
3495
|
+
const bashrc = path12.join(home, ".bashrc");
|
|
3496
|
+
if (fs10.existsSync(bashrc)) return bashrc;
|
|
3497
|
+
return path12.join(home, ".bash_profile");
|
|
2932
3498
|
}
|
|
2933
3499
|
return null;
|
|
2934
3500
|
};
|
|
2935
3501
|
var readSettingsApiKey2 = (configDir) => {
|
|
2936
|
-
const settingsPath =
|
|
2937
|
-
if (!
|
|
3502
|
+
const settingsPath = path12.join(configDir, SETTINGS_FILE2);
|
|
3503
|
+
if (!fs10.existsSync(settingsPath)) return null;
|
|
2938
3504
|
const settings = readJson(settingsPath);
|
|
2939
3505
|
const key = settings?.env?.ANTHROPIC_API_KEY;
|
|
2940
3506
|
if (typeof key !== "string") return null;
|
|
@@ -2943,266 +3509,100 @@ var readSettingsApiKey2 = (configDir) => {
|
|
|
2943
3509
|
var renderBlock = (apiKey) => `${BLOCK_START}
|
|
2944
3510
|
export Z_AI_API_KEY="${apiKey}"
|
|
2945
3511
|
${BLOCK_END}
|
|
2946
|
-
`;
|
|
2947
|
-
var upsertBlock = (content, block) => {
|
|
2948
|
-
if (content.includes(BLOCK_START) && content.includes(BLOCK_END)) {
|
|
2949
|
-
const start = content.indexOf(BLOCK_START);
|
|
2950
|
-
const end = content.indexOf(BLOCK_END, start);
|
|
2951
|
-
const before = content.slice(0, start).trimEnd();
|
|
2952
|
-
const after = content.slice(end + BLOCK_END.length).trimStart();
|
|
2953
|
-
return `${before}
|
|
2954
|
-
|
|
2955
|
-
${block}
|
|
2956
|
-
${after}`.trimEnd() + "\n";
|
|
2957
|
-
}
|
|
2958
|
-
return `${content.trimEnd()}
|
|
2959
|
-
|
|
2960
|
-
${block}`.trimEnd() + "\n";
|
|
2961
|
-
};
|
|
2962
|
-
var hasZaiKeyInProfile = (content) => {
|
|
2963
|
-
const lines = content.split("\n");
|
|
2964
|
-
for (const line of lines) {
|
|
2965
|
-
const trimmed = line.trim();
|
|
2966
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
2967
|
-
const exportStripped = trimmed.startsWith("export ") ? trimmed.slice(7).trim() : trimmed;
|
|
2968
|
-
if (!exportStripped.startsWith("Z_AI_API_KEY")) continue;
|
|
2969
|
-
const equalsIndex = exportStripped.indexOf("=");
|
|
2970
|
-
if (equalsIndex === -1) continue;
|
|
2971
|
-
let value = exportStripped.slice(equalsIndex + 1).trim();
|
|
2972
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
2973
|
-
value = value.slice(1, -1);
|
|
2974
|
-
}
|
|
2975
|
-
if (normalizeApiKey(value)) return true;
|
|
2976
|
-
}
|
|
2977
|
-
return false;
|
|
2978
|
-
};
|
|
2979
|
-
var ensureZaiShellEnv = (opts) => {
|
|
2980
|
-
const apiKey = normalizeApiKey(opts.apiKey) || readSettingsApiKey2(opts.configDir);
|
|
2981
|
-
if (!apiKey) {
|
|
2982
|
-
return { status: "skipped", message: "Z_AI_API_KEY not set (missing API key)" };
|
|
2983
|
-
}
|
|
2984
|
-
const envKey = normalizeApiKey(process.env.Z_AI_API_KEY);
|
|
2985
|
-
if (envKey) {
|
|
2986
|
-
return { status: "skipped", message: "Z_AI_API_KEY already set in environment" };
|
|
2987
|
-
}
|
|
2988
|
-
const profile = opts.profilePath ?? resolveShellProfile();
|
|
2989
|
-
if (!profile) {
|
|
2990
|
-
return { status: "failed", message: "Unsupported shell; set Z_AI_API_KEY manually" };
|
|
2991
|
-
}
|
|
2992
|
-
const existing = fs8.existsSync(profile) ? fs8.readFileSync(profile, "utf8") : "";
|
|
2993
|
-
if (hasZaiKeyInProfile(existing)) {
|
|
2994
|
-
return { status: "skipped", message: "Z_AI_API_KEY already set in shell profile", path: profile };
|
|
2995
|
-
}
|
|
2996
|
-
const next = upsertBlock(existing, renderBlock(apiKey));
|
|
2997
|
-
if (next === existing) {
|
|
2998
|
-
return { status: "skipped", message: "Shell profile already up to date", path: profile };
|
|
2999
|
-
}
|
|
3000
|
-
fs8.writeFileSync(profile, next);
|
|
3001
|
-
return { status: "updated", path: profile, message: `Run: source ${profile}` };
|
|
3002
|
-
};
|
|
3003
|
-
|
|
3004
|
-
// src/core/variant-builder/steps/ShellEnvStep.ts
|
|
3005
|
-
var ShellEnvStep = class {
|
|
3006
|
-
name = "ShellEnv";
|
|
3007
|
-
execute(ctx) {
|
|
3008
|
-
this.setupShellEnv(ctx);
|
|
3009
|
-
}
|
|
3010
|
-
async executeAsync(ctx) {
|
|
3011
|
-
if (ctx.prefs.shellEnvEnabled && ctx.params.providerKey === "zai") {
|
|
3012
|
-
await ctx.report("Configuring shell environment...");
|
|
3013
|
-
}
|
|
3014
|
-
this.setupShellEnv(ctx);
|
|
3015
|
-
}
|
|
3016
|
-
setupShellEnv(ctx) {
|
|
3017
|
-
const { params, paths, prefs, state } = ctx;
|
|
3018
|
-
if (prefs.shellEnvEnabled && params.providerKey === "zai") {
|
|
3019
|
-
ctx.report("Configuring shell environment...");
|
|
3020
|
-
const shellResult = ensureZaiShellEnv({
|
|
3021
|
-
apiKey: state.resolvedApiKey ?? null,
|
|
3022
|
-
configDir: paths.configDir
|
|
3023
|
-
});
|
|
3024
|
-
if (shellResult.status === "updated") {
|
|
3025
|
-
const suffix = shellResult.message ? ` (${shellResult.message})` : "";
|
|
3026
|
-
state.notes.push(`Z_AI_API_KEY written to ${shellResult.path}${suffix}`);
|
|
3027
|
-
} else if (shellResult.status === "failed") {
|
|
3028
|
-
state.notes.push(`Z_AI_API_KEY not written: ${shellResult.message || "unknown error"}`);
|
|
3029
|
-
} else if (shellResult.message) {
|
|
3030
|
-
state.notes.push(`Z_AI_API_KEY: ${shellResult.message}`);
|
|
3031
|
-
}
|
|
3032
|
-
} else if (params.providerKey === "zai") {
|
|
3033
|
-
state.notes.push("Z_AI_API_KEY not written to shell profile. Set it manually in your shell rc file.");
|
|
3034
|
-
}
|
|
3035
|
-
}
|
|
3036
|
-
};
|
|
3037
|
-
|
|
3038
|
-
// src/core/variant-builder/steps/SkillInstallStep.ts
|
|
3039
|
-
import path12 from "node:path";
|
|
3040
|
-
|
|
3041
|
-
// src/core/skills.ts
|
|
3042
|
-
import fs9 from "node:fs";
|
|
3043
|
-
import os5 from "node:os";
|
|
3044
|
-
import path11 from "node:path";
|
|
3045
|
-
import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
|
|
3046
|
-
var DEV_BROWSER_REPO = "https://github.com/SawyerHood/dev-browser.git";
|
|
3047
|
-
var DEV_BROWSER_ARCHIVE = "https://github.com/SawyerHood/dev-browser/archive/refs/heads/main.tar.gz";
|
|
3048
|
-
var SKILL_SUBDIR = path11.join("skills", "dev-browser");
|
|
3049
|
-
var MANAGED_MARKER = ".cc-mirror-managed";
|
|
3050
|
-
var ensureDir2 = (dir) => {
|
|
3051
|
-
fs9.mkdirSync(dir, { recursive: true });
|
|
3052
|
-
};
|
|
3053
|
-
var copyDir = (source, target) => {
|
|
3054
|
-
fs9.cpSync(source, target, { recursive: true });
|
|
3055
|
-
};
|
|
3056
|
-
var resolveSkillSourceDir = (repoDir) => {
|
|
3057
|
-
const direct = path11.join(repoDir, SKILL_SUBDIR);
|
|
3058
|
-
if (fs9.existsSync(direct)) return direct;
|
|
3059
|
-
const nested = fs9.readdirSync(repoDir).find((entry) => entry.startsWith("dev-browser-"));
|
|
3060
|
-
if (nested) {
|
|
3061
|
-
const candidate = path11.join(repoDir, nested, SKILL_SUBDIR);
|
|
3062
|
-
if (fs9.existsSync(candidate)) return candidate;
|
|
3063
|
-
}
|
|
3064
|
-
return null;
|
|
3065
|
-
};
|
|
3066
|
-
var cloneRepo = (targetDir) => {
|
|
3067
|
-
if (!commandExists("git")) return { ok: false, message: "git not found" };
|
|
3068
|
-
const result = spawnSync4("git", ["clone", "--depth", "1", DEV_BROWSER_REPO, targetDir], {
|
|
3069
|
-
encoding: "utf8"
|
|
3070
|
-
});
|
|
3071
|
-
if (result.status === 0) return { ok: true };
|
|
3072
|
-
return { ok: false, message: result.stderr?.trim() || result.stdout?.trim() || "git clone failed" };
|
|
3073
|
-
};
|
|
3074
|
-
var downloadArchive = (targetDir) => {
|
|
3075
|
-
if (!commandExists("curl") || !commandExists("tar")) {
|
|
3076
|
-
return { ok: false, message: "curl or tar not found" };
|
|
3077
|
-
}
|
|
3078
|
-
const archivePath = path11.join(targetDir, "dev-browser.tar.gz");
|
|
3079
|
-
const curlResult = spawnSync4("curl", ["-L", "-o", archivePath, DEV_BROWSER_ARCHIVE], { encoding: "utf8" });
|
|
3080
|
-
if (curlResult.status !== 0) {
|
|
3081
|
-
return { ok: false, message: curlResult.stderr?.trim() || "curl failed" };
|
|
3082
|
-
}
|
|
3083
|
-
const tarResult = spawnSync4("tar", ["-xzf", archivePath, "-C", targetDir], { encoding: "utf8" });
|
|
3084
|
-
if (tarResult.status !== 0) {
|
|
3085
|
-
return { ok: false, message: tarResult.stderr?.trim() || "tar extract failed" };
|
|
3086
|
-
}
|
|
3087
|
-
return { ok: true };
|
|
3088
|
-
};
|
|
3089
|
-
var ensureDevBrowserSkill = (opts) => {
|
|
3090
|
-
if (!opts.install) {
|
|
3091
|
-
return { status: "skipped", message: "skill install disabled" };
|
|
3092
|
-
}
|
|
3093
|
-
const skillRoot = opts.targetDir || path11.join(os5.homedir(), ".claude", "skills");
|
|
3094
|
-
const targetDir = path11.join(skillRoot, "dev-browser");
|
|
3095
|
-
const markerPath = path11.join(targetDir, MANAGED_MARKER);
|
|
3096
|
-
const exists = fs9.existsSync(targetDir);
|
|
3097
|
-
const managed = exists && fs9.existsSync(markerPath);
|
|
3098
|
-
if (exists && !managed && !opts.update) {
|
|
3099
|
-
return { status: "skipped", message: "existing skill is user-managed", path: targetDir };
|
|
3100
|
-
}
|
|
3101
|
-
ensureDir2(skillRoot);
|
|
3102
|
-
const tmpDir = fs9.mkdtempSync(path11.join(os5.tmpdir(), "cc-mirror-skill-"));
|
|
3103
|
-
try {
|
|
3104
|
-
let fetchResult = cloneRepo(tmpDir);
|
|
3105
|
-
if (!fetchResult.ok) {
|
|
3106
|
-
fetchResult = downloadArchive(tmpDir);
|
|
3107
|
-
}
|
|
3108
|
-
if (!fetchResult.ok) {
|
|
3109
|
-
return { status: "failed", message: fetchResult.message || "skill fetch failed" };
|
|
3110
|
-
}
|
|
3111
|
-
const sourceDir = resolveSkillSourceDir(tmpDir);
|
|
3112
|
-
if (!sourceDir) {
|
|
3113
|
-
return { status: "failed", message: "skill source not found after download" };
|
|
3114
|
-
}
|
|
3115
|
-
if (exists) {
|
|
3116
|
-
fs9.rmSync(targetDir, { recursive: true, force: true });
|
|
3117
|
-
}
|
|
3118
|
-
copyDir(sourceDir, targetDir);
|
|
3119
|
-
fs9.writeFileSync(
|
|
3120
|
-
markerPath,
|
|
3121
|
-
JSON.stringify({ managedBy: "cc-mirror", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
3122
|
-
);
|
|
3123
|
-
return { status: exists ? "updated" : "installed", path: targetDir };
|
|
3124
|
-
} catch (error) {
|
|
3125
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
3126
|
-
return { status: "failed", message };
|
|
3127
|
-
} finally {
|
|
3128
|
-
fs9.rmSync(tmpDir, { recursive: true, force: true });
|
|
3129
|
-
}
|
|
3130
|
-
};
|
|
3131
|
-
var spawnAsync = (cmd, args) => {
|
|
3132
|
-
return new Promise((resolve) => {
|
|
3133
|
-
const child = spawn3(cmd, args, { stdio: "pipe" });
|
|
3134
|
-
let stderr = "";
|
|
3135
|
-
let stdout = "";
|
|
3136
|
-
child.stdout?.on("data", (d) => {
|
|
3137
|
-
stdout += d.toString();
|
|
3138
|
-
});
|
|
3139
|
-
child.stderr?.on("data", (d) => {
|
|
3140
|
-
stderr += d.toString();
|
|
3141
|
-
});
|
|
3142
|
-
child.on("close", (code) => {
|
|
3143
|
-
if (code === 0) resolve({ ok: true });
|
|
3144
|
-
else resolve({ ok: false, message: stderr.trim() || stdout.trim() || `${cmd} failed` });
|
|
3145
|
-
});
|
|
3146
|
-
child.on("error", (err) => resolve({ ok: false, message: err.message }));
|
|
3147
|
-
});
|
|
3148
|
-
};
|
|
3149
|
-
var cloneRepoAsync = async (targetDir) => {
|
|
3150
|
-
if (!commandExists("git")) return { ok: false, message: "git not found" };
|
|
3151
|
-
return spawnAsync("git", ["clone", "--depth", "1", DEV_BROWSER_REPO, targetDir]);
|
|
3512
|
+
`;
|
|
3513
|
+
var upsertBlock = (content, block) => {
|
|
3514
|
+
if (content.includes(BLOCK_START) && content.includes(BLOCK_END)) {
|
|
3515
|
+
const start = content.indexOf(BLOCK_START);
|
|
3516
|
+
const end = content.indexOf(BLOCK_END, start);
|
|
3517
|
+
const before = content.slice(0, start).trimEnd();
|
|
3518
|
+
const after = content.slice(end + BLOCK_END.length).trimStart();
|
|
3519
|
+
return `${before}
|
|
3520
|
+
|
|
3521
|
+
${block}
|
|
3522
|
+
${after}`.trimEnd() + "\n";
|
|
3523
|
+
}
|
|
3524
|
+
return `${content.trimEnd()}
|
|
3525
|
+
|
|
3526
|
+
${block}`.trimEnd() + "\n";
|
|
3152
3527
|
};
|
|
3153
|
-
var
|
|
3154
|
-
|
|
3155
|
-
|
|
3528
|
+
var hasZaiKeyInProfile = (content) => {
|
|
3529
|
+
const lines = content.split("\n");
|
|
3530
|
+
for (const line of lines) {
|
|
3531
|
+
const trimmed = line.trim();
|
|
3532
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
3533
|
+
const exportStripped = trimmed.startsWith("export ") ? trimmed.slice(7).trim() : trimmed;
|
|
3534
|
+
if (!exportStripped.startsWith("Z_AI_API_KEY")) continue;
|
|
3535
|
+
const equalsIndex = exportStripped.indexOf("=");
|
|
3536
|
+
if (equalsIndex === -1) continue;
|
|
3537
|
+
let value = exportStripped.slice(equalsIndex + 1).trim();
|
|
3538
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
3539
|
+
value = value.slice(1, -1);
|
|
3540
|
+
}
|
|
3541
|
+
if (normalizeApiKey(value)) return true;
|
|
3156
3542
|
}
|
|
3157
|
-
|
|
3158
|
-
const curlResult = await spawnAsync("curl", ["-L", "-o", archivePath, DEV_BROWSER_ARCHIVE]);
|
|
3159
|
-
if (!curlResult.ok) return curlResult;
|
|
3160
|
-
return spawnAsync("tar", ["-xzf", archivePath, "-C", targetDir]);
|
|
3543
|
+
return false;
|
|
3161
3544
|
};
|
|
3162
|
-
var
|
|
3163
|
-
|
|
3164
|
-
|
|
3545
|
+
var ensureZaiShellEnv = (opts) => {
|
|
3546
|
+
const apiKey = normalizeApiKey(opts.apiKey) || readSettingsApiKey2(opts.configDir);
|
|
3547
|
+
if (!apiKey) {
|
|
3548
|
+
return { status: "skipped", message: "Z_AI_API_KEY not set (missing API key)" };
|
|
3165
3549
|
}
|
|
3166
|
-
const
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
const exists = fs9.existsSync(targetDir);
|
|
3170
|
-
const managed = exists && fs9.existsSync(markerPath);
|
|
3171
|
-
if (exists && !managed && !opts.update) {
|
|
3172
|
-
return { status: "skipped", message: "existing skill is user-managed", path: targetDir };
|
|
3550
|
+
const envKey = normalizeApiKey(process.env.Z_AI_API_KEY);
|
|
3551
|
+
if (envKey) {
|
|
3552
|
+
return { status: "skipped", message: "Z_AI_API_KEY already set in environment" };
|
|
3173
3553
|
}
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
}
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3554
|
+
const profile = opts.profilePath ?? resolveShellProfile();
|
|
3555
|
+
if (!profile) {
|
|
3556
|
+
return { status: "failed", message: "Unsupported shell; set Z_AI_API_KEY manually" };
|
|
3557
|
+
}
|
|
3558
|
+
const existing = fs10.existsSync(profile) ? fs10.readFileSync(profile, "utf8") : "";
|
|
3559
|
+
if (hasZaiKeyInProfile(existing)) {
|
|
3560
|
+
return { status: "skipped", message: "Z_AI_API_KEY already set in shell profile", path: profile };
|
|
3561
|
+
}
|
|
3562
|
+
const next = upsertBlock(existing, renderBlock(apiKey));
|
|
3563
|
+
if (next === existing) {
|
|
3564
|
+
return { status: "skipped", message: "Shell profile already up to date", path: profile };
|
|
3565
|
+
}
|
|
3566
|
+
fs10.writeFileSync(profile, next);
|
|
3567
|
+
return { status: "updated", path: profile, message: `Run: source ${profile}` };
|
|
3568
|
+
};
|
|
3569
|
+
|
|
3570
|
+
// src/core/variant-builder/steps/ShellEnvStep.ts
|
|
3571
|
+
var ShellEnvStep = class {
|
|
3572
|
+
name = "ShellEnv";
|
|
3573
|
+
execute(ctx) {
|
|
3574
|
+
this.setupShellEnv(ctx);
|
|
3575
|
+
}
|
|
3576
|
+
async executeAsync(ctx) {
|
|
3577
|
+
if (ctx.prefs.shellEnvEnabled && ctx.params.providerKey === "zai") {
|
|
3578
|
+
await ctx.report("Configuring shell environment...");
|
|
3187
3579
|
}
|
|
3188
|
-
|
|
3189
|
-
|
|
3580
|
+
this.setupShellEnv(ctx);
|
|
3581
|
+
}
|
|
3582
|
+
setupShellEnv(ctx) {
|
|
3583
|
+
const { params, paths, prefs, state } = ctx;
|
|
3584
|
+
if (prefs.shellEnvEnabled && params.providerKey === "zai") {
|
|
3585
|
+
ctx.report("Configuring shell environment...");
|
|
3586
|
+
const shellResult = ensureZaiShellEnv({
|
|
3587
|
+
apiKey: state.resolvedApiKey ?? null,
|
|
3588
|
+
configDir: paths.configDir
|
|
3589
|
+
});
|
|
3590
|
+
if (shellResult.status === "updated") {
|
|
3591
|
+
const suffix = shellResult.message ? ` (${shellResult.message})` : "";
|
|
3592
|
+
state.notes.push(`Z_AI_API_KEY written to ${shellResult.path}${suffix}`);
|
|
3593
|
+
} else if (shellResult.status === "failed") {
|
|
3594
|
+
state.notes.push(`Z_AI_API_KEY not written: ${shellResult.message || "unknown error"}`);
|
|
3595
|
+
} else if (shellResult.message) {
|
|
3596
|
+
state.notes.push(`Z_AI_API_KEY: ${shellResult.message}`);
|
|
3597
|
+
}
|
|
3598
|
+
} else if (params.providerKey === "zai") {
|
|
3599
|
+
state.notes.push("Z_AI_API_KEY not written to shell profile. Set it manually in your shell rc file.");
|
|
3190
3600
|
}
|
|
3191
|
-
copyDir(sourceDir, targetDir);
|
|
3192
|
-
fs9.writeFileSync(
|
|
3193
|
-
markerPath,
|
|
3194
|
-
JSON.stringify({ managedBy: "cc-mirror", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
3195
|
-
);
|
|
3196
|
-
return { status: exists ? "updated" : "installed", path: targetDir };
|
|
3197
|
-
} catch (error) {
|
|
3198
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
3199
|
-
return { status: "failed", message };
|
|
3200
|
-
} finally {
|
|
3201
|
-
fs9.rmSync(tmpDir, { recursive: true, force: true });
|
|
3202
3601
|
}
|
|
3203
3602
|
};
|
|
3204
3603
|
|
|
3205
3604
|
// src/core/variant-builder/steps/SkillInstallStep.ts
|
|
3605
|
+
import path13 from "node:path";
|
|
3206
3606
|
var SkillInstallStep = class {
|
|
3207
3607
|
name = "SkillInstall";
|
|
3208
3608
|
execute(ctx) {
|
|
@@ -3214,7 +3614,7 @@ var SkillInstallStep = class {
|
|
|
3214
3614
|
const skillResult = ensureDevBrowserSkill({
|
|
3215
3615
|
install: true,
|
|
3216
3616
|
update: prefs.skillUpdateEnabled,
|
|
3217
|
-
targetDir:
|
|
3617
|
+
targetDir: path13.join(paths.configDir, "skills")
|
|
3218
3618
|
});
|
|
3219
3619
|
if (skillResult.status === "failed") {
|
|
3220
3620
|
state.notes.push(`dev-browser skill install failed: ${skillResult.message || "unknown error"}`);
|
|
@@ -3231,7 +3631,7 @@ var SkillInstallStep = class {
|
|
|
3231
3631
|
const skillResult = await ensureDevBrowserSkillAsync({
|
|
3232
3632
|
install: true,
|
|
3233
3633
|
update: prefs.skillUpdateEnabled,
|
|
3234
|
-
targetDir:
|
|
3634
|
+
targetDir: path13.join(paths.configDir, "skills")
|
|
3235
3635
|
});
|
|
3236
3636
|
if (skillResult.status === "failed") {
|
|
3237
3637
|
state.notes.push(`dev-browser skill install failed: ${skillResult.message || "unknown error"}`);
|
|
@@ -3242,7 +3642,7 @@ var SkillInstallStep = class {
|
|
|
3242
3642
|
};
|
|
3243
3643
|
|
|
3244
3644
|
// src/core/variant-builder/steps/FinalizeStep.ts
|
|
3245
|
-
import
|
|
3645
|
+
import path14 from "node:path";
|
|
3246
3646
|
var FinalizeStep = class {
|
|
3247
3647
|
name = "Finalize";
|
|
3248
3648
|
execute(ctx) {
|
|
@@ -3254,7 +3654,8 @@ var FinalizeStep = class {
|
|
|
3254
3654
|
this.finalize(ctx);
|
|
3255
3655
|
}
|
|
3256
3656
|
finalize(ctx) {
|
|
3257
|
-
const { params, paths, prefs, state } = ctx;
|
|
3657
|
+
const { params, paths, prefs, state, provider } = ctx;
|
|
3658
|
+
const teamModeEnabled = Boolean(params.enableTeamMode) || Boolean(provider.enablesTeamMode);
|
|
3258
3659
|
const meta = {
|
|
3259
3660
|
name: params.name,
|
|
3260
3661
|
provider: params.providerKey,
|
|
@@ -3273,9 +3674,10 @@ var FinalizeStep = class {
|
|
|
3273
3674
|
installType: "npm",
|
|
3274
3675
|
npmDir: paths.npmDir,
|
|
3275
3676
|
npmPackage: prefs.resolvedNpmPackage,
|
|
3276
|
-
npmVersion: prefs.resolvedNpmVersion
|
|
3677
|
+
npmVersion: prefs.resolvedNpmVersion,
|
|
3678
|
+
teamModeEnabled
|
|
3277
3679
|
};
|
|
3278
|
-
writeJson(
|
|
3680
|
+
writeJson(path14.join(paths.variantDir, "variant.json"), meta);
|
|
3279
3681
|
state.meta = meta;
|
|
3280
3682
|
}
|
|
3281
3683
|
};
|
|
@@ -3283,7 +3685,10 @@ var FinalizeStep = class {
|
|
|
3283
3685
|
// src/core/variant-builder/VariantBuilder.ts
|
|
3284
3686
|
var normalizeNpmPackage = (value) => value && value.trim().length > 0 ? value.trim() : DEFAULT_NPM_PACKAGE;
|
|
3285
3687
|
var normalizeNpmVersion = () => DEFAULT_NPM_VERSION;
|
|
3286
|
-
var shouldEnablePromptPack = (providerKey) =>
|
|
3688
|
+
var shouldEnablePromptPack = (providerKey, provider) => {
|
|
3689
|
+
if (provider?.noPromptPack) return false;
|
|
3690
|
+
return providerKey === "zai" || providerKey === "minimax";
|
|
3691
|
+
};
|
|
3287
3692
|
var defaultPromptPackMode = (providerKey) => providerKey === "zai" || providerKey === "minimax" ? "maximal" : "minimal";
|
|
3288
3693
|
var shouldInstallSkills = (providerKey) => providerKey === "zai" || providerKey === "minimax";
|
|
3289
3694
|
var shouldEnableShellEnv = (providerKey) => providerKey === "zai";
|
|
@@ -3294,6 +3699,8 @@ var VariantBuilder = class {
|
|
|
3294
3699
|
this.steps = [
|
|
3295
3700
|
new PrepareDirectoriesStep(),
|
|
3296
3701
|
new InstallNpmStep(),
|
|
3702
|
+
new TeamModeStep(),
|
|
3703
|
+
// Patches cli.js for team mode (if enabled)
|
|
3297
3704
|
new WriteConfigStep(),
|
|
3298
3705
|
new BrandThemeStep(),
|
|
3299
3706
|
new TweakccStep(),
|
|
@@ -3315,11 +3722,11 @@ var VariantBuilder = class {
|
|
|
3315
3722
|
const binDir = params.binDir ?? DEFAULT_BIN_DIR;
|
|
3316
3723
|
const resolvedRoot = expandTilde(rootDir) ?? rootDir;
|
|
3317
3724
|
const resolvedBin = expandTilde(binDir) ?? binDir;
|
|
3318
|
-
const variantDir =
|
|
3319
|
-
const configDir =
|
|
3320
|
-
const tweakDir =
|
|
3321
|
-
const wrapperPath =
|
|
3322
|
-
const npmDir =
|
|
3725
|
+
const variantDir = path15.join(resolvedRoot, params.name);
|
|
3726
|
+
const configDir = path15.join(variantDir, "config");
|
|
3727
|
+
const tweakDir = path15.join(variantDir, "tweakcc");
|
|
3728
|
+
const wrapperPath = path15.join(resolvedBin, params.name);
|
|
3729
|
+
const npmDir = path15.join(variantDir, "npm");
|
|
3323
3730
|
const paths = {
|
|
3324
3731
|
resolvedRoot,
|
|
3325
3732
|
resolvedBin,
|
|
@@ -3331,7 +3738,7 @@ var VariantBuilder = class {
|
|
|
3331
3738
|
};
|
|
3332
3739
|
const resolvedNpmPackage = normalizeNpmPackage(params.npmPackage);
|
|
3333
3740
|
const resolvedNpmVersion = normalizeNpmVersion();
|
|
3334
|
-
const promptPackPreference = params.promptPack ?? shouldEnablePromptPack(params.providerKey);
|
|
3741
|
+
const promptPackPreference = params.promptPack ?? shouldEnablePromptPack(params.providerKey, provider);
|
|
3335
3742
|
const promptPackModePreference = params.promptPackMode ?? defaultPromptPackMode(params.providerKey);
|
|
3336
3743
|
const promptPackEnabled = !params.noTweak && promptPackPreference;
|
|
3337
3744
|
const skillInstallEnabled = params.skillInstall ?? shouldInstallSkills(params.providerKey);
|
|
@@ -3416,7 +3823,7 @@ var VariantBuilder = class {
|
|
|
3416
3823
|
};
|
|
3417
3824
|
|
|
3418
3825
|
// src/core/variant-builder/VariantUpdater.ts
|
|
3419
|
-
import
|
|
3826
|
+
import path20 from "node:path";
|
|
3420
3827
|
|
|
3421
3828
|
// src/core/variant-builder/update-steps/InstallNpmUpdateStep.ts
|
|
3422
3829
|
var InstallNpmUpdateStep = class {
|
|
@@ -3450,6 +3857,128 @@ var InstallNpmUpdateStep = class {
|
|
|
3450
3857
|
}
|
|
3451
3858
|
};
|
|
3452
3859
|
|
|
3860
|
+
// src/core/variant-builder/update-steps/TeamModeUpdateStep.ts
|
|
3861
|
+
import fs11 from "node:fs";
|
|
3862
|
+
import path16 from "node:path";
|
|
3863
|
+
var TEAM_MODE_DISABLED2 = "function sU(){return!1}";
|
|
3864
|
+
var TEAM_MODE_ENABLED2 = "function sU(){return!0}";
|
|
3865
|
+
var TeamModeUpdateStep = class {
|
|
3866
|
+
name = "TeamMode";
|
|
3867
|
+
shouldEnableTeamMode(ctx) {
|
|
3868
|
+
const provider = getProvider(ctx.meta.provider);
|
|
3869
|
+
return Boolean(ctx.opts.enableTeamMode) || Boolean(provider?.enablesTeamMode);
|
|
3870
|
+
}
|
|
3871
|
+
shouldDisableTeamMode(ctx) {
|
|
3872
|
+
return Boolean(ctx.opts.disableTeamMode);
|
|
3873
|
+
}
|
|
3874
|
+
execute(ctx) {
|
|
3875
|
+
if (this.shouldDisableTeamMode(ctx)) {
|
|
3876
|
+
ctx.report("Disabling team mode...");
|
|
3877
|
+
this.unpatchCli(ctx);
|
|
3878
|
+
return;
|
|
3879
|
+
}
|
|
3880
|
+
if (!this.shouldEnableTeamMode(ctx)) return;
|
|
3881
|
+
ctx.report("Enabling team mode...");
|
|
3882
|
+
this.patchCli(ctx);
|
|
3883
|
+
}
|
|
3884
|
+
async executeAsync(ctx) {
|
|
3885
|
+
if (this.shouldDisableTeamMode(ctx)) {
|
|
3886
|
+
await ctx.report("Disabling team mode...");
|
|
3887
|
+
this.unpatchCli(ctx);
|
|
3888
|
+
return;
|
|
3889
|
+
}
|
|
3890
|
+
if (!this.shouldEnableTeamMode(ctx)) return;
|
|
3891
|
+
await ctx.report("Enabling team mode...");
|
|
3892
|
+
this.patchCli(ctx);
|
|
3893
|
+
}
|
|
3894
|
+
unpatchCli(ctx) {
|
|
3895
|
+
const { state, meta } = ctx;
|
|
3896
|
+
const cliPath = path16.join(meta.npmDir || "", "node_modules", "@anthropic-ai", "claude-code", "cli.js");
|
|
3897
|
+
if (!fs11.existsSync(cliPath)) {
|
|
3898
|
+
state.notes.push("Warning: cli.js not found, skipping team mode unpatch");
|
|
3899
|
+
return;
|
|
3900
|
+
}
|
|
3901
|
+
let content = fs11.readFileSync(cliPath, "utf8");
|
|
3902
|
+
if (content.includes(TEAM_MODE_DISABLED2)) {
|
|
3903
|
+
state.notes.push("Team mode already disabled");
|
|
3904
|
+
meta.teamModeEnabled = false;
|
|
3905
|
+
return;
|
|
3906
|
+
}
|
|
3907
|
+
if (!content.includes(TEAM_MODE_ENABLED2)) {
|
|
3908
|
+
state.notes.push("Warning: Team mode function not found in cli.js");
|
|
3909
|
+
return;
|
|
3910
|
+
}
|
|
3911
|
+
content = content.replace(TEAM_MODE_ENABLED2, TEAM_MODE_DISABLED2);
|
|
3912
|
+
fs11.writeFileSync(cliPath, content);
|
|
3913
|
+
const verifyContent = fs11.readFileSync(cliPath, "utf8");
|
|
3914
|
+
if (!verifyContent.includes(TEAM_MODE_DISABLED2)) {
|
|
3915
|
+
state.notes.push("Warning: Team mode unpatch verification failed");
|
|
3916
|
+
return;
|
|
3917
|
+
}
|
|
3918
|
+
meta.teamModeEnabled = false;
|
|
3919
|
+
state.notes.push("Team mode disabled successfully");
|
|
3920
|
+
const skillResult = removeOrchestratorSkill(meta.configDir);
|
|
3921
|
+
if (skillResult.status === "removed") {
|
|
3922
|
+
state.notes.push("Multi-agent orchestrator skill removed");
|
|
3923
|
+
} else if (skillResult.status === "failed") {
|
|
3924
|
+
state.notes.push(`Warning: orchestrator skill removal failed: ${skillResult.message}`);
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
patchCli(ctx) {
|
|
3928
|
+
const { state, meta, name } = ctx;
|
|
3929
|
+
const cliPath = path16.join(meta.npmDir || "", "node_modules", "@anthropic-ai", "claude-code", "cli.js");
|
|
3930
|
+
const backupPath = `${cliPath}.backup`;
|
|
3931
|
+
if (!fs11.existsSync(cliPath)) {
|
|
3932
|
+
state.notes.push("Warning: cli.js not found, skipping team mode patch");
|
|
3933
|
+
return;
|
|
3934
|
+
}
|
|
3935
|
+
if (!fs11.existsSync(backupPath)) {
|
|
3936
|
+
fs11.copyFileSync(cliPath, backupPath);
|
|
3937
|
+
}
|
|
3938
|
+
let content = fs11.readFileSync(cliPath, "utf8");
|
|
3939
|
+
if (content.includes(TEAM_MODE_ENABLED2)) {
|
|
3940
|
+
state.notes.push("Team mode already enabled");
|
|
3941
|
+
meta.teamModeEnabled = true;
|
|
3942
|
+
return;
|
|
3943
|
+
}
|
|
3944
|
+
if (!content.includes(TEAM_MODE_DISABLED2)) {
|
|
3945
|
+
state.notes.push("Warning: Team mode function not found in cli.js, patch may not work");
|
|
3946
|
+
return;
|
|
3947
|
+
}
|
|
3948
|
+
content = content.replace(TEAM_MODE_DISABLED2, TEAM_MODE_ENABLED2);
|
|
3949
|
+
fs11.writeFileSync(cliPath, content);
|
|
3950
|
+
const verifyContent = fs11.readFileSync(cliPath, "utf8");
|
|
3951
|
+
if (!verifyContent.includes(TEAM_MODE_ENABLED2)) {
|
|
3952
|
+
state.notes.push("Warning: Team mode patch verification failed");
|
|
3953
|
+
return;
|
|
3954
|
+
}
|
|
3955
|
+
const settingsPath = path16.join(meta.configDir, "settings.json");
|
|
3956
|
+
if (fs11.existsSync(settingsPath)) {
|
|
3957
|
+
try {
|
|
3958
|
+
const settings = JSON.parse(fs11.readFileSync(settingsPath, "utf8"));
|
|
3959
|
+
settings.env = settings.env || {};
|
|
3960
|
+
if (!settings.env.CLAUDE_CODE_TEAM_NAME) {
|
|
3961
|
+
settings.env.CLAUDE_CODE_TEAM_NAME = name;
|
|
3962
|
+
}
|
|
3963
|
+
if (!settings.env.CLAUDE_CODE_AGENT_TYPE) {
|
|
3964
|
+
settings.env.CLAUDE_CODE_AGENT_TYPE = "team-lead";
|
|
3965
|
+
}
|
|
3966
|
+
fs11.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
3967
|
+
} catch {
|
|
3968
|
+
state.notes.push("Warning: Could not update settings.json with team env vars");
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
meta.teamModeEnabled = true;
|
|
3972
|
+
state.notes.push("Team mode enabled successfully");
|
|
3973
|
+
const skillResult = installOrchestratorSkill(meta.configDir);
|
|
3974
|
+
if (skillResult.status === "installed") {
|
|
3975
|
+
state.notes.push("Multi-agent orchestrator skill installed");
|
|
3976
|
+
} else if (skillResult.status === "failed") {
|
|
3977
|
+
state.notes.push(`Warning: orchestrator skill install failed: ${skillResult.message}`);
|
|
3978
|
+
}
|
|
3979
|
+
}
|
|
3980
|
+
};
|
|
3981
|
+
|
|
3453
3982
|
// src/core/variant-builder/update-steps/ModelOverridesStep.ts
|
|
3454
3983
|
var ModelOverridesStep = class {
|
|
3455
3984
|
name = "ModelOverrides";
|
|
@@ -3533,7 +4062,7 @@ ${reapply.stdout ?? ""}`.trim();
|
|
|
3533
4062
|
};
|
|
3534
4063
|
|
|
3535
4064
|
// src/core/variant-builder/update-steps/WrapperUpdateStep.ts
|
|
3536
|
-
import
|
|
4065
|
+
import path17 from "node:path";
|
|
3537
4066
|
var WrapperUpdateStep = class {
|
|
3538
4067
|
name = "Wrapper";
|
|
3539
4068
|
execute(ctx) {
|
|
@@ -3551,7 +4080,7 @@ var WrapperUpdateStep = class {
|
|
|
3551
4080
|
const resolvedBin = opts.binDir ? expandTilde(opts.binDir) ?? opts.binDir : meta.binDir;
|
|
3552
4081
|
if (resolvedBin) {
|
|
3553
4082
|
ensureDir(resolvedBin);
|
|
3554
|
-
const wrapperPath =
|
|
4083
|
+
const wrapperPath = path17.join(resolvedBin, name);
|
|
3555
4084
|
writeWrapper(wrapperPath, meta.configDir, meta.binaryPath, "node");
|
|
3556
4085
|
meta.binDir = resolvedBin;
|
|
3557
4086
|
}
|
|
@@ -3643,7 +4172,7 @@ var ShellEnvUpdateStep = class {
|
|
|
3643
4172
|
};
|
|
3644
4173
|
|
|
3645
4174
|
// src/core/variant-builder/update-steps/SkillInstallUpdateStep.ts
|
|
3646
|
-
import
|
|
4175
|
+
import path18 from "node:path";
|
|
3647
4176
|
var SkillInstallUpdateStep = class {
|
|
3648
4177
|
name = "SkillInstall";
|
|
3649
4178
|
execute(ctx) {
|
|
@@ -3663,7 +4192,7 @@ var SkillInstallUpdateStep = class {
|
|
|
3663
4192
|
const skillOpts = {
|
|
3664
4193
|
install: true,
|
|
3665
4194
|
update: prefs.skillUpdateEnabled,
|
|
3666
|
-
targetDir:
|
|
4195
|
+
targetDir: path18.join(meta.configDir, "skills")
|
|
3667
4196
|
};
|
|
3668
4197
|
const skillResult = isAsync ? await ensureDevBrowserSkillAsync(skillOpts) : ensureDevBrowserSkill(skillOpts);
|
|
3669
4198
|
if (skillResult.status === "failed") {
|
|
@@ -3675,7 +4204,7 @@ var SkillInstallUpdateStep = class {
|
|
|
3675
4204
|
};
|
|
3676
4205
|
|
|
3677
4206
|
// src/core/variant-builder/update-steps/FinalizeUpdateStep.ts
|
|
3678
|
-
import
|
|
4207
|
+
import path19 from "node:path";
|
|
3679
4208
|
var FinalizeUpdateStep = class {
|
|
3680
4209
|
name = "Finalize";
|
|
3681
4210
|
execute(ctx) {
|
|
@@ -3693,14 +4222,18 @@ var FinalizeUpdateStep = class {
|
|
|
3693
4222
|
meta.promptPackMode = prefs.promptPackModePreference;
|
|
3694
4223
|
meta.skillInstall = prefs.skillInstallEnabled;
|
|
3695
4224
|
meta.shellEnv = prefs.shellEnvEnabled;
|
|
3696
|
-
writeJson(
|
|
4225
|
+
writeJson(path19.join(paths.variantDir, "variant.json"), meta);
|
|
3697
4226
|
}
|
|
3698
4227
|
};
|
|
3699
4228
|
|
|
3700
4229
|
// src/core/variant-builder/VariantUpdater.ts
|
|
3701
4230
|
var normalizeNpmPackage2 = (value) => value && value.trim().length > 0 ? value.trim() : DEFAULT_NPM_PACKAGE;
|
|
3702
4231
|
var normalizeNpmVersion2 = () => DEFAULT_NPM_VERSION;
|
|
3703
|
-
var shouldEnablePromptPack2 = (providerKey) =>
|
|
4232
|
+
var shouldEnablePromptPack2 = (providerKey) => {
|
|
4233
|
+
const provider = getProvider(providerKey);
|
|
4234
|
+
if (provider?.noPromptPack) return false;
|
|
4235
|
+
return providerKey === "zai" || providerKey === "minimax";
|
|
4236
|
+
};
|
|
3704
4237
|
var defaultPromptPackMode2 = (providerKey) => providerKey === "zai" || providerKey === "minimax" ? "maximal" : "minimal";
|
|
3705
4238
|
var shouldInstallSkills2 = (providerKey) => providerKey === "zai" || providerKey === "minimax";
|
|
3706
4239
|
var shouldEnableShellEnv2 = (providerKey) => providerKey === "zai";
|
|
@@ -3710,6 +4243,8 @@ var VariantUpdater = class {
|
|
|
3710
4243
|
this.isAsync = isAsync;
|
|
3711
4244
|
this.steps = [
|
|
3712
4245
|
new InstallNpmUpdateStep(),
|
|
4246
|
+
new TeamModeUpdateStep(),
|
|
4247
|
+
// Patches cli.js for team mode (if enabled)
|
|
3713
4248
|
new ModelOverridesStep(),
|
|
3714
4249
|
new TweakccUpdateStep(),
|
|
3715
4250
|
new WrapperUpdateStep(),
|
|
@@ -3725,7 +4260,7 @@ var VariantUpdater = class {
|
|
|
3725
4260
|
*/
|
|
3726
4261
|
initContext(rootDir, name, opts) {
|
|
3727
4262
|
const resolvedRoot = expandTilde(rootDir || DEFAULT_ROOT) ?? rootDir;
|
|
3728
|
-
const variantDir =
|
|
4263
|
+
const variantDir = path20.join(resolvedRoot, name);
|
|
3729
4264
|
const meta = loadVariantMeta(variantDir);
|
|
3730
4265
|
if (!meta) throw new Error(`Variant not found: ${name}`);
|
|
3731
4266
|
const resolvedNpmPackage = normalizeNpmPackage2(opts.npmPackage ?? meta.npmPackage);
|
|
@@ -3741,7 +4276,7 @@ var VariantUpdater = class {
|
|
|
3741
4276
|
resolvedRoot,
|
|
3742
4277
|
resolvedBin: opts.binDir ? expandTilde(opts.binDir) ?? opts.binDir : meta.binDir,
|
|
3743
4278
|
variantDir,
|
|
3744
|
-
npmDir: meta.npmDir ||
|
|
4279
|
+
npmDir: meta.npmDir || path20.join(variantDir, "npm")
|
|
3745
4280
|
};
|
|
3746
4281
|
const prefs = {
|
|
3747
4282
|
resolvedNpmPackage,
|
|
@@ -3829,17 +4364,17 @@ var updateVariant = (rootDir, name, opts = {}) => {
|
|
|
3829
4364
|
};
|
|
3830
4365
|
var removeVariant = (rootDir, name) => {
|
|
3831
4366
|
const resolvedRoot = expandTilde(rootDir || DEFAULT_ROOT) ?? rootDir;
|
|
3832
|
-
const variantDir =
|
|
3833
|
-
if (!
|
|
3834
|
-
|
|
4367
|
+
const variantDir = path21.join(resolvedRoot, name);
|
|
4368
|
+
if (!fs12.existsSync(variantDir)) throw new Error(`Variant not found: ${name}`);
|
|
4369
|
+
fs12.rmSync(variantDir, { recursive: true, force: true });
|
|
3835
4370
|
};
|
|
3836
4371
|
var doctor = (rootDir, binDir) => {
|
|
3837
4372
|
const resolvedRoot = expandTilde(rootDir || DEFAULT_ROOT) ?? rootDir;
|
|
3838
4373
|
const resolvedBin = expandTilde(binDir || DEFAULT_BIN_DIR) ?? binDir;
|
|
3839
4374
|
const variants = listVariants(resolvedRoot);
|
|
3840
4375
|
return variants.map(({ name, meta }) => {
|
|
3841
|
-
const wrapperPath =
|
|
3842
|
-
const ok = Boolean(meta &&
|
|
4376
|
+
const wrapperPath = path21.join(resolvedBin, name);
|
|
4377
|
+
const ok = Boolean(meta && fs12.existsSync(meta.binaryPath) && fs12.existsSync(wrapperPath));
|
|
3843
4378
|
return {
|
|
3844
4379
|
name,
|
|
3845
4380
|
ok,
|
|
@@ -3851,7 +4386,7 @@ var doctor = (rootDir, binDir) => {
|
|
|
3851
4386
|
var listVariants2 = (rootDir) => listVariants(rootDir);
|
|
3852
4387
|
var tweakVariant = (rootDir, name) => {
|
|
3853
4388
|
const resolvedRoot = expandTilde(rootDir || DEFAULT_ROOT) ?? rootDir;
|
|
3854
|
-
const variantDir =
|
|
4389
|
+
const variantDir = path21.join(resolvedRoot, name);
|
|
3855
4390
|
const meta = loadVariantMeta(variantDir);
|
|
3856
4391
|
if (!meta) throw new Error(`Variant not found: ${name}`);
|
|
3857
4392
|
ensureDir(meta.tweakDir);
|
|
@@ -3867,7 +4402,7 @@ ${result.stdout ?? ""}`.trim();
|
|
|
3867
4402
|
|
|
3868
4403
|
// src/tui/hooks/useVariantCreate.ts
|
|
3869
4404
|
import { useEffect } from "react";
|
|
3870
|
-
import
|
|
4405
|
+
import path22 from "node:path";
|
|
3871
4406
|
function buildCreateSummary(params) {
|
|
3872
4407
|
const {
|
|
3873
4408
|
providerLabel,
|
|
@@ -3898,7 +4433,7 @@ function buildCreateNextSteps(name, rootDir) {
|
|
|
3898
4433
|
`Run: ${name}`,
|
|
3899
4434
|
`Update: cc-mirror update ${name}`,
|
|
3900
4435
|
`Tweak: cc-mirror tweak ${name}`,
|
|
3901
|
-
`Config: ${
|
|
4436
|
+
`Config: ${path22.join(rootDir, name, "config", "settings.json")}`
|
|
3902
4437
|
];
|
|
3903
4438
|
}
|
|
3904
4439
|
function buildHelpLines() {
|
|
@@ -3952,7 +4487,7 @@ function useVariantCreate(options) {
|
|
|
3952
4487
|
doneLines: [
|
|
3953
4488
|
`Variant created: ${params.name}`,
|
|
3954
4489
|
`Wrapper: ${result.wrapperPath}`,
|
|
3955
|
-
`Config: ${
|
|
4490
|
+
`Config: ${path22.join(params.rootDir, params.name, "config")}`
|
|
3956
4491
|
],
|
|
3957
4492
|
summary,
|
|
3958
4493
|
nextSteps: buildCreateNextSteps(params.name, params.rootDir),
|
|
@@ -3980,7 +4515,7 @@ function useVariantCreate(options) {
|
|
|
3980
4515
|
|
|
3981
4516
|
// src/tui/hooks/useVariantUpdate.ts
|
|
3982
4517
|
import { useEffect as useEffect2 } from "react";
|
|
3983
|
-
import
|
|
4518
|
+
import path23 from "node:path";
|
|
3984
4519
|
function buildUpdateSummary(meta, notes) {
|
|
3985
4520
|
return [
|
|
3986
4521
|
`Provider: ${meta.provider}`,
|
|
@@ -3994,7 +4529,7 @@ function buildUpdateNextSteps(name, rootDir) {
|
|
|
3994
4529
|
return [
|
|
3995
4530
|
`Run: ${name}`,
|
|
3996
4531
|
`Tweak: cc-mirror tweak ${name}`,
|
|
3997
|
-
`Config: ${
|
|
4532
|
+
`Config: ${path23.join(rootDir, name, "config", "settings.json")}`
|
|
3998
4533
|
];
|
|
3999
4534
|
}
|
|
4000
4535
|
function useVariantUpdate(options) {
|
|
@@ -4186,6 +4721,59 @@ function useModelConfig(options) {
|
|
|
4186
4721
|
]);
|
|
4187
4722
|
}
|
|
4188
4723
|
|
|
4724
|
+
// src/tui/hooks/useTeamModeToggle.ts
|
|
4725
|
+
import { useEffect as useEffect5 } from "react";
|
|
4726
|
+
function useTeamModeToggle(options) {
|
|
4727
|
+
const { screen, selectedVariant, rootDir, binDir, core, setProgressLines, setScreen, onComplete, refreshVariants } = options;
|
|
4728
|
+
useEffect5(() => {
|
|
4729
|
+
if (screen !== "manage-team-mode") return;
|
|
4730
|
+
if (!selectedVariant) return;
|
|
4731
|
+
let cancelled = false;
|
|
4732
|
+
const runToggle = async () => {
|
|
4733
|
+
try {
|
|
4734
|
+
setProgressLines(() => []);
|
|
4735
|
+
const isCurrentlyEnabled = selectedVariant.teamModeEnabled;
|
|
4736
|
+
const action = isCurrentlyEnabled ? "Disabling" : "Enabling";
|
|
4737
|
+
setProgressLines((prev) => [...prev, `${action} team mode...`]);
|
|
4738
|
+
const opts = {
|
|
4739
|
+
tweakccStdio: "pipe",
|
|
4740
|
+
binDir,
|
|
4741
|
+
settingsOnly: true,
|
|
4742
|
+
// Don't reinstall npm package
|
|
4743
|
+
enableTeamMode: !isCurrentlyEnabled,
|
|
4744
|
+
disableTeamMode: isCurrentlyEnabled,
|
|
4745
|
+
onProgress: (step) => setProgressLines((prev) => [...prev, step])
|
|
4746
|
+
};
|
|
4747
|
+
const result = core.updateVariantAsync ? await core.updateVariantAsync(rootDir, selectedVariant.name, opts) : core.updateVariant(rootDir, selectedVariant.name, opts);
|
|
4748
|
+
if (cancelled) return;
|
|
4749
|
+
const newStatus = result.meta.teamModeEnabled ? "enabled" : "disabled";
|
|
4750
|
+
const completion = {
|
|
4751
|
+
doneLines: [`Team mode ${newStatus} for ${selectedVariant.name}`],
|
|
4752
|
+
summary: [...result.notes || []],
|
|
4753
|
+
nextSteps: [`Run: ${selectedVariant.name}`],
|
|
4754
|
+
help: ["Team mode adds TaskCreate, TaskGet, TaskUpdate, TaskList tools for multi-agent coordination"]
|
|
4755
|
+
};
|
|
4756
|
+
onComplete(completion);
|
|
4757
|
+
refreshVariants();
|
|
4758
|
+
} catch (error) {
|
|
4759
|
+
if (cancelled) return;
|
|
4760
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4761
|
+
onComplete({
|
|
4762
|
+
doneLines: [`Failed: ${message}`],
|
|
4763
|
+
summary: [],
|
|
4764
|
+
nextSteps: [],
|
|
4765
|
+
help: []
|
|
4766
|
+
});
|
|
4767
|
+
}
|
|
4768
|
+
if (!cancelled) setScreen("manage-team-mode-done");
|
|
4769
|
+
};
|
|
4770
|
+
runToggle();
|
|
4771
|
+
return () => {
|
|
4772
|
+
cancelled = true;
|
|
4773
|
+
};
|
|
4774
|
+
}, [screen, selectedVariant, rootDir, binDir, core, setProgressLines, setScreen, onComplete, refreshVariants]);
|
|
4775
|
+
}
|
|
4776
|
+
|
|
4189
4777
|
// src/tui/screens/HomeScreen.tsx
|
|
4190
4778
|
import { useState, useRef } from "react";
|
|
4191
4779
|
import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
|
|
@@ -4351,7 +4939,7 @@ var SelectMenu = ({ items, selectedIndex, onIndexChange, onSelect }) => {
|
|
|
4351
4939
|
});
|
|
4352
4940
|
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: items.map((item, idx) => /* @__PURE__ */ jsx2(MenuItemDisplay, { item, selected: idx === selectedIndex }, item.value)) });
|
|
4353
4941
|
};
|
|
4354
|
-
var ProviderCard = ({ provider, selected, disabled = false }) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
|
|
4942
|
+
var ProviderCard = ({ provider, selected, disabled = false, docsUrl }) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
|
|
4355
4943
|
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
4356
4944
|
/* @__PURE__ */ jsxs2(Text2, { color: selected ? colors.gold : colors.textMuted, children: [
|
|
4357
4945
|
selected ? icons.pointer : icons.pointerEmpty,
|
|
@@ -4369,9 +4957,10 @@ var ProviderCard = ({ provider, selected, disabled = false }) => /* @__PURE__ */
|
|
|
4369
4957
|
disabled && /* @__PURE__ */ jsx2(Text2, { color: colors.warning, children: " [Coming Soon]" })
|
|
4370
4958
|
] }),
|
|
4371
4959
|
/* @__PURE__ */ jsx2(Box2, { marginLeft: 3, children: /* @__PURE__ */ jsx2(Text2, { color: disabled ? colors.textDim : colors.textMuted, dimColor: disabled, children: provider.description }) }),
|
|
4372
|
-
provider.baseUrl && !disabled && /* @__PURE__ */ jsx2(Box2, { marginLeft: 3, children: /* @__PURE__ */ jsx2(Text2, { color: colors.primaryBright, dimColor: true, children: provider.baseUrl }) })
|
|
4960
|
+
provider.baseUrl && !disabled && /* @__PURE__ */ jsx2(Box2, { marginLeft: 3, children: /* @__PURE__ */ jsx2(Text2, { color: colors.primaryBright, dimColor: true, children: provider.baseUrl }) }),
|
|
4961
|
+
!provider.baseUrl && docsUrl && !disabled && /* @__PURE__ */ jsx2(Box2, { marginLeft: 3, children: /* @__PURE__ */ jsx2(Text2, { color: colors.primaryBright, dimColor: true, children: docsUrl }) })
|
|
4373
4962
|
] });
|
|
4374
|
-
var VariantCard = ({ name, provider, path:
|
|
4963
|
+
var VariantCard = ({ name, provider, path: path25, selected }) => /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
|
|
4375
4964
|
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
4376
4965
|
/* @__PURE__ */ jsxs2(Text2, { color: selected ? colors.gold : colors.textMuted, children: [
|
|
4377
4966
|
selected ? icons.pointer : icons.pointerEmpty,
|
|
@@ -4384,7 +4973,7 @@ var VariantCard = ({ name, provider, path: path23, selected }) => /* @__PURE__ *
|
|
|
4384
4973
|
")"
|
|
4385
4974
|
] })
|
|
4386
4975
|
] }),
|
|
4387
|
-
/* @__PURE__ */ jsx2(Box2, { marginLeft: 3, children: /* @__PURE__ */ jsx2(Text2, { color: colors.primaryBright, dimColor: true, children:
|
|
4976
|
+
/* @__PURE__ */ jsx2(Box2, { marginLeft: 3, children: /* @__PURE__ */ jsx2(Text2, { color: colors.primaryBright, dimColor: true, children: path25 || `~/.local/bin/${name}` }) })
|
|
4388
4977
|
] });
|
|
4389
4978
|
|
|
4390
4979
|
// src/tui/components/ui/Logo.tsx
|
|
@@ -4657,6 +5246,26 @@ var PROVIDER_EDUCATION = {
|
|
|
4657
5246
|
docs: "https://github.com/musistudio/claude-code-router#2-configuration"
|
|
4658
5247
|
},
|
|
4659
5248
|
setupNote: 'Install: npm i -g @musistudio/claude-code-router, run "ccr start". Configure models in ~/.claude-code-router/config.json'
|
|
5249
|
+
},
|
|
5250
|
+
mirror: {
|
|
5251
|
+
headline: "Mirror Claude \u2014 Pure Claude Code, Enhanced",
|
|
5252
|
+
tagline: "Reflections of perfection",
|
|
5253
|
+
features: [
|
|
5254
|
+
"Pure Claude Code experience (no proxy)",
|
|
5255
|
+
"Team mode enabled by default",
|
|
5256
|
+
"Isolated config for experimentation",
|
|
5257
|
+
"Premium silver/chrome theme",
|
|
5258
|
+
"No API key required at setup"
|
|
5259
|
+
],
|
|
5260
|
+
bestFor: "Power users who want enhanced Claude Code without changing the AI",
|
|
5261
|
+
requiresMapping: false,
|
|
5262
|
+
hasPromptPack: false,
|
|
5263
|
+
setupLinks: {
|
|
5264
|
+
subscribe: "https://console.anthropic.com/settings/plans",
|
|
5265
|
+
apiKey: "https://console.anthropic.com/settings/keys",
|
|
5266
|
+
docs: "https://github.com/numman-ali/cc-mirror/blob/main/docs/features/mirror-claude.md"
|
|
5267
|
+
},
|
|
5268
|
+
setupNote: "Uses normal Claude authentication. Sign in via OAuth or set ANTHROPIC_API_KEY."
|
|
4660
5269
|
}
|
|
4661
5270
|
};
|
|
4662
5271
|
var getProviderEducation = (providerKey) => {
|
|
@@ -4716,15 +5325,20 @@ var ProviderSelectScreen = ({ providers, onSelect }) => {
|
|
|
4716
5325
|
" OpenRouter/Local LLMs require model mapping"
|
|
4717
5326
|
] })
|
|
4718
5327
|
] }),
|
|
4719
|
-
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", marginY: 1, children: providers.map((provider, idx) =>
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
5328
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", marginY: 1, children: providers.map((provider, idx) => {
|
|
5329
|
+
const providerEducation = getProviderEducation(provider.key);
|
|
5330
|
+
const docsUrl = providerEducation?.setupLinks?.docs;
|
|
5331
|
+
return /* @__PURE__ */ jsx7(
|
|
5332
|
+
ProviderCard,
|
|
5333
|
+
{
|
|
5334
|
+
provider,
|
|
5335
|
+
selected: idx === selectedIndex && !provider.experimental,
|
|
5336
|
+
disabled: provider.experimental,
|
|
5337
|
+
docsUrl
|
|
5338
|
+
},
|
|
5339
|
+
provider.key
|
|
5340
|
+
);
|
|
5341
|
+
}) }),
|
|
4728
5342
|
showDetails && education && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, paddingX: 1, children: [
|
|
4729
5343
|
/* @__PURE__ */ jsxs7(Box7, { marginBottom: 1, children: [
|
|
4730
5344
|
/* @__PURE__ */ jsxs7(Text7, { color: colors.gold, children: [
|
|
@@ -4797,6 +5411,16 @@ var ProviderIntroScreen = ({
|
|
|
4797
5411
|
steps2.push("Create!");
|
|
4798
5412
|
return steps2;
|
|
4799
5413
|
}
|
|
5414
|
+
if (providerKey === "mirror") {
|
|
5415
|
+
if (!isQuickSetup) {
|
|
5416
|
+
steps2.push("Choose a visual theme");
|
|
5417
|
+
steps2.push("Optional: dev-browser skill");
|
|
5418
|
+
}
|
|
5419
|
+
steps2.push("Name your variant");
|
|
5420
|
+
steps2.push("Create!");
|
|
5421
|
+
steps2.push("Authenticate via Claude Code (OAuth or API key)");
|
|
5422
|
+
return steps2;
|
|
5423
|
+
}
|
|
4800
5424
|
steps2.push("Enter your API key");
|
|
4801
5425
|
if (education?.requiresMapping) {
|
|
4802
5426
|
steps2.push("Configure model aliases");
|
|
@@ -4841,7 +5465,14 @@ var ProviderIntroScreen = ({
|
|
|
4841
5465
|
] }, index)) })
|
|
4842
5466
|
] }),
|
|
4843
5467
|
education?.setupNote && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { color: colors.textDim, italic: true, children: education.setupNote }) }),
|
|
4844
|
-
|
|
5468
|
+
education?.setupLinks?.github && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text8, { color: colors.primaryBright, children: [
|
|
5469
|
+
"GitHub: ",
|
|
5470
|
+
education.setupLinks.github
|
|
5471
|
+
] }) }),
|
|
5472
|
+
education?.setupLinks?.docs && !education?.setupLinks?.github && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text8, { color: colors.primaryBright, children: [
|
|
5473
|
+
"Docs: ",
|
|
5474
|
+
education.setupLinks.docs
|
|
5475
|
+
] }) }),
|
|
4845
5476
|
/* @__PURE__ */ jsx8(Box8, { marginTop: 2, children: /* @__PURE__ */ jsx8(Text8, { color: colors.primaryBright, children: "Press Enter to continue \u2192" }) })
|
|
4846
5477
|
]
|
|
4847
5478
|
}
|
|
@@ -5115,16 +5746,16 @@ var SummaryScreen = ({ data, onConfirm, onBack, onCancel }) => {
|
|
|
5115
5746
|
};
|
|
5116
5747
|
|
|
5117
5748
|
// src/tui/screens/ProgressScreen.tsx
|
|
5118
|
-
import { useEffect as
|
|
5749
|
+
import { useEffect as useEffect7, useMemo, useState as useState5 } from "react";
|
|
5119
5750
|
import { Box as Box15, Text as Text14 } from "ink";
|
|
5120
5751
|
|
|
5121
5752
|
// src/tui/components/ui/Progress.tsx
|
|
5122
|
-
import { useState as useState4, useEffect as
|
|
5753
|
+
import { useState as useState4, useEffect as useEffect6 } from "react";
|
|
5123
5754
|
import { Box as Box14, Text as Text13, useStdout } from "ink";
|
|
5124
5755
|
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
5125
5756
|
var useSpinner = (interval = 80) => {
|
|
5126
5757
|
const [frame, setFrame] = useState4(0);
|
|
5127
|
-
|
|
5758
|
+
useEffect6(() => {
|
|
5128
5759
|
const timer = setInterval(() => {
|
|
5129
5760
|
setFrame((prev) => (prev + 1) % spinnerFrames.length);
|
|
5130
5761
|
}, interval);
|
|
@@ -5217,7 +5848,7 @@ var HealthCheck = ({ name, ok, details }) => /* @__PURE__ */ jsxs14(Box14, { fle
|
|
|
5217
5848
|
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
5218
5849
|
var ProgressScreen = ({ title, lines, variantName }) => {
|
|
5219
5850
|
const [elapsedSeconds, setElapsedSeconds] = useState5(0);
|
|
5220
|
-
|
|
5851
|
+
useEffect7(() => {
|
|
5221
5852
|
const start = Date.now();
|
|
5222
5853
|
const timer = setInterval(() => {
|
|
5223
5854
|
setElapsedSeconds(Math.floor((Date.now() - start) / 1e3));
|
|
@@ -5433,13 +6064,21 @@ var VariantActionsScreen = ({
|
|
|
5433
6064
|
onTweak,
|
|
5434
6065
|
onRemove,
|
|
5435
6066
|
onConfigureModels,
|
|
6067
|
+
onToggleTeamMode,
|
|
5436
6068
|
onBack
|
|
5437
6069
|
}) => {
|
|
5438
6070
|
const [selectedIndex, setSelectedIndex] = useState8(0);
|
|
5439
6071
|
const requiresModelMapping = meta.provider && MODEL_MAPPING_PROVIDERS.includes(meta.provider);
|
|
6072
|
+
const teamModeAction = onToggleTeamMode ? meta.teamModeEnabled ? { value: "team-mode", label: "Disable Team Mode", description: "Remove multi-agent task tools" } : {
|
|
6073
|
+
value: "team-mode",
|
|
6074
|
+
label: "Enable Team Mode",
|
|
6075
|
+
description: "Add multi-agent task tools",
|
|
6076
|
+
icon: "star"
|
|
6077
|
+
} : null;
|
|
5440
6078
|
const actions = [
|
|
5441
6079
|
{ value: "update", label: "Update", description: "Re-sync binary + patches" },
|
|
5442
6080
|
...requiresModelMapping && onConfigureModels ? [{ value: "models", label: "Configure Models", description: "Edit Opus/Sonnet/Haiku mapping" }] : [],
|
|
6081
|
+
...teamModeAction ? [teamModeAction] : [],
|
|
5443
6082
|
{ value: "tweak", label: "Customize", description: "Open tweakcc" },
|
|
5444
6083
|
{ value: "remove", label: "Remove", description: "Delete variant", icon: "exit" },
|
|
5445
6084
|
{ value: "back", label: "Back", icon: "back" }
|
|
@@ -5447,6 +6086,7 @@ var VariantActionsScreen = ({
|
|
|
5447
6086
|
const handleSelect = (value) => {
|
|
5448
6087
|
if (value === "update") onUpdate();
|
|
5449
6088
|
if (value === "models" && onConfigureModels) onConfigureModels();
|
|
6089
|
+
if (value === "team-mode" && onToggleTeamMode) onToggleTeamMode();
|
|
5450
6090
|
if (value === "tweak") onTweak();
|
|
5451
6091
|
if (value === "remove") onRemove();
|
|
5452
6092
|
if (value === "back") onBack();
|
|
@@ -5457,7 +6097,8 @@ var VariantActionsScreen = ({
|
|
|
5457
6097
|
/* @__PURE__ */ jsx18(SummaryRow, { label: "Install", value: "NPM (cli.js)" }),
|
|
5458
6098
|
/* @__PURE__ */ jsx18(SummaryRow, { label: "Binary", value: meta.binaryPath }),
|
|
5459
6099
|
/* @__PURE__ */ jsx18(SummaryRow, { label: "Config", value: meta.configDir }),
|
|
5460
|
-
/* @__PURE__ */ jsx18(SummaryRow, { label: "Wrapper", value: meta.wrapperPath })
|
|
6100
|
+
/* @__PURE__ */ jsx18(SummaryRow, { label: "Wrapper", value: meta.wrapperPath }),
|
|
6101
|
+
/* @__PURE__ */ jsx18(SummaryRow, { label: "Team Mode", value: meta.teamModeEnabled ? "Enabled" : "Disabled" })
|
|
5461
6102
|
] }),
|
|
5462
6103
|
/* @__PURE__ */ jsx18(Box18, { marginY: 1, children: /* @__PURE__ */ jsx18(
|
|
5463
6104
|
SelectMenu,
|
|
@@ -5937,8 +6578,14 @@ var FeedbackScreen = ({ onBack }) => {
|
|
|
5937
6578
|
import { useState as useState12 } from "react";
|
|
5938
6579
|
import { Box as Box24, Text as Text22, useInput as useInput12 } from "ink";
|
|
5939
6580
|
import { jsx as jsx24, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
5940
|
-
var YesNoSelect = ({
|
|
5941
|
-
|
|
6581
|
+
var YesNoSelect = ({
|
|
6582
|
+
title,
|
|
6583
|
+
onSelect,
|
|
6584
|
+
yesLabel = "Yes",
|
|
6585
|
+
noLabel = "No",
|
|
6586
|
+
defaultNo = false
|
|
6587
|
+
}) => {
|
|
6588
|
+
const [selectedIndex, setSelectedIndex] = useState12(defaultNo ? 1 : 0);
|
|
5942
6589
|
useInput12((input, key) => {
|
|
5943
6590
|
if (key.upArrow || key.downArrow) {
|
|
5944
6591
|
setSelectedIndex((prev) => prev === 0 ? 1 : 0);
|
|
@@ -6107,12 +6754,12 @@ var App = ({
|
|
|
6107
6754
|
}
|
|
6108
6755
|
}
|
|
6109
6756
|
});
|
|
6110
|
-
|
|
6757
|
+
useEffect8(() => {
|
|
6111
6758
|
if (screen === "manage") {
|
|
6112
6759
|
setVariants(core.listVariants(rootDir));
|
|
6113
6760
|
}
|
|
6114
6761
|
}, [screen, rootDir, core]);
|
|
6115
|
-
|
|
6762
|
+
useEffect8(() => {
|
|
6116
6763
|
if (screen !== "doctor") return;
|
|
6117
6764
|
setDoctorReport(core.doctor(rootDir, binDir));
|
|
6118
6765
|
}, [screen, rootDir, binDir, core]);
|
|
@@ -6180,7 +6827,7 @@ var App = ({
|
|
|
6180
6827
|
setScreen,
|
|
6181
6828
|
onComplete: handleOperationComplete
|
|
6182
6829
|
});
|
|
6183
|
-
|
|
6830
|
+
useEffect8(() => {
|
|
6184
6831
|
if (screen !== "manage-tweak") return;
|
|
6185
6832
|
if (!selectedVariant) return;
|
|
6186
6833
|
setDoneLines([`To customize ${selectedVariant.name}, run:`]);
|
|
@@ -6202,6 +6849,17 @@ var App = ({
|
|
|
6202
6849
|
setScreen,
|
|
6203
6850
|
onComplete: handleOperationComplete
|
|
6204
6851
|
});
|
|
6852
|
+
useTeamModeToggle({
|
|
6853
|
+
screen,
|
|
6854
|
+
selectedVariant,
|
|
6855
|
+
rootDir,
|
|
6856
|
+
binDir,
|
|
6857
|
+
core,
|
|
6858
|
+
setProgressLines,
|
|
6859
|
+
setScreen,
|
|
6860
|
+
onComplete: handleOperationComplete,
|
|
6861
|
+
refreshVariants: () => setVariants(core.listVariants(rootDir))
|
|
6862
|
+
});
|
|
6205
6863
|
useUpdateAll({
|
|
6206
6864
|
screen,
|
|
6207
6865
|
rootDir,
|
|
@@ -6232,7 +6890,7 @@ var App = ({
|
|
|
6232
6890
|
setCompletionNextSteps([]);
|
|
6233
6891
|
setCompletionHelp([]);
|
|
6234
6892
|
};
|
|
6235
|
-
|
|
6893
|
+
useEffect8(() => {
|
|
6236
6894
|
if (screen === "exit") {
|
|
6237
6895
|
const timer = setTimeout(() => exit(), 100);
|
|
6238
6896
|
return () => clearTimeout(timer);
|
|
@@ -6274,7 +6932,7 @@ var App = ({
|
|
|
6274
6932
|
const defaults = providerDefaults(value);
|
|
6275
6933
|
const keyDefaults = value === "zai" ? resolveZaiApiKey() : { value: "", detectedFrom: null, skipPrompt: false };
|
|
6276
6934
|
setProviderKey(value);
|
|
6277
|
-
setName(value);
|
|
6935
|
+
setName(value === "mirror" ? "mclaude" : value);
|
|
6278
6936
|
setBaseUrl(selected?.baseUrl || "");
|
|
6279
6937
|
setApiKey(keyDefaults.value);
|
|
6280
6938
|
setApiKeyDetectedFrom(keyDefaults.detectedFrom);
|
|
@@ -6395,7 +7053,7 @@ var App = ({
|
|
|
6395
7053
|
const defaults = providerDefaults(value);
|
|
6396
7054
|
const keyDefaults = value === "zai" ? resolveZaiApiKey() : { value: "", detectedFrom: null, skipPrompt: false };
|
|
6397
7055
|
setProviderKey(value);
|
|
6398
|
-
setName(value);
|
|
7056
|
+
setName(value === "mirror" ? "mclaude" : value);
|
|
6399
7057
|
setBaseUrl(selected?.baseUrl || "");
|
|
6400
7058
|
setApiKey(keyDefaults.value);
|
|
6401
7059
|
setApiKeyDetectedFrom(keyDefaults.detectedFrom);
|
|
@@ -6452,7 +7110,12 @@ var App = ({
|
|
|
6452
7110
|
] });
|
|
6453
7111
|
}
|
|
6454
7112
|
if (screen === "create-name") {
|
|
6455
|
-
const
|
|
7113
|
+
const getNextScreen = () => {
|
|
7114
|
+
if (providerKey === "ccrouter") return "create-ccrouter-url";
|
|
7115
|
+
if (providerKey === "mirror") return "create-skill-install";
|
|
7116
|
+
return "create-base-url";
|
|
7117
|
+
};
|
|
7118
|
+
const nextScreen = getNextScreen();
|
|
6456
7119
|
return /* @__PURE__ */ jsxs25(Frame, { children: [
|
|
6457
7120
|
/* @__PURE__ */ jsx25(Header, { title: "Variant Name", subtitle: "This becomes the CLI command name" }),
|
|
6458
7121
|
/* @__PURE__ */ jsx25(Divider, {}),
|
|
@@ -6642,6 +7305,7 @@ var App = ({
|
|
|
6642
7305
|
YesNoSelect,
|
|
6643
7306
|
{
|
|
6644
7307
|
title: "Add custom env entries?",
|
|
7308
|
+
defaultNo: true,
|
|
6645
7309
|
onSelect: (value) => {
|
|
6646
7310
|
if (value) {
|
|
6647
7311
|
setScreen("create-env-add");
|
|
@@ -6730,12 +7394,12 @@ var App = ({
|
|
|
6730
7394
|
variants: variants.map((v) => ({
|
|
6731
7395
|
name: v.name,
|
|
6732
7396
|
provider: v.meta?.provider,
|
|
6733
|
-
wrapperPath:
|
|
7397
|
+
wrapperPath: path24.join(binDir, v.name)
|
|
6734
7398
|
})),
|
|
6735
7399
|
onSelect: (variantName) => {
|
|
6736
7400
|
const entry = variants.find((item) => item.name === variantName);
|
|
6737
7401
|
if (!entry || !entry.meta) return;
|
|
6738
|
-
setSelectedVariant({ ...entry.meta, wrapperPath:
|
|
7402
|
+
setSelectedVariant({ ...entry.meta, wrapperPath: path24.join(binDir, entry.name) });
|
|
6739
7403
|
setScreen("manage-actions");
|
|
6740
7404
|
},
|
|
6741
7405
|
onBack: () => setScreen("home")
|
|
@@ -6754,6 +7418,7 @@ var App = ({
|
|
|
6754
7418
|
setModelHaiku("");
|
|
6755
7419
|
setScreen("manage-models");
|
|
6756
7420
|
},
|
|
7421
|
+
onToggleTeamMode: () => setScreen("manage-team-mode"),
|
|
6757
7422
|
onTweak: () => setScreen("manage-tweak"),
|
|
6758
7423
|
onRemove: () => setScreen("manage-remove"),
|
|
6759
7424
|
onBack: () => setScreen("manage")
|
|
@@ -6779,6 +7444,26 @@ var App = ({
|
|
|
6779
7444
|
}
|
|
6780
7445
|
);
|
|
6781
7446
|
}
|
|
7447
|
+
if (screen === "manage-team-mode" && selectedVariant) {
|
|
7448
|
+
const action = selectedVariant.teamModeEnabled ? "Disabling" : "Enabling";
|
|
7449
|
+
return /* @__PURE__ */ jsx25(ProgressScreen, { title: `${action} team mode`, lines: progressLines });
|
|
7450
|
+
}
|
|
7451
|
+
if (screen === "manage-team-mode-done") {
|
|
7452
|
+
return /* @__PURE__ */ jsx25(
|
|
7453
|
+
CompletionScreen,
|
|
7454
|
+
{
|
|
7455
|
+
title: "Team Mode",
|
|
7456
|
+
lines: doneLines,
|
|
7457
|
+
summary: completionSummary,
|
|
7458
|
+
nextSteps: completionNextSteps,
|
|
7459
|
+
help: completionHelp,
|
|
7460
|
+
onDone: (value) => {
|
|
7461
|
+
if (value === "home") setScreen("home");
|
|
7462
|
+
else setScreen("exit");
|
|
7463
|
+
}
|
|
7464
|
+
}
|
|
7465
|
+
);
|
|
7466
|
+
}
|
|
6782
7467
|
if (screen === "manage-tweak" && selectedVariant) {
|
|
6783
7468
|
return /* @__PURE__ */ jsx25(ProgressScreen, { title: "Launching tweakcc", lines: progressLines });
|
|
6784
7469
|
}
|