ccg-workflow 2.1.15 → 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.15 | [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.15 | [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.C2MaYeHU.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.C2MaYeHU.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.15";
13
+ const version = "2.1.16";
14
14
 
15
15
  function cmd(id, order, category, name, nameEn, description, descriptionEn, cmdOverride) {
16
16
  return {
@@ -1795,15 +1795,31 @@ const zhCN = {
1795
1795
  collaboration: "\u534F\u4F5C\u6A21\u5F0F:",
1796
1796
  workflows: "\u5DE5\u4F5C\u6D41:",
1797
1797
  selected: "\u4E2A\u5DF2\u9009\u62E9",
1798
+ apiProvider: "API \u63D0\u4F9B\u65B9",
1798
1799
  modelRouting: "\u6A21\u578B\u8DEF\u7531",
1800
+ geminiModel: "Gemini \u578B\u53F7",
1799
1801
  commandCount: "\u547D\u4EE4\u6570\u91CF",
1800
1802
  mcpTool: "MCP \u5DE5\u5177",
1801
1803
  webUI: "Web UI",
1804
+ apiSelfManaged: "\u81EA\u884C\u7BA1\u7406\uFF08CCG \u4E0D\u4ECB\u5165\uFF09",
1802
1805
  pendingConfig: "\u5F85\u914D\u7F6E",
1803
1806
  skipped: "\u8DF3\u8FC7",
1804
1807
  enabled: "\u542F\u7528",
1805
1808
  disabled: "\u7981\u7528"
1806
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
+ },
1807
1823
  mcp: {
1808
1824
  title: "MCP \u4EE3\u7801\u68C0\u7D22\u5DE5\u5177\u914D\u7F6E",
1809
1825
  selectProvider: "\u9009\u62E9\u4EE3\u7801\u68C0\u7D22 MCP \u5DE5\u5177",
@@ -1851,7 +1867,9 @@ const zhCN = {
1851
1867
  cwConfiguring: "\u6B63\u5728\u914D\u7F6E ContextWeaver MCP...",
1852
1868
  cwFailed: "ContextWeaver MCP \u914D\u7F6E\u5931\u8D25",
1853
1869
  cwConfigFile: "\u914D\u7F6E\u6587\u4EF6",
1854
- 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"
1855
1873
  },
1856
1874
  api: {
1857
1875
  title: "Claude Code API \u914D\u7F6E",
@@ -1861,6 +1879,8 @@ const zhCN = {
1861
1879
  thirdPartyOption: "\u7B2C\u4E09\u65B9 API \u4EE3\u7406\uFF08\u81EA\u5B9A\u4E49 URL + Key\uFF09",
1862
1880
  sponsor302AI: "302.AI\uFF08\u6309\u7528\u91CF\u4ED8\u8D39\u7684\u4F01\u4E1A\u7EA7 AI \u8D44\u6E90\u5E73\u53F0\uFF09",
1863
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_*",
1864
1884
  urlPrompt: "API URL",
1865
1885
  urlRequired: "\u5FC5\u586B",
1866
1886
  keyPrompt: "API Key",
@@ -2271,15 +2291,31 @@ const en = {
2271
2291
  collaboration: "Collaboration:",
2272
2292
  workflows: "Workflows:",
2273
2293
  selected: "selected",
2294
+ apiProvider: "API Provider",
2274
2295
  modelRouting: "Model Routing",
2296
+ geminiModel: "Gemini Model",
2275
2297
  commandCount: "Commands",
2276
2298
  mcpTool: "MCP Tool",
2277
2299
  webUI: "Web UI",
2300
+ apiSelfManaged: "self-managed (CCG does not touch)",
2278
2301
  pendingConfig: "pending",
2279
2302
  skipped: "skipped",
2280
2303
  enabled: "Enabled",
2281
2304
  disabled: "Disabled"
2282
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
+ },
2283
2319
  mcp: {
2284
2320
  title: "MCP Code Retrieval Tool",
2285
2321
  selectProvider: "Select code retrieval MCP tool",
@@ -2327,7 +2363,9 @@ const en = {
2327
2363
  cwConfiguring: "Configuring ContextWeaver MCP...",
2328
2364
  cwFailed: "ContextWeaver MCP configuration failed",
2329
2365
  cwConfigFile: "Config file",
2330
- cwIndexHint: "First use requires indexing your codebase:"
2366
+ cwIndexHint: "First use requires indexing your codebase:",
2367
+ gatePrompt: "Configure MCP tools?",
2368
+ gateContinue: "Start configuration"
2331
2369
  },
2332
2370
  api: {
2333
2371
  title: "Claude Code API Configuration",
@@ -2337,6 +2375,8 @@ const en = {
2337
2375
  thirdPartyOption: "Third-party API proxy (custom URL + Key)",
2338
2376
  sponsor302AI: "302.AI (Pay-as-you-go Enterprise AI Resource Hub)",
2339
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",
2340
2380
  urlPrompt: "API URL",
2341
2381
  urlRequired: "Required",
2342
2382
  keyPrompt: "API Key",
@@ -2903,6 +2943,22 @@ For example, when using the \`fastapi\` library to encapsulate an API endpoint,
2903
2943
  await fs.ensureDir(rulesDir);
2904
2944
  await fs.writeFile(rulePath, prompt, "utf-8");
2905
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
+ }
2906
2962
  async function installGrokSearchMcp(keys) {
2907
2963
  const env = {};
2908
2964
  if (keys.tavilyKey)
@@ -2979,273 +3035,444 @@ async function init(options = {}) {
2979
3035
  let grokApiKey = "";
2980
3036
  let apiUrl = "";
2981
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
+ }
2982
3050
  if (!options.skipPrompt) {
2983
- console.log();
2984
- console.log(ansis.cyan.bold(` \u{1F511} Step 1/4 \u2014 ${i18n.t("init:api.title")}`));
2985
- console.log();
2986
- const { apiProvider } = await inquirer.prompt([{
2987
- type: "list",
2988
- name: "apiProvider",
2989
- message: i18n.t("init:api.providerPrompt"),
2990
- choices: [
2991
- { name: `${ansis.green("\u25CF")} ${i18n.t("init:api.officialOption")}`, value: "official" },
2992
- { name: `${ansis.cyan("\u25CF")} ${i18n.t("init:api.thirdPartyOption")}`, value: "thirdparty" },
2993
- { name: `${ansis.yellow("\u2605")} ${i18n.t("init:api.sponsor302AI")} ${ansis.gray("\u2014 https://share.302.ai/oUDqQ6")}`, value: "302ai" }
2994
- ]
2995
- }]);
2996
- if (apiProvider === "302ai") {
2997
- 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) {
2998
3066
  console.log();
2999
- 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")}`));
3000
3068
  console.log();
3001
- const { key } = await inquirer.prompt([{
3002
- type: "password",
3003
- name: "key",
3004
- message: `302.AI API Key ${ansis.gray(`(${i18n.t("init:api.keyRequired")})`)}`,
3005
- mask: "*",
3006
- 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
+ ]
3007
3080
  }]);
3008
- apiKey = key?.trim() || "";
3009
- } else if (apiProvider === "thirdparty") {
3010
- const apiAnswers = await inquirer.prompt([
3011
- {
3012
- type: "input",
3013
- name: "url",
3014
- message: `API URL ${ansis.gray(`(${i18n.t("init:api.urlRequired")})`)}`,
3015
- validate: (v) => v.trim() !== "" || i18n.t("init:api.enterUrl")
3016
- },
3017
- {
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([{
3018
3093
  type: "password",
3019
3094
  name: "key",
3020
- message: `API Key ${ansis.gray(`(${i18n.t("init:api.keyRequired")})`)}`,
3095
+ message: `302.AI API Key ${ansis.gray(`(${i18n.t("init:api.keyRequired")})`)}`,
3021
3096
  mask: "*",
3022
3097
  validate: (v) => v.trim() !== "" || i18n.t("init:api.enterKey")
3023
- }
3024
- ]);
3025
- apiUrl = apiAnswers.url?.trim() || "";
3026
- 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";
3027
3123
  }
3028
- }
3029
- if (!options.skipPrompt) {
3030
- const existingConfig = await readCcgConfig();
3031
- console.log();
3032
- console.log(ansis.cyan.bold(` \u{1F9E0} Step 2/4 \u2014 ${i18n.t("init:model.title")}`));
3033
- console.log();
3034
- const { selectedFrontend } = await inquirer.prompt([{
3035
- type: "list",
3036
- name: "selectedFrontend",
3037
- message: i18n.t("init:model.selectFrontend"),
3038
- choices: [
3039
- { name: `Gemini ${ansis.green(`(${i18n.t("init:model.recommended")})`)}`, value: "gemini" },
3040
- { name: "Codex", value: "codex" }
3041
- ],
3042
- default: existingConfig?.routing?.frontend?.primary || "gemini"
3043
- }]);
3044
- const { selectedBackend } = await inquirer.prompt([{
3045
- type: "list",
3046
- name: "selectedBackend",
3047
- message: i18n.t("init:model.selectBackend"),
3048
- choices: [
3049
- { name: "Gemini", value: "gemini" },
3050
- { name: `Codex ${ansis.green(`(${i18n.t("init:model.recommended")})`)}`, value: "codex" }
3051
- ],
3052
- default: existingConfig?.routing?.backend?.primary || "codex"
3053
- }]);
3054
- frontendModels = [selectedFrontend];
3055
- backendModels = [selectedBackend];
3056
- if (selectedFrontend === "gemini" || selectedBackend === "gemini") {
3057
- 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([{
3058
3129
  type: "list",
3059
- name: "selectedGeminiModel",
3060
- message: i18n.t("init:model.selectGeminiModel"),
3130
+ name: "selectedFrontend",
3131
+ message: i18n.t("init:model.selectFrontend"),
3061
3132
  choices: [
3062
- { name: `gemini-3.1-pro-preview ${ansis.green(`(${i18n.t("init:model.recommended")})`)}`, value: "gemini-3.1-pro-preview" },
3063
- { name: "gemini-2.5-flash", value: "gemini-2.5-flash" },
3064
- { 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)
3065
3136
  ],
3066
- default: existingConfig?.routing?.geminiModel || "gemini-3.1-pro-preview"
3137
+ default: frontendModels[0] || "gemini"
3067
3138
  }]);
3068
- if (selectedGeminiModel === "custom") {
3069
- const { customModel } = await inquirer.prompt([{
3070
- type: "input",
3071
- name: "customModel",
3072
- message: i18n.t("init:model.enterCustomModel"),
3073
- 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"
3074
3166
  }]);
3075
- geminiModel = customModel.trim();
3076
- } else {
3077
- geminiModel = selectedGeminiModel;
3078
- }
3079
- }
3080
- }
3081
- if (options.skipMcp) {
3082
- const existingConfig = await readCcgConfig();
3083
- mcpProvider = existingConfig?.mcp?.provider || "skip";
3084
- } else if (!options.skipPrompt) {
3085
- console.log();
3086
- console.log(ansis.cyan.bold(` \u{1F527} Step 3/4 \u2014 ${i18n.t("init:mcp.title")}`));
3087
- console.log();
3088
- const { selectedTools } = await inquirer.prompt([{
3089
- type: "checkbox",
3090
- name: "selectedTools",
3091
- message: i18n.t("init:mcp.selectTools"),
3092
- choices: [
3093
- {
3094
- name: `ace-tool ${ansis.green(`(${i18n.t("common:info")})`)} ${ansis.gray("\u2014 search_context \u4EE3\u7801\u68C0\u7D22")}`,
3095
- value: "ace-tool",
3096
- checked: true
3097
- },
3098
- {
3099
- name: `fast-context ${ansis.gray("\u2014 AI \u9A71\u52A8\u8BED\u4E49\u641C\u7D22")}`,
3100
- value: "fast-context"
3101
- },
3102
- {
3103
- name: `context7 ${ansis.green("(free)")} ${ansis.gray("\u2014 \u5E93\u6587\u6863\u67E5\u8BE2")}`,
3104
- value: "context7",
3105
- checked: true
3106
- },
3107
- {
3108
- name: `grok-search ${ansis.gray("\u2014 \u8054\u7F51\u641C\u7D22 (\u9700 API Key)")}`,
3109
- value: "grok-search"
3110
- },
3111
- {
3112
- name: `contextweaver ${ansis.gray("\u2014 \u7845\u57FA\u6D41\u52A8\u5D4C\u5165\u68C0\u7D22 (\u9700 API Key)")}`,
3113
- 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;
3114
3178
  }
3115
- ]
3116
- }]);
3117
- const hasAceTool = selectedTools.includes("ace-tool");
3118
- const hasFastContext = selectedTools.includes("fast-context");
3119
- const hasContextWeaver = selectedTools.includes("contextweaver");
3120
- wantFastContext = hasFastContext;
3121
- wantGrokSearch = selectedTools.includes("grok-search");
3122
- if (hasAceTool) {
3123
- mcpProvider = "ace-tool";
3124
- } else if (hasFastContext) {
3125
- mcpProvider = "fast-context";
3126
- } else if (hasContextWeaver) {
3127
- mcpProvider = "contextweaver";
3128
- } else {
3129
- mcpProvider = "skip";
3179
+ }
3180
+ return "next";
3130
3181
  }
3131
- if (hasAceTool) {
3132
- console.log();
3133
- 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
+ }
3134
3187
  console.log();
3135
- console.log(` ${ansis.gray("\u2022")} ${ansis.cyan(i18n.t("init:mcp.officialService"))}: ${ansis.underline("https://augmentcode.com/")}`);
3136
- 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")}`));
3137
3189
  console.log();
3138
- const aceAnswers = await inquirer.prompt([
3139
- {
3140
- type: "input",
3141
- name: "baseUrl",
3142
- message: `Base URL ${ansis.gray(`(${i18n.t("init:mcp.baseUrlHint")})`)}`,
3143
- default: ""
3144
- },
3145
- {
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([{
3146
3316
  type: "password",
3147
- name: "token",
3148
- message: `Token ${ansis.gray(`(${i18n.t("init:mcp.tokenRequired")})`)}`,
3149
- mask: "*",
3150
- validate: (input) => input.trim() !== "" || i18n.t("init:mcp.enterToken")
3151
- }
3152
- ]);
3153
- aceToolBaseUrl = aceAnswers.baseUrl || "";
3154
- aceToolToken = aceAnswers.token || "";
3155
- }
3156
- if (hasFastContext) {
3157
- console.log();
3158
- console.log(ansis.cyan.bold(` \u{1F527} fast-context MCP`));
3159
- console.log(ansis.gray(` Windsurf Fast Context \u2014 ${i18n.t("init:mcp.fcAutoExtract")}`));
3160
- console.log();
3161
- const fcAnswers = await inquirer.prompt([
3162
- {
3163
- type: "input",
3164
3317
  name: "apiKey",
3165
- message: `WINDSURF_API_KEY ${ansis.gray(`(${i18n.t("init:mcp.fcLeaveEmpty")})`)}`,
3166
- default: ""
3167
- },
3168
- {
3169
- type: "list",
3170
- name: "includeSnippets",
3171
- message: i18n.t("init:mcp.fcSnippetMode"),
3172
- choices: [
3173
- { name: `${i18n.t("init:mcp.fcPathOnly")} ${ansis.gray(`(${i18n.t("init:mcp.fcSaveToken")})`)}`, value: false },
3174
- { name: i18n.t("init:mcp.fcFullSnippet"), value: true }
3175
- ]
3176
- }
3177
- ]);
3178
- fastContextApiKey = fcAnswers.apiKey?.trim() || "";
3179
- 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";
3180
3344
  }
3181
- if (hasContextWeaver) {
3182
- console.log();
3183
- console.log(ansis.cyan.bold(` \u{1F527} ContextWeaver MCP`));
3345
+ async function runPerfStep(canGoBack) {
3184
3346
  console.log();
3185
- console.log(` ${ansis.gray("1.")} ${i18n.t("init:mcp.siliconflowStep1", { url: ansis.underline("https://siliconflow.cn/") })}`);
3186
- console.log(` ${ansis.gray("2.")} ${i18n.t("init:mcp.siliconflowStep2")}`);
3187
- 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")}`));
3188
3348
  console.log();
3189
- const cwAnswers = await inquirer.prompt([{
3190
- type: "password",
3191
- name: "apiKey",
3192
- message: `SiliconFlow API Key ${ansis.gray("(sk-xxx)")}`,
3193
- mask: "*",
3194
- 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"
3359
+ }]);
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
3195
3370
  }]);
3196
- contextWeaverApiKey = cwAnswers.apiKey || "";
3371
+ skipImpeccable = !includeImpeccable;
3372
+ return "next";
3197
3373
  }
3198
- if (wantGrokSearch) {
3374
+ const runSummaryStep = async (workflowsCount) => {
3199
3375
  console.log();
3200
- 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")}`));
3201
3378
  console.log();
3202
- console.log(` Tavily: ${ansis.underline("https://www.tavily.com/")} ${ansis.gray(`(${i18n.t("init:grok.tavilyHint")})`)}`);
3203
- console.log(` Firecrawl: ${ansis.underline("https://www.firecrawl.dev/")} ${ansis.gray(`(${i18n.t("init:grok.firecrawlHint")})`)}`);
3204
- 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)));
3205
3409
  console.log();
3206
- const grokAnswers = await inquirer.prompt([
3207
- { type: "input", name: "grokApiUrl", message: `GROK_API_URL ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, default: "" },
3208
- { type: "password", name: "grokApiKey", message: `GROK_API_KEY ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, mask: "*" },
3209
- { type: "password", name: "tavilyKey", message: `TAVILY_API_KEY ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, mask: "*" },
3210
- { type: "password", name: "firecrawlKey", message: `FIRECRAWL_API_KEY ${ansis.gray(`(${i18n.t("init:grok.optional")})`)}`, mask: "*" }
3211
- ]);
3212
- tavilyKey = grokAnswers.tavilyKey?.trim() || "";
3213
- firecrawlKey = grokAnswers.firecrawlKey?.trim() || "";
3214
- grokApiUrl = grokAnswers.grokApiUrl?.trim() || "";
3215
- grokApiKey = grokAnswers.grokApiKey?.trim() || "";
3216
- }
3217
- }
3218
- if (!options.skipPrompt) {
3219
- const existingConfig = await readCcgConfig();
3220
- const currentLiteMode = existingConfig?.performance?.liteMode || false;
3221
- console.log();
3222
- console.log(ansis.cyan.bold(` \u26A1 Step 4/4 \u2014 ${i18n.t("init:perf.title")}`));
3223
- console.log();
3224
- const { perfMode } = await inquirer.prompt([{
3225
- type: "list",
3226
- name: "perfMode",
3227
- message: i18n.t("init:perf.selectMode"),
3228
- choices: [
3229
- { name: `${ansis.green("\u25CF")} ${i18n.t("init:perf.standardOption")}`, value: "standard" },
3230
- { name: `${ansis.cyan("\u25CF")} ${i18n.t("init:perf.liteOption")}`, value: "lite" }
3231
- ],
3232
- default: currentLiteMode ? "lite" : "standard"
3233
- }]);
3234
- liteMode = perfMode === "lite";
3235
- const { includeImpeccable } = await inquirer.prompt([{
3236
- type: "confirm",
3237
- name: "includeImpeccable",
3238
- message: i18n.t("init:commands.includeImpeccable"),
3239
- default: false
3240
- }]);
3241
- skipImpeccable = !includeImpeccable;
3242
- } else {
3243
- const existingConfig = await readCcgConfig();
3244
- if (existingConfig?.performance?.liteMode !== void 0) {
3245
- liteMode = existingConfig.performance.liteMode;
3246
- }
3247
- if (existingConfig?.performance?.skipImpeccable !== void 0) {
3248
- 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
+ }
3249
3476
  }
3250
3477
  }
3251
3478
  const routing = {
@@ -3266,38 +3493,17 @@ async function init(options = {}) {
3266
3493
  mode,
3267
3494
  geminiModel
3268
3495
  };
3269
- console.log();
3270
- console.log(ansis.yellow("\u2501".repeat(50)));
3271
- console.log(ansis.bold(` ${i18n.t("init:summary.title")}`));
3272
- console.log();
3273
- const fmName = frontendModels[0].charAt(0).toUpperCase() + frontendModels[0].slice(1);
3274
- const bmName = backendModels[0].charAt(0).toUpperCase() + backendModels[0].slice(1);
3275
- console.log(` ${ansis.cyan(i18n.t("init:summary.modelRouting"))} ${ansis.green(fmName)} (Frontend) + ${ansis.blue(bmName)} (Backend)`);
3276
- console.log(` ${ansis.cyan(i18n.t("init:summary.commandCount"))} ${ansis.yellow(selectedWorkflows.length.toString())}`);
3277
- const mcpSummary = (() => {
3278
- if (mcpProvider === "fast-context") return ansis.green("fast-context");
3279
- if (mcpProvider === "ace-tool" || mcpProvider === "ace-tool-rs") return aceToolToken ? ansis.green(mcpProvider) : ansis.yellow(`${mcpProvider} (${i18n.t("init:summary.pendingConfig")})`);
3280
- if (mcpProvider === "contextweaver") return contextWeaverApiKey ? ansis.green("contextweaver") : ansis.yellow(`contextweaver (${i18n.t("init:summary.pendingConfig")})`);
3281
- return ansis.gray(i18n.t("init:summary.skipped"));
3282
- })();
3283
- console.log(` ${ansis.cyan(i18n.t("init:summary.mcpTool"))} ${mcpSummary}`);
3284
- console.log(` ${ansis.cyan(i18n.t("init:summary.webUI"))} ${liteMode ? ansis.gray(i18n.t("init:summary.disabled")) : ansis.green(i18n.t("init:summary.enabled"))}`);
3285
- if (wantGrokSearch) {
3286
- console.log(` ${ansis.cyan("grok-search")} ${tavilyKey ? ansis.green("\u2713") : ansis.yellow(`(${i18n.t("init:summary.pendingConfig")})`)}`);
3287
- }
3288
- console.log(ansis.yellow("\u2501".repeat(50)));
3289
- console.log();
3290
- if (!options.skipPrompt && !options.force) {
3291
- const { confirmed } = await inquirer.prompt([{
3292
- type: "confirm",
3293
- name: "confirmed",
3294
- message: i18n.t("init:confirmInstall"),
3295
- default: true
3296
- }]);
3297
- if (!confirmed) {
3298
- console.log(ansis.yellow(i18n.t("init:installCancelled")));
3299
- return;
3300
- }
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();
3301
3507
  }
3302
3508
  const spinner = ora(i18n.t("init:installing")).start();
3303
3509
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccg-workflow",
3
- "version": "2.1.15",
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",