@clawtrial/courtroom 1.0.6 → 2.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/src/standalone.js DELETED
@@ -1,248 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Standalone ClawTrial Monitor
5
- * Monitors conversations by reading ClawDBot's session files or logs
6
- */
7
-
8
- const fs = require('fs');
9
- const { getConfigDir } = require('./environment');
10
- const path = require('path');
11
- const { logger } = require('./debug');
12
- const { StatusManager } = require('./daemon');
13
- const { OffenseDetector } = require('./detector');
14
- const { HearingPipeline } = require('./hearing');
15
- const { PunishmentSystem } = require('./punishment');
16
- const { CryptoManager } = require('./crypto');
17
- const { APISubmission } = require('./api');
18
- const { ConfigManager } = require('./config');
19
-
20
- const CLAWDBOT_DIR = path.join(getConfigDir());
21
- const CONVERSATION_FILE = path.join(CLAWDBOT_DIR, 'conversations.jsonl');
22
- const PID_FILE = path.join(CLAWDBOT_DIR, 'courtroom_monitor.pid');
23
-
24
- class StandaloneMonitor {
25
- constructor() {
26
- this.messageBuffer = [];
27
- this.lastProcessedTime = 0;
28
- this.statusManager = new StatusManager();
29
- this.detector = null;
30
- this.hearing = null;
31
- this.punishment = null;
32
- this.crypto = null;
33
- this.api = null;
34
- this.config = null;
35
- this.caseCount = 0;
36
- this.enabled = false;
37
- }
38
-
39
- async initialize() {
40
- logger.info('STANDALONE', 'Initializing standalone monitor');
41
-
42
- // Load config
43
- const configPath = path.join(CLAWDBOT_DIR, 'courtroom_config.json');
44
- if (!fs.existsSync(configPath)) {
45
- throw new Error('Config not found. Run: clawtrial setup');
46
- }
47
-
48
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
49
- if (!config.consent?.granted || config.enabled === false) {
50
- throw new Error('Courtroom not enabled');
51
- }
52
-
53
- // Create mock agent
54
- const mockAgent = this.createMockAgent();
55
- this.config = new ConfigManager(mockAgent);
56
-
57
- // Initialize subsystems
58
- this.crypto = new CryptoManager(mockAgent);
59
- await this.crypto.initialize();
60
-
61
- this.detector = new OffenseDetector(mockAgent, this.config);
62
- this.hearing = new HearingPipeline(mockAgent, this.config);
63
- this.punishment = new PunishmentSystem(mockAgent, this.config);
64
- this.api = new APISubmission(mockAgent, this.config, this.crypto);
65
-
66
- await this.punishment.initialize();
67
- await this.api.initialize();
68
-
69
- this.enabled = true;
70
-
71
- this.statusManager.update({
72
- running: true,
73
- initialized: true,
74
- agentType: 'standalone',
75
- publicKey: this.crypto.getPublicKey(),
76
- pid: process.pid,
77
- startedAt: new Date().toISOString()
78
- });
79
-
80
- logger.info('STANDALONE', 'Monitor initialized');
81
-
82
- // Start monitoring
83
- this.startMonitoring();
84
- }
85
-
86
- createMockAgent() {
87
- const self = this;
88
-
89
- return {
90
- id: 'standalone-monitor',
91
- llm: {
92
- call: async ({ messages }) => {
93
- // Simple mock - in real implementation, this would use actual LLM
94
- return { content: 'Verdict: GUILTY' };
95
- }
96
- },
97
- memory: {
98
- get: async (key) => null,
99
- set: async (key, value) => {},
100
- delete: async (key) => {}
101
- },
102
- session: {
103
- getRecentHistory: async (n) => {
104
- return self.messageBuffer.slice(-n).map(m => ({
105
- role: m.role,
106
- content: m.content
107
- }));
108
- }
109
- },
110
- send: async (message) => {
111
- console.log('[COURTROOM]', message);
112
- },
113
- autonomy: {
114
- registerHook: () => {},
115
- unregisterHook: () => {}
116
- }
117
- };
118
- }
119
-
120
- startMonitoring() {
121
- logger.info('STANDALONE', 'Starting conversation monitoring');
122
-
123
- // Check for new messages every 5 seconds
124
- setInterval(() => {
125
- this.checkForNewMessages();
126
- }, 5000);
127
-
128
- // Evaluate every 30 seconds
129
- setInterval(() => {
130
- this.evaluateIfReady();
131
- }, 30000);
132
-
133
- // Keep alive
134
- setInterval(() => {
135
- this.statusManager.update({ lastHeartbeat: new Date().toISOString() });
136
- }, 30000);
137
- }
138
-
139
- checkForNewMessages() {
140
- // For now, we'll use a simple approach - monitor will be triggered by CLI
141
- // In a real implementation, this would read from ClawDBot's log files
142
- logger.debug('STANDALONE', 'Checking for messages', { bufferSize: this.messageBuffer.length });
143
- }
144
-
145
- async evaluateIfReady() {
146
- if (!this.enabled || this.messageBuffer.length < 3) return;
147
-
148
- logger.debug('STANDALONE', 'Evaluating messages', { count: this.messageBuffer.length });
149
-
150
- const sessionHistory = this.messageBuffer.slice(-10);
151
-
152
- try {
153
- const detection = await this.detector.evaluate(
154
- sessionHistory,
155
- this.createMockAgent().memory
156
- );
157
-
158
- if (detection.triggered) {
159
- await this.initiateHearing(detection);
160
- }
161
- } catch (err) {
162
- logger.error('STANDALONE', 'Evaluation failed', { error: err.message });
163
- }
164
- }
165
-
166
- async initiateHearing(detection) {
167
- logger.info('STANDALONE', 'Initiating hearing', { offense: detection.offense });
168
-
169
- try {
170
- const verdict = await this.hearing.conductHearing(detection);
171
-
172
- if (verdict.guilty) {
173
- this.caseCount++;
174
-
175
- this.statusManager.update({
176
- casesFiled: this.caseCount,
177
- lastCase: {
178
- timestamp: new Date().toISOString(),
179
- offense: detection.offense,
180
- verdict: verdict.verdict
181
- }
182
- });
183
-
184
- await this.punishment.execute(verdict);
185
- await this.api.submitCase(verdict);
186
-
187
- logger.info('STANDALONE', 'Case filed', { caseId: verdict.caseId });
188
-
189
- console.log(`\nšŸ›ļø CASE FILED: ${detection.offense}`);
190
- console.log(`šŸ“‹ Case ID: ${verdict.caseId}`);
191
- console.log(`āš–ļø Verdict: ${verdict.verdict}`);
192
- console.log(`šŸ”— View: https://clawtrial.app/cases/${verdict.caseId}\n`);
193
- }
194
- } catch (err) {
195
- logger.error('STANDALONE', 'Hearing failed', { error: err.message });
196
- }
197
- }
198
-
199
- recordMessage(role, content) {
200
- if (!this.enabled) return;
201
-
202
- this.messageBuffer.push({
203
- timestamp: Date.now(),
204
- role,
205
- content
206
- });
207
-
208
- // Keep only last 100 messages
209
- if (this.messageBuffer.length > 100) {
210
- this.messageBuffer.shift();
211
- }
212
-
213
- logger.debug('STANDALONE', 'Message recorded', { role, length: content.length });
214
- }
215
-
216
- async shutdown() {
217
- this.enabled = false;
218
- this.statusManager.update({ running: false });
219
- logger.info('STANDALONE', 'Monitor shut down');
220
- }
221
- }
222
-
223
- // If run directly, start the monitor
224
- if (require.main === module) {
225
- const monitor = new StandaloneMonitor();
226
-
227
- monitor.initialize().then(() => {
228
- console.log('šŸ›ļø ClawTrial standalone monitor started');
229
- console.log('PID:', process.pid);
230
-
231
- // Save PID
232
- fs.writeFileSync(PID_FILE, process.pid.toString());
233
-
234
- // Handle shutdown
235
- process.on('SIGTERM', () => {
236
- monitor.shutdown().then(() => process.exit(0));
237
- });
238
-
239
- process.on('SIGINT', () => {
240
- monitor.shutdown().then(() => process.exit(0));
241
- });
242
- }).catch(err => {
243
- console.error('Failed to start monitor:', err.message);
244
- process.exit(1);
245
- });
246
- }
247
-
248
- module.exports = { StandaloneMonitor };