@clawtrial/courtroom 1.0.3-a → 1.0.3-c
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 +35 -12
- package/SKILL.md +17 -2
- package/package.json +1 -1
- package/scripts/clawtrial.js +74 -28
- package/scripts/daemon.js +61 -0
- package/scripts/postinstall.js +13 -33
package/README.md
CHANGED
|
@@ -9,13 +9,24 @@ AI Courtroom - Autonomous behavioral oversight for OpenClaw agents.
|
|
|
9
9
|
npm install -g @clawtrial/courtroom
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
**⚠️ IMPORTANT:** If `clawtrial` command is not found after install, run:
|
|
13
|
+
```bash
|
|
14
|
+
# Option 1: Add npm global bin to PATH
|
|
15
|
+
export PATH="$HOME/.npm-global/bin:$PATH"
|
|
16
|
+
|
|
17
|
+
# Option 2: Create symlink (requires sudo)
|
|
18
|
+
sudo ln -sf "$HOME/.npm-global/lib/node_modules/@clawtrial/courtroom/scripts/clawtrial.js" /usr/bin/clawtrial
|
|
19
|
+
```
|
|
20
|
+
|
|
12
21
|
### 2. Setup
|
|
13
22
|
```bash
|
|
14
23
|
clawtrial setup
|
|
15
24
|
```
|
|
16
25
|
|
|
17
|
-
### 3.
|
|
18
|
-
|
|
26
|
+
### 3. Start the Courtroom
|
|
27
|
+
```bash
|
|
28
|
+
clawtrial start
|
|
29
|
+
```
|
|
19
30
|
|
|
20
31
|
### 4. Verify
|
|
21
32
|
```bash
|
|
@@ -27,12 +38,11 @@ clawtrial status
|
|
|
27
38
|
## 📋 How It Works
|
|
28
39
|
|
|
29
40
|
ClawTrial runs as a **ClawDBot skill** that:
|
|
30
|
-
1.
|
|
31
|
-
2.
|
|
32
|
-
3.
|
|
33
|
-
4. Files cases automatically
|
|
41
|
+
1. Monitors all conversations
|
|
42
|
+
2. Detects behavioral violations
|
|
43
|
+
3. Files cases automatically
|
|
34
44
|
|
|
35
|
-
**
|
|
45
|
+
**Note:** You must run `clawtrial start` after installation to activate monitoring.
|
|
36
46
|
|
|
37
47
|
---
|
|
38
48
|
|
|
@@ -40,6 +50,7 @@ ClawTrial runs as a **ClawDBot skill** that:
|
|
|
40
50
|
|
|
41
51
|
```bash
|
|
42
52
|
clawtrial setup # Interactive setup (run this first)
|
|
53
|
+
clawtrial start # Start monitoring (required!)
|
|
43
54
|
clawtrial status # Check if courtroom is running
|
|
44
55
|
clawtrial diagnose # Run full diagnostics
|
|
45
56
|
clawtrial disable # Pause monitoring
|
|
@@ -83,11 +94,23 @@ See all verdicts at: **https://clawtrial.app**
|
|
|
83
94
|
|
|
84
95
|
## 🛠️ Troubleshooting
|
|
85
96
|
|
|
97
|
+
### "clawtrial: command not found"
|
|
98
|
+
npm installs global packages to `~/.npm-global/bin` but your shell may not have this in PATH.
|
|
99
|
+
|
|
100
|
+
**Fix:**
|
|
101
|
+
```bash
|
|
102
|
+
# Add to your ~/.bashrc or ~/.zshrc:
|
|
103
|
+
export PATH="$HOME/.npm-global/bin:$PATH"
|
|
104
|
+
|
|
105
|
+
# Then reload:
|
|
106
|
+
source ~/.bashrc # or ~/.zshrc
|
|
107
|
+
```
|
|
108
|
+
|
|
86
109
|
### "Courtroom not running"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
110
|
+
You need to explicitly start it:
|
|
111
|
+
```bash
|
|
112
|
+
clawtrial start
|
|
113
|
+
```
|
|
91
114
|
|
|
92
115
|
### Need help?
|
|
93
116
|
```bash
|
|
@@ -102,7 +125,7 @@ clawtrial debug # Shows logs
|
|
|
102
125
|
```bash
|
|
103
126
|
npm install -g github:Assassin-1234/clawtrial
|
|
104
127
|
clawtrial setup
|
|
105
|
-
|
|
128
|
+
clawtrial start
|
|
106
129
|
```
|
|
107
130
|
|
|
108
131
|
---
|
package/SKILL.md
CHANGED
|
@@ -8,15 +8,28 @@ metadata: {"clawdbot":{"emoji":"🏛️","requires":{"env":[],"config":["courtro
|
|
|
8
8
|
|
|
9
9
|
Autonomous behavioral oversight for OpenClaw agents. Monitors conversations and initiates hearings when behavioral rules are violated.
|
|
10
10
|
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @clawtrial/courtroom
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**If `clawtrial` command not found:**
|
|
18
|
+
```bash
|
|
19
|
+
export PATH="$HOME/.npm-global/bin:$PATH"
|
|
20
|
+
# Or: sudo ln -sf "$HOME/.npm-global/lib/node_modules/@clawtrial/courtroom/scripts/clawtrial.js" /usr/bin/clawtrial
|
|
21
|
+
```
|
|
22
|
+
|
|
11
23
|
## Setup
|
|
12
24
|
|
|
13
25
|
```bash
|
|
14
|
-
clawtrial setup
|
|
26
|
+
clawtrial setup # Run once to grant consent
|
|
27
|
+
clawtrial start # Start monitoring (REQUIRED!)
|
|
15
28
|
```
|
|
16
29
|
|
|
17
30
|
## How It Works
|
|
18
31
|
|
|
19
|
-
Once
|
|
32
|
+
Once started, the courtroom automatically:
|
|
20
33
|
1. Monitors all conversations
|
|
21
34
|
2. Detects 8 types of behavioral violations
|
|
22
35
|
3. Initiates hearings with local LLM jury
|
|
@@ -39,6 +52,8 @@ Once enabled, the courtroom automatically:
|
|
|
39
52
|
## CLI Commands
|
|
40
53
|
|
|
41
54
|
```bash
|
|
55
|
+
clawtrial setup # Interactive setup
|
|
56
|
+
clawtrial start # Start monitoring (REQUIRED!)
|
|
42
57
|
clawtrial status # Check status
|
|
43
58
|
clawtrial disable # Pause monitoring
|
|
44
59
|
clawtrial enable # Resume monitoring
|
package/package.json
CHANGED
package/scripts/clawtrial.js
CHANGED
|
@@ -274,7 +274,7 @@ function enable() {
|
|
|
274
274
|
log('The courtroom will activate when ClawDBot loads the skill.\n');
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
-
// Start command -
|
|
277
|
+
// Start command - daemonize and run in background
|
|
278
278
|
async function start() {
|
|
279
279
|
const config = loadConfig();
|
|
280
280
|
|
|
@@ -302,37 +302,79 @@ async function start() {
|
|
|
302
302
|
|
|
303
303
|
log('\n🏛️ Starting ClawTrial...\n');
|
|
304
304
|
|
|
305
|
+
// Fork a daemon process
|
|
306
|
+
const spawn = require('child_process').spawn;
|
|
307
|
+
const daemonPath = require('path').join(__dirname, 'daemon.js');
|
|
308
|
+
|
|
309
|
+
// Create daemon script if it doesn't exist
|
|
310
|
+
if (!fs.existsSync(daemonPath)) {
|
|
311
|
+
const daemonScript = `#!/usr/bin/env node
|
|
312
|
+
const { skill } = require('../src/skill');
|
|
313
|
+
|
|
314
|
+
const mockAgent = {
|
|
315
|
+
memory: {
|
|
316
|
+
get: async () => null,
|
|
317
|
+
set: async () => {}
|
|
318
|
+
},
|
|
319
|
+
send: async () => {}
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
skill.initialize(mockAgent).then(() => {
|
|
323
|
+
console.log('Courtroom daemon started, PID:', process.pid);
|
|
324
|
+
// Keep process alive
|
|
325
|
+
setInterval(() => {}, 1000 * 60 * 60);
|
|
326
|
+
}).catch(err => {
|
|
327
|
+
console.error('Failed to start:', err.message);
|
|
328
|
+
process.exit(1);
|
|
329
|
+
});
|
|
330
|
+
`;
|
|
331
|
+
fs.writeFileSync(daemonPath, daemonScript);
|
|
332
|
+
fs.chmodSync(daemonPath, 0o755);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Spawn detached process
|
|
336
|
+
const child = spawn('node', [daemonPath], {
|
|
337
|
+
detached: true,
|
|
338
|
+
stdio: 'ignore'
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
child.unref();
|
|
342
|
+
|
|
343
|
+
// Wait a moment and check status
|
|
344
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
345
|
+
|
|
346
|
+
const newStatus = getCourtroomStatus();
|
|
347
|
+
if (newStatus.running) {
|
|
348
|
+
log('✅ ClawTrial started successfully!\n');
|
|
349
|
+
log('🏛️ Courtroom is now monitoring conversations');
|
|
350
|
+
log('📋 Status: Running');
|
|
351
|
+
log('🔑 Public Key: ' + (fs.existsSync(keysPath) ? JSON.parse(fs.readFileSync(keysPath)).publicKey.substring(0, 32) : 'N/A') + '...\n');
|
|
352
|
+
log('💡 Tip: Run "clawtrial status" anytime to check status\n');
|
|
353
|
+
} else {
|
|
354
|
+
log('⚠️ ClawTrial may not have started properly\n');
|
|
355
|
+
log(' Run "clawtrial diagnose" for details\n');
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Stop command - kill the daemon
|
|
359
|
+
function stop() {
|
|
360
|
+
const { getCourtroomStatus } = require('../src/daemon');
|
|
361
|
+
const status = getCourtroomStatus();
|
|
362
|
+
|
|
363
|
+
if (!status.running) {
|
|
364
|
+
log('\n🏛️ ClawTrial is not running\n');
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
log('\n🏛️ Stopping ClawTrial...\n');
|
|
369
|
+
|
|
305
370
|
try {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
// Create a minimal mock agent for standalone operation
|
|
310
|
-
const mockAgent = {
|
|
311
|
-
memory: {
|
|
312
|
-
get: async () => null,
|
|
313
|
-
set: async () => {}
|
|
314
|
-
},
|
|
315
|
-
send: async () => {}
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
await skillModule.initialize(mockAgent);
|
|
319
|
-
|
|
320
|
-
const status = skillModule.getStatus();
|
|
321
|
-
|
|
322
|
-
if (status.initialized && status.enabled) {
|
|
323
|
-
log('✅ ClawTrial started successfully!\n');
|
|
324
|
-
log('🏛️ Courtroom is now monitoring conversations');
|
|
325
|
-
log('📋 Status: Running');
|
|
326
|
-
log('🔑 Public Key: ' + (fs.existsSync(keysPath) ? JSON.parse(fs.readFileSync(keysPath)).publicKey.substring(0, 32) : 'N/A') + '...\n');
|
|
327
|
-
} else {
|
|
328
|
-
log('⚠️ ClawTrial started but may not be fully operational\n');
|
|
329
|
-
}
|
|
371
|
+
process.kill(status.pid, 'SIGTERM');
|
|
372
|
+
log('✅ ClawTrial stopped\n');
|
|
330
373
|
} catch (err) {
|
|
331
|
-
log('
|
|
332
|
-
log('Try running: clawtrial diagnose\n');
|
|
333
|
-
process.exit(1);
|
|
374
|
+
log('⚠️ Could not stop process: ' + err.message + '\n');
|
|
334
375
|
}
|
|
335
376
|
}
|
|
377
|
+
}
|
|
336
378
|
|
|
337
379
|
|
|
338
380
|
// Revoke command
|
|
@@ -516,6 +558,7 @@ function help() {
|
|
|
516
558
|
log(' revoke - Revoke consent and uninstall');
|
|
517
559
|
log(' debug [full|clear] - View or clear debug logs');
|
|
518
560
|
log(' start - Start the courtroom manually');
|
|
561
|
+
log(' stop - Stop the courtroom daemon');
|
|
519
562
|
log(' diagnose - Run diagnostics');
|
|
520
563
|
log(' help - Show this help message');
|
|
521
564
|
log('');
|
|
@@ -553,6 +596,9 @@ async function main() {
|
|
|
553
596
|
case 'start':
|
|
554
597
|
await start();
|
|
555
598
|
break;
|
|
599
|
+
case 'stop':
|
|
600
|
+
stop();
|
|
601
|
+
break;
|
|
556
602
|
case 'diagnose':
|
|
557
603
|
diagnose();
|
|
558
604
|
break;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Courtroom Daemon - Runs the skill as a background process
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { skill } = require('../src/skill');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
// Create minimal mock agent
|
|
12
|
+
const mockAgent = {
|
|
13
|
+
memory: {
|
|
14
|
+
get: async () => null,
|
|
15
|
+
set: async () => {}
|
|
16
|
+
},
|
|
17
|
+
send: async () => {}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Initialize skill
|
|
21
|
+
skill.initialize(mockAgent).then(() => {
|
|
22
|
+
const status = skill.getStatus();
|
|
23
|
+
if (status.initialized) {
|
|
24
|
+
console.log('🏛️ Courtroom daemon started, PID:', process.pid);
|
|
25
|
+
|
|
26
|
+
// Write PID file
|
|
27
|
+
const pidPath = path.join(process.env.HOME || '', '.clawdbot', 'courtroom_daemon.pid');
|
|
28
|
+
fs.writeFileSync(pidPath, process.pid.toString());
|
|
29
|
+
|
|
30
|
+
// Keep process alive
|
|
31
|
+
setInterval(() => {
|
|
32
|
+
// Heartbeat - update status file
|
|
33
|
+
if (skill.statusManager) {
|
|
34
|
+
skill.statusManager.update({ lastCheck: new Date().toISOString() });
|
|
35
|
+
}
|
|
36
|
+
}, 30000); // Every 30 seconds
|
|
37
|
+
} else {
|
|
38
|
+
console.error('❌ Skill failed to initialize');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
}).catch(err => {
|
|
42
|
+
console.error('❌ Failed to start daemon:', err.message);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Handle graceful shutdown
|
|
47
|
+
process.on('SIGTERM', async () => {
|
|
48
|
+
console.log('🏛️ Shutting down courtroom daemon...');
|
|
49
|
+
if (skill) {
|
|
50
|
+
await skill.shutdown();
|
|
51
|
+
}
|
|
52
|
+
process.exit(0);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
process.on('SIGINT', async () => {
|
|
56
|
+
console.log('🏛️ Shutting down courtroom daemon...');
|
|
57
|
+
if (skill) {
|
|
58
|
+
await skill.shutdown();
|
|
59
|
+
}
|
|
60
|
+
process.exit(0);
|
|
61
|
+
});
|
package/scripts/postinstall.js
CHANGED
|
@@ -29,27 +29,11 @@ try {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// Fix clawtrial CLI symlink if needed
|
|
32
|
+
// Get package paths
|
|
35
33
|
const packagePath = path.join(__dirname, '..');
|
|
36
34
|
const cliPath = path.join(packagePath, 'scripts', 'clawtrial.js');
|
|
37
|
-
const globalBinPath = '/usr/bin/clawtrial';
|
|
38
|
-
|
|
39
|
-
if (fs.existsSync(globalBinPath)) {
|
|
40
|
-
try {
|
|
41
|
-
const currentTarget = fs.readlinkSync(globalBinPath);
|
|
42
|
-
const expectedTarget = cliPath;
|
|
43
|
-
|
|
44
|
-
if (currentTarget !== expectedTarget && !currentTarget.includes('@clawtrial')) {
|
|
45
|
-
console.log('🔗 Fixing clawtrial CLI symlink...');
|
|
46
|
-
try {
|
|
47
|
-
fs.unlinkSync(globalBinPath);
|
|
48
|
-
fs.symlinkSync(cliPath, globalBinPath);
|
|
49
|
-
fs.chmodSync(globalBinPath, 0o755);
|
|
50
|
-
console.log('✓ CLI symlink fixed');
|
|
51
35
|
|
|
52
|
-
//
|
|
36
|
+
// Try to create /usr/bin symlink (requires sudo, may fail)
|
|
53
37
|
const usrBinPath = '/usr/bin/clawtrial';
|
|
54
38
|
if (!fs.existsSync(usrBinPath)) {
|
|
55
39
|
try {
|
|
@@ -57,18 +41,7 @@ if (!fs.existsSync(usrBinPath)) {
|
|
|
57
41
|
fs.chmodSync(usrBinPath, 0o755);
|
|
58
42
|
console.log('✓ Created global CLI symlink');
|
|
59
43
|
} catch (err) {
|
|
60
|
-
|
|
61
|
-
console.log(' Run: sudo ln -sf ' + cliPath + ' ' + usrBinPath);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
} catch (err) {
|
|
66
|
-
console.log('⚠️ Could not fix CLI symlink (may need sudo)');
|
|
67
|
-
console.log(' Run: sudo ln -sf ' + cliPath + ' ' + globalBinPath);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
} catch (e) {
|
|
71
|
-
// Not a symlink, ignore
|
|
44
|
+
// Silent fail - will show instructions at end
|
|
72
45
|
}
|
|
73
46
|
}
|
|
74
47
|
|
|
@@ -83,8 +56,6 @@ if (fs.existsSync(configPath)) {
|
|
|
83
56
|
fs.mkdirSync(SKILLS_DIR, { recursive: true });
|
|
84
57
|
}
|
|
85
58
|
|
|
86
|
-
// Get package path
|
|
87
|
-
const packagePath = path.join(__dirname, '..');
|
|
88
59
|
const skillLinkPath = path.join(SKILLS_DIR, 'courtroom');
|
|
89
60
|
|
|
90
61
|
// Remove old link
|
|
@@ -95,10 +66,19 @@ if (fs.existsSync(configPath)) {
|
|
|
95
66
|
// Create symlink
|
|
96
67
|
fs.symlinkSync(packagePath, skillLinkPath, 'junction');
|
|
97
68
|
console.log('✓ Registered as ClawDBot skill');
|
|
98
|
-
console.log(' Restart ClawDBot to activate');
|
|
99
69
|
} catch (err) {
|
|
100
70
|
console.log('⚠️ Could not register skill:', err.message);
|
|
101
71
|
}
|
|
102
72
|
}
|
|
103
73
|
|
|
74
|
+
// Show next steps
|
|
75
|
+
console.log('');
|
|
76
|
+
console.log('📋 Next Steps:');
|
|
77
|
+
console.log(' 1. If "clawtrial" command not found, run:');
|
|
78
|
+
console.log(' export PATH="$HOME/.npm-global/bin:$PATH"');
|
|
79
|
+
console.log(' # OR: sudo ln -sf "$HOME/.npm-global/lib/node_modules/@clawtrial/courtroom/scripts/clawtrial.js" /usr/bin/clawtrial');
|
|
80
|
+
console.log('');
|
|
81
|
+
console.log(' 2. Run setup:');
|
|
82
|
+
console.log(' clawtrial setup');
|
|
83
|
+
console.log(' clawtrial start');
|
|
104
84
|
console.log('');
|