ccg-workflow 2.1.14 → 2.1.16

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 CHANGED
@@ -380,4 +380,4 @@ MIT
380
380
 
381
381
  ---
382
382
 
383
- v2.1.11 | [Issues](https://github.com/fengshao1227/ccg-workflow/issues) | [Contributing](./CONTRIBUTING.md)
383
+ v2.1.16 | [Issues](https://github.com/fengshao1227/ccg-workflow/issues) | [Contributing](./CONTRIBUTING.md)
package/README.zh-CN.md CHANGED
@@ -377,4 +377,4 @@ MIT
377
377
 
378
378
  ---
379
379
 
380
- v2.1.11 | [Issues](https://github.com/fengshao1227/ccg-workflow/issues) | [参与贡献](./CONTRIBUTING.md)
380
+ v2.1.16 | [Issues](https://github.com/fengshao1227/ccg-workflow/issues) | [参与贡献](./CONTRIBUTING.md)
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import cac from 'cac';
3
3
  import ansis from 'ansis';
4
- import { z as diagnoseMcpConfig, A as isWindows, B as readClaudeCodeConfig, C as fixWindowsMcpConfig, D as writeClaudeCodeConfig, r as readCcgConfig, b as initI18n, a as i18n, s as showMainMenu, i as init, E as configMcp, F as version } from './shared/ccg-workflow.BDGb5Nln.mjs';
4
+ import { z as diagnoseMcpConfig, A as isWindows, B as readClaudeCodeConfig, C as fixWindowsMcpConfig, D as writeClaudeCodeConfig, r as readCcgConfig, b as initI18n, a as i18n, s as showMainMenu, i as init, E as configMcp, F as version } from './shared/ccg-workflow.CewMlBCj.mjs';
5
5
  import 'inquirer';
6
6
  import 'ora';
7
7
  import 'node:child_process';
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { c as changeLanguage, x as checkForUpdates, y as compareVersions, d as createDefaultConfig, e as createDefaultRouting, g as getCcgDir, f as getConfigPath, t as getCurrentVersion, v as getLatestVersion, j as getWorkflowById, h as getWorkflowConfigs, a as i18n, i as init, b as initI18n, l as installAceTool, m as installAceToolRs, k as installWorkflows, p as migrateToV1_4_0, q as needsMigration, r as readCcgConfig, s as showMainMenu, o as uninstallAceTool, n as uninstallWorkflows, u as update, w as writeCcgConfig } from './shared/ccg-workflow.BDGb5Nln.mjs';
1
+ export { c as changeLanguage, x as checkForUpdates, y as compareVersions, d as createDefaultConfig, e as createDefaultRouting, g as getCcgDir, f as getConfigPath, t as getCurrentVersion, v as getLatestVersion, j as getWorkflowById, h as getWorkflowConfigs, a as i18n, i as init, b as initI18n, l as installAceTool, m as installAceToolRs, k as installWorkflows, p as migrateToV1_4_0, q as needsMigration, r as readCcgConfig, s as showMainMenu, o as uninstallAceTool, n as uninstallWorkflows, u as update, w as writeCcgConfig } from './shared/ccg-workflow.CewMlBCj.mjs';
2
2
  import 'ansis';
3
3
  import 'inquirer';
4
4
  import 'ora';
@@ -10,7 +10,7 @@ import fs from 'fs-extra';
10
10
  import { parse, stringify } from 'smol-toml';
11
11
  import i18next from 'i18next';
12
12
 
13
- const version = "2.1.14";
13
+ const version = "2.1.16";
14
14
 
15
15
  function cmd(id, order, category, name, nameEn, description, descriptionEn, cmdOverride) {
16
16
  return {
@@ -135,8 +135,22 @@ function injectConfigVariables(content, config) {
135
135
  processed = processed.replace(/\{\{ROUTING_MODE\}\}/g, routingMode);
136
136
  const geminiModel = routing.geminiModel || "gemini-3.1-pro-preview";
137
137
  const usesGemini = frontendPrimary === "gemini" || backendPrimary === "gemini";
138
- const geminiModelFlag = usesGemini ? `--gemini-model ${geminiModel} ` : "";
139
- processed = processed.replace(/\{\{GEMINI_MODEL_FLAG\}\}/g, geminiModelFlag);
138
+ if (!usesGemini) {
139
+ processed = processed.replace(/\{\{GEMINI_MODEL_FLAG\}\}/g, "");
140
+ } else {
141
+ const geminiModelFlagValue = `--gemini-model ${geminiModel} `;
142
+ const hardCodedBackendRe = /--backend\s+([a-z0-9-]+)(?:\s|$)/;
143
+ processed = processed.split("\n").map((line) => {
144
+ if (!line.includes("{{GEMINI_MODEL_FLAG}}")) {
145
+ return line;
146
+ }
147
+ const m = line.match(hardCodedBackendRe);
148
+ if (m && m[1] !== "gemini") {
149
+ return line.replace(/\{\{GEMINI_MODEL_FLAG\}\}/g, "");
150
+ }
151
+ return line.replace(/\{\{GEMINI_MODEL_FLAG\}\}/g, geminiModelFlagValue);
152
+ }).join("\n");
153
+ }
140
154
  const liteModeFlag = config.liteMode ? "--lite " : "";
141
155
  processed = processed.replace(/\{\{LITE_MODE_FLAG\}\}/g, liteModeFlag);
142
156
  const mcpProvider = config.mcpProvider || "ace-tool";
@@ -1781,15 +1795,31 @@ const zhCN = {
1781
1795
  collaboration: "\u534F\u4F5C\u6A21\u5F0F:",
1782
1796
  workflows: "\u5DE5\u4F5C\u6D41:",
1783
1797
  selected: "\u4E2A\u5DF2\u9009\u62E9",
1798
+ apiProvider: "API \u63D0\u4F9B\u65B9",
1784
1799
  modelRouting: "\u6A21\u578B\u8DEF\u7531",
1800
+ geminiModel: "Gemini \u578B\u53F7",
1785
1801
  commandCount: "\u547D\u4EE4\u6570\u91CF",
1786
1802
  mcpTool: "MCP \u5DE5\u5177",
1787
1803
  webUI: "Web UI",
1804
+ apiSelfManaged: "\u81EA\u884C\u7BA1\u7406\uFF08CCG \u4E0D\u4ECB\u5165\uFF09",
1788
1805
  pendingConfig: "\u5F85\u914D\u7F6E",
1789
1806
  skipped: "\u8DF3\u8FC7",
1790
1807
  enabled: "\u542F\u7528",
1791
1808
  disabled: "\u7981\u7528"
1792
1809
  },
1810
+ nav: {
1811
+ back: "\u8FD4\u56DE\u4E0A\u4E00\u6B65",
1812
+ cancel: "\u53D6\u6D88\u5B89\u88C5"
1813
+ },
1814
+ summaryMenu: {
1815
+ prompt: "\u786E\u8BA4\u914D\u7F6E\uFF1F",
1816
+ confirm: "\u786E\u8BA4\u5B89\u88C5",
1817
+ editApi: "\u6539 API \u914D\u7F6E",
1818
+ editModel: "\u6539\u6A21\u578B\u8DEF\u7531",
1819
+ editMcp: "\u6539 MCP \u5DE5\u5177",
1820
+ editPerf: "\u6539\u6027\u80FD\u6A21\u5F0F",
1821
+ cancel: "\u53D6\u6D88\u5B89\u88C5"
1822
+ },
1793
1823
  mcp: {
1794
1824
  title: "MCP \u4EE3\u7801\u68C0\u7D22\u5DE5\u5177\u914D\u7F6E",
1795
1825
  selectProvider: "\u9009\u62E9\u4EE3\u7801\u68C0\u7D22 MCP \u5DE5\u5177",
@@ -1837,7 +1867,9 @@ const zhCN = {
1837
1867
  cwConfiguring: "\u6B63\u5728\u914D\u7F6E ContextWeaver MCP...",
1838
1868
  cwFailed: "ContextWeaver MCP \u914D\u7F6E\u5931\u8D25",
1839
1869
  cwConfigFile: "\u914D\u7F6E\u6587\u4EF6",
1840
- cwIndexHint: "\u9996\u6B21\u4F7F\u7528\u9700\u8981\u7D22\u5F15\u4EE3\u7801\u5E93\uFF1A"
1870
+ cwIndexHint: "\u9996\u6B21\u4F7F\u7528\u9700\u8981\u7D22\u5F15\u4EE3\u7801\u5E93\uFF1A",
1871
+ gatePrompt: "\u914D\u7F6E MCP \u5DE5\u5177\uFF1F",
1872
+ gateContinue: "\u5F00\u59CB\u914D\u7F6E"
1841
1873
  },
1842
1874
  api: {
1843
1875
  title: "Claude Code API \u914D\u7F6E",
@@ -1847,6 +1879,8 @@ const zhCN = {
1847
1879
  thirdPartyOption: "\u7B2C\u4E09\u65B9 API \u4EE3\u7406\uFF08\u81EA\u5B9A\u4E49 URL + Key\uFF09",
1848
1880
  sponsor302AI: "302.AI\uFF08\u6309\u7528\u91CF\u4ED8\u8D39\u7684\u4F01\u4E1A\u7EA7 AI \u8D44\u6E90\u5E73\u53F0\uFF09",
1849
1881
  sponsor302AIGetKey: "\u83B7\u53D6 API Key",
1882
+ skipOption: "\u8DF3\u8FC7 \u2014 \u6211\u5DF2\u901A\u8FC7 cc-switch / \u5176\u4ED6\u5DE5\u5177\u81EA\u884C\u914D\u7F6E",
1883
+ skipNoticeTitle: "API \u914D\u7F6E\u5DF2\u8DF3\u8FC7\uFF0CCCG \u4E0D\u4F1A\u4FEE\u6539 settings.json \u4E2D\u7684 ANTHROPIC_*",
1850
1884
  urlPrompt: "API URL",
1851
1885
  urlRequired: "\u5FC5\u586B",
1852
1886
  keyPrompt: "API Key",
@@ -2257,15 +2291,31 @@ const en = {
2257
2291
  collaboration: "Collaboration:",
2258
2292
  workflows: "Workflows:",
2259
2293
  selected: "selected",
2294
+ apiProvider: "API Provider",
2260
2295
  modelRouting: "Model Routing",
2296
+ geminiModel: "Gemini Model",
2261
2297
  commandCount: "Commands",
2262
2298
  mcpTool: "MCP Tool",
2263
2299
  webUI: "Web UI",
2300
+ apiSelfManaged: "self-managed (CCG does not touch)",
2264
2301
  pendingConfig: "pending",
2265
2302
  skipped: "skipped",
2266
2303
  enabled: "Enabled",
2267
2304
  disabled: "Disabled"
2268
2305
  },
2306
+ nav: {
2307
+ back: "Back to previous step",
2308
+ cancel: "Cancel installation"
2309
+ },
2310
+ summaryMenu: {
2311
+ prompt: "Confirm configuration?",
2312
+ confirm: "Confirm and install",
2313
+ editApi: "Edit API configuration",
2314
+ editModel: "Edit model routing",
2315
+ editMcp: "Edit MCP tools",
2316
+ editPerf: "Edit performance mode",
2317
+ cancel: "Cancel installation"
2318
+ },
2269
2319
  mcp: {
2270
2320
  title: "MCP Code Retrieval Tool",
2271
2321
  selectProvider: "Select code retrieval MCP tool",
@@ -2313,7 +2363,9 @@ const en = {
2313
2363
  cwConfiguring: "Configuring ContextWeaver MCP...",
2314
2364
  cwFailed: "ContextWeaver MCP configuration failed",
2315
2365
  cwConfigFile: "Config file",
2316
- cwIndexHint: "First use requires indexing your codebase:"
2366
+ cwIndexHint: "First use requires indexing your codebase:",
2367
+ gatePrompt: "Configure MCP tools?",
2368
+ gateContinue: "Start configuration"
2317
2369
  },
2318
2370
  api: {
2319
2371
  title: "Claude Code API Configuration",
@@ -2323,6 +2375,8 @@ const en = {
2323
2375
  thirdPartyOption: "Third-party API proxy (custom URL + Key)",
2324
2376
  sponsor302AI: "302.AI (Pay-as-you-go Enterprise AI Resource Hub)",
2325
2377
  sponsor302AIGetKey: "Get API Key",
2378
+ skipOption: "Skip \u2014 I've already configured API via cc-switch / other tools",
2379
+ skipNoticeTitle: "API configuration skipped \u2014 CCG will not touch ANTHROPIC_* in settings.json",
2326
2380
  urlPrompt: "API URL",
2327
2381
  urlRequired: "Required",
2328
2382
  keyPrompt: "API Key",
@@ -2889,6 +2943,22 @@ For example, when using the \`fastapi\` library to encapsulate an API endpoint,
2889
2943
  await fs.ensureDir(rulesDir);
2890
2944
  await fs.writeFile(rulePath, prompt, "utf-8");
2891
2945
  }
2946
+ const BACK_SENTINEL = "__ccg_back__";
2947
+ const CANCEL_SENTINEL = "__ccg_cancel__";
2948
+ function navSentinels(canGoBack) {
2949
+ const items = [new inquirer.Separator()];
2950
+ if (canGoBack) {
2951
+ items.push({
2952
+ name: `${ansis.cyan("\u2190")} ${i18n.t("init:nav.back")}`,
2953
+ value: BACK_SENTINEL
2954
+ });
2955
+ }
2956
+ items.push({
2957
+ name: `${ansis.red("\xD7")} ${i18n.t("init:nav.cancel")}`,
2958
+ value: CANCEL_SENTINEL
2959
+ });
2960
+ return items;
2961
+ }
2892
2962
  async function installGrokSearchMcp(keys) {
2893
2963
  const env = {};
2894
2964
  if (keys.tavilyKey)
@@ -2965,273 +3035,444 @@ async function init(options = {}) {
2965
3035
  let grokApiKey = "";
2966
3036
  let apiUrl = "";
2967
3037
  let apiKey = "";
3038
+ if (options.skipPrompt) {
3039
+ const existingConfig = await readCcgConfig();
3040
+ if (existingConfig?.performance?.liteMode !== void 0) {
3041
+ liteMode = existingConfig.performance.liteMode;
3042
+ }
3043
+ if (existingConfig?.performance?.skipImpeccable !== void 0) {
3044
+ skipImpeccable = existingConfig.performance.skipImpeccable;
3045
+ }
3046
+ if (options.skipMcp) {
3047
+ mcpProvider = existingConfig?.mcp?.provider || "skip";
3048
+ }
3049
+ }
2968
3050
  if (!options.skipPrompt) {
2969
- console.log();
2970
- console.log(ansis.cyan.bold(` \u{1F511} Step 1/4 \u2014 ${i18n.t("init:api.title")}`));
2971
- console.log();
2972
- const { apiProvider } = await inquirer.prompt([{
2973
- type: "list",
2974
- name: "apiProvider",
2975
- message: i18n.t("init:api.providerPrompt"),
2976
- choices: [
2977
- { name: `${ansis.green("\u25CF")} ${i18n.t("init:api.officialOption")}`, value: "official" },
2978
- { name: `${ansis.cyan("\u25CF")} ${i18n.t("init:api.thirdPartyOption")}`, value: "thirdparty" },
2979
- { name: `${ansis.yellow("\u2605")} ${i18n.t("init:api.sponsor302AI")} ${ansis.gray("\u2014 https://share.302.ai/oUDqQ6")}`, value: "302ai" }
2980
- ]
2981
- }]);
2982
- if (apiProvider === "302ai") {
2983
- apiUrl = "https://api.302.ai/cc";
3051
+ const existingConfig = await readCcgConfig();
3052
+ if (existingConfig?.routing) {
3053
+ const ef = existingConfig.routing.frontend?.primary;
3054
+ const eb = existingConfig.routing.backend?.primary;
3055
+ if (ef)
3056
+ frontendModels = [ef];
3057
+ if (eb)
3058
+ backendModels = [eb];
3059
+ if (existingConfig.routing.geminiModel)
3060
+ geminiModel = existingConfig.routing.geminiModel;
3061
+ }
3062
+ if (existingConfig?.performance?.liteMode !== void 0) {
3063
+ liteMode = existingConfig.performance.liteMode;
3064
+ }
3065
+ async function runApiStep(canGoBack) {
2984
3066
  console.log();
2985
- console.log(` ${ansis.yellow("\u2605")} ${i18n.t("init:api.sponsor302AIGetKey")}: ${ansis.cyan.underline("https://share.302.ai/oUDqQ6")}`);
3067
+ console.log(ansis.cyan.bold(` \u{1F511} Step 1/4 \u2014 ${i18n.t("init:api.title")}`));
2986
3068
  console.log();
2987
- const { key } = await inquirer.prompt([{
2988
- type: "password",
2989
- name: "key",
2990
- message: `302.AI API Key ${ansis.gray(`(${i18n.t("init:api.keyRequired")})`)}`,
2991
- mask: "*",
2992
- validate: (v) => v.trim() !== "" || i18n.t("init:api.enterKey")
3069
+ const { apiProvider } = await inquirer.prompt([{
3070
+ type: "list",
3071
+ name: "apiProvider",
3072
+ message: i18n.t("init:api.providerPrompt"),
3073
+ choices: [
3074
+ { name: `${ansis.green("\u25CF")} ${i18n.t("init:api.officialOption")}`, value: "official" },
3075
+ { name: `${ansis.cyan("\u25CF")} ${i18n.t("init:api.thirdPartyOption")}`, value: "thirdparty" },
3076
+ { name: `${ansis.yellow("\u2605")} ${i18n.t("init:api.sponsor302AI")} ${ansis.gray("\u2014 https://share.302.ai/oUDqQ6")}`, value: "302ai" },
3077
+ { name: `${ansis.gray("\u25CB")} ${i18n.t("init:api.skipOption")}`, value: "skip" },
3078
+ ...navSentinels(canGoBack)
3079
+ ]
2993
3080
  }]);
2994
- apiKey = key?.trim() || "";
2995
- } else if (apiProvider === "thirdparty") {
2996
- const apiAnswers = await inquirer.prompt([
2997
- {
2998
- type: "input",
2999
- name: "url",
3000
- message: `API URL ${ansis.gray(`(${i18n.t("init:api.urlRequired")})`)}`,
3001
- validate: (v) => v.trim() !== "" || i18n.t("init:api.enterUrl")
3002
- },
3003
- {
3081
+ if (apiProvider === BACK_SENTINEL)
3082
+ return "back";
3083
+ if (apiProvider === CANCEL_SENTINEL)
3084
+ return "cancel";
3085
+ apiUrl = "";
3086
+ apiKey = "";
3087
+ if (apiProvider === "302ai") {
3088
+ apiUrl = "https://api.302.ai/cc";
3089
+ console.log();
3090
+ console.log(` ${ansis.yellow("\u2605")} ${i18n.t("init:api.sponsor302AIGetKey")}: ${ansis.cyan.underline("https://share.302.ai/oUDqQ6")}`);
3091
+ console.log();
3092
+ const { key } = await inquirer.prompt([{
3004
3093
  type: "password",
3005
3094
  name: "key",
3006
- message: `API Key ${ansis.gray(`(${i18n.t("init:api.keyRequired")})`)}`,
3095
+ message: `302.AI API Key ${ansis.gray(`(${i18n.t("init:api.keyRequired")})`)}`,
3007
3096
  mask: "*",
3008
3097
  validate: (v) => v.trim() !== "" || i18n.t("init:api.enterKey")
3009
- }
3010
- ]);
3011
- apiUrl = apiAnswers.url?.trim() || "";
3012
- apiKey = apiAnswers.key?.trim() || "";
3098
+ }]);
3099
+ apiKey = key?.trim() || "";
3100
+ } else if (apiProvider === "thirdparty") {
3101
+ const apiAnswers = await inquirer.prompt([
3102
+ {
3103
+ type: "input",
3104
+ name: "url",
3105
+ message: `API URL ${ansis.gray(`(${i18n.t("init:api.urlRequired")})`)}`,
3106
+ validate: (v) => v.trim() !== "" || i18n.t("init:api.enterUrl")
3107
+ },
3108
+ {
3109
+ type: "password",
3110
+ name: "key",
3111
+ message: `API Key ${ansis.gray(`(${i18n.t("init:api.keyRequired")})`)}`,
3112
+ mask: "*",
3113
+ validate: (v) => v.trim() !== "" || i18n.t("init:api.enterKey")
3114
+ }
3115
+ ]);
3116
+ apiUrl = apiAnswers.url?.trim() || "";
3117
+ apiKey = apiAnswers.key?.trim() || "";
3118
+ } else if (apiProvider === "skip") {
3119
+ console.log();
3120
+ console.log(` ${ansis.gray("\u25CB")} ${i18n.t("init:api.skipNoticeTitle")}`);
3121
+ }
3122
+ return "next";
3013
3123
  }
3014
- }
3015
- if (!options.skipPrompt) {
3016
- const existingConfig = await readCcgConfig();
3017
- console.log();
3018
- console.log(ansis.cyan.bold(` \u{1F9E0} Step 2/4 \u2014 ${i18n.t("init:model.title")}`));
3019
- console.log();
3020
- const { selectedFrontend } = await inquirer.prompt([{
3021
- type: "list",
3022
- name: "selectedFrontend",
3023
- message: i18n.t("init:model.selectFrontend"),
3024
- choices: [
3025
- { name: `Gemini ${ansis.green(`(${i18n.t("init:model.recommended")})`)}`, value: "gemini" },
3026
- { name: "Codex", value: "codex" }
3027
- ],
3028
- default: existingConfig?.routing?.frontend?.primary || "gemini"
3029
- }]);
3030
- const { selectedBackend } = await inquirer.prompt([{
3031
- type: "list",
3032
- name: "selectedBackend",
3033
- message: i18n.t("init:model.selectBackend"),
3034
- choices: [
3035
- { name: "Gemini", value: "gemini" },
3036
- { name: `Codex ${ansis.green(`(${i18n.t("init:model.recommended")})`)}`, value: "codex" }
3037
- ],
3038
- default: existingConfig?.routing?.backend?.primary || "codex"
3039
- }]);
3040
- frontendModels = [selectedFrontend];
3041
- backendModels = [selectedBackend];
3042
- if (selectedFrontend === "gemini" || selectedBackend === "gemini") {
3043
- const { selectedGeminiModel } = await inquirer.prompt([{
3124
+ async function runModelStep(canGoBack) {
3125
+ console.log();
3126
+ console.log(ansis.cyan.bold(` \u{1F9E0} Step 2/4 \u2014 ${i18n.t("init:model.title")}`));
3127
+ console.log();
3128
+ const { selectedFrontend } = await inquirer.prompt([{
3044
3129
  type: "list",
3045
- name: "selectedGeminiModel",
3046
- message: i18n.t("init:model.selectGeminiModel"),
3130
+ name: "selectedFrontend",
3131
+ message: i18n.t("init:model.selectFrontend"),
3047
3132
  choices: [
3048
- { name: `gemini-3.1-pro-preview ${ansis.green(`(${i18n.t("init:model.recommended")})`)}`, value: "gemini-3.1-pro-preview" },
3049
- { name: "gemini-2.5-flash", value: "gemini-2.5-flash" },
3050
- { name: `${i18n.t("init:model.custom")}`, value: "custom" }
3133
+ { name: `Gemini ${ansis.green(`(${i18n.t("init:model.recommended")})`)}`, value: "gemini" },
3134
+ { name: "Codex", value: "codex" },
3135
+ ...navSentinels(canGoBack)
3051
3136
  ],
3052
- default: existingConfig?.routing?.geminiModel || "gemini-3.1-pro-preview"
3137
+ default: frontendModels[0] || "gemini"
3053
3138
  }]);
3054
- if (selectedGeminiModel === "custom") {
3055
- const { customModel } = await inquirer.prompt([{
3056
- type: "input",
3057
- name: "customModel",
3058
- message: i18n.t("init:model.enterCustomModel"),
3059
- validate: (v) => v.trim() !== "" || i18n.t("init:model.enterCustomModel")
3139
+ if (selectedFrontend === BACK_SENTINEL)
3140
+ return "back";
3141
+ if (selectedFrontend === CANCEL_SENTINEL)
3142
+ return "cancel";
3143
+ const { selectedBackend } = await inquirer.prompt([{
3144
+ type: "list",
3145
+ name: "selectedBackend",
3146
+ message: i18n.t("init:model.selectBackend"),
3147
+ choices: [
3148
+ { name: "Gemini", value: "gemini" },
3149
+ { name: `Codex ${ansis.green(`(${i18n.t("init:model.recommended")})`)}`, value: "codex" }
3150
+ ],
3151
+ default: backendModels[0] || "codex"
3152
+ }]);
3153
+ frontendModels = [selectedFrontend];
3154
+ backendModels = [selectedBackend];
3155
+ if (selectedFrontend === "gemini" || selectedBackend === "gemini") {
3156
+ const { selectedGeminiModel } = await inquirer.prompt([{
3157
+ type: "list",
3158
+ name: "selectedGeminiModel",
3159
+ message: i18n.t("init:model.selectGeminiModel"),
3160
+ choices: [
3161
+ { name: `gemini-3.1-pro-preview ${ansis.green(`(${i18n.t("init:model.recommended")})`)}`, value: "gemini-3.1-pro-preview" },
3162
+ { name: "gemini-2.5-flash", value: "gemini-2.5-flash" },
3163
+ { name: `${i18n.t("init:model.custom")}`, value: "custom" }
3164
+ ],
3165
+ default: geminiModel || "gemini-3.1-pro-preview"
3060
3166
  }]);
3061
- geminiModel = customModel.trim();
3062
- } else {
3063
- geminiModel = selectedGeminiModel;
3064
- }
3065
- }
3066
- }
3067
- if (options.skipMcp) {
3068
- const existingConfig = await readCcgConfig();
3069
- mcpProvider = existingConfig?.mcp?.provider || "skip";
3070
- } else if (!options.skipPrompt) {
3071
- console.log();
3072
- console.log(ansis.cyan.bold(` \u{1F527} Step 3/4 \u2014 ${i18n.t("init:mcp.title")}`));
3073
- console.log();
3074
- const { selectedTools } = await inquirer.prompt([{
3075
- type: "checkbox",
3076
- name: "selectedTools",
3077
- message: i18n.t("init:mcp.selectTools"),
3078
- choices: [
3079
- {
3080
- name: `ace-tool ${ansis.green(`(${i18n.t("common:info")})`)} ${ansis.gray("\u2014 search_context \u4EE3\u7801\u68C0\u7D22")}`,
3081
- value: "ace-tool",
3082
- checked: true
3083
- },
3084
- {
3085
- name: `fast-context ${ansis.gray("\u2014 AI \u9A71\u52A8\u8BED\u4E49\u641C\u7D22")}`,
3086
- value: "fast-context"
3087
- },
3088
- {
3089
- name: `context7 ${ansis.green("(free)")} ${ansis.gray("\u2014 \u5E93\u6587\u6863\u67E5\u8BE2")}`,
3090
- value: "context7",
3091
- checked: true
3092
- },
3093
- {
3094
- name: `grok-search ${ansis.gray("\u2014 \u8054\u7F51\u641C\u7D22 (\u9700 API Key)")}`,
3095
- value: "grok-search"
3096
- },
3097
- {
3098
- name: `contextweaver ${ansis.gray("\u2014 \u7845\u57FA\u6D41\u52A8\u5D4C\u5165\u68C0\u7D22 (\u9700 API Key)")}`,
3099
- value: "contextweaver"
3167
+ if (selectedGeminiModel === "custom") {
3168
+ const { customModel } = await inquirer.prompt([{
3169
+ type: "input",
3170
+ name: "customModel",
3171
+ message: i18n.t("init:model.enterCustomModel"),
3172
+ default: geminiModel || "",
3173
+ validate: (v) => v.trim() !== "" || i18n.t("init:model.enterCustomModel")
3174
+ }]);
3175
+ geminiModel = customModel.trim();
3176
+ } else {
3177
+ geminiModel = selectedGeminiModel;
3100
3178
  }
3101
- ]
3102
- }]);
3103
- const hasAceTool = selectedTools.includes("ace-tool");
3104
- const hasFastContext = selectedTools.includes("fast-context");
3105
- const hasContextWeaver = selectedTools.includes("contextweaver");
3106
- wantFastContext = hasFastContext;
3107
- wantGrokSearch = selectedTools.includes("grok-search");
3108
- if (hasAceTool) {
3109
- mcpProvider = "ace-tool";
3110
- } else if (hasFastContext) {
3111
- mcpProvider = "fast-context";
3112
- } else if (hasContextWeaver) {
3113
- mcpProvider = "contextweaver";
3114
- } else {
3115
- mcpProvider = "skip";
3179
+ }
3180
+ return "next";
3116
3181
  }
3117
- if (hasAceTool) {
3118
- console.log();
3119
- console.log(ansis.cyan.bold(` \u{1F527} ace-tool MCP`));
3182
+ async function runMcpStep(canGoBack) {
3183
+ if (options.skipMcp) {
3184
+ mcpProvider = existingConfig?.mcp?.provider || "skip";
3185
+ return "next";
3186
+ }
3120
3187
  console.log();
3121
- console.log(` ${ansis.gray("\u2022")} ${ansis.cyan(i18n.t("init:mcp.officialService"))}: ${ansis.underline("https://augmentcode.com/")}`);
3122
- console.log(` ${ansis.gray("\u2022")} ${ansis.cyan(i18n.t("init:mcp.proxyService"))} ${ansis.yellow(`(${i18n.t("init:mcp.noSignup")})`)}: ${ansis.underline("https://acemcp.heroman.wtf/")}`);
3188
+ console.log(ansis.cyan.bold(` \u{1F527} Step 3/4 \u2014 ${i18n.t("init:mcp.title")}`));
3123
3189
  console.log();
3124
- const aceAnswers = await inquirer.prompt([
3125
- {
3126
- type: "input",
3127
- name: "baseUrl",
3128
- message: `Base URL ${ansis.gray(`(${i18n.t("init:mcp.baseUrlHint")})`)}`,
3129
- default: ""
3130
- },
3131
- {
3190
+ const { gate } = await inquirer.prompt([{
3191
+ type: "list",
3192
+ name: "gate",
3193
+ message: i18n.t("init:mcp.gatePrompt"),
3194
+ choices: [
3195
+ { name: `${ansis.green("\u25CF")} ${i18n.t("init:mcp.gateContinue")}`, value: "continue" },
3196
+ ...navSentinels(canGoBack)
3197
+ ]
3198
+ }]);
3199
+ if (gate === BACK_SENTINEL)
3200
+ return "back";
3201
+ if (gate === CANCEL_SENTINEL)
3202
+ return "cancel";
3203
+ aceToolBaseUrl = "";
3204
+ aceToolToken = "";
3205
+ fastContextApiKey = "";
3206
+ fastContextIncludeSnippets = false;
3207
+ contextWeaverApiKey = "";
3208
+ wantFastContext = false;
3209
+ wantGrokSearch = false;
3210
+ tavilyKey = "";
3211
+ firecrawlKey = "";
3212
+ grokApiUrl = "";
3213
+ grokApiKey = "";
3214
+ const { selectedTools } = await inquirer.prompt([{
3215
+ type: "checkbox",
3216
+ name: "selectedTools",
3217
+ message: i18n.t("init:mcp.selectTools"),
3218
+ choices: [
3219
+ {
3220
+ name: `ace-tool ${ansis.green(`(${i18n.t("common:info")})`)} ${ansis.gray("\u2014 search_context \u4EE3\u7801\u68C0\u7D22")}`,
3221
+ value: "ace-tool",
3222
+ checked: true
3223
+ },
3224
+ {
3225
+ name: `fast-context ${ansis.gray("\u2014 AI \u9A71\u52A8\u8BED\u4E49\u641C\u7D22")}`,
3226
+ value: "fast-context"
3227
+ },
3228
+ {
3229
+ name: `context7 ${ansis.green("(free)")} ${ansis.gray("\u2014 \u5E93\u6587\u6863\u67E5\u8BE2")}`,
3230
+ value: "context7",
3231
+ checked: true
3232
+ },
3233
+ {
3234
+ name: `grok-search ${ansis.gray("\u2014 \u8054\u7F51\u641C\u7D22 (\u9700 API Key)")}`,
3235
+ value: "grok-search"
3236
+ },
3237
+ {
3238
+ name: `contextweaver ${ansis.gray("\u2014 \u7845\u57FA\u6D41\u52A8\u5D4C\u5165\u68C0\u7D22 (\u9700 API Key)")}`,
3239
+ value: "contextweaver"
3240
+ }
3241
+ ]
3242
+ }]);
3243
+ const hasAceTool = selectedTools.includes("ace-tool");
3244
+ const hasFastContext = selectedTools.includes("fast-context");
3245
+ const hasContextWeaver = selectedTools.includes("contextweaver");
3246
+ wantFastContext = hasFastContext;
3247
+ wantGrokSearch = selectedTools.includes("grok-search");
3248
+ if (hasAceTool) {
3249
+ mcpProvider = "ace-tool";
3250
+ } else if (hasFastContext) {
3251
+ mcpProvider = "fast-context";
3252
+ } else if (hasContextWeaver) {
3253
+ mcpProvider = "contextweaver";
3254
+ } else {
3255
+ mcpProvider = "skip";
3256
+ }
3257
+ if (hasAceTool) {
3258
+ console.log();
3259
+ console.log(ansis.cyan.bold(` \u{1F527} ace-tool MCP`));
3260
+ console.log();
3261
+ console.log(` ${ansis.gray("\u2022")} ${ansis.cyan(i18n.t("init:mcp.officialService"))}: ${ansis.underline("https://augmentcode.com/")}`);
3262
+ console.log(` ${ansis.gray("\u2022")} ${ansis.cyan(i18n.t("init:mcp.proxyService"))} ${ansis.yellow(`(${i18n.t("init:mcp.noSignup")})`)}: ${ansis.underline("https://acemcp.heroman.wtf/")}`);
3263
+ console.log();
3264
+ const aceAnswers = await inquirer.prompt([
3265
+ {
3266
+ type: "input",
3267
+ name: "baseUrl",
3268
+ message: `Base URL ${ansis.gray(`(${i18n.t("init:mcp.baseUrlHint")})`)}`,
3269
+ default: ""
3270
+ },
3271
+ {
3272
+ type: "password",
3273
+ name: "token",
3274
+ message: `Token ${ansis.gray(`(${i18n.t("init:mcp.tokenRequired")})`)}`,
3275
+ mask: "*",
3276
+ validate: (input) => input.trim() !== "" || i18n.t("init:mcp.enterToken")
3277
+ }
3278
+ ]);
3279
+ aceToolBaseUrl = aceAnswers.baseUrl || "";
3280
+ aceToolToken = aceAnswers.token || "";
3281
+ }
3282
+ if (hasFastContext) {
3283
+ console.log();
3284
+ console.log(ansis.cyan.bold(` \u{1F527} fast-context MCP`));
3285
+ console.log(ansis.gray(` Windsurf Fast Context \u2014 ${i18n.t("init:mcp.fcAutoExtract")}`));
3286
+ console.log();
3287
+ const fcAnswers = await inquirer.prompt([
3288
+ {
3289
+ type: "input",
3290
+ name: "apiKey",
3291
+ message: `WINDSURF_API_KEY ${ansis.gray(`(${i18n.t("init:mcp.fcLeaveEmpty")})`)}`,
3292
+ default: ""
3293
+ },
3294
+ {
3295
+ type: "list",
3296
+ name: "includeSnippets",
3297
+ message: i18n.t("init:mcp.fcSnippetMode"),
3298
+ choices: [
3299
+ { name: `${i18n.t("init:mcp.fcPathOnly")} ${ansis.gray(`(${i18n.t("init:mcp.fcSaveToken")})`)}`, value: false },
3300
+ { name: i18n.t("init:mcp.fcFullSnippet"), value: true }
3301
+ ]
3302
+ }
3303
+ ]);
3304
+ fastContextApiKey = fcAnswers.apiKey?.trim() || "";
3305
+ fastContextIncludeSnippets = fcAnswers.includeSnippets;
3306
+ }
3307
+ if (hasContextWeaver) {
3308
+ console.log();
3309
+ console.log(ansis.cyan.bold(` \u{1F527} ContextWeaver MCP`));
3310
+ console.log();
3311
+ console.log(` ${ansis.gray("1.")} ${i18n.t("init:mcp.siliconflowStep1", { url: ansis.underline("https://siliconflow.cn/") })}`);
3312
+ console.log(` ${ansis.gray("2.")} ${i18n.t("init:mcp.siliconflowStep2")}`);
3313
+ console.log(` ${ansis.gray("3.")} ${i18n.t("init:mcp.siliconflowStep3")}`);
3314
+ console.log();
3315
+ const cwAnswers = await inquirer.prompt([{
3132
3316
  type: "password",
3133
- name: "token",
3134
- message: `Token ${ansis.gray(`(${i18n.t("init:mcp.tokenRequired")})`)}`,
3135
- mask: "*",
3136
- validate: (input) => input.trim() !== "" || i18n.t("init:mcp.enterToken")
3137
- }
3138
- ]);
3139
- aceToolBaseUrl = aceAnswers.baseUrl || "";
3140
- aceToolToken = aceAnswers.token || "";
3141
- }
3142
- if (hasFastContext) {
3143
- console.log();
3144
- console.log(ansis.cyan.bold(` \u{1F527} fast-context MCP`));
3145
- console.log(ansis.gray(` Windsurf Fast Context \u2014 ${i18n.t("init:mcp.fcAutoExtract")}`));
3146
- console.log();
3147
- const fcAnswers = await inquirer.prompt([
3148
- {
3149
- type: "input",
3150
3317
  name: "apiKey",
3151
- message: `WINDSURF_API_KEY ${ansis.gray(`(${i18n.t("init:mcp.fcLeaveEmpty")})`)}`,
3152
- default: ""
3153
- },
3154
- {
3155
- type: "list",
3156
- name: "includeSnippets",
3157
- message: i18n.t("init:mcp.fcSnippetMode"),
3158
- choices: [
3159
- { name: `${i18n.t("init:mcp.fcPathOnly")} ${ansis.gray(`(${i18n.t("init:mcp.fcSaveToken")})`)}`, value: false },
3160
- { name: i18n.t("init:mcp.fcFullSnippet"), value: true }
3161
- ]
3162
- }
3163
- ]);
3164
- fastContextApiKey = fcAnswers.apiKey?.trim() || "";
3165
- fastContextIncludeSnippets = fcAnswers.includeSnippets;
3318
+ message: `SiliconFlow API Key ${ansis.gray("(sk-xxx)")}`,
3319
+ mask: "*",
3320
+ validate: (input) => input.trim() !== "" || i18n.t("init:mcp.enterApiKey")
3321
+ }]);
3322
+ contextWeaverApiKey = cwAnswers.apiKey || "";
3323
+ }
3324
+ if (wantGrokSearch) {
3325
+ console.log();
3326
+ console.log(ansis.cyan.bold(` \u{1F50D} grok-search MCP`));
3327
+ console.log();
3328
+ console.log(` Tavily: ${ansis.underline("https://www.tavily.com/")} ${ansis.gray(`(${i18n.t("init:grok.tavilyHint")})`)}`);
3329
+ console.log(` Firecrawl: ${ansis.underline("https://www.firecrawl.dev/")} ${ansis.gray(`(${i18n.t("init:grok.firecrawlHint")})`)}`);
3330
+ console.log(` Grok API: ${ansis.gray(i18n.t("init:grok.grokHint"))}`);
3331
+ console.log();
3332
+ const grokAnswers = await inquirer.prompt([
3333
+ { type: "input", name: "grokApiUrl", message: `GROK_API_URL ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, default: "" },
3334
+ { type: "password", name: "grokApiKey", message: `GROK_API_KEY ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, mask: "*" },
3335
+ { type: "password", name: "tavilyKey", message: `TAVILY_API_KEY ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, mask: "*" },
3336
+ { type: "password", name: "firecrawlKey", message: `FIRECRAWL_API_KEY ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, mask: "*" }
3337
+ ]);
3338
+ tavilyKey = grokAnswers.tavilyKey?.trim() || "";
3339
+ firecrawlKey = grokAnswers.firecrawlKey?.trim() || "";
3340
+ grokApiUrl = grokAnswers.grokApiUrl?.trim() || "";
3341
+ grokApiKey = grokAnswers.grokApiKey?.trim() || "";
3342
+ }
3343
+ return "next";
3166
3344
  }
3167
- if (hasContextWeaver) {
3168
- console.log();
3169
- console.log(ansis.cyan.bold(` \u{1F527} ContextWeaver MCP`));
3345
+ async function runPerfStep(canGoBack) {
3170
3346
  console.log();
3171
- console.log(` ${ansis.gray("1.")} ${i18n.t("init:mcp.siliconflowStep1", { url: ansis.underline("https://siliconflow.cn/") })}`);
3172
- console.log(` ${ansis.gray("2.")} ${i18n.t("init:mcp.siliconflowStep2")}`);
3173
- console.log(` ${ansis.gray("3.")} ${i18n.t("init:mcp.siliconflowStep3")}`);
3347
+ console.log(ansis.cyan.bold(` \u26A1 Step 4/4 \u2014 ${i18n.t("init:perf.title")}`));
3174
3348
  console.log();
3175
- const cwAnswers = await inquirer.prompt([{
3176
- type: "password",
3177
- name: "apiKey",
3178
- message: `SiliconFlow API Key ${ansis.gray("(sk-xxx)")}`,
3179
- mask: "*",
3180
- validate: (input) => input.trim() !== "" || i18n.t("init:mcp.enterApiKey")
3349
+ const { perfMode } = await inquirer.prompt([{
3350
+ type: "list",
3351
+ name: "perfMode",
3352
+ message: i18n.t("init:perf.selectMode"),
3353
+ choices: [
3354
+ { name: `${ansis.green("\u25CF")} ${i18n.t("init:perf.standardOption")}`, value: "standard" },
3355
+ { name: `${ansis.cyan("\u25CF")} ${i18n.t("init:perf.liteOption")}`, value: "lite" },
3356
+ ...navSentinels(canGoBack)
3357
+ ],
3358
+ default: liteMode ? "lite" : "standard"
3181
3359
  }]);
3182
- contextWeaverApiKey = cwAnswers.apiKey || "";
3360
+ if (perfMode === BACK_SENTINEL)
3361
+ return "back";
3362
+ if (perfMode === CANCEL_SENTINEL)
3363
+ return "cancel";
3364
+ liteMode = perfMode === "lite";
3365
+ const { includeImpeccable } = await inquirer.prompt([{
3366
+ type: "confirm",
3367
+ name: "includeImpeccable",
3368
+ message: i18n.t("init:commands.includeImpeccable"),
3369
+ default: !skipImpeccable
3370
+ }]);
3371
+ skipImpeccable = !includeImpeccable;
3372
+ return "next";
3183
3373
  }
3184
- if (wantGrokSearch) {
3374
+ const runSummaryStep = async (workflowsCount) => {
3185
3375
  console.log();
3186
- console.log(ansis.cyan.bold(` \u{1F50D} grok-search MCP`));
3376
+ console.log(ansis.yellow("\u2501".repeat(50)));
3377
+ console.log(ansis.bold(` ${i18n.t("init:summary.title")}`));
3187
3378
  console.log();
3188
- console.log(` Tavily: ${ansis.underline("https://www.tavily.com/")} ${ansis.gray(`(${i18n.t("init:grok.tavilyHint")})`)}`);
3189
- console.log(` Firecrawl: ${ansis.underline("https://www.firecrawl.dev/")} ${ansis.gray(`(${i18n.t("init:grok.firecrawlHint")})`)}`);
3190
- console.log(` Grok API: ${ansis.gray(i18n.t("init:grok.grokHint"))}`);
3379
+ const fmName = frontendModels[0].charAt(0).toUpperCase() + frontendModels[0].slice(1);
3380
+ const bmName = backendModels[0].charAt(0).toUpperCase() + backendModels[0].slice(1);
3381
+ const apiLabel = (() => {
3382
+ if (apiUrl && apiKey)
3383
+ return `${ansis.green("\u25CF")} ${apiUrl} ${ansis.gray("+ ***")}`;
3384
+ if (apiUrl)
3385
+ return `${ansis.green("\u25CF")} ${apiUrl}`;
3386
+ return `${ansis.gray("\u25CB")} ${i18n.t("init:summary.apiSelfManaged")}`;
3387
+ })();
3388
+ console.log(` ${ansis.cyan(i18n.t("init:summary.apiProvider"))} ${apiLabel}`);
3389
+ console.log(` ${ansis.cyan(i18n.t("init:summary.modelRouting"))} ${ansis.green(fmName)} (Frontend) + ${ansis.blue(bmName)} (Backend)`);
3390
+ if (frontendModels[0] === "gemini" || backendModels[0] === "gemini") {
3391
+ console.log(` ${ansis.cyan(i18n.t("init:summary.geminiModel"))} ${ansis.gray(geminiModel)}`);
3392
+ }
3393
+ console.log(` ${ansis.cyan(i18n.t("init:summary.commandCount"))} ${ansis.yellow(workflowsCount.toString())}`);
3394
+ const mcpSummary = (() => {
3395
+ if (mcpProvider === "fast-context")
3396
+ return ansis.green("fast-context");
3397
+ if (mcpProvider === "ace-tool" || mcpProvider === "ace-tool-rs")
3398
+ return aceToolToken ? ansis.green(mcpProvider) : ansis.yellow(`${mcpProvider} (${i18n.t("init:summary.pendingConfig")})`);
3399
+ if (mcpProvider === "contextweaver")
3400
+ return contextWeaverApiKey ? ansis.green("contextweaver") : ansis.yellow(`contextweaver (${i18n.t("init:summary.pendingConfig")})`);
3401
+ return ansis.gray(i18n.t("init:summary.skipped"));
3402
+ })();
3403
+ console.log(` ${ansis.cyan(i18n.t("init:summary.mcpTool"))} ${mcpSummary}`);
3404
+ console.log(` ${ansis.cyan(i18n.t("init:summary.webUI"))} ${liteMode ? ansis.gray(i18n.t("init:summary.disabled")) : ansis.green(i18n.t("init:summary.enabled"))}`);
3405
+ if (wantGrokSearch) {
3406
+ console.log(` ${ansis.cyan("grok-search")} ${tavilyKey ? ansis.green("\u2713") : ansis.yellow(`(${i18n.t("init:summary.pendingConfig")})`)}`);
3407
+ }
3408
+ console.log(ansis.yellow("\u2501".repeat(50)));
3191
3409
  console.log();
3192
- const grokAnswers = await inquirer.prompt([
3193
- { type: "input", name: "grokApiUrl", message: `GROK_API_URL ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, default: "" },
3194
- { type: "password", name: "grokApiKey", message: `GROK_API_KEY ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, mask: "*" },
3195
- { type: "password", name: "tavilyKey", message: `TAVILY_API_KEY ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, mask: "*" },
3196
- { type: "password", name: "firecrawlKey", message: `FIRECRAWL_API_KEY ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, mask: "*" }
3197
- ]);
3198
- tavilyKey = grokAnswers.tavilyKey?.trim() || "";
3199
- firecrawlKey = grokAnswers.firecrawlKey?.trim() || "";
3200
- grokApiUrl = grokAnswers.grokApiUrl?.trim() || "";
3201
- grokApiKey = grokAnswers.grokApiKey?.trim() || "";
3202
- }
3203
- }
3204
- if (!options.skipPrompt) {
3205
- const existingConfig = await readCcgConfig();
3206
- const currentLiteMode = existingConfig?.performance?.liteMode || false;
3207
- console.log();
3208
- console.log(ansis.cyan.bold(` \u26A1 Step 4/4 \u2014 ${i18n.t("init:perf.title")}`));
3209
- console.log();
3210
- const { perfMode } = await inquirer.prompt([{
3211
- type: "list",
3212
- name: "perfMode",
3213
- message: i18n.t("init:perf.selectMode"),
3214
- choices: [
3215
- { name: `${ansis.green("\u25CF")} ${i18n.t("init:perf.standardOption")}`, value: "standard" },
3216
- { name: `${ansis.cyan("\u25CF")} ${i18n.t("init:perf.liteOption")}`, value: "lite" }
3217
- ],
3218
- default: currentLiteMode ? "lite" : "standard"
3219
- }]);
3220
- liteMode = perfMode === "lite";
3221
- const { includeImpeccable } = await inquirer.prompt([{
3222
- type: "confirm",
3223
- name: "includeImpeccable",
3224
- message: i18n.t("init:commands.includeImpeccable"),
3225
- default: false
3226
- }]);
3227
- skipImpeccable = !includeImpeccable;
3228
- } else {
3229
- const existingConfig = await readCcgConfig();
3230
- if (existingConfig?.performance?.liteMode !== void 0) {
3231
- liteMode = existingConfig.performance.liteMode;
3232
- }
3233
- if (existingConfig?.performance?.skipImpeccable !== void 0) {
3234
- skipImpeccable = existingConfig.performance.skipImpeccable;
3410
+ const { action } = await inquirer.prompt([{
3411
+ type: "list",
3412
+ name: "action",
3413
+ message: i18n.t("init:summaryMenu.prompt"),
3414
+ choices: [
3415
+ { name: `${ansis.green("\u2713")} ${i18n.t("init:summaryMenu.confirm")}`, value: "confirm" },
3416
+ new inquirer.Separator(),
3417
+ { name: `${ansis.cyan("\u270E")} ${i18n.t("init:summaryMenu.editApi")}`, value: "api" },
3418
+ { name: `${ansis.cyan("\u270E")} ${i18n.t("init:summaryMenu.editModel")}`, value: "model" },
3419
+ { name: `${ansis.cyan("\u270E")} ${i18n.t("init:summaryMenu.editMcp")}`, value: "mcp" },
3420
+ { name: `${ansis.cyan("\u270E")} ${i18n.t("init:summaryMenu.editPerf")}`, value: "perf" },
3421
+ new inquirer.Separator(),
3422
+ { name: `${ansis.red("\xD7")} ${i18n.t("init:summaryMenu.cancel")}`, value: "cancel" }
3423
+ ],
3424
+ default: "confirm"
3425
+ }]);
3426
+ return action;
3427
+ };
3428
+ const stepOrder = ["api", "model", "mcp", "perf"];
3429
+ let stepIdx = 0;
3430
+ let jumpingToSummary = false;
3431
+ while (true) {
3432
+ if (stepIdx < stepOrder.length) {
3433
+ const stepId = stepOrder[stepIdx];
3434
+ const canGoBack = stepIdx > 0;
3435
+ let result;
3436
+ switch (stepId) {
3437
+ case "api":
3438
+ result = await runApiStep(canGoBack);
3439
+ break;
3440
+ case "model":
3441
+ result = await runModelStep(canGoBack);
3442
+ break;
3443
+ case "mcp":
3444
+ result = await runMcpStep(canGoBack);
3445
+ break;
3446
+ case "perf":
3447
+ result = await runPerfStep(canGoBack);
3448
+ break;
3449
+ }
3450
+ if (result === "cancel") {
3451
+ console.log(ansis.yellow(i18n.t("init:installCancelled")));
3452
+ return;
3453
+ }
3454
+ if (result === "back") {
3455
+ stepIdx = Math.max(0, stepIdx - 1);
3456
+ continue;
3457
+ }
3458
+ if (jumpingToSummary) {
3459
+ jumpingToSummary = false;
3460
+ stepIdx = stepOrder.length;
3461
+ } else {
3462
+ stepIdx++;
3463
+ }
3464
+ } else {
3465
+ const summaryAction = await runSummaryStep(selectedWorkflows.length);
3466
+ if (summaryAction === "confirm") {
3467
+ break;
3468
+ }
3469
+ if (summaryAction === "cancel") {
3470
+ console.log(ansis.yellow(i18n.t("init:installCancelled")));
3471
+ return;
3472
+ }
3473
+ jumpingToSummary = true;
3474
+ stepIdx = stepOrder.indexOf(summaryAction);
3475
+ }
3235
3476
  }
3236
3477
  }
3237
3478
  const routing = {
@@ -3252,38 +3493,17 @@ async function init(options = {}) {
3252
3493
  mode,
3253
3494
  geminiModel
3254
3495
  };
3255
- console.log();
3256
- console.log(ansis.yellow("\u2501".repeat(50)));
3257
- console.log(ansis.bold(` ${i18n.t("init:summary.title")}`));
3258
- console.log();
3259
- const fmName = frontendModels[0].charAt(0).toUpperCase() + frontendModels[0].slice(1);
3260
- const bmName = backendModels[0].charAt(0).toUpperCase() + backendModels[0].slice(1);
3261
- console.log(` ${ansis.cyan(i18n.t("init:summary.modelRouting"))} ${ansis.green(fmName)} (Frontend) + ${ansis.blue(bmName)} (Backend)`);
3262
- console.log(` ${ansis.cyan(i18n.t("init:summary.commandCount"))} ${ansis.yellow(selectedWorkflows.length.toString())}`);
3263
- const mcpSummary = (() => {
3264
- if (mcpProvider === "fast-context") return ansis.green("fast-context");
3265
- if (mcpProvider === "ace-tool" || mcpProvider === "ace-tool-rs") return aceToolToken ? ansis.green(mcpProvider) : ansis.yellow(`${mcpProvider} (${i18n.t("init:summary.pendingConfig")})`);
3266
- if (mcpProvider === "contextweaver") return contextWeaverApiKey ? ansis.green("contextweaver") : ansis.yellow(`contextweaver (${i18n.t("init:summary.pendingConfig")})`);
3267
- return ansis.gray(i18n.t("init:summary.skipped"));
3268
- })();
3269
- console.log(` ${ansis.cyan(i18n.t("init:summary.mcpTool"))} ${mcpSummary}`);
3270
- console.log(` ${ansis.cyan(i18n.t("init:summary.webUI"))} ${liteMode ? ansis.gray(i18n.t("init:summary.disabled")) : ansis.green(i18n.t("init:summary.enabled"))}`);
3271
- if (wantGrokSearch) {
3272
- console.log(` ${ansis.cyan("grok-search")} ${tavilyKey ? ansis.green("\u2713") : ansis.yellow(`(${i18n.t("init:summary.pendingConfig")})`)}`);
3273
- }
3274
- console.log(ansis.yellow("\u2501".repeat(50)));
3275
- console.log();
3276
- if (!options.skipPrompt && !options.force) {
3277
- const { confirmed } = await inquirer.prompt([{
3278
- type: "confirm",
3279
- name: "confirmed",
3280
- message: i18n.t("init:confirmInstall"),
3281
- default: true
3282
- }]);
3283
- if (!confirmed) {
3284
- console.log(ansis.yellow(i18n.t("init:installCancelled")));
3285
- return;
3286
- }
3496
+ if (options.skipPrompt || options.force) {
3497
+ console.log();
3498
+ console.log(ansis.yellow("\u2501".repeat(50)));
3499
+ console.log(ansis.bold(` ${i18n.t("init:summary.title")}`));
3500
+ console.log();
3501
+ const fmName = frontendModels[0].charAt(0).toUpperCase() + frontendModels[0].slice(1);
3502
+ const bmName = backendModels[0].charAt(0).toUpperCase() + backendModels[0].slice(1);
3503
+ console.log(` ${ansis.cyan(i18n.t("init:summary.modelRouting"))} ${ansis.green(fmName)} (Frontend) + ${ansis.blue(bmName)} (Backend)`);
3504
+ console.log(` ${ansis.cyan(i18n.t("init:summary.commandCount"))} ${ansis.yellow(selectedWorkflows.length.toString())}`);
3505
+ console.log(ansis.yellow("\u2501".repeat(50)));
3506
+ console.log();
3287
3507
  }
3288
3508
  const spinner = ora(i18n.t("init:installing")).start();
3289
3509
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccg-workflow",
3
- "version": "2.1.14",
3
+ "version": "2.1.16",
4
4
  "description": "Claude + Codex + Gemini multi-model collaboration system - smart routing development workflow",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.17.1",