@cc-claw/code 0.6.144 → 0.6.146

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,6 +7,10 @@
7
7
 
8
8
  ## 最近更新
9
9
 
10
+ v0.6.146:修复 Windows CI 上 cc-tui 测试的间歇性失败(**内部改动,无用户可见行为变化**)——这些用例用固定墙钟超时等待真实子进程(`cmd`/git-bash/嵌套 powershell),libtest 并发时互相抢进程与 IO,在 4 核 runner 上被放大成超时;现用全局锁串行化真起进程的用例并统一放宽等待预算,不改任何用例语义(#538)。
11
+
12
+ v0.6.145:三项 TUI 输入修复——① 输入框内 `/command` 用 suggestion 蓝高亮,规则对齐 Claude Code(`!` shell 态跳过,避免把 `/etc` 之类路径着色)(#529);② Rewind 对话回滚从「双击 `Esc`」改为正式命令 `/rewind`(别名 `/undo`)——`Esc` 是取消/中断键,连按两次会误弹出回滚面板,而输入 `/rewind` 反而无效(#531);③ Agent 运行中按 `Enter` 不再把命令静默变成模型提问——此前 `/exit` 不退出、`/gc` 不回收内存、未知命令反被模型回答。判定收敛到唯一入口 `CommandSystem::resolve`:普通消息 / Skill / ACP 命令 / 转发型命令入队等本轮结束后执行,需要空闲 UI 的命令、`!` 输入与未知命令一律拒绝并**保留输入框内容**(#533)。
13
+
10
14
  v0.6.144:修复后台子 Agent 抽屉「正在做什么」列的闪动——该列不再被工具名(`Bash`/`Grep`)覆盖,只显示子 Agent 最近一句助手文本;并新增 200ms 刷新节流(渲染快照,丢渲染帧不丢状态,结束时立即同步)。
11
15
 
12
16
  v0.6.143:修复两个 `/theme` 相关问题——① 主题面板补齐键盘路由,此前 `↑`/`↓` 不移动光标、`Esc` 关不掉面板(#521);② 状态栏配色固定、不再随主题切换,恢复打磨定稿的固定观感(#523)。
@@ -72,7 +76,6 @@ cc-code --model deepseek/deepseek-chat "重构这个函数"
72
76
  | `Alt+V` / `Ctrl+V` | 从剪贴板粘贴图片附件(`Alt+V` 专用于穿透 Windows Terminal 等现代终端对 `Ctrl+V` 的拦截) |
73
77
  | `Ctrl+O` | 切换详细模式(Verbose) |
74
78
  | `Ctrl+U` / `Ctrl+D` | 消息列表快速半页滚动(输入框为空时) |
75
- | `双击 Esc` | 打开 Rewind 会话历史回滚选择器 |
76
79
  | `Ctrl+C` | 中断执行(执行中)/ 双击退出(空闲时) |
77
80
 
78
81
  ## 常用 Slash 命令
@@ -86,6 +89,7 @@ cc-code --model deepseek/deepseek-chat "重构这个函数"
86
89
  | `/gc` | 手动释放内存并输出内存占用诊断信息 |
87
90
  | `/lang <lang>` | 切换系统提示与界面语言(en / zh-CN) |
88
91
  | `/recap` | 生成一句话会话回顾(目标 + 当前任务 + 下一步),别名 `/away`、`/catchup` |
92
+ | `/rewind` | 打开会话历史回滚选择器,回退到某条历史消息,别名 `/undo` |
89
93
  | `/clear` | 清空屏幕开启新会话 |
90
94
 
91
95
  ## 为什么选 cc-code?
package/install.js CHANGED
@@ -236,6 +236,44 @@ function backfillModels(ccCodeSettingsPath, detected) {
236
236
  return true;
237
237
  }
238
238
 
239
+ // 统一项目记忆目录:Claude Code 与 cc-code 各维护一份 projects/<slug>/memory,一旦两侧
240
+ // 都落过盘,记忆就会写散(系统提示对外呈现的 ~/.cc-code 路径,与实际读写的 ~/.claude
241
+ // 目录并不是同一份)。安装时把 Claude Code 侧已有的记忆目录在 cc-code 侧以链接接过来,
242
+ // 使两侧读写同一份物理目录:Windows 用 junction(免管理员权限),Unix 用目录符号链接。
243
+ // 只做 .claude -> .cc-code 单向,不往用户的 Claude Code 目录里添东西;
244
+ // 目标已存在(用户自己的数据或已建好的链接)一律不碰,任何失败只跳过、不影响安装。
245
+ function linkProjectMemories(home = homedir()) {
246
+ const linkType = process.platform === "win32" ? "junction" : "dir";
247
+ const from = join(home, ".claude", "projects");
248
+ const to = join(home, ".cc-code", "projects");
249
+
250
+ let entries;
251
+ try {
252
+ entries = readdirSync(from, { withFileTypes: true });
253
+ } catch {
254
+ return 0; // 没用过 Claude Code,没有可承接的记忆
255
+ }
256
+
257
+ let linked = 0;
258
+ for (const entry of entries) {
259
+ if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
260
+ const source = join(from, entry.name, "memory");
261
+ const target = join(to, entry.name, "memory");
262
+ if (!existsSync(source) || existsSync(target)) continue;
263
+ try {
264
+ mkdirSync(dirname(target), { recursive: true });
265
+ fs.symlinkSync(source, target, linkType);
266
+ linked++;
267
+ } catch (err) {
268
+ console.log(` (skipped memory link for ${entry.name}: ${err.message})`);
269
+ }
270
+ }
271
+ if (linked > 0) {
272
+ console.log(` Linked ${linked} Claude Code project memory dir(s) into ~/.cc-code/projects/`);
273
+ }
274
+ return linked;
275
+ }
276
+
239
277
  function migrateFromClaudeCode(home = homedir()) {
240
278
  const claudeSettingsPath = join(home, ".claude", "settings.json");
241
279
  const ccCodeDir = join(home, ".cc-code");
@@ -547,6 +585,9 @@ async function main() {
547
585
  // #290:密钥迁移需显式确认,不再静默复制
548
586
  const migrated = await maybeMigrateFromClaudeCode();
549
587
 
588
+ // 让 Claude Code 与 cc-code 共用同一份项目记忆目录(避免记忆写散到两侧)
589
+ linkProjectMemories();
590
+
550
591
  if (!migrated) {
551
592
  console.log("");
552
593
  console.log("─── Quick Start ───");
@@ -594,6 +635,7 @@ if (require.main === module) {
594
635
  }
595
636
 
596
637
  module.exports = {
638
+ linkProjectMemories,
597
639
  migrateFromClaudeCode,
598
640
  maybeMigrateFromClaudeCode,
599
641
  wouldCopyKeys,
package/install.test.js CHANGED
@@ -342,5 +342,63 @@ test("cleanOldBinaries unlinks released .old files and ignores still-locked ones
342
342
  if (fs.existsSync(inactiveOld)) throw new Error("inactiveOld should be unlinked");
343
343
  });
344
344
 
345
+ // --- linkProjectMemories ---
346
+ const { linkProjectMemories } = require("./install");
347
+
348
+ function writeMemoryDir(dir) {
349
+ fs.mkdirSync(dir, { recursive: true });
350
+ fs.writeFileSync(join(dir, "MEMORY.md"), "# Memory Index\n");
351
+ }
352
+
353
+ test("linkProjectMemories links Claude Code project memory into the cc-code side", (home) => {
354
+ const claudeMem = join(home, ".claude", "projects", "D--code-demo", "memory");
355
+ writeMemoryDir(claudeMem);
356
+
357
+ const linked = linkProjectMemories(home);
358
+ if (linked !== 1) throw new Error(`expected 1 link, got ${linked}`);
359
+
360
+ const ccMem = join(home, ".cc-code", "projects", "D--code-demo", "memory");
361
+ if (!fs.existsSync(join(ccMem, "MEMORY.md"))) throw new Error("memory not reachable via cc-code path");
362
+
363
+ // 写穿透:经 cc-code 侧写入必须落到 Claude Code 侧同一份
364
+ fs.writeFileSync(join(ccMem, "user_role.md"), "shared");
365
+ if (!fs.existsSync(join(claudeMem, "user_role.md"))) {
366
+ throw new Error("cc-code path is a separate physical directory, not a link");
367
+ }
368
+ });
369
+
370
+ test("linkProjectMemories leaves a cc-code-only project untouched", (home) => {
371
+ const ccMem = join(home, ".cc-code", "projects", "D--code-demo", "memory");
372
+ writeMemoryDir(ccMem);
373
+
374
+ const linked = linkProjectMemories(home);
375
+ if (linked !== 0) throw new Error(`expected 0 links, got ${linked}`);
376
+ if (fs.existsSync(join(home, ".claude", "projects", "D--code-demo"))) {
377
+ throw new Error("must not add anything under ~/.claude");
378
+ }
379
+ });
380
+
381
+ test("linkProjectMemories never overwrites an existing project memory dir", (home) => {
382
+ writeMemoryDir(join(home, ".claude", "projects", "D--code-demo", "memory"));
383
+ const ccMem = join(home, ".cc-code", "projects", "D--code-demo", "memory");
384
+ writeMemoryDir(ccMem);
385
+ fs.writeFileSync(join(ccMem, "own.md"), "keep me");
386
+
387
+ const linked = linkProjectMemories(home);
388
+ if (linked !== 0) throw new Error(`expected 0 links, got ${linked}`);
389
+ if (fs.readFileSync(join(ccMem, "own.md"), "utf-8") !== "keep me") {
390
+ throw new Error("existing cc-code memory content was touched");
391
+ }
392
+ if (fs.lstatSync(ccMem).isSymbolicLink()) throw new Error("existing dir must not be replaced by a link");
393
+ });
394
+
395
+ test("linkProjectMemories is idempotent and no-ops without project memory", (home) => {
396
+ if (linkProjectMemories(home) !== 0) throw new Error("expected 0 links on empty home");
397
+
398
+ writeMemoryDir(join(home, ".claude", "projects", "D--code-demo", "memory"));
399
+ if (linkProjectMemories(home) !== 1) throw new Error("first run should link 1");
400
+ if (linkProjectMemories(home) !== 0) throw new Error("second run should link nothing");
401
+ });
402
+
345
403
  // 由 runTests() 顺序执行(支持 async 用例)
346
404
  runTests();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cc-claw/code",
3
- "version": "0.6.144",
3
+ "version": "0.6.146",
4
4
  "description": "cc-code — Terminal coding agent powered by open-source models — Rust-built, Claude Code compatible",
5
5
  "keywords": [
6
6
  "agent",