@neuroverseos/governance 0.1.5 → 0.2.1

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 (82) hide show
  1. package/README.md +279 -423
  2. package/dist/adapters/express.cjs +242 -2
  3. package/dist/adapters/express.d.cts +1 -1
  4. package/dist/adapters/express.d.ts +1 -1
  5. package/dist/adapters/express.js +5 -3
  6. package/dist/adapters/index.cjs +301 -5
  7. package/dist/adapters/index.d.cts +1 -1
  8. package/dist/adapters/index.d.ts +1 -1
  9. package/dist/adapters/index.js +8 -6
  10. package/dist/adapters/langchain.cjs +267 -3
  11. package/dist/adapters/langchain.d.cts +8 -1
  12. package/dist/adapters/langchain.d.ts +8 -1
  13. package/dist/adapters/langchain.js +5 -3
  14. package/dist/adapters/openai.cjs +267 -3
  15. package/dist/adapters/openai.d.cts +8 -1
  16. package/dist/adapters/openai.d.ts +8 -1
  17. package/dist/adapters/openai.js +5 -3
  18. package/dist/adapters/openclaw.cjs +267 -3
  19. package/dist/adapters/openclaw.d.cts +8 -1
  20. package/dist/adapters/openclaw.d.ts +8 -1
  21. package/dist/adapters/openclaw.js +5 -3
  22. package/dist/{bootstrap-H4HHKQ5G.js → bootstrap-GXVDZNF7.js} +2 -1
  23. package/dist/{build-73KAVHEY.js → build-P42YFKQV.js} +34 -3
  24. package/dist/{chunk-FYPYZFV5.js → chunk-2JQJ5U5X.js} +1 -1
  25. package/dist/chunk-37JG24WH.js +161 -0
  26. package/dist/chunk-5EDDNJU6.js +321 -0
  27. package/dist/{chunk-O5OMJMIE.js → chunk-7P3S7MAY.js} +502 -2
  28. package/dist/chunk-A5W4GNQO.js +130 -0
  29. package/dist/{chunk-ITJ3LCPG.js → chunk-ADV7Q2LJ.js} +1 -1
  30. package/dist/chunk-AKW5YVCE.js +96 -0
  31. package/dist/{chunk-EIUHJXBB.js → chunk-GR6DGCZ2.js} +1 -1
  32. package/dist/{chunk-EQXFOKH2.js → chunk-IVPKFJX3.js} +24 -3
  33. package/dist/{chunk-D7BGWV2J.js → chunk-NF5POFCI.js} +5 -3
  34. package/dist/chunk-OT6PXH54.js +61 -0
  35. package/dist/chunk-P74Y66ZV.js +205 -0
  36. package/dist/chunk-PAX2P6ZP.js +601 -0
  37. package/dist/{chunk-B4NF3OLW.js → chunk-PQBJBVSW.js} +56 -2
  38. package/dist/{chunk-T4X42QXC.js → chunk-Q6O7ZLO2.js} +0 -59
  39. package/dist/{chunk-FZQCRGUU.js → chunk-TINSRYXQ.js} +24 -3
  40. package/dist/{chunk-CROPZ75A.js → chunk-UPJNTSVM.js} +24 -3
  41. package/dist/chunk-YZFATT7X.js +9 -0
  42. package/dist/{chunk-Z2S2HIV5.js → chunk-ZL4AHY4X.js} +2 -2
  43. package/dist/cli/neuroverse.cjs +5287 -740
  44. package/dist/cli/neuroverse.js +69 -13
  45. package/dist/cli/plan.cjs +1554 -0
  46. package/dist/cli/plan.d.cts +20 -0
  47. package/dist/cli/plan.d.ts +20 -0
  48. package/dist/cli/plan.js +346 -0
  49. package/dist/cli/run.cjs +1716 -0
  50. package/dist/cli/run.d.cts +20 -0
  51. package/dist/cli/run.d.ts +20 -0
  52. package/dist/cli/run.js +143 -0
  53. package/dist/{configure-ai-46JVG56I.js → configure-ai-TK67ZWZL.js} +5 -2
  54. package/dist/{derive-6NAEWLM5.js → derive-TLIV4OOU.js} +6 -4
  55. package/dist/doctor-V72UM2TC.js +170 -0
  56. package/dist/{explain-3B3VB6TL.js → explain-IDCRWMPX.js} +2 -1
  57. package/dist/{guard-67Y66P3I.js → guard-WA3FCCIO.js} +20 -6
  58. package/dist/{guard-contract-D_RQz9kt.d.ts → guard-contract-D-2LQInm.d.cts} +144 -2
  59. package/dist/{guard-contract-D_RQz9kt.d.cts → guard-contract-D-2LQInm.d.ts} +144 -2
  60. package/dist/guard-engine-D7X4CVAE.js +10 -0
  61. package/dist/{impact-CHERK3O6.js → impact-BWULZ5RP.js} +5 -3
  62. package/dist/{improve-YG6I6ERG.js → improve-GPUBKTEA.js} +4 -3
  63. package/dist/index.cjs +2095 -89
  64. package/dist/index.d.cts +466 -12
  65. package/dist/index.d.ts +466 -12
  66. package/dist/index.js +70 -20
  67. package/dist/{init-Z66T6TDI.js → init-PKPIYHYE.js} +2 -0
  68. package/dist/mcp-server-YUOQP4M5.js +13 -0
  69. package/dist/model-adapter-BB7G4MFI.js +11 -0
  70. package/dist/playground-CBXMAW2B.js +550 -0
  71. package/dist/redteam-SSNABQ7W.js +357 -0
  72. package/dist/session-MWRBTCYX.js +14 -0
  73. package/dist/{simulate-ETHHINZ4.js → simulate-VDOYQFRO.js} +2 -1
  74. package/dist/test-3GZSG5FR.js +217 -0
  75. package/dist/{trace-3YODSSIP.js → trace-TM4Z7G73.js} +4 -2
  76. package/dist/{validate-UVE6GKQU.js → validate-LLBWVPGV.js} +15 -6
  77. package/dist/validate-engine-UIABSIHD.js +7 -0
  78. package/dist/{world-WLNHL5XC.js → world-LAXO6DOX.js} +87 -7
  79. package/dist/world-loader-HMPTOEA2.js +9 -0
  80. package/package.json +19 -5
  81. package/dist/validate-engine-657D75OG.js +0 -6
  82. /package/dist/{chunk-M3TZFGHO.js → chunk-JZPQGIKR.js} +0 -0
