ccjk 13.5.2 → 13.5.4

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.
Files changed (35) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/boost.mjs +8 -1
  3. package/dist/chunks/ccjk-config.mjs +17 -0
  4. package/dist/chunks/ccr.mjs +2 -2
  5. package/dist/chunks/check-updates.mjs +1 -1
  6. package/dist/chunks/codex-config-switch.mjs +1 -1
  7. package/dist/chunks/codex-provider-manager.mjs +1 -1
  8. package/dist/chunks/codex.mjs +2 -2
  9. package/dist/chunks/completion.mjs +1 -1
  10. package/dist/chunks/config-switch.mjs +1 -1
  11. package/dist/chunks/context.mjs +316 -1
  12. package/dist/chunks/features.mjs +43 -14
  13. package/dist/chunks/index4.mjs +8 -1
  14. package/dist/chunks/init.mjs +2 -2
  15. package/dist/chunks/mcp-cli.mjs +3 -3
  16. package/dist/chunks/mcp.mjs +177 -35
  17. package/dist/{shared/ccjk.Crd_nEfj.mjs → chunks/memory-check.mjs} +18 -424
  18. package/dist/chunks/memory-paths.mjs +259 -0
  19. package/dist/chunks/memory-sync.mjs +209 -0
  20. package/dist/chunks/memory.mjs +140 -17
  21. package/dist/chunks/menu-hierarchical.mjs +2 -2
  22. package/dist/chunks/menu.mjs +1 -1
  23. package/dist/chunks/onboarding-wizard.mjs +8 -1
  24. package/dist/chunks/package.mjs +1 -1
  25. package/dist/chunks/quick-actions.mjs +8 -1
  26. package/dist/chunks/quick-setup.mjs +1 -1
  27. package/dist/chunks/smart-defaults.mjs +1 -20
  28. package/dist/chunks/status.mjs +8 -1
  29. package/dist/chunks/update.mjs +2 -2
  30. package/dist/cli.mjs +16 -4
  31. package/dist/shared/{ccjk.LTONy3IS.mjs → ccjk.BOfPON0N.mjs} +1 -1
  32. package/dist/shared/{ccjk.0aJQmVxS.mjs → ccjk.miT0g_vA.mjs} +3 -160
  33. package/dist/shared/ccjk.xkKNsC02.mjs +421 -0
  34. package/package.json +1 -1
  35. package/dist/chunks/auto-memory-bridge.mjs +0 -221
