@neuroverseos/governance 0.3.1 → 0.3.4

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.
Files changed (133) hide show
  1. package/.well-known/ai-plugin.json +34 -9
  2. package/AGENTS.md +72 -24
  3. package/README.md +343 -248
  4. package/dist/adapters/autoresearch.cjs +1345 -0
  5. package/dist/adapters/autoresearch.d.cts +111 -0
  6. package/dist/adapters/autoresearch.d.ts +111 -0
  7. package/dist/adapters/autoresearch.js +12 -0
  8. package/dist/adapters/deep-agents.cjs +1528 -0
  9. package/dist/adapters/deep-agents.d.cts +181 -0
  10. package/dist/adapters/deep-agents.d.ts +181 -0
  11. package/dist/adapters/deep-agents.js +17 -0
  12. package/dist/adapters/express.cjs +1253 -0
  13. package/dist/adapters/express.d.cts +66 -0
  14. package/dist/adapters/express.d.ts +66 -0
  15. package/dist/adapters/express.js +12 -0
  16. package/dist/adapters/index.cjs +2112 -0
  17. package/dist/adapters/index.d.cts +8 -0
  18. package/dist/adapters/index.d.ts +8 -0
  19. package/dist/adapters/index.js +68 -0
  20. package/dist/adapters/langchain.cjs +1315 -0
  21. package/dist/adapters/langchain.d.cts +89 -0
  22. package/dist/adapters/langchain.d.ts +89 -0
  23. package/dist/adapters/langchain.js +17 -0
  24. package/dist/adapters/openai.cjs +1345 -0
  25. package/dist/adapters/openai.d.cts +99 -0
  26. package/dist/adapters/openai.d.ts +99 -0
  27. package/dist/adapters/openai.js +17 -0
  28. package/dist/adapters/openclaw.cjs +1337 -0
  29. package/dist/adapters/openclaw.d.cts +99 -0
  30. package/dist/adapters/openclaw.d.ts +99 -0
  31. package/dist/adapters/openclaw.js +17 -0
  32. package/dist/add-ROOZLU62.js +314 -0
  33. package/dist/behavioral-MJO34S6Q.js +118 -0
  34. package/dist/bootstrap-CQRZVOXK.js +116 -0
  35. package/dist/bootstrap-emitter-Q7UIJZ2O.js +7 -0
  36. package/dist/bootstrap-parser-EEF36XDU.js +7 -0
  37. package/dist/browser.global.js +941 -0
  38. package/dist/build-ZHPMX5AZ.js +342 -0
  39. package/dist/chunk-3WQLXYTP.js +91 -0
  40. package/dist/chunk-4FLICVVA.js +119 -0
  41. package/dist/chunk-4NGDRRQH.js +10 -0
  42. package/dist/chunk-5TPFNWRU.js +215 -0
  43. package/dist/chunk-5U2MQO5P.js +57 -0
  44. package/dist/chunk-6CZSKEY5.js +164 -0
  45. package/dist/chunk-7P3S7MAY.js +1090 -0
  46. package/dist/chunk-A5W4GNQO.js +130 -0
  47. package/dist/chunk-A7GKPPU7.js +226 -0
  48. package/dist/chunk-AKW5YVCE.js +96 -0
  49. package/dist/chunk-B6OXJLJ5.js +622 -0
  50. package/dist/chunk-BNKJPUPQ.js +113 -0
  51. package/dist/chunk-BQZMOEML.js +43 -0
  52. package/dist/chunk-CNSO6XW5.js +207 -0
  53. package/dist/chunk-CTZHONLA.js +135 -0
  54. package/dist/chunk-D2UCV5AK.js +326 -0
  55. package/dist/chunk-EMQDLDAF.js +458 -0
  56. package/dist/chunk-F66BVUYB.js +340 -0
  57. package/dist/chunk-FMSTRBBS.js +17 -0
  58. package/dist/chunk-G7DJ6VOD.js +101 -0
  59. package/dist/chunk-I3RRAYK2.js +11 -0
  60. package/dist/chunk-INWQHLPS.js +47 -0
  61. package/dist/chunk-IS4WUH6Y.js +363 -0
  62. package/dist/chunk-O5ABKEA7.js +304 -0
  63. package/dist/chunk-OT6PXH54.js +61 -0
  64. package/dist/chunk-PVTQQS3Y.js +186 -0
  65. package/dist/chunk-QLPTHTVB.js +253 -0
  66. package/dist/chunk-QWGCMQQD.js +16 -0
  67. package/dist/chunk-QXBFT7NI.js +201 -0
  68. package/dist/chunk-TG6SEF24.js +246 -0
  69. package/dist/chunk-U6U7EJZL.js +177 -0
  70. package/dist/chunk-VXHSMA3I.js +166 -0
  71. package/dist/chunk-W7LLXRGY.js +830 -0
  72. package/dist/chunk-YEKMVDWK.js +624 -0
  73. package/dist/chunk-ZJTDUCC2.js +194 -0
  74. package/dist/chunk-ZWI3NIXK.js +314 -0
  75. package/dist/cli/neuroverse.cjs +14379 -0
  76. package/dist/cli/neuroverse.d.cts +1 -0
  77. package/dist/cli/neuroverse.d.ts +1 -0
  78. package/dist/cli/neuroverse.js +227 -0
  79. package/dist/cli/plan.cjs +2439 -0
  80. package/dist/cli/plan.d.cts +20 -0
  81. package/dist/cli/plan.d.ts +20 -0
  82. package/dist/cli/plan.js +353 -0
  83. package/dist/cli/run.cjs +2001 -0
  84. package/dist/cli/run.d.cts +20 -0
  85. package/dist/cli/run.d.ts +20 -0
  86. package/dist/cli/run.js +143 -0
  87. package/dist/configure-ai-5MP5DWTT.js +134 -0
  88. package/dist/decision-flow-M63D47LO.js +61 -0
  89. package/dist/demo-G43RLCPK.js +469 -0
  90. package/dist/derive-LMDUTXDD.js +154 -0
  91. package/dist/doctor-6BC6X2VO.js +173 -0
  92. package/dist/equity-penalties-SG5IZQ7I.js +244 -0
  93. package/dist/explain-RHBU2GBR.js +51 -0
  94. package/dist/guard-AEEJNWLD.js +126 -0
  95. package/dist/guard-contract-B7lplwm9.d.cts +837 -0
  96. package/dist/guard-contract-B7lplwm9.d.ts +837 -0
  97. package/dist/guard-engine-PNR6MHCM.js +10 -0
  98. package/dist/impact-3XVDSCBU.js +59 -0
  99. package/dist/improve-TQP4ECSY.js +66 -0
  100. package/dist/index.cjs +7738 -0
  101. package/dist/index.d.cts +2350 -0
  102. package/dist/index.d.ts +2350 -0
  103. package/dist/index.js +479 -0
  104. package/dist/infer-world-IFXCACJ5.js +543 -0
  105. package/dist/init-FYPV4SST.js +144 -0
  106. package/dist/init-world-TI7ARHBT.js +223 -0
  107. package/dist/mcp-server-5Y3ZM7TV.js +13 -0
  108. package/dist/model-adapter-VXEKB4LS.js +11 -0
  109. package/dist/playground-VZBNPPBO.js +560 -0
  110. package/dist/redteam-MZPZD3EF.js +357 -0
  111. package/dist/session-JYOARW54.js +15 -0
  112. package/dist/shared-7RLUHNMU.js +16 -0
  113. package/dist/shared-C_zpdvBm.d.cts +60 -0
  114. package/dist/shared-Cf7yxx4-.d.ts +60 -0
  115. package/dist/simulate-LJXYBC6M.js +83 -0
  116. package/dist/test-BOOR4A5F.js +217 -0
  117. package/dist/trace-PKV4KX56.js +166 -0
  118. package/dist/validate-RALX7CZS.js +81 -0
  119. package/dist/validate-engine-7ZXFVGF2.js +7 -0
  120. package/dist/viz/assets/index-B8SaeJZZ.js +23 -0
  121. package/dist/viz/index.html +23 -0
  122. package/dist/world-BIP4GZBZ.js +376 -0
  123. package/dist/world-loader-Y6HMQH2D.js +13 -0
  124. package/dist/worlds/autoresearch.nv-world.md +230 -0
  125. package/dist/worlds/coding-agent.nv-world.md +211 -0
  126. package/dist/worlds/derivation-world.nv-world.md +278 -0
  127. package/dist/worlds/research-agent.nv-world.md +169 -0
  128. package/dist/worlds/social-media.nv-world.md +198 -0
  129. package/dist/worlds/trading-agent.nv-world.md +218 -0
  130. package/examples/social-media-sim/bridge.py +209 -0
  131. package/examples/social-media-sim/simulation.py +927 -0
  132. package/package.json +16 -3
  133. package/simulate.html +4 -336
