ccjk 12.0.9 → 12.0.10

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.
@@ -6,7 +6,7 @@ import { c as resolve } from '../shared/ccjk.bQ7Dh1g4.mjs';
6
6
  import { e as executionTracer } from '../shared/ccjk.CePkJq2S.mjs';
7
7
  import { t as taskPersistence } from '../shared/ccjk.BFxsJM0k.mjs';
8
8
  import { contextLoader } from './context-loader.mjs';
9
- import { g as getGlobalConvoyManager } from './convoy-manager.mjs';
9
+ import { S as SessionIntelligence, g as getGlobalConvoyManager } from './convoy-manager.mjs';
10
10
  import '../shared/ccjk.BAGoDD49.mjs';
11
11
  import 'node:process';
12
12
  import '../shared/ccjk.Cjgrln_h.mjs';
@@ -16,11 +16,12 @@ import 'better-sqlite3';
16
16
  import 'node:fs';
17
17
  import 'tinyglobby';
18
18
  import '../shared/ccjk.BxSmJ8B7.mjs';
19
+ import 'node:child_process';
20
+ import 'node:fs/promises';
19
21
  import 'node:os';
22
+ import 'node:path';
20
23
  import './main.mjs';
21
24
  import 'module';
22
- import 'node:child_process';
23
- import 'node:path';
24
25
  import 'node:stream';
25
26
  import 'node:readline';
26
27
 
@@ -2675,18 +2676,23 @@ class BrainOrchestrator extends EventEmitter {
2675
2676
  task.metadata.custom = {};
2676
2677
  }
2677
2678
  task.metadata.custom.context = contextLoader.formatForLLM(context);
