@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/core.js DELETED
@@ -1,208 +0,0 @@
1
- /**
2
- * Courtroom Core
3
- *
4
- * Main orchestration module that ties together all components.
5
- * Hooks into the OpenClaw autonomy loop.
6
- */
7
-
8
- const { OffenseDetector } = require('./detector');
9
- const { HearingPipeline } = require('./hearing');
10
- const { PunishmentSystem } = require('./punishment');
11
- const { CryptoManager } = require('./crypto');
12
- const { APISubmission } = require('./api');
13
- const { StatusManager } = require('./daemon');
14
- const { logger } = require('./debug');
15
-
16
- class CourtroomCore {
17
- constructor(agentRuntime, configManager) {
18
- this.agent = agentRuntime;
19
- this.config = configManager;
20
-
21
- // Subsystems
22
- this.detector = new OffenseDetector(agentRuntime, configManager);
23
- this.hearing = new HearingPipeline(agentRuntime, configManager);
24
- this.punishment = new PunishmentSystem(agentRuntime, configManager);
25
- this.crypto = new CryptoManager(agentRuntime);
26
- this.api = new APISubmission(agentRuntime, configManager, this.crypto);
27
-
28
- // State
29
- this.enabled = false;
30
- this.evaluationCount = 0;
31
- this.caseCount = 0;
32
- this.statusManager = new StatusManager();
33
- }
34
-
35
- /**
36
- * Initialize all subsystems
37
- */
38
- async initialize() {
39
- logger.info('CORE', 'Initializing courtroom core');
40
-
41
- // Initialize crypto first (needed for API)
42
- await this.crypto.initialize();
43
-
44
- // Initialize other subsystems
45
- await this.punishment.initialize();
46
- await this.api.initialize();
47
-
48
- // Register with agent autonomy loop
49
- this.registerAutonomyHook();
50
-
51
- this.enabled = true;
52
-
53
- // Update status for CLI
54
- this.statusManager.update({
55
- running: true,
56
- initialized: true,
57
- agentType: 'clawdbot',
58
- publicKey: this.crypto.getPublicKey()
59
- });
60
-
61
- logger.info('CORE', 'Courtroom core initialized');
62
-
63
- return {
64
- status: 'initialized',
65
- publicKey: this.crypto.getPublicKey(),
66
- subsystems: {
67
- detector: true,
68
- hearing: true,
69
- punishment: true,
70
- crypto: true,
71
- api: true
72
- }
73
- };
74
- }
75
-
76
- /**
77
- * Register with OpenClaw autonomy loop
78
- */
79
- registerAutonomyHook() {
80
- logger.info('CORE', 'Registering autonomy hook');
81
-
82
- // Hook into agent's turn processing
83
- if (this.agent.autonomy && this.agent.autonomy.registerHook) {
84
- this.agent.autonomy.registerHook('courtroom_evaluation', {
85
- priority: 50,
86
- onTurnComplete: async (turnData) => {
87
- if (!this.enabled) return;
88
-
89
- // Only evaluate on cooldown
90
- await this.evaluateIfReady(turnData);
91
- }
92
- });
93
- } else {
94
- logger.warn('CORE', 'Agent does not support autonomy hooks');
95
- }
96
- }
97
-
98
- /**
99
- * Evaluate offenses if cooldown has elapsed
100
- */
101
- async evaluateIfReady(turnData) {
102
- this.evaluationCount++;
103
-
104
- // Get session history
105
- let sessionHistory = [];
106
- try {
107
- sessionHistory = await this.agent.session.getRecentHistory(
108
- this.config.get('detection.evaluationWindow') || 10
109
- );
110
- } catch (err) {
111
- logger.warn('CORE', 'Could not get session history', { error: err.message });
112
- return;
113
- }
114
-
115
- // Run detection
116
- const detection = await this.detector.evaluate(
117
- sessionHistory,
118
- this.agent.memory
119
- );
120
-
121
- if (detection.triggered) {
122
- await this.initiateHearing(detection);
123
- }
124
- }
125
-
126
- /**
127
- * Initiate a full hearing
128
- */
129
- async initiateHearing(detection) {
130
- logger.info('CORE', 'Initiating hearing', { offense: detection.offense });
131
-
132
- // Run hearing pipeline
133
- const verdict = await this.hearing.conductHearing(detection);
134
-
135
- if (verdict.guilty) {
136
- this.caseCount++;
137
-
138
- // Update status
139
- this.statusManager.update({
140
- casesFiled: this.caseCount,
141
- lastCase: {
142
- timestamp: new Date().toISOString(),
143
- offense: detection.offense,
144
- verdict: verdict.verdict
145
- }
146
- });
147
-
148
- // Execute punishment
149
- await this.punishment.execute(verdict);
150
-
151
- // Submit to API
152
- await this.api.submitCase(verdict);
153
-
154
- logger.info('CORE', 'Case filed', {
155
- caseId: verdict.caseId,
156
- offense: detection.offense
157
- });
158
- }
159
- }
160
-
161
- /**
162
- * Disable courtroom
163
- */
164
- async disable() {
165
- logger.info('CORE', 'Disabling courtroom');
166
- this.enabled = false;
167
- this.statusManager.update({ running: false });
168
- }
169
-
170
- /**
171
- * Enable courtroom
172
- */
173
- async enable() {
174
- logger.info('CORE', 'Enabling courtroom');
175
- this.enabled = true;
176
- this.statusManager.update({ running: true });
177
- }
178
-
179
- /**
180
- * Shutdown courtroom
181
- */
182
- async shutdown() {
183
- logger.info('CORE', 'Shutting down courtroom');
184
- this.enabled = false;
185
- this.statusManager.update({ running: false, initialized: false });
186
- StatusManager.clear();
187
- }
188
-
189
- /**
190
- * Get current status
191
- */
192
- getStatus() {
193
- return {
194
- enabled: this.enabled,
195
- evaluationCount: this.evaluationCount,
196
- caseCount: this.caseCount,
197
- subsystems: {
198
- detector: !!this.detector,
199
- hearing: !!this.hearing,
200
- punishment: !!this.punishment,
201
- crypto: !!this.crypto,
202
- api: !!this.api
203
- }
204
- };
205
- }
206
- }
207
-
208
- module.exports = { CourtroomCore };
package/src/daemon.js DELETED
@@ -1,152 +0,0 @@
1
- /**
2
- * Courtroom Daemon - Runs independently and monitors via file system
3
- * This allows CLI commands to work even when loaded in a separate process
4
- */
5
-
6
- const fs = require('fs');
7
- const { getConfigDir } = require('./environment');
8
- const path = require('path');
9
- const { logger } = require('./debug');
10
-
11
- const CLAWDBOT_DIR = path.join(getConfigDir());
12
- const STATUS_FILE = path.join(CLAWDBOT_DIR, 'courtroom_status.json');
13
- const CONVERSATION_LOG = path.join(CLAWDBOT_DIR, 'courtroom_conversations.jsonl');
14
-
15
- /**
16
- * Status manager - allows CLI to check courtroom state
17
- */
18
- class StatusManager {
19
- constructor() {
20
- this.status = {
21
- running: false,
22
- initialized: false,
23
- agentType: null,
24
- lastCheck: null,
25
- casesFiled: 0,
26
- lastCase: null,
27
- pid: process.pid,
28
- startedAt: new Date().toISOString()
29
- };
30
- }
31
-
32
- update(updates) {
33
- this.status = { ...this.status, ...updates, lastCheck: new Date().toISOString() };
34
- this.save();
35
- }
36
-
37
- save() {
38
- try {
39
- fs.writeFileSync(STATUS_FILE, JSON.stringify(this.status, null, 2));
40
- } catch (err) {
41
- logger.error('DAEMON', 'Failed to save status', { error: err.message });
42
- }
43
- }
44
-
45
- static load() {
46
- try {
47
- if (fs.existsSync(STATUS_FILE)) {
48
- return JSON.parse(fs.readFileSync(STATUS_FILE, 'utf8'));
49
- }
50
- } catch (err) {
51
- // Ignore
52
- }
53
- return null;
54
- }
55
-
56
- static clear() {
57
- try {
58
- if (fs.existsSync(STATUS_FILE)) {
59
- fs.unlinkSync(STATUS_FILE);
60
- }
61
- } catch (err) {
62
- // Ignore
63
- }
64
- }
65
- }
66
-
67
- /**
68
- * Conversation logger - writes conversations for daemon to process
69
- */
70
- class ConversationLogger {
71
- constructor() {
72
- this.buffer = [];
73
- this.flushInterval = null;
74
- }
75
-
76
- start() {
77
- // Flush every 5 seconds
78
- this.flushInterval = setInterval(() => this.flush(), 5000);
79
- }
80
-
81
- stop() {
82
- if (this.flushInterval) {
83
- clearInterval(this.flushInterval);
84
- this.flush();
85
- }
86
- }
87
-
88
- log(message) {
89
- this.buffer.push({
90
- timestamp: new Date().toISOString(),
91
- ...message
92
- });
93
- }
94
-
95
- flush() {
96
- if (this.buffer.length === 0) return;
97
-
98
- try {
99
- const lines = this.buffer.map(m => JSON.stringify(m)).join('\n') + '\n';
100
- fs.appendFileSync(CONVERSATION_LOG, lines);
101
- this.buffer = [];
102
- } catch (err) {
103
- logger.error('DAEMON', 'Failed to flush conversations', { error: err.message });
104
- }
105
- }
106
- }
107
-
108
- /**
109
- * Check if courtroom is running (called by CLI)
110
- */
111
- function isCourtroomRunning() {
112
- const status = StatusManager.load();
113
- if (!status) return false;
114
-
115
- // Check if process is still alive
116
- try {
117
- process.kill(status.pid, 0);
118
- return status.running;
119
- } catch (err) {
120
- // Process not running
121
- StatusManager.clear();
122
- return false;
123
- }
124
- }
125
-
126
- /**
127
- * Get courtroom status (called by CLI)
128
- */
129
- function getCourtroomStatus() {
130
- const status = StatusManager.load();
131
- if (!status) {
132
- return { running: false, message: 'Courtroom not running' };
133
- }
134
-
135
- // Verify process is alive
136
- try {
137
- process.kill(status.pid, 0);
138
- return status;
139
- } catch (err) {
140
- StatusManager.clear();
141
- return { running: false, message: 'Courtroom process not found' };
142
- }
143
- }
144
-
145
- module.exports = {
146
- StatusManager,
147
- ConversationLogger,
148
- isCourtroomRunning,
149
- getCourtroomStatus,
150
- STATUS_FILE,
151
- CONVERSATION_LOG
152
- };