chatccc 0.2.190 → 0.2.192
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/agent-prompts/claude_specific.md +45 -45
- package/agent-prompts/codex_specific.md +2 -2
- package/agent-prompts/cursor_specific.md +13 -13
- package/config.sample.json +14 -14
- package/im-skills/feishu-skill/receive-send-file.md +63 -63
- package/im-skills/feishu-skill/receive-send-image.md +24 -24
- package/im-skills/feishu-skill/skill.md +3 -3
- package/im-skills/wechat-file-skill/receive-send-file.md +38 -38
- package/im-skills/wechat-file-skill/send-file.mjs +83 -83
- package/im-skills/wechat-file-skill/skill.md +10 -10
- package/im-skills/wechat-image-skill/skill.md +10 -10
- package/im-skills/wechat-video-skill/receive-send-video.md +38 -38
- package/im-skills/wechat-video-skill/send-video.mjs +79 -79
- package/im-skills/wechat-video-skill/skill.md +10 -10
- package/package.json +1 -1
- package/scripts/postinstall-sharp-check.mjs +58 -58
- package/src/__tests__/agent-delegate-task-rpc.test.ts +165 -165
- package/src/__tests__/builtin-chat-session.test.ts +76 -0
- package/src/__tests__/builtin-config.test.ts +33 -33
- package/src/__tests__/builtin-context.test.ts +126 -0
- package/src/__tests__/builtin-sigint.test.ts +56 -0
- package/src/__tests__/card-plain-text.test.ts +5 -5
- package/src/__tests__/cardkit.test.ts +60 -60
- package/src/__tests__/cards.test.ts +77 -77
- package/src/__tests__/chatgpt-subscription-rpc.test.ts +89 -89
- package/src/__tests__/chatgpt-subscription.test.ts +135 -135
- package/src/__tests__/chrome-devtools-guard.test.ts +165 -165
- package/src/__tests__/claude-adapter.test.ts +592 -592
- package/src/__tests__/codex-reset-actions.test.ts +146 -146
- package/src/__tests__/config-reload.test.ts +4 -4
- package/src/__tests__/config-sample.test.ts +17 -17
- package/src/__tests__/feishu-api.test.ts +60 -60
- package/src/__tests__/feishu-platform.test.ts +22 -22
- package/src/__tests__/format-message.test.ts +47 -47
- package/src/__tests__/orchestrator.test.ts +120 -120
- package/src/__tests__/privacy.test.ts +198 -198
- package/src/__tests__/raw-stream-log.test.ts +106 -106
- package/src/__tests__/session.test.ts +17 -17
- package/src/__tests__/shared-prefix.test.ts +36 -36
- package/src/__tests__/stream-state.test.ts +42 -42
- package/src/__tests__/web-ui.test.ts +209 -209
- package/src/adapters/claude-adapter.ts +566 -566
- package/src/adapters/claude-session-meta-store.ts +120 -120
- package/src/adapters/codex-adapter.ts +30 -30
- package/src/adapters/cursor-adapter.ts +46 -46
- package/src/adapters/raw-stream-log.ts +124 -124
- package/src/adapters/resource-monitor.ts +140 -140
- package/src/agent-delegate-task-rpc.ts +153 -153
- package/src/agent-delegate-task.ts +81 -81
- package/src/agent-stop-stuck.ts +129 -129
- package/src/builtin/cli.ts +211 -189
- package/src/builtin/context.ts +225 -0
- package/src/builtin/index.ts +232 -170
- package/src/builtin/sigint.ts +50 -0
- package/src/cards.ts +137 -137
- package/src/chatgpt-subscription-rpc.ts +27 -27
- package/src/chatgpt-subscription.ts +299 -299
- package/src/chrome-devtools-guard.ts +318 -318
- package/src/codex-reset-actions.ts +184 -184
- package/src/config.ts +86 -86
- package/src/feishu-platform.ts +20 -20
- package/src/format-message.ts +293 -293
- package/src/litellm-proxy.ts +374 -374
- package/src/orchestrator.ts +143 -143
- package/src/privacy.ts +118 -118
- package/src/session-chat-binding.ts +6 -6
- package/src/session-name.ts +8 -8
- package/src/session.ts +98 -98
- package/src/shared-prefix.ts +29 -29
- package/src/sim-platform.ts +20 -20
- package/src/turn-cards.ts +117 -117
- package/src/web-ui.ts +205 -205
package/src/cards.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Button helpers
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
import { ABD_HELP_LINE } from "./shared-prefix.ts";
|
|
6
|
-
|
|
7
|
-
export interface ButtonDef {
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Button helpers
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
import { ABD_HELP_LINE } from "./shared-prefix.ts";
|
|
6
|
+
|
|
7
|
+
export interface ButtonDef {
|
|
8
8
|
text: string;
|
|
9
9
|
value: string;
|
|
10
10
|
type?: "primary" | "default" | "danger";
|
|
@@ -137,11 +137,11 @@ export function buildHelpCard(
|
|
|
137
137
|
"发送 **/newh** 重置当前会话(沿用当前工作目录,不切换)",
|
|
138
138
|
"发送 **/plan** 以规划模式提问(只读,不执行写操作)",
|
|
139
139
|
"发送 **/ask** 以问答模式提问(只读,不执行写操作)",
|
|
140
|
-
"发送 **/usage** 查看 Codex 5h/周用量,以及查询/使用主动重置卡",
|
|
141
|
-
"发送 **/restart** 重启 ChatCCC 进程",
|
|
142
|
-
"发送 **/update** 更新并重启(仅 npm 全局安装可用)",
|
|
143
|
-
ABD_HELP_LINE,
|
|
144
|
-
].join("\n");
|
|
140
|
+
"发送 **/usage** 查看 Codex 5h/周用量,以及查询/使用主动重置卡",
|
|
141
|
+
"发送 **/restart** 重启 ChatCCC 进程",
|
|
142
|
+
"发送 **/update** 更新并重启(仅 npm 全局安装可用)",
|
|
143
|
+
ABD_HELP_LINE,
|
|
144
|
+
].join("\n");
|
|
145
145
|
return JSON.stringify({
|
|
146
146
|
config: { wide_screen_mode: true },
|
|
147
147
|
header: { template: "blue", title: { content: "ChatCCC", tag: "plain_text" } },
|
|
@@ -410,11 +410,11 @@ export function buildQueueFullCard(): string {
|
|
|
410
410
|
}
|
|
411
411
|
|
|
412
412
|
// 状态卡片(带关闭按钮)
|
|
413
|
-
export function buildStatusCard(statusText: string, template = "blue"): string {
|
|
414
|
-
return JSON.stringify({
|
|
415
|
-
config: { wide_screen_mode: true },
|
|
416
|
-
header: { template, title: { content: "会话状态", tag: "plain_text" } },
|
|
417
|
-
elements: [
|
|
413
|
+
export function buildStatusCard(statusText: string, template = "blue"): string {
|
|
414
|
+
return JSON.stringify({
|
|
415
|
+
config: { wide_screen_mode: true },
|
|
416
|
+
header: { template, title: { content: "会话状态", tag: "plain_text" } },
|
|
417
|
+
elements: [
|
|
418
418
|
{ tag: "div", text: { tag: "lark_md", content: statusText } },
|
|
419
419
|
{ tag: "hr" },
|
|
420
420
|
{
|
|
@@ -426,82 +426,82 @@ export function buildStatusCard(statusText: string, template = "blue"): string {
|
|
|
426
426
|
value: { action: "close" },
|
|
427
427
|
}],
|
|
428
428
|
},
|
|
429
|
-
],
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
export function buildCodexUsageCard(content: string, resetCreditsAvailable: number | null): string {
|
|
434
|
-
const elements: object[] = [
|
|
435
|
-
{ tag: "div", text: { tag: "lark_md", content } },
|
|
436
|
-
];
|
|
437
|
-
if (resetCreditsAvailable !== null && resetCreditsAvailable > 0) {
|
|
438
|
-
elements.push({ tag: "hr" });
|
|
439
|
-
elements.push({
|
|
440
|
-
tag: "action",
|
|
441
|
-
actions: [{
|
|
442
|
-
tag: "button",
|
|
443
|
-
text: { tag: "plain_text", content: "发起重置" },
|
|
444
|
-
type: "primary",
|
|
445
|
-
value: { action: "codex_reset_request", availableCount: resetCreditsAvailable },
|
|
446
|
-
}],
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
return JSON.stringify({
|
|
451
|
-
config: { wide_screen_mode: true },
|
|
452
|
-
header: { template: "blue", title: { content: "Codex Usage", tag: "plain_text" } },
|
|
453
|
-
elements,
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
export function buildCodexResetConfirmCard(params: {
|
|
458
|
-
availableCount: number;
|
|
459
|
-
parentMessageId: string;
|
|
460
|
-
requestId: string;
|
|
461
|
-
}): string {
|
|
462
|
-
const valueBase = {
|
|
463
|
-
parentMessageId: params.parentMessageId,
|
|
464
|
-
requestId: params.requestId,
|
|
465
|
-
};
|
|
466
|
-
return JSON.stringify({
|
|
467
|
-
config: { wide_screen_mode: true },
|
|
468
|
-
header: { template: "yellow", title: { content: "确认 Codex 主动重置", tag: "plain_text" } },
|
|
469
|
-
elements: [
|
|
470
|
-
{
|
|
471
|
-
tag: "div",
|
|
472
|
-
text: {
|
|
473
|
-
tag: "lark_md",
|
|
474
|
-
content: `当前可用主动重置次数:**${params.availableCount}**。\n\n确认后会消耗 1 次主动重置,并重置当前可重置的 Codex 用量窗口。`,
|
|
475
|
-
},
|
|
476
|
-
},
|
|
477
|
-
{ tag: "hr" },
|
|
478
|
-
{
|
|
479
|
-
tag: "action",
|
|
480
|
-
actions: [
|
|
481
|
-
{
|
|
482
|
-
tag: "button",
|
|
483
|
-
text: { tag: "plain_text", content: "是,发起重置" },
|
|
484
|
-
type: "danger",
|
|
485
|
-
value: { action: "codex_reset_confirm", decision: "yes", ...valueBase },
|
|
486
|
-
},
|
|
487
|
-
{
|
|
488
|
-
tag: "button",
|
|
489
|
-
text: { tag: "plain_text", content: "否" },
|
|
490
|
-
type: "default",
|
|
491
|
-
value: { action: "codex_reset_confirm", decision: "no", ...valueBase },
|
|
492
|
-
},
|
|
493
|
-
],
|
|
494
|
-
},
|
|
495
|
-
],
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
/** 模型切换卡片(/model 命令,飞书专用,含切换按钮) */
|
|
500
|
-
export function buildModelCard(
|
|
501
|
-
currentModel: string,
|
|
502
|
-
models: string[],
|
|
503
|
-
tool?: string,
|
|
504
|
-
): string {
|
|
429
|
+
],
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export function buildCodexUsageCard(content: string, resetCreditsAvailable: number | null): string {
|
|
434
|
+
const elements: object[] = [
|
|
435
|
+
{ tag: "div", text: { tag: "lark_md", content } },
|
|
436
|
+
];
|
|
437
|
+
if (resetCreditsAvailable !== null && resetCreditsAvailable > 0) {
|
|
438
|
+
elements.push({ tag: "hr" });
|
|
439
|
+
elements.push({
|
|
440
|
+
tag: "action",
|
|
441
|
+
actions: [{
|
|
442
|
+
tag: "button",
|
|
443
|
+
text: { tag: "plain_text", content: "发起重置" },
|
|
444
|
+
type: "primary",
|
|
445
|
+
value: { action: "codex_reset_request", availableCount: resetCreditsAvailable },
|
|
446
|
+
}],
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return JSON.stringify({
|
|
451
|
+
config: { wide_screen_mode: true },
|
|
452
|
+
header: { template: "blue", title: { content: "Codex Usage", tag: "plain_text" } },
|
|
453
|
+
elements,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function buildCodexResetConfirmCard(params: {
|
|
458
|
+
availableCount: number;
|
|
459
|
+
parentMessageId: string;
|
|
460
|
+
requestId: string;
|
|
461
|
+
}): string {
|
|
462
|
+
const valueBase = {
|
|
463
|
+
parentMessageId: params.parentMessageId,
|
|
464
|
+
requestId: params.requestId,
|
|
465
|
+
};
|
|
466
|
+
return JSON.stringify({
|
|
467
|
+
config: { wide_screen_mode: true },
|
|
468
|
+
header: { template: "yellow", title: { content: "确认 Codex 主动重置", tag: "plain_text" } },
|
|
469
|
+
elements: [
|
|
470
|
+
{
|
|
471
|
+
tag: "div",
|
|
472
|
+
text: {
|
|
473
|
+
tag: "lark_md",
|
|
474
|
+
content: `当前可用主动重置次数:**${params.availableCount}**。\n\n确认后会消耗 1 次主动重置,并重置当前可重置的 Codex 用量窗口。`,
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
{ tag: "hr" },
|
|
478
|
+
{
|
|
479
|
+
tag: "action",
|
|
480
|
+
actions: [
|
|
481
|
+
{
|
|
482
|
+
tag: "button",
|
|
483
|
+
text: { tag: "plain_text", content: "是,发起重置" },
|
|
484
|
+
type: "danger",
|
|
485
|
+
value: { action: "codex_reset_confirm", decision: "yes", ...valueBase },
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
tag: "button",
|
|
489
|
+
text: { tag: "plain_text", content: "否" },
|
|
490
|
+
type: "default",
|
|
491
|
+
value: { action: "codex_reset_confirm", decision: "no", ...valueBase },
|
|
492
|
+
},
|
|
493
|
+
],
|
|
494
|
+
},
|
|
495
|
+
],
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/** 模型切换卡片(/model 命令,飞书专用,含切换按钮) */
|
|
500
|
+
export function buildModelCard(
|
|
501
|
+
currentModel: string,
|
|
502
|
+
models: string[],
|
|
503
|
+
tool?: string,
|
|
504
|
+
): string {
|
|
505
505
|
const toolLabel = tool ? ` (${tool})` : "";
|
|
506
506
|
const currentLine = currentModel
|
|
507
507
|
? `**当前模型:** \`${currentModel}\``
|
|
@@ -535,48 +535,48 @@ export function buildModelCard(
|
|
|
535
535
|
{ tag: "div", text: { tag: "lark_md", content: lines.join("\n") } },
|
|
536
536
|
{ tag: "hr" },
|
|
537
537
|
buildButtons(buttons),
|
|
538
|
-
],
|
|
539
|
-
});
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
export function buildEffortCard(
|
|
543
|
-
currentEffort: string,
|
|
544
|
-
efforts: string[],
|
|
545
|
-
tool?: string,
|
|
546
|
-
): string {
|
|
547
|
-
const toolLabel = tool ? ` (${tool})` : "";
|
|
548
|
-
const currentLine = currentEffort
|
|
549
|
-
? `**当前 effort:** \`${currentEffort}\``
|
|
550
|
-
: "**当前 effort:** 未指定";
|
|
551
|
-
|
|
552
|
-
const lines: string[] = [currentLine];
|
|
553
|
-
if (efforts.length > 0) {
|
|
554
|
-
lines.push("", "**可切换 effort**");
|
|
555
|
-
for (const effort of efforts) {
|
|
556
|
-
lines.push(`- \`${effort}\``);
|
|
557
|
-
}
|
|
558
|
-
lines.push("", "点击按钮切换 effort,或输入 `/effort clear` 恢复默认");
|
|
559
|
-
} else {
|
|
560
|
-
lines.push("", "当前 agent 不支持 effort 切换。");
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
const buttons: ButtonDef[] = [];
|
|
564
|
-
for (const effort of efforts.slice(0, 20)) {
|
|
565
|
-
buttons.push({
|
|
566
|
-
text: `/effort ${effort}`,
|
|
567
|
-
value: JSON.stringify({ cmd: `/effort ${effort}` }),
|
|
568
|
-
type: "primary",
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
return JSON.stringify({
|
|
573
|
-
config: { wide_screen_mode: true },
|
|
574
|
-
header: { template: "blue", title: { content: `Effort 切换${toolLabel}`, tag: "plain_text" } },
|
|
575
|
-
elements: [
|
|
576
|
-
{ tag: "div", text: { tag: "lark_md", content: lines.join("\n") } },
|
|
577
|
-
{ tag: "hr" },
|
|
578
|
-
buildButtons(buttons),
|
|
579
|
-
],
|
|
580
|
-
});
|
|
581
|
-
}
|
|
538
|
+
],
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
export function buildEffortCard(
|
|
543
|
+
currentEffort: string,
|
|
544
|
+
efforts: string[],
|
|
545
|
+
tool?: string,
|
|
546
|
+
): string {
|
|
547
|
+
const toolLabel = tool ? ` (${tool})` : "";
|
|
548
|
+
const currentLine = currentEffort
|
|
549
|
+
? `**当前 effort:** \`${currentEffort}\``
|
|
550
|
+
: "**当前 effort:** 未指定";
|
|
551
|
+
|
|
552
|
+
const lines: string[] = [currentLine];
|
|
553
|
+
if (efforts.length > 0) {
|
|
554
|
+
lines.push("", "**可切换 effort**");
|
|
555
|
+
for (const effort of efforts) {
|
|
556
|
+
lines.push(`- \`${effort}\``);
|
|
557
|
+
}
|
|
558
|
+
lines.push("", "点击按钮切换 effort,或输入 `/effort clear` 恢复默认");
|
|
559
|
+
} else {
|
|
560
|
+
lines.push("", "当前 agent 不支持 effort 切换。");
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const buttons: ButtonDef[] = [];
|
|
564
|
+
for (const effort of efforts.slice(0, 20)) {
|
|
565
|
+
buttons.push({
|
|
566
|
+
text: `/effort ${effort}`,
|
|
567
|
+
value: JSON.stringify({ cmd: `/effort ${effort}` }),
|
|
568
|
+
type: "primary",
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return JSON.stringify({
|
|
573
|
+
config: { wide_screen_mode: true },
|
|
574
|
+
header: { template: "blue", title: { content: `Effort 切换${toolLabel}`, tag: "plain_text" } },
|
|
575
|
+
elements: [
|
|
576
|
+
{ tag: "div", text: { tag: "lark_md", content: lines.join("\n") } },
|
|
577
|
+
{ tag: "hr" },
|
|
578
|
+
buildButtons(buttons),
|
|
579
|
+
],
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
582
|
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
-
|
|
3
|
-
import { getChatGptSubscriptionStatus } from "./chatgpt-subscription.ts";
|
|
4
|
-
|
|
5
|
-
export const CHATGPT_SUBSCRIPTION_PATH = "/api/chatgpt/subscription";
|
|
6
|
-
|
|
7
|
-
function jsonReply(res: ServerResponse, code: number, data: unknown): void {
|
|
8
|
-
res.writeHead(code, { "Content-Type": "application/json; charset=utf-8" });
|
|
9
|
-
res.end(JSON.stringify(data));
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export async function handleChatGptSubscriptionRequest(
|
|
13
|
-
req: IncomingMessage,
|
|
14
|
-
res: ServerResponse,
|
|
15
|
-
): Promise<boolean> {
|
|
16
|
-
const method = req.method ?? "GET";
|
|
17
|
-
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
18
|
-
if (url.pathname !== CHATGPT_SUBSCRIPTION_PATH) return false;
|
|
19
|
-
|
|
20
|
-
if (method !== "GET") {
|
|
21
|
-
jsonReply(res, 405, { ok: false, code: "method_not_allowed", reason: "Use GET." });
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
jsonReply(res, 200, await getChatGptSubscriptionStatus());
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
|
|
3
|
+
import { getChatGptSubscriptionStatus } from "./chatgpt-subscription.ts";
|
|
4
|
+
|
|
5
|
+
export const CHATGPT_SUBSCRIPTION_PATH = "/api/chatgpt/subscription";
|
|
6
|
+
|
|
7
|
+
function jsonReply(res: ServerResponse, code: number, data: unknown): void {
|
|
8
|
+
res.writeHead(code, { "Content-Type": "application/json; charset=utf-8" });
|
|
9
|
+
res.end(JSON.stringify(data));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function handleChatGptSubscriptionRequest(
|
|
13
|
+
req: IncomingMessage,
|
|
14
|
+
res: ServerResponse,
|
|
15
|
+
): Promise<boolean> {
|
|
16
|
+
const method = req.method ?? "GET";
|
|
17
|
+
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
18
|
+
if (url.pathname !== CHATGPT_SUBSCRIPTION_PATH) return false;
|
|
19
|
+
|
|
20
|
+
if (method !== "GET") {
|
|
21
|
+
jsonReply(res, 405, { ok: false, code: "method_not_allowed", reason: "Use GET." });
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
jsonReply(res, 200, await getChatGptSubscriptionStatus());
|
|
26
|
+
return true;
|
|
27
|
+
}
|