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.
Files changed (72) hide show
  1. package/agent-prompts/claude_specific.md +45 -45
  2. package/agent-prompts/codex_specific.md +2 -2
  3. package/agent-prompts/cursor_specific.md +13 -13
  4. package/config.sample.json +14 -14
  5. package/im-skills/feishu-skill/receive-send-file.md +63 -63
  6. package/im-skills/feishu-skill/receive-send-image.md +24 -24
  7. package/im-skills/feishu-skill/skill.md +3 -3
  8. package/im-skills/wechat-file-skill/receive-send-file.md +38 -38
  9. package/im-skills/wechat-file-skill/send-file.mjs +83 -83
  10. package/im-skills/wechat-file-skill/skill.md +10 -10
  11. package/im-skills/wechat-image-skill/skill.md +10 -10
  12. package/im-skills/wechat-video-skill/receive-send-video.md +38 -38
  13. package/im-skills/wechat-video-skill/send-video.mjs +79 -79
  14. package/im-skills/wechat-video-skill/skill.md +10 -10
  15. package/package.json +1 -1
  16. package/scripts/postinstall-sharp-check.mjs +58 -58
  17. package/src/__tests__/agent-delegate-task-rpc.test.ts +165 -165
  18. package/src/__tests__/builtin-chat-session.test.ts +76 -0
  19. package/src/__tests__/builtin-config.test.ts +33 -33
  20. package/src/__tests__/builtin-context.test.ts +126 -0
  21. package/src/__tests__/builtin-sigint.test.ts +56 -0
  22. package/src/__tests__/card-plain-text.test.ts +5 -5
  23. package/src/__tests__/cardkit.test.ts +60 -60
  24. package/src/__tests__/cards.test.ts +77 -77
  25. package/src/__tests__/chatgpt-subscription-rpc.test.ts +89 -89
  26. package/src/__tests__/chatgpt-subscription.test.ts +135 -135
  27. package/src/__tests__/chrome-devtools-guard.test.ts +165 -165
  28. package/src/__tests__/claude-adapter.test.ts +592 -592
  29. package/src/__tests__/codex-reset-actions.test.ts +146 -146
  30. package/src/__tests__/config-reload.test.ts +4 -4
  31. package/src/__tests__/config-sample.test.ts +17 -17
  32. package/src/__tests__/feishu-api.test.ts +60 -60
  33. package/src/__tests__/feishu-platform.test.ts +22 -22
  34. package/src/__tests__/format-message.test.ts +47 -47
  35. package/src/__tests__/orchestrator.test.ts +120 -120
  36. package/src/__tests__/privacy.test.ts +198 -198
  37. package/src/__tests__/raw-stream-log.test.ts +106 -106
  38. package/src/__tests__/session.test.ts +17 -17
  39. package/src/__tests__/shared-prefix.test.ts +36 -36
  40. package/src/__tests__/stream-state.test.ts +42 -42
  41. package/src/__tests__/web-ui.test.ts +209 -209
  42. package/src/adapters/claude-adapter.ts +566 -566
  43. package/src/adapters/claude-session-meta-store.ts +120 -120
  44. package/src/adapters/codex-adapter.ts +30 -30
  45. package/src/adapters/cursor-adapter.ts +46 -46
  46. package/src/adapters/raw-stream-log.ts +124 -124
  47. package/src/adapters/resource-monitor.ts +140 -140
  48. package/src/agent-delegate-task-rpc.ts +153 -153
  49. package/src/agent-delegate-task.ts +81 -81
  50. package/src/agent-stop-stuck.ts +129 -129
  51. package/src/builtin/cli.ts +211 -189
  52. package/src/builtin/context.ts +225 -0
  53. package/src/builtin/index.ts +232 -170
  54. package/src/builtin/sigint.ts +50 -0
  55. package/src/cards.ts +137 -137
  56. package/src/chatgpt-subscription-rpc.ts +27 -27
  57. package/src/chatgpt-subscription.ts +299 -299
  58. package/src/chrome-devtools-guard.ts +318 -318
  59. package/src/codex-reset-actions.ts +184 -184
  60. package/src/config.ts +86 -86
  61. package/src/feishu-platform.ts +20 -20
  62. package/src/format-message.ts +293 -293
  63. package/src/litellm-proxy.ts +374 -374
  64. package/src/orchestrator.ts +143 -143
  65. package/src/privacy.ts +118 -118
  66. package/src/session-chat-binding.ts +6 -6
  67. package/src/session-name.ts +8 -8
  68. package/src/session.ts +98 -98
  69. package/src/shared-prefix.ts +29 -29
  70. package/src/sim-platform.ts +20 -20
  71. package/src/turn-cards.ts +117 -117
  72. 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
+ }