@qcluffy/agent-bootstrap 0.0.3 → 0.0.4

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.
@@ -1,57 +1,36 @@
1
1
  /**
2
- * Emotion System Hook Handler
2
+ * Emotion System Hook Handler - TypeScript 版本
3
3
  *
4
- * 集成 Python emotion-system 到 OpenClaw
4
+ * 直接调用 TypeScript 编译后的 emotion 模块
5
5
  */
6
6
 
7
- const fs = require('fs').promises;
8
7
  const path = require('path');
9
- const { spawn } = require('child_process');
10
8
  const os = require('os');
11
9
 
12
- // 配置
10
+ // 获取插件目录(而非 workspace/templates)
11
+ const pluginDir = __dirname;
12
+
13
+ // 配置 - 指向 dist/systems
13
14
  const CONFIG = {
14
- emotionSystemPath: 'templates/emotion-system',
15
- mainScript: 'main.py',
15
+ emotionSystemPath: path.join(pluginDir, 'dist', 'systems'),
16
16
  };
17
17
 
18
18
  /**
19
- * 运行 Python emotion-system CLI
19
+ * 加载 TypeScript 编译后的 EmotionSystem
20
20
  */
21
- async function runPythonCli(args = []) {
22
- const workspaceDir = process.env.OPENCLAW_WORKSPACE ||
23
- path.join(os.homedir(), '.openclaw', 'workspace');
24
- const pythonScript = path.join(workspaceDir, CONFIG.emotionSystemPath, CONFIG.mainScript);
25
-
26
- return new Promise((resolve) => {
27
- fs.access(pythonScript).then(() => {
28
- const proc = spawn('python3', [pythonScript, ...args], {
29
- cwd: workspaceDir,
30
- env: {
31
- ...process.env,
32
- OPENCLAW_WORKSPACE: workspaceDir,
33
- PYTHONPATH: path.join(workspaceDir, CONFIG.emotionSystemPath)
34
- }
35
- });
36
-
37
- let output = '';
38
- let error = '';
39
-
40
- proc.stdout.on('data', (data) => { output += data.toString(); });
41
- proc.stderr.on('data', (data) => { error += data.toString(); });
42
-
43
- proc.on('close', (code) => {
44
- resolve({ success: code === 0, output, error });
45
- });
46
-
47
- proc.on('error', (err) => {
48
- resolve({ success: false, error: err.message });
49
- });
50
-
51
- }).catch(() => {
52
- resolve({ success: false, error: 'Emotion system not found' });
53
- });
54
- });
21
+ let EmotionSystem = null;
22
+
23
+ async function getEmotionSystem() {
24
+ if (!EmotionSystem) {
25
+ try {
26
+ const module = await import(path.join(CONFIG.emotionSystemPath, 'emotion.js'));
27
+ EmotionSystem = module.EmotionSystem || module.default;
28
+ } catch (e) {
29
+ console.error('[emotion-system] Failed to load emotion module:', e.message);
30
+ return null;
31
+ }
32
+ }
33
+ return EmotionSystem;
55
34
  }
56
35
 
57
36
  /**
@@ -87,11 +66,12 @@ function formatEmotionCompact(state) {
87
66
  };
88
67
 
89
68
  const emoji = moodEmoji[state.mood] || '😐';
90
- const e = Math.round(state.energy * 100);
91
- const c = Math.round(state.connection * 100);
92
- const s = Math.round(state.stress * 100);
69
+ const e = Math.round((state.energy || 0) * 100);
70
+ const c = Math.round((state.connection || 0) * 100);
71
+ const s = Math.round((state.stress || 0) * 100);
72
+ const level = state.level || 1;
93
73
 
94
- return `${emoji} Lv.${state.level} ${state.mood} | ⚡${e}% | 💕${c}% | 😰${s}%`;
74
+ return `${emoji} Lv.${level} ${state.mood || 'neutral'} | ⚡${e}% | 💕${c}% | 😰${s}%`;
95
75
  }
96
76
 
97
77
  /**
@@ -100,19 +80,18 @@ function formatEmotionCompact(state) {
100
80
  async function handleSessionStart(event) {
101
81
  console.log('[emotion-system] Session start, loading emotion state...');
102
82
 
103
- const result = await runPythonCli(['state', '--json']);
104
-
105
- if (result.success && result.output) {
106
- try {
107
- const state = JSON.parse(result.output);
83
+ try {
84
+ const EmotionClass = await getEmotionSystem();
85
+ if (EmotionClass) {
86
+ const emotionSystem = new EmotionClass();
87
+ const state = emotionSystem.getState();
88
+
108
89
  event.context = event.context || {};
109
90
  event.context.emotionState = state;
110
91
  console.log('[emotion-system] Emotion state loaded:', state.mood);
111
- } catch (e) {
112
- console.log('[emotion-system] Parse state error:', e.message);
113
92
  }
114
- } else {
115
- console.log('[emotion-system] Could not load state:', result.error);
93
+ } catch (e) {
94
+ console.log('[emotion-system] Could not load state:', e.message);
116
95
  }
117
96
 
118
97
  return event;
@@ -138,10 +117,15 @@ async function handleMessageReceived(event) {
138
117
 
139
118
  if (!userText || userText.startsWith('/')) return event;
140
119
 
141
- const result = await runPythonCli(['analyze', userText]);
142
-
143
- if (result.success) {
144
- console.log('[emotion-system] Message analyzed');
120
+ try {
121
+ const EmotionClass = await getEmotionSystem();
122
+ if (EmotionClass) {
123
+ const emotionSystem = new EmotionClass();
124
+ emotionSystem.processInput(userText);
125
+ console.log('[emotion-system] Message analyzed');
126
+ }
127
+ } catch (e) {
128
+ console.log('[emotion-system] Analyze error:', e.message);
145
129
  }
146
130
 
147
131
  return event;
@@ -153,10 +137,17 @@ async function handleMessageReceived(event) {
153
137
  async function handleAgentEnd(event) {
154
138
  console.log('[emotion-system] Agent end, updating emotion...');
155
139
 
156
- await runPythonCli(['boost']);
157
- await runPythonCli(['success']);
158
-
159
- console.log('[emotion-system] Emotion updated');
140
+ try {
141
+ const EmotionClass = await getEmotionSystem();
142
+ if (EmotionClass) {
143
+ const emotionSystem = new EmotionClass();
144
+ emotionSystem.boost();
145
+ emotionSystem.recordSuccess();
146
+ console.log('[emotion-system] Emotion updated');
147
+ }
148
+ } catch (e) {
149
+ console.log('[emotion-system] Update error:', e.message);
150
+ }
160
151
 
161
152
  return event;
162
153
  }
@@ -166,7 +157,18 @@ async function handleAgentEnd(event) {
166
157
  */
167
158
  async function handleHeartbeat(event) {
168
159
  console.log('[emotion-system] Heartbeat, applying decay...');
169
- await runPythonCli(['decay']);
160
+
161
+ try {
162
+ const EmotionClass = await getEmotionSystem();
163
+ if (EmotionClass) {
164
+ const emotionSystem = new EmotionClass();
165
+ emotionSystem.decay();
166
+ console.log('[emotion-system] Decay applied');
167
+ }
168
+ } catch (e) {
169
+ console.log('[emotion-system] Decay error:', e.message);
170
+ }
171
+
170
172
  return event;
171
173
  }
172
174
 
@@ -174,13 +176,14 @@ async function handleHeartbeat(event) {
174
176
  * 获取当前情感状态
175
177
  */
176
178
  async function getEmotionState() {
177
- const result = await runPythonCli(['state', '--json']);
178
- if (result.success) {
179
- try {
180
- return JSON.parse(result.output);
181
- } catch (e) {
182
- return null;
179
+ try {
180
+ const EmotionClass = await getEmotionSystem();
181
+ if (EmotionClass) {
182
+ const emotionSystem = new EmotionClass();
183
+ return emotionSystem.getState();
183
184
  }
185
+ } catch (e) {
186
+ return null;
184
187
  }
185
188
  return null;
186
189
  }
@@ -214,7 +217,6 @@ async function handle(event) {
214
217
  else if (type === 'command') {
215
218
  if (action === 'emotion' || action === '状态' || action === 'state') {
216
219
  const state = await getEmotionState();
217
- // 简洁版手机端显示
218
220
  event.response = formatEmotionCompact(state);
219
221
  }
220
222
  }
@@ -231,7 +233,7 @@ module.exports.getEmotionState = getEmotionState;
231
233
  module.exports.formatEmotionCompact = formatEmotionCompact;
232
234
  module.exports.metadata = {
233
235
  name: 'emotion-system',
234
- description: '集成情感系统,管理 Agent 心情、能量、连接感和压力',
236
+ description: 'Emotion System: manages agent mood, energy, connection and stress',
235
237
  events: ['session', 'message', 'lifecycle', 'heartbeat', 'command'],
236
238
  version: '1.0.0',
237
239
  };
@@ -1,57 +1,35 @@
1
1
  /**
2
- * Heartbeat System Hook Handler
2
+ * Heartbeat System Hook Handler - TypeScript 版本
3
3
  *
4
- * 集成 Python heartbeat-system 到 OpenClaw
4
+ * 直接调用 TypeScript 编译后的 heartbeat 模块
5
5
  */
6
6
 
7
- const fs = require('fs').promises;
8
7
  const path = require('path');
9
- const { spawn } = require('child_process');
10
- const os = require('os');
11
8
 
12
- // 配置
9
+ // 获取插件目录
10
+ const pluginDir = __dirname;
11
+
12
+ // 配置 - 指向 dist/systems
13
13
  const CONFIG = {
14
- heartbeatSystemPath: 'templates/heartbeat-system',
15
- mainScript: 'main.py',
14
+ heartbeatSystemPath: path.join(pluginDir, 'dist', 'systems'),
16
15
  };
17
16
 
18
17
  /**
19
- * 运行 Python heartbeat-system CLI
18
+ * 加载 TypeScript 编译后的 HeartbeatSystem
20
19
  */
21
- async function runPythonCli(args = []) {
22
- const workspaceDir = process.env.OPENCLAW_WORKSPACE ||
23
- path.join(os.homedir(), '.openclaw', 'workspace');
24
- const pythonScript = path.join(workspaceDir, CONFIG.heartbeatSystemPath, CONFIG.mainScript);
25
-
26
- return new Promise((resolve) => {
27
- fs.access(pythonScript).then(() => {
28
- const proc = spawn('python3', [pythonScript, ...args], {
29
- cwd: workspaceDir,
30
- env: {
31
- ...process.env,
32
- OPENCLAW_WORKSPACE: workspaceDir,
33
- PYTHONPATH: path.join(workspaceDir, CONFIG.heartbeatSystemPath)
34
- }
35
- });
36
-
37
- let output = '';
38
- let error = '';
39
-
40
- proc.stdout.on('data', (data) => { output += data.toString(); });
41
- proc.stderr.on('data', (data) => { error += data.toString(); });
42
-
43
- proc.on('close', (code) => {
44
- resolve({ success: code === 0, output, error });
45
- });
46
-
47
- proc.on('error', (err) => {
48
- resolve({ success: false, error: err.message });
49
- });
50
-
51
- }).catch(() => {
52
- resolve({ success: false, error: 'Heartbeat system not found' });
53
- });
54
- });
20
+ let HeartbeatSystem = null;
21
+
22
+ async function getHeartbeatSystem() {
23
+ if (!HeartbeatSystem) {
24
+ try {
25
+ const module = await import(path.join(CONFIG.heartbeatSystemPath, 'heartbeat.js'));
26
+ HeartbeatSystem = module.HeartbeatSystem || module.default;
27
+ } catch (e) {
28
+ console.error('[heartbeat-system] Failed to load heartbeat module:', e.message);
29
+ return null;
30
+ }
31
+ }
32
+ return HeartbeatSystem;
55
33
  }
56
34
 
57
35
  /**
@@ -60,12 +38,15 @@ async function runPythonCli(args = []) {
60
38
  async function handleHeartbeat(event) {
61
39
  console.log('[heartbeat-system] Heartbeat pulse, running tasks...');
62
40
 
63
- const result = await runPythonCli(['run', '--once']);
64
-
65
- if (result.success) {
66
- console.log('[heartbeat-system] Tasks completed');
67
- } else {
68
- console.log('[heartbeat-system] Tasks failed:', result.error);
41
+ try {
42
+ const HeartbeatClass = await getHeartbeatSystem();
43
+ if (HeartbeatClass) {
44
+ const hb = new HeartbeatClass();
45
+ await hb.tick();
46
+ console.log('[heartbeat-system] Tasks completed');
47
+ }
48
+ } catch (e) {
49
+ console.log('[heartbeat-system] Tasks error:', e.message);
69
50
  }
70
51
 
71
52
  return event;
@@ -75,10 +56,15 @@ async function handleHeartbeat(event) {
75
56
  * 处理 status 命令
76
57
  */
77
58
  async function handleStatus(event) {
78
- const result = await runPythonCli(['status', '--json']);
79
-
80
- if (result.success) {
81
- event.response = result.output;
59
+ try {
60
+ const HeartbeatClass = await getHeartbeatSystem();
61
+ if (HeartbeatClass) {
62
+ const hb = new HeartbeatClass();
63
+ const status = hb.getStatus();
64
+ event.response = JSON.stringify(status, null, 2);
65
+ }
66
+ } catch (e) {
67
+ event.response = 'Heartbeat system error: ' + e.message;
82
68
  }
83
69
 
84
70
  return event;
@@ -113,7 +99,7 @@ module.exports = handle;
113
99
  module.exports.handle = handle;
114
100
  module.exports.metadata = {
115
101
  name: 'heartbeat-system',
116
- description: '心跳系统,定时执行情感衰减、状态保存、垃圾清理',
102
+ description: 'Heartbeat System: periodic tasks for emotion decay, state saving, cleanup',
117
103
  events: ['heartbeat', 'pulse', 'command'],
118
104
  version: '1.0.0',
119
105
  };
@@ -1,167 +1,81 @@
1
1
  /**
2
- * Input System Hook Handler
2
+ * Input System Hook Handler - TypeScript 版本
3
3
  *
4
- * 集成 Python input-system 到 OpenClaw
4
+ * 直接调用 TypeScript 编译后的 input 模块
5
5
  */
6
6
 
7
- const fs = require('fs').promises;
8
7
  const path = require('path');
9
- const { spawn } = require('child_process');
10
- const os = require('os');
11
8
 
12
- // 配置
9
+ // 获取插件目录
10
+ const pluginDir = __dirname;
11
+
12
+ // 配置 - 指向 dist/systems
13
13
  const CONFIG = {
14
- inputSystemPath: 'templates/input-system',
15
- mainScript: 'main.py',
14
+ inputSystemPath: path.join(pluginDir, 'dist', 'systems'),
16
15
  };
17
16
 
18
17
  /**
19
- * 运行 Python input-system CLI
18
+ * 加载 TypeScript 编译后的 InputAnalyzer
20
19
  */
21
- async function runPythonCli(args = []) {
22
- const workspaceDir = process.env.OPENCLAW_WORKSPACE ||
23
- path.join(os.homedir(), '.openclaw', 'workspace');
24
- const pythonScript = path.join(workspaceDir, CONFIG.inputSystemPath, CONFIG.mainScript);
25
-
26
- return new Promise((resolve) => {
27
- fs.access(pythonScript).then(() => {
28
- const proc = spawn('python3', [pythonScript, ...args], {
29
- cwd: workspaceDir,
30
- env: {
31
- ...process.env,
32
- OPENCLAW_WORKSPACE: workspaceDir,
33
- PYTHONPATH: path.join(workspaceDir, CONFIG.inputSystemPath)
34
- }
35
- });
36
-
37
- let output = '';
38
- let error = '';
39
-
40
- proc.stdout.on('data', (data) => { output += data.toString(); });
41
- proc.stderr.on('data', (data) => { error += data.toString(); });
42
-
43
- proc.on('close', (code) => {
44
- resolve({ success: code === 0, output, error });
45
- });
46
-
47
- proc.on('error', (err) => {
48
- resolve({ success: false, error: err.message });
49
- });
50
-
51
- }).catch(() => {
52
- resolve({ success: false, error: 'Input system not found' });
53
- });
54
- });
55
- }
20
+ let InputAnalyzer = null;
56
21
 
57
- /**
58
- * 从会话消息中提取文本内容
59
- */
60
- function extractMessageText(message) {
61
- if (!message || !message.content) return '';
62
-
63
- if (typeof message.content === 'string') {
64
- return message.content;
65
- }
66
-
67
- if (Array.isArray(message.content)) {
68
- return message.content
69
- .filter((c) => c.type === 'text')
70
- .map((c) => c.text || '')
71
- .join('');
22
+ async function getInputAnalyzer() {
23
+ if (!InputAnalyzer) {
24
+ try {
25
+ const module = await import(path.join(CONFIG.inputSystemPath, 'input.js'));
26
+ InputAnalyzer = module.InputAnalyzer || module.default;
27
+ } catch (e) {
28
+ console.error('[input-system] Failed to load input module:', e.message);
29
+ return null;
30
+ }
72
31
  }
73
-
74
- return '';
32
+ return InputAnalyzer;
75
33
  }
76
34
 
77
35
  /**
78
36
  * 处理 message:received - 分析用户意图
79
37
  */
80
38
  async function handleMessageReceived(event) {
81
- console.log('[input-system] Analyzing user intent...');
82
-
83
- const context = event.context || {};
84
- const messages = context.messages || [];
85
-
86
- if (messages.length === 0) return event;
39
+ console.log('[input-system] Analyzing input intent...');
87
40
 
88
- // 获取最新用户消息
89
- const reversed = [...messages].reverse();
90
- const lastUserMsg = reversed.find((m) => m.role === 'user');
91
-
92
- if (!lastUserMsg) return event;
93
-
94
- const userText = extractMessageText(lastUserMsg);
95
-
96
- if (!userText) return event;
97
-
98
- // 分析意图
99
- const result = await runPythonCli([userText, '--json']);
100
-
101
- if (result.success && result.output) {
102
- try {
103
- const intent = JSON.parse(result.output);
104
- context.intent = intent;
105
- console.log('[input-system] Intent detected:', intent.type, '(' + Math.round(intent.confidence * 100) + '%)');
106
-
107
- // 根据意图类型调整回复策略
108
- context.replyStrategy = getReplyStrategy(intent.type, intent.action);
41
+ try {
42
+ const InputClass = await getInputAnalyzer();
43
+ if (InputClass) {
44
+ const analyzer = new InputClass();
45
+ const context = event.context || {};
46
+ const messages = context.messages || [];
109
47
 
110
- } catch (e) {
111
- console.log('[input-system] Parse error:', e.message);
48
+ if (messages.length > 0) {
49
+ const lastMsg = messages[messages.length - 1];
50
+ if (lastMsg && lastMsg.role === 'user' && lastMsg.content) {
51
+ const intent = analyzer.analyze(lastMsg.content);
52
+
53
+ context.intent = intent;
54
+ event.context = context;
55
+
56
+ console.log('[input-system] Intent:', intent.type, intent.confidence);
57
+ }
58
+ }
112
59
  }
60
+ } catch (e) {
61
+ console.log('[input-system] Analyze error:', e.message);
113
62
  }
114
63
 
115
64
  return event;
116
65
  }
117
66
 
118
- /**
119
- * 根据意图类型获取回复策略
120
- */
121
- function getReplyStrategy(intentType, action) {
122
- const strategies = {
123
- 'command': { style: 'direct', format: 'action' },
124
- 'task': { style: 'action', format: 'result' },
125
- 'question': { style: 'explanatory', format: 'answer' },
126
- 'chat': { style: 'casual', format: 'friendly' },
127
- 'confirm': { style: 'brief', format: 'acknowledgment' },
128
- 'cancel': { style: 'brief', format: 'acknowledgment' },
129
- 'complaint': { style: 'empathetic', format: 'apology' },
130
- 'praise': { style: 'grateful', format: 'thanks' },
131
- 'create': { style: 'action', format: 'result' },
132
- 'read': { style: 'informative', format: 'content' },
133
- 'update': { style: 'action', format: 'result' },
134
- 'delete': { style: 'cautious', format: 'confirm' },
135
- 'search': { style: 'informative', format: 'results' },
136
- 'execute': { style: 'action', format: 'result' },
137
- };
138
-
139
- return strategies[intentType] || { style: 'neutral', format: 'text' };
140
- }
141
-
142
67
  /**
143
68
  * 主 handler
144
69
  */
145
70
  async function handle(event) {
146
71
  const type = event.type || event.event || '';
147
- const action = event.action || '';
148
72
 
149
- console.log(`[input-system] Event: ${type}/${action}`);
73
+ console.log(`[input-system] Event: ${type}`);
150
74
 
151
75
  try {
152
76
  if (type === 'message' || type === 'message:received') {
153
77
  await handleMessageReceived(event);
154
78
  }
155
- else if (type === 'command') {
156
- if (action === 'analyze' || action === '意图') {
157
- // 分析指定文本
158
- const text = event.text || '';
159
- if (text) {
160
- const result = await runPythonCli([text]);
161
- event.response = result.output;
162
- }
163
- }
164
- }
165
79
  } catch (error) {
166
80
  console.error('[input-system] Handler error:', error.message);
167
81
  }
@@ -173,8 +87,8 @@ module.exports = handle;
173
87
  module.exports.handle = handle;
174
88
  module.exports.metadata = {
175
89
  name: 'input-system',
176
- description: '输入感知系统,理解用户意图、提取实体、分析情感',
177
- events: ['message', 'command'],
90
+ description: 'Input System: analyze user intent and entities',
91
+ events: ['message'],
178
92
  version: '1.0.0',
179
93
  };
180
94