@neuroverseos/governance 0.3.0 → 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.
Files changed (126) hide show
  1. package/.well-known/ai-plugin.json +34 -9
  2. package/AGENTS.md +72 -24
  3. package/README.md +352 -237
  4. package/dist/adapters/autoresearch.cjs +1152 -3
  5. package/dist/adapters/autoresearch.d.cts +11 -3
  6. package/dist/adapters/autoresearch.d.ts +11 -3
  7. package/dist/adapters/autoresearch.js +9 -4
  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 +171 -32
  13. package/dist/adapters/express.d.cts +1 -1
  14. package/dist/adapters/express.d.ts +1 -1
  15. package/dist/adapters/express.js +5 -5
  16. package/dist/adapters/index.cjs +564 -121
  17. package/dist/adapters/index.d.cts +3 -1
  18. package/dist/adapters/index.d.ts +3 -1
  19. package/dist/adapters/index.js +38 -16
  20. package/dist/adapters/langchain.cjs +217 -57
  21. package/dist/adapters/langchain.d.cts +5 -5
  22. package/dist/adapters/langchain.d.ts +5 -5
  23. package/dist/adapters/langchain.js +6 -5
  24. package/dist/adapters/openai.cjs +219 -59
  25. package/dist/adapters/openai.d.cts +5 -5
  26. package/dist/adapters/openai.d.ts +5 -5
  27. package/dist/adapters/openai.js +6 -5
  28. package/dist/adapters/openclaw.cjs +217 -57
  29. package/dist/adapters/openclaw.d.cts +6 -6
  30. package/dist/adapters/openclaw.d.ts +6 -6
  31. package/dist/adapters/openclaw.js +6 -5
  32. package/dist/add-ROOZLU62.js +314 -0
  33. package/dist/behavioral-MJO34S6Q.js +118 -0
  34. package/dist/{bootstrap-GXVDZNF7.js → bootstrap-CQRZVOXK.js} +6 -4
  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-P42YFKQV.js → build-QKOBBC23.js} +7 -5
  39. package/dist/{chunk-COT5XS4V.js → chunk-3WQLXYTP.js} +17 -35
  40. package/dist/{chunk-ER62HNGF.js → chunk-4FLICVVA.js} +17 -37
  41. package/dist/chunk-5TPFNWRU.js +215 -0
  42. package/dist/chunk-5U2MQO5P.js +57 -0
  43. package/dist/{chunk-NF5POFCI.js → chunk-6S5CFQXY.js} +6 -4
  44. package/dist/{chunk-QPASI2BR.js → chunk-A7GKPPU7.js} +49 -10
  45. package/dist/{chunk-OGL7QXZS.js → chunk-B6OXJLJ5.js} +17 -3
  46. package/dist/{chunk-2PQU3VAN.js → chunk-BNKJPUPQ.js} +17 -35
  47. package/dist/chunk-BQZMOEML.js +43 -0
  48. package/dist/chunk-CNSO6XW5.js +207 -0
  49. package/dist/{chunk-JZPQGIKR.js → chunk-CTZHONLA.js} +65 -9
  50. package/dist/chunk-D2UCV5AK.js +326 -0
  51. package/dist/{chunk-XPDMYECO.js → chunk-EMQDLDAF.js} +1 -185
  52. package/dist/{chunk-GR6DGCZ2.js → chunk-F66BVUYB.js} +3 -3
  53. package/dist/{chunk-2NICNKOM.js → chunk-G7DJ6VOD.js} +5 -4
  54. package/dist/{chunk-4A7LISES.js → chunk-IS4WUH6Y.js} +45 -6
  55. package/dist/{chunk-MWDQ4MJB.js → chunk-MH7BT4VH.js} +5 -1
  56. package/dist/chunk-O5ABKEA7.js +304 -0
  57. package/dist/chunk-PVTQQS3Y.js +186 -0
  58. package/dist/{chunk-4QXB6PEO.js → chunk-QLPTHTVB.js} +37 -16
  59. package/dist/chunk-QWGCMQQD.js +16 -0
  60. package/dist/{chunk-T5EUJQE5.js → chunk-QXBFT7NI.js} +31 -2
  61. package/dist/{chunk-PDOZHZWL.js → chunk-TG6SEF24.js} +25 -4
  62. package/dist/chunk-U6U7EJZL.js +177 -0
  63. package/dist/{chunk-4JRYGIO7.js → chunk-W7LLXRGY.js} +110 -7
  64. package/dist/{chunk-BUWWN2NX.js → chunk-ZJTDUCC2.js} +9 -7
  65. package/dist/{chunk-FYS2CBUW.js → chunk-ZWI3NIXK.js} +10 -0
  66. package/dist/cli/neuroverse.cjs +5091 -2348
  67. package/dist/cli/neuroverse.js +52 -21
  68. package/dist/cli/plan.cjs +881 -41
  69. package/dist/cli/plan.js +7 -15
  70. package/dist/cli/run.cjs +289 -34
  71. package/dist/cli/run.js +4 -4
  72. package/dist/{configure-ai-TK67ZWZL.js → configure-ai-6TZ3MCSI.js} +1 -1
  73. package/dist/decision-flow-M63D47LO.js +61 -0
  74. package/dist/demo-G43RLCPK.js +469 -0
  75. package/dist/{derive-TLIV4OOU.js → derive-FJZVIPUZ.js} +5 -4
  76. package/dist/{doctor-XPDLEYXN.js → doctor-6BC6X2VO.js} +6 -4
  77. package/dist/equity-penalties-SG5IZQ7I.js +244 -0
  78. package/dist/{explain-IDCRWMPX.js → explain-RHBU2GBR.js} +6 -25
  79. package/dist/{guard-RV65TT4L.js → guard-AJCCGZMF.js} +8 -12
  80. package/dist/{guard-contract-WZx__PmU.d.cts → guard-contract-DqFcTScd.d.cts} +117 -5
  81. package/dist/{guard-contract-WZx__PmU.d.ts → guard-contract-DqFcTScd.d.ts} +117 -5
  82. package/dist/{guard-engine-JLTUARGU.js → guard-engine-PNR6MHCM.js} +3 -3
  83. package/dist/{impact-XPECYRLH.js → impact-3XVDSCBU.js} +5 -5
  84. package/dist/{improve-GPUBKTEA.js → improve-TQP4ECSY.js} +7 -26
  85. package/dist/index.cjs +5597 -4279
  86. package/dist/index.d.cts +597 -18
  87. package/dist/index.d.ts +597 -18
  88. package/dist/index.js +134 -41
  89. package/dist/{infer-world-7GVZWFX4.js → infer-world-IFXCACJ5.js} +1 -1
  90. package/dist/{init-PKPIYHYE.js → init-FYPV4SST.js} +1 -1
  91. package/dist/{init-world-VWMQZQC7.js → init-world-TI7ARHBT.js} +1 -1
  92. package/dist/mcp-server-5Y3ZM7TV.js +13 -0
  93. package/dist/{model-adapter-BB7G4MFI.js → model-adapter-VXEKB4LS.js} +1 -1
  94. package/dist/{playground-E664U4T6.js → playground-VZBNPPBO.js} +29 -19
  95. package/dist/{redteam-Z7WREJ44.js → redteam-MZPZD3EF.js} +4 -4
  96. package/dist/session-JYOARW54.js +15 -0
  97. package/dist/shared-7RLUHNMU.js +16 -0
  98. package/dist/shared-B8dvUUD8.d.cts +60 -0
  99. package/dist/shared-Dr5Wiay8.d.ts +60 -0
  100. package/dist/{simulate-VDOYQFRO.js → simulate-LJXYBC6M.js} +8 -33
  101. package/dist/{test-OGXJK4QU.js → test-BOOR4A5F.js} +4 -4
  102. package/dist/{trace-JVF67VR3.js → trace-PKV4KX56.js} +4 -4
  103. package/dist/{validate-LLBWVPGV.js → validate-RALX7CZS.js} +2 -2
  104. package/dist/{validate-engine-UIABSIHD.js → validate-engine-7ZXFVGF2.js} +1 -1
  105. package/dist/viz/assets/index-B8SaeJZZ.js +23 -0
  106. package/dist/viz/index.html +23 -0
  107. package/dist/{world-LAXO6DOX.js → world-BIP4GZBZ.js} +9 -11
  108. package/dist/world-loader-Y6HMQH2D.js +13 -0
  109. package/dist/worlds/coding-agent.nv-world.md +211 -0
  110. package/dist/worlds/research-agent.nv-world.md +169 -0
  111. package/dist/worlds/social-media.nv-world.md +198 -0
  112. package/dist/worlds/trading-agent.nv-world.md +218 -0
  113. package/examples/social-media-sim/bridge.py +209 -0
  114. package/examples/social-media-sim/simulation.py +927 -0
  115. package/package.json +30 -4
  116. package/policies/content-moderation-rules.txt +8 -0
  117. package/policies/marketing-rules.txt +8 -0
  118. package/policies/science-research-rules.txt +11 -0
  119. package/policies/social-media-rules.txt +7 -0
  120. package/policies/strict-rules.txt +8 -0
  121. package/policies/trading-rules.txt +8 -0
  122. package/simulate.html +1567 -0
  123. package/dist/chunk-YZFATT7X.js +0 -9
  124. package/dist/mcp-server-FPVSU32Z.js +0 -13
  125. package/dist/session-EKTRSR7C.js +0 -14
  126. package/dist/world-loader-HMPTOEA2.js +0 -9
