chatccc 0.2.161 → 0.2.162
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 +1 -0
- package/package.json +1 -1
- package/src/__tests__/card-plain-text.test.ts +1 -0
- package/src/__tests__/cards.test.ts +1 -1
- package/src/cards.ts +3 -0
- package/src/index.ts +1 -1
- package/src/orchestrator.ts +57 -2
package/README.md
CHANGED
|
@@ -313,6 +313,7 @@ Codex 的默认模型和推理强度可继续由 `~/.codex/config.toml` 管理
|
|
|
313
313
|
| `/plan <内容>` | 只读计划模式:仅允许读文件和 stop-stuck-loop 请求,不执行任何写操作 |
|
|
314
314
|
| `/ask <内容>` | 只读问答模式:与 /plan 相同,仅允许读文件和 stop-stuck-loop 请求 |
|
|
315
315
|
| `/restart` | 重启机器人进程 |
|
|
316
|
+
| `/updateg` | 更新 npm 全局包并重启(仅限 `npm install -g chatccc` 安装的全局进程) |
|
|
316
317
|
|
|
317
318
|
> **模型切换**:`/model` 查看可选模型清单,`/model <名称>` 模糊匹配切换,`/model clear` 恢复默认。当前仅 Claude Code 支持模型切换(需同时填写 `claude.model` 和 `claude.subagentModel`),Cursor / Codex 切换正在开发中。
|
|
318
319
|
|
package/package.json
CHANGED
|
@@ -156,7 +156,7 @@ describe("buildHelpCard", () => {
|
|
|
156
156
|
const parsed = JSON.parse(card);
|
|
157
157
|
const action = parsed.elements[2];
|
|
158
158
|
expect(action.tag).toBe("action");
|
|
159
|
-
expect(action.actions).toHaveLength(
|
|
159
|
+
expect(action.actions).toHaveLength(7);
|
|
160
160
|
});
|
|
161
161
|
});
|
|
162
162
|
|
package/src/cards.ts
CHANGED
|
@@ -135,6 +135,8 @@ export function buildHelpCard(
|
|
|
135
135
|
"发送 **/newh** 重置当前会话(沿用当前工作目录,不切换)",
|
|
136
136
|
"发送 **/plan** 以规划模式提问(只读,不执行写操作)",
|
|
137
137
|
"发送 **/ask** 以问答模式提问(只读,不执行写操作)",
|
|
138
|
+
"发送 **/restart** 重启 ChatCCC 进程",
|
|
139
|
+
"发送 **/updateg** 更新并重启(仅 npm 全局安装可用)",
|
|
138
140
|
].join("\n");
|
|
139
141
|
return JSON.stringify({
|
|
140
142
|
config: { wide_screen_mode: true },
|
|
@@ -148,6 +150,7 @@ export function buildHelpCard(
|
|
|
148
150
|
{ text: "新建 Cursor 会话(/new cursor)", value: JSON.stringify({ cmd: "new cursor" }), type: "primary" },
|
|
149
151
|
{ text: "新建 Codex 会话(/new codex)", value: JSON.stringify({ cmd: "new codex" }), type: "primary" },
|
|
150
152
|
{ text: "重启 ChatCCC(/restart)", value: JSON.stringify({ cmd: "restart" }), type: "danger" },
|
|
153
|
+
{ text: "更新并重启(/updateg)", value: JSON.stringify({ cmd: "updateg" }), type: "danger" },
|
|
151
154
|
{ text: "切换工作路径(/cd)", value: JSON.stringify({ cmd: "cd" }), type: "default" },
|
|
152
155
|
]),
|
|
153
156
|
],
|
package/src/index.ts
CHANGED
|
@@ -213,7 +213,7 @@ function parseCardAction(data: unknown): CardActionResult | null {
|
|
|
213
213
|
}
|
|
214
214
|
if (!cmd) return null;
|
|
215
215
|
|
|
216
|
-
const CMD_MAP: Record<string, string> = { stop: "/stop", cancel: "/cancel", new: "/new", "new claude": "/new claude", "new cursor": "/new cursor", "new codex": "/new codex", restart: "/restart", state: "/state", cd: "/cd", sessions: "/sessions", newh: "/newh" };
|
|
216
|
+
const CMD_MAP: Record<string, string> = { stop: "/stop", cancel: "/cancel", new: "/new", "new claude": "/new claude", "new cursor": "/new cursor", "new codex": "/new codex", restart: "/restart", updateg: "/updateg", state: "/state", cd: "/cd", sessions: "/sessions", newh: "/newh" };
|
|
217
217
|
let text = CMD_MAP[cmd] ?? "";
|
|
218
218
|
if (cmd === "cd" && typeof action.value === "object" && action.value !== null) {
|
|
219
219
|
const path = (action.value as Record<string, string>).path;
|
package/src/orchestrator.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* 所有 IM 平台操作通过 PlatformAdapter 接口注入,不直接依赖 feishu-platform.ts。
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { spawn } from "node:child_process";
|
|
8
|
+
import { execSync, spawn } from "node:child_process";
|
|
9
9
|
import { readdir, stat } from "node:fs/promises";
|
|
10
|
-
import { readFileSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
11
11
|
import { resolve, dirname } from "node:path";
|
|
12
12
|
|
|
13
13
|
import { makeTraceId, logTrace } from "./trace.ts";
|
|
@@ -159,6 +159,45 @@ async function cleanupNonWechatP2pBinding(
|
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
/** 检测当前进程是否从 npm 全局安装启动 */
|
|
163
|
+
function isRunningFromGlobalNpm(): boolean {
|
|
164
|
+
try {
|
|
165
|
+
const globalRoot = execSync("npm root -g", { encoding: "utf8", timeout: 5000, windowsHide: true }).trim();
|
|
166
|
+
return resolve(PROJECT_ROOT).startsWith(resolve(globalRoot));
|
|
167
|
+
} catch {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** 更新并重启:spawn detached Node.js 中间脚本,轮询父进程退出后执行 npm update + chatccc */
|
|
173
|
+
function scheduleUpdateRestart(): void {
|
|
174
|
+
const parentPid = process.pid;
|
|
175
|
+
const watcherScript = `
|
|
176
|
+
var spawn = require('child_process').spawn;
|
|
177
|
+
var execSync = require('child_process').execSync;
|
|
178
|
+
var parentPid = ${parentPid};
|
|
179
|
+
(function wait() {
|
|
180
|
+
try { process.kill(parentPid, 0); setTimeout(wait, 300); } catch (_) {
|
|
181
|
+
try {
|
|
182
|
+
var npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
183
|
+
execSync(npmCmd + ' update -g chatccc', { stdio: 'inherit' });
|
|
184
|
+
} catch (e) {
|
|
185
|
+
console.error('npm update failed:', e.message);
|
|
186
|
+
}
|
|
187
|
+
var c = spawn('chatccc', [], { detached: true, stdio: 'ignore', shell: true });
|
|
188
|
+
c.unref();
|
|
189
|
+
process.exit(0);
|
|
190
|
+
}
|
|
191
|
+
})();
|
|
192
|
+
`;
|
|
193
|
+
const child = spawn("node", ["-e", watcherScript], {
|
|
194
|
+
detached: true,
|
|
195
|
+
stdio: "ignore",
|
|
196
|
+
shell: true,
|
|
197
|
+
});
|
|
198
|
+
child.unref();
|
|
199
|
+
}
|
|
200
|
+
|
|
162
201
|
// ---------------------------------------------------------------------------
|
|
163
202
|
// handleCommand — 平台无关的命令分发
|
|
164
203
|
// ---------------------------------------------------------------------------
|
|
@@ -212,6 +251,22 @@ export async function handleCommand(
|
|
|
212
251
|
return;
|
|
213
252
|
}
|
|
214
253
|
|
|
254
|
+
if (textLower === "/updateg") {
|
|
255
|
+
logTrace(tid, "BRANCH", { cmd: "/updateg" });
|
|
256
|
+
if (!isRunningFromGlobalNpm()) {
|
|
257
|
+
await platform.sendText(chatId, "当前进程非 npm 全局安装,无法使用 /updateg 更新。请通过 npm install -g chatccc 安装后使用。").catch(() => {});
|
|
258
|
+
logTrace(tid, "DONE", { outcome: "updateg_not_global" });
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
await platform.sendText(chatId, "正在更新并重启,请稍候...").catch(() => {});
|
|
262
|
+
logTrace(tid, "DONE", { outcome: "updateg" });
|
|
263
|
+
appendStartupTrace("updateg: spawn watcher begin", { fromPid: process.pid });
|
|
264
|
+
scheduleUpdateRestart();
|
|
265
|
+
// 短暂延迟确保消息发送后再退出
|
|
266
|
+
setTimeout(() => process.exit(0), 500);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
215
270
|
if (textLower === "/cd" || textLower.startsWith("/cd ")) {
|
|
216
271
|
logTrace(tid, "BRANCH", {
|
|
217
272
|
cmd: "/cd",
|