@cc-soul/openclaw 1.0.0

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/cc-soul/cli.js ADDED
@@ -0,0 +1,263 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { spawn } from "child_process";
4
+ import { homedir } from "os";
5
+ import { existsSync, readFileSync } from "fs";
6
+ import { DATA_DIR, loadJson } from "./persistence.ts";
7
+ import { resolve } from "path";
8
+ const OPENCLAW_CONFIG_PATH = resolve(homedir(), ".openclaw/openclaw.json");
9
+ const AI_CONFIG_PATH = resolve(DATA_DIR, "ai_config.json");
10
+ function detectAIConfig() {
11
+ const userConfig = loadJson(AI_CONFIG_PATH, {});
12
+ if (userConfig.backend) {
13
+ console.log(`[cc-soul][ai] using user override from ai_config.json`);
14
+ return {
15
+ backend: userConfig.backend,
16
+ cli_command: userConfig.cli_command || "claude",
17
+ cli_args: userConfig.cli_args || ["-p"],
18
+ api_base: userConfig.api_base || "https://api.openai.com/v1",
19
+ api_key: userConfig.api_key || "",
20
+ api_model: userConfig.api_model || "gpt-4o",
21
+ max_concurrent: userConfig.max_concurrent || 5
22
+ };
23
+ }
24
+ try {
25
+ if (existsSync(OPENCLAW_CONFIG_PATH)) {
26
+ const raw = JSON.parse(readFileSync(OPENCLAW_CONFIG_PATH, "utf-8"));
27
+ const agents = raw?.agents?.defaults || {};
28
+ const modelRef = agents?.model?.primary || "";
29
+ const cliBackends = agents?.cliBackends || {};
30
+ if (modelRef) {
31
+ const [provider] = modelRef.split("/");
32
+ const backendDef = cliBackends[provider];
33
+ if (backendDef?.command) {
34
+ const command = backendDef.command;
35
+ const args = backendDef.args || (command === "claude" ? ["-p"] : []);
36
+ console.log(`[cc-soul][ai] auto-detected from openclaw.json: CLI "${command}" (${modelRef})`);
37
+ return {
38
+ backend: "cli",
39
+ cli_command: command,
40
+ cli_args: command === "claude" ? ["-p"] : args,
41
+ api_base: "",
42
+ api_key: "",
43
+ api_model: "",
44
+ max_concurrent: 5
45
+ };
46
+ }
47
+ }
48
+ const env = raw?.env || {};
49
+ const openaiKey = env.OPENAI_API_KEY || "";
50
+ const anthropicKey = env.ANTHROPIC_API_KEY || "";
51
+ if (openaiKey) {
52
+ console.log(`[cc-soul][ai] auto-detected from openclaw.json: OpenAI API`);
53
+ return {
54
+ backend: "openai-compatible",
55
+ cli_command: "",
56
+ cli_args: [],
57
+ api_base: "https://api.openai.com/v1",
58
+ api_key: openaiKey,
59
+ api_model: "gpt-4o-mini",
60
+ // use cheap model for soul operations
61
+ max_concurrent: 8
62
+ };
63
+ }
64
+ }
65
+ } catch (e) {
66
+ console.error(`[cc-soul][ai] failed to read openclaw.json: ${e.message}`);
67
+ }
68
+ console.log(`[cc-soul][ai] using default: claude CLI`);
69
+ return {
70
+ backend: "cli",
71
+ cli_command: "claude",
72
+ cli_args: ["-p"],
73
+ api_base: "",
74
+ api_key: "",
75
+ api_model: "",
76
+ max_concurrent: 5
77
+ };
78
+ }
79
+ __name(detectAIConfig, "detectAIConfig");
80
+ let aiConfig = detectAIConfig();
81
+ function loadAIConfig() {
82
+ aiConfig = detectAIConfig();
83
+ }
84
+ __name(loadAIConfig, "loadAIConfig");
85
+ function getAIConfig() {
86
+ return aiConfig;
87
+ }
88
+ __name(getAIConfig, "getAIConfig");
89
+ let activeCLICount = 0;
90
+ function spawnCLI(prompt, callback, timeoutMs = 3e4) {
91
+ if (activeCLICount >= aiConfig.max_concurrent) {
92
+ console.log(`[cc-soul][ai] throttled (${activeCLICount}/${aiConfig.max_concurrent} active), skipping`);
93
+ callback("");
94
+ return;
95
+ }
96
+ if (aiConfig.backend === "openai-compatible") {
97
+ callOpenAICompatible(prompt, callback, timeoutMs);
98
+ } else {
99
+ callCLI(prompt, callback, timeoutMs);
100
+ }
101
+ }
102
+ __name(spawnCLI, "spawnCLI");
103
+ function callCLI(prompt, callback, timeoutMs) {
104
+ activeCLICount++;
105
+ let settled = false;
106
+ function release() {
107
+ if (!settled) {
108
+ settled = true;
109
+ activeCLICount--;
110
+ }
111
+ }
112
+ __name(release, "release");
113
+ try {
114
+ const args = [...aiConfig.cli_args, prompt, "--no-input"];
115
+ const proc = spawn(aiConfig.cli_command, args, {
116
+ cwd: homedir(),
117
+ timeout: timeoutMs,
118
+ stdio: ["pipe", "pipe", "pipe"]
119
+ });
120
+ const MAX_OUTPUT = 512 * 1024;
121
+ let output = "";
122
+ proc.stdout?.on("data", (d) => {
123
+ if (output.length < MAX_OUTPUT) {
124
+ output += d.toString();
125
+ if (output.length > MAX_OUTPUT) {
126
+ output = output.slice(0, MAX_OUTPUT);
127
+ console.log(`[cc-soul][ai] output truncated at ${MAX_OUTPUT / 1024}KB`);
128
+ }
129
+ }
130
+ });
131
+ proc.stderr?.on("data", () => {
132
+ });
133
+ const heartbeat = setInterval(() => {
134
+ console.log(`[cc-soul][ai] processing... (${Math.round(output.length / 1024)}kb received)`);
135
+ }, 6e4);
136
+ proc.on("close", (code, signal) => {
137
+ clearInterval(heartbeat);
138
+ release();
139
+ if (signal === "SIGTERM") {
140
+ console.log(`[cc-soul][ai] CLI timeout after ${timeoutMs}ms`);
141
+ callback("");
142
+ return;
143
+ }
144
+ callback(output.trim() || "");
145
+ });
146
+ proc.on("error", (err) => {
147
+ clearInterval(heartbeat);
148
+ release();
149
+ console.error(`[cc-soul][ai] CLI error: ${err.message}`);
150
+ callback("");
151
+ });
152
+ } catch (err) {
153
+ release();
154
+ console.error(`[cc-soul][ai] CLI spawn failed: ${err.message}`);
155
+ callback("");
156
+ }
157
+ }
158
+ __name(callCLI, "callCLI");
159
+ async function callOpenAICompatible(prompt, callback, timeoutMs) {
160
+ activeCLICount++;
161
+ const controller = new AbortController();
162
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
163
+ try {
164
+ const resp = await fetch(`${aiConfig.api_base}/chat/completions`, {
165
+ method: "POST",
166
+ headers: {
167
+ "Content-Type": "application/json",
168
+ "Authorization": `Bearer ${aiConfig.api_key}`
169
+ },
170
+ body: JSON.stringify({
171
+ model: aiConfig.api_model,
172
+ messages: [{ role: "user", content: prompt }],
173
+ max_tokens: 2048,
174
+ temperature: 0.7
175
+ }),
176
+ signal: controller.signal
177
+ });
178
+ clearTimeout(timer);
179
+ if (!resp.ok) {
180
+ const errText = await resp.text().catch(() => "");
181
+ console.error(`[cc-soul][ai] API error ${resp.status}: ${errText.slice(0, 200)}`);
182
+ callback("");
183
+ return;
184
+ }
185
+ const data = await resp.json();
186
+ const content = data.choices?.[0]?.message?.content || "";
187
+ callback(content.trim());
188
+ } catch (e) {
189
+ clearTimeout(timer);
190
+ if (e.name === "AbortError") {
191
+ console.log(`[cc-soul][ai] API timeout after ${timeoutMs}ms`);
192
+ } else {
193
+ console.error(`[cc-soul][ai] API error: ${e.message}`);
194
+ }
195
+ callback("");
196
+ } finally {
197
+ activeCLICount--;
198
+ }
199
+ }
200
+ __name(callOpenAICompatible, "callOpenAICompatible");
201
+ const EMPTY_RESULT = {
202
+ memories: [],
203
+ entities: [],
204
+ satisfaction: "NEUTRAL",
205
+ quality: { score: 5, issues: [] },
206
+ emotion: "neutral",
207
+ reflection: null,
208
+ curiosity: null
209
+ };
210
+ function runPostResponseAnalysis(userMsg, botResponse, callback) {
211
+ const prompt = `\u5206\u6790\u4EE5\u4E0B\u5BF9\u8BDD\uFF0C\u4E25\u683C\u6309JSON\u8F93\u51FA\uFF08\u4E0D\u8981\u5176\u4ED6\u6587\u5B57\uFF09\uFF1A
212
+
213
+ \u7528\u6237: "${userMsg.slice(0, 500)}"
214
+ \u56DE\u590D: "${botResponse.slice(0, 500)}"
215
+
216
+ \u8BF7\u540C\u65F6\u5B8C\u6210\u4EE5\u4E0B\u5206\u6790\uFF1A
217
+ 1. memories: \u63D0\u53D6\u503C\u5F97\u957F\u671F\u8BB0\u4F4F\u7684\u4FE1\u606F\u3002\u6BCF\u6761: {"content":"\u5185\u5BB9","scope":"\u7C7B\u578B","visibility":"\u53EF\u89C1\u6027"}\uFF0Cscope\u53EA\u80FD\u662F: preference/fact/event/opinion\u3002visibility\u53EA\u80FD\u662F: global(\u901A\u7528\u77E5\u8BC6/\u6280\u672F\u4E8B\u5B9E\uFF0C\u5BF9\u6240\u6709\u4EBA\u6709\u7528)/channel(\u9891\u9053\u76F8\u5173\uFF0C\u53EA\u5728\u5F53\u524D\u7FA4\u6709\u7528)/private(\u4E2A\u4EBA\u76F8\u5173\uFF0C\u53EA\u5BF9\u5F53\u524D\u7528\u6237\u6709\u7528)\u3002\u6CA1\u6709\u5C31\u7A7A\u6570\u7EC4\u3002
218
+ 2. entities: \u63D0\u53D6\u4EBA\u540D\u3001\u9879\u76EE\u540D\u3001\u516C\u53F8\u540D\u3001\u6280\u672F\u540D\u3002\u6BCF\u6761: {"name":"\u540D","type":"\u7C7B\u578B","relation":"\u5173\u7CFB"}\uFF0Ctype\u53EA\u80FD\u662F: person/project/company/tech/place\u3002\u6CA1\u6709\u5C31\u7A7A\u6570\u7EC4\u3002
219
+ 3. satisfaction: \u5224\u65AD\u7528\u6237\u5BF9\u56DE\u590D\u7684\u6EE1\u610F\u5EA6: POSITIVE/NEUTRAL/NEGATIVE/TOO_VERBOSE
220
+ 4. quality: \u56DE\u590D\u8D28\u91CF\u8BC4\u52061-10 + \u95EE\u9898\u5217\u8868\u3002{"score":N,"issues":["\u95EE\u9898"]}
221
+ 5. emotion: \u5BF9\u8BDD\u60C5\u611F\u6807\u7B7E: neutral/warm/important/painful/funny
222
+ 6. reflection: \u56DE\u590D\u6709\u4EC0\u4E48\u9057\u61BE\u6216\u53EF\u6539\u8FDB\u7684\uFF1F1\u53E5\u8BDD\uFF0C\u6CA1\u6709\u5C31null
223
+ 7. curiosity: \u4F5C\u4E3A\u670B\u53CB\u60F3\u8FFD\u95EE\u4EC0\u4E48\uFF1F1\u53E5\u8BDD\uFF0C\u6CA1\u6709\u5C31null
224
+
225
+ JSON\u683C\u5F0F(\u4E25\u683C):
226
+ {"memories":[],"entities":[],"satisfaction":"NEUTRAL","quality":{"score":5,"issues":[]},"emotion":"neutral","reflection":null,"curiosity":null}`;
227
+ spawnCLI(
228
+ prompt,
229
+ (output) => {
230
+ try {
231
+ const match = output.match(/\{[\s\S]*\}/);
232
+ if (match) {
233
+ const result = JSON.parse(match[0]);
234
+ callback({
235
+ memories: (result.memories || []).map((m) => ({
236
+ content: m.content,
237
+ scope: m.scope,
238
+ visibility: m.visibility || void 0
239
+ })),
240
+ entities: result.entities || [],
241
+ satisfaction: result.satisfaction || "NEUTRAL",
242
+ quality: result.quality || { score: 5, issues: [] },
243
+ emotion: result.emotion || "neutral",
244
+ reflection: result.reflection || null,
245
+ curiosity: result.curiosity || null
246
+ });
247
+ return;
248
+ }
249
+ } catch (e) {
250
+ console.error(`[cc-soul][ai] analysis parse error: ${e.message}`);
251
+ }
252
+ callback({ ...EMPTY_RESULT });
253
+ },
254
+ 45e3
255
+ );
256
+ }
257
+ __name(runPostResponseAnalysis, "runPostResponseAnalysis");
258
+ export {
259
+ getAIConfig,
260
+ loadAIConfig,
261
+ runPostResponseAnalysis,
262
+ spawnCLI
263
+ };
@@ -0,0 +1,143 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { body, bodyOnCorrection, bodyOnPositiveFeedback } from "./body.ts";
4
+ import { getProfile, getProfileTier } from "./user-profiles.ts";
5
+ function attentionGate(msg) {
6
+ const m = msg.toLowerCase();
7
+ const correctionWords = ["\u4E0D\u5BF9", "\u9519\u4E86", "\u641E\u9519", "\u7406\u89E3\u9519", "\u4E0D\u662F\u8FD9\u6837", "\u8BF4\u53CD\u4E86", "\u522B\u778E\u8BF4", "wrong", "\u91CD\u6765"];
8
+ const notCorrection = ["\u6CA1\u9519", "\u4E0D\u9519", "\u5BF9\u4E0D\u5BF9", "\u9519\u4E86\u5417", "\u662F\u4E0D\u662F\u9519", "\u4E0D\u5BF9\u79F0", "\u4E0D\u5BF9\u52B2", "\u9519\u4E86\u9519\u4E86\u6211\u7684", "\u4F60\u8BF4\u5F97\u5BF9", "\u6CA1\u6709\u9519"];
9
+ if (correctionWords.some((w) => m.includes(w))) {
10
+ if (!notCorrection.some((w) => m.includes(w))) {
11
+ return { type: "correction", priority: 10 };
12
+ }
13
+ }
14
+ if (["\u70E6", "\u7D2F", "\u96BE\u8FC7", "\u5D29\u6E83", "\u538B\u529B\u5927", "\u7126\u8651", "\u5F00\u5FC3", "\u54C8\u54C8", "\u725B\u903C", "\u592A\u68D2", "\u611F\u8C22", "\u8C22\u8C22"].some((w) => m.includes(w))) {
15
+ return { type: "emotional", priority: 7 };
16
+ }
17
+ if (["\u4EE3\u7801", "\u51FD\u6570", "\u62A5\u9519", "error", "bug", "crash", "\u7F16\u8BD1", "\u8C03\u8BD5", "debug", "\u5B9E\u73B0", "\u600E\u4E48\u5199", "hook", "frida", "ida"].some((w) => m.includes(w))) {
18
+ return { type: "technical", priority: 8 };
19
+ }
20
+ if (msg.length < 15 || ["\u55EF", "\u597D", "\u54E6", "\u884C", "\u53EF\u4EE5", "ok", "\u660E\u767D"].some((w) => m === w || m === w + "\u7684")) {
21
+ return { type: "casual", priority: 3 };
22
+ }
23
+ return { type: "general", priority: 5 };
24
+ }
25
+ __name(attentionGate, "attentionGate");
26
+ function detectIntent(msg) {
27
+ const m = msg.toLowerCase();
28
+ if (["\u4F60\u89C9\u5F97", "\u4F60\u770B", "\u4F60\u8BA4\u4E3A", "\u4F60\u600E\u4E48\u770B", "\u4F60\u7684\u770B\u6CD5", "\u5EFA\u8BAE"].some((w) => m.includes(w))) return "wants_opinion";
29
+ if (["\u987A\u4FBF", "\u53E6\u5916", "\u8FD8\u6709", "\u5BF9\u4E86"].some((w) => m.includes(w))) return "wants_proactive";
30
+ if (m.endsWith("?") || m.endsWith("\uFF1F") || ["\u5417", "\u5462", "\u4E48"].some((w) => m.endsWith(w))) return "wants_answer";
31
+ if (msg.length < 20) return "wants_quick";
32
+ if (["\u505A", "\u5199", "\u6539", "\u5E2E\u6211", "\u5B9E\u73B0", "\u751F\u6210"].some((w) => m.includes(w))) return "wants_action";
33
+ return "unclear";
34
+ }
35
+ __name(detectIntent, "detectIntent");
36
+ function decideStrategy(attention, intent, msgLen) {
37
+ if (attention.type === "correction") return "acknowledge_and_retry";
38
+ if (attention.type === "emotional") return "empathy_first";
39
+ if (intent === "wants_quick" || msgLen < 10) return "direct";
40
+ if (intent === "wants_opinion") return "opinion_with_reasoning";
41
+ if (intent === "wants_action") return "action_oriented";
42
+ if (msgLen > 200) return "detailed";
43
+ return "balanced";
44
+ }
45
+ __name(decideStrategy, "decideStrategy");
46
+ function detectImplicitFeedbackSync(msg, prevResponse) {
47
+ if (!prevResponse) return null;
48
+ const m = msg.toLowerCase();
49
+ if (prevResponse.length > 500 && msg.length < 10 && ["\u55EF", "\u597D", "\u884C", "\u54E6", "ok"].some((w) => m.includes(w))) {
50
+ return "too_verbose";
51
+ }
52
+ if (["\u55EF", "\u597D\u7684", "\u660E\u767D", "\u4E86\u89E3", "ok", "\u6536\u5230", "\u53EF\u4EE5", "\u597D"].some((w) => m === w)) {
53
+ return "silent_accept";
54
+ }
55
+ if (["\u592A\u597D\u4E86", "\u725B", "\u5389\u5BB3", "\u5B8C\u7F8E", "\u6B63\u662F", "\u5BF9\u5BF9\u5BF9", "\u5C31\u662F\u8FD9\u4E2A", "\u611F\u8C22"].some((w) => m.includes(w))) {
56
+ return "positive";
57
+ }
58
+ return null;
59
+ }
60
+ __name(detectImplicitFeedbackSync, "detectImplicitFeedbackSync");
61
+ function predictIntent(msg, _senderId, lastMsgs) {
62
+ const hints = [];
63
+ const m = msg.toLowerCase();
64
+ if (lastMsgs.length >= 2 && lastMsgs.slice(-2).every((x) => x.length < 50) && msg.length < 50) {
65
+ hints.push("\u7528\u6237\u5728\u8FDE\u7EED\u53D1\u77ED\u6D88\u606F\u63CF\u8FF0\u95EE\u9898\uFF0C\u7B49\u4ED6\u8BF4\u5B8C\u518D\u56DE\u590D\uFF0C\u4E0D\u8981\u9010\u6761\u56DE");
66
+ }
67
+ if (m === "?" || m === "\uFF1F" || m === "..." || m === "???") {
68
+ hints.push("\u7528\u6237\u5728\u50AC\u56DE\u590D\uFF0C\u7B80\u77ED\u56DE\u5E94\u5373\u53EF");
69
+ }
70
+ if (msg.includes("[\u56FE\u7247]") || msg.includes("[Image]") || msg.includes("\u622A\u56FE")) {
71
+ hints.push("\u7528\u6237\u53D1\u4E86\u56FE\u7247/\u622A\u56FE\uFF0C\u5173\u6CE8\u5185\u5BB9\u672C\u8EAB\uFF0C\u4E0D\u8981\u8BC4\u4EF7\u56FE\u7247\u8D28\u91CF");
72
+ }
73
+ if (msg.includes("[\u8F6C\u53D1]") || msg.includes("\u8F6C\u53D1") || msg.startsWith(">>")) {
74
+ hints.push("\u8FD9\u662F\u8F6C\u53D1\u7684\u5185\u5BB9\uFF0C\u7528\u6237\u60F3\u8981\u4F60\u7684\u5206\u6790/\u770B\u6CD5");
75
+ }
76
+ if (msg.includes("```") || msg.includes("error") || msg.includes("Error") || msg.includes("traceback")) {
77
+ hints.push("\u7528\u6237\u8D34\u4E86\u4EE3\u7801/\u9519\u8BEF\u4FE1\u606F\uFF0C\u76F4\u63A5\u5B9A\u4F4D\u95EE\u9898\u7ED9\u89E3\u51B3\u65B9\u6848");
78
+ }
79
+ if (msg.length > 200 && (msg.match(/\d+/g) || []).length > 5) {
80
+ hints.push("\u6D88\u606F\u5305\u542B\u5927\u91CF\u6570\u636E/\u6570\u5B57\uFF0C\u505A\u5206\u6790\u800C\u4E0D\u662F\u6458\u8981");
81
+ }
82
+ return hints;
83
+ }
84
+ __name(predictIntent, "predictIntent");
85
+ function cogProcess(msg, lastResponseContent, lastPrompt, senderId) {
86
+ const attention = attentionGate(msg);
87
+ const intent = detectIntent(msg);
88
+ const complexity = Math.min(1, msg.length / 500);
89
+ const strategy = decideStrategy(attention, intent, msg.length);
90
+ const hints = [];
91
+ if (attention.type === "correction") {
92
+ const profile = senderId ? getProfile(senderId) : null;
93
+ const tier = profile?.tier || "new";
94
+ if (tier === "owner") {
95
+ hints.push("\u26A0 \u4E3B\u4EBA\u5728\u7EA0\u6B63\u4F60\uFF0C\u8FD9\u662F\u9AD8\u6743\u91CD\u53CD\u9988\uFF0C\u5FC5\u987B\u8BA4\u771F\u5BF9\u5F85\u5E76\u8C03\u6574");
96
+ bodyOnCorrection();
97
+ } else if (tier === "known") {
98
+ hints.push("\u26A0 \u8001\u670B\u53CB\u5728\u7EA0\u6B63\u4F60\uFF0C\u6CE8\u610F\u8C03\u6574");
99
+ body.alertness = Math.min(1, body.alertness + 0.1);
100
+ body.mood = Math.max(-1, body.mood - 0.05);
101
+ } else {
102
+ hints.push("\u65B0\u7528\u6237\u53CD\u9988\uFF0C\u53EF\u80FD\u662F\u671F\u671B\u7BA1\u7406\u95EE\u9898\uFF0C\u6E29\u548C\u5BF9\u5F85");
103
+ body.alertness = Math.min(1, body.alertness + 0.05);
104
+ }
105
+ }
106
+ if (attention.type === "emotional") {
107
+ const neg = ["\u70E6", "\u7D2F", "\u96BE\u8FC7", "\u5D29\u6E83", "\u538B\u529B", "\u7126\u8651"].some((w) => msg.includes(w));
108
+ if (neg) {
109
+ hints.push("\u7528\u6237\u60C5\u7EEA\u4E0D\u597D\uFF0C\u5148\u5171\u60C5\u518D\u56DE\u7B54\uFF0C\u4E0D\u8981\u6025\u7740\u7ED9\u5EFA\u8BAE");
110
+ body.mood = Math.max(-1, body.mood - 0.15);
111
+ } else {
112
+ hints.push("\u7528\u6237\u60C5\u7EEA\u79EF\u6781\uFF0C\u53EF\u4EE5\u8F7B\u677E\u4E92\u52A8");
113
+ body.mood = Math.min(1, body.mood + 0.1);
114
+ }
115
+ }
116
+ if (strategy === "direct") hints.push("\u7B80\u77ED\u56DE\u7B54\u5373\u53EF");
117
+ if (strategy === "opinion_with_reasoning") hints.push('\u7ED9\u51FA\u660E\u786E\u7ACB\u573A\u548C\u7406\u7531\uFF0C\u4E0D\u8BF4"\u5404\u6709\u4F18\u52A3"');
118
+ if (strategy === "action_oriented") hints.push("\u5148\u7ED9\u4EE3\u7801/\u65B9\u6848\uFF0C\u518D\u89E3\u91CA");
119
+ if (strategy === "empathy_first") hints.push("\u5148\u5171\u60C5\uFF0C\u518D\u63D0\u4F9B\u5E2E\u52A9");
120
+ if (strategy === "acknowledge_and_retry") hints.push("\u5148\u627F\u8BA4\u9519\u8BEF\uFF0C\u518D\u7ED9\u51FA\u6B63\u786E\u7B54\u6848");
121
+ const implicit = detectImplicitFeedbackSync(msg, lastResponseContent);
122
+ if (implicit === "too_verbose") {
123
+ body.energy = Math.max(0, body.energy - 0.03);
124
+ hints.push("\u4E0A\u6B21\u56DE\u7B54\u53EF\u80FD\u592A\u957F\u4E86\uFF0C\u8FD9\u6B21\u7B80\u6D01\u4E9B");
125
+ } else if (implicit === "silent_accept") {
126
+ } else if (implicit === "positive") {
127
+ bodyOnPositiveFeedback();
128
+ }
129
+ if (senderId) {
130
+ const tier = getProfileTier(senderId);
131
+ if (tier === "owner") {
132
+ hints.push("\u4E3B\u4EBA\u5728\u8BF4\u8BDD\uFF0C\u6280\u672F\u6DF1\u5EA6\u4F18\u5148\uFF0C\u5C11\u5E9F\u8BDD");
133
+ } else if (tier === "new") {
134
+ hints.push("\u65B0\u7528\u6237\uFF0C\u8010\u5FC3\u89C2\u5BDF\uFF0C\u5148\u4E86\u89E3\u5BF9\u65B9\u518D\u9002\u914D\u98CE\u683C");
135
+ }
136
+ }
137
+ return { hints, intent, strategy, attention: attention.type, complexity };
138
+ }
139
+ __name(cogProcess, "cogProcess");
140
+ export {
141
+ cogProcess,
142
+ predictIntent
143
+ };
@@ -0,0 +1 @@
1
+ import{existsSync,readFileSync}from"fs";const MAX_FILES=2,INLINE_LIMIT=2e3,HEAD_LINES=50;function prepareContext(e){const r=[],t=(e.match(/(?:~\/|\/[\w.-]+)[\w./-]*\.[\w]+/g)||[]).map(e=>e.startsWith("~/")?e.replace("~",process.env.HOME||""):e).slice(0,2);for(const e of t)try{if(!existsSync(e))continue;const t=readFileSync(e,"utf-8");if(t.length<=2e3)r.push({content:`[文件内容: ${e}]\n${t}`,source:e});else{const n=t.split("\n"),o=n.slice(0,50).join("\n");r.push({content:`[文件内容: ${e}] (${n.length}行, 前50行)\n${o}`,source:e})}}catch{}const n=e.match(/(?:Error|错误|error|FAIL|panic|Exception|TypeError|ReferenceError|SyntaxError)[::]\s*(.{10,120})/i);return n&&r.push({content:`[错误信息提取] ${n[1].trim()}`,source:"error-detect"}),/0x[0-9a-f]{6,}/i.test(e)&&r.push({content:"[检测到内存地址] 用户可能在做逆向/调试,注意地址格式和偏移量",source:"hex-detect"}),r}export{prepareContext};
@@ -0,0 +1 @@
1
+ import{resolve}from"path";import{DATA_DIR,loadJson,debouncedSave}from"./persistence.ts";const EPISTEMIC_PATH=resolve(DATA_DIR,"epistemic.json"),domains=new Map;function detectDomain(o){const n=o.toLowerCase();return["frida","hook","ida","mach-o","dyld","arm64","objc","逆向","砸壳","tweak","substrate","theos"].some(o=>n.includes(o))?"ios-reverse":["swift","xcode","swiftui","uikit","cocoa","appkit"].some(o=>n.includes(o))?"swift":["python","pip","flask","django","def ","import ",".py","asyncio","pandas"].some(o=>n.includes(o))?"python":["typescript","javascript","node","react","vue",".ts",".js","npm","pnpm","bun"].some(o=>n.includes(o))?"javascript":["docker","k8s","kubernetes","nginx","linux","bash","shell","systemd","ssh"].some(o=>n.includes(o))?"devops":["sql","mysql","postgres","mongodb","数据库","redis","sqlite"].some(o=>n.includes(o))?"database":["图片","ocr","识别","照片","截图","看看这个","这张图"].some(o=>n.includes(o))?"图片识别":["git","github","pr","merge","branch","commit","rebase"].some(o=>n.includes(o))?"git":["rust","cargo",".rs","lifetime","borrow checker"].some(o=>n.includes(o))?"rust":["go ","golang","goroutine",".go","func "].some(o=>n.includes(o))?"golang":o.length<20?"闲聊":["怎么看","你觉得","建议","应该","推荐"].some(o=>n.includes(o))?"咨询":"通用"}function loadEpistemic(){const o=loadJson(EPISTEMIC_PATH,{});domains.clear();for(const[n,e]of Object.entries(o))domains.set(n,e);console.log(`[cc-soul][epistemic] loaded ${domains.size} domains`)}function saveEpistemic(){const o={};for(const[n,e]of domains)o[n]=e;debouncedSave(EPISTEMIC_PATH,o)}function ensureDomain(o){let n=domains.get(o);return n||(n={domain:o,o:0,t:0,i:0,m:5,u:0},domains.set(o,n)),n}function recompute(o){o.m=o.o>0?Math.round(o.t/o.o*10)/10:5,o.u=o.o>0?Math.round(o.i/o.o*1e3)/10:0}function trackDomainQuality(o,n){const e=ensureDomain(detectDomain(o));e.o++,e.t+=n,recompute(e),saveEpistemic()}function trackDomainCorrection(o){const n=ensureDomain(detectDomain(o));n.i++,recompute(n),saveEpistemic()}function getDomainConfidence(o){const n=detectDomain(o),e=domains.get(n);return!e||e.o<3?{domain:n,p:"medium",hint:""}:e.u>10&&e.o>=5?{domain:n,p:"low",hint:`[知识边界] "${n}" 领域纠正率 ${e.u}%,这个领域我不太确定,你验证一下`}:e.m<5&&e.o>=5?{domain:n,p:"low",hint:`[知识边界] "${n}" 领域平均质量 ${e.m}/10,我在这方面表现不佳,请仔细核实`}:e.m>7&&e.o>=10?{domain:n,p:"high",hint:""}:{domain:n,p:"medium",hint:""}}function getWeakDomains(){return[...domains.values()].filter(o=>o.o>=5&&(o.u>10||o.m<5)).sort((o,n)=>n.u-o.u).map(o=>o.domain)}function getEpistemicSummary(){if(0===domains.size)return"";const o=[...domains.values()].filter(o=>o.o>=3).sort((o,n)=>n.o-o.o);if(0===o.length)return"";const n=[],e=o.filter(o=>o.u>10&&o.o>=5||o.m<5&&o.o>=5);if(e.length>0){n.push("⚠ 薄弱领域(回答前要格外谨慎):");for(const o of e)n.push(`- ${o.domain}: 质量${o.m}/10, 纠正率${o.u}%, 样本${o.o}`)}const t=o.filter(o=>o.m>7&&o.o>=10);if(t.length>0){n.push("✓ 擅长领域:");for(const o of t)n.push(`- ${o.domain}: 质量${o.m}/10, 样本${o.o}`)}return n.join("\n")}export{detectDomain,getDomainConfidence,getEpistemicSummary,getWeakDomains,loadEpistemic,trackDomainCorrection,trackDomainQuality};
@@ -0,0 +1,176 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { createHash } from "crypto";
4
+ import { RULES_PATH, HYPOTHESES_PATH, loadJson, debouncedSave } from "./persistence.ts";
5
+ import { addMemory } from "./memory.ts";
6
+ import { notifySoulActivity } from "./notify.ts";
7
+ import { spawnCLI } from "./cli.ts";
8
+ const MAX_RULES = 50;
9
+ let rules = [];
10
+ let hypotheses = [];
11
+ function md5(s) {
12
+ return createHash("md5").update(s).digest("hex").slice(0, 16);
13
+ }
14
+ __name(md5, "md5");
15
+ function loadRules() {
16
+ rules = loadJson(RULES_PATH, []);
17
+ }
18
+ __name(loadRules, "loadRules");
19
+ function saveRules() {
20
+ debouncedSave(RULES_PATH, rules);
21
+ }
22
+ __name(saveRules, "saveRules");
23
+ function addRule(rule, source) {
24
+ if (!rule || rule.length < 5) return;
25
+ if (rules.some((r) => r.rule === rule)) return;
26
+ rules.push({ rule, source: source.slice(0, 100), ts: Date.now(), hits: 0 });
27
+ if (rules.length > MAX_RULES) {
28
+ rules.sort((a, b) => b.hits * 10 + b.ts / 1e10 - (a.hits * 10 + a.ts / 1e10));
29
+ rules = rules.slice(0, MAX_RULES);
30
+ }
31
+ saveRules();
32
+ }
33
+ __name(addRule, "addRule");
34
+ function getRelevantRules(msg, topN = 3) {
35
+ if (rules.length === 0) return [];
36
+ const msgWords = new Set((msg.match(/[\u4e00-\u9fff]{2,}|[a-z]{3,}/gi) || []).map((w) => w.toLowerCase()));
37
+ if (msgWords.size === 0) return rules.slice(0, topN);
38
+ const scored = rules.map((r) => {
39
+ const ruleWords = (r.rule.match(/[\u4e00-\u9fff]{2,}|[a-z]{3,}/gi) || []).map((w) => w.toLowerCase());
40
+ const overlap = ruleWords.filter((w) => msgWords.has(w)).length;
41
+ return { ...r, score: overlap + r.hits * 0.1 };
42
+ });
43
+ scored.sort((a, b) => b.score - a.score);
44
+ const relevant = scored.filter((r) => r.score > 0).slice(0, topN);
45
+ for (const r of relevant) {
46
+ const orig = rules.find((o) => o.rule === r.rule);
47
+ if (orig) orig.hits++;
48
+ }
49
+ return relevant;
50
+ }
51
+ __name(getRelevantRules, "getRelevantRules");
52
+ function loadHypotheses() {
53
+ hypotheses = loadJson(HYPOTHESES_PATH, []);
54
+ }
55
+ __name(loadHypotheses, "loadHypotheses");
56
+ function formHypothesis(pattern, observation) {
57
+ const id = md5(pattern);
58
+ if (hypotheses.some((h) => h.id === id)) return;
59
+ hypotheses.push({
60
+ id,
61
+ description: `\u5F53\u9047\u5230"${pattern.slice(0, 30)}"\u65F6: ${observation.slice(0, 60)}`,
62
+ evidence_for: 1,
63
+ evidence_against: 0,
64
+ status: "active",
65
+ created: Date.now()
66
+ });
67
+ if (hypotheses.length > 30) {
68
+ hypotheses = hypotheses.filter((h) => h.status !== "rejected").sort((a, b) => b.evidence_for - b.evidence_against - (a.evidence_for - a.evidence_against)).slice(0, 25);
69
+ }
70
+ debouncedSave(HYPOTHESES_PATH, hypotheses);
71
+ console.log(`[cc-soul][evolve] \u65B0\u5047\u8BBE: ${pattern.slice(0, 30)} \u2192 ${observation.slice(0, 40)}`);
72
+ notifySoulActivity(`\u{1F9EC} \u65B0\u5047\u8BBE: ${pattern.slice(0, 30)} \u2192 ${observation.slice(0, 40)}`).catch(() => {
73
+ });
74
+ }
75
+ __name(formHypothesis, "formHypothesis");
76
+ function verifyHypothesis(situation, wasCorrect) {
77
+ for (const h of hypotheses) {
78
+ if (h.status === "rejected") continue;
79
+ const keywords = h.description.match(/[\u4e00-\u9fff]{2,}|[a-z]{3,}/gi) || [];
80
+ const matches = keywords.filter((w) => situation.toLowerCase().includes(w.toLowerCase())).length;
81
+ if (matches < 2) continue;
82
+ if (wasCorrect) {
83
+ h.evidence_for++;
84
+ if (h.evidence_for >= 5 && h.status === "active") {
85
+ h.status = "verified";
86
+ addRule(h.description, "hypothesis_verified");
87
+ console.log(`[cc-soul][evolve] \u5047\u8BBE\u9A8C\u8BC1\u901A\u8FC7 \u2192 \u89C4\u5219: ${h.description.slice(0, 40)}`);
88
+ notifySoulActivity(`\u2705 \u5047\u8BBE\u9A8C\u8BC1: ${h.description.slice(0, 40)}`).catch(() => {
89
+ });
90
+ }
91
+ } else {
92
+ h.evidence_against++;
93
+ if (h.evidence_against >= 3) {
94
+ h.status = "rejected";
95
+ console.log(`[cc-soul][evolve] \u5047\u8BBE\u88AB\u5426\u5B9A: ${h.description.slice(0, 40)}`);
96
+ notifySoulActivity(`\u274C \u5047\u8BBE\u5426\u5B9A: ${h.description.slice(0, 40)}`).catch(() => {
97
+ });
98
+ }
99
+ }
100
+ }
101
+ debouncedSave(HYPOTHESES_PATH, hypotheses);
102
+ }
103
+ __name(verifyHypothesis, "verifyHypothesis");
104
+ function onCorrectionEvolution(userMsg) {
105
+ const patterns = [
106
+ /不要(.{2,30})/,
107
+ /别(.{2,20})/,
108
+ /应该(.{2,30})/,
109
+ /正确的是(.{2,30})/
110
+ ];
111
+ for (const p of patterns) {
112
+ const m = userMsg.match(p);
113
+ if (m) {
114
+ addRule(m[0], userMsg.slice(0, 80));
115
+ break;
116
+ }
117
+ }
118
+ addMemory(`\u7EA0\u6B63: ${userMsg.slice(0, 60)}`, "correction");
119
+ }
120
+ __name(onCorrectionEvolution, "onCorrectionEvolution");
121
+ function onCorrectionAdvanced(userMsg, lastResponse) {
122
+ onCorrectionEvolution(userMsg);
123
+ const causalPatterns = [
124
+ { pattern: /太长|太啰嗦|简洁/, cause: "\u56DE\u7B54\u592A\u5197\u957F\uFF0C\u7528\u6237\u8981\u7B80\u6D01" },
125
+ { pattern: /跑偏|离题|不是问/, cause: "\u7406\u89E3\u504F\u4E86\uFF0C\u6CA1\u56DE\u7B54\u5230\u70B9\u4E0A" },
126
+ { pattern: /不准|不对|错误/, cause: "\u4FE1\u606F\u4E0D\u51C6\u786E" },
127
+ { pattern: /口气|语气|态度/, cause: "\u8BED\u6C14\u4E0D\u5BF9" },
128
+ { pattern: /太简单|没深度|浅/, cause: "\u56DE\u7B54\u592A\u6D45" }
129
+ ];
130
+ for (const { pattern, cause } of causalPatterns) {
131
+ if (pattern.test(userMsg)) {
132
+ formHypothesis(userMsg.slice(0, 50), cause);
133
+ break;
134
+ }
135
+ }
136
+ verifyHypothesis(lastResponse, false);
137
+ }
138
+ __name(onCorrectionAdvanced, "onCorrectionAdvanced");
139
+ function attributeCorrection(userMsg, lastResponse, augmentsUsed) {
140
+ spawnCLI(
141
+ `\u4E0A\u4E00\u6B21\u56DE\u590D: "${lastResponse.slice(0, 300)}"
142
+ \u6CE8\u5165\u7684\u4E0A\u4E0B\u6587: ${augmentsUsed.slice(0, 3).join("; ").slice(0, 200)}
143
+ \u7528\u6237\u7EA0\u6B63: "${userMsg.slice(0, 200)}"
144
+
145
+ \u5224\u65AD\u56DE\u590D\u51FA\u9519\u7684\u539F\u56E0\uFF08\u53EA\u9009\u4E00\u4E2A\uFF09:
146
+ 1=\u6A21\u578B\u5E7B\u89C9 2=\u8BB0\u5FC6\u8BEF\u5BFC 3=\u89C4\u5219\u51B2\u7A81 4=\u7406\u89E3\u504F\u5DEE 5=\u9886\u57DF\u4E0D\u8DB3
147
+ \u683C\u5F0F: {"cause":N,"detail":"\u4E00\u53E5\u8BDD"}`,
148
+ (output) => {
149
+ try {
150
+ const m = output.match(/\{[\s\S]*?\}/);
151
+ if (m) {
152
+ const result = JSON.parse(m[0]);
153
+ const causeNames = ["", "\u6A21\u578B\u5E7B\u89C9", "\u8BB0\u5FC6\u8BEF\u5BFC", "\u89C4\u5219\u51B2\u7A81", "\u7406\u89E3\u504F\u5DEE", "\u9886\u57DF\u4E0D\u8DB3"];
154
+ const causeName = causeNames[result.cause] || "\u672A\u77E5";
155
+ console.log(`[cc-soul][attribution] cause=${causeName}: ${result.detail}`);
156
+ addMemory(`[\u7EA0\u6B63\u5F52\u56E0] ${causeName}: ${result.detail}`, "correction");
157
+ }
158
+ } catch (e) {
159
+ console.error(`[cc-soul][attribution] parse error: ${e.message}`);
160
+ }
161
+ }
162
+ );
163
+ }
164
+ __name(attributeCorrection, "attributeCorrection");
165
+ export {
166
+ addRule,
167
+ attributeCorrection,
168
+ formHypothesis,
169
+ getRelevantRules,
170
+ hypotheses,
171
+ loadHypotheses,
172
+ loadRules,
173
+ onCorrectionAdvanced,
174
+ rules,
175
+ verifyHypothesis
176
+ };
@@ -0,0 +1,79 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { FEATURES_PATH, loadJson, saveJson } from "./persistence.ts";
4
+ const DEFAULTS = {
5
+ memory_active: true,
6
+ memory_consolidation: true,
7
+ memory_contradiction_scan: true,
8
+ memory_tags: true,
9
+ memory_associative_recall: true,
10
+ memory_predictive: true,
11
+ memory_session_summary: true,
12
+ lorebook: true,
13
+ skill_library: true,
14
+ persona_splitting: true,
15
+ emotional_contagion: true,
16
+ fingerprint: true,
17
+ metacognition: true,
18
+ dream_mode: true,
19
+ autonomous_voice: true,
20
+ web_rover: true,
21
+ structured_reflection: true,
22
+ plan_tracking: true,
23
+ self_upgrade: false,
24
+ // 默认关闭 — 用户需要显式开启才能让 cc 改自己的代码
25
+ federation: true,
26
+ sync: true
27
+ };
28
+ let features = { ...DEFAULTS };
29
+ function loadFeatures() {
30
+ const loaded = loadJson(FEATURES_PATH, {});
31
+ features = { ...DEFAULTS, ...loaded };
32
+ saveJson(FEATURES_PATH, features);
33
+ const on = Object.values(features).filter((v) => v).length;
34
+ const total = Object.keys(features).length;
35
+ console.log(`[cc-soul][features] ${on}/${total} features enabled`);
36
+ }
37
+ __name(loadFeatures, "loadFeatures");
38
+ function isEnabled(feature) {
39
+ return features[feature] ?? true;
40
+ }
41
+ __name(isEnabled, "isEnabled");
42
+ function setFeature(feature, enabled) {
43
+ features[feature] = enabled;
44
+ saveJson(FEATURES_PATH, features);
45
+ console.log(`[cc-soul][features] ${feature} \u2192 ${enabled ? "ON" : "OFF"}`);
46
+ }
47
+ __name(setFeature, "setFeature");
48
+ function getAllFeatures() {
49
+ return { ...features };
50
+ }
51
+ __name(getAllFeatures, "getAllFeatures");
52
+ function handleFeatureCommand(msg) {
53
+ const m = msg.trim();
54
+ if (m === "\u529F\u80FD\u72B6\u6001" || m === "features" || m === "feature status") {
55
+ const lines = Object.entries(features).map(([k, v]) => ` ${v ? "\u2705" : "\u274C"} ${k}`).join("\n");
56
+ console.log(`[cc-soul][features] status:
57
+ ${lines}`);
58
+ return true;
59
+ }
60
+ const onMatch = m.match(/^(?:开启|启用|enable)\s+(\S+)$/);
61
+ if (onMatch && onMatch[1] in features) {
62
+ setFeature(onMatch[1], true);
63
+ return true;
64
+ }
65
+ const offMatch = m.match(/^(?:关闭|禁用|disable)\s+(\S+)$/);
66
+ if (offMatch && offMatch[1] in features) {
67
+ setFeature(offMatch[1], false);
68
+ return true;
69
+ }
70
+ return false;
71
+ }
72
+ __name(handleFeatureCommand, "handleFeatureCommand");
73
+ export {
74
+ getAllFeatures,
75
+ handleFeatureCommand,
76
+ isEnabled,
77
+ loadFeatures,
78
+ setFeature
79
+ };