@@ -0,0 +1,622 @@
1
+ import {
2
+ describeActiveWorld,
3
+ resolveWorldPath
4
+ } from "./chunk-AKW5YVCE.js";
5
+ import {
6
+ evaluateGuard
7
+ } from "./chunk-W7LLXRGY.js";
8
+ import {
9
+ advancePlan,
10
+ evaluatePlan,
11
+ getPlanProgress
12
+ } from "./chunk-QLPTHTVB.js";
13
+ import {
14
+ loadWorld
15
+ } from "./chunk-CTZHONLA.js";
16
+
17
+ // src/runtime/mcp-server.ts
18
+ import { execSync } from "child_process";
19
+ import { readFileSync, writeFileSync, readdirSync, statSync } from "fs";
20
+ import { join, resolve } from "path";
21
+ var GOVERNED_TOOLS = [
22
+ {
23
+ name: "governed_shell",
24
+ description: "Execute a shell command. This command is evaluated against governance rules before execution.",
25
+ inputSchema: {
26
+ type: "object",
27
+ properties: {
28
+ command: { type: "string", description: "The shell command to execute" }
29
+ },
30
+ required: ["command"]
31
+ }
32
+ },
33
+ {
34
+ name: "governed_read_file",
35
+ description: "Read a file. This action is evaluated against governance rules before execution.",
36
+ inputSchema: {
37
+ type: "object",
38
+ properties: {
39
+ path: { type: "string", description: "File path to read" }
40
+ },
41
+ required: ["path"]
42
+ }
43
+ },
44
+ {
45
+ name: "governed_write_file",
46
+ description: "Write content to a file. This action is evaluated against governance rules before execution.",
47
+ inputSchema: {
48
+ type: "object",
49
+ properties: {
50
+ path: { type: "string", description: "File path to write" },
51
+ content: { type: "string", description: "Content to write" }
52
+ },
53
+ required: ["path", "content"]
54
+ }
55
+ },
56
+ {
57
+ name: "governed_list_directory",
58
+ description: "List files in a directory. This action is evaluated against governance rules.",
59
+ inputSchema: {
60
+ type: "object",
61
+ properties: {
62
+ path: { type: "string", description: "Directory path to list" }
63
+ },
64
+ required: ["path"]
65
+ }
66
+ },
67
+ {
68
+ name: "governed_http_request",
69
+ description: "Make an HTTP request. This action is evaluated against governance rules before execution.",
70
+ inputSchema: {
71
+ type: "object",
72
+ properties: {
73
+ url: { type: "string", description: "URL to request" },
74
+ method: { type: "string", description: "HTTP method (GET, POST, PUT, DELETE)", default: "GET" },
75
+ body: { type: "string", description: "Request body (for POST/PUT)" },
76
+ headers: { type: "object", description: "Request headers" }
77
+ },
78
+ required: ["url"]
79
+ }
80
+ },
81
+ // Governance introspection tools — always available
82
+ {
83
+ name: "governance_check",
84
+ description: "Check if an action would be allowed by governance rules without executing it.",
85
+ inputSchema: {
86
+ type: "object",
87
+ properties: {
88
+ intent: { type: "string", description: "What the action intends to do" },
89
+ tool: { type: "string", description: "Tool name (shell, http, file, etc.)" },
90
+ scope: { type: "string", description: "Scope (file path, URL, etc.)" }
91
+ },
92
+ required: ["intent"]
93
+ }
94
+ },
95
+ {
96
+ name: "governance_plan_status",
97
+ description: "Show current plan progress and remaining steps.",
98
+ inputSchema: {
99
+ type: "object",
100
+ properties: {}
101
+ }
102
+ },
103
+ {
104
+ name: "governance_plan_advance",
105
+ description: "Mark a plan step as completed.",
106
+ inputSchema: {
107
+ type: "object",
108
+ properties: {
109
+ step_id: { type: "string", description: "ID of the step to mark as completed" }
110
+ },
111
+ required: ["step_id"]
112
+ }
113
+ }
114
+ ];
115
+ function executeShell(command, workingDir) {
116
+ try {
117
+ const result = execSync(command, {
118
+ cwd: workingDir,
119
+ encoding: "utf-8",
120
+ timeout: 3e4,
121
+ maxBuffer: 1024 * 1024
122
+ });
123
+ return result;
124
+ } catch (err) {
125
+ return `Error: ${err.message}
126
+ ${err.stderr ?? ""}`;
127
+ }
128
+ }
129
+ function executeReadFile(path, workingDir) {
130
+ const fullPath = resolve(workingDir ?? ".", path);
131
+ return readFileSync(fullPath, "utf-8");
132
+ }
133
+ function executeWriteFile(path, content, workingDir) {
134
+ const fullPath = resolve(workingDir ?? ".", path);
135
+ writeFileSync(fullPath, content);
136
+ return `File written: ${fullPath}`;
137
+ }
138
+ function executeListDir(path, workingDir) {
139
+ const fullPath = resolve(workingDir ?? ".", path);
140
+ const entries = readdirSync(fullPath);
141
+ return entries.map((e) => {
142
+ try {
143
+ const stat = statSync(join(fullPath, e));
144
+ return `${stat.isDirectory() ? "d" : "-"} ${e}`;
145
+ } catch {
146
+ return `? ${e}`;
147
+ }
148
+ }).join("\n");
149
+ }
150
+ async function executeHttpRequest(url, method, body, headers) {
151
+ const response = await fetch(url, {
152
+ method: method || "GET",
153
+ body: body || void 0,
154
+ headers: { "Content-Type": "application/json", ...headers }
155
+ });
156
+ const text = await response.text();
157
+ return `HTTP ${response.status}
158
+ ${text}`;
159
+ }
160
+ var McpGovernanceServer = class {
161
+ world;
162
+ plan;
163
+ config;
164
+ engineOptions;
165
+ initialized = false;
166
+ // Stats
167
+ actionsEvaluated = 0;
168
+ actionsAllowed = 0;
169
+ actionsBlocked = 0;
170
+ constructor(config) {
171
+ this.config = config;
172
+ this.plan = config.plan;
173
+ this.engineOptions = {
174
+ trace: config.trace ?? false,
175
+ level: config.level,
176
+ plan: this.plan
177
+ };
178
+ }
179
+ /**
180
+ * Start the MCP server — reads JSON-RPC from stdin, writes to stdout.
181
+ */
182
+ async start() {
183
+ if (this.config.worldPath) {
184
+ this.world = await loadWorld(this.config.worldPath);
185
+ } else if (this.config.world) {
186
+ this.world = this.config.world;
187
+ } else {
188
+ throw new Error("No world provided");
189
+ }
190
+ if (this.config.planPath && !this.plan) {
191
+ this.plan = JSON.parse(readFileSync(this.config.planPath, "utf-8"));
192
+ this.engineOptions.plan = this.plan;
193
+ }
194
+ process.stderr.write(`[neuroverse-mcp] Server starting
195
+ `);
196
+ process.stderr.write(`[neuroverse-mcp] World: ${this.world.world.name}
197
+ `);
198
+ if (this.plan) {
199
+ process.stderr.write(`[neuroverse-mcp] Plan: ${this.plan.plan_id}
200
+ `);
201
+ }
202
+ let buffer = "";
203
+ const MAX_BUFFER_SIZE = 10 * 1024 * 1024;
204
+ const MAX_CONTENT_LENGTH = 10 * 1024 * 1024;
205
+ process.stdin.setEncoding("utf-8");
206
+ process.stdin.on("data", (chunk) => {
207
+ buffer += chunk;
208
+ if (buffer.length > MAX_BUFFER_SIZE) {
209
+ process.stderr.write(`[neuroverse-mcp] Buffer exceeded ${MAX_BUFFER_SIZE} bytes, dropping.
210
+ `);
211
+ buffer = "";
212
+ return;
213
+ }
214
+ while (buffer.length > 0) {
215
+ const headerEnd = buffer.indexOf("\r\n\r\n");
216
+ if (headerEnd === -1) break;
217
+ const header = buffer.slice(0, headerEnd);
218
+ const contentLengthMatch = header.match(/Content-Length:\s*(\d+)/i);
219
+ if (!contentLengthMatch) {
220
+ const newlineIdx = buffer.indexOf("\n");
221
+ if (newlineIdx === -1) break;
222
+ const line = buffer.slice(0, newlineIdx).trim();
223
+ buffer = buffer.slice(newlineIdx + 1);
224
+ if (line) this.handleRawLine(line);
225
+ continue;
226
+ }
227
+ const contentLength = parseInt(contentLengthMatch[1], 10);
228
+ if (isNaN(contentLength) || contentLength < 0 || contentLength > MAX_CONTENT_LENGTH) {
229
+ process.stderr.write(`[neuroverse-mcp] Invalid Content-Length: ${contentLengthMatch[1]}, skipping.
230
+ `);
231
+ buffer = "";
232
+ break;
233
+ }
234
+ const bodyStart = headerEnd + 4;
235
+ const bodyEnd = bodyStart + contentLength;
236
+ if (buffer.length < bodyEnd) break;
237
+ const body = buffer.slice(bodyStart, bodyEnd);
238
+ buffer = buffer.slice(bodyEnd);
239
+ this.handleRawLine(body);
240
+ }
241
+ });
242
+ process.stdin.on("end", () => {
243
+ process.stderr.write(
244
+ `[neuroverse-mcp] Server stopped. Evaluated: ${this.actionsEvaluated}, Allowed: ${this.actionsAllowed}, Blocked: ${this.actionsBlocked}
245
+ `
246
+ );
247
+ });
248
+ await new Promise(() => {
249
+ });
250
+ }
251
+ handleRawLine(line) {
252
+ try {
253
+ const msg = JSON.parse(line);
254
+ if (msg.method) {
255
+ if (msg.id !== void 0) {
256
+ this.handleRequest(msg);
257
+ } else {
258
+ this.handleNotification(msg);
259
+ }
260
+ }
261
+ } catch (err) {
262
+ process.stderr.write(`[neuroverse-mcp] Parse error: ${err}
263
+ `);
264
+ }
265
+ }
266
+ send(msg) {
267
+ const json = JSON.stringify(msg);
268
+ const header = `Content-Length: ${Buffer.byteLength(json)}\r
269
+ \r
270
+ `;
271
+ process.stdout.write(header + json);
272
+ }
273
+ sendResult(id, result) {
274
+ this.send({ jsonrpc: "2.0", id, result });
275
+ }
276
+ sendError(id, code, message) {
277
+ this.send({ jsonrpc: "2.0", id, error: { code, message } });
278
+ }
279
+ // ─── Request Handlers ───────────────────────────────────────────────────
280
+ handleRequest(request) {
281
+ switch (request.method) {
282
+ case "initialize":
283
+ this.handleInitialize(request);
284
+ break;
285
+ case "tools/list":
286
+ this.handleToolsList(request);
287
+ break;
288
+ case "tools/call":
289
+ this.handleToolsCall(request);
290
+ break;
291
+ case "ping":
292
+ this.sendResult(request.id, {});
293
+ break;
294
+ default:
295
+ this.sendError(request.id, -32601, `Method not found: ${request.method}`);
296
+ }
297
+ }
298
+ handleNotification(notification) {
299
+ switch (notification.method) {
300
+ case "notifications/initialized":
301
+ this.initialized = true;
302
+ process.stderr.write(`[neuroverse-mcp] Client initialized
303
+ `);
304
+ break;
305
+ case "notifications/cancelled":
306
+ break;
307
+ default:
308
+ process.stderr.write(`[neuroverse-mcp] Unknown notification: ${notification.method}
309
+ `);
310
+ }
311
+ }
312
+ handleInitialize(request) {
313
+ this.sendResult(request.id, {
314
+ protocolVersion: "2024-11-05",
315
+ capabilities: {
316
+ tools: {}
317
+ },
318
+ serverInfo: {
319
+ name: "neuroverse-governance",
320
+ version: "0.2.0"
321
+ }
322
+ });
323
+ }
324
+ handleToolsList(request) {
325
+ const tools = [];
326
+ if (this.config.enableShell !== false) {
327
+ tools.push(GOVERNED_TOOLS.find((t) => t.name === "governed_shell"));
328
+ }
329
+ if (this.config.enableFiles !== false) {
330
+ tools.push(GOVERNED_TOOLS.find((t) => t.name === "governed_read_file"));
331
+ tools.push(GOVERNED_TOOLS.find((t) => t.name === "governed_write_file"));
332
+ tools.push(GOVERNED_TOOLS.find((t) => t.name === "governed_list_directory"));
333
+ }
334
+ if (this.config.enableHttp !== false) {
335
+ tools.push(GOVERNED_TOOLS.find((t) => t.name === "governed_http_request"));
336
+ }
337
+ tools.push(GOVERNED_TOOLS.find((t) => t.name === "governance_check"));
338
+ tools.push(GOVERNED_TOOLS.find((t) => t.name === "governance_plan_status"));
339
+ if (this.plan) {
340
+ tools.push(GOVERNED_TOOLS.find((t) => t.name === "governance_plan_advance"));
341
+ }
342
+ this.sendResult(request.id, { tools });
343
+ }
344
+ async handleToolsCall(request) {
345
+ const params = request.params;
346
+ const toolName = params.name;
347
+ const args = params.arguments ?? {};
348
+ try {
349
+ const result = await this.executeTool(toolName, args);
350
+ this.sendResult(request.id, result);
351
+ } catch (err) {
352
+ this.sendResult(request.id, {
353
+ content: [{ type: "text", text: `Error: ${err.message}` }],
354
+ isError: true
355
+ });
356
+ }
357
+ }
358
+ // ─── Tool Execution with Governance ─────────────────────────────────────
359
+ async executeTool(name, args) {
360
+ if (name === "governance_check") {
361
+ return this.toolGovernanceCheck(args);
362
+ }
363
+ if (name === "governance_plan_status") {
364
+ return this.toolPlanStatus();
365
+ }
366
+ if (name === "governance_plan_advance") {
367
+ return this.toolPlanAdvance(args);
368
+ }
369
+ const event = this.buildEvent(name, args);
370
+ this.engineOptions.plan = this.plan;
371
+ const verdict = evaluateGuard(event, this.world, this.engineOptions);
372
+ this.actionsEvaluated++;
373
+ if (verdict.status === "BLOCK") {
374
+ this.actionsBlocked++;
375
+ let reason = `[GOVERNANCE BLOCKED] ${verdict.reason ?? "Action blocked by governance rules."}`;
376
+ if (verdict.ruleId) reason += ` (Rule: ${verdict.ruleId})`;
377
+ if (verdict.trace?.planCheck && !verdict.trace.planCheck.matched) {
378
+ const pc = verdict.trace.planCheck;
379
+ if (pc.closestStepLabel) {
380
+ reason += `
381
+ Closest plan step: "${pc.closestStepLabel}"`;
382
+ }
383
+ }
384
+ process.stderr.write(`[neuroverse-mcp] BLOCKED: ${event.intent}
385
+ `);
386
+ return { content: [{ type: "text", text: reason }], isError: true };
387
+ }
388
+ if (verdict.status === "PAUSE") {
389
+ this.actionsBlocked++;
390
+ const reason = `[GOVERNANCE PAUSED] ${verdict.reason ?? "Action requires human approval."}`;
391
+ process.stderr.write(`[neuroverse-mcp] PAUSED: ${event.intent}
392
+ `);
393
+ return { content: [{ type: "text", text: reason }], isError: true };
394
+ }
395
+ this.actionsAllowed++;
396
+ process.stderr.write(`[neuroverse-mcp] ALLOWED: ${event.intent}
397
+ `);
398
+ const result = await this.executeActualTool(name, args);
399
+ if (this.plan) {
400
+ const planVerdict = evaluatePlan(event, this.plan);
401
+ if (planVerdict.matchedStep) {
402
+ const advResult = advancePlan(this.plan, planVerdict.matchedStep);
403
+ if (advResult.success && advResult.plan) {
404
+ this.plan = advResult.plan;
405
+ this.engineOptions.plan = this.plan;
406
+ }
407
+ const progress = getPlanProgress(this.plan);
408
+ process.stderr.write(
409
+ `[neuroverse-mcp] Plan: ${progress.completed}/${progress.total} (${progress.percentage}%)
410
+ `
411
+ );
412
+ if (progress.completed === progress.total) {
413
+ process.stderr.write(`[neuroverse-mcp] Plan complete!
414
+ `);
415
+ }
416
+ }
417
+ }
418
+ return result;
419
+ }
420
+ buildEvent(toolName, args) {
421
+ switch (toolName) {
422
+ case "governed_shell":
423
+ return {
424
+ intent: `execute shell command: ${args.command}`,
425
+ tool: "shell",
426
+ scope: String(args.command ?? ""),
427
+ actionCategory: "shell",
428
+ args,
429
+ direction: "input"
430
+ };
431
+ case "governed_read_file":
432
+ return {
433
+ intent: `read file: ${args.path}`,
434
+ tool: "fs",
435
+ scope: String(args.path ?? ""),
436
+ actionCategory: "read",
437
+ args,
438
+ direction: "input"
439
+ };
440
+ case "governed_write_file":
441
+ return {
442
+ intent: `write file: ${args.path}`,
443
+ tool: "fs",
444
+ scope: String(args.path ?? ""),
445
+ actionCategory: "write",
446
+ args,
447
+ direction: "input"
448
+ };
449
+ case "governed_list_directory":
450
+ return {
451
+ intent: `list directory: ${args.path}`,
452
+ tool: "fs",
453
+ scope: String(args.path ?? ""),
454
+ actionCategory: "read",
455
+ args,
456
+ direction: "input"
457
+ };
458
+ case "governed_http_request":
459
+ return {
460
+ intent: `http ${args.method ?? "GET"} ${args.url}`,
461
+ tool: "http",
462
+ scope: String(args.url ?? ""),
463
+ actionCategory: "network",
464
+ args,
465
+ direction: "input"
466
+ };
467
+ default:
468
+ return {
469
+ intent: `${toolName}: ${JSON.stringify(args)}`,
470
+ tool: toolName,
471
+ args,
472
+ direction: "input"
473
+ };
474
+ }
475
+ }
476
+ async executeActualTool(name, args) {
477
+ const workingDir = this.config.workingDir;
478
+ switch (name) {
479
+ case "governed_shell": {
480
+ const output = executeShell(String(args.command), workingDir);
481
+ return { content: [{ type: "text", text: output }] };
482
+ }
483
+ case "governed_read_file": {
484
+ const content = executeReadFile(String(args.path), workingDir);
485
+ return { content: [{ type: "text", text: content }] };
486
+ }
487
+ case "governed_write_file": {
488
+ const result = executeWriteFile(String(args.path), String(args.content), workingDir);
489
+ return { content: [{ type: "text", text: result }] };
490
+ }
491
+ case "governed_list_directory": {
492
+ const listing = executeListDir(String(args.path), workingDir);
493
+ return { content: [{ type: "text", text: listing }] };
494
+ }
495
+ case "governed_http_request": {
496
+ const result = await executeHttpRequest(
497
+ String(args.url),
498
+ String(args.method ?? "GET"),
499
+ args.body,
500
+ args.headers
501
+ );
502
+ return { content: [{ type: "text", text: result }] };
503
+ }
504
+ default:
505
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
506
+ }
507
+ }
508
+ // ─── Governance Introspection Tools ─────────────────────────────────────
509
+ toolGovernanceCheck(args) {
510
+ const event = {
511
+ intent: String(args.intent ?? ""),
512
+ tool: args.tool,
513
+ scope: args.scope,
514
+ direction: "input"
515
+ };
516
+ this.engineOptions.plan = this.plan;
517
+ const verdict = evaluateGuard(event, this.world, this.engineOptions);
518
+ const lines = [
519
+ `Verdict: ${verdict.status}`,
520
+ verdict.reason ? `Reason: ${verdict.reason}` : null,
521
+ verdict.ruleId ? `Rule: ${verdict.ruleId}` : null,
522
+ verdict.warning ? `Warning: ${verdict.warning}` : null
523
+ ].filter(Boolean).join("\n");
524
+ return { content: [{ type: "text", text: lines }] };
525
+ }
526
+ toolPlanStatus() {
527
+ if (!this.plan) {
528
+ return { content: [{ type: "text", text: "No active plan." }] };
529
+ }
530
+ const progress = getPlanProgress(this.plan);
531
+ const lines = [
532
+ `Plan: ${this.plan.plan_id}`,
533
+ `Objective: ${this.plan.objective}`,
534
+ `Progress: ${progress.completed}/${progress.total} (${progress.percentage}%)`,
535
+ "",
536
+ "Steps:",
537
+ ...this.plan.steps.map((s) => {
538
+ const icon = s.status === "completed" ? "[x]" : s.status === "active" ? "[>]" : "[ ]";
539
+ return ` ${icon} ${s.label} (${s.id})`;
540
+ })
541
+ ];
542
+ if (this.plan.constraints.length > 0) {
543
+ lines.push("", "Constraints:");
544
+ for (const c of this.plan.constraints) {
545
+ lines.push(` - ${c.description} [${c.type}]`);
546
+ }
547
+ }
548
+ return { content: [{ type: "text", text: lines.join("\n") }] };
549
+ }
550
+ toolPlanAdvance(args) {
551
+ if (!this.plan) {
552
+ return { content: [{ type: "text", text: "No active plan." }], isError: true };
553
+ }
554
+ const stepId = String(args.step_id ?? "");
555
+ const step = this.plan.steps.find((s) => s.id === stepId);
556
+ if (!step) {
557
+ const ids = this.plan.steps.map((s) => s.id).join(", ");
558
+ return {
559
+ content: [{ type: "text", text: `Step "${stepId}" not found. Available: ${ids}` }],
560
+ isError: true
561
+ };
562
+ }
563
+ if (step.status === "completed") {
564
+ return { content: [{ type: "text", text: `Step "${stepId}" is already completed.` }] };
565
+ }
566
+ const advResult = advancePlan(this.plan, stepId);
567
+ if (!advResult.success) {
568
+ return { content: [{ type: "text", text: `Cannot advance: ${advResult.reason}` }] };
569
+ }
570
+ this.plan = advResult.plan;
571
+ this.engineOptions.plan = this.plan;
572
+ const progress = getPlanProgress(this.plan);
573
+ let text = `Step completed: ${step.label}
574
+ Progress: ${progress.completed}/${progress.total} (${progress.percentage}%)`;
575
+ if (progress.completed === progress.total) {
576
+ text += "\n\nPlan complete!";
577
+ }
578
+ if (this.config.planPath) {
579
+ writeFileSync(this.config.planPath, JSON.stringify(this.plan, null, 2) + "\n");
580
+ }
581
+ return { content: [{ type: "text", text }] };
582
+ }
583
+ };
584
+ async function startMcpServer(args) {
585
+ function parseArg(flag) {
586
+ const idx = args.indexOf(flag);
587
+ return idx >= 0 && idx + 1 < args.length ? args[idx + 1] : void 0;
588
+ }
589
+ const worldPath = resolveWorldPath(parseArg("--world"));
590
+ const planPath = parseArg("--plan");
591
+ const level = parseArg("--level");
592
+ const trace = args.includes("--trace");
593
+ const workingDir = parseArg("--cwd");
594
+ if (!worldPath) {
595
+ process.stderr.write(
596
+ "Error: No world found.\nUse --world <path>, set NEUROVERSE_WORLD, or run `neuroverse world use <name>`\n"
597
+ );
598
+ process.exit(1);
599
+ return;
600
+ }
601
+ const worldInfo = describeActiveWorld(parseArg("--world"));
602
+ if (worldInfo) {
603
+ process.stderr.write(`Using world: ${worldInfo.name}
604
+ `);
605
+ }
606
+ const server = new McpGovernanceServer({
607
+ worldPath,
608
+ planPath,
609
+ level,
610
+ trace,
611
+ workingDir,
612
+ enableShell: !args.includes("--no-shell"),
613
+ enableFiles: !args.includes("--no-files"),
614
+ enableHttp: !args.includes("--no-http")
615
+ });
616
+ await server.start();
617
+ }
618
+
619
+ export {
620
+ McpGovernanceServer,
621
+ startMcpServer
622
+ };