@@ -35,6 +35,197 @@ __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 ?? []
44
+ ].join(" ").toLowerCase();
45
+ const keywords = stepText.split(/\s+/).filter((w) => w.length > 3);
46
+ if (keywords.length === 0) return false;
47
+ const matched = keywords.filter((kw) => eventText.includes(kw));
48
+ return matched.length >= Math.ceil(keywords.length * 0.5);
49
+ }
50
+ function tokenSimilarity(a, b) {
51
+ const tokensA = new Set(a.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
52
+ const tokensB = new Set(b.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
53
+ if (tokensA.size === 0 || tokensB.size === 0) return 0;
54
+ let intersection = 0;
55
+ for (const t of tokensA) {
56
+ if (tokensB.has(t)) intersection++;
57
+ }
58
+ const union = (/* @__PURE__ */ new Set([...tokensA, ...tokensB])).size;
59
+ return union > 0 ? intersection / union : 0;
60
+ }
61
+ function findMatchingStep(eventText, event, steps) {
62
+ const pendingOrActive = steps.filter((s) => s.status === "pending" || s.status === "active");
63
+ if (pendingOrActive.length === 0) {
64
+ return { matched: null, closest: null, closestScore: 0 };
65
+ }
66
+ for (const step of pendingOrActive) {
67
+ if (keywordMatch(eventText, step)) {
68
+ if (step.tools && event.tool && !step.tools.includes(event.tool)) {
69
+ continue;
70
+ }
71
+ return { matched: step, closest: step, closestScore: 1 };
72
+ }
73
+ }
74
+ const intentText = [event.intent, event.tool ?? "", event.scope ?? ""].join(" ");
75
+ let bestStep = null;
76
+ let bestScore = 0;
77
+ for (const step of pendingOrActive) {
78
+ const stepText = [step.label, step.description ?? "", ...step.tags ?? []].join(" ");
79
+ const score = tokenSimilarity(intentText, stepText);
80
+ if (score > bestScore) {
81
+ bestScore = score;
82
+ bestStep = step;
83
+ }
84
+ }
85
+ const SIMILARITY_THRESHOLD = 0.35;
86
+ if (bestScore >= SIMILARITY_THRESHOLD && bestStep) {
87
+ if (bestStep.tools && event.tool && !bestStep.tools.includes(event.tool)) {
88
+ return { matched: null, closest: bestStep, closestScore: bestScore };
89
+ }
90
+ return { matched: bestStep, closest: bestStep, closestScore: bestScore };
91
+ }
92
+ return { matched: null, closest: bestStep, closestScore: bestScore };
93
+ }
94
+ function isSequenceValid(step, plan) {
95
+ if (!plan.sequential) return true;
96
+ if (!step.requires || step.requires.length === 0) return true;
97
+ return step.requires.every((reqId) => {
98
+ const reqStep = plan.steps.find((s) => s.id === reqId);
99
+ return reqStep?.status === "completed";
100
+ });
101
+ }
102
+ function checkConstraints(event, eventText, constraints) {
103
+ const checks = [];
104
+ for (const constraint of constraints) {
105
+ if (constraint.type === "approval") {
106
+ if (constraint.trigger && eventText.includes(constraint.trigger.substring(0, 10).toLowerCase())) {
107
+ checks.push({ constraintId: constraint.id, passed: false, reason: constraint.description });
108
+ return { violated: constraint, checks };
109
+ }
110
+ const keywords = constraint.description.toLowerCase().split(/\s+/).filter((w) => w.length > 3);
111
+ const relevant = keywords.some((kw) => eventText.includes(kw));
112
+ if (relevant) {
113
+ checks.push({ constraintId: constraint.id, passed: false, reason: constraint.description });
114
+ return { violated: constraint, checks };
115
+ }
116
+ checks.push({ constraintId: constraint.id, passed: true });
117
+ continue;
118
+ }
119
+ if (constraint.type === "scope" && constraint.trigger) {
120
+ const keywords = constraint.trigger.split(/\s+/).filter((w) => w.length > 3);
121
+ const violated = keywords.length > 0 && keywords.every((kw) => eventText.includes(kw));
122
+ checks.push({
123
+ constraintId: constraint.id,
124
+ passed: !violated,
125
+ reason: violated ? constraint.description : void 0
126
+ });
127
+ if (violated) {
128
+ return { violated: constraint, checks };
129
+ }
130
+ continue;
131
+ }
132
+ checks.push({ constraintId: constraint.id, passed: true });
133
+ }
134
+ return { violated: null, checks };
135
+ }
136
+ function getPlanProgress(plan) {
137
+ const completed = plan.steps.filter((s) => s.status === "completed").length;
138
+ const total = plan.steps.length;
139
+ return {
140
+ completed,
141
+ total,
142
+ percentage: total > 0 ? Math.round(completed / total * 100) : 0
143
+ };
144
+ }
145
+ function evaluatePlan(event, plan) {
146
+ const progress = getPlanProgress(plan);
147
+ if (plan.expires_at) {
148
+ const expiresAt = new Date(plan.expires_at).getTime();
149
+ if (Date.now() > expiresAt) {
150
+ return {
151
+ allowed: true,
152
+ status: "PLAN_COMPLETE",
153
+ reason: "Plan has expired.",
154
+ progress
155
+ };
156
+ }
157
+ }
158
+ if (progress.completed === progress.total) {
159
+ return {
160
+ allowed: true,
161
+ status: "PLAN_COMPLETE",
162
+ reason: "All plan steps are completed.",
163
+ progress
164
+ };
165
+ }
166
+ const eventText = [
167
+ event.intent,
168
+ event.tool ?? "",
169
+ event.scope ?? ""
170
+ ].join(" ").toLowerCase();
171
+ const { matched, closest, closestScore } = findMatchingStep(eventText, event, plan.steps);
172
+ if (!matched) {
173
+ return {
174
+ allowed: false,
175
+ status: "OFF_PLAN",
176
+ reason: "Action does not match any plan step.",
177
+ closestStep: closest?.label,
178
+ similarityScore: closestScore,
179
+ progress
180
+ };
181
+ }
182
+ if (!isSequenceValid(matched, plan)) {
183
+ const pendingDeps = (matched.requires ?? []).filter((reqId) => plan.steps.find((s) => s.id === reqId)?.status !== "completed").join(", ");
184
+ return {
185
+ allowed: false,
186
+ status: "OFF_PLAN",
187
+ reason: `Step "${matched.label}" requires completion of: ${pendingDeps}`,
188
+ matchedStep: matched.id,
189
+ progress
190
+ };
191
+ }
192
+ const { violated } = checkConstraints(event, eventText, plan.constraints);
193
+ if (violated) {
194
+ return {
195
+ allowed: false,
196
+ status: "CONSTRAINT_VIOLATED",
197
+ reason: violated.description,
198
+ matchedStep: matched.id,
199
+ progress
200
+ };
201
+ }
202
+ return {
203
+ allowed: true,
204
+ status: "ON_PLAN",
205
+ reason: `Matches step: ${matched.label}`,
206
+ matchedStep: matched.id,
207
+ progress
208
+ };
209
+ }
210
+ function buildPlanCheck(event, plan, verdict) {
211
+ const eventText = [event.intent, event.tool ?? "", event.scope ?? ""].join(" ").toLowerCase();
212
+ const { matched, closest, closestScore } = findMatchingStep(eventText, event, plan.steps);
213
+ const { checks: constraintChecks } = checkConstraints(event, eventText, plan.constraints);
214
+ const progress = getPlanProgress(plan);
215
+ return {
216
+ planId: plan.plan_id,
217
+ matched: !!matched,
218
+ matchedStepId: matched?.id,
219
+ matchedStepLabel: matched?.label,
220
+ closestStepId: !matched ? closest?.id : void 0,
221
+ closestStepLabel: !matched ? closest?.label : void 0,
222
+ similarityScore: !matched ? closestScore : void 0,
223
+ sequenceValid: matched ? isSequenceValid(matched, plan) : void 0,
224
+ constraintsChecked: constraintChecks,
225
+ progress: { completed: progress.completed, total: progress.total }
226
+ };
227
+ }
228
+
38
229
  // src/engine/guard-engine.ts
39
230
  var PROMPT_INJECTION_PATTERNS = [
40
231
  // Instruction override
@@ -126,6 +317,7 @@ function evaluateGuard(event, world, options = {}) {
126
317
  const eventText = (event.intent + " " + (event.tool ?? "") + " " + (event.scope ?? "")).toLowerCase();
127
318
  const invariantChecks = [];
128
319
  const safetyChecks = [];
320
+ let planCheckResult;
129
321
  const roleChecks = [];
130
322
  const guardChecks = [];
131
323
  const kernelRuleChecks = [];
@@ -153,6 +345,7 @@ function evaluateGuard(event, world, options = {}) {
153
345
  includeTrace ? buildTrace(
154
346
  invariantChecks,
155
347
  safetyChecks,
348
+ planCheckResult,
156
349
  roleChecks,
157
350
  guardChecks,
158
351
  kernelRuleChecks,
@@ -181,6 +374,7 @@ function evaluateGuard(event, world, options = {}) {
181
374
  includeTrace ? buildTrace(
182
375
  invariantChecks,
183
376
  safetyChecks,
377
+ planCheckResult,
184
378
  roleChecks,
185
379
  guardChecks,
186
380
  kernelRuleChecks,
@@ -191,6 +385,42 @@ function evaluateGuard(event, world, options = {}) {
191
385
  ) : void 0
192
386
  );
193
387
  }
388
+ if (options.plan) {
389
+ const planVerdict = evaluatePlan(event, options.plan);
390
+ planCheckResult = buildPlanCheck(event, options.plan, planVerdict);
391
+ if (!planVerdict.allowed && planVerdict.status !== "PLAN_COMPLETE") {
392
+ decidingLayer = "plan-enforcement";
393
+ decidingId = `plan-${options.plan.plan_id}`;
394
+ const planStatus = planVerdict.status === "CONSTRAINT_VIOLATED" ? "PAUSE" : "BLOCK";
395
+ let reason = planVerdict.reason ?? "Action blocked by plan.";
396
+ if (planVerdict.status === "OFF_PLAN" && planVerdict.closestStep) {
397
+ reason += ` Closest step: "${planVerdict.closestStep}" (similarity: ${(planVerdict.similarityScore ?? 0).toFixed(2)})`;
398
+ }
399
+ return buildVerdict(
400
+ planStatus,
401
+ reason,
402
+ `plan-${options.plan.plan_id}`,
403
+ void 0,
404
+ world,
405
+ level,
406
+ invariantChecks,
407
+ guardsMatched,
408
+ rulesMatched,
409
+ includeTrace ? buildTrace(
410
+ invariantChecks,
411
+ safetyChecks,
412
+ planCheckResult,
413
+ roleChecks,
414
+ guardChecks,
415
+ kernelRuleChecks,
416
+ levelChecks,
417
+ decidingLayer,
418
+ decidingId,
419
+ startTime
420
+ ) : void 0
421
+ );
422
+ }
423
+ }
194
424
  const roleVerdict = checkRoleRules(event, eventText, world, roleChecks);
195
425
  if (roleVerdict) {
196
426
  decidingLayer = "role";
@@ -208,6 +438,7 @@ function evaluateGuard(event, world, options = {}) {
208
438
  includeTrace ? buildTrace(
209
439
  invariantChecks,
210
440
  safetyChecks,
441
+ planCheckResult,
211
442
  roleChecks,
212
443
  guardChecks,
213
444
  kernelRuleChecks,
@@ -236,6 +467,7 @@ function evaluateGuard(event, world, options = {}) {
236
467
  includeTrace ? buildTrace(
237
468
  invariantChecks,
238
469
  safetyChecks,
470
+ planCheckResult,
239
471
  roleChecks,
240
472
  guardChecks,
241
473
  kernelRuleChecks,
@@ -264,6 +496,7 @@ function evaluateGuard(event, world, options = {}) {
264
496
  includeTrace ? buildTrace(
265
497
  invariantChecks,
266
498
  safetyChecks,
499
+ planCheckResult,
267
500
  roleChecks,
268
501
  guardChecks,
269
502
  kernelRuleChecks,
@@ -291,6 +524,7 @@ function evaluateGuard(event, world, options = {}) {
291
524
  includeTrace ? buildTrace(
292
525
  invariantChecks,
293
526
  safetyChecks,
527
+ planCheckResult,
294
528
  roleChecks,
295
529
  guardChecks,
296
530
  kernelRuleChecks,
@@ -315,6 +549,7 @@ function evaluateGuard(event, world, options = {}) {
315
549
  includeTrace ? buildTrace(
316
550
  invariantChecks,
317
551
  safetyChecks,
552
+ planCheckResult,
318
553
  roleChecks,
319
554
  guardChecks,
320
555
  kernelRuleChecks,
@@ -652,8 +887,8 @@ function matchesKeywords(eventText, ruleText) {
652
887
  function eventToAllowlistKey(event) {
653
888
  return `${(event.tool ?? "*").toLowerCase()}::${event.intent.toLowerCase().trim()}`;
654
889
  }
655
- function buildTrace(invariantChecks, safetyChecks, roleChecks, guardChecks, kernelRuleChecks, levelChecks, decidingLayer, decidingId, startTime) {
656
- return {
890
+ function buildTrace(invariantChecks, safetyChecks, planCheck, roleChecks, guardChecks, kernelRuleChecks, levelChecks, decidingLayer, decidingId, startTime) {
891
+ const trace = {
657
892
  invariantChecks,
658
893
  safetyChecks,
659
894
  roleChecks,
@@ -671,6 +906,7 @@ function buildTrace(invariantChecks, safetyChecks, roleChecks, guardChecks, kern
671
906
  "safety-scope-escape",
672
907
  "safety-execution-claim",
673
908
  "safety-execution-intent",
909
+ "plan-enforcement",
674
910
  "role-rules",
675
911
  "declarative-guards",
676
912
  "kernel-rules",
@@ -680,6 +916,10 @@ function buildTrace(invariantChecks, safetyChecks, roleChecks, guardChecks, kern
680
916
  },
681
917
  durationMs: performance.now() - startTime
682
918
  };
919
+ if (planCheck) {
920
+ trace.planCheck = planCheck;
921
+ }
922
+ return trace;
683
923
  }
684
924
  function buildVerdict(status, reason, ruleId, warning, world, level, invariantChecks, guardsMatched, rulesMatched, trace) {
685
925
  const evidence = {
@@ -1,4 +1,4 @@
1
- import { G as GuardVerdict, a as GuardEvent, W as WorldDefinition } from '../guard-contract-D_RQz9kt.cjs';
1
+ import { G as GuardVerdict, a as GuardEvent, W as WorldDefinition } from '../guard-contract-D-2LQInm.cjs';
2
2
 
3
3
  /**
4
4
  * NeuroVerse Adapter — Express / Fastify
@@ -1,4 +1,4 @@
1
- import { G as GuardVerdict, a as GuardEvent, W as WorldDefinition } from '../guard-contract-D_RQz9kt.js';
1
+ import { G as GuardVerdict, a as GuardEvent, W as WorldDefinition } from '../guard-contract-D-2LQInm.js';
2
2
 
3
3
  /**
4
4
  * NeuroVerse Adapter — Express / Fastify
@@ -1,9 +1,11 @@
1
1
  import {
2
2
  createGovernanceMiddleware,
3
3
  createGovernanceMiddlewareFromWorld
4
- } from "../chunk-Z2S2HIV5.js";
5
- import "../chunk-B4NF3OLW.js";
6
- import "../chunk-M3TZFGHO.js";
4
+ } from "../chunk-ZL4AHY4X.js";
5
+ import "../chunk-PQBJBVSW.js";
6
+ import "../chunk-JZPQGIKR.js";
7
+ import "../chunk-P74Y66ZV.js";
8
+ import "../chunk-YZFATT7X.js";
7
9
  export {
8
10
  createGovernanceMiddleware,
9
11
  createGovernanceMiddlewareFromWorld