2679
+ const intel = SessionIntelligence.getInstance();
2680
+ intel.recordMessage("user", task.name);
2678
2681
  try {
2679
2682
  this.state.status = "planning";
2683
+ intel.updatePhase("exploring");
2680
2684
  this.log(`Starting orchestration for task: ${task.name}`);
2681
2685
  executionTracer.logDecision("orchestrator", `Planning task: ${task.name}`);
2682
2686
  const plan = await this.createPlan(task, strategy);
2683
2687
  this.emit("plan:created", plan);
2684
2688
  this.state.status = "executing";
2689
+ intel.updatePhase("executing");
2685
2690
  this.state.currentPlan = plan;
2686
2691
  this.state.startTime = (/* @__PURE__ */ new Date()).toISOString();
2687
2692
  this.emit("plan:started", plan.id);
2688
2693
  const result = await this.executePlan(plan);
2689
2694
  this.state.status = "idle";
2695
+ intel.updatePhase("reviewing");
2690
2696
  this.emit("plan:completed", result);
2691
2697
  executionTracer.logAgentEnd("orchestrator", { success: true });
2692
2698
  executionTracer.endSession(sessionId);
@@ -12,7 +12,7 @@ const __dirname = dirname(__filename);
12
12
  const CLOUD_CONFIG_DIR = join(CCJK_CONFIG_DIR, "cloud");
13
13
  const DEVICE_CONFIG_FILE = join(CLOUD_CONFIG_DIR, "device.json");
14
14
  const CLOUD_STATE_FILE = join(CLOUD_CONFIG_DIR, "state.json");
15
- const CLOUD_API_ENDPOINT = "https://api.api.claudehome.cn/v1";
15
+ const CLOUD_API_ENDPOINT = "https://api.claudehome.cn/api/v1";
16
16
  const AUTO_SYNC_INTERVAL = 30 * 60 * 1e3;
17
17
  const AUTO_UPGRADE_CHECK_INTERVAL = 6 * 60 * 60 * 1e3;
18
18
  function generateDeviceFingerprint() {
@@ -343,23 +343,30 @@ async function boost(options = {}) {
343
343
  console.log(a.gray("\n--dry-run: No changes applied.\n"));
344
344
  return;
345
345
  }
346
+ let selectedActions = actions;
346
347
  if (!options.yes) {
347
348
  const { default: inquirer } = await import('./index3.mjs').then(function (n) { return n.c; });
348
- const { confirm } = await inquirer.prompt([{
349
- type: "confirm",
350
- name: "confirm",
351
- message: `Apply ${actions.length} optimization${actions.length > 1 ? "s" : ""}?`,
352
- default: true
349
+ const { selected } = await inquirer.prompt([{
350
+ type: "checkbox",
351
+ name: "selected",
352
+ message: "Select optimizations to apply:",
353
+ choices: actions.map((a, i) => ({
354
+ name: `${a.rec.priority === "high" ? "[HIGH] " : "[MED] "}${a.label}`,
355
+ value: i,
356
+ checked: a.rec.priority === "high"
357
+ // pre-check high priority
358
+ }))
353
359
  }]);
354
- if (!confirm) {
355
- console.log(a.gray("\nCancelled.\n"));
360
+ if (!selected.length) {
361
+ console.log(a.gray("\nNothing selected. Cancelled.\n"));
356
362
  return;
357
363
  }
364
+ selectedActions = selected.map((i) => actions[i]);
358
365
  }
359
366
  console.log("");
360
367
  let applied = 0;
361
368
  let failed = 0;
362
- for (const action of actions) {
369
+ for (const action of selectedActions) {
363
370
  spinner = ora(action.label).start();
364
371
  try {
365
372
  const result = await executeRecommendation(action.rec);
@@ -84,17 +84,19 @@ function validateAgentDefinition(agent) {
84
84
 
85
85
  const _dirname = dirname(fileURLToPath(import.meta.url));
86
86
  const AGENT_TEMPLATES_DIR = join(_dirname, "..", "templates", "agents");
87
- const AGENT_TEMPLATES_DIR_FALLBACK = join(process.cwd(), "templates", "agents");
87
+ const AGENT_TEMPLATES_DIR_DEV = join(_dirname, "..", "..", "templates", "agents");
88
88
  function getAgentTemplatesDir() {
89
89
  if (existsSync(AGENT_TEMPLATES_DIR)) {
90
90
  return AGENT_TEMPLATES_DIR;
91
91
  }
92
- return AGENT_TEMPLATES_DIR_FALLBACK;
92
+ if (existsSync(AGENT_TEMPLATES_DIR_DEV)) {
93
+ return AGENT_TEMPLATES_DIR_DEV;
94
+ }
95
+ return join(process.cwd(), "templates", "agents");
93
96
  }
94
97
  async function loadAgentTemplates() {
95
98
  const templatesDir = getAgentTemplatesDir();
96
99
  if (!existsSync(templatesDir)) {
97
- console.warn("Agent templates directory not found:", templatesDir);
98
100
  return [];
99
101
  }
100
102
  const templates = [];
@@ -113,8 +115,8 @@ async function loadAgentTemplates() {
113
115
  mcpServers: template.mcpServers || [],
114
116
  persona: template.persona,
115
117
  capabilities: template.capabilities || [],
118
+ tags: template.metadata?.tags || [],
116
119
  confidence: 0.8,
117
- // Default confidence
118
120
  reason: `Matches project type and includes relevant skills: ${(template.skills || []).join(", ")}`
119
121
  };
120
122
  templates.push(recommendation);
@@ -169,10 +171,11 @@ async function ccjkAgents(options = {}) {
169
171
  (skill) => frameworks.includes(skill) || languages.includes(skill) || projectType.includes(skill)
170
172
  ) || t.capabilities.some(
171
173
  (cap) => frameworks.includes(cap) || languages.includes(cap) || projectType.includes(cap)
174
+ ) || (t.tags || []).some(
175
+ (tag) => frameworks.some((fw) => fw.toLowerCase().includes(tag) || tag.includes(fw.toLowerCase())) || languages.some((lang) => lang.toLowerCase().includes(tag) || tag.includes(lang.toLowerCase())) || projectType.toLowerCase().includes(tag)
172
176
  )
173
177
  );
174
178
  if (recommendations.length === 0) {
175
- consola.warn(isZh ? "\u672A\u627E\u5230\u5408\u9002\u7684\u4EE3\u7406\uFF0C\u4F7F\u7528\u6240\u6709\u6A21\u677F" : "No suitable agents found, using all templates");
176
179
  recommendations = allTemplates;
177
180
  }
178
181
  try {
@@ -36,7 +36,7 @@ async function ccjkSkills(options = {}) {
36
36
  const opts = {
37
37
  lang: options.lang || "en",
38
38
  interactive: options.interactive ?? true,
39
- category: options.category || "custom",
39
+ category: options.category || "",
40
40
  tags: options.tags || [],
41
41
  exclude: options.exclude || [],
42
42
  dryRun: options.dryRun ?? false,
@@ -273,7 +273,7 @@ async function getLocalRecommendations(analysis, _options) {
273
273
  templatePath: "react-patterns.md"
274
274
  });
275
275
  }
276
- if (fwMap.next > 0.5) {
276
+ if ((fwMap["next.js"] || fwMap.next) > 0.5) {
277
277
  skills.push({
278
278
  id: "nextjs-optimization",
279
279
  name: { "en": "Next.js Optimization", "zh-CN": "Next.js \u6027\u80FD\u4F18\u5316" },
@@ -1,13 +1,14 @@
1
1
  import { EventEmitter } from 'node:events';
2
- import { a as getGlobalStateManager, g as getGlobalConvoyManager } from './convoy-manager.mjs';
2
+ import { a as getGlobalStateManager, g as getGlobalConvoyManager, S as SessionIntelligence } from './convoy-manager.mjs';
3
3
  import { n as nanoid } from '../shared/ccjk.BoApaI4j.mjs';
4
4
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
5
5
  import { j as join } from '../shared/ccjk.bQ7Dh1g4.mjs';
6
+ import 'node:child_process';
7
+ import 'node:fs/promises';
6
8
  import 'node:os';
9
+ import 'node:path';
7
10
  import './main.mjs';
8
11
  import 'module';
9
- import 'node:child_process';
10
- import 'node:path';
11
12
  import 'node:process';
12
13
  import 'node:stream';
13
14
  import 'node:readline';
@@ -2134,6 +2135,7 @@ class BrainCliHook extends EventEmitter {
2134
2135
  await this.initialize();
2135
2136
  }
2136
2137
  try {
2138
+ SessionIntelligence.getInstance().recordMessage("user", userInput);
2137
2139
  const result = await processUserInput(userInput);
2138
2140
  if (result.handled && result.result) {
2139
2141
  this.emit("hook:handled", { input: userInput, result: result.result });
@@ -49,7 +49,7 @@ const CLOUD_ENDPOINTS = {
49
49
  * Used for: plugin discovery, installation, ratings
50
50
  */
51
51
  PLUGINS: {
52
- BASE_URL: "https://api.api.claudehome.cn",
52
+ BASE_URL: "https://api.claudehome.cn",
53
53
  API_VERSION: "/v1"
54
54
  },
55
55
  /**
@@ -14,6 +14,13 @@ const DEPTH_TOKEN_BUDGETS = {
14
14
  L2: Number.POSITIVE_INFINITY
15
15
  // Full content
16
16
  };
17
+ const PHASE_BUDGET_MULTIPLIERS = {
18
+ exploring: 2,
19
+ executing: 0.6,
20
+ generating: 0.4,
21
+ reviewing: 1.2,
22
+ idle: 1
23
+ };
17
24
  const CHARS_PER_TOKEN = 4;
18
25
  function estimateTokens(text) {
19
26
  return Math.ceil(text.length / CHARS_PER_TOKEN);
@@ -58,7 +65,8 @@ class ContextLoader {
58
65
  layers = ["project", "domain", "task", "execution"],
59
66
  task
60
67
  } = options;
61
- const effectiveBudget = tokenBudget ?? this.defaultTokenBudget;
68
+ const phaseMultiplier = options.taskPhase ? PHASE_BUDGET_MULTIPLIERS[options.taskPhase] ?? 1 : 1;
69
+ const effectiveBudget = Math.round((tokenBudget ?? this.defaultTokenBudget) * phaseMultiplier);
62
70
  const depth = this.resolveDepth(effectiveBudget, explicitDepth);
63
71
  const cacheKey = this.getCacheKey(projectRoot, layers, task?.id, depth);
64
72
  const cached = this.cache.get(cacheKey);
@@ -1,10 +1,115 @@
1
- import { EventEmitter } from 'node:events';
2
- import { n as nanoid } from '../shared/ccjk.BoApaI4j.mjs';
1
+ import 'node:child_process';
3
2
  import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
3
+ import 'node:fs/promises';
4
4
  import { homedir } from 'node:os';
5
+ import 'node:path';
6
+ import { EventEmitter } from 'node:events';
7
+ import { n as nanoid } from '../shared/ccjk.BoApaI4j.mjs';
5
8
  import { x as K } from './main.mjs';
6
9
  import { j as join } from '../shared/ccjk.bQ7Dh1g4.mjs';
7
10
 
11
+ function detectTaskPhase(history) {
12
+ if (history.length === 0) return "idle";
13
+ const recent = history.slice(-10);
14
+ const recentText = recent.map((h) => h.content).join(" ").toLowerCase();
15
+ if (recentText.includes("write") || recentText.includes("create") || recentText.includes("generating"))
16
+ return "generating";
17
+ if (recentText.includes("test") || recentText.includes("review") || recentText.includes("check"))
18
+ return "reviewing";
19
+ if (recentText.includes("edit") || recentText.includes("bash") || recentText.includes("run"))
20
+ return "executing";
21
+ if (recentText.includes("read") || recentText.includes("search") || recentText.includes("grep"))
22
+ return "exploring";
23
+ return "idle";
24
+ }
25
+ function extractFilePaths(content) {
26
+ const matches = content.match(/(?:\/[\w./\-]+\.\w+|[\w./\-]+\.(?:ts|js|json|md|py|go|rs))/g);
27
+ return matches ? [...new Set(matches)] : [];
28
+ }
29
+ class SessionIntelligence {
30
+ session;
31
+ constructor(session) {
32
+ this.session = session;
33
+ if (!session.intelligence) {
34
+ session.intelligence = {
35
+ taskPhase: "idle",
36
+ filesTouched: [],
37
+ keyDecisions: [],
38
+ toolCallCount: 0,
39
+ compressionWatermark: 0
40
+ };
41
+ }
42
+ }
43
+ get state() {
44
+ return this.session.intelligence;
45
+ }
46
+ /**
47
+ * Observe a new history entry and update intelligence state.
48
+ * Call this after every message added to the session.
49
+ */
50
+ observe(entry) {
51
+ const intel = this.state;
52
+ if (!intel.userOriginalIntent && entry.role === "user" && entry.content.trim().length > 10) {
53
+ intel.userOriginalIntent = entry.content.slice(0, 500);
54
+ }
55
+ const files = extractFilePaths(entry.content);
56
+ for (const f of files) {
57
+ if (!intel.filesTouched.includes(f)) {
58
+ intel.filesTouched.push(f);
59
+ }
60
+ }
61
+ if (entry.role === "assistant" && /\b(bash|read|write|edit|grep|glob)\b/i.test(entry.content)) {
62
+ intel.toolCallCount++;
63
+ }
64
+ intel.taskPhase = detectTaskPhase(this.session.history);
65
+ }
66
+ /**
67
+ * Record a key decision explicitly.
68
+ */
69
+ recordDecision(decision) {
70
+ const intel = this.state;
71
+ if (!intel.keyDecisions.includes(decision)) {
72
+ intel.keyDecisions.push(decision.slice(0, 200));
73
+ if (intel.keyDecisions.length > 20) {
74
+ intel.keyDecisions.shift();
75
+ }
76
+ }
77
+ }
78
+ /**
79
+ * Mark that history up to index N has been compressed.
80
+ */
81
+ markCompressed(upToIndex) {
82
+ this.state.compressionWatermark = upToIndex;
83
+ }
84
+ /**
85
+ * Generate a system prompt injection that preserves intent across compaction.
86
+ * Inject this whenever context is about to be compressed.
87
+ */
88
+ getSystemPromptInjection() {
89
+ const intel = this.state;
90
+ const parts = ["<!-- session-intelligence -->"];
91
+ if (intel.userOriginalIntent) {
92
+ parts.push(`Original user intent: ${intel.userOriginalIntent}`);
93
+ }
94
+ if (intel.keyDecisions.length > 0) {
95
+ parts.push(`Key decisions: ${intel.keyDecisions.join("; ")}`);
96
+ }
97
+ if (intel.filesTouched.length > 0) {
98
+ parts.push(`Files touched: ${intel.filesTouched.slice(-20).join(", ")}`);
99
+ }
100
+ parts.push(`Task phase: ${intel.taskPhase} | Tool calls: ${intel.toolCallCount}`);
101
+ parts.push("<!-- /session-intelligence -->");
102
+ return parts.join("\n");
103
+ }
104
+ /**
105
+ * Returns true if the session has enough context to be worth preserving.
106
+ */
107
+ hasSignificantContext() {
108
+ const intel = this.state;
109
+ return !!intel.userOriginalIntent || intel.toolCallCount > 3 || intel.filesTouched.length > 0;
110
+ }
111
+ }
112
+
8
113
  class GitBackedStateManager extends EventEmitter {
9
114
  config;
10
115
  worktrees = /* @__PURE__ */ new Map();
@@ -877,4 +982,4 @@ const convoyManager = {
877
982
  getGlobalConvoyManager: getGlobalConvoyManager
878
983
  };
879
984
 
880
- export { getGlobalStateManager as a, gitBackedState as b, convoyManager as c, getGlobalConvoyManager as g };
985
+ export { SessionIntelligence as S, getGlobalStateManager as a, gitBackedState as b, convoyManager as c, getGlobalConvoyManager as g };
@@ -301,7 +301,7 @@ async function mcpDoctor(options = {}) {
301
301
  console.log("");
302
302
  }
303
303
 
304
- const DEFAULT_API_URL = "https://api.api.claudehome.cn/v1/mcp-marketplace";
304
+ const DEFAULT_API_URL = "https://api.claudehome.cn/api/v1/mcp-marketplace";
305
305
  const REQUEST_TIMEOUT = 3e4;
306
306
  const MAX_RETRY_ATTEMPTS = 3;
307
307
  const RETRY_DELAY = 1e3;
@@ -31,40 +31,61 @@ function isOnboardingCompleted() {
31
31
  const state = readOnboardingState();
32
32
  return state?.completed === true;
33
33
  }
34
- async function runOnboardingWizard() {
34
+ async function runOnboardingWizard(options = {}) {
35
+ if (options.reset) {
36
+ try {
37
+ writeOnboardingState({ completed: false, completedAt: "", completedSteps: [] });
38
+ } catch {
39
+ }
40
+ }
41
+ const existingState = readOnboardingState();
42
+ const completedSteps = new Set(existingState?.completedSteps ?? []);
35
43
  const isZh = i18n.language === "zh-CN";
36
44
  console.log("");
37
45
  console.log(a.bold.yellow(isZh ? "\u{1F389} \u6B22\u8FCE\u4F7F\u7528 CCJK\uFF01" : "\u{1F389} Welcome to CCJK!"));
38
46
  console.log(a.dim(isZh ? " \u8BA9\u6211\u4EEC\u7528 3 \u6B65\u5B8C\u6210\u521D\u59CB\u5316\u914D\u7F6E" : " Let's get you set up in 3 steps"));
39
47
  console.log("");
40
- console.log(a.bold(`${isZh ? "\u6B65\u9AA4 1/3" : "Step 1/3"}: ${isZh ? "\u73AF\u5883\u68C0\u6D4B" : "Environment Detection"}`));
41
- try {
42
- const { detectSmartDefaults } = await import('./smart-defaults.mjs').then(function (n) { return n.s; });
43
- const defaults = await detectSmartDefaults();
44
- if (defaults) {
45
- console.log(a.green(` \u2714 ${isZh ? "\u68C0\u6D4B\u5230" : "Detected"}: ${defaults.codeToolType || "claude-code"}`));
46
- if (defaults.mcpServices?.length) {
47
- console.log(a.dim(` ${isZh ? "\u63A8\u8350 MCP \u670D\u52A1" : "Recommended MCP"}: ${defaults.mcpServices.slice(0, 3).join(", ")}`));
48
+ const step1Done = completedSteps.has(1);
49
+ console.log(a.bold(`${isZh ? "\u6B65\u9AA4 1/3" : "Step 1/3"}: ${isZh ? "\u73AF\u5883\u68C0\u6D4B" : "Environment Detection"}${step1Done ? a.green(" \u2714") : ""}`));
50
+ if (!step1Done) {
51
+ try {
52
+ const { detectSmartDefaults } = await import('./smart-defaults.mjs').then(function (n) { return n.s; });
53
+ const defaults = await detectSmartDefaults();
54
+ if (defaults) {
55
+ console.log(a.green(` \u2714 ${isZh ? "\u68C0\u6D4B\u5230" : "Detected"}: ${defaults.codeToolType || "claude-code"}`));
56
+ if (defaults.mcpServices?.length) {
57
+ console.log(a.dim(` ${isZh ? "\u63A8\u8350 MCP \u670D\u52A1" : "Recommended MCP"}: ${defaults.mcpServices.slice(0, 3).join(", ")}`));
58
+ }
59
+ } else {
60
+ console.log(a.dim(` ${isZh ? "\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E" : "Using default configuration"}`));
48
61
  }
49
- } else {
50
- console.log(a.dim(` ${isZh ? "\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E" : "Using default configuration"}`));
62
+ completedSteps.add(1);
63
+ } catch {
64
+ console.log(a.dim(` ${isZh ? "\u73AF\u5883\u68C0\u6D4B\u8DF3\u8FC7" : "Environment detection skipped"}`));
51
65
  }
52
- } catch {
53
- console.log(a.dim(` ${isZh ? "\u73AF\u5883\u68C0\u6D4B\u8DF3\u8FC7" : "Environment detection skipped"}`));
66
+ } else {
67
+ console.log(a.dim(` ${isZh ? "\u5DF2\u5B8C\u6210\uFF0C\u8DF3\u8FC7" : "Already done, skipping"}`));
54
68
  }
55
69
  console.log("");
56
- console.log(a.bold(`${isZh ? "\u6B65\u9AA4 2/3" : "Step 2/3"}: ${isZh ? "API \u914D\u7F6E" : "API Configuration"}`));
57
- try {
58
- const { getExistingApiConfig } = await import('./config.mjs').then(function (n) { return n.j; });
59
- const existing = getExistingApiConfig();
60
- if (existing?.key || existing?.url) {
61
- console.log(a.green(` \u2714 ${isZh ? "\u5DF2\u914D\u7F6E" : "Already configured"}`));
62
- } else {
63
- const { configureApiFeature } = await import('./features.mjs');
64
- await configureApiFeature();
70
+ const step2Done = completedSteps.has(2);
71
+ console.log(a.bold(`${isZh ? "\u6B65\u9AA4 2/3" : "Step 2/3"}: ${isZh ? "API \u914D\u7F6E" : "API Configuration"}${step2Done ? a.green(" \u2714") : ""}`));
72
+ if (!step2Done) {
73
+ try {
74
+ const { getExistingApiConfig } = await import('./config.mjs').then(function (n) { return n.j; });
75
+ const existing = getExistingApiConfig();
76
+ if (existing?.key || existing?.url) {
77
+ console.log(a.green(` \u2714 ${isZh ? "\u5DF2\u914D\u7F6E" : "Already configured"}`));
78
+ completedSteps.add(2);
79
+ } else {
80
+ const { configureApiFeature } = await import('./features.mjs');
81
+ await configureApiFeature();
82
+ completedSteps.add(2);
83
+ }
84
+ } catch {
85
+ console.log(a.yellow(` ${isZh ? "\u26A0 API \u914D\u7F6E\u8DF3\u8FC7\uFF0C\u7A0D\u540E\u53EF\u901A\u8FC7\u83DC\u5355\u914D\u7F6E" : "\u26A0 API setup skipped, configure later via menu"}`));
65
86
  }
66
- } catch {
67
- console.log(a.yellow(` ${isZh ? "\u26A0 API \u914D\u7F6E\u8DF3\u8FC7\uFF0C\u7A0D\u540E\u53EF\u901A\u8FC7\u83DC\u5355\u914D\u7F6E" : "\u26A0 API setup skipped, configure later via menu"}`));
87
+ } else {
88
+ console.log(a.dim(` ${isZh ? "\u5DF2\u5B8C\u6210\uFF0C\u8DF3\u8FC7" : "Already done, skipping"}`));
68
89
  }
69
90
  console.log("");
70
91
  console.log(a.bold(`${isZh ? "\u6B65\u9AA4 3/3" : "Step 3/3"}: ${isZh ? "\u73AF\u5883\u9A8C\u8BC1" : "Verification"}`));
@@ -85,7 +106,12 @@ async function runOnboardingWizard() {
85
106
  console.log(a.dim(` ${isZh ? "\u9A8C\u8BC1\u8DF3\u8FC7" : "Verification skipped"}`));
86
107
  }
87
108
  console.log("");
88
- writeOnboardingState({ completed: true, completedAt: (/* @__PURE__ */ new Date()).toISOString() });
109
+ completedSteps.add(3);
110
+ writeOnboardingState({
111
+ completed: true,
112
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
113
+ completedSteps: Array.from(completedSteps)
114
+ });
89
115
  console.log(a.bold.green(isZh ? "\u2705 \u521D\u59CB\u5316\u5B8C\u6210\uFF01\u8FDB\u5165\u4E3B\u83DC\u5355..." : "\u2705 Setup complete! Loading main menu..."));
90
116
  console.log("");
91
117
  }
@@ -1,3 +1,3 @@
1
- const version = "12.0.8";
1
+ const version = "12.0.10";
2
2
 
3
3
  export { version };
@@ -5624,7 +5624,7 @@ function extractMetadata(data, filePath) {
5624
5624
  return metadata;
5625
5625
  }
5626
5626
 
5627
- process__default.env.CCJK_CLOUD_API_URL || "https://api.api.claudehome.cn/v1";
5627
+ process__default.env.CCJK_CLOUD_API_URL || "https://api.claudehome.cn/api/v1";
5628
5628
  const SYNC_STATE_FILE = join(CCJK_CONFIG_DIR, "skills-sync-state.json");
5629
5629
  const DEFAULT_TIMEOUT = 3e4;
5630
5630
  function loadSyncState() {
@@ -236,6 +236,38 @@ function renderHealthSection(report, compact) {
236
236
  }
237
237
  return lines;
238
238
  }
239
+ function suggestNextAction(health, ctx) {
240
+ const lines = [];
241
+ lines.push(heading("Next Step"));
242
+ const score = health.totalScore;
243
+ const hasFailures = health.results.some((r) => r.status === "fail");
244
+ const hasWarnings = health.results.some((r) => r.status === "warn");
245
+ if (hasFailures) {
246
+ const firstFail = health.results.find((r) => r.status === "fail");
247
+ lines.push(` ${a.red("\u2192")} Fix ${a.bold(firstFail.name)}: ${firstFail.message}`);
248
+ if (firstFail.command) {
249
+ lines.push(` ${a.cyan(firstFail.command)}`);
250
+ } else {
251
+ lines.push(` ${a.cyan("ccjk boost")} to auto-fix`);
252
+ }
253
+ return lines;
254
+ }
255
+ if (score < 60) {
256
+ lines.push(` ${a.yellow("\u2192")} Score is ${score}/100. Run ${a.cyan("ccjk boost")} to optimize.`);
257
+ return lines;
258
+ }
259
+ if (hasWarnings) {
260
+ const warnCount = health.results.filter((r) => r.status === "warn").length;
261
+ lines.push(` ${a.yellow("\u2192")} ${warnCount} warning${warnCount > 1 ? "s" : ""} remaining. Run ${a.cyan("ccjk boost --dry-run")} to preview fixes.`);
262
+ return lines;
263
+ }
264
+ if (score >= 80) {
265
+ lines.push(` ${a.green("\u2192")} Setup looks great. Start coding or run ${a.cyan("ccjk brain status")} to check session.`);
266
+ } else {
267
+ lines.push(` ${a.green("\u2192")} Almost there. Run ${a.cyan("ccjk boost")} to push past ${score}.`);
268
+ }
269
+ return lines;
270
+ }
239
271
  async function statusCommand(options = {}) {
240
272
  try {
241
273
  const [ctx, defaults, installed, health] = await Promise.all([
@@ -270,6 +302,7 @@ async function statusCommand(options = {}) {
270
302
  sections.push(renderCompressionMetricsSection());
271
303
  } catch {
272
304
  }
305
+ sections.push(suggestNextAction(health, ctx));
273
306
  console.log();
274
307
  for (let i = 0; i < sections.length; i++) {
275
308
  console.log(sections[i].join("\n"));
package/dist/index.d.mts CHANGED
@@ -3611,6 +3611,7 @@ interface AgentRecommendation {
3611
3611
  mcpServers: string[];
3612
3612
  persona?: string;
3613
3613
  capabilities: string[];
3614
+ tags?: string[];
3614
3615
  confidence: number;
3615
3616
  reason: string;
3616
3617
  }
package/dist/index.d.ts CHANGED
@@ -3611,6 +3611,7 @@ interface AgentRecommendation {
3611
3611
  mcpServers: string[];
3612
3612
  persona?: string;
3613
3613
  capabilities: string[];
3614
+ tags?: string[];
3614
3615
  confidence: number;
3615
3616
  reason: string;
3616
3617
  }
@@ -0,0 +1,70 @@
1
+ {
2
+ "id": "fullstack-developer",
3
+ "subagent_type": "general-purpose",
4
+ "name": {
5
+ "en": "Full-Stack Developer",
6
+ "zh-CN": "全栈开发者"
7
+ },
8
+ "description": {
9
+ "en": "Full-stack developer with TDD expertise, specializing in end-to-end application development with modern TypeScript, React, and Node.js stack. Expert in testing automation and continuous integration practices.",
10
+ "zh-CN": "具有 TDD 专业知识的全栈开发者,专注于使用现代 TypeScript、React 和 Node.js 技术栈进行端到端应用开发。在测试自动化和持续集成实践方面具有专业知识。"
11
+ },
12
+ "persona": "You are a full-stack developer with comprehensive experience across the entire web development stack. You have 7+ years of experience building complete applications from database design to user interface implementation. You're passionate about Test-Driven Development (TDD) and believe in writing tests first to drive better design decisions. You have deep expertise in TypeScript, React, Node.js, and modern database technologies. You understand the importance of DevOps practices and have experience with CI/CD pipelines, containerization, and cloud deployment. You're skilled at breaking down complex requirements into manageable tasks and can work effectively across frontend, backend, and infrastructure concerns. You believe in clean architecture principles, proper separation of concerns, and building maintainable systems that can evolve over time. You stay current with modern development practices and tools, always looking for ways to improve developer productivity and code quality.",
13
+ "capabilities": [
14
+ "end-to-end-development",
15
+ "testing-automation",
16
+ "api-design",
17
+ "database-design",
18
+ "frontend-development",
19
+ "backend-development",
20
+ "devops-integration",
21
+ "architecture-planning"
22
+ ],
23
+ "skills": [
24
+ "ts-best-practices",
25
+ "react-patterns",
26
+ "testing-best-practices",
27
+ "tdd-workflow",
28
+ "api-design",
29
+ "database-optimization",
30
+ "ci-cd-practices"
31
+ ],
32
+ "mcpServers": [
33
+ "typescript-language-server",
34
+ "git-mcp",
35
+ "docker-mcp",
36
+ "jest-mcp"
37
+ ],
38
+ "systemPrompt": "You are a full-stack developer focused on building complete, well-tested applications using modern best practices. Always consider the entire application lifecycle from development to deployment. When reviewing code, look for opportunities to improve testability, maintainability, and user experience across the full stack. Provide comprehensive recommendations that consider both frontend and backend implications.",
39
+ "instructions": [
40
+ "Always start with tests when implementing new features (TDD approach)",
41
+ "Design APIs that are RESTful, well-documented, and version-controlled",
42
+ "Implement proper error handling and validation on both frontend and backend",
43
+ "Use TypeScript consistently across the entire stack for type safety",
44
+ "Design database schemas with proper normalization and indexing strategies",
45
+ "Implement proper authentication and authorization patterns",
46
+ "Use modern React patterns with hooks and proper state management",
47
+ "Set up comprehensive CI/CD pipelines with automated testing and deployment",
48
+ "Implement proper logging, monitoring, and observability across the stack",
49
+ "Follow security best practices including input validation, HTTPS, and secure headers"
50
+ ],
51
+ "triggers": [
52
+ "user needs end-to-end application development",
53
+ "user wants to implement TDD practices",
54
+ "user needs full-stack architecture guidance",
55
+ "user asks about testing strategies",
56
+ "user needs help with API design",
57
+ "user wants to set up CI/CD pipelines",
58
+ "user needs database design guidance",
59
+ "user asks about deployment strategies"
60
+ ],
61
+ "model": "sonnet",
62
+ "metadata": {
63
+ "version": "1.0.0",
64
+ "author": "ccjk-team",
65
+ "category": "development",
66
+ "tags": ["fullstack", "typescript", "react", "nodejs", "tdd", "testing", "ci-cd"],
67
+ "complexity": "intermediate-advanced",
68
+ "experience_level": "intermediate"
69
+ }
70
+ }