ccjk 13.3.13 → 13.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,75 @@
1
+ import { a as getSmartRouter } from '../shared/ccjk.DQXk596F.mjs';
2
+ import 'node:fs';
3
+ import 'node:fs/promises';
4
+ import 'node:os';
5
+ import '../shared/ccjk.bQ7Dh1g4.mjs';
6
+
7
+ async function brainConfigCommand(options) {
8
+ try {
9
+ const router = getSmartRouter();
10
+ if (options.show) {
11
+ const config = router.getConfig();
12
+ console.log("\n\u2699\uFE0F Current Brain Configuration:\n");
13
+ console.log(` \u80FD\u529B\u504F\u597D: ${config.capabilityPreference}/5`);
14
+ console.log(` \u81EA\u52A8Subagent\u9608\u503C: ${config.autoSubagentThreshold}/10`);
15
+ console.log(` \u6700\u5927\u5E76\u884CAgent: ${config.maxParallelAgents}`);
16
+ console.log(` \u9065\u6D4B: ${config.enableTelemetry ? "\u542F\u7528" : "\u7981\u7528"}`);
17
+ console.log(` \u663E\u793A\u51B3\u7B56\u7406\u7531: ${config.showReasoning ? "\u542F\u7528" : "\u7981\u7528"}`);
18
+ console.log();
19
+ return;
20
+ }
21
+ if (options.reset) {
22
+ router.updateConfig({
23
+ capabilityPreference: 2,
24
+ autoSubagentThreshold: 7,
25
+ maxParallelAgents: 3,
26
+ enableTelemetry: true,
27
+ showReasoning: true
28
+ });
29
+ console.log("\u2705 Configuration reset to defaults");
30
+ return;
31
+ }
32
+ const updates = {};
33
+ if (options.preference !== void 0) {
34
+ if (options.preference < 1 || options.preference > 5) {
35
+ console.error("\u274C Preference must be between 1 and 5");
36
+ process.exit(1);
37
+ }
38
+ updates.capabilityPreference = options.preference;
39
+ }
40
+ if (options.threshold !== void 0) {
41
+ if (options.threshold < 1 || options.threshold > 10) {
42
+ console.error("\u274C Threshold must be between 1 and 10");
43
+ process.exit(1);
44
+ }
45
+ updates.autoSubagentThreshold = options.threshold;
46
+ }
47
+ if (options.maxAgents !== void 0) {
48
+ if (options.maxAgents < 1 || options.maxAgents > 10) {
49
+ console.error("\u274C Max agents must be between 1 and 10");
50
+ process.exit(1);
51
+ }
52
+ updates.maxParallelAgents = options.maxAgents;
53
+ }
54
+ if (options.telemetry !== void 0) {
55
+ updates.enableTelemetry = options.telemetry === "on";
56
+ }
57
+ if (options.reasoning !== void 0) {
58
+ updates.showReasoning = options.reasoning === "on";
59
+ }
60
+ if (Object.keys(updates).length === 0) {
61
+ console.log("No configuration changes specified. Use --show to see current config.");
62
+ return;
63
+ }
64
+ router.updateConfig(updates);
65
+ console.log("\u2705 Configuration updated:");
66
+ for (const [key, value] of Object.entries(updates)) {
67
+ console.log(` ${key}: ${value}`);
68
+ }
69
+ } catch (error) {
70
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
71
+ process.exit(1);
72
+ }
73
+ }
74
+
75
+ export { brainConfigCommand };
@@ -0,0 +1,83 @@
1
+ import { g as getTelemetry, a as getSmartRouter, b as getCapabilityName } from '../shared/ccjk.DQXk596F.mjs';
2
+ import 'node:fs';
3
+ import 'node:fs/promises';
4
+ import 'node:os';
5
+ import '../shared/ccjk.bQ7Dh1g4.mjs';
6
+
7
+ async function brainStatusCommand(options) {
8
+ try {
9
+ const telemetry = getTelemetry();
10
+ const router = getSmartRouter();
11
+ const stats = await telemetry.getStats();
12
+ const config = router.getConfig();
13
+ if (options.json) {
14
+ console.log(JSON.stringify({ stats, config }, null, 2));
15
+ return;
16
+ }
17
+ console.log("\n\u{1F4CA} Brain Status Report\n");
18
+ console.log("\u2550".repeat(60));
19
+ console.log("\n\u2699\uFE0F Router Configuration:");
20
+ console.log(` \u80FD\u529B\u504F\u597D: ${config.capabilityPreference}/5 (${getPreferenceLabel(config.capabilityPreference)})`);
21
+ console.log(` \u81EA\u52A8Subagent\u9608\u503C: ${config.autoSubagentThreshold}/10`);
22
+ console.log(` \u6700\u5927\u5E76\u884CAgent: ${config.maxParallelAgents}`);
23
+ console.log(` \u9065\u6D4B: ${config.enableTelemetry ? "\u2705 \u542F\u7528" : "\u274C \u7981\u7528"}`);
24
+ console.log(` \u663E\u793A\u51B3\u7B56\u7406\u7531: ${config.showReasoning ? "\u2705 \u662F" : "\u274C \u5426"}`);
25
+ console.log("\n\u{1F4C8} Overall Statistics:");
26
+ console.log(` \u603B\u4EFB\u52A1\u6570: ${stats.totalTasks}`);
27
+ if (stats.totalTasks === 0) {
28
+ console.log("\n \u6682\u65E0\u4EFB\u52A1\u8BB0\u5F55");
29
+ console.log("\n\u2550".repeat(60));
30
+ return;
31
+ }
32
+ console.log("\n\u{1F3AF} By Capability Level:");
33
+ for (const [level, levelStats] of Object.entries(stats.byLevel)) {
34
+ const levelNum = Number(level);
35
+ const name = getCapabilityName(levelNum);
36
+ const successRate = (levelStats.successRate * 100).toFixed(1);
37
+ const avgDuration = levelStats.avgDuration.toFixed(1);
38
+ const avgScore = levelStats.avgEffectScore.toFixed(1);
39
+ console.log(`
40
+ Level ${level} - ${name}:`);
41
+ console.log(` \u4EFB\u52A1\u6570: ${levelStats.count}`);
42
+ console.log(` \u6210\u529F\u7387: ${successRate}% ${getSuccessEmoji(levelStats.successRate)}`);
43
+ console.log(` \u5E73\u5747\u8017\u65F6: ${avgDuration}s`);
44
+ console.log(` \u5E73\u5747\u8BC4\u5206: ${avgScore}/10 ${getScoreEmoji(levelStats.avgEffectScore)}`);
45
+ }
46
+ if (options.detailed && stats.recentTrend.length > 0) {
47
+ console.log("\n\u{1F4C5} Recent Trend (Last 30 Days):");
48
+ const recentDays = stats.recentTrend.slice(-7);
49
+ for (const day of recentDays) {
50
+ const successRate = (day.successRate * 100).toFixed(1);
51
+ console.log(` ${day.date}: ${day.count} tasks, ${successRate}% success`);
52
+ }
53
+ }
54
+ if (stats.recommendations.length > 0) {
55
+ console.log("\n\u{1F4A1} Recommendations:");
56
+ for (const rec of stats.recommendations) {
57
+ console.log(` \u2022 ${rec}`);
58
+ }
59
+ }
60
+ console.log("\n\u2550".repeat(60));
61
+ console.log();
62
+ } catch (error) {
63
+ console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
64
+ process.exit(1);
65
+ }
66
+ }
67
+ function getPreferenceLabel(pref) {
68
+ if (pref <= 2) return "\u4F18\u5148\u7B80\u5355";
69
+ if (pref >= 4) return "\u4F18\u5148\u590D\u6742";
70
+ return "\u5E73\u8861";
71
+ }
72
+ function getSuccessEmoji(rate) {
73
+ if (rate >= 0.9) return "\u{1F7E2}";
74
+ if (rate >= 0.7) return "\u{1F7E1}";
75
+ return "\u{1F534}";
76
+ }
77
+ function getScoreEmoji(score) {
78
+ if (score >= 8) return "\u{1F31F}";
79
+ if (score >= 6) return "\u{1F44D}";
80
+ return "\u{1F44E}";
81
+ }
82
+
83
+ export { brainStatusCommand };
@@ -18,9 +18,13 @@ const MODEL_ENV_KEYS = [
18
18
  // Deprecated but still cleaned to avoid stale values
19
19
  "ANTHROPIC_SMALL_FAST_MODEL"
20
20
  ];
