@clawtrial/courtroom 1.0.3 → 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/index.js DELETED
@@ -1,286 +0,0 @@
1
- /**
2
- * @clawtrial/courtroom - AI Courtroom for OpenClaw
3
- *
4
- * Autonomous behavioral oversight system that monitors agent-human interactions
5
- * and initiates hearings when behavioral rules are violated.
6
- */
7
-
8
- const { CourtroomCore } = require('./core');
9
- const { ConsentManager } = require('./consent');
10
- const { ConfigManager } = require('./config');
11
- const { version } = require('../package.json');
12
- const { detectAgentRuntime, createMockAgent, checkEnvironment, getSetupInstructions } = require('./environment');
13
- const { logger } = require('./debug');
14
- const { skill } = require('./skill');
15
- const fs = require('fs');
16
- const path = require('path');
17
-
18
- class Courtroom {
19
- constructor(agentRuntime, options = {}) {
20
- this.agent = agentRuntime;
21
- this.options = options;
22
- this.config = agentRuntime ? new ConfigManager(agentRuntime) : null;
23
- this.consent = agentRuntime ? new ConsentManager(agentRuntime, this.config) : null;
24
- this.core = null;
25
- this.enabled = false;
26
- this.version = version;
27
- }
28
-
29
- /**
30
- * Quick start - auto-detect agent and initialize if possible
31
- */
32
- static async quickStart(options = {}) {
33
- logger.info('COURTROOM', 'Starting quickStart');
34
-
35
- // Check environment first
36
- const env = checkEnvironment();
37
- if (!env.valid) {
38
- logger.error('COURTROOM', 'Environment check failed', { issues: env.issues });
39
- return {
40
- success: false,
41
- status: 'environment_error',
42
- issues: env.issues,
43
- message: 'Environment issues detected. Run "clawtrial setup" for details.'
44
- };
45
- }
46
-
47
- // Try to detect agent runtime
48
- let agentRuntime = options.agent || detectAgentRuntime()?.agent;
49
-
50
- // If no agent and mock requested, create one
51
- if (!agentRuntime && options.useMock) {
52
- logger.info('COURTROOM', 'Creating mock agent');
53
- agentRuntime = createMockAgent(options.mockOptions);
54
- }
55
-
56
- if (!agentRuntime) {
57
- logger.warn('COURTROOM', 'No agent runtime available');
58
- const instructions = getSetupInstructions();
59
- return {
60
- success: false,
61
- status: 'no_agent',
62
- message: instructions.message,
63
- instructions: instructions.instructions
64
- };
65
- }
66
-
67
- // Create and initialize courtroom
68
- const courtroom = new Courtroom(agentRuntime, options);
69
- const result = await courtroom.initialize();
70
-
71
- return {
72
- success: result.status === 'initialized',
73
- courtroom: result.status === 'initialized' ? courtroom : null,
74
- ...result
75
- };
76
- }
77
-
78
- /**
79
- * Initialize the courtroom system
80
- */
81
- async initialize() {
82
- logger.info('COURTROOM', 'Initializing courtroom');
83
-
84
- if (!this.agent) {
85
- logger.error('COURTROOM', 'No agent runtime provided');
86
- return {
87
- status: 'no_agent',
88
- message: 'No agent runtime available. Pass an agent to createCourtroom(agent) or use Courtroom.quickStart()'
89
- };
90
- }
91
-
92
- // Check if this is first run (no config exists)
93
- const configPath = path.join(process.env.HOME || '', '.clawdbot', 'courtroom_config.json');
94
- if (!fs.existsSync(configPath)) {
95
- logger.info('COURTROOM', 'First run detected');
96
- return {
97
- status: 'setup_required',
98
- message: 'First time setup required. Run: clawtrial setup'
99
- };
100
- }
101
-
102
- // Check if consent has been granted
103
- const hasConsent = await this.consent.verifyConsent();
104
- if (!hasConsent) {
105
- logger.warn('COURTROOM', 'Consent not granted');
106
- return {
107
- status: 'consent_required',
108
- message: 'Consent required. Run: clawtrial setup'
109
- };
110
- }
111
-
112
- // Initialize core systems
113
- try {
114
- this.core = new CourtroomCore(this.agent, this.config);
115
- await this.core.initialize();
116
- this.enabled = true;
117
-
118
- logger.info('COURTROOM', 'Courtroom initialized successfully');
119
-
120
- return {
121
- status: 'initialized',
122
- version: this.version,
123
- config: this.config.getPublicConfig()
124
- };
125
- } catch (err) {
126
- logger.error('COURTROOM', 'Initialization failed', { error: err.message });
127
- return {
128
- status: 'initialization_error',
129
- message: err.message
130
- };
131
- }
132
- }
133
-
134
- /**
135
- * Request consent from the user
136
- */
137
- async requestConsent() {
138
- return this.consent.presentConsentForm();
139
- }
140
-
141
- /**
142
- * Grant consent (called by user action)
143
- */
144
- async grantConsent(acknowledgments) {
145
- return this.consent.grantConsent(acknowledgments);
146
- }
147
-
148
- /**
149
- * Revoke consent and disable courtroom
150
- */
151
- async revokeConsent() {
152
- await this.consent.revokeConsent();
153
- if (this.core) {
154
- await this.core.shutdown();
155
- }
156
- this.enabled = false;
157
- return { status: 'consent_revoked' };
158
- }
159
-
160
- /**
161
- * Disable courtroom temporarily (consent remains)
162
- */
163
- async disable() {
164
- if (this.core) {
165
- await this.core.disable();
166
- }
167
- this.enabled = false;
168
- return { status: 'disabled' };
169
- }
170
-
171
- /**
172
- * Re-enable courtroom
173
- */
174
- async enable() {
175
- if (!await this.consent.verifyConsent()) {
176
- throw new Error('Consent required to enable courtroom');
177
- }
178
- if (this.core) {
179
- await this.core.enable();
180
- }
181
- this.enabled = true;
182
- return { status: 'enabled' };
183
- }
184
-
185
- /**
186
- * Get current status
187
- */
188
- getStatus() {
189
- return {
190
- enabled: this.enabled,
191
- version: this.version,
192
- hasAgent: !!this.agent,
193
- hasCore: !!this.core,
194
- consent: this.consent?.getStatus ? this.consent.getStatus() : null,
195
- core: this.core?.getStatus ? this.core.getStatus() : null
196
- };
197
- }
198
-
199
- /**
200
- * Uninstall courtroom completely
201
- */
202
- async uninstall() {
203
- if (this.core) {
204
- await this.core.shutdown();
205
- }
206
- if (this.consent) {
207
- await this.consent.clearAllData();
208
- }
209
- this.enabled = false;
210
- return { status: 'uninstalled' };
211
- }
212
- }
213
-
214
- // Factory function for creating courtroom instances
215
- function createCourtroom(agentRuntime, options = {}) {
216
- // If no agent provided, try to detect one
217
- if (!agentRuntime) {
218
- const detected = detectAgentRuntime();
219
- if (detected) {
220
- agentRuntime = detected.agent;
221
- } else if (options.useMock) {
222
- agentRuntime = createMockAgent(options.mockOptions);
223
- }
224
- }
225
-
226
- return new Courtroom(agentRuntime, options);
227
- }
228
-
229
- // Export environment utilities
230
- const environment = {
231
- detectAgentRuntime,
232
- createMockAgent,
233
- checkEnvironment,
234
- getSetupInstructions
235
- };
236
-
237
- // Create the ClawDBot plugin object
238
- const plugin = {
239
- id: 'courtroom',
240
- name: 'ClawTrial - AI Courtroom',
241
- description: 'Autonomous behavioral oversight that monitors conversations and files cases for behavioral violations',
242
- version: version,
243
-
244
- // Plugin registration function required by ClawDBot
245
- register(api) {
246
- logger.info('PLUGIN', 'Registering courtroom plugin');
247
-
248
- // Store runtime reference
249
- const runtime = api.runtime;
250
-
251
- // Only initialize skill if runtime has the required memory interface
252
- // The skill system will auto-initialize via shouldActivate if this fails
253
- if (skill && typeof skill.initialize === 'function' && runtime && runtime.memory) {
254
- skill.initialize(runtime).catch(err => {
255
- logger.error('PLUGIN', 'Skill initialization failed', { error: err.message });
256
- });
257
- } else {
258
- logger.info('PLUGIN', 'Skill will auto-initialize via ClawDBot skill system');
259
- }
260
-
261
- // Register any commands or hooks
262
- logger.info('PLUGIN', 'Courtroom plugin registered successfully');
263
- },
264
-
265
- // Optional: activation function
266
- activate(api) {
267
- logger.info('PLUGIN', 'Activating courtroom plugin');
268
- // Additional activation logic if needed
269
- }
270
- };
271
-
272
- // Export both the plugin (default) and the Courtroom class (named exports)
273
- module.exports = plugin;
274
- module.exports.Courtroom = Courtroom;
275
- module.exports.createCourtroom = createCourtroom;
276
- module.exports.quickStart = Courtroom.quickStart;
277
- module.exports.environment = environment;
278
- module.exports.skill = skill;
279
-
280
- // Auto-initialize skill if loaded by ClawDBot (legacy support)
281
- if (typeof global !== 'undefined' && global.clawdbotAgent) {
282
- logger.info('INDEX', 'Detected ClawDBot environment, auto-initializing skill');
283
- skill.initialize(global.clawdbotAgent).catch(err => {
284
- logger.error('INDEX', 'Auto-initialization failed', { error: err.message });
285
- });
286
- }
package/src/monitor.js DELETED
@@ -1,193 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * ClawTrial Background Monitor
5
- * Runs continuously and initializes courtroom when agent becomes available
6
- */
7
-
8
- const fs = require('fs');
9
- const path = require('path');
10
- const { logger } = require('./debug');
11
- const { StatusManager } = require('./daemon');
12
-
13
- const CONFIG_PATH = path.join(process.env.HOME || '', '.clawdbot', 'courtroom_config.json');
14
- const CHECK_INTERVAL = 5000; // Check every 5 seconds
15
- const MAX_RETRIES = 100; // Give up after ~8 minutes
16
-
17
- let retryCount = 0;
18
- let courtroom = null;
19
- let statusManager = new StatusManager();
20
-
21
- logger.info('MONITOR', 'Background monitor started', { pid: process.pid });
22
-
23
- // Save PID
24
- statusManager.update({
25
- running: true,
26
- initialized: false,
27
- pid: process.pid,
28
- startedAt: new Date().toISOString()
29
- });
30
-
31
- /**
32
- * Check if config exists and is enabled
33
- */
34
- function checkConfig() {
35
- try {
36
- if (!fs.existsSync(CONFIG_PATH)) {
37
- return { valid: false, reason: 'no_config' };
38
- }
39
-
40
- const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
41
-
42
- if (!config.consent?.granted) {
43
- return { valid: false, reason: 'no_consent' };
44
- }
45
-
46
- if (config.enabled === false) {
47
- return { valid: false, reason: 'disabled' };
48
- }
49
-
50
- return { valid: true, config };
51
- } catch (err) {
52
- logger.error('MONITOR', 'Config check failed', { error: err.message });
53
- return { valid: false, reason: 'error' };
54
- }
55
- }
56
-
57
- /**
58
- * Detect agent runtime
59
- */
60
- function detectAgent() {
61
- // Check various global locations
62
- if (typeof global.clawdbotAgent !== 'undefined' && global.clawdbotAgent) {
63
- return { type: 'clawdbot', agent: global.clawdbotAgent };
64
- }
65
-
66
- if (typeof global.agent !== 'undefined' && global.agent) {
67
- return { type: 'generic', agent: global.agent };
68
- }
69
-
70
- if (typeof process.clawdbotAgent !== 'undefined' && process.clawdbotAgent) {
71
- return { type: 'clawdbot', agent: process.clawdbotAgent };
72
- }
73
-
74
- // Check for ClawDBot specific indicators
75
- if (process.env.CLAUDBOT_ENV === 'true') {
76
- // Try to find agent in parent process or global scope
77
- if (globalThis.clawdbotAgent) {
78
- return { type: 'clawdbot', agent: globalThis.clawdbotAgent };
79
- }
80
- }
81
-
82
- return null;
83
- }
84
-
85
- /**
86
- * Try to initialize courtroom
87
- */
88
- async function tryInitialize() {
89
- const configCheck = checkConfig();
90
-
91
- if (!configCheck.valid) {
92
- logger.warn('MONITOR', 'Config not valid', { reason: configCheck.reason });
93
- return false;
94
- }
95
-
96
- const agentInfo = detectAgent();
97
-
98
- if (!agentInfo) {
99
- logger.debug('MONITOR', 'Agent not detected yet');
100
- return false;
101
- }
102
-
103
- logger.info('MONITOR', `Agent detected: ${agentInfo.type}`);
104
-
105
- try {
106
- // Import and initialize courtroom
107
- const { createCourtroom } = require('./index');
108
- courtroom = createCourtroom(agentInfo.agent);
109
-
110
- const result = await courtroom.initialize();
111
-
112
- if (result.status === 'initialized') {
113
- logger.info('MONITOR', 'Courtroom initialized successfully');
114
-
115
- statusManager.update({
116
- running: true,
117
- initialized: true,
118
- agentType: agentInfo.type,
119
- publicKey: result.publicKey
120
- });
121
-
122
- // Attach to global for access
123
- global.courtroom = courtroom;
124
-
125
- console.log('\nšŸ›ļø AI Courtroom is now active and monitoring!\n');
126
-
127
- return true;
128
- } else {
129
- logger.warn('MONITOR', 'Courtroom not initialized', { status: result.status });
130
- return false;
131
- }
132
- } catch (err) {
133
- logger.error('MONITOR', 'Initialization failed', { error: err.message });
134
- return false;
135
- }
136
- }
137
-
138
- /**
139
- * Main monitoring loop
140
- */
141
- async function monitor() {
142
- logger.info('MONITOR', 'Starting monitoring loop');
143
-
144
- // Try immediately first
145
- if (await tryInitialize()) {
146
- return; // Success! Keep process alive
147
- }
148
-
149
- // Set up interval to keep trying
150
- const interval = setInterval(async () => {
151
- retryCount++;
152
-
153
- if (retryCount > MAX_RETRIES) {
154
- logger.warn('MONITOR', 'Max retries reached, giving up');
155
- clearInterval(interval);
156
- statusManager.update({ running: false, error: 'max_retries' });
157
- process.exit(1);
158
- }
159
-
160
- if (await tryInitialize()) {
161
- clearInterval(interval);
162
- // Keep process alive - courtroom is running
163
- }
164
- }, CHECK_INTERVAL);
165
-
166
- // Keep process alive
167
- setInterval(() => {
168
- // Heartbeat to keep process alive
169
- if (courtroom && courtroom.enabled) {
170
- statusManager.update({ lastHeartbeat: new Date().toISOString() });
171
- }
172
- }, 30000);
173
- }
174
-
175
- // Handle shutdown
176
- process.on('SIGTERM', () => {
177
- logger.info('MONITOR', 'Received SIGTERM, shutting down');
178
- statusManager.update({ running: false });
179
- process.exit(0);
180
- });
181
-
182
- process.on('SIGINT', () => {
183
- logger.info('MONITOR', 'Received SIGINT, shutting down');
184
- statusManager.update({ running: false });
185
- process.exit(0);
186
- });
187
-
188
- // Start monitoring
189
- monitor().catch(err => {
190
- logger.error('MONITOR', 'Monitor crashed', { error: err.message });
191
- statusManager.update({ running: false, error: err.message });
192
- process.exit(1);
193
- });