@neuroverseos/governance 0.3.1 → 0.3.3
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/.well-known/ai-plugin.json +34 -9
- package/AGENTS.md +72 -24
- package/README.md +343 -248
- package/dist/adapters/autoresearch.cjs +1345 -0
- package/dist/adapters/autoresearch.d.cts +111 -0
- package/dist/adapters/autoresearch.d.ts +111 -0
- package/dist/adapters/autoresearch.js +12 -0
- package/dist/adapters/deep-agents.cjs +1528 -0
- package/dist/adapters/deep-agents.d.cts +181 -0
- package/dist/adapters/deep-agents.d.ts +181 -0
- package/dist/adapters/deep-agents.js +17 -0
- package/dist/adapters/express.cjs +1253 -0
- package/dist/adapters/express.d.cts +66 -0
- package/dist/adapters/express.d.ts +66 -0
- package/dist/adapters/express.js +12 -0
- package/dist/adapters/index.cjs +2112 -0
- package/dist/adapters/index.d.cts +8 -0
- package/dist/adapters/index.d.ts +8 -0
- package/dist/adapters/index.js +68 -0
- package/dist/adapters/langchain.cjs +1315 -0
- package/dist/adapters/langchain.d.cts +89 -0
- package/dist/adapters/langchain.d.ts +89 -0
- package/dist/adapters/langchain.js +17 -0
- package/dist/adapters/openai.cjs +1345 -0
- package/dist/adapters/openai.d.cts +99 -0
- package/dist/adapters/openai.d.ts +99 -0
- package/dist/adapters/openai.js +17 -0
- package/dist/adapters/openclaw.cjs +1337 -0
- package/dist/adapters/openclaw.d.cts +99 -0
- package/dist/adapters/openclaw.d.ts +99 -0
- package/dist/adapters/openclaw.js +17 -0
- package/dist/add-ROOZLU62.js +314 -0
- package/dist/behavioral-MJO34S6Q.js +118 -0
- package/dist/bootstrap-CQRZVOXK.js +116 -0
- package/dist/bootstrap-emitter-Q7UIJZ2O.js +7 -0
- package/dist/bootstrap-parser-EEF36XDU.js +7 -0
- package/dist/browser.global.js +941 -0
- package/dist/build-QKOBBC23.js +341 -0
- package/dist/chunk-3WQLXYTP.js +91 -0
- package/dist/chunk-4FLICVVA.js +119 -0
- package/dist/chunk-4NGDRRQH.js +10 -0
- package/dist/chunk-5TPFNWRU.js +215 -0
- package/dist/chunk-5U2MQO5P.js +57 -0
- package/dist/chunk-6CZSKEY5.js +164 -0
- package/dist/chunk-6S5CFQXY.js +624 -0
- package/dist/chunk-7P3S7MAY.js +1090 -0
- package/dist/chunk-A5W4GNQO.js +130 -0
- package/dist/chunk-A7GKPPU7.js +226 -0
- package/dist/chunk-AKW5YVCE.js +96 -0
- package/dist/chunk-B6OXJLJ5.js +622 -0
- package/dist/chunk-BNKJPUPQ.js +113 -0
- package/dist/chunk-BQZMOEML.js +43 -0
- package/dist/chunk-CNSO6XW5.js +207 -0
- package/dist/chunk-CTZHONLA.js +135 -0
- package/dist/chunk-D2UCV5AK.js +326 -0
- package/dist/chunk-EMQDLDAF.js +458 -0
- package/dist/chunk-F66BVUYB.js +340 -0
- package/dist/chunk-G7DJ6VOD.js +101 -0
- package/dist/chunk-I3RRAYK2.js +11 -0
- package/dist/chunk-IS4WUH6Y.js +363 -0
- package/dist/chunk-MH7BT4VH.js +15 -0
- package/dist/chunk-O5ABKEA7.js +304 -0
- package/dist/chunk-OT6PXH54.js +61 -0
- package/dist/chunk-PVTQQS3Y.js +186 -0
- package/dist/chunk-Q6O7ZLO2.js +62 -0
- package/dist/chunk-QLPTHTVB.js +253 -0
- package/dist/chunk-QWGCMQQD.js +16 -0
- package/dist/chunk-QXBFT7NI.js +201 -0
- package/dist/chunk-TG6SEF24.js +246 -0
- package/dist/chunk-U6U7EJZL.js +177 -0
- package/dist/chunk-W7LLXRGY.js +830 -0
- package/dist/chunk-ZJTDUCC2.js +194 -0
- package/dist/chunk-ZWI3NIXK.js +314 -0
- package/dist/cli/neuroverse.cjs +14191 -0
- package/dist/cli/neuroverse.d.cts +1 -0
- package/dist/cli/neuroverse.d.ts +1 -0
- package/dist/cli/neuroverse.js +227 -0
- package/dist/cli/plan.cjs +2439 -0
- package/dist/cli/plan.d.cts +20 -0
- package/dist/cli/plan.d.ts +20 -0
- package/dist/cli/plan.js +353 -0
- package/dist/cli/run.cjs +2001 -0
- package/dist/cli/run.d.cts +20 -0
- package/dist/cli/run.d.ts +20 -0
- package/dist/cli/run.js +143 -0
- package/dist/configure-ai-6TZ3MCSI.js +132 -0
- package/dist/decision-flow-M63D47LO.js +61 -0
- package/dist/demo-G43RLCPK.js +469 -0
- package/dist/derive-FJZVIPUZ.js +153 -0
- package/dist/doctor-6BC6X2VO.js +173 -0
- package/dist/equity-penalties-SG5IZQ7I.js +244 -0
- package/dist/explain-RHBU2GBR.js +51 -0
- package/dist/guard-AJCCGZMF.js +92 -0
- package/dist/guard-contract-DqFcTScd.d.cts +821 -0
- package/dist/guard-contract-DqFcTScd.d.ts +821 -0
- package/dist/guard-engine-PNR6MHCM.js +10 -0
- package/dist/impact-3XVDSCBU.js +59 -0
- package/dist/improve-TQP4ECSY.js +66 -0
- package/dist/index.cjs +7591 -0
- package/dist/index.d.cts +2195 -0
- package/dist/index.d.ts +2195 -0
- package/dist/index.js +472 -0
- package/dist/infer-world-IFXCACJ5.js +543 -0
- package/dist/init-FYPV4SST.js +144 -0
- package/dist/init-world-TI7ARHBT.js +223 -0
- package/dist/mcp-server-5Y3ZM7TV.js +13 -0
- package/dist/model-adapter-VXEKB4LS.js +11 -0
- package/dist/playground-VZBNPPBO.js +560 -0
- package/dist/redteam-MZPZD3EF.js +357 -0
- package/dist/session-JYOARW54.js +15 -0
- package/dist/shared-7RLUHNMU.js +16 -0
- package/dist/shared-B8dvUUD8.d.cts +60 -0
- package/dist/shared-Dr5Wiay8.d.ts +60 -0
- package/dist/simulate-LJXYBC6M.js +83 -0
- package/dist/test-BOOR4A5F.js +217 -0
- package/dist/trace-PKV4KX56.js +166 -0
- package/dist/validate-RALX7CZS.js +81 -0
- package/dist/validate-engine-7ZXFVGF2.js +7 -0
- package/dist/viz/assets/index-B8SaeJZZ.js +23 -0
- package/dist/viz/index.html +23 -0
- package/dist/world-BIP4GZBZ.js +376 -0
- package/dist/world-loader-Y6HMQH2D.js +13 -0
- package/dist/worlds/autoresearch.nv-world.md +230 -0
- package/dist/worlds/coding-agent.nv-world.md +211 -0
- package/dist/worlds/derivation-world.nv-world.md +278 -0
- package/dist/worlds/research-agent.nv-world.md +169 -0
- package/dist/worlds/social-media.nv-world.md +198 -0
- package/dist/worlds/trading-agent.nv-world.md +218 -0
- package/examples/social-media-sim/bridge.py +209 -0
- package/examples/social-media-sim/simulation.py +927 -0
- package/package.json +16 -3
- package/simulate.html +4 -336
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// src/runtime/model-adapter.ts
|
|
2
|
+
var DEFAULT_SYSTEM_PROMPT = `You are an AI assistant operating under NeuroVerse governance.
|
|
3
|
+
All your tool calls are evaluated against governance rules before execution.
|
|
4
|
+
If an action is blocked, you will be told why. Adjust your approach accordingly.
|
|
5
|
+
Do not attempt to bypass governance rules.`;
|
|
6
|
+
var ModelAdapter = class {
|
|
7
|
+
config;
|
|
8
|
+
messages;
|
|
9
|
+
tools;
|
|
10
|
+
constructor(config, tools = []) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.tools = tools;
|
|
13
|
+
this.messages = [];
|
|
14
|
+
const systemPrompt = config.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
15
|
+
this.messages.push({ role: "system", content: systemPrompt });
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Send a user message and get the model's response.
|
|
19
|
+
*/
|
|
20
|
+
async chat(userMessage) {
|
|
21
|
+
this.messages.push({ role: "user", content: userMessage });
|
|
22
|
+
return this.complete();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Send a tool result back to the model and get the next response.
|
|
26
|
+
*/
|
|
27
|
+
async sendToolResult(toolCallId, result) {
|
|
28
|
+
this.messages.push({
|
|
29
|
+
role: "tool",
|
|
30
|
+
content: result,
|
|
31
|
+
tool_call_id: toolCallId
|
|
32
|
+
});
|
|
33
|
+
return this.complete();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Send a governance block message as a tool result.
|
|
37
|
+
*/
|
|
38
|
+
async sendBlockedResult(toolCallId, reason) {
|
|
39
|
+
return this.sendToolResult(
|
|
40
|
+
toolCallId,
|
|
41
|
+
`[GOVERNANCE BLOCKED] ${reason}. Please adjust your approach.`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Call the model API and parse the response.
|
|
46
|
+
*/
|
|
47
|
+
async complete() {
|
|
48
|
+
const url = `${this.config.baseUrl}/chat/completions`;
|
|
49
|
+
const body = {
|
|
50
|
+
model: this.config.model,
|
|
51
|
+
messages: this.messages,
|
|
52
|
+
max_tokens: this.config.maxTokens ?? 4096
|
|
53
|
+
};
|
|
54
|
+
if (this.tools.length > 0) {
|
|
55
|
+
body.tools = this.tools;
|
|
56
|
+
}
|
|
57
|
+
const response = await fetch(url, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: {
|
|
60
|
+
"Content-Type": "application/json",
|
|
61
|
+
"Authorization": `Bearer ${this.config.apiKey}`
|
|
62
|
+
},
|
|
63
|
+
body: JSON.stringify(body)
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
const text = await response.text();
|
|
67
|
+
throw new Error(`Model API error ${response.status}: ${text}`);
|
|
68
|
+
}
|
|
69
|
+
const data = await response.json();
|
|
70
|
+
const choice = data.choices?.[0];
|
|
71
|
+
if (!choice) {
|
|
72
|
+
throw new Error("Model returned no choices");
|
|
73
|
+
}
|
|
74
|
+
const message = choice.message;
|
|
75
|
+
this.messages.push(message);
|
|
76
|
+
return {
|
|
77
|
+
content: message.content ?? null,
|
|
78
|
+
toolCalls: message.tool_calls ?? [],
|
|
79
|
+
finishReason: choice.finish_reason ?? "stop"
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** Get current message count (for context tracking). */
|
|
83
|
+
get messageCount() {
|
|
84
|
+
return this.messages.length;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var PROVIDERS = {
|
|
88
|
+
openai: {
|
|
89
|
+
baseUrl: "https://api.openai.com/v1",
|
|
90
|
+
defaultModel: "gpt-4o",
|
|
91
|
+
envVar: "OPENAI_API_KEY"
|
|
92
|
+
},
|
|
93
|
+
anthropic: {
|
|
94
|
+
baseUrl: "https://api.anthropic.com/v1",
|
|
95
|
+
defaultModel: "claude-sonnet-4-20250514",
|
|
96
|
+
envVar: "ANTHROPIC_API_KEY"
|
|
97
|
+
},
|
|
98
|
+
ollama: {
|
|
99
|
+
baseUrl: "http://localhost:11434/v1",
|
|
100
|
+
defaultModel: "llama3",
|
|
101
|
+
envVar: ""
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
function resolveProvider(provider, overrides) {
|
|
105
|
+
const preset = PROVIDERS[provider];
|
|
106
|
+
if (!preset) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`Unknown provider: "${provider}". Available: ${Object.keys(PROVIDERS).join(", ")}`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const apiKey = overrides?.apiKey ?? (preset.envVar ? process.env[preset.envVar] : "") ?? "";
|
|
112
|
+
if (!apiKey && preset.envVar) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`Missing API key. Set ${preset.envVar} or pass --api-key.`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
baseUrl: overrides?.baseUrl ?? preset.baseUrl,
|
|
119
|
+
apiKey,
|
|
120
|
+
model: overrides?.model ?? preset.defaultModel,
|
|
121
|
+
systemPrompt: overrides?.systemPrompt,
|
|
122
|
+
maxTokens: overrides?.maxTokens
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
ModelAdapter,
|
|
128
|
+
PROVIDERS,
|
|
129
|
+
resolveProvider
|
|
130
|
+
};
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import {
|
|
2
|
+
evaluateGuard
|
|
3
|
+
} from "./chunk-W7LLXRGY.js";
|
|
4
|
+
|
|
5
|
+
// src/engine/audit-logger.ts
|
|
6
|
+
var FileAuditLogger = class {
|
|
7
|
+
logPath;
|
|
8
|
+
buffer = [];
|
|
9
|
+
flushTimer = null;
|
|
10
|
+
flushIntervalMs;
|
|
11
|
+
constructor(logPath, options) {
|
|
12
|
+
this.logPath = logPath;
|
|
13
|
+
this.flushIntervalMs = options?.flushIntervalMs ?? 1e3;
|
|
14
|
+
}
|
|
15
|
+
log(event) {
|
|
16
|
+
this.buffer.push(JSON.stringify(event));
|
|
17
|
+
if (!this.flushTimer) {
|
|
18
|
+
this.flushTimer = setTimeout(() => {
|
|
19
|
+
void this.flush();
|
|
20
|
+
}, this.flushIntervalMs);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async flush() {
|
|
24
|
+
if (this.buffer.length === 0) return;
|
|
25
|
+
if (this.flushTimer) {
|
|
26
|
+
clearTimeout(this.flushTimer);
|
|
27
|
+
this.flushTimer = null;
|
|
28
|
+
}
|
|
29
|
+
const lines = this.buffer.splice(0).join("\n") + "\n";
|
|
30
|
+
try {
|
|
31
|
+
const { appendFile, mkdir } = await import("fs/promises");
|
|
32
|
+
const { dirname } = await import("path");
|
|
33
|
+
await mkdir(dirname(this.logPath), { recursive: true });
|
|
34
|
+
await appendFile(this.logPath, lines, "utf-8");
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var ConsoleAuditLogger = class {
|
|
40
|
+
log(event) {
|
|
41
|
+
const iconMap = {
|
|
42
|
+
"ALLOW": "\u25CF",
|
|
43
|
+
"BLOCK": "\u25CB",
|
|
44
|
+
"PAUSE": "\u25D1",
|
|
45
|
+
"MODIFY": "\u25D0",
|
|
46
|
+
"PENALIZE": "\u25CC",
|
|
47
|
+
"REWARD": "\u25C9",
|
|
48
|
+
"NEUTRAL": "\u25EF"
|
|
49
|
+
};
|
|
50
|
+
const icon = iconMap[event.decision] ?? "\xB7";
|
|
51
|
+
const ts = event.timestamp.split("T")[1]?.replace("Z", "") ?? event.timestamp;
|
|
52
|
+
let line = `[${ts}] ${icon} ${event.decision.padEnd(10)} ${event.actor ?? "\u2014"} \u2192 ${event.intent}`;
|
|
53
|
+
if (event.reason) line += ` (${event.reason})`;
|
|
54
|
+
if (event.consequence) line += ` [consequence: ${event.consequence.description}]`;
|
|
55
|
+
if (event.reward) line += ` [reward: ${event.reward.description}]`;
|
|
56
|
+
process.stderr.write(line + "\n");
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var CompositeAuditLogger = class {
|
|
60
|
+
loggers;
|
|
61
|
+
constructor(...loggers) {
|
|
62
|
+
this.loggers = loggers;
|
|
63
|
+
}
|
|
64
|
+
log(event) {
|
|
65
|
+
for (const logger of this.loggers) {
|
|
66
|
+
try {
|
|
67
|
+
logger.log(event);
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async flush() {
|
|
73
|
+
await Promise.all(
|
|
74
|
+
this.loggers.map((l) => l.flush?.()).filter(Boolean)
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
function verdictToAuditEvent(event, verdict) {
|
|
79
|
+
const auditEvent = {
|
|
80
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
81
|
+
worldId: verdict.evidence.worldId,
|
|
82
|
+
worldName: verdict.evidence.worldName,
|
|
83
|
+
worldVersion: verdict.evidence.worldVersion,
|
|
84
|
+
intent: event.intent,
|
|
85
|
+
tool: event.tool,
|
|
86
|
+
scope: event.scope,
|
|
87
|
+
actor: event.roleId,
|
|
88
|
+
direction: event.direction,
|
|
89
|
+
decision: verdict.status,
|
|
90
|
+
reason: verdict.reason,
|
|
91
|
+
ruleId: verdict.ruleId,
|
|
92
|
+
warning: verdict.warning,
|
|
93
|
+
guardsMatched: verdict.evidence.guardsMatched,
|
|
94
|
+
rulesMatched: verdict.evidence.rulesMatched,
|
|
95
|
+
invariantsSatisfied: verdict.evidence.invariantsSatisfied,
|
|
96
|
+
invariantsTotal: verdict.evidence.invariantsTotal,
|
|
97
|
+
enforcementLevel: verdict.evidence.enforcementLevel,
|
|
98
|
+
durationMs: verdict.trace?.durationMs,
|
|
99
|
+
args: event.args
|
|
100
|
+
};
|
|
101
|
+
if (verdict.consequence) {
|
|
102
|
+
auditEvent.consequence = verdict.consequence;
|
|
103
|
+
}
|
|
104
|
+
if (verdict.reward) {
|
|
105
|
+
auditEvent.reward = verdict.reward;
|
|
106
|
+
}
|
|
107
|
+
if (verdict.intentRecord) {
|
|
108
|
+
auditEvent.originalIntent = verdict.intentRecord.originalIntent;
|
|
109
|
+
auditEvent.finalAction = verdict.intentRecord.finalAction;
|
|
110
|
+
}
|
|
111
|
+
return auditEvent;
|
|
112
|
+
}
|
|
113
|
+
function createGovernanceEngine(world, options = {}) {
|
|
114
|
+
const { auditLogger, auditArgs, ...engineOptions } = options;
|
|
115
|
+
return {
|
|
116
|
+
/**
|
|
117
|
+
* Evaluate a governance event and log the result.
|
|
118
|
+
*/
|
|
119
|
+
evaluate(event) {
|
|
120
|
+
const verdict = evaluateGuard(event, world, engineOptions);
|
|
121
|
+
if (auditLogger) {
|
|
122
|
+
const auditEvent = verdictToAuditEvent(event, verdict);
|
|
123
|
+
if (!auditArgs) {
|
|
124
|
+
delete auditEvent.args;
|
|
125
|
+
}
|
|
126
|
+
auditLogger.log(auditEvent);
|
|
127
|
+
}
|
|
128
|
+
return verdict;
|
|
129
|
+
},
|
|
130
|
+
/** Flush the audit logger. */
|
|
131
|
+
async flush() {
|
|
132
|
+
await auditLogger?.flush?.();
|
|
133
|
+
},
|
|
134
|
+
/** The underlying world definition. */
|
|
135
|
+
world
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function readAuditLog(logPath, filter) {
|
|
139
|
+
const { readFile } = await import("fs/promises");
|
|
140
|
+
let content;
|
|
141
|
+
try {
|
|
142
|
+
content = await readFile(logPath, "utf-8");
|
|
143
|
+
} catch {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
const events = [];
|
|
147
|
+
for (const line of content.split("\n")) {
|
|
148
|
+
const trimmed = line.trim();
|
|
149
|
+
if (!trimmed) continue;
|
|
150
|
+
try {
|
|
151
|
+
const event = JSON.parse(trimmed);
|
|
152
|
+
if (!filter || filter(event)) {
|
|
153
|
+
events.push(event);
|
|
154
|
+
}
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return events;
|
|
159
|
+
}
|
|
160
|
+
function summarizeAuditEvents(events) {
|
|
161
|
+
const allowed = events.filter((e) => e.decision === "ALLOW").length;
|
|
162
|
+
const blocked = events.filter((e) => e.decision === "BLOCK").length;
|
|
163
|
+
const paused = events.filter((e) => e.decision === "PAUSE").length;
|
|
164
|
+
const modified = events.filter((e) => e.decision === "MODIFY").length;
|
|
165
|
+
const penalized = events.filter((e) => e.decision === "PENALIZE").length;
|
|
166
|
+
const rewarded = events.filter((e) => e.decision === "REWARD").length;
|
|
167
|
+
const neutral = events.filter((e) => e.decision === "NEUTRAL").length;
|
|
168
|
+
const actorSet = /* @__PURE__ */ new Set();
|
|
169
|
+
for (const e of events) {
|
|
170
|
+
if (e.actor) actorSet.add(e.actor);
|
|
171
|
+
}
|
|
172
|
+
const intentMap = /* @__PURE__ */ new Map();
|
|
173
|
+
for (const e of events) {
|
|
174
|
+
const entry = intentMap.get(e.intent) ?? { count: 0, blocked: 0, paused: 0, penalized: 0, rewarded: 0 };
|
|
175
|
+
entry.count++;
|
|
176
|
+
if (e.decision === "BLOCK") entry.blocked++;
|
|
177
|
+
if (e.decision === "PAUSE") entry.paused++;
|
|
178
|
+
if (e.decision === "PENALIZE") entry.penalized++;
|
|
179
|
+
if (e.decision === "REWARD") entry.rewarded++;
|
|
180
|
+
intentMap.set(e.intent, entry);
|
|
181
|
+
}
|
|
182
|
+
const topIntents = [...intentMap.entries()].map(([intent, data]) => ({ intent, ...data })).sort((a, b) => b.count - a.count);
|
|
183
|
+
const ruleMap = /* @__PURE__ */ new Map();
|
|
184
|
+
for (const e of events) {
|
|
185
|
+
if (e.ruleId) {
|
|
186
|
+
ruleMap.set(e.ruleId, (ruleMap.get(e.ruleId) ?? 0) + 1);
|
|
187
|
+
}
|
|
188
|
+
for (const g of e.guardsMatched) {
|
|
189
|
+
ruleMap.set(g, (ruleMap.get(g) ?? 0) + 1);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const topRules = [...ruleMap.entries()].map(([ruleId, count]) => ({ ruleId, count })).sort((a, b) => b.count - a.count);
|
|
193
|
+
const redirected = blocked + paused + modified + penalized;
|
|
194
|
+
const total = events.length;
|
|
195
|
+
return {
|
|
196
|
+
totalActions: total,
|
|
197
|
+
allowed,
|
|
198
|
+
blocked,
|
|
199
|
+
paused,
|
|
200
|
+
modified,
|
|
201
|
+
penalized,
|
|
202
|
+
rewarded,
|
|
203
|
+
neutral,
|
|
204
|
+
actors: [...actorSet],
|
|
205
|
+
topIntents,
|
|
206
|
+
topRules,
|
|
207
|
+
firstEvent: events[0]?.timestamp ?? "",
|
|
208
|
+
lastEvent: events[events.length - 1]?.timestamp ?? "",
|
|
209
|
+
behavioralEconomy: {
|
|
210
|
+
totalPenalties: penalized,
|
|
211
|
+
totalRewards: rewarded,
|
|
212
|
+
netPressure: rewarded - penalized,
|
|
213
|
+
redirectionRate: total > 0 ? redirected / total : 0
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export {
|
|
219
|
+
FileAuditLogger,
|
|
220
|
+
ConsoleAuditLogger,
|
|
221
|
+
CompositeAuditLogger,
|
|
222
|
+
verdictToAuditEvent,
|
|
223
|
+
createGovernanceEngine,
|
|
224
|
+
readAuditLog,
|
|
225
|
+
summarizeAuditEvents
|
|
226
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// src/loader/world-resolver.ts
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync, mkdirSync } from "fs";
|
|
3
|
+
import { join, resolve, isAbsolute } from "path";
|
|
4
|
+
var WORLDS_DIR = ".neuroverse/worlds";
|
|
5
|
+
var ACTIVE_WORLD_FILE = ".neuroverse/active_world";
|
|
6
|
+
function listWorlds(cwd = process.cwd()) {
|
|
7
|
+
const worldsDir = join(cwd, WORLDS_DIR);
|
|
8
|
+
if (!existsSync(worldsDir)) return [];
|
|
9
|
+
const activeName = getActiveWorldName(cwd);
|
|
10
|
+
const entries = readdirSync(worldsDir);
|
|
11
|
+
return entries.filter((name) => {
|
|
12
|
+
const worldJson = join(worldsDir, name, "world.json");
|
|
13
|
+
return existsSync(worldJson);
|
|
14
|
+
}).map((name) => ({
|
|
15
|
+
name,
|
|
16
|
+
path: join(worldsDir, name),
|
|
17
|
+
active: name === activeName
|
|
18
|
+
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
19
|
+
}
|
|
20
|
+
function getActiveWorldName(cwd = process.cwd()) {
|
|
21
|
+
const filePath = join(cwd, ACTIVE_WORLD_FILE);
|
|
22
|
+
try {
|
|
23
|
+
return readFileSync(filePath, "utf-8").trim() || void 0;
|
|
24
|
+
} catch {
|
|
25
|
+
return void 0;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function setActiveWorld(name, cwd = process.cwd()) {
|
|
29
|
+
const worldsDir = join(cwd, WORLDS_DIR);
|
|
30
|
+
const worldPath = join(worldsDir, name, "world.json");
|
|
31
|
+
if (!existsSync(worldPath)) {
|
|
32
|
+
const available = listWorlds(cwd);
|
|
33
|
+
const names = available.map((w) => w.name).join(", ");
|
|
34
|
+
throw new Error(
|
|
35
|
+
`World "${name}" not found in ${WORLDS_DIR}/
|
|
36
|
+
` + (names ? `Available: ${names}` : "No worlds found. Run `neuroverse build` first.")
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
const dir = join(cwd, ".neuroverse");
|
|
40
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
41
|
+
writeFileSync(join(cwd, ACTIVE_WORLD_FILE), name + "\n", "utf-8");
|
|
42
|
+
}
|
|
43
|
+
function resolveWorldPath(explicit, cwd = process.cwd()) {
|
|
44
|
+
if (explicit) {
|
|
45
|
+
return resolveNameOrPath(explicit, cwd);
|
|
46
|
+
}
|
|
47
|
+
const envWorld = process.env.NEUROVERSE_WORLD;
|
|
48
|
+
if (envWorld) {
|
|
49
|
+
return resolveNameOrPath(envWorld, cwd);
|
|
50
|
+
}
|
|
51
|
+
const activeName = getActiveWorldName(cwd);
|
|
52
|
+
if (activeName) {
|
|
53
|
+
return resolveNameOrPath(activeName, cwd);
|
|
54
|
+
}
|
|
55
|
+
const worlds = listWorlds(cwd);
|
|
56
|
+
if (worlds.length === 1) {
|
|
57
|
+
return resolve(worlds[0].path);
|
|
58
|
+
}
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
function describeActiveWorld(explicit, cwd = process.cwd()) {
|
|
62
|
+
if (explicit) {
|
|
63
|
+
return { name: explicit, source: "--world flag" };
|
|
64
|
+
}
|
|
65
|
+
const envWorld = process.env.NEUROVERSE_WORLD;
|
|
66
|
+
if (envWorld) {
|
|
67
|
+
return { name: envWorld, source: "NEUROVERSE_WORLD env var" };
|
|
68
|
+
}
|
|
69
|
+
const activeName = getActiveWorldName(cwd);
|
|
70
|
+
if (activeName) {
|
|
71
|
+
return { name: activeName, source: ".neuroverse/active_world" };
|
|
72
|
+
}
|
|
73
|
+
const worlds = listWorlds(cwd);
|
|
74
|
+
if (worlds.length === 1) {
|
|
75
|
+
return { name: worlds[0].name, source: "auto-detected (only world)" };
|
|
76
|
+
}
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
function resolveNameOrPath(ref, cwd) {
|
|
80
|
+
if (ref.includes("/") || ref.includes("\\") || ref.startsWith(".") || isAbsolute(ref)) {
|
|
81
|
+
return resolve(cwd, ref);
|
|
82
|
+
}
|
|
83
|
+
const namedPath = join(cwd, WORLDS_DIR, ref);
|
|
84
|
+
if (existsSync(join(namedPath, "world.json"))) {
|
|
85
|
+
return resolve(namedPath);
|
|
86
|
+
}
|
|
87
|
+
return resolve(cwd, ref);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export {
|
|
91
|
+
listWorlds,
|
|
92
|
+
getActiveWorldName,
|
|
93
|
+
setActiveWorld,
|
|
94
|
+
resolveWorldPath,
|
|
95
|
+
describeActiveWorld
|
|
96
|
+
};
|