21
- function clearModelEnv(env) {
21
+ function clearModelEnv(env, mode = "reset") {
22
22
  for (const key of MODEL_ENV_KEYS) {
23
- delete env[key];
23
+ if (mode === "reset" && key === "ANTHROPIC_MODEL") {
24
+ env[key] = "";
25
+ } else {
26
+ delete env[key];
27
+ }
24
28
  }
25
29
  }
26
30
 
@@ -157,7 +161,7 @@ function updateCustomModel(primaryModel, haikuModel, sonnetModel, opusModel) {
157
161
  }
158
162
  delete settings.model;
159
163
  settings.env = settings.env || {};
160
- clearModelEnv(settings.env);
164
+ clearModelEnv(settings.env, "override");
161
165
  if (primaryModel?.trim()) {
162
166
  settings.env.ANTHROPIC_MODEL = primaryModel.trim();
163
167
  }
@@ -252,7 +256,10 @@ function getExistingModelConfig() {
252
256
  if (!settings) {
253
257
  return null;
254
258
  }
255
- const hasModelEnv = MODEL_ENV_KEYS.some((key) => settings.env?.[key]);
259
+ const hasModelEnv = MODEL_ENV_KEYS.some((key) => {
260
+ const value = settings.env?.[key];
261
+ return value !== void 0 && value !== null && value !== "";
262
+ });
256
263
  if (hasModelEnv) {
257
264
  return "custom";
258
265
  }
@@ -28,6 +28,33 @@ import { doctor } from './doctor.mjs';
28
28
  import { uninstall } from './uninstall.mjs';
29
29
  import { update } from './update.mjs';
30
30
 
31
+ const DEFAULT_MODEL_CHOICES = [
32
+ {
33
+ nameKey: "configuration:defaultModelOption",
34
+ fallback: "Default - Let Claude Code choose",
35
+ value: "default"
36
+ },
37
+ {
38
+ nameKey: "configuration:opusModelOption",
39
+ fallback: "Opus - Only use opus, high token consumption, use with caution",
40
+ value: "opus"
41
+ },
42
+ {
43
+ nameKey: "configuration:sonnetModelOption",
44
+ fallback: "Sonnet - Recommended balanced model for daily coding",
45
+ value: "sonnet"
46
+ },
47
+ {
48
+ nameKey: "configuration:sonnet1mModelOption",
49
+ fallback: "Sonnet 1M - 1M context version",
50
+ value: "sonnet[1m]"
51
+ },
52
+ {
53
+ nameKey: "configuration:customModelOption",
54
+ fallback: "Custom - Specify custom model names",
55
+ value: "custom"
56
+ }
57
+ ];
31
58
  async function handleCancellation() {
32
59
  ensureI18nInitialized();
33
60
  console.log(a.yellow(i18n.t("common:cancelled")));
@@ -271,25 +298,13 @@ ${a.green(`\u2139 ${i18n.t("configuration:existingModelConfig") || "Existing mod
271
298
  type: "list",
272
299
  name: "model",
273
300
  message: i18n.t("configuration:selectDefaultModel") || "Select default model",
274
- choices: addNumbersToChoices([
275
- {
276
- name: i18n.t("configuration:defaultModelOption") || "Default - Let Claude Code choose",
277
- value: "default"
278
- },
279
- {
280
- name: i18n.t("configuration:opusModelOption") || "Opus - Only use opus, high token consumption, use with caution",
281
- value: "opus"
282
- },
283
- {
284
- name: i18n.t("configuration:sonnet1mModelOption") || "Sonnet 1M - 1M context version",
285
- value: "sonnet[1m]"
286
- },
287
- {
288
- name: i18n.t("configuration:customModelOption") || "Custom - Specify custom model names",
289
- value: "custom"
290
- }
291
- ]),
292
- default: existingModel ? ["default", "opus", "sonnet[1m]", "custom"].indexOf(existingModel) : 0
301
+ choices: addNumbersToChoices(
302
+ DEFAULT_MODEL_CHOICES.map((choice) => ({
303
+ name: i18n.t(choice.nameKey) || choice.fallback,
304
+ value: choice.value
305
+ }))
306
+ ),
307
+ default: existingModel ? DEFAULT_MODEL_CHOICES.findIndex((choice) => choice.value === existingModel) : 0
293
308
  });
294
309
  if (!model) {
295
310
  await handleCancellation();
@@ -775,6 +790,7 @@ ${ansis2.bold(i18n.t("memory:memoryContent"))}`);
775
790
 
776
791
  const features = {
777
792
  __proto__: null,
793
+ DEFAULT_MODEL_CHOICES: DEFAULT_MODEL_CHOICES,
778
794
  changeScriptLanguageFeature: changeScriptLanguageFeature,
779
795
  configureAiMemoryFeature: configureAiMemoryFeature,
780
796
  configureApiFeature: configureApiFeature,
@@ -1,3 +1,3 @@
1
- const version = "13.3.13";
1
+ const version = "13.3.15";
2
2
 
3
3
  export { version };
package/dist/cli.mjs CHANGED
@@ -1824,6 +1824,54 @@ ${ansis.yellow("By Status:")}`);
1824
1824
  };
1825
1825
  }
1826
1826
  },
1827
+ {
1828
+ name: "brain-status",
1829
+ description: "Brain capability routing and telemetry stats",
1830
+ aliases: ["bs"],
1831
+ tier: "core",
1832
+ options: [
1833
+ { flags: "--detailed, -d", description: "Show detailed statistics" },
1834
+ { flags: "--json, -j", description: "Output as JSON" }
1835
+ ],
1836
+ loader: async () => {
1837
+ const { brainStatusCommand } = await import('./chunks/brain-status.mjs');
1838
+ return async (options) => {
1839
+ await brainStatusCommand({
1840
+ detailed: options.detailed,
1841
+ json: options.json
1842
+ });
1843
+ };
1844
+ }
1845
+ },
1846
+ {
1847
+ name: "brain-config",
1848
+ description: "Configure Brain capability routing system",
1849
+ aliases: ["bc"],
1850
+ tier: "core",
1851
+ options: [
1852
+ { flags: "--preference, -p <level>", description: "Set capability preference (1-5)" },
1853
+ { flags: "--threshold, -t <value>", description: "Set auto-subagent threshold (1-10)" },
1854
+ { flags: "--max-agents, -m <count>", description: "Set max parallel agents" },
1855
+ { flags: "--telemetry <on|off>", description: "Enable/disable telemetry" },
1856
+ { flags: "--reasoning <on|off>", description: "Enable/disable reasoning display" },
1857
+ { flags: "--show, -s", description: "Show current configuration" },
1858
+ { flags: "--reset", description: "Reset to default configuration" }
1859
+ ],
1860
+ loader: async () => {
1861
+ const { brainConfigCommand } = await import('./chunks/brain-config.mjs');
1862
+ return async (options) => {
1863
+ await brainConfigCommand({
1864
+ preference: options.preference ? parseFloat(options.preference) : void 0,
1865
+ threshold: options.threshold ? parseFloat(options.threshold) : void 0,
1866
+ maxAgents: options.maxAgents ? parseInt(options.maxAgents, 10) : void 0,
1867
+ telemetry: options.telemetry,
1868
+ reasoning: options.reasoning,
1869
+ show: options.show,
1870
+ reset: options.reset
1871
+ });
1872
+ };
1873
+ }
1874
+ },
1827
1875
  // ==================== Plugin Management ====================
1828
1876
  {
1829
1877
  name: "add <source>",
@@ -41,6 +41,7 @@
41
41
  "openSettingsJsonDesc": "Advanced user customization",
42
42
  "openingSettingsJson": "Opening settings.json...",
43
43
  "opusModelOption": "Opus - Only use opus, high token consumption, use with caution",
44
+ "sonnetModelOption": "Sonnet - Recommended balanced model for daily coding",
44
45
  "sonnet1mModelOption": "Sonnet 1M - 1M context version",
45
46
  "outputStyleInstalled": "Output styles installed successfully",
46
47
  "outputStyles.default.description": "Claude completes coding tasks efficiently and provides concise responses (Claude Code built-in)",
@@ -41,6 +41,7 @@
41
41
  "openSettingsJsonDesc": "高级用户自定义",
42
42
  "openingSettingsJson": "正在打开 settings.json...",
43
43
  "opusModelOption": "Opus - 只用opus,token消耗高,慎用",
44
+ "sonnetModelOption": "Sonnet - 日常编码推荐的平衡模型",
44
45
  "sonnet1mModelOption": "Sonnet 1M - 1M上下文版本",
45
46
  "outputStyleInstalled": "输出风格安装成功",
46
47
  "outputStyles.default.description": "完成编码任务时高效且提供简洁响应 (Claude Code自带)",
@@ -0,0 +1,414 @@
1
+ import { existsSync, mkdirSync } from 'node:fs';
2
+ import { appendFile, readFile } from 'node:fs/promises';
3
+ import { homedir } from 'node:os';
4
+ import { j as join } from './ccjk.bQ7Dh1g4.mjs';
5
+
6
+ class BrainTelemetry {
7
+ logPath;
8
+ constructor(logPath) {
9
+ const ccjkDir = join(homedir(), ".ccjk");
10
+ if (!existsSync(ccjkDir)) {
11
+ mkdirSync(ccjkDir, { recursive: true });
12
+ }
13
+ this.logPath = logPath ?? join(ccjkDir, "task-decision-log.jsonl");
14
+ }
15
+ /**
16
+ * 记录任务执行
17
+ */
18
+ async logTask(log) {
19
+ const line = JSON.stringify({
20
+ ...log,
21
+ timestamp: log.timestamp || (/* @__PURE__ */ new Date()).toISOString()
22
+ });
23
+ await appendFile(this.logPath, `${line}
24
+ `, "utf-8");
25
+ const stats = await this.getStats();
26
+ if (stats.totalTasks % 10 === 0) {
27
+ await this.analyzeAndUpdate();
28
+ }
29
+ }
30
+ /**
31
+ * 读取所有日志
32
+ */
33
+ async readLogs() {
34
+ if (!existsSync(this.logPath)) {
35
+ return [];
36
+ }
37
+ const content = await readFile(this.logPath, "utf-8");
38
+ const lines = content.trim().split("\n").filter(Boolean);
39
+ return lines.map((line) => JSON.parse(line));
40
+ }
41
+ /**
42
+ * 获取统计数据
43
+ */
44
+ async getStats() {
45
+ const logs = await this.readLogs();
46
+ if (logs.length === 0) {
47
+ return {
48
+ totalTasks: 0,
49
+ byLevel: {},
50
+ recentTrend: [],
51
+ recommendations: []
52
+ };
53
+ }
54
+ const byLevel = {};
55
+ for (const log of logs) {
56
+ if (!byLevel[log.level]) {
57
+ byLevel[log.level] = [];
58
+ }
59
+ byLevel[log.level].push(log);
60
+ }
61
+ const levelStats = {};
62
+ for (const [level, levelLogs] of Object.entries(byLevel)) {
63
+ const successCount = levelLogs.filter((l) => l.success).length;
64
+ const totalDuration = levelLogs.reduce((sum, l) => sum + l.duration, 0);
65
+ const totalScore = levelLogs.reduce((sum, l) => sum + l.effectScore, 0);
66
+ levelStats[Number(level)] = {
67
+ count: levelLogs.length,
68
+ successRate: successCount / levelLogs.length,
69
+ avgDuration: totalDuration / levelLogs.length,
70
+ avgEffectScore: totalScore / levelLogs.length
71
+ };
72
+ }
73
+ const thirtyDaysAgo = /* @__PURE__ */ new Date();
74
+ thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
75
+ const recentLogs = logs.filter(
76
+ (log) => new Date(log.timestamp) >= thirtyDaysAgo
77
+ );
78
+ const dailyStats = /* @__PURE__ */ new Map();
79
+ for (const log of recentLogs) {
80
+ const date = log.timestamp.split("T")[0];
81
+ const stats = dailyStats.get(date) ?? { count: 0, success: 0 };
82
+ stats.count++;
83
+ if (log.success) stats.success++;
84
+ dailyStats.set(date, stats);
85
+ }
86
+ const recentTrend = Array.from(dailyStats.entries()).map(([date, stats]) => ({
87
+ date,
88
+ count: stats.count,
89
+ successRate: stats.success / stats.count
90
+ })).sort((a, b) => a.date.localeCompare(b.date));
91
+ const recommendations = this.generateRecommendations(levelStats);
92
+ return {
93
+ totalTasks: logs.length,
94
+ byLevel: levelStats,
95
+ recentTrend,
96
+ recommendations
97
+ };
98
+ }
99
+ /**
100
+ * 生成优化建议
101
+ */
102
+ generateRecommendations(levelStats) {
103
+ const recommendations = [];
104
+ for (const [level, stats] of Object.entries(levelStats)) {
105
+ const levelNum = Number(level);
106
+ if (stats.successRate < 0.8) {
107
+ recommendations.push(
108
+ `Level ${levelNum} \u6210\u529F\u7387\u504F\u4F4E (${(stats.successRate * 100).toFixed(1)}%)\uFF0C\u8003\u8651\u964D\u7EA7\u5230\u66F4\u7B80\u5355\u7684\u5C42\u7EA7`
109
+ );
110
+ }
111
+ if (stats.avgEffectScore < 7) {
112
+ recommendations.push(
113
+ `Level ${levelNum} \u6548\u679C\u8BC4\u5206\u504F\u4F4E (${stats.avgEffectScore.toFixed(1)}/10)\uFF0C\u9700\u8981\u4F18\u5316\u6267\u884C\u7B56\u7565`
114
+ );
115
+ }
116
+ if (levelNum <= 2 && stats.avgDuration > 30) {
117
+ recommendations.push(
118
+ `Level ${levelNum} \u5E73\u5747\u8017\u65F6\u8FC7\u957F (${stats.avgDuration.toFixed(1)}s)\uFF0C\u8003\u8651\u4F18\u5316\u6216\u5347\u7EA7`
119
+ );
120
+ }
121
+ }
122
+ return recommendations;
123
+ }
124
+ /**
125
+ * 分析并更新方法论
126
+ */
127
+ async analyzeAndUpdate() {
128
+ const stats = await this.getStats();
129
+ if (stats.recommendations.length > 0) {
130
+ console.log("\n\u{1F4CA} Brain Telemetry Analysis:");
131
+ for (const rec of stats.recommendations) {
132
+ console.log(` \u{1F4A1} ${rec}`);
133
+ }
134
+ console.log();
135
+ }
136
+ }
137
+ /**
138
+ * 清空日志
139
+ */
140
+ async clear() {
141
+ if (existsSync(this.logPath)) {
142
+ await appendFile(this.logPath, "", "utf-8");
143
+ }
144
+ }
145
+ }
146
+ let globalTelemetry = null;
147
+ function getTelemetry() {
148
+ if (!globalTelemetry) {
149
+ globalTelemetry = new BrainTelemetry();
150
+ }
151
+ return globalTelemetry;
152
+ }
153
+
154
+ function decideCapability(context) {
155
+ const { input, conversationTurns, hasUncommittedChanges, recentFailures } = context;
156
+ const lower = input.toLowerCase();
157
+ if (lower.includes("\u89E3\u91CA") || lower.includes("\u4EC0\u4E48\u662F") || lower.includes("\u4E3A\u4EC0\u4E48") || lower.includes("\u5982\u4F55\u7406\u89E3")) {
158
+ return {
159
+ level: 0,
160
+ reasoning: "\u7EAF\u6587\u672C\u63A8\u7406\u4EFB\u52A1",
161
+ expectedSteps: 1,
162
+ expectedDuration: 5,
163
+ complexity: 1
164
+ };
165
+ }
166
+ if (lower.startsWith("/") || lower.includes("commit") || lower.includes("review")) {
167
+ return {
168
+ level: 1,
169
+ reasoning: "Skill\u5FEB\u6377\u6307\u4EE4",
170
+ expectedSteps: 1,
171
+ expectedDuration: 10,
172
+ complexity: 2
173
+ };
174
+ }
175
+ if ((lower.includes("\u4FEE\u6539") || lower.includes("fix") || lower.includes("\u66F4\u65B0")) && !lower.includes("\u6240\u6709") && !lower.includes("\u6279\u91CF")) {
176
+ return {
177
+ level: 2,
178
+ reasoning: "\u5355\u6587\u4EF6\u4FEE\u6539",
179
+ expectedSteps: 3,
180
+ expectedDuration: 20,
181
+ complexity: 3
182
+ };
183
+ }
184
+ if (lower.includes("\u91CD\u6784") || lower.includes("\u6279\u91CF") || lower.includes("\u6240\u6709") || lower.includes("\u6DFB\u52A0") && lower.includes("\u529F\u80FD")) {
185
+ return {
186
+ level: 3,
187
+ reasoning: "\u591A\u6587\u4EF6\u534F\u8C03\u64CD\u4F5C",
188
+ expectedSteps: 8,
189
+ expectedDuration: 60,
190
+ complexity: 6
191
+ };
192
+ }
193
+ if (lower.includes("\u5206\u6790\u6574\u4E2A") || lower.includes("\u5168\u5C40") || lower.includes("\u67B6\u6784") || lower.includes("\u8FC1\u79FB")) {
194
+ return {
195
+ level: 4,
196
+ reasoning: "\u590D\u6742\u4EFB\u52A1\uFF0C\u5EFA\u8BAEsubagent",
197
+ expectedSteps: 15,
198
+ expectedDuration: 180,
199
+ complexity: 8
200
+ };
201
+ }
202
+ if (lower.includes("\u5B8C\u5168\u91CD\u5199") || lower.includes("\u4ECE\u96F6\u5F00\u59CB") || lower.includes("\u5927\u89C4\u6A21")) {
203
+ return {
204
+ level: 5,
205
+ reasoning: "\u6781\u590D\u6742\u4EFB\u52A1\uFF0C\u5FC5\u987Bsubagent",
206
+ expectedSteps: 30,
207
+ expectedDuration: 600,
208
+ complexity: 10
209
+ };
210
+ }
211
+ const complexity = Math.min(
212
+ 10,
213
+ 3 + conversationTurns * 0.5 + recentFailures * 2 + (hasUncommittedChanges ? 1 : 0)
214
+ );
215
+ if (complexity >= 8) {
216
+ return {
217
+ level: 4,
218
+ reasoning: "\u4E0A\u4E0B\u6587\u590D\u6742\u5EA6\u9AD8",
219
+ expectedSteps: 12,
220
+ expectedDuration: 120,
221
+ complexity: Math.round(complexity)
222
+ };
223
+ }
224
+ if (complexity >= 5) {
225
+ return {
226
+ level: 3,
227
+ reasoning: "\u4E2D\u7B49\u590D\u6742\u5EA6\u4EFB\u52A1",
228
+ expectedSteps: 6,
229
+ expectedDuration: 45,
230
+ complexity: Math.round(complexity)
231
+ };
232
+ }
233
+ return {
234
+ level: 2,
235
+ reasoning: "\u6807\u51C6\u64CD\u4F5C",
236
+ expectedSteps: 3,
237
+ expectedDuration: 20,
238
+ complexity: Math.round(complexity)
239
+ };
240
+ }
241
+ function getCapabilityName(level) {
242
+ const names = {
243
+ 0: "\u7EAF\u6587\u672C\u63A8\u7406",
244
+ 1: "Skill\u6267\u884C",
245
+ 2: "\u5355\u6587\u4EF6\u64CD\u4F5C",
246
+ 3: "\u591A\u6587\u4EF6\u534F\u8C03",
247
+ 4: "\u590D\u6742\u4EFB\u52A1",
248
+ 5: "\u6781\u590D\u6742\u4EFB\u52A1"
249
+ };
250
+ return names[level];
251
+ }
252
+
253
+ class SmartRouter {
254
+ config;
255
+ recentFailures = 0;
256
+ constructor(config = {}) {
257
+ this.config = {
258
+ capabilityPreference: config.capabilityPreference ?? 2,
259
+ autoSubagentThreshold: config.autoSubagentThreshold ?? 7,
260
+ maxParallelAgents: config.maxParallelAgents ?? 3,
261
+ enableTelemetry: config.enableTelemetry ?? true,
262
+ showReasoning: config.showReasoning ?? true
263
+ };
264
+ }
265
+ /**
266
+ * 路由任务到合适的能力层级
267
+ */
268
+ async route(input, context = {}) {
269
+ const fullContext = {
270
+ input,
271
+ conversationTurns: context.conversationTurns ?? 0,
272
+ cwd: context.cwd ?? process.cwd(),
273
+ hasUncommittedChanges: context.hasUncommittedChanges ?? false,
274
+ recentFailures: this.recentFailures
275
+ };
276
+ const decision = decideCapability(fullContext);
277
+ const adjustedDecision = this.applyPreference(decision);
278
+ const executionAdvice = this.generateAdvice(adjustedDecision);
279
+ if (this.config.showReasoning) {
280
+ console.log(`
281
+ [Brain Router] \u51B3\u7B56: ${getCapabilityName(adjustedDecision.level)}`);
282
+ console.log(` \u7406\u7531: ${adjustedDecision.reasoning}`);
283
+ console.log(` \u9884\u671F: ${adjustedDecision.expectedSteps}\u6B65 / ${adjustedDecision.expectedDuration}s`);
284
+ console.log(` \u590D\u6742\u5EA6: ${adjustedDecision.complexity}/10
285
+ `);
286
+ }
287
+ return {
288
+ decision: adjustedDecision,
289
+ shouldExecute: this.shouldExecute(adjustedDecision),
290
+ executionAdvice
291
+ };
292
+ }
293
+ /**
294
+ * 应用用户偏好调整决策
295
+ */
296
+ applyPreference(decision) {
297
+ const { capabilityPreference, autoSubagentThreshold } = this.config;
298
+ if (capabilityPreference <= 2 && decision.level >= 3) {
299
+ if (decision.complexity < autoSubagentThreshold) {
300
+ return {
301
+ ...decision,
302
+ level: 2,
303
+ // 降级到主Agent
304
+ reasoning: `${decision.reasoning} (\u7528\u6237\u504F\u597D\u7B80\u5355\uFF0C\u964D\u7EA7\u5230\u4E3BAgent)`
305
+ };
306
+ }
307
+ }
308
+ if (capabilityPreference >= 4 && decision.level === 2) {
309
+ if (decision.complexity >= 5) {
310
+ return {
311
+ ...decision,
312
+ level: 3,
313
+ // 升级到Subagent
314
+ reasoning: `${decision.reasoning} (\u7528\u6237\u504F\u597D\u590D\u6742\uFF0C\u5347\u7EA7\u5230Subagent)`
315
+ };
316
+ }
317
+ }
318
+ return decision;
319
+ }
320
+ /**
321
+ * 判断是否应该执行
322
+ */
323
+ shouldExecute(decision) {
324
+ if (decision.level <= 1) return true;
325
+ if (decision.level === 2) return true;
326
+ if (decision.level === 3) {
327
+ return decision.complexity >= this.config.autoSubagentThreshold;
328
+ }
329
+ return false;
330
+ }
331
+ /**
332
+ * 生成执行建议
333
+ */
334
+ generateAdvice(decision) {
335
+ switch (decision.level) {
336
+ case 0:
337
+ return "\u76F4\u63A5\u56DE\u7B54\uFF0C\u65E0\u9700\u5DE5\u5177\u8C03\u7528";
338
+ case 1:
339
+ return "\u4F7F\u7528Skill\u6267\u884C\uFF0C\u5355\u6B65\u5B8C\u6210";
340
+ case 2:
341
+ return "\u4E3BAgent\u5904\u7406\uFF0C\u9884\u8BA13-5\u6B65\u5B8C\u6210";
342
+ case 3:
343
+ return `\u542F\u52A8Subagent\uFF0C\u9884\u8BA1${decision.expectedSteps}\u6B65\u5B8C\u6210`;
344
+ case 4:
345
+ return "\u9700\u8981\u591AAgent\u534F\u4F5C\uFF0C\u5EFA\u8BAE\u7528\u6237\u786E\u8BA4";
346
+ case 5:
347
+ return "\u9700\u8981\u957F\u5BFFSession\uFF0C\u5EFA\u8BAE\u7528\u6237\u786E\u8BA4";
348
+ default:
349
+ return "\u672A\u77E5\u5C42\u7EA7";
350
+ }
351
+ }
352
+ /**
353
+ * 记录任务执行结果
354
+ */
355
+ async recordExecution(decision, result) {
356
+ if (!this.config.enableTelemetry) return;
357
+ const telemetry = getTelemetry();
358
+ const log = {
359
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
360
+ task: decision.reasoning,
361
+ level: decision.level,
362
+ actualSteps: result.actualSteps,
363
+ duration: result.duration,
364
+ success: result.success,
365
+ effectScore: result.effectScore,
366
+ recommendation: this.generateRecommendation(decision, result)
367
+ };
368
+ await telemetry.logTask(log);
369
+ if (!result.success) {
370
+ this.recentFailures++;
371
+ } else {
372
+ this.recentFailures = 0;
373
+ }
374
+ }
375
+ /**
376
+ * 生成下次建议
377
+ */
378
+ generateRecommendation(decision, result) {
379
+ if (!result.success) {
380
+ return `\u5931\u8D25\uFF0C\u4E0B\u6B21\u8003\u8651\u5347\u7EA7\u5230Level ${decision.level + 1}`;
381
+ }
382
+ if (result.effectScore < 7) {
383
+ return `\u6548\u679C\u4E00\u822C\uFF0C\u4E0B\u6B21\u8003\u8651\u8C03\u6574\u7B56\u7565`;
384
+ }
385
+ return `\u6548\u679C\u826F\u597D\uFF0C\u7EE7\u7EED\u4F7F\u7528Level ${decision.level}`;
386
+ }
387
+ /**
388
+ * 获取配置
389
+ */
390
+ getConfig() {
391
+ return { ...this.config };
392
+ }
393
+ /**
394
+ * 更新配置
395
+ */
396
+ updateConfig(config) {
397
+ this.config = { ...this.config, ...config };
398
+ }
399
+ /**
400
+ * 重置失败计数
401
+ */
402
+ resetFailures() {
403
+ this.recentFailures = 0;
404
+ }
405
+ }
406
+ let globalRouter = null;
407
+ function getSmartRouter() {
408
+ if (!globalRouter) {
409
+ globalRouter = new SmartRouter();
410
+ }
411
+ return globalRouter;
412
+ }
413
+
414
+ export { getSmartRouter as a, getCapabilityName as b, getTelemetry as g };
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "ccjk",
3
3
  "type": "module",
4
- "version": "13.3.13",
5
- "packageManager": "pnpm@10.17.1",
4
+ "version": "13.3.15",
6
5
  "description": "Turn Claude Code into a production-ready AI dev environment with one-command setup, persistent memory, MCP automation, cloud sync, and zero-config browser workflows.",
7
6
  "author": {
8
7
  "name": "CCJK Team",
@@ -81,71 +80,6 @@
81
80
  "engines": {
82
81
  "node": ">=20"
83
82
  },
84
- "scripts": {
85
- "dev": "tsx ./src/cli.ts",
86
- "build": "unbuild",
87
- "start": "node bin/ccjk.mjs",
88
- "typecheck": "tsc --noEmit",
89
- "release:verify": "node scripts/release-verify.mjs",
90
- "release:verify:full": "node scripts/release-verify.mjs --with-tests",
91
- "prepublishOnly": "node scripts/validate-prepublish.mjs && pnpm contract:check && pnpm build",
92
- "lint": "eslint",
93
- "lint:fix": "eslint --fix",
94
- "test": "vitest",
95
- "test:ui": "vitest --ui",
96
- "test:coverage": "vitest run --coverage",
97
- "test:run": "vitest run",
98
- "test:watch": "vitest watch",
99
- "test:e2e": "NODE_ENV=test vitest --config vitest.e2e.config.ts",
100
- "test:e2e:run": "NODE_ENV=test vitest run --config vitest.e2e.config.ts",
101
- "test:e2e:ui": "NODE_ENV=test vitest --config vitest.e2e.config.ts --ui",
102
- "test:e2e:coverage": "NODE_ENV=test vitest run --config vitest.e2e.config.ts --coverage",
103
- "test:e2e:debug": "NODE_ENV=test CCJK_E2E_DEBUG=true vitest --config vitest.e2e.config.ts",
104
- "test:v2": "vitest --config vitest.config.v2.ts",
105
- "test:v2:ui": "vitest --config vitest.config.v2.ts --ui",
106
- "test:v2:coverage": "vitest run --config vitest.config.v2.ts --coverage",
107
- "test:v2:run": "vitest run --config vitest.config.v2.ts",
108
- "test:v2:watch": "vitest watch --config vitest.config.v2.ts",
109
- "test:integration": "NODE_ENV=test vitest --config vitest.integration.config.ts",
110
- "test:integration:run": "NODE_ENV=test vitest run --config vitest.integration.config.ts",
111
- "test:integration:ui": "NODE_ENV=test vitest --config vitest.integration.config.ts --ui",
112
- "test:integration:coverage": "NODE_ENV=test vitest run --config vitest.integration.config.ts --coverage",
113
- "prepare": "husky",
114
- "format": "prettier --write src/**/*.ts",
115
- "prepublish:fix": "node scripts/fix-package-catalog.mjs",
116
- "cleanup": "node scripts/cleanup.js",
117
- "cleanup:auto": "node scripts/cleanup.js --auto",
118
- "cleanup:dry": "node scripts/cleanup.js --dry-run",
119
- "clean": "rm -rf dist coverage .turbo *.tsbuildinfo",
120
- "benchmark:compression": "tsx scripts/benchmark-compression.ts",
121
- "v2:setup": "chmod +x scripts/v2-dev-setup.sh && ./scripts/v2-dev-setup.sh",
122
- "v2:setup:skip-tests": "chmod +x scripts/v2-dev-setup.sh && ./scripts/v2-dev-setup.sh --skip-tests",
123
- "v2:services:up": "docker-compose -f docker-compose.dev.yml up -d",
124
- "v2:services:down": "docker-compose -f docker-compose.dev.yml down",
125
- "v2:services:restart": "docker-compose -f docker-compose.dev.yml restart",
126
- "v2:services:logs": "docker-compose -f docker-compose.dev.yml logs -f",
127
- "v2:services:status": "docker-compose -f docker-compose.dev.yml ps",
128
- "v2:db:reset": "docker-compose -f docker-compose.dev.yml down postgres && docker volume rm ccjk-public_postgres_data && docker-compose -f docker-compose.dev.yml up -d postgres",
129
- "v2:db:migrate": "echo 'Database migration script - to be implemented'",
130
- "v2:db:seed": "echo 'Database seeding script - to be implemented'",
131
- "v2:cache:clear": "docker exec ccjk-redis-dev redis-cli FLUSHALL",
132
- "v2:search:reindex": "curl -X DELETE http://localhost:9200/ccjk_dev* && echo 'Elasticsearch indexes cleared'",
133
- "v2:health": "chmod +x scripts/health-check.sh && ./scripts/health-check.sh",
134
- "v2:dev": "concurrently \"pnpm v2:services:up\" \"pnpm dev\"",
135
- "v2:test:integration": "NODE_ENV=test pnpm test -- --config vitest.integration.config.ts",
136
- "v2:test:e2e": "NODE_ENV=test pnpm test -- --config vitest.e2e.config.ts",
137
- "v2:monitoring:up": "docker-compose -f docker-compose.dev.yml --profile monitoring up -d",
138
- "v2:tracing:up": "docker-compose -f docker-compose.dev.yml --profile tracing up -d",
139
- "v2:clean": "pnpm clean && docker-compose -f docker-compose.dev.yml down -v && docker system prune -f",
140
- "benchmark": "tsx src/v2/__tests__/benchmarks.ts",
141
- "benchmark:save": "tsx src/v2/__tests__/benchmarks.ts && echo 'Results saved to .ccjk/benchmark-results.json'",
142
- "benchmark:detailed": "tsx src/v2/__tests__/benchmarks.ts --detailed",
143
- "benchmark:server": "npx http-server docs/v2 -p 8080 -o dashboard.html",
144
- "benchmark:open": "open docs/v2/dashboard.html || xdg-open docs/v2/dashboard.html || start docs/v2/dashboard.html",
145
- "i18n:check": "tsx scripts/check-i18n.ts",
146
- "i18n:report": "tsx scripts/check-i18n.ts --report",
147
- "contract:check": "node scripts/check-remote-contract.mjs"
148
- },
149
83
  "dependencies": {
150
84
  "better-sqlite3": "^12.6.2",
151
85
  "fdir": "^6.5.0",
@@ -208,5 +142,68 @@
208
142
  "unbuild": "^3.6.1",
209
143
  "uuid": "^11.1.0",
210
144
  "vitest": "^3.2.4"
145
+ },
146
+ "scripts": {
147
+ "dev": "tsx ./src/cli.ts",
148
+ "build": "unbuild",
149
+ "start": "node bin/ccjk.mjs",
150
+ "typecheck": "tsc --noEmit",
151
+ "release:verify": "node scripts/release-verify.mjs",
152
+ "release:verify:full": "node scripts/release-verify.mjs --with-tests",
153
+ "lint": "eslint",
154
+ "lint:fix": "eslint --fix",
155
+ "test": "vitest",
156
+ "test:ui": "vitest --ui",
157
+ "test:coverage": "vitest run --coverage",
158
+ "test:run": "vitest run",
159
+ "test:watch": "vitest watch",
160
+ "test:e2e": "NODE_ENV=test vitest --config vitest.e2e.config.ts",
161
+ "test:e2e:run": "NODE_ENV=test vitest run --config vitest.e2e.config.ts",
162
+ "test:e2e:ui": "NODE_ENV=test vitest --config vitest.e2e.config.ts --ui",
163
+ "test:e2e:coverage": "NODE_ENV=test vitest run --config vitest.e2e.config.ts --coverage",
164
+ "test:e2e:debug": "NODE_ENV=test CCJK_E2E_DEBUG=true vitest --config vitest.e2e.config.ts",
165
+ "test:v2": "vitest --config vitest.config.v2.ts",
166
+ "test:v2:ui": "vitest --config vitest.config.v2.ts --ui",
167
+ "test:v2:coverage": "vitest run --config vitest.config.v2.ts --coverage",
168
+ "test:v2:run": "vitest run --config vitest.config.v2.ts",
169
+ "test:v2:watch": "vitest watch --config vitest.config.v2.ts",
170
+ "test:integration": "NODE_ENV=test vitest --config vitest.integration.config.ts",
171
+ "test:integration:run": "NODE_ENV=test vitest run --config vitest.integration.config.ts",
172
+ "test:integration:ui": "NODE_ENV=test vitest --config vitest.integration.config.ts --ui",
173
+ "test:integration:coverage": "NODE_ENV=test vitest run --config vitest.integration.config.ts --coverage",
174
+ "format": "prettier --write src/**/*.ts",
175
+ "prepublish:fix": "node scripts/fix-package-catalog.mjs",
176
+ "cleanup": "node scripts/cleanup.js",
177
+ "cleanup:auto": "node scripts/cleanup.js --auto",
178
+ "cleanup:dry": "node scripts/cleanup.js --dry-run",
179
+ "clean": "rm -rf dist coverage .turbo *.tsbuildinfo",
180
+ "benchmark:compression": "tsx scripts/benchmark-compression.ts",
181
+ "v2:setup": "chmod +x scripts/v2-dev-setup.sh && ./scripts/v2-dev-setup.sh",
182
+ "v2:setup:skip-tests": "chmod +x scripts/v2-dev-setup.sh && ./scripts/v2-dev-setup.sh --skip-tests",
183
+ "v2:services:up": "docker-compose -f docker-compose.dev.yml up -d",
184
+ "v2:services:down": "docker-compose -f docker-compose.dev.yml down",
185
+ "v2:services:restart": "docker-compose -f docker-compose.dev.yml restart",
186
+ "v2:services:logs": "docker-compose -f docker-compose.dev.yml logs -f",
187
+ "v2:services:status": "docker-compose -f docker-compose.dev.yml ps",
188
+ "v2:db:reset": "docker-compose -f docker-compose.dev.yml down postgres && docker volume rm ccjk-public_postgres_data && docker-compose -f docker-compose.dev.yml up -d postgres",
189
+ "v2:db:migrate": "echo 'Database migration script - to be implemented'",
190
+ "v2:db:seed": "echo 'Database seeding script - to be implemented'",
191
+ "v2:cache:clear": "docker exec ccjk-redis-dev redis-cli FLUSHALL",
192
+ "v2:search:reindex": "curl -X DELETE http://localhost:9200/ccjk_dev* && echo 'Elasticsearch indexes cleared'",
193
+ "v2:health": "chmod +x scripts/health-check.sh && ./scripts/health-check.sh",
194
+ "v2:dev": "concurrently \"pnpm v2:services:up\" \"pnpm dev\"",
195
+ "v2:test:integration": "NODE_ENV=test pnpm test -- --config vitest.integration.config.ts",
196
+ "v2:test:e2e": "NODE_ENV=test pnpm test -- --config vitest.e2e.config.ts",
197
+ "v2:monitoring:up": "docker-compose -f docker-compose.dev.yml --profile monitoring up -d",
198
+ "v2:tracing:up": "docker-compose -f docker-compose.dev.yml --profile tracing up -d",
199
+ "v2:clean": "pnpm clean && docker-compose -f docker-compose.dev.yml down -v && docker system prune -f",
200
+ "benchmark": "tsx src/v2/__tests__/benchmarks.ts",
201
+ "benchmark:save": "tsx src/v2/__tests__/benchmarks.ts && echo 'Results saved to .ccjk/benchmark-results.json'",
202
+ "benchmark:detailed": "tsx src/v2/__tests__/benchmarks.ts --detailed",
203
+ "benchmark:server": "npx http-server docs/v2 -p 8080 -o dashboard.html",
204
+ "benchmark:open": "open docs/v2/dashboard.html || xdg-open docs/v2/dashboard.html || start docs/v2/dashboard.html",
205
+ "i18n:check": "tsx scripts/check-i18n.ts",
206
+ "i18n:report": "tsx scripts/check-i18n.ts --report",
207
+ "contract:check": "node scripts/check-remote-contract.mjs"
211
208
  }
212
- }
209
+ }