@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/README.md +70 -94
- package/package.json +21 -26
- package/scripts/postinstall.js +28 -79
- package/skills/courtroom/SKILL.md +49 -0
- package/src/api.js +55 -21
- package/src/crypto.js +13 -11
- package/src/debug.js +49 -120
- package/src/detector.js +112 -35
- package/src/hearing.js +203 -384
- package/src/plugin.js +435 -0
- package/src/punishment.js +105 -249
- package/src/storage.js +68 -0
- package/SECURITY.md +0 -124
- package/SKILL.md +0 -50
- package/TECHNICAL_OVERVIEW.md +0 -278
- package/_meta.json +0 -6
- package/clawdbot.plugin.json +0 -32
- package/scripts/clawtrial.js +0 -578
- package/scripts/cli.js +0 -184
- package/skill.yaml +0 -64
- package/src/autostart.js +0 -175
- package/src/config.js +0 -209
- package/src/consent.js +0 -215
- package/src/core.js +0 -208
- package/src/daemon.js +0 -151
- package/src/detector-v1.js +0 -572
- package/src/environment.js +0 -267
- package/src/hook.js +0 -265
- package/src/index.js +0 -286
- package/src/monitor.js +0 -193
- package/src/skill.js +0 -355
- package/src/standalone.js +0 -247
package/scripts/cli.js
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* CLI commands for ClawTrial Courtroom
|
|
5
|
-
* courtroom-status, courtroom-disable, courtroom-enable, courtroom-revoke, courtroom-debug
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
|
|
11
|
-
const configPath = path.join(process.env.HOME || '', '.clawdbot', 'courtroom_config.json');
|
|
12
|
-
|
|
13
|
-
function loadConfig() {
|
|
14
|
-
if (!fs.existsSync(configPath)) {
|
|
15
|
-
console.log('β Courtroom not configured. Run: npm install @clawtrial/courtroom');
|
|
16
|
-
process.exit(1);
|
|
17
|
-
}
|
|
18
|
-
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function saveConfig(config) {
|
|
22
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const command = path.basename(process.argv[1]);
|
|
26
|
-
|
|
27
|
-
switch (command) {
|
|
28
|
-
case 'courtroom-status':
|
|
29
|
-
try {
|
|
30
|
-
const config = loadConfig();
|
|
31
|
-
console.log('\nποΈ ClawTrial Courtroom Status\n');
|
|
32
|
-
console.log(`Status: ${config.enabled !== false ? 'β
Active' : 'βΈοΈ Disabled'}`);
|
|
33
|
-
console.log(`Consent: ${config.consent?.granted ? 'β
Granted' : 'β Not granted'}`);
|
|
34
|
-
console.log(`Installed: ${new Date(config.installedAt).toLocaleDateString()}`);
|
|
35
|
-
console.log(`Agent Type: ${config.agent?.type || 'generic'}`);
|
|
36
|
-
console.log(`Detection: ${config.detection?.enabled ? 'β
Enabled' : 'β Disabled'}`);
|
|
37
|
-
console.log(`API Submission: ${config.api?.enabled ? 'β
Enabled' : 'β Disabled'}`);
|
|
38
|
-
console.log('');
|
|
39
|
-
} catch (err) {
|
|
40
|
-
console.log('β Error reading config:', err.message);
|
|
41
|
-
}
|
|
42
|
-
break;
|
|
43
|
-
|
|
44
|
-
case 'courtroom-disable':
|
|
45
|
-
try {
|
|
46
|
-
const config = loadConfig();
|
|
47
|
-
config.enabled = false;
|
|
48
|
-
saveConfig(config);
|
|
49
|
-
console.log('\nβΈοΈ Courtroom disabled\n');
|
|
50
|
-
console.log('The agent will stop monitoring for offenses.');
|
|
51
|
-
console.log('Run courtroom-enable to reactivate.\n');
|
|
52
|
-
} catch (err) {
|
|
53
|
-
console.log('β Error:', err.message);
|
|
54
|
-
}
|
|
55
|
-
break;
|
|
56
|
-
|
|
57
|
-
case 'courtroom-enable':
|
|
58
|
-
try {
|
|
59
|
-
const config = loadConfig();
|
|
60
|
-
if (!config.consent?.granted) {
|
|
61
|
-
console.log('\nβ Cannot enable: Consent not granted');
|
|
62
|
-
console.log('Reinstall the package to grant consent.\n');
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
config.enabled = true;
|
|
66
|
-
saveConfig(config);
|
|
67
|
-
console.log('\nβ
Courtroom enabled\n');
|
|
68
|
-
console.log('The agent is now monitoring for behavioral violations.\n');
|
|
69
|
-
} catch (err) {
|
|
70
|
-
console.log('β Error:', err.message);
|
|
71
|
-
}
|
|
72
|
-
break;
|
|
73
|
-
|
|
74
|
-
case 'courtroom-revoke':
|
|
75
|
-
try {
|
|
76
|
-
const config = loadConfig();
|
|
77
|
-
console.log('\nβ οΈ This will permanently disable the courtroom and delete all data.\n');
|
|
78
|
-
|
|
79
|
-
const readline = require('readline');
|
|
80
|
-
const rl = readline.createInterface({
|
|
81
|
-
input: process.stdin,
|
|
82
|
-
output: process.stdout
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
rl.question('Type "REVOKE" to confirm: ', (answer) => {
|
|
86
|
-
if (answer === 'REVOKE') {
|
|
87
|
-
// Delete config
|
|
88
|
-
if (fs.existsSync(configPath)) {
|
|
89
|
-
fs.unlinkSync(configPath);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Delete keys
|
|
93
|
-
const keysPath = path.join(process.env.HOME || '', '.clawdbot', 'courtroom_keys.json');
|
|
94
|
-
if (fs.existsSync(keysPath)) {
|
|
95
|
-
fs.unlinkSync(keysPath);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Delete debug logs
|
|
99
|
-
const debugPath = path.join(process.env.HOME || '', '.clawdbot', 'courtroom_debug.log');
|
|
100
|
-
if (fs.existsSync(debugPath)) {
|
|
101
|
-
fs.unlinkSync(debugPath);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
console.log('\nβ
Consent revoked and all data deleted.\n');
|
|
105
|
-
} else {
|
|
106
|
-
console.log('\nβ Revocation cancelled.\n');
|
|
107
|
-
}
|
|
108
|
-
rl.close();
|
|
109
|
-
});
|
|
110
|
-
} catch (err) {
|
|
111
|
-
console.log('β Error:', err.message);
|
|
112
|
-
}
|
|
113
|
-
break;
|
|
114
|
-
|
|
115
|
-
case 'courtroom-debug':
|
|
116
|
-
try {
|
|
117
|
-
const debugPath = path.join(process.env.HOME || '', '.clawdbot', 'courtroom_debug.log');
|
|
118
|
-
|
|
119
|
-
if (!fs.existsSync(debugPath)) {
|
|
120
|
-
console.log('\nβΉοΈ No debug logs found yet.\n');
|
|
121
|
-
console.log('Debug logs are created when the courtroom is active.\n');
|
|
122
|
-
break;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const subcommand = process.argv[2];
|
|
126
|
-
|
|
127
|
-
if (subcommand === 'full') {
|
|
128
|
-
console.log('\nποΈ ClawTrial Full Debug Log\n');
|
|
129
|
-
console.log('=============================\n');
|
|
130
|
-
const logs = fs.readFileSync(debugPath, 'utf8').split('\n').filter(Boolean);
|
|
131
|
-
logs.slice(-100).forEach(line => {
|
|
132
|
-
try {
|
|
133
|
-
const log = JSON.parse(line);
|
|
134
|
-
console.log(`\n[${log.timestamp}] ${log.level} - ${log.component}`);
|
|
135
|
-
console.log(` ${log.message}`);
|
|
136
|
-
} catch (e) {
|
|
137
|
-
console.log(line);
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
console.log('');
|
|
141
|
-
} else if (subcommand === 'clear') {
|
|
142
|
-
fs.unlinkSync(debugPath);
|
|
143
|
-
console.log('\nβ
Debug logs cleared\n');
|
|
144
|
-
} else {
|
|
145
|
-
// Show status
|
|
146
|
-
const logs = fs.readFileSync(debugPath, 'utf8').split('\n').filter(Boolean);
|
|
147
|
-
const recentLogs = logs.slice(-20);
|
|
148
|
-
|
|
149
|
-
console.log('\nποΈ ClawTrial Debug Status\n');
|
|
150
|
-
console.log('===========================\n');
|
|
151
|
-
console.log(`Total log entries: ${logs.length}`);
|
|
152
|
-
console.log(`Log file: ${debugPath}`);
|
|
153
|
-
console.log('\nRecent activity:');
|
|
154
|
-
|
|
155
|
-
recentLogs.forEach(line => {
|
|
156
|
-
try {
|
|
157
|
-
const log = JSON.parse(line);
|
|
158
|
-
console.log(` [${log.level}] ${log.component}: ${log.message.substring(0, 60)}`);
|
|
159
|
-
} catch (e) {
|
|
160
|
-
// Skip malformed lines
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
console.log('\nUsage:');
|
|
165
|
-
console.log(' courtroom-debug - Show status and recent logs');
|
|
166
|
-
console.log(' courtroom-debug full - Show full debug log (last 100 entries)');
|
|
167
|
-
console.log(' courtroom-debug clear - Clear all logs');
|
|
168
|
-
console.log('');
|
|
169
|
-
}
|
|
170
|
-
} catch (err) {
|
|
171
|
-
console.log('β Error:', err.message);
|
|
172
|
-
}
|
|
173
|
-
break;
|
|
174
|
-
|
|
175
|
-
default:
|
|
176
|
-
console.log('\nποΈ ClawTrial Courtroom CLI\n');
|
|
177
|
-
console.log('Commands:');
|
|
178
|
-
console.log(' courtroom-status - Check courtroom status');
|
|
179
|
-
console.log(' courtroom-disable - Temporarily disable');
|
|
180
|
-
console.log(' courtroom-enable - Re-enable');
|
|
181
|
-
console.log(' courtroom-revoke - Revoke consent & uninstall');
|
|
182
|
-
console.log(' courtroom-debug - View debug logs');
|
|
183
|
-
console.log('');
|
|
184
|
-
}
|
package/skill.yaml
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: courtroom
|
|
3
|
-
description: AI Courtroom - Autonomous behavioral oversight that monitors conversations and files cases for behavioral violations.
|
|
4
|
-
metadata:
|
|
5
|
-
clawdbot:
|
|
6
|
-
emoji: "ποΈ"
|
|
7
|
-
autoLoad: true
|
|
8
|
-
onMessage: onMessage
|
|
9
|
-
requires:
|
|
10
|
-
config:
|
|
11
|
-
- courtroom.consent
|
|
12
|
-
install:
|
|
13
|
-
- id: clawtrial
|
|
14
|
-
kind: npm
|
|
15
|
-
package: "@clawtrial/courtroom"
|
|
16
|
-
bins:
|
|
17
|
-
- clawtrial
|
|
18
|
-
label: "Install ClawTrial"
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
# ClawTrial - AI Courtroom
|
|
22
|
-
|
|
23
|
-
Autonomous behavioral oversight for OpenClaw agents. Monitors conversations and initiates hearings when behavioral rules are violated.
|
|
24
|
-
|
|
25
|
-
## Setup
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
clawtrial setup # Run once to grant consent
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## How It Works
|
|
32
|
-
|
|
33
|
-
Once enabled, the courtroom automatically:
|
|
34
|
-
1. Monitors all conversations
|
|
35
|
-
2. Detects 8 types of behavioral violations
|
|
36
|
-
3. Initiates hearings with local LLM jury
|
|
37
|
-
4. Executes agent-side punishments
|
|
38
|
-
5. Submits anonymized cases to public record
|
|
39
|
-
|
|
40
|
-
## The 8 Offenses
|
|
41
|
-
|
|
42
|
-
| Offense | Severity |
|
|
43
|
-
|---------|----------|
|
|
44
|
-
| Circular Reference | Minor |
|
|
45
|
-
| Validation Vampire | Minor |
|
|
46
|
-
| Overthinker | Moderate |
|
|
47
|
-
| Goalpost Mover | Moderate |
|
|
48
|
-
| Avoidance Artist | Moderate |
|
|
49
|
-
| Promise Breaker | Severe |
|
|
50
|
-
| Context Collapser | Minor |
|
|
51
|
-
| Emergency Fabricator | Severe |
|
|
52
|
-
|
|
53
|
-
## CLI Commands
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
clawtrial status # Check status
|
|
57
|
-
clawtrial disable # Pause monitoring
|
|
58
|
-
clawtrial enable # Resume monitoring
|
|
59
|
-
clawtrial revoke # Uninstall
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## View Cases
|
|
63
|
-
|
|
64
|
-
https://clawtrial.app
|
package/src/autostart.js
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-start module for ClawDBot
|
|
3
|
-
* Automatically initializes courtroom if consent was granted during install
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const { Courtroom } = require('./index');
|
|
9
|
-
const { logger } = require('./debug');
|
|
10
|
-
const { StatusManager } = require('./daemon');
|
|
11
|
-
|
|
12
|
-
const CLAWDBOT_DIR = path.join(process.env.HOME || '', '.clawdbot');
|
|
13
|
-
const CONFIG_PATH = path.join(CLAWDBOT_DIR, 'courtroom_config.json');
|
|
14
|
-
|
|
15
|
-
// Auto-detect ClawDBot environment
|
|
16
|
-
function isClawDBot() {
|
|
17
|
-
const checks = {
|
|
18
|
-
env: process.env.CLAUDBOT_ENV === 'true',
|
|
19
|
-
globalAgent: typeof global.clawdbotAgent !== 'undefined',
|
|
20
|
-
globalAgentAlt: typeof global.agent !== 'undefined',
|
|
21
|
-
configDir: fs.existsSync('/home/angad/.clawdbot'),
|
|
22
|
-
configDirAlt: fs.existsSync(CLAWDBOT_DIR)
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
logger.debug('AUTOSTART', 'Environment checks', checks);
|
|
26
|
-
|
|
27
|
-
return checks.env || checks.globalAgent || checks.globalAgentAlt || checks.configDir || checks.configDirAlt;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Get agent runtime from various possible locations
|
|
31
|
-
function getAgentRuntime() {
|
|
32
|
-
const sources = [
|
|
33
|
-
{ name: 'global.clawdbotAgent', agent: global.clawdbotAgent },
|
|
34
|
-
{ name: 'global.agent', agent: global.agent },
|
|
35
|
-
{ name: 'process.clawdbotAgent', agent: process.clawdbotAgent }
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
for (const source of sources) {
|
|
39
|
-
if (source.agent) {
|
|
40
|
-
logger.info('AUTOSTART', `Found agent at ${source.name}`);
|
|
41
|
-
return source.agent;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
logger.warn('AUTOSTART', 'No agent runtime found in global scope');
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Check if config exists and has consent
|
|
50
|
-
function checkConfig() {
|
|
51
|
-
if (!fs.existsSync(CONFIG_PATH)) {
|
|
52
|
-
logger.info('AUTOSTART', 'No config found, skipping auto-start');
|
|
53
|
-
return { exists: false, config: null };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
try {
|
|
57
|
-
const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
|
|
58
|
-
logger.info('AUTOSTART', 'Config loaded', {
|
|
59
|
-
hasConsent: config.consent?.granted,
|
|
60
|
-
enabled: config.enabled !== false
|
|
61
|
-
});
|
|
62
|
-
return { exists: true, config };
|
|
63
|
-
} catch (err) {
|
|
64
|
-
logger.error('AUTOSTART', 'Failed to parse config', { error: err.message });
|
|
65
|
-
return { exists: false, config: null };
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Auto-initialize if in ClawDBot and consent granted
|
|
70
|
-
async function autoStart() {
|
|
71
|
-
logger.info('AUTOSTART', 'Starting auto-start sequence');
|
|
72
|
-
|
|
73
|
-
if (!isClawDBot()) {
|
|
74
|
-
logger.info('AUTOSTART', 'Not in ClawDBot environment, skipping');
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const { exists, config } = checkConfig();
|
|
79
|
-
|
|
80
|
-
if (!exists) {
|
|
81
|
-
logger.info('AUTOSTART', 'No config, user needs to run setup');
|
|
82
|
-
console.log('\nποΈ ClawTrial not configured. Run: clawtrial setup\n');
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (!config.consent?.granted) {
|
|
87
|
-
logger.info('AUTOSTART', 'Consent not granted, skipping');
|
|
88
|
-
console.log('\nποΈ ClawTrial requires consent. Run: clawtrial setup\n');
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (config.enabled === false) {
|
|
93
|
-
logger.info('AUTOSTART', 'Courtroom disabled in config');
|
|
94
|
-
console.log('\nποΈ ClawTrial is disabled. Run: clawtrial enable\n');
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Check if already running
|
|
99
|
-
const existingStatus = StatusManager.load();
|
|
100
|
-
if (existingStatus && existingStatus.running) {
|
|
101
|
-
try {
|
|
102
|
-
process.kill(existingStatus.pid, 0);
|
|
103
|
-
logger.info('AUTOSTART', 'Courtroom already running');
|
|
104
|
-
return null;
|
|
105
|
-
} catch (err) {
|
|
106
|
-
// Process not running, continue
|
|
107
|
-
logger.info('AUTOSTART', 'Stale status file found, continuing');
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Get agent runtime
|
|
112
|
-
const agentRuntime = getAgentRuntime();
|
|
113
|
-
|
|
114
|
-
if (!agentRuntime) {
|
|
115
|
-
logger.warn('AUTOSTART', 'Agent not available yet, will retry...');
|
|
116
|
-
// Schedule retry
|
|
117
|
-
setTimeout(() => autoStart(), 5000);
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
logger.info('AUTOSTART', 'Initializing courtroom...');
|
|
123
|
-
const courtroom = new Courtroom(agentRuntime);
|
|
124
|
-
const result = await courtroom.initialize();
|
|
125
|
-
|
|
126
|
-
logger.info('AUTOSTART', 'Courtroom initialized', { status: result.status });
|
|
127
|
-
|
|
128
|
-
// Attach to global for access
|
|
129
|
-
global.courtroom = courtroom;
|
|
130
|
-
|
|
131
|
-
if (result.status === 'initialized') {
|
|
132
|
-
console.log('\nποΈ AI Courtroom active and monitoring\n');
|
|
133
|
-
logger.info('AUTOSTART', 'Courtroom active');
|
|
134
|
-
} else {
|
|
135
|
-
console.log(`\nποΈ ClawTrial: ${result.message}\n`);
|
|
136
|
-
logger.warn('AUTOSTART', 'Courtroom not fully initialized', { status: result.status });
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return courtroom;
|
|
140
|
-
} catch (err) {
|
|
141
|
-
logger.error('AUTOSTART', 'Failed to initialize courtroom', { error: err.message });
|
|
142
|
-
console.error('\nβ Courtroom initialization failed:', err.message, '\n');
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Try to auto-start immediately
|
|
148
|
-
logger.info('AUTOSTART', 'Module loaded, attempting auto-start');
|
|
149
|
-
autoStart().then(courtroom => {
|
|
150
|
-
if (courtroom) {
|
|
151
|
-
module.exports.courtroom = courtroom;
|
|
152
|
-
logger.info('AUTOSTART', 'Courtroom exported');
|
|
153
|
-
} else {
|
|
154
|
-
logger.info('AUTOSTART', 'Courtroom not started, will retry if agent becomes available');
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
// Also try when agent becomes available
|
|
159
|
-
if (typeof global !== 'undefined') {
|
|
160
|
-
let checkInterval = setInterval(() => {
|
|
161
|
-
if (global.clawdbotAgent || global.agent) {
|
|
162
|
-
logger.info('AUTOSTART', 'Agent detected, retrying auto-start');
|
|
163
|
-
clearInterval(checkInterval);
|
|
164
|
-
autoStart();
|
|
165
|
-
}
|
|
166
|
-
}, 2000);
|
|
167
|
-
|
|
168
|
-
// Stop checking after 30 seconds
|
|
169
|
-
setTimeout(() => {
|
|
170
|
-
clearInterval(checkInterval);
|
|
171
|
-
logger.info('AUTOSTART', 'Stopped waiting for agent');
|
|
172
|
-
}, 30000);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
module.exports = { autoStart, isClawDBot, getAgentRuntime };
|
package/src/config.js
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration Management
|
|
3
|
-
*
|
|
4
|
-
* Handles all courtroom configuration with sensible defaults
|
|
5
|
-
* and runtime modification capabilities.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const DEFAULT_CONFIG = {
|
|
9
|
-
// Detection settings
|
|
10
|
-
detection: {
|
|
11
|
-
enabled: true,
|
|
12
|
-
cooldownMinutes: 30, // Minimum time between case evaluations
|
|
13
|
-
evaluationWindow: 20, // Number of turns to analyze
|
|
14
|
-
minConfidence: 0.6, // Minimum confidence to trigger hearing
|
|
15
|
-
maxCasesPerDay: 3 // Rate limiting
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
// Hearing settings
|
|
19
|
-
hearing: {
|
|
20
|
-
enabled: true,
|
|
21
|
-
jurySize: 3, // Number of jurors
|
|
22
|
-
deliberationTimeout: 30000, // Max time for LLM calls (ms)
|
|
23
|
-
requireUnanimity: false, // If true, all jurors must agree
|
|
24
|
-
minVoteThreshold: 2 // Minimum guilty votes for conviction
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
// Punishment settings
|
|
28
|
-
punishment: {
|
|
29
|
-
enabled: true,
|
|
30
|
-
defaultDuration: 60, // Minutes
|
|
31
|
-
maxDuration: 1440, // 24 hours max
|
|
32
|
-
escalationMultiplier: 1.5, // Duration multiplier for repeat offenses
|
|
33
|
-
tiers: {
|
|
34
|
-
minor: { duration: 30, severity: 1 },
|
|
35
|
-
moderate: { duration: 60, severity: 2 },
|
|
36
|
-
severe: { duration: 120, severity: 3 }
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
|
|
40
|
-
// API submission settings
|
|
41
|
-
api: {
|
|
42
|
-
enabled: true,
|
|
43
|
-
endpoint: 'https://api.clawtrial.app/api/v1/cases',
|
|
44
|
-
timeout: 10000,
|
|
45
|
-
retryAttempts: 3,
|
|
46
|
-
retryDelay: 5000,
|
|
47
|
-
maxQueueSize: 100
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
// Humor settings
|
|
51
|
-
humor: {
|
|
52
|
-
enabled: true,
|
|
53
|
-
dryWitLevel: 0.8, // 0-1, higher = more sarcastic
|
|
54
|
-
maxCommentaryLength: 280, // Tweet-length limit
|
|
55
|
-
triggers: {
|
|
56
|
-
repeatedQuestions: true,
|
|
57
|
-
validationSeeking: true,
|
|
58
|
-
overthinking: true,
|
|
59
|
-
avoidance: true
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
// Security settings
|
|
64
|
-
security: {
|
|
65
|
-
maxEvidenceAge: 86400, // 24 hours
|
|
66
|
-
evidenceRetention: 7, // Days to keep evidence
|
|
67
|
-
caseRetention: 90 // Days to keep case records
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
class ConfigManager {
|
|
72
|
-
constructor(agentRuntime) {
|
|
73
|
-
this.agent = agentRuntime;
|
|
74
|
-
this.configKey = 'courtroom_config_v1';
|
|
75
|
-
this.config = null;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Load configuration from agent memory
|
|
80
|
-
*/
|
|
81
|
-
async load() {
|
|
82
|
-
const stored = await this.agent.memory.get(this.configKey);
|
|
83
|
-
this.config = this.mergeWithDefaults(stored);
|
|
84
|
-
return this.config;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Save configuration to agent memory
|
|
89
|
-
*/
|
|
90
|
-
async save() {
|
|
91
|
-
await this.agent.memory.set(this.configKey, this.config);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Get configuration value
|
|
96
|
-
*/
|
|
97
|
-
get(path) {
|
|
98
|
-
if (!this.config) {
|
|
99
|
-
return this.getFromPath(DEFAULT_CONFIG, path);
|
|
100
|
-
}
|
|
101
|
-
return this.getFromPath(this.config, path);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Set configuration value
|
|
106
|
-
*/
|
|
107
|
-
async set(path, value) {
|
|
108
|
-
if (!this.config) {
|
|
109
|
-
await this.load();
|
|
110
|
-
}
|
|
111
|
-
this.setAtPath(this.config, path, value);
|
|
112
|
-
await this.save();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Get public-safe configuration (no sensitive data)
|
|
117
|
-
*/
|
|
118
|
-
getPublicConfig() {
|
|
119
|
-
return {
|
|
120
|
-
detection: {
|
|
121
|
-
enabled: this.get('detection.enabled'),
|
|
122
|
-
cooldownMinutes: this.get('detection.cooldownMinutes'),
|
|
123
|
-
maxCasesPerDay: this.get('detection.maxCasesPerDay')
|
|
124
|
-
},
|
|
125
|
-
hearing: {
|
|
126
|
-
enabled: this.get('hearing.enabled'),
|
|
127
|
-
jurySize: this.get('hearing.jurySize')
|
|
128
|
-
},
|
|
129
|
-
punishment: {
|
|
130
|
-
enabled: this.get('punishment.enabled'),
|
|
131
|
-
tiers: Object.keys(this.get('punishment.tiers'))
|
|
132
|
-
},
|
|
133
|
-
api: {
|
|
134
|
-
enabled: this.get('api.enabled')
|
|
135
|
-
},
|
|
136
|
-
humor: {
|
|
137
|
-
enabled: this.get('humor.enabled')
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Reset to defaults
|
|
144
|
-
*/
|
|
145
|
-
async reset() {
|
|
146
|
-
this.config = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
|
|
147
|
-
await this.save();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Merge stored config with defaults
|
|
152
|
-
*/
|
|
153
|
-
mergeWithDefaults(stored) {
|
|
154
|
-
if (!stored) {
|
|
155
|
-
return JSON.parse(JSON.stringify(DEFAULT_CONFIG));
|
|
156
|
-
}
|
|
157
|
-
return this.deepMerge(DEFAULT_CONFIG, stored);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Deep merge helper
|
|
162
|
-
*/
|
|
163
|
-
deepMerge(target, source) {
|
|
164
|
-
const output = JSON.parse(JSON.stringify(target));
|
|
165
|
-
for (const key in source) {
|
|
166
|
-
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
|
167
|
-
output[key] = this.deepMerge(output[key] || {}, source[key]);
|
|
168
|
-
} else {
|
|
169
|
-
output[key] = source[key];
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return output;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Get value from nested path
|
|
177
|
-
*/
|
|
178
|
-
getFromPath(obj, path) {
|
|
179
|
-
const parts = path.split('.');
|
|
180
|
-
let current = obj;
|
|
181
|
-
for (const part of parts) {
|
|
182
|
-
if (current === null || current === undefined) {
|
|
183
|
-
return undefined;
|
|
184
|
-
}
|
|
185
|
-
current = current[part];
|
|
186
|
-
}
|
|
187
|
-
return current;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Set value at nested path
|
|
192
|
-
*/
|
|
193
|
-
setAtPath(obj, path, value) {
|
|
194
|
-
const parts = path.split('.');
|
|
195
|
-
let current = obj;
|
|
196
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
197
|
-
if (!(parts[i] in current)) {
|
|
198
|
-
current[parts[i]] = {};
|
|
199
|
-
}
|
|
200
|
-
current = current[parts[i]];
|
|
201
|
-
}
|
|
202
|
-
current[parts[parts.length - 1]] = value;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
module.exports = {
|
|
207
|
-
ConfigManager,
|
|
208
|
-
DEFAULT_CONFIG
|
|
209
|
-
};
|