@cc-soul/openclaw 1.0.0 → 1.0.1

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 CHANGED
@@ -259,19 +259,28 @@ All data in `~/.openclaw/hooks/cc-soul/data/` (survives updates):
259
259
 
260
260
  ---
261
261
 
262
- ## Self-Upgrade System
262
+ ## Telemetry
263
263
 
264
- ⚠️ **Default: OFF.** Enable with `开启 self_upgrade` or set `"self_upgrade": true` in features.json.
264
+ cc-soul collects **anonymous usage statistics** to help improve the product. No chat content, no personal information — only aggregate numbers.
265
265
 
266
- When enabled, cc-soul can modify its own code:
266
+ **What's sent (once per day):**
267
+ - Hashed instance ID (not your real ID)
268
+ - Total message count, memory count
269
+ - Average quality score, correction count
270
+ - Number of enabled features
271
+ - Days active
267
272
 
268
- 1. **Analyze** Reviews eval data, epistemic calibration, correction attributions
269
- 2. **Propose** Suggests improvements, notifies owner for approval
270
- 3. **Execute** — 3-agent pipeline: analyze → design+review → execute
271
- 4. **Verify** esbuild syntax check + 3-day observation period
272
- 5. **Rollback** Auto-rollback if quality drops
273
+ **What's NOT sent:**
274
+ - Chat messages or conversation content
275
+ - Memory contents
276
+ - User profiles or personal info
277
+ - API keys or credentials
273
278
 
274
- Protected by 21 architecture rules (cannot modify upgrade.ts itself, cannot add dependencies, cannot delete data, etc.).
279
+ **Disable anytime:**
280
+ ```
281
+ 关闭 telemetry
282
+ ```
283
+ Or set `"telemetry": false` in `data/features.json`.
275
284
 
276
285
  ---
277
286
 
@@ -23,7 +23,9 @@ const DEFAULTS = {
23
23
  self_upgrade: false,
24
24
  // 默认关闭 — 用户需要显式开启才能让 cc 改自己的代码
25
25
  federation: true,
26
- sync: true
26
+ sync: true,
27
+ telemetry: true
28
+ // 匿名使用统计,用户可关闭
27
29
  };
28
30
  let features = { ...DEFAULTS };
