@neuroverseos/governance 0.1.0 → 0.1.2
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.md +190 -0
- package/README.md +472 -115
- package/dist/adapters/express.cjs +874 -0
- package/dist/adapters/express.d.cts +66 -0
- package/dist/adapters/express.d.ts +66 -0
- package/dist/adapters/express.js +10 -0
- package/dist/adapters/index.cjs +1166 -0
- package/dist/adapters/index.d.cts +5 -0
- package/dist/adapters/index.d.ts +5 -0
- package/dist/adapters/index.js +40 -0
- package/dist/adapters/langchain.cjs +861 -0
- package/dist/adapters/langchain.d.cts +82 -0
- package/dist/adapters/langchain.d.ts +82 -0
- package/dist/adapters/langchain.js +14 -0
- package/dist/adapters/openai.cjs +891 -0
- package/dist/adapters/openai.d.cts +92 -0
- package/dist/adapters/openai.d.ts +92 -0
- package/dist/adapters/openai.js +14 -0
- package/dist/adapters/openclaw.cjs +883 -0
- package/dist/adapters/openclaw.d.cts +92 -0
- package/dist/adapters/openclaw.d.ts +92 -0
- package/dist/adapters/openclaw.js +14 -0
- package/dist/bootstrap-H4HHKQ5G.js +113 -0
- package/dist/build-73KAVHEY.js +308 -0
- package/dist/chunk-4NGDRRQH.js +10 -0
- package/dist/chunk-B4NF3OLW.js +673 -0
- package/dist/chunk-BUWWN2NX.js +192 -0
- package/dist/chunk-CROPZ75A.js +107 -0
- package/dist/chunk-D7BGWV2J.js +620 -0
- package/dist/chunk-EIUHJXBB.js +340 -0
- package/dist/chunk-EQXFOKH2.js +85 -0
- package/dist/chunk-FYPYZFV5.js +187 -0
- package/dist/chunk-FYS2CBUW.js +304 -0
- package/dist/chunk-FZQCRGUU.js +115 -0
- package/dist/chunk-I3RRAYK2.js +11 -0
- package/dist/chunk-ITJ3LCPG.js +225 -0
- package/dist/chunk-M3TZFGHO.js +79 -0
- package/dist/chunk-MWDQ4MJB.js +11 -0
- package/dist/chunk-O5OMJMIE.js +590 -0
- package/dist/chunk-T4X42QXC.js +121 -0
- package/dist/chunk-XPDMYECO.js +642 -0
- package/dist/chunk-Z2S2HIV5.js +100 -0
- package/dist/cli/neuroverse.cjs +5864 -0
- package/dist/cli/neuroverse.d.cts +1 -0
- package/dist/cli/neuroverse.d.ts +1 -0
- package/dist/cli/neuroverse.js +128 -0
- package/dist/configure-ai-46JVG56I.js +129 -0
- package/dist/derive-6NAEWLM5.js +150 -0
- package/dist/explain-3B3VB6TL.js +69 -0
- package/dist/guard-67Y66P3I.js +82 -0
- package/dist/guard-contract-D_RQz9kt.d.cts +529 -0
- package/dist/guard-contract-D_RQz9kt.d.ts +529 -0
- package/dist/impact-CHERK3O6.js +57 -0
- package/dist/improve-YG6I6ERG.js +84 -0
- package/dist/index.cjs +4227 -0
- package/dist/index.d.cts +1147 -0
- package/dist/index.d.ts +1139 -25
- package/dist/index.js +318 -1159
- package/dist/init-Z66T6TDI.js +142 -0
- package/dist/simulate-ETHHINZ4.js +107 -0
- package/dist/trace-3YODSSIP.js +164 -0
- package/dist/validate-UVE6GKQU.js +72 -0
- package/dist/validate-engine-657D75OG.js +6 -0
- package/dist/world-WLNHL5XC.js +298 -0
- package/dist/worlds/derivation-world.nv-world.md +278 -0
- package/package.json +74 -26
- package/LICENSE +0 -21
- package/dist/audit-logger.d.ts +0 -38
- package/dist/audit-logger.d.ts.map +0 -1
- package/dist/audit-logger.js +0 -100
- package/dist/audit-logger.js.map +0 -1
- package/dist/condition-engine.d.ts +0 -16
- package/dist/condition-engine.d.ts.map +0 -1
- package/dist/condition-engine.js +0 -186
- package/dist/condition-engine.js.map +0 -1
- package/dist/drift-monitor.d.ts +0 -81
- package/dist/drift-monitor.d.ts.map +0 -1
- package/dist/drift-monitor.js +0 -228
- package/dist/drift-monitor.js.map +0 -1
- package/dist/governance-engine.d.ts +0 -131
- package/dist/governance-engine.d.ts.map +0 -1
- package/dist/governance-engine.js +0 -660
- package/dist/governance-engine.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/types.d.ts +0 -196
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -9
- package/dist/types.js.map +0 -1
- package/dist/world-bootstrap.d.ts +0 -31
- package/dist/world-bootstrap.d.ts.map +0 -1
- package/dist/world-bootstrap.js +0 -415
- package/dist/world-bootstrap.js.map +0 -1
- package/openclaw.plugin.json +0 -59
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// src/cli/init.ts
|
|
2
|
+
function generateTemplate(name) {
|
|
3
|
+
const worldId = name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
|
|
4
|
+
return `---
|
|
5
|
+
world_id: ${worldId}
|
|
6
|
+
name: ${name}
|
|
7
|
+
version: 1.0.0
|
|
8
|
+
runtime_mode: SIMULATION
|
|
9
|
+
default_profile: baseline
|
|
10
|
+
alternative_profile: alternative
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Thesis
|
|
14
|
+
|
|
15
|
+
Replace this with your world's structural claim \u2014 the testable hypothesis that simulation can confirm or refute.
|
|
16
|
+
|
|
17
|
+
# Invariants
|
|
18
|
+
|
|
19
|
+
- \`invariant_one\` \u2014 Replace with a structural truth that must always hold (structural, immutable)
|
|
20
|
+
- \`invariant_two\` \u2014 Replace with another non-negotiable constraint (structural, immutable)
|
|
21
|
+
|
|
22
|
+
# State
|
|
23
|
+
|
|
24
|
+
## example_variable
|
|
25
|
+
- type: number
|
|
26
|
+
- min: 0
|
|
27
|
+
- max: 100
|
|
28
|
+
- step: 5
|
|
29
|
+
- default: 50
|
|
30
|
+
- label: Example Variable
|
|
31
|
+
- description: Replace with what this variable represents
|
|
32
|
+
|
|
33
|
+
## example_enum
|
|
34
|
+
- type: enum
|
|
35
|
+
- options: option_a, option_b, option_c
|
|
36
|
+
- default: option_a
|
|
37
|
+
- label: Example Enum
|
|
38
|
+
- description: Replace with what this choice represents
|
|
39
|
+
|
|
40
|
+
# Assumptions
|
|
41
|
+
|
|
42
|
+
## baseline
|
|
43
|
+
- name: Baseline Scenario
|
|
44
|
+
- description: The default conditions under which the model operates
|
|
45
|
+
- example_param: default_value
|
|
46
|
+
|
|
47
|
+
## alternative
|
|
48
|
+
- name: Alternative Scenario
|
|
49
|
+
- description: What changes under different conditions
|
|
50
|
+
- example_param: changed_value
|
|
51
|
+
|
|
52
|
+
# Rules
|
|
53
|
+
|
|
54
|
+
## rule-001: Example Rule (structural)
|
|
55
|
+
Replace with a description of what this rule detects and why it matters.
|
|
56
|
+
|
|
57
|
+
When example_variable < 20 [state]
|
|
58
|
+
Then effective_margin *= 0.30
|
|
59
|
+
Collapse: effective_margin < 0.03
|
|
60
|
+
|
|
61
|
+
> trigger: Replace with what triggers this rule
|
|
62
|
+
> rule: Replace with the causal mechanism
|
|
63
|
+
> shift: Replace with what changes structurally
|
|
64
|
+
> effect: Replace with the quantitative impact
|
|
65
|
+
|
|
66
|
+
## rule-002: Example Advantage (advantage)
|
|
67
|
+
Replace with a description of a positive reinforcement rule.
|
|
68
|
+
|
|
69
|
+
When example_variable > 80 [state]
|
|
70
|
+
Then effective_margin *= 1.15
|
|
71
|
+
|
|
72
|
+
> trigger: Replace with what triggers this advantage
|
|
73
|
+
> rule: Replace with why this helps
|
|
74
|
+
> shift: Replace with the structural improvement
|
|
75
|
+
> effect: Replace with the quantitative benefit
|
|
76
|
+
|
|
77
|
+
# Gates
|
|
78
|
+
|
|
79
|
+
- THRIVING: effective_margin >= 40
|
|
80
|
+
- STABLE: effective_margin >= 20
|
|
81
|
+
- COMPRESSED: effective_margin >= 10
|
|
82
|
+
- CRITICAL: effective_margin > 3
|
|
83
|
+
- MODEL_COLLAPSES: effective_margin <= 3
|
|
84
|
+
|
|
85
|
+
# Outcomes
|
|
86
|
+
|
|
87
|
+
## effective_margin
|
|
88
|
+
- type: number
|
|
89
|
+
- range: 0-100
|
|
90
|
+
- display: percentage
|
|
91
|
+
- label: Effective Margin
|
|
92
|
+
- primary: true
|
|
93
|
+
`;
|
|
94
|
+
}
|
|
95
|
+
function parseArgs(argv) {
|
|
96
|
+
let name = "My World";
|
|
97
|
+
let outputPath = "./world.nv-world.md";
|
|
98
|
+
for (let i = 0; i < argv.length; i++) {
|
|
99
|
+
const arg = argv[i];
|
|
100
|
+
if (arg === "--name" && i + 1 < argv.length) {
|
|
101
|
+
name = argv[++i];
|
|
102
|
+
} else if (arg === "--output" && i + 1 < argv.length) {
|
|
103
|
+
outputPath = argv[++i];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return { name, outputPath };
|
|
107
|
+
}
|
|
108
|
+
async function main(argv = process.argv.slice(2)) {
|
|
109
|
+
try {
|
|
110
|
+
const args = parseArgs(argv);
|
|
111
|
+
const { writeFile } = await import("fs/promises");
|
|
112
|
+
const { existsSync } = await import("fs");
|
|
113
|
+
if (existsSync(args.outputPath)) {
|
|
114
|
+
process.stderr.write(`File already exists: ${args.outputPath}
|
|
115
|
+
`);
|
|
116
|
+
process.stderr.write("Use a different --output path or remove the existing file.\n");
|
|
117
|
+
process.exit(1);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const template = generateTemplate(args.name);
|
|
121
|
+
await writeFile(args.outputPath, template, "utf-8");
|
|
122
|
+
const result = {
|
|
123
|
+
created: args.outputPath,
|
|
124
|
+
worldName: args.name,
|
|
125
|
+
nextSteps: [
|
|
126
|
+
`Edit ${args.outputPath} \u2014 replace placeholder content with your governance spec`,
|
|
127
|
+
`neuroverse bootstrap --input ${args.outputPath} --output ./world/ --validate`,
|
|
128
|
+
"neuroverse validate --world ./world/",
|
|
129
|
+
`echo '{"intent":"test action"}' | neuroverse guard --world ./world/`
|
|
130
|
+
]
|
|
131
|
+
};
|
|
132
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
133
|
+
process.exit(0);
|
|
134
|
+
} catch (e) {
|
|
135
|
+
process.stderr.write(`Init failed: ${e}
|
|
136
|
+
`);
|
|
137
|
+
process.exit(3);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export {
|
|
141
|
+
main
|
|
142
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {
|
|
2
|
+
renderSimulateText,
|
|
3
|
+
simulateWorld
|
|
4
|
+
} from "./chunk-FYS2CBUW.js";
|
|
5
|
+
import {
|
|
6
|
+
loadWorld
|
|
7
|
+
} from "./chunk-M3TZFGHO.js";
|
|
8
|
+
|
|
9
|
+
// src/cli/simulate.ts
|
|
10
|
+
function parseArgs(argv) {
|
|
11
|
+
let worldPath = "";
|
|
12
|
+
let steps = 1;
|
|
13
|
+
let json = false;
|
|
14
|
+
let profile;
|
|
15
|
+
const stateOverrides = {};
|
|
16
|
+
for (let i = 0; i < argv.length; i++) {
|
|
17
|
+
const arg = argv[i];
|
|
18
|
+
if (arg === "--json") {
|
|
19
|
+
json = true;
|
|
20
|
+
} else if (arg === "--steps" && i + 1 < argv.length) {
|
|
21
|
+
steps = parseInt(argv[++i], 10);
|
|
22
|
+
if (isNaN(steps) || steps < 1) steps = 1;
|
|
23
|
+
if (steps > 50) steps = 50;
|
|
24
|
+
} else if (arg === "--profile" && i + 1 < argv.length) {
|
|
25
|
+
profile = argv[++i];
|
|
26
|
+
} else if (arg === "--set" && i + 1 < argv.length) {
|
|
27
|
+
const pair = argv[++i];
|
|
28
|
+
const eqIdx = pair.indexOf("=");
|
|
29
|
+
if (eqIdx > 0) {
|
|
30
|
+
const key = pair.slice(0, eqIdx);
|
|
31
|
+
const rawValue = pair.slice(eqIdx + 1);
|
|
32
|
+
stateOverrides[key] = parseValue(rawValue);
|
|
33
|
+
}
|
|
34
|
+
} else if (!arg.startsWith("--") && !worldPath) {
|
|
35
|
+
worldPath = arg;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!worldPath) {
|
|
39
|
+
throw new Error("Usage: neuroverse simulate <world-path-or-id> [--steps N] [--set key=value]");
|
|
40
|
+
}
|
|
41
|
+
return { worldPath, steps, stateOverrides, profile, json };
|
|
42
|
+
}
|
|
43
|
+
function parseValue(raw) {
|
|
44
|
+
if (raw === "true") return true;
|
|
45
|
+
if (raw === "false") return false;
|
|
46
|
+
const num = Number(raw);
|
|
47
|
+
if (!isNaN(num) && raw.trim() !== "") return num;
|
|
48
|
+
return raw;
|
|
49
|
+
}
|
|
50
|
+
async function resolveWorldPath(input) {
|
|
51
|
+
const { stat } = await import("fs/promises");
|
|
52
|
+
try {
|
|
53
|
+
const info = await stat(input);
|
|
54
|
+
if (info.isDirectory()) return input;
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
const neuroversePath = `.neuroverse/worlds/${input}`;
|
|
58
|
+
try {
|
|
59
|
+
const info = await stat(neuroversePath);
|
|
60
|
+
if (info.isDirectory()) return neuroversePath;
|
|
61
|
+
} catch {
|
|
62
|
+
}
|
|
63
|
+
throw new Error(
|
|
64
|
+
`World not found: "${input}"
|
|
65
|
+
Tried:
|
|
66
|
+
${input}
|
|
67
|
+
${neuroversePath}
|
|
68
|
+
|
|
69
|
+
Build a world first: neuroverse build <input.md>`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
async function main(argv = process.argv.slice(2)) {
|
|
73
|
+
try {
|
|
74
|
+
const args = parseArgs(argv);
|
|
75
|
+
const resolvedPath = await resolveWorldPath(args.worldPath);
|
|
76
|
+
const world = await loadWorld(resolvedPath);
|
|
77
|
+
const result = simulateWorld(world, {
|
|
78
|
+
steps: args.steps,
|
|
79
|
+
stateOverrides: Object.keys(args.stateOverrides).length > 0 ? args.stateOverrides : void 0,
|
|
80
|
+
profile: args.profile
|
|
81
|
+
});
|
|
82
|
+
if (args.json) {
|
|
83
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
84
|
+
} else {
|
|
85
|
+
process.stderr.write("\n");
|
|
86
|
+
process.stderr.write(renderSimulateText(result) + "\n");
|
|
87
|
+
}
|
|
88
|
+
if (!args.json) {
|
|
89
|
+
process.stderr.write("\nNext steps:\n");
|
|
90
|
+
process.stderr.write(` Improve neuroverse improve ${args.worldPath}
|
|
91
|
+
`);
|
|
92
|
+
if (args.steps === 1) {
|
|
93
|
+
process.stderr.write(` Deeper neuroverse simulate ${args.worldPath} --steps 5
|
|
94
|
+
`);
|
|
95
|
+
}
|
|
96
|
+
process.stderr.write("\n");
|
|
97
|
+
}
|
|
98
|
+
process.exit(result.collapsed ? 2 : 0);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
process.stderr.write(`${e instanceof Error ? e.message : String(e)}
|
|
101
|
+
`);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export {
|
|
106
|
+
main
|
|
107
|
+
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readAuditLog,
|
|
3
|
+
summarizeAuditEvents
|
|
4
|
+
} from "./chunk-FYPYZFV5.js";
|
|
5
|
+
import "./chunk-B4NF3OLW.js";
|
|
6
|
+
|
|
7
|
+
// src/cli/trace.ts
|
|
8
|
+
function parseArgs(argv) {
|
|
9
|
+
const args = {};
|
|
10
|
+
for (let i = 0; i < argv.length; i++) {
|
|
11
|
+
const arg = argv[i];
|
|
12
|
+
if (arg === "--summary") {
|
|
13
|
+
args.summary = true;
|
|
14
|
+
} else if (arg === "--json") {
|
|
15
|
+
args.json = true;
|
|
16
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
17
|
+
args.help = true;
|
|
18
|
+
} else if (arg === "--log" && argv[i + 1]) {
|
|
19
|
+
args.log = argv[++i];
|
|
20
|
+
} else if (arg === "--filter" && argv[i + 1]) {
|
|
21
|
+
args.filter = argv[++i].toUpperCase();
|
|
22
|
+
} else if (arg === "--actor" && argv[i + 1]) {
|
|
23
|
+
args.actor = argv[++i];
|
|
24
|
+
} else if (arg === "--intent" && argv[i + 1]) {
|
|
25
|
+
args.intent = argv[++i];
|
|
26
|
+
} else if (arg === "--last" && argv[i + 1]) {
|
|
27
|
+
args.last = argv[++i];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return args;
|
|
31
|
+
}
|
|
32
|
+
var USAGE = `
|
|
33
|
+
neuroverse trace \u2014 Runtime action audit log
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
neuroverse trace [options]
|
|
37
|
+
|
|
38
|
+
Options:
|
|
39
|
+
--log <path> Path to audit log (default: .neuroverse/audit.ndjson)
|
|
40
|
+
--summary Show aggregate summary
|
|
41
|
+
--filter <decision> Filter: ALLOW, BLOCK, or PAUSE
|
|
42
|
+
--actor <id> Filter by actor/role ID
|
|
43
|
+
--intent <pattern> Filter by intent (substring)
|
|
44
|
+
--last <n> Show last N events
|
|
45
|
+
--json Raw JSON output
|
|
46
|
+
`.trim();
|
|
47
|
+
function formatEvent(event) {
|
|
48
|
+
const ts = event.timestamp.split("T")[1]?.replace("Z", "").slice(0, 8) ?? event.timestamp;
|
|
49
|
+
const icon = event.decision === "ALLOW" ? " \u2713" : event.decision === "BLOCK" ? " \u2717" : " \u23F8";
|
|
50
|
+
const parts = [];
|
|
51
|
+
parts.push(` [${ts}] ${event.actor ?? "unknown"}`);
|
|
52
|
+
parts.push(` Action: ${event.intent}${event.tool ? ` (tool: ${event.tool})` : ""}`);
|
|
53
|
+
parts.push(` Result:${icon} ${event.decision}`);
|
|
54
|
+
if (event.guardsMatched.length > 0) {
|
|
55
|
+
parts.push(` Guards: ${event.guardsMatched.join(", ")}`);
|
|
56
|
+
}
|
|
57
|
+
if (event.rulesMatched.length > 0) {
|
|
58
|
+
parts.push(` Rules: ${event.rulesMatched.join(", ")}`);
|
|
59
|
+
}
|
|
60
|
+
if (event.reason) {
|
|
61
|
+
parts.push(` Reason: ${event.reason}`);
|
|
62
|
+
}
|
|
63
|
+
if (event.warning) {
|
|
64
|
+
parts.push(` Warning: ${event.warning}`);
|
|
65
|
+
}
|
|
66
|
+
return parts.join("\n");
|
|
67
|
+
}
|
|
68
|
+
function formatSummary(events) {
|
|
69
|
+
const summary = summarizeAuditEvents(events);
|
|
70
|
+
const lines = [];
|
|
71
|
+
lines.push("GOVERNANCE SUMMARY");
|
|
72
|
+
lines.push("\u2500".repeat(40));
|
|
73
|
+
lines.push("");
|
|
74
|
+
lines.push(` Total actions: ${summary.totalActions}`);
|
|
75
|
+
lines.push(` Allowed: ${summary.allowed}`);
|
|
76
|
+
lines.push(` Blocked: ${summary.blocked}`);
|
|
77
|
+
lines.push(` Paused: ${summary.paused}`);
|
|
78
|
+
if (summary.actors.length > 0) {
|
|
79
|
+
lines.push("");
|
|
80
|
+
lines.push(` Actors: ${summary.actors.join(", ")}`);
|
|
81
|
+
}
|
|
82
|
+
if (summary.firstEvent) {
|
|
83
|
+
lines.push("");
|
|
84
|
+
lines.push(` First event: ${summary.firstEvent}`);
|
|
85
|
+
lines.push(` Last event: ${summary.lastEvent}`);
|
|
86
|
+
}
|
|
87
|
+
if (summary.topIntents.length > 0) {
|
|
88
|
+
lines.push("");
|
|
89
|
+
lines.push(" Top actions:");
|
|
90
|
+
for (const entry of summary.topIntents.slice(0, 10)) {
|
|
91
|
+
const extra = [];
|
|
92
|
+
if (entry.blocked > 0) extra.push(`${entry.blocked} blocked`);
|
|
93
|
+
if (entry.paused > 0) extra.push(`${entry.paused} paused`);
|
|
94
|
+
const suffix = extra.length > 0 ? ` (${extra.join(", ")})` : "";
|
|
95
|
+
lines.push(` ${entry.intent.padEnd(30)} ${String(entry.count).padStart(5)}${suffix}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (summary.topRules.length > 0) {
|
|
99
|
+
lines.push("");
|
|
100
|
+
lines.push(" Top triggered rules/guards:");
|
|
101
|
+
for (const entry of summary.topRules.slice(0, 10)) {
|
|
102
|
+
lines.push(` ${entry.ruleId.padEnd(30)} ${String(entry.count).padStart(5)}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return lines.join("\n");
|
|
106
|
+
}
|
|
107
|
+
async function main(argv = process.argv.slice(2)) {
|
|
108
|
+
const args = parseArgs(argv);
|
|
109
|
+
if (args.help) {
|
|
110
|
+
process.stdout.write(USAGE + "\n");
|
|
111
|
+
process.exit(0);
|
|
112
|
+
}
|
|
113
|
+
const logPath = args.log ?? ".neuroverse/audit.ndjson";
|
|
114
|
+
const filterFn = (event) => {
|
|
115
|
+
if (args.filter && event.decision !== args.filter) return false;
|
|
116
|
+
if (args.actor && event.actor !== args.actor) return false;
|
|
117
|
+
if (args.intent && !event.intent.includes(args.intent)) return false;
|
|
118
|
+
return true;
|
|
119
|
+
};
|
|
120
|
+
let events = await readAuditLog(logPath, filterFn);
|
|
121
|
+
if (events.length === 0) {
|
|
122
|
+
process.stderr.write(`No audit events found in ${logPath}
|
|
123
|
+
`);
|
|
124
|
+
process.stderr.write("Run governance evaluations with audit logging enabled to generate events.\n");
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
if (args.last) {
|
|
128
|
+
const n = parseInt(args.last, 10);
|
|
129
|
+
if (n > 0 && n < events.length) {
|
|
130
|
+
events = events.slice(-n);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (args.summary) {
|
|
134
|
+
if (args.json) {
|
|
135
|
+
process.stdout.write(JSON.stringify(summarizeAuditEvents(events), null, 2) + "\n");
|
|
136
|
+
} else {
|
|
137
|
+
process.stdout.write(formatSummary(events) + "\n");
|
|
138
|
+
}
|
|
139
|
+
process.exit(0);
|
|
140
|
+
}
|
|
141
|
+
if (args.json) {
|
|
142
|
+
process.stdout.write(JSON.stringify(events, null, 2) + "\n");
|
|
143
|
+
process.exit(0);
|
|
144
|
+
}
|
|
145
|
+
process.stdout.write("ACTION TRACE\n");
|
|
146
|
+
process.stdout.write("\u2500".repeat(40) + "\n");
|
|
147
|
+
for (const event of events) {
|
|
148
|
+
process.stdout.write("\n" + formatEvent(event) + "\n");
|
|
149
|
+
}
|
|
150
|
+
process.stdout.write("\n");
|
|
151
|
+
process.stdout.write(`Total: ${events.length} events`);
|
|
152
|
+
const blocked = events.filter((e) => e.decision === "BLOCK").length;
|
|
153
|
+
const paused = events.filter((e) => e.decision === "PAUSE").length;
|
|
154
|
+
if (blocked > 0 || paused > 0) {
|
|
155
|
+
const parts = [];
|
|
156
|
+
if (blocked > 0) parts.push(`${blocked} blocked`);
|
|
157
|
+
if (paused > 0) parts.push(`${paused} paused`);
|
|
158
|
+
process.stdout.write(` (${parts.join(", ")})`);
|
|
159
|
+
}
|
|
160
|
+
process.stdout.write("\n");
|
|
161
|
+
}
|
|
162
|
+
export {
|
|
163
|
+
main
|
|
164
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VALIDATE_EXIT_CODES
|
|
3
|
+
} from "./chunk-I3RRAYK2.js";
|
|
4
|
+
import {
|
|
5
|
+
loadWorld
|
|
6
|
+
} from "./chunk-M3TZFGHO.js";
|
|
7
|
+
import {
|
|
8
|
+
validateWorld
|
|
9
|
+
} from "./chunk-O5OMJMIE.js";
|
|
10
|
+
|
|
11
|
+
// src/cli/validate.ts
|
|
12
|
+
function parseArgs(argv) {
|
|
13
|
+
let worldPath = "";
|
|
14
|
+
let format = "full";
|
|
15
|
+
for (let i = 0; i < argv.length; i++) {
|
|
16
|
+
const arg = argv[i];
|
|
17
|
+
if (arg === "--world" && i + 1 < argv.length) {
|
|
18
|
+
worldPath = argv[++i];
|
|
19
|
+
} else if (arg === "--format" && i + 1 < argv.length) {
|
|
20
|
+
const val = argv[++i];
|
|
21
|
+
if (val === "full" || val === "summary" || val === "findings") {
|
|
22
|
+
format = val;
|
|
23
|
+
} else {
|
|
24
|
+
throw new Error(`Invalid format: "${val}". Must be full, summary, or findings.`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (!worldPath) {
|
|
29
|
+
throw new Error("--world <path> is required");
|
|
30
|
+
}
|
|
31
|
+
return { worldPath, format };
|
|
32
|
+
}
|
|
33
|
+
function formatOutput(report, format) {
|
|
34
|
+
if (format === "summary") {
|
|
35
|
+
return JSON.stringify({
|
|
36
|
+
worldName: report.worldName,
|
|
37
|
+
worldVersion: report.worldVersion,
|
|
38
|
+
summary: report.summary
|
|
39
|
+
}, null, 2);
|
|
40
|
+
}
|
|
41
|
+
if (format === "findings") {
|
|
42
|
+
return JSON.stringify({
|
|
43
|
+
worldName: report.worldName,
|
|
44
|
+
findings: report.findings
|
|
45
|
+
}, null, 2);
|
|
46
|
+
}
|
|
47
|
+
return JSON.stringify(report, null, 2);
|
|
48
|
+
}
|
|
49
|
+
async function main(argv = process.argv.slice(2)) {
|
|
50
|
+
try {
|
|
51
|
+
const args = parseArgs(argv);
|
|
52
|
+
const world = await loadWorld(args.worldPath);
|
|
53
|
+
const report = validateWorld(world);
|
|
54
|
+
process.stdout.write(formatOutput(report, args.format) + "\n");
|
|
55
|
+
let exitCode;
|
|
56
|
+
if (report.summary.errors > 0) {
|
|
57
|
+
exitCode = VALIDATE_EXIT_CODES.FAIL;
|
|
58
|
+
} else if (report.summary.warnings > 0) {
|
|
59
|
+
exitCode = VALIDATE_EXIT_CODES.WARN;
|
|
60
|
+
} else {
|
|
61
|
+
exitCode = VALIDATE_EXIT_CODES.PASS;
|
|
62
|
+
}
|
|
63
|
+
process.exit(exitCode);
|
|
64
|
+
} catch (e) {
|
|
65
|
+
const errorResult = { error: "Validation failed", detail: String(e) };
|
|
66
|
+
process.stderr.write(JSON.stringify(errorResult, null, 2) + "\n");
|
|
67
|
+
process.exit(VALIDATE_EXIT_CODES.ERROR);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
main
|
|
72
|
+
};
|