@@ -0,0 +1,259 @@
1
+ import { resolve } from 'node:path';
2
+ import { CCJK_CONFIG_FILE, SUPPORTED_LANGS, DEFAULT_CODE_TOOL_TYPE, CCJK_CONFIG_DIR, CLAUDE_DIR } from './constants.mjs';
3
+ import { p as parse } from '../shared/ccjk.BBtCGd_g.mjs';
4
+ import { stringify } from './index6.mjs';
5
+ import { exists, readFile, ensureDir, writeFileAtomic } from './fs-operations.mjs';
6
+ import { d as dirname, j as join } from '../shared/ccjk.bQ7Dh1g4.mjs';
7
+ import 'node:os';
8
+ import './index5.mjs';
9
+ import 'node:fs';
10
+ import 'node:process';
11
+ import 'node:url';
12
+ import 'node:crypto';
13
+ import 'node:fs/promises';
14
+
15
+ const DEFAULT_CONFIG_VERSION = "4.0.0";
16
+ function createDefaultCcjkConfig(preferredLang = "en", claudeCodeInstallType = "global") {
17
+ return {
18
+ version: DEFAULT_CONFIG_VERSION,
19
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
20
+ general: {
21
+ preferredLang,
22
+ templateLang: preferredLang,
23
+ aiOutputLang: preferredLang === "zh-CN" ? "zh-CN" : void 0,
24
+ currentTool: DEFAULT_CODE_TOOL_TYPE
25
+ },
26
+ tools: {
27
+ claudeCode: {
28
+ enabled: true,
29
+ installType: claudeCodeInstallType,
30
+ outputStyles: ["speed-coder", "senior-architect", "pair-programmer"],
31
+ defaultOutputStyle: "senior-architect",
32
+ currentProfile: "",
33
+ profiles: {}
34
+ },
35
+ codex: {
36
+ enabled: false,
37
+ systemPromptStyle: "senior-architect"
38
+ }
39
+ },
40
+ storage: {
41
+ memory: {}
42
+ }
43
+ };
44
+ }
45
+ function readCcjkConfig(configPath = CCJK_CONFIG_FILE) {
46
+ try {
47
+ if (!exists(configPath)) {
48
+ return null;
49
+ }
50
+ const content = readFile(configPath);
51
+ const parsed = parse(content);
52
+ return convertTomlToCcjkConfig(parsed);
53
+ } catch (error) {
54
+ console.error(`Failed to read CCJK config from ${configPath}:`, error);
55
+ return null;
56
+ }
57
+ }
58
+ function writeCcjkConfig(config, configPath = CCJK_CONFIG_FILE) {
59
+ try {
60
+ const configDir = dirname(configPath);
61
+ ensureDir(configDir);
62
+ config.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
63
+ const tomlContent = stringify(config);
64
+ writeFileAtomic(configPath, tomlContent);
65
+ } catch (error) {
66
+ console.error(`Failed to write CCJK config to ${configPath}:`, error);
67
+ throw new Error(`Failed to write CCJK config: ${error instanceof Error ? error.message : String(error)}`);
68
+ }
69
+ }
70
+ function updateCcjkConfig(updates, configPath = CCJK_CONFIG_FILE) {
71
+ const existingConfig = readCcjkConfig(configPath) || createDefaultCcjkConfig();
72
+ const updatedConfig = {
73
+ version: updates.version || existingConfig.version,
74
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
75
+ general: {
76
+ ...existingConfig.general,
77
+ ...updates.general
78
+ },
79
+ tools: {
80
+ ...existingConfig.tools,
81
+ ...updates.tools,
82
+ claudeCode: {
83
+ ...existingConfig.tools.claudeCode,
84
+ ...updates.tools?.claudeCode
85
+ },
86
+ codex: {
87
+ ...existingConfig.tools.codex,
88
+ ...updates.tools?.codex
89
+ }
90
+ },
91
+ storage: {
92
+ ...existingConfig.storage,
93
+ ...updates.storage,
94
+ memory: {
95
+ ...existingConfig.storage.memory,
96
+ ...updates.storage?.memory
97
+ }
98
+ }
99
+ };
100
+ writeCcjkConfig(updatedConfig, configPath);
101
+ return updatedConfig;
102
+ }
103
+ function getCcjkConfig(configPath = CCJK_CONFIG_FILE) {
104
+ const config = readCcjkConfig(configPath);
105
+ return config || createDefaultCcjkConfig();
106
+ }
107
+ function validateCcjkConfig(config) {
108
+ const errors = [];
109
+ if (!config || typeof config !== "object") {
110
+ return { valid: false, errors: ["Configuration must be an object"] };
111
+ }
112
+ const cfg = config;
113
+ if (!cfg.version || typeof cfg.version !== "string") {
114
+ errors.push("Invalid or missing version");
115
+ }
116
+ if (!cfg.general || typeof cfg.general !== "object") {
117
+ errors.push("Invalid or missing general section");
118
+ } else {
119
+ if (!cfg.general.preferredLang || !SUPPORTED_LANGS.includes(cfg.general.preferredLang)) {
120
+ errors.push(`Invalid preferredLang: ${cfg.general.preferredLang}`);
121
+ }
122
+ if (cfg.general.templateLang && !SUPPORTED_LANGS.includes(cfg.general.templateLang)) {
123
+ errors.push(`Invalid templateLang: ${cfg.general.templateLang}`);
124
+ }
125
+ }
126
+ if (!cfg.tools || typeof cfg.tools !== "object") {
127
+ errors.push("Invalid or missing tools section");
128
+ } else {
129
+ if (!cfg.tools.claudeCode || typeof cfg.tools.claudeCode !== "object") {
130
+ errors.push("Invalid or missing claudeCode tool config");
131
+ }
132
+ if (!cfg.tools.codex || typeof cfg.tools.codex !== "object") {
133
+ errors.push("Invalid or missing codex tool config");
134
+ }
135
+ }
136
+ if (!cfg.storage || typeof cfg.storage !== "object") {
137
+ errors.push("Invalid or missing storage section");
138
+ }
139
+ return {
140
+ valid: errors.length === 0,
141
+ errors
142
+ };
143
+ }
144
+ function convertTomlToCcjkConfig(tomlConfig) {
145
+ if (!tomlConfig) {
146
+ return null;
147
+ }
148
+ return {
149
+ version: tomlConfig.version || DEFAULT_CONFIG_VERSION,
150
+ lastUpdated: tomlConfig.lastUpdated || (/* @__PURE__ */ new Date()).toISOString(),
151
+ general: {
152
+ preferredLang: tomlConfig.general?.preferredLang || "en",
153
+ templateLang: tomlConfig.general?.templateLang,
154
+ aiOutputLang: tomlConfig.general?.aiOutputLang,
155
+ currentTool: tomlConfig.general?.currentTool || DEFAULT_CODE_TOOL_TYPE
156
+ },
157
+ tools: {
158
+ claudeCode: {
159
+ enabled: tomlConfig.claudeCode?.enabled ?? true,
160
+ installType: tomlConfig.claudeCode?.installType || "global",
161
+ installMethod: tomlConfig.claudeCode?.installMethod,
162
+ outputStyles: tomlConfig.claudeCode?.outputStyles || [],
163
+ defaultOutputStyle: tomlConfig.claudeCode?.defaultOutputStyle,
164
+ currentProfile: tomlConfig.claudeCode?.currentProfile || "",
165
+ profiles: tomlConfig.claudeCode?.profiles || {},
166
+ version: tomlConfig.claudeCode?.version
167
+ },
168
+ codex: {
169
+ enabled: tomlConfig.codex?.enabled ?? false,
170
+ systemPromptStyle: tomlConfig.codex?.systemPromptStyle || "senior-architect",
171
+ installMethod: tomlConfig.codex?.installMethod,
172
+ envKeyMigrated: tomlConfig.codex?.envKeyMigrated
173
+ }
174
+ },
175
+ storage: {
176
+ memory: {
177
+ claudeDir: tomlConfig.storage?.memory?.claudeDir,
178
+ ccjkDir: tomlConfig.storage?.memory?.ccjkDir
179
+ }
180
+ }
181
+ };
182
+ }
183
+
184
+ const config = {
185
+ /**
186
+ * CCJK Configuration (~/.ccjk/config.toml)
187
+ */
188
+ ccjk: {
189
+ /**
190
+ * Read CCJK configuration
191
+ */
192
+ read: readCcjkConfig,
193
+ /**
194
+ * Write CCJK configuration
195
+ */
196
+ write: writeCcjkConfig,
197
+ /**
198
+ * Update CCJK configuration with partial changes
199
+ */
200
+ update: updateCcjkConfig,
201
+ /**
202
+ * Get or create CCJK configuration (with defaults)
203
+ */
204
+ get: getCcjkConfig,
205
+ /**
206
+ * Create default CCJK configuration
207
+ */
208
+ createDefault: createDefaultCcjkConfig,
209
+ /**
210
+ * Validate CCJK configuration
211
+ */
212
+ validate: validateCcjkConfig
213
+ }};
214
+
215
+ function getMemoryDirectoryOverrides() {
216
+ const ccjkConfig = config.ccjk.read();
217
+ return {
218
+ claudeDir: ccjkConfig?.storage?.memory?.claudeDir,
219
+ ccjkDir: ccjkConfig?.storage?.memory?.ccjkDir
220
+ };
221
+ }
222
+ function resolveClaudeDir(claudeDir) {
223
+ return normalizeProjectPath(claudeDir || getMemoryDirectoryOverrides().claudeDir || CLAUDE_DIR);
224
+ }
225
+ function resolveCcjkDir(ccjkDir) {
226
+ return normalizeProjectPath(ccjkDir || getMemoryDirectoryOverrides().ccjkDir || CCJK_CONFIG_DIR);
227
+ }
228
+ function normalizeProjectPath(projectPath) {
229
+ return resolve(projectPath).replace(/\\/g, "/");
230
+ }
231
+ function toClaudeProjectDirName(projectPath) {
232
+ const normalizedPath = normalizeProjectPath(projectPath).replace(/^\/+/, "");
233
+ return `-${normalizedPath.replace(/[:/]/g, "-")}`;
234
+ }
235
+ function getClaudeMemoryPath(projectPath, claudeDir) {
236
+ const resolvedClaudeDir = resolveClaudeDir(claudeDir);
237
+ if (projectPath) {
238
+ return join(resolvedClaudeDir, "projects", toClaudeProjectDirName(projectPath), "memory", "MEMORY.md");
239
+ }
240
+ return join(resolvedClaudeDir, "memory", "MEMORY.md");
241
+ }
242
+ function getCcjkMemoryPath(projectPath, ccjkDir) {
243
+ const resolvedCcjkDir = resolveCcjkDir(ccjkDir);
244
+ if (projectPath) {
245
+ return join(resolvedCcjkDir, "memory", "projects", toClaudeProjectDirName(projectPath), "MEMORY.md");
246
+ }
247
+ return join(resolvedCcjkDir, "memory", "global", "MEMORY.md");
248
+ }
249
+ function getClaudeProjectsDir(claudeDir) {
250
+ return join(resolveClaudeDir(claudeDir), "projects");
251
+ }
252
+ function getConfiguredMemoryDirectories() {
253
+ return {
254
+ claudeDir: resolveClaudeDir(),
255
+ ccjkDir: resolveCcjkDir()
256
+ };
257
+ }
258
+
259
+ export { getCcjkMemoryPath, getClaudeMemoryPath, getClaudeProjectsDir, getConfiguredMemoryDirectories, normalizeProjectPath, toClaudeProjectDirName };
@@ -0,0 +1,209 @@
1
+ import { readFileSync, existsSync, statSync, mkdirSync, writeFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+ import 'node:fs/promises';
4
+ import { normalizeProjectPath, getCcjkMemoryPath, getClaudeMemoryPath } from './memory-paths.mjs';
5
+ import './constants.mjs';
6
+ import 'node:os';
7
+ import './index5.mjs';
8
+ import 'node:process';
9
+ import 'node:url';
10
+ import '../shared/ccjk.bQ7Dh1g4.mjs';
11
+ import '../shared/ccjk.BBtCGd_g.mjs';
12
+ import './index6.mjs';
13
+ import './fs-operations.mjs';
14
+ import 'node:crypto';
15
+
16
+ function parseAutoMemory(content) {
17
+ const lines = content.split("\n");
18
+ const entries = [];
19
+ let currentEntry = null;
20
+ for (const line of lines) {
21
+ const headerMatch = line.match(/^(#{1,6})\s+(.+)$/);
22
+ if (headerMatch) {
23
+ if (currentEntry && currentEntry.content.length > 0) {
24
+ entries.push(currentEntry);
25
+ }
26
+ currentEntry = {
27
+ title: headerMatch[2].trim(),
28
+ content: [],
29
+ level: headerMatch[1].length
30
+ };
31
+ } else if (currentEntry && line.trim()) {
32
+ currentEntry.content.push(line);
33
+ }
34
+ }
35
+ if (currentEntry && currentEntry.content.length > 0) {
36
+ entries.push(currentEntry);
37
+ }
38
+ return entries;
39
+ }
40
+ function autoMemoryToBrainContext(entries, projectPath) {
41
+ const context = {
42
+ facts: [],
43
+ patterns: [],
44
+ decisions: [],
45
+ metadata: {
46
+ source: "auto-memory",
47
+ projectPath,
48
+ syncedAt: (/* @__PURE__ */ new Date()).toISOString()
49
+ }
50
+ };
51
+ for (const entry of entries) {
52
+ const contentText = entry.content.join("\n").trim();
53
+ const titleLower = entry.title.toLowerCase();
54
+ if (titleLower.includes("architecture") || titleLower.includes("pattern") || titleLower.includes("design")) {
55
+ context.patterns.push({
56
+ name: entry.title,
57
+ description: contentText,
58
+ category: "architecture"
59
+ });
60
+ } else if (titleLower.includes("decision") || titleLower.includes("choice") || titleLower.includes("why")) {
61
+ context.decisions.push({
62
+ decision: entry.title,
63
+ rationale: contentText,
64
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
65
+ });
66
+ } else {
67
+ context.facts.push({
68
+ key: entry.title,
69
+ value: contentText,
70
+ confidence: 0.9
71
+ });
72
+ }
73
+ }
74
+ return context;
75
+ }
76
+
77
+ function readMemorySnapshot(path) {
78
+ if (!existsSync(path)) {
79
+ return {
80
+ path,
81
+ content: "",
82
+ exists: false,
83
+ hasContent: false,
84
+ sizeBytes: 0,
85
+ mtimeMs: 0
86
+ };
87
+ }
88
+ const stats = statSync(path);
89
+ const content = readFileSync(path, "utf-8");
90
+ return {
91
+ path,
92
+ content,
93
+ exists: true,
94
+ hasContent: content.trim().length > 0,
95
+ sizeBytes: stats.size,
96
+ mtimeMs: stats.mtimeMs
97
+ };
98
+ }
99
+ function writeMemorySnapshot(path, content) {
100
+ mkdirSync(dirname(path), { recursive: true });
101
+ writeFileSync(path, content, "utf-8");
102
+ }
103
+ function summarizeMemoryContent(content, projectPath) {
104
+ if (!content.trim()) {
105
+ return {
106
+ parseMode: "empty",
107
+ entryCount: 0,
108
+ factCount: 0,
109
+ patternCount: 0,
110
+ decisionCount: 0
111
+ };
112
+ }
113
+ const entries = parseAutoMemory(content);
114
+ if (entries.length === 0) {
115
+ return {
116
+ parseMode: "freeform",
117
+ entryCount: 0,
118
+ factCount: 0,
119
+ patternCount: 0,
120
+ decisionCount: 0
121
+ };
122
+ }
123
+ const context = autoMemoryToBrainContext(entries, projectPath || "global");
124
+ return {
125
+ parseMode: "structured",
126
+ entryCount: entries.length,
127
+ factCount: context.facts.length,
128
+ patternCount: context.patterns.length,
129
+ decisionCount: context.decisions.length
130
+ };
131
+ }
132
+ function inspectSnapshots(claudeSnapshot, ccjkSnapshot, projectPath) {
133
+ let source = "none";
134
+ let sourceContent = "";
135
+ let syncState = "empty";
136
+ if (claudeSnapshot.hasContent || ccjkSnapshot.hasContent) {
137
+ if (claudeSnapshot.hasContent && ccjkSnapshot.hasContent && claudeSnapshot.content === ccjkSnapshot.content) {
138
+ source = "already-synced";
139
+ sourceContent = claudeSnapshot.content;
140
+ syncState = "in-sync";
141
+ } else if (claudeSnapshot.hasContent && !ccjkSnapshot.hasContent) {
142
+ source = "claude";
143
+ sourceContent = claudeSnapshot.content;
144
+ syncState = "claude-only";
145
+ } else if (ccjkSnapshot.hasContent && !claudeSnapshot.hasContent) {
146
+ source = "ccjk";
147
+ sourceContent = ccjkSnapshot.content;
148
+ syncState = "ccjk-only";
149
+ } else if (claudeSnapshot.mtimeMs >= ccjkSnapshot.mtimeMs) {
150
+ source = "claude";
151
+ sourceContent = claudeSnapshot.content;
152
+ syncState = "claude-newer";
153
+ } else {
154
+ source = "ccjk";
155
+ sourceContent = ccjkSnapshot.content;
156
+ syncState = "ccjk-newer";
157
+ }
158
+ }
159
+ return {
160
+ source,
161
+ syncState,
162
+ snapshots: {
163
+ claude: {
164
+ exists: claudeSnapshot.exists,
165
+ hasContent: claudeSnapshot.hasContent,
166
+ sizeBytes: claudeSnapshot.sizeBytes,
167
+ mtimeMs: claudeSnapshot.mtimeMs
168
+ },
169
+ ccjk: {
170
+ exists: ccjkSnapshot.exists,
171
+ hasContent: ccjkSnapshot.hasContent,
172
+ sizeBytes: ccjkSnapshot.sizeBytes,
173
+ mtimeMs: ccjkSnapshot.mtimeMs
174
+ }
175
+ },
176
+ ...summarizeMemoryContent(sourceContent, projectPath)
177
+ };
178
+ }
179
+ function inspectMemoryFiles(options = {}) {
180
+ const projectPath = options.projectPath ? normalizeProjectPath(options.projectPath) : void 0;
181
+ const paths = {
182
+ claude: getClaudeMemoryPath(projectPath, options.claudeDir),
183
+ ccjk: getCcjkMemoryPath(projectPath, options.ccjkDir)
184
+ };
185
+ const claudeSnapshot = readMemorySnapshot(paths.claude);
186
+ const ccjkSnapshot = readMemorySnapshot(paths.ccjk);
187
+ return {
188
+ scope: projectPath ? "project" : "global",
189
+ paths,
190
+ ...inspectSnapshots(claudeSnapshot, ccjkSnapshot, projectPath)
191
+ };
192
+ }
193
+ function syncMemoryFiles(options = {}) {
194
+ const inspection = inspectMemoryFiles(options);
195
+ const updatedTargets = [];
196
+ if (inspection.source === "claude" && inspection.syncState !== "in-sync") {
197
+ writeMemorySnapshot(inspection.paths.ccjk, readFileSync(inspection.paths.claude, "utf-8"));
198
+ updatedTargets.push("ccjk");
199
+ } else if (inspection.source === "ccjk" && inspection.syncState !== "in-sync") {
200
+ writeMemorySnapshot(inspection.paths.claude, readFileSync(inspection.paths.ccjk, "utf-8"));
201
+ updatedTargets.push("claude");
202
+ }
203
+ return {
204
+ ...inspection,
205
+ updatedTargets
206
+ };
207
+ }
208
+
209
+ export { inspectMemoryFiles, syncMemoryFiles };
@@ -1,10 +1,10 @@
1
1
  import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
2
- import { homedir } from 'node:os';
3
2
  import a from './index2.mjs';
4
3
  import { i as inquirer } from './index3.mjs';
5
4
  import { x as K } from './main.mjs';
6
- import { AutoMemoryBridge } from './auto-memory-bridge.mjs';
7
- import { CLAUDE_DIR } from './constants.mjs';
5
+ import { getClaudeMemoryPath } from './memory-paths.mjs';
6
+ import { memoryCheck } from './memory-check.mjs';
7
+ import { inspectMemoryFiles, syncMemoryFiles } from './memory-sync.mjs';
8
8
  import { j as join } from '../shared/ccjk.bQ7Dh1g4.mjs';
9
9
  import '../shared/ccjk.BAGoDD49.mjs';
10
10
  import 'node:readline';
@@ -18,26 +18,118 @@ import 'tty';
18
18
  import 'fs';
19
19
  import 'child_process';
20
20
  import 'node:path';
21
+ import 'node:os';
21
22
  import 'node:crypto';
22
23
  import 'buffer';
23
24
  import 'string_decoder';
24
25
  import 'module';
25
26
  import 'node:child_process';
26
27
  import 'node:stream';
27
- import 'node:fs/promises';
28
+ import './constants.mjs';
28
29
  import './index5.mjs';
29
30
  import 'node:url';
31
+ import '../shared/ccjk.BBtCGd_g.mjs';
32
+ import './index6.mjs';
33
+ import './fs-operations.mjs';
34
+ import 'node:fs/promises';
35
+ import 'constants';
36
+ import 'util';
37
+ import 'assert';
38
+ import 'path';
30
39
 
31
- function getClaudeDir() {
32
- return join(homedir(), CLAUDE_DIR);
40
+ function formatTimestamp(timestampMs) {
41
+ if (!timestampMs) {
42
+ return "never";
43
+ }
44
+ return new Date(timestampMs).toISOString();
33
45
  }
34
- function getMemoryPath(projectPath) {
35
- const claudeDir = getClaudeDir();
36
- if (projectPath) {
37
- const projectHash = Buffer.from(projectPath).toString("base64").replace(/[/+=]/g, "_");
38
- return join(claudeDir, "projects", projectHash, "memory", "MEMORY.md");
46
+ function formatSize(sizeBytes) {
47
+ return `${(sizeBytes / 1024).toFixed(2)} KB`;
48
+ }
49
+ function describeSyncState(syncState) {
50
+ switch (syncState) {
51
+ case "in-sync":
52
+ return "Claude and CCJK memory are in sync";
53
+ case "claude-only":
54
+ return "Only Claude memory has content";
55
+ case "ccjk-only":
56
+ return "Only CCJK memory has content";
57
+ case "claude-newer":
58
+ return "Claude memory is newer than the CCJK mirror";
59
+ case "ccjk-newer":
60
+ return "CCJK mirror is newer than Claude memory";
61
+ case "empty":
62
+ return "No memory content found";
63
+ }
64
+ }
65
+ async function showMemoryStatus(projectPath) {
66
+ const result = inspectMemoryFiles({ projectPath });
67
+ console.log(a.cyan.bold("\n\u{1F4CA} Memory Status"));
68
+ console.log(a.gray(`Scope: ${result.scope}`));
69
+ console.log(a.gray(`State: ${describeSyncState(result.syncState)}`));
70
+ console.log(a.gray(`Source: ${result.source}`));
71
+ console.log(a.gray(`Claude: ${result.paths.claude}`));
72
+ console.log(a.gray(`CCJK: ${result.paths.ccjk}`));
73
+ console.log("");
74
+ console.log(a.bold("Claude Memory"));
75
+ console.log(a.gray(` Exists: ${result.snapshots.claude.exists ? "yes" : "no"}`));
76
+ console.log(a.gray(` Content: ${result.snapshots.claude.hasContent ? "yes" : "no"}`));
77
+ console.log(a.gray(` Size: ${formatSize(result.snapshots.claude.sizeBytes)}`));
78
+ console.log(a.gray(` Updated: ${formatTimestamp(result.snapshots.claude.mtimeMs)}`));
79
+ console.log(a.bold("\nCCJK Mirror"));
80
+ console.log(a.gray(` Exists: ${result.snapshots.ccjk.exists ? "yes" : "no"}`));
81
+ console.log(a.gray(` Content: ${result.snapshots.ccjk.hasContent ? "yes" : "no"}`));
82
+ console.log(a.gray(` Size: ${formatSize(result.snapshots.ccjk.sizeBytes)}`));
83
+ console.log(a.gray(` Updated: ${formatTimestamp(result.snapshots.ccjk.mtimeMs)}`));
84
+ if (result.parseMode === "structured") {
85
+ console.log(a.bold("\nStructured Summary"));
86
+ console.log(a.gray(` Entries: ${result.entryCount}`));
87
+ console.log(a.gray(` Facts: ${result.factCount}`));
88
+ console.log(a.gray(` Patterns: ${result.patternCount}`));
89
+ console.log(a.gray(` Decisions: ${result.decisionCount}`));
90
+ } else if (result.parseMode === "freeform") {
91
+ console.log(a.bold("\nStructured Summary"));
92
+ console.log(a.gray(" Freeform notes detected; no structured headings parsed"));
93
+ }
94
+ console.log("");
95
+ }
96
+ async function runMemoryDoctor(projectPath) {
97
+ const result = inspectMemoryFiles({ projectPath });
98
+ const health = await memoryCheck.check();
99
+ console.log(a.cyan.bold("\n\u{1FA7A} Memory Doctor"));
100
+ console.log(a.gray(`Project state: ${describeSyncState(result.syncState)}`));
101
+ console.log(a.gray(`Health score: ${health.score}/100 (${health.status})`));
102
+ console.log(a.gray(`Summary: ${health.message}`));
103
+ if (health.details && health.details.length > 0) {
104
+ console.log(a.bold("\nHealth Details"));
105
+ for (const detail of health.details) {
106
+ console.log(a.gray(` ${detail}`));
107
+ }
108
+ }
109
+ const recommendations = [];
110
+ if (result.syncState === "claude-newer" || result.syncState === "ccjk-newer" || result.syncState === "claude-only" || result.syncState === "ccjk-only") {
111
+ recommendations.push("Run `ccjk memory --sync` to reconcile Claude memory and the CCJK mirror");
112
+ }
113
+ if (result.syncState === "empty") {
114
+ recommendations.push("Add project memory with `ccjk memory --edit` before relying on sync or doctor checks");
115
+ }
116
+ if (health.fix) {
117
+ recommendations.push(health.fix);
39
118
  }
40
- return join(claudeDir, "memory", "MEMORY.md");
119
+ if (recommendations.length > 0) {
120
+ console.log(a.bold("\nRecommendations"));
121
+ for (const recommendation of recommendations) {
122
+ console.log(a.gray(` - ${recommendation}`));
123
+ }
124
+ }
125
+ if (health.command) {
126
+ console.log(a.bold("\nSuggested Command"));
127
+ console.log(a.gray(` ${health.command}`));
128
+ }
129
+ console.log("");
130
+ }
131
+ function getMemoryPath(projectPath) {
132
+ return getClaudeMemoryPath(projectPath);
41
133
  }
42
134
  function readMemory(memoryPath) {
43
135
  if (!existsSync(memoryPath)) {
@@ -151,20 +243,43 @@ ${formattedContent}` : formattedContent;
151
243
  console.log(a.green("\u2713 Memory replaced"));
152
244
  }
153
245
  }
154
- async function syncMemory(_projectPath) {
246
+ async function syncMemory(projectPath) {
155
247
  console.log(a.cyan("\nSyncing memory with AutoMemoryBridge..."));
156
248
  try {
157
- const _bridge = new AutoMemoryBridge({});
158
- console.log(a.yellow("\u26A0 AutoMemoryBridge sync not yet implemented"));
159
- console.log(a.green("\u2713 Memory sync placeholder executed"));
249
+ const result = syncMemoryFiles({ projectPath });
250
+ if (result.source === "none") {
251
+ console.log(a.yellow("\u26A0 No memory content found in Claude or CCJK storage"));
252
+ console.log(a.gray(` Claude: ${result.paths.claude}`));
253
+ console.log(a.gray(` CCJK: ${result.paths.ccjk}`));
254
+ return;
255
+ }
256
+ const sourceLabel = result.source === "already-synced" ? "Claude and CCJK memory" : `${result.source === "claude" ? "Claude" : "CCJK"} memory`;
257
+ const targetLabel = result.updatedTargets.length === 0 ? "already in sync" : `updated ${result.updatedTargets.map((target) => target === "claude" ? "Claude" : "CCJK").join(", ")}`;
258
+ console.log(a.green(`\u2713 Synced ${sourceLabel} (${targetLabel})`));
259
+ console.log(a.gray(` Claude: ${result.paths.claude}`));
260
+ console.log(a.gray(` CCJK: ${result.paths.ccjk}`));
261
+ if (result.parseMode === "structured") {
262
+ console.log(a.gray(
263
+ ` Structured entries: ${result.entryCount} (facts ${result.factCount}, patterns ${result.patternCount}, decisions ${result.decisionCount})`
264
+ ));
265
+ } else if (result.parseMode === "freeform") {
266
+ console.log(a.gray(" Synced freeform notes (no structured headings detected)"));
267
+ }
160
268
  } catch (error) {
161
269
  console.error(a.red("Failed to sync memory:"), error);
162
270
  throw error;
163
271
  }
164
272
  }
165
273
  async function memoryCommand(options) {
166
- options.project || process.cwd();
167
274
  const memoryPath = getMemoryPath(options.project);
275
+ if (options.status) {
276
+ await showMemoryStatus(options.project);
277
+ return;
278
+ }
279
+ if (options.doctor) {
280
+ await runMemoryDoctor(options.project);
281
+ return;
282
+ }
168
283
  if (options.view) {
169
284
  const content = readMemory(memoryPath);
170
285
  const title = options.project ? `Project Memory: ${options.project}` : "Global Memory";
@@ -188,6 +303,8 @@ async function memoryCommand(options) {
188
303
  name: "action",
189
304
  message: "What would you like to do?",
190
305
  choices: [
306
+ { name: "\u{1F4CA} Status", value: "status" },
307
+ { name: "\u{1FA7A} Doctor", value: "doctor" },
191
308
  { name: "\u{1F441}\uFE0F View memory", value: "view" },
192
309
  { name: "\u270F\uFE0F Edit memory", value: "edit" },
193
310
  { name: "\u{1F504} Sync memory (AutoMemoryBridge)", value: "sync" },
@@ -197,6 +314,12 @@ async function memoryCommand(options) {
197
314
  }
198
315
  ]);
199
316
  switch (action) {
317
+ case "status":
318
+ await showMemoryStatus(options.project);
319
+ break;
320
+ case "doctor":
321
+ await runMemoryDoctor(options.project);
322
+ break;
200
323
  case "view": {
201
324
  const content = readMemory(memoryPath);
202
325
  const title = options.project ? `Project Memory: ${options.project}` : "Global Memory";
@@ -21,7 +21,7 @@ import 'string_decoder';
21
21
  import 'node:fs';
22
22
  import 'node:url';
23
23
  import '../shared/ccjk.bQ7Dh1g4.mjs';
24
- import '../shared/ccjk.0aJQmVxS.mjs';
24
+ import '../shared/ccjk.miT0g_vA.mjs';
25
25
  import 'node:child_process';
26
26
  import './constants.mjs';
27
27
  import './banner.mjs';
@@ -81,7 +81,7 @@ import './uninstall.mjs';
81
81
  import '../shared/ccjk.CvChMYvB.mjs';
82
82
  import 'globby';
83
83
  import './update.mjs';
84
- import '../shared/ccjk.LTONy3IS.mjs';
84
+ import '../shared/ccjk.BOfPON0N.mjs';
85
85
 
86
86
  function renderMenuHeader(context, _isZh) {
87
87
  const title = context.breadcrumb.join(i18n.t("menu:menu.breadcrumb.separator"));