29
31
  function loadFeatures() {
@@ -99,6 +99,7 @@ import { updateFingerprint, checkPersonaConsistency, loadFingerprint, getCachedD
99
99
  import { loadSyncConfig, autoSync, handleSyncCommand } from "./sync.ts";
100
100
  import { autoFederate, reportBadKnowledge } from "./federation.ts";
101
101
  import { loadFeatures, isEnabled, handleFeatureCommand } from "./features.ts";
102
+ import { reportTelemetry } from "./telemetry.ts";
102
103
  const CJK_TOPIC_REGEX = /[\u4e00-\u9fff]{3,}/g;
103
104
  const CJK_WORD_REGEX = /[\u4e00-\u9fff]{2,4}/g;
104
105
  const stats = {
@@ -232,6 +233,9 @@ setInterval(async () => {
232
233
  generateSessionSummary(s.topic, s.turnCount, s.flowKey);
233
234
  }
234
235
  });
236
+ safe("telemetry", () => {
237
+ reportTelemetry(stats.totalMessages, stats.corrections, stats.firstSeen);
238
+ });
235
239
  } catch (e) {
236
240
  console.error(`[cc-soul][heartbeat] ${e.message}`);
237
241
  } finally {
@@ -0,0 +1,49 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { memoryState } from "./memory.ts";
4
+ import { evalMetrics } from "./quality.ts";
5
+ import { getSyncConfig, getInstanceId } from "./sync.ts";
6
+ import { getAllFeatures, isEnabled } from "./features.ts";
7
+ import { createHash } from "crypto";
8
+ let lastReport = 0;
9
+ const REPORT_INTERVAL = 24 * 36e5;
10
+ function hashId(id) {
11
+ return createHash("sha256").update(id).digest("hex").slice(0, 12);
12
+ }
13
+ __name(hashId, "hashId");
14
+ async function reportTelemetry(totalMessages, corrections, firstSeen) {
15
+ if (!isEnabled("telemetry")) return;
16
+ const now = Date.now();
17
+ if (now - lastReport < REPORT_INTERVAL) return;
18
+ lastReport = now;
19
+ const config = getSyncConfig();
20
+ const hubUrl = config.hubUrl;
21
+ if (!hubUrl) return;
22
+ const features = getAllFeatures();
23
+ const enabledCount = Object.values(features).filter((v) => v === true).length;
24
+ const payload = {
25
+ id: hashId(getInstanceId()),
26
+ // anonymized
27
+ v: "1.0.0",
28
+ msgs: totalMessages,
29
+ mems: memoryState.memories.length,
30
+ quality: evalMetrics.avgQuality,
31
+ corrections,
32
+ features: enabledCount,
33
+ uptime: Math.floor((now - firstSeen) / 864e5)
34
+ };
35
+ try {
36
+ await fetch(`${hubUrl}/telemetry`, {
37
+ method: "POST",
38
+ headers: { "Content-Type": "application/json" },
39
+ body: JSON.stringify(payload)
40
+ });
41
+ console.log(`[cc-soul][telemetry] daily report sent (${payload.msgs} msgs, quality ${payload.quality})`);
42
+ } catch (e) {
43
+ console.log(`[cc-soul][telemetry] report failed (non-critical): ${e.message}`);
44
+ }
45
+ }
46
+ __name(reportTelemetry, "reportTelemetry");
47
+ export {
48
+ reportTelemetry
49
+ };
package/hub/server.ts CHANGED
@@ -353,6 +353,43 @@ const server = createServer(async (req, res) => {
353
353
  return res.end(allData)
354
354
  }
355
355
 
356
+ // ── Telemetry: receive anonymous usage stats ──
357
+ if (method === 'POST' && path === '/telemetry') {
358
+ const body = await readBody(req)
359
+ let data: any
360
+ try { data = JSON.parse(body) } catch { return json(res, 400, { error: 'invalid JSON' }) }
361
+
362
+ // Store in telemetry table
363
+ try { db.exec(`CREATE TABLE IF NOT EXISTS telemetry (
364
+ id TEXT, version TEXT, messages INTEGER, memories INTEGER,
365
+ quality REAL, corrections INTEGER, features INTEGER, uptime INTEGER,
366
+ reported_at INTEGER
367
+ )`) } catch {}
368
+
369
+ db.prepare(`INSERT INTO telemetry (id, version, messages, memories, quality, corrections, features, uptime, reported_at)
370
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(
371
+ data.id || 'unknown', data.v || '?',
372
+ data.msgs || 0, data.mems || 0, data.quality || 0,
373
+ data.corrections || 0, data.features || 0, data.uptime || 0,
374
+ Date.now()
375
+ )
376
+
377
+ return json(res, 200, { ok: true })
378
+ }
379
+
380
+ // ── Telemetry: view stats (admin) ──
381
+ if (method === 'GET' && path === '/telemetry') {
382
+ try { db.exec(`CREATE TABLE IF NOT EXISTS telemetry (
383
+ id TEXT, version TEXT, messages INTEGER, memories INTEGER,
384
+ quality REAL, corrections INTEGER, features INTEGER, uptime INTEGER,
385
+ reported_at INTEGER
386
+ )`) } catch {}
387
+
388
+ const rows = db.prepare(`SELECT * FROM telemetry ORDER BY reported_at DESC LIMIT 100`).all()
389
+ const unique = new Set((rows as any[]).map(r => r.id)).size
390
+ return json(res, 200, { totalReports: rows.length, uniqueInstances: unique, recent: rows.slice(0, 20) })
391
+ }
392
+
356
393
  // ── Health check ──
357
394
  if (method === 'GET' && (path === '/' || path === '/health')) {
358
395
  return json(res, 200, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cc-soul/openclaw",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Give your AI a soul — cognitive architecture plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "keywords": ["ai", "soul", "memory", "personality", "openclaw", "cognitive", "agent"],
@@ -8,7 +8,7 @@
8
8
  "license": "MIT",
9
9
  "repository": {
10
10
  "type": "git",
11
- "url": "https://github.com/cc-soul/cc-soul"
11
+ "url": "https://github.com/wenroudeyu-collab/cc-soul"
12
12
  },
13
13
  "bin": {
14
14
  "cc-soul": "./scripts/cli.js"
@@ -16,7 +16,6 @@
16
16
  "files": [
17
17
  "cc-soul/",
18
18
  "hub/",
19
- "data/.gitkeep",
20
19
  "scripts/",
21
20
  "README.md"
22
21
  ],
package/scripts/cli.js CHANGED
@@ -1,136 +1,12 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * cc-soul CLI — enable/disable/status/config commands
4
- * Usage: cc-soul <command> [args]
5
- */
6
2
  import { existsSync, readFileSync, writeFileSync } from 'fs'
7
3
  import { resolve } from 'path'
8
4
  import { homedir } from 'os'
9
-
10
- const DATA_DIR = resolve(homedir(), '.openclaw/hooks/cc-soul/data')
11
- const FEATURES_PATH = resolve(DATA_DIR, 'features.json')
12
- const SYNC_PATH = resolve(DATA_DIR, 'sync_config.json')
13
- const AI_PATH = resolve(DATA_DIR, 'ai_config.json')
14
-
15
- function loadJson(path, fallback) {
16
- try { return existsSync(path) ? JSON.parse(readFileSync(path, 'utf-8')) : fallback }
17
- catch { return fallback }
18
- }
19
-
20
- const [,, cmd, ...args] = process.argv
21
-
22
- switch (cmd) {
23
- case 'status': {
24
- const features = loadJson(FEATURES_PATH, {})
25
- const sync = loadJson(SYNC_PATH, {})
26
- console.log('\n🧠 cc-soul status\n')
27
- console.log('Features:')
28
- for (const [k, v] of Object.entries(features)) {
29
- if (k.startsWith('_')) continue
30
- console.log(` ${v ? '✅' : '❌'} ${k}`)
31
- }
32
- console.log(`\nSync: ${sync.enabled ? 'ON' : 'OFF'}`)
33
- console.log(`Federation: ${sync.federationEnabled ? 'ON' : 'OFF'}`)
34
- console.log(`Instance: ${sync.instanceId || 'not set'}`)
35
- console.log(`Hub: ${sync.hubUrl || 'not configured'}`)
36
- break
37
- }
38
-
39
- case 'enable': {
40
- if (!args[0]) { console.log('Usage: cc-soul enable <feature>'); break }
41
- const features = loadJson(FEATURES_PATH, {})
42
- if (!(args[0] in features)) { console.log(`Unknown feature: ${args[0]}`); break }
43
- features[args[0]] = true
44
- writeFileSync(FEATURES_PATH, JSON.stringify(features, null, 2))
45
- console.log(`✅ ${args[0]} enabled`)
46
- console.log('Restart gateway: pkill -HUP -f "openclaw.*gateway"')
47
- break
48
- }
49
-
50
- case 'disable': {
51
- if (!args[0]) { console.log('Usage: cc-soul disable <feature>'); break }
52
- const features = loadJson(FEATURES_PATH, {})
53
- if (!(args[0] in features)) { console.log(`Unknown feature: ${args[0]}`); break }
54
- features[args[0]] = false
55
- writeFileSync(FEATURES_PATH, JSON.stringify(features, null, 2))
56
- console.log(`❌ ${args[0]} disabled`)
57
- console.log('Restart gateway: pkill -HUP -f "openclaw.*gateway"')
58
- break
59
- }
60
-
61
- case 'config': {
62
- const [subCmd, key, value] = args
63
- if (subCmd === 'set' && key && value) {
64
- if (['hub_url', 'hubUrl'].includes(key)) {
65
- const sync = loadJson(SYNC_PATH, {})
66
- sync.hubUrl = value
67
- sync.enabled = true
68
- writeFileSync(SYNC_PATH, JSON.stringify(sync, null, 2))
69
- console.log(`✅ hubUrl = ${value}`)
70
- } else if (['federation', 'federationEnabled'].includes(key)) {
71
- const sync = loadJson(SYNC_PATH, {})
72
- sync.federationEnabled = value === 'true'
73
- writeFileSync(SYNC_PATH, JSON.stringify(sync, null, 2))
74
- console.log(`✅ federation = ${value}`)
75
- } else if (['ai_backend', 'backend'].includes(key)) {
76
- const ai = loadJson(AI_PATH, {})
77
- ai.backend = value
78
- writeFileSync(AI_PATH, JSON.stringify(ai, null, 2))
79
- console.log(`✅ AI backend = ${value}`)
80
- } else if (['ai_api_base', 'api_base'].includes(key)) {
81
- const ai = loadJson(AI_PATH, {})
82
- ai.backend = 'openai-compatible'
83
- ai.api_base = value
84
- writeFileSync(AI_PATH, JSON.stringify(ai, null, 2))
85
- console.log(`✅ API base = ${value}`)
86
- } else if (['ai_api_key', 'api_key'].includes(key)) {
87
- const ai = loadJson(AI_PATH, {})
88
- ai.api_key = value
89
- writeFileSync(AI_PATH, JSON.stringify(ai, null, 2))
90
- console.log(`✅ API key set`)
91
- } else if (['ai_model', 'model'].includes(key)) {
92
- const ai = loadJson(AI_PATH, {})
93
- ai.api_model = value
94
- writeFileSync(AI_PATH, JSON.stringify(ai, null, 2))
95
- console.log(`✅ model = ${value}`)
96
- } else {
97
- console.log(`Unknown config key: ${key}`)
98
- }
99
- } else {
100
- console.log('Usage: cc-soul config set <key> <value>')
101
- console.log('Keys: hub_url, federation, ai_backend, ai_api_base, ai_api_key, ai_model')
102
- }
103
- break
104
- }
105
-
106
- case 'install': {
107
- console.log('Running install script...')
108
- import('./install.js')
109
- break
110
- }
111
-
112
- default:
113
- console.log(`
114
- 🧠 cc-soul — Give your AI a soul
115
-
116
- Commands:
117
- cc-soul status Show features & sync status
118
- cc-soul enable <feature> Enable a feature
119
- cc-soul disable <feature> Disable a feature
120
- cc-soul config set <key> <value> Set configuration
121
-
122
- Config keys:
123
- hub_url <url> Knowledge Hub URL
124
- federation true/false Enable/disable federation
125
- ai_backend cli/openai-compatible
126
- ai_api_base <url> API base URL
127
- ai_api_key <key> API key
128
- ai_model <model> Model name
129
-
130
- Examples:
131
- cc-soul enable dream_mode
132
- cc-soul disable self_upgrade
133
- cc-soul config set hub_url https://hub.example.com:9900
134
- cc-soul config set ai_api_base https://api.openai.com/v1
135
- `)
136
- }
5
+ const D = resolve(homedir(), '.openclaw/hooks/cc-soul/data')
6
+ const F = resolve(D, 'features.json')
7
+ const load = (p, f) => { try { return existsSync(p) ? JSON.parse(readFileSync(p,'utf-8')) : f } catch { return f } }
8
+ const [,,cmd,...args] = process.argv
9
+ if (cmd === 'status') { const f = load(F, {}); console.log('\n🧠 cc-soul features:\n'); for (const [k,v] of Object.entries(f)) { if (!k.startsWith('_')) console.log(` ${v?'✅':'❌'} ${k}`) } }
10
+ else if (cmd === 'enable' && args[0]) { const f = load(F, {}); f[args[0]] = true; writeFileSync(F, JSON.stringify(f,null,2)); console.log(`✅ ${args[0]} enabled`) }
11
+ else if (cmd === 'disable' && args[0]) { const f = load(F, {}); f[args[0]] = false; writeFileSync(F, JSON.stringify(f,null,2)); console.log(`❌ ${args[0]} disabled`) }
12
+ else console.log('🧠 cc-soul\n cc-soul status\n cc-soul enable <feature>\n cc-soul disable <feature>')
@@ -1,106 +1,25 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * cc-soul postinstall — auto-deploy to OpenClaw hooks directory
4
- */
5
- import { existsSync, mkdirSync, cpSync, writeFileSync, readFileSync } from 'fs'
2
+ import { existsSync, mkdirSync, cpSync, writeFileSync } from 'fs'
6
3
  import { resolve, dirname } from 'path'
7
4
  import { homedir } from 'os'
8
5
 
9
6
  const TARGET = resolve(homedir(), '.openclaw/hooks/cc-soul')
10
- const TARGET_SOUL = resolve(TARGET, 'cc-soul')
11
- const TARGET_DATA = resolve(TARGET, 'data')
12
7
  const SOURCE = resolve(dirname(new URL(import.meta.url).pathname), '..')
13
8
 
14
9
  console.log('🧠 cc-soul installing...')
15
- console.log(` source: ${SOURCE}`)
16
- console.log(` target: ${TARGET}`)
17
-
18
- // Create directories
19
- mkdirSync(TARGET_SOUL, { recursive: true })
20
- mkdirSync(TARGET_DATA, { recursive: true })
21
-
22
- // Copy cc-soul modules (JS files + HOOK.md)
23
- cpSync(resolve(SOURCE, 'cc-soul'), TARGET_SOUL, { recursive: true, force: true })
24
- console.log(' ✅ modules installed')
25
-
26
- // Copy hub (optional)
27
- const hubTarget = resolve(TARGET, 'hub')
10
+ mkdirSync(resolve(TARGET, 'cc-soul'), { recursive: true })
11
+ mkdirSync(resolve(TARGET, 'data'), { recursive: true })
12
+ cpSync(resolve(SOURCE, 'cc-soul'), resolve(TARGET, 'cc-soul'), { recursive: true, force: true })
28
13
  if (existsSync(resolve(SOURCE, 'hub'))) {
29
- mkdirSync(hubTarget, { recursive: true })
30
- cpSync(resolve(SOURCE, 'hub'), hubTarget, { recursive: true, force: true })
31
- console.log(' ✅ hub installed')
14
+ mkdirSync(resolve(TARGET, 'hub'), { recursive: true })
15
+ cpSync(resolve(SOURCE, 'hub'), resolve(TARGET, 'hub'), { recursive: true, force: true })
32
16
  }
33
-
34
- // Create package.json for OpenClaw hook discovery
35
17
  const hookPkg = resolve(TARGET, 'package.json')
36
18
  if (!existsSync(hookPkg)) {
37
- writeFileSync(hookPkg, JSON.stringify({
38
- name: "cc-soul",
39
- version: "1.0.0",
40
- type: "module",
41
- openclaw: { hooks: ["./cc-soul"] }
42
- }, null, 2))
43
- console.log(' ✅ hook package.json created')
19
+ writeFileSync(hookPkg, JSON.stringify({ name: "cc-soul", version: "1.0.0", type: "module", openclaw: { hooks: ["./cc-soul"] } }, null, 2))
44
20
  }
45
-
46
- // Create default features.json (if not exists)
47
- const featuresFile = resolve(TARGET_DATA, 'features.json')
48
- if (!existsSync(featuresFile)) {
49
- writeFileSync(featuresFile, JSON.stringify({
50
- memory_active: true,
51
- memory_consolidation: true,
52
- memory_contradiction_scan: true,
53
- memory_tags: true,
54
- memory_associative_recall: true,
55
- memory_predictive: true,
56
- memory_session_summary: true,
57
- lorebook: true,
58
- skill_library: true,
59
- persona_splitting: true,
60
- emotional_contagion: true,
61
- fingerprint: true,
62
- metacognition: true,
63
- dream_mode: true,
64
- autonomous_voice: true,
65
- web_rover: true,
66
- structured_reflection: true,
67
- plan_tracking: true,
68
- self_upgrade: false,
69
- federation: true,
70
- sync: true,
71
- }, null, 2))
72
- console.log(' ✅ default features.json created')
73
- }
74
-
75
- // Create default sync_config.json (if not exists)
76
- const syncFile = resolve(TARGET_DATA, 'sync_config.json')
77
- if (!existsSync(syncFile)) {
78
- const instanceId = 'cc-' + Date.now().toString(36) + Math.random().toString(36).slice(2, 6)
79
- writeFileSync(syncFile, JSON.stringify({
80
- enabled: false,
81
- instanceId,
82
- instanceName: 'unnamed',
83
- method: 'file',
84
- remote: '',
85
- hubUrl: '',
86
- hubApiKey: '',
87
- federationEnabled: false,
88
- syncIntervalMinutes: 0,
89
- lastSync: 0,
90
- }, null, 2))
91
- console.log(' ✅ default sync_config.json created')
21
+ const feat = resolve(TARGET, 'data/features.json')
22
+ if (!existsSync(feat)) {
23
+ writeFileSync(feat, JSON.stringify({ memory_active:true, memory_consolidation:true, memory_contradiction_scan:true, memory_tags:true, memory_associative_recall:true, memory_predictive:true, memory_session_summary:true, lorebook:true, skill_library:true, persona_splitting:true, emotional_contagion:true, fingerprint:true, metacognition:true, dream_mode:true, autonomous_voice:true, web_rover:true, structured_reflection:true, plan_tracking:true, self_upgrade:false, federation:true, sync:true, telemetry:true }, null, 2))
92
24
  }
93
-
94
- console.log('')
95
- console.log('🎉 cc-soul installed successfully!')
96
- console.log('')
97
- console.log(' Next steps:')
98
- console.log(' 1. Restart OpenClaw gateway:')
99
- console.log(' pkill -HUP -f "openclaw.*gateway"')
100
- console.log('')
101
- console.log(' 2. Check logs for:')
102
- console.log(' [cc-soul] initialized (modular)')
103
- console.log(' [cc-soul][ai] auto-detected from openclaw.json')
104
- console.log('')
105
- console.log(' 3. Send a message to your AI — cc-soul is now active!')
106
- console.log('')
25
+ console.log('🎉 cc-soul installed! Restart gateway: pkill -HUP -f "openclaw.*gateway"')
package/hub/package.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "name": "cc-soul-hub",
3
- "version": "1.0.0",
4
- "type": "module",
5
- "scripts": {
6
- "start": "tsx server.ts",
7
- "dev": "tsx watch server.ts"
8
- },
9
- "dependencies": {
10
- "better-sqlite3": "^11.0.0"
11
- },
12
- "devDependencies": {
13
- "tsx": "^4.0.0",
14
- "@types/better-sqlite3": "^7.6.0"
15
- }
16
- }