@@ -35,17 +35,27 @@ __export(express_exports, {
35
35
  });
36
36
  module.exports = __toCommonJS(express_exports);
37
37
 
38
- // src/engine/plan-engine.ts
39
- function keywordMatch(eventText, step) {
40
- const stepText = [
41
- step.label,
42
- step.description ?? "",
43
- ...step.tags ?? []
38
+ // src/engine/text-utils.ts
39
+ function normalizeEventText(event) {
40
+ return [
41
+ event.intent,
42
+ event.tool ?? "",
43
+ event.scope ?? ""
44
44
  ].join(" ").toLowerCase();
45
- const keywords = stepText.split(/\s+/).filter((w) => w.length > 3);
45
+ }
46
+ function extractKeywords(text, minLength = 3) {
47
+ return text.toLowerCase().split(/\s+/).filter((w) => w.length > minLength);
48
+ }
49
+ function matchesAllKeywords(eventText, ruleText) {
50
+ const keywords = extractKeywords(ruleText);
51
+ if (keywords.length === 0) return false;
52
+ return keywords.every((kw) => eventText.includes(kw));
53
+ }
54
+ function matchesKeywordThreshold(eventText, ruleText, threshold = 0.5) {
55
+ const keywords = extractKeywords(ruleText);
46
56
  if (keywords.length === 0) return false;
47
57
  const matched = keywords.filter((kw) => eventText.includes(kw));
48
- return matched.length >= Math.ceil(keywords.length * 0.5);
58
+ return matched.length >= Math.ceil(keywords.length * threshold);
49
59
  }
50
60
  function tokenSimilarity(a, b) {
51
61
  const tokensA = new Set(a.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
@@ -58,6 +68,19 @@ function tokenSimilarity(a, b) {
58
68
  const union = (/* @__PURE__ */ new Set([...tokensA, ...tokensB])).size;
59
69
  return union > 0 ? intersection / union : 0;
60
70
  }
71
+
72
+ // src/engine/plan-engine.ts
73
+ function keywordMatch(eventText, step) {
74
+ const stepText = [
75
+ step.label,
76
+ step.description ?? "",
77
+ ...step.tags ?? []
78
+ ].join(" ");
79
+ return matchesKeywordThreshold(eventText, stepText, 0.5);
80
+ }
81
+ function tokenSimilarity2(a, b) {
82
+ return tokenSimilarity(a, b);
83
+ }
61
84
  function findMatchingStep(eventText, event, steps) {
62
85
  const pendingOrActive = steps.filter((s) => s.status === "pending" || s.status === "active");
63
86
  if (pendingOrActive.length === 0) {
@@ -76,7 +99,7 @@ function findMatchingStep(eventText, event, steps) {
76
99
  let bestScore = 0;
77
100
  for (const step of pendingOrActive) {
78
101
  const stepText = [step.label, step.description ?? "", ...step.tags ?? []].join(" ");
79
- const score = tokenSimilarity(intentText, stepText);
102
+ const score = tokenSimilarity2(intentText, stepText);
80
103
  if (score > bestScore) {
81
104
  bestScore = score;
82
105
  bestStep = step;
@@ -117,7 +140,7 @@ function checkConstraints(event, eventText, constraints) {
117
140
  continue;
118
141
  }
119
142
  if (constraint.type === "scope" && constraint.trigger) {
120
- const keywords = constraint.trigger.split(/\s+/).filter((w) => w.length > 3);
143
+ const keywords = extractKeywords(constraint.trigger);
121
144
  const violated = keywords.length > 0 && keywords.every((kw) => eventText.includes(kw));
122
145
  checks.push({
123
146
  constraintId: constraint.id,
@@ -163,11 +186,7 @@ function evaluatePlan(event, plan) {
163
186
  progress
164
187
  };
165
188
  }
166
- const eventText = [
167
- event.intent,
168
- event.tool ?? "",
169
- event.scope ?? ""
170
- ].join(" ").toLowerCase();
189
+ const eventText = normalizeEventText(event);
171
190
  const { matched, closest, closestScore } = findMatchingStep(eventText, event, plan.steps);
172
191
  if (!matched) {
173
192
  return {
@@ -208,7 +227,7 @@ function evaluatePlan(event, plan) {
208
227
  };
209
228
  }
210
229
  function buildPlanCheck(event, plan, verdict) {
211
- const eventText = [event.intent, event.tool ?? "", event.scope ?? ""].join(" ").toLowerCase();
230
+ const eventText = normalizeEventText(event);
212
231
  const { matched, closest, closestScore } = findMatchingStep(eventText, event, plan.steps);
213
232
  const { checks: constraintChecks } = checkConstraints(event, eventText, plan.constraints);
214
233
  const progress = getPlanProgress(plan);
@@ -310,11 +329,49 @@ function isExternalScope(scope) {
310
329
  ];
311
330
  return !internalPatterns.some((p) => p.test(scope));
312
331
  }
332
+ var MAX_INPUT_LENGTH = 1e5;
313
333
  function evaluateGuard(event, world, options = {}) {
314
334
  const startTime = performance.now();
315
335
  const level = options.level ?? "standard";
316
336
  const includeTrace = options.trace ?? false;
317
- const eventText = (event.intent + " " + (event.tool ?? "") + " " + (event.scope ?? "")).toLowerCase();
337
+ if (!event.intent || typeof event.intent !== "string") {
338
+ return {
339
+ status: "BLOCK",
340
+ reason: "GuardEvent.intent is required and must be a string",
341
+ ruleId: "safety-input-validation",
342
+ evidence: {
343
+ worldId: world.world?.world_id ?? "",
344
+ worldName: world.world?.name ?? "",
345
+ worldVersion: world.world?.version ?? "",
346
+ evaluatedAt: Date.now(),
347
+ invariantsSatisfied: 0,
348
+ invariantsTotal: 0,
349
+ guardsMatched: [],
350
+ rulesMatched: [],
351
+ enforcementLevel: level
352
+ }
353
+ };
354
+ }
355
+ const inputLength = event.intent.length + (event.tool?.length ?? 0) + (event.scope?.length ?? 0) + (event.payload ? JSON.stringify(event.payload).length : 0);
356
+ if (inputLength > MAX_INPUT_LENGTH) {
357
+ return {
358
+ status: "BLOCK",
359
+ reason: `Input exceeds maximum allowed length (${MAX_INPUT_LENGTH} characters)`,
360
+ ruleId: "safety-input-length",
361
+ evidence: {
362
+ worldId: world.world?.world_id ?? "",
363
+ worldName: world.world?.name ?? "",
364
+ worldVersion: world.world?.version ?? "",
365
+ evaluatedAt: Date.now(),
366
+ invariantsSatisfied: 0,
367
+ invariantsTotal: 0,
368
+ guardsMatched: [],
369
+ rulesMatched: [],
370
+ enforcementLevel: level
371
+ }
372
+ };
373
+ }
374
+ const eventText = normalizeEventText(event);
318
375
  const invariantChecks = [];
319
376
  const safetyChecks = [];
320
377
  let planCheckResult;
@@ -327,6 +384,43 @@ function evaluateGuard(event, world, options = {}) {
327
384
  const guardsMatched = [];
328
385
  const rulesMatched = [];
329
386
  checkInvariantCoverage(world, invariantChecks);
387
+ if (event.roleId && options.agentStates) {
388
+ const agentState = options.agentStates.get(event.roleId);
389
+ if (agentState && agentState.cooldownRemaining > 0) {
390
+ decidingLayer = "safety";
391
+ decidingId = `penalize-cooldown-${event.roleId}`;
392
+ const verdict = buildVerdict(
393
+ "PENALIZE",
394
+ `Agent "${event.roleId}" is frozen for ${agentState.cooldownRemaining} more round(s) due to prior penalty.`,
395
+ `penalize-cooldown-${event.roleId}`,
396
+ void 0,
397
+ world,
398
+ level,
399
+ invariantChecks,
400
+ guardsMatched,
401
+ rulesMatched,
402
+ includeTrace ? buildTrace(
403
+ invariantChecks,
404
+ safetyChecks,
405
+ planCheckResult,
406
+ roleChecks,
407
+ guardChecks,
408
+ kernelRuleChecks,
409
+ levelChecks,
410
+ decidingLayer,
411
+ decidingId,
412
+ startTime
413
+ ) : void 0
414
+ );
415
+ verdict.intentRecord = {
416
+ originalIntent: event.intent,
417
+ finalAction: "blocked (agent frozen)",
418
+ enforcement: "PENALIZE",
419
+ consequence: { type: "freeze", rounds: agentState.cooldownRemaining, description: "Agent still in cooldown from prior penalty" }
420
+ };
421
+ return verdict;
422
+ }
423
+ }
330
424
  if (options.sessionAllowlist) {
331
425
  const key = eventToAllowlistKey(event);
332
426
  if (options.sessionAllowlist.has(key)) {
@@ -454,7 +548,16 @@ function evaluateGuard(event, world, options = {}) {
454
548
  if (guardVerdict.status !== "ALLOW") {
455
549
  decidingLayer = "guard";
456
550
  decidingId = guardVerdict.ruleId;
457
- return buildVerdict(
551
+ const intentRecord = {
552
+ originalIntent: event.intent,
553
+ finalAction: guardVerdict.status === "MODIFY" ? guardVerdict.modifiedTo ?? "modified" : guardVerdict.status === "PENALIZE" ? "blocked + penalized" : guardVerdict.status === "REWARD" ? event.intent : guardVerdict.status === "NEUTRAL" ? event.intent : guardVerdict.status === "BLOCK" ? "blocked" : "paused",
554
+ ruleApplied: guardVerdict.ruleId,
555
+ enforcement: guardVerdict.status,
556
+ modifiedTo: guardVerdict.modifiedTo,
557
+ consequence: guardVerdict.consequence,
558
+ reward: guardVerdict.reward
559
+ };
560
+ const verdict = buildVerdict(
458
561
  guardVerdict.status,
459
562
  guardVerdict.reason,
460
563
  guardVerdict.ruleId,
@@ -477,6 +580,10 @@ function evaluateGuard(event, world, options = {}) {
477
580
  startTime
478
581
  ) : void 0
479
582
  );
583
+ verdict.intentRecord = intentRecord;
584
+ if (guardVerdict.consequence) verdict.consequence = guardVerdict.consequence;
585
+ if (guardVerdict.reward) verdict.reward = guardVerdict.reward;
586
+ return verdict;
480
587
  }
481
588
  }
482
589
  const kernelVerdict = checkKernelRules(eventText, world, kernelRuleChecks, rulesMatched);
@@ -771,6 +878,21 @@ function checkGuards(event, eventText, world, checks, guardsMatched) {
771
878
  if (actionMode === "pause") {
772
879
  return { status: "PAUSE", reason, ruleId: `guard-${guard.id}` };
773
880
  }
881
+ if (actionMode === "penalize") {
882
+ const consequence = guard.consequence ? { ...guard.consequence } : { type: "freeze", rounds: 1, description: `Penalized for violating: ${guard.label}` };
883
+ return { status: "PENALIZE", reason, ruleId: `guard-${guard.id}`, consequence };
884
+ }
885
+ if (actionMode === "reward") {
886
+ const reward = guard.reward ? { ...guard.reward } : { type: "boost_influence", magnitude: 0.1, description: `Rewarded for: ${guard.label}` };
887
+ return { status: "REWARD", reason, ruleId: `guard-${guard.id}`, reward };
888
+ }
889
+ if (actionMode === "modify") {
890
+ const modifiedTo = guard.modify_to ?? guard.redirect ?? "hold";
891
+ return { status: "MODIFY", reason: `${reason} \u2192 Modified to: ${modifiedTo}`, ruleId: `guard-${guard.id}`, modifiedTo };
892
+ }
893
+ if (actionMode === "neutral") {
894
+ return { status: "NEUTRAL", reason, ruleId: `guard-${guard.id}` };
895
+ }
774
896
  if (actionMode === "warn" && !warnResult) {
775
897
  warnResult = { status: "ALLOW", warning: reason, ruleId: `guard-${guard.id}` };
776
898
  }
@@ -880,9 +1002,7 @@ function checkLevelConstraints(event, level, checks) {
880
1002
  return null;
881
1003
  }
882
1004
  function matchesKeywords(eventText, ruleText) {
883
- const keywords = ruleText.toLowerCase().split(/\s+/).filter((w) => w.length > 3);
884
- if (keywords.length === 0) return false;
885
- return keywords.every((kw) => eventText.includes(kw));
1005
+ return matchesAllKeywords(eventText, ruleText);
886
1006
  }
887
1007
  function eventToAllowlistKey(event) {
888
1008
  return `${(event.tool ?? "*").toLowerCase()}::${event.intent.toLowerCase().trim()}`;
@@ -950,10 +1070,18 @@ async function loadWorldFromDirectory(dirPath) {
950
1070
  const { join } = await import("path");
951
1071
  const { readdirSync } = await import("fs");
952
1072
  async function readJson(filename) {
1073
+ const filePath = join(dirPath, filename);
953
1074
  try {
954
- const content = await readFile(join(dirPath, filename), "utf-8");
1075
+ const content = await readFile(filePath, "utf-8");
955
1076
  return JSON.parse(content);
956
- } catch {
1077
+ } catch (err) {
1078
+ if (err instanceof Error && "code" in err && err.code === "ENOENT") {
1079
+ return void 0;
1080
+ }
1081
+ process.stderr.write(
1082
+ `[neuroverse] Warning: Failed to read ${filename}: ${err instanceof Error ? err.message : String(err)}
1083
+ `
1084
+ );
957
1085
  return void 0;
958
1086
  }
959
1087
  }
@@ -975,10 +1103,23 @@ async function loadWorldFromDirectory(dirPath) {
975
1103
  const rulesDir = join(dirPath, "rules");
976
1104
  const ruleFiles = readdirSync(rulesDir).filter((f) => f.endsWith(".json")).sort();
977
1105
  for (const file of ruleFiles) {
978
- const content = await readFile(join(rulesDir, file), "utf-8");
979
- rules.push(JSON.parse(content));
1106
+ try {
1107
+ const content = await readFile(join(rulesDir, file), "utf-8");
1108
+ rules.push(JSON.parse(content));
1109
+ } catch (err) {
1110
+ process.stderr.write(
1111
+ `[neuroverse] Warning: Failed to parse rule ${file}: ${err instanceof Error ? err.message : String(err)}
1112
+ `
1113
+ );
1114
+ }
1115
+ }
1116
+ } catch (err) {
1117
+ if (!(err instanceof Error && "code" in err && err.code === "ENOENT")) {
1118
+ process.stderr.write(
1119
+ `[neuroverse] Warning: Failed to read rules directory: ${err instanceof Error ? err.message : String(err)}
1120
+ `
1121
+ );
980
1122
  }
981
- } catch {
982
1123
  }
983
1124
  return {
984
1125
  world: worldJson,
@@ -1013,10 +1154,7 @@ async function loadWorld(worldPath) {
1013
1154
  if (info.isDirectory()) {
1014
1155
  return loadWorldFromDirectory(worldPath);
1015
1156
  }
1016
- if (worldPath.endsWith(".nv-world.zip")) {
1017
- throw new Error(".nv-world.zip loading not yet implemented \u2014 use a world directory");
1018
- }
1019
- throw new Error(`Cannot load world from: ${worldPath} \u2014 expected a directory or .nv-world.zip`);
1157
+ throw new Error(`Cannot load world from: ${worldPath} \u2014 expected a directory`);
1020
1158
  }
1021
1159
 
1022
1160
  // src/adapters/express.ts
@@ -1060,8 +1198,9 @@ function defaultOnBlock(verdict, _req, res, statusCode) {
1060
1198
  ruleId: verdict.ruleId,
1061
1199
  status: verdict.status
1062
1200
  };
1063
- if (res.status && res.json) {
1064
- res.status(statusCode).json(body);
1201
+ if (typeof res.status === "function" && typeof res.json === "function") {
1202
+ const r = res.status(statusCode);
1203
+ r.json(body);
1065
1204
  } else if (res.send) {
1066
1205
  res.statusCode = statusCode;
1067
1206
  res.send(JSON.stringify(body));
@@ -1,4 +1,4 @@
1
- import { a as GuardVerdict, G as GuardEvent, W as WorldDefinition } from '../guard-contract-WZx__PmU.cjs';
1
+ import { a as GuardVerdict, G as GuardEvent, W as WorldDefinition } from '../guard-contract-DqFcTScd.cjs';
2
2
 
3
3
  /**
4
4
  * NeuroVerse Adapter — Express / Fastify
@@ -1,4 +1,4 @@
1
- import { a as GuardVerdict, G as GuardEvent, W as WorldDefinition } from '../guard-contract-WZx__PmU.js';
1
+ import { a as GuardVerdict, G as GuardEvent, W as WorldDefinition } from '../guard-contract-DqFcTScd.js';
2
2
 
3
3
  /**
4
4
  * NeuroVerse Adapter — Express / Fastify
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createGovernanceMiddleware,
3
3
  createGovernanceMiddlewareFromWorld
4
- } from "../chunk-2NICNKOM.js";
5
- import "../chunk-4JRYGIO7.js";
6
- import "../chunk-4QXB6PEO.js";
7
- import "../chunk-JZPQGIKR.js";
8
- import "../chunk-YZFATT7X.js";
4
+ } from "../chunk-G7DJ6VOD.js";
5
+ import "../chunk-W7LLXRGY.js";
6
+ import "../chunk-QLPTHTVB.js";
7
+ import "../chunk-CTZHONLA.js";
8
+ import "../chunk-QWGCMQQD.js";
9
9
  export {
10
10
  createGovernanceMiddleware,
11
11
  createGovernanceMiddlewareFromWorld