chatccc 0.2.187 → 0.2.189
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 +5 -0
- 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-config.test.ts +33 -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 -125
- 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 +1 -0
- package/src/__tests__/config-sample.test.ts +11 -0
- package/src/__tests__/feishu-api.test.ts +60 -60
- package/src/__tests__/feishu-avatar.test.ts +180 -115
- package/src/__tests__/feishu-platform.test.ts +22 -22
- package/src/__tests__/format-message.test.ts +47 -47
- package/src/__tests__/orchestrator.test.ts +150 -2
- package/src/__tests__/privacy.test.ts +198 -198
- package/src/__tests__/raw-stream-log.test.ts +106 -106
- package/src/__tests__/session.test.ts +10 -0
- 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 -130
- package/src/adapters/claude-adapter.ts +566 -566
- package/src/adapters/claude-session-meta-store.ts +120 -120
- package/src/adapters/codex-adapter.ts +10 -6
- 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 +189 -197
- package/src/builtin/index.ts +168 -167
- package/src/cards.ts +130 -89
- package/src/chatgpt-subscription-rpc.ts +27 -27
- package/src/chatgpt-subscription.ts +299 -299
- package/src/chrome-devtools-guard.ts +318 -242
- package/src/codex-reset-actions.ts +184 -184
- package/src/config.ts +38 -0
- package/src/feishu-api.ts +219 -190
- package/src/feishu-platform.ts +20 -20
- package/src/format-message.ts +293 -293
- package/src/index.ts +2 -2
- package/src/litellm-proxy.ts +374 -374
- package/src/orchestrator.ts +201 -9
- package/src/platform-adapter.ts +9 -1
- 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 +44 -16
- 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 +142 -24
|
@@ -1,184 +1,184 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
|
|
3
|
-
import { buildCodexResetConfirmCard } from "./cards.ts";
|
|
4
|
-
import type { CodexResetConsumeResult } from "./feishu-api.ts";
|
|
5
|
-
|
|
6
|
-
type CodexResetDecision = "yes" | "no";
|
|
7
|
-
|
|
8
|
-
interface PendingCodexResetRequest {
|
|
9
|
-
chatId: string;
|
|
10
|
-
parentMessageId: string;
|
|
11
|
-
status: "pending" | "handled";
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface CodexResetActionDeps {
|
|
15
|
-
getTenantAccessToken(): Promise<string>;
|
|
16
|
-
sendRawCard(token: string, chatId: string, cardJson: string): Promise<boolean>;
|
|
17
|
-
sendTextReply(token: string, chatId: string, text: string): Promise<boolean>;
|
|
18
|
-
sendCardReply(token: string, chatId: string, title: string, content: string, template?: string): Promise<boolean>;
|
|
19
|
-
updateCardMessage(token: string, messageId: string, content: string): Promise<boolean>;
|
|
20
|
-
recallMessage(token: string, messageId: string): Promise<boolean>;
|
|
21
|
-
consumeCodexRateLimitResetCredit(redeemRequestId: string): Promise<CodexResetConsumeResult>;
|
|
22
|
-
createRequestId?: () => string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const pendingCodexResetRequests = new Map<string, PendingCodexResetRequest>();
|
|
26
|
-
|
|
27
|
-
function rawEvent(data: unknown): Record<string, unknown> {
|
|
28
|
-
return ((data as Record<string, unknown>)?.event ?? data) as Record<string, unknown>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function actionValue(raw: Record<string, unknown>): Record<string, unknown> | null {
|
|
32
|
-
const action = raw.action as { value?: unknown } | undefined;
|
|
33
|
-
const value = action?.value;
|
|
34
|
-
if (!value || typeof value !== "object") return null;
|
|
35
|
-
return value as Record<string, unknown>;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function eventMessageId(raw: Record<string, unknown>): string {
|
|
39
|
-
return typeof raw.open_message_id === "string"
|
|
40
|
-
? raw.open_message_id
|
|
41
|
-
: typeof (raw.context as Record<string, unknown> | undefined)?.open_message_id === "string"
|
|
42
|
-
? (raw.context as Record<string, string>).open_message_id
|
|
43
|
-
: typeof raw.message_id === "string"
|
|
44
|
-
? raw.message_id
|
|
45
|
-
: typeof (raw.context as Record<string, unknown> | undefined)?.message_id === "string"
|
|
46
|
-
? (raw.context as Record<string, string>).message_id
|
|
47
|
-
: typeof (raw.message as Record<string, unknown> | undefined)?.message_id === "string"
|
|
48
|
-
? (raw.message as Record<string, string>).message_id
|
|
49
|
-
: "";
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function eventChatId(raw: Record<string, unknown>): string {
|
|
53
|
-
return typeof raw.open_chat_id === "string"
|
|
54
|
-
? raw.open_chat_id
|
|
55
|
-
: typeof (raw.context as Record<string, unknown> | undefined)?.open_chat_id === "string"
|
|
56
|
-
? (raw.context as Record<string, string>).open_chat_id
|
|
57
|
-
: typeof (raw.message as Record<string, unknown> | undefined)?.chat_id === "string"
|
|
58
|
-
? (raw.message as Record<string, string>).chat_id
|
|
59
|
-
: "";
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function collapsedCard(): string {
|
|
63
|
-
return JSON.stringify({
|
|
64
|
-
config: { wide_screen_mode: true },
|
|
65
|
-
elements: [{ tag: "markdown", content: " " }],
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function resetResultMessage(result: CodexResetConsumeResult): { content: string; template: string } {
|
|
70
|
-
if (result.code === "reset") {
|
|
71
|
-
return {
|
|
72
|
-
content: `重置成功。已重置 ${result.windowsReset} 个 Codex 用量窗口。`,
|
|
73
|
-
template: "green",
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
if (result.code === "nothing_to_reset") {
|
|
77
|
-
return {
|
|
78
|
-
content: "没有需要重置的 Codex 用量窗口。",
|
|
79
|
-
template: "yellow",
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
if (result.code === "no_credit") {
|
|
83
|
-
return {
|
|
84
|
-
content: "没有可用的 Codex 主动重置次数。",
|
|
85
|
-
template: "red",
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
content: "这次 Codex 主动重置请求已经处理过。",
|
|
90
|
-
template: "yellow",
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async function sendResetRequestConfirmation(
|
|
95
|
-
raw: Record<string, unknown>,
|
|
96
|
-
value: Record<string, unknown>,
|
|
97
|
-
deps: CodexResetActionDeps,
|
|
98
|
-
): Promise<boolean> {
|
|
99
|
-
const parentMessageId = eventMessageId(raw);
|
|
100
|
-
const chatId = eventChatId(raw);
|
|
101
|
-
if (!parentMessageId || !chatId) return true;
|
|
102
|
-
const availableCount = Number(value.availableCount);
|
|
103
|
-
|
|
104
|
-
const requestId = (deps.createRequestId ?? randomUUID)();
|
|
105
|
-
pendingCodexResetRequests.set(requestId, {
|
|
106
|
-
chatId,
|
|
107
|
-
parentMessageId,
|
|
108
|
-
status: "pending",
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
const token = await deps.getTenantAccessToken();
|
|
112
|
-
await deps.sendRawCard(token, chatId, buildCodexResetConfirmCard({
|
|
113
|
-
availableCount: Number.isFinite(availableCount) ? Math.max(1, Math.trunc(availableCount)) : 1,
|
|
114
|
-
parentMessageId,
|
|
115
|
-
requestId,
|
|
116
|
-
}));
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async function handleResetConfirmation(
|
|
121
|
-
raw: Record<string, unknown>,
|
|
122
|
-
value: Record<string, unknown>,
|
|
123
|
-
deps: CodexResetActionDeps,
|
|
124
|
-
): Promise<boolean> {
|
|
125
|
-
const decision = value.decision;
|
|
126
|
-
const requestId = value.requestId;
|
|
127
|
-
const parentMessageId = value.parentMessageId;
|
|
128
|
-
if ((decision !== "yes" && decision !== "no") || typeof requestId !== "string" || typeof parentMessageId !== "string") {
|
|
129
|
-
return true;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const token = await deps.getTenantAccessToken();
|
|
133
|
-
const confirmMessageId = eventMessageId(raw);
|
|
134
|
-
if (confirmMessageId) {
|
|
135
|
-
const collapsed = await deps.updateCardMessage(token, confirmMessageId, collapsedCard());
|
|
136
|
-
console.log(`[Codex Reset] collapse confirmation card ${collapsed ? "OK" : "FAILED"}: messageId=${confirmMessageId}`);
|
|
137
|
-
const recalled = await deps.recallMessage(token, confirmMessageId);
|
|
138
|
-
console.log(`[Codex Reset] recall confirmation card ${recalled ? "OK" : "FAILED"}: messageId=${confirmMessageId}`);
|
|
139
|
-
} else {
|
|
140
|
-
console.error("[Codex Reset] missing confirmation card message id; cannot collapse");
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const pending = pendingCodexResetRequests.get(requestId);
|
|
144
|
-
const chatId = pending?.chatId ?? eventChatId(raw);
|
|
145
|
-
if (!chatId) return true;
|
|
146
|
-
|
|
147
|
-
if (!pending || pending.status !== "pending" || pending.parentMessageId !== parentMessageId) {
|
|
148
|
-
await deps.sendTextReply(token, chatId, "Codex 主动重置:这张确认卡片已经失效或已处理。");
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
pending.status = "handled";
|
|
152
|
-
|
|
153
|
-
if (decision === "no") {
|
|
154
|
-
await deps.sendTextReply(token, chatId, "Codex 主动重置:用户取消了重置。");
|
|
155
|
-
return true;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
try {
|
|
159
|
-
const result = await deps.consumeCodexRateLimitResetCredit(requestId);
|
|
160
|
-
const message = resetResultMessage(result);
|
|
161
|
-
await deps.sendTextReply(token, chatId, `Codex 主动重置:${message.content}`);
|
|
162
|
-
} catch (err) {
|
|
163
|
-
await deps.sendTextReply(token, chatId, `Codex 主动重置失败:${(err as Error).message}`);
|
|
164
|
-
}
|
|
165
|
-
return true;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export async function handleCodexResetCardAction(data: unknown, deps: CodexResetActionDeps): Promise<boolean> {
|
|
169
|
-
const raw = rawEvent(data);
|
|
170
|
-
const value = actionValue(raw);
|
|
171
|
-
if (!value) return false;
|
|
172
|
-
const action = value?.action;
|
|
173
|
-
if (action === "codex_reset_request") {
|
|
174
|
-
return sendResetRequestConfirmation(raw, value, deps);
|
|
175
|
-
}
|
|
176
|
-
if (action === "codex_reset_confirm") {
|
|
177
|
-
return handleResetConfirmation(raw, value, deps);
|
|
178
|
-
}
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export function _resetCodexResetRequestsForTest(): void {
|
|
183
|
-
pendingCodexResetRequests.clear();
|
|
184
|
-
}
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
import { buildCodexResetConfirmCard } from "./cards.ts";
|
|
4
|
+
import type { CodexResetConsumeResult } from "./feishu-api.ts";
|
|
5
|
+
|
|
6
|
+
type CodexResetDecision = "yes" | "no";
|
|
7
|
+
|
|
8
|
+
interface PendingCodexResetRequest {
|
|
9
|
+
chatId: string;
|
|
10
|
+
parentMessageId: string;
|
|
11
|
+
status: "pending" | "handled";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface CodexResetActionDeps {
|
|
15
|
+
getTenantAccessToken(): Promise<string>;
|
|
16
|
+
sendRawCard(token: string, chatId: string, cardJson: string): Promise<boolean>;
|
|
17
|
+
sendTextReply(token: string, chatId: string, text: string): Promise<boolean>;
|
|
18
|
+
sendCardReply(token: string, chatId: string, title: string, content: string, template?: string): Promise<boolean>;
|
|
19
|
+
updateCardMessage(token: string, messageId: string, content: string): Promise<boolean>;
|
|
20
|
+
recallMessage(token: string, messageId: string): Promise<boolean>;
|
|
21
|
+
consumeCodexRateLimitResetCredit(redeemRequestId: string): Promise<CodexResetConsumeResult>;
|
|
22
|
+
createRequestId?: () => string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const pendingCodexResetRequests = new Map<string, PendingCodexResetRequest>();
|
|
26
|
+
|
|
27
|
+
function rawEvent(data: unknown): Record<string, unknown> {
|
|
28
|
+
return ((data as Record<string, unknown>)?.event ?? data) as Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function actionValue(raw: Record<string, unknown>): Record<string, unknown> | null {
|
|
32
|
+
const action = raw.action as { value?: unknown } | undefined;
|
|
33
|
+
const value = action?.value;
|
|
34
|
+
if (!value || typeof value !== "object") return null;
|
|
35
|
+
return value as Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function eventMessageId(raw: Record<string, unknown>): string {
|
|
39
|
+
return typeof raw.open_message_id === "string"
|
|
40
|
+
? raw.open_message_id
|
|
41
|
+
: typeof (raw.context as Record<string, unknown> | undefined)?.open_message_id === "string"
|
|
42
|
+
? (raw.context as Record<string, string>).open_message_id
|
|
43
|
+
: typeof raw.message_id === "string"
|
|
44
|
+
? raw.message_id
|
|
45
|
+
: typeof (raw.context as Record<string, unknown> | undefined)?.message_id === "string"
|
|
46
|
+
? (raw.context as Record<string, string>).message_id
|
|
47
|
+
: typeof (raw.message as Record<string, unknown> | undefined)?.message_id === "string"
|
|
48
|
+
? (raw.message as Record<string, string>).message_id
|
|
49
|
+
: "";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function eventChatId(raw: Record<string, unknown>): string {
|
|
53
|
+
return typeof raw.open_chat_id === "string"
|
|
54
|
+
? raw.open_chat_id
|
|
55
|
+
: typeof (raw.context as Record<string, unknown> | undefined)?.open_chat_id === "string"
|
|
56
|
+
? (raw.context as Record<string, string>).open_chat_id
|
|
57
|
+
: typeof (raw.message as Record<string, unknown> | undefined)?.chat_id === "string"
|
|
58
|
+
? (raw.message as Record<string, string>).chat_id
|
|
59
|
+
: "";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function collapsedCard(): string {
|
|
63
|
+
return JSON.stringify({
|
|
64
|
+
config: { wide_screen_mode: true },
|
|
65
|
+
elements: [{ tag: "markdown", content: " " }],
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function resetResultMessage(result: CodexResetConsumeResult): { content: string; template: string } {
|
|
70
|
+
if (result.code === "reset") {
|
|
71
|
+
return {
|
|
72
|
+
content: `重置成功。已重置 ${result.windowsReset} 个 Codex 用量窗口。`,
|
|
73
|
+
template: "green",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (result.code === "nothing_to_reset") {
|
|
77
|
+
return {
|
|
78
|
+
content: "没有需要重置的 Codex 用量窗口。",
|
|
79
|
+
template: "yellow",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (result.code === "no_credit") {
|
|
83
|
+
return {
|
|
84
|
+
content: "没有可用的 Codex 主动重置次数。",
|
|
85
|
+
template: "red",
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
content: "这次 Codex 主动重置请求已经处理过。",
|
|
90
|
+
template: "yellow",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function sendResetRequestConfirmation(
|
|
95
|
+
raw: Record<string, unknown>,
|
|
96
|
+
value: Record<string, unknown>,
|
|
97
|
+
deps: CodexResetActionDeps,
|
|
98
|
+
): Promise<boolean> {
|
|
99
|
+
const parentMessageId = eventMessageId(raw);
|
|
100
|
+
const chatId = eventChatId(raw);
|
|
101
|
+
if (!parentMessageId || !chatId) return true;
|
|
102
|
+
const availableCount = Number(value.availableCount);
|
|
103
|
+
|
|
104
|
+
const requestId = (deps.createRequestId ?? randomUUID)();
|
|
105
|
+
pendingCodexResetRequests.set(requestId, {
|
|
106
|
+
chatId,
|
|
107
|
+
parentMessageId,
|
|
108
|
+
status: "pending",
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const token = await deps.getTenantAccessToken();
|
|
112
|
+
await deps.sendRawCard(token, chatId, buildCodexResetConfirmCard({
|
|
113
|
+
availableCount: Number.isFinite(availableCount) ? Math.max(1, Math.trunc(availableCount)) : 1,
|
|
114
|
+
parentMessageId,
|
|
115
|
+
requestId,
|
|
116
|
+
}));
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function handleResetConfirmation(
|
|
121
|
+
raw: Record<string, unknown>,
|
|
122
|
+
value: Record<string, unknown>,
|
|
123
|
+
deps: CodexResetActionDeps,
|
|
124
|
+
): Promise<boolean> {
|
|
125
|
+
const decision = value.decision;
|
|
126
|
+
const requestId = value.requestId;
|
|
127
|
+
const parentMessageId = value.parentMessageId;
|
|
128
|
+
if ((decision !== "yes" && decision !== "no") || typeof requestId !== "string" || typeof parentMessageId !== "string") {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const token = await deps.getTenantAccessToken();
|
|
133
|
+
const confirmMessageId = eventMessageId(raw);
|
|
134
|
+
if (confirmMessageId) {
|
|
135
|
+
const collapsed = await deps.updateCardMessage(token, confirmMessageId, collapsedCard());
|
|
136
|
+
console.log(`[Codex Reset] collapse confirmation card ${collapsed ? "OK" : "FAILED"}: messageId=${confirmMessageId}`);
|
|
137
|
+
const recalled = await deps.recallMessage(token, confirmMessageId);
|
|
138
|
+
console.log(`[Codex Reset] recall confirmation card ${recalled ? "OK" : "FAILED"}: messageId=${confirmMessageId}`);
|
|
139
|
+
} else {
|
|
140
|
+
console.error("[Codex Reset] missing confirmation card message id; cannot collapse");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const pending = pendingCodexResetRequests.get(requestId);
|
|
144
|
+
const chatId = pending?.chatId ?? eventChatId(raw);
|
|
145
|
+
if (!chatId) return true;
|
|
146
|
+
|
|
147
|
+
if (!pending || pending.status !== "pending" || pending.parentMessageId !== parentMessageId) {
|
|
148
|
+
await deps.sendTextReply(token, chatId, "Codex 主动重置:这张确认卡片已经失效或已处理。");
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
pending.status = "handled";
|
|
152
|
+
|
|
153
|
+
if (decision === "no") {
|
|
154
|
+
await deps.sendTextReply(token, chatId, "Codex 主动重置:用户取消了重置。");
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
const result = await deps.consumeCodexRateLimitResetCredit(requestId);
|
|
160
|
+
const message = resetResultMessage(result);
|
|
161
|
+
await deps.sendTextReply(token, chatId, `Codex 主动重置:${message.content}`);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
await deps.sendTextReply(token, chatId, `Codex 主动重置失败:${(err as Error).message}`);
|
|
164
|
+
}
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export async function handleCodexResetCardAction(data: unknown, deps: CodexResetActionDeps): Promise<boolean> {
|
|
169
|
+
const raw = rawEvent(data);
|
|
170
|
+
const value = actionValue(raw);
|
|
171
|
+
if (!value) return false;
|
|
172
|
+
const action = value?.action;
|
|
173
|
+
if (action === "codex_reset_request") {
|
|
174
|
+
return sendResetRequestConfirmation(raw, value, deps);
|
|
175
|
+
}
|
|
176
|
+
if (action === "codex_reset_confirm") {
|
|
177
|
+
return handleResetConfirmation(raw, value, deps);
|
|
178
|
+
}
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function _resetCodexResetRequestsForTest(): void {
|
|
183
|
+
pendingCodexResetRequests.clear();
|
|
184
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -101,6 +101,15 @@ export interface CodexConfig {
|
|
|
101
101
|
effort: string;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
export interface CccConfig {
|
|
105
|
+
/** DeepSeek API Key for the ChatCCC self-developed agent. */
|
|
106
|
+
DEEPSEEK_API_KEY: string;
|
|
107
|
+
/** DeepSeek-compatible API Base URL for the ChatCCC self-developed agent. */
|
|
108
|
+
DEEPSEEK_BASE_URL: string;
|
|
109
|
+
/** Model used by the ChatCCC self-developed agent. */
|
|
110
|
+
model: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
104
113
|
export interface FeishuConfig {
|
|
105
114
|
appId: string;
|
|
106
115
|
appSecret: string;
|
|
@@ -152,6 +161,7 @@ export interface AppConfig {
|
|
|
152
161
|
claude: ClaudeConfig;
|
|
153
162
|
cursor: CursorConfig;
|
|
154
163
|
codex: CodexConfig;
|
|
164
|
+
ccc: CccConfig;
|
|
155
165
|
}
|
|
156
166
|
|
|
157
167
|
export type AgentTool = "claude" | "cursor" | "codex";
|
|
@@ -179,8 +189,25 @@ export function getAllModelsForTool(tool: AgentTool, cfg: AppConfig = config): s
|
|
|
179
189
|
return Array.from(seen).slice(0, 100);
|
|
180
190
|
}
|
|
181
191
|
|
|
192
|
+
export const CLAUDE_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"] as const;
|
|
193
|
+
export const CODEX_EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh"] as const;
|
|
194
|
+
|
|
195
|
+
export function getAllEffortsForTool(tool: AgentTool): string[] {
|
|
196
|
+
if (tool === "claude") return [...CLAUDE_EFFORT_LEVELS];
|
|
197
|
+
if (tool === "codex") return [...CODEX_EFFORT_LEVELS];
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function getDefaultEffortForTool(tool: AgentTool, cfg: AppConfig = config): string {
|
|
202
|
+
if (tool === "claude") return cfg.claude.effort;
|
|
203
|
+
if (tool === "codex") return cfg.codex.effort;
|
|
204
|
+
return "";
|
|
205
|
+
}
|
|
206
|
+
|
|
182
207
|
const CONFIG_FILE = join(USER_DATA_DIR, "config.json");
|
|
183
208
|
const CONFIG_SAMPLE_FILE = join(PROJECT_ROOT, "config.sample.json");
|
|
209
|
+
export const DEFAULT_CCC_DEEPSEEK_BASE_URL = "https://api.deepseek.com/v1";
|
|
210
|
+
export const DEFAULT_CCC_MODEL = "deepseek-v4-pro[1m]";
|
|
184
211
|
|
|
185
212
|
/**
|
|
186
213
|
* 将旧位置(PROJECT_ROOT)的持久化数据一次性迁移到 USER_DATA_DIR。
|
|
@@ -410,6 +437,7 @@ function loadConfig(): AppConfig {
|
|
|
410
437
|
onDemandMonthlyBudget: 1000,
|
|
411
438
|
},
|
|
412
439
|
codex: { enabled: false, defaultAgent: false, path: "", model: "", alternativeModel: "", effort: "" },
|
|
440
|
+
ccc: { DEEPSEEK_API_KEY: "", DEEPSEEK_BASE_URL: DEFAULT_CCC_DEEPSEEK_BASE_URL, model: DEFAULT_CCC_MODEL },
|
|
413
441
|
};
|
|
414
442
|
|
|
415
443
|
if (!IS_TEST_ENV) {
|
|
@@ -462,6 +490,7 @@ function loadConfig(): AppConfig {
|
|
|
462
490
|
onDemandMonthlyBudget?: unknown;
|
|
463
491
|
};
|
|
464
492
|
codex?: { enabled?: unknown; defaultAgent?: unknown; path?: unknown; command?: unknown; model?: unknown; alternativeModel?: unknown; effort?: unknown };
|
|
493
|
+
ccc?: { DEEPSEEK_API_KEY?: unknown; DEEPSEEK_BASE_URL?: unknown; model?: unknown };
|
|
465
494
|
chromeDevtools?: { enabled?: unknown; port?: unknown; chromePath?: unknown };
|
|
466
495
|
rawStreamLogs?: unknown;
|
|
467
496
|
};
|
|
@@ -476,6 +505,7 @@ function loadConfig(): AppConfig {
|
|
|
476
505
|
const claude = parsed.claude ?? {} as Partial<ClaudeConfig>;
|
|
477
506
|
const cursorRaw = (parsed.cursor ?? {}) as NonNullable<typeof parsed.cursor>;
|
|
478
507
|
const codexRaw = (parsed.codex ?? {}) as NonNullable<typeof parsed.codex>;
|
|
508
|
+
const cccRaw = (parsed.ccc ?? {}) as NonNullable<typeof parsed.ccc>;
|
|
479
509
|
const chromeDevtoolsRaw = (parsed.chromeDevtools ?? {}) as NonNullable<typeof parsed.chromeDevtools>;
|
|
480
510
|
const rawStreamLogsRaw = typeof parsed.rawStreamLogs === "object" && parsed.rawStreamLogs !== null
|
|
481
511
|
? parsed.rawStreamLogs as unknown as Record<string, unknown>
|
|
@@ -607,6 +637,14 @@ function loadConfig(): AppConfig {
|
|
|
607
637
|
alternativeModel: normalizeOptionalConfigField(codexRaw.alternativeModel, { label: "codex.alternativeModel" }),
|
|
608
638
|
effort: normalizeOptionalConfigField(codexRaw.effort, { label: "codex.effort" }),
|
|
609
639
|
},
|
|
640
|
+
ccc: {
|
|
641
|
+
DEEPSEEK_API_KEY: normalizeOptionalConfigField(cccRaw.DEEPSEEK_API_KEY, { label: "ccc.DEEPSEEK_API_KEY" }),
|
|
642
|
+
DEEPSEEK_BASE_URL: normalizeOptionalConfigField(cccRaw.DEEPSEEK_BASE_URL, {
|
|
643
|
+
label: "ccc.DEEPSEEK_BASE_URL",
|
|
644
|
+
fallback: DEFAULT_CCC_DEEPSEEK_BASE_URL,
|
|
645
|
+
}),
|
|
646
|
+
model: normalizeOptionalConfigField(cccRaw.model, { label: "ccc.model", fallback: DEFAULT_CCC_MODEL }),
|
|
647
|
+
},
|
|
610
648
|
};
|
|
611
649
|
}
|
|
612
650
|
|